1 /*
2 * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3 * Copyright (C) 2004-2021 Kim Woelders
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies of the Software, its documentation and marketing & publicity
14 * materials, and acknowledgment shall be given in the documentation, materials
15 * and software packages that this Software was used.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24 #include "config.h"
25
26 #include <X11/Xlib.h>
27 #include <X11/Xutil.h>
28 #if USE_XSYNC
29 #include <X11/extensions/sync.h>
30 #endif
31
32 #include "E.h"
33 #include "desktops.h"
34 #include "ewins.h"
35 #include "hints.h"
36 #include "session.h"
37 #include "xprop.h"
38 #include "xwin.h"
39
40 static void ICCCM_SetIconSizes(void);
41
42 void
ICCCM_Init(void)43 ICCCM_Init(void)
44 {
45 ex_icccm_init();
46
47 Mode.current_cmap = WinGetCmap(VROOT);
48
49 ICCCM_SetIconSizes();
50
51 if (Mode.wm.window)
52 {
53 EX_Atom wm_props[1];
54
55 wm_props[0] = ea_i.WM_DELETE_WINDOW;
56 ex_window_prop_atom_set(WinGetXwin(VROOT), ea_i.WM_PROTOCOLS,
57 wm_props, 1);
58 }
59 }
60
61 int
ICCCM_ProcessClientClientMessage(EWin * ewin,XClientMessageEvent * event)62 ICCCM_ProcessClientClientMessage(EWin * ewin, XClientMessageEvent * event)
63 {
64 if (event->message_type == ea_i.WM_CHANGE_STATE)
65 {
66 if (event->data.l[0] == IconicState)
67 {
68 EwinIconify(ewin);
69 }
70 return 1;
71 }
72
73 return 0;
74 }
75
76 int
ICCCM_ProcessRootClientMessage(XClientMessageEvent * event)77 ICCCM_ProcessRootClientMessage(XClientMessageEvent * event)
78 {
79 EX_Atom a;
80
81 if (event->message_type == ea_i.WM_PROTOCOLS)
82 {
83 a = event->data.l[0];
84 if (a == ea_i.WM_DELETE_WINDOW)
85 SessionExit(EEXIT_EXIT, NULL);
86 return 1;
87 }
88
89 return 0;
90 }
91
92 void
ICCCM_GetTitle(EWin * ewin)93 ICCCM_GetTitle(EWin * ewin)
94 {
95 EFREE_NULL(EwinGetIcccmName(ewin));
96
97 EwinGetIcccmName(ewin) = ex_icccm_title_get(EwinGetClientXwin(ewin));
98
99 EwinChange(ewin, EWIN_CHANGE_NAME);
100 }
101
102 void
ICCCM_Delete(const EWin * ewin)103 ICCCM_Delete(const EWin * ewin)
104 {
105 if (EwinIsInternal(ewin))
106 {
107 EwinHide((EWin *) ewin);
108 return;
109 }
110
111 if (ewin->icccm.delete_window)
112 ex_icccm_delete_window_send(EwinGetClientXwin(ewin), CurrentTime);
113 else
114 XKillClient(disp, EwinGetClientXwin(ewin));
115 }
116
117 #if 0 /* Deprecated */
118 void
119 ICCCM_Save(const EWin * ewin)
120 {
121 if (EwinIsInternal(ewin))
122 return;
123
124 ex_icccm_send_save_yourself(EwinGetClientXwin(ewin));
125 }
126 #endif
127
128 void
ICCCM_Iconify(const EWin * ewin)129 ICCCM_Iconify(const EWin * ewin)
130 {
131 EUnmapWindow(EwinGetClientWin(ewin));
132 ex_icccm_state_set_iconic(EwinGetClientXwin(ewin));
133 }
134
135 void
ICCCM_DeIconify(const EWin * ewin)136 ICCCM_DeIconify(const EWin * ewin)
137 {
138 EMapWindow(EwinGetClientWin(ewin));
139 ex_icccm_state_set_normal(EwinGetClientXwin(ewin));
140 }
141
142 void
ICCCM_Withdraw(const EWin * ewin)143 ICCCM_Withdraw(const EWin * ewin)
144 {
145 /* We have a choice of deleting the WM_STATE property
146 * or changing the value to Withdrawn. Since twm/fvwm does
147 * it that way, we change it to Withdrawn.
148 */
149 ex_icccm_state_set_withdrawn(EwinGetClientXwin(ewin));
150
151 XRemoveFromSaveSet(disp, EwinGetClientXwin(ewin));
152 }
153
154 void
ICCCM_SizeMatch(const EWin * ewin,int wi,int hi,int * pwo,int * pho)155 ICCCM_SizeMatch(const EWin * ewin, int wi, int hi, int *pwo, int *pho)
156 {
157 int w, h;
158 int i, j;
159 float aspect, dw, dh;
160
161 w = wi;
162 h = hi;
163
164 if (w < ewin->icccm.width_min)
165 w = ewin->icccm.width_min;
166 if (w > ewin->icccm.width_max)
167 w = ewin->icccm.width_max;
168 if (h < ewin->icccm.height_min)
169 h = ewin->icccm.height_min;
170 if (h > ewin->icccm.height_max)
171 h = ewin->icccm.height_max;
172
173 if (w <= 0 || h <= 0)
174 return;
175
176 w -= ewin->icccm.base_w;
177 h -= ewin->icccm.base_h;
178 if ((w > 0) && (h > 0))
179 {
180 /* Ignore aspect ratio constraints when fullscreening */
181 if (!ewin->state.fullscreen)
182 {
183 aspect = ((float)w) / ((float)h);
184 dw = ewin->icccm.w_inc / 4.f;
185 dh = ewin->icccm.h_inc / 4.f;
186 if (Mode.mode == MODE_RESIZE_H)
187 {
188 if (aspect < ewin->icccm.aspect_min)
189 h = (int)((float)w / ewin->icccm.aspect_min + dh);
190 else if (aspect > ewin->icccm.aspect_max)
191 h = (int)((float)w / ewin->icccm.aspect_max + dh);
192 }
193 else if (Mode.mode == MODE_RESIZE_V)
194 {
195 if (aspect < ewin->icccm.aspect_min)
196 w = (int)((float)h * ewin->icccm.aspect_min + dw);
197 else if (aspect > ewin->icccm.aspect_max)
198 w = (int)((float)h * ewin->icccm.aspect_max + dw);
199 }
200 else
201 {
202 if (aspect < ewin->icccm.aspect_min)
203 {
204 if (ewin->icccm.aspect_min >= 1.f)
205 h = (int)((float)w / ewin->icccm.aspect_min + dh);
206 else
207 w = (int)((float)h * ewin->icccm.aspect_min + dw);
208 }
209 else if (aspect > ewin->icccm.aspect_max)
210 {
211 if (ewin->icccm.aspect_max >= 1.f)
212 h = (int)((float)w / ewin->icccm.aspect_max + dh);
213 else
214 w = (int)((float)h * ewin->icccm.aspect_max + dw);
215 }
216 }
217 }
218 i = w / ewin->icccm.w_inc;
219 j = h / ewin->icccm.h_inc;
220 w = i * ewin->icccm.w_inc;
221 h = j * ewin->icccm.h_inc;
222 }
223 w += ewin->icccm.base_w;
224 h += ewin->icccm.base_h;
225
226 *pwo = w;
227 *pho = h;
228 }
229
230 #if 0 /* Unused */
231 void
232 ICCCM_MatchSize(EWin * ewin)
233 {
234 ICCCM_SizeMatch(ewin, ewin->client.w, ewin->client.h, &ewin->client.w,
235 &ewin->client.h);
236 }
237 #endif
238
239 void
ICCCM_GetIncrementalSize(EWin * ewin,unsigned int w,unsigned int h,unsigned int * wi,unsigned int * hi)240 ICCCM_GetIncrementalSize(EWin * ewin, unsigned int w, unsigned int h,
241 unsigned int *wi, unsigned int *hi)
242 {
243 *wi = (w - ewin->icccm.base_w) / ewin->icccm.w_inc;
244 *hi = (h - ewin->icccm.base_h) / ewin->icccm.h_inc;
245 }
246
247 void
ICCCM_SetSizeConstraints(EWin * ewin,unsigned int wmin,unsigned int hmin,unsigned int wmax,unsigned int hmax,unsigned int wbase,unsigned int hbase,unsigned int winc,unsigned int hinc,float amin,float amax)248 ICCCM_SetSizeConstraints(EWin * ewin, unsigned int wmin, unsigned int hmin,
249 unsigned int wmax, unsigned int hmax,
250 unsigned int wbase, unsigned int hbase,
251 unsigned int winc, unsigned int hinc,
252 float amin, float amax)
253 {
254 ewin->icccm.width_min = wmin;
255 ewin->icccm.height_min = hmin;
256 ewin->icccm.width_max = wmax;
257 ewin->icccm.height_max = hmax;
258
259 ewin->icccm.base_w = wbase;
260 ewin->icccm.base_h = hbase;
261 ewin->icccm.w_inc = winc;
262 ewin->icccm.h_inc = hinc;
263
264 ewin->icccm.aspect_min = amin;
265 ewin->icccm.aspect_max = amax;
266
267 ewin->props.no_resize_h = (wmin == wmax);
268 ewin->props.no_resize_v = (hmin == hmax);
269 }
270
271 void
ICCCM_Configure(EWin * ewin)272 ICCCM_Configure(EWin * ewin)
273 {
274 XEvent ev;
275
276 if (EwinIsInternal(ewin))
277 return;
278
279 ev.type = ConfigureNotify;
280 ev.xconfigure.display = disp;
281 ev.xconfigure.event = EwinGetClientXwin(ewin);
282 ev.xconfigure.window = EwinGetClientXwin(ewin);
283 #if 0 /* FIXME - Remove? */
284 Desk *dsk;
285
286 dsk = EoGetDesk(ewin);
287 ev.xconfigure.x = EoGetX(dsk) + ewin->client.x;
288 ev.xconfigure.y = EoGetY(dsk) + ewin->client.y;
289 #else
290 ev.xconfigure.x = ewin->client.x;
291 ev.xconfigure.y = ewin->client.y;
292 #endif
293 if (Mode.wm.window)
294 {
295 ev.xconfigure.x += Mode.wm.win_x;
296 ev.xconfigure.y += Mode.wm.win_y;
297 }
298 ev.xconfigure.width = ewin->client.w;
299 ev.xconfigure.height = ewin->client.h;
300 ev.xconfigure.border_width = 0;
301 ev.xconfigure.above = EoGetXwin(ewin);
302 ev.xconfigure.override_redirect = False;
303 EXSendEvent(EwinGetClientXwin(ewin), StructureNotifyMask, &ev);
304 }
305
306 void
ICCCM_AdoptStart(const EWin * ewin)307 ICCCM_AdoptStart(const EWin * ewin)
308 {
309 EX_Window win = EwinGetClientXwin(ewin);
310
311 if (!EwinIsInternal(ewin))
312 XAddToSaveSet(disp, win);
313 }
314
315 void
ICCCM_Adopt(const EWin * ewin)316 ICCCM_Adopt(const EWin * ewin)
317 {
318 EX_Window win = EwinGetClientXwin(ewin);
319
320 if (ewin->icccm.start_iconified)
321 ex_icccm_state_set_iconic(win);
322 else
323 ex_icccm_state_set_normal(win);
324 }
325
326 void
ICCCM_Cmap(EWin * ewin)327 ICCCM_Cmap(EWin * ewin)
328 {
329 EX_Colormap ecmap, dcmap, ccmap;
330 XWindowAttributes xwa;
331 int i, num;
332 EX_Window *wlist;
333
334 ecmap = Mode.current_cmap;
335 dcmap = WinGetCmap(VROOT);
336
337 if (!ewin)
338 {
339 if (ecmap == dcmap)
340 return;
341 ccmap = dcmap;
342 goto set_cmap;
343 }
344
345 ccmap = EwinGetClientWin(ewin)->cmap;
346
347 if (ccmap == ecmap || EoGetWin(ewin)->argb)
348 return;
349
350 /* Hack - assume that if client cmap is default cmap it doesn't have
351 * WM_COLORMAP_WINDOWS */
352 if (ccmap == dcmap)
353 goto set_cmap;
354
355 num = ex_window_prop_window_list_get(EwinGetClientXwin(ewin),
356 ea_i.WM_COLORMAP_WINDOWS, &wlist);
357 if (num > 0)
358 {
359 for (i = 0; i < num; i++)
360 {
361 if (EXGetWindowAttributes(wlist[i], &xwa))
362 {
363 if (xwa.colormap != dcmap)
364 {
365 XInstallColormap(disp, xwa.colormap);
366 Mode.current_cmap = xwa.colormap;
367 }
368 }
369 }
370 Efree(wlist);
371 return;
372 }
373
374 set_cmap:
375 if (EDebug(EDBUG_TYPE_FOCUS))
376 Eprintf("%s: %#x\n", __func__, ccmap);
377 XInstallColormap(disp, ccmap);
378 Mode.current_cmap = ccmap;
379 }
380
381 void
ICCCM_Focus(const EWin * ewin)382 ICCCM_Focus(const EWin * ewin)
383 {
384 if (EDebug(EDBUG_TYPE_FOCUS))
385 {
386 if (ewin)
387 Eprintf("%s: T=%#x R=%#x %#x %s\n", __func__, Mode.events.time,
388 (int)NextRequest(disp), EwinGetClientXwin(ewin),
389 EwinGetTitle(ewin));
390 else
391 Eprintf("%s: T=%#x R=%#x None\n", __func__, Mode.events.time,
392 (int)NextRequest(disp));
393 }
394
395 if (!ewin)
396 {
397 XSetInputFocus(disp, WinGetXwin(VROOT), RevertToPointerRoot,
398 Mode.events.time);
399 HintsSetActiveWindow(NoXID);
400 return;
401 }
402
403 if (ewin->icccm.take_focus)
404 {
405 ex_icccm_take_focus_send(EwinGetClientXwin(ewin), Mode.events.time);
406 }
407
408 if (ewin->icccm.need_input)
409 XSetInputFocus(disp, EwinGetClientXwin(ewin),
410 RevertToPointerRoot, Mode.events.time);
411
412 HintsSetActiveWindow(EwinGetClientXwin(ewin));
413 }
414
415 void
ICCCM_GetGeoms(EWin * ewin)416 ICCCM_GetGeoms(EWin * ewin)
417 {
418 XSizeHints hint;
419 long mask;
420
421 if (XGetWMNormalHints(disp, EwinGetClientXwin(ewin), &hint, &mask))
422 {
423 if (!(ewin->state.placed))
424 {
425 if ((hint.flags & USPosition) || ((hint.flags & PPosition)))
426 {
427 if ((hint.flags & PPosition) && (!EoIsSticky(ewin)))
428 {
429 Desk *dsk;
430
431 dsk = EoGetDesk(ewin);
432 if (!dsk)
433 dsk = DesksGetCurrent();
434 ewin->client.x -= EoGetX(dsk);
435 ewin->client.y -= EoGetY(dsk);
436 if (ewin->client.x + ewin->client.w >= WinGetW(VROOT))
437 {
438 ewin->client.x += EoGetX(dsk);
439 }
440 else if (ewin->client.x < 0)
441 {
442 ewin->client.x += EoGetX(dsk);
443 }
444 if (ewin->client.y + ewin->client.h >= WinGetH(VROOT))
445 {
446 ewin->client.y += EoGetY(dsk);
447 }
448 else if (ewin->client.y < 0)
449 {
450 ewin->client.y += EoGetY(dsk);
451 }
452 }
453 ewin->state.placed = 1;
454 }
455 }
456
457 if (hint.flags & PMinSize)
458 {
459 ewin->icccm.width_min = MAX(0, hint.min_width);
460 ewin->icccm.height_min = MAX(0, hint.min_height);
461 }
462 else
463 {
464 ewin->icccm.width_min = 0;
465 ewin->icccm.height_min = 0;
466 }
467
468 if (hint.flags & PMaxSize)
469 {
470 ewin->icccm.width_max = MIN(hint.max_width, 65535);
471 ewin->icccm.height_max = MIN(hint.max_height, 65535);
472 }
473 else
474 {
475 ewin->icccm.width_max = 65535;
476 ewin->icccm.height_max = 65535;
477 }
478
479 if (hint.flags & PResizeInc)
480 {
481 ewin->icccm.w_inc = MAX(1, hint.width_inc);
482 ewin->icccm.h_inc = MAX(1, hint.height_inc);
483 }
484 else
485 {
486 ewin->icccm.w_inc = 1;
487 ewin->icccm.h_inc = 1;
488 }
489
490 if (hint.flags & PAspect)
491 {
492 if (hint.min_aspect.y > 0 && hint.min_aspect.x > 0)
493 {
494 ewin->icccm.aspect_min =
495 ((float)hint.min_aspect.x) / ((float)hint.min_aspect.y);
496 }
497 else
498 {
499 ewin->icccm.aspect_min = 0.f;
500 }
501 if (hint.max_aspect.y > 0 && hint.max_aspect.x > 0)
502 {
503 ewin->icccm.aspect_max =
504 ((float)hint.max_aspect.x) / ((float)hint.max_aspect.y);
505 }
506 else
507 {
508 ewin->icccm.aspect_max = 65535.f;
509 }
510 }
511 else
512 {
513 ewin->icccm.aspect_min = 0.f;
514 ewin->icccm.aspect_max = 65535.f;
515 }
516
517 if (hint.flags & PBaseSize)
518 {
519 ewin->icccm.base_w = hint.base_width;
520 ewin->icccm.base_h = hint.base_height;
521 }
522 else
523 {
524 ewin->icccm.base_w = ewin->icccm.width_min;
525 ewin->icccm.base_h = ewin->icccm.height_min;
526 }
527
528 if (ewin->icccm.width_min < ewin->icccm.base_w)
529 ewin->icccm.width_min = ewin->icccm.base_w;
530 if (ewin->icccm.height_min < ewin->icccm.base_h)
531 ewin->icccm.height_min = ewin->icccm.base_h;
532
533 if (ewin->icccm.width_max < ewin->icccm.base_w)
534 ewin->icccm.width_max = ewin->icccm.base_w;
535 if (ewin->icccm.height_max < ewin->icccm.base_h)
536 ewin->icccm.height_max = ewin->icccm.base_h;
537
538 if (hint.flags & PWinGravity)
539 ewin->icccm.grav = hint.win_gravity;
540 else
541 ewin->icccm.grav = NorthWestGravity;
542 }
543
544 ewin->props.no_resize_h = (ewin->icccm.width_min == ewin->icccm.width_max);
545 ewin->props.no_resize_v = (ewin->icccm.height_min == ewin->icccm.height_max);
546
547 if (EDebug(EDBUG_TYPE_SNAPS))
548 Eprintf("Snap get icccm %#x: %4d+%4d %4dx%4d: %s\n",
549 EwinGetClientXwin(ewin), ewin->client.x, ewin->client.y,
550 ewin->client.w, ewin->client.h, EwinGetTitle(ewin));
551 }
552
553 #define TryGroup(e) (((e)->icccm.group != NoXID) && ((e)->icccm.group != EwinGetClientXwin(e)))
554
555 static void
ICCCM_GetWmClass(EWin * ewin)556 ICCCM_GetWmClass(EWin * ewin)
557 {
558 EFREE_NULL(EwinGetIcccmCName(ewin));
559 EFREE_NULL(EwinGetIcccmClass(ewin));
560
561 ex_icccm_name_class_get(EwinGetClientXwin(ewin),
562 &EwinGetIcccmCName(ewin), &EwinGetIcccmClass(ewin));
563 if (!EwinGetIcccmCName(ewin) && TryGroup(ewin))
564 ex_icccm_name_class_get(ewin->icccm.group,
565 &EwinGetIcccmCName(ewin),
566 &EwinGetIcccmClass(ewin));
567 }
568
569 static void
ICCCM_GetWmCommand(EWin * ewin)570 ICCCM_GetWmCommand(EWin * ewin)
571 {
572 int argc;
573 char **argv, s[4096], *ss;
574
575 EFREE_NULL(ewin->icccm.wm_command);
576
577 argc = ex_window_prop_string_list_get(EwinGetClientXwin(ewin),
578 ea_i.WM_COMMAND, &argv);
579 if ((argc < 0) && TryGroup(ewin))
580 argc = ex_window_prop_string_list_get(ewin->icccm.group,
581 ea_i.WM_COMMAND, &argv);
582
583 ss = StrlistEncodeEscaped(s, sizeof(s), argv, argc);
584 ewin->icccm.wm_command = Estrdup(ss);
585 StrlistFree(argv, argc);
586 }
587
588 static void
ICCCM_GetWmClientMachine(EWin * ewin)589 ICCCM_GetWmClientMachine(EWin * ewin)
590 {
591 EFREE_NULL(ewin->icccm.wm_machine);
592
593 ewin->icccm.wm_machine =
594 ex_window_prop_string_get(EwinGetClientXwin(ewin),
595 ea_i.WM_CLIENT_MACHINE);
596 if (!ewin->icccm.wm_machine && TryGroup(ewin))
597 ewin->icccm.wm_machine =
598 ex_window_prop_string_get(ewin->icccm.group, ea_i.WM_CLIENT_MACHINE);
599 }
600
601 static void
ICCCM_GetWmIconName(EWin * ewin)602 ICCCM_GetWmIconName(EWin * ewin)
603 {
604 EFREE_NULL(ewin->icccm.wm_icon_name);
605
606 ewin->icccm.wm_icon_name =
607 ex_window_prop_string_get(EwinGetClientXwin(ewin), ea_i.WM_ICON_NAME);
608 if (!ewin->icccm.wm_icon_name && TryGroup(ewin))
609 ewin->icccm.wm_icon_name =
610 ex_window_prop_string_get(ewin->icccm.group, ea_i.WM_ICON_NAME);
611 }
612
613 static void
ICCCM_GetWmWindowRole(EWin * ewin)614 ICCCM_GetWmWindowRole(EWin * ewin)
615 {
616 EFREE_NULL(ewin->icccm.wm_role);
617 ewin->icccm.wm_role =
618 ex_window_prop_string_get(EwinGetClientXwin(ewin), ea_i.WM_WINDOW_ROLE);
619 }
620
621 void
ICCCM_GetInfo(EWin * ewin)622 ICCCM_GetInfo(EWin * ewin)
623 {
624 ICCCM_GetWmClass(ewin);
625 ICCCM_GetWmCommand(ewin);
626 ICCCM_GetWmClientMachine(ewin);
627 ICCCM_GetWmIconName(ewin);
628 ICCCM_GetWmWindowRole(ewin);
629 }
630
631 static void
ICCCM_GetWmHints(EWin * ewin)632 ICCCM_GetWmHints(EWin * ewin)
633 {
634 XWMHints *hint;
635
636 hint = XGetWMHints(disp, EwinGetClientXwin(ewin));
637 if (!hint)
638 return;
639
640 /* I have to make sure the thing i'm docking is a dock app */
641 if ((hint->flags & StateHint) && (hint->initial_state == WithdrawnState))
642 {
643 if (hint->flags & (StateHint | IconWindowHint | IconPositionHint |
644 WindowGroupHint))
645 {
646 if ((hint->icon_x == 0) && (hint->icon_y == 0)
647 && hint->window_group == EwinGetClientXwin(ewin))
648 ewin->state.docked = 1;
649 }
650 }
651
652 ewin->icccm.need_input =
653 ((hint->flags & InputHint) && (!hint->input)) ? 0 : 1;
654
655 ewin->icccm.start_iconified =
656 ((hint->flags & StateHint) &&
657 (hint->initial_state == IconicState)) ? 1 : 0;
658
659 if (hint->flags & IconPixmapHint)
660 {
661 if (ewin->icccm.icon_pmap != hint->icon_pixmap)
662 {
663 ewin->icccm.icon_pmap = hint->icon_pixmap;
664 EwinChange(ewin, EWIN_CHANGE_ICON_PMAP);
665 }
666 }
667 else
668 {
669 ewin->icccm.icon_pmap = NoXID;
670 }
671
672 ewin->icccm.icon_mask =
673 (hint->flags & IconMaskHint) ? hint->icon_mask : NoXID;
674
675 ewin->icccm.icon_win =
676 (hint->flags & IconWindowHint) ? hint->icon_window : NoXID;
677
678 ewin->icccm.group =
679 (hint->flags & WindowGroupHint) ? hint->window_group : NoXID;
680
681 if (hint->flags & XUrgencyHint)
682 {
683 if (!ewin->state.attention)
684 EwinChange(ewin, EWIN_CHANGE_ATTENTION);
685 ewin->icccm.urgency = 1;
686 ewin->state.attention = 1;
687 }
688 else
689 {
690 ewin->icccm.urgency = 0;
691 }
692
693 if (ewin->icccm.group == EwinGetClientXwin(ewin))
694 {
695 ewin->icccm.is_group_leader = 1;
696 }
697 else
698 {
699 ewin->icccm.is_group_leader = 0;
700 }
701
702 XFree(hint);
703 }
704
705 static void
ICCCM_GetWmProtocols(EWin * ewin)706 ICCCM_GetWmProtocols(EWin * ewin)
707 {
708 EX_Atom prop[64]; /* More is unlikely */
709 int i, num;
710
711 num = ex_window_prop_atom_get(EwinGetClientXwin(ewin), ea_i.WM_PROTOCOLS,
712 prop, 64);
713 if (num < 0)
714 return;
715
716 ewin->icccm.take_focus = 0;
717 ewin->icccm.delete_window = 0;
718 for (i = 0; i < num; i++)
719 {
720 if (prop[i] == ea_i.WM_TAKE_FOCUS)
721 ewin->icccm.take_focus = 1;
722 else if (prop[i] == ea_i.WM_DELETE_WINDOW)
723 ewin->icccm.delete_window = 1;
724 #if USE_XSYNC
725 else if (prop[i] == ea_n._NET_WM_SYNC_REQUEST)
726 {
727 unsigned int c;
728
729 ewin->ewmh.sync_request_enable = 1;
730 ex_window_prop_card32_get(EwinGetClientXwin(ewin),
731 ea_n._NET_WM_SYNC_REQUEST_COUNTER,
732 &c, 1);
733 ewin->ewmh.sync_request_counter = c;
734 }
735 #endif
736 }
737 }
738
739 static void
ICCCM_GetWmTransientFor(EWin * ewin)740 ICCCM_GetWmTransientFor(EWin * ewin)
741 {
742 int num;
743 EX_Window win;
744
745 num = ex_window_prop_window_get(EwinGetClientXwin(ewin),
746 ea_i.WM_TRANSIENT_FOR, &win, 1);
747 if (num > 0)
748 {
749 ewin->icccm.transient = 1;
750 ewin->icccm.transient_for = win;
751 }
752 else
753 {
754 ewin->icccm.transient = 0;
755 ewin->icccm.transient_for = NoXID;
756 }
757 }
758
759 static void
ICCCM_GetWmClientLeader(EWin * ewin)760 ICCCM_GetWmClientLeader(EWin * ewin)
761 {
762 int num;
763 EX_Window cleader;
764
765 num = ex_window_prop_window_get(EwinGetClientXwin(ewin),
766 ea_i.WM_CLIENT_LEADER, &cleader, 1);
767 if (num > 0)
768 {
769 ewin->icccm.client_leader = cleader;
770 if (!ewin->icccm.group)
771 ewin->icccm.group = cleader;
772 }
773 }
774
775 void
ICCCM_GetHints(EWin * ewin)776 ICCCM_GetHints(EWin * ewin)
777 {
778 ICCCM_GetWmHints(ewin);
779 ICCCM_GetWmProtocols(ewin);
780 ICCCM_GetWmTransientFor(ewin);
781 ICCCM_GetWmClientLeader(ewin);
782 }
783
784 static void
ICCCM_SetIconSizes(void)785 ICCCM_SetIconSizes(void)
786 {
787 XIconSize *is;
788
789 is = XAllocIconSize();
790 is->min_width = 8;
791 is->min_height = 8;
792 is->max_width = 48;
793 is->max_height = 48;
794 is->width_inc = 1;
795 is->height_inc = 1;
796 XSetIconSizes(disp, WinGetXwin(VROOT), is, 1);
797 XFree(is);
798 }
799
800 /*
801 * Process received window property change
802 */
803 int
ICCCM_ProcessPropertyChange(EWin * ewin,EX_Atom atom_change)804 ICCCM_ProcessPropertyChange(EWin * ewin, EX_Atom atom_change)
805 {
806 if (atom_change == ea_i.WM_NAME)
807 {
808 ICCCM_GetTitle(ewin);
809 return 1;
810 }
811
812 /* ICCCM_GetHints */
813 if (atom_change == ea_i.WM_HINTS)
814 {
815 ICCCM_GetWmHints(ewin);
816 return 1;
817 }
818 if (atom_change == ea_i.WM_PROTOCOLS)
819 {
820 ICCCM_GetWmProtocols(ewin);
821 return 1;
822 }
823 if (atom_change == ea_i.WM_TRANSIENT_FOR)
824 {
825 ICCCM_GetWmTransientFor(ewin);
826 return 1;
827 }
828 if (atom_change == ea_i.WM_CLIENT_LEADER)
829 {
830 ICCCM_GetWmClientLeader(ewin);
831 return 1;
832 }
833
834 /* ICCCM_GetInfo */
835 if (atom_change == ea_i.WM_ICON_NAME)
836 {
837 ICCCM_GetWmIconName(ewin);
838 return 1;
839 }
840 #if 1 /* FIXME - Any reason to process these? */
841 if (atom_change == ea_i.WM_CLASS)
842 {
843 ICCCM_GetWmClass(ewin);
844 return 1;
845 }
846 if (atom_change == ea_i.WM_COMMAND)
847 {
848 ICCCM_GetWmCommand(ewin);
849 return 1;
850 }
851 if (atom_change == ea_i.WM_CLIENT_MACHINE)
852 {
853 ICCCM_GetWmClientMachine(ewin);
854 return 1;
855 }
856 if (atom_change == ea_i.WM_WINDOW_ROLE)
857 {
858 ICCCM_GetWmWindowRole(ewin);
859 return 1;
860 }
861 #endif
862
863 if (atom_change == ea_i.WM_COLORMAP_WINDOWS)
864 {
865 ICCCM_Cmap(ewin);
866 return 1;
867 }
868
869 if (atom_change == ea_i.WM_NORMAL_HINTS)
870 {
871 ICCCM_GetGeoms(ewin);
872 return 1;
873 }
874
875 return 0;
876 }
877
878 #if USE_XSYNC
879 int
EwinSyncRequestSend(EWin * ewin)880 EwinSyncRequestSend(EWin * ewin)
881 {
882 long long count;
883
884 if (!ewin->ewmh.sync_request_enable || EServerIsGrabbed())
885 return 0;
886
887 count = ++ewin->ewmh.sync_request_count;
888
889 if (count == 0)
890 ewin->ewmh.sync_request_count = ++count;
891 ex_client_message32_send(EwinGetClientXwin(ewin),
892 ea_i.WM_PROTOCOLS,
893 StructureNotifyMask,
894 ea_n._NET_WM_SYNC_REQUEST,
895 Mode.events.time,
896 (long)(count & 0xffffffff), (long)(count >> 32), 0);
897
898 return 1;
899 }
900
901 void
EwinSyncRequestWait(EWin * ewin)902 EwinSyncRequestWait(EWin * ewin)
903 {
904 XSyncWaitCondition xswc[2];
905 unsigned int tus;
906
907 if (!ewin->ewmh.sync_request_enable || EServerIsGrabbed())
908 return;
909
910 xswc[0].trigger.counter = ewin->ewmh.sync_request_counter;
911 xswc[0].trigger.value_type = XSyncAbsolute;
912 XSyncIntsToValue(&xswc[0].trigger.wait_value,
913 ewin->ewmh.sync_request_count & 0xffffffff,
914 ewin->ewmh.sync_request_count >> 32);
915 xswc[0].trigger.test_type = XSyncPositiveComparison;
916 XSyncIntsToValue(&xswc[0].event_threshold, 0, 0);
917
918 xswc[1].trigger.counter = Mode.display.server_time;
919 xswc[1].trigger.value_type = XSyncRelative;
920 XSyncIntsToValue(&xswc[1].trigger.wait_value, 200, 0); /* 200 ms */
921 xswc[1].trigger.test_type = XSyncPositiveComparison;
922 XSyncIntsToValue(&xswc[1].event_threshold, 0, 0);
923
924 tus = GetTimeUs();
925 XSyncAwait(disp, xswc, 2);
926 if (EDebug(EDBUG_TYPE_SYNC))
927 Eprintf("%s: t=%#lx c=%llx: Delay=%u us\n", __func__,
928 xswc[0].trigger.counter, ewin->ewmh.sync_request_count,
929 GetTimeUs() - tus);
930 }
931 #endif /* USE_XSYNC */
932