desktop-icons

git clone git://source.orangerot.dev:/desktop-icons.git
Log | Files | Refs | README | LICENSE

dicons.c (8937B)


      1 #include <gtk/gtk.h>
      2 #include <gio/gdesktopappinfo.h>
      3 #include <gio/gio.h>
      4 #include <gtk-layer-shell/gtk-layer-shell.h>
      5 
      6 enum
      7 {
      8     COL_PIXBUF,
      9     COL_DISPLAY_NAME,
     10     COL_FILE,
     11     COL_FILE_INFO,
     12     NUM_COLS
     13 };
     14 
     15 static GtkTargetEntry targets[] =
     16 {
     17     { "text/uri-list", 0, 0 }
     18 };
     19 
     20 GtkIconTheme *theme;
     21 
     22 void remove_row_by_file(GtkListStore *store, GFile *file)
     23 {
     24     GtkTreeIter iter;
     25     GFile *file_iter;
     26     gboolean valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
     27 
     28     while (valid) 
     29     {
     30         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, COL_FILE, &file_iter, -1);
     31 
     32         if (g_file_equal(file, file_iter))
     33         {
     34             gtk_list_store_remove(store, &iter);   
     35             return;
     36         } 
     37         valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
     38     }
     39     
     40 }
     41 
     42 void append_row_from_file(GtkListStore *store, GFile *file)
     43 {
     44     GtkTreeIter iter;
     45     GFileInfo *file_info;
     46     GdkPixbuf *pixbuf;
     47     GAppInfo *app;
     48     const gchar *display_name = NULL;
     49     GIcon *icon = NULL;
     50 
     51     GKeyFile *keyfile = g_key_file_new ();
     52     file_info = g_file_query_info(file, "standard::*,ownser::user", 0, 0, 0);
     53     if (g_key_file_load_from_file (keyfile, g_file_get_path(file), G_KEY_FILE_NONE, NULL))
     54     {
     55         app = (GAppInfo*)g_desktop_app_info_new_from_keyfile (keyfile);
     56         if (app) {
     57             display_name = g_app_info_get_display_name(app);
     58             icon = g_app_info_get_icon(app);
     59         }
     60     }
     61 
     62     if (!display_name)
     63         display_name = g_file_info_get_display_name(file_info);
     64     if (!icon)
     65         icon = g_file_info_get_icon(file_info);
     66 
     67     pixbuf = gtk_icon_info_load_icon(
     68             gtk_icon_theme_lookup_by_gicon(theme, icon, 48, 0), 0);
     69 
     70     gtk_list_store_append(store, &iter);
     71     gtk_list_store_set(store, &iter,
     72             COL_PIXBUF, pixbuf,
     73             COL_DISPLAY_NAME, display_name,
     74             COL_FILE, file, 
     75             COL_FILE_INFO, file_info,
     76             -1
     77             );
     78 }
     79 
     80 // Callback function for file created signal
     81 static void file_changed_cb(GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent evtype, gpointer user_data)
     82 {
     83     GtkListStore *store = GTK_LIST_STORE(user_data);
     84     switch(evtype) {
     85         case G_FILE_MONITOR_EVENT_DELETED:
     86             remove_row_by_file(store, file);
     87             break;
     88         case G_FILE_MONITOR_EVENT_CREATED:
     89             append_row_from_file(store, file);
     90             break;
     91     }
     92 }
     93 
     94 static void drop_data_cb(GtkWidget* self, GdkDragContext* context, gint x, gint y, GtkSelectionData* data, guint info, guint time, gpointer user_data)
     95 {
     96     const gchar *desktop_path;
     97     gchar **uris;
     98     GFile *file, *dir_file;
     99     GFileInfo *file_info;
    100 
    101     desktop_path = g_get_user_special_dir(G_USER_DIRECTORY_DESKTOP);
    102     dir_file = g_file_new_for_path(desktop_path);
    103     printf("test\n");
    104 
    105     uris = gtk_selection_data_get_uris(data);
    106     for (gchar **uri = uris; *uri != 0; uri++)
    107     {
    108         printf("dropped %s\n", *uri);
    109         file = g_file_new_for_uri(*uri);
    110         file_info = g_file_query_info(file, "standard::*,owner:.user", 0, 0, 0);
    111         
    112         g_file_copy(file, g_file_get_child(dir_file, g_file_info_get_name(file_info)), G_FILE_COPY_NONE, 0, 0, 0, 0);
    113     }
    114     gtk_drag_finish(context, TRUE, FALSE, time);
    115 }
    116 
    117 static void drag_data_cb(GtkWidget* widget, GdkDragContext* context, GtkSelectionData* data, guint info, guint time, gpointer user_data)
    118 {
    119     GList *selected_items, *iter;
    120     GtkTreeModel *model = GTK_TREE_MODEL(user_data);
    121     gchar **uris;
    122     int index = 0;
    123 
    124     selected_items = gtk_icon_view_get_selected_items(GTK_ICON_VIEW(widget));
    125     uris = g_new(gchar*, g_list_length(selected_items) + 1);
    126     for (iter = selected_items; iter != NULL; iter = iter->next) 
    127     {
    128         GtkTreeIter tree_iter;
    129         GFile *file;
    130         gtk_tree_model_get_iter(model, &tree_iter, (GtkTreePath *)iter->data);
    131         gtk_tree_model_get(model, &tree_iter, COL_FILE, &file, -1);
    132         uris[index++] = g_file_get_uri(file);
    133     }
    134     gtk_selection_data_set_uris(data, uris);
    135 }
    136 
    137 static GtkListStore *create_desktop_list(void)
    138 {
    139     GtkTreeIter iter;
    140     GtkListStore *store;
    141     GDir *dir;
    142     GFile *file, *dir_file;
    143     GFileMonitor *monitor;
    144     const gchar *desktop_path, *file_name;
    145 
    146     desktop_path = g_get_user_special_dir(G_USER_DIRECTORY_DESKTOP);
    147     printf("desktop-path: %s\n", desktop_path);
    148 
    149     store = gtk_list_store_new(NUM_COLS,
    150             GDK_TYPE_PIXBUF,
    151             G_TYPE_STRING,
    152             G_TYPE_FILE,
    153             G_TYPE_FILE_INFO);
    154 
    155     dir = g_dir_open(desktop_path, 0, 0);
    156     dir_file = g_file_new_for_path(desktop_path);
    157     monitor = g_file_monitor_directory(dir_file, G_FILE_MONITOR_NONE, NULL, NULL);
    158 
    159     while ( (file_name = g_dir_read_name(dir)) ) {
    160         printf("contains: %s\n", file_name);
    161 
    162         file = g_file_new_for_path(g_build_filename(desktop_path, file_name, NULL));
    163         append_row_from_file(store, file);
    164     }
    165 
    166     g_signal_connect(monitor, "changed", G_CALLBACK(file_changed_cb), store);
    167 
    168     return GTK_LIST_STORE(store);
    169 }
    170 
    171 static void launch_default_or_app_for_file(GFile *desktop_file) {
    172     GAppInfo *app;
    173     GKeyFile *keyfile = g_key_file_new ();
    174     char* file_uri;
    175 
    176     if (g_key_file_load_from_file (keyfile, g_file_get_path(desktop_file), G_KEY_FILE_NONE, NULL))
    177     {
    178         app = (GAppInfo*)g_desktop_app_info_new_from_keyfile (keyfile);
    179         if (app) {
    180             GAppLaunchContext* app_context = g_app_launch_context_new ();
    181             g_app_info_launch(app, NULL, app_context, NULL);
    182             g_clear_object (&app_context);
    183             return;
    184         }
    185     }
    186     // Not a .desktop, falling back to xdg open
    187     file_uri = g_file_get_uri(desktop_file);
    188     g_app_info_launch_default_for_uri(file_uri, 0, 0);
    189 }
    190 
    191 static void activate_cb(GtkIconView *icon_view, GtkTreePath *tree_path, gpointer user_data)
    192 {
    193     GtkListStore *store;
    194     GtkTreeIter iter;
    195     GFile *file;
    196     store = GTK_LIST_STORE (user_data);
    197 
    198     gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, tree_path);
    199 
    200     gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, COL_FILE, &file, -1);
    201 
    202     launch_default_or_app_for_file(file);
    203 }
    204 
    205 static GtkWidget *window_new(GtkApplication *app, GtkListStore *model)
    206 {
    207     GtkWidget *window, *icon_view;
    208 
    209     window = gtk_application_window_new(app);
    210     gtk_window_set_title(GTK_WINDOW (window), "Window");
    211 
    212     gtk_layer_init_for_window(GTK_WINDOW(window));
    213     gtk_layer_set_namespace(GTK_WINDOW(window), "desktop-icons");
    214     gtk_layer_set_layer(GTK_WINDOW(window), GTK_LAYER_SHELL_LAYER_BOTTOM);
    215 
    216     for (int anchor = 0; anchor < 4; anchor++) 
    217         gtk_layer_set_anchor(GTK_WINDOW(window), anchor, 1); 
    218 
    219     gtk_layer_set_margin(GTK_WINDOW(window), GTK_LAYER_SHELL_EDGE_TOP, 20);
    220 
    221     icon_view = gtk_icon_view_new_with_model(GTK_TREE_MODEL(model));
    222 
    223     gtk_widget_override_background_color(icon_view, 0, &(GdkRGBA){0,0,0,0});
    224     gtk_widget_override_background_color(window, 0, &(GdkRGBA){0,0,0,0});
    225 
    226     gtk_icon_view_set_item_width(GTK_ICON_VIEW(icon_view), 96);
    227     gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (icon_view),
    228             GTK_SELECTION_MULTIPLE);
    229     gtk_icon_view_set_text_column(GTK_ICON_VIEW (icon_view), COL_DISPLAY_NAME);
    230     gtk_icon_view_set_pixbuf_column(GTK_ICON_VIEW (icon_view), COL_PIXBUF);
    231 
    232     gtk_drag_dest_set(icon_view, GTK_DEST_DEFAULT_ALL, targets, G_N_ELEMENTS(targets), GDK_ACTION_COPY);
    233     gtk_icon_view_enable_model_drag_source (
    234             GTK_ICON_VIEW(icon_view),
    235             GDK_BUTTON1_MASK,
    236             targets,
    237             G_N_ELEMENTS(targets),
    238             GDK_ACTION_COPY
    239             );
    240 
    241     g_signal_connect(icon_view, "item-activated", G_CALLBACK(activate_cb), model);
    242     g_signal_connect(icon_view, "drag-data-received", G_CALLBACK(drop_data_cb), model);
    243     g_signal_connect(icon_view, "drag-data-get", G_CALLBACK(drag_data_cb), model);
    244 
    245     gtk_container_add(GTK_CONTAINER(window), icon_view);
    246     gtk_widget_grab_focus (icon_view);
    247 
    248     gtk_widget_show_all (window);
    249     
    250     return window;
    251 }
    252 
    253 static void activate (GtkApplication* app, gpointer user_data)
    254 {
    255     GtkWidget *window, *icon_view;
    256     GtkListStore *model;
    257 
    258     GdkDisplay *display;
    259 
    260     display = gdk_display_get_default();
    261 
    262     theme = gtk_icon_theme_get_default();
    263     model = create_desktop_list();
    264 
    265     GdkMonitor *monitor;
    266 
    267     for (int i = 0; i < gdk_display_get_n_monitors(display); i++)
    268     {
    269         monitor = gdk_display_get_monitor(display, i);
    270         window = window_new(app, model);
    271         gtk_layer_set_monitor(GTK_WINDOW(window), monitor);
    272     }
    273 
    274 }
    275 
    276 int main (int argc, char **argv)
    277 {
    278     GtkApplication *app;
    279     int status;
    280 
    281     app = gtk_application_new("dev.orangerot.dicons", G_APPLICATION_DEFAULT_FLAGS);
    282     g_signal_connect(app, "activate", G_CALLBACK (activate), NULL);
    283     status = g_application_run(G_APPLICATION (app), argc, argv);
    284     g_object_unref(app);
    285 
    286     return status;
    287 }
    288