💾 Archived View for gemini.rmf-dev.com › repo › Vaati › Menkar › files › dd7d04ff5968407bd92b3ad5d1b… captured on 2023-05-24 at 18:30:59. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-03-20)
-=-=-=-=-=-=-
0 /*
1 * Program initialization and event loop
2 *
3 * Copyright 2006-2007 Johan Veenhuizen
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #include <assert.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <poll.h>
28 #include <signal.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33
34 #include <X11/keysym.h>
35 #include <X11/Xlib.h>
36 #include <X11/Xresource.h>
37 #include <X11/Xutil.h>
38
39 #include "global.h"
40 #include "lib.h"
41 #include "hints.h"
42 #include "menu.h"
43 #include "window.h"
44 #include "slock.h"
45
46 #include "delete.xbm"
47 #include "unmap.xbm"
48 #include "expand.xbm"
49 #include "expanded.xbm"
50
51 #define BORDERWIDTH_MIN 3
52
53 Display *display;
54 int screen;
55 Window root;
56
57 struct menu *winmenu;
58
59 XFontStruct *font;
60
61 int border_width = 4;
62 int panel_height = 32;
63 int button_size;
64 int title_pad;
65
66 struct color color_title_active_fg;
67 struct color color_title_active_bg;
68 struct color color_title_inactive_fg;
69 struct color color_title_inactive_bg;
70 struct color color_menu_fg;
71 struct color color_menu_bg;
72 struct color color_menu_selection_fg;
73 struct color color_menu_selection_bg;
74
75 DEFINE_IMAGE(delete_image, delete);
76 DEFINE_IMAGE(unmap_image, unmap);
77 DEFINE_IMAGE(expand_image, expand);
78 DEFINE_IMAGE(expanded_image, expanded);
79
80 static char *displayname = NULL;
81
82 static const char *ftnames[] = {
83 /* This will be overwritten by user supplied font name */
84 DEFAULT_FONT,
85
86 /* This is the one that looks best */
87 DEFAULT_FONT,
88
89 /* This is the one that exists */
90 "fixed"
91 };
92
93 static XrmOptionDescRec options[] = {
94 /*
95 * Documented options
96 */
97 { "-display", ".display", XrmoptionSepArg, NULL },
98 { "-font", ".font", XrmoptionSepArg, NULL },
99 { "-help", ".showHelp", XrmoptionNoArg, "True" },
100 { "-version", ".showVersion", XrmoptionNoArg, "True" },
101
102 /*
103 * Undocumented options
104 */
105 { "-afg", ".title.active.foreground", XrmoptionSepArg, NULL },
106 { "-abg", ".title.active.background", XrmoptionSepArg, NULL },
107 { "-ifg", ".title.inactive.foreground", XrmoptionSepArg, NULL },
108 { "-ibg", ".title.inactive.background", XrmoptionSepArg, NULL },
109 { "-mfg", ".menu.foreground", XrmoptionSepArg, NULL },
110 { "-mbg", ".menu.background", XrmoptionSepArg, NULL },
111 { "-msfg", ".menu.selection.foreground", XrmoptionSepArg, NULL },
112 { "-msbg", ".menu.selection.background", XrmoptionSepArg, NULL },
113 { "-bw", ".border.width", XrmoptionSepArg, NULL },
114 { "-xrm", NULL, XrmoptionResArg, NULL },
115 };
116
117 #define BLACK "rgb:00/00/00"
118 #define WHITE "rgb:ff/ff/ff"
119 #define GTK_LIGHTGRAY "rgb:dc/da/d5"
120 #define GTK_DARKGRAY "rgb:ac/aa/a5"
121 #define GTK_BLUE "rgb:4b/69/83"
122 #define FRESH_BLUE "rgb:c0/d0/e0"
123
124 static char *colorname_title_active_fg = BLACK;
125 static char *colorname_title_active_bg = GTK_LIGHTGRAY;
126 static char *colorname_title_inactive_fg = BLACK;
127 static char *colorname_title_inactive_bg = GTK_DARKGRAY;
128 static char *colorname_menu_fg = BLACK;
129 static char *colorname_menu_bg = WHITE;
130 static char *colorname_menu_selection_fg = BLACK;
131 static char *colorname_menu_selection_bg = GTK_LIGHTGRAY;
132
133 /* The signals that we care about */
134 static const int sigv[] = { SIGHUP, SIGINT, SIGTERM };
135
136 /* The self-pipe for delivering signals */
137 static int sigpipe[2] = { -1, -1 };
138
139 /* If greater than zero, don't report X errors */
140 static int errlev = 0;
141
142 static int xerr_report(Display *dpy, XErrorEvent *ep)
143 {
144 static char buf[256];
145
146 if (ep->error_code == BadAccess && ep->resourceid == root) {
147 error("another window manager is already running "
148 "on display \"%s\"", XDisplayName(displayname));
149 exit(1);
150 } else {
151 XGetErrorText(dpy, ep->error_code, buf, sizeof buf);
152 error("%s", buf);
153 return 0;
154 }
155 }
156
157 static int xerr_ignore(Display *dpy, XErrorEvent *e)
158 {
159 return 0;
160 }
161
162 void clerr(void)
163 {
164 assert(errlev >= 0);
165
166 if (errlev++ == 0) {
167 XGrabServer(display);
168 XSetErrorHandler(xerr_ignore);
169 }
170 }
171
172 void sterr(void)
173 {
174 assert(errlev >= 1);
175
176 if (--errlev == 0) {
177 XSync(display, False);
178 XUngrabServer(display);
179 XSetErrorHandler(xerr_report);
180 }
181 }
182
183 static void sighandler(int signo)
184 {
185 int e = errno;
186 char c = signo;
187
188 if (sigpipe[1] != -1) {
189 int ret = write(sigpipe[1], &c, 1);
190 if (ret!=1) {
191 printf("Failed to write to sig pipe\n");
192 exit(1);
193 }
194 }
195 errno = e;
196 }
197
198 static void die(int signo)
199 {
200 struct sigaction sigact;
201
202 window_fini();
203 hints_fini();
204 destroy_menu(winmenu);
205 widget_fini();
206
207 XFreeFont(display, font);
208
209 XSetInputFocus(display, PointerRoot, RevertToPointerRoot, CurrentTime);
210 XCloseDisplay(display);
211
212 if (sigpipe[0] != -1)
213 close(sigpipe[0]);
214 if (sigpipe[1] != -1)
215 close(sigpipe[1]);
216
217 if (signo > 0) {
218 sigact.sa_handler = SIG_DFL;
219 sigemptyset(&sigact.sa_mask);
220 sigact.sa_flags = 0;
221 sigaction(signo, &sigact, NULL);
222 raise(signo);
223 } else
224 exit(1);
225 }
226
227 static int readsig(int fd)
228 {
229 char c = 42;
230
231 if (read(fd, &c, 1) == -1)
232 return 0;
233 else
234 return c;
235 }
236
237 static void waitevent(void)
238 {
239 struct pollfd pfd[2];
240 int res;
241
242 pfd[0].fd = ConnectionNumber(display);
243 pfd[0].events = POLLIN;
244
245 pfd[1].fd = sigpipe[0];
246 pfd[1].events = POLLIN;
247
248 for (;;) {
249 //printf("waitevent loop\n");
250 do {
251 //printf("pool 1\n");
252 res = poll(pfd, 2, -1);
253 //printf("pool 2\n");
254 } while (res == -1 && (errno == EINTR || errno == EAGAIN));
255 //printf("waitevent loop 2\n");
256 if (res == -1) {
257 error("poll: %s", strerror(errno));
258 die(0);
259 } else {
260 int sig;
261
262 if (pfd[1].revents == POLLIN &&
263 (sig = readsig(pfd[1].fd)) != 0) {
264 /* Signal received on our self-pipe */
265 debug("terminating on signal %d", sig);
266 die(sig);
267 } else if (pfd[0].revents == POLLIN) {
268 /* Event received */
269 return;
270 } else if (pfd[0].revents == POLLERR) {
271 /* X connection broken */
272 error("X connection broken");
273 die(0);
274 }
275 }
276 //printf("waitevent loop 3\n");
277 }
278 }
279
280 static void nextevent(XEvent *ep)
281 {
282 XFlush(display);
283 if (XQLength(display) == 0)
284 waitevent();
285 XNextEvent(display, ep);
286 }
287
288 static unsigned short scalepixel(unsigned c, double d)
289 {
290 double r;
291
292 r = c + 65535. * d;
293 r = MIN(r, 65535.);
294 r = MAX(r, 0.);
295 return r;
296 }
297
298 static void scalecolor(XColor *rp, const XColor *cp, double d)
299 {
300 rp->red = scalepixel(cp->red, d);
301 rp->green = scalepixel(cp->green, d);
302 rp->blue = scalepixel(cp->blue, d);
303 }
304
305 static void mkcolor(struct color *color, const char *name)
306 {
307 XColor tc, sc;
308
309 XAllocNamedColor(display, DefaultColormap(display, screen),
310 name, &sc, &tc);
311
312 color->normal = sc.pixel;
313
314 scalecolor(&sc, &tc, -.07);
315 XAllocColor(display, DefaultColormap(display, screen), &sc);
316 color->shadow1 = sc.pixel;
317
318 scalecolor(&sc, &tc, -.25);
319 XAllocColor(display, DefaultColormap(display, screen), &sc);
320 color->shadow2 = sc.pixel;
321
322 scalecolor(&sc, &tc, +.07);
323 XAllocColor(display, DefaultColormap(display, screen), &sc);
324 color->bright1 = sc.pixel;
325
326 scalecolor(&sc, &tc, +.25);
327 XAllocColor(display, DefaultColormap(display, screen), &sc);
328 color->bright2 = sc.pixel;
329 }
330
331 static void usage(FILE *fp)
332 {
333 fprintf(fp,
334 "usage: karmen [-display name] [-font name] [-help] [-version]\n");
335 }
336
337 static void loadres(XrmDatabase db)
338 {
339 XrmValue val;
340 char *type;
341
342 if (XrmGetResource(db, "karmen.showHelp",
343 "Karmen.ShowHelp", &type, &val)) {
344 usage(stdout);
345 exit(0);
346 }
347
348 if (XrmGetResource(db, "karmen.showVersion",
349 "Karmen.ShowVersion", &type, &val)) {
350 printf("%s\n", PACKAGE_STRING);
351 exit(0);
352 }
353
354 if (XrmGetResource(db, "karmen.display",
355 "Karmen.Display", &type, &val))
356 displayname = STRDUP((char *)val.addr);
357
358 if (XrmGetResource(db, "karmen.title.active.foreground",
359 "Karmen.Title.Active.Foreground", &type, &val))
360 colorname_title_active_fg = STRDUP((char *)val.addr);
361
362 if (XrmGetResource(db, "karmen.title.active.background",
363 "Karmen.Title.Active.Background", &type, &val))
364 colorname_title_active_bg = STRDUP((char *)val.addr);
365
366 if (XrmGetResource(db, "karmen.title.inactive.foreground",
367 "Karmen.Title.Inactive.Foreground", &type, &val))
368 colorname_title_inactive_fg = STRDUP((char *)val.addr);
369
370 if (XrmGetResource(db, "karmen.title.inactive.background",
371 "Karmen.Title.Inactive.Background", &type, &val))
372 colorname_title_inactive_bg = STRDUP((char *)val.addr);
373
374 if (XrmGetResource(db, "karmen.menu.foreground",
375 "Karmen.Menu.Foreground", &type, &val))
376 colorname_menu_fg = STRDUP((char *)val.addr);
377
378 if (XrmGetResource(db, "karmen.menu.background",
379 "Karmen.Menu.Background", &type, &val))
380 colorname_menu_bg = STRDUP((char *)val.addr);
381
382 if (XrmGetResource(db, "karmen.menu.selection.foreground",
383 "Karmen.Menu.Selection.Foreground", &type, &val))
384 colorname_menu_selection_fg = STRDUP((char *)val.addr);
385
386 if (XrmGetResource(db, "karmen.menu.selection.background",
387 "Karmen.Menu.Selection.Background", &type, &val))
388 colorname_menu_selection_bg = STRDUP((char *)val.addr);
389
390 if (XrmGetResource(db, "karmen.border.width",
391 "Karmen.Border.Width", &type, &val))
392 border_width = MAX(BORDERWIDTH_MIN, atoi((char *)val.addr));
393
394 if (XrmGetResource(db, "karmen.font", "Karmen.Font", &type, &val))
395 ftnames[0] = STRDUP((char *)val.addr);
396 }
397
398 static void loadfont(void)
399 {
400 int i;
401
402 for (i = 0; i < NELEM(ftnames); i++) {
403 font = XLoadQueryFont(display, ftnames[i]);
404 if (font != NULL)
405 return;
406 error("can't load font \"%s\"", ftnames[i]);
407 }
408 error("fatal: no more fonts");
409 exit(1);
410 }
411
412 #include "monitor.h"
413 monitor* monitors;
414 int monitors_len;
415 int mouse_posx;
416 int mouse_posy;
417 static void setupmonitors() {
418 #ifdef XINERAMA
419 if (XineramaIsActive(display)) {
420 XineramaScreenInfo *info = XineramaQueryScreens(display, &monitors_len);
421 //XineramaScreenInfo *unique = NULL;
422 monitors = malloc(sizeof(monitor)*monitors_len);
423 for (int i = 0; i < monitors_len; i++) {
424 monitors[i].id = info[i].screen_number;
425 monitors[i].x = info[i].x_org;
426 monitors[i].y = info[i].y_org;
427 monitors[i].w = info[i].width;
428 monitors[i].h = info[i].height;
429 }
430 XFree(info);
431 }
432 #else
433 monitors = malloc(sizeof(monitor));
434 monitors[0].id = 0;
435 monitors[0].x = 0;
436 monitors[0].y = 0;
437 monitors[0].w = DisplayWidth(display, screen);
438 monitors[0].h = DisplayHeight(display, screen);
439 #endif
440 }
441
442 static void init(int *argcp, char *argv[])
443 {
444
445 /* Prevents zombie processes */
446 if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) {
447 printf("SIGCHLD failed");
448 exit(1);
449 }
450
451 XrmDatabase adb, db;
452 struct sigaction sigact, oldact;
453 char *dbstr;
454 int i;
455
456 int ret = pipe(sigpipe);
457 if (ret) {
458 printf("sig pipe failed\n");
459 exit(1);
460 }
461 fcntl(sigpipe[0], F_SETFL, O_NONBLOCK);
462 fcntl(sigpipe[1], F_SETFL, O_NONBLOCK);
463
464 /*
465 * Set up signal handlers for those that were not ignored.
466 */
467 sigact.sa_handler = sighandler;
468 sigact.sa_flags = 0;
469 sigfillset(&sigact.sa_mask);
470 for (i = 0; i < NELEM(sigv); i++) {
471 sigaction(sigv[i], NULL, &oldact);
472 if (oldact.sa_handler != SIG_IGN)
473 sigaction(sigv[i], &sigact, NULL);
474 }
475
476 XSetErrorHandler(xerr_report);
477
478 XrmInitialize();
479
480 /* Load command line options before XOpenDisplay to read -display */
481 adb = NULL;
482 XrmParseCommand(&adb, options, NELEM(options), "karmen", argcp, argv);
483 if (*argcp > 1) {
484 for (i = 1; i < *argcp; i++)
485 error("invalid option: %s", argv[i]);
486 usage(stderr);
487 exit(1);
488 }
489 loadres(adb);
490
491 if ((display = XOpenDisplay(displayname)) == NULL) {
492 error("can't open display \"%s\"", XDisplayName(displayname));
493 exit(1);
494 }
495
496 /* Load the default database. */
497 db = NULL;
498 if ((dbstr = XResourceManagerString(display)) != NULL)
499 db = XrmGetStringDatabase(dbstr);
500 XrmMergeDatabases(adb, &db);
501 loadres(db);
502
503 XrmDestroyDatabase(db);
504
505 screen = DefaultScreen(display);
506 root = RootWindow(display, screen);
507
508 XSelectInput(display, root, ButtonPressMask |
509 SubstructureRedirectMask | SubstructureNotifyMask |
510 KeyPressMask | KeyReleaseMask);
511
512 grabkey(display, XKeysymToKeycode(display, XK_Tab),
513 Mod1Mask, root, True, GrabModeAsync, GrabModeAsync);
514 grabkey(display, XKeysymToKeycode(display, XK_Tab),
515 ShiftMask | Mod1Mask, root, True, GrabModeAsync, GrabModeAsync);
516
517 grabkey(display, XKeysymToKeycode(display, XK_Return),
518 Mod1Mask, root, True, GrabModeAsync, GrabModeAsync);
519
520 grabkey(display, XKeysymToKeycode(display, XK_space),
521 Mod1Mask, root, True, GrabModeAsync, GrabModeAsync);
522
523 grabkey(display, XKeysymToKeycode(display, XK_s),
524 Mod1Mask, root, True, GrabModeAsync, GrabModeAsync);
525
526 grabkey(display, XKeysymToKeycode(display, XK_p),
527 Mod1Mask, root, True, GrabModeAsync, GrabModeAsync);
528
529 grabkey(display, XKeysymToKeycode(display, XK_Escape),
530 Mod1Mask, root, True, GrabModeAsync, GrabModeAsync);
531
532 grabkey(display, XKeysymToKeycode(display, XK_l),
533 Mod1Mask, root, True, GrabModeAsync, GrabModeAsync);
534
535 //grabkey(display, XKeysymToKeycode(display, XK_BackSpace),
536 // Mod1Mask, root, True, GrabModeAsync, GrabModeAsync);
537 grabkey(display, XKeysymToKeycode(display, XK_BackSpace),
538 ShiftMask | Mod1Mask, root, True, GrabModeAsync, GrabModeAsync);
539
540 loadfont();
541
542 title_pad = 1 + MAX(1, (font->ascent + font->descent) / 10);
543 button_size = font->ascent + font->descent + 2 * title_pad;
544 if ((button_size & 1) == 1)
545 button_size++;
546 button_size++;
547
548 mkcolor(&color_title_active_fg, colorname_title_active_fg);
549 mkcolor(&color_title_active_bg, colorname_title_active_bg);
550 mkcolor(&color_title_inactive_fg, colorname_title_inactive_fg);
551 mkcolor(&color_title_inactive_bg, colorname_title_inactive_bg);
552 mkcolor(&color_menu_fg, colorname_menu_fg);
553 mkcolor(&color_menu_bg, colorname_menu_bg);
554 mkcolor(&color_menu_selection_fg, colorname_menu_selection_fg);
555 mkcolor(&color_menu_selection_bg, colorname_menu_selection_bg);
556 }
557
558 KeySym getKeysym(KeyCode kc) {
559 int i;
560 KeySym *ks = XGetKeyboardMapping(display,kc,1,&i);
561 KeySym ret = ks[0];
562 XFree(ks);
563 return ret;
564 }
565
566 #include <X11/Xlib.h>
567 #include <X11/Xutil.h>
568
569 static void handlekey(XKeyEvent *ep)
570 {
571 static int cycling = 0;
572
573 Display *dpy;
574 switch (getKeysym(ep->keycode)) {
575 case XK_Meta_L:
576 case XK_Meta_R:
577 case XK_Alt_L:
578 case XK_Alt_R:
579 if (ep->type == KeyRelease) {
580 /* end window cycling */
581 if (cycling) {
582 cycling = 0;
583 XUngrabKeyboard(display, CurrentTime);
584 select_current_menuitem(winmenu);
585 hide_menu(winmenu);
586 }
587 }
588 break;
589 case XK_l:
590 if (ep->type == KeyRelease) {
591 pthread_mutex_lock(&mutex);
592 slock();
593 pthread_mutex_unlock(&mutex);
594 }
595 break;
596 case XK_Tab:
597 if (ep->type == KeyPress) {
598 cycling = 1;
599
600 /* Listen for Alt/Meta release */
601 XGrabKeyboard(display, root, True,
602 GrabModeAsync, GrabModeAsync, CurrentTime);
603
604 if (!WIDGET_MAPPED(winmenu)) {
605 int x = DisplayWidth(display, screen) / 2
606 - WIDGET_WIDTH(winmenu) / 2;
607 int y = DisplayHeight(display, screen) / 2
608 - WIDGET_HEIGHT(winmenu) / 2;
609 show_menu(winmenu, x, y, -1);
610 }
611
612 if (winmenu->current == -1)
613 winmenu->current = ep->state & ShiftMask ?
614 winmenu->nitems - 1 : 1;
615 else
616 winmenu->current +=
617 ep->state & ShiftMask ? -1 : 1;
618
619 if (winmenu->current >= winmenu->nitems)
620 winmenu->current = 0;
621 else if (winmenu->current < 0)
622 winmenu->current = winmenu->nitems - 1;
623
624 REPAINT(winmenu);
625 }
626 break;
627 case XK_space:
628 if (ep->type == KeyPress && active != NULL)
629 maximize_window(active, -1, -1);
630 break;
631 case XK_Return:
632 if (ep->type == KeyPress && active != NULL)
633 spawn(TERM);
634 break;
635 case XK_s:
636 if (ep->type == KeyPress && active != NULL) {
637 char* argv[4] = {SHELL, "-c", SCREENSHOT, NULL};
638 spawn_argv(argv);
639 }
640 break;
641 case XK_p:
642 if (ep->type == KeyPress && active != NULL) {
643 spawn("thingylaunch");
644 }
645 break;
646 case XK_Escape:
647 if (cycling) {
648 cycling = 0;
649 hide_menu(winmenu);
650 XUngrabKeyboard(display, CurrentTime);
651 } else if (ep->type == KeyPress && active != NULL)
652 user_unmap_window(active);
653 break;
654 case XK_BackSpace:
655 if (ep->type == KeyPress && active != NULL) {
656 /*if (ep->state & ShiftMask) {
657 clerr();
658 XKillClient(display, active->client);
659 sterr();
660 } else*/
661 delete_window(active);
662 }
663 break;
664 default:
665 debug("handlekey(): Unhandled key");
666 break;
667 }
668 }
669
670 static void configrequest(XConfigureRequestEvent *conf)
671 {
672 XWindowChanges wc;
673
674 wc.x = conf->x;
675 wc.y = conf->y;
676 wc.width = conf->width;
677 wc.height = conf->height;
678 wc.border_width = conf->border_width;
679 wc.sibling = conf->above;
680 wc.stack_mode = conf->detail;
681
682 clerr();
683 XConfigureWindow(display, conf->window,
684 conf->value_mask, &wc);
685 sterr();
686 }
687
688 static Window xeventwindow(XEvent *ep)
689 {
690 switch (ep->type) {
691 case ConfigureRequest:
692 /*
693 * For some reason, the first configure request
694 * received from a client sometimes has the root
695 * window as its parent even though we have already
696 * managed to reparent it, and since xany.window maps
697 * to xmaprequest.parent we won't be able to figure
698 * out what window it is unless we read the
699 * xconfigurerequest.window member instead.
700 *
701 * I spent so much time finding this out ...
702 */
703 return ep->xconfigurerequest.window;
704
705 case MapRequest:
706 /*
707 * A map request event's xany.window member maps
708 * to xmaprequest.parent, which will be the root
709 * window when a client maps itself. We are
710 * interested in the xmaprequest.window member.
711 */
712 return ep->xmaprequest.window;
713
714 default:
715 /*
716 * For most event types, the xany.window member
717 * is what we're interested in.
718 */
719 return ep->xany.window;
720 }
721 }
722
723 static void mainloop(void)
724 {
725 XEvent e;
726 Window xwindow;
727 struct widget *widget;
728
729 for (;;) {
730 restack_all_windows();
731 repaint_widgets();
732 nextevent(&e);
733 xwindow = xeventwindow(&e);
734 widget = find_widget(xwindow, WIDGET_ANY);
735 if (widget != NULL) {
736 if (widget->event != NULL)
737 widget->event(widget, &e);
738 } else {
739 switch (e.type) {
740 case MapRequest:
741 manage_window(xwindow, 0);
742 break;
743 case ConfigureRequest:
744 configrequest(&e.xconfigurerequest);
745 break;
746 case ButtonPress:
747 if (e.xbutton.window == root &&
748 e.xbutton.subwindow == None &&
749 e.xbutton.button == Button3)
750 show_menu(winmenu,
751 e.xbutton.x, e.xbutton.y,
752 e.xbutton.button);
753 break;
754 case KeyPress:
755 case KeyRelease:
756 if (e.xkey.window == root)
757 handlekey(&e.xkey);
758 break;
759 case ClientMessage:
760 case CreateNotify:
761 case DestroyNotify:
762 case ConfigureNotify:
763 case ReparentNotify:
764 case MapNotify:
765 case UnmapNotify:
766 /* ignore */
767 break;
768 default:
769 debug("mainloop(): unhandled event -- %s (%d)",
770 eventname(e.type), e.type);
771 break;
772 }
773 }
774 //printf("step last\n");
775 }
776 }
777
778 int spawn(char* path) {
779 char* argv[2] = {path, NULL};
780 return spawn_argv(argv);
781 }
782
783 int spawn_argv(char** argv) {
784 int pid = fork();
785 if (pid == 0) {
786 if(display)
787 close(ConnectionNumber(display));
788 setsid();
789 execvp(argv[0], argv);
790 exit(0);
791 }
792 return pid;
793 }
794
795 #include <pthread.h>
796 int main(int argc, char *argv[])
797 {
798 init(&argc, argv);
799
800 widget_init();
801 winmenu = create_menu();
802 hints_init();
803 window_init();
804 setupmonitors();
805 system("~/.fehbg");
806 pthread_t thread;
807 pthread_create(&thread, NULL, (void*)screensaver, NULL);
808 spawn(PANEL);
809 mainloop();
810 return 0;
811 }
812