wlt: add --term, --login, --palette and --sb-size
[platform/upstream/kmscon.git] / src / wlt_main.c
1 /*
2  * wlt - Wayland Terminal
3  *
4  * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files
8  * (the "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25
26 /*
27  * Wayland Terminal main application
28  */
29
30 #include <errno.h>
31 #include <paths.h>
32 #include <signal.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/signalfd.h>
37 #include <wayland-client.h>
38 #include "conf.h"
39 #include "eloop.h"
40 #include "log.h"
41 #include "shl_misc.h"
42 #include "text.h"
43 #include "wlt_main.h"
44 #include "wlt_terminal.h"
45 #include "wlt_theme.h"
46 #include "wlt_toolkit.h"
47
48 #define LOG_SUBSYSTEM "wlt"
49
50 struct wlt_app {
51         struct ev_eloop *eloop;
52         struct wlt_display *disp;
53         struct wlt_window *wnd;
54 };
55
56 static void sig_generic(struct ev_eloop *eloop, struct signalfd_siginfo *info,
57                         void *data)
58 {
59         struct wlt_app *app = data;
60
61         ev_eloop_exit(app->eloop);
62         log_info("terminating due to caught signal %d", info->ssi_signo);
63 }
64
65 static void window_close(struct wlt_window *wnd, void *data)
66 {
67         struct wlt_app *app = data;
68
69         log_info("closing window");
70         ev_eloop_exit(app->eloop);
71 }
72
73 static void terminal_close(struct wlt_terminal *term, unsigned int event,
74                            void *data)
75 {
76         struct wlt_app *app = data;
77
78         if (event == WLT_TERMINAL_HUP) {
79                 log_info("closing pty");
80                 ev_eloop_exit(app->eloop);
81         }
82 }
83
84 static int window_init(struct wlt_app *app)
85 {
86         int ret;
87         struct wlt_theme *theme;
88         struct wlt_terminal *term;
89
90         ret = wlt_display_create_window(app->disp, &app->wnd,
91                                         600, 400, app);
92         if (ret) {
93                 log_error("cannot create wayland window");
94                 return ret;
95         }
96         wlt_window_set_close_cb(app->wnd, window_close);
97
98         ret = wlt_theme_new(&theme, app->wnd);
99         if (ret) {
100                 log_error("cannot create theme");
101                 return ret;
102         }
103
104         ret = wlt_terminal_new(&term, app->wnd);
105         if (ret) {
106                 log_error("cannot create terminal");
107                 return ret;
108         }
109
110         ret = wlt_terminal_open(term, terminal_close, app);
111         if (ret) {
112                 log_error("cannot open terminal");
113                 return ret;
114         }
115
116         return 0;
117 }
118
119 static void display_event(struct wlt_display *disp, unsigned int event,
120                           void *data)
121 {
122         struct wlt_app *app = data;
123         int ret;
124
125         switch (event) {
126         case WLT_DISPLAY_READY:
127                 log_info("wayland display initialized");
128                 ret = window_init(app);
129                 if (ret)
130                         ev_eloop_exit(app->eloop);
131                 break;
132         case WLT_DISPLAY_HUP:
133                 log_info("wayland display connection lost");
134                 ev_eloop_exit(app->eloop);
135                 break;
136         }
137 }
138
139 static void destroy_app(struct wlt_app *app)
140 {
141         wlt_window_unref(app->wnd);
142         wlt_display_unregister_cb(app->disp, display_event, app);
143         wlt_display_unref(app->disp);
144         ev_eloop_unregister_signal_cb(app->eloop, SIGINT, sig_generic, app);
145         ev_eloop_unregister_signal_cb(app->eloop, SIGTERM, sig_generic, app);
146         ev_eloop_unref(app->eloop);
147 }
148
149 static int setup_app(struct wlt_app *app)
150 {
151         int ret;
152
153         ret = ev_eloop_new(&app->eloop, log_llog);
154         if (ret)
155                 goto err_app;
156
157         ret = ev_eloop_register_signal_cb(app->eloop, SIGTERM,
158                                                 sig_generic, app);
159         if (ret)
160                 goto err_app;
161
162         ret = ev_eloop_register_signal_cb(app->eloop, SIGINT,
163                                                 sig_generic, app);
164         if (ret)
165                 goto err_app;
166
167         ret = wlt_display_new(&app->disp, app->eloop);
168         if (ret)
169                 goto err_app;
170
171         ret = wlt_display_register_cb(app->disp, display_event, app);
172         if (ret)
173                 goto err_app;
174
175         return 0;
176
177 err_app:
178         destroy_app(app);
179         return ret;
180 }
181
182 struct wlt_conf_t wlt_conf;
183
184 static void print_help()
185 {
186         /*
187          * Usage/Help information
188          * This should be scaled to a maximum of 80 characters per line:
189          *
190          * 80 char line:
191          *       |   10   |    20   |    30   |    40   |    50   |    60   |    70   |    80   |
192          *      "12345678901234567890123456789012345678901234567890123456789012345678901234567890\n"
193          * 80 char line starting with tab:
194          *       |10|    20   |    30   |    40   |    50   |    60   |    70   |    80   |
195          *      "\t901234567890123456789012345678901234567890123456789012345678901234567890\n"
196          */
197         fprintf(stderr,
198                 "Usage:\n"
199                 "\t%1$s [options]\n"
200                 "\t%1$s -h [options]\n"
201                 "\t%1$s -l [options] -- /bin/sh [sh-arguments]\n"
202                 "\n"
203                 "You can prefix boolean options with \"no-\" to negate it. If an argument is\n"
204                 "given multiple times, only the last argument matters if not otherwise stated.\n"
205                 "\n"
206                 "General Options:\n"
207                 "\t-h, --help                  [off]   Print this help and exit\n"
208                 "\t-v, --verbose               [off]   Print verbose messages\n"
209                 "\t    --debug                 [off]   Enable debug mode\n"
210                 "\t    --silent                [off]   Suppress notices and warnings\n"
211                 "\n"
212                 "Terminal Options:\n"
213                 "\t-l, --login                 [/bin/sh]\n"
214                 "\t                              Start the given login process instead\n"
215                 "\t                              of the default process; all arguments\n"
216                 "\t                              following '--' will be be parsed as\n"
217                 "\t                              argv to this process. No more options\n"
218                 "\t                              after '--' will be parsed so use it at\n"
219                 "\t                              the end of the argument string\n"
220                 "\t-t, --term <TERM>           [xterm-256color]\n"
221                 "\t                              Value of the TERM environment variable\n"
222                 "\t                              for the child process\n"
223                 "\t    --palette <name>        [default]\n"
224                 "\t                              Select the used color palette\n"
225                 "\t    --sb-size <num>         [1000]\n"
226                 "\t                              Size of the scrollback-buffer in lines\n"
227                 "\n"
228                 "Keyboard Shortcuts and Grabs:\n"
229                 "\t    --grab-scroll-up <grab>   [<Shift>Up]\n"
230                 "\t                                Shortcut to scroll up\n"
231                 "\t    --grab-scroll-down <grab> [<Shift>Down]\n"
232                 "\t                                Shortcut to scroll down\n"
233                 "\t    --grab-page-up <grab>     [<Shift>Prior]\n"
234                 "\t                                Shortcut to scroll page up\n"
235                 "\t    --grab-page-down <grab>   [<Shift>Next]\n"
236                 "\t                                Shortcut to scroll page down\n"
237                 "Font Options:\n"
238                 "\t    --font-engine <engine>  [pango]\n"
239                 "\t                              Font engine\n"
240                 "\t    --font-size <points>    [15]\n"
241                 "\t                              Font size in points\n"
242                 "\t    --font-name <name>      [monospace]\n"
243                 "\t                              Font name\n"
244                 "\t    --font-dpi <dpi>        [96]\n"
245                 "\t                              Force DPI value for all fonts\n",
246                 "wlterm");
247         /*
248          * 80 char line:
249          *       |   10   |    20   |    30   |    40   |    50   |    60   |    70   |    80   |
250          *      "12345678901234567890123456789012345678901234567890123456789012345678901234567890\n"
251          * 80 char line starting with tab:
252          *       |10|    20   |    30   |    40   |    50   |    60   |    70   |    80   |
253          *      "\t901234567890123456789012345678901234567890123456789012345678901234567890\n"
254          */
255 }
256
257 static int aftercheck_debug(struct conf_option *opt, int argc, char **argv,
258                             int idx)
259 {
260         /* --debug implies --verbose */
261         if (wlt_conf.debug)
262                 wlt_conf.verbose = 1;
263
264         return 0;
265 }
266
267 static int aftercheck_help(struct conf_option *opt, int argc, char **argv,
268                            int idx)
269 {
270         /* exit after printing --help information */
271         if (wlt_conf.help) {
272                 print_help();
273                 wlt_conf.exit = true;
274         }
275
276         return 0;
277 }
278
279 static char *def_argv[] = { NULL, "-i", NULL };
280
281 static int aftercheck_login(struct conf_option *opt, int argc, char **argv,
282                             int idx)
283 {
284         int ret;
285
286         /* parse "--login [...] -- args" arguments */
287         if (wlt_conf.login) {
288                 if (idx >= argc) {
289                         fprintf(stderr, "Arguments for --login missing\n");
290                         return -EFAULT;
291                 }
292
293                 wlt_conf.argv = &argv[idx];
294                 ret = argc - idx;
295         } else {
296                 def_argv[0] = getenv("SHELL") ? : _PATH_BSHELL;
297                 wlt_conf.argv = def_argv;
298                 ret = 0;
299         }
300
301         return ret;
302 }
303
304 static struct conf_grab def_grab_scroll_up = {
305         .mods = SHL_SHIFT_MASK,
306         .keysym = XKB_KEY_Up,
307 };
308
309 static struct conf_grab def_grab_scroll_down = {
310         .mods = SHL_SHIFT_MASK,
311         .keysym = XKB_KEY_Down,
312 };
313
314 static struct conf_grab def_grab_page_up = {
315         .mods = SHL_SHIFT_MASK,
316         .keysym = XKB_KEY_Prior,
317 };
318
319 static struct conf_grab def_grab_page_down = {
320         .mods = SHL_SHIFT_MASK,
321         .keysym = XKB_KEY_Next,
322 };
323
324 struct conf_option options[] = {
325         CONF_OPTION_BOOL('h', "help", aftercheck_help, &wlt_conf.help, false),
326         CONF_OPTION_BOOL('v', "verbose", NULL, &wlt_conf.verbose, false),
327         CONF_OPTION_BOOL(0, "debug", aftercheck_debug, &wlt_conf.debug, false),
328         CONF_OPTION_BOOL(0, "silent", NULL, &wlt_conf.silent, false),
329
330         CONF_OPTION_BOOL('l', "login", aftercheck_login, &wlt_conf.login, false),
331         CONF_OPTION_STRING('t', "term", NULL, &wlt_conf.term, "xterm-256color"),
332         CONF_OPTION_STRING(0, "palette", NULL, &wlt_conf.palette, NULL),
333         CONF_OPTION_UINT(0, "sb-size", NULL, &wlt_conf.sb_size, 1000),
334
335         CONF_OPTION_GRAB(0, "grab-scroll-up", NULL, &wlt_conf.grab_scroll_up, &def_grab_scroll_up),
336         CONF_OPTION_GRAB(0, "grab-scroll-down", NULL, &wlt_conf.grab_scroll_down, &def_grab_scroll_down),
337         CONF_OPTION_GRAB(0, "grab-page-up", NULL, &wlt_conf.grab_page_up, &def_grab_page_up),
338         CONF_OPTION_GRAB(0, "grab-page-down", NULL, &wlt_conf.grab_page_down, &def_grab_page_down),
339
340         CONF_OPTION_STRING(0, "font-engine", NULL, &wlt_conf.font_engine, "pango"),
341         CONF_OPTION_UINT(0, "font-size", NULL, &wlt_conf.font_size, 12),
342         CONF_OPTION_STRING(0, "font-name", NULL, &wlt_conf.font_name, "monospace"),
343         CONF_OPTION_UINT(0, "font-dpi", NULL, &wlt_conf.font_ppi, 96),
344 };
345
346 int main(int argc, char **argv)
347 {
348         int ret;
349         struct wlt_app app;
350         size_t onum;
351
352         onum = sizeof(options) / sizeof(*options);
353         ret = conf_parse_argv(options, onum, argc, argv);
354         if (ret)
355                 goto err_out;
356
357         if (wlt_conf.exit) {
358                 conf_free(options, onum);
359                 return EXIT_SUCCESS;
360         }
361
362         if (!wlt_conf.debug && !wlt_conf.verbose && wlt_conf.silent)
363                 log_set_config(&LOG_CONFIG_WARNING(0, 0, 0, 0));
364         else
365                 log_set_config(&LOG_CONFIG_INFO(wlt_conf.debug,
366                                                 wlt_conf.verbose));
367
368         log_print_init("wlterm");
369
370         kmscon_font_load_all();
371
372         memset(&app, 0, sizeof(app));
373         ret = setup_app(&app);
374         if (ret)
375                 goto err_unload;
376
377         ev_eloop_run(app.eloop, -1);
378
379         destroy_app(&app);
380         kmscon_font_unload_all();
381         conf_free(options, onum);
382         log_info("exiting");
383
384         return EXIT_SUCCESS;
385
386 err_unload:
387         kmscon_font_unload_all();
388 err_out:
389         conf_free(options, onum);
390         log_err("cannot initialize wlterm, errno %d: %s", ret, strerror(-ret));
391         return -ret;
392 }