Documentation: Use G_SOURCE_CONTINUE and G_SOURCE_REMOVE
[geeqie.git] / src / remote.cc
index f123510..f7ffc29 100644 (file)
@@ -116,7 +116,7 @@ static gchar *set_pwd(gchar *filename)
 
 static gboolean remote_server_client_cb(GIOChannel *source, GIOCondition condition, gpointer data)
 {
-       RemoteClient *client = data;
+       RemoteClient *client = static_cast<RemoteClient *>(data);
        RemoteConnection *rc;
        GIOStatus status = G_IO_STATUS_NORMAL;
 
@@ -187,7 +187,7 @@ static void remote_server_client_add(RemoteConnection *rc, gint fd)
        client->fd = fd;
 
        channel = g_io_channel_unix_new(fd);
-       client->channel_id = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, G_IO_IN | G_IO_HUP,
+       client->channel_id = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, static_cast<GIOCondition>(G_IO_IN | G_IO_HUP),
                                                 remote_server_client_cb, client, NULL);
        g_io_channel_unref(channel);
 
@@ -199,7 +199,7 @@ static void remote_server_clients_close(RemoteConnection *rc)
 {
        while (rc->clients)
                {
-               RemoteClient *client = rc->clients->data;
+               RemoteClient *client = static_cast<RemoteClient *>(rc->clients->data);
 
                rc->clients = g_list_remove(rc->clients, client);
 
@@ -211,7 +211,7 @@ static void remote_server_clients_close(RemoteConnection *rc)
 
 static gboolean remote_server_read_cb(GIOChannel *UNUSED(source), GIOCondition UNUSED(condition), gpointer data)
 {
-       RemoteConnection *rc = data;
+       RemoteConnection *rc = static_cast<RemoteConnection *>(data);
        gint fd;
        guint alen;
 
@@ -463,18 +463,18 @@ static void gr_new_window(const gchar *UNUSED(text), GIOChannel *UNUSED(channel)
        layout_set_path(lw_id, pwd);
 }
 
-static gboolean gr_close_window_cb()
+static gboolean gr_close_window_cb(gpointer UNUSED(data))
 {
        if (!layout_valid(&lw_id)) return FALSE;
 
        layout_menu_close_cb(NULL, lw_id);
 
-       return FALSE;
+       return G_SOURCE_REMOVE;
 }
 
 static void gr_close_window(const gchar *UNUSED(text), GIOChannel *UNUSED(channel), gpointer UNUSED(data))
 {
-       g_idle_add(gr_close_window_cb, NULL);
+       g_idle_add((gr_close_window_cb), NULL);
 }
 
 static void gr_image_prev(const gchar *UNUSED(text), GIOChannel *UNUSED(channel), gpointer UNUSED(data))
@@ -674,7 +674,7 @@ static gboolean gr_quit_idle_cb(gpointer UNUSED(data))
 {
        exit_program();
 
-       return FALSE;
+       return G_SOURCE_REMOVE;
 }
 
 static void gr_quit(const gchar *UNUSED(text), GIOChannel *UNUSED(channel), gpointer UNUSED(data))
@@ -876,7 +876,7 @@ static void get_filelist(const gchar *text, GIOChannel *channel, gboolean recurs
        work = list;
        while (work)
                {
-               fd = work->data;
+               fd = static_cast<FileData *>(work->data);
                g_string_append_printf(out_string, "%s", fd->path);
                format_class = filter_file_get_class(fd->path);
 
@@ -922,6 +922,200 @@ static void get_filelist(const gchar *text, GIOChannel *channel, gboolean recurs
        file_data_unref(dir_fd);
 }
 
+static void gr_get_selection(const gchar *UNUSED(text), GIOChannel *channel, gpointer UNUSED(data))
+{
+       if (!layout_valid(&lw_id)) return;
+
+       GList *selected = layout_selection_list(lw_id);  // Keep copy to free.
+       GString *out_string = g_string_new(NULL);
+
+       GList *work = selected;
+       while (work)
+               {
+               FileData *fd = static_cast<FileData *>(work->data);
+               g_assert(fd->magick == FD_MAGICK);
+
+               g_string_append_printf(out_string, "%s    %s\n",
+                                      fd->path,
+                                      format_class_list[filter_file_get_class(fd->path)]);
+
+               work = work->next;
+               }
+
+       g_io_channel_write_chars(channel, out_string->str, -1, NULL, NULL);
+       g_io_channel_write_chars(channel, "<gq_end_of_command>", -1, NULL, NULL);
+
+       filelist_free(selected);
+       g_string_free(out_string, TRUE);
+}
+
+static void gr_selection_add(const gchar *text, GIOChannel *UNUSED(channel), gpointer UNUSED(data))
+{
+       if (!layout_valid(&lw_id)) return;
+
+       FileData *fd_to_select = NULL;
+       if (strcmp(text, "") == 0)
+               {
+               // No file specified, use current fd.
+               fd_to_select = layout_image_get_fd(lw_id);
+               }
+       else
+               {
+               // Search through the current file list for a file matching the specified path.
+               // "Match" is either a basename match or a file path match.
+               gchar *path = expand_tilde(text);
+               gchar *filename = g_path_get_basename(path);
+               gchar *slash_plus_filename = g_strdup_printf("%s%s", G_DIR_SEPARATOR_S, filename);
+
+               GList *file_list = layout_list(lw_id);
+               for (GList *work = file_list; work && !fd_to_select; work = work->next)
+                       {
+                       FileData *fd = static_cast<FileData *>(work->data);
+                       if (!strcmp(path, fd->path) || g_str_has_suffix(fd->path, slash_plus_filename))
+                               {
+                               fd_to_select = file_data_ref(fd);
+                               continue;  // will exit loop.
+                               }
+
+                       for (GList *sidecar = fd->sidecar_files; sidecar && !fd_to_select; sidecar = sidecar->next)
+                               {
+                               FileData *side_fd = static_cast<FileData *>(sidecar->data);
+                               if (!strcmp(path, side_fd->path)
+                                   || g_str_has_suffix(side_fd->path, slash_plus_filename))
+                                       {
+                                       fd_to_select = file_data_ref(side_fd);
+                                       continue;  // will exit both nested loops.
+                                       }
+                               }
+                       }
+
+               if (!fd_to_select)
+                       {
+                       log_printf("remote sent --selection-add filename that could not be found: \"%s\"\n",
+                                  filename);
+                       }
+
+               filelist_free(file_list);
+               g_free(slash_plus_filename);
+               g_free(filename);
+               g_free(path);
+               }
+
+       if (fd_to_select)
+               {
+               GList *to_select = g_list_append(NULL, fd_to_select);
+               // Using the "_list" variant doesn't clear the existing selection.
+               layout_select_list(lw_id, to_select);
+               filelist_free(to_select);
+               }
+}
+
+static void gr_selection_clear(const gchar *UNUSED(text), GIOChannel *UNUSED(channel), gpointer UNUSED(data))
+{
+       layout_select_none(lw_id);  // Checks lw_id validity internally.
+}
+
+static void gr_selection_remove(const gchar *text, GIOChannel *UNUSED(channel), gpointer UNUSED(data))
+{
+       if (!layout_valid(&lw_id)) return;
+
+       GList *selected = layout_selection_list(lw_id);  // Keep copy to free.
+       if (!selected)
+               {
+               log_printf("remote sent --selection-remove with empty selection.");
+               return;
+               }
+
+       FileData *fd_to_deselect = NULL;
+       gchar *path = NULL;
+       gchar *filename = NULL;
+       gchar *slash_plus_filename = NULL;
+       if (strcmp(text, "") == 0)
+               {
+               // No file specified, use current fd.
+               fd_to_deselect = layout_image_get_fd(lw_id);
+               if (!fd_to_deselect)
+                       {
+                       log_printf("remote sent \"--selection-remove:\" with no current image");
+                       filelist_free(selected);
+                       return;
+                       }
+               }
+       else
+               {
+               // Search through the selection list for a file matching the specified path.
+               // "Match" is either a basename match or a file path match.
+               path = expand_tilde(text);
+               filename = g_path_get_basename(path);
+               slash_plus_filename = g_strdup_printf("%s%s", G_DIR_SEPARATOR_S, filename);
+               }
+
+       GList *prior_link = NULL;  // Stash base for link removal to avoid a second traversal.
+       GList *link_to_remove = NULL;
+       for (GList *work = selected; work; prior_link = work, work = work->next)
+               {
+               FileData *fd = static_cast<FileData *>(work->data);
+               if (fd_to_deselect)
+                       {
+                       if (fd == fd_to_deselect)
+                               {
+                               link_to_remove = work;
+                               break;
+                               }
+                       }
+               else
+                       {
+                       // path, filename, and slash_plus_filename should be defined.
+
+                       if (!strcmp(path, fd->path) || g_str_has_suffix(fd->path, slash_plus_filename))
+                               {
+                               link_to_remove = work;
+                               break;
+                               }
+                       }
+               }
+
+       if (!link_to_remove)
+               {
+               if (fd_to_deselect)
+                       {
+                       log_printf("remote sent \"--selection-remove:\" but current image is not selected");
+                       }
+               else
+                       {
+                       log_printf("remote sent \"--selection-remove:%s\" but that filename is not selected",
+                                  filename);
+                       }
+               }
+       else
+               {
+               if (link_to_remove == selected)
+                       {
+                       // Remove first link.
+                       selected = g_list_remove_link(selected, link_to_remove);
+                       filelist_free(link_to_remove);
+                       link_to_remove = NULL;
+                       }
+               else
+                       {
+                       // Remove a subsequent link.
+                       prior_link = g_list_remove_link(prior_link, link_to_remove);
+                       filelist_free(link_to_remove);
+                       link_to_remove = NULL;
+                       }
+
+               // Re-select all but the deselected item.
+               layout_select_none(lw_id);
+               layout_select_list(lw_id, selected);
+               }
+
+       filelist_free(selected);
+       file_data_unref(fd_to_deselect);
+       g_free(slash_plus_filename);
+       g_free(filename);
+       g_free(path);
+}
+
 static void gr_collection(const gchar *text, GIOChannel *channel, gpointer UNUSED(data))
 {
        GString *contents = g_string_new(NULL);
@@ -953,7 +1147,7 @@ static void gr_collection_list(const gchar *UNUSED(text), GIOChannel *channel, g
        work = collection_list;
        while (work)
                {
-               const gchar *collection_name = work->data;
+               const gchar *collection_name = static_cast<const gchar *>(work->data);
                out_string = g_string_append(out_string, g_strdup(collection_name));
                out_string = g_string_append(out_string, "\n");
 
@@ -975,7 +1169,7 @@ static gboolean wait_cb(const gpointer data)
 
        gtk_window_move(GTK_WINDOW(lw_id->window), x, y);
 
-       return FALSE;
+       return G_SOURCE_REMOVE;
 }
 
 static void gr_geometry(const gchar *text, GIOChannel *UNUSED(channel), gpointer UNUSED(data))
@@ -1202,7 +1396,7 @@ static void gr_get_sidecars(const gchar *text, GIOChannel *channel, gpointer UNU
 
        while (work)
                {
-               fd = work->data;
+               fd = static_cast<FileData *>(work->data);
                work = work->next;
                g_io_channel_write_chars(channel, fd->path, -1, NULL, NULL);
                g_io_channel_write_chars(channel, "<gq_end_of_command>", -1, NULL, NULL);
@@ -1237,7 +1431,7 @@ static void gr_file_view(const gchar *text, GIOChannel *UNUSED(channel), gpointe
 
 static void gr_list_clear(const gchar *UNUSED(text), GIOChannel *UNUSED(channel), gpointer data)
 {
-       RemoteData *remote_data = data;
+       RemoteData *remote_data = static_cast<RemoteData *>(data);
 
        remote_data->command_collection = NULL;
        remote_data->file_list = NULL;
@@ -1246,12 +1440,20 @@ static void gr_list_clear(const gchar *UNUSED(text), GIOChannel *UNUSED(channel)
 
 static void gr_list_add(const gchar *text, GIOChannel *UNUSED(channel), gpointer data)
 {
-       RemoteData *remote_data = data;
+       RemoteData *remote_data = static_cast<RemoteData *>(data);
        gboolean is_new = TRUE;
        gchar *path = NULL;
        FileData *fd;
        FileData *first;
 
+       /** @FIXME Should check if file is in current dir, has tilde or is relative */
+       if (!isfile(text))
+               {
+               log_printf("Warning: File does not exist --remote --list-add:%s", text);
+
+               return;
+               }
+
        /* If there is a files list on the command line
         * check if they are all in the same folder
         */
@@ -1383,13 +1585,13 @@ static void gr_lua(const gchar *text, GIOChannel *channel, gpointer UNUSED(data)
 
 typedef struct _RemoteCommandEntry RemoteCommandEntry;
 struct _RemoteCommandEntry {
-       gchar *opt_s;
-       gchar *opt_l;
+       const gchar *opt_s;
+       const gchar *opt_l;
        void (*func)(const gchar *text, GIOChannel *channel, gpointer data);
        gboolean needs_extra;
        gboolean prefer_command_line;
-       gchar *parameter;
-       gchar *description;
+       const gchar *parameter;
+       const gchar *description;
 };
 
 static RemoteCommandEntry remote_commands[] = {
@@ -1422,6 +1624,7 @@ static RemoteCommandEntry remote_commands[] = {
        { NULL, "--get-filelist-recurse:", gr_filelist_recurse, TRUE,  FALSE, N_("[<FOLDER>]"), N_("get list of files and class recursive") },
        { NULL, "--get-rectangle",      gr_rectangle,           FALSE, FALSE, NULL, N_("get rectangle co-ordinates") },
        { NULL, "--get-render-intent",  gr_render_intent,       FALSE, FALSE, NULL, N_("get render intent") },
+       { NULL, "--get-selection",      gr_get_selection,       FALSE, FALSE, NULL, N_("get list of selected files") },
        { NULL, "--get-sidecars:",      gr_get_sidecars,        TRUE,  FALSE, N_("<FILE>"), N_("get list of sidecars of FILE") },
        { NULL, "--id:",                gr_lw_id,               TRUE, FALSE, N_("<ID>"), N_("window id for following commands") },
        { NULL, "--last",               gr_image_last,          FALSE, FALSE, NULL, N_("last image") },
@@ -1438,6 +1641,9 @@ static RemoteCommandEntry remote_commands[] = {
        { "-q", "--quit",               gr_quit,                FALSE, FALSE, NULL, N_("quit") },
        { NULL, "--raise",              gr_raise,               FALSE, FALSE, NULL, N_("bring the Geeqie window to the top") },
        { NULL, "raise",                gr_raise,               FALSE, FALSE, NULL, N_("bring the Geeqie window to the top") },
+       { NULL, "--selection-add:",     gr_selection_add,       TRUE,  FALSE, N_("[<FILE>]"), N_("adds the current file (or the specified file) to the current selection") },
+       { NULL, "--selection-clear",    gr_selection_clear,     FALSE, FALSE, NULL, N_("clears the current selection") },
+       { NULL, "--selection-remove:",  gr_selection_remove,    TRUE,  FALSE, N_("[<FILE>]"), N_("removes the current file (or the specified file) from the current selection") },
        { "-s", "--slideshow",          gr_slideshow_toggle,    FALSE, TRUE,  NULL, N_("toggle slide show") },
        { NULL, "--slideshow-recurse:", gr_slideshow_start_rec, TRUE,  FALSE, N_("<FOLDER>"), N_("start recursive slide show in FOLDER") },
        { "-ss","--slideshow-start",    gr_slideshow_start,     FALSE, FALSE, NULL, N_("start slide show") },
@@ -1589,7 +1795,7 @@ void remote_control(const gchar *arg_exec, GList *remote_list, const gchar *path
                        gchar *text;
                        RemoteCommandEntry *entry;
 
-                       text = work->data;
+                       text = static_cast<gchar *>(work->data);
                        work = work->next;
 
                        entry = remote_command_find(text, NULL);
@@ -1647,7 +1853,7 @@ void remote_control(const gchar *arg_exec, GList *remote_list, const gchar *path
                        gchar *text;
                        RemoteCommandEntry *entry;
 
-                       text = work->data;
+                       text = static_cast<gchar *>(work->data);
                        work = work->next;
 
                        entry = remote_command_find(text, NULL);
@@ -1700,7 +1906,7 @@ void remote_control(const gchar *arg_exec, GList *remote_list, const gchar *path
                        const gchar *name;
                        gchar *text;
 
-                       name = work->data;
+                       name = static_cast<const gchar *>(work->data);
                        work = work->next;
 
                        text = g_strdup_printf("file:%s", name);