~alan-griffiths/compiz-core/Bug-931283

« back to all changes in this revision

Viewing changes to src/display.c

  • Committer: David Reveman
  • Date: 2006-02-09 06:03:09 UTC
  • Revision ID: git-v1:9959c2b13ded64a5e66359a8097250dc9d87fc1c
Initial revision

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2005 Novell, Inc.
 
3
 *
 
4
 * Permission to use, copy, modify, distribute, and sell this software
 
5
 * and its documentation for any purpose is hereby granted without
 
6
 * fee, provided that the above copyright notice appear in all copies
 
7
 * and that both that copyright notice and this permission notice
 
8
 * appear in supporting documentation, and that the name of
 
9
 * Novell, Inc. not be used in advertising or publicity pertaining to
 
10
 * distribution of the software without specific, written prior permission.
 
11
 * Novell, Inc. makes no representations about the suitability of this
 
12
 * software for any purpose. It is provided "as is" without express or
 
13
 * implied warranty.
 
14
 *
 
15
 * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 
16
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
 
17
 * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 
18
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 
19
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 
20
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 
21
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
22
 *
 
23
 * Author: David Reveman <davidr@novell.com>
 
24
 */
 
25
 
 
26
#ifdef HAVE_CONFIG_H
 
27
#  include "../config.h"
 
28
#endif
 
29
 
 
30
#include <stdio.h>
 
31
#include <stdlib.h>
 
32
#include <string.h>
 
33
#include <sys/poll.h>
 
34
#include <unistd.h>
 
35
 
 
36
#define XK_MISCELLANY
 
37
#include <X11/keysymdef.h>
 
38
 
 
39
#include <X11/Xlib.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>
 
45
 
 
46
#include <compiz.h>
 
47
 
 
48
static unsigned int virtualModMask[] = {
 
49
    CompAltMask, CompMetaMask, CompSuperMask, CompHyperMask,
 
50
    CompModeSwitchMask, CompNumLockMask, CompScrollLockMask
 
51
};
 
52
 
 
53
typedef struct _CompTimeout {
 
54
    struct _CompTimeout *next;
 
55
    int                 time;
 
56
    int                 left;
 
57
    CallBackProc        callBack;
 
58
    void                *closure;
 
59
    CompTimeoutHandle   handle;
 
60
} CompTimeout;
 
61
 
 
62
static CompTimeout       *timeouts = 0;
 
63
static struct timeval    lastTimeout;
 
64
static CompTimeoutHandle lastTimeoutHandle = 1;
 
65
 
 
66
#define CLICK_TO_FOCUS_DEFAULT TRUE
 
67
 
 
68
#define AUTORAISE_DEFAULT TRUE
 
69
 
 
70
#define AUTORAISE_DELAY_DEFAULT 1000
 
71
#define AUTORAISE_DELAY_MIN     0
 
72
#define AUTORAISE_DELAY_MAX     10000
 
73
 
 
74
#define NUM_OPTIONS(d) (sizeof ((d)->opt) / sizeof (CompOption))
 
75
 
 
76
static char *textureFilter[] = { "Fast", "Good", "Best" };
 
77
 
 
78
#define NUM_TEXTURE_FILTER (sizeof (textureFilter) / sizeof (textureFilter[0]))
 
79
 
 
80
CompDisplay *compDisplays = 0;
 
81
 
 
82
static CompDisplay compDisplay;
 
83
 
 
84
static char *displayPrivateIndices = 0;
 
85
static int  displayPrivateLen = 0;
 
86
 
 
87
static int
 
88
reallocDisplayPrivate (int  size,
 
89
                       void *closure)
 
90
{
 
91
    CompDisplay *d = compDisplays;
 
92
    void        *privates;
 
93
 
 
94
    if (d)
 
95
    {
 
96
        privates = realloc (d->privates, size * sizeof (CompPrivate));
 
97
        if (!privates)
 
98
            return FALSE;
 
99
 
 
100
        d->privates = (CompPrivate *) privates;
 
101
    }
 
102
 
 
103
    return TRUE;
 
104
}
 
105
 
 
106
int
 
107
allocateDisplayPrivateIndex (void)
 
108
{
 
109
    return allocatePrivateIndex (&displayPrivateLen,
 
110
                                 &displayPrivateIndices,
 
111
                                 reallocDisplayPrivate,
 
112
                                 0);
 
113
}
 
114
 
 
115
void
 
116
freeDisplayPrivateIndex (int index)
 
117
{
 
118
    freePrivateIndex (displayPrivateLen, displayPrivateIndices, index);
 
119
}
 
120
 
 
121
static void
 
122
compDisplayInitOptions (CompDisplay *display,
 
123
                        char        **plugin,
 
124
                        int         nPlugin)
 
125
{
 
126
    CompOption *o;
 
127
    int        i;
 
128
 
 
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;
 
141
 
 
142
    display->dirtyPluginList = TRUE;
 
143
 
 
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;
 
152
 
 
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;
 
159
 
 
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;
 
166
 
 
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;
 
175
}
 
176
 
 
177
CompOption *
 
178
compGetDisplayOptions (CompDisplay *display,
 
179
                       int         *count)
 
180
{
 
181
    *count = NUM_OPTIONS (display);
 
182
    return display->opt;
 
183
}
 
184
 
 
185
static Bool
 
186
setDisplayOption (CompDisplay     *display,
 
187
                  char            *name,
 
188
                  CompOptionValue *value)
 
189
{
 
190
    CompOption *o;
 
191
    int        index;
 
192
 
 
193
    o = compFindOption (display->opt, NUM_OPTIONS (display), name, &index);
 
194
    if (!o)
 
195
        return FALSE;
 
196
 
 
197
    switch (index) {
 
198
    case COMP_DISPLAY_OPTION_ACTIVE_PLUGINS:
 
199
        if (compSetOptionList (o, value))
 
200
        {
 
201
            display->dirtyPluginList = TRUE;
 
202
            return TRUE;
 
203
        }
 
204
        break;
 
205
    case COMP_DISPLAY_OPTION_TEXTURE_FILTER:
 
206
        if (compSetStringOption (o, value))
 
207
        {
 
208
            CompScreen *s;
 
209
 
 
210
            for (s = display->screens; s; s = s->next)
 
211
                damageScreen (s);
 
212
 
 
213
            if (strcmp (o->value.s, "Fast") == 0)
 
214
                display->textureFilter = GL_NEAREST;
 
215
            else
 
216
                display->textureFilter = GL_LINEAR;
 
217
 
 
218
            return TRUE;
 
219
        }
 
220
        break;
 
221
    case COMP_DISPLAY_OPTION_CLICK_TO_FOCUS:
 
222
        if (compSetBoolOption (o, value))
 
223
            return TRUE;
 
224
        break;
 
225
    case COMP_DISPLAY_OPTION_AUTORAISE:
 
226
        if (compSetBoolOption (o, value))
 
227
            return TRUE;
 
228
        break;
 
229
    case COMP_DISPLAY_OPTION_AUTORAISE_DELAY:
 
230
        if (compSetIntOption (o, value))
 
231
            return TRUE;
 
232
    default:
 
233
        break;
 
234
    }
 
235
 
 
236
    return FALSE;
 
237
}
 
238
 
 
239
static Bool
 
240
setDisplayOptionForPlugin (CompDisplay     *display,
 
241
                           char            *plugin,
 
242
                           char            *name,
 
243
                           CompOptionValue *value)
 
244
{
 
245
    CompPlugin *p;
 
246
 
 
247
    p = findActivePlugin (plugin);
 
248
    if (p && p->vTable->setDisplayOption)
 
249
        return (*p->vTable->setDisplayOption) (display, name, value);
 
250
 
 
251
    return FALSE;
 
252
}
 
