From 40bee9911209e2e9e9c30bdb1a87443f7e36a3f1 Mon Sep 17 00:00:00 2001 From: Javier Date: Sat, 21 Feb 2015 16:34:35 +0100 Subject: add red dot if any window on item needs attention --- libmdock/mdock-item.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++- libmdock/mdock-item.h | 1 + 2 files changed, 56 insertions(+), 1 deletion(-) (limited to 'libmdock') diff --git a/libmdock/mdock-item.c b/libmdock/mdock-item.c index 68cfb80..6ee7b6a 100644 --- a/libmdock/mdock-item.c +++ b/libmdock/mdock-item.c @@ -31,6 +31,7 @@ struct _MDockItemPrivate guint icon_size; GdkPixbuf *icon; GList *windows; + gboolean needs_attention; }; G_DEFINE_TYPE (MDockItem, mdock_item, GTK_TYPE_WIDGET) @@ -41,6 +42,7 @@ enum { PROP_DESKTOP_APP_INFO, PROP_N_WINDOWS, PROP_DISPLAY_NAME, + PROP_NEEDS_ATTENTION, N_PROPERTIES }; @@ -107,6 +109,30 @@ static void mdock_item_update_icon_geometry(MDockItem *self) } } +static void mdock_item_update_needs_attention(MDockItem *self) +{ + gboolean needs_it = FALSE; + + for (GList *l = self->priv->windows; l; l = g_list_next(l)) { + WnckWindow *window = WNCK_WINDOW(l->data); + needs_it |= wnck_window_or_transient_needs_attention(window); + } + + if (needs_it != self->priv->needs_attention) { + self->priv->needs_attention = needs_it; + gtk_widget_queue_draw(GTK_WIDGET(self)); + g_object_notify_by_pspec(G_OBJECT(self), + obj_properties[PROP_NEEDS_ATTENTION]); + } +} + +static void handle_window_state_changed(WnckWindow *window, WnckWindowState changed_mask, WnckWindowState new_state, MDockItem *self) +{ + if (changed_mask & (WNCK_WINDOW_STATE_DEMANDS_ATTENTION | WNCK_WINDOW_STATE_URGENT)) { + mdock_item_update_needs_attention(self); + } +} + static void mdock_item_realize(GtkWidget *widget) { MDockItem *self = MDOCK_ITEM(widget); @@ -163,7 +189,11 @@ static gboolean mdock_item_expose(GtkWidget *widget, GdkEventExpose *event) if (self->priv->windows) { double circle_radius = self->priv->icon_size / 8.0; cairo_save(cr); - cairo_set_source_rgba(cr, 0.4, 0.4, 0.6, 0.8); + if (self->priv->needs_attention) { + cairo_set_source_rgba(cr, 0.9, 0.3, 0.3, 1.0); + } else { + cairo_set_source_rgba(cr, 0.4, 0.4, 0.6, 0.8); + } cairo_translate(cr, self->priv->icon_size / 2.0, self->priv->icon_size - circle_radius / 2.0 - 1.0); cairo_arc(cr, 0, 0, circle_radius, 0, 2 * M_PI); cairo_fill(cr); @@ -214,6 +244,9 @@ static void mdock_item_get_property(GObject *object, case PROP_DISPLAY_NAME: g_value_set_string(value, mdock_item_get_display_name(self)); break; + case PROP_NEEDS_ATTENTION: + g_value_set_boolean(value, self->priv->needs_attention); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; @@ -240,6 +273,7 @@ static void mdock_item_init(MDockItem *self) self->priv = MDOCK_ITEM_GET_PRIVATE (self); self->priv->pinned = FALSE; self->priv->icon_size = REQUISITION_ICON_SIZE; + self->priv->needs_attention = FALSE; gtk_widget_add_events(GTK_WIDGET(self), GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); @@ -285,6 +319,12 @@ mdock_item_class_init(MDockItemClass *klass) "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_NEEDS_ATTENTION] = g_param_spec_boolean("needs-attention", + "Needs attention", + "Whether any of the windows in this item requires attention", + FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties(obj_class, N_PROPERTIES, obj_properties); g_type_class_add_private (obj_class, sizeof (MDockItemPrivate)); @@ -386,6 +426,11 @@ GdkPixbuf *mdock_item_get_icon_pixbuf(MDockItem *self) return self->priv->icon; } +gboolean mdock_item_needs_attention(MDockItem *self) +{ + return self->priv->needs_attention; +} + void mdock_item_add_window(MDockItem *self, WnckWindow *window) { if (!self->priv->windows) { @@ -398,6 +443,11 @@ void mdock_item_add_window(MDockItem *self, WnckWindow *window) mdock_item_update_icon(self); } mdock_item_update_icon_geometry_for_window(self, window); + if (wnck_window_or_transient_needs_attention(window)) { + mdock_item_update_needs_attention(self); + } + g_signal_connect_object(window, "state-changed", + G_CALLBACK(handle_window_state_changed), self, 0); g_object_notify_by_pspec(G_OBJECT(self), obj_properties[PROP_N_WINDOWS]); } @@ -409,6 +459,10 @@ void mdock_item_remove_window(MDockItem *self, WnckWindow *window) // we want to redraw in order to remove the "active" indicator. gtk_widget_queue_draw(GTK_WIDGET(self)); } + if (wnck_window_or_transient_needs_attention(window)) { + mdock_item_update_needs_attention(self); + } + g_signal_handlers_disconnect_by_data(window, self); g_object_notify_by_pspec(G_OBJECT(self), obj_properties[PROP_N_WINDOWS]); } diff --git a/libmdock/mdock-item.h b/libmdock/mdock-item.h index 739c966..bb7a2ab 100644 --- a/libmdock/mdock-item.h +++ b/libmdock/mdock-item.h @@ -64,6 +64,7 @@ void mdock_item_launch(MDockItem *self); const gchar *mdock_item_get_display_name(MDockItem *self); GdkPixbuf *mdock_item_get_icon_pixbuf(MDockItem *self); +gboolean mdock_item_needs_attention(MDockItem *self); void mdock_item_add_window(MDockItem *self, WnckWindow *window); void mdock_item_remove_window(MDockItem *self, WnckWindow *window); -- cgit v1.2.3