summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libmdock/mdock-item.c29
-rw-r--r--libmdock/mdock-item.h2
-rw-r--r--libmdock/mdock-widget.c226
-rw-r--r--test/mdock-standalone.c2
4 files changed, 249 insertions, 10 deletions
diff --git a/libmdock/mdock-item.c b/libmdock/mdock-item.c
index 2399e19..a9d9ad0 100644
--- a/libmdock/mdock-item.c
+++ b/libmdock/mdock-item.c
@@ -170,6 +170,24 @@ 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) {
@@ -209,13 +227,10 @@ static gboolean mdock_item_button_press(GtkWidget *widget, GdkEventButton *event
} else {
g_warning("A MDockItem has no windows and no appinfo to launch");
}
-
break;
case 3:
- gtk_menu_popup(self->priv->right_menu,
- NULL, NULL, NULL, NULL,
- event->button, event->time);
+ // Popup menu shown during press
break;
}
@@ -353,6 +368,7 @@ mdock_item_class_init(MDockItemClass *klass)
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",
@@ -437,6 +453,11 @@ void mdock_item_launch(MDockItem *self)
}
}
+GdkPixbuf *mdock_item_get_icon_pixbuf(MDockItem *self)
+{
+ return self->priv->icon;
+}
+
void mdock_item_add_window(MDockItem *self, WnckWindow *window)
{
thumbnailer_enable_for_window(window);
diff --git a/libmdock/mdock-item.h b/libmdock/mdock-item.h
index 328187e..082805e 100644
--- a/libmdock/mdock-item.h
+++ b/libmdock/mdock-item.h
@@ -60,6 +60,8 @@ 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);
+GdkPixbuf *mdock_item_get_icon_pixbuf(MDockItem *self);
+
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);
diff --git a/libmdock/mdock-widget.c b/libmdock/mdock-widget.c
index 1ce9a4d..5e3fbbd 100644
--- a/libmdock/mdock-widget.c
+++ b/libmdock/mdock-widget.c
@@ -50,6 +50,18 @@ enum {
static GParamSpec *obj_properties[N_PROPERTIES] = { NULL };
+G_DEFINE_QUARK(mdock-widget-item-iter, mdock_widget_item_iter)
+
+enum {
+ DRAG_TYPE_ITEM,
+ DRAG_TYPE_URILIST
+};
+
+static const GtkTargetEntry drag_types[] = {
+ "application/x-mdock-item", GTK_TARGET_SAME_APP, DRAG_TYPE_ITEM,
+ "text/uri-list", 0, DRAG_TYPE_URILIST
+};
+
static void save_items_to_settings(MDockWidget *self)
{
GSettings *settings = self->priv->settings;
@@ -76,6 +88,14 @@ static void save_items_to_settings(MDockWidget *self)
self->priv->loading_settings = FALSE;
}
+static void move_item_to_position(MDockWidget *self, GSequenceIter *iter, GSequenceIter *position)
+{
+ g_debug("moving item to position %d", g_sequence_iter_get_position(position));
+ gtk_box_reorder_child(GTK_BOX(self), GTK_WIDGET(g_sequence_get(iter)),
+ g_sequence_iter_get_position(position));
+ g_sequence_move(iter, position);
+}
+
static void handle_item_pinned_changed(MDockWidget *self, GParamSpec *spec, MDockItem *item)
{
if (!self->priv->loading_settings) {
@@ -83,8 +103,171 @@ static void handle_item_pinned_changed(MDockWidget *self, GParamSpec *spec, MDoc
}
}
-static void connect_item(MDockWidget *self, MDockItem *item)
+static void handle_item_drag_begin(MDockWidget *self, GdkDragContext *dc, MDockItem *item)
+{
+ g_debug("drag begin");
+ gtk_drag_set_icon_pixbuf(dc, mdock_item_get_icon_pixbuf(item), 0, 0);
+ gtk_widget_hide(GTK_WIDGET(item));
+}
+
+static void handle_item_drag_end(MDockWidget *self, GdkDragContext *dc, MDockItem *item)
+{
+ g_debug("drag end");
+ gtk_widget_show(GTK_WIDGET(item));
+}
+
+static void handle_item_drag_data_get(MDockWidget *self, GdkDragContext *dc,
+ GtkSelectionData *selection_data, guint target_type, guint timestamp, MDockItem *item)
+{
+ g_debug("data get");
+ GSequenceIter *iter = g_object_get_qdata(G_OBJECT(item), mdock_widget_item_iter_quark());
+ GDesktopAppInfo *appinfo = mdock_item_get_desktop_app_info(item);
+ gint32 position = g_sequence_iter_get_position(iter);
+
+ switch (target_type) {
+ case DRAG_TYPE_ITEM:
+ g_debug("data get item");
+ gtk_selection_data_set(selection_data, gtk_selection_data_get_target(selection_data),
+ sizeof(gint32)*8, (guchar*)&position, sizeof(gint32));
+ break;
+ case DRAG_TYPE_URILIST:
+ g_debug("data get urilist");
+ if (appinfo) {
+ const gchar *strv[2] = { g_desktop_app_info_get_filename(appinfo), NULL };
+ gtk_selection_data_set_uris(selection_data, (gchar**) strv);
+ }
+ break;
+ }
+}
+
+static void handle_item_drag_data_delete(MDockWidget *self, GdkDragContext *dc, MDockItem *item)
+{
+ g_debug("data delete");
+}
+
+static GSequenceIter * find_drop_position_at_coordinates(MDockWidget *self, gint x, gint y)
+{
+ const guint icon_size = g_settings_get_uint(self->priv->settings, "icon-size");
+ const guint spacing = gtk_box_get_spacing(GTK_BOX(self));
+ const guint offset = icon_size / 4;
+ if (gtk_orientable_get_orientation(GTK_ORIENTABLE(self)) == GTK_ORIENTATION_HORIZONTAL) {
+ g_debug("dropped in position %d", x / icon_size);
+ return g_sequence_get_iter_at_pos(self->priv->items, (x + offset) / (icon_size + spacing)) ;
+ } else {
+ return g_sequence_get_iter_at_pos(self->priv->items, (y + offset) / (icon_size + spacing));
+ }
+}
+
+static void mdock_widget_drag_data_received(GtkWidget *widget, GdkDragContext *context,
+ gint x, gint y, GtkSelectionData *selection_data,
+ guint info, guint timestamp)
{
+ g_debug("data received");
+ MDockWidget *self = MDOCK_WIDGET(widget);
+ const guchar *data = gtk_selection_data_get_data(selection_data);
+ gchar **uris;
+
+ switch (info) {
+ case DRAG_TYPE_ITEM:
+ g_debug("Got item");
+ if (data) {
+ gint32 position = *(gint32*)data;
+ g_debug("Got position %u", position);
+ GSequenceIter *iter = g_sequence_get_iter_at_pos(self->priv->items, position);
+ g_warn_if_fail(iter);
+ GSequenceIter *pos_iter = find_drop_position_at_coordinates(self, x, y);
+ move_item_to_position(self, iter, pos_iter);
+ if (mdock_item_get_pinned(MDOCK_ITEM(g_sequence_get(iter)))) {
+ save_items_to_settings(self);
+ }
+ }
+ gtk_drag_finish(context, TRUE, TRUE, timestamp);
+ break;
+ case DRAG_TYPE_URILIST:
+ uris = gtk_selection_data_get_uris(selection_data);
+ if (uris) {
+ for (int i = 0; uris[i]; i++) {
+ gchar *uri = uris[i];
+ g_debug("Got uri %s", uri);
+ }
+ g_strfreev(uris);
+ }
+
+ gtk_drag_finish(context, TRUE, FALSE, timestamp);
+ break;
+ default:
+ g_message("Drag target type not found");
+ gtk_drag_finish(context, FALSE, FALSE, timestamp);
+ break;
+ }
+}
+
+static gboolean mdock_widget_drag_drop(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint timestamp)
+{
+ GtkTargetList *target_list = gtk_drag_dest_get_target_list(widget);
+ GdkAtom target = gtk_drag_dest_find_target(widget, context, target_list);
+ guint info;
+ gboolean drag_ok = FALSE;
+
+ if (target != GDK_NONE && gtk_target_list_find(target_list, target, &info)) {
+ switch (info) {
+ case DRAG_TYPE_ITEM:
+ case DRAG_TYPE_URILIST:
+ drag_ok = TRUE;
+ break;
+ default:
+ break;
+ }
+ } else {
+ g_message("Drag target type not found");
+ }
+
+ if (drag_ok) {
+ gtk_drag_get_data(widget, context, target, timestamp);
+ } else {
+ gtk_drag_finish(context, FALSE, FALSE, timestamp);
+ }
+
+ return TRUE;
+}
+
+static gboolean mdock_widget_drag_motion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint timestamp)
+{
+ GtkTargetList *target_list = gtk_drag_dest_get_target_list(widget);
+ GdkAtom target = gtk_drag_dest_find_target(widget, context, target_list);
+ guint info;
+ gboolean drag_ok = FALSE;
+
+ if (target != GDK_NONE && gtk_target_list_find(target_list, target, &info)) {
+ switch (info) {
+ case DRAG_TYPE_ITEM:
+ gdk_drag_status(context, GDK_ACTION_MOVE, timestamp);
+ drag_ok = TRUE;
+ break;
+ case DRAG_TYPE_URILIST:
+ gdk_drag_status(context, GDK_ACTION_COPY, timestamp);
+ drag_ok = TRUE;
+ break;
+ default:
+ break;
+ }
+ } else {
+ g_message("Drag target type not found");
+ }
+
+ if (drag_ok) {
+ // TODO Draw placeholder
+ } else {
+ gdk_drag_status(context, 0, timestamp);
+ }
+
+ return TRUE;
+}
+
+static void connect_item(MDockWidget *self, MDockItem *item, GSequenceIter *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,
G_CONNECT_SWAPPED);
@@ -92,6 +275,22 @@ static void connect_item(MDockWidget *self, MDockItem *item)
g_settings_bind(self->priv->settings, "icon-size",
item, "icon-size",
G_SETTINGS_BIND_GET | G_SETTINGS_BIND_NO_SENSITIVITY);
+
+ 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, "drag-begin",
+ G_CALLBACK(handle_item_drag_begin), self,
+ G_CONNECT_SWAPPED);
+ g_signal_connect_object(item, "drag-end",
+ G_CALLBACK(handle_item_drag_end), self,
+ G_CONNECT_SWAPPED);
+ g_signal_connect_object(item, "drag-data-get",
+ G_CALLBACK(handle_item_drag_data_get), self,
+ G_CONNECT_SWAPPED);
+ g_signal_connect_object(item, "drag-data-delete",
+ G_CALLBACK(handle_item_drag_data_delete), self,
+ G_CONNECT_SWAPPED);
}
@@ -123,12 +322,18 @@ static void reload_items_from_settings(MDockWidget *self)
mdock_item_set_desktop_app_info(item, set_appinfo);
mdock_item_set_pinned(item, TRUE);
- connect_item(self, item);
-
iter = g_sequence_insert_before(seq_iter, item);
g_hash_table_insert(self->priv->desktopid_to_item, g_strdup(set_desktopid), iter);
+
+ connect_item(self, item, iter);
+
gtk_widget_show(GTK_WIDGET(item));
- gtk_box_pack_start(GTK_BOX(self), GTK_WIDGET(item), TRUE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(self), GTK_WIDGET(item), FALSE, FALSE, 0);
+ if (!g_sequence_iter_is_end(seq_iter)) {
+ // Fix the order!
+ gtk_box_reorder_child(GTK_BOX(self), GTK_WIDGET(item),
+ g_sequence_iter_get_position(iter));
+ }
}
g_object_unref(set_appinfo);
@@ -212,7 +417,7 @@ static void handle_window_opened(MDockWidget *self, WnckWindow *window, WnckScre
g_object_unref(app_info);
}
- connect_item(self, item);
+ connect_item(self, item, iter);
mdock_item_add_window(item, window);
@@ -223,7 +428,7 @@ static void handle_window_opened(MDockWidget *self, WnckWindow *window, WnckScre
g_hash_table_insert(self->priv->window_to_item, window, iter);
gtk_widget_show(GTK_WIDGET(item));
- gtk_box_pack_start(GTK_BOX(self), GTK_WIDGET(item), TRUE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(self), GTK_WIDGET(item), FALSE, FALSE, 0);
}
static void handle_settings_items_changed(MDockWidget *self, gchar *key, GSettings *settings)
@@ -327,10 +532,19 @@ static void mdock_widget_get_property(GObject *object,
static void mdock_widget_init(MDockWidget *self)
{
self->priv = MDOCK_WIDGET_GET_PRIVATE(self);
+
+ gtk_drag_dest_set(GTK_WIDGET(self), 0,
+ drag_types, G_N_ELEMENTS(drag_types),
+ GDK_ACTION_MOVE);
}
static void mdock_widget_class_init(MDockWidgetClass *klass)
{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+ widget_class->drag_data_received = mdock_widget_drag_data_received;
+ widget_class->drag_drop = mdock_widget_drag_drop;
+ widget_class->drag_motion = mdock_widget_drag_motion;
+
GObjectClass *obj_class = G_OBJECT_CLASS(klass);
obj_class->constructed = mdock_widget_constructed;
obj_class->dispose = mdock_widget_dispose;
diff --git a/test/mdock-standalone.c b/test/mdock-standalone.c
index d977dea..53453c5 100644
--- a/test/mdock-standalone.c
+++ b/test/mdock-standalone.c
@@ -42,6 +42,8 @@ int main(int argc, char **argv)
gtk_window_set_keep_above(mainwin, TRUE);
gtk_window_set_skip_taskbar_hint(mainwin, TRUE);
+ gtk_window_set_accept_focus(mainwin, FALSE);
+ gtk_window_set_resizable(mainwin, FALSE);
gtk_widget_show_all(GTK_WIDGET(mainwin));
gtk_main();