253
 
 
254
static Bool
 
255
initPluginForDisplay (CompPlugin  *p,
 
256
                      CompDisplay *d)
 
257
{
 
258
    return (*p->vTable->initDisplay) (p, d);
 
259
}
 
260
 
 
261
static void
 
262
finiPluginForDisplay (CompPlugin  *p,
 
263
                      CompDisplay *d)
 
264
{
 
265
    (*p->vTable->finiDisplay) (p, d);
 
266
}
 
267
 
 
268
static void
 
269
updatePlugins (CompDisplay *d)
 
270
{
 
271
    CompOption *o;
 
272
    CompPlugin *p, **pop = 0;
 
273
    int        nPop, i, j;
 
274
 
 
275
    d->dirtyPluginList = FALSE;
 
276
 
 
277
    o = &d->opt[COMP_DISPLAY_OPTION_ACTIVE_PLUGINS];
 
278
    for (i = 0; i < d->plugin.list.nValue && i < o->value.list.nValue; i++)
 
279
    {
 
280
        if (strcmp (d->plugin.list.value[i].s, o->value.list.value[i].s))
 
281
            break;
 
282
    }
 
283
 
 
284
    nPop = d->plugin.list.nValue - i;
 
285
 
 
286
    if (nPop)
 
287
    {
 
288
        pop = malloc (sizeof (CompPlugin *) * nPop);
 
289
        if (!pop)
 
290
        {
 
291
            (*d->setDisplayOption) (d, o->name, &d->plugin);
 
292
            return;
 
293
        }
 
294
    }
 
295
 
 
296
    for (j = 0; j < nPop; j++)
 
297
    {
 
298
        pop[j] = popPlugin ();
 
299
        d->plugin.list.nValue--;
 
300
        free (d->plugin.list.value[d->plugin.list.nValue].s);
 
301
    }
 
302
 
 
303
    for (; i < o->value.list.nValue; i++)
 
304
    {
 
305
        p = 0;
 
306
        for (j = 0; j < nPop; j++)
 
307
        {
 
308
            if (pop[j] && strcmp (pop[j]->vTable->name,
 
309
                                  o->value.list.value[i].s) == 0)
 
310
            {
 
311
                if (pushPlugin (pop[j]))
 
312
                {
 
313
                    p = pop[j];
 
314
                    pop[j] = 0;
 
315
                    break;
 
316
                }
 
317
            }
 
318
        }
 
319
 
 
320
        if (p == 0)
 
321
        {
 
322
            p = loadPlugin (o->value.list.value[i].s);
 
323
            if (p)
 
324
            {
 
325
                if (!pushPlugin (p))
 
326
                {
 
327
                    unloadPlugin (p);
 
328
                    p = 0;
 
329
                }
 
330
            }
 
331
        }
 
332
 
 
333
        if (p)
 
334
        {
 
335
            CompOptionValue *value;
 
336
 
 
337
            value = realloc (d->plugin.list.value, sizeof (CompOption) *
 
338
                             (d->plugin.list.nValue + 1));
 
339
            if (value)
 
340
            {
 
341
                value[d->plugin.list.nValue].s = strdup (p->vTable->name);
 
342
 
 
343
                d->plugin.list.value = value;
 
344
                d->plugin.list.nValue++;
 
345
            }
 
346
            else
 
347
            {
 
348
                p = popPlugin ();
 
349
                unloadPlugin (p);
 
350
            }
 
351
        }
 
352
    }
 
353
 
 
354
    for (j = 0; j < nPop; j++)
 
355
    {
 
356
        if (pop[j])
 
357
            unloadPlugin (pop[j]);
 
358
    }
 
359
 
 
360
    if (nPop)
 
361
        free (pop);
 
362
 
 
363
    (*d->setDisplayOption) (d, o->name, &d->plugin);
 
364
}
 
365
 
 
366
static void
 
367
addTimeout (CompTimeout *timeout)
 
368
{
 
369
    CompTimeout *p = 0, *t;
 
370
 
 
371
    for (t = timeouts; t; t = t->next)
 
372
    {
 
373
        if (timeout->time < t->left)
 
374
            break;
 
375
 
 
376
        p = t;
 
377
    }
 
378
 
 
379
    timeout->next = t;
 
380
    timeout->left = timeout->time;
 
381
 
 
382
    if (p)
 
383
        p->next = timeout;
 
384
    else
 
385
        timeouts = timeout;
 
386
}
 
387
 
 
388
CompTimeoutHandle
 
389
compAddTimeout (int          time,
 
390
                CallBackProc callBack,
 
391
                void         *closure)
 
392
{
 
393
    CompTimeout *timeout;
 
394
 
 
395
    timeout = malloc (sizeof (CompTimeout));
 
396
    if (!timeout)
 
397
        return 0;
 
398
 
 
399
    timeout->time     = time;
 
400
    timeout->callBack = callBack;
 
401
    timeout->closure  = closure;
 
402
    timeout->handle   = lastTimeoutHandle++;
 
403
 
 
404
    if (lastTimeoutHandle == MAXSHORT)
 
405
        lastTimeoutHandle = 1;
 
406
 
 
407
    if (!timeouts)
 
408
        gettimeofday (&lastTimeout, 0);
 
409
 
 
410
    addTimeout (timeout);
 
411
 
 
412
    return timeout->handle;
 
413
}
 
414
 
 
415
void
 
416
compRemoveTimeout (CompTimeoutHandle handle)
 
417
{
 
418
    CompTimeout *p = 0, *t;
 
419
 
 
420
    for (t = timeouts; t; t = t->next)
 
421
    {
 
422
        if (t->handle == handle)
 
423
            break;
 
424
 
 
425
        p = t;
 
426
    }
 
427
 
 
428
    if (t)
 
429
    {
 
430
        if (p)
 
431
            p->next = t->next;
 
432
        else
 
433
            timeouts = t->next;
 
434
 
 
435
        free (t);
 
436
    }
 
437
}
 
438
 
 
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
 
445
 
 
446
static int
 
447
getTimeToNextRedraw (CompScreen     *s,
 
448
                     struct timeval *lastTv,
 
449
                     Bool           idle)
 
450
{
 
451
    struct timeval tv;
 
452
    int            diff, next;
 
453
    static int     timeMult = 1;
 
454
 
 
455
    gettimeofday (&tv, 0);
 
456
 
 
457
    diff = TIMEVALDIFF (&tv, lastTv);
 
458
 
 
459
    if (idle)
 
460
    {
 
461
        if (timeMult > 1)
 
462
        {
 
463
            s->frameStatus = -1;
 
464
            s->redrawTime = s->optimalRedrawTime;
 
465
            timeMult--;
 
466
        }
 
467
    }
 
468
    else
 
469
    {
 
470
        if (diff > s->redrawTime)
 
471
        {
 
472
            if (s->frameStatus > 0)
 
473
                s->frameStatus = 0;
 
474
 
 
475
            next = s->optimalRedrawTime * (timeMult + 1);
 
476
            if (diff > next)
 
477
            {
 
478
                s->frameStatus--;
 
479
                if (s->frameStatus < -1)
 
480
                {
 
481
                    timeMult++;
 
482
                    s->redrawTime = diff = next;
 
483
                }
 
484
            }
 
485
        }
 
486
        else if (diff < s->redrawTime)
 
487
        {
 
488
            if (s->frameStatus < 0)
 
489
                s->frameStatus = 0;
 
490
 
 
491
            if (timeMult > 1)
 
492
            {
 
493
                next = s->optimalRedrawTime * (timeMult - 1);
 
494
                if (diff < next)
 
495
                {
 
496
                    s->frameStatus++;
 
497
                    if (s->frameStatus > 4)
 
498
                    {
 
499
                        timeMult--;
 
500
                        s->redrawTime = next;
 
501
                    }
 
502
                }
 
503
            }
 
504
        }
 
505
    }
 
506
 
 
507
    if (diff > s->redrawTime)
 
508
        return 0;
 
509
 
 
510
    return s->redrawTime - diff;
 
511
}
 
