1 /*
   2  * Copyright �� 2005 Novell, Inc.
   3  *
   4  * Permission to use, copy, modify, distribute, and sell this software
   5  * and its documentation for any purpose is hereby granted without
   6  * fee, provided that the above copyright notice appear in all copies
   7  * and that both that copyright notice and this permission notice
   8  * appear in supporting documentation, and that the name of
   9  * Novell, Inc. not be used in advertising or publicity pertaining to
  10  * distribution of the software without specific, written prior permission.
  11  * Novell, Inc. makes no representations about the suitability of this
  12  * software for any purpose. It is provided "as is" without express or
  13  * implied warranty.
  14  *
  15  * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
  17  * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
  19  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  20  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  21  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22  *
  23  * Author: David Reveman <davidr@novell.com>
  24  */
  25 
  26 #ifdef HAVE_CONFIG_H
  27 #  include <config.h>
  28 #endif
  29 
  30 #include <stdio.h>
  31 #include <stdlib.h>
  32 #include <stdarg.h>
  33 #include <math.h>
  34 #include <dlfcn.h>
  35 #include <string.h>
  36 #include <sys/types.h>
  37 #include <sys/time.h>
  38 #include <unistd.h>
  39 #include <assert.h>
  40 #include <limits.h>
  41 #include <poll.h>
  42 #include <libgen.h>
  43 #include <algorithm>
  44 
  45 #include <boost/bind.hpp>
  46 #include <boost/foreach.hpp>
  47 #define foreach BOOST_FOREACH
  48 
  49 #include <X11/Xlib.h>
  50 #include <X11/Xatom.h>
  51 #include <X11/Xproto.h>
  52 #include <X11/extensions/Xrandr.h>
  53 #include <X11/extensions/shape.h>
  54 #include <X11/cursorfont.h>
  55 
  56 #include <core/global.h>
  57 #include <core/screen.h>
  58 #include <core/icon.h>
  59 #include <core/atoms.h>
  60 #include "privatescreen.h"
  61 #include "privatewindow.h"
  62 #include "privateaction.h"
  63 #include "privatestackdebugger.h"
  64 
  65 template class WrapableInterface<CompScreen, ScreenInterface>;
  66 
  67 CompOutput *targetOutput;
  68 
  69 int lastPointerX = 0;
  70 int lastPointerY = 0;
  71 unsigned int lastPointerMods = 0;
  72 int pointerX     = 0;
  73 int pointerY     = 0;
  74 unsigned int pointerMods = 0;
  75 
  76 namespace
  77 {
  78 bool inHandleEvent = false;
  79 
  80 bool screenInitalized = false;
  81 }
  82 
  83 #define MwmHintsFunctions   (1L << 0)
  84 #define MwmHintsDecorations (1L << 1)
  85 static const unsigned short PropMotifWmHintElements = 3;
  86 
  87 typedef struct {
  88     unsigned long flags;
  89     unsigned long functions;
  90     unsigned long decorations;
  91 } MwmHints;
  92 
  93 namespace cps = compiz::private_screen;
  94 namespace ca = compiz::actions;
  95 
  96 
  97 
  98 CompScreen *screen;
  99 ModifierHandler *modHandler;
 100 
 101 PluginClassStorage::Indices screenPluginClassIndices (0);
 102 
 103 void CompScreenImpl::sizePluginClasses(unsigned int size)
 104 {
 105     if(size != pluginClasses.size ())
 106  	pluginClasses.resize (size);
 107 }
 108 
 109 void CompScreenImpl::setWindowState (unsigned int state, Window id)
 110 {
 111     privateScreen.setWindowState (state, id);
 112 }
 113 
 114 void CompScreenImpl::addToDestroyedWindows(CompWindow * cw)
 115 {
 116     windowManager.addToDestroyedWindows(cw);
 117 }
 118 
 119 void CompScreenImpl::processEvents () { privateScreen.processEvents (); }
 120 
 121 unsigned int
 122 CompScreen::allocPluginClassIndex ()
 123 {
 124     unsigned int i = PluginClassStorage::allocatePluginClassIndex (screenPluginClassIndices);
 125 
 126     sizePluginClasses(screenPluginClassIndices.size());
 127 
 128     return i;
 129 }
 130 
 131 void
 132 CompScreen::freePluginClassIndex (unsigned int index)
 133 {
 134     PluginClassStorage::freePluginClassIndex (screenPluginClassIndices, index);
 135 
 136     sizePluginClasses(screenPluginClassIndices.size());
 137 }
 138 
 139 void
 140 cps::EventManager::handleSignal (int signum)
 141 {
 142     switch (signum)
 143     {
 144 	case SIGINT:
 145 	case SIGTERM:
 146 	    mainloop->quit ();
 147 	    break;
 148 	case SIGHUP:
 149 	    restartSignal = true;
 150 	    mainloop->quit ();
 151 	    break;
 152 	default:
 153 	    break;
 154     }
 155 
 156     mainloop->quit ();
 157 }
 158 
 159 void
 160 CompScreenImpl::eventLoop ()
 161 {
 162     privateScreen.eventManager.startEventLoop (dpy());
 163 }
 164 
 165 void
 166 cps::EventManager::startEventLoop(Display* dpy)
 167 {
 168     source = CompEventSource::create ();
 169     timeout = CompTimeoutSource::create (ctx);
 170 
 171     source->attach (ctx);
 172 
 173     XFlush (dpy);
 174 
 175     mainloop->run();
 176 }
 177 
 178 CompFileWatchHandle
 179 CompScreenImpl::addFileWatch (const char        *path,
 180 			  int               mask,
 181 			  FileWatchCallBack callBack)
 182 {
 183     CompFileWatch *fileWatch = privateScreen.eventManager.addFileWatch (path, mask, callBack);
 184 
 185     if (!fileWatch)
 186 	return 0;
 187 
 188     fileWatchAdded (fileWatch);
 189 
 190     return fileWatch->handle;
 191 }
 192 
 193 CompFileWatch*
 194 cps::EventManager::addFileWatch (
 195     const char        *path,
 196     int               mask,
 197     FileWatchCallBack callBack)
 198 {
 199     CompFileWatch *fw = new CompFileWatch ();
 200     if (!fw)
 201 	return 0;
 202 
 203     fw->path	= path;
 204     fw->mask	= mask;
 205     fw->callBack = callBack;
 206     fw->handle   = lastFileWatchHandle++;
 207 
 208     if (lastFileWatchHandle == MAXSHORT)
 209 	lastFileWatchHandle = 1;
 210 
 211     fileWatch.push_front (fw);
 212 
 213     return fw;
 214 }
 215 
 216 void
 217 CompScreenImpl::removeFileWatch (CompFileWatchHandle handle)
 218 {
 219     if (CompFileWatch* w = privateScreen.eventManager.removeFileWatch (handle))
 220     {
 221 	fileWatchRemoved (w);
 222 
 223 	delete w;
 224     }
 225 }
 226 
 227 CompFileWatch*
 228 cps::EventManager::removeFileWatch (CompFileWatchHandle handle)
 229 {
 230     std::list<CompFileWatch *>::iterator it;
 231 
 232     for (it = fileWatch.begin (); it != fileWatch.end (); ++it)
 233 	if ((*it)->handle == handle)
 234 	    break;
 235 
 236     if (it == fileWatch.end ())
 237 	return 0;
 238 
 239     CompFileWatch* w = (*it);
 240     fileWatch.erase (it);
 241 
 242     return w;
 243 }
 244 
 245 const CompFileWatchList &
 246 CompScreenImpl::getFileWatches () const
 247 {
 248     return privateScreen.eventManager.getFileWatches ();
 249 }
 250 
 251 const CompFileWatchList &
 252 cps::EventManager::getFileWatches () const
 253 {
 254     return fileWatch;
 255 }
 256 
 257 CompWatchFd::CompWatchFd (int		    fd,
 258 			  Glib::IOCondition events,
 259 			  FdWatchCallBack   callback) :
 260     Glib::IOSource (fd, events),
 261     mFd (fd),
 262     mCallBack (callback),
 263     mForceFail (false),
 264     mExecuting (false)
 265 {
 266     connect (sigc::mem_fun <Glib::IOCondition, bool>
 267 	     (this, &CompWatchFd::internalCallback));
 268 }
 269 
 270 CompWatchFd::~CompWatchFd ()
 271 {
 272 }
 273 
 274 CompWatchFd *
 275 CompWatchFd::create (int               fd,
 276 		     Glib::IOCondition events,
 277 		     FdWatchCallBack   callback)
 278 {
 279     return new CompWatchFd (fd, events, callback);
 280 }
 281 
 282 CompWatchFdHandle
 283 CompScreenImpl::addWatchFd (int             fd,
 284 			short int       events,
 285 			FdWatchCallBack callBack)
 286 {
 287     return privateScreen.eventManager.addWatchFd (fd, events, callBack);
 288 }
 289 
 290 CompWatchFdHandle
 291 cps::EventManager::addWatchFd (int             fd,
 292 			short int       events,
 293 			FdWatchCallBack callBack)
 294 {
 295     Glib::IOCondition gEvents;
 296     
 297     memset (&gEvents, 0, sizeof (Glib::IOCondition));
 298 
 299     if (events & POLLIN)
 300 	gEvents |= Glib::IO_IN;
 301     if (events & POLLOUT)
 302 	gEvents |= Glib::IO_OUT;
 303     if (events & POLLPRI)
 304 	gEvents |= Glib::IO_PRI;
 305     if (events & POLLERR)
 306 	gEvents |= Glib::IO_ERR;
 307     if (events & POLLHUP)
 308 	gEvents |= Glib::IO_HUP;
 309 
 310     CompWatchFd *watchFd = CompWatchFd::create (fd, gEvents, callBack);
 311 
 312     watchFd->attach (ctx);
 313 
 314     if (!watchFd)
 315 	return 0;
 316     watchFd->mHandle   = lastWatchFdHandle++;
 317 
 318     if (lastWatchFdHandle == MAXSHORT)
 319 	lastWatchFdHandle = 1;
 320 
 321     watchFds.push_front (watchFd);
 322 
 323     return watchFd->mHandle;
 324 }
 325 
 326 void
 327 CompScreenImpl::removeWatchFd (CompWatchFdHandle handle)
 328 {
 329     privateScreen.eventManager.removeWatchFd (handle);
 330 }
 331 
 332 void
 333 cps::EventManager::removeWatchFd (CompWatchFdHandle handle)
 334 {
 335     std::list<CompWatchFd * >::iterator it;
 336     CompWatchFd *			w;
 337 
 338     for (it = watchFds.begin();
 339 	 it != watchFds.end (); ++it)
 340     {
 341 	if ((*it)->mHandle == handle)
 342 	    break;
 343     }
 344 
 345     if (it == watchFds.end ())
 346 	return;
 347 
 348     w = (*it);
 349 
 350     if (w->mExecuting)
 351     {
 352 	w->mForceFail = true;
 353 	return;
 354     }
 355 
 356     delete w;
 357     watchFds.erase (it);
 358 }
 359 
 360 void
 361 CompScreenImpl::storeValue (CompString key, CompPrivate value)
 362 {
 363     ValueHolder::Default ()->storeValue (key, value);
 364 }
 365 
 366 bool
 367 CompScreenImpl::hasValue (CompString key)
 368 {
 369     return ValueHolder::Default ()->hasValue (key);
 370 }
 371 
 372 CompPrivate
 373 CompScreenImpl::getValue (CompString key)
 374 {
 375     return ValueHolder::Default ()->getValue (key);
 376 }
 377 
 378 bool
 379 CompWatchFd::internalCallback (Glib::IOCondition events)
 380 {
 381     short int revents = 0;
 382 
 383     if (events & Glib::IO_IN)
 384 	revents |= POLLIN;
 385     if (events & Glib::IO_OUT)
 386 	revents |= POLLOUT;
 387     if (events & Glib::IO_PRI)
 388 	revents |= POLLPRI;
 389     if (events & Glib::IO_ERR)
 390 	revents |= POLLERR;
 391     if (events & Glib::IO_HUP)
 392 	revents |= POLLHUP;
 393     if (events & Glib::IO_NVAL)
 394 	return false;
 395 
 396     mExecuting = true;
 397     mCallBack (revents);
 398     mExecuting = false;
 399 
 400     if (mForceFail)
 401     {
 402 	/* FIXME: Need to find a way to properly remove the watchFd
 403 	 * from the internal list in core */
 404 	//screen->priv->watchFds.remove (this);
 405 	return false;
 406     }
 407     
 408     return true;
 409 }    
 410 
 411 void
 412 CompScreenImpl::eraseValue (CompString key)
 413 {
 414     ValueHolder::Default ()->eraseValue (key);
 415 }
 416 
 417 void
 418 CompScreen::fileWatchAdded (CompFileWatch *watch)
 419 {
 420     WRAPABLE_HND_FUNCTN (fileWatchAdded, watch);
 421     _fileWatchAdded (watch);
 422 }
 423 
 424 void
 425 CompScreenImpl::_fileWatchAdded (CompFileWatch *watch)
 426 {
 427 }
 428 
 429 void
 430 CompScreen::fileWatchRemoved (CompFileWatch *watch)
 431 {
 432     WRAPABLE_HND_FUNCTN (fileWatchRemoved, watch);
 433     _fileWatchRemoved (watch);
 434 }
 435 
 436 void
 437 CompScreenImpl::_fileWatchRemoved (CompFileWatch *watch)
 438 {
 439 }
 440 
 441 bool
 442 CompScreen::setOptionForPlugin (const char        *plugin,
 443 				const char        *name,
 444 				CompOption::Value &value)
 445 {
 446     WRAPABLE_HND_FUNCTN_RETURN (bool, setOptionForPlugin,
 447 			      plugin, name, value)
 448 
 449     return _setOptionForPlugin(plugin, name, value);
 450 }
 451 
 452 bool
 453 CompScreenImpl::_setOptionForPlugin (const char        *plugin,
 454 				const char        *name,
 455 				CompOption::Value &value)
 456 {
 457     CompPlugin *p = CompPlugin::find (plugin);
 458     if (p)
 459 	return p->vTable->setOption (name, value);
 460 
 461     return false;
 462 }
 463 
 464 void
 465 CompScreen::sessionEvent (CompSession::Event event,
 466 			  CompOption::Vector &arguments)
 467 {
 468     WRAPABLE_HND_FUNCTN (sessionEvent, event, arguments);
 469     _sessionEvent(event, arguments);
 470 }
 471 
 472 void
 473 CompScreenImpl::_sessionEvent (CompSession::Event event,
 474 			  CompOption::Vector &arguments)
 475 {
 476 }
 477 
 478 void
 479 ScreenInterface::fileWatchAdded (CompFileWatch *watch)
 480     WRAPABLE_DEF (fileWatchAdded, watch)
 481 
 482 void
 483 ScreenInterface::fileWatchRemoved (CompFileWatch *watch)
 484     WRAPABLE_DEF (fileWatchRemoved, watch)
 485 
 486 bool
 487 ScreenInterface::initPluginForScreen (CompPlugin *plugin)
 488     WRAPABLE_DEF (initPluginForScreen, plugin)
 489 
 490 void
 491 ScreenInterface::finiPluginForScreen (CompPlugin *plugin)
 492     WRAPABLE_DEF (finiPluginForScreen, plugin)
 493 
 494 bool
 495 ScreenInterface::setOptionForPlugin (const char        *plugin,
 496 				     const char	       *name,
 497 				     CompOption::Value &value)
 498     WRAPABLE_DEF (setOptionForPlugin, plugin, name, value)
 499 
 500 void
 501 ScreenInterface::sessionEvent (CompSession::Event event,
 502 			       CompOption::Vector &arguments)
 503     WRAPABLE_DEF (sessionEvent, event, arguments)
 504 
 505 
 506 static int errors = 0;
 507 
 508 static int
 509 errorHandler (Display     *dpy,
 510 	      XErrorEvent *e)
 511 {
 512 
 513 #ifdef DEBUG
 514     char str[128];
 515 #endif
 516 
 517     errors++;
 518 
 519 #ifdef DEBUG
 520     XGetErrorDatabaseText (dpy, "XlibMessage", "XError", "", str, 128);
 521     fprintf (stderr, "%s", str);
 522 
 523     XGetErrorText (dpy, e->error_code, str, 128);
 524     fprintf (stderr, ": %s\n  ", str);
 525 
 526     XGetErrorDatabaseText (dpy, "XlibMessage", "MajorCode", "%d", str, 128);
 527     fprintf (stderr, str, e->request_code);
 528 
 529     sprintf (str, "%d", e->request_code);
 530     XGetErrorDatabaseText (dpy, "XRequest", str, "", str, 128);
 531     if (strcmp (str, ""))
 532 	fprintf (stderr, " (%s)", str);
 533     fprintf (stderr, "\n  ");
 534 
 535     XGetErrorDatabaseText (dpy, "XlibMessage", "MinorCode", "%d", str, 128);
 536     fprintf (stderr, str, e->minor_code);
 537     fprintf (stderr, "\n  ");
 538 
 539     XGetErrorDatabaseText (dpy, "XlibMessage", "ResourceID", "%d", str, 128);
 540     fprintf (stderr, str, e->resourceid);
 541     fprintf (stderr, "\n");
 542 
 543     /* abort (); */
 544 #endif
 545 
 546     return 0;
 547 }
 548 
 549 int
 550 CompScreen::checkForError (Display *dpy)
 551 {
 552     int e;
 553 
 554     XSync (dpy, false);
 555 
 556     e = errors;
 557     errors = 0;
 558 
 559     return e;
 560 }
 561 
 562 Display *
 563 CompScreenImpl::dpy ()
 564 {
 565     return privateScreen.dpy;
 566 }
 567 
 568 bool
 569 CompScreenImpl::XRandr ()
 570 {
 571     return privateScreen.xRandr.isEnabled ();
 572 }
 573 
 574 int
 575 CompScreenImpl::randrEvent ()
 576 {
 577     return privateScreen.xRandr.get ();
 578 }
 579 
 580 bool
 581 CompScreenImpl::XShape ()
 582 {
 583     return privateScreen.xShape.isEnabled ();
 584 }
 585 
 586 int
 587 CompScreenImpl::shapeEvent ()
 588 {
 589     return privateScreen.xShape.get ();
 590 }
 591 
 592 int
 593 CompScreenImpl::syncEvent ()
 594 {
 595     return privateScreen.xSync.get ();
 596 }
 597 
 598 
 599 SnDisplay *
 600 CompScreenImpl::snDisplay ()
 601 {
 602     return privateScreen.getSnDisplay ();
 603 }
 604 
 605 Window
 606 CompScreenImpl::activeWindow ()
 607 {
 608     return privateScreen.orphanData.activeWindow;
 609 }
 610 
 611 Window
 612 CompScreenImpl::autoRaiseWindow ()
 613 {
 614     return autoRaiseWindow_;
 615 }
 616 
 617 const char *
 618 CompScreenImpl::displayString ()
 619 {
 620     return privateScreen.displayString ();
 621 }
 622 
 623 void
 624 PrivateScreen::updateScreenInfo ()
 625 {
 626     if (xineramaExtension)
 627     {
 628 	int nInfo;
 629 	XineramaScreenInfo *info = XineramaQueryScreens (dpy, &nInfo);
 630 
 631 	screenInfo = std::vector<XineramaScreenInfo> (info, info + nInfo);
 632 
 633 	if (info)
 634 	    XFree (info);
 635     }
 636 }
 637 
 638 void
 639 PrivateScreen::setAudibleBell (bool audible)
 640 {
 641     if (xkbEvent.isEnabled())
 642 	XkbChangeEnabledControls (dpy,
 643 				  XkbUseCoreKbd,
 644 				  XkbAudibleBellMask,
 645 				  audible ? XkbAudibleBellMask : 0);
 646 }
 647 
 648 bool
 649 CompScreenImpl::handlePingTimeout ()
 650 {
 651     return Ping::handlePingTimeout(
 652 	    windowManager.begin(),
 653 	    windowManager.end(),
 654 	    privateScreen.dpy);
 655 }
 656 
 657 bool
 658 cps::Ping::handlePingTimeout (WindowManager::iterator begin, WindowManager::iterator end, Display* dpy)
 659 {
 660     XEvent      ev;
 661     int		ping = lastPing_ + 1;
 662 
 663     ev.type		    = ClientMessage;
 664     ev.xclient.window	    = 0;
 665     ev.xclient.message_type = Atoms::wmProtocols;
 666     ev.xclient.format	    = 32;
 667     ev.xclient.data.l[0]    = Atoms::wmPing;
 668     ev.xclient.data.l[1]    = ping;
 669     ev.xclient.data.l[2]    = 0;
 670     ev.xclient.data.l[3]    = 0;
 671     ev.xclient.data.l[4]    = 0;
 672 
 673     for (WindowManager::iterator i = begin; i != end; ++i)
 674     {
 675 	CompWindow* const w(*i);
 676 	if (w->priv->handlePingTimeout (lastPing_))
 677 	{
 678 	    ev.xclient.window    = w->id ();
 679 	    ev.xclient.data.l[2] = w->id ();
 680 
 681 	    XSendEvent (dpy, w->id (), false, NoEventMask, &ev);
 682 	}
 683     }
 684 
 685     lastPing_ = ping;
 686 
 687     return true;
 688 }
 689 
 690 CompOption::Vector &
 691 CompScreenImpl::getOptions ()
 692 {
 693     return privateScreen.getOptions ();
 694 }
 695 
 696 bool
 697 CompScreenImpl::setOption (const CompString  &name,
 698 		       CompOption::Value &value)
 699 {
 700     return privateScreen.setOption (name, value);
 701 }
 702 
 703 bool
 704 PrivateScreen::setOption (const CompString  &name,
 705 			  CompOption::Value &value)
 706 {
 707     unsigned int index;
 708 
 709     bool rv = CoreOptions::setOption (name, value);
 710 
 711     if (!rv)
 712 	return false;
 713 
 714     if (!CompOption::findOption (getOptions (), name, &index))
 715         return false;
 716 
 717     switch (index) {
 718 	case CoreOptions::ActivePlugins:
 719 	    pluginManager.setDirtyPluginList ();
 720 	    break;
 721 	case CoreOptions::PingDelay:
 722 	    pingTimer.setTimes (optionGetPingDelay (),
 723 				optionGetPingDelay () + 500);
 724 	    break;
 725 	case CoreOptions::AudibleBell:
 726 	    setAudibleBell (optionGetAudibleBell ());
 727 	    break;
 728 	case CoreOptions::DetectOutputs:
 729 	    if (optionGetDetectOutputs ())
 730 		detectOutputDevices (*this);
 731 	    break;
 732 	case CoreOptions::Hsize:
 733 	case CoreOptions::Vsize:
 734 
 735 	    if (optionGetHsize () * screen->width () > MAXSHORT)
 736 		return false;
 737 	    if (optionGetVsize () * screen->height () > MAXSHORT)
 738 		return false;
 739 
 740 	    setVirtualScreenSize (optionGetHsize (), optionGetVsize ());
 741 	    break;
 742 	case CoreOptions::NumberOfDesktops:
 743 	    setNumberOfDesktops (optionGetNumberOfDesktops ());
 744 	    break;
 745 	case CoreOptions::DefaultIcon:
 746 	    return screen->updateDefaultIcon ();
 747 	    break;
 748 	case CoreOptions::Outputs:
 749 	    if (optionGetDetectOutputs ())
 750 		return false;
 751 	    updateOutputDevices (*this);
 752 	    break;
 753 	default:
 754 	    break;
 755     }
 756 
 757     return rv;
 758 }
 759 
 760 bool
 761 PrivateScreen::getNextXEvent (XEvent &ev)
 762 {
 763     if (!XEventsQueued (dpy, QueuedAlready))
 764 	return false;
 765     XNextEvent (dpy, &ev);
 766 
 767     /* Skip to the last MotionNotify
 768      * event in this sequence */
 769     if (ev.type == MotionNotify)
 770     {
 771 	XEvent peekEvent;
 772 	while (XPending (dpy))
 773 	{
 774 	    XPeekEvent (dpy, &peekEvent);
 775 
 776 	    if (peekEvent.type != MotionNotify)
 777 		break;
 778 
 779 	    XNextEvent (dpy, &peekEvent);
 780 	}
 781     }
 782 
 783     return true;
 784 }
 785 
 786 bool
 787 PrivateScreen::getNextEvent (XEvent &ev)
 788 {
 789     StackDebugger *dbg = StackDebugger::Default ();
 790 
 791     if (StackDebugger::Default ())
 792     {
 793 	return dbg->getNextEvent (ev);
 794     }
 795     else
 796 	return getNextXEvent (ev);
 797 }
 798 
 799 void
 800 PrivateScreen::processEvents ()
 801 {
 802     StackDebugger *dbg = StackDebugger::Default ();
 803 
 804     if (pluginManager.isDirtyPluginList ())
 805     {
 806 	eventManager.resetPossibleTap();
 807 	pluginManager.updatePlugins (screen, optionGetActivePlugins());
 808     }
 809 
 810     windowManager.validateServerWindows();
 811 
 812     if (dbg)
 813     {
 814 	dbg->windowsChanged (false);
 815 	dbg->serverWindowsChanged (false);
 816 	dbg->loadStack (windowManager.getServerWindows());
 817     }
 818 
 819     windowManager.invalidateServerWindows();
 820 
 821     XEvent event;
 822 
 823     while (getNextEvent (event))
 824     {
 825 	switch (event.type) {
 826 	case ButtonPress:
 827 	case ButtonRelease:
 828 	    pointerX = event.xbutton.x_root;
 829 	    pointerY = event.xbutton.y_root;
 830 	    pointerMods = event.xbutton.state;
 831 	    break;
 832 	case KeyPress:
 833 	case KeyRelease:
 834 	    pointerX = event.xkey.x_root;
 835 	    pointerY = event.xkey.y_root;
 836 	    pointerMods = event.xkey.state;
 837 	    break;
 838 	case MotionNotify:
 839 
 840 	    pointerX = event.xmotion.x_root;
 841 	    pointerY = event.xmotion.y_root;
 842 	    pointerMods = event.xmotion.state;
 843 	    break;
 844 	case EnterNotify:
 845 	case LeaveNotify:
 846 	    pointerX = event.xcrossing.x_root;
 847 	    pointerY = event.xcrossing.y_root;
 848 	    pointerMods = event.xcrossing.state;
 849 	    break;
 850 	case ClientMessage:
 851 	    if (event.xclient.message_type == Atoms::xdndPosition)
 852 	    {
 853 		pointerX = event.xclient.data.l[2] >> 16;
 854 		pointerY = event.xclient.data.l[2] & 0xffff;
 855 		/* FIXME: Xdnd provides us no way of getting the pointer mods
 856 		 * without doing XQueryPointer, which is a round-trip */
 857 		pointerMods = 0;
 858 	    }
 859 	    else if (event.xclient.message_type == Atoms::wmMoveResize)
 860 	    {
 861 		int i;
 862 		Window child, root;
 863 		/* _NET_WM_MOVERESIZE is most often sent by clients who provide
 864 		 * a special "grab space" on a window for the user to initiate
 865 		 * adjustment by the window manager. Since we don't have a
 866 		 * passive grab on Button1 for active and raised windows, we
 867 		 * need to update the pointer buffer here */
 868 
 869 		XQueryPointer (screen->dpy (), screen->root (),
 870 			       &root, &child, &pointerX, &pointerY,
 871 			       &i, &i, &pointerMods);
 872 	    }
 873 	    break;
 874 	default:
 875 	    break;
 876         }
 877 
 878 	sn_display_process_event (snDisplay, &event);
 879 
 880 	inHandleEvent = true;
 881 	screen->alwaysHandleEvent (&event);
 882 	inHandleEvent = false;
 883 
 884 	XFlush (dpy);
 885 
 886 	lastPointerX = pointerX;
 887 	lastPointerY = pointerY;
 888 	lastPointerMods = pointerMods;
 889     }
 890 
 891     /* remove destroyed windows */
 892     windowManager.removeDestroyed ();
 893 
 894     if (dbg)
 895     {
 896 	if (dbg->windowsChanged () &&
 897 	    dbg->cmpStack (windowManager.getWindows(), windowManager.getServerWindows()))
 898 	{
 899 	    compLogMessage ("core", CompLogLevelDebug, "stacks are out of sync");
 900 	    if (dbg->timedOut ())
 901 		compLogMessage ("core", CompLogLevelDebug, "however, this may be a false positive");
 902 	}
 903 
 904 	if (dbg->serverWindowsChanged () && dbg->checkSanity (windowManager.getWindows()))
 905 	    compLogMessage ("core", CompLogLevelDebug, "windows are stacked incorrectly");
 906     }
 907 }
 908 
 909 void
 910 cps::WindowManager::validateServerWindows()
 911 {
 912     /* Restacks recently processed, ensure that
 913      * plugins use the stack last received from
 914      * the server */
 915     if (stackIsFresh)
 916     {
 917 	serverWindows.clear ();
 918 
 919 	foreach (CompWindow *sw, windows)
 920 	{
 921 	    sw->serverPrev = sw->prev;
 922 	    sw->serverNext = sw->next;
 923 	    serverWindows.push_back (sw);
 924 	}
 925     }
 926 }
 927 
 928 void
 929 cps::WindowManager::invalidateServerWindows()
 930 {
 931     stackIsFresh = false;
 932 }
 933 
 934 void
 935 cps::WindowManager::clearFullscreenHints() const
 936 {
 937     /* clear out fullscreen monitor hints of all windows as
 938        suggested on monitor layout changes in EWMH */
 939     for (iterator i = windows.begin(); i != windows.end(); ++i)
 940     {
 941 	CompWindow* const w(*i);
 942 	if (w->priv->fullscreenMonitorsSet)
 943 	    w->priv->setFullscreenMonitors (NULL);
 944     }
 945 }
 946 
 947 void
 948 cps::WindowManager::showOrHideForDesktop(unsigned int desktop) const
 949 {
 950     for (iterator i = windows.begin(); i != windows.end(); ++i)
 951     {
 952 	CompWindow* const w(*i);
 953 	if (w->desktop () == 0xffffffff)
 954 	    continue;
 955 
 956 	if (w->desktop () == desktop)
 957 	    w->priv->show ();
 958 	else
 959 	    w->priv->hide ();
 960     }
 961 }
 962 
 963 void
 964 cps::WindowManager::setWindowActiveness(cps::History& history) const
 965 {
 966     for (iterator i = windows.begin(); i != windows.end(); ++i)
 967     {
 968 	CompWindow* const w(*i);
 969 	if (w->isViewable ())
 970 	    w->priv->activeNum = history.nextActiveNum ();
 971     }
 972 }
 973 
 974 void
 975 cps::WindowManager::setNumberOfDesktops(unsigned int desktops) const
 976 {
 977     for (iterator i = windows.begin(); i != windows.end(); ++i)
 978     {
 979 	CompWindow* const w(*i);
 980 	if (w->desktop () == 0xffffffff)
 981 	    continue;
 982 
 983 	if (w->desktop () >= desktops)
 984 	    w->setDesktop (desktops - 1);
 985     }
 986 }
 987 
 988 void
 989 cps::WindowManager::updateWindowSizes() const
 990 {
 991     for (iterator i = windows.begin(); i != windows.end(); ++i)
 992     {
 993 	CompWindow* const w(*i);
 994 	w->priv->updateSize ();
 995     }
 996 }
 997 
 998 
 999 CompOption::Value::Vector
