1 /*
   2  * Copyright �� 2005 Novell, Inc.
   3  *
   4  * Permission to use, copy, modify, distribute, and sell this software
   5  * and its documentation for any purpose is hereby granted without
   6  * fee, provided that the above copyright notice appear in all copies
   7  * and that both that copyright notice and this permission notice
   8  * appear in supporting documentation, and that the name of
   9  * Novell, Inc. not be used in advertising or publicity pertaining to
  10  * distribution of the software without specific, written prior permission.
  11  * Novell, Inc. makes no representations about the suitability of this
  12  * software for any purpose. It is provided "as is" without express or
  13  * implied warranty.
  14  *
  15  * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
  17  * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
  19  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  20  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  21  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22  *
  23  * Author: David Reveman <davidr@novell.com>
  24  */
  25 
  26 #ifdef HAVE_CONFIG_H
  27 #  include <config.h>
  28 #endif
  29 
  30 #include <stdio.h>
  31 #include <stdlib.h>
  32 #include <string.h>
  33 #include <math.h>
  34 #include <unistd.h>
  35 
  36 #include <core/abiversion.h>
  37 #include <decoration.h>
  38 #include "decor.h"
  39 
  40 #include <X11/Xatom.h>
  41 #include <X11/extensions/shape.h>
  42 
  43 COMPIZ_PLUGIN_20090315 (decor, DecorPluginVTable)
  44 
  45 MatchedDecorClipGroup::MatchedDecorClipGroup (const CompMatch &match) :
  46     mMatch (match)
  47 {
  48 }
  49 
  50 bool
  51 MatchedDecorClipGroup::doPushClippable (DecorClippableInterface *dc)
  52 {
  53     if (dc->matches (mMatch))
  54 	return mClipGroupImpl.pushClippable (dc);
  55 
  56     return false;
  57 }
  58 
  59 void
  60 DecorWindow::doUpdateShadow (const CompRegion &reg)
  61 {
  62     shadowRegion = outputRegion () - (reg - inputRegion ());
  63 }
  64 
  65 void
  66 DecorWindow::doSetOwner (DecorClipGroupInterface *i)
  67 {
  68     mClipGroup = i;
  69 }
  70 
  71 bool
  72 DecorWindow::doMatches (const CompMatch &m)
  73 {
  74     return const_cast <CompMatch &> (m).evaluate (window) && !window->invisible ();
  75 }
  76 
  77 const CompRegion &
  78 DecorWindow::getOutputRegion ()
  79 {
  80     return mOutputRegion;
  81 }
  82 
  83 const CompRegion &
  84 DecorWindow::getInputRegion ()
  85 {
  86     return mInputRegion;
  87 }
  88 
  89 void
  90 DecorWindow::doUpdateGroupShadows ()
  91 {
  92     if (mClipGroup)
  93 	mClipGroup->updateAllShadows ();
  94 }
  95 
  96 /* From core */
  97 
  98 /*
  99  * DecorWindow::glDraw
 100  *
 101  * Handles the drawing of the actual decoration texture
 102  * (whether that be the bound pixmap for a window type
 103  *  decoration or a redirected scaled-quad pixmap for
 104  *  pixmap type decorations).
 105  *
 106  * For pixmap type decorations, we need to use the precomputed
 107  * shadow region for the clipping region of when we draw the
 108  * window decoration with glDrawTexture. We also need to add
 109  * geometry for each quad on the pixmap decoration so that it
 110  * stretches from its original size to the size of the actual
 111  * window.
 112  *
 113  * Usually, this works something like this
 114  *
 115  * -----------------------------------
 116  * | Q1 | Buttons ... Text (Q2) | Q3 |
 117  * -----------------------------------
 118  * | Q4 |                       | Q5 |
 119  * -----------------------------------
 120  * | Q6 |         Q7            | Q8 |
 121  * -----------------------------------
 122  *
 123  *
 124  * ---------------------------------------------------
 125  * | Q1 | Buttons ... Text (Q2)                 | Q3 |
 126  * ---------------------------------------------------
 127  * | Q4 |                                       | Q5 |
 128  * |    |                                       |    |
 129  * |    |                                       |    |
 130  * |    |                                       |    |
 131  * |    |                                       |    |
 132  * |    |                                       |    |
 133  * |    |                                       |    |
 134  * |    |                                       |    |
 135  * |    |                                       |    |
 136  * |    |                                       |    |
 137  * ---------------------------------------------------
 138  * | Q6 |         Q7                            | Q8 |
 139  * ---------------------------------------------------
 140  *
 141  * Note here that quads 2, 4, 5 and 7 are scaled according
 142  * to the matrix supplied on each quad structure.
 143  *
 144  * FIXME: This doesn't work with multiple textures, that
 145  * needs work to determine the quads for each separate texture
 146  *
 147  * For window type decorations we add geometry for the frame
 148  * region of the window.
 149  *
 150  * Next, we draw the actual texture with the saved window geometry
 151  *
 152  */
 153 
 154 bool
 155 DecorWindow::glDraw (const GLMatrix     &transform,
 156 		     const GLWindowPaintAttrib &attrib,
 157 		     const CompRegion   &region,
 158 		     unsigned int       mask)
 159 {
 160     bool status;
 161 
 162     status = gWindow->glDraw (transform, attrib, region, mask);
 163 
 164     /* Don't render dock decorations (shadows) on just any old window */
 165     if (!(window->type () & CompWindowTypeDockMask))
 166     {
 167 	glDecorate (transform, attrib, region, mask);
 168 	/* Render dock decorations (shadows) on desktop windows only */
 169 	if (window->type () & CompWindowTypeDesktopMask)
 170 	{
 171 	    foreach (CompWindow *w, dScreen->cScreen->getWindowPaintList ())
 172 	    {
 173 		bool isDock = w->type () & CompWindowTypeDockMask;
 174 		bool drawShadow = !(w->invisible () || w->destroyed ());
 175 
 176 		if (isDock && drawShadow)
 177 		{
 178 		    DecorWindow *d = DecorWindow::get (w);
 179 
 180 		    /* If the last mask was an occlusion pass, glPaint
 181 		     * return value will mean something different, so
 182 		     * remove it */
 183 		    unsigned int pmask = d->gWindow->lastMask () &
 184 				~(PAINT_WINDOW_OCCLUSION_DETECTION_MASK);
 185 
 186 		    /* Check if the window would draw by seeing if glPaint
 187 		     * returns true when using PAINT_NO_CORE_INSTANCE_MASK
 188 		     */
 189 		    pmask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
 190 
 191 		    const GLWindowPaintAttrib &pAttrib (d->gWindow->paintAttrib ());
 192 
 193 		    if (d->gWindow->glPaint (pAttrib,
 194 					     transform,
 195 					     region,
 196 					     pmask))
 197 			d->glDecorate (transform, pAttrib, region, mask);
 198 		}
 199 	    }
 200 	}
 201     }
 202 
 203     return status;
 204 }
 205 
 206 void
 207 DecorWindow::glDecorate (const GLMatrix     &transform,
 208 			 const GLWindowPaintAttrib &attrib,
 209 		         const CompRegion   &region,
 210 		         unsigned int       mask)
 211 {
 212     if (wd &&
 213 	wd->decor->type == WINDOW_DECORATION_TYPE_PIXMAP)
 214     {
 215 	CompRect box;
 216 	GLTexture::MatrixList ml (1);
 217 	mask |= PAINT_WINDOW_BLEND_MASK;
 218 
 219 	gWindow->vertexBuffer ()->begin ();
 220 	const CompRegion *preg = NULL;
 221 
 222 	if ((mask & (PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK |
 223 		     PAINT_WINDOW_WITH_OFFSET_MASK)))
 224 	    preg = &region;
 225 	else if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
 226 	    preg = &infiniteRegion;
 227 	else if (mClipGroup)
 228 	{
 229 	    tmpRegion = mOutputRegion;
 230 	    tmpRegion &= region;
 231 	    tmpRegion &= shadowRegion;
 232 	    preg = &tmpRegion;
 233 	}
 234 	else
 235 	    preg = &region;
 236 
 237 	/* In case some plugin needs to paint us with an offset region */
 238 	if (preg->isEmpty ())
 239 	    preg = &region;
 240 
 241 	const CompRegion &reg (*preg);
 242 
 243 	if (updateMatrix)
 244 	    updateDecorationScale ();
 245 
 246 	for (int i = 0; i < wd->nQuad; i++)
 247 	{
 248 	    box.setGeometry (wd->quad[i].box.x1,
 249 			     wd->quad[i].box.y1,
 250 			     wd->quad[i].box.x2 - wd->quad[i].box.x1,
 251 			     wd->quad[i].box.y2 - wd->quad[i].box.y1);
 252 
 253 	    if (box.width () > 0 && box.height () > 0)
 254 	    {
 255 		ml[0] = wd->quad[i].matrix;
 256 		const CompRegionRef boxRegion (box.region ());
 257 		gWindow->glAddGeometry (ml, boxRegion, reg);
 258 	    }
 259 	}
 260 
 261 	if (gWindow->vertexBuffer ()->end ())
 262 	{
 263 	    glEnable (GL_BLEND);
 264 	    gWindow->glDrawTexture (wd->decor->texture->textures[0], transform,
 265 				    attrib, mask);
 266 	    glDisable (GL_BLEND);
 267 	}
 268     }
 269     else if (wd && wd->decor->type == WINDOW_DECORATION_TYPE_WINDOW)
 270     {
 271 	GLTexture::MatrixList ml (1);
 272 
 273 	if (gWindow->textures ().empty ())
 274 	    gWindow->bind ();
 275 	if (gWindow->textures ().empty ())
 276 	    return;
 277 
 278 	if (updateMatrix)
 279 	    updateDecorationScale ();
 280 
 281 	glEnable (GL_BLEND);
 282 
 283 	if (gWindow->textures ().size () == 1)
 284 	{
 285 	    ml[0] = gWindow->matrices ()[0];
 286 	    gWindow->vertexBuffer ()->begin ();
 287 	    gWindow->glAddGeometry (ml, window->frameRegion (), region);
 288 	    if (gWindow->vertexBuffer ()->end ())
 289 		gWindow->glDrawTexture (gWindow->textures ()[0], transform,
 290 		                        attrib, mask);
 291 	}
 292 	else
 293 	{
 294 	    if (updateReg)
 295 		updateWindowRegions ();
 296 	    for (unsigned int i = 0; i < gWindow->textures ().size (); i++)
 297 	    {
 298 		ml[0] = gWindow->matrices ()[i];
 299 		gWindow->vertexBuffer ()->begin ();
 300 		gWindow->glAddGeometry (ml, regions[i], region);
 301 		if (gWindow->vertexBuffer ()->end ())
 302 		    gWindow->glDrawTexture (gWindow->textures ()[i], transform,
 303 		                            attrib, mask);
 304 	    }
 305 	}
 306 
 307 	glDisable (GL_BLEND);
 308     }
 309 }
 310 
 311 static bool bindFailed;
 312 /*
 313  * DecorTexture::DecorTexture
 314  *
 315  * Creates a texture for a given pixmap in the property.
 316  * bindFailed is a global variable used to determine if
 317  * binding to a pixmap gave us more than one texture since
 318  * FIXME that isn't supported yet. Also sets damage handlers
 319  * for this pixmap
 320  */
 321 
 322 DecorTexture::DecorTexture (DecorPixmapInterface::Ptr pixmap) :
 323     status (true),
 324     refCount (1),
 325     pixmap (pixmap),
 326     damage (None)
 327 {
 328     unsigned int width, height, depth, ui;
 329     Window	 root;
 330     int		 i;
 331 
 332     if (!XGetGeometry (screen->dpy (), pixmap->getPixmap (), &root,
 333 		       &i, &i, &width, &height, &ui, &depth))
 334     {
 335 	status = false;
 336 	return;
 337     }
 338 
 339     bindFailed = false;
 340     textures = GLTexture::bindPixmapToTexture (pixmap->getPixmap (),
 341 					       width, height, depth,
 342 					       compiz::opengl::ExternallyManaged);
 343     if (textures.size () != 1)
 344     {
 345 	bindFailed = true;
 346 	status = false;
 347 	return;
 348     }
 349 
 350     if (!DecorScreen::get (screen)->optionGetMipmap ())
 351 	textures[0]->setMipmap (false);
 352 
 353     damage = XDamageCreate (screen->dpy (), pixmap->getPixmap (),
 354 			     XDamageReportBoundingBox);
 355 }
 356 
 357 /*
 358  * DecorTexture::~DecorTexture
 359  *
 360  * Remove damage handle on texture
 361  *
 362  */
 363 
 364 DecorTexture::~DecorTexture ()
 365 {
 366     if (damage)
 367 	XDamageDestroy (screen->dpy (), damage);
 368 }
 369 
 370 /*
 371  * DecorScreen::getTexture
 372  *
 373  * Returns the texture for a given pixmap. Note
 374  * that if this particular pixmap was already found
 375  * in the list of decor textures, then the refcount
 376  * is increased and that one is returned instead of
 377  * binding a new texture.
 378  *
 379  */
 380 
 381 DecorTexture *
 382 DecorScreen::getTexture (Pixmap pixmap)
 383 {
 384     if (!cmActive)
 385 	return NULL;
 386 
 387     foreach (DecorTexture *t, textures)
 388 	if (t->pixmap->getPixmap () == pixmap)
 389 	{
 390 	    t->refCount++;
 391 	    return t;
 392 	}
 393 
 394     X11PixmapDeletor::Ptr dl = boost::make_shared <X11PixmapDeletor> (screen->dpy ());
 395     DecorPixmap::Ptr pm = boost::make_shared <DecorPixmap> (pixmap, dl);
 396 
 397     DecorTexture *texture = new DecorTexture (boost::shared_static_cast <DecorPixmapInterface> (pm));
 398 
 399     if (!texture->status)
 400     {
 401 	delete texture;
 402 	return NULL;
 403     }
 404 
 405     textures.push_back (texture);
 406 
 407     return texture;
 408 }
 409 
 410 /*
 411  * DecorScreen::releaseTexture
 412  *
 413  * Unreferences the texture, deletes the texture from
 414  * the list of textures if its no longer in use
 415  */
 416 
 417 void
 418 DecorScreen::releaseTexture (DecorTexture *texture)
 419 {
 420     texture->refCount--;
 421     if (texture->refCount)
 422 	return;
 423 
 424     std::list<DecorTexture *>::iterator it =
 425 	std::find (textures.begin (), textures.end (), texture);
 426 
 427     if (it == textures.end ())
 428 	return;
 429 
 430     textures.erase (it);
 431     delete texture;
 432 }
 433 
 434 /*
 435  * computeQuadBox
 436  *
 437  * Determines a scaled quad box for the decor plugin
 438  * by determining the x2 and y2 points by either clamping
 439  * or stretching the box. Also applies gravity to determine
 440  * relative x1 and y1 points to the window
 441  *
 442  */
 443 
 444 static void
 445 computeQuadBox (decor_quad_t *q,
 446 		int	     width,
 447 		int	     height,
 448 		int	     *return_x1,
 449 		int	     *return_y1,
 450 		int	     *return_x2,
 451 		int	     *return_y2,
 452 		float        *return_sx,
 453 		float        *return_sy)
 454 {
 455     int   x1, y1, x2, y2;
 456     float sx = 1.0f;
 457     float sy = 1.0f;
 458 
 459     decor_apply_gravity (q->p1.gravity, q->p1.x, q->p1.y, width, height,
 460 			 &x1, &y1);
 461     decor_apply_gravity (q->p2.gravity, q->p2.x, q->p2.y, width, height,
 462 			 &x2, &y2);
 463 
 464     if (q->clamp & CLAMP_HORZ)
 465     {
 466 	if (x1 < 0)
 467 	    x1 = 0;
 468 	if (x2 > width)
 469 	    x2 = width;
 470     }
 471 
 472     if (q->clamp & CLAMP_VERT)
 473     {
 474 	if (y1 < 0)
 475 	    y1 = 0;
 476 	if (y2 > height)
 477 	    y2 = height;
 478     }
 479 
 480     if (q->stretch & STRETCH_X)
 481     {
 482 	sx = (float) q->max_width / ((float) (x2 - x1));
 483     }
 484     else if (q->max_width < x2 - x1)
 485     {
 486 	if (q->align & ALIGN_RIGHT)
 487 	    x1 = x2 - q->max_width;
 488 	else
 489 	    x2 = x1 + q->max_width;
 490     }
 491 
 492     if (q->stretch & STRETCH_Y)
 493     {
 494 	sy = (float) q->max_height / ((float) (y2 - y1));
 495     }
 496     else if (q->max_height < y2 - y1)
 497     {
 498 	if (q->align & ALIGN_BOTTOM)
 499 	    y1 = y2 - q->max_height;
 500 	else
 501 	    y2 = y1 + q->max_height;
 502     }
 503 
 504     *return_x1 = x1;
 505     *return_y1 = y1;
 506     *return_x2 = x2;
 507     *return_y2 = y2;
 508 
 509     if (return_sx)
 510 	*return_sx = sx;
 511     if (return_sy)
 512 	*return_sy = sy;
 513 }
 514 
 515 /*
 516  * Decoration::create
 517  *
 518  * Factory function to create a Decoration *, takes a decoration
 519  * property data, size, type and offset inside that property data
 520  * to start reading from.
 521  *
 522  * This function determines the decoration type and reads the property
 523  * data appropriately and then uses the property data to determine the
 524  * quads and extents of the input windows and the hinted extents.
 525  *
 526  */
 527 
 528 Decoration::Ptr
 529 Decoration::create (Window        id,
 530 		    long          *prop,
 531 		    unsigned int  size,
 532 		    unsigned int  type,
 533 		    unsigned int  nOffset,
 534 		    DecorPixmapRequestorInterface *requestor)
 535 {
 536     unsigned int    frameType, frameState, frameActions;
 537     Pixmap	    pixmap = None;
 538     decor_extents_t border;
 539     decor_extents_t input;
 540     decor_extents_t maxBorder;
 541     decor_extents_t maxInput;
 542     int		    minWidth;
 543     int		    minHeight;
 544     int             nQuad = N_QUADS_MAX;
 545     boost::shared_array <decor_quad_t> quad (new decor_quad_t[nQuad]);
 546 
 547     if (type ==  WINDOW_DECORATION_TYPE_PIXMAP &&
 548 	!DecorScreen::get (screen)->cmActive)
 549     {
 550 	compLogMessage ("decor", CompLogLevelWarn, "requested a pixmap type decoration when compositing isn't available");
 551 	throw std::exception ();
 552     }
 553 
 554     if (type == WINDOW_DECORATION_TYPE_PIXMAP)
 555     {
 556 	nQuad = decor_pixmap_property_to_quads (prop, nOffset, size, &pixmap, &input,
 557 						&border, &maxInput,
 558 						&maxBorder, &minWidth, &minHeight,
 559 						&frameType, &frameState, &frameActions, quad.get ());
 560 
 561 	if (!nQuad)
 562 	    throw std::exception ();
 563     }
 564     else if (type == WINDOW_DECORATION_TYPE_WINDOW)
 565     {
 566 	if (!decor_window_property (prop, nOffset, size, &input, &maxInput,
 567 				    &minWidth, &minHeight, &frameType, &frameState, &frameActions))
 568 	{
 569 	    compLogMessage ("decor", CompLogLevelWarn, "malformed decoration - not a window");
 570 	    throw std::exception ();
 571 	}
 572 
 573 	border = input;
 574 	maxBorder = maxInput;
 575     }
 576     else
 577     {
 578 	compLogMessage ("decor", CompLogLevelWarn, "malformed decoration - undetermined type");
 579 	throw std::exception ();
 580     }
 581 
 582     return Decoration::Ptr (new Decoration (type, border, input, maxBorder, maxInput, frameType, frameState, frameActions, minWidth, minHeight, pixmap, quad, nQuad, id, requestor));
 583 }
 584 
 585 Decoration::Decoration (int   type,
 586 			const decor_extents_t &border,
 587 			const decor_extents_t &input,
 588 			const decor_extents_t &maxBorder,
 589 			const decor_extents_t &maxInput,
 590 			unsigned int frameType,
 591 			unsigned int frameState,
 592 			unsigned int frameActions,
 593 			unsigned int minWidth,
 594 			unsigned int minHeight,
 595 			Pixmap       pixmap,
 596 			const boost::shared_array <decor_quad_t> &quad,
 597 			unsigned int nQuad,
 598 			Window       owner,
 599 			DecorPixmapRequestorInterface *requestor) :
 600     refCount (0),
 601     texture (DecorScreen::get (screen)->getTexture (pixmap)),
 602     border (border.left, border.right, border.top, border.bottom),
 603     input (input.left, input.right, input.top, input.bottom),
 604     maxBorder (maxBorder.left, maxBorder.right, maxBorder.top, maxBorder.bottom),
 605     maxInput (maxInput.left, maxInput.right, maxInput.top, maxInput.bottom),
 606     minWidth (minWidth),
 607     minHeight (minHeight),
 608     frameType (frameType),
 609     frameState (frameState),
 610     frameActions (frameActions),
 611     quad (quad),
 612     nQuad (nQuad),
 613     type (type),
 614     updateState (0),
 615     mPixmapReceiver (requestor, this)
 616 {
 617     int		    x1, y1, x2, y2;
 618 
 619     if (!texture && type == WINDOW_DECORATION_TYPE_PIXMAP)
 620     {
 621         compLogMessage ("decor", CompLogLevelWarn, "failed to bind pixmap to texture");
 622 	throw std::exception ();
 623     }
 624 
 625     if (type == WINDOW_DECORATION_TYPE_PIXMAP)
 626     {
 627 	int left = 0, right = minWidth, top = 0, bottom = minHeight;
 628 
 629 	for (unsigned int i = 0; i  < nQuad; i++)
 630 	{
 631 	    computeQuadBox (&(quad[i]), minWidth, minHeight, &x1, &y1, &x2, &y2,
 632 			    NULL, NULL);
 633 
 634 	    if (x1 < left)
 635 		left = x1;
 636 	    if (y1 < top)
 637 		top = y1;
 638 	    if (x2 > right)
 639 		right = x2;
 640 	    if (y2 > bottom)
 641 		bottom = y2;
 642 	}
 643 
 644 	this->output.left   = -left;
 645 	this->output.right  = right - minWidth;
 646 	this->output.top    = -top;
 647 	this->output.bottom = bottom - minHeight;
 648     }
 649     else
 650     {
 651 	this->output.left   = MAX (input.left, maxInput.left);
 652 	this->output.right  = MAX (input.right, maxInput.right);
 653 	this->output.top    = MAX (input.top, maxInput.top);
 654 	this->output.bottom = MAX (input.bottom, maxInput.bottom);
 655     }
 656 }
 657 
 658 /*
 659  * Decoration::~Decoration
 660  *
 661  * Unreferences the decoration, also unreferences the texture
 662  * if this decoration is about to be destroyed
 663  *
 664  */
 665 
 666 Decoration::~Decoration ()
 667 {
 668     if (texture)
 669 	DecorScreen::get (screen)->releaseTexture (texture);
 670 }
 671 
 672 DecorPixmapReceiverInterface &
 673 Decoration::receiverInterface ()
 674 {
 675     return mPixmapReceiver;
 676 }
 677 
 678 unsigned int
 679 Decoration::getFrameType () const
 680 {
 681     return frameType;
 682 }
 683 
 684 unsigned int
 685 Decoration::getFrameState () const
 686 {
 687     return frameState;
 688 }
 689 
 690 unsigned int
 691 Decoration::getFrameActions () const
 692 {
 693     return frameActions;
 694 }
 695 
 696 /*
 697  * DecorationList is a class which allows multiple decorations
 698  * to be stored in a list and read from a window property, which
 699  * allows caching to be done for decorations so that we aren't
 700  * always querying another process for decorations
 701  *
 702  */
 703 
 704 DecorationList::DecorationList () :
 705     mList (0)
 706 {
 707 }
 708 
 709 /*
 710  * DecorationList::updateDecoration
 711  *
 712  * Fetches the window property for a particular
 713  * window for this decoration list on a particular
 714  * decoration atom (whether that be the default
 715  * atom on the root window or the _COMPIZ_WINDOW_DECOR
 716  * atom on the client)
 717  *
 718  * Note that due to the way XGetWindowProperty works,
 719  * we only cache what is appropriate and then get the
 720  * rest from the property in case we didn't read enough
 721  * data. It would be awesome if XGetWindowProperty allowed
 722  * you to read as much as you wanted.
 723  *
 724  * FIXME: Currently this function refreshes all decorations.
 725  * That's slow and should be fixed
 726  *
 727  */
 728 
 729 bool
 730 DecorationList::updateDecoration (Window   id,
 731 				  Atom     decorAtom,
 732 				  DecorPixmapRequestorInterface *requestor)
 733 {
 734     unsigned long   n, nleft;
 735     unsigned char   *data;
 736     long	    *prop;
 737     Atom	    actual;
 738     int		    result, format;
 739     unsigned int    type;
 740 
 741     /* Dispatch any new updates */
 742     foreach (const Decoration::Ptr &d, mList)
 743     {
 744 	d->mPixmapReceiver.update ();
 745     }
 746 
 747     result = XGetWindowProperty (screen->dpy (), id,
 748                                  decorAtom, 0L,
 749                                  PROP_HEADER_SIZE + 6 * (BASE_PROP_SIZE +
 750                                                          QUAD_PROP_SIZE * N_QUADS_MAX),
 751                                  false, XA_INTEGER, &actual, &format,
 752 				 &n, &nleft, &data);
 753 
 754     if (result != Success || !n || !data)
 755         return false;
 756 
 757     /* Attempted to read the reasonable amount of
 758      * around 6 pixmap decorations, if there are more, we need
 759      * an additional roundtrip to read everything else
 760      */
 761     if (nleft)
 762     {
 763         XFree (data);
 764 
 765         result = XGetWindowProperty (screen->dpy (), id, decorAtom, 0L,
 766                                      n + nleft, false, XA_INTEGER, &actual, &format,
 767                                      &n, &nleft, &data);
 768 
 769         if (result != Success || !n || !data)
 770             return false;
 771     }
 772 
 773     prop = (long *) data;
 774 
 775     if (decor_property_get_version (prop) != decor_version ())
 776     {
 777 	compLogMessage ("decoration", CompLogLevelWarn,
 778 			"Property ignored because "
 779 			"version is %d and decoration plugin version is %d\n",
 780 			decor_property_get_version (prop), decor_version ());
 781 
 782 	XFree (data);
 783 	return false;
 784     }
 785 
 786     type = decor_property_get_type (prop);
 787 
 788     std::list <Decoration::Ptr> remove;
 789     std::list <int> skip;
 790 
 791     /* only recreate decorations if they need to be updated */
 792     foreach (const Decoration::Ptr &d, mList)
 793     {
 794 	decor_extents_t input, border, maxInput, maxBorder;
 795 
 796 	input.left = d->input.left;
 797 	input.right = d->input.right;
 798 	input.top = d->input.top;
 799 	input.bottom = d->input.bottom;
 800 
 801 	border.left = d->border.left;
 802 	border.right = d->border.right;
 803 	border.top = d->border.top;
 804 	border.bottom = d->border.bottom;
 805 
 806 	maxInput.left = d->maxInput.left;
 807 	maxInput.right = d->maxInput.right;
 808 	maxInput.top = d->maxInput.top;
 809 	maxInput.bottom = d->maxInput.bottom;
 810 
 811 	maxBorder.left = d->maxBorder.left;
 812 	maxBorder.right = d->maxBorder.right;
 813 	maxBorder.top = d->maxBorder.top;
 814 	maxBorder.bottom = d->maxBorder.bottom;
 815 
 816 	Pixmap pm = d->texture->pixmap->getPixmap ();
 817 
 818 	int num = decor_match_pixmap (prop, n, &pm, &input, &border, &maxInput, &maxBorder,
 819 				     d->minWidth, d->minHeight, d->frameType, d->frameState, d->frameActions,
 820 				    d->quad.get (), d->nQuad);
 821 	if (num != -1)
 822 	    skip.push_back (num);
 823 	else
 824 	    remove.push_back (d);
 825     }
 826 
 827     /* Create a new decoration for each individual item on the property */
 828     for (int i = 0; i < decor_property_get_num (prop); i++)
 829     {
 830 	if (std::find (skip.begin (), skip.end (), i) != skip.end ())
 831 	    continue;
 832 
 833 	try
 834 	{
 835 	    std::list <Decoration::Ptr>::iterator it = mList.begin ();
 836 	    Decoration::Ptr d = Decoration::create (id, prop, n, type, i, requestor);
 837 
 838 	    /* Try to replace an existing decoration */
 839 	    for (; it != mList.end (); ++it)
 840 	    {
 841 		if ((*it)->frameType == d->frameType &&
 842 		    (*it)->frameState == d->frameState &&
 843 		    (*it)->frameActions == d->frameActions)
 844 		{
 845 		    remove.remove ((*it));
 846 		    (*it) = d;
 847 		    break;
 848 		}
 849 	    }
 850 
 851 	    if (it == mList.end ())
 852 		mList.push_back (d);
 853 	}
 854 	catch (...)
 855 	{
 856 	    /* Creating a new decoration failed ... see if we can use
 857 	     * the old one */
 858 
 859 	    unsigned int    frameType, frameState, frameActions;
 860 	    Pixmap	    pixmap = None;
 861 	    decor_extents_t border;
 862 	    decor_extents_t input;
 863 	    decor_extents_t maxBorder;
 864 	    decor_extents_t maxInput;
 865 	    int		    minWidth;
 866 	    int		    minHeight;
 867 	    int             ok = 0;
 868 	    boost::shared_array <decor_quad_t> quad (new decor_quad_t[N_QUADS_MAX]);
 869 
 870 	    if (type == WINDOW_DECORATION_TYPE_PIXMAP)
 871 	    {
 872 		ok = decor_pixmap_property_to_quads (prop, i, n, &pixmap, &input,
 873 							&border, &maxInput,
 874 							&maxBorder, &minWidth, &minHeight,
 875 							&frameType, &frameState, &frameActions, quad.get ());
 876 	    }
 877 	    else if (type == WINDOW_DECORATION_TYPE_WINDOW)
 878 	    {
 879 		ok = decor_window_property (prop, i, n, &input, &maxInput,
 880 					    &minWidth, &minHeight, &frameType, &frameState, &frameActions);
 881 	    }
 882 
 883 	    if (ok)
 884 	    {
 885 		std::list <Decoration::Ptr>::iterator it = mList.begin ();
 886 
 887 		/* Use an existing decoration */
 888 		for (; it != mList.end (); ++it)
 889 		{
 890 		    if ((*it)->frameType == frameType &&
 891 			(*it)->frameState == frameState &&
 892 			(*it)->frameActions == frameActions)
 893 		    {
 894 			remove.remove ((*it));
 895 			break;
 896 		    }
 897 		}
 898 	    }
 899 	}
 900     }
 901 
 902     foreach (const Decoration::Ptr &d, remove)
 903 	mList.remove (d);
 904 
 905     XFree (data);
 906 
 907     return true;
 908 }
 909 
 910 /*
 911  * DecorWindow::updateDecoration
 912  *
 913  * Updates the decoration list on this window
 914  */
 915 
 916 void
 917 DecorWindow::updateDecoration ()
 918 {
 919     bindFailed = false;
 920 
 921     decor.updateDecoration (window->id (), dScreen->winDecorAtom, &mRequestor);
 922     if (bindFailed)
 923 	pixmapFailed = true;
 924     else
 925 	pixmapFailed = false;
 926 }
 927 
 928 /*
 929  * WindowDecoration::create
 930  *
 931  * Factory function for WindowDecoration, creates
 932  * a window specific decoration for this window,
 933  * not to be confused with window /type/ decorations
 934  * which are a different matter.
 935  *
 936  * Decorations can indeed be re-used, and that is what
 937  * WindowDecoration is for.
 938  *
 939  */
 940 WindowDecoration *
 941 WindowDecoration::create (const Decoration::Ptr &d)
 942 {
 943     WindowDecoration *wd;
 944 
 945     wd = new WindowDecoration ();
 946     if (!wd)
 947 	return NULL;
 948 
 949     if (d->type == WINDOW_DECORATION_TYPE_PIXMAP)
 950     {
 951 	wd->quad = new ScaledQuad[d->nQuad];
 952 
 953 	if (!wd->quad)
 954 	{
 955 	    delete wd;
 956 	    return NULL;
 957 	}
 958     }
 959     else
 960 	wd->quad = NULL;
 961 
 962     d->refCount++;
 963 
 964     wd->decor = d;
 965     wd->nQuad = d->nQuad;
 966 
 967     return wd;
 968 }
 969 
 970 /*
 971  * WindowDecoration::destroy
 972  *
 973  * Unreferences the bound decoration
 974  * and frees quads
 975  */
 976 void
 977 WindowDecoration::destroy (WindowDecoration *wd)
 978 {
 979     delete [] wd->quad;
 980     delete wd;
 981 }
 982 
 983 /*
 984  * DecorWindow::setDecorationMatrices
 985  *
 986  * Statically update the quad display matrices
 987  * (2x3 matrix) each time the window is moved
 988  * or resized
 989  *
 990  * For this to work, we need to multiply the
 991  * scaled quad and decor quad matrices together
 992  * to get the final scaled transformation
 993  *
 994  * Translation (x0, y0) is based on the actual box
 995  * position in decoration co-ordinate space multiplied
 996  * by the scaled transformation matrix
 997  */
 998 void
 999 DecorWindow::setDecorationMatrices ()
