summaryrefslogtreecommitdiff
path: root/libmdock
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2015-01-24 21:06:58 +0100
committerJavier <dev.git@javispedro.com>2015-01-24 21:06:58 +0100
commitfe69cfd1ad1e98508be79b85a34a7f0c04190c91 (patch)
tree9eb5e11d3e5864a0aa4fd1e619116d421dbec799 /libmdock
parent26263b2ef8ff7356d33d9b82bffae5b508359168 (diff)
downloadmdock-fe69cfd1ad1e98508be79b85a34a7f0c04190c91.tar.gz
mdock-fe69cfd1ad1e98508be79b85a34a7f0c04190c91.zip
adding window selector popup
Diffstat (limited to 'libmdock')
-rw-r--r--libmdock/Makefile.am2
-rw-r--r--libmdock/mdock-item-window-selector.c111
-rw-r--r--libmdock/mdock-item-window-selector.h5
-rw-r--r--libmdock/mdock-item.c42
-rw-r--r--libmdock/mdock-item.h1
-rw-r--r--libmdock/mdock-widget.c189
-rw-r--r--libmdock/mdock-window.c141
-rw-r--r--libmdock/mdock-window.h41
-rw-r--r--libmdock/thumbnailer.c4
9 files changed, 508 insertions, 28 deletions
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 <gtk/gtk.h>
+#define WNCK_I_KNOW_THIS_IS_UNSTABLE 1
+#include <libwnck/libwnck.h>
+
+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 <gdk/gdkx.h>
#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
{