]> Dogcows Code - chaz/tint2/blob - src/taskbar/taskbar.c
order of panel items : partial implementation. expect crash/instability
[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 void init_taskbar()
50 {
51 Panel *panel;
52 int i, j;
53
54 if (win_to_task_table == 0)
55 win_to_task_table = g_hash_table_new_full(win_hash, win_compare, free, free_ptr_array);
56
57 task_active = 0;
58 task_drag = 0;
59
60 for (i=0 ; i < nb_panel ; i++) {
61 panel = &panel1[i];
62
63 if (panel->g_taskbar.bg == 0) {
64 panel->g_taskbar.bg = &g_array_index(backgrounds, Background, 0);
65 panel->g_taskbar.area.bg = panel->g_taskbar.bg;
66 }
67 if (panel->g_taskbar.bg_active == 0)
68 panel->g_taskbar.bg_active = panel->g_taskbar.bg;
69 if (panel->g_task.area.bg == 0)
70 panel->g_task.area.bg = &g_array_index(backgrounds, Background, 0);
71
72 // taskbar
73 panel->g_taskbar.area.size_mode = SIZE_BY_LAYOUT;
74 panel->g_taskbar.area._resize = resize_taskbar;
75 panel->g_taskbar.area.redraw = 1;
76 panel->g_taskbar.area.on_screen = 1;
77 if (panel_horizontal) {
78 panel->g_taskbar.area.posy = panel->area.bg->border.width + panel->area.paddingy;
79 panel->g_taskbar.area.height = panel->area.height - (2 * panel->g_taskbar.area.posy);
80 }
81 else {
82 panel->g_taskbar.area.posx = panel->area.bg->border.width + panel->area.paddingy;
83 panel->g_taskbar.area.width = panel->area.width - (2 * panel->g_taskbar.area.posx);
84 }
85
86 // task
87 panel->g_task.area.size_mode = SIZE_BY_LAYOUT;
88 panel->g_task.area._draw_foreground = draw_task;
89 panel->g_task.area.redraw = 1;
90 panel->g_task.area.on_screen = 1;
91 if ((panel->g_task.config_asb_mask & (1<<TASK_NORMAL)) == 0) {
92 panel->g_task.alpha[TASK_NORMAL] = 100;
93 panel->g_task.saturation[TASK_NORMAL] = 0;
94 panel->g_task.brightness[TASK_NORMAL] = 0;
95 }
96 if ((panel->g_task.config_asb_mask & (1<<TASK_ACTIVE)) == 0) {
97 panel->g_task.alpha[TASK_ACTIVE] = panel->g_task.alpha[TASK_NORMAL];
98 panel->g_task.saturation[TASK_ACTIVE] = panel->g_task.saturation[TASK_NORMAL];
99 panel->g_task.brightness[TASK_ACTIVE] = panel->g_task.brightness[TASK_NORMAL];
100 }
101 if ((panel->g_task.config_asb_mask & (1<<TASK_ICONIFIED)) == 0) {
102 panel->g_task.alpha[TASK_ICONIFIED] = panel->g_task.alpha[TASK_NORMAL];
103 panel->g_task.saturation[TASK_ICONIFIED] = panel->g_task.saturation[TASK_NORMAL];
104 panel->g_task.brightness[TASK_ICONIFIED] = panel->g_task.brightness[TASK_NORMAL];
105 }
106 if ((panel->g_task.config_asb_mask & (1<<TASK_URGENT)) == 0) {
107 panel->g_task.alpha[TASK_URGENT] = panel->g_task.alpha[TASK_ACTIVE];
108 panel->g_task.saturation[TASK_URGENT] = panel->g_task.saturation[TASK_ACTIVE];
109 panel->g_task.brightness[TASK_URGENT] = panel->g_task.brightness[TASK_ACTIVE];
110 }
111 if ((panel->g_task.config_font_mask & (1<<TASK_NORMAL)) == 0) panel->g_task.font[TASK_NORMAL] = (Color){{0, 0, 0}, 0};
112 if ((panel->g_task.config_font_mask & (1<<TASK_ACTIVE)) == 0) panel->g_task.font[TASK_ACTIVE] = panel->g_task.font[TASK_NORMAL];
113 if ((panel->g_task.config_font_mask & (1<<TASK_ICONIFIED)) == 0) panel->g_task.font[TASK_ICONIFIED] = panel->g_task.font[TASK_NORMAL];
114 if ((panel->g_task.config_font_mask & (1<<TASK_URGENT)) == 0) panel->g_task.font[TASK_URGENT] = panel->g_task.font[TASK_ACTIVE];
115 if ((panel->g_task.config_font_mask & (1<<TASK_NORMAL)) == 0) panel->g_task.background[TASK_NORMAL] = &g_array_index(backgrounds, Background, 0);
116 if ((panel->g_task.config_background_mask & (1<<TASK_ACTIVE)) == 0) panel->g_task.background[TASK_ACTIVE] = panel->g_task.background[TASK_NORMAL];
117 if ((panel->g_task.config_background_mask & (1<<TASK_ICONIFIED)) == 0) panel->g_task.background[TASK_ICONIFIED] = panel->g_task.background[TASK_NORMAL];
118 if ((panel->g_task.config_background_mask & (1<<TASK_URGENT)) == 0) panel->g_task.background[TASK_URGENT] = panel->g_task.background[TASK_ACTIVE];
119
120 if (panel_horizontal) {
121 panel->g_task.area.posy = panel->g_taskbar.area.posy + panel->g_taskbar.bg->border.width + panel->g_taskbar.area.paddingy;
122 panel->g_task.area.height = panel->area.height - (2 * panel->g_task.area.posy);
123 }
124 else {
125 panel->g_task.area.posx = panel->g_taskbar.area.posx + panel->g_taskbar.bg->border.width + panel->g_taskbar.area.paddingy;
126 panel->g_task.area.width = panel->area.width - (2 * panel->g_task.area.posx);
127 panel->g_task.area.height = panel->g_task.maximum_height;
128 }
129
130 int k;
131 for (k=0; k<TASK_STATE_COUNT; ++k) {
132 if (panel->g_task.background[k]->border.rounded > panel->g_task.area.height/2) {
133 printf("task%sbackground_id has a too large rounded value. Please fix your tint2rc\n", k==0 ? "_" : k==1 ? "_active_" : k==2 ? "_iconified_" : "_urgent_");
134 g_array_append_val(backgrounds, *panel->g_task.background[k]);
135 panel->g_task.background[k] = &g_array_index(backgrounds, Background, backgrounds->len-1);
136 panel->g_task.background[k]->border.rounded = panel->g_task.area.height/2;
137 }
138 }
139
140 // compute vertical position : text and icon
141 int height_ink, height;
142 get_text_size(panel->g_task.font_desc, &height_ink, &height, panel->area.height, "TAjpg", 5);
143
144 if (!panel->g_task.maximum_width && panel_horizontal)
145 panel->g_task.maximum_width = server.monitor[panel->monitor].width;
146
147 panel->g_task.text_posx = panel->g_task.background[0]->border.width + panel->g_task.area.paddingxlr;
148 panel->g_task.text_height = panel->g_task.area.height - (2 * panel->g_task.area.paddingy);
149 if (panel->g_task.icon) {
150 panel->g_task.icon_size1 = panel->g_task.area.height - (2 * panel->g_task.area.paddingy);
151 panel->g_task.text_posx += panel->g_task.icon_size1;
152 panel->g_task.icon_posy = (panel->g_task.area.height - panel->g_task.icon_size1) / 2;
153 }
154 //printf("monitor %d, task_maximum_width %d\n", panel->monitor, panel->g_task.maximum_width);
155
156 Taskbar *tskbar;
157 for (j=0 ; j < panel->nb_desktop ; j++) {
158 tskbar = &panel->taskbar[j];
159 memcpy(&tskbar->area, &panel->g_taskbar, sizeof(Area));
160 tskbar->desktop = j;
161 if (j == server.desktop && panel->g_taskbar.use_active)
162 tskbar->area.bg = panel->g_taskbar.bg_active;
163 }
164 }
165 }
166
167 void taskbar_remove_task(gpointer key, gpointer value, gpointer user_data)
168 {
169 remove_task(task_get_task(*(Window*)key));
170 }
171
172 void default_taskbar()
173 {
174 win_to_task_table = 0;
175 urgent_timeout = 0;
176 urgent_list = 0;
177 }
178
179 void cleanup_taskbar()
180 {
181 Panel *panel;
182 Taskbar *tskbar;
183 int i, j;
184
185 if (win_to_task_table) g_hash_table_foreach(win_to_task_table, taskbar_remove_task, 0);
186 for (i=0 ; i < nb_panel ; i++) {
187 panel = &panel1[i];
188 for (j=0 ; j < panel->nb_desktop ; j++) {
189 tskbar = &panel->taskbar[j];
190 free_area (&tskbar->area);
191 // remove taskbar from the panel
192 panel->area.list = g_slist_remove(panel->area.list, tskbar);
193 }
194 if (panel->taskbar) {
195 free(panel->taskbar);
196 panel->taskbar = 0;
197 }
198 }
199
200 if (win_to_task_table) {
201 g_hash_table_destroy(win_to_task_table);
202 win_to_task_table = 0;
203 }
204 }
205
206
207 Task *task_get_task (Window win)
208 {
209 GPtrArray* task_group = task_get_tasks(win);
210 if (task_group)
211 return g_ptr_array_index(task_group, 0);
212 else
213 return 0;
214 }
215
216
217 GPtrArray* task_get_tasks(Window win)
218 {
219 if (win_to_task_table)
220 return g_hash_table_lookup(win_to_task_table, &win);
221 else
222 return 0;
223 }
224
225
226 void task_refresh_tasklist ()
227 {
228 Window *win;
229 int num_results, i;
230
231 win = server_get_property (server.root_win, server.atom._NET_CLIENT_LIST, XA_WINDOW, &num_results);
232 if (!win) return;
233
234 GList* win_list = g_hash_table_get_keys(win_to_task_table);
235 GList* it;
236 for (it=win_list; it; it=it->next) {
237 for (i = 0; i < num_results; i++)
238 if (*((Window*)it->data) == win[i])
239 break;
240 if (i == num_results)
241 taskbar_remove_task(it->data, 0, 0);
242 }
243 g_list_free(win_list);
244
245 // Add any new
246 for (i = 0; i < num_results; i++)
247 if (!task_get_task (win[i]))
248 add_task (win[i]);
249
250 XFree (win);
251 }
252
253
254 int resize_taskbar(void *obj)
255 {
256 Taskbar *taskbar = (Taskbar*)obj;
257 Panel *panel = (Panel*)taskbar->area.panel;
258 Task *tsk;
259 GSList *l;
260 int task_count, border_width;
261
262 //printf("resize_taskbar : posx et width des taches\n");
263 taskbar->area.redraw = 1;
264
265 border_width = taskbar->area.bg->border.width;
266
267 if (panel_horizontal) {
268 int pixel_width, modulo_width=0;
269 int x, taskbar_width;
270
271 // new task width for 'desktop'
272 task_count = g_slist_length(taskbar->area.list);
273 if (!task_count) pixel_width = panel->g_task.maximum_width;
274 else {
275 taskbar_width = taskbar->area.width - (2 * border_width) - (2 * panel->g_taskbar.area.paddingxlr);
276 if (task_count>1) taskbar_width -= ((task_count-1) * panel->g_taskbar.area.paddingx);
277
278 pixel_width = taskbar_width / task_count;
279 if (pixel_width > panel->g_task.maximum_width)
280 pixel_width = panel->g_task.maximum_width;
281 else
282 modulo_width = taskbar_width % task_count;
283 }
284
285 taskbar->task_width = pixel_width;
286 taskbar->task_modulo = modulo_width;
287 taskbar->text_width = pixel_width - panel->g_task.text_posx - panel->g_task.area.bg->border.width - panel->g_task.area.paddingx;
288
289 // change pos_x and width for all tasks
290 x = taskbar->area.posx + border_width + taskbar->area.paddingxlr;
291 for (l = taskbar->area.list; l ; l = l->next) {
292 tsk = l->data;
293 if (!tsk->area.on_screen) continue;
294 tsk->area.posx = x;
295 set_task_redraw(tsk); // always redraw task, because the background could have changed (taskbar_active_id)
296 tsk->area.width = pixel_width;
297 long value[] = { panel->posx+x, panel->posy, pixel_width, panel->area.height };
298 XChangeProperty (server.dsp, tsk->win, server.atom._NET_WM_ICON_GEOMETRY, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)value, 4);
299
300 if (modulo_width) {
301 tsk->area.width++;
302 modulo_width--;
303 }
304
305 x += tsk->area.width + panel->g_taskbar.area.paddingx;
306 }
307 }
308 else {
309 int pixel_height, modulo_height=0;
310 int y, taskbar_height;
311
312 // new task width for 'desktop'
313 task_count = g_slist_length(taskbar->area.list);
314 if (!task_count) pixel_height = panel->g_task.maximum_height;
315 else {
316 taskbar_height = taskbar->area.height - (2 * border_width) - (2 * panel->g_taskbar.area.paddingxlr);
317 if (task_count>1) taskbar_height -= ((task_count-1) * panel->g_taskbar.area.paddingx);
318
319 pixel_height = taskbar_height / task_count;
320 if (pixel_height > panel->g_task.maximum_height)
321 pixel_height = panel->g_task.maximum_height;
322 else
323 modulo_height = taskbar_height % task_count;
324 }
325
326 taskbar->task_width = pixel_height;
327 taskbar->task_modulo = modulo_height;
328 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;
329
330 // change pos_y and height for all tasks
331 y = taskbar->area.posy + border_width + taskbar->area.paddingxlr;
332 for (l = taskbar->area.list; l ; l = l->next) {
333 tsk = l->data;
334 if (!tsk->area.on_screen) continue;
335 tsk->area.posy = y;
336 set_task_redraw(tsk); // always redraw task, because the background could have changed (taskbar_active_id)
337 tsk->area.height = pixel_height;
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 y += tsk->area.height + panel->g_taskbar.area.paddingx;
347 }
348 }
349 return 0;
350 }
This page took 0.047604 seconds and 4 git commands to generate.