512
 
 
513
static CompWindow *
 
514
findWindowAt (CompDisplay *d,
 
515
              Window      root,
 
516
              int         x,
 
517
              int         y)
 
518
{
 
519
    CompScreen *s;
 
520
    CompWindow *w;
 
521
 
 
522
    for (s = d->screens; s; s = s->next)
 
523
    {
 
524
        if (s->root == root && s->maxGrab == 0)
 
525
        {
 
526
            for (w = s->reverseWindows; w; w = w->prev)
 
527
            {
 
528
                if (x >= w->attrib.x &&
 
529
                    y >= w->attrib.y &&
 
530
                    x <  w->attrib.x + w->width &&
 
531
                    y <  w->attrib.y + w->height)
 
532
                    return w;
 
533
            }
 
534
        }
 
535
    }
 
536
 
 
537
    return 0;
 
538
}
 
539
 
 
540
static Window
 
541
translateToRootWindow (CompDisplay *d,
 
542
                       Window      child)
 
543
{
 
544
    CompScreen *s;
 
545
 
 
546
    for (s = d->screens; s; s = s->next)
 
547
    {
 
548
        if (s->root == child || s->grabWindow == child)
 
549
            return s->root;
 
550
    }
 
551
 
 
552
    return child;
 
553
}
 
554
 
 
555
void
 
556
updateModifierMappings (CompDisplay *d)
 
557
{
 
558
    XModifierKeymap *modmap;
 
559
    unsigned int    modMask[CompModNum];
 
560
    int             i, minKeycode, maxKeycode, keysymsPerKeycode = 0;
 
561
 
 
562
    for (i = 0; i < CompModNum; i++)
 
563
        modMask[i] = 0;
 
564
 
 
565
    XDisplayKeycodes (d->display, &minKeycode, &maxKeycode);
 
566
    XGetKeyboardMapping (d->display, minKeycode, (maxKeycode - minKeycode + 1),
 
567
                         &keysymsPerKeycode);
 
568
 
 
569
    modmap = XGetModifierMapping (d->display);
 
570
    if (modmap && modmap->max_keypermod > 0)
 
571
    {
 
572
        static int maskTable[] = {
 
573
            ShiftMask, LockMask, ControlMask, Mod1Mask,
 
574
            Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
 
575
        };
 
576
        KeySym keysym;
 
577
        int    index, size, mask;
 
578
 
 
579
        size = (sizeof (maskTable) / sizeof (int)) * modmap->max_keypermod;
 
580
 
 
581
        for (i = 0; i < size; i++)
 
582
        {
 
583
            if (!modmap->modifiermap[i])
 
584
                continue;
 
585
 
 
586
            index = 0;
 
587
            do
 
588
            {
 
589
                keysym = XKeycodeToKeysym (d->display,
 
590
                                           modmap->modifiermap[i],
 
591
                                           index++);
 
592
            } while (!keysym && index < keysymsPerKeycode);
 
593
 
 
594
            if (keysym)
 
595
            {
 
596
                mask = maskTable[i / modmap->max_keypermod];
 
597
 
 
598
                if (keysym == XK_Alt_L ||
 
599
                    keysym == XK_Alt_R)
 
600
                {
 
601
                    modMask[CompModAlt] |= mask;
 
602
                }
 
603
                else if (keysym == XK_Meta_L ||
 
604
                         keysym == XK_Meta_R)
 
605
                {
 
606
                    modMask[CompModMeta] |= mask;
 
607
                }
 
608
                else if (keysym == XK_Super_L ||
 
609
                         keysym == XK_Super_R)
 
610
                {
 
611
                    modMask[CompModSuper] |= mask;
 
612
                }
 
613
                else if (keysym == XK_Hyper_L ||
 
614
                         keysym == XK_Hyper_R)
 
615
                {
 
616
                    modMask[CompModHyper] |= mask;
 
617
                }
 
618
                else if (keysym == XK_Mode_switch)
 
619
                {
 
620
                    modMask[CompModModeSwitch] |= mask;
 
621
                }
 
622
                else if (keysym == XK_Scroll_Lock)
 
623
                {
 
624
                    modMask[CompModScrollLock] |= mask;
 
625
                }
 
626
                else if (keysym == XK_Num_Lock)
 
627
                {
 
628
                    modMask[CompModNumLock] |= mask;
 
629
                }
 
630
            }
 
631
        }
 
632
 
 
633
        if (modmap)
 
634
            XFreeModifiermap (modmap);
 
635
 
 
636
        for (i = 0; i < CompModNum; i++)
 
637
        {
 
638
            if (!modMask[i])
 
639
                modMask[i] = CompNoMask;
 
640
        }
 
641
 
 
642
        if (memcmp (modMask, d->modMask, sizeof (modMask)))
 
643
        {
 
644
            CompScreen *s;
 
645
 
 
646
            memcpy (d->modMask, modMask, sizeof (modMask));
 
647
 
 
648
            d->ignoredModMask = LockMask |
 
649
                (modMask[CompModNumLock]    & ~CompNoMask) |
 
650
                (modMask[CompModScrollLock] & ~CompNoMask);
 
651
 
 
652
            for (s = d->screens; s; s = s->next)
 
653
                updatePassiveGrabs (s);
 
654
        }
 
655
    }
 
656
}
 
657
 
 
658
unsigned int
 
659
virtualToRealModMask (CompDisplay  *d,
 
660
                      unsigned int modMask)
 
661
{
 
662
    int i;
 
663
 
 
664
    for (i = 0; i < CompModNum; i++)
 
665
    {
 
666
        if (modMask & virtualModMask[i])
 
667
        {
 
668
            modMask &= ~virtualModMask[i];
 
669
            modMask |= d->modMask[i];
 
670
        }
 
671
    }
 
672
 
 
673
    return (modMask & ~(CompPressMask | CompReleaseMask));
 
674
}
 
675
 
 
676
static unsigned int
 
677
realToVirtualModMask (CompDisplay  *d,
 
678
                      unsigned int modMask)
 
679
{
 
680
    int i;
 
681
 
 
682
    for (i = 0; i < CompModNum; i++)
 
683
    {
 
684
        if (modMask & d->modMask[i])
 
685
            modMask |= virtualModMask[i];
 
686
    }
 
687
 
 
688
    return modMask;
 
689
}
 
690
 
 
691
void
 
692
eventLoop (void)
 
