1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2 
3 /*
4  * Functions designed and implemented by Minami Hirokazu(minami@mistfall.net)
5  * are:
6  * - XDND support
7  * - Extended Window Manager Hint(Icon) support
8  */
9 
10 #include "../ui_window.h"
11 
12 #include <stdlib.h>    /* abs */
13 #include <string.h>    /* memset/memcpy */
14 #include <unistd.h>    /* getpid */
15 #include <X11/Xutil.h> /* for XSizeHints */
16 #include <X11/Xatom.h>
17 #include <pobl/bl_debug.h>
18 #include <pobl/bl_mem.h>    /* realloc/free */
19 #include <pobl/bl_util.h>   /* BL_MAX */
20 #include <pobl/bl_unistd.h> /* bl_usleep */
21 #include <pobl/bl_locale.h> /* bl_get_codeset() */
22 
23 #include "../ui_xic.h"
24 #include "../ui_picture.h"
25 #ifndef DISABLE_XDND
26 #include "../ui_dnd.h"
27 #endif
28 #include "ui_type_loader.h"
29 
30 #include "ui_display.h" /* ui_display_get_cursor */
31 #include "ui_decsp_font.h"
32 
33 /*
34  * Atom macros.
35  * Not cached because Atom may differ on each display
36  */
37 
38 #define XA_CLIPBOARD(display) (XInternAtom(display, "CLIPBOARD", False))
39 #define XA_COMPOUND_TEXT(display) (XInternAtom(display, "COMPOUND_TEXT", False))
40 #define XA_TARGETS(display) (XInternAtom(display, "TARGETS", False))
41 #ifdef DEBUG
42 #define XA_MULTIPLE(display) (XInternAtom(display, "MULTIPLE", False))
43 #endif
44 #define XA_TEXT(display) (XInternAtom(display, "TEXT", False))
45 #define XA_UTF8_STRING(display) (XInternAtom(display, "UTF8_STRING", False))
46 #define XA_BMP(display) (XInternAtom(display, "image/bmp", False))
47 #define XA_NONE(display) (XInternAtom(display, "NONE", False))
48 #define XA_SELECTION(display) (XInternAtom(display, "MLTERM_SELECTION", False))
49 #define XA_DELETE_WINDOW(display) (XInternAtom(display, "WM_DELETE_WINDOW", False))
50 #define XA_TAKE_FOCUS(display) (XInternAtom(display, "WM_TAKE_FOCUS", False))
51 #define XA_INCR(display) (XInternAtom(display, "INCR", False))
52 #define XA_XROOTPMAP_ID(display) (XInternAtom(display, "_XROOTPMAP_ID", False))
53 #define XA_XSETROOT_ID(display) (XInternAtom(display, "_XSETROOT_ID", False))
54 #define XA_WM_CLIENT_LEADER(display) (XInternAtom(display, "WM_CLIENT_LEADER", False))
55 
56 /*
57  * Extended Window Manager Hint support
58  */
59 #define XA_NET_WM_ICON(display) (XInternAtom(display, "_NET_WM_ICON", False))
60 #define XA_NET_WM_PID(display) (XInternAtom(display, "_NET_WM_PID", False))
61 
62 /*
63  * Motif Window Manager Hint (for borderless window)
64  */
65 #define XA_MWM_INFO(display) (XInternAtom(display, "_MOTIF_WM_INFO", True))
66 #define XA_MWM_HINTS(display) (XInternAtom(display, "_MOTIF_WM_HINTS", True))
67 
68 #define IS_INHERIT_TRANSPARENT(win) \
69   (use_inherit_transparent && ui_picture_modifier_is_normal((win)->pic_mod))
70 
71 /* win->width is not multiples of (win)->width_inc if window is maximized. */
72 #define RIGHT_MARGIN(win) \
73   ((win)->width_inc ? ((win)->width - (win)->min_width) % (win)->width_inc : 0)
74 #define BOTTOM_MARGIN(win) \
75   ((win)->height_inc ? ((win)->height - (win)->min_height) % (win)->height_inc : 0)
76 
77 typedef struct {
78   u_int32_t flags;
79   u_int32_t functions;
80   u_int32_t decorations;
81   int32_t inputMode;
82   u_int32_t status;
83 } MWMHints_t;
84 
85 #define MWM_HINTS_ELEMENTS      5
86 #define MWM_HINTS_DECORATIONS (1L << 1)
87 
88 #define MAX_CLICK 3 /* max is triple click */
89 
90 #define restore_fg_color(win) ui_gc_set_fg_color((win)->gc, (win)->fg_color.pixel)
91 #define restore_bg_color(win) ui_gc_set_bg_color((win)->gc, (win)->bg_color.pixel)
92 
93 #if 0
94 #define __DEBUG
95 #endif
96 
97 /* --- static variables --- */
98 
99 static int click_interval = 250; /* millisecond, same as xterm. */
100 /* ParentRelative isn't used for transparency by default */
101 static int use_inherit_transparent = 0;
102 static int use_clipboard = 1;
103 static int use_urgent_bell = 0;
104 
105 static struct {
106   u_int8_t h_type[2];
107   u_int8_t h_size[4];
108   u_int8_t h_res1[2];
109   u_int8_t h_res2[2];
110   u_int8_t h_offbits[4];
111 
112   u_int8_t i_size[4];
113   u_int8_t i_width[4];
114   u_int8_t i_height[4];
115   u_int8_t i_planes[2];
116   u_int8_t i_bitcount[2];
117   u_int8_t i_compression[4];
118   u_int8_t i_sizeimage[4];
119   u_int8_t i_xpelspermeter[4];
120   u_int8_t i_ypelspermeter[4];
121   u_int8_t i_clrused[4];
122   u_int8_t i_clrimportant[4];
123 
124   u_char data[1];
125 
126 } * sel_bmp;
127 static size_t sel_bmp_size;
128 
129 /* --- static functions --- */
130 
locale_is_utf8(void)131 static int locale_is_utf8(void) {
132   char *p = bl_get_codeset();
133 
134   if ((*(p++) & ~0x20) == 'U' && (*(p++) & ~0x20) == 'T' &&
135       (*(p++) & ~0x20) == 'F' && p[(*p == '-' || *p == '_')] == '8') {
136     return 1;
137   } else {
138     return 0;
139   }
140 }
141 
urgent_bell(ui_window_t * win,int on)142 static void urgent_bell(ui_window_t *win, int on) {
143   if (use_urgent_bell && (!win->is_focused || !on)) {
144 #ifndef XUrgencyHint
145 #define XUrgencyHint (1L << 8) /* not defined in X11R5 */
146 #endif
147 
148     XWMHints *hints;
149 
150     win = ui_get_root_window(win);
151 
152     if ((hints = XGetWMHints(win->disp->display, win->my_window))) {
153       if (on) {
154         hints->flags |= XUrgencyHint;
155       } else {
156         hints->flags &= ~XUrgencyHint;
157       }
158 
159       XSetWMHints(win->disp->display, win->my_window, hints);
160       XFree(hints);
161     }
162   }
163 }
164 
clear_margin_area(ui_window_t * win)165 static void clear_margin_area(ui_window_t *win) {
166   u_int right_margin;
167   u_int bottom_margin;
168 
169   right_margin = RIGHT_MARGIN(win);
170   bottom_margin = BOTTOM_MARGIN(win);
171 
172   if (win->hmargin > 0) {
173     XClearArea(win->disp->display, win->my_window, 0, 0, win->hmargin, ACTUAL_HEIGHT(win), 0);
174   }
175 
176   if (win->hmargin + right_margin > 0) {
177     XClearArea(win->disp->display, win->my_window, win->width - right_margin + win->hmargin, 0,
178                win->hmargin + right_margin, ACTUAL_HEIGHT(win), 0);
179   }
180 
181   if (win->vmargin > 0) {
182     XClearArea(win->disp->display, win->my_window, win->hmargin, 0, win->width - right_margin,
183                win->vmargin, 0);
184   }
185 
186   if (win->vmargin + bottom_margin > 0) {
187     XClearArea(win->disp->display, win->my_window, win->hmargin,
188                win->height - bottom_margin + win->vmargin, win->width - right_margin,
189                win->vmargin + bottom_margin, 0);
190   }
191 }
192 
193 /* Only used for set_transparent|update_modified_transparent */
set_transparent_picture(ui_window_t * win,Pixmap pixmap)194 static int set_transparent_picture(ui_window_t *win, Pixmap pixmap) {
195   /*
196    * !! Notice !!
197    * This must be done before ui_window_set_wall_picture() because
198    * ui_window_set_wall_picture() doesn't do anything if is_transparent
199    * flag is on.
200    */
201   win->is_transparent = 0;
202 
203   if (!ui_window_set_wall_picture(win, pixmap, 1)) {
204     win->pic_mod = NULL;
205 
206     return 0;
207   }
208 
209   win->is_transparent = 1;
210 
211   return 1;
212 }
213 
214 /* Only used for set_transparent */
update_transparent_picture(ui_window_t * win)215 static int update_transparent_picture(ui_window_t *win) {
216   ui_picture_t *pic;
217 
218   if (!(pic = ui_acquire_bg_picture(win, win->pic_mod, "root"))) {
219     goto error1;
220   }
221 
222   if (!set_transparent_picture(win, pic->pixmap)) {
223     goto error2;
224   }
225 
226   ui_release_picture(pic);
227 
228   return 1;
229 
230 error2:
231   ui_release_picture(pic);
232 
233 error1:
234   win->is_transparent = 0;
235 
236   /* win->pic_mod = NULL is done in set_transparent. */
237 
238   return 0;
239 }
240 
unset_transparent(ui_window_t * win)241 static int unset_transparent(ui_window_t *win) {
242   /*
243    * XXX
244    * If previous mode is not modified transparent,
245    * ParentRelative mode of parent windows should be unset.
246    */
247 
248   /*
249    * !! Notice !!
250    * this must be done before ui_window_unset_wall_picture() because
251    * ui_window_unset_wall_picture() doesn't do anything if is_transparent
252    * flag is on.
253    */
254   win->is_transparent = 0;
255   win->pic_mod = NULL;
256 
257   return ui_window_unset_wall_picture(win, 1);
258 }
259 
set_transparent(ui_window_t * win)260 static int set_transparent(ui_window_t *win) {
261   Window parent;
262 
263   if (!IS_INHERIT_TRANSPARENT(win)) {
264     /*
265      * XXX
266      * If previous mode is not modified transparent,
267      * ParentRelative mode of parent windows should be unset.
268      */
269 
270     /* win->is_transparent is set appropriately in update_transparent_picture().
271      */
272     if (update_transparent_picture(win)) {
273       return 1;
274     } else {
275       bl_msg_printf("_XROOTPMAP_ID is not found.\n");
276 
277       if (win->disp->depth == 32) {
278         /* XSetWindowBackgroundPixmap() fails with BadMatch. (gnome-shell 3.34.4) */
279         unset_transparent(win);
280 
281         return 0;
282       }
283 
284       bl_msg_printf("Trying ParentRelative for transparency instead.\n");
285 
286       if (!ui_picture_modifier_is_normal(win->pic_mod)) {
287         bl_msg_printf("(brightness, contrast, gamma and alpha options are ignored)\n");
288 
289         win->pic_mod = NULL;
290       }
291 
292       use_inherit_transparent = 1;
293     }
294   }
295 
296   /*
297    * It is not necessary to set ParentRelative more than once, so
298    * this function should be used as follows.
299    * if (!IS_INHERIT_TRANSPARENT(win) || !win->wall_picture_is_set) {
300    *   set_transparent(win);
301    * }
302    */
303 
304   /*
305    * Root - Window A - Window C
306    *      - Window B - Window D
307    *                 - Window E
308    * If Window C is set_transparent(), C -> A -> Root are set ParentRelative.
309    * Window B,D and E are not set ParentRelative.
310    */
311 
312   while (win->parent) {
313     /* win->is_transparent is set appropriately in set_transparent() */
314     set_transparent_picture(win, ParentRelative);
315 
316     win = win->parent;
317   }
318 
319   set_transparent_picture(win, ParentRelative);
320 
321   parent = win->my_window;
322   while (1) {
323     Window root;
324     Window *list;
325     u_int n;
326     XWindowAttributes attr;
327 
328     if (!XQueryTree(win->disp->display, parent, &root, &parent, &list, &n)) {
329       break;
330     }
331 
332     XFree(list);
333 
334     if (!parent || parent == root) {
335       break;
336     }
337 
338     if (XGetWindowAttributes(win->disp->display, parent, &attr) && attr.depth == win->disp->depth) {
339       XSetWindowBackgroundPixmap(win->disp->display, parent, ParentRelative);
340     } else {
341       break;
342     }
343   }
344 
345   return 1;
346 }
347 
notify_focus_in_to_children(ui_window_t * win)348 static void notify_focus_in_to_children(ui_window_t *win) {
349   u_int count;
350 
351   if (!win->is_focused && win->inputtable > 0) {
352     win->is_focused = 1;
353 
354     if (win->window_focused) {
355       (*win->window_focused)(win);
356     }
357 
358     ui_xic_set_focus(win);
359   }
360 
361   for (count = 0; count < win->num_children; count++) {
362     notify_focus_in_to_children(win->children[count]);
363   }
364 }
365 
notify_focus_out_to_children(ui_window_t * win)366 static void notify_focus_out_to_children(ui_window_t *win) {
367   u_int count;
368 
369   if (win->is_focused) {
370     win->is_focused = 0;
371 
372     if (win->window_unfocused) {
373       (*win->window_unfocused)(win);
374     }
375 
376     ui_xic_unset_focus(win);
377   }
378 
379   for (count = 0; count < win->num_children; count++) {
380     notify_focus_out_to_children(win->children[count]);
381   }
382 }
383 
notify_configure_to_children(ui_window_t * win)384 static void notify_configure_to_children(ui_window_t *win) {
385   u_int count;
386 
387   if (win->is_transparent) {
388     if (!IS_INHERIT_TRANSPARENT(win) || !win->wall_picture_is_set) {
389 #ifdef __DEBUG
390       bl_debug_printf("configure notify for transparency\n");
391 #endif
392       set_transparent(win);
393     } else if (win->window_exposed) {
394       clear_margin_area(win);
395       (*win->window_exposed)(win, 0, 0, win->width, win->height);
396     }
397 #if 0
398     else {
399       clear_margin_area(win);
400       ui_window_clear_all(win);
401     }
402 #endif
403   }
404 
405   for (count = 0; count < win->num_children; count++) {
406     notify_configure_to_children(win->children[count]);
407   }
408 }
409 
notify_reparent_to_children(ui_window_t * win)410 static void notify_reparent_to_children(ui_window_t *win) {
411   u_int count;
412 
413   if (win->is_transparent) {
414 /* Parent window is changed. => Reset transparent. */
415 
416 #ifdef __DEBUG
417     bl_debug_printf("reparent notify for transparency\n");
418 #endif
419     set_transparent(win);
420   }
421 
422   for (count = 0; count < win->num_children; count++) {
423     notify_reparent_to_children(win->children[count]);
424   }
425 }
426 
notify_property_to_children(ui_window_t * win)427 static void notify_property_to_children(ui_window_t *win) {
428   u_int count;
429 
430   if (win->is_transparent) {
431     /* Background image of desktop is changed. */
432 
433     if (!IS_INHERIT_TRANSPARENT(win)) {
434 #ifdef __DEBUG
435       bl_debug_printf("property notify for transparency\n");
436 #endif
437       set_transparent(win);
438     }
439   }
440 
441   for (count = 0; count < win->num_children; count++) {
442     notify_property_to_children(win->children[count]);
443   }
444 }
445 
is_descendant_window(ui_window_t * win,Window window)446 static int is_descendant_window(ui_window_t *win, Window window) {
447   u_int count;
448 
449   if (win->my_window == window) {
450     return 1;
451   }
452 
453   for (count = 0; count < win->num_children; count++) {
454     if (is_descendant_window(win->children[count], window)) {
455       return 1;
456     }
457   }
458 
459   return 0;
460 }
461 
is_in_the_same_window_family(ui_window_t * win,Window window)462 static int is_in_the_same_window_family(ui_window_t *win, Window window) {
463   return is_descendant_window(ui_get_root_window(win), window);
464 }
465 
total_min_width(ui_window_t * win)466 static u_int total_min_width(ui_window_t *win) {
467   u_int count;
468   u_int min_width;
469 
470   min_width = win->min_width + win->hmargin * 2 + RIGHT_MARGIN(win);
471 
472   for (count = 0; count < win->num_children; count++) {
473     if (win->children[count]->is_mapped &&
474         (win->children[count]->sizehint_flag & SIZEHINT_WIDTH)) {
475       min_width += total_min_width(win->children[count]);
476     }
477   }
478 
479   return min_width;
480 }
481 
total_min_height(ui_window_t * win)482 static u_int total_min_height(ui_window_t *win) {
483   u_int count;
484   u_int min_height;
485 
486   min_height = win->min_height + win->vmargin * 2 + BOTTOM_MARGIN(win);
487 
488   for (count = 0; count < win->num_children; count++) {
489     if (win->children[count]->is_mapped &&
490         (win->children[count]->sizehint_flag & SIZEHINT_HEIGHT)) {
491       min_height += total_min_height(win->children[count]);
492     }
493   }
494 
495   return min_height;
496 }
497 
total_width_inc(ui_window_t * win)498 static u_int total_width_inc(ui_window_t *win) {
499   u_int count;
500   u_int width_inc;
501 
502   width_inc = win->width_inc;
503 
504   for (count = 0; count < win->num_children; count++) {
505     if (win->children[count]->is_mapped &&
506         (win->children[count]->sizehint_flag & SIZEHINT_WIDTH)) {
507       width_inc += total_width_inc(win->children[count]);
508     }
509   }
510 
511   return width_inc;
512 }
513 
total_height_inc(ui_window_t * win)514 static u_int total_height_inc(ui_window_t *win) {
515   u_int count;
516   u_int height_inc;
517 
518   height_inc = win->height_inc;
519 
520   for (count = 0; count < win->num_children; count++) {
521     if (win->children[count]->is_mapped &&
522         (win->children[count]->sizehint_flag & SIZEHINT_HEIGHT)) {
523       height_inc += total_height_inc(win->children[count]);
524     }
525   }
526 
527   return height_inc;
528 }
529 
max_width_inc(ui_window_t * win)530 static u_int max_width_inc(ui_window_t *win) {
531   u_int count;
532   u_int width_inc;
533 
534   width_inc = win->width_inc;
535 
536   for (count = 0; count < win->num_children; count++) {
537     if (win->children[count]->is_mapped &&
538         (win->children[count]->sizehint_flag & SIZEHINT_WIDTH)) {
539       u_int sub_inc;
540 
541       /*
542        * XXX
543        * we should calculate least common multiple of width_inc and sub_inc.
544        */
545       if ((sub_inc = total_width_inc(win->children[count])) > width_inc) {
546         width_inc = sub_inc;
547       }
548     }
549   }
550 
551   return width_inc;
552 }
553 
max_height_inc(ui_window_t * win)554 static u_int max_height_inc(ui_window_t *win) {
555   u_int count;
556   u_int height_inc;
557 
558   height_inc = win->height_inc;
559 
560   for (count = 0; count < win->num_children; count++) {
561     if (win->children[count]->is_mapped &&
562         (win->children[count]->sizehint_flag & SIZEHINT_HEIGHT)) {
563       u_int sub_inc;
564 
565       /*
566        * XXX
567        * we should calculate least common multiple of width_inc and sub_inc.
568        */
569       if ((sub_inc = max_height_inc(win->children[count])) > height_inc) {
570         height_inc = sub_inc;
571       }
572     }
573   }
574 
575   return height_inc;
576 }
577 
reset_client_leader(ui_window_t * root)578 static XID reset_client_leader(ui_window_t *root) {
579   u_long leader;
580 
581   if ((leader = ui_display_get_group_leader(root->disp)) == None) {
582     leader = root->my_window;
583   }
584 
585   XChangeProperty(root->disp->display, root->my_window, XA_WM_CLIENT_LEADER(root->disp->display),
586                   XA_WINDOW, 32, PropModeReplace, (unsigned char *)(&leader), 1);
587 
588   return leader;
589 }
590 
convert_to_decsp_font_index(u_char * str,u_int len)591 static void convert_to_decsp_font_index(u_char *str, u_int len) {
592   while (len != 0) {
593     if (*str == 0x5f) {
594       *str = 0x7f;
595     } else if (0x5f < *str && *str < 0x7f) {
596       (*str) -= 0x5f;
597     }
598 
599     len--;
600     str++;
601   }
602 }
603 
scroll_region(ui_window_t * win,int src_x,int src_y,u_int width,u_int height,int dst_x,int dst_y)604 static void scroll_region(ui_window_t *win, int src_x, int src_y, u_int width, u_int height,
605                           int dst_x, int dst_y) {
606   XCopyArea(win->disp->display, win->my_window, win->my_window, win->gc->gc, src_x + win->hmargin,
607             src_y + win->vmargin, width, height, dst_x + win->hmargin, dst_y + win->vmargin);
608 
609   while (win->wait_copy_area_response) {
610     XEvent ev;
611 
612     XWindowEvent(win->disp->display, win->my_window, ExposureMask, &ev);
613     if (ev.type == GraphicsExpose) {
614       /*
615        * GraphicsExpose caused by the previous XCopyArea is
616        * processed *after* XCopyArea above to avoid following problem.
617        *
618        *  - : GraphicsExpose Area
619        *
620        * (X Window screen)  (vt_term_t)
621        * aaaaaaaaaa         aaaaaaaaaa
622        * bbbbbbbbbb         bbbbbbbbbb
623        * cccccccccc         cccccccccc
624        *   1||(CA)             1||
625        *    \/                  \/
626        * bbbbbbbbbb         bbbbbbbbbb
627        * cccccccccc         cccccccccc
628        * ----------         dddddddddd
629        *                       2||
630        *                        \/
631        * bbbbbbbbbb 3(GE)   cccccccccc
632        * cccccccccc <=====  dddddddddd
633        * eeeeeeeeee         eeeeeeeeee
634        *   4||(CA)
635        *    \/
636        * cccccccccc
637        * eeeeeeeeee
638        * eeeeeeeeee
639        */
640       ev.xgraphicsexpose.x += (dst_x - src_x);
641       ev.xgraphicsexpose.y += (dst_y - src_y);
642     }
643     ui_window_receive_event(win, &ev);
644   }
645 
646   win->wait_copy_area_response = 1;
647 }
648 
send_selection(ui_window_t * win,XSelectionRequestEvent * req_ev,u_char * sel_data,size_t sel_len,Atom sel_type,int sel_format)649 static int send_selection(ui_window_t *win, XSelectionRequestEvent *req_ev, u_char *sel_data,
650                           size_t sel_len, Atom sel_type, int sel_format) {
651   XEvent res_ev;
652 
653   res_ev.xselection.type = SelectionNotify;
654   res_ev.xselection.display = req_ev->display;
655   res_ev.xselection.requestor = req_ev->requestor;
656   res_ev.xselection.selection = req_ev->selection;
657   res_ev.xselection.target = req_ev->target;
658   res_ev.xselection.time = req_ev->time;
659 
660   if (sel_data == NULL) {
661     res_ev.xselection.property = None;
662   } else {
663     if (req_ev->property == None) {
664       /* An obsolete client may fill None as a property.
665        * Try to deal with them by using 'target' instead.
666        */
667       req_ev->property = req_ev->target;
668     }
669     if (req_ev->property != None) {
670       XChangeProperty(win->disp->display, req_ev->requestor, req_ev->property, sel_type, sel_format,
671                       PropModeReplace, sel_data, sel_len);
672     }
673     res_ev.xselection.property = req_ev->property;
674   }
675 
676   XSendEvent(win->disp->display, res_ev.xselection.requestor, False, 0, &res_ev);
677 
678   return 1;
679 }
680 
right_shift(u_long mask)681 static int right_shift(u_long mask) {
682   int shift = 0;
683   int count = 8;
684 
685   if (mask == 0) {
686     return 0;
687   }
688 
689   while ((mask & 1) == 0) {
690     mask >>= 1;
691     shift++;
692   }
693 
694   while ((mask & 1) == 1) {
695     mask >>= 1;
696     count--;
697   }
698 
699   if (count > 0) {
700     shift -= count;
701   }
702 
703   return shift;
704 }
705 
reset_input_focus(ui_window_t * win)706 static void reset_input_focus(ui_window_t *win) {
707   u_int count;
708 
709   if (win->inputtable) {
710     win->inputtable = -1;
711   } else {
712     win->inputtable = 0;
713   }
714 
715   for (count = 0; count < win->num_children; count++) {
716     reset_input_focus(win->children[count]);
717   }
718 }
719 
ensure_input_focus(ui_window_t * win)720 static void ensure_input_focus(ui_window_t *win) {
721   u_int count;
722 
723   if (win->inputtable > 0) {
724     if (!win->is_focused) {
725       XSetInputFocus(win->disp->display, win->my_window, RevertToParent, CurrentTime);
726     }
727   } else {
728     for (count = 0; count < win->num_children; count++) {
729       ensure_input_focus(win->children[count]);
730     }
731   }
732 }
733 
get_num_inputtables(ui_window_t * win)734 static int get_num_inputtables(ui_window_t *win) {
735   u_int count;
736   int num = (win->inputtable != 0) ? 1 : 0;
737 
738   for (count = 0; count < win->num_children; count++) {
739     num += get_num_inputtables(win->children[count]);
740   }
741 
742   return num;
743 }
744 
745 #if !defined(NO_DYNAMIC_LOAD_TYPE)
746 
ui_window_set_use_xft(ui_window_t * win,int use_xft)747 static void ui_window_set_use_xft(ui_window_t *win, int use_xft) {
748   void (*func)(ui_window_t *, int);
749 
750   if (!(func = ui_load_type_xft_func(UI_WINDOW_SET_TYPE))) {
751     return;
752   }
753 
754   (*func)(win, use_xft);
755 }
756 
ui_window_xft_draw_string8(ui_window_t * win,ui_font_t * font,ui_color_t * fg_color,int x,int y,u_char * str,size_t len)757 static void ui_window_xft_draw_string8(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color,
758                                        int x, int y, u_char *str, size_t len) {
759   void (*func)(ui_window_t *, ui_font_t *, ui_color_t *, int, int, u_char *, size_t);
760 
761   if (!(func = ui_load_type_xft_func(UI_WINDOW_DRAW_STRING8))) {
762     return;
763   }
764 
765   (*func)(win, font, fg_color, x, y, str, len);
766 }
767 
ui_window_xft_draw_string32(ui_window_t * win,ui_font_t * font,ui_color_t * fg_color,int x,int y,u_int32_t * str,size_t len)768 static void ui_window_xft_draw_string32(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color,
769                                         int x, int y, /* FcChar32 */ u_int32_t *str, size_t len) {
770   void (*func)(ui_window_t *, ui_font_t *, ui_color_t *, int, int,
771                /* FcChar32 */ u_int32_t *, size_t);
772 
773   if (!(func = ui_load_type_xft_func(UI_WINDOW_DRAW_STRING32))) {
774     return;
775   }
776 
777   (*func)(win, font, fg_color, x, y, str, len);
778 }
779 
xft_set_clip(ui_window_t * win,int x,int y,u_int width,u_int height)780 static void xft_set_clip(ui_window_t *win, int x, int y, u_int width, u_int height) {
781   void (*func)(ui_window_t *, int, int, u_int, u_int);
782 
783   if (!(func = ui_load_type_xft_func(UI_WINDOW_SET_CLIP))) {
784     return;
785   }
786 
787   (*func)(win, x, y, width, height);
788 }
789 
xft_unset_clip(ui_window_t * win)790 static void xft_unset_clip(ui_window_t *win) {
791   void (*func)(ui_window_t *);
792 
793   if (!(func = ui_load_type_xft_func(UI_WINDOW_UNSET_CLIP))) {
794     return;
795   }
796 
797   (*func)(win);
798 }
799 
ui_window_set_use_cairo(ui_window_t * win,int use_cairo)800 static void ui_window_set_use_cairo(ui_window_t *win, int use_cairo) {
801   void (*func)(ui_window_t *, int);
802 
803   if (!(func = ui_load_type_cairo_func(UI_WINDOW_SET_TYPE))) {
804     return;
805   }
806 
807   (*func)(win, use_cairo);
808 }
809 
ui_window_cairo_draw_string8(ui_window_t * win,ui_font_t * font,ui_color_t * fg_color,int x,int y,u_char * str,size_t len)810 static void ui_window_cairo_draw_string8(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color,
811                                          int x, int y, u_char *str, size_t len) {
812   void (*func)(ui_window_t *, ui_font_t *, ui_color_t *, int, int, u_char *, size_t);
813 
814   if (!(func = ui_load_type_cairo_func(UI_WINDOW_DRAW_STRING8))) {
815     return;
816   }
817 
818   (*func)(win, font, fg_color, x, y, str, len);
819 }
820 
ui_window_cairo_draw_string32(ui_window_t * win,ui_font_t * font,ui_color_t * fg_color,int x,int y,u_int32_t * str,size_t len)821 static void ui_window_cairo_draw_string32(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color,
822                                           int x, int y, /* FcChar32 */ u_int32_t *str, size_t len) {
823   void (*func)(ui_window_t *, ui_font_t *, ui_color_t *, int, int,
824                /* FcChar32 */ u_int32_t *, size_t);
825 
826   if (!(func = ui_load_type_cairo_func(UI_WINDOW_DRAW_STRING32))) {
827     return;
828   }
829 
830   (*func)(win, font, fg_color, x, y, str, len);
831 }
832 
cairo_resize(ui_window_t * win)833 static void cairo_resize(ui_window_t *win) {
834   void (*func)(ui_window_t *);
835 
836   if (!(func = ui_load_type_cairo_func(UI_WINDOW_RESIZE))) {
837     return;
838   }
839 
840   (*func)(win);
841 }
842 
cairo_set_clip(ui_window_t * win,int x,int y,u_int width,u_int height)843 static void cairo_set_clip(ui_window_t *win, int x, int y, u_int width, u_int height) {
844   void (*func)(ui_window_t *, int, int, u_int, u_int);
845 
846   if (!(func = ui_load_type_cairo_func(UI_WINDOW_SET_CLIP))) {
847     return;
848   }
849 
850   (*func)(win, x, y, width, height);
851 }
852 
cairo_unset_clip(ui_window_t * win)853 static void cairo_unset_clip(ui_window_t *win) {
854   void (*func)(ui_window_t *);
855 
856   if (!(func = ui_load_type_cairo_func(UI_WINDOW_UNSET_CLIP))) {
857     return;
858   }
859 
860   (*func)(win);
861 }
862 
863 #else /* NO_DYNAMIC_LOAD_TYPE */
864 #ifdef USE_TYPE_XFT
865 void ui_window_set_use_xft(ui_window_t *win, int use_xft);
866 void ui_window_xft_draw_string8(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color, int x,
867                                 int y, u_char *str, size_t len);
868 void ui_window_xft_draw_string32(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color, int x,
869                                  int y, u_int32_t *str, size_t len);
870 void xft_set_clip(ui_window_t *win, int x, int y, u_int width, u_int height);
871 void xft_unset_clip(ui_window_t *win);
872 #endif
873 #ifdef USE_TYPE_CAIRO
874 void ui_window_set_use_cairo(ui_window_t *win, int use_cairo);
875 void ui_window_cairo_draw_string8(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color, int x,
876                                   int y, u_char *str, size_t len);
877 void ui_window_cairo_draw_string32(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color, int x,
878                                    int y, u_int32_t *str, size_t len);
879 void cairo_resize(ui_window_t *win);
880 void cairo_set_clip(ui_window_t *win, int x, int y, u_int width, u_int height);
881 void cairo_unset_clip(ui_window_t *win);
882 #endif
883 #endif /* NO_DYNAMIC_LOAD_TYPE */
884 
885 /* --- global functions --- */
886 
ui_window_init(ui_window_t * win,u_int width,u_int height,u_int min_width,u_int min_height,u_int width_inc,u_int height_inc,u_int hmargin,u_int vmargin,int create_gc,int inputtable)887 int ui_window_init(ui_window_t *win, u_int width, u_int height,
888                    u_int min_width,  /* width_inc * 1 must be added to if width_inc > 0 */
889                    u_int min_height, /* height_inc * 1 must be added to if height_inc > 0 */
890                    u_int width_inc, u_int height_inc, u_int hmargin, u_int vmargin, int create_gc,
891                    int inputtable) {
892   memset(win, 0, sizeof(ui_window_t));
893 
894   win->fg_color.pixel = 0xff000000;
895   win->fg_color.alpha = 0xff;
896   memset(&win->bg_color, 0xff, sizeof(win->bg_color));
897 
898   win->event_mask = ExposureMask | FocusChangeMask | PropertyChangeMask;
899 
900   /* If wall picture is set, scrollable will be 0. */
901   win->is_scrollable = 1;
902 
903 #if 0
904   /*
905    * is_focus member shoule be 0 by default in order to call
906    * XSetICFocus(ui_xic_set_focus) in startup FocusIn event.
907    * If XSetICFocus() is not called, KeyPress event is discarded
908    * in XFilterEvent.
909    */
910   win->is_focused = 0;
911 #endif
912 
913   win->inputtable = inputtable;
914 
915   /* This flag will map window automatically in ui_window_show() */
916   win->is_mapped = 1;
917 
918   win->create_gc = create_gc;
919 
920   win->width = width;
921   win->height = height;
922   win->min_width = min_width;
923   win->min_height = min_height;
924   win->width_inc = width_inc;
925   win->height_inc = height_inc;
926   win->sizehint_flag = SIZEHINT_WIDTH|SIZEHINT_HEIGHT;
927   win->hmargin = hmargin;
928   win->vmargin = vmargin;
929 
930   win->prev_clicked_button = -1;
931 
932   win->app_name = "mlterm"; /* Can be changed in ui_display_show_root(). */
933 
934   return 1;
935 }
936 
ui_window_final(ui_window_t * win)937 void ui_window_final(ui_window_t *win) {
938   u_int count;
939 
940 #ifdef DEBUG
941   bl_debug_printf("[deleting child windows]\n");
942   ui_window_dump_children(win);
943 #endif
944 
945   for (count = 0; count < win->num_children; count++) {
946     ui_window_final(win->children[count]);
947   }
948 
949   free(win->children);
950 
951   if (win->my_window) {
952     ui_display_clear_selection(win->disp, win);
953 
954     ui_xic_deactivate(win);
955 
956     /* Delete cairo/xft. */
957     ui_window_set_type_engine(win, TYPE_XCORE);
958 
959     XDestroyWindow(win->disp->display, win->my_window);
960 
961     if (win->create_gc) {
962       ui_gc_destroy(win->gc);
963     }
964   } else {
965     /* ui_window_show() is not called yet. */
966   }
967 
968   if (win->window_finalized) {
969     (*win->window_finalized)(win);
970   }
971 }
972 
973 /*
974  * Call this function in window_realized event at first.
975  */
ui_window_set_type_engine(ui_window_t * win,ui_type_engine_t type_engine)976 void ui_window_set_type_engine(ui_window_t *win, ui_type_engine_t type_engine) {
977 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XFT)
978   if ((win->xft_draw != NULL) != (type_engine == TYPE_XFT)) {
979     ui_window_set_use_xft(win, (type_engine == TYPE_XFT));
980   }
981 #endif
982 
983 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_CAIRO)
984   if ((win->cairo_draw != NULL) != (type_engine == TYPE_CAIRO)) {
985     ui_window_set_use_cairo(win, (type_engine == TYPE_CAIRO));
986   }
987 #endif
988 }
989 
ui_window_add_event_mask(ui_window_t * win,long event_mask)990 void ui_window_add_event_mask(ui_window_t *win, long event_mask) {
991 #if 0
992   if (event_mask & ButtonMotionMask) {
993     event_mask &= ~ButtonMotionMask;
994     event_mask |= (Button1MotionMask | Button2MotionMask | Button3MotionMask | Button4MotionMask |
995                    Button5MotionMask);
996   }
997 #endif
998 
999   win->event_mask |= event_mask;
1000 
1001   if (win->my_window) {
1002     XSelectInput(win->disp->display, win->my_window, win->event_mask);
1003   }
1004 }
1005 
ui_window_remove_event_mask(ui_window_t * win,long event_mask)1006 void ui_window_remove_event_mask(ui_window_t *win, long event_mask) {
1007 #if 0
1008   if (event_mask & ButtonMotionMask) {
1009     event_mask &= ~ButtonMotionMask;
1010     event_mask |= (Button1MotionMask | Button2MotionMask | Button3MotionMask | Button4MotionMask |
1011                    Button5MotionMask);
1012   }
1013 #endif
1014 
1015   win->event_mask &= ~event_mask;
1016 
1017   if (win->my_window) {
1018     XSelectInput(win->disp->display, win->my_window, win->event_mask);
1019   }
1020 }
1021 
ui_window_ungrab_pointer(ui_window_t * win)1022 void ui_window_ungrab_pointer(ui_window_t *win) {
1023   XUngrabPointer(win->disp->display, CurrentTime);
1024 }
1025 
ui_window_set_wall_picture(ui_window_t * win,Pixmap pic,int do_expose)1026 int ui_window_set_wall_picture(ui_window_t *win, Pixmap pic, int do_expose) {
1027   u_int count;
1028 
1029   if (win->is_transparent) {
1030     /*
1031      * unset transparent before setting wall picture !
1032      */
1033 
1034     return 0;
1035   }
1036 
1037   XSetWindowBackgroundPixmap(win->disp->display, win->my_window, pic);
1038   win->wall_picture_is_set = 1;
1039   win->is_scrollable = 0;
1040 
1041   if (do_expose) {
1042     clear_margin_area(win);
1043 
1044     if (win->window_exposed) {
1045       (*win->window_exposed)(win, 0, 0, win->width, win->height);
1046     }
1047 #if 0
1048     else {
1049       ui_window_clear_all(win);
1050     }
1051 #endif
1052   }
1053 
1054   for (count = 0; count < win->num_children; count++) {
1055     ui_window_set_wall_picture(win->children[count], ParentRelative, do_expose);
1056   }
1057 
1058   return 1;
1059 }
1060 
ui_window_unset_wall_picture(ui_window_t * win,int do_expose)1061 int ui_window_unset_wall_picture(ui_window_t *win, int do_expose) {
1062   u_int count;
1063 
1064 /*
1065  * win->wall_picture_is_set == 0 doesn't mean that following codes
1066  * to disable wall picture is already processed.
1067  * e.g.) If ui_window_unset_transparent() is called after
1068  * ui_window_set_transparent() before my_window is created,
1069  * XSetWindowBackground() which is not called in ui_window_set_bg_color()
1070  * (because is_transparent flag is set by ui_window_set_transparent())
1071  * is never called in startup by checking win->wall_picture_is_set as follows.
1072  */
1073 #if 0
1074   if (!win->wall_picture_is_set) {
1075     /* already unset */
1076 
1077     return 1;
1078   }
1079 #endif
1080 
1081   if (win->is_transparent) {
1082     /*
1083      * transparent background is not a wall picture :)
1084      * this case is regarded as not using a wall picture.
1085      */
1086 
1087     return 1;
1088   }
1089 
1090   XSetWindowBackgroundPixmap(win->disp->display, win->my_window, None);
1091   XSetWindowBackground(win->disp->display, win->my_window, win->bg_color.pixel);
1092 
1093   win->wall_picture_is_set = 0;
1094   win->is_scrollable = 1;
1095 
1096   if (do_expose) {
1097     clear_margin_area(win);
1098 
1099     if (win->window_exposed) {
1100       (*win->window_exposed)(win, 0, 0, win->width, win->height);
1101     }
1102 #if 0
1103     else {
1104       ui_window_clear_all(win);
1105     }
1106 #endif
1107   }
1108 
1109   for (count = 0; count < win->num_children; count++) {
1110     ui_window_unset_wall_picture(win->children[count], do_expose);
1111   }
1112 
1113   return 1;
1114 }
1115 
1116 /*
1117  * This function is possible to be called before my_window is created.
1118  * (because ui_screen_t doesn't contain transparent flag.)
1119  */
ui_window_set_transparent(ui_window_t * win,ui_picture_modifier_t * pic_mod)1120 int ui_window_set_transparent(
1121     ui_window_t *win, /* Transparency is applied to all children recursively */
1122     ui_picture_modifier_t *pic_mod) {
1123   u_int count;
1124 
1125   win->pic_mod = pic_mod;
1126 
1127   if (win->my_window == None) {
1128     /*
1129      * If Window is not still created , actual drawing is delayed and
1130      * ReparentNotify event will do transparent processing automatically after
1131      * ui_window_show().
1132      */
1133 
1134     win->is_transparent = 1;
1135   } else if (!set_transparent(win)) {
1136     return 0;
1137   }
1138 
1139   for (count = 0; count < win->num_children; count++) {
1140     ui_window_set_transparent(win->children[count], win->pic_mod);
1141   }
1142 
1143   return 1;
1144 }
1145 
1146 /*
1147  * This function is possible to be called before my_window is created.
1148  * (because ui_screen_t doesn't contain transparent flag.)
1149  */
ui_window_unset_transparent(ui_window_t * win)1150 int ui_window_unset_transparent(ui_window_t *win) {
1151   u_int count;
1152 
1153   if (win->my_window == None) {
1154     win->is_transparent = 0;
1155   } else if (win->is_transparent) {
1156     unset_transparent(win);
1157 
1158     clear_margin_area(win);
1159 
1160     if (win->window_exposed) {
1161       (*win->window_exposed)(win, 0, 0, win->width, win->height);
1162     }
1163 #if 0
1164     else {
1165       ui_window_clear_all(win);
1166     }
1167 #endif
1168   }
1169 
1170   for (count = 0; count < win->num_children; count++) {
1171     ui_window_unset_transparent(win->children[count]);
1172   }
1173 
1174   return 1;
1175 }
1176 
1177 /*
1178  * Cursor is not changeable after ui_window_show().
1179  */
ui_window_set_cursor(ui_window_t * win,u_int cursor_shape)1180 void ui_window_set_cursor(ui_window_t *win, u_int cursor_shape) {
1181   if (win->my_window == None) {
1182     win->cursor_shape = cursor_shape;
1183   } else {
1184     Cursor cursor;
1185 
1186     if ((cursor = ui_display_get_cursor(win->disp, (win->cursor_shape = cursor_shape)))) {
1187       XDefineCursor(win->disp->display, win->my_window, cursor);
1188     }
1189   }
1190 }
1191 
ui_window_set_fg_color(ui_window_t * win,ui_color_t * fg_color)1192 int ui_window_set_fg_color(ui_window_t *win, ui_color_t *fg_color) {
1193   if (win->fg_color.pixel == fg_color->pixel) {
1194     return 0;
1195   }
1196 
1197   win->fg_color = *fg_color;
1198 
1199   return 1;
1200 }
1201 
ui_window_set_bg_color(ui_window_t * win,ui_color_t * bg_color)1202 int ui_window_set_bg_color(ui_window_t *win, ui_color_t *bg_color) {
1203   if (win->bg_color.pixel == bg_color->pixel) {
1204     return 0;
1205   }
1206 
1207   win->bg_color = *bg_color;
1208 
1209   if (!win->is_transparent && !win->wall_picture_is_set) {
1210     XSetWindowBackground(win->disp->display, win->my_window, win->bg_color.pixel);
1211 
1212     clear_margin_area(win);
1213   }
1214 
1215   return 1;
1216 }
1217 
ui_window_add_child(ui_window_t * win,ui_window_t * child,int x,int y,int map)1218 int ui_window_add_child(ui_window_t *win, ui_window_t *child, int x, int y, int map) {
1219   void *p;
1220 
1221   if ((p = realloc(win->children, sizeof(*win->children) * (win->num_children + 1))) == NULL) {
1222 #ifdef DEBUG
1223     bl_warn_printf(BL_DEBUG_TAG " realloc failed.\n");
1224 #endif
1225 
1226     return 0;
1227   }
1228 
1229   win->children = p;
1230 
1231   child->parent = win;
1232   child->x = x + win->hmargin;
1233   child->y = y + win->vmargin;
1234 
1235   if (!(child->is_mapped = map) && child->inputtable > 0) {
1236     child->inputtable = -1;
1237   }
1238 
1239   win->children[win->num_children++] = child;
1240 
1241   return 1;
1242 }
1243 
ui_window_remove_child(ui_window_t * win,ui_window_t * child)1244 int ui_window_remove_child(ui_window_t *win, ui_window_t *child) {
1245   u_int count;
1246 
1247   for (count = 0; count < win->num_children; count++) {
1248     if (win->children[count] == child) {
1249       child->parent = NULL;
1250       win->children[count] = win->children[--win->num_children];
1251 
1252       return 1;
1253     }
1254   }
1255 
1256   return 0;
1257 }
1258 
ui_get_root_window(ui_window_t * win)1259 ui_window_t *ui_get_root_window(ui_window_t *win) {
1260   while (win->parent != NULL) {
1261     win = win->parent;
1262   }
1263 
1264   return win;
1265 }
1266 
ui_window_get_fg_gc(ui_window_t * win)1267 GC ui_window_get_fg_gc(ui_window_t *win) {
1268   /* Reset */
1269   restore_fg_color(win);
1270 
1271 #if 0
1272   restore_bg_color(win);
1273 #endif
1274 
1275   return win->gc->gc;
1276 }
1277 
ui_window_get_bg_gc(ui_window_t * win)1278 GC ui_window_get_bg_gc(ui_window_t *win) {
1279   ui_gc_set_fg_color((win)->gc, (win)->bg_color.pixel);
1280 
1281 #if 0
1282   ui_gc_set_bg_color((win)->gc, (win)->fg_color.pixel);
1283 #endif
1284 
1285   return win->gc->gc;
1286 }
1287 
1288 /*
1289  * If win->parent(_window) is None, specify XValue|YValue as 'hint' to locate
1290  * window at win->x/win->y.
1291  */
ui_window_show(ui_window_t * win,int hint)1292 int ui_window_show(ui_window_t *win, int hint) {
1293   u_int count;
1294   XSetWindowAttributes s_attr;
1295 
1296   if (win->my_window) {
1297     /* already shown */
1298 
1299     return 0;
1300   }
1301 
1302   if (win->parent) {
1303     win->disp = win->parent->disp;
1304     win->gc = win->parent->gc;
1305     win->parent_window = win->parent->my_window;
1306   }
1307 
1308   if (hint & XNegative) {
1309     win->x += (win->disp->width - ACTUAL_WIDTH(win));
1310   }
1311 
1312   if (hint & YNegative) {
1313     win->y += (win->disp->height - ACTUAL_HEIGHT(win));
1314   }
1315 
1316   s_attr.background_pixel = win->bg_color.pixel;
1317   s_attr.border_pixel = win->fg_color.pixel;
1318   s_attr.colormap = win->disp->colormap;
1319 #if 1
1320   win->my_window =
1321       XCreateWindow(win->disp->display, win->parent_window, win->x, win->y, ACTUAL_WIDTH(win),
1322                     ACTUAL_HEIGHT(win), 0, win->disp->depth, InputOutput, win->disp->visual,
1323                     CWBackPixel | CWBorderPixel | CWColormap, &s_attr);
1324 #else
1325   win->my_window =
1326       XCreateSimpleWindow(win->disp->display, win->parent_window, win->x, win->y, ACTUAL_WIDTH(win),
1327                           ACTUAL_HEIGHT(win), 0, win->fg_color.pixel, win->bg_color.pixel);
1328 #endif
1329 
1330   if (win->create_gc) {
1331     ui_gc_t *gc;
1332 
1333     if ((gc = ui_gc_new(win->disp->display, win->my_window)) == NULL) {
1334 #ifdef DEBUG
1335       bl_debug_printf(BL_DEBUG_TAG " ui_gc_new failed.\n");
1336 #endif
1337       win->create_gc = 0;
1338     } else {
1339       win->gc = gc;
1340     }
1341   }
1342 
1343   if (win->cursor_shape) {
1344     Cursor cursor;
1345 
1346     if ((cursor = ui_display_get_cursor(win->disp, win->cursor_shape))) {
1347       XDefineCursor(win->disp->display, win->my_window, cursor);
1348     }
1349   }
1350 
1351   /* Don't use win->parent here in case mlterm works as libvte. */
1352   if (PARENT_WINDOWID_IS_TOP(win)) {
1353     /* Root window */
1354 
1355     XSizeHints size_hints;
1356     int total;
1357     XClassHint class_hint;
1358     XWMHints wm_hints;
1359     int argc = 1;
1360     char *argv[] = {
1361         "mlterm", NULL,
1362     };
1363     Atom protocols[2];
1364     XID pid;
1365 
1366     win->event_mask |= StructureNotifyMask;
1367 
1368     /*
1369      * XXX
1370      * x/y/width/height are obsoleted. (see XSizeHints(3))
1371      */
1372     size_hints.x = win->x;
1373     size_hints.y = win->y;
1374     size_hints.width = ACTUAL_WIDTH(win);
1375     size_hints.height = ACTUAL_HEIGHT(win);
1376 
1377     size_hints.width_inc = max_width_inc(win);
1378     size_hints.height_inc = max_height_inc(win);
1379     size_hints.min_width = total_min_width(win);
1380     size_hints.min_height = total_min_height(win);
1381     total = total_width_inc(win);
1382     size_hints.base_width = (size_hints.min_width > total) ?
1383                              size_hints.min_width - total : 0;
1384     total = total_height_inc(win);
1385     size_hints.base_height = (size_hints.min_height > total) ?
1386                               size_hints.min_height - total : 0;
1387 
1388 #ifdef DEBUG
1389     bl_debug_printf(BL_DEBUG_TAG " Size hints => w %d h %d wi %d hi %d mw %d mh %d bw %d bh %d\n",
1390                     size_hints.width, size_hints.height, size_hints.width_inc,
1391                     size_hints.height_inc, size_hints.min_width, size_hints.min_height,
1392                     size_hints.base_width, size_hints.base_height);
1393 #endif
1394 
1395     if (hint & XNegative) {
1396       if (hint & YNegative) {
1397         size_hints.win_gravity = SouthEastGravity;
1398       } else {
1399         size_hints.win_gravity = NorthEastGravity;
1400       }
1401     } else {
1402       if (hint & YNegative) {
1403         size_hints.win_gravity = SouthWestGravity;
1404       } else {
1405         size_hints.win_gravity = NorthWestGravity;
1406       }
1407     }
1408 
1409     size_hints.flags = PSize | PMinSize | PResizeInc | PBaseSize | PWinGravity;
1410 
1411     if (hint & (XValue | YValue)) {
1412       size_hints.flags |= PPosition;
1413       size_hints.flags |= USPosition;
1414     }
1415 
1416     /*
1417      * XXX
1418      * If res_name = "mlterm" and res_class = "mlterm", lxde (0.99.2) doesn't
1419      * show title bar for mlterm.
1420      */
1421     class_hint.res_name = "xterm"; /* same as xterm */
1422     class_hint.res_class = win->app_name;
1423 
1424     wm_hints.initial_state = NormalState; /* or IconicState */
1425     wm_hints.input = True;                /* wants FocusIn/FocusOut */
1426     wm_hints.window_group = reset_client_leader(win);
1427     wm_hints.flags = StateHint | InputHint | WindowGroupHint;
1428 #if 0
1429     bl_debug_printf(BL_DEBUG_TAG " Group leader -> %x\n", wm_hints.window_group);
1430 #endif
1431 
1432     /* Notify to window manager. */
1433     XmbSetWMProperties(win->disp->display, win->my_window, win->app_name, win->app_name, argv, argc,
1434                        &size_hints, &wm_hints, &class_hint);
1435 
1436     protocols[0] = XA_DELETE_WINDOW(win->disp->display);
1437     protocols[1] = XA_TAKE_FOCUS(win->disp->display);
1438 
1439     XSetWMProtocols(win->disp->display, win->my_window, protocols, 2);
1440 
1441     pid = getpid();
1442     XChangeProperty(win->disp->display, win->my_window,
1443                     XA_NET_WM_PID(win->disp->display), XA_CARDINAL,
1444                     32, PropModeReplace, (unsigned char *)&pid, 1);
1445   }
1446 
1447   if (win->parent && !win->parent->is_transparent && win->parent->wall_picture_is_set) {
1448     ui_window_set_wall_picture(win, ParentRelative, 0);
1449   }
1450 
1451   /*
1452    * This should be called after Window Manager settings, because
1453    * ui_set_{window|icon}_name() can be called in win->window_realized().
1454    */
1455   if (win->window_realized) {
1456     (*win->window_realized)(win);
1457   }
1458 
1459   XSelectInput(win->disp->display, win->my_window, win->event_mask);
1460 
1461 #if 0
1462   {
1463     char *locale;
1464 
1465     if ((locale = bl_get_locale())) {
1466       XChangeProperty(win->disp->display, win->my_window,
1467                       XInternAtom(win->disp->display, "WM_LOCALE_NAME", False), XA_STRING, 8,
1468                       PropModeReplace, locale, strlen(locale));
1469     }
1470   }
1471 #endif
1472 
1473   /*
1474    * showing child windows.
1475    */
1476 
1477   for (count = 0; count < win->num_children; count++) {
1478     ui_window_show(win->children[count], 0);
1479   }
1480 
1481   /*
1482    * really visualized.
1483    */
1484 
1485   if (win->is_mapped) {
1486     XMapWindow(win->disp->display, win->my_window);
1487 
1488     if (win->inputtable > 0) {
1489       reset_input_focus(ui_get_root_window(win));
1490       win->inputtable = 1;
1491     }
1492 
1493 #if 0
1494     ui_window_clear_all(win);
1495 #endif
1496   }
1497 
1498   return 1;
1499 }
1500 
ui_window_map(ui_window_t * win)1501 void ui_window_map(ui_window_t *win) {
1502   if (win->is_mapped) {
1503     return;
1504   }
1505 
1506   XMapWindow(win->disp->display, win->my_window);
1507   win->is_mapped = 1;
1508 }
1509 
ui_window_unmap(ui_window_t * win)1510 void ui_window_unmap(ui_window_t *win) {
1511   if (!win->is_mapped) {
1512     return;
1513   }
1514 
1515   XUnmapWindow(win->disp->display, win->my_window);
1516   win->is_mapped = 0;
1517 }
1518 
ui_window_resize(ui_window_t * win,u_int width,u_int height,ui_resize_flag_t flag)1519 int ui_window_resize(ui_window_t *win, u_int width, /* excluding margin */
1520                      u_int height,                  /* excluding margin */
1521                      ui_resize_flag_t flag          /* NOTIFY_TO_PARENT , NOTIFY_TO_MYSELF */
1522                      ) {
1523   if (win->width == width && win->height == height) {
1524     return 0;
1525   }
1526 
1527   /* Max width of each window is DisplayWidth(). */
1528   if ((flag & LIMIT_RESIZE) && win->disp->width < width) {
1529     win->width = win->disp->width - win->hmargin * 2;
1530   } else {
1531     win->width = width;
1532   }
1533 
1534   /* Maui.height of each window is DisplayHeight(). */
1535   if ((flag & LIMIT_RESIZE) && win->disp->height < height) {
1536     win->height = win->disp->height - win->vmargin * 2;
1537   } else {
1538     win->height = height;
1539   }
1540 
1541   if ((flag & NOTIFY_TO_PARENT) && win->parent && win->parent->child_window_resized) {
1542     (*win->parent->child_window_resized)(win->parent, win);
1543   }
1544 
1545   XResizeWindow(win->disp->display, win->my_window, ACTUAL_WIDTH(win), ACTUAL_HEIGHT(win));
1546 
1547   if ((flag & NOTIFY_TO_MYSELF) && win->window_resized) {
1548     (*win->window_resized)(win);
1549   }
1550 
1551 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_CAIRO)
1552   if (win->cairo_draw) {
1553     cairo_resize(win);
1554   }
1555 #endif
1556 
1557   if (!win->configure_root && !(flag & NOTIFY_TO_PARENT) && win->parent) {
1558     notify_configure_to_children(win);
1559   }
1560 
1561   return 1;
1562 }
1563 
1564 /*
1565  * !! Notice !!
1566  * This function is not recommended.
1567  * Use ui_window_resize if at all possible.
1568  */
ui_window_resize_with_margin(ui_window_t * win,u_int width,u_int height,ui_resize_flag_t flag)1569 int ui_window_resize_with_margin(ui_window_t *win, u_int width, u_int height,
1570                                  ui_resize_flag_t flag /* NOTIFY_TO_PARENT , NOTIFY_TO_MYSELF */
1571                                  ) {
1572   u_int min_width;
1573   u_int min_height;
1574 
1575   min_width = total_min_width(win);
1576   min_height = total_min_height(win);
1577 
1578   return ui_window_resize(win, width <= min_width ? min_width : width - win->hmargin * 2,
1579                           height <= min_height ? min_height : height - win->vmargin * 2, flag);
1580 }
1581 
ui_window_set_maximize_flag(ui_window_t * win,ui_maximize_flag_t flag)1582 void ui_window_set_maximize_flag(ui_window_t *win, ui_maximize_flag_t flag) {
1583   if (flag) {
1584     u_int w;
1585     u_int h;
1586     int x;
1587     int y;
1588 
1589     win = ui_get_root_window(win);
1590 
1591     ui_window_translate_coordinates(win, 0, 0, &x, &y);
1592 
1593     if (flag & MAXIMIZE_HORIZONTAL) {
1594       w = win->disp->width - win->hmargin * 2;
1595       x = 0;
1596     } else {
1597       w = win->width;
1598     }
1599 
1600     if (flag & MAXIMIZE_VERTICAL) {
1601       h = win->disp->height - win->vmargin * 2;
1602       y = 0;
1603     } else {
1604       h = win->height;
1605     }
1606 
1607     XMoveWindow(win->disp->display, win->my_window, x, y);
1608     ui_window_resize(win, w, h, NOTIFY_TO_MYSELF);
1609   } else {
1610     /* XXX MAXIMIZE_RESTORE is not supported for now. */
1611   }
1612 }
1613 
ui_window_set_normal_hints(ui_window_t * win,u_int min_width,u_int min_height,u_int width_inc,u_int height_inc)1614 void ui_window_set_normal_hints(ui_window_t *win, u_int min_width, u_int min_height,
1615                                 u_int width_inc, u_int height_inc) {
1616   XSizeHints size_hints;
1617   int total;
1618   ui_window_t *root;
1619 
1620   win->min_width = min_width;
1621   win->min_height = min_height;
1622   win->width_inc = width_inc;
1623   win->height_inc = height_inc;
1624 
1625   root = ui_get_root_window(win);
1626 
1627   /*
1628    * these hints must be set at the same time !
1629    */
1630   size_hints.width_inc = max_width_inc(root);
1631   size_hints.height_inc = max_height_inc(root);
1632   size_hints.min_width = total_min_width(root);
1633   size_hints.min_height = total_min_height(root);
1634   total = total_width_inc(win);
1635   size_hints.base_width = (size_hints.min_width > total) ?
1636                            size_hints.min_width - total : 0;
1637   total = total_height_inc(win);
1638   size_hints.base_height = (size_hints.min_height > total) ?
1639                             size_hints.min_height - total : 0;
1640   size_hints.flags = PMinSize | PResizeInc | PBaseSize;
1641 
1642 #ifdef DEBUG
1643   bl_debug_printf(BL_DEBUG_TAG " Size hints => w %u h %u wi %u hi %u mw %u mh %u bw %u bh %u\n",
1644                   ACTUAL_WIDTH(win), ACTUAL_HEIGHT(win),
1645                   size_hints.width_inc, size_hints.height_inc, size_hints.min_width,
1646                   size_hints.min_height, size_hints.base_width, size_hints.base_height);
1647 #endif
1648 
1649   XSetWMNormalHints(root->disp->display, root->my_window, &size_hints);
1650 }
1651 
ui_window_set_override_redirect(ui_window_t * win,int flag)1652 void ui_window_set_override_redirect(ui_window_t *win, int flag) {
1653   ui_window_t *root;
1654   XSetWindowAttributes s_attr;
1655   XWindowAttributes g_attr;
1656 
1657   root = ui_get_root_window(win);
1658 
1659   XGetWindowAttributes(root->disp->display, root->my_window, &g_attr);
1660   if (flag) {
1661     s_attr.override_redirect = True;
1662   } else {
1663     s_attr.override_redirect = False;
1664   }
1665 
1666   if (g_attr.override_redirect == s_attr.override_redirect) {
1667     return;
1668   }
1669 
1670   XChangeWindowAttributes(root->disp->display, root->my_window, CWOverrideRedirect, &s_attr);
1671 
1672   if (g_attr.map_state != IsUnmapped) {
1673     XUnmapWindow(root->disp->display, root->my_window);
1674     XMapWindow(root->disp->display, root->my_window);
1675   }
1676 
1677   reset_input_focus(root);
1678   /* XXX Always focused not to execute XSetInputFocus(). */
1679   win->inputtable = win->is_focused = 1;
1680 }
1681 
ui_window_set_borderless_flag(ui_window_t * win,int flag)1682 int ui_window_set_borderless_flag(ui_window_t *win, int flag) {
1683   /*
1684    * XXX
1685    * Support borderless with _MOTIF_WM_HINTS.
1686    * (See Eterm/src/windows.c)
1687    */
1688 
1689   ui_window_t *root;
1690   Atom atom;
1691 
1692   root = ui_get_root_window(win);
1693 
1694 #ifdef __DEBUG
1695   bl_debug_printf("MOTIF_WM_HINTS: %x\nMOTIF_WM_INFO: %x\n",
1696                   XInternAtom(root->disp->display, "_MOTIF_WM_HINTS", True),
1697                   XInternAtom(root->disp->display, "_MOTIF_WM_INFO", True));
1698 #endif
1699 
1700   if ((atom = XA_MWM_HINTS(root->disp->display)) != None) {
1701     if (flag) {
1702       MWMHints_t mwmhints = {MWM_HINTS_DECORATIONS, 0, 0, 0, 0};
1703 
1704       XChangeProperty(root->disp->display, root->my_window, atom, atom, 32, PropModeReplace,
1705                       (u_char *)&mwmhints, MWM_HINTS_ELEMENTS);
1706     } else {
1707       XDeleteProperty(root->disp->display, root->my_window, atom);
1708     }
1709   } else {
1710     /* fall back to override redirect */
1711     ui_window_set_override_redirect(win, flag);
1712   }
1713 
1714   return 1;
1715 }
1716 
ui_window_move(ui_window_t * win,int x,int y)1717 int ui_window_move(ui_window_t *win, int x, int y) {
1718   if (win->parent) {
1719     x += win->parent->hmargin;
1720     y += win->parent->vmargin;
1721   }
1722 
1723   if (win->x == x && win->y == y) {
1724     return 0;
1725   }
1726 
1727   win->x = x;
1728   win->y = y;
1729 
1730   XMoveWindow(win->disp->display, win->my_window, win->x, win->y);
1731 
1732   if (!win->configure_root && win->parent) {
1733     notify_configure_to_children(win);
1734   }
1735 
1736   return 1;
1737 }
1738 
ui_window_clear(ui_window_t * win,int x,int y,u_int width,u_int height)1739 void ui_window_clear(ui_window_t *win, int x, int y, u_int width, u_int height) {
1740 #ifdef AUTO_CLEAR_MARGIN
1741   if (x + width >= win->width) {
1742     /* Clearing margin area */
1743     width += win->hmargin;
1744   }
1745 
1746   if (x > 0)
1747 #endif
1748   {
1749     x += win->hmargin;
1750   }
1751 #ifdef AUTO_CLEAR_MARGIN
1752   else {
1753     /* Clearing margin area */
1754     width += win->hmargin;
1755   }
1756 
1757   if (y + height >= win->height) {
1758     /* Clearing margin area */
1759     height += win->vmargin;
1760   }
1761 
1762   if (y > 0)
1763 #endif
1764   {
1765     y += win->vmargin;
1766   }
1767 #ifdef AUTO_CLEAR_MARGIN
1768   else {
1769     /* Clearing margin area */
1770     height += win->vmargin;
1771   }
1772 #endif
1773 
1774   XClearArea(win->disp->display, win->my_window, x, y, width, height, False);
1775 }
1776 
ui_window_clear_all(ui_window_t * win)1777 void ui_window_clear_all(ui_window_t *win) {
1778   ui_window_clear(win, 0, 0, win->width, win->height);
1779 }
1780 
ui_window_fill(ui_window_t * win,int x,int y,u_int width,u_int height)1781 void ui_window_fill(ui_window_t *win, int x, int y, u_int width, u_int height) {
1782   restore_fg_color(win);
1783 
1784   XFillRectangle(win->disp->display, win->my_window, win->gc->gc, x + win->hmargin,
1785                  y + win->vmargin, width, height);
1786 }
1787 
ui_window_fill_with(ui_window_t * win,ui_color_t * color,int x,int y,u_int width,u_int height)1788 void ui_window_fill_with(ui_window_t *win, ui_color_t *color, int x, int y, u_int width,
1789                         u_int height) {
1790   ui_gc_set_fg_color(win->gc, color->pixel);
1791 
1792   XFillRectangle(win->disp->display, win->my_window, win->gc->gc, x + win->hmargin,
1793                  y + win->vmargin, width, height);
1794 }
1795 
ui_window_blank(ui_window_t * win)1796 void ui_window_blank(ui_window_t *win) {
1797   restore_fg_color(win);
1798 
1799   XFillRectangle(win->disp->display, win->my_window, win->gc->gc, win->hmargin, win->vmargin,
1800                  win->width - RIGHT_MARGIN(win), win->height - BOTTOM_MARGIN(win));
1801 }
1802 
1803 #if 0
1804 /*
1805  * XXX
1806  * At the present time, not used and not maintained.
1807  */
1808 void ui_window_blank_with(ui_window_t *win, ui_color_t *color) {
1809   ui_gc_set_fg_color(win->gc, color->pixel);
1810 
1811   XFillRectangle(win->disp->display, win->my_window, win->gc->gc, win->hmargin, win->vmargin,
1812                  win->width, win->height);
1813 }
1814 #endif
1815 
ui_window_update(ui_window_t * win,int flag)1816 void ui_window_update(ui_window_t *win, int flag) {
1817   if (win->update_window) {
1818     (*win->update_window)(win, flag);
1819 
1820     if (win->gc->mask) {
1821       /*
1822        * ui_window_copy_area() can set win->gc->mask.
1823        * It can cause unexpected drawing in ui_animate_inline_pictures().
1824        */
1825       XSetClipMask(win->disp->display, win->gc->gc, None);
1826       win->gc->mask = None;
1827     }
1828   }
1829 }
1830 
ui_window_update_all(ui_window_t * win)1831 void ui_window_update_all(ui_window_t *win) {
1832   u_int count;
1833 
1834   clear_margin_area(win);
1835 
1836   if (win->window_exposed) {
1837     (*win->window_exposed)(win, 0, 0, win->width, win->height);
1838   }
1839 
1840   for (count = 0; count < win->num_children; count++) {
1841     ui_window_update_all(win->children[count]);
1842   }
1843 }
1844 
ui_window_idling(ui_window_t * win)1845 void ui_window_idling(ui_window_t *win) {
1846   u_int count;
1847 
1848   for (count = 0; count < win->num_children; count++) {
1849     ui_window_idling(win->children[count]);
1850   }
1851 
1852 #ifdef __DEBUG
1853   if (win->button_is_pressing) {
1854     bl_debug_printf(BL_DEBUG_TAG " button is pressing...\n");
1855   }
1856 #endif
1857 
1858   if (win->button_is_pressing && win->button_press_continued) {
1859     (*win->button_press_continued)(win, &win->prev_button_press_event);
1860   } else if (win->idling) {
1861     (*win->idling)(win);
1862   }
1863 }
1864 
1865 /*
1866  * Return value: 0 => different window.
1867  *               1 => finished processing.
1868  */
ui_window_receive_event(ui_window_t * win,XEvent * event)1869 int ui_window_receive_event(ui_window_t *win, XEvent *event) {
1870   u_int count;
1871 
1872   for (count = 0; count < win->num_children; count++) {
1873     if (ui_window_receive_event(win->children[count], event)) {
1874       return 1;
1875     }
1876   }
1877 
1878   if (win->my_window != event->xany.window) {
1879     /*
1880      * XXX
1881      * if some window invokes xim window open event and it doesn't have any xic
1882      * ,
1883      * no xim window will be opened at XFilterEvent() in
1884      * ui_display_receive_next_event().
1885      * but it is desired to open xim window of ui_screen when its event is
1886      * invoked
1887      * on scrollbar or title bar.
1888      * this hack enables it , but this way won't deal with the case that
1889      * multiple
1890      * xics exist.
1891      */
1892     if (win->xic) {
1893       if (is_in_the_same_window_family(win, event->xany.window) &&
1894           XFilterEvent(event, win->my_window)) {
1895         return 1;
1896       }
1897     }
1898 
1899     if (event->type == PropertyNotify && win == ui_get_root_window(win) &&
1900         (event->xproperty.atom == XA_XSETROOT_ID(win->disp->display) ||
1901          event->xproperty.atom == XA_XROOTPMAP_ID(win->disp->display))) {
1902       /*
1903        * Background image is changed.
1904        * (notify_property_to_children() is called here because
1905        * event->xproperty.window is not win->my_window.)
1906        *
1907        * twm => XA_XSETROOT_ID
1908        * englightment => XA_XROOTPMAP_ID
1909        */
1910 
1911       notify_property_to_children(win);
1912 
1913       return 1;
1914     }
1915 
1916     if (event->type == MappingNotify && event->xmapping.request != MappingPointer) {
1917       if (win->disp) {
1918 #ifdef DEBUG
1919         bl_warn_printf(BL_DEBUG_TAG " MappingNotify serial #%d\n", event->xmapping.serial);
1920 #endif
1921         XRefreshKeyboardMapping(&(event->xmapping));
1922         ui_display_update_modifier_mapping(win->disp, event->xmapping.serial);
1923         /* have to process only once */
1924         return 1;
1925       }
1926 
1927       if (win->mapping_notify) {
1928         (*win->mapping_notify)(win);
1929       }
1930     }
1931 
1932     return 0;
1933   }
1934 
1935 #ifndef DISABLE_XDND
1936   if (ui_dnd_filter_event(event, win)) {
1937     /* event was consumed by xdnd handlers */
1938     return 1;
1939   }
1940 #endif
1941 
1942   if (event->type == KeyPress) {
1943     if (win->key_pressed) {
1944       (*win->key_pressed)(win, &event->xkey);
1945     }
1946   } else if (event->type == FocusIn) {
1947 #ifdef __DEBUG
1948     bl_debug_printf("FOCUS IN %p (parent %p)\n", event->xany.window, win->parent);
1949 #endif
1950 
1951     urgent_bell(win, 0);
1952 
1953     if (!win->parent && get_num_inputtables(win) > 1) {
1954       ensure_input_focus(win);
1955     } else {
1956       /*
1957        * Cygwin/X can send FocusIn/FocusOut events not to top windows
1958        * but to child ones in changing window focus, so don't encircle
1959        * notify_focus_{in|out}_to_children with if(!win->parent).
1960        */
1961       notify_focus_in_to_children(win);
1962     }
1963   } else if (event->type == FocusOut) {
1964 #ifdef __DEBUG
1965     bl_debug_printf("FOCUS OUT %p (parent %p)\n", event->xany.window, win->parent);
1966 #endif
1967 
1968     /*
1969      * Cygwin/X can send FocusIn/FocusOut events not to top windows
1970      * but to child ones in changing window focus, so don't encircle
1971      * notify_focus_{in|out}_to_children with if(!win->parent).
1972      */
1973     notify_focus_out_to_children(win);
1974   } else if (event->type == MotionNotify) {
1975     XEvent ahead;
1976 
1977     while (XEventsQueued(win->disp->display, QueuedAfterReading)) {
1978       XPeekEvent(win->disp->display, &ahead);
1979 
1980       if (ahead.type != MotionNotify || ahead.xmotion.window != event->xmotion.window) {
1981         break;
1982       }
1983 
1984       XNextEvent(win->disp->display, event);
1985     }
1986 
1987     /*
1988      * If ButtonReleaseMask is not set to win->event_mask,
1989      * win->button_is_pressing
1990      * is always 0. So, event->xmotion.state is also checked.
1991      */
1992     if (win->button_is_pressing || (event->xmotion.state & ButtonMask)) {
1993       if (win->button_motion) {
1994         event->xmotion.x -= win->hmargin;
1995         event->xmotion.y -= win->vmargin;
1996 
1997         (*win->button_motion)(win, &event->xmotion);
1998       }
1999 
2000       /* following button motion ... */
2001 
2002       win->prev_button_press_event.x = event->xmotion.x;
2003       win->prev_button_press_event.y = event->xmotion.y;
2004       win->prev_button_press_event.time = event->xmotion.time;
2005     } else if (win->pointer_motion) {
2006       event->xmotion.x -= win->hmargin;
2007       event->xmotion.y -= win->vmargin;
2008 
2009       (*win->pointer_motion)(win, &event->xmotion);
2010     }
2011   } else if (event->type == ButtonRelease) {
2012     if (win->button_released) {
2013       event->xbutton.x -= win->hmargin;
2014       event->xbutton.y -= win->vmargin;
2015 
2016       (*win->button_released)(win, &event->xbutton);
2017     }
2018 
2019     win->button_is_pressing = 0;
2020   } else if (event->type == ButtonPress) {
2021     if (win->button_pressed) {
2022       event->xbutton.x -= win->hmargin;
2023       event->xbutton.y -= win->vmargin;
2024 
2025       /* XXX If button is released outside screen, ButtonRelease event might not happen. */
2026       if (win->button_is_pressing) {
2027         if (win->button_released) {
2028           XButtonEvent ev = event->xbutton;
2029           ev.type = ButtonRelease;
2030           (*win->button_released)(win, &ev);
2031         }
2032         win->button_is_pressing = 0;
2033       }
2034 
2035       if (win->click_num == MAX_CLICK) {
2036         win->click_num = 0;
2037       }
2038 
2039       if (win->prev_clicked_time + click_interval >= event->xbutton.time &&
2040           event->xbutton.button == win->prev_clicked_button) {
2041         win->click_num++;
2042         win->prev_clicked_time = event->xbutton.time;
2043       } else {
2044         win->click_num = 1;
2045         win->prev_clicked_time = event->xbutton.time;
2046         win->prev_clicked_button = event->xbutton.button;
2047       }
2048 
2049       (*win->button_pressed)(win, &event->xbutton, win->click_num);
2050     }
2051 
2052     if (win->event_mask & ButtonReleaseMask) {
2053       /*
2054        * if ButtonReleaseMask is not set and ui_window_t doesn't receive
2055        * ButtonRelease event , button_is_pressing flag must never be set ,
2056        * since once it is set , it will never unset.
2057        */
2058       win->button_is_pressing = 1;
2059       win->prev_button_press_event = event->xbutton;
2060     }
2061 
2062     /* XXX Note that win->is_focused is always true on override redirect mode.
2063      */
2064     if (!win->is_focused && win->inputtable && event->xbutton.button == Button1 &&
2065         !event->xbutton.state) {
2066       ui_window_set_input_focus(win);
2067     }
2068   } else if (event->type == NoExpose) {
2069     win->wait_copy_area_response = 0;
2070   } else if (event->type == Expose || event->type == GraphicsExpose) {
2071     XEvent next_ev;
2072     int x;
2073     int y;
2074     u_int width;
2075     u_int height;
2076     int margin_area_exposed;
2077 #ifdef __DEBUG
2078     int nskip = 0;
2079 #endif
2080 
2081     /* Optimize redrawing. */
2082     while (XCheckTypedWindowEvent(win->disp->display, win->my_window, event->type, &next_ev)) {
2083       XEvent ev;
2084       int diff;
2085 
2086       ev = *event;
2087 
2088 #ifdef __DEBUG
2089       bl_debug_printf(BL_DEBUG_TAG " x %d y %d w %d h %d + x %d y %d w %d h %d ->", ev.xexpose.x,
2090                       ev.xexpose.y, ev.xexpose.width, ev.xexpose.height, next_ev.xexpose.x,
2091                       next_ev.xexpose.y, next_ev.xexpose.width, next_ev.xexpose.height);
2092 #endif
2093 
2094       if ((diff = ev.xexpose.x - next_ev.xexpose.x) > 0) {
2095         ev.xexpose.width += diff;
2096         ev.xexpose.x = next_ev.xexpose.x;
2097       }
2098 
2099       if ((diff = next_ev.xexpose.x + next_ev.xexpose.width - ev.xexpose.x - ev.xexpose.width) >
2100           0) {
2101         ev.xexpose.width += diff;
2102       }
2103 
2104       if ((diff = ev.xexpose.y - next_ev.xexpose.y) > 0) {
2105         ev.xexpose.height += diff;
2106         ev.xexpose.y = next_ev.xexpose.y;
2107       }
2108 
2109       if ((diff = next_ev.xexpose.y + next_ev.xexpose.height - ev.xexpose.y - ev.xexpose.height) >
2110           0) {
2111         ev.xexpose.height += diff;
2112       }
2113 
2114 #ifdef __DEBUG
2115       bl_msg_printf(" x %d y %d w %d h %d\n", ev.xexpose.x, ev.xexpose.y, ev.xexpose.width,
2116                     ev.xexpose.height);
2117 #endif
2118 
2119       /* Minimum character size is regarded as w5 ui.h10. */
2120       if ((ev.xexpose.width * ev.xexpose.height) / 4 >=
2121           (BL_MAX(event->xexpose.width, 5) * BL_MAX(event->xexpose.height, 10) +
2122            BL_MAX(next_ev.xexpose.width, 5) * BL_MAX(next_ev.xexpose.height, 10)) /
2123               3) {
2124 /* Redrawing area is increased over 33.3% by this combination. */
2125 
2126 #ifdef __DEBUG
2127         bl_msg_printf(
2128             "=> Discard combination of XExposeEvents "
2129             "because of inefficiency.\n");
2130 #endif
2131 
2132         XPutBackEvent(win->disp->display, &next_ev);
2133 
2134         break;
2135       } else {
2136 #ifdef __DEBUG
2137         nskip++;
2138 #endif
2139 
2140         *event = ev;
2141       }
2142     }
2143 
2144 #ifdef __DEBUG
2145     bl_debug_printf(BL_DEBUG_TAG " skipped %d expose events.\n", nskip);
2146 #endif
2147 
2148     margin_area_exposed = 0;
2149 
2150     if (event->xexpose.x < win->hmargin) {
2151       margin_area_exposed = 1;
2152       x = 0;
2153 
2154       if (x + event->xexpose.width > win->width) {
2155         width = win->width;
2156       } else if (event->xexpose.width < (win->hmargin - event->xexpose.x)) {
2157         width = 0;
2158       } else {
2159         width = event->xexpose.width - (win->hmargin - event->xexpose.x);
2160       }
2161     } else {
2162       x = event->xexpose.x - win->hmargin;
2163 
2164       if (x + event->xexpose.width > win->width) {
2165         margin_area_exposed = 1;
2166         width = win->width - x;
2167       } else {
2168         width = event->xexpose.width;
2169       }
2170     }
2171 
2172     if (event->xexpose.y < win->vmargin) {
2173       margin_area_exposed = 1;
2174       y = 0;
2175 
2176       if (y + event->xexpose.height > win->height) {
2177         height = win->height;
2178       } else if (event->xexpose.height < (win->vmargin - event->xexpose.y)) {
2179         height = 0;
2180       } else {
2181         height = event->xexpose.height - (win->vmargin - event->xexpose.y);
2182       }
2183     } else {
2184       y = event->xexpose.y - win->vmargin;
2185 
2186       if (y + event->xexpose.height > win->height) {
2187         margin_area_exposed = 1;
2188         height = win->height - y;
2189       } else {
2190         height = event->xexpose.height;
2191       }
2192     }
2193 
2194     /*
2195      * It is desirable to set win->is_scrollable = 0 before calling
2196      * window_exposed event for GraphicsExpose event, because
2197      * GraphicsExpose event itself is caused by scrolling (XCopyArea).
2198      *
2199      * XXX
2200      * But win->is_scrollable = 0 is disabled for now because there
2201      * seems no cases which cause definite inconvenience.
2202      * (ref. flush_scroll_cache() in ui_screen.c)
2203      */
2204     if (event->type == GraphicsExpose) {
2205       win->wait_copy_area_response = 0;
2206 #if 0
2207       win->is_scrollable = 0;
2208 #endif
2209     }
2210 
2211     if (margin_area_exposed) {
2212       clear_margin_area(win);
2213     }
2214 
2215     if (win->window_exposed) {
2216       (*win->window_exposed)(win, x, y, width, height);
2217     }
2218 #if 0
2219     else {
2220       ui_window_clear_all(win);
2221     }
2222 #endif
2223 
2224 #if 0
2225     if (event->type == GraphicsExpose) {
2226       win->is_scrollable = 1;
2227     }
2228 #endif
2229   } else if (event->type == ConfigureNotify) {
2230     int is_changed;
2231     XEvent next_ev;
2232 
2233     /*
2234      * Optimize transparent processing in notify_configure_to_children.
2235      */
2236     while (XCheckTypedWindowEvent(win->disp->display, win->my_window, ConfigureNotify, &next_ev)) {
2237       *event = next_ev;
2238     }
2239 
2240     is_changed = 0;
2241 
2242     if (event->xconfigure.x != win->x || event->xconfigure.y != win->y) {
2243       /*
2244        * for fvwm2 style virtual screen.
2245        */
2246       if (abs(event->xconfigure.x - win->x) % win->disp->width != 0 ||
2247           abs(event->xconfigure.y - win->y) % win->disp->height != 0 ||
2248           (event->xconfigure.x < 0 && event->xconfigure.x + (int)ACTUAL_WIDTH(win) > 0) ||
2249           (event->xconfigure.x > 0 &&
2250            event->xconfigure.x + (int)ACTUAL_WIDTH(win) > (int)win->disp->width) ||
2251           (event->xconfigure.y < 0 && event->xconfigure.y + (int)ACTUAL_HEIGHT(win) > 0) ||
2252           (event->xconfigure.y > 0 &&
2253            event->xconfigure.y + (int)ACTUAL_HEIGHT(win) > (int)win->disp->height)) {
2254         is_changed = 1;
2255       }
2256 
2257       win->x = event->xconfigure.x;
2258       win->y = event->xconfigure.y;
2259     }
2260 
2261     if (event->xconfigure.width != ACTUAL_WIDTH(win) ||
2262         event->xconfigure.height != ACTUAL_HEIGHT(win)) {
2263       win->width = event->xconfigure.width - win->hmargin * 2;
2264       win->height = event->xconfigure.height - win->vmargin * 2;
2265 
2266       if (win->window_resized) {
2267         win->configure_root = 1;
2268         (*win->window_resized)(win);
2269         win->configure_root = 0;
2270       }
2271 
2272       is_changed = 1;
2273 
2274 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_CAIRO)
2275       if (win->cairo_draw) {
2276         cairo_resize(win);
2277       }
2278 #endif
2279     }
2280 
2281     if (is_changed) {
2282       notify_configure_to_children(win);
2283     }
2284   } else if (event->type == ReparentNotify) {
2285     XEvent next_ev;
2286 
2287     /*
2288      * Optimize transparent processing in notify_reparent_to_children.
2289      */
2290     while (XCheckTypedWindowEvent(win->disp->display, win->my_window, ReparentNotify, &next_ev)) {
2291       *event = next_ev;
2292     }
2293 
2294     win->x = event->xreparent.x;
2295     win->y = event->xreparent.y;
2296 
2297     notify_reparent_to_children(win);
2298   }
2299 #if 0
2300   else if (event->type == MapNotify) {
2301     if (win->is_transparent && !win->wall_picture_is_set) {
2302       set_transparent(win);
2303     }
2304   }
2305 #endif
2306   else if (event->type == SelectionClear) {
2307     /* Call win->selection_cleared in ui_display_clear_selection. */
2308     ui_display_clear_selection(win->disp, win);
2309 
2310     free(sel_bmp);
2311     sel_bmp = NULL;
2312   } else if (event->type == SelectionRequest) {
2313     Atom xa_utf8_string;
2314     Atom xa_compound_text;
2315 #ifdef DEBUG
2316     Atom xa_multiple;
2317 #endif
2318     Atom xa_targets;
2319     Atom xa_text;
2320     Atom xa_bmp;
2321 
2322     xa_compound_text = XA_COMPOUND_TEXT(win->disp->display);
2323     xa_targets = XA_TARGETS(win->disp->display);
2324 #ifdef DEBUG
2325     xa_multiple = XA_MULTIPLE(win->disp->display);
2326 #endif
2327     xa_text = XA_TEXT(win->disp->display);
2328     xa_utf8_string = XA_UTF8_STRING(win->disp->display);
2329     xa_bmp = XA_BMP(win->disp->display);
2330 
2331     if (event->xselectionrequest.target == XA_STRING) {
2332       if (win->xct_selection_requested) {
2333         (*win->xct_selection_requested)(win, &event->xselectionrequest,
2334                                         event->xselectionrequest.target);
2335       }
2336     } else if (event->xselectionrequest.target == xa_text ||
2337                event->xselectionrequest.target == xa_compound_text) {
2338       if (win->xct_selection_requested) {
2339         /*
2340          * kterm requests selection with "TEXT" atom , but
2341          * wants it to be sent back with "COMPOUND_TEXT" atom.
2342          * why ?
2343          */
2344 
2345         (*win->xct_selection_requested)(win, &event->xselectionrequest, xa_compound_text);
2346       }
2347     } else if (event->xselectionrequest.target == xa_utf8_string) {
2348       if (win->utf_selection_requested) {
2349         (*win->utf_selection_requested)(win, &event->xselectionrequest, xa_utf8_string);
2350       }
2351     } else if (event->xselectionrequest.target == xa_targets) {
2352       Atom targets[6];
2353 
2354       targets[0] = xa_targets;
2355       targets[1] = XA_STRING;
2356       targets[2] = xa_text;
2357       targets[3] = xa_compound_text;
2358       targets[4] = xa_utf8_string;
2359       targets[5] = xa_bmp;
2360 
2361       send_selection(win, &event->xselectionrequest, (u_char *)targets,
2362                      sizeof(targets) / sizeof targets[0], XA_ATOM, 32);
2363     }
2364 #ifdef DEBUG
2365     else if (event->xselectionrequest.target == xa_multiple) {
2366       bl_debug_printf("MULTIPLE requested(not yet implemented)\n");
2367     }
2368 #endif
2369     else if (event->xselectionrequest.target == xa_bmp && sel_bmp) {
2370       send_selection(win, &event->xselectionrequest, (u_char *)sel_bmp, sel_bmp_size, xa_bmp, 8);
2371     } else {
2372       send_selection(win, &event->xselectionrequest, NULL, 0, 0, 0);
2373     }
2374   } else if (event->type == SelectionNotify) {
2375     Atom xa_utf8_string;
2376     Atom xa_compound_text;
2377     Atom xa_text;
2378     Atom xa_selection;
2379 
2380     xa_compound_text = XA_COMPOUND_TEXT(win->disp->display);
2381     xa_text = XA_TEXT(win->disp->display);
2382     xa_utf8_string = XA_UTF8_STRING(win->disp->display);
2383     xa_selection = XA_SELECTION(win->disp->display);
2384 
2385     if (event->xselection.property == None ||
2386         event->xselection.property == XA_NONE(win->disp->display)) {
2387       /*
2388        * Selection request failed.
2389        * Retrying with xa_compound_text => xa_text => XA_STRING
2390        */
2391 
2392       if (event->xselection.target == xa_utf8_string) {
2393         XConvertSelection(win->disp->display, XA_PRIMARY, xa_compound_text, xa_selection,
2394                           win->my_window, CurrentTime);
2395       } else if (event->xselection.target == xa_compound_text) {
2396         XConvertSelection(win->disp->display, XA_PRIMARY, xa_text, xa_selection, win->my_window,
2397                           CurrentTime);
2398       } else if (event->xselection.target == xa_text) {
2399         XConvertSelection(win->disp->display, XA_PRIMARY, XA_STRING, xa_selection, win->my_window,
2400                           CurrentTime);
2401       }
2402 
2403       return 1;
2404     }
2405 
2406     /* SELECTION */
2407     if (event->xselection.selection == XA_PRIMARY &&
2408         (event->xselection.property == xa_selection &&
2409          (event->xselection.target == XA_STRING || event->xselection.target == xa_text ||
2410           event->xselection.target == xa_compound_text ||
2411           event->xselection.target == xa_utf8_string))) {
2412       u_long bytes_after;
2413       XTextProperty ct;
2414       int seg;
2415 
2416       for (seg = 0;; seg += ct.nitems) {
2417         /*
2418          * XXX
2419          * long_offset and long_len is the same as rxvt-2.6.3 ,
2420          * but I'm not confident if this is OK.
2421          */
2422         if (XGetWindowProperty(win->disp->display, event->xselection.requestor,
2423                                event->xselection.property, seg / 4, 4096, False, AnyPropertyType,
2424                                &ct.encoding, &ct.format, &ct.nitems, &bytes_after,
2425                                &ct.value) != Success) {
2426           break;
2427         }
2428 
2429         if (ct.value == NULL || ct.nitems == 0) {
2430           break;
2431         }
2432 
2433         if (ct.encoding == XA_STRING || ct.encoding == xa_text || ct.encoding == xa_compound_text) {
2434           if (win->xct_selection_notified) {
2435             (*win->xct_selection_notified)(win, ct.value, ct.nitems);
2436           }
2437         } else if (ct.encoding == xa_utf8_string) {
2438           if (win->utf_selection_notified) {
2439             (*win->utf_selection_notified)(win, ct.value, ct.nitems);
2440           }
2441         }
2442 
2443         XFree(ct.value);
2444 
2445         if (bytes_after == 0) {
2446           break;
2447         }
2448       }
2449     }
2450 
2451     XDeleteProperty(win->disp->display, event->xselection.requestor, event->xselection.property);
2452   } else if (event->type == ClientMessage) {
2453     if (event->xclient.format == 32 &&
2454         event->xclient.data.l[0] == XA_DELETE_WINDOW(win->disp->display)) {
2455 #ifdef DEBUG
2456       bl_warn_printf(BL_DEBUG_TAG " DeleteWindow message is received. exiting...\n");
2457 #endif
2458       if (win->window_destroyed) {
2459         (*win->window_destroyed)(win);
2460       } else {
2461         exit(0);
2462       }
2463     }
2464 #if 0
2465     else if (event->xclient.format == 32 &&
2466              event->xclient.data.l[0] == XA_TAKE_FOCUS(win->disp->display)) {
2467       bl_warn_printf(BL_DEBUG_TAG " TakeFocus message is received.\n");
2468     }
2469 #endif
2470   } else if (event->type == PropertyNotify) {
2471     if (event->xproperty.atom == XA_SELECTION(win->disp->display) &&
2472         event->xproperty.state == PropertyNewValue) {
2473       XTextProperty ct;
2474       u_long bytes_after;
2475 
2476       XGetWindowProperty(win->disp->display, event->xproperty.window, event->xproperty.atom, 0, 0,
2477                          False, AnyPropertyType, &ct.encoding, &ct.format, &ct.nitems, &bytes_after,
2478                          &ct.value);
2479       if (ct.value) {
2480         XFree(ct.value);
2481       }
2482 
2483       if (ct.encoding == XA_INCR(win->disp->display) || bytes_after == 0) {
2484         XDeleteProperty(win->disp->display, event->xproperty.window, ct.encoding);
2485       } else {
2486         XGetWindowProperty(win->disp->display, event->xproperty.window, event->xproperty.atom, 0,
2487                            bytes_after, True, AnyPropertyType, &ct.encoding, &ct.format, &ct.nitems,
2488                            &bytes_after, &ct.value);
2489         if (ct.encoding == XA_STRING || ct.encoding == XA_TEXT(win->disp->display) ||
2490             ct.encoding == XA_COMPOUND_TEXT(win->disp->display)) {
2491           if (win->xct_selection_notified) {
2492             (*win->xct_selection_notified)(win, ct.value, ct.nitems);
2493           }
2494         } else if (ct.encoding == XA_UTF8_STRING(win->disp->display)) {
2495           if (win->utf_selection_notified) {
2496             (*win->utf_selection_notified)(win, ct.value, ct.nitems);
2497           }
2498         }
2499 
2500         if (ct.value) {
2501           XFree(ct.value);
2502         }
2503       }
2504     }
2505   }
2506 #ifdef __DEBUG
2507   else {
2508     bl_warn_printf(BL_DEBUG_TAG " event %d is received, but not processed.\n", event->type);
2509   }
2510 #endif
2511 
2512   return 1;
2513 }
2514 
ui_window_get_str(ui_window_t * win,u_char * seq,size_t seq_len,ef_parser_t ** parser,KeySym * keysym,XKeyEvent * event)2515 size_t ui_window_get_str(ui_window_t *win, u_char *seq, size_t seq_len, ef_parser_t **parser,
2516                          KeySym *keysym, XKeyEvent *event) {
2517   size_t len;
2518 
2519   *keysym = 0;
2520 
2521   if ((len = ui_xic_get_str(win, seq, seq_len, parser, keysym, event)) > 0) {
2522     return len;
2523   }
2524 
2525   if ((len = XLookupString(event, seq, seq_len, keysym, NULL)) > 0) {
2526     *parser = NULL;
2527 
2528     return len;
2529   }
2530 
2531   if ((len = ui_xic_get_utf8_str(win, seq, seq_len, parser, keysym, event)) > 0) {
2532     return len;
2533   }
2534 
2535   return 0;
2536 }
2537 
2538 /*
2539  * Scroll functions.
2540  * The caller side should clear the scrolled area.
2541  */
2542 
ui_window_scroll_upward(ui_window_t * win,u_int height)2543 int ui_window_scroll_upward(ui_window_t *win, u_int height) {
2544   return ui_window_scroll_upward_region(win, 0, win->height, height);
2545 }
2546 
ui_window_scroll_upward_region(ui_window_t * win,int boundary_start,int boundary_end,u_int height)2547 int ui_window_scroll_upward_region(ui_window_t *win, int boundary_start, int boundary_end,
2548                                    u_int height) {
2549   if (!win->is_scrollable) {
2550     return 0;
2551   }
2552 
2553   if (boundary_start < 0 || boundary_end > win->height || boundary_end <= boundary_start + height) {
2554 #ifdef DEBUG
2555     bl_warn_printf(BL_DEBUG_TAG " boundary start %d end %d height %d in window((h) %d (w) %d)\n",
2556                    boundary_start, boundary_end, height, win->height, win->width);
2557 #endif
2558 
2559     return 0;
2560   }
2561 
2562   scroll_region(win, 0, boundary_start + height,                    /* src */
2563                 win->width, boundary_end - boundary_start - height, /* size */
2564                 0, boundary_start);                                 /* dst */
2565 
2566   return 1;
2567 }
2568 
ui_window_scroll_downward(ui_window_t * win,u_int height)2569 int ui_window_scroll_downward(ui_window_t *win, u_int height) {
2570   return ui_window_scroll_downward_region(win, 0, win->height, height);
2571 }
2572 
ui_window_scroll_downward_region(ui_window_t * win,int boundary_start,int boundary_end,u_int height)2573 int ui_window_scroll_downward_region(ui_window_t *win, int boundary_start, int boundary_end,
2574                                      u_int height) {
2575   if (!win->is_scrollable) {
2576     return 0;
2577   }
2578 
2579   if (boundary_start < 0 || boundary_end > win->height || boundary_end <= boundary_start + height) {
2580 #ifdef DEBUG
2581     bl_warn_printf(BL_DEBUG_TAG " boundary start %d end %d height %d\n", boundary_start,
2582                    boundary_end, height);
2583 #endif
2584 
2585     return 0;
2586   }
2587 
2588   scroll_region(win, 0, boundary_start, win->width, boundary_end - boundary_start - height, 0,
2589                 boundary_start + height);
2590 
2591   return 1;
2592 }
2593 
ui_window_scroll_leftward(ui_window_t * win,u_int width)2594 int ui_window_scroll_leftward(ui_window_t *win, u_int width) {
2595   return ui_window_scroll_leftward_region(win, 0, win->width, width);
2596 }
2597 
ui_window_scroll_leftward_region(ui_window_t * win,int boundary_start,int boundary_end,u_int width)2598 int ui_window_scroll_leftward_region(ui_window_t *win, int boundary_start, int boundary_end,
2599                                      u_int width) {
2600   if (!win->is_scrollable) {
2601     return 0;
2602   }
2603 
2604   if (boundary_start < 0 || boundary_end > win->width || boundary_end <= boundary_start + width) {
2605 #ifdef DEBUG
2606     bl_warn_printf(BL_DEBUG_TAG " boundary start %d end %d width %d in window((h) %d (w) %d)\n",
2607                    boundary_start, boundary_end, width, win->height, win->width);
2608 #endif
2609 
2610     return 0;
2611   }
2612 
2613   scroll_region(win, boundary_start + width, 0,                     /* src */
2614                 boundary_end - boundary_start - width, win->height, /* size */
2615                 boundary_start, 0);                                 /* dst */
2616 
2617   return 1;
2618 }
2619 
ui_window_scroll_rightward(ui_window_t * win,u_int width)2620 int ui_window_scroll_rightward(ui_window_t *win, u_int width) {
2621   return ui_window_scroll_rightward_region(win, 0, win->width, width);
2622 }
2623 
ui_window_scroll_rightward_region(ui_window_t * win,int boundary_start,int boundary_end,u_int width)2624 int ui_window_scroll_rightward_region(ui_window_t *win, int boundary_start, int boundary_end,
2625                                       u_int width) {
2626   if (!win->is_scrollable) {
2627     return 0;
2628   }
2629 
2630   if (boundary_start < 0 || boundary_end > win->width || boundary_end <= boundary_start + width) {
2631 #ifdef DEBUG
2632     bl_warn_printf(BL_DEBUG_TAG " boundary start %d end %d width %d\n", boundary_start,
2633                    boundary_end, width);
2634 #endif
2635 
2636     return 0;
2637   }
2638 
2639   scroll_region(win, boundary_start, 0, boundary_end - boundary_start - width, win->height,
2640                 boundary_start + width, 0);
2641 
2642   return 1;
2643 }
2644 
ui_window_copy_area(ui_window_t * win,Pixmap src,PixmapMask mask,int src_x,int src_y,u_int width,u_int height,int dst_x,int dst_y)2645 int ui_window_copy_area(ui_window_t *win, Pixmap src, PixmapMask mask, int src_x, /* >= 0 */
2646                         int src_y,                                                /* >= 0 */
2647                         u_int width, u_int height, int dst_x,                     /* >= 0 */
2648                         int dst_y                                                 /* >= 0 */
2649                         ) {
2650   if (dst_x >= win->width || dst_y >= win->height) {
2651     return 0;
2652   }
2653 
2654   if (dst_x + width > win->width) {
2655     width = win->width - dst_x;
2656   }
2657 
2658   if (dst_y + height > win->height) {
2659     height = win->height - dst_y;
2660   }
2661 
2662   if (win->gc->mask != mask) {
2663     XSetClipMask(win->disp->display, win->gc->gc, mask);
2664     win->gc->mask = mask;
2665   }
2666 
2667   if (mask) {
2668     XSetClipOrigin(win->disp->display, win->gc->gc, dst_x + win->hmargin - src_x,
2669                    dst_y + win->vmargin - src_y);
2670   }
2671 
2672   XCopyArea(win->disp->display, src, win->my_window, win->gc->gc, src_x, src_y, width, height,
2673             dst_x + win->hmargin, dst_y + win->vmargin);
2674 
2675   return 1;
2676 }
2677 
ui_window_set_clip(ui_window_t * win,int x,int y,u_int width,u_int height)2678 void ui_window_set_clip(ui_window_t *win, int x, int y, u_int width, u_int height) {
2679 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_CAIRO)
2680   if (win->cairo_draw) {
2681     cairo_set_clip(win, x + win->hmargin, y + win->vmargin, width, height);
2682   } else
2683 #endif
2684 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XFT)
2685       if (win->xft_draw) {
2686     xft_set_clip(win, x + win->hmargin, y + win->vmargin, width, height);
2687   } else
2688 #endif
2689   {
2690     XRectangle rect;
2691 
2692     rect.x = 0;
2693     rect.y = 0;
2694     rect.width = width;
2695     rect.height = height;
2696 
2697     XSetClipRectangles(win->disp->display, win->gc->gc, x + win->hmargin, y + win->vmargin, &rect,
2698                        1, YSorted);
2699   }
2700 }
2701 
ui_window_unset_clip(ui_window_t * win)2702 void ui_window_unset_clip(ui_window_t *win) {
2703 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_CAIRO)
2704   if (win->cairo_draw) {
2705     cairo_unset_clip(win);
2706   } else
2707 #endif
2708 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XFT)
2709       if (win->xft_draw) {
2710     xft_unset_clip(win);
2711   } else
2712 #endif
2713   {
2714     XSetClipMask(win->disp->display, win->gc->gc, None);
2715   }
2716 }
2717 
ui_window_draw_decsp_string(ui_window_t * win,ui_font_t * font,ui_color_t * fg_color,int x,int y,u_char * str,u_int len)2718 void ui_window_draw_decsp_string(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color, int x,
2719                                  int y, u_char *str, u_int len) {
2720   convert_to_decsp_font_index(str, len);
2721 
2722   if (font->decsp_font) {
2723     ui_gc_set_fg_color(win->gc, fg_color->pixel);
2724 
2725     ui_decsp_font_draw_string(font->decsp_font, win->disp->display, win->my_window,
2726                               win->gc->gc, x + win->hmargin, y + win->vmargin, str, len);
2727   }
2728 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XCORE)
2729   else if (font->xfont) {
2730     ui_window_draw_string(win, font, fg_color, x, y, str, len);
2731   }
2732 #endif
2733 }
2734 
ui_window_draw_decsp_image_string(ui_window_t * win,ui_font_t * font,ui_color_t * fg_color,ui_color_t * bg_color,int x,int y,u_char * str,u_int len)2735 void ui_window_draw_decsp_image_string(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color,
2736                                        ui_color_t *bg_color, int x, int y, u_char *str, u_int len) {
2737   convert_to_decsp_font_index(str, len);
2738 
2739   if (font->decsp_font) {
2740     ui_gc_set_fg_color(win->gc, fg_color->pixel);
2741     ui_gc_set_bg_color(win->gc, bg_color->pixel);
2742 
2743     ui_decsp_font_draw_image_string(font->decsp_font, win->disp->display, win->my_window,
2744                                     win->gc->gc, x + win->hmargin, y + win->vmargin, str, len);
2745   }
2746 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XCORE)
2747   else if (font->xfont) {
2748     ui_window_draw_image_string(win, font, fg_color, bg_color, x, y, str, len);
2749   }
2750 #endif
2751 }
2752 
2753 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XCORE)
ui_window_draw_string(ui_window_t * win,ui_font_t * font,ui_color_t * fg_color,int x,int y,u_char * str,u_int len)2754 void ui_window_draw_string(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color, int x, int y,
2755                            u_char *str, u_int len) {
2756   /*
2757    * Removing trailing spaces.
2758    *
2759    * XXX Ignore USE_OT_LAYOUT because OpenTyep layout never works on xcore.
2760    */
2761   while (1) {
2762     if (len == 0) {
2763       return;
2764     }
2765 
2766     if (*(str + len - 1) == ' ') {
2767       len--;
2768     } else {
2769       break;
2770     }
2771   }
2772 
2773   ui_gc_set_fid(win->gc, font->xfont->fid);
2774   ui_gc_set_fg_color(win->gc, fg_color->pixel);
2775 
2776   XDrawString(win->disp->display, win->my_window, win->gc->gc, x + font->x_off + win->hmargin,
2777               y + win->vmargin, (char *)str, len);
2778 
2779   if (font->double_draw_gap) {
2780     XDrawString(win->disp->display, win->my_window, win->gc->gc,
2781                 x + font->x_off + win->hmargin + font->double_draw_gap, y + win->vmargin,
2782                 (char *)str, len);
2783   }
2784 }
2785 
ui_window_draw_string16(ui_window_t * win,ui_font_t * font,ui_color_t * fg_color,int x,int y,XChar2b * str,u_int len)2786 void ui_window_draw_string16(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color, int x, int y,
2787                              XChar2b *str, u_int len) {
2788   ui_gc_set_fid(win->gc, font->xfont->fid);
2789   ui_gc_set_fg_color(win->gc, fg_color->pixel);
2790 
2791   XDrawString16(win->disp->display, win->my_window, win->gc->gc, x + font->x_off + win->hmargin,
2792                 y + win->vmargin, str, len);
2793 
2794   if (font->double_draw_gap) {
2795     XDrawString16(win->disp->display, win->my_window, win->gc->gc,
2796                   x + font->x_off + win->hmargin + font->double_draw_gap, y + win->vmargin, str,
2797                   len);
2798   }
2799 }
2800 
ui_window_draw_image_string(ui_window_t * win,ui_font_t * font,ui_color_t * fg_color,ui_color_t * bg_color,int x,int y,u_char * str,u_int len)2801 void ui_window_draw_image_string(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color,
2802                                  ui_color_t *bg_color, int x, int y, u_char *str, u_int len) {
2803   ui_gc_set_fid(win->gc, font->xfont->fid);
2804   ui_gc_set_fg_color(win->gc, fg_color->pixel);
2805   ui_gc_set_bg_color(win->gc, bg_color->pixel);
2806 
2807   XDrawImageString(win->disp->display, win->my_window, win->gc->gc, x + font->x_off + win->hmargin,
2808                    y + win->vmargin, (char *)str, len);
2809 
2810   if (font->double_draw_gap) {
2811     XDrawString(win->disp->display, win->my_window, win->gc->gc,
2812                 x + font->x_off + win->hmargin + font->double_draw_gap, y + win->vmargin,
2813                 (char *)str, len);
2814   }
2815 }
2816 
ui_window_draw_image_string16(ui_window_t * win,ui_font_t * font,ui_color_t * fg_color,ui_color_t * bg_color,int x,int y,XChar2b * str,u_int len)2817 void ui_window_draw_image_string16(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color,
2818                                    ui_color_t *bg_color, int x, int y, XChar2b *str, u_int len) {
2819   ui_gc_set_fid(win->gc, font->xfont->fid);
2820   ui_gc_set_fg_color(win->gc, fg_color->pixel);
2821   ui_gc_set_bg_color(win->gc, bg_color->pixel);
2822 
2823   XDrawImageString16(win->disp->display, win->my_window, win->gc->gc,
2824                      x + font->x_off + win->hmargin, y + win->vmargin, str, len);
2825 
2826   if (font->double_draw_gap) {
2827     XDrawString16(win->disp->display, win->my_window, win->gc->gc,
2828                   x + font->x_off + win->hmargin + font->double_draw_gap, y + win->vmargin, str,
2829                   len);
2830   }
2831 }
2832 #endif
2833 
2834 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XFT) || defined(USE_TYPE_CAIRO)
ui_window_ft_draw_string8(ui_window_t * win,ui_font_t * font,ui_color_t * fg_color,int x,int y,u_char * str,size_t len)2835 void ui_window_ft_draw_string8(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color, int x,
2836                                int y, u_char *str, size_t len) {
2837 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_CAIRO)
2838   if (win->cairo_draw) {
2839     ui_window_cairo_draw_string8(win, font, fg_color, x, y, str, len);
2840 
2841     return;
2842   }
2843 #endif
2844 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XFT)
2845   if (win->xft_draw) {
2846     ui_window_xft_draw_string8(win, font, fg_color, x, y, str, len);
2847 
2848     return;
2849   }
2850 #endif
2851 }
2852 
ui_window_ft_draw_string32(ui_window_t * win,ui_font_t * font,ui_color_t * fg_color,int x,int y,u_int32_t * str,u_int len)2853 void ui_window_ft_draw_string32(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color, int x,
2854                                 int y, /* FcChar32 */ u_int32_t *str, u_int len) {
2855 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_CAIRO)
2856   if (win->cairo_draw) {
2857     ui_window_cairo_draw_string32(win, font, fg_color, x, y, str, len);
2858 
2859     return;
2860   }
2861 #endif
2862 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XFT)
2863   if (win->xft_draw) {
2864     ui_window_xft_draw_string32(win, font, fg_color, x, y, str, len);
2865 
2866     return;
2867   }
2868 #endif
2869 }
2870 
2871 #endif
2872 
ui_window_draw_rect_frame(ui_window_t * win,int x1,int y1,int x2,int y2)2873 void ui_window_draw_rect_frame(ui_window_t *win, int x1, int y1, int x2, int y2) {
2874   XPoint points[5] = {
2875       {x1 += win->hmargin, y1 += win->vmargin},
2876       {x1, y2 += win->vmargin},
2877       {x2 += win->hmargin, y2},
2878       {x2, y1},
2879       {x1, y1},
2880   };
2881 
2882   restore_fg_color(win);
2883 
2884   XDrawLines(win->disp->display, win->my_window, win->gc->gc, points, 5, CoordModeOrigin);
2885 }
2886 
ui_set_use_clipboard_selection(int use_it)2887 void ui_set_use_clipboard_selection(int use_it) {
2888   if (use_clipboard == use_it) {
2889     return;
2890   }
2891 
2892   use_clipboard = use_it;
2893 
2894   /*
2895    * disp->selection_owner is reset.
2896    * If it isn't reset and value of 'use_clipboard' option is changed from false
2897    * to true dynamically, ui_window_set_selection_owner() returns before calling
2898    * XSetSelectionOwner().
2899    */
2900   ui_display_clear_selection(NULL, NULL);
2901 }
2902 
ui_is_using_clipboard_selection(void)2903 int ui_is_using_clipboard_selection(void) { return use_clipboard; }
2904 
ui_window_set_selection_owner(ui_window_t * win,Time time)2905 int ui_window_set_selection_owner(ui_window_t *win, Time time) {
2906   if (ui_window_is_selection_owner(win)) {
2907     /* Already owner */
2908 
2909     return 1;
2910   }
2911 
2912   XSetSelectionOwner(win->disp->display, XA_PRIMARY, win->my_window, time);
2913   if (use_clipboard) {
2914     XSetSelectionOwner(win->disp->display, XA_CLIPBOARD(win->disp->display), win->my_window, time);
2915   }
2916 
2917 #ifdef DEBUG
2918   bl_debug_printf(BL_DEBUG_TAG " XA_PRIMARY => %lu, XA_CLIPBOARD => %lu (mywin %lu)\n",
2919                   XGetSelectionOwner(win->disp->display, XA_PRIMARY),
2920                   XGetSelectionOwner(win->disp->display, XA_CLIPBOARD(win->disp->display)),
2921                   win->my_window);
2922 #endif
2923 
2924   if (win->my_window != XGetSelectionOwner(win->disp->display, XA_PRIMARY) &&
2925       (!use_clipboard ||
2926        win->my_window !=
2927            XGetSelectionOwner(win->disp->display, XA_CLIPBOARD(win->disp->display)))) {
2928     return 0;
2929   } else {
2930     return ui_display_own_selection(win->disp, win);
2931   }
2932 }
2933 
ui_window_xct_selection_request(ui_window_t * win,Time time)2934 int ui_window_xct_selection_request(ui_window_t *win, Time time) {
2935   XConvertSelection(win->disp->display, XA_PRIMARY, XA_COMPOUND_TEXT(win->disp->display),
2936                     XA_SELECTION(win->disp->display), win->my_window, time);
2937 
2938   return 1;
2939 }
2940 
ui_window_utf_selection_request(ui_window_t * win,Time time)2941 int ui_window_utf_selection_request(ui_window_t *win, Time time) {
2942   XConvertSelection(win->disp->display, XA_PRIMARY, XA_UTF8_STRING(win->disp->display),
2943                     XA_SELECTION(win->disp->display), win->my_window, time);
2944 
2945   return 1;
2946 }
2947 
ui_window_send_picture_selection(ui_window_t * win,Pixmap pixmap,u_int width,u_int height)2948 void ui_window_send_picture_selection(ui_window_t *win, Pixmap pixmap, u_int width, u_int height) {
2949   XImage *image;
2950 
2951   if (win->disp->visual->class == TrueColor &&
2952       (image = XGetImage(win->disp->display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap))) {
2953     XVisualInfo *vinfo;
2954 
2955     if ((vinfo = ui_display_get_visual_info(win->disp))) {
2956       int shift[3];
2957       u_long mask[3];
2958       size_t image_size;
2959 
2960       shift[0] = right_shift((mask[0] = vinfo->blue_mask));
2961       shift[1] = right_shift((mask[1] = vinfo->green_mask));
2962       shift[2] = right_shift((mask[2] = vinfo->red_mask));
2963 
2964       image_size = width * height * 4;
2965       sel_bmp_size = image_size + 54;
2966 
2967       free(sel_bmp);
2968       if ((sel_bmp = calloc(1, sel_bmp_size))) {
2969         int x;
2970         int y;
2971         u_char *dst;
2972 
2973         sel_bmp->h_type[0] = 0x42;
2974         sel_bmp->h_type[1] = 0x4d;
2975         sel_bmp->h_size[0] = sel_bmp_size & 0xff;
2976         sel_bmp->h_size[1] = (sel_bmp_size >> 8) & 0xff;
2977         sel_bmp->h_size[2] = (sel_bmp_size >> 16) & 0xff;
2978         sel_bmp->h_size[3] = (sel_bmp_size >> 24) & 0xff;
2979         sel_bmp->h_offbits[0] = 54;
2980         sel_bmp->i_size[0] = 40;
2981         sel_bmp->i_width[0] = width & 0xff;
2982         sel_bmp->i_width[1] = (width >> 8) & 0xff;
2983         sel_bmp->i_width[2] = (width >> 16) & 0xff;
2984         sel_bmp->i_width[3] = (width >> 24) & 0xff;
2985         sel_bmp->i_height[0] = height & 0xff;
2986         sel_bmp->i_height[1] = (height >> 8) & 0xff;
2987         sel_bmp->i_height[2] = (height >> 16) & 0xff;
2988         sel_bmp->i_height[3] = (height >> 24) & 0xff;
2989         sel_bmp->i_planes[0] = 1;
2990         sel_bmp->i_bitcount[0] = 32;
2991         sel_bmp->i_sizeimage[0] = image_size & 0xff;
2992         sel_bmp->i_sizeimage[1] = (image_size >> 8) & 0xff;
2993         sel_bmp->i_sizeimage[2] = (image_size >> 16) & 0xff;
2994         sel_bmp->i_sizeimage[3] = (image_size >> 24) & 0xff;
2995 
2996         dst = sel_bmp->data;
2997         for (y = height - 1; y >= 0; y--) {
2998           for (x = 0; x < width; x++) {
2999             u_long pixel;
3000             int count;
3001 
3002             pixel = XGetPixel(image, x, y);
3003 
3004             for (count = 0; count < 3; count++) {
3005               if (shift[count] < 0) {
3006                 *(dst++) = (pixel & mask[count]) << (-shift[count]);
3007               } else {
3008                 *(dst++) = (pixel & mask[count]) >> (shift[count]);
3009               }
3010             }
3011 
3012             *(dst++) = 0x00;
3013           }
3014         }
3015 
3016         ui_window_set_selection_owner(win, CurrentTime);
3017 
3018         bl_msg_printf("Set a clicked picture to the clipboard.\n");
3019       }
3020 
3021       XFree(vinfo);
3022     }
3023 
3024     XDestroyImage(image);
3025   }
3026 }
3027 
ui_window_send_text_selection(ui_window_t * win,XSelectionRequestEvent * req_ev,u_char * sel_data,size_t sel_len,Atom sel_type)3028 void ui_window_send_text_selection(ui_window_t *win, XSelectionRequestEvent *req_ev,
3029                                    u_char *sel_data, size_t sel_len, Atom sel_type) {
3030   XEvent res_ev;
3031 
3032   res_ev.xselection.type = SelectionNotify;
3033   res_ev.xselection.display = req_ev->display;
3034   res_ev.xselection.requestor = req_ev->requestor;
3035   res_ev.xselection.selection = req_ev->selection;
3036   res_ev.xselection.target = req_ev->target;
3037   res_ev.xselection.time = req_ev->time;
3038 
3039   if (sel_data == NULL) {
3040     res_ev.xselection.property = None;
3041   } else {
3042     if (req_ev->property == None) {
3043       /* An obsolete client may fill None as a property.
3044        * Try to deal with them by using 'target' instead.
3045        */
3046       req_ev->property = req_ev->target;
3047     }
3048     if (req_ev->property != None) {
3049       XChangeProperty(win->disp->display, req_ev->requestor, req_ev->property, sel_type, 8,
3050                       PropModeReplace, sel_data, sel_len);
3051     }
3052     res_ev.xselection.property = req_ev->property;
3053   }
3054 
3055   XSendEvent(win->disp->display, res_ev.xselection.requestor, False, 0, &res_ev);
3056 }
3057 
ui_set_window_name(ui_window_t * win,u_char * name)3058 void ui_set_window_name(ui_window_t *win, u_char *name) {
3059   ui_window_t *root;
3060   XTextProperty prop;
3061 
3062   root = ui_get_root_window(win);
3063 
3064   if (name == NULL) {
3065     name = root->app_name;
3066   }
3067 
3068   if (XmbTextListToTextProperty(root->disp->display, (char **)&name, 1, XStdICCTextStyle, &prop) >=
3069       Success) {
3070     Atom atom;
3071 
3072     XSetWMName(root->disp->display, root->my_window, &prop);
3073     XFree(prop.value);
3074 
3075     if (locale_is_utf8() &&
3076         (atom = XInternAtom(root->disp->display, "_NET_WM_NAME", True)) != None) {
3077       XChangeProperty(root->disp->display, root->my_window, atom,
3078                       XA_UTF8_STRING(root->disp->display), 8, PropModeReplace,
3079                       name, strlen(name));
3080     }
3081 #ifdef DEBUG
3082     else {
3083       bl_debug_printf("_NET_WM_NAME is not set.\n");
3084     }
3085 #endif
3086   } else {
3087     /* XXX which is better , doing this or return 0 without doing anything ? */
3088     XStoreName(root->disp->display, root->my_window, name);
3089   }
3090 }
3091 
ui_set_icon_name(ui_window_t * win,u_char * name)3092 void ui_set_icon_name(ui_window_t *win, u_char *name) {
3093   ui_window_t *root;
3094   XTextProperty prop;
3095 
3096   root = ui_get_root_window(win);
3097 
3098   if (name == NULL) {
3099     name = root->app_name;
3100   }
3101 
3102   if (XmbTextListToTextProperty(root->disp->display, (char **)&name, 1, XStdICCTextStyle, &prop) >=
3103       Success) {
3104     Atom atom;
3105 
3106     XSetWMIconName(root->disp->display, root->my_window, &prop);
3107     XFree(prop.value);
3108 
3109     if (locale_is_utf8() &&
3110        (atom = XInternAtom(root->disp->display, "_NET_ICON_NAME", True)) != None) {
3111       XChangeProperty(root->disp->display, root->my_window, atom,
3112                       XA_UTF8_STRING(root->disp->display), 8, PropModeReplace,
3113                       name, strlen(name));
3114     }
3115 #ifdef DEBUG
3116     else {
3117       bl_debug_printf("_NET_ICON_NAME is not set.\n");
3118     }
3119 #endif
3120   } else {
3121     /* XXX which is better , doing this or return 0 without doing anything ? */
3122     XSetIconName(root->disp->display, root->my_window, name);
3123   }
3124 }
3125 
ui_window_set_icon(ui_window_t * win,ui_icon_picture_t * icon)3126 void ui_window_set_icon(ui_window_t *win, ui_icon_picture_t *icon) {
3127   ui_window_t *root;
3128   XWMHints *hints;
3129 
3130   root = ui_get_root_window(win);
3131 
3132   /* set extended window manager hint's icon */
3133   if (icon->cardinal && icon->cardinal[0] && icon->cardinal[1]) {
3134     int num;
3135     u_long *data;
3136 
3137     /* width * height + 2 */
3138     num = icon->cardinal[0] * icon->cardinal[1] + 2;
3139 
3140     if (sizeof(u_long) != 4) {
3141       int count;
3142 
3143       if (!(data = alloca(sizeof(u_long) * num))) {
3144         return;
3145       }
3146 
3147       for (count = 0; count < num; count++) {
3148         data[count] = icon->cardinal[count];
3149       }
3150     } else {
3151       data = icon->cardinal;
3152     }
3153 
3154     /*it should be possible to set multiple icons...*/
3155     XChangeProperty(root->disp->display, root->my_window, XA_NET_WM_ICON(root->disp->display),
3156                     XA_CARDINAL, 32, PropModeReplace, (u_char *)data, num);
3157   }
3158 
3159   if ((hints = XGetWMHints(root->disp->display, root->my_window)) == NULL &&
3160       (hints = XAllocWMHints()) == NULL) {
3161     return;
3162   }
3163 
3164   if (icon->pixmap) {
3165     hints->flags |= IconPixmapHint;
3166     hints->icon_pixmap = icon->pixmap;
3167   }
3168 
3169   if (icon->mask) {
3170     hints->flags |= IconMaskHint;
3171     hints->icon_mask = icon->mask;
3172   }
3173 
3174   XSetWMHints(root->disp->display, root->my_window, hints);
3175   XFree(hints);
3176 }
3177 
ui_window_remove_icon(ui_window_t * win)3178 void ui_window_remove_icon(ui_window_t *win) {
3179   ui_window_t *root;
3180   XWMHints *hints;
3181 
3182   root = ui_get_root_window(win);
3183 
3184   if ((hints = XGetWMHints(root->disp->display, root->my_window))) {
3185 #if 0
3186     bl_debug_printf(" Removing icon.\n");
3187 #endif
3188 
3189     hints->flags &= ~(IconPixmapHint | IconMaskHint);
3190     hints->icon_pixmap = None;
3191     hints->icon_mask = None;
3192 
3193     XSetWMHints(root->disp->display, root->my_window, hints);
3194     XFree(hints);
3195   }
3196 
3197   XDeleteProperty(root->disp->display, root->my_window, XA_NET_WM_ICON(root->disp->display));
3198 }
3199 
3200 /* for xlib/ui_display.c */
ui_window_reset_group(ui_window_t * win)3201 void ui_window_reset_group(ui_window_t *win) {
3202   ui_window_t *root;
3203   XWMHints *hints;
3204 
3205   root = ui_get_root_window(win);
3206 
3207   if ((hints = XGetWMHints(root->disp->display, root->my_window)) == NULL &&
3208       (hints = XAllocWMHints()) == NULL) {
3209     return;
3210   }
3211 
3212   hints->flags |= WindowGroupHint;
3213   hints->window_group = reset_client_leader(root);
3214 
3215   XSetWMHints(root->disp->display, root->my_window, hints);
3216   XFree(hints);
3217 }
3218 
3219 /* for xlib/ui_imagelib.c */
ui_window_get_visible_geometry(ui_window_t * win,int * x,int * y,int * my_x,int * my_y,u_int * width,u_int * height)3220 int ui_window_get_visible_geometry(ui_window_t *win, int *x, /* x relative to root window */
3221                                    int *y,                   /* y relative to root window */
3222                                    int *my_x,                /* x relative to my window */
3223                                    int *my_y,                /* y relative to my window */
3224                                    u_int *width, u_int *height) {
3225   Window child;
3226 
3227   XTranslateCoordinates(win->disp->display, win->my_window, win->disp->my_window, 0, 0, x, y,
3228                         &child);
3229 
3230   if (*x >= (int)win->disp->width || *y >= (int)win->disp->height) {
3231     /* no visible window */
3232 
3233     return 0;
3234   }
3235 
3236   if (*x < 0) {
3237     if (ACTUAL_WIDTH(win) <= abs(*x)) {
3238       /* no visible window */
3239 
3240       return 0;
3241     }
3242 
3243     *my_x = abs(*x);
3244 
3245     *width = ACTUAL_WIDTH(win) - abs(*x);
3246     *x = 0;
3247   } else {
3248     *my_x = 0;
3249     *width = ACTUAL_WIDTH(win);
3250   }
3251 
3252   if (*y < 0) {
3253     if (ACTUAL_HEIGHT(win) <= abs(*y)) {
3254       /* no visible window */
3255 
3256       return 0;
3257     }
3258 
3259     *my_y = abs(*y);
3260 
3261     *height = ACTUAL_HEIGHT(win) - abs(*y);
3262     *y = 0;
3263   } else {
3264     *my_y = 0;
3265     *height = ACTUAL_HEIGHT(win);
3266   }
3267 
3268   if (*x + (int)*width > (int)win->disp->width) {
3269     *width = win->disp->width - *x;
3270   }
3271 
3272   if (*y + (int)*height > (int)win->disp->height) {
3273     *height = win->disp->height - *y;
3274   }
3275 
3276   return 1;
3277 }
3278 
ui_set_click_interval(int interval)3279 void ui_set_click_interval(int interval) {
3280   click_interval = interval;
3281 }
3282 
ui_get_click_interval(void)3283 int ui_get_click_interval(void) {
3284   return click_interval;
3285 }
3286 
ui_window_get_mod_ignore_mask(ui_window_t * win,KeySym * keysyms)3287 u_int ui_window_get_mod_ignore_mask(ui_window_t *win, KeySym *keysyms) {
3288   XModifierKeymap *mod_map;
3289   int count;
3290   u_int ignore;
3291   u_int masks[] = {Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask};
3292   KeySym default_keysyms[] = {XK_Num_Lock, XK_Scroll_Lock, XK_ISO_Level3_Lock, NoSymbol};
3293 
3294   if (!keysyms) {
3295     keysyms = default_keysyms;
3296   }
3297 
3298   if ((mod_map = ui_window_get_modifier_mapping(win)) == NULL) {
3299     return ~0;
3300   }
3301 
3302   ignore = 0;
3303 
3304   count = 0;
3305   while (keysyms[count] != NoSymbol) {
3306     int ks_count;
3307     KeyCode kc;
3308 
3309     kc = XKeysymToKeycode(win->disp->display, keysyms[count]);
3310     for (ks_count = 0; ks_count < sizeof(masks) / sizeof(masks[0]); ks_count++) {
3311       int kc_count;
3312       KeyCode *key_codes;
3313 
3314       key_codes = &(mod_map->modifiermap[(ks_count + 3) * mod_map->max_keypermod]);
3315       for (kc_count = 0; kc_count < mod_map->max_keypermod; kc_count++) {
3316         if (key_codes[kc_count] == 0) {
3317           break;
3318         }
3319         if (key_codes[kc_count] == kc) {
3320 #ifdef DEBUG
3321           bl_debug_printf("keycode = %d, mod%d  idx %d  (by %s)\n", kc, ks_count + 1, kc_count + 1,
3322                           XKeysymToString(keysyms[count]));
3323 #endif
3324           ignore |= masks[ks_count];
3325           break;
3326         }
3327       }
3328     }
3329     count++;
3330   }
3331 
3332   return ~ignore;
3333 }
3334 
ui_window_get_mod_meta_mask(ui_window_t * win,char * mod_key)3335 u_int ui_window_get_mod_meta_mask(ui_window_t *win, char *mod_key) {
3336   int mask_count;
3337   int kc_count;
3338   XModifierKeymap *mod_map;
3339   KeyCode *key_codes;
3340   KeySym sym;
3341   char *mod_keys[] = {"mod1", "mod2", "mod3", "mod4", "mod5"};
3342   u_int mod_masks[] = {Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask};
3343   if (mod_key) {
3344     int count;
3345 
3346     for (count = 0; count < sizeof(mod_keys) / sizeof(mod_keys[0]); count++) {
3347       if (strcmp(mod_key, mod_keys[count]) == 0) {
3348         return mod_masks[count];
3349       }
3350     }
3351   }
3352 
3353   if ((mod_map = ui_window_get_modifier_mapping(win)) == NULL) {
3354 #ifdef DEBUG
3355     bl_debug_printf(BL_DEBUG_TAG " ui_window_get_modifier_mapping failed.\n");
3356 #endif
3357 
3358     return 0;
3359   }
3360 
3361   key_codes = mod_map->modifiermap;
3362 
3363   for (mask_count = 0; mask_count < sizeof(mod_masks) / sizeof(mod_masks[0]); mask_count++) {
3364     int count;
3365 
3366     /*
3367      * KeyCodes order is like this.
3368      * Shift[max_keypermod] Lock[max_keypermod] Control[max_keypermod]
3369      * Mod1[max_keypermod] Mod2[max_keypermod] Mod3[max_keypermod]
3370      * Mod4[max_keypermod] Mod5[max_keypermod]
3371      */
3372 
3373     /*
3374      * this modmap handling is tested with Xsun and XFree86-4.x
3375      * it works fine on both X servers. (2004-10-19 seiichi)
3376      */
3377 
3378     /* skip shift/lock/control */
3379     kc_count = (mask_count + 3) * mod_map->max_keypermod;
3380 
3381     for (count = 0; count < mod_map->max_keypermod; count++) {
3382       if (key_codes[kc_count] == 0) {
3383         break;
3384       }
3385 
3386       sym = XKeycodeToKeysym(win->disp->display, key_codes[kc_count], 0);
3387 
3388       if (((mod_key == NULL || strcmp(mod_key, "meta") == 0) &&
3389            (sym == XK_Meta_L || sym == XK_Meta_R)) ||
3390           ((mod_key == NULL || strcmp(mod_key, "alt") == 0) &&
3391            (sym == XK_Alt_L || sym == XK_Alt_R)) ||
3392           ((mod_key == NULL || strcmp(mod_key, "super") == 0) &&
3393            (sym == XK_Super_L || sym == XK_Super_R)) ||
3394           ((mod_key == NULL || strcmp(mod_key, "hyper") == 0) &&
3395            (sym == XK_Hyper_L || sym == XK_Hyper_R))) {
3396         return mod_masks[mask_count];
3397       }
3398 
3399       kc_count++;
3400     }
3401   }
3402 
3403 #ifdef DEBUG
3404   bl_debug_printf(BL_DEBUG_TAG " No meta key was found.\n");
3405 #endif
3406 
3407   return 0;
3408 }
3409 
ui_set_use_urgent_bell(int use)3410 void ui_set_use_urgent_bell(int use) {
3411   use_urgent_bell = use;
3412 }
3413 
ui_window_bell(ui_window_t * win,ui_bel_mode_t mode)3414 void ui_window_bell(ui_window_t *win, ui_bel_mode_t mode) {
3415   urgent_bell(win, 1);
3416 
3417   if (mode & BEL_VISUAL) {
3418     ui_window_blank(win);
3419 
3420 #if 0
3421     XSync(win->disp->display, False);
3422 #else
3423     XFlush(win->disp->display);
3424 #endif
3425     bl_usleep(1);
3426 
3427     (*win->window_exposed)(win, 0, 0, win->width, win->height);
3428   }
3429 
3430   if (mode & BEL_SOUND) {
3431     XBell(win->disp->display, 0);
3432   }
3433 }
3434 
ui_window_translate_coordinates(ui_window_t * win,int x,int y,int * global_x,int * global_y)3435 void ui_window_translate_coordinates(ui_window_t *win, int x, int y, int *global_x, int *global_y) {
3436   Window child;
3437 
3438   XTranslateCoordinates(win->disp->display, win->my_window, DefaultRootWindow(win->disp->display),
3439                         x, y, global_x, global_y, &child);
3440 }
3441 
ui_window_set_input_focus(ui_window_t * win)3442 void ui_window_set_input_focus(ui_window_t *win) {
3443   reset_input_focus(ui_get_root_window(win));
3444   win->inputtable = 1;
3445   XSetInputFocus(win->disp->display, win->my_window, RevertToParent, CurrentTime);
3446 }
3447 
ui_window_flush(ui_window_t * win)3448 void ui_window_flush(ui_window_t *win) {
3449 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_CAIRO)
3450   if (win->cairo_draw) {
3451     /* calls cairo_flush() */
3452     ui_window_cairo_draw_string32(win, NULL, NULL, 0, 0, NULL, 0);
3453   }
3454 #endif
3455 }
3456 
3457 #ifdef DEBUG
ui_window_dump_children(ui_window_t * win)3458 void ui_window_dump_children(ui_window_t *win) {
3459   int count;
3460 
3461   bl_msg_printf("%p(%li) => ", win, win->my_window);
3462   for (count = 0; count < win->num_children; count++) {
3463     bl_msg_printf("%p(%li) ", win->children[count], win->children[count]->my_window);
3464   }
3465   bl_msg_printf("\n");
3466 
3467   for (count = 0; count < win->num_children; count++) {
3468     ui_window_dump_children(win->children[count]);
3469   }
3470 }
3471 #endif
3472