1 | #include <config.h> |
---|
2 | #include <gnome.h> |
---|
3 | #include <libgnomeui/gnome-window-icon.h> |
---|
4 | |
---|
5 | #include "gstc.h" |
---|
6 | #include "gwmh.h" |
---|
7 | |
---|
8 | #include <gdk/gdkx.h> |
---|
9 | #include <X11/Xlib.h> |
---|
10 | #include <X11/Xutil.h> |
---|
11 | |
---|
12 | #include <gdk-pixbuf/gdk-pixbuf.h> |
---|
13 | |
---|
14 | #include "tasklist_applet.h" |
---|
15 | #include "unknown.xpm" |
---|
16 | |
---|
17 | /* from gtkhandlebox.c */ |
---|
18 | #define DRAG_HANDLE_SIZE 10 |
---|
19 | |
---|
20 | /* define to x for debugging output */ |
---|
21 | #define d(x) |
---|
22 | |
---|
23 | #define APPLET_COMPILE_AS_PROCESS |
---|
24 | /* sorting the list... */ |
---|
25 | static gint |
---|
26 | tlsort (gconstpointer data1, gconstpointer data2) |
---|
27 | { |
---|
28 | const TasklistTask *la = data1; |
---|
29 | const TasklistTask *lb = data2; |
---|
30 | const char *sa, *sb; |
---|
31 | |
---|
32 | d(g_print ("la: %p\tlb: %p\n", la, lb)); |
---|
33 | |
---|
34 | sa = la->task_group ? la->group_name : (la->group ? la->group->group_name : la->gwmh_task->name); |
---|
35 | sb = lb->task_group ? lb->group_name : (lb->group ? lb->group->group_name : lb->gwmh_task->name); |
---|
36 | |
---|
37 | if (sa && sb) { |
---|
38 | int cmp = g_strcasecmp (sa, sb); |
---|
39 | /* if the same, then sort by the window id, this is arbitrary |
---|
40 | * but makes tasks of the same group stay in the same order */ |
---|
41 | if (cmp == 0) { |
---|
42 | if (la->gwmh_task->xwin > lb->gwmh_task->xwin) |
---|
43 | return 1; |
---|
44 | else |
---|
45 | return -1; |
---|
46 | } else { |
---|
47 | return cmp; |
---|
48 | } |
---|
49 | } else if (sa) { |
---|
50 | return 1; |
---|
51 | } else if (sb) { |
---|
52 | return -1; |
---|
53 | } else { |
---|
54 | return 0; |
---|
55 | } |
---|
56 | } |
---|
57 | |
---|
58 | static void |
---|
59 | clamp_size (Tasklist *tasklist, int *size) |
---|
60 | { |
---|
61 | int free_space; |
---|
62 | |
---|
63 | free_space = applet_widget_get_free_space (APPLET_WIDGET (tasklist->applet)); |
---|
64 | |
---|
65 | if (free_space > 0 && free_space < *size) |
---|
66 | *size = free_space; |
---|
67 | } |
---|
68 | |
---|
69 | void |
---|
70 | tasklist_clean_menu (TasklistTask *task) |
---|
71 | { |
---|
72 | if(task->menu) { |
---|
73 | d(g_print ("group had a menu: %p\t", task->menu)); |
---|
74 | gtk_widget_destroy (task->menu); |
---|
75 | d(g_print ("%p\n", task->menu)); |
---|
76 | } |
---|
77 | } |
---|
78 | |
---|
79 | static char * |
---|
80 | get_task_class (GwmhTask *task) |
---|
81 | { |
---|
82 | XClassHint hint; |
---|
83 | char *retval; |
---|
84 | Status status; |
---|
85 | |
---|
86 | gdk_error_trap_push (); |
---|
87 | status = XGetClassHint (GDK_DISPLAY (), task->xwin, &hint); |
---|
88 | gdk_flush (); |
---|
89 | if (gdk_error_trap_pop ()) |
---|
90 | return NULL; |
---|
91 | |
---|
92 | if ( ! status) |
---|
93 | return NULL; |
---|
94 | |
---|
95 | d(g_print ("name: %s\tclass: %s\n", hint.res_name, hint.res_class)); |
---|
96 | retval = g_strdup (hint.res_class); |
---|
97 | |
---|
98 | XFree (hint.res_name); |
---|
99 | XFree (hint.res_class); |
---|
100 | |
---|
101 | return retval; |
---|
102 | } |
---|
103 | |
---|
104 | /* get the horz_rows depending on the configuration settings */ |
---|
105 | static gint |
---|
106 | get_horz_rows(Tasklist *tasklist) |
---|
107 | { |
---|
108 | int result; |
---|
109 | |
---|
110 | g_return_val_if_fail (tasklist != NULL, 1); |
---|
111 | |
---|
112 | if (tasklist->config.follow_panel_size) |
---|
113 | result = tasklist->panel_size/ROW_HEIGHT; |
---|
114 | else |
---|
115 | result = tasklist->config.horz_rows; |
---|
116 | |
---|
117 | if (result < 1) |
---|
118 | result = 1; |
---|
119 | |
---|
120 | return result; |
---|
121 | } |
---|
122 | |
---|
123 | /* Shorten a label that is too long */ |
---|
124 | gchar * |
---|
125 | tasklist_task_get_label (TasklistTask *task, int width, gboolean add_groupcount) |
---|
126 | { |
---|
127 | Tasklist *tasklist = task->tasklist; |
---|
128 | gchar *das_string; |
---|
129 | gchar *str, *tempstr, *groupcount = NULL; |
---|
130 | gint len, label_len, overhead, allowed_width; |
---|
131 | |
---|
132 | das_string = task->gwmh_task->name; |
---|
133 | |
---|
134 | if (das_string == NULL) |
---|
135 | das_string = _("???"); |
---|
136 | |
---|
137 | label_len = gdk_string_width (tasklist->area->style->font, das_string); |
---|
138 | |
---|
139 | overhead = tasklist->config.show_mini_icons ? 30 : 6; |
---|
140 | |
---|
141 | if (add_groupcount) { |
---|
142 | GSList *vtasks = task->vtasks; |
---|
143 | /* not sure why this was there but at least |
---|
144 | * now it has the correct logic, perhaps sometime |
---|
145 | * we'd want to draw a task with it's group count */ |
---|
146 | if (vtasks == NULL && |
---|
147 | task->group != NULL) |
---|
148 | vtasks = task->group->vtasks; |
---|
149 | groupcount = g_strdup_printf ("(%d) ", g_slist_length (vtasks)); |
---|
150 | |
---|
151 | overhead += 10 + gdk_string_width (tasklist->area->style->font, |
---|
152 | groupcount); |
---|
153 | } |
---|
154 | |
---|
155 | if (GWMH_TASK_ICONIFIED (task->gwmh_task)) |
---|
156 | overhead += gdk_string_width (tasklist->area->style->font, "[]"); |
---|
157 | |
---|
158 | allowed_width = width - overhead; |
---|
159 | |
---|
160 | if ( (width > 0) && (label_len > allowed_width) ) { |
---|
161 | GdkWChar *wstr; |
---|
162 | |
---|
163 | g_assert (width > 0); |
---|
164 | |
---|
165 | len = strlen (das_string); |
---|
166 | wstr = g_new (GdkWChar, len + 3); |
---|
167 | len = gdk_mbstowcs (wstr, das_string, len); |
---|
168 | /* ok, the below thing is broken */ |
---|
169 | if ( len < 0 ) { /* if the conversion is failed */ |
---|
170 | wstr[0] = wstr[1] = wstr[2] = '?'; |
---|
171 | wstr[3] = '\0'; /* wcscpy(wstr,"???");*/ |
---|
172 | len = 3; |
---|
173 | label_len = gdk_text_width_wc(tasklist->area->style->font, |
---|
174 | wstr, len); |
---|
175 | if (label_len <= allowed_width) { |
---|
176 | str = gdk_wcstombs(wstr); |
---|
177 | g_free(wstr); |
---|
178 | goto finish_label_up; |
---|
179 | } |
---|
180 | } |
---|
181 | wstr[len] = wstr[len+1] = '.'; |
---|
182 | wstr[len+2] = '\0'; /*wcscat(wstr,"..");*/ |
---|
183 | len--; |
---|
184 | |
---|
185 | for (; len > 0; len--) { |
---|
186 | wstr[len] = '.'; |
---|
187 | wstr[len + 3] = '\0'; |
---|
188 | |
---|
189 | label_len = gdk_text_width_wc (tasklist->area->style->font, |
---|
190 | wstr, len + 3); |
---|
191 | |
---|
192 | if (label_len <= allowed_width) |
---|
193 | break; |
---|
194 | } |
---|
195 | str = gdk_wcstombs (wstr); |
---|
196 | g_free (wstr); |
---|
197 | } else { |
---|
198 | str = g_strdup (das_string); |
---|
199 | } |
---|
200 | |
---|
201 | finish_label_up: |
---|
202 | |
---|
203 | if (task->gwmh_task && GWMH_TASK_ICONIFIED (task->gwmh_task)) { |
---|
204 | tempstr = g_strdup_printf ("[%s]", str); |
---|
205 | g_free(str); |
---|
206 | str = tempstr; |
---|
207 | } |
---|
208 | |
---|
209 | if (groupcount) { |
---|
210 | tempstr = g_strconcat (groupcount, str, NULL); |
---|
211 | g_free (str); |
---|
212 | str = tempstr; |
---|
213 | } |
---|
214 | |
---|
215 | return str; |
---|
216 | } |
---|
217 | |
---|
218 | /* Check if a task is "visible", |
---|
219 | if it should be drawn onto the tasklist */ |
---|
220 | static gboolean |
---|
221 | is_task_visible (TasklistTask *task) |
---|
222 | { |
---|
223 | Tasklist *tasklist; |
---|
224 | GwmhDesk *desk_info; |
---|
225 | |
---|
226 | if (!task || task->destroyed || task->task_group) |
---|
227 | return FALSE; |
---|
228 | |
---|
229 | tasklist = task->tasklist; |
---|
230 | |
---|
231 | desk_info = gwmh_desk_get_config (); |
---|
232 | |
---|
233 | if (GWMH_TASK_SKIP_TASKBAR (task->gwmh_task)) |
---|
234 | return FALSE; |
---|
235 | |
---|
236 | if (task->gwmh_task->desktop != desk_info->current_desktop || |
---|
237 | task->gwmh_task->harea != desk_info->current_harea || |
---|
238 | task->gwmh_task->varea != desk_info->current_varea) { |
---|
239 | if (!GWMH_TASK_STICKY (task->gwmh_task)) { |
---|
240 | if (!tasklist->config.all_desks_minimized && |
---|
241 | !tasklist->config.all_desks_normal) |
---|
242 | return FALSE; |
---|
243 | |
---|
244 | else if (tasklist->config.all_desks_minimized && |
---|
245 | !tasklist->config.all_desks_normal) { |
---|
246 | if (!GWMH_TASK_ICONIFIED (task->gwmh_task)) |
---|
247 | return FALSE; |
---|
248 | } |
---|
249 | else if (tasklist->config.all_desks_normal && |
---|
250 | !tasklist->config.all_desks_minimized) { |
---|
251 | if (GWMH_TASK_ICONIFIED (task->gwmh_task)) |
---|
252 | return FALSE; |
---|
253 | } |
---|
254 | } |
---|
255 | } |
---|
256 | |
---|
257 | if (GWMH_TASK_ICONIFIED (task->gwmh_task)) { |
---|
258 | if (!tasklist->config.show_minimized) |
---|
259 | return FALSE; |
---|
260 | } else { |
---|
261 | if (!tasklist->config.show_normal) |
---|
262 | return FALSE; |
---|
263 | } |
---|
264 | |
---|
265 | return TRUE; |
---|
266 | } |
---|
267 | |
---|
268 | static gboolean |
---|
269 | is_task_really_visible (TasklistTask *task) |
---|
270 | { |
---|
271 | g_return_val_if_fail (task != NULL, FALSE); |
---|
272 | |
---|
273 | if (!task->tasklist->config.enable_grouping) |
---|
274 | return is_task_visible (task); |
---|
275 | |
---|
276 | /* we can probably unroll the length test */ |
---|
277 | if (task->group && g_slist_length (task->group->vtasks) > task->tasklist->config.grouping_min) |
---|
278 | return FALSE; |
---|
279 | else if (task->task_group) |
---|
280 | return g_slist_length (task->vtasks) > task->tasklist->config.grouping_min; |
---|
281 | return is_task_visible (task); |
---|
282 | } |
---|
283 | |
---|
284 | static void print_task (TasklistTask *task); |
---|
285 | |
---|
286 | static void |
---|
287 | print_task_iterator (gpointer data, gpointer user_data) |
---|
288 | { |
---|
289 | TasklistTask *task = data; |
---|
290 | print_task (task); |
---|
291 | } |
---|
292 | |
---|
293 | static void |
---|
294 | print_task (TasklistTask *task) |
---|
295 | { |
---|
296 | if (!task) |
---|
297 | g_print (" * * NULL TASK * *\n"); |
---|
298 | else if (task->group) |
---|
299 | g_print ("task: %p (%p) [%d, %d]: %s\n", |
---|
300 | task, task->gwmh_task, |
---|
301 | is_task_visible (task), |
---|
302 | is_task_really_visible (task), |
---|
303 | task->gwmh_task->name); |
---|
304 | else if (task->task_group) { |
---|
305 | g_print ("group: %p [%d]: %s\n", task, is_task_really_visible (task), task->group_name); |
---|
306 | g_slist_foreach (task->tasks, print_task_iterator, NULL); |
---|
307 | g_print ("/\n"); |
---|
308 | } else { |
---|
309 | g_print ("Unknown task: %p\n", task); |
---|
310 | g_assert_not_reached (); |
---|
311 | } |
---|
312 | } |
---|
313 | |
---|
314 | /* returns TRUE if the group entry should be redrawn */ |
---|
315 | static gboolean |
---|
316 | fixup_group (TasklistTask *group) |
---|
317 | { |
---|
318 | TasklistTask *focused_task; |
---|
319 | gboolean iconified; |
---|
320 | TasklistTask *task; |
---|
321 | GSList *item; |
---|
322 | |
---|
323 | g_return_val_if_fail (group != NULL, FALSE); |
---|
324 | |
---|
325 | focused_task = NULL; |
---|
326 | iconified = TRUE; |
---|
327 | |
---|
328 | g_slist_free (group->vtasks); |
---|
329 | group->vtasks = NULL; |
---|
330 | |
---|
331 | for (item = group->tasks; item; item = item->next) { |
---|
332 | task = (TasklistTask *)item->data; |
---|
333 | if (is_task_visible (task)) { |
---|
334 | group->vtasks = g_slist_prepend (group->vtasks, task); |
---|
335 | if (!task->gwmh_task->iconified) |
---|
336 | iconified = FALSE; |
---|
337 | if (task->gwmh_task->focused) |
---|
338 | focused_task = task; |
---|
339 | } |
---|
340 | } |
---|
341 | |
---|
342 | if (group->focused_task != focused_task || |
---|
343 | group->gwmh_task->iconified != iconified) { |
---|
344 | group->focused_task = focused_task; |
---|
345 | group->gwmh_task->iconified = iconified; |
---|
346 | |
---|
347 | return TRUE; |
---|
348 | } else { |
---|
349 | return FALSE; |
---|
350 | } |
---|
351 | } |
---|
352 | |
---|
353 | static gboolean fixup_vtask (TasklistTask *task, gboolean *redraw); |
---|
354 | |
---|
355 | static void |
---|
356 | fixup_vtask_iterator (gpointer data, gpointer user_data) |
---|
357 | { |
---|
358 | TasklistTask *task = data; |
---|
359 | fixup_vtask (task, NULL); |
---|
360 | } |
---|
361 | |
---|
362 | static gboolean |
---|
363 | fixup_vtask (TasklistTask *task, gboolean *redraw) |
---|
364 | { |
---|
365 | gboolean visible; |
---|
366 | |
---|
367 | /* why not layout if we are confused */ |
---|
368 | g_return_val_if_fail (task, TRUE); |
---|
369 | |
---|
370 | if (task->task_group) { |
---|
371 | gboolean do_redraw = fixup_group (task); |
---|
372 | if (redraw != NULL) |
---|
373 | *redraw = do_redraw; |
---|
374 | } |
---|
375 | |
---|
376 | visible = is_task_really_visible (task); |
---|
377 | |
---|
378 | if (visible == task->visible) |
---|
379 | return FALSE; |
---|
380 | |
---|
381 | task->visible = visible; |
---|
382 | if (visible) { |
---|
383 | task->tasklist->vtasks = |
---|
384 | g_slist_insert_sorted (task->tasklist->vtasks, task, tlsort); |
---|
385 | } else { |
---|
386 | task->tasklist->vtasks = |
---|
387 | g_slist_remove (task->tasklist->vtasks, task); |
---|
388 | } |
---|
389 | |
---|
390 | if (task->tasklist->config.enable_grouping) { |
---|
391 | if (task->task_group) { |
---|
392 | g_slist_foreach (task->tasks, fixup_vtask_iterator, NULL); |
---|
393 | } else if (task->group) { |
---|
394 | fixup_vtask (task->group, NULL); |
---|
395 | } |
---|
396 | } |
---|
397 | |
---|
398 | d(g_print (">>>>>\tfixup_vtask ")); |
---|
399 | d(print_task (task)); |
---|
400 | d(g_slist_foreach (task->tasklist->vtasks, print_task_iterator, NULL)); |
---|
401 | d(g_print ("<<<<<\n")); |
---|
402 | |
---|
403 | return TRUE; |
---|
404 | } |
---|
405 | |
---|
406 | static void |
---|
407 | redo_groups_iterator (gpointer key, gpointer data, gpointer user_data) |
---|
408 | { |
---|
409 | TasklistTask *task = data; |
---|
410 | Tasklist *tasklist = user_data; |
---|
411 | |
---|
412 | d (print_task (task)); |
---|
413 | |
---|
414 | fixup_group (task); |
---|
415 | task->visible = is_task_really_visible (task); |
---|
416 | if (task->visible) |
---|
417 | tasklist->vtasks = g_slist_insert_sorted (tasklist->vtasks, task, tlsort); |
---|
418 | } |
---|
419 | |
---|
420 | void |
---|
421 | tasklist_redo_vtasks (Tasklist *tasklist) |
---|
422 | { |
---|
423 | TasklistTask *task; |
---|
424 | GList *item; |
---|
425 | |
---|
426 | if (tasklist->vtasks) { |
---|
427 | g_slist_free (tasklist->vtasks); |
---|
428 | tasklist->vtasks = NULL; |
---|
429 | } |
---|
430 | |
---|
431 | d(g_print ("\n\n\n\n\n\n\n\n\n\nredo_vtasks\n\n\n\n\n\n\n\n\n\n")); |
---|
432 | |
---|
433 | if (tasklist->config.enable_grouping) |
---|
434 | g_hash_table_foreach (tasklist->groups, redo_groups_iterator, tasklist); |
---|
435 | |
---|
436 | for (item = gwmh_task_list_get (); item; item = item->next) { |
---|
437 | task = g_hash_table_lookup (tasklist->tasks, item->data); |
---|
438 | |
---|
439 | /* this should never actually happen */ |
---|
440 | if (!task) continue; |
---|
441 | |
---|
442 | task->visible = is_task_really_visible (task); |
---|
443 | |
---|
444 | if (task->visible) |
---|
445 | tasklist->vtasks = g_slist_insert_sorted (tasklist->vtasks, task, tlsort); |
---|
446 | } |
---|
447 | |
---|
448 | #if 0 |
---|
449 | if (!tasklist->config.sort_tasklist) |
---|
450 | tasklist->vtasks = g_slist_reverse (tasklist->vtasks); |
---|
451 | #endif |
---|
452 | d(g_print ("\n\n\n\n\n\n\n\n\n\nvtasks: %d\n", g_slist_length (tasklist->vtasks))); |
---|
453 | |
---|
454 | d(g_print (">>>>>\tredo_vtasks:\n")); |
---|
455 | d(g_slist_foreach (tasklist->vtasks, print_task_iterator, NULL)); |
---|
456 | d(g_print ("<<<<<\n")); |
---|
457 | } |
---|
458 | |
---|
459 | /* Check what task (if any) is at position x,y on the tasklist */ |
---|
460 | static TasklistTask * |
---|
461 | task_get_xy (Tasklist *tasklist, gint x, gint y) |
---|
462 | { |
---|
463 | GSList *temp_tasks, *temp; |
---|
464 | TasklistTask *task; |
---|
465 | |
---|
466 | temp_tasks = tasklist->vtasks; |
---|
467 | |
---|
468 | for (temp = temp_tasks; temp != NULL; temp = temp->next) { |
---|
469 | task = (TasklistTask *)temp->data; |
---|
470 | if (x > task->x && |
---|
471 | x < task->x + task->width && |
---|
472 | y > task->y && |
---|
473 | y < task->y + task->height) |
---|
474 | return task; |
---|
475 | } |
---|
476 | |
---|
477 | return NULL; |
---|
478 | } |
---|
479 | |
---|
480 | static void |
---|
481 | draw_dot (GdkWindow *window, GdkGC *lgc, GdkGC *dgc, int x, int y) |
---|
482 | { |
---|
483 | gdk_draw_point (window, dgc, x, y); |
---|
484 | gdk_draw_point (window, lgc, x+1, y+1); |
---|
485 | } |
---|
486 | |
---|
487 | /* Draw a single task */ |
---|
488 | void |
---|
489 | tasklist_draw_task (TasklistTask *task, GdkRectangle *rect) |
---|
490 | { |
---|
491 | TasklistTask *real_task; |
---|
492 | gchar *tempstr; |
---|
493 | gint text_height, text_width; |
---|
494 | gboolean focused; |
---|
495 | |
---|
496 | /* For mini icons */ |
---|
497 | TasklistIcon *icon; |
---|
498 | GdkPixbuf *pixbuf; |
---|
499 | |
---|
500 | Tasklist *tasklist; |
---|
501 | |
---|
502 | if (!is_task_really_visible (task)) |
---|
503 | return; |
---|
504 | |
---|
505 | /* is_task_visible should return FALSE for task == NULL */ |
---|
506 | g_assert (task != NULL); |
---|
507 | |
---|
508 | tasklist = task->tasklist; |
---|
509 | |
---|
510 | real_task = task; |
---|
511 | if (is_task_visible (task->focused_task) && GWMH_TASK_FOCUSED (task->focused_task->gwmh_task)) |
---|
512 | task = task->focused_task; |
---|
513 | |
---|
514 | focused = GWMH_TASK_FOCUSED (task->gwmh_task) || real_task->menu != NULL; |
---|
515 | |
---|
516 | gtk_paint_box (tasklist->area->style, tasklist->area->window, |
---|
517 | focused ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL, |
---|
518 | focused ? GTK_SHADOW_IN : GTK_SHADOW_OUT, |
---|
519 | rect, tasklist->area, "button", |
---|
520 | real_task->x, real_task->y, |
---|
521 | real_task->width, real_task->height); |
---|
522 | |
---|
523 | tempstr = tasklist_task_get_label (task, real_task->width, real_task->task_group); |
---|
524 | if (tempstr) { |
---|
525 | text_height = gdk_string_height (tasklist->area->style->font, "1"); |
---|
526 | text_width = gdk_string_width (tasklist->area->style->font, tempstr); |
---|
527 | gdk_draw_string (tasklist->area->window, |
---|
528 | tasklist->area->style->font, |
---|
529 | focused ? |
---|
530 | tasklist->area->style->fg_gc[GTK_STATE_ACTIVE] : |
---|
531 | tasklist->area->style->fg_gc[GTK_STATE_NORMAL], |
---|
532 | real_task->x + |
---|
533 | (tasklist->config.show_mini_icons ? 10 : 0) + |
---|
534 | ((real_task->width - text_width) / 2), |
---|
535 | real_task->y + ((real_task->height - text_height) / 2) + text_height, |
---|
536 | tempstr); |
---|
537 | |
---|
538 | g_free (tempstr); |
---|
539 | } |
---|
540 | |
---|
541 | if (tasklist->config.show_mini_icons) { |
---|
542 | icon = task->icon; |
---|
543 | |
---|
544 | if ( GWMH_TASK_ICONIFIED (task->gwmh_task)) |
---|
545 | pixbuf = icon->minimized; |
---|
546 | else |
---|
547 | pixbuf = icon->normal; |
---|
548 | |
---|
549 | gdk_pixbuf_render_to_drawable_alpha ( |
---|
550 | pixbuf, |
---|
551 | tasklist->area->window, |
---|
552 | 0, 0, |
---|
553 | real_task->x + 3 + (16 - gdk_pixbuf_get_width (pixbuf)) / 2, |
---|
554 | real_task->y + (real_task->height - gdk_pixbuf_get_height (pixbuf)) / 2, |
---|
555 | gdk_pixbuf_get_width (pixbuf), |
---|
556 | gdk_pixbuf_get_height (pixbuf), |
---|
557 | GDK_PIXBUF_ALPHA_BILEVEL, |
---|
558 | 127, |
---|
559 | GDK_RGB_DITHER_NORMAL, |
---|
560 | gdk_pixbuf_get_width (pixbuf), |
---|
561 | gdk_pixbuf_get_height (pixbuf)); |
---|
562 | |
---|
563 | } |
---|
564 | |
---|
565 | if (real_task->task_group) { |
---|
566 | GtkStyle *style; |
---|
567 | GdkWindow *window; |
---|
568 | GdkGC *lgc, *dgc; |
---|
569 | int x, y, i, j; |
---|
570 | |
---|
571 | style = tasklist->area->style; |
---|
572 | |
---|
573 | lgc = style->light_gc[focused ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL]; |
---|
574 | dgc = style->dark_gc[focused ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL]; |
---|
575 | |
---|
576 | window = tasklist->area->window; |
---|
577 | |
---|
578 | x = real_task->x + real_task->width - style->klass->ythickness - 10; |
---|
579 | y = real_task->y + style->klass->xthickness + 2; |
---|
580 | |
---|
581 | for (i = 0; i < 3; i++) { |
---|
582 | for (j = i; j < 3; j++) { |
---|
583 | draw_dot (window, lgc, dgc, x + j*3, y + i*3); |
---|
584 | } |
---|
585 | } |
---|
586 | |
---|
587 | |
---|
588 | |
---|
589 | #if 0 |
---|
590 | gtk_draw_arrow (tasklist->area->style, tasklist->area->window, |
---|
591 | focused ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL, |
---|
592 | GTK_SHADOW_ETCHED_IN, |
---|
593 | GTK_ARROW_DOWN, TRUE, |
---|
594 | real_task->x + real_task->width - 12, |
---|
595 | real_task->y + (real_task->height - 8) / 2, |
---|
596 | 9, 8); |
---|
597 | #endif |
---|
598 | } |
---|
599 | |
---|
600 | } |
---|
601 | |
---|
602 | |
---|
603 | static int |
---|
604 | max_width (GSList *tasks) |
---|
605 | { |
---|
606 | TasklistTask *task; |
---|
607 | GSList *li; |
---|
608 | int maxwidth = 0; |
---|
609 | char *s; |
---|
610 | |
---|
611 | for (li = tasks; li; li = li->next) { |
---|
612 | task = li->data; |
---|
613 | |
---|
614 | if (task->fullwidth < 0) { |
---|
615 | s = tasklist_task_get_label (task, -1, task->task_group); |
---|
616 | task->fullwidth = gdk_string_width (task->tasklist->area->style->font, s); |
---|
617 | g_free (s); |
---|
618 | } |
---|
619 | |
---|
620 | maxwidth = MAX (maxwidth, |
---|
621 | task->fullwidth + |
---|
622 | (task->tasklist->config.show_mini_icons |
---|
623 | ? ROW_HEIGHT + 10 : 0)); |
---|
624 | } |
---|
625 | return MIN (maxwidth, 512); |
---|
626 | } |
---|
627 | |
---|
628 | /* Layout the tasklist */ |
---|
629 | static gboolean |
---|
630 | real_layout_tasklist (gpointer data) |
---|
631 | { |
---|
632 | Tasklist *tasklist = data; |
---|
633 | gint j = 0, k = 0, num = 0, p = 0; |
---|
634 | TasklistTask *task; |
---|
635 | GSList *temp = NULL; |
---|
636 | gint num_rows = 0, num_cols = 0; |
---|
637 | gint curx = 0, cury = 0, curwidth = 0, curheight = 0; |
---|
638 | |
---|
639 | tasklist->layout_idle = 0; |
---|
640 | d(g_message ("Layout!")); |
---|
641 | |
---|
642 | if (!tasklist->vtasks) { |
---|
643 | d(g_message ("no tasks :(\n")); |
---|
644 | gtk_widget_draw (tasklist->area, NULL); |
---|
645 | return FALSE; |
---|
646 | } |
---|
647 | |
---|
648 | num = g_slist_length (tasklist->vtasks); |
---|
649 | |
---|
650 | switch (applet_widget_get_panel_orient (APPLET_WIDGET (tasklist->applet))) { |
---|
651 | case ORIENT_UP: |
---|
652 | case ORIENT_DOWN: |
---|
653 | if (num == 0) { |
---|
654 | if (tasklist->config.horz_fixed) |
---|
655 | tasklist->horz_width = tasklist->config.horz_width; |
---|
656 | else |
---|
657 | tasklist->horz_width = 4; |
---|
658 | |
---|
659 | tasklist_change_size (tasklist, FALSE, -1); |
---|
660 | |
---|
661 | gtk_widget_draw (tasklist->area, NULL); |
---|
662 | return FALSE; |
---|
663 | } |
---|
664 | |
---|
665 | while (p < num) { |
---|
666 | if (num < get_horz_rows(tasklist)) |
---|
667 | num_rows = num; |
---|
668 | |
---|
669 | j++; |
---|
670 | if (num_cols < j) |
---|
671 | num_cols = j; |
---|
672 | if (num_rows < k + 1) |
---|
673 | num_rows = k + 1; |
---|
674 | |
---|
675 | if (get_horz_rows (tasklist) == 0 || j >= ((num + get_horz_rows(tasklist) - 1) / get_horz_rows(tasklist))) { |
---|
676 | j = 0; |
---|
677 | k++; |
---|
678 | } |
---|
679 | p++; |
---|
680 | } |
---|
681 | |
---|
682 | if (tasklist->config.horz_fixed) { |
---|
683 | curheight = (ROW_HEIGHT * get_horz_rows(tasklist) - (tasklist->config.sunken?4:0)) / num_rows; |
---|
684 | curwidth = (tasklist->config.horz_width - (tasklist->config.sunken?4:0)) / num_cols; |
---|
685 | |
---|
686 | } else { |
---|
687 | int width; |
---|
688 | |
---|
689 | width = tasklist->config.horz_taskwidth * num_cols + DRAG_HANDLE_SIZE; |
---|
690 | |
---|
691 | if (width > tasklist->config.horz_width) |
---|
692 | width = tasklist->config.horz_width; |
---|
693 | |
---|
694 | if (tasklist->config.horz_never_push) |
---|
695 | clamp_size (tasklist, &width); |
---|
696 | |
---|
697 | width -= DRAG_HANDLE_SIZE; |
---|
698 | |
---|
699 | curheight = (ROW_HEIGHT * get_horz_rows(tasklist) - (tasklist->config.sunken?4:0)) / num_rows; |
---|
700 | #if 0 |
---|
701 | /* If the total width is higher than allowed, |
---|
702 | we use the "fixed" way instead */ |
---|
703 | if ((curwidth * num_cols) > tasklist->config.horz_width) |
---|
704 | curwidth = (tasklist->config.horz_width - 0) / num_cols; |
---|
705 | #endif |
---|
706 | curwidth = width / num_cols; |
---|
707 | } |
---|
708 | |
---|
709 | |
---|
710 | curx = (tasklist->config.sunken?2:0); |
---|
711 | cury = (tasklist->config.sunken?2:0); |
---|
712 | |
---|
713 | |
---|
714 | for (temp = tasklist->vtasks; temp != NULL; temp = temp->next) { |
---|
715 | task = (TasklistTask *) temp->data; |
---|
716 | |
---|
717 | task->x = curx; |
---|
718 | task->y = cury; |
---|
719 | task->width = curwidth; |
---|
720 | task->height = curheight; |
---|
721 | |
---|
722 | if (tasklist->config.horz_fixed) { |
---|
723 | curx += curwidth; |
---|
724 | |
---|
725 | if (curx >= tasklist->config.horz_width || |
---|
726 | curx + curwidth > tasklist->config.horz_width) { |
---|
727 | cury += curheight; |
---|
728 | curx = (tasklist->config.sunken?2:0); |
---|
729 | } |
---|
730 | } else { |
---|
731 | |
---|
732 | curx += curwidth; |
---|
733 | |
---|
734 | if (curx >= num_cols * curwidth) { |
---|
735 | cury += curheight; |
---|
736 | curx = (tasklist->config.sunken?2:0); |
---|
737 | } |
---|
738 | } |
---|
739 | } |
---|
740 | |
---|
741 | if (tasklist->config.horz_fixed) |
---|
742 | tasklist->horz_width = tasklist->config.horz_width; |
---|
743 | else |
---|
744 | tasklist->horz_width = num_cols * curwidth + 4; |
---|
745 | |
---|
746 | tasklist_change_size (tasklist, FALSE, -1); |
---|
747 | |
---|
748 | break; |
---|
749 | |
---|
750 | case ORIENT_LEFT: |
---|
751 | case ORIENT_RIGHT: |
---|
752 | |
---|
753 | if (num == 0) { |
---|
754 | if (tasklist->config.vert_fixed) |
---|
755 | tasklist->vert_height = tasklist->config.vert_height; |
---|
756 | else |
---|
757 | tasklist->vert_height = 4; |
---|
758 | |
---|
759 | tasklist_change_size (tasklist, FALSE, -1); |
---|
760 | |
---|
761 | gtk_widget_draw (tasklist->area, NULL); |
---|
762 | return FALSE; |
---|
763 | } |
---|
764 | |
---|
765 | curheight = ROW_HEIGHT; |
---|
766 | if (tasklist->config.follow_panel_size) |
---|
767 | curwidth = tasklist->panel_size - (tasklist->config.sunken?4:0); |
---|
768 | else |
---|
769 | curwidth = tasklist->config.vert_width - (tasklist->config.sunken?4:0); |
---|
770 | |
---|
771 | if (tasklist->config.vert_width_full) |
---|
772 | curwidth = MAX (curwidth, max_width (tasklist->vtasks)); |
---|
773 | |
---|
774 | num_cols = 1; |
---|
775 | num_rows = num; |
---|
776 | |
---|
777 | curx = (tasklist->config.sunken?2:0); |
---|
778 | cury = (tasklist->config.sunken?2:0); |
---|
779 | |
---|
780 | if (tasklist->config.vert_fixed) { |
---|
781 | tasklist->vert_height = tasklist->config.vert_height; |
---|
782 | } else { |
---|
783 | tasklist->vert_height = curheight * num_rows + 4 + DRAG_HANDLE_SIZE; |
---|
784 | if (tasklist->config.vert_never_push) |
---|
785 | clamp_size (tasklist, &tasklist->vert_height); |
---|
786 | tasklist->vert_height -= DRAG_HANDLE_SIZE; |
---|
787 | } |
---|
788 | |
---|
789 | tasklist_change_size (tasklist, FALSE, curwidth); |
---|
790 | |
---|
791 | for (temp = tasklist->vtasks; temp != NULL; temp = temp->next) { |
---|
792 | task = (TasklistTask *) temp->data; |
---|
793 | |
---|
794 | task->x = curx; |
---|
795 | task->y = cury; |
---|
796 | task->width = curwidth; |
---|
797 | task->height = curheight; |
---|
798 | |
---|
799 | curx += curwidth; |
---|
800 | |
---|
801 | if (curx >= (tasklist->config.follow_panel_size? |
---|
802 | tasklist->panel_size: |
---|
803 | tasklist->config.vert_width) - (tasklist->config.sunken?4:0)) { |
---|
804 | cury += curheight; |
---|
805 | curx = (tasklist->config.sunken?2:0); |
---|
806 | } |
---|
807 | } |
---|
808 | |
---|
809 | break; |
---|
810 | } |
---|
811 | |
---|
812 | gtk_widget_draw (tasklist->area, NULL); |
---|
813 | |
---|
814 | return FALSE; |
---|
815 | } |
---|
816 | |
---|
817 | /* this now actually just queues a relayout */ |
---|
818 | void |
---|
819 | tasklist_layout_tasklist (Tasklist *tasklist) |
---|
820 | { |
---|
821 | g_return_if_fail (tasklist); |
---|
822 | |
---|
823 | /* don't queue another timeout */ |
---|
824 | if (tasklist->layout_idle) { |
---|
825 | d(g_message ("Skipped layout!")); |
---|
826 | return; |
---|
827 | } |
---|
828 | |
---|
829 | d(g_message ("Adding layout callback...")); |
---|
830 | tasklist->layout_idle = gtk_idle_add (real_layout_tasklist, tasklist); |
---|
831 | } |
---|
832 | |
---|
833 | #if 0 |
---|
834 | /* Get a task from the list that has got the given gwmh_task */ |
---|
835 | static TasklistTask * |
---|
836 | find_gwmh_task (Tasklist *tasklist, GwmhTask *gwmh_task) |
---|
837 | { |
---|
838 | GList *temp_tasks; |
---|
839 | TasklistTask *task; |
---|
840 | |
---|
841 | temp_tasks = tasklist->tasks; |
---|
842 | |
---|
843 | while (temp_tasks) { |
---|
844 | task = (TasklistTask *)temp_tasks->data; |
---|
845 | if (task->gwmh_task == gwmh_task) |
---|
846 | return task; |
---|
847 | temp_tasks = temp_tasks->next; |
---|
848 | } |
---|
849 | |
---|
850 | return NULL; |
---|
851 | } |
---|
852 | #endif |
---|
853 | |
---|
854 | /* This routine gets called when desktops are switched etc */ |
---|
855 | static gboolean |
---|
856 | desk_notifier (gpointer func_data, GwmhDesk *desk, |
---|
857 | GwmhDeskInfoMask change_mask) |
---|
858 | { |
---|
859 | Tasklist *tasklist = (Tasklist *) func_data; |
---|
860 | |
---|
861 | if (tasklist->config.all_desks_minimized && |
---|
862 | tasklist->config.all_desks_normal) |
---|
863 | return TRUE; |
---|
864 | |
---|
865 | tasklist_redo_vtasks (tasklist); |
---|
866 | tasklist_layout_tasklist (tasklist); |
---|
867 | |
---|
868 | return TRUE; |
---|
869 | } |
---|
870 | |
---|
871 | static void |
---|
872 | tasklist_group_destroy (TasklistTask *group) |
---|
873 | { |
---|
874 | d(g_print (" *** destroying group: %s\n", group->group_name)); |
---|
875 | |
---|
876 | tasklist_icon_destroy (group); |
---|
877 | |
---|
878 | g_hash_table_remove (group->tasklist->groups, group->group_name); |
---|
879 | |
---|
880 | g_free (group->gwmh_task); |
---|
881 | group->gwmh_task = NULL; |
---|
882 | g_free (group->group_name); |
---|
883 | group->group_name = NULL; |
---|
884 | |
---|
885 | tasklist_clean_menu (group); |
---|
886 | |
---|
887 | g_free (group); |
---|
888 | } |
---|
889 | |
---|
890 | static void |
---|
891 | tasklist_task_destroy (GwmhTask *gtask, Tasklist *tasklist) |
---|
892 | { |
---|
893 | TasklistTask *ttask; |
---|
894 | |
---|
895 | g_return_if_fail (gtask != NULL); |
---|
896 | g_return_if_fail (tasklist != NULL); |
---|
897 | |
---|
898 | ttask = g_hash_table_lookup (tasklist->tasks, gtask); |
---|
899 | |
---|
900 | if (!ttask) { |
---|
901 | g_warning ("Task not found in tasklist: %p; not destroying", gtask); |
---|
902 | return; |
---|
903 | } |
---|
904 | |
---|
905 | d(g_print (" *** removing: %p (%s)\n", ttask, gtask->name)); |
---|
906 | |
---|
907 | ttask->destroyed = TRUE; |
---|
908 | |
---|
909 | g_hash_table_remove (tasklist->tasks, gtask); |
---|
910 | |
---|
911 | if (ttask == tasklist->motion_task) |
---|
912 | tasklist->motion_task = NULL; |
---|
913 | |
---|
914 | if (ttask->menuitem) { |
---|
915 | gtk_object_set_data (GTK_OBJECT (ttask->menuitem), |
---|
916 | "task", NULL); |
---|
917 | gtk_widget_hide (ttask->menuitem); |
---|
918 | ttask->menuitem = NULL; |
---|
919 | } |
---|
920 | |
---|
921 | tasklist_icon_destroy (ttask); |
---|
922 | tasklist_clean_menu (ttask); |
---|
923 | |
---|
924 | if (ttask->group) { |
---|
925 | if (ttask->group->focused_task == ttask) |
---|
926 | ttask->group->focused_task = NULL; |
---|
927 | |
---|
928 | ttask->group->tasks = g_slist_remove (ttask->group->tasks, ttask); |
---|
929 | |
---|
930 | if (!ttask->group->tasks) |
---|
931 | tasklist_group_destroy (ttask->group); |
---|
932 | else |
---|
933 | fixup_vtask (ttask->group, NULL); |
---|
934 | } |
---|
935 | |
---|
936 | tasklist->vtasks = g_slist_remove (tasklist->vtasks, ttask); |
---|
937 | |
---|
938 | g_free (ttask); |
---|
939 | |
---|
940 | tasklist_layout_tasklist (tasklist); |
---|
941 | } |
---|
942 | |
---|
943 | static TasklistTask * |
---|
944 | tasklist_group_new (TasklistTask *first_task, const char *group_name) |
---|
945 | { |
---|
946 | TasklistTask *group; |
---|
947 | |
---|
948 | g_return_val_if_fail (first_task != NULL, NULL); |
---|
949 | g_return_val_if_fail (group_name != NULL, NULL); |
---|
950 | |
---|
951 | group = g_new0 (TasklistTask, 1); |
---|
952 | group->tasklist = first_task->tasklist; |
---|
953 | group->task_group = TRUE; |
---|
954 | group->group_name = g_strdup (group_name); |
---|
955 | group->fullwidth = -1; |
---|
956 | g_hash_table_insert (group->tasklist->groups, |
---|
957 | group->group_name, group); |
---|
958 | |
---|
959 | gdk_pixbuf_ref (first_task->icon->normal); |
---|
960 | gdk_pixbuf_ref (first_task->icon->minimized); |
---|
961 | |
---|
962 | group->icon = g_new (TasklistIcon, 1); |
---|
963 | group->icon->normal = first_task->icon->normal; |
---|
964 | group->icon->minimized = first_task->icon->minimized; |
---|
965 | |
---|
966 | group->tasks = g_slist_prepend (group->tasks, first_task); |
---|
967 | |
---|
968 | group->gwmh_task = g_new0 (GwmhTask, 1); |
---|
969 | group->gwmh_task->name = group->group_name; |
---|
970 | |
---|
971 | return group; |
---|
972 | } |
---|
973 | |
---|
974 | /* |
---|
975 | * this is void since we don't need to get the return value when a |
---|
976 | * task is created and we can just create a lot of tasks from the gwmh |
---|
977 | * task glist |
---|
978 | */ |
---|
979 | |
---|
980 | static void |
---|
981 | tasklist_task_new (GwmhTask *gtask, Tasklist *tasklist) |
---|
982 | { |
---|
983 | TasklistTask *ttask; |
---|
984 | char *class; |
---|
985 | |
---|
986 | g_return_if_fail (gtask != NULL); |
---|
987 | g_return_if_fail (tasklist != NULL); |
---|
988 | g_return_if_fail (tasklist->tasks != NULL); |
---|
989 | |
---|
990 | d(g_print ("Adding task: %s\n", gtask->name)); |
---|
991 | |
---|
992 | ttask = g_new0 (TasklistTask, 1); |
---|
993 | |
---|
994 | ttask->tasklist = tasklist; |
---|
995 | ttask->gwmh_task = gtask; |
---|
996 | |
---|
997 | g_hash_table_insert (tasklist->tasks, gtask, ttask); |
---|
998 | |
---|
999 | ttask->wmhints_icon = tasklist_icon_get_pixmap (ttask); |
---|
1000 | |
---|
1001 | tasklist_icon_set (ttask); |
---|
1002 | ttask->fullwidth = -1; |
---|
1003 | |
---|
1004 | class = get_task_class (gtask); |
---|
1005 | if (class == NULL) |
---|
1006 | return; |
---|
1007 | |
---|
1008 | ttask->group = g_hash_table_lookup (tasklist->groups, class); |
---|
1009 | |
---|
1010 | if (ttask->group == NULL) { |
---|
1011 | ttask->group = tasklist_group_new (ttask, class); |
---|
1012 | } else { |
---|
1013 | ttask->group->tasks = g_slist_prepend (ttask->group->tasks, ttask); |
---|
1014 | fixup_vtask (ttask->group, NULL); |
---|
1015 | } |
---|
1016 | |
---|
1017 | g_free (class); |
---|
1018 | } |
---|
1019 | |
---|
1020 | static void |
---|
1021 | tasklist_task_new_iterator (gpointer data, gpointer user_data) |
---|
1022 | { |
---|
1023 | GwmhTask *gtask = data; |
---|
1024 | Tasklist *tasklist = user_data; |
---|
1025 | |
---|
1026 | tasklist_task_new (gtask, tasklist); |
---|
1027 | } |
---|
1028 | |
---|
1029 | |
---|
1030 | /* This routine gets called when tasks are created/destroyed etc */ |
---|
1031 | static gboolean |
---|
1032 | task_notifier (gpointer func_data, GwmhTask *gwmh_task, |
---|
1033 | GwmhTaskNotifyType ntype, |
---|
1034 | GwmhTaskInfoMask imask) |
---|
1035 | { |
---|
1036 | Tasklist *tasklist = (Tasklist *) func_data; |
---|
1037 | TasklistTask *task; |
---|
1038 | gboolean redraw = FALSE; |
---|
1039 | gboolean relayout = FALSE; |
---|
1040 | |
---|
1041 | switch (ntype) |
---|
1042 | { |
---|
1043 | case GWMH_NOTIFY_INFO_CHANGED: |
---|
1044 | /* if this is just an allocation change, then no we don't want |
---|
1045 | * to do anything */ |
---|
1046 | if ( ! (imask & ~GWMH_TASK_INFO_ALLOCATION)) |
---|
1047 | break; |
---|
1048 | |
---|
1049 | task = g_hash_table_lookup (tasklist->tasks, gwmh_task); |
---|
1050 | if (!task) { |
---|
1051 | g_warning ("Getting info about task we don't know about: %p", gwmh_task); |
---|
1052 | break; |
---|
1053 | } |
---|
1054 | |
---|
1055 | if ((imask & GWMH_TASK_INFO_FOCUSED) && |
---|
1056 | task->gwmh_task->focused && task->group) |
---|
1057 | task->group->focused_task = task; |
---|
1058 | |
---|
1059 | |
---|
1060 | if (imask & GWMH_TASK_INFO_MISC) { |
---|
1061 | if (tasklist->config.vert_width_full && |
---|
1062 | (tasklist->orient == ORIENT_LEFT || |
---|
1063 | tasklist->orient == ORIENT_RIGHT)) |
---|
1064 | relayout = TRUE; |
---|
1065 | task->fullwidth = -1; |
---|
1066 | } |
---|
1067 | |
---|
1068 | /* we only need to re-layout if the task has changed |
---|
1069 | * visibility status. If it has, its group will also get |
---|
1070 | * fixed up |
---|
1071 | */ |
---|
1072 | if (fixup_vtask (task, &redraw)) { |
---|
1073 | relayout = TRUE; |
---|
1074 | } |
---|
1075 | |
---|
1076 | |
---|
1077 | if (imask & GWMH_TASK_INFO_WM_HINTS) { |
---|
1078 | if (tasklist_icon_get_pixmap (task) != |
---|
1079 | task->wmhints_icon) { |
---|
1080 | tasklist_icon_destroy (task); |
---|
1081 | tasklist_icon_set (task); |
---|
1082 | redraw = TRUE; |
---|
1083 | } |
---|
1084 | } |
---|
1085 | if (imask & GWMH_TASK_INFO_GSTATE) |
---|
1086 | relayout = TRUE; |
---|
1087 | if (imask & GWMH_TASK_INFO_ICONIFIED) |
---|
1088 | relayout = TRUE; |
---|
1089 | |
---|
1090 | if (imask & GWMH_TASK_INFO_FOCUSED) |
---|
1091 | redraw = TRUE; |
---|
1092 | if (imask & GWMH_TASK_INFO_MISC) |
---|
1093 | redraw = TRUE; |
---|
1094 | if (imask & GWMH_TASK_INFO_DESKTOP) |
---|
1095 | relayout = TRUE; |
---|
1096 | |
---|
1097 | /* BTW, change_size is always called from the layout_tasklist |
---|
1098 | * since we pass TRUE */ |
---|
1099 | if (relayout) |
---|
1100 | tasklist_layout_tasklist (tasklist); |
---|
1101 | else if (redraw) |
---|
1102 | tasklist_draw_task (task->group && is_task_really_visible (task->group) |
---|
1103 | ? task->group : task, NULL); |
---|
1104 | |
---|
1105 | break; |
---|
1106 | case GWMH_NOTIFY_NEW: |
---|
1107 | tasklist_task_new (gwmh_task, tasklist); |
---|
1108 | tasklist_layout_tasklist (tasklist); |
---|
1109 | break; |
---|
1110 | case GWMH_NOTIFY_DESTROY: |
---|
1111 | tasklist_task_destroy (gwmh_task, tasklist); |
---|
1112 | break; |
---|
1113 | default: |
---|
1114 | d(g_print ("Unknown ntype: %d\n", ntype)); |
---|
1115 | } |
---|
1116 | |
---|
1117 | return TRUE; |
---|
1118 | } |
---|
1119 | |
---|
1120 | /* Show the task if need. Return TRUE if so */ |
---|
1121 | static gboolean |
---|
1122 | show_task (Tasklist *tasklist, TasklistTask *task) |
---|
1123 | { |
---|
1124 | if (!GWMH_TASK_ICONIFIED (task->gwmh_task) && GWMH_TASK_FOCUSED (task->gwmh_task)) |
---|
1125 | return FALSE; |
---|
1126 | |
---|
1127 | |
---|
1128 | if (!(tasklist->config.move_to_current && GWMH_TASK_ICONIFIED (task->gwmh_task))) { |
---|
1129 | GwmhDesk *desk_info; |
---|
1130 | desk_info = gwmh_desk_get_config (); |
---|
1131 | |
---|
1132 | if (task->gwmh_task->desktop != desk_info->current_desktop || |
---|
1133 | task->gwmh_task->harea != desk_info->current_harea || |
---|
1134 | task->gwmh_task->varea != desk_info->current_varea) { |
---|
1135 | gwmh_desk_set_current_area (task->gwmh_task->desktop, |
---|
1136 | task->gwmh_task->harea, |
---|
1137 | task->gwmh_task->varea); |
---|
1138 | } |
---|
1139 | } |
---|
1140 | |
---|
1141 | gwmh_task_show (task->gwmh_task); |
---|
1142 | #if 0 |
---|
1143 | /* Why is a focus needed here? |
---|
1144 | gwmh_task_show is supposed to give focus */ |
---|
1145 | |
---|
1146 | /* |
---|
1147 | * i think this is a sawfish bug: when "give |
---|
1148 | * uniconised windows focused" is unchecked it |
---|
1149 | * probably doesn't reassign focus. -- jacob |
---|
1150 | */ |
---|
1151 | |
---|
1152 | gwmh_task_focus (task->gwmh_task); |
---|
1153 | gwmh_task_focus (task->gwmh_task); |
---|
1154 | |
---|
1155 | #endif |
---|
1156 | return TRUE; |
---|
1157 | } |
---|
1158 | |
---|
1159 | /* This routine gets called when the mouse is pressed */ |
---|
1160 | static gboolean |
---|
1161 | cb_button_press_event (GtkWidget *widget, GdkEventButton *event, Tasklist *tasklist) |
---|
1162 | { |
---|
1163 | TasklistTask *task; |
---|
1164 | |
---|
1165 | task = task_get_xy (tasklist, (gint)event->x, (gint)event->y); |
---|
1166 | |
---|
1167 | if (!task) |
---|
1168 | return FALSE; |
---|
1169 | |
---|
1170 | if (event->button == 1) { |
---|
1171 | if (task->task_group) |
---|
1172 | tasklist_group_popup (task, event->button, event->time); |
---|
1173 | else if (! show_task (tasklist, task)) |
---|
1174 | gwmh_task_iconify (task->gwmh_task); |
---|
1175 | |
---|
1176 | return TRUE; |
---|
1177 | } |
---|
1178 | |
---|
1179 | if (event->button == 3) { |
---|
1180 | gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), |
---|
1181 | "button_press_event"); |
---|
1182 | tasklist_menu_popup (task, event->button, event->time); |
---|
1183 | return TRUE; |
---|
1184 | } |
---|
1185 | |
---|
1186 | return FALSE; |
---|
1187 | } |
---|
1188 | |
---|
1189 | static void |
---|
1190 | cb_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time, Tasklist *tasklist) |
---|
1191 | { |
---|
1192 | if (tasklist->motion_timeout) { |
---|
1193 | gtk_timeout_remove (tasklist->motion_timeout); |
---|
1194 | tasklist->motion_timeout = 0; |
---|
1195 | tasklist->motion_task = NULL; |
---|
1196 | } |
---|
1197 | } |
---|
1198 | |
---|
1199 | static gboolean |
---|
1200 | cb_motion_timeout (gpointer user_data) |
---|
1201 | { |
---|
1202 | Tasklist *tasklist = user_data; |
---|
1203 | |
---|
1204 | if (tasklist->motion_task && !(tasklist->motion_task->task_group)) { |
---|
1205 | show_task (tasklist, tasklist->motion_task); |
---|
1206 | } |
---|
1207 | |
---|
1208 | tasklist->motion_timeout = 0; |
---|
1209 | tasklist->motion_task = NULL; |
---|
1210 | |
---|
1211 | return FALSE; |
---|
1212 | } |
---|
1213 | |
---|
1214 | /* This routine gets called when user drag something over the tasklist */ |
---|
1215 | static gboolean |
---|
1216 | cb_drag_motion (GtkWidget *widget, GdkDragContext *context, int x, int y, guint time, Tasklist *tasklist) |
---|
1217 | { |
---|
1218 | TasklistTask *task; |
---|
1219 | |
---|
1220 | gdk_drag_status (context, 0, time); |
---|
1221 | |
---|
1222 | task = task_get_xy (tasklist, x, y); |
---|
1223 | |
---|
1224 | if (task != tasklist->motion_task) { |
---|
1225 | |
---|
1226 | if (tasklist->motion_timeout) { |
---|
1227 | gtk_timeout_remove (tasklist->motion_timeout); |
---|
1228 | } |
---|
1229 | |
---|
1230 | tasklist->motion_task = task; |
---|
1231 | |
---|
1232 | if (task) { |
---|
1233 | tasklist->motion_timeout = gtk_timeout_add (MOTION_TIMEOUT, cb_motion_timeout, tasklist); |
---|
1234 | } else { |
---|
1235 | tasklist->motion_timeout = 0; |
---|
1236 | } |
---|
1237 | } |
---|
1238 | |
---|
1239 | return TRUE; |
---|
1240 | } |
---|
1241 | |
---|
1242 | /* FIXME: This routine is one of the ugliest ones in existence, |
---|
1243 | * gtk purists should not look at it. This should get rewritten such |
---|
1244 | * that each label has a widget with an inputonly window OR draw the |
---|
1245 | * tooltips ourselves. However for the time being this is better then |
---|
1246 | * nothing I suppose. Feel free to flame me for this. Tooltips have |
---|
1247 | * been one of the more requested features for a LONG time. |
---|
1248 | * |
---|
1249 | * -George |
---|
1250 | */ |
---|
1251 | static gboolean |
---|
1252 | cb_area_event (GtkWidget *widget, GdkEvent *event, Tasklist *tasklist) |
---|
1253 | { |
---|
1254 | GSList *temp_tasks, *temp; |
---|
1255 | TasklistTask *task; |
---|
1256 | |
---|
1257 | if ((event->type == GDK_LEAVE_NOTIFY || |
---|
1258 | event->type == GDK_ENTER_NOTIFY) && |
---|
1259 | event->crossing.detail == GDK_NOTIFY_INFERIOR) |
---|
1260 | return FALSE; |
---|
1261 | |
---|
1262 | if (event->type == GDK_LEAVE_NOTIFY) { |
---|
1263 | gtk_tooltips_set_tip (tasklist->tooltips, |
---|
1264 | tasklist->fake_tooltip_widget, |
---|
1265 | NULL, NULL); |
---|
1266 | tasklist->tooltip_task = NULL; |
---|
1267 | return FALSE; |
---|
1268 | } |
---|
1269 | |
---|
1270 | if (event->type == GDK_MOTION_NOTIFY || |
---|
1271 | event->type == GDK_ENTER_NOTIFY) { |
---|
1272 | int x, y; |
---|
1273 | |
---|
1274 | if (event->type == GDK_MOTION_NOTIFY) { |
---|
1275 | x = event->motion.x; |
---|
1276 | y = event->motion.y; |
---|
1277 | } else { |
---|
1278 | x = event->crossing.x; |
---|
1279 | y = event->crossing.y; |
---|
1280 | } |
---|
1281 | |
---|
1282 | temp_tasks = tasklist->vtasks; |
---|
1283 | for (temp = temp_tasks; temp != NULL; temp = temp->next) { |
---|
1284 | task = (TasklistTask *)temp->data; |
---|
1285 | |
---|
1286 | if (!is_task_really_visible (task)) |
---|
1287 | continue; |
---|
1288 | |
---|
1289 | if (x >= task->x && |
---|
1290 | x <= task->x + task->width && |
---|
1291 | y >= task->y && |
---|
1292 | y <= task->y + task->height) { |
---|
1293 | /* This is it, and this is |
---|
1294 | * also the utterly evil part */ |
---|
1295 | if (tasklist->tooltip_task != task) { |
---|
1296 | char *label; |
---|
1297 | gboolean ignore; |
---|
1298 | gpointer old_data; |
---|
1299 | GdkEvent new_event = { 0 }; |
---|
1300 | GtkWidget *fake = tasklist->fake_tooltip_widget; |
---|
1301 | |
---|
1302 | tasklist->tooltip_task = task; |
---|
1303 | |
---|
1304 | fake->allocation.x = task->x; |
---|
1305 | fake->allocation.y = task->y; |
---|
1306 | fake->allocation.width = task->width; |
---|
1307 | fake->allocation.height = task->height; |
---|
1308 | fake->window = tasklist->area->window; |
---|
1309 | |
---|
1310 | label = tasklist_task_get_label |
---|
1311 | (task, 0, task->task_group); |
---|
1312 | |
---|
1313 | gtk_tooltips_set_tip |
---|
1314 | (tasklist->tooltips, |
---|
1315 | fake, label, NULL); |
---|
1316 | |
---|
1317 | g_free (label); |
---|
1318 | |
---|
1319 | if (event->type == GDK_ENTER_NOTIFY) { |
---|
1320 | new_event = *event; |
---|
1321 | } else { |
---|
1322 | new_event.type = GDK_ENTER_NOTIFY; |
---|
1323 | new_event.any.window = fake->window; |
---|
1324 | } |
---|
1325 | |
---|
1326 | /* EEEEEEEEEEEEEVIL, this is the only |
---|
1327 | * way to make gtk draw the tooltips |
---|
1328 | * short of drawing them ourselves. |
---|
1329 | * The tooltips unfortunately do a whole |
---|
1330 | * bunch of internal checking so we abuse |
---|
1331 | * the area window. This way it will |
---|
1332 | * appear almost as if the window belongs |
---|
1333 | * to the fake rather then to the area, |
---|
1334 | * at least for the duration of this call. */ |
---|
1335 | old_data = fake->window->user_data; |
---|
1336 | fake->window->user_data = fake; |
---|
1337 | gtk_signal_emit_by_name (GTK_OBJECT (fake), |
---|
1338 | "event", |
---|
1339 | &new_event, |
---|
1340 | &ignore); |
---|
1341 | fake->window->user_data = old_data; |
---|
1342 | } |
---|
1343 | break; |
---|
1344 | } |
---|
1345 | } |
---|
1346 | /* No task found, so we want to turn off the tooltip */ |
---|
1347 | if (temp == NULL) { |
---|
1348 | gtk_tooltips_set_tip (tasklist->tooltips, |
---|
1349 | tasklist->fake_tooltip_widget, |
---|
1350 | NULL, NULL); |
---|
1351 | tasklist->tooltip_task = NULL; |
---|
1352 | return FALSE; |
---|
1353 | } |
---|
1354 | } |
---|
1355 | |
---|
1356 | return FALSE; |
---|
1357 | } |
---|
1358 | |
---|
1359 | /* This routine gets called when the tasklist is exposed */ |
---|
1360 | static gboolean |
---|
1361 | cb_expose_event (GtkWidget *widget, GdkEventExpose *event, Tasklist *tasklist) |
---|
1362 | { |
---|
1363 | GSList *temp_tasks, *temp; |
---|
1364 | TasklistTask *task; |
---|
1365 | |
---|
1366 | temp_tasks = tasklist->vtasks; |
---|
1367 | |
---|
1368 | gtk_paint_box (tasklist->area->style, tasklist->area->window, |
---|
1369 | tasklist->area->state, |
---|
1370 | tasklist->config.sunken?GTK_SHADOW_IN:GTK_SHADOW_NONE, |
---|
1371 | &event->area, tasklist->area, "button", |
---|
1372 | 0, 0, -1, -1); |
---|
1373 | |
---|
1374 | for (temp = temp_tasks; temp != NULL; temp = temp->next) { |
---|
1375 | GdkRectangle rect, dest; |
---|
1376 | task = (TasklistTask *)temp->data; |
---|
1377 | |
---|
1378 | rect.x = task->x; |
---|
1379 | rect.y = task->y; |
---|
1380 | rect.width = task->width; |
---|
1381 | rect.height = task->height; |
---|
1382 | |
---|
1383 | if(gdk_rectangle_intersect(&event->area, &rect, &dest)) |
---|
1384 | tasklist_draw_task (task, &dest); |
---|
1385 | } |
---|
1386 | |
---|
1387 | return FALSE; |
---|
1388 | } |
---|
1389 | |
---|
1390 | /* This routine gets called when the user selects "properties" */ |
---|
1391 | static void |
---|
1392 | cb_properties (AppletWidget *applet, Tasklist *tasklist) |
---|
1393 | { |
---|
1394 | tasklist_display_properties (tasklist); |
---|
1395 | } |
---|
1396 | |
---|
1397 | /* This routine gets called when the user selects "about" */ |
---|
1398 | static void |
---|
1399 | cb_about (AppletWidget *applet, Tasklist *tasklist) |
---|
1400 | { |
---|
1401 | |
---|
1402 | const char *authors[] = { |
---|
1403 | "Anders Carlsson (andersca@gnu.org)", |
---|
1404 | "Miguel de Icaza (miguel@ximian.com)", |
---|
1405 | "Jacob Berkman (jacob@ximian.com)", |
---|
1406 | "George Lebl (jirka@5z.com)", |
---|
1407 | NULL |
---|
1408 | }; |
---|
1409 | |
---|
1410 | /* Stop the about box from being shown twice at once */ |
---|
1411 | if (tasklist->about_dialog != NULL) |
---|
1412 | { |
---|
1413 | gtk_widget_show_now (tasklist->about_dialog); |
---|
1414 | gdk_window_raise (tasklist->about_dialog->window); |
---|
1415 | return; |
---|
1416 | } |
---|
1417 | |
---|
1418 | tasklist->about_dialog = gnome_about_new ( |
---|
1419 | "Gnome Tasklist", |
---|
1420 | VERSION, |
---|
1421 | _("Copyright (C) 1999 Anders Carlsson"), |
---|
1422 | authors, |
---|
1423 | _("A tasklist for the GNOME desktop environment.\nIcons by Tuomas Kuosmanen (tigert@gimp.org)."), |
---|
1424 | NULL); |
---|
1425 | gtk_signal_connect (GTK_OBJECT(tasklist->about_dialog), "destroy", |
---|
1426 | GTK_SIGNAL_FUNC(gtk_widget_destroyed), &tasklist->about_dialog); |
---|
1427 | |
---|
1428 | gtk_widget_show_now (tasklist->about_dialog); |
---|
1429 | |
---|
1430 | if (tasklist->about_dialog->window != NULL) |
---|
1431 | gdk_window_raise (tasklist->about_dialog->window); |
---|
1432 | } |
---|
1433 | |
---|
1434 | /* Ignore mouse button 1 clicks */ |
---|
1435 | static gboolean |
---|
1436 | ignore_1st_click (GtkWidget *widget, GdkEvent *event, Tasklist *tasklist) |
---|
1437 | { |
---|
1438 | GdkEventButton *buttonevent = (GdkEventButton *)event; |
---|
1439 | |
---|
1440 | if (event->type == GDK_BUTTON_PRESS && |
---|
1441 | buttonevent->button == 1) { |
---|
1442 | if (buttonevent->window != tasklist->area->window) |
---|
1443 | buttonevent->button = 2; |
---|
1444 | } |
---|
1445 | if (event->type == GDK_BUTTON_RELEASE && |
---|
1446 | buttonevent->button == 1) { |
---|
1447 | if (buttonevent->window != tasklist->area->window) |
---|
1448 | buttonevent->button = 2; |
---|
1449 | } |
---|
1450 | |
---|
1451 | return FALSE; |
---|
1452 | } |
---|
1453 | |
---|
1454 | /* Changes size of the applet */ |
---|
1455 | void |
---|
1456 | tasklist_change_size (Tasklist *tasklist, gboolean layout, int fullwidth) |
---|
1457 | { |
---|
1458 | int handle_width = 0; |
---|
1459 | int handle_height = 0; |
---|
1460 | int width = 0; |
---|
1461 | int height = 0; |
---|
1462 | |
---|
1463 | |
---|
1464 | switch (applet_widget_get_panel_orient (APPLET_WIDGET (tasklist->applet))) { |
---|
1465 | case ORIENT_UP: |
---|
1466 | case ORIENT_DOWN: |
---|
1467 | width = tasklist->horz_width; |
---|
1468 | handle_width = tasklist->horz_width + DRAG_HANDLE_SIZE; |
---|
1469 | height = handle_height = get_horz_rows (tasklist) * ROW_HEIGHT; |
---|
1470 | |
---|
1471 | GTK_HANDLE_BOX (tasklist->handle)->handle_position = GTK_POS_LEFT; |
---|
1472 | break; |
---|
1473 | case ORIENT_LEFT: |
---|
1474 | case ORIENT_RIGHT: |
---|
1475 | width = tasklist->config.follow_panel_size |
---|
1476 | ? tasklist->panel_size |
---|
1477 | : tasklist->config.vert_width; |
---|
1478 | |
---|
1479 | if (tasklist->config.vert_width_full) { |
---|
1480 | if (fullwidth < 0) |
---|
1481 | fullwidth = max_width (tasklist->vtasks); |
---|
1482 | |
---|
1483 | width = MAX (width, fullwidth); |
---|
1484 | } |
---|
1485 | |
---|
1486 | handle_width = width; |
---|
1487 | handle_height = tasklist->vert_height + DRAG_HANDLE_SIZE; |
---|
1488 | height = tasklist->vert_height; |
---|
1489 | |
---|
1490 | GTK_HANDLE_BOX (tasklist->handle)->handle_position = GTK_POS_TOP; |
---|
1491 | } |
---|
1492 | |
---|
1493 | gtk_widget_set_usize (tasklist->handle, handle_width, handle_height); |
---|
1494 | gtk_drawing_area_size (GTK_DRAWING_AREA (tasklist->area), width, height); |
---|
1495 | |
---|
1496 | if (layout) |
---|
1497 | tasklist_layout_tasklist (tasklist); |
---|
1498 | } |
---|
1499 | |
---|
1500 | /* Called when the panel's orient changes */ |
---|
1501 | static void |
---|
1502 | cb_change_orient (GtkWidget *widget, GNOME_Panel_OrientType orient, Tasklist *tasklist) |
---|
1503 | { |
---|
1504 | tasklist->orient = orient; |
---|
1505 | |
---|
1506 | /* Change size accordingly */ |
---|
1507 | tasklist_change_size (tasklist, TRUE, -1); |
---|
1508 | } |
---|
1509 | |
---|
1510 | static void |
---|
1511 | cb_change_pixel_size (GtkWidget *widget, int size, Tasklist *tasklist) |
---|
1512 | { |
---|
1513 | tasklist->panel_size = size; |
---|
1514 | |
---|
1515 | /* Change size accordingly */ |
---|
1516 | if(tasklist->config.follow_panel_size) |
---|
1517 | tasklist_change_size (tasklist, TRUE, -1); |
---|
1518 | } |
---|
1519 | |
---|
1520 | static void |
---|
1521 | cb_help (AppletWidget *w, Tasklist *tasklist) |
---|
1522 | { |
---|
1523 | GnomeHelpMenuEntry help_entry = { "tasklist_applet", |
---|
1524 | "index.html" }; |
---|
1525 | gnome_help_display(NULL, &help_entry); |
---|
1526 | } |
---|
1527 | |
---|
1528 | static void |
---|
1529 | tasklist_destroy (GtkObject *applet_widget, Tasklist *tasklist) |
---|
1530 | { |
---|
1531 | gwmh_task_notifier_remove (tasklist->task_notifier_id); |
---|
1532 | gwmh_desk_notifier_remove (tasklist->desk_notifier_id); |
---|
1533 | |
---|
1534 | tasklist->task_notifier_id = -1; |
---|
1535 | tasklist->desk_notifier_id = -1; |
---|
1536 | |
---|
1537 | if (tasklist->layout_idle != 0) { |
---|
1538 | gtk_idle_remove (tasklist->layout_idle); |
---|
1539 | tasklist->layout_idle = 0; |
---|
1540 | } |
---|
1541 | |
---|
1542 | if (tasklist->motion_timeout) { |
---|
1543 | gtk_timeout_remove (tasklist->motion_timeout); |
---|
1544 | tasklist->motion_timeout = 0; |
---|
1545 | tasklist->motion_task = NULL; |
---|
1546 | } |
---|
1547 | |
---|
1548 | if (tasklist->prop) |
---|
1549 | gtk_widget_destroy (tasklist->prop); |
---|
1550 | tasklist->prop = NULL; |
---|
1551 | |
---|
1552 | if (tasklist->about_dialog) |
---|
1553 | gtk_widget_destroy (tasklist->about_dialog); |
---|
1554 | tasklist->about_dialog = NULL; |
---|
1555 | |
---|
1556 | if (tasklist->unknown_icon != NULL) { |
---|
1557 | if (tasklist->unknown_icon->normal != NULL) { |
---|
1558 | gdk_pixbuf_unref (tasklist->unknown_icon->normal); |
---|
1559 | tasklist->unknown_icon->normal = NULL; |
---|
1560 | } |
---|
1561 | if (tasklist->unknown_icon->minimized != NULL) { |
---|
1562 | gdk_pixbuf_unref (tasklist->unknown_icon->minimized); |
---|
1563 | tasklist->unknown_icon->minimized = NULL; |
---|
1564 | } |
---|
1565 | g_free (tasklist->unknown_icon); |
---|
1566 | tasklist->unknown_icon = NULL; |
---|
1567 | } |
---|
1568 | |
---|
1569 | g_slist_free (tasklist->vtasks); |
---|
1570 | tasklist->vtasks = NULL; |
---|
1571 | |
---|
1572 | #ifndef APPLET_COMPILE_AS_PROCESS |
---|
1573 | #warning Here we save peoples memory by making this a shlib applet and leaking whatever we possibly can! |
---|
1574 | #endif |
---|
1575 | |
---|
1576 | if (tasklist->fake_tooltip_widget != NULL) { |
---|
1577 | tasklist->fake_tooltip_widget->window = NULL; |
---|
1578 | gtk_widget_unref (tasklist->fake_tooltip_widget); |
---|
1579 | tasklist->fake_tooltip_widget = NULL; |
---|
1580 | } |
---|
1581 | |
---|
1582 | if (tasklist->tooltips != NULL) { |
---|
1583 | gtk_object_destroy (GTK_OBJECT (tasklist->tooltips)); |
---|
1584 | tasklist->tooltips = NULL; |
---|
1585 | } |
---|
1586 | |
---|
1587 | if (tasklist->groups != NULL) { |
---|
1588 | /* FIXME: we leak EVERYTHING here */ |
---|
1589 | g_hash_table_destroy (tasklist->groups); |
---|
1590 | tasklist->groups = NULL; |
---|
1591 | } |
---|
1592 | if (tasklist->tasks != NULL) { |
---|
1593 | /* FIXME: we leak EVERYTHING here */ |
---|
1594 | g_hash_table_destroy (tasklist->tasks); |
---|
1595 | tasklist->tasks = NULL; |
---|
1596 | } |
---|
1597 | |
---|
1598 | g_free (tasklist); |
---|
1599 | } |
---|
1600 | |
---|
1601 | /* Create the applet */ |
---|
1602 | static Tasklist * |
---|
1603 | tasklist_new (void) |
---|
1604 | { |
---|
1605 | Tasklist *tasklist; |
---|
1606 | GtkWidget *hbox; |
---|
1607 | |
---|
1608 | tasklist = g_new0 (Tasklist, 1); |
---|
1609 | tasklist->panel_size = 48; |
---|
1610 | tasklist->horz_width = 0; |
---|
1611 | tasklist->vert_height = 0; |
---|
1612 | |
---|
1613 | tasklist->applet = applet_widget_new ("tasklist_applet"); |
---|
1614 | if (!tasklist->applet) { |
---|
1615 | g_warning (_("Tasklist: Unable to create applet widget")); |
---|
1616 | g_free (tasklist); |
---|
1617 | return NULL; |
---|
1618 | } |
---|
1619 | |
---|
1620 | /* Some evil tooltip stuff, this is some pretty evil stuff */ |
---|
1621 | tasklist->tooltips = gtk_tooltips_new (); |
---|
1622 | tasklist->fake_tooltip_widget = gtk_type_new (gtk_widget_get_type ()); |
---|
1623 | GTK_WIDGET_SET_FLAGS (tasklist->fake_tooltip_widget, GTK_NO_WINDOW); |
---|
1624 | GTK_WIDGET_SET_FLAGS (tasklist->fake_tooltip_widget, GTK_VISIBLE); |
---|
1625 | GTK_WIDGET_SET_FLAGS (tasklist->fake_tooltip_widget, GTK_MAPPED); |
---|
1626 | gtk_widget_ref (tasklist->fake_tooltip_widget); |
---|
1627 | gtk_object_sink (GTK_OBJECT (tasklist->fake_tooltip_widget)); |
---|
1628 | tasklist->tooltip_task = NULL; |
---|
1629 | |
---|
1630 | hbox = gtk_hbox_new (FALSE, 0); |
---|
1631 | gtk_widget_show (hbox); |
---|
1632 | |
---|
1633 | tasklist->handle = gtk_handle_box_new (); |
---|
1634 | gtk_signal_connect (GTK_OBJECT (tasklist->handle), "event", |
---|
1635 | GTK_SIGNAL_FUNC (ignore_1st_click), tasklist); |
---|
1636 | |
---|
1637 | tasklist->area = gtk_drawing_area_new (); |
---|
1638 | |
---|
1639 | gtk_widget_ensure_style (tasklist->area); |
---|
1640 | tasklist->unknown_icon = g_new (TasklistIcon, 1); |
---|
1641 | tasklist->unknown_icon->normal = gdk_pixbuf_new_from_xpm_data (unknown_xpm); |
---|
1642 | tasklist->unknown_icon->minimized = tasklist_icon_create_minimized_icon (tasklist, tasklist->unknown_icon->normal); |
---|
1643 | |
---|
1644 | #if 0 |
---|
1645 | gtk_container_add (GTK_CONTAINER (tasklist->handle), tasklist->area); |
---|
1646 | #endif |
---|
1647 | |
---|
1648 | /* we must bind signals BEFORE applet_widget_add to avoid |
---|
1649 | * a race */ |
---|
1650 | gtk_signal_connect (GTK_OBJECT (tasklist->applet), "change-orient", |
---|
1651 | GTK_SIGNAL_FUNC (cb_change_orient), tasklist); |
---|
1652 | gtk_signal_connect (GTK_OBJECT (tasklist->applet), "save-session", |
---|
1653 | GTK_SIGNAL_FUNC (tasklist_write_config), tasklist); |
---|
1654 | gtk_signal_connect (GTK_OBJECT (tasklist->applet), "change-pixel-size", |
---|
1655 | GTK_SIGNAL_FUNC (cb_change_pixel_size), tasklist); |
---|
1656 | |
---|
1657 | gtk_widget_set_events (tasklist->area, GDK_EXPOSURE_MASK | |
---|
1658 | GDK_BUTTON_PRESS_MASK | |
---|
1659 | GDK_BUTTON_RELEASE_MASK | |
---|
1660 | GDK_ENTER_NOTIFY_MASK | |
---|
1661 | GDK_LEAVE_NOTIFY_MASK | |
---|
1662 | GDK_POINTER_MOTION_MASK); |
---|
1663 | gtk_signal_connect (GTK_OBJECT (tasklist->area), "event", |
---|
1664 | GTK_SIGNAL_FUNC (cb_area_event), tasklist); |
---|
1665 | gtk_signal_connect (GTK_OBJECT (tasklist->area), "expose_event", |
---|
1666 | GTK_SIGNAL_FUNC (cb_expose_event), tasklist); |
---|
1667 | gtk_signal_connect (GTK_OBJECT (tasklist->area), "button_press_event", |
---|
1668 | GTK_SIGNAL_FUNC (cb_button_press_event), tasklist); |
---|
1669 | gtk_signal_connect (GTK_OBJECT (tasklist->area), "drag_motion", |
---|
1670 | GTK_SIGNAL_FUNC (cb_drag_motion), tasklist); |
---|
1671 | gtk_signal_connect (GTK_OBJECT (tasklist->area), "drag_leave", |
---|
1672 | GTK_SIGNAL_FUNC (cb_drag_leave), tasklist); |
---|
1673 | |
---|
1674 | gtk_drag_dest_set (GTK_WIDGET (tasklist->area), 0, |
---|
1675 | NULL, 0, GDK_ACTION_COPY); |
---|
1676 | |
---|
1677 | /* |
---|
1678 | * we add the area *after* the widget so that we get events on it |
---|
1679 | */ |
---|
1680 | gtk_container_add (GTK_CONTAINER (hbox), tasklist->handle); |
---|
1681 | applet_widget_add (APPLET_WIDGET (tasklist->applet), hbox); |
---|
1682 | gtk_container_add (GTK_CONTAINER (tasklist->handle), tasklist->area); |
---|
1683 | |
---|
1684 | tasklist_read_config (tasklist); |
---|
1685 | |
---|
1686 | if ( ! tasklist->config.enable_tooltips) |
---|
1687 | gtk_tooltips_disable (tasklist->tooltips); |
---|
1688 | |
---|
1689 | applet_widget_register_stock_callback ( |
---|
1690 | APPLET_WIDGET (tasklist->applet), |
---|
1691 | "properties", |
---|
1692 | GNOME_STOCK_MENU_PROP, |
---|
1693 | _("Properties..."), |
---|
1694 | (AppletCallbackFunc) cb_properties, |
---|
1695 | tasklist); |
---|
1696 | |
---|
1697 | applet_widget_register_stock_callback ( |
---|
1698 | APPLET_WIDGET (tasklist->applet), |
---|
1699 | "help", |
---|
1700 | GNOME_STOCK_PIXMAP_HELP, |
---|
1701 | _("Help"), |
---|
1702 | (AppletCallbackFunc) cb_help, |
---|
1703 | tasklist); |
---|
1704 | |
---|
1705 | applet_widget_register_stock_callback ( |
---|
1706 | APPLET_WIDGET (tasklist->applet), |
---|
1707 | "about", |
---|
1708 | GNOME_STOCK_MENU_ABOUT, |
---|
1709 | _("About..."), |
---|
1710 | (AppletCallbackFunc) cb_about, |
---|
1711 | tasklist); |
---|
1712 | |
---|
1713 | tasklist->panel_size = applet_widget_get_panel_pixel_size(APPLET_WIDGET(tasklist->applet)); |
---|
1714 | tasklist->orient = applet_widget_get_panel_orient(APPLET_WIDGET(tasklist->applet)); |
---|
1715 | |
---|
1716 | tasklist->task_notifier_id = gwmh_task_notifier_add (task_notifier, tasklist); |
---|
1717 | tasklist->desk_notifier_id = gwmh_desk_notifier_add (desk_notifier, tasklist); |
---|
1718 | |
---|
1719 | gtk_signal_connect (GTK_OBJECT (tasklist->applet), "destroy", |
---|
1720 | GTK_SIGNAL_FUNC (tasklist_destroy), tasklist); |
---|
1721 | |
---|
1722 | gtk_widget_show_all (tasklist->area); |
---|
1723 | gtk_widget_show_all (tasklist->handle); |
---|
1724 | |
---|
1725 | tasklist_change_size (tasklist, TRUE, -1); |
---|
1726 | |
---|
1727 | tasklist->tasks = g_hash_table_new (g_direct_hash, g_direct_equal); |
---|
1728 | tasklist->groups = g_hash_table_new (g_str_hash, g_str_equal); |
---|
1729 | |
---|
1730 | g_list_foreach (gwmh_task_list_get (), |
---|
1731 | tasklist_task_new_iterator, |
---|
1732 | tasklist); |
---|
1733 | |
---|
1734 | return tasklist; |
---|
1735 | } |
---|
1736 | |
---|
1737 | static void |
---|
1738 | tasklist_init (void) |
---|
1739 | { |
---|
1740 | gwmh_init (); |
---|
1741 | } |
---|
1742 | |
---|
1743 | #ifdef APPLET_COMPILE_AS_PROCESS |
---|
1744 | gint |
---|
1745 | main (gint argc, gchar *argv[]) |
---|
1746 | { |
---|
1747 | Tasklist *tasklist; |
---|
1748 | |
---|
1749 | /* Initialize i18n */ |
---|
1750 | bindtextdomain (PACKAGE, GNOMELOCALEDIR); |
---|
1751 | textdomain (PACKAGE); |
---|
1752 | |
---|
1753 | applet_widget_init ("tasklist_applet", |
---|
1754 | VERSION, |
---|
1755 | argc, argv, |
---|
1756 | NULL, 0, NULL); |
---|
1757 | |
---|
1758 | gdk_rgb_init (); |
---|
1759 | |
---|
1760 | gnome_window_icon_set_default_from_file (GNOME_ICONDIR"/gnome-tasklist.png"); |
---|
1761 | |
---|
1762 | gtk_widget_set_default_colormap (gdk_rgb_get_cmap ()); |
---|
1763 | gtk_widget_set_default_visual (gdk_rgb_get_visual ()); |
---|
1764 | |
---|
1765 | tasklist_init (); |
---|
1766 | |
---|
1767 | tasklist = tasklist_new (); |
---|
1768 | |
---|
1769 | gtk_widget_show_all (tasklist->applet); |
---|
1770 | |
---|
1771 | applet_widget_gtk_main (); |
---|
1772 | |
---|
1773 | return 0; |
---|
1774 | } |
---|
1775 | #else |
---|
1776 | static GtkWidget * |
---|
1777 | make_new_applet (const char *goad_id) |
---|
1778 | { |
---|
1779 | static int inited = 0; |
---|
1780 | Tasklist *tasklist; |
---|
1781 | |
---|
1782 | if (!inited){ |
---|
1783 | tasklist_init (); |
---|
1784 | inited = 1; |
---|
1785 | } |
---|
1786 | tasklist = tasklist_new (); |
---|
1787 | |
---|
1788 | if (!tasklist) |
---|
1789 | return NULL; |
---|
1790 | |
---|
1791 | gtk_widget_show_all (tasklist->applet); |
---|
1792 | |
---|
1793 | return tasklist->applet; |
---|
1794 | } |
---|
1795 | |
---|
1796 | static CORBA_Object |
---|
1797 | activator (PortableServer_POA poa, |
---|
1798 | const char *goad_id, |
---|
1799 | const char **params, |
---|
1800 | gpointer *impl_ptr, |
---|
1801 | CORBA_Environment *ev) |
---|
1802 | { |
---|
1803 | GtkWidget *widget; |
---|
1804 | |
---|
1805 | widget = make_new_applet (goad_id); |
---|
1806 | if (widget == NULL) { |
---|
1807 | g_warning (_("Don't know how to activate `%s'\n"), goad_id); |
---|
1808 | return CORBA_OBJECT_NIL; |
---|
1809 | } |
---|
1810 | |
---|
1811 | return applet_widget_corba_activate (widget, poa, goad_id, |
---|
1812 | params, impl_ptr, ev); |
---|
1813 | } |
---|
1814 | static void |
---|
1815 | deactivator (PortableServer_POA poa, |
---|
1816 | const char *goad_id, |
---|
1817 | gpointer impl_ptr, |
---|
1818 | CORBA_Environment *ev) |
---|
1819 | { |
---|
1820 | applet_widget_corba_deactivate (poa, goad_id, impl_ptr, ev); |
---|
1821 | } |
---|
1822 | |
---|
1823 | static const char *repo_id[]={ "IDL:GNOME/Applet:1.0", NULL }; |
---|
1824 | static GnomePluginObject applets_list[] = { |
---|
1825 | { repo_id, "tasklist_applet", NULL, "Task list applet", |
---|
1826 | &activator, &deactivator }, |
---|
1827 | { NULL } |
---|
1828 | }; |
---|
1829 | |
---|
1830 | GnomePlugin GNOME_Plugin_info = { |
---|
1831 | applets_list, |
---|
1832 | NULL |
---|
1833 | }; |
---|
1834 | |
---|
1835 | #endif |
---|