693
{
 
694
    XEvent         event;
 
695
    struct pollfd  ufd;
 
696
    int            timeDiff;
 
697
    struct timeval tv;
 
698
    Region         tmpRegion;
 
699
    CompDisplay    *display = compDisplays;
 
700
    CompScreen     *s = display->screens;
 
701
    int            timeToNextRedraw = 0;
 
702
    CompWindow     *move = 0;
 
703
    int            px = 0, py = 0;
 
704
    int            moveX = 0, moveY = 0;
 
705
    CompTimeout    *t;
 
706
    Bool           idle = TRUE;
 
707
 
 
708
    tmpRegion = XCreateRegion ();
 
709
    if (!tmpRegion)
 
710
    {
 
711
        fprintf (stderr, "%s: Couldn't create region\n", programName);
 
712
        return;
 
713
    }
 
714
 
 
715
    ufd.fd = ConnectionNumber (display->display);
 
716
    ufd.events = POLLIN;
 
717
 
 
718
    for (;;)
 
719
    {
 
720
        if (display->dirtyPluginList)
 
721
            updatePlugins (display);
 
722
 
 
723
        if (restartSignal)
 
724
        {
 
725
             execvp (programName, programArgv);
 
726
             exit (1);
 
727
        }
 
728
 
 
729
        while (XPending (display->display))
 
730
        {
 
731
            XNextEvent (display->display, &event);
 
732
 
 
733
            /* translate root window coordinates */
 
734
            if (testMode)
 
735
            {
 
736
                Window root, child;
 
737
 
 
738
                switch (event.type) {
 
739
                case ButtonPress:
 
740
                    if (!move)
 
741
                    {
 
742
                        px = event.xbutton.x;
 
743
                        py = event.xbutton.y;
 
744
 
 
745
                        move = findWindowAt (display, event.xbutton.window,
 
746
                                             px, py);
 
747
                        if (move)
 
748
                        {
 
749
                            moveX = move->attrib.x;
 
750
                            moveY = move->attrib.y;
 
751
                            XRaiseWindow (display->display, move->id);
 
752
                            continue;
 
753
                        }
 
754
                    }
 
755
                    /* fall-through */
 
756
                case ButtonRelease:
 
757
                    move = 0;
 
758
 
 
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,
 
767
                                           &child);
 
768
                    event.xbutton.root = root;
 
769
                    break;
 
770
                case KeyPress:
 
771
                case KeyRelease:
 
772
                    root = translateToRootWindow (display, event.xkey.window);
 
773
                    XTranslateCoordinates (display->display,
 
774
                                           event.xkey.root, root,
 
775
                                           event.xkey.x_root,
 
776
                                           event.xkey.y_root,
 
777
                                           &event.xkey.x_root,
 
778
                                           &event.xkey.y_root,
 
779
                                           &child);
 
780
                    event.xkey.root = root;
 
781
                    break;
 
782
                case MotionNotify:
 
783
                    if (move)
 
784
                    {
 
785
                        moveX += event.xbutton.x - px;
 
786
                        moveY += event.xbutton.y - py;
 
787
                        px = event.xbutton.x;
 
788
                        py = event.xbutton.y;
 
789
 
 
790
                        XMoveWindow (display->display, move->id, moveX, moveY);
 
791
 
 
792
                        continue;
 
793
                    }
 
794
 
 
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,
 
803
                                           &child);
 
804
                    event.xmotion.root = root;
 
805
                default:
 
806
                    break;
 
807
                }
 
808
            }
 
809
 
 
810
            /* add virtual modifiers */
 
811
            switch (event.type) {
 
812
            case ButtonPress:
 
813
                event.xbutton.state |= CompPressMask;
 
814
                event.xbutton.state =
 
815
                    realToVirtualModMask (display, event.xbutton.state);
 
816
                break;
 
817
            case ButtonRelease:
 
818
                event.xbutton.state |= CompReleaseMask;
 
819
                event.xbutton.state =
 
820
                    realToVirtualModMask (display, event.xbutton.state);
 
821
                break;
 
822
            case KeyPress:
 
823
                event.xkey.state |= CompPressMask;
 
824
                event.xkey.state = realToVirtualModMask (display,
 
825
                                                         event.xkey.state);
 
826
                break;
 
827
            case KeyRelease:
 
828
                event.xkey.state |= CompReleaseMask;
 
829
                event.xkey.state = realToVirtualModMask (display,
 
830
                                                         event.xkey.state);
 
831
                break;
 
832
            case MotionNotify:
 
833
                event.xmotion.state =
 
834
                    realToVirtualModMask (display, event.xmotion.state);
 
835
                break;
 
836
            default:
 
837
                break;
 
838
            }
 
839
 
 
840
            sn_display_process_event (display->snDisplay, &event);
 
841
 
 
842
            (*display->handleEvent) (display, &event);
 
843
        }
 
844
 
 
845
        if (s->damageMask)
 
846
        {
 
847
            /* sync with server */
 
848
            glFinish ();
 
849
 
 
850
            timeToNextRedraw = getTimeToNextRedraw (s, &s->lastRedraw, idle);
 
851
            if (timeToNextRedraw)
 
852
                timeToNextRedraw = poll (&ufd, 1, timeToNextRedraw);
 
853
 
 
854
            if (timeToNextRedraw == 0)
 
855
            {
 
856
                gettimeofday (&tv, 0);
 
857
 
 
858
                timeDiff = TIMEVALDIFF (&tv, &s->lastRedraw);
 
859
 
 
860
                s->stencilRef = 0;
 
861
 
 
862
                (*s->preparePaintScreen) (s, idle ? s->redrawTime : timeDiff);
 
863
 
 
864
                if (s->damageMask & COMP_SCREEN_DAMAGE_REGION_MASK)
 
865
                {
 
866
                    XIntersectRegion (s->damage, &s->region, tmpRegion);
 
867
 
 
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)
 
873
                        damageScreen (s);
 
874
                }
 
875
 
 
876
                EMPTY_REGION (s->damage);
 
877
 
 
878
                if (s->damageMask & COMP_SCREEN_DAMAGE_ALL_MASK)
 
879
                {
 
880
                    s->damageMask = 0;
 
881
 
 
882
                    (*s->paintScreen) (s,
 
883
                                       &defaultScreenPaintAttrib,
 
884
                                       &s->region,
 
885
                                       PAINT_SCREEN_REGION_MASK |
 
886
                                       PAINT_SCREEN_FULL_MASK);
 
887
 
 
888
                    glXSwapBuffers (s->display->display, s->root);
 
889
                }
 
890
                else if (s->damageMask & COMP_SCREEN_DAMAGE_REGION_MASK)
 
891
                {
 
892
                    s->damageMask = 0;
 
893
 
 
894
                    if ((*s->paintScreen) (s,
 
895
                                           &defaultScreenPaintAttrib,
 
896
                                           tmpRegion,
 
897
                                           PAINT_SCREEN_REGION_MASK))
 
898
                    {
 
899
                        BoxPtr pBox;
 
900
                        int    nBox, y;
 
901
 
 
902
                        /*
 
903
                        pBox = tmpRegion->rects;
 
904
                        nBox = tmpRegion->numRects;
 
905
                        while (nBox--)
 
906
                        {
 
907
                            y = s->height - pBox->y2;
 
908
 
 
909
                            glXCopySubBufferMESA (s->display->display,
 
910
                                                  s->root,
 
911
                                                  pBox->x1, y,
 
912
                                                  pBox->x2 - pBox->x1,
 
913
                                                  pBox->y2 - pBox->y1);
 
914
 
 
915
                            pBox++;
 
916
                        }
 
917
 
 
918
                        */ /* ugly empty rect flush hack */ /*
 
919
                        glXCopySubBufferMESA (s->display->display, s->root,
 
920
                                              0, 0, 0, 0);
 
921
                        */
 
922
 
 
923
                        glEnable (GL_SCISSOR_TEST);
 
924
                        glDrawBuffer (GL_FRONT);
 
925
 
 
926
                        pBox = tmpRegion->rects;
 
927
                        nBox = tmpRegion->numRects;
 
928
                        while (nBox--)
 
929
                        {
 
930
                            y = s->height - pBox->y2;
 
931
 
 
932
                            glBitmap (0, 0, 0, 0,
 
933
                                      pBox->x1 - s->rasterX, y - s->rasterY,
 
934
                                      NULL);
 
935
 
 
936
                            s->rasterX = pBox->x1;
 
937
                            s->rasterY = y;
 
938
 
 
939
                            glScissor (pBox->x1, y,
 
940
                                       pBox->x2 - pBox->x1,
 
941
                                       pBox->y2 - pBox->y1);
 
942
 
 
943
                            glCopyPixels (pBox->x1, y,
 
944
                                          pBox->x2 - pBox->x1,
 
945
                                          pBox->y2 - pBox->y1,
 
946
                                          GL_COLOR);
 
947
 
 
948
                            pBox++;
 
949
                        }
 
950
 
 
951
                        glDrawBuffer (GL_BACK);
 
952
                        glDisable (GL_SCISSOR_TEST);
 
953
                        glFlush ();
 
954
                    }
 
955
                    else
 
956
                    {
 
957
                        (*s->paintScreen) (s,
 
958
                                           &defaultScreenPaintAttrib,
 
959
                                           &s->region,
 
960
                                           PAINT_SCREEN_FULL_MASK);
 
961
 
 
962
                        glXSwapBuffers (s->display->display, s->root);
 
963
                    }
 
964
                }
 
965
 
 
966
                s->lastRedraw = tv;
 
967
 
 
968
                (*s->donePaintScreen) (s);
 
969
 
 
970
                /* remove destroyed windows */
 
971
                while (s->pendingDestroys)
 
972
                {
 
973
                    CompWindow *w;
 
974
 
 
975
                    for (w = s->windows; w; w = w->next)
 
976
                    {
 
977
                        if (w->destroyed)
 
978
                        {
 
979
                            addWindowDamage (w);
 
980
                            removeWindow (w);
 
981
                            break;
 
982
                        }
 
983
                    }
 
984
 
 
985
                    s->pendingDestroys--;
 
986
                }
 
987
            }
 
