1 /*
2 * Copyright (C) 2004-2018 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 #include "config.h"
24
25 #include <X11/Xlib.h>
26
27 #include "E.h"
28 #include "animation.h"
29 #include "desktops.h"
30 #include "ecompmgr.h"
31 #include "eobj.h"
32 #include "ewins.h" /* FIXME - Should not be here */
33 #include "hints.h"
34 #include "xprop.h"
35 #include "xwin.h"
36
37 int
OpacityFix(int op,int op_0)38 OpacityFix(int op, int op_0)
39 {
40 if (op <= 0)
41 op = op_0;
42 else if (op > 255)
43 op = 100;
44 else if (op > 100) /* Hack to convert old 0-255 range */
45 op = (100 * op) / 255;
46 return op;
47 }
48
49 unsigned int
OpacityFromPercent(int opx)50 OpacityFromPercent(int opx)
51 {
52 unsigned int op = (unsigned int)opx;
53
54 /* op is 0-100, extend to 32 bit */
55 /* op <= 0 and op > 100 is mapped to 100 (opaque) */
56 if (op >= 100)
57 return 0xffffffff;
58 return op * 42949672;
59 }
60
61 int
OpacityToPercent(unsigned int opacity)62 OpacityToPercent(unsigned int opacity)
63 {
64 return (int)(opacity / 42949672);
65 }
66
67 const char *
EobjGetNameSafe(const EObj * eo)68 EobjGetNameSafe(const EObj * eo)
69 {
70 const char *name = NULL;
71
72 if (!eo)
73 goto done;
74
75 name = EobjGetName(eo);
76
77 done:
78 return name ? name : "None";
79 }
80
81 void
EobjSetLayer(EObj * eo,int layer)82 EobjSetLayer(EObj * eo, int layer)
83 {
84 int ilayer = eo->ilayer;
85
86 eo->layer = layer;
87 /*
88 * For usual EWin's the internal layer is the "old" E-layer * 10.
89 *
90 * Internal layers:
91 * 0: Root
92 * 3: Desktop type apps
93 * 5: Below buttons
94 * 10: Lowest ewins
95 * 15: Normal buttons
96 * 20: Normal below ewins
97 * 40: Normal ewins
98 * 60: Above ewins
99 * 75: Above buttons
100 * 80: Ontop ewins
101 * 100: E-Dialogs
102 * 512-: Floating windows
103 * + 0: Virtual desktops
104 * +30: E-Menus
105 * +40: Override redirects
106 * +40: E-Tooltips
107 */
108
109 switch (eo->type)
110 {
111 case EOBJ_TYPE_EWIN:
112 eo->ilayer = 10 * eo->layer;
113 if (eo->ilayer == 0)
114 eo->ilayer = 3;
115 break;
116
117 case EOBJ_TYPE_BUTTON:
118 if (eo->layer > 0)
119 eo->ilayer = 75; /* Ontop */
120 else if (eo->layer == 0)
121 eo->ilayer = 15; /* Normal */
122 else if (eo->layer < 0)
123 eo->ilayer = 5; /* Below */
124 if (eo->layer > 0 && eo->sticky)
125 eo->floating = 1;
126 break;
127
128 default:
129 eo->ilayer = 10 * eo->layer;
130 break;
131 }
132
133 if (eo->floating)
134 eo->ilayer |= 512;
135 else
136 eo->ilayer &= ~512;
137 if (eo->ghost)
138 eo->ilayer |= 1024;
139
140 if (eo->ilayer != ilayer)
141 EobjRaise(eo);
142 }
143
144 void
EobjSetFloating(EObj * eo,int floating)145 EobjSetFloating(EObj * eo, int floating)
146 {
147 if (floating == eo->floating)
148 return;
149
150 #if 0
151 switch (eo->type)
152 {
153 default:
154 break;
155 case EOBJ_TYPE_EWIN:
156 if (floating > 1)
157 eo->desk = 0;
158 break;
159 }
160 #endif
161
162 eo->floating = floating;
163 EobjSetLayer(eo, eo->layer);
164 }
165
166 #if 1 /* FIXME - Remove */
167 int
EobjIsShaped(const EObj * eo)168 EobjIsShaped(const EObj * eo)
169 {
170 switch (eo->type)
171 {
172 default:
173 return 0; /* FIXME */
174 case EOBJ_TYPE_EWIN:
175 return ((EWin *) eo)->state.shaped;
176 }
177 }
178 #endif
179
180 #if USE_GLX
181 #define WINTYPE(t) ((t == EOBJ_TYPE_GLX) ? WIN_TYPE_GLX : WIN_TYPE_INTERNAL)
182 #else
183 #define WINTYPE(t) WIN_TYPE_INTERNAL
184 #endif
185
186 void
EobjInit(EObj * eo,int type,Win win,int x,int y,int w,int h,int su,const char * name)187 EobjInit(EObj * eo, int type, Win win, int x, int y, int w, int h,
188 int su, const char *name)
189 {
190 if (!eo->desk)
191 eo->desk = DeskGet(0);
192
193 if (!win)
194 {
195 if (type == EOBJ_TYPE_EVENT)
196 {
197 win = ECreateEventWindow(VROOT, x, y, w, h);
198 eo->inputonly = 1;
199 }
200 else
201 {
202 win = ECreateObjectWindow(EoGetWin(eo->desk), x, y, w, h, su,
203 WINTYPE(type), NULL);
204 }
205 }
206 eo->type = type;
207 eo->win = win;
208 eo->shaped = -1;
209 if (!win)
210 return;
211
212 if (type == EOBJ_TYPE_EXT)
213 {
214 eo->icccm.wm_name = ex_icccm_title_get(WinGetXwin(win));
215 ex_icccm_name_class_get(WinGetXwin(win),
216 &eo->icccm.wm_res_name,
217 &eo->icccm.wm_res_class);
218 }
219 else if (name)
220 eo->icccm.wm_name = Estrdup(name);
221 if (!eo->icccm.wm_name)
222 eo->icccm.wm_name = Estrdup("-?-");
223
224 if (type != EOBJ_TYPE_EWIN && type != EOBJ_TYPE_EXT)
225 HintsSetWindowName(EobjGetWin(eo), eo->icccm.wm_name);
226
227 #if USE_COMPOSITE
228 switch (type)
229 {
230 case EOBJ_TYPE_EVENT:
231 case EOBJ_TYPE_MISC_NR:
232 case EOBJ_TYPE_ROOT_BG:
233 eo->noredir = 1;
234 break;
235 }
236 ECompMgrWinNew(eo);
237 #endif
238 if (EobjGetXwin(eo) != WinGetXwin(VROOT))
239 EobjListStackAdd(eo, 1);
240
241 if (EDebug(EDBUG_TYPE_EWINS))
242 Eprintf("%s: %#x %s\n", __func__, EobjGetXwin(eo), EobjGetName(eo));
243 }
244
245 void
EobjFini(EObj * eo)246 EobjFini(EObj * eo)
247 {
248 if (EDebug(EDBUG_TYPE_EWINS))
249 Eprintf("%s: %#x %s\n", __func__, EobjGetXwin(eo), EobjGetName(eo));
250
251 EobjListStackDel(eo);
252
253 #if USE_COMPOSITE
254 if (!eo->external)
255 eo->gone = 1; /* Actually not yet (but soon) */
256
257 if (eo->cmhook)
258 ECompMgrWinDel(eo);
259 #endif
260
261 if (eo->external)
262 EUnregisterWindow(EobjGetWin(eo));
263 else
264 EDestroyWindow(EobjGetWin(eo));
265
266 Efree(eo->icccm.wm_name);
267 Efree(eo->icccm.wm_res_name);
268 Efree(eo->icccm.wm_res_class);
269 AnimatorsFree(eo);
270 }
271
272 void
EobjDestroy(EObj * eo)273 EobjDestroy(EObj * eo)
274 {
275 if (EDebug(EDBUG_TYPE_EWINS))
276 Eprintf("%s: %#x %s\n", __func__, EobjGetXwin(eo), EobjGetName(eo));
277
278 EobjFini(eo);
279
280 Efree(eo);
281 }
282
283 EObj *
EobjWindowCreate(int type,int x,int y,int w,int h,int su,const char * name)284 EobjWindowCreate(int type, int x, int y, int w, int h, int su, const char *name)
285 {
286 EObj *eo;
287
288 eo = ECALLOC(EObj, 1);
289
290 eo->floating = 1;
291 EobjSetLayer(eo, 20);
292 EobjInit(eo, type, EobjGetWin(eo), x, y, w, h, su, name);
293 if (!eo->win)
294 {
295 EFREE_NULL(eo);
296 }
297
298 return eo;
299 }
300
301 void
EobjWindowDestroy(EObj * eo)302 EobjWindowDestroy(EObj * eo)
303 {
304 #if USE_COMPOSITE
305 if (eo->shown && !eo->inputonly)
306 EobjUnmap(eo);
307 #endif
308 EobjDestroy(eo);
309 }
310
311 EObj *
EobjRegisterOR(EX_Window xwin __UNUSED__,XWindowAttributes * pxwa __UNUSED__,int mapped __UNUSED__)312 EobjRegisterOR(EX_Window xwin __UNUSED__, XWindowAttributes * pxwa __UNUSED__,
313 int mapped __UNUSED__)
314 {
315 EObj *eo = NULL;
316
317 #if USE_COMPOSITE
318 XWindowAttributes attr;
319 Win win;
320
321 if (!ECompMgrIsActive())
322 return NULL;
323
324 eo = EobjListStackFind(xwin);
325 if (eo)
326 {
327 if (eo->external)
328 goto done;
329 else
330 return eo;
331 }
332
333 if (!pxwa)
334 {
335 pxwa = &attr;
336 if (!EXGetWindowAttributes(xwin, &attr))
337 return NULL;
338 }
339 if (!pxwa->override_redirect)
340 return NULL;
341 #ifndef __cplusplus
342 #define c_class class
343 #endif
344 if (pxwa->c_class != InputOutput)
345 return NULL;
346
347 win = ERegisterWindow(xwin, pxwa);
348 if (!win)
349 return NULL;
350
351 eo = ECALLOC(EObj, 1);
352 if (!eo)
353 return eo;
354
355 eo->external = 1;
356 eo->fade = 1;
357 eo->shadow = 1;
358
359 EobjInit(eo, EOBJ_TYPE_EXT, win, pxwa->x, pxwa->y, pxwa->width, pxwa->height,
360 0, NULL);
361
362 eo->shaped = 0; /* FIXME - Assume unshaped for now */
363 if (win->argb)
364 eo->shadow = 0;
365 EobjSetFloating(eo, 1);
366 EobjSetLayer(eo, 4);
367
368 done:
369 if (mapped)
370 {
371 eo->shown = 1;
372 EobjListStackRaise(eo, 0);
373 ECompMgrWinMap(eo);
374 }
375
376 #if 0
377 Eprintf("%s: %#x depth=%d argb=%d %s\n", __func__,
378 EobjGetXwin(eo), win->depth, win->argb, EobjGetName(eo));
379 #endif
380
381 #endif /* USE_COMPOSITE */
382
383 return eo;
384 }
385
386 void
EobjUnregister(EObj * eo)387 EobjUnregister(EObj * eo)
388 {
389 #if 0
390 Eprintf("%s: %#x type=%d: %s\n", __func__, EobjGetXwin(eo), eo->type,
391 EobjGetName(eo));
392 #endif
393 EobjDestroy(eo);
394 }
395
396 void
EobjMap(EObj * eo,int raise)397 EobjMap(EObj * eo, int raise)
398 {
399 if (eo->shown)
400 return;
401 eo->shown = 1;
402
403 if (raise)
404 EobjListStackRaise(eo, 0);
405
406 if (eo->stacked <= 0 || raise > 1)
407 DeskRestack(eo->desk);
408
409 if (eo->shaped < 0)
410 EobjShapeUpdate(eo, 0);
411
412 EMapWindow(EobjGetWin(eo));
413 #if USE_COMPOSITE
414 ECompMgrWinMap(eo);
415 #endif
416 }
417
418 void
EobjUnmap(EObj * eo)419 EobjUnmap(EObj * eo)
420 {
421 if (!eo->shown)
422 return;
423
424 #if USE_COMPOSITE
425 if (eo->cmhook)
426 ECompMgrWinUnmap(eo);
427 #endif
428 EUnmapWindow(EobjGetWin(eo));
429 eo->shown = 0;
430 }
431
432 void
EobjMoveResize(EObj * eo,int x,int y,int w,int h)433 EobjMoveResize(EObj * eo, int x, int y, int w, int h)
434 {
435 #if USE_COMPOSITE
436 int move, resize;
437
438 move = x != EobjGetX(eo) || y != EobjGetY(eo);
439 resize = w != EobjGetW(eo) || h != EobjGetH(eo);
440 #endif
441
442 EMoveResizeWindow(EobjGetWin(eo), x, y, w, h);
443
444 #if USE_COMPOSITE
445 if (eo->cmhook)
446 ECompMgrWinMoveResize(eo, move, resize, 0);
447 #endif
448 }
449
450 void
EobjMove(EObj * eo,int x,int y)451 EobjMove(EObj * eo, int x, int y)
452 {
453 EobjMoveResize(eo, x, y, EobjGetW(eo), EobjGetH(eo));
454 }
455
456 void
EobjResize(EObj * eo,int w,int h)457 EobjResize(EObj * eo, int w, int h)
458 {
459 EobjMoveResize(eo, EobjGetX(eo), EobjGetY(eo), w, h);
460 }
461
462 #if USE_COMPOSITE
463 void
EobjDamage(EObj * eo)464 EobjDamage(EObj * eo)
465 {
466 if (eo->cmhook)
467 ECompMgrWinDamageArea(eo, 0, 0, 0, 0);
468 }
469 #else
470 void
EobjDamage(EObj * eo __UNUSED__)471 EobjDamage(EObj * eo __UNUSED__)
472 {
473 }
474 #endif
475
476 void
EobjReparent(EObj * eo,EObj * dst,int x,int y)477 EobjReparent(EObj * eo, EObj * dst, int x, int y)
478 {
479 #if USE_COMPOSITE
480 int move;
481
482 move = x != EobjGetX(eo) || y != EobjGetY(eo);
483 #endif
484
485 EReparentWindow(EobjGetWin(eo), EobjGetWin(dst), x, y);
486 if (dst->type == EOBJ_TYPE_DESK)
487 {
488 Desk *dsk = (Desk *) dst;
489
490 if (eo->stacked < 0)
491 {
492 eo->desk = NULL;
493 eo->stacked = 0;
494 }
495 if (eo->desk != dsk)
496 DeskSetDirtyStack(dsk, eo);
497 #if USE_COMPOSITE
498 if (eo->cmhook)
499 ECompMgrWinReparent(eo, dsk, move);
500 #endif
501 eo->desk = dsk;
502 }
503 else
504 {
505 EobjListStackDel(eo);
506 #if USE_COMPOSITE
507 if (eo->cmhook)
508 ECompMgrWinDel(eo);
509 #endif
510 }
511 }
512
513 int
EobjRaise(EObj * eo)514 EobjRaise(EObj * eo)
515 {
516 #if USE_COMPOSITE
517 int num;
518
519 num = EobjListStackRaise(eo, 1);
520 if (num == 0)
521 return num;
522
523 if (num < 0)
524 num = EobjListStackRaise(eo, 0);
525 if (eo->shown && eo->cmhook)
526 ECompMgrWinRaiseLower(eo, num);
527 if (num > 0)
528 num = EobjListStackRaise(eo, 0);
529
530 return num;
531 #else
532 return EobjListStackRaise(eo, 0);
533 #endif
534 }
535
536 int
EobjLower(EObj * eo)537 EobjLower(EObj * eo)
538 {
539 #if USE_COMPOSITE
540 int num;
541
542 num = EobjListStackLower(eo, 1);
543 if (num == 0)
544 return num;
545
546 if (num < 0)
547 num = EobjListStackLower(eo, 0);
548 if (eo->shown && eo->cmhook)
549 ECompMgrWinRaiseLower(eo, num);
550 if (num > 0)
551 num = EobjListStackLower(eo, 0);
552
553 return num;
554 #else
555 return EobjListStackLower(eo, 0);
556 #endif
557 }
558
559 void
EobjShapeUpdate(EObj * eo,int propagate)560 EobjShapeUpdate(EObj * eo, int propagate)
561 {
562 #if USE_COMPOSITE
563 int was_shaped = eo->shaped;
564 #endif
565
566 if (propagate)
567 eo->shaped = EShapePropagate(EobjGetWin(eo)) != 0;
568 else
569 eo->shaped = EShapeCheck(EobjGetWin(eo)) != 0;
570
571 #if USE_COMPOSITE
572 if (was_shaped <= 0 && eo->shaped <= 0)
573 return;
574
575 /* Shape may still be unchanged. Well ... */
576 if (eo->shown && eo->cmhook)
577 ECompMgrWinChangeShape(eo);
578 #endif
579 }
580
581 #if USE_COMPOSITE
582 EX_Pixmap
EobjGetPixmap(const EObj * eo)583 EobjGetPixmap(const EObj * eo)
584 {
585 return ECompMgrWinGetPixmap(eo);
586 }
587 #else
588 EX_Pixmap
EobjGetPixmap(const EObj * eo __UNUSED__)589 EobjGetPixmap(const EObj * eo __UNUSED__)
590 {
591 return NoXID;
592 }
593 #endif
594
595 #if USE_COMPOSITE
596 /* Update now */
597 void
EobjChangeOpacityNow(EObj * eo,unsigned int opacity)598 EobjChangeOpacityNow(EObj * eo, unsigned int opacity)
599 {
600 if (eo->opacity == opacity)
601 return;
602 eo->opacity = opacity;
603 ECompMgrWinSetOpacity(eo, opacity);
604 }
605
606 /* Change through fade, if enabled */
607 void
EobjChangeOpacity(EObj * eo,unsigned int opacity)608 EobjChangeOpacity(EObj * eo, unsigned int opacity)
609 {
610 if (eo->opacity == opacity)
611 return;
612 eo->opacity = opacity;
613 ECompMgrWinChangeOpacity(eo, opacity);
614 }
615
616 void
EobjChangeShadow(EObj * eo,int shadow)617 EobjChangeShadow(EObj * eo, int shadow)
618 {
619 ECompMgrWinChangeShadow(eo, shadow);
620 }
621 #else
622 void
EobjChangeOpacityNow(EObj * eo __UNUSED__,unsigned int opacity __UNUSED__)623 EobjChangeOpacityNow(EObj * eo __UNUSED__, unsigned int opacity __UNUSED__)
624 {
625 }
626
627 void
EobjChangeOpacity(EObj * eo __UNUSED__,unsigned int opacity __UNUSED__)628 EobjChangeOpacity(EObj * eo __UNUSED__, unsigned int opacity __UNUSED__)
629 {
630 }
631
632 void
EobjChangeShadow(EObj * eo __UNUSED__,int shadow __UNUSED__)633 EobjChangeShadow(EObj * eo __UNUSED__, int shadow __UNUSED__)
634 {
635 }
636 #endif
637
638 void
EobjsRepaint(void)639 EobjsRepaint(void)
640 {
641 #if USE_COMPOSITE
642 if (ECompMgrIsActive())
643 ECompMgrRepaint();
644 else
645 #endif
646 ESync(0);
647 }
648
649 #if USE_COMPOSITE
650 void
EobjsOpacityUpdate(int op_or)651 EobjsOpacityUpdate(int op_or)
652 {
653 EObj *eo, *const *lst;
654 int i, num;
655
656 lst = EobjListStackGet(&num);
657 for (i = 0; i < num; i++)
658 {
659 eo = lst[i];
660 switch (eo->type)
661 {
662 default:
663 break;
664 case EOBJ_TYPE_EWIN:
665 EwinUpdateOpacity((EWin *) eo);
666 break;
667 case EOBJ_TYPE_EXT:
668 EobjChangeOpacity(eo, OpacityFromPercent(op_or));
669 break;
670 }
671 }
672 }
673 #endif
674