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