diff --git a/src/Makefile.am b/src/Makefile.am index 405108ed2..6d9b5e27b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -174,6 +174,7 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES = \ compositor/meta-background-group.c \ compositor/meta-cullable.c \ compositor/meta-cullable.h \ + compositor/meta-dnd.c \ compositor/meta-dnd-actor.c \ compositor/meta-dnd-actor-private.h \ compositor/meta-feedback-actor.c \ @@ -430,6 +431,7 @@ libmutterinclude_headers = \ meta/meta-background-image.h \ meta/meta-background-group.h \ meta/meta-cursor-tracker.h \ + meta/meta-dnd.h \ meta/meta-idle-monitor.h \ meta/meta-plugin.h \ meta/meta-monitor-manager.h \ diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c index 9f22a945e..e606404a4 100644 --- a/src/backends/meta-backend.c +++ b/src/backends/meta-backend.c @@ -78,6 +78,7 @@ struct _MetaBackendPrivate int current_device_id; MetaPointerConstraint *client_pointer_constraint; + MetaDnd *dnd; }; typedef struct _MetaBackendPrivate MetaBackendPrivate; @@ -457,6 +458,8 @@ meta_backend_initable_init (GInitable *initable, priv->cursor_tracker = g_object_new (META_TYPE_CURSOR_TRACKER, NULL); + priv->dnd = g_object_new (META_TYPE_DND, NULL); + return TRUE; } @@ -866,3 +869,19 @@ meta_backend_get_input_settings (MetaBackend *backend) return priv->input_settings; } + +/** + * meta_backend_get_dnd: + * @backend: A #MetaDnd + * + * Gets the global #MetaDnd that's managed by this backend. + * + * Returns: (transfer none): the #MetaDnd + */ +MetaDnd * +meta_backend_get_dnd (MetaBackend *backend) +{ + MetaBackendPrivate *priv = meta_backend_get_instance_private (backend); + + return priv->dnd; +} diff --git a/src/backends/meta-dnd-private.h b/src/backends/meta-dnd-private.h new file mode 100644 index 000000000..41aa2a0d7 --- /dev/null +++ b/src/backends/meta-dnd-private.h @@ -0,0 +1,30 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2016 Hyungwon Hwang + * + * This program 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 2 of the + * License, or (at your option) any later version. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef META_DND_PRIVATE__H +#define META_DND_PRIVATE__H + +#include + +gboolean meta_dnd_handle_xdnd_event (MetaBackend *backend, + MetaCompositor *compositor, + MetaDisplay *display, + XEvent *xev); + +#endif /* META_DND_PRIVATE_H */ diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c index 83d30d892..439fb96fb 100644 --- a/src/backends/x11/meta-backend-x11.c +++ b/src/backends/x11/meta-backend-x11.c @@ -46,6 +46,7 @@ #include #include "display-private.h" #include "compositor/compositor-private.h" +#include "backends/meta-dnd-private.h" struct _MetaBackendX11Private { @@ -255,6 +256,9 @@ handle_host_xevent (MetaBackend *backend, MetaCompositor *compositor = display->compositor; if (meta_plugin_manager_xevent_filter (compositor->plugin_mgr, event)) bypass_clutter = TRUE; + + if (meta_dnd_handle_xdnd_event (backend, compositor, display, event)) + bypass_clutter = TRUE; } } diff --git a/src/compositor/meta-dnd.c b/src/compositor/meta-dnd.c new file mode 100644 index 000000000..fa294902d --- /dev/null +++ b/src/compositor/meta-dnd.c @@ -0,0 +1,171 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * Copyright (C) 2016 Hyungwon Hwang + * + * This program 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 2 of the + * License, or (at your option) any later version. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + +#include "config.h" + +#include + +#include "clutter/x11/clutter-x11.h" +#include "meta/meta-backend.h" +#include "compositor/compositor-private.h" +#include "core/display-private.h" +#include "backends/meta-dnd-private.h" +#include "meta/meta-dnd.h" + +struct _MetaDndClass +{ + GObjectClass parent_class; +}; + +struct _MetaDnd +{ + GObject parent; +}; + +G_DEFINE_TYPE (MetaDnd, meta_dnd, G_TYPE_OBJECT); + +enum +{ + ENTER, + POSITION_CHANGE, + LEAVE, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void +meta_dnd_class_init (MetaDndClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + signals[ENTER] = + g_signal_new ("dnd-enter", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); + + signals[POSITION_CHANGE] = + g_signal_new ("dnd-position-change", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); + + signals[LEAVE] = + g_signal_new ("dnd-leave", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); +} + +static void +meta_dnd_init (MetaDnd *dnd) +{ +} + +static void +meta_dnd_notify_dnd_enter (MetaDnd *dnd) +{ + g_signal_emit (dnd, signals[ENTER], 0); +} + +static void +meta_dnd_notify_dnd_position_change (MetaDnd *dnd, + int x, + int y) +{ + g_signal_emit (dnd, signals[POSITION_CHANGE], 0, x, y); +} + +static void +meta_dnd_notify_dnd_leave (MetaDnd *dnd) +{ + g_signal_emit (dnd, signals[LEAVE], 0); +} + +/* + * Process Xdnd events + * + * We pass the position and leave events to the plugin via a signal + * where the actual drag & drop handling happens. + * + * http://www.freedesktop.org/wiki/Specifications/XDND + */ +gboolean +meta_dnd_handle_xdnd_event (MetaBackend *backend, + MetaCompositor *compositor, + MetaDisplay *display, + XEvent *xev) +{ + MetaDnd *dnd = meta_backend_get_dnd (backend); + Window output_window = compositor->output; + + if (xev->xany.type != ClientMessage) + return FALSE; + + if (xev->xany.window != output_window && + xev->xany.window != clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage))) + return FALSE; + + if (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 = 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 (display->xdisplay, src, False, 0, &xevent); + + meta_dnd_notify_dnd_position_change (dnd, + (int)(xev->xclient.data.l[2] >> 16), + (int)(xev->xclient.data.l[2] & 0xFFFF)); + + return TRUE; + } + else if (xev->xclient.message_type == gdk_x11_get_xatom_by_name ("XdndLeave")) + { + meta_dnd_notify_dnd_leave (dnd); + + return TRUE; + } + else if (xev->xclient.message_type == gdk_x11_get_xatom_by_name ("XdndEnter")) + { + meta_dnd_notify_dnd_enter (dnd); + + return TRUE; + } + + return FALSE; +} diff --git a/src/meta/meta-backend.h b/src/meta/meta-backend.h index fad8f558b..152cfc116 100644 --- a/src/meta/meta-backend.h +++ b/src/meta/meta-backend.h @@ -28,6 +28,7 @@ #include #include +#include "meta/meta-dnd.h" typedef struct _MetaBackend MetaBackend; typedef struct _MetaBackendClass MetaBackendClass; @@ -48,6 +49,7 @@ void meta_backend_set_numlock (MetaBackend *backend, gboolean numlock_state); ClutterActor *meta_backend_get_stage (MetaBackend *backend); +MetaDnd *meta_backend_get_dnd (MetaBackend *backend); void meta_clutter_init (void); diff --git a/src/meta/meta-dnd.h b/src/meta/meta-dnd.h new file mode 100644 index 000000000..bc77c24c2 --- /dev/null +++ b/src/meta/meta-dnd.h @@ -0,0 +1,31 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2016 Hyungwon Hwang + * + * This program 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 2 of the + * License, or (at your option) any later version. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef META_DND_H +#define META_DND_H + +#include +#include + +#include "meta/types.h" + +#define META_TYPE_DND (meta_dnd_get_type ()) +G_DECLARE_FINAL_TYPE (MetaDnd, meta_dnd, META, DND, GObject) + +#endif /* META_DND_H */ diff --git a/src/meta/types.h b/src/meta/types.h index cd6af2b63..22778899d 100644 --- a/src/meta/types.h +++ b/src/meta/types.h @@ -24,6 +24,7 @@ * MetaCompositor: (skip) * */ +typedef struct _MetaBackend MetaBackend; typedef struct _MetaCompositor MetaCompositor; typedef struct _MetaDisplay MetaDisplay; typedef struct _MetaFrame MetaFrame; @@ -38,4 +39,6 @@ typedef struct _MetaGroup MetaGroup; typedef struct _MetaKeyBinding MetaKeyBinding; typedef struct _MetaCursorTracker MetaCursorTracker; +typedef struct _MetaDnd MetaDnd; + #endif