changed author email
[guish.git] / src / main.c
blobb8b6359d1173ad721ff04e75370b4acace506632
1 /*************************************************************************
2 * Copyright (C) 2024 Francesco Palumbo <phranz.dev@gmail.com>, Naples (Italy)
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 *************************************************************************/
18 #include <stdio.h>
19 #include <unistd.h>
20 #include <stdlib.h>
21 #include <signal.h>
22 #include <errno.h>
24 #include "cutils.h"
25 #include "dectypes.h"
26 #include "evaluator.h"
27 #include "sourcedriver.h"
28 #include "tokenizer.h"
29 #include "parser.h"
30 #include "syntax.h"
31 #include "debug.h"
32 #include "main.h"
34 #define AUTHOR "Francesco Palumbo <phranz.dev@gmail.com>"
35 #define LICENSE "GPL-3.0-or-later"
36 #define VERSION "2.6.11"
38 int exit_status;
39 unsigned long options;
40 char buf[BSIZ];
42 #ifdef ENABLE_X11
43 #include <sys/wait.h>
45 #include "widget.h"
46 #include "exec.h"
48 // widgets never created or not
49 extern int dirty;
50 extern widget_t* it;
52 int dfd;
54 Display* display;
55 int screen;
57 Window root;
58 Atom delatom;
59 map_strcol_t* colors;
60 GC gc;
61 XColor null;
63 map_widwidget_t* widgets;
64 map_pidwid_t* exts;
66 void x11_init() {
67 static int x11_initialized;
69 if (x11_initialized || display)
70 return;
71 if (!getenv("DISPLAY"))
72 return;
73 display = XOpenDisplay(NULL);
74 if (!display)
75 return;
76 dfd = ConnectionNumber(display);
77 screen = DefaultScreen(display);
78 root = DefaultRootWindow(display);
80 delatom = XInternAtom(display, "WM_DELETE_WINDOW", False);
81 colors = alloc(map_strcol_t);
82 colors->strcmp = 1;
84 colors->insert(colors, salloc("black"), calloc(1, sizeof(XColor)));
85 colors->insert(colors, salloc("white"), calloc(1, sizeof(XColor)));
86 colors->insert(colors, salloc("gray"), calloc(1, sizeof(XColor)));
87 colors->insert(colors, salloc("lightgray"), calloc(1, sizeof(XColor)));
88 colors->insert(colors, salloc("red"), calloc(1, sizeof(XColor)));
89 colors->insert(colors, salloc("green"), calloc(1, sizeof(XColor)));
90 colors->insert(colors, salloc("blue"), calloc(1, sizeof(XColor)));
91 colors->insert(colors, salloc("yellow"), calloc(1, sizeof(XColor)));
92 colors->insert(colors, salloc("cyan"), calloc(1, sizeof(XColor)));
93 colors->insert(colors, salloc("magenta"), calloc(1, sizeof(XColor)));
95 XColor* c;
96 colors->get(colors, "black", &c);
97 XAllocNamedColor(display, DefaultColormap(display, screen), "black", c, &null);
98 colors->get(colors, "white", &c);
99 XAllocNamedColor(display, DefaultColormap(display, screen), "white", c, &null);
100 colors->get(colors, "gray", &c);
101 XAllocNamedColor(display, DefaultColormap(display, screen), "gray", c, &null);
102 colors->get(colors, "lightgray", &c);
103 XAllocNamedColor(display, DefaultColormap(display, screen), "lightgray", c, &null);
104 colors->get(colors, "red", &c);
105 XAllocNamedColor(display, DefaultColormap(display, screen), "red", c, &null);
106 colors->get(colors, "green", &c);
107 XAllocNamedColor(display, DefaultColormap(display, screen), "green", c, &null);
108 colors->get(colors, "blue", &c);
109 XAllocNamedColor(display, DefaultColormap(display, screen), "blue", c, &null);
110 colors->get(colors, "yellow", &c);
111 XAllocNamedColor(display, DefaultColormap(display, screen), "yellow", c, &null);
112 colors->get(colors, "cyan", &c);
113 XAllocNamedColor(display, DefaultColormap(display, screen), "cyan", c, &null);
114 colors->get(colors, "magenta", &c);
115 XAllocNamedColor(display, DefaultColormap(display, screen), "magenta", c, &null);
117 widgets = alloc(map_widwidget_t);
118 exts = alloc(map_pidwid_t);
119 x11_initialized = 1;
122 static void x11_clean() {
123 if (!display)
124 return;
125 strcol_t* c;
126 eachitem(colors, strcol_t, c,
127 free((char*)c->key);
128 free(c->val);
130 release(colors);
131 if (gc)
132 XFreeGC(display, gc);
133 XFlush(display);
134 XCloseDisplay(display);
135 release(exts);
138 static int last_closed() {
139 if (!widgets || (!widgets->count && !dirty))
140 return 0;
142 size_t closed = 0;
143 widwidget_t* w;
144 eachitem(widgets, widwidget_t, w,
145 if (w->val->flags & F_CLOSED)
146 ++closed;
148 return closed == widgets->count;
151 static void manage_exts() {
152 if (exts->count) {
153 int stat;
154 pidwid_t* p;
155 eachitem(exts, pidwid_t, p,
156 if (kill(p->key, 0) < 0 && errno == ESRCH) {
157 if (p->val == it)
158 it = NULL;
159 del(p->val->wid);
160 exts->remove(exts, p->key);
161 continue;
163 if (waitpid(p->key, &stat, WNOHANG) > 0 && !stat) {
164 if (p->val == it)
165 it = NULL;
166 del(p->val->wid);
167 exts->remove(exts, p->key);
173 void process_events() {
174 XEvent e;
175 widget_t* w;
177 while (XPending(display)) {
178 XNextEvent(display, &e);
179 if (widgets->get(widgets, e.xany.window, &w) && w)
180 event(w, &e);
184 void poll_and_process_events(int us) {
185 struct timeval tv;
186 fd_set ins;
187 int r;
189 FD_ZERO(&ins);
190 FD_SET(dfd, &ins);
191 tv.tv_usec = us;
192 tv.tv_sec = 0;
193 r = select(dfd+1, &ins, NULL, NULL, &tv);
194 if (r > 0)
195 process_events();
198 static void showfonts() {
199 int r;
200 char** f;
202 display = XOpenDisplay(NULL);
203 if (!display) {
204 fprintf(stderr, "Error, unable to open display!\n");
205 exit(EXIT_FAILURE);
207 f = XListFonts(display, "*", 2000, &r);
208 for (size_t i=0; i<(size_t)r; ++i)
209 printf("%s\n", f[i]);
210 XFreeFontNames(f);
211 XCloseDisplay(display);
212 display = NULL;
214 #else
215 #define showfonts(X)
216 #define exec(X) (0)
217 #endif
219 extern map_sigtoken_t actions;
220 extern map_int_timetoken_t* schedules;
221 extern map_int_timetoken_t* onetimes;
222 extern scope_t* cs;
223 extern sig_atomic_t sq;
224 extern unsigned long flags;
225 extern sourcedata_t* current;
227 static void help(int fd, char** argv) {
228 dprintf(fd,
229 "Usage: %s [-c <code>][-s][-q][-k][-t][-f][-v][-b][-h][<file>][<arguments>]\n"
230 "\n"
231 " -c <code> read and execute commands from command line.\n"
232 " -s display elements when created.\n"
233 " -q quit when closing last element/window.\n"
234 " -k terminate all external programs when quitting.\n"
235 " -t fallback on tty after reading data from other inputs.\n"
236 " -f show available X11 fonts.\n"
237 " -v show version.\n"
238 " -b show build (compiled in) options.\n"
239 " -h guess.\n"
240 "\nAuthor: %s"
241 "\nLicense: %s\n",
242 argv[0], AUTHOR, LICENSE);
245 static void build_info() {
246 printf("%s" "\n%s" "\n%s" "\n%s\n",
247 #ifdef ENABLE_X11
248 "X11 support (Xlib): yes"
249 #else
250 "X11 support (Xlib): no"
251 #endif
253 #ifdef ENABLE_CONTROL
254 "Control support (Xtst): yes"
255 #else
256 "Control support (Xtst): no"
257 #endif
259 #ifdef ENABLE_IMAGES
260 "Images support (Imlib2): yes"
261 #else
262 "Images support (Imlib2): no"
263 #endif
265 #ifdef DEBUG
266 "Debug activated: yes"
267 #else
268 "Debug activated: no"
269 #endif
273 static void interpret(vec_token_t* args) {
274 phrase_t* p = NULL;
275 vec_token_t* objs = NULL;
276 while (!(flags & EV_QUITCALLED) && !sq) {
277 p = tokenize();
278 if (!p)
279 break;
280 objs = parse_phrase(p, cs);
281 release(p);
282 if (!objs)
283 break;
284 while (!sq && objs && eval_expressions(objs, args) && !sq && eval_statements(objs, args) &&
285 !(flags & EV_QUITCALLED) && !sq && exec(objs));
286 release_phrase(objs);
287 objs = NULL;
289 release_phrase(objs);
292 int loop(int s, char* data, vec_token_t* args) {
293 debug("initial source %d\n", s);
294 if (!s)
295 new_source(S_STDIN, NULL);
296 else
297 new_source(s, data);
298 #ifdef ENABLE_X11
299 x11_init();
300 if (display) {
301 while (!sq && !(flags & EV_QUITCALLED) && !(options & QUIT_ON_LAST_CLOSED && last_closed())) {
302 process_events();
303 schedule();
304 if (!valid_source()) {
305 if ((!widgets || !widgets->count) &&
306 (!onetimes || !onetimes->count) &&
307 (!schedules || !schedules->count))
308 break;
309 poll_and_process_events(100000);
310 continue;
312 interpret(args);
313 manage_exts();
314 if (sq || flags & EV_QUITCALLED)
315 break;
316 if (source_exahusted())
317 next_source();
318 process_events();
319 if (current && current->nb)
320 poll_and_process_events(100000);
322 #else
323 if (0) {
324 #endif
325 } else {
326 while (!sq && !(flags & EV_QUITCALLED) && valid_source()) {
327 schedule();
328 interpret(args);
329 if (sq || flags & EV_QUITCALLED)
330 break;
331 if (source_exahusted())
332 next_source();
333 if (!current || current->nb)
334 usleep(10);
337 if (sq)
338 trigger(0, SIG_TERM);
339 else
340 trigger(0, SIG_EXIT);
341 return exit_status;
344 int main(int argc, char **argv) {
345 int opt;
346 int initial_source = S_NOSRC;
347 char* source_data = NULL;
349 while ((opt = getopt(argc, argv, "c:sqktfvbh")) > 0) {
350 switch (opt) {
351 case 'c':
352 initial_source = S_CMDLINE;
353 source_data = salloc(optarg);
354 break;
355 case 's':
356 options |= SHOW_ON_CREATE;
357 break;
358 case 'q':
359 options |= QUIT_ON_LAST_CLOSED;
360 break;
361 case 'k':
362 options |= KILL_EXTS_ON_QUIT;
363 break;
364 case 't':
365 options |= FALLBACK_ON_TTY;
366 break;
367 case 'f':
368 showfonts();
369 return EXIT_SUCCESS;
370 case 'v':
371 printf("%s\n", VERSION);
372 return EXIT_SUCCESS;
373 case 'b':
374 build_info();
375 return EXIT_SUCCESS;
376 case 'h':
377 help(1, argv);
378 return EXIT_SUCCESS;
379 default:
380 help(2, argv);
381 return EXIT_FAILURE;
384 debug("optind: %d argc: %d\n", optind, argc);
385 if (optind < argc && !source_data) {
386 initial_source = S_SOURCE;
387 source_data = salloc(argv[optind++]);
389 sourcedriver_init();
390 evaluator_init();
391 syntax_init();
392 vec_token_t* args = NULL;
393 while (optind < argc) {
394 if (!args)
395 args = alloc(vec_token_t);
396 token_t* arg = alloc(token_t);
397 arg->type = T_QUOTE;
398 arg->data = salloc(argv[optind++]);
399 args->push(args, arg);
401 int ret = loop(initial_source, source_data, args);
402 release_phrase(args);
403 if (source_data)
404 zfree(source_data);
405 evaluator_free();
406 sourcedriver_free();
407 syntax_free();
408 #ifdef ENABLE_X11
409 x11_clean();
410 #endif
411 return ret;