diff options
-rw-r--r-- | libmdock/Makefile.am | 2 | ||||
-rw-r--r-- | libmdock/matcher.c | 1 | ||||
-rw-r--r-- | libmdock/mdock-item-menu.c | 209 | ||||
-rw-r--r-- | libmdock/mdock-item-menu.h | 54 | ||||
-rw-r--r-- | libmdock/mdock-item-window-list.c | 56 | ||||
-rw-r--r-- | libmdock/mdock-item-window-list.h | 55 | ||||
-rw-r--r-- | libmdock/mdock-item.c | 203 | ||||
-rw-r--r-- | libmdock/mdock-item.h | 3 | ||||
-rw-r--r-- | libmdock/mdock-widget.c | 51 |
9 files changed, 489 insertions, 145 deletions
diff --git a/libmdock/Makefile.am b/libmdock/Makefile.am index cb8ca1d..421f656 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 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-list.c mdock-item-window-list.h 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/matcher.c b/libmdock/matcher.c index df8e8b6..129514e 100644 --- a/libmdock/matcher.c +++ b/libmdock/matcher.c @@ -154,6 +154,7 @@ static void add_desktop_info(GDesktopAppInfo *info) if (wmclass && wmclass[0]) { gchar *wmclass_lower = g_ascii_strdown(wmclass, -1); add_desktop_item_by_wmclass(wmclass_lower, info, 128000); + g_free(wmclass_lower); } if (executable && executable[0]) { diff --git a/libmdock/mdock-item-menu.c b/libmdock/mdock-item-menu.c new file mode 100644 index 0000000..e5e60fc --- /dev/null +++ b/libmdock/mdock-item-menu.c @@ -0,0 +1,209 @@ +/* + * Copyright 2015 Javier S. Pedro <dev.git@javispedro.com> + * + * This file is part of MDock. + * + * MDock is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MDock is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MDock. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <glib/gi18n.h> + +#include "mdock-item-menu.h" + +#define MDOCK_ITEM_MENU_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), MDOCK_TYPE_ITEM_MENU, MDockItemMenuPrivate)) + +struct _MDockItemMenuPrivate +{ + GtkSeparatorMenuItem *menu_sep1; + GtkImageMenuItem *menu_close_all; + GtkImageMenuItem *menu_pin; + GtkImageMenuItem *menu_launch; +}; + +G_DEFINE_TYPE (MDockItemMenu, mdock_item_menu, GTK_TYPE_MENU) + +enum { + PROP_0, + PROP_ITEM, + N_PROPERTIES +}; + +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL }; + +static void handle_item_pinned(MDockItemMenu *self, GParamSpec *spec, MDockItem *item) +{ + const gboolean pinned = mdock_item_get_pinned(item); + gtk_menu_item_set_label(GTK_MENU_ITEM(self->priv->menu_pin), + pinned ? _("Un_pin") : _("_Pin")); +} + +static void handle_item_desktop_app_info(MDockItemMenu *self, GParamSpec *spec, MDockItem *item) +{ + GDesktopAppInfo *appinfo = mdock_item_get_desktop_app_info(item); + + gtk_widget_set_visible(GTK_WIDGET(self->priv->menu_pin), appinfo != NULL); + gtk_widget_set_visible(GTK_WIDGET(self->priv->menu_launch), appinfo != NULL); + + if (!gtk_image_menu_item_get_image(self->priv->menu_launch) && appinfo) { + gint width, height; + if (gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height)) { + GtkIconTheme *theme = gtk_icon_theme_get_default(); + gint icon_size = MAX(width, height); + GIcon *icon = g_app_info_get_icon(G_APP_INFO(appinfo)); + GtkIconInfo *info = gtk_icon_theme_lookup_by_gicon(theme, icon, icon_size, + GTK_ICON_LOOKUP_GENERIC_FALLBACK | GTK_ICON_LOOKUP_FORCE_SIZE); + if (info) { + GdkPixbuf *pixbuf = gtk_icon_info_load_icon(info, NULL); + if (pixbuf) { + GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf); + gtk_image_menu_item_set_image(self->priv->menu_launch, image); + g_object_unref(pixbuf); + } + gtk_icon_info_free(info); + } + } + } +} + +static void handle_item_n_windows(MDockItemMenu *self, GParamSpec *spec, MDockItem *item) +{ + gtk_widget_set_visible(GTK_WIDGET(self->priv->menu_close_all), + mdock_item_has_windows(item)); +} + +static void mdock_item_menu_set_property(GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + MDockItemMenu *self = MDOCK_ITEM_MENU(object); + switch (property_id) { + case PROP_ITEM: + g_clear_object(&self->item); + self->item = g_value_dup_object(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void mdock_item_menu_get_property(GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + MDockItemMenu *self = MDOCK_ITEM_MENU(object); + switch (property_id) { + case PROP_ITEM: + g_value_set_object(value, self->item); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void +mdock_item_menu_constructed(GObject *object) +{ + MDockItemMenu *self = MDOCK_ITEM_MENU(object); + + g_signal_connect_object(self->priv->menu_close_all, "activate", + G_CALLBACK(mdock_item_close_all_windows), self->item, + G_CONNECT_SWAPPED); + + g_signal_connect_object(self->priv->menu_pin, "activate", + G_CALLBACK(mdock_item_toggle_pinned), self->item, + G_CONNECT_SWAPPED); + + g_signal_connect_object(self->priv->menu_launch, "activate", + G_CALLBACK(mdock_item_launch), self->item, + G_CONNECT_SWAPPED); + + g_signal_connect_object(self->item, "notify::pinned", + G_CALLBACK(handle_item_pinned), self, + G_CONNECT_SWAPPED); + + g_signal_connect_object(self->item, "notify::desktop-app-info", + G_CALLBACK(handle_item_desktop_app_info), self, + G_CONNECT_SWAPPED); + + g_signal_connect_object(self->item, "notify::n-windows", + G_CALLBACK(handle_item_n_windows), self, + G_CONNECT_SWAPPED); + + handle_item_desktop_app_info(self, NULL, self->item); + handle_item_pinned(self, NULL, self->item); +} + + +static void +mdock_item_menu_dispose(GObject *object) +{ + MDockItemMenu *self = MDOCK_ITEM_MENU(object); + g_clear_object(&self->item); + G_OBJECT_CLASS (mdock_item_menu_parent_class)->dispose(object); +} + +static void +mdock_item_menu_finalize (GObject *object) +{ + G_OBJECT_CLASS (mdock_item_menu_parent_class)->finalize (object); +} + +static void +mdock_item_menu_init (MDockItemMenu *self) +{ + self->priv = MDOCK_ITEM_MENU_GET_PRIVATE (self); + + self->priv->menu_sep1 = GTK_SEPARATOR_MENU_ITEM(gtk_separator_menu_item_new()); + gtk_menu_shell_append(GTK_MENU_SHELL(self), GTK_WIDGET(self->priv->menu_sep1)); + + self->priv->menu_close_all = GTK_IMAGE_MENU_ITEM(gtk_image_menu_item_new_from_stock(GTK_STOCK_CLOSE, NULL)); + gtk_menu_shell_append(GTK_MENU_SHELL(self), GTK_WIDGET(self->priv->menu_close_all)); + + self->priv->menu_pin = GTK_IMAGE_MENU_ITEM(gtk_image_menu_item_new_with_mnemonic(_("_Pin"))); + gtk_menu_shell_append(GTK_MENU_SHELL(self), GTK_WIDGET(self->priv->menu_pin)); + + self->priv->menu_launch = GTK_IMAGE_MENU_ITEM(gtk_image_menu_item_new_with_mnemonic(_("_New instance"))); + gtk_menu_shell_append(GTK_MENU_SHELL(self), GTK_WIDGET(self->priv->menu_launch)); +} + +static void +mdock_item_menu_class_init (MDockItemMenuClass *klass) +{ + GObjectClass *obj_class = G_OBJECT_CLASS (klass); + obj_class->set_property = mdock_item_menu_set_property; + obj_class->get_property = mdock_item_menu_get_property; + obj_class->constructed = mdock_item_menu_constructed; + obj_class->dispose = mdock_item_menu_dispose; + obj_class->finalize = mdock_item_menu_finalize; + + g_type_class_add_private(obj_class, sizeof(MDockItemMenuPrivate)); + + obj_properties[PROP_ITEM] = g_param_spec_object("item", + "The MDockItem the options in this menu apply to", + "Set the MDockItem the options in this menu apply to", + MDOCK_TYPE_ITEM, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(obj_class, N_PROPERTIES, obj_properties); +} + +MDockItemMenu * +mdock_item_menu_new(MDockItem *item) +{ + return g_object_new(MDOCK_TYPE_ITEM_MENU, "item", item, NULL); +} diff --git a/libmdock/mdock-item-menu.h b/libmdock/mdock-item-menu.h new file mode 100644 index 0000000..b81c311 --- /dev/null +++ b/libmdock/mdock-item-menu.h @@ -0,0 +1,54 @@ +/* + * Copyright 2015 Javier S. Pedro <dev.git@javispedro.com> + * + * This file is part of MDock. + * + * MDock is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MDock is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MDock. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __MDOCK_ITEM_MENU_H__ +#define __MDOCK_ITEM_MENU_H__ + +#include "mdock-item.h" + +G_BEGIN_DECLS + +#define MDOCK_TYPE_ITEM_MENU (mdock_item_menu_get_type ()) +#define MDOCK_ITEM_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MDOCK_TYPE_ITEM_MENU, MDockItemMenu)) +#define MDOCK_ITEM_MENU_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MDOCK_TYPE_ITEM_MENU, MDockItemMenu const)) +#define MDOCK_ITEM_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MDOCK_TYPE_ITEM_MENU, MDockItemMenuClass)) +#define MDOCK_IS_ITEM_MENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MDOCK_TYPE_ITEM_MENU)) +#define MDOCK_IS_ITEM_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MDOCK_TYPE_ITEM_MENU)) +#define MDOCK_ITEM_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MDOCK_TYPE_ITEM_MENU, MDockItemMenuClass)) + +typedef struct _MDockItemMenu MDockItemMenu; +typedef struct _MDockItemMenuClass MDockItemMenuClass; +typedef struct _MDockItemMenuPrivate MDockItemMenuPrivate; + +struct _MDockItemMenu { + GtkMenu parent; + MDockItem *item; + MDockItemMenuPrivate *priv; +}; + +struct _MDockItemMenuClass { + GtkMenuClass parent_class; +}; + +GType mdock_item_menu_get_type(void) G_GNUC_CONST; +MDockItemMenu *mdock_item_menu_new(MDockItem *item); + +G_END_DECLS + +#endif /* __MDOCK_ITEM_MENU_H__ */ diff --git a/libmdock/mdock-item-window-list.c b/libmdock/mdock-item-window-list.c new file mode 100644 index 0000000..ebaedd3 --- /dev/null +++ b/libmdock/mdock-item-window-list.c @@ -0,0 +1,56 @@ +/* + * Copyright 2015 Javier S. Pedro <dev.git@javispedro.com> + * + * This file is part of MDock. + * + * MDock is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MDock is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MDock. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "mdock-item-window-list.h" + +#define MDOCK_ITEM_WINDOW_LIST_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), MDOCK_TYPE_ITEM_WINDOW_LIST, MDockItemWindowListPrivate)) + +struct _MDockItemWindowListPrivate +{ +}; + +G_DEFINE_TYPE (MDockItemWindowList, mdock_item_window_list, GTK_TYPE_WINDOW) + +static void +mdock_item_window_list_finalize (GObject *object) +{ + G_OBJECT_CLASS (mdock_item_window_list_parent_class)->finalize (object); +} + +static void +mdock_item_window_list_class_init (MDockItemWindowListClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = mdock_item_window_list_finalize; + + g_type_class_add_private (object_class, sizeof (MDockItemWindowListPrivate)); +} + +static void +mdock_item_window_list_init (MDockItemWindowList *self) +{ + self->priv = MDOCK_ITEM_WINDOW_LIST_GET_PRIVATE (self); +} + +MDockItemWindowList * +mdock_item_window_list_new () +{ + return g_object_new (MDOCK_TYPE_ITEM_WINDOW_LIST, NULL); +} diff --git a/libmdock/mdock-item-window-list.h b/libmdock/mdock-item-window-list.h new file mode 100644 index 0000000..b353c46 --- /dev/null +++ b/libmdock/mdock-item-window-list.h @@ -0,0 +1,55 @@ +/* + * Copyright 2015 Javier S. Pedro <dev.git@javispedro.com> + * + * This file is part of MDock. + * + * MDock is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MDock is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MDock. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __MDOCK_ITEM_WINDOW_LIST_H__ +#define __MDOCK_ITEM_WINDOW_LIST_H__ + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define MDOCK_TYPE_ITEM_WINDOW_LIST (mdock_item_window_list_get_type ()) +#define MDOCK_ITEM_WINDOW_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MDOCK_TYPE_ITEM_WINDOW_LIST, MdockItemWindowList)) +#define MDOCK_ITEM_WINDOW_LIST_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MDOCK_TYPE_ITEM_WINDOW_LIST, MdockItemWindowList const)) +#define MDOCK_ITEM_WINDOW_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MDOCK_TYPE_ITEM_WINDOW_LIST, MdockItemWindowListClass)) +#define MDOCK_IS_ITEM_WINDOW_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MDOCK_TYPE_ITEM_WINDOW_LIST)) +#define MDOCK_IS_ITEM_WINDOW_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MDOCK_TYPE_ITEM_WINDOW_LIST)) +#define MDOCK_ITEM_WINDOW_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MDOCK_TYPE_ITEM_WINDOW_LIST, MdockItemWindowListClass)) + +typedef struct _MDockItemWindowList MDockItemWindowList; +typedef struct _MDockItemWindowListClass MDockItemWindowListClass; +typedef struct _MDockItemWindowListPrivate MDockItemWindowListPrivate; + +struct _MDockItemWindowList { + GtkWindow parent; + + MDockItemWindowListPrivate *priv; +}; + +struct _MDockItemWindowListClass { + GtkWindowClass parent_class; +}; + +GType mdock_item_window_list_get_type (void) G_GNUC_CONST; +MDockItemWindowList *mdock_item_window_list_new (void); + + +G_END_DECLS + +#endif /* __MDOCK_ITEM_WINDOW_LIST_H__ */ diff --git a/libmdock/mdock-item.c b/libmdock/mdock-item.c index a9d9ad0..7de1264 100644 --- a/libmdock/mdock-item.c +++ b/libmdock/mdock-item.c @@ -17,7 +17,6 @@ * along with MDock. If not, see <http://www.gnu.org/licenses/>. */ -#include <glib/gi18n.h> #include "mdock-enums.h" #include "mdock-item.h" #include "mdock-item-menu.h" @@ -36,11 +35,6 @@ struct _MDockItemPrivate WnckWindow *last_active; MDockItemMenu *menu; - - GtkMenu *right_menu; - GtkImageMenuItem *menu_close_all; - GtkImageMenuItem *menu_pin; - GtkImageMenuItem *menu_launch; }; G_DEFINE_TYPE (MDockItem, mdock_item, GTK_TYPE_WIDGET) @@ -50,6 +44,7 @@ enum { PROP_PINNED, PROP_DESKTOP_APP_INFO, PROP_ICON_SIZE, + PROP_N_WINDOWS, N_PROPERTIES }; @@ -100,33 +95,6 @@ static void mdock_item_update_icon(MDockItem *self) gtk_widget_queue_draw(GTK_WIDGET(self)); } -static void mdock_item_update_tooltip(MDockItem *self) -{ - // TODO gtk_widget_set_tooltip_text(GTK_WIDGET(self), mdock_item_get_display_name(self)); -} - -static void mdock_item_update_menu(MDockItem *self) -{ - gtk_widget_set_visible(GTK_WIDGET(self->priv->menu_close_all), self->priv->windows != NULL); - gtk_widget_set_visible(GTK_WIDGET(self->priv->menu_pin), self->priv->appinfo != NULL); - if (self->priv->appinfo) { - gtk_menu_item_set_label(GTK_MENU_ITEM(self->priv->menu_pin), - self->priv->pinned ? _("Un_pin") : _("_Pin")); - } - gtk_widget_set_visible(GTK_WIDGET(self->priv->menu_launch), self->priv->appinfo != NULL); - if (!gtk_image_menu_item_get_image(self->priv->menu_launch) && self->priv->appinfo && self->priv->icon) { - gint width, height; - if (gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height)) { - GdkPixbuf *pixbuf = mdock_item_load_icon(self, MIN(width, height)); - if (pixbuf) { - GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf); - gtk_image_menu_item_set_image(self->priv->menu_launch, image); - g_object_unref(pixbuf); - } - } - } -} - static void mdock_item_realize(GtkWidget *widget) { GdkWindowAttr attributes; @@ -165,78 +133,6 @@ static void mdock_item_size_allocate(GtkWidget *widget, GtkAllocation *allocatio GTK_WIDGET_CLASS(mdock_item_parent_class)->size_allocate(widget, allocation); } -static gboolean mdock_item_button_press(GtkWidget *widget, GdkEventButton *event) -{ - MDockItem *self = MDOCK_ITEM(widget); - switch (event->button) { - case 1: - // Will activate item during release. - break; - - case 3: - gtk_menu_popup(self->priv->right_menu, - NULL, NULL, NULL, NULL, - event->button, event->time); - break; - } - - return TRUE; -} - -static gboolean mdock_item_button_release(GtkWidget *widget, GdkEventButton *event) -{ - MDockItem *self = MDOCK_ITEM(widget); - switch (event->button) { - case 1: - if (self->priv->windows) { - // This item has one window at least - if (self->priv->windows->next) { - // There is more than one window - gboolean found_window = FALSE; - for (GList *l = self->priv->windows; l; l = g_list_next(l)) { - WnckWindow *window = WNCK_WINDOW(l->data); - if (wnck_window_is_most_recently_activated(window) - || wnck_window_transient_is_most_recently_activated(window)) { - // This is the currently focused window, let's focus the next in the list - GList *n = l->next ? g_list_next(l) : self->priv->windows; - window = WNCK_WINDOW(n->data); - wnck_window_activate_transient(window, event->time); - found_window = TRUE; - break; - } - } - if (!found_window) { - WnckWindow *window = WNCK_WINDOW(self->priv->windows->data); - wnck_window_activate_transient(window, event->time); - } - } else { - // There is only one window in this group - WnckWindow *window = WNCK_WINDOW(self->priv->windows->data); - if (wnck_window_is_minimized(window)) { - wnck_window_unminimize(window, event->time); - } else if (wnck_window_is_most_recently_activated(window) - || wnck_window_transient_is_most_recently_activated(window)) { - wnck_window_minimize(window); - } else { - wnck_window_activate_transient(window, event->time); - } - } - } else if (self->priv->appinfo) { - // No windows, but we have an application to launch! - mdock_item_launch(self); - } else { - g_warning("A MDockItem has no windows and no appinfo to launch"); - } - break; - - case 3: - // Popup menu shown during press - break; - } - - return TRUE; -} - static gboolean mdock_item_expose(GtkWidget *widget, GdkEventExpose *event) { MDockItem *self = MDOCK_ITEM(widget); @@ -261,13 +157,10 @@ static void mdock_item_set_property(GObject *object, switch (property_id) { case PROP_PINNED: self->priv->pinned = g_value_get_boolean(value); - mdock_item_update_menu(self); break; case PROP_DESKTOP_APP_INFO: self->priv->appinfo = g_value_dup_object(value); mdock_item_update_icon(self); - mdock_item_update_tooltip(self); - mdock_item_update_menu(self); break; case PROP_ICON_SIZE: self->priv->icon_size = g_value_get_uint(value); @@ -296,6 +189,9 @@ static void mdock_item_get_property(GObject *object, case PROP_ICON_SIZE: g_value_set_uint(value, self->priv->icon_size); break; + case PROP_N_WINDOWS: + g_value_set_uint(value, g_list_length(self->priv->windows)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; @@ -308,10 +204,6 @@ static void mdock_item_dispose(GObject *object) g_clear_object(&self->priv->appinfo); g_clear_object(&self->priv->icon); g_clear_object(&self->priv->menu); - g_clear_object(&self->priv->right_menu); - g_clear_object(&self->priv->menu_close_all); - g_clear_object(&self->priv->menu_pin); - g_clear_object(&self->priv->menu_launch); G_OBJECT_CLASS(mdock_item_parent_class)->dispose(object); } @@ -329,29 +221,6 @@ static void mdock_item_init(MDockItem *self) self->priv->icon_size = 48; gtk_widget_add_events(GTK_WIDGET(self), GDK_BUTTON_PRESS_MASK); - - self->priv->menu = g_object_ref_sink(mdock_item_menu_new()); - gtk_widget_set_tooltip_window(GTK_WIDGET(self), GTK_WINDOW(self->priv->menu)); - - self->priv->right_menu = g_object_ref_sink(gtk_menu_new()); - - self->priv->menu_close_all = g_object_ref_sink(gtk_image_menu_item_new_from_stock(GTK_STOCK_CLOSE, NULL)); - gtk_menu_shell_append(GTK_MENU_SHELL(self->priv->right_menu), - GTK_WIDGET(self->priv->menu_close_all)); - g_signal_connect_swapped(self->priv->menu_close_all, "activate", - G_CALLBACK(mdock_item_close_all_windows), self); - - self->priv->menu_pin = g_object_ref_sink(gtk_image_menu_item_new_with_mnemonic(_("_Pin"))); - gtk_menu_shell_append(GTK_MENU_SHELL(self->priv->right_menu), - GTK_WIDGET(self->priv->menu_pin)); - g_signal_connect_swapped(self->priv->menu_pin, "activate", - G_CALLBACK(mdock_item_toggle_pinned), self); - - self->priv->menu_launch = g_object_ref_sink(gtk_image_menu_item_new_with_mnemonic(_("_New instance"))); - gtk_menu_shell_append(GTK_MENU_SHELL(self->priv->right_menu), - GTK_WIDGET(self->priv->menu_launch)); - g_signal_connect_swapped(self->priv->menu_launch, "activate", - G_CALLBACK(mdock_item_launch), self); } static void @@ -367,8 +236,6 @@ mdock_item_class_init(MDockItemClass *klass) widget_class->realize = mdock_item_realize; widget_class->size_request = mdock_item_size_request; widget_class->size_allocate = mdock_item_size_allocate; - widget_class->button_press_event = mdock_item_button_press; - widget_class->button_release_event = mdock_item_button_release; widget_class->expose_event = mdock_item_expose; obj_properties[PROP_PINNED] = g_param_spec_boolean("pinned", @@ -390,6 +257,13 @@ mdock_item_class_init(MDockItemClass *klass) 48, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_N_WINDOWS] = g_param_spec_uint("n-windows", + "Number of windows", + "Reads the current number of windows under this item", + 0, G_MAXINT32, + 0, + 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)); @@ -465,10 +339,7 @@ void mdock_item_add_window(MDockItem *self, WnckWindow *window) if (!self->priv->icon) { mdock_item_update_icon(self); } - if (!gtk_widget_get_has_tooltip(GTK_WIDGET(self))) { - mdock_item_update_tooltip(self); - } - mdock_item_update_menu(self); + g_object_notify_by_pspec(G_OBJECT(self), obj_properties[PROP_N_WINDOWS]); } void mdock_item_remove_window(MDockItem *self, WnckWindow *window) @@ -477,7 +348,7 @@ void mdock_item_remove_window(MDockItem *self, WnckWindow *window) if (self->priv->last_active == window) { self->priv->last_active = NULL; } - mdock_item_update_menu(self); + g_object_notify_by_pspec(G_OBJECT(self), obj_properties[PROP_N_WINDOWS]); } void mdock_item_set_last_active_window(MDockItem *self, WnckWindow *window) @@ -492,6 +363,11 @@ gint mdock_item_get_num_windows(MDockItem *self) return g_list_length(self->priv->windows); } +gboolean mdock_item_has_windows(MDockItem *self) +{ + return self->priv->windows ? TRUE : FALSE; +} + void mdock_item_close_all_windows(MDockItem *self) { for (GList *l = self->priv->windows; l; l = g_list_next(l)) { @@ -499,3 +375,46 @@ void mdock_item_close_all_windows(MDockItem *self) wnck_window_close(window, GDK_CURRENT_TIME); } } + +void mdock_item_activate(MDockItem *self) +{ + if (self->priv->windows) { + // This item has one window at least + if (self->priv->windows->next) { + // There is more than one window + gboolean found_window = FALSE; + for (GList *l = self->priv->windows; l; l = g_list_next(l)) { + WnckWindow *window = WNCK_WINDOW(l->data); + if (wnck_window_is_most_recently_activated(window) + || wnck_window_transient_is_most_recently_activated(window)) { + // This is the currently focused window, let's focus the next in the list + GList *n = l->next ? g_list_next(l) : self->priv->windows; + window = WNCK_WINDOW(n->data); + wnck_window_activate_transient(window, gtk_get_current_event_time()); + found_window = TRUE; + break; + } + } + if (!found_window) { + WnckWindow *window = WNCK_WINDOW(self->priv->windows->data); + wnck_window_activate_transient(window, gtk_get_current_event_time()); + } + } else { + // There is only one window in this group + WnckWindow *window = WNCK_WINDOW(self->priv->windows->data); + if (wnck_window_is_minimized(window)) { + wnck_window_unminimize(window, gtk_get_current_event_time()); + } else if (wnck_window_is_most_recently_activated(window) + || wnck_window_transient_is_most_recently_activated(window)) { + wnck_window_minimize(window); + } else { + wnck_window_activate_transient(window, gtk_get_current_event_time()); + } + } + } else if (self->priv->appinfo) { + // No windows, but we have an application to launch! + mdock_item_launch(self); + } else { + g_warning("A MDockItem has no windows and no appinfo to launch"); + } +} diff --git a/libmdock/mdock-item.h b/libmdock/mdock-item.h index 082805e..649a0e2 100644 --- a/libmdock/mdock-item.h +++ b/libmdock/mdock-item.h @@ -66,9 +66,12 @@ void mdock_item_add_window(MDockItem *self, WnckWindow *window); void mdock_item_remove_window(MDockItem *self, WnckWindow *window); void mdock_item_set_last_active_window(MDockItem *self, WnckWindow *window); gint mdock_item_get_num_windows(MDockItem *self); +gboolean mdock_item_has_windows(MDockItem *self); void mdock_item_close_all_windows(MDockItem *self); +void mdock_item_activate(MDockItem *self); + G_END_DECLS #endif /* __MDOCK_ITEM_H__ */ diff --git a/libmdock/mdock-widget.c b/libmdock/mdock-widget.c index 5e3fbbd..a97e886 100644 --- a/libmdock/mdock-widget.c +++ b/libmdock/mdock-widget.c @@ -23,6 +23,8 @@ #include <libwnck/libwnck.h> #include "mdock-widget.h" +#include "mdock-item-window-list.h" +#include "mdock-item-menu.h" #include "mdock-item.h" #include "matcher.h" @@ -35,7 +37,8 @@ struct _MDockWidgetPrivate GHashTable *appid_to_item; GHashTable *desktopid_to_item; GHashTable *window_to_item; - gboolean loading_settings; + gboolean loading_settings : 1; + gboolean just_dropped : 1; }; G_DEFINE_TYPE(MDockWidget, mdock_widget, GTK_TYPE_BOX) @@ -51,6 +54,7 @@ enum { static GParamSpec *obj_properties[N_PROPERTIES] = { NULL }; G_DEFINE_QUARK(mdock-widget-item-iter, mdock_widget_item_iter) +G_DEFINE_QUARK(mdock-widget-item-menu, mdock_widget_item_menu) enum { DRAG_TYPE_ITEM, @@ -103,6 +107,36 @@ static void handle_item_pinned_changed(MDockWidget *self, GParamSpec *spec, MDoc } } +static gboolean handle_item_button_press(MDockWidget *self, GdkEventButton *event, MDockItem *item) +{ + switch (event->button) { + case 3: + 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); + + break; + } + + return TRUE; +} + +static gboolean handle_item_button_release(MDockWidget *self, GdkEventButton *event, MDockItem *item) +{ + switch (event->button) { + case 1: + if (self->priv->just_dropped) { + self->priv->just_dropped = FALSE; + break; + } + + mdock_item_activate(item); + + break; + } + + return TRUE; +} + static void handle_item_drag_begin(MDockWidget *self, GdkDragContext *dc, MDockItem *item) { g_debug("drag begin"); @@ -204,6 +238,7 @@ static void mdock_widget_drag_data_received(GtkWidget *widget, GdkDragContext *c static gboolean mdock_widget_drag_drop(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint timestamp) { + MDockWidget *self = MDOCK_WIDGET(widget); GtkTargetList *target_list = gtk_drag_dest_get_target_list(widget); GdkAtom target = gtk_drag_dest_find_target(widget, context, target_list); guint info; @@ -222,6 +257,9 @@ static gboolean mdock_widget_drag_drop(GtkWidget *widget, GdkDragContext *contex g_message("Drag target type not found"); } + g_debug("drag drop"); + self->priv->just_dropped = TRUE; + if (drag_ok) { gtk_drag_get_data(widget, context, target, timestamp); } else { @@ -279,6 +317,12 @@ static void connect_item(MDockWidget *self, MDockItem *item, GSequenceIter *posi gtk_drag_source_set(GTK_WIDGET(item), GDK_BUTTON1_MASK, drag_types, G_N_ELEMENTS(drag_types), GDK_ACTION_MOVE); + g_signal_connect_object(item, "button-press-event", + G_CALLBACK(handle_item_button_press), self, + G_CONNECT_SWAPPED); + g_signal_connect_object(item, "button-release-event", + G_CALLBACK(handle_item_button_release), self, + G_CONNECT_SWAPPED); g_signal_connect_object(item, "drag-begin", G_CALLBACK(handle_item_drag_begin), self, G_CONNECT_SWAPPED); @@ -291,6 +335,9 @@ 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_object_set_qdata_full(G_OBJECT(item), mdock_widget_item_menu_quark(), + mdock_item_menu_new(item), (GDestroyNotify)gtk_widget_destroy); } @@ -372,7 +419,7 @@ static void handle_window_closed(MDockWidget *self, WnckWindow *window, WnckScre mdock_item_remove_window(item, window); g_hash_table_remove(self->priv->window_to_item, window); - if (mdock_item_get_num_windows(item) == 0 && !mdock_item_get_pinned(item)) { + if (!mdock_item_has_windows(item) && !mdock_item_get_pinned(item)) { // Removing item from dock 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); |