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 }