]> Dogcows Code - chaz/tint2/blob - src/taskbar/taskbar.c
panel_items : fixed segfault (panel without clock, change number desktop)
[chaz/tint2] / src / taskbar / taskbar.c
1 /**************************************************************************
2 *
3 * Tint2 : taskbar
4 *
5 * Copyright (C) 2008 thierry lorthiois (lorthiois@bbsoft.fr)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version 2
9 * as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **************************************************************************/
19
20 #include <X11/Xlib.h>
21 #include <X11/Xutil.h>
22 #include <X11/Xatom.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <glib.h>
27 #include <Imlib2.h>
28
29 #include "task.h"
30 #include "taskbar.h"
31 #include "server.h"
32 #include "window.h"
33 #include "panel.h"
34
35
36 /* win_to_task_table holds for every Window an array of tasks. Usually the array contains only one
37 element. However for omnipresent windows (windows which are visible in every taskbar) the array
38 contains to every Task* on each panel a pointer (i.e. GPtrArray.len == server.nb_desktop)
39 */
40 GHashTable* win_to_task_table;
41
42 Task *task_active;
43 Task *task_drag;
44
45 guint win_hash(gconstpointer key) { return (guint)*((Window*)key); }
46 gboolean win_compare(gconstpointer a, gconstpointer b) { return (*((Window*)a) == *((Window*)b)); }
47 void free_ptr_array(gpointer data) { g_ptr_array_free(data, 1); }
48
49
50 void default_taskbar()
51 {
52 win_to_task_table = 0;
53 urgent_timeout = 0;
54 urgent_list = 0;
55 }
56
57 void cleanup_taskbar()
58 {
59 Panel *panel;
60 Taskbar *tskbar;
61 int i, j;
62
63 if (win_to_task_table) g_hash_table_foreach(win_to_task_table, taskbar_remove_task, 0);
64 for (i=0 ; i < nb_panel ; i++) {
65 panel = &panel1[i];
66 for (j=0 ; j < panel->nb_desktop ; j++) {
67 tskbar = &panel->taskbar[j];
68 free_area (&tskbar->area);
69 // remove taskbar from the panel
70 panel->area.list = g_slist_remove(panel->area.list, tskbar);
71 }
72 if (panel->taskbar) {
73 free(panel->taskbar);
74 panel->taskbar = 0;
75 }
76 }
77
78 if (win_to_task_table) {
79 g_hash_table_destroy(win_to_task_table);
80 win_to_task_table = 0;
81 }
82 }
83
84
85 void init_taskbar()
86 {
87 if (win_to_task_table == 0)
88 win_to_task_table = g_hash_table_new_full(win_hash, win_compare, free, free_ptr_array);
89
90 task_active = 0;
91 task_drag = 0;
92 }
93
94
95 void init_taskbar_panel(void *p)
96 {
97 Panel *panel =(Panel*)p;
98 int j;
99
100 if (panel->g_taskbar.bg == 0) {
101 panel->g_taskbar.bg = &g_array_index(backgrounds, Background, 0);
102 panel->g_taskbar.area.bg = panel->g_taskbar.bg;
103 }
104 if (panel->g_taskbar.bg_active == 0)
105 panel->g_taskbar.bg_active = panel->g_taskbar.bg;
106 if (panel->g_task.area.bg == 0)
107 panel->g_task.area.bg = &g_array_index(backgrounds, Background, 0);
108
109 // taskbar
110 panel->g_taskbar.area.size_mode = SIZE_BY_LAYOUT;
111 panel->g_taskbar.area._resize = resize_taskbar;
112 panel->g_taskbar.area.redraw = 1;
113 panel->g_taskbar.area.on_screen = 1;
114 if (panel_horizontal) {
115 panel->g_taskbar.area.posy = panel->area.bg->border.width + panel->area.paddingy;
116 panel->g_taskbar.area.height = panel->area.height - (2 * panel->g_taskbar.area.posy);
117 }
118 else {
119 panel->g_taskbar.area.posx = panel->area.bg->border.width + panel->area.paddingy;
120 panel->g_taskbar.area.width = panel->area.width - (2 * panel->g_taskbar.area.posx);
121 }
122
123 // task
124 panel->g_task.area.size_mode = SIZE_BY_LAYOUT;
125 panel->g_task.area._draw_foreground = draw_task;
126 panel->g_task.area.redraw = 1;
127 panel->g_task.area.on_screen = 1;
128 if ((panel->g_task.config_asb_mask & (1<<TASK_NORMAL)) == 0) {
129 panel->g_task.alpha[TASK_NORMAL] = 100;
130 panel->g_task.saturation[TASK_NORMAL] = 0;
131 panel->g_task.brightness[TASK_NORMAL] = 0;
132 }
133 if ((panel->g_task.config_asb_mask & (1<<TASK_ACTIVE)) == 0) {
134 panel->g_task.alpha[TASK_ACTIVE] = panel->g_task.alpha[TASK_NORMAL];
135 panel->g_task.saturation[TASK_ACTIVE] = panel->g_task.saturation[TASK_NORMAL];
136 panel->g_task.brightness[TASK_ACTIVE] = panel->g_task.brightness[TASK_NORMAL];
137 }
138 if ((panel->g_task.config_asb_mask & (1<<TASK_ICONIFIED)) == 0) {
139 panel->g_task.alpha[TASK_ICONIFIED] = panel->g_task.alpha[TASK_NORMAL];
140 panel->g_task.saturation[TASK_ICONIFIED] = panel->g_task.saturation[TASK_NORMAL];
141 panel->g_task.brightness[TASK_ICONIFIED] = panel->g_task.brightness[TASK_NORMAL];
142 }
143 if ((panel->g_task.config_asb_mask & (1<<TASK_URGENT)) == 0) {
144 panel->g_task.alpha[TASK_URGENT] = panel->g_task.alpha[TASK_ACTIVE];
145 panel->g_task.saturation[TASK_URGENT] = panel->g_task.saturation[TASK_ACTIVE];
146 panel->g_task.brightness[TASK_URGENT] = panel->g_task.brightness[TASK_ACTIVE];
147 }
148 if ((panel->g_task.config_font_mask & (1<<TASK_NORMAL)) == 0) panel->g_task.font[TASK_NORMAL] = (Color){{0, 0, 0}, 0};
149 if ((panel->g_task.config_font_mask & (1<<TASK_ACTIVE)) == 0) panel->g_task.font[TASK_ACTIVE] = panel->g_task.font[TASK_NORMAL];
150 if ((panel->g_task.config_font_mask & (1<<TASK_ICONIFIED)) == 0) panel->g_task.font[TASK_ICONIFIED] = panel->g_task.font[TASK_NORMAL];
151 if ((panel->g_task.config_font_mask & (1<<TASK_URGENT)) == 0) panel->g_task.font[TASK_URGENT] = panel->g_task.font[TASK_ACTIVE];
152 if ((panel->g_task.config_font_mask & (1<<TASK_NORMAL)) == 0) panel->g_task.background[TASK_NORMAL] = &g_array_index(backgrounds, Background, 0);
153 if ((panel->g_task.config_background_mask & (1<<TASK_ACTIVE)) == 0) panel->g_task.background[TASK_ACTIVE] = panel->g_task.background[TASK_NORMAL];
154 if ((panel->g_task.config_background_mask & (1<<TASK_ICONIFIED)) == 0) panel->g_task.background[TASK_ICONIFIED] = panel->g_task.background[TASK_NORMAL];
155 if ((panel->g_task.config_background_mask & (1<<TASK_URGENT)) == 0) panel->g_task.background[TASK_URGENT] = panel->g_task.background[TASK_ACTIVE];
156
157 if (panel_horizontal) {
158 panel->g_task.area.posy = panel->g_taskbar.area.posy + panel->g_taskbar.bg->border.width + panel->g_taskbar.area.paddingy;
159 panel->g_task.area.height = panel->area.height - (2 * panel->g_task.area.posy);
160 }
161 else {
162 panel->g_task.area.posx = panel->g_taskbar.area.posx + panel->g_taskbar.bg->border.width + panel->g_taskbar.area.paddingy;
163 panel->g_task.area.width = panel->area.width - (2 * panel->g_task.area.posx);
164 panel->g_task.area.height = panel->g_task.maximum_height;
165 }
166
167 for (j=0; j<TASK_STATE_COUNT; ++j) {
168 if (panel->g_task.background[j]->border.rounded > panel->g_task.area.height/2) {
169 printf("task%sbackground_id has a too large rounded value. Please fix your tint2rc\n", j==0 ? "_" : j==1 ? "_active_" : j==2 ? "_iconified_" : "_urgent_");
170 g_array_append_val(backgrounds, *panel->g_task.background[j]);
171 panel->g_task.background[j] = &g_array_index(backgrounds, Background, backgrounds->len-1);
172 panel->g_task.background[j]->border.rounded = panel->g_task.area.height/2;
173 }
174 }
175
176 // compute vertical position : text and icon
177 int height_ink, height;
178 get_text_size(panel->g_task.font_desc, &height_ink, &height, panel->area.height, "TAjpg", 5);
179
180 if (!panel->g_task.maximum_width && panel_horizontal)
181 panel->g_task.maximum_width = server.monitor[panel->monitor].width;
182
183 panel->g_task.text_posx = panel->g_task.background[0]->border.width + panel->g_task.area.paddingxlr;
184 panel->g_task.text_height = panel->g_task.area.height - (2 * panel->g_task.area.paddingy);
185 if (panel->g_task.icon) {
186 panel->g_task.icon_size1 = panel->g_task.area.height - (2 * panel->g_task.area.paddingy);
187 panel->g_task.text_posx += panel->g_task.icon_size1;
188 panel->g_task.icon_posy = (panel->g_task.area.height - panel->g_task.icon_size1) / 2;
189 }
190 //printf("monitor %d, task_maximum_width %d\n", panel->monitor, panel->g_task.maximum_width);
191
192 Taskbar *tskbar;
193 panel->nb_desktop = server.nb_desktop;
194 panel->taskbar = calloc(server.nb_desktop, sizeof(Taskbar));
195 for (j=0 ; j < panel->nb_desktop ; j++) {
196 tskbar = &panel->taskbar[j];
197 memcpy(&tskbar->area, &panel->g_taskbar, sizeof(Area));
198 tskbar->desktop = j;
199 if (j == server.desktop && panel->g_taskbar.use_active)
200 tskbar->area.bg = panel->g_taskbar.bg_active;
201 }
202 }
203
204
205 void taskbar_remove_task(gpointer key, gpointer value, gpointer user_data)
206 {
207 remove_task(task_get_task(*(Window*)key));
208 }
209
210
211 Task *task_get_task (Window win)
212 {
213 GPtrArray* task_group = task_get_tasks(win);
214 if (task_group)
215 return g_ptr_array_index(task_group, 0);
216 else
217 return 0;
218 }
219
220
221 GPtrArray* task_get_tasks(Window win)
222 {
223 if (win_to_task_table)
224 return g_hash_table_lookup(win_to_task_table, &win);
225 else
226 return 0;
227 }
228
229
230 void task_refresh_tasklist ()
231 {
232 Window *win;
233 int num_results, i;
234
235 win = server_get_property (server.root_win, server.atom._NET_CLIENT_LIST, XA_WINDOW, &num_results);
236 if (!win) return;
237
238 GList* win_list = g_hash_table_get_keys(win_to_task_table);
239 GList* it;
240 for (it=win_list; it; it=it->next) {
241 for (i = 0; i < num_results; i++)
242 if (*((Window*)it->data) == win[i])
243 break;
244 if (i == num_results)
245 taskbar_remove_task(it->data, 0, 0);
246 }
247 g_list_free(win_list);
248
249 // Add any new
250 for (i = 0; i < num_results; i++)
251 if (!task_get_task (win[i]))
252 add_task (win[i]);
253
254 XFree (win);
255 }
256
257
258 int resize_taskbar(void *obj)
259 {
260 Taskbar *taskbar = (Taskbar*)obj;
261 Panel *panel = (Panel*)taskbar->area.panel;
262 Task *tsk;
263 GSList *l;
264 int task_count, border_width;
265
266 //printf("resize_taskbar : posx et width des taches\n");
267 taskbar->area.redraw = 1;
268
269 border_width = taskbar->area.bg->border.width;
270
271 if (panel_horizontal) {
272 int pixel_width, modulo_width=0;
273 int taskbar_width;
274
275 // new task width for 'desktop'
276 task_count = g_slist_length(taskbar->area.list);
277 if (!task_count) pixel_width = panel->g_task.maximum_width;
278 else {
279 taskbar_width = taskbar->area.width - (2 * border_width) - (2 * panel->g_taskbar.area.paddingxlr);
280 if (task_count>1) taskbar_width -= ((task_count-1) * panel->g_taskbar.area.paddingx);
281
282 pixel_width = taskbar_width / task_count;
283 if (pixel_width > panel->g_task.maximum_width)
284 pixel_width = panel->g_task.maximum_width;
285 else
286 modulo_width = taskbar_width % task_count;
287 }
288
289 taskbar->task_width = pixel_width;
290 taskbar->task_modulo = modulo_width;
291 taskbar->text_width = pixel_width - panel->g_task.text_posx - panel->g_task.area.bg->border.width - panel->g_task.area.paddingx;
292
293 // change pos_x and width for all tasks
294 for (l = taskbar->area.list; l ; l = l->next) {
295 tsk = l->data;
296 if (!tsk->area.on_screen) continue;
297 set_task_redraw(tsk); // always redraw task, because the background could have changed (taskbar_active_id)
298 tsk->area.width = pixel_width;
299 // TODO : move later (when posx is known)
300 // long value[] = { panel->posx+x, panel->posy, pixel_width, panel->area.height };
301 // XChangeProperty (server.dsp, tsk->win, server.atom._NET_WM_ICON_GEOMETRY, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)value, 4);
302
303 if (modulo_width) {
304 tsk->area.width++;
305 modulo_width--;
306 }
307 }
308 }
309 else {
310 int pixel_height, modulo_height=0;
311 int taskbar_height;
312
313 // new task width for 'desktop'
314 task_count = g_slist_length(taskbar->area.list);
315 if (!task_count) pixel_height = panel->g_task.maximum_height;
316 else {
317 taskbar_height = taskbar->area.height - (2 * border_width) - (2 * panel->g_taskbar.area.paddingxlr);
318 if (task_count>1) taskbar_height -= ((task_count-1) * panel->g_taskbar.area.paddingx);
319
320 pixel_height = taskbar_height / task_count;
321 if (pixel_height > panel->g_task.maximum_height)
322 pixel_height = panel->g_task.maximum_height;
323 else
324 modulo_height = taskbar_height % task_count;
325 }
326
327 taskbar->task_width = pixel_height;
328 taskbar->task_modulo = modulo_height;
329 taskbar->text_width = taskbar->area.width - (2 * panel->g_taskbar.area.paddingy) - panel->g_task.text_posx - panel->g_task.area.bg->border.width - panel->g_task.area.paddingx;
330
331 // change pos_y and height for all tasks
332 for (l = taskbar->area.list; l ; l = l->next) {
333 tsk = l->data;
334 if (!tsk->area.on_screen) continue;
335 set_task_redraw(tsk); // always redraw task, because the background could have changed (taskbar_active_id)
336 tsk->area.height = pixel_height;
337 // TODO : move later (when posy is known)
338 // long value[] = { panel->posx, panel->posy+y, panel->area.width, pixel_height };
339 // XChangeProperty (server.dsp, tsk->win, server.atom._NET_WM_ICON_GEOMETRY, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)value, 4);
340
341 if (modulo_height) {
342 tsk->area.height++;
343 modulo_height--;
344 }
345 }
346 }
347 return 0;
348 }
349
This page took 0.052823 seconds and 4 git commands to generate.