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