1000 cps::PluginManager::mergedPluginList (CompOption::Value::Vector const& extraPluginsRequested) const
1001 {
1002     CompOption::Value::Vector result;
1003 
1004     /* Must have core as first plugin */
1005     result.push_back("core");
1006 
1007     /* Add initial plugins */
1008     foreach(CompString & p, initialPlugins)
1009     {
1010 	if (p == "core")
1011 	    continue;
1012 
1013 	if (blacklist.find (p) != blacklist.end ())
1014 	    continue;
1015 
1016 	result.push_back(p);
1017     }
1018 
1019     /* Add plugins not in the initial list */
1020     foreach(CompOption::Value const& opt, extraPluginsRequested)
1021     {
1022 	if (opt.s() == "core")
1023 	    continue;
1024 
1025 	if (blacklist.find (opt.s()) != blacklist.end ())
1026 	    continue;
1027 
1028 	typedef std::list<CompString>::iterator iterator;
1029 	bool skip = false;
1030 
1031 	for (iterator it = initialPlugins.begin(); it != initialPlugins.end();
1032 		++it)
1033 	{
1034 	    if ((*it) == opt.s())
1035 	    {
1036 		skip = true;
1037 		break;
1038 	    }
1039 	}
1040 
1041 	if (!skip)
1042 	{
1043 	    result.push_back(opt.s());
1044 	}
1045     }
1046     return result;
1047 }
1048 
1049 
1050 void
1051 cps::PluginManager::updatePlugins (CompScreen* screen, CompOption::Value::Vector const& extraPluginsRequested)
1052 {
1053     dirtyPluginList = false;
1054 
1055     CompOption::Value::Vector const desiredPlugins(mergedPluginList(extraPluginsRequested));
1056 
1057     unsigned int pluginIndex;
1058     for (pluginIndex = 1;
1059 	pluginIndex < plugin.list ().size () && pluginIndex < desiredPlugins.size ();
1060 	pluginIndex++)
1061     {
1062 	if (plugin.list ().at (pluginIndex).s () != desiredPlugins.at (pluginIndex).s ())
1063 	    break;
1064     }
1065 
1066     unsigned int desireIndex = pluginIndex;
1067 
1068     // We have pluginIndex pointing at first difference (or end).
1069     // Now pop plugins off stack to this point, but keep track that they are loaded
1070     CompPlugin::List alreadyLoaded;
1071     if (const unsigned int nPop = plugin.list().size() - pluginIndex)
1072     {
1073 	for (pluginIndex = 0; pluginIndex < nPop; pluginIndex++)
1074 	{
1075 	    alreadyLoaded.push_back(CompPlugin::pop());
1076 	    plugin.list().pop_back();
1077 	}
1078     }
1079 
1080     // Now work forward through requested plugins
1081     for (; desireIndex < desiredPlugins.size(); desireIndex++)
1082     {
1083 	CompPlugin *p = NULL;
1084 	bool failedPush = false;
1085 
1086 	// If already loaded, just try to push it...
1087 	foreach(CompPlugin * pp, alreadyLoaded)
1088 	{
1089 	    if (desiredPlugins[desireIndex].s() == pp->vTable->name())
1090 	    {
1091 		if (CompPlugin::push (pp))
1092 		{
1093 		    p = pp;
1094 		    alreadyLoaded.erase(
1095 			    std::find(alreadyLoaded.begin(),
1096 				    alreadyLoaded.end(), pp));
1097 		    break;
1098 		}
1099 		else
1100 		{
1101 		    alreadyLoaded.erase(
1102 			    std::find(alreadyLoaded.begin(),
1103 				    alreadyLoaded.end(), pp));
1104 		    blacklist.insert (desiredPlugins[desireIndex].s ());
1105 		    CompPlugin::unload(pp);
1106 		    p = NULL;
1107 		    failedPush = true;
1108 		    break;
1109 		}
1110 	    }
1111 	}
1112 
1113 	// ...otherwise, try to load and push
1114 	if (p == 0 && !failedPush)
1115 	{
1116 	    p = CompPlugin::load(desiredPlugins[desireIndex].s ().c_str ());
1117 
1118 	    if (p)
1119 	    {
1120 		if (!CompPlugin::push(p))
1121 		{
1122 		    blacklist.insert (desiredPlugins[desireIndex].s ());
1123 		    CompPlugin::unload(p);
1124 		    p = 0;
1125 		}
1126 	    }
1127 	    else
1128 	    {
1129 		blacklist.insert (desiredPlugins[desireIndex].s ());
1130 	    }
1131 	}
1132 
1133 	if (p)
1134 	    plugin.list().push_back(p->vTable->name());
1135     }
1136 
1137     // Any plugins that are loaded, but were not re-initialized can be unloaded.
1138     foreach(CompPlugin * pp, alreadyLoaded)
1139 	CompPlugin::unload (pp);
1140 
1141     if (!dirtyPluginList)
1142 	screen->setOptionForPlugin ("core", "active_plugins", plugin);
1143 }
1144 
1145 /* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
1146 static bool
1147 convertProperty (Display *dpy,
1148 		 Time    time,
1149 		 Window  w,
1150 		 Atom    target,
1151 		 Atom    property)
1152 {
1153 
1154 static const unsigned short N_TARGETS = 4;
1155 
1156     Atom conversionTargets[N_TARGETS];
1157 
1158     conversionTargets[0] = Atoms::targets;
1159     conversionTargets[1] = Atoms::multiple;
1160     conversionTargets[2] = Atoms::timestamp;
1161     conversionTargets[3] = Atoms::version;
1162 
1163     if (target == Atoms::targets)
1164 	XChangeProperty (dpy, w, property,
1165 			 XA_ATOM, 32, PropModeReplace,
1166 			 (unsigned char *) conversionTargets, N_TARGETS);
1167     else if (target == Atoms::timestamp)
1168 	XChangeProperty (dpy, w, property,
1169 			 XA_INTEGER, 32, PropModeReplace,
1170 			 (unsigned char *) &time, 1);
1171     else if (target == Atoms::version)
1172     {
1173 	long icccmVersion[] = { 2, 0 };
1174 	XChangeProperty (dpy, w, property,
1175 			 XA_INTEGER, 32, PropModeReplace,
1176 			 (unsigned char *) icccmVersion, 2);
1177     }
1178     else
1179 	return false;
1180 
1181     /* Be sure the PropertyNotify has arrived so we
1182      * can send SelectionNotify
1183      */
1184     XSync (dpy, false);
1185 
1186     return true;
1187 }
1188 
1189 /* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
1190 void
1191 PrivateScreen::handleSelectionRequest (XEvent *event)
1192 {
1193     if (wmSnSelectionWindow != event->xselectionrequest.owner ||
1194 	wmSnAtom != event->xselectionrequest.selection)
1195 	return;
1196 
1197     XSelectionEvent reply;
1198 
1199     reply.type	    = SelectionNotify;
1200     reply.display   = dpy;
1201     reply.requestor = event->xselectionrequest.requestor;
1202     reply.selection = event->xselectionrequest.selection;
1203     reply.target    = event->xselectionrequest.target;
1204     reply.property  = None;
1205     reply.time	    = event->xselectionrequest.time;
1206 
1207     if (event->xselectionrequest.target == Atoms::multiple)
1208     {
1209 	if (event->xselectionrequest.property != None)
1210 	{
1211 	    Atom	  type, *adata;
1212 	    int		  i, format;
1213 	    unsigned long num, rest;
1214 	    unsigned char *data;
1215 
1216 	    if (XGetWindowProperty (dpy,
1217 				    event->xselectionrequest.requestor,
1218 				    event->xselectionrequest.property,
1219 				    0, 256, false,
1220 				    Atoms::atomPair,
1221 				    &type, &format, &num, &rest,
1222 				    &data) != Success)
1223 		return;
1224 
1225 	    /* FIXME: to be 100% correct, should deal with rest > 0,
1226 	     * but since we have 4 possible targets, we will hardly ever
1227 	     * meet multiple requests with a length > 8
1228 	     */
1229 	    adata = (Atom *) data;
1230 	    i = 0;
1231 	    while (i < (int) num)
1232 	    {
1233 		if (!convertProperty (dpy, wmSnTimestamp,
1234 				      event->xselectionrequest.requestor,
1235 				      adata[i], adata[i + 1]))
1236 		    adata[i + 1] = None;
1237 
1238 		i += 2;
1239 	    }
1240 
1241 	    XChangeProperty (dpy,
1242 			     event->xselectionrequest.requestor,
1243 			     event->xselectionrequest.property,
1244 			     Atoms::atomPair,
1245 			     32, PropModeReplace, data, num);
1246 
1247 	    if (data)
1248 		XFree (data);
1249 	}
1250     }
1251     else
1252     {
1253 	if (event->xselectionrequest.property == None)
1254 	    event->xselectionrequest.property = event->xselectionrequest.target;
1255 
1256 	if (convertProperty (dpy, wmSnTimestamp,
1257 			     event->xselectionrequest.requestor,
1258 			     event->xselectionrequest.target,
1259 			     event->xselectionrequest.property))
1260 	    reply.property = event->xselectionrequest.property;
1261     }
1262 
1263     XSendEvent (dpy, event->xselectionrequest.requestor,
1264 		false, 0L, (XEvent *) &reply);
1265 }
1266 
1267 void
1268 PrivateScreen::handleSelectionClear (XEvent *event)
1269 {
1270     /* We need to unmanage the screen on which we lost the selection */
1271     if (wmSnSelectionWindow != event->xselectionclear.window ||
1272 	wmSnAtom != event->xselectionclear.selection)
1273 	return;
1274 
1275     eventManager.quit ();
1276 }
1277 
1278 static const std::string IMAGEDIR("images");
1279 static const std::string HOMECOMPIZDIR(".compiz-1");
1280 
1281 bool
1282 CompScreenImpl::readImageFromFile (CompString &name,
1283 			       CompString &pname,
1284 			       CompSize   &size,
1285 			       void       *&data)
1286 {
1287     bool status;
1288     int  stride;
1289 
1290     status = fileToImage (name, size, stride, data);
1291     if (!status)
1292     {
1293 	char       *home = getenv ("HOME");
1294 	CompString path;
1295 	if (home)
1296 	{
1297 	    path =  home;
1298 	    path += "/";
1299 	    path += HOMECOMPIZDIR;
1300 	    path += "/";
1301 	    path += pname;
1302 	    path += "/";
1303 	    path += IMAGEDIR;
1304 	    path += "/";
1305 	    path += name;
1306 
1307 	    status = fileToImage (path, size, stride, data);
1308 
1309 	    if (status)
1310 		return true;
1311 	}
1312 
1313 	path = SHAREDIR;
1314 	path += "/";
1315 	path += pname;
1316 	path += "/";
1317 	path += IMAGEDIR;
1318 	path += "/";
1319 	path += name;
1320 	status = fileToImage (path, size, stride, data);
1321     }
1322 
1323     return status;
1324 }
1325 
1326 bool
1327 CompScreenImpl::writeImageToFile (CompString &path,
1328 			      const char *format,
1329 			      CompSize   &size,
1330 			      void       *data)
1331 {
1332     CompString formatString (format);
1333     return imageToFile (path, formatString, size, size.width () * 4, data);
1334 }
1335 
1336 Window
1337 PrivateScreen::getActiveWindow (Window root)
1338 {
1339     Atom	  actual;
1340     int		  result, format;
1341     unsigned long n, left;
1342     unsigned char *data;
1343     Window	  w = None;
1344 
1345     result = XGetWindowProperty (dpy, root,
1346 				 Atoms::winActive, 0L, 1L, false,
1347 				 XA_WINDOW, &actual, &format,
1348 				 &n, &left, &data);
1349 
1350     if (result == Success && data)
1351     {
1352 	if (n)
1353 	    memcpy (&w, data, sizeof (Window));
1354 	XFree (data);
1355     }
1356 
1357     return w;
1358 }
1359 
1360 bool
1361 CompScreen::fileToImage (CompString &name,
1362 			 CompSize   &size,
1363 			 int        &stride,
1364 			 void       *&data)
1365 {
1366     WRAPABLE_HND_FUNCTN_RETURN (bool, fileToImage, name, size, stride, data);
1367     return _fileToImage(name, size, stride, data);
1368 }
1369 
1370 bool
1371 CompScreenImpl::_fileToImage (CompString &name,
1372 			 CompSize   &size,
1373 			 int        &stride,
1374 			 void       *&data)
1375 {
1376     return false;
1377 }
1378 
1379 bool
1380 CompScreen::imageToFile (CompString &path,
1381 			 CompString &format,
1382 			 CompSize   &size,
1383 			 int        stride,
1384 			 void       *data)
1385 {
1386     WRAPABLE_HND_FUNCTN_RETURN (bool, imageToFile, path, format, size,
1387 			      stride, data);
1388     return _imageToFile (path, format, size, stride, data);
1389 }
1390 
1391 bool
1392 CompScreenImpl::_imageToFile (CompString &path,
1393 			 CompString &format,
1394 			 CompSize   &size,
1395 			 int        stride,
1396 			 void       *data)
1397 {
1398     return false;
1399 }
1400 
1401 void
1402 CompScreen::logMessage (const char   *componentName,
1403 			CompLogLevel level,
1404 			const char   *message)
1405 {
1406     WRAPABLE_HND_FUNCTN (logMessage, componentName, level, message)
1407     _logMessage (componentName, level, message);
1408 }
1409 
1410 void
1411 CompScreenImpl::_logMessage (const char   *componentName,
1412 			CompLogLevel level,
1413 			const char   *message)
1414 {
1415     ::logMessage (componentName, level, message);
1416 }
1417 
1418 int
1419 cps::XWindowInfo::getWmState (Window id)
1420 {
1421     Atom	  actual;
1422     int		  result, format;
1423     unsigned long n, left;
1424     unsigned char *data;
1425     unsigned long state = NormalState;
1426 
1427     result = XGetWindowProperty (dpy, id,
1428 				 Atoms::wmState, 0L, 2L, false,
1429 				 Atoms::wmState, &actual, &format,
1430 				 &n, &left, &data);
1431 
1432     if (result == Success && data)
1433     {
1434 	if (n)
1435 	    memcpy (&state, data, sizeof (unsigned long));
1436 	XFree ((void *) data);
1437     }
1438 
1439     return state;
1440 }
1441 
1442 void
1443 cps::XWindowInfo::setWmState (int state, Window id) const
1444 {
1445     unsigned long data[2];
1446 
1447     data[0] = state;
1448     data[1] = None;
1449 
1450     XChangeProperty (dpy, id,
1451 		     Atoms::wmState, Atoms::wmState,
1452 		     32, PropModeReplace, (unsigned char *) data, 2);
1453 }
1454 
1455 unsigned int
1456 cps::windowStateMask (Atom state)
1457 {
1458     if (state == Atoms::winStateModal)
1459 	return CompWindowStateModalMask;
1460     else if (state == Atoms::winStateSticky)
1461 	return CompWindowStateStickyMask;
1462     else if (state == Atoms::winStateMaximizedVert)
1463 	return CompWindowStateMaximizedVertMask;
1464     else if (state == Atoms::winStateMaximizedHorz)
1465 	return CompWindowStateMaximizedHorzMask;
1466     else if (state == Atoms::winStateShaded)
1467 	return CompWindowStateShadedMask;
1468     else if (state == Atoms::winStateSkipTaskbar)
1469 	return CompWindowStateSkipTaskbarMask;
1470     else if (state == Atoms::winStateSkipPager)
1471 	return CompWindowStateSkipPagerMask;
1472     else if (state == Atoms::winStateHidden)
1473 	return CompWindowStateHiddenMask;
1474     else if (state == Atoms::winStateFullscreen)
1475 	return CompWindowStateFullscreenMask;
1476     else if (state == Atoms::winStateAbove)
1477 	return CompWindowStateAboveMask;
1478     else if (state == Atoms::winStateBelow)
1479 	return CompWindowStateBelowMask;
1480     else if (state == Atoms::winStateDemandsAttention)
1481 	return CompWindowStateDemandsAttentionMask;
1482     else if (state == Atoms::winStateDisplayModal)
1483 	return CompWindowStateDisplayModalMask;
1484 
1485     return 0;
1486 }
1487 
1488 unsigned int
1489 cps::windowStateFromString (const char *str)
1490 {
1491     if (strcasecmp (str, "modal") == 0)
1492 	return CompWindowStateModalMask;
1493     else if (strcasecmp (str, "sticky") == 0)
1494 	return CompWindowStateStickyMask;
1495     else if (strcasecmp (str, "maxvert") == 0)
1496 	return CompWindowStateMaximizedVertMask;
1497     else if (strcasecmp (str, "maxhorz") == 0)
1498 	return CompWindowStateMaximizedHorzMask;
1499     else if (strcasecmp (str, "shaded") == 0)
1500 	return CompWindowStateShadedMask;
1501     else if (strcasecmp (str, "skiptaskbar") == 0)
1502 	return CompWindowStateSkipTaskbarMask;
1503     else if (strcasecmp (str, "skippager") == 0)
1504 	return CompWindowStateSkipPagerMask;
1505     else if (strcasecmp (str, "hidden") == 0)
1506 	return CompWindowStateHiddenMask;
1507     else if (strcasecmp (str, "fullscreen") == 0)
1508 	return CompWindowStateFullscreenMask;
1509     else if (strcasecmp (str, "above") == 0)
1510 	return CompWindowStateAboveMask;
1511     else if (strcasecmp (str, "below") == 0)
1512 	return CompWindowStateBelowMask;
1513     else if (strcasecmp (str, "demandsattention") == 0)
1514 	return CompWindowStateDemandsAttentionMask;
1515 
1516     return 0;
1517 }
1518 
1519 unsigned int
1520 cps::XWindowInfo::getWindowState (Window id)
1521 {
1522     Atom	  actual;
1523     int		  result, format;
1524     unsigned long n, left;
1525     unsigned char *data;
1526     unsigned int  state = 0;
1527 
1528     result = XGetWindowProperty (dpy, id,
1529 				 Atoms::winState,
1530 				 0L, 1024L, false, XA_ATOM, &actual, &format,
1531 				 &n, &left, &data);
1532 
1533     if (result == Success && data)
1534     {
1535 	Atom *a = (Atom *) data;
1536 
1537 	while (n--)
1538 	    state |= cps::windowStateMask (*a++);
1539 
1540 	XFree ((void *) data);
1541     }
1542 
1543     return state;
1544 }
1545 
1546 unsigned int
1547 compiz::window::fillStateData (unsigned int state, Atom *data)
1548 {
1549     int	 i = 0;
1550 
1551     if (state & CompWindowStateModalMask)
1552 	data[i++] = Atoms::winStateModal;
1553     if (state & CompWindowStateStickyMask)
1554 	data[i++] = Atoms::winStateSticky;
1555     if (state & CompWindowStateMaximizedVertMask)
1556 	data[i++] = Atoms::winStateMaximizedVert;
1557     if (state & CompWindowStateMaximizedHorzMask)
1558 	data[i++] = Atoms::winStateMaximizedHorz;
1559     if (state & CompWindowStateShadedMask)
1560 	data[i++] = Atoms::winStateShaded;
1561     if (state & CompWindowStateSkipTaskbarMask)
1562 	data[i++] = Atoms::winStateSkipTaskbar;
1563     if (state & CompWindowStateSkipPagerMask)
1564 	data[i++] = Atoms::winStateSkipPager;
1565     if (state & CompWindowStateHiddenMask)
1566 	data[i++] = Atoms::winStateHidden;
1567     if (state & CompWindowStateFullscreenMask)
1568 	data[i++] = Atoms::winStateFullscreen;
1569     if (state & CompWindowStateAboveMask)
1570 	data[i++] = Atoms::winStateAbove;
1571     if (state & CompWindowStateBelowMask)
1572 	data[i++] = Atoms::winStateBelow;
1573     if (state & CompWindowStateDemandsAttentionMask)
1574 	data[i++] = Atoms::winStateDemandsAttention;
1575     if (state & CompWindowStateDisplayModalMask)
1576 	data[i++] = Atoms::winStateDisplayModal;
1577     if (state & CompWindowStateFocusedMask)
1578 	data[i++] = Atoms::winStateFocused;
1579 
1580     return i;
1581 }
1582 
1583 void
1584 PrivateScreen::setWindowState (unsigned int state, Window id)
1585 {
1586     int i = 0;
1587     Atom data[32];
1588 
1589     i = compiz::window::fillStateData (state, data);
1590     XChangeProperty (dpy, id, Atoms::winState,
1591                      XA_ATOM, 32, PropModeReplace,
1592                      (unsigned char *) data, i);
1593 }
1594 
1595 unsigned int
1596 cps::XWindowInfo::getWindowType (Window id)
1597 {
1598     Atom	  actual, a = None;
1599     int		  result, format;
1600     unsigned long n, left;
1601     unsigned char *data;
1602 
1603     result = XGetWindowProperty (dpy , id,
1604 				 Atoms::winType,
1605 				 0L, 1L, false, XA_ATOM, &actual, &format,
1606 				 &n, &left, &data);
1607 
1608     if (result == Success && data)
1609     {
1610 	if (n)
1611 	    memcpy (&a, data, sizeof (Atom));
1612 	XFree ((void *) data);
1613     }
1614 
1615     if (a)
1616     {
1617 	if (a == Atoms::winTypeNormal)
1618 	    return CompWindowTypeNormalMask;
1619 	else if (a == Atoms::winTypeMenu)
1620 	    return CompWindowTypeMenuMask;
1621 	else if (a == Atoms::winTypeDesktop)
1622 	    return CompWindowTypeDesktopMask;
1623 	else if (a == Atoms::winTypeDock)
1624 	    return CompWindowTypeDockMask;
1625 	else if (a == Atoms::winTypeToolbar)
1626 	    return CompWindowTypeToolbarMask;
1627 	else if (a == Atoms::winTypeUtil)
1628 	    return CompWindowTypeUtilMask;
1629 	else if (a == Atoms::winTypeSplash)
1630 	    return CompWindowTypeSplashMask;
1631 	else if (a == Atoms::winTypeDialog)
1632 	    return CompWindowTypeDialogMask;
1633 	else if (a == Atoms::winTypeDropdownMenu)
1634 	    return CompWindowTypeDropdownMenuMask;
1635 	else if (a == Atoms::winTypePopupMenu)
1636 	    return CompWindowTypePopupMenuMask;
1637 	else if (a == Atoms::winTypeTooltip)
1638 	    return CompWindowTypeTooltipMask;
1639 	else if (a == Atoms::winTypeNotification)
1640 	    return CompWindowTypeNotificationMask;
1641 	else if (a == Atoms::winTypeCombo)
1642 	    return CompWindowTypeComboMask;
1643 	else if (a == Atoms::winTypeDnd)
1644 	    return CompWindowTypeDndMask;
1645     }
1646 
1647     return CompWindowTypeUnknownMask;
1648 }
1649 
1650 void
1651 cps::XWindowInfo::getMwmHints (Window       id,
1652 			    unsigned int *func,
1653 			    unsigned int *decor) const
1654 {
1655     Atom	  actual;
1656     int		  result, format;
1657     unsigned long n, left;
1658     unsigned char *data;
1659 
1660     *func  = MwmFuncAll;
1661     *decor = MwmDecorAll;
1662 
1663     result = XGetWindowProperty (dpy, id,
1664 				 Atoms::mwmHints,
1665 				 0L, 20L, false, Atoms::mwmHints,
1666 				 &actual, &format, &n, &left, &data);
1667 
1668     if (result == Success && data)
1669     {
1670 	MwmHints *mwmHints = (MwmHints *) data;
1671 
1672 	if (n >= PropMotifWmHintElements)
1673 	{
1674 	    if (mwmHints->flags & MwmHintsDecorations)
1675 		*decor = mwmHints->decorations;
1676 
1677 	    if (mwmHints->flags & MwmHintsFunctions)
1678 		*func = mwmHints->functions;
1679 	}
1680 
1681 	XFree (data);
1682     }
1683 }
1684 
1685 unsigned int
1686 cps::XWindowInfo::getProtocols (Window id)
1687 {
1688     Atom         *protocol;
1689     int          count;
1690     unsigned int protocols = 0;
1691 
1692     if (XGetWMProtocols (dpy, id, &protocol, &count))
1693     {
1694 	for (int i = 0; i < count; i++)
1695 	{
1696 	    if (protocol[i] == Atoms::wmDeleteWindow)
1697 		protocols |= CompWindowProtocolDeleteMask;
1698 	    else if (protocol[i] == Atoms::wmTakeFocus)
1699 		protocols |= CompWindowProtocolTakeFocusMask;
1700 	    else if (protocol[i] == Atoms::wmPing)
1701 		protocols |= CompWindowProtocolPingMask;
1702 	    else if (protocol[i] == Atoms::wmSyncRequest)
1703 		protocols |= CompWindowProtocolSyncRequestMask;
1704 	}
1705 
1706 	XFree (protocol);
1707     }
1708 
1709     return protocols;
1710 }
1711 
1712 unsigned int
1713 CompScreenImpl::getWindowProp (Window       id,
1714 			   Atom         property,
1715 			   unsigned int defaultValue)
1716 {
1717     Atom	  actual;
1718     int		  result, format;
1719     unsigned long n, left;
1720     unsigned char *data;
1721     unsigned int  retval = defaultValue;
1722 
1723     result = XGetWindowProperty (privateScreen.dpy, id, property,
1724 				 0L, 1L, false, XA_CARDINAL, &actual, &format,
1725 				 &n, &left, &data);
1726 
1727     if (result == Success && data)
1728     {
1729 	if (n)
1730 	{
1731 	    unsigned long value;
1732 	    memcpy (&value, data, sizeof (unsigned long));
1733 	    retval = (unsigned int) value;
1734 	}
1735 
1736 	XFree (data);
1737     }
1738 
1739     return retval;
1740 }
1741 
1742 void
1743 CompScreenImpl::setWindowProp (Window       id,
1744 			   Atom         property,
1745 			   unsigned int value)
1746 {
1747     unsigned long data = value;
1748 
1749     XChangeProperty (privateScreen.dpy, id, property,
1750 		     XA_CARDINAL, 32, PropModeReplace,
1751 		     (unsigned char *) &data, 1);
1752 }
1753 
1754 bool
1755 PrivateScreen::readWindowProp32 (Window         id,
1756 				 Atom           property,
1757 				 unsigned short *returnValue)
1758 {
1759     Atom	  actual;
1760     int		  result, format;
1761     unsigned long n, left;
1762     unsigned char *data;
1763     bool          retval = false;
1764 
1765     result = XGetWindowProperty (dpy, id, property,
1766 				 0L, 1L, false, XA_CARDINAL, &actual, &format,
1767 				 &n, &left, &data);
1768 
1769     if (result == Success && data)
1770     {
1771 	if (n)
1772 	{
1773 	    CARD32 value;
1774 
1775 	    memcpy (&value, data, sizeof (CARD32));
1776 	    retval       = true;
1777 	    *returnValue = value >> 16;
1778 	}
1779 
1780 	XFree (data);
1781     }
1782 
1783     return retval;
1784 }
1785 
1786 unsigned short
1787 CompScreenImpl::getWindowProp32 (Window         id,
1788 			     Atom           property,
1789 			     unsigned short defaultValue)
1790 {
1791     unsigned short result;
1792 
1793     if (privateScreen.readWindowProp32 (id, property, &result))
1794 	return result;
1795 
1796     return defaultValue;
1797 }
1798 
1799 void
1800 CompScreenImpl::setWindowProp32 (Window         id,
1801 			     Atom           property,
1802 			     unsigned short value)
1803 {
1804     CARD32 value32;
1805 
1806     value32 = value << 16 | value;
1807 
1808     XChangeProperty (privateScreen.dpy, id, property,
1809 		     XA_CARDINAL, 32, PropModeReplace,
1810 		     (unsigned char *) &value32, 1);
1811 }
1812 
1813 void
1814 ScreenInterface::handleEvent (XEvent *event)
1815     WRAPABLE_DEF (handleEvent, event)
1816 
1817 void
1818 ScreenInterface::handleCompizEvent (const char         *plugin,
1819 				    const char         *event,
1820 				    CompOption::Vector &options)
1821     WRAPABLE_DEF (handleCompizEvent, plugin, event, options)
1822 
1823 bool
1824 ScreenInterface::fileToImage (CompString &name,
1825 			      CompSize   &size,
1826 			      int        &stride,
1827 			      void       *&data)
1828     WRAPABLE_DEF (fileToImage, name, size, stride, data)
1829 
1830 bool
1831 ScreenInterface::imageToFile (CompString &path,
1832 			      CompString &format,
1833 			      CompSize   &size,
1834 			      int        stride,
1835 			      void       *data)
1836     WRAPABLE_DEF (imageToFile, path, format, size, stride, data)
1837 
1838 CompMatch::Expression *
1839 ScreenInterface::matchInitExp (const CompString& value)
1840     WRAPABLE_DEF (matchInitExp, value)
1841 
1842 void
1843 ScreenInterface::matchExpHandlerChanged ()
1844     WRAPABLE_DEF (matchExpHandlerChanged)
1845 
1846 void
1847 ScreenInterface::matchPropertyChanged (CompWindow *window)
1848     WRAPABLE_DEF (matchPropertyChanged, window)
1849 
1850 void
1851 ScreenInterface::logMessage (const char   *componentName,
1852 			     CompLogLevel level,
1853 			     const char   *message)
1854     WRAPABLE_DEF (logMessage, componentName, level, message)
1855 
1856 
1857 bool
1858 PrivateScreen::desktopHintEqual (unsigned long *data,
1859 				 int           size,
1860 				 int           offset,
1861 				 int           hintSize)
1862 {
1863     if (size != desktopHintSize)
1864 	return false;
1865 
1866     if (memcmp (data + offset,
1867 		desktopHintData + offset,
1868 		hintSize * sizeof (unsigned long)) == 0)
1869 	return true;
1870 
1871     return false;
1872 }
1873 
1874 void
1875 PrivateScreen::setDesktopHints ()
1876 {
1877     unsigned long *data;
1878 
1879     int dSize = nDesktop * 2 + nDesktop * 2 + nDesktop * 4 + 1;
1880 
1881     data = (unsigned long *) malloc (sizeof (unsigned long) * dSize);
1882     if (!data)
1883 	return;
1884 
1885     unsigned int  i;
1886     int offset   = 0;
1887     int hintSize = nDesktop * 2;
1888 
1889     for (i = 0; i < nDesktop; i++)
1890     {
1891 	data[offset + i * 2 + 0] = viewPort.vp.x () * screen->width ();
1892 	data[offset + i * 2 + 1] = viewPort.vp.y () * screen->height ();
1893     }
1894 
1895     if (!desktopHintEqual (data, dSize, offset, hintSize))
1896 	XChangeProperty (dpy, rootWindow(),
1897 			 Atoms::desktopViewport,
1898 			 XA_CARDINAL, 32, PropModeReplace,
1899 			 (unsigned char *) &data[offset], hintSize);
1900 
1901     offset += hintSize;
1902 
1903     for (i = 0; i < nDesktop; i++)
1904     {
1905 	data[offset + i * 2 + 0] = screen->width () * viewPort.vpSize.width ();
1906 	data[offset + i * 2 + 1] = screen->height () * viewPort.vpSize.height ();
1907     }
1908 
1909     if (!desktopHintEqual (data, dSize, offset, hintSize))
1910 	XChangeProperty (dpy, rootWindow(),
1911 			 Atoms::desktopGeometry,
1912 			 XA_CARDINAL, 32, PropModeReplace,
1913 			 (unsigned char *) &data[offset], hintSize);
1914 
1915     offset += hintSize;
1916     hintSize = nDesktop * 4;
1917 
1918     for (i = 0; i < nDesktop; i++)
1919     {
1920 	data[offset + i * 4 + 0] = workArea.x ();
1921 	data[offset + i * 4 + 1] = workArea.y ();
1922 	data[offset + i * 4 + 2] = workArea.width ();
1923 	data[offset + i * 4 + 3] = workArea.height ();
1924     }
1925 
1926     if (!desktopHintEqual (data, dSize, offset, hintSize))
1927 	XChangeProperty (dpy, rootWindow(),
1928 			 Atoms::workarea,
1929 			 XA_CARDINAL, 32, PropModeReplace,
1930 			 (unsigned char *) &data[offset], hintSize);
1931 
1932     offset += hintSize;
1933 
1934     data[offset] = nDesktop;
1935     hintSize = 1;
1936 
1937     if (!desktopHintEqual (data, dSize, offset, hintSize))
1938 	XChangeProperty (dpy, rootWindow(),
1939 			 Atoms::numberOfDesktops,
1940 			 XA_CARDINAL, 32, PropModeReplace,
1941 			 (unsigned char *) &data[offset], hintSize);
1942 
1943     if (desktopHintData)
1944 	free (desktopHintData);
1945 
1946     desktopHintData = data;
1947     desktopHintSize = dSize;
1948 }
1949 
1950 void
1951 PrivateScreen::setVirtualScreenSize (int newh, int newv)
1952 {
1953     /* if newh or newv is being reduced */
1954     if (newh < screen->vpSize ().width () ||
1955 	newv < screen->vpSize ().height ())
1956     {
1957 	int        tx = 0;
1958 	int        ty = 0;
1959 
1960 	if (screen->vp ().x () >= newh)
1961 	    tx = screen->vp ().x () - (newh - 1);
1962 	if (screen->vp ().y () >= newv)
1963 	    ty = screen->vp ().y () - (newv - 1);
1964 
1965 	if (tx != 0 || ty != 0)
1966 	    screen->moveViewport (tx, ty, TRUE);
1967 
1968 	/* Move windows that were in one of the deleted viewports into the
1969 	   closest viewport */
1970 	foreach (CompWindow *w, screen->windows ())
1971 	{
1972 	    int moveX = 0;
1973 	    int moveY = 0;
1974 
1975 	    if (w->onAllViewports ())
1976 		continue;
1977 
1978 	    /* Find which viewport the (inner) window's top-left corner falls
1979 	       in, and check if it's outside the new viewport horizontal and
1980 	       vertical index range */
1981 	    if (newh < screen->vpSize ().width ())
1982 	    {
1983 		int vpX;   /* x index of a window's vp */
1984 
1985 		vpX = w->serverX () / screen->width ();
1986 		if (w->serverX () < 0)
1987 		    vpX -= 1;
1988 
1989 		vpX += screen->vp ().x (); /* Convert relative to absolute vp index */
1990 
1991 		/* Move windows too far right to left */
1992 		if (vpX >= newh)
1993 		    moveX = ((newh - 1) - vpX) * screen->width ();
1994 	    }
1995 	    if (newv < screen->vpSize ().height ())
1996 	    {
1997 		int vpY;   /* y index of a window's vp */
1998 
1999 		vpY = w->serverY () / screen->height ();
2000 		if (w->serverY () < 0)
2001 		    vpY -= 1;
2002 
2003 		vpY += screen->vp ().y (); /* Convert relative to absolute vp index */
2004 
2005 		/* Move windows too far right to left */
2006 		if (vpY >= newv)
2007 		    moveY = ((newv - 1) - vpY) * screen->height ();
2008 	    }
2009 
2010 	    if (moveX != 0 || moveY != 0)
2011 	    {
2012 		unsigned int valueMask = CWX | CWY;
2013 		XWindowChanges xwc;
2014 
2015 		xwc.x = w->serverGeometry ().x () + moveX;
2016 		xwc.y = w->serverGeometry ().y () + moveY;
2017 
2018 		w->configureXWindow (valueMask, &xwc);
2019 	    }
2020 	}
2021     }
2022 
2023     viewPort.vpSize.setWidth (newh);
2024     viewPort.vpSize.setHeight (newv);
2025 
2026     setDesktopHints ();
2027 }
2028 
2029 void
2030 PrivateScreen::updateOutputDevices (CoreOptions& coreOptions)
2031 {
2032     outputDevices.updateOutputDevices(coreOptions, screen);
2033 
2034     windowManager.clearFullscreenHints();
2035 
2036     screen->updateWorkarea ();
2037 
2038     screen->outputChangeNotify ();
2039 }
2040 
2041 void
2042 PrivateScreen::detectOutputDevices (CoreOptions& coreOptions)
2043 {
2044     if (coreOptions.optionGetDetectOutputs ())
2045     {
2046 	CompString	  name;
2047 	CompOption::Value value;
2048 
2049 	if (!screenInfo.empty ())
2050 	{
2051 	    CompOption::Value::Vector l;
2052 	    foreach (XineramaScreenInfo xi, screenInfo)
2053 	    {
2054 		l.push_back (compPrintf ("%dx%d+%d+%d", xi.width, xi.height,
2055 					 xi.x_org, xi.y_org));
2056 	    }
2057 
2058 	    value.set (CompOption::TypeString, l);
2059 	}
2060 	else
2061 	{
2062 	    CompOption::Value::Vector l;
2063 	    l.push_back (compPrintf ("%dx%d+%d+%d", screen->width (),
2064 				     screen->height (), 0, 0));
2065 	    value.set (CompOption::TypeString, l);
2066 	}
2067 
2068 	coreOptions.getOptions()[CoreOptions::DetectOutputs].value ().set (false);
2069 	screen->setOptionForPlugin ("core", "outputs", value);
2070 	coreOptions.getOptions()[CoreOptions::DetectOutputs].value ().set (true);
2071     }
2072     else
2073     {
2074 	updateOutputDevices (coreOptions);
2075     }
2076 }
2077 
2078 
2079 void
2080 cps::StartupSequenceImpl::updateStartupFeedback ()
2081 {
2082     if (priv->initialized)
2083     {
2084 	if (!emptySequence())
2085 	    XDefineCursor (priv->dpy, priv->rootWindow(), priv->busyCursor);
2086 	else
2087 	    XDefineCursor (priv->dpy, priv->rootWindow(), priv->normalCursor);
2088     }
2089 }
2090 
2091 static const unsigned int STARTUP_TIMEOUT_DELAY = 15000;
2092 
2093 bool
2094 cps::StartupSequence::handleStartupSequenceTimeout ()
2095 {
2096     struct timeval	now, active;
2097     double		elapsed;
2098 
2099     gettimeofday (&now, NULL);
2100 
2101     foreach (CompStartupSequence *s, startupSequences)
2102     {
2103 	sn_startup_sequence_get_last_active_time (s->sequence,
2104 						  &active.tv_sec,
2105 						  &active.tv_usec);
2106 
2107 	elapsed = ((((double) now.tv_sec - active.tv_sec) * 1000000.0 +
2108 		    (now.tv_usec - active.tv_usec))) / 1000.0;
2109 
2110 	if (elapsed > STARTUP_TIMEOUT_DELAY)
2111 	    sn_startup_sequence_complete (s->sequence);
2112     }
2113 
2114     return true;
2115 }
2116 
2117 void
2118 cps::StartupSequence::addSequence (SnStartupSequence *sequence, CompPoint const& vp)
2119 {
2120     CompStartupSequence *s;
2121 
2122     s = new CompStartupSequence ();
2123     if (!s)
2124 	return;
2125 
2126     sn_startup_sequence_ref (sequence);
2127 
2128     s->sequence = sequence;
2129     s->viewportX = vp.x ();
2130     s->viewportY = vp.y ();
2131 
2132     startupSequences.push_front (s);
2133 
2134     if (!startupSequenceTimer.active ())
2135 	startupSequenceTimer.start ();
2136 
2137     updateStartupFeedback ();
2138 }
2139 
2140 void
2141 cps::StartupSequence::removeSequence (SnStartupSequence *sequence)
2142 {
2143     CompStartupSequence *s = NULL;
2144 
2145     std::list<CompStartupSequence *>::iterator it = startupSequences.begin ();
2146 
2147     for (; it != startupSequences.end (); ++it)
2148     {
2149 	if ((*it)->sequence == sequence)
2150 	{
2151 	    s = (*it);
2152 	    break;
2153 	}
2154     }
2155 
2156     if (!s)
2157 	return;
2158 
2159     sn_startup_sequence_unref (sequence);
2160 
2161     startupSequences.erase (it);
2162 
2163     delete s;
2164 
2165     if (startupSequences.empty () && startupSequenceTimer.active ())
2166 	startupSequenceTimer.stop ();
2167 
2168     updateStartupFeedback ();
2169 }
2170 
2171 void
2172 cps::StartupSequence::removeAllSequences ()
2173 {
2174     foreach (CompStartupSequence *s, startupSequences)
2175     {
2176 	sn_startup_sequence_unref (s->sequence);
2177 	delete s;
2178     }
2179 
2180     startupSequences.clear ();
2181 
2182     if (startupSequenceTimer.active ())
2183 	startupSequenceTimer.stop ();
2184 
2185     updateStartupFeedback ();
2186 }
2187 
2188 void
2189 PrivateScreen::compScreenSnEvent (SnMonitorEvent *event,
2190 			       void           *userData)
2191 {
2192     PrivateScreen	      *self = (PrivateScreen *) userData;
2193     SnStartupSequence *sequence;
2194 
2195     sequence = sn_monitor_event_get_startup_sequence (event);
2196 
2197     switch (sn_monitor_event_get_type (event)) {
2198     case SN_MONITOR_EVENT_INITIATED:
2199 	self->startupSequence.addSequence (sequence, self->viewPort.vp);
2200 	break;
2201     case SN_MONITOR_EVENT_COMPLETED:
2202 	self->startupSequence.removeSequence (sequence);
2203 	break;
2204     case SN_MONITOR_EVENT_CHANGED:
2205     case SN_MONITOR_EVENT_CANCELED:
2206 	break;
2207     }
2208 }
2209 
2210 void
2211 PrivateScreen::updateScreenEdges ()
2212 {
2213     struct screenEdgeGeometry {
2214 	int xw, x0;
2215 	int yh, y0;
2216 	int ww, w0;
2217 	int hh, h0;
2218     } geometry[SCREEN_EDGE_NUM] = {
2219 	{ 0, -1,   0,  2,   0,  2,   1, -4 }, /* left */
2220 	{ 1, -1,   0,  2,   0,  2,   1, -4 }, /* right */
2221 	{ 0,  2,   0, -1,   1, -4,   0,  2 }, /* top */
2222 	{ 0,  2,   1, -1,   1, -4,   0,  2 }, /* bottom */
2223 	{ 0, -1,   0, -1,   0,  2,   0,  2 }, /* top-left */
2224 	{ 1, -1,   0, -1,   0,  2,   0,  2 }, /* top-right */
2225 	{ 0, -1,   1, -1,   0,  2,   0,  2 }, /* bottom-left */
2226 	{ 1, -1,   1, -1,   0,  2,   0,  2 }  /* bottom-right */
2227     };
2228 
2229     for (int i = 0; i < SCREEN_EDGE_NUM; i++)
2230     {
2231 	if (screenEdge[i].id)
2232 	    XMoveResizeWindow (dpy, screenEdge[i].id,
2233 			       geometry[i].xw * screen->width () +
2234 			       geometry[i].x0,
2235 			       geometry[i].yh * screen->height () +
2236 			       geometry[i].y0,
2237 			       geometry[i].ww * screen->width () +
2238 			       geometry[i].w0,
2239 			       geometry[i].hh * screen->height () +
2240 			       geometry[i].h0);
2241     }
2242 }
2243 
2244 void
2245 PrivateScreen::reshape (int w, int h)
2246 {
2247     updateScreenInfo ();
2248 
2249     region = CompRegion (0, 0, w, h);
2250 
2251     screen->setWidth (w);
2252     screen->setHeight (h);
2253 
2254     fullscreenOutput.setId ("fullscreen", ~0);
2255     fullscreenOutput.setGeometry (0, 0, w, h);
2256 
2257     updateScreenEdges ();
2258 }
2259 
2260 void
2261 PrivateScreen::configure (XConfigureEvent *ce)
2262 {
2263     if (attrib.width  != ce->width ||
2264 	attrib.height != ce->height)
2265     {
2266 	attrib.width  = ce->width;
2267 	attrib.height = ce->height;
2268     }
2269 
2270 	reshape (ce->width, ce->height);
2271 
2272 	detectOutputDevices (*this);
2273 
2274 	updateOutputDevices (*this);
2275 }
2276 
2277 void
2278 cps::EventManager::setSupportingWmCheck (Display* dpy, Window root)
2279 {
2280     XChangeProperty (dpy, grabWindow,
2281 		     Atoms::supportingWmCheck,
2282 		     XA_WINDOW, 32, PropModeReplace,
2283 		     (unsigned char *) &grabWindow, 1);
2284 
2285     XChangeProperty (dpy, grabWindow, Atoms::wmName,
2286 		     Atoms::utf8String, 8, PropModeReplace,
2287 		     (unsigned char *) PACKAGE, strlen (PACKAGE));
2288     XChangeProperty (dpy, grabWindow, Atoms::winState,
2289 		     XA_ATOM, 32, PropModeReplace,
2290 		     (unsigned char *) &Atoms::winStateSkipTaskbar,
2291 		     1);
2292     XChangeProperty (dpy, grabWindow, Atoms::winState,
2293 		     XA_ATOM, 32, PropModeAppend,
2294 		     (unsigned char *) &Atoms::winStateSkipPager, 1);
2295     XChangeProperty (dpy, grabWindow, Atoms::winState,
2296 		     XA_ATOM, 32, PropModeAppend,
2297 		     (unsigned char *) &Atoms::winStateHidden, 1);
2298 
2299     XChangeProperty (dpy, root, Atoms::supportingWmCheck,
2300 		     XA_WINDOW, 32, PropModeReplace,
2301 		     (unsigned char *) &grabWindow, 1);
2302 }
2303 
2304 void
2305 cps::EventManager::createGrabWindow (Display* dpy, Window root, XSetWindowAttributes* attrib)
2306 {
2307     grabWindow = XCreateWindow (dpy, root, -100, -100, 1, 1, 0,
2308 				  CopyFromParent, InputOnly, CopyFromParent,
2309 				  CWOverrideRedirect | CWEventMask,
2310 				  attrib);
2311     XMapWindow (dpy, grabWindow);
2312 }
2313 
2314 
2315 void
2316 CompScreenImpl::updateSupportedWmHints ()
2317 {
2318     std::vector<Atom> atoms;
2319 
2320     addSupportedAtoms (atoms);
2321 
2322     XChangeProperty (dpy (), root (), Atoms::supported,
2323 		     XA_ATOM, 32, PropModeReplace,
2324 		     (const unsigned char *) &atoms.at (0), atoms.size ());
2325 }
2326 
2327 void
2328 CompScreen::addSupportedAtoms (std::vector<Atom> &atoms)
2329 {
2330     WRAPABLE_HND_FUNCTN (addSupportedAtoms, atoms);
2331     _addSupportedAtoms (atoms);
2332 }
2333 
2334 void
2335 CompScreenImpl::_addSupportedAtoms (std::vector<Atom> &atoms)
2336 {
2337     atoms.push_back (Atoms::supported);
2338     atoms.push_back (Atoms::supportingWmCheck);
2339 
2340     atoms.push_back (Atoms::utf8String);
2341 
2342     atoms.push_back (Atoms::clientList);
2343     atoms.push_back (Atoms::clientListStacking);
2344 
2345     atoms.push_back (Atoms::winActive);
2346 
2347     atoms.push_back (Atoms::desktopViewport);
2348     atoms.push_back (Atoms::desktopGeometry);
2349     atoms.push_back (Atoms::currentDesktop);
2350     atoms.push_back (Atoms::numberOfDesktops);
2351     atoms.push_back (Atoms::showingDesktop);
2352 
2353     atoms.push_back (Atoms::workarea);
2354 
2355     atoms.push_back (Atoms::wmName);
2356 /*
2357     atoms.push_back (Atoms::wmVisibleName);
2358 */
2359 
2360     atoms.push_back (Atoms::wmStrut);
2361     atoms.push_back (Atoms::wmStrutPartial);
2362 
2363 /*
2364     atoms.push_back (Atoms::wmPid);
2365 */
2366 
2367     atoms.push_back (Atoms::wmUserTime);
2368     atoms.push_back (Atoms::frameExtents);
2369     atoms.push_back (Atoms::frameWindow);
2370 
2371     atoms.push_back (Atoms::winState);
2372     atoms.push_back (Atoms::winStateModal);
2373     atoms.push_back (Atoms::winStateSticky);
2374     atoms.push_back (Atoms::winStateMaximizedVert);
2375     atoms.push_back (Atoms::winStateMaximizedHorz);
2376     atoms.push_back (Atoms::winStateShaded);
2377     atoms.push_back (Atoms::winStateSkipTaskbar);
2378     atoms.push_back (Atoms::winStateSkipPager);
2379     atoms.push_back (Atoms::winStateHidden);
2380     atoms.push_back (Atoms::winStateFullscreen);
2381     atoms.push_back (Atoms::winStateAbove);
2382     atoms.push_back (Atoms::winStateBelow);
2383     atoms.push_back (Atoms::winStateDemandsAttention);
2384     atoms.push_back (Atoms::winStateFocused);
2385 
2386     atoms.push_back (Atoms::winOpacity);
2387     atoms.push_back (Atoms::winBrightness);
2388 
2389 /* FIXME */
2390 #if 0
2391     if (canDoSaturated)
2392     {
2393 	atoms.push_back (Atoms::winSaturation);
2394 	atoms.push_back (Atoms::winStateDisplayModal);
2395     }
2396 #endif
2397 
2398     atoms.push_back (Atoms::wmAllowedActions);
2399 
2400     atoms.push_back (Atoms::winActionMove);
2401     atoms.push_back (Atoms::winActionResize);
2402     atoms.push_back (Atoms::winActionStick);
2403     atoms.push_back (Atoms::winActionMinimize);
2404     atoms.push_back (Atoms::winActionMaximizeHorz);
2405     atoms.push_back (Atoms::winActionMaximizeVert);
2406     atoms.push_back (Atoms::winActionFullscreen);
2407     atoms.push_back (Atoms::winActionClose);
2408     atoms.push_back (Atoms::winActionShade);
2409     atoms.push_back (Atoms::winActionChangeDesktop);
2410     atoms.push_back (Atoms::winActionAbove);
2411     atoms.push_back (Atoms::winActionBelow);
2412 
2413     atoms.push_back (Atoms::winType);
2414     atoms.push_back (Atoms::winTypeDesktop);
2415     atoms.push_back (Atoms::winTypeDock);
2416     atoms.push_back (Atoms::winTypeToolbar);
2417     atoms.push_back (Atoms::winTypeMenu);
2418     atoms.push_back (Atoms::winTypeSplash);
2419     atoms.push_back (Atoms::winTypeDialog);
2420     atoms.push_back (Atoms::winTypeUtil);
2421     atoms.push_back (Atoms::winTypeNormal);
2422 
2423     atoms.push_back (Atoms::wmDeleteWindow);
2424     atoms.push_back (Atoms::wmPing);
2425 
2426     atoms.push_back (Atoms::wmMoveResize);
2427     atoms.push_back (Atoms::moveResizeWindow);
2428     atoms.push_back (Atoms::restackWindow);
2429 
2430     atoms.push_back (Atoms::wmFullscreenMonitors);
2431 }
2432 
2433 void
2434 PrivateScreen::getDesktopHints (unsigned int showingDesktopMask)
2435 {
2436     unsigned long data[2];
2437     Atom	  actual;
2438     int		  result, format;
2439     unsigned long n, left;
2440     unsigned char *propData;
2441 
2442     if (useDesktopHints)
2443     {
2444 	result = XGetWindowProperty (dpy, rootWindow(),
2445 				     Atoms::numberOfDesktops,
2446 				     0L, 1L, false, XA_CARDINAL, &actual,
2447 				     &format, &n, &left, &propData);
2448 
2449 	if (result == Success && propData)
2450 	{
2451 	    if (n)
2452 	    {
2453 		memcpy (data, propData, sizeof (unsigned long));
2454 		if (data[0] > 0 && data[0] < 0xffffffff)
2455 		    nDesktop = data[0];
2456 	    }
2457 
2458 	    XFree (propData);
2459 	}
2460 
2461 	result = XGetWindowProperty (dpy, rootWindow(),
2462 				     Atoms::desktopViewport, 0L, 2L,
2463 				     false, XA_CARDINAL, &actual, &format,
2464 				     &n, &left, &propData);
2465 
2466 	if (result == Success && propData)
2467 	{
2468 	    if (n == 2)
2469 	    {
2470 		memcpy (data, propData, sizeof (unsigned long) * 2);
2471 
2472 		if (data[0] / (unsigned int) screen->width () <
2473 					     (unsigned int) viewPort.vpSize.width () - 1)
2474 		    viewPort.vp.setX (data[0] / screen->width ());
2475 
2476 		if (data[1] / (unsigned int) screen->height () <
2477 					    (unsigned int) viewPort.vpSize.height () - 1)
2478 		    viewPort.vp.setY (data[1] / screen->height ());
2479 	    }
2480 
2481 	    XFree (propData);
2482 	}
2483 
2484 	result = XGetWindowProperty (dpy, rootWindow(),
2485 				     Atoms::currentDesktop,
2486 				     0L, 1L, false, XA_CARDINAL, &actual,
2487 				     &format, &n, &left, &propData);
2488 
2489 	if (result == Success && propData)
2490 	{
2491 	    if (n)
2492 	    {
2493 		memcpy (data, propData, sizeof (unsigned long));
2494 		if (data[0] < nDesktop)
2495 		    currentDesktop = data[0];
2496 	    }
2497 
2498 	    XFree (propData);
2499 	}
2500     }
2501 
2502     result = XGetWindowProperty (dpy, rootWindow(),
2503 				 Atoms::showingDesktop,
2504 				 0L, 1L, false, XA_CARDINAL, &actual, &format,
2505 				 &n, &left, &propData);
2506 
2507     if (result == Success && propData)
2508     {
2509 	if (n)
2510 	{
2511 	    memcpy (data, propData, sizeof (unsigned long));
2512 	    if (data[0])
2513 		screen->enterShowDesktopMode ();
2514 	}
2515 
2516 	XFree (propData);
2517     }
2518 
2519     data[0] = currentDesktop;
2520 
2521     XChangeProperty (dpy, rootWindow(), Atoms::currentDesktop,
2522 		     XA_CARDINAL, 32, PropModeReplace,
2523 		     (unsigned char *) data, 1);
2524 
2525     data[0] = showingDesktopMask ? true : false;
2526 
2527     XChangeProperty (dpy, rootWindow(), Atoms::showingDesktop,
2528 		     XA_CARDINAL, 32, PropModeReplace,
2529 		     (unsigned char *) data, 1);
2530 }
2531 
2532 void
2533 CompScreen::enterShowDesktopMode ()
2534 {
2535     WRAPABLE_HND_FUNCTN (enterShowDesktopMode)
2536     _enterShowDesktopMode ();
2537 }
2538 
2539 unsigned int CompScreenImpl::showingDesktopMask() const
2540 {
2541     return showingDesktopMask_;
2542 }
2543 
2544 bool CompScreenImpl::grabsEmpty() const
2545 {
2546     return privateScreen.eventManager.grabsEmpty();
2547 }
2548 
2549 void
2550 CompScreenImpl::_enterShowDesktopMode ()
2551 {
2552     unsigned long data = 1;
2553     int		  count = 0;
2554     bool          st = privateScreen.optionGetHideSkipTaskbarWindows ();
2555 
2556     showingDesktopMask_ = ~(CompWindowTypeDesktopMask |
2557 				 CompWindowTypeDockMask);
2558 
2559     for (cps::WindowManager::iterator i = windowManager.begin(); i != windowManager.end(); ++i)
2560     {
2561 	CompWindow* const w(*i);
2562 	if ((showingDesktopMask_ & w->wmType ()) &&
2563 	    (!(w->state () & CompWindowStateSkipTaskbarMask) || st))
2564 	{
2565 	    if (!w->inShowDesktopMode () && !w->grabbed () &&
2566 		w->managed () && w->focus ())
2567 	    {
2568 		w->setShowDesktopMode (true);
2569 		w->windowNotify (CompWindowNotifyEnterShowDesktopMode);
2570 		w->priv->hide ();
2571 	    }
2572 	}
2573 
2574 	if (w->inShowDesktopMode ())
2575 	    count++;
2576     }
2577 
2578     if (!count)
2579     {
2580 	showingDesktopMask_ = 0;
2581 	data = 0;
2582     }
2583 
2584     XChangeProperty (privateScreen.dpy, privateScreen.rootWindow(),
2585 		     Atoms::showingDesktop,
2586 		     XA_CARDINAL, 32, PropModeReplace,
2587 		     (unsigned char *) &data, 1);
2588 }
2589 
2590 void
2591 CompScreen::leaveShowDesktopMode (CompWindow *window)
2592 {
2593     WRAPABLE_HND_FUNCTN (leaveShowDesktopMode, window)
2594     _leaveShowDesktopMode (window);
2595 }
2596 
2597 void
2598 CompScreenImpl::_leaveShowDesktopMode (CompWindow *window)
2599 {
2600     unsigned long data = 0;
2601 
2602     if (window)
2603     {
2604 	if (!window->inShowDesktopMode ())
2605 	    return;
2606 
2607 	window->setShowDesktopMode (false);
2608 	window->windowNotify (CompWindowNotifyLeaveShowDesktopMode);
2609 	window->priv->show ();
2610 
2611 	/* return if some other window is still in show desktop mode */
2612 	for (cps::WindowManager::iterator i = windowManager.begin(); i != windowManager.end(); ++i)
2613 	{
2614 	    CompWindow* const w(*i);
2615 	    if (w->inShowDesktopMode ())
2616 		return;
2617 	}
2618 	showingDesktopMask_ = 0;
2619     }
2620     else
2621     {
2622 	showingDesktopMask_ = 0;
2623 
2624 	for (cps::WindowManager::iterator i = windowManager.begin(); i != windowManager.end(); ++i)
2625 	{
2626 	    CompWindow* const w(*i);
2627 	    if (!w->inShowDesktopMode ())
2628 		continue;
2629 
2630 	    w->setShowDesktopMode (false);
2631 	    w->windowNotify (CompWindowNotifyLeaveShowDesktopMode);
2632 	    w->priv->show ();
2633 	}
2634 
2635 	/* focus default window - most likely this will be the window
2636 	   which had focus before entering showdesktop mode */
2637 	focusDefaultWindow ();
2638     }
2639 
2640     XChangeProperty (privateScreen.dpy, privateScreen.rootWindow(),
2641 		     Atoms::showingDesktop,
2642 		     XA_CARDINAL, 32, PropModeReplace,
2643 		     (unsigned char *) &data, 1);
2644 }
2645 
2646 void
2647 CompScreenImpl::forEachWindow (CompWindow::ForEach proc)
2648 {
2649     windowManager.forEachWindow(proc);
2650 }
2651 
2652 void
2653 CompScreenImpl::focusDefaultWindow ()
2654 {
2655     CompWindow  *w;
2656     CompWindow  *focus = NULL;
2657 
2658     if (!privateScreen.optionGetClickToFocus ())
2659     {
2660 	w = findTopLevelWindow (below);
2661 
2662 	if (w && w->focus ())
2663 	{
2664 	    if (!(w->type () & (CompWindowTypeDesktopMask |
2665 				CompWindowTypeDockMask)))
2666 		focus = w;
2667 	}
2668 	else
2669 	{
2670 	    bool         status;
2671 	    Window       rootReturn, childReturn;
2672 	    int          dummyInt;
2673 	    unsigned int dummyUInt;
2674 
2675 	    /* huh, we didn't find d->below ... perhaps it's out of date;
2676 	       try grabbing it through the server */
2677 
2678 	    status = XQueryPointer (dpy (), privateScreen.rootWindow(), &rootReturn,
2679 				    &childReturn, &dummyInt, &dummyInt,
2680 				    &dummyInt, &dummyInt, &dummyUInt);
2681 
2682 	    if (status && rootReturn == privateScreen.rootWindow())
2683 	    {
2684 		w = findTopLevelWindow (childReturn);
2685 
2686 		if (w && w->focus ())
2687 		{
2688 		    if (!(w->type () & (CompWindowTypeDesktopMask |
2689 					CompWindowTypeDockMask)))
2690 			focus = w;
2691 		}
2692 	    }
2693 	}
2694     }
2695 
2696     if (!focus)
2697     {
2698 	/* Traverse down the stack */
2699 	for (cps::WindowManager::reverse_iterator rit = windowManager.rbegin();
2700 	     rit != windowManager.rend(); rit++)
2701 	{
2702 	    w = (*rit);
2703 
2704 	    if (w->type () & CompWindowTypeDockMask)
2705 		continue;
2706 
2707 	    if (w->focus ())
2708 	    {
2709 		if (focus)
2710 		{
2711 		    if (w->type () & (CompWindowTypeNormalMask |
2712 				      CompWindowTypeDialogMask |
2713 				      CompWindowTypeModalDialogMask))
2714 		    {
2715 			if (!privateScreen.optionGetClickToFocus ())
2716 			{
2717 			    /* We should favor the more active window in the mouse focus
2718 			     * case since the user does not care if the focused window is on top */
2719 			    if (PrivateWindow::compareWindowActiveness (focus, w) < 0)
2720 				focus = w;
2721 			}
2722 			else
2723 			{
2724 			    focus = w;
2725 			    break;
2726 			}
2727 		    }
2728 		}
2729 		else
2730 		{
2731 		    focus = w;
2732 
2733 		    if (privateScreen.optionGetClickToFocus ())
2734 			break;
2735 		}
2736 	    }
2737 	}
2738     }
2739 
2740     if (focus)
2741     {
2742 	if (focus->id () != privateScreen.orphanData.activeWindow)
2743 	    focus->moveInputFocusTo ();
2744     }
2745     else
2746     {
2747 	XSetInputFocus (privateScreen.dpy, privateScreen.rootWindow(), RevertToPointerRoot,
2748 			CurrentTime);
2749     }
2750 }
2751 
2752 CompWindow *
2753 CompScreenImpl::findWindow (Window id)
2754 {
2755     return windowManager.findWindow (id);
2756 }
2757 
2758 CompWindow*
2759 cps::WindowManager::findWindow (Window id) const
2760 {
2761     if (lastFoundWindow && lastFoundWindow->id () == id)
2762     {
2763 	return lastFoundWindow;
2764     }
2765     else
2766     {
2767         CompWindow::Map::const_iterator it = windowsMap.find (id);
2768 
2769         if (it != windowsMap.end ())
2770             return (lastFoundWindow = it->second);
2771     }
2772 
2773     return 0;
2774 }
2775 
2776 CompWindow *
2777 CompScreenImpl::findTopLevelWindow (Window id, bool override_redirect)
2778 {
2779     CompWindow *w;
2780 
2781     w = findWindow (id);
2782 
2783     if (w)
2784     {
2785 	if (w->overrideRedirect () && !override_redirect)
2786 	    return NULL;
2787 	else
2788 	    return w;
2789     }
2790 
2791     for (cps::WindowManager::iterator i = windowManager.begin(); i != windowManager.end(); ++i)
2792     {
2793 	CompWindow* const w(*i);
2794 	if (w->priv->serverFrame == id)
2795 	{
2796 	    if (w->overrideRedirect () && !override_redirect)
2797 		return NULL;
2798 	    else
2799 		return w;
2800 	}
2801     }
2802 
2803     return NULL;
2804 }
2805 
2806 void
2807 CompScreenImpl::insertWindow (CompWindow *w, Window	aboveId)
2808 {
2809     windowManager.insertWindow (w, aboveId);
2810 }
2811 void
2812 cps::WindowManager::insertWindow (CompWindow* w, Window aboveId)
2813 {
2814     StackDebugger *dbg = StackDebugger::Default ();
2815 
2816     if (dbg)
2817 	dbg->windowsChanged (true);
2818 
2819     invalidateServerWindows();
2820 
2821     w->prev = NULL;
2822     w->next = NULL;
2823 
2824     if (!aboveId || windows.empty ())
2825     {
2826 	if (!windows.empty ())
2827 	{
2828 	    windows.front ()->prev = w;
2829 	    w->next = windows.front ();
2830 	}
2831 	windows.push_front (w);
2832 
2833 	addWindowToMap(w);
2834 
2835 	return;
2836     }
2837 
2838     CompWindowList::iterator it = windows.begin ();
2839 
2840     while (it != windows.end ())
2841     {
2842 	if ((*it)->id () == aboveId ||
2843 	    ((*it)->priv->frame && (*it)->priv->frame == aboveId))
2844 	{
2845 	    break;
2846 	}
2847 	++it;
2848     }
2849 
2850     if (it == windows.end ())
2851     {
2852 	compLogMessage ("core", CompLogLevelDebug, "could not insert 0x%x above 0x%x",
2853 			(unsigned int) w->priv->serverId, aboveId);
2854 #ifdef DEBUG
2855 	abort ();
2856 #endif
2857 	return;
2858     }
2859 
2860     w->next = (*it)->next;
2861     w->prev = (*it);
2862     (*it)->next = w;
2863 
2864     if (w->next)
2865     {
2866 	w->next->prev = w;
2867     }
2868 
2869     windows.insert (++it, w);
2870     addWindowToMap(w);
2871 }
2872 
2873 void
2874 CompScreenImpl::insertServerWindow (CompWindow *w, Window	aboveId)
2875 {
2876     windowManager.insertServerWindow(w, aboveId);
2877 }
2878 
2879 void
2880 cps::WindowManager::insertServerWindow(CompWindow* w, Window aboveId)
2881 {
2882     StackDebugger *dbg = StackDebugger::Default ();
2883 
2884     if (dbg)
2885 	dbg->serverWindowsChanged (true);
2886 
2887     w->serverPrev = NULL;
2888     w->serverNext = NULL;
2889 
2890     if (!aboveId || serverWindows.empty ())
2891     {
2892 	if (!serverWindows.empty ())
2893 	{
2894 	    serverWindows.front ()->serverPrev = w;
2895 	    w->serverNext = serverWindows.front ();
2896 	}
2897 	serverWindows.push_front (w);
2898 
2899 	return;
2900     }
2901 
2902     CompWindowList::iterator it = serverWindows.begin ();
2903 
2904     while (it != serverWindows.end ())
2905     {
2906 	if ((*it)->priv->serverId == aboveId ||
2907 	    ((*it)->priv->serverFrame && (*it)->priv->serverFrame == aboveId))
2908 	{
2909 	    break;
2910 	}
2911 	++it;
2912     }
2913 
2914     if (it == serverWindows.end ())
2915     {
2916 	compLogMessage ("core", CompLogLevelWarn, "could not insert 0x%x above 0x%x",
2917 			(unsigned int) w->priv->serverId, aboveId);
2918 #ifdef DEBUG
2919 	abort ();
2920 #endif
2921 	return;
2922     }
2923 
2924     w->serverNext = (*it)->serverNext;
2925     w->serverPrev = (*it);
2926     (*it)->serverNext = w;
2927 
2928     if (w->serverNext)
2929     {
2930 	w->serverNext->serverPrev = w;
2931     }
2932 
2933     serverWindows.insert (++it, w);
2934 }
2935 
2936 void
2937 cps::WindowManager::eraseWindowFromMap (Window id)
2938 {
2939     if (id != 1)
2940         windowsMap.erase (id);
2941 }
2942 
2943 void
2944 CompScreenImpl::unhookWindow (CompWindow *w)
2945 {
2946     windowManager.unhookWindow (w);
2947 }
2948 
2949 void
2950 cps::WindowManager::unhookWindow(CompWindow* w)
2951 {
2952     StackDebugger *dbg = StackDebugger::Default ();
2953 
2954     if (dbg)
2955 	dbg->windowsChanged (true);
2956 
2957     CompWindowList::iterator it =
2958 	std::find (windows.begin(), windows.end(), w);
2959 
2960     if (it == windows.end())
2961     {
2962 	compLogMessage ("core", CompLogLevelWarn, "a broken plugin tried to remove a window twice, we won't allow that!");
2963 	return;
2964     }
2965 
2966     windows.erase (it);
2967     eraseWindowFromMap (w->id ());
2968 
2969     if (w->next)
2970 	w->next->prev = w->prev;
2971 
2972     if (w->prev)
2973 	w->prev->next = w->next;
2974 
2975     w->next = NULL;
2976     w->prev = NULL;
2977 
2978     removeFromFindWindowCache(w);
2979 }
2980 
2981 void
2982 CompScreenImpl::unhookServerWindow (CompWindow *w)
2983 {
2984     windowManager.unhookServerWindow (w);
2985 }
2986 
2987 void
2988 cps::WindowManager::unhookServerWindow (CompWindow *w)
2989 {
2990     StackDebugger *dbg = StackDebugger::Default ();
2991 
2992     if (dbg)
2993 	dbg->serverWindowsChanged (true);
2994 
2995     CompWindowList::iterator it =
2996 	std::find (serverWindows.begin (), serverWindows.end (), w);
2997 
2998     if (it == serverWindows.end ())
2999     {
3000 	compLogMessage ("core", CompLogLevelWarn, "a broken plugin tried to remove a window twice, we won't allow that!");
3001 	return;
3002     }
3003 
3004     serverWindows.erase (it);
3005 
3006     if (w->serverNext)
3007 	w->serverNext->serverPrev = w->serverPrev;
3008 
3009     if (w->serverPrev)
3010 	w->serverPrev->serverNext = w->serverNext;
3011 
3012     w->serverNext = NULL;
3013     w->serverPrev = NULL;
3014 }
3015 
3016 Cursor
3017 CompScreenImpl::normalCursor ()
3018 {
3019     return privateScreen.normalCursor;
3020 }
3021 
3022 Cursor
3023 CompScreenImpl::invisibleCursor ()
3024 {
3025     return privateScreen.invisibleCursor;
3026 }
3027 
3028 #define POINTER_GRAB_MASK (ButtonReleaseMask | \
3029 			   ButtonPressMask   | \
3030 			   PointerMotionMask)
3031 CompScreenImpl::GrabHandle
3032 CompScreenImpl::pushGrab (Cursor cursor, const char *name)
3033 {
3034     if (privateScreen.eventManager.grabsEmpty ())
3035     {
3036 	int status;
3037 
3038 	status = XGrabPointer (privateScreen.dpy, privateScreen.eventManager.getGrabWindow(), true,
3039 			       POINTER_GRAB_MASK,
3040 			       GrabModeAsync, GrabModeAsync,
3041 			       privateScreen.rootWindow(), cursor,
3042 			       CurrentTime);
3043 
3044 	if (status == GrabSuccess)
3045 	{
3046 	    status = XGrabKeyboard (privateScreen.dpy,
3047 				    privateScreen.eventManager.getGrabWindow(), true,
3048 				    GrabModeAsync, GrabModeAsync,
3049 				    CurrentTime);
3050 	    if (status != GrabSuccess)
3051 	    {
3052 		XUngrabPointer (privateScreen.dpy, CurrentTime);
3053 		return NULL;
3054 	    }
3055 	}
3056 	else
3057 	    return NULL;
3058     }
3059     else
3060     {
3061 	XChangeActivePointerGrab (privateScreen.dpy, POINTER_GRAB_MASK,
3062 				  cursor, CurrentTime);
3063     }
3064 
3065     cps::Grab *grab = new cps::Grab (cursor, name);
3066     privateScreen.eventManager.grabsPush (grab);
3067 
3068     return grab;
3069 }
3070 
3071 void
3072 CompScreenImpl::updateGrab (CompScreen::GrabHandle handle, Cursor cursor)
3073 {
3074     if (!handle)
3075 	return;
3076 
3077     XChangeActivePointerGrab (privateScreen.dpy, POINTER_GRAB_MASK,
3078 			      cursor, CurrentTime);
3079 
3080     handle->cursor = cursor;
3081 }
3082 
3083 void
3084 CompScreenImpl::removeGrab (CompScreen::GrabHandle handle,
3085 			CompPoint *restorePointer)
3086 {
3087     if (!handle)
3088 	return;
3089 
3090     privateScreen.eventManager.grabsRemove(handle);
3091 
3092     if (!privateScreen.eventManager.grabsEmpty ())
3093     {
3094 	XChangeActivePointerGrab (privateScreen.dpy,
3095 				  POINTER_GRAB_MASK,
3096 				  privateScreen.eventManager.grabsBack ()->cursor,
3097 				  CurrentTime);
3098     }
3099     else
3100     {
3101 	if (restorePointer)
3102 	    warpPointer (restorePointer->x () - pointerX,
3103 			 restorePointer->y () - pointerY);
3104 
3105 	XUngrabPointer (privateScreen.dpy, CurrentTime);
3106 	XUngrabKeyboard (privateScreen.dpy, CurrentTime);
3107     }
3108 }
3109 
3110 void
3111 cps::GrabList::grabsRemove(Grab* handle)
3112 {
3113     GrabIterator it = std::find (grabsBegin (), grabsEnd (), handle);
3114 
3115     if (it != grabsEnd ())
3116     {
3117 	grabs.erase (it);
3118 	delete (handle);
3119     }
3120 }
3121 
3122 /* otherScreenGrabExist takes a series of strings terminated by a NULL.
3123    It returns true if a grab exists but it is NOT held by one of the
3124    plugins listed, returns false otherwise. */
3125 
3126 bool
3127 CompScreenImpl::otherGrabExist (const char *first, ...)
3128 {
3129     va_list    ap;
3130     const char *name;
3131 
3132     std::list<cps::Grab *>::iterator it;
3133 
3134     for (it = privateScreen.eventManager.grabsBegin (); it != privateScreen.eventManager.grabsEnd (); ++it)
3135     {
3136 	va_start (ap, first);
3137 
3138 	name = first;
3139 	while (name)
3140 	{
3141 	    if (strcmp (name, (*it)->name) == 0)
3142 		break;
3143 
3144 	    name = va_arg (ap, const char *);
3145 	}
3146 
3147 	va_end (ap);
3148 
3149 	if (!name)
3150 	return true;
3151     }
3152 
3153     return false;
3154 }
3155 
3156 bool
3157 CompScreenImpl::grabExist (const char *grab)
3158 {
3159     return privateScreen.eventManager.grabExist (grab);
3160 }
3161 
3162 bool
3163 cps::GrabList::grabExist (const char *grab)
3164 {
3165     foreach (cps::Grab* g, grabs)
3166     {
3167 	if (strcmp (g->name, grab) == 0)
3168 	    return true;
3169     }
3170     return false;
3171 }
3172 
3173 bool
3174 CompScreenImpl::grabbed ()
3175 {
3176     return privateScreen.eventManager.isGrabbed();
3177 }
3178 
3179 void
3180 cps::GrabManager::grabUngrabOneKey (unsigned int modifiers,
3181 				 int          keycode,
3182 				 bool         grab)
3183 {
3184     if (grab)
3185     {
3186 	/*
3187 	 * Always grab the keyboard Sync-ronously. This is so that we can
3188 	 * choose to ReplayKeyboard in alwaysHandleEvent if need be.
3189 	 */
3190 	XGrabKey (screen->dpy(),
3191 		  keycode,
3192 		  modifiers,
3193 		  screen->root(),
3194 		  true,
3195 		  GrabModeAsync,
3196 		  GrabModeSync);
3197     }
3198     else
3199     {
3200 	XUngrabKey (screen->dpy(),
3201 		    keycode,
3202 		    modifiers,
3203 		    screen->root());
3204     }
3205 }
3206 
3207 bool
3208 cps::GrabManager::grabUngrabKeys (unsigned int modifiers,
3209 			       int          keycode,
3210 			       bool         grab)
3211 {
3212     int             mod, k;
3213     unsigned int    ignore;
3214 
3215     CompScreen::checkForError (screen->dpy());
3216 
3217     for (ignore = 0; ignore <= modHandler->ignoredModMask (); ignore++)
3218     {
3219 	if (ignore & ~modHandler->ignoredModMask ())
3220 	    continue;
3221 
3222 	if (keycode != 0)
3223 	{
3224 	    grabUngrabOneKey (modifiers | ignore, keycode, grab);
3225 	}
3226 	else
3227 	{
3228 	    for (mod = 0; mod < 8; mod++)
3229 	    {
3230 		if (modifiers & (1 << mod))
3231 		{
3232 		    for (k = mod * modHandler->modMap ()->max_keypermod;
3233 			 k < (mod + 1) * modHandler->modMap ()->max_keypermod;
3234 			 k++)
3235 		    {
3236 			if (modHandler->modMap ()->modifiermap[k])
3237 			{
3238 			    grabUngrabOneKey ((modifiers & ~(1 << mod)) |
3239 					      ignore,
3240 					      modHandler->modMap ()->modifiermap[k],
3241 					      grab);
3242 			}
3243 		    }
3244 		}
3245 	    }
3246 
3247 	    /*
3248 	     * keycode == 0, so this is a modifier-only keybinding.
3249 	     * Until now I have been trying to:
3250 	     *     grabUngrabOneKey (modifiers | ignore, AnyKey, grab);
3251 	     * which does not seem to work at all.
3252 	     * However, binding to each keycode individually does work.
3253 	     * This is so that we can detect taps on individual modifier
3254 	     * keys, and know to cancel the tap if <modifier>+k is pressed.
3255 	     */
3256 	    if (!(currentState & CompAction::StateIgnoreTap))
3257             {
3258  		int minCode, maxCode;
3259  		XDisplayKeycodes (screen->dpy(), &minCode, &maxCode);
3260  		for (k = minCode; k <= maxCode; k++)
3261  		    grabUngrabOneKey (modifiers | ignore, k, grab);
3262             }
3263 	}
3264 
3265 	if (CompScreen::checkForError (screen->dpy()))
3266 	    return false;
3267     }
3268 
3269     return true;
3270 }
3271 
3272 bool
3273 cps::GrabManager::addPassiveKeyGrab (CompAction::KeyBinding &key)
3274 {
3275     KeyGrab                      newKeyGrab;
3276     unsigned int                 mask;
3277     std::list<KeyGrab>::iterator it;
3278 
3279     mask = modHandler->virtualToRealModMask (key.modifiers ());
3280 
3281     for (it = keyGrabs.begin (); it != keyGrabs.end (); ++it)
3282     {
3283 	if (key.keycode () == (*it).keycode &&
3284 	    mask           == (*it).modifiers)
3285 	{
3286 	    (*it).count++;
3287 	    return true;
3288 	}
3289     }
3290 
3291 
3292 
3293     if (!(mask & CompNoMask))
3294     {
3295 	if (!grabUngrabKeys (mask, key.keycode (), true))
3296 	    return false;
3297     }
3298 
3299     newKeyGrab.keycode   = key.keycode ();
3300     newKeyGrab.modifiers = mask;
3301     newKeyGrab.count     = 1;
3302 
3303     keyGrabs.push_back (newKeyGrab);
3304 
3305     return true;
3306 }
3307 
3308 void
3309 cps::GrabManager::removePassiveKeyGrab (CompAction::KeyBinding &key)
3310 {
3311     unsigned int                 mask;
3312     std::list<KeyGrab>::iterator it;
3313 
3314     mask = modHandler->virtualToRealModMask (key.modifiers ());
3315 
3316     for (it = keyGrabs.begin (); it != keyGrabs.end (); ++it)
3317     {
3318 	if (key.keycode () == (*it).keycode &&
3319 	    mask           == (*it).modifiers)
3320 	{
3321 	    (*it).count--;
3322 	    if ((*it).count)
3323 		return;
3324 
3325 	    it = keyGrabs.erase (it);
3326 
3327 	    if (!(mask & CompNoMask))
3328 		grabUngrabKeys (mask, key.keycode (), false);
3329 	}
3330     }
3331 
3332     /*
3333      * Removing modifier-only grabs is tricky. Because it also removes grabs
3334      * for modifier+all_other_keys. See XDisplayKeycodes above to find out why.
3335      * So we need to refresh all grabs...
3336      */
3337     if (!(mask & CompNoMask) && key.keycode () == 0)
3338 	updatePassiveKeyGrabs ();
3339 }
3340 
3341 void
3342 cps::GrabManager::updatePassiveKeyGrabs ()
3343 {
3344     std::list<cps::KeyGrab>::iterator it;
3345 
3346     XUngrabKey (screen->dpy(), AnyKey, AnyModifier, screen->root());
3347 
3348     for (it = keyGrabs.begin (); it != keyGrabs.end (); ++it)
3349     {
3350 	if (!((*it).modifiers & CompNoMask))
3351 	{
3352 	    grabUngrabKeys ((*it).modifiers,
3353 			    (*it).keycode, true);
3354 	}
3355     }
3356 }
3357 
3358 bool
3359 cps::GrabManager::addPassiveButtonGrab (CompAction::ButtonBinding &button)
3360 {
3361     ButtonGrab                      newButtonGrab;
3362     std::list<ButtonGrab>::iterator it;
3363 
3364     for (it = buttonGrabs.begin (); it != buttonGrabs.end (); ++it)
3365     {
3366 	if (button.button ()    == (*it).button &&
3367 	    button.modifiers () == (*it).modifiers)
3368 	{
3369 	    (*it).count++;
3370 	    return true;
3371 	}
3372     }
3373 
3374     newButtonGrab.button    = button.button ();
3375     newButtonGrab.modifiers = button.modifiers ();
3376     newButtonGrab.count     = 1;
3377 
3378     buttonGrabs.push_back (newButtonGrab);
3379 
3380     foreach (CompWindow *w, screen->windows ())
3381 	w->priv->updatePassiveButtonGrabs ();
3382 
3383     return true;
3384 }
3385 
3386 void cps::GrabManager::updatePassiveButtonGrabs(Window serverFrame)
3387 {
3388     /* Grab only we have bindings on */
3389     foreach (ButtonGrab &bind, buttonGrabs)
3390     {
3391 	unsigned int mods = modHandler->virtualToRealModMask (bind.modifiers);
3392 
3393 	if (mods & CompNoMask)
3394 	    continue;
3395 
3396 	for (unsigned int ignore = 0;
3397 		 ignore <= modHandler->ignoredModMask (); ignore++)
3398 	{
3399 	    if (ignore & ~modHandler->ignoredModMask ())
3400 		continue;
3401 
3402 	    XGrabButton (screen->dpy(),
3403 			 bind.button,
3404 			 mods | ignore,
3405 			 serverFrame,
3406 			 false,
3407 			 ButtonPressMask | ButtonReleaseMask |
3408 			    ButtonMotionMask,
3409 			 GrabModeSync,
3410 			 GrabModeAsync,
3411 			 None,
3412 			 None);
3413 	}
3414     }
3415 }
3416 
3417 void
3418 cps::GrabManager::removePassiveButtonGrab (CompAction::ButtonBinding &button)
3419 {
3420     std::list<ButtonGrab>::iterator it;
3421 
3422     for (it = buttonGrabs.begin (); it != buttonGrabs.end (); ++it)
3423     {
3424 	if (button.button ()    == (*it).button &&
3425 	    button.modifiers () == (*it).modifiers)
3426 	{
3427 	    (*it).count--;
3428 	    if ((*it).count)
3429 		return;
3430 
3431 	    it = buttonGrabs.erase (it);
3432 
3433 	    foreach (CompWindow *w, screen->windows ())
3434 		w->priv->updatePassiveButtonGrabs ();
3435 	}
3436     }
3437 }
3438 
3439 void
3440 cps::GrabManager::setCurrentState (CompAction::State state)
3441 {
3442     currentState = state;
3443 }
3444 
3445 bool
3446 CompScreenImpl::addAction (CompAction *action)
3447 {
3448     assert (privateScreen.initialized);
3449     if (!privateScreen.initialized)
3450 	return false;
3451 
3452     if (action->active ())
3453 	return false;
3454 
3455     grabManager.setCurrentState(action->state());
3456 
3457     if (action->type () & CompAction::BindingTypeKey)
3458     {
3459 	if (!grabManager.addPassiveKeyGrab (action->key ()))
3460 	    return false;
3461     }
3462 
3463     if (action->type () & CompAction::BindingTypeButton)
3464     {
3465 	if (!grabManager.addPassiveButtonGrab (action->button ()))
3466 	{
3467 	    if (action->type () & CompAction::BindingTypeKey)
3468 		grabManager.removePassiveKeyGrab (action->key ());
3469 
3470 	    return false;
3471 	}
3472     }
3473 
3474     if (action->edgeMask ())
3475     {
3476 	for (int i = 0; i < SCREEN_EDGE_NUM; i++)
3477 	    if (action->edgeMask () & (1 << i))
3478 		privateScreen.enableEdge (i);
3479     }
3480 
3481     ca::setActionActiveState (*action, true);
3482 
3483     return true;
3484 }
3485 
3486 void
3487 CompScreenImpl::removeAction (CompAction *action)
3488 {
3489     if (!(privateScreen.initialized || action->active ()))
3490 	return;
3491 
3492     grabManager.setCurrentState(action->state());
3493 
3494     if (action->type () & CompAction::BindingTypeKey)
3495 	grabManager.removePassiveKeyGrab (action->key ());
3496 
3497     if (action->type () & CompAction::BindingTypeButton)
3498 	grabManager.removePassiveButtonGrab (action->button ());
3499 
3500     if (action->edgeMask ())
3501     {
3502 	for (int i = 0; i < SCREEN_EDGE_NUM; i++)
3503 	    if (action->edgeMask () & (1 << i))
3504 		privateScreen.disableEdge (i);
3505     }
3506 
3507     ca::setActionActiveState (*action, false);
3508 }
3509 
3510 void
3511 CompScreenImpl::updateWorkarea ()
3512 {
3513     CompRect workArea;
3514     CompRegion allWorkArea = CompRegion ();
3515     bool     workAreaChanged = false;
3516     privateScreen.outputDevices.computeWorkAreas(
3517 	    workArea,
3518 	    workAreaChanged,
3519 	    allWorkArea,
3520 	    windowManager.getWindows());
3521 
3522     workArea = allWorkArea.boundingRect ();
3523 
3524     if (privateScreen.workArea != workArea)
3525     {
3526 	workAreaChanged = true;
3527 	privateScreen.workArea = workArea;
3528 
3529 	privateScreen.setDesktopHints ();
3530     }
3531 
3532     if (workAreaChanged)
3533     {
3534 	/* as work area changed, update all maximized windows on this
3535 	   screen to snap to the new work area */
3536 	windowManager.updateWindowSizes();
3537     }
3538 }
3539 
3540 static bool
3541 isClientListWindow (CompWindow *w)
3542 {
3543     /* windows with client id less than 2 have been destroyed and only exists
3544        because some plugin keeps a reference to them. they should not be in
3545        client lists */
3546     if (w->id () < 2)
3547 	return false;
3548 
3549     if (w->overrideRedirect ())
3550 	return false;
3551 
3552     if (!w->isViewable ())
3553     {
3554 	if (!(w->state () & CompWindowStateHiddenMask))
3555 	    return false;
3556     }
3557 
3558     return true;
3559 }
3560 
3561 static void
3562 countClientListWindow (CompWindow *w,
3563 		       int        *n)
3564 {
3565     if (isClientListWindow (w))
3566     {
3567 	*n = *n + 1;
3568     }
3569 }
3570 
3571 static bool
3572 compareMappingOrder (const CompWindow *w1,
3573 		     const CompWindow *w2)
3574 {
3575     return w1->mapNum () < w2->mapNum ();
3576 }
3577 
3578 void
3579 cps::WindowManager::updateClientList (PrivateScreen& ps)
3580 {
3581     bool   updateClientList = false;
3582     bool   updateClientListStacking = false;
3583     int	   n = 0;
3584 
3585     screen->forEachWindow (boost::bind (countClientListWindow, _1, &n));
3586 
3587     if (n == 0)
3588     {
3589 	if ((unsigned int) n != clientList.size ())
3590 	{
3591 	    clientList.clear ();
3592 	    clientListStacking.clear ();
3593 	    clientIdList.clear ();
3594 	    clientIdListStacking.clear ();
3595 
3596 	    XChangeProperty (ps.dpy, ps.rootWindow(),
3597 			     Atoms::clientList,
3598 			     XA_WINDOW, 32, PropModeReplace,
3599 			     (unsigned char *) &ps.eventManager.getGrabWindow(), 1);
3600 	    XChangeProperty (ps.dpy, ps.rootWindow(),
3601 			     Atoms::clientListStacking,
3602 			     XA_WINDOW, 32, PropModeReplace,
3603 			     (unsigned char *) &ps.eventManager.getGrabWindow(), 1);
3604 	}
3605 
3606 	return;
3607     }
3608 
3609     if ((unsigned int) n != clientList.size ())
3610     {
3611 	clientIdList.resize (n);
3612 	clientIdListStacking.resize (n);
3613 
3614 	updateClientList = updateClientListStacking = true;
3615     }
3616 
3617     clientListStacking.clear ();
3618 
3619     for (iterator i = begin(); i != end(); ++i)
3620     {
3621 	CompWindow* const w(*i);
3622 	if (isClientListWindow (w))
3623 	    clientListStacking.push_back (w);
3624     }
3625 
3626     /* clear clientList and copy clientListStacking into clientList */
3627     clientList = clientListStacking;
3628 
3629     /* sort clientList in mapping order */
3630     sort (clientList.begin (), clientList.end (),
3631 	  compareMappingOrder);
3632 
3633     /* make sure client id lists are up-to-date */
3634     for (int i = 0; i < n; i++)
3635     {
3636 	if (!updateClientList &&
3637 	    clientIdList[i] != clientList[i]->id ())
3638 	{
3639 	    updateClientList = true;
3640 	}
3641 
3642 	clientIdList[i] = clientList[i]->id ();
3643     }
3644     for (int i = 0; i < n; i++)
3645     {
3646 	if (!updateClientListStacking &&
3647 	    clientIdListStacking[i] != clientListStacking[i]->id ())
3648 	{
3649 	    updateClientListStacking = true;
3650 	}
3651 
3652 	clientIdListStacking[i] = clientListStacking[i]->id ();
3653     }
3654 
3655     if (updateClientList)
3656 	XChangeProperty (ps.dpy, ps.rootWindow(),
3657 			 Atoms::clientList,
3658 			 XA_WINDOW, 32, PropModeReplace,
3659 			 (unsigned char *) &clientIdList.at (0), n);
3660 
3661     if (updateClientListStacking)
3662 	XChangeProperty (ps.dpy, ps.rootWindow(),
3663 			 Atoms::clientListStacking,
3664 			 XA_WINDOW, 32, PropModeReplace,
3665 			 (unsigned char *) &clientIdListStacking.at (0),
3666 			 n);
3667 }
3668 
3669 const CompWindowVector &
3670 CompScreenImpl::clientList (bool stackingOrder)
3671 {
3672    return stackingOrder ? windowManager.getClientListStacking() : windowManager.getClientList();
3673 }
3674 
3675 void
3676 CompScreenImpl::toolkitAction (Atom   toolkitAction,
3677 			   Time   eventTime,
3678 			   Window window,
3679 			   long   data0,
3680 			   long   data1,
3681 			   long   data2)
3682 {
3683     XEvent ev;
3684 
3685     ev.type		    = ClientMessage;
3686     ev.xclient.window	    = window;
3687     ev.xclient.message_type = Atoms::toolkitAction;
3688     ev.xclient.format	    = 32;
3689     ev.xclient.data.l[0]    = toolkitAction;
3690     ev.xclient.data.l[1]    = eventTime;
3691     ev.xclient.data.l[2]    = data0;
3692     ev.xclient.data.l[3]    = data1;
3693     ev.xclient.data.l[4]    = data2;
3694 
3695     XUngrabPointer (privateScreen.dpy, CurrentTime);
3696     XUngrabKeyboard (privateScreen.dpy, CurrentTime);
3697 
3698     XSendEvent (privateScreen.dpy, privateScreen.rootWindow(), false,
3699 		StructureNotifyMask, &ev);
3700 }
3701 
3702 void
3703 CompScreenImpl::runCommand (CompString command)
3704 {
3705     if (command.size () == 0)
3706 	return;
3707 
3708     if (fork () == 0)
3709     {
3710 	size_t       pos;
3711 	CompString   env (privateScreen.displayString ());
3712 
3713 	setsid ();
3714 
3715 	pos = env.find (':');
3716 	if (pos != std::string::npos)
3717 	{
3718             size_t pointPos = env.find ('.', pos);
3719 
3720 	    if (pointPos != std::string::npos)
3721 	    {
3722 		env.erase (pointPos);
3723 	    }
3724 	    else
3725 	    {
3726                 unsigned int displayNum = atoi (env.substr (pos + 1).c_str ());
3727 		env.erase (pos);
3728 		env.append (compPrintf (":%i", displayNum));
3729 	    }
3730 	}
3731 
3732 	env.append (compPrintf (".%d", privateScreen.screenNum));
3733 
3734 	putenv (strdup (env.c_str ()));  // parameter needs to be leaked!
3735 
3736 	exit (execl ("/bin/sh", "/bin/sh", "-c", command.c_str (), NULL));
3737     }
3738 }
3739 
3740 void
3741 CompScreenImpl::moveViewport (int tx, int ty, bool sync)
3742 {
3743     CompPoint pnt;
3744 
3745     tx = privateScreen.viewPort.vp.x () - tx;
3746     tx = compiz::core::screen::wraparound_mod (tx, privateScreen.viewPort.vpSize.width ());
3747     tx -= privateScreen.viewPort.vp.x ();
3748 
3749     ty = privateScreen.viewPort.vp.y () - ty;
3750     ty = compiz::core::screen::wraparound_mod (ty, privateScreen.viewPort.vpSize.height ());
3751     ty -= privateScreen.viewPort.vp.y ();
3752 
3753     if (!tx && !ty)
3754 	return;
3755 
3756     privateScreen.viewPort.vp.setX (privateScreen.viewPort.vp.x () + tx);
3757     privateScreen.viewPort.vp.setY (privateScreen.viewPort.vp.y () + ty);
3758 
3759     tx *= -width ();
3760     ty *= -height ();
3761 
3762     for (cps::WindowManager::iterator i = windowManager.begin(); i != windowManager.end(); ++i)
3763     {
3764 	CompWindow* const w(*i);
3765 	unsigned int valueMask = CWX | CWY;
3766 	XWindowChanges xwc= XWINDOWCHANGES_INIT;
3767 
3768 	if (w->onAllViewports ())
3769 	    continue;
3770 
3771 	pnt = w->getMovementForOffset (CompPoint (tx, ty));
3772 
3773 	if (w->saveMask () & CWX)
3774 	    w->saveWc ().x += pnt.x ();
3775 
3776 	if (w->saveMask () & CWY)
3777 	    w->saveWc ().y += pnt.y ();
3778 
3779 	xwc.x = w->serverGeometry ().x () + pnt.x ();
3780 	xwc.y = w->serverGeometry ().y () + pnt.y ();
3781 
3782 	w->configureXWindow (valueMask, &xwc);
3783     }
3784 
3785     if (sync)
3786     {
3787 	CompWindow *w;
3788 
3789 	privateScreen.setDesktopHints ();
3790 
3791 	setCurrentActiveWindowHistory (privateScreen.viewPort.vp.x (), privateScreen.viewPort.vp.y ());
3792 
3793 	w = findWindow (privateScreen.orphanData.activeWindow);
3794 	if (w)
3795 	{
3796 	    CompPoint dvp;
3797 
3798 	    dvp = w->defaultViewport ();
3799 
3800 	    /* add window to current history if it's default viewport is
3801 	       still the current one. */
3802 	    if (privateScreen.viewPort.vp.x () == dvp.x () && privateScreen.viewPort.vp.y () == dvp.y ())
3803 		addToCurrentActiveWindowHistory (w->id ());
3804 	}
3805     }
3806 }
3807 
3808 CompGroup *
3809 cps::WindowManager::addGroup (Window id)
3810 {
3811     CompGroup *group = new CompGroup ();
3812 
3813     group->refCnt = 1;
3814     group->id     = id;
3815 
3816     groups.push_back (group);
3817 
3818     return group;
3819 }
3820 
3821 void
3822 cps::WindowManager::removeGroup (CompGroup *group)
3823 {
3824     group->refCnt--;
3825     if (group->refCnt)
3826 	return;
3827 
3828     std::list<CompGroup *>::iterator it =
3829 	std::find (groups.begin (), groups.end (), group);
3830 
3831     if (it != groups.end ())
3832     {
3833 	groups.erase (it);
3834     }
3835 
3836     delete group;
3837 }
3838 
3839 CompGroup *
3840 cps::WindowManager::findGroup (Window id)
3841 {
3842     foreach (CompGroup *g, groups)
3843 	if (g->id == id)
3844 	    return g;
3845 
3846     return NULL;
3847 }
3848 
3849 void
3850 cps::StartupSequence::applyStartupProperties (CompScreen* screen, CompWindow *window)
3851 {
3852     CompStartupSequence *s = NULL;
3853     const char	        *startupId = window->startupId ();
3854 
3855     if (!startupId)
3856     {
3857 	CompWindow *leader;
3858 
3859 	leader = screen->findWindow (window->clientLeader ());
3860 	if (leader)
3861 	    startupId = leader->startupId ();
3862 
3863 	if (!startupId)
3864 	    return;
3865     }
3866 
3867     foreach (CompStartupSequence *ss, startupSequences)
3868     {
3869 	const char *id;
3870 
3871 	id = sn_startup_sequence_get_id (ss->sequence);
3872 	if (strcmp (id, startupId) == 0)
3873 	{
3874 	    s = ss;
3875 	    break;
3876 	}
3877     }
3878 
3879     if (s)
3880 	window->priv->applyStartupProperties (s);
3881 }
3882 
3883 void
3884 CompScreenImpl::sendWindowActivationRequest (Window id)
3885 {
3886     XEvent xev;
3887 
3888     xev.xclient.type    = ClientMessage;
3889     xev.xclient.display = privateScreen.dpy;
3890     xev.xclient.format  = 32;
3891 
3892     xev.xclient.message_type = Atoms::winActive;
3893     xev.xclient.window	     = id;
3894 
3895     xev.xclient.data.l[0] = ClientTypePager;
3896     xev.xclient.data.l[1] = 0;
3897     xev.xclient.data.l[2] = 0;
3898     xev.xclient.data.l[3] = 0;
3899     xev.xclient.data.l[4] = 0;
3900 
3901     XSendEvent (privateScreen.dpy, privateScreen.rootWindow(), false,
3902 		SubstructureRedirectMask | SubstructureNotifyMask, &xev);
3903 }
3904 
3905 void
3906 PrivateScreen::enableEdge (int edge)
3907 {
3908     screenEdge[edge].count++;
3909     if (screenEdge[edge].count == 1)
3910 	XMapRaised (dpy, screenEdge[edge].id);
3911 }
3912 
3913 void
3914 PrivateScreen::disableEdge (int edge)
3915 {
3916     screenEdge[edge].count--;
3917     if (screenEdge[edge].count == 0)
3918 	XUnmapWindow (dpy, screenEdge[edge].id);
3919 }
3920 
3921 CompWindow *
3922 cps::WindowManager::getTopWindow() const
3923 {
3924     /* return first window that has not been destroyed */
3925     if (!windows.empty ())
3926 	return windows.back ();
3927 
3928     return NULL;
3929 }
3930 
3931 CompWindow *
3932 cps::WindowManager::getTopServerWindow () const
3933 {
3934     if (!serverWindows.empty ())
3935 	return serverWindows.back ();
3936 
3937     return NULL;
3938 }
3939 
3940 int
3941 CompScreenImpl::outputDeviceForPoint (const CompPoint &point)
3942 {
3943     return outputDeviceForPoint (point.x (), point.y ());
3944 }
3945 
3946 int
3947 CompScreenImpl::outputDeviceForPoint (int x, int y)
3948 {
3949     CompWindow::Geometry geom (x, y, 1, 1, 0);
3950 
3951     return outputDeviceForGeometry (geom);
3952 }
3953 
3954 CompRect
3955 CompScreenImpl::getCurrentOutputExtents ()
3956 {
3957     return privateScreen.outputDevices.getCurrentOutputDev ();
3958 }
3959 
3960 void
3961 PrivateScreen::setNumberOfDesktops (unsigned int nDesktop)
3962 {
3963     if (nDesktop < 1 || nDesktop >= 0xffffffff || nDesktop == this->nDesktop)
3964 	return;
3965 
3966     if (currentDesktop >= nDesktop)
3967 	currentDesktop = nDesktop - 1;
3968 
3969     windowManager.setNumberOfDesktops(nDesktop);
3970 
3971     this->nDesktop = nDesktop;
3972 
3973     setDesktopHints ();
3974 }
3975 
3976 void
3977 PrivateScreen::setCurrentDesktop (unsigned int desktop)
3978 {
3979     if (desktop >= nDesktop || desktop == currentDesktop)
3980 	return;
3981 
3982     currentDesktop = desktop;
3983 
3984     windowManager.showOrHideForDesktop(desktop);
3985 
3986     unsigned long data = desktop;
3987 
3988     XChangeProperty (dpy, rootWindow(), Atoms::currentDesktop,
3989 		     XA_CARDINAL, 32, PropModeReplace,
3990 		     (unsigned char *) &data, 1);
3991 }
3992 
3993 const CompRect&
3994 CompScreenImpl::getWorkareaForOutput (unsigned int outputNum) const
3995 {
3996     return privateScreen.outputDevices.getOutputDev (outputNum).workArea ();
3997 }
3998 
3999 void
4000 CompScreen::outputChangeNotify ()
4001 {
4002     WRAPABLE_HND_FUNCTN (outputChangeNotify);
4003     _outputChangeNotify ();
4004 }
4005 
4006 void
4007 CompScreenImpl::_outputChangeNotify ()
4008 {
4009 }
4010 
4011 /* Returns default viewport for some window geometry. If the window spans
4012  * more than one viewport the most appropriate viewport is returned. How the
4013  * most appropriate viewport is computed can be made optional if necessary. It
4014  * is currently computed as the viewport where the center of the window is
4015  * located.
4016  *
4017  * XXX: It is possible for this function to return a negative viewport, which
4018  * definitely feels wrong, however it seems that some plugins depend on this behaviour
4019  * so they need to be fixed first
4020  */
4021 void
4022 compiz::private_screen::viewports::viewportForGeometry (const CompWindow::Geometry &gm,
4023 							CompPoint                  &viewport,
4024 							ViewportRetrievalInterface *viewports,
4025 							const CompSize &           screenSize)
4026 {
4027     CompRect rect (gm);
4028     int      offset;
4029 
4030     const CompPoint &vp = viewports->getCurrentViewport ();
4031     const CompSize &vpSize = viewports->viewportDimensions ();
4032 
4033     rect.setWidth  (gm.widthIncBorders ());
4034     rect.setHeight (gm.heightIncBorders ());
4035 
4036     offset = rect.centerX () < 0 ? -1 : 0;
4037     viewport.setX (vp.x () + ((rect.centerX () / screenSize.width ()) + offset) % vpSize.width ());
4038 
4039     offset = rect.centerY () < 0 ? -1 : 0;
4040     viewport.setY (vp.y () + ((rect.centerY () / screenSize.height ()) + offset ) % vpSize.height ());
4041 }
4042 
4043 void
4044 CompScreenImpl::viewportForGeometry (const CompWindow::Geometry& gm,
4045 				     CompPoint&                  viewport)
4046 {
4047     compiz::private_screen::viewports::viewportForGeometry (gm, viewport, &privateScreen.viewPort, *this);
4048 }
4049 
4050 int
4051 CompScreenImpl::outputDeviceForGeometry (const CompWindow::Geometry& gm)
4052 {
4053     return privateScreen.outputDevices.outputDeviceForGeometry (gm, privateScreen.optionGetOverlappingOutputs (), this);
4054 }
4055 
4056 CompIcon *
4057 CompScreenImpl::defaultIcon () const
4058 {
4059     return defaultIcon_;
4060 }
4061 
4062 bool
4063 CompScreenImpl::updateDefaultIcon ()
4064 {
4065     CompString file = privateScreen.optionGetDefaultIcon ();
4066     CompString pname = "core/";
4067     void       *data;
4068     CompSize   size;
4069 
4070     if (defaultIcon_)
4071     {
4072 	delete defaultIcon_;
4073 	defaultIcon_ = NULL;
4074     }
4075 
4076     if (!readImageFromFile (file, pname, size, data))
4077 	return false;
4078 
4079     defaultIcon_ = new CompIcon (size.width (), size.height ());
4080 
4081     memcpy (defaultIcon_->data (), data,
4082 	    size.width () * size.height () * sizeof (CARD32));
4083 
4084     free (data);
4085 
4086     return true;
4087 }
4088 
4089 void
4090 cps::History::setCurrentActiveWindowHistory (int x, int y)
4091 {
4092     int	i, min = 0;
4093 
4094     for (i = 0; i < ACTIVE_WINDOW_HISTORY_NUM; i++)
4095     {
4096 	if (history[i].x == x && history[i].y == y)
4097 	{
4098 	    currentHistory_ = i;
4099 	    return;
4100 	}
4101     }
4102 
4103     for (i = 1; i < ACTIVE_WINDOW_HISTORY_NUM; i++)
4104 	if (history[i].activeNum < history[min].activeNum)
4105 	    min = i;
4106 
4107     currentHistory_ = min;
4108 
4109     history[min].activeNum = activeNum_;
4110     history[min].x         = x;
4111     history[min].y         = y;
4112 
4113     memset (history[min].id, 0, sizeof (history[min].id));
4114 }
4115 
4116 void
4117 cps::History::addToCurrentActiveWindowHistory (Window id)
4118 {
4119     CompActiveWindowHistory *history = &this->history[currentHistory_];
4120     Window		    tmp, next = id;
4121 
4122     /* walk and move history */
4123     for (int i = 0; i < ACTIVE_WINDOW_HISTORY_SIZE; i++)
4124     {
4125 	tmp = history->id[i];
4126 	history->id[i] = next;
4127 	next = tmp;
4128 
4129 	/* we're done when we find an old instance or an empty slot */
4130 	if (tmp == id || tmp == None)
4131 	    break;
4132     }
4133 
4134     history->activeNum = activeNum_;
4135 }
4136 
4137 void
4138 ScreenInterface::enterShowDesktopMode ()
4139     WRAPABLE_DEF (enterShowDesktopMode)
4140 
4141 void
4142 ScreenInterface::leaveShowDesktopMode (CompWindow *window)
4143     WRAPABLE_DEF (leaveShowDesktopMode, window)
4144 
4145 void
4146 ScreenInterface::outputChangeNotify ()
4147     WRAPABLE_DEF (outputChangeNotify)
4148 
4149 void
4150 ScreenInterface::addSupportedAtoms (std::vector<Atom>& atoms)
4151     WRAPABLE_DEF (addSupportedAtoms, atoms)
4152 
4153 
4154 Window
4155 CompScreenImpl::root ()
4156 {
4157     return privateScreen.rootWindow();
4158 }
4159 
4160 int
4161 CompScreenImpl::xkbEvent ()
4162 {
4163     return privateScreen.getXkbEvent ();
4164 }
4165 
4166 void
4167 PrivateScreen::identifyEdgeWindow(Window id)
4168 {
4169     edgeWindow = 0;
4170     for (unsigned int i = 0; i < SCREEN_EDGE_NUM; i++)
4171     {
4172 	if (id == screenEdge[i].id)
4173 	{
4174 	    edgeWindow = 1 << i;
4175 	    break;
4176 	}
4177     }
4178 }
4179 
4180 void
4181 CompScreenImpl::warpPointer (int dx,
4182 			 int dy)
4183 {
4184     XEvent      event;
4185 
4186     pointerX += dx;
4187     pointerY += dy;
4188 
4189     if (pointerX >= width ())
4190 	pointerX = width () - 1;
4191     else if (pointerX < 0)
4192 	pointerX = 0;
4193 
4194     if (pointerY >= height ())
4195 	pointerY = height () - 1;
4196     else if (pointerY < 0)
4197 	pointerY = 0;
4198 
4199     XWarpPointer (privateScreen.dpy,
4200 		  None, privateScreen.rootWindow(),
4201 		  0, 0, 0, 0,
4202 		  pointerX, pointerY);
4203 
4204     XSync (privateScreen.dpy, false);
4205 
4206     /* XWarpPointer will generate Leave, Enter and PointerMotion
4207      * events as if the user had instantaneously moved the cursor
4208      * from one position to another. Because most of this is
4209      * useless to process, we just throw out the events and update
4210      * the pointer position. However, we do need to process some
4211      * crossing events since they tell us which edge windows are
4212      * hovered. Note that we don't actually trigger the bindings
4213      * in the case where we warped from one edge window to
4214      * another.
4215      *
4216      * FIXME: Probably don't need to process *all* the crossing
4217      * events here ... maybe there is a way to check only the last
4218      * event in the output buffer without roundtripping a lot */
4219     while (XCheckMaskEvent (privateScreen.dpy,
4220 			    LeaveWindowMask |
4221 			    EnterWindowMask |
4222 			    PointerMotionMask,
4223 			    &event))
4224     {
4225 	if (event.type == EnterNotify)
4226 	{
4227 	    if (event.xcrossing.mode != NotifyGrab ||
4228 		event.xcrossing.mode != NotifyUngrab ||
4229 		event.xcrossing.mode != NotifyInferior)
4230 	    {
4231 		privateScreen.identifyEdgeWindow(event.xcrossing.window);
4232 	    }
4233 	}
4234     }
4235 
4236     if (!inHandleEvent)
4237     {
4238 	lastPointerX = pointerX;
4239 	lastPointerY = pointerY;
4240     }
4241 }
4242 
4243 CompWindowList &
4244 CompScreenImpl::windows ()
4245 {
4246     return windowManager.getWindows();
4247 }
4248 
4249 CompWindowList &
4250 CompScreenImpl::serverWindows ()
4251 {
4252     return windowManager.getServerWindows();
4253 }
4254 
4255 CompWindowList &
4256 CompScreenImpl::destroyedWindows ()
4257 {
4258     return windowManager.getDestroyedWindows();
4259 }
4260 
4261 
4262 Time
4263 CompScreenImpl::getCurrentTime ()
4264 {
4265     return privateScreen.eventManager.getCurrentTime (privateScreen.dpy);
4266 }
4267 
4268 Time
4269 cps::EventManager::getCurrentTime (Display* dpy) const
4270 {
4271     XEvent event;
4272 
4273     XChangeProperty (dpy, grabWindow,
4274 		     XA_PRIMARY, XA_STRING, 8,
4275 		     PropModeAppend, NULL, 0);
4276     XWindowEvent (dpy, grabWindow,
4277 		  PropertyChangeMask,
4278 		  &event);
4279 
4280     return event.xproperty.time;
4281 }
4282 
4283 Window
4284 CompScreenImpl::selectionWindow ()
4285 {
4286     return privateScreen.wmSnSelectionWindow;
4287 }
4288 
4289 int
4290 CompScreenImpl::screenNum ()
4291 {
4292     return privateScreen.screenNum;
4293 }
4294 
4295 const CompPoint &
4296 CompScreenImpl::vp () const
4297 {
4298     return privateScreen.viewPort.vp;
4299 }
4300 
4301 const CompSize &
4302 CompScreenImpl::vpSize () const
4303 {
4304     return privateScreen.viewPort.vpSize;
4305 }
4306 
4307 int
4308 cps::DesktopWindowCount::desktopWindowCount ()
4309 {
4310     return count;
4311 }
4312 
4313 unsigned int
4314 cps::History::activeNum () const
4315 {
4316     return activeNum_;
4317 }
4318 
4319 CompOutput::vector &
4320 CompScreenImpl::outputDevs ()
4321 {
4322     return privateScreen.outputDevices.getOutputDevs ();
4323 }
4324 
4325 CompOutput &
4326 CompScreenImpl::currentOutputDev () const
4327 {
4328     return const_cast<PrivateScreen&>(privateScreen).outputDevices.getCurrentOutputDev ();
4329 }
4330 
4331 const CompRect &
4332 CompScreenImpl::workArea () const
4333 {
4334     return privateScreen.workArea;
4335 }
4336 
4337 unsigned int
4338 CompScreenImpl::currentDesktop ()
4339 {
4340     return privateScreen.currentDesktop;
4341 }
4342 
4343 unsigned int
4344 CompScreenImpl::nDesktop ()
4345 {
4346     return privateScreen.nDesktop;
4347 }
4348 
4349 CompActiveWindowHistory*
4350 cps::History::currentHistory ()
4351 {
4352     return history+currentHistory_;
4353 }
4354 
4355 bool
4356 CompScreenImpl::shouldSerializePlugins ()
4357 {
4358     return privateScreen.optionGetDoSerialize ();
4359 }
4360 
4361 void
4362 cps::WindowManager::removeDestroyed ()
4363 {
4364     while (pendingDestroys)
4365     {
4366 	foreach (CompWindow *w, destroyedWindows)
4367 	{
4368 	    if (w->destroyed ())
4369 	    {
4370 		delete w;
4371 		break;
4372 	    }
4373 	}
4374 
4375 	pendingDestroys--;
4376     }
4377 }
4378 
4379 const CompRegion &
4380 CompScreenImpl::region () const
4381 {
4382     return privateScreen.getRegion ();
4383 }
4384 
4385 bool
4386 CompScreenImpl::hasOverlappingOutputs ()
4387 {
4388     return privateScreen.outputDevices.hasOverlappingOutputs ();
4389 }
4390 
4391 CompOutput &
4392 CompScreenImpl::fullscreenOutput ()
4393 {
4394     return privateScreen.fullscreenOutput;
4395 }
4396 
4397 
4398 XWindowAttributes
4399 CompScreenImpl::attrib ()
4400 {
4401     return privateScreen.getAttrib ();
4402 }
4403 
4404 std::vector<XineramaScreenInfo> &
4405 CompScreenImpl::screenInfo ()
4406 {
4407     return privateScreen.getScreenInfo ();
4408 }
4409 
4410 bool
4411 CompScreenImpl::createFailed () const
4412 {
4413     return !screenInitalized;
4414 }
4415 
4416 CompScreen::CompScreen ():
4417     PluginClassStorage (screenPluginClassIndices)
4418 {
4419 }
4420 
4421 CompScreenImpl::CompScreenImpl () :
4422     cps::XWindowInfo(privateScreen.dpy),
4423     below(),
4424     autoRaiseTimer_(),
4425     autoRaiseWindow_(0),
4426     defaultIcon_(0),
4427     grabManager (this),
4428     eventHandled (false),
4429     privateScreen(this, windowManager),
4430     showingDesktopMask_(0)
4431 {
4432     ValueHolder::SetDefault (&valueHolder);
4433 
4434     CompPrivate p;
4435     CompOption::Value::Vector vList;
4436 
4437     privateScreen.setPingTimerCallback(
4438 	boost::bind (&CompScreenImpl::handlePingTimeout, this));
4439 
4440     screenInitalized = true;
4441 
4442     CompPlugin* corePlugin = CompPlugin::load ("core");
4443     if (!corePlugin)
4444     {
4445 	compLogMessage ("core", CompLogLevelFatal,
4446 			"Couldn't load core plugin");
4447 	screenInitalized = false;
4448     }
4449 
4450     if (!CompPlugin::push (corePlugin))
4451     {
4452 	compLogMessage ("core", CompLogLevelFatal,
4453 			"Couldn't activate core plugin");
4454 	screenInitalized = false;
4455     }
4456 
4457     p.uval = CORE_ABIVERSION;
4458     storeValue ("core_ABI", p);
4459 
4460     vList.push_back ("core");
4461 
4462     privateScreen.setPlugins (vList);
4463 }
4464 
4465 void
4466 PrivateScreen::setPlugins(CompOption::Value::Vector const& vList)
4467 {
4468     pluginManager.setPlugins(vList);
4469 }
4470 
4471 void
4472 PrivateScreen::initPlugins()
4473 {
4474     pluginManager.setDirtyPluginList ();
4475     pluginManager.updatePlugins (screen, optionGetActivePlugins());
4476 }
4477 
4478 bool
4479 CompScreenImpl::init (const char *name)
4480 {
4481     privateScreen.eventManager.init();
4482 
4483     if (privateScreen.initDisplay(name, *this, showingDesktopMask_))
4484     {
4485 	privateScreen.optionSetCloseWindowKeyInitiate (CompScreenImpl::closeWin);
4486 	privateScreen.optionSetCloseWindowButtonInitiate (CompScreenImpl::closeWin);
4487 	privateScreen.optionSetRaiseWindowKeyInitiate (CompScreenImpl::raiseWin);
4488 	privateScreen.optionSetRaiseWindowButtonInitiate (CompScreenImpl::raiseWin);
4489 	privateScreen.optionSetLowerWindowKeyInitiate (CompScreenImpl::lowerWin);
4490 	privateScreen.optionSetLowerWindowButtonInitiate (CompScreenImpl::lowerWin);
4491 
4492 	privateScreen.optionSetUnmaximizeWindowKeyInitiate (CompScreenImpl::unmaximizeWin);
4493 
4494 	privateScreen.optionSetMinimizeWindowKeyInitiate (CompScreenImpl::minimizeWin);
4495 	privateScreen.optionSetMinimizeWindowButtonInitiate (CompScreenImpl::minimizeWin);
4496 	privateScreen.optionSetMaximizeWindowKeyInitiate (CompScreenImpl::maximizeWin);
4497 	privateScreen.optionSetMaximizeWindowHorizontallyKeyInitiate (
4498 	    CompScreenImpl::maximizeWinHorizontally);
4499 	privateScreen.optionSetMaximizeWindowVerticallyKeyInitiate (
4500 	    CompScreenImpl::maximizeWinVertically);
4501 
4502 	privateScreen.optionSetWindowMenuKeyInitiate (CompScreenImpl::windowMenu);
4503 	privateScreen.optionSetWindowMenuButtonInitiate (CompScreenImpl::windowMenu);
4504 
4505 	privateScreen.optionSetShowDesktopKeyInitiate (CompScreenImpl::showDesktop);
4506 	privateScreen.optionSetShowDesktopEdgeInitiate (CompScreenImpl::showDesktop);
4507 
4508 	privateScreen.optionSetToggleWindowMaximizedKeyInitiate (CompScreenImpl::toggleWinMaximized);
4509 	privateScreen.optionSetToggleWindowMaximizedButtonInitiate (CompScreenImpl::toggleWinMaximized);
4510 
4511 	privateScreen.optionSetToggleWindowMaximizedHorizontallyKeyInitiate (
4512 	    CompScreenImpl::toggleWinMaximizedHorizontally);
4513 	privateScreen.optionSetToggleWindowMaximizedVerticallyKeyInitiate (
4514 	    CompScreenImpl::toggleWinMaximizedVertically);
4515 
4516 	privateScreen.optionSetToggleWindowShadedKeyInitiate (CompScreenImpl::shadeWin);
4517 
4518 	privateScreen.initPlugins();
4519 
4520 	if (debugOutput)
4521 	{
4522 	    StackDebugger::SetDefault (
4523 		new StackDebugger (
4524 		    dpy (),
4525 		    root (),
4526 		    &privateScreen));
4527 	}
4528 
4529 	return true;
4530     }
4531     return false;
4532 }
4533 
4534 void
4535 cps::EventManager::init ()
4536 {
4537     ctx = Glib::MainContext::get_default ();
4538     mainloop = Glib::MainLoop::create (ctx, false);
4539     sighupSource = CompSignalSource::create (SIGHUP, boost::bind (&EventManager::handleSignal, this, _1));
4540     sigintSource = CompSignalSource::create (SIGINT, boost::bind (&EventManager::handleSignal, this, _1));
4541     sigtermSource = CompSignalSource::create (SIGTERM, boost::bind (&EventManager::handleSignal, this, _1));
4542 }
4543 
4544 bool
4545 CompScreenImpl::displayInitialised() const
4546 {
4547     return privateScreen.initialized;
4548 }
4549 
4550 void
4551 CompScreenImpl::updatePassiveKeyGrabs () const
4552 {
4553     grabManager.updatePassiveKeyGrabs ();
4554 }
4555 
4556 void
4557 CompScreenImpl::applyStartupProperties (CompWindow *window)
4558 {
4559     privateScreen.startupSequence.applyStartupProperties (this, window);
4560 }
4561 
4562 void
4563 CompScreenImpl::updateClientList()
4564 {
4565     privateScreen.updateClientList ();
4566 }
4567 
4568 CompWindow *
4569 CompScreenImpl::getTopWindow() const
4570 {
4571     return windowManager.getTopWindow();
4572 }
4573 
4574 CompWindow *
4575 CompScreenImpl::getTopServerWindow () const
4576 {
4577     return windowManager.getTopServerWindow();
4578 }
4579 
4580 CoreOptions&
4581 CompScreenImpl::getCoreOptions()
4582 {
4583     return privateScreen;
4584 }
4585 
4586 Colormap
4587 CompScreenImpl::colormap() const
4588 {
4589     return privateScreen.colormap;
4590 }
4591 
4592 void
4593 CompScreenImpl::setCurrentDesktop (unsigned int desktop)
4594 {
4595     privateScreen.setCurrentDesktop(desktop);
4596 }
4597 
4598 Window
4599 CompScreenImpl::activeWindow() const
4600 {
4601     return privateScreen.orphanData.activeWindow;
4602 }
4603 
4604 void
4605 CompScreenImpl::updatePassiveButtonGrabs(Window serverFrame)
4606 {
4607     grabManager.updatePassiveButtonGrabs(serverFrame);
4608 }
4609 
4610 bool
4611 CompScreenImpl::grabWindowIsNot(Window w) const
4612 {
4613     return privateScreen.eventManager.notGrabWindow(w);
4614 }
4615 
4616 void
4617 CompScreenImpl::incrementPendingDestroys()
4618 {
4619     windowManager.incrementPendingDestroys();
4620 }
4621 
4622 cps::DesktopWindowCount::DesktopWindowCount() :
4623 count(0)
4624 {
4625 }
4626 
4627 void
4628 cps::DesktopWindowCount::incrementDesktopWindowCount()
4629 {
4630     count++;
4631 }
4632 void
4633 cps::DesktopWindowCount::decrementDesktopWindowCount()
4634 {
4635     count--;
4636 }
4637 
4638 cps::MapNum::MapNum() :
4639 mapNum (1)
4640 {
4641 }
4642 
4643 unsigned int
4644 cps::MapNum::nextMapNum()
4645 {
4646     return mapNum++;
4647 }
4648 
4649 void
4650 CompScreenImpl::setNextActiveWindow(Window id)
4651 {
4652     privateScreen.orphanData.nextActiveWindow = id;
4653 }
4654 Window
4655 CompScreenImpl::getNextActiveWindow() const
4656 {
4657     return privateScreen.orphanData.nextActiveWindow;
4658 }
4659 
4660 namespace
4661 {
4662 void sendStartupMessageToClients (Display *dpy, bool success)
4663 {
4664     /* Send a client message indicating that our startup is complete if
4665      * we were asked to do so */
4666     if (sendStartupMessage)
4667     {
4668 	Atom   startupMessageAtom = XInternAtom (dpy,
4669 						 "_COMPIZ_TESTING_STARTUP",
4670 						 FALSE);
4671 	XEvent startupMessageEvent;
4672 	Window root = DefaultRootWindow (dpy);
4673 
4674 	startupMessageEvent.xclient.type         = ClientMessage;
4675 	startupMessageEvent.xclient.window       = root;
4676 	startupMessageEvent.xclient.message_type = startupMessageAtom;
4677 	startupMessageEvent.xclient.format       = 32;
4678 	startupMessageEvent.xclient.data.l[0]    = success ? 1 : 0;
4679 	startupMessageEvent.xclient.data.l[1]    = 0;
4680 	startupMessageEvent.xclient.data.l[2]    = 0;
4681 	startupMessageEvent.xclient.data.l[3]    = 0;
4682 	startupMessageEvent.xclient.data.l[4]    = 0;
4683 
4684 	XSendEvent (dpy,
4685 		    root,
4686 		    FALSE,
4687 		    StructureNotifyMask,
4688 		    &startupMessageEvent);
4689 	XFlush (dpy);
4690     }
4691 }
4692 }
4693 
4694 
4695 bool
4696 PrivateScreen::initDisplay (const char *name, cps::History& history, unsigned int showingDesktopMask)
4697 {
4698     dpy = XOpenDisplay (name);
4699     if (!dpy)
4700     {
4701 	compLogMessage ("core", CompLogLevelFatal,
4702 			"Couldn't open display %s", XDisplayName (name));
4703 	return false;
4704     }
4705 
4706     /* Use synchronous behaviour when running with --sync, useful
4707      * for getting stacktraces when X Errors occurr */
4708     XSynchronize (dpy, synchronousX ? True : False);
4709 
4710     snprintf (displayString_, 255, "DISPLAY=%s",
4711 	      DisplayString (dpy));
4712 
4713     Atoms::init (dpy);
4714 
4715     XSetErrorHandler (errorHandler);
4716 
4717     snDisplay = sn_display_new (dpy, NULL, NULL);
4718     if (!snDisplay)
4719 	return true;
4720 
4721     if (!xSync.init<XSyncQueryExtension> (dpy))
4722     {
4723 	compLogMessage ("core", CompLogLevelFatal,
4724 		       "No sync extension");
4725 	sendStartupMessageToClients (dpy, false);
4726 	return false;
4727     }
4728 
4729     xRandr.init<XRRQueryExtension> (dpy);
4730     xShape.init<XShapeQueryExtension> (dpy);
4731 
4732     xkbEvent.init<XkbQueryExtension> (dpy);
4733     if (xkbEvent.isEnabled ())
4734     {
4735 	XkbSelectEvents (dpy, XkbUseCoreKbd,
4736 			 XkbBellNotifyMask | XkbStateNotifyMask,
4737 			 XkbAllEventsMask);
4738     }
4739     else
4740     {
4741 	compLogMessage ("core", CompLogLevelFatal,
4742 			"No XKB extension");
4743     }
4744 
4745     int  xineramaError;
4746     int  xineramaEvent;
4747     xineramaExtension = XineramaQueryExtension (dpy,
4748 						      &xineramaEvent,
4749 						      &xineramaError);
4750 
4751     updateScreenInfo ();
4752 
4753     escapeKeyCode = XKeysymToKeycode (dpy, XStringToKeysym ("Escape"));
4754     returnKeyCode = XKeysymToKeycode (dpy, XStringToKeysym ("Return"));
4755 
4756     modHandler->updateModifierMappings ();
4757 
4758     Window root_tmp = XRootWindow (dpy, DefaultScreen (dpy));
4759 
4760 
4761     /* Don't select for SubstructureRedirectMask or
4762      * SubstructureNotifyMask yet since we need to
4763      * act in complete synchronization here when
4764      * doing the initial window init in order to ensure
4765      * that windows don't receive invalid stack positions
4766      * but we don't want to receive an invalid CreateNotify
4767      * when we create windows like edge windows here either */
4768     XSelectInput (dpy, root_tmp,
4769 		  StructureNotifyMask      |
4770 		  PropertyChangeMask       |
4771 		  LeaveWindowMask          |
4772 		  EnterWindowMask          |
4773 		  KeyPressMask             |
4774 		  KeyReleaseMask           |
4775 		  ButtonPressMask          |
4776 		  ButtonReleaseMask        |
4777 		  FocusChangeMask          |
4778 		  ExposureMask);
4779 
4780     /* We need to register for EnterWindowMask |
4781      * ButtonPressMask | FocusChangeMask on other
4782      * root windows as well because focus happens
4783      * on a display level and we need to check
4784      * if the screen we are running on lost focus */
4785 
4786     for (int i = 0; i <= ScreenCount (dpy) - 1; i++)
4787     {
4788 	Window rt = XRootWindow (dpy, i);
4789 
4790 	if (rt == root_tmp)
4791 	    continue;
4792 
4793 	XSelectInput (dpy, rt,
4794 		      FocusChangeMask |
4795 		      SubstructureNotifyMask);
4796     }
4797 
4798     for (int i = 0; i < SCREEN_EDGE_NUM; i++)
4799     {
4800 	screenEdge[i].id    = None;
4801 	screenEdge[i].count = 0;
4802     }
4803 
4804     screenNum = DefaultScreen (dpy);
4805     colormap  = DefaultColormap (dpy, screenNum);
4806     root = root_tmp;
4807 
4808     snContext = sn_monitor_context_new (snDisplay, screenNum,
4809 					      compScreenSnEvent, this, NULL);
4810 
4811     if (!XGetWindowAttributes (dpy, rootWindow(), &attrib))
4812 	return false;
4813 
4814     workArea.setWidth (attrib.width);
4815     workArea.setHeight (attrib.height);
4816 
4817     XVisualInfo          templ;
4818     templ.visualid = XVisualIDFromVisual (attrib.visual);
4819 
4820     int                  nvisinfo;
4821     XVisualInfo* visinfo = XGetVisualInfo (dpy, VisualIDMask, &templ, &nvisinfo);
4822     if (!nvisinfo)
4823     {
4824 	compLogMessage ("core", CompLogLevelFatal,
4825 			"Couldn't get visual info for default visual");
4826 	sendStartupMessageToClients (dpy, false);
4827 	return false;
4828     }
4829 
4830     XColor               black;
4831     black.red = black.green = black.blue = 0;
4832 
4833     if (!XAllocColor (dpy, colormap, &black))
4834     {
4835 	compLogMessage ("core", CompLogLevelFatal,
4836 			"Couldn't allocate color");
4837 	sendStartupMessageToClients (dpy, false);
4838 	XFree (visinfo);
4839 	return false;
4840     }
4841 
4842     static char          data = 0;
4843     Pixmap bitmap = XCreateBitmapFromData (dpy, rootWindow(), &data, 1, 1);
4844     if (!bitmap)
4845     {
4846 	compLogMessage ("core", CompLogLevelFatal,
4847 			"Couldn't create bitmap");
4848 	sendStartupMessageToClients (dpy, false);
4849 	XFree (visinfo);
4850 	return false;
4851     }
4852 
4853     invisibleCursor = XCreatePixmapCursor (dpy, bitmap, bitmap,
4854 						 &black, &black, 0, 0);
4855     if (!invisibleCursor)
4856     {
4857 	compLogMessage ("core", CompLogLevelFatal,
4858 			"Couldn't create invisible cursor");
4859 	sendStartupMessageToClients (dpy, false);
4860 	XFree (visinfo);
4861 	return false;
4862     }
4863 
4864     XFreePixmap (dpy, bitmap);
4865     XFreeColors (dpy, colormap, &black.pixel, 1, 0);
4866 
4867     XFree (visinfo);
4868 
4869     reshape (attrib.width, attrib.height);
4870 
4871     initialized = true;
4872     initOptions ();
4873     detectOutputDevices (*this);
4874     updateOutputDevices (*this);
4875 
4876     getDesktopHints (showingDesktopMask);
4877 
4878     /* Check for other window managers */
4879 
4880     char                 buf[128];
CID 12529 - SECURE_CODING
[VERY RISKY]. Using "sprintf" can cause a buffer overflow when done incorrectly.  Because sprintf() assumes an arbitrarily long string, callers must be careful not to overflow the actual space of the destination. Use snprintf() instead, or correct precision specifiers.
4881     sprintf (buf, "WM_S%d", DefaultScreen (dpy));
4882     wmSnAtom = XInternAtom (dpy, buf, 0);
4883 
4884     Window currentWmSnOwner = XGetSelectionOwner (dpy, wmSnAtom);
4885 
4886     if (currentWmSnOwner != None)
4887     {
4888 	if (!replaceCurrentWm)
4889 	{
4890 	    compLogMessage ("core", CompLogLevelError,
4891 			    "Screen %d on display \"%s\" already "
4892 			    "has a window manager; try using the "
4893 			    "--replace option to replace the current "
4894 			    "window manager.",
4895 			    DefaultScreen (dpy), DisplayString (dpy));
4896 	    sendStartupMessageToClients (dpy, false);
4897 
4898 	    return false;
4899 	}
4900 
4901 	XSelectInput (dpy, currentWmSnOwner, StructureNotifyMask);
4902     }
4903 
4904     XSetWindowAttributes attr;
4905     attr.override_redirect = true;
4906     attr.event_mask        = PropertyChangeMask;
4907 
4908     Window newWmSnOwner =
4909 	XCreateWindow (dpy, root_tmp, -100, -100, 1, 1, 0,
4910 		       CopyFromParent, CopyFromParent,
4911 		       CopyFromParent,
4912 		       CWOverrideRedirect | CWEventMask,
4913 		       &attr);
4914 
4915     XChangeProperty (dpy, newWmSnOwner, Atoms::wmName, Atoms::utf8String, 8,
4916 		     PropModeReplace, (unsigned char *) PACKAGE,
4917 		     strlen (PACKAGE));
4918 
4919     XEvent event;
4920     XWindowEvent (dpy, newWmSnOwner, PropertyChangeMask, &event);
4921 
4922     Time wmSnTimestamp = event.xproperty.time;
4923 
4924     XSetSelectionOwner (dpy, wmSnAtom, newWmSnOwner, wmSnTimestamp);
4925 
4926     if (XGetSelectionOwner (dpy, wmSnAtom) != newWmSnOwner)
4927     {
4928 	compLogMessage ("core", CompLogLevelError,
4929 			"Could not acquire window manager "
4930 			"selection on screen %d display \"%s\"",
4931 			DefaultScreen (dpy), DisplayString (dpy));
4932 
4933 	XDestroyWindow (dpy, newWmSnOwner);
4934 	sendStartupMessageToClients (dpy, false);
4935 
4936 	return false;
4937     }
4938 
4939     /* Send client message indicating that we are now the window manager */
4940     event.xclient.type         = ClientMessage;
4941     event.xclient.window       = root_tmp;
4942     event.xclient.message_type = Atoms::manager;
4943     event.xclient.format       = 32;
4944     event.xclient.data.l[0]    = wmSnTimestamp;
4945     event.xclient.data.l[1]    = wmSnAtom;
4946     event.xclient.data.l[2]    = 0;
4947     event.xclient.data.l[3]    = 0;
4948     event.xclient.data.l[4]    = 0;
4949 
4950     XSendEvent (dpy, root_tmp, FALSE, StructureNotifyMask, &event);
4951 
4952     /* Wait for old window manager to go away */
4953     if (currentWmSnOwner != None)
4954     {
4955 	do {
4956 	    XWindowEvent (dpy, currentWmSnOwner, StructureNotifyMask, &event);
4957 	} while (event.type != DestroyNotify);
4958     }
4959 
4960 
4961     /* Server grab from here, we are creating windows */
4962 
4963     XGrabServer (dpy);
4964 
4965     {
4966 	XSetWindowAttributes attrib;
4967 	attrib.override_redirect = 1;
4968 	attrib.event_mask = PropertyChangeMask;
4969 
4970 	eventManager.createGrabWindow(dpy, rootWindow(), &attrib);
4971 
4972 	for (int i = 0; i < SCREEN_EDGE_NUM; i++)
4973 	{
4974 	    long xdndVersion = 3;
4975 
4976 	    screenEdge[i].id = XCreateWindow (dpy, rootWindow(),
4977 						    -100, -100, 1, 1, 0,
4978 						    CopyFromParent, InputOnly,
4979 						    CopyFromParent,
4980 						    CWOverrideRedirect,
4981 						    &attrib);
4982 
4983 	    XChangeProperty (dpy, screenEdge[i].id, Atoms::xdndAware,
4984 			     XA_ATOM, 32, PropModeReplace,
4985 			     (unsigned char *) &xdndVersion, 1);
4986 
4987 	    /* CompWindow::CompWindow will select for
4988 	     * crossing events when it gets called on
4989 	     * CreateNotify of this window, so no need
4990 	     * to select for them here */
4991 	    XSelectInput (dpy, screenEdge[i].id,
4992 			  StructureNotifyMask |
4993 			  ButtonPressMask   |
4994 			  ButtonReleaseMask |
4995 			  PointerMotionMask);
4996 	}
4997     }
4998 
4999     updateScreenEdges ();
5000 
5001     setDesktopHints ();
5002     eventManager.setSupportingWmCheck (dpy, rootWindow());
5003     screen->updateSupportedWmHints ();
5004 
5005     normalCursor = XCreateFontCursor (dpy, XC_left_ptr);
5006     busyCursor   = XCreateFontCursor (dpy, XC_watch);
5007 
5008     XDefineCursor (dpy, rootWindow(), normalCursor);
5009 
5010     /* Attempt to gain SubstructureRedirectMask */
5011     CompScreenImpl::checkForError (dpy);
5012 
5013     /* We should get DestroyNotify events for any windows that were
5014      * destroyed while initializing windows here now */
5015     XSelectInput (dpy, rootWindow(), attrib.your_event_mask |
5016 		  SubstructureRedirectMask | SubstructureNotifyMask);
5017 
5018     if (CompScreenImpl::checkForError (dpy))
5019     {
5020 	compLogMessage ("core", CompLogLevelError,
5021 			"Another window manager is "
5022 			"already running on screen: %d", DefaultScreen (dpy));
5023 
5024 	XUngrabServer (dpy);
5025 	XSync (dpy, FALSE);
5026 
5027 	sendStartupMessageToClients (dpy, false);
5028 	return false;
5029     }
5030 
5031     wmSnSelectionWindow = newWmSnOwner;
5032     this->wmSnTimestamp       = wmSnTimestamp;
5033 
5034     Window rootReturn, parentReturn;
5035     Window               *children;
5036     unsigned int         nchildren;
5037     XQueryTree (dpy, rootWindow(),
5038 		&rootReturn, &parentReturn,
5039 		&children, &nchildren);
5040 
5041     XUngrabServer (dpy);
5042     XSync (dpy, FALSE);
5043 
5044     /* Start initializing windows here */
5045 
5046     for (unsigned int i = 0; i < nchildren; i++)
5047     {
5048 	XWindowAttributes attrib;
5049 
5050 	/* Failure means the window has been destroyed, do not
5051 	 * manage this window since we will not receive a DestroyNotify
5052 	 * for it
5053 	 */
5054 
5055 	if (!XGetWindowAttributes (screen->dpy (), children[i], &attrib))
5056 	    setDefaultWindowAttributes(&attrib);
5057 
5058 	Window topWindowInTree = i ? children[i - 1] : None;
5059 
5060 	PrivateWindow::createCompWindow (topWindowInTree, topWindowInTree, attrib, children[i]);
5061     }
5062 
5063     /* enforce restack on all windows
5064      * using list last sent to server
5065     i = 0;
5066     for (CompWindowList::reverse_iterator rit = serverWindows.rbegin ();
5067 	 rit != serverWindows.rend (); rit++)
5068 	children[i++] = ROOTPARENT ((*rit));
5069 
5070     XRestackWindows (dpy, children, i);
5071     */
5072     XFree (children);
5073 
5074     windowManager.setWindowActiveness(history);
5075 
5076     Window               focus;
5077     int                  revertTo;
5078     XGetInputFocus (dpy, &focus, &revertTo);
5079 
5080     /* move input focus to root window so that we get a FocusIn event when
5081        moving it to the default window */
5082     XSetInputFocus (dpy, rootWindow(), RevertToPointerRoot, CurrentTime);
5083 
5084     if (focus == None || focus == PointerRoot)
5085     {
5086 	screen->focusDefaultWindow ();
5087     }
5088     else
5089     {
5090 	CompWindow *w;
5091 
5092 	w = screen->findWindow (focus);
5093 	if (w)
5094 	    w->moveInputFocusTo ();
5095 	else
5096 	    screen->focusDefaultWindow ();
5097     }
5098 
5099     /* Need to set a default here so that the value isn't uninitialized
5100      * when loading plugins FIXME: Should find a way to initialize options
5101      * first and then set this value, or better yet, tie this value directly
5102      * to the option */
5103     viewPort.vpSize.setWidth (optionGetHsize ());
5104     viewPort.vpSize.setHeight (optionGetVsize ());
5105 
5106     /* TODO: Bailout properly when screenInitPlugins fails
5107      * TODO: It would be nicer if this line could mean
5108      * "init all the screens", but unfortunately it only inits
5109      * plugins loaded on the command line screen's and then
5110      * we need to call updatePlugins () to init the remaining
5111      * screens from option changes */
5112     bool init_succeeded = CompPlugin::screenInitPlugins (screen);
5113     assert (init_succeeded);
5114     if (!init_succeeded)
5115       return false;
5116 
5117     /* The active plugins list might have been changed - load any
5118      * new plugins */
5119 
5120     viewPort.vpSize.setWidth (optionGetHsize ());
5121     viewPort.vpSize.setHeight (optionGetVsize ());
5122 
5123     setAudibleBell (optionGetAudibleBell ());
5124 
5125 
5126     pingTimer.setTimes (optionGetPingDelay (),
5127 			      optionGetPingDelay () + 500);
5128 
5129     pingTimer.start ();
5130 
5131     sendStartupMessageToClients (dpy, true);
5132 
5133     return true;
5134 }
5135 
5136 CompScreenImpl::~CompScreenImpl ()
5137 {
5138     privateScreen.startupSequence.removeAllSequences ();
5139 
5140     while (!windowManager.getWindows().empty ())
5141         delete windowManager.getWindows().front ();
5142 
5143     while (CompPlugin* p = CompPlugin::pop ())
5144 	CompPlugin::unload (p);
5145 
5146     screen = NULL;
5147 
5148     if (defaultIcon_)
5149 	delete defaultIcon_;
5150 }
5151 
5152 cps::GrabManager::GrabManager (CompScreen *screen) :
5153     screen(screen),
5154     currentState(0),
5155     buttonGrabs (),
5156     keyGrabs ()
5157 {
5158 }
5159 
5160 cps::ViewPort::ViewPort() :
5161     vp (0, 0),
5162     vpSize (1, 1)
5163 {
5164 }
5165 
5166 cps::StartupSequence::StartupSequence() :
5167     startupSequences (),
5168     startupSequenceTimer ()
5169 {
5170     startupSequenceTimer.setCallback (
5171 	boost::bind (&cps::StartupSequence::handleStartupSequenceTimeout, this));
5172     startupSequenceTimer.setTimes (1000, 1500);
5173 }
5174 
5175 PrivateScreen::PrivateScreen (CompScreen *screen, cps::WindowManager& windowManager) :
5176     CoreOptions(false),
5177     dpy (NULL),
5178     startupSequence(this),
5179     eventManager (),
5180     nDesktop (1),
5181     currentDesktop (0),
5182     wmSnSelectionWindow (None),
5183     normalCursor (None),
5184     busyCursor (None),
5185     invisibleCursor (None),
5186     initialized (false),
5187     screen(screen),
5188     screenInfo (),
5189     snDisplay(0),
5190     root(None),
5191     snContext (0),
5192     wmSnAtom (None),
5193     desktopHintData (0),
5194     desktopHintSize (0),
5195     edgeWindow (None),
5196     edgeDelayTimer (),
5197     xdndWindow (None),
5198     windowManager(windowManager)
5199 {
5200     for (int i = 0; i < SCREEN_EDGE_NUM; i++)
5201     {
5202 	screenEdge[i].id    = None;
5203 	screenEdge[i].count = 0;
5204     }
5205 
5206 }
5207 
5208 cps::History::History() :
5209     currentHistory_(0),
5210     activeNum_ (1)
5211 {
5212     memset (history, 0, sizeof history);
5213 }
5214 
5215 cps::WindowManager::WindowManager() :
5216     windows (),
5217     serverWindows (),
5218     destroyedWindows (),
5219     stackIsFresh (false),
5220     groups (0),
5221     pendingDestroys (0),
5222     lastFoundWindow(0)
5223 {
5224 }
5225 
5226 cps::PluginManager::PluginManager() :
5227     plugin (),
5228     dirtyPluginList (true)
5229 {
5230 }
5231 
5232 cps::EventManager::EventManager () :
5233     possibleTap(NULL),
5234     source(0),
5235     timeout(0),
5236     sighupSource(0),
5237     sigtermSource(0),
5238     sigintSource(0),
5239     fileWatch (0),
5240     lastFileWatchHandle (1),
5241     watchFds (0),
5242     lastWatchFdHandle (1),
5243     grabWindow (None)
5244 {
5245     TimeoutHandler *dTimeoutHandler = new TimeoutHandler ();
5246     TimeoutHandler::SetDefault (dTimeoutHandler);
5247 }
5248 
5249 cps::OrphanData::OrphanData() :
5250     activeWindow (0),
5251     nextActiveWindow(0)
5252 {
5253 }
5254 
5255 cps::OrphanData::~OrphanData()
5256 {
5257 }
5258 
5259 cps::EventManager::~EventManager ()
5260 {
5261     /* Not guaranteed to be created by EventManager's constructor */
5262     if (timeout)
5263     {
5264 	/* This will implicitly call ~CompTimeoutSource
5265 	 * See LP: #1085590 */
5266 	g_source_destroy (timeout->gobj ());
5267     }
5268     delete sigintSource;
5269     delete sigtermSource;
5270     delete sighupSource;
5271 
5272     /* Not guaranteed to be created by EventManager's constructor */
5273     if (source)
5274     {
5275 	/* This will implicitly call ~CompEventSource */
5276 	g_source_destroy (source->gobj ());
5277     }
5278 
5279     /* This will implicitly call ~CompWatchFd */
5280     foreach (CompWatchFd *fd, watchFds)
5281 	g_source_destroy (fd->gobj ());
5282 
5283     watchFds.clear ();
5284 }
5285 
5286 PrivateScreen::~PrivateScreen ()
5287 {
5288     initialized = false;
5289 
5290     if (snContext)
5291 	sn_monitor_context_unref (snContext);
5292 
5293     if (dpy != NULL)
5294     {
5295 	XUngrabKey (dpy, AnyKey, AnyModifier, rootWindow());
5296 
5297 	for (int i = 0; i < SCREEN_EDGE_NUM; i++)
5298 	{
5299 	    Window id = screenEdge[i].id;
5300 	    if (id != None)
5301 		XDestroyWindow (dpy, id);
5302 	}
5303 
5304 	eventManager.destroyGrabWindow (dpy);
5305 
5306 	if (normalCursor != None)
5307 	    XFreeCursor (dpy, normalCursor);
5308 
5309 	if (busyCursor != None)
5310 	    XFreeCursor (dpy, busyCursor);
5311 
5312 	if (invisibleCursor != None)
5313 	    XFreeCursor (dpy, invisibleCursor);
5314 
5315 	/* Do not destroy wmSnSelectionWindow here.
5316 	 *
5317 	 * Because we haven't changed our active event mask
5318 	 * to remove SubstructureRedirectMask, other ICCCM
5319 	 * compliant window managers may receive a DestroyNotify
5320 	 * (eg, because we're blocked on XSync) before we get
5321 	 * a chance to close our display connection and remove
5322 	 * our SubstructureRedirectMask. That will cause them
5323 	 * to fail to start.
5324 	 *
5325 	 * The selection window is destroyed anyways when we
5326 	 * close our connection, and that is a very accurate
5327 	 * indicator to other WM's that we are well and truly
5328 	 * gone because the protocol requires the implementation
5329 	 * to remove all client event masks before destroying
5330 	 * windows
5331 	 */
5332 
5333 	XSync (dpy, False);  // Redundant?
5334 	XCloseDisplay (dpy);
5335     }
5336 
5337     if (desktopHintData)
5338 	free (desktopHintData);
5339 
5340     if (snDisplay)
5341 	sn_display_unref (snDisplay);
5342 }