[Xfce4-commits] <xfce4-panel:devel> Backport and improve the launcher dnd code.
Nick Schermer
nick at xfce.org
Tue Aug 11 20:28:44 CEST 2009
Updating branch refs/heads/devel
to de74be2cf5f10ec91ec1fbc034ebfdeed831fe83 (commit)
from 0fa56e9ec27e352f93e8de370ea8b58a243e3c58 (commit)
commit de74be2cf5f10ec91ec1fbc034ebfdeed831fe83
Author: Nick Schermer <nick at xfce.org>
Date: Fri Mar 6 23:26:33 2009 +0100
Backport and improve the launcher dnd code.
plugins/launcher/launcher.c | 271 ++++++++++++++++++++++++++++++++++++++++---
1 files changed, 253 insertions(+), 18 deletions(-)
diff --git a/plugins/launcher/launcher.c b/plugins/launcher/launcher.c
index 7aa29fd..74c4f09 100644
--- a/plugins/launcher/launcher.c
+++ b/plugins/launcher/launcher.c
@@ -34,9 +34,12 @@
#include "launcher.h"
#include "launcher-dialog.h"
-#define ARROW_BUTTON_SIZE (12)
-#define DEFAULT_MENU_ICON_SIZE (24)
-#define MENU_POPUP_DELAY (225)
+#define ARROW_BUTTON_SIZE (12)
+#define DEFAULT_MENU_ICON_SIZE (24)
+#define MENU_POPUP_DELAY (225)
+#define NO_ARROW_INSIDE_BUTTON(plugin) ((plugin)->arrow_position != LAUNCHER_ARROW_INTERNAL \
+ || LIST_HAS_ONE_OR_NO_ENTRIES ((plugin)->items))
+#define ARROW_INSIDE_BUTTON(plugin) (!NO_ARROW_INSIDE_BUTTON (plugin))
static void launcher_plugin_style_set (GtkWidget *widget, GtkStyle *previous_style);
@@ -56,6 +59,7 @@ static void launcher_plugin_pack_widgets (XfceLauncherPlugin *plugin);
static void launcher_plugin_menu_deactivate (GtkWidget *menu, XfceLauncherPlugin *plugin);
static gboolean launcher_plugin_menu_item_released (GtkMenuItem *widget, GdkEventButton *event, XfceMenuItem *item);
+static void launcher_plugin_menu_item_drag_data_received (GtkWidget *widget,GdkDragContext *context, gint x,gint y,GtkSelectionData *data, guint info, guint drag_time, XfceMenuItem *item);
static void launcher_plugin_menu_construct (XfceLauncherPlugin *plugin);
static void launcher_plugin_menu_popup_destroyed (gpointer user_data);
static gboolean launcher_plugin_menu_popup (gpointer user_data);
@@ -66,11 +70,15 @@ static void launcher_plugin_button_state_changed (GtkWidget *button_a, GtkStateT
static gboolean launcher_plugin_button_press_event (GtkWidget *button, GdkEventButton *event, XfceLauncherPlugin *plugin);
static gboolean launcher_plugin_button_release_event (GtkWidget *button, GdkEventButton *event, XfceLauncherPlugin *plugin);
static gboolean launcher_plugin_button_query_tooltip (GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, XfceLauncherPlugin *plugin);
-static void launcher_plugin_button_drag_data_received (GtkWidget *widget,GdkDragContext *context, gint x,gint y,GtkSelectionData *selection_data, guint info, guint drag_time, XfceLauncherPlugin *plugin);
+static void launcher_plugin_button_drag_data_received (GtkWidget *widget,GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint drag_time, XfceLauncherPlugin *plugin);
+static gboolean launcher_plugin_button_drag_motion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint drag_time, XfceLauncherPlugin *plugin);
+static void launcher_plugin_button_drag_leave (GtkWidget *widget, GdkDragContext *context, guint drag_time, XfceLauncherPlugin *plugin);
static gboolean launcher_plugin_button_expose_event (GtkWidget *widget, GdkEventExpose *event, XfceLauncherPlugin *launcher);
static void launcher_plugin_arrow_visibility (XfceLauncherPlugin *plugin);
static gboolean launcher_plugin_arrow_press_event (GtkWidget *button, GdkEventButton *event, XfceLauncherPlugin *plugin);
+static gboolean launcher_plugin_arrow_drag_motion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint drag_time, XfceLauncherPlugin *plugin);
+static void launcher_plugin_arrow_drag_leave (GtkWidget *widget, GdkDragContext *context, guint drag_time, XfceLauncherPlugin *plugin);
static void launcher_plugin_items_load (XfceLauncherPlugin *plugin);
static gboolean launcher_plugin_item_query_tooltip (GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, XfceMenuItem *item);
@@ -205,7 +213,7 @@ launcher_plugin_init (XfceLauncherPlugin *plugin)
xfce_panel_plugin_add_action_widget (XFCE_PANEL_PLUGIN (plugin), plugin->button);
gtk_widget_set_has_tooltip (plugin->button, TRUE);
gtk_widget_show (plugin->button);
- gtk_drag_dest_set (plugin->button, GTK_DEST_DEFAULT_ALL,
+ gtk_drag_dest_set (plugin->button, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
drop_targets, G_N_ELEMENTS (drop_targets),
GDK_ACTION_COPY);
g_signal_connect (G_OBJECT (plugin->button), "button-press-event",
@@ -216,6 +224,10 @@ launcher_plugin_init (XfceLauncherPlugin *plugin)
G_CALLBACK (launcher_plugin_button_query_tooltip), plugin);
g_signal_connect (G_OBJECT (plugin->button), "drag-data-received",
G_CALLBACK (launcher_plugin_button_drag_data_received), plugin);
+ g_signal_connect (G_OBJECT (plugin->button), "drag-motion",
+ G_CALLBACK (launcher_plugin_button_drag_motion), plugin);
+ g_signal_connect (G_OBJECT (plugin->button), "drag-leave",
+ G_CALLBACK (launcher_plugin_button_drag_leave), plugin);
g_signal_connect_after (G_OBJECT (plugin->button), "expose-event",
G_CALLBACK (launcher_plugin_button_expose_event), plugin);
@@ -227,11 +239,15 @@ launcher_plugin_init (XfceLauncherPlugin *plugin)
gtk_box_pack_start (GTK_BOX (plugin->box), plugin->arrow, FALSE, FALSE, 0);
xfce_panel_plugin_add_action_widget (XFCE_PANEL_PLUGIN (plugin), plugin->arrow);
gtk_button_set_relief (GTK_BUTTON (plugin->arrow), GTK_RELIEF_NONE);
- gtk_drag_dest_set (plugin->arrow, GTK_DEST_DEFAULT_ALL,
+ gtk_drag_dest_set (plugin->arrow, GTK_DEST_DEFAULT_MOTION,
drop_targets, G_N_ELEMENTS (drop_targets),
GDK_ACTION_COPY);
g_signal_connect (G_OBJECT (plugin->arrow), "button-press-event",
G_CALLBACK (launcher_plugin_arrow_press_event), plugin);
+ g_signal_connect (G_OBJECT (plugin->arrow), "drag-motion",
+ G_CALLBACK (launcher_plugin_arrow_drag_motion), plugin);
+ g_signal_connect (G_OBJECT (plugin->arrow), "drag-leave",
+ G_CALLBACK (launcher_plugin_arrow_drag_leave), plugin);
/* sync button states */
g_signal_connect (G_OBJECT (plugin->button), "state-changed",
@@ -650,6 +666,52 @@ launcher_plugin_menu_item_released (GtkMenuItem *widget,
static void
+launcher_plugin_menu_item_drag_data_received (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *data,
+ guint info,
+ guint drag_time,
+ XfceMenuItem *item)
+{
+ XfceLauncherPlugin *plugin;
+ GSList *uri_list;
+
+ panel_return_if_fail (GTK_IS_MENU_ITEM (widget));
+ panel_return_if_fail (XFCE_IS_MENU_ITEM (item));
+
+ /* get the plugin */
+ plugin = g_object_get_qdata (G_OBJECT (widget), launcher_plugin_quark);
+ panel_return_if_fail (XFCE_IS_LAUNCHER_PLUGIN (plugin));
+
+ /* extract the uris from the selection data */
+ uri_list = launcher_plugin_uri_list_extract (data);
+ if (G_LIKELY (uri_list != NULL))
+ {
+ /* execute the menu item */
+ launcher_plugin_item_exec (item, drag_time,
+ gtk_widget_get_screen (widget),
+ uri_list);
+
+ /* cleanup */
+ launcher_plugin_uri_list_free (uri_list);
+ }
+
+ /* hide the menu */
+ gtk_widget_hide (GTK_MENU (plugin->menu)->toplevel);
+ gtk_widget_hide (plugin->menu);
+
+ /* inactivate the toggle button */
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (plugin->arrow), FALSE);
+
+ /* finish the drag */
+ gtk_drag_finish (context, TRUE, FALSE, drag_time);
+}
+
+
+
+static void
launcher_plugin_menu_construct (XfceLauncherPlugin *plugin)
{
GtkArrowType arrow_type;
@@ -689,8 +751,15 @@ launcher_plugin_menu_construct (XfceLauncherPlugin *plugin)
g_object_set_qdata (G_OBJECT (mi), launcher_plugin_quark, plugin);
gtk_widget_set_has_tooltip (mi, TRUE);
gtk_widget_show (mi);
+ gtk_drag_dest_set (mi, GTK_DEST_DEFAULT_ALL,
+ drop_targets, G_N_ELEMENTS (drop_targets),
+ GDK_ACTION_COPY);
g_signal_connect (G_OBJECT (mi), "button-release-event",
G_CALLBACK (launcher_plugin_menu_item_released), item);
+ g_signal_connect (G_OBJECT (mi), "drag-data-received",
+ G_CALLBACK (launcher_plugin_menu_item_drag_data_received), item);
+ g_signal_connect (G_OBJECT (mi), "drag-leave",
+ G_CALLBACK (launcher_plugin_arrow_drag_leave), plugin);
/* only connect the tooltip signal if tips are enabled */
if (plugin->disable_tooltips == FALSE)
@@ -736,6 +805,7 @@ static gboolean
launcher_plugin_menu_popup (gpointer user_data)
{
XfceLauncherPlugin *plugin = XFCE_LAUNCHER_PLUGIN (user_data);
+ gint x, y;
panel_return_val_if_fail (XFCE_IS_LAUNCHER_PLUGIN (plugin), FALSE);
@@ -754,6 +824,24 @@ launcher_plugin_menu_popup (gpointer user_data)
XFCE_PANEL_PLUGIN (plugin), 1,
gtk_get_current_event_time ());
+ /* fallback to manual positioning, this is used with
+ * drag motion over the arrow button */
+ if (!GTK_WIDGET_VISIBLE (plugin->menu))
+ {
+ /* make sure the size is allocated */
+ if (!GTK_WIDGET_REALIZED (plugin->menu))
+ gtk_widget_realize (plugin->menu);
+
+ /* use the widget position function to get the coordinates */
+ xfce_panel_plugin_position_widget (XFCE_PANEL_PLUGIN (plugin),
+ plugin->menu, NULL, &x, &y);
+
+ /* bit ugly... but show the menu */
+ gtk_widget_show (plugin->menu);
+ gtk_window_move (GTK_WINDOW (GTK_MENU (plugin->menu)->toplevel), x, y);
+ gtk_widget_show (GTK_MENU (plugin->menu)->toplevel);
+ }
+
GDK_THREADS_LEAVE ();
return FALSE;
@@ -849,8 +937,7 @@ launcher_plugin_button_press_event (GtkWidget *button,
if (event->button != 1 || modifiers == GDK_CONTROL_MASK)
return FALSE;
- if (plugin->arrow_position == LAUNCHER_ARROW_INTERNAL
- && LIST_HAS_TWO_OR_MORE_ENTRIES (plugin->items))
+ if (ARROW_INSIDE_BUTTON (plugin))
{
/* directly popup the menu */
launcher_plugin_menu_popup (plugin);
@@ -886,9 +973,9 @@ launcher_plugin_button_release_event (GtkWidget *button,
g_source_remove (plugin->menu_timeout_id);
/* leave when there are no menu items or there is an internal arrow */
- if (plugin->items == NULL || GTK_BUTTON (button)->in_button == FALSE
- || (plugin->arrow_position == LAUNCHER_ARROW_INTERNAL
- && LIST_HAS_TWO_OR_MORE_ENTRIES (plugin->items)))
+ if (plugin->items == NULL
+ || GTK_BUTTON (button)->in_button == FALSE
+ || ARROW_INSIDE_BUTTON (plugin))
return FALSE;
/* get the menu item and the screen */
@@ -920,6 +1007,7 @@ launcher_plugin_button_query_tooltip (GtkWidget *widget,
/* check if we show tooltips */
if (plugin->disable_tooltips
+ || plugin->arrow_position
|| plugin->items == NULL
|| plugin->items->data == NULL)
return FALSE;
@@ -946,8 +1034,7 @@ launcher_plugin_button_drag_data_received (GtkWidget *widget,
panel_return_if_fail (XFCE_IS_LAUNCHER_PLUGIN (plugin));
/* leave when there are not items or the arrow is internal */
- if (plugin->arrow_position == LAUNCHER_ARROW_INTERNAL
- || plugin->items == NULL)
+ if (ARROW_INSIDE_BUTTON (plugin) || plugin->items == NULL)
return;
/* get the list of uris from the selection data */
@@ -964,12 +1051,62 @@ launcher_plugin_button_drag_data_received (GtkWidget *widget,
launcher_plugin_uri_list_free (uri_list);
}
+ /* finish the drag */
gtk_drag_finish (context, TRUE, FALSE, drag_time);
}
static gboolean
+launcher_plugin_button_drag_motion (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint drag_time,
+ XfceLauncherPlugin *plugin)
+{
+ panel_return_val_if_fail (XFCE_IS_LAUNCHER_PLUGIN (plugin), FALSE);
+
+ /* do nothing if the plugin is empty */
+ if (plugin->items == NULL)
+ {
+ /* not a drop zone */
+ gdk_drag_status (context, 0, drag_time);
+ return FALSE;
+ }
+
+ /* highlight the button if this is a launcher button */
+ if (NO_ARROW_INSIDE_BUTTON (plugin))
+ {
+ gtk_drag_highlight (widget);
+ return TRUE;
+ }
+
+ /* handle the popup menu */
+ return launcher_plugin_arrow_drag_motion (widget, context, x, y,
+ drag_time, plugin);
+}
+
+
+
+static void
+launcher_plugin_button_drag_leave (GtkWidget *widget,
+ GdkDragContext *context,
+ guint drag_time,
+ XfceLauncherPlugin *plugin)
+{
+ panel_return_if_fail (XFCE_IS_LAUNCHER_PLUGIN (plugin));
+
+ /* unhighlight the widget or make sure the menu is deactivated */
+ if (NO_ARROW_INSIDE_BUTTON (plugin))
+ gtk_drag_unhighlight (widget);
+ else
+ launcher_plugin_arrow_drag_leave (widget, context, drag_time, plugin);
+}
+
+
+
+static gboolean
launcher_plugin_button_expose_event (GtkWidget *widget,
GdkEventExpose *event,
XfceLauncherPlugin *plugin)
@@ -979,10 +1116,8 @@ launcher_plugin_button_expose_event (GtkWidget *widget,
panel_return_val_if_fail (XFCE_IS_LAUNCHER_PLUGIN (plugin), FALSE);
- /* leave when the arrow is not shown inside the button or there are
- * no menu items */
- if (plugin->arrow_position != LAUNCHER_ARROW_INTERNAL
- || !LIST_HAS_TWO_OR_MORE_ENTRIES (plugin->items))
+ /* leave when the arrow is not shown inside the button */
+ if (NO_ARROW_INSIDE_BUTTON (plugin))
return FALSE;
/* get the arrow type */
@@ -1065,6 +1200,104 @@ launcher_plugin_arrow_press_event (GtkWidget *button,
+
+static gboolean
+launcher_plugin_arrow_drag_motion (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint drag_time,
+ XfceLauncherPlugin *plugin)
+{
+ panel_return_val_if_fail (XFCE_IS_LAUNCHER_PLUGIN (plugin), FALSE);
+
+ /* the arrow is not a drop zone */
+ gdk_drag_status (context, 0, drag_time);
+
+ if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (plugin->arrow)))
+ {
+ /* make the toggle button active */
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (plugin->arrow), TRUE);
+
+ /* start the popup timeout */
+ plugin->menu_timeout_id =
+ g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, MENU_POPUP_DELAY,
+ launcher_plugin_menu_popup, plugin,
+ launcher_plugin_menu_popup_destroyed);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+static gboolean
+launcher_plugin_arrow_drag_leave_timeout (gpointer user_data)
+{
+ XfceLauncherPlugin *plugin = XFCE_LAUNCHER_PLUGIN (user_data);
+ gint pointer_x, pointer_y;
+ GtkWidget *menu = plugin->menu;
+ gint menu_x, menu_y, menu_w, menu_h;
+
+ panel_return_val_if_fail (XFCE_IS_LAUNCHER_PLUGIN (plugin), FALSE);
+ panel_return_val_if_fail (menu == NULL || GDK_IS_WINDOW (menu->window), FALSE);
+
+ /* leave when the menu is destroyed */
+ if (G_UNLIKELY (plugin->menu == NULL))
+ return FALSE;
+
+ /* get the pointer position */
+ gdk_display_get_pointer (gtk_widget_get_display (menu),
+ NULL, &pointer_x, &pointer_y, NULL);
+
+ /* get the menu position */
+ gdk_window_get_root_origin (menu->window, &menu_x, &menu_y);
+ gdk_drawable_get_size (GDK_DRAWABLE (menu->window), &menu_w, &menu_h);
+
+ /* check if we should hide the menu */
+ if (pointer_x < menu_x || pointer_x > menu_x + menu_w
+ || pointer_y < menu_y || pointer_y > menu_y + menu_h)
+ {
+ /* hide the menu */
+ gtk_widget_hide (GTK_MENU (menu)->toplevel);
+ gtk_widget_hide (menu);
+
+ /* inactive the toggle button */
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (plugin->arrow), FALSE);
+ }
+
+ return FALSE;
+}
+
+
+
+static void
+launcher_plugin_arrow_drag_leave (GtkWidget *widget,
+ GdkDragContext *context,
+ guint drag_time,
+ XfceLauncherPlugin *plugin)
+{
+ panel_return_if_fail (XFCE_IS_LAUNCHER_PLUGIN (plugin));
+
+ if (plugin->menu_timeout_id != 0)
+ {
+ /* stop the popup timeout */
+ g_source_remove (plugin->menu_timeout_id);
+
+ /* inactive the toggle button */
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (plugin->arrow), FALSE);
+ }
+ else
+ {
+ /* start a timeout to give the user some time to drag to the menu */
+ g_timeout_add (MENU_POPUP_DELAY, launcher_plugin_arrow_drag_leave_timeout, plugin);
+ }
+}
+
+
+
static void
launcher_plugin_items_load (XfceLauncherPlugin *plugin)
{
@@ -1087,6 +1320,7 @@ launcher_plugin_items_load (XfceLauncherPlugin *plugin)
if (G_LIKELY (item != NULL))
plugin->items = g_slist_append (plugin->items, item);
else
+ /* TODO */
g_message ("Lookup the item in the pool...");
}
@@ -1170,7 +1404,8 @@ launcher_plugin_item_exec_on_screen (XfceMenuItem *item,
if (G_UNLIKELY (succeed == FALSE))
{
/* show an error dialog */
- xfce_dialog_show_error (screen, error, _("Failed to execute command \"%s\"."),
+ xfce_dialog_show_error (screen, error,
+ _("Failed to execute command \"%s\"."),
xfce_menu_item_get_command (item));
/* cleanup */
More information about the Xfce4-commits
mailing list