1000 {
1001     float	      x0, y0;
1002     decor_matrix_t    a;
1003     GLTexture::Matrix b;
1004 
1005     if (!wd)
1006 	return;
1007 
1008     for (int i = 0; i < wd->nQuad; i++)
1009     {
1010 	/* Set the quad matrix to the texture matrix */
1011 	wd->quad[i].matrix = wd->decor->texture->textures[0]->matrix ();
1012 
1013 	/* Initial translation point is based on existing translation point */
1014 	x0 = wd->decor->quad[i].m.x0;
1015 	y0 = wd->decor->quad[i].m.y0;
1016 
1017 	a = wd->decor->quad[i].m;
1018 	b = wd->quad[i].matrix;
1019 
1020 	/* Multiply wd->quad[i].matrix (decoration matrix)
1021 	 * and the scaled quad matrix */
1022 	wd->quad[i].matrix.xx = a.xx * b.xx + a.yx * b.xy;
1023 	wd->quad[i].matrix.yx = a.xx * b.yx + a.yx * b.yy;
1024 	wd->quad[i].matrix.xy = a.xy * b.xx + a.yy * b.xy;
1025 	wd->quad[i].matrix.yy = a.xy * b.yx + a.yy * b.yy;
1026 	wd->quad[i].matrix.x0 = x0 * b.xx + y0 * b.xy + b.x0;
1027 	wd->quad[i].matrix.y0 = x0 * b.yx + y0 * b.yy + b.y0;
1028 
1029 	wd->quad[i].matrix.xx *= wd->quad[i].sx;
1030 	wd->quad[i].matrix.yx *= wd->quad[i].sx;
1031 	wd->quad[i].matrix.xy *= wd->quad[i].sy;
1032 	wd->quad[i].matrix.yy *= wd->quad[i].sy;
1033 
1034 	/* Align translation points to the right
1035 	 * in the scaled quad (window) space */
1036 	if (wd->decor->quad[i].align & ALIGN_RIGHT)
1037 	    x0 = wd->quad[i].box.x2 - wd->quad[i].box.x1;
1038 	else
1039 	    x0 = 0.0f;
1040 
1041 	/* Align translation points to the bottom
1042 	 * in the scaled quad (window) space */
1043 	if (wd->decor->quad[i].align & ALIGN_BOTTOM)
1044 	    y0 = wd->quad[i].box.y2 - wd->quad[i].box.y1;
1045 	else
1046 	    y0 = 0.0f;
1047 
1048 	wd->quad[i].matrix.x0 -=
1049 	    x0 * wd->quad[i].matrix.xx +
1050 	    y0 * wd->quad[i].matrix.xy;
1051 
1052 	wd->quad[i].matrix.y0 -=
1053 	    y0 * wd->quad[i].matrix.yy +
1054 	    x0 * wd->quad[i].matrix.yx;
1055 
1056 	wd->quad[i].matrix.x0 -=
1057 	    wd->quad[i].box.x1 * wd->quad[i].matrix.xx +
1058 	    wd->quad[i].box.y1 * wd->quad[i].matrix.xy;
1059 
1060 	wd->quad[i].matrix.y0 -=
1061 	    wd->quad[i].box.y1 * wd->quad[i].matrix.yy +
1062 	    wd->quad[i].box.x1 * wd->quad[i].matrix.yx;
1063     }
1064 
1065     updateMatrix = false;
1066 }
1067 
1068 /*
1069  * DecorWindow::updateDecorationScale
1070  *
1071  * Update the scaled quads box for this
1072  * window. Do that by determining
1073  * the scaled quad box for the window size
1074  * and then translating each quad box by
1075  * the window position
1076  *
1077  */
1078 
1079 void
1080 DecorWindow::updateDecorationScale ()
1081 {
1082     int		     x1, y1, x2, y2;
1083     float            sx, sy;
1084 
1085     if (!wd)
1086 	return;
1087 
1088     for (int i = 0; i < wd->nQuad; i++)
1089     {
1090 	int x, y;
1091 	unsigned int width = window->size ().width ();
1092 	unsigned int height = window->size ().height ();
1093 
1094 	if (window->shaded ())
1095 	{
1096 	    if (dScreen->cScreen &&
1097 		dScreen->cScreen->compositingActive ())
1098 	    {
1099 		if (!cWindow->pixmap ())
1100 		    height = 0;
1101 	    }
1102 	    else
1103 		height = 0;
1104 	}
1105 
1106 	computeQuadBox (&wd->decor->quad[i], width, height,
1107 			&x1, &y1, &x2, &y2, &sx, &sy);
1108 
1109 	/* Translate by x and y points of this window */
1110 	x = window->geometry ().x ();
1111 	y = window->geometry ().y ();
1112 
1113 	wd->quad[i].box.x1 = x1 + x;
1114 	wd->quad[i].box.y1 = y1 + y;
1115 	wd->quad[i].box.x2 = x2 + x;
1116 	wd->quad[i].box.y2 = y2 + y;
1117 
1118 	wd->quad[i].sx     = sx;
1119 	wd->quad[i].sy     = sy;
1120     }
1121 
1122     setDecorationMatrices ();
1123 }
1124 
1125 /*
1126  * DecorWindow::checkSize
1127  *
1128  * Convenience function to check if this decoration
1129  * is going to display laerger than the window size
1130  * itself, in that case we can't use it since it
1131  * would like the decoration was larger than the window
1132  * (or trying to compress it anymore would result in
1133  * eg, distorted text or buttons). In that case
1134  * we'd use default decorations
1135  *
1136  */
1137 bool
1138 DecorWindow::checkSize (const Decoration::Ptr &decoration)
1139 {
1140     return (decoration->minWidth <= (int) window->size ().width () &&
1141 	    decoration->minHeight <= (int) window->size ().height ());
1142 }
1143 
1144 /*
1145  * decorOffsetMove
1146  *
1147  * Function called on a timer (to avoid calling configureXWindow from
1148  * within a ::moveNotify) which actually moves the window by the offset
1149  * specified in the xwc. Also sends a notification that the window
1150  * was decorated
1151  *
1152  */
1153 static bool
1154 decorOffsetMove (CompWindow *w, XWindowChanges xwc, unsigned int mask)
1155 {
1156     CompOption::Vector o (1);
1157 
1158     o.at (0).setName ("window", CompOption::TypeInt);
1159     o.at (0).value ().set ((int) w->id ());
1160 
1161     xwc.x += w->serverGeometry ().x ();
1162     xwc.y += w->serverGeometry ().y ();
1163 
1164     w->configureXWindow (mask, &xwc);
1165     screen->handleCompizEvent ("decor", "window_decorated", o);
1166     return false;
1167 }
1168 
1169 /*
1170  * DecorWindow::matchType
1171  *
1172  * Converts libdecoration window types packed
1173  * into the property into Compiz window types
1174  *
1175  */
1176 bool
1177 DecorWindow::matchType (CompWindow *w,
1178                         unsigned int decorType)
1179 {
1180     const unsigned int nTypeStates = 5;
1181     struct typestate {
1182         unsigned int compFlag;
1183         unsigned int decorFlag;
1184     } typeStates[] =
1185     {
1186         { CompWindowTypeNormalMask, DECOR_WINDOW_TYPE_NORMAL },
1187         { CompWindowTypeDialogMask, DECOR_WINDOW_TYPE_DIALOG },
1188         { CompWindowTypeModalDialogMask, DECOR_WINDOW_TYPE_MODAL_DIALOG },
1189         { CompWindowTypeMenuMask, DECOR_WINDOW_TYPE_MENU },
1190         { CompWindowTypeUtilMask, DECOR_WINDOW_TYPE_UTILITY}
1191     };
1192 
1193     for (unsigned int i = 0; i < nTypeStates; i++)
1194     {
1195         if ((decorType & typeStates[i].decorFlag) && (w->type () & typeStates[i].compFlag))
1196             return true;
1197     }
1198 
1199     return false;
1200 }
1201 
1202 /*
1203  * DecorWindow::matchType
1204  *
1205  * Converts libdecoration window states packed
1206  * into the property into Compiz window states
1207  *
1208  * Since there is no _NET_WM_STATE_ACTIVE
1209  * we need to determine that ourselves from
1210  * _NET_ACTIVE_WINDOW on the root window
1211  *
1212  */
1213 bool
1214 DecorWindow::matchState (CompWindow   *w,
1215                          unsigned int decorState)
1216 {
1217     const unsigned int nStateStates = 3;
1218     struct statestate {
1219         unsigned int compFlag;
1220         unsigned int decorFlag;
1221     } stateStates[] =
1222     {
1223         { CompWindowStateMaximizedVertMask, DECOR_WINDOW_STATE_MAXIMIZED_VERT },
1224         { CompWindowStateMaximizedHorzMask, DECOR_WINDOW_STATE_MAXIMIZED_HORZ },
1225         { CompWindowStateShadedMask, DECOR_WINDOW_STATE_SHADED }
1226     };
1227 
1228     /* Active is a separate check */
1229     if (screen->activeWindow () == w->id ())
1230         decorState &= ~(DECOR_WINDOW_STATE_FOCUS);
1231 
1232     for (unsigned int i = 0; i < nStateStates; i++)
1233     {
1234         if ((decorState & stateStates[i].decorFlag) && (w->state () & stateStates[i].compFlag))
1235             decorState &= ~(stateStates[i].decorFlag);
1236     }
1237 
1238     return (decorState == 0);
1239 }
1240 
1241 /*
1242  * DecorWindow::matchActions
1243  *
1244  * Converts libdecoration window actions packed
1245  * into the property into Compiz window types
1246  *
1247  */
1248 bool
1249 DecorWindow::matchActions (CompWindow   *w,
1250                            unsigned int decorActions)
1251 {
1252     const unsigned int nActionStates =16;
1253     struct actionstate {
1254         unsigned int compFlag;
1255         unsigned int decorFlag;
1256     } actionStates[] =
1257     {
1258         { DECOR_WINDOW_ACTION_RESIZE_HORZ, CompWindowActionResizeMask },
1259         { DECOR_WINDOW_ACTION_RESIZE_VERT, CompWindowActionResizeMask },
1260         { DECOR_WINDOW_ACTION_CLOSE, CompWindowActionCloseMask },
1261         { DECOR_WINDOW_ACTION_MINIMIZE, CompWindowActionMinimizeMask },
1262         { DECOR_WINDOW_ACTION_UNMINIMIZE,CompWindowActionMinimizeMask },
1263         { DECOR_WINDOW_ACTION_MAXIMIZE_HORZ, CompWindowActionMaximizeHorzMask },
1264         { DECOR_WINDOW_ACTION_MAXIMIZE_VERT, CompWindowActionMaximizeVertMask },
1265         { DECOR_WINDOW_ACTION_UNMAXIMIZE_HORZ, CompWindowActionMaximizeHorzMask },
1266         { DECOR_WINDOW_ACTION_UNMAXIMIZE_VERT, CompWindowActionMaximizeVertMask },
1267         { DECOR_WINDOW_ACTION_SHADE, CompWindowActionShadeMask },
1268         { DECOR_WINDOW_ACTION_UNSHADE, CompWindowActionShadeMask },
1269         { DECOR_WINDOW_ACTION_STICK, CompWindowActionStickMask },
1270         { DECOR_WINDOW_ACTION_UNSTICK, CompWindowActionStickMask },
1271         { DECOR_WINDOW_ACTION_FULLSCREEN, CompWindowActionFullscreenMask },
1272         { DECOR_WINDOW_ACTION_ABOVE, CompWindowActionAboveMask },
1273         { DECOR_WINDOW_ACTION_BELOW, CompWindowActionBelowMask },
1274     };
1275 
1276     for (unsigned int i = 0; i < nActionStates; i++)
1277     {
1278         if ((decorActions & actionStates[i].decorFlag) && (w->type () & actionStates[i].compFlag))
1279             decorActions &= ~(actionStates[i].decorFlag);
1280     }
1281 
1282     return (decorActions == 0);
1283 }
1284 
1285 DecorationInterface::Ptr
1286 DecorationList::findMatchingDecoration (unsigned int frameType,
1287 					unsigned int frameState,
1288 					unsigned int frameActions)
1289 {
1290     foreach (const Decoration::Ptr &d, mList)
1291     {
1292 	if (d->frameType == frameType &&
1293 	    d->frameState == frameState &&
1294 	    d->frameActions == frameActions)
1295 	    return boost::shared_static_cast <DecorationInterface> (d);
1296     }
1297 
1298     return DecorationInterface::Ptr ();
1299 }
1300 
1301 /*
1302  * DecorationList::findMatchingDecoration
1303  *
1304  * Searches a decoration list for a decoration
1305  * that actually matches this window, or at least
1306  * comes close to it.
1307  * 
1308  * There is an order of preference when matching
1309  * decorations here.
1310  *
1311  * Type:State:Actions
1312  *
1313  * If a property before another one is matched, that
1314  * decoration is "locked" so if a decoration is found
1315  * that has the correct matching property but does not
1316  * match the locked property, then it is not matched
1317  *
1318  */
1319 const Decoration::Ptr &
1320 DecorationList::findMatchingDecoration (CompWindow *w,
1321                                         bool       sizeCheck)
1322 {
1323     std::list <Decoration::Ptr>::iterator cit = mList.end ();
1324     DECOR_WINDOW (w);
1325 
1326     if (!mList.empty ())
1327     {
1328         const unsigned int typeMatch = (1 << 0);
1329         const unsigned int stateMatch = (1 << 1);
1330         const unsigned int actionsMatch = (1 << 2);
1331 
1332         unsigned int currentDecorState = 0;
1333 
1334 	if (sizeCheck)
1335 	    if (dw->checkSize (mList.front ()))
1336 		cit = mList.begin ();
1337 
1338 	for (std::list <Decoration::Ptr>::iterator it = mList.begin ();
1339 	     it != mList.end (); ++it)
1340 	{
1341 	    const Decoration::Ptr &d = *it;
1342 
1343 	    /* Must always match type */
1344 	    if (DecorWindow::matchType (w, d->frameType))
1345 	    {
1346 		/* Use this decoration if the type matched */
1347 		if (!(typeMatch & currentDecorState) && (!sizeCheck || dw->checkSize (d)))
1348 		{
1349 		    cit = it;
1350 		    currentDecorState |= typeMatch;
1351 		}
1352 
1353 		/* Must always match state if type is already matched */
1354 		if (DecorWindow::matchState (w, d->frameState) && (!sizeCheck || dw->checkSize (d)))
1355 		{
1356 		    /* Use this decoration if the type and state match */
1357 		    if (!(stateMatch & currentDecorState))
1358 		    {
1359 			cit = it;
1360 			currentDecorState |= stateMatch;
1361 		    }
1362 
1363 		    /* Must always match actions if state and type are already matched */
1364 		    if (DecorWindow::matchActions (w, d->frameActions) && (!sizeCheck || dw->checkSize (d)))
1365 		    {
1366 			/* Use this decoration if the requested actions match */
1367 			if (!(actionsMatch & currentDecorState))
1368 			{
1369 			    cit = it;
1370 			    currentDecorState |= actionsMatch;
1371 
1372 			    /* Perfect match, no need to continue searching */
1373 			    break;
1374 			}
1375 		    }
1376 		}
1377 	    }
1378 	}
1379     }
1380 
1381     if (cit == mList.end ())
1382 	throw std::exception ();
1383 
1384     return *cit;
1385 }
1386 
1387 /*
1388  * DecorWindow::update
1389  * This is the master function for managing decorations on windows
1390  *
1391  * The first part of this function determines if we want to actually
1392  * decorate a particular window. This only passes if the window
1393  * matches the decorated type match and it is also capable of being
1394  * decorated (eg, has a frame window and not override redirect) and
1395  * also has appropriate _MOTIF_WM_HINTS set on it (specifically 0x3
1396  * and 0x6)
1397  *
1398  * The next part of the function attempts to find a matching decoration
1399  * has has been created by the decorators. If it can't find one, the
1400  * window gets a default decoration (until the decorators have "caught
1401  * up" with us and given this window an actual decoration.
1402  *
1403  * Windows that we've marked not to decorate get shadows around them
1404  * at least. This is the "bare" type decoration
1405  *
1406  * If an appropriate decoration is found for this window, a WindowDecoration
1407  * (which is a window specific class determining how that decoration
1408  *  should operate on /this particular window/) is created.
1409  *
1410  * At this point we also update the "frame extents" in core (for
1411  * _NET_REQUEST_FRAME_EXTENTS) and also the actual frame geometry
1412  * since we might need a larger space on the frame window (which is
1413  * shaped to accomadate decorations) for things like, eg grab areas
1414  * which shouldn't be represented to clients as actual visible
1415  * decoration space
1416  *
1417  * FIXME: There are a bunch of hacks in here to allow override redirect
1418  * windows which have "special" switcher type decorations to be decorated
1419  * without being reparented. Ideally, these shouldn't be handled by 
1420  * the decor plugin
1421  *
1422  */
1423 bool
1424 DecorWindow::update (bool allowDecoration)
1425 {
1426     Decoration::Ptr  old, decoration;
1427     bool	     decorate = false;
1428     bool	     shadowOnly = true;
1429     CompPoint        oldShift, movement;
1430 
1431     if (wd)
1432 	old = wd->decor;
1433     else
1434 	old.reset ();
1435 
1436     /* Only want to decorate windows which have a frame or are in the process
1437      * of waiting for an animation to be unmapped (in which case we can give
1438      * them a new pixmap type frame since we don't actually need an input
1439      * window to go along with that
1440      *
1441      * FIXME: That's not going to play nice with reparented decorations in core
1442      * since the window gets reparented right away before plugins are done
1443      * with it */
1444 
1445     /* Unconditionally decorate switchers */
1446     if (!isSwitcher)
1447     {
1448         switch (window->type ()) {
1449 	    case CompWindowTypeDialogMask:
1450 	    case CompWindowTypeModalDialogMask:
1451 	    case CompWindowTypeUtilMask:
1452 	    case CompWindowTypeMenuMask:
1453 	    case CompWindowTypeNormalMask:
1454 		if (window->mwmDecor () & (MwmDecorAll | MwmDecorTitle))
1455 		    shadowOnly = false;
1456 	    default:
1457 		break;
1458 	}
1459 
1460 	if (window->overrideRedirect ())
1461 	    shadowOnly = true;
1462 
1463 	if (window->wmType () & (CompWindowTypeDockMask | CompWindowTypeDesktopMask))
1464 	    shadowOnly = true;
1465 
1466 	if (!shadowOnly)
1467 	{
1468 	    if (!dScreen->optionGetDecorationMatch ().evaluate (window))
1469 		shadowOnly = true;
1470 	}
1471     }
1472     else
1473 	shadowOnly = false;
1474 
1475     decorate = ((window->frame () ||
1476 		 window->hasUnmapReference ()) && !shadowOnly) ||
1477 		 isSwitcher;
1478 
1479     if (decorate || frameExtentsRequested)
1480     {
1481         /* Attempt to find a matching decoration */
1482 	try
1483 	{
1484 	    decoration = decor.findMatchingDecoration (window, true);
1485 	}
1486 	catch (...)
1487 	{
1488 	    /* Find an appropriate default decoration to use */
1489 	    if (dScreen->dmSupports & WINDOW_DECORATION_TYPE_PIXMAP &&
1490 	        dScreen->cmActive &&
1491 		!(dScreen->dmSupports & WINDOW_DECORATION_TYPE_WINDOW &&
1492 		  pixmapFailed))
1493 	    {
1494 		try
1495 		{
1496 		    decoration = dScreen->decor[DECOR_ACTIVE].findMatchingDecoration (window, false);
1497 		}
1498 		catch (...)
1499 		{
1500 		    compLogMessage ("decor", CompLogLevelWarn, "No default decoration found, placement will not be correct");
1501 		    decoration.reset ();
1502 		}
1503 	    }
1504 	    else if (dScreen->dmSupports & WINDOW_DECORATION_TYPE_WINDOW)
1505 		decoration = dScreen->windowDefault;
1506 	}
1507 
1508 	/* Do not allow windows which are later undecorated
1509 	 * to have a set _NET_FRAME_EXTENTS */
1510 	if (decorate)
1511 	    frameExtentsRequested = false;
1512     }
1513     else
1514     {
1515 	/* This window isn't "decorated" but it still gets a shadow as long
1516 	 * as it isn't shaped weirdly, since the shadow is just a quad rect */
1517 	if (dScreen->optionGetShadowMatch ().evaluate (window))
1518 	{
1519 	    if (window->region ().numRects () == 1 && !window->alpha () && dScreen->decor[DECOR_BARE].mList.size ())
1520 		decoration = dScreen->decor[DECOR_BARE].mList.front ();
1521 
1522 	    if (decoration)
1523 	    {
1524 		if (!checkSize (decoration))
1525 		    decoration.reset ();
1526 	    }
1527 	}
1528     }
1529 
1530     /* Don't allow the windows to be decorated if
1531      * we're tearing down or if a decorator isn't running
1532      * (nobody owns the selection window) 
1533      */
1534     if (!dScreen->dmWin || !allowDecoration)
1535 	decoration.reset ();
1536 
1537     /* Don't bother going any further if
1538      * this window is going to get the same
1539      * decoration, just use the old one */
1540     if (decoration == old)
1541 	return false;
1542 
1543     /* We need to damage the current output extents
1544      * and recompute the shadow region if a compositor
1545      * is running
1546      */
1547     if (dScreen->cmActive)
1548     {
1549 	cWindow->damageOutputExtents ();
1550 	updateGroupShadows ();
1551     }
1552 
1553     /* Determine how much we moved the window for the old
1554      * decoration and save that, also destroy the old
1555      * WindowDecoration */
1556     if (old)
1557     {
1558 	oldShift = compiz::window::extents::shift (window->border (), window->sizeHints ().win_gravity);
1559 
1560 	WindowDecoration::destroy (wd);
1561 
1562 	wd = NULL;
1563     }
1564 
1565     /* If a decoration was found for this window, create
1566      * a new WindowDecoration for it and set the frame
1567      * extents accordingly. We should also move the
1568      * window by the distance the new decoration provides
1569      * in case that actually changed
1570      */
1571     if (decoration)
1572     {
1573 	wd = WindowDecoration::create (decoration);
1574 	if (!wd)
1575 	    return false;
1576 
1577 	/* Set extents based on maximize/unmaximize state
1578 	 * FIXME: With the new type system, this should be
1579 	 * removed */
1580 	if ((window->state () & MAXIMIZE_STATE))
1581 	    window->setWindowFrameExtents (&wd->decor->maxBorder,
1582 					   &wd->decor->maxInput);
1583 	else if (!window->hasUnmapReference ())
1584 	    window->setWindowFrameExtents (&wd->decor->border,
1585 					   &wd->decor->input);
1586 
1587 	movement = compiz::window::extents::shift (window->border (), window->sizeHints ().win_gravity);
1588 	movement -= oldShift;
1589 
1590 	/* Update the input and output frame */
1591 	if (decorate)
1592 	    updateFrame ();
1593 	window->updateWindowOutputExtents ();
1594 
1595 	updateReg = true;
1596 	updateMatrix = true;
1597 	mOutputRegion = CompRegion (window->outputRect ());
1598 	updateGroupShadows ();
1599 	if (dScreen->cmActive)
1600 	    cWindow->damageOutputExtents ();
1601 	updateDecorationScale ();
1602     }
1603     else
1604     {
1605 	CompWindowExtents emptyExtents;
1606 	wd = NULL;
1607 
1608 	/* Undecorated windows need to have the
1609 	 * input and output frame removed and the
1610 	 * frame window geometry reset */
1611 	updateFrame ();
1612 
1613 	memset (&emptyExtents, 0, sizeof (CompWindowExtents));
1614 
1615 	window->setWindowFrameExtents (&emptyExtents, &emptyExtents);
1616 
1617 	movement -= oldShift;
1618     }
1619 
1620     /* Need to actually move the window */
1621     if (window->placed () && !window->overrideRedirect () &&
1622 	(movement.x () || movement.y ()))
1623     {
1624 	XWindowChanges xwc;
1625 	unsigned int   mask = CWX | CWY;
1626 
1627 	memset (&xwc, 0, sizeof (XWindowChanges));
1628 
1629 	/* Grab the geometry last sent to server at configureXWindow
1630 	 * time and not here since serverGeometry may be updated by
1631 	 * the time that we do call configureXWindow */
1632 	xwc.x = movement.x ();
1633 	xwc.y = movement.y ();
1634 
1635 	/* Except if it's fullscreen, maximized or such */
1636 	if (window->state () & CompWindowStateFullscreenMask)
1637 	    mask &= ~(CWX | CWY);
1638 
1639 	if (window->state () & CompWindowStateMaximizedHorzMask)
1640 	    mask &= ~CWX;
1641 
1642 	if (window->state () & CompWindowStateMaximizedVertMask)
1643 	    mask &= ~CWY;
1644 
1645 	if (window->saveMask () & CWX)
1646 	    window->saveWc ().x += movement.x ();
1647 
1648 	if (window->saveMask () & CWY)
1649 	    window->saveWc ().y += movement.y ();
1650 
1651 	if (mask)
1652 	{
1653 	    /* allowDecoration is only false in the case of
1654 	     * the destructor calling the update function so since it
1655 	     * is not safe to put the function in a timer (since
1656 	     * it will get unref'd on the vtable destruction) we
1657 	     * need to do it immediately
1658 	     *
1659 	     * FIXME: CompTimer should really be PIMPL and allow
1660 	     * refcounting in case we need to keep it alive
1661 	     */
1662 	    if (!allowDecoration)
1663 		decorOffsetMove (window, xwc, mask);
1664 	    else
1665 		moveUpdate.start (boost::bind (decorOffsetMove, window, xwc, mask), 0);
1666 	}
1667     }
1668 
1669     return true;
1670 }
1671 
1672 /*
1673  * DecorWindow::updateFrame
1674  *
1675  * Updates the actual frame window which is
1676  * used for either displaying the decoration in the case of window
1677  * type reparented decorations, or handling input events in the case
1678  * of pixmap decorations
1679  */
1680 void
1681 DecorWindow::updateFrame ()
1682 {
1683     /* Destroy the input and output frames in case the window can't
1684      * actually be decorated */
1685     if (!wd || !(window->border ().left || window->border ().right ||
1686 		 window->border ().top || window->border ().bottom) ||
1687         (wd->decor->type == WINDOW_DECORATION_TYPE_PIXMAP && outputFrame) ||
1688         (wd->decor->type == WINDOW_DECORATION_TYPE_WINDOW && inputFrame))
1689     {
1690 	if (inputFrame)
1691 	{
1692 	    XDeleteProperty (screen->dpy (), window->id (),
1693 			     dScreen->inputFrameAtom);
1694 
1695 	    if (window->frame ())
1696 		XDestroyWindow (screen->dpy (), inputFrame);
1697 
1698 	    inputFrame = None;
1699 	    frameRegion = CompRegion ();
1700 
1701 	    oldX = 0;
1702 	    oldY = 0;
1703 	    oldWidth  = 0;
1704 	    oldHeight = 0;
1705 	}
1706 	if (outputFrame)
1707 	{
1708 	    XDamageDestroy (screen->dpy (), frameDamage);
1709 	    XDeleteProperty (screen->dpy (), window->id (),
1710 			     dScreen->outputFrameAtom);
1711 
1712 	    if (window->frame ())
1713 		XDestroyWindow (screen->dpy (), outputFrame);
1714 	    dScreen->frames.erase (outputFrame);
1715 
1716 	    outputFrame = None;
1717 	    frameRegion = CompRegion ();
1718 
1719 	    oldX = 0;
1720 	    oldY = 0;
1721 	    oldWidth  = 0;
1722 	    oldHeight = 0;
1723 	}
1724     }
1725     /* If the window can be decorated, update the frames */
1726     if (wd && (window->border ().left || window->border ().right ||
1727 	       window->border ().top || window->border ().bottom))
1728     {
1729 	if (wd->decor->type == WINDOW_DECORATION_TYPE_PIXMAP)
1730 	    updateInputFrame ();
1731 	else if (wd->decor->type == WINDOW_DECORATION_TYPE_WINDOW)
1732 	    updateOutputFrame ();
1733     }
1734 }
1735 
1736 /*
1737  * DecorWindow::updateInputFrame
1738  *
1739  * Actually creates an input frame if there isn't
1740  * one, otherwise sets the shape regions on it so that
1741  * if the decoration inside the parent window ever
1742  * gets stacked on top of the client, it won't obstruct
1743  * it
1744  *
1745  * This also sets the _COMPIZ_WINDOW_DECOR_INPUT_FRAME
1746  * atom on the window. Decorators should listen for this
1747  * to determine if a window is to be decorated, and when
1748  * they get a PropertyNotify indicating that this the case
1749  * should draw a decoration and set the _COMPIZ_WINDOW_DECOR
1750  * atom in response, otherwise this window is going to
1751  * be stuck with default decorations
1752  *
1753  */
1754 void
1755 DecorWindow::updateInputFrame ()
1756 {
1757     XRectangle           rects[4];
1758     int                  x, y, width, height;
1759     CompWindow::Geometry server = window->serverGeometry ();
1760     CompWindowExtents	 input;
1761     CompWindowExtents    border;
1762     Window		 parent;
1763 
1764     /* Switchers are special, we need to put input frames
1765      * there in the root window rather than in the frame
1766      * window that this window is reparented into */
1767     if (isSwitcher)
1768 	parent = screen->root ();
1769     else
1770 	parent = window->frame ();
1771 
1772     /* Determine frame extents */
1773     if ((window->state () & MAXIMIZE_STATE))
1774     {
1775 	border = wd->decor->maxBorder;
1776 	input = wd->decor->maxInput;
1777     }
1778     else
1779     {
1780 	border = wd->decor->border;
1781 	input = wd->decor->input;
1782     }
1783 
1784     x      = window->border ().left - border.left;
1785     y      = window->border ().top - border.top;
1786     width  = server.widthIncBorders () + input.left + input.right;
1787     height = server.heightIncBorders ()+ input.top  + input.bottom ;
1788 
1789     /* Non switcher windows are rooted relative to the frame window of the client
1790      * and switchers need to be offset by the window geometry of the client */
1791     if (isSwitcher)
1792     {
1793 	x += window->x ();
1794 	y += window->y ();
1795     }
1796 
1797     /* Shaded windows automatically have no height */
1798     if (window->shaded ())
1799 	height = input.top + input.bottom;
1800 
1801     /* Since we're reparenting windows here, we need to grab the server
1802      * which sucks, but its necessary */
1803     XGrabServer (screen->dpy ());
1804 
1805     if (!inputFrame)
1806     {
1807 	XSetWindowAttributes attr;
1808 
1809 	attr.event_mask	   = StructureNotifyMask;
1810 	attr.override_redirect = true;
1811 
1812 	inputFrame = XCreateWindow (screen->dpy (), parent,
1813 				    x, y, width, height, 0, CopyFromParent,
1814 				    InputOnly, CopyFromParent,
1815 				    CWOverrideRedirect | CWEventMask,
1816 				    &attr);
1817 
1818 	XGrabButton (screen->dpy (), AnyButton, AnyModifier, inputFrame,
1819 		     true, ButtonPressMask | ButtonReleaseMask |
1820 		     ButtonMotionMask, GrabModeSync, GrabModeSync, None,
1821 		     None);
1822 
1823 	XMapWindow (screen->dpy (), inputFrame);
1824 
1825 	/* Notify the decorators that an input frame has been created on
1826 	 * this window so that they can react by actually create a decoration
1827 	 * for it (while we use the default decorations) */
1828 	XChangeProperty (screen->dpy (), window->id (),
1829 			 dScreen->inputFrameAtom, XA_WINDOW, 32,
1830 			 PropModeReplace, (unsigned char *) &inputFrame, 1);
1831 
1832 	if (screen->XShape ())
1833 	    XShapeSelectInput (screen->dpy (), inputFrame, ShapeNotifyMask);
1834 
1835 	/* invalidate the decoration so that it gets shaped */
1836 	oldX = 0;
1837 	oldY = 0;
1838 	oldWidth  = 0;
1839 	oldHeight = 0;
1840     }
1841 
1842     if (x != oldX || y != oldY || width != oldWidth || height != oldHeight)
1843     {
1844 	int    i = 0;
1845 	oldX = x;
1846 	oldY = y;
1847 	oldWidth  = width;
1848 	oldHeight = height;
1849 
1850 	XMoveResizeWindow (screen->dpy (), inputFrame, x, y,
1851 			   width, height);
1852 
1853 	/* Non switcher decorations need to be lowered in
1854 	 * in the frame to ensure that they go below
1855 	 * the window contents (so that our set input shape
1856 	 * works correctly */
1857 	if (!isSwitcher)
1858 	    XLowerWindow (screen->dpy (), inputFrame);
1859 
1860 	rects[i].x	= 0;
1861 	rects[i].y	= 0;
1862 	rects[i].width  = width;
1863 	rects[i].height = input.top;
1864 
1865 	if (rects[i].width && rects[i].height)
1866 	    i++;
1867 
1868 	rects[i].x	= 0;
1869 	rects[i].y	= input.top;
1870 	rects[i].width  = input.left;
1871 	rects[i].height = height - input.top - input.bottom;
1872 
1873 	if (rects[i].width && rects[i].height)
1874 	    i++;
1875 
1876 	rects[i].x	= width - input.right;
1877 	rects[i].y	= input.top;
1878 	rects[i].width  = input.right;
1879 	rects[i].height = height - input.top - input.bottom;
1880 
1881 	if (rects[i].width && rects[i].height)
1882 	    i++;
1883 
1884 	rects[i].x	= 0;
1885 	rects[i].y	= height - input.bottom;
1886 	rects[i].width  = width;
1887 	rects[i].height = input.bottom;
1888 
1889 	if (rects[i].width && rects[i].height)
1890 	    i++;
1891 
1892 	XShapeCombineRectangles (screen->dpy (), inputFrame,
1893 				 ShapeInput, 0, 0, rects, i,
1894 				 ShapeSet, YXBanded);
1895 
1896 	frameRegion = CompRegion ();
1897     }
1898 
1899     XUngrabServer (screen->dpy ());
1900 }
1901 
1902 /*
1903  * DecorWindow::updateOutputFrame
1904  *
1905  * Actually creates an output frame if there isn't
1906  * one, otherwise sets the shape regions on it so that
1907  * if the decoration inside the parent window ever
1908  * gets stacked on top of the client, it won't obstruct
1909  * it
1910  *
1911  * This also sets the _COMPIZ_WINDOW_DECOR_OUTPUT_FRAME
1912  * atom on the window. Decorators should listen for this
1913  * to determine if a window is to be decorated, and when
1914  * they get a PropertyNotify indicating that this the case
1915  * should draw a decoration inside the window and set the
1916  * _COMPIZ_WINDOW_DECOR atom in response, otherwise this
1917  * window is going to be stuck with default decorations
1918  *
1919  */
1920 void
1921 DecorWindow::updateOutputFrame ()
1922 {
1923     XRectangle           rects[4];
1924     int                  x, y, width, height;
1925     CompWindow::Geometry server = window->serverGeometry ();
1926     CompWindowExtents	 input;
1927 
1928     /* Determine frame extents */
1929     if ((window->state () & MAXIMIZE_STATE))
1930 	input = wd->decor->maxInput;
1931     else
1932 	input = wd->decor->input;
1933 
1934     x      = window->input ().left - input.left;
1935     y      = window->input ().top - input.top;
1936     width  = server.widthIncBorders () + input.left + input.right;
1937     height = server.heightIncBorders ()+ input.top  + input.bottom;
1938 
1939     if (window->shaded ())
1940 	height = input.top + input.bottom;
1941 
1942     /* Since we're reparenting windows here, we need to grab the server
1943      * which sucks, but its necessary */
1944     XGrabServer (screen->dpy ());
1945 
1946     if (!outputFrame)
1947     {
1948 	XSetWindowAttributes attr;
1949 
1950 	attr.background_pixel  = 0x0;
1951 	attr.event_mask        = StructureNotifyMask;
1952 	attr.override_redirect = true;
1953 
1954 	outputFrame = XCreateWindow (screen->dpy (), window->frame (),
1955 				     x, y, width, height, 0, CopyFromParent,
1956 				     InputOutput, CopyFromParent,
1957 				     CWOverrideRedirect | CWEventMask,
1958 				     &attr);
1959 
1960 	XGrabButton (screen->dpy (), AnyButton, AnyModifier, outputFrame,
1961 			true, ButtonPressMask | ButtonReleaseMask |
1962 			ButtonMotionMask, GrabModeSync, GrabModeSync, None,
1963 			None);
1964 
1965 	XMapWindow (screen->dpy (), outputFrame);
1966 
1967 	/* Notify the decorators that an input frame has been created on
1968 	 * this window so that they can react by actually create a decoration
1969 	 * for it (while we use the default decorations) */
1970 	XChangeProperty (screen->dpy (), window->id (),
1971 			 dScreen->outputFrameAtom, XA_WINDOW, 32,
1972 			 PropModeReplace, (unsigned char *) &outputFrame, 1);
1973 
1974 	if (screen->XShape ())
1975 	    XShapeSelectInput (screen->dpy (), outputFrame,
1976 			       ShapeNotifyMask);
1977 
1978 	/* invalidate the decoration so that it gets shaped */
1979 	oldX = 0;
1980 	oldY = 0;
1981 	oldWidth  = 0;
1982 	oldHeight = 0;
1983 
1984 	frameDamage = XDamageCreate (screen->dpy (), outputFrame,
1985 			             XDamageReportBoundingBox);
1986 
1987 	dScreen->frames[outputFrame] = this;
1988     }
1989 
1990     if (x != oldX || y != oldY || width != oldWidth || height != oldHeight)
1991     {
1992 	int    i = 0;
1993 	oldX = x;
1994 	oldY = y;
1995 	oldWidth  = width;
1996 	oldHeight = height;
1997 
1998 	XMoveResizeWindow (screen->dpy (), outputFrame, x, y, width, height);
1999 	XLowerWindow (screen->dpy (), outputFrame);
2000 
2001 
2002 	rects[i].x	= 0;
2003 	rects[i].y	= 0;
2004 	rects[i].width  = width;
2005 	rects[i].height = input.top;
2006 
2007 	if (rects[i].width && rects[i].height)
2008 	    i++;
2009 
2010 	rects[i].x	= 0;
2011 	rects[i].y	= input.top;
2012 	rects[i].width  = input.left;
2013 	rects[i].height = height - input.top - input.bottom;
2014 
2015 	if (rects[i].width && rects[i].height)
2016 	    i++;
2017 
2018 	rects[i].x	= width - input.right;
2019 	rects[i].y	= input.top;
2020 	rects[i].width  = input.right;
2021 	rects[i].height = height - input.top - input.bottom;
2022 
2023 	if (rects[i].width && rects[i].height)
2024 	    i++;
2025 
2026 	rects[i].x	= 0;
2027 	rects[i].y	= height - input.bottom;
2028 	rects[i].width  = width;
2029 	rects[i].height = input.bottom;
2030 
2031 	if (rects[i].width && rects[i].height)
2032 	    i++;
2033 
2034 	XShapeCombineRectangles (screen->dpy (), outputFrame,
2035 				 ShapeBounding, 0, 0, rects, i,
2036 				 ShapeSet, YXBanded);
2037 
2038 	frameRegion = CompRegion ();
2039     }
2040 
2041     XUngrabServer (screen->dpy ());
2042 }
2043 
2044 /*
2045  * DecorScreen::checkForDm
2046  *
2047  * Checks for a running decoration manager on the root window
2048  * and also checks to see what decoration modes it supports
2049  *
2050  * dmWin is set based on the window on supportingDmCheckAtom
2051  * on the root window. That's a window which is owned by
2052  * the decorator, so if it changes we need to invalidate
2053  * all the decorations
2054  */
2055 
2056 void
2057 DecorScreen::checkForDm (bool updateWindows)
2058 {
2059     Atom	  actual;
2060     int		  result, format, dmSupports = 0;
2061     unsigned long n, left;
2062     unsigned char *data;
2063     Window	  dmWin = None;
2064 
2065     result = XGetWindowProperty (screen->dpy (), screen->root (),
2066 				 supportingDmCheckAtom, 0L, 1L, false,
2067 				 XA_WINDOW, &actual, &format,
2068 				 &n, &left, &data);
2069 
2070     if (result == Success && n && data)
2071     {
2072 	XWindowAttributes attr;
2073 
2074 	memcpy (&dmWin, data, sizeof (Window));
2075 	XFree (data);
2076 
2077 	CompScreen::checkForError (screen->dpy ());
2078 
2079 	XGetWindowAttributes (screen->dpy (), dmWin, &attr);
2080 
2081 	if (CompScreen::checkForError (screen->dpy ()))
2082 	    dmWin = None;
2083 	else
2084 	{
2085 	    result = XGetWindowProperty (screen->dpy (), dmWin,
2086 					 decorTypeAtom, 0L, 2L, false,
2087 					 XA_ATOM, &actual, &format,
2088 					 &n, &left, &data);
2089 	    if (result == Success && n && data)
2090 	    {
2091 		Atom *ret = (Atom *) data;
2092 
2093 		for (unsigned long i = 0; i < n; i++)
2094 		{
2095 		    if (ret[i] == decorTypePixmapAtom)
2096 			dmSupports |= WINDOW_DECORATION_TYPE_PIXMAP;
2097 		    else if (ret[i] == decorTypeWindowAtom)
2098 			dmSupports |= WINDOW_DECORATION_TYPE_WINDOW;
2099 		}
2100 
2101 		if (!dmSupports)
2102 		    dmWin = None;
2103 
2104 		XFree (data);
2105 	    }
2106 	    else
2107 		dmWin = None;
2108 	}
2109     }
2110 
2111     /* Different decorator became active, update all decorations */
2112     if (dmWin != this->dmWin)
2113     {
2114 	int i;
2115 
2116 	this->dmSupports = dmSupports;
2117 
2118 	/* Create new default decorations */
2119 	screen->updateSupportedWmHints ();
2120 
2121 	if (dmWin)
2122 	{
2123 	    for (i = 0; i < DECOR_NUM; i++)
2124 	    {
2125 		decor[i].updateDecoration (screen->root (), decorAtom[i], &mRequestor);
2126 	    }
2127 	}
2128 	else
2129 	{
2130 	    /* No decorator active, destroy all decorations */
2131 	    for (i = 0; i < DECOR_NUM; i++)
2132 	    {
2133 		decor[i].clear ();
2134 
2135 		foreach (CompWindow *w, screen->windows ())
2136 		    DecorWindow::get (w)->decor.mList.clear ();
2137 	    }
2138 	}
2139 
2140 	this->dmWin = dmWin;
2141 
2142 	if (updateWindows)
2143 	{
2144 	    foreach (CompWindow *w, screen->windows ())
2145 		if (w->shaded () || w->isViewable ())
2146 		    DecorWindow::get (w)->update (true);
2147 	}
2148     }
2149 }
2150 
2151 /*
2152  * DecorWindow::updateFrameRegion
2153  *
2154  * Shapes the toplevel frame region according to the rects
2155  * in the decoration that we have. This is a wrapped function
2156  *
2157  */
2158 void
2159 DecorWindow::updateFrameRegion (CompRegion &region)
2160 {
2161     window->updateFrameRegion (region);
2162     if (wd)
2163     {
2164 	if (!frameRegion.isEmpty ())
2165 	{
2166 	    int x, y;
2167 
2168 	    x = window->geometry (). x ();
2169 	    y = window->geometry (). y ();
2170 
2171 	    region += frameRegion.translated (x - wd->decor->input.left,
2172 					      y - wd->decor->input.top);
2173 	}
2174 	else
2175 	{
2176 	    region += infiniteRegion;
2177 	}
2178     }
2179 
2180     updateReg = true;
2181     updateMatrix = true;
2182 }
2183 
2184 /*
2185  * DecorWindow::updateWindowRegions
2186  *
2187  * Used to update the region that the window type
2188  * decorations occupty when the window is moved */
2189 void
2190 DecorWindow::updateWindowRegions ()
2191 {
2192     const CompRect &input (window->inputRect ());
2193 
2194     if (regions.size () != gWindow->textures ().size ())
2195 	regions.resize (gWindow->textures ().size ());
2196 
2197     for (unsigned int i = 0; i < gWindow->textures ().size (); i++)
2198     {
2199 	regions[i] = CompRegion (*gWindow->textures ()[i]);
2200 	regions[i].translate (input.x (), input.y ());
2201 	regions[i] &= window->frameRegion ();
2202     }
2203 
2204     updateReg = false;
2205 }
2206 
2207 /*
2208  * DecorWindow::windowNotify
2209  *
2210  * Window event notification handler. On various
2211  * events on windows we need to update the decorations
2212  *
2213  */
2214 void
2215 DecorWindow::windowNotify (CompWindowNotify n)
2216 {
2217     switch (n)
2218     {
2219 	case CompWindowNotifyMap:
2220 
2221 	    /* When the switcher is mapped, it has no frame window
2222 	     * so the frame window for it needs to mapped manually */
2223 	    if (isSwitcher)
2224 	    {
2225 		update (true);
2226 		XMapWindow (screen->dpy (), inputFrame);
2227 		break;
2228 	    }
2229 
2230 	    /* For non-switcher windows we need to update the decoration
2231 	     * anyways, since the window is unmapped. Also need to
2232 	     * update the shadow clip regions for panels and other windows */
2233 	    update (true);
2234 	    updateDecorationScale ();
2235 	    if (dScreen->mMenusClipGroup.pushClippable (this))
2236 		updateGroupShadows ();
2237 
2238 	    break;
2239 
2240 	case CompWindowNotifyUnmap:
2241 	{
2242 
2243 	    /* When the switcher is unmapped, it has no frame window
2244 	     * so the frame window for it needs to unmapped manually */
2245 	    if (isSwitcher)
2246 	    {
2247 		update (true);
2248 		XUnmapWindow (screen->dpy (), inputFrame);
2249 		break;
2250 	    }
2251 
2252 	    /* For non-switcher windows we need to update the decoration
2253 	     * anyways, since the window is unmapped. Also need to
2254 	     * update the shadow clip regions for panels and other windows */
2255 	    update (true);
2256 	    updateDecorationScale ();
2257 	    /* Preserve the group shadow update ptr */
2258 	    DecorClipGroupInterface *clipGroup = mClipGroup;
2259 
2260 	    if (dScreen->mMenusClipGroup.popClippable (this))
2261 		if (clipGroup)
2262 		    clipGroup->updateAllShadows ();
2263 	    break;
2264 	}
2265 	case CompWindowNotifyUnreparent:
2266 	{
2267 	    /* Compiz detaches the frame window from
2268 	     * the client on unreparent, so we must
2269 	     * destroy our frame windows by forcing
2270 	     * this window to have no decorations */
2271 
2272 	    update (false);
2273 	    
2274 	    break;
2275 	}
2276 	case CompWindowNotifyReparent:
2277 	    /* Always update decorations when a window gets reparented */
2278 	    update (true);
2279 	    break;
2280 	case CompWindowNotifyShade:
2281 	    /* We get the notification for shade before the window is
2282 	     * actually resized which means that calling update ->
2283 	     * damageOutputExtents here will not do anything useful for us
2284 	     * so we need to track when windows are (un)shading and then wait
2285 	     * for the following resize notification to actually
2286 	     * update their decoration (since at this point they would have
2287 	     * been resized)
2288 	     */
2289 	    shading = true;
2290 	    unshading = false;
2291 	    break;
2292 	case CompWindowNotifyUnshade:
2293 	    unshading = true;
2294 	    shading = false;
2295 	    break;
2296 	default:
2297 	    break;
2298     }
2299 
2300     window->windowNotify (n);
2301 }
2302 
2303 /*
2304  * DecorWindow::updateSwitcher
2305  *
2306  * Check this window to see if it is a switcher,
2307  * if so, update the switcher flag 
2308  */
2309 void
2310 DecorWindow::updateSwitcher ()
2311 {
2312     Atom	  actualType;
2313     int	      	  actualFmt;
2314     unsigned long nitems, nleft;
2315     unsigned long *data;
2316 
2317     DECOR_SCREEN (screen);
2318 
2319     if (XGetWindowProperty (screen->dpy (), window->id (),
2320 		    	    ds->decorSwitchWindowAtom, 0L, 1024L,
2321 		    	    false, XA_WINDOW, &actualType, &actualFmt,
2322 		    	    &nitems, &nleft, (unsigned char **) &data) == Success)
2323     {
2324 	if (data)
2325 	    XFree (data);
2326 
2327 	if (nitems == 1)
2328 	{
2329 	    isSwitcher = true;
2330 	    return;
2331 	}
2332     }
2333 
2334     isSwitcher = false;
2335 }
2336 
2337 
2338 /*
2339  * DecorScreen::handleEvent
2340  *
2341  * Handles X11 events
2342  */
2343 void
2344 DecorScreen::handleEvent (XEvent *event)
2345 {
2346     Window  activeWindow = screen->activeWindow ();
2347     CompWindow *w;
2348 
2349     switch (event->type) {
2350 	case DestroyNotify:
2351 	    /* When a decorator selection owner window is destroyed
2352 	     * it means that this decorator went away, so we need
2353 	     * to account for this */
2354 	    w = screen->findWindow (event->xdestroywindow.window);
2355 	    if (w)
2356 	    {
2357 		if (w->id () == dmWin)
2358 		    checkForDm (true);
2359 	    }
2360 	    break;
2361 	case ClientMessage:
2362 	    /* Update decorations whenever someone requests frame extents
2363 	     * so that core doesn't reply with the wrong extents when
2364 	     * when handleEvent is passed to core
2365 	     */
2366 	    if (event->xclient.message_type == requestFrameExtentsAtom)
2367 	    {
2368 		w = screen->findWindow (event->xclient.window);
2369 		if (w)
2370 		    DecorWindow::get (w)->update (true);
2371 	    }
2372 	    /* A decoration is pending creation, allow it to be created */
2373 	    if (event->xclient.message_type == decorPendingAtom)
2374 	    {
2375 		CompWindow *w = screen->findWindow (event->xclient.window);
2376 
2377 		if (w)
2378 		{
2379 		    DecorWindow *dw = DecorWindow::get (w);
2380 
2381 		    dw->mRequestor.handlePending (event->xclient.data.l);
2382 		}
2383 	    }
2384 	default:
2385 	    /* Check for damage events. If the output or input window
2386 	     * or a texture is updated then damage output extents.
2387 	     */
2388 	    if (cmActive &&
2389 		event->type == cScreen->damageEvent () + XDamageNotify)
2390 	    {
2391 		XDamageNotifyEvent *de = (XDamageNotifyEvent *) event;
2392 
2393 		if (frames.find (de->drawable) != frames.end ())
2394 		    frames[de->drawable]->cWindow->damageOutputExtents ();
2395 
2396 		foreach (DecorTexture *t, textures)
2397 		{
2398 		    if (t->pixmap->getPixmap () == de->drawable)
2399 		    {
2400 			foreach (CompWindow *w, screen->windows ())
2401 			{
2402 			    if (w->shaded () || w->mapNum ())
2403 			    {
2404 				DECOR_WINDOW (w);
2405 
2406 				if (dw->wd && dw->wd->decor->texture == t)
2407 				    dw->cWindow->damageOutputExtents ();
2408 			    }
2409 			}
2410 			break;
2411 		    }
2412 		}
2413 	    }
2414 	    break;
2415     }
2416 
2417     screen->handleEvent (event);
2418 
2419     /* If the active window changed, update the decoration,
2420      * as long as the decoration isn't animating out */
2421     if (screen->activeWindow () != activeWindow)
2422     {
2423 	w = screen->findWindow (activeWindow);
2424 	if (w && !w->hasUnmapReference ())
2425 	    DecorWindow::get (w)->update (true);
2426 
2427 	w = screen->findWindow (screen->activeWindow ());
2428 	if (w)
2429 	    DecorWindow::get (w)->update (true);
2430     }
2431 
2432     switch (event->type) {
2433 	case PropertyNotify:
2434 	    /* When the switcher atom changes we should probably
2435 	     * update the switcher property on this window */
2436 	    if (event->xproperty.atom == decorSwitchWindowAtom)
2437 	    {
2438 		CompWindow    *w = screen->findWindow (event->xproperty.window);
2439 
2440 		if (w)
2441 		{
2442 		    DECOR_WINDOW (w);
2443 
2444 		    if (dw->isSwitcher && !event->xproperty.state == PropertyDelete)
2445 			dw->updateSwitcher ();
2446 		}
2447 	    }
2448 	    /* Decorator has created or updated a decoration for this window,
2449 	     * update the decoration */
2450 	    else if (event->xproperty.atom == winDecorAtom)
2451 	    {
2452 		w = screen->findWindow (event->xproperty.window);
2453 		if (w)
2454 		{
2455 		    DECOR_WINDOW (w);
2456 
2457 		    dw->updateDecoration ();
2458 		    dw->update (true);
2459 		}
2460 	    }
2461 	    /* _MOTIF_WM_HINTS has been set on this window, it may not
2462 	     * may need to be decorated */
2463 	    else if (event->xproperty.atom == Atoms::mwmHints)
2464 	    {
2465 		w = screen->findWindow (event->xproperty.window);
2466 		if (w)
2467 		    DecorWindow::get (w)->update (true);
2468 	    }
2469 	    else
2470 	    {
2471 		if (event->xproperty.window == screen->root ())
2472 		{
2473 		    /* If the supportingDmCheckAtom changed on the root window
2474 		     * it could mean that the decorator changed, so we need
2475 		     * to update decorations */
2476 		    if (event->xproperty.atom == supportingDmCheckAtom)
2477 		    {
2478 			checkForDm (true);
2479 		    }
2480 		    else
2481 		    {
2482 			/* A default decoration changed */
2483 			for (int i = 0; i < DECOR_NUM; i++)
2484 			{
2485 			    if (event->xproperty.atom == decorAtom[i])
2486 			    {
2487 				decor[i].updateDecoration (screen->root (),
2488 							   decorAtom[i],
2489 							   &mRequestor);
2490 
2491 				foreach (CompWindow *w, screen->windows ())
2492 				    DecorWindow::get (w)->update (true);
2493 			    }
2494 			}
2495 		    }
2496 		}
2497 	    }
2498 	    break;
2499 	/* Whenever a window is configured, we need to update the frame window */
2500 	case ConfigureNotify:
2501 	    w = screen->findTopLevelWindow (event->xconfigure.window);
2502 	    if (w)
2503 	    {
2504 		DECOR_WINDOW (w);
2505 		if (!w->hasUnmapReference () && dw->wd && dw->wd->decor)
2506 		    dw->updateFrame ();
2507 	    }
2508 	    break;
2509 	case DestroyNotify:
2510 	    /* Only for when the client window gets destroyed */
2511 	    w = screen->findTopLevelWindow (event->xproperty.window);
2512 	    if (w)
2513 	    {
2514 		DECOR_WINDOW (w);
2515 		if (dw->inputFrame &&
2516 		    dw->inputFrame == event->xdestroywindow.window)
2517 		{
2518 		    XDeleteProperty (screen->dpy (), w->id (),
2519 				     inputFrameAtom);
2520 		    dw->inputFrame = None;
2521 		}
2522 		else if (dw->outputFrame &&
2523 		         dw->outputFrame == event->xdestroywindow.window)
2524 		{
2525 		    XDeleteProperty (screen->dpy (), w->id (),
2526 				     outputFrameAtom);
2527 		    dw->outputFrame = None;
2528 		}
2529 	    }
2530 	    break;
2531 	/* Add new shape rects to frame region in case of a
2532 	 * shape notification */
2533 	default:
2534 	    if (screen->XShape () && event->type ==
2535 		screen->shapeEvent () + ShapeNotify)
2536 	    {
2537 		w = screen->findWindow (((XShapeEvent *) event)->window);
2538 		if (w)
2539 		    DecorWindow::get (w)->update (true);
2540 		else
2541 		{
2542 		    foreach (w, screen->windows ())
2543 		    {
2544 			DECOR_WINDOW (w);
2545 			if (dw->inputFrame ==
2546 			    ((XShapeEvent *) event)->window)
2547 			{
2548 			    XRectangle *shapeRects = 0;
2549 			    int order, n;
2550 
2551 			    dw->frameRegion = CompRegion ();
2552 
2553 			    shapeRects =
2554 				XShapeGetRectangles (screen->dpy (),
2555 				    dw->inputFrame, ShapeInput,
2556 				    &n, &order);
2557 			    if (!shapeRects || !n)
2558 				break;
2559 
2560 			    for (int i = 0; i < n; i++)
2561 				dw->frameRegion +=
2562 				    CompRegion (shapeRects[i].x,
2563 					        shapeRects[i].y,
2564 						shapeRects[i].width,
2565 						shapeRects[i].height);
2566 
2567 			    w->updateFrameRegion ();
2568 
2569 			    XFree (shapeRects);
2570 			}
2571 			else if (dw->outputFrame ==
2572 			         ((XShapeEvent *) event)->window)
2573 			{
2574 			    XRectangle *shapeRects = 0;
2575 			    int order, n;
2576 
2577 			    dw->frameRegion = CompRegion ();
2578 
2579 			    shapeRects =
2580 				XShapeGetRectangles (screen->dpy (),
2581 				    dw->outputFrame, ShapeBounding,
2582 				    &n, &order);
2583 			    if (!n || !shapeRects)
2584 				break;
2585 
2586 			    for (int i = 0; i < n; i++)
2587 				dw->frameRegion +=
2588 				    CompRegion (shapeRects[i].x,
2589 					        shapeRects[i].y,
2590 						shapeRects[i].width,
2591 						shapeRects[i].height);
2592 
2593 			    w->updateFrameRegion ();
2594 
2595 			    XFree (shapeRects);
2596 			}
2597 		    }
2598 		}
2599 	    }
2600 	    break;
2601     }
2602 }
2603 
2604 /*
2605  * DecorWindow::damageRect
2606  *
2607  * When this window is first presented to the user, we need to update
2608  * the decoration since it is now visible
2609  *
2610  */
2611 
2612 bool
2613 DecorWindow::damageRect (bool initial, const CompRect &rect)
2614 {
2615     if (initial)
2616 	update (true);
2617 
2618     return cWindow->damageRect (initial, rect);
2619 }
2620 
2621 /*
2622  * DecorWindow::getOutputExtents
2623  *
2624  * Extend "output extents" (eg decoration + shadows) for this
2625  * window if necessary
2626  */
2627 
2628 void
2629 DecorWindow::getOutputExtents (CompWindowExtents& output)
2630 {
2631     window->getOutputExtents (output);
2632 
2633     if (wd)
2634     {
2635 	CompWindowExtents *e = &wd->decor->output;
2636 
2637 	if (e->left > output.left)
2638 	    output.left = e->left;
2639 	if (e->right > output.right)
2640 	    output.right = e->right;
2641 	if (e->top > output.top)
2642 	    output.top = e->top;
2643 	if (e->bottom > output.bottom)
2644 	    output.bottom = e->bottom;
2645     }
2646 }
2647 
2648 /*
2649  * DecorScreen::updateDefaultShadowProperty
2650  *
2651  * Set some default shadow options on the root
2652  * window in case the default decorator doesn't
2653  * use custom shadows
2654  */
2655 
2656 void
2657 DecorScreen::updateDefaultShadowProperty ()
2658 {
2659     long data[8];
2660     CompOption *activeColorOption = CompOption::findOption (getOptions (), "active_shadow_color");
2661     CompOption *inactiveColorOption = CompOption::findOption (getOptions (), "inactive_shadow_color");
2662     char *colorString[2];
2663     XTextProperty xtp;
2664 
2665     if (!activeColorOption || !inactiveColorOption)
2666 	return;
2667 
2668     colorString[0] = strdup (CompOption::colorToString (activeColorOption->value ().c ()).c_str ());
2669     colorString[1] = strdup (CompOption::colorToString (inactiveColorOption->value ().c ()).c_str ());
2670 
2671     /* 1) Active Shadow Radius
2672      * 2) Active Shadow Opacity
2673      * 3) Active Shadow Offset X
2674      * 4) Active Shadow Offset Y
2675      * 5) Inactive Shadow Radius
2676      * 6) Inactive Shadow Opacity
2677      * 7) Inactive Shadow Offset X
2678      * 8) Inactive Shadow Offset Y
2679      */
2680 
2681     /* the precision is 0.0001, so multiply by 1000 */
2682     data[0] = optionGetActiveShadowRadius () * 1000;
2683     data[1] = optionGetActiveShadowOpacity () * 1000;
2684     data[2] = optionGetActiveShadowXOffset ();
2685     data[3] = optionGetActiveShadowYOffset ();
2686     data[4] = optionGetInactiveShadowRadius () * 1000;
2687     data[5] = optionGetInactiveShadowOpacity () * 1000;
2688     data[6] = optionGetInactiveShadowXOffset ();
2689     data[7] = optionGetInactiveShadowYOffset ();
2690 
2691 
2692     XChangeProperty (screen->dpy (), screen->root (),
2693 		      shadowInfoAtom, XA_INTEGER, 32,
2694 		      PropModeReplace, (unsigned char *) data, 8);
2695 
2696     if (XStringListToTextProperty (colorString, 2, &xtp))
2697     {
2698 	XSetTextProperty (screen->dpy (), screen->root (), &xtp, shadowColorAtom);
2699 	XFree (xtp.value);
2700     }
2701 
2702     free (colorString[0]);
2703     free (colorString[1]);
2704 }
2705 
2706 bool
2707 DecorScreen::setOption (const CompString  &name,
2708 			CompOption::Value &value)
2709 {
2710     unsigned int index;
2711 
2712     bool rv = DecorOptions::setOption (name, value);
2713 
2714     if (!rv || !CompOption::findOption (getOptions (), name, &index))
2715 	return false;
2716 
2717     switch (index) {
2718 	case DecorOptions::Command:
2719 	    if (!dmWin)
2720 		screen->runCommand (optionGetCommand ());
2721 	    break;
2722 	case DecorOptions::ShadowMatch:
2723 	    {
2724 		CompString matchString;
2725 
2726 		/*
2727 		Make sure RGBA matching is always present and disable shadows
2728 		for RGBA windows by default if the user didn't specify an
2729 		RGBA match.
2730 		Reasoning for that is that shadows are desired for some RGBA
2731 		windows (e.g. rectangular windows that just happen to have an
2732 		RGBA colormap), while it's absolutely undesired for others
2733 		(especially shaped ones) ... by enforcing no shadows for RGBA
2734 		windows by default, we are flexible to user desires while still
2735 		making sure we don't show ugliness by default
2736 		*/
2737 
2738 		matchString = optionGetShadowMatch ().toString ();
2739 		if (matchString.find ("rgba=") == CompString::npos)
2740 		{
2741 		    CompMatch rgbaMatch ("rgba=0");
2742 		    optionGetShadowMatch () &= rgbaMatch;
2743 		}
2744 	    }
2745 	    /* fall-through intended */
2746 	case DecorOptions::DecorationMatch:
2747 	    foreach (CompWindow *w, screen->windows ())
2748 		DecorWindow::get (w)->update (true);
2749 	    break;
2750 	case DecorOptions::ActiveShadowRadius:
2751 	case DecorOptions::ActiveShadowOpacity:
2752 	case DecorOptions::ActiveShadowColor:
2753 	case DecorOptions::ActiveShadowXOffset:
2754 	case DecorOptions::ActiveShadowYOffset:
2755 	case DecorOptions::InactiveShadowRadius:
2756 	case DecorOptions::InactiveShadowOpacity:
2757 	case DecorOptions::InactiveShadowColor:
2758 	case DecorOptions::InactiveShadowXOffset:
2759 	case DecorOptions::InactiveShadowYOffset:
2760 	    updateDefaultShadowProperty ();
2761 	    break;
2762 	default:
2763 	    break;
2764     }
2765 
2766     return rv;
2767 }
2768 
2769 /*
2770  * DecorWindow::moveNotify
2771  *
2772  * Translate window scaled quad boxes for movement
2773  * and also recompute shadow clip regions
2774  * for panels and menus
2775  */
2776 void
2777 DecorWindow::moveNotify (int dx, int dy, bool immediate)
2778 {
2779     if (wd)
2780     {
2781 	for (int i = 0; i < wd->nQuad; i++)
2782 	{
2783 	    wd->quad[i].box.x1 += dx;
2784 	    wd->quad[i].box.y1 += dy;
2785 	    wd->quad[i].box.x2 += dx;
2786 	    wd->quad[i].box.y2 += dy;
2787 	}
2788     }
2789 
2790     updateReg = true;
2791     updateMatrix = true;
2792 
2793     mInputRegion.translate (dx, dy);
2794     mOutputRegion.translate (dx, dy);
2795 
2796     if (dScreen->cmActive && mClipGroup)
2797 	updateGroupShadows ();
2798 
2799     window->moveNotify (dx, dy, immediate);
2800 }
2801 
2802 /*
2803  * DecorWindow::resizeNotify
2804  *
2805  * Called whenever a window is resized. Update scaled quads and 
2806  * recompute shadow region
2807  *
2808  */
2809 
2810 void
2811 DecorWindow::resizeNotify (int dx, int dy, int dwidth, int dheight)
2812 {
2813     if (shading || unshading)
2814     {
2815 	shading = false;
2816 	unshading = false;
2817     }
2818     /* FIXME: we should not need a timer for calling decorWindowUpdate,
2819        and only call updateWindowDecorationScale if decorWindowUpdate
2820        returns false. Unfortunately, decorWindowUpdate may call
2821        updateWindowOutputExtents, which may call WindowResizeNotify. As
2822        we never should call a wrapped function that's currently
2823        processed, we need the timer for the moment. updateWindowOutputExtents
2824        should be fixed so that it does not emit a resize notification. */
2825     updateMatrix = true;
2826     updateReg = true;
2827 
2828     mInputRegion = CompRegion (window->inputRect ());
2829     mOutputRegion = CompRegion (window->outputRect ());
2830     if (dScreen->cmActive && mClipGroup)
2831 	updateGroupShadows ();
2832 
2833     updateReg = true;
2834 
2835     window->resizeNotify (dx, dy, dwidth, dheight);
2836 }
2837 
2838 
2839 /*
2840  * DecorWindow::stateChangeNotify
2841  *
2842  * Called whenever a window state changes, we might need to use
2843  * different extents in case the decoration didn't change
2844  *
2845  */
2846 void
2847 DecorWindow::stateChangeNotify (unsigned int lastState)
2848 {
2849     if (wd && wd->decor)
2850     {
2851 	CompPoint oldShift = compiz::window::extents::shift (window->border (), window->sizeHints ().win_gravity);
2852 	
2853 
2854 	if ((window->state () & MAXIMIZE_STATE))
2855 	    window->setWindowFrameExtents (&wd->decor->maxBorder,
2856 					   &wd->decor->maxInput);
2857 	else
2858 	    window->setWindowFrameExtents (&wd->decor->border,
2859 					   &wd->decor->input);
2860 
2861 	/* Since we immediately update the frame extents, we must
2862 	 * also update the stored saved window geometry in order
2863 	 * to prevent the window from shifting back too far once
2864 	 * unmaximized */
2865 
2866 	CompPoint movement = compiz::window::extents::shift (window->border (), window->sizeHints ().win_gravity) - oldShift;
2867 
2868 	if (window->saveMask () & CWX)
2869 	    window->saveWc ().x += movement.x ();
2870 
2871 	if (window->saveMask () & CWY)
2872 	    window->saveWc ().y += movement.y ();
2873 
2874 	updateFrame ();
2875     }
2876 
2877     window->stateChangeNotify (lastState);
2878 }
2879 
2880 void
2881 DecorScreen::matchPropertyChanged (CompWindow *w)
2882 {
2883     DecorWindow::get (w)->update (true);
2884 
2885     screen->matchPropertyChanged (w);
2886 }
2887 
2888 /*
2889  * DecorScreen::addSupportedAtoms
2890  *
2891  * _NET_REQUEST_FRAME_EXTENTS is only supported where
2892  * a decorator is running, so add that to _NET_WM_SUPPORTED
2893  * where that is the case
2894  *
2895  */
2896 void
2897 DecorScreen::addSupportedAtoms (std::vector<Atom> &atoms)
2898 {
2899     screen->addSupportedAtoms (atoms);
2900 
2901     /* Don't support _NET_REQUEST_FRAME_EXTENTS
2902      * where there is no decorator running yet */
2903     if (dmWin)
2904 	atoms.push_back (requestFrameExtentsAtom);
2905 }
2906 
2907 void
2908 DecorWindow::updateHandlers ()
2909 {
2910     if (dScreen->cmActive)
2911     {
2912 	gWindow = GLWindow::get (window);
2913 	cWindow = CompositeWindow::get (window);
2914 
2915 	CompositeWindowInterface::setHandler (cWindow);
2916 	GLWindowInterface::setHandler (gWindow);
2917     }
2918     else
2919     {
2920 	CompositeWindowInterface::setHandler (cWindow, false);
2921 	GLWindowInterface::setHandler (gWindow, false);
2922 
2923 	gWindow = NULL;
2924 	cWindow = NULL;
2925     }
2926 }
2927 
2928 /*
2929  * DecorScreen::decoratorStartTimeout
2930  *
2931  * Start a decorator in case there isn't one running
2932  *
2933  */
2934 bool
2935 DecorScreen::decoratorStartTimeout ()
2936 {
2937     if (!dmWin)
2938 	screen->runCommand (optionGetCommand ());
2939 
2940     /* Update all the windows */
2941     foreach (CompWindow *w, screen->windows ())
2942     {
2943 	DECOR_WINDOW (w);
2944 
2945 	dw->updateHandlers ();
2946 
2947 	dw->updateSwitcher ();
2948 
2949 	if (!w->overrideRedirect () || dw->isSwitcher)
2950 	    dw->updateDecoration ();
2951 
2952 	if (w->shaded () || w->isViewable ())
2953 	    dw->update (true);
2954     }
2955 
2956     return false;
2957 }
2958 
2959 bool
2960 DecorScreen::registerPaintHandler (compiz::composite::PaintHandler *p)
2961 {
2962     cmActive = true;
2963     return cScreen->registerPaintHandler (p);
2964 }
2965 
2966 void
2967 DecorScreen::unregisterPaintHandler ()
2968 {
2969     cmActive = false;
2970     return cScreen->unregisterPaintHandler ();
2971 }
2972 
2973 /*
2974  * DecorScreen::DecorScreen
2975  *
2976  * Initialize atoms, and create a
2977  * default "window type" decoration
2978  * and ensure that _NET_REQUEST_FRAME_EXTENTS
2979  * gets added to _NET_WM_SUPPORTED
2980  *
2981  */
2982 DecorScreen::DecorScreen (CompScreen *s) :
2983     PluginClassHandler<DecorScreen,CompScreen> (s),
2984     cScreen (CompositeScreen::get (s)),
2985     textures (),
2986     dmWin (None),
2987     dmSupports (0),
2988     cmActive (false),
2989     windowDefault (new Decoration (WINDOW_DECORATION_TYPE_WINDOW,
2990 				   decor_extents_t (),
2991 				   decor_extents_t (),
2992 				   decor_extents_t (),
2993 				   decor_extents_t (),
2994 				   0,
2995 				   0,
2996 				   0,
2997 				   0,
2998 				   0,
2999 				   None,
3000 				   boost::shared_array <decor_quad_t> (NULL),
3001 				   0,
3002 				   screen->root (),
3003 				   NULL)),
3004     mMenusClipGroup (CompMatch ("type=Dock | type=DropdownMenu | type=PopupMenu")),
3005     mRequestor (screen->dpy (), screen->root (), &(decor[DECOR_ACTIVE]))
3006 {
3007     supportingDmCheckAtom =
3008 	XInternAtom (s->dpy (), DECOR_SUPPORTING_DM_CHECK_ATOM_NAME, 0);
3009     winDecorAtom =
3010 	XInternAtom (s->dpy (), DECOR_WINDOW_ATOM_NAME, 0);
3011     decorAtom[DECOR_BARE] =
3012         XInternAtom (s->dpy (), DECOR_BARE_ATOM_NAME, 0);
3013     decorAtom[DECOR_ACTIVE] =
3014 	XInternAtom (s->dpy (), DECOR_ACTIVE_ATOM_NAME, 0);
3015     inputFrameAtom =
3016 	XInternAtom (s->dpy (), DECOR_INPUT_FRAME_ATOM_NAME, 0);
3017     outputFrameAtom =
3018 	XInternAtom (s->dpy (), DECOR_OUTPUT_FRAME_ATOM_NAME, 0);
3019     decorTypeAtom =
3020 	XInternAtom (s->dpy (), DECOR_TYPE_ATOM_NAME, 0);
3021     decorTypePixmapAtom =
3022 	XInternAtom (s->dpy (), DECOR_TYPE_PIXMAP_ATOM_NAME, 0);
3023     decorTypeWindowAtom =
3024 	XInternAtom (s->dpy (), DECOR_TYPE_WINDOW_ATOM_NAME, 0);
3025     decorSwitchWindowAtom =
3026 	XInternAtom (s->dpy (), DECOR_SWITCH_WINDOW_ATOM_NAME, 0);
3027     decorPendingAtom =
3028 	XInternAtom (s->dpy (), "_COMPIZ_DECOR_PENDING", 0);
3029     decorRequestAtom =
3030 	XInternAtom (s->dpy (), "_COMPIZ_DECOR_REQUEST", 0);
3031     requestFrameExtentsAtom =
3032         XInternAtom (s->dpy (), "_NET_REQUEST_FRAME_EXTENTS", 0);
3033     shadowColorAtom =
3034 	XInternAtom (s->dpy (), "_COMPIZ_NET_CM_SHADOW_COLOR", 0);
3035     shadowInfoAtom =
3036 	XInternAtom (s->dpy (), "_COMPIZ_NET_CM_SHADOW_PROPERTIES", 0);
3037 
3038     cmActive = (cScreen) ? cScreen->compositingActive () &&
3039                GLScreen::get (s) != NULL : false;
3040 
3041     checkForDm (false);
3042 
3043     decoratorStart.start (boost::bind (&DecorScreen::decoratorStartTimeout,
3044 				       this),
3045 			  0);
3046 
3047     ScreenInterface::setHandler (s);
3048     CompositeScreenInterface::setHandler (cScreen);
3049     screen->updateSupportedWmHints ();
3050 }
3051 
3052 /*
3053  * DecorScreen::~DecorScreen
3054  *
3055  * Ensure that _NET_REQUEST_FRAME_EXTENTS
3056  * is cleared from _NET_WM_SUPPORTED
3057  *
3058  */
3059 DecorScreen::~DecorScreen ()
3060 {
3061     for (unsigned int i = 0; i < DECOR_NUM; i++)
3062         decor[i].clear ();
3063 
3064     screen->addSupportedAtomsSetEnabled (this, false);
3065     screen->updateSupportedWmHints ();
3066 }
3067 
3068 DecorWindow::DecorWindow (CompWindow *w) :
3069     PluginClassHandler<DecorWindow,CompWindow> (w),
3070     window (w),
3071     gWindow (GLWindow::get (w)),
3072     cWindow (CompositeWindow::get (w)),
3073     dScreen (DecorScreen::get (screen)),
3074     wd (NULL),
3075     inputFrame (None),
3076     outputFrame (None),
3077     pixmapFailed (false),
3078     regions (),
3079     updateReg (true),
3080     updateMatrix (true),
3081     unshading (false),
3082     shading (false),
3083     isSwitcher (false),
3084     frameExtentsRequested (false),
3085     mClipGroup (NULL),
3086     mOutputRegion (window->outputRect ()),
3087     mInputRegion (window->inputRect ()),
3088     mRequestor (screen->dpy (), w->id (), &decor)
3089 {
3090     WindowInterface::setHandler (window);
3091 
3092     /* FIXME :DecorWindow::update can call updateWindowOutputExtents
3093      * which will call a zero-diff resizeNotify. Since this window
3094      * might be part of a startup procedure, we can't assume that
3095      * all other windows in the list are necessarily safe to use
3096      * (since DecorWindow::DecorWindow might not have been called
3097      * for them) so we need to turn off resize notifications
3098      * and turn them back on once we're done updating the decoration
3099      */
3100 
3101     window->resizeNotifySetEnabled (this, false);
3102 
Condition "!this->dScreen->decoratorStart.active()", taking false branch
3103     if (!dScreen->decoratorStart.active ())
3104     {
3105 	updateHandlers ();
3106 
3107 	updateSwitcher ();
3108 
3109 	if (!w->overrideRedirect () || isSwitcher)
3110 	    updateDecoration ();
3111 
3112 	if (w->shaded () || w->isViewable ())
3113 	    update (true);
End of if statement
3114     }
3115 
3116     window->resizeNotifySetEnabled (this, true);
3117 
Condition "!this->window->invisible()", taking true branch
3118     if (!window->invisible ())
Condition "this->dScreen->mMenusClipGroup.pushClippable(this)", taking true branch
3119 	if (dScreen->mMenusClipGroup.pushClippable (this))
3120 	    updateGroupShadows ();
CID 12571 - UNINIT_CTOR
Non-static class member "frameDamage" is not initialized in this constructor nor in any functions that it calls.
Non-static class member "oldX" is not initialized in this constructor nor in any functions that it calls.
Non-static class member "oldY" is not initialized in this constructor nor in any functions that it calls.
Non-static class member "oldWidth" is not initialized in this constructor nor in any functions that it calls.
Non-static class member "oldHeight" is not initialized in this constructor nor in any functions that it calls.
3121 }
3122 
3123 /* 
3124  * DecorWindow::~DecorWindow
3125  * 
3126  * On tear-down, we need to shift all windows
3127  * back to their original positions
3128  */
3129 DecorWindow::~DecorWindow ()
3130 {
3131     if (!window->destroyed ())
3132 	update (false);
3133 
3134     if (wd)
3135 	WindowDecoration::destroy (wd);
3136 
3137     if (mClipGroup)
3138 	mClipGroup->popClippable (this);
3139 
3140     decor.mList.clear ();
3141 }
3142 
3143 bool
3144 DecorPluginVTable::init ()
3145 {
3146     if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION))
3147 	 return false;
3148 
3149     return true;
3150 }