- XEvent e;
- fd_set fd;
- int x11_fd, i, c;
- struct timeval tv;
-
- c = getopt (argc, argv, "c:");
- init ();
-
-load_config:
- if (panel.area.pix.pmap) XFreePixmap (server.dsp, panel.area.pix.pmap);
- panel.area.pix.pmap = 0;
- // append full transparency background
- list_back = g_slist_append(0, calloc(1, sizeof(Area)));
-
- // read tint2rc config
- i = 0;
- if (c != -1)
- i = config_read_file (optarg);
- if (!i)
- i = config_read ();
- if (!i) {
- fprintf(stderr, "usage: tint2 [-c] <config_file>\n");
- cleanup();
- exit(1);
- }
- config_finish ();
-
- window_draw_panel ();
-
- // BUG: refresh(clock) is needed here, but 'on the paper' it's not necessary.
- refresh(&panel.clock.area);
-
- x11_fd = ConnectionNumber (server.dsp);
- XSync (server.dsp, False);
-
- while (1) {
- // thanks to AngryLlama for the timer
- // Create a File Description Set containing x11_fd
- FD_ZERO (&fd);
- FD_SET (x11_fd, &fd);
-
- tv.tv_usec = 500000;
- tv.tv_sec = 0;
-
- // Wait for X Event or a Timer
- if (select(x11_fd+1, &fd, 0, 0, &tv)) {
- while (XPending (server.dsp)) {
- XNextEvent(server.dsp, &e);
-
- switch (e.type) {
- case ButtonPress:
- if (e.xbutton.button == 1) event_button_press (e.xbutton.x, e.xbutton.y);
- break;
-
- case ButtonRelease:
- event_button_release (e.xbutton.button, e.xbutton.x, e.xbutton.y);
- break;
-
- case Expose:
- XCopyArea (server.dsp, panel.area.pix.pmap, server.root_win, server.gc_root, 0, 0, panel.area.width, panel.area.height, server.posx, server.posy);
- XCopyArea (server.dsp, server.pmap, window.main_win, server.gc, panel.area.paddingx, 0, panel.area.width-(2*panel.area.paddingx), panel.area.height, 0, 0);
- break;
-
- case PropertyNotify:
- //printf("PropertyNotify\n");
- event_property_notify (e.xproperty.window, e.xproperty.atom);
- break;
-
- case ConfigureNotify:
- if (e.xconfigure.window == server.root_win)
- goto load_config;
- else
- event_configure_notify (e.xconfigure.window);
- break;
- }
- }
- }
- else event_timer();
-
- switch (panel.signal_pending) {
- case SIGUSR1:
- goto load_config;
- case SIGINT:
- case SIGTERM:
- cleanup ();
- return 0;
- }
-
- if (panel.refresh && !panel.sleep_mode) {
- visual_refresh ();
- //printf(" *** visual_refresh\n");
- }
- }
+ XEvent e;
+ fd_set fdset;
+ int x11_fd, i;
+ Panel *panel;
+ GSList *it;
+ GSList* timer_iter;
+ struct timer* timer;
+
+ init (argc, argv);
+
+ i = 0;
+ init_config();
+ if (config_path)
+ i = config_read_file (config_path);
+ else
+ i = config_read ();
+ if (!i) {
+ fprintf(stderr, "usage: tint2 [-c] <config_file>\n");
+ cleanup();
+ exit(1);
+ }
+ init_panel();
+ cleanup_config();
+ if (snapshot_path) {
+ get_snapshot(snapshot_path);
+ cleanup();
+ exit(0);
+ }
+
+ x11_fd = ConnectionNumber(server.dsp);
+ XSync(server.dsp, False);
+
+ sigset_t empty_mask;
+ sigemptyset(&empty_mask);
+
+ while (1) {
+ if (panel_refresh) {
+ panel_refresh = 0;
+
+ if (refresh_systray) {
+ panel = (Panel*)systray.area.panel;
+ XSetWindowBackgroundPixmap (server.dsp, panel->main_win, None);
+ }
+ for (i=0 ; i < nb_panel ; i++) {
+ panel = &panel1[i];
+
+ if (panel->temp_pmap) XFreePixmap(server.dsp, panel->temp_pmap);
+ panel->temp_pmap = XCreatePixmap(server.dsp, server.root_win, panel->area.width, panel->area.height, server.depth);
+
+ refresh(&panel->area);
+ XCopyArea(server.dsp, panel->temp_pmap, panel->main_win, server.gc, 0, 0, panel->area.width, panel->area.height, 0, 0);
+ }
+ XFlush (server.dsp);
+
+ if (refresh_systray) {
+ refresh_systray = 0;
+ panel = (Panel*)systray.area.panel;
+ // tint2 doen't draw systray icons. it just redraw background.
+ XSetWindowBackgroundPixmap (server.dsp, panel->main_win, panel->temp_pmap);
+ // force icon's refresh
+ refresh_systray_icon();
+ }
+ }
+
+ // thanks to AngryLlama for the timer
+ // Create a File Description Set containing x11_fd, and every timer_fd
+ FD_ZERO (&fdset);
+ FD_SET (x11_fd, &fdset);
+ int max_fd = x11_fd;
+ timer_iter = timer_list;
+ while (timer_iter) {
+ timer = timer_iter->data;
+ max_fd = timer->id > max_fd ? timer->id : max_fd;
+ FD_SET(timer->id, &fdset);
+ timer_iter = timer_iter->next;
+ }
+
+ // Wait for X Event or a Timer
+ if (pselect(max_fd+1, &fdset, 0, 0, 0, &empty_mask) > 0) {
+ while (XPending (server.dsp)) {
+ XNextEvent(server.dsp, &e);
+
+ switch (e.type) {
+ case ButtonPress:
+ tooltip_hide();
+ event_button_press (&e);
+ break;
+
+ case ButtonRelease:
+ event_button_release(&e);
+ break;
+
+ case MotionNotify: {
+ if (!g_tooltip.enabled) break;
+ Panel* panel = get_panel(e.xmotion.window);
+ Area* area = click_area(panel, e.xmotion.x, e.xmotion.y);
+ if (area->_get_tooltip_text) {
+ tooltip_trigger_show(area, panel, e.xmotion.x_root, e.xmotion.y_root);
+ }
+ else
+ tooltip_trigger_hide();
+ break;
+ }
+
+ case LeaveNotify:
+ tooltip_trigger_hide();
+ break;
+
+ case Expose:
+ event_expose(&e);
+ break;
+
+ case MapNotify:
+ if (e.xany.window == g_tooltip.window)
+ tooltip_update();
+ break;
+
+ case PropertyNotify:
+ event_property_notify(&e);
+ break;
+
+ case ConfigureNotify:
+ event_configure_notify (e.xconfigure.window);
+ break;
+
+ case ReparentNotify:
+ if (!systray_enabled)
+ break;
+ panel = (Panel*)systray.area.panel;
+ if (e.xany.window == panel->main_win) // reparented to us
+ break;
+ // FIXME: 'reparent to us' badly detected => disabled
+ break;
+ case UnmapNotify:
+ case DestroyNotify:
+ if (e.xany.window == g_tooltip.window || !systray.area.on_screen)
+ break;
+ for (it = systray.list_icons; it; it = g_slist_next(it)) {
+ if (((TrayWindow*)it->data)->id == e.xany.window) {
+ remove_icon((TrayWindow*)it->data);
+ break;
+ }
+ }
+ break;
+
+ case ClientMessage:
+ if (!systray.area.on_screen) break;
+ if (e.xclient.message_type == server.atom._NET_SYSTEM_TRAY_OPCODE && e.xclient.format == 32 && e.xclient.window == net_sel_win) {
+ net_message(&e.xclient);
+ }
+ else if (e.xclient.message_type == server.atom.XdndPosition) {
+ dnd_message(&e.xclient);
+ }
+ break;
+ }
+ }
+
+ // we need to iterate over the whole timer list, since fd_set can only be checked with the
+ // brute force method FD_ISSET for every possible timer
+ timer_iter = timer_list;
+ while (timer_iter) {
+ timer = timer_iter->data;
+ if (FD_ISSET(timer->id, &fdset)) {
+ uint64_t dummy;
+ read(timer->id, &dummy, sizeof(uint64_t));
+ timer->_callback();
+ }
+ timer_iter = timer_iter->next;
+ }
+ }
+
+ switch (signal_pending) {
+ case SIGUSR1: // reload config file
+ signal_pending = 0;
+ init_config();
+ config_read_file (config_path);
+ init_panel();
+ cleanup_config();
+ break;
+ case SIGINT:
+ case SIGTERM:
+ case SIGHUP:
+ cleanup ();
+ return 0;
+ }
+ }