2
* Copyright © 2005 Novell, Inc.
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
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 SPECI<<<<<fAL, 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.
23
* Author: David Reveman <davidr@novell.com>
36
#include <sys/types.h>
44
#include <boost/bind.hpp>
45
#include <boost/foreach.hpp>
46
#define foreach BOOST_FOREACH
49
#include <X11/Xatom.h>
50
#include <X11/Xproto.h>
51
#include <X11/extensions/Xrandr.h>
52
#include <X11/extensions/shape.h>
53
#include <X11/cursorfont.h>
55
#include <core/core.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"
64
bool inHandleEvent = false;
66
bool screenInitalized = false;
68
CompScreen *targetScreen = NULL;
69
CompOutput *targetOutput;
73
unsigned int lastPointerMods = 0;
76
unsigned int pointerMods = 0;
78
#define MwmHintsFunctions (1L << 0)
79
#define MwmHintsDecorations (1L << 1)
80
#define PropMotifWmHintElements 3
84
unsigned long functions;
85
unsigned long decorations;
91
ModifierHandler *modHandler;
93
PluginClassStorage::Indices screenPluginClassIndices (0);
96
CompScreen::allocPluginClassIndex ()
98
unsigned int i = PluginClassStorage::allocatePluginClassIndex (screenPluginClassIndices);
100
if (screenPluginClassIndices.size () != screen->pluginClasses.size ())
101
screen->pluginClasses.resize (screenPluginClassIndices.size ());
107
CompScreen::freePluginClassIndex (unsigned int index)
109
PluginClassStorage::freePluginClassIndex (screenPluginClassIndices, index);
111
if (screenPluginClassIndices.size () != screen->pluginClasses.size ())
112
screen->pluginClasses.resize (screenPluginClassIndices.size ());
116
CompScreen::eventLoop ()
118
priv->ctx = Glib::MainContext::get_default ();
119
priv->mainloop = Glib::MainLoop::create (priv->ctx, false);
120
priv->source = CompEventSource::create ();
121
priv->timeout = CompTimeoutSource::create ();
123
priv->source->attach (priv->ctx);
125
/* Kick the event loop */
126
priv->ctx->iteration (false);
128
priv->mainloop->run ();
132
CompScreen::addFileWatch (const char *path,
134
FileWatchCallBack callBack)
136
CompFileWatch *fileWatch = new CompFileWatch ();
140
fileWatch->path = path;
141
fileWatch->mask = mask;
142
fileWatch->callBack = callBack;
143
fileWatch->handle = priv->lastFileWatchHandle++;
145
if (priv->lastFileWatchHandle == MAXSHORT)
146
priv->lastFileWatchHandle = 1;
148
priv->fileWatch.push_front (fileWatch);
150
fileWatchAdded (fileWatch);
152
return fileWatch->handle;
156
CompScreen::removeFileWatch (CompFileWatchHandle handle)
158
std::list<CompFileWatch *>::iterator it;
161
for (it = priv->fileWatch.begin (); it != priv->fileWatch.end (); it++)
162
if ((*it)->handle == handle)
165
if (it == priv->fileWatch.end ())
169
priv->fileWatch.erase (it);
171
fileWatchRemoved (w);
176
const CompFileWatchList &
177
CompScreen::getFileWatches () const
179
return priv->fileWatch;
183
PrivateScreen::addTimer (CompTimer *timer)
185
std::list<CompTimer *>::iterator it;
187
it = std::find (timers.begin (), timers.end (), timer);
189
if (it != timers.end ())
192
for (it = timers.begin (); it != timers.end (); it++)
194
if ((int) timer->mMinTime < (*it)->mMinLeft)
198
timer->mMinLeft = timer->mMinTime;
199
timer->mMaxLeft = timer->mMaxTime;
201
timers.insert (it, timer);
205
PrivateScreen::removeTimer (CompTimer *timer)
207
std::list<CompTimer *>::iterator it;
209
it = std::find (timers.begin (), timers.end (), timer);
211
if (it == timers.end ())
217
CompWatchFd::CompWatchFd (int fd,
218
Glib::IOCondition events,
219
FdWatchCallBack callback) :
220
Glib::IOSource (fd, events),
222
mCallBack (callback),
226
connect (sigc::mem_fun <Glib::IOCondition, bool>
227
(this, &CompWatchFd::internalCallback));
230
Glib::RefPtr <CompWatchFd>
231
CompWatchFd::create (int fd,
232
Glib::IOCondition events,
233
FdWatchCallBack callback)
235
return Glib::RefPtr <CompWatchFd> (new CompWatchFd (fd, events, callback));
239
CompScreen::addWatchFd (int fd,
241
FdWatchCallBack callBack)
243
Glib::IOCondition gEvents;
245
memset (&gEvents, 0, sizeof (Glib::IOCondition));
248
gEvents |= Glib::IO_IN;
249
if (events & POLLOUT)
250
gEvents |= Glib::IO_OUT;
251
if (events & POLLPRI)
252
gEvents |= Glib::IO_PRI;
253
if (events & POLLERR)
254
gEvents |= Glib::IO_ERR;
255
if (events & POLLHUP)
256
gEvents |= Glib::IO_HUP;
258
Glib::RefPtr <CompWatchFd> watchFd = CompWatchFd::create (fd, gEvents, callBack);
260
watchFd->attach (priv->ctx);
264
watchFd->mHandle = priv->lastWatchFdHandle++;
266
if (priv->lastWatchFdHandle == MAXSHORT)
267
priv->lastWatchFdHandle = 1;
269
priv->watchFds.push_front (watchFd);
271
return watchFd->mHandle;
275
CompScreen::removeWatchFd (CompWatchFdHandle handle)
277
std::list<Glib::RefPtr <CompWatchFd> >::iterator it;
278
Glib::RefPtr <CompWatchFd> w;
280
for (it = priv->watchFds.begin();
281
it != priv->watchFds.end (); it++)
283
if ((*it)->mHandle == handle)
287
if (it == priv->watchFds.end ())
294
w->mForceFail = true;
299
priv->watchFds.erase (it);
303
CompScreen::storeValue (CompString key, CompPrivate value)
305
std::map<CompString,CompPrivate>::iterator it;
307
it = priv->valueMap.find (key);
309
if (it != priv->valueMap.end ())
315
priv->valueMap.insert (std::pair<CompString,CompPrivate> (key, value));
320
CompScreen::hasValue (CompString key)
322
return (priv->valueMap.find (key) != priv->valueMap.end ());
326
CompScreen::getValue (CompString key)
330
std::map<CompString,CompPrivate>::iterator it;
331
it = priv->valueMap.find (key);
333
if (it != priv->valueMap.end ())
345
CompWatchFd::internalCallback (Glib::IOCondition events)
347
short int revents = 0;
349
if (events & Glib::IO_IN)
351
if (events & Glib::IO_OUT)
353
if (events & Glib::IO_PRI)
355
if (events & Glib::IO_ERR)
357
if (events & Glib::IO_HUP)
359
if (events & Glib::IO_NVAL)
368
/* FIXME: Need to find a way to properly remove the watchFd
369
* from the internal list in core */
370
//screen->priv->watchFds.remove (this);
378
CompScreen::eraseValue (CompString key)
380
std::map<CompString,CompPrivate>::iterator it;
381
it = priv->valueMap.find (key);
383
if (it != priv->valueMap.end ())
385
priv->valueMap.erase (key);
390
CompScreen::fileWatchAdded (CompFileWatch *watch)
391
WRAPABLE_HND_FUNC (0, fileWatchAdded, watch)
394
CompScreen::fileWatchRemoved (CompFileWatch *watch)
395
WRAPABLE_HND_FUNC (1, fileWatchRemoved, watch)
398
CompScreen::setOptionForPlugin (const char *plugin,
400
CompOption::Value &value)
402
WRAPABLE_HND_FUNC_RETURN (4, bool, setOptionForPlugin,
405
CompPlugin *p = CompPlugin::find (plugin);
407
return p->vTable->setOption (name, value);
413
CompScreen::sessionEvent (CompSession::Event event,
414
CompOption::Vector &arguments)
415
WRAPABLE_HND_FUNC (5, sessionEvent, event, arguments)
418
ScreenInterface::fileWatchAdded (CompFileWatch *watch)
419
WRAPABLE_DEF (fileWatchAdded, watch)
422
ScreenInterface::fileWatchRemoved (CompFileWatch *watch)
423
WRAPABLE_DEF (fileWatchRemoved, watch)
426
ScreenInterface::initPluginForScreen (CompPlugin *plugin)
427
WRAPABLE_DEF (initPluginForScreen, plugin)
430
ScreenInterface::finiPluginForScreen (CompPlugin *plugin)
431
WRAPABLE_DEF (finiPluginForScreen, plugin)
434
ScreenInterface::setOptionForPlugin (const char *plugin,
436
CompOption::Value &value)
437
WRAPABLE_DEF (setOptionForPlugin, plugin, name, value)
440
ScreenInterface::sessionEvent (CompSession::Event event,
441
CompOption::Vector &arguments)
442
WRAPABLE_DEF (sessionEvent, event, arguments)
445
static int errors = 0;
448
errorHandler (Display *dpy,
459
XGetErrorDatabaseText (dpy, "XlibMessage", "XError", "", str, 128);
460
fprintf (stderr, "%s", str);
462
XGetErrorText (dpy, e->error_code, str, 128);
463
fprintf (stderr, ": %s\n ", str);
465
XGetErrorDatabaseText (dpy, "XlibMessage", "MajorCode", "%d", str, 128);
466
fprintf (stderr, str, e->request_code);
468
sprintf (str, "%d", e->request_code);
469
XGetErrorDatabaseText (dpy, "XRequest", str, "", str, 128);
470
if (strcmp (str, ""))
471
fprintf (stderr, " (%s)", str);
472
fprintf (stderr, "\n ");
474
XGetErrorDatabaseText (dpy, "XlibMessage", "MinorCode", "%d", str, 128);
475
fprintf (stderr, str, e->minor_code);
476
fprintf (stderr, "\n ");
478
XGetErrorDatabaseText (dpy, "XlibMessage", "ResourceID", "%d", str, 128);
479
fprintf (stderr, str, e->resourceid);
480
fprintf (stderr, "\n");
489
CompScreen::checkForError (Display *dpy)
508
CompScreen::XRandr ()
510
return priv->randrExtension;
514
CompScreen::randrEvent ()
516
return priv->randrEvent;
520
CompScreen::XShape ()
522
return priv->shapeExtension;
526
CompScreen::shapeEvent ()
528
return priv->shapeEvent;
532
CompScreen::syncEvent ()
534
return priv->syncEvent;
538
CompScreen::snDisplay ()
540
return priv->snDisplay;
544
CompScreen::activeWindow ()
546
return priv->activeWindow;
550
CompScreen::autoRaiseWindow ()
552
return priv->autoRaiseWindow;
556
CompScreen::displayString ()
558
return priv->displayString;
562
PrivateScreen::updateScreenInfo ()
564
if (xineramaExtension)
567
XineramaScreenInfo *info = XineramaQueryScreens (dpy, &nInfo);
569
screenInfo = std::vector<XineramaScreenInfo> (info, info + nInfo);
577
PrivateScreen::setAudibleBell (bool audible)
580
XkbChangeEnabledControls (dpy,
583
audible ? XkbAudibleBellMask : 0);
587
PrivateScreen::handlePingTimeout ()
590
int ping = lastPing + 1;
592
ev.type = ClientMessage;
593
ev.xclient.window = 0;
594
ev.xclient.message_type = Atoms::wmProtocols;
595
ev.xclient.format = 32;
596
ev.xclient.data.l[0] = Atoms::wmPing;
597
ev.xclient.data.l[1] = ping;
598
ev.xclient.data.l[2] = 0;
599
ev.xclient.data.l[3] = 0;
600
ev.xclient.data.l[4] = 0;
602
foreach (CompWindow *w, windows)
604
if (w->priv->handlePingTimeout (lastPing))
606
ev.xclient.window = w->id ();
607
ev.xclient.data.l[2] = w->id ();
609
XSendEvent (dpy, w->id (), false, NoEventMask, &ev);
619
PrivateScreen::syncStacks ()
622
unsigned int nchildren;
623
Window root_return, parent_return;
625
CompWindowList syncedList;
627
XGrabServer (screen->dpy ());
628
XQueryTree (screen->dpy (), screen->root (), &root_return,
629
&parent_return, &children, &nchildren);
630
XUngrabServer (screen->dpy ());
632
/* For each window in the tree, try and find
633
* the CompWindow equavilent and then stack
636
for (unsigned int i = 0; i < nchildren; i++)
638
CompWindow *w = screen->findTopLevelWindow (children[i], true);
641
syncedList.push_back (w);
644
fprintf (stderr, "real window list: \n");
645
foreach (CompWindow *w, screen->windows ())
647
fprintf (stderr, " - id 0x%x\n", w->id ());
650
fprintf (stderr, "synced window list: \n");
651
foreach (CompWindow *w, screen->windows ())
653
fprintf (stderr, " - id 0x%x\n", w->id ());
657
while (screen->windows ().size ())
659
CompWindow *w = screen->windows ().back ();
661
screen->unhookWindow (w);
664
foreach (CompWindow *w, syncedList)
665
screen->insertWindow (w, screen->windows ().size () ?
666
screen->windows ().back ()->id () : 0);
675
CompScreen::getOptions ()
677
return priv->getOptions ();
681
CompScreen::setOption (const CompString &name,
682
CompOption::Value &value)
684
return priv->setOption (name, value);
688
PrivateScreen::setOption (const CompString &name,
689
CompOption::Value &value)
693
bool rv = CoreOptions::setOption (name, value);
698
if (!CompOption::findOption (getOptions (), name, &index))
702
case CoreOptions::ActivePlugins:
703
dirtyPluginList = true;
705
case CoreOptions::SyncStacksTimeout:
706
stackAttackTimer.stop ();
707
stackAttackTimer.setTimes (optionGetSyncStacksTimeout (), optionGetSyncStacksTimeout () * 1.4);
709
case CoreOptions::PingDelay:
710
pingTimer.setTimes (optionGetPingDelay (),
711
optionGetPingDelay () + 500);
713
case CoreOptions::AudibleBell:
714
setAudibleBell (optionGetAudibleBell ());
716
case CoreOptions::DetectOutputs:
717
if (optionGetDetectOutputs ())
718
detectOutputDevices ();
720
case CoreOptions::Hsize:
721
case CoreOptions::Vsize:
723
if (optionGetHsize () * screen->width () > MAXSHORT)
725
if (optionGetVsize () * screen->height () > MAXSHORT)
728
setVirtualScreenSize (optionGetHsize (), optionGetVsize ());
730
case CoreOptions::NumberOfDesktops:
731
setNumberOfDesktops (optionGetNumberOfDesktops ());
733
case CoreOptions::DefaultIcon:
734
return screen->updateDefaultIcon ();
736
case CoreOptions::Outputs:
737
if (!noDetection && optionGetDetectOutputs ())
739
updateOutputDevices ();
749
PrivateScreen::processEvents ()
751
XEvent event, peekEvent;
753
/* remove destroyed windows */
759
while (XPending (dpy))
761
XNextEvent (dpy, &event);
763
switch (event.type) {
766
pointerX = event.xbutton.x_root;
767
pointerY = event.xbutton.y_root;
768
pointerMods = event.xbutton.state;
772
pointerX = event.xkey.x_root;
773
pointerY = event.xkey.y_root;
774
pointerMods = event.xbutton.state;
777
while (XPending (dpy))
779
XPeekEvent (dpy, &peekEvent);
781
if (peekEvent.type != MotionNotify)
784
XNextEvent (dpy, &event);
787
pointerX = event.xmotion.x_root;
788
pointerY = event.xmotion.y_root;
789
pointerMods = event.xbutton.state;
793
pointerX = event.xcrossing.x_root;
794
pointerY = event.xcrossing.y_root;
795
pointerMods = event.xbutton.state;
798
if (event.xclient.message_type == Atoms::xdndPosition)
800
pointerX = event.xclient.data.l[2] >> 16;
801
pointerY = event.xclient.data.l[2] & 0xffff;
802
/* FIXME: Xdnd provides us no way of getting the pointer mods
803
* without doing XQueryPointer, which is a round-trip */
806
else if (event.xclient.message_type == Atoms::wmMoveResize)
810
/* _NET_WM_MOVERESIZE is most often sent by clients who provide
811
* a special "grab space" on a window for the user to initiate
812
* adjustment by the window manager. Since we don't have a
813
* passive grab on Button1 for active and raised windows, we
814
* need to update the pointer buffer here */
816
XQueryPointer (screen->dpy (), screen->root (),
817
&root, &child, &pointerX, &pointerY,
818
&i, &i, &pointerMods);
825
sn_display_process_event (snDisplay, &event);
827
inHandleEvent = true;
828
screen->handleEvent (&event);
829
inHandleEvent = false;
831
lastPointerX = pointerX;
832
lastPointerY = pointerY;
833
lastPointerMods = pointerMods;
838
PrivateScreen::updatePlugins ()
841
unsigned int nPop, i, j, pListCount = 1;
842
CompOption::Value::Vector pList;
843
CompPlugin::List pop;
847
dirtyPluginList = false;
849
CompOption::Value::Vector &list = optionGetActivePlugins ();
851
/* Determine the number of plugins, which is core +
852
* initial plugins + plugins in option list in addition
853
* to initial plugins */
854
foreach (CompString &pn, initialPlugins)
860
foreach (CompOption::Value &lp, list)
863
if (lp.s () == "core")
866
foreach (CompString &p, initialPlugins)
875
/* plugin not in initial list */
880
/* dupPluginCount is now the number of plugisn contained in both the
881
* initial and new plugins list */
882
pList.resize (pListCount);
886
screen->setOptionForPlugin ("core", "active_plugins", plugin);
890
/* Must have core as first plugin */
891
pList.at (0) = "core";
894
/* Add initial plugins */
895
foreach (CompString &p, initialPlugins)
899
pList.at (j).set (p);
903
/* Add plugins not in the initial list */
904
foreach (CompOption::Value &opt, list)
906
std::list <CompString>::iterator it = initialPlugins.begin ();
908
if (opt.s () == "core")
911
for (; it != initialPlugins.end (); it++)
913
if ((*it) == opt.s ())
921
pList.at (j++).set (opt.s ());
924
assert (j == pList.size ());
926
/* j is initialized to 1 to make sure we never pop the core plugin */
927
for (i = j = 1; j < plugin.list ().size () && i < pList.size (); i++, j++)
929
if (plugin.list ().at (j).s () != pList.at (i).s ())
933
nPop = plugin.list ().size () - j;
937
for (j = 0; j < nPop; j++)
939
pop.push_back (CompPlugin::pop ());
940
plugin.list ().pop_back ();
944
for (; i < pList.size (); i++)
948
foreach (CompPlugin *pp, pop)
950
if (pList[i]. s () == pp->vTable->name ())
952
if (CompPlugin::push (pp))
955
pop.erase (std::find (pop.begin (), pop.end (), pp));
960
pop.erase (std::find (pop.begin (), pop.end (), pp));
961
CompPlugin::unload (pp);
969
if (p == 0 && !failedPush)
971
p = CompPlugin::load (pList[i].s ().c_str ());
974
if (!CompPlugin::push (p))
976
CompPlugin::unload (p);
983
plugin.list ().push_back (p->vTable->name ());
986
foreach (CompPlugin *pp, pop)
987
CompPlugin::unload (pp);
989
if (!priv->dirtyPluginList)
990
screen->setOptionForPlugin ("core", "active_plugins", plugin);
993
/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
995
convertProperty (Display *dpy,
1004
Atom conversionTargets[N_TARGETS];
1005
long icccmVersion[] = { 2, 0 };
1007
conversionTargets[0] = Atoms::targets;
1008
conversionTargets[1] = Atoms::multiple;
1009
conversionTargets[2] = Atoms::timestamp;
1010
conversionTargets[3] = Atoms::version;
1012
if (target == Atoms::targets)
1013
XChangeProperty (dpy, w, property,
1014
XA_ATOM, 32, PropModeReplace,
1015
(unsigned char *) conversionTargets, N_TARGETS);
1016
else if (target == Atoms::timestamp)
1017
XChangeProperty (dpy, w, property,
1018
XA_INTEGER, 32, PropModeReplace,
1019
(unsigned char *) &time, 1);
1020
else if (target == Atoms::version)
1021
XChangeProperty (dpy, w, property,
1022
XA_INTEGER, 32, PropModeReplace,
1023
(unsigned char *) icccmVersion, 2);
1027
/* Be sure the PropertyNotify has arrived so we
1028
* can send SelectionNotify
1035
/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
1037
PrivateScreen::handleSelectionRequest (XEvent *event)
1039
XSelectionEvent reply;
1041
if (wmSnSelectionWindow != event->xselectionrequest.owner ||
1042
wmSnAtom != event->xselectionrequest.selection)
1045
reply.type = SelectionNotify;
1046
reply.display = dpy;
1047
reply.requestor = event->xselectionrequest.requestor;
1048
reply.selection = event->xselectionrequest.selection;
1049
reply.target = event->xselectionrequest.target;
1050
reply.property = None;
1051
reply.time = event->xselectionrequest.time;
1053
if (event->xselectionrequest.target == Atoms::multiple)
1055
if (event->xselectionrequest.property != None)
1059
unsigned long num, rest;
1060
unsigned char *data;
1062
if (XGetWindowProperty (dpy,
1063
event->xselectionrequest.requestor,
1064
event->xselectionrequest.property,
1067
&type, &format, &num, &rest,
1071
/* FIXME: to be 100% correct, should deal with rest > 0,
1072
* but since we have 4 possible targets, we will hardly ever
1073
* meet multiple requests with a length > 8
1075
adata = (Atom *) data;
1077
while (i < (int) num)
1079
if (!convertProperty (dpy, wmSnTimestamp,
1080
event->xselectionrequest.requestor,
1081
adata[i], adata[i + 1]))
1082
adata[i + 1] = None;
1087
XChangeProperty (dpy,
1088
event->xselectionrequest.requestor,
1089
event->xselectionrequest.property,
1091
32, PropModeReplace, data, num);
1099
if (event->xselectionrequest.property == None)
1100
event->xselectionrequest.property = event->xselectionrequest.target;
1102
if (convertProperty (dpy, wmSnTimestamp,
1103
event->xselectionrequest.requestor,
1104
event->xselectionrequest.target,
1105
event->xselectionrequest.property))
1106
reply.property = event->xselectionrequest.property;
1109
XSendEvent (dpy, event->xselectionrequest.requestor,
1110
false, 0L, (XEvent *) &reply);
1114
PrivateScreen::handleSelectionClear (XEvent *event)
1116
/* We need to unmanage the screen on which we lost the selection */
1117
if (wmSnSelectionWindow != event->xselectionclear.window ||
1118
wmSnAtom != event->xselectionclear.selection)
1124
#define IMAGEDIR "images"
1125
#define HOMECOMPIZDIR ".compiz-1"
1128
CompScreen::readImageFromFile (CompString &name,
1136
status = fileToImage (name, size, stride, data);
1139
char *home = getenv ("HOME");
1145
path += HOMECOMPIZDIR;
1153
status = fileToImage (path, size, stride, data);
1166
status = fileToImage (path, size, stride, data);
1173
CompScreen::writeImageToFile (CompString &path,
1178
CompString formatString (format);
1179
return imageToFile (path, formatString, size, size.width () * 4, data);
1183
PrivateScreen::getActiveWindow (Window root)
1187
unsigned long n, left;
1188
unsigned char *data;
1191
result = XGetWindowProperty (priv->dpy, root,
1192
Atoms::winActive, 0L, 1L, false,
1193
XA_WINDOW, &actual, &format,
1196
if (result == Success && data)
1199
memcpy (&w, data, sizeof (Window));
1207
CompScreen::fileToImage (CompString &name,
1212
WRAPABLE_HND_FUNC_RETURN (8, bool, fileToImage, name, size, stride, data);
1217
CompScreen::imageToFile (CompString &path,
1223
WRAPABLE_HND_FUNC_RETURN (9, bool, imageToFile, path, format, size,
1229
logLevelToString (CompLogLevel level)
1232
case CompLogLevelFatal:
1234
case CompLogLevelError:
1236
case CompLogLevelWarn:
1238
case CompLogLevelInfo:
1240
case CompLogLevelDebug:
1250
logMessage (const char *componentName,
1252
const char *message)
1254
if (!debugOutput && level >= CompLogLevelDebug)
1257
fprintf (stderr, "%s (%s) - %s: %s\n",
1258
programName, componentName,
1259
logLevelToString (level), message);
1263
CompScreen::logMessage (const char *componentName,
1265
const char *message)
1267
WRAPABLE_HND_FUNC (13, logMessage, componentName, level, message)
1268
::logMessage (componentName, level, message);
1272
compLogMessage (const char *componentName,
1280
va_start (args, format);
1282
vsnprintf (message, 2048, format, args);
1285
screen->logMessage (componentName, level, message);
1287
logMessage (componentName, level, message);
1293
PrivateScreen::getWmState (Window id)
1297
unsigned long n, left;
1298
unsigned char *data;
1299
unsigned long state = NormalState;
1301
result = XGetWindowProperty (priv->dpy, id,
1302
Atoms::wmState, 0L, 2L, false,
1303
Atoms::wmState, &actual, &format,
1306
if (result == Success && data)
1309
memcpy (&state, data, sizeof (unsigned long));
1310
XFree ((void *) data);
1317
PrivateScreen::setWmState (int state, Window id)
1319
unsigned long data[2];
1324
XChangeProperty (priv->dpy, id,
1325
Atoms::wmState, Atoms::wmState,
1326
32, PropModeReplace, (unsigned char *) data, 2);
1330
PrivateScreen::windowStateMask (Atom state)
1332
if (state == Atoms::winStateModal)
1333
return CompWindowStateModalMask;
1334
else if (state == Atoms::winStateSticky)
1335
return CompWindowStateStickyMask;
1336
else if (state == Atoms::winStateMaximizedVert)
1337
return CompWindowStateMaximizedVertMask;
1338
else if (state == Atoms::winStateMaximizedHorz)
1339
return CompWindowStateMaximizedHorzMask;
1340
else if (state == Atoms::winStateShaded)
1341
return CompWindowStateShadedMask;
1342
else if (state == Atoms::winStateSkipTaskbar)
1343
return CompWindowStateSkipTaskbarMask;
1344
else if (state == Atoms::winStateSkipPager)
1345
return CompWindowStateSkipPagerMask;
1346
else if (state == Atoms::winStateHidden)
1347
return CompWindowStateHiddenMask;
1348
else if (state == Atoms::winStateFullscreen)
1349
return CompWindowStateFullscreenMask;
1350
else if (state == Atoms::winStateAbove)
1351
return CompWindowStateAboveMask;
1352
else if (state == Atoms::winStateBelow)
1353
return CompWindowStateBelowMask;
1354
else if (state == Atoms::winStateDemandsAttention)
1355
return CompWindowStateDemandsAttentionMask;
1356
else if (state == Atoms::winStateDisplayModal)
1357
return CompWindowStateDisplayModalMask;
1363
PrivateScreen::windowStateFromString (const char *str)
1365
if (strcasecmp (str, "modal") == 0)
1366
return CompWindowStateModalMask;
1367
else if (strcasecmp (str, "sticky") == 0)
1368
return CompWindowStateStickyMask;
1369
else if (strcasecmp (str, "maxvert") == 0)
1370
return CompWindowStateMaximizedVertMask;
1371
else if (strcasecmp (str, "maxhorz") == 0)
1372
return CompWindowStateMaximizedHorzMask;
1373
else if (strcasecmp (str, "shaded") == 0)
1374
return CompWindowStateShadedMask;
1375
else if (strcasecmp (str, "skiptaskbar") == 0)
1376
return CompWindowStateSkipTaskbarMask;
1377
else if (strcasecmp (str, "skippager") == 0)
1378
return CompWindowStateSkipPagerMask;
1379
else if (strcasecmp (str, "hidden") == 0)
1380
return CompWindowStateHiddenMask;
1381
else if (strcasecmp (str, "fullscreen") == 0)
1382
return CompWindowStateFullscreenMask;
1383
else if (strcasecmp (str, "above") == 0)
1384
return CompWindowStateAboveMask;
1385
else if (strcasecmp (str, "below") == 0)
1386
return CompWindowStateBelowMask;
1387
else if (strcasecmp (str, "demandsattention") == 0)
1388
return CompWindowStateDemandsAttentionMask;
1394
PrivateScreen::getWindowState (Window id)
1398
unsigned long n, left;
1399
unsigned char *data;
1400
unsigned int state = 0;
1402
result = XGetWindowProperty (priv->dpy, id,
1404
0L, 1024L, false, XA_ATOM, &actual, &format,
1407
if (result == Success && data)
1409
Atom *a = (Atom *) data;
1412
state |= windowStateMask (*a++);
1414
XFree ((void *) data);
1421
PrivateScreen::setWindowState (unsigned int state, Window id)
1426
if (state & CompWindowStateModalMask)
1427
data[i++] = Atoms::winStateModal;
1428
if (state & CompWindowStateStickyMask)
1429
data[i++] = Atoms::winStateSticky;
1430
if (state & CompWindowStateMaximizedVertMask)
1431
data[i++] = Atoms::winStateMaximizedVert;
1432
if (state & CompWindowStateMaximizedHorzMask)
1433
data[i++] = Atoms::winStateMaximizedHorz;
1434
if (state & CompWindowStateShadedMask)
1435
data[i++] = Atoms::winStateShaded;
1436
if (state & CompWindowStateSkipTaskbarMask)
1437
data[i++] = Atoms::winStateSkipTaskbar;
1438
if (state & CompWindowStateSkipPagerMask)
1439
data[i++] = Atoms::winStateSkipPager;
1440
if (state & CompWindowStateHiddenMask)
1441
data[i++] = Atoms::winStateHidden;
1442
if (state & CompWindowStateFullscreenMask)
1443
data[i++] = Atoms::winStateFullscreen;
1444
if (state & CompWindowStateAboveMask)
1445
data[i++] = Atoms::winStateAbove;
1446
if (state & CompWindowStateBelowMask)
1447
data[i++] = Atoms::winStateBelow;
1448
if (state & CompWindowStateDemandsAttentionMask)
1449
data[i++] = Atoms::winStateDemandsAttention;
1450
if (state & CompWindowStateDisplayModalMask)
1451
data[i++] = Atoms::winStateDisplayModal;
1453
XChangeProperty (priv->dpy, id, Atoms::winState,
1454
XA_ATOM, 32, PropModeReplace,
1455
(unsigned char *) data, i);
1459
PrivateScreen::getWindowType (Window id)
1461
Atom actual, a = None;
1463
unsigned long n, left;
1464
unsigned char *data;
1466
result = XGetWindowProperty (priv->dpy , id,
1468
0L, 1L, false, XA_ATOM, &actual, &format,
1471
if (result == Success && data)
1474
memcpy (&a, data, sizeof (Atom));
1475
XFree ((void *) data);
1480
if (a == Atoms::winTypeNormal)
1481
return CompWindowTypeNormalMask;
1482
else if (a == Atoms::winTypeMenu)
1483
return CompWindowTypeMenuMask;
1484
else if (a == Atoms::winTypeDesktop)
1485
return CompWindowTypeDesktopMask;
1486
else if (a == Atoms::winTypeDock)
1487
return CompWindowTypeDockMask;
1488
else if (a == Atoms::winTypeToolbar)
1489
return CompWindowTypeToolbarMask;
1490
else if (a == Atoms::winTypeUtil)
1491
return CompWindowTypeUtilMask;
1492
else if (a == Atoms::winTypeSplash)
1493
return CompWindowTypeSplashMask;
1494
else if (a == Atoms::winTypeDialog)
1495
return CompWindowTypeDialogMask;
1496
else if (a == Atoms::winTypeDropdownMenu)
1497
return CompWindowTypeDropdownMenuMask;
1498
else if (a == Atoms::winTypePopupMenu)
1499
return CompWindowTypePopupMenuMask;
1500
else if (a == Atoms::winTypeTooltip)
1501
return CompWindowTypeTooltipMask;
1502
else if (a == Atoms::winTypeNotification)
1503
return CompWindowTypeNotificationMask;
1504
else if (a == Atoms::winTypeCombo)
1505
return CompWindowTypeComboMask;
1506
else if (a == Atoms::winTypeDnd)
1507
return CompWindowTypeDndMask;
1510
return CompWindowTypeUnknownMask;
1514
PrivateScreen::getMwmHints (Window id,
1516
unsigned int *decor)
1520
unsigned long n, left;
1521
unsigned char *data;
1524
*decor = MwmDecorAll;
1526
result = XGetWindowProperty (priv->dpy, id,
1528
0L, 20L, false, Atoms::mwmHints,
1529
&actual, &format, &n, &left, &data);
1531
if (result == Success && data)
1533
MwmHints *mwmHints = (MwmHints *) data;
1535
if (n >= PropMotifWmHintElements)
1537
if (mwmHints->flags & MwmHintsDecorations)
1538
*decor = mwmHints->decorations;
1540
if (mwmHints->flags & MwmHintsFunctions)
1541
*func = mwmHints->functions;
1549
PrivateScreen::getProtocols (Window id)
1553
unsigned int protocols = 0;
1555
if (XGetWMProtocols (priv->dpy, id, &protocol, &count))
1559
for (i = 0; i < count; i++)
1561
if (protocol[i] == Atoms::wmDeleteWindow)
1562
protocols |= CompWindowProtocolDeleteMask;
1563
else if (protocol[i] == Atoms::wmTakeFocus)
1564
protocols |= CompWindowProtocolTakeFocusMask;
1565
else if (protocol[i] == Atoms::wmPing)
1566
protocols |= CompWindowProtocolPingMask;
1567
else if (protocol[i] == Atoms::wmSyncRequest)
1568
protocols |= CompWindowProtocolSyncRequestMask;
1578
CompScreen::getWindowProp (Window id,
1580
unsigned int defaultValue)
1584
unsigned long n, left;
1585
unsigned char *data;
1586
unsigned int retval = defaultValue;
1588
result = XGetWindowProperty (priv->dpy, id, property,
1589
0L, 1L, false, XA_CARDINAL, &actual, &format,
1592
if (result == Success && data)
1596
unsigned long value;
1597
memcpy (&value, data, sizeof (unsigned long));
1598
retval = (unsigned int) value;
1608
CompScreen::setWindowProp (Window id,
1612
unsigned long data = value;
1614
XChangeProperty (priv->dpy, id, property,
1615
XA_CARDINAL, 32, PropModeReplace,
1616
(unsigned char *) &data, 1);
1620
PrivateScreen::readWindowProp32 (Window id,
1622
unsigned short *returnValue)
1626
unsigned long n, left;
1627
unsigned char *data;
1628
bool retval = false;
1630
result = XGetWindowProperty (priv->dpy, id, property,
1631
0L, 1L, false, XA_CARDINAL, &actual, &format,
1634
if (result == Success && data)
1640
memcpy (&value, data, sizeof (CARD32));
1642
*returnValue = value >> 16;
1652
CompScreen::getWindowProp32 (Window id,
1654
unsigned short defaultValue)
1656
unsigned short result;
1658
if (priv->readWindowProp32 (id, property, &result))
1661
return defaultValue;
1665
CompScreen::setWindowProp32 (Window id,
1667
unsigned short value)
1671
value32 = value << 16 | value;
1673
XChangeProperty (priv->dpy, id, property,
1674
XA_CARDINAL, 32, PropModeReplace,
1675
(unsigned char *) &value32, 1);
1679
ScreenInterface::handleEvent (XEvent *event)
1680
WRAPABLE_DEF (handleEvent, event)
1683
ScreenInterface::handleCompizEvent (const char *plugin,
1685
CompOption::Vector &options)
1686
WRAPABLE_DEF (handleCompizEvent, plugin, event, options)
1689
ScreenInterface::fileToImage (CompString &name,
1693
WRAPABLE_DEF (fileToImage, name, size, stride, data)
1696
ScreenInterface::imageToFile (CompString &path,
1701
WRAPABLE_DEF (imageToFile, path, format, size, stride, data)
1703
CompMatch::Expression *
1704
ScreenInterface::matchInitExp (const CompString& value)
1705
WRAPABLE_DEF (matchInitExp, value)
1708
ScreenInterface::matchExpHandlerChanged ()
1709
WRAPABLE_DEF (matchExpHandlerChanged)
1712
ScreenInterface::matchPropertyChanged (CompWindow *window)
1713
WRAPABLE_DEF (matchPropertyChanged, window)
1716
ScreenInterface::logMessage (const char *componentName,
1718
const char *message)
1719
WRAPABLE_DEF (logMessage, componentName, level, message)
1723
PrivateScreen::desktopHintEqual (unsigned long *data,
1728
if (size != desktopHintSize)
1731
if (memcmp (data + offset,
1732
desktopHintData + offset,
1733
hintSize * sizeof (unsigned long)) == 0)
1740
PrivateScreen::setDesktopHints ()
1742
unsigned long *data;
1743
int dSize, offset, hintSize;
1746
dSize = nDesktop * 2 + nDesktop * 2 + nDesktop * 4 + 1;
1748
data = (unsigned long *) malloc (sizeof (unsigned long) * dSize);
1753
hintSize = nDesktop * 2;
1755
for (i = 0; i < nDesktop; i++)
1757
data[offset + i * 2 + 0] = vp.x () * screen->width ();
1758
data[offset + i * 2 + 1] = vp.y () * screen->height ();
1761
if (!desktopHintEqual (data, dSize, offset, hintSize))
1762
XChangeProperty (dpy, root,
1763
Atoms::desktopViewport,
1764
XA_CARDINAL, 32, PropModeReplace,
1765
(unsigned char *) &data[offset], hintSize);
1769
for (i = 0; i < nDesktop; i++)
1771
data[offset + i * 2 + 0] = screen->width () * vpSize.width ();
1772
data[offset + i * 2 + 1] = screen->height () * vpSize.height ();
1775
if (!desktopHintEqual (data, dSize, offset, hintSize))
1776
XChangeProperty (dpy, root,
1777
Atoms::desktopGeometry,
1778
XA_CARDINAL, 32, PropModeReplace,
1779
(unsigned char *) &data[offset], hintSize);
1782
hintSize = nDesktop * 4;
1784
for (i = 0; i < nDesktop; i++)
1786
data[offset + i * 4 + 0] = workArea.x ();
1787
data[offset + i * 4 + 1] = workArea.y ();
1788
data[offset + i * 4 + 2] = workArea.width ();
1789
data[offset + i * 4 + 3] = workArea.height ();
1792
if (!desktopHintEqual (data, dSize, offset, hintSize))
1793
XChangeProperty (dpy, root,
1795
XA_CARDINAL, 32, PropModeReplace,
1796
(unsigned char *) &data[offset], hintSize);
1800
data[offset] = nDesktop;
1803
if (!desktopHintEqual (data, dSize, offset, hintSize))
1804
XChangeProperty (dpy, root,
1805
Atoms::numberOfDesktops,
1806
XA_CARDINAL, 32, PropModeReplace,
1807
(unsigned char *) &data[offset], hintSize);
1809
if (desktopHintData)
1810
free (desktopHintData);
1812
desktopHintData = data;
1813
desktopHintSize = dSize;
1817
PrivateScreen::setVirtualScreenSize (int newh, int newv)
1819
/* if newh or newv is being reduced */
1820
if (newh < screen->vpSize ().width () ||
1821
newv < screen->vpSize ().height ())
1826
if (screen->vp ().x () >= newh)
1827
tx = screen->vp ().x () - (newh - 1);
1828
if (screen->vp ().y () >= newv)
1829
ty = screen->vp ().y () - (newv - 1);
1831
if (tx != 0 || ty != 0)
1832
screen->moveViewport (tx, ty, TRUE);
1834
/* Move windows that were in one of the deleted viewports into the
1836
foreach (CompWindow *w, screen->windows ())
1841
if (w->onAllViewports ())
1844
/* Find which viewport the (inner) window's top-left corner falls
1845
in, and check if it's outside the new viewport horizontal and
1846
vertical index range */
1847
if (newh < screen->vpSize ().width ())
1849
int vpX; /* x index of a window's vp */
1851
vpX = w->serverX () / screen->width ();
1852
if (w->serverX () < 0)
1855
vpX += screen->vp ().x (); /* Convert relative to absolute vp index */
1857
/* Move windows too far right to left */
1859
moveX = ((newh - 1) - vpX) * screen->width ();
1861
if (newv < screen->vpSize ().height ())
1863
int vpY; /* y index of a window's vp */
1865
vpY = w->serverY () / screen->height ();
1866
if (w->serverY () < 0)
1869
vpY += screen->vp ().y (); /* Convert relative to absolute vp index */
1871
/* Move windows too far right to left */
1873
moveY = ((newv - 1) - vpY) * screen->height ();
1876
if (moveX != 0 || moveY != 0)
1878
w->move (moveX, moveY, true);
1884
vpSize.setWidth (newh);
1885
vpSize.setHeight (newv);
1891
PrivateScreen::updateOutputDevices ()
1893
CompOption::Value::Vector &list = optionGetOutputs ();
1894
unsigned int nOutput = 0;
1896
unsigned int uWidth, uHeight;
1901
foreach (CompOption::Value &value, list)
1905
uWidth = (unsigned) screen->width ();
1906
uHeight = (unsigned) screen->height ();
1908
bits = XParseGeometry (value.s ().c_str (), &x, &y, &uWidth, &uHeight);
1909
width = (int) uWidth;
1910
height = (int) uHeight;
1912
if (bits & XNegative)
1913
x = screen->width () + x - width;
1915
if (bits & YNegative)
1916
y = screen->height () + y - height;
1927
if (x2 > screen->width ())
1928
x2 = screen->width ();
1929
if (y2 > screen->height ())
1930
y2 = screen->height ();
1932
if (x1 < x2 && y1 < y2)
1934
if (outputDevs.size () < nOutput + 1)
1935
outputDevs.resize (nOutput + 1);
1937
outputDevs[nOutput].setGeometry (x1, y1, x2 - x1, y2 - y1);
1942
/* make sure we have at least one output */
1945
if (outputDevs.size () < 1)
1946
outputDevs.resize (1);
1948
outputDevs[0].setGeometry (0, 0, screen->width (), screen->height ());
1952
if (outputDevs.size () > nOutput)
1953
outputDevs.resize (nOutput);
1955
/* set name, width, height and update rect pointers in all regions */
1956
for (unsigned int i = 0; i < nOutput; i++)
1958
snprintf (str, 10, "Output %d", i);
1959
outputDevs[i].setId (str, i);
1962
hasOverlappingOutputs = false;
1964
setCurrentOutput (currentOutputDev);
1966
/* clear out fullscreen monitor hints of all windows as
1967
suggested on monitor layout changes in EWMH */
1968
foreach (CompWindow *w, windows)
1969
if (w->priv->fullscreenMonitorsSet)
1970
w->priv->setFullscreenMonitors (NULL);
1972
for (unsigned int i = 0; i < nOutput - 1; i++)
1973
for (unsigned int j = i + 1; j < nOutput; j++)
1974
if (outputDevs[i].intersects (outputDevs[j]))
1975
hasOverlappingOutputs = true;
1977
screen->updateWorkarea ();
1979
screen->outputChangeNotify ();
1983
PrivateScreen::detectOutputDevices ()
1985
if (!noDetection && optionGetDetectOutputs ())
1988
CompOption::Value value;
1990
if (screenInfo.size ())
1992
CompOption::Value::Vector l;
1993
foreach (XineramaScreenInfo xi, screenInfo)
1995
l.push_back (compPrintf ("%dx%d+%d+%d", xi.width, xi.height,
1996
xi.x_org, xi.y_org));
1999
value.set (CompOption::TypeString, l);
2003
CompOption::Value::Vector l;
2004
l.push_back (compPrintf ("%dx%d+%d+%d", screen->width (),
2005
screen->height (), 0, 0));
2006
value.set (CompOption::TypeString, l);
2009
mOptions[CoreOptions::DetectOutputs].value ().set (false);
2010
screen->setOptionForPlugin ("core", "outputs", value);
2011
mOptions[CoreOptions::DetectOutputs].value ().set (true);
2016
updateOutputDevices ();
2022
PrivateScreen::updateStartupFeedback ()
2024
if (!startupSequences.empty ())
2025
XDefineCursor (dpy, root, busyCursor);
2027
XDefineCursor (dpy, root, normalCursor);
2030
#define STARTUP_TIMEOUT_DELAY 15000
2033
PrivateScreen::handleStartupSequenceTimeout ()
2035
struct timeval now, active;
2038
gettimeofday (&now, NULL);
2040
foreach (CompStartupSequence *s, startupSequences)
2042
sn_startup_sequence_get_last_active_time (s->sequence,
2046
elapsed = ((((double) now.tv_sec - active.tv_sec) * 1000000.0 +
2047
(now.tv_usec - active.tv_usec))) / 1000.0;
2049
if (elapsed > STARTUP_TIMEOUT_DELAY)
2050
sn_startup_sequence_complete (s->sequence);
2057
PrivateScreen::addSequence (SnStartupSequence *sequence)
2059
CompStartupSequence *s;
2061
s = new CompStartupSequence ();
2065
sn_startup_sequence_ref (sequence);
2067
s->sequence = sequence;
2068
s->viewportX = vp.x ();
2069
s->viewportY = vp.y ();
2071
startupSequences.push_front (s);
2073
if (!startupSequenceTimer.active ())
2074
startupSequenceTimer.start ();
2076
updateStartupFeedback ();
2080
PrivateScreen::removeSequence (SnStartupSequence *sequence)
2082
CompStartupSequence *s = NULL;
2084
std::list<CompStartupSequence *>::iterator it = startupSequences.begin ();
2086
for (; it != startupSequences.end (); it++)
2088
if ((*it)->sequence == sequence)
2098
sn_startup_sequence_unref (sequence);
2100
startupSequences.erase (it);
2104
if (startupSequences.empty () && startupSequenceTimer.active ())
2105
startupSequenceTimer.stop ();
2107
updateStartupFeedback ();
2111
PrivateScreen::removeAllSequences ()
2113
foreach (CompStartupSequence *s, startupSequences)
2115
sn_startup_sequence_unref (s->sequence);
2119
startupSequences.clear ();
2121
if (startupSequenceTimer.active ())
2122
startupSequenceTimer.stop ();
2124
updateStartupFeedback ();
2128
CompScreen::compScreenSnEvent (SnMonitorEvent *event,
2131
CompScreen *screen = (CompScreen *) userData;
2132
SnStartupSequence *sequence;
2134
sequence = sn_monitor_event_get_startup_sequence (event);
2136
switch (sn_monitor_event_get_type (event)) {
2137
case SN_MONITOR_EVENT_INITIATED:
2138
screen->priv->addSequence (sequence);
2140
case SN_MONITOR_EVENT_COMPLETED:
2141
screen->priv->removeSequence (sequence);
2143
case SN_MONITOR_EVENT_CHANGED:
2144
case SN_MONITOR_EVENT_CANCELED:
2150
PrivateScreen::updateScreenEdges ()
2152
struct screenEdgeGeometry {
2157
} geometry[SCREEN_EDGE_NUM] = {
2158
{ 0, 0, 0, 2, 0, 2, 1, -4 }, /* left */
2159
{ 1, -2, 0, 2, 0, 2, 1, -4 }, /* right */
2160
{ 0, 2, 0, 0, 1, -4, 0, 2 }, /* top */
2161
{ 0, 2, 1, -2, 1, -4, 0, 2 }, /* bottom */
2162
{ 0, 0, 0, 0, 0, 2, 0, 2 }, /* top-left */
2163
{ 1, -2, 0, 0, 0, 2, 0, 2 }, /* top-right */
2164
{ 0, 0, 1, -2, 0, 2, 0, 2 }, /* bottom-left */
2165
{ 1, -2, 1, -2, 0, 2, 0, 2 } /* bottom-right */
2169
for (i = 0; i < SCREEN_EDGE_NUM; i++)
2171
if (screenEdge[i].id)
2172
XMoveResizeWindow (dpy, screenEdge[i].id,
2173
geometry[i].xw * screen->width () +
2175
geometry[i].yh * screen->height () +
2177
geometry[i].ww * screen->width () +
2179
geometry[i].hh * screen->height () +
2185
PrivateScreen::setCurrentOutput (unsigned int outputNum)
2187
if (outputNum >= priv->outputDevs.size ())
2190
priv->currentOutputDev = outputNum;
2194
PrivateScreen::reshape (int w, int h)
2196
updateScreenInfo ();
2198
region = CompRegion (0, 0, w, h);
2200
screen->setWidth (w);
2201
screen->setHeight (h);
2203
fullscreenOutput.setId ("fullscreen", ~0);
2204
fullscreenOutput.setGeometry (0, 0, w, h);
2206
updateScreenEdges ();
2210
PrivateScreen::configure (XConfigureEvent *ce)
2212
if (priv->attrib.width != ce->width ||
2213
priv->attrib.height != ce->height)
2215
priv->attrib.width = ce->width;
2216
priv->attrib.height = ce->height;
2218
priv->reshape (ce->width, ce->height);
2220
priv->detectOutputDevices ();
2225
PrivateScreen::setSupportingWmCheck ()
2227
XChangeProperty (dpy, grabWindow,
2228
Atoms::supportingWmCheck,
2229
XA_WINDOW, 32, PropModeReplace,
2230
(unsigned char *) &grabWindow, 1);
2232
XChangeProperty (dpy, grabWindow, Atoms::wmName,
2233
Atoms::utf8String, 8, PropModeReplace,
2234
(unsigned char *) PACKAGE, strlen (PACKAGE));
2235
XChangeProperty (dpy, grabWindow, Atoms::winState,
2236
XA_ATOM, 32, PropModeReplace,
2237
(unsigned char *) &Atoms::winStateSkipTaskbar,
2239
XChangeProperty (dpy, grabWindow, Atoms::winState,
2240
XA_ATOM, 32, PropModeAppend,
2241
(unsigned char *) &Atoms::winStateSkipPager, 1);
2242
XChangeProperty (dpy, grabWindow, Atoms::winState,
2243
XA_ATOM, 32, PropModeAppend,
2244
(unsigned char *) &Atoms::winStateHidden, 1);
2246
XChangeProperty (dpy, root, Atoms::supportingWmCheck,
2247
XA_WINDOW, 32, PropModeReplace,
2248
(unsigned char *) &grabWindow, 1);
2252
CompScreen::updateSupportedWmHints ()
2254
std::vector<Atom> atoms;
2256
addSupportedAtoms (atoms);
2258
XChangeProperty (dpy (), root (), Atoms::supported,
2259
XA_ATOM, 32, PropModeReplace,
2260
(const unsigned char *) &atoms.at (0), atoms.size ());
2264
CompScreen::addSupportedAtoms (std::vector<Atom> &atoms)
2266
WRAPABLE_HND_FUNC (17, addSupportedAtoms, atoms);
2268
atoms.push_back (Atoms::supported);
2269
atoms.push_back (Atoms::supportingWmCheck);
2271
atoms.push_back (Atoms::utf8String);
2273
atoms.push_back (Atoms::clientList);
2274
atoms.push_back (Atoms::clientListStacking);
2276
atoms.push_back (Atoms::winActive);
2278
atoms.push_back (Atoms::desktopViewport);
2279
atoms.push_back (Atoms::desktopGeometry);
2280
atoms.push_back (Atoms::currentDesktop);
2281
atoms.push_back (Atoms::numberOfDesktops);
2282
atoms.push_back (Atoms::showingDesktop);
2284
atoms.push_back (Atoms::workarea);
2286
atoms.push_back (Atoms::wmName);
2288
atoms.push_back (Atoms::wmVisibleName);
2291
atoms.push_back (Atoms::wmStrut);
2292
atoms.push_back (Atoms::wmStrutPartial);
2295
atoms.push_back (Atoms::wmPid);
2298
atoms.push_back (Atoms::wmUserTime);
2299
atoms.push_back (Atoms::frameExtents);
2300
atoms.push_back (Atoms::frameWindow);
2302
atoms.push_back (Atoms::winState);
2303
atoms.push_back (Atoms::winStateModal);
2304
atoms.push_back (Atoms::winStateSticky);
2305
atoms.push_back (Atoms::winStateMaximizedVert);
2306
atoms.push_back (Atoms::winStateMaximizedHorz);
2307
atoms.push_back (Atoms::winStateShaded);
2308
atoms.push_back (Atoms::winStateSkipTaskbar);
2309
atoms.push_back (Atoms::winStateSkipPager);
2310
atoms.push_back (Atoms::winStateHidden);
2311
atoms.push_back (Atoms::winStateFullscreen);
2312
atoms.push_back (Atoms::winStateAbove);
2313
atoms.push_back (Atoms::winStateBelow);
2314
atoms.push_back (Atoms::winStateDemandsAttention);
2316
atoms.push_back (Atoms::winOpacity);
2317
atoms.push_back (Atoms::winBrightness);
2323
atoms.push_back (Atoms::winSaturation);
2324
atoms.push_back (Atoms::winStateDisplayModal);
2328
atoms.push_back (Atoms::wmAllowedActions);
2330
atoms.push_back (Atoms::winActionMove);
2331
atoms.push_back (Atoms::winActionResize);
2332
atoms.push_back (Atoms::winActionStick);
2333
atoms.push_back (Atoms::winActionMinimize);
2334
atoms.push_back (Atoms::winActionMaximizeHorz);
2335
atoms.push_back (Atoms::winActionMaximizeVert);
2336
atoms.push_back (Atoms::winActionFullscreen);
2337
atoms.push_back (Atoms::winActionClose);
2338
atoms.push_back (Atoms::winActionShade);
2339
atoms.push_back (Atoms::winActionChangeDesktop);
2340
atoms.push_back (Atoms::winActionAbove);
2341
atoms.push_back (Atoms::winActionBelow);
2343
atoms.push_back (Atoms::winType);
2344
atoms.push_back (Atoms::winTypeDesktop);
2345
atoms.push_back (Atoms::winTypeDock);
2346
atoms.push_back (Atoms::winTypeToolbar);
2347
atoms.push_back (Atoms::winTypeMenu);
2348
atoms.push_back (Atoms::winTypeSplash);
2349
atoms.push_back (Atoms::winTypeDialog);
2350
atoms.push_back (Atoms::winTypeUtil);
2351
atoms.push_back (Atoms::winTypeNormal);
2353
atoms.push_back (Atoms::wmDeleteWindow);
2354
atoms.push_back (Atoms::wmPing);
2356
atoms.push_back (Atoms::wmMoveResize);
2357
atoms.push_back (Atoms::moveResizeWindow);
2358
atoms.push_back (Atoms::restackWindow);
2360
atoms.push_back (Atoms::wmFullscreenMonitors);
2364
PrivateScreen::getDesktopHints ()
2366
unsigned long data[2];
2369
unsigned long n, left;
2370
unsigned char *propData;
2372
if (useDesktopHints)
2374
result = XGetWindowProperty (dpy, root,
2375
Atoms::numberOfDesktops,
2376
0L, 1L, false, XA_CARDINAL, &actual,
2377
&format, &n, &left, &propData);
2379
if (result == Success && propData)
2383
memcpy (data, propData, sizeof (unsigned long));
2384
if (data[0] > 0 && data[0] < 0xffffffff)
2391
result = XGetWindowProperty (dpy, root,
2392
Atoms::desktopViewport, 0L, 2L,
2393
false, XA_CARDINAL, &actual, &format,
2394
&n, &left, &propData);
2396
if (result == Success && propData)
2400
memcpy (data, propData, sizeof (unsigned long) * 2);
2402
if (data[0] / (unsigned int) screen->width () <
2403
(unsigned int) vpSize.width () - 1)
2404
vp.setX (data[0] / screen->width ());
2406
if (data[1] / (unsigned int) screen->height () <
2407
(unsigned int) vpSize.height () - 1)
2408
vp.setY (data[1] / screen->height ());
2414
result = XGetWindowProperty (dpy, root,
2415
Atoms::currentDesktop,
2416
0L, 1L, false, XA_CARDINAL, &actual,
2417
&format, &n, &left, &propData);
2419
if (result == Success && propData)
2423
memcpy (data, propData, sizeof (unsigned long));
2424
if (data[0] < nDesktop)
2425
currentDesktop = data[0];
2432
result = XGetWindowProperty (dpy, root,
2433
Atoms::showingDesktop,
2434
0L, 1L, false, XA_CARDINAL, &actual, &format,
2435
&n, &left, &propData);
2437
if (result == Success && propData)
2441
memcpy (data, propData, sizeof (unsigned long));
2443
screen->enterShowDesktopMode ();
2449
data[0] = currentDesktop;
2451
XChangeProperty (dpy, root, Atoms::currentDesktop,
2452
XA_CARDINAL, 32, PropModeReplace,
2453
(unsigned char *) data, 1);
2455
data[0] = showingDesktopMask ? true : false;
2457
XChangeProperty (dpy, root, Atoms::showingDesktop,
2458
XA_CARDINAL, 32, PropModeReplace,
2459
(unsigned char *) data, 1);
2463
CompScreen::enterShowDesktopMode ()
2465
WRAPABLE_HND_FUNC (14, enterShowDesktopMode)
2467
unsigned long data = 1;
2469
bool st = priv->optionGetHideSkipTaskbarWindows ();
2471
priv->showingDesktopMask = ~(CompWindowTypeDesktopMask |
2472
CompWindowTypeDockMask);
2474
foreach (CompWindow *w, priv->windows)
2476
if ((priv->showingDesktopMask & w->wmType ()) &&
2477
(!(w->state () & CompWindowStateSkipTaskbarMask) || st))
2479
if (!w->inShowDesktopMode () && !w->grabbed () &&
2480
w->managed () && w->focus ())
2482
w->setShowDesktopMode (true);
2483
w->windowNotify (CompWindowNotifyEnterShowDesktopMode);
2488
if (w->inShowDesktopMode ())
2494
priv->showingDesktopMask = 0;
2498
XChangeProperty (priv->dpy, priv->root,
2499
Atoms::showingDesktop,
2500
XA_CARDINAL, 32, PropModeReplace,
2501
(unsigned char *) &data, 1);
2505
CompScreen::leaveShowDesktopMode (CompWindow *window)
2507
WRAPABLE_HND_FUNC (15, leaveShowDesktopMode, window)
2509
unsigned long data = 0;
2513
if (!window->inShowDesktopMode ())
2516
window->setShowDesktopMode (false);
2517
window->windowNotify (CompWindowNotifyLeaveShowDesktopMode);
2518
window->priv->show ();
2520
/* return if some other window is still in show desktop mode */
2521
foreach (CompWindow *w, priv->windows)
2522
if (w->inShowDesktopMode ())
2525
priv->showingDesktopMask = 0;
2529
priv->showingDesktopMask = 0;
2531
foreach (CompWindow *w, priv->windows)
2533
if (!w->inShowDesktopMode ())
2536
w->setShowDesktopMode (false);
2537
w->windowNotify (CompWindowNotifyLeaveShowDesktopMode);
2541
/* focus default window - most likely this will be the window
2542
which had focus before entering showdesktop mode */
2543
focusDefaultWindow ();
2546
XChangeProperty (priv->dpy, priv->root,
2547
Atoms::showingDesktop,
2548
XA_CARDINAL, 32, PropModeReplace,
2549
(unsigned char *) &data, 1);
2553
CompScreen::forEachWindow (CompWindow::ForEach proc)
2555
foreach (CompWindow *w, priv->windows)
2560
CompScreen::focusDefaultWindow ()
2563
CompWindow *focus = NULL;
2565
if (!priv->optionGetClickToFocus ())
2567
w = findTopLevelWindow (priv->below);
2569
if (w && w->focus ())
2571
if (!(w->type () & (CompWindowTypeDesktopMask |
2572
CompWindowTypeDockMask)))
2578
Window rootReturn, childReturn;
2580
unsigned int dummyUInt;
2582
/* huh, we didn't find d->below ... perhaps it's out of date;
2583
try grabbing it through the server */
2585
status = XQueryPointer (dpy (), priv->root, &rootReturn,
2586
&childReturn, &dummyInt, &dummyInt,
2587
&dummyInt, &dummyInt, &dummyUInt);
2589
if (status && rootReturn == priv->root)
2591
w = findTopLevelWindow (childReturn);
2593
if (w && w->focus ())
2595
if (!(w->type () & (CompWindowTypeDesktopMask |
2596
CompWindowTypeDockMask)))
2605
for (CompWindowList::reverse_iterator rit = priv->windows.rbegin ();
2606
rit != priv->windows.rend (); rit++)
2610
if (w->type () & CompWindowTypeDockMask)
2617
if (w->type () & (CompWindowTypeNormalMask |
2618
CompWindowTypeDialogMask |
2619
CompWindowTypeModalDialogMask))
2621
if (PrivateWindow::compareWindowActiveness (focus, w) < 0)
2633
if (focus->id () != priv->activeWindow)
2634
focus->moveInputFocusTo ();
2638
XSetInputFocus (priv->dpy, priv->root, RevertToPointerRoot,
2644
CompScreen::findWindow (Window id)
2646
if (lastFoundWindow && lastFoundWindow->id () == id)
2648
return lastFoundWindow;
2652
CompWindow::Map::iterator it = priv->windowsMap.find (id);
2654
if (it != priv->windowsMap.end ())
2655
return (lastFoundWindow = it->second);
2662
CompScreen::findTopLevelWindow (Window id, bool override_redirect)
2666
w = findWindow (id);
2670
if (w->overrideRedirect () && !override_redirect)
2676
foreach (CompWindow *w, priv->windows)
2677
if (w->frame () == id)
2679
if (w->overrideRedirect () && !override_redirect)
2689
CompScreen::insertWindow (CompWindow *w, Window aboveId)
2694
if (!aboveId || priv->windows.empty ())
2696
if (!priv->windows.empty ())
2698
priv->windows.front ()->prev = w;
2699
w->next = priv->windows.front ();
2701
priv->windows.push_front (w);
2703
priv->windowsMap[w->id ()] = w;
2708
CompWindowList::iterator it = priv->windows.begin ();
2710
while (it != priv->windows.end ())
2712
if ((*it)->id () == aboveId ||
2713
((*it)->frame () && (*it)->frame () == aboveId))
2720
if (it == priv->windows.end ())
2728
w->next = (*it)->next;
2737
priv->windows.insert (++it, w);
2739
priv->windowsMap[w->id ()] = w;
2743
PrivateScreen::eraseWindowFromMap (Window id)
2746
priv->windowsMap.erase (id);
2750
CompScreen::unhookWindow (CompWindow *w)
2752
CompWindowList::iterator it =
2753
std::find (priv->windows.begin (), priv->windows.end (), w);
2755
priv->windows.erase (it);
2756
priv->eraseWindowFromMap (w->id ());
2759
w->next->prev = w->prev;
2762
w->prev->next = w->next;
2767
if (w == lastFoundWindow)
2768
lastFoundWindow = NULL;
2772
CompScreen::normalCursor ()
2774
return priv->normalCursor;
2778
CompScreen::invisibleCursor ()
2780
return priv->invisibleCursor;
2783
#define POINTER_GRAB_MASK (ButtonReleaseMask | \
2786
CompScreen::GrabHandle
2787
CompScreen::pushGrab (Cursor cursor, const char *name)
2789
if (priv->grabs.empty ())
2793
status = XGrabPointer (priv->dpy, priv->grabWindow, true,
2795
GrabModeAsync, GrabModeAsync,
2799
if (status == GrabSuccess)
2801
status = XGrabKeyboard (priv->dpy,
2802
priv->grabWindow, true,
2803
GrabModeAsync, GrabModeAsync,
2805
if (status != GrabSuccess)
2807
XUngrabPointer (priv->dpy, CurrentTime);
2816
XChangeActivePointerGrab (priv->dpy, POINTER_GRAB_MASK,
2817
cursor, CurrentTime);
2820
PrivateScreen::Grab *grab = new PrivateScreen::Grab ();
2821
grab->cursor = cursor;
2824
priv->grabs.push_back (grab);
2830
CompScreen::updateGrab (CompScreen::GrabHandle handle, Cursor cursor)
2835
XChangeActivePointerGrab (priv->dpy, POINTER_GRAB_MASK,
2836
cursor, CurrentTime);
2838
((PrivateScreen::Grab *) handle)->cursor = cursor;
2842
CompScreen::removeGrab (CompScreen::GrabHandle handle,
2843
CompPoint *restorePointer)
2848
std::list<PrivateScreen::Grab *>::iterator it;
2850
it = std::find (priv->grabs.begin (), priv->grabs.end (), handle);
2852
if (it != priv->grabs.end ())
2854
priv->grabs.erase (it);
2855
delete (static_cast<PrivateScreen::Grab *> (handle));
2857
if (!priv->grabs.empty ())
2859
XChangeActivePointerGrab (priv->dpy,
2861
priv->grabs.back ()->cursor,
2867
warpPointer (restorePointer->x () - pointerX,
2868
restorePointer->y () - pointerY);
2870
XUngrabPointer (priv->dpy, CurrentTime);
2871
XUngrabKeyboard (priv->dpy, CurrentTime);
2875
/* otherScreenGrabExist takes a series of strings terminated by a NULL.
2876
It returns true if a grab exists but it is NOT held by one of the
2877
plugins listed, returns false otherwise. */
2880
CompScreen::otherGrabExist (const char *first, ...)
2885
std::list<PrivateScreen::Grab *>::iterator it;
2887
for (it = priv->grabs.begin (); it != priv->grabs.end (); it++)
2889
va_start (ap, first);
2894
if (strcmp (name, (*it)->name) == 0)
2897
name = va_arg (ap, const char *);
2910
CompScreen::grabExist (const char *grab)
2912
foreach (PrivateScreen::Grab* g, priv->grabs)
2914
if (strcmp (g->name, grab) == 0)
2921
CompScreen::grabbed ()
2923
return priv->grabbed;
2927
PrivateScreen::grabUngrabOneKey (unsigned int modifiers,
2951
PrivateScreen::grabUngrabKeys (unsigned int modifiers,
2956
unsigned int ignore;
2958
CompScreen::checkForError (dpy);
2960
for (ignore = 0; ignore <= modHandler->ignoredModMask (); ignore++)
2962
if (ignore & ~modHandler->ignoredModMask ())
2967
grabUngrabOneKey (modifiers | ignore, keycode, grab);
2971
for (mod = 0; mod < 8; mod++)
2973
if (modifiers & (1 << mod))
2975
for (k = mod * modHandler->modMap ()->max_keypermod;
2976
k < (mod + 1) * modHandler->modMap ()->max_keypermod;
2979
if (modHandler->modMap ()->modifiermap[k])
2981
grabUngrabOneKey ((modifiers & ~(1 << mod)) |
2983
modHandler->modMap ()->modifiermap[k],
2991
if (CompScreen::checkForError (dpy))
2999
PrivateScreen::addPassiveKeyGrab (CompAction::KeyBinding &key)
3003
std::list<KeyGrab>::iterator it;
3005
mask = modHandler->virtualToRealModMask (key.modifiers ());
3007
for (it = keyGrabs.begin (); it != keyGrabs.end (); it++)
3009
if (key.keycode () == (*it).keycode &&
3010
mask == (*it).modifiers)
3019
if (!(mask & CompNoMask))
3021
if (!grabUngrabKeys (mask, key.keycode (), true))
3025
newKeyGrab.keycode = key.keycode ();
3026
newKeyGrab.modifiers = mask;
3027
newKeyGrab.count = 1;
3029
keyGrabs.push_back (newKeyGrab);
3035
PrivateScreen::removePassiveKeyGrab (CompAction::KeyBinding &key)
3038
std::list<KeyGrab>::iterator it;
3040
mask = modHandler->virtualToRealModMask (key.modifiers ());
3042
for (it = keyGrabs.begin (); it != keyGrabs.end (); it++)
3044
if (key.keycode () == (*it).keycode &&
3045
mask == (*it).modifiers)
3051
it = keyGrabs.erase (it);
3053
if (!(mask & CompNoMask))
3054
grabUngrabKeys (mask, key.keycode (), false);
3060
PrivateScreen::updatePassiveKeyGrabs ()
3062
std::list<KeyGrab>::iterator it;
3064
XUngrabKey (dpy, AnyKey, AnyModifier, root);
3066
for (it = keyGrabs.begin (); it != keyGrabs.end (); it++)
3068
if (!((*it).modifiers & CompNoMask))
3070
grabUngrabKeys ((*it).modifiers,
3071
(*it).keycode, true);
3077
PrivateScreen::addPassiveButtonGrab (CompAction::ButtonBinding &button)
3079
ButtonGrab newButtonGrab;
3080
std::list<ButtonGrab>::iterator it;
3082
for (it = buttonGrabs.begin (); it != buttonGrabs.end (); it++)
3084
if (button.button () == (*it).button &&
3085
button.modifiers () == (*it).modifiers)
3092
newButtonGrab.button = button.button ();
3093
newButtonGrab.modifiers = button.modifiers ();
3094
newButtonGrab.count = 1;
3096
buttonGrabs.push_back (newButtonGrab);
3098
foreach (CompWindow *w, screen->windows ())
3099
w->priv->updatePassiveButtonGrabs ();
3105
PrivateScreen::removePassiveButtonGrab (CompAction::ButtonBinding &button)
3107
std::list<ButtonGrab>::iterator it;
3109
for (it = buttonGrabs.begin (); it != buttonGrabs.end (); it++)
3111
if (button.button () == (*it).button &&
3112
button.modifiers () == (*it).modifiers)
3118
it = buttonGrabs.erase (it);
3120
foreach (CompWindow *w, screen->windows ())
3121
w->priv->updatePassiveButtonGrabs ();
3126
/* add actions that should be automatically added as no screens
3127
existed when they were initialized. */
3129
PrivateScreen::addScreenActions ()
3131
foreach (CompOption &o, mOptions)
3136
if (o.value ().action ().state () & CompAction::StateAutoGrab)
3137
screen->addAction (&o.value ().action ());
3142
CompScreen::addAction (CompAction *action)
3144
if (!screenInitalized || !priv->initialized)
3147
if (action->active ())
3150
if (action->type () & CompAction::BindingTypeKey)
3152
if (!priv->addPassiveKeyGrab (action->key ()))
3156
if (action->type () & CompAction::BindingTypeButton)
3158
if (!priv->addPassiveButtonGrab (action->button ()))
3160
if (action->type () & CompAction::BindingTypeKey)
3161
priv->removePassiveKeyGrab (action->key ());
3167
if (action->edgeMask ())
3171
for (i = 0; i < SCREEN_EDGE_NUM; i++)
3172
if (action->edgeMask () & (1 << i))
3173
priv->enableEdge (i);
3176
action->priv->active = true;
3182
CompScreen::removeAction (CompAction *action)
3184
if (!priv->initialized)
3187
if (!action->active ())
3190
if (action->type () & CompAction::BindingTypeKey)
3191
priv->removePassiveKeyGrab (action->key ());
3193
if (action->type () & CompAction::BindingTypeButton)
3194
priv->removePassiveButtonGrab (action->button ());
3196
if (action->edgeMask ())
3200
for (i = 0; i < SCREEN_EDGE_NUM; i++)
3201
if (action->edgeMask () & (1 << i))
3202
priv->disableEdge (i);
3205
action->priv->active = false;
3209
PrivateScreen::computeWorkareaForBox (const CompRect& box)
3216
foreach (CompWindow *w, windows)
3218
if (!w->isMapped ())
3223
x1 = w->struts ()->left.x;
3224
y1 = w->struts ()->left.y;
3225
x2 = x1 + w->struts ()->left.width;
3226
y2 = y1 + w->struts ()->left.height;
3228
if (y1 < box.y2 () && y2 > box.y1 ())
3229
region -= CompRect (x1, box.y1 (), x2 - x1, box.height ());
3231
x1 = w->struts ()->right.x;
3232
y1 = w->struts ()->right.y;
3233
x2 = x1 + w->struts ()->right.width;
3234
y2 = y1 + w->struts ()->right.height;
3236
if (y1 < box.y2 () && y2 > box.y1 ())
3237
region -= CompRect (x1, box.y1 (), x2 - x1, box.height ());
3239
x1 = w->struts ()->top.x;
3240
y1 = w->struts ()->top.y;
3241
x2 = x1 + w->struts ()->top.width;
3242
y2 = y1 + w->struts ()->top.height;
3244
if (x1 < box.x2 () && x2 > box.x1 ())
3245
region -= CompRect (box.x1 (), y1, box.width (), y2 - y1);
3247
x1 = w->struts ()->bottom.x;
3248
y1 = w->struts ()->bottom.y;
3249
x2 = x1 + w->struts ()->bottom.width;
3250
y2 = y1 + w->struts ()->bottom.height;
3252
if (x1 < box.x2 () && x2 > box.x1 ())
3253
region -= CompRect (box.x1 (), y1, box.width (), y2 - y1);
3257
if (region.isEmpty ())
3259
compLogMessage ("core", CompLogLevelWarn,
3260
"Empty box after applying struts, ignoring struts");
3264
return region.boundingRect ();
3268
CompScreen::updateWorkarea ()
3271
bool workAreaChanged = false;
3273
for (unsigned int i = 0; i < priv->outputDevs.size (); i++)
3275
CompRect oldWorkArea = priv->outputDevs[i].workArea ();
3277
workArea = priv->computeWorkareaForBox (priv->outputDevs[i]);
3279
if (workArea != oldWorkArea)
3281
workAreaChanged = true;
3282
priv->outputDevs[i].setWorkArea (workArea);
3286
workArea = priv->computeWorkareaForBox (CompRect (0, 0,
3288
screen->height ()));
3290
if (priv->workArea != workArea)
3292
workAreaChanged = true;
3293
priv->workArea = workArea;
3295
priv->setDesktopHints ();
3298
if (workAreaChanged)
3300
/* as work area changed, update all maximized windows on this
3301
screen to snap to the new work area */
3302
foreach (CompWindow *w, priv->windows)
3303
w->priv->updateSize ();
3308
isClientListWindow (CompWindow *w)
3310
/* windows with client id less than 2 have been destroyed and only exists
3311
because some plugin keeps a reference to them. they should not be in
3316
if (w->overrideRedirect ())
3319
if (!w->isViewable ())
3321
if (!(w->state () & CompWindowStateHiddenMask))
3329
countClientListWindow (CompWindow *w,
3332
if (isClientListWindow (w))
3339
compareMappingOrder (const CompWindow *w1,
3340
const CompWindow *w2)
3342
return w1->mapNum () < w2->mapNum ();
3346
PrivateScreen::updateClientList ()
3348
bool updateClientList = false;
3349
bool updateClientListStacking = false;
3352
screen->forEachWindow (boost::bind (countClientListWindow, _1, &n));
3356
if ((unsigned int) n != priv->clientList.size ())
3358
priv->clientList.clear ();
3359
priv->clientListStacking.clear ();
3360
priv->clientIdList.clear ();
3361
priv->clientIdListStacking.clear ();
3363
XChangeProperty (priv->dpy, priv->root,
3365
XA_WINDOW, 32, PropModeReplace,
3366
(unsigned char *) &priv->grabWindow, 1);
3367
XChangeProperty (priv->dpy, priv->root,
3368
Atoms::clientListStacking,
3369
XA_WINDOW, 32, PropModeReplace,
3370
(unsigned char *) &priv->grabWindow, 1);
3376
if ((unsigned int) n != priv->clientList.size ())
3378
priv->clientIdList.resize (n);
3379
priv->clientIdListStacking.resize (n);
3381
updateClientList = updateClientListStacking = true;
3384
priv->clientListStacking.clear ();
3386
foreach (CompWindow *w, priv->windows)
3387
if (isClientListWindow (w))
3388
priv->clientListStacking.push_back (w);
3390
/* clear clientList and copy clientListStacking into clientList */
3391
priv->clientList = priv->clientListStacking;
3393
/* sort clientList in mapping order */
3394
sort (priv->clientList.begin (), priv->clientList.end (),
3395
compareMappingOrder);
3397
/* make sure client id lists are up-to-date */
3398
for (int i = 0; i < n; i++)
3400
if (!updateClientList &&
3401
priv->clientIdList[i] != priv->clientList[i]->id ())
3403
updateClientList = true;
3406
priv->clientIdList[i] = priv->clientList[i]->id ();
3408
for (int i = 0; i < n; i++)
3410
if (!updateClientListStacking &&
3411
priv->clientIdListStacking[i] != priv->clientListStacking[i]->id ())
3413
updateClientListStacking = true;
3416
priv->clientIdListStacking[i] = priv->clientListStacking[i]->id ();
3419
if (updateClientList)
3420
XChangeProperty (priv->dpy, priv->root,
3422
XA_WINDOW, 32, PropModeReplace,
3423
(unsigned char *) &priv->clientIdList.at (0), n);
3425
if (updateClientListStacking)
3426
XChangeProperty (priv->dpy, priv->root,
3427
Atoms::clientListStacking,
3428
XA_WINDOW, 32, PropModeReplace,
3429
(unsigned char *) &priv->clientIdListStacking.at (0),
3433
const CompWindowVector &
3434
CompScreen::clientList (bool stackingOrder)
3436
return stackingOrder ? priv->clientListStacking : priv->clientList;
3440
CompScreen::toolkitAction (Atom toolkitAction,
3449
ev.type = ClientMessage;
3450
ev.xclient.window = window;
3451
ev.xclient.message_type = Atoms::toolkitAction;
3452
ev.xclient.format = 32;
3453
ev.xclient.data.l[0] = toolkitAction;
3454
ev.xclient.data.l[1] = eventTime;
3455
ev.xclient.data.l[2] = data0;
3456
ev.xclient.data.l[3] = data1;
3457
ev.xclient.data.l[4] = data2;
3459
XUngrabPointer (priv->dpy, CurrentTime);
3460
XUngrabKeyboard (priv->dpy, CurrentTime);
3462
XSendEvent (priv->dpy, priv->root, false,
3463
StructureNotifyMask, &ev);
3467
CompScreen::runCommand (CompString command)
3469
if (command.size () == 0)
3475
CompString env (priv->displayString);
3479
pos = env.find (':');
3480
if (pos != std::string::npos)
3482
size_t pointPos = env.find ('.', pos);
3484
if (pointPos != std::string::npos)
3486
env.erase (pointPos);
3490
unsigned int displayNum = atoi (env.substr (pos + 1).c_str ());
3492
env.append (compPrintf (":%i", displayNum));
3496
env.append (compPrintf (".%d", priv->screenNum));
3498
putenv (const_cast<char *> (env.c_str ()));
3500
exit (execl ("/bin/sh", "/bin/sh", "-c", command.c_str (), NULL));
3505
CompScreen::moveViewport (int tx, int ty, bool sync)
3509
tx = priv->vp.x () - tx;
3510
tx = MOD (tx, priv->vpSize.width ());
3511
tx -= priv->vp.x ();
3513
ty = priv->vp.y () - ty;
3514
ty = MOD (ty, priv->vpSize.height ());
3515
ty -= priv->vp.y ();
3520
priv->vp.setX (priv->vp.x () + tx);
3521
priv->vp.setY (priv->vp.y () + ty);
3526
foreach (CompWindow *w, priv->windows)
3528
if (w->onAllViewports ())
3531
pnt = w->getMovementForOffset (CompPoint (tx, ty));
3533
if (w->saveMask () & CWX)
3534
w->saveWc ().x += pnt.x ();
3536
if (w->saveMask () & CWY)
3537
w->saveWc ().y += pnt.y ();
3540
w->move (pnt.x (), pnt.y ());
3550
priv->setDesktopHints ();
3552
priv->setCurrentActiveWindowHistory (priv->vp.x (), priv->vp.y ());
3554
w = findWindow (priv->activeWindow);
3559
dvp = w->defaultViewport ();
3561
/* add window to current history if it's default viewport is
3562
still the current one. */
3563
if (priv->vp.x () == dvp.x () && priv->vp.y () == dvp.y ())
3564
priv->addToCurrentActiveWindowHistory (w->id ());
3570
PrivateScreen::addGroup (Window id)
3572
CompGroup *group = new CompGroup ();
3577
priv->groups.push_back (group);
3583
PrivateScreen::removeGroup (CompGroup *group)
3589
std::list<CompGroup *>::iterator it =
3590
std::find (priv->groups.begin (), priv->groups.end (), group);
3592
if (it != priv->groups.end ())
3594
priv->groups.erase (it);
3601
PrivateScreen::findGroup (Window id)
3603
foreach (CompGroup *g, priv->groups)
3611
PrivateScreen::applyStartupProperties (CompWindow *window)
3613
CompStartupSequence *s = NULL;
3614
const char *startupId = window->startupId ();
3620
leader = screen->findWindow (window->clientLeader ());
3622
startupId = leader->startupId ();
3628
foreach (CompStartupSequence *ss, priv->startupSequences)
3632
id = sn_startup_sequence_get_id (ss->sequence);
3633
if (strcmp (id, startupId) == 0)
3641
window->priv->applyStartupProperties (s);
3645
CompScreen::sendWindowActivationRequest (Window id)
3649
xev.xclient.type = ClientMessage;
3650
xev.xclient.display = priv->dpy;
3651
xev.xclient.format = 32;
3653
xev.xclient.message_type = Atoms::winActive;
3654
xev.xclient.window = id;
3656
xev.xclient.data.l[0] = ClientTypePager;
3657
xev.xclient.data.l[1] = 0;
3658
xev.xclient.data.l[2] = 0;
3659
xev.xclient.data.l[3] = 0;
3660
xev.xclient.data.l[4] = 0;
3662
XSendEvent (priv->dpy, priv->root, false,
3663
SubstructureRedirectMask | SubstructureNotifyMask, &xev);
3667
PrivateScreen::enableEdge (int edge)
3669
priv->screenEdge[edge].count++;
3670
if (priv->screenEdge[edge].count == 1)
3671
XMapRaised (priv->dpy, priv->screenEdge[edge].id);
3675
PrivateScreen::disableEdge (int edge)
3677
priv->screenEdge[edge].count--;
3678
if (priv->screenEdge[edge].count == 0)
3679
XUnmapWindow (priv->dpy, priv->screenEdge[edge].id);
3683
PrivateScreen::getTopWindow ()
3685
/* return first window that has not been destroyed */
3686
for (CompWindowList::reverse_iterator rit = priv->windows.rbegin ();
3687
rit != priv->windows.rend (); rit++)
3689
if ((*rit)->id () > 1)
3690
return (*rit)->id ();
3697
CompScreen::outputDeviceForPoint (const CompPoint &point)
3699
return outputDeviceForPoint (point.x (), point.y ());
3703
CompScreen::outputDeviceForPoint (int x, int y)
3705
CompWindow::Geometry geom (x, y, 1, 1, 0);
3707
return outputDeviceForGeometry (geom);
3711
CompScreen::getCurrentOutputExtents ()
3713
return priv->outputDevs[priv->currentOutputDev];
3717
PrivateScreen::setNumberOfDesktops (unsigned int nDesktop)
3719
if (nDesktop < 1 || nDesktop >= 0xffffffff)
3722
if (nDesktop == priv->nDesktop)
3725
if (priv->currentDesktop >= nDesktop)
3726
priv->currentDesktop = nDesktop - 1;
3728
foreach (CompWindow *w, priv->windows)
3730
if (w->desktop () == 0xffffffff)
3733
if (w->desktop () >= nDesktop)
3734
w->setDesktop (nDesktop - 1);
3737
priv->nDesktop = nDesktop;
3739
priv->setDesktopHints ();
3743
PrivateScreen::setCurrentDesktop (unsigned int desktop)
3747
if (desktop >= priv->nDesktop)
3750
if (desktop == priv->currentDesktop)
3753
priv->currentDesktop = desktop;
3755
foreach (CompWindow *w, priv->windows)
3757
if (w->desktop () == 0xffffffff)
3760
if (w->desktop () == desktop)
3768
XChangeProperty (priv->dpy, priv->root, Atoms::currentDesktop,
3769
XA_CARDINAL, 32, PropModeReplace,
3770
(unsigned char *) &data, 1);
3774
CompScreen::getWorkareaForOutput (unsigned int outputNum) const
3776
return priv->outputDevs[outputNum].workArea ();
3780
CompScreen::outputChangeNotify ()
3781
WRAPABLE_HND_FUNC (16, outputChangeNotify)
3785
/* Returns default viewport for some window geometry. If the window spans
3786
more than one viewport the most appropriate viewport is returned. How the
3787
most appropriate viewport is computed can be made optional if necessary. It
3788
is currently computed as the viewport where the center of the window is
3791
CompScreen::viewportForGeometry (const CompWindow::Geometry& gm,
3792
CompPoint& viewport)
3797
rect.setWidth (rect.width () + (gm.border () * 2));
3798
rect.setHeight (rect.height () + (gm.border () * 2));
3800
offset = rect.centerX () < 0 ? -1 : 0;
3801
viewport.setX (priv->vp.x () + ((rect.centerX () / width ()) + offset) %
3802
priv->vpSize.width ());
3804
offset = rect.centerY () < 0 ? -1 : 0;
3805
viewport.setY (priv->vp.y () + ((rect.centerY () / height ()) + offset ) %
3806
priv->vpSize.height ());
3810
CompScreen::outputDeviceForGeometry (const CompWindow::Geometry& gm)
3812
int overlapAreas[priv->outputDevs.size ()];
3813
int highest, seen, highestScore;
3818
if (priv->outputDevs.size () == 1)
3821
strategy = priv->optionGetOverlappingOutputs ();
3823
if (strategy == CoreOptions::OverlappingOutputsSmartMode)
3825
int centerX, centerY;
3827
/* for smart mode, calculate the overlap of the whole rectangle
3828
with the output device rectangle */
3829
geomRect.setWidth (gm.width () + 2 * gm.border ());
3830
geomRect.setHeight (gm.height () + 2 * gm.border ());
3832
x = gm.x () % width ();
3833
centerX = (x + (geomRect.width () / 2));
3836
else if (centerX > width ())
3840
y = gm.y () % height ();
3841
centerY = (y + (geomRect.height () / 2));
3844
else if (centerY > height ())
3850
/* for biggest/smallest modes, only use the window center to determine
3851
the correct output device */
3852
x = (gm.x () + (gm.width () / 2) + gm.border ()) % width ();
3855
y = (gm.y () + (gm.height () / 2) + gm.border ()) % height ();
3859
geomRect.setGeometry (x, y, 1, 1);
3862
/* get amount of overlap on all output devices */
3863
for (i = 0; i < priv->outputDevs.size (); i++)
3865
CompRect overlap = priv->outputDevs[i] & geomRect;
3866
overlapAreas[i] = overlap.area ();
3869
/* find output with largest overlap */
3870
for (i = 0, highest = 0, highestScore = 0;
3871
i < priv->outputDevs.size (); i++)
3873
if (overlapAreas[i] > highestScore)
3876
highestScore = overlapAreas[i];
3880
/* look if the highest score is unique */
3881
for (i = 0, seen = 0; i < priv->outputDevs.size (); i++)
3882
if (overlapAreas[i] == highestScore)
3887
/* it's not unique, select one output of the matching ones and use the
3888
user preferred strategy for that */
3889
unsigned int currentSize, bestOutputSize;
3893
(strategy != CoreOptions::OverlappingOutputsPreferSmallerOutput);
3898
bestOutputSize = UINT_MAX;
3900
for (i = 0, highest = 0; i < priv->outputDevs.size (); i++)
3901
if (overlapAreas[i] == highestScore)
3905
currentSize = priv->outputDevs[i].area ();
3908
bestFit = (currentSize > bestOutputSize);
3910
bestFit = (currentSize < bestOutputSize);
3915
bestOutputSize = currentSize;
3924
CompScreen::defaultIcon () const
3926
return priv->defaultIcon;
3930
CompScreen::updateDefaultIcon ()
3932
CompString file = priv->optionGetDefaultIcon ();
3933
CompString pname = "core/";
3937
if (priv->defaultIcon)
3939
delete priv->defaultIcon;
3940
priv->defaultIcon = NULL;
3943
if (!readImageFromFile (file, pname, size, data))
3946
priv->defaultIcon = new CompIcon (screen, size.width (), size.height ());
3948
memcpy (priv->defaultIcon->data (), data,
3949
size.width () * size.height () * sizeof (CARD32));
3957
PrivateScreen::setCurrentActiveWindowHistory (int x, int y)
3961
for (i = 0; i < ACTIVE_WINDOW_HISTORY_NUM; i++)
3963
if (priv->history[i].x == x && priv->history[i].y == y)
3965
priv->currentHistory = i;
3970
for (i = 1; i < ACTIVE_WINDOW_HISTORY_NUM; i++)
3971
if (priv->history[i].activeNum < priv->history[min].activeNum)
3974
priv->currentHistory = min;
3976
priv->history[min].activeNum = priv->activeNum;
3977
priv->history[min].x = x;
3978
priv->history[min].y = y;
3980
memset (priv->history[min].id, 0, sizeof (priv->history[min].id));
3984
PrivateScreen::addToCurrentActiveWindowHistory (Window id)
3986
CompActiveWindowHistory *history = &priv->history[priv->currentHistory];
3987
Window tmp, next = id;
3990
/* walk and move history */
3991
for (i = 0; i < ACTIVE_WINDOW_HISTORY_SIZE; i++)
3993
tmp = history->id[i];
3994
history->id[i] = next;
3997
/* we're done when we find an old instance or an empty slot */
3998
if (tmp == id || tmp == None)
4002
history->activeNum = priv->activeNum;
4006
ScreenInterface::enterShowDesktopMode ()
4007
WRAPABLE_DEF (enterShowDesktopMode)
4010
ScreenInterface::leaveShowDesktopMode (CompWindow *window)
4011
WRAPABLE_DEF (leaveShowDesktopMode, window)
4014
ScreenInterface::outputChangeNotify ()
4015
WRAPABLE_DEF (outputChangeNotify)
4018
ScreenInterface::addSupportedAtoms (std::vector<Atom>& atoms)
4019
WRAPABLE_DEF (addSupportedAtoms, atoms)
4029
CompScreen::xkbEvent ()
4031
return priv->xkbEvent;
4035
CompScreen::warpPointer (int dx,
4043
if (pointerX >= width ())
4044
pointerX = width () - 1;
4045
else if (pointerX < 0)
4048
if (pointerY >= height ())
4049
pointerY = height () - 1;
4050
else if (pointerY < 0)
4053
XWarpPointer (priv->dpy,
4056
pointerX, pointerY);
4058
XSync (priv->dpy, false);
4060
/* XWarpPointer will generate Leave, Enter and PointerMotion
4061
* events as if the user had instantaneously moved the cursor
4062
* from one position to another. Because most of this is
4063
* useless to process, we just throw out the events and update
4064
* the pointer position. However, we do need to process some
4065
* crossing events since they tell us which edge windows are
4066
* hovered. Note that we don't actually trigger the bindings
4067
* in the case where we warped from one edge window to
4070
* FIXME: Probably don't need to process *all* the crossing
4071
* events here ... maybe there is a way to check only the last
4072
* event in the output buffer without roundtripping a lot */
4073
while (XCheckMaskEvent (priv->dpy,
4079
if (event.type == EnterNotify)
4081
if (event.xcrossing.mode != NotifyGrab ||
4082
event.xcrossing.mode != NotifyUngrab ||
4083
event.xcrossing.mode != NotifyInferior)
4085
priv->edgeWindow = 0;
4087
for (unsigned int i = 0; i < SCREEN_EDGE_NUM; i++)
4089
if (event.xcrossing.window == priv->screenEdge[i].id)
4091
priv->edgeWindow = 1 << i;
4101
lastPointerX = pointerX;
4102
lastPointerY = pointerY;
4107
CompScreen::windows ()
4109
return priv->windows;
4113
CompScreen::getCurrentTime ()
4117
XChangeProperty (priv->dpy, priv->grabWindow,
4118
XA_PRIMARY, XA_STRING, 8,
4119
PropModeAppend, NULL, 0);
4120
XWindowEvent (priv->dpy, priv->grabWindow,
4124
return event.xproperty.time;
4128
CompScreen::selectionWindow ()
4130
return priv->wmSnSelectionWindow;
4134
CompScreen::screenNum ()
4136
return priv->screenNum;
4146
CompScreen::vpSize ()
4148
return priv->vpSize;
4152
CompScreen::desktopWindowCount ()
4154
return priv->desktopWindowCount;
4158
CompScreen::activeNum () const
4160
return priv->activeNum;
4163
CompOutput::vector &
4164
CompScreen::outputDevs ()
4166
return priv->outputDevs;
4170
CompScreen::currentOutputDev () const
4172
return priv->outputDevs [priv->currentOutputDev];
4176
CompScreen::workArea () const
4178
return priv->workArea;
4182
CompScreen::currentDesktop ()
4184
return priv->currentDesktop;
4188
CompScreen::nDesktop ()
4190
return priv->nDesktop;
4193
CompActiveWindowHistory *
4194
CompScreen::currentHistory ()
4196
return &priv->history[priv->currentHistory];
4200
CompScreen::shouldSerializePlugins ()
4202
return priv->optionGetDoSerialize ();
4206
PrivateScreen::removeDestroyed ()
4208
while (pendingDestroys)
4210
foreach (CompWindow *w, windows)
4212
if (w->destroyed ())
4224
CompScreen::region () const
4226
return priv->region;
4230
CompScreen::hasOverlappingOutputs ()
4232
return priv->hasOverlappingOutputs;
4236
CompScreen::fullscreenOutput ()
4238
return priv->fullscreenOutput;
4243
CompScreen::attrib ()
4245
return priv->attrib;
4248
std::vector<XineramaScreenInfo> &
4249
CompScreen::screenInfo ()
4251
return priv->screenInfo;
4255
PrivateScreen::createFailed ()
4257
return !screenInitalized;
4260
CompScreen::CompScreen ():
4261
PluginClassStorage (screenPluginClassIndices),
4265
CompOption::Value::Vector vList;
4266
CompPlugin *corePlugin;
4268
priv = new PrivateScreen (this);
4271
screenInitalized = true;
4273
corePlugin = CompPlugin::load ("core");
4276
compLogMessage ("core", CompLogLevelFatal,
4277
"Couldn't load core plugin");
4278
screenInitalized = false;
4281
if (!CompPlugin::push (corePlugin))
4283
compLogMessage ("core", CompLogLevelFatal,
4284
"Couldn't activate core plugin");
4285
screenInitalized = false;
4288
p.uval = CORE_ABIVERSION;
4289
storeValue ("core_ABI", p);
4291
vList.push_back ("core");
4293
priv->plugin.set (CompOption::TypeString, vList);
4297
CompScreen::init (const char *name)
4304
Window newWmSnOwner = None;
4306
Time wmSnTimestamp = 0;
4308
XSetWindowAttributes attr;
4309
Window currentWmSnOwner;
4311
static char data = 0;
4315
XVisualInfo *visinfo;
4316
Window rootReturn, parentReturn;
4318
unsigned int nchildren;
4320
XSetWindowAttributes attrib;
4322
dpy = priv->dpy = XOpenDisplay (name);
4325
compLogMessage ("core", CompLogLevelFatal,
4326
"Couldn't open display %s", XDisplayName (name));
4330
// priv->connection = XGetXCBConnection (priv->dpy);
4332
snprintf (priv->displayString, 255, "DISPLAY=%s",
4333
DisplayString (dpy));
4336
XSynchronize (priv->dpy, true);
4339
Atoms::init (priv->dpy);
4341
XSetErrorHandler (errorHandler);
4343
priv->snDisplay = sn_display_new (dpy, NULL, NULL);
4344
if (!priv->snDisplay)
4349
if (!XSyncQueryExtension (dpy, &priv->syncEvent, &priv->syncError))
4351
compLogMessage ("core", CompLogLevelFatal,
4352
"No sync extension");
4356
priv->randrExtension = XRRQueryExtension (dpy, &priv->randrEvent,
4359
priv->shapeExtension = XShapeQueryExtension (dpy, &priv->shapeEvent,
4362
priv->xkbExtension = XkbQueryExtension (dpy, &xkbOpcode,
4363
&priv->xkbEvent, &priv->xkbError,
4365
if (priv->xkbExtension)
4367
XkbSelectEvents (dpy, XkbUseCoreKbd,
4368
XkbBellNotifyMask | XkbStateNotifyMask,
4373
compLogMessage ("core", CompLogLevelFatal,
4374
"No XKB extension");
4376
priv->xkbEvent = priv->xkbError = -1;
4379
priv->xineramaExtension = XineramaQueryExtension (dpy,
4380
&priv->xineramaEvent,
4381
&priv->xineramaError);
4383
priv->updateScreenInfo ();
4385
priv->escapeKeyCode = XKeysymToKeycode (dpy, XStringToKeysym ("Escape"));
4386
priv->returnKeyCode = XKeysymToKeycode (dpy, XStringToKeysym ("Return"));
4388
sprintf (buf, "WM_S%d", DefaultScreen (dpy));
4389
wmSnAtom = XInternAtom (dpy, buf, 0);
4391
currentWmSnOwner = XGetSelectionOwner (dpy, wmSnAtom);
4393
if (currentWmSnOwner != None)
4395
if (!replaceCurrentWm)
4397
compLogMessage ("core", CompLogLevelError,
4398
"Screen %d on display \"%s\" already "
4399
"has a window manager; try using the "
4400
"--replace option to replace the current "
4402
DefaultScreen (dpy), DisplayString (dpy));
4407
XSelectInput (dpy, currentWmSnOwner, StructureNotifyMask);
4410
root = XRootWindow (dpy, DefaultScreen (dpy));
4412
attr.override_redirect = true;
4413
attr.event_mask = PropertyChangeMask;
4416
XCreateWindow (dpy, root, -100, -100, 1, 1, 0,
4417
CopyFromParent, CopyFromParent,
4419
CWOverrideRedirect | CWEventMask,
4422
XChangeProperty (dpy, newWmSnOwner, Atoms::wmName, Atoms::utf8String, 8,
4423
PropModeReplace, (unsigned char *) PACKAGE,
4426
XWindowEvent (dpy, newWmSnOwner, PropertyChangeMask, &event);
4428
wmSnTimestamp = event.xproperty.time;
4430
XSetSelectionOwner (dpy, wmSnAtom, newWmSnOwner, wmSnTimestamp);
4432
if (XGetSelectionOwner (dpy, wmSnAtom) != newWmSnOwner)
4434
compLogMessage ("core", CompLogLevelError,
4435
"Could not acquire window manager "
4436
"selection on screen %d display \"%s\"",
4437
DefaultScreen (dpy), DisplayString (dpy));
4439
XDestroyWindow (dpy, newWmSnOwner);
4444
/* Send client message indicating that we are now the window manager */
4445
event.xclient.type = ClientMessage;
4446
event.xclient.window = root;
4447
event.xclient.message_type = Atoms::manager;
4448
event.xclient.format = 32;
4449
event.xclient.data.l[0] = wmSnTimestamp;
4450
event.xclient.data.l[1] = wmSnAtom;
4451
event.xclient.data.l[2] = 0;
4452
event.xclient.data.l[3] = 0;
4453
event.xclient.data.l[4] = 0;
4455
XSendEvent (dpy, root, FALSE, StructureNotifyMask, &event);
4457
/* Wait for old window manager to go away */
4458
if (currentWmSnOwner != None)
4461
XWindowEvent (dpy, currentWmSnOwner, StructureNotifyMask, &event);
4462
} while (event.type != DestroyNotify);
4465
modHandler->updateModifierMappings ();
4467
CompScreen::checkForError (dpy);
4471
XSelectInput (dpy, root,
4472
SubstructureRedirectMask |
4473
SubstructureNotifyMask |
4474
StructureNotifyMask |
4475
PropertyChangeMask |
4485
/* We need to register for EnterWindowMask |
4486
* ButtonPressMask | FocusChangeMask on other
4487
* root windows as well because focus happens
4488
* on a display level and we need to check
4489
* if the screen we are running on lost focus */
4491
for (int i = 0; i <= ScreenCount (dpy) - 1; i++)
4493
Window rt = XRootWindow (dpy, i);
4498
XSelectInput (dpy, rt,
4500
SubstructureNotifyMask);
4503
if (CompScreen::checkForError (dpy))
4505
compLogMessage ("core", CompLogLevelError,
4506
"Another window manager is "
4507
"already running on screen: %d", DefaultScreen (dpy));
4509
XUngrabServer (dpy);
4513
/* We only care about windows we're not going to
4514
* get a CreateNotify for later, so query the tree
4515
* here, init plugin screens, and then init windows */
4517
XQueryTree (dpy, root,
4518
&rootReturn, &parentReturn,
4519
&children, &nchildren);
4521
for (i = 0; i < SCREEN_EDGE_NUM; i++)
4523
priv->screenEdge[i].id = None;
4524
priv->screenEdge[i].count = 0;
4527
priv->screenNum = DefaultScreen (dpy);
4528
priv->colormap = DefaultColormap (dpy, priv->screenNum);
4531
priv->snContext = sn_monitor_context_new (priv->snDisplay, priv->screenNum,
4532
compScreenSnEvent, this, NULL);
4534
priv->wmSnSelectionWindow = newWmSnOwner;
4535
priv->wmSnAtom = wmSnAtom;
4536
priv->wmSnTimestamp = wmSnTimestamp;
4538
if (!XGetWindowAttributes (dpy, priv->root, &priv->attrib))
4541
priv->workArea.setWidth (priv->attrib.width);
4542
priv->workArea.setHeight (priv->attrib.height);
4544
priv->grabWindow = None;
4546
templ.visualid = XVisualIDFromVisual (priv->attrib.visual);
4548
visinfo = XGetVisualInfo (dpy, VisualIDMask, &templ, &nvisinfo);
4551
compLogMessage ("core", CompLogLevelFatal,
4552
"Couldn't get visual info for default visual");
4556
black.red = black.green = black.blue = 0;
4558
if (!XAllocColor (dpy, priv->colormap, &black))
4560
compLogMessage ("core", CompLogLevelFatal,
4561
"Couldn't allocate color");
4566
bitmap = XCreateBitmapFromData (dpy, priv->root, &data, 1, 1);
4569
compLogMessage ("core", CompLogLevelFatal,
4570
"Couldn't create bitmap");
4575
priv->invisibleCursor = XCreatePixmapCursor (dpy, bitmap, bitmap,
4576
&black, &black, 0, 0);
4577
if (!priv->invisibleCursor)
4579
compLogMessage ("core", CompLogLevelFatal,
4580
"Couldn't create invisible cursor");
4585
XFreePixmap (dpy, bitmap);
4586
XFreeColors (dpy, priv->colormap, &black.pixel, 1, 0);
4590
priv->reshape (priv->attrib.width, priv->attrib.height);
4592
priv->detectOutputDevices ();
4593
priv->updateOutputDevices ();
4595
priv->getDesktopHints ();
4597
attrib.override_redirect = 1;
4598
attrib.event_mask = PropertyChangeMask;
4600
priv->grabWindow = XCreateWindow (dpy, priv->root, -100, -100, 1, 1, 0,
4601
CopyFromParent, InputOnly, CopyFromParent,
4602
CWOverrideRedirect | CWEventMask,
4604
XMapWindow (dpy, priv->grabWindow);
4606
for (i = 0; i < SCREEN_EDGE_NUM; i++)
4608
long xdndVersion = 3;
4610
priv->screenEdge[i].id = XCreateWindow (dpy, priv->root,
4611
-100, -100, 1, 1, 0,
4612
CopyFromParent, InputOnly,
4617
XChangeProperty (dpy, priv->screenEdge[i].id, Atoms::xdndAware,
4618
XA_ATOM, 32, PropModeReplace,
4619
(unsigned char *) &xdndVersion, 1);
4621
XSelectInput (dpy, priv->screenEdge[i].id,
4629
priv->updateScreenEdges ();
4631
priv->setDesktopHints ();
4632
priv->setSupportingWmCheck ();
4633
updateSupportedWmHints ();
4635
priv->normalCursor = XCreateFontCursor (dpy, XC_left_ptr);
4636
priv->busyCursor = XCreateFontCursor (dpy, XC_watch);
4638
XDefineCursor (dpy, priv->root, priv->normalCursor);
4640
XUngrabServer (dpy);
4643
priv->setAudibleBell (priv->optionGetAudibleBell ());
4645
priv->pingTimer.setTimes (priv->optionGetPingDelay (),
4646
priv->optionGetPingDelay () + 500);
4648
priv->pingTimer.start ();
4650
priv->stackAttackTimer.setTimes (priv->optionGetSyncStacksTimeout (), priv->optionGetSyncStacksTimeout () * 1.4);
4651
priv->stackAttackTimer.start ();
4653
priv->addScreenActions ();
4655
/* Need to set a default here so that the value isn't uninitialized
4656
* when loading plugins FIXME: Should find a way to initialize options
4657
* first and then set this value, or better yet, tie this value directly
4659
priv->vpSize.setWidth (priv->optionGetHsize ());
4660
priv->vpSize.setHeight (priv->optionGetVsize ());
4662
priv->initialized = true;
4664
/* TODO: Bailout properly when screenInitPlugins fails
4665
* TODO: It would be nicer if this line could mean
4666
* "init all the screens", but unfortunately it only inits
4667
* plugins loaded on the command line screen's and then
4668
* we need to call updatePlugins () to init the remaining
4669
* screens from option changes */
4670
assert (CompPlugin::screenInitPlugins (this));
4672
/* The active plugins list might have been changed - load any
4675
priv->vpSize.setWidth (priv->optionGetHsize ());
4676
priv->vpSize.setHeight (priv->optionGetVsize ());
4678
if (priv->dirtyPluginList)
4679
priv->updatePlugins ();
4681
/* Start initializing windows here */
4683
for (unsigned int i = 0; i < nchildren; i++)
4685
XWindowAttributes attrib;
4687
/* Failure means the window has been destroyed, but
4688
* still add it to the window list anyways since we
4689
* will soon handle the DestroyNotify event for it
4690
* and in between CreateNotify time and DestroyNotify
4691
* time there might be ConfigureRequests asking us
4692
* to stack windows relative to it
4695
if (!XGetWindowAttributes (screen->dpy (), children[i], &attrib))
4696
priv->setDefaultWindowAttributes (&attrib);
4698
fprintf (stderr, "Window created on XQueryTree, map state isViewable? %i\n", attrib.map_state == IsViewable);
4700
CoreWindow *cw = new CoreWindow (children[i]);
4701
cw->manage (i ? children[i - 1] : 0, attrib);
4703
priv->createdWindows.remove (cw);
4709
/* enforce restack on all windows */
4711
for (CompWindowList::reverse_iterator rit = priv->windows.rbegin ();
4712
rit != priv->windows.rend (); rit++)
4713
children[i++] = (*rit)->id ();
4715
XRestackWindows (dpy, children, i);
4719
foreach (CompWindow *w, priv->windows)
4721
if (w->isViewable ())
4722
w->priv->activeNum = priv->activeNum++;
4725
XGetInputFocus (dpy, &focus, &revertTo);
4727
/* move input focus to root window so that we get a FocusIn event when
4728
moving it to the default window */
4729
XSetInputFocus (dpy, priv->root, RevertToPointerRoot, CurrentTime);
4731
if (focus == None || focus == PointerRoot)
4733
focusDefaultWindow ();
4739
w = findWindow (focus);
4741
w->moveInputFocusTo ();
4743
focusDefaultWindow ();
4749
CompScreen::~CompScreen ()
4753
priv->removeAllSequences ();
4755
while (!priv->windows.empty ())
4756
delete priv->windows.front ();
4758
while ((p = CompPlugin::pop ()))
4759
CompPlugin::unload (p);
4761
XUngrabKey (priv->dpy, AnyKey, AnyModifier, priv->root);
4763
priv->initialized = false;
4765
for (int i = 0; i < SCREEN_EDGE_NUM; i++)
4766
XDestroyWindow (priv->dpy, priv->screenEdge[i].id);
4768
XDestroyWindow (priv->dpy, priv->grabWindow);
4770
if (priv->defaultIcon)
4771
delete priv->defaultIcon;
4773
XFreeCursor (priv->dpy, priv->invisibleCursor);
4775
if (priv->desktopHintData)
4776
free (priv->desktopHintData);
4778
if (priv->snContext)
4779
sn_monitor_context_unref (priv->snContext);
4781
if (priv->snDisplay)
4782
sn_display_unref (priv->snDisplay);
4784
XSync (priv->dpy, False);
4785
XCloseDisplay (priv->dpy);
4792
PrivateScreen::PrivateScreen (CompScreen *screen) :
4795
lastFileWatchHandle (1),
4797
lastWatchFdHandle (1),
4803
autoRaiseWindow (0),
4806
dirtyPluginList (true),
4815
desktopWindowCount (0),
4819
currentOutputDev (0),
4820
hasOverlappingOutputs (false),
4823
startupSequences (0),
4824
startupSequenceTimer (),
4831
pendingDestroys (0),
4832
showingDesktopMask (0),
4833
desktopHintData (0),
4834
desktopHintSize (0),
4839
gettimeofday (&lastTimeout, 0);
4841
pingTimer.setCallback (
4842
boost::bind (&PrivateScreen::handlePingTimeout, this));
4844
stackAttackTimer.setCallback (boost::bind (&PrivateScreen::syncStacks, this));
4846
startupSequenceTimer.setCallback (
4847
boost::bind (&PrivateScreen::handleStartupSequenceTimeout, this));
4848
startupSequenceTimer.setTimes (1000, 1500);
4850
optionSetCloseWindowKeyInitiate (CompScreen::closeWin);
4851
optionSetCloseWindowButtonInitiate (CompScreen::closeWin);
4852
optionSetRaiseWindowKeyInitiate (CompScreen::raiseWin);
4853
optionSetRaiseWindowButtonInitiate (CompScreen::raiseWin);
4854
optionSetLowerWindowKeyInitiate (CompScreen::lowerWin);
4855
optionSetLowerWindowButtonInitiate (CompScreen::lowerWin);
4857
optionSetUnmaximizeWindowKeyInitiate (CompScreen::unmaximizeWin);
4859
optionSetMinimizeWindowKeyInitiate (CompScreen::minimizeWin);
4860
optionSetMinimizeWindowButtonInitiate (CompScreen::minimizeWin);
4861
optionSetMaximizeWindowKeyInitiate (CompScreen::maximizeWin);
4862
optionSetMaximizeWindowHorizontallyKeyInitiate (
4863
CompScreen::maximizeWinHorizontally);
4864
optionSetMaximizeWindowVerticallyKeyInitiate (
4865
CompScreen::maximizeWinVertically);
4867
optionSetWindowMenuKeyInitiate (CompScreen::windowMenu);
4868
optionSetWindowMenuButtonInitiate (CompScreen::windowMenu);
4870
optionSetShowDesktopKeyInitiate (CompScreen::showDesktop);
4871
optionSetShowDesktopEdgeInitiate (CompScreen::showDesktop);
4873
optionSetToggleWindowMaximizedKeyInitiate (CompScreen::toggleWinMaximized);
4874
optionSetToggleWindowMaximizedButtonInitiate (CompScreen::toggleWinMaximized);
4876
optionSetToggleWindowMaximizedHorizontallyKeyInitiate (
4877
CompScreen::toggleWinMaximizedHorizontally);
4878
optionSetToggleWindowMaximizedVerticallyKeyInitiate (
4879
CompScreen::toggleWinMaximizedVertically);
4881
optionSetToggleWindowShadedKeyInitiate (CompScreen::shadeWin);
4884
PrivateScreen::~PrivateScreen ()