988
 
 
989
            idle = FALSE;
 
990
        }
 
991
        else
 
992
        {
 
993
            if (timeouts)
 
994
            {
 
995
                if (timeouts->left > 0)
 
996
                    poll (&ufd, 1, timeouts->left);
 
997
 
 
998
                gettimeofday (&tv, 0);
 
999
 
 
1000
                timeDiff = TIMEVALDIFF (&tv, &lastTimeout);
 
1001
 
 
1002
                for (t = timeouts; t; t = t->next)
 
1003
                    t->left -= timeDiff;
 
1004
 
 
1005
                while (timeouts && timeouts->left <= 0)
 
1006
                {
 
1007
                    t = timeouts;
 
1008
                    if ((*t->callBack) (t->closure))
 
1009
                    {
 
1010
                        timeouts = t->next;
 
1011
                        addTimeout (t);
 
1012
                    }
 
1013
                    else
 
1014
                    {
 
1015
                        timeouts = t->next;
 
1016
                        free (t);
 
1017
                    }
 
1018
                }
 
1019
 
 
1020
                lastTimeout = tv;
 
1021
            }
 
1022
            else
 
1023
            {
 
1024
                poll (&ufd, 1, 1000);
 
1025
            }
 
1026
 
 
1027
            idle = TRUE;
 
1028
        }
 
1029
    }
 
1030
}
 
1031
 
 
1032
static int errors = 0;
 
1033
 
 
1034
static int
 
1035
errorHandler (Display     *dpy,
 
1036
              XErrorEvent *e)
 
1037
{
 
1038
 
 
1039
#ifdef DEBUG
 
1040
    char str[128];
 
1041
    char *name = 0;
 
1042
    int  o;
 
1043
#endif
 
1044
 
 
1045
    errors++;
 
1046
 
 
1047
#ifdef DEBUG
 
1048
    XGetErrorDatabaseText (dpy, "XlibMessage", "XError", "", str, 128);
 
1049
    fprintf (stderr, "%s", str);
 
1050
 
 
1051
    o = e->error_code - compDisplays->damageError;
 
1052
    switch (o) {
 
1053
    case BadDamage:
 
1054
        name = "BadDamage";
 
1055
        break;
 
1056
    default:
 
1057
        break;
 
1058
    }
 
1059
 
 
1060
    if (name)
 
1061
    {
 
1062
        fprintf (stderr, ": %s\n  ", name);
 
1063
    }
 
1064
    else
 
1065
    {
 
1066
        XGetErrorText (dpy, e->error_code, str, 128);
 
1067
        fprintf (stderr, ": %s\n  ", str);
 
1068
    }
 
1069
 
 
1070
    XGetErrorDatabaseText (dpy, "XlibMessage", "MajorCode", "%d", str, 128);
 
1071
    fprintf (stderr, str, e->request_code);
 
1072
 
 
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  ");
 
1078
 
 
1079
    XGetErrorDatabaseText (dpy, "XlibMessage", "MinorCode", "%d", str, 128);
 
1080
    fprintf (stderr, str, e->minor_code);
 
1081
    fprintf (stderr, "\n  ");
 
1082
 
 
1083
    XGetErrorDatabaseText (dpy, "XlibMessage", "ResourceID", "%d", str, 128);
 
1084
    fprintf (stderr, str, e->resourceid);
 
1085
    fprintf (stderr, "\n");
 
1086
 
 
1087
    /* abort (); */
 
1088
#endif
 
1089
 
 
1090
    return 0;
 
1091
}
 
1092
 
 
1093
int
 
1094
compCheckForError (Display *dpy)
 
1095
{
 
1096
    int e;
 
1097
 
 
1098
    XSync (dpy, FALSE);
 
1099
 
 
1100
    e = errors;
 
1101
    errors = 0;
 
1102
 
 
1103
    return e;
 
1104
}
 
1105
 
 
1106
#define PING_DELAY 5000
 
1107
 
 
1108
static Bool
 
1109
pingTimeout (void *closure)
 
1110
{
 
1111
    CompDisplay *d = closure;
 
1112
    CompScreen  *s;
 
1113
    CompWindow  *w;
 
1114
    XEvent      ev;
 
1115
    int         ping = d->lastPing + 1;
 
1116
 
 
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;
 
1126
 
 
1127
    for (s = d->screens; s; s = s->next)
 
1128
    {
 
1129
        for (w = s->windows; w; w = w->next)
 
1130
        {
 
1131
            if (w->attrib.map_state != IsViewable)
 
1132
                continue;
 
1133
 
 
1134
            if (!(w->type & CompWindowTypeNormalMask))
 
1135
                continue;
 
1136
 
 
1137
            if (w->protocols & CompWindowProtocolPingMask)
 
1138
            {
 
1139
                if (w->transientFor)
 
1140
                    continue;
 
1141
 
 
1142
                if (w->lastPong < d->lastPing)
 
1143
                {
 
1144
                    if (w->alive)
 
1145
                    {
 
1146
                        w->alive            = FALSE;
 
1147
                        w->paint.saturation = 0;
 
1148
 
 
1149
                        addWindowDamage (w);
 
1150
                    }
 
1151
                }
 
1152
 
 
1153
                ev.xclient.window    = w->id;
 
1154
                ev.xclient.data.l[2] = w->id;
 
1155
 
 
1156
                XSendEvent (d->display, w->id, FALSE, NoEventMask, &ev);
 
1157
            }
 
1158
        }
 
1159
    }
 
1160
 
 
1161
    d->lastPing = ping;
 
1162
 
 
1163
    return TRUE;
 
1164
}
 
1165
 
 
1166
Bool
 
1167
addDisplay (char *name,
 
1168
            char **plugin,
 
1169
            int  nPlugin)
 
