summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libmdock/Makefile.am2
-rw-r--r--libmdock/matcher.c1
-rw-r--r--libmdock/mdock-item-menu.c209
-rw-r--r--libmdock/mdock-item-menu.h54
-rw-r--r--libmdock/mdock-item-window-list.c56
-rw-r--r--libmdock/mdock-item-window-list.h55
-rw-r--r--libmdock/mdock-item.c203
-rw-r--r--libmdock/mdock-item.h3
-rw-r--r--libmdock/mdock-widget.c51
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);