53
GtkWidget *button, *label;
66
unsigned int focused:1;
67
unsigned int iconified:1;
68
unsigned int urgency:1;
69
unsigned int using_netwm_icon:1;
71
unsigned int flash_state:1;
74
typedef struct _taskbar{
79
GHashTable *task_list;
80
GtkWidget *bar, *menu;
81
GdkPixbuf *gen_pixbuf;
82
GtkStateType normal_state;
83
GtkStateType focused_state;
98
gboolean accept_skip_pager;// : 1;
99
gboolean show_iconified;// : 1;
100
gboolean show_mapped;// : 1;
101
gboolean show_all_desks;// : 1;
102
gboolean tooltips;// : 1;
103
gboolean icons_only;// : 1;
104
gboolean use_mouse_wheel;// : 1;
105
gboolean use_urgency_hint;// : 1;
106
gboolean flat_button;
53
/* Structure representing a class. This comes from WM_CLASS, and should identify windows that come from an application. */
54
typedef struct _task_class {
55
struct _task_class * res_class_flink; /* Forward link */
56
char * res_class; /* Class name */
57
struct _task * res_class_head; /* Head of list of tasks with this class */
58
struct _task * visible_task; /* Task that is visible in current desktop, if any */
59
char * visible_name; /* Name that will be visible for grouped tasks */
60
int visible_count; /* Count of tasks that are visible in current desktop */
63
/* Structure representing a "task", an open window. */
64
typedef struct _task {
65
struct _task * task_flink; /* Forward link to next task in X window ID order */
66
struct _taskbar * tb; /* Back pointer to taskbar */
67
Window win; /* X window ID */
68
char * name; /* Taskbar label when normal, from WM_NAME or NET_WM_NAME */
69
char * name_iconified; /* Taskbar label when iconified */
70
Atom name_source; /* Atom that is the source of taskbar label */
71
TaskClass * res_class; /* Class, from WM_CLASS */
72
struct _task * res_class_flink; /* Forward link to task in same class */
73
GtkWidget * button; /* Button representing task in taskbar */
74
GtkWidget * image; /* Icon for task, child of button */
75
Atom image_source; /* Atom that is the source of taskbar icon */
76
GtkWidget * label; /* Label for task, child of button */
77
int desktop; /* Desktop that contains task, needed to switch to it on Raise */
78
guint flash_timeout; /* Timer for urgency notification */
79
unsigned int focused : 1; /* True if window has focus */
80
unsigned int iconified : 1; /* True if window is iconified, from WM_STATE */
81
unsigned int urgency : 1; /* True if window has an urgency hint, from WM_HINTS */
82
unsigned int flash_state : 1; /* One-bit counter to flash taskbar */
83
unsigned int entered_state : 1; /* True if cursor is inside taskbar button */
84
unsigned int present_in_client_list : 1; /* State during WM_CLIENT_LIST processing to detect deletions */
87
/* Private context for taskbar plugin. */
88
typedef struct _taskbar {
89
Plugin * plug; /* Back pointer to Plugin */
90
Task * task_list; /* List of tasks to be displayed in taskbar */
91
TaskClass * res_class_list; /* Window class list */
92
IconGrid * icon_grid; /* Manager for taskbar buttons */
93
GtkWidget * menu; /* Popup menu for task control (Close, Raise, etc.) */
94
GtkWidget * group_menu; /* Popup menu for grouping selection */
95
GdkPixbuf * fallback_pixbuf; /* Fallback task icon when none is available */
96
int number_of_desktops; /* Number of desktops, from NET_WM_NUMBER_OF_DESKTOPS */
97
int current_desktop; /* Current desktop, from NET_WM_CURRENT_DESKTOP */
98
Task * focused; /* Task that has focus */
99
Task * focused_previous; /* Task that had focus just before panel got it */
100
Task * menutask; /* Task for which popup menu is open */
101
guint dnd_delay_timer; /* Timer for drag and drop delay */
102
int icon_size; /* Size of task icons */
103
gboolean show_all_desks; /* User preference: show windows from all desktops */
104
gboolean tooltips; /* User preference: show tooltips */
105
gboolean icons_only; /* User preference: show icons only, omit name */
106
gboolean use_mouse_wheel; /* User preference: scroll wheel does iconify and raise */
107
gboolean use_urgency_hint; /* User preference: windows with urgency will flash */
108
gboolean flat_button; /* User preference: taskbar buttons have visible background */
109
gboolean grouped_tasks; /* User preference: windows from same task are grouped onto a single button */
110
int task_width_max; /* Maximum width of a taskbar button in horizontal orientation */
111
int spacing; /* Spacing between taskbar buttons */
112
gboolean use_net_active; /* NET_WM_ACTIVE_WINDOW is supported by the window manager */
109
115
static gchar *taskbar_rc = "style 'taskbar-style'\n"
111
"GtkWidget::focus-line-width = 0\n"
112
"GtkWidget::focus-padding = 0\n"
113
"GtkButton::default-border = { 0, 0, 0, 0 }\n"
114
"GtkButton::default-outside-border = { 0, 0, 0, 0 }\n"
115
"GtkButton::default_border = { 0, 0, 0, 0 }\n"
116
"GtkButton::default_outside_border = { 0, 0, 0, 0 }\n"
117
"GtkWidget::focus-padding=0\n" /* FIXME: seem to fix #2821771, not sure if this is ok. */
118
"GtkWidget::focus-line-width=0\n"
119
"GtkWidget::focus-padding=0\n"
120
"GtkButton::default-border={0,0,0,0}\n"
121
"GtkButton::default-outside-border={0,0,0,0}\n"
122
"GtkButton::inner-border={0,0,0,0}\n" /* added in gtk+ 2.10 */
118
124
"widget '*.taskbar.*' style 'taskbar-style'";
120
static gboolean use_net_active=FALSE;
122
#define DRAG_ACTIVE_DELAY 1000
123
#define TASK_WIDTH_MAX 200
124
#define TASK_PADDING 4
126
#define ALL_WORKSPACES (0xFFFFFFFF)
128
static void tk_display(taskbar *tb, task *tk);
129
static void tb_propertynotify(taskbar *tb, XEvent *ev);
130
static GdkFilterReturn tb_event_filter( XEvent *, GdkEvent *, taskbar *);
131
static void taskbar_destructor(Plugin *p);
133
static gboolean tk_has_urgency( task* tk );
135
static void tk_flash_window( task *tk );
136
static void tk_unflash_window( task *tk );
137
static void tk_raise_window( task *tk, guint32 time );
140
update_label_orient( GtkWidget* child, gpointer user_data );
143
#define TASK_VISIBLE(tb, tk) \
144
((tk)->desktop == (tb)->cur_desk || (tk)->desktop == -1 /* 0xFFFFFFFF */ )
147
task_visible(taskbar *tb, task *tk)
150
if (tk->desktop != -1 && !tb->show_all_desks && tk->desktop != tb->cur_desk)
153
if (!tb->show_iconified)
156
if (!tb->show_mapped)
163
accept_net_wm_state(NetWMState *nws, int accept_skip_pager)
166
RET(!(nws->skip_taskbar || (accept_skip_pager && nws->skip_pager)));
170
accept_net_wm_window_type(NetWMWindowType *nwwt)
173
RET(!(nwwt->desktop || nwwt->dock || nwwt->splash));
179
tk_free_names(task *tk)
182
DBG("tk->name %s\n", tk->name);
183
DBG("tk->iname %s\n", tk->iname);
126
#define DRAG_ACTIVE_DELAY 1000
127
#define TASK_WIDTH_MAX 200
128
#define TASK_PADDING 4
129
#define ALL_WORKSPACES (-1)
130
#define ICON_ONLY_EXTRA 6 /* Amount needed to have button lay out symmetrically */
131
#define BUTTON_HEIGHT_EXTRA 4 /* Amount needed to have button not clip icon */
133
static void set_timer_on_task(Task * tk);
134
static gboolean task_is_visible_on_current_desktop(TaskbarPlugin * tb, Task * tk);
135
static void recompute_group_visibility_for_class(TaskbarPlugin * tb, TaskClass * tc);
136
static void recompute_group_visibility_on_current_desktop(TaskbarPlugin * tb);
137
static void task_draw_label(Task * tk);
138
static gboolean task_is_visible(TaskbarPlugin * tb, Task * tk);
139
static void task_button_redraw(Task * tk, TaskbarPlugin * tb);
140
static void taskbar_redraw(TaskbarPlugin * tb);
141
static gboolean accept_net_wm_state(NetWMState * nws);
142
static gboolean accept_net_wm_window_type(NetWMWindowType * nwwt);
143
static void task_free_names(Task * tk);
144
static void task_set_names(Task * tk, Atom source);
145
static void task_unlink_class(Task * tk);
146
static TaskClass * taskbar_enter_res_class(TaskbarPlugin * tb, char * res_class, gboolean * name_consumed);
147
static void task_set_class(Task * tk);
148
static Task * task_lookup(TaskbarPlugin * tb, Window win);
149
static void task_delete(TaskbarPlugin * tb, Task * tk, gboolean unlink);
150
static GdkColormap * get_colormap_from_pixmap(GdkPixmap * pixmap);
151
static GdkPixbuf * _wnck_gdk_pixbuf_get_from_pixmap(
152
GdkPixbuf * dest, Pixmap xpixmap, int src_x, int src_y, int dest_x, int dest_y, int width, int height);
153
static GdkPixbuf * apply_mask(GdkPixbuf * pixbuf, GdkPixbuf * mask);
154
static GdkPixbuf * get_wm_icon(Window task_win, int required_width, int required_height, Atom source, Atom * current_source);
155
static GdkPixbuf * task_update_icon(TaskbarPlugin * tb, Task * tk, Atom source);
156
static gboolean flash_window_timeout(Task * tk);
157
static void task_set_urgency(Task * tk);
158
static void task_clear_urgency(Task * tk);
159
static void task_raise_window(Task * tk, guint32 time);
160
static void taskbar_popup_set_position(GtkWidget * menu, gint * px, gint * py, gboolean * push_in, gpointer data);
161
static void task_group_menu_destroy(TaskbarPlugin * tb);
162
static gboolean taskbar_task_control_event(GtkWidget * widget, GdkEventButton * event, Task * tk, gboolean popup_menu);
163
static gboolean taskbar_button_press_event(GtkWidget * widget, GdkEventButton * event, Task * tk);
164
static gboolean taskbar_popup_activate_event(GtkWidget * widget, GdkEventButton * event, Task * tk);
165
static gboolean taskbar_button_drag_motion_timeout(Task * tk);
166
static gboolean taskbar_button_drag_motion(GtkWidget * widget, GdkDragContext * drag_context, gint x, gint y, guint time, Task * tk);
167
static void taskbar_button_enter(GtkWidget * widget, Task * tk);
168
static void taskbar_button_leave(GtkWidget * widget, Task * tk);
169
static gboolean taskbar_button_scroll_event(GtkWidget * widget, GdkEventScroll * event, Task * tk);
170
static void taskbar_button_size_allocate(GtkWidget * btn, GtkAllocation * alloc, Task * tk);
171
static void taskbar_update_style(TaskbarPlugin * tb);
172
static void task_update_style(Task * tk, TaskbarPlugin * tb);
173
static void task_build_gui(TaskbarPlugin * tb, Task * tk);
174
static void taskbar_net_client_list(GtkWidget * widget, TaskbarPlugin * tb);
175
static void taskbar_net_current_desktop(GtkWidget * widget, TaskbarPlugin * tb);
176
static void taskbar_net_number_of_desktops(GtkWidget * widget, TaskbarPlugin * tb);
177
static void taskbar_net_active_window(GtkWidget * widget, TaskbarPlugin * tb);
178
static gboolean task_has_urgency(Task * tk);
179
static void taskbar_property_notify_event(TaskbarPlugin * tb, XEvent *ev);
180
static GdkFilterReturn taskbar_event_filter(XEvent * xev, GdkEvent * event, TaskbarPlugin * tb);
181
static void menu_raise_window(GtkWidget * widget, TaskbarPlugin * tb);
182
static void menu_restore_window(GtkWidget * widget, TaskbarPlugin * tb);
183
static void menu_maximize_window(GtkWidget * widget, TaskbarPlugin * tb);
184
static void menu_iconify_window(GtkWidget * widget, TaskbarPlugin * tb);
185
static void menu_move_to_workspace(GtkWidget * widget, TaskbarPlugin * tb);
186
static void menu_close_window(GtkWidget * widget, TaskbarPlugin * tb);
187
static void taskbar_make_menu(TaskbarPlugin * tb);
188
static void taskbar_build_gui(Plugin * p);
189
static gboolean net_active_supported(void);
190
static int taskbar_constructor(Plugin * p, char ** fp);
191
static void taskbar_destructor(Plugin * p);
192
static void taskbar_apply_configuration(Plugin * p);
193
static void taskbar_configure(Plugin * p, GtkWindow * parent);
194
static void taskbar_save_configuration(Plugin * p, FILE * fp);
195
static void taskbar_panel_configuration_changed(Plugin * p);
197
/* Set an urgency timer on a task. */
198
static void set_timer_on_task(Task * tk)
201
g_object_get(gtk_widget_get_settings(tk->button), "gtk-cursor-blink-time", &interval, NULL);
202
tk->flash_timeout = g_timeout_add(interval, (GSourceFunc) flash_window_timeout, tk);
205
/* Determine if a task is visible considering only its desktop placement. */
206
static gboolean task_is_visible_on_current_desktop(TaskbarPlugin * tb, Task * tk)
208
return ((tk->desktop == ALL_WORKSPACES) || (tk->desktop == tb->current_desktop) || (tb->show_all_desks));
211
/* Recompute the visible task for a class when the class membership changes.
212
* Also transfer the urgency state to the visible task if necessary. */
213
static void recompute_group_visibility_for_class(TaskbarPlugin * tb, TaskClass * tc)
215
tc->visible_count = 0;
216
tc->visible_task = NULL;
217
tc->visible_name = NULL;
218
Task * flashing_task = NULL;
219
gboolean class_has_urgency = FALSE;
221
for (tk = tc->res_class_head; tk != NULL; tk = tk->res_class_flink)
223
if (task_is_visible_on_current_desktop(tb, tk))
225
/* Count visible tasks and make the first visible task the one that is used for display. */
226
if (tc->visible_count == 0)
227
tc->visible_task = tk;
228
tc->visible_count += 1;
230
/* Compute summary bit for urgency anywhere in the class. */
232
class_has_urgency = TRUE;
234
/* If there is urgency, record the currently flashing task. */
235
if (tk->flash_timeout != 0)
238
/* Compute the visible name. If all visible windows have the same title, use that.
239
* Otherwise, use the class name. This follows WNCK.
240
* Note that the visible name is not a separate string, but is set to point to one of the others. */
241
if (tc->visible_name == NULL)
242
tc->visible_name = tk->name;
243
else if ((tc->visible_name != tc->res_class)
244
&& (tc->visible_name != NULL) && (tk->name != NULL)
245
&& (strcmp(tc->visible_name, tk->name) != 0))
246
tc->visible_name = tc->res_class;
250
/* Transfer the flash timeout to the visible task. */
251
if (class_has_urgency)
253
if (flashing_task == NULL)
255
/* Set the flashing context and flash the window immediately. */
256
tc->visible_task->flash_state = TRUE;
257
flash_window_timeout(tc->visible_task);
259
/* Set the timer, since none is set. */
260
set_timer_on_task(tc->visible_task);
262
else if (flashing_task != tc->visible_task)
264
/* Reset the timer on the new representative.
265
* There will be a slight hiccup on the flash cadence. */
266
g_source_remove(flashing_task->flash_timeout);
267
flashing_task->flash_timeout = 0;
268
tc->visible_task->flash_state = flashing_task->flash_state;
269
flashing_task->flash_state = FALSE;
270
set_timer_on_task(tc->visible_task);
275
/* No task has urgency. Cancel the timer if one is set. */
276
if (flashing_task != NULL)
278
g_source_remove(flashing_task->flash_timeout);
279
flashing_task->flash_state = FALSE;
284
/* Recompute the visible task for all classes when the desktop changes. */
285
static void recompute_group_visibility_on_current_desktop(TaskbarPlugin * tb)
288
for (tc = tb->res_class_list; tc != NULL; tc = tc->res_class_flink)
290
recompute_group_visibility_for_class(tb, tc);
294
/* Draw the label and tooltip on a taskbar button. */
295
static void task_draw_label(Task * tk)
297
TaskClass * tc = tk->res_class;
298
gboolean bold_style = (((tk->entered_state) && (tk->tb->flat_button)) || tk->flash_state);
299
if ((tk->tb->grouped_tasks) && (tc != NULL) && (tc->visible_task == tk) && (tc->visible_count > 1))
301
char * label = g_strdup_printf("(%d) %s", tc->visible_count, tc->visible_name);
302
gtk_widget_set_tooltip_text(tk->button, label);
303
panel_draw_label_text(tk->tb->plug->panel, tk->label, label, bold_style, tk->tb->flat_button);
308
char * name = tk->iconified ? tk->name_iconified : tk->name;
309
if (tk->tb->tooltips)
310
gtk_widget_set_tooltip_text(tk->button, name);
311
panel_draw_label_text(tk->tb->plug->panel, tk->label, name, bold_style, tk->tb->flat_button);
315
/* Determine if a task is visible. */
316
static gboolean task_is_visible(TaskbarPlugin * tb, Task * tk)
318
/* Not visible due to grouping. */
319
if ((tb->grouped_tasks) && (tk->res_class != NULL) && (tk->res_class->visible_task != tk))
322
/* Desktop placement. */
323
return task_is_visible_on_current_desktop(tb, tk);
326
/* Redraw a task button. */
327
static void task_button_redraw(Task * tk, TaskbarPlugin * tb)
329
if (task_is_visible(tb, tk))
332
icon_grid_set_visible(tb->icon_grid, tk->button, TRUE);
335
icon_grid_set_visible(tb->icon_grid, tk->button, FALSE);
338
/* Redraw all tasks in the taskbar. */
339
static void taskbar_redraw(TaskbarPlugin * tb)
342
for (tk = tb->task_list; tk != NULL; tk = tk->task_flink)
343
task_button_redraw(tk, tb);
346
/* Determine if a task should be visible given its NET_WM_STATE. */
347
static gboolean accept_net_wm_state(NetWMState * nws)
349
return ( ! (nws->skip_taskbar));
352
/* Determine if a task should be visible given its NET_WM_WINDOW_TYPE. */
353
static gboolean accept_net_wm_window_type(NetWMWindowType * nwwt)
355
return ( ! ((nwwt->desktop) || (nwwt->dock) || (nwwt->splash)));
358
/* Free the names associated with a task. */
359
static void task_free_names(Task * tk)
184
361
g_free(tk->name);
187
tk->name = tk->iname = NULL;
362
g_free(tk->name_iconified);
363
tk->name = tk->name_iconified = NULL;
192
tk_set_names(task *tk)
366
/* Set the names associated with a task.
367
* This is expected to be the same as the title the window manager is displaying. */
368
static void task_set_names(Task * tk, Atom source)
199
/*name = get_utf8_property(tk->win, a_NET_WM_VISIBLE_NAME);
200
DBG2("a_NET_WM_VISIBLE_NAME:%s\n", name);
203
name = get_utf8_property(tk->win, a_NET_WM_NAME);
204
DBG("a_NET_WM_NAME:%s\n", name);
372
/* Try _NET_WM_VISIBLE_NAME, which supports UTF-8.
373
* If it is set, the window manager is displaying it as the window title. */
374
if ((source == None) || (source == a_NET_WM_VISIBLE_NAME))
376
name = get_utf8_property(tk->win, a_NET_WM_VISIBLE_NAME);
378
tk->name_source = a_NET_WM_VISIBLE_NAME;
381
/* Try _NET_WM_NAME, which supports UTF-8, but do not overwrite _NET_WM_VISIBLE_NAME. */
383
&& ((source == None) || (source == a_NET_WM_NAME))
384
&& ((tk->name_source == None) || (tk->name_source == a_NET_WM_NAME) || (tk->name_source == XA_WM_NAME)))
386
name = get_utf8_property(tk->win, a_NET_WM_NAME);
388
tk->name_source = a_NET_WM_NAME;
391
/* Try WM_NAME, which supports only ISO-8859-1, but do not overwrite _NET_WM_VISIBLE_NAME or _NET_WM_NAME. */
393
&& ((source == None) || (source == XA_WM_NAME))
394
&& ((tk->name_source == None) || (tk->name_source == XA_WM_NAME)))
206
396
name = get_textproperty(tk->win, XA_WM_NAME);
207
DBG("XA_WM_NAME:%s\n", name);
211
tk->name = g_strdup_printf(" %s ", name);
212
tk->iname = g_strdup_printf("[%s]", name);
214
name = tk->iconified ? tk->iname : tk->name;
216
gtk_label_set_text(GTK_LABEL(tk->label), name);
217
if (tk->tb->tooltips)
218
gtk_widget_set_tooltip_text( tk->button, tk->name );
225
find_task (taskbar * tb, Window win)
228
RET(g_hash_table_lookup(tb->task_list, &win));
233
del_task (taskbar * tb, task *tk, int hdel)
236
DBG("deleting(%d) %08x %s\n", hdel, tk->win, tk->name);
237
if( tk->flash_timeout )
238
g_source_remove( tk->flash_timeout );
239
gtk_widget_destroy(tk->button);
398
tk->name_source = XA_WM_NAME;
401
/* Set the name into the task context, and also on the tooltip. */
405
tk->name = g_strdup(name);
406
tk->name_iconified = g_strdup_printf("[%s]", name);
409
/* Redraw the button. */
410
task_button_redraw(tk, tk->tb);
414
/* Unlink a task from the class list because its class changed or it was deleted. */
415
static void task_unlink_class(Task * tk)
417
TaskClass * tc = tk->res_class;
420
/* Remove from per-class task list. */
421
if (tc->res_class_head == tk)
423
/* Removing the head of the list. This causes a new task to be the visible task, so we redraw. */
424
tc->res_class_head = tk->res_class_flink;
425
if (tc->res_class_head != NULL)
426
task_button_redraw(tc->res_class_head, tk->tb);
430
/* Locate the task and its predecessor in the list and then remove it. For safety, ensure it is found. */
431
Task * tk_pred = NULL;
434
tk_cursor = tc->res_class_head;
435
((tk_cursor != NULL) && (tk_cursor != tk));
436
tk_pred = tk_cursor, tk_cursor = tk_cursor->res_class_flink) ;
438
tk_pred->res_class_flink = tk->res_class_flink;
441
/* Recompute group visibility. */
442
recompute_group_visibility_for_class(tk->tb, tc);
446
/* Enter class with specified name. */
447
static TaskClass * taskbar_enter_res_class(TaskbarPlugin * tb, char * res_class, gboolean * name_consumed)
449
/* Find existing entry or insertion point. */
450
*name_consumed = FALSE;
451
TaskClass * tc_pred = NULL;
453
for (tc = tb->res_class_list; tc != NULL; tc_pred = tc, tc = tc->res_class_flink)
455
int status = strcmp(res_class, tc->res_class);
462
/* Insert new entry. */
463
tc = g_new0(TaskClass, 1);
464
tc->res_class = res_class;
465
*name_consumed = TRUE;
468
tc->res_class_flink = tb->res_class_list;
469
tb->res_class_list = tc;
473
tc->res_class_flink = tc_pred->res_class_flink;
474
tc_pred->res_class_flink = tc;
479
/* Set the class associated with a task. */
480
static void task_set_class(Task * tk)
482
/* Read the WM_CLASS property. */
486
XGetClassHint(GDK_DISPLAY(), tk->win, &ch);
488
/* If the res_name was returned, free it. We make no use of it at this time. */
489
if (ch.res_name != NULL)
494
/* If the res_class was returned, process it.
495
* This identifies the application that created the window and is the basis for taskbar grouping. */
496
if (ch.res_class != NULL)
498
/* Convert the class to UTF-8 and enter it in the class table. */
499
gchar * res_class = g_locale_to_utf8(ch.res_class, -1, NULL, NULL, NULL);
500
gboolean name_consumed;
501
TaskClass * tc = taskbar_enter_res_class(tk->tb, res_class, &name_consumed);
502
if ( ! name_consumed) g_free(res_class);
504
/* If the task changed class, update data structures. */
505
TaskClass * old_tc = tk->res_class;
508
/* Unlink from previous class, if any. */
509
task_unlink_class(tk);
511
/* Add to end of per-class task list. Do this to keep the popup menu in order of creation. */
512
if (tc->res_class_head == NULL)
513
tc->res_class_head = tk;
517
for (tk_pred = tc->res_class_head; tk_pred->res_class_flink != NULL; tk_pred = tk_pred->res_class_flink) ;
518
tk_pred->res_class_flink = tk;
519
task_button_redraw(tk, tk->tb);
523
/* Recompute group visibility. */
524
recompute_group_visibility_for_class(tk->tb, tc);
530
/* Look up a task in the task list. */
531
static Task * task_lookup(TaskbarPlugin * tb, Window win)
534
for (tk = tb->task_list; tk != NULL; tk = tk->task_flink)
544
/* Delete a task and optionally unlink it from the task list. */
545
static void task_delete(TaskbarPlugin * tb, Task * tk, gboolean unlink)
547
/* If we think this task had focus, remove that. */
242
548
if (tb->focused == tk)
243
549
tb->focused = NULL;
245
g_hash_table_remove(tb->task_list, &tk->win);
551
/* Deallocate structures. */
552
icon_grid_remove(tb->icon_grid, tk->button);
554
task_unlink_class(tk);
556
/* If there is an urgency timeout, remove it. */
557
if (tk->flash_timeout != 0)
558
g_source_remove(tk->flash_timeout);
560
/* If requested, unlink the task from the task list.
561
* If not requested, the caller will do this. */
564
if (tb->task_list == tk)
565
tb->task_list = tk->task_flink;
568
/* Locate the task and its predecessor in the list and then remove it. For safety, ensure it is found. */
569
Task * tk_pred = NULL;
572
tk_cursor = tb->task_list;
573
((tk_cursor != NULL) && (tk_cursor != tk));
574
tk_pred = tk_cursor, tk_cursor = tk_cursor->task_flink) ;
576
tk_pred->task_flink = tk->task_flink;
580
/* Deallocate the task structure. */
253
get_cmap (GdkPixmap *pixmap)
584
/* Get the color map from a pixmap.
585
* From libwnck, Copyright (C) 2001 Havoc Pennington. */
586
static GdkColormap * get_colormap_from_pixmap(GdkPixmap * pixmap)
258
cmap = gdk_drawable_get_colormap (pixmap);
260
g_object_ref (G_OBJECT (cmap));
588
GdkColormap * colormap = gdk_drawable_get_colormap(pixmap);
589
if (colormap != NULL)
590
g_object_ref(G_OBJECT(colormap));
264
if (gdk_drawable_get_depth (pixmap) == 1)
593
if (gdk_drawable_get_depth(pixmap) == 1)
595
/* Try null colormap. */
271
/* Try system cmap */
272
GdkScreen *screen = gdk_drawable_get_screen (GDK_DRAWABLE (pixmap));
273
cmap = gdk_screen_get_system_colormap (screen);
274
g_object_ref (G_OBJECT (cmap));
600
/* Try system colormap. */
601
GdkScreen * screen = gdk_drawable_get_screen(GDK_DRAWABLE(pixmap));
602
colormap = gdk_screen_get_system_colormap(screen);
603
g_object_ref(G_OBJECT(colormap));
278
/* Be sure we aren't going to blow up due to visual mismatch */
280
(gdk_colormap_get_visual (cmap)->depth !=
281
gdk_drawable_get_depth (pixmap)))
607
/* Be sure we aren't going to blow up due to visual mismatch. */
608
if ((colormap != NULL) && (gdk_colormap_get_visual(colormap)->depth != gdk_drawable_get_depth(pixmap)))
287
614
/* These functions with the prefix wnck are taken from libwnck
288
615
* Copyright (C) 2001 Havoc Pennington
289
616
* slightly modified by Hong Jen Yee for LXPanel
292
_wnck_change_workspace (Screen *screen,
298
xev.xclient.type = ClientMessage;
299
xev.xclient.serial = 0;
300
xev.xclient.send_event = True;
301
xev.xclient.display = gdk_display;
302
xev.xclient.window = xwindow;
303
xev.xclient.message_type = a_NET_WM_DESKTOP;
304
xev.xclient.format = 32;
305
xev.xclient.data.l[0] = new_space;
306
xev.xclient.data.l[1] = 0;
307
xev.xclient.data.l[2] = 0;
308
xev.xclient.data.l[3] = 0;
309
xev.xclient.data.l[4] = 0;
311
XSendEvent (gdk_display,
312
RootWindowOfScreen (screen),
314
SubstructureRedirectMask | SubstructureNotifyMask,
319
_wnck_gdk_pixbuf_get_from_pixmap (GdkPixbuf *dest,
328
GdkDrawable *drawable;
335
drawable = gdk_xid_table_lookup (xpixmap);
338
g_object_ref (G_OBJECT (drawable));
619
/* Get a pixbuf from a pixmap. */
620
static GdkPixbuf * _wnck_gdk_pixbuf_get_from_pixmap(
621
GdkPixbuf * dest, Pixmap xpixmap, int src_x, int src_y, int dest_x, int dest_y, int width, int height)
623
/* Initialize; get the drawable and its colormap. */
624
GdkPixbuf * retval = NULL;
625
GdkDrawable * drawable = gdk_xid_table_lookup(xpixmap);
626
if (drawable != NULL)
627
g_object_ref(G_OBJECT(drawable));
340
drawable = gdk_pixmap_foreign_new (xpixmap);
342
cmap = get_cmap (drawable);
344
/* GDK is supposed to do this but doesn't in GTK 2.0.2,
348
gdk_drawable_get_size (drawable, &width, NULL);
350
gdk_drawable_get_size (drawable, NULL, &height);
352
retval = gdk_pixbuf_get_from_drawable (dest,
360
g_object_unref (G_OBJECT (cmap));
361
g_object_unref (G_OBJECT (drawable));
367
apply_mask (GdkPixbuf *pixbuf,
372
GdkPixbuf *with_alpha;
379
w = MIN (gdk_pixbuf_get_width (mask), gdk_pixbuf_get_width (pixbuf));
380
h = MIN (gdk_pixbuf_get_height (mask), gdk_pixbuf_get_height (pixbuf));
382
with_alpha = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
384
dest = gdk_pixbuf_get_pixels (with_alpha);
385
src = gdk_pixbuf_get_pixels (mask);
387
dest_stride = gdk_pixbuf_get_rowstride (with_alpha);
388
src_stride = gdk_pixbuf_get_rowstride (mask);
396
guchar *s = src + i * src_stride + j * 3;
397
guchar *d = dest + i * dest_stride + j * 4;
399
/* s[0] == s[1] == s[2], they are 255 if the bit was set, 0
403
d[3] = 0; /* transparent */
405
d[3] = 255; /* opaque */
416
/* set the iconification destination */
417
static void set_iconification_dest( Window win, int x, int y, int w, int h )
425
XChangeProperty(GDK_DISPLAY(), win,
426
gdk_x11_get_xatom_by_name("_NET_WM_ICON_GEOMETRY"),
427
XA_CARDINAL, 32, PropModeReplace, (guchar *)&data, 4);
431
get_netwm_icon(Window tkwin, int iw, int ih)
434
GdkPixbuf *ret = NULL;
437
wmhints = XGetWMHints( GDK_DISPLAY(), GDK_ROOT_WINDOW() );
440
* IconPixmapHint flag indicates that wmhints->icon_pixmap contains
441
* valid data that is already in pixdata format, so we could process
442
* it and turn it into a GTK image.
444
if( wmhints && (wmhints->flags & IconPixmapHint) ) {
445
GdkPixmap *gdkPixmap;
446
GdkPixbuf *gdkPixbuf = NULL;
447
GdkColormap *colormap;
449
colormap = gdk_colormap_get_system();
451
gdkPixmap = gdk_pixmap_foreign_new(wmhints->icon_pixmap);
452
gdkPixbuf = gdk_pixbuf_get_from_drawable(
453
NULL, gdkPixmap, colormap, 0, 0, 0, 0, iw, ih );
454
ret = gdk_pixbuf_scale_simple( gdkPixbuf, 24, 24, GDK_INTERP_BILINEAR );
455
gdk_pixbuf_unref(gdkPixbuf);
463
free_pixels(guchar *pixels, gpointer data)
469
get_wm_icon(Window tkwin, int iw, int ih)
472
Pixmap xpixmap = None, xmask = None;
475
int sd, result, format;
476
GdkPixbuf *ret=NULL, *masked=NULL, *pixmap = NULL, *mask = NULL;
481
guchar *pixdata=NULL, *p=NULL;
485
* According to freedesktop.org document:
486
* http://standards.freedesktop.org/wm-spec/wm-spec-1.4.html#id2552223
487
* _NET_WM_ICON contains an array of 32-bit packed CARDINAL ARGB.
488
* However, this is incorrect. Actually it's an array of long integers.
489
* Toolkits like gtk+ use unsigned long here to store icons.
490
* Besides, according to manpage of XGetWindowProperty, when returned format,
491
* is 32, the property data will be stored as an array of longs
492
* (which in a 64-bit application will be 64-bit values that are
493
* padded in the upper 4 bytes).
496
result = XGetWindowProperty(GDK_DISPLAY(),
498
gdk_x11_get_xatom_by_name("_NET_WM_ICON"),
500
0, XA_CARDINAL, &type, &format, &nitems,
501
&bytes_after, (void*)&data);
502
/* g_debug("type=%d, format=%d, nitems=%d", type, format, nitems); */
503
if(type != XA_CARDINAL || nitems <= 0 )
505
LOG(LOG_WARN, "lxpanel : type is not XA_CARDINAL\n");
513
if(result == Success)
515
gulong* pdata = data;
516
gulong* pdata_end = data + nitems;
517
gulong* max_icon = NULL;
518
gulong max_w = 0, max_h = 0;
520
/* get the largest icon available. */
521
/* FIXME: should we try to find an icon whose size is closest to
522
* iw and ih to reduce unnecessary resizing? */
523
while(pdata + 2 < pdata_end)
527
gulong size = (w * h);
530
if( pdata + size > pdata_end ) /* corrupt icon */
533
if( w > max_w && h > max_h )
540
/* rare special case: the desire size is the same as icon size */
541
if( iw == w && ih == h )
549
gulong len = max_w * max_h;
550
pixdata = g_new(guchar, len * 4);
559
rgba = (argb << 8) | (argb >> 24);
563
*p = (rgba >> 16) & 0xff;
565
*p = (rgba >> 8) & 0xff;
629
drawable = gdk_pixmap_foreign_new(xpixmap);
630
GdkColormap * colormap = get_colormap_from_pixmap(drawable);
632
/* Do the major work. */
633
retval = gdk_pixbuf_get_from_drawable(dest,
640
/* Clean up and return. */
641
if (colormap != NULL)
642
g_object_unref(G_OBJECT(colormap));
643
g_object_unref(G_OBJECT(drawable));
647
/* Apply a mask to a pixbuf.
648
* From libwnck, Copyright (C) 2001 Havoc Pennington. */
649
static GdkPixbuf * apply_mask(GdkPixbuf * pixbuf, GdkPixbuf * mask)
652
int w = MIN(gdk_pixbuf_get_width(mask), gdk_pixbuf_get_width(pixbuf));
653
int h = MIN(gdk_pixbuf_get_height(mask), gdk_pixbuf_get_height(pixbuf));
654
GdkPixbuf * with_alpha = gdk_pixbuf_add_alpha(pixbuf, FALSE, 0, 0, 0);
655
guchar * dst = gdk_pixbuf_get_pixels(with_alpha);
656
guchar * src = gdk_pixbuf_get_pixels(mask);
657
int dst_stride = gdk_pixbuf_get_rowstride(with_alpha);
658
int src_stride = gdk_pixbuf_get_rowstride(mask);
660
/* Loop to do the work. */
662
for (i = 0; i < h; i += 1)
665
for (j = 0; j < w; j += 1)
667
guchar * s = src + i * src_stride + j * 3;
668
guchar * d = dst + i * dst_stride + j * 4;
670
/* s[0] == s[1] == s[2], they are 255 if the bit was set, 0 otherwise. */
671
d[3] = ((s[0] == 0) ? 0 : 255); /* 0 = transparent, 255 = opaque */
678
/* Get an icon from the window manager for a task, and scale it to a specified size. */
679
static GdkPixbuf * get_wm_icon(Window task_win, int required_width, int required_height, Atom source, Atom * current_source)
682
GdkPixbuf * pixmap = NULL;
683
Atom possible_source = None;
686
if ((source == None) || (source == a_NET_WM_ICON))
689
* According to freedesktop.org document:
690
* http://standards.freedesktop.org/wm-spec/wm-spec-1.4.html#id2552223
691
* _NET_WM_ICON contains an array of 32-bit packed CARDINAL ARGB.
692
* However, this is incorrect. Actually it's an array of long integers.
693
* Toolkits like gtk+ use unsigned long here to store icons.
694
* Besides, according to manpage of XGetWindowProperty, when returned format,
695
* is 32, the property data will be stored as an array of longs
696
* (which in a 64-bit application will be 64-bit values that are
697
* padded in the upper 4 bytes).
700
/* Get the window property _NET_WM_ICON, if possible. */
705
gulong * data = NULL;
706
result = XGetWindowProperty(
712
&type, &format, &nitems, &bytes_after, (void *) &data);
714
/* Inspect the result to see if it is usable. If not, and we got data, free it. */
715
if ((type != XA_CARDINAL) || (nitems <= 0))
722
/* If the result is usable, extract the icon from it. */
723
if (result == Success)
725
/* Get the largest icon available, unless there is one that is the desired size. */
726
/* FIXME: should we try to find an icon whose size is closest to
727
* required_width and required_height to reduce unnecessary resizing? */
728
gulong * pdata = data;
729
gulong * pdata_end = data + nitems;
730
gulong * max_icon = NULL;
733
while ((pdata + 2) < pdata_end)
735
/* Extract the width and height. */
741
/* Bounds check the icon. */
742
if (pdata + size > pdata_end)
745
/* Rare special case: the desired size is the same as icon size. */
746
if ((required_width == w) && (required_height == h))
754
/* If the icon is the largest so far, capture it. */
755
if ((w > max_w) && (h > max_h))
764
/* If an icon was extracted, convert it to a pixbuf.
765
* Its size is max_w and max_h. */
766
if (max_icon != NULL)
768
/* Allocate enough space for the pixel data. */
769
gulong len = max_w * max_h;
770
guchar * pixdata = g_new(guchar, len * 4);
772
/* Loop to convert the pixel data. */
773
guchar * p = pixdata;
775
for (i = 0; i < len; p += 4, i += 1)
777
guint argb = max_icon[i];
778
guint rgba = (argb << 8) | (argb >> 24);
780
p[1] = (rgba >> 16) & 0xff;
781
p[2] = (rgba >> 8) & 0xff;
573
pixmap = gdk_pixbuf_new_from_data(pixdata,
576
max_w, max_h, max_w * 4,
785
/* Initialize a pixmap with the pixel data. */
786
pixmap = gdk_pixbuf_new_from_data(
789
TRUE, 8, /* has_alpha, bits_per_sample */
790
max_w, max_h, max_w * 4,
791
(GdkPixbufDestroyNotify) g_free,
793
possible_source = a_NET_WM_ICON;
798
/* Free the X property data. */
588
if(result != Success)
803
/* No icon available from _NET_WM_ICON. Next try WM_HINTS, but do not overwrite _NET_WM_ICON. */
804
if ((result != Success) && (*current_source != a_NET_WM_ICON)
805
&& ((source == None) || (source != a_NET_WM_ICON)))
590
LOG(LOG_WARN, "lxpanel : Can't read _NET_WM_ICON, try to read pixmap icon\n");
592
hints = XGetWMHints(GDK_DISPLAY(), tkwin);
807
XWMHints * hints = XGetWMHints(GDK_DISPLAY(), task_win);
593
808
result = (hints != NULL) ? Success : -1;
809
Pixmap xpixmap = None;
595
if(result == Success)
812
if (result == Success)
814
/* WM_HINTS is available. Extract the X pixmap and mask. */
597
815
if ((hints->flags & IconPixmapHint))
598
816
xpixmap = hints->icon_pixmap;
599
817
if ((hints->flags & IconMaskHint))
600
818
xmask = hints->icon_mask;
603
result = (xpixmap != None)?Success:-1;
823
possible_source = XA_WM_HINTS;
606
if(result != Success)
829
if (result != Success)
831
/* No icon available from _NET_WM_ICON or WM_HINTS. Next try KWM_WIN_ICON. */
608
836
Pixmap *icons = NULL;
609
LOG(LOG_WARN, "lxpanel : can't get icon using HINTS try to use KWM_WIN_ICON\n");
610
837
Atom kwin_win_icon_atom = gdk_x11_get_xatom_by_name("KWM_WIN_ICON");
611
result = XGetWindowProperty(GDK_DISPLAY(), tkwin,
616
&type, &format, &nitems,
617
&bytes_after, (void*)&icons);
618
if(type != kwin_win_icon_atom)
838
result = XGetWindowProperty(
843
False, kwin_win_icon_atom,
844
&type, &format, &nitems, &bytes_after, (void *) &icons);
846
/* Inspect the result to see if it is usable. If not, and we got data, free it. */
847
if (type != kwin_win_icon_atom)
626
if(result == Success)
854
/* If the result is usable, extract the X pixmap and mask from it. */
855
if (result == Success)
628
857
xpixmap = icons[0];
630
result = (xpixmap != None) ? Success : -1;
862
possible_source = kwin_win_icon_atom;
634
if(result == Success)
636
result = XGetGeometry(GDK_DISPLAY(),
639
(guint *)&sd, (guint *)&sd) ? Success : -1;
642
if(result != Success)
644
LOG(LOG_WARN,"lxpanel : XGetGeometry failed for %x pixmap\n", (unsigned int)xpixmap);
648
DBG("tkwin=%x icon pixmap w=%d h=%d\n", tkwin, w, h);
649
pixmap = _wnck_gdk_pixbuf_get_from_pixmap (NULL, xpixmap, 0, 0, 0, 0, w, h);
650
result = pixmap?Success:-1;
653
if(result == Success)
655
if (xmask != None && XGetGeometry(GDK_DISPLAY(), xmask,
656
&win, &sd, &sd, &w, &h,
657
(guint *)&sd, (guint *)&sd))
869
/* If we have an X pixmap, get its geometry.*/
871
if (result == Success)
875
unsigned int unused_2;
876
result = XGetGeometry(
877
GDK_DISPLAY(), xpixmap,
878
&unused_win, &unused, &unused, &w, &h, &unused_2, &unused_2) ? Success : -1;
881
/* If we have an X pixmap and its geometry, convert it to a GDK pixmap. */
882
if (result == Success)
884
pixmap = _wnck_gdk_pixbuf_get_from_pixmap(NULL, xpixmap, 0, 0, 0, 0, w, h);
885
result = ((pixmap != NULL) ? Success : -1);
888
/* If we have success, see if the result needs to be masked.
889
* Failures here are implemented as nonfatal. */
890
if ((result == Success) && (xmask != None))
894
unsigned int unused_2;
896
GDK_DISPLAY(), xmask,
897
&unused_win, &unused, &unused, &w, &h, &unused_2, &unused_2))
659
mask = _wnck_gdk_pixbuf_get_from_pixmap (NULL, xmask, 0, 0, 0, 0, w, h);
899
/* Convert the X mask to a GDK pixmap. */
900
GdkPixbuf * mask = _wnck_gdk_pixbuf_get_from_pixmap(NULL, xmask, 0, 0, 0, 0, w, h);
662
masked = apply_mask (pixmap, mask);
663
g_object_unref (G_OBJECT (pixmap));
664
g_object_unref (G_OBJECT (mask));
903
/* Apply the mask. */
904
GdkPixbuf * masked_pixmap = apply_mask(pixmap, mask);
905
g_object_unref(G_OBJECT(pixmap));
906
g_object_unref(G_OBJECT(mask));
907
pixmap = masked_pixmap;
674
ret = gdk_pixbuf_scale_simple (pixmap, iw, ih, GDK_INTERP_TILES);
675
g_object_unref(pixmap);
680
inline static GdkPixbuf*
681
get_generic_icon(taskbar *tb)
684
g_object_ref(tb->gen_pixbuf);
689
tk_update_icon (taskbar *tb, task *tk, Atom a)
694
g_assert ((tb != NULL) && (tk != NULL));
695
g_return_if_fail(tk != NULL);
698
if (a == a_NET_WM_ICON || a == None) {
699
tk->pixbuf = get_netwm_icon(tk->win, tb->iconsize, tb->iconsize);
700
tk->using_netwm_icon = (tk->pixbuf != NULL);
702
if (!tk->using_netwm_icon)
703
tk->pixbuf = get_wm_icon(tk->win, tb->iconsize, tb->iconsize);
705
tk->pixbuf = get_generic_icon(tb); // always exists
706
if (pixbuf != tk->pixbuf) {
708
g_object_unref(pixbuf);
713
static gboolean on_flash_win( task *tk )
715
tk->flash_state = !tk->flash_state;
716
gtk_widget_set_state(tk->button,
717
tk->flash_state ? GTK_STATE_SELECTED : tk->tb->normal_state);
718
gtk_widget_queue_draw(tk->button);
913
/* If we got a pixmap, scale it and return it. */
918
GdkPixbuf * ret = gdk_pixbuf_scale_simple(pixmap, required_width, required_height, GDK_INTERP_TILES);
919
g_object_unref(pixmap);
920
*current_source = possible_source;
925
/* Update the icon of a task. */
926
static GdkPixbuf * task_update_icon(TaskbarPlugin * tb, Task * tk, Atom source)
928
/* Get the icon from the window's hints. */
929
GdkPixbuf * pixbuf = get_wm_icon(tk->win, tb->icon_size, tb->icon_size, source, &tk->image_source);
931
/* If that fails, and we have no other icon yet, return the fallback icon. */
933
&& ((source == None) || (tk->image_source == None)))
935
/* Establish the fallback task icon. This is used when no other icon is available. */
936
if (tb->fallback_pixbuf == NULL)
937
tb->fallback_pixbuf = gdk_pixbuf_new_from_xpm_data((const char **) icon_xpm);
938
g_object_ref(tb->fallback_pixbuf);
939
pixbuf = tb->fallback_pixbuf;
942
/* Return what we have. This may be NULL to indicate that no change should be made to the icon. */
946
/* Timer expiration for urgency notification. Also used to draw the button in setting and clearing urgency. */
947
static gboolean flash_window_timeout(Task * tk)
949
/* Set state on the button and redraw. */
950
if (tk->tb->flat_button)
954
gtk_widget_set_state(tk->button, tk->flash_state ? GTK_STATE_SELECTED : GTK_STATE_NORMAL);
955
gtk_widget_queue_draw(tk->button);
958
/* Complement the flashing context. */
959
tk->flash_state = ! tk->flash_state;
723
tk_flash_window( task *tk )
727
tk->flash_state = !tk->flash_state;
728
if (tk->flash_timeout)
730
g_object_get( gtk_widget_get_settings(tk->button),
731
"gtk-cursor-blink-time", &interval, NULL );
732
tk->flash_timeout = g_timeout_add(interval, (GSourceFunc)on_flash_win, tk);
736
tk_unflash_window( task *tk )
738
tk->flash = tk->flash_state = 0;
739
if (tk->flash_timeout) {
740
g_source_remove(tk->flash_timeout);
741
tk->flash_timeout = 0;
746
tk_raise_window( task *tk, guint32 time )
748
if (tk->desktop != -1 && tk->desktop != tk->tb->cur_desk){
963
/* Set urgency notification. */
964
static void task_set_urgency(Task * tk)
966
if (( ! tk->tb->grouped_tasks) || (tk->res_class == NULL))
968
/* Set the flashing context and flash the window immediately. */
969
tk->flash_state = TRUE;
970
flash_window_timeout(tk);
972
/* Set the timer if none is set. */
973
if (tk->flash_timeout == 0)
974
set_timer_on_task(tk);
977
recompute_group_visibility_for_class(tk->tb, tk->res_class);
980
/* Clear urgency notification. */
981
static void task_clear_urgency(Task * tk)
983
if (( ! tk->tb->grouped_tasks) || (tk->res_class == NULL))
985
/* Remove the timer if one is set. */
986
if (tk->flash_timeout != 0)
988
g_source_remove(tk->flash_timeout);
989
tk->flash_timeout = 0;
992
/* Clear the flashing context and unflash the window immediately. */
993
tk->flash_state = FALSE;
994
flash_window_timeout(tk);
995
tk->flash_state = FALSE;
998
recompute_group_visibility_for_class(tk->tb, tk->res_class);
1001
/* Do the proper steps to raise a window.
1002
* This means removing it from iconified state and bringing it to the front.
1003
* We also switch the active desktop and viewport if needed. */
1004
static void task_raise_window(Task * tk, guint32 time)
1006
/* Change desktop if needed. */
1007
if ((tk->desktop != -1) && (tk->desktop != tk->tb->current_desktop))
749
1008
Xclimsg(GDK_ROOT_WINDOW(), a_NET_CURRENT_DESKTOP, tk->desktop, 0, 0, 0, 0);
750
XSync (gdk_display, False);
752
XSetInputFocus (GDK_DISPLAY(), tk->win, RevertToNone, CurrentTime);
753
XRaiseWindow (GDK_DISPLAY(), tk->win);
754
Xclimsg(tk->win, a_NET_ACTIVE_WINDOW, 2, time, 0, 0, 0);
755
DBG("XRaiseWindow %x\n", tk->win);
759
on_tk_leave( GtkWidget *widget, task *tk)
763
gtk_widget_set_state(widget,
764
(tk->focused) ? tk->tb->focused_state : tk->tb->normal_state);
771
on_tk_enter( GtkWidget *widget, task *tk )
775
gtk_widget_set_state(widget,
776
(tk->focused) ? tk->tb->focused_state : tk->tb->normal_state);
781
static gboolean delay_active_win(task* tk)
783
/* FIXME: gtk_get_current_event_time() often returns 0.
784
However, passing 0 as time for this function is not OK. */
785
tk_raise_window(tk, gtk_get_current_event_time() );
786
tk->tb->dnd_activate = 0;
791
on_tk_drag_motion( GtkWidget *widget,
792
GdkDragContext *drag_context,
794
guint time, task *tk)
796
/* prevent excessive motion notification */
797
if (!tk->tb->dnd_activate) {
798
tk->tb->dnd_activate = g_timeout_add(DRAG_ACTIVE_DELAY,
799
(GSourceFunc)delay_active_win, tk);
801
gdk_drag_status (drag_context,0,time);
806
on_tk_drag_leave (GtkWidget *widget,
807
GdkDragContext *drag_context,
808
guint time, task *tk)
810
if (tk->tb->dnd_activate) {
811
g_source_remove(tk->tb->dnd_activate);
812
tk->tb->dnd_activate = 0;
819
on_tk_expose(GtkWidget *widget, GdkEventExpose *event, task *tk)
823
state = (tk->focused) ? tk->tb->focused_state : tk->tb->normal_state;
824
if (GTK_WIDGET_STATE(widget) != state) {
825
gtk_widget_set_state(widget, state);
826
gtk_widget_queue_draw(widget);
828
if( ! tk->flash || 0 == tk->flash_state ) {
829
gtk_paint_box (widget->style, widget->window,
831
(tk->focused) ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
832
&event->area, widget, "button",
833
widget->allocation.x, widget->allocation.y,
834
widget->allocation.width, widget->allocation.height);
836
gdk_draw_rectangle( widget->window,
837
widget->style->bg_gc[GTK_STATE_SELECTED],
839
widget->allocation.width,
840
widget->allocation.height );
843
_gtk_button_paint(GTK_BUTTON(widget), &event->area, state,
844
(tk->focused) ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
845
"button", "buttondefault");
847
gtk_container_propagate_expose(GTK_CONTAINER(widget), GTK_BIN(widget)->child, event);
854
on_tk_scroll_event (GtkWidget *widget, GdkEventScroll *event, task *tk)
857
if( ! tk->tb->use_mouse_wheel )
859
if (event->direction == GDK_SCROLL_UP) {
860
GdkWindow *gdkwindow;
862
gdkwindow = gdk_xid_table_lookup (tk->win);
864
gdk_window_show (gdkwindow);
1010
/* Raise the window. We can use NET_ACTIVE_WINDOW if the window manager supports it.
1011
* Otherwise, do it the old way with XMapRaised and XSetInputFocus. */
1012
if (tk->tb->use_net_active)
1013
Xclimsg(tk->win, a_NET_ACTIVE_WINDOW, 2, time, 0, 0, 0);
1016
GdkWindow * gdkwindow = gdk_xid_table_lookup(tk->win);
1017
if (gdkwindow != NULL)
1018
gdk_window_show(gdkwindow);
866
XMapRaised (GDK_DISPLAY(), tk->win);
867
XSetInputFocus (GDK_DISPLAY(), tk->win, RevertToNone, CurrentTime);
868
DBG("XMapRaised %x\n", tk->win);
869
} else if (event->direction == GDK_SCROLL_DOWN) {
870
DBG("tb->ptk = %x\n", (tk->tb->ptk) ? tk->tb->ptk->win : 0);
871
XIconifyWindow (GDK_DISPLAY(), tk->win, DefaultScreen(GDK_DISPLAY()));
872
DBG("XIconifyWindow %x\n", tk->win);
875
XSync (gdk_display, False);
880
on_tk_btn_press_event(GtkWidget *widget, GdkEventButton *event, task *tk)
882
if( event->type == GDK_BUTTON_PRESS && event->button == 3 )
884
tk->tb->menutask = tk;
885
gtk_menu_popup (GTK_MENU (tk->tb->menu), NULL, NULL, NULL, NULL, event->button, event->time);
892
on_tk_btn_release_event(GtkWidget *widget, GdkEventButton *event, task *tk)
1020
XMapRaised(GDK_DISPLAY(), tk->win);
1021
XSync(GDK_DISPLAY(), False); /* This we need to avoid BadMatch */
1022
XSetInputFocus(GDK_DISPLAY(), tk->win, RevertToNone, time);
1025
/* Change viewport if needed. */
894
1026
XWindowAttributes xwa;
896
if( event->type != GDK_BUTTON_RELEASE )
899
if( event->button == 1 )
1027
XGetWindowAttributes(GDK_DISPLAY(), tk->win, &xwa);
1028
Xclimsg(tk->win, a_NET_DESKTOP_VIEWPORT, xwa.x, xwa.y, 0, 0, 0);
1031
/* Position-calculation callback for grouped-task and window-management popup menu. */
1032
static void taskbar_popup_set_position(GtkWidget * menu, gint * px, gint * py, gboolean * push_in, gpointer data)
1034
Task * tk = (Task *) data;
1036
/* Get the allocation of the popup menu. */
1037
GtkRequisition popup_req;
1038
gtk_widget_size_request(menu, &popup_req);
1040
/* Determine the coordinates. */
1041
plugin_popup_set_position_helper(tk->tb->plug, tk->button, menu, &popup_req, px, py);
1045
/* Remove the grouped-task popup menu from the screen. */
1046
static void task_group_menu_destroy(TaskbarPlugin * tb)
1048
if (tb->group_menu != NULL)
1050
gtk_widget_destroy(tb->group_menu);
1051
tb->group_menu = NULL;
1055
/* Handler for "button-press-event" event from taskbar button,
1056
* or "activate" event from grouped-task popup menu item. */
1057
static gboolean taskbar_task_control_event(GtkWidget * widget, GdkEventButton * event, Task * tk, gboolean popup_menu)
1059
TaskbarPlugin * tb = tk->tb;
1060
TaskClass * tc = tk->res_class;
1061
if ((tb->grouped_tasks) && (tc != NULL) && (tc->visible_count > 1) && (GTK_IS_BUTTON(widget)))
1063
/* If this is a grouped-task representative, meaning that there is a class with at least two windows,
1064
* bring up a popup menu listing all the class members. */
1065
GtkWidget * menu = gtk_menu_new();
1067
for (tk_cursor = tc->res_class_head; tk_cursor != NULL; tk_cursor = tk_cursor->res_class_flink)
904
Xclimsg(tk->win, a_NET_ACTIVE_WINDOW, 2, event->time, 0, 0, 0);
1069
if (task_is_visible_on_current_desktop(tb, tk_cursor))
907
GdkWindow *gdkwindow;
908
gdkwindow = gdk_xid_table_lookup (tk->win);
910
gdk_window_show (gdkwindow);
912
XMapRaised (GDK_DISPLAY(), tk->win);
913
XSync (GDK_DISPLAY(), False);
1071
/* The menu item has the name, or the iconified name, and the icon of the application window. */
1072
GtkWidget * mi = gtk_image_menu_item_new_with_label(((tk_cursor->iconified) ? tk_cursor->name_iconified : tk_cursor->name));
1073
GtkWidget * im = gtk_image_new_from_pixbuf(gtk_image_get_pixbuf(GTK_IMAGE(tk_cursor->image)));
1074
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), im);
1075
g_signal_connect(mi, "button_press_event", G_CALLBACK(taskbar_popup_activate_event), (gpointer) tk_cursor);
1076
gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
915
/* if window isn't on current viewport, we change viewport */
916
XGetWindowAttributes(GDK_DISPLAY(), tk->win, &xwa);
917
Xclimsg(tk->win, a_NET_DESKTOP_VIEWPORT, xwa.x, xwa.y, 0, 0, 0);
1080
/* Show the menu. Set context so we can find the menu later to dismiss it.
1081
* Use a position-calculation callback to get the menu nicely positioned with respect to the button. */
1082
gtk_widget_show_all(menu);
1083
tb->group_menu = menu;
1084
gtk_menu_popup(GTK_MENU(menu), NULL, NULL, (GtkMenuPositionFunc) taskbar_popup_set_position, (gpointer) tk, event->button, event->time);
1088
/* Not a grouped-task representative, or entered from the grouped-task popup menu. */
1089
Task * visible_task = (((tk->res_class == NULL) || ( ! tk->tb->grouped_tasks)) ? tk : tk->res_class->visible_task);
1090
task_group_menu_destroy(tb);
1092
if (event->button == 1)
1095
* If the task is iconified, raise it.
1096
* If the task is not iconified and has focus, iconify it.
1097
* If the task is not iconified and does not have focus, raise it. */
1099
task_raise_window(tk, event->time);
1100
else if ((tk->focused) || (tk == tb->focused_previous))
1101
XIconifyWindow(GDK_DISPLAY(), tk->win, DefaultScreen(GDK_DISPLAY()));
1103
task_raise_window(tk, event->time);
1105
else if (event->button == 2)
1107
/* Middle button. Toggle the shaded state of the window. */
1108
Xclimsg(tk->win, a_NET_WM_STATE,
1109
2, /* a_NET_WM_STATE_TOGGLE */
1110
a_NET_WM_STATE_SHADED,
1113
else if (event->button == 3)
1115
/* Right button. Bring up the window state popup menu. */
1116
tk->tb->menutask = tk;
1120
(GtkMenuPositionFunc) taskbar_popup_set_position, (gpointer) visible_task,
1121
event->button, event->time);
1125
/* As a matter of policy, avoid showing selected or prelight states on flat buttons. */
1126
if (tb->flat_button)
1127
gtk_widget_set_state(widget, GTK_STATE_NORMAL);
1131
/* Handler for "button-press-event" event from taskbar button. */
1132
static gboolean taskbar_button_press_event(GtkWidget * widget, GdkEventButton * event, Task * tk)
1134
return taskbar_task_control_event(widget, event, tk, FALSE);
1137
/* Handler for "activate" event from grouped-task popup menu item. */
1138
static gboolean taskbar_popup_activate_event(GtkWidget * widget, GdkEventButton * event, Task * tk)
1140
return taskbar_task_control_event(widget, event, tk, TRUE);
1143
/* Handler for "drag-motion" timeout. */
1144
static gboolean taskbar_button_drag_motion_timeout(Task * tk)
1146
guint time = gtk_get_current_event_time();
1147
task_raise_window(tk, ((time != 0) ? time : CurrentTime));
1148
tk->tb->dnd_delay_timer = 0;
1152
/* Handler for "drag-motion" event from taskbar button. */
1153
static gboolean taskbar_button_drag_motion(GtkWidget * widget, GdkDragContext * drag_context, gint x, gint y, guint time, Task * tk)
1155
/* Prevent excessive motion notification. */
1156
if (tk->tb->dnd_delay_timer == 0)
1157
tk->tb->dnd_delay_timer = g_timeout_add(DRAG_ACTIVE_DELAY, (GSourceFunc) taskbar_button_drag_motion_timeout, tk);
1158
gdk_drag_status(drag_context, 0, time);
1162
/* Handler for "drag-leave" event from taskbar button. */
1163
static void taskbar_button_drag_leave(GtkWidget * widget, GdkDragContext * drag_context, guint time, Task * tk)
1165
/* Cancel the timer if set. */
1166
if (tk->tb->dnd_delay_timer != 0)
1168
g_source_remove(tk->tb->dnd_delay_timer);
1169
tk->tb->dnd_delay_timer = 0;
1174
/* Handler for "enter" event from taskbar button. This indicates that the cursor position has entered the button. */
1175
static void taskbar_button_enter(GtkWidget * widget, Task * tk)
1177
tk->entered_state = TRUE;
1178
if (tk->tb->flat_button)
1179
gtk_widget_set_state(widget, GTK_STATE_NORMAL);
1180
task_draw_label(tk);
1183
/* Handler for "leave" event from taskbar button. This indicates that the cursor position has left the button. */
1184
static void taskbar_button_leave(GtkWidget * widget, Task * tk)
1186
tk->entered_state = FALSE;
1187
task_draw_label(tk);
1190
/* Handler for "scroll-event" event from taskbar button. */
1191
static gboolean taskbar_button_scroll_event(GtkWidget * widget, GdkEventScroll * event, Task * tk)
1193
TaskbarPlugin * tb = tk->tb;
1194
TaskClass * tc = tk->res_class;
1195
if ((tb->use_mouse_wheel)
1196
&& (( ! tb->grouped_tasks) || (tc == NULL) || (tc->visible_count == 1)))
1198
if ((event->direction == GDK_SCROLL_UP) || (event->direction == GDK_SCROLL_LEFT))
1199
task_raise_window(tk, event->time);
921
if (tk->focused || tk == tk->tb->ptk)
922
XIconifyWindow (GDK_DISPLAY(), tk->win, DefaultScreen(GDK_DISPLAY()));
924
tk_raise_window( tk, event->time );
927
else if (event->button == 2)
929
Xclimsg(tk->win, a_NET_WM_STATE,
930
2 /*a_NET_WM_STATE_TOGGLE*/,
931
a_NET_WM_STATE_SHADED,
934
XSync (gdk_display, False);
941
tk_update(gpointer key, task *tk, taskbar *tb)
944
g_assert ((tb != NULL) && (tk != NULL));
945
if (task_visible(tb, tk)) {
946
/* g_debug( "SET_ACTIVE: %p, %d", tk->button, tk->focused ); */
947
if( gtk_toggle_button_get_active( (GtkToggleButton*)tk->button) != tk->focused )
948
gtk_toggle_button_set_active( (GtkToggleButton*)tk->button, tk->focused );
950
gtk_widget_show(tk->button);
952
//DBG2("tip %x %s\n", tk->win, tk->name);
953
gtk_widget_set_tooltip_text( tk->button, tk->name );
957
gtk_widget_hide(tk->button);
962
tk_display(taskbar *tb, task *tk)
965
tk_update(NULL, tk, tb);
970
tb_display(taskbar *tb)
974
g_hash_table_foreach(tb->task_list, (GHFunc) tk_update, (gpointer) tb);
979
static void on_tk_btn_size_allocate(GtkWidget* btn, GtkAllocation* alloc, task* tk)
982
if( ! GTK_WIDGET_REALIZED(btn) )
984
gdk_window_get_origin(GTK_BUTTON(btn)->event_window, &x, &y);
985
set_iconification_dest( tk->win, x, y, alloc->width, alloc->height );
989
tk_build_gui(taskbar *tb, task *tk)
994
g_assert ((tb != NULL) && (tk != NULL));
1201
XIconifyWindow(GDK_DISPLAY(), tk->win, DefaultScreen(GDK_DISPLAY()));
1206
/* Handler for "size-allocate" event from taskbar button. */
1207
static void taskbar_button_size_allocate(GtkWidget * btn, GtkAllocation * alloc, Task * tk)
1209
if (GTK_WIDGET_REALIZED(btn))
1211
/* Get the coordinates of the button. */
1213
gdk_window_get_origin(GTK_BUTTON(btn)->event_window, &x, &y);
1215
/* Send a NET_WM_ICON_GEOMETRY property change on the window. */
1219
data[2] = alloc->width;
1220
data[3] = alloc->height;
1221
XChangeProperty(GDK_DISPLAY(), tk->win,
1222
gdk_x11_get_xatom_by_name("_NET_WM_ICON_GEOMETRY"),
1223
XA_CARDINAL, 32, PropModeReplace, (guchar *) &data, 4);
1227
/* Update style on the taskbar when created or after a configuration change. */
1228
static void taskbar_update_style(TaskbarPlugin * tb)
1230
GtkOrientation bo = (tb->plug->panel->orientation == ORIENT_HORIZ) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
1231
icon_grid_set_geometry(tb->icon_grid, bo,
1232
((tb->icons_only) ? tb->icon_size + ICON_ONLY_EXTRA : tb->task_width_max), tb->icon_size + BUTTON_HEIGHT_EXTRA,
1233
tb->spacing, 0, tb->plug->panel->height);
1236
/* Update style on a task button when created or after a configuration change. */
1237
static void task_update_style(Task * tk, TaskbarPlugin * tb)
1240
gtk_widget_hide(tk->label);
1242
gtk_widget_show(tk->label);
1244
if( tb->flat_button )
1246
gtk_toggle_button_set_active((GtkToggleButton*)tk->button, FALSE);
1247
gtk_button_set_relief(GTK_BUTTON(tk->button), GTK_RELIEF_NONE);
1251
gtk_toggle_button_set_active((GtkToggleButton*)tk->button, tk->focused);
1252
gtk_button_set_relief(GTK_BUTTON(tk->button), GTK_RELIEF_NORMAL);
1255
task_draw_label(tk);
1258
/* Build graphic elements needed for a task button. */
1259
static void task_build_gui(TaskbarPlugin * tb, Task * tk)
997
1262
* 1. the extended mask is sum of taskbar and pager needs
998
1263
* see bug [ 940441 ] pager loose track of windows
1000
* Do not change event mask to gtk windows spwaned by this gtk client
1265
* Do not change event mask to gtk windows spawned by this gtk client
1001
1266
* this breaks gtk internals */
1002
if (!FBPANEL_WIN(tk->win))
1003
XSelectInput (GDK_DISPLAY(), tk->win, PropertyChangeMask | StructureNotifyMask);
1267
if ( ! FBPANEL_WIN(tk->win))
1268
XSelectInput(GDK_DISPLAY(), tk->win, PropertyChangeMask | StructureNotifyMask);
1270
/* Allocate a toggle button as the top level widget. */
1007
1271
tk->button = gtk_toggle_button_new();
1008
if( tb->flat_button )
1009
gtk_button_set_relief( (GtkButton*)tk->button, GTK_RELIEF_NONE );
1011
gtk_button_set_relief( (GtkButton*)tk->button, GTK_RELIEF_NORMAL);
1013
gtk_widget_show(tk->button);
1014
1272
gtk_container_set_border_width(GTK_CONTAINER(tk->button), 0);
1015
gtk_widget_add_events (tk->button, GDK_BUTTON_RELEASE_MASK );
1016
g_signal_connect(tk->button, "button_press_event",
1017
G_CALLBACK(on_tk_btn_press_event), (gpointer)tk);
1018
g_signal_connect(tk->button, "button_release_event",
1019
G_CALLBACK(on_tk_btn_release_event), (gpointer)tk);
1021
g_signal_connect_after (G_OBJECT (tk->button), "leave",
1022
G_CALLBACK (on_tk_leave), (gpointer) tk);
1023
g_signal_connect_after (G_OBJECT (tk->button), "enter",
1024
G_CALLBACK (on_tk_enter), (gpointer) tk);
1026
g_signal_connect(tk->button, "size-allocate",
1027
G_CALLBACK(on_tk_btn_size_allocate), (gpointer)tk);
1030
g_signal_connect_after (G_OBJECT (tk->button), "expose-event",
1031
G_CALLBACK (on_tk_expose), (gpointer) tk);
1033
gtk_drag_dest_set( tk->button, 0, NULL, 0, 0);
1034
g_signal_connect (G_OBJECT (tk->button), "drag-motion",
1035
G_CALLBACK (on_tk_drag_motion), (gpointer) tk);
1036
g_signal_connect (G_OBJECT (tk->button), "drag-leave",
1037
G_CALLBACK (on_tk_drag_leave), (gpointer) tk);
1038
g_signal_connect_after(G_OBJECT(tk->button), "scroll-event",
1039
G_CALLBACK(on_tk_scroll_event), (gpointer)tk);
1042
w1 = tb->plug->panel->my_box_new(FALSE, 1);
1043
gtk_container_set_border_width(GTK_CONTAINER(w1), 0);
1047
tk_update_icon(tb, tk, None);
1048
tk->image = gtk_image_new_from_pixbuf(tk->pixbuf );
1273
gtk_drag_dest_set(tk->button, 0, NULL, 0, 0);
1275
/* Connect signals to the button. */
1276
g_signal_connect(tk->button, "button_press_event", G_CALLBACK(taskbar_button_press_event), (gpointer) tk);
1277
g_signal_connect(G_OBJECT(tk->button), "drag-motion", G_CALLBACK(taskbar_button_drag_motion), (gpointer) tk);
1278
g_signal_connect(G_OBJECT(tk->button), "drag-leave", G_CALLBACK(taskbar_button_drag_leave), (gpointer) tk);
1279
g_signal_connect_after(G_OBJECT (tk->button), "enter", G_CALLBACK(taskbar_button_enter), (gpointer) tk);
1280
g_signal_connect_after(G_OBJECT (tk->button), "leave", G_CALLBACK(taskbar_button_leave), (gpointer) tk);
1281
g_signal_connect_after(G_OBJECT(tk->button), "scroll-event", G_CALLBACK(taskbar_button_scroll_event), (gpointer) tk);
1282
g_signal_connect(tk->button, "size-allocate", G_CALLBACK(taskbar_button_size_allocate), (gpointer) tk);
1284
/* Create a box to contain the application icon and window title. */
1285
GtkWidget * container = gtk_hbox_new(FALSE, 1);
1286
gtk_container_set_border_width(GTK_CONTAINER(container), 0);
1288
/* Create an image to contain the application icon and add it to the box. */
1289
GdkPixbuf* pixbuf = task_update_icon(tb, tk, None);
1290
tk->image = gtk_image_new_from_pixbuf(pixbuf);
1291
gtk_misc_set_padding(GTK_MISC(tk->image), 0, 0);
1292
g_object_unref(pixbuf);
1049
1293
gtk_widget_show(tk->image);
1050
gtk_box_pack_start(GTK_BOX(w1), tk->image, FALSE, FALSE, 0);
1053
tk->label = gtk_label_new(tk->iconified ? tk->iname : tk->name);
1054
update_label_orient( tk->label, tb->plug );
1055
if (!tb->icons_only)
1056
gtk_widget_show(tk->label);
1057
gtk_box_pack_start(GTK_BOX(w1), tk->label, TRUE, TRUE, 0);
1058
gtk_widget_show(w1);
1059
gtk_container_add (GTK_CONTAINER (tk->button), w1);
1061
//gtk_container_add (GTK_CONTAINER (tk->eb), tk->button);
1062
gtk_box_pack_start(GTK_BOX(tb->bar), tk->button, FALSE, TRUE, 0);
1063
GTK_WIDGET_UNSET_FLAGS (tk->button, GTK_CAN_FOCUS);
1064
GTK_WIDGET_UNSET_FLAGS (tk->button, GTK_CAN_DEFAULT);
1066
gtk_widget_show(tk->button);
1067
if (!task_visible(tb, tk)) {
1068
gtk_widget_hide(tk->button);
1072
/* Flash button for window with urgency hint */
1073
tk_flash_window(tk);
1078
/* tell to remove element with zero refcount */
1080
tb_remove_stale_tasks(Window *win, task *tk, gpointer data)
1083
if (tk->refcount-- == 0) {
1084
//DBG("tb_net_list <del>: 0x%x %s\n", tk->win, tk->name);
1085
del_task(tk->tb, tk, 0);
1294
gtk_box_pack_start(GTK_BOX(container), tk->image, FALSE, FALSE, 0);
1296
/* Create a label to contain the window title and add it to the box. */
1297
tk->label = gtk_label_new(NULL);
1298
gtk_misc_set_alignment(GTK_MISC(tk->label), 0.0, 0.5);
1299
gtk_label_set_ellipsize(GTK_LABEL(tk->label), PANGO_ELLIPSIZE_END);
1300
gtk_box_pack_start(GTK_BOX(container), tk->label, TRUE, TRUE, 0);
1302
/* Add the box to the button. */
1303
gtk_widget_show(container);
1304
gtk_container_add(GTK_CONTAINER(tk->button), container);
1305
gtk_container_set_border_width(GTK_CONTAINER(tk->button), 0);
1307
/* Add the button to the taskbar. */
1308
icon_grid_add(tb->icon_grid, tk->button, TRUE);
1309
GTK_WIDGET_UNSET_FLAGS(tk->button, GTK_CAN_FOCUS);
1310
GTK_WIDGET_UNSET_FLAGS(tk->button, GTK_CAN_DEFAULT);
1312
/* Update styles on the button. */
1313
task_update_style(tk, tb);
1315
/* Flash button for window with urgency hint. */
1317
task_set_urgency(tk);
1091
1320
/*****************************************************
1092
1321
* handlers for NET actions *
1093
1322
*****************************************************/
1097
tb_net_client_list(GtkWidget *widget, taskbar *tb)
1105
tb->wins = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_CLIENT_LIST, XA_WINDOW, &tb->win_num);
1108
for (i = 0; i < tb->win_num; i++) {
1109
if ((tk = g_hash_table_lookup(tb->task_list, &tb->wins[i]))) {
1112
NetWMWindowType nwwt;
1115
get_net_wm_state(tb->wins[i], &nws);
1116
if (!accept_net_wm_state(&nws, tb->accept_skip_pager))
1118
get_net_wm_window_type(tb->wins[i], &nwwt);
1119
if (!accept_net_wm_window_type(&nwwt))
1122
tk = g_new0(task, 1);
1125
tk->win = tb->wins[i];
1127
tk->iconified = (get_wm_state(tk->win) == IconicState);
1128
tk->desktop = get_net_wm_desktop(tk->win);
1131
if( tb->use_urgency_hint && tk_has_urgency(tk)) {
1135
tk_build_gui(tb, tk);
1137
g_hash_table_insert(tb->task_list, &tk->win, tk);
1138
DBG("adding %08x(%p) %s\n", tk->win, FBPANEL_WIN(tk->win), tk->name);
1142
/* remove windows that arn't in the NET_CLIENT_LIST anymore */
1143
g_hash_table_foreach_remove(tb->task_list, (GHRFunc) tb_remove_stale_tasks, NULL);
1149
tb_net_current_desktop(GtkWidget *widget, taskbar *tb)
1152
tb->cur_desk = get_net_current_desktop();
1158
tb_net_number_of_desktops(GtkWidget *widget, taskbar *tb)
1161
tb->desk_num = get_net_number_of_desktops();
1167
/* set new active window. if that happens to be us, then remeber
1168
* current focus to use it for iconify command */
1170
tb_net_active_window(GtkWidget *widget, taskbar *tb)
1174
int drop_old, make_new;
1177
g_assert (tb != NULL);
1178
drop_old = make_new = 0;
1181
f = get_xaproperty(GDK_ROOT_WINDOW(), a_NET_ACTIVE_WINDOW, XA_WINDOW, 0);
1182
DBG("FOCUS=%x\n", f ? *f : 0);
1187
if (*f == tb->topxwin) {
1194
ntk = find_task(tb, *f);
1324
/* Handler for "client-list" event from root window listener. */
1325
static void taskbar_net_client_list(GtkWidget * widget, TaskbarPlugin * tb)
1327
/* Get the NET_CLIENT_LIST property. */
1329
Window * client_list = get_xaproperty(GDK_ROOT_WINDOW(), a_NET_CLIENT_LIST, XA_WINDOW, &client_count);
1330
if (client_list != NULL)
1332
/* Loop over client list, correlating it with task list. */
1334
for (i = 0; i < client_count; i++)
1336
/* Search for the window in the task list. Set up context to do an insert right away if needed. */
1337
Task * tk_pred = NULL;
1340
for (tk_cursor = tb->task_list; tk_cursor != NULL; tk_pred = tk_cursor, tk_cursor = tk_cursor->task_flink)
1342
if (tk_cursor->win == client_list[i])
1347
if (tk_cursor->win > client_list[i])
1351
/* Task is already in task list. */
1353
tk->present_in_client_list = TRUE;
1355
/* Task is not in task list. */
1358
/* Evaluate window state and window type to see if it should be in task list. */
1359
NetWMWindowType nwwt;
1361
get_net_wm_state(client_list[i], &nws);
1362
get_net_wm_window_type(client_list[i], &nwwt);
1363
if ((accept_net_wm_state(&nws))
1364
&& (accept_net_wm_window_type(&nwwt)))
1366
/* Allocate and initialize new task structure. */
1367
tk = g_new0(Task, 1);
1368
tk->present_in_client_list = TRUE;
1369
tk->win = client_list[i];
1371
tk->name_source = None;
1372
tk->image_source = None;
1373
tk->iconified = (get_wm_state(tk->win) == IconicState);
1374
tk->desktop = get_net_wm_desktop(tk->win);
1375
if (tb->use_urgency_hint)
1376
tk->urgency = task_has_urgency(tk);
1377
task_build_gui(tb, tk);
1378
task_set_names(tk, None);
1381
/* Link the task structure into the task list. */
1382
if (tk_pred == NULL)
1384
tk->task_flink = tb->task_list;
1389
tk->task_flink = tk_pred->task_flink;
1390
tk_pred->task_flink = tk;
1398
/* Remove windows from the task list that are not present in the NET_CLIENT_LIST. */
1399
Task * tk_pred = NULL;
1400
Task * tk = tb->task_list;
1403
Task * tk_succ = tk->task_flink;
1404
if (tk->present_in_client_list)
1406
tk->present_in_client_list = FALSE;
1411
if (tk_pred == NULL)
1412
tb->task_list = tk_succ;
1413
else tk_pred->task_flink = tk_succ;
1414
task_delete(tb, tk, FALSE);
1419
/* Redraw the taskbar. */
1423
/* Handler for "current-desktop" event from root window listener. */
1424
static void taskbar_net_current_desktop(GtkWidget * widget, TaskbarPlugin * tb)
1426
/* Store the local copy of current desktops. Redisplay the taskbar. */
1427
tb->current_desktop = get_net_current_desktop();
1428
recompute_group_visibility_on_current_desktop(tb);
1432
/* Handler for "number-of-desktops" event from root window listener. */
1433
static void taskbar_net_number_of_desktops(GtkWidget * widget, TaskbarPlugin * tb)
1435
/* Store the local copy of number of desktops. Recompute the popup menu and redisplay the taskbar. */
1436
tb->number_of_desktops = get_net_number_of_desktops();
1437
taskbar_make_menu(tb);
1441
/* Handler for "active-window" event from root window listener. */
1442
static void taskbar_net_active_window(GtkWidget * widget, TaskbarPlugin * tb)
1444
gboolean drop_old = FALSE;
1445
gboolean make_new = FALSE;
1446
Task * ctk = tb->focused;
1449
/* Get the window that has focus. */
1450
Window * f = get_xaproperty(GDK_ROOT_WINDOW(), a_NET_ACTIVE_WINDOW, XA_WINDOW, 0);
1453
/* No window has focus. */
1455
tb->focused_previous = NULL;
1459
if (*f == tb->plug->panel->topxwin)
1461
/* Taskbar window gained focus (this isn't supposed to be able to happen). Remember current focus. */
1464
tb->focused_previous = ctk;
1470
/* Identify task that gained focus. */
1471
tb->focused_previous = NULL;
1472
ntk = task_lookup(tb, *f);
1202
if (ctk && drop_old) {
1482
/* If our idea of the current task lost focus, update data structures. */
1483
if ((ctk != NULL) && (drop_old))
1485
ctk->focused = FALSE;
1204
1486
tb->focused = NULL;
1205
tk_display(tb, ctk);
1206
DBG("old focus was dropped\n");
1487
if(!tb->flat_button) /* relieve the button if flat buttons is not used. */
1488
gtk_toggle_button_set_active((GtkToggleButton*)ctk->button, FALSE);
1490
task_button_redraw(ctk, tb);
1208
if (ntk && make_new) {
1493
/* If a task gained focus, update data structures. */
1494
if ((ntk != NULL) && (make_new))
1496
if(!tb->flat_button) /* depress the button if flat buttons is not used. */
1497
gtk_toggle_button_set_active((GtkToggleButton*)ntk->button, TRUE);
1498
ntk->focused = TRUE;
1210
1499
tb->focused = ntk;
1211
tk_display(tb, ntk);
1212
DBG("new focus was set\n");
1217
/* For older Xlib headers */
1218
#ifndef XUrgencyHint
1219
#define XUrgencyHint (1 << 8)
1223
tk_has_urgency( task* tk )
1228
hints = (XWMHints *) get_xaproperty (tk->win, XA_WM_HINTS, XA_WM_HINTS, 0);
1230
if (hints->flags & XUrgencyHint) /* Got urgency hint */
1238
tb_propertynotify(taskbar *tb, XEvent *ev)
1244
DBG("win=%x\n", ev->xproperty.window);
1246
/* The property is deleted */
1247
if( ((XPropertyEvent*)ev)->state == 1 )
1250
at = ev->xproperty.atom;
1251
win = ev->xproperty.window;
1252
if (win != GDK_ROOT_WINDOW()) {
1253
task *tk = find_task(tb, win);
1256
DBG("win=%x\n", ev->xproperty.window);
1257
if (at == a_NET_WM_DESKTOP) {
1258
DBG("NET_WM_DESKTOP\n");
1259
tk->desktop = get_net_wm_desktop(win);
1261
} else if (at == XA_WM_NAME) {
1264
//tk_display(tb, tk);
1265
} else if (at == XA_WM_CLASS) {
1268
} else if (at == a_WM_STATE) {
1270
/* iconified state changed? */
1271
tk->iconified = (get_wm_state (tk->win) == IconicState);
1273
//tk_display(tb, tk);
1274
} else if (at == XA_WM_HINTS) {
1275
/* some windows set their WM_HINTS icon after mapping */
1276
DBG("XA_WM_HINTS\n");
1278
tk_update_icon (tb, tk, XA_WM_HINTS);
1279
gtk_image_set_from_pixbuf (GTK_IMAGE(tk->image), tk->pixbuf);
1280
if (tb->use_urgency_hint) {
1281
if (tk_has_urgency(tk)) {
1283
tk_flash_window(tk);
1286
tk_unflash_window(tk);
1289
} else if (at == a_NET_WM_STATE) {
1292
DBG("_NET_WM_STATE\n");
1293
get_net_wm_state(tk->win, &nws);
1294
if (!accept_net_wm_state(&nws, tb->accept_skip_pager)) {
1295
del_task(tb, tk, 1);
1298
} else if (at == a_NET_WM_ICON) {
1299
DBG("_NET_WM_ICON\n");
1300
DBG("#0 %d\n", GDK_IS_PIXBUF (tk->pixbuf));
1301
tk_update_icon (tb, tk, a_NET_WM_ICON);
1302
DBG("#1 %d\n", GDK_IS_PIXBUF (tk->pixbuf));
1303
gtk_image_set_from_pixbuf (GTK_IMAGE(tk->image), tk->pixbuf);
1304
DBG("#2 %d\n", GDK_IS_PIXBUF (tk->pixbuf));
1305
} else if (at == a_NET_WM_WINDOW_TYPE) {
1306
NetWMWindowType nwwt;
1308
DBG("_NET_WM_WINDOW_TYPE\n");
1309
get_net_wm_window_type(tk->win, &nwwt);
1310
if (!accept_net_wm_window_type(&nwwt)) {
1311
del_task(tb, tk, 1);
1315
DBG("at = %d\n", at);
1500
task_button_redraw(ntk, tb);
1504
/* Determine if the "urgency" hint is set on a window. */
1505
static gboolean task_has_urgency(Task * tk)
1507
gboolean result = FALSE;
1508
XWMHints * hints = (XWMHints *) get_xaproperty(tk->win, XA_WM_HINTS, XA_WM_HINTS, 0);
1511
if (hints->flags & XUrgencyHint)
1518
/* Handle PropertyNotify event.
1519
* http://tronche.com/gui/x/icccm/
1520
* http://standards.freedesktop.org/wm-spec/wm-spec-1.4.html */
1521
static void taskbar_property_notify_event(TaskbarPlugin *tb, XEvent *ev)
1523
/* State may be PropertyNewValue, PropertyDeleted. */
1524
if (((XPropertyEvent*) ev)->state == PropertyNewValue)
1526
Atom at = ev->xproperty.atom;
1527
Window win = ev->xproperty.window;
1528
if (win != GDK_ROOT_WINDOW())
1530
/* Look up task structure by X window handle. */
1531
Task * tk = task_lookup(tb, win);
1534
/* Install an error handler that ignores BadWindow.
1535
* We frequently get a PropertyNotify event on deleted windows. */
1536
XErrorHandler previous_error_handler = XSetErrorHandler(panel_handle_x_error_swallow_BadWindow_BadDrawable);
1538
/* Dispatch on atom. */
1539
if (at == a_NET_WM_DESKTOP)
1541
/* Window changed desktop. */
1542
tk->desktop = get_net_wm_desktop(win);
1545
else if ((at == XA_WM_NAME) || (at == a_NET_WM_NAME) || (at == a_NET_WM_VISIBLE_NAME))
1547
/* Window changed name. */
1548
task_set_names(tk, at);
1549
if (tk->res_class != NULL)
1551
/* A change to the window name may change the visible name of the class. */
1552
recompute_group_visibility_for_class(tb, tk->res_class);
1553
if (tk->res_class->visible_task != NULL)
1554
task_draw_label(tk->res_class->visible_task);
1557
else if (at == XA_WM_CLASS)
1559
/* Window changed class. */
1563
else if (at == a_WM_STATE)
1565
/* Window changed state. */
1566
tk->iconified = (get_wm_state(win) == IconicState);
1567
task_draw_label(tk);
1569
else if (at == XA_WM_HINTS)
1571
/* Window changed "window manager hints".
1572
* Some windows set their WM_HINTS icon after mapping. */
1573
GdkPixbuf * pixbuf = task_update_icon(tb, tk, XA_WM_HINTS);
1576
gtk_image_set_from_pixbuf(GTK_IMAGE(tk->image), pixbuf);
1577
g_object_unref(pixbuf);
1580
if (tb->use_urgency_hint)
1582
tk->urgency = task_has_urgency(tk);
1584
task_set_urgency(tk);
1586
task_clear_urgency(tk);
1589
else if (at == a_NET_WM_STATE)
1591
/* Window changed EWMH state. */
1593
get_net_wm_state(tk->win, &nws);
1594
if ( ! accept_net_wm_state(&nws))
1596
task_delete(tb, tk, TRUE);
1600
else if (at == a_NET_WM_ICON)
1602
/* Window changed EWMH icon. */
1603
GdkPixbuf * pixbuf = task_update_icon(tb, tk, a_NET_WM_ICON);
1606
gtk_image_set_from_pixbuf(GTK_IMAGE(tk->image), pixbuf);
1607
g_object_unref(pixbuf);
1610
else if (at == a_NET_WM_WINDOW_TYPE)
1612
/* Window changed EWMH window type. */
1613
NetWMWindowType nwwt;
1614
get_net_wm_window_type(tk->win, &nwwt);
1615
if ( ! accept_net_wm_window_type(&nwwt))
1617
task_delete(tb, tk, TRUE);
1621
XSetErrorHandler(previous_error_handler);
1321
static GdkFilterReturn
1322
tb_event_filter( XEvent *xev, GdkEvent *event, taskbar *tb)
1326
//RET(GDK_FILTER_CONTINUE);
1327
g_assert(tb != NULL);
1328
if (xev->type == PropertyNotify )
1329
tb_propertynotify(tb, xev);
1330
RET(GDK_FILTER_CONTINUE);
1334
menu_close_window(GtkWidget *widget, taskbar *tb)
1337
DBG("win %x\n", tb->menutask->win);
1338
XSync (GDK_DISPLAY(), 0);
1339
//XKillClient(GDK_DISPLAY(), tb->menutask->win);
1627
/* GDK event filter. */
1628
static GdkFilterReturn taskbar_event_filter(XEvent * xev, GdkEvent * event, TaskbarPlugin * tb)
1630
/* Look for PropertyNotify events and update state. */
1631
if (xev->type == PropertyNotify)
1632
taskbar_property_notify_event(tb, xev);
1633
return GDK_FILTER_CONTINUE;
1636
/* Handler for "activate" event on Raise item of right-click menu for task buttons. */
1637
static void menu_raise_window(GtkWidget * widget, TaskbarPlugin * tb)
1639
if ((tb->menutask->desktop != -1) && (tb->menutask->desktop != tb->current_desktop))
1640
Xclimsg(GDK_ROOT_WINDOW(), a_NET_CURRENT_DESKTOP, tb->menutask->desktop, 0, 0, 0, 0);
1641
XMapRaised(GDK_DISPLAY(), tb->menutask->win);
1642
task_group_menu_destroy(tb);
1645
/* Handler for "activate" event on Restore item of right-click menu for task buttons. */
1646
static void menu_restore_window(GtkWidget * widget, TaskbarPlugin * tb)
1648
GdkWindow * win = gdk_window_foreign_new(tb->menutask->win);
1649
gdk_window_unmaximize(win);
1650
gdk_window_unref(win);
1651
task_group_menu_destroy(tb);
1654
/* Handler for "activate" event on Maximize item of right-click menu for task buttons. */
1655
static void menu_maximize_window(GtkWidget * widget, TaskbarPlugin * tb)
1657
GdkWindow * win = gdk_window_foreign_new(tb->menutask->win);
1658
gdk_window_maximize(win);
1659
gdk_window_unref(win);
1660
task_group_menu_destroy(tb);
1663
/* Handler for "activate" event on Iconify item of right-click menu for task buttons. */
1664
static void menu_iconify_window(GtkWidget * widget, TaskbarPlugin * tb)
1666
XIconifyWindow(GDK_DISPLAY(), tb->menutask->win, DefaultScreen(GDK_DISPLAY()));
1667
task_group_menu_destroy(tb);
1670
/* Handler for "activate" event on Move to Workspace item of right-click menu for task buttons. */
1671
static void menu_move_to_workspace(GtkWidget * widget, TaskbarPlugin * tb)
1673
int num = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "num"));
1674
Xclimsg(tb->menutask->win, a_NET_WM_DESKTOP, num, 0, 0, 0, 0);
1675
task_group_menu_destroy(tb);
1678
/* Handler for "activate" event on Close item of right-click menu for task buttons. */
1679
static void menu_close_window(GtkWidget * widget, TaskbarPlugin * tb)
1340
1681
Xclimsgwm(tb->menutask->win, a_WM_PROTOCOLS, a_WM_DELETE_WINDOW);
1341
XSync (GDK_DISPLAY(), 0);
1347
menu_raise_window(GtkWidget *widget, taskbar *tb)
1350
DBG("win %x\n", tb->menutask->win);
1351
XMapRaised(GDK_DISPLAY(), tb->menutask->win);
1357
menu_iconify_window(GtkWidget *widget, taskbar *tb)
1360
DBG("win %x\n", tb->menutask->win);
1361
XIconifyWindow (GDK_DISPLAY(), tb->menutask->win, DefaultScreen(GDK_DISPLAY()));
1366
menu_restore_window(GtkWidget *widget, taskbar *tb)
1370
DBG("win %x\n", tb->menutask->win);
1371
win = gdk_window_foreign_new( tb->menutask->win );
1372
gdk_window_unmaximize( win );
1373
gdk_window_unref( win );
1378
menu_maximize_window(GtkWidget *widget, taskbar *tb)
1382
DBG("win %x\n", tb->menutask->win);
1383
win = gdk_window_foreign_new( tb->menutask->win );
1384
gdk_window_maximize( win );
1385
gdk_window_unref( win );
1390
menu_move_to_workspace( GtkWidget* mi, taskbar* tb )
1393
int num = GPOINTER_TO_INT( g_object_get_data( G_OBJECT(mi), "num" ) );
1394
_wnck_change_workspace( DefaultScreenOfDisplay(GDK_DISPLAY()), tb->menutask->win, num );
1398
taskbar_make_menu(taskbar *tb)
1400
GtkWidget *mi, *menu, *workspace_menu = NULL;
1405
menu = gtk_menu_new ();
1407
mi = gtk_menu_item_new_with_label (_("Raise"));
1408
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
1409
g_signal_connect(G_OBJECT(mi), "activate", (GCallback)menu_raise_window, tb);
1411
mi = gtk_menu_item_new_with_label (_("Restore"));
1412
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
1413
g_signal_connect(G_OBJECT(mi), "activate", (GCallback)menu_restore_window, tb);
1415
mi = gtk_menu_item_new_with_label (_("Maximize"));
1416
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
1417
g_signal_connect(G_OBJECT(mi), "activate", (GCallback)menu_maximize_window, tb);
1419
mi = gtk_menu_item_new_with_label (_("Iconify"));
1420
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
1421
g_signal_connect(G_OBJECT(mi), "activate", (GCallback)menu_iconify_window, tb);
1423
if( tb->desk_num > 1 )
1682
task_group_menu_destroy(tb);
1685
/* Make right-click menu for task buttons.
1686
* This depends on number of desktops and edge. */
1687
static void taskbar_make_menu(TaskbarPlugin * tb)
1689
/* Deallocate old menu if present. */
1690
if (tb->menu != NULL)
1691
gtk_widget_destroy(tb->menu);
1693
/* Allocate menu. */
1694
GtkWidget * menu = gtk_menu_new();
1696
/* Add Raise menu item. */
1697
GtkWidget *mi = gtk_menu_item_new_with_mnemonic(_("_Raise"));
1698
gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
1699
g_signal_connect(G_OBJECT(mi), "activate", (GCallback) menu_raise_window, tb);
1701
/* Add Restore menu item. */
1702
mi = gtk_menu_item_new_with_mnemonic(_("R_estore"));
1703
gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
1704
g_signal_connect(G_OBJECT(mi), "activate", (GCallback) menu_restore_window, tb);
1706
/* Add Maximize menu item. */
1707
mi = gtk_menu_item_new_with_mnemonic(_("Ma_ximize"));
1708
gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
1709
g_signal_connect(G_OBJECT(mi), "activate", (GCallback) menu_maximize_window, tb);
1711
/* Add Iconify menu item. */
1712
mi = gtk_menu_item_new_with_mnemonic(_("Ico_nify"));
1713
gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
1714
g_signal_connect(G_OBJECT(mi), "activate", (GCallback) menu_iconify_window, tb);
1716
/* If multiple desktops are supported, add menu items to select them. */
1717
if (tb->number_of_desktops > 1)
1425
workspace_menu = gtk_menu_new();
1426
for( i = 1; i <= tb->desk_num; ++i )
1721
/* Allocate submenu. */
1722
GtkWidget * workspace_menu = gtk_menu_new();
1724
/* Loop over all desktops. */
1726
for (i = 1; i <= tb->number_of_desktops; i++)
1428
g_snprintf( label, 128, _("Workspace %d"), i);
1429
mi = gtk_menu_item_new_with_label( label );
1430
g_object_set_data( G_OBJECT(mi), "num", GINT_TO_POINTER(i - 1) );
1431
g_signal_connect( mi, "activate", G_CALLBACK(menu_move_to_workspace), tb );
1432
gtk_menu_shell_append( (GtkMenuShell*)workspace_menu, mi );
1728
/* For the first 9 desktops, allow the desktop number as a keyboard shortcut. */
1731
g_snprintf(label, sizeof(label), _("Workspace _%d"), i);
1732
mi = gtk_menu_item_new_with_mnemonic(label);
1736
g_snprintf(label, sizeof(label), _("Workspace %d"), i);
1737
mi = gtk_menu_item_new_with_label(label);
1740
/* Set the desktop number as a property on the menu item. */
1741
g_object_set_data(G_OBJECT(mi), "num", GINT_TO_POINTER(i - 1));
1742
g_signal_connect(mi, "activate", G_CALLBACK(menu_move_to_workspace), tb);
1743
gtk_menu_shell_append(GTK_MENU_SHELL(workspace_menu), mi);
1434
gtk_menu_shell_append( GTK_MENU_SHELL (workspace_menu),
1435
gtk_separator_menu_item_new());
1436
mi = gtk_menu_item_new_with_label(_("All workspaces"));
1437
g_object_set_data( G_OBJECT(mi), "num", GINT_TO_POINTER(ALL_WORKSPACES) );
1438
g_signal_connect( mi, "activate", G_CALLBACK(menu_move_to_workspace), tb );
1439
gtk_menu_shell_append( (GtkMenuShell*)workspace_menu, mi );
1441
gtk_widget_show_all( workspace_menu );
1443
mi = gtk_menu_item_new_with_label (_("Move to Workspace"));
1444
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
1446
gtk_menu_item_set_submenu( GTK_MENU_ITEM(mi), workspace_menu );
1447
workspace_menu = mi;
1746
/* Add a separator. */
1747
gtk_menu_shell_append(GTK_MENU_SHELL(workspace_menu), gtk_separator_menu_item_new());
1749
/* Add "move to all workspaces" item. This causes the window to be visible no matter what desktop is active. */
1750
mi = gtk_menu_item_new_with_mnemonic(_("_All workspaces"));
1751
g_object_set_data(G_OBJECT(mi), "num", GINT_TO_POINTER(ALL_WORKSPACES));
1752
g_signal_connect(mi, "activate", G_CALLBACK(menu_move_to_workspace), tb);
1753
gtk_menu_shell_append(GTK_MENU_SHELL(workspace_menu), mi);
1755
/* Add Move to Workspace menu item as a submenu. */
1756
mi = gtk_menu_item_new_with_mnemonic(_("_Move to Workspace"));
1757
gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
1758
gtk_menu_item_set_submenu(GTK_MENU_ITEM(mi), workspace_menu);
1450
/* we want this item to be farest from mouse pointer */
1451
mi = gtk_menu_item_new_with_label (_("Close Window"));
1452
if (tb->plug->panel->edge == EDGE_BOTTOM)
1761
/* Add Close menu item. By popular demand, we place this menu item closest to the cursor. */
1762
mi = gtk_menu_item_new_with_mnemonic (_("_Close Window"));
1763
if (tb->plug->panel->edge != EDGE_BOTTOM)
1454
gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), gtk_separator_menu_item_new());
1455
gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi);
1765
gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
1766
gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi);
1459
// gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), workspace_menu);
1461
gtk_menu_shell_append (GTK_MENU_SHELL (menu), gtk_separator_menu_item_new());
1462
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
1770
gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
1771
gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
1464
1773
g_signal_connect(G_OBJECT(mi), "activate", (GCallback)menu_close_window, tb);
1465
gtk_widget_show_all (menu);
1472
taskbar_build_gui(Plugin *p)
1474
taskbar *tb = (taskbar *)p->priv;
1479
bo = (tb->plug->panel->orientation == ORIENT_HORIZ) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
1480
tb->bar = gtk_bar_new(bo, tb->spacing);
1481
if (tb->icons_only) {
1482
gtk_bar_set_max_child_size(GTK_BAR(tb->bar),
1483
GTK_WIDGET(p->panel->box)->allocation.height -2);
1485
gtk_bar_set_max_child_size(GTK_BAR(tb->bar), tb->task_width_max);
1486
gtk_container_add (GTK_CONTAINER (p->pwid), tb->bar);
1487
gtk_widget_show(tb->bar);
1489
tb->gen_pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)icon_xpm);
1491
gdk_window_add_filter(NULL, (GdkFilterFunc)tb_event_filter, tb );
1493
g_signal_connect (G_OBJECT (fbev), "current_desktop",
1494
G_CALLBACK (tb_net_current_desktop), (gpointer) tb);
1495
g_signal_connect (G_OBJECT (fbev), "active_window",
1496
G_CALLBACK (tb_net_active_window), (gpointer) tb);
1497
g_signal_connect (G_OBJECT (fbev), "number_of_desktops",
1498
G_CALLBACK (tb_net_number_of_desktops), (gpointer) tb);
1499
g_signal_connect (G_OBJECT (fbev), "client_list",
1500
G_CALLBACK (tb_net_client_list), (gpointer) tb);
1502
tb->desk_num = get_net_number_of_desktops();
1503
tb->cur_desk = get_net_current_desktop();
1506
tb->menu = taskbar_make_menu(tb);
1507
gtk_container_set_border_width(GTK_CONTAINER(p->pwid), 0);
1508
gtk_widget_show_all(tb->bar);
1512
void net_active_detect()
1517
data = get_xaproperty(GDK_ROOT_WINDOW(), a_NET_SUPPORTED, XA_ATOM, &nitens);
1522
if(data[--nitens]==a_NET_ACTIVE_WINDOW) {
1523
use_net_active = TRUE;
1531
taskbar_constructor(Plugin *p, char** fp)
1775
gtk_widget_show_all(menu);
1779
/* Build graphic elements needed for the taskbar. */
1780
static void taskbar_build_gui(Plugin * p)
1782
TaskbarPlugin * tb = (TaskbarPlugin *) p->priv;
1784
/* Set up style for taskbar. */
1539
1785
gtk_rc_parse_string(taskbar_rc);
1541
/* FIXME: Is there any better way to do this? */
1787
/* Allocate top level widget and set into Plugin widget pointer. */
1542
1788
p->pwid = gtk_event_box_new();
1543
GTK_WIDGET_SET_FLAGS( p->pwid, GTK_NO_WINDOW );
1789
gtk_container_set_border_width(GTK_CONTAINER(p->pwid), 0);
1790
GTK_WIDGET_SET_FLAGS(p->pwid, GTK_NO_WINDOW);
1544
1791
gtk_widget_set_name(p->pwid, "taskbar");
1546
get_button_spacing(&req, GTK_CONTAINER(p->pwid), "");
1548
net_active_detect();
1550
tb = g_new0(taskbar, 1);
1793
/* Make container for task buttons as a child of top level widget. */
1794
GtkOrientation bo = (tb->plug->panel->orientation == ORIENT_HORIZ) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
1795
tb->icon_grid = icon_grid_new(p->panel, p->pwid, bo, tb->task_width_max, tb->icon_size, tb->spacing, 0, p->panel->height);
1796
icon_grid_set_constrain_width(tb->icon_grid, TRUE);
1797
taskbar_update_style(tb);
1799
/* Add GDK event filter. */
1800
gdk_window_add_filter(NULL, (GdkFilterFunc) taskbar_event_filter, tb);
1802
/* Connect signal to receive mouse events on the unused portion of the taskbar. */
1803
g_signal_connect(p->pwid, "button-press-event", G_CALLBACK(plugin_button_press_event), p);
1805
/* Connect signals to receive root window events and initialize root window properties. */
1806
tb->number_of_desktops = get_net_number_of_desktops();
1807
tb->current_desktop = get_net_current_desktop();
1808
g_signal_connect(G_OBJECT(fbev), "current_desktop", G_CALLBACK(taskbar_net_current_desktop), (gpointer) tb);
1809
g_signal_connect(G_OBJECT(fbev), "active_window", G_CALLBACK(taskbar_net_active_window), (gpointer) tb);
1810
g_signal_connect(G_OBJECT(fbev), "number_of_desktops", G_CALLBACK(taskbar_net_number_of_desktops), (gpointer) tb);
1811
g_signal_connect(G_OBJECT(fbev), "client_list", G_CALLBACK(taskbar_net_client_list), (gpointer) tb);
1813
/* Make right-click menu for task buttons.
1814
* It is retained for the life of the taskbar and will be shown as needed.
1815
* Number of desktops and edge is needed for this operation. */
1816
taskbar_make_menu(tb);
1819
/* Determine if the window manager supports NET_ACTIVE_WINDOW. */
1820
static gboolean net_active_supported(void)
1823
Atom * data = get_xaproperty(GDK_ROOT_WINDOW(), a_NET_SUPPORTED, XA_ATOM, &nitems);
1829
if (data[--nitems] == a_NET_ACTIVE_WINDOW)
1839
/* Plugin constructor. */
1840
static int taskbar_constructor(Plugin * p, char ** fp)
1842
/* Allocate plugin context and set into Plugin private data pointer. */
1843
TaskbarPlugin * tb = g_new0(TaskbarPlugin, 1);
1554
if (p->panel->orientation == ORIENT_HORIZ) {
1555
tb->iconsize = GTK_WIDGET(p->panel->box)->allocation.height - req.height;
1556
DBG("pwid height = %d\n", GTK_WIDGET(p->pwid)->allocation.height);
1559
tb->topxwin = p->panel->topxwin;
1562
tb->accept_skip_pager = 1;
1563
tb->show_iconified = 1;
1564
tb->show_mapped = 1;
1565
tb->show_all_desks = 0;
1847
/* Initialize to defaults. */
1848
tb->icon_size = p->panel->icon_size;
1849
tb->tooltips = TRUE;
1850
tb->icons_only = FALSE;
1851
tb->show_all_desks = FALSE;
1566
1852
tb->task_width_max = TASK_WIDTH_MAX;
1567
tb->task_list = g_hash_table_new(g_int_hash, g_int_equal);
1568
tb->focused_state = GTK_STATE_ACTIVE;
1569
tb->normal_state = GTK_STATE_NORMAL;
1570
1853
tb->spacing = 1;
1571
tb->use_mouse_wheel = 1;
1572
tb->use_urgency_hint = 1;
1854
tb->use_mouse_wheel = TRUE;
1855
tb->use_urgency_hint = TRUE;
1856
tb->grouped_tasks = FALSE;
1857
tb->use_net_active = net_active_supported();
1859
/* Process configuration file. */
1576
1864
while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END) {
1577
1865
if (s.type == LINE_NONE) {
1578
1866
ERR( "taskbar: illegal token %s\n", s.str);
1581
if (s.type == LINE_VAR) {
1582
if (!g_ascii_strcasecmp(s.t[0], "tooltips")) {
1869
if (s.type == LINE_VAR)
1871
if (g_ascii_strcasecmp(s.t[0], "tooltips") == 0)
1583
1872
tb->tooltips = str2num(bool_pair, s.t[1], 1);
1584
} else if (!g_ascii_strcasecmp(s.t[0], "IconsOnly")) {
1873
else if (g_ascii_strcasecmp(s.t[0], "IconsOnly") == 0)
1585
1874
tb->icons_only = str2num(bool_pair, s.t[1], 0);
1586
} else if (!g_ascii_strcasecmp(s.t[0], "AcceptSkipPager")) {
1587
tb->accept_skip_pager = str2num(bool_pair, s.t[1], 1);
1588
} else if (!g_ascii_strcasecmp(s.t[0], "ShowIconified")) {
1589
tb->show_iconified = str2num(bool_pair, s.t[1], 1);
1590
} else if (!g_ascii_strcasecmp(s.t[0], "ShowMapped")) {
1591
tb->show_mapped = str2num(bool_pair, s.t[1], 1);
1592
} else if (!g_ascii_strcasecmp(s.t[0], "ShowAllDesks")) {
1875
else if (g_ascii_strcasecmp(s.t[0], "AcceptSkipPager") == 0) /* For backward compatibility */
1877
else if (g_ascii_strcasecmp(s.t[0], "ShowIconified") == 0) /* For backward compatibility */
1879
else if (g_ascii_strcasecmp(s.t[0], "ShowMapped") == 0) /* For backward compatibility */
1881
else if (g_ascii_strcasecmp(s.t[0], "ShowAllDesks") == 0)
1593
1882
tb->show_all_desks = str2num(bool_pair, s.t[1], 0);
1594
} else if (!g_ascii_strcasecmp(s.t[0], "MaxTaskWidth")) {
1883
else if (g_ascii_strcasecmp(s.t[0], "MaxTaskWidth") == 0)
1595
1884
tb->task_width_max = atoi(s.t[1]);
1596
DBG("task_width_max = %d\n", tb->task_width_max);
1597
} else if (!g_ascii_strcasecmp(s.t[0], "spacing")) {
1885
else if (g_ascii_strcasecmp(s.t[0], "spacing") == 0)
1598
1886
tb->spacing = atoi(s.t[1]);
1599
} else if (!g_ascii_strcasecmp(s.t[0], "UseMouseWheel")) {
1887
else if (g_ascii_strcasecmp(s.t[0], "UseMouseWheel") == 0)
1600
1888
tb->use_mouse_wheel = str2num(bool_pair, s.t[1], 1);
1601
} else if (!g_ascii_strcasecmp(s.t[0], "UseUrgencyHint")) {
1889
else if (g_ascii_strcasecmp(s.t[0], "UseUrgencyHint") == 0)
1602
1890
tb->use_urgency_hint = str2num(bool_pair, s.t[1], 1);
1603
} else if (!g_ascii_strcasecmp(s.t[0], "FlatButton")) {
1891
else if (g_ascii_strcasecmp(s.t[0], "FlatButton") == 0)
1604
1892
tb->flat_button = str2num(bool_pair, s.t[1], 1);
1893
else if (g_ascii_strcasecmp(s.t[0], "GroupedTasks") == 0)
1894
tb->grouped_tasks = str2num(bool_pair, s.t[1], 1);
1606
1896
ERR( "taskbar: unknown var %s\n", s.t[0]);
1610
1900
ERR( "taskbar: illegal in this context %s\n", s.str);
1906
/* Build the graphic elements. */
1615
1907
taskbar_build_gui(p);
1616
tb_net_client_list(NULL, tb);
1618
tb_net_active_window(NULL, tb);
1622
taskbar_destructor(p);
1909
/* Fetch the client list and redraw the taskbar. Then determine what window has focus. */
1910
taskbar_net_client_list(NULL, tb);
1911
taskbar_net_active_window(NULL, tb);
1628
taskbar_destructor(Plugin *p)
1915
/* Plugin destructor. */
1916
static void taskbar_destructor(Plugin * p)
1630
taskbar *tb = (taskbar *)p->priv;
1631
g_hash_table_foreach( tb->task_list, (GHFunc)del_task, NULL );
1633
g_signal_handlers_disconnect_by_func(G_OBJECT (fbev), tb_net_current_desktop, tb);
1634
g_signal_handlers_disconnect_by_func(G_OBJECT (fbev), tb_net_active_window, tb);
1635
g_signal_handlers_disconnect_by_func(G_OBJECT (fbev), tb_net_number_of_desktops, tb);
1636
g_signal_handlers_disconnect_by_func(G_OBJECT (fbev), tb_net_client_list, tb);
1637
gdk_window_remove_filter(NULL, (GdkFilterFunc)tb_event_filter, tb );
1638
g_hash_table_destroy(tb->task_list);
1639
/* The widget is destroyed in plugin_stop().
1640
gtk_widget_destroy(tb->bar);
1918
TaskbarPlugin * tb = (TaskbarPlugin *) p->priv;
1920
/* Remove GDK event filter. */
1921
gdk_window_remove_filter(NULL, (GdkFilterFunc) taskbar_event_filter, tb);
1923
/* Remove root window signal handlers. */
1924
g_signal_handlers_disconnect_by_func(fbev, taskbar_net_current_desktop, tb);
1925
g_signal_handlers_disconnect_by_func(fbev, taskbar_net_active_window, tb);
1926
g_signal_handlers_disconnect_by_func(fbev, taskbar_net_number_of_desktops, tb);
1927
g_signal_handlers_disconnect_by_func(fbev, taskbar_net_client_list, tb);
1929
/* Deallocate task list. */
1930
while (tb->task_list != NULL)
1931
task_delete(tb, tb->task_list, TRUE);
1933
/* Deallocate class list. */
1934
while (tb->res_class_list != NULL)
1936
TaskClass * tc = tb->res_class_list;
1937
tb->res_class_list = tc->res_class_flink;
1938
g_free(tc->res_class);
1942
/* Deallocate other memory. */
1642
1943
gtk_widget_destroy(tb->menu);
1646
update_task_button( gpointer key, task* tk, taskbar* tb )
1648
if( tb->icons_only )
1649
gtk_widget_hide( tk->label );
1651
gtk_widget_show( tk->label );
1653
if( tb->flat_button )
1654
gtk_button_set_relief( (GtkButton*)tk->button, GTK_RELIEF_NONE );
1656
gtk_button_set_relief( (GtkButton*)tk->button, GTK_RELIEF_NORMAL);
1659
static void apply_config( Plugin* p )
1661
taskbar *tb = (taskbar *)p->priv;
1663
gtk_container_foreach( GTK_CONTAINER(tb->bar), (GtkCallback)gtk_widget_set_has_tooltip, (gpointer)TRUE );
1665
gtk_container_foreach( GTK_CONTAINER(tb->bar), (GtkCallback)gtk_widget_set_has_tooltip, (gpointer)FALSE );
1947
/* Callback from configuration dialog mechanism to apply the configuration. */
1948
static void taskbar_apply_configuration(Plugin * p)
1950
TaskbarPlugin * tb = (TaskbarPlugin *) p->priv;
1952
/* Update style on taskbar. */
1953
taskbar_update_style(tb);
1955
/* Update styles on each button. */
1957
for (tk = tb->task_list; tk != NULL; tk = tk->task_flink)
1958
task_update_style(tk, tb);
1960
/* Refetch the client list and redraw. */
1961
recompute_group_visibility_on_current_desktop(tb);
1962
taskbar_net_client_list(NULL, tb);
1965
/* Display the configuration dialog. */
1966
static void taskbar_configure(Plugin * p, GtkWindow * parent)
1968
TaskbarPlugin * tb = (TaskbarPlugin *) p->priv;
1969
GtkWidget* dlg = create_generic_config_dlg(
1972
(GSourceFunc) taskbar_apply_configuration, (gpointer) p,
1973
_("Show tooltips"), &tb->tooltips, CONF_TYPE_BOOL,
1974
_("Icons only"), &tb->icons_only, CONF_TYPE_BOOL,
1975
_("Flat buttons"), &tb->flat_button, CONF_TYPE_BOOL,
1976
_("Show windows from all desktops"), &tb->show_all_desks, CONF_TYPE_BOOL,
1977
_("Use mouse wheel"), &tb->use_mouse_wheel, CONF_TYPE_BOOL,
1978
_("Flash when there is any window requiring attention"), &tb->use_urgency_hint, CONF_TYPE_BOOL,
1979
_("Combine multiple application windows into a single button"), &tb->grouped_tasks, CONF_TYPE_BOOL,
1980
_("Maximum width of task button"), &tb->task_width_max, CONF_TYPE_INT,
1981
_("Spacing"), &tb->spacing, CONF_TYPE_INT,
1983
gtk_window_present(GTK_WINDOW(dlg));
1986
/* Save the configuration to the configuration file. */
1987
static void taskbar_save_configuration(Plugin * p, FILE * fp)
1989
TaskbarPlugin * tb = (TaskbarPlugin *) p->priv;
1990
lxpanel_put_bool(fp, "tooltips", tb->tooltips);
1991
lxpanel_put_bool(fp, "IconsOnly", tb->icons_only);
1992
lxpanel_put_bool(fp, "ShowAllDesks", tb->show_all_desks);
1993
lxpanel_put_bool(fp, "UseMouseWheel", tb->use_mouse_wheel);
1994
lxpanel_put_bool(fp, "UseUrgencyHint", tb->use_urgency_hint);
1995
lxpanel_put_bool(fp, "FlatButton", tb->flat_button);
1996
lxpanel_put_int(fp, "MaxTaskWidth", tb->task_width_max);
1997
lxpanel_put_int(fp, "spacing", tb->spacing);
1998
lxpanel_put_bool(fp, "GroupedTasks", tb->grouped_tasks);
2001
/* Callback when panel configuration changes. */
2002
static void taskbar_panel_configuration_changed(Plugin * p)
2004
TaskbarPlugin * tb = (TaskbarPlugin *) p->priv;
2005
taskbar_update_style(tb);
2006
taskbar_make_menu(tb);
2007
GtkOrientation bo = (tb->plug->panel->orientation == ORIENT_HORIZ) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
2008
icon_grid_set_geometry(tb->icon_grid, bo,
2009
((tb->icons_only) ? tb->plug->panel->icon_size + ICON_ONLY_EXTRA : tb->task_width_max), tb->plug->panel->icon_size + BUTTON_HEIGHT_EXTRA,
2010
tb->spacing, 0, tb->plug->panel->height);
2012
/* If the icon size changed, refetch all the icons. */
2013
if (tb->plug->panel->icon_size != tb->icon_size)
1669
gtk_bar_set_max_child_size(GTK_BAR(tb->bar),
1670
GTK_WIDGET(p->panel->box)->allocation.height -2);
1673
gtk_bar_set_max_child_size(GTK_BAR(tb->bar), tb->task_width_max);
1675
gtk_box_set_spacing( GTK_BOX(tb->bar), tb->spacing );
1676
tb_net_client_list(NULL, tb);
1677
g_hash_table_foreach( tb->task_list,
1678
(GHFunc)update_task_button,
1682
static void taskbar_config( Plugin* p, GtkWindow* parent )
1685
taskbar *tb = (taskbar *)p->priv;
1687
dlg = create_generic_config_dlg(
1690
(GSourceFunc) apply_config, (gpointer) p,
1691
_("Show tooltips"), &tb->tooltips, CONF_TYPE_BOOL,
1692
_("Icons only"), &tb->icons_only, CONF_TYPE_BOOL,
1693
_("Flat Buttons"), &tb->flat_button, CONF_TYPE_BOOL,
1694
_("Accept SkipPager"), &tb->accept_skip_pager, CONF_TYPE_BOOL,
1695
_("Show Iconified windows"), &tb->show_iconified, CONF_TYPE_BOOL,
1696
_("Show mapped windows"), &tb->show_mapped, CONF_TYPE_BOOL,
1697
_("Show windows from all desktops"), &tb->show_all_desks, CONF_TYPE_BOOL,
1698
_("Use mouse wheel"), &tb->use_mouse_wheel, CONF_TYPE_BOOL,
1699
_("Flash when there is any window requiring attention"), &tb->use_urgency_hint, CONF_TYPE_BOOL,
1700
_("Max width of task button"), &tb->task_width_max, CONF_TYPE_INT,
1701
_("Spacing"), &tb->spacing, CONF_TYPE_INT,
1703
gtk_window_present( GTK_WINDOW(dlg) );
1706
static void save_config( Plugin* p, FILE* fp )
1708
taskbar *tb = (taskbar *)p->priv;
1709
lxpanel_put_bool( fp, "tooltips", tb->tooltips );
1710
lxpanel_put_bool( fp, "IconsOnly", tb->icons_only );
1711
lxpanel_put_bool( fp, "AcceptSkipPager", tb->accept_skip_pager );
1712
lxpanel_put_bool( fp, "ShowIconified", tb->show_iconified );
1713
lxpanel_put_bool( fp, "ShowMapped", tb->show_mapped );
1714
lxpanel_put_bool( fp, "ShowAllDesks", tb->show_all_desks );
1715
lxpanel_put_bool( fp, "UseMouseWheel", tb->use_mouse_wheel );
1716
lxpanel_put_bool( fp, "UseUrgencyHint", tb->use_urgency_hint );
1717
lxpanel_put_bool( fp, "FlatButton", tb->flat_button );
1718
lxpanel_put_int( fp, "MaxTaskWidth", tb->task_width_max );
1719
lxpanel_put_int( fp, "spacing", tb->spacing );
1723
update_label_orient( GtkWidget* child, gpointer user_data )
1725
/* FIXME: gtk+ has only limited support for this, sigh! */
1726
Plugin* p = (Plugin*)user_data;
1727
if( GTK_IS_LABEL(child) ) {
1729
if( p->panel->edge == EDGE_LEFT ) {
1731
/* FIXME: ellipsize cannot be used in conjunction with angle.
1732
This is the limit of gtk+, and turn off ellipsize do
1733
cause problems here. How can this be solved? Sigh!
1735
gtk_label_set_ellipsize( GTK_LABEL(child), PANGO_ELLIPSIZE_NONE );
1737
else if( p->panel->edge == EDGE_RIGHT ) {
1739
gtk_label_set_ellipsize( GTK_LABEL(child), PANGO_ELLIPSIZE_NONE );
1743
gtk_label_set_ellipsize( GTK_LABEL(child), PANGO_ELLIPSIZE_END );
1745
gtk_label_set_angle( GTK_LABEL(child), angle );
1746
gtk_misc_set_alignment(GTK_MISC(child), 0.0, 0.5);
1750
static void orientation_changed( Plugin* p )
1752
taskbar *tb = (taskbar *)p->priv;
1753
GList *child, *children;
1755
children = gtk_container_get_children( GTK_CONTAINER (tb->bar) );
1756
for( child = children; child; child = child->next ) {
1757
GtkWidget *button = GTK_WIDGET(child->data);
1758
GtkBox *box = (GtkBox*)gtk_bin_get_child( GTK_BIN(button) );
1759
GtkBox *newbox = GTK_BOX(recreate_box( box, p->panel->orientation ));
1760
if( newbox != box ) {
1761
gtk_container_add( GTK_CONTAINER(button), GTK_WIDGET(newbox) );
1763
gtk_container_foreach( GTK_CONTAINER(newbox),
1764
update_label_orient, p );
1766
g_list_free( children );
1768
gtk_widget_destroy( tb->menu );
1769
tb->menu = taskbar_make_menu( tb );
1771
gtk_bar_set_orientation( GTK_BAR(tb->bar), p->panel->orientation );
2015
tb->icon_size = tb->plug->panel->icon_size;
2017
for (tk = tb->task_list; tk != NULL; tk = tk->task_flink)
2019
GdkPixbuf * pixbuf = task_update_icon(tb, tk, None);
2022
gtk_image_set_from_pixbuf(GTK_IMAGE(tk->image), pixbuf);
2023
g_object_unref(pixbuf);
2028
/* Redraw all the labels. Icon size or font color may have changed. */
2032
/* Plugin descriptor. */
1774
2033
PluginClass taskbar_plugin_class = {
2035
PLUGINCLASS_VERSIONING,
1778
2037
type : "taskbar",
1779
2038
name : N_("Task Bar (Window List)"),
1780
2039
version: "1.0",
1781
2040
description : N_("Taskbar shows all opened windows and allow to iconify them, shade or get focus"),
2042
/* Stretch is available and default for this plugin. */
2043
expand_available : TRUE,
2044
expand_default : TRUE,
1783
2046
constructor : taskbar_constructor,
1784
2047
destructor : taskbar_destructor,
1785
config : taskbar_config,
1787
orientation : orientation_changed
2048
config : taskbar_configure,
2049
save : taskbar_save_configuration,
2050
panel_configuration_changed : taskbar_panel_configuration_changed