1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2 
3 #include "ui_window.h"
4 
5 #include <stdlib.h> /* abs */
6 #include <string.h> /* memset/memcpy */
7 #include <pobl/bl_debug.h>
8 #include <pobl/bl_mem.h>  /* realloc/free */
9 
10 #include "../ui_xic.h"
11 #include "../ui_picture.h"
12 #include "../ui_imagelib.h"
13 #ifndef DISABLE_XDND
14 #include "../ui_dnd.h"
15 #endif
16 
17 #include "ui_display.h" /* ui_display_get_cursor */
18 #include "beos.h"
19 
20 /* win->width is not multiples of (win)->width_inc if window is maximized. */
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 #define ParentRelative (1L)
27 
28 #define IS_UILAYOUT(win) ((win)->child_window_resized)
29 #define IS_IM_WINDOW(win) ((win)->window_resized == NULL)
30 
31 #if 0
32 #define DEBUG_SCROLLABLE
33 #endif
34 
35 #if 0
36 #define __DEBUG
37 #endif
38 
39 /* --- static variables --- */
40 
41 static int click_interval = 250; /* millisecond, same as xterm. */
42 static int use_urgent_bell;
43 
44 /* --- static functions --- */
45 
urgent_bell(ui_window_t * win,int on)46 static void urgent_bell(ui_window_t *win, int on) {
47   if (use_urgent_bell && (!win->is_focused || !on)) {
48     win = ui_get_root_window(win);
49 
50     app_urgent_bell(on);
51   }
52 }
53 
notify_focus_in_to_children(ui_window_t * win)54 static void notify_focus_in_to_children(ui_window_t *win) {
55   u_int count;
56 
57   if (!win->is_focused) {
58     if (win->inputtable > 0 || win->parent == NULL) /* check_scrollable checks root->is_focused */
59     {
60       win->is_focused = 1;
61     }
62 
63     if (win->inputtable > 0) {
64       ui_xic_set_focus(win);
65 
66       if (win->window_focused) {
67         (*win->window_focused)(win);
68       }
69     }
70   }
71 
72   for (count = 0; count < win->num_children; count++) {
73     notify_focus_in_to_children(win->children[count]);
74   }
75 }
76 
notify_focus_out_to_children(ui_window_t * win)77 static void notify_focus_out_to_children(ui_window_t *win) {
78   u_int count;
79 
80   if (win->is_focused) {
81     win->is_focused = 0;
82 
83     ui_xic_unset_focus(win);
84 
85     if (win->window_unfocused) {
86       (*win->window_unfocused)(win);
87     }
88   }
89 
90   for (count = 0; count < win->num_children; count++) {
91     notify_focus_out_to_children(win->children[count]);
92   }
93 }
94 
notify_move_to_children(ui_window_t * win)95 static void notify_move_to_children(ui_window_t *win) {
96   int count;
97 
98   for (count = 0; count < win->num_children; count++) {
99     notify_move_to_children(win->children[count]);
100   }
101 }
102 
max_width_inc(ui_window_t * win)103 static u_int max_width_inc(ui_window_t *win) {
104   u_int count;
105   u_int width_inc;
106 
107   width_inc = win->width_inc;
108 
109   for (count = 0; count < win->num_children; count++) {
110     if (win->children[count]->is_mapped &&
111         (win->children[count]->sizehint_flag & SIZEHINT_WIDTH)) {
112       u_int sub_inc;
113 
114       /*
115        * XXX
116        * we should calculate least common multiple of width_inc and sub_inc.
117        */
118       if ((sub_inc = max_width_inc(win->children[count])) > width_inc) {
119         width_inc = sub_inc;
120       }
121     }
122   }
123 
124   return width_inc;
125 }
126 
max_height_inc(ui_window_t * win)127 static u_int max_height_inc(ui_window_t *win) {
128   u_int count;
129   u_int height_inc;
130 
131   height_inc = win->height_inc;
132 
133   for (count = 0; count < win->num_children; count++) {
134     if (win->children[count]->is_mapped &&
135         (win->children[count]->sizehint_flag & SIZEHINT_HEIGHT)) {
136       u_int sub_inc;
137 
138       /*
139        * XXX
140        * we should calculate least common multiple of width_inc and sub_inc.
141        */
142       if ((sub_inc = max_height_inc(win->children[count])) > height_inc) {
143         height_inc = sub_inc;
144       }
145     }
146   }
147 
148   return height_inc;
149 }
150 
reset_input_focus(ui_window_t * win)151 static void reset_input_focus(ui_window_t *win) {
152   u_int count;
153 
154   if (win->inputtable) {
155     win->inputtable = -1;
156   } else {
157     win->inputtable = 0;
158   }
159 
160   for (count = 0; count < win->num_children; count++) {
161     reset_input_focus(win->children[count]);
162   }
163 }
164 
clear_margin_area(ui_window_t * win)165 static void clear_margin_area(ui_window_t *win) {
166   void *view;
167   u_int right_margin;
168   u_int bottom_margin;
169   u_int win_width;
170   u_int win_height;
171 
172   if (win->parent) {
173     view = win->my_window;
174   } else if (!(view = window_get_orphan(win->my_window, 0))) {
175     return;
176   }
177 
178   right_margin = RIGHT_MARGIN(win);
179   bottom_margin = BOTTOM_MARGIN(win);
180   win_width = win->width - right_margin;
181   win_height = win->height - bottom_margin;
182 
183   if (win->wall_picture) {
184     Pixmap pic;
185     int src_x;
186     int src_y;
187 
188     if (win->wall_picture == ParentRelative) {
189       pic = win->parent->wall_picture;
190       src_x = win->x;
191       src_y = win->y;
192     } else {
193       pic = win->wall_picture;
194       src_x = src_y = 0;
195     }
196 
197     if (win->hmargin > 0 || right_margin > 0) {
198       view_copy_area(view, pic, src_x, src_y, win->hmargin, ACTUAL_HEIGHT(win), 0, 0);
199       view_copy_area(view, pic, src_x + win_width + win->hmargin, src_y,
200                      win->hmargin + right_margin, ACTUAL_HEIGHT(win), win_width + win->hmargin, 0);
201     }
202 
203     if (win->vmargin > 0 || bottom_margin > 0) {
204       view_copy_area(view, pic, src_x + win->hmargin, src_y, win_width, win->vmargin,
205                      win->hmargin, 0);
206       view_copy_area(view, pic, src_x + win->hmargin, src_y + win_height + win->vmargin,
207                      win_width, win->vmargin + bottom_margin, win->hmargin,
208                      win_height + win->vmargin);
209     }
210   } else {
211     if (win->hmargin > 0 || right_margin > 0) {
212       view_fill_with(view, &win->bg_color, 0, 0, win->hmargin, ACTUAL_HEIGHT(win));
213       view_fill_with(view, &win->bg_color, win_width + win->hmargin, 0,
214                      ACTUAL_WIDTH(win) - win_width - win->hmargin, ACTUAL_HEIGHT(win));
215     }
216 
217     if (win->vmargin > 0 || bottom_margin > 0) {
218       view_fill_with(view, &win->bg_color, win->hmargin, 0, win_width, win->vmargin);
219       view_fill_with(view, &win->bg_color, win->hmargin, win_height + win->vmargin,
220                      win_width, ACTUAL_HEIGHT(win) - win_height - win->vmargin);
221     }
222   }
223 }
224 
clear_margin_area_all(ui_window_t * win)225 static void clear_margin_area_all(ui_window_t *win) {
226   u_int count;
227 
228   clear_margin_area(win);
229 
230   for (count = 0; count < win->num_children; count++) {
231     clear_margin_area_all(win->children[count]);
232   }
233 }
234 
expose(ui_window_t * win,XExposeEvent * event)235 static void expose(ui_window_t *win, XExposeEvent *event) {
236   int clear_margin;
237 
238   if (event->force_expose) {
239     event->x = win->hmargin;
240     event->y = win->vmargin;
241     event->width = win->width;
242     event->height = win->height;
243     clear_margin = 1;
244   } else if (win->update_window_flag) {
245     if (win->update_window) {
246       (*win->update_window)(win, win->update_window_flag);
247     }
248 
249     return;
250   } else {
251     clear_margin = 0;
252 
253     if (event->x < win->hmargin) {
254       event->width -= (win->hmargin - event->x);
255       event->x = win->hmargin;
256       clear_margin = 1;
257     }
258 
259     if (event->y < win->vmargin) {
260       event->height -= (win->vmargin - event->y);
261       event->y = win->vmargin;
262       clear_margin = 1;
263     }
264 
265     if (!clear_margin && (event->x + event->width > win->hmargin + win->width ||
266                           event->y + event->height > win->vmargin + win->height)) {
267       clear_margin = 1;
268     }
269   }
270 
271   if (clear_margin) {
272     clear_margin_area(win);
273   }
274 
275   if (win->window_exposed) {
276     (*win->window_exposed)(win, event->x - win->hmargin, event->y - win->vmargin, event->width,
277                            event->height);
278   }
279 }
280 
281 /* --- global functions --- */
282 
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)283 int ui_window_init(ui_window_t *win, u_int width, u_int height, u_int min_width, u_int min_height,
284                    u_int width_inc, u_int height_inc, u_int hmargin, u_int vmargin,
285                    int create_gc, /* ignored */
286                    int inputtable) {
287   memset(win, 0, sizeof(ui_window_t));
288 
289   win->fg_color.pixel = 0xff000000;
290   win->bg_color.pixel = 0xffffffff;
291 
292   win->is_scrollable = 0;
293 
294   win->is_focused = 0;
295 
296   win->inputtable = inputtable;
297 
298   /* This flag will map window automatically in ui_window_show(). */
299   win->is_mapped = 1;
300 
301   win->create_gc = create_gc;
302 
303   win->width = width;
304   win->height = height;
305   win->min_width = min_width;
306   win->min_height = min_height;
307   win->width_inc = width_inc;
308   win->height_inc = height_inc;
309   win->sizehint_flag = SIZEHINT_WIDTH|SIZEHINT_HEIGHT;
310   win->hmargin = hmargin;
311   win->vmargin = vmargin;
312 
313   win->prev_clicked_button = -1;
314 
315   win->app_name = "mlterm";
316 
317   return 1;
318 }
319 
ui_window_final(ui_window_t * win)320 void ui_window_final(ui_window_t *win) {
321   u_int count;
322   Window my_window;
323   int is_window;
324 
325 #ifdef __DEBUG
326   bl_debug_printf("[deleting child windows]\n");
327   ui_window_dump_children(win);
328 #endif
329 
330   for (count = 0; count < win->num_children; count++) {
331     ui_window_final(win->children[count]);
332   }
333 
334   my_window = win->my_window;
335   if (win->my_window) {
336     /*
337      * win->parent may be NULL because this function is called
338      * from ui_layout after ui_window_remove_child(),
339      * not only win->parent but also IS_UILAYOUT(win) is necessary.
340      */
341     if (!win->parent && (IS_UILAYOUT(win) || IS_IM_WINDOW(win))) {
342       is_window = 1;
343     } else {
344       is_window = -1;
345     }
346 
347     win->my_window = None;
348   } else {
349     is_window = 0;
350   }
351 
352   free(win->children);
353   win->num_children = 0;
354 
355   ui_display_clear_selection(win->disp, win);
356 
357   ui_xic_deactivate(win);
358 
359   if (win->window_finalized) {
360     (*win->window_finalized)(win);
361   }
362 
363   if (is_window == 1) {
364     window_dealloc(my_window);
365     /* Not reach. */
366   } else if (is_window == -1) {
367     view_dealloc(my_window);
368   }
369 }
370 
ui_window_set_type_engine(ui_window_t * win,ui_type_engine_t type_engine)371 void ui_window_set_type_engine(ui_window_t *win, ui_type_engine_t type_engine) {}
372 
ui_window_add_event_mask(ui_window_t * win,long event_mask)373 void ui_window_add_event_mask(ui_window_t *win, long event_mask) {
374   if (event_mask & PointerMotionMask) {
375     win->event_mask = PointerMotionMask;
376   }
377 }
378 
ui_window_remove_event_mask(ui_window_t * win,long event_mask)379 void ui_window_remove_event_mask(ui_window_t *win, long event_mask) {
380   if (event_mask & PointerMotionMask) {
381     win->event_mask = 0;
382   }
383 }
384 
ui_window_ungrab_pointer(ui_window_t * win)385 void ui_window_ungrab_pointer(ui_window_t *win) {}
386 
ui_window_set_wall_picture(ui_window_t * win,Pixmap pic,int do_expose)387 int ui_window_set_wall_picture(ui_window_t *win, Pixmap pic, int do_expose) {
388   u_int count;
389 
390   win->wall_picture = pic;
391 
392 #if 1
393   if (win->my_window != None && do_expose) {
394     if (win->parent) {
395       view_update(win->my_window, 1);
396     } else {
397       void *view;
398 
399       if ((view = window_get_orphan(win->my_window, 0))) {
400         view_update(view, 1);
401       }
402     }
403   }
404 #endif
405 
406   for (count = 0; count < win->num_children; count++) {
407     ui_window_set_wall_picture(win->children[count], ParentRelative, do_expose);
408   }
409 
410   return 1;
411 }
412 
ui_window_unset_wall_picture(ui_window_t * win,int do_expose)413 int ui_window_unset_wall_picture(ui_window_t *win, int do_expose) {
414   u_int count;
415 
416   win->wall_picture = None;
417 
418   if (win->my_window != None) {
419 #if 0
420     InvalidateRect(win->my_window, NULL, FALSE);
421 #endif
422   }
423 
424   for (count = 0; count < win->num_children; count++) {
425     ui_window_unset_wall_picture(win->children[count], do_expose);
426   }
427 
428   return 1;
429 }
430 
ui_window_set_transparent(ui_window_t * win,ui_picture_modifier_t * pic_mod)431 int ui_window_set_transparent(ui_window_t *win, ui_picture_modifier_t *pic_mod) { return 0; }
432 
ui_window_unset_transparent(ui_window_t * win)433 int ui_window_unset_transparent(ui_window_t *win) { return 0; }
434 
ui_window_set_cursor(ui_window_t * win,u_int cursor_shape)435 void ui_window_set_cursor(ui_window_t *win, u_int cursor_shape) {
436   win->cursor_shape = cursor_shape;
437 }
438 
ui_window_set_fg_color(ui_window_t * win,ui_color_t * fg_color)439 int ui_window_set_fg_color(ui_window_t *win, ui_color_t *fg_color) {
440   if (win->fg_color.pixel == fg_color->pixel) {
441     return 0;
442   }
443 
444   win->fg_color = *fg_color;
445 
446   return 1;
447 }
448 
ui_window_set_bg_color(ui_window_t * win,ui_color_t * bg_color)449 int ui_window_set_bg_color(ui_window_t *win, ui_color_t *bg_color) {
450   if (win->bg_color.pixel == bg_color->pixel) {
451     return 0;
452   }
453 
454   win->bg_color = *bg_color;
455 
456   if (win->my_window && win->parent) {
457     view_bg_color_changed(win->my_window);
458     ui_window_update_all(win);
459   }
460 
461   return 1;
462 }
463 
ui_window_add_child(ui_window_t * win,ui_window_t * child,int x,int y,int map)464 int ui_window_add_child(ui_window_t *win, ui_window_t *child, int x, int y, int map) {
465   void *p;
466 
467   if ((p = realloc(win->children, sizeof(*win->children) * (win->num_children + 1))) == NULL) {
468 #ifdef DEBUG
469     bl_warn_printf(BL_DEBUG_TAG " realloc failed.\n");
470 #endif
471 
472     return 0;
473   }
474 
475   win->children = p;
476 
477   child->parent = win;
478   child->x = x + win->hmargin;
479   child->y = y + win->vmargin;
480 
481   if (!(child->is_mapped = map) && child->inputtable > 0) {
482     child->inputtable = -1;
483   }
484 
485   win->children[win->num_children++] = child;
486 
487   return 1;
488 }
489 
ui_window_remove_child(ui_window_t * win,ui_window_t * child)490 int ui_window_remove_child(ui_window_t *win, ui_window_t *child) {
491   u_int count;
492 
493   for (count = 0; count < win->num_children; count++) {
494     if (win->children[count] == child) {
495       child->parent = NULL;
496       win->children[count] = win->children[--win->num_children];
497 
498       return 1;
499     }
500   }
501 
502   return 0;
503 }
504 
ui_window_get_fg_gc(ui_window_t * win)505 GC ui_window_get_fg_gc(ui_window_t *win) { return None; }
506 
ui_window_get_bg_gc(ui_window_t * win)507 GC ui_window_get_bg_gc(ui_window_t *win) { return None; }
508 
ui_get_root_window(ui_window_t * win)509 ui_window_t *ui_get_root_window(ui_window_t *win) {
510   while (win->parent != NULL) {
511     win = win->parent;
512   }
513 
514   return win;
515 }
516 
ui_window_show(ui_window_t * win,int hint)517 int ui_window_show(ui_window_t *win,
518                    int hint /* If win->parent(_window) is None,
519                                specify XValue|YValue to localte window at win->x/win->y. */
520                    ) {
521   u_int count;
522 
523   if (win->my_window) {
524     /* already shown */
525 
526     return 0;
527   }
528 
529 #ifndef USE_BEOS
530   if (hint & XNegative) {
531     win->x += (win->disp->width - ACTUAL_WIDTH(win));
532   }
533 
534   if (hint & YNegative) {
535     win->y += (win->disp->height - ACTUAL_HEIGHT(win));
536   }
537 #endif
538 
539   if (win->parent) {
540     win->disp = win->parent->disp;
541     win->parent_window = win->parent->my_window;
542     win->gc = win->parent->gc;
543 
544     view_alloc(win, win->x, win->y, ACTUAL_WIDTH(win), ACTUAL_HEIGHT(win));
545   } else {
546     window_alloc(win, win->x, win->y, ACTUAL_WIDTH(win), ACTUAL_HEIGHT(win),
547                  IS_IM_WINDOW(win), hint);
548   }
549 
550 #ifndef DISABLE_XDND
551 /* DragAcceptFiles( win->my_window , TRUE) ; */
552 #endif
553 
554   if (win->parent && !win->parent->is_transparent && win->parent->wall_picture) {
555     ui_window_set_wall_picture(win, ParentRelative, 0);
556   }
557 
558   /*
559    * This should be called after Window Manager settings, because
560    * ui_set_{window|icon}_name() can be called in win->window_realized().
561    */
562   if (win->window_realized) {
563     (*win->window_realized)(win);
564   }
565 
566   /*
567    * showing child windows.
568    */
569 
570   for (count = 0; count < win->num_children; count++) {
571     ui_window_show(win->children[count], 0);
572   }
573 
574   if (!win->parent) {
575     window_show(win->my_window);
576   }
577 
578   /*
579    * really visualized.
580    */
581 
582   if (win->is_mapped) {
583     if (win->inputtable > 0) {
584       reset_input_focus(ui_get_root_window(win));
585       win->inputtable = 1;
586     }
587   }
588 
589   if (win->is_transparent) {
590     ui_window_set_transparent(win, win->pic_mod);
591   }
592 
593   return 1;
594 }
595 
ui_window_map(ui_window_t * win)596 void ui_window_map(ui_window_t *win) {
597   if (win->is_mapped) {
598     return;
599   }
600 
601   if (win->parent) {
602     view_set_hidden(win->my_window, 0);
603   }
604 
605   win->is_mapped = 1;
606 }
607 
ui_window_unmap(ui_window_t * win)608 void ui_window_unmap(ui_window_t *win) {
609   if (!win->is_mapped) {
610     return;
611   }
612 
613   if (win->parent) {
614     view_set_hidden(win->my_window, 1);
615 
616 #if 0
617     /* Scrollbar position is corrupt without this. */
618     ui_window_move(win, -1, -1);
619 #endif
620   }
621 
622   win->is_mapped = 0;
623 }
624 
ui_window_resize(ui_window_t * win,u_int width,u_int height,ui_resize_flag_t flag)625 int ui_window_resize(ui_window_t *win, u_int width, /* excluding margin */
626                      u_int height,                  /* excluding margin */
627                      ui_resize_flag_t flag          /* NOTIFY_TO_PARENT , NOTIFY_TO_MYSELF */
628                      ) {
629   if (win->width == width && win->height == height) {
630     return 0;
631   }
632 
633   /* Max width of each window is screen width. */
634   if ((flag & LIMIT_RESIZE) && win->disp->width < width) {
635     win->width = win->disp->width - win->hmargin * 2;
636   } else {
637     win->width = width;
638   }
639 
640   /* Max.height of each window is screen height. */
641   if ((flag & LIMIT_RESIZE) && win->disp->height < height) {
642     win->height = win->disp->height - win->vmargin * 2;
643   } else {
644     win->height = height;
645   }
646 
647   if (win->parent) {
648     view_resize(win->my_window, ACTUAL_WIDTH(win), ACTUAL_HEIGHT(win));
649 
650     if ((flag & NOTIFY_TO_PARENT) && win->parent->child_window_resized) {
651       (*win->parent->child_window_resized)(win->parent, win);
652     }
653   } else {
654     /*
655      * win->parent may be NULL because this function is called
656      * from ui_layout after ui_window_remove_child(),
657      * not only win->parent but also IS_UILAYOUT(win) is necessary.
658      */
659     if (IS_UILAYOUT(win) || IS_IM_WINDOW(win)) {
660       window_resize(win->my_window, ACTUAL_WIDTH(win), ACTUAL_HEIGHT(win));
661     }
662   }
663 
664   if ((flag & NOTIFY_TO_MYSELF) && win->window_resized) {
665     (*win->window_resized)(win);
666     win->update_window_flag = 0; /* force redraw */
667   }
668 
669   return 1;
670 }
671 
672 /*
673  * !! Notice !!
674  * This function is not recommended.
675  * Use ui_window_resize if at all possible.
676  */
ui_window_resize_with_margin(ui_window_t * win,u_int width,u_int height,ui_resize_flag_t flag)677 int ui_window_resize_with_margin(ui_window_t *win, u_int width, u_int height,
678                                  ui_resize_flag_t flag /* NOTIFY_TO_PARENT , NOTIFY_TO_MYSELF */
679                                  ) {
680   return ui_window_resize(win, width - win->hmargin * 2, height - win->vmargin * 2, flag);
681 }
682 
ui_window_set_maximize_flag(ui_window_t * win,ui_maximize_flag_t flag)683 void ui_window_set_maximize_flag(ui_window_t *win, ui_maximize_flag_t flag) {
684   if (flag) {
685     u_int w;
686     u_int h;
687     int x;
688     int y;
689 
690     win = ui_get_root_window(win);
691 
692     window_get_position(win->my_window, &x, &y);
693 
694     if (flag & MAXIMIZE_HORIZONTAL) {
695       w = win->disp->width;
696       x = 0;
697     } else {
698       w = win->width;
699     }
700 
701     if (flag & MAXIMIZE_VERTICAL) {
702       h = win->disp->height;
703       y = 0;
704     } else {
705       h = win->height;
706     }
707 
708     window_resize(win->my_window, w, h);
709     window_move(win->my_window, x, y);
710 
711     /* Same processing as ui_window_resize() */
712     if (win->window_resized) {
713       (*win->window_resized)(win);
714       win->update_window_flag = 0; /* force redraw */
715     }
716   } else {
717     /* XXX MAXIMIZE_RESTORE is not supported for now. */
718   }
719 }
720 
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)721 void ui_window_set_normal_hints(ui_window_t *win, u_int min_width, u_int min_height,
722                                 u_int width_inc, u_int height_inc) {
723   win->min_width = min_width;
724   win->min_height = min_height;
725   win->width_inc = width_inc;
726   win->height_inc = height_inc;
727 }
728 
ui_window_set_override_redirect(ui_window_t * win,int flag)729 void ui_window_set_override_redirect(ui_window_t *win, int flag) {}
730 
ui_window_set_borderless_flag(ui_window_t * win,int flag)731 int ui_window_set_borderless_flag(ui_window_t *win, int flag) { return 0; }
732 
ui_window_move(ui_window_t * win,int x,int y)733 int ui_window_move(ui_window_t *win, int x, int y) {
734   if (win->parent) {
735     x += win->parent->hmargin;
736     y += win->parent->vmargin;
737   }
738 
739   if (win->x == x && win->y == y) {
740     return 0;
741   }
742 
743   win->x = x;
744   win->y = y;
745 
746   if (win->parent) {
747     view_move(win->my_window, x, y);
748   } else {
749     window_move(win->my_window, x, y);
750   }
751 
752   return 1;
753 }
754 
755 /*
756  * This function can be used in context except window_exposed and update_window
757  * events.
758  */
ui_window_clear(ui_window_t * win,int x,int y,u_int width,u_int height)759 void ui_window_clear(ui_window_t *win, int x, int y, u_int width, u_int height) {
760   void *view;
761 
762 #ifdef AUTO_CLEAR_MARGIN
763   if (x + width >= win->width) {
764     /* Clearing margin area */
765     width += win->hmargin;
766   }
767 
768   if (x > 0)
769 #endif
770   {
771     x += win->hmargin;
772   }
773 #ifdef AUTO_CLEAR_MARGIN
774   else {
775     /* Clearing margin area */
776     width += win->hmargin;
777   }
778 
779   if (y + height >= win->height) {
780     /* Clearing margin area */
781     height += win->vmargin;
782   }
783 
784   if (y > 0)
785 #endif
786   {
787     y += win->vmargin;
788   }
789 #ifdef AUTO_CLEAR_MARGIN
790   else {
791     /* Clearing margin area */
792     height += win->vmargin;
793   }
794 #endif
795 
796   if (win->parent) {
797     view = win->my_window;
798   } else if (!(view = window_get_orphan(win->my_window, 0))) {
799     return;
800   }
801 
802   if (win->wall_picture) {
803     Pixmap pic;
804     int src_x;
805     int src_y;
806 
807     if (win->wall_picture == ParentRelative) {
808       pic = win->parent->wall_picture;
809       src_x = win->x;
810       src_y = win->y;
811     } else {
812       pic = win->wall_picture;
813       src_x = src_y = 0;
814     }
815 
816     view_copy_area(view, pic, src_x + x, src_y + y, width, height, x, y);
817   } else {
818     view_fill_with(view, &win->bg_color, x, y, width, height);
819   }
820 }
821 
ui_window_clear_all(ui_window_t * win)822 void ui_window_clear_all(ui_window_t *win) {
823   ui_window_clear(win, 0, 0, win->width, win->height);
824 }
825 
ui_window_fill(ui_window_t * win,int x,int y,u_int width,u_int height)826 void ui_window_fill(ui_window_t *win, int x, int y, u_int width, u_int height) {
827   ui_window_fill_with(win, &win->fg_color, x, y, width, height);
828 }
829 
ui_window_fill_with(ui_window_t * win,ui_color_t * color,int x,int y,u_int width,u_int height)830 void ui_window_fill_with(ui_window_t *win, ui_color_t *color, int x, int y, u_int width,
831                         u_int height) {
832   void *view;
833 
834   if (win->parent) {
835     view = win->my_window;
836   } else if (!(view = window_get_orphan(win->my_window, 0))) {
837     return;
838   }
839 
840   view_fill_with(view, color, x + win->hmargin, y + win->vmargin, width, height);
841 }
842 
843 /*
844  * This function can be used in context except window_exposed and update_window
845  * events.
846  */
ui_window_blank(ui_window_t * win)847 void ui_window_blank(ui_window_t *win) {}
848 
849 #if 0
850 /*
851  * XXX
852  * at the present time , not used and not maintained.
853  */
854 void ui_window_fill_all_with(ui_window_t *win, ui_color_t *color) {}
855 #endif
856 
ui_window_update(ui_window_t * win,int flag)857 void ui_window_update(ui_window_t *win, int flag) {
858   void *view;
859 
860   if (win->parent) {
861     view = win->my_window;
862   }
863   /*
864    * ui_screen which is removed and becomes an orphan is resized by
865    * ui_window_resize() in ui_layout_remove_child(), then ui_window_update()
866    * is called.
867    * In this case win->parent is NULL but win->my_window is not MLWindow* but
868    * MLView*, so window_get_orphan(win->my_window) fails.
869    * 'if ((!IS_UILAYOUT(win) && !IS_IM_WINDOW(win)))' avoids the failure.
870    */
871   else if ((!IS_UILAYOUT(win) && !IS_IM_WINDOW(win)) ||
872            !(view = window_get_orphan(win->my_window, 0))) {
873     return;
874   }
875 
876   win->update_window_flag |= flag;
877   view_update(view, 0);
878 }
879 
ui_window_update_all(ui_window_t * win)880 void ui_window_update_all(ui_window_t *win) {
881   void *view;
882   u_int count;
883 
884   if (win->parent) {
885     view = win->my_window;
886   } else if (!(view = window_get_orphan(win->my_window, 0))) {
887     return;
888   }
889 
890   view_update(view, 1);
891 
892   for (count = 0; count < win->num_children; count++) {
893     ui_window_update_all(win->children[count]);
894   }
895 }
896 
ui_window_idling(ui_window_t * win)897 void ui_window_idling(ui_window_t *win) {
898   u_int count;
899 
900   for (count = 0; count < win->num_children; count++) {
901     ui_window_idling(win->children[count]);
902   }
903 
904 #ifdef __DEBUG
905   if (win->button_is_pressing) {
906     bl_debug_printf(BL_DEBUG_TAG " button is pressing...\n");
907   }
908 #endif
909 
910   if (win->button_is_pressing && win->button_press_continued) {
911     (*win->button_press_continued)(win, &win->prev_button_press_event);
912   } else if (win->idling) {
913     (*win->idling)(win);
914   }
915 }
916 
917 /*
918  * Return value: 0 => different window.
919  *               1 => finished processing.
920  *              -1 => continuing default processing.
921  */
ui_window_receive_event(ui_window_t * win,XEvent * event)922 int ui_window_receive_event(ui_window_t *win, XEvent *event) {
923   switch (event->type) {
924     case UI_KEY_FOCUS_IN:
925       reset_input_focus(ui_get_root_window(win));
926       win->inputtable = 1;
927       win = ui_get_root_window(win);
928       notify_focus_out_to_children(win);
929       /* Fall through */
930 
931     case UI_FOCUS_IN:
932       urgent_bell(win, 0);
933       notify_focus_in_to_children(win);
934       break;
935 
936     case UI_FOCUS_OUT:
937       notify_focus_out_to_children(win);
938       break;
939 
940     case UI_BUTTON_PRESS:
941       if (win->button_pressed) {
942         XButtonEvent *bev;
943 
944         bev = (XButtonEvent*)event;
945         bev->x -= win->hmargin;
946         bev->y -= win->vmargin;
947 
948         (*win->button_pressed)(win, bev, bev->click_count);
949 
950         win->button_is_pressing = 1;
951         win->prev_button_press_event = *bev;
952       }
953       break;
954 
955     case UI_BUTTON_RELEASE:
956       if (win->button_released) {
957         XButtonEvent *bev;
958 
959         bev = (XButtonEvent*)event;
960         bev->x -= win->hmargin;
961         bev->y -= win->vmargin;
962 
963         (*win->button_released)(win, bev);
964 
965         win->button_is_pressing = 0;
966       }
967       break;
968 
969     case UI_BUTTON_MOTION:
970       if (win->button_motion) {
971         XMotionEvent *mev;
972 
973         mev = (XMotionEvent*)event;
974         mev->x -= win->hmargin;
975         mev->y -= win->vmargin;
976 
977         (*win->button_motion)(win, mev);
978 
979         /* following button motion ... */
980         win->prev_button_press_event.x = mev->x;
981         win->prev_button_press_event.y = mev->y;
982         win->prev_button_press_event.time = mev->time;
983       }
984       break;
985 
986     case UI_POINTER_MOTION:
987       if (win->pointer_motion) {
988         XMotionEvent *mev;
989 
990         mev = (XMotionEvent*)event;
991         mev->x -= win->hmargin;
992         mev->y -= win->vmargin;
993 
994         (*win->pointer_motion)(win, mev);
995       }
996       break;
997 
998     case UI_KEY_PRESS:
999       if (win->key_pressed) {
1000         (*win->key_pressed)(win, (XKeyEvent*)event);
1001       }
1002       break;
1003 
1004     case UI_EXPOSE:
1005       expose(win, (XExposeEvent*)event);
1006       break;
1007 
1008     case UI_SELECTION_REQUESTED:
1009       if (win->utf_selection_requested) {
1010         (*win->utf_selection_requested)(win, (XSelectionRequestEvent*)event, 0);
1011       }
1012       break;
1013 
1014     case UI_SELECTION_NOTIFIED:
1015       if (win->utf_selection_notified) {
1016         (*win->utf_selection_notified)(win, ((XSelectionNotifyEvent*)event)->data,
1017                                        ((XSelectionNotifyEvent*)event)->len);
1018       }
1019       break;
1020 
1021     case UI_CLOSE_WINDOW:
1022       /* root window */
1023       if (win->window_destroyed) {
1024         (*win->window_destroyed)(win);
1025       }
1026       break;
1027 
1028     case UI_RESIZE:
1029       if (win->window_resized) {
1030         (*win->window_resized)(win);
1031       }
1032       clear_margin_area_all(win);
1033 
1034       break;
1035   }
1036 
1037   return 1;
1038 }
1039 
ui_window_get_str(ui_window_t * win,u_char * seq,size_t seq_len,ef_parser_t ** parser,KeySym * keysym,XKeyEvent * event)1040 size_t ui_window_get_str(ui_window_t *win, u_char *seq, size_t seq_len, ef_parser_t **parser,
1041                          KeySym *keysym, XKeyEvent *event) {
1042   return ui_xic_get_str(win, seq, seq_len, parser, keysym, event);
1043 }
1044 
1045 /*
1046  * Scroll functions.
1047  * The caller side should clear the scrolled area.
1048  */
1049 
ui_window_scroll_upward(ui_window_t * win,u_int height)1050 int ui_window_scroll_upward(ui_window_t *win, u_int height) {
1051   return ui_window_scroll_upward_region(win, 0, win->height, height);
1052 }
1053 
ui_window_scroll_upward_region(ui_window_t * win,int boundary_start,int boundary_end,u_int height)1054 int ui_window_scroll_upward_region(ui_window_t *win, int boundary_start, int boundary_end,
1055                                    u_int height) {
1056   if (!win->is_scrollable) {
1057     return 0;
1058   }
1059 
1060   if (boundary_start < 0 || boundary_end > win->height || boundary_end <= boundary_start + height) {
1061 #ifdef DEBUG
1062     bl_warn_printf(BL_DEBUG_TAG " boundary start %d end %d height %d in window((h) %d (w) %d)\n",
1063                    boundary_start, boundary_end, height, win->height, win->width);
1064 #endif
1065 
1066     return 0;
1067   }
1068 
1069   if (win->parent) {
1070     view_scroll(win->my_window, win->hmargin, win->vmargin + boundary_start + height, /* src */
1071                 win->width, boundary_end - boundary_start - height,                   /* size */
1072                 win->hmargin, win->vmargin + boundary_start);                         /* dst */
1073   }
1074 
1075   return 1;
1076 }
1077 
ui_window_scroll_downward(ui_window_t * win,u_int height)1078 int ui_window_scroll_downward(ui_window_t *win, u_int height) {
1079   return ui_window_scroll_downward_region(win, 0, win->height, height);
1080 }
1081 
ui_window_scroll_downward_region(ui_window_t * win,int boundary_start,int boundary_end,u_int height)1082 int ui_window_scroll_downward_region(ui_window_t *win, int boundary_start, int boundary_end,
1083                                      u_int height) {
1084   if (!win->is_scrollable) {
1085     return 0;
1086   }
1087 
1088   if (boundary_start < 0 || boundary_end > win->height || boundary_end <= boundary_start + height) {
1089 #ifdef DEBUG
1090     bl_warn_printf(BL_DEBUG_TAG " boundary start %d end %d height %d\n", boundary_start,
1091                    boundary_end, height);
1092 #endif
1093 
1094     return 0;
1095   }
1096 
1097   if (win->parent) {
1098     view_scroll(win->my_window, win->hmargin, win->vmargin + boundary_start, /* src */
1099                 win->width, boundary_end - boundary_start - height,          /* size */
1100                 win->hmargin, win->vmargin + boundary_start + height);       /* dst */
1101   }
1102 
1103   return 1;
1104 }
1105 
ui_window_scroll_leftward(ui_window_t * win,u_int width)1106 int ui_window_scroll_leftward(ui_window_t *win, u_int width) {
1107   return ui_window_scroll_leftward_region(win, 0, win->width, width);
1108 }
1109 
ui_window_scroll_leftward_region(ui_window_t * win,int boundary_start,int boundary_end,u_int width)1110 int ui_window_scroll_leftward_region(ui_window_t *win, int boundary_start, int boundary_end,
1111                                      u_int width) {
1112   if (!win->is_scrollable) {
1113     return 0;
1114   }
1115 
1116   if (boundary_start < 0 || boundary_end > win->width || boundary_end <= boundary_start + width) {
1117 #ifdef DEBUG
1118     bl_warn_printf(BL_DEBUG_TAG " boundary start %d end %d width %d in window((h) %d (w) %d)\n",
1119                    boundary_start, boundary_end, width, win->height, win->width);
1120 #endif
1121 
1122     return 0;
1123   }
1124 
1125   if (win->parent) {
1126     view_scroll(win->my_window, win->hmargin + boundary_start + width, win->vmargin, /* src */
1127                 boundary_end - boundary_start - width, win->height,                  /* size */
1128                 win->hmargin + boundary_start, win->vmargin);                        /* dst */
1129   }
1130 
1131   return 1;
1132 }
1133 
ui_window_scroll_rightward(ui_window_t * win,u_int width)1134 int ui_window_scroll_rightward(ui_window_t *win, u_int width) {
1135   return ui_window_scroll_rightward_region(win, 0, win->width, width);
1136 }
1137 
ui_window_scroll_rightward_region(ui_window_t * win,int boundary_start,int boundary_end,u_int width)1138 int ui_window_scroll_rightward_region(ui_window_t *win, int boundary_start, int boundary_end,
1139                                       u_int width) {
1140   if (!win->is_scrollable) {
1141     return 0;
1142   }
1143 
1144   if (boundary_start < 0 || boundary_end > win->width || boundary_end <= boundary_start + width) {
1145 #ifdef DEBUG
1146     bl_warn_printf(BL_DEBUG_TAG " boundary start %d end %d width %d\n", boundary_start,
1147                    boundary_end, width);
1148 #endif
1149 
1150     return 0;
1151   }
1152 
1153   if (win->parent) {
1154     view_scroll(win->my_window, win->hmargin + boundary_start, win->vmargin, /* src */
1155                 boundary_end - boundary_start - width, win->height,          /* size */
1156                 win->hmargin + boundary_start + width, win->vmargin);        /* dst */
1157   }
1158 
1159   return 1;
1160 }
1161 
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)1162 int ui_window_copy_area(ui_window_t *win, Pixmap src, PixmapMask mask, int src_x, /* >= 0 */
1163                         int src_y,                                                /* >= 0 */
1164                         u_int width, u_int height, int dst_x,                     /* >= 0 */
1165                         int dst_y                                                 /* >= 0 */
1166                         ) {
1167   if (dst_x >= win->width || dst_y >= win->height) {
1168     return 0;
1169   }
1170 
1171   if (dst_x + width > win->width) {
1172     width = win->width - dst_x;
1173   }
1174 
1175   if (dst_y + height > win->height) {
1176     height = win->height - dst_y;
1177   }
1178 
1179   if (win->parent) {
1180     view_copy_area(win->my_window, src, src_x, src_y, width, height, dst_x + win->hmargin,
1181                    dst_y + win->vmargin);
1182   }
1183 
1184   return 1;
1185 }
1186 
ui_window_set_clip(ui_window_t * win,int x,int y,u_int width,u_int height)1187 void ui_window_set_clip(ui_window_t *win, int x, int y, u_int width, u_int height) {
1188   if (win->parent) {
1189     view_set_clip(win->my_window, x + win->hmargin, y + win->vmargin, width, height);
1190   }
1191 }
1192 
ui_window_unset_clip(ui_window_t * win)1193 void ui_window_unset_clip(ui_window_t *win) {
1194   if (win->parent) {
1195     view_unset_clip(win->my_window);
1196   }
1197 }
1198 
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)1199 void ui_window_draw_decsp_string(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color, int x,
1200                                 int y, u_char *str, u_int len) {
1201   ui_window_draw_string(win, font, fg_color, x, y, str, len);
1202 }
1203 
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)1204 void ui_window_draw_string(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color, int x, int y,
1205                            u_char *str, u_int len) {
1206   void *view;
1207 
1208   if (win->parent) {
1209     view = win->my_window;
1210   } else if (!(view = window_get_orphan(win->my_window, 0))) {
1211     return;
1212   }
1213 
1214   view_draw_string(view, font, fg_color, x + win->hmargin, y + win->vmargin, str, len);
1215 }
1216 
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)1217 void ui_window_draw_string16(ui_window_t *win, ui_font_t *font, ui_color_t *fg_color, int x, int y,
1218                              XChar2b *str, u_int len) {
1219   void *view;
1220 
1221   if (win->parent) {
1222     view = win->my_window;
1223   } else if (!(view = window_get_orphan(win->my_window, 0))) {
1224     return;
1225   }
1226 
1227   view_draw_string16(view, font, fg_color, x + win->hmargin, y + win->vmargin, str, len);
1228 }
1229 
ui_window_draw_rect_frame(ui_window_t * win,int x1,int y1,int x2,int y2)1230 void ui_window_draw_rect_frame(ui_window_t *win, int x1, int y1, int x2, int y2) {
1231   if (win->parent) {
1232     view_draw_rect_frame(win->my_window, &win->fg_color, x1 + win->hmargin, y1 + win->vmargin,
1233                          x2 + win->hmargin, y2 + win->vmargin);
1234   }
1235 }
1236 
ui_set_use_clipboard_selection(int use_it)1237 void ui_set_use_clipboard_selection(int use_it) {}
1238 
ui_is_using_clipboard_selection(void)1239 int ui_is_using_clipboard_selection(void) { return 0; }
1240 
ui_window_set_selection_owner(ui_window_t * win,Time time)1241 int ui_window_set_selection_owner(ui_window_t *win, Time time) {
1242   if (ui_window_is_selection_owner(win)) {
1243     /* Already owner */
1244 
1245     return 1;
1246   }
1247 
1248 #if 0
1249   bl_debug_printf(BL_DEBUG_TAG " ui_window_set_selection_owner.\n");
1250 #endif
1251 
1252   if (win->utf_selection_requested) {
1253     (*win->utf_selection_requested)(win, NULL, 0);
1254   }
1255 
1256   return 1;
1257 }
1258 
ui_window_xct_selection_request(ui_window_t * win,Time time)1259 int ui_window_xct_selection_request(ui_window_t *win, Time time) { return 0; }
1260 
ui_window_utf_selection_request(ui_window_t * win,Time time)1261 int ui_window_utf_selection_request(ui_window_t *win, Time time) {
1262   if (win->utf_selection_notified) {
1263     u_char *str;
1264     size_t len;
1265 
1266     if (beos_clipboard_get(&str, &len)) {
1267       (*win->utf_selection_notified)(win, str, len);
1268 
1269       return 1;
1270     }
1271   }
1272 
1273   return 0;
1274 }
1275 
ui_window_send_picture_selection(ui_window_t * win,Pixmap pixmap,u_int width,u_int height)1276 void ui_window_send_picture_selection(ui_window_t *win, Pixmap pixmap, u_int width, u_int height) {}
1277 
ui_window_send_text_selection(ui_window_t * win,XSelectionRequestEvent * req_ev,u_char * sel_data,size_t sel_len,Atom sel_type)1278 void ui_window_send_text_selection(ui_window_t *win, XSelectionRequestEvent *req_ev,
1279                                    u_char *sel_data, size_t sel_len, Atom sel_type) {
1280   beos_clipboard_set(sel_data, sel_len);
1281 }
1282 
ui_set_window_name(ui_window_t * win,u_char * name)1283 void ui_set_window_name(ui_window_t *win, u_char *name) {
1284   ui_window_t *root = ui_get_root_window(win);
1285 
1286   if (name == NULL) {
1287     name = root->app_name;
1288   }
1289 
1290   /* name is utf8 (see vt_parser.c) */
1291   window_set_title(root->my_window, name);
1292 }
1293 
ui_set_icon_name(ui_window_t * win,u_char * name)1294 void ui_set_icon_name(ui_window_t *win, u_char *name) {}
1295 
ui_window_set_icon(ui_window_t * win,ui_icon_picture_t * icon)1296 void ui_window_set_icon(ui_window_t *win, ui_icon_picture_t *icon) {}
1297 
ui_window_remove_icon(ui_window_t * win)1298 void ui_window_remove_icon(ui_window_t *win) {}
1299 
ui_window_reset_group(ui_window_t * win)1300 void ui_window_reset_group(ui_window_t *win) {}
1301 
ui_set_click_interval(int interval)1302 void ui_set_click_interval(int interval) {
1303   click_interval = interval;
1304 }
1305 
ui_get_click_interval(void)1306 int ui_get_click_interval(void) {
1307   return click_interval;
1308 }
1309 
ui_window_get_mod_ignore_mask(ui_window_t * win,KeySym * keysyms)1310 u_int ui_window_get_mod_ignore_mask(ui_window_t *win, KeySym *keysyms) { return ~0; }
1311 
ui_window_get_mod_meta_mask(ui_window_t * win,char * mod_key)1312 u_int ui_window_get_mod_meta_mask(ui_window_t *win, char *mod_key) { return ModMask; }
1313 
ui_set_use_urgent_bell(int use)1314 void ui_set_use_urgent_bell(int use) {
1315   use_urgent_bell = use;
1316 }
1317 
ui_window_bell(ui_window_t * win,ui_bel_mode_t mode)1318 void ui_window_bell(ui_window_t *win, ui_bel_mode_t mode) {
1319   urgent_bell(win, 1);
1320 
1321   if (mode & BEL_VISUAL) {
1322     if (win->parent) {
1323       view_visual_bell(win->my_window);
1324     }
1325   }
1326 
1327   if (mode & BEL_SOUND) {
1328     beos_beep();
1329   }
1330 }
1331 
ui_window_translate_coordinates(ui_window_t * win,int x,int y,int * global_x,int * global_y)1332 void ui_window_translate_coordinates(ui_window_t *win, int x, int y, int *global_x, int *global_y) {
1333   win = ui_get_root_window(win);
1334   window_get_position(win->my_window, global_x, global_y);
1335   *global_x += x;
1336   *global_y += y;
1337 }
1338 
ui_window_set_input_focus(ui_window_t * win)1339 void ui_window_set_input_focus(ui_window_t *win) {
1340   reset_input_focus(ui_get_root_window(win));
1341   win->inputtable = 1;
1342 
1343   if (win->parent) {
1344     view_set_input_focus(win->my_window);
1345   }
1346 }
1347 
1348 #ifdef DEBUG
ui_window_dump_children(ui_window_t * win)1349 void ui_window_dump_children(ui_window_t *win) {
1350   u_int count;
1351 
1352   bl_msg_printf("%p(%li) => ", win, win->my_window);
1353   for (count = 0; count < win->num_children; count++) {
1354     bl_msg_printf("%p(%li) ", win->children[count], win->children[count]->my_window);
1355   }
1356   bl_msg_printf("\n");
1357 
1358   for (count = 0; count < win->num_children; count++) {
1359     ui_window_dump_children(win->children[count]);
1360   }
1361 }
1362 #endif
1363