Merge lp:~jassmith/window-picker-applet/task-item-rewrite into lp:window-picker-applet

Proposed by Jason Smith
Status: Merged
Merged at revision: not available
Proposed branch: lp:~jassmith/window-picker-applet/task-item-rewrite
Merge into: lp:window-picker-applet
Diff against target: None lines
To merge this branch: bzr merge lp:~jassmith/window-picker-applet/task-item-rewrite
Reviewer Review Type Date Requested Status
Neil J. Patel (community) Needs Fixing
Review via email: mp+10512@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Jason Smith (jassmith) wrote :

- Window items are now their own class and self managing
- Window item icons are full size of the panel (contain small click detection bug)
- Active window item is fully opaque, inactive items are slightly transparent
- Title bar has lost extra icon
- Title bar contains bold text
- Title bar now properly prelights the close button, this however will need to be themed properly in the gtkrc file
- Window items that set the urgent status now slowly (around 1 second) fade in and out to indicate this, rather than sudden blinks. Very passive.

99. By Jason Smith <jason@t500>

modified:
  src/task-item.c : Added prelighting to buttons

Revision history for this message
Neil J. Patel (njpatel) wrote :

Nice job! Love the fading animation when window has the urgent hint, and definitely like the clean-up fo the code.

There are a couple of things I noticed that need to be fixed before merge:

- The icons no-longer pickup the colour of the panel if it's different from the standard Gtk colour (i.e. when using right-click->properities->background and setting it to a different colour/changing transparency or setting a background image).

- The 1px click-through area the top of the icons seems to effect the entire applet, so maybe the container border needs to be removed from the the main box thats holding the applet's content.

-- Below is not merge-critical as we can fix after feature freeze --:

- Using it for some time on a netbook, I don't think there's enough difference between an active window's icon and a non-active window's icon. We should try a hi-light behind the active icon as before, or a glow/etc.

review: Needs Fixing
100. By Jason Smith <jason@t500>

Actually draw on parent window. oops.
Fixes bug where buttons would have black background in some situations.

101. By Jason Smith <jason@t500>

Fix fitz law problem

Revision history for this message
Jason Smith (jassmith) wrote :

> Nice job! Love the fading animation when window has the urgent hint, and
> definitely like the clean-up fo the code.
>
> There are a couple of things I noticed that need to be fixed before merge:
>
> - The icons no-longer pickup the colour of the panel if it's different from
> the standard Gtk colour (i.e. when using right-click->properities->background
> and setting it to a different colour/changing transparency or setting a
> background image).

  Fixed

>
> - The 1px click-through area the top of the icons seems to effect the entire
> applet, so maybe the container border needs to be removed from the the main
> box thats holding the applet's content.

  Fixed AND grew the icons by 2px.

>
> -- Below is not merge-critical as we can fix after feature freeze --:
>
> - Using it for some time on a netbook, I don't think there's enough difference
> between an active window's icon and a non-active window's icon. We should try
> a hi-light behind the active icon as before, or a glow/etc.

Just let me know what you want. I will do a glow like effect and see if that helps. I will strive to make it very very obvious which one is active. We will need something other than what we had before however since in many cases, that wont be at all visible.

102. By Jason Smith <jason@t500>

