1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2 
3 #include "main_loop.h"
4 
5 #include <signal.h>
6 #include <unistd.h> /* getpid */
7 #include <pobl/bl_locale.h>
8 #include <pobl/bl_sig_child.h>
9 #include <pobl/bl_mem.h> /* bl_alloca_garbage_collect */
10 #include <pobl/bl_str.h> /* bl_str_sep */
11 #include <pobl/bl_def.h> /* USE_WIN32API */
12 
13 #include <ui_font.h> /* ui_use_cp932_ucs_fot_xft */
14 #include <ui_screen_manager.h>
15 #include <ui_event_source.h>
16 #ifdef USE_XLIB
17 #include <xlib/ui_xim.h>
18 #endif
19 #ifdef USE_BRLAPI
20 #include <ui_brltty.h>
21 #endif
22 #ifdef USE_CONSOLE
23 #include <vt_term_manager.h> /* vt_get_all_terms */
24 #endif
25 
26 #include "version.h"
27 #include "daemon.h"
28 
29 #if defined(__ANDROID__) || defined(USE_QUARTZ) || (defined(USE_SDL2) && defined(__APPLE__)) || \
30   defined(USE_WIN32API)
31 /* Shrink unused memory */
32 #define bl_conf_add_opt(conf, a, b, c, d, e) bl_conf_add_opt(conf, a, b, c, d, "")
33 #endif
34 
35 #if 0
36 #define __DEBUG
37 #endif
38 
39 /* --- static variables --- */
40 
41 static int8_t is_genuine_daemon;
42 
43 /* --- static functions --- */
44 
45 /*
46  * signal handlers.
47  */
48 #ifndef USE_WIN32API
sig_fatal(int sig)49 static void sig_fatal(int sig) {
50 #ifdef DEBUG
51   bl_warn_printf(BL_DEBUG_TAG "signal %d is received\n", sig);
52 #endif
53 
54   /* Remove ~/.mlterm/socket. */
55   daemon_final();
56 
57   /* reset */
58   signal(sig, SIG_DFL);
59 
60   kill(getpid(), sig);
61 }
62 #endif /* USE_WIN32API */
63 
get_font_size_range(u_int * min,u_int * max,const char * str)64 static int get_font_size_range(u_int *min, u_int *max, const char *str) {
65   char *str_p;
66   char *p;
67 
68   if ((str_p = alloca(strlen(str) + 1)) == NULL) {
69     return 0;
70   }
71   strcpy(str_p, str);
72 
73   /* bl_str_sep() never returns NULL because str_p isn't NULL. */
74   p = bl_str_sep(&str_p, "-");
75 
76   if (str_p == NULL) {
77     bl_msg_printf("max font size is missing.\n");
78 
79     return 0;
80   }
81 
82   if (!bl_str_to_uint(min, p)) {
83     bl_msg_printf("min font size %s is not valid.\n", p);
84 
85     return 0;
86   }
87 
88   if (!bl_str_to_uint(max, str_p)) {
89     bl_msg_printf("max font size %s is not valid.\n", str_p);
90 
91     return 0;
92   }
93 
94   return 1;
95 }
96 
97 #ifdef USE_LIBSSH2
ssh_keepalive(void)98 static void ssh_keepalive(void) { vt_pty_ssh_keepalive(100); }
99 #endif
100 
101 /* --- global functions --- */
102 
main_loop_init(int argc,char ** argv)103 int main_loop_init(int argc, char **argv) {
104   ui_main_config_t main_config;
105   bl_conf_t *conf;
106   char *value;
107 #ifdef USE_XLIB
108   int use_xim;
109 #endif
110   u_int max_screens_multiple;
111   u_int num_startup_screens;
112   u_int depth;
113   char *invalid_msg = "%s %s is not valid.\n";
114   char *orig_argv;
115 #if defined(USE_FRAMEBUFFER) || defined(USE_WAYLAND) || defined(USE_SDL2)
116   int use_aafont = 0;
117 #endif
118 
119   if (!bl_locale_init("")) {
120     bl_msg_printf("locale settings failed.\n");
121   }
122 
123   bl_sig_child_start();
124 
125   bl_init_prog(argv[0],
126                DETAIL_VERSION
127                "\nFeatures:"
128 #if defined(USE_XLIB) && defined(NO_DYNAMIC_LOAD_TYPE)
129 #ifndef USE_TYPE_XFT
130                " no-xft"
131 #endif
132 #ifndef USE_TYPE_CAIRO
133                " no-cairo"
134 #endif
135 #endif
136 #ifdef NO_DYNAMIC_LOAD_CTL
137 #ifndef USE_FRIBIDI
138                " no-bidi"
139 #endif
140 #ifndef USE_IND
141                " no-indic"
142 #endif
143 #endif
144 #ifdef USE_OT_LAYOUT
145                " otl"
146 #endif
147 #ifdef USE_LIBSSH2
148                " ssh"
149 #endif
150 #ifdef USE_FREETYPE
151                " freetype"
152 #endif
153 #ifdef USE_FONTCONFIG
154                " fontconfig"
155 #endif
156 #ifdef USE_IM_PLUGIN
157                " implugin"
158 #endif
159 #ifdef BUILTIN_IMAGELIB
160                " imagelib(builtin)"
161 #endif
162 #ifdef USE_UTMP
163                " utmp"
164 #endif
165 #ifdef USE_BRLAPI
166                " brlapi"
167 #endif
168   );
169 
170   if ((conf = bl_conf_new()) == NULL) {
171     return 0;
172   }
173 
174   ui_prepare_for_main_config(conf);
175 
176   /*
177    * Same processing as vte_terminal_class_init().
178    * Following options are not possible to specify as arguments of mlclient.
179    * 1) Options which are used only when mlterm starts up and which aren't
180    *    changed dynamically. (e.g. "startup_screens")
181    * 2) Options which change status of all ptys or windows. (Including ones
182    *    which are possible to change dynamically.)
183    *    (e.g. "font_size_range")
184    */
185 
186   bl_conf_add_opt(conf, '@', "screens", 0, "startup_screens",
187                   "number of screens to open in start up [1]");
188   bl_conf_add_opt(conf, 'h', "help", 1, "help", "show this help message");
189   bl_conf_add_opt(conf, 'v', "version", 1, "version", "show version message");
190   bl_conf_add_opt(conf, 'R', "fsrange", 0, "font_size_range",
191                   "font size range for GUI configurator [1-100]");
192 #ifdef COMPOSE_DECSP_FONT
193   bl_conf_add_opt(conf, 'Y', "decsp", 1, "compose_dec_special_font",
194                   "compose dec special font [false]");
195 #endif
196 #ifdef USE_XLIB
197   bl_conf_add_opt(conf, 'i', "xim", 1, "use_xim", "use XIM (X Input Method) [true]");
198 #endif
199 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XFT) || defined(USE_TYPE_CAIRO)
200   bl_conf_add_opt(conf, 'c', "cp932", 1, "use_cp932_ucs_for_xft",
201                   "use CP932-Unicode mapping table for JISX0208 [false]");
202 #endif
203 #ifndef USE_WIN32API
204   bl_conf_add_opt(conf, 'j', "daemon", 0, "daemon_mode",
205 #ifdef USE_WIN32GUI
206                   /* 'genuine' is not supported in win32. */
207                   "start as a daemon (none/blend) [none]"
208 #else
209                   "start as a daemon (none/blend/genuine) [none]"
210 #endif
211                   );
212 #endif
213   bl_conf_add_opt(conf, '\0', "depth", 0, "depth", "visual depth");
214   bl_conf_add_opt(conf, '\0', "maxptys", 0, "max_ptys",
215                   "max ptys to open simultaneously (multiple of 32)");
216 #ifdef USE_LIBSSH2
217   bl_conf_add_opt(conf, '\0', "keepalive", 0, "ssh_keepalive_interval",
218                   "interval seconds to send keepalive. [0 = not send]");
219 #endif
220   bl_conf_add_opt(conf, '\0', "deffont", 0, "default_font", "default font");
221 #ifdef SUPPORT_POINT_SIZE_FONT
222   bl_conf_add_opt(conf, '\0', "point", 1, "use_point_size",
223                   "treat fontsize as point instead of pixel [false]");
224 #endif
225 #if defined(USE_FREETYPE) && defined(USE_FONTCONFIG)
226   bl_conf_add_opt(conf, '\0', "aafont", 1, "use_aafont",
227                   "use [tv]aafont files with the use of fontconfig"
228 #if defined(USE_WAYLAND) || defined(USE_SDL2)
229                   " [true]"
230 #else /* USE_FRAMEBUFFER */
231                   " [false]"
232 #endif
233                   );
234 #endif
235 
236   orig_argv = argv;
237   if (!bl_conf_parse_args(conf, &argc, &argv,
238 #if defined(USE_QUARTZ) || (defined(USE_SDL2) && defined(__APPLE__))
239                           1
240 #else
241                           0
242 #endif
243       )) {
244     bl_conf_destroy(conf);
245 
246     return 0;
247   }
248 
249   if ((value = bl_conf_get_value(conf, "font_size_range"))) {
250     u_int min_font_size;
251     u_int max_font_size;
252 
253     if (get_font_size_range(&min_font_size, &max_font_size, value)) {
254       ui_set_font_size_range(min_font_size, max_font_size);
255     } else {
256       bl_msg_printf(invalid_msg, "font_size_range", value);
257     }
258   }
259 
260   is_genuine_daemon = 0;
261 
262 #ifndef USE_WIN32API
263   if ((value = bl_conf_get_value(conf, "daemon_mode"))) {
264     int ret;
265 
266     ret = 0;
267 
268 #ifndef USE_WIN32GUI
269     /* 'genuine' is not supported in win32. */
270     if (strcmp(value, "genuine") == 0) {
271       if ((ret = daemon_init()) > 0) {
272         is_genuine_daemon = 1;
273       }
274     } else
275 #endif
276         if (strcmp(value, "blend") == 0) {
277       ret = daemon_init();
278     }
279 #if 0
280     else if (strcmp(value, "none") == 0) {
281     }
282 #endif
283 
284     if (ret == -1) {
285       execvp("mlclient", orig_argv);
286     }
287   }
288 #endif
289 
290 #ifdef USE_XLIB
291   use_xim = 1;
292 
293   if ((value = bl_conf_get_value(conf, "use_xim"))) {
294     if (strcmp(value, "false") == 0) {
295       use_xim = 0;
296     }
297   }
298 
299   ui_xim_init(use_xim);
300 #endif
301 
302 #ifdef COMPOSE_DECSP_FONT
303   if ((value = bl_conf_get_value(conf, "compose_dec_special_font"))) {
304     if (strcmp(value, "true") == 0) {
305       ui_compose_dec_special_font();
306     }
307   }
308 #endif
309 
310 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XFT) || defined(USE_TYPE_CAIRO)
311   if ((value = bl_conf_get_value(conf, "use_cp932_ucs_for_xft")) == NULL ||
312       strcmp(value, "true") == 0) {
313     ui_use_cp932_ucs_for_xft();
314   }
315 #endif
316 
317   if ((value = bl_conf_get_value(conf, "depth"))) {
318     bl_str_to_uint(&depth, value);
319   } else {
320     depth = 0;
321   }
322 
323   max_screens_multiple = 1;
324 
325   if ((value = bl_conf_get_value(conf, "max_ptys"))) {
326     u_int max_ptys;
327 
328     if (bl_str_to_uint(&max_ptys, value)) {
329       u_int multiple;
330 
331       multiple = max_ptys / 32;
332 
333       if (multiple * 32 != max_ptys) {
334         bl_msg_printf("max_ptys %s is not multiple of 32.\n", value);
335       }
336 
337       if (multiple > 1) {
338         max_screens_multiple = multiple;
339       }
340     } else {
341       bl_msg_printf(invalid_msg, "max_ptys", value);
342     }
343   }
344 
345   num_startup_screens = 1;
346 
347   if ((value = bl_conf_get_value(conf, "startup_screens"))) {
348     u_int n;
349 
350     if (!bl_str_to_uint(&n, value) || (!is_genuine_daemon && n == 0)) {
351       bl_msg_printf(invalid_msg, "startup_screens", value);
352     } else {
353       num_startup_screens = n;
354     }
355   }
356 
357 #ifdef USE_LIBSSH2
358   if ((value = bl_conf_get_value(conf, "ssh_keepalive_interval"))) {
359     u_int interval;
360 
361     if (bl_str_to_uint(&interval, value) && interval > 0) {
362       vt_pty_ssh_set_keepalive_interval(interval);
363       ui_event_source_add_fd(-1, ssh_keepalive);
364     }
365   }
366 #endif
367 
368 #ifdef KEY_REPEAT_BY_MYSELF
369   if ((value = bl_conf_get_value(conf, "kbd_repeat_1"))) {
370     extern int kbd_repeat_1;
371 
372     bl_str_to_int(&kbd_repeat_1, value);
373   }
374 
375   if ((value = bl_conf_get_value(conf, "kbd_repeat_N"))) {
376     extern int kbd_repeat_N;
377 
378     bl_str_to_int(&kbd_repeat_N, value);
379   }
380 #endif
381 
382 #ifdef USE_FRAMEBUFFER
383 #if defined(__OpenBSD__) || defined(__NetBSD__)
384   if ((value = bl_conf_get_value(conf, "fb_resolution"))) {
385     extern u_int fb_width;
386     extern u_int fb_height;
387     extern u_int fb_depth;
388 
389     sscanf(value, "%dx%dx%d", &fb_width, &fb_height, &fb_depth);
390   }
391 #endif
392 #endif
393 
394 #if defined(USE_FREETYPE) && defined(USE_FONTCONFIG)
395 #if defined(USE_WAYLAND) || defined(USE_SDL2)
396   if (!(value = bl_conf_get_value(conf, "use_aafont")) || strcmp(value, "false") != 0) {
397     ui_use_aafont();
398     use_aafont = 1;
399   }
400 #else /* USE_FRAMEBUFFER */
401   if ((value = bl_conf_get_value(conf, "use_aafont")) && strcmp(value, "true") == 0) {
402     ui_use_aafont();
403     use_aafont = 1;
404   }
405 #endif
406 #endif
407 
408   ui_main_config_init(&main_config, conf, argc, argv);
409 
410   if ((value = bl_conf_get_value(conf, "default_font"))) {
411 #if defined(USE_WAYLAND) || defined(USE_FRAMEBUFFER) || defined(USE_SDL2)
412     ui_customize_font_file(use_aafont ? "aafont" : "font", "DEFAULT", value, 0);
413     ui_customize_font_file(use_aafont ? "aafont" : "font", "ISO10646_UCS4_1", value, 0);
414 #else
415     ui_customize_font_file(main_config.type_engine == TYPE_XCORE ? "font" : "aafont", "DEFAULT",
416                            value, 0);
417 #if defined(USE_XLIB)
418     if (main_config.type_engine == TYPE_XCORE) {
419       char *ucs_font;
420 
421       if (*(value + strlen(value) - 1) == '-' && ((ucs_font = alloca(strlen(value) + 11)))) {
422         sprintf(ucs_font, "%siso10646-1", value);
423         ui_customize_font_file("font", "ISO10646_UCS4_1", ucs_font, 0);
424       } else {
425         ui_customize_font_file("font", "ISO10646_UCS4_1", value, 0);
426       }
427     } else {
428       ui_customize_font_file("aafont", "ISO10646_UCS4_1", value, 0);
429     }
430 #else
431     ui_customize_font_file(main_config.type_engine == TYPE_XCORE ? "font" : "aafont",
432                            "ISO10646_UCS4_1", value, 0);
433 #endif
434 #endif
435   }
436 
437 #ifdef SUPPORT_POINT_SIZE_FONT
438   if ((value = bl_conf_get_value(conf, "use_point_size"))) {
439     if (strcmp(value, "true") == 0) {
440       ui_font_use_point_size(1);
441     }
442   }
443 #endif
444 
445   bl_conf_destroy(conf);
446 
447   if (!ui_screen_manager_init("MLTERM=" VERSION, depth, max_screens_multiple,
448                               num_startup_screens, &main_config)) {
449     daemon_final();
450 #ifdef USE_XLIB
451     ui_xim_final();
452 #endif
453     bl_sig_child_final();
454     bl_locale_final();
455 
456     return 0;
457   }
458 
459   ui_event_source_init();
460 
461 #ifdef USE_BRLAPI
462   ui_brltty_init();
463 #endif
464 
465   bl_alloca_garbage_collect();
466 
467 #ifndef USE_WIN32API
468   signal(SIGHUP, sig_fatal);
469   signal(SIGINT, sig_fatal);
470   signal(SIGQUIT, sig_fatal);
471   signal(SIGTERM, sig_fatal);
472   signal(SIGPIPE, SIG_IGN);
473 #endif
474 
475   return 1;
476 }
477 
main_loop_final(void)478 void main_loop_final(void) {
479 #ifdef USE_BRLAPI
480   ui_brltty_final();
481 #endif
482 
483   ui_event_source_final();
484 
485   ui_screen_manager_final();
486 
487   daemon_final();
488 
489   vt_free_word_separators();
490 
491   ui_free_mod_meta_prefix();
492 
493   bl_set_msg_log_file_name(NULL);
494 
495 #ifdef USE_XLIB
496   ui_xim_final();
497 #endif
498 
499   bl_sig_child_final();
500 
501   bl_locale_final();
502 
503   bl_alloca_garbage_collect();
504 }
505 
main_loop_start(void)506 int main_loop_start(void) {
507   if (ui_screen_manager_startup() == 0 && !is_genuine_daemon) {
508 #ifdef DEBUG
509     bl_warn_printf(BL_DEBUG_TAG " open_screen_intern() failed.\n");
510 #endif
511 
512     if (!is_genuine_daemon) {
513       bl_msg_printf("Unable to open screen.\n");
514 
515       return 0;
516     }
517   }
518 
519   while (1) {
520     bl_alloca_begin_stack_frame();
521 
522     if (!ui_event_source_process() && !is_genuine_daemon) {
523 #ifdef __DEBUG
524       bl_debug_printf(BL_DEBUG_TAG " Exiting...\n");
525 #endif
526 
527       break;
528     }
529 #ifdef USE_CONSOLE
530     else if (vt_get_all_terms(NULL) == 0) {
531       break;
532     }
533 #endif
534 
535     bl_alloca_end_stack_frame();
536   }
537 
538   return 1;
539 }
540