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
CompScreen::getOptions ()
621
return priv->getOptions ();
625
CompScreen::setOption (const CompString &name,
626
CompOption::Value &value)
628
return priv->setOption (name, value);
632
PrivateScreen::setOption (const CompString &name,
633
CompOption::Value &value)
637
bool rv = CoreOptions::setOption (name, value);
642
if (!CompOption::findOption (getOptions (), name, &index))
646
case CoreOptions::ActivePlugins:
647
dirtyPluginList = true;
649
case CoreOptions::PingDelay:
650
pingTimer.setTimes (optionGetPingDelay (),
651
optionGetPingDelay () + 500);
653
case CoreOptions::AudibleBell:
654
setAudibleBell (optionGetAudibleBell ());
656
case CoreOptions::DetectOutputs:
657
if (optionGetDetectOutputs ())
658
detectOutputDevices ();
660
case CoreOptions::Hsize:
661
case CoreOptions::Vsize:
663
if (optionGetHsize () * screen->width () > MAXSHORT)
665
if (optionGetVsize () * screen->height () > MAXSHORT)
668
setVirtualScreenSize (optionGetHsize (), optionGetVsize ());
670
case CoreOptions::NumberOfDesktops:
671
setNumberOfDesktops (optionGetNumberOfDesktops ());
673
case CoreOptions::DefaultIcon:
674
return screen->updateDefaultIcon ();
676
case CoreOptions::Outputs:
677
if (!noDetection && optionGetDetectOutputs ())
679
updateOutputDevices ();
689
PrivateScreen::processEvents ()
691
XEvent event, peekEvent;
693
/* remove destroyed windows */
699
while (XPending (dpy))
701
XNextEvent (dpy, &event);
703
switch (event.type) {
706
pointerX = event.xbutton.x_root;
707
pointerY = event.xbutton.y_root;
708
pointerMods = event.xbutton.state;
712
pointerX = event.xkey.x_root;
713
pointerY = event.xkey.y_root;
714
pointerMods = event.xbutton.state;
717
while (XPending (dpy))
719
XPeekEvent (dpy, &peekEvent);
721
if (peekEvent.type != MotionNotify)
724
XNextEvent (dpy, &event);
727
pointerX = event.xmotion.x_root;
728
pointerY = event.xmotion.y_root;
729
pointerMods = event.xbutton.state;
733
pointerX = event.xcrossing.x_root;
734
pointerY = event.xcrossing.y_root;
735
pointerMods = event.xbutton.state;
738
if (event.xclient.message_type == Atoms::xdndPosition)
740
pointerX = event.xclient.data.l[2] >> 16;
741
pointerY = event.xclient.data.l[2] & 0xffff;
742
/* FIXME: Xdnd provides us no way of getting the pointer mods
743
* without doing XQueryPointer, which is a round-trip */
746
else if (event.xclient.message_type == Atoms::wmMoveResize)
750
/* _NET_WM_MOVERESIZE is most often sent by clients who provide
751
* a special "grab space" on a window for the user to initiate
752
* adjustment by the window manager. Since we don't have a
753
* passive grab on Button1 for active and raised windows, we
754
* need to update the pointer buffer here */
756
XQueryPointer (screen->dpy (), screen->root (),
757
&root, &child, &pointerX, &pointerY,
758
&i, &i, &pointerMods);
765
sn_display_process_event (snDisplay, &event);
767
inHandleEvent = true;
768
screen->handleEvent (&event);
769
inHandleEvent = false;
771
lastPointerX = pointerX;
772
lastPointerY = pointerY;
773
lastPointerMods = pointerMods;
778
PrivateScreen::updatePlugins ()
781
unsigned int nPop, i, j, pListCount = 1;
782
CompOption::Value::Vector pList;
783
CompPlugin::List pop;
787
dirtyPluginList = false;
789
CompOption::Value::Vector &list = optionGetActivePlugins ();
791
/* Determine the number of plugins, which is core +
792
* initial plugins + plugins in option list in addition
793
* to initial plugins */
794
foreach (CompString &pn, initialPlugins)
800
foreach (CompOption::Value &lp, list)
803
if (lp.s () == "core")
806
foreach (CompString &p, initialPlugins)
815
/* plugin not in initial list */
820
/* dupPluginCount is now the number of plugisn contained in both the
821
* initial and new plugins list */
822
pList.resize (pListCount);
826
screen->setOptionForPlugin ("core", "active_plugins", plugin);
830
/* Must have core as first plugin */
831
pList.at (0) = "core";
834
/* Add initial plugins */
835
foreach (CompString &p, initialPlugins)
839
pList.at (j).set (p);
843
/* Add plugins not in the initial list */
844
foreach (CompOption::Value &opt, list)
846
std::list <CompString>::iterator it = initialPlugins.begin ();
848
if (opt.s () == "core")
851
for (; it != initialPlugins.end (); it++)
853
if ((*it) == opt.s ())
861
pList.at (j++).set (opt.s ());
864
assert (j == pList.size ());
866
/* j is initialized to 1 to make sure we never pop the core plugin */
867
for (i = j = 1; j < plugin.list ().size () && i < pList.size (); i++, j++)
869
if (plugin.list ().at (j).s () != pList.at (i).s ())
873
nPop = plugin.list ().size () - j;
877
for (j = 0; j < nPop; j++)
879
pop.push_back (CompPlugin::pop ());
880
plugin.list ().pop_back ();
884
for (; i < pList.size (); i++)
888
foreach (CompPlugin *pp, pop)
890
if (pList[i]. s () == pp->vTable->name ())
892
if (CompPlugin::push (pp))
895
pop.erase (std::find (pop.begin (), pop.end (), pp));
900
pop.erase (std::find (pop.begin (), pop.end (), pp));
901
CompPlugin::unload (pp);
909
if (p == 0 && !failedPush)
911
p = CompPlugin::load (pList[i].s ().c_str ());
914
if (!CompPlugin::push (p))
916
CompPlugin::unload (p);
923
plugin.list ().push_back (p->vTable->name ());
926
foreach (CompPlugin *pp, pop)
927
CompPlugin::unload (pp);
929
if (!priv->dirtyPluginList)
930
screen->setOptionForPlugin ("core", "active_plugins", plugin);
933
/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
935
convertProperty (Display *dpy,
944
Atom conversionTargets[N_TARGETS];
945
long icccmVersion[] = { 2, 0 };
947
conversionTargets[0] = Atoms::targets;
948
conversionTargets[1] = Atoms::multiple;
949
conversionTargets[2] = Atoms::timestamp;
950
conversionTargets[3] = Atoms::version;
952
if (target == Atoms::targets)
953
XChangeProperty (dpy, w, property,
954
XA_ATOM, 32, PropModeReplace,
955
(unsigned char *) conversionTargets, N_TARGETS);
956
else if (target == Atoms::timestamp)
957
XChangeProperty (dpy, w, property,
958
XA_INTEGER, 32, PropModeReplace,
959
(unsigned char *) &time, 1);
960
else if (target == Atoms::version)
961
XChangeProperty (dpy, w, property,
962
XA_INTEGER, 32, PropModeReplace,
963
(unsigned char *) icccmVersion, 2);
967
/* Be sure the PropertyNotify has arrived so we
968
* can send SelectionNotify
975
/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
977
PrivateScreen::handleSelectionRequest (XEvent *event)
979
XSelectionEvent reply;
981
if (wmSnSelectionWindow != event->xselectionrequest.owner ||
982
wmSnAtom != event->xselectionrequest.selection)
985
reply.type = SelectionNotify;
987
reply.requestor = event->xselectionrequest.requestor;
988
reply.selection = event->xselectionrequest.selection;
989
reply.target = event->xselectionrequest.target;
990
reply.property = None;
991
reply.time = event->xselectionrequest.time;
993
if (event->xselectionrequest.target == Atoms::multiple)
995
if (event->xselectionrequest.property != None)
999
unsigned long num, rest;
1000
unsigned char *data;
1002
if (XGetWindowProperty (dpy,
1003
event->xselectionrequest.requestor,
1004
event->xselectionrequest.property,
1007
&type, &format, &num, &rest,
1011
/* FIXME: to be 100% correct, should deal with rest > 0,
1012
* but since we have 4 possible targets, we will hardly ever
1013
* meet multiple requests with a length > 8
1015
adata = (Atom *) data;
1017
while (i < (int) num)
1019
if (!convertProperty (dpy, wmSnTimestamp,
1020
event->xselectionrequest.requestor,
1021
adata[i], adata[i + 1]))
1022
adata[i + 1] = None;
1027
XChangeProperty (dpy,
1028
event->xselectionrequest.requestor,
1029
event->xselectionrequest.property,
1031
32, PropModeReplace, data, num);
1039
if (event->xselectionrequest.property == None)
1040
event->xselectionrequest.property = event->xselectionrequest.target;
1042
if (convertProperty (dpy, wmSnTimestamp,
1043
event->xselectionrequest.requestor,
1044
event->xselectionrequest.target,
1045
event->xselectionrequest.property))
1046
reply.property = event->xselectionrequest.property;
1049
XSendEvent (dpy, event->xselectionrequest.requestor,
1050
false, 0L, (XEvent *) &reply);
1054
PrivateScreen::handleSelectionClear (XEvent *event)
1056
/* We need to unmanage the screen on which we lost the selection */
1057
if (wmSnSelectionWindow != event->xselectionclear.window ||
1058
wmSnAtom != event->xselectionclear.selection)
1064
#define HOME_IMAGEDIR ".compiz-1/images"
1067
CompScreen::readImageFromFile (CompString &name,
1075
status = fileToImage (name, size, stride, data);
1078
char *home = getenv ("HOME");
1084
path += HOME_IMAGEDIR;
1090
status = fileToImage (path, size, stride, data);
1101
status = fileToImage (path, size, stride, data);
1108
CompScreen::writeImageToFile (CompString &path,
1113
CompString formatString (format);
1114
return imageToFile (path, formatString, size, size.width () * 4, data);
1118
PrivateScreen::getActiveWindow (Window root)
1122
unsigned long n, left;
1123
unsigned char *data;
1126
result = XGetWindowProperty (priv->dpy, root,
1127
Atoms::winActive, 0L, 1L, false,
1128
XA_WINDOW, &actual, &format,
1131
if (result == Success && data)
1134
memcpy (&w, data, sizeof (Window));
1142
CompScreen::fileToImage (CompString &name,
1147
WRAPABLE_HND_FUNC_RETURN (8, bool, fileToImage, name, size, stride, data);
1152
CompScreen::imageToFile (CompString &path,
1158
WRAPABLE_HND_FUNC_RETURN (9, bool, imageToFile, path, format, size,
1164
logLevelToString (CompLogLevel level)
1167
case CompLogLevelFatal:
1169
case CompLogLevelError:
1171
case CompLogLevelWarn:
1173
case CompLogLevelInfo:
1175
case CompLogLevelDebug:
1185
logMessage (const char *componentName,
1187
const char *message)
1189
if (!debugOutput && level >= CompLogLevelDebug)
1192
fprintf (stderr, "%s (%s) - %s: %s\n",
1193
programName, componentName,
1194
logLevelToString (level), message);
1198
CompScreen::logMessage (const char *componentName,
1200
const char *message)
1202
WRAPABLE_HND_FUNC (13, logMessage, componentName, level, message)
1203
::logMessage (componentName, level, message);
1207
compLogMessage (const char *componentName,
1215
va_start (args, format);
1217
vsnprintf (message, 2048, format, args);
1220
screen->logMessage (componentName, level, message);
1222
logMessage (componentName, level, message);
1228
PrivateScreen::getWmState (Window id)
1232
unsigned long n, left;
1233
unsigned char *data;
1234
unsigned long state = NormalState;
1236
result = XGetWindowProperty (priv->dpy, id,
1237
Atoms::wmState, 0L, 2L, false,
1238
Atoms::wmState, &actual, &format,
1241
if (result == Success && data)
1244
memcpy (&state, data, sizeof (unsigned long));
1245
XFree ((void *) data);
1252
PrivateScreen::setWmState (int state, Window id)
1254
unsigned long data[2];
1259
XChangeProperty (priv->dpy, id,
1260
Atoms::wmState, Atoms::wmState,
1261
32, PropModeReplace, (unsigned char *) data, 2);
1265
PrivateScreen::windowStateMask (Atom state)
1267
if (state == Atoms::winStateModal)
1268
return CompWindowStateModalMask;
1269
else if (state == Atoms::winStateSticky)
1270
return CompWindowStateStickyMask;
1271
else if (state == Atoms::winStateMaximizedVert)
1272
return CompWindowStateMaximizedVertMask;
1273
else if (state == Atoms::winStateMaximizedHorz)
1274
return CompWindowStateMaximizedHorzMask;
1275
else if (state == Atoms::winStateShaded)
1276
return CompWindowStateShadedMask;
1277
else if (state == Atoms::winStateSkipTaskbar)
1278
return CompWindowStateSkipTaskbarMask;
1279
else if (state == Atoms::winStateSkipPager)
1280
return CompWindowStateSkipPagerMask;
1281
else if (state == Atoms::winStateHidden)
1282
return CompWindowStateHiddenMask;
1283
else if (state == Atoms::winStateFullscreen)
1284
return CompWindowStateFullscreenMask;
1285
else if (state == Atoms::winStateAbove)
1286
return CompWindowStateAboveMask;
1287
else if (state == Atoms::winStateBelow)
1288
return CompWindowStateBelowMask;
1289
else if (state == Atoms::winStateDemandsAttention)
1290
return CompWindowStateDemandsAttentionMask;
1291
else if (state == Atoms::winStateDisplayModal)
1292
return CompWindowStateDisplayModalMask;
1298
PrivateScreen::windowStateFromString (const char *str)
1300
if (strcasecmp (str, "modal") == 0)
1301
return CompWindowStateModalMask;
1302
else if (strcasecmp (str, "sticky") == 0)
1303
return CompWindowStateStickyMask;
1304
else if (strcasecmp (str, "maxvert") == 0)
1305
return CompWindowStateMaximizedVertMask;
1306
else if (strcasecmp (str, "maxhorz") == 0)
1307
return CompWindowStateMaximizedHorzMask;
1308
else if (strcasecmp (str, "shaded") == 0)
1309
return CompWindowStateShadedMask;
1310
else if (strcasecmp (str, "skiptaskbar") == 0)
1311
return CompWindowStateSkipTaskbarMask;
1312
else if (strcasecmp (str, "skippager") == 0)
1313
return CompWindowStateSkipPagerMask;
1314
else if (strcasecmp (str, "hidden") == 0)
1315
return CompWindowStateHiddenMask;
1316
else if (strcasecmp (str, "fullscreen") == 0)
1317
return CompWindowStateFullscreenMask;
1318
else if (strcasecmp (str, "above") == 0)
1319
return CompWindowStateAboveMask;
1320
else if (strcasecmp (str, "below") == 0)
1321
return CompWindowStateBelowMask;
1322
else if (strcasecmp (str, "demandsattention") == 0)
1323
return CompWindowStateDemandsAttentionMask;
1329
PrivateScreen::getWindowState (Window id)
1333
unsigned long n, left;
1334
unsigned char *data;
1335
unsigned int state = 0;
1337
result = XGetWindowProperty (priv->dpy, id,
1339
0L, 1024L, false, XA_ATOM, &actual, &format,
1342
if (result == Success && data)
1344
Atom *a = (Atom *) data;
1347
state |= windowStateMask (*a++);
1349
XFree ((void *) data);
1356
PrivateScreen::setWindowState (unsigned int state, Window id)
1361
if (state & CompWindowStateModalMask)
1362
data[i++] = Atoms::winStateModal;
1363
if (state & CompWindowStateStickyMask)
1364
data[i++] = Atoms::winStateSticky;
1365
if (state & CompWindowStateMaximizedVertMask)
1366
data[i++] = Atoms::winStateMaximizedVert;
1367
if (state & CompWindowStateMaximizedHorzMask)
1368
data[i++] = Atoms::winStateMaximizedHorz;
1369
if (state & CompWindowStateShadedMask)
1370
data[i++] = Atoms::winStateShaded;
1371
if (state & CompWindowStateSkipTaskbarMask)
1372
data[i++] = Atoms::winStateSkipTaskbar;
1373
if (state & CompWindowStateSkipPagerMask)
1374
data[i++] = Atoms::winStateSkipPager;
1375
if (state & CompWindowStateHiddenMask)
1376
data[i++] = Atoms::winStateHidden;
1377
if (state & CompWindowStateFullscreenMask)
1378
data[i++] = Atoms::winStateFullscreen;
1379
if (state & CompWindowStateAboveMask)
1380
data[i++] = Atoms::winStateAbove;
1381
if (state & CompWindowStateBelowMask)
1382
data[i++] = Atoms::winStateBelow;
1383
if (state & CompWindowStateDemandsAttentionMask)
1384
data[i++] = Atoms::winStateDemandsAttention;
1385
if (state & CompWindowStateDisplayModalMask)
1386
data[i++] = Atoms::winStateDisplayModal;
1388
XChangeProperty (priv->dpy, id, Atoms::winState,
1389
XA_ATOM, 32, PropModeReplace,
1390
(unsigned char *) data, i);
1394
PrivateScreen::getWindowType (Window id)
1396
Atom actual, a = None;
1398
unsigned long n, left;
1399
unsigned char *data;
1401
result = XGetWindowProperty (priv->dpy , id,
1403
0L, 1L, false, XA_ATOM, &actual, &format,
1406
if (result == Success && data)
1409
memcpy (&a, data, sizeof (Atom));
1410
XFree ((void *) data);
1415
if (a == Atoms::winTypeNormal)
1416
return CompWindowTypeNormalMask;
1417
else if (a == Atoms::winTypeMenu)
1418
return CompWindowTypeMenuMask;
1419
else if (a == Atoms::winTypeDesktop)
1420
return CompWindowTypeDesktopMask;
1421
else if (a == Atoms::winTypeDock)
1422
return CompWindowTypeDockMask;
1423
else if (a == Atoms::winTypeToolbar)
1424
return CompWindowTypeToolbarMask;
1425
else if (a == Atoms::winTypeUtil)
1426
return CompWindowTypeUtilMask;
1427
else if (a == Atoms::winTypeSplash)
1428
return CompWindowTypeSplashMask;
1429
else if (a == Atoms::winTypeDialog)
1430
return CompWindowTypeDialogMask;
1431
else if (a == Atoms::winTypeDropdownMenu)
1432
return CompWindowTypeDropdownMenuMask;
1433
else if (a == Atoms::winTypePopupMenu)
1434
return CompWindowTypePopupMenuMask;
1435
else if (a == Atoms::winTypeTooltip)
1436
return CompWindowTypeTooltipMask;
1437
else if (a == Atoms::winTypeNotification)
1438
return CompWindowTypeNotificationMask;
1439
else if (a == Atoms::winTypeCombo)
1440
return CompWindowTypeComboMask;
1441
else if (a == Atoms::winTypeDnd)
1442
return CompWindowTypeDndMask;
1445
return CompWindowTypeUnknownMask;
1449
PrivateScreen::getMwmHints (Window id,
1451
unsigned int *decor)
1455
unsigned long n, left;
1456
unsigned char *data;
1459
*decor = MwmDecorAll;
1461
result = XGetWindowProperty (priv->dpy, id,
1463
0L, 20L, false, Atoms::mwmHints,
1464
&actual, &format, &n, &left, &data);
1466
if (result == Success && data)
1468
MwmHints *mwmHints = (MwmHints *) data;
1470
if (n >= PropMotifWmHintElements)
1472
if (mwmHints->flags & MwmHintsDecorations)
1473
*decor = mwmHints->decorations;
1475
if (mwmHints->flags & MwmHintsFunctions)
1476
*func = mwmHints->functions;
1484
PrivateScreen::getProtocols (Window id)
1488
unsigned int protocols = 0;
1490
if (XGetWMProtocols (priv->dpy, id, &protocol, &count))
1494
for (i = 0; i < count; i++)
1496
if (protocol[i] == Atoms::wmDeleteWindow)
1497
protocols |= CompWindowProtocolDeleteMask;
1498
else if (protocol[i] == Atoms::wmTakeFocus)
1499
protocols |= CompWindowProtocolTakeFocusMask;
1500
else if (protocol[i] == Atoms::wmPing)
1501
protocols |= CompWindowProtocolPingMask;
1502
else if (protocol[i] == Atoms::wmSyncRequest)
1503
protocols |= CompWindowProtocolSyncRequestMask;
1513
CompScreen::getWindowProp (Window id,
1515
unsigned int defaultValue)
1519
unsigned long n, left;
1520
unsigned char *data;
1521
unsigned int retval = defaultValue;
1523
result = XGetWindowProperty (priv->dpy, id, property,
1524
0L, 1L, false, XA_CARDINAL, &actual, &format,
1527
if (result == Success && data)
1531
unsigned long value;
1532
memcpy (&value, data, sizeof (unsigned long));
1533
retval = (unsigned int) value;
1543
CompScreen::setWindowProp (Window id,
1547
unsigned long data = value;
1549
XChangeProperty (priv->dpy, id, property,
1550
XA_CARDINAL, 32, PropModeReplace,
1551
(unsigned char *) &data, 1);
1555
PrivateScreen::readWindowProp32 (Window id,
1557
unsigned short *returnValue)
1561
unsigned long n, left;
1562
unsigned char *data;
1563
bool retval = false;
1565
result = XGetWindowProperty (priv->dpy, id, property,
1566
0L, 1L, false, XA_CARDINAL, &actual, &format,
1569
if (result == Success && data)
1575
memcpy (&value, data, sizeof (CARD32));
1577
*returnValue = value >> 16;
1587
CompScreen::getWindowProp32 (Window id,
1589
unsigned short defaultValue)
1591
unsigned short result;
1593
if (priv->readWindowProp32 (id, property, &result))
1596
return defaultValue;
1600
CompScreen::setWindowProp32 (Window id,
1602
unsigned short value)
1606
value32 = value << 16 | value;
1608
XChangeProperty (priv->dpy, id, property,
1609
XA_CARDINAL, 32, PropModeReplace,
1610
(unsigned char *) &value32, 1);
1614
ScreenInterface::handleEvent (XEvent *event)
1615
WRAPABLE_DEF (handleEvent, event)
1618
ScreenInterface::handleCompizEvent (const char *plugin,
1620
CompOption::Vector &options)
1621
WRAPABLE_DEF (handleCompizEvent, plugin, event, options)
1624
ScreenInterface::fileToImage (CompString &name,
1628
WRAPABLE_DEF (fileToImage, name, size, stride, data)
1631
ScreenInterface::imageToFile (CompString &path,
1636
WRAPABLE_DEF (imageToFile, path, format, size, stride, data)
1638
CompMatch::Expression *
1639
ScreenInterface::matchInitExp (const CompString& value)
1640
WRAPABLE_DEF (matchInitExp, value)
1643
ScreenInterface::matchExpHandlerChanged ()
1644
WRAPABLE_DEF (matchExpHandlerChanged)
1647
ScreenInterface::matchPropertyChanged (CompWindow *window)
1648
WRAPABLE_DEF (matchPropertyChanged, window)
1651
ScreenInterface::logMessage (const char *componentName,
1653
const char *message)
1654
WRAPABLE_DEF (logMessage, componentName, level, message)
1658
PrivateScreen::desktopHintEqual (unsigned long *data,
1663
if (size != desktopHintSize)
1666
if (memcmp (data + offset,
1667
desktopHintData + offset,
1668
hintSize * sizeof (unsigned long)) == 0)
1675
PrivateScreen::setDesktopHints ()
1677
unsigned long *data;
1678
int dSize, offset, hintSize;
1681
dSize = nDesktop * 2 + nDesktop * 2 + nDesktop * 4 + 1;
1683
data = (unsigned long *) malloc (sizeof (unsigned long) * dSize);
1688
hintSize = nDesktop * 2;
1690
for (i = 0; i < nDesktop; i++)
1692
data[offset + i * 2 + 0] = vp.x () * screen->width ();
1693
data[offset + i * 2 + 1] = vp.y () * screen->height ();
1696
if (!desktopHintEqual (data, dSize, offset, hintSize))
1697
XChangeProperty (dpy, root,
1698
Atoms::desktopViewport,
1699
XA_CARDINAL, 32, PropModeReplace,
1700
(unsigned char *) &data[offset], hintSize);
1704
for (i = 0; i < nDesktop; i++)
1706
data[offset + i * 2 + 0] = screen->width () * vpSize.width ();
1707
data[offset + i * 2 + 1] = screen->height () * vpSize.height ();
1710
if (!desktopHintEqual (data, dSize, offset, hintSize))
1711
XChangeProperty (dpy, root,
1712
Atoms::desktopGeometry,
1713
XA_CARDINAL, 32, PropModeReplace,
1714
(unsigned char *) &data[offset], hintSize);
1717
hintSize = nDesktop * 4;
1719
for (i = 0; i < nDesktop; i++)
1721
data[offset + i * 4 + 0] = workArea.x ();
1722
data[offset + i * 4 + 1] = workArea.y ();
1723
data[offset + i * 4 + 2] = workArea.width ();
1724
data[offset + i * 4 + 3] = workArea.height ();
1727
if (!desktopHintEqual (data, dSize, offset, hintSize))
1728
XChangeProperty (dpy, root,
1730
XA_CARDINAL, 32, PropModeReplace,
1731
(unsigned char *) &data[offset], hintSize);
1735
data[offset] = nDesktop;
1738
if (!desktopHintEqual (data, dSize, offset, hintSize))
1739
XChangeProperty (dpy, root,
1740
Atoms::numberOfDesktops,
1741
XA_CARDINAL, 32, PropModeReplace,
1742
(unsigned char *) &data[offset], hintSize);
1744
if (desktopHintData)
1745
free (desktopHintData);
1747
desktopHintData = data;
1748
desktopHintSize = dSize;
1752
PrivateScreen::setVirtualScreenSize (int newh, int newv)
1754
/* if newh or newv is being reduced */
1755
if (newh < screen->vpSize ().width () ||
1756
newv < screen->vpSize ().height ())
1761
if (screen->vp ().x () >= newh)
1762
tx = screen->vp ().x () - (newh - 1);
1763
if (screen->vp ().y () >= newv)
1764
ty = screen->vp ().y () - (newv - 1);
1766
if (tx != 0 || ty != 0)
1767
screen->moveViewport (tx, ty, TRUE);
1769
/* Move windows that were in one of the deleted viewports into the
1771
foreach (CompWindow *w, screen->windows ())
1776
if (w->onAllViewports ())
1779
/* Find which viewport the (inner) window's top-left corner falls
1780
in, and check if it's outside the new viewport horizontal and
1781
vertical index range */
1782
if (newh < screen->vpSize ().width ())
1784
int vpX; /* x index of a window's vp */
1786
vpX = w->serverX () / screen->width ();
1787
if (w->serverX () < 0)
1790
vpX += screen->vp ().x (); /* Convert relative to absolute vp index */
1792
/* Move windows too far right to left */
1794
moveX = ((newh - 1) - vpX) * screen->width ();
1796
if (newv < screen->vpSize ().height ())
1798
int vpY; /* y index of a window's vp */
1800
vpY = w->serverY () / screen->height ();
1801
if (w->serverY () < 0)
1804
vpY += screen->vp ().y (); /* Convert relative to absolute vp index */
1806
/* Move windows too far right to left */
1808
moveY = ((newv - 1) - vpY) * screen->height ();
1811
if (moveX != 0 || moveY != 0)
1813
w->move (moveX, moveY, true);
1819
vpSize.setWidth (newh);
1820
vpSize.setHeight (newv);
1826
PrivateScreen::updateOutputDevices ()
1828
CompOption::Value::Vector &list = optionGetOutputs ();
1829
unsigned int nOutput = 0;
1831
unsigned int uWidth, uHeight;
1836
foreach (CompOption::Value &value, list)
1840
uWidth = (unsigned) screen->width ();
1841
uHeight = (unsigned) screen->height ();
1843
bits = XParseGeometry (value.s ().c_str (), &x, &y, &uWidth, &uHeight);
1844
width = (int) uWidth;
1845
height = (int) uHeight;
1847
if (bits & XNegative)
1848
x = screen->width () + x - width;
1850
if (bits & YNegative)
1851
y = screen->height () + y - height;
1862
if (x2 > screen->width ())
1863
x2 = screen->width ();
1864
if (y2 > screen->height ())
1865
y2 = screen->height ();
1867
if (x1 < x2 && y1 < y2)
1869
if (outputDevs.size () < nOutput + 1)
1870
outputDevs.resize (nOutput + 1);
1872
outputDevs[nOutput].setGeometry (x1, y1, x2 - x1, y2 - y1);
1877
/* make sure we have at least one output */
1880
if (outputDevs.size () < 1)
1881
outputDevs.resize (1);
1883
outputDevs[0].setGeometry (0, 0, screen->width (), screen->height ());
1887
if (outputDevs.size () > nOutput)
1888
outputDevs.resize (nOutput);
1890
/* set name, width, height and update rect pointers in all regions */
1891
for (unsigned int i = 0; i < nOutput; i++)
1893
snprintf (str, 10, "Output %d", i);
1894
outputDevs[i].setId (str, i);
1897
hasOverlappingOutputs = false;
1899
setCurrentOutput (currentOutputDev);
1901
/* clear out fullscreen monitor hints of all windows as
1902
suggested on monitor layout changes in EWMH */
1903
foreach (CompWindow *w, windows)
1904
if (w->priv->fullscreenMonitorsSet)
1905
w->priv->setFullscreenMonitors (NULL);
1907
for (unsigned int i = 0; i < nOutput - 1; i++)
1908
for (unsigned int j = i + 1; j < nOutput; j++)
1909
if (outputDevs[i].intersects (outputDevs[j]))
1910
hasOverlappingOutputs = true;
1912
screen->updateWorkarea ();
1914
screen->outputChangeNotify ();
1918
PrivateScreen::detectOutputDevices ()
1920
if (!noDetection && optionGetDetectOutputs ())
1923
CompOption::Value value;
1925
if (screenInfo.size ())
1927
CompOption::Value::Vector l;
1928
foreach (XineramaScreenInfo xi, screenInfo)
1930
l.push_back (compPrintf ("%dx%d+%d+%d", xi.width, xi.height,
1931
xi.x_org, xi.y_org));
1934
value.set (CompOption::TypeString, l);
1938
CompOption::Value::Vector l;
1939
l.push_back (compPrintf ("%dx%d+%d+%d", screen->width (),
1940
screen->height (), 0, 0));
1941
value.set (CompOption::TypeString, l);
1944
mOptions[CoreOptions::DetectOutputs].value ().set (false);
1945
screen->setOptionForPlugin ("core", "outputs", value);
1946
mOptions[CoreOptions::DetectOutputs].value ().set (true);
1951
updateOutputDevices ();
1957
PrivateScreen::updateStartupFeedback ()
1959
if (!startupSequences.empty ())
1960
XDefineCursor (dpy, root, busyCursor);
1962
XDefineCursor (dpy, root, normalCursor);
1965
#define STARTUP_TIMEOUT_DELAY 15000
1968
PrivateScreen::handleStartupSequenceTimeout ()
1970
struct timeval now, active;
1973
gettimeofday (&now, NULL);
1975
foreach (CompStartupSequence *s, startupSequences)
1977
sn_startup_sequence_get_last_active_time (s->sequence,
1981
elapsed = ((((double) now.tv_sec - active.tv_sec) * 1000000.0 +
1982
(now.tv_usec - active.tv_usec))) / 1000.0;
1984
if (elapsed > STARTUP_TIMEOUT_DELAY)
1985
sn_startup_sequence_complete (s->sequence);
1992
PrivateScreen::addSequence (SnStartupSequence *sequence)
1994
CompStartupSequence *s;
1996
s = new CompStartupSequence ();
2000
sn_startup_sequence_ref (sequence);
2002
s->sequence = sequence;
2003
s->viewportX = vp.x ();
2004
s->viewportY = vp.y ();
2006
startupSequences.push_front (s);
2008
if (!startupSequenceTimer.active ())
2009
startupSequenceTimer.start ();
2011
updateStartupFeedback ();
2015
PrivateScreen::removeSequence (SnStartupSequence *sequence)
2017
CompStartupSequence *s = NULL;
2019
std::list<CompStartupSequence *>::iterator it = startupSequences.begin ();
2021
for (; it != startupSequences.end (); it++)
2023
if ((*it)->sequence == sequence)
2033
sn_startup_sequence_unref (sequence);
2035
startupSequences.erase (it);
2039
if (startupSequences.empty () && startupSequenceTimer.active ())
2040
startupSequenceTimer.stop ();
2042
updateStartupFeedback ();
2046
PrivateScreen::removeAllSequences ()
2048
foreach (CompStartupSequence *s, startupSequences)
2050
sn_startup_sequence_unref (s->sequence);
2054
startupSequences.clear ();
2056
if (startupSequenceTimer.active ())
2057
startupSequenceTimer.stop ();
2059
updateStartupFeedback ();
2063
CompScreen::compScreenSnEvent (SnMonitorEvent *event,
2066
CompScreen *screen = (CompScreen *) userData;
2067
SnStartupSequence *sequence;
2069
sequence = sn_monitor_event_get_startup_sequence (event);
2071
switch (sn_monitor_event_get_type (event)) {
2072
case SN_MONITOR_EVENT_INITIATED:
2073
screen->priv->addSequence (sequence);
2075
case SN_MONITOR_EVENT_COMPLETED:
2076
screen->priv->removeSequence (sequence);
2078
case SN_MONITOR_EVENT_CHANGED:
2079
case SN_MONITOR_EVENT_CANCELED:
2085
PrivateScreen::updateScreenEdges ()
2087
struct screenEdgeGeometry {
2092
} geometry[SCREEN_EDGE_NUM] = {
2093
{ 0, 0, 0, 2, 0, 2, 1, -4 }, /* left */
2094
{ 1, -2, 0, 2, 0, 2, 1, -4 }, /* right */
2095
{ 0, 2, 0, 0, 1, -4, 0, 2 }, /* top */
2096
{ 0, 2, 1, -2, 1, -4, 0, 2 }, /* bottom */
2097
{ 0, 0, 0, 0, 0, 2, 0, 2 }, /* top-left */
2098
{ 1, -2, 0, 0, 0, 2, 0, 2 }, /* top-right */
2099
{ 0, 0, 1, -2, 0, 2, 0, 2 }, /* bottom-left */
2100
{ 1, -2, 1, -2, 0, 2, 0, 2 } /* bottom-right */
2104
for (i = 0; i < SCREEN_EDGE_NUM; i++)
2106
if (screenEdge[i].id)
2107
XMoveResizeWindow (dpy, screenEdge[i].id,
2108
geometry[i].xw * screen->width () +
2110
geometry[i].yh * screen->height () +
2112
geometry[i].ww * screen->width () +
2114
geometry[i].hh * screen->height () +
2120
PrivateScreen::setCurrentOutput (unsigned int outputNum)
2122
if (outputNum >= priv->outputDevs.size ())
2125
priv->currentOutputDev = outputNum;
2129
PrivateScreen::reshape (int w, int h)
2131
updateScreenInfo ();
2133
region = CompRegion (0, 0, w, h);
2135
screen->setWidth (w);
2136
screen->setHeight (h);
2138
fullscreenOutput.setId ("fullscreen", ~0);
2139
fullscreenOutput.setGeometry (0, 0, w, h);
2141
updateScreenEdges ();
2145
PrivateScreen::configure (XConfigureEvent *ce)
2147
if (priv->attrib.width != ce->width ||
2148
priv->attrib.height != ce->height)
2150
priv->attrib.width = ce->width;
2151
priv->attrib.height = ce->height;
2153
priv->reshape (ce->width, ce->height);
2155
priv->detectOutputDevices ();
2160
PrivateScreen::setSupportingWmCheck ()
2162
XChangeProperty (dpy, grabWindow,
2163
Atoms::supportingWmCheck,
2164
XA_WINDOW, 32, PropModeReplace,
2165
(unsigned char *) &grabWindow, 1);
2167
XChangeProperty (dpy, grabWindow, Atoms::wmName,
2168
Atoms::utf8String, 8, PropModeReplace,
2169
(unsigned char *) PACKAGE, strlen (PACKAGE));
2170
XChangeProperty (dpy, grabWindow, Atoms::winState,
2171
XA_ATOM, 32, PropModeReplace,
2172
(unsigned char *) &Atoms::winStateSkipTaskbar,
2174
XChangeProperty (dpy, grabWindow, Atoms::winState,
2175
XA_ATOM, 32, PropModeAppend,
2176
(unsigned char *) &Atoms::winStateSkipPager, 1);
2177
XChangeProperty (dpy, grabWindow, Atoms::winState,
2178
XA_ATOM, 32, PropModeAppend,
2179
(unsigned char *) &Atoms::winStateHidden, 1);
2181
XChangeProperty (dpy, root, Atoms::supportingWmCheck,
2182
XA_WINDOW, 32, PropModeReplace,
2183
(unsigned char *) &grabWindow, 1);
2187
CompScreen::updateSupportedWmHints ()
2189
std::vector<Atom> atoms;
2191
addSupportedAtoms (atoms);
2193
XChangeProperty (dpy (), root (), Atoms::supported,
2194
XA_ATOM, 32, PropModeReplace,
2195
(const unsigned char *) &atoms.at (0), atoms.size ());
2199
CompScreen::addSupportedAtoms (std::vector<Atom> &atoms)
2201
WRAPABLE_HND_FUNC (17, addSupportedAtoms, atoms);
2203
atoms.push_back (Atoms::supported);
2204
atoms.push_back (Atoms::supportingWmCheck);
2206
atoms.push_back (Atoms::utf8String);
2208
atoms.push_back (Atoms::clientList);
2209
atoms.push_back (Atoms::clientListStacking);
2211
atoms.push_back (Atoms::winActive);
2213
atoms.push_back (Atoms::desktopViewport);
2214
atoms.push_back (Atoms::desktopGeometry);
2215
atoms.push_back (Atoms::currentDesktop);
2216
atoms.push_back (Atoms::numberOfDesktops);
2217
atoms.push_back (Atoms::showingDesktop);
2219
atoms.push_back (Atoms::workarea);
2221
atoms.push_back (Atoms::wmName);
2223
atoms.push_back (Atoms::wmVisibleName);
2226
atoms.push_back (Atoms::wmStrut);
2227
atoms.push_back (Atoms::wmStrutPartial);
2230
atoms.push_back (Atoms::wmPid);
2233
atoms.push_back (Atoms::wmUserTime);
2234
atoms.push_back (Atoms::frameExtents);
2235
atoms.push_back (Atoms::frameWindow);
2237
atoms.push_back (Atoms::winState);
2238
atoms.push_back (Atoms::winStateModal);
2239
atoms.push_back (Atoms::winStateSticky);
2240
atoms.push_back (Atoms::winStateMaximizedVert);
2241
atoms.push_back (Atoms::winStateMaximizedHorz);
2242
atoms.push_back (Atoms::winStateShaded);
2243
atoms.push_back (Atoms::winStateSkipTaskbar);
2244
atoms.push_back (Atoms::winStateSkipPager);
2245
atoms.push_back (Atoms::winStateHidden);
2246
atoms.push_back (Atoms::winStateFullscreen);
2247
atoms.push_back (Atoms::winStateAbove);
2248
atoms.push_back (Atoms::winStateBelow);
2249
atoms.push_back (Atoms::winStateDemandsAttention);
2251
atoms.push_back (Atoms::winOpacity);
2252
atoms.push_back (Atoms::winBrightness);
2258
atoms.push_back (Atoms::winSaturation);
2259
atoms.push_back (Atoms::winStateDisplayModal);
2263
atoms.push_back (Atoms::wmAllowedActions);
2265
atoms.push_back (Atoms::winActionMove);
2266
atoms.push_back (Atoms::winActionResize);
2267
atoms.push_back (Atoms::winActionStick);
2268
atoms.push_back (Atoms::winActionMinimize);
2269
atoms.push_back (Atoms::winActionMaximizeHorz);
2270
atoms.push_back (Atoms::winActionMaximizeVert);
2271
atoms.push_back (Atoms::winActionFullscreen);
2272
atoms.push_back (Atoms::winActionClose);
2273
atoms.push_back (Atoms::winActionShade);
2274
atoms.push_back (Atoms::winActionChangeDesktop);
2275
atoms.push_back (Atoms::winActionAbove);
2276
atoms.push_back (Atoms::winActionBelow);
2278
atoms.push_back (Atoms::winType);
2279
atoms.push_back (Atoms::winTypeDesktop);
2280
atoms.push_back (Atoms::winTypeDock);
2281
atoms.push_back (Atoms::winTypeToolbar);
2282
atoms.push_back (Atoms::winTypeMenu);
2283
atoms.push_back (Atoms::winTypeSplash);
2284
atoms.push_back (Atoms::winTypeDialog);
2285
atoms.push_back (Atoms::winTypeUtil);
2286
atoms.push_back (Atoms::winTypeNormal);
2288
atoms.push_back (Atoms::wmDeleteWindow);
2289
atoms.push_back (Atoms::wmPing);
2291
atoms.push_back (Atoms::wmMoveResize);
2292
atoms.push_back (Atoms::moveResizeWindow);
2293
atoms.push_back (Atoms::restackWindow);
2295
atoms.push_back (Atoms::wmFullscreenMonitors);
2299
PrivateScreen::getDesktopHints ()
2301
unsigned long data[2];
2304
unsigned long n, left;
2305
unsigned char *propData;
2307
if (useDesktopHints)
2309
result = XGetWindowProperty (dpy, root,
2310
Atoms::numberOfDesktops,
2311
0L, 1L, false, XA_CARDINAL, &actual,
2312
&format, &n, &left, &propData);
2314
if (result == Success && propData)
2318
memcpy (data, propData, sizeof (unsigned long));
2319
if (data[0] > 0 && data[0] < 0xffffffff)
2326
result = XGetWindowProperty (dpy, root,
2327
Atoms::desktopViewport, 0L, 2L,
2328
false, XA_CARDINAL, &actual, &format,
2329
&n, &left, &propData);
2331
if (result == Success && propData)
2335
memcpy (data, propData, sizeof (unsigned long) * 2);
2337
if (data[0] / (unsigned int) screen->width () <
2338
(unsigned int) vpSize.width () - 1)
2339
vp.setX (data[0] / screen->width ());
2341
if (data[1] / (unsigned int) screen->height () <
2342
(unsigned int) vpSize.height () - 1)
2343
vp.setY (data[1] / screen->height ());
2349
result = XGetWindowProperty (dpy, root,
2350
Atoms::currentDesktop,
2351
0L, 1L, false, XA_CARDINAL, &actual,
2352
&format, &n, &left, &propData);
2354
if (result == Success && propData)
2358
memcpy (data, propData, sizeof (unsigned long));
2359
if (data[0] < nDesktop)
2360
currentDesktop = data[0];
2367
result = XGetWindowProperty (dpy, root,
2368
Atoms::showingDesktop,
2369
0L, 1L, false, XA_CARDINAL, &actual, &format,
2370
&n, &left, &propData);
2372
if (result == Success && propData)
2376
memcpy (data, propData, sizeof (unsigned long));
2378
screen->enterShowDesktopMode ();
2384
data[0] = currentDesktop;
2386
XChangeProperty (dpy, root, Atoms::currentDesktop,
2387
XA_CARDINAL, 32, PropModeReplace,
2388
(unsigned char *) data, 1);
2390
data[0] = showingDesktopMask ? true : false;
2392
XChangeProperty (dpy, root, Atoms::showingDesktop,
2393
XA_CARDINAL, 32, PropModeReplace,
2394
(unsigned char *) data, 1);
2398
CompScreen::enterShowDesktopMode ()
2400
WRAPABLE_HND_FUNC (14, enterShowDesktopMode)
2402
unsigned long data = 1;
2404
bool st = priv->optionGetHideSkipTaskbarWindows ();
2406
priv->showingDesktopMask = ~(CompWindowTypeDesktopMask |
2407
CompWindowTypeDockMask);
2409
foreach (CompWindow *w, priv->windows)
2411
if ((priv->showingDesktopMask & w->wmType ()) &&
2412
(!(w->state () & CompWindowStateSkipTaskbarMask) || st))
2414
if (!w->inShowDesktopMode () && !w->grabbed () &&
2415
w->managed () && w->focus ())
2417
w->setShowDesktopMode (true);
2418
w->windowNotify (CompWindowNotifyEnterShowDesktopMode);
2423
if (w->inShowDesktopMode ())
2429
priv->showingDesktopMask = 0;
2433
XChangeProperty (priv->dpy, priv->root,
2434
Atoms::showingDesktop,
2435
XA_CARDINAL, 32, PropModeReplace,
2436
(unsigned char *) &data, 1);
2440
CompScreen::leaveShowDesktopMode (CompWindow *window)
2442
WRAPABLE_HND_FUNC (15, leaveShowDesktopMode, window)
2444
unsigned long data = 0;
2448
if (!window->inShowDesktopMode ())
2451
window->setShowDesktopMode (false);
2452
window->windowNotify (CompWindowNotifyLeaveShowDesktopMode);
2453
window->priv->show ();
2455
/* return if some other window is still in show desktop mode */
2456
foreach (CompWindow *w, priv->windows)
2457
if (w->inShowDesktopMode ())
2460
priv->showingDesktopMask = 0;
2464
priv->showingDesktopMask = 0;
2466
foreach (CompWindow *w, priv->windows)
2468
if (!w->inShowDesktopMode ())
2471
w->setShowDesktopMode (false);
2472
w->windowNotify (CompWindowNotifyLeaveShowDesktopMode);
2476
/* focus default window - most likely this will be the window
2477
which had focus before entering showdesktop mode */
2478
focusDefaultWindow ();
2481
XChangeProperty (priv->dpy, priv->root,
2482
Atoms::showingDesktop,
2483
XA_CARDINAL, 32, PropModeReplace,
2484
(unsigned char *) &data, 1);
2488
CompScreen::forEachWindow (CompWindow::ForEach proc)
2490
foreach (CompWindow *w, priv->windows)
2495
CompScreen::focusDefaultWindow ()
2498
CompWindow *focus = NULL;
2500
if (!priv->optionGetClickToFocus ())
2502
w = findTopLevelWindow (priv->below);
2504
if (w && w->focus ())
2506
if (!(w->type () & (CompWindowTypeDesktopMask |
2507
CompWindowTypeDockMask)))
2513
Window rootReturn, childReturn;
2515
unsigned int dummyUInt;
2517
/* huh, we didn't find d->below ... perhaps it's out of date;
2518
try grabbing it through the server */
2520
status = XQueryPointer (dpy (), priv->root, &rootReturn,
2521
&childReturn, &dummyInt, &dummyInt,
2522
&dummyInt, &dummyInt, &dummyUInt);
2524
if (status && rootReturn == priv->root)
2526
w = findTopLevelWindow (childReturn);
2528
if (w && w->focus ())
2530
if (!(w->type () & (CompWindowTypeDesktopMask |
2531
CompWindowTypeDockMask)))
2540
for (CompWindowList::reverse_iterator rit = priv->windows.rbegin ();
2541
rit != priv->windows.rend (); rit++)
2545
if (w->type () & CompWindowTypeDockMask)
2552
if (w->type () & (CompWindowTypeNormalMask |
2553
CompWindowTypeDialogMask |
2554
CompWindowTypeModalDialogMask))
2556
if (PrivateWindow::compareWindowActiveness (focus, w) < 0)
2568
if (focus->id () != priv->activeWindow)
2569
focus->moveInputFocusTo ();
2573
XSetInputFocus (priv->dpy, priv->root, RevertToPointerRoot,
2579
CompScreen::findWindow (Window id)
2581
if (lastFoundWindow && lastFoundWindow->id () == id)
2583
return lastFoundWindow;
2587
CompWindow::Map::iterator it = priv->windowsMap.find (id);
2589
if (it != priv->windowsMap.end ())
2590
return (lastFoundWindow = it->second);
2597
CompScreen::findTopLevelWindow (Window id, bool override_redirect)
2601
w = findWindow (id);
2605
if (w->overrideRedirect () && !override_redirect)
2611
foreach (CompWindow *w, priv->windows)
2612
if (w->frame () == id)
2614
if (w->overrideRedirect () && !override_redirect)
2624
CompScreen::insertWindow (CompWindow *w, Window aboveId)
2629
if (!aboveId || priv->windows.empty ())
2631
if (!priv->windows.empty ())
2633
priv->windows.front ()->prev = w;
2634
w->next = priv->windows.front ();
2636
priv->windows.push_front (w);
2638
priv->windowsMap[w->id ()] = w;
2643
CompWindowList::iterator it = priv->windows.begin ();
2645
while (it != priv->windows.end ())
2647
if ((*it)->id () == aboveId ||
2648
((*it)->frame () && (*it)->frame () == aboveId))
2655
if (it == priv->windows.end ())
2663
w->next = (*it)->next;
2672
priv->windows.insert (++it, w);
2674
priv->windowsMap[w->id ()] = w;
2678
PrivateScreen::eraseWindowFromMap (Window id)
2681
priv->windowsMap.erase (id);
2685
CompScreen::unhookWindow (CompWindow *w)
2687
CompWindowList::iterator it =
2688
std::find (priv->windows.begin (), priv->windows.end (), w);
2690
priv->windows.erase (it);
2691
priv->eraseWindowFromMap (w->id ());
2694
w->next->prev = w->prev;
2697
w->prev->next = w->next;
2702
if (w == lastFoundWindow)
2703
lastFoundWindow = NULL;
2707
CompScreen::normalCursor ()
2709
return priv->normalCursor;
2713
CompScreen::invisibleCursor ()
2715
return priv->invisibleCursor;
2718
#define POINTER_GRAB_MASK (ButtonReleaseMask | \
2721
CompScreen::GrabHandle
2722
CompScreen::pushGrab (Cursor cursor, const char *name)
2724
if (priv->grabs.empty ())
2728
status = XGrabPointer (priv->dpy, priv->grabWindow, true,
2730
GrabModeAsync, GrabModeAsync,
2734
if (status == GrabSuccess)
2736
status = XGrabKeyboard (priv->dpy,
2737
priv->grabWindow, true,
2738
GrabModeAsync, GrabModeAsync,
2740
if (status != GrabSuccess)
2742
XUngrabPointer (priv->dpy, CurrentTime);
2751
XChangeActivePointerGrab (priv->dpy, POINTER_GRAB_MASK,
2752
cursor, CurrentTime);
2755
PrivateScreen::Grab *grab = new PrivateScreen::Grab ();
2756
grab->cursor = cursor;
2759
priv->grabs.push_back (grab);
2765
CompScreen::updateGrab (CompScreen::GrabHandle handle, Cursor cursor)
2770
XChangeActivePointerGrab (priv->dpy, POINTER_GRAB_MASK,
2771
cursor, CurrentTime);
2773
((PrivateScreen::Grab *) handle)->cursor = cursor;
2777
CompScreen::removeGrab (CompScreen::GrabHandle handle,
2778
CompPoint *restorePointer)
2783
std::list<PrivateScreen::Grab *>::iterator it;
2785
it = std::find (priv->grabs.begin (), priv->grabs.end (), handle);
2787
if (it != priv->grabs.end ())
2789
priv->grabs.erase (it);
2790
delete (static_cast<PrivateScreen::Grab *> (handle));
2792
if (!priv->grabs.empty ())
2794
XChangeActivePointerGrab (priv->dpy,
2796
priv->grabs.back ()->cursor,
2802
warpPointer (restorePointer->x () - pointerX,
2803
restorePointer->y () - pointerY);
2805
XUngrabPointer (priv->dpy, CurrentTime);
2806
XUngrabKeyboard (priv->dpy, CurrentTime);
2810
/* otherScreenGrabExist takes a series of strings terminated by a NULL.
2811
It returns true if a grab exists but it is NOT held by one of the
2812
plugins listed, returns false otherwise. */
2815
CompScreen::otherGrabExist (const char *first, ...)
2820
std::list<PrivateScreen::Grab *>::iterator it;
2822
for (it = priv->grabs.begin (); it != priv->grabs.end (); it++)
2824
va_start (ap, first);
2829
if (strcmp (name, (*it)->name) == 0)
2832
name = va_arg (ap, const char *);
2845
CompScreen::grabExist (const char *grab)
2847
foreach (PrivateScreen::Grab* g, priv->grabs)
2849
if (strcmp (g->name, grab) == 0)
2856
CompScreen::grabbed ()
2858
return priv->grabbed;
2862
PrivateScreen::grabUngrabOneKey (unsigned int modifiers,
2886
PrivateScreen::grabUngrabKeys (unsigned int modifiers,
2891
unsigned int ignore;
2893
CompScreen::checkForError (dpy);
2895
for (ignore = 0; ignore <= modHandler->ignoredModMask (); ignore++)
2897
if (ignore & ~modHandler->ignoredModMask ())
2902
grabUngrabOneKey (modifiers | ignore, keycode, grab);
2906
for (mod = 0; mod < 8; mod++)
2908
if (modifiers & (1 << mod))
2910
for (k = mod * modHandler->modMap ()->max_keypermod;
2911
k < (mod + 1) * modHandler->modMap ()->max_keypermod;
2914
if (modHandler->modMap ()->modifiermap[k])
2916
grabUngrabOneKey ((modifiers & ~(1 << mod)) |
2918
modHandler->modMap ()->modifiermap[k],
2926
if (CompScreen::checkForError (dpy))
2934
PrivateScreen::addPassiveKeyGrab (CompAction::KeyBinding &key)
2938
std::list<KeyGrab>::iterator it;
2940
mask = modHandler->virtualToRealModMask (key.modifiers ());
2942
for (it = keyGrabs.begin (); it != keyGrabs.end (); it++)
2944
if (key.keycode () == (*it).keycode &&
2945
mask == (*it).modifiers)
2954
if (!(mask & CompNoMask))
2956
if (!grabUngrabKeys (mask, key.keycode (), true))
2960
newKeyGrab.keycode = key.keycode ();
2961
newKeyGrab.modifiers = mask;
2962
newKeyGrab.count = 1;
2964
keyGrabs.push_back (newKeyGrab);
2970
PrivateScreen::removePassiveKeyGrab (CompAction::KeyBinding &key)
2973
std::list<KeyGrab>::iterator it;
2975
mask = modHandler->virtualToRealModMask (key.modifiers ());
2977
for (it = keyGrabs.begin (); it != keyGrabs.end (); it++)
2979
if (key.keycode () == (*it).keycode &&
2980
mask == (*it).modifiers)
2986
it = keyGrabs.erase (it);
2988
if (!(mask & CompNoMask))
2989
grabUngrabKeys (mask, key.keycode (), false);
2995
PrivateScreen::updatePassiveKeyGrabs ()
2997
std::list<KeyGrab>::iterator it;
2999
XUngrabKey (dpy, AnyKey, AnyModifier, root);
3001
for (it = keyGrabs.begin (); it != keyGrabs.end (); it++)
3003
if (!((*it).modifiers & CompNoMask))
3005
grabUngrabKeys ((*it).modifiers,
3006
(*it).keycode, true);
3012
PrivateScreen::addPassiveButtonGrab (CompAction::ButtonBinding &button)
3014
ButtonGrab newButtonGrab;
3015
std::list<ButtonGrab>::iterator it;
3017
for (it = buttonGrabs.begin (); it != buttonGrabs.end (); it++)
3019
if (button.button () == (*it).button &&
3020
button.modifiers () == (*it).modifiers)
3027
newButtonGrab.button = button.button ();
3028
newButtonGrab.modifiers = button.modifiers ();
3029
newButtonGrab.count = 1;
3031
buttonGrabs.push_back (newButtonGrab);
3033
foreach (CompWindow *w, screen->windows ())
3034
w->priv->updatePassiveButtonGrabs ();
3040
PrivateScreen::removePassiveButtonGrab (CompAction::ButtonBinding &button)
3042
std::list<ButtonGrab>::iterator it;
3044
for (it = buttonGrabs.begin (); it != buttonGrabs.end (); it++)
3046
if (button.button () == (*it).button &&
3047
button.modifiers () == (*it).modifiers)
3053
it = buttonGrabs.erase (it);
3055
foreach (CompWindow *w, screen->windows ())
3056
w->priv->updatePassiveButtonGrabs ();
3061
/* add actions that should be automatically added as no screens
3062
existed when they were initialized. */
3064
PrivateScreen::addScreenActions ()
3066
foreach (CompOption &o, mOptions)
3071
if (o.value ().action ().state () & CompAction::StateAutoGrab)
3072
screen->addAction (&o.value ().action ());
3077
CompScreen::addAction (CompAction *action)
3079
if (!screenInitalized || !priv->initialized)
3082
if (action->active ())
3085
if (action->type () & CompAction::BindingTypeKey)
3087
if (!priv->addPassiveKeyGrab (action->key ()))
3091
if (action->type () & CompAction::BindingTypeButton)
3093
if (!priv->addPassiveButtonGrab (action->button ()))
3095
if (action->type () & CompAction::BindingTypeKey)
3096
priv->removePassiveKeyGrab (action->key ());
3102
if (action->edgeMask ())
3106
for (i = 0; i < SCREEN_EDGE_NUM; i++)
3107
if (action->edgeMask () & (1 << i))
3108
priv->enableEdge (i);
3111
action->priv->active = true;
3117
CompScreen::removeAction (CompAction *action)
3119
if (!priv->initialized)
3122
if (!action->active ())
3125
if (action->type () & CompAction::BindingTypeKey)
3126
priv->removePassiveKeyGrab (action->key ());
3128
if (action->type () & CompAction::BindingTypeButton)
3129
priv->removePassiveButtonGrab (action->button ());
3131
if (action->edgeMask ())
3135
for (i = 0; i < SCREEN_EDGE_NUM; i++)
3136
if (action->edgeMask () & (1 << i))
3137
priv->disableEdge (i);
3140
action->priv->active = false;
3144
PrivateScreen::computeWorkareaForBox (const CompRect& box)
3151
foreach (CompWindow *w, windows)
3153
if (!w->isMapped ())
3158
x1 = w->struts ()->left.x;
3159
y1 = w->struts ()->left.y;
3160
x2 = x1 + w->struts ()->left.width;
3161
y2 = y1 + w->struts ()->left.height;
3163
if (y1 < box.y2 () && y2 > box.y1 ())
3164
region -= CompRect (x1, box.y1 (), x2 - x1, box.height ());
3166
x1 = w->struts ()->right.x;
3167
y1 = w->struts ()->right.y;
3168
x2 = x1 + w->struts ()->right.width;
3169
y2 = y1 + w->struts ()->right.height;
3171
if (y1 < box.y2 () && y2 > box.y1 ())
3172
region -= CompRect (x1, box.y1 (), x2 - x1, box.height ());
3174
x1 = w->struts ()->top.x;
3175
y1 = w->struts ()->top.y;
3176
x2 = x1 + w->struts ()->top.width;
3177
y2 = y1 + w->struts ()->top.height;
3179
if (x1 < box.x2 () && x2 > box.x1 ())
3180
region -= CompRect (box.x1 (), y1, box.width (), y2 - y1);
3182
x1 = w->struts ()->bottom.x;
3183
y1 = w->struts ()->bottom.y;
3184
x2 = x1 + w->struts ()->bottom.width;
3185
y2 = y1 + w->struts ()->bottom.height;
3187
if (x1 < box.x2 () && x2 > box.x1 ())
3188
region -= CompRect (box.x1 (), y1, box.width (), y2 - y1);
3192
if (region.isEmpty ())
3194
compLogMessage ("core", CompLogLevelWarn,
3195
"Empty box after applying struts, ignoring struts");
3199
return region.boundingRect ();
3203
CompScreen::updateWorkarea ()
3206
bool workAreaChanged = false;
3208
for (unsigned int i = 0; i < priv->outputDevs.size (); i++)
3210
CompRect oldWorkArea = priv->outputDevs[i].workArea ();
3212
workArea = priv->computeWorkareaForBox (priv->outputDevs[i]);
3214
if (workArea != oldWorkArea)
3216
workAreaChanged = true;
3217
priv->outputDevs[i].setWorkArea (workArea);
3221
workArea = priv->computeWorkareaForBox (CompRect (0, 0,
3223
screen->height ()));
3225
if (priv->workArea != workArea)
3227
workAreaChanged = true;
3228
priv->workArea = workArea;
3230
priv->setDesktopHints ();
3233
if (workAreaChanged)
3235
/* as work area changed, update all maximized windows on this
3236
screen to snap to the new work area */
3237
foreach (CompWindow *w, priv->windows)
3238
w->priv->updateSize ();
3243
isClientListWindow (CompWindow *w)
3245
/* windows with client id less than 2 have been destroyed and only exists
3246
because some plugin keeps a reference to them. they should not be in
3251
if (w->overrideRedirect ())
3254
if (!w->isViewable ())
3256
if (!(w->state () & CompWindowStateHiddenMask))
3264
countClientListWindow (CompWindow *w,
3267
if (isClientListWindow (w))
3274
compareMappingOrder (const CompWindow *w1,
3275
const CompWindow *w2)
3277
return w1->mapNum () < w2->mapNum ();
3281
PrivateScreen::updateClientList ()
3283
bool updateClientList = false;
3284
bool updateClientListStacking = false;
3287
screen->forEachWindow (boost::bind (countClientListWindow, _1, &n));
3291
if ((unsigned int) n != priv->clientList.size ())
3293
priv->clientList.clear ();
3294
priv->clientListStacking.clear ();
3295
priv->clientIdList.clear ();
3296
priv->clientIdListStacking.clear ();
3298
XChangeProperty (priv->dpy, priv->root,
3300
XA_WINDOW, 32, PropModeReplace,
3301
(unsigned char *) &priv->grabWindow, 1);
3302
XChangeProperty (priv->dpy, priv->root,
3303
Atoms::clientListStacking,
3304
XA_WINDOW, 32, PropModeReplace,
3305
(unsigned char *) &priv->grabWindow, 1);
3311
if ((unsigned int) n != priv->clientList.size ())
3313
priv->clientIdList.resize (n);
3314
priv->clientIdListStacking.resize (n);
3316
updateClientList = updateClientListStacking = true;
3319
priv->clientListStacking.clear ();
3321
foreach (CompWindow *w, priv->windows)
3322
if (isClientListWindow (w))
3323
priv->clientListStacking.push_back (w);
3325
/* clear clientList and copy clientListStacking into clientList */
3326
priv->clientList = priv->clientListStacking;
3328
/* sort clientList in mapping order */
3329
sort (priv->clientList.begin (), priv->clientList.end (),
3330
compareMappingOrder);
3332
/* make sure client id lists are up-to-date */
3333
for (int i = 0; i < n; i++)
3335
if (!updateClientList &&
3336
priv->clientIdList[i] != priv->clientList[i]->id ())
3338
updateClientList = true;
3341
priv->clientIdList[i] = priv->clientList[i]->id ();
3343
for (int i = 0; i < n; i++)
3345
if (!updateClientListStacking &&
3346
priv->clientIdListStacking[i] != priv->clientListStacking[i]->id ())
3348
updateClientListStacking = true;
3351
priv->clientIdListStacking[i] = priv->clientListStacking[i]->id ();
3354
if (updateClientList)
3355
XChangeProperty (priv->dpy, priv->root,
3357
XA_WINDOW, 32, PropModeReplace,
3358
(unsigned char *) &priv->clientIdList.at (0), n);
3360
if (updateClientListStacking)
3361
XChangeProperty (priv->dpy, priv->root,
3362
Atoms::clientListStacking,
3363
XA_WINDOW, 32, PropModeReplace,
3364
(unsigned char *) &priv->clientIdListStacking.at (0),
3368
const CompWindowVector &
3369
CompScreen::clientList (bool stackingOrder)
3371
return stackingOrder ? priv->clientListStacking : priv->clientList;
3375
CompScreen::toolkitAction (Atom toolkitAction,
3384
ev.type = ClientMessage;
3385
ev.xclient.window = window;
3386
ev.xclient.message_type = Atoms::toolkitAction;
3387
ev.xclient.format = 32;
3388
ev.xclient.data.l[0] = toolkitAction;
3389
ev.xclient.data.l[1] = eventTime;
3390
ev.xclient.data.l[2] = data0;
3391
ev.xclient.data.l[3] = data1;
3392
ev.xclient.data.l[4] = data2;
3394
XUngrabPointer (priv->dpy, CurrentTime);
3395
XUngrabKeyboard (priv->dpy, CurrentTime);
3397
XSendEvent (priv->dpy, priv->root, false,
3398
StructureNotifyMask, &ev);
3402
CompScreen::runCommand (CompString command)
3404
if (command.size () == 0)
3410
CompString env (priv->displayString);
3414
pos = env.find (':');
3415
if (pos != std::string::npos)
3417
if (env.find ('.', pos) != std::string::npos)
3419
env.erase (env.find ('.', pos));
3428
env.append (compPrintf (".%d", priv->screenNum));
3430
putenv (const_cast<char *> (env.c_str ()));
3432
exit (execl ("/bin/sh", "/bin/sh", "-c", command.c_str (), NULL));
3437
CompScreen::moveViewport (int tx, int ty, bool sync)
3441
tx = priv->vp.x () - tx;
3442
tx = MOD (tx, priv->vpSize.width ());
3443
tx -= priv->vp.x ();
3445
ty = priv->vp.y () - ty;
3446
ty = MOD (ty, priv->vpSize.height ());
3447
ty -= priv->vp.y ();
3452
priv->vp.setX (priv->vp.x () + tx);
3453
priv->vp.setY (priv->vp.y () + ty);
3458
foreach (CompWindow *w, priv->windows)
3460
if (w->onAllViewports ())
3463
pnt = w->getMovementForOffset (CompPoint (tx, ty));
3465
if (w->saveMask () & CWX)
3466
w->saveWc ().x += pnt.x ();
3468
if (w->saveMask () & CWY)
3469
w->saveWc ().y += pnt.y ();
3472
w->move (pnt.x (), pnt.y ());
3482
priv->setDesktopHints ();
3484
priv->setCurrentActiveWindowHistory (priv->vp.x (), priv->vp.y ());
3486
w = findWindow (priv->activeWindow);
3491
dvp = w->defaultViewport ();
3493
/* add window to current history if it's default viewport is
3494
still the current one. */
3495
if (priv->vp.x () == dvp.x () && priv->vp.y () == dvp.y ())
3496
priv->addToCurrentActiveWindowHistory (w->id ());
3502
PrivateScreen::addGroup (Window id)
3504
CompGroup *group = new CompGroup ();
3509
priv->groups.push_back (group);
3515
PrivateScreen::removeGroup (CompGroup *group)
3521
std::list<CompGroup *>::iterator it =
3522
std::find (priv->groups.begin (), priv->groups.end (), group);
3524
if (it != priv->groups.end ())
3526
priv->groups.erase (it);
3533
PrivateScreen::findGroup (Window id)
3535
foreach (CompGroup *g, priv->groups)
3543
PrivateScreen::applyStartupProperties (CompWindow *window)
3545
CompStartupSequence *s = NULL;
3546
const char *startupId = window->startupId ();
3552
leader = screen->findWindow (window->clientLeader ());
3554
startupId = leader->startupId ();
3560
foreach (CompStartupSequence *ss, priv->startupSequences)
3564
id = sn_startup_sequence_get_id (ss->sequence);
3565
if (strcmp (id, startupId) == 0)
3573
window->priv->applyStartupProperties (s);
3577
CompScreen::sendWindowActivationRequest (Window id)
3581
xev.xclient.type = ClientMessage;
3582
xev.xclient.display = priv->dpy;
3583
xev.xclient.format = 32;
3585
xev.xclient.message_type = Atoms::winActive;
3586
xev.xclient.window = id;
3588
xev.xclient.data.l[0] = ClientTypePager;
3589
xev.xclient.data.l[1] = 0;
3590
xev.xclient.data.l[2] = 0;
3591
xev.xclient.data.l[3] = 0;
3592
xev.xclient.data.l[4] = 0;
3594
XSendEvent (priv->dpy, priv->root, false,
3595
SubstructureRedirectMask | SubstructureNotifyMask, &xev);
3599
PrivateScreen::enableEdge (int edge)
3601
priv->screenEdge[edge].count++;
3602
if (priv->screenEdge[edge].count == 1)
3603
XMapRaised (priv->dpy, priv->screenEdge[edge].id);
3607
PrivateScreen::disableEdge (int edge)
3609
priv->screenEdge[edge].count--;
3610
if (priv->screenEdge[edge].count == 0)
3611
XUnmapWindow (priv->dpy, priv->screenEdge[edge].id);
3615
PrivateScreen::getTopWindow ()
3617
/* return first window that has not been destroyed */
3618
for (CompWindowList::reverse_iterator rit = priv->windows.rbegin ();
3619
rit != priv->windows.rend (); rit++)
3621
if ((*rit)->id () > 1)
3622
return (*rit)->id ();
3629
CompScreen::outputDeviceForPoint (const CompPoint &point)
3631
return outputDeviceForPoint (point.x (), point.y ());
3635
CompScreen::outputDeviceForPoint (int x, int y)
3637
CompWindow::Geometry geom (x, y, 1, 1, 0);
3639
return outputDeviceForGeometry (geom);
3643
CompScreen::getCurrentOutputExtents ()
3645
return priv->outputDevs[priv->currentOutputDev];
3649
PrivateScreen::setNumberOfDesktops (unsigned int nDesktop)
3651
if (nDesktop < 1 || nDesktop >= 0xffffffff)
3654
if (nDesktop == priv->nDesktop)
3657
if (priv->currentDesktop >= nDesktop)
3658
priv->currentDesktop = nDesktop - 1;
3660
foreach (CompWindow *w, priv->windows)
3662
if (w->desktop () == 0xffffffff)
3665
if (w->desktop () >= nDesktop)
3666
w->setDesktop (nDesktop - 1);
3669
priv->nDesktop = nDesktop;
3671
priv->setDesktopHints ();
3675
PrivateScreen::setCurrentDesktop (unsigned int desktop)
3679
if (desktop >= priv->nDesktop)
3682
if (desktop == priv->currentDesktop)
3685
priv->currentDesktop = desktop;
3687
foreach (CompWindow *w, priv->windows)
3689
if (w->desktop () == 0xffffffff)
3692
if (w->desktop () == desktop)
3700
XChangeProperty (priv->dpy, priv->root, Atoms::currentDesktop,
3701
XA_CARDINAL, 32, PropModeReplace,
3702
(unsigned char *) &data, 1);
3706
CompScreen::getWorkareaForOutput (unsigned int outputNum) const
3708
return priv->outputDevs[outputNum].workArea ();
3712
CompScreen::outputChangeNotify ()
3713
WRAPABLE_HND_FUNC (16, outputChangeNotify)
3717
/* Returns default viewport for some window geometry. If the window spans
3718
more than one viewport the most appropriate viewport is returned. How the
3719
most appropriate viewport is computed can be made optional if necessary. It
3720
is currently computed as the viewport where the center of the window is
3723
CompScreen::viewportForGeometry (const CompWindow::Geometry& gm,
3724
CompPoint& viewport)
3729
rect.setWidth (rect.width () + (gm.border () * 2));
3730
rect.setHeight (rect.height () + (gm.border () * 2));
3732
offset = rect.centerX () < 0 ? -1 : 0;
3733
viewport.setX (priv->vp.x () + ((rect.centerX () / width ()) + offset) %
3734
priv->vpSize.width ());
3736
offset = rect.centerY () < 0 ? -1 : 0;
3737
viewport.setY (priv->vp.y () + ((rect.centerY () / height ()) + offset ) %
3738
priv->vpSize.height ());
3742
CompScreen::outputDeviceForGeometry (const CompWindow::Geometry& gm)
3744
int overlapAreas[priv->outputDevs.size ()];
3745
int highest, seen, highestScore;
3750
if (priv->outputDevs.size () == 1)
3753
strategy = priv->optionGetOverlappingOutputs ();
3755
if (strategy == CoreOptions::OverlappingOutputsSmartMode)
3757
int centerX, centerY;
3759
/* for smart mode, calculate the overlap of the whole rectangle
3760
with the output device rectangle */
3761
geomRect.setWidth (gm.width () + 2 * gm.border ());
3762
geomRect.setHeight (gm.height () + 2 * gm.border ());
3764
x = gm.x () % width ();
3765
centerX = (x + (geomRect.width () / 2));
3768
else if (centerX > width ())
3772
y = gm.y () % height ();
3773
centerY = (y + (geomRect.height () / 2));
3776
else if (centerY > height ())
3782
/* for biggest/smallest modes, only use the window center to determine
3783
the correct output device */
3784
x = (gm.x () + (gm.width () / 2) + gm.border ()) % width ();
3787
y = (gm.y () + (gm.height () / 2) + gm.border ()) % height ();
3791
geomRect.setGeometry (x, y, 1, 1);
3794
/* get amount of overlap on all output devices */
3795
for (i = 0; i < priv->outputDevs.size (); i++)
3797
CompRect overlap = priv->outputDevs[i] & geomRect;
3798
overlapAreas[i] = overlap.area ();
3801
/* find output with largest overlap */
3802
for (i = 0, highest = 0, highestScore = 0;
3803
i < priv->outputDevs.size (); i++)
3805
if (overlapAreas[i] > highestScore)
3808
highestScore = overlapAreas[i];
3812
/* look if the highest score is unique */
3813
for (i = 0, seen = 0; i < priv->outputDevs.size (); i++)
3814
if (overlapAreas[i] == highestScore)
3819
/* it's not unique, select one output of the matching ones and use the
3820
user preferred strategy for that */
3821
unsigned int currentSize, bestOutputSize;
3825
(strategy != CoreOptions::OverlappingOutputsPreferSmallerOutput);
3830
bestOutputSize = UINT_MAX;
3832
for (i = 0, highest = 0; i < priv->outputDevs.size (); i++)
3833
if (overlapAreas[i] == highestScore)
3837
currentSize = priv->outputDevs[i].area ();
3840
bestFit = (currentSize > bestOutputSize);
3842
bestFit = (currentSize < bestOutputSize);
3847
bestOutputSize = currentSize;
3856
CompScreen::defaultIcon () const
3858
return priv->defaultIcon;
3862
CompScreen::updateDefaultIcon ()
3864
CompString file = priv->optionGetDefaultIcon ();
3865
CompString pname = "";
3869
if (priv->defaultIcon)
3871
delete priv->defaultIcon;
3872
priv->defaultIcon = NULL;
3875
if (!readImageFromFile (file, pname, size, data))
3878
priv->defaultIcon = new CompIcon (screen, size.width (), size.height ());
3880
memcpy (priv->defaultIcon->data (), data,
3881
size.width () * size.height () * sizeof (CARD32));
3889
PrivateScreen::setCurrentActiveWindowHistory (int x, int y)
3893
for (i = 0; i < ACTIVE_WINDOW_HISTORY_NUM; i++)
3895
if (priv->history[i].x == x && priv->history[i].y == y)
3897
priv->currentHistory = i;
3902
for (i = 1; i < ACTIVE_WINDOW_HISTORY_NUM; i++)
3903
if (priv->history[i].activeNum < priv->history[min].activeNum)
3906
priv->currentHistory = min;
3908
priv->history[min].activeNum = priv->activeNum;
3909
priv->history[min].x = x;
3910
priv->history[min].y = y;
3912
memset (priv->history[min].id, 0, sizeof (priv->history[min].id));
3916
PrivateScreen::addToCurrentActiveWindowHistory (Window id)
3918
CompActiveWindowHistory *history = &priv->history[priv->currentHistory];
3919
Window tmp, next = id;
3922
/* walk and move history */
3923
for (i = 0; i < ACTIVE_WINDOW_HISTORY_SIZE; i++)
3925
tmp = history->id[i];
3926
history->id[i] = next;
3929
/* we're done when we find an old instance or an empty slot */
3930
if (tmp == id || tmp == None)
3934
history->activeNum = priv->activeNum;
3938
ScreenInterface::enterShowDesktopMode ()
3939
WRAPABLE_DEF (enterShowDesktopMode)
3942
ScreenInterface::leaveShowDesktopMode (CompWindow *window)
3943
WRAPABLE_DEF (leaveShowDesktopMode, window)
3946
ScreenInterface::outputChangeNotify ()
3947
WRAPABLE_DEF (outputChangeNotify)
3950
ScreenInterface::addSupportedAtoms (std::vector<Atom>& atoms)
3951
WRAPABLE_DEF (addSupportedAtoms, atoms)
3961
CompScreen::xkbEvent ()
3963
return priv->xkbEvent;
3967
CompScreen::warpPointer (int dx,
3975
if (pointerX >= width ())
3976
pointerX = width () - 1;
3977
else if (pointerX < 0)
3980
if (pointerY >= height ())
3981
pointerY = height () - 1;
3982
else if (pointerY < 0)
3985
XWarpPointer (priv->dpy,
3988
pointerX, pointerY);
3990
XSync (priv->dpy, false);
3992
while (XCheckMaskEvent (priv->dpy,
4000
lastPointerX = pointerX;
4001
lastPointerY = pointerY;
4006
CompScreen::windows ()
4008
return priv->windows;
4012
CompScreen::getCurrentTime ()
4016
XChangeProperty (priv->dpy, priv->grabWindow,
4017
XA_PRIMARY, XA_STRING, 8,
4018
PropModeAppend, NULL, 0);
4019
XWindowEvent (priv->dpy, priv->grabWindow,
4023
return event.xproperty.time;
4027
CompScreen::selectionWindow ()
4029
return priv->wmSnSelectionWindow;
4033
CompScreen::screenNum ()
4035
return priv->screenNum;
4045
CompScreen::vpSize ()
4047
return priv->vpSize;
4051
CompScreen::desktopWindowCount ()
4053
return priv->desktopWindowCount;
4057
CompScreen::activeNum () const
4059
return priv->activeNum;
4062
CompOutput::vector &
4063
CompScreen::outputDevs ()
4065
return priv->outputDevs;
4069
CompScreen::currentOutputDev () const
4071
return priv->outputDevs [priv->currentOutputDev];
4075
CompScreen::workArea () const
4077
return priv->workArea;
4081
CompScreen::currentDesktop ()
4083
return priv->currentDesktop;
4087
CompScreen::nDesktop ()
4089
return priv->nDesktop;
4092
CompActiveWindowHistory *
4093
CompScreen::currentHistory ()
4095
return &priv->history[priv->currentHistory];
4099
CompScreen::shouldSerializePlugins ()
4101
return priv->optionGetDoSerialize ();
4105
PrivateScreen::removeDestroyed ()
4107
while (pendingDestroys)
4109
foreach (CompWindow *w, windows)
4111
if (w->destroyed ())
4123
CompScreen::region () const
4125
return priv->region;
4129
CompScreen::hasOverlappingOutputs ()
4131
return priv->hasOverlappingOutputs;
4135
CompScreen::fullscreenOutput ()
4137
return priv->fullscreenOutput;
4142
CompScreen::attrib ()
4144
return priv->attrib;
4147
std::vector<XineramaScreenInfo> &
4148
CompScreen::screenInfo ()
4150
return priv->screenInfo;
4154
PrivateScreen::createFailed ()
4156
return !screenInitalized;
4159
CompScreen::CompScreen ():
4160
PluginClassStorage (screenPluginClassIndices),
4164
CompOption::Value::Vector vList;
4165
CompPlugin *corePlugin;
4167
priv = new PrivateScreen (this);
4170
screenInitalized = true;
4172
corePlugin = CompPlugin::load ("core");
4175
compLogMessage ("core", CompLogLevelFatal,
4176
"Couldn't load core plugin");
4177
screenInitalized = false;
4180
if (!CompPlugin::push (corePlugin))
4182
compLogMessage ("core", CompLogLevelFatal,
4183
"Couldn't activate core plugin");
4184
screenInitalized = false;
4187
p.uval = CORE_ABIVERSION;
4188
storeValue ("core_ABI", p);
4190
vList.push_back ("core");
4192
priv->plugin.set (CompOption::TypeString, vList);
4196
CompScreen::init (const char *name)
4203
Window newWmSnOwner = None;
4205
Time wmSnTimestamp = 0;
4207
XSetWindowAttributes attr;
4208
Window currentWmSnOwner;
4210
static char data = 0;
4214
XVisualInfo *visinfo;
4215
Window rootReturn, parentReturn;
4217
unsigned int nchildren;
4219
XSetWindowAttributes attrib;
4221
dpy = priv->dpy = XOpenDisplay (name);
4224
compLogMessage ("core", CompLogLevelFatal,
4225
"Couldn't open display %s", XDisplayName (name));
4229
// priv->connection = XGetXCBConnection (priv->dpy);
4231
snprintf (priv->displayString, 255, "DISPLAY=%s",
4232
DisplayString (dpy));
4235
XSynchronize (priv->dpy, true);
4238
Atoms::init (priv->dpy);
4240
XSetErrorHandler (errorHandler);
4242
priv->snDisplay = sn_display_new (dpy, NULL, NULL);
4243
if (!priv->snDisplay)
4248
if (!XSyncQueryExtension (dpy, &priv->syncEvent, &priv->syncError))
4250
compLogMessage ("core", CompLogLevelFatal,
4251
"No sync extension");
4255
priv->randrExtension = XRRQueryExtension (dpy, &priv->randrEvent,
4258
priv->shapeExtension = XShapeQueryExtension (dpy, &priv->shapeEvent,
4261
priv->xkbExtension = XkbQueryExtension (dpy, &xkbOpcode,
4262
&priv->xkbEvent, &priv->xkbError,
4264
if (priv->xkbExtension)
4266
XkbSelectEvents (dpy, XkbUseCoreKbd,
4267
XkbBellNotifyMask | XkbStateNotifyMask,
4272
compLogMessage ("core", CompLogLevelFatal,
4273
"No XKB extension");
4275
priv->xkbEvent = priv->xkbError = -1;
4278
priv->xineramaExtension = XineramaQueryExtension (dpy,
4279
&priv->xineramaEvent,
4280
&priv->xineramaError);
4282
priv->updateScreenInfo ();
4284
priv->escapeKeyCode = XKeysymToKeycode (dpy, XStringToKeysym ("Escape"));
4285
priv->returnKeyCode = XKeysymToKeycode (dpy, XStringToKeysym ("Return"));
4287
sprintf (buf, "WM_S%d", DefaultScreen (dpy));
4288
wmSnAtom = XInternAtom (dpy, buf, 0);
4290
currentWmSnOwner = XGetSelectionOwner (dpy, wmSnAtom);
4292
if (currentWmSnOwner != None)
4294
if (!replaceCurrentWm)
4296
compLogMessage ("core", CompLogLevelError,
4297
"Screen %d on display \"%s\" already "
4298
"has a window manager; try using the "
4299
"--replace option to replace the current "
4301
DefaultScreen (dpy), DisplayString (dpy));
4306
XSelectInput (dpy, currentWmSnOwner, StructureNotifyMask);
4309
root = XRootWindow (dpy, DefaultScreen (dpy));
4311
attr.override_redirect = true;
4312
attr.event_mask = PropertyChangeMask;
4315
XCreateWindow (dpy, root, -100, -100, 1, 1, 0,
4316
CopyFromParent, CopyFromParent,
4318
CWOverrideRedirect | CWEventMask,
4321
XChangeProperty (dpy, newWmSnOwner, Atoms::wmName, Atoms::utf8String, 8,
4322
PropModeReplace, (unsigned char *) PACKAGE,
4325
XWindowEvent (dpy, newWmSnOwner, PropertyChangeMask, &event);
4327
wmSnTimestamp = event.xproperty.time;
4329
XSetSelectionOwner (dpy, wmSnAtom, newWmSnOwner, wmSnTimestamp);
4331
if (XGetSelectionOwner (dpy, wmSnAtom) != newWmSnOwner)
4333
compLogMessage ("core", CompLogLevelError,
4334
"Could not acquire window manager "
4335
"selection on screen %d display \"%s\"",
4336
DefaultScreen (dpy), DisplayString (dpy));
4338
XDestroyWindow (dpy, newWmSnOwner);
4343
/* Send client message indicating that we are now the window manager */
4344
event.xclient.type = ClientMessage;
4345
event.xclient.window = root;
4346
event.xclient.message_type = Atoms::manager;
4347
event.xclient.format = 32;
4348
event.xclient.data.l[0] = wmSnTimestamp;
4349
event.xclient.data.l[1] = wmSnAtom;
4350
event.xclient.data.l[2] = 0;
4351
event.xclient.data.l[3] = 0;
4352
event.xclient.data.l[4] = 0;
4354
XSendEvent (dpy, root, FALSE, StructureNotifyMask, &event);
4356
/* Wait for old window manager to go away */
4357
if (currentWmSnOwner != None)
4360
XWindowEvent (dpy, currentWmSnOwner, StructureNotifyMask, &event);
4361
} while (event.type != DestroyNotify);
4364
modHandler->updateModifierMappings ();
4366
CompScreen::checkForError (dpy);
4370
XSelectInput (dpy, root,
4371
SubstructureRedirectMask |
4372
SubstructureNotifyMask |
4373
StructureNotifyMask |
4374
PropertyChangeMask |
4384
/* We need to register for EnterWindowMask |
4385
* ButtonPressMask | FocusChangeMask on other
4386
* root windows as well because focus happens
4387
* on a display level and we need to check
4388
* if the screen we are running on lost focus */
4390
for (int i = 0; i <= ScreenCount (dpy) - 1; i++)
4392
Window rt = XRootWindow (dpy, i);
4397
XSelectInput (dpy, rt,
4399
SubstructureNotifyMask);
4402
if (CompScreen::checkForError (dpy))
4404
compLogMessage ("core", CompLogLevelError,
4405
"Another window manager is "
4406
"already running on screen: %d", DefaultScreen (dpy));
4408
XUngrabServer (dpy);
4412
/* We only care about windows we're not going to
4413
* get a CreateNotify for later, so query the tree
4414
* here, init plugin screens, and then init windows */
4416
XQueryTree (dpy, root,
4417
&rootReturn, &parentReturn,
4418
&children, &nchildren);
4420
for (i = 0; i < SCREEN_EDGE_NUM; i++)
4422
priv->screenEdge[i].id = None;
4423
priv->screenEdge[i].count = 0;
4426
priv->screenNum = DefaultScreen (dpy);
4427
priv->colormap = DefaultColormap (dpy, priv->screenNum);
4430
priv->snContext = sn_monitor_context_new (priv->snDisplay, priv->screenNum,
4431
compScreenSnEvent, this, NULL);
4433
priv->wmSnSelectionWindow = newWmSnOwner;
4434
priv->wmSnAtom = wmSnAtom;
4435
priv->wmSnTimestamp = wmSnTimestamp;
4437
if (!XGetWindowAttributes (dpy, priv->root, &priv->attrib))
4440
priv->workArea.setWidth (priv->attrib.width);
4441
priv->workArea.setHeight (priv->attrib.height);
4443
priv->grabWindow = None;
4445
templ.visualid = XVisualIDFromVisual (priv->attrib.visual);
4447
visinfo = XGetVisualInfo (dpy, VisualIDMask, &templ, &nvisinfo);
4450
compLogMessage ("core", CompLogLevelFatal,
4451
"Couldn't get visual info for default visual");
4455
black.red = black.green = black.blue = 0;
4457
if (!XAllocColor (dpy, priv->colormap, &black))
4459
compLogMessage ("core", CompLogLevelFatal,
4460
"Couldn't allocate color");
4465
bitmap = XCreateBitmapFromData (dpy, priv->root, &data, 1, 1);
4468
compLogMessage ("core", CompLogLevelFatal,
4469
"Couldn't create bitmap");
4474
priv->invisibleCursor = XCreatePixmapCursor (dpy, bitmap, bitmap,
4475
&black, &black, 0, 0);
4476
if (!priv->invisibleCursor)
4478
compLogMessage ("core", CompLogLevelFatal,
4479
"Couldn't create invisible cursor");
4484
XFreePixmap (dpy, bitmap);
4485
XFreeColors (dpy, priv->colormap, &black.pixel, 1, 0);
4489
priv->reshape (priv->attrib.width, priv->attrib.height);
4491
priv->detectOutputDevices ();
4492
priv->updateOutputDevices ();
4494
priv->getDesktopHints ();
4496
attrib.override_redirect = 1;
4497
attrib.event_mask = PropertyChangeMask;
4499
priv->grabWindow = XCreateWindow (dpy, priv->root, -100, -100, 1, 1, 0,
4500
CopyFromParent, InputOnly, CopyFromParent,
4501
CWOverrideRedirect | CWEventMask,
4503
XMapWindow (dpy, priv->grabWindow);
4505
for (i = 0; i < SCREEN_EDGE_NUM; i++)
4507
long xdndVersion = 3;
4509
priv->screenEdge[i].id = XCreateWindow (dpy, priv->root,
4510
-100, -100, 1, 1, 0,
4511
CopyFromParent, InputOnly,
4516
XChangeProperty (dpy, priv->screenEdge[i].id, Atoms::xdndAware,
4517
XA_ATOM, 32, PropModeReplace,
4518
(unsigned char *) &xdndVersion, 1);
4520
XSelectInput (dpy, priv->screenEdge[i].id,
4528
priv->updateScreenEdges ();
4530
priv->setDesktopHints ();
4531
priv->setSupportingWmCheck ();
4532
updateSupportedWmHints ();
4534
priv->normalCursor = XCreateFontCursor (dpy, XC_left_ptr);
4535
priv->busyCursor = XCreateFontCursor (dpy, XC_watch);
4537
XDefineCursor (dpy, priv->root, priv->normalCursor);
4539
XUngrabServer (dpy);
4542
priv->setAudibleBell (priv->optionGetAudibleBell ());
4544
priv->pingTimer.setTimes (priv->optionGetPingDelay (),
4545
priv->optionGetPingDelay () + 500);
4547
priv->pingTimer.start ();
4549
priv->addScreenActions ();
4551
/* Need to set a default here so that the value isn't uninitialized
4552
* when loading plugins FIXME: Should find a way to initialize options
4553
* first and then set this value, or better yet, tie this value directly
4555
priv->vpSize.setWidth (priv->optionGetHsize ());
4556
priv->vpSize.setHeight (priv->optionGetVsize ());
4558
priv->initialized = true;
4560
/* TODO: Bailout properly when screenInitPlugins fails
4561
* TODO: It would be nicer if this line could mean
4562
* "init all the screens", but unfortunately it only inits
4563
* plugins loaded on the command line screen's and then
4564
* we need to call updatePlugins () to init the remaining
4565
* screens from option changes */
4566
assert (CompPlugin::screenInitPlugins (this));
4568
/* The active plugins list might have been changed - load any
4571
priv->vpSize.setWidth (priv->optionGetHsize ());
4572
priv->vpSize.setHeight (priv->optionGetVsize ());
4574
if (priv->dirtyPluginList)
4575
priv->updatePlugins ();
4577
/* Start initializing windows here */
4579
for (unsigned int i = 0; i < nchildren; i++)
4581
XWindowAttributes attrib;
4583
/* Failure means the window has been destroyed, but
4584
* still add it to the window list anyways since we
4585
* will soon handle the DestroyNotify event for it
4586
* and in between CreateNotify time and DestroyNotify
4587
* time there might be ConfigureRequests asking us
4588
* to stack windows relative to it
4591
if (!XGetWindowAttributes (screen->dpy (), children[i], &attrib))
4592
priv->setDefaultWindowAttributes (&attrib);
4594
CoreWindow *cw = new CoreWindow (children[i]);
4598
cw->manage (i ? children[i - 1] : 0, attrib);
4605
/* enforce restack on all windows */
4607
for (CompWindowList::reverse_iterator rit = priv->windows.rbegin ();
4608
rit != priv->windows.rend (); rit++)
4609
children[i++] = (*rit)->id ();
4611
XRestackWindows (dpy, children, i);
4615
foreach (CompWindow *w, priv->windows)
4617
if (w->isViewable ())
4618
w->priv->activeNum = priv->activeNum++;
4621
XGetInputFocus (dpy, &focus, &revertTo);
4623
/* move input focus to root window so that we get a FocusIn event when
4624
moving it to the default window */
4625
XSetInputFocus (dpy, priv->root, RevertToPointerRoot, CurrentTime);
4627
if (focus == None || focus == PointerRoot)
4629
focusDefaultWindow ();
4635
w = findWindow (focus);
4637
w->moveInputFocusTo ();
4639
focusDefaultWindow ();
4645
CompScreen::~CompScreen ()
4649
priv->removeAllSequences ();
4651
while (!priv->windows.empty ())
4652
delete priv->windows.front ();
4654
while ((p = CompPlugin::pop ()))
4655
CompPlugin::unload (p);
4657
XUngrabKey (priv->dpy, AnyKey, AnyModifier, priv->root);
4659
priv->initialized = false;
4661
for (int i = 0; i < SCREEN_EDGE_NUM; i++)
4662
XDestroyWindow (priv->dpy, priv->screenEdge[i].id);
4664
XDestroyWindow (priv->dpy, priv->grabWindow);
4666
if (priv->defaultIcon)
4667
delete priv->defaultIcon;
4669
XFreeCursor (priv->dpy, priv->invisibleCursor);
4671
if (priv->desktopHintData)
4672
free (priv->desktopHintData);
4674
if (priv->snContext)
4675
sn_monitor_context_unref (priv->snContext);
4677
if (priv->snDisplay)
4678
sn_display_unref (priv->snDisplay);
4680
XSync (priv->dpy, False);
4681
XCloseDisplay (priv->dpy);
4688
PrivateScreen::PrivateScreen (CompScreen *screen) :
4691
lastFileWatchHandle (1),
4693
lastWatchFdHandle (1),
4699
autoRaiseWindow (0),
4702
dirtyPluginList (true),
4711
desktopWindowCount (0),
4715
currentOutputDev (0),
4716
hasOverlappingOutputs (false),
4719
startupSequences (0),
4720
startupSequenceTimer (),
4727
pendingDestroys (0),
4728
showingDesktopMask (0),
4729
desktopHintData (0),
4730
desktopHintSize (0),
4733
gettimeofday (&lastTimeout, 0);
4735
pingTimer.setCallback (
4736
boost::bind (&PrivateScreen::handlePingTimeout, this));
4738
startupSequenceTimer.setCallback (
4739
boost::bind (&PrivateScreen::handleStartupSequenceTimeout, this));
4740
startupSequenceTimer.setTimes (1000, 1500);
4742
optionSetCloseWindowKeyInitiate (CompScreen::closeWin);
4743
optionSetCloseWindowButtonInitiate (CompScreen::closeWin);
4744
optionSetRaiseWindowKeyInitiate (CompScreen::raiseWin);
4745
optionSetRaiseWindowButtonInitiate (CompScreen::raiseWin);
4746
optionSetLowerWindowKeyInitiate (CompScreen::lowerWin);
4747
optionSetLowerWindowButtonInitiate (CompScreen::lowerWin);
4749
optionSetUnmaximizeWindowKeyInitiate (CompScreen::unmaximizeWin);
4751
optionSetMinimizeWindowKeyInitiate (CompScreen::minimizeWin);
4752
optionSetMinimizeWindowButtonInitiate (CompScreen::minimizeWin);
4753
optionSetMaximizeWindowKeyInitiate (CompScreen::maximizeWin);
4754
optionSetMaximizeWindowHorizontallyKeyInitiate (
4755
CompScreen::maximizeWinHorizontally);
4756
optionSetMaximizeWindowVerticallyKeyInitiate (
4757
CompScreen::maximizeWinVertically);
4759
optionSetWindowMenuKeyInitiate (CompScreen::windowMenu);
4760
optionSetWindowMenuButtonInitiate (CompScreen::windowMenu);
4762
optionSetShowDesktopKeyInitiate (CompScreen::showDesktop);
4763
optionSetShowDesktopEdgeInitiate (CompScreen::showDesktop);
4765
optionSetToggleWindowMaximizedKeyInitiate (CompScreen::toggleWinMaximized);
4766
optionSetToggleWindowMaximizedButtonInitiate (CompScreen::toggleWinMaximized);
4768
optionSetToggleWindowMaximizedHorizontallyKeyInitiate (
4769
CompScreen::toggleWinMaximizedHorizontally);
4770
optionSetToggleWindowMaximizedVerticallyKeyInitiate (
4771
CompScreen::toggleWinMaximizedVertically);
4773
optionSetToggleWindowShadedKeyInitiate (CompScreen::shadeWin);
4776
PrivateScreen::~PrivateScreen ()