1 /*
2 * Various ICCCM related functions.
3 *
4 * This is ALL the code involving anything ICCCM related. for both WM and
5 * client.
6 */
7
8 #ifdef HAVE_CONFIG_H
9 # include <config.h>
10 #endif /* ifdef HAVE_CONFIG_H */
11
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include "Ecore.h"
16 #include "ecore_x_private.h"
17 #include "Ecore_X.h"
18 #include "Ecore_X_Atoms.h"
19
20 EAPI void
ecore_x_icccm_init(void)21 ecore_x_icccm_init(void)
22 {
23 LOGFN;
24 }
25
26 EAPI void
ecore_x_icccm_state_set(Ecore_X_Window win,Ecore_X_Window_State_Hint state)27 ecore_x_icccm_state_set(Ecore_X_Window win,
28 Ecore_X_Window_State_Hint state)
29 {
30 unsigned long c[2];
31
32 LOGFN;
33 if (state == ECORE_X_WINDOW_STATE_HINT_WITHDRAWN)
34 c[0] = WithdrawnState;
35 else if (state == ECORE_X_WINDOW_STATE_HINT_NORMAL)
36 c[0] = NormalState;
37 else if (state == ECORE_X_WINDOW_STATE_HINT_ICONIC)
38 c[0] = IconicState;
39
40 c[1] = None;
41 XChangeProperty(_ecore_x_disp, win, ECORE_X_ATOM_WM_STATE,
42 ECORE_X_ATOM_WM_STATE, 32, PropModeReplace,
43 (unsigned char *)c, 2);
44 if (_ecore_xlib_sync) ecore_x_sync();
45 }
46
47 EAPI Ecore_X_Window_State_Hint
ecore_x_icccm_state_get(Ecore_X_Window win)48 ecore_x_icccm_state_get(Ecore_X_Window win)
49 {
50 unsigned char *prop_ret = NULL;
51 Atom type_ret;
52 unsigned long bytes_after, num_ret;
53 int format_ret;
54 Ecore_X_Window_State_Hint hint;
55
56 LOGFN;
57 hint = ECORE_X_WINDOW_STATE_HINT_NONE;
58 XGetWindowProperty(_ecore_x_disp, win, ECORE_X_ATOM_WM_STATE,
59 0, 0x7fffffff, False, ECORE_X_ATOM_WM_STATE,
60 &type_ret, &format_ret, &num_ret, &bytes_after,
61 &prop_ret);
62 if (_ecore_xlib_sync) ecore_x_sync();
63 if ((prop_ret) && (num_ret == 2))
64 {
65 if (prop_ret[0] == WithdrawnState)
66 hint = ECORE_X_WINDOW_STATE_HINT_WITHDRAWN;
67 else if (prop_ret[0] == NormalState)
68 hint = ECORE_X_WINDOW_STATE_HINT_NORMAL;
69 else if (prop_ret[0] == IconicState)
70 hint = ECORE_X_WINDOW_STATE_HINT_ICONIC;
71 }
72
73 if (prop_ret)
74 XFree(prop_ret);
75
76 return hint;
77 }
78
79 EAPI void
ecore_x_icccm_delete_window_send(Ecore_X_Window win,Ecore_X_Time t)80 ecore_x_icccm_delete_window_send(Ecore_X_Window win,
81 Ecore_X_Time t)
82 {
83 LOGFN;
84 ecore_x_client_message32_send(win, ECORE_X_ATOM_WM_PROTOCOLS,
85 ECORE_X_EVENT_MASK_NONE,
86 ECORE_X_ATOM_WM_DELETE_WINDOW,
87 t, 0, 0, 0);
88 }
89
90 EAPI void
ecore_x_icccm_take_focus_send(Ecore_X_Window win,Ecore_X_Time t)91 ecore_x_icccm_take_focus_send(Ecore_X_Window win,
92 Ecore_X_Time t)
93 {
94 LOGFN;
95 ecore_x_client_message32_send(win, ECORE_X_ATOM_WM_PROTOCOLS,
96 ECORE_X_EVENT_MASK_NONE,
97 ECORE_X_ATOM_WM_TAKE_FOCUS,
98 t, 0, 0, 0);
99 }
100
101 EAPI void
ecore_x_icccm_save_yourself_send(Ecore_X_Window win,Ecore_X_Time t)102 ecore_x_icccm_save_yourself_send(Ecore_X_Window win,
103 Ecore_X_Time t)
104 {
105 LOGFN;
106 ecore_x_client_message32_send(win, ECORE_X_ATOM_WM_PROTOCOLS,
107 ECORE_X_EVENT_MASK_NONE,
108 ECORE_X_ATOM_WM_SAVE_YOURSELF,
109 t, 0, 0, 0);
110 }
111
112 EAPI void
ecore_x_icccm_move_resize_send(Ecore_X_Window win,int x,int y,int w,int h)113 ecore_x_icccm_move_resize_send(Ecore_X_Window win,
114 int x,
115 int y,
116 int w,
117 int h)
118 {
119 XEvent ev;
120
121 LOGFN;
122 ev.type = ConfigureNotify;
123 ev.xconfigure.display = _ecore_x_disp;
124 ev.xconfigure.event = win;
125 ev.xconfigure.window = win;
126 ev.xconfigure.x = x;
127 ev.xconfigure.y = y;
128 ev.xconfigure.width = w;
129 ev.xconfigure.height = h;
130 ev.xconfigure.border_width = 0;
131 ev.xconfigure.above = None;
132 ev.xconfigure.override_redirect = False;
133 XSendEvent(_ecore_x_disp, win, False, StructureNotifyMask, &ev);
134 if (_ecore_xlib_sync) ecore_x_sync();
135 }
136
137 EAPI void
ecore_x_icccm_hints_set(Ecore_X_Window win,Eina_Bool accepts_focus,Ecore_X_Window_State_Hint initial_state,Ecore_X_Pixmap icon_pixmap,Ecore_X_Pixmap icon_mask,Ecore_X_Window icon_window,Ecore_X_Window window_group,Eina_Bool is_urgent)138 ecore_x_icccm_hints_set(Ecore_X_Window win,
139 Eina_Bool accepts_focus,
140 Ecore_X_Window_State_Hint initial_state,
141 Ecore_X_Pixmap icon_pixmap,
142 Ecore_X_Pixmap icon_mask,
143 Ecore_X_Window icon_window,
144 Ecore_X_Window window_group,
145 Eina_Bool is_urgent)
146 {
147 XWMHints *hints;
148
149 hints = XAllocWMHints();
150 if (!hints)
151 return;
152
153 LOGFN;
154 hints->flags = InputHint | StateHint;
155 hints->input = accepts_focus;
156 if (initial_state == ECORE_X_WINDOW_STATE_HINT_WITHDRAWN)
157 hints->initial_state = WithdrawnState;
158 else if (initial_state == ECORE_X_WINDOW_STATE_HINT_NORMAL)
159 hints->initial_state = NormalState;
160 else if (initial_state == ECORE_X_WINDOW_STATE_HINT_ICONIC)
161 hints->initial_state = IconicState;
162
163 if (icon_pixmap != 0)
164 {
165 hints->icon_pixmap = icon_pixmap;
166 hints->flags |= IconPixmapHint;
167 }
168
169 if (icon_mask != 0)
170 {
171 hints->icon_mask = icon_mask;
172 hints->flags |= IconMaskHint;
173 }
174
175 if (icon_window != 0)
176 {
177 hints->icon_window = icon_window;
178 hints->flags |= IconWindowHint;
179 }
180
181 if (window_group != 0)
182 {
183 hints->window_group = window_group;
184 hints->flags |= WindowGroupHint;
185 }
186
187 if (is_urgent)
188 hints->flags |= XUrgencyHint;
189
190 XSetWMHints(_ecore_x_disp, win, hints);
191 if (_ecore_xlib_sync) ecore_x_sync();
192 XFree(hints);
193 }
194
195 EAPI Eina_Bool
ecore_x_icccm_hints_get(Ecore_X_Window win,Eina_Bool * accepts_focus,Ecore_X_Window_State_Hint * initial_state,Ecore_X_Pixmap * icon_pixmap,Ecore_X_Pixmap * icon_mask,Ecore_X_Window * icon_window,Ecore_X_Window * window_group,Eina_Bool * is_urgent)196 ecore_x_icccm_hints_get(Ecore_X_Window win,
197 Eina_Bool *accepts_focus,
198 Ecore_X_Window_State_Hint *initial_state,
199 Ecore_X_Pixmap *icon_pixmap,
200 Ecore_X_Pixmap *icon_mask,
201 Ecore_X_Window *icon_window,
202 Ecore_X_Window *window_group,
203 Eina_Bool *is_urgent)
204 {
205 XWMHints *hints;
206
207 LOGFN;
208 if (accepts_focus)
209 *accepts_focus = EINA_TRUE;
210
211 if (initial_state)
212 *initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL;
213
214 if (icon_pixmap)
215 *icon_pixmap = 0;
216
217 if (icon_mask)
218 *icon_mask = 0;
219
220 if (icon_window)
221 *icon_window = 0;
222
223 if (window_group)
224 *window_group = 0;
225
226 if (is_urgent)
227 *is_urgent = EINA_FALSE;
228
229 hints = XGetWMHints(_ecore_x_disp, win);
230 if (_ecore_xlib_sync) ecore_x_sync();
231 if (hints)
232 {
233 if ((hints->flags & InputHint) && (accepts_focus))
234 {
235 if (hints->input)
236 *accepts_focus = EINA_TRUE;
237 else
238 *accepts_focus = EINA_FALSE;
239 }
240
241 if ((hints->flags & StateHint) && (initial_state))
242 {
243 if (hints->initial_state == WithdrawnState)
244 *initial_state = ECORE_X_WINDOW_STATE_HINT_WITHDRAWN;
245 else if (hints->initial_state == NormalState)
246 *initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL;
247 else if (hints->initial_state == IconicState)
248 *initial_state = ECORE_X_WINDOW_STATE_HINT_ICONIC;
249 }
250
251 if ((hints->flags & IconPixmapHint) && (icon_pixmap))
252 *icon_pixmap = hints->icon_pixmap;
253
254 if ((hints->flags & IconMaskHint) && (icon_mask))
255 *icon_mask = hints->icon_mask;
256
257 if ((hints->flags & IconWindowHint) && (icon_window))
258 *icon_window = hints->icon_window;
259
260 if ((hints->flags & WindowGroupHint) && (window_group))
261 *window_group = hints->window_group;
262
263 if ((hints->flags & XUrgencyHint) && (is_urgent))
264 *is_urgent = EINA_TRUE;
265
266 XFree(hints);
267 return EINA_TRUE;
268 }
269
270 return EINA_FALSE;
271 }
272
273 EAPI void
ecore_x_icccm_size_pos_hints_set(Ecore_X_Window win,Eina_Bool request_pos,Ecore_X_Gravity gravity,int min_w,int min_h,int max_w,int max_h,int base_w,int base_h,int step_x,int step_y,double min_aspect,double max_aspect)274 ecore_x_icccm_size_pos_hints_set(Ecore_X_Window win,
275 Eina_Bool request_pos,
276 Ecore_X_Gravity gravity,
277 int min_w,
278 int min_h,
279 int max_w,
280 int max_h,
281 int base_w,
282 int base_h,
283 int step_x,
284 int step_y,
285 double min_aspect,
286 double max_aspect)
287 {
288 XSizeHints hint;
289 long mask;
290
291 LOGFN;
292 if (!XGetWMNormalHints(_ecore_x_disp, win, &hint, &mask))
293 memset(&hint, 0, sizeof(XSizeHints));
294 if (_ecore_xlib_sync) ecore_x_sync();
295
296 hint.flags = 0;
297 if (request_pos)
298 hint.flags |= USPosition;
299
300 if (gravity != ECORE_X_GRAVITY_NW)
301 {
302 hint.flags |= PWinGravity;
303 hint.win_gravity = gravity;
304 }
305
306 if ((min_w > 0) || (min_h > 0))
307 {
308 hint.flags |= PMinSize;
309 hint.min_width = min_w;
310 hint.min_height = min_h;
311 }
312
313 if ((max_w > 0) || (max_h > 0))
314 {
315 hint.flags |= PMaxSize;
316 hint.max_width = max_w;
317 hint.max_height = max_h;
318 }
319
320 if ((base_w > 0) || (base_h > 0))
321 {
322 hint.flags |= PBaseSize;
323 hint.base_width = base_w;
324 hint.base_height = base_h;
325 }
326
327 if ((step_x > 1) || (step_y > 1))
328 {
329 hint.flags |= PResizeInc;
330 hint.width_inc = step_x;
331 hint.height_inc = step_y;
332 }
333
334 if ((min_aspect > 0.0) || (max_aspect > 0.0))
335 {
336 hint.flags |= PAspect;
337 hint.min_aspect.x = min_aspect * 10000;
338 hint.min_aspect.y = 10000;
339 hint.max_aspect.x = max_aspect * 10000;
340 hint.max_aspect.y = 10000;
341 }
342
343 XSetWMNormalHints(_ecore_x_disp, win, &hint);
344 if (_ecore_xlib_sync) ecore_x_sync();
345 }
346
347 EAPI Eina_Bool
ecore_x_icccm_size_pos_hints_get(Ecore_X_Window win,Eina_Bool * request_pos,Ecore_X_Gravity * gravity,int * min_w,int * min_h,int * max_w,int * max_h,int * base_w,int * base_h,int * step_x,int * step_y,double * min_aspect,double * max_aspect)348 ecore_x_icccm_size_pos_hints_get(Ecore_X_Window win,
349 Eina_Bool *request_pos,
350 Ecore_X_Gravity *gravity,
351 int *min_w,
352 int *min_h,
353 int *max_w,
354 int *max_h,
355 int *base_w,
356 int *base_h,
357 int *step_x,
358 int *step_y,
359 double *min_aspect,
360 double *max_aspect)
361 {
362 XSizeHints hint;
363 long mask;
364
365 int minw = 0, minh = 0;
366 int maxw = 32767, maxh = 32767;
367 int basew = -1, baseh = -1;
368 int stepx = -1, stepy = -1;
369 double mina = 0.0, maxa = 0.0;
370
371 LOGFN;
372 if (!XGetWMNormalHints(_ecore_x_disp, win, &hint, &mask))
373 {
374 if (_ecore_xlib_sync) ecore_x_sync();
375 return EINA_FALSE;
376 }
377
378 if ((hint.flags & USPosition) || ((hint.flags & PPosition)))
379 {
380 if (request_pos)
381 *request_pos = EINA_TRUE;
382 }
383 else if (request_pos)
384 *request_pos = EINA_FALSE;
385
386 if (hint.flags & PWinGravity)
387 {
388 if (gravity)
389 *gravity = hint.win_gravity;
390 }
391 else if (gravity)
392 *gravity = ECORE_X_GRAVITY_NW;
393
394 if (hint.flags & PMinSize)
395 {
396 minw = hint.min_width;
397 minh = hint.min_height;
398 }
399
400 if (hint.flags & PMaxSize)
401 {
402 maxw = hint.max_width;
403 maxh = hint.max_height;
404 if (maxw < minw)
405 maxw = minw;
406
407 if (maxh < minh)
408 maxh = minh;
409 }
410
411 if (hint.flags & PBaseSize)
412 {
413 basew = hint.base_width;
414 baseh = hint.base_height;
415 if (basew > minw)
416 minw = basew;
417
418 if (baseh > minh)
419 minh = baseh;
420 }
421
422 if (hint.flags & PResizeInc)
423 {
424 stepx = hint.width_inc;
425 stepy = hint.height_inc;
426 if (stepx < 1)
427 stepx = 1;
428
429 if (stepy < 1)
430 stepy = 1;
431 }
432
433 if (hint.flags & PAspect)
434 {
435 if (hint.min_aspect.y > 0)
436 mina = ((double)hint.min_aspect.x) / ((double)hint.min_aspect.y);
437
438 if (hint.max_aspect.y > 0)
439 maxa = ((double)hint.max_aspect.x) / ((double)hint.max_aspect.y);
440 }
441
442 if (min_w)
443 *min_w = minw;
444
445 if (min_h)
446 *min_h = minh;
447
448 if (max_w)
449 *max_w = maxw;
450
451 if (max_h)
452 *max_h = maxh;
453
454 if (base_w)
455 *base_w = basew;
456
457 if (base_h)
458 *base_h = baseh;
459
460 if (step_x)
461 *step_x = stepx;
462
463 if (step_y)
464 *step_y = stepy;
465
466 if (min_aspect)
467 *min_aspect = mina;
468
469 if (max_aspect)
470 *max_aspect = maxa;
471
472 return EINA_TRUE;
473 }
474
475 EAPI void
ecore_x_icccm_title_set(Ecore_X_Window win,const char * t)476 ecore_x_icccm_title_set(Ecore_X_Window win,
477 const char *t)
478 {
479 char *list[1];
480 XTextProperty xprop;
481 int ret;
482
483 if (!t)
484 return;
485
486 LOGFN;
487 xprop.value = NULL;
488 #ifdef X_HAVE_UTF8_STRING
489 list[0] = strdup(t);
490 ret =
491 Xutf8TextListToTextProperty(_ecore_x_disp, list, 1, XUTF8StringStyle,
492 &xprop);
493 #else /* ifdef X_HAVE_UTF8_STRING */
494 list[0] = strdup(t);
495 ret =
496 XmbTextListToTextProperty(_ecore_x_disp, list, 1, XStdICCTextStyle,
497 &xprop);
498 #endif /* ifdef X_HAVE_UTF8_STRING */
499 if (_ecore_xlib_sync) ecore_x_sync();
500 if (ret >= Success)
501 {
502 XSetWMName(_ecore_x_disp, win, &xprop);
503 if (_ecore_xlib_sync) ecore_x_sync();
504 if (xprop.value)
505 XFree(xprop.value);
506 }
507 else if (XStringListToTextProperty(list, 1, &xprop) >= Success)
508 {
509 XSetWMName(_ecore_x_disp, win, &xprop);
510 if (_ecore_xlib_sync) ecore_x_sync();
511 if (xprop.value)
512 XFree(xprop.value);
513 }
514
515 free(list[0]);
516 }
517
518 EAPI char *
ecore_x_icccm_title_get(Ecore_X_Window win)519 ecore_x_icccm_title_get(Ecore_X_Window win)
520 {
521 XTextProperty xprop;
522
523 LOGFN;
524 xprop.value = NULL;
525 if (XGetWMName(_ecore_x_disp, win, &xprop) >= Success)
526 {
527 if (_ecore_xlib_sync) ecore_x_sync();
528 if (xprop.value)
529 {
530 char **list = NULL;
531 char *t = NULL;
532 int num = 0;
533 int ret;
534
535 if (xprop.encoding == ECORE_X_ATOM_UTF8_STRING)
536 t = strdup((char *)xprop.value);
537 else
538 {
539 /* convert to utf8 */
540 #ifdef X_HAVE_UTF8_STRING
541 ret = Xutf8TextPropertyToTextList(_ecore_x_disp, &xprop,
542 &list, &num);
543 #else /* ifdef X_HAVE_UTF8_STRING */
544 ret = XmbTextPropertyToTextList(_ecore_x_disp, &xprop,
545 &list, &num);
546 #endif /* ifdef X_HAVE_UTF8_STRING */
547 if (_ecore_xlib_sync) ecore_x_sync();
548
549 if ((ret == XLocaleNotSupported) ||
550 (ret == XNoMemory) || (ret == XConverterNotFound))
551 t = strdup((char *)xprop.value);
552 else if ((ret >= Success) && (num > 0))
553 t = strdup(list[0]);
554
555 if (list)
556 XFreeStringList(list);
557 }
558
559 if (xprop.value)
560 XFree(xprop.value);
561
562 return t;
563 }
564 }
565 else
566 {
567 if (_ecore_xlib_sync) ecore_x_sync();
568 }
569
570 return NULL;
571 }
572
573 /**
574 * Set protocol atoms explicitly
575 * @param win The Window
576 * @param protos An array of protocol atoms
577 * @param num the number of members of the array
578 */
579 EAPI void
ecore_x_icccm_protocol_atoms_set(Ecore_X_Window win,Ecore_X_Atom * protos,int num)580 ecore_x_icccm_protocol_atoms_set(Ecore_X_Window win,
581 Ecore_X_Atom *protos,
582 int num)
583 {
584 Atom *protos2 = alloca(sizeof(Atom) * num);
585 int i;
586
587 for (i = 0; i < num; i++) protos2[i] = protos[i];
588 LOGFN;
589 if (num > 0)
590 XSetWMProtocols(_ecore_x_disp, win, protos2, num);
591 else
592 XDeleteProperty(_ecore_x_disp, win, ECORE_X_ATOM_WM_PROTOCOLS);
593 if (_ecore_xlib_sync) ecore_x_sync();
594 }
595
596 /**
597 * Set or unset a wm protocol property.
598 * @param win The Window
599 * @param protocol The protocol to enable/disable
600 * @param on On/Off
601 */
602 EAPI void
ecore_x_icccm_protocol_set(Ecore_X_Window win,Ecore_X_WM_Protocol protocol,Eina_Bool on)603 ecore_x_icccm_protocol_set(Ecore_X_Window win,
604 Ecore_X_WM_Protocol protocol,
605 Eina_Bool on)
606 {
607 Atom *protos = NULL;
608 Atom proto;
609 int protos_count = 0;
610 int already_set = 0;
611 int i;
612
613 /* Check for invalid values */
614 if (protocol >= ECORE_X_WM_PROTOCOL_NUM)
615 return;
616
617 LOGFN;
618 proto = _ecore_x_atoms_wm_protocols[protocol];
619
620 if (!XGetWMProtocols(_ecore_x_disp, win, &protos, &protos_count))
621 {
622 protos = NULL;
623 protos_count = 0;
624 }
625 if (_ecore_xlib_sync) ecore_x_sync();
626 for (i = 0; i < protos_count; i++)
627 {
628 if (protos[i] == proto)
629 {
630 already_set = 1;
631 break;
632 }
633 }
634
635 if (on)
636 {
637 Atom *new_protos = NULL;
638
639 if (already_set)
640 goto leave;
641
642 new_protos = malloc((protos_count + 1) * sizeof(Atom));
643 if (!new_protos)
644 goto leave;
645
646 for (i = 0; i < protos_count; i++)
647 new_protos[i] = protos[i];
648 new_protos[protos_count] = proto;
649 XSetWMProtocols(_ecore_x_disp, win, new_protos, protos_count + 1);
650 if (_ecore_xlib_sync) ecore_x_sync();
651 free(new_protos);
652 }
653 else
654 {
655 if (!already_set)
656 goto leave;
657
658 for (i = 0; i < protos_count; i++)
659 {
660 if (protos[i] == proto)
661 {
662 int j;
663
664 for (j = i + 1; j < protos_count; j++)
665 protos[j - 1] = protos[j];
666 if (protos_count > 1)
667 XSetWMProtocols(_ecore_x_disp, win, protos,
668 protos_count - 1);
669 else
670 XDeleteProperty(_ecore_x_disp, win,
671 ECORE_X_ATOM_WM_PROTOCOLS);
672 if (_ecore_xlib_sync) ecore_x_sync();
673
674 goto leave;
675 }
676 }
677 }
678
679 leave:
680 if (protos)
681 XFree(protos);
682 }
683
684 /**
685 * Determines whether a protocol is set for a window.
686 * @param win The Window
687 * @param protocol The protocol to query
688 * @return 1 if the protocol is set, else 0.
689 */
690 EAPI Eina_Bool
ecore_x_icccm_protocol_isset(Ecore_X_Window win,Ecore_X_WM_Protocol protocol)691 ecore_x_icccm_protocol_isset(Ecore_X_Window win,
692 Ecore_X_WM_Protocol protocol)
693 {
694 Atom proto, *protos = NULL;
695 int i, protos_count = 0;
696 Eina_Bool ret = EINA_FALSE;
697
698 /* check for invalid values */
699 if (protocol >= ECORE_X_WM_PROTOCOL_NUM)
700 return EINA_FALSE;
701
702 LOGFN;
703 proto = _ecore_x_atoms_wm_protocols[protocol];
704
705 if (!XGetWMProtocols(_ecore_x_disp, win, &protos, &protos_count))
706 return EINA_FALSE;
707 if (_ecore_xlib_sync) ecore_x_sync();
708
709 for (i = 0; i < protos_count; i++)
710 if (protos[i] == proto)
711 {
712 ret = EINA_TRUE;
713 break;
714 }
715
716 if (protos)
717 XFree(protos);
718
719 return ret;
720 }
721
722 /**
723 * Set a window name & class.
724 * @param win The window
725 * @param n The name string
726 * @param c The class string
727 *
728 * Set a window name * class
729 */
730 EAPI void
ecore_x_icccm_name_class_set(Ecore_X_Window win,const char * n,const char * c)731 ecore_x_icccm_name_class_set(Ecore_X_Window win,
732 const char *n,
733 const char *c)
734 {
735 XClassHint *xch;
736
737 xch = XAllocClassHint();
738 if (!xch)
739 return;
740
741 LOGFN;
742 xch->res_name = (char *)n;
743 xch->res_class = (char *)c;
744 XSetClassHint(_ecore_x_disp, win, xch);
745 if (_ecore_xlib_sync) ecore_x_sync();
746 XFree(xch);
747 }
748
749 /**
750 * Get a window name & class.
751 * @param win The window
752 * @param n The name string
753 * @param c The class string
754 *
755 * Get a window name * class
756 */
757 EAPI void
ecore_x_icccm_name_class_get(Ecore_X_Window win,char ** n,char ** c)758 ecore_x_icccm_name_class_get(Ecore_X_Window win,
759 char **n,
760 char **c)
761 {
762 XClassHint xch;
763
764 LOGFN;
765 if (n)
766 *n = NULL;
767
768 if (c)
769 *c = NULL;
770
771 xch.res_name = NULL;
772 xch.res_class = NULL;
773 if (XGetClassHint(_ecore_x_disp, win, &xch))
774 {
775 if (n)
776 if (xch.res_name)
777 *n = strdup(xch.res_name);
778
779 if (c)
780 if (xch.res_class)
781 *c = strdup(xch.res_class);
782
783 XFree(xch.res_name);
784 XFree(xch.res_class);
785 }
786 if (_ecore_xlib_sync) ecore_x_sync();
787 }
788
789 /**
790 * Get a window client machine string.
791 * @param win The window
792 * @return The windows client machine string
793 *
794 * Return the client machine of a window. String must be free'd when done with.
795 */
796 EAPI char *
ecore_x_icccm_client_machine_get(Ecore_X_Window win)797 ecore_x_icccm_client_machine_get(Ecore_X_Window win)
798 {
799 char *name;
800
801 LOGFN;
802 name = ecore_x_window_prop_string_get(win, ECORE_X_ATOM_WM_CLIENT_MACHINE);
803 return name;
804 }
805
806 /**
807 * Sets the WM_COMMAND property for @a win.
808 *
809 * @param win The window.
810 * @param argc Number of arguments.
811 * @param argv Arguments.
812 */
813 EAPI void
ecore_x_icccm_command_set(Ecore_X_Window win,int argc,char ** argv)814 ecore_x_icccm_command_set(Ecore_X_Window win,
815 int argc,
816 char **argv)
817 {
818 LOGFN;
819 XSetCommand(_ecore_x_disp, win, argv, argc);
820 if (_ecore_xlib_sync) ecore_x_sync();
821 }
822
823 /**
824 * Get the WM_COMMAND property for @a win.
825 *
826 * Return the command of a window. String must be free'd when done with.
827 *
828 * @param win The window.
829 * @param argc Number of arguments.
830 * @param argv Arguments.
831 */
832 EAPI void
ecore_x_icccm_command_get(Ecore_X_Window win,int * argc,char *** argv)833 ecore_x_icccm_command_get(Ecore_X_Window win,
834 int *argc,
835 char ***argv)
836 {
837 int i, c;
838 char **v;
839 Eina_Bool success;
840
841 if (argc)
842 *argc = 0;
843
844 if (argv)
845 *argv = NULL;
846
847 LOGFN;
848 success = XGetCommand(_ecore_x_disp, win, &v, &c);
849 if (_ecore_xlib_sync) ecore_x_sync();
850 if (!success) return;
851
852 if (c < 1)
853 {
854 if (v)
855 XFreeStringList(v);
856
857 return;
858 }
859
860 if (argc)
861 *argc = c;
862
863 if (argv)
864 {
865 (*argv) = malloc(c * sizeof(char *));
866 if (!*argv)
867 {
868 XFreeStringList(v);
869 if (argc)
870 *argc = 0;
871
872 return;
873 }
874
875 for (i = 0; i < c; i++)
876 {
877 if (v[i])
878 (*argv)[i] = strdup(v[i]);
879 else
880 (*argv)[i] = strdup("");
881 }
882 }
883
884 XFreeStringList(v);
885 }
886
887 /**
888 * Set a window icon name.
889 * @param win The window
890 * @param t The icon name string
891 *
892 * Set a window icon name
893 */
894 EAPI void
ecore_x_icccm_icon_name_set(Ecore_X_Window win,const char * t)895 ecore_x_icccm_icon_name_set(Ecore_X_Window win,
896 const char *t)
897 {
898 char *list[1];
899 XTextProperty xprop;
900 int ret;
901
902 LOGFN;
903 xprop.value = NULL;
904 #ifdef X_HAVE_UTF8_STRING
905 list[0] = strdup(t);
906 ret = Xutf8TextListToTextProperty(_ecore_x_disp, list, 1,
907 XUTF8StringStyle, &xprop);
908 #else /* ifdef X_HAVE_UTF8_STRING */
909 list[0] = strdup(t);
910 ret = XmbTextListToTextProperty(_ecore_x_disp, list, 1,
911 XStdICCTextStyle, &xprop);
912 #endif /* ifdef X_HAVE_UTF8_STRING */
913 if (_ecore_xlib_sync) ecore_x_sync();
914 if (ret >= Success)
915 {
916 XSetWMIconName(_ecore_x_disp, win, &xprop);
917 if (_ecore_xlib_sync) ecore_x_sync();
918 if (xprop.value)
919 XFree(xprop.value);
920 }
921 else if (XStringListToTextProperty(list, 1, &xprop) >= Success)
922 {
923 XSetWMIconName(_ecore_x_disp, win, &xprop);
924 if (_ecore_xlib_sync) ecore_x_sync();
925 if (xprop.value)
926 XFree(xprop.value);
927 }
928
929 free(list[0]);
930 }
931
932 /**
933 * Get a window icon name.
934 * @param win The window
935 * @return The windows icon name string
936 *
937 * Return the icon name of a window. String must be free'd when done with.
938 */
939 EAPI char *
ecore_x_icccm_icon_name_get(Ecore_X_Window win)940 ecore_x_icccm_icon_name_get(Ecore_X_Window win)
941 {
942 XTextProperty xprop;
943
944 LOGFN;
945 xprop.value = NULL;
946 if (XGetWMIconName(_ecore_x_disp, win, &xprop) >= Success)
947 {
948 if (_ecore_xlib_sync) ecore_x_sync();
949 if (xprop.value)
950 {
951 char **list = NULL;
952 char *t = NULL;
953 int num = 0;
954 int ret;
955
956 if (xprop.encoding == ECORE_X_ATOM_UTF8_STRING)
957 t = strdup((char *)xprop.value);
958 else
959 {
960 /* convert to utf8 */
961 #ifdef X_HAVE_UTF8_STRING
962 ret = Xutf8TextPropertyToTextList(_ecore_x_disp, &xprop,
963 &list, &num);
964 #else /* ifdef X_HAVE_UTF8_STRING */
965 ret = XmbTextPropertyToTextList(_ecore_x_disp, &xprop,
966 &list, &num);
967 #endif /* ifdef X_HAVE_UTF8_STRING */
968 if (_ecore_xlib_sync) ecore_x_sync();
969
970 if ((ret == XLocaleNotSupported) ||
971 (ret == XNoMemory) || (ret == XConverterNotFound))
972 t = strdup((char *)xprop.value);
973 else if (ret >= Success)
974 {
975 if ((num >= 1) && (list))
976 t = strdup(list[0]);
977
978 if (list)
979 XFreeStringList(list);
980 }
981 }
982
983 if (xprop.value)
984 XFree(xprop.value);
985
986 return t;
987 }
988 }
989 else
990 {
991 if (_ecore_xlib_sync) ecore_x_sync();
992 }
993
994 return NULL;
995 }
996
997 /**
998 * Add a subwindow to the list of windows that need a different colormap installed.
999 * @param win The toplevel window
1000 * @param subwin The subwindow to be added to the colormap windows list
1001 */
1002 EAPI void
ecore_x_icccm_colormap_window_set(Ecore_X_Window win,Ecore_X_Window subwin)1003 ecore_x_icccm_colormap_window_set(Ecore_X_Window win,
1004 Ecore_X_Window subwin)
1005 {
1006 int num = 0, i;
1007 unsigned char *old_data = NULL;
1008 unsigned char *data = NULL;
1009 Window *oldset = NULL;
1010 Window *newset = NULL;
1011
1012 LOGFN;
1013 if (!ecore_x_window_prop_property_get(win,
1014 ECORE_X_ATOM_WM_COLORMAP_WINDOWS,
1015 XA_WINDOW, 32, &old_data, &num))
1016 {
1017 newset = calloc(1, sizeof(Window));
1018 if (!newset)
1019 {
1020 if (old_data) free(old_data);
1021 return;
1022 }
1023
1024 newset[0] = subwin;
1025 num = 1;
1026 data = (unsigned char *)newset;
1027 }
1028 else
1029 {
1030 newset = calloc(num + 1, sizeof(Window));
1031 oldset = (Window *)old_data;
1032 if (!newset)
1033 {
1034 if (old_data) free(old_data);
1035 return;
1036 }
1037
1038 for (i = 0; i < num; ++i)
1039 {
1040 if (oldset[i] == subwin)
1041 {
1042 free(old_data);
1043 free(newset);
1044 return;
1045 }
1046
1047 newset[i] = oldset[i];
1048 }
1049
1050 newset[num++] = subwin;
1051 data = (unsigned char *)newset;
1052 }
1053
1054 ecore_x_window_prop_property_set(win,
1055 ECORE_X_ATOM_WM_COLORMAP_WINDOWS,
1056 XA_WINDOW, 32, data, num);
1057 free(newset);
1058 free(old_data);
1059 }
1060
1061 /**
1062 * Remove a window from the list of colormap windows.
1063 * @param win The toplevel window
1064 * @param subwin The window to be removed from the colormap window list.
1065 */
1066 EAPI void
ecore_x_icccm_colormap_window_unset(Ecore_X_Window win,Ecore_X_Window subwin)1067 ecore_x_icccm_colormap_window_unset(Ecore_X_Window win,
1068 Ecore_X_Window subwin)
1069 {
1070 int num = 0, i, j, k = 0;
1071 unsigned char *old_data = NULL;
1072 unsigned char *data = NULL;
1073 Window *oldset = NULL;
1074 Window *newset = NULL;
1075
1076 LOGFN;
1077 if (!ecore_x_window_prop_property_get(win,
1078 ECORE_X_ATOM_WM_COLORMAP_WINDOWS,
1079 XA_WINDOW, 32, &old_data, &num))
1080 {
1081 if (old_data) free(old_data);
1082 return;
1083 }
1084
1085 oldset = (Window *)old_data;
1086 for (i = 0; i < num; i++)
1087 {
1088 if (oldset[i] == subwin)
1089 {
1090 if (num == 1)
1091 {
1092 XDeleteProperty(_ecore_x_disp,
1093 win, ECORE_X_ATOM_WM_COLORMAP_WINDOWS);
1094 if (_ecore_xlib_sync) ecore_x_sync();
1095 free(old_data);
1096
1097 old_data = NULL;
1098 return;
1099 }
1100 else
1101 {
1102 newset = calloc(num - 1, sizeof(Window));
1103 data = (unsigned char *)newset;
1104 for (j = 0; j < num; ++j)
1105 if (oldset[j] != subwin)
1106 newset[k++] = oldset[j];
1107
1108 ecore_x_window_prop_property_set(
1109 win,
1110 ECORE_X_ATOM_WM_COLORMAP_WINDOWS,
1111 XA_WINDOW,
1112 32,
1113 data,
1114 k);
1115 free(old_data);
1116
1117 old_data = NULL;
1118 free(newset);
1119 return;
1120 }
1121 }
1122 }
1123
1124 if (old_data)
1125 free(old_data);
1126 }
1127
1128 /**
1129 * Specify that a window is transient for another top-level window and should be handled accordingly.
1130 * @param win the transient window
1131 * @param forwin the toplevel window
1132 */
1133 EAPI void
ecore_x_icccm_transient_for_set(Ecore_X_Window win,Ecore_X_Window forwin)1134 ecore_x_icccm_transient_for_set(Ecore_X_Window win,
1135 Ecore_X_Window forwin)
1136 {
1137 LOGFN;
1138 XSetTransientForHint(_ecore_x_disp, win, forwin);
1139 if (_ecore_xlib_sync) ecore_x_sync();
1140 }
1141
1142 /**
1143 * Remove the transient_for setting from a window.
1144 * @param win The window
1145 */
1146 EAPI void
ecore_x_icccm_transient_for_unset(Ecore_X_Window win)1147 ecore_x_icccm_transient_for_unset(Ecore_X_Window win)
1148 {
1149 LOGFN;
1150 XDeleteProperty(_ecore_x_disp, win, ECORE_X_ATOM_WM_TRANSIENT_FOR);
1151 if (_ecore_xlib_sync) ecore_x_sync();
1152 }
1153
1154 /**
1155 * Get the window this window is transient for, if any.
1156 * @param win The window to check
1157 * @return The window ID of the top-level window, or 0 if the property does not exist.
1158 */
1159 EAPI Ecore_X_Window
ecore_x_icccm_transient_for_get(Ecore_X_Window win)1160 ecore_x_icccm_transient_for_get(Ecore_X_Window win)
1161 {
1162 Window forwin;
1163 Eina_Bool success;
1164
1165 LOGFN;
1166 success = XGetTransientForHint(_ecore_x_disp, win, &forwin);
1167 if (_ecore_xlib_sync) ecore_x_sync();
1168 if (success)
1169 return (Ecore_X_Window)forwin;
1170 else
1171 return 0;
1172 }
1173
1174 /**
1175 * Set the window role hint.
1176 * @param win The window
1177 * @param role The role string
1178 */
1179 EAPI void
ecore_x_icccm_window_role_set(Ecore_X_Window win,const char * role)1180 ecore_x_icccm_window_role_set(Ecore_X_Window win,
1181 const char *role)
1182 {
1183 LOGFN;
1184 ecore_x_window_prop_string_set(win, ECORE_X_ATOM_WM_WINDOW_ROLE,
1185 (char *)role);
1186 }
1187
1188 /**
1189 * Get the window role.
1190 * @param win The window
1191 * @return The window's role string.
1192 */
1193 EAPI char *
ecore_x_icccm_window_role_get(Ecore_X_Window win)1194 ecore_x_icccm_window_role_get(Ecore_X_Window win)
1195 {
1196 LOGFN;
1197 return ecore_x_window_prop_string_get(win, ECORE_X_ATOM_WM_WINDOW_ROLE);
1198 }
1199
1200 /**
1201 * Set the window's client leader.
1202 * @param win The window
1203 * @param l The client leader window
1204 *
1205 * All non-transient top-level windows created by an app other than
1206 * the main window must have this property set to the app's main window.
1207 */
1208 EAPI void
ecore_x_icccm_client_leader_set(Ecore_X_Window win,Ecore_X_Window l)1209 ecore_x_icccm_client_leader_set(Ecore_X_Window win,
1210 Ecore_X_Window l)
1211 {
1212 LOGFN;
1213 ecore_x_window_prop_window_set(win, ECORE_X_ATOM_WM_CLIENT_LEADER,
1214 &l, 1);
1215 }
1216
1217 /**
1218 * Get the window's client leader.
1219 * @param win The window
1220 * @return The window's client leader window, or 0 if unset */
1221 EAPI Ecore_X_Window
ecore_x_icccm_client_leader_get(Ecore_X_Window win)1222 ecore_x_icccm_client_leader_get(Ecore_X_Window win)
1223 {
1224 Ecore_X_Window l;
1225
1226 LOGFN;
1227 if (ecore_x_window_prop_window_get(win, ECORE_X_ATOM_WM_CLIENT_LEADER,
1228 &l, 1) > 0)
1229 return l;
1230
1231 return 0;
1232 }
1233
1234 EAPI void
ecore_x_icccm_iconic_request_send(Ecore_X_Window win,Ecore_X_Window root)1235 ecore_x_icccm_iconic_request_send(Ecore_X_Window win,
1236 Ecore_X_Window root)
1237 {
1238 XEvent xev = { 0 };
1239
1240 if (!win)
1241 return;
1242
1243 LOGFN;
1244 if (!root)
1245 root = DefaultRootWindow(_ecore_x_disp);
1246
1247 xev.xclient.type = ClientMessage;
1248 xev.xclient.serial = 0;
1249 xev.xclient.send_event = True;
1250 xev.xclient.display = _ecore_x_disp;
1251 xev.xclient.window = win;
1252 xev.xclient.format = 32;
1253 xev.xclient.message_type = ECORE_X_ATOM_WM_CHANGE_STATE;
1254 xev.xclient.data.l[0] = IconicState;
1255
1256 XSendEvent(_ecore_x_disp, root, False,
1257 SubstructureNotifyMask | SubstructureRedirectMask, &xev);
1258 if (_ecore_xlib_sync) ecore_x_sync();
1259 }
1260
1261 /* FIXME: there are older E hints, gnome hints and mwm hints and new netwm */
1262 /* hints. each should go in their own file/section so we know which */
1263 /* is which. also older kde hints too. we should try support as much */
1264 /* as makese sense to support */
1265