task-item.c : fix render glitch, remember allocation

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/Makefile.am'
2--- src/Makefile.am 2008-06-14 15:09:30 +0000
3+++ src/Makefile.am 2009-08-18 23:59:03 +0000
4@@ -16,6 +16,8 @@
5
6 window_picker_applet_SOURCES = \
7 applet.c \
8+ task-item.c \
9+ task-item.h \
10 task-list.c \
11 task-list.h \
12 task-title.c \
13
14=== added file 'src/task-item.c'
15--- src/task-item.c 1970-01-01 00:00:00 +0000
16+++ src/task-item.c 2009-08-21 07:06:29 +0000
17@@ -0,0 +1,633 @@
18+/*
19+ * Copyright (C) 2008 Canonical Ltd
20+ *
21+ * This program is free software: you can redistribute it and/or modify
22+ * it under the terms of the GNU General Public License version 3 as
23+ * published by the Free Software Foundation.
24+ *
25+ * This program is distributed in the hope that it will be useful,
26+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
27+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28+ * GNU General Public License for more details.
29+ *
30+ * You should have received a copy of the GNU General Public License
31+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
32+ *
33+ * Authored by Jason Smith <jassmith@gmail.com>
34+ *
35+ */
36+
37+#include "task-item.h"
38+#include "task-list.h"
39+
40+#include <math.h>
41+#include <cairo/cairo.h>
42+
43+G_DEFINE_TYPE (TaskItem, task_item, GTK_TYPE_EVENT_BOX);
44+
45+#define TASK_ITEM_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
46+ TASK_TYPE_ITEM, \
47+ TaskItemPrivate))
48+
49+#define DEFAULT_TASK_ITEM_HEIGHT 24;
50+#define DEFAULT_TASK_ITEM_WIDTH 28
51+
52+struct _TaskItemPrivate
53+{
54+ WnckWindow *window;
55+ WnckScreen *screen;
56+ GdkPixbuf *pixbuf;
57+
58+ GTimeVal urgent_time;
59+ guint timer;
60+};
61+
62+enum {
63+ TASK_ITEM_CLOSED_SIGNAL,
64+ LAST_SIGNAL
65+};
66+
67+/* D&D stuff */
68+static const GtkTargetEntry drop_types[] =
69+{
70+ { "STRING", 0, 0 },
71+ { "text/plain", 0, 0},
72+ { "text/uri-list", 0, 0}
73+};
74+static const gint n_drop_types = G_N_ELEMENTS(drop_types);
75+
76+static guint task_item_signals[LAST_SIGNAL] = { 0 };
77+
78+static void
79+update_hints (TaskItem *item)
80+{
81+ GtkWidget *parent;
82+ GtkWidget *widget;
83+ WnckWindow *window;
84+ gint x, y, x1, y1;
85+
86+ widget = GTK_WIDGET (item);
87+ window = item->priv->window;
88+ /* Skip problems */
89+ if (!WNCK_IS_WINDOW (window)) return;
90+ if (!GTK_IS_WIDGET (widget)) return;
91+
92+ /* Skip invisible windows */
93+ if (!GTK_WIDGET_VISIBLE (widget)) return;
94+
95+ x = y = 0;
96+
97+ /* Recursively compute the button's coordinates */
98+ for (parent = widget; parent; parent = parent->parent)
99+ {
100+ if (parent->parent)
101+ {
102+ x += parent->allocation.x;
103+ y += parent->allocation.y;
104+ }
105+ else
106+ {
107+ x1 = y1 = 0;
108+ if (GDK_IS_WINDOW (parent->window))
109+ gdk_window_get_origin (parent->window, &x1, &y1);
110+ x += x1; y += y1;
111+ break;
112+ }
113+ }
114+
115+ /* Set the minimize hint for the window */
116+ wnck_window_set_icon_geometry (window, x, y,
117+ widget->allocation.width,
118+ widget->allocation.height);
119+}
120+
121+static gboolean
122+on_task_item_button_released (GtkWidget *widget,
123+ GdkEventButton *event,
124+ TaskItem *item)
125+{
126+ WnckWindow *window;
127+ WnckScreen *screen;
128+ WnckWorkspace *workspace;
129+ TaskItemPrivate *priv;
130+
131+ g_return_val_if_fail (TASK_IS_ITEM (item), TRUE);
132+
133+ priv = item->priv;
134+ window = priv->window;
135+
136+ g_return_val_if_fail (WNCK_IS_WINDOW (window), TRUE);
137+
138+ screen = priv->screen;
139+ workspace = wnck_window_get_workspace (window);
140+
141+ if (event->button == 1)
142+ {
143+
144+ if (WNCK_IS_WORKSPACE (workspace) && workspace != wnck_screen_get_active_workspace (screen))
145+ {
146+ wnck_workspace_activate (workspace, GDK_CURRENT_TIME);
147+ }
148+ if (wnck_window_is_active (window))
149+ {
150+ wnck_window_minimize (window);
151+ }
152+ else
153+ {
154+ wnck_window_activate (window, GDK_CURRENT_TIME);
155+ }
156+ }
157+ return TRUE;
158+}
159+
160+static void
161+task_item_set_visibility (TaskItem *item)
162+{
163+ WnckScreen *screen;
164+ WnckWindow *window;
165+ WnckWorkspace *workspace;
166+
167+ g_return_if_fail (TASK_IS_ITEM (item));
168+
169+ TaskItemPrivate *priv = item->priv;
170+
171+ if (!WNCK_IS_WINDOW (priv->window))
172+ {
173+ gtk_widget_hide (GTK_WIDGET (item));
174+ return;
175+ }
176+
177+ window = priv->window;
178+
179+ screen = priv->screen;
180+ workspace = wnck_screen_get_active_workspace (screen);
181+
182+ gboolean show_all = task_list_get_show_all_windows (TASK_LIST (task_list_get_default ()));
183+
184+ if (wnck_window_is_skip_tasklist (window) ||
185+ (!show_all && !wnck_window_is_on_workspace (window, workspace)))
186+ {
187+ gtk_widget_hide (GTK_WIDGET (item));
188+ }
189+ else
190+ {
191+ gtk_widget_show (GTK_WIDGET (item));
192+ }
193+}
194+
195+static void
196+task_item_size_request (GtkWidget *widget,
197+ GtkRequisition *requisition)
198+{
199+ /* Candidate for terrible hack of the year award */
200+ requisition->width = DEFAULT_TASK_ITEM_WIDTH;
201+ requisition->height = DEFAULT_TASK_ITEM_HEIGHT;
202+}
203+
204+static GdkPixbuf *
205+task_item_sized_pixbuf_for_window (TaskItem *item,
206+ WnckWindow *window,
207+ gint size)
208+{
209+ GdkPixbuf *pbuf;
210+
211+ g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
212+
213+ if (wnck_window_has_icon_name (window))
214+ {
215+ const gchar *icon_name = wnck_window_get_icon_name (window);
216+ GtkIconTheme *icon_theme = gtk_icon_theme_get_default ();
217+
218+ if (gtk_icon_theme_has_icon (icon_theme, icon_name))
219+ {
220+
221+ pbuf = gdk_pixbuf_copy (gtk_icon_theme_load_icon (icon_theme,
222+ icon_name,
223+ size,
224+ GTK_ICON_LOOKUP_FORCE_SIZE,
225+ NULL));
226+ }
227+ }
228+
229+ if (!pbuf)
230+ {
231+ pbuf = gdk_pixbuf_copy (wnck_window_get_icon (item->priv->window));
232+ }
233+
234+ gint width = gdk_pixbuf_get_width (pbuf);
235+ gint height = gdk_pixbuf_get_height (pbuf);
236+
237+ if (width > size || height > size)
238+ {
239+ gdouble scale;
240+ if (width > size)
241+ {
242+ scale = (gdouble) size / (gdouble) width;
243+ width = size;
244+ height = (int) (height * scale);
245+ }
246+ if (height > size)
247+ {
248+ scale = (gdouble) size / (gdouble) height;
249+ height = size;
250+ width = (int) (width * scale);
251+ }
252+
253+ GdkPixbuf *tmp = pbuf;
254+ pbuf = gdk_pixbuf_scale_simple (tmp, width, height, GDK_INTERP_HYPER);
255+
256+ g_object_unref (tmp);
257+ }
258+
259+ return pbuf;
260+}
261+static gboolean
262+task_item_expose_event (GtkWidget *widget,
263+ GdkEventExpose *event)
264+{
265+ cairo_t *cr;
266+ TaskItem *item;
267+ GdkRectangle area;
268+ TaskItemPrivate *priv;
269+
270+ g_return_val_if_fail (widget != NULL, FALSE);
271+ g_return_val_if_fail (TASK_IS_ITEM (widget), FALSE);
272+ g_return_val_if_fail (event != NULL, FALSE);
273+
274+ if (event->count > 0)
275+ return FALSE;
276+
277+ item = TASK_ITEM (widget);
278+ priv = item->priv;
279+
280+ g_return_val_if_fail (WNCK_IS_WINDOW (item->priv->window), FALSE);
281+
282+ area = event->area;
283+ cr = gdk_cairo_create (event->window);
284+
285+ GdkPixbuf *pbuf = priv->pixbuf;
286+
287+ gint size = MIN (area.height, area.width);
288+
289+ if (GDK_IS_PIXBUF (pbuf) && (gdk_pixbuf_get_width (pbuf) > size ||
290+ gdk_pixbuf_get_height (pbuf) > size))
291+ {
292+ g_object_unref (pbuf);
293+ pbuf = NULL;
294+ }
295+
296+ if (!pbuf)
297+ {
298+ pbuf = task_item_sized_pixbuf_for_window (item, priv->window, size);
299+ }
300+
301+ gdk_cairo_set_source_pixbuf (cr,
302+ pbuf,
303+ (area.width - gdk_pixbuf_get_width (pbuf)) / 2,
304+ (area.height - gdk_pixbuf_get_height (pbuf)) / 2);
305+
306+ g_object_unref (pbuf);
307+
308+ if (wnck_window_or_transient_needs_attention (priv->window))
309+ {
310+ GTimeVal current_time;
311+ g_get_current_time (&current_time);
312+
313+ gdouble ms = (current_time.tv_sec - priv->urgent_time.tv_sec) * 1000 +
314+ (current_time.tv_usec - priv->urgent_time.tv_usec) / 1000;
315+
316+ gdouble alpha = .75 + (cos (ms / 500) / 4);
317+ cairo_paint_with_alpha (cr, alpha);
318+ }
319+ else if (wnck_window_is_active (priv->window))
320+ {
321+ cairo_paint (cr);
322+ }
323+ else
324+ {
325+ cairo_paint_with_alpha (cr, .6);
326+ }
327+
328+ cairo_destroy (cr);
329+
330+ return FALSE;
331+}
332+
333+static void
334+on_size_allocate (GtkWidget *widget,
335+ GtkAllocation *allocation,
336+ TaskItem *item)
337+{
338+ if (allocation->width != allocation->height)
339+ gtk_widget_set_size_request (widget, allocation->height, -1);
340+
341+ update_hints (item);
342+}
343+
344+static gboolean
345+on_button_pressed (GtkWidget *button,
346+ GdkEventButton *event,
347+ TaskItem *item)
348+{
349+ WnckWindow *window;
350+ g_return_val_if_fail (TASK_IS_ITEM (item), FALSE);
351+ window = item->priv->window;
352+ g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
353+
354+ if (event->button == 3)
355+ {
356+ GtkWidget *menu = wnck_action_menu_new (window);
357+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
358+ event->button, event->time);
359+ return TRUE;
360+ }
361+
362+ return FALSE;
363+}
364+
365+static gboolean
366+on_query_tooltip (GtkWidget *widget,
367+ gint x, gint y,
368+ gboolean keyboard_mode,
369+ GtkTooltip *tooltip,
370+ TaskItem *item)
371+{
372+ WnckWindow *window = item->priv->window;
373+ g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
374+
375+ gtk_tooltip_set_text (tooltip, wnck_window_get_name(window));
376+ gtk_tooltip_set_icon (tooltip, wnck_window_get_icon (window));
377+
378+ return TRUE;
379+}
380+
381+static gboolean
382+on_blink (TaskItem *item)
383+{
384+ g_return_val_if_fail (TASK_IS_ITEM (item), FALSE);
385+
386+ gtk_widget_queue_draw (GTK_WIDGET (item));
387+
388+ if (wnck_window_or_transient_needs_attention (item->priv->window))
389+ {
390+ return TRUE;
391+ }
392+ else
393+ {
394+ item->priv->timer = 0;
395+ return FALSE;
396+ }
397+}
398+
399+static void
400+on_window_state_changed (WnckWindow *window,
401+ WnckWindowState changed_mask,
402+ WnckWindowState new_state,
403+ TaskItem *item)
404+{
405+ g_return_if_fail (WNCK_IS_WINDOW (window));
406+ g_return_if_fail (TASK_IS_ITEM (item));
407+
408+ TaskItemPrivate *priv = item->priv;
409+
410+ if (new_state & WNCK_WINDOW_STATE_URGENT && !priv->timer)
411+ {
412+ priv->timer = g_timeout_add (30, (GSourceFunc)on_blink, item);
413+ g_get_current_time (&priv->urgent_time);
414+ }
415+
416+ task_item_set_visibility (item);
417+}
418+
419+static void
420+on_window_workspace_changed (WnckWindow *window, TaskItem *item)
421+{
422+ g_return_if_fail (TASK_IS_ITEM (item));
423+
424+ task_item_set_visibility (item);
425+}
426+
427+static void
428+on_screen_active_window_changed (WnckScreen *screen,
429+ WnckWindow *old_window,
430+ TaskItem *item)
431+{
432+ WnckWindow *window;
433+ TaskItemPrivate *priv;
434+
435+ g_return_if_fail (TASK_IS_ITEM (item));
436+
437+ priv = item->priv;
438+ window = priv->window;
439+
440+ g_return_if_fail (WNCK_IS_WINDOW (window));
441+
442+ if ((WNCK_IS_WINDOW (old_window) && window == old_window) ||
443+ window == wnck_screen_get_active_window (screen))
444+ {
445+ /* queue a draw to reflect that we are [no longer] the active window */
446+ gtk_widget_queue_draw (GTK_WIDGET (item));
447+ }
448+}
449+
450+static void
451+on_screen_active_workspace_changed (WnckScreen *screen,
452+ WnckWorkspace *old_workspace,
453+ TaskItem *item)
454+{
455+ g_return_if_fail (TASK_IS_ITEM (item));
456+
457+ task_item_set_visibility (item);
458+}
459+
460+static void
461+on_screen_active_viewport_changed (WnckScreen *screen,
462+ TaskItem *item)
463+{
464+ g_return_if_fail (TASK_IS_ITEM (item));
465+
466+ task_item_set_visibility (item);
467+}
468+
469+static void
470+on_screen_window_closed (WnckScreen *screen,
471+ WnckWindow *window,
472+ TaskItem *item)
473+{
474+ TaskItemPrivate *priv;
475+
476+ g_return_if_fail (TASK_IS_ITEM (item));
477+ priv = item->priv;
478+ g_return_if_fail (WNCK_IS_WINDOW (priv->window));
479+
480+ if (priv->window == window)
481+ {
482+ g_signal_handlers_disconnect_by_func (screen, G_CALLBACK (on_screen_window_closed), item);
483+ g_signal_handlers_disconnect_by_func (screen, G_CALLBACK (on_screen_active_window_changed), item);
484+ g_signal_handlers_disconnect_by_func (screen, G_CALLBACK (on_screen_active_workspace_changed), item);
485+ g_signal_handlers_disconnect_by_func (screen, G_CALLBACK (on_screen_window_closed), item);
486+ g_signal_handlers_disconnect_by_func (window, G_CALLBACK (on_window_workspace_changed), item);
487+ g_signal_handlers_disconnect_by_func (window, G_CALLBACK (on_window_state_changed), item);
488+
489+ g_signal_emit (G_OBJECT (item), task_item_signals[TASK_ITEM_CLOSED_SIGNAL], 0);
490+ }
491+}
492+
493+static gboolean
494+activate_window (GtkWidget *widget)
495+{
496+ gint active;
497+
498+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
499+
500+ active = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "drag-true"));
501+
502+ if (active)
503+ {
504+ WnckWindow *window;
505+
506+ window = (WnckWindow*)g_object_get_data (G_OBJECT (widget), "WnckWindow");
507+ if (WNCK_IS_WINDOW (window))
508+ wnck_window_activate (window, time (NULL));
509+ }
510+
511+ g_object_set_data (G_OBJECT (widget), "drag-true", GINT_TO_POINTER (0));
512+
513+ return FALSE;
514+}
515+
516+static void
517+on_drag_leave (GtkWidget *item,
518+ GdkDragContext *context,
519+ guint time)
520+{
521+ g_object_set_data (G_OBJECT (item), "drag-true", GINT_TO_POINTER (0));
522+}
523+
524+static gboolean
525+on_drag_motion (GtkWidget *item,
526+ GdkDragContext *context,
527+ gint x,
528+ gint y,
529+ guint t)
530+{
531+ gint active;
532+
533+ active = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "drag-true"));
534+
535+ if (!active)
536+ {
537+ g_object_set_data (G_OBJECT (item), "drag-true", GINT_TO_POINTER (1));
538+
539+ g_timeout_add (1000, (GSourceFunc)activate_window, item);
540+ }
541+
542+ return FALSE;
543+}
544+
545+static void
546+task_item_finalize (GObject *object)
547+{
548+ TaskItemPrivate *priv;
549+ priv = TASK_ITEM_GET_PRIVATE (object);
550+
551+ /* remove timer */
552+ if (priv->timer) g_source_remove (priv->timer);
553+
554+ G_OBJECT_CLASS (task_item_parent_class)->finalize (object);
555+}
556+
557+static void
558+task_item_class_init (TaskItemClass *klass)
559+{
560+ GObjectClass *obj_class = G_OBJECT_CLASS (klass);
561+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
562+
563+ obj_class->finalize = task_item_finalize;
564+ widget_class->expose_event = task_item_expose_event;
565+ widget_class->size_request = task_item_size_request;
566+
567+ g_type_class_add_private (obj_class, sizeof (TaskItemPrivate));
568+
569+ task_item_signals [TASK_ITEM_CLOSED_SIGNAL] =
570+ g_signal_new ("task-item-closed",
571+ G_TYPE_FROM_CLASS (klass),
572+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
573+ G_STRUCT_OFFSET (TaskItemClass, itemclosed),
574+ NULL, NULL,
575+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
576+}
577+
578+static void
579+task_item_init (TaskItem *item)
580+{
581+ TaskItemPrivate *priv;
582+ priv = item->priv = TASK_ITEM_GET_PRIVATE (item);
583+
584+ priv->timer = 0;
585+}
586+
587+GtkWidget *
588+task_item_new (WnckWindow *window)
589+{
590+ GtkWidget *item = NULL;
591+ TaskItem *task;
592+ TaskItemPrivate *priv;
593+ WnckScreen *screen;
594+
595+ g_return_val_if_fail (WNCK_IS_WINDOW (window), item);
596+
597+ item = g_object_new (TASK_TYPE_ITEM,
598+ "has-tooltip", TRUE,
599+ "visible-window", TRUE,
600+ "above-child", TRUE,
601+ NULL);
602+
603+ gtk_widget_add_events (item, GDK_ALL_EVENTS_MASK);
604+ gtk_container_set_border_width (GTK_CONTAINER (item), 0);
605+
606+ task = TASK_ITEM (item);
607+ priv = task->priv;
608+ priv->window = window;
609+
610+ screen = wnck_window_get_screen (window);
611+ priv->screen = screen;
612+
613+ gtk_drag_dest_set (item,
614+ GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
615+ drop_types, n_drop_types,
616+ GDK_ACTION_COPY);
617+ gtk_drag_dest_add_uri_targets (item);
618+ gtk_drag_dest_add_text_targets (item);
619+ g_signal_connect (item, "drag-motion",
620+ G_CALLBACK (on_drag_motion), NULL);
621+ g_signal_connect (item, "drag-leave",
622+ G_CALLBACK (on_drag_leave), NULL);
623+
624+ g_signal_connect (screen, "viewports-changed",
625+ G_CALLBACK (on_screen_active_viewport_changed), item);
626+ g_signal_connect (screen, "active-window-changed",
627+ G_CALLBACK (on_screen_active_window_changed), item);
628+ g_signal_connect (screen, "active-workspace-changed",
629+ G_CALLBACK (on_screen_active_workspace_changed), item);
630+ g_signal_connect (screen, "window-closed",
631+ G_CALLBACK (on_screen_window_closed), item);
632+
633+ g_signal_connect (window, "workspace-changed",
634+ G_CALLBACK (on_window_workspace_changed), item);
635+ g_signal_connect (window, "state-changed",
636+ G_CALLBACK (on_window_state_changed), item);
637+
638+ g_signal_connect (item, "button-release-event",
639+ G_CALLBACK (on_task_item_button_released), item);
640+ g_signal_connect (item, "button-press-event",
641+ G_CALLBACK (on_button_pressed), item);
642+ g_signal_connect (item, "size-allocate",
643+ G_CALLBACK (on_size_allocate), item);
644+ g_signal_connect (item, "query-tooltip",
645+ G_CALLBACK (on_query_tooltip), item);
646+
647+ task_item_set_visibility (task);
648+
649+ return item;
650+}
651
652=== added file 'src/task-item.h'
653--- src/task-item.h 1970-01-01 00:00:00 +0000
654+++ src/task-item.h 2009-08-20 23:49:02 +0000
655@@ -0,0 +1,72 @@
656+/*
657+ * Copyright (C) 2008 Canonical Ltd
658+ *
659+ * This program is free software: you can redistribute it and/or modify
660+ * it under the terms of the GNU General Public License version 3 as
661+ * published by the Free Software Foundation.
662+ *
663+ * This program is distributed in the hope that it will be useful,
664+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
665+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
666+ * GNU General Public License for more details.
667+ *
668+ * You should have received a copy of the GNU General Public License
669+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
670+ *
671+ * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
672+ * Jason Smith <jassmith@gmail.com>
673+ *
674+ */
675+
676+#ifndef _TASK_ITEM_H_
677+#define _TASK_ITEM_H_
678+
679+#include <glib.h>
680+#include <gtk/gtk.h>
681+#include <libwnck/libwnck.h>
682+
683+#define TASK_TYPE_ITEM (task_item_get_type ())
684+
685+#define TASK_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
686+ TASK_TYPE_ITEM, TaskItem))
687+
688+#define TASK_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
689+ TASK_TYPE_ITEM, TaskItemClass))
690+
691+#define TASK_IS_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
692+ TASK_TYPE_ITEM))
693+
694+#define TASK_IS_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
695+ TASK_TYPE_ITEM))
696+
697+#define TASK_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
698+ TASK_TYPE_ITEM, TaskItemClass))
699+
700+typedef struct _TaskItem TaskItem;
701+typedef struct _TaskItemClass TaskItemClass;
702+typedef struct _TaskItemPrivate TaskItemPrivate;
703+
704+struct _TaskItem
705+{
706+ GtkEventBox parent;
707+
708+ TaskItemPrivate *priv;
709+};
710+
711+struct _TaskItemClass
712+{
713+ GtkEventBoxClass parent_class;
714+
715+ void (* itemclosed) (TaskItem *item);
716+};
717+
718+GType task_item_get_type (void) G_GNUC_CONST;
719+
720+GtkWidget * task_item_new (WnckWindow *window);
721+
722+GtkWidget * task_item_get_default (void);
723+
724+gboolean task_item_get_desktop_visible (TaskItem *item);
725+
726+#endif /* _TASK_ITEM_H_ */
727+
728
729=== modified file 'src/task-list.c'
730--- src/task-list.c 2009-04-08 10:19:27 +0000
731+++ src/task-list.c 2009-08-21 07:06:29 +0000
732@@ -18,6 +18,7 @@
733 */
734
735 #include "task-list.h"
736+#include "task-item.h"
737
738 #include <libwnck/libwnck.h>
739
740@@ -44,109 +45,6 @@
741 PROP_SHOW_ALL_WINDOWS
742 };
743
744-/* D&D stuff */
745-static const GtkTargetEntry drop_types[] =
746-{
747- { "STRING", 0, 0 },
748- { "text/plain", 0, 0},
749- { "text/uri-list", 0, 0}
750-};
751-static const gint n_drop_types = G_N_ELEMENTS(drop_types);
752-
753-static void
754-update_hints (WnckWindow *window, GtkWidget *button)
755-{
756- GtkWidget *parent;
757- gint x, y, x1, y1;
758-
759- /* Skip problems */
760- if (!WNCK_IS_WINDOW (window)) return;
761- if (!GTK_IS_WIDGET (button)) return;
762-
763- /* Skip invisible windows */
764- if (!GTK_WIDGET_VISIBLE (button)) return;
765-
766- x = y = 0;
767-
768- /* Recursively compute the button's coordinates */
769- for (parent = button; parent; parent = parent->parent)
770- {
771- if (parent->parent)
772- {
773- x += parent->allocation.x;
774- y += parent->allocation.y;
775- }
776- else
777- {
778- x1 = y1 = 0;
779- if (GDK_IS_WINDOW (parent->window))
780- gdk_window_get_origin (parent->window, &x1, &y1);
781- x += x1; y += y1;
782- break;
783- }
784- }
785-
786- /* Set the minimize hint for the window */
787- wnck_window_set_icon_geometry (window, x, y,
788- button->allocation.width,
789- button->allocation.height);
790-}
791-
792-static void
793-set_minimize_hints (TaskList *list)
794-{
795- TaskListPrivate *priv;
796-
797- g_return_if_fail (TASK_IS_LIST (list));
798- priv = list->priv;
799-
800- g_hash_table_foreach (priv->win_table,
801- (GHFunc)update_hints,
802- NULL);
803-
804-}
805-
806-/*
807- * Show all windows code
808- */
809-static gboolean
810-ensure_list (TaskList *list)
811-{
812- TaskListPrivate *priv = list->priv;
813- WnckWorkspace *current;
814- GList *children, *c;
815-
816- current = wnck_screen_get_active_workspace (priv->screen);
817-
818- if (!WNCK_IS_WORKSPACE (current))
819- return FALSE;
820-
821- children = gtk_container_get_children (GTK_CONTAINER (list));
822- for (c = children; c; c = c->next)
823- {
824- GtkWidget *widget = c->data;
825- WnckWindow *window = g_object_get_data (G_OBJECT (widget), "WnckWindow");
826-
827- if (priv->show_all_windows
828- || (wnck_window_is_on_workspace (window, current)
829- && wnck_window_is_in_viewport (window, current)))
830- {
831- if (!wnck_window_is_skip_tasklist (window))
832- gtk_widget_show (widget);
833- }
834- else
835- {
836- gtk_widget_hide (widget);
837- }
838- }
839- g_list_free (children);
840-
841- /* Re-set minimize hints */
842- set_minimize_hints (list);
843-
844- return FALSE;
845-}
846-
847 static void
848 task_list_set_show_all_windows (TaskList *list, gboolean show_all_windows)
849 {
850@@ -154,252 +52,16 @@
851
852 priv->show_all_windows = show_all_windows;
853
854- ensure_list (list);
855-
856 g_debug ("Show all windows: %s", show_all_windows ? "true" : "false");
857 }
858
859-/* Callback */
860-static gboolean
861-on_leave_notify_event (GtkWidget *button,
862- GdkEventCrossing *event,
863- TaskList *list)
864-{
865- g_return_val_if_fail (TASK_IS_LIST (list), FALSE);
866-
867- gtk_widget_queue_draw (GTK_WIDGET (list));
868-
869- return FALSE;
870-}
871-
872-static gboolean
873-on_button_released (GtkWidget *button,
874- GdkEventButton *event,
875- WnckWindow *window)
876-{
877- g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
878-
879- if (event->button == 1)
880- {
881- WnckWorkspace *space;
882-
883- if (wnck_window_is_active (window))
884- {
885- wnck_window_minimize (window);
886- }
887- else
888- {
889- space = wnck_window_get_workspace (window);
890- wnck_workspace_activate (space, event->time);
891- wnck_window_activate (window, event->time);
892- }
893-
894- return TRUE;
895- }
896-
897- return FALSE;
898-}
899-
900-static gboolean
901-on_button_pressed (GtkWidget *button,
902- GdkEventButton *event,
903- WnckWindow *window)
904-{
905- g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
906-
907- if (event->button == 3)
908- {
909- GtkWidget *menu = wnck_action_menu_new (window);
910- gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
911- event->button, event->time);
912- return TRUE;
913- }
914-
915- return FALSE;
916-}
917-
918-static gboolean
919-on_query_tooltip (GtkWidget *button,
920- gint x, gint y,
921- gboolean keyboard_mode,
922- GtkTooltip *tooltip,
923- WnckWindow *window)
924-{
925- g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
926-
927- gtk_tooltip_set_text (tooltip, wnck_window_get_name(window));
928- gtk_tooltip_set_icon (tooltip, wnck_window_get_icon (window));
929-
930- return TRUE;
931-}
932-
933-static gboolean
934-activate_window (GtkWidget *button)
935-{
936- gint active;
937-
938- g_return_val_if_fail (GTK_IS_WIDGET (button), FALSE);
939-
940- active = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "drag-true"));
941-
942- if (active)
943- {
944- WnckWindow *window;
945-
946- window = (WnckWindow*)g_object_get_data (G_OBJECT (button), "WnckWindow");
947- if (WNCK_IS_WINDOW (window))
948- wnck_window_activate (window, time (NULL));
949- }
950-
951- g_object_set_data (G_OBJECT (button), "drag-true", GINT_TO_POINTER (0));
952-
953- return FALSE;
954-}
955-
956-static void
957-on_drag_leave (GtkWidget *button,
958- GdkDragContext *context,
959- guint time)
960-{
961- g_object_set_data (G_OBJECT (button), "drag-true", GINT_TO_POINTER (0));
962-}
963-
964-static gboolean
965-on_drag_motion (GtkWidget *button,
966- GdkDragContext *context,
967- gint x,
968- gint y,
969- guint t)
970-{
971- gint active;
972-
973- active = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "drag-true"));
974-
975- if (!active)
976- {
977- g_object_set_data (G_OBJECT (button), "drag-true", GINT_TO_POINTER (1));
978-
979- g_timeout_add (1000, (GSourceFunc)activate_window, button);
980- }
981-
982- return FALSE;
983-}
984-
985-static void
986-on_icon_changed (WnckWindow *window, GtkButton *button)
987-{
988- if (WNCK_IS_WINDOW (window) && GTK_IS_BUTTON (button))
989- {
990- gtk_image_set_from_pixbuf (GTK_IMAGE (gtk_button_get_image (button)),
991- wnck_window_get_mini_icon (window));
992- gtk_widget_queue_draw (GTK_WIDGET (button));
993- }
994-}
995-
996-static void
997-set_state (WnckWindow *window, GtkButton *button, gboolean *found)
998-{
999- TaskListPrivate *priv = TASK_LIST (task_list_get_default ())->priv;
1000-
1001- /* Skip problems */
1002- if (!WNCK_IS_WINDOW (window))
1003- return;
1004- if (!GTK_IS_WIDGET (button))
1005- return;
1006-
1007- /* Skip invisible windows */
1008- if (!GTK_WIDGET_VISIBLE (button))
1009- return;
1010-
1011- /* Skip windows that don't need attention */
1012- if (!wnck_window_or_transient_needs_attention (window))
1013- return;
1014-
1015- /* Blink the button */
1016- gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button),
1017- priv->counter & 1);
1018-
1019- /* Don't destroy the timeout */
1020- *found = TRUE;
1021-}
1022-
1023-static gboolean
1024-on_blink (TaskList *list)
1025-{
1026- TaskListPrivate *priv;
1027- gboolean found = FALSE;
1028-
1029- g_return_val_if_fail (TASK_IS_LIST (list), FALSE);
1030- priv = list->priv;
1031-
1032- /* Increment the blink counter */
1033- priv->counter ++;
1034-
1035- g_hash_table_foreach (priv->win_table,
1036- (GHFunc)set_state,
1037- &found);
1038-
1039- /* Continue the periodic timeout if needed */
1040- if (!found) priv->timer = 0;
1041- return found;
1042-}
1043-
1044-static void
1045-on_state_changed (WnckWindow *window,
1046- WnckWindowState changed_mask,
1047- WnckWindowState new_state,
1048- TaskList *list)
1049-{
1050- TaskListPrivate *priv;
1051- GtkWidget *button;
1052- WnckWorkspace *current;
1053-
1054- g_return_if_fail (WNCK_IS_WINDOW (window));
1055- g_return_if_fail (TASK_IS_LIST (list));
1056- priv = list->priv;
1057-
1058- /* Get the button */
1059- button = g_hash_table_lookup (priv->win_table, window);
1060- g_return_if_fail (GTK_IS_WIDGET (button));
1061-
1062- /* Get the workspace */
1063- current = wnck_screen_get_active_workspace (priv->screen);
1064-
1065- /* Check if the button should be hidden */
1066- if (wnck_window_is_skip_tasklist (window)
1067- || (current
1068- && !wnck_window_is_on_workspace (window, current)
1069- && !priv->show_all_windows))
1070- gtk_widget_hide (button);
1071- else
1072- {
1073- gtk_widget_show (button);
1074-
1075- /* If the window needs attention and there is no timer... */
1076- if (!priv->timer &&
1077- wnck_window_or_transient_needs_attention (window) )
1078- {
1079- /* Start the timer */
1080- priv->timer = g_timeout_add (500, (GSourceFunc)on_blink, list);
1081- priv->counter = 0;
1082- }
1083- }
1084-
1085- /* Update the button's state */
1086- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
1087- wnck_screen_get_active_window (priv->screen) == window);
1088-
1089- /* Re-set minimize hints */
1090- ensure_list (list);
1091- set_minimize_hints (list);
1092-}
1093-
1094-static void
1095-on_workspace_changed (WnckWindow *window, TaskList *list)
1096-{
1097- g_return_if_fail (TASK_IS_LIST (list));
1098-
1099- ensure_list (list);
1100+static void
1101+on_task_item_closed (TaskItem *item,
1102+ TaskList *list)
1103+{
1104+ gtk_container_remove (GTK_CONTAINER (list),
1105+ GTK_WIDGET (item));
1106+ gtk_widget_destroy (GTK_WIDGET (item));
1107 }
1108
1109 static void
1110@@ -409,7 +71,6 @@
1111 {
1112 TaskListPrivate *priv;
1113 WnckWindowType type;
1114- GtkWidget *button;
1115
1116 g_return_if_fail (TASK_IS_LIST (list));
1117 priv = list->priv;
1118@@ -422,123 +83,21 @@
1119 || type == WNCK_WINDOW_MENU)
1120 return;
1121
1122- button = g_object_new (GTK_TYPE_TOGGLE_BUTTON,
1123- "has-tooltip", TRUE,
1124- "image", gtk_image_new_from_pixbuf (
1125- wnck_window_get_mini_icon (window)),
1126- "name", "tasklist-button2",
1127- "relief", GTK_RELIEF_NONE,
1128- NULL);
1129- /* D&D */
1130- gtk_widget_add_events (GTK_WIDGET (button),GDK_ALL_EVENTS_MASK);
1131- gtk_drag_dest_set (GTK_WIDGET (button),
1132- GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
1133- drop_types, n_drop_types,
1134- GDK_ACTION_COPY);
1135- gtk_drag_dest_add_uri_targets (GTK_WIDGET (button));
1136- gtk_drag_dest_add_text_targets (GTK_WIDGET (button));
1137- g_signal_connect (button, "drag-motion",
1138- G_CALLBACK (on_drag_motion), NULL);
1139- g_signal_connect (button, "drag-leave",
1140- G_CALLBACK (on_drag_leave), NULL);
1141-
1142- gtk_box_pack_start (GTK_BOX (list), button, FALSE, FALSE, 0);
1143-
1144- g_signal_connect (button, "button-release-event",
1145- G_CALLBACK (on_button_released), window);
1146- g_signal_connect (button, "button-press-event",
1147- G_CALLBACK (on_button_pressed), window);
1148- g_signal_connect (button, "leave-notify-event",
1149- G_CALLBACK (on_leave_notify_event), list);
1150- g_signal_connect (button, "query-tooltip",
1151- G_CALLBACK (on_query_tooltip), window);
1152- g_signal_connect (window, "icon-changed",
1153- G_CALLBACK (on_icon_changed), button);
1154- g_signal_connect (window, "state-changed",
1155- G_CALLBACK (on_state_changed), list);
1156- g_signal_connect (window, "workspace-changed",
1157- G_CALLBACK (on_workspace_changed), list);
1158-
1159- g_hash_table_insert (priv->win_table, window, button);
1160- g_object_set_data (G_OBJECT (button), "WnckWindow", window);
1161-
1162- /* Do an initial state change to avoid code duplication here */
1163- on_state_changed (window, 0xFFFFFFFF, wnck_window_get_state (window), list);
1164-
1165- /* Show the window if it's button is visible (why??) */
1166+ /* Show the window if it's button is visible (why??)
1167+ BECAUSE IT'S DUMB, that explains the urgency behavior....
1168 if (GTK_WIDGET_VISIBLE (button))
1169- wnck_window_activate (window, GDK_CURRENT_TIME);
1170-}
1171-
1172-static void
1173-on_window_closed (WnckScreen *screen,
1174- WnckWindow *window,
1175- TaskList *list)
1176-{
1177- TaskListPrivate *priv;
1178- GtkWidget *button;
1179-
1180- g_return_if_fail (TASK_IS_LIST (list));
1181- priv = list->priv;
1182-
1183- button = g_hash_table_lookup (priv->win_table, window);
1184-
1185- if (GTK_IS_WIDGET (button))
1186- gtk_widget_destroy (button);
1187-
1188- g_hash_table_remove (priv->win_table, window);
1189-
1190- /* Set minimize hints */
1191- set_minimize_hints (list);
1192-}
1193-
1194-static void
1195-on_active_window_changed (WnckScreen *screen,
1196- WnckWindow *old_window,
1197- TaskList *list)
1198-{
1199- TaskListPrivate *priv;
1200- WnckWindow *act_window;
1201- GtkWidget *old_button;
1202- GtkWidget *act_button;
1203-
1204- g_return_if_fail (TASK_IS_LIST (list));
1205- priv = list->priv;
1206-
1207- old_button = g_hash_table_lookup (priv->win_table, old_window);
1208- if (GTK_IS_WIDGET (old_button))
1209- {
1210- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (old_button), FALSE);
1211- }
1212-
1213- act_window = wnck_screen_get_active_window (priv->screen);
1214- act_button = g_hash_table_lookup (priv->win_table, act_window);
1215- if (GTK_IS_WIDGET (act_button))
1216- {
1217- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (act_button), TRUE);
1218- }
1219-
1220- ensure_list (list);
1221-}
1222-
1223-static void
1224-on_active_workspace_changed (WnckScreen *screen,
1225- WnckWorkspace *old_workspace,
1226- TaskList *list)
1227-{
1228- g_return_if_fail (TASK_IS_LIST (list));
1229-
1230- ensure_list (list);
1231-}
1232-
1233-static void
1234-on_active_viewport_changed (WnckScreen *screen,
1235- TaskList *list)
1236-{
1237- g_return_if_fail (TASK_IS_LIST (list));
1238-
1239- ensure_list (list);
1240-}
1241+ wnck_window_activate (window, GDK_CURRENT_TIME); */
1242+
1243+ GtkWidget *item = task_item_new (window);
1244+
1245+ if (item)
1246+ {
1247+ gtk_box_pack_start (GTK_BOX (list), item, FALSE, FALSE, 0);
1248+ g_signal_connect (TASK_ITEM (item), "task-item-closed",
1249+ G_CALLBACK (on_task_item_closed), list);
1250+ }
1251+}
1252+
1253 /* GObject stuff */
1254 static void
1255 task_list_finalize (GObject *object)
1256@@ -635,14 +194,6 @@
1257
1258 g_signal_connect (priv->screen, "window-opened",
1259 G_CALLBACK (on_window_opened), list);
1260- g_signal_connect (priv->screen, "window-closed",
1261- G_CALLBACK (on_window_closed), list);
1262- g_signal_connect (priv->screen, "active-workspace-changed",
1263- G_CALLBACK (on_active_workspace_changed), list);
1264- g_signal_connect (priv->screen, "viewports-changed",
1265- G_CALLBACK (on_active_viewport_changed), list);
1266- g_signal_connect (priv->screen, "active-window-changed",
1267- G_CALLBACK (on_active_window_changed), list);
1268 }
1269
1270 GtkWidget *
1271@@ -656,8 +207,6 @@
1272 "spacing", 2,
1273 NULL);
1274
1275- g_idle_add ((GSourceFunc)ensure_list, list);
1276-
1277 return list;
1278 }
1279
1280@@ -675,23 +224,28 @@
1281 gboolean
1282 task_list_get_desktop_visible (TaskList *list)
1283 {
1284- GList *children, *c;
1285+ GList *windows, *w;
1286 gboolean all_minimised = TRUE;
1287
1288 g_return_val_if_fail (TASK_IS_LIST (list), TRUE);
1289
1290- children = gtk_container_get_children (GTK_CONTAINER (list));
1291- for (c = children; c; c = c->next)
1292+ windows = wnck_screen_get_windows (list->priv->screen);
1293+ for (w = windows; w; w = w->next)
1294 {
1295 WnckWindow *window;
1296
1297- window = g_object_get_data (G_OBJECT (c->data), "WnckWindow");
1298+ window = w->data;
1299
1300 if (WNCK_IS_WINDOW (window) && !wnck_window_is_minimized (window))
1301 all_minimised = FALSE;
1302 }
1303- g_list_free (children);
1304
1305 return all_minimised;
1306 }
1307
1308+gboolean
1309+task_list_get_show_all_windows (TaskList *list)
1310+{
1311+ return list->priv->show_all_windows;
1312+}
1313+
1314
1315=== modified file 'src/task-list.h'
1316--- src/task-list.h 2009-03-04 16:14:38 +0000
1317+++ src/task-list.h 2009-08-21 07:06:29 +0000
1318@@ -64,5 +64,7 @@
1319
1320 gboolean task_list_get_desktop_visible (TaskList *list);
1321
1322+gboolean task_list_get_show_all_windows (TaskList *list);
1323+
1324 #endif /* _TASK_LIST_H_ */
1325
1326
1327=== modified file 'src/task-title.c'
1328--- src/task-title.c 2009-05-04 19:57:27 +0000
1329+++ src/task-title.c 2009-08-21 09:12:47 +0000
1330@@ -43,13 +43,13 @@
1331 WnckWindow *window;
1332 GtkWidget *align;
1333 GtkWidget *box;
1334- GtkWidget *image;
1335 GtkWidget *label;
1336 GtkWidget *button;
1337 GtkWidget *button_image;
1338 GdkPixbuf *quit_icon;
1339
1340 gboolean show_home_title;
1341+ gboolean mouse_in_close_button;
1342 };
1343
1344 static void disconnect_window (TaskTitle *title);
1345@@ -87,6 +87,60 @@
1346 return TRUE;
1347 }
1348
1349+static gboolean
1350+on_enter_notify (GtkWidget *widget,
1351+ GdkEventCrossing *event,
1352+ TaskTitle *title)
1353+{
1354+ g_return_val_if_fail (TASK_IS_TITLE (title), FALSE);
1355+
1356+ title->priv->mouse_in_close_button = TRUE;
1357+ gtk_widget_queue_draw (widget);
1358+
1359+ return FALSE;
1360+}
1361+
1362+static gboolean
1363+on_leave_notify (GtkWidget *widget,
1364+ GdkEventCrossing *event,
1365+ TaskTitle *title)
1366+{
1367+ g_return_val_if_fail (TASK_IS_TITLE (title), FALSE);
1368+
1369+ title->priv->mouse_in_close_button = FALSE;
1370+ gtk_widget_queue_draw (widget);
1371+
1372+ return FALSE;
1373+}
1374+
1375+static gboolean
1376+on_button_expose (GtkWidget *widget,
1377+ GdkEventExpose *event,
1378+ TaskTitle *title)
1379+{
1380+ g_return_val_if_fail (TASK_IS_TITLE (title), FALSE);
1381+
1382+ TaskTitlePrivate *priv;
1383+ priv = title->priv;
1384+
1385+ if (priv->mouse_in_close_button)
1386+ {
1387+ GtkStyle *style = gtk_widget_get_style (widget);
1388+ gtk_paint_box (style,
1389+ event->window,
1390+ GTK_STATE_PRELIGHT,
1391+ GTK_SHADOW_NONE,
1392+ NULL,
1393+ NULL,
1394+ NULL,
1395+ event->area.x,
1396+ event->area.y + 2,
1397+ event->area.width,
1398+ event->area.height - 4);
1399+ }
1400+ return FALSE;
1401+}
1402+
1403 static void
1404 on_name_changed (WnckWindow *window, TaskTitle *title)
1405 {
1406@@ -119,8 +173,6 @@
1407 if (priv->window != window)
1408 return;
1409
1410- gtk_image_set_from_pixbuf (GTK_IMAGE (title->priv->image),
1411- wnck_window_get_mini_icon (window));
1412 gtk_widget_queue_draw (GTK_WIDGET (title));
1413 }
1414
1415@@ -196,8 +248,6 @@
1416 {
1417 if (priv->show_home_title)
1418 {
1419- gtk_image_set_from_stock (GTK_IMAGE (priv->image),
1420- GTK_STOCK_HOME, GTK_ICON_SIZE_MENU);
1421 gtk_label_set_text (GTK_LABEL (priv->label), _("Home"));
1422 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->button_image),
1423 priv->quit_icon);
1424@@ -217,8 +267,6 @@
1425 }
1426 else
1427 {
1428- gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image),
1429- wnck_window_get_mini_icon (act_window));
1430 gtk_label_set_text (GTK_LABEL (priv->label),
1431 wnck_window_get_name (act_window));
1432 gtk_image_set_from_stock (GTK_IMAGE (priv->button_image),
1433@@ -250,8 +298,6 @@
1434 if (task_list_get_desktop_visible (TASK_LIST (task_list_get_default ()))
1435 && priv->show_home_title)
1436 {
1437- gtk_image_set_from_stock (GTK_IMAGE (priv->image),
1438- GTK_STOCK_HOME, GTK_ICON_SIZE_MENU);
1439 gtk_label_set_text (GTK_LABEL (priv->label), _("Home"));
1440 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->button_image),
1441 priv->quit_icon);
1442@@ -380,13 +426,15 @@
1443 gtk_widget_set_no_show_all (priv->box, TRUE);
1444 gtk_widget_show (priv->box);
1445
1446- priv->image = gtk_image_new_from_stock (GTK_STOCK_HOME, GTK_ICON_SIZE_MENU);
1447- gtk_box_pack_start (GTK_BOX (priv->box), priv->image, FALSE, FALSE, 0);
1448- gtk_widget_show (priv->image);
1449-
1450 priv->label = gtk_label_new (_("Home"));
1451 gtk_label_set_ellipsize (GTK_LABEL (priv->label), PANGO_ELLIPSIZE_END);
1452 gtk_misc_set_alignment (GTK_MISC (priv->label), 0.0, 0.5);
1453+
1454+ PangoAttrList *attr_list = pango_attr_list_new ();
1455+ PangoAttribute *attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
1456+ pango_attr_list_insert (attr_list, attr);
1457+ gtk_label_set_attributes (GTK_LABEL (priv->label), attr_list);
1458+
1459 gtk_box_pack_start (GTK_BOX (priv->box), priv->label, TRUE, TRUE, 0);
1460 gtk_widget_show (priv->label);
1461
1462@@ -396,8 +444,15 @@
1463 NULL);
1464 gtk_box_pack_start (GTK_BOX (priv->box), priv->button, FALSE, FALSE, 0);
1465 gtk_widget_show (priv->button);
1466+
1467 g_signal_connect (priv->button, "button-release-event",
1468 G_CALLBACK (on_close_clicked), title);
1469+ g_signal_connect (priv->button, "enter-notify-event",
1470+ G_CALLBACK (on_enter_notify), title);
1471+ g_signal_connect (priv->button, "leave-notify-event",
1472+ G_CALLBACK (on_leave_notify), title);
1473+ g_signal_connect (priv->button, "expose-event",
1474+ G_CALLBACK (on_button_expose), title);
1475
1476 /* Load the quit icon. We have to do this in such a god-forsaken way
1477 because of http://bugzilla.gnome.org/show_bug.cgi?id=581359 and the

Subscribers

People subscribed via source and target branches

to all changes: