]> Dogcows Code - chaz/tint2/blob - src/tint.c
big change : panel_monitor = all will draw one panel per monitor, panel_size accept...
[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 <sys/time.h>
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <X11/Xutil.h>
28 #include <X11/Xatom.h>
29 #include <X11/Xlocale.h>
30 #include <Imlib2.h>
31 #include <signal.h>
32
33 #include "server.h"
34 #include "window.h"
35 #include "config.h"
36 #include "task.h"
37 #include "taskbar.h"
38 #include "panel.h"
39 #include "docker.h"
40 #include "net.h"
41 #include "kde.h"
42
43
44 void signal_handler(int sig)
45 {
46 // signal handler is light as it should be
47 signal_pending = sig;
48 }
49
50
51 void init ()
52 {
53 // Set signal handler
54 signal(SIGUSR1, signal_handler);
55 signal(SIGINT, signal_handler);
56 signal(SIGTERM, signal_handler);
57
58 // set global data
59 memset(&server, 0, sizeof(Server_global));
60
61 server.dsp = XOpenDisplay (NULL);
62 if (!server.dsp) {
63 fprintf(stderr, "Could not open display.\n");
64 exit(0);
65 }
66 server_init_atoms ();
67 server.screen = DefaultScreen (server.dsp);
68 server.root_win = RootWindow(server.dsp, server.screen);
69 server.depth = DefaultDepth (server.dsp, server.screen);
70 server.visual = DefaultVisual (server.dsp, server.screen);
71 server.desktop = server_get_current_desktop ();
72 XGCValues gcv;
73 server.gc = XCreateGC (server.dsp, server.root_win, (unsigned long)0, &gcv) ;
74
75 XSetErrorHandler ((XErrorHandler) server_catch_error);
76
77 // init systray
78 //display = server.dsp;
79 //root = RootWindow(display, DefaultScreen(display));
80 //create_main_window();
81 //kde_init();
82 //net_init();
83 //printf("ici 4\n");
84
85 imlib_context_set_display (server.dsp);
86 imlib_context_set_visual (server.visual);
87 imlib_context_set_colormap (DefaultColormap (server.dsp, server.screen));
88
89 /* Catch events */
90 XSelectInput (server.dsp, server.root_win, PropertyChangeMask|StructureNotifyMask);
91
92 setlocale (LC_ALL, "");
93 }
94
95
96 void cleanup()
97 {
98 cleanup_panel();
99
100 if (time1_font_desc) pango_font_description_free(time1_font_desc);
101 if (time2_font_desc) pango_font_description_free(time2_font_desc);
102 if (time1_format) g_free(time1_format);
103 if (time2_format) g_free(time2_format);
104
105 if (server.monitor) free(server.monitor);
106 XFreeGC(server.dsp, server.gc);
107 XCloseDisplay(server.dsp);
108 }
109
110
111 void window_action (Task *tsk, int action)
112 {
113 switch (action) {
114 case CLOSE:
115 set_close (tsk->win);
116 break;
117 case TOGGLE:
118 set_active(tsk->win);
119 break;
120 case ICONIFY:
121 XIconifyWindow (server.dsp, tsk->win, server.screen);
122 break;
123 case TOGGLE_ICONIFY:
124 if (tsk == task_active) XIconifyWindow (server.dsp, tsk->win, server.screen);
125 else set_active (tsk->win);
126 break;
127 case SHADE:
128 window_toggle_shade (tsk->win);
129 break;
130 }
131 }
132
133
134 void event_button_press (XEvent *e)
135 {
136 Panel *panel = get_panel(e->xany.window);
137 if (!panel) return;
138
139 if (panel_mode != MULTI_DESKTOP) {
140 // drag and drop disabled
141 //XLowerWindow (server.dsp, panel.main_win);
142 return;
143 }
144
145 GSList *l0;
146 Taskbar *tskbar;
147 int x = e->xbutton.x;
148 int y = e->xbutton.y;
149 for (l0 = panel->area.list; l0 ; l0 = l0->next) {
150 tskbar = l0->data;
151 if (x >= tskbar->area.posx && x <= (tskbar->area.posx + tskbar->area.width))
152 break;
153 }
154
155 if (l0) {
156 Task *tsk;
157 for (l0 = tskbar->area.list; l0 ; l0 = l0->next) {
158 tsk = l0->data;
159 if (x >= tsk->area.posx && x <= (tsk->area.posx + tsk->area.width)) {
160 task_drag = tsk;
161 break;
162 }
163 }
164 }
165
166 //XLowerWindow (server.dsp, panel.main_win);
167 }
168
169
170 void event_button_release (XEvent *e)
171 {
172 // TODO: convert event_button_press(int x, int y) to area->event_button_press()
173
174 Panel *panel = get_panel(e->xany.window);
175 if (!panel) return;
176
177 int action = TOGGLE_ICONIFY;
178 int x = e->xbutton.x;
179 int y = e->xbutton.y;
180 switch (e->xbutton.button) {
181 case 2:
182 action = mouse_middle;
183 break;
184 case 3:
185 action = mouse_right;
186 break;
187 case 4:
188 action = mouse_scroll_up;
189 break;
190 case 5:
191 action = mouse_scroll_down;
192 break;
193 }
194
195 // search taskbar
196 Taskbar *tskbar;
197 GSList *l0;
198 for (l0 = panel->area.list; l0 ; l0 = l0->next) {
199 tskbar = l0->data;
200 if (x >= tskbar->area.posx && x <= (tskbar->area.posx + tskbar->area.width))
201 goto suite;
202 }
203
204 // TODO: check better solution to keep window below
205 //XLowerWindow (server.dsp, panel.main_win);
206 task_drag = 0;
207 return;
208
209 suite:
210 // drag and drop task
211 if (task_drag) {
212 if (tskbar != task_drag->area.parent && action == TOGGLE_ICONIFY) {
213 if (task_drag->desktop != ALLDESKTOP && panel_mode == MULTI_DESKTOP) {
214 windows_set_desktop(task_drag->win, tskbar->desktop);
215 if (tskbar->desktop == server.desktop)
216 set_active(task_drag->win);
217 task_drag = 0;
218 }
219 return;
220 }
221 else task_drag = 0;
222 }
223
224 // switch desktop
225 if (panel_mode == MULTI_DESKTOP)
226 if (tskbar->desktop != server.desktop && action != CLOSE)
227 set_desktop (tskbar->desktop);
228
229 // action on task
230 Task *tsk;
231 GSList *l;
232 for (l = tskbar->area.list ; l ; l = l->next) {
233 tsk = l->data;
234 if (x >= tsk->area.posx && x <= (tsk->area.posx + tsk->area.width)) {
235 window_action (tsk, action);
236 break;
237 }
238 }
239
240 // to keep window below
241 //XLowerWindow (server.dsp, panel.main_win);
242 }
243
244
245 void event_property_notify (Window win, Atom at)
246 {
247 int i, j;
248 Task *tsk;
249
250 if (win == server.root_win) {
251 if (!server.got_root_win) {
252 XSelectInput (server.dsp, server.root_win, PropertyChangeMask|StructureNotifyMask);
253 server.got_root_win = 1;
254 }
255
256 /* Change number of desktops */
257 else if (at == server.atom._NET_NUMBER_OF_DESKTOPS) {
258 server.nb_desktop = server_get_number_of_desktop ();
259 cleanup_taskbar();
260 init_taskbar();
261 visible_object();
262 task_refresh_tasklist();
263 panel_refresh = 1;
264 }
265 /* Change desktop */
266 else if (at == server.atom._NET_CURRENT_DESKTOP) {
267 server.desktop = server_get_current_desktop ();
268 if (panel_mode != MULTI_DESKTOP) {
269 visible_object();
270 }
271 }
272 /* Window list */
273 else if (at == server.atom._NET_CLIENT_LIST) {
274 task_refresh_tasklist();
275 panel_refresh = 1;
276 }
277 /* Change active */
278 else if (at == server.atom._NET_ACTIVE_WINDOW) {
279 GSList *l0;
280 if (task_active) {
281 for (i=0 ; i < nb_panel ; i++) {
282 for (j=0 ; j < panel1[i].nb_desktop ; j++) {
283 for (l0 = panel1[i].taskbar[j].area.list; l0 ; l0 = l0->next) {
284 tsk = l0->data;
285 tsk->area.is_active = 0;
286 }
287 }
288 }
289 task_active = 0;
290 }
291 Window w1 = window_get_active ();
292 Task *t = task_get_task(w1);
293 if (!t) {
294 Window w2;
295 if (XGetTransientForHint(server.dsp, w1, &w2) != 0)
296 if (w2) t = task_get_task(w2);
297 }
298 if (t) {
299 for (i=0 ; i < nb_panel ; i++) {
300 for (j=0 ; j < panel1[i].nb_desktop ; j++) {
301 for (l0 = panel1[i].taskbar[j].area.list; l0 ; l0 = l0->next) {
302 tsk = l0->data;
303 if (tsk->win == t->win) {
304 tsk->area.is_active = 1;
305 //printf("active monitor %d, task %s\n", panel1[i].monitor, tsk->title);
306 }
307 }
308 }
309 }
310 task_active = t;
311 }
312 panel_refresh = 1;
313 }
314 /* Wallpaper changed */
315 else if (at == server.atom._XROOTPMAP_ID) {
316 for (i=0 ; i < nb_panel ; i++) {
317 set_panel_background(&panel1[i]);
318 }
319 panel_refresh = 1;
320 }
321 }
322 else {
323 tsk = task_get_task (win);
324 if (!tsk) return;
325 //printf("atom root_win = %s, %s\n", XGetAtomName(server.dsp, at), tsk->title);
326
327 /* Window title changed */
328 if (at == server.atom._NET_WM_VISIBLE_NAME || at == server.atom._NET_WM_NAME || at == server.atom.WM_NAME) {
329 Task *tsk2;
330 GSList *l0;
331 get_title(tsk);
332 // changed other tsk->title
333 for (i=0 ; i < nb_panel ; i++) {
334 for (j=0 ; j < panel1[i].nb_desktop ; j++) {
335 for (l0 = panel1[i].taskbar[j].area.list; l0 ; l0 = l0->next) {
336 tsk2 = l0->data;
337 if (tsk->win == tsk2->win && tsk != tsk2) {
338 tsk2->title = tsk->title;
339 tsk2->area.redraw = 1;
340 }
341 }
342 }
343 }
344 panel_refresh = 1;
345 }
346 /* Iconic state */
347 else if (at == server.atom.WM_STATE) {
348 if (window_is_iconified (win))
349 if (task_active) {
350 if (task_active->win == tsk->win) {
351 Task *tsk2;
352 GSList *l0;
353 for (i=0 ; i < nb_panel ; i++) {
354 for (j=0 ; j < panel1[i].nb_desktop ; j++) {
355 for (l0 = panel1[i].taskbar[j].area.list; l0 ; l0 = l0->next) {
356 tsk2 = l0->data;
357 tsk2->area.is_active = 0;
358 }
359 }
360 }
361 task_active = 0;
362 }
363 }
364 }
365 /* Window icon changed */
366 else if (at == server.atom._NET_WM_ICON) {
367 get_icon(tsk);
368 Task *tsk2;
369 GSList *l0;
370 for (i=0 ; i < nb_panel ; i++) {
371 for (j=0 ; j < panel1[i].nb_desktop ; j++) {
372 for (l0 = panel1[i].taskbar[j].area.list; l0 ; l0 = l0->next) {
373 tsk2 = l0->data;
374 if (tsk->win == tsk2->win && tsk != tsk2) {
375 tsk2->icon_width = tsk->icon_width;
376 tsk2->icon_height = tsk->icon_height;
377 tsk2->icon_data = tsk->icon_data;
378 tsk2->area.redraw = 1;
379 }
380 }
381 }
382 }
383 panel_refresh = 1;
384 }
385 /* Window desktop changed */
386 else if (at == server.atom._NET_WM_DESKTOP) {
387 remove_task (tsk);
388 add_task (win);
389 panel_refresh = 1;
390 }
391
392 if (!server.got_root_win) server.root_win = RootWindow (server.dsp, server.screen);
393 }
394 }
395
396
397 void event_configure_notify (Window win)
398 {
399 if (panel_mode != SINGLE_MONITOR) return;
400 if (server.nb_monitor == 1) return;
401
402 Task *tsk = task_get_task (win);
403 if (!tsk) return;
404
405 Panel *p = tsk->area.panel;
406 if (p->monitor != window_get_monitor (win)) {
407 // task on another monitor
408 remove_task (tsk);
409 add_task (win);
410 panel_refresh = 1;
411 }
412 }
413
414
415 void event_timer()
416 {
417 struct timeval stv;
418
419 if (!time1_format) return;
420
421 if (gettimeofday(&stv, 0)) return;
422
423 if (abs(stv.tv_sec - time_clock.tv_sec) < time_precision) return;
424
425 // update clock
426 time_clock.tv_sec = stv.tv_sec;
427 time_clock.tv_sec -= time_clock.tv_sec % time_precision;
428
429 int i;
430 for (i=0 ; i < nb_panel ; i++) {
431 panel1[i].clock.area.redraw = 1;
432 }
433 panel_refresh = 1;
434 }
435
436
437 int main (int argc, char *argv[])
438 {
439 XEvent e;
440 fd_set fd;
441 int x11_fd, i, c;
442 struct timeval tv;
443 Panel *panel;
444
445 c = getopt (argc, argv, "c:");
446 init ();
447
448 load_config:
449 i = 0;
450 init_config();
451 if (c != -1)
452 i = config_read_file (optarg);
453 if (!i)
454 i = config_read ();
455 if (!i) {
456 fprintf(stderr, "usage: tint2 [-c] <config_file>\n");
457 cleanup();
458 exit(1);
459 }
460 config_finish();
461
462 // BUG: refresh(clock) is needed here, but 'on the paper' it's not necessary.
463 for (i=0 ; i < nb_panel ; i++) {
464 refresh(&panel1[i].clock.area);
465 }
466
467 x11_fd = ConnectionNumber(server.dsp);
468 XSync(server.dsp, False);
469
470 while (1) {
471 // thanks to AngryLlama for the timer
472 // Create a File Description Set containing x11_fd
473 FD_ZERO (&fd);
474 FD_SET (x11_fd, &fd);
475
476 tv.tv_usec = 500000;
477 tv.tv_sec = 0;
478
479 // Wait for X Event or a Timer
480 if (select(x11_fd+1, &fd, 0, 0, &tv)) {
481 while (XPending (server.dsp)) {
482 XNextEvent(server.dsp, &e);
483
484 switch (e.type) {
485 case ButtonPress:
486 //printf("ButtonPress %lx\n", e.xproperty.window);
487 if (e.xbutton.button == 1) event_button_press (&e);
488 break;
489
490 case ButtonRelease:
491 event_button_release (&e);
492 break;
493
494 case Expose:
495 panel = get_panel(e.xany.window);
496 if (!panel) break;
497 //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);
498 //XCopyArea (server.dsp, server.pmap, panel.main_win, server.gc, panel.area.paddingxlr, 0, panel.area.width-(2*panel.area.paddingxlr), panel.area.height, 0, 0);
499 XCopyArea (server.dsp, panel->root_pmap, panel->main_win, server.gc, 0, 0, panel->area.width, panel->area.height, 0, 0);
500 break;
501
502 case PropertyNotify:
503 //printf("PropertyNotify %lx\n", e.xproperty.window);
504 event_property_notify (e.xproperty.window, e.xproperty.atom);
505 break;
506
507 case ConfigureNotify:
508 if (e.xconfigure.window == server.root_win)
509 goto load_config;
510 else
511 event_configure_notify (e.xconfigure.window);
512 break;
513 }
514 }
515 }
516 else event_timer();
517
518 switch (signal_pending) {
519 case SIGUSR1:
520 goto load_config;
521 case SIGINT:
522 case SIGTERM:
523 cleanup ();
524 return 0;
525 }
526
527 if (panel_refresh) {
528 for (i=0 ; i < nb_panel ; i++)
529 visual_refresh(&panel1[i]);
530 XFlush (server.dsp);
531 panel_refresh = 0;
532 }
533 }
534 }
535
536
This page took 0.059106 seconds and 4 git commands to generate.