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