From fe69cfd1ad1e98508be79b85a34a7f0c04190c91 Mon Sep 17 00:00:00 2001 From: Javier Date: Sat, 24 Jan 2015 21:06:58 +0100 Subject: adding window selector popup --- libmdock/Makefile.am | 2 +- libmdock/mdock-item-window-selector.c | 111 +++++++++++++++++++- libmdock/mdock-item-window-selector.h | 5 + libmdock/mdock-item.c | 42 +++++--- libmdock/mdock-item.h | 1 + libmdock/mdock-widget.c | 189 +++++++++++++++++++++++++++++++++- libmdock/mdock-window.c | 141 +++++++++++++++++++++++++ libmdock/mdock-window.h | 41 ++++++++ libmdock/thumbnailer.c | 4 +- 9 files changed, 508 insertions(+), 28 deletions(-) create mode 100644 libmdock/mdock-window.c create mode 100644 libmdock/mdock-window.h diff --git a/libmdock/Makefile.am b/libmdock/Makefile.am index 023ed49..3abcc9d 100644 --- a/libmdock/Makefile.am +++ b/libmdock/Makefile.am @@ -1,5 +1,5 @@ lib_LTLIBRARIES = libmdock.la -libmdock_la_SOURCES = mdock-widget.h mdock-widget.c mdock-enums.h mdock-enums.c mdock-item.h mdock-item.c mdock-item-menu.c mdock-item-menu.h mdock-item-window-selector.c mdock-item-window-selector.h matcher.h matcher.c app-id.h app-id.c thumbnailer.h thumbnailer.c +libmdock_la_SOURCES = mdock-widget.h mdock-widget.c mdock-enums.h mdock-enums.c mdock-item.h mdock-item.c mdock-item-menu.c mdock-item-menu.h mdock-item-window-selector.c mdock-item-window-selector.h mdock-window.h mdock-window.c matcher.h matcher.c app-id.h app-id.c thumbnailer.h thumbnailer.c libmdock_la_CPPFLAGS = $(GTK_CFLAGS) $(GIO_CFLAGS) $(WNCK_CFLAGS) $(GTOP_CFLAGS) -D_GNU_SOURCE -DG_LOG_DOMAIN=\"libmdock\" libmdock_la_LIBADD = $(GTK_LIBS) $(GIO_LIBS) $(WNCK_LIBS) $(GTOP_LIBS) diff --git a/libmdock/mdock-item-window-selector.c b/libmdock/mdock-item-window-selector.c index c7df718..ea5ceb8 100644 --- a/libmdock/mdock-item-window-selector.c +++ b/libmdock/mdock-item-window-selector.c @@ -18,24 +18,61 @@ */ #include "mdock-item-window-selector.h" +#include "mdock-window.h" #define MDOCK_ITEM_WINDOW_SELECTOR_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), MDOCK_TYPE_ITEM_WINDOW_SELECTOR, MDockItemWindowSelectorPrivate)) +#define GLOBAL_PADDING 8 +#define WINDOW_PADDING 4 +#define APP_NAME_PADDING 8 + struct _MDockItemWindowSelectorPrivate { - GList *temp; + GSequence *windows; + GSequenceIter *active_window; + GtkLabel *app_label; + GtkBox *window_box; }; -G_DEFINE_TYPE (MDockItemWindowSelector, mdock_item_window_selector, GTK_TYPE_WINDOW) +static void mdock_item_window_selector_orientable_init(GtkOrientableIface *iface); + +G_DEFINE_TYPE_WITH_CODE(MDockItemWindowSelector, mdock_item_window_selector, GTK_TYPE_WINDOW, + G_IMPLEMENT_INTERFACE(GTK_TYPE_ORIENTABLE, mdock_item_window_selector_orientable_init)) -enum { +enum MDockItemWindowSelectorProperties { PROP_0, PROP_ITEM, - N_PROPERTIES + N_PROPERTIES, + PROP_ORIENTATION }; static GParamSpec *obj_properties[N_PROPERTIES] = { NULL }; +static GSequenceIter * find_window(MDockItemWindowSelector *self, WnckWindow *window) +{ + GSequenceIter *iter = g_sequence_get_begin_iter(self->priv->windows); + while (!g_sequence_iter_is_end(iter)) { + MDockWindow *dwin = MDOCK_WINDOW(g_sequence_get(iter)); + if (dwin->window == window) { + return iter; + } + + iter = g_sequence_iter_next(iter); + } + return NULL; +} + +static gboolean handle_window_button_release(MDockItemWindowSelector *self, GdkEventButton *event, MDockWindow *window) +{ + switch (event->button) { + case 1: + wnck_window_activate_transient(window->window, event->time); + break; + } + + return TRUE; +} + static void mdock_item_window_selector_set_property(GObject *object, guint property_id, const GValue *value, @@ -47,6 +84,10 @@ static void mdock_item_window_selector_set_property(GObject *object, g_clear_object(&self->item); self->item = g_value_dup_object(value); break; + case PROP_ORIENTATION: + gtk_orientable_set_orientation(GTK_ORIENTABLE(self->priv->window_box), + g_value_get_enum(value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; @@ -63,6 +104,10 @@ static void mdock_item_window_selector_get_property(GObject *object, case PROP_ITEM: g_value_set_object(value, self->item); break; + case PROP_ORIENTATION: + g_value_set_enum(value, + gtk_orientable_get_orientation(GTK_ORIENTABLE(self->priv->window_box))); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; @@ -71,7 +116,15 @@ static void mdock_item_window_selector_get_property(GObject *object, static void mdock_item_window_selector_constructed(GObject *object) { + GtkWindow *window = GTK_WINDOW(object); + window->type = GTK_WINDOW_POPUP; + gtk_window_set_type_hint(window, GDK_WINDOW_TYPE_HINT_TOOLTIP); + G_OBJECT_CLASS(mdock_item_window_selector_parent_class)->constructed(object); + + MDockItemWindowSelector *self = MDOCK_ITEM_WINDOW_SELECTOR(object); + gtk_label_set_text(self->priv->app_label, + mdock_item_get_display_name(self->item)); } static void mdock_item_window_selector_dispose(GObject *object) @@ -84,6 +137,10 @@ static void mdock_item_window_selector_finalize(GObject *object) G_OBJECT_CLASS(mdock_item_window_selector_parent_class)->finalize(object); } +static void mdock_item_window_selector_orientable_init(GtkOrientableIface *iface) +{ +} + static void mdock_item_window_selector_class_init(MDockItemWindowSelectorClass *klass) { @@ -103,12 +160,56 @@ mdock_item_window_selector_class_init(MDockItemWindowSelectorClass *klass) G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties(obj_class, N_PROPERTIES, obj_properties); + g_object_class_override_property(obj_class, PROP_ORIENTATION, "orientation"); } static void -mdock_item_window_selector_init (MDockItemWindowSelector *self) +mdock_item_window_selector_init(MDockItemWindowSelector *self) { self->priv = MDOCK_ITEM_WINDOW_SELECTOR_GET_PRIVATE (self); + self->priv->windows = g_sequence_new(NULL); + self->priv->app_label = GTK_LABEL(gtk_label_new(NULL)); + self->priv->window_box = GTK_BOX(gtk_hbox_new(TRUE, 1)); + gtk_container_set_border_width(GTK_CONTAINER(self), GLOBAL_PADDING); + gtk_container_add(GTK_CONTAINER(self), GTK_WIDGET(self->priv->window_box)); + gtk_box_pack_start(self->priv->window_box, GTK_WIDGET(self->priv->app_label), TRUE, TRUE, APP_NAME_PADDING); + gtk_widget_show_all(GTK_WIDGET(self->priv->window_box)); +} + +void mdock_item_window_selector_add_window(MDockItemWindowSelector *self, WnckWindow *window) +{ + MDockWindow *win = mdock_window_new(window); + g_sequence_append(self->priv->windows, win); + gtk_box_pack_start(self->priv->window_box, GTK_WIDGET(win), FALSE, FALSE, WINDOW_PADDING); + gtk_widget_hide(GTK_WIDGET(self->priv->app_label)); + gtk_widget_show(GTK_WIDGET(win)); + + g_signal_connect_object(win, "button-release-event", + G_CALLBACK(handle_window_button_release), self, + G_CONNECT_SWAPPED); +} + +void mdock_item_window_selector_remove_window(MDockItemWindowSelector *self, WnckWindow *window) +{ + GSequenceIter *iter = find_window(self, window); + g_return_if_fail(iter); + + MDockWindow *dwin = g_sequence_get(iter); + g_sequence_remove(iter); + gtk_widget_destroy(GTK_WIDGET(dwin)); + + if (g_sequence_get_length(self->priv->windows) == 0) { + gtk_widget_show(GTK_WIDGET(self->priv->app_label)); + } +} + +void mdock_item_window_selector_set_active_window(MDockItemWindowSelector *self, WnckWindow *window) +{ + GSequenceIter *iter = find_window(self, window); + g_return_if_fail(iter); + + MDockWindow *dwin = g_sequence_get(iter); + mdock_window_update_screenshot(dwin); } MDockItemWindowSelector * diff --git a/libmdock/mdock-item-window-selector.h b/libmdock/mdock-item-window-selector.h index da78b2b..86d97b0 100644 --- a/libmdock/mdock-item-window-selector.h +++ b/libmdock/mdock-item-window-selector.h @@ -47,6 +47,11 @@ struct _MDockItemWindowSelectorClass { }; GType mdock_item_window_selector_get_type(void) G_GNUC_CONST; + +void mdock_item_window_selector_add_window(MDockItemWindowSelector *self, WnckWindow *window); +void mdock_item_window_selector_remove_window(MDockItemWindowSelector *self, WnckWindow *window); +void mdock_item_window_selector_set_active_window(MDockItemWindowSelector *self, WnckWindow *window); + MDockItemWindowSelector *mdock_item_window_selector_new(MDockItem *item); G_END_DECLS diff --git a/libmdock/mdock-item.c b/libmdock/mdock-item.c index 1d899c0..67f581f 100644 --- a/libmdock/mdock-item.c +++ b/libmdock/mdock-item.c @@ -19,7 +19,6 @@ #include "mdock-enums.h" #include "mdock-item.h" -#include "thumbnailer.h" #define MDOCK_ITEM_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), MDOCK_TYPE_ITEM, MDockItemPrivate)) @@ -42,6 +41,7 @@ enum { PROP_DESKTOP_APP_INFO, PROP_ICON_SIZE, PROP_N_WINDOWS, + PROP_DISPLAY_NAME, N_PROPERTIES }; @@ -73,18 +73,6 @@ static GdkPixbuf *mdock_item_load_icon(MDockItem *self, guint icon_size) return NULL; } -static const gchar *mdock_item_get_display_name(MDockItem *self) -{ - if (self->priv->appinfo) { - return g_app_info_get_display_name(G_APP_INFO(self->priv->appinfo)); - } else if (self->priv->windows) { - WnckApplication *app = wnck_window_get_application(self->priv->windows->data); - return wnck_application_get_name(app); - } else { - return NULL; - } -} - static void mdock_item_update_icon(MDockItem *self) { g_clear_object(&self->priv->icon); @@ -189,6 +177,9 @@ static void mdock_item_get_property(GObject *object, case PROP_N_WINDOWS: g_value_set_uint(value, g_list_length(self->priv->windows)); break; + case PROP_DISPLAY_NAME: + g_value_set_string(value, mdock_item_get_display_name(self)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; @@ -216,7 +207,8 @@ static void mdock_item_init(MDockItem *self) self->priv->pinned = FALSE; self->priv->icon_size = 48; - gtk_widget_add_events(GTK_WIDGET(self), GDK_BUTTON_PRESS_MASK); + gtk_widget_add_events(GTK_WIDGET(self), + GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); } static void @@ -260,6 +252,12 @@ mdock_item_class_init(MDockItemClass *klass) 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_DISPLAY_NAME] = g_param_spec_string("display-name", + "Name of this item", + "Reads the current name of this item", + "", + 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)); @@ -287,7 +285,7 @@ void mdock_item_toggle_pinned(MDockItem *self) GDesktopAppInfo *mdock_item_get_desktop_app_info(MDockItem *self) { - return g_object_ref(self->priv->appinfo); + return self->priv->appinfo; } void mdock_item_set_desktop_app_info(MDockItem *self, GDesktopAppInfo *app_info) @@ -323,6 +321,18 @@ void mdock_item_launch(MDockItem *self) } } +const gchar *mdock_item_get_display_name(MDockItem *self) +{ + if (self->priv->appinfo) { + return g_app_info_get_display_name(G_APP_INFO(self->priv->appinfo)); + } else if (self->priv->windows) { + WnckApplication *app = wnck_window_get_application(self->priv->windows->data); + return wnck_application_get_name(app); + } else { + return NULL; + } +} + GdkPixbuf *mdock_item_get_icon_pixbuf(MDockItem *self) { return self->priv->icon; @@ -330,7 +340,6 @@ GdkPixbuf *mdock_item_get_icon_pixbuf(MDockItem *self) void mdock_item_add_window(MDockItem *self, WnckWindow *window) { - thumbnailer_enable_for_window(window); self->priv->windows = g_list_append(self->priv->windows, window); if (!self->priv->icon) { mdock_item_update_icon(self); @@ -351,7 +360,6 @@ void mdock_item_set_last_active_window(MDockItem *self, WnckWindow *window) { g_return_if_fail(g_list_find(self->priv->windows, window)); self->priv->last_active = window; - thumbnailer_update_thumbnail(window); } gint mdock_item_get_num_windows(MDockItem *self) diff --git a/libmdock/mdock-item.h b/libmdock/mdock-item.h index 649a0e2..0048a8d 100644 --- a/libmdock/mdock-item.h +++ b/libmdock/mdock-item.h @@ -60,6 +60,7 @@ GDesktopAppInfo *mdock_item_get_desktop_app_info(MDockItem *self); void mdock_item_set_desktop_app_info(MDockItem *self, GDesktopAppInfo *app_info); void mdock_item_launch(MDockItem *self); +const gchar *mdock_item_get_display_name(MDockItem *self); GdkPixbuf *mdock_item_get_icon_pixbuf(MDockItem *self); void mdock_item_add_window(MDockItem *self, WnckWindow *window); diff --git a/libmdock/mdock-widget.c b/libmdock/mdock-widget.c index af3b165..004a590 100644 --- a/libmdock/mdock-widget.c +++ b/libmdock/mdock-widget.c @@ -28,6 +28,9 @@ #include "mdock-item.h" #include "matcher.h" +#define POPUP_SHOW_TIMEOUT 200 +#define POPUP_HIDE_TIMEOUT 500 + struct _MDockWidgetPrivate { gchar *settings_path; @@ -37,6 +40,9 @@ struct _MDockWidgetPrivate GHashTable *appid_to_item; GHashTable *desktopid_to_item; GHashTable *window_to_item; + MDockItem *current_pointed_item; + MDockItem *current_popup_item; + guint popup_timer; gboolean loading_settings : 1; gboolean just_dropped : 1; }; @@ -67,6 +73,12 @@ static const GtkTargetEntry drag_types[] = { "text/uri-list", 0, DRAG_TYPE_URILIST }; +static inline MDockItemWindowSelector * selector_from_item(MDockItem *item) +{ + return g_object_get_qdata((GObject*)item, + mdock_widget_item_window_selector_quark()); +} + static void save_items_to_settings(MDockWidget *self) { GSettings *settings = self->priv->settings; @@ -101,6 +113,77 @@ static void move_item_to_position(MDockWidget *self, GSequenceIter *iter, GSeque g_sequence_move(iter, position); } +static void hide_item_popup(MDockWidget *self) +{ + g_return_if_fail(self->priv->current_popup_item); + g_debug("hiding popup %p", self->priv->current_popup_item); + + MDockItemWindowSelector *selector = + MDOCK_ITEM_WINDOW_SELECTOR(g_object_get_qdata(G_OBJECT(self->priv->current_popup_item), + mdock_widget_item_window_selector_quark())); + + gtk_widget_hide(GTK_WIDGET(selector)); + self->priv->current_popup_item = NULL; +} + +static void show_item_popup(MDockWidget *self, MDockItem *item) +{ + g_warn_if_fail(!self->priv->current_popup_item); + g_debug("showing popup %p", item); + + MDockItemWindowSelector *selector = + MDOCK_ITEM_WINDOW_SELECTOR(g_object_get_qdata(G_OBJECT(item), + mdock_widget_item_window_selector_quark())); + + // Position the popup + GtkOrientation orientation = gtk_orientable_get_orientation(GTK_ORIENTABLE(self)); + GdkWindow *item_window = gtk_widget_get_window(GTK_WIDGET(item)); + GdkScreen *screen = gdk_window_get_screen(item_window); + gint monitor_num = gdk_screen_get_monitor_at_window(screen, item_window); + GdkRectangle monitor; + GtkRequisition requisition; + gint item_x, item_y, item_w, item_h; + gint x, y; + + gdk_window_get_origin(item_window, &item_x, &item_y); + gdk_window_get_size(item_window, &item_w, &item_h); + gdk_screen_get_monitor_geometry(screen, monitor_num, &monitor); + gtk_widget_size_request(GTK_WIDGET(selector), &requisition); + + if (requisition.width > 0 || requisition.height > 0) { + if (orientation == GTK_ORIENTATION_HORIZONTAL) { + x = item_x + item_w / 2 - requisition.width / 2; + if (item_y > (monitor.y + monitor.height / 2)) { + y = item_y - requisition.height; + } else { + y = item_y + item_h; + } + } else { + y = item_y + item_y / 2 - requisition.height / 2; + if (item_x > (monitor.x + monitor.width / 2)) { + x = item_x - requisition.width; + } else { + x = item_x + item_w; + } + } + + if (x + requisition.width > monitor.x + monitor.width) { + x -= x - (monitor.x + monitor.width) + requisition.width; + } else if (x < monitor.x) { + x = monitor.x; + } + + if (y + requisition.height > monitor.y + monitor.height) { + y -= y - (monitor.y + monitor.height) + requisition.height; + } + + gtk_window_move(GTK_WINDOW(selector), x, y); + gtk_widget_show(GTK_WIDGET(selector)); + } + + self->priv->current_popup_item = item; +} + static void handle_item_pinned_changed(MDockWidget *self, GParamSpec *spec, MDockItem *item) { if (!self->priv->loading_settings) { @@ -112,6 +195,14 @@ static gboolean handle_item_button_press(MDockWidget *self, GdkEventButton *even { switch (event->button) { case 3: + if (self->priv->popup_timer) { + g_source_remove(self->priv->popup_timer); + self->priv->popup_timer = 0; + } + if (self->priv->current_popup_item) { + hide_item_popup(self); + } + gtk_menu_popup(GTK_MENU(g_object_get_qdata(G_OBJECT(item), mdock_widget_item_menu_quark())), NULL, NULL, NULL, NULL, event->button, event->time); @@ -303,9 +394,75 @@ static gboolean mdock_widget_drag_motion(GtkWidget *widget, GdkDragContext *cont return TRUE; } +static gboolean handle_popup_timer(gpointer user_data) +{ + MDockWidget *self = MDOCK_WIDGET(user_data); + if (self->priv->current_popup_item) { + hide_item_popup(self); + } else if (self->priv->current_pointed_item) { + show_item_popup(self, self->priv->current_pointed_item); + } + + self->priv->popup_timer = 0; + return G_SOURCE_REMOVE; +} + +static gboolean handle_item_enter(MDockWidget *self, GdkEventCrossing *event, MDockItem *item) +{ + g_debug("Item enter"); + self->priv->current_pointed_item = item; + if (self->priv->current_popup_item) { + if (self->priv->popup_timer) { + g_source_remove(self->priv->popup_timer); + self->priv->popup_timer = 0; + } + hide_item_popup(self); + show_item_popup(self, item); + + } else if (!self->priv->popup_timer) { + self->priv->popup_timer = g_timeout_add(POPUP_SHOW_TIMEOUT, handle_popup_timer, self); + } + return FALSE; +} + +static gboolean handle_item_leave(MDockWidget *self, GdkEventCrossing *event, MDockItem *item) +{ + g_debug("Item leave"); + g_warn_if_fail(self->priv->current_pointed_item == item); + g_warn_if_fail(!self->priv->current_popup_item || self->priv->current_pointed_item == item); + self->priv->current_pointed_item = NULL; + if (self->priv->current_popup_item && !self->priv->popup_timer) { + self->priv->popup_timer = g_timeout_add(POPUP_HIDE_TIMEOUT, handle_popup_timer, self); + } + return FALSE; +} + +static gboolean handle_item_selector_enter(MDockWidget *self, GdkEventCrossing *event, MDockItemWindowSelector *selector) +{ + g_debug("Item selector enter %d", event->detail); + if (event->detail != GDK_NOTIFY_NONLINEAR) return FALSE; + g_warn_if_fail(self->priv->current_popup_item); + if (self->priv->popup_timer) { + g_source_remove(self->priv->popup_timer); + self->priv->popup_timer = 0; + } + return FALSE; +} + +static gboolean handle_item_selector_leave(MDockWidget *self, GdkEventCrossing *event, MDockItemWindowSelector *selector) +{ + g_debug("Item selector leave %d", event->detail); + if (event->detail != GDK_NOTIFY_NONLINEAR) return FALSE; + g_warn_if_fail(self->priv->current_popup_item); + if (!self->priv->popup_timer) { + self->priv->popup_timer = g_timeout_add(POPUP_HIDE_TIMEOUT, handle_popup_timer, self); + } + return FALSE; +} + static void connect_item(MDockWidget *self, MDockItem *item, GSequenceIter *position) { - g_object_set_qdata(G_OBJECT(item), mdock_widget_item_iter_quark(), position); + g_object_set_qdata(G_OBJECT(item), mdock_widget_item_iter_quark(), position);; g_signal_connect_object(item, "notify::pinned", G_CALLBACK(handle_item_pinned_changed), self, @@ -336,12 +493,30 @@ static void connect_item(MDockWidget *self, MDockItem *item, GSequenceIter *posi g_signal_connect_object(item, "drag-data-delete", G_CALLBACK(handle_item_drag_data_delete), self, G_CONNECT_SWAPPED); + g_signal_connect_object(item, "enter-notify-event", + G_CALLBACK(handle_item_enter), self, + G_CONNECT_SWAPPED); + g_signal_connect_object(item, "leave-notify-event", + G_CALLBACK(handle_item_leave), self, + G_CONNECT_SWAPPED); + MDockItemMenu *menu = mdock_item_menu_new(item); g_object_set_qdata_full(G_OBJECT(item), mdock_widget_item_menu_quark(), - mdock_item_menu_new(item), (GDestroyNotify)gtk_widget_destroy); + menu, (GDestroyNotify)gtk_widget_destroy); + MDockItemWindowSelector *selector = mdock_item_window_selector_new(item); g_object_set_qdata_full(G_OBJECT(item), mdock_widget_item_window_selector_quark(), - mdock_item_window_selector_new(item), (GDestroyNotify)gtk_widget_destroy); + selector, (GDestroyNotify)gtk_widget_destroy); + + g_object_bind_property(self, "orientation", + selector, "orientation", + G_BINDING_DEFAULT); + g_signal_connect_object(selector, "enter-notify-event", + G_CALLBACK(handle_item_selector_enter), self, + G_CONNECT_SWAPPED); + g_signal_connect_object(selector, "leave-notify-event", + G_CALLBACK(handle_item_selector_leave), self, + G_CONNECT_SWAPPED); } @@ -403,6 +578,7 @@ static void handle_active_window_changed(MDockWidget *self, WnckWindow *previous if (iter) { MDockItem *item = MDOCK_ITEM(g_sequence_get(iter)); mdock_item_set_last_active_window(item, window); + mdock_item_window_selector_set_active_window(selector_from_item(item), window); } } @@ -421,6 +597,7 @@ static void handle_window_closed(MDockWidget *self, WnckWindow *window, WnckScre MDockItem *item = MDOCK_ITEM(g_sequence_get(iter)); mdock_item_remove_window(item, window); + mdock_item_window_selector_remove_window(selector_from_item(item), window); g_hash_table_remove(self->priv->window_to_item, window); if (!mdock_item_has_windows(item) && !mdock_item_get_pinned(item)) { @@ -428,6 +605,9 @@ static void handle_window_closed(MDockWidget *self, WnckWindow *window, WnckScre g_hash_table_foreach_remove(self->priv->appid_to_item, filter_deleted_group, iter); g_hash_table_foreach_remove(self->priv->desktopid_to_item, filter_deleted_group, iter); g_sequence_remove(iter); + if (self->priv->current_popup_item == item) { + hide_item_popup(self); + } gtk_widget_destroy(GTK_WIDGET(item)); } } @@ -443,6 +623,7 @@ static void handle_window_opened(MDockWidget *self, WnckWindow *window, WnckScre if (iter) { MDockItem *item = MDOCK_ITEM(g_sequence_get(iter)); mdock_item_add_window(item, window); + mdock_item_window_selector_add_window(selector_from_item(item), window); app_id_destroy(appid); g_hash_table_insert(self->priv->window_to_item, window, iter); return; @@ -454,6 +635,7 @@ static void handle_window_opened(MDockWidget *self, WnckWindow *window, WnckScre if (iter) { MDockItem *item = MDOCK_ITEM(g_sequence_get(iter)); mdock_item_add_window(item, window); + mdock_item_window_selector_add_window(selector_from_item(item), window); g_hash_table_insert(self->priv->appid_to_item, appid, iter); // takes ownership of appid g_hash_table_insert(self->priv->window_to_item, window, iter); return; @@ -471,6 +653,7 @@ static void handle_window_opened(MDockWidget *self, WnckWindow *window, WnckScre connect_item(self, item, iter); mdock_item_add_window(item, window); + mdock_item_window_selector_add_window(selector_from_item(item), window); g_hash_table_insert(self->priv->appid_to_item, appid, iter); // takes ownership of appid if (desktopid) { diff --git a/libmdock/mdock-window.c b/libmdock/mdock-window.c new file mode 100644 index 0000000..5707cf5 --- /dev/null +++ b/libmdock/mdock-window.c @@ -0,0 +1,141 @@ +#include "mdock-window.h" +#include "thumbnailer.h" + +#define MDOCK_WINDOW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), MDOCK_TYPE_WINDOW, MDockWindowPrivate)) + +struct _MDockWindowPrivate +{ + GtkImage *icon; + GtkLabel *title; + GtkWidget *close_btn; + GtkImage *img; +}; + +G_DEFINE_TYPE(MDockWindow, mdock_window, GTK_TYPE_TABLE) + +enum MDockItemWindowSelectorProperties { + PROP_0, + PROP_WINDOW, + N_PROPERTIES +}; + +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL }; + +static void handle_close_btn_clicked(MDockWindow *self, GtkToolButton *toolbtn) +{ + wnck_window_close(self->window, gtk_get_current_event_time()); +} + +static void mdock_window_set_property(GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + MDockWindow *self = MDOCK_WINDOW(object); + switch (property_id) { + case PROP_WINDOW: + self->window = g_value_get_object(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void mdock_window_get_property(GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + MDockWindow *self = MDOCK_WINDOW(object); + switch (property_id) { + case PROP_WINDOW: + g_value_set_object(value, self->window); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void mdock_window_constructed(GObject *object) +{ + MDockWindow *self = MDOCK_WINDOW(object); + G_OBJECT_CLASS(mdock_window_parent_class)->constructed(object); + thumbnailer_enable_for_window(self->window); + + gtk_table_resize(GTK_TABLE(self), 2, 3); + + self->priv->icon = GTK_IMAGE(gtk_image_new_from_pixbuf(wnck_window_get_icon(self->window))); + gtk_table_attach(GTK_TABLE(self), GTK_WIDGET(self->priv->icon), + 0, 1, 0, 1, 0, 0, 0, 0); + gtk_widget_show(GTK_WIDGET(self->priv->icon)); + + self->priv->title = GTK_LABEL(gtk_label_new(wnck_window_get_name(self->window))); + gtk_label_set_max_width_chars(self->priv->title, 20); + gtk_table_attach(GTK_TABLE(self), GTK_WIDGET(self->priv->title), + 1, 2, 0, 1, GTK_EXPAND | GTK_FILL | GTK_SHRINK, GTK_FILL, 0, 0); + gtk_widget_show(GTK_WIDGET(self->priv->title)); + + self->priv->close_btn = GTK_WIDGET(gtk_tool_button_new_from_stock(GTK_STOCK_CLOSE)); + gtk_table_attach(GTK_TABLE(self), self->priv->close_btn, + 2, 3, 0, 1, 0, 0, 0, 0); + if (wnck_window_get_actions(self->window) & WNCK_WINDOW_ACTION_CLOSE) { + gtk_widget_show(self->priv->close_btn); + g_signal_connect_swapped(self->priv->close_btn, "clicked", + G_CALLBACK(handle_close_btn_clicked), self); + } + + self->priv->img = GTK_IMAGE(gtk_image_new()); + gtk_table_attach(GTK_TABLE(self), GTK_WIDGET(self->priv->img), + 0, 3, 1, 2, GTK_EXPAND | GTK_FILL | GTK_SHRINK, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0); + gtk_widget_show(GTK_WIDGET(self->priv->img)); +} + +static void mdock_window_dispose(GObject *object) +{ + G_OBJECT_CLASS(mdock_window_parent_class)->dispose(object); +} + +static void mdock_window_finalize(GObject *object) +{ + G_OBJECT_CLASS(mdock_window_parent_class)->finalize(object); +} + +static void mdock_window_class_init (MDockWindowClass *klass) +{ + GObjectClass *obj_class = G_OBJECT_CLASS (klass); + obj_class->set_property = mdock_window_set_property; + obj_class->get_property = mdock_window_get_property; + obj_class->constructed = mdock_window_constructed; + obj_class->dispose = mdock_window_dispose; + obj_class->finalize = mdock_window_finalize; + + g_type_class_add_private(obj_class, sizeof (MDockWindowPrivate)); + + obj_properties[PROP_WINDOW] = g_param_spec_object("window", + "The WnckWindow corresponding to this window", + "Set the WnckWindow the options in this menu apply to", + WNCK_TYPE_WINDOW, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(obj_class, N_PROPERTIES, obj_properties); +} + +static void mdock_window_init(MDockWindow *self) +{ + self->priv = MDOCK_WINDOW_GET_PRIVATE(self); +} + +void mdock_window_update_screenshot(MDockWindow *self) +{ + g_return_if_fail(self->window); + thumbnailer_update_thumbnail(self->window); + gtk_image_set_from_pixmap(self->priv->img, + thumbnailer_get_thumbnail(self->window), NULL); +} + +MDockWindow *mdock_window_new(WnckWindow *window) +{ + return g_object_new(MDOCK_TYPE_WINDOW, "window", window, NULL); +} diff --git a/libmdock/mdock-window.h b/libmdock/mdock-window.h new file mode 100644 index 0000000..103a2d7 --- /dev/null +++ b/libmdock/mdock-window.h @@ -0,0 +1,41 @@ +#ifndef __MDOCK_WINDOW_H__ +#define __MDOCK_WINDOW_H__ + +#include +#define WNCK_I_KNOW_THIS_IS_UNSTABLE 1 +#include + +G_BEGIN_DECLS + +#define MDOCK_TYPE_WINDOW (mdock_window_get_type ()) +#define MDOCK_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MDOCK_TYPE_WINDOW, MDockWindow)) +#define MDOCK_WINDOW_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MDOCK_TYPE_WINDOW, MDockWindow const)) +#define MDOCK_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MDOCK_TYPE_WINDOW, MDockWindowClass)) +#define MDOCK_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MDOCK_TYPE_WINDOW)) +#define MDOCK_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MDOCK_TYPE_WINDOW)) +#define MDOCK_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MDOCK_TYPE_WINDOW, MDockWindowClass)) + +typedef struct _MDockWindow MDockWindow; +typedef struct _MDockWindowClass MDockWindowClass; +typedef struct _MDockWindowPrivate MDockWindowPrivate; + +struct _MDockWindow { + GtkTable parent; + WnckWindow *window; + MDockWindowPrivate *priv; +}; + +struct _MDockWindowClass { + GtkTableClass parent_class; +}; + +GType mdock_window_get_type(void) G_GNUC_CONST; + +void mdock_window_update_screenshot(MDockWindow *window); + +MDockWindow *mdock_window_new(WnckWindow *window); + + +G_END_DECLS + +#endif /* __MDOCK_WINDOW_H__ */ diff --git a/libmdock/thumbnailer.c b/libmdock/thumbnailer.c index c2adc0f..e07ba80 100644 --- a/libmdock/thumbnailer.c +++ b/libmdock/thumbnailer.c @@ -20,8 +20,8 @@ #include #include "thumbnailer.h" -#define THUMBNAIL_MAX_WIDTH 256 -#define THUMBNAIL_MAX_HEIGHT 256 +#define THUMBNAIL_MAX_WIDTH 196 +#define THUMBNAIL_MAX_HEIGHT 196 typedef struct _ThumbnailData { -- cgit v1.2.3