Bug Summary

File:_build/../libvnck/tasklist.c
Warning:line 2311, column 7
Although the value stored to 'windows' is used in the enclosing expression, the value is never actually read from 'windows'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name tasklist.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/_build -fcoverage-compilation-dir=/rootdir/_build -resource-dir /usr/lib/llvm-19/lib/clang/19 -I libvnck/libvnck-3.so.0.3.0.p -I libvnck -I ../libvnck -I . -I .. -I /usr/include/cairo -I /usr/include/libpng16 -I /usr/include/freetype2 -I /usr/include/pixman-1 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/harfbuzz -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/startup-notification-1.0 -D _FILE_OFFSET_BITS=64 -D G_LOG_DOMAIN="Vnck" -D VNCK_I_KNOW_THIS_IS_UNSTABLE -D VNCK_LOCALEDIR="/usr/local/share/locale" -D VNCK_COMPILATION -D SN_API_NOT_YET_FROZEN=1 -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2025-07-25-114028-9305-1 -x c ../libvnck/tasklist.c
1/* tasklist object */
2
3/*
4 * Copyright (C) 2001 Havoc Pennington
5 * Copyright (C) 2003 Kim Woelders
6 * Copyright (C) 2003 Red Hat, Inc.
7 * Copyright (C) 2003, 2005-2007 Vincent Untz
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21*/
22
23#include <config.h>
24
25#include <math.h>
26#include <string.h>
27#include <stdio.h>
28#include <glib/gi18n-lib.h>
29#include "tasklist.h"
30#include "window.h"
31#include "class-group.h"
32#include "window-action-menu.h"
33#include "vnck-image-menu-item-private.h"
34#include "workspace.h"
35#include "xutils.h"
36#include "private.h"
37
38/**
39 * SECTION:tasklist
40 * @short_description: a tasklist widget, showing the list of windows as a list
41 * of buttons.
42 * @see_also: #VnckScreen, #VnckSelector
43 * @stability: Unstable
44 *
45 * The #VnckTasklist represents client windows on a screen as a list of buttons
46 * labelled with the window titles and icons. Pressing a button can activate or
47 * minimize the represented window, and other typical actions are available
48 * through a popup menu. Windows needing attention can also be distinguished
49 * by a fade effect on the buttons representing them, to help attract the
50 * user's attention.
51 *
52 * The behavior of the #VnckTasklist can be customized in various ways, like
53 * grouping multiple windows of the same application in one button (see
54 * vnck_tasklist_set_grouping() and vnck_tasklist_set_grouping_limit()), or
55 * showing windows from all workspaces (see
56 * vnck_tasklist_set_include_all_workspaces()). The fade effect for windows
57 * needing attention can be controlled by various style properties like
58 * #VnckTasklist:fade-max-loops and #VnckTasklist:fade-opacity.
59 *
60 * The tasklist also acts as iconification destination. If there are multiple
61 * #VnckTasklist or other applications setting the iconification destination
62 * for windows, the iconification destinations might not be consistent among
63 * windows and it is not possible to determine which #VnckTasklist (or which
64 * other application) owns this propriety.
65 */
66
67/* TODO:
68 *
69 * Add total focused time to the grouping score function
70 * Fine tune the grouping scoring function
71 * Fix "changes" to icon for groups/applications
72 * Maybe fine tune size_allocate() some more...
73 * Better vertical layout handling
74 * prefs
75 * support for right-click menu merging w/ bonobo for the applet
76 *
77 */
78
79
80#define VNCK_TYPE_TASK(vnck_task_get_type ()) (vnck_task_get_type ())
81#define VNCK_TASK(object)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((vnck_task_get_type ()))))))
(G_TYPE_CHECK_INSTANCE_CAST ((object), VNCK_TYPE_TASK, VnckTask)(((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((vnck_task_get_type ())))))
)
82#define VNCK_TASK_CLASS(klass)((((VnckTaskClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), ((vnck_task_get_type ()))))))
(G_TYPE_CHECK_CLASS_CAST ((klass), VNCK_TYPE_TASK, VnckTaskClass)(((VnckTaskClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), ((vnck_task_get_type ())))))
)
83#define VNCK_IS_TASK(object)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(object)); GType __t = ((vnck_task_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
(G_TYPE_CHECK_INSTANCE_TYPE ((object), VNCK_TYPE_TASK)((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(object)); GType __t = ((vnck_task_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))
)
84#define VNCK_IS_TASK_CLASS(klass)(((__extension__ ({ GTypeClass *__class = (GTypeClass*) ((klass
)); GType __t = ((vnck_task_get_type ())); gboolean __r; if (
!__class) __r = (0); else if (__class->g_type == __t) __r =
(!(0)); else __r = g_type_check_class_is_a (__class, __t); __r
; }))))
(G_TYPE_CHECK_CLASS_TYPE ((klass), VNCK_TYPE_TASK)((__extension__ ({ GTypeClass *__class = (GTypeClass*) ((klass
)); GType __t = ((vnck_task_get_type ())); gboolean __r; if (
!__class) __r = (0); else if (__class->g_type == __t) __r =
(!(0)); else __r = g_type_check_class_is_a (__class, __t); __r
; })))
)
85#define VNCK_TASK_GET_CLASS(obj)((((VnckTaskClass*) (((GTypeInstance*) ((obj)))->g_class))
))
(G_TYPE_INSTANCE_GET_CLASS ((obj), VNCK_TYPE_TASK, VnckTaskClass)(((VnckTaskClass*) (((GTypeInstance*) ((obj)))->g_class))))
86
87typedef struct _VnckTask VnckTask;
88typedef struct _VnckTaskClass VnckTaskClass;
89
90#define DEFAULT_GROUPING_LIMIT80 80
91
92#define MINI_ICON_SIZE_vnck_get_default_mini_icon_size () _vnck_get_default_mini_icon_size ()
93#define TASKLIST_BUTTON_PADDING4 4
94#define TASKLIST_TEXT_MAX_WIDTH25 25 /* maximum width in characters */
95
96#define N_SCREEN_CONNECTIONS5 5
97
98#define POINT_IN_RECT(xcoord, ycoord, rect)((xcoord) >= (rect).x && (xcoord) < ((rect).x +
(rect).width) && (ycoord) >= (rect).y && (
ycoord) < ((rect).y + (rect).height))
\
99 ((xcoord) >= (rect).x && \
100 (xcoord) < ((rect).x + (rect).width) && \
101 (ycoord) >= (rect).y && \
102 (ycoord) < ((rect).y + (rect).height))
103
104typedef enum
105{
106 VNCK_TASK_CLASS_GROUP,
107 VNCK_TASK_WINDOW,
108 VNCK_TASK_STARTUP_SEQUENCE
109} VnckTaskType;
110
111struct _VnckTask
112{
113 GObject parent_instance;
114
115 VnckTasklist *tasklist;
116
117 CtkWidget *button;
118 CtkWidget *image;
119 CtkWidget *label;
120
121 VnckTaskType type;
122
123 VnckClassGroup *class_group;
124 VnckWindow *window;
125#ifdef HAVE_STARTUP_NOTIFICATION1
126 SnStartupSequence *startup_sequence;
127#endif
128
129 gdouble grouping_score;
130
131 GList *windows; /* List of the VnckTask for the window,
132 if this is a class group */
133 guint state_changed_tag;
134 guint icon_changed_tag;
135 guint name_changed_tag;
136 guint class_name_changed_tag;
137 guint class_icon_changed_tag;
138
139 /* task menu */
140 CtkWidget *menu;
141 /* ops menu */
142 CtkWidget *action_menu;
143
144 guint really_toggling : 1; /* Set when tasklist really wants
145 * to change the togglebutton state
146 */
147 guint was_active : 1; /* used to fixup activation behavior */
148
149 guint button_activate;
150
151 guint32 dnd_timestamp;
152
153 time_t start_needs_attention;
154 gdouble glow_start_time;
155 gdouble glow_factor;
156
157 guint button_glow;
158
159 gint row;
160 gint col;
161
162 guint resize_idle_id;
163};
164
165struct _VnckTaskClass
166{
167 GObjectClass parent_class;
168};
169
170typedef struct _skipped_window
171{
172 VnckWindow *window;
173 gulong tag;
174} skipped_window;
175
176struct _VnckTasklistPrivate
177{
178 VnckScreen *screen;
179
180 VnckTask *active_task; /* NULL if active window not in tasklist */
181 VnckTask *active_class_group; /* NULL if active window not in tasklist */
182
183 gboolean include_all_workspaces;
184
185 /* Calculated by update_lists */
186 GList *class_groups;
187 GList *windows;
188 GList *windows_without_class_group;
189
190 /* Not handled by update_lists */
191 GList *startup_sequences;
192
193 /* windows with _NET_WM_STATE_SKIP_TASKBAR set; connected to
194 * "state_changed" signal, but excluded from tasklist.
195 */
196 GList *skipped_windows;
197
198 GHashTable *class_group_hash;
199 GHashTable *win_hash;
200
201 gint max_button_width;
202 gint max_button_height;
203
204 gboolean switch_workspace_on_unminimize;
205 gboolean middle_click_close;
206
207 VnckTasklistGroupingType grouping;
208 gint grouping_limit;
209
210 guint activate_timeout_id;
211 guint screen_connections [N_SCREEN_CONNECTIONS5];
212
213 guint idle_callback_tag;
214
215 int *size_hints;
216 int size_hints_len;
217
218 VnckLoadIconFunction icon_loader;
219 void *icon_loader_data;
220 GDestroyNotify free_icon_loader_data;
221
222#ifdef HAVE_STARTUP_NOTIFICATION1
223 SnMonitorContext *sn_context;
224 guint startup_sequence_timeout;
225#endif
226
227 CdkMonitor *monitor;
228 CdkRectangle monitor_geometry;
229 CtkReliefStyle relief;
230 CtkOrientation orientation;
231
232 guint drag_start_time;
233
234 gboolean scroll_enabled;
235};
236
237static GType vnck_task_get_type (void);
238
239G_DEFINE_TYPE (VnckTask, vnck_task, G_TYPE_OBJECT)static void vnck_task_init (VnckTask *self); static void vnck_task_class_init
(VnckTaskClass *klass); static GType vnck_task_get_type_once
(void); static gpointer vnck_task_parent_class = ((void*)0);
static gint VnckTask_private_offset; static void vnck_task_class_intern_init
(gpointer klass) { vnck_task_parent_class = g_type_class_peek_parent
(klass); if (VnckTask_private_offset != 0) g_type_class_adjust_private_offset
(klass, &VnckTask_private_offset); vnck_task_class_init (
(VnckTaskClass*) klass); } __attribute__ ((__unused__)) static
inline gpointer vnck_task_get_instance_private (VnckTask *self
) { return (((gpointer) ((guint8*) (self) + (glong) (VnckTask_private_offset
)))); } GType vnck_task_get_type (void) { static GType static_g_define_type_id
= 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) * (&static_g_define_type_id) : ((void*)
0)); (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter_pointer (
&static_g_define_type_id)); })) ) { GType g_define_type_id
= vnck_task_get_type_once (); (__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id
) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer
((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id
)); })) ; } return static_g_define_type_id; } __attribute__ (
(__noinline__)) static GType vnck_task_get_type_once (void) {
GType g_define_type_id = g_type_register_static_simple (((GType
) ((20) << (2))), g_intern_static_string ("VnckTask"), sizeof
(VnckTaskClass), (GClassInitFunc)(void (*)(void)) vnck_task_class_intern_init
, sizeof (VnckTask), (GInstanceInitFunc)(void (*)(void)) vnck_task_init
, (GTypeFlags) 0); { {{};} } return g_define_type_id; }
;
240G_DEFINE_TYPE_WITH_PRIVATE (VnckTasklist, vnck_tasklist, CTK_TYPE_CONTAINER)static void vnck_tasklist_init (VnckTasklist *self); static void
vnck_tasklist_class_init (VnckTasklistClass *klass); static GType
vnck_tasklist_get_type_once (void); static gpointer vnck_tasklist_parent_class
= ((void*)0); static gint VnckTasklist_private_offset; static
void vnck_tasklist_class_intern_init (gpointer klass) { vnck_tasklist_parent_class
= g_type_class_peek_parent (klass); if (VnckTasklist_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &VnckTasklist_private_offset
); vnck_tasklist_class_init ((VnckTasklistClass*) klass); } __attribute__
((__unused__)) static inline gpointer vnck_tasklist_get_instance_private
(VnckTasklist *self) { return (((gpointer) ((guint8*) (self)
+ (glong) (VnckTasklist_private_offset)))); } GType vnck_tasklist_get_type
(void) { static GType static_g_define_type_id = 0; if ((__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); (void) (
0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0))
; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter_pointer (
&static_g_define_type_id)); })) ) { GType g_define_type_id
= vnck_tasklist_get_type_once (); (__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id
) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer
((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id
)); })) ; } return static_g_define_type_id; } __attribute__ (
(__noinline__)) static GType vnck_tasklist_get_type_once (void
) { GType g_define_type_id = g_type_register_static_simple ((
ctk_container_get_type ()), g_intern_static_string ("VnckTasklist"
), sizeof (VnckTasklistClass), (GClassInitFunc)(void (*)(void
)) vnck_tasklist_class_intern_init, sizeof (VnckTasklist), (GInstanceInitFunc
)(void (*)(void)) vnck_tasklist_init, (GTypeFlags) 0); { {{ VnckTasklist_private_offset
= g_type_add_instance_private (g_define_type_id, sizeof (VnckTasklistPrivate
)); };} } return g_define_type_id; }
;
241
242enum
243{
244 TASK_ENTER_NOTIFY,
245 TASK_LEAVE_NOTIFY,
246 LAST_SIGNAL
247};
248
249static void vnck_task_finalize (GObject *object);
250
251static void vnck_task_stop_glow (VnckTask *task);
252
253static VnckTask *vnck_task_new_from_window (VnckTasklist *tasklist,
254 VnckWindow *window);
255static VnckTask *vnck_task_new_from_class_group (VnckTasklist *tasklist,
256 VnckClassGroup *class_group);
257#ifdef HAVE_STARTUP_NOTIFICATION1
258static VnckTask *vnck_task_new_from_startup_sequence (VnckTasklist *tasklist,
259 SnStartupSequence *sequence);
260#endif
261static gboolean vnck_task_get_needs_attention (VnckTask *task);
262
263
264static char *vnck_task_get_text (VnckTask *task,
265 gboolean icon_text,
266 gboolean include_state);
267static GdkPixbuf *vnck_task_get_icon (VnckTask *task);
268static gint vnck_task_compare_alphabetically (gconstpointer a,
269 gconstpointer b);
270static gint vnck_task_compare (gconstpointer a,
271 gconstpointer b);
272static void vnck_task_update_visible_state (VnckTask *task);
273static void vnck_task_state_changed (VnckWindow *window,
274 VnckWindowState changed_mask,
275 VnckWindowState new_state,
276 gpointer data);
277
278static void vnck_task_drag_begin (CtkWidget *widget,
279 CdkDragContext *context,
280 VnckTask *task);
281static void vnck_task_drag_end (CtkWidget *widget,
282 CdkDragContext *context,
283 VnckTask *task);
284static void vnck_task_drag_data_get (CtkWidget *widget,
285 CdkDragContext *context,
286 CtkSelectionData *selection_data,
287 guint info,
288 guint time,
289 VnckTask *task);
290
291static void vnck_tasklist_finalize (GObject *object);
292
293static void vnck_tasklist_get_preferred_width (CtkWidget *widget,
294 int *minimum_width,
295 int *natural_width);
296static void vnck_tasklist_get_preferred_height (CtkWidget *widget,
297 int *minimum_height,
298 int *natural_height);
299static void vnck_tasklist_size_allocate (CtkWidget *widget,
300 CtkAllocation *allocation);
301static void vnck_tasklist_realize (CtkWidget *widget);
302static void vnck_tasklist_unrealize (CtkWidget *widget);
303static gboolean vnck_tasklist_scroll_event (CtkWidget *widget,
304 CdkEventScroll *event);
305static void vnck_tasklist_forall (CtkContainer *container,
306 gboolean include_internals,
307 CtkCallback callback,
308 gpointer callback_data);
309static void vnck_tasklist_remove (CtkContainer *container,
310 CtkWidget *widget);
311static void vnck_tasklist_free_tasks (VnckTasklist *tasklist);
312static void vnck_tasklist_update_lists (VnckTasklist *tasklist);
313static int vnck_tasklist_layout (CtkAllocation *allocation,
314 int max_width,
315 int max_height,
316 int n_buttons,
317 CtkOrientation orientation,
318 int *n_cols_out,
319 int *n_rows_out);
320
321static void vnck_tasklist_active_window_changed (VnckScreen *screen,
322 VnckWindow *previous_window,
323 VnckTasklist *tasklist);
324static void vnck_tasklist_active_workspace_changed (VnckScreen *screen,
325 VnckWorkspace *previous_workspace,
326 VnckTasklist *tasklist);
327static void vnck_tasklist_window_added (VnckScreen *screen,
328 VnckWindow *win,
329 VnckTasklist *tasklist);
330static void vnck_tasklist_window_removed (VnckScreen *screen,
331 VnckWindow *win,
332 VnckTasklist *tasklist);
333static void vnck_tasklist_viewports_changed (VnckScreen *screen,
334 VnckTasklist *tasklist);
335static void vnck_tasklist_connect_window (VnckTasklist *tasklist,
336 VnckWindow *window);
337static void vnck_tasklist_disconnect_window (VnckTasklist *tasklist,
338 VnckWindow *window);
339
340static void vnck_tasklist_change_active_task (VnckTasklist *tasklist,
341 VnckTask *active_task);
342static gboolean vnck_tasklist_change_active_timeout (gpointer data);
343static void vnck_tasklist_activate_task_window (VnckTask *task,
344 guint32 timestamp);
345
346static void vnck_tasklist_update_icon_geometries (VnckTasklist *tasklist,
347 GList *visible_tasks);
348static void vnck_tasklist_connect_screen (VnckTasklist *tasklist);
349static void vnck_tasklist_disconnect_screen (VnckTasklist *tasklist);
350
351#ifdef HAVE_STARTUP_NOTIFICATION1
352static void vnck_tasklist_sn_event (SnMonitorEvent *event,
353 void *user_data);
354static void vnck_tasklist_check_end_sequence (VnckTasklist *tasklist,
355 VnckWindow *window);
356#endif
357
358/*
359 * Keep track of all tasklist instances so we can decide
360 * whether to show windows from all monitors in the
361 * tasklist
362 */
363static GSList *tasklist_instances;
364
365static void
366vnck_task_init (VnckTask *task)
367{
368 task->type = VNCK_TASK_WINDOW;
369 task->resize_idle_id = 0;
370}
371
372static void
373vnck_task_class_init (VnckTaskClass *klass)
374{
375 GObjectClass *object_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), (((GType) ((20) << (2))))))))
;
376
377 object_class->finalize = vnck_task_finalize;
378}
379
380static gboolean
381vnck_task_button_glow (VnckTask *task)
382{
383 gdouble now;
384 gfloat fade_opacity, loop_time;
385 gint fade_max_loops;
386 gboolean stopped;
387
388 now = g_get_real_time () / G_USEC_PER_SEC1000000;
389
390 if (task->glow_start_time <= G_MINDOUBLE2.2250738585072014e-308)
391 task->glow_start_time = now;
392
393 ctk_widget_style_get (CTK_WIDGET (task->tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->tasklist)), ((ctk_widget_get_type ()))))))
, "fade-opacity", &fade_opacity,
394 "fade-loop-time", &loop_time,
395 "fade-max-loops", &fade_max_loops,
396 NULL((void*)0));
397
398 if (task->button_glow == 0)
399 {
400 /* we're in "has stopped glowing" mode */
401 task->glow_factor = (gdouble) fade_opacity * 0.5;
402 stopped = TRUE(!(0));
403 }
404 else
405 {
406 task->glow_factor =
407 (gdouble) fade_opacity * (0.5 -
408 0.5 * cos ((now - task->glow_start_time) *
409 M_PI3.14159265358979323846 * 2.0 / (gdouble) loop_time));
410
411 if (now - task->start_needs_attention > (gdouble) loop_time * 1.0 * fade_max_loops)
412 stopped = ABS (task->glow_factor - (gdouble) fade_opacity * 0.5)(((task->glow_factor - (gdouble) fade_opacity * 0.5) < 0
) ? -(task->glow_factor - (gdouble) fade_opacity * 0.5) : (
task->glow_factor - (gdouble) fade_opacity * 0.5))
< 0.05;
413 else
414 stopped = FALSE(0);
415 }
416
417 ctk_widget_queue_draw (task->button);
418
419 if (stopped)
420 vnck_task_stop_glow (task);
421
422 return !stopped;
423}
424
425static void
426vnck_task_clear_glow_start_timeout_id (VnckTask *task)
427{
428 task->button_glow = 0;
429}
430
431static void
432vnck_task_queue_glow (VnckTask *task)
433{
434 if (task->button_glow == 0)
435 {
436 task->glow_start_time = 0.0;
437
438 /* The animation doesn't speed up or slow down based on the
439 * timeout value, but instead will just appear smoother or
440 * choppier.
441 */
442 task->button_glow =
443 g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE200,
444 50,
445 (GSourceFunc) vnck_task_button_glow, task,
446 (GDestroyNotify) vnck_task_clear_glow_start_timeout_id);
447 }
448}
449
450static void
451vnck_task_stop_glow (VnckTask *task)
452{
453 /* We stop glowing, but we might still have the task colored,
454 * so we don't reset the glow factor */
455 if (task->button_glow != 0)
456 g_source_remove (task->button_glow);
457}
458
459static void
460vnck_task_reset_glow (VnckTask *task)
461{
462 vnck_task_stop_glow (task);
463 task->glow_factor = 0.0;
464}
465
466static void
467vnck_task_finalize (GObject *object)
468{
469 VnckTask *task;
470
471 task = VNCK_TASK (object)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((vnck_task_get_type ()))))))
;
472
473 if (task->tasklist->priv->active_task == task)
474 vnck_tasklist_change_active_task (task->tasklist, NULL((void*)0));
475
476 if (task->button)
477 {
478 g_object_remove_weak_pointer (G_OBJECT (task->button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), (((GType) ((20) << (2))))))))
,
479 (void**) &task->button);
480 ctk_widget_destroy (task->button);
481 task->button = NULL((void*)0);
482 task->image = NULL((void*)0);
483 task->label = NULL((void*)0);
484 }
485
486#ifdef HAVE_STARTUP_NOTIFICATION1
487 if (task->startup_sequence)
488 {
489 sn_startup_sequence_unref (task->startup_sequence);
490 task->startup_sequence = NULL((void*)0);
491 }
492#endif
493
494 g_list_free (task->windows);
495 task->windows = NULL((void*)0);
496
497 if (task->state_changed_tag != 0)
498 {
499 g_signal_handler_disconnect (task->window,
500 task->state_changed_tag);
501 task->state_changed_tag = 0;
502 }
503
504 if (task->icon_changed_tag != 0)
505 {
506 g_signal_handler_disconnect (task->window,
507 task->icon_changed_tag);
508 task->icon_changed_tag = 0;
509 }
510
511 if (task->name_changed_tag != 0)
512 {
513 g_signal_handler_disconnect (task->window,
514 task->name_changed_tag);
515 task->name_changed_tag = 0;
516 }
517
518 if (task->class_name_changed_tag != 0)
519 {
520 g_signal_handler_disconnect (task->class_group,
521 task->class_name_changed_tag);
522 task->class_name_changed_tag = 0;
523 }
524
525 if (task->class_icon_changed_tag != 0)
526 {
527 g_signal_handler_disconnect (task->class_group,
528 task->class_icon_changed_tag);
529 task->class_icon_changed_tag = 0;
530 }
531
532 if (task->class_group)
533 {
534 g_object_unref (task->class_group);
535 task->class_group = NULL((void*)0);
536 }
537
538 if (task->window)
539 {
540 g_object_unref (task->window);
541 task->window = NULL((void*)0);
542 }
543
544 if (task->menu)
545 {
546 ctk_widget_destroy (task->menu);
547 task->menu = NULL((void*)0);
548 }
549
550 if (task->action_menu)
551 {
552 g_object_remove_weak_pointer (G_OBJECT (task->action_menu)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->action_menu)), (((GType) ((20) << (2)))))
)))
,
553 (void**) &task->action_menu);
554 ctk_widget_destroy (task->action_menu);
555 task->action_menu = NULL((void*)0);
556 }
557
558 if (task->button_activate != 0)
559 {
560 g_source_remove (task->button_activate);
561 task->button_activate = 0;
562 }
563
564 vnck_task_stop_glow (task);
565
566 if (task->resize_idle_id > 0)
567 {
568 g_source_remove (task->resize_idle_id);
569 task->resize_idle_id = 0;
570 }
571
572 G_OBJECT_CLASS (vnck_task_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((vnck_task_parent_class)), (((GType) ((20) << (2)))
)))))
->finalize (object);
573}
574
575static guint signals[LAST_SIGNAL] = { 0 };
576
577static void
578vnck_tasklist_init (VnckTasklist *tasklist)
579{
580 CtkWidget *widget;
581 AtkObject *atk_obj;
582
583 widget = CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
;
584
585 ctk_widget_set_has_window (widget, FALSE(0));
586
587 tasklist->priv = vnck_tasklist_get_instance_private (tasklist);
588
589 tasklist->priv->class_group_hash = g_hash_table_new (NULL((void*)0), NULL((void*)0));
590 tasklist->priv->win_hash = g_hash_table_new (NULL((void*)0), NULL((void*)0));
591
592 tasklist->priv->grouping = VNCK_TASKLIST_AUTO_GROUP;
593 tasklist->priv->grouping_limit = DEFAULT_GROUPING_LIMIT80;
594
595 tasklist->priv->monitor = NULL((void*)0);
596 tasklist->priv->monitor_geometry.width = -1; /* invalid value */
597 tasklist->priv->relief = CTK_RELIEF_NORMAL;
598 tasklist->priv->orientation = CTK_ORIENTATION_HORIZONTAL;
599 tasklist->priv->scroll_enabled = TRUE(!(0));
600
601 atk_obj = ctk_widget_get_accessible (widget);
602 atk_object_set_name (atk_obj, _("Window List")((char *) g_dgettext ("libvnck-3.0", "Window List")));
603 atk_object_set_description (atk_obj, _("Tool to switch between visible windows")((char *) g_dgettext ("libvnck-3.0", "Tool to switch between visible windows"
))
);
604
605#if 0
606 /* This doesn't work because, and I think this is because we have no window;
607 * therefore, we use the scroll events on task buttons instead */
608 ctk_widget_add_events (widget, CDK_SCROLL_MASK);
609#endif
610}
611
612static void
613vnck_tasklist_class_init (VnckTasklistClass *klass)
614{
615 GObjectClass *object_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), (((GType) ((20) << (2))))))))
;
616 CtkWidgetClass *widget_class = CTK_WIDGET_CLASS (klass)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), ((ctk_widget_get_type ()))))))
;
617 CtkContainerClass *container_class = CTK_CONTAINER_CLASS (klass)((((CtkContainerClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), ((ctk_container_get_type ()))))))
;
618
619 object_class->finalize = vnck_tasklist_finalize;
620
621 widget_class->get_preferred_width = vnck_tasklist_get_preferred_width;
622 widget_class->get_preferred_height = vnck_tasklist_get_preferred_height;
623 widget_class->size_allocate = vnck_tasklist_size_allocate;
624 widget_class->realize = vnck_tasklist_realize;
625 widget_class->unrealize = vnck_tasklist_unrealize;
626#if 0
627 /* See comment above ctk_widget_add_events() in vnck_tasklist_init() */
628 widget_class->scroll_event = vnck_tasklist_scroll_event;
629#endif
630
631 container_class->forall = vnck_tasklist_forall;
632 container_class->remove = vnck_tasklist_remove;
633
634 /**
635 * VnckTasklist:fade-loop-time:
636 *
637 * When a window needs attention, a fade effect is drawn on the button
638 * representing the window. This property controls the time one loop of this
639 * fade effect takes, in seconds.
640 *
641 * Since: 2.16
642 */
643 ctk_widget_class_install_style_property (widget_class,
644 g_param_spec_float ("fade-loop-time",
645 "Loop time",
646 "The time one loop takes when fading, in seconds. Default: 3.0",
647 0.2, 10.0, 3.0,
648 G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
649
650 /**
651 * VnckTasklist:fade-max-loops:
652 *
653 * When a window needs attention, a fade effect is drawn on the button
654 * representing the window. This property controls the number of loops for
655 * this fade effect. 0 means the button will only fade to the final color.
656 *
657 * Since: 2.20
658 */
659 ctk_widget_class_install_style_property (widget_class,
660 g_param_spec_int ("fade-max-loops",
661 "Maximum number of loops",
662 "The number of fading loops. 0 means the button will only fade to the final color. Default: 5",
663 0, 50, 5,
664 G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
665
666 /**
667 * VnckTasklist:fade-overlay-rect:
668 *
669 * When a window needs attention, a fade effect is drawn on the button
670 * representing the window. Set this property to %TRUE to enable a
671 * compatibility mode for pixbuf engine themes that cannot react to color
672 * changes. If enabled, a rectangle with the correct color will be drawn on
673 * top of the button.
674 *
675 * Since: 2.16
676 */
677 ctk_widget_class_install_style_property (widget_class,
678 g_param_spec_boolean ("fade-overlay-rect",
679 "Overlay a rectangle, instead of modifying the background.",
680 "Compatibility mode for pixbuf engine themes that cannot react to color changes. If enabled, a rectangle with the correct color will be drawn on top of the button. Default: TRUE",
681 TRUE(!(0)),
682 G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
683
684 /**
685 * VnckTasklist:fade-opacity:
686 *
687 * When a window needs attention, a fade effect is drawn on the button
688 * representing the window. This property controls the final opacity that
689 * will be reached by the fade effect.
690 *
691 * Since: 2.16
692 */
693 ctk_widget_class_install_style_property (widget_class,
694 g_param_spec_float ("fade-opacity",
695 "Final opacity",
696 "The final opacity that will be reached. Default: 0.8",
697 0.0, 1.0, 0.8,
698 G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
699
700 ctk_widget_class_set_css_name (widget_class, "vnck-tasklist");
701
702 /**
703 * VnckTasklist::task-enter-notify:
704 * @tasklist: the #VnckTasklist which emitted the signal.
705 * @windows: the #GList with all the #VnckWindow belonging to the task.
706 *
707 * Emitted when the task is entered.
708 */
709 signals[TASK_ENTER_NOTIFY] =
710 g_signal_new ("task_enter_notify",
711 G_OBJECT_CLASS_TYPE (object_class)((((GTypeClass*) (object_class))->g_type)),
712 G_SIGNAL_RUN_LAST,
713 0, NULL((void*)0), NULL((void*)0), NULL((void*)0),
714 G_TYPE_NONE((GType) ((1) << (2))), 1,
715 G_TYPE_POINTER((GType) ((17) << (2))));
716
717 /**
718 * VnckTasklist::task-leave-notify:
719 * @tasklist: the #VnckTasklist which emitted the signal.
720 * @windows: the #GList with all the #VnckWindow belonging to the task.
721 *
722 * Emitted when the task is entered.
723 */
724 signals[TASK_LEAVE_NOTIFY] =
725 g_signal_new ("task_leave_notify",
726 G_OBJECT_CLASS_TYPE (object_class)((((GTypeClass*) (object_class))->g_type)),
727 G_SIGNAL_RUN_LAST,
728 0, NULL((void*)0), NULL((void*)0), NULL((void*)0),
729 G_TYPE_NONE((GType) ((1) << (2))), 1,
730 G_TYPE_POINTER((GType) ((17) << (2))));
731}
732
733static void
734vnck_tasklist_free_skipped_windows (VnckTasklist *tasklist)
735{
736 GList *l;
737
738 l = tasklist->priv->skipped_windows;
739
740 while (l != NULL((void*)0))
741 {
742 skipped_window *skipped = (skipped_window*) l->data;
743 g_signal_handler_disconnect (skipped->window, skipped->tag);
744 g_object_unref (skipped->window);
745 g_free (skipped);
746 l = l->next;
747 }
748
749 g_list_free (tasklist->priv->skipped_windows);
750}
751
752static void
753vnck_tasklist_finalize (GObject *object)
754{
755 VnckTasklist *tasklist;
756
757 tasklist = VNCK_TASKLIST (object)((((VnckTasklist*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((vnck_tasklist_get_type ()))))))
;
758
759 /* Tasks should have gone away due to removing their
760 * buttons in container destruction
761 */
762 g_assert (tasklist->priv->class_groups == NULL)do { if (tasklist->priv->class_groups == ((void*)0)) ; else
g_assertion_message_expr ("Vnck", "../libvnck/tasklist.c", 762
, ((const char*) (__func__)), "tasklist->priv->class_groups == NULL"
); } while (0)
;
763 g_assert (tasklist->priv->windows == NULL)do { if (tasklist->priv->windows == ((void*)0)) ; else g_assertion_message_expr
("Vnck", "../libvnck/tasklist.c", 763, ((const char*) (__func__
)), "tasklist->priv->windows == NULL"); } while (0)
;
764 g_assert (tasklist->priv->windows_without_class_group == NULL)do { if (tasklist->priv->windows_without_class_group ==
((void*)0)) ; else g_assertion_message_expr ("Vnck", "../libvnck/tasklist.c"
, 764, ((const char*) (__func__)), "tasklist->priv->windows_without_class_group == NULL"
); } while (0)
;
765 g_assert (tasklist->priv->startup_sequences == NULL)do { if (tasklist->priv->startup_sequences == ((void*)0
)) ; else g_assertion_message_expr ("Vnck", "../libvnck/tasklist.c"
, 765, ((const char*) (__func__)), "tasklist->priv->startup_sequences == NULL"
); } while (0)
;
766 /* vnck_tasklist_free_tasks (tasklist); */
767
768 if (tasklist->priv->skipped_windows)
769 {
770 vnck_tasklist_free_skipped_windows (tasklist);
771 tasklist->priv->skipped_windows = NULL((void*)0);
772 }
773
774 g_hash_table_destroy (tasklist->priv->class_group_hash);
775 tasklist->priv->class_group_hash = NULL((void*)0);
776
777 g_hash_table_destroy (tasklist->priv->win_hash);
778 tasklist->priv->win_hash = NULL((void*)0);
779
780 if (tasklist->priv->activate_timeout_id != 0)
781 {
782 g_source_remove (tasklist->priv->activate_timeout_id);
783 tasklist->priv->activate_timeout_id = 0;
784 }
785
786 if (tasklist->priv->idle_callback_tag != 0)
787 {
788 g_source_remove (tasklist->priv->idle_callback_tag);
789 tasklist->priv->idle_callback_tag = 0;
790 }
791
792 g_free (tasklist->priv->size_hints);
793 tasklist->priv->size_hints = NULL((void*)0);
794 tasklist->priv->size_hints_len = 0;
795
796 if (tasklist->priv->free_icon_loader_data != NULL((void*)0))
797 (* tasklist->priv->free_icon_loader_data) (tasklist->priv->icon_loader_data);
798 tasklist->priv->free_icon_loader_data = NULL((void*)0);
799 tasklist->priv->icon_loader_data = NULL((void*)0);
800
801 G_OBJECT_CLASS (vnck_tasklist_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((vnck_tasklist_parent_class)), (((GType) ((20) << (
2))))))))
->finalize (object);
802}
803
804/**
805 * vnck_tasklist_set_grouping:
806 * @tasklist: a #VnckTasklist.
807 * @grouping: a grouping policy.
808 *
809 * Sets the grouping policy for @tasklist to @grouping.
810 */
811void
812vnck_tasklist_set_grouping (VnckTasklist *tasklist,
813 VnckTasklistGroupingType grouping)
814{
815 g_return_if_fail (VNCK_IS_TASKLIST (tasklist))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((tasklist)); GType __t = ((vnck_tasklist_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Vnck", ((const char*) (__func__
)), "VNCK_IS_TASKLIST (tasklist)"); return; } } while (0)
;
816
817 if (tasklist->priv->grouping == grouping)
818 return;
819
820 tasklist->priv->grouping = grouping;
821 ctk_widget_queue_resize (CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
);
822}
823
824static void
825vnck_tasklist_set_relief_callback (VnckWindow *win G_GNUC_UNUSED__attribute__ ((__unused__)),
826 VnckTask *task,
827 VnckTasklist *tasklist)
828{
829 ctk_button_set_relief (CTK_BUTTON (task->button)((((CtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), ((ctk_button_get_type ()))))))
, tasklist->priv->relief);
830}
831
832/**
833 * vnck_tasklist_set_button_relief:
834 * @tasklist: a #VnckTasklist.
835 * @relief: a relief type.
836 *
837 * Sets the relief type of the buttons in @tasklist to @relief. The main use of
838 * this function is proper integration of #VnckTasklist in panels with
839 * non-system backgrounds.
840 *
841 * Since: 2.12
842 */
843void
844vnck_tasklist_set_button_relief (VnckTasklist *tasklist, CtkReliefStyle relief)
845{
846 GList *walk;
847
848 g_return_if_fail (VNCK_IS_TASKLIST (tasklist))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((tasklist)); GType __t = ((vnck_tasklist_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Vnck", ((const char*) (__func__
)), "VNCK_IS_TASKLIST (tasklist)"); return; } } while (0)
;
849
850 if (relief == tasklist->priv->relief)
851 return;
852
853 tasklist->priv->relief = relief;
854
855 g_hash_table_foreach (tasklist->priv->win_hash,
856 (GHFunc) vnck_tasklist_set_relief_callback,
857 tasklist);
858 for (walk = tasklist->priv->class_groups; walk; walk = g_list_next (walk)((walk) ? (((GList *)(walk))->next) : ((void*)0)))
859 ctk_button_set_relief (CTK_BUTTON (VNCK_TASK (walk->data)->button)((((CtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((walk->data)), ((vnck_task_get_type ()))))))->button
)), ((ctk_button_get_type ()))))))
, relief);
860}
861
862/**
863 * vnck_tasklist_set_middle_click_close:
864 * @tasklist: a #VnckTasklist.
865 * @middle_click_close: whether to close windows with middle click on
866 * button.
867 *
868 * Sets @tasklist to close windows with mouse middle click on button,
869 * according to @middle_click_close.
870 *
871 * Since: 3.4.6
872 */
873void
874vnck_tasklist_set_middle_click_close (VnckTasklist *tasklist,
875 gboolean middle_click_close)
876{
877 g_return_if_fail (VNCK_IS_TASKLIST (tasklist))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((tasklist)); GType __t = ((vnck_tasklist_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Vnck", ((const char*) (__func__
)), "VNCK_IS_TASKLIST (tasklist)"); return; } } while (0)
;
878
879 tasklist->priv->middle_click_close = middle_click_close;
880}
881
882/**
883 * vnck_tasklist_set_orientation:
884 * @tasklist: a #VnckTasklist.
885 * @orient: a CtkOrientation.
886 *
887 * Set the orientation of the @tasklist to match @orient.
888 * This function can be used to integrate a #VnckTasklist in vertical panels.
889 *
890 * Since: 3.4.6
891 */
892void vnck_tasklist_set_orientation (VnckTasklist *tasklist,
893 CtkOrientation orient)
894{
895 g_return_if_fail (VNCK_IS_TASKLIST (tasklist))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((tasklist)); GType __t = ((vnck_tasklist_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Vnck", ((const char*) (__func__
)), "VNCK_IS_TASKLIST (tasklist)"); return; } } while (0)
;
896
897 tasklist->priv->orientation = orient;
898}
899
900/**
901 * vnck_tasklist_set_scroll_enabled:
902 * @tasklist: a #VnckTasklist.
903 * @scroll_enabled: a boolean.
904 *
905 * Sets the scroll behavior of the @tasklist. When set to %TRUE, a scroll
906 * event over the tasklist will change the current window accordingly.
907 *
908 * Since: 3.24.0
909 */
910void
911vnck_tasklist_set_scroll_enabled (VnckTasklist *tasklist,
912 gboolean scroll_enabled)
913{
914 g_return_if_fail (VNCK_IS_TASKLIST (tasklist))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((tasklist)); GType __t = ((vnck_tasklist_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Vnck", ((const char*) (__func__
)), "VNCK_IS_TASKLIST (tasklist)"); return; } } while (0)
;
915
916 tasklist->priv->scroll_enabled = scroll_enabled;
917}
918
919/**
920 * vnck_tasklist_get_scroll_enabled:
921 * @tasklist: a #VnckTasklist.
922 *
923 * Gets the scroll behavior of the @tasklist.
924 *
925 * Since: 3.24.0
926 */
927gboolean
928vnck_tasklist_get_scroll_enabled (VnckTasklist *tasklist)
929{
930 g_return_val_if_fail (VNCK_IS_TASKLIST (tasklist), TRUE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((tasklist)); GType __t = ((vnck_tasklist_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Vnck", ((const char*) (__func__
)), "VNCK_IS_TASKLIST (tasklist)"); return ((!(0))); } } while
(0)
;
931
932 return tasklist->priv->scroll_enabled;
933}
934
935/**
936 * vnck_tasklist_set_switch_workspace_on_unminimize:
937 * @tasklist: a #VnckTasklist.
938 * @switch_workspace_on_unminimize: whether to activate the #VnckWorkspace a
939 * #VnckWindow is on when unminimizing it.
940 *
941 * Sets @tasklist to activate or not the #VnckWorkspace a #VnckWindow is on
942 * when unminimizing it, according to @switch_workspace_on_unminimize.
943 *
944 * FIXME: does it still work?
945 */
946void
947vnck_tasklist_set_switch_workspace_on_unminimize (VnckTasklist *tasklist,
948 gboolean switch_workspace_on_unminimize)
949{
950 g_return_if_fail (VNCK_IS_TASKLIST (tasklist))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((tasklist)); GType __t = ((vnck_tasklist_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Vnck", ((const char*) (__func__
)), "VNCK_IS_TASKLIST (tasklist)"); return; } } while (0)
;
951
952 tasklist->priv->switch_workspace_on_unminimize = switch_workspace_on_unminimize;
953}
954
955/**
956 * vnck_tasklist_set_include_all_workspaces:
957 * @tasklist: a #VnckTasklist.
958 * @include_all_workspaces: whether to display #VnckWindow from all
959 * #VnckWorkspace in @tasklist.
960 *
961 * Sets @tasklist to display #VnckWindow from all #VnckWorkspace or not,
962 * according to @include_all_workspaces.
963 *
964 * Note that if the active #VnckWorkspace has a viewport and if
965 * @include_all_workspaces is %FALSE, then only the #VnckWindow visible in the
966 * viewport are displayed in @tasklist. The rationale for this is that the
967 * viewport is generally used to implement workspace-like behavior. A
968 * side-effect of this is that, when using multiple #VnckWorkspace with
969 * viewport, it is not possible to show all #VnckWindow from a #VnckWorkspace
970 * (even those that are not visible in the viewport) in @tasklist without
971 * showing all #VnckWindow from all #VnckWorkspace.
972 */
973void
974vnck_tasklist_set_include_all_workspaces (VnckTasklist *tasklist,
975 gboolean include_all_workspaces)
976{
977 g_return_if_fail (VNCK_IS_TASKLIST (tasklist))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((tasklist)); GType __t = ((vnck_tasklist_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Vnck", ((const char*) (__func__
)), "VNCK_IS_TASKLIST (tasklist)"); return; } } while (0)
;
978
979 include_all_workspaces = (include_all_workspaces != 0);
980
981 if (tasklist->priv->include_all_workspaces == include_all_workspaces)
982 return;
983
984 tasklist->priv->include_all_workspaces = include_all_workspaces;
985 vnck_tasklist_update_lists (tasklist);
986 ctk_widget_queue_resize (CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
);
987}
988
989/**
990 * vnck_tasklist_set_grouping_limit:
991 * @tasklist: a #VnckTasklist.
992 * @limit: a size in pixels.
993 *
994 * Sets the maximum size of buttons in @tasklist before @tasklist tries to
995 * group #VnckWindow in the same #VnckApplication in only one button. This
996 * limit is valid only when the grouping policy of @tasklist is
997 * %VNCK_TASKLIST_AUTO_GROUP.
998 */
999void
1000vnck_tasklist_set_grouping_limit (VnckTasklist *tasklist,
1001 gint limit)
1002{
1003 g_return_if_fail (VNCK_IS_TASKLIST (tasklist))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((tasklist)); GType __t = ((vnck_tasklist_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Vnck", ((const char*) (__func__
)), "VNCK_IS_TASKLIST (tasklist)"); return; } } while (0)
;
1004
1005 if (tasklist->priv->grouping_limit == limit)
1006 return;
1007
1008 tasklist->priv->grouping_limit = limit;
1009 ctk_widget_queue_resize (CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
);
1010}
1011
1012/**
1013 * vnck_tasklist_set_icon_loader:
1014 * @tasklist: a #VnckTasklist
1015 * @load_icon_func: icon loader function
1016 * @data: data for icon loader function
1017 * @free_data_func: function to free the data
1018 *
1019 * Sets a function to be used for loading icons.
1020 *
1021 * Since: 2.2
1022 **/
1023void
1024vnck_tasklist_set_icon_loader (VnckTasklist *tasklist,
1025 VnckLoadIconFunction load_icon_func,
1026 void *data,
1027 GDestroyNotify free_data_func)
1028{
1029 g_return_if_fail (VNCK_IS_TASKLIST (tasklist))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((tasklist)); GType __t = ((vnck_tasklist_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Vnck", ((const char*) (__func__
)), "VNCK_IS_TASKLIST (tasklist)"); return; } } while (0)
;
1030
1031 if (tasklist->priv->free_icon_loader_data != NULL((void*)0))
1032 (* tasklist->priv->free_icon_loader_data) (tasklist->priv->icon_loader_data);
1033
1034 tasklist->priv->icon_loader = load_icon_func;
1035 tasklist->priv->icon_loader_data = data;
1036 tasklist->priv->free_icon_loader_data = free_data_func;
1037}
1038
1039/* returns the maximal possible button width (i.e. if you
1040 * don't want to stretch the buttons to fill the alloctions
1041 * the width can be smaller) */
1042static int
1043vnck_tasklist_layout (CtkAllocation *allocation,
1044 int max_width,
1045 int max_height,
1046 int n_buttons,
1047 CtkOrientation orientation,
1048 int *n_cols_out,
1049 int *n_rows_out)
1050{
1051 int n_cols, n_rows;
1052
1053 if (n_buttons == 0)
1054 {
1055 *n_cols_out = 0;
1056 *n_rows_out = 0;
1057 return 0;
1058 }
1059
1060 if (orientation == CTK_ORIENTATION_HORIZONTAL)
1061 {
1062 /* How many rows fit in the allocation */
1063 n_rows = allocation->height / max_height;
1064
1065 /* Don't have more rows than buttons */
1066 n_rows = MIN (n_rows, n_buttons)(((n_rows) < (n_buttons)) ? (n_rows) : (n_buttons));
1067
1068 /* At least one row */
1069 n_rows = MAX (n_rows, 1)(((n_rows) > (1)) ? (n_rows) : (1));
1070
1071 /* We want to use as many cols as possible to limit the width */
1072 n_cols = (n_buttons + n_rows - 1) / n_rows;
1073
1074 /* At least one column */
1075 n_cols = MAX (n_cols, 1)(((n_cols) > (1)) ? (n_cols) : (1));
1076 }
1077 else
1078 {
1079 /* How many cols fit in the allocation */
1080 n_cols = allocation->width / max_width;
1081
1082 /* Don't have more cols than buttons */
1083 n_cols = MIN (n_cols, n_buttons)(((n_cols) < (n_buttons)) ? (n_cols) : (n_buttons));
1084
1085 /* At least one col */
1086 n_cols = MAX (n_cols, 1)(((n_cols) > (1)) ? (n_cols) : (1));
1087
1088 /* We want to use as many rows as possible to limit the height */
1089 n_rows = (n_buttons + n_cols - 1) / n_cols;
1090
1091 /* At least one row */
1092 n_rows = MAX (n_rows, 1)(((n_rows) > (1)) ? (n_rows) : (1));
1093 }
1094
1095 *n_cols_out = n_cols;
1096 *n_rows_out = n_rows;
1097
1098 return allocation->width / n_cols;
1099}
1100
1101static void
1102vnck_tasklist_score_groups (VnckTasklist *tasklist G_GNUC_UNUSED__attribute__ ((__unused__)),
1103 GList *ungrouped_class_groups)
1104{
1105 VnckTask *class_group_task;
1106 VnckTask *win_task;
1107 GList *l, *w;
1108 const char *first_name = NULL((void*)0);
1109 int n_windows;
1110 int n_same_title;
1111 double same_window_ratio;
1112
1113 l = ungrouped_class_groups;
1114 while (l != NULL((void*)0))
1115 {
1116 class_group_task = VNCK_TASK (l->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_task_get_type ()))))))
;
1117
1118 n_windows = g_list_length (class_group_task->windows);
1119
1120 n_same_title = 0;
1121 w = class_group_task->windows;
1122 while (w != NULL((void*)0))
1123 {
1124 win_task = VNCK_TASK (w->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((w->data)), ((vnck_task_get_type ()))))))
;
1125
1126 if (first_name == NULL((void*)0))
1127 {
1128 if (vnck_window_has_icon_name (win_task->window))
1129 first_name = vnck_window_get_icon_name (win_task->window);
1130 else
1131 first_name = vnck_window_get_name (win_task->window);
1132 n_same_title++;
1133 }
1134 else
1135 {
1136 const char *name;
1137
1138 if (vnck_window_has_icon_name (win_task->window))
1139 name = vnck_window_get_icon_name (win_task->window);
1140 else
1141 name = vnck_window_get_name (win_task->window);
1142
1143 if (strcmp (name, first_name) == 0)
1144 n_same_title++;
1145 }
1146
1147 w = w->next;
1148 }
1149 same_window_ratio = (double)n_same_title/(double)n_windows;
1150
1151 /* FIXME: This is fairly bogus and should be researched more.
1152 * XP groups by least used, so we probably want to add
1153 * total focused time to this expression.
1154 */
1155 class_group_task->grouping_score = -same_window_ratio * 5 + n_windows;
1156
1157 l = l->next;
1158 }
1159}
1160
1161static GList *
1162vnck_task_get_highest_scored (GList *ungrouped_class_groups,
1163 VnckTask **class_group_task_out)
1164{
1165 VnckTask *class_group_task;
1166 VnckTask *best_task = NULL((void*)0);
1167 double max_score = -1000000000.0; /* Large negative score */
1168 GList *l;
1169
1170 l = ungrouped_class_groups;
1171 while (l != NULL((void*)0))
1172 {
1173 class_group_task = VNCK_TASK (l->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_task_get_type ()))))))
;
1174
1175 if (class_group_task->grouping_score >= max_score)
1176 {
1177 max_score = class_group_task->grouping_score;
1178 best_task = class_group_task;
1179 }
1180
1181 l = l->next;
1182 }
1183
1184 *class_group_task_out = best_task;
1185
1186 return g_list_remove (ungrouped_class_groups, best_task);
1187}
1188
1189static int
1190vnck_tasklist_get_button_size (CtkWidget *widget)
1191{
1192 CtkStyleContext *style_context;
1193 CtkStateFlags state;
1194 PangoContext *context;
1195 PangoFontMetrics *metrics;
1196 PangoFontDescription *description;
1197 gint char_width;
1198 gint text_width;
1199 gint width;
1200
1201 style_context = ctk_widget_get_style_context (widget);
1202 state = ctk_style_context_get_state (style_context);
1203 ctk_style_context_get (style_context, state, CTK_STYLE_PROPERTY_FONT"font", &description, NULL((void*)0));
1204
1205 context = ctk_widget_get_pango_context (widget);
1206 metrics = pango_context_get_metrics (context, description,
1207 pango_context_get_language (context));
1208 char_width = pango_font_metrics_get_approximate_char_width (metrics);
1209 pango_font_metrics_unref (metrics);
1210 text_width = PANGO_PIXELS (TASKLIST_TEXT_MAX_WIDTH * char_width)(((int)(25 * char_width) + 512) >> 10);
1211
1212 width = text_width + 2 * TASKLIST_BUTTON_PADDING4
1213 + MINI_ICON_SIZE_vnck_get_default_mini_icon_size () + 2 * TASKLIST_BUTTON_PADDING4;
1214
1215 return width;
1216}
1217
1218static void
1219vnck_tasklist_size_request (CtkWidget *widget,
1220 CtkRequisition *requisition)
1221{
1222 VnckTasklist *tasklist;
1223 CtkRequisition child_req;
1224 CtkAllocation tasklist_allocation;
1225 CtkAllocation fake_allocation;
1226 int max_height = 1;
1227 int max_width = 1;
1228 /* int u_width, u_height; */
1229 GList *l;
1230 GArray *array;
1231 GList *ungrouped_class_groups;
1232 int n_windows;
1233 int n_startup_sequences;
1234 int n_rows;
1235 int n_cols, last_n_cols;
1236 int n_grouped_buttons;
1237 gboolean score_set;
1238 int val;
1239 VnckTask *class_group_task;
1240 int lowest_range;
1241 int grouping_limit;
1242
1243 tasklist = VNCK_TASKLIST (widget)((((VnckTasklist*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((vnck_tasklist_get_type ()))))))
;
1244
1245 /* Calculate max needed height and width of the buttons */
1246#define GET_MAX_WIDTH_HEIGHT_FROM_BUTTONS(list)l = list; while (l != ((void*)0)) { VnckTask *task = ((((VnckTask
*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((l->
data)), ((vnck_task_get_type ())))))); ctk_widget_get_preferred_size
(task->button, &child_req, ((void*)0)); max_height = (
((child_req.height) > (max_height)) ? (child_req.height) :
(max_height)); max_width = (((child_req.width) > (max_width
)) ? (child_req.width) : (max_width)); l = l->next; }
\
1247 l = list; \
1248 while (l != NULL((void*)0)) \
1249 { \
1250 VnckTask *task = VNCK_TASK (l->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_task_get_type ()))))))
; \
1251 \
1252 ctk_widget_get_preferred_size (task->button, \
1253 &child_req, NULL((void*)0)); \
1254 \
1255 max_height = MAX (child_req.height, \(((child_req.height) > (max_height)) ? (child_req.height) :
(max_height))
1256 max_height)(((child_req.height) > (max_height)) ? (child_req.height) :
(max_height))
; \
1257 max_width = MAX (child_req.width, \(((child_req.width) > (max_width)) ? (child_req.width) : (
max_width))
1258 max_width)(((child_req.width) > (max_width)) ? (child_req.width) : (
max_width))
; \
1259 \
1260 l = l->next; \
1261 }
1262
1263 GET_MAX_WIDTH_HEIGHT_FROM_BUTTONS (tasklist->priv->windows)l = tasklist->priv->windows; while (l != ((void*)0)) { VnckTask
*task = ((((VnckTask*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((l->data)), ((vnck_task_get_type ())))))
); ctk_widget_get_preferred_size (task->button, &child_req
, ((void*)0)); max_height = (((child_req.height) > (max_height
)) ? (child_req.height) : (max_height)); max_width = (((child_req
.width) > (max_width)) ? (child_req.width) : (max_width));
l = l->next; }
1264 GET_MAX_WIDTH_HEIGHT_FROM_BUTTONS (tasklist->priv->class_groups)l = tasklist->priv->class_groups; while (l != ((void*)0
)) { VnckTask *task = ((((VnckTask*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((l->data)), ((vnck_task_get_type ())))
))); ctk_widget_get_preferred_size (task->button, &child_req
, ((void*)0)); max_height = (((child_req.height) > (max_height
)) ? (child_req.height) : (max_height)); max_width = (((child_req
.width) > (max_width)) ? (child_req.width) : (max_width));
l = l->next; }
1265 GET_MAX_WIDTH_HEIGHT_FROM_BUTTONS (tasklist->priv->startup_sequences)l = tasklist->priv->startup_sequences; while (l != ((void
*)0)) { VnckTask *task = ((((VnckTask*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((l->data)), ((vnck_task_get_type ())))
))); ctk_widget_get_preferred_size (task->button, &child_req
, ((void*)0)); max_height = (((child_req.height) > (max_height
)) ? (child_req.height) : (max_height)); max_width = (((child_req
.width) > (max_width)) ? (child_req.width) : (max_width));
l = l->next; }
1266
1267 /* Note that the fact that we nearly don't care about the width/height
1268 * requested by the buttons makes it possible to hide/show the label/image
1269 * in vnck_task_size_allocated(). If we really cared about those, this
1270 * wouldn't work since our call to ctk_widget_size_request() does not take
1271 * into account the hidden widgets.
1272 */
1273 tasklist->priv->max_button_width = vnck_tasklist_get_button_size (widget);
1274 tasklist->priv->max_button_height = max_height;
1275
1276 ctk_widget_get_allocation (CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
, &tasklist_allocation);
1277
1278 fake_allocation.width = tasklist_allocation.width;
1279 fake_allocation.height = tasklist_allocation.height;
1280
1281 array = g_array_new (FALSE(0), FALSE(0), sizeof (int));
1282
1283 /* Calculate size_hints list */
1284
1285 n_windows = g_list_length (tasklist->priv->windows);
1286 n_startup_sequences = g_list_length (tasklist->priv->startup_sequences);
1287 n_grouped_buttons = 0;
1288 ungrouped_class_groups = g_list_copy (tasklist->priv->class_groups);
1289 score_set = FALSE(0);
1290
1291 grouping_limit = MIN (tasklist->priv->grouping_limit,(((tasklist->priv->grouping_limit) < (tasklist->priv
->max_button_width)) ? (tasklist->priv->grouping_limit
) : (tasklist->priv->max_button_width))
1292 tasklist->priv->max_button_width)(((tasklist->priv->grouping_limit) < (tasklist->priv
->max_button_width)) ? (tasklist->priv->grouping_limit
) : (tasklist->priv->max_button_width))
;
1293
1294 /* Try ungrouped mode */
1295 vnck_tasklist_layout (&fake_allocation,
1296 tasklist->priv->max_button_width,
1297 tasklist->priv->max_button_height,
1298 n_windows + n_startup_sequences,
1299 tasklist->priv->orientation,
1300 &n_cols, &n_rows);
1301
1302 last_n_cols = G_MAXINT2147483647;
1303 lowest_range = G_MAXINT2147483647;
1304 if (tasklist->priv->grouping != VNCK_TASKLIST_ALWAYS_GROUP)
1305 {
1306 if (tasklist->priv->orientation == CTK_ORIENTATION_HORIZONTAL)
1307 {
1308 val = n_cols * tasklist->priv->max_button_width;
1309 g_array_insert_val (array, array->len, val)g_array_insert_vals (array, array->len, &(val), 1);
1310 val = n_cols * grouping_limit;
1311 g_array_insert_val (array, array->len, val)g_array_insert_vals (array, array->len, &(val), 1);
1312
1313 last_n_cols = n_cols;
1314 lowest_range = val;
1315 }
1316 else
1317 {
1318 val = n_rows * tasklist->priv->max_button_height;
1319 g_array_insert_val (array, array->len, val)g_array_insert_vals (array, array->len, &(val), 1);
1320 val = n_rows * grouping_limit;
1321 g_array_insert_val (array, array->len, val)g_array_insert_vals (array, array->len, &(val), 1);
1322
1323 last_n_cols = n_rows;
1324 lowest_range = val;
1325 }
1326 }
1327
1328 while (ungrouped_class_groups != NULL((void*)0) &&
1329 tasklist->priv->grouping != VNCK_TASKLIST_NEVER_GROUP)
1330 {
1331 if (!score_set)
1332 {
1333 vnck_tasklist_score_groups (tasklist, ungrouped_class_groups);
1334 score_set = TRUE(!(0));
1335 }
1336
1337 ungrouped_class_groups = vnck_task_get_highest_scored (ungrouped_class_groups, &class_group_task);
1338
1339 n_grouped_buttons += g_list_length (class_group_task->windows) - 1;
1340
1341 vnck_tasklist_layout (&fake_allocation,
1342 tasklist->priv->max_button_width,
1343 tasklist->priv->max_button_height,
1344 n_startup_sequences + n_windows - n_grouped_buttons,
1345 tasklist->priv->orientation,
1346 &n_cols, &n_rows);
1347
1348 if (tasklist->priv->orientation == CTK_ORIENTATION_HORIZONTAL)
1349 {
1350 if (n_cols != last_n_cols &&
1351 (tasklist->priv->grouping == VNCK_TASKLIST_AUTO_GROUP ||
1352 ungrouped_class_groups == NULL((void*)0)))
1353 {
1354 val = n_cols * tasklist->priv->max_button_width;
1355 if (val >= lowest_range)
1356 {
1357 /* Overlaps old range */
1358 g_assert (array->len > 0)do { if (array->len > 0) ; else g_assertion_message_expr
("Vnck", "../libvnck/tasklist.c", 1358, ((const char*) (__func__
)), "array->len > 0"); } while (0)
;
1359 lowest_range = n_cols * grouping_limit;
1360 g_array_index(array, int, array->len-1)(((int*) (void *) (array)->data) [(array->len-1)]) = lowest_range;
1361 }
1362 else
1363 {
1364 /* Full new range */
1365 g_array_insert_val (array, array->len, val)g_array_insert_vals (array, array->len, &(val), 1);
1366 val = n_cols * grouping_limit;
1367 g_array_insert_val (array, array->len, val)g_array_insert_vals (array, array->len, &(val), 1);
1368 lowest_range = val;
1369 }
1370
1371 last_n_cols = n_cols;
1372 }
1373 }
1374 else
1375 {
1376 if (n_rows != last_n_cols &&
1377 (tasklist->priv->grouping == VNCK_TASKLIST_AUTO_GROUP ||
1378 ungrouped_class_groups == NULL((void*)0)))
1379 {
1380 val = n_rows * tasklist->priv->max_button_height;
1381 if (val >= lowest_range)
1382 {
1383 /* Overlaps old range */
1384 g_assert (array->len > 0)do { if (array->len > 0) ; else g_assertion_message_expr
("Vnck", "../libvnck/tasklist.c", 1384, ((const char*) (__func__
)), "array->len > 0"); } while (0)
;
1385 lowest_range = n_rows * grouping_limit;
1386 g_array_index (array, int, array->len-1)(((int*) (void *) (array)->data) [(array->len-1)]) = lowest_range;
1387 }
1388 else
1389 {
1390 /* Full new range */
1391 g_array_insert_val (array, array->len, val)g_array_insert_vals (array, array->len, &(val), 1);
1392 val = n_rows * grouping_limit;
1393 g_array_insert_val (array, array->len, val)g_array_insert_vals (array, array->len, &(val), 1);
1394 lowest_range = val;
1395 }
1396
1397 last_n_cols = n_rows;
1398 }
1399 }
1400 }
1401
1402 g_list_free (ungrouped_class_groups);
1403
1404 /* Always let you go down to a zero size: */
1405 if (array->len > 0)
1406 {
1407 g_array_index(array, int, array->len-1)(((int*) (void *) (array)->data) [(array->len-1)]) = 0;
1408 }
1409 else
1410 {
1411 val = 0;
1412 g_array_insert_val (array, 0, val)g_array_insert_vals (array, 0, &(val), 1);
1413 g_array_insert_val (array, 0, val)g_array_insert_vals (array, 0, &(val), 1);
1414 }
1415
1416 if (tasklist->priv->size_hints)
1417 g_free (tasklist->priv->size_hints);
1418
1419 tasklist->priv->size_hints_len = array->len;
1420 tasklist->priv->size_hints = (int *)g_array_free (array, FALSE(0));
1421
1422 if (tasklist->priv->orientation == CTK_ORIENTATION_HORIZONTAL)
1423 {
1424 requisition->width = tasklist->priv->size_hints[0];
1425 requisition->height = fake_allocation.height;
1426 }
1427 else
1428 {
1429 requisition->width = fake_allocation.width;
1430 requisition->height = tasklist->priv->size_hints[0];
1431 }
1432}
1433
1434static void
1435vnck_tasklist_get_preferred_width (CtkWidget *widget,
1436 int *minimum_width,
1437 int *natural_width)
1438{
1439 CtkRequisition req;
1440
1441 vnck_tasklist_size_request (widget, &req);
1442
1443 *minimum_width = *natural_width = req.width;
1444}
1445
1446static void
1447vnck_tasklist_get_preferred_height (CtkWidget *widget,
1448 int *minimum_height,
1449 int *natural_height)
1450{
1451 CtkRequisition req;
1452
1453 vnck_tasklist_size_request (widget, &req);
1454
1455 *minimum_height = *natural_height = req.height;
1456}
1457
1458
1459/**
1460 * vnck_tasklist_get_size_hint_list:
1461 * @tasklist: a #VnckTasklist.
1462 * @n_elements: return location for the number of elements in the array
1463 * returned by this function. This number should always be pair.
1464 *
1465 * Since a #VnckTasklist does not have a fixed size (#VnckWindow can be grouped
1466 * when needed, for example), the standard size request mechanism in CTK+ is
1467 * not enough to announce what sizes can be used by @tasklist. The size hints
1468 * mechanism is a solution for this. See panel_applet_set_size_hints() for more
1469 * information.
1470 *
1471 * Return value: a list of size hints that can be used to allocate an
1472 * appropriate size for @tasklist.
1473 */
1474const int *
1475vnck_tasklist_get_size_hint_list (VnckTasklist *tasklist,
1476 int *n_elements)
1477{
1478 g_return_val_if_fail (VNCK_IS_TASKLIST (tasklist), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((tasklist)); GType __t = ((vnck_tasklist_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Vnck", ((const char*) (__func__
)), "VNCK_IS_TASKLIST (tasklist)"); return (((void*)0)); } } while
(0)
;
1479 g_return_val_if_fail (n_elements != NULL, NULL)do { if ((n_elements != ((void*)0))) { } else { g_return_if_fail_warning
("Vnck", ((const char*) (__func__)), "n_elements != NULL"); return
(((void*)0)); } } while (0)
;
1480
1481 *n_elements = tasklist->priv->size_hints_len;
1482 return tasklist->priv->size_hints;
1483}
1484
1485static gboolean
1486task_button_queue_resize (gpointer user_data)
1487{
1488 VnckTask *task = VNCK_TASK (user_data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((user_data)), ((vnck_task_get_type ()))))))
;
1489
1490 ctk_widget_queue_resize (task->button);
1491 task->resize_idle_id = 0;
1492
1493 return G_SOURCE_REMOVE(0);
1494}
1495
1496static void
1497vnck_task_size_allocated (CtkWidget *widget,
1498 CtkAllocation *allocation,
1499 gpointer data)
1500{
1501 VnckTask *task = VNCK_TASK (data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((vnck_task_get_type ()))))))
;
1502 CtkStyleContext *context;
1503 CtkStateFlags state;
1504 CtkBorder padding;
1505 int min_image_width;
1506 gboolean old_image_visible;
1507 gboolean old_label_visible;
1508
1509 context = ctk_widget_get_style_context (widget);
1510 state = ctk_style_context_get_state (context);
1511 ctk_style_context_get_padding (context, state, &padding);
1512
1513 min_image_width = MINI_ICON_SIZE_vnck_get_default_mini_icon_size () +
1514 padding.left + padding.right +
1515 2 * TASKLIST_BUTTON_PADDING4;
1516 old_image_visible = ctk_widget_get_visible (task->image);
1517 old_label_visible = ctk_widget_get_visible (task->label);
1518
1519 if ((allocation->width < min_image_width + 2 * TASKLIST_BUTTON_PADDING4) &&
1520 (allocation->width >= min_image_width)) {
1521 ctk_widget_show (task->image);
1522 ctk_widget_hide (task->label);
1523 } else if (allocation->width < min_image_width) {
1524 ctk_widget_hide (task->image);
1525 ctk_widget_show (task->label);
1526 } else {
1527 ctk_widget_show (task->image);
1528 ctk_widget_show (task->label);
1529 }
1530
1531 if (old_image_visible != ctk_widget_get_visible (task->image) ||
1532 old_label_visible != ctk_widget_get_visible (task->label))
1533 {
1534 if (task->resize_idle_id == 0)
1535 task->resize_idle_id = g_idle_add (task_button_queue_resize, task);
1536 }
1537}
1538
1539static void
1540vnck_tasklist_size_allocate (CtkWidget *widget,
1541 CtkAllocation *allocation)
1542{
1543 CtkAllocation child_allocation;
1544 VnckTasklist *tasklist;
1545 VnckTask *class_group_task;
1546 int n_windows;
1547 int n_startup_sequences;
1548 GList *l;
1549 int button_width;
1550 int total_width;
1551 int n_rows;
1552 int n_cols;
1553 int n_grouped_buttons;
1554 int i;
1555 gboolean score_set;
1556 GList *ungrouped_class_groups;
1557 VnckTask *win_task;
1558 GList *visible_tasks = NULL((void*)0);
1559 GList *windows_sorted = NULL((void*)0);
1560 int grouping_limit;
1561
1562 if (allocation->width <= 1 || allocation->height <= 1)
1563 {
1564 CTK_WIDGET_CLASS (vnck_tasklist_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((vnck_tasklist_parent_class)), ((ctk_widget_get_type ()))
))))
->size_allocate (widget, allocation);
1565 return;
1566 }
1567
1568 tasklist = VNCK_TASKLIST (widget)((((VnckTasklist*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((vnck_tasklist_get_type ()))))))
;
1569
1570 n_windows = g_list_length (tasklist->priv->windows);
1571 n_startup_sequences = g_list_length (tasklist->priv->startup_sequences);
1572 n_grouped_buttons = 0;
1573 ungrouped_class_groups = g_list_copy (tasklist->priv->class_groups);
1574 score_set = FALSE(0);
1575
1576 grouping_limit = MIN (tasklist->priv->grouping_limit,(((tasklist->priv->grouping_limit) < (tasklist->priv
->max_button_width)) ? (tasklist->priv->grouping_limit
) : (tasklist->priv->max_button_width))
1577 tasklist->priv->max_button_width)(((tasklist->priv->grouping_limit) < (tasklist->priv
->max_button_width)) ? (tasklist->priv->grouping_limit
) : (tasklist->priv->max_button_width))
;
1578
1579 /* Try ungrouped mode */
1580 button_width = vnck_tasklist_layout (allocation,
1581 tasklist->priv->max_button_width,
1582 tasklist->priv->max_button_height,
1583 n_startup_sequences + n_windows,
1584 tasklist->priv->orientation,
1585 &n_cols, &n_rows);
1586 while (ungrouped_class_groups != NULL((void*)0) &&
1587 ((tasklist->priv->grouping == VNCK_TASKLIST_ALWAYS_GROUP) ||
1588 ((tasklist->priv->grouping == VNCK_TASKLIST_AUTO_GROUP) &&
1589 (button_width < grouping_limit))))
1590 {
1591 if (!score_set)
1592 {
1593 vnck_tasklist_score_groups (tasklist, ungrouped_class_groups);
1594 score_set = TRUE(!(0));
1595 }
1596
1597 ungrouped_class_groups = vnck_task_get_highest_scored (ungrouped_class_groups, &class_group_task);
1598
1599 n_grouped_buttons += g_list_length (class_group_task->windows) - 1;
1600
1601 if (g_list_length (class_group_task->windows) > 1)
1602 {
1603 visible_tasks = g_list_prepend (visible_tasks, class_group_task);
1604
1605 /* Sort */
1606 class_group_task->windows = g_list_sort (class_group_task->windows,
1607 vnck_task_compare_alphabetically);
1608
1609 /* Hide all this group's windows */
1610 l = class_group_task->windows;
1611 while (l != NULL((void*)0))
1612 {
1613 win_task = VNCK_TASK (l->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_task_get_type ()))))))
;
1614
1615 ctk_widget_set_child_visible (CTK_WIDGET (win_task->button)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((win_task->button)), ((ctk_widget_get_type ()))))))
, FALSE(0));
1616
1617 l = l->next;
1618 }
1619 }
1620 else
1621 {
1622 visible_tasks = g_list_prepend (visible_tasks, class_group_task->windows->data);
1623 ctk_widget_set_child_visible (CTK_WIDGET (class_group_task->button)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((class_group_task->button)), ((ctk_widget_get_type ())
)))))
, FALSE(0));
1624 }
1625
1626 button_width = vnck_tasklist_layout (allocation,
1627 tasklist->priv->max_button_width,
1628 tasklist->priv->max_button_height,
1629 n_startup_sequences + n_windows - n_grouped_buttons,
1630 tasklist->priv->orientation,
1631 &n_cols, &n_rows);
1632 }
1633
1634 /* Add all ungrouped windows to visible_tasks, and hide their class groups */
1635 l = ungrouped_class_groups;
1636 while (l != NULL((void*)0))
1637 {
1638 class_group_task = VNCK_TASK (l->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_task_get_type ()))))))
;
1639
1640 visible_tasks = g_list_concat (visible_tasks, g_list_copy (class_group_task->windows));
1641 ctk_widget_set_child_visible (CTK_WIDGET (class_group_task->button)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((class_group_task->button)), ((ctk_widget_get_type ())
)))))
, FALSE(0));
1642
1643 l = l->next;
1644 }
1645
1646 /* Add all windows that are ungrouped because they don't belong to any class
1647 * group */
1648 l = tasklist->priv->windows_without_class_group;
1649 while (l != NULL((void*)0))
1650 {
1651 VnckTask *task;
1652
1653 task = VNCK_TASK (l->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_task_get_type ()))))))
;
1654 visible_tasks = g_list_append (visible_tasks, task);
1655
1656 l = l->next;
1657 }
1658
1659 /* Add all startup sequences */
1660 visible_tasks = g_list_concat (visible_tasks, g_list_copy (tasklist->priv->startup_sequences));
1661
1662 /* Sort */
1663 visible_tasks = g_list_sort (visible_tasks, vnck_task_compare);
1664
1665 /* Allocate children */
1666 l = visible_tasks;
1667 i = 0;
1668 total_width = tasklist->priv->max_button_width * n_cols;
1669 total_width = MIN (total_width, allocation->width)(((total_width) < (allocation->width)) ? (total_width) :
(allocation->width))
;
1670 /* FIXME: this is obviously wrong, but if we don't this, some space that the
1671 * panel allocated to us won't have the panel popup menu, but the tasklist
1672 * popup menu */
1673 total_width = allocation->width;
1674 while (l != NULL((void*)0))
1675 {
1676 VnckTask *task = VNCK_TASK (l->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_task_get_type ()))))))
;
1677 int row = i % n_rows;
1678 int col = i / n_rows;
1679
1680 if (ctk_widget_get_direction (widget) == CTK_TEXT_DIR_RTL)
1681 col = n_cols - col - 1;
1682
1683 child_allocation.x = total_width*col / n_cols;
1684 child_allocation.y = allocation->height*row / n_rows;
1685 child_allocation.width = total_width*(col + 1) / n_cols - child_allocation.x;
1686 child_allocation.height = allocation->height*(row + 1) / n_rows - child_allocation.y;
1687 child_allocation.x += allocation->x;
1688 child_allocation.y += allocation->y;
1689
1690 ctk_widget_size_allocate (task->button, &child_allocation);
1691 ctk_widget_set_child_visible (CTK_WIDGET (task->button)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), ((ctk_widget_get_type ()))))))
, TRUE(!(0)));
1692
1693 if (task->type != VNCK_TASK_STARTUP_SEQUENCE)
1694 {
1695 GList *ll;
1696
1697 /* Build sorted windows list */
1698 if (g_list_length (task->windows) > 1)
1699 windows_sorted = g_list_concat (windows_sorted,
1700 g_list_copy (task->windows));
1701 else
1702 windows_sorted = g_list_append (windows_sorted, task);
1703 task->row = row;
1704 task->col = col;
1705 for (ll = task->windows; ll; ll = ll->next)
1706 {
1707 VNCK_TASK (ll->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((ll->data)), ((vnck_task_get_type ()))))))
->row = row;
1708 VNCK_TASK (ll->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((ll->data)), ((vnck_task_get_type ()))))))
->col = col;
1709 }
1710 }
1711 i++;
1712 l = l->next;
1713 }
1714
1715 /* Update icon geometries. */
1716 vnck_tasklist_update_icon_geometries (tasklist, visible_tasks);
1717
1718 g_list_free (visible_tasks);
1719 g_list_free (tasklist->priv->windows);
1720 g_list_free (ungrouped_class_groups);
1721 tasklist->priv->windows = windows_sorted;
1722
1723 CTK_WIDGET_CLASS (vnck_tasklist_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((vnck_tasklist_parent_class)), ((ctk_widget_get_type ()))
))))
->size_allocate (widget,
1724 allocation);
1725}
1726
1727static void
1728foreach_tasklist (VnckTasklist *tasklist,
1729 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
1730{
1731 vnck_tasklist_update_lists (tasklist);
1732}
1733
1734static void
1735vnck_tasklist_realize (CtkWidget *widget)
1736{
1737 VnckTasklist *tasklist;
1738 CdkScreen *cdkscreen;
1739
1740 tasklist = VNCK_TASKLIST (widget)((((VnckTasklist*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((vnck_tasklist_get_type ()))))))
;
1741
1742 cdkscreen = ctk_widget_get_screen (widget);
1743 tasklist->priv->screen = vnck_screen_get (cdk_x11_screen_get_screen_number (cdkscreen));
1744 g_assert (tasklist->priv->screen != NULL)do { if (tasklist->priv->screen != ((void*)0)) ; else g_assertion_message_expr
("Vnck", "../libvnck/tasklist.c", 1744, ((const char*) (__func__
)), "tasklist->priv->screen != NULL"); } while (0)
;
1745
1746#ifdef HAVE_STARTUP_NOTIFICATION1
1747 tasklist->priv->sn_context =
1748 sn_monitor_context_new (_vnck_screen_get_sn_display (tasklist->priv->screen),
1749 vnck_screen_get_number (tasklist->priv->screen),
1750 vnck_tasklist_sn_event,
1751 tasklist,
1752 NULL((void*)0));
1753#endif
1754
1755 (* CTK_WIDGET_CLASS (vnck_tasklist_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((vnck_tasklist_parent_class)), ((ctk_widget_get_type ()))
))))
->realize) (widget);
1756
1757 tasklist_instances = g_slist_append (tasklist_instances, tasklist);
1758 g_slist_foreach (tasklist_instances, (GFunc) foreach_tasklist, NULL((void*)0));
1759
1760 vnck_tasklist_update_lists (tasklist);
1761
1762 vnck_tasklist_connect_screen (tasklist);
1763}
1764
1765static void
1766vnck_tasklist_unrealize (CtkWidget *widget)
1767{
1768 VnckTasklist *tasklist;
1769
1770 tasklist = VNCK_TASKLIST (widget)((((VnckTasklist*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((vnck_tasklist_get_type ()))))))
;
1771
1772 vnck_tasklist_disconnect_screen (tasklist);
1773 tasklist->priv->screen = NULL((void*)0);
1774
1775#ifdef HAVE_STARTUP_NOTIFICATION1
1776 sn_monitor_context_unref (tasklist->priv->sn_context);
1777 tasklist->priv->sn_context = NULL((void*)0);
1778#endif
1779
1780 (* CTK_WIDGET_CLASS (vnck_tasklist_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((vnck_tasklist_parent_class)), ((ctk_widget_get_type ()))
))))
->unrealize) (widget);
1781
1782 tasklist_instances = g_slist_remove (tasklist_instances, tasklist);
1783 g_slist_foreach (tasklist_instances, (GFunc) foreach_tasklist, NULL((void*)0));
1784}
1785
1786static void
1787vnck_tasklist_forall (CtkContainer *container,
1788 gboolean include_internals G_GNUC_UNUSED__attribute__ ((__unused__)),
1789 CtkCallback callback,
1790 gpointer callback_data)
1791{
1792 VnckTasklist *tasklist;
1793 GList *tmp;
1794
1795 tasklist = VNCK_TASKLIST (container)((((VnckTasklist*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((vnck_tasklist_get_type ()))))))
;
1796
1797 tmp = tasklist->priv->windows;
1798 while (tmp != NULL((void*)0))
1799 {
1800 VnckTask *task = VNCK_TASK (tmp->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tmp->data)), ((vnck_task_get_type ()))))))
;
1801 tmp = tmp->next;
1802
1803 (* callback) (task->button, callback_data);
1804 }
1805
1806 tmp = tasklist->priv->class_groups;
1807 while (tmp != NULL((void*)0))
1808 {
1809 VnckTask *task = VNCK_TASK (tmp->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tmp->data)), ((vnck_task_get_type ()))))))
;
1810 tmp = tmp->next;
1811
1812 (* callback) (task->button, callback_data);
1813 }
1814
1815 tmp = tasklist->priv->startup_sequences;
1816 while (tmp != NULL((void*)0))
1817 {
1818 VnckTask *task = VNCK_TASK (tmp->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tmp->data)), ((vnck_task_get_type ()))))))
;
1819 tmp = tmp->next;
1820
1821 (* callback) (task->button, callback_data);
1822 }
1823}
1824
1825static void
1826vnck_tasklist_remove (CtkContainer *container,
1827 CtkWidget *widget)
1828{
1829 VnckTasklist *tasklist;
1830 GList *tmp;
1831
1832 g_return_if_fail (VNCK_IS_TASKLIST (container))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((container)); GType __t = ((vnck_tasklist_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Vnck", ((const char*) (__func__
)), "VNCK_IS_TASKLIST (container)"); return; } } while (0)
;
1833 g_return_if_fail (widget != NULL)do { if ((widget != ((void*)0))) { } else { g_return_if_fail_warning
("Vnck", ((const char*) (__func__)), "widget != NULL"); return
; } } while (0)
;
1834
1835 tasklist = VNCK_TASKLIST (container)((((VnckTasklist*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((vnck_tasklist_get_type ()))))))
;
1836
1837 /* it's safer to handle windows_without_class_group before windows */
1838 tmp = tasklist->priv->windows_without_class_group;
1839 while (tmp != NULL((void*)0))
1840 {
1841 VnckTask *task = VNCK_TASK (tmp->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tmp->data)), ((vnck_task_get_type ()))))))
;
1842 tmp = tmp->next;
1843
1844 if (task->button == widget)
1845 {
1846 tasklist->priv->windows_without_class_group =
1847 g_list_remove (tasklist->priv->windows_without_class_group,
1848 task);
1849 g_object_unref (task);
1850 break;
1851 }
1852 }
1853
1854 tmp = tasklist->priv->windows;
1855 while (tmp != NULL((void*)0))
1856 {
1857 VnckTask *task = VNCK_TASK (tmp->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tmp->data)), ((vnck_task_get_type ()))))))
;
1858 tmp = tmp->next;
1859
1860 if (task->button == widget)
1861 {
1862 g_hash_table_remove (tasklist->priv->win_hash,
1863 task->window);
1864 tasklist->priv->windows =
1865 g_list_remove (tasklist->priv->windows,
1866 task);
1867
1868 ctk_widget_unparent (widget);
1869 g_object_unref (task);
1870 break;
1871 }
1872 }
1873
1874 tmp = tasklist->priv->class_groups;
1875 while (tmp != NULL((void*)0))
1876 {
1877 VnckTask *task = VNCK_TASK (tmp->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tmp->data)), ((vnck_task_get_type ()))))))
;
1878 tmp = tmp->next;
1879
1880 if (task->button == widget)
1881 {
1882 g_hash_table_remove (tasklist->priv->class_group_hash,
1883 task->class_group);
1884 tasklist->priv->class_groups =
1885 g_list_remove (tasklist->priv->class_groups,
1886 task);
1887
1888 ctk_widget_unparent (widget);
1889 g_object_unref (task);
1890 break;
1891 }
1892 }
1893
1894 tmp = tasklist->priv->startup_sequences;
1895 while (tmp != NULL((void*)0))
1896 {
1897 VnckTask *task = VNCK_TASK (tmp->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tmp->data)), ((vnck_task_get_type ()))))))
;
1898 tmp = tmp->next;
1899
1900 if (task->button == widget)
1901 {
1902 tasklist->priv->startup_sequences =
1903 g_list_remove (tasklist->priv->startup_sequences,
1904 task);
1905
1906 ctk_widget_unparent (widget);
1907 g_object_unref (task);
1908 break;
1909 }
1910 }
1911
1912 ctk_widget_queue_resize (CTK_WIDGET (container)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_widget_get_type ()))))))
);
1913}
1914
1915static void
1916vnck_tasklist_connect_screen (VnckTasklist *tasklist)
1917{
1918 GList *windows;
1919 guint *c;
1920 int i;
1921 VnckScreen *screen;
1922
1923 g_return_if_fail (tasklist->priv->screen != NULL)do { if ((tasklist->priv->screen != ((void*)0))) { } else
{ g_return_if_fail_warning ("Vnck", ((const char*) (__func__
)), "tasklist->priv->screen != NULL"); return; } } while
(0)
;
1924
1925 screen = tasklist->priv->screen;
1926
1927 i = 0;
1928 c = tasklist->priv->screen_connections;
1929
1930 c [i++] = g_signal_connect_object (G_OBJECT (screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((screen)), (((GType) ((20) << (2))))))))
, "active_window_changed",
1931 G_CALLBACK (vnck_tasklist_active_window_changed)((GCallback) (vnck_tasklist_active_window_changed)),
1932 tasklist, 0);
1933 c [i++] = g_signal_connect_object (G_OBJECT (screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((screen)), (((GType) ((20) << (2))))))))
, "active_workspace_changed",
1934 G_CALLBACK (vnck_tasklist_active_workspace_changed)((GCallback) (vnck_tasklist_active_workspace_changed)),
1935 tasklist, 0);
1936 c [i++] = g_signal_connect_object (G_OBJECT (screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((screen)), (((GType) ((20) << (2))))))))
, "window_opened",
1937 G_CALLBACK (vnck_tasklist_window_added)((GCallback) (vnck_tasklist_window_added)),
1938 tasklist, 0);
1939 c [i++] = g_signal_connect_object (G_OBJECT (screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((screen)), (((GType) ((20) << (2))))))))
, "window_closed",
1940 G_CALLBACK (vnck_tasklist_window_removed)((GCallback) (vnck_tasklist_window_removed)),
1941 tasklist, 0);
1942 c [i++] = g_signal_connect_object (G_OBJECT (screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((screen)), (((GType) ((20) << (2))))))))
, "viewports_changed",
1943 G_CALLBACK (vnck_tasklist_viewports_changed)((GCallback) (vnck_tasklist_viewports_changed)),
1944 tasklist, 0);
1945
1946
1947 g_assert (i == N_SCREEN_CONNECTIONS)do { if (i == 5) ; else g_assertion_message_expr ("Vnck", "../libvnck/tasklist.c"
, 1947, ((const char*) (__func__)), "i == N_SCREEN_CONNECTIONS"
); } while (0)
;
1948
1949 windows = vnck_screen_get_windows (screen);
1950 while (windows != NULL((void*)0))
1951 {
1952 vnck_tasklist_connect_window (tasklist, windows->data);
1953 windows = windows->next;
1954 }
1955}
1956
1957static void
1958vnck_tasklist_disconnect_screen (VnckTasklist *tasklist)
1959{
1960 GList *windows;
1961 int i;
1962
1963 windows = vnck_screen_get_windows (tasklist->priv->screen);
1964 while (windows != NULL((void*)0))
1965 {
1966 vnck_tasklist_disconnect_window (tasklist, windows->data);
1967 windows = windows->next;
1968 }
1969
1970 i = 0;
1971 while (i < N_SCREEN_CONNECTIONS5)
1972 {
1973 if (tasklist->priv->screen_connections [i] != 0)
1974 g_signal_handler_disconnect (G_OBJECT (tasklist->priv->screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist->priv->screen)), (((GType) ((20) <<
(2))))))))
,
1975 tasklist->priv->screen_connections [i]);
1976
1977 tasklist->priv->screen_connections [i] = 0;
1978
1979 ++i;
1980 }
1981
1982 g_assert (i == N_SCREEN_CONNECTIONS)do { if (i == 5) ; else g_assertion_message_expr ("Vnck", "../libvnck/tasklist.c"
, 1982, ((const char*) (__func__)), "i == N_SCREEN_CONNECTIONS"
); } while (0)
;
1983
1984#ifdef HAVE_STARTUP_NOTIFICATION1
1985 if (tasklist->priv->startup_sequence_timeout != 0)
1986 {
1987 g_source_remove (tasklist->priv->startup_sequence_timeout);
1988 tasklist->priv->startup_sequence_timeout = 0;
1989 }
1990#endif
1991}
1992
1993static gboolean
1994vnck_tasklist_scroll_event (CtkWidget *widget,
1995 CdkEventScroll *event)
1996{
1997 /* use the fact that tasklist->priv->windows is sorted
1998 * see vnck_tasklist_size_allocate() */
1999 VnckTasklist *tasklist;
2000 CtkTextDirection ltr;
2001 GList *window;
2002 gint row = 0;
2003 gint col = 0;
2004
2005 tasklist = VNCK_TASKLIST (widget)((((VnckTasklist*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((vnck_tasklist_get_type ()))))))
;
2006
2007 if (!tasklist->priv->scroll_enabled)
2008 return FALSE(0);
2009
2010 window = g_list_find (tasklist->priv->windows,
2011 tasklist->priv->active_task);
2012 if (window)
2013 {
2014 row = VNCK_TASK (window->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window->data)), ((vnck_task_get_type ()))))))
->row;
2015 col = VNCK_TASK (window->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window->data)), ((vnck_task_get_type ()))))))
->col;
2016 }
2017 else
2018 if (tasklist->priv->activate_timeout_id)
2019 /* There is no active_task yet, but there will be one after the timeout.
2020 * It occurs if we change the active task too fast. */
2021 return TRUE(!(0));
2022
2023 ltr = (ctk_widget_get_direction (CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
) != CTK_TEXT_DIR_RTL);
2024
2025 switch (event->direction)
2026 {
2027 case CDK_SCROLL_UP:
2028 if (!window)
2029 window = g_list_last (tasklist->priv->windows);
2030 else
2031 window = window->prev;
2032 break;
2033
2034 case CDK_SCROLL_DOWN:
2035 if (!window)
2036 window = tasklist->priv->windows;
2037 else
2038 window = window->next;
2039 break;
2040
2041#define TASKLIST_GET_MOST_LEFT(ltr, window, tasklist) \
2042 do \
2043 { \
2044 if (ltr) \
2045 window = tasklist->priv->windows; \
2046 else \
2047 window = g_list_last (tasklist->priv->windows); \
2048 } while (0)
2049
2050#define TASKLIST_GET_MOST_RIGHT(ltr, window, tasklist) \
2051 do \
2052 { \
2053 if (ltr) \
2054 window = g_list_last (tasklist->priv->windows); \
2055 else \
2056 window = tasklist->priv->windows; \
2057 } while (0)
2058
2059 case CDK_SCROLL_LEFT:
2060 if (!window)
2061 TASKLIST_GET_MOST_RIGHT (ltr, window, tasklist);
2062 else
2063 {
2064 /* Search the first window on the previous colomn at same row */
2065 if (ltr)
2066 {
2067 while (window && (VNCK_TASK(window->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window->data)), ((vnck_task_get_type ()))))))
->row != row ||
2068 VNCK_TASK(window->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window->data)), ((vnck_task_get_type ()))))))
->col != col-1))
2069 window = window->prev;
2070 }
2071 else
2072 {
2073 while (window && (VNCK_TASK(window->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window->data)), ((vnck_task_get_type ()))))))
->row != row ||
2074 VNCK_TASK(window->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window->data)), ((vnck_task_get_type ()))))))
->col != col-1))
2075 window = window->next;
2076 }
2077 /* If no window found, select the top/bottom left one */
2078 if (!window)
2079 TASKLIST_GET_MOST_LEFT (ltr, window, tasklist);
2080 }
2081 break;
2082
2083 case CDK_SCROLL_RIGHT:
2084 if (!window)
2085 TASKLIST_GET_MOST_LEFT (ltr, window, tasklist);
2086 else
2087 {
2088 /* Search the first window on the next colomn at same row */
2089 if (ltr)
2090 {
2091 while (window && (VNCK_TASK(window->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window->data)), ((vnck_task_get_type ()))))))
->row != row ||
2092 VNCK_TASK(window->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window->data)), ((vnck_task_get_type ()))))))
->col != col+1))
2093 window = window->next;
2094 }
2095 else
2096 {
2097 while (window && (VNCK_TASK(window->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window->data)), ((vnck_task_get_type ()))))))
->row != row ||
2098 VNCK_TASK(window->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window->data)), ((vnck_task_get_type ()))))))
->col != col+1))
2099 window = window->prev;
2100 }
2101 /* If no window found, select the top/bottom right one */
2102 if (!window)
2103 TASKLIST_GET_MOST_RIGHT (ltr, window, tasklist);
2104 }
2105 break;
2106
2107 case CDK_SCROLL_SMOOTH:
2108 window = NULL((void*)0);
2109 break;
2110
2111#undef TASKLIST_GET_MOST_LEFT
2112#undef TASKLIST_GET_MOST_RIGHT
2113
2114 default:
2115 g_assert_not_reached ()do { g_assertion_message_expr ("Vnck", "../libvnck/tasklist.c"
, 2115, ((const char*) (__func__)), ((void*)0)); } while (0)
;
2116 }
2117
2118 if (window)
2119 vnck_tasklist_activate_task_window (window->data, event->time);
2120
2121 return TRUE(!(0));
2122}
2123
2124/**
2125 * vnck_tasklist_new:
2126 *
2127 * Creates a new #VnckTasklist. The #VnckTasklist will list #VnckWindow of the
2128 * #VnckScreen it is on.
2129 *
2130 * Return value: a newly created #VnckTasklist.
2131 */
2132CtkWidget*
2133vnck_tasklist_new (void)
2134{
2135 VnckTasklist *tasklist;
2136
2137 tasklist = g_object_new (VNCK_TYPE_TASKLIST(vnck_tasklist_get_type ()), NULL((void*)0));
2138
2139 return CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
;
2140}
2141
2142static void
2143vnck_tasklist_free_tasks (VnckTasklist *tasklist)
2144{
2145 GList *l;
2146
2147 tasklist->priv->active_task = NULL((void*)0);
2148 tasklist->priv->active_class_group = NULL((void*)0);
2149
2150 if (tasklist->priv->windows)
2151 {
2152 l = tasklist->priv->windows;
2153 while (l != NULL((void*)0))
2154 {
2155 VnckTask *task = VNCK_TASK (l->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_task_get_type ()))))))
;
2156 l = l->next;
2157 /* if we just unref the task it means we lose our ref to the
2158 * task before we unparent the button, which breaks stuff.
2159 */
2160 ctk_widget_destroy (task->button);
2161 }
2162 }
2163 g_assert (tasklist->priv->windows == NULL)do { if (tasklist->priv->windows == ((void*)0)) ; else g_assertion_message_expr
("Vnck", "../libvnck/tasklist.c", 2163, ((const char*) (__func__
)), "tasklist->priv->windows == NULL"); } while (0)
;
2164 g_assert (tasklist->priv->windows_without_class_group == NULL)do { if (tasklist->priv->windows_without_class_group ==
((void*)0)) ; else g_assertion_message_expr ("Vnck", "../libvnck/tasklist.c"
, 2164, ((const char*) (__func__)), "tasklist->priv->windows_without_class_group == NULL"
); } while (0)
;
2165 g_assert (g_hash_table_size (tasklist->priv->win_hash) == 0)do { if (g_hash_table_size (tasklist->priv->win_hash) ==
0) ; else g_assertion_message_expr ("Vnck", "../libvnck/tasklist.c"
, 2165, ((const char*) (__func__)), "g_hash_table_size (tasklist->priv->win_hash) == 0"
); } while (0)
;
2166
2167 if (tasklist->priv->class_groups)
2168 {
2169 l = tasklist->priv->class_groups;
2170 while (l != NULL((void*)0))
2171 {
2172 VnckTask *task = VNCK_TASK (l->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_task_get_type ()))))))
;
2173 l = l->next;
2174 /* if we just unref the task it means we lose our ref to the
2175 * task before we unparent the button, which breaks stuff.
2176 */
2177 ctk_widget_destroy (task->button);
2178 }
2179 }
2180
2181 g_assert (tasklist->priv->class_groups == NULL)do { if (tasklist->priv->class_groups == ((void*)0)) ; else
g_assertion_message_expr ("Vnck", "../libvnck/tasklist.c", 2181
, ((const char*) (__func__)), "tasklist->priv->class_groups == NULL"
); } while (0)
;
2182 g_assert (g_hash_table_size (tasklist->priv->class_group_hash) == 0)do { if (g_hash_table_size (tasklist->priv->class_group_hash
) == 0) ; else g_assertion_message_expr ("Vnck", "../libvnck/tasklist.c"
, 2182, ((const char*) (__func__)), "g_hash_table_size (tasklist->priv->class_group_hash) == 0"
); } while (0)
;
2183
2184 if (tasklist->priv->skipped_windows)
2185 {
2186 vnck_tasklist_free_skipped_windows (tasklist);
2187 tasklist->priv->skipped_windows = NULL((void*)0);
2188 }
2189}
2190
2191
2192/*
2193 * This function determines if a window should be included in the tasklist.
2194 */
2195static gboolean
2196tasklist_include_window_impl (VnckTasklist *tasklist,
2197 VnckWindow *win,
2198 gboolean check_for_skipped_list)
2199{
2200 VnckWorkspace *active_workspace;
2201 int x, y, w, h;
2202
2203 if (!check_for_skipped_list &&
2204 vnck_window_get_state (win) & VNCK_WINDOW_STATE_SKIP_TASKLIST)
2205 return FALSE(0);
2206
2207 if (tasklist->priv->monitor != NULL((void*)0))
2208 {
2209 CdkDisplay *display;
2210 CdkMonitor *monitor;
2211
2212 vnck_window_get_geometry (win, &x, &y, &w, &h);
2213
2214 /* Don't include the window if its center point is not on the same monitor */
2215
2216 display = cdk_display_get_default ();
2217 monitor = cdk_display_get_monitor_at_point (display, x + w / 2, y + h / 2);
2218
2219 if (monitor != tasklist->priv->monitor)
2220 return FALSE(0);
2221 }
2222
2223 /* Remainder of checks aren't relevant for checking if the window should
2224 * be in the skipped list.
2225 */
2226 if (check_for_skipped_list)
2227 return TRUE(!(0));
2228
2229 if (tasklist->priv->include_all_workspaces)
2230 return TRUE(!(0));
2231
2232 if (vnck_window_is_pinned (win))
2233 return TRUE(!(0));
2234
2235 active_workspace = vnck_screen_get_active_workspace (tasklist->priv->screen);
2236 if (active_workspace == NULL((void*)0))
2237 return TRUE(!(0));
2238
2239 if (vnck_window_or_transient_needs_attention (win))
2240 return TRUE(!(0));
2241
2242 if (active_workspace != vnck_window_get_workspace (win))
2243 return FALSE(0);
2244
2245 if (!vnck_workspace_is_virtual (active_workspace))
2246 return TRUE(!(0));
2247
2248 return vnck_window_is_in_viewport (win, active_workspace);
2249}
2250
2251static gboolean
2252tasklist_include_in_skipped_list (VnckTasklist *tasklist, VnckWindow *win)
2253{
2254 return tasklist_include_window_impl (tasklist,
2255 win,
2256 TRUE(!(0)) /* check_for_skipped_list */);
2257}
2258
2259static gboolean
2260vnck_tasklist_include_window (VnckTasklist *tasklist, VnckWindow *win)
2261{
2262 return tasklist_include_window_impl (tasklist,
2263 win,
2264 FALSE(0) /* check_for_skipped_list */);
2265}
2266
2267static void
2268vnck_tasklist_update_lists (VnckTasklist *tasklist)
2269{
2270 CdkWindow *tasklist_window;
2271 GList *windows;
2272 VnckWindow *win;
2273 VnckClassGroup *class_group;
2274 GList *l;
2275 VnckTask *win_task;
2276 VnckTask *class_group_task;
2277
2278 vnck_tasklist_free_tasks (tasklist);
2279
2280 /* vnck_tasklist_update_lists() will be called on realize */
2281 if (!ctk_widget_get_realized (CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
))
2282 return;
2283
2284 tasklist_window = ctk_widget_get_window (CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
);
2285
2286 if (tasklist_window != NULL((void*)0))
2287 {
2288 /*
2289 * only show windows from this monitor if there is more than one tasklist running
2290 */
2291 if (tasklist_instances == NULL((void*)0) || tasklist_instances->next == NULL((void*)0))
2292 {
2293 tasklist->priv->monitor = NULL((void*)0);
2294 }
2295 else
2296 {
2297 CdkDisplay *display;
2298 CdkMonitor *monitor;
2299
2300 display = cdk_display_get_default ();
2301 monitor = cdk_display_get_monitor_at_window (display, tasklist_window);
2302
2303 if (monitor != tasklist->priv->monitor)
2304 {
2305 tasklist->priv->monitor = monitor;
2306 cdk_monitor_get_geometry (monitor, &tasklist->priv->monitor_geometry);
2307 }
2308 }
2309 }
2310
2311 l = windows = vnck_screen_get_windows (tasklist->priv->screen);
Although the value stored to 'windows' is used in the enclosing expression, the value is never actually read from 'windows'
2312 while (l != NULL((void*)0))
2313 {
2314 win = VNCK_WINDOW (l->data)((((VnckWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_window_get_type ()))))))
;
2315
2316 if (vnck_tasklist_include_window (tasklist, win))
2317 {
2318 win_task = vnck_task_new_from_window (tasklist, win);
2319 tasklist->priv->windows = g_list_prepend (tasklist->priv->windows, win_task);
2320 g_hash_table_insert (tasklist->priv->win_hash, win, win_task);
2321
2322 ctk_widget_set_parent (win_task->button, CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
);
2323 ctk_widget_show (win_task->button);
2324
2325 /* Class group */
2326
2327 class_group = vnck_window_get_class_group (win);
2328 /* don't group windows if they do not belong to any class */
2329 if (strcmp (vnck_class_group_get_id (class_group), "") != 0)
2330 {
2331 class_group_task =
2332 g_hash_table_lookup (tasklist->priv->class_group_hash,
2333 class_group);
2334
2335 if (class_group_task == NULL((void*)0))
2336 {
2337 class_group_task =
2338 vnck_task_new_from_class_group (tasklist,
2339 class_group);
2340 ctk_widget_set_parent (class_group_task->button,
2341 CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
);
2342 ctk_widget_show (class_group_task->button);
2343
2344 tasklist->priv->class_groups =
2345 g_list_prepend (tasklist->priv->class_groups,
2346 class_group_task);
2347 g_hash_table_insert (tasklist->priv->class_group_hash,
2348 class_group, class_group_task);
2349 }
2350
2351 class_group_task->windows =
2352 g_list_prepend (class_group_task->windows,
2353 win_task);
2354 }
2355 else
2356 {
2357 g_object_ref (win_task)((__typeof__ (win_task)) (g_object_ref) (win_task));
2358 tasklist->priv->windows_without_class_group =
2359 g_list_prepend (tasklist->priv->windows_without_class_group,
2360 win_task);
2361 }
2362 }
2363 else if (tasklist_include_in_skipped_list (tasklist, win))
2364 {
2365 skipped_window *skipped = g_new0 (skipped_window, 1)((skipped_window *) g_malloc0_n ((1), sizeof (skipped_window)
))
;
2366 skipped->window = g_object_ref (win)((__typeof__ (win)) (g_object_ref) (win));
2367 skipped->tag = g_signal_connect (G_OBJECT (win),g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((win)), (((GType) ((20) << (2))))))
))), ("state_changed"), (((GCallback) (vnck_task_state_changed
))), (tasklist), ((void*)0), (GConnectFlags) 0)
2368 "state_changed",g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((win)), (((GType) ((20) << (2))))))
))), ("state_changed"), (((GCallback) (vnck_task_state_changed
))), (tasklist), ((void*)0), (GConnectFlags) 0)
2369 G_CALLBACK (vnck_task_state_changed),g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((win)), (((GType) ((20) << (2))))))
))), ("state_changed"), (((GCallback) (vnck_task_state_changed
))), (tasklist), ((void*)0), (GConnectFlags) 0)
2370 tasklist)g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((win)), (((GType) ((20) << (2))))))
))), ("state_changed"), (((GCallback) (vnck_task_state_changed
))), (tasklist), ((void*)0), (GConnectFlags) 0)
;
2371 tasklist->priv->skipped_windows =
2372 g_list_prepend (tasklist->priv->skipped_windows,
2373 (gpointer) skipped);
2374 }
2375
2376 l = l->next;
2377 }
2378
2379 /* Sort the class group list */
2380 l = tasklist->priv->class_groups;
2381 while (l)
2382 {
2383 class_group_task = VNCK_TASK (l->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_task_get_type ()))))))
;
2384
2385 class_group_task->windows = g_list_sort (class_group_task->windows, vnck_task_compare);
2386
2387 /* so the number of windows in the task gets reset on the
2388 * task label
2389 */
2390 vnck_task_update_visible_state (class_group_task);
2391
2392 l = l->next;
2393 }
2394
2395 /* since we cleared active_window we need to reset it */
2396 vnck_tasklist_active_window_changed (tasklist->priv->screen, NULL((void*)0), tasklist);
2397
2398 ctk_widget_queue_resize (CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
);
2399}
2400
2401static void
2402vnck_tasklist_change_active_task (VnckTasklist *tasklist, VnckTask *active_task)
2403{
2404 if (active_task &&
2405 active_task == tasklist->priv->active_task)
2406 return;
2407
2408 g_assert (active_task == NULL ||do { if (active_task == ((void*)0) || active_task->type !=
VNCK_TASK_STARTUP_SEQUENCE) ; else g_assertion_message_expr (
"Vnck", "../libvnck/tasklist.c", 2409, ((const char*) (__func__
)), "active_task == NULL || active_task->type != VNCK_TASK_STARTUP_SEQUENCE"
); } while (0)
2409 active_task->type != VNCK_TASK_STARTUP_SEQUENCE)do { if (active_task == ((void*)0) || active_task->type !=
VNCK_TASK_STARTUP_SEQUENCE) ; else g_assertion_message_expr (
"Vnck", "../libvnck/tasklist.c", 2409, ((const char*) (__func__
)), "active_task == NULL || active_task->type != VNCK_TASK_STARTUP_SEQUENCE"
); } while (0)
;
2410
2411 if (tasklist->priv->active_task)
2412 {
2413 tasklist->priv->active_task->really_toggling = TRUE(!(0));
2414 ctk_toggle_button_set_active (CTK_TOGGLE_BUTTON (tasklist->priv->active_task->button)((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist->priv->active_task->button)), ((ctk_toggle_button_get_type
()))))))
,
2415 FALSE(0));
2416 tasklist->priv->active_task->really_toggling = FALSE(0);
2417 }
2418
2419 tasklist->priv->active_task = active_task;
2420
2421 if (tasklist->priv->active_task)
2422 {
2423 tasklist->priv->active_task->really_toggling = TRUE(!(0));
2424 ctk_toggle_button_set_active (CTK_TOGGLE_BUTTON (tasklist->priv->active_task->button)((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist->priv->active_task->button)), ((ctk_toggle_button_get_type
()))))))
,
2425 TRUE(!(0)));
2426 tasklist->priv->active_task->really_toggling = FALSE(0);
2427 }
2428
2429 if (active_task)
2430 {
2431 active_task = g_hash_table_lookup (tasklist->priv->class_group_hash,
2432 active_task->class_group);
2433
2434 if (active_task &&
2435 active_task == tasklist->priv->active_class_group)
2436 return;
2437
2438 if (tasklist->priv->active_class_group)
2439 {
2440 tasklist->priv->active_class_group->really_toggling = TRUE(!(0));
2441 ctk_toggle_button_set_active (CTK_TOGGLE_BUTTON (tasklist->priv->active_class_group->button)((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist->priv->active_class_group->button)), (
(ctk_toggle_button_get_type ()))))))
,
2442 FALSE(0));
2443 tasklist->priv->active_class_group->really_toggling = FALSE(0);
2444 }
2445
2446 tasklist->priv->active_class_group = active_task;
2447
2448 if (tasklist->priv->active_class_group)
2449 {
2450 tasklist->priv->active_class_group->really_toggling = TRUE(!(0));
2451 ctk_toggle_button_set_active (CTK_TOGGLE_BUTTON (tasklist->priv->active_class_group->button)((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist->priv->active_class_group->button)), (
(ctk_toggle_button_get_type ()))))))
,
2452 TRUE(!(0)));
2453 tasklist->priv->active_class_group->really_toggling = FALSE(0);
2454 }
2455 }
2456}
2457
2458static void
2459vnck_tasklist_update_icon_geometries (VnckTasklist *tasklist G_GNUC_UNUSED__attribute__ ((__unused__)),
2460 GList *visible_tasks)
2461{
2462 gint x, y, width, height;
2463 GList *l1;
2464
2465 for (l1 = visible_tasks; l1; l1 = l1->next) {
2466 VnckTask *task = VNCK_TASK (l1->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l1->data)), ((vnck_task_get_type ()))))))
;
2467 CtkAllocation allocation;
2468
2469 if (!ctk_widget_get_realized (task->button))
2470 continue;
2471
2472 /* Let's cheat with some internal knowledge of CtkButton: in a
2473 * CtkButton, the window is the same as the parent window. So
2474 * to know the position of the widget, we should use the
2475 * the position of the parent window and the allocation information. */
2476
2477 ctk_widget_get_allocation (task->button, &allocation);
2478
2479 cdk_window_get_origin (ctk_widget_get_parent_window (task->button),
2480 &x, &y);
2481
2482 x += allocation.x;
2483 y += allocation.y;
2484 width = allocation.width;
2485 height = allocation.height;
2486
2487 if (task->window)
2488 vnck_window_set_icon_geometry (task->window,
2489 x, y, width, height);
2490 else {
2491 GList *l2;
2492
2493 for (l2 = task->windows; l2; l2 = l2->next) {
2494 VnckTask *win_task = VNCK_TASK (l2->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l2->data)), ((vnck_task_get_type ()))))))
;
2495
2496 g_assert (win_task->window)do { if (win_task->window) ; else g_assertion_message_expr
("Vnck", "../libvnck/tasklist.c", 2496, ((const char*) (__func__
)), "win_task->window"); } while (0)
;
2497
2498 vnck_window_set_icon_geometry (win_task->window,
2499 x, y, width, height);
2500 }
2501 }
2502 }
2503}
2504
2505static void
2506vnck_tasklist_active_window_changed (VnckScreen *screen,
2507 VnckWindow *previous_window G_GNUC_UNUSED__attribute__ ((__unused__)),
2508 VnckTasklist *tasklist)
2509{
2510 VnckWindow *active_window;
2511 VnckWindow *initial_window;
2512 VnckTask *active_task = NULL((void*)0);
2513
2514 /* FIXME: check for group modal window */
2515 initial_window = active_window = vnck_screen_get_active_window (screen);
2516 active_task = g_hash_table_lookup (tasklist->priv->win_hash, active_window);
2517 while (active_window && !active_task)
2518 {
2519 active_window = vnck_window_get_transient (active_window);
2520 active_task = g_hash_table_lookup (tasklist->priv->win_hash,
2521 active_window);
2522 /* Check for transient cycles */
2523 if (active_window == initial_window)
2524 break;
2525 }
2526
2527 vnck_tasklist_change_active_task (tasklist, active_task);
2528}
2529
2530static void
2531vnck_tasklist_active_workspace_changed (VnckScreen *screen G_GNUC_UNUSED__attribute__ ((__unused__)),
2532 VnckWorkspace *previous_workspace G_GNUC_UNUSED__attribute__ ((__unused__)),
2533 VnckTasklist *tasklist)
2534{
2535 vnck_tasklist_update_lists (tasklist);
2536 ctk_widget_queue_resize (CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
);
2537}
2538
2539static void
2540vnck_tasklist_window_changed_workspace (VnckWindow *window,
2541 VnckTasklist *tasklist)
2542{
2543 VnckWorkspace *active_ws;
2544 VnckWorkspace *window_ws;
2545 gboolean need_update;
2546 GList *l;
2547
2548 active_ws = vnck_screen_get_active_workspace (tasklist->priv->screen);
2549 window_ws = vnck_window_get_workspace (window);
2550
2551 if (!window_ws)
2552 return;
2553
2554 need_update = FALSE(0);
2555
2556 if (active_ws == window_ws)
2557 need_update = TRUE(!(0));
2558
2559 l = tasklist->priv->windows;
2560 while (!need_update && l != NULL((void*)0))
2561 {
2562 VnckTask *task = l->data;
2563
2564 if (task->type == VNCK_TASK_WINDOW &&
2565 task->window == window)
2566 need_update = TRUE(!(0));
2567
2568 l = l->next;
2569 }
2570
2571 if (need_update)
2572 {
2573 vnck_tasklist_update_lists (tasklist);
2574 ctk_widget_queue_resize (CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
);
2575 }
2576}
2577
2578static gboolean
2579do_vnck_tasklist_update_lists (gpointer data)
2580{
2581 VnckTasklist *tasklist = VNCK_TASKLIST (data)((((VnckTasklist*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((vnck_tasklist_get_type ()))))))
;
2582
2583 tasklist->priv->idle_callback_tag = 0;
2584
2585 vnck_tasklist_update_lists (tasklist);
2586
2587 return FALSE(0);
2588}
2589
2590static void
2591vnck_tasklist_window_changed_geometry (VnckWindow *window,
2592 VnckTasklist *tasklist)
2593{
2594 CdkWindow *tasklist_window;
2595 VnckTask *win_task;
2596 gboolean show;
2597 gboolean monitor_changed;
2598 int x, y, w, h;
2599
2600 if (tasklist->priv->idle_callback_tag != 0)
2601 return;
2602
2603 tasklist_window = ctk_widget_get_window (CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
);
2604
2605 /*
2606 * If the (parent of the) tasklist itself skips
2607 * the tasklist, we need an extra check whether
2608 * the tasklist itself possibly changed monitor.
2609 */
2610 monitor_changed = FALSE(0);
2611 if (tasklist->priv->monitor != NULL((void*)0) &&
2612 (vnck_window_get_state (window) & VNCK_WINDOW_STATE_SKIP_TASKLIST) &&
2613 tasklist_window != NULL((void*)0))
2614 {
2615 /* Do the extra check only if there is a suspect of a monitor change (= this window is off monitor) */
2616 vnck_window_get_geometry (window, &x, &y, &w, &h);
2617 if (!POINT_IN_RECT (x + w / 2, y + h / 2, tasklist->priv->monitor_geometry)((x + w / 2) >= (tasklist->priv->monitor_geometry).x
&& (x + w / 2) < ((tasklist->priv->monitor_geometry
).x + (tasklist->priv->monitor_geometry).width) &&
(y + h / 2) >= (tasklist->priv->monitor_geometry).y
&& (y + h / 2) < ((tasklist->priv->monitor_geometry
).y + (tasklist->priv->monitor_geometry).height))
)
2618 {
2619 CdkDisplay *display;
2620 CdkMonitor *monitor;
2621
2622 display = cdk_display_get_default ();
2623 monitor = cdk_display_get_monitor_at_window (display, tasklist_window);
2624
2625 monitor_changed = (monitor != tasklist->priv->monitor);
2626 }
2627 }
2628
2629 /*
2630 * We want to re-generate the task list if
2631 * the window is shown but shouldn't be or
2632 * the window isn't shown but should be or
2633 * the tasklist itself changed monitor.
2634 */
2635 win_task = g_hash_table_lookup (tasklist->priv->win_hash, window);
2636 show = vnck_tasklist_include_window (tasklist, window);
2637 if (((win_task == NULL((void*)0) && !show) || (win_task != NULL((void*)0) && show)) &&
2638 !monitor_changed)
2639 return;
2640
2641 /* Don't keep any stale references */
2642 ctk_widget_queue_draw (CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
);
2643
2644 tasklist->priv->idle_callback_tag = g_idle_add (do_vnck_tasklist_update_lists, tasklist);
2645}
2646
2647static void
2648vnck_tasklist_connect_window (VnckTasklist *tasklist,
2649 VnckWindow *window)
2650{
2651 g_signal_connect_object (window, "workspace_changed",
2652 G_CALLBACK (vnck_tasklist_window_changed_workspace)((GCallback) (vnck_tasklist_window_changed_workspace)),
2653 tasklist, 0);
2654 g_signal_connect_object (window, "geometry_changed",
2655 G_CALLBACK (vnck_tasklist_window_changed_geometry)((GCallback) (vnck_tasklist_window_changed_geometry)),
2656 tasklist, 0);
2657}
2658
2659static void
2660vnck_tasklist_disconnect_window (VnckTasklist *tasklist,
2661 VnckWindow *window)
2662{
2663 g_signal_handlers_disconnect_by_func (window,g_signal_handlers_disconnect_matched ((window), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (vnck_tasklist_window_changed_workspace), (tasklist))
2664 vnck_tasklist_window_changed_workspace,g_signal_handlers_disconnect_matched ((window), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (vnck_tasklist_window_changed_workspace), (tasklist))
2665 tasklist)g_signal_handlers_disconnect_matched ((window), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (vnck_tasklist_window_changed_workspace), (tasklist))
;
2666 g_signal_handlers_disconnect_by_func (window,g_signal_handlers_disconnect_matched ((window), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (vnck_tasklist_window_changed_geometry), (tasklist))
2667 vnck_tasklist_window_changed_geometry,g_signal_handlers_disconnect_matched ((window), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (vnck_tasklist_window_changed_geometry), (tasklist))
2668 tasklist)g_signal_handlers_disconnect_matched ((window), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (vnck_tasklist_window_changed_geometry), (tasklist))
;
2669}
2670
2671static void
2672vnck_tasklist_window_added (VnckScreen *screen G_GNUC_UNUSED__attribute__ ((__unused__)),
2673 VnckWindow *win,
2674 VnckTasklist *tasklist)
2675{
2676#ifdef HAVE_STARTUP_NOTIFICATION1
2677 vnck_tasklist_check_end_sequence (tasklist, win);
2678#endif
2679
2680 vnck_tasklist_connect_window (tasklist, win);
2681
2682 vnck_tasklist_update_lists (tasklist);
2683 ctk_widget_queue_resize (CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
);
2684}
2685
2686static void
2687vnck_tasklist_window_removed (VnckScreen *screen G_GNUC_UNUSED__attribute__ ((__unused__)),
2688 VnckWindow *win G_GNUC_UNUSED__attribute__ ((__unused__)),
2689 VnckTasklist *tasklist)
2690{
2691 vnck_tasklist_update_lists (tasklist);
2692 ctk_widget_queue_resize (CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
);
2693}
2694
2695static void
2696vnck_tasklist_viewports_changed (VnckScreen *screen G_GNUC_UNUSED__attribute__ ((__unused__)),
2697 VnckTasklist *tasklist)
2698{
2699 vnck_tasklist_update_lists (tasklist);
2700 ctk_widget_queue_resize (CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
);
2701}
2702
2703static gboolean
2704vnck_tasklist_change_active_timeout (gpointer data)
2705{
2706 VnckTasklist *tasklist = VNCK_TASKLIST (data)((((VnckTasklist*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((vnck_tasklist_get_type ()))))))
;
2707
2708 tasklist->priv->activate_timeout_id = 0;
2709
2710 vnck_tasklist_active_window_changed (tasklist->priv->screen, NULL((void*)0), tasklist);
2711
2712 return FALSE(0);
2713}
2714
2715static void
2716vnck_task_menu_activated (CtkMenuItem *menu_item G_GNUC_UNUSED__attribute__ ((__unused__)),
2717 gpointer data)
2718{
2719 VnckTask *task = VNCK_TASK (data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((vnck_task_get_type ()))))))
;
2720
2721 /* This is an "activate" callback function so ctk_get_current_event_time()
2722 * will suffice.
2723 */
2724 vnck_tasklist_activate_task_window (task, ctk_get_current_event_time ());
2725}
2726
2727static void
2728vnck_tasklist_activate_next_in_class_group (VnckTask *task,
2729 guint32 timestamp)
2730{
2731 VnckTask *activate_task;
2732 gboolean activate_next;
2733 GList *l;
2734
2735 activate_task = NULL((void*)0);
2736 activate_next = FALSE(0);
2737
2738 l = task->windows;
2739 while (l)
2740 {
2741 VnckTask *tmp;
2742
2743 tmp = VNCK_TASK (l->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_task_get_type ()))))))
;
2744
2745 if (vnck_window_is_most_recently_activated (tmp->window))
2746 activate_next = TRUE(!(0));
2747 else if (activate_next)
2748 {
2749 activate_task = tmp;
2750 break;
2751 }
2752
2753 l = l->next;
2754 }
2755
2756 /* no task in this group is active, or only the last one => activate
2757 * the first task */
2758 if (!activate_task && task->windows)
2759 activate_task = VNCK_TASK (task->windows->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->windows->data)), ((vnck_task_get_type ()))))
))
;
2760
2761 if (activate_task)
2762 {
2763 task->was_active = FALSE(0);
2764 vnck_tasklist_activate_task_window (activate_task, timestamp);
2765 }
2766}
2767
2768static void
2769vnck_tasklist_activate_task_window (VnckTask *task,
2770 guint32 timestamp)
2771{
2772 VnckTasklist *tasklist;
2773 VnckWindowState state;
2774 VnckWorkspace *active_ws;
2775 VnckWorkspace *window_ws;
2776
2777 tasklist = task->tasklist;
2778
2779 if (task->window == NULL((void*)0))
2780 return;
2781
2782 state = vnck_window_get_state (task->window);
2783
2784 active_ws = vnck_screen_get_active_workspace (tasklist->priv->screen);
2785 window_ws = vnck_window_get_workspace (task->window);
2786
2787 if (state & VNCK_WINDOW_STATE_MINIMIZED)
2788 {
2789 if (window_ws &&
2790 active_ws != window_ws &&
2791 !tasklist->priv->switch_workspace_on_unminimize)
2792 vnck_workspace_activate (window_ws, timestamp);
2793
2794 vnck_window_activate_transient (task->window, timestamp);
2795 }
2796 else
2797 {
2798 if ((task->was_active ||
2799 vnck_window_transient_is_most_recently_activated (task->window)) &&
2800 (!window_ws || active_ws == window_ws))
2801 {
2802 task->was_active = FALSE(0);
2803 vnck_window_minimize (task->window);
2804 return;
2805 }
2806 else
2807 {
2808 /* FIXME: THIS IS SICK AND WRONG AND BUGGY. See the end of
2809 * http://mail.gnome.org/archives/wm-spec-list/2005-July/msg00032.html
2810 * There should only be *one* activate call.
2811 */
2812 if (window_ws)
2813 vnck_workspace_activate (window_ws, timestamp);
2814
2815 vnck_window_activate_transient (task->window, timestamp);
2816 }
2817 }
2818
2819
2820 if (tasklist->priv->activate_timeout_id)
2821 g_source_remove (tasklist->priv->activate_timeout_id);
2822
2823 tasklist->priv->activate_timeout_id =
2824 g_timeout_add (500, &vnck_tasklist_change_active_timeout, tasklist);
2825
2826 vnck_tasklist_change_active_task (tasklist, task);
2827}
2828
2829static void
2830vnck_task_close_all (CtkMenuItem *menu_item G_GNUC_UNUSED__attribute__ ((__unused__)),
2831 gpointer data)
2832{
2833 VnckTask *task = VNCK_TASK (data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((vnck_task_get_type ()))))))
;
2834 GList *l;
2835
2836 l = task->windows;
2837 while (l)
2838 {
2839 VnckTask *child = VNCK_TASK (l->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_task_get_type ()))))))
;
2840 vnck_window_close (child->window, ctk_get_current_event_time ());
2841 l = l->next;
2842 }
2843}
2844
2845static void
2846vnck_task_unminimize_all (CtkMenuItem *menu_item G_GNUC_UNUSED__attribute__ ((__unused__)),
2847 gpointer data)
2848{
2849 VnckTask *task = VNCK_TASK (data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((vnck_task_get_type ()))))))
;
2850 GList *l;
2851
2852 l = task->windows;
2853 while (l)
2854 {
2855 VnckTask *child = VNCK_TASK (l->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_task_get_type ()))))))
;
2856 /* This is inside an activate callback, so ctk_get_current_event_time()
2857 * will work.
2858 */
2859 vnck_window_unminimize (child->window, ctk_get_current_event_time ());
2860 l = l->next;
2861 }
2862}
2863
2864static void
2865vnck_task_minimize_all (CtkMenuItem *menu_item G_GNUC_UNUSED__attribute__ ((__unused__)),
2866 gpointer data)
2867{
2868 VnckTask *task = VNCK_TASK (data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((vnck_task_get_type ()))))))
;
2869 GList *l;
2870
2871 l = task->windows;
2872 while (l)
2873 {
2874 VnckTask *child = VNCK_TASK (l->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_task_get_type ()))))))
;
2875 vnck_window_minimize (child->window);
2876 l = l->next;
2877 }
2878}
2879
2880static void
2881vnck_task_unmaximize_all (CtkMenuItem *menu_item G_GNUC_UNUSED__attribute__ ((__unused__)),
2882 gpointer data)
2883{
2884 VnckTask *task = VNCK_TASK (data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((vnck_task_get_type ()))))))
;
2885 GList *l;
2886
2887 l = task->windows;
2888 while (l)
2889 {
2890 VnckTask *child = VNCK_TASK (l->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_task_get_type ()))))))
;
2891 vnck_window_unmaximize (child->window);
2892 l = l->next;
2893 }
2894}
2895
2896static void
2897vnck_task_maximize_all (CtkMenuItem *menu_item G_GNUC_UNUSED__attribute__ ((__unused__)),
2898 gpointer data)
2899{
2900 VnckTask *task = VNCK_TASK (data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((vnck_task_get_type ()))))))
;
2901 GList *l;
2902
2903 l = task->windows;
2904 while (l)
2905 {
2906 VnckTask *child = VNCK_TASK (l->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_task_get_type ()))))))
;
2907 vnck_window_maximize (child->window);
2908 l = l->next;
2909 }
2910}
2911
2912static void
2913vnck_task_popup_menu (VnckTask *task,
2914 gboolean action_submenu)
2915{
2916 CtkWidget *menu;
2917 VnckTask *win_task;
2918 char *text;
2919 GdkPixbuf *pixbuf;
2920 CtkWidget *menu_item;
2921 GList *l, *list;
2922
2923 g_return_if_fail (task->type == VNCK_TASK_CLASS_GROUP)do { if ((task->type == VNCK_TASK_CLASS_GROUP)) { } else {
g_return_if_fail_warning ("Vnck", ((const char*) (__func__))
, "task->type == VNCK_TASK_CLASS_GROUP"); return; } } while
(0)
;
2924
2925 if (task->class_group == NULL((void*)0))
2926 return;
2927
2928 if (task->menu == NULL((void*)0))
2929 {
2930 task->menu = ctk_menu_new ();
2931 g_object_ref_sink (task->menu)((__typeof__ (task->menu)) (g_object_ref_sink) (task->menu
))
;
2932 }
2933
2934 menu = task->menu;
2935
2936 /* Remove old menu content */
2937 list = ctk_container_get_children (CTK_CONTAINER (menu)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu)), ((ctk_container_get_type ()))))))
);
2938 l = list;
2939 while (l)
2940 {
2941 CtkWidget *child = CTK_WIDGET (l->data)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((ctk_widget_get_type ()))))))
;
2942 ctk_container_remove (CTK_CONTAINER (menu)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu)), ((ctk_container_get_type ()))))))
, child);
2943 l = l->next;
2944 }
2945 g_list_free (list);
2946
2947 l = task->windows;
2948 while (l)
2949 {
2950 win_task = VNCK_TASK (l->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_task_get_type ()))))))
;
2951
2952 text = vnck_task_get_text (win_task, TRUE(!(0)), TRUE(!(0)));
2953 menu_item = vnck_image_menu_item_new_with_label (text);
2954 g_free (text);
2955
2956 if (vnck_task_get_needs_attention (win_task))
2957 _make_ctk_label_bold (CTK_LABEL (ctk_bin_get_child (CTK_BIN (menu_item)))((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((ctk_bin_get_child (((((CtkBin*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((menu_item)), ((ctk_bin_get_type ()))))))
))), ((ctk_label_get_type ()))))))
);
2958
2959 text = vnck_task_get_text (win_task, FALSE(0), FALSE(0));
2960 ctk_widget_set_tooltip_text (menu_item, text);
2961 g_free (text);
2962
2963 pixbuf = vnck_task_get_icon (win_task);
2964 if (pixbuf)
2965 {
2966 VnckImageMenuItem *item;
2967
2968 item = VNCK_IMAGE_MENU_ITEM (menu_item);
2969
2970 vnck_image_menu_item_set_image_from_icon_pixbuf (item, pixbuf);
2971 g_object_unref (pixbuf);
2972 }
2973
2974 ctk_widget_show (menu_item);
2975
2976 if (action_submenu)
2977 ctk_menu_item_set_submenu (CTK_MENU_ITEM (menu_item)((((CtkMenuItem*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu_item)), ((ctk_menu_item_get_type ()))))))
,
2978 vnck_action_menu_new (win_task->window));
2979 else
2980 {
2981 static const CtkTargetEntry targets[] = {
2982 { (gchar *) "application/x-vnck-window-id", 0, 0 }
2983 };
2984
2985 g_signal_connect_object (G_OBJECT (menu_item)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu_item)), (((GType) ((20) << (2))))))))
, "activate",
2986 G_CALLBACK (vnck_task_menu_activated)((GCallback) (vnck_task_menu_activated)),
2987 G_OBJECT (win_task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((win_task)), (((GType) ((20) << (2))))))))
,
2988 0);
2989
2990
2991 ctk_drag_source_set (menu_item, CDK_BUTTON1_MASK,
2992 targets, 1, CDK_ACTION_MOVE);
2993 g_signal_connect_object (G_OBJECT(menu_item)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu_item)), (((GType) ((20) << (2))))))))
, "drag_begin",
2994 G_CALLBACK (vnck_task_drag_begin)((GCallback) (vnck_task_drag_begin)),
2995 G_OBJECT (win_task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((win_task)), (((GType) ((20) << (2))))))))
,
2996 0);
2997 g_signal_connect_object (G_OBJECT(menu_item)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu_item)), (((GType) ((20) << (2))))))))
, "drag_end",
2998 G_CALLBACK (vnck_task_drag_end)((GCallback) (vnck_task_drag_end)),
2999 G_OBJECT (win_task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((win_task)), (((GType) ((20) << (2))))))))
,
3000 0);
3001 g_signal_connect_object (G_OBJECT(menu_item)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu_item)), (((GType) ((20) << (2))))))))
, "drag_data_get",
3002 G_CALLBACK (vnck_task_drag_data_get)((GCallback) (vnck_task_drag_data_get)),
3003 G_OBJECT (win_task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((win_task)), (((GType) ((20) << (2))))))))
,
3004 0);
3005 }
3006
3007 ctk_menu_shell_append (CTK_MENU_SHELL (menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu)), ((ctk_menu_shell_get_type ()))))))
, menu_item);
3008
3009 l = l->next;
3010 }
3011
3012 /* In case of Right click, show Minimize All, Unminimize All, Close All*/
3013 if (action_submenu)
3014 {
3015 CtkWidget *separator;
3016
3017 separator = ctk_separator_menu_item_new ();
3018 ctk_widget_show (separator);
3019 ctk_menu_shell_append (CTK_MENU_SHELL (menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu)), ((ctk_menu_shell_get_type ()))))))
, separator);
3020
3021 menu_item = ctk_menu_item_new_with_mnemonic (_("Mi_nimize All")((char *) g_dgettext ("libvnck-3.0", "Mi_nimize All")));
3022 ctk_widget_show (menu_item);
3023 ctk_menu_shell_append (CTK_MENU_SHELL (menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu)), ((ctk_menu_shell_get_type ()))))))
, menu_item);
3024 g_signal_connect_object (G_OBJECT (menu_item)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu_item)), (((GType) ((20) << (2))))))))
, "activate",
3025 G_CALLBACK (vnck_task_minimize_all)((GCallback) (vnck_task_minimize_all)),
3026 G_OBJECT (task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task)), (((GType) ((20) << (2))))))))
,
3027 0);
3028
3029 menu_item = ctk_menu_item_new_with_mnemonic (_("Un_minimize All")((char *) g_dgettext ("libvnck-3.0", "Un_minimize All")));
3030 ctk_widget_show (menu_item);
3031 ctk_menu_shell_append (CTK_MENU_SHELL (menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu)), ((ctk_menu_shell_get_type ()))))))
, menu_item);
3032 g_signal_connect_object (G_OBJECT (menu_item)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu_item)), (((GType) ((20) << (2))))))))
, "activate",
3033 G_CALLBACK (vnck_task_unminimize_all)((GCallback) (vnck_task_unminimize_all)),
3034 G_OBJECT (task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task)), (((GType) ((20) << (2))))))))
,
3035 0);
3036
3037 menu_item = ctk_menu_item_new_with_mnemonic (_("Ma_ximize All")((char *) g_dgettext ("libvnck-3.0", "Ma_ximize All")));
3038 ctk_widget_show (menu_item);
3039 ctk_menu_shell_append (CTK_MENU_SHELL (menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu)), ((ctk_menu_shell_get_type ()))))))
, menu_item);
3040 g_signal_connect_object (G_OBJECT (menu_item)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu_item)), (((GType) ((20) << (2))))))))
, "activate",
3041 G_CALLBACK (vnck_task_maximize_all)((GCallback) (vnck_task_maximize_all)),
3042 G_OBJECT (task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task)), (((GType) ((20) << (2))))))))
,
3043 0);
3044
3045 menu_item = ctk_menu_item_new_with_mnemonic (_("_Unmaximize All")((char *) g_dgettext ("libvnck-3.0", "_Unmaximize All")));
3046 ctk_widget_show (menu_item);
3047 ctk_menu_shell_append (CTK_MENU_SHELL (menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu)), ((ctk_menu_shell_get_type ()))))))
, menu_item);
3048 g_signal_connect_object (G_OBJECT (menu_item)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu_item)), (((GType) ((20) << (2))))))))
, "activate",
3049 G_CALLBACK (vnck_task_unmaximize_all)((GCallback) (vnck_task_unmaximize_all)),
3050 G_OBJECT (task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task)), (((GType) ((20) << (2))))))))
,
3051 0);
3052
3053 separator = ctk_separator_menu_item_new ();
3054 ctk_widget_show (separator);
3055 ctk_menu_shell_append (CTK_MENU_SHELL (menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu)), ((ctk_menu_shell_get_type ()))))))
, separator);
3056
3057 menu_item = ctk_menu_item_new_with_mnemonic(_("_Close All")((char *) g_dgettext ("libvnck-3.0", "_Close All")));
3058 ctk_widget_show (menu_item);
3059 ctk_menu_shell_append (CTK_MENU_SHELL (menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu)), ((ctk_menu_shell_get_type ()))))))
, menu_item);
3060 g_signal_connect_object (G_OBJECT (menu_item)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu_item)), (((GType) ((20) << (2))))))))
, "activate",
3061 G_CALLBACK (vnck_task_close_all)((GCallback) (vnck_task_close_all)),
3062 G_OBJECT (task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task)), (((GType) ((20) << (2))))))))
,
3063 0);
3064 }
3065
3066 ctk_menu_set_screen (CTK_MENU (menu)((((CtkMenu*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu)), ((ctk_menu_get_type ()))))))
,
3067 _vnck_screen_get_cdk_screen (task->tasklist->priv->screen));
3068
3069 ctk_widget_show (menu);
3070 ctk_menu_popup_at_widget (CTK_MENU (menu)((((CtkMenu*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu)), ((ctk_menu_get_type ()))))))
, task->button,
3071 CDK_GRAVITY_SOUTH_WEST,
3072 CDK_GRAVITY_NORTH_WEST,
3073 NULL((void*)0));
3074}
3075
3076static void
3077vnck_task_button_toggled (CtkButton *button,
3078 VnckTask *task)
3079{
3080 /* Did we really want to change the state of the togglebutton? */
3081 if (task->really_toggling)
3082 return;
3083
3084 /* Undo the toggle */
3085 task->really_toggling = TRUE(!(0));
3086 ctk_toggle_button_set_active (CTK_TOGGLE_BUTTON (button)((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), ((ctk_toggle_button_get_type ()))))))
,
3087 !ctk_toggle_button_get_active (CTK_TOGGLE_BUTTON (button)((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), ((ctk_toggle_button_get_type ()))))))
));
3088 task->really_toggling = FALSE(0);
3089
3090 switch (task->type)
3091 {
3092 case VNCK_TASK_CLASS_GROUP:
3093 vnck_task_popup_menu (task, FALSE(0));
3094 break;
3095 case VNCK_TASK_WINDOW:
3096 if (task->window == NULL((void*)0))
3097 return;
3098
3099 /* This should only be called by clicking on the task button, so
3100 * ctk_get_current_event_time() should be fine here...
3101 */
3102 vnck_tasklist_activate_task_window (task, ctk_get_current_event_time ());
3103 break;
3104 case VNCK_TASK_STARTUP_SEQUENCE:
3105 break;
3106 default:
3107 break;
3108 }
3109}
3110
3111static char *
3112vnck_task_get_text (VnckTask *task,
3113 gboolean icon_text,
3114 gboolean include_state)
3115{
3116 const char *name;
3117
3118 switch (task->type)
3119 {
3120 case VNCK_TASK_CLASS_GROUP:
3121 name = vnck_class_group_get_name (task->class_group);
3122 if (name[0] != 0)
3123 return g_strdup_printf ("%s (%d)",
3124 name,
3125 g_list_length (task->windows));
3126 else
3127 return g_strdup_printf ("(%d)",
3128 g_list_length (task->windows));
3129
3130 case VNCK_TASK_WINDOW:
3131 return _vnck_window_get_name_for_display (task->window,
3132 icon_text, include_state);
3133 break;
3134
3135 case VNCK_TASK_STARTUP_SEQUENCE:
3136#ifdef HAVE_STARTUP_NOTIFICATION1
3137 name = sn_startup_sequence_get_description (task->startup_sequence);
3138 if (name == NULL((void*)0))
3139 name = sn_startup_sequence_get_name (task->startup_sequence);
3140 if (name == NULL((void*)0))
3141 name = sn_startup_sequence_get_binary_name (task->startup_sequence);
3142
3143 return g_strdup (name)g_strdup_inline (name);
3144#else
3145 return NULL((void*)0);
3146#endif
3147 break;
3148
3149 default:
3150 break;
3151 }
3152
3153 return NULL((void*)0);
3154}
3155
3156static void
3157vnck_dimm_icon (GdkPixbuf *pixbuf)
3158{
3159 int x, y, pixel_stride, row_stride;
3160 guchar *row, *pixels;
3161 int w, h;
3162
3163 g_assert (pixbuf != NULL)do { if (pixbuf != ((void*)0)) ; else g_assertion_message_expr
("Vnck", "../libvnck/tasklist.c", 3163, ((const char*) (__func__
)), "pixbuf != NULL"); } while (0)
;
3164
3165 w = gdk_pixbuf_get_width (pixbuf);
3166 h = gdk_pixbuf_get_height (pixbuf);
3167
3168 g_assert (gdk_pixbuf_get_has_alpha (pixbuf))do { if (gdk_pixbuf_get_has_alpha (pixbuf)) ; else g_assertion_message_expr
("Vnck", "../libvnck/tasklist.c", 3168, ((const char*) (__func__
)), "gdk_pixbuf_get_has_alpha (pixbuf)"); } while (0)
;
3169
3170 pixel_stride = 4;
3171
3172 row = gdk_pixbuf_get_pixels (pixbuf);
3173 row_stride = gdk_pixbuf_get_rowstride (pixbuf);
3174
3175 for (y = 0; y < h; y++)
3176 {
3177 pixels = row;
3178
3179 for (x = 0; x < w; x++)
3180 {
3181 pixels[3] /= 2;
3182
3183 pixels += pixel_stride;
3184 }
3185
3186 row += row_stride;
3187 }
3188}
3189
3190static GdkPixbuf *
3191vnck_task_scale_icon (GdkPixbuf *orig, gboolean minimized)
3192{
3193 int w, h;
3194 GdkPixbuf *pixbuf;
3195
3196 if (!orig)
3197 return NULL((void*)0);
3198
3199 w = gdk_pixbuf_get_width (orig);
3200 h = gdk_pixbuf_get_height (orig);
3201
3202 if (h != (int) MINI_ICON_SIZE_vnck_get_default_mini_icon_size () ||
3203 !gdk_pixbuf_get_has_alpha (orig))
3204 {
3205 double scale;
3206
3207 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
3208 TRUE(!(0)),
3209 8,
3210 MINI_ICON_SIZE_vnck_get_default_mini_icon_size () * w / (double) h,
3211 MINI_ICON_SIZE_vnck_get_default_mini_icon_size ());
3212
3213 scale = MINI_ICON_SIZE_vnck_get_default_mini_icon_size () / (double) gdk_pixbuf_get_height (orig);
3214
3215 gdk_pixbuf_scale (orig,
3216 pixbuf,
3217 0, 0,
3218 gdk_pixbuf_get_width (pixbuf),
3219 gdk_pixbuf_get_height (pixbuf),
3220 0, 0,
3221 scale, scale,
3222 GDK_INTERP_HYPER);
3223 }
3224 else
3225 pixbuf = orig;
3226
3227 if (minimized)
3228 {
3229 if (orig == pixbuf)
3230 pixbuf = gdk_pixbuf_copy (orig);
3231
3232 vnck_dimm_icon (pixbuf);
3233 }
3234
3235 if (orig == pixbuf)
3236 g_object_ref (pixbuf)((__typeof__ (pixbuf)) (g_object_ref) (pixbuf));
3237
3238 return pixbuf;
3239}
3240
3241
3242static GdkPixbuf *
3243vnck_task_get_icon (VnckTask *task)
3244{
3245 VnckWindowState state;
3246 GdkPixbuf *pixbuf;
3247
3248 pixbuf = NULL((void*)0);
3249
3250 switch (task->type)
3251 {
3252 case VNCK_TASK_CLASS_GROUP:
3253 pixbuf = vnck_task_scale_icon (vnck_class_group_get_mini_icon (task->class_group),
3254 FALSE(0));
3255 break;
3256
3257 case VNCK_TASK_WINDOW:
3258 state = vnck_window_get_state (task->window);
3259
3260 pixbuf = vnck_task_scale_icon (vnck_window_get_mini_icon (task->window),
3261 state & VNCK_WINDOW_STATE_MINIMIZED);
3262 break;
3263
3264 case VNCK_TASK_STARTUP_SEQUENCE:
3265#ifdef HAVE_STARTUP_NOTIFICATION1
3266 if (task->tasklist->priv->icon_loader != NULL((void*)0))
3267 {
3268 const char *icon;
3269
3270 icon = sn_startup_sequence_get_icon_name (task->startup_sequence);
3271 if (icon != NULL((void*)0))
3272 {
3273 GdkPixbuf *loaded;
3274
3275 loaded = (* task->tasklist->priv->icon_loader) (icon,
3276 MINI_ICON_SIZE_vnck_get_default_mini_icon_size (),
3277 0,
3278 task->tasklist->priv->icon_loader_data);
3279
3280 if (loaded != NULL((void*)0))
3281 {
3282 pixbuf = vnck_task_scale_icon (loaded, FALSE(0));
3283 g_object_unref (G_OBJECT (loaded)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((loaded)), (((GType) ((20) << (2))))))))
);
3284 }
3285 }
3286 }
3287
3288 if (pixbuf == NULL((void*)0))
3289 {
3290 _vnck_get_fallback_icons (NULL((void*)0), 0, 0,
3291 &pixbuf, MINI_ICON_SIZE_vnck_get_default_mini_icon_size (), MINI_ICON_SIZE_vnck_get_default_mini_icon_size ());
3292 }
3293#endif
3294 break;
3295
3296 default:
3297 break;
3298 }
3299
3300 return pixbuf;
3301}
3302
3303static gboolean
3304vnck_task_get_needs_attention (VnckTask *task)
3305{
3306 GList *l;
3307 VnckTask *win_task;
3308 gboolean needs_attention;
3309
3310 needs_attention = FALSE(0);
3311
3312 switch (task->type)
3313 {
3314 case VNCK_TASK_CLASS_GROUP:
3315 task->start_needs_attention = 0;
3316 l = task->windows;
3317 while (l)
3318 {
3319 win_task = VNCK_TASK (l->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_task_get_type ()))))))
;
3320
3321 if (vnck_window_or_transient_needs_attention (win_task->window))
3322 {
3323 needs_attention = TRUE(!(0));
3324 task->start_needs_attention = MAX (task->start_needs_attention, _vnck_window_or_transient_get_needs_attention_time (win_task->window))(((task->start_needs_attention) > (_vnck_window_or_transient_get_needs_attention_time
(win_task->window))) ? (task->start_needs_attention) :
(_vnck_window_or_transient_get_needs_attention_time (win_task
->window)))
;
3325 break;
3326 }
3327
3328 l = l->next;
3329 }
3330 break;
3331
3332 case VNCK_TASK_WINDOW:
3333 needs_attention =
3334 vnck_window_or_transient_needs_attention (task->window);
3335 task->start_needs_attention = _vnck_window_or_transient_get_needs_attention_time (task->window);
3336 break;
3337
3338 case VNCK_TASK_STARTUP_SEQUENCE:
3339 default:
3340 break;
3341 }
3342
3343 return needs_attention != FALSE(0);
3344}
3345
3346static void
3347vnck_task_update_visible_state (VnckTask *task)
3348{
3349 GdkPixbuf *pixbuf;
3350 char *text;
3351
3352 pixbuf = vnck_task_get_icon (task);
3353 ctk_image_set_from_pixbuf (CTK_IMAGE (task->image)((((CtkImage*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->image)), ((ctk_image_get_type ()))))))
,
3354 pixbuf);
3355 if (pixbuf)
3356 g_object_unref (pixbuf);
3357
3358 text = vnck_task_get_text (task, TRUE(!(0)), TRUE(!(0)));
3359 if (text != NULL((void*)0))
3360 {
3361 ctk_label_set_text (CTK_LABEL (task->label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->label)), ((ctk_label_get_type ()))))))
, text);
3362 if (vnck_task_get_needs_attention (task))
3363 {
3364 _make_ctk_label_bold ((CTK_LABEL (task->label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->label)), ((ctk_label_get_type ()))))))
));
3365 vnck_task_queue_glow (task);
3366 }
3367 else
3368 {
3369 _make_ctk_label_normal ((CTK_LABEL (task->label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->label)), ((ctk_label_get_type ()))))))
));
3370 vnck_task_reset_glow (task);
3371 }
3372 g_free (text);
3373 }
3374
3375 text = vnck_task_get_text (task, FALSE(0), FALSE(0));
3376 /* if text is NULL, this unsets the tooltip, which is probably what we'd want
3377 * to do */
3378 ctk_widget_set_tooltip_text (task->button, text);
3379 g_free (text);
3380
3381 ctk_widget_queue_resize (CTK_WIDGET (task->tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->tasklist)), ((ctk_widget_get_type ()))))))
);
3382}
3383
3384static void
3385vnck_task_state_changed (VnckWindow *window,
3386 VnckWindowState changed_mask,
3387 VnckWindowState new_state G_GNUC_UNUSED__attribute__ ((__unused__)),
3388 gpointer data)
3389{
3390 VnckTasklist *tasklist = VNCK_TASKLIST (data)((((VnckTasklist*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((vnck_tasklist_get_type ()))))))
;
3391
3392 if (changed_mask & VNCK_WINDOW_STATE_SKIP_TASKLIST)
3393 {
3394 vnck_tasklist_update_lists (tasklist);
3395 ctk_widget_queue_resize (CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
);
3396 return;
3397 }
3398
3399 if ((changed_mask & VNCK_WINDOW_STATE_DEMANDS_ATTENTION) ||
3400 (changed_mask & VNCK_WINDOW_STATE_URGENT))
3401 {
3402 VnckWorkspace *active_workspace =
3403 vnck_screen_get_active_workspace (tasklist->priv->screen);
3404
3405 if (active_workspace &&
3406 (active_workspace != vnck_window_get_workspace (window) ||
3407 (vnck_workspace_is_virtual (active_workspace) &&
3408 !vnck_window_is_in_viewport (window, active_workspace))))
3409 {
3410 vnck_tasklist_update_lists (tasklist);
3411 ctk_widget_queue_resize (CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
);
3412 }
3413 }
3414
3415 if ((changed_mask & VNCK_WINDOW_STATE_MINIMIZED) ||
3416 (changed_mask & VNCK_WINDOW_STATE_DEMANDS_ATTENTION) ||
3417 (changed_mask & VNCK_WINDOW_STATE_URGENT))
3418 {
3419 VnckTask *win_task = NULL((void*)0);
3420
3421 /* FIXME: Handle group modal dialogs */
3422 for (; window && !win_task; window = vnck_window_get_transient (window))
3423 win_task = g_hash_table_lookup (tasklist->priv->win_hash, window);
3424
3425 if (win_task)
3426 {
3427 VnckTask *class_group_task;
3428
3429 vnck_task_update_visible_state (win_task);
3430
3431 class_group_task =
3432 g_hash_table_lookup (tasklist->priv->class_group_hash,
3433 win_task->class_group);
3434
3435 if (class_group_task)
3436 vnck_task_update_visible_state (class_group_task);
3437 }
3438 }
3439
3440}
3441
3442static void
3443vnck_task_icon_changed (VnckWindow *window G_GNUC_UNUSED__attribute__ ((__unused__)),
3444 gpointer data)
3445{
3446 VnckTask *task = VNCK_TASK (data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((vnck_task_get_type ()))))))
;
3447
3448 if (task)
3449 vnck_task_update_visible_state (task);
3450}
3451
3452static void
3453vnck_task_name_changed (VnckWindow *window G_GNUC_UNUSED__attribute__ ((__unused__)),
3454 gpointer data)
3455{
3456 VnckTask *task = VNCK_TASK (data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((vnck_task_get_type ()))))))
;
3457
3458 if (task)
3459 vnck_task_update_visible_state (task);
3460}
3461
3462static void
3463vnck_task_class_name_changed (VnckClassGroup *class_group G_GNUC_UNUSED__attribute__ ((__unused__)),
3464 gpointer data)
3465{
3466 VnckTask *task = VNCK_TASK (data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((vnck_task_get_type ()))))))
;
3467
3468 if (task)
3469 vnck_task_update_visible_state (task);
3470}
3471
3472static void
3473vnck_task_class_icon_changed (VnckClassGroup *class_group G_GNUC_UNUSED__attribute__ ((__unused__)),
3474 gpointer data)
3475{
3476 VnckTask *task = VNCK_TASK (data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((vnck_task_get_type ()))))))
;
3477
3478 if (task)
3479 vnck_task_update_visible_state (task);
3480}
3481
3482static gboolean
3483vnck_task_motion_timeout (gpointer data)
3484{
3485 VnckWorkspace *ws;
3486 VnckTask *task = VNCK_TASK (data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((vnck_task_get_type ()))))))
;
3487
3488 task->button_activate = 0;
3489
3490 /* FIXME: THIS IS SICK AND WRONG AND BUGGY. See the end of
3491 * http://mail.gnome.org/archives/wm-spec-list/2005-July/msg00032.html
3492 * There should only be *one* activate call.
3493 */
3494 ws = vnck_window_get_workspace (task->window);
3495 if (ws && ws != vnck_screen_get_active_workspace (vnck_screen_get_default ()))
3496 {
3497 vnck_workspace_activate (ws, task->dnd_timestamp);
3498 }
3499 vnck_window_activate_transient (task->window, task->dnd_timestamp);
3500
3501 task->dnd_timestamp = 0;
3502
3503 return FALSE(0);
3504}
3505
3506static void
3507vnck_task_drag_leave (CtkWidget *widget,
3508 CdkDragContext *context G_GNUC_UNUSED__attribute__ ((__unused__)),
3509 guint time G_GNUC_UNUSED__attribute__ ((__unused__)),
3510 VnckTask *task)
3511{
3512 if (task->button_activate != 0)
3513 {
3514 g_source_remove (task->button_activate);
3515 task->button_activate = 0;
3516 }
3517
3518 ctk_drag_unhighlight (widget);
3519}
3520
3521static gboolean
3522vnck_task_drag_motion (CtkWidget *widget,
3523 CdkDragContext *context,
3524 gint x G_GNUC_UNUSED__attribute__ ((__unused__)),
3525 gint y G_GNUC_UNUSED__attribute__ ((__unused__)),
3526 guint time,
3527 VnckTask *task)
3528{
3529 if (ctk_drag_dest_find_target (widget, context, NULL((void*)0)))
3530 {
3531 ctk_drag_highlight (widget);
3532 cdk_drag_status (context, cdk_drag_context_get_suggested_action (context), time);
3533 }
3534 else
3535 {
3536 task->dnd_timestamp = time;
3537
3538 if (task->button_activate == 0 && task->type == VNCK_TASK_WINDOW)
3539 {
3540 task->button_activate = g_timeout_add_seconds (VNCK_ACTIVATE_TIMEOUT1,
3541 vnck_task_motion_timeout,
3542 task);
3543 }
3544
3545 cdk_drag_status (context, 0, time);
3546 }
3547 return TRUE(!(0));
3548}
3549
3550static void
3551vnck_task_drag_begin (CtkWidget *widget G_GNUC_UNUSED__attribute__ ((__unused__)),
3552 CdkDragContext *context,
3553 VnckTask *task)
3554{
3555 _vnck_window_set_as_drag_icon (task->window, context,
3556 CTK_WIDGET (task->tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->tasklist)), ((ctk_widget_get_type ()))))))
);
3557
3558 task->tasklist->priv->drag_start_time = ctk_get_current_event_time ();
3559}
3560
3561static void
3562vnck_task_drag_end (CtkWidget *widget G_GNUC_UNUSED__attribute__ ((__unused__)),
3563 CdkDragContext *context G_GNUC_UNUSED__attribute__ ((__unused__)),
3564 VnckTask *task)
3565{
3566 task->tasklist->priv->drag_start_time = 0;
3567}
3568
3569static void
3570vnck_task_drag_data_get (CtkWidget *widget G_GNUC_UNUSED__attribute__ ((__unused__)),
3571 CdkDragContext *context G_GNUC_UNUSED__attribute__ ((__unused__)),
3572 CtkSelectionData *selection_data,
3573 guint info G_GNUC_UNUSED__attribute__ ((__unused__)),
3574 guint time G_GNUC_UNUSED__attribute__ ((__unused__)),
3575 VnckTask *task)
3576{
3577 gulong xid;
3578
3579 xid = vnck_window_get_xid (task->window);
3580 ctk_selection_data_set (selection_data,
3581 ctk_selection_data_get_target (selection_data),
3582 8, (guchar *)&xid, sizeof (gulong));
3583}
3584
3585static void
3586vnck_task_drag_data_received (CtkWidget *widget G_GNUC_UNUSED__attribute__ ((__unused__)),
3587 CdkDragContext *context,
3588 gint x G_GNUC_UNUSED__attribute__ ((__unused__)),
3589 gint y G_GNUC_UNUSED__attribute__ ((__unused__)),
3590 CtkSelectionData *data,
3591 guint info G_GNUC_UNUSED__attribute__ ((__unused__)),
3592 guint time,
3593 VnckTask *target_task)
3594{
3595 VnckTasklist *tasklist;
3596 GList *l, *windows;
3597 VnckWindow *window;
3598 gulong *xid;
3599 guint new_order, old_order, order;
3600 VnckWindow *found_window;
3601
3602 if ((ctk_selection_data_get_length (data) != sizeof (gulong)) ||
3603 (ctk_selection_data_get_format (data) != 8))
3604 {
3605 ctk_drag_finish (context, FALSE(0), FALSE(0), time);
3606 return;
3607 }
3608
3609 tasklist = target_task->tasklist;
3610 xid = (gulong *) ctk_selection_data_get_data (data);
3611 found_window = NULL((void*)0);
3612 new_order = 0;
3613 windows = vnck_screen_get_windows (tasklist->priv->screen);
3614
3615 for (l = windows; l; l = l->next)
3616 {
3617 window = VNCK_WINDOW (l->data)((((VnckWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_window_get_type ()))))))
;
3618 if (vnck_window_get_xid (window) == *xid)
3619 {
3620 old_order = vnck_window_get_sort_order (window);
3621 new_order = vnck_window_get_sort_order (target_task->window);
3622 if (old_order < new_order)
3623 new_order++;
3624 found_window = window;
3625 break;
3626 }
3627 }
3628
3629 if (target_task->window == found_window)
3630 {
3631 CtkSettings *settings;
3632 guint double_click_time;
3633
3634 settings = ctk_settings_get_for_screen (ctk_widget_get_screen (CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
));
3635 double_click_time = 0;
3636 g_object_get (G_OBJECT (settings)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((settings)), (((GType) ((20) << (2))))))))
,
3637 "ctk-double-click-time", &double_click_time,
3638 NULL((void*)0));
3639
3640 if ((time - tasklist->priv->drag_start_time) < double_click_time)
3641 {
3642 vnck_tasklist_activate_task_window (target_task, time);
3643 ctk_drag_finish (context, TRUE(!(0)), FALSE(0), time);
3644 return;
3645 }
3646 }
3647
3648 if (found_window)
3649 {
3650 for (l = windows; l; l = l->next)
3651 {
3652 window = VNCK_WINDOW (l->data)((((VnckWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_window_get_type ()))))))
;
3653 order = vnck_window_get_sort_order (window);
3654 if (order >= new_order)
3655 vnck_window_set_sort_order (window, order + 1);
3656 }
3657 vnck_window_set_sort_order (found_window, new_order);
3658
3659 if (!tasklist->priv->include_all_workspaces &&
3660 !vnck_window_is_pinned (found_window))
3661 {
3662 VnckWorkspace *active_space;
3663 active_space = vnck_screen_get_active_workspace (tasklist->priv->screen);
3664 vnck_window_move_to_workspace (found_window, active_space);
3665 }
3666
3667 ctk_widget_queue_resize (CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
);
3668 }
3669
3670 ctk_drag_finish (context, TRUE(!(0)), FALSE(0), time);
3671}
3672
3673static gboolean
3674vnck_task_button_press_event (CtkWidget *widget G_GNUC_UNUSED__attribute__ ((__unused__)),
3675 CdkEventButton *event,
3676 gpointer data)
3677{
3678 VnckTask *task = VNCK_TASK (data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((vnck_task_get_type ()))))))
;
3679
3680 switch (task->type)
3681 {
3682 case VNCK_TASK_CLASS_GROUP:
3683 if (event->button == 2)
3684 vnck_tasklist_activate_next_in_class_group (task, event->time);
3685 else
3686 vnck_task_popup_menu (task,
3687 event->button == 3);
3688 return TRUE(!(0));
3689
3690 case VNCK_TASK_WINDOW:
3691 if (event->button == 1)
3692 {
3693 /* is_most_recently_activated == is_active for click &
3694 * sloppy focus methods. We use the former here because
3695 * 'mouse' focus provides a special case. In that case, no
3696 * window will be active, but if a window was the most
3697 * recently active one (i.e. user moves mouse straight from
3698 * window to tasklist), then we should still minimize it.
3699 */
3700 if (vnck_window_is_most_recently_activated (task->window))
3701 task->was_active = TRUE(!(0));
3702 else
3703 task->was_active = FALSE(0);
3704
3705 return FALSE(0);
3706 }
3707 else if (event->button == 2)
3708 {
3709 /* middle-click close window */
3710 if (task->tasklist->priv->middle_click_close == TRUE(!(0)))
3711 {
3712 vnck_window_close (task->window, ctk_get_current_event_time ());
3713 return TRUE(!(0));
3714 }
3715 }
3716 else if (event->button == 3)
3717 {
3718 if (task->action_menu)
3719 ctk_widget_destroy (task->action_menu);
3720
3721 g_assert (task->action_menu == NULL)do { if (task->action_menu == ((void*)0)) ; else g_assertion_message_expr
("Vnck", "../libvnck/tasklist.c", 3721, ((const char*) (__func__
)), "task->action_menu == NULL"); } while (0)
;
3722
3723 task->action_menu = vnck_action_menu_new (task->window);
3724
3725 g_object_add_weak_pointer (G_OBJECT (task->action_menu)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->action_menu)), (((GType) ((20) << (2)))))
)))
,
3726 (void**) &task->action_menu);
3727
3728 ctk_menu_set_screen (CTK_MENU (task->action_menu)((((CtkMenu*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->action_menu)), ((ctk_menu_get_type ()))))))
,
3729 _vnck_screen_get_cdk_screen (task->tasklist->priv->screen));
3730
3731 ctk_widget_show (task->action_menu);
3732 ctk_menu_popup_at_widget (CTK_MENU (task->action_menu)((((CtkMenu*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->action_menu)), ((ctk_menu_get_type ()))))))
, task->button,
3733 CDK_GRAVITY_SOUTH_WEST,
3734 CDK_GRAVITY_NORTH_WEST,
3735 (CdkEvent *) event);
3736
3737 g_signal_connect (task->action_menu, "selection-done",g_signal_connect_data ((task->action_menu), ("selection-done"
), (((GCallback) (ctk_widget_destroy))), (((void*)0)), ((void
*)0), (GConnectFlags) 0)
3738 G_CALLBACK (ctk_widget_destroy), NULL)g_signal_connect_data ((task->action_menu), ("selection-done"
), (((GCallback) (ctk_widget_destroy))), (((void*)0)), ((void
*)0), (GConnectFlags) 0)
;
3739
3740 return TRUE(!(0));
3741 }
3742 break;
3743
3744 case VNCK_TASK_STARTUP_SEQUENCE:
3745 default:
3746 break;
3747 }
3748
3749 return FALSE(0);
3750}
3751
3752static GList*
3753vnck_task_extract_windows (VnckTask *task)
3754{
3755 GList *windows = NULL((void*)0);
3756 GList *l;
3757
3758 /* Add the ungrouped window in the task */
3759 if (task->window != NULL((void*)0))
3760 {
3761 windows = g_list_prepend (windows, task->window);
3762 }
3763
3764 /* Add any grouped windows available in the task */
3765 for (l = task->windows; l != NULL((void*)0); l = l->next)
3766 {
3767 VnckTask *t = VNCK_TASK (l->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((vnck_task_get_type ()))))))
;
3768 windows = g_list_prepend (windows, t->window);
3769 }
3770
3771 return g_list_reverse (windows);
3772}
3773
3774static gboolean
3775vnck_task_enter_notify_event (CtkWidget *widget G_GNUC_UNUSED__attribute__ ((__unused__)),
3776 CdkEvent *event G_GNUC_UNUSED__attribute__ ((__unused__)),
3777 gpointer data)
3778{
3779 VnckTask *task = VNCK_TASK (data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((vnck_task_get_type ()))))))
;
3780 GList *windows = vnck_task_extract_windows (task);
3781
3782 g_signal_emit (G_OBJECT (task->tasklist)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->tasklist)), (((GType) ((20) << (2))))))))
,
3783 signals[TASK_ENTER_NOTIFY],
3784 0, windows);
3785
3786 g_list_free (windows);
3787
3788 return FALSE(0);
3789}
3790
3791static gboolean
3792vnck_task_leave_notify_event (CtkWidget *widget G_GNUC_UNUSED__attribute__ ((__unused__)),
3793 CdkEvent *event G_GNUC_UNUSED__attribute__ ((__unused__)),
3794 gpointer data)
3795{
3796 VnckTask *task = VNCK_TASK (data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((vnck_task_get_type ()))))))
;
3797 GList *windows = vnck_task_extract_windows (task);
3798
3799 g_signal_emit (G_OBJECT (task->tasklist)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->tasklist)), (((GType) ((20) << (2))))))))
,
3800 signals[TASK_LEAVE_NOTIFY],
3801 0, windows);
3802
3803 g_list_free (windows);
3804
3805 return FALSE(0);
3806}
3807
3808static gboolean
3809vnck_task_scroll_event (CtkWidget *widget G_GNUC_UNUSED__attribute__ ((__unused__)),
3810 CdkEvent *event,
3811 gpointer data)
3812{
3813 VnckTask *task = VNCK_TASK (data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((vnck_task_get_type ()))))))
;
3814
3815 return vnck_tasklist_scroll_event (CTK_WIDGET (task->tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->tasklist)), ((ctk_widget_get_type ()))))))
, (CdkEventScroll *) event);
3816}
3817
3818static gboolean
3819vnck_task_draw (CtkWidget *widget,
3820 cairo_t *cr,
3821 gpointer data);
3822
3823static void
3824vnck_task_create_widgets (VnckTask *task, CtkReliefStyle relief)
3825{
3826 CtkWidget *hbox;
3827 GdkPixbuf *pixbuf;
3828 char *text;
3829 static const CtkTargetEntry targets[] = {
3830 { (gchar *) "application/x-vnck-window-id", 0, 0 }
3831 };
3832
3833 if (task->type == VNCK_TASK_STARTUP_SEQUENCE)
3834 task->button = ctk_button_new ();
3835 else
3836 task->button = ctk_toggle_button_new ();
3837
3838 ctk_button_set_relief (CTK_BUTTON (task->button)((((CtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), ((ctk_button_get_type ()))))))
, relief);
3839
3840 task->button_activate = 0;
3841 g_object_add_weak_pointer (G_OBJECT (task->button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), (((GType) ((20) << (2))))))))
,
3842 (void**) &task->button);
3843
3844 ctk_widget_set_name (task->button,
3845 "tasklist-button");
3846
3847 if (task->type == VNCK_TASK_WINDOW)
3848 {
3849 ctk_drag_source_set (CTK_WIDGET (task->button)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), ((ctk_widget_get_type ()))))))
,
3850 CDK_BUTTON1_MASK,
3851 targets, 1,
3852 CDK_ACTION_MOVE);
3853 ctk_drag_dest_set (CTK_WIDGET (task->button)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), ((ctk_widget_get_type ()))))))
, CTK_DEST_DEFAULT_DROP,
3854 targets, 1, CDK_ACTION_MOVE);
3855 }
3856 else
3857 ctk_drag_dest_set (CTK_WIDGET (task->button)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), ((ctk_widget_get_type ()))))))
, 0,
3858 NULL((void*)0), 0, CDK_ACTION_DEFAULT);
3859
3860 hbox = ctk_box_new (CTK_ORIENTATION_HORIZONTAL, 0);
3861
3862 pixbuf = vnck_task_get_icon (task);
3863 if (pixbuf)
3864 {
3865 task->image = ctk_image_new_from_pixbuf (pixbuf);
3866 g_object_unref (pixbuf);
3867 }
3868 else
3869 task->image = ctk_image_new ();
3870
3871 ctk_widget_show (task->image);
3872
3873 text = vnck_task_get_text (task, TRUE(!(0)), TRUE(!(0)));
3874 task->label = ctk_label_new (text);
3875 ctk_label_set_xalign (CTK_LABEL (task->label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->label)), ((ctk_label_get_type ()))))))
, 0.0);
3876 ctk_label_set_ellipsize (CTK_LABEL (task->label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->label)), ((ctk_label_get_type ()))))))
,
3877 PANGO_ELLIPSIZE_END);
3878
3879 if (vnck_task_get_needs_attention (task))
3880 {
3881 _make_ctk_label_bold ((CTK_LABEL (task->label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->label)), ((ctk_label_get_type ()))))))
));
3882 vnck_task_queue_glow (task);
3883 }
3884
3885 ctk_widget_show (task->label);
3886
3887 ctk_box_pack_start (CTK_BOX (hbox)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((ctk_box_get_type ()))))))
, task->image, FALSE(0), FALSE(0),
3888 TASKLIST_BUTTON_PADDING4);
3889 ctk_box_pack_start (CTK_BOX (hbox)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((ctk_box_get_type ()))))))
, task->label, TRUE(!(0)), TRUE(!(0)),
3890 TASKLIST_BUTTON_PADDING4);
3891
3892 ctk_container_add (CTK_CONTAINER (task->button)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), ((ctk_container_get_type ()))))))
, hbox);
3893 ctk_widget_show (hbox);
3894 g_free (text);
3895
3896 text = vnck_task_get_text (task, FALSE(0), FALSE(0));
3897 ctk_widget_set_tooltip_text (task->button, text);
3898 g_free (text);
3899
3900 /* Set up signals */
3901 if (CTK_IS_TOGGLE_BUTTON (task->button)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(task->button)); GType __t = ((ctk_toggle_button_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
3902 g_signal_connect_object (G_OBJECT (task->button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), (((GType) ((20) << (2))))))))
, "toggled",
3903 G_CALLBACK (vnck_task_button_toggled)((GCallback) (vnck_task_button_toggled)),
3904 G_OBJECT (task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task)), (((GType) ((20) << (2))))))))
,
3905 0);
3906
3907 g_signal_connect_object (G_OBJECT (task->button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), (((GType) ((20) << (2))))))))
, "size_allocate",
3908 G_CALLBACK (vnck_task_size_allocated)((GCallback) (vnck_task_size_allocated)),
3909 G_OBJECT (task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task)), (((GType) ((20) << (2))))))))
,
3910 0);
3911
3912 g_signal_connect_object (G_OBJECT (task->button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), (((GType) ((20) << (2))))))))
, "button_press_event",
3913 G_CALLBACK (vnck_task_button_press_event)((GCallback) (vnck_task_button_press_event)),
3914 G_OBJECT (task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task)), (((GType) ((20) << (2))))))))
,
3915 0);
3916
3917 g_signal_connect_object (G_OBJECT (task->button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), (((GType) ((20) << (2))))))))
, "enter_notify_event",
3918 G_CALLBACK (vnck_task_enter_notify_event)((GCallback) (vnck_task_enter_notify_event)),
3919 G_OBJECT (task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task)), (((GType) ((20) << (2))))))))
,
3920 0);
3921
3922 g_signal_connect_object (G_OBJECT (task->button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), (((GType) ((20) << (2))))))))
, "leave_notify_event",
3923 G_CALLBACK (vnck_task_leave_notify_event)((GCallback) (vnck_task_leave_notify_event)),
3924 G_OBJECT (task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task)), (((GType) ((20) << (2))))))))
,
3925 0);
3926
3927 ctk_widget_add_events (task->button, CDK_SCROLL_MASK);
3928 g_signal_connect_object (G_OBJECT (task->button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), (((GType) ((20) << (2))))))))
, "scroll_event",
3929 G_CALLBACK (vnck_task_scroll_event)((GCallback) (vnck_task_scroll_event)),
3930 G_OBJECT (task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task)), (((GType) ((20) << (2))))))))
,
3931 0);
3932
3933 g_signal_connect_object (G_OBJECT(task->button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), (((GType) ((20) << (2))))))))
, "drag_motion",
3934 G_CALLBACK (vnck_task_drag_motion)((GCallback) (vnck_task_drag_motion)),
3935 G_OBJECT (task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task)), (((GType) ((20) << (2))))))))
,
3936 0);
3937
3938 if (task->type == VNCK_TASK_WINDOW)
3939 {
3940 g_signal_connect_object (G_OBJECT (task->button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), (((GType) ((20) << (2))))))))
, "drag_data_received",
3941 G_CALLBACK (vnck_task_drag_data_received)((GCallback) (vnck_task_drag_data_received)),
3942 G_OBJECT (task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task)), (((GType) ((20) << (2))))))))
,
3943 0);
3944
3945 }
3946
3947 g_signal_connect_object (G_OBJECT(task->button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), (((GType) ((20) << (2))))))))
, "drag_leave",
3948 G_CALLBACK (vnck_task_drag_leave)((GCallback) (vnck_task_drag_leave)),
3949 G_OBJECT (task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task)), (((GType) ((20) << (2))))))))
,
3950 0);
3951
3952 if (task->type == VNCK_TASK_WINDOW) {
3953 g_signal_connect_object (G_OBJECT(task->button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), (((GType) ((20) << (2))))))))
, "drag_data_get",
3954 G_CALLBACK (vnck_task_drag_data_get)((GCallback) (vnck_task_drag_data_get)),
3955 G_OBJECT (task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task)), (((GType) ((20) << (2))))))))
,
3956 0);
3957
3958 g_signal_connect_object (G_OBJECT(task->button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), (((GType) ((20) << (2))))))))
, "drag_begin",
3959 G_CALLBACK (vnck_task_drag_begin)((GCallback) (vnck_task_drag_begin)),
3960 G_OBJECT (task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task)), (((GType) ((20) << (2))))))))
,
3961 0);
3962
3963 g_signal_connect_object (G_OBJECT(task->button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), (((GType) ((20) << (2))))))))
, "drag_end",
3964 G_CALLBACK (vnck_task_drag_end)((GCallback) (vnck_task_drag_end)),
3965 G_OBJECT (task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task)), (((GType) ((20) << (2))))))))
,
3966 0);
3967 }
3968
3969 switch (task->type)
3970 {
3971 case VNCK_TASK_CLASS_GROUP:
3972 task->class_name_changed_tag = g_signal_connect (G_OBJECT (task->class_group), "name_changed",g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((task->class_group)), (((GType) ((20) <<
(2))))))))), ("name_changed"), (((GCallback) (vnck_task_class_name_changed
))), (task), ((void*)0), (GConnectFlags) 0)
3973 G_CALLBACK (vnck_task_class_name_changed), task)g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((task->class_group)), (((GType) ((20) <<
(2))))))))), ("name_changed"), (((GCallback) (vnck_task_class_name_changed
))), (task), ((void*)0), (GConnectFlags) 0)
;
3974 task->class_icon_changed_tag = g_signal_connect (G_OBJECT (task->class_group), "icon_changed",g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((task->class_group)), (((GType) ((20) <<
(2))))))))), ("icon_changed"), (((GCallback) (vnck_task_class_icon_changed
))), (task), ((void*)0), (GConnectFlags) 0)
3975 G_CALLBACK (vnck_task_class_icon_changed), task)g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((task->class_group)), (((GType) ((20) <<
(2))))))))), ("icon_changed"), (((GCallback) (vnck_task_class_icon_changed
))), (task), ((void*)0), (GConnectFlags) 0)
;
3976 break;
3977
3978 case VNCK_TASK_WINDOW:
3979 task->state_changed_tag = g_signal_connect (G_OBJECT (task->window), "state_changed",g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((task->window)), (((GType) ((20) <<
(2))))))))), ("state_changed"), (((GCallback) (vnck_task_state_changed
))), (task->tasklist), ((void*)0), (GConnectFlags) 0)
3980 G_CALLBACK (vnck_task_state_changed), task->tasklist)g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((task->window)), (((GType) ((20) <<
(2))))))))), ("state_changed"), (((GCallback) (vnck_task_state_changed
))), (task->tasklist), ((void*)0), (GConnectFlags) 0)
;
3981 task->icon_changed_tag = g_signal_connect (G_OBJECT (task->window), "icon_changed",g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((task->window)), (((GType) ((20) <<
(2))))))))), ("icon_changed"), (((GCallback) (vnck_task_icon_changed
))), (task), ((void*)0), (GConnectFlags) 0)
3982 G_CALLBACK (vnck_task_icon_changed), task)g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((task->window)), (((GType) ((20) <<
(2))))))))), ("icon_changed"), (((GCallback) (vnck_task_icon_changed
))), (task), ((void*)0), (GConnectFlags) 0)
;
3983 task->name_changed_tag = g_signal_connect (G_OBJECT (task->window), "name_changed",g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((task->window)), (((GType) ((20) <<
(2))))))))), ("name_changed"), (((GCallback) (vnck_task_name_changed
))), (task), ((void*)0), (GConnectFlags) 0)
3984 G_CALLBACK (vnck_task_name_changed), task)g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((task->window)), (((GType) ((20) <<
(2))))))))), ("name_changed"), (((GCallback) (vnck_task_name_changed
))), (task), ((void*)0), (GConnectFlags) 0)
;
3985 break;
3986
3987 case VNCK_TASK_STARTUP_SEQUENCE:
3988 break;
3989
3990 default:
3991 g_assert_not_reached ()do { g_assertion_message_expr ("Vnck", "../libvnck/tasklist.c"
, 3991, ((const char*) (__func__)), ((void*)0)); } while (0)
;
3992 }
3993
3994 g_signal_connect_object (task->button, "draw",
3995 G_CALLBACK (vnck_task_draw)((GCallback) (vnck_task_draw)),
3996 G_OBJECT (task)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task)), (((GType) ((20) << (2))))))))
,
3997 G_CONNECT_AFTER);
3998}
3999
4000#define ARROW_SPACE4 4
4001#define ARROW_SIZE12 12
4002#define INDICATOR_SIZE7 7
4003
4004static gboolean
4005vnck_task_draw (CtkWidget *widget,
4006 cairo_t *cr,
4007 gpointer data)
4008{
4009 int x, y;
4010 VnckTask *task;
4011 CtkStyleContext *context;
4012 CtkStateFlags state;
4013 CtkBorder padding;
4014 CtkWidget *tasklist_widget;
4015 gint width, height;
4016 gboolean overlay_rect;
4017 gint arrow_width;
4018 gint arrow_height;
4019 CdkRGBA color;
4020
4021 task = VNCK_TASK (data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((vnck_task_get_type ()))))))
;
4022
4023 switch (task->type)
4024 {
4025 case VNCK_TASK_CLASS_GROUP:
4026 context = ctk_widget_get_style_context (widget);
4027
4028 state = ctk_style_context_get_state (context);
4029 ctk_style_context_get_padding (context, state, &padding);
4030
4031 state = (task->tasklist->priv->active_class_group == task) ?
4032 CTK_STATE_FLAG_ACTIVE : CTK_STATE_FLAG_NORMAL;
4033
4034 ctk_style_context_save (context);
4035 ctk_style_context_set_state (context, state);
4036 ctk_style_context_get_color (context, state, &color);
4037 ctk_style_context_restore (context);
4038
4039 x = ctk_widget_get_allocated_width (widget) -
4040 (ctk_container_get_border_width (CTK_CONTAINER (widget)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_container_get_type ()))))))
) + padding.right + ARROW_SIZE12);
4041 y = ctk_widget_get_allocated_height (widget) / 2;
4042
4043 arrow_width = INDICATOR_SIZE7 + ((INDICATOR_SIZE7 % 2) - 1);
4044 arrow_height = arrow_width / 2 + 1;
4045 x += (ARROW_SIZE12 - arrow_width) / 2;
4046 y -= (2 * arrow_height + ARROW_SPACE4) / 2;
4047
4048 cairo_save (cr);
4049 cdk_cairo_set_source_rgba (cr, &color);
4050
4051 /* Up arrow */
4052 cairo_move_to (cr, x, y + arrow_height);
4053 cairo_line_to (cr, x + arrow_width / 2., y);
4054 cairo_line_to (cr, x + arrow_width, y + arrow_height);
4055 cairo_close_path (cr);
4056 cairo_fill (cr);
4057
4058 /* Down arrow */
4059 y += arrow_height + ARROW_SPACE4;
4060 cairo_move_to (cr, x, y);
4061 cairo_line_to (cr, x + arrow_width, y);
4062 cairo_line_to (cr, x + arrow_width / 2., y + arrow_height);
4063 cairo_close_path (cr);
4064 cairo_fill (cr);
4065
4066 cairo_restore (cr);
4067
4068 break;
4069
4070 case VNCK_TASK_WINDOW:
4071 case VNCK_TASK_STARTUP_SEQUENCE:
4072 default:
4073 break;
4074 }
4075
4076 if (task->glow_factor == 0.0)
4077 return FALSE(0);
4078
4079 /* push a translucent overlay to paint to, so we can blend later */
4080 cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA);
4081
4082 width = ctk_widget_get_allocated_width (task->button);
4083 height = ctk_widget_get_allocated_height (task->button);
4084
4085 tasklist_widget = CTK_WIDGET (task->tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->tasklist)), ((ctk_widget_get_type ()))))))
;
4086
4087 context = ctk_widget_get_style_context (task->button);
4088
4089 /* first draw the button */
4090 ctk_widget_style_get (tasklist_widget, "fade-overlay-rect", &overlay_rect, NULL((void*)0));
4091 if (overlay_rect)
4092 {
4093 ctk_style_context_save (context);
4094 ctk_style_context_set_state (context, CTK_STATE_FLAG_SELECTED);
4095
4096 /* Draw a rectangle with selected background color */
4097 ctk_render_background (context, cr, 0, 0, width, height);
4098
4099 ctk_style_context_restore (context);
4100 }
4101 else
4102 {
4103 ctk_style_context_save (context);
4104 ctk_style_context_set_state (context, CTK_STATE_FLAG_SELECTED);
4105 ctk_style_context_add_class (context, CTK_STYLE_CLASS_BUTTON"button");
4106
4107 cairo_save (cr);
4108 ctk_render_background (context, cr, 0, 0, width, height);
4109 ctk_render_frame (context, cr, 0, 0, width, height);
4110 cairo_restore (cr);
4111
4112 ctk_style_context_restore (context);
4113 }
4114
4115 /* then the contents */
4116 ctk_container_propagate_draw (CTK_CONTAINER (task->button)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), ((ctk_container_get_type ()))))))
,
4117 ctk_bin_get_child (CTK_BIN (task->button)((((CtkBin*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((task->button)), ((ctk_bin_get_type ()))))))
),
4118 cr);
4119 /* finally blend it */
4120 cairo_pop_group_to_source (cr);
4121 cairo_paint_with_alpha (cr, task->glow_factor);
4122
4123 return FALSE(0);
4124}
4125
4126static gint
4127vnck_task_compare_alphabetically (gconstpointer a,
4128 gconstpointer b)
4129{
4130 char *text1;
4131 char *text2;
4132 gint result;
4133
4134 text1 = vnck_task_get_text (VNCK_TASK (a)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((a)), ((vnck_task_get_type ()))))))
, TRUE(!(0)), FALSE(0));
4135 text2 = vnck_task_get_text (VNCK_TASK (b)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((b)), ((vnck_task_get_type ()))))))
, TRUE(!(0)), FALSE(0));
4136
4137 result= g_utf8_collate (text1, text2);
4138
4139 g_free (text1);
4140 g_free (text2);
4141
4142 return result;
4143}
4144
4145static gint
4146compare_class_group_tasks (VnckTask *task1, VnckTask *task2)
4147{
4148 const char *name1, *name2;
4149
4150 name1 = vnck_class_group_get_name (task1->class_group);
4151 name2 = vnck_class_group_get_name (task2->class_group);
4152
4153 return g_utf8_collate (name1, name2);
4154}
4155
4156static gint
4157vnck_task_compare (gconstpointer a,
4158 gconstpointer b)
4159{
4160 VnckTask *task1 = VNCK_TASK (a)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((a)), ((vnck_task_get_type ()))))))
;
4161 VnckTask *task2 = VNCK_TASK (b)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((b)), ((vnck_task_get_type ()))))))
;
4162 gint pos1, pos2;
4163
4164 pos1 = pos2 = 0; /* silence the compiler */
4165
4166 switch (task1->type)
4167 {
4168 case VNCK_TASK_CLASS_GROUP:
4169 if (task2->type == VNCK_TASK_CLASS_GROUP)
4170 return compare_class_group_tasks (task1, task2);
4171 else
4172 return -1; /* Sort groups before everything else */
4173
4174 case VNCK_TASK_WINDOW:
4175 pos1 = vnck_window_get_sort_order (task1->window);
4176 break;
4177 case VNCK_TASK_STARTUP_SEQUENCE:
4178 pos1 = G_MAXINT2147483647; /* startup sequences are sorted at the end. */
4179 break; /* Changing this will break scrolling. */
4180
4181 default:
4182 break;
4183 }
4184
4185 switch (task2->type)
4186 {
4187 case VNCK_TASK_CLASS_GROUP:
4188 if (task1->type == VNCK_TASK_CLASS_GROUP)
4189 return compare_class_group_tasks (task1, task2);
4190 else
4191 return 1; /* Sort groups before everything else */
4192
4193 case VNCK_TASK_WINDOW:
4194 pos2 = vnck_window_get_sort_order (task2->window);
4195 break;
4196 case VNCK_TASK_STARTUP_SEQUENCE:
4197 pos2 = G_MAXINT2147483647;
4198 break;
4199
4200 default:
4201 break;
4202 }
4203
4204 if (pos1 < pos2)
4205 return -1;
4206 else if (pos1 > pos2)
4207 return 1;
4208 else
4209 return 0; /* should only happen if there's multiple processes being
4210 * started, and then who cares about sort order... */
4211}
4212
4213static void
4214remove_startup_sequences_for_window (VnckTasklist *tasklist,
4215 VnckWindow *window)
4216{
4217#ifdef HAVE_STARTUP_NOTIFICATION1
4218 const char *win_id;
4219 GList *tmp;
4220
4221 win_id = _vnck_window_get_startup_id (window);
4222 if (win_id == NULL((void*)0))
4223 return;
4224
4225 tmp = tasklist->priv->startup_sequences;
4226 while (tmp != NULL((void*)0))
4227 {
4228 VnckTask *task = tmp->data;
4229 GList *next = tmp->next;
4230 const char *task_id;
4231
4232 g_assert (task->type == VNCK_TASK_STARTUP_SEQUENCE)do { if (task->type == VNCK_TASK_STARTUP_SEQUENCE) ; else g_assertion_message_expr
("Vnck", "../libvnck/tasklist.c", 4232, ((const char*) (__func__
)), "task->type == VNCK_TASK_STARTUP_SEQUENCE"); } while (
0)
;
4233
4234 task_id = sn_startup_sequence_get_id (task->startup_sequence);
4235
4236 if (task_id && strcmp (task_id, win_id) == 0)
4237 ctk_widget_destroy (task->button);
4238
4239 tmp = next;
4240 }
4241#else
4242 ; /* nothing */
4243#endif
4244}
4245
4246static VnckTask *
4247vnck_task_new_from_window (VnckTasklist *tasklist,
4248 VnckWindow *window)
4249{
4250 VnckTask *task;
4251
4252 task = g_object_new (VNCK_TYPE_TASK(vnck_task_get_type ()), NULL((void*)0));
4253 task->type = VNCK_TASK_WINDOW;
4254 task->window = g_object_ref (window)((__typeof__ (window)) (g_object_ref) (window));
4255 task->class_group = g_object_ref (vnck_window_get_class_group (window))((__typeof__ (vnck_window_get_class_group (window))) (g_object_ref
) (vnck_window_get_class_group (window)))
;
4256 task->tasklist = tasklist;
4257
4258 vnck_task_create_widgets (task, tasklist->priv->relief);
4259
4260 remove_startup_sequences_for_window (tasklist, window);
4261
4262 return task;
4263}
4264
4265static VnckTask *
4266vnck_task_new_from_class_group (VnckTasklist *tasklist,
4267 VnckClassGroup *class_group)
4268{
4269 VnckTask *task;
4270
4271 task = g_object_new (VNCK_TYPE_TASK(vnck_task_get_type ()), NULL((void*)0));
4272
4273 task->type = VNCK_TASK_CLASS_GROUP;
4274 task->window = NULL((void*)0);
4275 task->class_group = g_object_ref (class_group)((__typeof__ (class_group)) (g_object_ref) (class_group));
4276 task->tasklist = tasklist;
4277
4278 vnck_task_create_widgets (task, tasklist->priv->relief);
4279
4280 return task;
4281}
4282
4283#ifdef HAVE_STARTUP_NOTIFICATION1
4284static VnckTask*
4285vnck_task_new_from_startup_sequence (VnckTasklist *tasklist,
4286 SnStartupSequence *sequence)
4287{
4288 VnckTask *task;
4289
4290 task = g_object_new (VNCK_TYPE_TASK(vnck_task_get_type ()), NULL((void*)0));
4291
4292 task->type = VNCK_TASK_STARTUP_SEQUENCE;
4293 task->window = NULL((void*)0);
4294 task->class_group = NULL((void*)0);
4295 task->startup_sequence = sequence;
4296 sn_startup_sequence_ref (task->startup_sequence);
4297 task->tasklist = tasklist;
4298
4299 vnck_task_create_widgets (task, tasklist->priv->relief);
4300
4301 return task;
4302}
4303
4304/* This should be fairly long, as it should never be required unless
4305 * apps or .desktop files are buggy, and it's confusing if
4306 * OpenOffice or whatever seems to stop launching - people
4307 * might decide they need to launch it again.
4308 */
4309#define STARTUP_TIMEOUT15000 15000
4310
4311static gboolean
4312sequence_timeout_callback (void *user_data)
4313{
4314 VnckTasklist *tasklist = user_data;
4315 GList *tmp;
4316 gint64 now;
4317 long tv_sec, tv_usec;
4318 double elapsed;
4319
4320 now = g_get_real_time ();
4321
4322 restart:
4323 tmp = tasklist->priv->startup_sequences;
4324 while (tmp != NULL((void*)0))
4325 {
4326 VnckTask *task = VNCK_TASK (tmp->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tmp->data)), ((vnck_task_get_type ()))))))
;
4327
4328 sn_startup_sequence_get_last_active_time (task->startup_sequence,
4329 &tv_sec, &tv_usec);
4330
4331 elapsed = (now - (tv_sec * G_USEC_PER_SEC1000000 + tv_usec)) / 1000.0;
4332
4333 if (elapsed > STARTUP_TIMEOUT15000)
4334 {
4335 g_assert (task->button != NULL)do { if (task->button != ((void*)0)) ; else g_assertion_message_expr
("Vnck", "../libvnck/tasklist.c", 4335, ((const char*) (__func__
)), "task->button != NULL"); } while (0)
;
4336 /* removes task from list as a side effect */
4337 ctk_widget_destroy (task->button);
4338
4339 goto restart; /* don't iterate over changed list, just restart;
4340 * not efficient but who cares here.
4341 */
4342 }
4343
4344 tmp = tmp->next;
4345 }
4346
4347 if (tasklist->priv->startup_sequences == NULL((void*)0))
4348 {
4349 tasklist->priv->startup_sequence_timeout = 0;
4350 return FALSE(0);
4351 }
4352 else
4353 return TRUE(!(0));
4354}
4355
4356static void
4357vnck_tasklist_sn_event (SnMonitorEvent *event,
4358 void *user_data)
4359{
4360 VnckTasklist *tasklist;
4361
4362 tasklist = VNCK_TASKLIST (user_data)((((VnckTasklist*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((user_data)), ((vnck_tasklist_get_type ()))))))
;
4363
4364 switch (sn_monitor_event_get_type (event))
4365 {
4366 case SN_MONITOR_EVENT_INITIATED:
4367 {
4368 VnckTask *task;
4369
4370 task = vnck_task_new_from_startup_sequence (tasklist,
4371 sn_monitor_event_get_startup_sequence (event));
4372
4373 ctk_widget_set_parent (task->button, CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
);
4374 ctk_widget_show (task->button);
4375
4376 tasklist->priv->startup_sequences =
4377 g_list_prepend (tasklist->priv->startup_sequences,
4378 task);
4379
4380 if (tasklist->priv->startup_sequence_timeout == 0)
4381 {
4382 tasklist->priv->startup_sequence_timeout =
4383 g_timeout_add_seconds (1, sequence_timeout_callback,
4384 tasklist);
4385 }
4386
4387 ctk_widget_queue_resize (CTK_WIDGET (tasklist)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tasklist)), ((ctk_widget_get_type ()))))))
);
4388 }
4389 break;
4390
4391 case SN_MONITOR_EVENT_COMPLETED:
4392 {
4393 GList *tmp;
4394 tmp = tasklist->priv->startup_sequences;
4395 while (tmp != NULL((void*)0))
4396 {
4397 VnckTask *task = VNCK_TASK (tmp->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tmp->data)), ((vnck_task_get_type ()))))))
;
4398
4399 if (task->startup_sequence ==
4400 sn_monitor_event_get_startup_sequence (event))
4401 {
4402 g_assert (task->button != NULL)do { if (task->button != ((void*)0)) ; else g_assertion_message_expr
("Vnck", "../libvnck/tasklist.c", 4402, ((const char*) (__func__
)), "task->button != NULL"); } while (0)
;
4403 /* removes task from list as a side effect */
4404 ctk_widget_destroy (task->button);
4405 break;
4406 }
4407
4408 tmp = tmp->next;
4409 }
4410 }
4411 break;
4412
4413 case SN_MONITOR_EVENT_CHANGED:
4414 break;
4415
4416 case SN_MONITOR_EVENT_CANCELED:
4417 break;
4418
4419 default:
4420 break;
4421 }
4422
4423 if (tasklist->priv->startup_sequences == NULL((void*)0) &&
4424 tasklist->priv->startup_sequence_timeout != 0)
4425 {
4426 g_source_remove (tasklist->priv->startup_sequence_timeout);
4427 tasklist->priv->startup_sequence_timeout = 0;
4428 }
4429}
4430
4431static void
4432vnck_tasklist_check_end_sequence (VnckTasklist *tasklist,
4433 VnckWindow *window)
4434{
4435 const char *res_class;
4436 const char *res_name;
4437 GList *tmp;
4438
4439 if (tasklist->priv->startup_sequences == NULL((void*)0))
4440 return;
4441
4442 res_class = vnck_window_get_class_group_name (window);
4443 res_name = vnck_window_get_class_instance_name (window);
4444
4445 if (res_class == NULL((void*)0) && res_name == NULL((void*)0))
4446 return;
4447
4448 tmp = tasklist->priv->startup_sequences;
4449 while (tmp != NULL((void*)0))
4450 {
4451 VnckTask *task = VNCK_TASK (tmp->data)((((VnckTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tmp->data)), ((vnck_task_get_type ()))))))
;
4452 const char *wmclass;
4453
4454 wmclass = sn_startup_sequence_get_wmclass (task->startup_sequence);
4455
4456 if (wmclass != NULL((void*)0) &&
4457 ((res_class && strcmp (res_class, wmclass) == 0) ||
4458 (res_name && strcmp (res_name, wmclass) == 0)))
4459 {
4460 sn_startup_sequence_complete (task->startup_sequence);
4461
4462 g_assert (task->button != NULL)do { if (task->button != ((void*)0)) ; else g_assertion_message_expr
("Vnck", "../libvnck/tasklist.c", 4462, ((const char*) (__func__
)), "task->button != NULL"); } while (0)
;
4463 /* removes task from list as a side effect */
4464 ctk_widget_destroy (task->button);
4465
4466 /* only match one */
4467 return;
4468 }
4469
4470 tmp = tmp->next;
4471 }
4472}
4473
4474#endif /* HAVE_STARTUP_NOTIFICATION */