1170
{
 
1171
    CompDisplay *d;
 
1172
    Display     *dpy;
 
1173
    Window      focus;
 
1174
    int         revertTo, i;
 
1175
 
 
1176
    d = &compDisplay;
 
1177
 
 
1178
    if (displayPrivateLen)
 
1179
    {
 
1180
        d->privates = malloc (displayPrivateLen * sizeof (CompPrivate));
 
1181
        if (!d->privates)
 
1182
            return FALSE;
 
1183
    }
 
1184
    else
 
1185
        d->privates = 0;
 
1186
 
 
1187
    d->screenPrivateIndices = 0;
 
1188
    d->screenPrivateLen     = 0;
 
1189
 
 
1190
    for (i = 0; i < CompModNum; i++)
 
1191
        d->modMask[i] = CompNoMask;
 
1192
 
 
1193
    d->ignoredModMask = LockMask;
 
1194
 
 
1195
    d->plugin.list.type   = CompOptionTypeString;
 
1196
    d->plugin.list.nValue = 0;
 
1197
    d->plugin.list.value  = 0;
 
1198
 
 
1199
    compDisplayInitOptions (d, plugin, nPlugin);
 
1200
 
 
1201
    d->textureFilter = GL_LINEAR;
 
1202
    d->below         = None;
 
1203
 
 
1204
    d->activeWindow = 0;
 
1205
 
 
1206
    d->autoRaiseHandle = 0;
 
1207
    d->autoRaiseWindow = None;
 
1208
 
 
1209
    d->display = dpy = XOpenDisplay (name);
 
1210
    if (!d->display)
 
1211
    {
 
1212
        fprintf (stderr, "%s: Couldn't open display %s\n",
 
1213
                 programName, XDisplayName (name));
 
1214
        return FALSE;
 
1215
    }
 
1216
 
 
1217
    snprintf (d->displayString, 255, "DISPLAY=%s", DisplayString (dpy));
 
1218
 
 
1219
#ifdef DEBUG
 
1220
    XSynchronize (dpy, TRUE);
 
1221
#endif
 
1222
 
 
1223
    XSetErrorHandler (errorHandler);
 
1224
 
 
1225
    updateModifierMappings (d);
 
1226
 
 
1227
    d->setDisplayOption          = setDisplayOption;
 
1228
    d->setDisplayOptionForPlugin = setDisplayOptionForPlugin;
 
1229
 
 
1230
    d->initPluginForDisplay = initPluginForDisplay;
 
1231
    d->finiPluginForDisplay = finiPluginForDisplay;
 
1232
 
 
1233
    d->handleEvent = handleEvent;
 
1234
 
 
1235
    d->supportedAtom         = XInternAtom (dpy, "_NET_SUPPORTED", 0);
 
1236
    d->supportingWmCheckAtom = XInternAtom (dpy, "_NET_SUPPORTING_WM_CHECK", 0);
 
1237
 
 
1238
    d->utf8StringAtom = XInternAtom (dpy, "UTF8_STRING", 0);
 
1239
 
 
1240
    d->wmNameAtom = XInternAtom (dpy, "_NET_WM_NAME", 0);
 
1241
 
 
1242
    d->winTypeAtom        = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE", 0);
 
1243
    d->winTypeDesktopAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DESKTOP",
 
1244
                                         0);
 
1245
    d->winTypeDockAtom    = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DOCK", 0);
 
1246
    d->winTypeToolbarAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR",
 
1247
                                         0);
 
1248
    d->winTypeMenuAtom    = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_MENU", 0);
 
1249
    d->winTypeUtilAtom    = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_UTILITY",
 
1250
                                         0);
 
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);
 
1254
 
 
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);
 
1258
 
 
1259
    d->winActiveAtom = XInternAtom (dpy, "_NET_ACTIVE_WINDOW", 0);
 
1260
 
 
1261
    d->workareaAtom = XInternAtom (dpy, "_NET_WORKAREA", 0);
 
1262
 
 
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);
 
1267
 
 
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);
 
1295
 
 
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);
 
1308
 
 
1309
    d->wmAllowedActionsAtom = XInternAtom (dpy, "_NET_WM_ALLOWED_ACTIONS", 0);
 
1310
 
 
1311
    d->wmStrutAtom        = XInternAtom (dpy, "_NET_WM_STRUT", 0);
 
1312
    d->wmStrutPartialAtom = XInternAtom (dpy, "_NET_WM_STRUT_PARTIAL", 0);
 
1313
 
 
1314
    d->clientListAtom         = XInternAtom (dpy, "_NET_CLIENT_LIST", 0);
 
1315
    d->clientListStackingAtom =
 
1316
        XInternAtom (dpy, "_NET_CLIENT_LIST_STACKING", 0);
 
1317
 
 
1318
    d->frameExtentsAtom = XInternAtom (dpy, "_NET_FRAME_EXTENTS", 0);
 
1319
    d->frameWindowAtom  = XInternAtom (dpy, "_NET_FRAME_WINDOW", 0);
 
1320
 
 
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);
 
1325
 
 
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);
 
1330
 
 
1331
    d->wmSyncRequestCounterAtom =
 
1332
        XInternAtom (dpy, "_NET_WM_SYNC_REQUEST_COUNTER", 0);
 
1333
 
 
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);
 
1337
 
 
1338
    d->showingDesktopAtom = XInternAtom (dpy, "_NET_SHOWING_DESKTOP", 0);
 
1339
 
 
1340
    d->xBackgroundAtom[0] = XInternAtom (dpy, "_XSETROOT_ID", 0);
 
1341
    d->xBackgroundAtom[1] = XInternAtom (dpy, "_XROOTPMAP_ID", 0);
 
1342
 
 
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);
 
1348
 
 
1349
    d->mwmHintsAtom = XInternAtom (dpy, "_MOTIF_WM_HINTS", 0);
 
1350
 
 
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);
 
1357
 
 
1358
    d->snDisplay = sn_display_new (dpy, NULL, NULL);
 
1359
    if (!d->snDisplay)
 
1360
        return FALSE;
 
1361
 
 
1362
    d->lastPing = 1;
 
1363
 
 
1364
    if (testMode)
 
1365
    {
 
1366
        d->compositeOpcode = MAXSHORT;
 
1367
        d->compositeEvent  = MAXSHORT;
 
1368
        d->compositeError  = MAXSHORT;
 
1369
 
 
1370
        d->damageEvent = MAXSHORT;
 
1371
        d->damageError = MAXSHORT;
 
1372
    }
 
1373
    else
 
1374
    {
 
1375
        int compositeMajor, compositeMinor;
 
1376
 
 
1377
        if (!XQueryExtension (dpy,
 
1378
                              COMPOSITE_NAME,
 
1379
                              &d->compositeOpcode,
 
1380
                              &d->compositeEvent,
 
1381
                              &d->compositeError))
 
1382
        {
 
1383
            fprintf (stderr, "%s: No composite extension\n", programName);
 
1384
            return FALSE;
 
1385
        }
 
1386
 
 
1387
        XCompositeQueryVersion (dpy, &compositeMajor, &compositeMinor);
 
1388
        if (compositeMajor == 0 && compositeMinor < 2)
 
1389
        {
 
1390
            fprintf (stderr, "%s: Old composite extension\n", programName);
 
1391
            return FALSE;
 
1392
        }
 
1393
 
 
1394
        if (!XDamageQueryExtension (dpy, &d->damageEvent, &d->damageError))
 
1395
        {
 
1396
            fprintf (stderr, "%s: No damage extension\n", programName);
 
1397
            return FALSE;
 
1398
        }
 
1399
 
 
1400
        if (!XRRQueryExtension (dpy, &d->randrEvent, &d->randrError))
 
1401
        {
 
1402
            fprintf (stderr, "%s: No RandR extension\n", programName);
 
1403
            return FALSE;
 
1404
        }
 
1405
 
 
1406
        if (!XSyncQueryExtension (dpy, &d->syncEvent, &d->syncError))
 
1407
        {
 
1408
            fprintf (stderr, "%s: No sync extension\n", programName);
 
1409
            return FALSE;
 
1410
        }
 
1411
    }
 
