1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2
3 #include "ui_layout.h"
4
5 #include <pobl/bl_types.h> /* u_int */
6 #include <pobl/bl_str.h>
7
8 #ifdef USE_BEOS
9 void view_reset_uiwindow(ui_window_t *uiwindow);
10 #endif
11
12 #ifdef USE_CONSOLE
13 static u_int dummy_arg;
14 #define SEPARATOR_WIDTH ui_get_opened_displays(&dummy_arg)[0]->display->col_width
15 #define SEPARATOR_HEIGHT ui_get_opened_displays(&dummy_arg)[0]->display->line_height
16 #else
17 #define SEPARATOR_WIDTH 1
18 #define SEPARATOR_HEIGHT 1
19 #endif
20 #define SCROLLBAR_WIDTH(scrollbar) (ACTUAL_WIDTH(&(scrollbar).window) + SEPARATOR_WIDTH)
21 #define HAS_MULTI_CHILDREN(layout) ((layout)->term.next[0] || (layout)->term.next[1])
22
23 /* --- static variables --- */
24
25 static void (*orig_window_focused)(ui_window_t *);
26 static void (*orig_xterm_set_window_name)(void *, u_char *);
27 static void (*orig_xterm_set_icon_name)(void *, u_char *);
28
29 /* --- static functions --- */
30
update_title(ui_screen_t * screen)31 static void update_title(ui_screen_t *screen) {
32 ui_set_window_name(&screen->window, vt_term_window_name(screen->term));
33 ui_set_icon_name(&screen->window, vt_term_icon_name(screen->term));
34 }
35
window_focused(ui_window_t * win)36 static void window_focused(ui_window_t *win) {
37 ui_layout_t *layout = (ui_layout_t*)win->parent;
38
39 (*orig_window_focused)(win);
40
41 if (HAS_MULTI_CHILDREN(layout)) {
42 /*
43 * If two screens in layout and one of them is removed, update_title() is
44 * not called here. It is called at the end of ui_layout_remove_child().
45 */
46 update_title((ui_screen_t*)win);
47 }
48 }
49
xterm_set_window_name(void * p,u_char * name)50 static void xterm_set_window_name(void *p, u_char *name) {
51 ui_window_t *win = p;
52 ui_layout_t *layout = (ui_layout_t*)win->parent;
53
54 if (!HAS_MULTI_CHILDREN(layout) || win->inputtable > 0) {
55 (*orig_xterm_set_window_name)(p, name);
56 }
57 }
58
xterm_set_icon_name(void * p,u_char * name)59 static void xterm_set_icon_name(void *p, u_char *name) {
60 ui_window_t *win = p;
61 ui_layout_t *layout = (ui_layout_t*)win->parent;
62
63 if (!HAS_MULTI_CHILDREN(layout) || win->inputtable > 0) {
64 (*orig_xterm_set_icon_name)(p, name);
65 }
66 }
67
modify_separator(u_int separator,u_int total,u_int next_min,u_int unit,u_int fixed,u_int margin)68 static u_int modify_separator(u_int separator, u_int total, u_int next_min, u_int unit, u_int fixed,
69 u_int margin) {
70 u_int surplus;
71 int dont_round_up;
72
73 if (total < separator + margin + next_min) {
74 #if 0
75 separator = total - next_min - margin;
76 #else
77 separator = total / 2;
78 #endif
79 dont_round_up = 1;
80 } else {
81 dont_round_up = 0;
82 }
83
84 if ((surplus = (separator - fixed) % unit) > 0) {
85 if (!dont_round_up && surplus > unit / 2) {
86 separator += (unit - surplus);
87 } else if (separator - fixed > surplus) {
88 separator -= surplus;
89 } else {
90 separator = fixed + unit;
91 }
92 }
93
94 return separator;
95 }
96
reset_layout(struct terminal * term,int x,int y,u_int width,u_int height)97 static void reset_layout(struct terminal *term, int x, int y, u_int width, u_int height) {
98 u_int child_width;
99 u_int child_height;
100 int screen_moved;
101 int screen_resized;
102
103 if (term->separator_x > 0) {
104 term->separator_x = child_width = modify_separator(
105 term->separator_x, width,
106 term->next[0]->screen->window.hmargin * 2 + ui_col_width(term->next[0]->screen) +
107 (term->next[0]->sb_mode != SBM_NONE ? SCROLLBAR_WIDTH(term->next[0]->scrollbar) : 0),
108 ui_col_width(term->screen),
109 term->screen->window.hmargin * 2 +
110 (term->sb_mode != SBM_NONE ? SCROLLBAR_WIDTH(term->scrollbar) : 0),
111 SEPARATOR_WIDTH);
112 } else {
113 child_width = width;
114 }
115
116 if (term->separator_y > 0) {
117 term->separator_y = child_height = modify_separator(
118 term->separator_y, height,
119 term->next[1]->screen->window.vmargin * 2 + ui_line_height(term->next[1]->screen),
120 ui_line_height(term->screen), term->screen->window.vmargin * 2, SEPARATOR_HEIGHT);
121 } else {
122 child_height = height;
123 }
124
125 if (term->sb_mode != SBM_NONE) {
126 int sep_x;
127 int sb_moved;
128 int sb_resized;
129
130 if (term->sb_mode == SBM_RIGHT) {
131 screen_moved = ui_window_move(&term->screen->window, x, y);
132 sb_moved = ui_window_move(&term->scrollbar.window,
133 x + child_width - ACTUAL_WIDTH(&term->scrollbar.window), y);
134 sep_x = x + child_width - SCROLLBAR_WIDTH(term->scrollbar);
135 } else {
136 screen_moved = ui_window_move(&term->screen->window, x + SCROLLBAR_WIDTH(term->scrollbar), y);
137 sb_moved = ui_window_move(&term->scrollbar.window, x, y);
138 sep_x = x + ACTUAL_WIDTH(&term->scrollbar.window);
139 }
140
141 /*
142 * The order of resizing: ui_scrollbar_t -> ui_screen_t
143 *
144 * ui_window_resize_with_margin(screen) may call ui_scrollbar_line_is_added()
145 * which redraws screen by ui_window_update(), so you should resize ui_scrollbar_t
146 * before ui_screen_t.
147 */
148 sb_resized = ui_window_resize_with_margin(&term->scrollbar.window,
149 ACTUAL_WIDTH(&term->scrollbar.window),
150 child_height, NOTIFY_TO_MYSELF);
151 screen_resized = ui_window_resize_with_margin(&term->screen->window,
152 child_width - SCROLLBAR_WIDTH(term->scrollbar),
153 child_height, NOTIFY_TO_MYSELF);
154
155 #ifdef MANAGE_SUB_WINDOWS_BY_MYSELF
156 ui_window_fill_with(&UI_SCREEN_TO_LAYOUT(term->screen)->window,
157 &UI_SCREEN_TO_LAYOUT(term->screen)->window.fg_color, sep_x, y,
158 SEPARATOR_WIDTH, child_height);
159 #else
160 if (
161 #ifdef USE_WIN32GUI
162 /*
163 * Scrollbar 3 isn't clearly redrawn without this.
164 *
165 * 1 2 3
166 * +-+------------+-+-----+-+----+
167 * | |$ hresize_sc| |$ | |$ |
168 * | |reen +1 | | | | |
169 * | | | | | | |
170 */
171 sb_moved
172 #else
173 sb_moved && !sb_resized && UI_SCREEN_TO_LAYOUT(term->screen)->bg_pic
174 #endif
175 ) {
176 ui_window_update_all(&term->scrollbar.window);
177 }
178 #endif
179 } else {
180 screen_moved = ui_window_move(&term->screen->window, x, y);
181 screen_resized = ui_window_resize_with_margin(&term->screen->window, child_width, child_height,
182 NOTIFY_TO_MYSELF);
183 }
184
185 #ifndef MANAGE_SUB_WINDOWS_BY_MYSELF
186 if (
187 #ifdef USE_QUARTZ
188 /* ui_window_move() clears screen in true transparency on MacOSX/Cocoa. */
189 term->screen->color_man->alpha < 255 ||
190 #endif
191 (screen_moved && !screen_resized && UI_SCREEN_TO_LAYOUT(term->screen)->bg_pic)) {
192 ui_window_update_all(&term->screen->window);
193 }
194 #endif
195
196 if (term->yfirst) {
197 if (term->next[1] && term->separator_y > 0) {
198 reset_layout(term->next[1], x, y + term->separator_y + SEPARATOR_HEIGHT, width,
199 height - term->separator_y - SEPARATOR_HEIGHT);
200 #ifdef MANAGE_SUB_WINDOWS_BY_MYSELF
201 ui_window_fill_with(&UI_SCREEN_TO_LAYOUT(term->screen)->window,
202 &UI_SCREEN_TO_LAYOUT(term->screen)->window.fg_color, x,
203 y + term->separator_y, width, SEPARATOR_HEIGHT);
204 #endif
205 }
206
207 if (term->next[0] && term->separator_x > 0) {
208 reset_layout(term->next[0], x + term->separator_x + SEPARATOR_WIDTH, y,
209 width - term->separator_x - SEPARATOR_WIDTH, child_height);
210 #ifdef MANAGE_SUB_WINDOWS_BY_MYSELF
211 ui_window_fill_with(&UI_SCREEN_TO_LAYOUT(term->screen)->window,
212 &UI_SCREEN_TO_LAYOUT(term->screen)->window.fg_color,
213 x + term->separator_x, y, SEPARATOR_WIDTH, child_height);
214 #endif
215 }
216 } else {
217 if (term->next[0] && term->separator_x > 0) {
218 reset_layout(term->next[0], x + term->separator_x + SEPARATOR_WIDTH, y,
219 width - term->separator_x - SEPARATOR_WIDTH, height);
220 #ifdef MANAGE_SUB_WINDOWS_BY_MYSELF
221 ui_window_fill_with(&UI_SCREEN_TO_LAYOUT(term->screen)->window,
222 &UI_SCREEN_TO_LAYOUT(term->screen)->window.fg_color,
223 x + term->separator_x, y, SEPARATOR_WIDTH, height);
224 #endif
225 }
226
227 if (term->next[1] && term->separator_y > 0) {
228 reset_layout(term->next[1], x, y + term->separator_y + SEPARATOR_HEIGHT, child_width,
229 height - term->separator_y - SEPARATOR_HEIGHT);
230 #ifdef MANAGE_SUB_WINDOWS_BY_MYSELF
231 ui_window_fill_with(&UI_SCREEN_TO_LAYOUT(term->screen)->window,
232 &UI_SCREEN_TO_LAYOUT(term->screen)->window.fg_color, x,
233 y + term->separator_y, child_width, SEPARATOR_HEIGHT);
234 #endif
235 }
236 }
237 }
238
search_term(struct terminal * term,ui_screen_t * screen)239 static struct terminal *search_term(struct terminal *term, ui_screen_t *screen) {
240 struct terminal *hit;
241
242 if (term->screen == screen) {
243 return term;
244 }
245
246 if ((term->next[0] && (hit = search_term(term->next[0], screen))) ||
247 (term->next[1] && (hit = search_term(term->next[1], screen)))) {
248 return hit;
249 }
250
251 return NULL;
252 }
253
search_parent_term(struct terminal * term,struct terminal * child)254 static struct terminal *search_parent_term(struct terminal *term, struct terminal *child) {
255 struct terminal *parent;
256
257 if (term->next[0] == child || term->next[1] == child) {
258 return term;
259 }
260
261 if ((term->next[0] && (parent = search_parent_term(term->next[0], child))) ||
262 (term->next[1] && (parent = search_parent_term(term->next[1], child)))) {
263 return parent;
264 }
265
266 return NULL;
267 }
268
search_next_screen(struct terminal * term,ui_screen_t * screen,int * found)269 static ui_screen_t *search_next_screen(struct terminal *term, ui_screen_t *screen, int *found) {
270 ui_screen_t *hit;
271 int idx;
272 int count;
273
274 if (term->screen == screen) {
275 *found = 1;
276 }
277
278 if (term->yfirst) {
279 idx = 0;
280 } else {
281 idx = 1;
282 }
283
284 for (count = 0; count < 2; count++) {
285 if (term->next[idx]) {
286 if (*found) {
287 return term->next[idx]->screen;
288 } else if ((hit = search_next_screen(term->next[idx], screen, found))) {
289 return hit;
290 }
291 }
292
293 idx = !idx;
294 }
295
296 return NULL;
297 }
298
search_prev_screen(struct terminal * term,ui_screen_t * screen,ui_screen_t ** prev)299 static ui_screen_t *search_prev_screen(struct terminal *term, ui_screen_t *screen,
300 ui_screen_t **prev) {
301 int idx;
302 int count;
303
304 if (*prev && term->screen == screen) {
305 return *prev;
306 }
307
308 *prev = term->screen;
309
310 if (term->yfirst) {
311 idx = 0;
312 } else {
313 idx = 1;
314 }
315
316 for (count = 0; count < 2; count++) {
317 if (term->next[idx] && search_prev_screen(term->next[idx], screen, prev)) {
318 return *prev;
319 }
320
321 idx = !idx;
322 }
323
324 return NULL;
325 }
326
get_current_term(struct terminal * term)327 static struct terminal *get_current_term(struct terminal *term) {
328 struct terminal *current;
329
330 if (term->screen->window.inputtable > 0) {
331 return term;
332 }
333
334 if ((term->next[0] && (current = get_current_term(term->next[0]))) ||
335 (term->next[1] && (current = get_current_term(term->next[1])))) {
336 return current;
337 }
338
339 return NULL;
340 }
341
get_current_window(ui_layout_t * layout)342 static ui_window_t *get_current_window(ui_layout_t *layout) {
343 struct terminal *term;
344
345 if ((term = get_current_term(&layout->term))) {
346 return &term->screen->window;
347 } else {
348 return &layout->term.screen->window;
349 }
350 }
351
get_separator_x(ui_screen_t * screen,u_int sb_width,u_int percent)352 static u_int get_separator_x(ui_screen_t *screen, u_int sb_width, u_int percent /* < 100 */
353 ) {
354 u_int width;
355 u_int fixed_width;
356 u_int sep_x;
357
358 width = screen->window.width;
359 fixed_width = screen->window.hmargin * 2 + sb_width;
360
361 sep_x = (width + fixed_width) * percent / 100;
362 if (sep_x < fixed_width + ui_col_width(screen)) {
363 return 0;
364 }
365
366 #ifdef PSEUDO_COLOR_DISPLAY
367 if (screen->window.disp->display->pixels_per_byte > 1) {
368 return sep_x - sep_x % screen->window.disp->display->pixels_per_byte - SEPARATOR_WIDTH;
369 } else
370 #endif
371 {
372 return sep_x - (sep_x - fixed_width) % ui_col_width(screen);
373 }
374 }
375
get_separator_y(ui_screen_t * screen,u_int percent)376 static u_int get_separator_y(ui_screen_t *screen, u_int percent /* < 100 */
377 ) {
378 u_int height;
379 u_int fixed_height;
380 u_int sep_y;
381
382 height = screen->window.height;
383 fixed_height = screen->window.vmargin * 2;
384
385 sep_y = (height + fixed_height) * percent / 100;
386 if (sep_y < fixed_height + ui_line_height(screen)) {
387 return 0;
388 }
389
390 return sep_y - (sep_y - fixed_height) % ui_line_height(screen);
391 }
392
393 /*
394 * callbacks of ui_window_t events.
395 */
396
window_finalized(ui_window_t * win)397 static void window_finalized(ui_window_t *win) {
398 ui_layout_t *layout;
399
400 layout = (ui_layout_t *)win;
401
402 ui_layout_destroy(layout);
403 }
404
405 #ifdef WALL_PICTURE_SIXEL_REPLACES_SYSTEM_PALETTE
reload_color_cache(struct terminal * term,int do_unload)406 static void reload_color_cache(struct terminal *term, int do_unload) {
407 ui_screen_reload_color_cache(term->screen, do_unload);
408
409 if (term->next[0]) {
410 reload_color_cache(term->next[0], 0);
411 }
412
413 if (term->next[1]) {
414 reload_color_cache(term->next[1], 0);
415 }
416 }
417 #endif
418
window_resized(ui_window_t * win)419 static void window_resized(ui_window_t *win) {
420 ui_layout_t *layout;
421 ui_picture_t *pic;
422
423 layout = (ui_layout_t *)win;
424
425 if (layout->bg_pic &&
426 (pic = ui_acquire_bg_picture(&layout->window, &layout->pic_mod, layout->pic_file_path))) {
427 ui_window_set_wall_picture(&layout->window, pic->pixmap, 0);
428 ui_release_picture(layout->bg_pic);
429 layout->bg_pic = pic;
430
431 #ifdef WALL_PICTURE_SIXEL_REPLACES_SYSTEM_PALETTE
432 if (layout->window.disp->depth == 4 && strstr(layout->pic_file_path, "six")) {
433 /*
434 * Color pallette of ui_display can be changed by ui_acquire_bg_picture().
435 * (see ui_display_set_cmap() called from fb/ui_imagelib.c.)
436 */
437 reload_color_cache(&layout->term, 1);
438 }
439 #endif
440 }
441
442 reset_layout(&layout->term, 0, 0, win->width, win->height);
443 }
444
child_window_resized(ui_window_t * win,ui_window_t * child)445 static void child_window_resized(ui_window_t *win, ui_window_t *child) {
446 ui_layout_t *layout;
447 u_int actual_width;
448
449 layout = (ui_layout_t *)win;
450
451 if (HAS_MULTI_CHILDREN(layout)) {
452 reset_layout(&layout->term, 0, 0, layout->window.width, layout->window.height);
453
454 return;
455 }
456
457 if (&layout->term.screen->window == child) {
458 if (layout->term.sb_mode == SBM_NONE) {
459 actual_width = ACTUAL_WIDTH(child);
460 } else {
461 actual_width =
462 ACTUAL_WIDTH(child) + ACTUAL_WIDTH(&layout->term.scrollbar.window) + SEPARATOR_WIDTH;
463 }
464
465 ui_window_resize_with_margin(&layout->window, actual_width, ACTUAL_HEIGHT(child),
466 NOTIFY_TO_NONE);
467
468 ui_window_resize_with_margin(&layout->term.scrollbar.window,
469 ACTUAL_WIDTH(&layout->term.scrollbar.window), ACTUAL_HEIGHT(child),
470 NOTIFY_TO_MYSELF);
471
472 if (layout->term.sb_mode == SBM_RIGHT) {
473 ui_window_move(&layout->term.scrollbar.window,
474 ACTUAL_WIDTH(&layout->term.screen->window) + SEPARATOR_WIDTH, 0);
475 }
476 } else if (&layout->term.scrollbar.window == child) {
477 if (layout->term.sb_mode == SBM_NONE) {
478 return;
479 }
480
481 ui_window_resize_with_margin(
482 &layout->window,
483 ACTUAL_WIDTH(child) + ACTUAL_WIDTH(&layout->term.screen->window) + SEPARATOR_WIDTH,
484 ACTUAL_HEIGHT(child), NOTIFY_TO_NONE);
485
486 if (layout->term.sb_mode == SBM_LEFT) {
487 ui_window_move(&layout->term.screen->window,
488 ACTUAL_WIDTH(&layout->term.scrollbar.window) + SEPARATOR_WIDTH, 0);
489 }
490 } else {
491 #ifdef DEBUG
492 bl_warn_printf(BL_DEBUG_TAG " illegal child. this event should be invoken only by screen.\n");
493 #endif
494 }
495 }
496
window_exposed(ui_window_t * win,int x,int y,u_int width,u_int height)497 static void window_exposed(ui_window_t *win, int x, int y, u_int width, u_int height) {
498 ui_window_fill_with(win, &win->fg_color, x, y, width,
499 height);
500 }
501
key_pressed(ui_window_t * win,XKeyEvent * event)502 static void key_pressed(ui_window_t *win, XKeyEvent *event) {
503 ui_layout_t *layout;
504 ui_window_t *child;
505
506 layout = (ui_layout_t *)win;
507 child = get_current_window(layout);
508
509 /* key_pressed of ui_screen_t can be NULL. (see xterm_lock_keyboard in ui_screen.c) */
510 if (child->key_pressed) {
511 /* dispatch to screen */
512 (*child->key_pressed)(child, event);
513 }
514 }
515
utf_selection_notified(ui_window_t * win,u_char * buf,size_t len)516 static void utf_selection_notified(ui_window_t *win, u_char *buf, size_t len) {
517 ui_layout_t *layout;
518 ui_window_t *child;
519
520 layout = (ui_layout_t *)win;
521 child = get_current_window(layout);
522
523 /* dispatch to screen */
524 (*child->utf_selection_notified)(child, buf, len);
525 }
526
xct_selection_notified(ui_window_t * win,u_char * buf,size_t len)527 static void xct_selection_notified(ui_window_t *win, u_char *buf, size_t len) {
528 ui_layout_t *layout;
529 ui_window_t *child;
530
531 layout = (ui_layout_t *)win;
532 child = get_current_window(layout);
533
534 /* dispatch to screen */
535 (*child->xct_selection_notified)(child, buf, len);
536 }
537
538 #ifndef DISABLE_XDND
set_xdnd_config(ui_window_t * win,char * dev,char * buf,char * value)539 static void set_xdnd_config(ui_window_t *win, char *dev, char *buf, char *value) {
540 ui_layout_t *layout;
541 ui_window_t *child;
542
543 layout = (ui_layout_t *)win;
544 child = get_current_window(layout);
545
546 /* dispatch to screen */
547 (*child->set_xdnd_config)(child, dev, buf, value);
548 }
549 #endif
550
window_destroyed_intern(struct terminal * term)551 static void window_destroyed_intern(struct terminal *term) {
552 if (term->next[0]) {
553 window_destroyed_intern(term->next[0]);
554 }
555
556 if (term->next[1]) {
557 window_destroyed_intern(term->next[1]);
558 }
559
560 /* dispatch to screen */
561 (*term->screen->window.window_destroyed)(&term->screen->window);
562 }
563
window_destroyed(ui_window_t * win)564 static void window_destroyed(ui_window_t *win) {
565 ui_layout_t *layout;
566
567 layout = (ui_layout_t *)win;
568
569 window_destroyed_intern(&layout->term);
570 }
571
572 #ifndef USE_QUARTZ
573 static void change_sb_mode_intern(struct terminal *term, ui_sb_mode_t new_mode, int dynamic_change);
574
check_scrollbar_visible(struct terminal * term)575 static void check_scrollbar_visible(struct terminal *term) {
576 if (term->autohide_scrollbar && term->sb_mode == SBM_RIGHT) {
577 if (term->scrollbar.window.button_is_pressing) {
578 term->idling_count = 0;
579 } else if (++term->idling_count == 30) {
580 term->idling_count = 0;
581 change_sb_mode_intern(term, SBM_NONE, 1);
582 }
583 }
584
585 if (term->next[0]) {
586 check_scrollbar_visible(term->next[0]);
587 }
588
589 if (term->next[1]) {
590 check_scrollbar_visible(term->next[1]);
591 }
592 }
593
window_idling(ui_window_t * win)594 static void window_idling(ui_window_t *win) {
595 ui_layout_t *layout;
596
597 layout = (ui_layout_t *)win;
598
599 check_scrollbar_visible(&layout->term);
600 }
601 #endif
602
603 #if 0
604 /*
605 * Overriding methods of ui_scrollbar_t.
606 */
607
608 static void sb_key_pressed(ui_window_t *win, XKeyEvent *event) {
609 struct terminal term;
610 ui_screen_t **screen;
611
612 screen = ((void *)win) - (((void *)&term.scrollbar) - ((void *)&term.screen));
613
614 /* dispatch to screen */
615 (*(*screen)->window.key_pressed)(&(*screen)->window, event);
616 }
617 #endif
618
619 /*
620 * Overriding methods of vt_screen_listener_t of ui_screen_t.
621 */
622
line_scrolled_out(void * p)623 static void line_scrolled_out(void *p /* must be ui_screen_t(, or child of ui_layout_t) */
624 ) {
625 ui_layout_t *layout;
626 struct terminal *term;
627
628 layout = UI_SCREEN_TO_LAYOUT((ui_screen_t *)p);
629
630 (*layout->line_scrolled_out)(p);
631
632 if ((term = search_term(&layout->term, p))) {
633 if (vt_term_log_size_is_unlimited(((ui_screen_t *)p)->term)) {
634 ui_scrollbar_set_num_log_lines(&term->scrollbar,
635 vt_term_get_log_size(((ui_screen_t *)p)->term));
636 }
637
638 ui_scrollbar_line_is_added(&term->scrollbar);
639 }
640 }
641
642 /*
643 * callbacks of ui_sb_event_listener_t events.
644 */
645
screen_scroll_to(void * p,int row)646 static void screen_scroll_to(void *p, int row) {
647 struct terminal *term;
648
649 term = p;
650
651 ui_screen_scroll_to(term->screen, row);
652 }
653
screen_scroll_upward(void * p,u_int size)654 static void screen_scroll_upward(void *p, u_int size) {
655 struct terminal *term;
656
657 term = p;
658
659 ui_screen_scroll_upward(term->screen, size);
660 }
661
screen_scroll_downward(void * p,u_int size)662 static void screen_scroll_downward(void *p, u_int size) {
663 struct terminal *term;
664
665 term = p;
666
667 ui_screen_scroll_downward(term->screen, size);
668 }
669
screen_is_static(void * p)670 static int screen_is_static(void *p) {
671 struct terminal *term;
672
673 term = p;
674
675 if (vt_term_is_backscrolling(term->screen->term) == BSM_STATIC) {
676 return 1;
677 } else {
678 return 0;
679 }
680 }
681
682 /*
683 * callbacks of ui_screen_scroll_event_listener_t events.
684 */
685
bs_mode_exited(void * p)686 static void bs_mode_exited(void *p) {
687 struct terminal *term;
688
689 term = p;
690
691 ui_scrollbar_reset(&term->scrollbar);
692 }
693
scrolled_upward(void * p,u_int size)694 static void scrolled_upward(void *p, u_int size) {
695 struct terminal *term;
696
697 term = p;
698
699 ui_scrollbar_move_downward(&term->scrollbar, size);
700 }
701
scrolled_downward(void * p,u_int size)702 static void scrolled_downward(void *p, u_int size) {
703 struct terminal *term;
704
705 term = p;
706
707 ui_scrollbar_move_upward(&term->scrollbar, size);
708 }
709
scrolled_to(void * p,int row)710 static void scrolled_to(void *p, int row) {
711 struct terminal *term;
712
713 term = p;
714
715 ui_scrollbar_move(&term->scrollbar, row);
716 }
717
log_size_changed(void * p,u_int log_size)718 static void log_size_changed(void *p, u_int log_size) {
719 struct terminal *term;
720
721 term = p;
722
723 ui_scrollbar_set_num_log_lines(&term->scrollbar, log_size);
724 }
725
line_height_changed(void * p,u_int line_height)726 static void line_height_changed(void *p, u_int line_height) {
727 struct terminal *term;
728
729 term = p;
730
731 ui_scrollbar_set_line_height(&term->scrollbar, line_height);
732 }
733
change_fg_color(void * p,char * color)734 static void change_fg_color(void *p, char *color) {
735 struct terminal *term;
736
737 term = p;
738
739 ui_scrollbar_set_fg_color(&term->scrollbar, color);
740 }
741
get_fg_color(void * p)742 static char *get_fg_color(void *p) {
743 struct terminal *term;
744
745 term = p;
746
747 return term->scrollbar.fg_color;
748 }
749
change_bg_color(void * p,char * color)750 static void change_bg_color(void *p, char *color) {
751 struct terminal *term;
752
753 term = p;
754
755 ui_scrollbar_set_bg_color(&term->scrollbar, color);
756 }
757
get_bg_color(void * p)758 static char *get_bg_color(void *p) {
759 struct terminal *term;
760
761 term = p;
762
763 return term->scrollbar.bg_color;
764 }
765
change_view(void * p,char * name)766 static void change_view(void *p, char *name) {
767 struct terminal *term;
768
769 term = p;
770
771 ui_scrollbar_change_view(&term->scrollbar, name);
772 }
773
get_view_name(void * p)774 static char *get_view_name(void *p) {
775 struct terminal *term;
776
777 term = p;
778
779 return term->scrollbar.view_name;
780 }
781
transparent_state_changed(void * p,int is_transparent,ui_picture_modifier_t * pic_mod)782 static void transparent_state_changed(void *p, int is_transparent, ui_picture_modifier_t *pic_mod) {
783 struct terminal *term;
784
785 term = p;
786
787 if (is_transparent == 1) {
788 ui_scrollbar_set_transparent(&term->scrollbar, pic_mod, 1);
789 } else {
790 ui_scrollbar_unset_transparent(&term->scrollbar);
791 }
792 }
793
sb_mode(void * p)794 static ui_sb_mode_t sb_mode(void *p) {
795 struct terminal *term;
796
797 term = p;
798
799 if (term->autohide_scrollbar) {
800 return SBM_AUTOHIDE;
801 } else {
802 return term->sb_mode;
803 }
804 }
805
screen_color_changed(void * p)806 static void screen_color_changed(void *p) {
807 ui_layout_t *layout;
808
809 layout = UI_SCREEN_TO_LAYOUT(((struct terminal *)p)->screen);
810
811 if (&layout->term == p) {
812 ui_window_set_fg_color(&layout->window, &layout->term.screen->window.fg_color);
813 ui_window_set_bg_color(&layout->window, &layout->term.screen->window.bg_color);
814 }
815 }
816
total_width(struct terminal * term)817 static u_int total_width(struct terminal *term) {
818 u_int width;
819
820 width = ACTUAL_WIDTH(&term->screen->window);
821
822 if (term->sb_mode != SBM_NONE) {
823 width += (ACTUAL_WIDTH(&term->scrollbar.window) + SEPARATOR_WIDTH);
824 }
825
826 if (term->separator_x > 0 && term->next[0]) {
827 width += (total_width(term->next[0]) + SEPARATOR_WIDTH);
828 }
829
830 return width;
831 }
832
total_height(struct terminal * term)833 static u_int total_height(struct terminal *term) {
834 u_int height;
835
836 height = ACTUAL_HEIGHT(&term->screen->window);
837
838 if (term->separator_y > 0 && term->next[1]) {
839 height += (total_height(term->next[1]) + SEPARATOR_HEIGHT);
840 }
841
842 return height;
843 }
844
clear_hint_size(struct terminal * term)845 static void clear_hint_size(struct terminal *term) {
846 int count;
847
848 for (count = 0; count < 2; count++) {
849 if (term->next[count]) {
850 clear_hint_size(term->next[count]);
851 }
852 }
853
854 term->screen->window.sizehint_flag = 0;
855 term->scrollbar.window.sizehint_flag = 0;
856 }
857
total_hint_width(struct terminal * term,u_int * width)858 static void total_hint_width(struct terminal *term, u_int *width) {
859 if (term->sb_mode != SBM_NONE) {
860 *width += SEPARATOR_WIDTH;
861 }
862
863 if (term->next[0]) {
864 *width += SEPARATOR_WIDTH;
865 total_hint_width(term->next[0], width);
866 }
867
868 if (term->next[1]) {
869 clear_hint_size(term->next[1]);
870 }
871
872 term->screen->window.sizehint_flag = SIZEHINT_WIDTH;
873 term->scrollbar.window.sizehint_flag = SIZEHINT_WIDTH;
874 }
875
total_hint_height(struct terminal * term,u_int * height)876 static void total_hint_height(struct terminal *term, u_int *height) {
877 if (term->next[0]) {
878 clear_hint_size(term->next[0]);
879 }
880
881 if (term->next[1]) {
882 *height += SEPARATOR_HEIGHT;
883 total_hint_height(term->next[1], height);
884 }
885
886 term->screen->window.sizehint_flag = SIZEHINT_HEIGHT;
887 term->scrollbar.window.sizehint_flag = 0;
888 }
889
total_hint_size(struct terminal * term,u_int * width,u_int * height)890 static void total_hint_size(struct terminal *term, u_int *width, u_int *height) {
891 if (term->sb_mode != SBM_NONE) {
892 *width += SEPARATOR_WIDTH;
893 }
894
895 if (term->next[0]) {
896 *width += SEPARATOR_WIDTH;
897 total_hint_width(term->next[0], width);
898 }
899
900 if (term->next[1]) {
901 *height += SEPARATOR_HEIGHT;
902 total_hint_height(term->next[1], height);
903 }
904
905 term->screen->window.sizehint_flag = SIZEHINT_HEIGHT|SIZEHINT_WIDTH;
906 term->scrollbar.window.sizehint_flag = SIZEHINT_WIDTH;
907 }
908
update_normal_hints(ui_layout_t * layout)909 static void update_normal_hints(ui_layout_t *layout) {
910 u_int min_width = 0;
911 u_int min_height = 0;
912
913 total_hint_size(&layout->term, &min_width, &min_height);
914 ui_window_set_normal_hints(&layout->window, min_width, min_height, 0, 0);
915 }
916
917 #ifndef USE_QUARTZ
need_idling_event(struct terminal * term)918 static int need_idling_event(struct terminal *term) {
919 if (!term->autohide_scrollbar && (!term->next[0] || !need_idling_event(term->next[0])) &&
920 (!term->next[1] || !need_idling_event(term->next[1]))) {
921 return 0;
922 } else {
923 return 1;
924 }
925 }
926 #endif
927
change_sb_mode_intern(struct terminal * term,ui_sb_mode_t new_mode,int dynamic_change)928 static void change_sb_mode_intern(struct terminal *term, ui_sb_mode_t new_mode,
929 int dynamic_change) {
930 ui_layout_t *layout;
931 ui_sb_mode_t old_mode;
932
933 layout = UI_SCREEN_TO_LAYOUT(term->screen);
934
935 if (new_mode == SBM_AUTOHIDE) {
936 if (term->autohide_scrollbar) {
937 return;
938 }
939
940 new_mode = SBM_NONE;
941 term->autohide_scrollbar = 1;
942 ui_window_add_event_mask(&term->screen->window, PointerMotionMask);
943 #ifndef USE_QUARTZ
944 layout->window.idling = window_idling;
945 #endif
946 } else if (!dynamic_change) {
947 term->autohide_scrollbar = 0;
948 ui_window_remove_event_mask(&term->screen->window, PointerMotionMask);
949 (*term->screen->xterm_listener.set_mouse_report)(term->screen->xterm_listener.self);
950
951 #ifndef USE_QUARTZ
952 if (!need_idling_event(&layout->term)) {
953 layout->window.idling = NULL;
954 }
955 #endif
956 }
957
958 if ((old_mode = term->sb_mode) == new_mode) {
959 return;
960 }
961
962 /*
963 * term->sb_mode should be changed before ui_window_unmap/ui_window_map
964 * for framebuffer. (see fb/ui_window.c)
965 */
966 term->sb_mode = new_mode;
967
968 if (new_mode == SBM_NONE) {
969 ui_window_unmap(&term->scrollbar.window);
970 }
971 #ifdef MANAGE_ROOT_WINDOWS_BY_MYSELF
972 else if (old_mode == SBM_NONE) {
973 /* scrollbar's height may have been changed. */
974 ui_window_resize_with_margin(&term->scrollbar.window, ACTUAL_WIDTH(&term->scrollbar.window),
975 ACTUAL_HEIGHT(&term->screen->window), NOTIFY_TO_MYSELF);
976
977 /* Don't call ui_window_map() because scrollbar's position may be
978 * inappropriate. */
979 term->scrollbar.window.is_mapped = 1;
980 term->scrollbar.window.x = -1; /* To redraw scrollbar in ui_window_move() */
981
982 if (new_mode == SBM_LEFT) {
983 /* Shrink window size before ui_window_move() in reset_layout(). */
984 ui_window_resize_with_margin(&term->screen->window, ACTUAL_WIDTH(&term->screen->window) -
985 SCROLLBAR_WIDTH(term->scrollbar),
986 ACTUAL_HEIGHT(&term->screen->window), 0);
987 }
988 }
989
990 reset_layout(&layout->term, 0, 0, layout->window.width, layout->window.height);
991
992 if (new_mode == SBM_NONE) {
993 /* Window size was enlarged but not exposed. */
994 (*term->screen->window.window_exposed)(
995 &term->screen->window,
996 ACTUAL_WIDTH(&term->screen->window) - SCROLLBAR_WIDTH(term->scrollbar), 0,
997 SCROLLBAR_WIDTH(term->scrollbar), ACTUAL_HEIGHT(&term->screen->window));
998 }
999 #else
1000 else if (old_mode == SBM_NONE) {
1001 ui_window_map(&term->scrollbar.window);
1002 #ifdef MANAGE_SUB_WINDOWS_BY_MYSELF
1003 /* To show hidden scrollbar whose size and position aren't changed. (for wayland) */
1004 term->scrollbar.window.x = -1; /* To redraw scrollbar in ui_window_move() */
1005 #endif
1006 } else {
1007 goto noresize;
1008 }
1009
1010 if (term->screen->window.x + ACTUAL_WIDTH(&term->screen->window) +
1011 (old_mode != SBM_NONE ? SCROLLBAR_WIDTH(term->scrollbar) : 0) >=
1012 ACTUAL_WIDTH(&layout->window)) {
1013 /* This should be called before ui_window_resize(&layout->window) */
1014 update_normal_hints(layout);
1015 if (ui_window_resize(&layout->window, total_width(&layout->term), total_height(&layout->term),
1016 NOTIFY_TO_MYSELF)) {
1017 return;
1018 }
1019 }
1020
1021 noresize:
1022 reset_layout(&layout->term, 0, 0, layout->window.width, layout->window.height);
1023 #endif
1024
1025 update_normal_hints(layout);
1026 }
1027
change_sb_mode(void * p,ui_sb_mode_t new_mode)1028 static void change_sb_mode(void *p, ui_sb_mode_t new_mode) {
1029 change_sb_mode_intern(p, new_mode, 0);
1030 }
1031
term_changed(void * p,u_int log_size,u_int logged_lines)1032 static void term_changed(void *p, u_int log_size, u_int logged_lines) {
1033 struct terminal *term;
1034
1035 term = p;
1036
1037 ui_scrollbar_set_num_log_lines(&term->scrollbar, log_size);
1038 ui_scrollbar_set_num_filled_log_lines(&term->scrollbar, logged_lines);
1039 }
1040
screen_pointer_motion(ui_window_t * win,XMotionEvent * event)1041 static void screen_pointer_motion(ui_window_t *win, XMotionEvent *event) {
1042 struct terminal *term;
1043 ui_layout_t *layout;
1044
1045 layout = UI_SCREEN_TO_LAYOUT((ui_screen_t *)win);
1046 (*layout->pointer_motion)(win, event);
1047
1048 term = search_term(&layout->term, (ui_screen_t *)win);
1049
1050 if (term->autohide_scrollbar) {
1051 ui_sb_mode_t mode;
1052
1053 if (((int)win->width) - 2 <= event->x && 0 <= event->y && event->y < win->height) {
1054 if (term->scrollbar.window.is_mapped) {
1055 return;
1056 }
1057
1058 mode = SBM_RIGHT;
1059 } else {
1060 if (!term->scrollbar.window.is_mapped) {
1061 return;
1062 }
1063
1064 mode = SBM_NONE;
1065 }
1066
1067 change_sb_mode_intern(term, mode, 1);
1068 }
1069 }
1070
destroy_term(struct terminal * term)1071 static void destroy_term(struct terminal *term) {
1072 ui_scrollbar_final(&term->scrollbar);
1073
1074 if (term->next[0]) {
1075 destroy_term(term->next[0]);
1076 free(term->next[0]);
1077 }
1078
1079 if (term->next[1]) {
1080 destroy_term(term->next[1]);
1081 free(term->next[1]);
1082 }
1083 }
1084
destroy_screen_bg_pic(ui_screen_t * screen)1085 static void destroy_screen_bg_pic(ui_screen_t *screen) {
1086 free(screen->pic_file_path);
1087 screen->pic_file_path = NULL;
1088 ui_release_picture(screen->bg_pic);
1089 screen->bg_pic = NULL;
1090 }
1091
destroy_layout_bg_pic(ui_layout_t * layout)1092 static void destroy_layout_bg_pic(ui_layout_t *layout) {
1093 free(layout->pic_file_path);
1094 layout->pic_file_path = NULL;
1095 ui_release_picture(layout->bg_pic);
1096 layout->bg_pic = NULL;
1097 }
1098
save_screen_bg_pic(ui_layout_t * layout)1099 static void save_screen_bg_pic(ui_layout_t *layout) {
1100 /* layout->bg_pic has been already set. */
1101 ui_release_picture(layout->term.screen->bg_pic);
1102 layout->term.screen->bg_pic = NULL;
1103
1104 layout->pic_file_path = layout->term.screen->pic_file_path;
1105 layout->term.screen->pic_file_path = NULL;
1106
1107 layout->pic_mod = layout->term.screen->pic_mod;
1108 }
1109
restore_screen_bg_pic(ui_layout_t * layout)1110 static void restore_screen_bg_pic(ui_layout_t *layout) {
1111 layout->term.screen->pic_file_path = layout->pic_file_path;
1112 layout->pic_file_path = NULL;
1113 layout->term.screen->bg_pic = layout->bg_pic;
1114 layout->bg_pic = NULL;
1115 layout->term.screen->pic_mod = layout->pic_mod;
1116 }
1117
1118 /* --- global functions --- */
1119
ui_layout_new(ui_screen_t * screen,char * view_name,char * fg_color,char * bg_color,ui_sb_mode_t mode,u_int hmargin,u_int vmargin)1120 ui_layout_t *ui_layout_new(ui_screen_t *screen, char *view_name, char *fg_color, char *bg_color,
1121 ui_sb_mode_t mode, u_int hmargin, u_int vmargin) {
1122 ui_layout_t *layout;
1123 u_int actual_width;
1124 u_int min_width;
1125 int screen_x;
1126 int sb_x;
1127 int sb_map;
1128
1129 if ((layout = calloc(1, sizeof(ui_layout_t))) == NULL) {
1130 return NULL;
1131 }
1132
1133 /*
1134 * event callbacks.
1135 */
1136 layout->term.sb_listener.self = &layout->term;
1137 layout->term.sb_listener.screen_scroll_to = screen_scroll_to;
1138 layout->term.sb_listener.screen_scroll_upward = screen_scroll_upward;
1139 layout->term.sb_listener.screen_scroll_downward = screen_scroll_downward;
1140 layout->term.sb_listener.screen_is_static = screen_is_static;
1141
1142 if (ui_scrollbar_init(
1143 &layout->term.scrollbar, &layout->term.sb_listener, view_name, fg_color, bg_color,
1144 ACTUAL_HEIGHT(&screen->window), ui_line_height(screen),
1145 vt_term_get_log_size(screen->term), vt_term_get_num_logged_lines(screen->term),
1146 screen->window.is_transparent, ui_screen_get_picture_modifier(screen)) == 0) {
1147 #ifdef DEBUG
1148 bl_warn_printf(BL_DEBUG_TAG " ui_scrollbar_init() failed.\n");
1149 #endif
1150
1151 goto error;
1152 }
1153 #if 0
1154 layout->term.scrollbar.window.key_pressed = sb_key_pressed;
1155 #endif
1156 layout->term.screen = screen;
1157
1158 /*
1159 * event callbacks.
1160 */
1161 layout->term.screen_scroll_listener.self = &layout->term;
1162 layout->term.screen_scroll_listener.bs_mode_entered = NULL;
1163 layout->term.screen_scroll_listener.bs_mode_exited = bs_mode_exited;
1164 layout->term.screen_scroll_listener.scrolled_upward = scrolled_upward;
1165 layout->term.screen_scroll_listener.scrolled_downward = scrolled_downward;
1166 layout->term.screen_scroll_listener.scrolled_to = scrolled_to;
1167 layout->term.screen_scroll_listener.log_size_changed = log_size_changed;
1168 layout->term.screen_scroll_listener.line_height_changed = line_height_changed;
1169 layout->term.screen_scroll_listener.change_fg_color = change_fg_color;
1170 layout->term.screen_scroll_listener.fg_color = get_fg_color;
1171 layout->term.screen_scroll_listener.change_bg_color = change_bg_color;
1172 layout->term.screen_scroll_listener.bg_color = get_bg_color;
1173 layout->term.screen_scroll_listener.change_view = change_view;
1174 layout->term.screen_scroll_listener.view_name = get_view_name;
1175 layout->term.screen_scroll_listener.transparent_state_changed = transparent_state_changed;
1176 layout->term.screen_scroll_listener.sb_mode = sb_mode;
1177 layout->term.screen_scroll_listener.change_sb_mode = change_sb_mode;
1178 layout->term.screen_scroll_listener.term_changed = term_changed;
1179 layout->term.screen_scroll_listener.screen_color_changed = screen_color_changed;
1180
1181 ui_set_screen_scroll_listener(screen, &layout->term.screen_scroll_listener);
1182
1183 layout->line_scrolled_out = screen->screen_listener.line_scrolled_out;
1184 screen->screen_listener.line_scrolled_out = line_scrolled_out;
1185
1186 if (mode == SBM_AUTOHIDE) {
1187 layout->term.sb_mode = SBM_NONE;
1188 layout->term.autohide_scrollbar = 1;
1189 } else {
1190 layout->term.sb_mode = mode;
1191 }
1192 layout->pointer_motion = screen->window.pointer_motion;
1193 screen->window.pointer_motion = screen_pointer_motion;
1194
1195 if (layout->term.sb_mode == SBM_NONE) {
1196 actual_width = ACTUAL_WIDTH(&screen->window);
1197
1198 min_width = 0;
1199 } else {
1200 actual_width = ACTUAL_WIDTH(&screen->window) + SCROLLBAR_WIDTH(layout->term.scrollbar);
1201
1202 min_width = SEPARATOR_WIDTH;
1203 }
1204
1205 if (ui_window_init(&layout->window, actual_width, ACTUAL_HEIGHT(&screen->window), min_width, 0, 0,
1206 0, hmargin, vmargin, 0, 0) == 0) {
1207 #ifdef DEBUG
1208 bl_warn_printf(BL_DEBUG_TAG " ui_window_init() failed.\n");
1209 #endif
1210
1211 goto error;
1212 }
1213
1214 if (layout->term.sb_mode == SBM_RIGHT) {
1215 screen_x = 0;
1216 sb_x = ACTUAL_WIDTH(&screen->window) + SEPARATOR_WIDTH;
1217 sb_map = 1;
1218 } else if (layout->term.sb_mode == SBM_LEFT) {
1219 screen_x = ACTUAL_WIDTH(&layout->term.scrollbar.window) + SEPARATOR_WIDTH;
1220 sb_x = 0;
1221 sb_map = 1;
1222 } else /* if( layout->term.sb_mode == SBM_NONE) */
1223 {
1224 screen_x = sb_x = 0; /* overlaying scrollbar window */
1225 sb_map = 0;
1226 }
1227
1228 orig_window_focused = screen->window.window_focused;
1229 orig_xterm_set_window_name = screen->xterm_listener.set_window_name;
1230 orig_xterm_set_icon_name = screen->xterm_listener.set_icon_name;
1231 screen->window.window_focused = window_focused;
1232 screen->xterm_listener.set_window_name = xterm_set_window_name;
1233 screen->xterm_listener.set_icon_name = xterm_set_icon_name;
1234
1235 if (!ui_window_add_child(&layout->window, &layout->term.scrollbar.window, sb_x, 0, sb_map) ||
1236 !ui_window_add_child(&layout->window, &screen->window, screen_x, 0, 1)) {
1237 goto error;
1238 }
1239
1240 /*
1241 * event call backs.
1242 */
1243 ui_window_add_event_mask(&layout->window, KeyPressMask);
1244 layout->window.window_finalized = window_finalized;
1245 layout->window.window_resized = window_resized;
1246 layout->window.child_window_resized = child_window_resized;
1247 layout->window.window_exposed = window_exposed;
1248 layout->window.key_pressed = key_pressed;
1249 layout->window.utf_selection_notified = utf_selection_notified;
1250 layout->window.xct_selection_notified = xct_selection_notified;
1251 layout->window.window_destroyed = window_destroyed;
1252 #ifndef DISABLE_XDND
1253 layout->window.set_xdnd_config = set_xdnd_config;
1254 #endif
1255
1256 if (layout->term.autohide_scrollbar) {
1257 #ifndef USE_QUARTZ
1258 layout->window.idling = window_idling;
1259 #endif
1260 ui_window_add_event_mask(&screen->window, PointerMotionMask);
1261 }
1262
1263 return layout;
1264
1265 error:
1266 free(layout);
1267
1268 return NULL;
1269 }
1270
ui_layout_destroy(ui_layout_t * layout)1271 void ui_layout_destroy(ui_layout_t *layout) {
1272 if (layout->bg_pic) {
1273 destroy_layout_bg_pic(layout);
1274 }
1275
1276 destroy_term(&layout->term);
1277 free(layout);
1278 }
1279
ui_layout_add_child(ui_layout_t * layout,ui_screen_t * screen,int horizontal,const char * sep_str)1280 int ui_layout_add_child(ui_layout_t *layout, ui_screen_t *screen, int horizontal,
1281 const char *sep_str /* "XX%" or "XX" */
1282 ) {
1283 struct terminal *next;
1284 struct terminal *term;
1285 u_int sep = 50;
1286 int is_percent = 1;
1287
1288 if (sep_str) {
1289 char *p;
1290
1291 if ((p = strchr(sep_str, '%'))) {
1292 if (!bl_str_n_to_uint(&sep, sep_str, p - sep_str) || sep >= 100 || sep == 0) {
1293 return 0;
1294 }
1295 } else {
1296 if (!bl_str_to_uint(&sep, sep_str) || sep == 0) {
1297 return 0;
1298 }
1299
1300 is_percent = 0;
1301 }
1302 }
1303
1304 if (!(next = calloc(1, sizeof(struct terminal)))) {
1305 return 0;
1306 }
1307
1308 if (!(term = get_current_term(&layout->term))) {
1309 term = &layout->term;
1310 }
1311
1312 if (horizontal) {
1313 u_int orig_separator_x;
1314 u_int sb_width;
1315
1316 orig_separator_x = term->separator_x;
1317
1318 if (term->sb_mode != SBM_NONE) {
1319 sb_width = SCROLLBAR_WIDTH(term->scrollbar);
1320 } else {
1321 sb_width = 0;
1322 }
1323
1324 if (is_percent ? ((term->separator_x = get_separator_x(term->screen, sb_width, sep)) == 0)
1325 : ((term->separator_x = screen->window.hmargin * 2 +
1326 ui_col_width(term->screen) * sep + sb_width) >=
1327 ACTUAL_WIDTH(&term->screen->window) + sb_width)) {
1328 term->separator_x = orig_separator_x;
1329 free(next);
1330
1331 return 0;
1332 }
1333
1334 next->next[0] = term->next[0];
1335 term->next[0] = next;
1336
1337 if (orig_separator_x > 0) {
1338 next->separator_x = orig_separator_x - term->separator_x;
1339 }
1340 } else {
1341 u_int orig_separator_y;
1342
1343 orig_separator_y = term->separator_y;
1344
1345 if (is_percent ? ((term->separator_y = get_separator_y(term->screen, sep)) == 0)
1346 : ((term->separator_y = screen->window.vmargin * 2 +
1347 ui_line_height(term->screen) * sep) >=
1348 ACTUAL_HEIGHT(&term->screen->window))) {
1349 term->separator_y = orig_separator_y;
1350 free(next);
1351
1352 return 0;
1353 }
1354
1355 if (term->separator_x == 0) {
1356 term->yfirst = 1;
1357 }
1358
1359 next->next[1] = term->next[1];
1360 term->next[1] = next;
1361
1362 if (orig_separator_y > 0) {
1363 next->separator_y = orig_separator_y - term->separator_y;
1364 }
1365 }
1366
1367 next->sb_listener = term->sb_listener;
1368 next->sb_listener.self = next;
1369
1370 ui_scrollbar_init(
1371 &next->scrollbar, &next->sb_listener, term->scrollbar.view_name, term->scrollbar.fg_color,
1372 term->scrollbar.bg_color, ACTUAL_HEIGHT(&screen->window), ui_line_height(screen),
1373 vt_term_get_log_size(screen->term), vt_term_get_num_logged_lines(screen->term),
1374 screen->window.is_transparent, ui_screen_get_picture_modifier(screen));
1375 #if 0
1376 next->scrollbar.window.key_pressed = sb_key_pressed;
1377 #endif
1378 ui_window_add_child(&layout->window, &next->scrollbar.window, 0, 0, 0);
1379 ui_window_show(&next->scrollbar.window, 0);
1380
1381 next->screen_scroll_listener = term->screen_scroll_listener;
1382 next->screen_scroll_listener.self = next;
1383
1384 next->screen = screen;
1385 ui_set_screen_scroll_listener(screen, &next->screen_scroll_listener);
1386 screen->screen_listener.line_scrolled_out = line_scrolled_out;
1387 screen->window.window_focused = window_focused;
1388 screen->xterm_listener.set_window_name = xterm_set_window_name;
1389 screen->xterm_listener.set_icon_name = xterm_set_icon_name;
1390 ui_window_add_child(&layout->window, &screen->window, 0, 0, 0);
1391
1392 if (screen->pic_file_path) {
1393 destroy_screen_bg_pic(screen);
1394 }
1395
1396 ui_window_show(&screen->window, 0);
1397
1398 if (!ui_window_has_wall_picture(&layout->window) && layout->term.screen->pic_file_path) {
1399 if ((layout->bg_pic = ui_acquire_bg_picture(&layout->window, &layout->term.screen->pic_mod,
1400 layout->term.screen->pic_file_path))) {
1401 save_screen_bg_pic(layout);
1402 ui_window_set_wall_picture(&layout->window, layout->bg_pic->pixmap, 0);
1403
1404 #ifdef WALL_PICTURE_SIXEL_REPLACES_SYSTEM_PALETTE
1405 if (layout->window.disp->depth == 4 && strstr(layout->pic_file_path, "six")) {
1406 /*
1407 * Color pallette of ui_display can be changed by
1408 * ui_acquire_bg_picture().
1409 * (see ui_display_set_cmap() called from fb/ui_imagelib.c.)
1410 */
1411 reload_color_cache(&layout->term, 1);
1412 }
1413 #endif
1414 }
1415 }
1416
1417 next->sb_mode = term->sb_mode;
1418 if ((next->autohide_scrollbar = term->autohide_scrollbar)) {
1419 ui_window_add_event_mask(&screen->window, PointerMotionMask);
1420 }
1421 screen->window.pointer_motion = screen_pointer_motion;
1422
1423 reset_layout(&layout->term, 0, 0, layout->window.width, layout->window.height);
1424
1425 if (term->sb_mode != SBM_NONE) {
1426 ui_window_map(&next->scrollbar.window);
1427 }
1428 ui_window_map(&screen->window);
1429
1430 ui_window_set_input_focus(&term->screen->window);
1431
1432 update_normal_hints(layout);
1433
1434 return 1;
1435 }
1436
ui_layout_remove_child(ui_layout_t * layout,ui_screen_t * screen)1437 int ui_layout_remove_child(ui_layout_t *layout, ui_screen_t *screen) {
1438 struct terminal *term;
1439 int idx2;
1440 #ifndef MANAGE_SUB_WINDOWS_BY_MYSELF
1441 u_int w_surplus;
1442 u_int h_surplus;
1443 #endif
1444
1445 if (!HAS_MULTI_CHILDREN(layout)) {
1446 return 0;
1447 }
1448
1449 term = search_term(&layout->term, screen);
1450
1451 ui_scrollbar_final(&term->scrollbar);
1452 ui_window_unmap(&term->scrollbar.window);
1453 ui_window_final(&term->scrollbar.window);
1454
1455 if (term->yfirst) {
1456 idx2 = 0;
1457 } else {
1458 idx2 = 1;
1459 }
1460
1461 if (!term->next[idx2]) {
1462 idx2 = !idx2;
1463 }
1464
1465 if (term == &layout->term) {
1466 struct terminal *next;
1467
1468 if (idx2 == 0) {
1469 if (term->separator_y > 0) {
1470 term->next[0]->separator_y = term->separator_y;
1471 }
1472 } else {
1473 if (term->separator_x > 0) {
1474 term->next[1]->separator_x = term->separator_x;
1475 }
1476 }
1477
1478 term->next[idx2]->yfirst = term->yfirst;
1479
1480 next = term->next[idx2];
1481
1482 if (term->next[!idx2]) {
1483 struct terminal *parent;
1484 int empty_idx;
1485
1486 /* Search from 'next' for a term whose child is NULL. */
1487 parent = search_parent_term(next, NULL);
1488 if (parent->next[!idx2] == NULL) {
1489 empty_idx = !idx2;
1490 } else {
1491 empty_idx = idx2;
1492 }
1493
1494 parent->next[empty_idx] = term->next[!idx2];
1495 if (empty_idx == 0) {
1496 parent->separator_x =
1497 get_separator_x(parent->screen,
1498 parent->sb_mode == SBM_NONE ? 0 : SCROLLBAR_WIDTH(parent->scrollbar),
1499 100);
1500 } else {
1501 parent->separator_y = get_separator_y(parent->screen, 100);
1502 }
1503 }
1504
1505 *term = *next;
1506 term->screen_scroll_listener.self = term;
1507 ui_set_screen_scroll_listener(term->screen, &term->screen_scroll_listener);
1508 term->sb_listener.self = term;
1509 term->scrollbar.sb_listener = &term->sb_listener;
1510 #ifndef USE_QUARTZ
1511 term->scrollbar.view->win = &term->scrollbar.window;
1512 #ifdef USE_BEOS
1513 view_reset_uiwindow(&term->scrollbar.window);
1514 #endif
1515 #endif
1516
1517 term = next;
1518 } else {
1519 struct terminal *parent;
1520 int idx;
1521
1522 parent = search_parent_term(&layout->term, term);
1523
1524 if (parent->next[0] == term) {
1525 idx = 0;
1526 } else {
1527 idx = 1;
1528 }
1529
1530 if (term->next[idx2]) {
1531 if (idx2 == 0) {
1532 if (term->separator_y > 0) {
1533 term->next[0]->separator_y = term->separator_y;
1534 }
1535 } else {
1536 if (term->separator_x > 0) {
1537 term->next[1]->separator_x = term->separator_x;
1538 }
1539 }
1540 term->next[idx2]->yfirst = term->yfirst;
1541
1542 parent->next[idx] = term->next[idx2];
1543
1544 if (term->next[!idx2]) {
1545 parent = search_parent_term(parent->next[idx], NULL);
1546 if (parent->next[!idx2] == NULL) {
1547 parent->next[!idx2] = term->next[!idx2];
1548 } else {
1549 parent->next[idx2] = term->next[!idx2];
1550 }
1551 }
1552 } else {
1553 parent->next[idx] = NULL;
1554
1555 if (idx == 0) {
1556 parent->separator_x = 0;
1557 } else {
1558 parent->separator_y = 0;
1559 }
1560 }
1561 }
1562
1563 ui_window_remove_child(&layout->window, &term->scrollbar.window);
1564 ui_window_remove_child(&layout->window, &screen->window);
1565 screen->screen_listener.line_scrolled_out = layout->line_scrolled_out;
1566 ui_window_unmap(&screen->window);
1567
1568 if (layout->bg_pic && !HAS_MULTI_CHILDREN(layout)) {
1569 restore_screen_bg_pic(layout);
1570 ui_window_unset_wall_picture(&layout->window, 0);
1571 }
1572
1573 #ifndef MANAGE_SUB_WINDOWS_BY_MYSELF
1574 if (!HAS_MULTI_CHILDREN(layout)) {
1575 w_surplus = (layout->window.width - layout->term.screen->window.hmargin * 2 -
1576 (layout->term.sb_mode != SBM_NONE ? SCROLLBAR_WIDTH(layout->term.scrollbar) : 0)) %
1577 ui_col_width(layout->term.screen);
1578 h_surplus = (layout->window.height - layout->term.screen->window.vmargin * 2) %
1579 ui_line_height(layout->term.screen);
1580 } else {
1581 w_surplus = h_surplus = 0;
1582 }
1583
1584 if (w_surplus > 0 || h_surplus > 0) {
1585 ui_window_resize(&layout->window, layout->window.width - w_surplus,
1586 layout->window.height - h_surplus, NOTIFY_TO_MYSELF);
1587 } else
1588 #endif
1589 {
1590 reset_layout(&layout->term, 0, 0, layout->window.width, layout->window.height);
1591 }
1592
1593 update_normal_hints(layout);
1594
1595 #ifndef MANAGE_SUB_WINDOWS_BY_MYSELF
1596 if (ui_screen_attached(screen)) {
1597 /* Revert the size of vt_term to the original one. */
1598 ui_window_resize_with_margin(
1599 &screen->window, ACTUAL_WIDTH(&layout->window) -
1600 (term->sb_mode != SBM_NONE ? SCROLLBAR_WIDTH(term->scrollbar) : 0),
1601 ACTUAL_HEIGHT(&layout->window), NOTIFY_TO_MYSELF);
1602 }
1603 #endif
1604
1605 free(term);
1606
1607 ui_window_set_input_focus(&layout->term.screen->window);
1608
1609 /* See window_focused() above */
1610 if (!HAS_MULTI_CHILDREN(layout)) {
1611 update_title(layout->term.screen);
1612 }
1613
1614 #ifndef USE_QUARTZ
1615 if (layout->window.idling && !need_idling_event(&layout->term)) {
1616 layout->window.idling = NULL;
1617 }
1618 #endif
1619
1620 return 1;
1621 }
1622
ui_layout_switch_screen(ui_layout_t * layout,int prev)1623 int ui_layout_switch_screen(ui_layout_t *layout, int prev) {
1624 ui_screen_t *screen;
1625
1626 if (!HAS_MULTI_CHILDREN(layout)) {
1627 return 0;
1628 }
1629
1630 if (prev) {
1631 screen = NULL;
1632
1633 search_prev_screen(&layout->term, (ui_screen_t *)get_current_window(layout), &screen);
1634 } else {
1635 int found = 0;
1636
1637 if (!(screen = search_next_screen(&layout->term, (ui_screen_t *)get_current_window(layout),
1638 &found))) {
1639 screen = layout->term.screen;
1640 }
1641 }
1642
1643 ui_window_set_input_focus(&screen->window);
1644
1645 return 1;
1646 }
1647
ui_layout_resize(ui_layout_t * layout,ui_screen_t * screen,int horizontal,const char * size_str)1648 int ui_layout_resize(ui_layout_t *layout, ui_screen_t *screen, int horizontal,
1649 const char *size_str /* "N", "+N", "-N" or "N%" */) {
1650 struct terminal *term;
1651 struct terminal *child = NULL;
1652 int size;
1653 int is_percent;
1654 char *p;
1655
1656 if ((p = strchr(size_str, '%'))) {
1657 if (!bl_str_n_to_int(&size, size_str, p - size_str) || size <= 0) {
1658 return 0;
1659 }
1660 is_percent = 1;
1661 } else {
1662 if (!bl_str_to_int(&size, *size_str == '+' ? size_str + 1: size_str) || size == 0) {
1663 return 0;
1664 }
1665 is_percent = 0;
1666 }
1667
1668 if (!(term = search_term(&layout->term, screen))) {
1669 term = &layout->term;
1670 }
1671
1672 if (horizontal) {
1673 if (is_percent) {
1674 if (term->separator_x > 0) {
1675 term->separator_x = total_width(term) * size / 100;
1676 }
1677 } else {
1678 int step;
1679
1680 if (*size_str == '+' || *size_str == '-') {
1681 step = size;
1682 } else {
1683 step = size - vt_term_get_cols(screen->term);
1684 }
1685
1686 while (term->separator_x == 0) {
1687 if (!(term = search_parent_term(&layout->term, (child = term)))) {
1688 return 0;
1689 }
1690 }
1691
1692 if (term->next[0] == child) {
1693 step = -step;
1694 }
1695
1696 step *= ui_col_width(term->screen);
1697
1698 if (step < 0 && term->separator_x < abs(step)) {
1699 return 0;
1700 }
1701
1702 term->separator_x += step;
1703 }
1704 } else {
1705 if (is_percent) {
1706 if (term->separator_y > 0) {
1707 term->separator_y = total_height(term) * size / 100;
1708 }
1709 } else {
1710 int step;
1711
1712 if (*size_str == '+' || *size_str == '-') {
1713 step = size;
1714 } else {
1715 step = size - vt_term_get_rows(screen->term);
1716 }
1717
1718 while (term->separator_y == 0) {
1719 if (!(term = search_parent_term(&layout->term, (child = term)))) {
1720 return 0;
1721 }
1722 }
1723
1724 if (term->next[1] == child) {
1725 step = -step;
1726 }
1727
1728 step *= ui_line_height(term->screen);
1729
1730 if (step < 0 && term->separator_y < abs(step)) {
1731 return 0;
1732 }
1733
1734 term->separator_y += step;
1735 }
1736 }
1737
1738 reset_layout(&layout->term, 0, 0, layout->window.width, layout->window.height);
1739
1740 return 1;
1741 }
1742