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