Implement cross overview drag & drop

The gnome-panel allows the user to hover over a tasklist entry
while draging to activate a minimized or obscured window and drop onto it.

Implement a similar behaviour by allowing draging to the activities button or
the hotcorner (and thus opening the overview), which allows the user to
activate any window (even on different workspaces) as a drop target.

https://bugzilla.gnome.org/show_bug.cgi?id=601731
This commit is contained in:
Adel Gadllah
2011-01-05 15:47:27 +01:00
parent 62507c9759
commit ceedc7e32c
11 changed files with 433 additions and 16 deletions

View File

@@ -113,6 +113,8 @@ struct _GnomeShellPlugin
int glx_error_base;
int glx_event_base;
guint have_swap_event : 1;
ShellGlobal *global;
};
struct _GnomeShellPluginClass
@@ -320,7 +322,6 @@ gnome_shell_plugin_start (MetaPlugin *plugin)
int status;
const char *shell_js;
char **search_path;
ShellGlobal *global;
const char *glx_extensions;
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
@@ -379,10 +380,10 @@ gnome_shell_plugin_start (MetaPlugin *plugin)
gvc_muted_debug_log_handler, NULL);
/* Initialize the global object here. */
global = shell_global_get ();
shell_plugin->global = shell_global_get ();
_shell_global_set_plugin (global, META_PLUGIN(shell_plugin));
_shell_global_set_gjs_context (global, shell_plugin->gjs_context);
_shell_global_set_plugin (shell_plugin->global, META_PLUGIN(shell_plugin));
_shell_global_set_gjs_context (shell_plugin->global, shell_plugin->gjs_context);
add_statistics (shell_plugin);
@@ -511,9 +512,9 @@ static gboolean
gnome_shell_plugin_xevent_filter (MetaPlugin *plugin,
XEvent *xev)
{
#ifdef GLX_INTEL_swap_event
GnomeShellPlugin *shell_plugin = GNOME_SHELL_PLUGIN (plugin);
GnomeShellPlugin *shell_plugin = GNOME_SHELL_PLUGIN (plugin);
#ifdef GLX_INTEL_swap_event
if (shell_plugin->have_swap_event &&
xev->type == (shell_plugin->glx_event_base + GLX_BufferSwapComplete))
{
@@ -545,6 +546,12 @@ gnome_shell_plugin_xevent_filter (MetaPlugin *plugin,
&& xev->xcrossing.window == clutter_x11_get_stage_window (CLUTTER_STAGE (clutter_stage_get_default ())))
return TRUE;
/*
* Pass the event to shell-global
*/
if (_shell_global_check_xdnd_event (shell_plugin->global, xev))
return TRUE;
return clutter_x11_handle_event (xev) != CLUTTER_X11_FILTER_CONTINUE;
}

View File

@@ -11,4 +11,6 @@ void _shell_global_set_plugin (ShellGlobal *global,
void _shell_global_set_gjs_context (ShellGlobal *global,
GjsContext *context);
gboolean _shell_global_check_xdnd_event (ShellGlobal *global,
XEvent *xev);
#endif /* __SHELL_GLOBAL_PRIVATE_H__ */

View File

@@ -6,6 +6,7 @@
#include "shell-enum-types.h"
#include "shell-perf-log.h"
#include "shell-window-tracker.h"
#include "shell-marshal.h"
#include "shell-wm.h"
#include "st.h"
@@ -70,6 +71,8 @@ struct _ShellGlobal {
/* For sound notifications */
ca_context *sound_context;
guint32 xdnd_timestamp;
};
enum {
@@ -92,8 +95,19 @@ enum {
PROP_FOCUS_MANAGER,
};
/* Signals */
enum
{
XDND_POSITION_CHANGED,
XDND_LEAVE,
XDND_ENTER,
LAST_SIGNAL
};
G_DEFINE_TYPE(ShellGlobal, shell_global, G_TYPE_OBJECT);
static guint shell_global_signals [LAST_SIGNAL] = { 0 };
static void
shell_global_set_property(GObject *object,
guint prop_id,
@@ -238,6 +252,36 @@ shell_global_class_init (ShellGlobalClass *klass)
gobject_class->get_property = shell_global_get_property;
gobject_class->set_property = shell_global_set_property;
/* Emitted from gnome-shell-plugin.c during event handling */
shell_global_signals[XDND_POSITION_CHANGED] =
g_signal_new ("xdnd-position-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
_shell_marshal_VOID__INT_INT,
G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
/* Emitted from gnome-shell-plugin.c during event handling */
shell_global_signals[XDND_LEAVE] =
g_signal_new ("xdnd-leave",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/* Emitted from gnome-shell-plugin.c during event handling */
shell_global_signals[XDND_ENTER] =
g_signal_new ("xdnd-enter",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
g_object_class_install_property (gobject_class,
PROP_OVERLAY_GROUP,
g_param_spec_object ("overlay-group",
@@ -1130,6 +1174,39 @@ grab_notify (GtkWidget *widget, gboolean was_grabbed, gpointer user_data)
shell_global_set_stage_input_mode (global, global->input_mode);
}
/**
* shell_global_init_xdnd:
* @global: the #ShellGlobal
*
* Enables tracking of Xdnd events
*/
void shell_global_init_xdnd (ShellGlobal *global)
{
long xdnd_version = 5;
MetaScreen *screen = shell_global_get_screen (global);
Window output_window = meta_get_overlay_window (screen);
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdisplay = meta_display_get_xdisplay (display);
ClutterStage *stage = CLUTTER_STAGE(meta_plugin_get_stage (global->plugin));
Window stage_win = clutter_x11_get_stage_window (stage);
XChangeProperty (xdisplay, stage_win, gdk_x11_get_xatom_by_name ("XdndAware"), XA_ATOM,
32, PropModeReplace, (const unsigned char *)&xdnd_version, 1);
XChangeProperty (xdisplay, output_window, gdk_x11_get_xatom_by_name ("XdndProxy"), XA_WINDOW,
32, PropModeReplace, (const unsigned char *)&stage_win, 1);
/*
* XdndProxy is additionally set on the proxy window as verification that the
* XdndProxy property on the target window isn't a left-over
*/
XChangeProperty (xdisplay, stage_win, gdk_x11_get_xatom_by_name ("XdndProxy"), XA_WINDOW,
32, PropModeReplace, (const unsigned char *)&stage_win, 1);
}
/**
* shell_global_format_time_relative_pretty:
* @global:
@@ -1422,6 +1499,10 @@ shell_global_get_current_time (ShellGlobal *global)
guint32 time;
MetaDisplay *display;
/* In case we have a xdnd timestamp use it */
if (global->xdnd_timestamp != 0)
return global->xdnd_timestamp;
/* meta_display_get_current_time() will return the correct time
when handling an X or Gdk event, but will return CurrentTime
from some Clutter event callbacks.
@@ -1689,3 +1770,67 @@ shell_global_play_theme_sound (ShellGlobal *global,
{
ca_context_play (global->sound_context, 0, CA_PROP_EVENT_ID, name, NULL);
}
/*
* Process Xdnd events
*
* We pass the position and leave events to JS via a signal
* where the actual drag & drop handling happens.
*
* http://www.freedesktop.org/wiki/Specifications/XDND
*/
gboolean _shell_global_check_xdnd_event (ShellGlobal *global,
XEvent *xev)
{
MetaScreen *screen = meta_plugin_get_screen (global->plugin);
Window output_window = meta_get_overlay_window (screen);
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdisplay = meta_display_get_xdisplay (display);
ClutterStage *stage = CLUTTER_STAGE (meta_plugin_get_stage (global->plugin));
Window stage_win = clutter_x11_get_stage_window (stage);
if (xev->xany.window != output_window && xev->xany.window != stage_win)
return FALSE;
if (xev->xany.type == ClientMessage && xev->xclient.message_type == gdk_x11_get_xatom_by_name ("XdndPosition"))
{
XEvent xevent;
Window src = xev->xclient.data.l[0];
memset (&xevent, 0, sizeof(xevent));
xevent.xany.type = ClientMessage;
xevent.xany.display = xdisplay;
xevent.xclient.window = src;
xevent.xclient.message_type = gdk_x11_get_xatom_by_name ("XdndStatus");
xevent.xclient.format = 32;
xevent.xclient.data.l[0] = output_window;
/* flags: bit 0: will we accept the drop? bit 1: do we want more position messages */
xevent.xclient.data.l[1] = 2;
xevent.xclient.data.l[4] = None;
XSendEvent (xdisplay, src, False, 0, &xevent);
/* Store the timestamp of the xdnd position event */
global->xdnd_timestamp = xev->xclient.data.l[3];
g_signal_emit_by_name (G_OBJECT (global), "xdnd-position-changed",
(int)(xev->xclient.data.l[2] >> 16), (int)(xev->xclient.data.l[2] & 0xFFFF));
global->xdnd_timestamp = 0;
return TRUE;
}
else if (xev->xany.type == ClientMessage && xev->xclient.message_type == gdk_x11_get_xatom_by_name ("XdndLeave"))
{
g_signal_emit_by_name (G_OBJECT (global), "xdnd-leave");
return TRUE;
}
else if (xev->xany.type == ClientMessage && xev->xclient.message_type == gdk_x11_get_xatom_by_name ("XdndEnter"))
{
g_signal_emit_by_name (G_OBJECT (global), "xdnd-enter");
return TRUE;
}
return FALSE;
}

View File

@@ -132,6 +132,8 @@ void shell_global_run_at_leisure (ShellGlobal *global,
void shell_global_play_theme_sound (ShellGlobal *global,
const char *name);
void shell_global_init_xdnd (ShellGlobal *global);
G_END_DECLS
#endif /* __SHELL_GLOBAL_H__ */

View File

@@ -4,3 +4,4 @@ VOID:BOXED
VOID:BOXED,OBJECT
VOID:OBJECT,OBJECT
VOID:STRING,OBJECT,BOOLEAN
VOID:INT,INT