1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2
3 #include "ui_screen_manager.h"
4
5 #include <stdio.h> /* sprintf */
6 #include <string.h> /* memset/memcpy */
7 #include <stdlib.h> /* getenv */
8 #include <unistd.h> /* getuid */
9
10 #include <pobl/bl_def.h> /* USE_WIN32API */
11 #ifndef USE_WIN32API
12 #include <pwd.h> /* getpwuid */
13 #endif
14
15 #include <pobl/bl_debug.h>
16 #include <pobl/bl_str.h> /* bl_str_sep/bl_str_to_int/strdup */
17 #include <pobl/bl_path.h> /* bl_basename */
18 #include <pobl/bl_util.h> /* DIGIT_STR_LEN */
19 #include <pobl/bl_mem.h> /* alloca/malloc/free */
20 #include <pobl/bl_conf.h>
21 #include <pobl/bl_conf_io.h>
22 #include <pobl/bl_types.h> /* u_int */
23 #include <pobl/bl_args.h> /* bl_arg_str_to_array */
24 #include <pobl/bl_sig_child.h>
25 #include <pobl/bl_dialog.h>
26 #include <vt_term_manager.h>
27 #include <vt_char_encoding.h>
28
29 #include "ui_layout.h"
30 #include "ui_display.h"
31
32 #if defined(USE_WIN32API) || defined(USE_LIBSSH2)
33 #include "ui_connect_dialog.h"
34 #endif
35
36 #define MAX_SCREENS (MSU * max_screens_multiple) /* Default MAX_SCREENS is 32. */
37 #define MSU (8 * sizeof(dead_mask[0])) /* MAX_SCREENS_UNIT */
38
39 #if 0
40 #define __DEBUG
41 #endif
42
43 /* --- static variables --- */
44
45 static char *mlterm_version;
46
47 static u_int max_screens_multiple;
48 static u_int32_t *dead_mask;
49
50 static ui_screen_t **screens;
51 static u_int num_screens;
52
53 static u_int depth;
54
55 static u_int num_startup_screens;
56
57 static ui_system_event_listener_t system_listener;
58
59 static ui_main_config_t main_config;
60
61 static ui_shortcut_t shortcut;
62
63 /* --- static functions --- */
64
65 /*
66 * Callbacks of vt_config_event_listener_t events.
67 */
68
69 /*
70 * Reload mlterm/main file and reset main_config.
71 * Notice: Saved changes are not applied to the screens already opened.
72 */
config_saved(void)73 static void config_saved(void) {
74 bl_conf_t *conf;
75 char *argv[] = {"mlterm", NULL};
76
77 ui_main_config_final(&main_config);
78
79 if ((conf = bl_conf_new()) == NULL) {
80 return;
81 }
82
83 ui_prepare_for_main_config(conf);
84 ui_main_config_init(&main_config, conf, 1, argv);
85
86 bl_conf_destroy(conf);
87 }
88
font_config_updated(void)89 static void font_config_updated(void) {
90 u_int count;
91
92 ui_font_cache_unload_all();
93
94 for (count = 0; count < num_screens; count++) {
95 ui_screen_reset_view(screens[count]);
96 }
97 }
98
color_config_updated(void)99 static void color_config_updated(void) {
100 u_int count;
101
102 ui_color_cache_unload_all();
103
104 ui_display_reset_cmap();
105
106 for (count = 0; count < num_screens; count++) {
107 ui_screen_reset_view(screens[count]);
108 }
109 }
110
create_term_intern(void)111 static vt_term_t *create_term_intern(void) {
112 vt_term_t *term;
113
114 if ((term = vt_create_term(
115 main_config.term_type, main_config.cols, main_config.rows, main_config.tab_size,
116 main_config.num_log_lines, main_config.encoding, main_config.is_auto_encoding,
117 main_config.use_auto_detect, main_config.logging_vt_seq, main_config.unicode_policy,
118 main_config.col_size_of_width_a, main_config.use_char_combining,
119 main_config.use_multi_col_char, main_config.use_ctl, main_config.bidi_mode,
120 main_config.bidi_separators, main_config.use_dynamic_comb, main_config.bs_mode,
121 main_config.vertical_mode, main_config.use_local_echo, main_config.title,
122 main_config.icon_name, main_config.use_ansi_colors, main_config.alt_color_mode,
123 main_config.use_ot_layout, main_config.blink_cursor ? CS_BLINK|CS_BLOCK : CS_BLOCK,
124 main_config.ignore_broadcasted_chars)) == NULL) {
125 return NULL;
126 }
127
128 if (main_config.icon_path) {
129 vt_term_set_icon_path(term, main_config.icon_path);
130 }
131
132 if (main_config.unlimit_log_size) {
133 vt_term_unlimit_log_size(term);
134 }
135
136 return term;
137 }
138
open_pty_intern(vt_term_t * term,char * cmd_path,char ** cmd_argv,ui_window_t * win,int show_dialog)139 static int open_pty_intern(vt_term_t *term, char *cmd_path, char **cmd_argv,
140 ui_window_t *win, int show_dialog) {
141 char *display;
142 Window window;
143 u_int width_pix;
144 u_int height_pix;
145 char *env[7]; /* MLTERM,TERM,WINDOWID,WAYLAND_DISPLAY,DISPLAY,COLORFGBG,NULL */
146 char **env_p;
147 char wid_env[9 + DIGIT_STR_LEN(Window) + 1]; /* "WINDOWID="(9) + [32bit digit] + NULL(1) */
148 char *disp_env;
149 char *term_env;
150 char *uri;
151 char *pass;
152 #ifdef USE_LIBSSH2
153 char *privkey;
154 #endif
155 int ret;
156
157 display = win->disp->name;
158 window = win->my_window;
159
160 if (vt_term_get_vertical_mode(term)) {
161 width_pix = win->height * 100 / ((ui_screen_t*)win)->screen_width_ratio;
162 height_pix = win->width;
163 } else {
164 width_pix = win->width * 100 / ((ui_screen_t*)win)->screen_width_ratio;
165 height_pix = win->height;
166 }
167
168 env_p = env;
169
170 *(env_p++) = mlterm_version;
171
172 #if defined(USE_XLIB)
173 sprintf(wid_env, "WINDOWID=%ld", window);
174 *(env_p++) = wid_env;
175 #endif
176
177 #if defined(USE_WAYLAND)
178 /* "WAYLAND_DISPLAY="(16) + NULL(1) */
179 if (display && (disp_env = alloca(16 + strlen(display) + 1))) {
180 sprintf(disp_env, "WAYLAND_DISPLAY=%s", display);
181 *(env_p++) = disp_env;
182 }
183 *(env_p++) = "DISPLAY=:0.0";
184 #elif defined(USE_XLIB)
185 /* "DISPLAY="(8) + NULL(1) */
186 if (display && (disp_env = alloca(8 + strlen(display) + 1))) {
187 sprintf(disp_env, "DISPLAY=%s", display);
188 *(env_p++) = disp_env;
189 }
190 #endif
191
192 /* "TERM="(5) + NULL(1) */
193 if (main_config.term_type && (term_env = alloca(5 + strlen(main_config.term_type) + 1))) {
194 sprintf(term_env, "TERM=%s", main_config.term_type);
195 *(env_p++) = term_env;
196 }
197
198 *(env_p++) = "COLORFGBG=default;default";
199
200 /* NULL terminator */
201 *env_p = NULL;
202
203 uri = NULL;
204 pass = NULL;
205 #ifdef USE_LIBSSH2
206 privkey = main_config.private_key;
207 #endif
208
209 #if defined(USE_WIN32API) || defined(USE_LIBSSH2)
210 if (show_dialog || main_config.default_server) {
211 char *default_server_dup;
212 char *uri_dup;
213 char *user;
214 char *host;
215 char *port;
216 char *encoding = NULL;
217 char *exec_cmd = NULL;
218 int x11_fwd;
219 void *session;
220
221 x11_fwd = main_config.use_x11_forwarding;
222
223 #ifdef USE_LIBSSH2
224 if (!show_dialog && main_config.default_server &&
225 (default_server_dup = alloca(strlen(main_config.default_server) + 1)) &&
226 bl_parse_uri(NULL, &user, &host, &port, NULL, &encoding,
227 strcpy(default_server_dup, main_config.default_server)) &&
228 (session = vt_search_ssh_session(host, port, user))) {
229 uri = strdup(main_config.default_server);
230 pass = strdup("");
231
232 if (x11_fwd) {
233 vt_pty_ssh_set_use_x11_forwarding(session, x11_fwd);
234 }
235 } else
236 #endif
237 if (!ui_connect_dialog(&uri, &pass, &exec_cmd, &privkey, &x11_fwd, display, window,
238 main_config.default_server)) {
239 #ifdef DEBUG
240 bl_debug_printf(BL_DEBUG_TAG " Connect dialog is canceled.\n");
241 #endif
242
243 /*
244 * open_screen_intern() calls close_screen_intern() if this fuction
245 * returns 0, then this thread will be terminated on Haiku.
246 * (If mlclient --serv ... is executed and the connect dialog is cancelled,
247 * the screen where mlclient is executed also exits.)
248 * So don't return 0 even if the connect dialog is cancelled.
249 *
250 * (vt_term_open_pty() below never returns 0 because OPEN_PTY_ASYNC
251 * is defined on Haiku.)
252 */
253 #ifndef USE_BEOS
254 if (vt_get_all_terms(NULL) > 1) {
255 return 0;
256 }
257 #endif
258 } else if ((uri_dup = alloca(strlen(uri) + 1))) {
259 bl_parse_uri(NULL, &user, &host, &port, NULL, &encoding, strcpy(uri_dup, uri));
260
261 #ifdef USE_LIBSSH2
262 vt_pty_ssh_set_use_x11_forwarding(vt_search_ssh_session(host, port, user), x11_fwd);
263 #endif
264 } else {
265 /* XXX Not recovering error. */
266 return 0;
267 }
268
269 #ifdef __DEBUG
270 bl_debug_printf("Connect dialog: URI %s pass %s\n", uri, pass);
271 #endif
272
273 if (encoding) {
274 if (vt_term_is_attached(term)) {
275 /*
276 * Don't use vt_term_change_encoding() here because
277 * encoding change could cause special visual change
278 * which should update the state of ui_screen_t.
279 */
280 char *seq;
281 size_t len;
282
283 if ((seq = alloca((len = 16 + strlen(encoding) + 2)))) {
284 sprintf(seq, "\x1b]5379;encoding=%s\x07", encoding);
285 vt_term_write_loopback(term, seq, len - 1);
286 }
287 } else {
288 vt_term_change_encoding(term, vt_get_char_encoding(encoding));
289 }
290 }
291
292 if (exec_cmd) {
293 char *tmp = exec_cmd;
294
295 if ((exec_cmd = alloca(strlen(exec_cmd) + 1))) {
296 strcpy(exec_cmd, tmp);
297 }
298 free(tmp);
299
300 if ((tmp = bl_argv_alloca(exec_cmd))) {
301 int argc;
302
303 if (bl_arg_str_to_array((char**)tmp, &argc, exec_cmd)) {
304 cmd_argv = (char**)tmp;
305 cmd_path = cmd_argv[0];
306 }
307 }
308 }
309 }
310 #endif
311
312 #if 0
313 if (cmd_argv) {
314 char **p;
315
316 bl_debug_printf(BL_DEBUG_TAG " %s", cmd_path);
317 p = cmd_argv;
318 while (*p) {
319 bl_msg_printf(" %s", *p);
320 p++;
321 }
322 bl_msg_printf("\n");
323 }
324 #endif
325
326 /*
327 * If cmd_path and pass are NULL, set default shell as cmd_path.
328 * If uri is not NULL (= connecting to ssh/telnet/rlogin etc servers),
329 * cmd_path is not changed.
330 */
331 if (!uri && !cmd_path) {
332 #ifdef __APPLE__
333 char *user;
334
335 if ((user = getenv("USER")) && (cmd_argv = alloca(sizeof(char *) * 4))) {
336 cmd_argv[0] = cmd_path = "login";
337 cmd_argv[1] = "-fp";
338 cmd_argv[2] = user;
339 cmd_argv[3] = NULL;
340 } else
341 #endif
342 {
343 /*
344 * SHELL env var -> /etc/passwd -> /bin/sh
345 */
346 if ((cmd_path = getenv("SHELL")) == NULL || *cmd_path == '\0') {
347 #ifndef USE_WIN32API
348 struct passwd *pw;
349
350 if ((pw = getpwuid(getuid())) == NULL || *(cmd_path = pw->pw_shell) == '\0')
351 #endif
352 {
353 cmd_path = "/bin/sh";
354 }
355 }
356 }
357 }
358
359 /*
360 * Set cmd_argv by cmd_path.
361 */
362 if (cmd_path && !cmd_argv) {
363 char *cmd_file;
364
365 cmd_file = bl_basename(cmd_path);
366
367 if ((cmd_argv = alloca(sizeof(char *) * 2)) == NULL) {
368 return 0;
369 }
370
371 /* 2 = `-' and NULL */
372 if ((cmd_argv[0] = alloca(strlen(cmd_file) + 2)) == NULL) {
373 return 0;
374 }
375
376 if (main_config.use_login_shell) {
377 sprintf(cmd_argv[0], "-%s", cmd_file);
378 } else {
379 strcpy(cmd_argv[0], cmd_file);
380 }
381
382 cmd_argv[1] = NULL;
383 }
384
385 #ifdef USE_LIBSSH2
386 ret = vt_term_open_pty(term, cmd_path, cmd_argv, env, uri ? uri : display, main_config.work_dir,
387 pass, main_config.public_key, privkey, width_pix, height_pix);
388 #else
389 ret = vt_term_open_pty(term, cmd_path, cmd_argv, env, uri ? uri : display, main_config.work_dir,
390 pass, NULL, NULL, width_pix, height_pix);
391 #endif
392
393 #if defined(USE_WIN32API) || defined(USE_LIBSSH2)
394 if (uri) {
395 if (ret && bl_compare_str(uri, main_config.default_server) != 0) {
396 free(main_config.default_server);
397 main_config.default_server = uri;
398 } else {
399 free(uri);
400 }
401
402 free(pass);
403
404 if (privkey != main_config.private_key) {
405 free(privkey);
406 }
407 }
408 #endif
409
410 return ret;
411 }
412
413 #ifndef NO_IMAGE
414
get_picture_data(void * p,char * file_path,int * num_cols,int * num_rows,int * num_cols_small,int * num_rows_small,u_int32_t ** sixel_palette,int keep_aspect,int drcs_sixel)415 static vt_char_t *get_picture_data(void *p, char *file_path, int *num_cols /* can be 0 */,
416 int *num_rows /* can be 0 */,
417 int *num_cols_small /* set only if drcs_sixel is 1. */,
418 int *num_rows_small /* set only if drcs_sixel is 1. */,
419 u_int32_t **sixel_palette, int keep_aspect, int drcs_sixel) {
420 vt_char_t *data;
421
422 if (num_screens > 0) {
423 vt_term_t *orig_term;
424
425 orig_term = screens[0]->term;
426 screens[0]->term = p; /* XXX */
427 data = (*screens[0]->xterm_listener.get_picture_data)(screens[0]->xterm_listener.self,
428 file_path, num_cols, num_rows,
429 num_cols_small, num_rows_small,
430 sixel_palette, 0, drcs_sixel);
431 screens[0]->term = orig_term;
432 } else {
433 data = NULL;
434 }
435
436 return data;
437 }
438
detach_screen(ui_screen_t * screen)439 static vt_term_t *detach_screen(ui_screen_t *screen) {
440 vt_term_t *term;
441
442 if ((term = ui_screen_detach(screen))) {
443 vt_xterm_event_listener_t *listener;
444
445 if (!(listener = vt_term_get_user_data(term, term))) {
446 if (!(listener = calloc(1, sizeof(vt_xterm_event_listener_t)))) {
447 return term;
448 }
449
450 listener->self = term;
451 listener->get_picture_data = get_picture_data;
452
453 vt_term_set_user_data(term, term, listener);
454 }
455
456 /* XXX */
457 term->parser->xterm_listener = listener;
458 }
459
460 return term;
461 }
462
463 #define ui_screen_detach(screen) detach_screen(screen)
464
465 #endif
466
467 #ifdef USE_WIN32GUI
close_screen_win32(ui_screen_t * screen)468 static void close_screen_win32(ui_screen_t *screen) {
469 int is_orphan;
470
471 if (UI_SCREEN_TO_LAYOUT(screen) && ui_layout_remove_child(UI_SCREEN_TO_LAYOUT(screen), screen)) {
472 is_orphan = 1;
473 } else {
474 is_orphan = 0;
475
476 /*
477 * XXX Hack
478 * In case SendMessage(WM_CLOSE) causes WM_KILLFOCUS
479 * and operates screen->term which was already destroyed.
480 * (see window_unfocused())
481 */
482 screen->window.window_unfocused = NULL;
483 }
484
485 SendMessage(ui_get_root_window(&screen->window)->my_window, WM_CLOSE, 0, 0);
486
487 if (is_orphan && screen->window.window_destroyed) {
488 (*screen->window.window_destroyed)(&screen->window);
489 }
490 }
491 #endif
492
close_screen_intern(ui_screen_t * screen)493 static void close_screen_intern(ui_screen_t *screen) {
494 ui_window_t *root;
495 ui_display_t *disp;
496
497 if (UI_SCREEN_TO_LAYOUT(screen)) {
498 ui_layout_remove_child(UI_SCREEN_TO_LAYOUT(screen), screen);
499 /* ui_get_root_window() below doesn't return ui_layout. */
500 }
501
502 ui_screen_detach(screen);
503 ui_font_manager_destroy(screen->font_man);
504 ui_color_manager_destroy(screen->color_man);
505
506 root = ui_get_root_window(&screen->window);
507 disp = root->disp;
508
509 if (!ui_display_remove_root(disp, root)) {
510 ui_window_unmap(root);
511 ui_window_final(root);
512 } else if (disp->num_roots == 0) {
513 ui_display_close(disp);
514 }
515 }
516
open_screen_intern(char * disp_name,vt_term_t * term,ui_layout_t * layout,int horizontal,const char * sep,int show_dialog)517 static ui_screen_t *open_screen_intern(char *disp_name, vt_term_t *term, ui_layout_t *layout,
518 int horizontal, const char *sep, int show_dialog) {
519 ui_display_t *disp;
520 ui_screen_t *screen;
521 ui_font_manager_t *font_man;
522 ui_color_manager_t *color_man;
523 ui_window_t *root;
524 ef_charset_t usascii_font_cs;
525 void *p;
526
527 /*
528 * these are dynamically allocated.
529 */
530 disp = NULL;
531 font_man = NULL;
532 color_man = NULL;
533 screen = NULL;
534 root = NULL;
535
536 if (MAX_SCREENS <= num_screens) {
537 return NULL;
538 }
539
540 if (!term) {
541 if ((!layout || (term = vt_get_detached_term(NULL)) == NULL) &&
542 (term = create_term_intern()) == NULL) {
543 return NULL;
544 }
545 }
546
547 if (layout) {
548 disp = layout->window.disp;
549 } else if ((disp = ui_display_open(disp_name, depth)) == NULL) {
550 #ifdef DEBUG
551 bl_warn_printf(BL_DEBUG_TAG " ui_display_open failed.\n");
552 #endif
553
554 goto error;
555 }
556
557 if (main_config.unicode_policy & NOT_USE_UNICODE_FONT || main_config.iso88591_font_for_usascii) {
558 usascii_font_cs = ui_get_usascii_font_cs(VT_ISO8859_1);
559 } else if (main_config.unicode_policy & ONLY_USE_UNICODE_FONT) {
560 usascii_font_cs = ui_get_usascii_font_cs(VT_UTF8);
561 } else {
562 usascii_font_cs = ui_get_usascii_font_cs(vt_term_get_encoding(term));
563 }
564
565 if ((font_man = ui_font_manager_new(disp->display, main_config.type_engine,
566 main_config.font_present, main_config.font_size,
567 usascii_font_cs, main_config.step_in_changing_font_size,
568 main_config.letter_space, main_config.use_bold_font,
569 main_config.use_italic_font)) == NULL) {
570 const char *msg_fmt = "No fonts for %s";
571 char *msg;
572 char *name;
573
574 if (!(name = ui_get_charset_name(usascii_font_cs))) {
575 name = "US-ASCII";
576 }
577
578 if ((msg = alloca(13 + strlen(name) + 1))) {
579 sprintf(msg, msg_fmt, name);
580 bl_dialog(BL_DIALOG_ALERT, msg);
581 }
582
583 goto error;
584 }
585
586 if ((color_man = ui_color_manager_new(
587 disp, main_config.fg_color, main_config.bg_color, main_config.cursor_fg_color,
588 main_config.cursor_bg_color, main_config.bd_color, main_config.ul_color,
589 main_config.bl_color, main_config.rv_color, main_config.it_color,
590 main_config.co_color)) == NULL) {
591 goto error;
592 }
593
594 if ((screen = ui_screen_new(term, font_man, color_man, main_config.brightness,
595 main_config.contrast, main_config.gamma, main_config.alpha,
596 main_config.fade_ratio, &shortcut, main_config.screen_width_ratio,
597 main_config.mod_meta_key, main_config.mod_meta_mode,
598 main_config.bel_mode, main_config.receive_string_via_ucs,
599 main_config.pic_file_path, main_config.use_transbg,
600 main_config.use_vertical_cursor, main_config.borderless,
601 main_config.line_space, main_config.input_method,
602 main_config.allow_osc52, main_config.hmargin, main_config.vmargin,
603 main_config.hide_underline, main_config.underline_offset,
604 main_config.baseline_offset)) == NULL) {
605 #ifdef DEBUG
606 bl_warn_printf(BL_DEBUG_TAG " ui_screen_new() failed.\n");
607 #endif
608
609 goto error;
610 }
611
612 /* Override config event listener. */
613 screen->config_listener.saved = config_saved;
614
615 ui_set_system_listener(screen, &system_listener);
616
617 if (layout) {
618 if (!ui_layout_add_child(layout, screen, horizontal, sep)) {
619 layout = NULL;
620
621 goto error;
622 }
623
624 root = &layout->window;
625 } else {
626 if (main_config.use_mdi &&
627 (layout = ui_layout_new(screen, main_config.scrollbar_view_name, main_config.sb_fg_color,
628 main_config.sb_bg_color, main_config.sb_mode,
629 main_config.layout_hmargin, main_config.layout_vmargin))) {
630 root = &layout->window;
631 } else {
632 root = &screen->window;
633 }
634
635 if (!ui_display_show_root(disp, root, main_config.x, main_config.y, main_config.geom_hint,
636 main_config.app_name, main_config.parent_window)) {
637 #ifdef DEBUG
638 bl_warn_printf(BL_DEBUG_TAG " ui_display_show_root() failed.\n");
639 #endif
640
641 goto error;
642 }
643 }
644
645 if ((p = realloc(screens, sizeof(ui_screen_t *) * (num_screens + 1))) == NULL) {
646 /*
647 * XXX
648 * After ui_display_show_root() screen is not destroyed correctly by
649 * 'goto error'(see following error handling in open_pty_intern),
650 * but I don't know how to do.
651 */
652 goto error;
653 }
654
655 screens = p;
656
657 /*
658 * New screen is successfully created here except vt_pty.
659 */
660
661 if (vt_term_pty_is_opened(term)) {
662 #if 0
663 /* mlclient /dev/... -e foo */
664 if (main_config.cmd_argv) {
665 int count;
666 for (count = 0; main_config.cmd_argv[count]; count++) {
667 vt_term_write(term, main_config.cmd_argv[count], strlen(main_config.cmd_argv[count]), 0);
668 vt_term_write(term, " ", 1, 0);
669 }
670
671 vt_term_write(term, "\n", 1, 0);
672 }
673 #endif
674 } else {
675 if (!open_pty_intern(term, main_config.cmd_path, main_config.cmd_argv,
676 &screen->window, show_dialog)) {
677 ui_screen_detach(screen);
678 vt_destroy_term(term);
679
680 #ifdef USE_WIN32GUI
681 screens[num_screens++] = screen;
682 close_screen_win32(screen);
683 #else
684 close_screen_intern(screen);
685 #endif
686
687 return NULL;
688 }
689
690 if (main_config.init_str) {
691 vt_term_write(term, main_config.init_str, strlen(main_config.init_str));
692 }
693 }
694
695 /* Don't add screen to screens before "return NULL" above unless USE_WIN32GUI. */
696 screens[num_screens++] = screen;
697
698 return screen;
699
700 error:
701 if (font_man) {
702 ui_font_manager_destroy(font_man);
703 }
704
705 if (color_man) {
706 ui_color_manager_destroy(color_man);
707 }
708
709 if (!root || !ui_display_remove_root(disp, root)) {
710 /*
711 * If root is still NULL or is not registered to disp yet.
712 */
713
714 if (screen) {
715 ui_screen_destroy(screen);
716 }
717
718 if (layout) {
719 ui_layout_destroy(layout);
720 }
721 }
722
723 if (disp && disp->num_roots == 0) {
724 ui_display_close(disp);
725 }
726
727 vt_destroy_term(term);
728
729 return NULL;
730 }
731
732 /*
733 * callbacks of ui_system_event_listener_t
734 */
735
736 /*
737 * EXIT_PROGRAM shortcut calls this at last.
738 * this is for debugging.
739 */
740 #ifdef DEBUG
741 #include "../main/main_loop.h"
742
__exit(void * p,int status)743 static void __exit(void *p, int status) {
744 #ifdef USE_WIN32GUI
745 u_int count;
746
747 for (count = 0; count < num_screens; count++) {
748 SendMessage(ui_get_root_window(&screens[count]->window), WM_CLOSE, 0, 0);
749 }
750 #endif
751 #if 1
752 bl_mem_dump_all();
753 #endif
754
755 main_loop_final();
756
757 #if defined(USE_WIN32API) && defined(USE_LIBSSH2)
758 WSACleanup();
759 #endif
760
761 bl_msg_printf("reporting unfreed memories --->\n");
762
763 bl_mem_free_all();
764
765 bl_dl_close_all();
766
767 exit(status);
768 }
769 #endif
770
open_pty(void * p,ui_screen_t * screen,char * dev)771 static void open_pty(void *p, ui_screen_t *screen, char *dev) {
772 vt_term_t *new;
773
774 if (dev) {
775 if ((new = vt_get_detached_term(dev)) == NULL) {
776 return;
777 }
778 } else {
779 vt_char_encoding_t encoding;
780 #if defined(USE_WIN32API) || defined(USE_LIBSSH2)
781 char *default_server;
782 char *new_cmd_line;
783 char *new_cmd_line_dup;
784 char *cmd_path;
785 char **cmd_argv;
786 #endif
787 int ret;
788
789 encoding = main_config.encoding;
790 main_config.encoding = vt_term_get_encoding(screen->term);
791
792 if ((new = create_term_intern()) == NULL) {
793 main_config.encoding = encoding;
794
795 return;
796 }
797
798 #if defined(USE_WIN32API) || defined(USE_LIBSSH2)
799 if (!main_config.show_dialog) {
800 default_server = main_config.default_server;
801 main_config.default_server = vt_term_get_uri(screen->term);
802 }
803
804 if ((new_cmd_line = vt_term_get_cmd_line(screen->term)) &&
805 (new_cmd_line_dup = alloca(strlen(new_cmd_line) + 1))) {
806 int argc;
807
808 cmd_path = main_config.cmd_path;
809 cmd_argv = main_config.cmd_argv;
810
811 if ((main_config.cmd_argv = bl_argv_alloca(new_cmd_line)) &&
812 bl_arg_str_to_array(main_config.cmd_argv, &argc,
813 strcpy(new_cmd_line_dup, new_cmd_line))) {
814 main_config.cmd_path = main_config.cmd_argv[0];
815 } else {
816 main_config.cmd_argv = cmd_argv;
817 }
818 }
819 #endif
820
821 #if defined(USE_WIN32API) || defined(USE_LIBSSH2)
822 ret = open_pty_intern(new, main_config.cmd_path, main_config.cmd_argv, &screen->window,
823 main_config.show_dialog);
824 #else
825 ret = open_pty_intern(new, main_config.cmd_path, main_config.cmd_argv, &screen->window, 0);
826 #endif
827
828 main_config.encoding = encoding;
829 #if defined(USE_WIN32API) || defined(USE_LIBSSH2)
830 if (!main_config.show_dialog) {
831 main_config.default_server = default_server;
832 }
833
834 if (new_cmd_line) {
835 main_config.cmd_path = cmd_path;
836 main_config.cmd_argv = cmd_argv;
837 }
838 #endif
839
840 if (!ret) {
841 vt_destroy_term(new);
842
843 return;
844 }
845 }
846
847 ui_screen_detach(screen);
848 ui_screen_attach(screen, new);
849 }
850
next_pty(void * p,ui_screen_t * screen)851 static void next_pty(void *p, ui_screen_t *screen) {
852 vt_term_t *old;
853 vt_term_t *new;
854
855 if ((old = ui_screen_detach(screen)) == NULL) {
856 return;
857 }
858
859 if ((new = vt_next_term(old)) == NULL) {
860 ui_screen_attach(screen, old);
861 } else {
862 ui_screen_attach(screen, new);
863 }
864 }
865
prev_pty(void * p,ui_screen_t * screen)866 static void prev_pty(void *p, ui_screen_t *screen) {
867 vt_term_t *old;
868 vt_term_t *new;
869
870 if ((old = ui_screen_detach(screen)) == NULL) {
871 return;
872 }
873
874 if ((new = vt_prev_term(old)) == NULL) {
875 ui_screen_attach(screen, old);
876 } else {
877 ui_screen_attach(screen, new);
878 }
879 }
880
close_pty(void * p,ui_screen_t * screen,char * dev)881 static void close_pty(void *p, ui_screen_t *screen, char *dev) {
882 vt_term_t *term;
883
884 if (dev) {
885 if ((term = vt_get_term(dev)) == NULL) {
886 return;
887 }
888 } else {
889 term = screen->term;
890 }
891
892 /*
893 * Don't call vt_destroy_term directly, because close_pty() can be called
894 * in the context of parsing vt100 sequence.
895 */
896 bl_trigger_sig_child(vt_term_get_child_pid(term));
897 }
898
pty_closed(void * p,ui_screen_t * screen)899 static void pty_closed(void *p, ui_screen_t *screen /* screen->term was already destroyed. */
900 ) {
901 int count;
902
903 #ifdef DEBUG
904 bl_debug_printf(BL_DEBUG_TAG " pty which is attached to screen %p is closed.\n", screen);
905 #endif
906
907 for (count = num_screens - 1; count >= 0; count--) {
908 if (screen == screens[count]) {
909 vt_term_t *term;
910
911 if ((term = vt_get_detached_term(NULL)) == NULL) {
912 #ifdef COCOA_TOUCH
913 if (vt_get_all_terms(NULL) == 0 && (term = create_term_intern())) {
914 #ifdef USE_LIBSSH2
915 if (open_pty_intern(term, main_config.cmd_path, main_config.cmd_argv,
916 &screen->window, main_config.show_dialog))
917 #else
918 if (open_pty_intern(term, main_config.cmd_path, main_config.cmd_argv,
919 &screen->window, 0))
920 #endif
921 {
922 ui_screen_attach(screen, term);
923
924 return;
925 } else {
926 vt_destroy_term(term);
927 }
928 }
929 #endif
930
931 #ifdef __DEBUG
932 bl_debug_printf(" no detached term. closing screen.\n");
933 #endif
934
935 #ifdef USE_WIN32GUI
936 close_screen_win32(screen);
937 #else
938 screens[count] = screens[--num_screens];
939 close_screen_intern(screen);
940 #endif
941 } else {
942 #ifdef __DEBUG
943 bl_debug_printf(" using detached term.\n");
944 #endif
945
946 ui_screen_attach(screen, term);
947 }
948
949 return;
950 }
951 }
952 }
953
open_cloned_screen(ui_screen_t * cur_screen,ui_layout_t * layout,int horizontal,const char * sep,int show_dialog)954 static void open_cloned_screen(ui_screen_t *cur_screen, ui_layout_t *layout, int horizontal,
955 const char *sep, int show_dialog) {
956 vt_char_encoding_t encoding;
957 #if defined(USE_WIN32API) || defined(USE_LIBSSH2)
958 char *default_server;
959 char *new_cmd_line;
960 char *new_cmd_line_dup;
961 char *cmd_path;
962 char **cmd_argv;
963 #endif
964
965 encoding = main_config.encoding;
966 main_config.encoding = vt_term_get_encoding(cur_screen->term);
967 #if defined(USE_WIN32API) || defined(USE_LIBSSH2)
968 if (!show_dialog) {
969 default_server = main_config.default_server;
970 main_config.default_server = vt_term_get_uri(cur_screen->term);
971 }
972
973 if ((new_cmd_line = vt_term_get_cmd_line(cur_screen->term)) &&
974 (new_cmd_line_dup = alloca(strlen(new_cmd_line) + 1))) {
975 int argc;
976
977 cmd_path = main_config.cmd_path;
978 cmd_argv = main_config.cmd_argv;
979
980 if ((main_config.cmd_argv = bl_argv_alloca(new_cmd_line)) &&
981 bl_arg_str_to_array(main_config.cmd_argv, &argc,
982 strcpy(new_cmd_line_dup, new_cmd_line))) {
983 main_config.cmd_path = main_config.cmd_argv[0];
984 } else {
985 main_config.cmd_argv = cmd_argv;
986 }
987 }
988 #endif
989
990 #if defined(USE_WIN32API) || defined(USE_LIBSSH2)
991 open_screen_intern(cur_screen->window.disp->name, NULL, layout, horizontal, sep,
992 main_config.show_dialog);
993 #else
994 open_screen_intern(cur_screen->window.disp->name, NULL, layout, horizontal, sep, 0);
995 #endif
996
997 main_config.encoding = encoding;
998 #if defined(USE_WIN32API) || defined(USE_LIBSSH2)
999 if (!show_dialog) {
1000 main_config.default_server = default_server;
1001 }
1002
1003 if (new_cmd_line) {
1004 main_config.cmd_path = cmd_path;
1005 main_config.cmd_argv = cmd_argv;
1006 }
1007 #endif
1008 }
1009
open_screen(void * p,ui_screen_t * screen)1010 static void open_screen(void *p, ui_screen_t *screen /* Screen which triggers this event. */
1011 ) {
1012 #if defined(USE_WIN32API) || defined(USE_LIBSSH2)
1013 open_cloned_screen(screen, NULL, 0, NULL, main_config.show_dialog);
1014 #else
1015 open_cloned_screen(screen, NULL, 0, NULL, 0);
1016 #endif
1017 }
1018
split_screen(void * p,ui_screen_t * screen,int horizontal,const char * sep)1019 static void split_screen(void *p, ui_screen_t *screen, /* Screen which triggers this event. */
1020 int horizontal, const char *sep) {
1021 if (UI_SCREEN_TO_LAYOUT(screen)) {
1022 #if defined(USE_WIN32API) || defined(USE_LIBSSH2)
1023 open_cloned_screen(screen, UI_SCREEN_TO_LAYOUT(screen), horizontal, sep,
1024 main_config.show_dialog);
1025 #else
1026 open_cloned_screen(screen, UI_SCREEN_TO_LAYOUT(screen), horizontal, sep, 0);
1027 #endif
1028 }
1029 }
1030
close_screen(void * p,ui_screen_t * screen,int force)1031 static int close_screen(void *p, ui_screen_t *screen, /* Screen which triggers this event. */
1032 int force) {
1033 u_int count;
1034
1035 if (!force &&
1036 (!UI_SCREEN_TO_LAYOUT(screen) || ui_layout_has_one_child(UI_SCREEN_TO_LAYOUT(screen)))) {
1037 return 0;
1038 }
1039
1040 for (count = 0; count < num_screens; count++) {
1041 u_int idx;
1042
1043 if (screen != screens[count]) {
1044 continue;
1045 }
1046
1047 #ifdef __DEBUG
1048 bl_debug_printf(BL_DEBUG_TAG " screen %p is registered to be closed.\n", screen);
1049 #endif
1050
1051 #ifdef USE_BEOS
1052 /*
1053 * Don't use ui_close_dead_screens().
1054 * It doesn't clear dead_mask because BWindow::Quit() called from
1055 * close_screen_intern() exists the current thread.
1056 */
1057 screens[count] = screens[--num_screens];
1058 close_screen_intern(screen);
1059 #else
1060 idx = count / MSU; /* count / 8 */
1061 dead_mask[idx] |= (1 << (count - MSU * idx));
1062 #endif
1063
1064 break;
1065 }
1066
1067 return 1;
1068 }
1069
next_screen(void * self,ui_screen_t * screen)1070 static int next_screen(void *self, ui_screen_t *screen) {
1071 if (UI_SCREEN_TO_LAYOUT(screen)) {
1072 return ui_layout_switch_screen(UI_SCREEN_TO_LAYOUT(screen), 0);
1073 } else {
1074 return 0;
1075 }
1076 }
1077
prev_screen(void * self,ui_screen_t * screen)1078 static int prev_screen(void *self, ui_screen_t *screen) {
1079 if (UI_SCREEN_TO_LAYOUT(screen)) {
1080 return ui_layout_switch_screen(UI_SCREEN_TO_LAYOUT(screen), 1);
1081 } else {
1082 return 0;
1083 }
1084 }
1085
resize_screen(void * self,ui_screen_t * screen,int horizontal,const char * size)1086 static int resize_screen(void *self, ui_screen_t *screen, int horizontal, const char *size) {
1087 if (UI_SCREEN_TO_LAYOUT(screen)) {
1088 return ui_layout_resize(UI_SCREEN_TO_LAYOUT(screen), screen, horizontal, size);
1089 } else {
1090 return 0;
1091 }
1092 }
1093
mlclient(void * self,ui_screen_t * screen,char * args,FILE * fp)1094 static int mlclient(void *self, ui_screen_t *screen, char *args,
1095 FILE *fp /* Stream to output response of mlclient. */
1096 ) {
1097 char **argv;
1098 int argc;
1099
1100 if (!(argv = bl_argv_alloca(args)) || !bl_arg_str_to_array(argv, &argc, args)) {
1101 return 0;
1102 }
1103
1104 #ifdef __DEBUG
1105 {
1106 int i;
1107
1108 for (i = 0; i < argc; i++) {
1109 bl_msg_printf("%s\n", argv[i]);
1110 }
1111 }
1112 #endif
1113
1114 if (argc == 0
1115 #if defined(USE_FRAMEBUFFER)
1116 || screen == NULL
1117 #endif
1118 ) {
1119 return 0;
1120 }
1121
1122 if (argc == 2 && (strcmp(argv[1], "-P") == 0 || strcmp(argv[1], "--ptylist") == 0)) {
1123 /*
1124 * mlclient -P or mlclient --ptylist
1125 */
1126
1127 vt_term_t **terms;
1128 u_int num;
1129 int count;
1130
1131 num = vt_get_all_terms(&terms);
1132 for (count = 0; count < num; count++) {
1133 fprintf(fp, "#%s", vt_term_get_slave_name(terms[count]));
1134 if (vt_term_window_name(terms[count])) {
1135 fprintf(fp, "(whose title is %s)", vt_term_window_name(terms[count]));
1136 }
1137 if (vt_term_is_attached(terms[count])) {
1138 fprintf(fp, " is active:)\n");
1139 } else {
1140 fprintf(fp, " is sleeping.zZ\n");
1141 }
1142 }
1143 } else {
1144 bl_conf_t *conf;
1145 ui_main_config_t orig_conf;
1146 char *pty;
1147 int horizontal;
1148 char *sep;
1149
1150 if (argc >= 2 && *(argv[1]) != '-') {
1151 /*
1152 * mlclient [dev] [options...]
1153 */
1154
1155 pty = argv[1];
1156 argv[1] = argv[0];
1157 argv = &argv[1];
1158 argc--;
1159 } else {
1160 pty = NULL;
1161 }
1162
1163 if ((conf = bl_conf_new()) == NULL) {
1164 return 0;
1165 }
1166
1167 ui_prepare_for_main_config(conf);
1168
1169 bl_conf_add_opt(conf, '\0', "hsep", 0, "hsep", "");
1170 bl_conf_add_opt(conf, '\0', "vsep", 0, "vsep", "");
1171
1172 if (!bl_conf_parse_args(conf, &argc, &argv, 1)) {
1173 bl_conf_destroy(conf);
1174
1175 return 0;
1176 }
1177
1178 if (screen && UI_SCREEN_TO_LAYOUT(screen)) {
1179 char *p;
1180
1181 if ((p = bl_conf_get_value(conf, "hsep"))) {
1182 horizontal = 1;
1183 } else if ((p = bl_conf_get_value(conf, "vsep"))) {
1184 horizontal = 0;
1185 } else {
1186 sep = NULL;
1187 goto end_check_sep;
1188 }
1189 if ((sep = alloca(strlen(p) + 1))) {
1190 strcpy(sep, p);
1191 }
1192 } else {
1193 sep = NULL;
1194 }
1195
1196 end_check_sep:
1197 orig_conf = main_config;
1198
1199 ui_main_config_init(&main_config, conf, argc, argv);
1200
1201 bl_conf_destroy(conf);
1202
1203 if (screen) {
1204 if (sep) {
1205 #if defined(USE_WIN32API) || defined(USE_LIBSSH2)
1206 open_screen_intern(screen->window.disp->name, NULL, UI_SCREEN_TO_LAYOUT(screen),
1207 horizontal, sep, main_config.show_dialog);
1208 #else
1209 open_screen_intern(screen->window.disp->name, NULL, UI_SCREEN_TO_LAYOUT(screen),
1210 horizontal, sep, 0);
1211 #endif
1212 } else {
1213 vt_term_t *term;
1214
1215 if ((term = create_term_intern())) {
1216 #if defined(USE_WIN32API) || defined(USE_LIBSSH2)
1217 if (!open_pty_intern(term, main_config.cmd_path, main_config.cmd_argv,
1218 &screen->window, main_config.show_dialog))
1219 #else
1220 if (!open_pty_intern(term, main_config.cmd_path, main_config.cmd_argv,
1221 &screen->window, 0))
1222 #endif
1223 {
1224 vt_destroy_term(term);
1225 } else {
1226 ui_screen_detach(screen);
1227 ui_screen_attach(screen, term);
1228 }
1229 }
1230 }
1231 } else {
1232 vt_term_t *term = NULL;
1233
1234 #ifdef USE_CONSOLE
1235 if (*main_config.disp_name)
1236 #endif
1237 {
1238 if ((pty && !(term = vt_get_detached_term(pty))) ||
1239 !open_screen_intern(main_config.disp_name, term, NULL, 0, 0, 0)) {
1240 #ifdef DEBUG
1241 bl_warn_printf(BL_DEBUG_TAG " open_screen_intern() failed.\n");
1242 #endif
1243 }
1244 }
1245 }
1246
1247 ui_main_config_final(&main_config);
1248
1249 main_config = orig_conf;
1250 }
1251
1252 /* Flush fp stream because write(2) is called after this function is called.
1253 */
1254 fflush(fp);
1255
1256 return 1;
1257 }
1258
1259 /* --- global functions --- */
1260
ui_screen_manager_init(char * _mlterm_version,u_int _depth,u_int _max_screens_multiple,u_int _num_startup_screens,ui_main_config_t * _main_config)1261 int ui_screen_manager_init(char *_mlterm_version, u_int _depth, u_int _max_screens_multiple,
1262 u_int _num_startup_screens, ui_main_config_t *_main_config) {
1263 mlterm_version = _mlterm_version;
1264
1265 depth = _depth;
1266
1267 main_config = *_main_config;
1268
1269 max_screens_multiple = _max_screens_multiple;
1270
1271 if ((dead_mask = calloc(sizeof(*dead_mask), max_screens_multiple)) == NULL) {
1272 return 0;
1273 }
1274
1275 if (_num_startup_screens > MAX_SCREENS) {
1276 num_startup_screens = MAX_SCREENS;
1277 } else {
1278 num_startup_screens = _num_startup_screens;
1279 }
1280
1281 if (!vt_term_manager_init(max_screens_multiple)) {
1282 free(dead_mask);
1283
1284 return 0;
1285 }
1286
1287 vt_color_config_init();
1288
1289 ui_shortcut_init(&shortcut);
1290
1291 /* BACKWARD COMPAT (3.1.7 or before) */
1292 #if 1
1293 {
1294 size_t count;
1295 char key0[] = "Control+Button1";
1296 char key1[] = "Control+Button2";
1297 char key2[] = "Control+Button3";
1298 char key3[] = "Button3";
1299 char *keys[] = {key0, key1, key2, key3};
1300
1301 for (count = 0; count < sizeof(keys) / sizeof(keys[0]); count++) {
1302 if (main_config.shortcut_strs[count]) {
1303 ui_shortcut_parse(&shortcut, keys[count], main_config.shortcut_strs[count]);
1304 }
1305 }
1306 }
1307 #endif
1308
1309 if (*main_config.disp_name) {
1310 /*
1311 * setting DISPLAY environment variable to match "--display" option.
1312 */
1313
1314 char *env;
1315
1316 #ifdef USE_WAYLAND
1317 if ((env = malloc(16 + strlen(main_config.disp_name) + 1))) {
1318 sprintf(env, "WAYLAND_DISPLAY=%s", main_config.disp_name);
1319 putenv(env);
1320 }
1321 #else
1322 if ((env = malloc(8 + strlen(main_config.disp_name) + 1))) {
1323 sprintf(env, "DISPLAY=%s", main_config.disp_name);
1324 putenv(env);
1325 }
1326 #endif
1327 }
1328
1329 system_listener.self = NULL;
1330 #ifdef DEBUG
1331 system_listener.exit = __exit;
1332 #else
1333 system_listener.exit = NULL;
1334 #endif
1335 #ifdef MANAGE_ROOT_WINDOWS_BY_MYSELF
1336 system_listener.open_screen = NULL;
1337 #else
1338 system_listener.open_screen = open_screen;
1339 #endif
1340 system_listener.split_screen = split_screen;
1341 system_listener.close_screen = close_screen;
1342 system_listener.next_screen = next_screen;
1343 system_listener.prev_screen = prev_screen;
1344 system_listener.resize_screen = resize_screen;
1345 system_listener.open_pty = open_pty;
1346 system_listener.next_pty = next_pty;
1347 system_listener.prev_pty = prev_pty;
1348 system_listener.close_pty = close_pty;
1349 system_listener.pty_closed = pty_closed;
1350 system_listener.mlclient = mlclient;
1351 system_listener.font_config_updated = font_config_updated;
1352 system_listener.color_config_updated = color_config_updated;
1353
1354 return 1;
1355 }
1356
ui_screen_manager_final(void)1357 void ui_screen_manager_final(void) {
1358 u_int count;
1359
1360 ui_main_config_final(&main_config);
1361
1362 for (count = 0; count < num_screens; count++) {
1363 close_screen_intern(screens[count]);
1364 }
1365
1366 free(screens);
1367 free(dead_mask);
1368
1369 vt_term_manager_final();
1370
1371 ui_display_close_all();
1372
1373 vt_color_config_final();
1374 ui_shortcut_final(&shortcut);
1375 }
1376
1377 #ifdef __ANDROID__
1378 static int suspended;
1379
1380 void ui_event_source_final(void); /* ui_event_source.h */
1381
ui_screen_manager_suspend(void)1382 int ui_screen_manager_suspend(void) {
1383 u_int count;
1384
1385 ui_close_dead_screens();
1386
1387 for (count = 0; count < num_screens; count++) {
1388 close_screen_intern(screens[count]);
1389 }
1390
1391 free(screens);
1392 screens = NULL;
1393 num_screens = 0;
1394
1395 ui_display_close_all();
1396
1397 ui_event_source_final();
1398
1399 suspended = 1;
1400
1401 return 1;
1402 }
1403 #endif
1404
ui_screen_manager_startup(void)1405 u_int ui_screen_manager_startup(void) {
1406 u_int count;
1407 u_int num_started;
1408
1409 num_started = 0;
1410
1411 #ifdef __ANDROID__
1412 if (suspended) {
1413 /* reload ~/.mlterm/main. */
1414 config_saved();
1415 ui_shortcut_final(&shortcut);
1416 ui_shortcut_init(&shortcut);
1417 vt_color_config_final();
1418 vt_color_config_init();
1419 }
1420 #endif
1421
1422 for (count = 0; count < num_startup_screens; count++) {
1423 if (!open_screen_intern(main_config.disp_name, vt_get_detached_term(NULL), NULL, 0, 0,
1424 #if defined(USE_LIBSSH2) && defined(__ANDROID__)
1425 !start_with_local_pty
1426 #elif defined(USE_WIN32API)
1427 1 /* show dialog */
1428 #else
1429 0
1430 #endif
1431 )) {
1432 #ifdef DEBUG
1433 bl_warn_printf(BL_DEBUG_TAG " open_screen_intern() failed.\n");
1434 #endif
1435 } else {
1436 num_started++;
1437 }
1438 }
1439
1440 return num_started;
1441 }
1442
ui_close_dead_screens(void)1443 void ui_close_dead_screens(void) {
1444 if (num_screens > 0) {
1445 int idx;
1446
1447 for (idx = (num_screens - 1) / MSU; idx >= 0; idx--) {
1448 if (dead_mask[idx]) {
1449 int count;
1450
1451 for (count = MSU - 1; count >= 0; count--) {
1452 if (dead_mask[idx] & (0x1 << count)) {
1453 ui_screen_t *screen;
1454
1455 #ifdef __DEBUG
1456 bl_debug_printf(BL_DEBUG_TAG " closing screen %d-%d.", idx, count);
1457 #endif
1458
1459 screen = screens[idx * MSU + count];
1460 screens[idx * MSU + count] = screens[--num_screens];
1461 close_screen_intern(screen);
1462
1463 #ifdef __DEBUG
1464 bl_msg_printf(" => Finished. Rest %d\n", num_screens);
1465 #endif
1466 }
1467 }
1468
1469 memset(&dead_mask[idx], 0, sizeof(dead_mask[idx]));
1470 }
1471 }
1472 }
1473 }
1474
ui_get_all_screens(ui_screen_t *** _screens)1475 u_int ui_get_all_screens(ui_screen_t ***_screens) {
1476 if (_screens) {
1477 *_screens = screens;
1478 }
1479
1480 return num_screens;
1481 }
1482
ui_mlclient(char * args,FILE * fp)1483 int ui_mlclient(char *args, FILE *fp) { return mlclient(NULL, NULL, args, fp); }
1484