Implementation of drag&drop files and launchers to some free panel space.
authorAndriy Grytsenko <andrej@rep.kiev.ua>
Mon, 10 Oct 2016 23:44:59 +0000 (02:44 +0300)
committerAndriy Grytsenko <andrej@rep.kiev.ua>
Mon, 10 Oct 2016 23:44:59 +0000 (02:44 +0300)
This should finally cover full support on drag&drop of launchers.

ChangeLog
plugins/launchtaskbar.c
src/configurator.c
src/main.c
src/panel.c
src/plugin.c
src/plugin.h
src/private.h
src/space.c
src/space.h

index 3f98255..2d056ab 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
     consistent on chosen orientation.
 * Implemented dropping file or folder onto launch bar to create launcher.
 * Implemented dragging launchers around launchbars (between panels too).
+* Implemented dropping file/folder on free panel space to create launcher.
+* Implemented dragging launchers from launchbar to some free panel space.
+    When launcher dropped onto another place and former place's launchbar
+    becomes empty, it will not be replaced with a bootstrapping icon (as
+    it happens when you remove last launcher via configuration dialog) but
+    launchbar will be removed from panel instead, that is more obvious and
+    sensible.
 
 0.8.2
 -------------------------------------------------------------------------
index d04ce62..e8b946f 100644 (file)
@@ -490,8 +490,14 @@ static void on_launchbar_drag_data_delete(GtkWidget *widget,
     launchbar_remove_launcher(lb, lb->dragged_launcher);
     fm_path_unref(lb->dragged_launcher);
     lb->dragged_launcher = NULL;
-    launchbar_check_bootstrap(lb);
-    //FIXME: destroy empty plugin instead if in LAUNCHBAR mode?
+    if (lb->mode == LAUNCHBAR)
+    {
+        /* destroy empty plugin if it is in LAUNCHBAR mode */
+        if (panel_icon_grid_get_n_children(PANEL_ICON_GRID(lb->lb_icon_grid)) == 0)
+            lxpanel_remove_plugin(lb->panel, lb->plugin);
+    }
+    else
+        launchbar_check_bootstrap(lb);
 }
 
 static void on_launchbar_drag_end(GtkWidget *widget, GdkDragContext *context,
@@ -1773,6 +1779,31 @@ static void launchtaskbar_panel_configuration_changed(LXPanel *panel, GtkWidget
     }
 }
 
