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 #include <X11/Xlib.h>
  27 #include <X11/Xatom.h>
  28 #include <X11/Xproto.h>
  29 #include <X11/extensions/shape.h>
  30 
  31 #include <stdio.h>
  32 #include <string.h>
  33 #include <strings.h>
  34 #include <stdlib.h>
  35 #include <stdint.h>
  36 #include <assert.h>
  37 #include <math.h>
  38 
  39 #include <boost/bind.hpp>
  40 
  41 #include <core/icon.h>
  42 #include <core/atoms.h>
  43 #include "core/windowconstrainment.h"
  44 #include "privatewindow.h"
  45 #include "privatescreen.h"
  46 #include "privatestackdebugger.h"
  47 
  48 #include <boost/scoped_array.hpp>
  49 
  50 template class WrapableInterface<CompWindow, WindowInterface>;
  51 
  52 PluginClassStorage::Indices windowPluginClassIndices (0);
  53 
  54 unsigned int
  55 CompWindow::allocPluginClassIndex ()
  56 {
  57     unsigned int i = PluginClassStorage::allocatePluginClassIndex (windowPluginClassIndices);
  58 
  59     foreach (CompWindow *w, screen->windows ())
  60 	if (windowPluginClassIndices.size () != w->pluginClasses.size ())
  61 	    w->pluginClasses.resize (windowPluginClassIndices.size ());
  62 
  63     return i;
  64 }
  65 
  66 void
  67 CompWindow::freePluginClassIndex (unsigned int index)
  68 {
  69     PluginClassStorage::freePluginClassIndex (windowPluginClassIndices, index);
  70 
  71     foreach (CompWindow *w, ::screen->windows ())
  72 	if (windowPluginClassIndices.size () != w->pluginClasses.size ())
  73 	    w->pluginClasses.resize (windowPluginClassIndices.size ());
  74 }
  75 
  76 inline bool
  77 PrivateWindow::isInvisible() const
  78 {
  79     return attrib.map_state != IsViewable ||
  80      attrib.x + geometry.width ()  + output.right  <= 0 ||
  81      attrib.y + geometry.height () + output.bottom <= 0 ||
  82      attrib.x - output.left >= (int) screen->width () ||
  83      attrib.y - output.top >= (int) screen->height ();
  84 }
  85 
  86 bool
  87 PrivateWindow::isAncestorTo (CompWindow *transient,
  88 			     CompWindow *ancestor)
  89 {
  90     if (transient->priv->transientFor)
  91     {
  92 	if (transient->priv->transientFor == ancestor->priv->id)
  93 	    return true;
  94 
  95 	transient = screen->findWindow (transient->priv->transientFor);
  96 	if (transient)
  97 	    return isAncestorTo (transient, ancestor);
  98     }
  99 
 100     return false;
 101 }
 102 
 103 void
 104 PrivateWindow::recalcNormalHints ()
 105 {
 106     int maxSize;
 107 
 108 /* FIXME to max Texture size */
 109     maxSize  = MAXSHORT;
 110     maxSize -= serverGeometry.border () * 2;
 111 
 112     sizeHints.x      = serverGeometry.x ();
 113     sizeHints.y      = serverGeometry.y ();
 114     sizeHints.width  = serverGeometry.width ();
 115     sizeHints.height = serverGeometry.height ();
 116 
 117     if (!(sizeHints.flags & PBaseSize))
 118     {
 119 	if (sizeHints.flags & PMinSize)
 120 	{
 121 	    sizeHints.base_width  = sizeHints.min_width;
 122 	    sizeHints.base_height = sizeHints.min_height;
 123 	}
 124 	else
 125 	{
 126 	    sizeHints.base_width  = 0;
 127 	    sizeHints.base_height = 0;
 128 	}
 129 
 130 	sizeHints.flags |= PBaseSize;
 131     }
 132 
 133     if (!(sizeHints.flags & PMinSize))
 134     {
 135 	sizeHints.min_width  = sizeHints.base_width;
 136 	sizeHints.min_height = sizeHints.base_height;
 137 	sizeHints.flags |= PMinSize;
 138     }
 139 
 140     if (!(sizeHints.flags & PMaxSize))
 141     {
 142 	sizeHints.max_width  = 65535;
 143 	sizeHints.max_height = 65535;
 144 	sizeHints.flags |= PMaxSize;
 145     }
 146 
 147     if (sizeHints.max_width < sizeHints.min_width)
 148 	sizeHints.max_width = sizeHints.min_width;
 149 
 150     if (sizeHints.max_height < sizeHints.min_height)
 151 	sizeHints.max_height = sizeHints.min_height;
 152 
 153     if (sizeHints.min_width < 1)
 154 	sizeHints.min_width = 1;
 155 
 156     if (sizeHints.max_width < 1)
 157 	sizeHints.max_width = 1;
 158 
 159     if (sizeHints.min_height < 1)
 160 	sizeHints.min_height = 1;
 161 
 162     if (sizeHints.max_height < 1)
 163 	sizeHints.max_height = 1;
 164 
 165     if (sizeHints.max_width > maxSize)
 166 	sizeHints.max_width = maxSize;
 167 
 168     if (sizeHints.max_height > maxSize)
 169 	sizeHints.max_height = maxSize;
 170 
 171     if (sizeHints.min_width > maxSize)
 172 	sizeHints.min_width = maxSize;
 173 
 174     if (sizeHints.min_height > maxSize)
 175 	sizeHints.min_height = maxSize;
 176 
 177     if (sizeHints.base_width > maxSize)
 178 	sizeHints.base_width = maxSize;
 179 
 180     if (sizeHints.base_height > maxSize)
 181 	sizeHints.base_height = maxSize;
 182 
 183     if (sizeHints.flags & PResizeInc)
 184     {
 185 	if (sizeHints.width_inc == 0)
 186 	    sizeHints.width_inc = 1;
 187 
 188 	if (sizeHints.height_inc == 0)
 189 	    sizeHints.height_inc = 1;
 190     }
 191     else
 192     {
 193 	sizeHints.width_inc  = 1;
 194 	sizeHints.height_inc = 1;
 195 	sizeHints.flags |= PResizeInc;
 196     }
 197 
 198     if (sizeHints.flags & PAspect)
 199     {
 200 	/* don't divide by 0 */
 201 	if (sizeHints.min_aspect.y < 1)
 202 	    sizeHints.min_aspect.y = 1;
 203 
 204 	if (sizeHints.max_aspect.y < 1)
 205 	    sizeHints.max_aspect.y = 1;
 206     }
 207     else
 208     {
 209 	sizeHints.min_aspect.x = 1;
 210 	sizeHints.min_aspect.y = 65535;
 211 	sizeHints.max_aspect.x = 65535;
 212 	sizeHints.max_aspect.y = 1;
 213 	sizeHints.flags |= PAspect;
 214     }
 215 
 216     if (!(sizeHints.flags & PWinGravity))
 217     {
 218 	sizeHints.win_gravity = NorthWestGravity;
 219 	sizeHints.flags |= PWinGravity;
 220     }
 221 }
 222 
 223 void
 224 PrivateWindow::updateNormalHints ()
 225 {
 226     Status status;
 227     long   supplied;
 228 
 229     status = XGetWMNormalHints (screen->dpy (), priv->id,
 230 				&priv->sizeHints, &supplied);
 231 
 232     if (!status)
 233 	priv->sizeHints.flags = 0;
 234 
 235     priv->recalcNormalHints ();
 236 }
 237 
 238 void
 239 PrivateWindow::updateWmHints ()
 240 {
 241     XWMHints *newHints;
 242     long     dFlags = 0;
 243     bool     iconChanged = false;
 244 
 245     if (hints)
 246 	dFlags = hints->flags;
 247 
 248     inputHint = true;
 249 
 250     newHints = XGetWMHints (screen->dpy (), id);
 251     if (newHints)
 252     {
 253 	dFlags ^= newHints->flags;
 254 
 255 	if (newHints->flags & InputHint)
 256 	    inputHint = newHints->input;
 257 
 258 	if (hints)
 259 	{
 260 	    if ((newHints->flags & IconPixmapHint) &&
 261 		(hints->icon_pixmap != newHints->icon_pixmap))
 262 	    {
 263 		iconChanged = true;
 264 	    }
 265 	    else if ((newHints->flags & IconMaskHint) &&
 266 		     (hints->icon_mask != newHints->icon_mask))
 267 	    {
 268 		iconChanged = true;
 269 	    }
 270 	}
 271     }
 272 
 273     iconChanged |= (dFlags & (IconPixmapHint | IconMaskHint));
 274 
 275     if (iconChanged)
 276 	freeIcons ();
 277 
 278     if (hints)
 279 	XFree (hints);
 280 
 281     hints = newHints;
 282 }
 283 
 284 void
 285 PrivateWindow::updateClassHints ()
 286 {
 287     XClassHint classHint;
 288     int	       status;
 289 
 290     if (priv->resName)
 291     {
 292 	free (priv->resName);
 293 	priv->resName = NULL;
 294     }
 295 
 296     if (priv->resClass)
 297     {
 298 	free (priv->resClass);
 299 	priv->resClass = NULL;
 300     }
 301 
 302     status = XGetClassHint (screen->dpy (),
 303 			    priv->id, &classHint);
 304     if (status)
 305     {
 306 	if (classHint.res_name)
 307 	{
 308 	    priv->resName = strdup (classHint.res_name);
 309 	    XFree (classHint.res_name);
 310 	}
 311 
 312 	if (classHint.res_class)
 313 	{
 314 	    priv->resClass = strdup (classHint.res_class);
 315 	    XFree (classHint.res_class);
 316 	}
 317     }
 318 }
 319 
 320 void
 321 PrivateWindow::updateTransientHint ()
 322 {
 323     Window transientFor;
 324     Status status;
 325 
 326     priv->transientFor = None;
 327 
 328     status = XGetTransientForHint (screen->dpy (),
 329 				   priv->id, &transientFor);
 330 
 331     if (status)
 332     {
 333 	CompWindow *ancestor;
 334 
 335 	ancestor = screen->findWindow (transientFor);
 336 	if (!ancestor)
 337 	    return;
 338 
 339 	/* protect against circular transient dependencies */
 340 	if (transientFor == priv->id ||
 341 	    PrivateWindow::isAncestorTo (ancestor, window))
 342 	    return;
 343 
 344 	priv->transientFor = transientFor;
 345     }
 346 }
 347 
 348 void
 349 PrivateWindow::updateIconGeometry ()
 350 {
 351     Atom	  actual;
 352     int		  result, format;
 353     unsigned long n, left;
 354     unsigned char *data;
 355 
 356     priv->iconGeometry.setGeometry (0, 0, 0, 0);
 357 
 358     result = XGetWindowProperty (screen->dpy (), priv->id,
 359 				 Atoms::wmIconGeometry,
 360 				 0L, 1024L, False, XA_CARDINAL,
 361 				 &actual, &format, &n, &left, &data);
 362 
 363     if (result == Success && data)
 364     {
 365 	if (n == 4)
 366 	{
 367 	    unsigned long *geometry = (unsigned long *) data;
 368 
 369 	    priv->iconGeometry.setX (geometry[0]);
 370 	    priv->iconGeometry.setY (geometry[1]);
 371 	    priv->iconGeometry.setWidth (geometry[2]);
 372 	    priv->iconGeometry.setHeight (geometry[3]);
 373 	}
 374 
 375 	XFree (data);
 376     }
 377 }
 378 
 379 Window
 380 PrivateWindow::getClientLeaderOfAncestor ()
 381 {
 382     if (transientFor)
 383     {
 384 	CompWindow *w = screen->findWindow (transientFor);
 385 	if (w)
 386 	{
 387 	    if (w->priv->clientLeader)
 388 		return w->priv->clientLeader;
 389 
 390 	    return w->priv->getClientLeaderOfAncestor ();
 391 	}
 392     }
 393 
 394     return None;
 395 }
 396 
 397 Window
 398 PrivateWindow::getClientLeader ()
 399 {
 400     Atom	  actual;
 401     int		  result, format;
 402     unsigned long n, left;
 403     unsigned char *data;
 404 
 405     result = XGetWindowProperty (screen->dpy (), priv->id,
 406 				 Atoms::wmClientLeader,
 407 				 0L, 1L, False, XA_WINDOW, &actual, &format,
 408 				 &n, &left, &data);
 409 
 410     if (result == Success && data)
 411     {
 412 	Window win = None;
 413 
 414 	if (n)
 415 	    memcpy (&win, data, sizeof (Window));
 416 
 417 	XFree ((void *) data);
 418 
 419 	if (win)
 420 	    return win;
 421     }
 422 
 423     return priv->getClientLeaderOfAncestor ();
 424 }
 425 
 426 char *
 427 PrivateWindow::getStartupId ()
 428 {
 429     Atom	  actual;
 430     int		  result, format;
 431     unsigned long n, left;
 432     unsigned char *data;
 433 
 434     result = XGetWindowProperty (screen->dpy (), priv->id,
 435 				 Atoms::startupId,
 436 				 0L, 1024L, False,
 437 				 Atoms::utf8String,
 438 				 &actual, &format,
 439 				 &n, &left, &data);
 440 
 441     if (result == Success && data)
 442     {
 443 	char *id = NULL;
 444 
 445 	if (n)
 446 	    id = strdup ((char *) data);
 447 	XFree ((void *) data);
 448 
 449 	return id;
 450     }
 451 
 452     return NULL;
 453 }
 454 
 455 void
 456 PrivateWindow::setFullscreenMonitors (CompFullscreenMonitorSet *monitors)
 457 {
 458     bool         hadFsMonitors = fullscreenMonitorsSet;
 459     unsigned int outputs = screen->outputDevs ().size ();
 460 
 461     fullscreenMonitorsSet = false;
 462 
 463     if (monitors                   &&
 464 	(unsigned int) monitors->left   < outputs &&
 465 	(unsigned int) monitors->right  < outputs &&
 466 	(unsigned int) monitors->top    < outputs &&
 467 	(unsigned int) monitors->bottom < outputs)
 468     {
 469 	CompRect fsRect (screen->outputDevs ()[monitors->left].x1 (),
 470 			 screen->outputDevs ()[monitors->top].y1 (),
 471 			 screen->outputDevs ()[monitors->right].x2 (),
 472 			 screen->outputDevs ()[monitors->bottom].y2 ());
 473 
 474 	if (fsRect.x1 () < fsRect.x2 () && fsRect.y1 () < fsRect.y2 ())
 475 	{
 476 	    fullscreenMonitorsSet = true;
 477 	    fullscreenMonitorRect = fsRect;
 478 	}
 479     }
 480 
 481     if (fullscreenMonitorsSet)
 482     {
 483 	long data[4];
 484 
 485 	data[0] = monitors->top;
 486 	data[1] = monitors->bottom;
 487 	data[2] = monitors->left;
 488 	data[3] = monitors->right;
 489 
 490 	XChangeProperty (screen->dpy (), id, Atoms::wmFullscreenMonitors,
 491 			 XA_CARDINAL, 32, PropModeReplace,
 492 			 (unsigned char *) data, 4);
 493     }
 494     else if (hadFsMonitors)
 495     {
 496 	XDeleteProperty (screen->dpy (), id, Atoms::wmFullscreenMonitors);
 497     }
 498 
 499     if (state & CompWindowStateFullscreenMask)
 500 	if (fullscreenMonitorsSet || hadFsMonitors)
 501 	    window->updateAttributes (CompStackingUpdateModeNone);
 502 }
 503 
 504 void
 505 CompWindow::changeState (unsigned int newState)
 506 {
 507     if (priv->state == newState)
 508 	return;
 509 
 510     unsigned int oldState = priv->state;
 511     priv->state = newState;
 512 
 513     recalcType ();
 514     recalcActions ();
 515 
 516     if (priv->managed)
 517 	screen->setWindowState (priv->state, priv->id);
 518 
 519     stateChangeNotify (oldState);
 520     screen->matchPropertyChanged (this);
 521 }
 522 
 523 static void
 524 setWindowActions (CompScreen   *s,
 525 		  unsigned int actions,
 526 		  Window       id)
 527 {
 528     Atom data[32];
 529     int	 i = 0;
 530 
 531     if (actions & CompWindowActionMoveMask)
 532 	data[i++] = Atoms::winActionMove;
 533     if (actions & CompWindowActionResizeMask)
 534 	data[i++] = Atoms::winActionResize;
 535     if (actions & CompWindowActionStickMask)
 536 	data[i++] = Atoms::winActionStick;
 537     if (actions & CompWindowActionMinimizeMask)
 538 	data[i++] = Atoms::winActionMinimize;
 539     if (actions & CompWindowActionMaximizeHorzMask)
 540 	data[i++] = Atoms::winActionMaximizeHorz;
 541     if (actions & CompWindowActionMaximizeVertMask)
 542 	data[i++] = Atoms::winActionMaximizeVert;
 543     if (actions & CompWindowActionFullscreenMask)
 544 	data[i++] = Atoms::winActionFullscreen;
 545     if (actions & CompWindowActionCloseMask)
 546 	data[i++] = Atoms::winActionClose;
 547     if (actions & CompWindowActionShadeMask)
 548 	data[i++] = Atoms::winActionShade;
 549     if (actions & CompWindowActionChangeDesktopMask)
 550 	data[i++] = Atoms::winActionChangeDesktop;
 551     if (actions & CompWindowActionAboveMask)
 552 	data[i++] = Atoms::winActionAbove;
 553     if (actions & CompWindowActionBelowMask)
 554 	data[i++] = Atoms::winActionBelow;
 555 
 556     XChangeProperty (s->dpy (), id, Atoms::wmAllowedActions,
 557 		     XA_ATOM, 32, PropModeReplace,
 558 		     (unsigned char *) data, i);
 559 }
 560 
 561 void
 562 CompWindow::recalcActions ()
 563 {
 564     unsigned int actions = 0;
 565     unsigned int setActions, clearActions;
 566 
 567     switch (priv->type) {
 568     case CompWindowTypeFullscreenMask:
 569     case CompWindowTypeNormalMask:
 570 	actions =
 571 	    CompWindowActionMaximizeHorzMask |
 572 	    CompWindowActionMaximizeVertMask |
 573 	    CompWindowActionFullscreenMask   |
 574 	    CompWindowActionMoveMask         |
 575 	    CompWindowActionResizeMask       |
 576 	    CompWindowActionStickMask        |
 577 	    CompWindowActionMinimizeMask     |
 578 	    CompWindowActionCloseMask	     |
 579 	    CompWindowActionChangeDesktopMask;
 580 	break;
 581     case CompWindowTypeUtilMask:
 582     case CompWindowTypeMenuMask:
 583     case CompWindowTypeToolbarMask:
 584 	actions =
 585 	    CompWindowActionMoveMask   |
 586 	    CompWindowActionResizeMask |
 587 	    CompWindowActionStickMask  |
 588 	    CompWindowActionCloseMask  |
 589 	    CompWindowActionChangeDesktopMask;
 590 	break;
 591     case CompWindowTypeDialogMask:
 592     case CompWindowTypeModalDialogMask:
 593 	actions =
 594 	    CompWindowActionMaximizeHorzMask |
 595 	    CompWindowActionMaximizeVertMask |
 596 	    CompWindowActionMoveMask         |
 597 	    CompWindowActionResizeMask       |
 598 	    CompWindowActionStickMask        |
 599 	    CompWindowActionCloseMask        |
 600 	    CompWindowActionChangeDesktopMask;
 601 
 602 	/* allow minimization for dialog windows if they
 603 	   a) are not a transient (transients can be minimized
 604 	      with their parent)
 605 	   b) don't have the skip taskbar hint set (as those
 606 	      have no target to be minimized to)
 607 	*/
 608 	if (!priv->transientFor &&
 609 	    !(priv->state & CompWindowStateSkipTaskbarMask))
 610 	{
 611 	    actions |= CompWindowActionMinimizeMask;
 612 	}
 613     default:
 614 	break;
 615     }
 616 
 617     if (priv->serverInput.top)
 618 	actions |= CompWindowActionShadeMask;
 619 
 620     actions |= (CompWindowActionAboveMask | CompWindowActionBelowMask);
 621 
 622     switch (priv->wmType) {
 623     case CompWindowTypeNormalMask:
 624 	actions |= CompWindowActionFullscreenMask |
 625 	           CompWindowActionMinimizeMask;
 626     default:
 627 	break;
 628     }
 629 
 630     if (priv->sizeHints.min_width  == priv->sizeHints.max_width &&
 631 	priv->sizeHints.min_height == priv->sizeHints.max_height)
 632 	actions &= ~(CompWindowActionResizeMask	      |
 633 		     CompWindowActionMaximizeHorzMask |
 634 		     CompWindowActionMaximizeVertMask |
 635 		     CompWindowActionFullscreenMask);
 636 
 637     /* Don't allow maximization or fullscreen
 638      * of windows which are too big to fit
 639      * the screen */
 640     bool foundVert = false;
 641     bool foundHorz = false;
 642     bool foundFull = false;
 643 
 644     foreach (CompOutput &o, screen->outputDevs ())
 645     {
 646 	if (o.width () >= (priv->sizeHints.min_width + priv->border.left + priv->border.right))
 647 	    foundHorz = true;
 648 	if (o.height () >= (priv->sizeHints.min_height + priv->border.top + priv->border.bottom))
 649 	    foundVert = true;
 650 
 651 	/* Fullscreen windows don't need to fit borders... */
 652 	if (o.width () >= priv->sizeHints.min_width &&
 653 	    o.height () >= priv->sizeHints.min_height)
 654 	    foundFull = true;
 655     }
 656 
 657     if (!foundHorz)
 658 	actions &= ~CompWindowActionMaximizeHorzMask;
 659 
 660     if (!foundVert)
 661 	actions &= ~CompWindowActionMaximizeVertMask;
 662 
 663     if (!foundFull)
 664 	actions &= ~CompWindowActionFullscreenMask;
 665 
 666     if (!(priv->mwmFunc & MwmFuncAll))
 667     {
 668 	if (!(priv->mwmFunc & MwmFuncResize))
 669 	    actions &= ~(CompWindowActionResizeMask	  |
 670 			 CompWindowActionMaximizeHorzMask |
 671 			 CompWindowActionMaximizeVertMask |
 672 			 CompWindowActionFullscreenMask);
 673 
 674 	if (!(priv->mwmFunc & MwmFuncMove))
 675 	    actions &= ~(CompWindowActionMoveMask	  |
 676 			 CompWindowActionMaximizeHorzMask |
 677 			 CompWindowActionMaximizeVertMask |
 678 			 CompWindowActionFullscreenMask);
 679 
 680 	if (!(priv->mwmFunc & MwmFuncIconify))
 681 	    actions &= ~CompWindowActionMinimizeMask;
 682 
 683 	if (!(priv->mwmFunc & MwmFuncClose))
 684 	    actions &= ~CompWindowActionCloseMask;
 685     }
 686 
 687     getAllowedActions (setActions, clearActions);
 688     actions &= ~clearActions;
 689     actions |= setActions;
 690 
 691     if (actions != priv->actions)
 692     {
 693 	priv->actions = actions;
 694 	setWindowActions (screen, actions, priv->id);
 695     }
 696 }
 697 
 698 void
 699 CompWindow::getAllowedActions (unsigned int &setActions,
 700 			       unsigned int &clearActions)
 701 {
 702     WRAPABLE_HND_FUNCTN (getAllowedActions, setActions, clearActions)
 703 
 704     setActions   = 0;
 705     clearActions = 0;
 706 }
 707 
 708 unsigned int
 709 CompWindow::constrainWindowState (unsigned int state,
 710 				  unsigned int actions)
 711 {
 712     if (!(actions & CompWindowActionMaximizeHorzMask))
 713 	state &= ~CompWindowStateMaximizedHorzMask;
 714 
 715     if (!(actions & CompWindowActionMaximizeVertMask))
 716 	state &= ~CompWindowStateMaximizedVertMask;
 717 
 718     if (!(actions & CompWindowActionShadeMask))
 719 	state &= ~CompWindowStateShadedMask;
 720 
 721     if (!(actions & CompWindowActionFullscreenMask))
 722 	state &= ~CompWindowStateFullscreenMask;
 723 
 724     return state;
 725 }
 726 
 727 unsigned int
 728 PrivateWindow::windowTypeFromString (const char *str)
 729 {
 730     if (strcasecmp (str, "desktop") == 0)
 731 	return CompWindowTypeDesktopMask;
 732     else if (strcasecmp (str, "dock") == 0)
 733 	return CompWindowTypeDockMask;
 734     else if (strcasecmp (str, "toolbar") == 0)
 735 	return CompWindowTypeToolbarMask;
 736     else if (strcasecmp (str, "menu") == 0)
 737 	return CompWindowTypeMenuMask;
 738     else if (strcasecmp (str, "utility") == 0)
 739 	return CompWindowTypeUtilMask;
 740     else if (strcasecmp (str, "splash") == 0)
 741 	return CompWindowTypeSplashMask;
 742     else if (strcasecmp (str, "dialog") == 0)
 743 	return CompWindowTypeDialogMask;
 744     else if (strcasecmp (str, "normal") == 0)
 745 	return CompWindowTypeNormalMask;
 746     else if (strcasecmp (str, "dropdownmenu") == 0)
 747 	return CompWindowTypeDropdownMenuMask;
 748     else if (strcasecmp (str, "popupmenu") == 0)
 749 	return CompWindowTypePopupMenuMask;
 750     else if (strcasecmp (str, "tooltip") == 0)
 751 	return CompWindowTypeTooltipMask;
 752     else if (strcasecmp (str, "notification") == 0)
 753 	return CompWindowTypeNotificationMask;
 754     else if (strcasecmp (str, "combo") == 0)
 755 	return CompWindowTypeComboMask;
 756     else if (strcasecmp (str, "dnd") == 0)
 757 	return CompWindowTypeDndMask;
 758     else if (strcasecmp (str, "modaldialog") == 0)
 759 	return CompWindowTypeModalDialogMask;
 760     else if (strcasecmp (str, "fullscreen") == 0)
 761 	return CompWindowTypeFullscreenMask;
 762     else if (strcasecmp (str, "unknown") == 0)
 763 	return CompWindowTypeUnknownMask;
 764     else if (strcasecmp (str, "any") == 0)
 765 	return ~0;
 766 
 767     return 0;
 768 }
 769 
 770 void
 771 CompWindow::recalcType ()
 772 {
 773     unsigned int type;
 774 
 775     type = priv->wmType;
 776 
 777     if (!overrideRedirect () && priv->wmType == CompWindowTypeUnknownMask)
 778 	type = CompWindowTypeNormalMask;
 779 
 780     if (priv->state & CompWindowStateFullscreenMask)
 781 	type = CompWindowTypeFullscreenMask;
 782 
 783     if (type == CompWindowTypeNormalMask)
 784     {
 785 	if (priv->transientFor)
 786 	    type = CompWindowTypeDialogMask;
 787     }
 788 
 789     if (type == CompWindowTypeDockMask &&
 790 	(priv->state & CompWindowStateBelowMask))
 791     {
 792 	type = CompWindowTypeNormalMask;
 793     }
 794 
 795     if ((type & (CompWindowTypeNormalMask | CompWindowTypeDialogMask)) &&
 796 	(priv->state & CompWindowStateModalMask))
 797     {
 798 	type = CompWindowTypeModalDialogMask;
 799     }
 800 
 801     priv->type = type;
 802 }
 803 
 804 
 805 void
 806 PrivateWindow::updateFrameWindow ()
 807 {
 808     if (!serverFrame)
 809 	return;
 810 
 811     XWindowChanges xwc = XWINDOWCHANGES_INIT;
 812     unsigned int   valueMask = CWX | CWY | CWWidth | CWHeight;
 813 
 814     xwc.x = serverGeometry.x ();
 815     xwc.y = serverGeometry.y ();
 816     xwc.width = serverGeometry.width ();
 817     xwc.height = serverGeometry.height ();
 818     xwc.border_width = serverGeometry.border ();
 819 
 820     window->configureXWindow (valueMask, &xwc);
 821     window->windowNotify (CompWindowNotifyFrameUpdate);
 822     window->recalcActions ();
 823 }
 824 
 825 
 826 
 827 void
 828 CompWindow::updateWindowOutputExtents ()
 829 {
 830     CompWindowExtents output (priv->output);
 831 
 832     getOutputExtents (output);
 833 
 834     if (output.left   != priv->output.left  ||
 835 	output.right  != priv->output.right ||
 836 	output.top    != priv->output.top   ||
 837 	output.bottom != priv->output.bottom)
 838     {
 839 	priv->output = output;
 840 
 841 	resizeNotify (0, 0, 0, 0);
 842     }
 843 }
 844 
 845 void
 846 CompWindow::getOutputExtents (CompWindowExtents& output)
 847 {
 848     WRAPABLE_HND_FUNCTN (getOutputExtents, output)
 849 
 850     output.left   = 0;
 851     output.right  = 0;
 852     output.top    = 0;
 853     output.bottom = 0;
 854 }
 855 
 856 CompRegion
 857 PrivateWindow::rectsToRegion (unsigned int n, XRectangle *rects)
 858 {
 859     CompRegion ret;
 860     int        x1, x2, y1, y2;
 861     const CompWindow::Geometry &geom = attrib.override_redirect ? priv->geometry : priv->serverGeometry;
 862 
 863     for (unsigned int i = 0; i < n; i++)
 864     {
 865 	x1 = rects[i].x + geom.border ();
 866 	y1 = rects[i].y + geom.border ();
 867 	x2 = x1 + rects[i].width;
 868 	y2 = y1 + rects[i].height;
 869 
 870 	if (x1 < 0)
 871 	    x1 = 0;
 872 	if (y1 < 0)
 873 	    y1 = 0;
 874 	if (x2 > geom.width ())
 875 	    x2 = geom.width ();
 876 	if (y2 > geom.height ())
 877 	    y2 = geom.height ();
 878 
 879 	if (y1 < y2 && x1 < x2)
 880 	{
 881 	    x1 += geom.x ();
 882 	    y1 += geom.y ();
 883 	    x2 += geom.x ();
 884 	    y2 += geom.y ();
 885 
 886 	    ret += CompRect (x1, y1, x2 - x1, y2 - y1);
 887 	}
 888     }
 889 
 890     return ret;
 891 }
 892 
 893 /* TODO: This function should be able to check the XShape event
 894  * kind and only get/set shape rectangles for either ShapeInput
 895  * or ShapeBounding, but not both at the same time
 896  */
 897 
 898 void
 899 PrivateWindow::updateRegion ()
 900 {
 901     XRectangle r, *boundingShapeRects = NULL;
 902     XRectangle *inputShapeRects = NULL;
 903     int	       nBounding = 0, nInput = 0;
 904     const CompWindow::Geometry &geom = attrib.override_redirect ? priv->geometry : priv->serverGeometry;
 905 
 906     priv->region = priv->inputRegion = emptyRegion;
 907 
 908     bool useXShape = screen->XShape ();
 909     if (useXShape)
 910     {
 911 	int order;
 912 
 913 	/* We should update the server here */
 914 	XSync (screen->dpy (), false);
 915 
 916 	boundingShapeRects = XShapeGetRectangles (screen->dpy (), priv->id,
 917 					 	  ShapeBounding, &nBounding, &order);
 918 	inputShapeRects = XShapeGetRectangles (screen->dpy (), priv->id,
 919 					       ShapeInput, &nInput, &order);
 920     }
 921 
 922     r.x      = -geom.border ();
 923     r.y      = -geom.border ();
 924     r.width  = geom.widthIncBorders ();
 925     r.height = geom.heightIncBorders ();
 926 
 927     if (nBounding < 1)
 928     {
 929 	boundingShapeRects = &r;
 930 	nBounding = 1;
 931     }
 932 
 933     if (!useXShape)
 934     {
 935 	inputShapeRects = &r;
 936 	nInput = 1;
 937     }
 938 
 939     priv->region += rectsToRegion (nBounding, boundingShapeRects);
 940     priv->inputRegion += rectsToRegion (nInput, inputShapeRects);
 941 
 942     if (boundingShapeRects && boundingShapeRects != &r)
 943 	XFree (boundingShapeRects);
 944     if (inputShapeRects && inputShapeRects != &r)
 945 	XFree (inputShapeRects);
 946 
 947     window->updateFrameRegion ();
 948 }
 949 
 950 bool
 951 CompWindow::updateStruts ()
 952 {
 953     Atom	  actual;
 954     int		  result, format;
 955     unsigned long n, left;
 956     unsigned char *data;
 957     bool	  hasOld, hasNew;
 958     CompStruts    oldStrut, newStrut;
 959 
 960     if (priv->struts)
 961     {
 962 	hasOld = true;
 963 
 964 	oldStrut.left   = priv->struts->left;
 965 	oldStrut.right  = priv->struts->right;
 966 	oldStrut.top    = priv->struts->top;
 967 	oldStrut.bottom = priv->struts->bottom;
 968     }
 969     else
 970     {
 971 	hasOld = false;
 972     }
 973 
 974     hasNew = false;
 975 
 976     newStrut.left.x	    = 0;
 977     newStrut.left.y	    = 0;
 978     newStrut.left.width  = 0;
 979     newStrut.left.height = screen->height ();
 980 
 981     newStrut.right.x      = screen->width ();
 982     newStrut.right.y      = 0;
 983     newStrut.right.width  = 0;
 984     newStrut.right.height = screen->height ();
 985 
 986     newStrut.top.x	   = 0;
 987     newStrut.top.y	   = 0;
 988     newStrut.top.width  = screen->width ();
 989     newStrut.top.height = 0;
 990 
 991     newStrut.bottom.x      = 0;
 992     newStrut.bottom.y      = screen->height ();
 993     newStrut.bottom.width  = screen->width ();
 994     newStrut.bottom.height = 0;
 995 
 996     result = XGetWindowProperty (screen->dpy (), priv->id,
 997 				 Atoms::wmStrutPartial,
 998 				 0L, 12L, false, XA_CARDINAL, &actual, &format,
 999 				 &n, &left, &data);
1000 
1001     if (result == Success && data)
1002     {
1003 	unsigned long *struts = (unsigned long *) data;
1004 
1005 	if (n == 12)
1006 	{
1007 	    hasNew = true;
1008 
1009 	    newStrut.left.y        = struts[4];
1010 	    newStrut.left.width    = struts[0];
1011 	    newStrut.left.height   = struts[5] - newStrut.left.y + 1;
1012 
1013 	    newStrut.right.width   = struts[1];
1014 	    newStrut.right.x       = screen->width () - newStrut.right.width;
1015 	    newStrut.right.y       = struts[6];
1016 	    newStrut.right.height  = struts[7] - newStrut.right.y + 1;
1017 
1018 	    newStrut.top.x         = struts[8];
1019 	    newStrut.top.width     = struts[9] - newStrut.top.x + 1;
1020 	    newStrut.top.height    = struts[2];
1021 
1022 	    newStrut.bottom.x      = struts[10];
1023 	    newStrut.bottom.width  = struts[11] - newStrut.bottom.x + 1;
1024 	    newStrut.bottom.height = struts[3];
1025 	    newStrut.bottom.y      = screen->height () - newStrut.bottom.height;
1026 	}
1027 
1028 	XFree (data);
1029     }
1030 
1031     if (!hasNew)
1032     {
1033 	result = XGetWindowProperty (screen->dpy (), priv->id,
1034 				     Atoms::wmStrut,
1035 				     0L, 4L, false, XA_CARDINAL,
1036 				     &actual, &format, &n, &left, &data);
1037 
1038 	if (result == Success && data)
1039 	{
1040 	    unsigned long *struts = (unsigned long *) data;
1041 
1042 	    if (n == 4)
1043 	    {
1044 		hasNew = true;
1045 
1046 		newStrut.left.x        = 0;
1047 		newStrut.left.width    = struts[0];
1048 
1049 		newStrut.right.width   = struts[1];
1050 		newStrut.right.x       = screen->width () - newStrut.right.width;
1051 
1052 		newStrut.top.y         = 0;
1053 		newStrut.top.height    = struts[2];
1054 
1055 		newStrut.bottom.height = struts[3];
1056 		newStrut.bottom.y      = screen->height () - newStrut.bottom.height;
1057 	    }
1058 
1059 	    XFree (data);
1060 	}
1061     }
1062 
1063     if (hasNew)
1064     {
1065 	int strutX1, strutY1, strutX2, strutY2;
1066 	int x1, y1, x2, y2;
1067 
1068 	/* applications expect us to clip struts to xinerama edges */
1069 	for (unsigned int i = 0;
1070 	     i < screen->screenInfo ().size (); i++)
1071 	{
1072 	    x1 = screen->screenInfo ()[i].x_org;
1073 	    y1 = screen->screenInfo ()[i].y_org;
1074 	    x2 = x1 + screen->screenInfo ()[i].width;
1075 	    y2 = y1 + screen->screenInfo ()[i].height;
1076 
1077 	    strutX1 = newStrut.left.x;
1078 	    strutX2 = strutX1 + newStrut.left.width;
1079 	    strutY1 = newStrut.left.y;
1080 	    strutY2 = strutY1 + newStrut.left.height;
1081 
1082 	    if (strutX2 > x1 && strutX2 <= x2 &&
1083 		strutY1 < y2 && strutY2 > y1)
1084 	    {
1085 		newStrut.left.x     = x1;
1086 		newStrut.left.width = strutX2 - x1;
1087 	    }
1088 
1089 	    strutX1 = newStrut.right.x;
1090 	    strutX2 = strutX1 + newStrut.right.width;
1091 	    strutY1 = newStrut.right.y;
1092 	    strutY2 = strutY1 + newStrut.right.height;
1093 
1094 	    if (strutX1 > x1 && strutX1 <= x2 &&
1095 		strutY1 < y2 && strutY2 > y1)
1096 	    {
1097 		newStrut.right.x     = strutX1;
1098 		newStrut.right.width = x2 - strutX1;
1099 	    }
1100 
1101 	    strutX1 = newStrut.top.x;
1102 	    strutX2 = strutX1 + newStrut.top.width;
1103 	    strutY1 = newStrut.top.y;
1104 	    strutY2 = strutY1 + newStrut.top.height;
1105 
1106 	    if (strutX1 < x2 && strutX2 > x1 &&
1107 		strutY2 > y1 && strutY2 <= y2)
1108 	    {
1109 		newStrut.top.y      = y1;
1110 		newStrut.top.height = strutY2 - y1;
1111 	    }
1112 
1113 	    strutX1 = newStrut.bottom.x;
1114 	    strutX2 = strutX1 + newStrut.bottom.width;
1115 	    strutY1 = newStrut.bottom.y;
1116 	    strutY2 = strutY1 + newStrut.bottom.height;
1117 
1118 	    if (strutX1 < x2 && strutX2 > x1 &&
1119 		strutY1 > y1 && strutY1 <= y2)
1120 	    {
1121 		newStrut.bottom.y      = strutY1;
1122 		newStrut.bottom.height = y2 - strutY1;
1123 	    }
1124 	}
1125     }
1126 
1127     if (hasOld != hasNew ||
1128 	(hasNew && hasOld &&
1129 	 memcmp (&newStrut, &oldStrut, sizeof (CompStruts))))
1130     {
1131 	if (hasNew)
1132 	{
1133 	    if (!priv->struts)
1134 	    {
1135 		priv->struts = (CompStruts *) malloc (sizeof (CompStruts));
1136 		if (!priv->struts)
1137 		    return false;
1138 	    }
1139 
1140 	    *priv->struts = newStrut;
1141 	}
1142 	else
1143 	{
1144 	    free (priv->struts);
1145 	    priv->struts = NULL;
1146 	}
1147 
1148 	return true;
1149     }
1150 
1151     return false;
1152 }
1153 
1154 void
1155 CompWindow::incrementDestroyReference ()
1156 {
1157     priv->destroyRefCnt++;
1158 }
1159 
1160 void
1161 CompWindow::destroy ()
1162 {
1163     if (priv->id)
1164     {
1165 	CompWindow *oldServerNext, *oldServerPrev, *oldNext, *oldPrev;
1166 	StackDebugger *dbg = StackDebugger::Default ();
1167 
1168 	windowNotify (CompWindowNotifyBeforeDestroy);
1169 
1170 	/* Don't allow frame windows to block input */
1171 	if (priv->serverFrame)
1172 	    XUnmapWindow (screen->dpy (), priv->serverFrame);
1173 
1174 	if (priv->wrapper)
1175 	    XUnmapWindow (screen->dpy (), priv->wrapper);
1176 
1177 	oldServerNext = serverNext;
1178 	oldServerPrev = serverPrev;
1179 	oldNext = next;
1180 	oldPrev = prev;
1181 
1182 	/* This is where things get tricky ... it is possible
1183 	 * to receive a ConfigureNotify relative to a frame window
1184 	 * for a destroyed window in case we process a ConfigureRequest
1185 	 * for the destroyed window and then a DestroyNotify for it directly
1186 	 * afterwards. In that case, we will receive the ConfigureNotify
1187 	 * for the XConfigureWindow request we made relative to that frame
1188 	 * window. Because of this, we must keep the frame window in the stack
1189 	 * as a new toplevel window so that the ConfigureNotify will be processed
1190 	 * properly until it too receives a DestroyNotify */
1191 
1192 	if (priv->serverFrame)
1193 	{
1194 	    XWindowAttributes attrib;
1195 
1196 	    /* It's possible that the frame window was already destroyed because
1197 	     * the client was unreparented before it was destroyed (eg
1198 	     * UnmapNotify before DestroyNotify). In that case the frame window
1199 	     * is going to be an invalid window but since we haven't received
1200 	     * a DestroyNotify for it yet, it is possible that restacking
1201 	     * operations could occurr relative to it so we need to hold it
1202 	     * in the stack for now. Ensure that it is marked override redirect */
1203 	    XGetWindowAttributes (screen->dpy (), priv->serverFrame, &attrib);
1204 
1205 	    /* Put the frame window "above" the client window
1206 	     * in the stack */
1207 	    PrivateWindow::createCompWindow (priv->id, priv->id, attrib, priv->serverFrame);
1208 	}
1209 
1210 	/* Immediately unhook the window once destroyed
1211 	 * as the stacking order will be invalid if we don't
1212 	 * and will continue to be invalid for the period
1213 	 * that we keep it around in the stack. Instead, push
1214 	 * it to another stack and keep the next and prev members
1215 	 * in tact, letting plugins sort out where those windows
1216 	 * might be in case they need to use them relative to
1217 	 * other windows */
1218 
1219 	screen->unhookWindow (this);
1220 	screen->unhookServerWindow (this);
1221 
1222 	/* We must immediately insert the window into the debugging
1223 	 * stack */
1224 	if (dbg)
1225 	    dbg->removeServerWindow (id ());
1226 
1227 	/* Unhooking the window will also NULL the next/prev
1228 	 * linked list links but we don't want that so don't
1229 	 * do that */
1230 
1231 	next = oldNext;
1232 	prev = oldPrev;
1233 	serverNext = oldServerNext;
1234 	serverPrev = oldServerPrev;
1235 
1236 	screen->addToDestroyedWindows (this);
1237 
1238 	/* We must set the xid of this window
1239 	 * to zero as it no longer references
1240 	 * a valid window */
1241 	priv->mapNum = 0;
1242 	priv->id = 0;
1243 	priv->frame = 0;
1244 	priv->serverFrame = 0;
1245 	priv->managed    = false;
1246     }
1247 
1248     priv->destroyRefCnt--;
1249     if (priv->destroyRefCnt)
1250 	return;
1251 
1252     if (!priv->destroyed)
1253     {
1254 	if (!priv->serverFrame)
1255 	{
1256 	    StackDebugger *dbg = StackDebugger::Default ();
1257 
1258 	    if (dbg)
1259 		dbg->addDestroyedFrame (priv->serverId);
1260 	}
1261 
1262 	priv->destroyed = true;
1263 	screen->incrementPendingDestroys();
1264     }
1265 
1266 }
1267 
1268 void
1269 CompWindow::sendConfigureNotify ()
1270 {
1271     XConfigureEvent xev;
1272 
1273     xev.type   = ConfigureNotify;
1274     xev.event  = priv->id;
1275     xev.window = priv->id;
1276 
1277     xev.x	     = priv->serverGeometry.x ();
1278     xev.y	     = priv->serverGeometry.y ();
1279     xev.width	     = priv->serverGeometry.width ();
1280     xev.height	     = priv->serverGeometry.height ();
1281     xev.border_width = priv->serverGeometry.border ();
1282     xev.override_redirect = priv->attrib.override_redirect;
1283 
1284     /* These used to be based on the actual sibling of the window
1285      * (eg, obtained using XQueryTree), but they are now zeroed out.
1286      *
1287      * The ICCCM is a big unclear on what these should be - it
1288      * requires that after the client attempts to configure a window
1289      * we should issue a synthetic ConfigureNotify to work around
1290      * the change of co-ordinates due to reparenting:
1291      *
1292      * "A client will receive a synthetic ConfigureNotify event
1293      *  following the change that describes the new geometry of the window"
1294      *
1295      * However there is an acknowledgement on stacking order:
1296      *
1297      * "Not changing the size, location, border width,
1298      *  or stacking order of the window at all."
1299      *
1300      * Since there isn't any advice as to what to set the above and
1301      * detail members, the only choices are to either grab the server
1302      * and query it for the sibling to the window's parent, or to just
1303      * set them to zero.
1304      *
1305      * An evaluation of other window managers showed that they just set
1306      * these fields to zero. This is probably a safe option and justifies
1307      * the potential performance tradeoff that we get out of not having
1308      * to grab the server, query window attributes and children and
1309      * translate co-ordinates every time a window is moved
1310      */
1311 
1312     xev.above = None;
1313 
1314     XSendEvent (screen->dpy (), priv->id, false,
1315 		StructureNotifyMask, (XEvent *) &xev);
1316 }
1317 
1318 void
1319 CompWindow::map ()
1320 {
1321     windowNotify (CompWindowNotifyBeforeMap);
1322 
1323     /* Previously not viewable */
1324     if (!isViewable ())
1325     {
1326 	if (priv->pendingMaps > 0)
1327 	    priv->pendingMaps = 0;
1328 
1329 	priv->mapNum = screen->nextMapNum();
1330 
1331 	if (priv->struts)
1332 	    screen->updateWorkarea ();
1333 
1334 	if (windowClass () == InputOnly)
1335 	    return;
1336 
1337 	priv->unmapRefCnt = 1;
1338 
1339 	priv->attrib.map_state = IsViewable;
1340 
1341 	if (!overrideRedirect ())
1342 	    screen->setWmState (NormalState, priv->id);
1343 
1344 	priv->invisible  = priv->isInvisible ();
1345 	priv->alive      = true;
1346 
1347 	priv->lastPong = screen->lastPing ();
1348 
1349 	priv->updateRegion ();
1350 	priv->updateSize ();
1351 
1352 	screen->updateClientList ();
1353 
1354 	if (priv->type & CompWindowTypeDesktopMask)
1355 	    screen->incrementDesktopWindowCount();
1356 
1357 	if (priv->protocols & CompWindowProtocolSyncRequestMask)
1358 	{
1359 	    sendSyncRequest ();
1360 	    sendConfigureNotify ();
1361 	}
1362 
1363 	if (!overrideRedirect ())
1364 	{
1365 	    /* been shaded */
1366 	    if (priv->shaded)
1367 	    {
1368 		priv->shaded = false;
1369 		priv->updateFrameWindow ();
1370 	    }
1371 	}
1372     }
1373 
1374     windowNotify (CompWindowNotifyMap);
1375     /* Send a resizeNotify to plugins to indicate
1376      * that the map is complete */
1377     resizeNotify (0, 0, 0, 0);
1378 }
1379 
1380 void
1381 CompWindow::incrementUnmapReference ()
1382 {
1383     priv->unmapRefCnt++;
1384 }
1385 
1386 void
1387 CompWindow::unmap ()
1388 {
1389     if (priv->mapNum)
1390 	priv->mapNum = 0;
1391 
1392     windowNotify (CompWindowNotifyBeforeUnmap);
1393 
1394     /* Even though we're still keeping the backing
1395      * pixmap of the window around, it's safe to
1396      * unmap the frame window since there's no use
1397      * for it at this point anyways and it just blocks
1398      * input, but keep it around if shaded */
1399 
1400     XUnmapWindow (screen->dpy (), priv->wrapper);
1401 
1402     if (!priv->shaded)
1403 	XUnmapWindow (screen->dpy (), priv->serverFrame);
1404 
1405     priv->unmapRefCnt--;
1406     if (priv->unmapRefCnt > 0)
1407 	return;
1408 
1409     if (priv->unmanaging)
1410     {
1411 	XWindowChanges xwc = XWINDOWCHANGES_INIT;
1412 	unsigned int   xwcm;
1413 	int		   gravity = priv->sizeHints.win_gravity;
1414 
1415 	/* revert gravity adjustment made at MapNotify time */
1416 	xwc.x	= priv->serverGeometry.x ();
1417 	xwc.y	= priv->serverGeometry.y ();
1418 	xwc.width   = 0;
1419 	xwc.height  = 0;
1420 
1421 	xwcm = priv->adjustConfigureRequestForGravity (&xwc,
1422 						       CWX | CWY,
1423 						       gravity,
1424 						       -1);
1425 	if (xwcm)
1426 	    configureXWindow (xwcm, &xwc);
1427 
1428 	priv->unmanaging = false;
1429     }
1430 
1431     if (priv->serverFrame && !priv->shaded)
1432 	priv->unreparent ();
1433 
1434     if (priv->struts)
1435 	screen->updateWorkarea ();
1436 
1437     if (priv->attrib.map_state != IsViewable)
1438 	return;
1439 
1440     if (priv->type == CompWindowTypeDesktopMask)
1441 	screen->decrementDesktopWindowCount();
1442 
1443     priv->attrib.map_state = IsUnmapped;
1444     priv->invisible = true;
1445 
1446     if (priv->shaded)
1447 	priv->updateFrameWindow ();
1448 
1449     screen->updateClientList ();
1450 
1451     windowNotify (CompWindowNotifyUnmap);
1452 }
1453 
1454 void
1455 PrivateWindow::withdraw ()
1456 {
1457     if (!attrib.override_redirect)
1458 	screen->setWmState (WithdrawnState, id);
1459 
1460     placed     = false;
1461     unmanaging = managed;
1462     managed    = false;
1463 }
1464 
1465 bool
1466 PrivateWindow::restack (Window aboveId)
1467 {
1468     if (aboveId && (aboveId == id || aboveId == serverFrame))
1469 	// Don't try to raise a window above itself
1470 	return false;
1471     else if (window->prev)
1472     {
1473 	if (aboveId && (aboveId == window->prev->id () ||
1474 			aboveId == window->prev->priv->frame))
1475 	    return false;
1476     }
1477     else if (aboveId == None && !window->next)
1478 	return false;
1479 
1480     if (aboveId && !screen->findTopLevelWindow (aboveId, true))
1481     {
1482         return false;
1483     }
1484 
1485     screen->unhookWindow (window);
1486     screen->insertWindow (window, aboveId);
1487 
1488     /* Update the server side window list for
1489      * override redirect windows immediately
1490      * since there is no opportunity to update
1491      * the server side list when we configure them
1492      * since we never get a ConfigureRequest for those */
1493     if (attrib.override_redirect != 0)
1494     {
1495 	StackDebugger *dbg = StackDebugger::Default ();
1496 
1497 	screen->unhookServerWindow (window);
1498 	screen->insertServerWindow (window, aboveId);
1499 
1500 	if (dbg)
1501 	    dbg->overrideRedirectRestack (window->id (), aboveId);
1502     }
1503 
1504     screen->updateClientList ();
1505 
1506     window->windowNotify (CompWindowNotifyRestack);
1507 
1508     return true;
1509 }
1510 
1511 bool
CID 12473 - PASS_BY_VALUE
Passing parameter attr of type XWindowAttributes (size 136 bytes) by value.
1512 CompWindow::resize (XWindowAttributes attr)
1513 {
1514     return resize (Geometry (attr.x, attr.y, attr.width, attr.height,
1515 			     attr.border_width));
1516 }
1517 
1518 bool
1519 CompWindow::resize (int          x,
1520 		    int          y,
1521 		    int          width,
1522 		    int          height,
1523 		    int          border)
1524 {
1525     return resize (Geometry (x, y, width, height, border));
1526 }
1527 
1528 bool
1529 PrivateWindow::resize (const CompWindow::Geometry &gm)
1530 {
1531     /* Input extents are now the last thing sent
1532      * from the server. This might not work in some
1533      * cases though because setWindowFrameExtents may
1534      * be called more than once in an event processing
1535      * cycle so every set of input extents up until the
1536      * last one will be invalid. The real solution
1537      * here is to handle ConfigureNotify events on
1538      * frame windows and client windows separately */
1539 
1540     priv->input = priv->serverInput;
1541 
1542     if (priv->geometry.width ()   != gm.width ()  ||
1543 	priv->geometry.height ()  != gm.height () ||
1544 	priv->geometry.border ()  != gm.border ())
1545     {
1546 	int dx, dy, dwidth, dheight;
1547 
1548 	dx      = gm.x () - priv->geometry.x ();
1549 	dy      = gm.y () - priv->geometry.y ();
1550 	dwidth  = gm.width () - priv->geometry.width ();
1551 	dheight = gm.height () - priv->geometry.height ();
1552 
1553 	priv->geometry.set (gm.x (), gm.y (),
1554 			    gm.width (), gm.height (),
1555 			    gm.border ());
1556 
1557 	priv->invisible = priv->isInvisible ();
1558 
1559 	if (priv->attrib.override_redirect)
1560 	{
1561 	    priv->serverGeometry = priv->geometry;
1562 	    priv->serverFrameGeometry = priv->frameGeometry;
1563 
1564 	    if (priv->mapNum)
1565 		priv->updateRegion ();
1566 
1567 	    window->resizeNotify (dx, dy, dwidth, dheight);
1568 	}
1569     }
1570     else if (priv->geometry.x () != gm.x () || priv->geometry.y () != gm.y ())
1571     {
1572 	move (gm.x () - priv->geometry.x (),
1573 	      gm.y () - priv->geometry.y (), true);
1574     }
1575 
1576     return true;
1577 }
1578 
1579 bool
1580 PrivateWindow::resize (const XWindowAttributes &attr)
1581 {
1582     return resize (CompWindow::Geometry (attr.x, attr.y, attr.width, attr.height,
1583 					 attr.border_width));
1584 }
1585 
1586 bool
1587 PrivateWindow::resize (int          x,
1588 		       int          y,
1589 		       int          width,
1590 		       int          height,
1591 		       int          border)
1592 {
1593     return resize (CompWindow::Geometry (x, y, width, height, border));
1594 }
1595 
1596 bool
1597 CompWindow::resize (CompWindow::Geometry gm)
1598 {
1599     XWindowChanges xwc = XWINDOWCHANGES_INIT;
1600     unsigned int   valueMask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
1601 
1602     xwc.x = gm.x ();
1603     xwc.y = gm.y ();
1604     xwc.width = gm.width ();
1605     xwc.height = gm.height ();
1606     xwc.border_width = gm.border ();
1607 
1608     configureXWindow (valueMask, &xwc);
1609 
1610     return true;
1611 }
1612 
1613 static void
1614 syncValueIncrement (XSyncValue *value)
1615 {
1616     XSyncValue one;
1617     int	       overflow;
1618 
1619     XSyncIntToValue (&one, 1);
1620     XSyncValueAdd (value, *value, one, &overflow);
1621 }
1622 
1623 bool
1624 PrivateWindow::initializeSyncCounter ()
1625 {
1626     XSyncAlarmAttributes values;
1627     Atom		 actual;
1628     int			 result, format;
1629     unsigned long	 n, left;
1630     unsigned char	 *data;
1631 
1632     if (syncCounter)
1633 	return syncAlarm != None;
1634 
1635     if (!(protocols & CompWindowProtocolSyncRequestMask))
1636 	return false;
1637 
1638     result = XGetWindowProperty (screen->dpy (), id,
1639 				 Atoms::wmSyncRequestCounter,
1640 				 0L, 1L, false, XA_CARDINAL, &actual, &format,
1641 				 &n, &left, &data);
1642 
1643     if (result == Success && n && data)
1644     {
1645 	unsigned long *counter = (unsigned long *) data;
1646 
1647 	syncCounter = *counter;
1648 
1649 	XFree (data);
1650 
1651 	XSyncIntsToValue (&syncValue, (unsigned int) rand (), 0);
1652 	XSyncSetCounter (screen->dpy (),
1653 			 syncCounter,
1654 			 syncValue);
1655 
1656 	syncValueIncrement (&syncValue);
1657 
1658 	values.events = true;
1659 
1660 	values.trigger.counter    = syncCounter;
1661 	values.trigger.wait_value = syncValue;
1662 
1663 	values.trigger.value_type = XSyncAbsolute;
1664 	values.trigger.test_type  = XSyncPositiveComparison;
1665 
1666 	XSyncIntToValue (&values.delta, 1);
1667 
1668 	values.events = true;
1669 
1670 	CompScreenImpl::checkForError (screen->dpy ());
1671 
1672 	/* Note that by default, the alarm increments the trigger value
1673 	 * when it fires until the condition (counter.value < trigger.value)
1674 	 * is false again.
1675 	 */
1676 	syncAlarm = XSyncCreateAlarm (screen->dpy (),
1677 				      XSyncCACounter   |
1678 				      XSyncCAValue     |
1679 				      XSyncCAValueType |
1680 				      XSyncCATestType  |
1681 				      XSyncCADelta     |
1682 				      XSyncCAEvents,
1683 				      &values);
1684 
1685 	if (CompScreenImpl::checkForError (screen->dpy ()))
1686 	    return true;
1687 
1688 	XSyncDestroyAlarm (screen->dpy (), syncAlarm);
1689 	syncAlarm = None;
1690     }
1691     else if (result == Success && data)
1692     {
1693 	XFree (data);
1694     }
1695 
1696     return false;
1697 }
1698 
1699 void
1700 CompWindow::sendSyncRequest ()
1701 {
1702     if (priv->syncWait)
1703 	return;
1704 
1705     if (!priv->initializeSyncCounter ())
1706 	return;
1707 
1708     XClientMessageEvent xev;
1709 
1710     xev.type	     = ClientMessage;
1711     xev.window	     = priv->id;
1712     xev.message_type = Atoms::wmProtocols;
1713     xev.format	     = 32;
1714     xev.data.l[0]    = Atoms::wmSyncRequest;
1715     xev.data.l[1]    = CurrentTime;
1716     xev.data.l[2]    = XSyncValueLow32 (priv->syncValue);
1717     xev.data.l[3]    = XSyncValueHigh32 (priv->syncValue);
1718     xev.data.l[4]    = 0;
1719 
1720     syncValueIncrement (&priv->syncValue);
1721 
1722     XSendEvent (screen->dpy (), priv->id, false, 0, (XEvent *) &xev);
1723 
1724     priv->syncWait     = true;
1725     priv->syncGeometry = priv->serverGeometry;
1726 
1727     if (!priv->syncWaitTimer.active ())
1728 	priv->syncWaitTimer.start ();
1729 }
1730 
1731 void
1732 PrivateWindow::configure (XConfigureEvent *ce)
1733 {
1734     if (priv->frame)
1735 	return;
1736 
1737     unsigned int valueMask = 0;
1738 
1739     /* remove configure event from pending configures */
1740     if (priv->geometry.x () != ce->x)
1741 	valueMask |= CWX;
1742 
1743     if (priv->geometry.y () != ce->y)
1744 	valueMask |= CWY;
1745 
1746     if (priv->geometry.width () != ce->width)
1747 	valueMask |= CWWidth;
1748 
1749     if (priv->geometry.height () != ce->height)
1750 	valueMask |= CWHeight;
1751 
1752     if (priv->geometry.border () != ce->border_width)
1753 	valueMask |= CWBorderWidth;
1754 
1755     if (window->prev)
1756     {
1757 	if (ROOTPARENT (window->prev) != ce->above)
1758 	    valueMask |= CWSibling | CWStackMode;
1759     }
1760     else
1761     {
1762 	if (ce->above != 0)
1763 	    valueMask |= CWSibling | CWStackMode;
1764     }
1765 
1766     priv->attrib.override_redirect = ce->override_redirect;
1767 
1768     priv->frameGeometry.set (ce->x, ce->y, ce->width,
1769 			     ce->height, ce->border_width);
1770 
1771     if (priv->syncWait)
1772 	priv->syncGeometry.set (ce->x, ce->y, ce->width, ce->height,
1773 				ce->border_width);
1774     else
1775     {
1776 	resize (ce->x, ce->y, ce->width, ce->height, ce->border_width);
1777     }
1778 
1779     if (ce->event == screen->root ())
1780 	priv->restack (ce->above);
1781 }
1782 
1783 void
1784 PrivateWindow::configureFrame (XConfigureEvent *ce)
1785 {
1786     if (!priv->frame)
1787 	return;
1788 
1789     int x, y, width, height;
1790     CompWindow	     *above;
1791     unsigned int     valueMask = 0;
1792 
1793     /* remove configure event from pending configures */
1794     if (priv->frameGeometry.x () != ce->x)
1795 	valueMask |= CWX;
1796 
1797     if (priv->frameGeometry.y () != ce->y)
1798 	valueMask |= CWY;
1799 
1800     if (priv->frameGeometry.width () != ce->width)
1801 	valueMask |= CWWidth;
1802 
1803     if (priv->frameGeometry.height () != ce->height)
1804 	valueMask |= CWHeight;
1805 
1806     if (priv->frameGeometry.border () != ce->border_width)
1807 	valueMask |= CWBorderWidth;
1808 
1809     if (window->prev)
1810     {
1811 	if (ROOTPARENT (window->prev) != ce->above)
1812 	    valueMask |= CWSibling | CWStackMode;
1813     }
1814     else
1815     {
1816 	if (ce->above != 0)
1817 	    valueMask |= CWSibling | CWStackMode;
1818     }
1819 
1820     if (!pendingConfigures.match ((XEvent *) ce))
1821     {
1822 	compLogMessage ("core", CompLogLevelWarn, "unhandled ConfigureNotify on 0x%x!", serverFrame);
1823 	compLogMessage ("core", CompLogLevelWarn, "this should never happen. you should "\
1824 						  "probably file a bug about this.");
1825 #ifdef DEBUG
1826 	abort ();
1827 #else
1828 	pendingConfigures.clear ();
1829 #endif
1830     }
1831 
1832     /* subtract the input extents last sent to the
1833      * server to calculate the client size and then
1834      * re-sync the input extents and extents last
1835      * sent to server on resize () */
1836 
1837     x      = ce->x + priv->serverInput.left;
1838     y      = ce->y + priv->serverInput.top;
1839     width  = ce->width - priv->serverGeometry.border () * 2 - priv->serverInput.left - priv->serverInput.right;
1840 
1841     /* Don't use the server side frame geometry
1842      * to determine the geometry of shaded
1843      * windows since we didn't resize them
1844      * on configureXWindow */
1845     if (priv->shaded)
1846 	height = priv->serverGeometry.heightIncBorders () - priv->serverInput.top - priv->serverInput.bottom;
1847     else
1848 	height = ce->height + priv->serverGeometry.border () * 2 - priv->serverInput.top - priv->serverInput.bottom;
1849 
1850     /* set the frame geometry */
1851     priv->frameGeometry.set (ce->x, ce->y, ce->width, ce->height, ce->border_width);
1852 
1853 
1854     if (priv->syncWait)
1855 	priv->syncGeometry.set (x, y, width, height, ce->border_width);
1856     else
1857 	resize (x, y, width, height, ce->border_width);
1858 
1859     if (priv->restack (ce->above))
1860 	priv->updatePassiveButtonGrabs ();
1861 
1862     above = screen->findWindow (ce->above);
1863 
1864     if (above)
1865 	above->priv->updatePassiveButtonGrabs ();
1866 }
1867 
1868 void
1869 PrivateWindow::circulate (XCirculateEvent *ce)
1870 {
1871     Window newAboveId;
1872 
1873     if (ce->place == PlaceOnTop)
1874     {
1875 	CompWindow *newAbove = screen->getTopWindow ();
1876 	newAboveId = newAbove ? newAbove->id () : None;
1877     }
1878     else
1879 	newAboveId = 0;
1880 
1881     priv->restack (newAboveId);
1882 }
1883 
1884 void
1885 CompWindow::move (int  dx,
1886 		  int  dy,
1887 		  bool immediate)
1888 {
1889     if (dx || dy)
1890     {
1891 	XWindowChanges xwc = XWINDOWCHANGES_INIT;
1892 	unsigned int   valueMask = CWX | CWY;
1893 
1894 	xwc.x = priv->serverGeometry.x () + dx;
1895 	xwc.y = priv->serverGeometry.y () + dy;
1896 
1897 	priv->nextMoveImmediate = immediate;
1898 
1899 	configureXWindow (valueMask, &xwc);
1900     }
1901 }
1902 
1903 void
1904 PrivateWindow::move (int dx,
1905 		     int dy,
1906 		     bool immediate)
1907 {
1908     if (dx || dy)
1909     {
1910 	priv->geometry.setX (priv->geometry.x () + dx);
1911 	priv->geometry.setY (priv->geometry.y () + dy);
1912 	priv->frameGeometry.setX (priv->frameGeometry.x () + dx);
1913 	priv->frameGeometry.setY (priv->frameGeometry.y () + dy);
1914 
1915 	if (priv->attrib.override_redirect)
1916 	{
1917 	    priv->serverGeometry = priv->geometry;
1918 	    priv->serverFrameGeometry = priv->frameGeometry;
1919 	    priv->region.translate (dx, dy);
1920 	    priv->inputRegion.translate (dx, dy);
1921 	    if (!priv->frameRegion.isEmpty ())
1922 		priv->frameRegion.translate (dx, dy);
1923 
1924 	    priv->invisible = priv->isInvisible ();
1925 
1926 	    window->moveNotify (dx, dy, true);
1927 	}
1928     }
1929 }
1930 
1931 bool
1932 compiz::X11::PendingEventQueue::pending ()
1933 {
1934     return !mEvents.empty ();
1935 }
1936 
1937 void
1938 compiz::X11::PendingEventQueue::add (PendingEvent::Ptr p)
1939 {
1940     compLogMessage ("core", CompLogLevelDebug, "pending request:");
1941     p->dump ();
1942 
1943     mEvents.push_back (p);
1944 }
1945 
1946 bool
1947 compiz::X11::PendingEventQueue::removeIfMatching (const PendingEvent::Ptr &p, XEvent *event)
1948 {
1949     if (p->match (event))
1950     {
1951 	compLogMessage ("core", CompLogLevelDebug, "received event:");
1952 	p->dump ();
1953 	return true;
1954     }
1955 
1956     return false;
1957 }
1958 
1959 void
1960 compiz::X11::PendingEvent::dump ()
1961 {
1962     compLogMessage ("core", CompLogLevelDebug, "- event serial: %i", mSerial);
1963     compLogMessage ("core", CompLogLevelDebug,  "- event window 0x%x", mWindow);
1964 }
1965 
1966 void
1967 compiz::X11::PendingConfigureEvent::dump ()
1968 {
1969     compiz::X11::PendingEvent::dump ();
1970 
1971     compLogMessage ("core", CompLogLevelDebug,  "- x: %i y: %i width: %i height: %i "\
1972 						 "border: %i, sibling: 0x%x",
1973 						 mXwc.x, mXwc.y, mXwc.width, mXwc.height, mXwc.border_width, mXwc.sibling);
1974 }
1975 
1976 bool
1977 compiz::X11::PendingEventQueue::match (XEvent *event)
1978 {
1979     unsigned int lastSize = mEvents.size ();
1980 
1981     mEvents.erase (std::remove_if (mEvents.begin (), mEvents.end (),
1982 				   boost::bind (&compiz::X11::PendingEventQueue::removeIfMatching, this, _1, event)), mEvents.end ());
1983 
1984     return lastSize != mEvents.size ();
1985 }
1986 
1987 bool
1988 compiz::X11::PendingEventQueue::forEachIf (boost::function<bool (compiz::X11::PendingEvent::Ptr)> f)
1989 {
1990     foreach (compiz::X11::PendingEvent::Ptr p, mEvents)
1991     {
1992 	if (f (p))
1993 	    return true;
1994     }
1995 
1996     return false;
1997 }
1998 
1999 void
2000 compiz::X11::PendingEventQueue::dump ()
2001 {
2002     foreach (compiz::X11::PendingEvent::Ptr p, mEvents)
2003 	p->dump ();
2004 }
2005 
2006 compiz::X11::PendingEventQueue::PendingEventQueue (Display *d)
2007 {
2008     /* mClearCheckTimeout.setTimes (0, 0)
2009      *
2010      * XXX: For whatever reason, calling setTimes (0, 0) here causes
2011      * the destructor of the timer object to be called twice later on
2012      * in execution and the stack gets smashed. This could be a
2013      * compiler bug, but requires further investigation */
2014 }
2015 
2016 compiz::X11::PendingEventQueue::~PendingEventQueue ()
2017 {
2018 }
2019 
2020 Window
2021 compiz::X11::PendingEvent::getEventWindow (XEvent *event)
2022 {
2023     return event->xany.window;
2024 }
2025 
2026 bool
2027 compiz::X11::PendingEvent::match (XEvent *event)
2028 {
2029     if (event->xany.serial != mSerial)
2030 	return false;
2031     if (getEventWindow (event)!= mWindow)
2032 	return false;
2033 
2034     return true;
2035 }
2036 
2037 compiz::X11::PendingEvent::PendingEvent (Display *d, Window w) :
2038     mSerial (XNextRequest (d)),
2039     mWindow (w)
2040 {
2041 }
2042 
2043 compiz::X11::PendingEvent::~PendingEvent ()
2044 {
2045 }
2046 
2047 Window
2048 compiz::X11::PendingConfigureEvent::getEventWindow (XEvent *event)
2049 {
2050     return event->xconfigure.window;
2051 }
2052 
2053 bool
2054 compiz::X11::PendingConfigureEvent::matchVM (unsigned int valueMask)
2055 {
2056     unsigned int result = mValueMask != 0 ? valueMask & mValueMask : 1;
2057 
2058     return result != 0;
2059 }
2060 
2061 bool
2062 compiz::X11::PendingConfigureEvent::matchRequest (XWindowChanges &xwc, unsigned int valueMask)
2063 {
2064     if (matchVM (valueMask))
2065     {
2066 	if (valueMask & CWX)
2067 	    if (xwc.x != mXwc.x)
2068 		return false;
2069 
2070 	if (valueMask & CWY)
2071 	    if (xwc.y != mXwc.y)
2072 		return false;
2073 
2074 	if (valueMask & CWWidth)
2075 	    if (xwc.width != mXwc.width)
2076 		return false;
2077 
2078 	if (valueMask & CWHeight)
2079 	    if (xwc.height != mXwc.height)
2080 		return false;
2081 
2082 	if (valueMask & CWBorderWidth)
2083 	    if (xwc.border_width != mXwc.border_width)
2084 		return false;
2085 
2086 	if (valueMask & (CWStackMode | CWSibling))
2087 	    if (xwc.sibling != mXwc.sibling)
2088 		return false;
2089 
2090 	return true;
2091     }
2092 
2093     return false;
2094 }
2095 
2096 bool
2097 compiz::X11::PendingConfigureEvent::match (XEvent *event)
2098 {
2099     XConfigureEvent *ce = (XConfigureEvent *) event;
2100     bool matched = true;
2101 
2102     if (!compiz::X11::PendingEvent::match (event))
2103 	return false;
2104 
2105     XWindowChanges xwc = XWINDOWCHANGES_INIT;
2106 
2107     xwc.x = ce->x;
2108     xwc.y = ce->y;
2109     xwc.width = ce->width;
2110     xwc.height = ce->height;
2111     xwc.border_width = ce->border_width;
2112     xwc.sibling = ce->above;
2113 
2114     matched = matchRequest (xwc, mValueMask);
2115 
2116     /* Remove events from the queue
2117      * even if they didn't match what
2118      * we expected them to be, but still
2119      * complain about it */
2120     if (!matched)
2121     {
2122 	compLogMessage ("core", CompLogLevelWarn, "no exact match for ConfigureNotify on 0x%x!", mWindow);
2123 	compLogMessage ("core", CompLogLevelWarn, "expected the following changes:");
2124 	if (mValueMask & CWX)
2125 	    compLogMessage ("core", CompLogLevelWarn, "x: %i", mXwc.x);
2126 	if (mValueMask & CWY)
2127 	    compLogMessage ("core", CompLogLevelWarn, "y: %i", mXwc.y);
2128 	if (mValueMask & CWWidth)
2129 	    compLogMessage ("core", CompLogLevelWarn, "width: %i", mXwc.width);
2130 	if (mValueMask & CWHeight)
2131 	    compLogMessage ("core", CompLogLevelWarn, "height: %i", mXwc.height);
2132 	if (mValueMask & CWBorderWidth)
2133 	    compLogMessage ("core", CompLogLevelWarn, "border: %i", mXwc.border_width);
2134 	if (mValueMask & (CWStackMode | CWSibling))
2135 	    compLogMessage ("core", CompLogLevelWarn, "sibling: 0x%x", mXwc.sibling);
2136 
2137 	compLogMessage ("core", CompLogLevelWarn, "instead got:");
2138 	compLogMessage ("core", CompLogLevelWarn, "x: %i", ce->x);
2139 	compLogMessage ("core", CompLogLevelWarn, "y: %i", ce->y);
2140 	compLogMessage ("core", CompLogLevelWarn, "width: %i", ce->width);
2141 	compLogMessage ("core", CompLogLevelWarn, "height: %i", ce->height);
2142 	compLogMessage ("core", CompLogLevelWarn, "above: %i", ce->above);
2143 	compLogMessage ("core", CompLogLevelWarn, "this should never happen. you should "\
2144 						  "probably file a bug about this.");
2145     }
2146 
2147     return true;
2148 }
2149 
2150 compiz::X11::PendingConfigureEvent::PendingConfigureEvent (Display *d,
2151 							   Window   w,
2152 							   unsigned int valueMask,
2153 							   XWindowChanges *xwc) :
2154     compiz::X11::PendingEvent::PendingEvent (d, w),
2155     mValueMask (valueMask),
2156     mXwc (*xwc)
2157 {
2158 }
2159 
2160 compiz::X11::PendingConfigureEvent::~PendingConfigureEvent ()
2161 {
2162 }
2163 
2164 void
2165 CompWindow::syncPosition ()
2166 {
2167 }
2168 
2169 bool
2170 CompWindow::focus ()
2171 {
2172     WRAPABLE_HND_FUNCTN_RETURN (bool, focus)
2173 
2174     if (overrideRedirect ())
2175 	return false;
2176 
2177     if (!priv->managed || priv->unmanaging)
2178 	return false;
2179 
2180     if (!onCurrentDesktop ())
2181 	return false;
2182 
2183     if (priv->destroyed)
2184 	return false;
2185 
2186     if (!priv->shaded && (priv->state & CompWindowStateHiddenMask))
2187 	return false;
2188 
2189     if (priv->serverGeometry.x () + priv->serverGeometry.width ()  <= 0	||
2190 	priv->serverGeometry.y () + priv->serverGeometry.height () <= 0	||
2191 	priv->serverGeometry.x () >= (int) screen->width ()||
2192 	priv->serverGeometry.y () >= (int) screen->height ())
2193 	return false;
2194 
2195     return true;
2196 }
2197 
2198 bool
2199 CompWindow::place (CompPoint &pos)
2200 {
2201     WRAPABLE_HND_FUNCTN_RETURN (bool, place, pos)
2202     return false;
2203 }
2204 
2205 void
2206 CompWindow::validateResizeRequest (unsigned int   &mask,
2207 				   XWindowChanges *xwc,
2208 				   unsigned int   source)
2209 {
2210     WRAPABLE_HND_FUNCTN (validateResizeRequest, mask, xwc, source)
2211 
2212     if (!(priv->type & (CompWindowTypeDockMask    |
2213 		     CompWindowTypeFullscreenMask |
2214 		     CompWindowTypeUnknownMask)))
2215     {
2216 	if (mask & CWY)
2217 	{
2218 	    int min, max;
2219 
2220 	    min = screen->workArea ().y () + priv->input.top;
2221 	    max = screen->workArea ().bottom ();
2222 
2223 	    if (priv->state & CompWindowStateStickyMask &&
2224 	    	 (xwc->y < min || xwc->y > max))
2225 	    {
2226 		xwc->y = priv->serverGeometry.y ();
2227 	    }
2228 	    else
2229 	    {
2230 		min -= screen->vp ().y () * screen->height ();
2231 		max += (screen->vpSize ().height () - screen->vp ().y () - 1) *
2232 			screen->height ();
2233 
2234 		if (xwc->y < min)
2235 		    xwc->y = min;
2236 		else if (xwc->y > max)
2237 		    xwc->y = max;
2238 	    }
2239 	}
2240 
2241 	if (mask & CWX)
2242 	{
2243 	    int min, max;
2244 
2245 	    min = screen->workArea ().x () + priv->input.left;
2246 	    max = screen->workArea ().right ();
2247 
2248 	    if (priv->state & CompWindowStateStickyMask &&
2249 		(xwc->x < min || xwc->x > max))
2250 	    {
2251 		xwc->x = priv->serverGeometry.x ();
2252 	    }
2253 	    else
2254 	    {
2255 		min -= screen->vp ().x () * screen->width ();
2256 		max += (screen->vpSize ().width () - screen->vp ().x () - 1) *
2257 			screen->width ();
2258 
2259 		if (xwc->x < min)
2260 		    xwc->x = min;
2261 		else if (xwc->x > max)
2262 		    xwc->x = max;
2263 	    }
2264 	}
2265     }
2266 }
2267 
2268 void
2269 CompWindow::resizeNotify (int dx,
2270 			  int dy,
2271 			  int dwidth,
2272 			  int dheight)
2273     WRAPABLE_HND_FUNCTN (resizeNotify, dx, dy, dwidth, dheight)
2274 
2275 void
2276 CompWindow::moveNotify (int  dx,
2277 			int  dy,
2278 			bool immediate)
2279     WRAPABLE_HND_FUNCTN (moveNotify, dx, dy, immediate)
2280 
2281 void
2282 CompWindow::windowNotify (CompWindowNotify n)
2283     WRAPABLE_HND_FUNCTN (windowNotify, n)
2284 
2285 void
2286 CompWindow::grabNotify (int	     x,
2287 			int	     y,
2288 			unsigned int state,
2289 			unsigned int mask)
2290 {
2291     WRAPABLE_HND_FUNCTN (grabNotify, x, y, state, mask)
2292     priv->grabbed = true;
2293 }
2294 
2295 void
2296 CompWindow::ungrabNotify ()
2297 {
2298     WRAPABLE_HND_FUNCTN (ungrabNotify)
2299     priv->grabbed = false;
2300 }
2301 
2302 void
2303 CompWindow::stateChangeNotify (unsigned int lastState)
2304 {
2305     WRAPABLE_HND_FUNCTN (stateChangeNotify, lastState);
2306 
2307     /* if being made sticky */
2308     if (!(lastState & CompWindowStateStickyMask) &&
2309 	(priv->state & CompWindowStateStickyMask))
2310     {
2311 	CompPoint vp;   /* index of the window's vp */
2312 
2313 	/* Find which viewport the window falls in,
2314 	   and check if it's the current viewport */
2315 	vp = defaultViewport ();
2316 	if (screen->vp () != vp)
2317 	{
2318 	    unsigned int valueMask = CWX | CWY;
2319 	    XWindowChanges xwc = XWINDOWCHANGES_INIT;
2320 
2321 	    xwc.x = serverGeometry ().x () +  (screen->vp ().x () - vp.x ()) * screen->width ();
2322 	    xwc.y = serverGeometry ().y () +  (screen->vp ().y () - vp.y ()) * screen->height ();
2323 
2324 	    configureXWindow (valueMask, &xwc);
2325 	}
2326     }
2327 }
2328 
2329 
2330 bool
2331 PrivateWindow::isGroupTransient (Window clientLeader)
2332 {
2333     if (!clientLeader)
2334 	return false;
2335 
2336     if (transientFor == None || transientFor == screen->root ())
2337     {
2338 	if (type & (CompWindowTypeUtilMask    |
2339 		    CompWindowTypeToolbarMask |
2340 		    CompWindowTypeMenuMask    |
2341 		    CompWindowTypeDialogMask  |
2342 		    CompWindowTypeModalDialogMask))
2343 	{
2344 	    if (this->clientLeader == clientLeader)
2345 		return true;
2346 	}
2347     }
2348 
2349     return false;
2350 }
2351 
2352 CompWindow *
2353 PrivateWindow::getModalTransient ()
2354 {
2355     CompWindow *w, *modalTransient;
2356 
2357     modalTransient = window;
2358 
2359     for (w = screen->windows ().back (); w; w = w->prev)
2360     {
2361 	if (w == modalTransient || w->priv->mapNum == 0)
2362 	    continue;
2363 
2364 	if (w->priv->transientFor == modalTransient->priv->id)
2365 	{
2366 	    if (w->priv->state & CompWindowStateModalMask)
2367 	    {
2368 		modalTransient = w;
2369 		w = screen->windows ().back ();
2370 	    }
2371 	}
2372     }
2373 
2374     if (modalTransient == window)
2375     {
2376 	/* don't look for group transients with modal state if current window
2377 	   has modal state */
2378 	if (state & CompWindowStateModalMask)
2379 	    return NULL;
2380 
2381 	for (w = screen->windows ().back (); w; w = w->prev)
2382 	{
2383 	    if (w == modalTransient || w->priv->mapNum == 0)
2384 		continue;
2385 
2386 	    if (isAncestorTo (modalTransient, w))
2387 		continue;
2388 
2389 	    if (w->priv->isGroupTransient (modalTransient->priv->clientLeader))
2390 	    {
2391 		if (w->priv->state & CompWindowStateModalMask)
2392 		{
2393 		    modalTransient = w;
2394 		    w = w->priv->getModalTransient ();
2395 		    if (w)
2396 			modalTransient = w;
2397 
2398 		    break;
2399 		}
2400 	    }
2401 	}
2402     }
2403 
2404     if (modalTransient == window)
2405 	modalTransient = NULL;
2406 
2407     return modalTransient;
2408 }
2409 
2410 void
2411 CompWindow::moveInputFocusTo ()
2412 {
2413     CompScreen  *s = screen;
2414     CompWindow  *modalTransient;
2415 
2416     modalTransient = priv->getModalTransient ();
2417     if (modalTransient)
2418 	return modalTransient->moveInputFocusTo ();
2419 
2420     /* If the window is still hidden but not shaded
2421      * it probably meant that a plugin overloaded
2422      * CompWindow::focus to allow the focus to go
2423      * to this window, so only move the input focus
2424      * to the frame if the window is shaded */
2425     if (shaded ())
2426     {
2427 	XSetInputFocus (s->dpy (), priv->serverFrame,
2428 			RevertToPointerRoot, CurrentTime);
2429 	XChangeProperty (s->dpy (), s->root (), Atoms::winActive,
2430 			 XA_WINDOW, 32, PropModeReplace,
2431 			 (unsigned char *) &priv->id, 1);
2432 
2433 	screen->setNextActiveWindow(priv->serverFrame);
2434     }
2435     else
2436     {
2437 	bool setFocus = false;
2438 
2439 	if (priv->inputHint)
2440 	{
2441 	    XSetInputFocus (s->dpy (), priv->id, RevertToPointerRoot,
2442 			    CurrentTime);
2443 	    setFocus = true;
2444 	}
2445 
2446 	if (priv->protocols & CompWindowProtocolTakeFocusMask)
2447 	{
2448 	    XEvent ev;
2449 
2450 	    ev.type		    = ClientMessage;
2451 	    ev.xclient.window	    = priv->id;
2452 	    ev.xclient.message_type = Atoms::wmProtocols;
2453 	    ev.xclient.format	    = 32;
2454 	    ev.xclient.data.l[0]    = Atoms::wmTakeFocus;
2455 	    ev.xclient.data.l[1]    = s->getCurrentTime ();
2456 	    ev.xclient.data.l[2]    = 0;
2457 	    ev.xclient.data.l[3]    = 0;
2458 	    ev.xclient.data.l[4]    = 0;
2459 
2460 	    XSendEvent (s->dpy (), priv->id, false, NoEventMask, &ev);
2461 
2462 	    setFocus = true;
2463 	}
2464 
2465 	if (setFocus)
2466 	    screen->setNextActiveWindow(priv->id);
2467 
2468 	if (!setFocus && !modalTransient)
2469 	{
2470 	    CompWindow *ancestor;
2471 
2472 	    /* move input to closest ancestor */
2473 	    for (ancestor = s->windows ().front (); ancestor;
2474 		 ancestor = ancestor->next)
2475 	    {
2476 		if (PrivateWindow::isAncestorTo (this, ancestor))
2477 		{
2478 		    ancestor->moveInputFocusTo ();
2479 		    break;
2480 		}
2481 	    }
2482 	}
2483     }
2484 }
2485 
2486 void
2487 CompWindow::moveInputFocusToOtherWindow ()
2488 {
2489     if (priv->id == screen->activeWindow () ||
2490 	priv->id == screen->getNextActiveWindow())
2491     {
2492 	CompWindow *nextActive = screen->findWindow (screen->getNextActiveWindow());
2493 
2494         /* Window pending focus */
2495 	if (priv->id != screen->getNextActiveWindow() &&
2496 	    nextActive &&
2497 	    nextActive->focus ())
2498 	{
2499 	    nextActive->moveInputFocusTo ();
2500 	}
2501 	else if (priv->transientFor && priv->transientFor != screen->root ())
2502 	{
2503 	    CompWindow *ancestor;
2504 	    ancestor = screen->findWindow (priv->transientFor);
2505 	    if (ancestor &&
2506 		ancestor->focus () &&
2507 		!(ancestor->priv->type & (CompWindowTypeDesktopMask |
2508 					  CompWindowTypeDockMask)))
2509 	    {
2510 		ancestor->moveInputFocusTo ();
2511 	    }
2512 	    else
2513 		screen->focusDefaultWindow ();
2514 	}
2515 	else if (priv->type & (CompWindowTypeDialogMask |
2516 			       CompWindowTypeModalDialogMask))
2517 	{
2518 	    CompWindow *a, *focus = NULL;
2519 
2520 	    for (a = screen->windows ().back (); a; a = a->prev)
2521 	    {
2522 		if (a->priv->clientLeader == priv->clientLeader)
2523 		{
2524 		    if (a->focus ())
2525 		    {
2526 			if (focus)
2527 			{
2528 			    if (a->priv->type & (CompWindowTypeNormalMask |
2529 						 CompWindowTypeDialogMask |
2530 						 CompWindowTypeModalDialogMask))
2531 			    {
2532 				if (priv->compareWindowActiveness (focus, a) < 0)
2533 				    focus = a;
2534 			    }
2535 			}
2536 			else
2537 			    focus = a;
2538 		    }
2539 		}
2540 	    }
2541 
2542 	    if (focus && !(focus->priv->type & (CompWindowTypeDesktopMask |
2543 						CompWindowTypeDockMask)))
2544 	    {
2545 		focus->moveInputFocusTo ();
2546 	    }
2547 	    else
2548 		screen->focusDefaultWindow ();
2549 	}
2550 	else
2551 	    screen->focusDefaultWindow ();
2552     }
2553 }
2554 
2555 
2556 bool
2557 PrivateWindow::stackLayerCheck (CompWindow *w,
2558 				Window	    clientLeader,
2559 				CompWindow *below)
2560 {
2561     if (isAncestorTo (w, below))
2562 	return true;
2563 
2564     if (isAncestorTo (below, w))
2565 	return false;
2566 
2567     if (clientLeader && below->priv->clientLeader == clientLeader)
2568 	if (below->priv->isGroupTransient (clientLeader))
2569 	    return false;
2570 
2571     if (w->priv->state & CompWindowStateAboveMask)
2572     {
2573 	return true;
2574     }
2575     else if (w->priv->state & CompWindowStateBelowMask)
2576     {
2577 	if (below->priv->state & CompWindowStateBelowMask)
2578 	    return true;
2579     }
2580     else if (!(below->priv->state & CompWindowStateAboveMask))
2581     {
2582 	return true;
2583     }
2584 
2585     return false;
2586 }
2587 
2588 bool
2589 PrivateWindow::avoidStackingRelativeTo (CompWindow *w)
2590 {
2591     if (w->overrideRedirect ())
2592 	return true;
2593 
2594     if (w->destroyed ())
2595 	return true;
2596 
2597     bool allowRelativeToUnmmaped = w->priv->receivedMapRequestAndAwaitingMap ||
2598 				   w->priv->shaded ||
2599 				   w->priv->pendingMaps;
2600 
2601     if (!allowRelativeToUnmmaped)
2602     {
2603 	if (!w->isViewable () || !w->isMapped ())
2604 	    return true;
2605     }
2606 
2607     return false;
2608 }
2609 
2610 /* goes through the stack, top-down until we find a window we should
2611    stack above, normal windows can be stacked above fullscreen windows
2612    (and fullscreen windows over others in their layer) if aboveFs is true. */
2613 CompWindow *
2614 PrivateWindow::findSiblingBelow (CompWindow *w,
2615 				 bool       aboveFs)
2616 {
2617     CompWindow   *below;
2618     CompWindow   *t = screen->findWindow (w->transientFor ());
2619     Window	 clientLeader = w->priv->clientLeader;
2620     unsigned int type = w->priv->type;
2621     unsigned int belowMask;
2622 
2623     if (aboveFs)
2624 	belowMask = CompWindowTypeDockMask;
2625     else
2626 	belowMask = CompWindowTypeDockMask | CompWindowTypeFullscreenMask;
2627 
2628     /* normal stacking of fullscreen windows with below state */
2629     if ((type & CompWindowTypeFullscreenMask) &&
2630 	(w->priv->state & CompWindowStateBelowMask))
2631 	type = CompWindowTypeNormalMask;
2632 
2633     while (t && type != CompWindowTypeDockMask)
2634     {
2635 	/* dock stacking of transients for docks */
2636 	if (t->type () & CompWindowTypeDockMask)
2637 	    type = CompWindowTypeDockMask;
2638 
2639 	t = screen->findWindow (t->transientFor ());
2640     }
2641 
2642     if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2643 	clientLeader = None;
2644 
2645     for (below = screen->serverWindows ().back (); below;
2646 	 below = below->serverPrev)
2647     {
2648 	if (below == w || avoidStackingRelativeTo (below))
2649 	    continue;
2650 
2651 	/* always above desktop windows */
2652 	if (below->priv->type & CompWindowTypeDesktopMask)
2653 	    return below;
2654 
2655 	switch (type) {
2656 	case CompWindowTypeDesktopMask:
2657 	    /* desktop window layer */
2658 	    break;
2659 	case CompWindowTypeFullscreenMask:
2660 	    if (aboveFs)
2661 		return below;
2662 	    /* otherwise fall-through */
2663 	case CompWindowTypeDockMask:
2664 	    /* fullscreen and dock layer */
2665 	    if (below->priv->type & (CompWindowTypeFullscreenMask |
2666 			       CompWindowTypeDockMask))
2667 	    {
2668 		if (stackLayerCheck (w, clientLeader, below))
2669 		    return below;
2670 	    }
2671 	    else
2672 	    {
2673 		return below;
2674 	    }
2675 	    break;
2676 	default:
2677 	{
2678 	    bool allowedRelativeToLayer = !(below->priv->type & belowMask);
2679 
2680 	    if (aboveFs && below->priv->type & CompWindowTypeFullscreenMask)
2681 		if (!below->focus ())
2682 		    break;
2683 
2684 	    t = screen->findWindow (below->transientFor ());
2685 
2686 	    while (t && allowedRelativeToLayer)
2687 	    {
2688 		/* dock stacking of transients for docks */
2689 		allowedRelativeToLayer = !(t->priv->type & belowMask);
2690 
2691 		t = screen->findWindow (t->transientFor ());
2692 	    }
2693 
2694 	    /* fullscreen and normal layer */
2695 	    if (allowedRelativeToLayer)
2696 	    {
2697 		if (stackLayerCheck (w, clientLeader, below))
2698 		    return below;
2699 	    }
2700 	    break;
2701 	}
2702 	}
2703     }
2704 
2705     return NULL;
2706 }
2707 
2708 /* goes through the stack, top-down and returns the lowest window we
2709    can stack above. */
2710 CompWindow *
2711 PrivateWindow::findLowestSiblingBelow (CompWindow *w)
2712 {
2713     CompWindow   *below, *lowest = screen->serverWindows ().back ();
2714     CompWindow   *t = screen->findWindow (w->transientFor ());
2715     Window	 clientLeader = w->priv->clientLeader;
2716     unsigned int type = w->priv->type;
2717 
2718     /* normal stacking fullscreen windows with below state */
2719     if ((type & CompWindowTypeFullscreenMask) &&
2720 	(w->priv->state & CompWindowStateBelowMask))
2721 	type = CompWindowTypeNormalMask;
2722 
2723     while (t && type != CompWindowTypeDockMask)
2724     {
2725 	/* dock stacking of transients for docks */
2726 	if (t->type () & CompWindowTypeDockMask)
2727 	    type = CompWindowTypeDockMask;
2728 
2729 	t = screen->findWindow (t->transientFor ());
2730     }
2731 
2732 
2733     if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2734 	clientLeader = None;
2735 
2736     for (below = screen->serverWindows ().back (); below;
2737 	 below = below->serverPrev)
2738     {
2739 	if (below == w || avoidStackingRelativeTo (below))
2740 	    continue;
2741 
2742 	/* always above desktop windows */
2743 	if (below->priv->type & CompWindowTypeDesktopMask)
2744 	    return below;
2745 
2746 	switch (type) {
2747 	case CompWindowTypeDesktopMask:
2748 	    /* desktop window layer - desktop windows always should be
2749 	       stacked at the bottom; no other window should be below them */
2750 	    return NULL;
2751 	    break;
2752 	case CompWindowTypeFullscreenMask:
2753 	case CompWindowTypeDockMask:
2754 	    /* fullscreen and dock layer */
2755 	    if (below->priv->type & (CompWindowTypeFullscreenMask |
2756 			       CompWindowTypeDockMask))
2757 	    {
2758 		if (!stackLayerCheck (below, clientLeader, w))
2759 		    return lowest;
2760 	    }
2761 	    else
2762 	    {
2763 		return lowest;
2764 	    }
2765 	    break;
2766 	default:
2767 	{
2768 	    bool allowedRelativeToLayer = !(below->priv->type & CompWindowTypeDockMask);
2769 
2770 	    t = screen->findWindow (below->transientFor ());
2771 
2772 	    while (t && allowedRelativeToLayer)
2773 	    {
2774 		/* dock stacking of transients for docks */
2775 		allowedRelativeToLayer = !(t->priv->type & CompWindowTypeDockMask);
2776 
2777 		t = screen->findWindow (t->transientFor ());
2778 	    }
2779 
2780 	    /* fullscreen and normal layer */
2781 	    if (allowedRelativeToLayer)
2782 	    {
2783 		if (!stackLayerCheck (below, clientLeader, w))
2784 		    return lowest;
2785 	    }
2786 	    break;
2787 	}
2788 	}
2789 
2790 	lowest = below;
2791     }
2792 
2793     return lowest;
2794 }
2795 
2796 bool
2797 PrivateWindow::validSiblingBelow (CompWindow *w,
2798 				  CompWindow *sibling)
2799 {
2800     CompWindow   *t = screen->findWindow (w->transientFor ());
2801     Window	 clientLeader = w->priv->clientLeader;
2802     unsigned int type = w->priv->type;
2803 
2804     /* normal stacking fullscreen windows with below state */
2805     if ((type & CompWindowTypeFullscreenMask) &&
2806 	(w->priv->state & CompWindowStateBelowMask))
2807 	type = CompWindowTypeNormalMask;
2808 
2809     while (t && type != CompWindowTypeDockMask)
2810     {
2811 	/* dock stacking of transients for docks */
2812 	if (t->type () & CompWindowTypeDockMask)
2813 	    type = CompWindowTypeDockMask;
2814 
2815 	t = screen->findWindow (t->transientFor ());
2816     }
2817 
2818 
2819     if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
2820 	clientLeader = None;
2821 
2822     if (sibling == w || avoidStackingRelativeTo (sibling))
2823 	return false;
2824 
2825     /* always above desktop windows */
2826     if (sibling->priv->type & CompWindowTypeDesktopMask)
2827 	return true;
2828 
2829     switch (type) {
2830     case CompWindowTypeDesktopMask:
2831 	/* desktop window layer */
2832 	break;
2833     case CompWindowTypeFullscreenMask:
2834     case CompWindowTypeDockMask:
2835 	/* fullscreen and dock layer */
2836 	if (sibling->priv->type & (CompWindowTypeFullscreenMask |
2837 			     CompWindowTypeDockMask))
2838 	{
2839 	    if (stackLayerCheck (w, clientLeader, sibling))
2840 		return true;
2841 	}
2842 	else
2843 	{
2844 	    return true;
2845 	}
2846 	break;
2847     default:
2848     {
2849 	bool allowedRelativeToLayer = !(sibling->priv->type & CompWindowTypeDockMask);
2850 
2851 	t = screen->findWindow (sibling->transientFor ());
2852 
2853 	while (t && allowedRelativeToLayer)
2854 	{
2855 	    /* dock stacking of transients for docks */
2856 	    allowedRelativeToLayer = !(t->priv->type & CompWindowTypeDockMask);
2857 
2858 	    t = screen->findWindow (t->transientFor ());
2859 	}
2860 
2861 	/* fullscreen and normal layer */
2862 	if (allowedRelativeToLayer)
2863 	{
2864 	    if (stackLayerCheck (w, clientLeader, sibling))
2865 		return true;
2866 	}
2867 	break;
2868     }
2869     }
2870 
2871     return false;
2872 }
2873 
2874 void
2875 PrivateWindow::saveGeometry (int mask)
2876 {
2877     /* only save geometry if window has been placed */
2878     if (!placed)
2879 	return;
2880 
2881     int m = mask & ~saveMask;
2882 
2883     if (m & CWX)
2884 	saveWc.x = serverGeometry.x ();
2885 
2886     if (m & CWY)
2887 	saveWc.y = serverGeometry.y ();
2888 
2889     if (m & CWWidth)
2890 	saveWc.width = serverGeometry.width ();
2891 
2892     if (m & CWHeight)
2893 	saveWc.height = serverGeometry.height ();
2894 
2895     if (m & CWBorderWidth)
2896 	saveWc.border_width = serverGeometry.border ();
2897 
2898     saveMask |= m;
2899 }
2900 
2901 int
2902 PrivateWindow::restoreGeometry (XWindowChanges *xwc,
2903 				int            mask)
2904 {
2905     int m = mask & saveMask;
2906 
2907     if (m & CWX)
2908 	xwc->x = saveWc.x;
2909 
2910     if (m & CWY)
2911 	xwc->y = saveWc.y;
2912 
2913     if (m & CWWidth)
2914     {
2915 	xwc->width = saveWc.width;
2916 
2917 	/* This is not perfect but it works OK for now. If the saved width is
2918 	   the same as the current width then make it a little be smaller so
2919 	   the user can see that it changed and it also makes sure that
2920 	   windowResizeNotify is called and plugins are notified. */
2921 	if (xwc->width == (int) serverGeometry.width ())
2922 	{
2923 	    xwc->width -= 10;
2924 	    if (m & CWX)
2925 		xwc->x += 5;
2926 	}
2927     }
2928 
2929     if (m & CWHeight)
2930     {
2931 	xwc->height = saveWc.height;
2932 
2933 	/* As above, if the saved height is the same as the current height
2934 	   then make it a little be smaller. */
2935 	if (xwc->height == (int) serverGeometry.height ())
2936 	{
2937 	    xwc->height -= 10;
2938 	    if (m & CWY)
2939 		xwc->y += 5;
2940 	}
2941     }
2942 
2943     if (m & CWBorderWidth)
2944 	xwc->border_width = saveWc.border_width;
2945 
2946     saveMask &= ~mask;
2947 
2948     return m;
2949 }
2950 
2951 static bool isPendingRestack (compiz::X11::PendingEvent::Ptr p)
2952 {
2953     compiz::X11::PendingConfigureEvent::Ptr pc = boost::shared_static_cast <compiz::X11::PendingConfigureEvent> (p);
2954 
2955     return pc->matchVM (CWStackMode | CWSibling);
2956 }
2957 
2958 static bool isExistingRequest (compiz::X11::PendingEvent::Ptr p, XWindowChanges &xwc, unsigned int valueMask)
2959 {
2960     compiz::X11::PendingConfigureEvent::Ptr pc = boost::shared_static_cast <compiz::X11::PendingConfigureEvent> (p);
2961 
2962     return pc->matchRequest (xwc, valueMask);
2963 }
2964 
2965 void
2966 PrivateWindow::reconfigureXWindow (unsigned int   valueMask,
2967 				   XWindowChanges *xwc)
2968 {
2969     if (id == screen->root ())
2970     {
2971 	compLogMessage ("core", CompLogLevelWarn, "attempted to reconfigure root window");
2972 	return;
2973     }
2974 
2975     unsigned int frameValueMask = 0;
2976 
2977     /* Remove redundant bits */
2978 
2979     xwc->x = valueMask & CWX ? xwc->x : serverGeometry.x ();
2980     xwc->y = valueMask & CWY ? xwc->y : serverGeometry.y ();
2981     xwc->width = valueMask & CWWidth ? xwc->width : serverGeometry.width ();
2982     xwc->height = valueMask & CWHeight ? xwc->height : serverGeometry.height ();
2983     xwc->border_width = valueMask & CWBorderWidth ? xwc->border_width : serverGeometry.border ();
2984 
2985     /* Don't allow anything that might generate a BadValue */
2986     if (valueMask & CWWidth && !xwc->width)
2987     {
2988 	compLogMessage ("core", CompLogLevelWarn, "Attempted to set < 1 width on a window");
2989 	xwc->width = 1;
2990     }
2991 
2992     if (valueMask & CWHeight && !xwc->height)
2993     {
2994 	compLogMessage ("core", CompLogLevelWarn, "Attempted to set < 1 height on a window");
2995 	xwc->height = 1;
2996     }
2997 
2998     int dx = valueMask & CWX ? xwc->x - serverGeometry.x () : 0;
2999     int dy = valueMask & CWY ? xwc->y - serverGeometry.y () : 0;
3000     int dwidth = valueMask & CWWidth ? xwc->width - serverGeometry.width () : 0;
3001     int dheight = valueMask & CWHeight ? xwc->height - serverGeometry.height () : 0;
3002 
3003     /* FIXME: This is a total fallacy for the reparenting case
3004      * at least since the client doesn't actually move here, it only
3005      * moves within the frame */
3006     if (valueMask & CWX && serverGeometry.x () == xwc->x)
3007 	valueMask &= ~(CWX);
3008 
3009     if (valueMask & CWY && serverGeometry.y () == xwc->y)
3010 	valueMask &= ~(CWY);
3011 
3012     if (valueMask & CWWidth && serverGeometry.width () == xwc->width)
3013 	valueMask &= ~(CWWidth);
3014 
3015     if (valueMask & CWHeight && serverGeometry.height () == xwc->height)
3016 	valueMask &= ~(CWHeight);
3017 
3018     if (valueMask & CWBorderWidth && serverGeometry.border () == xwc->border_width)
3019 	valueMask &= ~(CWBorderWidth);
3020 
3021     if (valueMask & CWSibling && window->serverPrev)
3022     {
3023 	/* check if the sibling is also pending a restack,
3024 	 * if not, then setting this bit is useless */
3025 	if (ROOTPARENT (window->serverPrev) == xwc->sibling)
3026 	{
3027 	    bool matchingRequest = priv->pendingConfigures.forEachIf (boost::bind (isExistingRequest, _1, *xwc, valueMask));
3028 	    bool restackPending = window->serverPrev->priv->pendingConfigures.forEachIf (boost::bind (isPendingRestack, _1));
3029 	    bool remove = matchingRequest;
3030 
3031 	    if (!remove)
3032 		remove = !restackPending;
3033 
3034 	    if (remove)
3035 		valueMask &= ~(CWSibling | CWStackMode);
3036 	}
3037     }
3038 
3039     if (valueMask & CWBorderWidth)
3040 	serverGeometry.setBorder (xwc->border_width);
3041 
3042     if (valueMask & CWX)
3043 	serverGeometry.setX (xwc->x);
3044 
3045     if (valueMask & CWY)
3046 	serverGeometry.setY (xwc->y);
3047 
3048     if (valueMask & CWWidth)
3049 	serverGeometry.setWidth (xwc->width);
3050 
3051     if (valueMask & CWHeight)
3052 	serverGeometry.setHeight (xwc->height);
3053 
3054     /* Update the server side window list on raise, lower and restack functions.
3055      * This function should only recieve stack_mode == Above
3056      * but warn incase something else does get through, to make the cause
3057      * of any potential misbehaviour obvious. */
3058     if (valueMask & (CWSibling | CWStackMode))
3059     {
3060 	if (xwc->stack_mode == Above)
3061 	{
3062 	    if (xwc->sibling)
3063 	    {
3064 		screen->unhookServerWindow (window);
3065 		screen->insertServerWindow (window, xwc->sibling);
3066 	    }
3067 	}
3068 	else
3069 	    compLogMessage ("core", CompLogLevelWarn, "restack_mode not Above");
3070     }
3071 
3072     frameValueMask = CWX | CWY | CWWidth | CWHeight | (valueMask & (CWStackMode | CWSibling));
3073 
3074     if (serverFrameGeometry.x () == xwc->x - serverGeometry.border () - serverInput.left)
3075 	frameValueMask &= ~(CWX);
3076 
3077     if (serverFrameGeometry.y () == xwc->y - serverGeometry.border () - serverInput.top)
3078 	frameValueMask &= ~(CWY);
3079 
3080    if (serverFrameGeometry.width () == xwc->width + serverGeometry.border () * 2
3081 				      + serverInput.left + serverInput.right)
3082 	frameValueMask &= ~(CWWidth);
3083 
3084     /* shaded windows are not allowed to have their frame window
3085      * height changed (but are allowed to have their client height
3086      * changed */
3087 
3088     if (shaded)
3089     {
3090 	if (serverFrameGeometry.height () == serverGeometry.border () * 2
3091 	    + serverInput.top + serverInput.bottom)
3092 	    frameValueMask &= ~(CWHeight);
3093     }
3094     else
3095     {
3096 	if (serverFrameGeometry.height () == xwc->height + serverGeometry.border () * 2
3097 	    + serverInput.top + serverInput.bottom)
3098 	    frameValueMask &= ~(CWHeight);
3099     }
3100 
3101 
3102     if (valueMask & CWStackMode &&
3103         ((xwc->stack_mode != TopIf) && (xwc->stack_mode != BottomIf) && (xwc->stack_mode != Opposite) &&
3104 	 (xwc->stack_mode != Above) && (xwc->stack_mode != Below)))
3105     {
3106 	compLogMessage ("core", CompLogLevelWarn, "Invalid stack mode %i", xwc->stack_mode);
3107 	valueMask &= ~(CWStackMode | CWSibling);
3108     }
3109 
3110     /* Don't allow anything that might cause a BadMatch error */
3111 
3112     if (valueMask & CWSibling && !(valueMask & CWStackMode))
3113     {
3114 	compLogMessage ("core", CompLogLevelWarn, "Didn't specify a CWStackMode for CWSibling");
3115 	valueMask &= ~CWSibling;
3116     }
3117 
3118     if (valueMask & CWSibling && xwc->sibling == (serverFrame ? serverFrame : id))
3119     {
3120 	compLogMessage ("core", CompLogLevelWarn, "Can't restack a window relative to itself");
3121 	valueMask &= ~CWSibling;
3122     }
3123 
3124     if (valueMask & CWBorderWidth && attrib.c_class == InputOnly)
3125     {
3126 	compLogMessage ("core", CompLogLevelWarn, "Cannot set border_width of an input_only window");
3127 	valueMask &= ~CWBorderWidth;
3128     }
3129 
3130     if (valueMask & CWSibling)
3131     {
3132 	CompWindow *sibling = screen->findTopLevelWindow (xwc->sibling);
3133 
3134 	if (!sibling)
3135 	{
3136 	    compLogMessage ("core", CompLogLevelWarn, "Attempted to restack relative to 0x%x which is "\
3137 			    "not a child of the root window or a window compiz owns", static_cast <unsigned int> (xwc->sibling));
3138 	    valueMask &= ~(CWSibling | CWStackMode);
3139 	}
3140 	else if (sibling->frame () && xwc->sibling != sibling->frame ())
3141 	{
3142 	    compLogMessage ("core", CompLogLevelWarn, "Attempted to restack relative to 0x%x which is "\
3143 			    "not a child of the root window", static_cast <unsigned int> (xwc->sibling));
3144 	    valueMask &= ~(CWSibling | CWStackMode);
3145 	}
3146     }
3147 
3148     /* Can't set the border width of frame windows */
3149     frameValueMask &= ~(CWBorderWidth);
3150 
3151     if (frameValueMask & CWX)
3152 	serverFrameGeometry.setX (xwc->x - serverGeometry.border () - serverInput.left);
3153 
3154     if (frameValueMask & CWY)
3155 	serverFrameGeometry.setY (xwc->y -serverGeometry.border () - serverInput.top);
3156 
3157     if (frameValueMask & CWWidth)
3158 	serverFrameGeometry.setWidth (xwc->width + serverGeometry.border () * 2
3159 				      + serverInput.left + serverInput.right);
3160 
3161     if (shaded)
3162     {
3163 	if (frameValueMask & CWHeight)
3164 	    serverFrameGeometry.setHeight (serverGeometry.border () * 2
3165 					   + serverInput.top + serverInput.bottom);
3166     }
3167     else
3168     {
3169 	if (frameValueMask & CWHeight)
3170 	    serverFrameGeometry.setHeight (xwc->height + serverGeometry.border () * 2
3171 					   + serverInput.top + serverInput.bottom);
3172     }
3173 
3174     if (serverFrame)
3175     {
3176 	if (frameValueMask)
3177 	{
3178 	    XWindowChanges wc = *xwc;
3179 
3180 	    wc.x      = serverFrameGeometry.x ();
3181 	    wc.y      = serverFrameGeometry.y ();
3182 	    wc.width  = serverFrameGeometry.width ();
3183 	    wc.height = serverFrameGeometry.height ();
3184 
3185 	    compiz::X11::PendingEvent::Ptr pc =
3186 		    boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
3187 									      new compiz::X11::PendingConfigureEvent (
3188 										  screen->dpy (), priv->serverFrame, frameValueMask, &wc)));
3189 
3190 	    pendingConfigures.add (pc);
3191 
3192 	    XConfigureWindow (screen->dpy (), serverFrame, frameValueMask, &wc);
3193 	}
3194 
3195 	valueMask &= ~(CWSibling | CWStackMode);
3196 
3197 	/* If the frame has changed position (eg, serverInput.top
3198 	 * or serverInput.left have changed) then we also need to
3199 	 * update the client and wrapper position */
3200 	if (!(valueMask & CWX))
3201 	    valueMask |= frameValueMask & CWX;
3202 	if (!(valueMask & CWY))
3203 	    valueMask |= frameValueMask & CWY;
3204 
3205 	if (valueMask)
3206 	{
3207 	    xwc->x = serverInput.left;
3208 	    xwc->y = serverInput.top;
3209 	    XConfigureWindow (screen->dpy (), wrapper, valueMask, xwc);
3210 
3211 	    xwc->x = 0;
3212 	    xwc->y = 0;
3213 	}
3214     }
3215 
3216     if (valueMask)
3217 	XConfigureWindow (screen->dpy (), id, valueMask, xwc);
3218 
3219     /* Send the synthetic configure notify
3220      * after the real configure notify arrives
3221      * (ICCCM s4.1.5) */
3222     if (serverFrame)
3223 	window->sendConfigureNotify ();
3224 
3225     /* When updating plugins we care about
3226      * the absolute position */
3227     if (dx)
3228 	valueMask |= CWX;
3229     if (dy)
3230 	valueMask |= CWY;
3231     if (dwidth)
3232 	valueMask |= CWWidth;
3233     if (dheight)
3234 	valueMask |= CWHeight;
3235 
3236     if (!attrib.override_redirect)
3237     {
3238 	if (valueMask & (CWWidth | CWHeight))
3239 	{
3240 	    updateRegion ();
3241 	    window->resizeNotify (dx, dy, dwidth, dheight);
3242 	}
3243 	else if (valueMask & (CWX | CWY))
3244 	{
3245 	    region.translate (dx, dy);
3246 	    inputRegion.translate (dx, dy);
3247 	    if (!frameRegion.isEmpty ())
3248 		frameRegion.translate (dx, dy);
3249 
3250 	    if (dx || dy)
3251 	    {
3252 		window->moveNotify (dx, dy, priv->nextMoveImmediate);
3253 		priv->nextMoveImmediate = true;
3254 	    }
3255 	}
3256     }
3257 }
3258 
3259 bool
3260 PrivateWindow::stackDocks (CompWindow     *w,
3261                            CompWindowList &updateList,
3262                            XWindowChanges *xwc,
3263                            unsigned int   *mask)
3264 {
3265     CompWindow *firstFullscreenWindow = NULL;
3266     CompWindow *belowDocks = NULL;
3267 
3268     foreach (CompWindow *dw, screen->serverWindows ())
3269     {
3270         /* fullscreen window found */
3271         if (firstFullscreenWindow)
3272         {
3273 	    /* If there is another toplevel window above the fullscreen one
3274 	     * then we need to stack above that */
3275 	    if ((dw->priv->managed && !dw->priv->unmanaging) &&
3276 		!(dw->priv->state & CompWindowStateHiddenMask) &&
3277                 !PrivateWindow::isAncestorTo (w, dw) &&
3278                 !(dw->type () & (CompWindowTypeFullscreenMask |
3279                                  CompWindowTypeDockMask)) &&
3280 		!dw->overrideRedirect () &&
3281 		dw->isViewable ())
3282             {
3283                 belowDocks = dw;
3284             }
3285         }
3286         else if (dw->type () & CompWindowTypeFullscreenMask)
3287         {
3288 	    /* First fullscreen window found when checking up the stack
3289 	     * now go back down to find a suitable candidate client
3290 	     * window to put the docks above */
3291             firstFullscreenWindow = dw;
3292 	    for (CompWindow *dww = dw->serverPrev; dww; dww = dww->serverPrev)
3293             {
3294 		if ((dw->priv->managed && !dw->priv->unmanaging) &&
3295 		    !(dw->priv->state & CompWindowStateHiddenMask) &&
3296 		    !(dww->type () & (CompWindowTypeFullscreenMask |
3297                                       CompWindowTypeDockMask)) &&
3298 		    !dww->overrideRedirect () &&
3299 		    dww->isViewable ())
3300                 {
3301                     belowDocks = dww;
3302                     break;
3303                 }
3304             }
3305         }
3306     }
3307 
3308     if (belowDocks)
3309     {
3310         *mask = CWSibling | CWStackMode;
3311         xwc->sibling = ROOTPARENT (belowDocks);
3312 
3313         /* Collect all dock windows first */
3314 	foreach (CompWindow *dw, screen->serverWindows ())
3315             if (dw->priv->type & CompWindowTypeDockMask)
3316                 updateList.push_front (dw);
3317 
3318         return true;
3319     }
3320 
3321     return false;
3322 }
3323 
3324 bool
3325 PrivateWindow::stackTransients (CompWindow	*w,
3326 				CompWindow	*avoid,
3327 				XWindowChanges *xwc,
3328 				CompWindowList &updateList)
3329 {
3330     CompWindow *t;
3331     Window     clientLeader = w->priv->clientLeader;
3332 
3333     if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
3334 	clientLeader = None;
3335 
3336     for (t = screen->serverWindows ().back (); t; t = t->serverPrev)
3337     {
3338 	if (t == w || t == avoid)
3339 	    continue;
3340 
3341 	if (t->priv->transientFor == w->priv->id ||
3342 	    t->priv->isGroupTransient (clientLeader))
3343 	{
3344 	    if (!stackTransients (t, avoid, xwc, updateList))
3345 		return false;
3346 
3347 	    if (xwc->sibling == t->priv->id ||
3348 		(t->priv->serverFrame && xwc->sibling == t->priv->serverFrame))
3349 		return false;
3350 
3351 	    if (t->priv->mapNum || t->priv->pendingMaps)
3352 		updateList.push_back (t);
3353 	}
3354     }
3355 
3356     return true;
3357 }
3358 
3359 void
3360 PrivateWindow::stackAncestors (CompWindow     *w,
3361 			       XWindowChanges *xwc,
3362 			       CompWindowList &updateList)
3363 {
3364     CompWindow *transient = NULL;
3365 
3366     if (w->priv->transientFor)
3367 	transient = screen->findWindow (w->priv->transientFor);
3368 
3369     if (transient                           &&
3370 	xwc->sibling != transient->priv->id &&
3371 	(!transient->priv->serverFrame || xwc->sibling != transient->priv->serverFrame))
3372     {
3373 	CompWindow *ancestor;
3374 
3375 	ancestor = screen->findWindow (w->priv->transientFor);
3376 	if (ancestor)
3377 	{
3378 	    if (!stackTransients (ancestor, w, xwc, updateList))
3379 		return;
3380 
3381 	    if (ancestor->priv->type & CompWindowTypeDesktopMask)
3382 		return;
3383 
3384 	    if (ancestor->priv->type & CompWindowTypeDockMask)
3385 		if (!(w->priv->type & CompWindowTypeDockMask))
3386 		    return;
3387 
3388 	    if (ancestor->priv->mapNum || ancestor->priv->pendingMaps)
3389 		updateList.push_back (ancestor);
3390 
3391 	    stackAncestors (ancestor, xwc, updateList);
3392 	}
3393     }
3394     else if (w->priv->isGroupTransient (w->priv->clientLeader))
3395     {
3396 	CompWindow *a;
3397 
3398 	for (a = screen->serverWindows ().back (); a; a = a->serverPrev)
3399 	{
3400 	    if (a->priv->clientLeader == w->priv->clientLeader &&
3401 		a->priv->transientFor == None		       &&
3402 		!a->priv->isGroupTransient (w->priv->clientLeader))
3403 	    {
3404 		if (xwc->sibling == a->priv->id ||
3405 		    (a->priv->serverFrame && xwc->sibling == a->priv->serverFrame))
3406 		    break;
3407 
3408 		if (!stackTransients (a, w, xwc, updateList))
3409 		    break;
3410 
3411 		if (a->priv->type & CompWindowTypeDesktopMask)
3412 		    continue;
3413 
3414 		if (a->priv->type & CompWindowTypeDockMask)
3415 		    if (!(w->priv->type & CompWindowTypeDockMask))
3416 			break;
3417 
3418 		if (a->priv->mapNum || a->priv->pendingMaps)
3419 		    updateList.push_back (a);
3420 	    }
3421 	}
3422     }
3423 }
3424 
3425 void
3426 CompWindow::configureXWindow (unsigned int valueMask,
3427 			      XWindowChanges *xwc)
3428 {
3429     if (priv->managed && (valueMask & (CWSibling | CWStackMode)))
3430     {
3431 	CompWindowList transients;
3432 	CompWindowList ancestors;
3433 	CompWindowList docks;
3434 
3435 	/* Since the window list is being reordered in reconfigureXWindow
3436 	   the list of windows which need to be restacked must be stored
3437 	   first. The windows are stacked in the opposite order than they
3438 	   were previously stacked, in order that they are above xwc->sibling
3439 	   so that when compiz gets the ConfigureNotify event it doesn't
3440 	   have to restack all the windows again. */
3441 
3442 	/* transient children above */
3443 	if (PrivateWindow::stackTransients (this, NULL, xwc, transients))
3444 	{
3445 	    /* ancestors, siblings and sibling transients below */
3446 	    PrivateWindow::stackAncestors (this, xwc, ancestors);
3447 
3448 	    for (CompWindowList::reverse_iterator w = ancestors.rbegin ();
3449 		 w != ancestors.rend (); w++)
3450 	    {
3451 		(*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
3452 		xwc->sibling = ROOTPARENT (*w);
3453 	    }
3454 
3455 	    this->priv->reconfigureXWindow (valueMask, xwc);
3456 	    xwc->sibling = ROOTPARENT (this);
3457 
3458 	    for (CompWindowList::reverse_iterator w = transients.rbegin ();
3459 		 w != transients.rend (); w++)
3460 	    {
3461 		(*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
3462 		xwc->sibling = ROOTPARENT (*w);
3463 	    }
3464 
3465 	    if (PrivateWindow::stackDocks (this, docks, xwc, &valueMask))
3466 	    {
3467 		Window sibling = xwc->sibling;
3468 		xwc->stack_mode = Above;
3469 
3470                 /* Then update the dock windows */
3471                 foreach (CompWindow *dw, docks)
3472                 {
3473                     xwc->sibling = sibling;
3474                     dw->priv->reconfigureXWindow (valueMask, xwc);
3475                 }
3476             }
3477 	}
3478     }
3479     else if (priv->id)
3480     {
3481 	priv->reconfigureXWindow (valueMask, xwc);
3482     }
3483 }
3484 
3485 int
3486 PrivateWindow::addWindowSizeChanges (XWindowChanges       *xwc,
3487 				     CompWindow::Geometry old)
3488 {
3489     CompRect  workArea;
3490     int	      mask = 0;
3491     int	      x, y;
3492     CompOutput *output;
3493     CompPoint viewport;
3494 
3495     screen->viewportForGeometry (old, viewport);
3496 
3497     x = (viewport.x () - screen->vp ().x ()) * screen->width ();
3498     y = (viewport.y () - screen->vp ().y ()) * screen->height ();
3499 
3500     /* Try to select and output device that the window is on first
3501      * and make sure if we are fullscreening or maximizing that the
3502      * window is actually able to fit on this output ... otherwise
3503      * we're going to have to use another output device which sucks
3504      * but at least the user will be able to see all of the window */
3505     output   = &screen->outputDevs ().at (screen->outputDeviceForGeometry (old));
3506 
3507     /*
3508      * output is now the correct output for the given geometry.
3509      * There used to be a lot more logic here to handle the rare special
3510      * case of maximizing a window whose hints say it is too large to fit
3511      * the output and choose a different one. However that logic was a bad
3512      * idea because:
3513      *   (1) It's confusing to the user to auto-magically move a window
3514      *       between monitors when they didn't ask for it. So don't.
3515      *   (2) In the worst case where the window can't go small enough to fit
3516      *       the output, they can simply move it with Alt+drag, Alt+F7 or
3517      *       expo.
3518      * Not moving the window at all is much less annoying than moving it when
3519      * the user never asked to.
3520      */
3521 
3522     workArea = output->workArea ();
3523 
3524     if (type & CompWindowTypeFullscreenMask)
3525     {
3526 	saveGeometry (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
3527 
3528 	if (fullscreenMonitorsSet)
3529 	{
3530 	    xwc->x      = x + fullscreenMonitorRect.x ();
3531 	    xwc->y      = y + fullscreenMonitorRect.y ();
3532 	    xwc->width  = fullscreenMonitorRect.width ();
3533 	    xwc->height = fullscreenMonitorRect.height ();
3534 	}
3535 	else
3536 	{
3537 	    xwc->x      = x + output->x ();
3538 	    xwc->y      = y + output->y ();
3539 	    xwc->width  = output->width ();
3540 	    xwc->height = output->height ();
3541 	}
3542 
3543 	xwc->border_width = 0;
3544 
3545 	mask |= CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
3546     }
3547     else
3548     {
3549 	mask |= restoreGeometry (xwc, CWBorderWidth);
3550 	if (state & CompWindowStateMaximizedVertMask)
3551 	{
3552 	    saveGeometry (CWY | CWHeight);
3553 
3554 	    xwc->height = workArea.height () - border.top -
3555 			  border.bottom - old.border () * 2;
3556 
3557 	    mask |= CWHeight;
3558 	}
3559 	else
3560 	{
3561 	    mask |= restoreGeometry (xwc, CWY | CWHeight);
3562 	}
3563 
3564 	if (state & CompWindowStateMaximizedHorzMask)
3565 	{
3566 	    saveGeometry (CWX | CWWidth);
3567 
3568 	    xwc->width = workArea.width () - border.left -
3569 			 border.right - old.border () * 2;
3570 
3571 	    mask |= CWWidth;
3572 	}
3573 	else
3574 	{
3575 	    mask |= restoreGeometry (xwc, CWX | CWWidth);
3576 	}
3577 
3578 	/* constrain window width if smaller than minimum width */
3579 	if (!(mask & CWWidth) && (int) old.width () < sizeHints.min_width)
3580 	{
3581 	    xwc->width = sizeHints.min_width;
3582 	    mask |= CWWidth;
3583 	}
3584 
3585 	/* constrain window width if greater than maximum width */
3586 	if (!(mask & CWWidth) && (int) old.width () > sizeHints.max_width)
3587 	{
3588 	    xwc->width = sizeHints.max_width;
3589 	    mask |= CWWidth;
3590 	}
3591 
3592 	/* constrain window height if smaller than minimum height */
3593 	if (!(mask & CWHeight) && (int) old.height () < sizeHints.min_height)
3594 	{
3595 	    xwc->height = sizeHints.min_height;
3596 	    mask |= CWHeight;
3597 	}
3598 
3599 	/* constrain window height if greater than maximum height */
3600 	if (!(mask & CWHeight) && (int) old.height () > sizeHints.max_height)
3601 	{
3602 	    xwc->height = sizeHints.max_height;
3603 	    mask |= CWHeight;
3604 	}
3605 
3606 	if (mask & (CWWidth | CWHeight))
3607 	{
3608 	    int width, height, max;
3609 
3610 	    width  = (mask & CWWidth)  ? xwc->width  : old.width ();
3611 	    height = (mask & CWHeight) ? xwc->height : old.height ();
3612 
3613 	    xwc->width  = old.width ();
3614 	    xwc->height = old.height ();
3615 
3616 	    window->constrainNewWindowSize (width, height, &width, &height);
3617 
3618 	    if (width != (int) old.width ())
3619 	    {
3620 		mask |= CWWidth;
3621 		xwc->width = width;
3622 	    }
3623 	    else
3624 		mask &= ~CWWidth;
3625 
3626 	    if (height != (int) old.height ())
3627 	    {
3628 		mask |= CWHeight;
3629 		xwc->height = height;
3630 	    }
3631 	    else
3632 		mask &= ~CWHeight;
3633 
3634 	    if (state & CompWindowStateMaximizedVertMask)
3635 	    {
3636 		/* If the window is still offscreen, then we need to constrain it
3637 		 * by the gravity value (so that the corner that the gravity specifies
3638 		 * is 'anchored' to that edge of the workarea) */
3639 
3640 		xwc->y = y + workArea.y () + border.top;
3641 		mask |= CWY;
3642 
3643 		switch (priv->sizeHints.win_gravity)
3644 		{
3645 		    case SouthWestGravity:
3646 		    case SouthEastGravity:
3647 		    case SouthGravity:
3648 			/* Shift the window so that the bottom meets the top of the bottom */
3649 			height = xwc->height + old.border () * 2;
3650 
3651 			max = y + workArea.bottom ();
3652 			if (xwc->y + xwc->height + border.bottom > max)
3653 			{
3654 			    xwc->y = max - height - border.bottom;
3655 			    mask |= CWY;
3656 			}
3657 			break;
3658 		    /* For EastGravity, WestGravity and CenterGravity we default to the top
3659 		     * of the window since the user should at least be able to close it
3660 		     * (but not for SouthGravity, SouthWestGravity and SouthEastGravity since
3661 		     * that indicates that the application has requested positioning in that area
3662 		     */
3663 		    case EastGravity:
3664 		    case WestGravity:
3665 		    case CenterGravity:
3666 		    case NorthWestGravity:
3667 		    case NorthEastGravity:
3668 		    case NorthGravity:
3669 		    default:
3670 			/* Shift the window so that the top meets the top of the screen */
3671 			break;
3672 		}
3673 	    }
3674 
3675 	    if (state & CompWindowStateMaximizedHorzMask)
3676 	    {
3677 		xwc->x = x + workArea.x () + border.left;
3678 		mask |= CWX;
3679 
3680 		switch (priv->sizeHints.win_gravity)
3681 		{
3682 		    case NorthEastGravity:
3683 		    case SouthEastGravity:
3684 		    case EastGravity:
3685 			width = xwc->width + old.border () * 2;
3686 
3687 			max = x + workArea.right ();
3688 
3689 			if (old.x () + (int) old.width () + border.right > max)
3690 			{
3691 			    xwc->x = max - width - border.right;
3692 			    mask |= CWX;
3693 			}
3694 			else if (old.x () + width + border.right > max)
3695 			{
3696 			    xwc->x = x + workArea.x () +
3697 				     (workArea.width () - border.left - width -
3698 				      border.right) / 2 + border.left;
3699 			    mask |= CWX;
3700 			}
3701 		    /* For NorthGravity, SouthGravity and CenterGravity we default to the top
3702 		     * of the window since the user should at least be able to close it
3703 		     * (but not for SouthGravity, SouthWestGravity and SouthEastGravity since
3704 		     * that indicates that the application has requested positioning in that area
3705 		     */
3706 		    case NorthGravity:
3707 		    case SouthGravity:
3708 		    case CenterGravity:
3709 		    case NorthWestGravity:
3710 		    case SouthWestGravity:
3711 		    case WestGravity:
3712 		    default:
3713 			break;
3714 		}
3715 	    }
3716 	}
3717     }
3718 
3719     if ((mask & CWX) && (xwc->x == old.x ()))
3720 	mask &= ~CWX;
3721 
3722     if ((mask & CWY) && (xwc->y == old.y ()))
3723 	mask &= ~CWY;
3724 
3725     if ((mask & CWWidth) && (xwc->width == (int) old.width ()))
3726 	mask &= ~CWWidth;
3727 
3728     if ((mask & CWHeight) && (xwc->height == (int) old.height ()))
3729 	mask &= ~CWHeight;
3730 
3731     return mask;
3732 }
3733 
3734 unsigned int
3735 PrivateWindow::adjustConfigureRequestForGravity (XWindowChanges *xwc,
3736 						 unsigned int   xwcm,
3737 						 int            gravity,
3738 						 int		direction)
3739 {
3740     int          newX, newY;
3741     unsigned int mask = 0;
3742 
3743     newX = xwc->x;
3744     newY = xwc->y;
3745 
3746     if (xwcm & (CWX | CWWidth))
3747     {
3748 	switch (gravity) {
3749 	case NorthWestGravity:
3750 	case WestGravity:
3751 	case SouthWestGravity:
3752 	    if (xwcm & CWX)
3753 		newX += priv->border.left * direction;
3754 	    break;
3755 
3756 	case NorthGravity:
3757 	case CenterGravity:
3758 	case SouthGravity:
3759 	    if (xwcm & CWX)
3760 		newX -= (xwc->width / 2 - priv->border.left +
3761 			(priv->border.left + priv->border.right) / 2) * direction;
3762 	    else
3763 	        newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
3764 	    break;
3765 
3766 	case NorthEastGravity:
3767 	case EastGravity:
3768 	case SouthEastGravity:
3769 	    if (xwcm & CWX)
3770 		newX -= xwc->width + priv->border.right * direction;
3771 	    else
3772 		newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
3773 	    break;
3774 
3775 	case StaticGravity:
3776 	default:
3777 	    break;
3778 	}
3779     }
3780 
3781     if (xwcm & (CWY | CWHeight))
3782     {
3783 	switch (gravity) {
3784 	case NorthWestGravity:
3785 	case NorthGravity:
3786 	case NorthEastGravity:
3787 	    if (xwcm & CWY)
3788 		newY = xwc->y + priv->border.top * direction;
3789 	    break;
3790 
3791 	case WestGravity:
3792 	case CenterGravity:
3793 	case EastGravity:
3794 	    if (xwcm & CWY)
3795 		newY -= (xwc->height / 2 - priv->border.top +
3796 			(priv->border.top + priv->border.bottom) / 2) * direction;
3797 	    else
3798 		newY -= ((xwc->height - priv->serverGeometry.height ()) / 2) * direction;
3799 	    break;
3800 
3801 	case SouthWestGravity:
3802 	case SouthGravity:
3803 	case SouthEastGravity:
3804 	    if (xwcm & CWY)
3805 		newY -= xwc->height + priv->border.bottom * direction;
3806 	    else
3807 		newY -= (xwc->height - priv->serverGeometry.height ()) * direction;
3808 	    break;
3809 
3810 	case StaticGravity:
3811 	default:
3812 	    break;
3813 	}
3814     }
3815 
3816     if (newX != xwc->x)
3817     {
3818 	xwc->x += (newX - xwc->x);
3819 	mask |= CWX;
3820     }
3821 
3822     if (newY != xwc->y)
3823     {
3824 	xwc->y += (newY - xwc->y);
3825 	mask |= CWY;
3826     }
3827 
3828     return mask;
3829 }
3830 
3831 void
3832 CompWindow::moveResize (XWindowChanges *xwc,
3833 			unsigned int   xwcm,
3834 			int            gravity,
3835 			unsigned int   source)
3836 {
3837     bool placed = false;
3838 
3839     xwcm &= (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
3840 
3841     if (xwcm & (CWX | CWY))
3842 	if (priv->sizeHints.flags & (USPosition | PPosition))
3843 	    placed = true;
3844 
3845     if (gravity == 0)
3846 	gravity = priv->sizeHints.win_gravity;
3847 
3848     if (!(xwcm & CWX))
3849 	xwc->x = priv->serverGeometry.x ();
3850     if (!(xwcm & CWY))
3851 	xwc->y = priv->serverGeometry.y ();
3852     if (!(xwcm & CWWidth))
3853 	xwc->width = priv->serverGeometry.width ();
3854     if (!(xwcm & CWHeight))
3855 	xwc->height = priv->serverGeometry.height ();
3856 
3857     if (xwcm & (CWWidth | CWHeight))
3858     {
3859 	int width, height;
3860 
3861 	if (constrainNewWindowSize (xwc->width, xwc->height, &width, &height))
3862 	{
3863 	    if (width != xwc->width)
3864 		xwcm |= CWWidth;
3865 
3866 	    if (height != xwc->height)
3867 		xwcm |= CWHeight;
3868 
3869 	    xwc->width = width;
3870 	    xwc->height = height;
3871 	}
3872     }
3873 
3874     xwcm |= priv->adjustConfigureRequestForGravity (xwc, xwcm, gravity, 1);
3875 
3876     validateResizeRequest (xwcm, xwc, source);
3877 
3878     /* when horizontally maximized only allow width changes added by
3879        addWindowSizeChanges */
3880     if (priv->state & CompWindowStateMaximizedHorzMask)
3881 	xwcm &= ~CWWidth;
3882 
3883     /* when vertically maximized only allow height changes added by
3884        addWindowSizeChanges */
3885     if (priv->state & CompWindowStateMaximizedVertMask)
3886 	xwcm &= ~CWHeight;
3887 
3888     xwcm |= priv->addWindowSizeChanges (xwc, Geometry (xwc->x, xwc->y,
3889 					xwc->width, xwc->height,
3890 					xwc->border_width));
3891 
3892     /* check if the new coordinates are useful and valid (different
3893        to current size); if not, we have to clear them to make sure
3894        we send a synthetic ConfigureNotify event if all coordinates
3895        match the server coordinates */
3896     if (xwc->x == priv->serverGeometry.x ())
3897 	xwcm &= ~CWX;
3898 
3899     if (xwc->y == priv->serverGeometry.y ())
3900 	xwcm &= ~CWY;
3901 
3902     if (xwc->width == (int) priv->serverGeometry.width ())
3903 	xwcm &= ~CWWidth;
3904 
3905     if (xwc->height == (int) priv->serverGeometry.height ())
3906 	xwcm &= ~CWHeight;
3907 
3908     if (xwc->border_width == (int) priv->serverGeometry.border ())
3909 	xwcm &= ~CWBorderWidth;
3910 
3911     /* update saved window coordinates - if CWX or CWY is set for fullscreen
3912        or maximized windows after addWindowSizeChanges, it should be pretty
3913        safe to assume that the saved coordinates should be updated too, e.g.
3914        because the window was moved to another viewport by some client */
3915     if ((xwcm & CWX) && (priv->saveMask & CWX))
3916 	priv->saveWc.x += (xwc->x - priv->serverGeometry.x ());
3917 
3918     if ((xwcm & CWY) && (priv->saveMask & CWY))
3919 	priv->saveWc.y += (xwc->y - priv->serverGeometry.y ());
3920 
3921     if (priv->mapNum && (xwcm & (CWWidth | CWHeight)))
3922 	sendSyncRequest ();
3923 
3924     if (xwcm)
3925 	configureXWindow (xwcm, xwc);
3926     else
3927     {
3928 	/* we have to send a configure notify on ConfigureRequest events if
3929 	   we decide not to do anything according to ICCCM 4.1.5 */
3930 	sendConfigureNotify ();
3931     }
3932 
3933     if (placed)
3934 	priv->placed = true;
3935 }
3936 
3937 void
3938 PrivateWindow::updateSize ()
3939 {
3940     if (window->overrideRedirect () || !managed)
3941 	return;
3942 
3943     XWindowChanges xwc = XWINDOWCHANGES_INIT;
3944 
3945     int mask = priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
3946     if (mask)
3947     {
3948 	if (priv->mapNum && (mask & (CWWidth | CWHeight)))
3949 	    window->sendSyncRequest ();
3950 
3951 	window->configureXWindow (mask, &xwc);
3952     }
3953 }
3954 
3955 int
3956 PrivateWindow::addWindowStackChanges (XWindowChanges *xwc,
3957 				      CompWindow     *sibling)
3958 {
3959     int	mask = 0;
3960 
3961     if (!sibling || sibling->priv->id != id)
3962     {
3963 	/* Alow requests to go on top of serverPrev
3964 	 * if serverPrev was recently restacked */
3965 	if (window->serverPrev)
3966 	{
3967 	    if (!sibling && id)
3968 	    {
3969 		XWindowChanges lxwc = XWINDOWCHANGES_INIT;
3970 		unsigned int   valueMask = CWStackMode;
3971 
3972 		lxwc.stack_mode = Below;
3973 
3974 		if (serverFrame)
3975 		{
3976 		    compiz::X11::PendingEvent::Ptr pc =
3977 			    boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
3978 										      new compiz::X11::PendingConfigureEvent (
3979 											  screen->dpy (), serverFrame, valueMask, &lxwc)));
3980 
3981 		    pendingConfigures.add (pc);
3982 		}
3983 
3984 		/* Below with no sibling puts the window at the bottom
3985 		 * of the stack */
3986 		XConfigureWindow (screen->dpy (), ROOTPARENT (window), valueMask, &lxwc);
3987 
3988 		/* Update the list of windows last sent to the server */
3989 		screen->unhookServerWindow (window);
3990 		screen->insertServerWindow (window, 0);
3991 	    }
3992 	    else if (sibling)
3993 	    {
3994 		bool matchingRequest = priv->pendingConfigures.forEachIf (boost::bind (isExistingRequest, _1, *xwc, (CWStackMode | CWSibling)));
3995 		bool restackPending = window->serverPrev->priv->pendingConfigures.forEachIf (boost::bind (isPendingRestack, _1));
3996 		bool processAnyways = restackPending;
3997 
3998 		if (matchingRequest)
3999 		    processAnyways = false;
4000 
4001 		if (sibling->priv->id != window->serverPrev->priv->id ||
4002 		    processAnyways)
4003 		{
4004 		    mask |= CWSibling | CWStackMode;
4005 
4006 		    xwc->stack_mode = Above;
4007 		    xwc->sibling    = ROOTPARENT (sibling);
4008 		}
4009 	    }
4010 	}
4011 	else if (sibling)
4012 	{
4013 	    mask |= CWSibling | CWStackMode;
4014 
4015 	    xwc->stack_mode = Above;
4016 	    xwc->sibling    = ROOTPARENT (sibling);
4017 	}
4018     }
4019 
4020     return mask;
4021 }
4022 
4023 void
4024 CompWindow::raise ()
4025 {
4026     XWindowChanges xwc = XWINDOWCHANGES_INIT;
4027     int		   mask;
4028     bool	   aboveFs = false;
4029 
4030     /* an active fullscreen window should be raised over all other
4031        windows in its layer */
4032     if (priv->type & CompWindowTypeFullscreenMask)
4033 	if (priv->id == screen->activeWindow ())
4034 	    aboveFs = true;
4035 
4036     for (CompWindow *pw = serverPrev; pw; pw = pw->serverPrev)
4037     {
4038 	if (pw->priv->type & CompWindowTypeFullscreenMask)
4039 	{
4040 	    if (priv->id == screen->activeWindow ())
4041 		aboveFs = true;
4042 
4043 	    break;
4044 	}
4045     }
4046 
4047     mask = priv->addWindowStackChanges (&xwc,
4048 	PrivateWindow::findSiblingBelow (this, aboveFs));
4049 
4050     if (mask)
4051 	configureXWindow (mask, &xwc);
4052 }
4053 
4054 CompWindow *
4055 CompScreenImpl::focusTopMostWindow ()
4056 {
4057     using ::compiz::private_screen::WindowManager;
4058 
4059     CompWindow  *focus = NULL;
4060     WindowManager::reverse_iterator it = windowManager.rbegin ();
4061 
4062     for (; it != windowManager.rend (); it++)
4063     {
4064 	CompWindow *w = *it;
4065 
4066 	if (w->type () & CompWindowTypeDockMask)
4067 	    continue;
4068 
4069 	if (w->focus ())
4070 	{
4071 	    focus = w;
4072 	    break;
4073 	}
4074     }
4075 
4076     if (focus)
4077     {
4078 	if (focus->id () != privateScreen.orphanData.activeWindow)
4079 	    focus->moveInputFocusTo ();
4080     }
4081     else
4082 	XSetInputFocus (privateScreen.dpy, privateScreen.rootWindow(), RevertToPointerRoot,
4083 			CurrentTime);
4084     return focus;
4085 }
4086 
4087 
4088 void
4089 CompWindow::lower ()
4090 {
4091     XWindowChanges xwc = XWINDOWCHANGES_INIT;
4092     int		   mask;
4093 
4094     mask = priv->addWindowStackChanges (&xwc,
4095 	PrivateWindow::findLowestSiblingBelow (this));
4096     if (mask)
4097 	configureXWindow (mask, &xwc);
4098 
4099     /* when lowering a window, focus the topmost window if
4100        the click-to-focus option is on */
4101     if ((screen->getCoreOptions().optionGetClickToFocus ()))
4102     {
4103 	CompWindow *focusedWindow = screen->focusTopMostWindow ();
4104 
4105 	/* if the newly focused window is a desktop window,
4106 	   give the focus back to w */
4107 	if (focusedWindow &&
4108 	    focusedWindow->type () & CompWindowTypeDesktopMask)
4109 	{
4110 	    moveInputFocusTo ();
4111 	}
4112     }
4113 }
4114 
4115 void
4116 CompWindow::restackAbove (CompWindow *sibling)
4117 {
4118     for (; sibling; sibling = sibling->serverNext)
4119 	if (PrivateWindow::validSiblingBelow (this, sibling))
4120 	    break;
4121 
4122     if (sibling)
4123     {
4124 	XWindowChanges xwc = XWINDOWCHANGES_INIT;
4125 	int	       mask;
4126 
4127 	mask = priv->addWindowStackChanges (&xwc, sibling);
4128 	if (mask)
4129 	    configureXWindow (mask, &xwc);
4130     }
4131 }
4132 
4133 /* finds the highest window under sibling we can stack above */
4134 CompWindow *
4135 PrivateWindow::findValidStackSiblingBelow (CompWindow *w,
4136 					   CompWindow *sibling)
4137 {
4138     CompWindow *lowest, *last, *p;
4139 
4140     /* check whether we're allowed to stack under a sibling by finding
4141      * the above 'sibling' and checking whether or not we're allowed
4142      * to stack under that - if not, then there is no valid sibling
4143      * underneath it */
4144 
4145     for (p = sibling; p; p = p->serverNext)
4146     {
4147 	if (!avoidStackingRelativeTo (p))
4148 	{
4149 	    if (!validSiblingBelow (p, w))
4150 		return NULL;
4151 	    break;
4152 	}
4153     }
4154 
4155     /* get lowest sibling we're allowed to stack above */
4156     lowest = last = findLowestSiblingBelow (w);
4157 
4158     /* walk from bottom up */
4159     for (p = screen->serverWindows ().front (); p; p = p->serverNext)
4160     {
4161 	/* stop walking when we reach the sibling we should try to stack
4162 	   below */
4163 	if (p == sibling)
4164 	    return lowest;
4165 
4166 	/* skip windows that we should avoid */
4167 	if (w == p || avoidStackingRelativeTo (p))
4168 	    continue;
4169 
4170 	if (validSiblingBelow (w, p))
4171 	{
4172 	    /* update lowest as we find windows below sibling that we're
4173 	       allowed to stack above. last window must be equal to the
4174 	       lowest as we shouldn't update lowest if we passed an
4175 	       invalid window */
4176 	    if (last == lowest)
4177 		lowest = p;
4178 	}
4179 
4180 	/* update last pointer */
4181 	last = p;
4182     }
4183 
4184     return lowest;
4185 }
4186 
4187 void
4188 CompWindow::restackBelow (CompWindow *sibling)
4189 {
4190     XWindowChanges xwc = XWINDOWCHANGES_INIT;
4191     unsigned int   mask;
4192 
4193     mask = priv->addWindowStackChanges (&xwc,
4194 	PrivateWindow::findValidStackSiblingBelow (this, sibling));
4195 
4196     if (mask)
4197 	configureXWindow (mask, &xwc);
4198 }
4199 
4200 void
4201 CompWindow::updateAttributes (CompStackingUpdateMode stackingMode)
4202 {
4203     if (overrideRedirect () || !priv->managed)
4204 	return;
4205 
4206     XWindowChanges xwc = XWINDOWCHANGES_INIT;
4207     int		   mask = 0;
4208 
4209     if (priv->state & CompWindowStateShadedMask && !priv->shaded)
4210     {
4211 	windowNotify (CompWindowNotifyShade);
4212 
4213 	priv->hide ();
4214     }
4215     else if (priv->shaded)
4216     {
4217 	windowNotify (CompWindowNotifyUnshade);
4218 
4219 	priv->show ();
4220     }
4221 
4222     if (stackingMode != CompStackingUpdateModeNone)
4223     {
4224 	bool       aboveFs;
4225 	CompWindow *sibling;
4226 
4227 	aboveFs = (stackingMode == CompStackingUpdateModeAboveFullscreen);
4228 	if (priv->type & CompWindowTypeFullscreenMask)
4229 	{
4230 	    /* put active or soon-to-be-active fullscreen windows over
4231 	       all others in their layer */
4232 	    if (priv->id == screen->activeWindow () ||
4233 		priv->id == screen->getNextActiveWindow())
4234 	    {
4235 		aboveFs = true;
4236 	    }
4237 	}
4238 
4239 	/* put windows that are just mapped, over fullscreen windows */
4240 	if (stackingMode == CompStackingUpdateModeInitialMap)
4241 	    aboveFs = true;
4242 
4243 	sibling = PrivateWindow::findSiblingBelow (this, aboveFs);
4244 
4245 	if (sibling &&
4246 	    (stackingMode == CompStackingUpdateModeInitialMapDeniedFocus))
4247 	{
4248 	    CompWindow *p;
4249 
4250 	    for (p = sibling; p; p = p->serverPrev)
4251 		if (p->priv->id == screen->activeWindow ())
4252 		    break;
4253 
4254 	    /* window is above active window so we should lower it,
4255 	     * assuing that is allowed (if, for example, our window has
4256 	     * the "above" state, then lowering beneath the active
4257 	     * window may not be allowed). */
4258 	    if (p && PrivateWindow::validSiblingBelow (p, this))
4259 	    {
4260 		p = PrivateWindow::findValidStackSiblingBelow (this, p);
4261 
4262 		/* if we found a valid sibling under the active window, it's
4263 		   our new sibling we want to stack above */
4264 		if (p)
4265 		    sibling = p;
4266 	    }
4267 	}
4268 
4269 	/* If sibling is NULL, then this window will go on the bottom
4270 	 * of the stack */
4271 	mask |= priv->addWindowStackChanges (&xwc, sibling);
4272     }
4273 
4274     mask |= priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
4275 
4276     if (priv->mapNum && (mask & (CWWidth | CWHeight)))
4277 	sendSyncRequest ();
4278 
4279     if (mask)
4280 	configureXWindow (mask, &xwc);
4281 }
4282 
4283 void
4284 PrivateWindow::ensureWindowVisibility ()
4285 {
4286     if (struts || attrib.override_redirect)
4287 	return;
4288 
4289     if (type & (CompWindowTypeDockMask	     |
4290 		CompWindowTypeFullscreenMask |
4291 		CompWindowTypeUnknownMask))
4292 	return;
4293 
4294     int x1 = screen->workArea ().x () - screen->width () * screen->vp ().x ();
4295     int y1 = screen->workArea ().y () - screen->height () * screen->vp ().y ();
4296     int x2 = x1 + screen->workArea ().width () + screen->vpSize ().width () *
4297 	 screen->width ();
4298     int y2 = y1 + screen->workArea ().height () + screen->vpSize ().height () *
4299 	 screen->height ();
4300 
4301     int dx = 0;
4302     int width = serverGeometry.widthIncBorders ();
4303 
4304     if (serverGeometry.x () - serverInput.left >= x2)
4305 	dx = (x2 - 25) - serverGeometry.x ();
4306     else if (serverGeometry.x () + width + serverInput.right <= x1)
4307 	dx = (x1 + 25) - (serverGeometry.x () + width);
4308 
4309     int dy = 0;
4310     int height = serverGeometry.heightIncBorders ();
4311 
4312     if (serverGeometry.y () - serverInput.top >= y2)
4313 	dy = (y2 - 25) - serverGeometry.y ();
4314     else if (serverGeometry.y () + height + serverInput.bottom <= y1)
4315 	dy = (y1 + 25) - (serverGeometry.y () + height);
4316 
4317     if (dx || dy)
4318     {
4319 	XWindowChanges xwc = XWINDOWCHANGES_INIT;
4320 
4321 	xwc.x = serverGeometry.x () + dx;
4322 	xwc.y = serverGeometry.y () + dy;
4323 
4324 	window->configureXWindow (CWX | CWY, &xwc);
4325     }
4326 }
4327 
4328 void
4329 PrivateWindow::reveal ()
4330 {
4331     if (window->minimized ())
4332 	window->unminimize ();
4333 }
4334 
4335 void
4336 PrivateWindow::revealAncestors (CompWindow *w,
4337 				CompWindow *transient)
4338 {
4339     if (isAncestorTo (transient, w))
4340     {
4341 	screen->forEachWindow (boost::bind (revealAncestors, _1, w));
4342 	w->priv->reveal ();
4343     }
4344 }
4345 
4346 void
4347 CompWindow::activate ()
4348 {
4349     WRAPABLE_HND_FUNCTN (activate)
4350 
4351     screen->setCurrentDesktop (priv->desktop);
4352 
4353     screen->forEachWindow (
4354 	boost::bind (PrivateWindow::revealAncestors, _1, this));
4355     priv->reveal ();
4356 
4357     screen->leaveShowDesktopMode (this);
4358 
4359     if (priv->state & CompWindowStateHiddenMask)
4360     {
4361 	priv->state &= ~CompWindowStateShadedMask;
4362 	if (priv->shaded)
4363 	    priv->show ();
4364     }
4365 
4366     if (priv->state & CompWindowStateHiddenMask)
4367 	return;
4368 
4369     if (!onCurrentDesktop ())
4370 	return;
4371 
4372     priv->ensureWindowVisibility ();
4373     updateAttributes (CompStackingUpdateModeAboveFullscreen);
4374     moveInputFocusTo ();
4375 }
4376 
4377 
4378 #define PVertResizeInc (1 << 0)
4379 #define PHorzResizeInc (1 << 1)
4380 
4381 bool
4382 CompWindow::constrainNewWindowSize (int        width,
4383 				    int        height,
4384 				    int        *newWidth,
4385 				    int        *newHeight)
4386 {
4387     CompSize         size (width, height);
4388     long	     ignoredHints = 0;
4389     long	     ignoredResizeHints = 0;
4390 
4391     if (screen->getCoreOptions().optionGetIgnoreHintsWhenMaximized ())
4392     {
4393 	ignoredHints |= PAspect;
4394 
4395 	if (priv->state & CompWindowStateMaximizedHorzMask)
4396 	    ignoredResizeHints |= PHorzResizeInc;
4397 
4398 	if (priv->state & CompWindowStateMaximizedVertMask)
4399 	    ignoredResizeHints |= PVertResizeInc;
4400     }
4401 
4402     CompSize ret = compiz::window::constrainment::constrainToHints (priv->sizeHints,
4403 								    size,
4404 								    ignoredHints, ignoredResizeHints);
4405 
4406     *newWidth = ret.width ();
4407     *newHeight = ret.height ();
4408 
4409     return ret != size;
4410 }
4411 
4412 void
4413 CompWindow::hide ()
4414 {
4415     priv->hidden = true;
4416     priv->hide ();
4417 }
4418 
4419 void
4420 CompWindow::show ()
4421 {
4422     priv->hidden = false;
4423     priv->show ();
4424 }
4425 
4426 void
4427 PrivateWindow::hide ()
4428 {
4429     if (!managed)
4430 	return;
4431 
4432     bool onDesktop = window->onCurrentDesktop ();
4433 
4434     if (!window->minimized () && !inShowDesktopMode &&
4435 	!hidden && onDesktop)
4436     {
4437 	if (state & CompWindowStateShadedMask)
4438 	{
4439 	    shaded = true;
4440 	}
4441 	else
4442 	{
4443 	    return;
4444 	}
4445     }
4446     else
4447     {
4448 	shaded = false;
4449 
4450 	if ((state & CompWindowStateShadedMask) && serverFrame)
4451 	    XUnmapWindow (screen->dpy (), serverFrame);
4452     }
4453 
4454     if (!pendingMaps && !window->isViewable ())
4455 	return;
4456 
4457     window->windowNotify (CompWindowNotifyHide);
4458 
4459     pendingUnmaps++;
4460 
4461     if (serverFrame && !shaded)
4462 	XUnmapWindow (screen->dpy (), serverFrame);
4463 
4464     XUnmapWindow (screen->dpy (), id);
4465 
4466     if (window->minimized () || inShowDesktopMode || hidden || shaded)
4467 	window->changeState (state | CompWindowStateHiddenMask);
4468 
4469     if (shaded && id == screen->activeWindow ())
4470 	window->moveInputFocusTo ();
4471 }
4472 
4473 void
4474 PrivateWindow::show ()
4475 {
4476     if (!managed)
4477 	return;
4478 
4479     bool onDesktop = window->onCurrentDesktop ();
4480 
4481     if (minimized || inShowDesktopMode ||
4482 	hidden    || !onDesktop)
4483     {
4484 	/* no longer hidden but not on current desktop */
4485 	if (!minimized && !inShowDesktopMode && !hidden)
4486 	    window->changeState (state & ~CompWindowStateHiddenMask);
4487 
4488 	return;
4489     }
4490 
4491     /* transition from minimized to shaded */
4492     if (state & CompWindowStateShadedMask)
4493     {
4494 	shaded = true;
4495 
4496 	if (serverFrame)
4497 	    XMapWindow (screen->dpy (), serverFrame);
4498 
4499 	updateFrameWindow ();
4500 
4501 	return;
4502     }
4503 
4504     window->windowNotify (CompWindowNotifyShow);
4505 
4506     pendingMaps++;
4507 
4508     if (serverFrame)
4509     {
4510 	XMapWindow (screen->dpy (), serverFrame);
4511 	XMapWindow (screen->dpy (), wrapper);
4512     }
4513 
4514     XMapWindow (screen->dpy (), id);
4515 
4516     window->changeState (state & ~CompWindowStateHiddenMask);
4517     screen->setWindowState (state, id);
4518 }
4519 
4520 void
4521 PrivateWindow::minimizeTransients (CompWindow *w,
4522 				   CompWindow *ancestor)
4523 {
4524     if (w->priv->transientFor == ancestor->priv->id ||
4525 	w->priv->isGroupTransient (ancestor->priv->clientLeader))
4526     {
4527 	w->minimize ();
4528     }
4529 }
4530 
4531 void
4532 CompWindow::minimize ()
4533 {
4534     WRAPABLE_HND_FUNCTN (minimize);
4535 
4536     if (!priv->managed)
4537 	return;
4538 
4539     if (!priv->minimized)
4540     {
4541 	windowNotify (CompWindowNotifyMinimize);
4542 
4543 	priv->minimized = true;
4544 
4545 	screen->forEachWindow (
4546 	    boost::bind (PrivateWindow::minimizeTransients, _1, this));
4547 
4548 	priv->hide ();
4549     }
4550 }
4551 
4552 void
4553 PrivateWindow::unminimizeTransients (CompWindow *w,
4554 				     CompWindow *ancestor)
4555 {
4556     if (w->priv->transientFor == ancestor->priv->id ||
4557 	w->priv->isGroupTransient (ancestor->priv->clientLeader))
4558 	w->unminimize ();
4559 }
4560 
4561 void
4562 CompWindow::unminimize ()
4563 {
4564     WRAPABLE_HND_FUNCTN (unminimize);
4565     if (priv->minimized)
4566     {
4567 	windowNotify (CompWindowNotifyUnminimize);
4568 
4569 	priv->minimized = false;
4570 
4571 	priv->show ();
4572 
4573 	screen->forEachWindow (
4574 	    boost::bind (PrivateWindow::unminimizeTransients, _1, this));
4575     }
4576 }
4577 
4578 void
4579 CompWindow::maximize (unsigned int state)
4580 {
4581     if (overrideRedirect ())
4582 	return;
4583 
4584     state = constrainWindowState (state, priv->actions);
4585 
4586     state &= MAXIMIZE_STATE;
4587 
4588     if (state == (priv->state & MAXIMIZE_STATE))
4589 	return;
4590 
4591     state |= (priv->state & ~MAXIMIZE_STATE);
4592 
4593     changeState (state);
4594     updateAttributes (CompStackingUpdateModeNone);
4595 }
4596 
4597 bool
4598 PrivateWindow::getUserTime (Time& time)
4599 {
4600     Atom	  actual;
4601     int		  result, format;
4602     unsigned long n, left;
4603     unsigned char *data;
4604     bool          retval = false;
4605 
4606     result = XGetWindowProperty (screen->dpy (), priv->id,
4607 				 Atoms::wmUserTime,
4608 				 0L, 1L, False, XA_CARDINAL, &actual, &format,
4609 				 &n, &left, &data);
4610 
4611     if (result == Success && data)
4612     {
4613 	if (n)
4614 	{
4615 	    CARD32 value;
4616 
4617 	    memcpy (&value, data, sizeof (CARD32));
4618 	    retval = true;
4619 	    time   = (Time) value;
4620 	}
4621 
4622 	XFree ((void *) data);
4623     }
4624 
4625     return retval;
4626 }
4627 
4628 void
4629 PrivateWindow::setUserTime (Time time)
4630 {
4631     CARD32 value = (CARD32) time;
4632 
4633     XChangeProperty (screen->dpy (), priv->id,
4634 		     Atoms::wmUserTime,
4635 		     XA_CARDINAL, 32, PropModeReplace,
4636 		     (unsigned char *) &value, 1);
4637 }
4638 
4639 /*
4640  * Macros from metacity
4641  *
4642  * Xserver time can wraparound, thus comparing two timestamps needs to
4643  * take this into account.  Here's a little macro to help out.  If no
4644  * wraparound has occurred, this is equivalent to
4645  *   time1 < time2
4646  * Of course, the rest of the ugliness of this macro comes from
4647  * accounting for the fact that wraparound can occur and the fact that
4648  * a timestamp of 0 must be special-cased since it means older than
4649  * anything else.
4650  *
4651  * Note that this is NOT an equivalent for time1 <= time2; if that's
4652  * what you need then you'll need to swap the order of the arguments
4653  * and negate the result.
4654  */
4655 #define XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS(time1, time2) \
4656     ( (( (time1) < (time2) ) &&					      \
4657        ( (time2) - (time1) < ((unsigned long) -1) / 2 )) ||	      \
4658       (( (time1) > (time2) ) &&					      \
4659        ( (time1) - (time2) > ((unsigned long) -1) / 2 ))	      \
4660 	)
4661 #define XSERVER_TIME_IS_BEFORE(time1, time2)				 \
4662     ( (time1) == 0 ||							 \
4663       (XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS (time1, time2) && \
4664        (time2) != 0)							 \
4665 	)
4666 
4667 bool
4668 PrivateWindow::getUsageTimestamp (Time& timestamp)
4669 {
4670     if (getUserTime (timestamp))
4671 	return true;
4672 
4673     if (initialTimestampSet)
4674     {
4675 	timestamp = initialTimestamp;
4676 	return true;
4677     }
4678 
4679     return false;
4680 }
4681 
4682 bool
4683 PrivateWindow::isWindowFocusAllowed (Time timestamp)
4684 {
4685     CompScreen   *s = screen;
4686     CompWindow   *active;
4687     Time	 wUserTime, aUserTime;
4688     bool         gotTimestamp = false;
4689     int          level;
4690     CompPoint    dvp;
4691 
4692     level = s->getCoreOptions().optionGetFocusPreventionLevel ();
4693 
4694     if (level == CoreOptions::FocusPreventionLevelOff)
4695 	return true;
4696 
4697     if (timestamp)
4698     {
4699 	/* the caller passed a timestamp, so use that
4700 	   instead of the window's user time */
4701 	wUserTime = timestamp;
4702 	gotTimestamp = true;
4703     }
4704     else
4705     {
4706 	gotTimestamp = getUsageTimestamp (wUserTime);
4707     }
4708 
4709     /* if we got no timestamp for the window, try to get at least a timestamp
4710        for its transient parent, if any */
4711     if (!gotTimestamp && transientFor)
4712     {
4713 	CompWindow *parent;
4714 
4715 	parent = screen->findWindow (transientFor);
4716 	if (parent)
4717 	    gotTimestamp = parent->priv->getUsageTimestamp (wUserTime);
4718     }
4719 
4720     if (gotTimestamp && !wUserTime)
4721     {
4722 	/* window explicitly requested no focus */
4723 	return false;
4724     }
4725 
4726     /* allow focus for excluded windows */
4727     CompMatch &match = s->getCoreOptions().optionGetFocusPreventionMatch ();
4728     if (!match.evaluate (window))
4729 	return true;
4730 
4731     if (level == CoreOptions::FocusPreventionLevelVeryHigh)
4732 	return false;
4733 
4734     active = s->findWindow (s->activeWindow ());
4735 
4736     /* no active window */
4737     if (!active || (active->type () & CompWindowTypeDesktopMask))
4738 	return true;
4739 
4740     /* active window belongs to same application */
4741     if (window->clientLeader () == active->clientLeader ())
4742        return true;
4743 
4744     if (level == CoreOptions::FocusPreventionLevelHigh)
4745        return false;
4746 
4747     /* not in current viewport or desktop */
4748     if (!window->onCurrentDesktop ())
4749 	return false;
4750 
4751     dvp = window->defaultViewport ();
4752     if (dvp.x () != s->vp ().x () || dvp.y () != s->vp ().y ())
4753 	return false;
4754 
4755     if (!gotTimestamp)
4756     {
4757 	/* unsure as we have nothing to compare - allow focus in low level,
4758 	   don't allow in normal level */
4759 	if (level == CoreOptions::FocusPreventionLevelNormal)
4760 	    return false;
4761 
4762 	return true;
4763     }
4764 
4765     /* can't get user time for active window */
4766     if (!active->priv->getUserTime (aUserTime))
4767 	return true;
4768 
4769     if (XSERVER_TIME_IS_BEFORE (wUserTime, aUserTime))
4770 	return false;
4771 
4772     return true;
4773 }
4774 
4775 bool
4776 PrivateWindow::allowWindowFocus (unsigned int noFocusMask,
4777 				 Time         timestamp)
4778 {
4779     bool retval;
4780 
4781     if (priv->id == screen->activeWindow ())
4782 	return true;
4783 
4784     /* do not focus windows of these types */
4785     if (priv->type & noFocusMask)
4786 	return false;
4787 
4788     /* window doesn't take focus */
4789     if (!priv->inputHint &&
4790 	!(priv->protocols & CompWindowProtocolTakeFocusMask))
4791     {
4792 	return false;
4793     }
4794 
4795     retval = priv->isWindowFocusAllowed (timestamp);
4796     if (!retval)
4797     {
4798 	/* add demands attention state if focus was prevented */
4799 	window->changeState (priv->state | CompWindowStateDemandsAttentionMask);
4800     }
4801 
4802     return retval;
4803 }
4804 
4805 CompPoint
4806 CompWindow::defaultViewport () const
4807 {
4808     CompPoint viewport;
4809 
4810     if (priv->serverGeometry.x () < (int) screen->width ()            &&
4811 	priv->serverGeometry.x () + priv->serverGeometry.width () > 0 &&
4812 	priv->serverGeometry.y () < (int) screen->height ()           &&
4813 	priv->serverGeometry.y ()+ priv->serverGeometry.height () > 0)
4814     {
4815 	return screen->vp ();
4816     }
4817 
4818     screen->viewportForGeometry (priv->serverGeometry, viewport);
4819 
4820     return viewport;
4821 }
4822 
4823 const CompPoint &
4824 CompWindow::initialViewport () const
4825 {
4826     return priv->initialViewport;
4827 }
4828 
4829 void
4830 PrivateWindow::readIconHint ()
4831 {
4832     XImage       *image, *maskImage = NULL;
4833     Display      *dpy = screen->dpy ();
4834     unsigned int width, height, dummy;
4835     unsigned int i, j, k;
4836     int		 iDummy;
4837     Window       wDummy;
4838     CompIcon     *icon;
4839     CARD32       *p;
4840 
4841     if (!XGetGeometry (dpy, hints->icon_pixmap, &wDummy, &iDummy,
4842 		       &iDummy, &width, &height, &dummy, &dummy))
4843 	return;
4844 
4845     image = XGetImage (dpy, hints->icon_pixmap, 0, 0, width, height,
4846 		       AllPlanes, ZPixmap);
4847     if (!image)
4848 	return;
4849 
4850     boost::scoped_array<XColor> colors(new XColor[width * height]);
4851     if (!colors)
4852     {
4853 	XDestroyImage (image);
4854 	return;
4855     }
4856 
4857     k = 0;
4858     for (j = 0; j < height; j++)
4859 	for (i = 0; i < width; i++)
4860 	    colors[k++].pixel = XGetPixel (image, i, j);
4861 
4862     for (i = 0; i < k; i += 256)
4863 	XQueryColors (dpy, screen->colormap(),
4864 		      &colors[i], MIN (k - i, 256));
4865 
4866     XDestroyImage (image);
4867 
4868     icon = new CompIcon (width, height);
4869     if (!icon)
4870     {
4871 	return;
4872     }
4873 
4874     if (hints->flags & IconMaskHint)
4875 	maskImage = XGetImage (dpy, hints->icon_mask, 0, 0,
4876 			       width, height, AllPlanes, ZPixmap);
4877 
4878     k = 0;
4879     p = (CARD32 *) icon->data ();
4880 
4881     for (j = 0; j < height; j++)
4882     {
4883 	for (i = 0; i < width; i++)
4884 	{
4885 	    if (maskImage && !XGetPixel (maskImage, i, j))
4886 		*p++ = 0;
4887 	    else if (image->depth == 1)  /* white   : black */
4888 		*p++ = colors[k].pixel ? 0xffffffff : 0xff000000;
4889 	    else
4890 		*p++ = 0xff000000                             | /* alpha */
4891 		       (((colors[k].red >> 8) & 0xff) << 16)  | /* red */
4892 		       (((colors[k].green >> 8) & 0xff) << 8) | /* green */
4893 		       ((colors[k].blue >> 8) & 0xff);          /* blue */
4894 
4895 	    k++;
4896 	}
4897     }
4898 
4899     if (maskImage)
4900 	XDestroyImage (maskImage);
4901 
4902     icons.push_back (icon);
4903 }
4904 
4905 /* returns icon with dimensions as close as possible to width and height
4906    but never greater. */
4907 CompIcon *
4908 CompWindow::getIcon (int width,
4909 		     int height)
4910 {
4911     CompIcon     *icon;
4912     int          wh, diff, oldDiff;
4913     unsigned int i;
4914 
4915     /* need to fetch icon property */
4916     if (priv->icons.size () == 0 && !priv->noIcons)
4917     {
4918 	Atom	      actual;
4919 	int	      result, format;
4920 	unsigned long n, left;
4921 	unsigned char *data;
4922 
4923 	result = XGetWindowProperty (screen->dpy (), priv->id, Atoms::wmIcon,
4924 				     0L, 65536L, false, XA_CARDINAL,
4925 				     &actual, &format, &n, &left, &data);
4926 
4927 	if (result == Success && data)
4928 	{
4929 	    CARD32        *p;
4930 	    CARD32        alpha, red, green, blue;
4931 	    unsigned long iw, ih;
4932 
4933 	    for (i = 0; i + 2 < n; i += iw * ih + 2)
4934 	    {
4935 		unsigned long *idata = (unsigned long *) data;
4936 
4937 		iw = idata[i];
4938 		ih = idata[i + 1];
4939 
4940 		/* iw * ih may be larger than the value range of unsigned
4941 		* long, so better do some checking for extremely weird
4942 		* icon sizes first */
4943 		if (iw > 2048 || ih > 2048 || iw * ih + 2 > n - i)
4944 		    break;
4945 
4946 		if (iw && ih)
4947 		{
4948 		    icon = new CompIcon (iw, ih);
4949 		    if (!icon)
4950 			continue;
4951 
4952 		    priv->icons.push_back (icon);
4953 
4954 		    p = (CARD32 *) (icon->data ());
4955 
4956 		    /* EWMH doesn't say if icon data is premultiplied or
4957 		       not but most applications seem to assume data should
4958 		       be unpremultiplied. */
4959 		    for (unsigned long j = 0; j < iw * ih; j++)
4960 		    {
4961 			alpha = (idata[i + j + 2] >> 24) & 0xff;
4962 			red   = (idata[i + j + 2] >> 16) & 0xff;
4963 			green = (idata[i + j + 2] >>  8) & 0xff;
4964 			blue  = (idata[i + j + 2] >>  0) & 0xff;
4965 
4966 			red   = (red   * alpha) >> 8;
4967 			green = (green * alpha) >> 8;
4968 			blue  = (blue  * alpha) >> 8;
4969 
4970 			p[j] =
4971 			    (alpha << 24) |
4972 			    (red   << 16) |
4973 			    (green <<  8) |
4974 			    (blue  <<  0);
4975 		    }
4976 		}
4977 	    }
4978 
4979 	    XFree (data);
4980 	}
4981 	else if (priv->hints && (priv->hints->flags & IconPixmapHint))
4982 	{
4983 	    priv->readIconHint ();
4984 	}
4985 
4986 	/* don't fetch property again */
4987 	if (priv->icons.size () == 0)
4988 	    priv->noIcons = true;
4989     }
4990 
4991     /* no icons available for this window */
4992     if (priv->noIcons)
4993 	return NULL;
4994 
4995     icon = NULL;
4996     wh   = width + height;
4997 
4998     for (i = 0; i < priv->icons.size (); i++)
4999     {
5000 	const CompSize iconSize = *priv->icons[i];
5001 
5002 	if ((int) iconSize.width () > width ||
5003 	    (int) iconSize.height () > height)
5004 	    continue;
5005 
5006 	if (icon)
5007 	{
5008 	    diff    = wh - (iconSize.width () + iconSize.height ());
5009 	    oldDiff = wh - (icon->width () + icon->height ());
5010 
5011 	    if (diff < oldDiff)
5012 		icon = priv->icons[i];
5013 	}
5014 	else
5015 	    icon = priv->icons[i];
5016     }
5017 
5018     return icon;
5019 }
5020 
5021 const CompRect&
5022 CompWindow::iconGeometry () const
5023 {
5024     return priv->iconGeometry;
5025 }
5026 
5027 void
5028 PrivateWindow::freeIcons ()
5029 {
5030     for (unsigned int i = 0; i < priv->icons.size (); i++)
5031 	delete priv->icons[i];
5032 
5033     priv->icons.resize (0);
5034     priv->noIcons = false;
5035 }
5036 
5037 int
5038 CompWindow::outputDevice () const
5039 {
5040     return screen->outputDeviceForGeometry (priv->serverGeometry);
5041 }
5042 
5043 bool
5044 CompWindow::onCurrentDesktop () const
5045 {
5046     if (priv->desktop == 0xffffffff ||
5047 	priv->desktop == screen->currentDesktop ())
5048     {
5049 	return true;
5050     }
5051 
5052     return false;
5053 }
5054 
5055 void
5056 CompWindow::setDesktop (unsigned int desktop)
5057 {
5058     if (desktop != 0xffffffff)
5059     {
5060 	if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
5061 	    return;
5062 
5063 	if (desktop >= screen->nDesktop ())
5064 	    return;
5065     }
5066 
5067     if (desktop == priv->desktop)
5068 	return;
5069 
5070     priv->desktop = desktop;
5071 
5072     if (desktop == 0xffffffff || desktop == screen->currentDesktop ())
5073 	priv->show ();
5074     else
5075 	priv->hide ();
5076 
5077     screen->setWindowProp (priv->id, Atoms::winDesktop, priv->desktop);
5078 }
5079 
5080 /* The compareWindowActiveness function compares the two windows 'w1'
5081    and 'w2'. It returns an integer less than, equal to, or greater
5082    than zero if 'w1' is found, respectively, to activated longer time
5083    ago than, to be activated at the same time, or be activated more
5084    recently than 'w2'. */
5085 int
5086 PrivateWindow::compareWindowActiveness (CompWindow *w1,
5087 					CompWindow *w2)
5088 {
5089     CompActiveWindowHistory *history = screen->currentHistory ();
5090     int			    i;
5091 
5092     /* check current window history first */
5093     for (i = 0; i < ACTIVE_WINDOW_HISTORY_SIZE; i++)
5094     {
5095 	if (history->id[i] == w1->priv->id)
5096 	    return 1;
5097 
5098 	if (history->id[i] == w2->priv->id)
5099 	    return -1;
5100 
5101 	if (!history->id[i])
5102 	    break;
5103     }
5104 
5105     return w1->priv->activeNum - w2->priv->activeNum;
5106 }
5107 
5108 bool
5109 CompWindow::onAllViewports () const
5110 {
5111     if (overrideRedirect ())
5112 	return true;
5113 
5114     if (!priv->managed && !isViewable ())
5115 	return true;
5116 
5117     if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
5118 	return true;
5119 
5120     if (priv->state & CompWindowStateStickyMask)
5121 	return true;
5122 
5123     return false;
5124 }
5125 
5126 CompPoint
5127 CompWindow::getMovementForOffset (const CompPoint &offset) const
5128 {
5129     CompScreen *s = screen;
5130     int         m, vWidth, vHeight;
5131     int         offX = offset.x (), offY = offset.y ();
5132     CompPoint   rv;
5133 
5134     vWidth = s->width () * s->vpSize ().width ();
5135     vHeight = s->height () * s->vpSize ().height ();
5136 
5137     offX %= vWidth;
5138     offY %= vHeight;
5139 
5140     /* x */
5141     if (s->vpSize ().width () == 1)
5142     {
5143 	rv.setX (offX);
5144     }
5145     else
5146     {
5147 	m = priv->serverGeometry.x () + offX;
5148 	if (m - priv->serverInput.left < (int) s->width () - vWidth)
5149 	    rv.setX (offX + vWidth);
5150 	else if (m + priv->serverGeometry.width () + priv->serverInput.right > vWidth)
5151 	    rv.setX (offX - vWidth);
5152 	else
5153 	    rv.setX (offX);
5154     }
5155 
5156     if (s->vpSize ().height () == 1)
5157     {
5158 	rv.setY (offY);
5159     }
5160     else
5161     {
5162 	m = priv->serverGeometry.y () + offY;
5163 	if (m - priv->serverInput.top < (int) s->height () - vHeight)
5164 	    rv.setY (offY + vHeight);
5165 	else if (m + priv->serverGeometry.height () + priv->serverInput.bottom > vHeight)
5166 	    rv.setY (offY - vHeight);
5167 	else
5168 	    rv.setY (offY);
5169     }
5170 
5171     return rv;
5172 }
5173 
5174 void
5175 WindowInterface::getOutputExtents (CompWindowExtents& output)
5176     WRAPABLE_DEF (getOutputExtents, output)
5177 
5178 void
5179 WindowInterface::getAllowedActions (unsigned int &setActions,
5180 				    unsigned int &clearActions)
5181     WRAPABLE_DEF (getAllowedActions, setActions, clearActions)
5182 
5183 bool
5184 WindowInterface::focus ()
5185     WRAPABLE_DEF (focus)
5186 
5187 void
5188 WindowInterface::activate ()
5189     WRAPABLE_DEF (activate)
5190 
5191 bool
5192 WindowInterface::place (CompPoint &pos)
5193     WRAPABLE_DEF (place, pos)
5194 
5195 void
5196 WindowInterface::validateResizeRequest (unsigned int   &mask,
5197 					XWindowChanges *xwc,
5198 					unsigned int   source)
5199     WRAPABLE_DEF (validateResizeRequest, mask, xwc, source)
5200 
5201 void
5202 WindowInterface::resizeNotify (int dx,
5203 			       int dy,
5204 			       int dwidth,
5205 			       int dheight)
5206     WRAPABLE_DEF (resizeNotify, dx, dy, dwidth, dheight)
5207 
5208 void
5209 WindowInterface::moveNotify (int  dx,
5210 			     int  dy,
5211 			     bool immediate)
5212     WRAPABLE_DEF (moveNotify, dx, dy, immediate)
5213 
5214 void
5215 WindowInterface::windowNotify (CompWindowNotify n)
5216     WRAPABLE_DEF (windowNotify, n)
5217 
5218 void
5219 WindowInterface::grabNotify (int          x,
5220 			     int          y,
5221 			     unsigned int state,
5222 			     unsigned int mask)
5223     WRAPABLE_DEF (grabNotify, x, y, state, mask)
5224 
5225 void
5226 WindowInterface::ungrabNotify ()
5227     WRAPABLE_DEF (ungrabNotify)
5228 
5229 void
5230 WindowInterface::stateChangeNotify (unsigned int lastState)
5231     WRAPABLE_DEF (stateChangeNotify, lastState)
5232 
5233 void
5234 WindowInterface::updateFrameRegion (CompRegion &region)
5235     WRAPABLE_DEF (updateFrameRegion, region)
5236 
5237 void
5238 WindowInterface::minimize ()
5239     WRAPABLE_DEF (minimize);
5240 
5241 void
5242 WindowInterface::unminimize ()
5243     WRAPABLE_DEF (unminimize);
5244 
5245 bool
5246 WindowInterface::minimized () const
5247     WRAPABLE_DEF (minimized);
5248 
5249 bool
5250 WindowInterface::alpha () const
5251     WRAPABLE_DEF (alpha);
5252 
5253 bool
5254 WindowInterface::isFocussable () const
5255     WRAPABLE_DEF (isFocussable);
5256 
5257 bool
5258 WindowInterface::managed () const
5259     WRAPABLE_DEF (managed);
5260 
5261 bool
5262 WindowInterface::focused () const
5263     WRAPABLE_DEF (focused);
5264 
5265 Window
5266 CompWindow::id () const
5267 {
5268     return priv->id;
5269 }
5270 
5271 unsigned int
5272 CompWindow::type () const
5273 {
5274     return priv->type;
5275 }
5276 
5277 unsigned int &
5278 CompWindow::state () const
5279 {
5280     return priv->state;
5281 }
5282 
5283 unsigned int
5284 CompWindow::actions () const
5285 {
5286     return priv->actions;
5287 }
5288 
5289 unsigned int &
5290 CompWindow::protocols () const
5291 {
5292     return priv->protocols;
5293 }
5294 
5295 void
5296 CompWindow::close (Time serverTime)
5297 {
5298     if (serverTime == 0)
5299 	serverTime = screen->getCurrentTime ();
5300 
5301     if (priv->alive)
5302     {
5303 	if (priv->protocols & CompWindowProtocolDeleteMask)
5304 	{
5305 	    XEvent ev;
5306 
5307 	    ev.type		    = ClientMessage;
5308 	    ev.xclient.window	    = priv->id;
5309 	    ev.xclient.message_type = Atoms::wmProtocols;
5310 	    ev.xclient.format	    = 32;
5311 	    ev.xclient.data.l[0]    = Atoms::wmDeleteWindow;
5312 	    ev.xclient.data.l[1]    = serverTime;
5313 	    ev.xclient.data.l[2]    = 0;
5314 	    ev.xclient.data.l[3]    = 0;
5315 	    ev.xclient.data.l[4]    = 0;
5316 
5317 	    XSendEvent (screen->dpy (), priv->id, false, NoEventMask, &ev);
5318 	}
5319 	else
5320 	{
5321 	    XKillClient (screen->dpy (), priv->id);
5322 	}
5323 
5324 	priv->closeRequests++;
5325     }
5326     else
5327     {
5328 	screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
5329 				     serverTime, priv->id, true, 0, 0);
5330     }
5331 
5332     priv->lastCloseRequestTime = serverTime;
5333 }
5334 
5335 bool
5336 PrivateWindow::handlePingTimeout (unsigned int lastPing)
5337 {
5338     if (!window->isViewable ())
5339 	return false;
5340 
5341     if (!(priv->type & CompWindowTypeNormalMask))
5342 	return false;
5343 
5344     if (priv->protocols & CompWindowProtocolPingMask)
5345     {
5346 	if (priv->transientFor)
5347 	    return false;
5348 
5349 	if (priv->lastPong < lastPing)
5350 	{
5351 	    if (priv->alive)
5352 	    {
5353 		priv->alive = false;
5354 
5355 		window->windowNotify (CompWindowNotifyAliveChanged);
5356 
5357 		if (priv->closeRequests)
5358 		{
5359 		    screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
5360 					   priv->lastCloseRequestTime,
5361 					   priv->id, true, 0, 0);
5362 
5363 		    priv->closeRequests = 0;
5364 		}
5365 	    }
5366 	}
5367 
5368 	return true;
5369     }
5370     return false;
5371 }
5372 
5373 void
5374 PrivateWindow::handlePing (int lastPing)
5375 {
5376     if (!priv->alive)
5377     {
5378 	priv->alive = true;
5379 
5380 	window->windowNotify (CompWindowNotifyAliveChanged);
5381 
5382 	if (priv->lastCloseRequestTime)
5383 	{
5384 	    screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
5385 				   priv->lastCloseRequestTime,
5386 				   priv->id, false, 0, 0);
5387 
5388 	    priv->lastCloseRequestTime = 0;
5389 	}
5390     }
5391     priv->lastPong = lastPing;
5392 }
5393 
5394 void
5395 PrivateWindow::processMap ()
5396 {
5397     bool                   allowFocus;
5398     bool                   initiallyMinimized;
5399     CompStackingUpdateMode stackingMode;
5400 
5401     priv->initialViewport = screen->vp ();
5402 
5403     priv->initialTimestampSet = false;
5404 
5405     screen->applyStartupProperties (window);
5406 
5407     initiallyMinimized = (priv->hints &&
5408 			  priv->hints->initial_state == IconicState &&
5409 			  !window->minimized ());
5410 
5411     if (!serverFrame && !initiallyMinimized)
5412 	reparent ();
5413 
5414     priv->managed = true;
5415 
5416     if (!initiallyMinimized && !(priv->state & CompWindowStateHiddenMask))
5417 	receivedMapRequestAndAwaitingMap = true;
5418 
5419     if (!priv->placed)
5420     {
5421 	int            gravity = priv->sizeHints.win_gravity;
5422 	XWindowChanges xwc = XWINDOWCHANGES_INIT;
5423 	unsigned int   xwcm;
5424 
5425 	/* adjust for gravity, but only for frame size */
5426 	xwc.x      = priv->serverGeometry.x ();
5427 	xwc.y      = priv->serverGeometry.y ();
5428 	xwc.width  = 0;
5429 	xwc.height = 0;
5430 
5431 	xwcm = adjustConfigureRequestForGravity (&xwc, CWX | CWY, gravity, 1);
5432 
5433 	xwc.width = priv->serverGeometry.width ();
5434 	xwc.height = priv->serverGeometry.height ();
5435 
5436 	window->validateResizeRequest (xwcm, &xwc, ClientTypeApplication);
5437 
5438 	CompPoint pos (xwc.x, xwc.y);
5439 	if (window->place (pos))
5440 	{
5441 	    xwc.x = pos.x ();
5442 	    xwc.y = pos.y ();
5443 	    xwcm |= CWX | CWY;
5444 	}
5445 
5446 	if (xwcm)
5447 	    window->configureXWindow (xwcm, &xwc);
5448 
5449 	priv->placed = true;
5450     }
5451 
5452     allowFocus = allowWindowFocus (NO_FOCUS_MASK, 0);
5453 
5454     if (!allowFocus && (priv->type & ~NO_FOCUS_MASK))
5455 	stackingMode = CompStackingUpdateModeInitialMapDeniedFocus;
5456     else
5457 	stackingMode = CompStackingUpdateModeInitialMap;
5458 
5459     window->updateAttributes (stackingMode);
5460 
5461     if (window->minimized () && !initiallyMinimized)
5462 	window->unminimize ();
5463 
5464     screen->leaveShowDesktopMode (window);
5465 
5466     if (!initiallyMinimized)
5467     {
5468 	if (allowFocus && !window->onCurrentDesktop ())
5469 	    screen->setCurrentDesktop (priv->desktop);
5470 
5471 	if (!(priv->state & CompWindowStateHiddenMask))
5472 	{
5473 	    show ();
5474 	    receivedMapRequestAndAwaitingMap = false;
5475 	 }
5476 
5477 	if (allowFocus)
5478 	{
5479 	    window->moveInputFocusTo ();
5480 	    if (!window->onCurrentDesktop ())
5481 		screen->setCurrentDesktop (priv->desktop);
5482 	}
5483     }
5484     else
5485     {
5486 	window->minimize ();
5487 	window->changeState (window->state () | CompWindowStateHiddenMask);
5488     }
5489 
5490     screen->updateClientList ();
5491 }
5492 
5493 /*
5494  * PrivateWindow::updatePassiveButtonGrabs
5495  *
5496  * Updates the passive button grabs for a window. When
5497  * one of the specified button + modifier combinations
5498  * for this window is activated, compiz will be given
5499  * an active grab for the window (which we can turn off
5500  * by calling XAllowEvents later in ::handleEvent)
5501  *
5502  * NOTE: ICCCM says that we are only allowed to grab
5503  * windows that we actually own as a client, so only
5504  * grab the frame window. Additionally, although there
5505  * isn't anything in the ICCCM that says we cannot
5506  * grab every button, some clients do not interpret
5507  * EnterNotify and LeaveNotify events caused by the
5508  * activation of the grab correctly, so ungrab button
5509  * and modifier combinations that we do not need on
5510  * active windows (but in reality we shouldn't be grabbing
5511  * for buttons that we don't actually need at that point
5512  * anyways)
5513  */
5514 
5515 void
5516 PrivateWindow::updatePassiveButtonGrabs ()
5517 {
5518     if (!priv->frame)
5519 	return;
5520 
5521     bool onlyActions = (priv->id == screen->activeWindow() ||
5522 			!screen->getCoreOptions().optionGetClickToFocus ());
5523 
5524     /* Ungrab everything */
5525     XUngrabButton (screen->dpy(), AnyButton, AnyModifier, frame);
5526 
5527     /* We don't need the full grab in the following cases:
5528      * - This window has the focus and either
5529      *   - it is raised or
5530      *   - we don't want click raise
5531      */
5532 
5533     if (onlyActions)
5534     {
5535 	if (screen->getCoreOptions().optionGetRaiseOnClick ())
5536 	{
5537 	    CompWindow *highestSibling =
5538 		    PrivateWindow::findSiblingBelow (window, true);
5539 
5540 	    /* Check if this window is permitted to be raised */
5541 	    for (CompWindow *above = window->serverNext;
5542 		above != NULL; above = above->serverNext)
5543 	    {
5544 		if (highestSibling == above)
5545 		{
5546 		    onlyActions = false;
5547 		    break;
5548 		}
5549 	    }
5550 	}
5551     }
5552 
5553     if (onlyActions)
5554     {
5555         screen->updatePassiveButtonGrabs(serverFrame);
5556     }
5557     else
5558     {
5559 	/* Grab everything */
5560 	XGrabButton (screen->dpy(),
5561 		     AnyButton,
5562 		     AnyModifier,
5563 		     serverFrame, false,
5564 		     ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
5565 		     GrabModeSync,
5566 		     GrabModeAsync,
5567 		     None,
5568 		     None);
5569     }
5570 }
5571 
5572 
5573 const CompRegion &
5574 CompWindow::region () const
5575 {
5576     return priv->region;
5577 }
5578 
5579 const CompRegion &
5580 CompWindow::frameRegion () const
5581 {
5582     return priv->frameRegion;
5583 }
5584 
5585 bool
5586 CompWindow::inShowDesktopMode () const
5587 {
5588     return priv->inShowDesktopMode;
5589 }
5590 
5591 void
5592 CompWindow::setShowDesktopMode (bool value)
5593 {
5594     priv->inShowDesktopMode = value;
5595 }
5596 
5597 bool
5598 CompWindow::managed () const
5599 {
5600     WRAPABLE_HND_FUNCTN_RETURN (bool, managed);
5601     return priv->managed;
5602 }
5603 
5604 bool
5605 CompWindow::focused () const
5606 {
5607     WRAPABLE_HND_FUNCTN_RETURN (bool, focused);
5608     return screen->activeWindow () == id ();
5609 }
5610 
5611 bool
5612 CompWindow::grabbed () const
5613 {
5614     return priv->grabbed;
5615 }
5616 
5617 int
5618 CompWindow::pendingMaps () const
5619 {
5620     return priv->pendingMaps;
5621 }
5622 
5623 unsigned int &
5624 CompWindow::wmType () const
5625 {
5626     return priv->wmType;
5627 }
5628 
5629 unsigned int
5630 CompWindow::activeNum () const
5631 {
5632     return priv->activeNum;
5633 }
5634 
5635 Window
5636 CompWindow::frame () const
5637 {
5638     return priv->serverFrame;
5639 }
5640 
5641 CompString
5642 CompWindow::resName () const
5643 {
5644     if (priv->resName)
5645 	return priv->resName;
5646 
5647     return CompString ();
5648 }
5649 
5650 int
5651 CompWindow::mapNum () const
5652 {
5653     return priv->mapNum;
5654 }
5655 
5656 const CompStruts *
5657 CompWindow::struts () const
5658 {
5659     return priv->struts;
5660 }
5661 
5662 int &
5663 CompWindow::saveMask () const
5664 {
5665     return priv->saveMask;
5666 }
5667 
5668 XWindowChanges &
5669 CompWindow::saveWc ()
5670 {
5671     return priv->saveWc;
5672 }
5673 
5674 void
5675 CompWindow::moveToViewportPosition (int  x,
5676 				    int  y,
5677 				    bool sync)
5678 {
5679     int tx, ty;
5680     int vWidth  = screen->width () * screen->vpSize ().width ();
5681     int vHeight = screen->height () * screen->vpSize ().height ();
5682 
5683     if (screen->vpSize ().width () != 1)
5684     {
5685 	x += screen->vp ().x () * screen->width ();
5686 	x = compiz::core::screen::wraparound_mod (x, vWidth);
5687 	x -= screen->vp ().x () * screen->width ();
5688     }
5689 
5690     if (screen->vpSize ().height () != 1)
5691     {
5692 	y += screen->vp ().y () * screen->height ();
5693 	y = compiz::core::screen::wraparound_mod (y, vHeight);
5694 	y -= screen->vp ().y () * screen->height ();
5695     }
5696 
5697     tx = x - priv->serverGeometry.x ();
5698     ty = y - priv->serverGeometry.y ();
5699 
5700     if (tx || ty)
5701     {
5702 	unsigned int   valueMask = CWX | CWY;
5703 	XWindowChanges xwc = XWINDOWCHANGES_INIT;
5704 
5705 	if (!priv->managed)
5706 	    return;
5707 
5708 	if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
5709 	    return;
5710 
5711 	if (priv->state & CompWindowStateStickyMask)
5712 	    return;
5713 
5714 	int wx = tx;
5715 	int wy = ty;
5716 	int m;
5717 
5718 	if (screen->vpSize ().width ()!= 1)
5719 	{
5720 	    m = priv->serverGeometry.x () + tx;
5721 
5722 	    if (m - priv->output.left < (int) screen->width () - vWidth)
5723 		wx = tx + vWidth;
5724 	    else if (m + priv->serverGeometry.width () + priv->output.right > vWidth)
5725 		wx = tx - vWidth;
5726 	}
5727 
5728 	if (screen->vpSize ().height () != 1)
5729 	{
5730 	    m = priv->serverGeometry.y () + ty;
5731 
5732 	    if (m - priv->output.top < (int) screen->height () - vHeight)
5733 		wy = ty + vHeight;
5734 	    else if (m + priv->serverGeometry.height () + priv->output.bottom > vHeight)
5735 		wy = ty - vHeight;
5736 	}
5737 
5738 	if (priv->saveMask & CWX)
5739 	    priv->saveWc.x += wx;
5740 
5741 	if (priv->saveMask & CWY)
5742 	    priv->saveWc.y += wy;
5743 
5744 	xwc.x = serverGeometry ().x () + wx;
5745 	xwc.y = serverGeometry ().y () + wy;
5746 
5747 	configureXWindow (valueMask, &xwc);
5748     }
5749 }
5750 
5751 const char *
5752 CompWindow::startupId () const
5753 {
5754      return priv->startupId;
5755 }
5756 
5757 void
5758 PrivateWindow::applyStartupProperties (CompStartupSequence *s)
5759 {
5760     int workspace;
5761 
5762     priv->initialViewport.setX (s->viewportX);
5763     priv->initialViewport.setY (s->viewportY);
5764 
5765     workspace = sn_startup_sequence_get_workspace (s->sequence);
5766     if (workspace >= 0)
5767 	window->setDesktop (workspace);
5768 
5769     priv->initialTimestamp    =
5770 	sn_startup_sequence_get_timestamp (s->sequence);
5771     priv->initialTimestampSet = true;
5772 }
5773 
5774 unsigned int
5775 CompWindow::desktop () const
5776 {
5777     return priv->desktop;
5778 }
5779 
5780 Window
5781 CompWindow::clientLeader (bool checkAncestor) const
5782 {
5783     if (priv->clientLeader)
5784 	return priv->clientLeader;
5785 
5786     if (checkAncestor)
5787 	return priv->getClientLeaderOfAncestor ();
5788 
5789     return None;
5790 }
5791 
5792 Window
5793 CompWindow::transientFor () const
5794 {
5795     return priv->transientFor;
5796 }
5797 
5798 int
5799 CompWindow::pendingUnmaps () const
5800 {
5801     return priv->pendingUnmaps;
5802 }
5803 
5804 bool
5805 CompWindow::minimized () const
5806 {
5807     WRAPABLE_HND_FUNCTN_RETURN (bool, minimized);
5808     return priv->minimized;
5809 }
5810 
5811 bool
5812 CompWindow::placed () const
5813 {
5814     return priv->placed;
5815 }
5816 
5817 bool
5818 CompWindow::shaded () const
5819 {
5820     return priv->shaded;
5821 }
5822 
5823 const CompWindowExtents &
5824 CompWindow::border () const
5825 {
5826     return priv->border;
5827 }
5828 
5829 const CompWindowExtents &
5830 CompWindow::input () const
5831 {
5832     return priv->serverInput;
5833 }
5834 
5835 const CompWindowExtents &
5836 CompWindow::output () const
5837 {
5838     return priv->output;
5839 }
5840 
5841 XSizeHints &
5842 CompWindow::sizeHints () const
5843 {
5844     return priv->sizeHints;
5845 }
5846 
5847 void
5848 PrivateWindow::updateMwmHints ()
5849 {
5850     screen->getMwmHints (priv->id, &priv->mwmFunc, &priv->mwmDecor);
5851     window->recalcActions ();
5852 }
5853 
5854 void
5855 PrivateWindow::updateStartupId ()
5856 {
5857     char *oldId = startupId;
5858     bool newId = true;
5859 
5860     startupId = getStartupId ();
5861 
5862     if (oldId && startupId)
5863     {
5864 	if (strcmp (startupId, oldId) == 0)
5865 	    newId = false;
5866     }
5867 
5868     if (managed && startupId && newId)
5869     {
5870 	Time       timestamp = 0;
5871 	CompPoint  vp, svp;
5872 	CompSize   size;
5873 	int        x, y;
5874 
5875 	initialTimestampSet = false;
5876 	screen->applyStartupProperties (window);
5877 
5878 	if (initialTimestampSet)
5879 	    timestamp = initialTimestamp;
5880 
5881 	/* as the viewport can't be transmitted via startup
5882 	   notification, assume the client changing the ID
5883 	   wanted to activate the window on the current viewport */
5884 
5885 	vp   = window->defaultViewport ();
5886 	svp  = screen->vp ();
5887 	size = *screen;
5888 
5889 	x = window->serverGeometry ().x () + (svp.x () - vp.x ()) * size.width ();
5890 	y = window->serverGeometry ().y () + (svp.y () - vp.y ()) * size.height ();
5891 	window->moveToViewportPosition (x, y, true);
5892 
5893 	if (allowWindowFocus (0, timestamp))
5894 	    window->activate ();
5895     }
5896     
5897     if (oldId)
5898 	free (oldId);
5899 }
5900 
5901 bool
5902 CompWindow::destroyed () const
5903 {
5904     return priv->destroyed;
5905 }
5906 
5907 bool
5908 CompWindow::invisible () const
5909 {
5910     return priv->invisible;
5911 }
5912 
5913 XSyncAlarm
5914 CompWindow::syncAlarm () const
5915 {
5916     return priv->syncAlarm;
5917 }
5918 
5919 CompWindow *
5920 PrivateWindow::createCompWindow (Window aboveId, Window aboveServerId, XWindowAttributes &wa, Window id)
5921 {
5922     PrivateWindow* priv(new PrivateWindow ());
5923     priv->id = id;
5924     priv->serverId = id;
5925 
5926     CompWindow *fw = new CompWindow (aboveId, aboveServerId, wa, priv);
5927 
5928     return fw;
5929 }
5930 
5931 
5932 CompWindow::CompWindow (Window aboveId,
5933 			Window aboveServerId,
5934 			XWindowAttributes &wa,
5935 			PrivateWindow *priv) :
5936     PluginClassStorage (windowPluginClassIndices),
5937     priv (priv)
5938 {
5939     StackDebugger *dbg = StackDebugger::Default ();
5940 
5941     // TODO: Reparent first!
5942 
5943     priv->window = this;
5944 
5945     screen->insertWindow (this, aboveId);
5946     screen->insertServerWindow (this, aboveServerId);
5947 
5948     /* We must immediately insert the window into the debugging
5949      * stack */
5950     if (dbg)
5951 	dbg->overrideRedirectRestack (priv->id, aboveId);
5952 
5953     priv->attrib = wa;
5954     priv->serverGeometry.set (priv->attrib.x, priv->attrib.y,
5955 			      priv->attrib.width, priv->attrib.height,
5956 			      priv->attrib.border_width);
5957     priv->serverFrameGeometry = priv->frameGeometry = priv->syncGeometry
5958 	    = priv->geometry = priv->serverGeometry;
5959 
5960     priv->sizeHints.flags = 0;
5961 
5962     priv->recalcNormalHints ();
5963 
5964     priv->transientFor = None;
5965     priv->clientLeader = None;
5966 
5967     XSelectInput (screen->dpy (), priv->id,
5968 		  wa.your_event_mask |
5969 		  PropertyChangeMask |
5970 		  EnterWindowMask    |
5971 		  FocusChangeMask);
5972 
5973     priv->alpha     = (priv->attrib.depth == 32);
5974     priv->lastPong  = screen->lastPing ();
5975 
5976     if (screen->XShape ())
5977 	XShapeSelectInput (screen->dpy (), priv->id, ShapeNotifyMask);
5978 
5979     if (priv->attrib.c_class != InputOnly)
5980     {
5981 	priv->region = CompRegion (priv->serverGeometry);
5982 	priv->inputRegion = priv->region;
5983 
5984 	/* need to check for DisplayModal state on all windows */
5985 	priv->state = screen->getWindowState (priv->id);
5986 
5987 	priv->updateClassHints ();
5988     }
5989     else
5990     {
5991 	priv->attrib.map_state = IsUnmapped;
5992     }
5993 
5994     priv->wmType    = screen->getWindowType (priv->id);
5995     priv->protocols = screen->getProtocols (priv->id);
5996 
5997     if (!overrideRedirect ())
5998     {
5999 	priv->updateNormalHints ();
6000 	updateStruts ();
6001 	priv->updateWmHints ();
6002 	priv->updateTransientHint ();
6003 
6004 	priv->clientLeader = priv->getClientLeader ();
6005 	priv->startupId = priv->getStartupId ();
6006 
6007 	recalcType ();
6008 
6009 	screen->getMwmHints (priv->id, &priv->mwmFunc, &priv->mwmDecor);
6010 
6011 	if (!(priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask)))
6012 	{
6013 	    priv->desktop = screen->getWindowProp (priv->id, Atoms::winDesktop,
6014 					           priv->desktop);
6015 	    if (priv->desktop != 0xffffffff)
6016 	    {
6017 		if (priv->desktop >= screen->nDesktop ())
6018 		    priv->desktop = screen->currentDesktop ();
6019 	    }
6020 	}
6021     }
6022     else
6023     {
6024 	recalcType ();
6025     }
6026 
6027     if (priv->attrib.map_state == IsViewable)
6028     {
6029 	priv->placed = true;
6030 
6031 	if (!overrideRedirect ())
6032 	{
6033 	    // needs to happen right after maprequest
6034 	    if (!priv->serverFrame)
6035 		priv->reparent ();
6036 	    priv->managed = true;
6037 
6038 	    if (screen->getWmState (priv->id) == IconicState)
6039 	    {
6040 		if (priv->state & CompWindowStateShadedMask)
6041 		    priv->shaded = true;
6042 		else
6043 		    priv->minimized = true;
6044 	    }
6045 	    else
6046 	    {
6047 		if (priv->wmType & (CompWindowTypeDockMask |
6048 				 CompWindowTypeDesktopMask))
6049 		{
6050 		    setDesktop (0xffffffff);
6051 		}
6052 		else
6053 		{
6054 		    if (priv->desktop != 0xffffffff)
6055 			priv->desktop = screen->currentDesktop ();
6056 
6057 		    screen->setWindowProp (priv->id, Atoms::winDesktop,
6058 				           priv->desktop);
6059 		}
6060 	    }
6061 	}
6062 
6063 	priv->attrib.map_state = IsUnmapped;
6064 	priv->pendingMaps++;
6065 
6066 	map ();
6067 
6068 	updateAttributes (CompStackingUpdateModeNormal);
6069 
6070 	if (priv->minimized || priv->inShowDesktopMode ||
6071 	    priv->hidden || priv->shaded)
6072 	{
6073 	    priv->state |= CompWindowStateHiddenMask;
6074 
6075 	    priv->pendingUnmaps++;
6076 
6077 	    if (priv->serverFrame && !priv->shaded)
6078 		XUnmapWindow (screen->dpy (), priv->serverFrame);
6079 
6080 	    XUnmapWindow (screen->dpy (), priv->id);
6081 
6082 	    screen->setWindowState (priv->state, priv->id);
6083 	}
6084     }
6085     else if (!overrideRedirect ())
6086     {
6087 	if (screen->getWmState (priv->id) == IconicState)
6088 	{
6089 	    // before everything else in maprequest
6090 	    if (!priv->serverFrame)
6091 		priv->reparent ();
6092 	    priv->managed = true;
6093 	    priv->placed  = true;
6094 
6095 	    if (priv->state & CompWindowStateHiddenMask)
6096 	    {
6097 		if (priv->state & CompWindowStateShadedMask)
6098 		    priv->shaded = true;
6099 		else
6100 		    priv->minimized = true;
6101 	    }
6102 	}
6103     }
6104 
6105     /* TODO: bailout properly when objectInitPlugins fails */
6106     bool init_succeeded = CompPlugin::windowInitPlugins (this);
6107     assert (init_succeeded);
6108     if (!init_succeeded)
6109       return;
6110 
6111     recalcActions ();
6112     priv->updateIconGeometry ();
6113 
6114     if (priv->shaded)
6115 	priv->updateFrameWindow ();
6116 
6117     if (priv->attrib.map_state == IsViewable)
6118     {
6119 	priv->invisible = priv->isInvisible ();
6120     }
6121 }
6122 
6123 CompWindow::~CompWindow ()
6124 {
6125     if (priv->serverFrame)
6126 	priv->unreparent ();
6127 
6128     /* Update the references of other windows
6129      * pending destroy if this was a sibling
6130      * of one of those */
6131 
6132     screen->destroyedWindows().remove (this);
6133 
6134     foreach (CompWindow *dw, screen->destroyedWindows())
6135     {
6136 	if (dw->next == this)
6137 	    dw->next = this->next;
6138 	if (dw->prev == this)
6139 	    dw->prev = this->prev;
6140 
6141 	if (dw->serverNext == this)
6142 	    dw->serverNext = this->serverNext;
6143 	if (dw->serverPrev == this)
6144 	    dw->serverPrev = this->serverPrev;
6145     }
6146 
6147     if (!priv->destroyed)
6148     {
6149 	StackDebugger *dbg = StackDebugger::Default ();
6150 
6151 	screen->unhookWindow (this);
6152 	screen->unhookServerWindow (this);
6153 
6154 	/* We must immediately insert the window into the debugging
6155 	 * stack */
6156 	if (dbg)
6157 	    dbg->removeServerWindow (id ());
6158 
6159 	/* restore saved geometry and map if hidden */
6160 	if (!priv->attrib.override_redirect)
6161 	{
6162 	    if (priv->saveMask)
6163 		XConfigureWindow (screen->dpy (), priv->id,
6164 				  priv->saveMask, &priv->saveWc);
6165 
6166 	    if (!priv->hidden)
6167 	    {
6168 		if (priv->state & CompWindowStateHiddenMask)
6169 		    XMapWindow (screen->dpy (), priv->id);
6170 	    }
6171 	}
6172 
6173 	if (screen->XShape ())
6174 	    XShapeSelectInput (screen->dpy (), priv->id, NoEventMask);
6175 
6176 	if (screen->grabWindowIsNot(priv->id))
6177 	    XSelectInput (screen->dpy (), priv->id, NoEventMask);
6178 
6179 	XUngrabButton (screen->dpy (), AnyButton, AnyModifier, priv->id);
6180     }
6181 
6182 
6183     if (priv->attrib.map_state == IsViewable)
6184     {
6185 	if (priv->type == CompWindowTypeDesktopMask)
6186 	    screen->decrementDesktopWindowCount();
6187 
6188 	if (priv->destroyed && priv->struts)
6189 	    screen->updateWorkarea ();
6190     }
6191 
6192     if (priv->destroyed)
6193 	screen->updateClientList ();
6194 
6195     CompPlugin::windowFiniPlugins (this);
6196 
6197     delete priv;
6198 }
6199 
6200 PrivateWindow::PrivateWindow () :
6201     priv (this),
6202     refcnt (1),
6203     id (None),
6204     serverFrame (None),
6205     frame (None),
6206     wrapper (None),
6207     mapNum (0),
6208     activeNum (0),
6209     transientFor (None),
6210     clientLeader (None),
6211     hints (NULL),
6212     inputHint (true),
6213     alpha (false),
6214     region (),
6215     wmType (0),
6216     type (CompWindowTypeUnknownMask),
6217     state (0),
6218     actions (0),
6219     protocols (0),
6220     mwmDecor (MwmDecorAll),
6221     mwmFunc (MwmFuncAll),
6222     invisible (true),
6223     destroyed (false),
6224     managed (false),
6225     unmanaging (false),
6226     destroyRefCnt (1),
6227     unmapRefCnt (1),
6228 
6229     initialViewport (0, 0),
6230 
6231     initialTimestamp (0),
6232     initialTimestampSet (false),
6233 
6234     fullscreenMonitorsSet (false),
6235 
6236     placed (false),
6237     minimized (false),
6238     inShowDesktopMode (false),
6239     shaded (false),
6240     hidden (false),
6241     grabbed (false),
6242 
6243     desktop (0),
6244 
6245     pendingUnmaps (0),
6246     pendingMaps (0),
6247     pendingConfigures (screen->dpy ()),
6248     receivedMapRequestAndAwaitingMap (false),
6249 
6250     startupId (0),
6251     resName (0),
6252     resClass (0),
6253 
6254     group (0),
6255 
6256     lastPong (0),
6257     alive (true),
6258 
6259     struts (0),
6260 
6261     icons (0),
6262     noIcons (false),
6263 
6264     saveMask (0),
6265     syncCounter (0),
6266     syncAlarm (None),
6267     syncWaitTimer (),
6268 
6269     syncWait (false),
6270     closeRequests (false),
6271     lastCloseRequestTime (0)
6272 {
6273     input.left   = 0;
6274     input.right  = 0;
6275     input.top    = 0;
6276     input.bottom = 0;
6277 
6278     serverInput.left   = 0;
6279     serverInput.right  = 0;
6280     serverInput.top    = 0;
6281     serverInput.bottom = 0;
6282 
6283     border.top    = 0;
6284     border.bottom = 0;
6285     border.left   = 0;
6286     border.right  = 0;
6287 
6288     output.left   = 0;
6289     output.right  = 0;
6290     output.top    = 0;
6291     output.bottom = 0;
6292 
6293     syncWaitTimer.setTimes (1000, 1200);
6294     syncWaitTimer.setCallback (boost::bind (&PrivateWindow::handleSyncAlarm,
6295 					    this));
6296 }
6297 
6298 PrivateWindow::~PrivateWindow ()
6299 {
6300      if (syncAlarm)
6301 	XSyncDestroyAlarm (screen->dpy (), syncAlarm);
6302 
6303     syncWaitTimer.stop ();
6304 
6305     if (serverFrame)
6306 	XDestroyWindow (screen->dpy (), serverFrame);
6307     else if (frame)
6308 	XDestroyWindow (screen->dpy (), frame);
6309 
6310     if (struts)
6311 	free (struts);
6312 
6313     if (hints)
6314 	XFree (hints);
6315 
6316     if (icons.size ())
6317 	freeIcons ();
6318 
6319     if (startupId)
6320 	free (startupId);
6321 
6322     if (resName)
6323 	free (resName);
6324 
6325     if (resClass)
6326 	free (resClass);
6327 }
6328 
6329 bool
6330 CompWindow::syncWait () const
6331 {
6332     return priv->syncWait;
6333 }
6334 
6335 bool
6336 CompWindow::alpha () const
6337 {
6338     WRAPABLE_HND_FUNCTN_RETURN (bool, alpha);
6339 
6340     return priv->alpha;
6341 }
6342 
6343 bool
6344 CompWindow::overrideRedirect () const
6345 {
6346     return priv->attrib.override_redirect;
6347 }
6348 
6349 void
6350 PrivateWindow::setOverrideRedirect (bool overrideRedirect)
6351 {
6352     if (overrideRedirect == window->overrideRedirect ())
6353 	return;
6354 
6355     priv->attrib.override_redirect = overrideRedirect ? 1 : 0;
6356     window->recalcType ();
6357     window->recalcActions ();
6358 
6359     screen->matchPropertyChanged (window);
6360 }
6361 
6362 bool
6363 CompWindow::isMapped () const
6364 {
6365     return priv->mapNum > 0;
6366 }
6367 
6368 bool
6369 CompWindow::isViewable () const
6370 {
6371     return (priv->attrib.map_state == IsViewable);
6372 }
6373 
6374 bool
6375 CompWindow::isFocussable () const
6376 {
6377     WRAPABLE_HND_FUNCTN_RETURN (bool, isFocussable);
6378 
6379     if (priv->inputHint)
6380 	return true;
6381 
6382     if (priv->protocols & CompWindowProtocolTakeFocusMask)
6383 	return true;
6384 
6385     return false;
6386 }
6387 
6388 int
6389 CompWindow::windowClass () const
6390 {
6391     return priv->attrib.c_class;
6392 }
6393 
6394 unsigned int
6395 CompWindow::depth () const
6396 {
6397     return priv->attrib.depth;
6398 }
6399 
6400 bool
6401 CompWindow::alive () const
6402 {
6403     return priv->alive;
6404 }
6405 
6406 unsigned int
6407 CompWindow::mwmDecor () const
6408 {
6409     return priv->mwmDecor;
6410 }
6411 
6412 unsigned int
6413 CompWindow::mwmFunc () const
6414 {
6415     return priv->mwmFunc;
6416 }
6417 
6418 /* TODO: This function should be able to check the XShape event
6419  * kind and only get/set shape rectangles for either ShapeInput
6420  * or ShapeBounding, but not both at the same time
6421  */
6422 
6423 void
6424 CompWindow::updateFrameRegion ()
6425 {
6426     if (priv->serverFrame)
6427     {
6428 	CompRect   r;
6429 	int        x, y;
6430 
6431 	priv->frameRegion = emptyRegion;
6432 
6433 	updateFrameRegion (priv->frameRegion);
6434 
6435 	if (!shaded ())
6436 	{
6437 	    r = priv->region.boundingRect ();
6438 	    priv->frameRegion -= r;
6439 
6440 	    r.setGeometry (r.x1 () - priv->serverInput.left,
6441 			r.y1 () - priv->serverInput.top,
6442 			r.width  () + priv->serverInput.right + priv->serverInput.left,
6443 			r.height () + priv->serverInput.bottom + priv->serverInput.top);
6444 
6445 	    priv->frameRegion &= CompRegion (r);
6446 	}
6447 
6448 	x = priv->serverGeometry.x () - priv->serverInput.left;
6449 	y = priv->serverGeometry.y () - priv->serverInput.top;
6450 
6451 	XShapeCombineRegion (screen->dpy (), priv->serverFrame,
6452 			     ShapeBounding, -x, -y,
6453 			     priv->frameRegion.united (priv->region).handle (),
6454 			     ShapeSet);
6455 
6456 	XShapeCombineRegion (screen->dpy (), priv->serverFrame,
6457 			     ShapeInput, -x, -y,
6458 			     priv->frameRegion.united (priv->inputRegion).handle (),
6459 			     ShapeSet);
6460     }
6461 }
6462 
6463 void
6464 CompWindow::setWindowFrameExtents (const CompWindowExtents *b,
6465 				   const CompWindowExtents *i)
6466 {
6467     /* override redirect windows can't have frame extents */
6468     if (priv->attrib.override_redirect)
6469 	return;
6470 
6471     /* Input extents are used for frame size,
6472      * Border extents used for placement.
6473      */
6474 
6475     if (!i)
6476 	i = b;
6477 
6478     if (priv->serverInput.left   != i->left ||
6479 	priv->serverInput.right  != i->right ||
6480 	priv->serverInput.top    != i->top ||
6481 	priv->serverInput.bottom != i->bottom ||
6482 	priv->border.left   != b->left ||
6483 	priv->border.right  != b->right ||
6484 	priv->border.top    != b->top ||
6485 	priv->border.bottom != b->bottom)
6486     {
6487 	priv->serverInput = *i;
6488 	priv->border = *b;
6489 
6490 	recalcActions ();
6491 
6492 	priv->updateSize ();
6493 	priv->updateFrameWindow ();
6494 
6495 	/* Always send a moveNotify
6496 	 * whenever the frame extents update
6497 	 * so that plugins can re-position appropriately */
6498 	moveNotify (0, 0, true);
6499     }
6500 
6501     /* Use b for _NET_WM_FRAME_EXTENTS here because
6502      * that is the representation of the actual decoration
6503      * around the window that the user sees and should
6504      * be used for placement and such */
6505 
6506     /* Also update frame extents regardless of whether or not
6507      * the frame extents actually changed, eg, a plugin could
6508      * suggest that a window has no frame extents and that it
6509      * might later get frame extents - this is mandatory if we
6510      * say that we support it, so set them
6511      * additionaly some applications might request frame extents
6512      * and we must respond by setting the property - ideally
6513      * this should only ever be done when some plugin actually
6514      * need to change the frame extents or the applications
6515      * requested it */
6516 
6517     unsigned long data[4];
6518 
6519     data[0] = b->left;
6520     data[1] = b->right;
6521     data[2] = b->top;
6522     data[3] = b->bottom;
6523 
6524     XChangeProperty (screen->dpy (), priv->id,
6525 		     Atoms::frameExtents,
6526 		     XA_CARDINAL, 32, PropModeReplace,
6527 		     (unsigned char *) data, 4);
6528 }
6529 
6530 bool
6531 CompWindow::hasUnmapReference () const
6532 {
6533     return (priv && priv->unmapRefCnt > 1);
6534 }
6535 
6536 void
6537 CompWindow::updateFrameRegion (CompRegion& region)
6538     WRAPABLE_HND_FUNCTN (updateFrameRegion, region)
6539 
6540 bool
6541 PrivateWindow::reparent ()
6542 {
6543     XSetWindowAttributes attr;
6544     XWindowAttributes    wa;
6545     XWindowChanges       xwc = XWINDOWCHANGES_INIT;
6546     int                  mask;
6547     unsigned int         nchildren;
6548     Window		 *children, root_return, parent_return;
6549     Display              *dpy = screen->dpy ();
6550     Visual		 *visual = DefaultVisual (screen->dpy (),
6551 						  screen->screenNum ());
6552     Colormap		 cmap = DefaultColormap (screen->dpy (),
6553 						 screen->screenNum ());
6554 
6555     if (serverFrame)
6556 	return false;
6557 
6558     XSync (dpy, false);
6559     XGrabServer (dpy);
6560 
6561     if (!XGetWindowAttributes (dpy, id, &wa))
6562     {
6563 	XUngrabServer (dpy);
6564 	XSync (dpy, false);
6565 	return false;
6566     }
6567 
6568     if (wa.override_redirect)
6569 	return false;
6570 
6571     /* Don't ever reparent windows which have ended up
6572      * reparented themselves on the server side but not
6573      * on the client side */
6574 
6575     XQueryTree (dpy, id, &root_return, &parent_return, &children, &nchildren);
6576 
6577     if (parent_return != root_return)
6578     {
6579 	XFree (children);
6580 	XUngrabServer (dpy);
6581 	XSync (dpy, false);
6582 	return false;
6583     }
6584 
6585     XFree (children);
6586 
6587     XQueryTree (dpy, root_return, &root_return, &parent_return, &children, &nchildren);
6588 
6589     XChangeSaveSet (dpy, id, SetModeInsert);
6590 
6591     /* Force border width to 0 */
6592     xwc.border_width = 0;
6593     XConfigureWindow (dpy, id, CWBorderWidth, &xwc);
6594 
6595     priv->serverGeometry.setBorder (0);
6596 
6597     mask = CWBorderPixel | CWColormap | CWBackPixmap | CWOverrideRedirect;
6598 
6599     if (wa.depth == 32)
6600     {
6601 	cmap = wa.colormap;
6602 	visual = wa.visual;
6603     }
6604 
6605     attr.background_pixmap = None;
6606     attr.border_pixel      = 0;
6607     attr.colormap          = cmap;
6608     attr.override_redirect = true;
6609 
6610     /* We need to know when the frame window is created
6611      * but that's all */
6612     XSelectInput (dpy, screen->root (), SubstructureNotifyMask);
6613 
6614     /* Awaiting a new frame to be given to us */
6615     frame = None;
6616     serverFrame = XCreateWindow (dpy, screen->root (), 0, 0,
6617 				 wa.width, wa.height, 0, wa.depth,
6618 				 InputOutput, visual, mask, &attr);
6619 
6620     /* Do not get any events from here on */
6621     XSelectInput (dpy, screen->root (), NoEventMask);
6622 
6623     wrapper = XCreateWindow (dpy, serverFrame, 0, 0,
6624 			    wa.width, wa.height, 0, wa.depth,
6625 			    InputOutput, visual, mask, &attr);
6626 
6627     xwc.stack_mode = Above;
6628 
6629     /* Look for the client in the current server side stacking
6630      * order and put the frame above what the client is above
6631      */
6632     if (nchildren &&
6633 	children[0] == id)
6634     {
6635 	/* client at the bottom */
6636 	xwc.stack_mode = Below;
6637 	xwc.sibling = id;
6638     }
6639     else
6640     {
6641 	for (unsigned int i = 0; i < nchildren; i++)
6642 	{
6643 	    if (i < nchildren - 1)
6644 	    {
6645 		if (children[i + 1] == id)
6646 		{
6647 		    xwc.sibling = children[i];
6648 		    break;
6649 		}
6650 	    }
6651 	    else /* client on top */
6652 		xwc.sibling = children[i];
6653 	}
6654     }
6655 
6656     XFree (children);
6657 
6658     /* Make sure the frame is underneath the client */
6659     XConfigureWindow (dpy, serverFrame, CWSibling | CWStackMode, &xwc);
6660 
6661     /* Wait for the restacking to finish */
6662     XSync (dpy, false);
6663 
6664     /* Always need to have the wrapper window mapped */
6665     XMapWindow (dpy, wrapper);
6666 
6667     /* Reparent the client into the wrapper window */
6668     XReparentWindow (dpy, id, wrapper, 0, 0);
6669 
6670     /* Restore events */
6671     attr.event_mask = wa.your_event_mask;
6672 
6673     /* We don't care about client events on the frame, and listening for them
6674      * will probably end up fighting the client anyways, so disable them */
6675 
6676     attr.do_not_propagate_mask = KeyPressMask | KeyReleaseMask |
6677 				 ButtonPressMask | ButtonReleaseMask |
6678 				 EnterWindowMask | LeaveWindowMask |
6679 				 PointerMotionMask | PointerMotionHintMask |
6680 				 Button1MotionMask | Button2MotionMask |
6681 				 Button3MotionMask | Button4MotionMask |
6682 				 Button5MotionMask | ButtonMotionMask |
6683 				 KeymapStateMask | ExposureMask |
6684 				 VisibilityChangeMask | StructureNotifyMask |
6685 				 ResizeRedirectMask | SubstructureNotifyMask |
6686 				 SubstructureRedirectMask | FocusChangeMask |
6687 				 PropertyChangeMask | ColormapChangeMask |
6688 				 OwnerGrabButtonMask;
6689 
6690     XChangeWindowAttributes (dpy, id, CWEventMask | CWDontPropagate, &attr);
6691 
6692     if (wa.map_state == IsViewable || shaded)
6693 	XMapWindow (dpy, serverFrame);
6694 
6695     attr.event_mask = SubstructureRedirectMask |
6696 		      SubstructureNotifyMask | EnterWindowMask |
6697 		      LeaveWindowMask;
6698 
6699     serverFrameGeometry = serverGeometry;
6700 
6701     XMoveResizeWindow (dpy, serverFrame, serverFrameGeometry.x (), serverFrameGeometry.y (),
6702 		       serverFrameGeometry.width (), serverFrameGeometry.height ());
6703 
6704     XChangeWindowAttributes (dpy, serverFrame, CWEventMask, &attr);
6705     XChangeWindowAttributes (dpy, wrapper, CWEventMask, &attr);
6706 
6707     XSelectInput (dpy, screen->root (),
6708 		  SubstructureRedirectMask |
6709 		  SubstructureNotifyMask   |
6710 		  StructureNotifyMask      |
6711 		  PropertyChangeMask       |
6712 		  LeaveWindowMask          |
6713 		  EnterWindowMask          |
6714 		  KeyPressMask             |
6715 		  KeyReleaseMask           |
6716 		  ButtonPressMask          |
6717 		  ButtonReleaseMask        |
6718 		  FocusChangeMask          |
6719 		  ExposureMask);
6720 
6721     XUngrabServer (dpy);
6722     XSync (dpy, false);
6723 
6724     window->windowNotify (CompWindowNotifyReparent);
6725 
6726     return true;
6727 }
6728 
6729 void
6730 PrivateWindow::unreparent ()
6731 {
6732     Display        	 *dpy = screen->dpy ();
6733     XEvent         	 e;
6734     bool           	 alive = true;
6735     XWindowChanges 	 xwc = XWINDOWCHANGES_INIT;
6736     unsigned int         nchildren;
6737     Window		 *children = NULL, root_return, parent_return;
6738     XWindowAttributes	 wa;
6739     StackDebugger        *dbg = StackDebugger::Default ();
6740 
6741     if (!serverFrame)
6742 	return;
6743 
6744     XSync (dpy, false);
6745 
6746     if (XCheckTypedWindowEvent (dpy, id, DestroyNotify, &e))
6747     {
6748         XPutBackEvent (dpy, &e);
6749         alive = false;
6750     }
6751     else
6752     {
6753 	if (!XGetWindowAttributes (dpy, id, &wa))
6754 	    alive = false;
6755     }
6756 
6757     /* Also don't reparent back into root windows that have ended up
6758      * reparented into other windows (and as such we are unmanaging them) */
6759 
6760     if (alive)
6761     {
6762 	XQueryTree (dpy, id, &root_return, &parent_return, &children, &nchildren);
6763 
6764 	if (parent_return != wrapper)
6765 	    alive = false;
6766     }
6767 
6768     if ((!destroyed) && alive)
6769     {
6770 	XGrabServer (dpy);
6771 
6772         XChangeSaveSet (dpy, id, SetModeDelete);
6773 	XSelectInput (dpy, serverFrame, NoEventMask);
6774 	XSelectInput (dpy, wrapper, NoEventMask);
6775 	XSelectInput (dpy, id, NoEventMask);
6776 	XSelectInput (dpy, screen->root (), NoEventMask);
6777 	XReparentWindow (dpy, id, screen->root (), 0, 0);
6778 
6779 	/* Wait for the reparent to finish */
6780 	XSync (dpy, false);
6781 
6782 	xwc.x = serverGeometry.xMinusBorder ();
6783 	xwc.y = serverGeometry.yMinusBorder ();
6784 	xwc.width = serverGeometry.widthIncBorders ();
6785 	xwc.height = serverGeometry.heightIncBorders ();
6786 
6787 	XConfigureWindow (dpy, serverFrame, CWX | CWY | CWWidth | CWHeight, &xwc);
6788 
6789 
6790 	xwc.stack_mode = Below;
6791 	xwc.sibling    = serverFrame;
6792 	XConfigureWindow (dpy, id, CWSibling | CWStackMode, &xwc);
6793 
6794 	/* Wait for the window to be restacked */
6795 	XSync (dpy, false);
6796 
6797 	XUnmapWindow (dpy, serverFrame);
6798 
6799 	XSelectInput (dpy, id, wa.your_event_mask);
6800 
6801 	XSelectInput (dpy, screen->root (),
6802 		  SubstructureRedirectMask |
6803 		  SubstructureNotifyMask   |
6804 		  StructureNotifyMask      |
6805 		  PropertyChangeMask       |
6806 		  LeaveWindowMask          |
6807 		  EnterWindowMask          |
6808 		  KeyPressMask             |
6809 		  KeyReleaseMask           |
6810 		  ButtonPressMask          |
6811 		  ButtonReleaseMask        |
6812 		  FocusChangeMask          |
6813 		  ExposureMask);
6814 
6815 	XUngrabServer (dpy);
6816 	XSync (dpy, false);
6817 
6818 	XMoveWindow (dpy, id, serverGeometry.x (), serverGeometry.y ());
6819     }
6820 
6821     if (children)
6822 	XFree (children);
6823 
6824     if (dbg)
6825 	dbg->addDestroyedFrame (serverFrame);
6826 
6827     /* This is where things get tricky ... it is possible
6828      * to receive a ConfigureNotify relative to a frame window
6829      * for a destroyed window in case we process a ConfigureRequest
6830      * for the destroyed window and then a DestroyNotify for it directly
6831      * afterwards. In that case, we will receive the ConfigureNotify
6832      * for the XConfigureWindow request we made relative to that frame
6833      * window. Because of this, we must keep the frame window in the stack
6834      * as a new toplevel window so that the ConfigureNotify will be processed
6835      * properly until it too receives a DestroyNotify */
6836 
6837     if (serverFrame)
6838     {
6839 	XWindowAttributes attrib;
6840 
6841 	/* It's possible that the frame window was already destroyed because
6842 	 * the client was unreparented before it was destroyed (eg
6843 	 * UnmapNotify before DestroyNotify). In that case the frame window
6844 	 * is going to be an invalid window but since we haven't received
6845 	 * a DestroyNotify for it yet, it is possible that restacking
6846 	 * operations could occurr relative to it so we need to hold it
6847 	 * in the stack for now. Ensure that it is marked override redirect */
6848 	XGetWindowAttributes (screen->dpy (), serverFrame, &attrib);
6849 
6850 	/* Put the frame window "above" the client window
6851 	 * in the stack */
6852 	PrivateWindow::createCompWindow (id, id, attrib, serverFrame);
6853     }
6854 
6855     /* Issue a DestroyNotify */
6856     XDestroyWindow (screen->dpy (), serverFrame);
6857     XDestroyWindow (screen->dpy (), wrapper);
6858 
6859     /* This window is no longer "managed" in the
6860      * reparenting sense so clear its pending event
6861      * queue ... though maybe in future it would
6862      * be better to bookeep these events too and
6863      * handle the ReparentNotify */
6864     pendingConfigures.clear ();
6865 
6866     frame = None;
6867     wrapper = None;
6868     serverFrame = None;
6869 
6870     // Finally, (i.e. after updating state) notify the change
6871     window->windowNotify (CompWindowNotifyUnreparent);
6872 }