1412
 
 
1413
    d->shapeExtension = XShapeQueryExtension (dpy,
 
1414
                                              &d->shapeEvent,
 
1415
                                              &d->shapeError);
 
1416
 
 
1417
    compDisplays = d;
 
1418
 
 
1419
    if (testMode)
 
1420
    {
 
1421
        addScreen (d, 0, None, 0, 0);
 
1422
    }
 
1423
    else
 
1424
    {
 
1425
        for (i = 0; i < ScreenCount (dpy); i++)
 
1426
        {
 
1427
            Window               newWmSnOwner = None;
 
1428
            Atom                 wmSnAtom = 0;
 
1429
            Time                 wmSnTimestamp = 0;
 
1430
            XEvent               event;
 
1431
            XSetWindowAttributes attr;
 
1432
            Window               currentWmSnOwner;
 
1433
            char                 buf[128];
 
1434
 
 
1435
            sprintf (buf, "WM_S%d", i);
 
1436
            wmSnAtom = XInternAtom (dpy, buf, 0);
 
1437
 
 
1438
            currentWmSnOwner = XGetSelectionOwner (dpy, wmSnAtom);
 
1439
 
 
1440
            if (currentWmSnOwner != None)
 
1441
            {
 
1442
                if (!replaceCurrentWm)
 
1443
                {
 
1444
                    fprintf (stderr,
 
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));
 
1450
 
 
1451
                    continue;
 
1452
                }
 
1453
 
 
1454
                XSelectInput (dpy, currentWmSnOwner,
 
1455
                              StructureNotifyMask);
 
1456
            }
 
1457
 
 
1458
            attr.override_redirect = TRUE;
 
1459
            attr.event_mask        = PropertyChangeMask;
 
1460
 
 
1461
            newWmSnOwner =
 
1462
                XCreateWindow (dpy, XRootWindow (dpy, i),
 
1463
                               -100, -100, 1, 1, 0,
 
1464
                               CopyFromParent, CopyFromParent,
 
1465
                               CopyFromParent,
 
1466
                               CWOverrideRedirect | CWEventMask,
 
1467
                               &attr);
 
1468
 
 
1469
            XChangeProperty (dpy,
 
1470
                             newWmSnOwner,
 
1471
                             d->wmNameAtom,
 
1472
                             d->utf8StringAtom, 8,
 
1473
                             PropModeReplace,
 
1474
                             (unsigned char *) PACKAGE,
 
1475
                             strlen (PACKAGE));
 
1476
 
 
1477
            XWindowEvent (dpy,
 
1478
                          newWmSnOwner,
 
1479
                          PropertyChangeMask,
 
1480
                          &event);
 
1481
 
 
1482
            wmSnTimestamp = event.xproperty.time;
 
1483
 
 
1484
            XSetSelectionOwner (dpy, wmSnAtom, newWmSnOwner,
 
1485
                                wmSnTimestamp);
 
1486
 
 
1487
            if (XGetSelectionOwner (dpy, wmSnAtom) != newWmSnOwner)
 
1488
            {
 
1489
                fprintf (stderr,
 
1490
                         "%s: Could not acquire window manager "
 
1491
                         "selection on screen %d display \"%s\"\n",
 
1492
                         programName, i, DisplayString (dpy));
 
1493
 
 
1494
                XDestroyWindow (dpy, newWmSnOwner);
 
1495
 
 
1496
                continue;
 
1497
            }
 
1498
 
 
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;
 
1509
 
 
1510
            XSendEvent (dpy, XRootWindow (dpy, i), FALSE,
 
1511
                        StructureNotifyMask, &event);
 
1512
 
 
1513
            /* Wait for old window manager to go away */
 
1514
            if (currentWmSnOwner != None)
 
1515
            {
 
1516
                do {
 
1517
                    XWindowEvent (dpy, currentWmSnOwner,
 
1518
                                  StructureNotifyMask, &event);
 
1519
                } while (event.type != DestroyNotify);
 
1520
            }
 
1521
 
 
1522
            compCheckForError (dpy);
 
1523
 
 
1524
            XCompositeRedirectSubwindows (dpy, XRootWindow (dpy, i),
 
1525
                                          CompositeRedirectManual);
 
1526
 
 
1527
            if (compCheckForError (dpy))
 
1528
            {
 
1529
                fprintf (stderr, "%s: Another composite manager is already "
 
1530
                         "running on screen: %d\n", programName, i);
 
1531
 
 
1532
                continue;
 
1533
            }
 
1534
 
 
1535
            XSelectInput (dpy, XRootWindow (dpy, i),
 
1536
                          SubstructureRedirectMask |
 
1537
                          SubstructureNotifyMask   |
 
1538
                          StructureNotifyMask      |
 
1539
                          PropertyChangeMask       |
 
1540
                          LeaveWindowMask          |
 
1541
                          EnterWindowMask          |
 
1542
                          KeyPressMask             |
 
1543
                          KeyReleaseMask           |
 
1544
                          FocusChangeMask          |
 
1545
                          ExposureMask);
 
1546
 
 
1547
            if (compCheckForError (dpy))
 
1548
            {
 
1549
                fprintf (stderr, "%s: Another window manager is "
 
1550
                         "already running on screen: %d\n",
 
1551
                         programName, i);
 
1552
 
 
1553
                continue;
 
1554
            }
 
1555
 
 
1556
            if (!addScreen (d, i, newWmSnOwner, wmSnAtom, wmSnTimestamp))
 
1557
            {
 
1558
                fprintf (stderr, "%s: Failed to manage screen: %d\n",
 
1559
                         programName, i);
 
1560
            }
 
1561
        }
 
1562
    }
 
1563
 
 
1564
    if (!d->screens)
 
1565
    {
 
1566
        fprintf (stderr, "%s: No managable screens found on display %s\n",
 
1567
                 programName, XDisplayName (name));
 
1568
        return FALSE;
 
1569
    }
 
1570
 
 
1571
    XGetInputFocus (dpy, &focus, &revertTo);
 
1572
 
 
1573
    if (focus == None || focus == PointerRoot)
 
1574
    {
 
1575
        focusDefaultWindow (d);
 
1576
    }
 
1577
    else
 
1578
    {
 
1579
        CompWindow *w;
 
1580
 
 
1581
        w = findWindowAtDisplay (d, focus);
 
1582
        if (w)
 
1583
        {
 
1584
            moveInputFocusToWindow (w);
 
1585
        }
 
1586
        else
 
1587
            focusDefaultWindow (d);
 
1588
    }
 
1589
 
 
1590
    d->pingHandle = compAddTimeout (PING_DELAY, pingTimeout, d);
 
1591
 
 
1592
    return TRUE;
 
1593
}
 
1594
 
 
1595
void
 
1596
focusDefaultWindow (CompDisplay *d)
 
