1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2 
3 #include "../ui_window.h"
4 
5 #include <string.h>
6 #include <pobl/bl_debug.h>
7 #include <pobl/bl_mem.h>
8 #include <pobl/bl_unistd.h> /* bl_usleep */
9 #include <mef/ef_ucs4_map.h>
10 #ifdef USE_WAYLAND
11 #include <mef/ef_utf8_parser.h>
12 #endif
13 #include <mef/ef_utf16_parser.h>
14 
15 #include "ui_display.h"
16 #include "ui_font.h"
17 
18 #define MAX_CLICK 3 /* max is triple click */
19 
20 /* win->width is not multiples of (win)->width_inc in framebuffer. */
21 #define RIGHT_MARGIN(win) \
22   ((win)->width_inc ? ((win)->width - (win)->min_width) % (win)->width_inc : 0)
23 #define BOTTOM_MARGIN(win) \
24   ((win)->height_inc ? ((win)->height - (win)->min_height) % (win)->height_inc : 0)
25 
26 #ifdef USE_GRF
27 static ui_color_t black = {TP_COLOR, 0, 0, 0, 0};
28 #endif
29 
30 #define ParentRelative (1L)
31 #define DummyPixmap (2L)
32 
33 /* XXX Check if win is input method window or not. */
34 #define IS_IM_WINDOW(win) ((win)->disp->num_roots >= 2 && (win) == (win)->disp->roots[1])
35 
36 /* --- static variables --- */
37 
38 static int click_interval = 250; /* millisecond, same as xterm. */
39 
40 /* --- static functions --- */
41 
scroll_region(ui_window_t * win,int src_x,int src_y,u_int width,u_int height,int dst_x,int dst_y)42 static int scroll_region(ui_window_t *win, int src_x, int src_y, u_int width, u_int height,
43                          int dst_x, int dst_y) {
44   if (!win->is_mapped || !ui_window_is_scrollable(win)) {
45     return 0;
46   }
47 
48   ui_display_copy_lines(win->disp, src_x + win->x + win->hmargin, src_y + win->y + win->vmargin,
49                         dst_x + win->x + win->hmargin, dst_y + win->y + win->vmargin,
50                         width, height);
51 
52   return 1;
53 }
54 
55 /*
56  * copy_pixel() is called more than twice, so if it is implemented as a function
57  * it may be uninlined in compiling.
58  * dst should be aligned.
59  */
60 #define copy_pixel(dst, pixel, bpp)    \
61   switch (bpp) {                       \
62     case 1:                            \
63       *(dst) = pixel;                  \
64       break;                           \
65     case 2:                            \
66       *((u_int16_t *)(dst)) = (pixel); \
67       break;                           \
68     /* case  4: */                     \
69     default:                           \
70       *((u_int32_t *)(dst)) = (pixel); \
71   }
72 
memset16(u_int16_t * dst,u_int16_t i,u_int len)73 static inline u_int16_t *memset16(u_int16_t *dst, u_int16_t i, u_int len) {
74   u_int count;
75 
76   for (count = 0; count < len; count++) {
77     dst[count] = i;
78   }
79 
80   return dst;
81 }
82 
memset32(u_int32_t * dst,u_int32_t i,u_int len)83 static inline u_int32_t *memset32(u_int32_t *dst, u_int32_t i, u_int len) {
84   u_int count;
85 
86   for (count = 0; count < len; count++) {
87     dst[count] = i;
88   }
89 
90   return dst;
91 }
92 
93 #ifdef USE_FREETYPE
94 #define BLEND(fg, bg, alpha) ((bg) + ((fg) - (bg)) * (alpha) / 255)
copy_blended_pixel(Display * display,u_char * dst,u_char ** bitmap,u_long fg,u_long bg,u_int bpp)95 static int copy_blended_pixel(Display *display, u_char *dst, u_char **bitmap, u_long fg, u_long bg,
96                               u_int bpp) {
97   int a1 = *((*bitmap)++);
98   int a2 = *((*bitmap)++);
99   int a3 = *((*bitmap)++);
100 
101   if (a1 + a2 + a3 > 0) {
102     int r1;
103     int g1;
104     int b1;
105     int r2;
106     int g2;
107     int b2;
108     u_long pixel;
109 
110     r1 = PIXEL_RED(fg, display->rgbinfo) & 0xff;
111     g1 = PIXEL_GREEN(fg, display->rgbinfo) & 0xff;
112     b1 = PIXEL_BLUE(fg, display->rgbinfo) & 0xff;
113     r2 = PIXEL_RED(bg, display->rgbinfo) & 0xff;
114     g2 = PIXEL_GREEN(bg, display->rgbinfo) & 0xff;
115     b2 = PIXEL_BLUE(bg, display->rgbinfo) & 0xff;
116 
117     pixel =
118 #ifndef MANAGE_ROOT_WINDOWS_BY_MYSELF
119       /*
120        * f: fg color
121        * b: bg color
122        * w: other windows or desktop wall picture below mlterm window.
123        * 0.6, 0.4: a1, a2, a3
124        * 1.0, 0.0: alpha of fg_color
125        * 0.8, 0.2: alpha of bg color
126        *
127        * Correct: 0.6*(1.0*f + 0.0*w) + 0.4*(0.8*b + 0.2*w) = 0.6*f + 0.32*b + 0.08*w
128        * Lazy   : (0.6*f + 0.4*b)*(1.0*0.6+0.8*0.4) + w*(1.0-(1.0*0.6+0.8*0.4))
129        *                          ^^^^^^^^^^^^^^^^^     ^^^^^^^^^^^^^^^^^^^^^^
130        *          = 0.552*f + 0.368*b + 0.08*w
131        */
132       BLEND((fg >> 24), (bg >> 24), (a1 + a2 + a3) / 3) << 24 |
133 #endif
134       RGB_TO_PIXEL(BLEND(r1, r2, a1), BLEND(g1, g2, a2), BLEND(b1, b2, a3), display->rgbinfo);
135 
136     copy_pixel(dst, pixel, bpp);
137 
138     return 1;
139   } else {
140     return 0;
141   }
142 }
143 #endif
144 
145 /*
146  * If the width and height of drawn characters is not over the window should be checked
147  * before calling ui_window_draw_*string().
148  */
draw_string_intern(ui_window_t * win,XFontStruct * xfont,u_int font_height,u_int font_ascent,u_int font_width,int font_x_off,int double_draw_gap,int is_proportional,int is_var_col_width,u_int32_t fg_pixel,u_int32_t bg_pixel,int x,int y,u_char ** bitmaps,u_int len,u_char * picture,size_t picture_line_len,int src_bg_is_set,int bpp)149 static void draw_string_intern(ui_window_t *win, XFontStruct *xfont, u_int font_height,
150                                u_int font_ascent, u_int font_width, int font_x_off,
151                                int double_draw_gap, int is_proportional, int is_var_col_width,
152                                u_int32_t fg_pixel, u_int32_t bg_pixel,
153                                int x, /* win->x and win->hmargin are added. */
154                                int y, /* win->y and win->vmargin are added. */
155                                u_char **bitmaps, u_int len, u_char *picture,
156                                size_t picture_line_len, int src_bg_is_set, int bpp) {
157   int clip_y;
158   u_int clip_bottom;
159   size_t size;
160   u_char *src;
161   u_char *p;
162   u_int count;
163   int y_off;
164   int orig_x;
165   u_char *bitmap_line;
166   u_long pixel;
167 
168   /*
169    * Check if font->height or font->ascent excesses the display height,
170    * because font->height doesn't necessarily equals to the height of the
171    * US-ASCII font.
172    *
173    * XXX
174    * On the other hand, font->width is always the same (or exactly double) for now.
175    */
176 
177   clip_y = win->y + win->vmargin + win->clip_y;
178   if (win->clip_height == 0) {
179     clip_bottom = win->y + ACTUAL_HEIGHT(win);
180   } else {
181     clip_bottom = clip_y + win->clip_height;
182   }
183 
184   if (y >= clip_bottom) {
185     return;
186   } else if (y + font_height > clip_bottom) {
187     font_height = clip_bottom - y;
188   }
189 
190   if (y + font_height < clip_y) {
191     return;
192   } else if (y < clip_y) {
193     y_off = clip_y - y;
194 
195     if (picture) {
196       picture += (y_off * picture_line_len);
197     }
198   } else {
199     y_off = 0;
200   }
201 
202   /*
203    * (len + 1) is for decreasing the number of calling alloca() below.
204    * (See if (retreat - filled > font_width) block.)
205    */
206 #ifdef USE_FREETYPE
207   if (xfont->is_aa && is_proportional) {
208     u_int width = font_width; /* means 'len + 1' */
209 
210     for (count = 0; count < len; count++) {
211       if (bitmaps[count] && bitmaps[count][0] /* Glyph advance */ > font_width) {
212         width += bitmaps[count][0];
213       } else {
214         width += font_width;
215       }
216     }
217 
218     /*
219      * The caller should check if the width of specified drawn strings <= the width
220      * of the window.
221      */
222 #if 0
223     if (x + width > win->width + win->hmargin + win->x) {
224       width = win->width + win->hmargin + win->x - x;
225     }
226 #endif
227 
228     size = width * bpp;
229 
230     /* This is true only if USE_SDL2 and USE_BG_TEXTURE. (see ui_draw_str.c) */
231     if (src_bg_is_set && picture) {
232       picture = NULL;
233       picture_line_len = 0;
234       src_bg_is_set = 0;
235     }
236 
237 #if defined(DEBUG) && defined(USE_SDL2) && !defined(USE_BG_TEXTURE)
238     {
239       static int output_msg;
240       if (!output_msg) {
241         bl_debug_printf("mlterm is built without USE_BG_TEXTURE, "
242                         "so screen is corrupt with -otl option.\n");
243         output_msg = 1;
244       }
245     }
246 #endif
247   } else
248 #endif
249   {
250     size = (len + 1) * font_width * bpp;
251   }
252 
253 #if defined(USE_SDL2) && defined(USE_BG_TEXTURE)
254   if (bg_pixel == win->bg_color.pixel || !src_bg_is_set) {
255     bg_pixel = 0x0;
256     src_bg_is_set = 1;
257   }
258 #endif
259 
260   if (!(src = alloca(size))) {
261     return;
262   }
263 
264 #ifdef USE_FREETYPE
265   if (!xfont->face || !xfont->is_aa)
266 #endif
267   {
268     u_int y_off_bytes;
269     /*
270      * If font_width is larger than xfont->width_full, memory access must be limited
271      * to the latter one. (Don't excess xfont->glyph_width_bytes)
272      */
273     u_int max_glyph_width = xfont->width_full;
274 
275     if (max_glyph_width + font_x_off > font_width) {
276       max_glyph_width = font_width - font_x_off;
277     }
278 
279 #if 1
280     /* Optimization for most cases */
281     if (src_bg_is_set && !double_draw_gap) {
282       int x_off;
283       u_int end_gap = font_width - font_x_off - max_glyph_width;
284       u_int y_off_bytes = y_off * xfont->glyph_width_bytes;
285 
286       switch (bpp) {
287       case 1:
288         for (; y_off < font_height; y_off++, y_off_bytes += xfont->glyph_width_bytes) {
289           p = (picture ? memcpy(src, (picture += picture_line_len), size)
290                        : memset(src, bg_pixel, size));
291 
292           for (count = 0; count < len; count++) {
293             if (!ui_get_bitmap_line(xfont, bitmaps[count], y_off_bytes, bitmap_line)) {
294               p += font_width;
295             } else {
296               p += font_x_off;
297 
298               for (x_off = 0; x_off < max_glyph_width; x_off++, p++) {
299                 if (ui_get_bitmap_cell(bitmap_line, x_off)) {
300                   *p = fg_pixel;
301                 }
302               }
303 
304               p += end_gap;
305             }
306           }
307 
308           ui_display_put_image(win->disp, x, y + y_off, src, p - src, 0);
309         }
310 
311         return;
312 
313       case 2:
314         for (; y_off < font_height; y_off++, y_off_bytes += xfont->glyph_width_bytes) {
315           p = (picture ? memcpy(src, (picture += picture_line_len), size)
316                        : memset16(src, bg_pixel, size / 2));
317 
318           for (count = 0; count < len; count++) {
319             if (!ui_get_bitmap_line(xfont, bitmaps[count], y_off_bytes, bitmap_line)) {
320               p += (font_width * 2);
321             } else {
322               p += (font_x_off * 2);
323 
324               for (x_off = 0; x_off < max_glyph_width; x_off++, p += 2) {
325                 if (ui_get_bitmap_cell(bitmap_line, x_off)) {
326                   *((u_int16_t *)p) = fg_pixel;
327                 }
328               }
329 
330               p += (end_gap * 2);
331             }
332           }
333 
334           ui_display_put_image(win->disp, x, y + y_off, src, p - src, 0);
335         }
336 
337         return;
338 
339       /* case  4: */
340       default:
341         for (; y_off < font_height; y_off++, y_off_bytes += xfont->glyph_width_bytes) {
342           p = (picture ? memcpy(src, (picture += picture_line_len), size)
343                        : memset32(src, bg_pixel, size / 4));
344 
345           for (count = 0; count < len; count++) {
346             if (!ui_get_bitmap_line(xfont, bitmaps[count], y_off_bytes, bitmap_line)) {
347               p += (font_width * 4);
348             } else {
349               p += (font_x_off * 4);
350 
351               for (x_off = 0; x_off < max_glyph_width; x_off++, p += 4) {
352                 if (ui_get_bitmap_cell(bitmap_line, x_off)) {
353                   *((u_int32_t *)p) = fg_pixel;
354                 }
355               }
356 
357               p += (end_gap * 4);
358             }
359           }
360 
361           ui_display_put_image(win->disp, x, y + y_off, src, p - src, 0);
362         }
363 
364         return;
365       }
366     }
367 #endif
368 
369     orig_x = x;
370 
371     for (; y_off < font_height; y_off++) {
372       if (src_bg_is_set) {
373         if (picture) {
374           memcpy(src, (picture += picture_line_len), size);
375         } else {
376           switch (bpp) {
377           case 1:
378             memset(src, bg_pixel, size);
379             break;
380 
381           case 2:
382             memset16(src, bg_pixel, size / 2);
383             break;
384 
385           /* case  4: */
386           default:
387             memset32(src, bg_pixel, size / 4);
388             break;
389           }
390         }
391       }
392 
393       p = src;
394 
395       y_off_bytes = y_off * xfont->glyph_width_bytes;
396 
397       for (count = 0; count < len; count++, x += font_width) {
398         int x_off;
399 
400         if (!ui_get_bitmap_line(xfont, bitmaps[count], y_off_bytes, bitmap_line)) {
401           if (src_bg_is_set) {
402             p += (font_width * bpp);
403           } else {
404             for (x_off = 0; x_off < font_width; x_off++, p += bpp) {
405               pixel = ui_display_get_pixel(win->disp, x + x_off, y + y_off);
406               copy_pixel(p, pixel, bpp);
407             }
408           }
409         } else {
410           int force_fg = 0;
411           u_int glyph_end = font_x_off + max_glyph_width;
412 
413           for (x_off = 0; ; x_off++, p += bpp) {
414             if (font_x_off <= x_off && x_off < glyph_end &&
415                 ui_get_bitmap_cell(bitmap_line, x_off - font_x_off)) {
416               pixel = fg_pixel;
417               force_fg = double_draw_gap;
418             } else if (font_width <= x_off) {
419               break;
420             } else {
421               if (force_fg) {
422                 pixel = fg_pixel;
423                 force_fg = 0;
424               } else if (src_bg_is_set) {
425                 continue;
426               } else {
427                 pixel = ui_display_get_pixel(win->disp, x + x_off, y + y_off);
428               }
429             }
430 
431             copy_pixel(p, pixel, bpp);
432           }
433         }
434       }
435 
436       ui_display_put_image(win->disp, (x = orig_x), y + y_off, src, p - src, !src_bg_is_set);
437     }
438   }
439 #if defined(USE_FREETYPE)
440   else {
441     int orig_y_off = y_off;
442 
443     orig_x = x;
444 
445     for (; y_off < font_height; y_off++) {
446       int prev_crowded_out = 0;
447 
448       if (src_bg_is_set) {
449         if (picture) {
450           memcpy(src, (picture += picture_line_len), size);
451         } else {
452           switch (bpp) {
453           case 1:
454             memset(src, bg_pixel, size);
455             break;
456 
457           case 2:
458             memset16(src, bg_pixel, size / 2);
459             break;
460 
461           /* case  4: */
462           default:
463             memset32(src, bg_pixel, size / 4);
464             break;
465           }
466         }
467       }
468 
469       p = src;
470 
471       if (is_proportional) {
472         /*
473          * Bitmap format
474          * 1 byte    1 byte    1 byte        1 byte    1 byte    1 byte
475          * [advance] [retreat] [glyph width] [R alpha] [G alpha] [B alpha] ...
476          */
477         for (count = 0; count < len; count++) {
478           /*
479            * src_bg_is_set is always false if is_proportional is true.
480            * This is because the edge of a glyph which is forced out from a cell
481            * can be redrawn incorrectly even if is_var_col_width is false.
482            * (see #ifdef USE_FRAMEBUFFER #ifdef USE_FREETYPE
483            * #endif #endif in xcore_draw_str() in ui_draw_str.c)
484            */
485           int x_off;
486 
487           if (!bitmaps[count]) {
488             if (src_bg_is_set /* && !picture */) {
489               p += (font_width * bpp);
490             } else {
491               for (x_off = 0; x_off < font_width; x_off++, p += bpp) {
492                 pixel = ui_display_get_pixel(win->disp, x + x_off, y + y_off);
493                 copy_pixel(p, pixel, bpp);
494               }
495             }
496 
497             if (prev_crowded_out > font_width) {
498               prev_crowded_out -= font_width;
499             } else {
500               prev_crowded_out = 0;
501             }
502 
503             x += font_width;
504           } else {
505             int retreat;
506             int width;
507 
508             width = bitmaps[count][2];
509 
510             bitmap_line = bitmaps[count] + 3 /* header */ + y_off * width * 3;
511 
512             if ((retreat = bitmaps[count][1]) > 0) {
513               u_int filled;
514 
515               if ((filled = (p - src) / bpp) < retreat) {
516                 while (x >= retreat) {
517                   int x_off2;
518 
519                   x_off = -retreat;
520 
521                   if (y_off == orig_y_off) {
522                     u_char *new_src;
523 
524                     if (retreat - filled > font_width) { /* See (len + 1) above */
525                       size_t new_size = size + (retreat - filled - font_width) * bpp;
526 
527                       if (!(new_src = alloca(new_size))) {
528                         break;
529                       }
530 
531                       memcpy(new_src, src, p - src);
532                       p = new_src + (p - src);
533                       src = new_src;
534                       size = new_size;
535                     }
536 
537                     orig_x -= (retreat - filled);
538                   } else {
539                     x += (retreat - filled);
540                   }
541 
542                   memmove(src + (retreat - filled) * bpp, src, p - src);
543 
544                   /*
545                    * Don't use bg_pixel even if src_bg_is_set and !picture, because retreated
546                    * pixels can be uncleared by overwriting glyphs afterwards.
547                    */
548                   for (x_off2 = 0, p = src; x_off2 < retreat - filled; x_off2++, p += bpp) {
549                     pixel = ui_display_get_pixel(win->disp, x + x_off + x_off2, y + y_off);
550                     copy_pixel(p, pixel, bpp);
551                   }
552 
553                   p = src;
554                   goto end_of_retreat;
555                 }
556 
557                 /* Give up retreating before 'filled'. */
558                 bitmap_line += (retreat - filled);
559                 x_off = -filled;
560                 p = src;
561               } else {
562                 x_off = -retreat;
563                 p -= (retreat * bpp);
564               }
565             } else {
566               x_off = 0;
567             }
568 
569           end_of_retreat:
570             width -= retreat;
571 
572             if (is_var_col_width) {
573               int advance = bitmaps[count][0];
574 
575               if (src_bg_is_set /* && !picture */) {
576                 for (; x_off < width; x_off++, p += bpp) {
577                   if (copy_blended_pixel(win->disp->display, p, &bitmap_line, fg_pixel, bg_pixel,
578                                          bpp)) {
579                     /* do nothing */
580                   } else if (x_off >= prev_crowded_out) {
581                     copy_pixel(p, bg_pixel, bpp);
582                   }
583                 }
584 
585                 for (; x_off < advance; x_off++, p += bpp) {
586                   if (x_off >= prev_crowded_out) {
587                     copy_pixel(p, bg_pixel, bpp);
588                   }
589                 }
590               } else {
591                 for (; x_off < width; x_off++, p += bpp) {
592                   u_long bg = ui_display_get_pixel(win->disp, x + x_off, y + y_off);
593 
594                   if (copy_blended_pixel(win->disp->display, p, &bitmap_line, fg_pixel, bg, bpp)) {
595                     /* do nothing */
596                   } else if (x_off >= prev_crowded_out) {
597                     copy_pixel(p, bg, bpp);
598                   }
599                 }
600 
601                 for (; x_off < advance; x_off++, p += bpp) {
602                   if (x_off >= prev_crowded_out) {
603                     pixel = ui_display_get_pixel(win->disp, x + x_off, y + y_off);
604                     copy_pixel(p, pixel, bpp);
605                   }
606                 }
607               }
608 
609               if (count + 1 < len) {
610                 if (prev_crowded_out > advance) {
611                   prev_crowded_out -= advance;
612                 } else {
613                   prev_crowded_out = 0;
614                 }
615 
616                 if (advance > 0 && x_off != advance) {
617                   p += ((advance - x_off) * bpp);
618 
619                   if (x_off > advance && prev_crowded_out < x_off - advance) {
620                     prev_crowded_out = x_off - advance;
621                   }
622                 }
623 
624                 x += advance;
625               } else {
626                 prev_crowded_out = 0;
627               }
628             } else {
629               /* is_var_col_width is false */
630               int padding;
631 
632               width += font_x_off;
633 
634               /*
635                * font_x_off is added to width above, so 'width + font_x_off'
636                * means that font_x_off * 2 is added to width.
637                */
638 #ifdef CENTER_PROPORTIONAL_GLYPHS
639               if (width + font_x_off < font_width) {
640                 int diff = (font_width - width - font_x_off) / 2;
641 
642                 width += diff;
643                 padding = font_x_off + diff;
644               } else
645 #endif
646               {
647                 if (width + font_x_off > font_width) {
648                   int diff = (width + font_x_off - font_width) / 2;
649 
650                   if (diff > font_x_off) {
651                     padding = 0;
652 
653                     /*
654                      * If you use Inconsolata font with --otl option, === is shaped
655                      * with garbage by this.
656                      */
657 #if 0
658                     bitmap_line += (diff - font_x_off) * 3;
659 #endif
660                   } else {
661                     padding = font_x_off - diff;
662                   }
663                 } else {
664                   padding = font_x_off;
665                 }
666 
667                 if (width > (len - count) * font_width) {
668                   width = (len - count) * font_width;
669                 }
670               }
671 
672               if (padding > 0) {
673                 if ((!src_bg_is_set /* || picture */) && padding + x_off > 0) {
674                   int copy_and_skip = padding;
675 
676                   if (x_off < 0) {
677                     /* x_off < 0 has been already copied from ui_display_get_pixel(). */
678                     copy_and_skip += (x_off);
679                     p += (-x_off * bpp);
680                     x_off = 0;
681                   }
682 
683                   for (; copy_and_skip > 0; copy_and_skip--, x_off++, p += bpp) {
684                     if (x_off >= prev_crowded_out) {
685                       pixel = ui_display_get_pixel(win->disp, x + x_off, y + y_off);
686                       copy_pixel(p, pixel, bpp);
687                     }
688                   }
689                 } else {
690                   /* x_off < 0 has been already copied from ui_display_get_pixel(). */
691                   p += (padding * bpp);
692                   x_off += padding;
693                 }
694               }
695 
696               if (src_bg_is_set /* && !picture */) {
697                 for (; x_off < width; x_off++, p += bpp) {
698                   if (copy_blended_pixel(win->disp->display, p, &bitmap_line, fg_pixel, bg_pixel,
699                                          bpp)) {
700                     /* do nothing */
701                   } else if (x_off >= prev_crowded_out) {
702                     copy_pixel(p, bg_pixel, bpp);
703                   }
704                 }
705 
706                 for (; x_off < font_width; x_off++, p += bpp) {
707                   copy_pixel(p, bg_pixel, bpp);
708                 }
709               } else {
710                 for (; x_off < width; x_off++, p += bpp) {
711                   u_long bg = ui_display_get_pixel(win->disp, x + x_off, y + y_off);
712 
713                   if (copy_blended_pixel(win->disp->display, p, &bitmap_line, fg_pixel, bg, bpp)) {
714                     /* do nothing */
715                   } else if (x_off >= prev_crowded_out) {
716                     copy_pixel(p, bg, bpp);
717                   }
718                 }
719 
720                 for (; x_off < font_width; x_off++, p += bpp) {
721                   pixel = ui_display_get_pixel(win->disp, x + x_off, y + y_off);
722                   copy_pixel(p, pixel, bpp);
723                 }
724               }
725 
726               /* If count == len - 1, width <= font_width is always true. */
727               if (width <= font_width) {
728                 prev_crowded_out = 0;
729               } else {
730                 prev_crowded_out = width - font_width;
731                 p -= (prev_crowded_out * bpp);
732               }
733 
734               x += font_width;
735             }
736           }
737         }
738       } else {
739         /* is_proportional is false */
740         for (count = 0; count < len; count++, x += font_width) {
741           int x_off;
742 
743           if (!bitmaps[count]) {
744             if (src_bg_is_set) {
745               p += (font_width * bpp);
746             } else {
747               for (x_off = 0; x_off < font_width; x_off++, p += bpp) {
748                 pixel = ui_display_get_pixel(win->disp, x + x_off, y + y_off);
749                 copy_pixel(p, pixel, bpp);
750               }
751             }
752           } else {
753             u_int glyph_end = font_x_off + ((u_int16_t*)bitmaps[count])[1];
754             int padding;
755 
756             /*
757              * font_x_off is added to width above, so 'width + font_x_off'
758              * means that font_x_off * 2 is added to width.
759              */
760 #ifdef CENTER_PROPORTIONAL_GLYPHS
761             if (glyph_end + font_x_off < font_width) {
762               int diff = (font_width - glyph_end - font_x_off) / 2;
763 
764               glyph_end += diff;
765               padding = font_x_off + diff;
766             } else
767 #endif
768             {
769               padding = font_x_off;
770 
771               if (glyph_end > font_width) {
772                 glyph_end = font_width;
773               }
774             }
775 
776             bitmap_line = bitmaps[count] + 4 + y_off * ((u_int16_t*)bitmaps[count])[0];
777 
778             if (src_bg_is_set) {
779               if (picture) {
780                 for (x_off = 0; ; x_off++, p += bpp) {
781                   if (padding <= x_off && x_off < glyph_end) {
782                     u_long bg = (bpp == 2) ? *((u_int16_t *)p) : *((u_int32_t *)p);
783                     copy_blended_pixel(win->disp->display, p, &bitmap_line, fg_pixel, bg, bpp);
784                   } else if (font_width <= x_off) {
785                     break;
786                   }
787                 }
788               } else {
789                 for (x_off = 0; ; x_off++, p += bpp) {
790                   if (padding <= x_off && x_off < glyph_end) {
791                     copy_blended_pixel(win->disp->display, p, &bitmap_line, fg_pixel,
792                                        bg_pixel, bpp);
793                   } else if (font_width <= x_off) {
794                     break;
795                   }
796                 }
797               }
798             } else {
799               for (x_off = 0; ; x_off++, p += bpp) {
800                 if (padding <= x_off && x_off < glyph_end) {
801                   u_long bg = ui_display_get_pixel(win->disp, x + x_off, y + y_off);
802                   if (copy_blended_pixel(win->disp->display, p, &bitmap_line, fg_pixel, bg, bpp)) {
803                     continue;
804                   }
805                 } else if (font_width <= x_off) {
806                   break;
807                 }
808 
809                 pixel = ui_display_get_pixel(win->disp, x + x_off, y + y_off);
810                 copy_pixel(p, pixel, bpp);
811               }
812             }
813           }
814         }
815       }
816 
817       ui_display_put_image(win->disp, (x = orig_x), y + y_off, src, p - src, !src_bg_is_set);
818     }
819   }
820 #endif
821 }
822 
draw_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,u_int ch_len,int wall_picture_bg)823 static void draw_string(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color,
824                         ui_color_t *bg_color,      /* must be NULL if wall_picture_bg is 1 */
825                         int x, int y, u_char *str, /* 'len * ch_len' bytes */
826                         u_int len, u_int ch_len, int wall_picture_bg) {
827   u_int bpp;
828   XFontStruct *xfont;
829   u_char **bitmaps;
830   u_int font_height;
831   u_int font_ascent;
832   u_char *picture;
833   size_t picture_line_len;
834   u_int count;
835   int src_bg_is_set;
836   int use_ot_layout;
837   int get_space_glyph;
838   int x_off;
839 
840   if (!win->is_mapped) {
841     return;
842   }
843 
844   if (!(bitmaps = alloca((len * sizeof(*bitmaps))))) {
845     return;
846   }
847 
848   bpp = win->disp->display->bytes_per_pixel;
849   xfont = font->xfont;
850 
851 #ifdef USE_OT_LAYOUT
852   use_ot_layout = (font->use_ot_layout /* && font->ot_font */);
853 #else
854   use_ot_layout = 0;
855 #endif
856 
857   /* Following check is done by the caller of this function. */
858 #if 0
859   /*
860    * Check if font->width * len excesses the display height
861    * because full width fonts can be used for characters which console
862    * applications regard as half width.
863    */
864 
865   if (x + font->width * len > win->width) {
866     len = (win->width - x) / font->width;
867   }
868 #endif
869 
870   x += (win->hmargin + win->x);
871   y = y + (win->vmargin + win->y) - font->ascent;
872 
873   if (wall_picture_bg) {
874     /* bg_color is always NULL */
875     Pixmap pic;
876     int pic_x;
877     int pic_y;
878 
879     if (win->wall_picture == ParentRelative) {
880       pic = win->parent->wall_picture;
881       pic_x = x;
882       pic_y = y;
883     } else {
884       pic = win->wall_picture;
885       pic_x = x - win->x;
886       pic_y = y - win->y;
887     }
888 
889     picture_line_len = pic->width * bpp;
890     picture = pic->image + pic_y * picture_line_len +
891               /* - picture_line_len is for picture += picture_line_len below. */
892               pic_x * bpp - picture_line_len;
893 
894     src_bg_is_set = 1;
895   } else {
896     picture = NULL;
897 
898     if (bg_color) {
899       src_bg_is_set = 1;
900     } else {
901       src_bg_is_set = 0;
902     }
903   }
904 
905   x_off = font->x_off;
906   /* See ui_calculate_char_width() in ui_font.c */
907   get_space_glyph = font->is_proportional && font->is_var_col_width;
908 
909   if (ch_len == 1) {
910     for (count = 0; count < len; count++) {
911       bitmaps[count] = ui_get_bitmap(xfont, str + count, 1, use_ot_layout,
912                                      get_space_glyph, NULL);
913     }
914   } else /* if(ch_len == 2) */ {
915     XFontStruct *compl_xfont;
916 
917 #if defined(USE_FREETYPE)
918     if (xfont->face && !IS_ISO10646_UCS4(font->id)) {
919       u_char *str_p = str;
920       ef_char_t non_ucs;
921       ef_char_t ucs4;
922 
923       non_ucs.size = 2;
924       non_ucs.cs = FONT_CS(font->id);
925       non_ucs.property = 0;
926       for (count = 0; count < len; count++, str_p += 2) {
927         memcpy(non_ucs.ch, str_p, 2);
928         if (!ef_map_to_ucs4(&ucs4, &non_ucs)) {
929           continue;
930         }
931 
932         if (ucs4.ch[0] == '\0' && ucs4.ch[1] == '\0') {
933           memcpy(str_p, ucs4.ch + 2, 2);
934         }
935 #if 0
936         else {
937           memcpy(str_p, ucs4.ch, 4);
938           ch_len = 4;
939         }
940 #endif
941       }
942     }
943 #endif
944 
945     for (count = 0; count < len;) {
946       if (0xd8 <= str[0] && str[0] <= 0xdb) {
947         if (use_ot_layout || count >= --len) {
948           break;
949         }
950 
951         if (0xdc <= str[2] && str[2] <= 0xdf) {
952           /* surrogate pair */
953           ef_int_to_bytes(str, 4, (str[0] - 0xd8) * 0x100 * 0x400 + str[1] * 0x400 +
954                                        (str[2] - 0xdc) * 0x100 + str[3] + 0x10000);
955           ch_len = 4;
956         } else {
957           /* illegal, ignored. */
958           len--;
959           count--;
960           str += 4;
961           continue;
962         }
963       }
964 
965       compl_xfont = NULL;
966       bitmaps[count] = ui_get_bitmap(font->xfont, str, ch_len, use_ot_layout,
967                                      get_space_glyph, &compl_xfont);
968       if (compl_xfont && xfont != compl_xfont) {
969         u_int w;
970 
971         if (count > 0) {
972           font_ascent = font->ascent;
973           font_height = font->height;
974           if (ui_modify_bitmaps(xfont, bitmaps, count, &font_height, &font_ascent)) {
975             draw_string_intern(win, xfont, font_height, font_ascent, font->width, x_off,
976                                font->double_draw_gap, font->is_proportional, font->is_var_col_width,
977                                fg_color->pixel, bg_color ? bg_color->pixel : 0, x, y,
978                                bitmaps, count, picture, picture_line_len, src_bg_is_set, bpp);
979           }
980           x += (font->width * count);
981 
982           bitmaps[0] = bitmaps[count];
983           len -= count;
984           count = 0;
985         } else {
986           count++;
987         }
988         xfont = compl_xfont;
989 
990         /* see ui_font.c */
991         if (font->id & FONT_FULLWIDTH) {
992           w = xfont->width_full;
993         } else {
994           w = xfont->width;
995         }
996 
997         if (w >= font->width) {
998           x_off = 0;
999         } else {
1000           x_off = (font->width - w) / 2;
1001         }
1002       } else {
1003         count++;
1004       }
1005 
1006       str += ch_len;
1007       ch_len = 2;
1008     }
1009   }
1010 
1011   font_ascent = font->ascent;
1012   font_height = font->height;
1013   if (ui_modify_bitmaps(xfont, bitmaps, len, &font_height, &font_ascent)) {
1014     draw_string_intern(win, xfont, font_height, font_ascent, font->width, x_off,
1015                        font->double_draw_gap, font->is_proportional, font->is_var_col_width,
1016                        fg_color->pixel, bg_color ? bg_color->pixel : 0, x, y,
1017                        bitmaps, len, picture, picture_line_len, src_bg_is_set, bpp);
1018   }
1019 }
1020 
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,int accept_margin)1021 static int copy_area(ui_window_t *win, Pixmap src, PixmapMask mask, int src_x, /* can be minus */
1022                      int src_y,                                                /* can be minus */
1023                      u_int width, u_int height, int dst_x,                     /* can be minus */
1024                      int dst_y,                                                /* can be minus */
1025                      int accept_margin /* x/y can be minus and over width/height */
1026                      ) {
1027   int hmargin;
1028   int vmargin;
1029   int right_margin;
1030   int bottom_margin;
1031   int y_off;
1032   u_int bpp;
1033   u_char *picture;
1034   size_t src_width_size;
1035 
1036   if (!win->is_mapped) {
1037     return 0;
1038   }
1039 
1040   if (accept_margin) {
1041     hmargin = win->hmargin;
1042     vmargin = win->vmargin;
1043     right_margin = bottom_margin = 0;
1044   } else {
1045     hmargin = vmargin = 0;
1046     right_margin = RIGHT_MARGIN(win);
1047     bottom_margin = BOTTOM_MARGIN(win);
1048   }
1049 
1050   if (dst_x >= (int)win->width + hmargin || dst_y >= (int)win->height + vmargin) {
1051     return 0;
1052   }
1053 
1054   if (dst_x + width > win->width + hmargin - right_margin) {
1055     width = win->width + hmargin - right_margin - dst_x;
1056   }
1057 
1058   if (dst_y + height > win->height + vmargin - bottom_margin) {
1059     height = win->height + vmargin - bottom_margin - dst_y;
1060   }
1061 
1062   bpp = win->disp->display->bytes_per_pixel;
1063   src_width_size = src->width * bpp;
1064   picture = src->image + src_width_size * (vmargin + src_y) + bpp * (hmargin + src_x);
1065 
1066   if (mask) {
1067     mask += ((vmargin + src_y) * src->width + hmargin + src_x);
1068 
1069     for (y_off = 0; y_off < height; y_off++) {
1070       int x_off;
1071       u_int w;
1072 
1073       w = 0;
1074       for (x_off = 0; x_off < width; x_off++) {
1075         if (mask[x_off]) {
1076           w++;
1077 
1078           if (x_off + 1 == width) {
1079             /* for x_off - w */
1080             x_off++;
1081           } else {
1082             continue;
1083           }
1084         } else if (w == 0) {
1085           continue;
1086         }
1087 
1088         ui_display_put_image(win->disp, win->x + win->hmargin + dst_x + x_off - w,
1089                              win->y + win->vmargin + dst_y + y_off, picture + bpp * (x_off - w),
1090                              w * bpp, 0);
1091         w = 0;
1092       }
1093 
1094       mask += src->width;
1095       picture += src_width_size;
1096     }
1097   } else {
1098     size_t size;
1099 
1100     size = width * bpp;
1101 
1102     for (y_off = 0; y_off < height; y_off++) {
1103       ui_display_put_image(win->disp, win->x + win->hmargin + dst_x,
1104                            win->y + win->vmargin + dst_y + y_off,
1105                            picture, size, 0);
1106       picture += src_width_size;
1107     }
1108   }
1109 
1110   return 1;
1111 }
1112 
clear_margin_area(ui_window_t * win)1113 static void clear_margin_area(ui_window_t *win) {
1114   u_int right_margin;
1115   u_int bottom_margin;
1116 
1117   right_margin = RIGHT_MARGIN(win);
1118   bottom_margin = BOTTOM_MARGIN(win);
1119 
1120   if (win->hmargin | win->vmargin | right_margin | bottom_margin) {
1121     ui_window_clear(win, -(win->hmargin), -(win->vmargin), win->hmargin, ACTUAL_HEIGHT(win));
1122     ui_window_clear(win, 0, -(win->vmargin), win->width, win->vmargin);
1123     ui_window_clear(win, win->width - right_margin, -(win->vmargin), win->hmargin + right_margin,
1124                     ACTUAL_HEIGHT(win));
1125     ui_window_clear(win, 0, win->height - bottom_margin, win->width, win->vmargin + bottom_margin);
1126   }
1127 
1128   /* XXX */
1129   if (win->num_children == 2 &&
1130       ACTUAL_HEIGHT(win->children[0]) == ACTUAL_HEIGHT(win->children[1])) {
1131     if (win->children[0]->x + ACTUAL_WIDTH(win->children[0]) <= win->children[1]->x) {
1132       ui_window_clear(win, win->children[0]->x + ACTUAL_WIDTH(win->children[0]), 0,
1133                       win->children[1]->x - win->children[0]->x - ACTUAL_WIDTH(win->children[0]),
1134                       win->height);
1135     } else if (win->children[0]->x >= win->children[1]->x + ACTUAL_WIDTH(win->children[1])) {
1136       ui_window_clear(win, win->children[1]->x + ACTUAL_WIDTH(win->children[1]), 0,
1137                       win->children[0]->x - win->children[1]->x - ACTUAL_WIDTH(win->children[1]),
1138                       win->height);
1139     }
1140   }
1141 }
1142 
fix_rl_boundary(ui_window_t * win,int boundary_start,int * boundary_end)1143 static int fix_rl_boundary(ui_window_t *win, int boundary_start, int *boundary_end) {
1144   int margin;
1145 
1146   margin = RIGHT_MARGIN(win);
1147 
1148   if (boundary_start > win->width - margin) {
1149     return 0;
1150   }
1151 
1152   if (*boundary_end > win->width - margin) {
1153     *boundary_end = win->width - margin;
1154   }
1155 
1156   return 1;
1157 }
1158 
reset_input_focus(ui_window_t * win)1159 static void reset_input_focus(ui_window_t *win) {
1160   u_int count;
1161 
1162 #ifndef MANAGE_ROOT_WINDOWS_BY_MYSELF
1163   /*
1164    * Switching input method engines invokes unfocus and focus. In this case,
1165    * it is necessary to search a window which was focused most recently.
1166    */
1167   if (win->inputtable > 0) {
1168     win->inputtable = -1;
1169   } else if (win->inputtable < 0) {
1170     if (win->inputtable > -10) {
1171       win->inputtable --;
1172     }
1173   }
1174 #else
1175   if (win->inputtable) {
1176     win->inputtable = -1;
1177   }
1178 #endif
1179   else {
1180     win->inputtable = 0;
1181   }
1182 
1183   if (win->is_focused) {
1184     win->is_focused = 0;
1185 
1186     if (win->window_unfocused) {
1187       (*win->window_unfocused)(win);
1188     }
1189   }
1190 
1191   for (count = 0; count < win->num_children; count++) {
1192     reset_input_focus(win->children[count]);
1193   }
1194 }
1195 
1196 #ifdef USE_WAYLAND
check_update_window(ui_window_t * win,int x,int y)1197 static void check_update_window(ui_window_t *win, int x /* parent */, int y /* parent */) {
1198   u_int count;
1199 
1200   x += win->x;
1201   y += win->y;
1202 
1203   if ((win->parent || win->num_children == 0) && /* XXX ui_layout_t is not updated. */
1204       (ui_display_get_pixel(win->disp, x + ACTUAL_WIDTH(win) / 2,
1205                             y + ACTUAL_HEIGHT(win) / 2) == 0 ||
1206        ui_display_get_pixel(win->disp, x + ACTUAL_WIDTH(win) - 1,
1207                             y + ACTUAL_HEIGHT(win) - 1) == 0)) {
1208     /* This window doesn't seem to have been drawn correctly yet after ui_display_resize(). */
1209     ui_window_update_all(win);
1210   }
1211 
1212   for (count = 0; count < win->num_children; count++) {
1213     check_update_window(win->children[count], x, y);
1214   }
1215 }
1216 #endif
1217 
1218 #if 0
1219 static int check_child_window_area(ui_window_t *win) {
1220   if (win->num_children > 0) {
1221     u_int count;
1222     u_int sum;
1223 
1224     for (sum = 0, count = 1; count < win->num_children; count++) {
1225       sum += (ACTUAL_WIDTH(win->children[count]) * ACTUAL_HEIGHT(win->children[count]));
1226     }
1227 
1228     if (sum < win->disp->width * win->disp->height * 0.9) {
1229       return 0;
1230     }
1231   }
1232 
1233   return 1;
1234 }
1235 #endif
1236 
convert_to_decsp_font_index(u_char * str,u_int len)1237 static void convert_to_decsp_font_index(u_char *str, u_int len) {
1238   while (len != 0) {
1239     if (*str == 0x5f) {
1240       *str = 0x7f;
1241     } else if (0x5f < *str && *str < 0x7f) {
1242       (*str) -= 0x5f;
1243     }
1244 
1245     len--;
1246     str++;
1247   }
1248 }
1249 
1250 /* --- global functions --- */
1251 
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)1252 int ui_window_init(ui_window_t *win, u_int width, u_int height, u_int min_width, u_int min_height,
1253                    u_int width_inc, u_int height_inc, u_int hmargin, u_int vmargin, int create_gc,
1254                    int inputtable) {
1255   memset(win, 0, sizeof(ui_window_t));
1256 
1257   /* If wall picture is set, scrollable will be 0. */
1258   win->is_scrollable = 1;
1259 
1260 #ifdef MANAGE_ROOT_WINDOWS_BY_MYSELF
1261   win->is_focused = 1;
1262 #endif
1263   win->inputtable = inputtable;
1264   win->is_mapped = 1;
1265 
1266   win->create_gc = create_gc;
1267 
1268   win->width = width;
1269   win->height = height;
1270   win->min_width = min_width;
1271   win->min_height = min_height;
1272   win->width_inc = width_inc;
1273   win->height_inc = height_inc;
1274   win->sizehint_flag = SIZEHINT_WIDTH|SIZEHINT_HEIGHT;
1275   win->hmargin = hmargin;
1276   win->vmargin = vmargin;
1277 
1278   win->prev_clicked_button = -1;
1279 
1280   win->app_name = "mlterm"; /* Can be changed in ui_display_show_root(). */
1281 
1282   return 1;
1283 }
1284 
ui_window_final(ui_window_t * win)1285 void ui_window_final(ui_window_t *win) {
1286   u_int count;
1287 
1288   for (count = 0; count < win->num_children; count++) {
1289     ui_window_final(win->children[count]);
1290   }
1291 
1292   free(win->children);
1293 
1294   ui_display_clear_selection(win->disp, win);
1295 
1296   if (win->window_finalized) {
1297     (*win->window_finalized)(win);
1298   }
1299 }
1300 
ui_window_set_type_engine(ui_window_t * win,ui_type_engine_t type_engine)1301 void ui_window_set_type_engine(ui_window_t *win, ui_type_engine_t type_engine) {}
1302 
ui_window_add_event_mask(ui_window_t * win,long event_mask)1303 void ui_window_add_event_mask(ui_window_t *win, long event_mask) {
1304   win->event_mask |= event_mask;
1305 }
1306 
ui_window_remove_event_mask(ui_window_t * win,long event_mask)1307 void ui_window_remove_event_mask(ui_window_t *win, long event_mask) {
1308   win->event_mask &= ~event_mask;
1309 }
1310 
ui_window_ungrab_pointer(ui_window_t * win)1311 void ui_window_ungrab_pointer(ui_window_t *win) {}
1312 
ui_window_set_wall_picture(ui_window_t * win,Pixmap pic,int do_expose)1313 int ui_window_set_wall_picture(ui_window_t *win, Pixmap pic, int do_expose) {
1314 #if defined(USE_SDL2) && defined(USE_BG_TEXTURE)
1315   ui_display_set_wall_picture(win->disp, pic->image, pic->width, pic->height);
1316 
1317   return 0; /* to free pic memory */
1318 #else
1319   u_int count;
1320 #ifdef USE_GRF
1321   int ret;
1322 
1323   if ((ret = x68k_tvram_set_wall_picture(pic->image, pic->width, pic->height))) {
1324     win->wall_picture = DummyPixmap; /* dummy */
1325 
1326     /* Don't set is_scrollable = 0. */
1327 
1328     /* If ret == 2, text vram was initialized just now. */
1329     if (ret == 2) {
1330       clear_margin_area(win);
1331 
1332       if (win->window_exposed) {
1333         (*win->window_exposed)(win, 0, 0, win->width, win->height);
1334       }
1335     }
1336 
1337     return 0; /* to free pic memory. */
1338   }
1339 #endif
1340 
1341   win->wall_picture = pic;
1342   win->is_scrollable = 0;
1343 
1344   if (do_expose) {
1345     clear_margin_area(win);
1346 
1347     if (win->window_exposed) {
1348       (*win->window_exposed)(win, 0, 0, win->width, win->height);
1349     }
1350 #if 0
1351     else {
1352       ui_window_clear_all(win);
1353     }
1354 #endif
1355   }
1356 
1357   for (count = 0; count < win->num_children; count++) {
1358     ui_window_set_wall_picture(win->children[count], ParentRelative, do_expose);
1359   }
1360 
1361   return 1;
1362 #endif
1363 }
1364 
ui_window_unset_wall_picture(ui_window_t * win,int do_expose)1365 int ui_window_unset_wall_picture(ui_window_t *win, int do_expose) {
1366   u_int count;
1367 
1368 #ifdef USE_GRF
1369   x68k_tvram_set_wall_picture(NULL, 0, 0);
1370 #endif
1371 
1372 #if defined(USE_SDL2) && defined(USE_BG_TEXTURE)
1373   ui_display_set_wall_picture(win->disp, NULL, 0, 0);
1374 #endif
1375 
1376   win->wall_picture = None;
1377   win->is_scrollable = 1;
1378 
1379   if (do_expose) {
1380     clear_margin_area(win);
1381 
1382     if (win->window_exposed) {
1383       (*win->window_exposed)(win, 0, 0, win->width, win->height);
1384     }
1385 #if 0
1386     else {
1387       ui_window_clear_all(win);
1388     }
1389 #endif
1390   }
1391 
1392   for (count = 0; count < win->num_children; count++) {
1393     ui_window_unset_wall_picture(win->children[count], do_expose);
1394   }
1395 
1396   return 1;
1397 }
1398 
ui_window_set_transparent(ui_window_t * win,ui_picture_modifier_ptr_t pic_mod)1399 int ui_window_set_transparent(
1400     ui_window_t *win, /* Transparency is applied to all children recursively */
1401     ui_picture_modifier_ptr_t pic_mod) {
1402   return 0;
1403 }
1404 
ui_window_unset_transparent(ui_window_t * win)1405 int ui_window_unset_transparent(ui_window_t *win) { return 0; }
1406 
ui_window_set_cursor(ui_window_t * win,u_int cursor_shape)1407 void ui_window_set_cursor(ui_window_t *win, u_int cursor_shape) {
1408   win->cursor_shape = cursor_shape;
1409 }
1410 
ui_window_set_fg_color(ui_window_t * win,ui_color_t * fg_color)1411 int ui_window_set_fg_color(ui_window_t *win, ui_color_t *fg_color) {
1412   if (win->fg_color.pixel == fg_color->pixel) {
1413     return 0;
1414   }
1415 
1416   win->fg_color = *fg_color;
1417 
1418   return 1;
1419 }
1420 
ui_window_set_bg_color(ui_window_t * win,ui_color_t * bg_color)1421 int ui_window_set_bg_color(ui_window_t *win, ui_color_t *bg_color) {
1422   if (win->bg_color.pixel == bg_color->pixel) {
1423     return 0;
1424   }
1425 
1426 #if defined(USE_SDL2) && defined(USE_BG_TEXTURE)
1427   ui_display_set_bg_color(win->disp, bg_color->pixel);
1428 #endif
1429 
1430   win->bg_color = *bg_color;
1431 
1432   clear_margin_area(win);
1433 
1434   return 1;
1435 }
1436 
ui_window_add_child(ui_window_t * win,ui_window_t * child,int x,int y,int map)1437 int ui_window_add_child(ui_window_t *win, ui_window_t *child, int x, int y, int map) {
1438   void *p;
1439 
1440   if (win->parent) {
1441     /* Can't add a grand child window. */
1442     return 0;
1443   }
1444 
1445   if ((p = realloc(win->children, sizeof(*win->children) * (win->num_children + 1))) == NULL) {
1446 #ifdef DEBUG
1447     bl_warn_printf(BL_DEBUG_TAG " realloc failed.\n");
1448 #endif
1449 
1450     return 0;
1451   }
1452 
1453   win->children = p;
1454 
1455   child->parent = win;
1456   child->x = x + win->hmargin;
1457   child->y = y + win->vmargin;
1458 
1459 #ifndef MANAGE_ROOT_WINDOWS_BY_MYSELF
1460   /*
1461    * The default value of is_focused is 0 on wayland, while 1 on framebuffer.
1462    * (see ui_window_init())
1463    */
1464   if (!(child->is_mapped = map) && child->inputtable > 0) {
1465     child->inputtable = -1;
1466   }
1467 #else
1468   if ((child->is_mapped = map) && win->is_focused && child->inputtable) {
1469     child->is_focused = 1;
1470   } else {
1471     child->is_focused = 0;
1472     if (child->inputtable > 0) {
1473       child->inputtable = -1;
1474     }
1475   }
1476 #endif
1477 
1478   win->children[win->num_children++] = child;
1479 
1480   return 1;
1481 }
1482 
ui_window_remove_child(ui_window_t * win,ui_window_t * child)1483 int ui_window_remove_child(ui_window_t *win, ui_window_t *child) {
1484   u_int count;
1485 
1486   for (count = 0; count < win->num_children; count++) {
1487     if (win->children[count] == child) {
1488       child->parent = NULL;
1489 
1490       win->children[count] = win->children[--win->num_children];
1491 
1492       return 1;
1493     }
1494   }
1495 
1496   return 0;
1497 }
1498 
ui_get_root_window(ui_window_t * win)1499 ui_window_t *ui_get_root_window(ui_window_t *win) {
1500   while (win->parent != NULL) {
1501     win = win->parent;
1502   }
1503 
1504   return win;
1505 }
1506 
ui_window_get_fg_gc(ui_window_t * win)1507 GC ui_window_get_fg_gc(ui_window_t *win) { return None; }
1508 
ui_window_get_bg_gc(ui_window_t * win)1509 GC ui_window_get_bg_gc(ui_window_t *win) { return None; }
1510 
ui_window_show(ui_window_t * win,int hint)1511 int ui_window_show(ui_window_t *win,
1512                    int hint /* If win->parent(_window) is None,
1513                                specify XValue|YValue to localte window at win->x/win->y. */
1514                    ) {
1515   u_int count;
1516 
1517   if (win->my_window) {
1518     /* already shown */
1519 
1520     return 0;
1521   }
1522 
1523   if (win->parent) {
1524     win->disp = win->parent->disp;
1525     win->parent_window = win->parent->my_window;
1526     win->gc = win->parent->gc;
1527   }
1528 
1529   win->my_window = win; /* Note that ui_connect_dialog.c uses this. */
1530 
1531   if (win->parent && !win->parent->is_transparent && win->parent->wall_picture) {
1532     ui_window_set_wall_picture(win, ParentRelative, 0);
1533   }
1534 
1535   /*
1536    * This should be called after Window Manager settings, because
1537    * ui_set_{window|icon}_name() can be called in win->window_realized().
1538    */
1539   if (win->window_realized) {
1540     int is_mapped;
1541 
1542     /*
1543      * Don't show anything until ui_window_resize_with_margin() is called
1544      * at the end of this function.
1545      */
1546     is_mapped = win->is_mapped;
1547     win->is_mapped = 0; /* XXX ui_window_set_wall_picture() depends on this. */
1548     (*win->window_realized)(win);
1549     win->is_mapped = is_mapped;
1550   }
1551 
1552   /*
1553    * showing child windows.
1554    */
1555 
1556   for (count = 0; count < win->num_children; count++) {
1557     ui_window_show(win->children[count], 0);
1558   }
1559 
1560 #ifdef MANAGE_ROOT_WINDOWS_BY_MYSELF
1561   if (!win->parent && win->x == 0 && win->y == 0) {
1562     ui_window_resize_with_margin(win, win->disp->width, win->disp->height, NOTIFY_TO_MYSELF);
1563   }
1564 #else
1565   /* win->window_realized() which was executed with is_mapped == 0 doesn't draw anything. */
1566   ui_window_update_all(win);
1567 #endif
1568 
1569   return 1;
1570 }
1571 
ui_window_map(ui_window_t * win)1572 void ui_window_map(ui_window_t *win) {
1573   if (!win->is_mapped) {
1574     win->is_mapped = 1;
1575 
1576     clear_margin_area(win);
1577     (*win->window_exposed)(win, 0, 0, ACTUAL_WIDTH(win), ACTUAL_HEIGHT(win));
1578   }
1579 }
1580 
ui_window_unmap(ui_window_t * win)1581 void ui_window_unmap(ui_window_t *win) {
1582   win->is_mapped = 0;
1583 }
1584 
ui_window_resize(ui_window_t * win,u_int width,u_int height,ui_resize_flag_t flag)1585 int ui_window_resize(ui_window_t *win, u_int width, /* excluding margin */
1586                      u_int height,                  /* excluding margin */
1587                      ui_resize_flag_t flag          /* NOTIFY_TO_PARENT , NOTIFY_TO_MYSELF */
1588                      ) {
1589 #ifdef MANAGE_ROOT_WINDOWS_BY_MYSELF
1590   if ((flag & NOTIFY_TO_PARENT) &&
1591       /* XXX Check if win is input method window or not. */
1592       !IS_IM_WINDOW(win)) {
1593     if (win->parent) {
1594       win = win->parent;
1595     }
1596 
1597     /*
1598      * XXX
1599      * If Font size, screen_{width|height}_ratio or vertical_mode is changed
1600      * and ui_window_resize( NOTIFY_TO_PARENT) is called, ignore this call and
1601      * resize windows with display size.
1602      */
1603     win->width = 0;
1604     return ui_window_resize_with_margin(win, win->disp->width, win->disp->height, NOTIFY_TO_MYSELF);
1605   }
1606 
1607   if (width + win->hmargin * 2 > win->disp->width) {
1608     width = win->disp->width - win->hmargin * 2;
1609   }
1610 
1611   if (height + win->vmargin * 2 > win->disp->height) {
1612     height = win->disp->height - win->vmargin * 2;
1613   }
1614 #endif
1615 
1616   if (win->width == width && win->height == height) {
1617     return 0;
1618   }
1619 
1620 #ifndef MANAGE_ROOT_WINDOWS_BY_MYSELF
1621   if (win->parent == NULL) {
1622     ui_display_resize(win->disp, width + win->hmargin * 2, height + win->vmargin * 2);
1623 #ifdef USE_SDL2
1624     if (win->disp->display->resizing) {
1625       return 1;
1626     }
1627 #endif
1628   } else if (flag & NOTIFY_TO_PARENT) {
1629     return ui_window_resize(win->parent, win->parent->width + width - win->width ,
1630                             win->parent->height + height - win->height,
1631                             NOTIFY_TO_MYSELF);
1632   }
1633 #endif
1634 
1635   win->width = width;
1636   win->height = height;
1637 
1638   if (flag & NOTIFY_TO_MYSELF) {
1639     if (win->window_resized) {
1640       (*win->window_resized)(win);
1641     }
1642 
1643     /*
1644      * clear_margin_area() must be called after win->window_resized
1645      * because wall_picture can be resized to fit to the new window
1646      * size in win->window_resized.
1647      *
1648      * Don't clear_margin_area() if flag == 0 because ui_window_resize()
1649      * is called before ui_window_move() in ui_im_*_screen.c and could
1650      * cause segfault.
1651      */
1652     clear_margin_area(win);
1653   }
1654 
1655 #ifdef USE_WAYLAND
1656   /*
1657    * ui_display_resize() clears screen.
1658    * (win is always root here.)
1659    */
1660   check_update_window(win, 0, 0);
1661 #endif
1662 
1663   return 1;
1664 }
1665 
1666 /*
1667  * !! Notice !!
1668  * This function is not recommended.
1669  * Use ui_window_resize if at all possible.
1670  */
ui_window_resize_with_margin(ui_window_t * win,u_int width,u_int height,ui_resize_flag_t flag)1671 int ui_window_resize_with_margin(ui_window_t *win, u_int width, u_int height,
1672                                  ui_resize_flag_t flag /* NOTIFY_TO_PARENT , NOTIFY_TO_MYSELF */
1673                                  ) {
1674   return ui_window_resize(win, width - win->hmargin * 2, height - win->vmargin * 2, flag);
1675 }
1676 
ui_window_set_maximize_flag(ui_window_t * win,ui_maximize_flag_t flag)1677 void ui_window_set_maximize_flag(ui_window_t *win, ui_maximize_flag_t flag) {
1678 #ifndef MANAGE_ROOT_WINDOWS_BY_MYSELF
1679   if (flag == MAXIMIZE_FULL) {
1680     ui_display_set_maximized(win->disp, 1);
1681   } else if (flag == MAXIMIZE_RESTORE) {
1682     ui_display_set_maximized(win->disp, 0);
1683   }
1684 #endif
1685 }
1686 
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)1687 void ui_window_set_normal_hints(ui_window_t *win, u_int min_width, u_int min_height,
1688                                 u_int width_inc, u_int height_inc) {
1689   win->min_width = min_width;
1690   win->min_height = min_height;
1691   win->width_inc = width_inc;
1692   win->height_inc = height_inc;
1693 }
1694 
ui_window_set_override_redirect(ui_window_t * win,int flag)1695 void ui_window_set_override_redirect(ui_window_t *win, int flag) {}
1696 
ui_window_set_borderless_flag(ui_window_t * win,int flag)1697 int ui_window_set_borderless_flag(ui_window_t *win, int flag) { return 0; }
1698 
ui_window_move(ui_window_t * win,int x,int y)1699 int ui_window_move(ui_window_t *win, int x, int y) {
1700   if (win->parent) {
1701     x += win->parent->hmargin;
1702     y += win->parent->vmargin;
1703   }
1704 #ifndef MANAGE_ROOT_WINDOWS_BY_MYSELF
1705   else {
1706     /*
1707      * Don't do "win->x = x; win->y = y;" here.
1708      * ui_window_xxx(..., x, y) functions add win->x and win->y to x and y arguments,
1709      * but it causes unexpected result because MANAGE_ROOT_WINDOWS_BY_MYSELF means that
1710      * win->x and win->y of root windows are always 0.
1711      */
1712     return ui_display_move(win->disp, x, y);
1713   }
1714 #endif
1715 
1716 
1717   if (win->x == x && win->y == y) {
1718     return 0;
1719   }
1720 
1721   win->x = x;
1722   win->y = y;
1723 
1724   if (/* ! check_child_window_area( ui_get_root_window( win)) || */
1725       win->x + ACTUAL_WIDTH(win) > win->disp->width ||
1726       win->y + ACTUAL_HEIGHT(win) > win->disp->height) {
1727     /*
1728      * XXX Hack
1729      * (Expect the caller to call ui_window_resize() immediately after this.)
1730      */
1731     return 1;
1732   }
1733 
1734   /*
1735    * XXX
1736    * Check if win is input method window or not, because ui_window_move()
1737    * can fall into the following infinite loop on framebuffer.
1738    * 1) ui_im_stat_screen::draw_screen() ->
1739    *    ui_window_move() ->
1740    *    ui_im_stat_screen::window_exposed() ->
1741    *    ui_im_stat_screen::draw_screen()
1742    * 2) ui_im_candidate_screen::draw_screen() ->
1743    *    ui_im_candidate_screen::resize() ->
1744    *    ui_window_move() ->
1745    *    ui_im_candidate_screen::window_exposed() ->
1746    *    ui_im_candidate_screen::draw_screen()
1747    */
1748   if (!IS_IM_WINDOW(win)) {
1749     clear_margin_area(win);
1750 
1751     if (win->window_exposed) {
1752       (*win->window_exposed)(win, 0, 0, win->width, win->height);
1753     }
1754 #if 0
1755     else {
1756       ui_window_clear_all(win);
1757     }
1758 #endif
1759 
1760     /* XXX */
1761     if (win->parent) {
1762       clear_margin_area(win->parent);
1763     }
1764   }
1765 
1766   return 1;
1767 }
1768 
ui_window_clear(ui_window_t * win,int x,int y,u_int width,u_int height)1769 void ui_window_clear(ui_window_t *win, int x, int y, u_int width, u_int height) {
1770 #ifdef USE_GRF
1771   if (x68k_tvram_is_enabled()) {
1772     ui_window_fill_with(win, &black, x, y, width, height);
1773   } else
1774 #endif
1775   if (!win->wall_picture) {
1776     ui_window_fill_with(win, &win->bg_color, x, y, width, height);
1777   } else {
1778     Pixmap pic;
1779     int src_x;
1780     int src_y;
1781 
1782     if (win->wall_picture == ParentRelative) {
1783       src_x = x + win->x;
1784       src_y = y + win->y;
1785       pic = win->parent->wall_picture;
1786     } else {
1787       pic = win->wall_picture;
1788       src_x = x;
1789       src_y = y;
1790     }
1791 
1792     copy_area(win, pic, None, src_x, src_y, width, height, x, y, 1);
1793   }
1794 }
1795 
ui_window_clear_all(ui_window_t * win)1796 void ui_window_clear_all(ui_window_t *win) {
1797   ui_window_clear(win, 0, 0, win->width, win->height);
1798 }
1799 
ui_window_fill(ui_window_t * win,int x,int y,u_int width,u_int height)1800 void ui_window_fill(ui_window_t *win, int x, int y, u_int width, u_int height) {
1801   ui_window_fill_with(win, &win->fg_color, x, y, width, height);
1802 }
1803 
ui_window_fill_with(ui_window_t * win,ui_color_t * color,int x,int y,u_int width,u_int height)1804 void ui_window_fill_with(ui_window_t *win, ui_color_t *color, int x, int y, u_int width,
1805                          u_int height) {
1806   u_char *src;
1807   size_t size;
1808   int y_off;
1809   u_int bpp;
1810   u_long pixel;
1811 
1812   if (!win->is_mapped) {
1813     return;
1814   }
1815 
1816 #if defined(USE_SDL2) && defined(USE_BG_TEXTURE)
1817   if (color->pixel == win->bg_color.pixel) {
1818     pixel = 0;
1819   } else
1820 #endif
1821   {
1822     pixel = color->pixel;
1823   }
1824 
1825   x += (win->x + win->hmargin);
1826   y += (win->y + win->vmargin);
1827 
1828   if ((bpp = win->disp->display->bytes_per_pixel) == 1) {
1829     ui_display_fill_with(x, y, width, height, (u_int8_t)pixel);
1830   } else {
1831     if (!(src = alloca((size = width * bpp)))) {
1832       return;
1833     }
1834 
1835     for (y_off = 0; y_off < height; y_off++) {
1836       u_char *p = src;
1837       int x_off;
1838 
1839       if (bpp == 2) {
1840         for (x_off = 0; x_off < width; x_off++) {
1841           *((u_int16_t *)p) = pixel;
1842           p += 2;
1843         }
1844       } else /* if (bpp == 4) */
1845       {
1846         for (x_off = 0; x_off < width; x_off++) {
1847           *((u_int32_t *)p) = pixel;
1848           p += 4;
1849         }
1850       }
1851 
1852       ui_display_put_image(win->disp, x, y + y_off, src, size, 0);
1853     }
1854   }
1855 }
1856 
ui_window_blank(ui_window_t * win)1857 void ui_window_blank(ui_window_t *win) {
1858   ui_window_fill_with(win, &win->fg_color, 0, 0, win->width - RIGHT_MARGIN(win),
1859                       win->height - BOTTOM_MARGIN(win));
1860 }
1861 
ui_window_update(ui_window_t * win,int flag)1862 void ui_window_update(ui_window_t *win, int flag) {
1863   if (!win->is_mapped) {
1864     return;
1865   }
1866 
1867   if (win->update_window) {
1868     (*win->update_window)(win, flag);
1869   }
1870 }
1871 
ui_window_update_all(ui_window_t * win)1872 void ui_window_update_all(ui_window_t *win) {
1873   u_int count;
1874 
1875   if (!win->is_mapped) {
1876     return;
1877   }
1878 
1879   if (!win->parent) {
1880     ui_display_reset_cmap();
1881   }
1882 
1883   clear_margin_area(win);
1884 
1885   if (win->window_exposed) {
1886     (*win->window_exposed)(win, 0, 0, win->width, win->height);
1887   }
1888 
1889   for (count = 0; count < win->num_children; count++) {
1890     ui_window_update_all(win->children[count]);
1891   }
1892 }
1893 
ui_window_idling(ui_window_t * win)1894 void ui_window_idling(ui_window_t *win) {
1895   u_int count;
1896 
1897   for (count = 0; count < win->num_children; count++) {
1898     ui_window_idling(win->children[count]);
1899   }
1900 
1901 #ifdef __DEBUG
1902   if (win->button_is_pressing) {
1903     bl_debug_printf(BL_DEBUG_TAG " button is pressing...\n");
1904   }
1905 #endif
1906 
1907   if (win->button_is_pressing && win->button_press_continued) {
1908     (*win->button_press_continued)(win, &win->prev_button_press_event);
1909   } else if (win->idling) {
1910     (*win->idling)(win);
1911   }
1912 }
1913 
1914 /*
1915  * Return value: 0 => different window.
1916  *               1 => finished processing.
1917  */
ui_window_receive_event(ui_window_t * win,XEvent * event)1918 int ui_window_receive_event(ui_window_t *win, XEvent *event) {
1919 #if 0
1920   u_int count;
1921 
1922   for (count = 0; count < win->num_children; count++) {
1923     if (ui_window_receive_event(win->children[count], event)) {
1924       return 1;
1925     }
1926   }
1927 #endif
1928 
1929   if (event->type == KeyPress) {
1930     if (win->key_pressed) {
1931       (*win->key_pressed)(win, &event->xkey);
1932     }
1933   } else if (event->type == MotionNotify) {
1934     if (win->button_is_pressing) {
1935       if (win->button_motion) {
1936         event->xmotion.x -= win->hmargin;
1937         event->xmotion.y -= win->vmargin;
1938 
1939         (*win->button_motion)(win, &event->xmotion);
1940       }
1941 
1942       /* following button motion ... */
1943 
1944       win->prev_button_press_event.x = event->xmotion.x;
1945       win->prev_button_press_event.y = event->xmotion.y;
1946       win->prev_button_press_event.time = event->xmotion.time;
1947     } else if ((win->event_mask & PointerMotionMask) && win->pointer_motion) {
1948       event->xmotion.x -= win->hmargin;
1949       event->xmotion.y -= win->vmargin;
1950 
1951       (*win->pointer_motion)(win, &event->xmotion);
1952     }
1953   } else if (event->type == ButtonRelease) {
1954     if (win->button_released) {
1955       event->xbutton.x -= win->hmargin;
1956       event->xbutton.y -= win->vmargin;
1957 
1958       (*win->button_released)(win, &event->xbutton);
1959     }
1960 
1961     win->button_is_pressing = 0;
1962   } else if (event->type == ButtonPress) {
1963     if (win->button_pressed) {
1964       event->xbutton.x -= win->hmargin;
1965       event->xbutton.y -= win->vmargin;
1966 
1967       /* XXX If button is released outside screen, ButtonRelease event might not happen. */
1968       if (win->button_is_pressing) {
1969         if (win->button_released) {
1970           XButtonEvent ev = event->xbutton;
1971           ev.type = ButtonRelease;
1972           (*win->button_released)(win, &ev);
1973         }
1974         win->button_is_pressing = 0;
1975       }
1976 
1977       if (win->click_num == MAX_CLICK) {
1978         win->click_num = 0;
1979       }
1980 
1981       if (win->prev_clicked_time + click_interval >= event->xbutton.time &&
1982           event->xbutton.button == win->prev_clicked_button) {
1983         win->click_num++;
1984         win->prev_clicked_time = event->xbutton.time;
1985       } else {
1986         win->click_num = 1;
1987         win->prev_clicked_time = event->xbutton.time;
1988         win->prev_clicked_button = event->xbutton.button;
1989       }
1990 
1991       (*win->button_pressed)(win, &event->xbutton, win->click_num);
1992     }
1993 
1994     if (event->xbutton.button <= Button3) {
1995       /* button_is_pressing flag is on except wheel mouse (Button4/Button5). */
1996       win->button_is_pressing = 1;
1997       win->prev_button_press_event = event->xbutton;
1998     }
1999 
2000     if (!win->is_focused && win->inputtable && event->xbutton.button == Button1 &&
2001         !event->xbutton.state) {
2002       ui_window_set_input_focus(win);
2003     }
2004   }
2005 #ifndef MANAGE_ROOT_WINDOWS_BY_MYSELF
2006   else if (event->type == FocusOut) {
2007     reset_input_focus(win);
2008   }
2009 #endif
2010 
2011   return 1;
2012 }
2013 
ui_window_get_str(ui_window_t * win,u_char * seq,size_t seq_len,ef_parser_t ** parser,KeySym * keysym,XKeyEvent * event)2014 size_t ui_window_get_str(ui_window_t *win, u_char *seq, size_t seq_len, ef_parser_t **parser,
2015                          KeySym *keysym, XKeyEvent *event) {
2016   u_int32_t ch;
2017 
2018   if (seq_len == 0) {
2019     return 0;
2020   }
2021 
2022   *parser = NULL;
2023 
2024 #ifdef USE_WAYLAND
2025   *keysym = event->ksym;
2026   {
2027     u_char buf[7]; /* UTF_MAX_SIZE + 1 */
2028     size_t len = ui_display_get_utf8(buf, event->ksym);
2029 
2030     if (len >= 2) {
2031       if (seq_len >= len) {
2032         static ef_parser_t *utf8_parser;
2033 
2034         if (utf8_parser == NULL) {
2035           utf8_parser = ef_utf8_parser_new(); /* XXX leaked */
2036         }
2037 
2038         *parser = utf8_parser;
2039         memcpy(seq, buf, len);
2040       }
2041 
2042       return len;
2043     } else if (len == 0) {
2044       return 0;
2045     } else {
2046       ch = buf[0];
2047     }
2048   }
2049 #else
2050 #ifdef USE_SDL2
2051   if (event->str) {
2052     size_t len = strlen(event->str);
2053     if (len <= seq_len) {
2054       strncpy(seq, event->str, len);
2055       *parser = event->parser;
2056       *keysym = event->ksym;
2057     }
2058 
2059     return len;
2060   }
2061 #endif
2062 
2063   ch = event->ksym;
2064 
2065 #ifdef __ANDROID__
2066   if (ch == 0) {
2067     return ui_display_get_str(seq, seq_len);
2068   }
2069 #endif
2070 
2071   if ((*keysym = event->ksym) >= 0x100) {
2072 #ifndef USE_SDL2
2073 #if defined(__linux__) || defined(__FreeBSD__)
2074     /*
2075      * Linux:
2076      * 0x00-0xff  : ASCII + ISO8859-1-R
2077      * 0x100-0x263: Function Keys (Max: KEY_CLEAR(0x163) + 0x100)
2078      * 0x1000-    : Unicode (Use after decrement 0x1000) (See kcode_to_ksym() in ui_display_linux.c)
2079      *
2080      * FreeBSD:
2081      * 0x00-0xff  : ASCII + ISO8859-1-R
2082      * 0x100-0x256: Function Keys (Max: KEY_KP0(0x156) + 0x100)
2083      * 0x1100-    : Unicode (Use after decrement 0x1000)
2084      *              (See receive_key_event() in ui_display_freebsd.c)
2085      */
2086     if (*keysym >= 0x1000) {
2087       ch -= 0x1000;
2088 
2089       goto ucs;
2090     } else
2091 #endif
2092 #endif
2093     {
2094       switch (*keysym) {
2095       case XK_KP_Multiply:
2096         ch = '*';
2097         break;
2098       case XK_KP_Add:
2099         ch = '+';
2100         break;
2101       case XK_KP_Separator:
2102         ch = ',';
2103         break;
2104       case XK_KP_Subtract:
2105         ch = '-';
2106         break;
2107       case XK_KP_Divide:
2108         ch = '/';
2109         break;
2110 
2111       default:
2112         if (win->disp->display->lock_state & NLKED) {
2113           switch (*keysym) {
2114           case XK_KP_Insert:
2115             ch = '0';
2116             break;
2117           case XK_KP_End:
2118             ch = '1';
2119             break;
2120           case XK_KP_Down:
2121             ch = '2';
2122             break;
2123           case XK_KP_Next:
2124             ch = '3';
2125             break;
2126           case XK_KP_Left:
2127             ch = '4';
2128             break;
2129           case XK_KP_Begin:
2130             ch = '5';
2131             break;
2132           case XK_KP_Right:
2133             ch = '6';
2134             break;
2135           case XK_KP_Home:
2136             ch = '7';
2137             break;
2138           case XK_KP_Up:
2139             ch = '8';
2140             break;
2141           case XK_KP_Prior:
2142             ch = '9';
2143             break;
2144           case XK_KP_Delete:
2145             ch = '.';
2146             break;
2147           default:
2148             return 0;
2149           }
2150 
2151           *keysym = ch;
2152         } else {
2153           return 0;
2154         }
2155       }
2156     }
2157   } else if (*keysym == XK_Tab && (event->state & ShiftMask)) {
2158     *keysym = XK_ISO_Left_Tab;
2159 
2160     return 0;
2161   }
2162 #endif
2163 
2164   /*
2165    * Control + '@'(0x40) ... '_'(0x5f) -> 0x00 ... 0x1f
2166    *
2167    * Not "<= '_'" but "<= 'z'" because Control + 'a' is not
2168    * distinguished from Control + 'A'.
2169    */
2170   if (ch < 0x80) {
2171     if ((event->state & ControlMask) && (ch == ' ' || ('@' <= ch && ch <= 'z'))) {
2172       seq[0] = (ch & 0x1f);
2173     } else {
2174       seq[0] = ch;
2175     }
2176 
2177     return 1;
2178   }
2179 
2180 ucs:
2181   if (seq_len >= 2) {
2182     static ef_parser_t *utf16_parser;
2183 
2184     if (utf16_parser == NULL) {
2185       utf16_parser = ef_utf16_parser_new(); /* XXX leaked */
2186     }
2187 
2188     *parser = utf16_parser;
2189 
2190     seq[0] = (ch >> 8) & 0xff;
2191     seq[1] = ch & 0xff;
2192 
2193     /*
2194      * Disable mod_meta_mode for UTF-16.
2195      * e.g.) "mod_meta_mode = 8bit" modifies 0x20AC to 0xA0AC.
2196      *       (see key_pressed() in ui_screen.c
2197      */
2198     event->state &= ~ModMask;
2199   }
2200 
2201   return 2;
2202 }
2203 
2204 /*
2205  * Scroll functions.
2206  * The caller side should clear the scrolled area.
2207  */
2208 
ui_window_scroll_upward(ui_window_t * win,u_int height)2209 int ui_window_scroll_upward(ui_window_t *win, u_int height) {
2210   return ui_window_scroll_upward_region(win, 0, win->height, height);
2211 }
2212 
2213 #ifdef MANAGE_ROOT_WINDOWS_BY_MYSELF
ui_window_is_scrollable(ui_window_t * win)2214 int ui_window_is_scrollable(ui_window_t *win) {
2215   /* XXX If input method module is activated, don't scroll window. */
2216   if (win->is_scrollable && !IM_WINDOW_IS_ACTIVATED(win->disp)) {
2217     return 1;
2218   } else {
2219     return 0;
2220   }
2221 }
2222 #endif
2223 
ui_window_scroll_upward_region(ui_window_t * win,int boundary_start,int boundary_end,u_int height)2224 int ui_window_scroll_upward_region(ui_window_t *win, int boundary_start, int boundary_end,
2225                                    u_int height) {
2226   if (boundary_start < 0 || boundary_end > win->height || boundary_end <= boundary_start + height) {
2227 #ifdef DEBUG
2228     bl_warn_printf(BL_DEBUG_TAG " boundary start %d end %d height %d in window((h) %d (w) %d)\n",
2229                    boundary_start, boundary_end, height, win->height, win->width);
2230 #endif
2231 
2232     return 0;
2233   }
2234 
2235   return scroll_region(win, 0, boundary_start + height,                    /* src */
2236                        win->width, boundary_end - boundary_start - height, /* size */
2237                        0, boundary_start);                                 /* dst */
2238 }
2239 
ui_window_scroll_downward(ui_window_t * win,u_int height)2240 int ui_window_scroll_downward(ui_window_t *win, u_int height) {
2241   return ui_window_scroll_downward_region(win, 0, win->height, height);
2242 }
2243 
ui_window_scroll_downward_region(ui_window_t * win,int boundary_start,int boundary_end,u_int height)2244 int ui_window_scroll_downward_region(ui_window_t *win, int boundary_start, int boundary_end,
2245                                      u_int height) {
2246   if (boundary_start < 0 || boundary_end > win->height || boundary_end <= boundary_start + height) {
2247 #ifdef DEBUG
2248     bl_warn_printf(BL_DEBUG_TAG " boundary start %d end %d height %d\n", boundary_start,
2249                    boundary_end, height);
2250 #endif
2251 
2252     return 0;
2253   }
2254 
2255   return scroll_region(win, 0, boundary_start, win->width, boundary_end - boundary_start - height,
2256                        0, boundary_start + height);
2257 }
2258 
ui_window_scroll_leftward(ui_window_t * win,u_int width)2259 int ui_window_scroll_leftward(ui_window_t *win, u_int width) {
2260   return ui_window_scroll_leftward_region(win, 0, win->width, width);
2261 }
2262 
ui_window_scroll_leftward_region(ui_window_t * win,int boundary_start,int boundary_end,u_int width)2263 int ui_window_scroll_leftward_region(ui_window_t *win, int boundary_start, int boundary_end,
2264                                      u_int width) {
2265   if (boundary_start < 0 || boundary_end > win->width || boundary_end <= boundary_start + width ||
2266       !fix_rl_boundary(win, boundary_start, &boundary_end)) {
2267 #ifdef DEBUG
2268     bl_warn_printf(BL_DEBUG_TAG " boundary start %d end %d width %d in window((h) %d (w) %d)\n",
2269                    boundary_start, boundary_end, width, win->height, win->width);
2270 #endif
2271 
2272     return 0;
2273   }
2274 
2275   scroll_region(win, boundary_start + width, 0,                     /* src */
2276                 boundary_end - boundary_start - width, win->height, /* size */
2277                 boundary_start, 0);                                 /* dst */
2278 
2279   return 1;
2280 }
2281 
ui_window_scroll_rightward(ui_window_t * win,u_int width)2282 int ui_window_scroll_rightward(ui_window_t *win, u_int width) {
2283   return ui_window_scroll_rightward_region(win, 0, win->width, width);
2284 }
2285 
ui_window_scroll_rightward_region(ui_window_t * win,int boundary_start,int boundary_end,u_int width)2286 int ui_window_scroll_rightward_region(ui_window_t *win, int boundary_start, int boundary_end,
2287                                       u_int width) {
2288   if (boundary_start < 0 || boundary_end > win->width || boundary_end <= boundary_start + width ||
2289       !fix_rl_boundary(win, boundary_start, &boundary_end)) {
2290 #ifdef DEBUG
2291     bl_warn_printf(BL_DEBUG_TAG " boundary start %d end %d width %d\n", boundary_start,
2292                    boundary_end, width);
2293 #endif
2294 
2295     return 0;
2296   }
2297 
2298   scroll_region(win, boundary_start, 0, boundary_end - boundary_start - width, win->height,
2299                 boundary_start + width, 0);
2300 
2301   return 1;
2302 }
2303 
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)2304 int ui_window_copy_area(ui_window_t *win, Pixmap src, PixmapMask mask, int src_x, /* >= 0 */
2305                         int src_y,                                                /* >= 0 */
2306                         u_int width, u_int height, int dst_x,                     /* >= 0 */
2307                         int dst_y                                                 /* >= 0 */
2308                         ) {
2309   return copy_area(win, src, mask, src_x, src_y, width, height, dst_x, dst_y, 0);
2310 }
2311 
ui_window_set_clip(ui_window_t * win,int x,int y,u_int width,u_int height)2312 void ui_window_set_clip(ui_window_t *win, int x, int y, u_int width, u_int height) {
2313   win->clip_y = y;
2314   win->clip_height = height;
2315 }
2316 
ui_window_unset_clip(ui_window_t * win)2317 void ui_window_unset_clip(ui_window_t *win) { win->clip_y = win->clip_height = 0; }
2318 
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)2319 void ui_window_draw_decsp_string(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color, int x,
2320                                  int y, u_char *str, u_int len) {
2321   convert_to_decsp_font_index(str, len);
2322 
2323   ui_window_draw_string(win, font, fg_color, x, y, str, len);
2324 }
2325 
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)2326 void ui_window_draw_decsp_image_string(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color,
2327                                        ui_color_t *bg_color, /* NULL => use wall_picture for bg */
2328                                        int x, int y, u_char *str, u_int len) {
2329   convert_to_decsp_font_index(str, len);
2330 
2331   ui_window_draw_image_string(win, font, fg_color, bg_color, x, y, str, len);
2332 }
2333 
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)2334 void ui_window_draw_string(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color, int x, int y,
2335                            u_char *str, u_int len) {
2336   draw_string(win, font, fg_color, NULL, x, y, str, len, 1, 0);
2337 }
2338 
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)2339 void ui_window_draw_string16(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color, int x, int y,
2340                              XChar2b *str, u_int len) {
2341   draw_string(win, font, fg_color, NULL, x, y, str, len, 2, 0);
2342 }
2343 
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)2344 void ui_window_draw_image_string(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color,
2345                                  ui_color_t *bg_color, /* NULL => use wall_picture for bg */
2346                                  int x, int y, u_char *str, u_int len) {
2347 #ifdef USE_GRF
2348   if (bg_color == NULL && x68k_tvram_is_enabled()) {
2349     bg_color = &black;
2350   }
2351 #endif
2352 
2353   draw_string(win, font, fg_color, bg_color, x, y, str, len, 1, bg_color == NULL);
2354 }
2355 
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)2356 void ui_window_draw_image_string16(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color,
2357                                    ui_color_t *bg_color, /* NULL => use wall_picture for bg */
2358                                    int x, int y, XChar2b *str, u_int len) {
2359 #ifdef USE_GRF
2360   if (bg_color == NULL && x68k_tvram_is_enabled()) {
2361     bg_color = &black;
2362   }
2363 #endif
2364 
2365   draw_string(win, font, fg_color, bg_color, x, y, str, len, 2, bg_color == NULL);
2366 }
2367 
ui_window_draw_rect_frame(ui_window_t * win,int x1,int y1,int x2,int y2)2368 void ui_window_draw_rect_frame(ui_window_t *win, int x1, int y1, int x2, int y2) {
2369   ui_window_fill_with(win, &win->fg_color, x1, y1, x2 - x1 + 1, 1);
2370   ui_window_fill_with(win, &win->fg_color, x1, y1, 1, y2 - y1 + 1);
2371   ui_window_fill_with(win, &win->fg_color, x1, y2, x2 - x1 + 1, 1);
2372   ui_window_fill_with(win, &win->fg_color, x2, y1, 1, y2 - y1 + 1);
2373 }
2374 
ui_set_use_clipboard_selection(int use_it)2375 void ui_set_use_clipboard_selection(int use_it) {}
2376 
ui_is_using_clipboard_selection(void)2377 int ui_is_using_clipboard_selection(void) { return 0; }
2378 
ui_window_set_selection_owner(ui_window_t * win,Time time)2379 int ui_window_set_selection_owner(ui_window_t *win, Time time) {
2380 #ifndef USE_SDL2
2381   if (ui_window_is_selection_owner(win)) {
2382     /* Already owner */
2383   } else
2384 #endif
2385   {
2386     ui_display_own_selection(win->disp, win);
2387   }
2388 
2389 #ifdef __ANDROID__
2390   if (win->utf_selection_requested) {
2391     (*win->utf_selection_requested)(win, NULL, 0);
2392   }
2393 #endif
2394 
2395   return 1;
2396 }
2397 
ui_window_xct_selection_request(ui_window_t * win,Time time)2398 int ui_window_xct_selection_request(ui_window_t *win, Time time) {
2399 #if defined(__ANDROID__) || defined(USE_WAYLAND)
2400   return 0;
2401 #else
2402   if (win->disp->selection_owner && win->disp->selection_owner->xct_selection_requested) {
2403     XSelectionRequestEvent ev;
2404     ev.type = 0;
2405     ev.target = win;
2406     (*win->disp->selection_owner->xct_selection_requested)(win->disp->selection_owner, &ev, 0);
2407   }
2408 
2409   return 1;
2410 #endif
2411 }
2412 
ui_window_utf_selection_request(ui_window_t * win,Time time)2413 int ui_window_utf_selection_request(ui_window_t *win, Time time) {
2414 #if defined(__ANDROID__)
2415   ui_display_request_text_selection();
2416 #elif defined(USE_WAYLAND) || defined(USE_SDL2)
2417   ui_display_request_text_selection(win->disp);
2418 #else
2419   if (win->disp->selection_owner && win->disp->selection_owner->utf_selection_requested) {
2420     XSelectionRequestEvent ev;
2421     ev.type = 1;
2422     ev.target = win;
2423     (*win->disp->selection_owner->utf_selection_requested)(win->disp->selection_owner, &ev, 0);
2424   }
2425 #endif
2426 
2427   return 1;
2428 }
2429 
ui_window_send_picture_selection(ui_window_t * win,Pixmap pixmap,u_int width,u_int height)2430 void ui_window_send_picture_selection(ui_window_t *win, Pixmap pixmap, u_int width, u_int height) {}
2431 
ui_window_send_text_selection(ui_window_t * win,XSelectionRequestEvent * req_ev,u_char * sel_data,size_t sel_len,Atom sel_type)2432 void ui_window_send_text_selection(ui_window_t *win, XSelectionRequestEvent *req_ev,
2433                                    u_char *sel_data, size_t sel_len, Atom sel_type) {
2434 #if defined(__ANDROID__)
2435   ui_display_send_text_selection(sel_data, sel_len);
2436 #elif defined(USE_WAYLAND) || defined(USE_SDL2)
2437   ui_display_send_text_selection(win->disp, req_ev, sel_data, sel_len);
2438 #else
2439   if (req_ev) {
2440     if (req_ev->type == 1) {
2441       if (req_ev->target->utf_selection_notified) {
2442         (*req_ev->target->utf_selection_notified)(req_ev->target, sel_data, sel_len);
2443       }
2444     } else {
2445       if (req_ev->target->xct_selection_notified) {
2446         (*req_ev->target->xct_selection_notified)(req_ev->target, sel_data, sel_len);
2447       }
2448     }
2449   }
2450 #endif
2451 }
2452 
ui_set_window_name(ui_window_t * win,u_char * name)2453 void ui_set_window_name(ui_window_t *win, u_char *name) {
2454 #ifndef MANAGE_ROOT_WINDOWS_BY_MYSELF
2455   if (name == NULL) {
2456     name = win->app_name;
2457   }
2458 
2459   ui_display_set_title(win->disp, name);
2460 #endif
2461 }
2462 
ui_set_icon_name(ui_window_t * win,u_char * name)2463 void ui_set_icon_name(ui_window_t *win, u_char *name) {}
2464 
ui_window_set_icon(ui_window_t * win,ui_icon_picture_ptr_t icon)2465 void ui_window_set_icon(ui_window_t *win, ui_icon_picture_ptr_t icon) {}
2466 
ui_window_remove_icon(ui_window_t * win)2467 void ui_window_remove_icon(ui_window_t *win) {}
2468 
ui_window_reset_group(ui_window_t * win)2469 void ui_window_reset_group(ui_window_t *win) {}
2470 
ui_set_click_interval(int interval)2471 void ui_set_click_interval(int interval) {
2472   click_interval = interval;
2473 }
2474 
ui_get_click_interval(void)2475 int ui_get_click_interval(void) {
2476   return click_interval;
2477 }
2478 
ui_window_get_mod_ignore_mask(ui_window_t * win,KeySym * keysyms)2479 u_int ui_window_get_mod_ignore_mask(ui_window_t *win, KeySym *keysyms) {
2480   return ~0;
2481 }
2482 
ui_window_get_mod_meta_mask(ui_window_t * win,char * mod_key)2483 u_int ui_window_get_mod_meta_mask(ui_window_t *win, char *mod_key) { return ModMask; }
2484 
ui_window_bell(ui_window_t * win,ui_bel_mode_t mode)2485 void ui_window_bell(ui_window_t *win, ui_bel_mode_t mode) {
2486   if (mode & BEL_VISUAL) {
2487     ui_window_blank(win);
2488     bl_usleep(100000); /* 100 mili sec */
2489     (*win->window_exposed)(win, 0, 0, win->width, win->height);
2490   }
2491 }
2492 
ui_window_translate_coordinates(ui_window_t * win,int x,int y,int * global_x,int * global_y)2493 void ui_window_translate_coordinates(ui_window_t *win, int x, int y, int *global_x, int *global_y) {
2494   *global_x = x + win->x;
2495   *global_y = y + win->y;
2496 
2497 #if defined(ROTATABLE_DISPLAY) && !defined(MANAGE_ROOT_WINDOWS_BY_MYSELF)
2498   /* USE_WAYLAND|USE_SDL2 */
2499   ui_display_logical_to_physical_coordinates(win->disp, global_x, global_y);
2500 #endif
2501 }
2502 
ui_window_set_input_focus(ui_window_t * win)2503 void ui_window_set_input_focus(ui_window_t *win) {
2504   if (win->inputtable > 0 && win->is_focused) {
2505     return;
2506   }
2507 
2508   reset_input_focus(ui_get_root_window(win));
2509   win->inputtable = win->is_focused = 1;
2510   if (win->window_focused) {
2511     (*win->window_focused)(win);
2512   }
2513 }
2514 
2515 /* for ui_display.c */
2516 
ui_window_clear_margin_area(ui_window_t * win)2517 void ui_window_clear_margin_area(ui_window_t *win) { clear_margin_area(win); }
2518