]> Dogcows Code - chaz/tint2/blob - src/tint.c
fd89b8c468a528467ec22347a4913fee61c19894
[chaz/tint2] / src / tint.c
1 /**************************************************************************
2 *
3 * Tint2 panel
4 *
5 * Copyright (C) 2007 Pål Staurland (staura@gmail.com)
6 * Modified (C) 2008 thierry lorthiois (lorthiois@bbsoft.fr)
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 **************************************************************************/
20
21 #include <sys/stat.h>
22 #include <unistd.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdint.h>
26 #include <string.h>
27 #include <X11/Xutil.h>
28 #include <X11/Xatom.h>
29 #include <X11/Xlocale.h>
30 #include <X11/extensions/Xdamage.h>
31 #include <Imlib2.h>
32 #include <signal.h>
33
34 #include <version.h>
35 #include "server.h"
36 #include "window.h"
37 #include "config.h"
38 #include "task.h"
39 #include "taskbar.h"
40 #include "systraybar.h"
41 #include "launcher.h"
42 #include "panel.h"
43 #include "tooltip.h"
44 #include "timer.h"
45
46
47 void signal_handler(int sig)
48 {
49 // signal handler is light as it should be
50 signal_pending = sig;
51 }
52
53
54 void init (int argc, char *argv[])
55 {
56 int i;
57
58 // set global data
59 default_config();
60 default_timeout();
61 default_systray();
62 memset(&server, 0, sizeof(Server_global));
63 #ifdef ENABLE_BATTERY
64 default_battery();
65 #endif
66 default_clock();
67 default_launcher();
68 default_taskbar();
69 default_tooltip();
70 default_panel();
71
72 // read options
73 for (i = 1; i < argc; ++i) {
74 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
75 printf("Usage: tint2 [-c] <config_file>\n");
76 exit(0);
77 }
78 if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
79 printf("tint2 version %s\n", VERSION_STRING);
80 exit(0);
81 }
82 if (!strcmp(argv[i], "-c")) {
83 i++;
84 if (i < argc)
85 config_path = strdup(argv[i]);
86 }
87 if (!strcmp(argv[i], "-s")) {
88 i++;
89 if (i < argc)
90 snapshot_path = strdup(argv[i]);
91 }
92 }
93 // Set signal handler
94 signal_pending = 0;
95 struct sigaction sa = { .sa_handler = signal_handler };
96 struct sigaction sa_chld = { .sa_handler = SIG_DFL, .sa_flags = SA_NOCLDWAIT };
97 sigaction(SIGUSR1, &sa, 0);
98 sigaction(SIGINT, &sa, 0);
99 sigaction(SIGTERM, &sa, 0);
100 sigaction(SIGHUP, &sa, 0);
101 sigaction(SIGCHLD, &sa_chld, 0);
102
103 // BSD does not support pselect(), therefore we have to use select and hope that we do not
104 // end up in a race condition there (see 'man select()' on a linux machine for more information)
105 // block all signals, such that no race conditions occur before pselect in our main loop
106 // sigset_t block_mask;
107 // sigaddset(&block_mask, SIGINT);
108 // sigaddset(&block_mask, SIGTERM);
109 // sigaddset(&block_mask, SIGHUP);
110 // sigaddset(&block_mask, SIGUSR1);
111 // sigprocmask(SIG_BLOCK, &block_mask, 0);
112 }
113
114 void init_X11()
115 {
116 server.dsp = XOpenDisplay (NULL);
117 if (!server.dsp) {
118 fprintf(stderr, "tint2 exit : could not open display.\n");
119 exit(0);
120 }
121 server_init_atoms ();
122 server.screen = DefaultScreen (server.dsp);
123 server.root_win = RootWindow(server.dsp, server.screen);
124 server.desktop = server_get_current_desktop ();
125 server_init_visual();
126 XSetErrorHandler ((XErrorHandler) server_catch_error);
127
128 imlib_context_set_display (server.dsp);
129 imlib_context_set_visual (server.visual);
130 imlib_context_set_colormap (server.colormap);
131
132 /* Catch events */
133 XSelectInput (server.dsp, server.root_win, PropertyChangeMask|StructureNotifyMask);
134
135 setlocale (LC_ALL, "");
136 // config file use '.' as decimal separator
137 setlocale(LC_NUMERIC, "POSIX");
138
139 // load default icon
140 gchar *path;
141 const gchar * const *data_dirs;
142 data_dirs = g_get_system_data_dirs ();
143 int i;
144 for (i = 0; data_dirs[i] != NULL; i++) {
145 path = g_build_filename(data_dirs[i], "tint2", "default_icon.png", NULL);
146 if (g_file_test (path, G_FILE_TEST_EXISTS))
147 default_icon = imlib_load_image(path);
148 g_free(path);
149 }
150
151 // get monitor and desktop config
152 get_monitors();
153 get_desktops();
154 }
155
156
157 void cleanup()
158 {
159 cleanup_timeout();
160 cleanup_systray();
161 cleanup_tooltip();
162 cleanup_clock();
163 cleanup_launcher();
164 #ifdef ENABLE_BATTERY
165 cleanup_battery();
166 #endif
167 cleanup_panel();
168 cleanup_config();
169
170 if (default_icon) {
171 imlib_context_set_image(default_icon);
172 imlib_free_image();
173 }
174 imlib_context_disconnect_display();
175
176 cleanup_server();
177 if (server.dsp) XCloseDisplay(server.dsp);
178 }
179
180
181 void get_snapshot(const char *path)
182 {
183 Panel *panel = &panel1[0];
184
185 if (panel->area.width > server.monitor[0].width)
186 panel->area.width = server.monitor[0].width;
187
188 panel->temp_pmap = XCreatePixmap(server.dsp, server.root_win, panel->area.width, panel->area.height, server.depth);
189 rendering(panel);
190
191 Imlib_Image img = NULL;
192 imlib_context_set_drawable(panel->temp_pmap);
193 img = imlib_create_image_from_drawable(0, 0, 0, panel->area.width, panel->area.height, 0);
194
195 imlib_context_set_image(img);
196 if (!panel_horizontal) {
197 // rotate 90° vertical panel
198 imlib_image_flip_horizontal();
199 imlib_image_flip_diagonal();
200 }
201 imlib_save_image(path);
202 imlib_free_image();
203 }
204
205
206 void window_action (Task *tsk, int action)
207 {
208 if (!tsk) return;
209 int desk;
210 switch (action) {
211 case CLOSE:
212 set_close (tsk->win);
213 break;
214 case TOGGLE:
215 set_active(tsk->win);
216 break;
217 case ICONIFY:
218 XIconifyWindow (server.dsp, tsk->win, server.screen);
219 break;
220 case TOGGLE_ICONIFY:
221 if (task_active && tsk->win == task_active->win)
222 XIconifyWindow (server.dsp, tsk->win, server.screen);
223 else
224 set_active (tsk->win);
225 break;
226 case SHADE:
227 window_toggle_shade (tsk->win);
228 break;
229 case MAXIMIZE_RESTORE:
230 window_maximize_restore (tsk->win);
231 break;
232 case MAXIMIZE:
233 window_maximize_restore (tsk->win);
234 break;
235 case RESTORE:
236 window_maximize_restore (tsk->win);
237 break;
238 case DESKTOP_LEFT:
239 if ( tsk->desktop == 0 ) break;
240 desk = tsk->desktop - 1;
241 windows_set_desktop(tsk->win, desk);
242 if (desk == server.desktop)
243 set_active(tsk->win);
244 break;
245 case DESKTOP_RIGHT:
246 if (tsk->desktop == server.nb_desktop ) break;
247 desk = tsk->desktop + 1;
248 windows_set_desktop(tsk->win, desk);
249 if (desk == server.desktop)
250 set_active(tsk->win);
251 break;
252 case NEXT_TASK:
253 if (task_active) {
254 Task *tsk1;
255 tsk1 = next_task(task_active);
256 set_active(tsk1->win);
257 }
258 break;
259 case PREV_TASK:
260 if (task_active) {
261 Task *tsk1;
262 tsk1 = prev_task(task_active);
263 set_active(tsk1->win);
264 }
265 }
266 }
267
268
269 int tint2_handles_click(Panel* panel, XButtonEvent* e)
270 {
271 Task* task = click_task(panel, e->x, e->y);
272 if (task) {
273 if( (e->button == 1)
274 || (e->button == 2 && mouse_middle != 0)
275 || (e->button == 3 && mouse_right != 0)
276 || (e->button == 4 && mouse_scroll_up != 0)
277 || (e->button == 5 && mouse_scroll_down !=0) )
278 {
279 return 1;
280 }
281 else
282 return 0;
283 }
284 LauncherIcon *icon = click_launcher_icon(panel, e->x, e->y);
285 if (icon) {
286 if (e->button == 1) {
287 return 1;
288 } else {
289 return 0;
290 }
291 }
292 // no launcher/task clicked --> check if taskbar clicked
293 Taskbar *tskbar = click_taskbar(panel, e->x, e->y);
294 if (tskbar && e->button == 1 && panel_mode == MULTI_DESKTOP)
295 return 1;
296 if (click_clock(panel, e->x, e->y)) {
297 if ( (e->button == 1 && clock_lclick_command) || (e->button == 3 && clock_rclick_command) )
298 return 1;
299 else
300 return 0;
301 }
302 return 0;
303 }
304
305
306 void forward_click(XEvent* e)
307 {
308 // forward the click to the desktop window (thanks conky)
309 XUngrabPointer(server.dsp, e->xbutton.time);
310 e->xbutton.window = server.root_win;
311 // icewm doesn't open under the mouse.
312 // and xfce doesn't open at all.
313 e->xbutton.x = e->xbutton.x_root;
314 e->xbutton.y = e->xbutton.y_root;
315 //printf("**** %d, %d\n", e->xbutton.x, e->xbutton.y);
316 //XSetInputFocus(server.dsp, e->xbutton.window, RevertToParent, e->xbutton.time);
317 XSendEvent(server.dsp, e->xbutton.window, False, ButtonPressMask, e);
318 }
319
320
321 void event_button_press (XEvent *e)
322 {
323 Panel *panel = get_panel(e->xany.window);
324 if (!panel) return;
325
326
327 if (wm_menu && !tint2_handles_click(panel, &e->xbutton) ) {
328 forward_click(e);
329 return;
330 }
331 task_drag = click_task(panel, e->xbutton.x, e->xbutton.y);
332
333 if (panel_layer == BOTTOM_LAYER)
334 XLowerWindow (server.dsp, panel->main_win);
335 }
336
337 void event_button_motion_notify (XEvent *e)
338 {
339 Panel * panel = get_panel(e->xany.window);
340 if(!panel || !task_drag)
341 return;
342
343 // Find the taskbar on the event's location
344 Taskbar * event_taskbar = click_taskbar(panel, e->xbutton.x, e->xbutton.y);
345 if(event_taskbar == NULL)
346 return;
347
348 // Find the task on the event's location
349 Task * event_task = click_task(panel, e->xbutton.x, e->xbutton.y);
350
351 // If the event takes place on the same taskbar as the task being dragged
352 if(event_taskbar == task_drag->area.parent) {
353 // Swap the task_drag with the task on the event's location (if they differ)
354 if(event_task && event_task != task_drag) {
355 GSList * drag_iter = g_slist_find(event_taskbar->area.list, task_drag);
356 GSList * task_iter = g_slist_find(event_taskbar->area.list, event_task);
357 if(drag_iter && task_iter) {
358 gpointer temp = task_iter->data;
359 task_iter->data = drag_iter->data;
360 drag_iter->data = temp;
361 event_taskbar->area.resize = 1;
362 panel_refresh = 1;
363 task_dragged = 1;
364 }
365 }
366 }
367 else { // The event is on another taskbar than the task being dragged
368 if(task_drag->desktop == ALLDESKTOP || panel_mode != MULTI_DESKTOP)
369 return;
370
371 Taskbar * drag_taskbar = (Taskbar*)task_drag->area.parent;
372 drag_taskbar->area.list = g_slist_remove(drag_taskbar->area.list, task_drag);
373
374 if(event_taskbar->area.posx > drag_taskbar->area.posx || event_taskbar->area.posy > drag_taskbar->area.posy)
375 event_taskbar->area.list = g_slist_prepend(event_taskbar->area.list, task_drag);
376 else
377 event_taskbar->area.list = g_slist_append(event_taskbar->area.list, task_drag);
378
379 // Move task to other desktop (but avoid the 'Window desktop changed' code in 'event_property_notify')
380 task_drag->area.parent = event_taskbar;
381 task_drag->desktop = event_taskbar->desktop;
382
383 windows_set_desktop(task_drag->win, event_taskbar->desktop);
384
385 event_taskbar->area.resize = 1;
386 drag_taskbar->area.resize = 1;
387 task_dragged = 1;
388 panel_refresh = 1;
389 }
390 }
391
392 void event_button_release (XEvent *e)
393 {
394 Panel *panel = get_panel(e->xany.window);
395 if (!panel) return;
396
397 if (wm_menu && !tint2_handles_click(panel, &e->xbutton)) {
398 forward_click(e);
399 if (panel_layer == BOTTOM_LAYER)
400 XLowerWindow (server.dsp, panel->main_win);
401 task_drag = 0;
402 return;
403 }
404
405 int action = TOGGLE_ICONIFY;
406 switch (e->xbutton.button) {
407 case 2:
408 action = mouse_middle;
409 break;
410 case 3:
411 action = mouse_right;
412 break;
413 case 4:
414 action = mouse_scroll_up;
415 break;
416 case 5:
417 action = mouse_scroll_down;
418 break;
419 case 6:
420 action = mouse_tilt_left;
421 break;
422 case 7:
423 action = mouse_tilt_right;
424 break;
425 }
426
427 if ( click_clock(panel, e->xbutton.x, e->xbutton.y)) {
428 clock_action(e->xbutton.button);
429 if (panel_layer == BOTTOM_LAYER)
430 XLowerWindow (server.dsp, panel->main_win);
431 task_drag = 0;
432 return;
433 }
434
435 if ( click_launcher(panel, e->xbutton.x, e->xbutton.y)) {
436 LauncherIcon *icon = click_launcher_icon(panel, e->xbutton.x, e->xbutton.y);
437 if (icon) {
438 launcher_action(icon);
439 }
440 task_drag = 0;
441 return;
442 }
443
444 Taskbar *tskbar;
445 if ( !(tskbar = click_taskbar(panel, e->xbutton.x, e->xbutton.y)) ) {
446 // TODO: check better solution to keep window below
447 if (panel_layer == BOTTOM_LAYER)
448 XLowerWindow (server.dsp, panel->main_win);
449 task_drag = 0;
450 return;
451 }
452
453 // drag and drop task
454 if (task_dragged) {
455 task_drag = 0;
456 task_dragged = 0;
457 return;
458 }
459
460 // switch desktop
461 if (panel_mode == MULTI_DESKTOP) {
462 if (tskbar->desktop != server.desktop && action != CLOSE && action != DESKTOP_LEFT && action != DESKTOP_RIGHT)
463 set_desktop (tskbar->desktop);
464 }
465
466 // action on task
467 window_action( click_task(panel, e->xbutton.x, e->xbutton.y), action);
468
469 // to keep window below
470 if (panel_layer == BOTTOM_LAYER)
471 XLowerWindow (server.dsp, panel->main_win);
472 }
473
474
475 void event_property_notify (XEvent *e)
476 {
477 int i;
478 Task *tsk;
479 Window win = e->xproperty.window;
480 Atom at = e->xproperty.atom;
481
482 if (win == server.root_win) {
483 if (!server.got_root_win) {
484 XSelectInput (server.dsp, server.root_win, PropertyChangeMask|StructureNotifyMask);
485 server.got_root_win = 1;
486 }
487
488 // Change number of desktops
489 else if (at == server.atom._NET_NUMBER_OF_DESKTOPS) {
490 server.nb_desktop = server_get_number_of_desktop ();
491 cleanup_taskbar();
492 init_taskbar();
493 visible_object();
494 for (i=0 ; i < nb_panel ; i++) {
495 panel1[i].area.resize = 1;
496 }
497 task_refresh_tasklist();
498 active_task();
499 panel_refresh = 1;
500 }
501 // Change desktop
502 else if (at == server.atom._NET_CURRENT_DESKTOP) {
503 int old_desktop = server.desktop;
504 server.desktop = server_get_current_desktop ();
505 for (i=0 ; i < nb_panel ; i++) {
506 Panel *panel = &panel1[i];
507 if (panel_mode == MULTI_DESKTOP && panel->g_taskbar.use_active) {
508 // redraw both taskbar
509 if (server.nb_desktop > old_desktop) {
510 // can happen if last desktop is deleted and we've been on the last desktop
511 panel->taskbar[old_desktop].area.bg = panel->g_taskbar.bg;
512 panel->taskbar[old_desktop].area.resize = 1;
513 }
514 panel->taskbar[server.desktop].area.bg = panel->g_taskbar.bg_active;
515 panel->taskbar[server.desktop].area.resize = 1;
516 panel_refresh = 1;
517 }
518 // check ALLDESKTOP task => resize taskbar
519 Taskbar *tskbar;
520 Task *tsk;
521 GSList *l;
522 if (server.nb_desktop > old_desktop) {
523 tskbar = &panel->taskbar[old_desktop];
524 for (l = tskbar->area.list; l ; l = l->next) {
525 tsk = l->data;
526 if (tsk->desktop == ALLDESKTOP) {
527 tsk->area.on_screen = 0;
528 tskbar->area.resize = 1;
529 panel_refresh = 1;
530 }
531 }
532 }
533 tskbar = &panel->taskbar[server.desktop];
534 for (l = tskbar->area.list; l ; l = l->next) {
535 tsk = l->data;
536 if (tsk->desktop == ALLDESKTOP) {
537 tsk->area.on_screen = 1;
538 tskbar->area.resize = 1;
539 }
540 }
541 }
542 if (panel_mode != MULTI_DESKTOP) {
543 visible_object();
544 }
545 }
546 // Window list
547 else if (at == server.atom._NET_CLIENT_LIST) {
548 task_refresh_tasklist();
549 panel_refresh = 1;
550 }
551 // Change active
552 else if (at == server.atom._NET_ACTIVE_WINDOW) {
553 active_task();
554 panel_refresh = 1;
555 }
556 else if (at == server.atom._XROOTPMAP_ID) {
557 // change Wallpaper
558 for (i=0 ; i < nb_panel ; i++) {
559 set_panel_background(&panel1[i]);
560 }
561 panel_refresh = 1;
562 }
563 }
564 else {
565 tsk = task_get_task (win);
566 if (!tsk) {
567 if (at != server.atom._NET_WM_STATE)
568 return;
569 else {
570 // xfce4 sends _NET_WM_STATE after minimized to tray, so we need to check if window is mapped
571 // if it is mapped and not set as skip_taskbar, we must add it to our task list
572 XWindowAttributes wa;
573 XGetWindowAttributes(server.dsp, win, &wa);
574 if (wa.map_state == IsViewable && !window_is_skip_taskbar(win)) {
575 if ( (tsk = add_task(win)) )
576 panel_refresh = 1;
577 else
578 return;
579 }
580 else
581 return;
582 }
583 }
584 //printf("atom root_win = %s, %s\n", XGetAtomName(server.dsp, at), tsk->title);
585
586 // Window title changed
587 if (at == server.atom._NET_WM_VISIBLE_NAME || at == server.atom._NET_WM_NAME || at == server.atom.WM_NAME) {
588 get_title(tsk);
589 if (g_tooltip.mapped && (g_tooltip.area == (Area*)tsk)) {
590 tooltip_copy_text((Area*)tsk);
591 tooltip_update();
592 }
593 panel_refresh = 1;
594 }
595 // Demand attention
596 else if (at == server.atom._NET_WM_STATE) {
597 if (window_is_urgent (win)) {
598 add_urgent(tsk);
599 }
600 if (window_is_skip_taskbar(win)) {
601 remove_task( tsk );
602 panel_refresh = 1;
603 }
604 }
605 else if (at == server.atom.WM_STATE) {
606 // Iconic state
607 int state = (task_active && tsk->win == task_active->win ? TASK_ACTIVE : TASK_NORMAL);
608 if (window_is_iconified(win))
609 state = TASK_ICONIFIED;
610 set_task_state(tsk, state);
611 panel_refresh = 1;
612 }
613 // Window icon changed
614 else if (at == server.atom._NET_WM_ICON) {
615 get_icon(tsk);
616 panel_refresh = 1;
617 }
618 // Window desktop changed
619 else if (at == server.atom._NET_WM_DESKTOP) {
620 int desktop = window_get_desktop (win);
621 //printf(" Window desktop changed %d, %d\n", tsk->desktop, desktop);
622 // bug in windowmaker : send unecessary 'desktop changed' when focus changed
623 if (desktop != tsk->desktop) {
624 remove_task (tsk);
625 tsk = add_task (win);
626 active_task();
627 panel_refresh = 1;
628 }
629 }
630 else if (at == server.atom.WM_HINTS) {
631 XWMHints* wmhints = XGetWMHints(server.dsp, win);
632 if (wmhints && wmhints->flags & XUrgencyHint) {
633 add_urgent(tsk);
634 }
635 XFree(wmhints);
636 }
637
638 if (!server.got_root_win) server.root_win = RootWindow (server.dsp, server.screen);
639 }
640 }
641
642
643 void event_expose (XEvent *e)
644 {
645 Panel *panel;
646 panel = get_panel(e->xany.window);
647 if (!panel) return;
648 // TODO : one panel_refresh per panel ?
649 panel_refresh = 1;
650 }
651
652
653 void event_configure_notify (Window win)
654 {
655 // change in root window (xrandr)
656 if (win == server.root_win) {
657 signal_pending = SIGUSR1;
658 return;
659 }
660
661 // 'win' is a trayer icon
662 TrayWindow *traywin;
663 GSList *l;
664 for (l = systray.list_icons; l ; l = l->next) {
665 traywin = (TrayWindow*)l->data;
666 if (traywin->tray_id == win) {
667 //printf("move tray %d\n", traywin->x);
668 XMoveResizeWindow(server.dsp, traywin->id, traywin->x, traywin->y, traywin->width, traywin->height);
669 XResizeWindow(server.dsp, traywin->tray_id, traywin->width, traywin->height);
670 panel_refresh = 1;
671 return;
672 }
673 }
674
675 // 'win' move in another monitor
676 if (nb_panel == 1) return;
677 Task *tsk = task_get_task (win);
678 if (!tsk) return;
679
680 Panel *p = tsk->area.panel;
681 if (p->monitor != window_get_monitor (win)) {
682 remove_task (tsk);
683 tsk = add_task (win);
684 if (win == window_get_active ()) {
685 set_task_state(tsk, TASK_ACTIVE);
686 task_active = tsk;
687 }
688 panel_refresh = 1;
689 }
690 }
691
692
693 void dnd_message(XClientMessageEvent *e)
694 {
695 Panel *panel = get_panel(e->window);
696 int x, y, mapX, mapY;
697 Window child;
698 x = (e->data.l[2] >> 16) & 0xFFFF;
699 y = e->data.l[2] & 0xFFFF;
700 XTranslateCoordinates(server.dsp, server.root_win, e->window, x, y, &mapX, &mapY, &child);
701 Task* task = click_task(panel, mapX, mapY);
702 if (task) {
703 if (task->desktop != server.desktop )
704 set_desktop (task->desktop);
705 window_action(task, TOGGLE);
706 }
707
708 // send XdndStatus event to get more XdndPosition events
709 XClientMessageEvent se;
710 se.type = ClientMessage;
711 se.window = e->data.l[0];
712 se.message_type = server.atom.XdndStatus;
713 se.format = 32;
714 se.data.l[0] = e->window; // XID of the target window
715 se.data.l[1] = 0; // bit 0: accept drop bit 1: send XdndPosition events if inside rectangle
716 se.data.l[2] = 0; // Rectangle x,y for which no more XdndPosition events
717 se.data.l[3] = (1 << 16) | 1; // Rectangle w,h for which no more XdndPosition events
718 se.data.l[4] = None; // None = drop will not be accepted
719 XSendEvent(server.dsp, e->data.l[0], False, NoEventMask, (XEvent*)&se);
720 }
721
722
723 int main (int argc, char *argv[])
724 {
725 XEvent e;
726 XClientMessageEvent *ev;
727 fd_set fdset;
728 int x11_fd, i;
729 Panel *panel;
730 GSList *it;
731 struct timeval* timeout;
732 int hidden_dnd = 0;
733
734 start:
735 init (argc, argv);
736 init_X11();
737
738 i = 0;
739 if (config_path)
740 i = config_read_file (config_path);
741 else
742 i = config_read ();
743 if (!i) {
744 fprintf(stderr, "usage: tint2 [-c] <config_file>\n");
745 cleanup();
746 exit(1);
747 }
748
749 init_panel();
750 if (snapshot_path) {
751 get_snapshot(snapshot_path);
752 cleanup();
753 exit(0);
754 }
755
756 int damage_event, damage_error;
757 XDamageQueryExtension(server.dsp, &damage_event, &damage_error);
758 x11_fd = ConnectionNumber(server.dsp);
759 XSync(server.dsp, False);
760
761 // sigset_t empty_mask;
762 // sigemptyset(&empty_mask);
763
764 while (1) {
765 if (panel_refresh) {
766 panel_refresh = 0;
767
768 for (i=0 ; i < nb_panel ; i++) {
769 panel = &panel1[i];
770
771 if (panel->is_hidden) {
772 XCopyArea(server.dsp, panel->hidden_pixmap, panel->main_win, server.gc, 0, 0, panel->hidden_width, panel->hidden_height, 0, 0);
773 XSetWindowBackgroundPixmap(server.dsp, panel->main_win, panel->hidden_pixmap);
774 }
775 else {
776 if (panel->temp_pmap) XFreePixmap(server.dsp, panel->temp_pmap);
777 panel->temp_pmap = XCreatePixmap(server.dsp, server.root_win, panel->area.width, panel->area.height, server.depth);
778 rendering(panel);
779 XCopyArea(server.dsp, panel->temp_pmap, panel->main_win, server.gc, 0, 0, panel->area.width, panel->area.height, 0, 0);
780 }
781 }
782 XFlush (server.dsp);
783
784 panel = (Panel*)systray.area.panel;
785 if (refresh_systray && panel && !panel->is_hidden) {
786 refresh_systray = 0;
787 // tint2 doen't draw systray icons. it just redraw background.
788 XSetWindowBackgroundPixmap (server.dsp, panel->main_win, panel->temp_pmap);
789 // force icon's refresh
790 refresh_systray_icon();
791 }
792 }
793
794 // thanks to AngryLlama for the timer
795 // Create a File Description Set containing x11_fd
796 FD_ZERO (&fdset);
797 FD_SET (x11_fd, &fdset);
798 update_next_timeout();
799 if (next_timeout.tv_sec >= 0 && next_timeout.tv_usec >= 0)
800 timeout = &next_timeout;
801 else
802 timeout = 0;
803
804 // Wait for X Event or a Timer
805 if (select(x11_fd+1, &fdset, 0, 0, timeout) > 0) {
806 while (XPending (server.dsp)) {
807 XNextEvent(server.dsp, &e);
808
809 panel = get_panel(e.xany.window);
810 if (panel && panel_autohide) {
811 if (e.type == EnterNotify)
812 autohide_trigger_show(panel);
813 else if (e.type == LeaveNotify)
814 autohide_trigger_hide(panel);
815 if (panel->is_hidden) {
816 if (e.type == ClientMessage && e.xclient.message_type == server.atom.XdndPosition) {
817 hidden_dnd = 1;
818 autohide_show(panel);
819 }
820 else
821 continue; // discard further processing of this event because the panel is not visible yet
822 }
823 else if (hidden_dnd && e.type == ClientMessage && e.xclient.message_type == server.atom.XdndLeave) {
824 hidden_dnd = 0;
825 autohide_hide(panel);
826 }
827 }
828
829 switch (e.type) {
830 case ButtonPress:
831 tooltip_hide(0);
832 event_button_press (&e);
833 break;
834
835 case ButtonRelease:
836 event_button_release(&e);
837 break;
838
839 case MotionNotify: {
840 unsigned int button_mask = Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask;
841 if (e.xmotion.state & button_mask)
842 event_button_motion_notify (&e);
843
844 if (!g_tooltip.enabled) break;
845 Panel* panel = get_panel(e.xmotion.window);
846 Area* area = click_area(panel, e.xmotion.x, e.xmotion.y);
847 if (area->_get_tooltip_text)
848 tooltip_trigger_show(area, panel, &e);
849 else
850 tooltip_trigger_hide();
851 break;
852 }
853
854 case LeaveNotify:
855 if (g_tooltip.enabled)
856 tooltip_trigger_hide();
857 break;
858
859 case Expose:
860 event_expose(&e);
861 break;
862
863 case PropertyNotify:
864 event_property_notify(&e);
865 break;
866
867 case ConfigureNotify:
868 event_configure_notify (e.xconfigure.window);
869 break;
870
871 case ReparentNotify:
872 if (!systray_enabled)
873 break;
874 panel = (Panel*)systray.area.panel;
875 if (e.xany.window == panel->main_win) // reparented to us
876 break;
877 // FIXME: 'reparent to us' badly detected => disabled
878 break;
879 case UnmapNotify:
880 case DestroyNotify:
881 if (e.xany.window == server.composite_manager) {
882 // Stop real_transparency
883 signal_pending = SIGUSR1;
884 break;
885 }
886 if (e.xany.window == g_tooltip.window || !systray.area.on_screen)
887 break;
888 for (it = systray.list_icons; it; it = g_slist_next(it)) {
889 if (((TrayWindow*)it->data)->tray_id == e.xany.window) {
890 remove_icon((TrayWindow*)it->data);
891 break;
892 }
893 }
894 break;
895
896 case ClientMessage:
897 ev = &e.xclient;
898 if (ev->data.l[1] == server.atom._NET_WM_CM_S0) {
899 if (ev->data.l[2] == None)
900 // Stop real_transparency
901 signal_pending = SIGUSR1;
902 else
903 // Start real_transparency
904 signal_pending = SIGUSR1;
905 }
906 if (systray.area.on_screen && e.xclient.message_type == server.atom._NET_SYSTEM_TRAY_OPCODE && e.xclient.format == 32 && e.xclient.window == net_sel_win) {
907 net_message(&e.xclient);
908 }
909 else if (e.xclient.message_type == server.atom.XdndPosition) {
910 dnd_message(&e.xclient);
911 }
912 break;
913
914 default:
915 if (e.type == XDamageNotify+damage_event) {
916 // union needed to avoid strict-aliasing warnings by gcc
917 union { XEvent e; XDamageNotifyEvent de; } event_union = {.e=e};
918 TrayWindow *traywin;
919 GSList *l;
920 XDamageNotifyEvent* de = &event_union.de;
921 for (l = systray.list_icons; l ; l = l->next) {
922 traywin = (TrayWindow*)l->data;
923 if ( traywin->id == de->drawable ) {
924 systray_render_icon(traywin);
925 break;
926 }
927 }
928 }
929 }
930 }
931 }
932
933 callback_timeout_expired();
934
935 if (signal_pending) {
936 cleanup();
937 if (signal_pending == SIGUSR1) {
938 // restart tint2
939 // SIGUSR1 used when : user's signal, composite manager stop/start or xrandr
940 FD_CLR (x11_fd, &fdset); // not sure if needed
941 goto start;
942 }
943 else {
944 // SIGINT, SIGTERM, SIGHUP
945 return 0;
946 }
947 }
948 }
949 }
950
951
This page took 0.067936 seconds and 3 git commands to generate.