1597
{
 
1598
    CompScreen *s;
 
1599
    CompWindow *w;
 
1600
    CompWindow *focus = NULL;
 
1601
 
 
1602
    for (s = d->screens; s; s = s->next)
 
1603
    {
 
1604
        for (w = s->reverseWindows; w; w = w->prev)
 
1605
        {
 
1606
            if (w->type & CompWindowTypeDockMask)
 
1607
                continue;
 
1608
 
 
1609
            if ((*s->focusWindow) (w))
 
1610
            {
 
1611
                if (focus)
 
1612
                {
 
1613
                    if (w->type & (CompWindowTypeNormalMask |
 
1614
                                   CompWindowTypeDialogMask |
 
1615
                                   CompWindowTypeModalDialogMask))
 
1616
                    {
 
1617
                        if (w->activeNum > focus->activeNum)
 
1618
                            focus = w;
 
1619
                    }
 
1620
                }
 
1621
                else
 
1622
                    focus = w;
 
1623
            }
 
1624
        }
 
1625
    }
 
1626
 
 
1627
    if (focus)
 
1628
    {
 
1629
        if (focus->id != d->activeWindow)
 
1630
            moveInputFocusToWindow (focus);
 
1631
    }
 
1632
    else
 
1633
    {
 
1634
        XSetInputFocus (d->display, d->screens->root, RevertToPointerRoot,
 
1635
                        CurrentTime);
 
1636
    }
 
1637
}
 
1638
 
 
1639
CompScreen *
 
1640
findScreenAtDisplay (CompDisplay *d,
 
1641
                     Window      root)
 
1642
{
 
1643
    CompScreen *s;
 
1644
 
 
1645
    for (s = d->screens; s; s = s->next)
 
1646
    {
 
1647
        if (s->root == root)
 
1648
            return s;
 
1649
    }
 
1650
 
 
1651
    return 0;
 
1652
}
 
1653
 
 
1654
void
 
1655
forEachWindowOnDisplay (CompDisplay       *display,
 
1656
                        ForEachWindowProc proc,
 
1657
                        void              *closure)
 
1658
{
 
1659
    CompScreen *s;
 
1660
 
 
1661
    for (s = display->screens; s; s = s->next)
 
1662
        forEachWindowOnScreen (s, proc, closure);
 
1663
}
 
1664
 
 
1665
CompWindow *
 
1666
findWindowAtDisplay (CompDisplay *d,
 
1667
                     Window      id)
 
1668
{
 
1669
    if (lastFoundWindow && lastFoundWindow->id == id)
 
1670
    {
 
1671
        return lastFoundWindow;
 
1672
    }
 
1673
    else
 
1674
    {
 
1675
        CompScreen *s;
 
1676
        CompWindow *w;
 
1677
 
 
1678
        for (s = d->screens; s; s = s->next)
 
1679
        {
 
1680
            w = findWindowAtScreen (s, id);
 
1681
            if (w)
 
1682
                return w;
 
1683
        }
 
1684
    }
 
1685
 
 
1686
    return 0;
 
1687
}
 
1688
 
 
1689
static CompScreen *
 
1690
findScreenForSelection (CompDisplay *display,
 
1691
                        Window       owner,
 
1692
                        Atom         selection)
 
1693
{
 
1694
    CompScreen *s;
 
1695
 
 
1696
    for (s = display->screens; s; s = s->next)
 
1697
    {
 
1698
        if (s->wmSnSelectionWindow == owner && s->wmSnAtom == selection)
 
1699
            return s;
 
1700
    }
 
1701
 
 
1702
    return NULL;
 
1703
}
 
1704
 
 
1705
/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
 
1706
static Bool
 
1707
convertProperty (CompDisplay *display,
 
1708
                 CompScreen  *screen,
 
1709
                 Window      w,
 
1710
                 Atom        target,
 
1711
                 Atom        property)
 
1712
{
 
1713
 
 
1714
#define N_TARGETS 4
 
1715
 
 
1716
    Atom conversionTargets[N_TARGETS];
 
1717
    long icccmVersion[] = { 2, 0 };
 
1718
 
 
1719
    conversionTargets[0] = display->targetsAtom;
 
1720
    conversionTargets[1] = display->multipleAtom;
 
1721
    conversionTargets[2] = display->timestampAtom;
 
1722
    conversionTargets[3] = display->versionAtom;
 
1723
 
 
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);
 
1736
    else
 
1737
        return FALSE;
 
1738
 
 
1739
    /* Be sure the PropertyNotify has arrived so we
 
1740
     * can send SelectionNotify
 
1741
     */
 
1742
    XSync (display->display, FALSE);
 
1743
 
 
1744
    return TRUE;
 
1745
}
 
1746
 
 
1747
/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
 
1748
void
 
1749
handleSelectionRequest (CompDisplay *display,
 
1750
                        XEvent      *event)
 
1751
{
 
1752
    XSelectionEvent reply;
 
1753
    CompScreen      *screen;
 
1754
 
 
1755
    screen = findScreenForSelection (display,
 
1756
                                     event->xselectionrequest.owner,
 
1757
                                     event->xselectionrequest.selection);
 
1758
    if (!screen)
 
1759
        return;
 
1760
 
 
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;
 
1768
 
 
1769
    if (event->xselectionrequest.target == display->multipleAtom)
 
1770
    {
 
1771
        if (event->xselectionrequest.property != None)
 
1772
        {
 
1773
            Atom          type, *adata;
 
1774
            int           i, format;
 
1775
            unsigned long num, rest;
 
1776
            unsigned char *data;
 
1777
 
 
1778
            if (XGetWindowProperty (display->display,
 
1779
                                    event->xselectionrequest.requestor,
 
1780
                                    event->xselectionrequest.property,
 
1781
                                    0, 256, FALSE,
 
1782
                                    display->atomPairAtom,
 
1783
                                    &type, &format, &num, &rest,
 
1784
                                    &data) != Success)
 
1785
                return;
 
1786
 
 
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
 
1790
             */
 
1791
            adata = (Atom *) data;
 
1792
            i = 0;
 
1793
            while (i < (int) num)
 
1794
            {
 
1795
                if (!convertProperty (display, screen,
 
1796
                                      event->xselectionrequest.requestor,
 
1797
                                      adata[i], adata[i + 1]))
 
1798
                    adata[i + 1] = None;
 
1799
 
 
1800
                i += 2;
 
1801
            }
 
1802
 
 
1803
            XChangeProperty (display->display,
 
1804
                             event->xselectionrequest.requestor,
 
1805
                             event->xselectionrequest.property,
 
1806
                             display->atomPairAtom,
 
1807
                             32, PropModeReplace, data, num);
 
1808
        }
 
1809
    }
 
1810
    else
 
1811
    {
 
1812
        if (event->xselectionrequest.property == None)
 
1813
            event->xselectionrequest.property = event->xselectionrequest.target;
 
1814
 
 
1815
        if (convertProperty (display, screen,
 
1816
                             event->xselectionrequest.requestor,
 
1817
                             event->xselectionrequest.target,
 
1818
                             event->xselectionrequest.property))
 
1819
            reply.property = event->xselectionrequest.property;
 
1820
    }
 
1821
 
 
1822
    XSendEvent (display->display,
 
1823
                event->xselectionrequest.requestor,
 
1824
                FALSE, 0L, (XEvent *) &reply);
 
1825
}
 
1826
 
 
1827
void
 
1828
handleSelectionClear (CompDisplay *display,
 
1829
                      XEvent      *event)
 
1830
{
 
1831
    /* We need to unmanage the screen on which we lost the selection */
 
1832
    CompScreen *screen;
 
1833
 
 
1834
    screen = findScreenForSelection (display,
 
1835
                                     event->xselectionclear.window,
 
1836
                                     event->xselectionclear.selection);
 
1837
 
 
1838
    if (!screen)
 
1839
        return;
 
1840
 
 
1841
    /* removeScreen (screen); */
 
1842
 
 
1843
    exit (0);
 
1844
}