+static gboolean launchtaskbar_control(GtkWidget *p, const char *cmd)
+{
+    LaunchTaskBarPlugin *ltbp = lxpanel_plugin_get_data(p);
+
+    if (ltbp->mode == LAUNCHBAR || ltbp->mode == LAUNCHTASKBAR)
+    {
+        if (strncmp(cmd, "add ", 4) == 0)
+        {
+            config_setting_t *s;
+
+            s = config_group_add_subgroup(ltbp->settings, "Button");
+            config_group_set_string(s, "id", &cmd[4]);
+            if (launchbutton_constructor(ltbp, s))
+            {
+                launchbar_remove_bootstrap(ltbp);
+                lxpanel_config_save(ltbp->panel);
+                return TRUE;
+            }
+            else
+                config_setting_destroy(s);
+        }
+    }
+    return FALSE;
+}
+
 /* Redraw all tasks in the taskbar. */
 static void taskbar_redraw(LaunchTaskBarPlugin * tb)
 {
@@ -2318,7 +2349,8 @@ static LXPanelPluginInit _launchbar_init = {
 
     .new_instance = launchbar_constructor,
     .config = launchtaskbar_configure,
-    .reconfigure = launchtaskbar_panel_configuration_changed
+    .reconfigure = launchtaskbar_panel_configuration_changed,
+    .control = launchtaskbar_control
 };
 
 static LXPanelPluginInit _taskbar_init = {
@@ -2330,7 +2362,8 @@ static LXPanelPluginInit _taskbar_init = {
 
     .new_instance = taskbar_constructor,
     .config = launchtaskbar_configure,
-    .reconfigure = launchtaskbar_panel_configuration_changed
+    .reconfigure = launchtaskbar_panel_configuration_changed,
+    .control = launchtaskbar_control
 };
 
 static void launchtaskbar_init(void)
@@ -2351,7 +2384,8 @@ LXPanelPluginInit lxpanel_static_plugin_launchtaskbar = {
     .new_instance = launchtaskbar_constructor,
     .config = launchtaskbar_configure,
     /* .update_context_menu = launchtaskbar_update_context_menu, */
-    .reconfigure = launchtaskbar_panel_configuration_changed
+    .reconfigure = launchtaskbar_panel_configuration_changed,
+    .control = launchtaskbar_control
 };
 
 
index de4f7ea..dee2fcf 100644 (file)
@@ -857,11 +857,13 @@ static void on_add_plugin( GtkButton* btn, GtkTreeView* _view )
 
 static void on_remove_plugin( GtkButton* btn, GtkTreeView* view )
 {
-    GtkTreeIter it;
+    GtkTreeIter it, it2;
     GtkTreePath* tree_path;
     GtkTreeModel* model;
     GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
-    GtkWidget* pl;
+    GtkWidget *pl, *prev, *next;
+    GList *plugins;
+    gint i;
 
     LXPanel* p = (LXPanel*) g_object_get_data( G_OBJECT(view), "panel" );
 
@@ -869,17 +871,44 @@ static void on_remove_plugin( GtkButton* btn, GtkTreeView* view )
     {
         tree_path = gtk_tree_model_get_path( model, &it );
         gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
+        plugins = p->priv->box ? gtk_container_get_children(GTK_CONTAINER(p->priv->box)) : NULL;
+        i = g_list_index(plugins, pl);
+        if (i > 0)
+        {
+            prev = g_list_nth_data(plugins, i - 1);
+            next = g_list_nth_data(plugins, i + 1);
+            gtk_tree_path_prev(tree_path);
+            gtk_tree_model_get_iter(model, &it2, tree_path);
+            gtk_tree_path_next(tree_path);
+        }
+        else
+            prev = next = NULL;
         if( gtk_tree_path_get_indices(tree_path)[0] >= gtk_tree_model_iter_n_children( model, NULL ) )
             gtk_tree_path_prev( tree_path );
         gtk_list_store_remove( GTK_LIST_STORE(model), &it );
         gtk_tree_selection_select_path( tree_sel, tree_path );
         gtk_tree_path_free( tree_path );
+        g_list_free(plugins);
+
+        _lxpanel_remove_plugin(p, pl);
 
-        config_setting_destroy(g_object_get_qdata(G_OBJECT(pl), lxpanel_plugin_qconf));
-        /* reset conf pointer because the widget still may be referenced by configurator */
-        g_object_set_qdata(G_OBJECT(pl), lxpanel_plugin_qconf, NULL);
-        gtk_widget_destroy(pl);
-        panel_config_save(p->priv);
+        if (next && prev)
+        {
+            plugins = gtk_container_get_children(GTK_CONTAINER(p->priv->box));
+            if (g_list_index(plugins, prev) < 0)
+            {
+                /* previous was removed */
+                gtk_list_store_remove(GTK_LIST_STORE(model), &it2);
+            }
+            else if (g_list_index(plugins, next) < 0)
+            {
+                /* next was removed */
+                if (gtk_tree_model_iter_next(model, &it2))
+                    gtk_list_store_remove(GTK_LIST_STORE(model), &it2);
+                //FIXME: else move selection!
+            }
+            g_list_free(plugins);
+        }
     }
 }
 
index db177e8..778bb8b 100644 (file)
@@ -132,6 +132,9 @@ static void process_client_msg ( XClientMessageEvent* ev )
         case LXPANEL_CMD_COMMAND:
             monitor = (ev->data.b[1] & 0xf) - 1; /* 0 for no monitor */
             edge = (ev->data.b[1] >> 4) & 0x7;
+            if ((ev->data.b[1] & 0x80) != 0)
+                /* some extension, not supported yet */
+                break;
             plugin_type = g_strndup(&ev->data.b[2], 18);
             command = strchr(plugin_type, '\t');
             if (command) do /* use do{}while(0) to enable break */
index 8efa0f8..5530222 100644 (file)
@@ -55,6 +55,7 @@
 
 #include "private.h"
 #include "misc.h"
+#include "space.h"
 
 #include "lxpanelctl.h"
 #include "dbg.h"
@@ -1104,10 +1105,72 @@ void lxpanel_remove_plugin(LXPanel *p, GtkWidget *plugin)
         gtk_widget_destroy(panel->pref_dialog);
         panel->pref_dialog = NULL;
     }
+    _lxpanel_remove_plugin(p, plugin);
+}
+
+void _lxpanel_remove_plugin(LXPanel *p, GtkWidget *plugin)
+{
+    Panel* panel = p->priv;
+    GtkWidget *prev, *next;
+    GList *children;
+    GtkAllocation alloc;
+    gint idx = -1, size1, size2;
+    gboolean expand;
+
     config_setting_destroy(g_object_get_qdata(G_OBJECT(plugin), lxpanel_plugin_qconf));
     /* reset conf pointer because the widget still may be referenced by configurator */
     g_object_set_qdata(G_OBJECT(plugin), lxpanel_plugin_qconf, NULL);
 
+    /* squash previous and next spaces if this plugin was between two spaces */
+    children = gtk_container_get_children(GTK_CONTAINER(panel->box));
+    idx = g_list_index(children, plugin);
+    if (idx > 0)
+    {
+
+        prev = g_list_nth_data(children, idx - 1);
+        next = g_list_nth_data(children, idx + 1);
+        if (next && PANEL_IS_SPACE(next) && PANEL_IS_SPACE(prev))
+        {
+            expand = FALSE;
+            gtk_container_child_get(GTK_CONTAINER(panel->box), prev, "expand", &expand, NULL);
+            if (expand == TRUE)
+            {
+                /* prev is expandable, remove next */
+                config_setting_destroy(g_object_get_qdata(G_OBJECT(next), lxpanel_plugin_qconf));
+                g_object_set_qdata(G_OBJECT(next), lxpanel_plugin_qconf, NULL);
+                gtk_widget_destroy(next);
+            }
+            else
+            {
+                gtk_container_child_get(GTK_CONTAINER(panel->box), next, "expand", &expand, NULL);
+                if (expand == TRUE)
+                {
+                    /* next is expandable, remove prev */
+                    config_setting_destroy(g_object_get_qdata(G_OBJECT(prev), lxpanel_plugin_qconf));
+                    g_object_set_qdata(G_OBJECT(prev), lxpanel_plugin_qconf, NULL);
+                    gtk_widget_destroy(prev);
+                }
+                else
+                {
+                    /* calculate size of prev -- add size of this and next to it */
+                    size1 = _panel_space_get_size(prev);
+                    size2 = _panel_space_get_size(next);
+                    gtk_widget_get_allocation(plugin, &alloc);
+                    if (panel->orientation == GTK_ORIENTATION_HORIZONTAL)
+                        size1 += alloc.width + size2;
+                    else
+                        size1 += alloc.height + size2;
+                    /* remove next */
+                    config_setting_destroy(g_object_get_qdata(G_OBJECT(next), lxpanel_plugin_qconf));
+                    g_object_set_qdata(G_OBJECT(next), lxpanel_plugin_qconf, NULL);
+                    gtk_widget_destroy(next);
+                    _panel_space_resize(prev, size1);
+                }
+            }
+        }
+    }
+    g_list_free(children);
+
     lxpanel_config_save(p);
     gtk_widget_destroy(plugin);
 }
