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