Implemetation of dropping file or folder onto launch bar to create launcher.
authorAndriy Grytsenko <andrej@rep.kiev.ua>
Tue, 4 Oct 2016 21:02:49 +0000 (00:02 +0300)
committerAndriy Grytsenko <andrej@rep.kiev.ua>
Tue, 4 Oct 2016 21:02:49 +0000 (00:02 +0300)
ChangeLog
plugins/launchtaskbar.c
src/icon-grid.c
src/icon-grid.h

index 22c4784..296295d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -12,6 +12,7 @@
 * Converted launch button into widget class for more easy management.
 * Adjusted PanelIconGrid: min spacing is now 1, no_window flag is now left
     unset by default.
+* Implemented dropping file or folder onto launch bar to create launcher.
 
 0.8.2
 -------------------------------------------------------------------------
index 3a0902b..432b2db 100644 (file)
@@ -110,6 +110,8 @@ struct LaunchTaskBarPlugin {
     GtkWidget *lb_icon_grid;         /* Icon grid managing the container */
     GtkWidget     *p_button_add, *p_button_remove, *p_label_menu_app_exec, *p_label_def_app_exec;
     FmDndDest *dd;                 /* Drag & drop on launchbar */
+    GtkWidget *last_lb_drag_dest;  /* Last launch button near drag on launchbar */
+    PanelIconGridDropPosition last_lb_drag_pos;
     /* TASKBAR */
     GtkWidget * tb_icon_grid;      /* Manager for taskbar buttons */
     int number_of_desktops;        /* Number of desktops, from NET_WM_NUMBER_OF_DESKTOPS */
@@ -292,6 +294,20 @@ static FmPath *f_find_menu_launchbutton_recursive(Window win, LaunchTaskBarPlugi
 }
 #endif
 
+static void launchbar_remove_bootstrap(LaunchTaskBarPlugin *ltbp)
+{
+    GList *btns = gtk_container_get_children(GTK_CONTAINER(ltbp->lb_icon_grid));
+    GList *l;
+
+    for (l = btns; l; l = l->next)
+        if (launch_button_get_settings(l->data) == NULL)
+        {
+            gtk_widget_destroy(l->data);
+            g_debug("launchtaskbar: removed bootstrap button %p", l->data);
+        }
+    g_list_free(btns);
+}
+
 /* Handler for "drag-motion" event from launchtaskbar button. */
 static gboolean on_launchbar_drag_motion(
     GtkWidget * widget,
@@ -304,6 +320,7 @@ static gboolean on_launchbar_drag_motion(
     GdkAtom target;
     GdkDragAction action = 0;
     GtkWidget *btn;
+    FmFileInfo *fi = NULL;
     PanelIconGridDropPosition pos;
 
     if (!panel_icon_grid_get_dest_at_pos(PANEL_ICON_GRID(b->lb_icon_grid), x, y,
@@ -314,17 +331,24 @@ static gboolean on_launchbar_drag_motion(
         gdk_drag_status(context, 0, time);
         return TRUE;
     }
+    b->last_lb_drag_dest = btn;
+    b->last_lb_drag_pos = pos;
     panel_icon_grid_set_drag_dest(PANEL_ICON_GRID(b->lb_icon_grid), btn, pos);
-    if (!PANEL_IS_LAUNCH_BUTTON(btn) || pos != PANEL_ICON_GRID_DROP_INTO)
+    if (PANEL_IS_LAUNCH_BUTTON(btn))
     {
-        fm_dnd_dest_set_dest_file(b->dd, NULL);
-        gdk_drag_status(context, 0, time);
-        return TRUE;
+        if (launch_button_get_settings((LaunchButton *)btn) == NULL)
+            /* bootstrap button */
+            b->last_lb_drag_pos = PANEL_ICON_GRID_DROP_LEFT_BEFORE;
+        else if (pos == PANEL_ICON_GRID_DROP_INTO)
+            fi = launch_button_get_file_info((LaunchButton *)btn);
     }
-    fm_dnd_dest_set_dest_file(b->dd, launch_button_get_file_info((LaunchButton *)btn));
+    fm_dnd_dest_set_dest_file(b->dd, fi);
     target = fm_dnd_dest_find_target(b->dd, context);
     if (target != GDK_NONE && fm_dnd_dest_is_target_supported(b->dd, target))
         action = fm_dnd_dest_get_default_action(b->dd, context, target);
+    if (fi == NULL && PANEL_IS_LAUNCH_BUTTON(btn))
+        /* dropping on free place */
+        action = GDK_ACTION_COPY;
     gdk_drag_status(context, action, time);
     /* g_debug("launchbutton_drag_motion_event: act=%u",action); */
     return TRUE;
@@ -337,6 +361,60 @@ static void on_launchbar_drag_leave(GtkWidget * widget, GdkDragContext * drag_co
     fm_dnd_dest_set_dest_file(lb->dd, NULL);
 }
 
+static gboolean on_launchbar_files_dropped(FmDndDest *dd, int x, int y, GdkDragAction action,
+                                           FmDndDestTargetType info_type,
+                                           FmPathList *files, LaunchTaskBarPlugin *lb)
+{
+    FmPath *path;
+    LaunchButton *btn;
+    char *path_str;
+    config_setting_t *s;
+    int i;
+
+    if (action != GDK_ACTION_COPY)
+        return FALSE;
+    path = fm_path_list_peek_head(files);
+    if (!path)
+        return FALSE;
+    if (!lb->last_lb_drag_dest)
+        return FALSE;
+    i = panel_icon_grid_get_child_position(PANEL_ICON_GRID(lb->lb_icon_grid),
+                                           lb->last_lb_drag_dest);
+    lb->last_lb_drag_dest = NULL;
+    if (i < 0)
+        return FALSE;
+    switch (lb->last_lb_drag_pos)
+    {
+    case PANEL_ICON_GRID_DROP_LEFT_AFTER:
+    case PANEL_ICON_GRID_DROP_RIGHT_AFTER:
+        i++;
+        break;
+    case PANEL_ICON_GRID_DROP_LEFT_BEFORE:
+    case PANEL_ICON_GRID_DROP_RIGHT_BEFORE:
+        break;
+    default:
+        return FALSE;
+    }
+    path_str = fm_path_to_str(path);
+    /* g_debug("*** path '%s' pos %d", path_str, i); */
+    s = config_group_add_subgroup(lb->settings, "Button");
+    config_group_set_string(s, "id", path_str);
+    g_free(path_str);
+    btn = launch_button_new(lb->panel, lb->plugin, path, s);
+    if (btn)
+    {
+        gtk_container_add(GTK_CONTAINER(lb->lb_icon_grid), GTK_WIDGET(btn));
+        panel_icon_grid_reorder_child(PANEL_ICON_GRID(lb->lb_icon_grid),
+                                      GTK_WIDGET(btn), i);
+        config_setting_move_elem(s, config_setting_get_parent(s), i);
+        lxpanel_config_save(lb->panel);
+        launchbar_remove_bootstrap(lb);
+    }
+    else
+        config_setting_destroy(s);
+    return TRUE;
+}
+
 #ifndef DISABLE_MENU
 static LaunchButton *launchbar_exec_bin_exists(LaunchTaskBarPlugin *lb, FmPath *path)
 {
@@ -504,6 +582,8 @@ static void launchtaskbar_constructor_launch(LaunchTaskBarPlugin *ltbp)
                          G_CALLBACK(on_launchbar_drag_motion), ltbp);
         g_signal_connect(ltbp->lb_icon_grid, "drag-leave",
                          G_CALLBACK(on_launchbar_drag_leave), ltbp);
+        g_signal_connect(ltbp->dd, "files-dropped",
+                         G_CALLBACK(on_launchbar_files_dropped), ltbp);
     }
     gtk_widget_set_visible(ltbp->lb_icon_grid, TRUE);
 }
@@ -716,7 +796,10 @@ static GtkWidget *launchtaskbar_constructor(LXPanel *panel, config_setting_t *se
 static void launchtaskbar_destructor_launch(LaunchTaskBarPlugin *ltbp)
 {
     if (ltbp->dd)
+    {
+        g_signal_handlers_disconnect_by_func(ltbp->dd, on_launchbar_files_dropped, ltbp);
         g_object_unref(ltbp->dd);
+    }
     /* do not disconnect handler on child widget - it is already destroyed */
 }
 
@@ -761,20 +844,6 @@ static void launchtaskbar_destructor(gpointer user_data)
     g_free(ltbp);
 }
 
-static void launchbar_remove_bootstrap(LaunchTaskBarPlugin *ltbp)
-{
-    GList *btns = gtk_container_get_children(GTK_CONTAINER(ltbp->lb_icon_grid));
-    GList *l;
-
-    for (l = btns; l; l = l->next)
-        if (launch_button_get_settings(l->data) == NULL)
-        {
-            gtk_widget_destroy(l->data);
-            g_debug("launchtaskbar: removed bootstrap button %p", l->data);
-        }
-    g_list_free(btns);
-}
-
 static void _launchbar_configure_add(GtkTreeView *menu_view, LaunchTaskBarPlugin *ltbp)
 {
     GtkTreeView * defined_view = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(ltbp->config_dlg), "defined_view"));
@@ -804,6 +873,7 @@ static void _launchbar_configure_add(GtkTreeView *menu_view, LaunchTaskBarPlugin
         settings = config_group_add_subgroup(ltbp->settings, "Button");
         config_group_set_string(settings, "id", path);
         launch_button_set_settings(btn, settings);
+        lxpanel_config_save(ltbp->panel);
         g_free(path);
         fm_path_unref(sel_path);
         launchbar_remove_bootstrap(ltbp);
index 1447beb..0dea215 100644 (file)
@@ -535,7 +535,7 @@ gboolean panel_icon_grid_get_dest_at_pos(PanelIconGrid * ig, gint x, gint y,
                 if (!rtl)
                 {
                     /* reached next column */
-                    drop_pos = PANEL_ICON_GRID_DROP_LEFT;
+                    drop_pos = PANEL_ICON_GRID_DROP_LEFT_BEFORE;
                     break;
                 }
             }
@@ -546,7 +546,7 @@ gboolean panel_icon_grid_get_dest_at_pos(PanelIconGrid * ig, gint x, gint y,
                 {
                     /* reached next row */
                     if (upper)
-                        drop_pos = rtl ? PANEL_ICON_GRID_DROP_RIGHT : PANEL_ICON_GRID_DROP_LEFT;
+                        drop_pos = rtl ? PANEL_ICON_GRID_DROP_RIGHT_BEFORE : PANEL_ICON_GRID_DROP_LEFT_BEFORE;
                     else
                         drop_pos = PANEL_ICON_GRID_DROP_ABOVE;
                     break;
@@ -562,7 +562,7 @@ gboolean panel_icon_grid_get_dest_at_pos(PanelIconGrid * ig, gint x, gint y,
             else if (rtl)
             {
                 /* reached next column */
-                drop_pos = PANEL_ICON_GRID_DROP_RIGHT;
+                drop_pos = PANEL_ICON_GRID_DROP_RIGHT_BEFORE;
                 break;
             }
         }
@@ -589,7 +589,7 @@ gboolean panel_icon_grid_get_dest_at_pos(PanelIconGrid * ig, gint x, gint y,
                         if (upper)
                             drop_pos = PANEL_ICON_GRID_DROP_ABOVE;
                         else
-                            drop_pos = PANEL_ICON_GRID_DROP_LEFT;
+                            drop_pos = PANEL_ICON_GRID_DROP_LEFT_BEFORE;
                         break;
                     }
                 }
@@ -605,7 +605,7 @@ gboolean panel_icon_grid_get_dest_at_pos(PanelIconGrid * ig, gint x, gint y,
                     if (upper)
                         drop_pos = PANEL_ICON_GRID_DROP_ABOVE;
                     else
-                        drop_pos = PANEL_ICON_GRID_DROP_RIGHT;
+                        drop_pos = PANEL_ICON_GRID_DROP_RIGHT_BEFORE;
                     break;
                 }
                 upper = FALSE;
@@ -619,9 +619,9 @@ gboolean panel_icon_grid_get_dest_at_pos(PanelIconGrid * ig, gint x, gint y,
         if (ig->orientation != GTK_ORIENTATION_HORIZONTAL)
             drop_pos = PANEL_ICON_GRID_DROP_BELOW;
         else if (rtl)
-            drop_pos = PANEL_ICON_GRID_DROP_LEFT;
+            drop_pos = PANEL_ICON_GRID_DROP_LEFT_AFTER;
         else
-            drop_pos = PANEL_ICON_GRID_DROP_RIGHT;
+            drop_pos = PANEL_ICON_GRID_DROP_RIGHT_AFTER;
     }
     if (child)
         *child = (ige == NULL) ? NULL : ige->data;
@@ -648,13 +648,15 @@ static void panel_icon_grid_queue_draw_child(PanelIconGrid * ig, GtkWidget * chi
 
     switch (ig->dest_pos)
     {
-    case PANEL_ICON_GRID_DROP_LEFT:
+    case PANEL_ICON_GRID_DROP_LEFT_AFTER:
+    case PANEL_ICON_GRID_DROP_LEFT_BEFORE:
         rect.x = allocation.x - ig->spacing - border;
         rect.width = border + ig->spacing;
         rect.y = allocation.y;
         rect.height = allocation.height;
         break;
-    case PANEL_ICON_GRID_DROP_RIGHT:
+    case PANEL_ICON_GRID_DROP_RIGHT_AFTER:
+    case PANEL_ICON_GRID_DROP_RIGHT_BEFORE:
         rect.x = allocation.x + allocation.width;
         rect.width = border + ig->spacing;
         rect.y = allocation.y;
@@ -719,6 +721,16 @@ void panel_icon_grid_set_drag_dest(PanelIconGrid * ig, GtkWidget * child,
     }
 }
 
+PanelIconGridDropPosition panel_icon_grid_get_drag_dest(PanelIconGrid * ig,
+                                                        GtkWidget ** child)
+{
+    g_return_val_if_fail(PANEL_IS_ICON_GRID(ig), 0);
+
+    if (child)
+        *child = ig->dest_item;
+    return ig->dest_pos;
+}
+
 G_DEFINE_TYPE_WITH_CODE(PanelIconGrid, panel_icon_grid, GTK_TYPE_CONTAINER,
                         G_IMPLEMENT_INTERFACE(GTK_TYPE_ORIENTABLE, NULL));
 
@@ -936,13 +948,15 @@ static gboolean panel_icon_grid_expose(GtkWidget *widget, GdkEventExpose *event)
 #endif
             switch(ig->dest_pos)
             {
-            case PANEL_ICON_GRID_DROP_LEFT:
+            case PANEL_ICON_GRID_DROP_LEFT_AFTER:
+            case PANEL_ICON_GRID_DROP_LEFT_BEFORE:
                 rect.x = allocation.x - ig->spacing - border;
                 rect.width = border + ig->spacing;
                 rect.y = allocation.y;
                 rect.height = allocation.height;
                 break;
-            case PANEL_ICON_GRID_DROP_RIGHT:
+            case PANEL_ICON_GRID_DROP_RIGHT_AFTER:
+            case PANEL_ICON_GRID_DROP_RIGHT_BEFORE:
                 rect.x = allocation.x + allocation.width;
                 rect.width = border + ig->spacing;
                 rect.y = allocation.y;
index c1bd120..b6ea9a1 100644 (file)
@@ -75,8 +75,10 @@ extern void panel_icon_grid_reorder_child(PanelIconGrid * ig, GtkWidget * child,
                                                /* Reorder the position of a child in the icon grid */
 
 typedef enum {
-    PANEL_ICON_GRID_DROP_LEFT,
-    PANEL_ICON_GRID_DROP_RIGHT,
+    PANEL_ICON_GRID_DROP_LEFT_AFTER,
+    PANEL_ICON_GRID_DROP_LEFT_BEFORE,
+    PANEL_ICON_GRID_DROP_RIGHT_AFTER,
+    PANEL_ICON_GRID_DROP_RIGHT_BEFORE,
     PANEL_ICON_GRID_DROP_BELOW,
     PANEL_ICON_GRID_DROP_ABOVE,
     PANEL_ICON_GRID_DROP_INTO
@@ -114,6 +116,20 @@ gboolean panel_icon_grid_get_dest_at_pos(PanelIconGrid * ig, gint x, gint y,
 void panel_icon_grid_set_drag_dest(PanelIconGrid * ig, GtkWidget * child,
                                    PanelIconGridDropPosition pos);
 
+/**
+ * panel_icon_grid_get_drag_dest
+ * @ig: a widget
+ * @child: (allow-none): pointer to pointer to a child
+ *
+ * Retrieves data last set with panel_icon_grid_set_drag_dest()
+ *
+ * Returns: position to drop.
+ *
+ * Since: 0.9.0
+ */
+PanelIconGridDropPosition panel_icon_grid_get_drag_dest(PanelIconGrid * ig,
+                                                        GtkWidget ** child);
+
 G_END_DECLS
 
 #endif