index 3d83403..c7372a5 100644 (file)
@@ -579,6 +579,8 @@ GtkWidget *lxpanel_add_plugin(LXPanel *p, const char *name, config_setting_t *cf
     }
     gtk_widget_set_name(widget, name);
     gtk_box_pack_start(GTK_BOX(p->priv->box), widget, expand, TRUE, padding);
+    if (at >= 0)
+        gtk_box_reorder_child(GTK_BOX(p->priv->box), widget, at);
     gtk_container_set_border_width(GTK_CONTAINER(widget), border);
     g_signal_connect(widget, "size-allocate", G_CALLBACK(on_size_allocate), p);
     gtk_widget_show(widget);
index 97cdd0e..c781bdf 100644 (file)
@@ -94,7 +94,7 @@ G_BEGIN_DECLS
  * are handled by lxpanel: "DEL" will remove plugin from panel, "ADD"
  * will create new instance if there is no instance yet. Due to design
  * limitations of XClientMessageEvent the size of plugin type and command
- * cannot exceed 16 characters in total.
+ * cannot exceed 18 characters in total.
  *
  * If @gettext_package is not %NULL then it will be used for translation
  * of @name and @description. (Since: 0.9.0)
@@ -111,7 +111,7 @@ typedef struct {
     gboolean (*button_press_event)(GtkWidget *widget, GdkEventButton *event, LXPanel *panel);
     void (*show_system_menu)(GtkWidget *widget);
     gboolean (*update_context_menu)(GtkWidget *plugin, GtkMenu *menu);
-    gboolean (*control)(GtkWidget *plugin, const char *cmd); /* not implemented */
+    gboolean (*control)(GtkWidget *plugin, const char *cmd);
     char *gettext_package;      /* optional: gettext package used to translate name and description */
     /*< private >*/
     gpointer _reserved1;
@@ -373,6 +373,10 @@ extern gboolean lxpanel_apply_hotkey(char **hkptr, const char *keystring,
  */
 extern guint panel_config_click_parse(const char *keystring, GdkModifierType *mods);
 
+/* Add/remove plugin to/from panel */
+GtkWidget *lxpanel_add_plugin(LXPanel *p, const char *name, config_setting_t *cfg, gint at);
+void lxpanel_remove_plugin(LXPanel *p, GtkWidget *plugin);
+
 G_END_DECLS
 
 #endif /* __PLUGIN_H__ */
index 1c88036..6d9137e 100644 (file)
@@ -211,9 +211,8 @@ static inline char *_user_config_file_name(const char *name1, const char *name2)
 void lxpanel_prepare_modules(void);
 void lxpanel_unload_modules(void);
 
-GtkWidget *lxpanel_add_plugin(LXPanel *p, const char *name, config_setting_t *cfg, gint at);
 GHashTable *lxpanel_get_all_types(void); /* transfer none */
-void lxpanel_remove_plugin(LXPanel *p, GtkWidget *plugin);
+void _lxpanel_remove_plugin(LXPanel *p, GtkWidget *plugin); /* no destroy dialog */
 
 extern GQuark lxpanel_plugin_qinit; /* access to LXPanelPluginInit data */
 #define PLUGIN_CLASS(_i) ((LXPanelPluginInit*)g_object_get_qdata(G_OBJECT(_i),lxpanel_plugin_qinit))
index ffe9e5c..3e0aaa7 100644 (file)
 #include <stdlib.h>
 
 #include <glib/gi18n.h>
+#include <libfm/fm-gtk.h>
 
 #include "space.h"
 
+#include "private.h"
+
 struct _PanelSpace
 {
     GtkEventBox parent;
     config_setting_t *settings;
+    FmDndDest *dd;
     int size;
 };
 
@@ -40,6 +44,228 @@ struct _PanelSpaceClass
     GtkEventBoxClass parent_class;
 };
 
+
+/* Drag&drop support to create launchers */
+enum {
+    LAUNCHER_DND_TARGET = N_FM_DND_DEST_DEFAULT_TARGETS
+};
+
+static const GtkTargetEntry dnd_targets[] = {
+    { "application/x-lxpanel-launcher", GTK_TARGET_SAME_APP, LAUNCHER_DND_TARGET }
+};
+
+static GdkAtom launcher_dnd_atom;
+
+static gboolean panel_space_drag_drop(GtkWidget *widget, GdkDragContext *context,
+                                      gint x, gint y, guint time)
+{
+    PanelSpace *sp = PANEL_SPACE(widget);
+    GdkAtom target;
+
+    target = gtk_drag_dest_find_target(widget, context, NULL);
+    if (target == launcher_dnd_atom)
+    {
+        /* request for data, it will be processed on "drag-data-received" signal */
+        gtk_drag_get_data(widget, context, launcher_dnd_atom, time);
+        return TRUE;
+    }
+    target = fm_dnd_dest_find_target(sp->dd, context);
+    if (G_LIKELY(target != GDK_NONE))
+        return fm_dnd_dest_drag_drop(sp->dd, context, target, x, y, time);
+    return FALSE;
+}
+
+static gboolean panel_space_make_launcher(GtkWidget *widget, gint x, gint y, const char *str)
+{
+    PanelSpace *sp = PANEL_SPACE(widget);
+    GtkWidget *panel_box, *launchbar, *sp2;
+    LXPanel *panel;
+    config_setting_t *cfg;
+    LXPanelPluginInit *init;
+    char *cmd;
+    GtkAllocation alloc;
+    int idx = -1, size, size2 = 0;
+    int icon_size;
+    gboolean expand = FALSE;
+
+    /* find position of this widget */
+    panel_box = gtk_widget_get_parent(widget);
+    gtk_container_child_get(GTK_CONTAINER(panel_box), widget, "position", &idx,
+                                                              "expand", &expand,
+                                                              NULL);
+    if (idx < 1)
+        // g_warning
+        return FALSE;
+    panel = PLUGIN_PANEL(widget);
+    /* prepare config for new widget and create launcher before PS */
+    cfg = config_group_add_subgroup(config_root_setting(panel->priv->config),
+                                    "Plugin");
+    config_group_set_string(cfg, "type", "launchbar");
+    config_setting_move_elem(cfg, config_setting_get_parent(cfg), idx + 1);
+    launchbar = lxpanel_add_plugin(panel, "launchbar", cfg, idx);
+    if (launchbar == NULL) /* failed to create */
+    {
+        config_setting_destroy(cfg);
+        return FALSE;
+    }
+    init = PLUGIN_CLASS(launchbar);
+    if (!init->control) /* cannot create a launcher */
+    {
+        lxpanel_remove_plugin(panel, launchbar);
+        return FALSE;
+    }
+    cmd = g_strdup_printf("add %s", str);
+    if (!init->control(launchbar, cmd)) /* failed to create a launcher */
+    {
+        g_free(cmd);
+        lxpanel_remove_plugin(panel, launchbar);
+        return FALSE;
+    }
+    /* success */
+    g_free(cmd);
+    /* now to find where to insert the launcher */
+    icon_size = panel_get_icon_size(panel);
+    if (!expand && sp->size <= icon_size/2 + 4) //just drop this PS
+    {
+        lxpanel_remove_plugin(panel, widget);
+        return TRUE;
+    }
+    gtk_widget_get_allocation(widget, &alloc);
+    if (panel_get_orientation(panel) == GTK_ORIENTATION_HORIZONTAL)
+    {
+        size = alloc.width;
+    }
+    else
+    {
+        size = alloc.height;
+        x = y; /* use x below as a position value */
+    }
+    /* g_debug("making launcher at %d on PanelSpace of size %d", x, size); */
+    if (x <= icon_size/2 + 4) //leave launchbar at idx (before PS), size -= icon_size+3
+    {
+    }
+    else if (x >= size - icon_size/2 - 4) //move launchbar to idx+1 (after PS), size -= icon_size+3
+    {
+        gtk_box_reorder_child(GTK_BOX(panel_box), launchbar, idx + 1);
+        config_setting_move_elem(cfg, config_setting_get_parent(cfg), idx + 2);
+    }
+    else if (expand && x < size/2) //create another PS at idx of size pos-icon_size/2-2, shifting launchbar
+    {
+        cfg = config_group_add_subgroup(config_root_setting(panel->priv->config),
+                                        "Plugin");
+        config_group_set_string(cfg, "type", "space");
+        sp2 = lxpanel_add_plugin(panel, "space", cfg, idx);
+        size2 = x - icon_size/2 - 2;
+        /* g_debug("adding new PanelSpace of size %d before Launcher", size2); */
+        config_setting_move_elem(cfg, config_setting_get_parent(cfg), idx + 1);
+        if (sp2 == NULL)
+            //FIXME: is it ever possible?
+            config_setting_destroy(cfg);
+        else
+            _panel_space_resize(sp2, size2);
+    }
+    else //move launchbar to idx+1, then create another PS at idx+2 of size size-pos-icon_size/2-2
+    {
+        gtk_box_reorder_child(GTK_BOX(panel_box), launchbar, idx + 1);
+        config_setting_move_elem(cfg, config_setting_get_parent(cfg), idx + 2);
+        cfg = config_group_add_subgroup(config_root_setting(panel->priv->config),
+                                        "Plugin");
+        config_group_set_string(cfg, "type", "space");
+        sp2 = lxpanel_add_plugin(panel, "space", cfg, idx + 2);
+        size2 = size - x - icon_size/2 - 2;
+        /* g_debug("adding new PanelSpace of size %d after Launcher", size2); */
+        config_setting_move_elem(cfg, config_setting_get_parent(cfg), idx + 3);
+        if (sp2 == NULL)
+            //FIXME: is it ever possible?
+            config_setting_destroy(cfg);
+        else
+            _panel_space_resize(sp2, size2);
+    }
+    if (!expand) //resize to sp->size - icon_size - 3 - size2, then queue resize
+    {
+        /* g_debug("resizing this space to %d", sp->size - icon_size - 3 - size2); */
+        _panel_space_resize(widget, sp->size - icon_size - 3 - size2);
+    }
+    return TRUE;
+}
+
+static void panel_space_drag_data_received(GtkWidget *widget,
+                                           GdkDragContext *context, gint x,
+                                           gint y, GtkSelectionData *sel_data,
+                                           guint info, guint time)
+{
+    char *str;
+
+    switch(info)
+    {
+    case LAUNCHER_DND_TARGET:
+        /* get data from selection */
+        str = (char *)gtk_selection_data_get_data(sel_data);
+        if (str == NULL)
+            break;
+        /* try to make a launcher */
+        if (panel_space_make_launcher(widget, x, y, str))
+            gtk_drag_finish(context, TRUE, TRUE, time);
+        else
+            gtk_drag_finish(context, FALSE, FALSE, time);
+        break;
+    default:
+        fm_dnd_dest_drag_data_received(PANEL_SPACE(widget)->dd, context, x, y,
+                                       sel_data, info, time);
+    }
+}
+
+/* Handler for "drag-motion" event from launchtaskbar button. */
+static gboolean panel_space_drag_motion(GtkWidget *widget,
+                                        GdkDragContext *context, gint x, gint y,
+                                        guint time)
+{
+    PanelSpace *sp = PANEL_SPACE(widget);
+    GdkAtom target;
+    GdkDragAction action = 0;
+
+    target = fm_dnd_dest_find_target(sp->dd, context);
+    if (target == GDK_NONE)
+    {
+        target = gtk_drag_dest_find_target(widget, context, NULL);
+        if (target == launcher_dnd_atom)
+            action = GDK_ACTION_MOVE; /* see launchbar plugin */
+    }
+    else if (fm_dnd_dest_is_target_supported(sp->dd, target))
+    {
+        fm_dnd_dest_get_default_action(sp->dd, context, target);
+        action = GDK_ACTION_COPY;
+    }
+    gdk_drag_status(context, action, time);
+
+    return TRUE;
+}
+
+static void panel_space_drag_leave(GtkWidget *widget,
+                                   GdkDragContext *drag_context, guint time)
+{
+    fm_dnd_dest_drag_leave(PANEL_SPACE(widget)->dd, drag_context, time);
+}
+
+static gboolean panel_space_files_dropped(FmDndDest *dd, int x, int y, GdkDragAction action,
+                                          FmDndDestTargetType info_type,
+                                          FmPathList *files, GtkWidget *sp)
+{
+    FmPath *path;
+    char *path_str;
+
+    if (action != GDK_ACTION_COPY)
+        return FALSE;
+    path = fm_path_list_peek_head(files);
+    if (!path)
+        return FALSE;
+    path_str = fm_path_to_str(path);
+    /* g_debug("*** path '%s' pos %d", path_str, i); */
+    panel_space_make_launcher(sp, x, y, path_str);
+    g_free(path_str);
+    return TRUE;
+}
+
 #if GTK_CHECK_VERSION(3, 0, 0)
 static void panel_space_get_preferred_size(GtkWidget *widget,
                                            gint *minimal_width,
@@ -64,9 +290,25 @@ static void panel_space_size_request(GtkWidget *widget,
 
 G_DEFINE_TYPE(PanelSpace, panel_space, GTK_TYPE_EVENT_BOX)
 
+static void panel_space_dispose(GObject *object)
+{
+    PanelSpace *self = (PanelSpace *)object;
+
+    if (self->dd)
+    {
+        g_signal_handlers_disconnect_by_func(self->dd,
+                                             panel_space_files_dropped, self);
+        g_object_unref(self->dd);
+        self->dd = NULL;
+    }
+
+    G_OBJECT_CLASS(panel_space_parent_class)->dispose(object);
+}
+
 static void panel_space_class_init(PanelSpaceClass *klass)
 {
     GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
 
 #if GTK_CHECK_VERSION(3, 0, 0)
     widget_class->get_preferred_width = panel_space_get_preferred_size;
@@ -74,11 +316,23 @@ static void panel_space_class_init(PanelSpaceClass *klass)
 #else
     widget_class->size_request = panel_space_size_request;
 #endif
+    widget_class->drag_drop = panel_space_drag_drop;
+    widget_class->drag_data_received = panel_space_drag_data_received;
+    widget_class->drag_motion = panel_space_drag_motion;
+    widget_class->drag_leave = panel_space_drag_leave;
+
+    object_class->dispose = panel_space_dispose;
+
+    launcher_dnd_atom = gdk_atom_intern_static_string("application/x-lxpanel-launcher");
 }
 
 static void panel_space_init(PanelSpace *self)
 {
     gtk_widget_set_has_window(GTK_WIDGET(self), FALSE);
+    self->dd = fm_dnd_dest_new(GTK_WIDGET(self));
+    fm_dnd_dest_add_targets(GTK_WIDGET(self), dnd_targets, G_N_ELEMENTS(dnd_targets));
+    g_signal_connect(self->dd, "files-dropped",
+                     G_CALLBACK(panel_space_files_dropped), self);
 }
 
 /* Plugin constructor. */
@@ -120,6 +374,11 @@ void _panel_space_resize(GtkWidget *spacer, gint size)
     space_apply_configuration(p);
 }
 
+gint _panel_space_get_size(GtkWidget *spacer)
+{
+    return PANEL_SPACE(spacer)->size;
+}
+
 /* Callback when the configuration dialog is to be shown. */
 static GtkWidget *space_configure(LXPanel *panel, GtkWidget *instance)
 {
index 9dc15de..8555950 100644 (file)
@@ -34,6 +34,7 @@ typedef struct _PanelSpaceClass      PanelSpaceClass;
 
 GtkWidget *_panel_space_new(LXPanel *panel, config_setting_t *settings);
 void _panel_space_resize(GtkWidget *spacer, gint size);
+gint _panel_space_get_size(GtkWidget *spacer);
 
 extern LXPanelPluginInit _lxpanel_static_plugin_space;