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 SPECIAL, INDIRECT OR
18
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23
* Author: David Reveman <davidr@novell.com>
27
# include "../config.h"
37
#include <X11/keysymdef.h>
40
#include <X11/Xatom.h>
41
#include <X11/extensions/Xcomposite.h>
42
#include <X11/extensions/Xrandr.h>
43
/* #include <X11/extensions/Xevie.h> */
44
#include <X11/extensions/shape.h>
48
static unsigned int virtualModMask[] = {
49
CompAltMask, CompMetaMask, CompSuperMask, CompHyperMask,
50
CompModeSwitchMask, CompNumLockMask, CompScrollLockMask
53
typedef struct _CompTimeout {
54
struct _CompTimeout *next;
57
CallBackProc callBack;
59
CompTimeoutHandle handle;
62
static CompTimeout *timeouts = 0;
63
static struct timeval lastTimeout;
64
static CompTimeoutHandle lastTimeoutHandle = 1;
66
#define CLICK_TO_FOCUS_DEFAULT TRUE
68
#define AUTORAISE_DEFAULT TRUE
70
#define AUTORAISE_DELAY_DEFAULT 1000
71
#define AUTORAISE_DELAY_MIN 0
72
#define AUTORAISE_DELAY_MAX 10000
74
#define NUM_OPTIONS(d) (sizeof ((d)->opt) / sizeof (CompOption))
76
static char *textureFilter[] = { "Fast", "Good", "Best" };
78
#define NUM_TEXTURE_FILTER (sizeof (textureFilter) / sizeof (textureFilter[0]))
80
CompDisplay *compDisplays = 0;
82
static CompDisplay compDisplay;
84
static char *displayPrivateIndices = 0;
85
static int displayPrivateLen = 0;
88
reallocDisplayPrivate (int size,
91
CompDisplay *d = compDisplays;
96
privates = realloc (d->privates, size * sizeof (CompPrivate));
100
d->privates = (CompPrivate *) privates;
107
allocateDisplayPrivateIndex (void)
109
return allocatePrivateIndex (&displayPrivateLen,
110
&displayPrivateIndices,
111
reallocDisplayPrivate,
116
freeDisplayPrivateIndex (int index)
118
freePrivateIndex (displayPrivateLen, displayPrivateIndices, index);
122
compDisplayInitOptions (CompDisplay *display,
129
o = &display->opt[COMP_DISPLAY_OPTION_ACTIVE_PLUGINS];
130
o->name = "active_plugins";
131
o->shortDesc = "Active Plugins";
132
o->longDesc = "List of currently active plugins";
133
o->type = CompOptionTypeList;
134
o->value.list.type = CompOptionTypeString;
135
o->value.list.nValue = nPlugin;
136
o->value.list.value = malloc (sizeof (CompOptionValue) * nPlugin);
137
for (i = 0; i < nPlugin; i++)
138
o->value.list.value[i].s = strdup (plugin[i]);
139
o->rest.s.string = 0;
140
o->rest.s.nString = 0;
142
display->dirtyPluginList = TRUE;
144
o = &display->opt[COMP_DISPLAY_OPTION_TEXTURE_FILTER];
145
o->name = "texture_filter";
146
o->shortDesc = "Texture Filter";
147
o->longDesc = "Texture filtering";
148
o->type = CompOptionTypeString;
149
o->value.s = strdup (defaultTextureFilter);
150
o->rest.s.string = textureFilter;
151
o->rest.s.nString = NUM_TEXTURE_FILTER;
153
o = &display->opt[COMP_DISPLAY_OPTION_CLICK_TO_FOCUS];
154
o->name = "click_to_focus";
155
o->shortDesc = "Click To Focus";
156
o->longDesc = "Click on window moves input focus to it";
157
o->type = CompOptionTypeBool;
158
o->value.b = CLICK_TO_FOCUS_DEFAULT;
160
o = &display->opt[COMP_DISPLAY_OPTION_AUTORAISE];
161
o->name = "autoraise";
162
o->shortDesc = "Auto-Raise";
163
o->longDesc = "Raise selected windows after interval";
164
o->type = CompOptionTypeBool;
165
o->value.b = AUTORAISE_DEFAULT;
167
o = &display->opt[COMP_DISPLAY_OPTION_AUTORAISE_DELAY];
168
o->name = "autoraise_delay";
169
o->shortDesc = "Auto-Raise Delay";
170
o->longDesc = "Interval before raising selected windows";
171
o->type = CompOptionTypeInt;
172
o->value.i = AUTORAISE_DELAY_DEFAULT;
173
o->rest.i.min = AUTORAISE_DELAY_MIN;
174
o->rest.i.max = AUTORAISE_DELAY_MAX;
178
compGetDisplayOptions (CompDisplay *display,
181
*count = NUM_OPTIONS (display);
186
setDisplayOption (CompDisplay *display,
188
CompOptionValue *value)
193
o = compFindOption (display->opt, NUM_OPTIONS (display), name, &index);
198
case COMP_DISPLAY_OPTION_ACTIVE_PLUGINS:
199
if (compSetOptionList (o, value))
201
display->dirtyPluginList = TRUE;
205
case COMP_DISPLAY_OPTION_TEXTURE_FILTER:
206
if (compSetStringOption (o, value))
210
for (s = display->screens; s; s = s->next)
213
if (strcmp (o->value.s, "Fast") == 0)
214
display->textureFilter = GL_NEAREST;
216
display->textureFilter = GL_LINEAR;
221
case COMP_DISPLAY_OPTION_CLICK_TO_FOCUS:
222
if (compSetBoolOption (o, value))
225
case COMP_DISPLAY_OPTION_AUTORAISE:
226
if (compSetBoolOption (o, value))
229
case COMP_DISPLAY_OPTION_AUTORAISE_DELAY:
230
if (compSetIntOption (o, value))
240
setDisplayOptionForPlugin (CompDisplay *display,
243
CompOptionValue *value)
247
p = findActivePlugin (plugin);
248
if (p && p->vTable->setDisplayOption)
249
return (*p->vTable->setDisplayOption) (display, name, value);
255
initPluginForDisplay (CompPlugin *p,
258
return (*p->vTable->initDisplay) (p, d);
262
finiPluginForDisplay (CompPlugin *p,
265
(*p->vTable->finiDisplay) (p, d);
269
updatePlugins (CompDisplay *d)
272
CompPlugin *p, **pop = 0;
275
d->dirtyPluginList = FALSE;
277
o = &d->opt[COMP_DISPLAY_OPTION_ACTIVE_PLUGINS];
278
for (i = 0; i < d->plugin.list.nValue && i < o->value.list.nValue; i++)
280
if (strcmp (d->plugin.list.value[i].s, o->value.list.value[i].s))
284
nPop = d->plugin.list.nValue - i;
288
pop = malloc (sizeof (CompPlugin *) * nPop);
291
(*d->setDisplayOption) (d, o->name, &d->plugin);
296
for (j = 0; j < nPop; j++)
298
pop[j] = popPlugin ();
299
d->plugin.list.nValue--;
300
free (d->plugin.list.value[d->plugin.list.nValue].s);
303
for (; i < o->value.list.nValue; i++)
306
for (j = 0; j < nPop; j++)
308
if (pop[j] && strcmp (pop[j]->vTable->name,
309
o->value.list.value[i].s) == 0)
311
if (pushPlugin (pop[j]))
322
p = loadPlugin (o->value.list.value[i].s);
335
CompOptionValue *value;
337
value = realloc (d->plugin.list.value, sizeof (CompOption) *
338
(d->plugin.list.nValue + 1));
341
value[d->plugin.list.nValue].s = strdup (p->vTable->name);
343
d->plugin.list.value = value;
344
d->plugin.list.nValue++;
354
for (j = 0; j < nPop; j++)
357
unloadPlugin (pop[j]);
363
(*d->setDisplayOption) (d, o->name, &d->plugin);
367
addTimeout (CompTimeout *timeout)
369
CompTimeout *p = 0, *t;
371
for (t = timeouts; t; t = t->next)
373
if (timeout->time < t->left)
380
timeout->left = timeout->time;
389
compAddTimeout (int time,
390
CallBackProc callBack,
393
CompTimeout *timeout;
395
timeout = malloc (sizeof (CompTimeout));
399
timeout->time = time;
400
timeout->callBack = callBack;
401
timeout->closure = closure;
402
timeout->handle = lastTimeoutHandle++;
404
if (lastTimeoutHandle == MAXSHORT)
405
lastTimeoutHandle = 1;
408
gettimeofday (&lastTimeout, 0);
410
addTimeout (timeout);
412
return timeout->handle;
416
compRemoveTimeout (CompTimeoutHandle handle)
418
CompTimeout *p = 0, *t;
420
for (t = timeouts; t; t = t->next)
422
if (t->handle == handle)
439
#define TIMEVALDIFF(tv1, tv2) \
440
((tv1)->tv_sec == (tv2)->tv_sec || (tv1)->tv_usec >= (tv2)->tv_usec) ? \
441
((((tv1)->tv_sec - (tv2)->tv_sec) * 1000000) + \
442
((tv1)->tv_usec - (tv2)->tv_usec)) / 1000 : \
443
((((tv1)->tv_sec - 1 - (tv2)->tv_sec) * 1000000) + \
444
(1000000 + (tv1)->tv_usec - (tv2)->tv_usec)) / 1000
447
getTimeToNextRedraw (CompScreen *s,
448
struct timeval *lastTv,
453
static int timeMult = 1;
455
gettimeofday (&tv, 0);
457
diff = TIMEVALDIFF (&tv, lastTv);
464
s->redrawTime = s->optimalRedrawTime;
470
if (diff > s->redrawTime)
472
if (s->frameStatus > 0)
475
next = s->optimalRedrawTime * (timeMult + 1);
479
if (s->frameStatus < -1)
482
s->redrawTime = diff = next;
486
else if (diff < s->redrawTime)
488
if (s->frameStatus < 0)
493
next = s->optimalRedrawTime * (timeMult - 1);
497
if (s->frameStatus > 4)
500
s->redrawTime = next;
507
if (diff > s->redrawTime)
510
return s->redrawTime - diff;
514
findWindowAt (CompDisplay *d,
522
for (s = d->screens; s; s = s->next)
524
if (s->root == root && s->maxGrab == 0)
526
for (w = s->reverseWindows; w; w = w->prev)
528
if (x >= w->attrib.x &&
530
x < w->attrib.x + w->width &&
531
y < w->attrib.y + w->height)
541
translateToRootWindow (CompDisplay *d,
546
for (s = d->screens; s; s = s->next)
548
if (s->root == child || s->grabWindow == child)
556
updateModifierMappings (CompDisplay *d)
558
XModifierKeymap *modmap;
559
unsigned int modMask[CompModNum];
560
int i, minKeycode, maxKeycode, keysymsPerKeycode = 0;
562
for (i = 0; i < CompModNum; i++)
565
XDisplayKeycodes (d->display, &minKeycode, &maxKeycode);
566
XGetKeyboardMapping (d->display, minKeycode, (maxKeycode - minKeycode + 1),
569
modmap = XGetModifierMapping (d->display);
570
if (modmap && modmap->max_keypermod > 0)
572
static int maskTable[] = {
573
ShiftMask, LockMask, ControlMask, Mod1Mask,
574
Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
577
int index, size, mask;
579
size = (sizeof (maskTable) / sizeof (int)) * modmap->max_keypermod;
581
for (i = 0; i < size; i++)
583
if (!modmap->modifiermap[i])
589
keysym = XKeycodeToKeysym (d->display,
590
modmap->modifiermap[i],
592
} while (!keysym && index < keysymsPerKeycode);
596
mask = maskTable[i / modmap->max_keypermod];
598
if (keysym == XK_Alt_L ||
601
modMask[CompModAlt] |= mask;
603
else if (keysym == XK_Meta_L ||
606
modMask[CompModMeta] |= mask;
608
else if (keysym == XK_Super_L ||
609
keysym == XK_Super_R)
611
modMask[CompModSuper] |= mask;
613
else if (keysym == XK_Hyper_L ||
614
keysym == XK_Hyper_R)
616
modMask[CompModHyper] |= mask;
618
else if (keysym == XK_Mode_switch)
620
modMask[CompModModeSwitch] |= mask;
622
else if (keysym == XK_Scroll_Lock)
624
modMask[CompModScrollLock] |= mask;
626
else if (keysym == XK_Num_Lock)
628
modMask[CompModNumLock] |= mask;
634
XFreeModifiermap (modmap);
636
for (i = 0; i < CompModNum; i++)
639
modMask[i] = CompNoMask;
642
if (memcmp (modMask, d->modMask, sizeof (modMask)))
646
memcpy (d->modMask, modMask, sizeof (modMask));
648
d->ignoredModMask = LockMask |
649
(modMask[CompModNumLock] & ~CompNoMask) |
650
(modMask[CompModScrollLock] & ~CompNoMask);
652
for (s = d->screens; s; s = s->next)
653
updatePassiveGrabs (s);
659
virtualToRealModMask (CompDisplay *d,
660
unsigned int modMask)
664
for (i = 0; i < CompModNum; i++)
666
if (modMask & virtualModMask[i])
668
modMask &= ~virtualModMask[i];
669
modMask |= d->modMask[i];
673
return (modMask & ~(CompPressMask | CompReleaseMask));
677
realToVirtualModMask (CompDisplay *d,
678
unsigned int modMask)
682
for (i = 0; i < CompModNum; i++)
684
if (modMask & d->modMask[i])
685
modMask |= virtualModMask[i];
699
CompDisplay *display = compDisplays;
700
CompScreen *s = display->screens;
701
int timeToNextRedraw = 0;
702
CompWindow *move = 0;
704
int moveX = 0, moveY = 0;
708
tmpRegion = XCreateRegion ();
711
fprintf (stderr, "%s: Couldn't create region\n", programName);
715
ufd.fd = ConnectionNumber (display->display);
720
if (display->dirtyPluginList)
721
updatePlugins (display);
725
execvp (programName, programArgv);
729
while (XPending (display->display))
731
XNextEvent (display->display, &event);
733
/* translate root window coordinates */
738
switch (event.type) {
742
px = event.xbutton.x;
743
py = event.xbutton.y;
745
move = findWindowAt (display, event.xbutton.window,
749
moveX = move->attrib.x;
750
moveY = move->attrib.y;
751
XRaiseWindow (display->display, move->id);
759
root = translateToRootWindow (display,
760
event.xbutton.window);
761
XTranslateCoordinates (display->display,
762
event.xbutton.root, root,
763
event.xbutton.x_root,
764
event.xbutton.y_root,
765
&event.xbutton.x_root,
766
&event.xbutton.y_root,
768
event.xbutton.root = root;
772
root = translateToRootWindow (display, event.xkey.window);
773
XTranslateCoordinates (display->display,
774
event.xkey.root, root,
780
event.xkey.root = root;
785
moveX += event.xbutton.x - px;
786
moveY += event.xbutton.y - py;
787
px = event.xbutton.x;
788
py = event.xbutton.y;
790
XMoveWindow (display->display, move->id, moveX, moveY);
795
root = translateToRootWindow (display,
796
event.xmotion.window);
797
XTranslateCoordinates (display->display,
798
event.xmotion.root, root,
799
event.xmotion.x_root,
800
event.xmotion.y_root,
801
&event.xmotion.x_root,
802
&event.xmotion.y_root,
804
event.xmotion.root = root;
810
/* add virtual modifiers */
811
switch (event.type) {
813
event.xbutton.state |= CompPressMask;
814
event.xbutton.state =
815
realToVirtualModMask (display, event.xbutton.state);
818
event.xbutton.state |= CompReleaseMask;
819
event.xbutton.state =
820
realToVirtualModMask (display, event.xbutton.state);
823
event.xkey.state |= CompPressMask;
824
event.xkey.state = realToVirtualModMask (display,
828
event.xkey.state |= CompReleaseMask;
829
event.xkey.state = realToVirtualModMask (display,
833
event.xmotion.state =
834
realToVirtualModMask (display, event.xmotion.state);
840
sn_display_process_event (display->snDisplay, &event);
842
(*display->handleEvent) (display, &event);
847
/* sync with server */
850
timeToNextRedraw = getTimeToNextRedraw (s, &s->lastRedraw, idle);
851
if (timeToNextRedraw)
852
timeToNextRedraw = poll (&ufd, 1, timeToNextRedraw);
854
if (timeToNextRedraw == 0)
856
gettimeofday (&tv, 0);
858
timeDiff = TIMEVALDIFF (&tv, &s->lastRedraw);
862
(*s->preparePaintScreen) (s, idle ? s->redrawTime : timeDiff);
864
if (s->damageMask & COMP_SCREEN_DAMAGE_REGION_MASK)
866
XIntersectRegion (s->damage, &s->region, tmpRegion);
868
if (tmpRegion->numRects == 1 &&
869
tmpRegion->rects->x1 == 0 &&
870
tmpRegion->rects->y1 == 0 &&
871
tmpRegion->rects->x2 == s->width &&
872
tmpRegion->rects->y2 == s->height)
876
EMPTY_REGION (s->damage);
878
if (s->damageMask & COMP_SCREEN_DAMAGE_ALL_MASK)
882
(*s->paintScreen) (s,
883
&defaultScreenPaintAttrib,
885
PAINT_SCREEN_REGION_MASK |
886
PAINT_SCREEN_FULL_MASK);
888
glXSwapBuffers (s->display->display, s->root);
890
else if (s->damageMask & COMP_SCREEN_DAMAGE_REGION_MASK)
894
if ((*s->paintScreen) (s,
895
&defaultScreenPaintAttrib,
897
PAINT_SCREEN_REGION_MASK))
903
pBox = tmpRegion->rects;
904
nBox = tmpRegion->numRects;
907
y = s->height - pBox->y2;
909
glXCopySubBufferMESA (s->display->display,
913
pBox->y2 - pBox->y1);
918
*/ /* ugly empty rect flush hack */ /*
919
glXCopySubBufferMESA (s->display->display, s->root,
923
glEnable (GL_SCISSOR_TEST);
924
glDrawBuffer (GL_FRONT);
926
pBox = tmpRegion->rects;
927
nBox = tmpRegion->numRects;
930
y = s->height - pBox->y2;
932
glBitmap (0, 0, 0, 0,
933
pBox->x1 - s->rasterX, y - s->rasterY,
936
s->rasterX = pBox->x1;
939
glScissor (pBox->x1, y,
941
pBox->y2 - pBox->y1);
943
glCopyPixels (pBox->x1, y,
951
glDrawBuffer (GL_BACK);
952
glDisable (GL_SCISSOR_TEST);
957
(*s->paintScreen) (s,
958
&defaultScreenPaintAttrib,
960
PAINT_SCREEN_FULL_MASK);
962
glXSwapBuffers (s->display->display, s->root);
968
(*s->donePaintScreen) (s);
970
/* remove destroyed windows */
971
while (s->pendingDestroys)
975
for (w = s->windows; w; w = w->next)
985
s->pendingDestroys--;
995
if (timeouts->left > 0)
996
poll (&ufd, 1, timeouts->left);
998
gettimeofday (&tv, 0);
1000
timeDiff = TIMEVALDIFF (&tv, &lastTimeout);
1002
for (t = timeouts; t; t = t->next)
1003
t->left -= timeDiff;
1005
while (timeouts && timeouts->left <= 0)
1008
if ((*t->callBack) (t->closure))
1024
poll (&ufd, 1, 1000);
1032
static int errors = 0;
1035
errorHandler (Display *dpy,
1048
XGetErrorDatabaseText (dpy, "XlibMessage", "XError", "", str, 128);
1049
fprintf (stderr, "%s", str);
1051
o = e->error_code - compDisplays->damageError;
1062
fprintf (stderr, ": %s\n ", name);
1066
XGetErrorText (dpy, e->error_code, str, 128);
1067
fprintf (stderr, ": %s\n ", str);
1070
XGetErrorDatabaseText (dpy, "XlibMessage", "MajorCode", "%d", str, 128);
1071
fprintf (stderr, str, e->request_code);
1073
sprintf (str, "%d", e->request_code);
1074
XGetErrorDatabaseText (dpy, "XRequest", str, "", str, 128);
1075
if (strcmp (str, ""))
1076
fprintf (stderr, " (%s)", str);
1077
fprintf (stderr, "\n ");
1079
XGetErrorDatabaseText (dpy, "XlibMessage", "MinorCode", "%d", str, 128);
1080
fprintf (stderr, str, e->minor_code);
1081
fprintf (stderr, "\n ");
1083
XGetErrorDatabaseText (dpy, "XlibMessage", "ResourceID", "%d", str, 128);
1084
fprintf (stderr, str, e->resourceid);
1085
fprintf (stderr, "\n");
1094
compCheckForError (Display *dpy)
1106
#define PING_DELAY 5000
1109
pingTimeout (void *closure)
1111
CompDisplay *d = closure;
1115
int ping = d->lastPing + 1;
1117
ev.type = ClientMessage;
1118
ev.xclient.window = 0;
1119
ev.xclient.message_type = d->wmProtocolsAtom;
1120
ev.xclient.format = 32;
1121
ev.xclient.data.l[0] = d->wmPingAtom;
1122
ev.xclient.data.l[1] = ping;
1123
ev.xclient.data.l[2] = 0;
1124
ev.xclient.data.l[3] = 0;
1125
ev.xclient.data.l[4] = 0;
1127
for (s = d->screens; s; s = s->next)
1129
for (w = s->windows; w; w = w->next)
1131
if (w->attrib.map_state != IsViewable)
1134
if (!(w->type & CompWindowTypeNormalMask))
1137
if (w->protocols & CompWindowProtocolPingMask)
1139
if (w->transientFor)
1142
if (w->lastPong < d->lastPing)
1147
w->paint.saturation = 0;
1149
addWindowDamage (w);
1153
ev.xclient.window = w->id;
1154
ev.xclient.data.l[2] = w->id;
1156
XSendEvent (d->display, w->id, FALSE, NoEventMask, &ev);
1167
addDisplay (char *name,
1178
if (displayPrivateLen)
1180
d->privates = malloc (displayPrivateLen * sizeof (CompPrivate));
1187
d->screenPrivateIndices = 0;
1188
d->screenPrivateLen = 0;
1190
for (i = 0; i < CompModNum; i++)
1191
d->modMask[i] = CompNoMask;
1193
d->ignoredModMask = LockMask;
1195
d->plugin.list.type = CompOptionTypeString;
1196
d->plugin.list.nValue = 0;
1197
d->plugin.list.value = 0;
1199
compDisplayInitOptions (d, plugin, nPlugin);
1201
d->textureFilter = GL_LINEAR;
1204
d->activeWindow = 0;
1206
d->autoRaiseHandle = 0;
1207
d->autoRaiseWindow = None;
1209
d->display = dpy = XOpenDisplay (name);
1212
fprintf (stderr, "%s: Couldn't open display %s\n",
1213
programName, XDisplayName (name));
1217
snprintf (d->displayString, 255, "DISPLAY=%s", DisplayString (dpy));
1220
XSynchronize (dpy, TRUE);
1223
XSetErrorHandler (errorHandler);
1225
updateModifierMappings (d);
1227
d->setDisplayOption = setDisplayOption;
1228
d->setDisplayOptionForPlugin = setDisplayOptionForPlugin;
1230
d->initPluginForDisplay = initPluginForDisplay;
1231
d->finiPluginForDisplay = finiPluginForDisplay;
1233
d->handleEvent = handleEvent;
1235
d->supportedAtom = XInternAtom (dpy, "_NET_SUPPORTED", 0);
1236
d->supportingWmCheckAtom = XInternAtom (dpy, "_NET_SUPPORTING_WM_CHECK", 0);
1238
d->utf8StringAtom = XInternAtom (dpy, "UTF8_STRING", 0);
1240
d->wmNameAtom = XInternAtom (dpy, "_NET_WM_NAME", 0);
1242
d->winTypeAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE", 0);
1243
d->winTypeDesktopAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DESKTOP",
1245
d->winTypeDockAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DOCK", 0);
1246
d->winTypeToolbarAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR",
1248
d->winTypeMenuAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_MENU", 0);
1249
d->winTypeUtilAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_UTILITY",
1251
d->winTypeSplashAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_SPLASH", 0);
1252
d->winTypeDialogAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DIALOG", 0);
1253
d->winTypeNormalAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_NORMAL", 0);
1255
d->winOpacityAtom = XInternAtom (dpy, "_NET_WM_WINDOW_OPACITY", 0);
1256
d->winBrightnessAtom = XInternAtom (dpy, "_NET_WM_WINDOW_BRIGHTNESS", 0);
1257
d->winSaturationAtom = XInternAtom (dpy, "_NET_WM_WINDOW_SATURATION", 0);
1259
d->winActiveAtom = XInternAtom (dpy, "_NET_ACTIVE_WINDOW", 0);
1261
d->workareaAtom = XInternAtom (dpy, "_NET_WORKAREA", 0);
1263
d->desktopViewportAtom = XInternAtom (dpy, "_NET_DESKTOP_VIEWPORT", 0);
1264
d->desktopGeometryAtom = XInternAtom (dpy, "_NET_DESKTOP_GEOMETRY", 0);
1265
d->currentDesktopAtom = XInternAtom (dpy, "_NET_CURRENT_DESKTOP", 0);
1266
d->numberOfDesktopsAtom = XInternAtom (dpy, "_NET_NUMBER_OF_DESKTOPS", 0);
1268
d->winStateAtom = XInternAtom (dpy, "_NET_WM_STATE", 0);
1269
d->winStateModalAtom =
1270
XInternAtom (dpy, "_NET_WM_STATE_MODAL", 0);
1271
d->winStateStickyAtom =
1272
XInternAtom (dpy, "_NET_WM_STATE_STICKY", 0);
1273
d->winStateMaximizedVertAtom =
1274
XInternAtom (dpy, "_NET_WM_STATE_MAXIMIZED_VERT", 0);
1275
d->winStateMaximizedHorzAtom =
1276
XInternAtom (dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", 0);
1277
d->winStateShadedAtom =
1278
XInternAtom (dpy, "_NET_WM_STATE_SHADED", 0);
1279
d->winStateSkipTaskbarAtom =
1280
XInternAtom (dpy, "_NET_WM_STATE_SKIP_TASKBAR", 0);
1281
d->winStateSkipPagerAtom =
1282
XInternAtom (dpy, "_NET_WM_STATE_SKIP_PAGER", 0);
1283
d->winStateHiddenAtom =
1284
XInternAtom (dpy, "_NET_WM_STATE_HIDDEN", 0);
1285
d->winStateFullscreenAtom =
1286
XInternAtom (dpy, "_NET_WM_STATE_FULLSCREEN", 0);
1287
d->winStateAboveAtom =
1288
XInternAtom (dpy, "_NET_WM_STATE_ABOVE", 0);
1289
d->winStateBelowAtom =
1290
XInternAtom (dpy, "_NET_WM_STATE_BELOW", 0);
1291
d->winStateDemandsAttentionAtom =
1292
XInternAtom (dpy, "_NET_WM_STATE_DEMANDS_ATTENTION", 0);
1293
d->winStateDisplayModalAtom =
1294
XInternAtom (dpy, "_NET_WM_STATE_DISPLAY_MODAL", 0);
1296
d->winActionMoveAtom = XInternAtom (dpy, "_NET_WM_ACTION_MOVE", 0);
1297
d->winActionResizeAtom = XInternAtom (dpy, "_NET_WM_ACTION_RESIZE", 0);
1298
d->winActionStickAtom = XInternAtom (dpy, "_NET_WM_ACTION_STICK", 0);
1299
d->winActionMinimizeAtom =
1300
XInternAtom (dpy, "_NET_WM_ACTION_MINIMIZE", 0);
1301
d->winActionMaximizeHorzAtom =
1302
XInternAtom (dpy, "_NET_WM_ACTION_MAXIMIZE_HORZ", 0);
1303
d->winActionMaximizeVertAtom =
1304
XInternAtom (dpy, "_NET_WM_ACTION_MAXIMIZE_VERT", 0);
1305
d->winActionFullscreenAtom =
1306
XInternAtom (dpy, "_NET_WM_ACTION_FULLSCREEN", 0);
1307
d->winActionCloseAtom = XInternAtom (dpy, "_NET_WM_ACTION_CLOSE", 0);
1309
d->wmAllowedActionsAtom = XInternAtom (dpy, "_NET_WM_ALLOWED_ACTIONS", 0);
1311
d->wmStrutAtom = XInternAtom (dpy, "_NET_WM_STRUT", 0);
1312
d->wmStrutPartialAtom = XInternAtom (dpy, "_NET_WM_STRUT_PARTIAL", 0);
1314
d->clientListAtom = XInternAtom (dpy, "_NET_CLIENT_LIST", 0);
1315
d->clientListStackingAtom =
1316
XInternAtom (dpy, "_NET_CLIENT_LIST_STACKING", 0);
1318
d->frameExtentsAtom = XInternAtom (dpy, "_NET_FRAME_EXTENTS", 0);
1319
d->frameWindowAtom = XInternAtom (dpy, "_NET_FRAME_WINDOW", 0);
1321
d->wmStateAtom = XInternAtom (dpy, "WM_STATE", 0);
1322
d->wmChangeStateAtom = XInternAtom (dpy, "WM_CHANGE_STATE", 0);
1323
d->wmProtocolsAtom = XInternAtom (dpy, "WM_PROTOCOLS", 0);
1324
d->wmClientLeaderAtom = XInternAtom (dpy, "WM_CLIENT_LEADER", 0);
1326
d->wmDeleteWindowAtom = XInternAtom (dpy, "WM_DELETE_WINDOW", 0);
1327
d->wmTakeFocusAtom = XInternAtom (dpy, "WM_TAKE_FOCUS", 0);
1328
d->wmPingAtom = XInternAtom (dpy, "_NET_WM_PING", 0);
1329
d->wmSyncRequestAtom = XInternAtom (dpy, "_NET_WM_SYNC_REQUEST", 0);
1331
d->wmSyncRequestCounterAtom =
1332
XInternAtom (dpy, "_NET_WM_SYNC_REQUEST_COUNTER", 0);
1334
d->closeWindowAtom = XInternAtom (dpy, "_NET_CLOSE_WINDOW", 0);
1335
d->wmMoveResizeAtom = XInternAtom (dpy, "_NET_WM_MOVERESIZE", 0);
1336
d->moveResizeWindowAtom = XInternAtom (dpy, "_NET_MOVERESIZE_WINDOW", 0);
1338
d->showingDesktopAtom = XInternAtom (dpy, "_NET_SHOWING_DESKTOP", 0);
1340
d->xBackgroundAtom[0] = XInternAtom (dpy, "_XSETROOT_ID", 0);
1341
d->xBackgroundAtom[1] = XInternAtom (dpy, "_XROOTPMAP_ID", 0);
1343
d->panelActionAtom = XInternAtom (dpy, "_GNOME_PANEL_ACTION", 0);
1344
d->panelActionMainMenuAtom =
1345
XInternAtom (dpy, "_GNOME_PANEL_ACTION_MAIN_MENU", 0);
1346
d->panelActionRunDialogAtom =
1347
XInternAtom (dpy, "_GNOME_PANEL_ACTION_RUN_DIALOG", 0);
1349
d->mwmHintsAtom = XInternAtom (dpy, "_MOTIF_WM_HINTS", 0);
1351
d->managerAtom = XInternAtom (dpy, "MANAGER", 0);
1352
d->targetsAtom = XInternAtom (dpy, "TARGETS", 0);
1353
d->multipleAtom = XInternAtom (dpy, "MULTIPLE", 0);
1354
d->timestampAtom = XInternAtom (dpy, "TIMESTAMP", 0);
1355
d->versionAtom = XInternAtom (dpy, "VERSION", 0);
1356
d->atomPairAtom = XInternAtom (dpy, "ATOM_PAIR", 0);
1358
d->snDisplay = sn_display_new (dpy, NULL, NULL);
1366
d->compositeOpcode = MAXSHORT;
1367
d->compositeEvent = MAXSHORT;
1368
d->compositeError = MAXSHORT;
1370
d->damageEvent = MAXSHORT;
1371
d->damageError = MAXSHORT;
1375
int compositeMajor, compositeMinor;
1377
if (!XQueryExtension (dpy,
1379
&d->compositeOpcode,
1381
&d->compositeError))
1383
fprintf (stderr, "%s: No composite extension\n", programName);
1387
XCompositeQueryVersion (dpy, &compositeMajor, &compositeMinor);
1388
if (compositeMajor == 0 && compositeMinor < 2)
1390
fprintf (stderr, "%s: Old composite extension\n", programName);
1394
if (!XDamageQueryExtension (dpy, &d->damageEvent, &d->damageError))
1396
fprintf (stderr, "%s: No damage extension\n", programName);
1400
if (!XRRQueryExtension (dpy, &d->randrEvent, &d->randrError))
1402
fprintf (stderr, "%s: No RandR extension\n", programName);
1406
if (!XSyncQueryExtension (dpy, &d->syncEvent, &d->syncError))
1408
fprintf (stderr, "%s: No sync extension\n", programName);
1413
d->shapeExtension = XShapeQueryExtension (dpy,
1421
addScreen (d, 0, None, 0, 0);
1425
for (i = 0; i < ScreenCount (dpy); i++)
1427
Window newWmSnOwner = None;
1429
Time wmSnTimestamp = 0;
1431
XSetWindowAttributes attr;
1432
Window currentWmSnOwner;
1435
sprintf (buf, "WM_S%d", i);
1436
wmSnAtom = XInternAtom (dpy, buf, 0);
1438
currentWmSnOwner = XGetSelectionOwner (dpy, wmSnAtom);
1440
if (currentWmSnOwner != None)
1442
if (!replaceCurrentWm)
1445
"%s: Screen %d on display \"%s\" already "
1446
"has a window manager; try using the "
1447
"--replace option to replace the current "
1448
"window manager.\n",
1449
programName, i, DisplayString (dpy));
1454
XSelectInput (dpy, currentWmSnOwner,
1455
StructureNotifyMask);
1458
attr.override_redirect = TRUE;
1459
attr.event_mask = PropertyChangeMask;
1462
XCreateWindow (dpy, XRootWindow (dpy, i),
1463
-100, -100, 1, 1, 0,
1464
CopyFromParent, CopyFromParent,
1466
CWOverrideRedirect | CWEventMask,
1469
XChangeProperty (dpy,
1472
d->utf8StringAtom, 8,
1474
(unsigned char *) PACKAGE,
1482
wmSnTimestamp = event.xproperty.time;
1484
XSetSelectionOwner (dpy, wmSnAtom, newWmSnOwner,
1487
if (XGetSelectionOwner (dpy, wmSnAtom) != newWmSnOwner)
1490
"%s: Could not acquire window manager "
1491
"selection on screen %d display \"%s\"\n",
1492
programName, i, DisplayString (dpy));
1494
XDestroyWindow (dpy, newWmSnOwner);
1499
/* Send client message indicating that we are now the WM */
1500
event.xclient.type = ClientMessage;
1501
event.xclient.window = XRootWindow (dpy, i);
1502
event.xclient.message_type = d->managerAtom;
1503
event.xclient.format = 32;
1504
event.xclient.data.l[0] = wmSnTimestamp;
1505
event.xclient.data.l[1] = wmSnAtom;
1506
event.xclient.data.l[2] = 0;
1507
event.xclient.data.l[3] = 0;
1508
event.xclient.data.l[4] = 0;
1510
XSendEvent (dpy, XRootWindow (dpy, i), FALSE,
1511
StructureNotifyMask, &event);
1513
/* Wait for old window manager to go away */
1514
if (currentWmSnOwner != None)
1517
XWindowEvent (dpy, currentWmSnOwner,
1518
StructureNotifyMask, &event);
1519
} while (event.type != DestroyNotify);
1522
compCheckForError (dpy);
1524
XCompositeRedirectSubwindows (dpy, XRootWindow (dpy, i),
1525
CompositeRedirectManual);
1527
if (compCheckForError (dpy))
1529
fprintf (stderr, "%s: Another composite manager is already "
1530
"running on screen: %d\n", programName, i);
1535
XSelectInput (dpy, XRootWindow (dpy, i),
1536
SubstructureRedirectMask |
1537
SubstructureNotifyMask |
1538
StructureNotifyMask |
1539
PropertyChangeMask |
1547
if (compCheckForError (dpy))
1549
fprintf (stderr, "%s: Another window manager is "
1550
"already running on screen: %d\n",
1556
if (!addScreen (d, i, newWmSnOwner, wmSnAtom, wmSnTimestamp))
1558
fprintf (stderr, "%s: Failed to manage screen: %d\n",
1566
fprintf (stderr, "%s: No managable screens found on display %s\n",
1567
programName, XDisplayName (name));
1571
XGetInputFocus (dpy, &focus, &revertTo);
1573
if (focus == None || focus == PointerRoot)
1575
focusDefaultWindow (d);
1581
w = findWindowAtDisplay (d, focus);
1584
moveInputFocusToWindow (w);
1587
focusDefaultWindow (d);
1590
d->pingHandle = compAddTimeout (PING_DELAY, pingTimeout, d);
1596
focusDefaultWindow (CompDisplay *d)
1600
CompWindow *focus = NULL;
1602
for (s = d->screens; s; s = s->next)
1604
for (w = s->reverseWindows; w; w = w->prev)
1606
if (w->type & CompWindowTypeDockMask)
1609
if ((*s->focusWindow) (w))
1613
if (w->type & (CompWindowTypeNormalMask |
1614
CompWindowTypeDialogMask |
1615
CompWindowTypeModalDialogMask))
1617
if (w->activeNum > focus->activeNum)
1629
if (focus->id != d->activeWindow)
1630
moveInputFocusToWindow (focus);
1634
XSetInputFocus (d->display, d->screens->root, RevertToPointerRoot,
1640
findScreenAtDisplay (CompDisplay *d,
1645
for (s = d->screens; s; s = s->next)
1647
if (s->root == root)
1655
forEachWindowOnDisplay (CompDisplay *display,
1656
ForEachWindowProc proc,
1661
for (s = display->screens; s; s = s->next)
1662
forEachWindowOnScreen (s, proc, closure);
1666
findWindowAtDisplay (CompDisplay *d,
1669
if (lastFoundWindow && lastFoundWindow->id == id)
1671
return lastFoundWindow;
1678
for (s = d->screens; s; s = s->next)
1680
w = findWindowAtScreen (s, id);
1690
findScreenForSelection (CompDisplay *display,
1696
for (s = display->screens; s; s = s->next)
1698
if (s->wmSnSelectionWindow == owner && s->wmSnAtom == selection)
1705
/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
1707
convertProperty (CompDisplay *display,
1716
Atom conversionTargets[N_TARGETS];
1717
long icccmVersion[] = { 2, 0 };
1719
conversionTargets[0] = display->targetsAtom;
1720
conversionTargets[1] = display->multipleAtom;
1721
conversionTargets[2] = display->timestampAtom;
1722
conversionTargets[3] = display->versionAtom;
1724
if (target == display->targetsAtom)
1725
XChangeProperty (display->display, w, property,
1726
XA_ATOM, 32, PropModeReplace,
1727
(unsigned char *) conversionTargets, N_TARGETS);
1728
else if (target == display->timestampAtom)
1729
XChangeProperty (display->display, w, property,
1730
XA_INTEGER, 32, PropModeReplace,
1731
(unsigned char *) &screen->wmSnTimestamp, 1);
1732
else if (target == display->versionAtom)
1733
XChangeProperty (display->display, w, property,
1734
XA_INTEGER, 32, PropModeReplace,
1735
(unsigned char *) icccmVersion, 2);
1739
/* Be sure the PropertyNotify has arrived so we
1740
* can send SelectionNotify
1742
XSync (display->display, FALSE);
1747
/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
1749
handleSelectionRequest (CompDisplay *display,
1752
XSelectionEvent reply;
1755
screen = findScreenForSelection (display,
1756
event->xselectionrequest.owner,
1757
event->xselectionrequest.selection);
1761
reply.type = SelectionNotify;
1762
reply.display = display->display;
1763
reply.requestor = event->xselectionrequest.requestor;
1764
reply.selection = event->xselectionrequest.selection;
1765
reply.target = event->xselectionrequest.target;
1766
reply.property = None;
1767
reply.time = event->xselectionrequest.time;
1769
if (event->xselectionrequest.target == display->multipleAtom)
1771
if (event->xselectionrequest.property != None)
1775
unsigned long num, rest;
1776
unsigned char *data;
1778
if (XGetWindowProperty (display->display,
1779
event->xselectionrequest.requestor,
1780
event->xselectionrequest.property,
1782
display->atomPairAtom,
1783
&type, &format, &num, &rest,
1787
/* FIXME: to be 100% correct, should deal with rest > 0,
1788
* but since we have 4 possible targets, we will hardly ever
1789
* meet multiple requests with a length > 8
1791
adata = (Atom *) data;
1793
while (i < (int) num)
1795
if (!convertProperty (display, screen,
1796
event->xselectionrequest.requestor,
1797
adata[i], adata[i + 1]))
1798
adata[i + 1] = None;
1803
XChangeProperty (display->display,
1804
event->xselectionrequest.requestor,
1805
event->xselectionrequest.property,
1806
display->atomPairAtom,
1807
32, PropModeReplace, data, num);
1812
if (event->xselectionrequest.property == None)
1813
event->xselectionrequest.property = event->xselectionrequest.target;
1815
if (convertProperty (display, screen,
1816
event->xselectionrequest.requestor,
1817
event->xselectionrequest.target,
1818
event->xselectionrequest.property))
1819
reply.property = event->xselectionrequest.property;
1822
XSendEvent (display->display,
1823
event->xselectionrequest.requestor,
1824
FALSE, 0L, (XEvent *) &reply);
1828
handleSelectionClear (CompDisplay *display,
1831
/* We need to unmanage the screen on which we lost the selection */
1834
screen = findScreenForSelection (display,
1835
event->xselectionclear.window,
1836
event->xselectionclear.selection);
1841
/* removeScreen (screen); */