chiark / gitweb /
Imported Upstream version 1.0.0
[e16] / src / ecompmgr.c
1 /*
2  * Copyright (C) 2004-2009 Kim Woelders
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies of the Software, its documentation and marketing & publicity
13  * materials, and acknowledgment shall be given in the documentation, materials
14  * and software packages that this Software was used.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 /*
24  * This code was originally derived from xcompmgr.c,  see original copyright
25  * notice at end.
26  * It has been mostly rewritten since, only the shadow code is more or less
27  * intact.
28  */
29
30 #include "E.h"
31 #if USE_COMPOSITE
32 #include "desktops.h"
33 #include "ecompmgr.h"
34 #include "emodule.h"
35 #include "eobj.h"
36 #include "events.h"
37 #include "hints.h"
38 #include "timers.h"
39 #include "windowmatch.h"
40 #include "xwin.h"
41
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <math.h>
46 #include <unistd.h>
47 #include <X11/Xlib.h>
48 #include <X11/Xutil.h>
49 #include <X11/extensions/shape.h>
50 #include <X11/extensions/Xcomposite.h>
51 #include <X11/extensions/Xdamage.h>
52 #include <X11/extensions/Xfixes.h>
53 #include <X11/extensions/Xrender.h>
54
55 #define ENABLE_SHADOWS      1
56
57 #define USE_DESK_EXPOSE     0
58 #define USE_DESK_VISIBILITY 1
59
60 #define USE_CLIP_RELATIVE_TO_DESK 1
61
62 /* Composite Overlay Window (client) availability */
63 #if (1000 * COMPOSITE_MAJOR + COMPOSITE_MINOR) >= 3
64 #define USE_COMPOSITE_OVERLAY_WINDOW 1
65 #else
66 #define USE_COMPOSITE_OVERLAY_WINDOW 0
67 #endif
68
69 #define ENABLE_DEBUG   1
70 #if ENABLE_DEBUG
71 #define D1printf(fmt...) if(EDebug(EDBUG_TYPE_COMPMGR))Eprintf(fmt)
72 #define D2printf(fmt...) if(EDebug(EDBUG_TYPE_COMPMGR2))Eprintf(fmt)
73 #define D3printf(fmt...) if(EDebug(EDBUG_TYPE_COMPMGR3))Eprintf(fmt)
74 #else
75 #define D1printf(fmt...)
76 #define D2printf(fmt...)
77 #define D3printf(fmt...)
78 #endif /* ENABLE_DEBUG */
79
80 #define DEBUG_OPACITY 0
81
82 #define INV_POS     0x01
83 #define INV_SIZE    0x02
84 #define INV_SHAPE   0x04
85 #define INV_CLIP    0x08
86 #define INV_OPACITY 0x10
87 #define INV_SHADOW  0x20
88 #define INV_PIXMAP  0x40
89 #define INV_PICTURE 0x80
90 #define INV_GEOM    (INV_POS | INV_SIZE | INV_SHAPE)
91 #define INV_ALL     (INV_POS | INV_SIZE | INV_CLIP | INV_OPACITY | INV_SHADOW | INV_PIXMAP)
92
93 typedef struct _cmhook ECmWinInfo;
94
95 struct _cmhook {
96    EObj               *next;    /* Paint order */
97    EObj               *prev;    /* Paint order */
98    Pixmap              pixmap;
99    int                 rcx, rcy, rcw, rch;
100    int                 mode;
101    unsigned            damaged:1;
102    unsigned            fadeout:1;
103    unsigned            has_shadow:1;
104    unsigned            have_shape:1;    /* Region validity - shape */
105    unsigned            have_extents:1;  /* Region validity - extents */
106    unsigned            have_clip:1;     /* Region validity - clip */
107    Damage              damage;
108    Picture             picture;
109    Picture             pict_alpha;      /* Solid, current opacity */
110    XserverRegion       shape;
111    XserverRegion       extents;
112    XserverRegion       clip;
113    int                 shape_x, shape_y;
114 #if ENABLE_SHADOWS
115    Picture             shadow_alpha;    /* Solid, sharp * current opacity */
116    Picture             shadow_pict;     /* Blurred shaped shadow */
117    int                 shadow_dx;
118    int                 shadow_dy;
119    int                 shadow_width;
120    int                 shadow_height;
121 #endif
122    unsigned int        opacity;
123
124    unsigned long       damage_sequence; /* sequence when damage was created */
125
126    Animator           *anim_fade;
127    unsigned int        opacity_to;
128 };
129
130 /*
131  * Configuration
132  */
133 #if ENABLE_SHADOWS
134 #define ECM_SHADOWS_OFF      0
135 #define ECM_SHADOWS_SHARP    1  /* use window alpha for shadow; sharp, but precise */
136 #define ECM_SHADOWS_ECHO     3  /* use window for shadow; sharp, but precise */
137 #define ECM_SHADOWS_BLURRED  2  /* use window extents for shadow, blurred */
138 #endif
139
140 #define ECM_OR_UNREDIRECTED  0
141 #define ECM_OR_ON_MAP        1
142 #define ECM_OR_ON_MAPUNMAP   2
143 #define ECM_OR_ON_CREATE     3
144
145 static struct {
146    char                enable;
147    char                resize_fix_enable;
148    char                use_name_pixmap;
149 #if USE_COMPOSITE_OVERLAY_WINDOW
150    char                use_cow;
151 #endif
152    int                 mode;
153    struct {
154       int                 mode;
155       int                 offset_x, offset_y;
156       struct {
157          int                 opacity;
158          int                 radius;
159       } blur;
160       struct {
161          int                 opacity;
162       } sharp;
163       unsigned int        color;
164    } shadows;
165    struct {
166       char                enable;
167       unsigned int        time; /* Fading time, ms */
168    } fading;
169    struct {
170       int                 mode;
171       int                 opacity;
172    } override_redirect;
173 } Conf_compmgr;
174
175 /*
176  * State
177  */
178 #define ECM_MODE_OFF    0
179 #define ECM_MODE_ROOT   1
180 #define ECM_MODE_WINDOW 2
181 #define ECM_MODE_AUTO   3
182
183 static struct {
184    int                 mode;
185    Window              root;
186 #if USE_COMPOSITE_OVERLAY_WINDOW
187    Window              cow;
188 #endif
189    Pixmap              pmap;    /* Compositing buffer */
190    char                active;
191    char                use_pixmap;
192    char                reorder;
193    char                ghosts;
194    EObj               *eo_first;
195    EObj               *eo_last;
196    XserverRegion       damage;
197    char                got_damage;
198    XserverRegion       rgn_screen;
199    XserverRegion       rgn_clip;
200    int                 shadow_mode;
201    float               opac_blur;       /* 0. -> 1. */
202    float               opac_sharp;      /* 0. -> 1. */
203 } Mode_compmgr;
204
205 /* FIXME - Optimize according to what actually changed */
206 #define _ECM_SET_CLIP_CHANGED()   Mode_compmgr.reorder = 1
207 #define _ECM_SET_STACK_CHANGED()  Mode_compmgr.reorder = 1
208 #define _ECM_SET_SHADOW_CHANGED() Mode_compmgr.reorder = 1
209
210 static Picture      rootPicture;
211 static Picture      rootBuffer;
212
213 static XserverRegion rgn_tmp;   /* Region for temporary use */
214 static XserverRegion rgn_tmp2;  /* Region for temporary use */
215
216 static ESelection  *wm_cm_sel = NULL;
217
218 #define OPAQUE          0xffffffff
219 #define OP32To8(op) (((unsigned int)(op)) >> 24)
220
221 #define WINDOW_UNREDIR  0
222 #define WINDOW_SOLID    1
223 #define WINDOW_TRANS    2
224 #define WINDOW_ARGB     3
225
226 static void         ECompMgrDamageAll(void);
227 static void         ECompMgrHandleRootEvent(Win win, XEvent * ev, void *prm);
228 static void         ECompMgrHandleWindowEvent(Win win, XEvent * ev, void *prm);
229 static int          doECompMgrWinFade(void *data);
230 static void         ECompMgrWinInvalidate(EObj * eo, int what);
231 static void         ECompMgrWinSetPicts(EObj * eo);
232 static void         ECompMgrWinFadeEnd(EObj * eo, int done);
233 static int          ECompMgrDetermineOrder(EObj * const *lst, int num,
234                                            EObj ** first, EObj ** last,
235                                            Desk * dsk, XserverRegion clip);
236
237 #define PIXMAP_DESTROY(pmap) \
238    if (pmap != None) { XFreePixmap(disp, pmap); pmap = None; }
239 #define PICTURE_DESTROY(pict) \
240    if (pict != None) { XRenderFreePicture(disp, pict); pict = None; }
241 #define REGION_DESTROY(rgn) \
242    if (rgn != None) { ERegionDestroy(rgn); rgn = None; }
243
244 /*
245  * Regions
246  */
247 #define DEBUG_REGIONS 0
248
249 #if DEBUG_REGIONS
250 static int          n_rgn_c = 0;
251 static int          n_rgn_d = 0;
252 #endif
253
254 static              XserverRegion
255 ERegionCreate(void)
256 {
257    XserverRegion       rgn;
258
259    rgn = XFixesCreateRegion(disp, NULL, 0);
260
261 #if DEBUG_REGIONS
262    n_rgn_c++;
263    Eprintf("%s: %#lx %d %d %d\n", __func__, rgn,
264            n_rgn_c - n_rgn_d, n_rgn_c, n_rgn_d);
265 #endif
266    return rgn;
267 }
268
269 static              XserverRegion
270 ERegionCreateRect(int x, int y, int w, int h)
271 {
272    XserverRegion       rgn;
273    XRectangle          rct;
274
275    rct.x = x;
276    rct.y = y;
277    rct.width = w;
278    rct.height = h;
279    rgn = XFixesCreateRegion(disp, &rct, 1);
280
281 #if DEBUG_REGIONS
282    n_rgn_c++;
283    Eprintf("%s: %#lx %d %d %d\n", __func__, rgn,
284            n_rgn_c - n_rgn_d, n_rgn_c, n_rgn_d);
285 #endif
286    return rgn;
287 }
288
289 #if USE_DESK_EXPOSE
290 static              XserverRegion
291 ERegionCreateFromRects(XRectangle * rectangles, int nrectangles)
292 {
293    XserverRegion       rgn;
294
295    rgn = XFixesCreateRegion(disp, rectangles, nrectangles);
296
297 #if DEBUG_REGIONS
298    n_rgn_c++;
299    Eprintf("%s: %#lx %d %d %d\n", __func__, rgn,
300            n_rgn_c - n_rgn_d, n_rgn_c, n_rgn_d);
301 #endif
302    return rgn;
303 }
304 #endif
305
306 static              XserverRegion
307 ERegionCreateFromWindow(Win win)
308 {
309    XserverRegion       rgn;
310
311    rgn =
312       XFixesCreateRegionFromWindow(disp, WinGetXwin(win), WindowRegionBounding);
313
314 #if DEBUG_REGIONS
315    n_rgn_c++;
316    Eprintf("%s: %#lx %d %d %d\n", __func__, rgn,
317            n_rgn_c - n_rgn_d, n_rgn_c, n_rgn_d);
318 #endif
319    return rgn;
320 }
321
322 static              XserverRegion
323 ERegionCopy(XserverRegion rgn, XserverRegion src)
324 {
325    XFixesCopyRegion(disp, rgn, src);
326    return rgn;
327 }
328
329 static              XserverRegion
330 ERegionClone(XserverRegion src)
331 {
332    XserverRegion       rgn;
333
334    rgn = ERegionCreate();
335    ERegionCopy(rgn, src);
336
337    return rgn;
338 }
339
340 static void
341 ERegionDestroy(XserverRegion rgn)
342 {
343 #if DEBUG_REGIONS
344    n_rgn_d++;
345    Eprintf("%s: %#lx %d %d %d\n", __func__, rgn,
346            n_rgn_c - n_rgn_d, n_rgn_c, n_rgn_d);
347 #endif
348    XFixesDestroyRegion(disp, rgn);
349 }
350
351 static void
352 ERegionEmpty(XserverRegion rgn)
353 {
354    XFixesSetRegion(disp, rgn, NULL, 0);
355 }
356
357 static void
358 ERegionSetRect(XserverRegion rgn, int x, int y, int w, int h)
359 {
360    XRectangle          rct;
361
362    rct.x = x;
363    rct.y = y;
364    rct.width = w;
365    rct.height = h;
366    XFixesSetRegion(disp, rgn, &rct, 1);
367 }
368
369 static void
370 ERegionTranslate(XserverRegion rgn, int dx, int dy)
371 {
372    if (dx == 0 && dy == 0)
373       return;
374    XFixesTranslateRegion(disp, rgn, dx, dy);
375 }
376
377 static void
378 ERegionIntersect(XserverRegion dst, XserverRegion src)
379 {
380    XFixesIntersectRegion(disp, dst, dst, src);
381 }
382
383 static void
384 ERegionUnion(XserverRegion dst, XserverRegion src)
385 {
386    XFixesUnionRegion(disp, dst, dst, src);
387 }
388
389 static void
390 ERegionSubtract(XserverRegion dst, XserverRegion src)
391 {
392    XFixesSubtractRegion(disp, dst, dst, src);
393 }
394
395 static void
396 ERegionSubtractOffset(XserverRegion dst, int dx, int dy, XserverRegion src)
397 {
398    Display            *dpy = disp;
399    XserverRegion       rgn;
400
401    rgn = src;
402    if (dx != 0 || dy != 0)
403      {
404         rgn = ERegionCopy(rgn_tmp, src);
405         XFixesTranslateRegion(dpy, rgn, dx, dy);
406      }
407    XFixesSubtractRegion(dpy, dst, dst, rgn);
408 }
409
410 static void
411 ERegionUnionOffset(XserverRegion dst, int dx, int dy, XserverRegion src)
412 {
413    Display            *dpy = disp;
414    XserverRegion       rgn;
415
416    rgn = src;
417    if (dx != 0 || dy != 0)
418      {
419         rgn = ERegionCopy(rgn_tmp, src);
420         XFixesTranslateRegion(dpy, rgn, dx, dy);
421      }
422    XFixesUnionRegion(dpy, dst, dst, rgn);
423 }
424
425 #if 0                           /* Unused (for debug) */
426 static int
427 ERegionIsEmpty(XserverRegion rgn)
428 {
429    int                 nr;
430    XRectangle         *pr;
431
432    pr = XFixesFetchRegion(disp, rgn, &nr);
433    if (pr)
434       XFree(pr);
435    return nr == 0;
436 }
437 #endif
438
439 static void
440 ERegionShow(const char *txt, XserverRegion rgn)
441 {
442    int                 i, nr;
443    XRectangle         *pr;
444
445    if (rgn == None)
446      {
447         Eprintf(" - region: %s %#lx is None\n", txt, rgn);
448         return;
449      }
450
451    pr = XFixesFetchRegion(disp, rgn, &nr);
452    if (!pr || nr <= 0)
453      {
454         Eprintf(" - region: %s %#lx is empty\n", txt, rgn);
455         goto done;
456      }
457
458    Eprintf(" - region: %s %#lx:\n", txt, rgn);
459    for (i = 0; i < nr; i++)
460       Eprintf("%4d: %4d+%4d %4dx%4d\n", i, pr[i].x, pr[i].y, pr[i].width,
461               pr[i].height);
462
463  done:
464    if (pr)
465       XFree(pr);
466 }
467
468 void
469 ECompMgrWinClipToGC(EObj * eo, GC gc)
470 {
471    XserverRegion       rgn = rgn_tmp2;
472
473    if (!eo || !eo->cmhook)
474       return;
475
476    ERegionCopy(rgn, Mode_compmgr.rgn_screen);
477    ERegionSubtract(rgn, eo->cmhook->clip);
478    XFixesSetGCClipRegion(disp, gc, 0, 0, rgn);
479 }
480
481 /*
482  * Pictures
483  */
484
485 #define _R(x) (((x) >> 16) & 0xff)
486 #define _G(x) (((x) >>  8) & 0xff)
487 #define _B(x) (((x)      ) & 0xff)
488
489 static              Picture
490 EPictureCreateSolid(Bool argb, unsigned int a, unsigned int rgb)
491 {
492    Display            *dpy = disp;
493    Pixmap              pmap;
494    Picture             pict;
495    XRenderPictFormat  *pictfmt;
496    XRenderPictureAttributes pa;
497    XRenderColor        c;
498
499    pmap = XCreatePixmap(dpy, Mode_compmgr.root, 1, 1, argb ? 32 : 8);
500    pictfmt = XRenderFindStandardFormat(dpy,
501                                        argb ? PictStandardARGB32 :
502                                        PictStandardA8);
503    pa.repeat = True;
504    pict = XRenderCreatePicture(dpy, pmap, pictfmt, CPRepeat, &pa);
505
506    c.alpha = (unsigned short)(a * 0x101);
507    c.red = (unsigned short)(_R(rgb) * 0x101);
508    c.green = (unsigned short)(_G(rgb) * 0x101);
509    c.blue = (unsigned short)(_B(rgb) * 0x101);
510    XRenderFillRectangle(dpy, PictOpSrc, pict, &c, 0, 0, 1, 1);
511
512    XFreePixmap(dpy, pmap);
513
514    return pict;
515 }
516
517 static              Picture
518 EPictureCreateBuffer(Win win, int w, int h, Pixmap * ppmap)
519 {
520    Picture             pict;
521    Pixmap              pmap;
522    XRenderPictFormat  *pictfmt;
523
524    pmap = XCreatePixmap(disp, WinGetXwin(win), w, h, WinGetDepth(win));
525    pictfmt = XRenderFindVisualFormat(disp, WinGetVisual(win));
526    pict = XRenderCreatePicture(disp, pmap, pictfmt, 0, 0);
527    if (ppmap)
528       *ppmap = pmap;
529    else
530       XFreePixmap(disp, pmap);
531
532    return pict;
533 }
534
535 #if 0
536 static              Picture
537 EPictureCreate(Window win, int depth, Visual * vis)
538 {
539    Picture             pict;
540    XRenderPictFormat  *pictfmt;
541
542    pictfmt = XRenderFindVisualFormat(disp, vis);
543    pict = XRenderCreatePicture(disp, win, pictfmt, 0, 0);
544
545    return pict;
546 }
547 #endif
548
549 /* Hack to fix redirected window resize bug(?) */
550 void
551 ECompMgrMoveResizeFix(EObj * eo, int x, int y, int w, int h)
552 {
553    Picture             pict;
554    int                 wo, ho;
555    ECmWinInfo         *cw = eo->cmhook;
556
557    if (!cw || !Conf_compmgr.resize_fix_enable)
558      {
559         EMoveResizeWindow(EobjGetWin(eo), x, y, w, h);
560         return;
561      }
562
563    wo = ho = 0;
564    EGetGeometry(EobjGetWin(eo), NULL, NULL, NULL, &wo, &ho, NULL, NULL);
565    if (wo <= 0 || ho <= 0 || (wo == w && ho == h))
566      {
567         EMoveResizeWindow(EobjGetWin(eo), x, y, w, h);
568         return;
569      }
570
571    /* Resizing - grab old contents */
572    pict = EPictureCreateBuffer(EobjGetWin(eo), wo, ho, NULL);
573    XRenderComposite(disp, PictOpSrc, cw->picture, None, pict, 0, 0, 0, 0, 0, 0,
574                     wo, ho);
575
576    /* Resize (+move) */
577    EMoveResizeWindow(EobjGetWin(eo), x, y, w, h);
578
579    /* Paste old contents back in */
580    if (w < wo)
581       w = wo;
582    if (h < ho)
583       h = ho;
584    XRenderComposite(disp, PictOpSrc, pict, None, cw->picture,
585                     0, 0, 0, 0, 0, 0, w, h);
586    XRenderFreePicture(disp, pict);
587 }
588
589 #if !USE_BG_WIN_ON_ALL_DESKS
590 /*
591  * Desk background
592  */
593
594 int
595 ECompMgrDeskConfigure(Desk * dsk)
596 {
597    EObj               *eo;
598    ECmWinInfo         *cw;
599    Picture             pict;
600    XRenderPictFormat  *pictfmt;
601    XRenderPictureAttributes pa;
602    Pixmap              pmap;
603
604    if (!Mode_compmgr.active)
605       return 0;
606
607    eo = dsk->bg.o;
608    if (!eo)
609       return 1;
610
611    ECompMgrWinInvalidate(eo, INV_PICTURE);
612
613    if (!dsk->viewable && dsk->bg.bg)
614       return 1;
615
616    if (dsk->bg.pmap == None)
617      {
618         GC                  gc;
619
620         pmap = XCreatePixmap(disp, Mode_compmgr.root, 1, 1, WinGetDepth(VROOT));
621         gc = EXCreateGC(pmap, 0, NULL);
622         XSetClipMask(disp, gc, 0);
623         XSetFillStyle(disp, gc, FillSolid);
624         XSetForeground(disp, gc, dsk->bg.pixel);
625         XFillRectangle(disp, pmap, gc, 0, 0, 1, 1);
626         EXFreeGC(gc);
627      }
628    else
629      {
630         pmap = dsk->bg.pmap;
631      }
632
633    pa.repeat = True;
634    pictfmt = XRenderFindVisualFormat(disp, WinGetVisual(VROOT));
635    pict = XRenderCreatePicture(disp, pmap, pictfmt, CPRepeat, &pa);
636
637    if (pmap != dsk->bg.pmap)
638       XFreePixmap(disp, pmap);
639
640    /* New background, all must be repainted */
641    ECompMgrDamageAll();
642
643    cw = eo->cmhook;
644    cw->picture = pict;
645
646    D1printf
647       ("ECompMgrDeskConfigure: Desk %d: using pixmap %#lx picture=%#lx\n",
648        dsk->num, pmap, cw->picture);
649
650    return 1;
651 }
652 #endif
653
654 #if USE_DESK_VISIBILITY
655 static void
656 ECompMgrDeskVisibility(EObj * eo, XEvent * ev)
657 {
658    Desk               *dsk;
659    int                 visible;
660
661    switch (eo->type)
662      {
663      default:
664         return;
665      case EOBJ_TYPE_DESK:
666         dsk = (Desk *) eo;
667         break;
668      case EOBJ_TYPE_ROOT_BG:
669         dsk = DeskGet(0);
670         break;
671      }
672
673    visible = dsk->viewable && ev->xvisibility.state != VisibilityFullyObscured;
674    if (dsk->visible == visible)
675       return;
676    dsk->visible = visible;
677    if (!visible)
678       return;
679
680    /*
681     * A viewable desk is no longer fully obscured. Assume this happened due
682     * to a VT switch to our display and repaint all. This may happen in other
683     * situations as well, but most likely when we must repaint everything
684     * anyway.
685     */
686    ECompMgrDamageAll();
687 }
688 #endif
689
690 /*
691  * Root (?)
692  */
693
694 static void
695 ECompMgrDamageMerge(XserverRegion damage)
696 {
697    if (Mode_compmgr.got_damage)
698      {
699         if (EDebug(EDBUG_TYPE_COMPMGR3))
700            ERegionShow("ECompMgrDamageMerge add:", damage);
701
702         ERegionUnion(Mode_compmgr.damage, damage);
703      }
704    else if (Mode_compmgr.damage != None)
705      {
706         ERegionCopy(Mode_compmgr.damage, damage);
707      }
708    else
709      {
710         Mode_compmgr.damage = ERegionClone(damage);
711      }
712    Mode_compmgr.got_damage = 1;
713
714    if (EDebug(EDBUG_TYPE_COMPMGR3))
715       ERegionShow("ECompMgrDamageMerge all:", Mode_compmgr.damage);
716 }
717
718 static void
719 ECompMgrDamageMergeObject(EObj * eo, XserverRegion damage)
720 {
721    ECmWinInfo         *cw = eo->cmhook;
722    Desk               *dsk = eo->desk;
723
724    if (!Mode_compmgr.active || damage == None)
725       return;
726
727    if (dsk->num > 0 && !dsk->viewable && eo->ilayer < 512)
728       return;
729
730    if (Mode_compmgr.reorder)
731       ECompMgrDetermineOrder(NULL, 0, &Mode_compmgr.eo_first,
732                              &Mode_compmgr.eo_last, DeskGet(0), None);
733
734    damage = ERegionCopy(rgn_tmp, damage);
735
736 #if USE_CLIP_RELATIVE_TO_DESK
737    if (cw->have_clip && eo->type != EOBJ_TYPE_DESK)
738       ERegionSubtract(damage, cw->clip);
739 #endif
740
741    if (EoGetX(dsk) != 0 || EoGetY(dsk) != 0)
742       ERegionTranslate(damage, EoGetX(dsk), EoGetY(dsk));
743
744 #if !USE_CLIP_RELATIVE_TO_DESK
745    if (cw->have_clip && eo->type != EOBJ_TYPE_DESK)
746       ERegionSubtract(damage, cw->clip);
747 #endif
748    if (!eo->ghost)
749       Mode.events.damage_count++;
750
751    ECompMgrDamageMerge(damage);
752 }
753
754 static void
755 ECompMgrDamageAll(void)
756 {
757    ECompMgrDamageMerge(Mode_compmgr.rgn_screen);
758 }
759
760 #if ENABLE_SHADOWS
761
762 static Picture      transBlackPicture;
763
764 typedef struct {
765    int                 size;
766    double             *data;
767 } conv;
768
769 static conv        *gaussianMap = NULL;
770
771 static double
772 gaussian(double r, double x, double y)
773 {
774    return ((1 / (sqrt(2 * M_PI * r))) * exp((-(x * x + y * y)) / (2 * r * r)));
775 }
776
777 static conv        *
778 make_gaussian_map(double r)
779 {
780    conv               *c;
781    int                 size = ((int)ceil((r * 3)) + 1) & ~1;
782    int                 center = size / 2;
783    int                 x, y;
784    double              t;
785    double              g;
786
787    c = (conv *) EMALLOC(char, sizeof(conv) + size * size * sizeof(double));
788
789    c->size = size;
790    c->data = (double *)(c + 1);
791    t = 0.0;
792    for (y = 0; y < size; y++)
793       for (x = 0; x < size; x++)
794         {
795            g = gaussian(r, (double)(x - center), (double)(y - center));
796            t += g;
797            c->data[y * size + x] = g;
798         }
799 /*    printf ("gaussian total %f\n", t); */
800    for (y = 0; y < size; y++)
801       for (x = 0; x < size; x++)
802         {
803            c->data[y * size + x] /= t;
804         }
805    return c;
806 }
807
808 /*
809  * A picture will help
810  *
811  *      -center   0                width  width+center
812  *  -center +-----+-------------------+-----+
813  *          |     |                   |     |
814  *          |     |                   |     |
815  *        0 +-----+-------------------+-----+
816  *          |     |                   |     |
817  *          |     |                   |     |
818  *          |     |                   |     |
819  *   height +-----+-------------------+-----+
820  *          |     |                   |     |
821  * height+  |     |                   |     |
822  *  center  +-----+-------------------+-----+
823  */
824
825 static unsigned char
826 sum_gaussian(conv * map, double opacity, int x, int y, int width, int height)
827 {
828    int                 fx, fy;
829    double             *g_data;
830    double             *g_line = map->data;
831    int                 g_size = map->size;
832    int                 center = g_size / 2;
833    int                 fx_start, fx_end;
834    int                 fy_start, fy_end;
835    double              v;
836
837    /*
838     * Compute set of filter values which are "in range",
839     * that's the set with:
840     *  0 <= x + (fx-center) && x + (fx-center) < width &&
841     *  0 <= y + (fy-center) && y + (fy-center) < height
842     *
843     *  0 <= x + (fx - center)  x + fx - center < width
844     *  center - x <= fx        fx < width + center - x
845     */
846
847    fx_start = center - x;
848    if (fx_start < 0)
849       fx_start = 0;
850    fx_end = width + center - x;
851    if (fx_end > g_size)
852       fx_end = g_size;
853
854    fy_start = center - y;
855    if (fy_start < 0)
856       fy_start = 0;
857    fy_end = height + center - y;
858    if (fy_end > g_size)
859       fy_end = g_size;
860
861    g_line = g_line + fy_start * g_size + fx_start;
862
863    v = 0;
864    for (fy = fy_start; fy < fy_end; fy++)
865      {
866         g_data = g_line;
867         g_line += g_size;
868
869         for (fx = fx_start; fx < fx_end; fx++)
870            v += *g_data++;
871      }
872    if (v > 1)
873       v = 1;
874
875    return ((unsigned char)(v * opacity * 255.0));
876 }
877
878 static XImage      *
879 make_shadow(double opacity, int width, int height)
880 {
881    Display            *dpy = disp;
882    XImage             *ximage;
883    unsigned char      *data;
884    int                 gsize = gaussianMap->size;
885    int                 ylimit, xlimit;
886    int                 swidth = width + gsize;
887    int                 sheight = height + gsize;
888    int                 center = gsize / 2;
889    int                 x, y;
890    unsigned char       d;
891    int                 x_diff;
892
893    data = ECALLOC(unsigned char, swidth * sheight);
894
895    if (!data)
896       return NULL;
897
898    ximage = XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)),
899                          8, ZPixmap, 0,
900                          (char *)data,
901                          swidth, sheight, 8, swidth * sizeof(unsigned char));
902    if (!ximage)
903      {
904         Efree(data);
905         return NULL;
906      }
907
908    /*
909     * Build the gaussian in sections
910     */
911
912 #if 1
913    /* FIXME - Handle properly - shaped/non-shaped/offset */
914    /*
915     * center (fill the complete data array)
916     */
917    d = sum_gaussian(gaussianMap, opacity, center, center, width, height);
918    memset(data, d, sheight * swidth);
919 #endif
920
921    /*
922     * corners
923     */
924    ylimit = gsize;
925    if (ylimit > sheight / 2)
926       ylimit = (sheight + 1) / 2;
927    xlimit = gsize;
928    if (xlimit > swidth / 2)
929       xlimit = (swidth + 1) / 2;
930
931    for (y = 0; y < ylimit; y++)
932       for (x = 0; x < xlimit; x++)
933         {
934            d = sum_gaussian(gaussianMap, opacity, x - center, y - center, width,
935                             height);
936            data[y * swidth + x] = d;
937            data[(sheight - y - 1) * swidth + x] = d;
938            data[(sheight - y - 1) * swidth + (swidth - x - 1)] = d;
939            data[y * swidth + (swidth - x - 1)] = d;
940         }
941
942    /*
943     * top/bottom
944     */
945    x_diff = swidth - (gsize * 2);
946    if (x_diff > 0 && ylimit > 0)
947      {
948         for (y = 0; y < ylimit; y++)
949           {
950              d = sum_gaussian(gaussianMap, opacity, center, y - center, width,
951                               height);
952              memset(&data[y * swidth + gsize], d, x_diff);
953              memset(&data[(sheight - y - 1) * swidth + gsize], d, x_diff);
954           }
955      }
956
957    /*
958     * sides
959     */
960    for (x = 0; x < xlimit; x++)
961      {
962         d = sum_gaussian(gaussianMap, opacity, x - center, center, width,
963                          height);
964         for (y = gsize; y < sheight - gsize; y++)
965           {
966              data[y * swidth + x] = d;
967              data[y * swidth + (swidth - x - 1)] = d;
968           }
969      }
970
971    return ximage;
972 }
973
974 static              Picture
975 shadow_picture(double opacity, int width, int height, int *wp, int *hp)
976 {
977    Display            *dpy = disp;
978    XImage             *shadowImage;
979    Pixmap              shadowPixmap;
980    Picture             shadowPicture;
981    GC                  gc;
982
983    shadowImage = make_shadow(opacity, width, height);
984    if (!shadowImage)
985       return None;
986
987    shadowPixmap = XCreatePixmap(dpy, Mode_compmgr.root,
988                                 shadowImage->width, shadowImage->height, 8);
989    shadowPicture = XRenderCreatePicture(dpy, shadowPixmap,
990                                         XRenderFindStandardFormat(dpy,
991                                                                   PictStandardA8),
992                                         0, 0);
993    gc = XCreateGC(dpy, shadowPixmap, 0, 0);
994
995    XPutImage(dpy, shadowPixmap, gc, shadowImage, 0, 0, 0, 0,
996              shadowImage->width, shadowImage->height);
997    *wp = shadowImage->width;
998    *hp = shadowImage->height;
999    XFreeGC(dpy, gc);
1000    XDestroyImage(shadowImage);
1001    XFreePixmap(dpy, shadowPixmap);
1002
1003    return shadowPicture;
1004 }
1005
1006 #endif /* ENABLE_SHADOWS */
1007
1008 static void         ECompMgrWinSetShape(EObj * eo);
1009
1010 /* Region of window in screen coordinates, including shadows */
1011 static void
1012 ECompMgrWinSetExtents(EObj * eo)
1013 {
1014    ECmWinInfo         *cw = eo->cmhook;
1015    XRectangle          r, sr;
1016    unsigned int        bw;
1017
1018    /* FIXME - Get this right */
1019    bw = EobjGetBW(eo);
1020    if (Mode_compmgr.use_pixmap)
1021      {
1022         cw->rcx = EobjGetX(eo);
1023         cw->rcy = EobjGetY(eo);
1024         cw->rcw = EobjGetW(eo) + 2 * bw;
1025         cw->rch = EobjGetH(eo) + 2 * bw;
1026      }
1027    else
1028      {
1029         cw->rcx = EobjGetX(eo) + bw;
1030         cw->rcy = EobjGetY(eo) + bw;
1031         cw->rcw = EobjGetW(eo);
1032         cw->rch = EobjGetH(eo);
1033      }
1034
1035    if (eo->noredir && bw)
1036      {
1037         r.x = EobjGetX(eo);
1038         r.y = EobjGetY(eo);
1039         r.width = EobjGetW(eo) + 2 * bw;
1040         r.height = EobjGetH(eo) + 2 * bw;
1041      }
1042    else
1043      {
1044         r.x = cw->rcx;
1045         r.y = cw->rcy;
1046         r.width = cw->rcw;
1047         r.height = cw->rch;
1048      }
1049
1050    if (cw->extents == None)
1051       cw->extents = ERegionCreate();
1052
1053 #if ENABLE_SHADOWS
1054    cw->has_shadow = (Mode_compmgr.shadow_mode != ECM_SHADOWS_OFF) &&
1055       eo->shadow && (EShapeCheck(EobjGetWin(eo)) >= 0);
1056    if (!cw->has_shadow)
1057       goto skip_shadow;
1058
1059    switch (Mode_compmgr.shadow_mode)
1060      {
1061      default:
1062         goto skip_shadow;
1063
1064      case ECM_SHADOWS_SHARP:
1065      case ECM_SHADOWS_ECHO:
1066         cw->shadow_dx = Conf_compmgr.shadows.offset_x;
1067         cw->shadow_dy = Conf_compmgr.shadows.offset_y;
1068         cw->shadow_width = cw->rcw;
1069         cw->shadow_height = cw->rch;
1070         break;
1071
1072      case ECM_SHADOWS_BLURRED:
1073         if (EobjIsShaped(eo) /* || cw->mode == WINDOW_ARGB */ )
1074            goto skip_shadow;
1075
1076         if (!gaussianMap)
1077           {
1078              gaussianMap =
1079                 make_gaussian_map((double)Conf_compmgr.shadows.blur.radius);
1080              if (!gaussianMap)
1081                 goto skip_shadow;
1082           }
1083
1084         cw->shadow_dx = Conf_compmgr.shadows.offset_x - gaussianMap->size / 2;
1085         cw->shadow_dy = Conf_compmgr.shadows.offset_y - gaussianMap->size / 2;
1086         if (!cw->shadow_pict)
1087            cw->shadow_pict = shadow_picture(Mode_compmgr.opac_blur,
1088                                             cw->rcw, cw->rch,
1089                                             &cw->shadow_width,
1090                                             &cw->shadow_height);
1091         break;
1092      }
1093    sr.x = cw->rcx + cw->shadow_dx;
1094    sr.y = cw->rcy + cw->shadow_dy;
1095    sr.width = cw->shadow_width;
1096    sr.height = cw->shadow_height;
1097    if (sr.x < r.x)
1098      {
1099         r.width = (r.x + r.width) - sr.x;
1100         r.x = sr.x;
1101      }
1102    if (sr.y < r.y)
1103      {
1104         r.height = (r.y + r.height) - sr.y;
1105         r.y = sr.y;
1106      }
1107    if (sr.x + sr.width > r.x + r.width)
1108       r.width = sr.x + sr.width - r.x;
1109    if (sr.y + sr.height > r.y + r.height)
1110       r.height = sr.y + sr.height - r.y;
1111
1112    ERegionSetRect(cw->extents, r.x, r.y, r.width, r.height);
1113    goto done;
1114
1115  skip_shadow:
1116 #endif
1117
1118    /* No shadow - extents = shape */
1119    if (!cw->have_shape)
1120       ECompMgrWinSetShape(eo);
1121    ERegionCopy(cw->extents, cw->shape);
1122
1123  done:
1124    cw->have_extents = 1;
1125
1126    D1printf("extents %#lx %d %d %d %d\n", EobjGetXwin(eo), r.x, r.y, r.width,
1127             r.height);
1128
1129    if (EDebug(EDBUG_TYPE_COMPMGR))
1130       ERegionShow("extents", cw->extents);
1131 }
1132
1133 /* Region of shaped window in screen coordinates */
1134 static void
1135 ECompMgrWinSetShape(EObj * eo)
1136 {
1137    ECmWinInfo         *cw = eo->cmhook;
1138    int                 x, y;
1139
1140    if (cw->shape == None)
1141      {
1142         cw->shape = ERegionCreateFromWindow(EobjGetWin(eo));
1143
1144         if (WinIsShaped(EobjGetWin(eo)))
1145           {
1146              /* Intersect with window size to get effective bounding region */
1147              ERegionSetRect(rgn_tmp, 0, 0, EobjGetW(eo), EobjGetH(eo));
1148              ERegionIntersect(cw->shape, rgn_tmp);
1149           }
1150         x = EobjGetX(eo) + EobjGetBW(eo);
1151         y = EobjGetY(eo) + EobjGetBW(eo);
1152      }
1153    else
1154      {
1155         x = EobjGetX(eo) + EobjGetBW(eo) - cw->shape_x;
1156         y = EobjGetY(eo) + EobjGetBW(eo) - cw->shape_y;
1157      }
1158
1159    ERegionTranslate(cw->shape, x, y);
1160
1161    cw->shape_x = EobjGetX(eo) + EobjGetBW(eo);
1162    cw->shape_y = EobjGetY(eo) + EobjGetBW(eo);
1163    cw->have_shape = 1;
1164
1165    D1printf("shape %#lx: %d %d\n", EobjGetXwin(eo), cw->shape_x, cw->shape_y);
1166    if (EDebug(EDBUG_TYPE_COMPMGR))
1167       ERegionShow("shape", cw->shape);
1168 }
1169
1170 static              Pixmap
1171 EWindowGetNamePixmap(const struct _xwin *win)
1172 {
1173    XWindowAttributes   xwa;
1174
1175    if (XGetWindowAttributes(disp, win->xwin, &xwa) == 0 ||
1176        xwa.map_state == IsUnmapped)
1177       return None;
1178
1179    return XCompositeNameWindowPixmap(disp, WinGetXwin(win));
1180 }
1181
1182 Pixmap
1183 ECompMgrWinGetPixmap(const EObj * eo)
1184 {
1185    ECmWinInfo         *cw = eo->cmhook;
1186
1187    if (!cw)
1188       return None;
1189
1190    if (cw->pixmap != None)
1191       return cw->pixmap;
1192
1193    if (eo->noredir)
1194       return None;
1195
1196    cw->pixmap = EWindowGetNamePixmap(EobjGetWin(eo));
1197
1198    return cw->pixmap;
1199 }
1200
1201 static void
1202 ECompMgrWinInvalidate(EObj * eo, int what)
1203 {
1204    ECmWinInfo         *cw = eo->cmhook;
1205    Display            *dpy = disp;
1206
1207    if (!cw)
1208       return;
1209
1210    D2printf("ECompMgrWinInvalidate %#lx: %#x\n", EobjGetXwin(eo), what);
1211
1212    if ((what & (INV_SIZE | INV_PIXMAP)) && cw->pixmap != None)
1213      {
1214         XFreePixmap(dpy, cw->pixmap);
1215         cw->pixmap = None;
1216         if (Mode_compmgr.use_pixmap)
1217            what |= INV_PICTURE;
1218 #if USE_GLX
1219         EobjTextureInvalidate(eo);
1220 #endif
1221      }
1222
1223    if (what & (INV_SIZE | INV_SHAPE))
1224       REGION_DESTROY(cw->shape);
1225    if (what & INV_GEOM)
1226       cw->have_shape = 0;
1227
1228    if (what & INV_PICTURE)
1229       PICTURE_DESTROY(cw->picture);
1230
1231    if (what & INV_OPACITY)
1232       PICTURE_DESTROY(cw->pict_alpha);
1233
1234    if (what & (INV_CLIP | INV_GEOM))
1235       cw->have_clip = 0;
1236
1237 #if ENABLE_SHADOWS
1238    if (what & (INV_SIZE | INV_SHADOW))
1239       PICTURE_DESTROY(cw->shadow_pict);
1240    if (what & (INV_OPACITY | INV_SHADOW))
1241       PICTURE_DESTROY(cw->shadow_alpha);
1242 #endif
1243
1244    if (what & (INV_GEOM | INV_SHADOW))
1245       cw->have_extents = 0;
1246 }
1247
1248 static void
1249 ECompMgrWinSetOpacity(EObj * eo, unsigned int opacity)
1250 {
1251    ECmWinInfo         *cw = eo->cmhook;
1252    int                 mode;
1253
1254    if (!cw || cw->opacity == opacity)
1255       return;
1256
1257    cw->opacity = opacity;
1258
1259    D1printf("ECompMgrWinSetOpacity: %#lx opacity=%#x\n", EobjGetXwin(eo),
1260             cw->opacity);
1261
1262    if (eo->shown || cw->fadeout)
1263       ECompMgrDamageMergeObject(eo, cw->extents);
1264
1265    /* Invalidate stuff changed by opacity */
1266    ECompMgrWinInvalidate(eo, INV_OPACITY);
1267
1268    if (eo->noredir)
1269       mode = WINDOW_UNREDIR;
1270    else if (EobjGetWin(eo)->argb)
1271       mode = WINDOW_ARGB;
1272    else if (cw->opacity != OPAQUE)
1273       mode = WINDOW_TRANS;
1274    else
1275       mode = WINDOW_SOLID;
1276
1277    if (mode != cw->mode)
1278       _ECM_SET_CLIP_CHANGED();
1279
1280    cw->mode = mode;
1281 }
1282
1283 static int
1284 doECompMgrWinFade(void *data)
1285 {
1286    EObj               *eo;
1287    ECmWinInfo         *cw;
1288    unsigned int        op, step;
1289
1290    eo = (EObj *) data;
1291
1292    /* May be gone */
1293    if (EobjListStackCheck(eo) < 0)
1294       return 0;
1295
1296    cw = eo->cmhook;
1297    op = cw->opacity_to;
1298
1299 #if DEBUG_OPACITY
1300    Eprintf("doECompMgrWinFade %#lx, %d/%d, %#x->%#x\n", EobjGetXwin(eo),
1301            eo->fading, cw->fadeout, cw->opacity, op);
1302 #endif
1303    if (!eo->fading)
1304       goto done;
1305
1306    eo->fading = cw->fadeout;
1307
1308    step = Conf_compmgr.fading.time / Conf.animation.step;
1309    if (step == 0)
1310       step = 1;
1311    step = 0xffffffff / step;
1312    if (op == cw->opacity)
1313      {
1314         op = eo->opacity;
1315         ECompMgrWinFadeEnd(eo, 0);
1316      }
1317    else if (op > cw->opacity)
1318      {
1319         if (op - cw->opacity > step)
1320           {
1321              op = cw->opacity + step;
1322              eo->fading = 1;
1323           }
1324      }
1325    else
1326      {
1327         if (cw->opacity - op > step)
1328           {
1329              op = cw->opacity - step;
1330              eo->fading = 1;
1331           }
1332      }
1333
1334 #if DEBUG_OPACITY
1335    Eprintf("doECompMgrWinFade %#lx, %#x\n", EobjGetXwin(eo), op);
1336 #endif
1337    ECompMgrWinSetOpacity(eo, op);
1338
1339    if (eo->fading)
1340       return 1;
1341
1342    if (eo->type == EOBJ_TYPE_EWIN)
1343       ModulesSignal(eo->shown ? ESIGNAL_EWIN_CHANGE : ESIGNAL_EWIN_UNMAP, eo);
1344
1345  done:
1346    cw->anim_fade = NULL;
1347    return 0;
1348 }
1349
1350 static void
1351 ECompMgrWinFade(EObj * eo, unsigned int op_from, unsigned int op_to)
1352 {
1353    ECmWinInfo         *cw = eo->cmhook;
1354
1355    if (op_from == op_to && op_to == eo->opacity)
1356      {
1357         if (eo->fading)
1358            ECompMgrWinFadeEnd(eo, 0);
1359         return;
1360      }
1361
1362    if (!cw->anim_fade)
1363       cw->anim_fade = AnimatorAdd(doECompMgrWinFade, eo);
1364    cw->opacity_to = op_to;
1365
1366    eo->fading = 1;
1367    ECompMgrWinSetOpacity(eo, op_from);
1368 }
1369
1370 static void
1371 ECompMgrWinFadeIn(EObj * eo)
1372 {
1373 #if DEBUG_OPACITY
1374    Eprintf("ECompMgrWinFadeIn  %#lx %#x -> %#x\n", EobjGetXwin(eo), 0x10000000,
1375            eo->opacity);
1376 #endif
1377    if (eo->fading)
1378       ECompMgrWinFadeEnd(eo, 0);
1379
1380    ECompMgrWinFade(eo, 0x10000000, eo->opacity);
1381 }
1382
1383 static void
1384 ECompMgrWinFadeOut(EObj * eo)
1385 {
1386    ECmWinInfo         *cw = eo->cmhook;
1387
1388 #if DEBUG_OPACITY
1389    Eprintf("ECompMgrWinFadeOut %#lx %#x -> %#x\n", EobjGetXwin(eo), cw->opacity,
1390            0x10000000);
1391 #endif
1392    cw->fadeout = 1;
1393    ECompMgrWinInvalidate(eo, INV_PICTURE);
1394    ECompMgrWinFade(eo, cw->opacity, 0x10000000);
1395 }
1396
1397 static void
1398 ECompMgrWinFadeEnd(EObj * eo, int done)
1399 {
1400    ECmWinInfo         *cw = eo->cmhook;
1401
1402 #if DEBUG_OPACITY
1403    Eprintf("ECompMgrWinFadeEnd %#lx\n", EobjGetXwin(eo));
1404 #endif
1405    if (cw->fadeout)
1406      {
1407         cw->fadeout = 0;
1408         ECompMgrWinInvalidate(eo, INV_PIXMAP | INV_PICTURE);
1409         ECompMgrDamageMergeObject(eo, cw->extents);
1410         _ECM_SET_CLIP_CHANGED();
1411      }
1412    eo->fading = 0;
1413    if (done)
1414      {
1415         AnimatorDel(cw->anim_fade);
1416         cw->anim_fade = NULL;
1417      }
1418 }
1419
1420 void
1421 ECompMgrWinChangeOpacity(EObj * eo, unsigned int opacity)
1422 {
1423    ECmWinInfo         *cw = eo->cmhook;
1424
1425    if (!cw)
1426       return;
1427
1428    if (eo->shown && Conf_compmgr.fading.enable && eo->fade)
1429       ECompMgrWinFade(eo, cw->opacity, opacity);
1430    else
1431       ECompMgrWinSetOpacity(eo, opacity);
1432 }
1433
1434 void
1435 ECompMgrWinMap(EObj * eo)
1436 {
1437    ECmWinInfo         *cw = eo->cmhook;
1438
1439    if (!cw)
1440      {
1441         ECompMgrWinNew(eo);
1442         cw = eo->cmhook;
1443         if (!cw)
1444            return;
1445      }
1446
1447    D1printf("ECompMgrWinMap %#lx\n", EobjGetXwin(eo));
1448
1449    if (!cw->have_extents)
1450       ECompMgrWinSetExtents(eo);
1451
1452    _ECM_SET_STACK_CHANGED();
1453    ECompMgrDamageMergeObject(eo, cw->extents);
1454
1455    if (Conf_compmgr.fading.enable && eo->fade)
1456       ECompMgrWinFadeIn(eo);
1457 }
1458
1459 void
1460 ECompMgrWinUnmap(EObj * eo)
1461 {
1462    ECmWinInfo         *cw = eo->cmhook;
1463
1464    D1printf("ECompMgrWinUnmap %#lx shown=%d\n", EobjGetXwin(eo), eo->shown);
1465    if (!eo->shown)              /* Sometimes we get a synthetic one too */
1466       return;
1467
1468    ECompMgrDamageMergeObject(eo, cw->extents);
1469    _ECM_SET_STACK_CHANGED();
1470    if (Conf_compmgr.fading.enable && eo->fade && !eo->gone)
1471       ECompMgrWinFadeOut(eo);
1472    else
1473       ECompMgrWinInvalidate(eo, INV_PIXMAP);
1474 }
1475
1476 static void
1477 ECompMgrWinSetPicts(EObj * eo)
1478 {
1479    ECmWinInfo         *cw = eo->cmhook;
1480
1481    if (cw->pixmap == None && eo->shown && !eo->noredir &&
1482        (Mode_compmgr.use_pixmap || (eo->fade && Conf_compmgr.fading.enable)))
1483      {
1484         cw->pixmap = EWindowGetNamePixmap(EobjGetWin(eo));
1485         D2printf("ECompMgrWinSetPicts %#lx: Pmap=%#lx\n", EobjGetXwin(eo),
1486                  cw->pixmap);
1487      }
1488
1489    if (cw->picture == None)
1490      {
1491         XRenderPictFormat  *pictfmt;
1492         XRenderPictureAttributes pa;
1493         Drawable            draw = EobjGetXwin(eo);
1494
1495         if ((cw->pixmap && Mode_compmgr.use_pixmap) || (cw->fadeout))
1496            draw = cw->pixmap;
1497         if (draw == None)
1498            return;
1499
1500         pictfmt = XRenderFindVisualFormat(disp, WinGetVisual(EobjGetWin(eo)));
1501         pa.subwindow_mode = IncludeInferiors;
1502         cw->picture = XRenderCreatePicture(disp, draw,
1503                                            pictfmt, CPSubwindowMode, &pa);
1504         D2printf("ECompMgrWinSetPicts %#lx: Pict=%#lx (drawable=%#lx)\n",
1505                  EobjGetXwin(eo), cw->picture, draw);
1506
1507         if (draw == cw->pixmap)
1508           {
1509              XserverRegion       clip;
1510
1511              clip = ERegionCreateFromWindow(EobjGetWin(eo));
1512              XFixesSetPictureClipRegion(disp, cw->picture, 0, 0, clip);
1513              ERegionDestroy(clip);
1514           }
1515      }
1516 }
1517
1518 void
1519 ECompMgrWinNew(EObj * eo)
1520 {
1521    ECmWinInfo         *cw;
1522
1523    if (!Mode_compmgr.active)    /* FIXME - Here? */
1524       return;
1525
1526    if (eo->inputonly || EobjGetWin(eo) == VROOT)
1527      {
1528         eo->noredir = 1;
1529         return;
1530      }
1531
1532    cw = ECALLOC(ECmWinInfo, 1);
1533    if (!cw)
1534       return;
1535
1536    D1printf("ECompMgrWinNew %#lx\n", EobjGetXwin(eo));
1537
1538    eo->cmhook = cw;
1539
1540    if (eo->type == EOBJ_TYPE_EXT &&
1541        Conf_compmgr.override_redirect.mode == ECM_OR_UNREDIRECTED)
1542      {
1543         eo->noredir = 1;
1544         eo->fade = 0;
1545         eo->shadow = 0;
1546      }
1547
1548    if (eo->noredir)
1549      {
1550         /* If already auto-redirected undo that */
1551         if (Mode_compmgr.mode == ECM_MODE_ROOT)
1552           {
1553              XCompositeUnredirectWindow(disp, EobjGetXwin(eo),
1554                                         CompositeRedirectManual);
1555              if (eo->type == EOBJ_TYPE_DESK)
1556                 XCompositeRedirectSubwindows(disp, EobjGetXwin(eo),
1557                                              CompositeRedirectManual);
1558           }
1559      }
1560    else
1561      {
1562         if (Mode_compmgr.mode == ECM_MODE_WINDOW)
1563            XCompositeRedirectWindow(disp, EobjGetXwin(eo),
1564                                     CompositeRedirectManual);
1565         cw->damage_sequence = NextRequest(disp);
1566         cw->damage =
1567            XDamageCreate(disp, EobjGetXwin(eo), XDamageReportNonEmpty);
1568      }
1569
1570    if (eo->type == EOBJ_TYPE_EXT)
1571       eo->opacity = OpacityFromPercent(Conf_compmgr.override_redirect.opacity);
1572    if (eo->opacity == 0)
1573       eo->opacity = 0xFFFFFFFF;
1574
1575    if (eo->type == EOBJ_TYPE_DESK || eo->type == EOBJ_TYPE_ROOT_BG)
1576      {
1577         ESelectInputChange(EobjGetWin(eo), VisibilityChangeMask, 0);
1578      }
1579
1580    if (eo->type != EOBJ_TYPE_EWIN)
1581       WindowMatchEobjOps(eo);
1582
1583    cw->opacity = 0xdeadbeef;
1584    ECompMgrWinSetOpacity(eo, eo->opacity);
1585
1586    EventCallbackRegister(EobjGetWin(eo), 0, ECompMgrHandleWindowEvent, eo);
1587 }
1588
1589 void
1590 ECompMgrWinMoveResize(EObj * eo, int change_xy, int change_wh, int change_bw)
1591 {
1592    ECmWinInfo         *cw = eo->cmhook;
1593    int                 invalidate;
1594
1595    D1printf("ECompMgrWinMoveResize %#lx xy=%d wh=%d bw=%d\n",
1596             EobjGetXwin(eo), change_xy, change_wh, change_bw);
1597
1598    invalidate = 0;
1599    if (change_xy || change_bw)
1600       invalidate |= INV_POS;
1601    if (change_wh || change_bw)
1602       invalidate |= INV_SIZE;
1603
1604    if (!invalidate)
1605       return;
1606
1607    if (cw->fadeout)
1608       ECompMgrWinFadeEnd(eo, 1);
1609
1610    if (!eo->shown)
1611      {
1612         ECompMgrWinInvalidate(eo, invalidate);
1613         return;
1614      }
1615
1616    if (EDebug(EDBUG_TYPE_COMPMGR3))
1617       ERegionShow("old-extents:", cw->extents);
1618
1619 #if 0                           /* FIXME - We shouldn't have to update clip if transparent */
1620    if (cw->mode == WINDOW_UNREDIR || cw->mode == WINDOW_SOLID)
1621 #endif
1622       _ECM_SET_CLIP_CHANGED();
1623
1624    if (cw->have_extents)
1625      {
1626         /* Invalidate old window region */
1627         ERegionCopy(rgn_tmp2, cw->extents);
1628         ECompMgrWinInvalidate(eo, invalidate);
1629         /* Invalidate new window region */
1630         ECompMgrWinSetExtents(eo);
1631         ERegionUnion(rgn_tmp2, cw->extents);
1632         ECompMgrDamageMergeObject(eo, rgn_tmp2);
1633      }
1634    else
1635      {
1636         ECompMgrWinInvalidate(eo, invalidate);
1637         /* Invalidate new window region */
1638         ECompMgrWinSetExtents(eo);
1639         ECompMgrDamageMergeObject(eo, cw->extents);
1640      }
1641 }
1642
1643 void
1644 ECompMgrWinDamageArea(EObj * eo, int x __UNUSED__, int y __UNUSED__,
1645                       int w __UNUSED__, int h __UNUSED__)
1646 {
1647    ECmWinInfo         *cw = eo->cmhook;
1648
1649    ECompMgrDamageMergeObject(eo, cw->shape);
1650 }
1651
1652 void
1653 ECompMgrWinChangeShadow(EObj * eo, int shadow)
1654 {
1655    ECmWinInfo         *cw = eo->cmhook;
1656
1657    if (!cw || !eo->shown)
1658       goto done;
1659
1660    if (!shadow && eo->shadow)
1661      {
1662         /* Disable shadow */
1663         ECompMgrDamageMergeObject(eo, cw->extents);
1664         ECompMgrWinInvalidate(eo, INV_SHADOW);
1665      }
1666    else if (shadow && !eo->shadow)
1667      {
1668         /* Enable shadow */
1669         ECompMgrWinInvalidate(eo, INV_SHADOW);
1670         eo->shadow = shadow;
1671         ECompMgrWinSetExtents(eo);
1672         ECompMgrDamageMergeObject(eo, cw->extents);
1673      }
1674  done:
1675    eo->shadow = shadow;
1676 }
1677
1678 static void
1679 ECompMgrWinConfigure(EObj * eo, XEvent * ev)
1680 {
1681    int                 x, y, w, h, bw;
1682    int                 change_xy, change_wh, change_bw;
1683
1684    x = ev->xconfigure.x;
1685    y = ev->xconfigure.y;
1686    w = ev->xconfigure.width;
1687    h = ev->xconfigure.height;
1688    bw = ev->xconfigure.border_width;
1689
1690    change_xy = EobjGetX(eo) != x || EobjGetY(eo) != y;
1691    change_wh = EobjGetW(eo) != w || EobjGetH(eo) != h;
1692    change_bw = EobjGetBW(eo) != bw;
1693
1694    EWindowSetGeometry(EobjGetWin(eo), x, y, w, h, bw);
1695
1696    ECompMgrWinMoveResize(eo, change_xy, change_wh, change_bw);
1697 }
1698
1699 void
1700 ECompMgrWinReparent(EObj * eo, Desk * dsk, int change_xy)
1701 {
1702    ECmWinInfo         *cw = eo->cmhook;
1703
1704    D1printf("ECompMgrWinReparent %#lx %#lx d=%d->%d x,y=%d,%d %d\n",
1705             EobjGetXwin(eo), cw->extents,
1706             (eo->desk) ? (int)eo->desk->num : -1, dsk->num,
1707             EobjGetX(eo), EobjGetY(eo), change_xy);
1708
1709    if (!eo->shown)
1710      {
1711         if (change_xy)
1712            ECompMgrWinInvalidate(eo, INV_POS);
1713         return;
1714      }
1715
1716    /* Invalidate old window region */
1717    if (EDebug(EDBUG_TYPE_COMPMGR3))
1718       ERegionShow("old-extents:", cw->extents);
1719    ECompMgrDamageMergeObject(eo, cw->extents);
1720    if (change_xy)
1721      {
1722         ECompMgrWinInvalidate(eo, INV_POS);
1723
1724         /* Find new window region */
1725         ECompMgrWinSetExtents(eo);
1726      }
1727    eo->desk = dsk;
1728    _ECM_SET_STACK_CHANGED();
1729    ECompMgrDamageMergeObject(eo, cw->extents);
1730    ECompMgrWinInvalidate(eo, INV_PIXMAP);
1731 }
1732
1733 static void
1734 ECompMgrWinCirculate(EObj * eo, XEvent * ev)
1735 {
1736    D1printf("ECompMgrWinCirculate %#lx %#lx\n", ev->xany.window,
1737             EobjGetXwin(eo));
1738
1739    _ECM_SET_STACK_CHANGED();
1740 }
1741
1742 void
1743 ECompMgrWinChangeShape(EObj * eo)
1744 {
1745    ECmWinInfo         *cw = eo->cmhook;
1746
1747    D1printf("ECompMgrWinChangeShape %#lx\n", EobjGetXwin(eo));
1748    if (cw->extents == None)
1749       return;
1750
1751    ECompMgrDamageMergeObject(eo, cw->extents);
1752    ECompMgrWinInvalidate(eo, INV_SHAPE);        /* Invalidate extents and shape */
1753    ECompMgrWinSetExtents(eo);
1754    ECompMgrDamageMergeObject(eo, cw->extents);
1755    _ECM_SET_CLIP_CHANGED();
1756 }
1757
1758 void
1759 ECompMgrWinRaiseLower(EObj * eo, int delta)
1760 {
1761    ECmWinInfo         *cw = eo->cmhook;
1762
1763    D1printf("ECompMgrWinRaiseLower %#lx delta=%d\n", EobjGetXwin(eo), delta);
1764
1765    if (delta < 0)               /* Raise */
1766       _ECM_SET_STACK_CHANGED();
1767    ECompMgrDamageMergeObject(eo, cw->extents);
1768    if (delta > 0)               /* Lower */
1769       _ECM_SET_STACK_CHANGED();
1770 }
1771
1772 void
1773 ECompMgrWinDel(EObj * eo)
1774 {
1775    ECmWinInfo         *cw = eo->cmhook;
1776
1777    if (!cw)
1778       return;
1779
1780    D1printf("ECompMgrWinDel %#lx\n", EobjGetXwin(eo));
1781
1782    if (eo->fading)
1783       ECompMgrWinFadeEnd(eo, 1);
1784
1785    EventCallbackUnregister(EobjGetWin(eo), 0, ECompMgrHandleWindowEvent, eo);
1786
1787    if (!eo->gone)
1788      {
1789         ECompMgrWinInvalidate(eo, INV_PICTURE);
1790
1791         if (eo->noredir)
1792           {
1793              if (Mode_compmgr.mode == ECM_MODE_ROOT &&
1794                  eo->type == EOBJ_TYPE_DESK)
1795                 XCompositeUnredirectSubwindows(disp, EobjGetXwin(eo),
1796                                                CompositeRedirectManual);
1797           }
1798         else
1799           {
1800              if (cw->damage != None)
1801                 XDamageDestroy(disp, cw->damage);
1802
1803              if (Mode_compmgr.mode == ECM_MODE_WINDOW)
1804                 XCompositeUnredirectWindow(disp, EobjGetXwin(eo),
1805                                            CompositeRedirectManual);
1806           }
1807      }
1808
1809    ECompMgrWinInvalidate(eo, INV_ALL);
1810    REGION_DESTROY(cw->extents);
1811    REGION_DESTROY(cw->clip);
1812
1813    Efree(eo->cmhook);
1814    eo->cmhook = NULL;
1815
1816    _ECM_SET_STACK_CHANGED();
1817 }
1818
1819 static void
1820 ECompMgrWinDamage(EObj * eo, XEvent * ev __UNUSED__)
1821 {
1822    ECmWinInfo         *cw = eo->cmhook;
1823    Display            *dpy = disp;
1824    XDamageNotifyEvent *de = (XDamageNotifyEvent *) ev;
1825    XserverRegion       parts;
1826
1827    D2printf("ECompMgrWinDamage %#lx %#lx damaged=%d %d,%d %dx%d\n",
1828             ev->xany.window, EobjGetXwin(eo), cw->damaged,
1829             de->area.x, de->area.y, de->area.width, de->area.height);
1830
1831    if (!cw->damaged)
1832      {
1833         parts = cw->extents;
1834         XDamageSubtract(dpy, cw->damage, None, None);
1835         cw->damaged = 1;
1836      }
1837    else
1838      {
1839         parts = rgn_tmp;
1840         XDamageSubtract(dpy, cw->damage, None, parts);
1841         ERegionTranslate(parts, EobjGetX(eo) + EobjGetBW(eo),
1842                          EobjGetY(eo) + EobjGetBW(eo));
1843      }
1844    eo->serial = ev->xany.serial;
1845    ECompMgrDamageMergeObject(eo, parts);
1846
1847    if (eo->type == EOBJ_TYPE_EWIN)
1848       ModulesSignal(ESIGNAL_EWIN_DAMAGE, eo);
1849 }
1850
1851 static void
1852 ECompMgrWinDumpInfo(const char *txt, EObj * eo, XserverRegion rgn, int force)
1853 {
1854    ECmWinInfo         *cw = eo->cmhook;
1855
1856    Eprintf("%s %#lx: %d,%d %dx%d: %s\n", txt, EobjGetXwin(eo),
1857            EobjGetX(eo), EobjGetY(eo), EobjGetW(eo), EobjGetH(eo),
1858            EobjGetName(eo));
1859    if (!cw)
1860      {
1861         Eprintf("Not managed\n");
1862         return;
1863      }
1864
1865    if (force || EDebug(EDBUG_TYPE_COMPMGR3))
1866      {
1867         Eprintf(" - pict=%#lx pmap=%#lx\n", cw->picture, cw->pixmap);
1868
1869         ERegionShow("win extents", cw->extents);
1870         ERegionShow("win shape  ", cw->shape);
1871         ERegionShow("win clip   ", cw->clip);
1872         if (rgn != None)
1873            ERegionShow("region", rgn);
1874      }
1875 }
1876
1877 static void
1878 ECompMgrDestroyClip(void)
1879 {
1880    EObj               *eo, *const *lst;
1881    ECmWinInfo         *cw;
1882    int                 i, num;
1883
1884    lst = EobjListStackGet(&num);
1885    for (i = 0; i < num; i++)
1886      {
1887         eo = lst[i];
1888         cw = eo->cmhook;
1889         if (!cw)
1890            continue;
1891         cw->have_clip = 0;
1892      }
1893 }
1894
1895 static int
1896 ECompMgrDetermineOrder(EObj * const *lst, int num, EObj ** first,
1897                        EObj ** last, Desk * dsk, XserverRegion clip)
1898 {
1899    EObj               *eo, *eo_prev, *eo_first;
1900    int                 i, stop;
1901    ECmWinInfo         *cw;
1902
1903    D1printf("ECompMgrDetermineOrder %d\n", dsk->num);
1904    if (!lst)
1905       lst = EobjListStackGet(&num);
1906    if (clip == None)
1907      {
1908         ECompMgrDestroyClip();
1909         clip = Mode_compmgr.rgn_clip;
1910         ERegionEmpty(clip);
1911      }
1912
1913    /* Determine overall paint order, top to bottom */
1914    stop = 0;
1915    eo_first = eo_prev = NULL;
1916    Mode_compmgr.ghosts = 0;
1917
1918    for (i = 0; i < num; i++)
1919      {
1920         eo = lst[i];
1921
1922         cw = eo->cmhook;
1923
1924         if (!cw)
1925            continue;
1926
1927         if ((!eo->shown && !eo->fading) || eo->desk != dsk)
1928            continue;
1929
1930         /* Region of shaped window in screen coordinates */
1931         if (!cw->have_shape)
1932            ECompMgrWinSetShape(eo);
1933
1934         /* Region of window in screen coordinates, including shadows */
1935         if (!cw->have_extents)
1936            ECompMgrWinSetExtents(eo);
1937
1938         D3printf(" - %#lx desk=%d shown=%d fading=%d fadeout=%d\n",
1939                  EobjGetXwin(eo), eo->desk->num, eo->shown, eo->fading,
1940                  cw->fadeout);
1941
1942         if (eo->type == EOBJ_TYPE_DESK)
1943           {
1944              EObj               *eo1, *eo2;
1945              Desk               *d = (Desk *) eo;
1946
1947              if (!d->viewable)
1948                 continue;
1949
1950 #if USE_CLIP_RELATIVE_TO_DESK
1951              ERegionTranslate(clip, -EoGetX(d), -EoGetY(d));
1952 #endif
1953              stop = ECompMgrDetermineOrder(lst, num, &eo1, &eo2, d, clip);
1954 #if USE_CLIP_RELATIVE_TO_DESK
1955              ERegionTranslate(clip, EoGetX(d), EoGetY(d));
1956 #endif
1957              if (eo1)
1958                {
1959                   if (!eo_first)
1960                      eo_first = eo1;
1961                   if (eo_prev)
1962                      eo_prev->cmhook->next = eo1;
1963                   eo1->cmhook->prev = eo_prev;
1964                   eo_prev = eo2;
1965                }
1966
1967 #if USE_BG_WIN_ON_ALL_DESKS     /* Only if using per desk bg overlay */
1968              /* FIXME - We should break when the clip region becomes empty */
1969              if (EobjGetX(eo) == 0 && EobjGetY(eo) == 0)
1970                 stop = 1;
1971              if (stop)
1972                 break;
1973 #endif
1974           }
1975
1976         if (cw->clip == None)
1977            cw->clip = ERegionCreate();
1978         ERegionCopy(cw->clip, clip);
1979         cw->have_clip = 1;
1980
1981         ECompMgrWinSetPicts(eo);
1982
1983         D3printf(" - %#lx desk=%d shown=%d dam=%d pict=%#lx\n",
1984                  EobjGetXwin(eo), eo->desk->num, eo->shown, cw->damaged,
1985                  cw->picture);
1986
1987 #if 0                           /* FIXME - Need this? */
1988         if (!cw->damaged)
1989            continue;
1990 #endif
1991         if (cw->picture == None && !eo->noredir)
1992            continue;
1993
1994         if (eo->ghost)
1995           {
1996              Mode_compmgr.ghosts = 1;
1997              continue;
1998           }
1999
2000         D3printf
2001            ("ECompMgrDetermineOrder hook in %d - %#lx desk=%d shown=%d\n",
2002             dsk->num, EobjGetXwin(eo), eo->desk->num, eo->shown);
2003
2004         if (!eo_first)
2005            eo_first = eo;
2006         cw->prev = eo_prev;
2007         if (eo_prev)
2008            eo_prev->cmhook->next = eo;
2009         eo_prev = eo;
2010
2011         switch (cw->mode)
2012           {
2013           case WINDOW_UNREDIR:
2014           case WINDOW_SOLID:
2015              D3printf("-   clip %#lx %#lx %d,%d %dx%d: %s\n", EobjGetXwin(eo),
2016                       cw->clip, EobjGetX(eo), EobjGetY(eo), EobjGetW(eo),
2017                       EobjGetH(eo), EobjGetName(eo));
2018 #if USE_CLIP_RELATIVE_TO_DESK
2019              ERegionUnionOffset(clip, 0, 0, cw->shape);
2020 #else
2021              ERegionUnionOffset(clip, EoGetX(dsk), EoGetY(dsk), cw->shape);
2022 #endif
2023              break;
2024
2025           default:
2026              D3printf("- noclip %#lx %#lx %d,%d %dx%d: %s\n", EobjGetXwin(eo),
2027                       cw->clip, EobjGetX(eo), EobjGetY(eo), EobjGetW(eo),
2028                       EobjGetH(eo), EobjGetName(eo));
2029              break;
2030           }
2031
2032 #if !USE_BG_WIN_ON_ALL_DESKS    /* Not if using per desk bg overlay */
2033         /* FIXME - We should break when the clip region becomes empty */
2034         if (eo->type == EOBJ_TYPE_DESK &&
2035             EobjGetX(eo) == 0 && EobjGetY(eo) == 0)
2036            stop = 1;
2037         if (stop)
2038            break;
2039 #endif
2040      }
2041    if (eo_prev)
2042       eo_prev->cmhook->next = NULL;
2043
2044    *first = eo_first;
2045    *last = eo_prev;
2046
2047    Mode_compmgr.reorder = 0;
2048    return stop;
2049 }
2050
2051 static              XserverRegion
2052 ECompMgrRepaintObjSetClip(XserverRegion rgn, XserverRegion damage,
2053                           XserverRegion clip, int x, int y)
2054 {
2055    ERegionCopy(rgn, damage);
2056 #if USE_CLIP_RELATIVE_TO_DESK
2057    ERegionSubtractOffset(rgn, x, y, clip);
2058 #else
2059    ERegionSubtractOffset(rgn, 0, 0, clip);
2060    x = y = 0;
2061 #endif
2062    return rgn;
2063 }
2064
2065 static void
2066 ECompMgrRepaintObj(Picture pbuf, XserverRegion region, EObj * eo, int mode)
2067 {
2068    static XserverRegion rgn_clip = None;
2069    Display            *dpy = disp;
2070    ECmWinInfo         *cw;
2071    Desk               *dsk = eo->desk;
2072    int                 x, y;
2073    XserverRegion       clip;
2074    Picture             alpha;
2075
2076    cw = eo->cmhook;
2077
2078    if (rgn_clip == None)
2079       rgn_clip = ERegionCreate();
2080
2081    x = EoGetX(dsk);
2082    y = EoGetY(dsk);
2083
2084    if (mode == 0)
2085      {
2086         /* Painting opaque windows top down. */
2087 #if 0
2088         if (ERegionIsEmpty(clip))
2089           {
2090              D2printf(" - Quit - repaint region is empty\n");
2091              return;
2092           }
2093 #endif
2094
2095         switch (cw->mode)
2096           {
2097           case WINDOW_UNREDIR:
2098           case WINDOW_SOLID:
2099              clip = ECompMgrRepaintObjSetClip(rgn_clip, region, cw->clip, x, y);
2100              if (EDebug(EDBUG_TYPE_COMPMGR2))
2101                 ECompMgrWinDumpInfo("ECompMgrRepaintObj solid", eo, clip, 0);
2102              XFixesSetPictureClipRegion(dpy, pbuf, 0, 0, clip);
2103              XRenderComposite(dpy, PictOpSrc, cw->picture, None, pbuf,
2104                               0, 0, 0, 0, x + cw->rcx, y + cw->rcy, cw->rcw,
2105                               cw->rch);
2106              break;
2107           }
2108      }
2109    else
2110      {
2111         /* Painting trans stuff bottom up. */
2112
2113         switch (cw->mode)
2114           {
2115           default:
2116              clip = None;
2117              break;
2118
2119           case WINDOW_TRANS:
2120           case WINDOW_ARGB:
2121              clip = ECompMgrRepaintObjSetClip(rgn_clip, region, cw->clip, x, y);
2122              if (EDebug(EDBUG_TYPE_COMPMGR2))
2123                 ECompMgrWinDumpInfo("ECompMgrRepaintObj trans", eo, clip, 0);
2124              XFixesSetPictureClipRegion(dpy, pbuf, 0, 0, clip);
2125              if (cw->opacity != OPAQUE && !cw->pict_alpha)
2126                 cw->pict_alpha =
2127                    EPictureCreateSolid(True, OP32To8(cw->opacity),
2128                                        Conf_compmgr.shadows.color);
2129              XRenderComposite(dpy, PictOpOver, cw->picture, cw->pict_alpha,
2130                               pbuf, 0, 0, 0, 0, x + cw->rcx, y + cw->rcy,
2131                               cw->rcw, cw->rch);
2132              break;
2133           }
2134
2135 #if ENABLE_SHADOWS
2136         if (!cw->has_shadow)
2137            return;
2138
2139         if (clip == None)
2140            clip = ECompMgrRepaintObjSetClip(rgn_clip, region, cw->clip, x, y);
2141         ERegionSubtractOffset(clip, x, y, cw->shape);
2142         XFixesSetPictureClipRegion(dpy, pbuf, 0, 0, clip);
2143
2144         switch (Mode_compmgr.shadow_mode)
2145           {
2146           case ECM_SHADOWS_SHARP:
2147           case ECM_SHADOWS_ECHO:
2148              if (cw->opacity != OPAQUE && !cw->shadow_alpha)
2149                 cw->shadow_alpha =
2150                    EPictureCreateSolid(True,
2151                                        OP32To8(cw->opacity *
2152                                                Mode_compmgr.opac_sharp),
2153                                        Conf_compmgr.shadows.color);
2154              alpha = cw->shadow_alpha ? cw->shadow_alpha : transBlackPicture;
2155              if (Mode_compmgr.shadow_mode == ECM_SHADOWS_SHARP)
2156                 XRenderComposite(dpy, PictOpOver, alpha, cw->picture, pbuf,
2157                                  0, 0, 0, 0,
2158                                  x + cw->rcx + cw->shadow_dx,
2159                                  y + cw->rcy + cw->shadow_dy,
2160                                  cw->shadow_width, cw->shadow_height);
2161              else
2162                 XRenderComposite(dpy, PictOpOver, cw->picture, alpha, pbuf,
2163                                  0, 0, 0, 0,
2164                                  x + cw->rcx + cw->shadow_dx,
2165                                  y + cw->rcy + cw->shadow_dy,
2166                                  cw->shadow_width, cw->shadow_height);
2167              break;
2168
2169           case ECM_SHADOWS_BLURRED:
2170              if (cw->shadow_pict == None)
2171                 break;
2172
2173              if (cw->opacity != OPAQUE && !cw->pict_alpha)
2174                 cw->pict_alpha =
2175                    EPictureCreateSolid(True, OP32To8(cw->opacity),
2176                                        Conf_compmgr.shadows.color);
2177              alpha = (cw->pict_alpha) ? cw->pict_alpha : transBlackPicture;
2178              XRenderComposite(dpy, PictOpOver, alpha, cw->shadow_pict, pbuf,
2179                               0, 0, 0, 0,
2180                               x + cw->rcx + cw->shadow_dx,
2181                               y + cw->rcy + cw->shadow_dy,
2182                               cw->shadow_width, cw->shadow_height);
2183              break;
2184           }
2185 #endif
2186      }
2187 }
2188
2189 static void
2190 ECompMgrPaintGhosts(Picture pict, XserverRegion damage)
2191 {
2192    EObj               *eo, *const *lst;
2193    int                 i, num;
2194
2195    lst = EobjListStackGet(&num);
2196    for (i = 0; i < num; i++)
2197      {
2198         eo = lst[i];
2199         if (!eo->shown || !eo->ghost)
2200            continue;
2201
2202         switch (eo->cmhook->mode)
2203           {
2204           case WINDOW_UNREDIR:
2205           case WINDOW_SOLID:
2206              ECompMgrRepaintObj(pict, Mode_compmgr.rgn_screen, eo, 0);
2207              break;
2208           case WINDOW_TRANS:
2209           case WINDOW_ARGB:
2210              ECompMgrRepaintObj(pict, Mode_compmgr.rgn_screen, eo, 1);
2211              break;
2212           }
2213
2214         /* Subtract window region from damage region */
2215         ERegionSubtractOffset(damage, 0, 0, eo->cmhook->shape);
2216      }
2217 }
2218
2219 void
2220 ECompMgrRepaint(void)
2221 {
2222    Display            *dpy = disp;
2223    EObj               *eo;
2224    Picture             pbuf;
2225    Desk               *dsk = DeskGet(0);
2226
2227    if (!Mode_compmgr.active || !Mode_compmgr.got_damage)
2228       return;
2229
2230    ERegionIntersect(Mode_compmgr.damage, Mode_compmgr.rgn_screen);
2231
2232    D2printf("ECompMgrRepaint rootBuffer=%#lx rootPicture=%#lx\n",
2233             rootBuffer, rootPicture);
2234    if (EDebug(EDBUG_TYPE_COMPMGR2))
2235       ERegionShow("damage", Mode_compmgr.damage);
2236
2237    pbuf = rootBuffer;
2238
2239    if (!dsk)
2240       return;
2241
2242    /* Do paint order list linking */
2243    if (Mode_compmgr.reorder)
2244       ECompMgrDetermineOrder(NULL, 0, &Mode_compmgr.eo_first,
2245                              &Mode_compmgr.eo_last, dsk, None);
2246
2247    /* Paint opaque windows top down */
2248    for (eo = Mode_compmgr.eo_first; eo; eo = eo->cmhook->next)
2249       ECompMgrRepaintObj(pbuf, Mode_compmgr.damage, eo, 0);
2250
2251 #if 0                           /* FIXME - NoBg? */
2252    Picture             pict;
2253
2254    if (EDebug(EDBUG_TYPE_COMPMGR2))
2255       ERegionShow("after opaque", region);
2256
2257    /* Repaint background, clipped by damage region and opaque windows */
2258    pict = dsk->o.cmhook->picture;
2259    D1printf("ECompMgrRepaint desk picture=%#lx\n", pict);
2260    XFixesSetPictureClipRegion(dpy, pbuf, 0, 0, region);
2261    XRenderComposite(dpy, PictOpSrc, pict, None, pbuf,
2262                     0, 0, 0, 0, 0, 0, WinGetW(VROOT), WinGetH(VROOT));
2263 #endif
2264
2265    /* Paint trans windows and shadows bottom up */
2266    for (eo = Mode_compmgr.eo_last; eo; eo = eo->cmhook->prev)
2267       ECompMgrRepaintObj(pbuf, Mode_compmgr.damage, eo, 1);
2268
2269    /* Paint any ghost windows (adjusting damage region) */
2270    if (Mode_compmgr.ghosts)
2271       ECompMgrPaintGhosts(rootPicture, Mode_compmgr.damage);
2272
2273    if (pbuf != rootPicture)
2274      {
2275         XFixesSetPictureClipRegion(dpy, pbuf, 0, 0, Mode_compmgr.damage);
2276         XRenderComposite(dpy, PictOpSrc, pbuf, None, rootPicture,
2277                          0, 0, 0, 0, 0, 0, WinGetW(VROOT), WinGetH(VROOT));
2278      }
2279
2280    Mode_compmgr.got_damage = 0;
2281 }
2282
2283 static void
2284 _ECompMgrIdler(void *data __UNUSED__)
2285 {
2286    /* Do we get here on auto? */
2287    if (!Mode_compmgr.got_damage /* || Mode_compmgr.mode == ECM_MODE_AUTO */ )
2288       return;
2289    ECompMgrRepaint();
2290 }
2291
2292 static void
2293 ECompMgrRootBufferCreate(unsigned int w, unsigned int h)
2294 {
2295    /* Root buffer picture and pixmap */
2296    rootBuffer = EPictureCreateBuffer(VROOT, w, h, &Mode_compmgr.pmap);
2297
2298    /* Screen region */
2299    Mode_compmgr.rgn_screen = ERegionCreateRect(0, 0, w, h);
2300
2301    /* Overall clip region used while recalculating window clip regions */
2302    Mode_compmgr.rgn_clip = ERegionCreate();
2303 }
2304
2305 static void
2306 ECompMgrRootBufferDestroy(void)
2307 {
2308    PICTURE_DESTROY(rootBuffer);
2309    PIXMAP_DESTROY(Mode_compmgr.pmap);
2310
2311    REGION_DESTROY(Mode_compmgr.rgn_screen);
2312    REGION_DESTROY(Mode_compmgr.rgn_clip);
2313 }
2314
2315 Pixmap
2316 ECompMgrGetRootBuffer(void)
2317 {
2318    return Mode_compmgr.pmap;
2319 }
2320
2321 static void
2322 ECompMgrRootConfigure(void *prm __UNUSED__, XEvent * ev)
2323 {
2324    D1printf("ECompMgrRootConfigure root\n");
2325
2326    ECompMgrRootBufferDestroy();
2327    ECompMgrRootBufferCreate(ev->xconfigure.width, ev->xconfigure.height);
2328 }
2329
2330 #if USE_DESK_EXPOSE             /* FIXME - Remove? */
2331 static void
2332 ECompMgrRootExpose(void *prm __UNUSED__, XEvent * ev)
2333 {
2334    static XRectangle  *expose_rects = 0;
2335    static int          size_expose = 0;
2336    static int          n_expose = 0;
2337    int                 more = ev->xexpose.count + 1;
2338
2339    if (ev->xexpose.window != WinGetXwin(VROOT))
2340       return;
2341
2342    D1printf("ECompMgrRootExpose %d %d %d\n", n_expose, size_expose,
2343             ev->xexpose.count);
2344
2345    if (n_expose == size_expose)
2346      {
2347         expose_rects = EREALLOC(XRectangle, expose_rects, size_expose + more);
2348         size_expose += more;
2349      }
2350    expose_rects[n_expose].x = ev->xexpose.x;
2351    expose_rects[n_expose].y = ev->xexpose.y;
2352    expose_rects[n_expose].width = ev->xexpose.width;
2353    expose_rects[n_expose].height = ev->xexpose.height;
2354    n_expose++;
2355    if (ev->xexpose.count == 0)
2356      {
2357         XserverRegion       region;
2358
2359         region = ERegionCreateFromRects(expose_rects, n_expose);
2360
2361         ECompMgrDamageMerge(region);
2362         ERegionDestroy(region);
2363         n_expose = 0;
2364      }
2365 }
2366 #endif
2367
2368 #if ENABLE_SHADOWS
2369 static void
2370 ECompMgrShadowsInit(int mode, int cleanup)
2371 {
2372    Mode_compmgr.shadow_mode = mode;
2373
2374    Conf_compmgr.shadows.blur.opacity =
2375       OpacityFix(Conf_compmgr.shadows.blur.opacity, 100);
2376    Mode_compmgr.opac_blur = .01 * Conf_compmgr.shadows.blur.opacity;
2377    Conf_compmgr.shadows.sharp.opacity =
2378       OpacityFix(Conf_compmgr.shadows.sharp.opacity, 100);
2379    Mode_compmgr.opac_sharp = .01 * Conf_compmgr.shadows.sharp.opacity;
2380
2381    Efree(gaussianMap);
2382    gaussianMap = NULL;
2383
2384    if (mode != ECM_SHADOWS_OFF)
2385      {
2386         if (mode == ECM_SHADOWS_BLURRED)
2387            transBlackPicture =
2388               EPictureCreateSolid(True, 255, Conf_compmgr.shadows.color);
2389         else
2390            transBlackPicture =
2391               EPictureCreateSolid(True,
2392                                   OP32To8(Mode_compmgr.opac_sharp * OPAQUE),
2393                                   Conf_compmgr.shadows.color);
2394      }
2395    else
2396      {
2397         PICTURE_DESTROY(transBlackPicture);
2398      }
2399
2400    if (cleanup)
2401      {
2402         EObj               *const *lst;
2403         int                 i, num;
2404
2405         lst = EobjListStackGet(&num);
2406         for (i = 0; i < num; i++)
2407            ECompMgrWinInvalidate(lst[i], INV_SHADOW);
2408         _ECM_SET_SHADOW_CHANGED();      /* Force extents/shadow update */
2409      }
2410 }
2411 #else
2412 #define ECompMgrShadowsInit(mode, cleanup)
2413 #endif
2414
2415 int
2416 ECompMgrIsActive(void)
2417 {
2418    return Mode_compmgr.active;
2419 }
2420
2421 static void
2422 ECompMgrStart(void)
2423 {
2424    EObj               *const *lst;
2425    int                 i, num;
2426    XRenderPictFormat  *pictfmt;
2427    XRenderPictureAttributes pa;
2428
2429    if (Mode_compmgr.active || Conf_compmgr.mode == ECM_MODE_OFF)
2430       return;
2431    Conf_compmgr.enable = Mode_compmgr.active = 1;
2432    Mode_compmgr.mode = Conf_compmgr.mode;
2433
2434    Conf_compmgr.override_redirect.opacity =
2435       OpacityFix(Conf_compmgr.override_redirect.opacity, 100);
2436
2437    ECompMgrRootBufferCreate(WinGetW(VROOT), WinGetH(VROOT));
2438
2439    Mode_compmgr.root = WinGetXwin(VROOT);
2440 #if USE_COMPOSITE_OVERLAY_WINDOW
2441    if (Conf_compmgr.use_cow && !Mode.wm.window)
2442      {
2443         Mode_compmgr.cow = XCompositeGetOverlayWindow(disp, WinGetXwin(VROOT));
2444         if (Mode_compmgr.cow != None)
2445           {
2446              /* Ok, got the cow! */
2447              Mode_compmgr.root = Mode_compmgr.cow;
2448              /* It is possible to get it stacked below others?!? */
2449              XRaiseWindow(disp, Mode_compmgr.cow);
2450              /* Pass all input events through */
2451              XShapeCombineRectangles(disp, Mode_compmgr.cow, ShapeInput, 0, 0,
2452                                      NULL, 0, ShapeSet, Unsorted);
2453              D1printf("COW/CMroot=%#lx/%#lx\n",
2454                       Mode_compmgr.cow, Mode_compmgr.root);
2455           }
2456      }
2457    else
2458      {
2459         Mode_compmgr.cow = None;
2460      }
2461 #endif
2462
2463    pa.subwindow_mode = IncludeInferiors;
2464    pictfmt = XRenderFindVisualFormat(disp, WinGetVisual(VROOT));
2465    rootPicture =
2466       XRenderCreatePicture(disp, Mode_compmgr.root, pictfmt, CPSubwindowMode,
2467                            &pa);
2468
2469    ECompMgrShadowsInit(Conf_compmgr.shadows.mode, 0);
2470
2471    EGrabServer();
2472
2473    switch (Mode_compmgr.mode)
2474      {
2475      case ECM_MODE_ROOT:
2476         XCompositeRedirectSubwindows(disp, WinGetXwin(VROOT),
2477                                      CompositeRedirectManual);
2478 #if USE_DESK_EXPOSE             /* FIXME - Remove? */
2479         ESelectInputChange(WinGetXwin(VROOT), ExposureMask, 0);
2480 #endif
2481         break;
2482      case ECM_MODE_WINDOW:
2483 #if USE_DESK_EXPOSE             /* FIXME - Remove? */
2484         ESelectInputChange(WinGetXwin(VROOT), ExposureMask, 0);
2485 #endif
2486         break;
2487      case ECM_MODE_AUTO:
2488         XCompositeRedirectSubwindows(disp, WinGetXwin(VROOT),
2489                                      CompositeRedirectAutomatic);
2490         break;
2491      }
2492
2493    Mode_compmgr.got_damage = 0;
2494
2495    rgn_tmp = ERegionCreate();
2496    rgn_tmp2 = ERegionCreate();
2497
2498    EventCallbackRegister(VROOT, 0, ECompMgrHandleRootEvent, NULL);
2499
2500    wm_cm_sel = SelectionAcquire("_NET_WM_CM_S", NULL, NULL);
2501
2502    lst = EobjListStackGet(&num);
2503    for (i = 0; i < num; i++)
2504      {
2505         ECompMgrWinNew(lst[i]);
2506         if (lst[i]->shown)
2507            ECompMgrWinMap(lst[i]);
2508      }
2509
2510 #if !USE_BG_WIN_ON_ALL_DESKS
2511    DesksBackgroundRefresh(NULL, DESK_BG_RECONFIGURE_ALL);
2512 #endif
2513    _ECM_SET_CLIP_CHANGED();
2514    EUngrabServer();
2515    ESync(0);
2516 }
2517
2518 static void
2519 ECompMgrStop(void)
2520 {
2521    EObj               *const *lst1, **lst;
2522    int                 i, num;
2523
2524    if (!Mode_compmgr.active)
2525       return;
2526    Conf_compmgr.enable = Mode_compmgr.active = 0;
2527
2528    EGrabServer();
2529
2530    SelectionRelease(wm_cm_sel);
2531    wm_cm_sel = NULL;
2532
2533    PICTURE_DESTROY(rootPicture);
2534
2535    ECompMgrRootBufferDestroy();
2536
2537    ECompMgrShadowsInit(ECM_SHADOWS_OFF, 0);
2538
2539    lst1 = EobjListStackGet(&num);
2540    if (num > 0)
2541      {
2542         lst = EMALLOC(EObj *, num);
2543         if (lst)
2544           {
2545              memcpy(lst, lst1, num * sizeof(EObj *));
2546              for (i = 0; i < num; i++)
2547                {
2548                   if (lst[i]->type == EOBJ_TYPE_EXT)
2549                      EobjUnregister(lst[i]);    /* Modifies the object stack! */
2550                   else
2551                      ECompMgrWinDel(lst[i]);
2552                }
2553              Efree(lst);
2554           }
2555      }
2556
2557    Mode_compmgr.got_damage = 0;
2558    REGION_DESTROY(Mode_compmgr.damage);
2559    REGION_DESTROY(rgn_tmp);
2560    REGION_DESTROY(rgn_tmp2);
2561
2562    if (Mode_compmgr.mode == ECM_MODE_ROOT)
2563       XCompositeUnredirectSubwindows(disp, WinGetXwin(VROOT),
2564                                      CompositeRedirectManual);
2565
2566    EventCallbackUnregister(VROOT, 0, ECompMgrHandleRootEvent, NULL);
2567
2568 #if USE_COMPOSITE_OVERLAY_WINDOW
2569    if (Mode_compmgr.cow != None)
2570      {
2571         XCompositeReleaseOverlayWindow(disp, WinGetXwin(VROOT));
2572         Mode_compmgr.cow = None;
2573      }
2574 #endif
2575
2576 #if !USE_BG_WIN_ON_ALL_DESKS
2577    DesksBackgroundRefresh(NULL, DESK_BG_RECONFIGURE_ALL);
2578 #endif
2579    EUngrabServer();
2580    ESync(0);
2581 }
2582
2583 void
2584 ECompMgrConfigGet(cfg_composite * cfg)
2585 {
2586    cfg->enable = Conf_compmgr.enable;
2587    cfg->shadow = Conf_compmgr.shadows.mode;
2588    cfg->fading = Conf_compmgr.fading.enable;
2589    cfg->opacity_focused = Conf.opacity.focused;
2590    cfg->opacity_unfocused = Conf.opacity.unfocused;
2591    cfg->opacity_override = Conf_compmgr.override_redirect.opacity;
2592    cfg->fade_speed = 100 - (Conf_compmgr.fading.time / 10);
2593 }
2594
2595 void
2596 ECompMgrConfigSet(const cfg_composite * cfg)
2597 {
2598    if (Conf_compmgr.mode == ECM_MODE_OFF)
2599      {
2600         if (cfg->enable)
2601            DialogOK("Enable Composite Error",
2602                     _("Cannot enable Composite Manager.\n"
2603                       "Use xdpyinfo to check that\n"
2604                       "Composite, Damage, Fixes, and Render\n"
2605                       "extensions are loaded."));
2606         return;
2607      }
2608
2609    if (cfg->enable != Conf_compmgr.enable)
2610      {
2611         Conf_compmgr.enable = cfg->enable;
2612         Conf_compmgr.shadows.mode = cfg->shadow;
2613         if (cfg->enable)
2614            ECompMgrStart();
2615         else
2616            ECompMgrStop();
2617      }
2618    else
2619      {
2620         if (cfg->shadow != Conf_compmgr.shadows.mode)
2621           {
2622              Conf_compmgr.shadows.mode = cfg->shadow;
2623              if (Conf_compmgr.enable)
2624                {
2625                   ECompMgrShadowsInit(Conf_compmgr.shadows.mode, 1);
2626                   ECompMgrDamageAll();
2627                }
2628           }
2629      }
2630
2631    Conf_compmgr.fading.enable = cfg->fading;
2632    Conf_compmgr.fading.time = (100 - cfg->fade_speed) * 10;
2633
2634    Conf.opacity.focused = cfg->opacity_focused;
2635    Conf.opacity.unfocused = cfg->opacity_unfocused;
2636    Conf_compmgr.override_redirect.opacity = cfg->opacity_override;
2637
2638    EobjsOpacityUpdate(Conf_compmgr.override_redirect.opacity);
2639
2640    autosave();
2641 }
2642
2643 /*
2644  * Event handlers
2645  */
2646 #define USE_WINDOW_EVENTS 0
2647
2648 static void
2649 ECompMgrHandleWindowEvent(Win win __UNUSED__, XEvent * ev, void *prm)
2650 {
2651    EObj               *eo = (EObj *) prm;
2652
2653    D2printf("ECompMgrHandleWindowEvent: type=%d\n", ev->type);
2654
2655    switch (ev->type)
2656      {
2657 #if USE_WINDOW_EVENTS
2658      case ConfigureNotify:
2659         ECompMgrWinConfigure(eo, ev);
2660         break;
2661
2662      case MapNotify:
2663         ECompMgrWinMap(eo);
2664         break;
2665      case UnmapNotify:
2666         if (eo->type == EOBJ_TYPE_EXT && eo->cmhook)
2667           {
2668              ECompMgrWinUnmap(eo);
2669              eo->shown = 0;
2670           }
2671         break;
2672
2673      case CirculateNotify:
2674         ECompMgrWinCirculate(eo, ev);
2675         break;
2676 #endif
2677
2678 #if USE_DESK_VISIBILITY
2679      case VisibilityNotify:
2680         ECompMgrDeskVisibility(eo, ev);
2681         break;
2682 #endif
2683
2684      case EX_EVENT_DAMAGE_NOTIFY:
2685         ECompMgrWinDamage(eo, ev);
2686         break;
2687      }
2688 }
2689
2690 static void
2691 ECompMgrHandleRootEvent(Win win __UNUSED__, XEvent * ev, void *prm)
2692 {
2693    Window              xwin;
2694    EObj               *eo;
2695
2696    D2printf("ECompMgrHandleRootEvent: type=%d\n", ev->type);
2697
2698    switch (ev->type)
2699      {
2700      case CreateNotify:
2701         xwin = ev->xcreatewindow.window;
2702       case_CreateNotify:
2703         if (Conf_compmgr.override_redirect.mode != ECM_OR_ON_CREATE)
2704            break;
2705         eo = EobjListStackFind(xwin);
2706         if (!eo)
2707            EobjRegister(xwin, EOBJ_TYPE_EXT);
2708         break;
2709
2710      case DestroyNotify:
2711         xwin = ev->xdestroywindow.window;
2712       case_DestroyNotify:
2713         eo = EobjListStackFind(xwin);
2714         if (eo && eo->type == EOBJ_TYPE_EXT)
2715           {
2716              if (ev->type == DestroyNotify)
2717                 eo->gone = 1;
2718              EobjUnregister(eo);
2719           }
2720         break;
2721
2722      case ReparentNotify:
2723      case EX_EVENT_REPARENT_GONE:
2724         xwin = ev->xreparent.window;
2725         if (ev->xreparent.parent == WinGetXwin(VROOT))
2726            goto case_CreateNotify;
2727         else
2728            goto case_DestroyNotify;
2729
2730      case ConfigureNotify:
2731         if (ev->xconfigure.window == WinGetXwin(VROOT))
2732           {
2733              ECompMgrRootConfigure(prm, ev);
2734           }
2735         else
2736           {
2737              eo = EobjListStackFind(ev->xconfigure.window);
2738              if (eo && eo->type == EOBJ_TYPE_EXT && eo->cmhook)
2739                {
2740                   ECompMgrWinConfigure(eo, ev);
2741                }
2742           }
2743         break;
2744
2745      case MapNotify:
2746 #if USE_COMPOSITE_OVERLAY_WINDOW
2747         if (ev->xmap.window == Mode_compmgr.cow)
2748            break;
2749 #endif
2750         eo = EobjListStackFind(ev->xmap.window);
2751         if (!eo)
2752            eo = EobjRegister(ev->xmap.window, EOBJ_TYPE_EXT);
2753         if (eo && eo->type == EOBJ_TYPE_EXT && eo->cmhook)
2754           {
2755              eo->shown = 1;
2756              EobjListStackRaise(eo, 0);
2757              ECompMgrWinMap(eo);
2758           }
2759         break;
2760
2761      case UnmapNotify:
2762      case EX_EVENT_UNMAP_GONE:
2763         eo = EobjListStackFind(ev->xunmap.window);
2764         if (eo && eo->type == EOBJ_TYPE_EXT && eo->cmhook)
2765           {
2766              if (ev->type == EX_EVENT_UNMAP_GONE)
2767                 eo->gone = 1;
2768 #if 0
2769              /* No. Unredirection seems to cause map/unmap => loop */
2770              if (Conf_compmgr.override_redirect.mode == ECM_OR_ON_MAPUNMAP)
2771                {
2772                   EobjUnregister(eo);
2773                }
2774              else
2775 #endif
2776                {
2777                   ECompMgrWinUnmap(eo);
2778                   eo->shown = 0;
2779                }
2780           }
2781         break;
2782
2783      case CirculateNotify:
2784         eo = EobjListStackFind(ev->xcirculate.window);
2785         if (eo && eo->cmhook)
2786            ECompMgrWinCirculate(eo, ev);
2787         break;
2788
2789 #if USE_DESK_EXPOSE             /* FIXME - Remove? */
2790      case Expose:
2791         if (Mode_compmgr.shadow_mode != ECM_SHADOWS_OFF)
2792            ECompMgrRootExpose(prm, ev);
2793         break;
2794 #endif
2795      }
2796 }
2797
2798 /*
2799  * Module functions
2800  */
2801
2802 static void
2803 ECompMgrInit(void)
2804 {
2805    if (!XEXT_AVAILABLE(XEXT_CM_ALL))
2806      {
2807         Conf_compmgr.mode = ECM_MODE_OFF;
2808         goto done;
2809      }
2810
2811    Mode_compmgr.use_pixmap = Conf_compmgr.use_name_pixmap;
2812
2813 #if 0                           /* TBD - Force ECM_MODE_ROOT at startup */
2814    if (Conf_compmgr.mode == ECM_MODE_OFF)
2815 #endif
2816       Conf_compmgr.mode = ECM_MODE_ROOT;
2817
2818  done:
2819    if (Conf_compmgr.mode == ECM_MODE_OFF)
2820       Conf_compmgr.enable = 0;
2821    D1printf("ECompMgrInit: enable=%d mode=%d\n", Conf_compmgr.enable,
2822             Conf_compmgr.mode);
2823 }
2824
2825 static void
2826 ECompMgrSighan(int sig, void *prm __UNUSED__)
2827 {
2828    if (sig != ESIGNAL_INIT && Mode_compmgr.mode == ECM_MODE_OFF)
2829       return;
2830
2831    switch (sig)
2832      {
2833      case ESIGNAL_INIT:
2834         ECompMgrInit();
2835         if (Conf_compmgr.enable)
2836            ECompMgrStart();
2837         IdlerAdd(_ECompMgrIdler, NULL);
2838         break;
2839      }
2840 }
2841
2842 static void
2843 CompMgrIpc(const char *params)
2844 {
2845    const char         *p;
2846    char                cmd[128], prm[4096];
2847    int                 len;
2848
2849    cmd[0] = prm[0] = '\0';
2850    p = params;
2851    if (p)
2852      {
2853         len = 0;
2854         sscanf(p, "%100s %4000s %n", cmd, prm, &len);
2855         p += len;
2856      }
2857
2858    if (!p || cmd[0] == '?')
2859      {
2860         IpcPrintf("CompMgr - on=%d\n", Mode_compmgr.active);
2861      }
2862    else if (!strcmp(cmd, "start"))
2863      {
2864         ECompMgrStart();
2865         autosave();
2866      }
2867    else if (!strcmp(cmd, "stop"))
2868      {
2869         ECompMgrStop();
2870         autosave();
2871      }
2872    else if (!strncmp(cmd, "list", 2))
2873      {
2874         /* TBD */
2875      }
2876    else if (!strncmp(cmd, "oi", 2))
2877      {
2878         Window              win;
2879         EObj               *eo;
2880
2881         win = None;
2882         sscanf(prm, "%lx", &win);
2883         eo = EobjListStackFind(win);
2884         if (eo)
2885            ECompMgrWinDumpInfo("EObj", eo, None, 1);
2886      }
2887 }
2888
2889 static const IpcItem CompMgrIpcArray[] = {
2890    {
2891     CompMgrIpc,
2892     "compmgr", "cm",
2893     "Composite manager functions",
2894     "  cm ?                     Show info\n"
2895     "  cm start                 Start composite manager\n"
2896     "  cm stop                  Stop composite manager\n"}
2897    ,
2898 };
2899 #define N_IPC_FUNCS (sizeof(CompMgrIpcArray)/sizeof(IpcItem))
2900
2901 static const CfgItem CompMgrCfgItems[] = {
2902    CFG_ITEM_BOOL(Conf_compmgr, enable, 0),
2903    CFG_ITEM_INT(Conf_compmgr, mode, ECM_MODE_ROOT),
2904    CFG_ITEM_INT(Conf_compmgr, shadows.mode, 0),
2905    CFG_ITEM_INT(Conf_compmgr, shadows.offset_x, 3),
2906    CFG_ITEM_INT(Conf_compmgr, shadows.offset_y, 5),
2907    CFG_ITEM_INT(Conf_compmgr, shadows.blur.radius, 5),
2908    CFG_ITEM_INT(Conf_compmgr, shadows.blur.opacity, 75),
2909    CFG_ITEM_INT(Conf_compmgr, shadows.sharp.opacity, 30),
2910    CFG_ITEM_HEX(Conf_compmgr, shadows.color, 0),
2911    CFG_ITEM_BOOL(Conf_compmgr, resize_fix_enable, 0),
2912    CFG_ITEM_BOOL(Conf_compmgr, use_name_pixmap, 0),
2913 #if USE_COMPOSITE_OVERLAY_WINDOW
2914    CFG_ITEM_BOOL(Conf_compmgr, use_cow, 1),
2915 #endif
2916    CFG_ITEM_BOOL(Conf_compmgr, fading.enable, 1),
2917    CFG_ITEM_INT(Conf_compmgr, fading.time, 200),
2918    CFG_ITEM_INT(Conf_compmgr, override_redirect.mode, 1),
2919    CFG_ITEM_INT(Conf_compmgr, override_redirect.opacity, 90),
2920 };
2921 #define N_CFG_ITEMS (sizeof(CompMgrCfgItems)/sizeof(CfgItem))
2922
2923 /*
2924  * Module descriptor
2925  */
2926 extern const EModule ModCompMgr;
2927 const EModule       ModCompMgr = {
2928    "compmgr", "cm",
2929    ECompMgrSighan,
2930    {N_IPC_FUNCS, CompMgrIpcArray},
2931    {N_CFG_ITEMS, CompMgrCfgItems}
2932 };
2933
2934 #endif /* USE_COMPOSITE */
2935
2936 /*
2937  * $Id: xcompmgr.c,v 1.26 2004/08/14 21:39:51 keithp Exp $
2938  *
2939  * Copyright © 2003 Keith Packard
2940  *
2941  * Permission to use, copy, modify, distribute, and sell this software and its
2942  * documentation for any purpose is hereby granted without fee, provided that
2943  * the above copyright notice appear in all copies and that both that
2944  * copyright notice and this permission notice appear in supporting
2945  * documentation, and that the name of Keith Packard not be used in
2946  * advertising or publicity pertaining to distribution of the software without
2947  * specific, written prior permission.  Keith Packard makes no
2948  * representations about the suitability of this software for any purpose.  It
2949  * is provided "as is" without express or implied warranty.
2950  *
2951  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
2952  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
2953  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
2954  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
2955  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
2956  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2957  * PERFORMANCE OF THIS SOFTWARE.
2958  */
2959 /*
2960  * Modified by Matthew Hawn. I don't know what to say here so follow what it 
2961  * says above. Not that I can really do anything about it
2962  */