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