/*
- * GQview image viewer
- * (C)2000 John Ellis
+ * GQview
+ * (C) 2004 John Ellis
*
* Author: John Ellis
*
+ * This software is released under the GNU General Public License (GNU GPL).
+ * Please read the included file COPYING for more information.
+ * This software comes with no warranty of any kind, use at your own risk!
*/
+
#include "gqview.h"
+
+#include "cache.h"
+#include "collect.h"
+#include "collect-io.h"
+#include "dnd.h"
+#include "editors.h"
+#include "filelist.h"
+#include "img-view.h"
+#include "layout.h"
+#include "layout_image.h"
+#include "menu.h"
+#include "preferences.h"
+#include "rcfile.h"
+#include "remote.h"
+#include "similar.h"
+#include "slideshow.h"
+#include "utilops.h"
+#include "ui_bookmark.h"
+#include "ui_help.h"
+#include "ui_fileops.h"
+#include "ui_tabcomp.h"
+#include "ui_utildlg.h"
+
#include <gdk/gdkkeysyms.h> /* for keyboard values */
-static void parse_command_line(int argc, char *argv[], gchar **path, gchar **file);
-static void setup_default_options();
+#include "icons/icon.xpm"
+
+
+#include <math.h>
+
+
+static RemoteConnection *gqview_remote = NULL;
+static CollectionData *gqview_command_collection = NULL;
+
/*
*-----------------------------------------------------------------------------
- * path manipulation routines (public)
+ * misc (public)
*-----------------------------------------------------------------------------
*/
-gchar *filename_from_path(char *t)
+typedef struct _WindowIconData WindowIconData;
+struct _WindowIconData
+{
+ const char **icon;
+ gchar *path;
+};
+
+static void window_set_icon_cb(GtkWidget *widget, gpointer data)
+{
+ WindowIconData *wid = data;
+ GdkPixbuf *pb;
+ GdkPixmap *pixmap;
+ GdkBitmap *mask;
+
+ if (wid->icon)
+ {
+ pb = gdk_pixbuf_new_from_xpm_data(wid->icon);
+ }
+ else
+ {
+ pb = gdk_pixbuf_new_from_file(wid->path, NULL);
+ }
+
+ g_free(wid->path);
+ g_free(wid);
+
+ if (!pb) return;
+
+ gdk_pixbuf_render_pixmap_and_mask(pb, &pixmap, &mask, 128);
+ gdk_pixbuf_unref(pb);
+
+ gdk_window_set_icon(widget->window, NULL, pixmap, mask);
+ /* apparently, gdk_window_set_icon does not ref the pixmap and mask, so don't unref it (leak?) */
+}
+
+void window_set_icon(GtkWidget *window, const char **icon, const gchar *file)
{
- char *p;
+ WindowIconData *wid;
+
+ if (!icon && !file) icon = (const char **)icon_xpm;
+
+ wid = g_new0(WindowIconData, 1);
+ wid->icon = icon;
+ wid->path = g_strdup(file);
- p = t + strlen(t);
- while(p > t && p[0] != '/') p--;
- if (p[0] == '/') p++;
- return p;
+ g_signal_connect(G_OBJECT(window), "realize",
+ G_CALLBACK(window_set_icon_cb), wid);
}
-gchar *remove_level_from_path(gchar *path)
+gint window_maximized(GtkWidget *window)
{
- gchar *new_path;
- gchar *ptr = path;
- gint p;
+ GdkWindowState state;
- if (!path) return NULL;
+ if (!window || !window->window) return FALSE;
- p = strlen(path) - 1;
- if (p < 0) return NULL;
- while(ptr[p] != '/' && p > 0) p--;
- if (p == 0 && ptr[p] == '/') p++;
- new_path = g_strndup(path, (guint)p);
- return new_path;
+ state = gdk_window_get_state(window->window);
+ return (state & GDK_WINDOW_STATE_MAXIMIZED);
+}
+
+gdouble get_zoom_increment(void)
+{
+ return ((zoom_increment != 0) ? (gdouble)zoom_increment / 10.0 : 1.0);
}
-void parse_out_relatives(gchar *path)
+/*
+ *-----------------------------------------------------------------------------
+ * Open browser with the help Documentation
+ *-----------------------------------------------------------------------------
+ */
+
+static gchar *command_result(const gchar *binary, const gchar *command)
{
- gint s, t;
+ gchar *result = NULL;
+ FILE *f;
+ char buf[2048];
+ int l;
+
+ if (!binary) return NULL;
+ if (!file_in_path(binary)) return NULL;
- if (!path) return;
+ if (!command) return g_strdup(binary);
+ if (command[0] == '!') return g_strdup(command + 1);
- s = t = 0;
+ f = popen(command, "r");
+ if (!f) return NULL;
- while (path[s] != '\0')
+ while ((l = fread(buf, sizeof(char), sizeof(buf), f)) > 0)
{
- if (path[s] == '/' && path[s+1] == '.' && (path[s+2] == '/' || path[s+2] == '\0') )
- {
- s += 2;
- }
- else if (path[s] == '/' && path[s+1] == '.' && path[s+2] == '.' && (path[s+3] == '/' || path[s+3] == '\0') )
- {
- s += 3;
- if (t > 0) t--;
- while (path[t] != '/' && t > 0) t--;
- }
- else
+ if (!result)
{
- if (s != t) path[t] = path[s];
- t++;
- s++;
+ int n = 0;
+
+ while (n < l && buf[n] != '\n' && buf[n] != '\r') n++;
+ if (n > 0) result = g_strndup(buf, n);
}
}
- if (t == 0 && path[t] == '/') t++;
- if (t > 1 && path[t-1] == '/') t--;
- path[t] = '\0';
+
+ pclose(f);
+
+ return result;
+}
+
+static void help_browser_command(const gchar *command, const gchar *path)
+{
+ gchar *result;
+ gchar *buf;
+ gchar *begin;
+ gchar *end;
+
+ if (!command || !path) return;
+
+ if (debug) printf("Help command pre \"%s\", \"%s\"\n", command, path);
+
+ buf = g_strdup(command);
+ begin = strstr(buf, "%s");
+ if (begin)
+ {
+ *begin = '\0';
+ end = begin + 2;
+ begin = buf;
+
+ result = g_strdup_printf("%s%s%s &", begin, path, end);
+ }
+ else
+ {
+ result = g_strdup_printf("%s \"%s\" &", command, path);
+ }
+ g_free(buf);
+
+ if (debug) printf("Help command post [%s]\n", result);
+
+ system(result);
+
+ g_free(result);
+}
+
+/*
+ * each set of 2 strings is one browser:
+ * the 1st is the binary to look for in the path
+ * the 2nd has 3 capabilities:
+ * NULL exec binary with html file path as command line
+ * string exec string and use results for command line
+ * !string use text following ! as command line, replacing optional %s with html file path
+*/
+static gchar *html_browsers[] =
+{
+ /* Redhat has a nifty htmlview script to start the user's preferred browser */
+ "htmlview", NULL,
+ /* GNOME 2 */
+ "gconftool-2", "gconftool-2 -g /desktop/gnome/url-handlers/http/command",
+ /* KDE */
+ "kfmclient", "!kfmclient exec \"%s\"",
+ /* use fallbacks */
+ "firefox", NULL,
+ "mozilla", NULL,
+ "konqueror", NULL,
+ "netscape", NULL,
+ NULL, NULL
+};
+
+static void help_browser_run(void)
+{
+ gchar *result = NULL;
+ gint i;
+
+ i = 0;
+ while (!result && html_browsers[i])
+ {
+ result = command_result(html_browsers[i], html_browsers[i+1]);
+ i += 2;
+ }
+
+ if (!result)
+ {
+ printf("Unable to detect an installed browser.\n");
+ return;
+ }
+
+ help_browser_command(result, GQVIEW_HTMLDIR "/index.html");
+
+ g_free(result);
}
/*
*-----------------------------------------------------------------------------
- * external editor start routines (public)
+ * help window
*-----------------------------------------------------------------------------
*/
-void start_editor_from_file(gint n, gchar *path)
-{
- gchar *cmd;
- if (!path) return;
- cmd = g_strdup_printf("%s \"%s\" &", editor_command[n], path);
- printf(_("GQview running: %s\n"),cmd);
- system(cmd);
- g_free(cmd);
-}
+static GtkWidget *help_window = NULL;
-void start_editor_from_image(gint n)
+static void help_window_destroy_cb(GtkWidget *window, gpointer data)
{
- start_editor_from_file(n, image_get_path());
+ help_window = NULL;
}
-void start_editor_from_list(gint n)
+void help_window_show(const gchar *key)
{
- gchar *cmd;
- gchar *buf;
- GList *list = file_get_selected_list();
- GList *work;
- if (!list) return;
- work = list;
- cmd = g_strconcat(editor_command[n], " ", NULL);
- while(work)
+ if (key && strcmp(key, "html_contents") == 0)
{
- buf = cmd;
- cmd = g_strconcat(buf, "\"", work->data, "\" ", NULL);
- g_free(buf);
- work = work->next;
+ help_browser_run();
+ return;
}
- buf = cmd;
- cmd = g_strconcat(buf, "&", NULL);
- g_free(buf);
- printf(_("GQview running: %s\n"),cmd);
- system(cmd);
- g_free(cmd);
- free_selected_list(list);
+
+ if (help_window)
+ {
+ gtk_window_present(GTK_WINDOW(help_window));
+ if (key) help_window_set_key(help_window, key);
+ return;
+ }
+
+ help_window = help_window_new(_("Help - GQview"), "GQview", "help",
+ GQVIEW_HELPDIR "/README", key);
+ g_signal_connect(G_OBJECT(help_window), "destroy",
+ G_CALLBACK(help_window_destroy_cb), NULL);
}
+
/*
*-----------------------------------------------------------------------------
* keyboard functions
static guint32 time_old = 0;
static guint keyval_old = 0;
+ if (event->state & GDK_CONTROL_MASK)
+ {
+ if (*x < 0) *x = G_MININT / 2;
+ if (*x > 0) *x = G_MAXINT / 2;
+ if (*y < 0) *y = G_MININT / 2;
+ if (*y > 0) *y = G_MAXINT / 2;
+
+ return;
+ }
+
if (progressive_key_scrolling)
{
guint32 time_diff;
*y = *y * delta;
}
-gint key_press_cb(GtkWidget *widget, GdkEventKey *event)
+
+/*
+ *-----------------------------------------------------------------------------
+ * remote functions
+ *-----------------------------------------------------------------------------
+ */
+
+static void gr_image_next(const gchar *text, gpointer data)
+{
+ layout_image_next(NULL);
+}
+
+static void gr_image_prev(const gchar *text, gpointer data)
+{
+ layout_image_prev(NULL);
+}
+
+static void gr_image_first(const gchar *text, gpointer data)
+{
+ layout_image_first(NULL);
+}
+
+static void gr_image_last(const gchar *text, gpointer data)
+{
+ layout_image_last(NULL);
+}
+
+static void gr_fullscreen_toggle(const gchar *text, gpointer data)
{
- gint stop_signal = FALSE;
- gint x = 0;
- gint y = 0;
+ layout_image_full_screen_toggle(NULL);
+}
- if (GTK_WIDGET_HAS_FOCUS(path_entry))
+static void gr_fullscreen_start(const gchar *text, gpointer data)
+{
+ layout_image_full_screen_start(NULL);
+}
+
+static void gr_fullscreen_stop(const gchar *text, gpointer data)
+{
+ layout_image_full_screen_stop(NULL);
+}
+
+static void gr_slideshow_start_rec(const gchar *text, gpointer data)
+{
+ GList *list;
+
+ list = path_list_recursive(text);
+ if (!list) return;
+printf("length: %d\n", g_list_length(list));
+ layout_image_slideshow_stop(NULL);
+ layout_image_slideshow_start_from_list(NULL, list);
+}
+
+static void gr_slideshow_toggle(const gchar *text, gpointer data)
+{
+ layout_image_slideshow_toggle(NULL);
+}
+
+static void gr_slideshow_start(const gchar *text, gpointer data)
+{
+ layout_image_slideshow_start(NULL);
+}
+
+static void gr_slideshow_stop(const gchar *text, gpointer data)
+{
+ layout_image_slideshow_stop(NULL);
+}
+
+static void gr_slideshow_delay(const gchar *text, gpointer data)
+{
+ gdouble n;
+
+ n = strtod(text, NULL);
+ if (n < SLIDESHOW_MIN_SECONDS || n > SLIDESHOW_MAX_SECONDS)
+ {
+ gchar *buf;
+
+ buf = g_strdup_printf("Remote slideshow delay out of range (%.1f to %.1f)\n",
+ SLIDESHOW_MIN_SECONDS, SLIDESHOW_MAX_SECONDS);
+ print_term(buf);
+ g_free(buf);
+
+ return;
+ }
+ slideshow_delay = (gint)(n * 10.0 + 0.01);
+}
+
+static void gr_tools_show(const gchar *text, gpointer data)
+{
+ gint popped;
+ gint hidden;
+
+ if (layout_tools_float_get(NULL, &popped, &hidden) && hidden)
+ {
+ layout_tools_float_set(NULL, popped, FALSE);
+ }
+}
+
+static void gr_tools_hide(const gchar *text, gpointer data)
+{
+ gint popped;
+ gint hidden;
+
+ if (layout_tools_float_get(NULL, &popped, &hidden) && !hidden)
{
- if (event->keyval == GDK_Escape)
- gtk_entry_set_text(GTK_ENTRY(path_entry), current_path);
- return stop_signal;
+ layout_tools_float_set(NULL, popped, TRUE);
}
+}
+
+static gint gr_quit_idle_cb(gpointer data)
+{
+ exit_gqview();
- if (full_screen_window || GTK_WIDGET_HAS_FOCUS(main_image->viewport))
+ return FALSE;
+}
+
+static void gr_quit(const gchar *text, gpointer data)
+{
+ /* schedule exit when idle, if done from within a
+ * remote handler remote_close will crash
+ */
+ g_idle_add(gr_quit_idle_cb, NULL);
+}
+
+static void gr_file_load(const gchar *text, gpointer data)
+{
+ if (isfile(text))
{
- switch (event->keyval)
+ if (file_extension_match(text, ".gqv"))
{
- case GDK_Left:
- x -= 1;
- stop_signal = TRUE;
- break;
- case GDK_Right:
- x += 1;
- stop_signal = TRUE;
- break;
- case GDK_Up:
- y -= 1;
- stop_signal = TRUE;
- break;
- case GDK_Down:
- y += 1;
- stop_signal = TRUE;
- break;
- case GDK_BackSpace:
- file_prev_image();
- stop_signal = TRUE;
- break;
- case GDK_space:
- file_next_image();
- stop_signal = TRUE;
- break;
+ collection_window_new(text);
}
+ else
+ {
+ layout_set_path(NULL, text);
+ }
+ }
+ else if (isdir(text))
+ {
+ layout_set_path(NULL, text);
+ }
+ else
+ {
+ printf("remote sent filename that does not exist:\"%s\"\n", text);
}
+}
- switch (event->keyval)
- {
- case '+':
- image_adjust_zoom(1);
- break;
- case GDK_Page_Up:
- file_prev_image();
- stop_signal = TRUE;
- break;
- case GDK_Page_Down:
- file_next_image();
- stop_signal = TRUE;
- break;
- case GDK_Home:
- file_first_image();
- stop_signal = TRUE;
- break;
- case GDK_End:
- file_last_image();
- stop_signal = TRUE;
- break;
- case GDK_Delete:
- file_util_delete(image_get_path(), NULL);
- stop_signal = TRUE;
- break;
- case GDK_Escape:
- interrupt_thumbs();
- stop_signal = TRUE;
- break;
- case 'Q': case 'q':
- if (event->state == 0 || (event->state & GDK_MODIFIER_MASK) == GDK_LOCK_MASK)
+static void gr_file_view(const gchar *text, gpointer data)
+{
+ view_window_new(text);
+}
+
+static void gr_list_clear(const gchar *text, gpointer data)
+{
+ if (gqview_command_collection) collection_unref(gqview_command_collection);
+ gqview_command_collection = NULL;
+}
+
+static void gr_list_add(const gchar *text, gpointer data)
+{
+ gint new = TRUE;
+
+ if (!gqview_command_collection)
+ {
+ CollectionData *cd;
+
+ cd = collection_new("");
+
+ g_free(cd->path);
+ cd->path = NULL;
+ g_free(cd->name);
+ cd->name = g_strdup(_("Command line"));
+
+ gqview_command_collection = cd;
+ }
+ else
+ {
+ new = (!collection_get_first(gqview_command_collection));
+ }
+
+ if (collection_add(gqview_command_collection, text, FALSE) && new)
+ {
+ layout_image_set_collection(NULL, gqview_command_collection,
+ collection_get_first(gqview_command_collection));
+ }
+}
+
+static void gr_raise(const gchar *text, gpointer data)
+{
+ LayoutWindow *lw = NULL;
+
+ if (layout_valid(&lw))
+ {
+ gtk_window_present(GTK_WINDOW(lw->window));
+ }
+}
+
+typedef struct _RemoteCommandEntry RemoteCommandEntry;
+struct _RemoteCommandEntry {
+ gchar *opt_s;
+ gchar *opt_l;
+ void (*func)(const gchar *text, gpointer data);
+ gint needs_extra;
+ gint prefer_command_line;
+ gchar *description;
+};
+
+static RemoteCommandEntry remote_commands[] = {
+ /* short, long callback, extra, prefer,description */
+ { "-n", "--next", gr_image_next, FALSE, FALSE, N_("next image") },
+ { "-b", "--back", gr_image_prev, FALSE, FALSE, N_("previous image") },
+ { NULL, "--first", gr_image_first, FALSE, FALSE, N_("first image") },
+ { NULL, "--last", gr_image_last, FALSE, FALSE, N_("last image") },
+ { "-f", "--fullscreen", gr_fullscreen_toggle, FALSE, TRUE, N_("toggle full screen") },
+ { "-fs","--fullscreen-start", gr_fullscreen_start, FALSE, FALSE, N_("start full screen") },
+ { "-fS","--fullscreen-stop", gr_fullscreen_stop, FALSE, FALSE, N_("stop full screen") },
+ { "-s", "--slideshow", gr_slideshow_toggle, FALSE, TRUE, N_("toggle slide show") },
+ { "-ss","--slideshow-start", gr_slideshow_start, FALSE, FALSE, N_("start slide show") },
+ { "-sS","--slideshow-stop", gr_slideshow_stop, FALSE, FALSE, N_("stop slide show") },
+ { "-sr","--slideshow-recurse", gr_slideshow_start_rec, TRUE, FALSE, N_("start recursive slide show") },
+ { "-d", "--delay=", gr_slideshow_delay, TRUE, FALSE, N_("set slide show delay in seconds") },
+ { "+t", "--tools-show", gr_tools_show, FALSE, TRUE, N_("show tools") },
+ { "-t", "--tools-hide", gr_tools_hide, FALSE, TRUE, N_("hide tools") },
+ { "-q", "--quit", gr_quit, FALSE, FALSE, N_("quit") },
+ { NULL, "file:", gr_file_load, TRUE, FALSE, N_("open file") },
+ { NULL, "view:", gr_file_view, TRUE, FALSE, N_("open file in new window") },
+ { NULL, "--list-clear", gr_list_clear, FALSE, FALSE, NULL },
+ { NULL, "--list-add:", gr_list_add, TRUE, FALSE, NULL },
+ { NULL, "raise", gr_raise, FALSE, FALSE, NULL },
+ { NULL, NULL, NULL, FALSE, FALSE, NULL }
+};
+
+static RemoteCommandEntry *gqview_remote_command_find(const gchar *text, const gchar **offset)
+{
+ gint match = FALSE;
+ gint i;
+
+ i = 0;
+ while (!match && remote_commands[i].func != NULL)
+ {
+ if (remote_commands[i].needs_extra)
+ {
+ if (remote_commands[i].opt_s &&
+ strncmp(remote_commands[i].opt_s, text, strlen(remote_commands[i].opt_s)) == 0)
{
- exit_gqview();
- return FALSE;
+ if (offset) *offset = text + strlen(remote_commands[i].opt_s);
+ return &remote_commands[i];
}
- break;
+ else if (remote_commands[i].opt_l &&
+ strncmp(remote_commands[i].opt_l, text, strlen(remote_commands[i].opt_l)) == 0)
+ {
+ if (offset) *offset = text + strlen(remote_commands[i].opt_l);
+ return &remote_commands[i];
+ }
+ }
+ else
+ {
+ if ((remote_commands[i].opt_s && strcmp(remote_commands[i].opt_s, text) == 0) ||
+ (remote_commands[i].opt_l && strcmp(remote_commands[i].opt_l, text) == 0))
+ {
+ if (offset) *offset = text;
+ return &remote_commands[i];
+ }
+ }
+
+ i++;
+ }
+
+ return NULL;
+}
+
+static void gqview_remote_cb(RemoteConnection *rc, const gchar *text, gpointer data)
+{
+ RemoteCommandEntry *entry;
+ const gchar *offset;
+
+ entry = gqview_remote_command_find(text, &offset);
+ if (entry && entry->func)
+ {
+ entry->func(offset, data);
+ }
+ else
+ {
+ printf("unknown remote command:%s\n", text);
+ }
+}
+
+static void gqview_remote_help(void)
+{
+ gint i;
+
+ print_term(_("Remote command list:\n"));
+
+ i = 0;
+ while (remote_commands[i].func != NULL)
+ {
+ if (remote_commands[i].description)
+ {
+ gchar *buf;
+
+ buf = g_strdup_printf(" %-3s%s %-20s %s\n",
+ (remote_commands[i].opt_s) ? remote_commands[i].opt_s : "",
+ (remote_commands[i].opt_s && remote_commands[i].opt_l) ? "," : " ",
+ (remote_commands[i].opt_l) ? remote_commands[i].opt_l : "",
+ _(remote_commands[i].description));
+
+ print_term(buf);
+ g_free(buf);
+ }
+ i++;
}
+}
+
+static GList *gqview_remote_build_list(GList *list, int argc, char *argv[])
+{
+ gint i;
- if (event->state & GDK_SHIFT_MASK)
+ i = 1;
+ while (i < argc)
{
- x *= 3;
- y *= 3;
+ RemoteCommandEntry *entry;
+
+ entry = gqview_remote_command_find(argv[i], NULL);
+ if (entry)
+ {
+ list = g_list_append(list, argv[i]);
+ }
+ i++;
}
- if (x != 0 || y!= 0)
+ return list;
+}
+
+static void gqview_remote_control(const gchar *arg_exec, GList *remote_list, const gchar *path,
+ GList *cmd_list, GList *collection_list)
+{
+ RemoteConnection *rc;
+ gint started = FALSE;
+ gchar *buf;
+
+ buf = g_strconcat(homedir(), "/", GQVIEW_RC_DIR, "/.command", NULL);
+ rc = remote_client_open(buf);
+ if (!rc)
{
- keyboard_scroll_calc(&x, &y, event);
- image_scroll(x, y);
+ GString *command;
+ GList *work;
+ gint retry_count = 12;
+ gint blank = FALSE;
+
+ print_term(_("Remote GQview not running, starting..."));
+ command = g_string_new(arg_exec);
+
+ work = remote_list;
+ while (work)
+ {
+ gchar *text;
+ RemoteCommandEntry *entry;
+
+ text = work->data;
+ work = work->next;
+
+ entry = gqview_remote_command_find(text, NULL);
+ if (entry)
+ {
+ if (entry->prefer_command_line)
+ {
+ remote_list = g_list_remove(remote_list, text);
+ g_string_append(command, " ");
+ g_string_append(command, text);
+ }
+ if (entry->opt_l && strcmp(entry->opt_l, "file:") == 0)
+ {
+ blank = TRUE;
+ }
+ }
+ }
+
+ if (blank || cmd_list || path) g_string_append(command, " --blank");
+ if (debug) g_string_append(command, " --debug");
+
+ g_string_append(command, " &");
+ system(command->str);
+ g_string_free(command, TRUE);
+
+ while (!rc && retry_count > 0)
+ {
+ usleep((retry_count > 10) ? 500000 : 1000000);
+ rc = remote_client_open(buf);
+ if (!rc) print_term(".");
+ retry_count--;
+ }
+
+ print_term("\n");
+
+ started = TRUE;
}
+ g_free(buf);
+
+ if (rc)
+ {
+ GList *work;
+ const gchar *prefix;
+ gint use_path = TRUE;
+ gint sent = FALSE;
+
+ work = remote_list;
+ while (work)
+ {
+ gchar *text;
+ RemoteCommandEntry *entry;
+
+ text = work->data;
+ work = work->next;
+
+ entry = gqview_remote_command_find(text, NULL);
+ if (entry &&
+ entry->opt_l &&
+ strcmp(entry->opt_l, "file:") == 0) use_path = FALSE;
+
+ remote_client_send(rc, text);
+
+ sent = TRUE;
+ }
+
+ if (cmd_list && cmd_list->next)
+ {
+ prefix = "--list-add:";
+ remote_client_send(rc, "--list-clear");
+ }
+ else
+ {
+ prefix = "file:";
+ }
+
+ work = cmd_list;
+ while (work)
+ {
+ const gchar *name;
+ gchar *text;
+
+ name = work->data;
+ work = work->next;
+
+ text = g_strconcat(prefix, name, NULL);
+ remote_client_send(rc, text);
+ g_free(text);
+
+ sent = TRUE;
+ }
+
+ if (path && !cmd_list && use_path)
+ {
+ gchar *text;
+
+ text = g_strdup_printf("file:%s", path);
+ remote_client_send(rc, text);
+ g_free(text);
+
+ sent = TRUE;
+ }
+
+ work = collection_list;
+ while (work)
+ {
+ const gchar *name;
+ gchar *text;
+
+ name = work->data;
+ work = work->next;
+
+ text = g_strdup_printf("file:%s", name);
+ remote_client_send(rc, text);
+ g_free(text);
+
+ sent = TRUE;
+ }
- if (stop_signal) gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "key_press_event");
+ if (!started && !sent)
+ {
+ remote_client_send(rc, "raise");
+ }
+ }
+ else
+ {
+ print_term(_("Remote not available\n"));
+ }
- return stop_signal;
+ _exit(0);
}
/*
*-----------------------------------------------------------------------------
*/
+static gint startup_blank = FALSE;
static gint startup_full_screen = FALSE;
static gint startup_in_slideshow = FALSE;
+static gint startup_command_line_collection = FALSE;
+
-static void parse_command_line(int argc, char *argv[], gchar **path, gchar **file)
+static void parse_command_line_add_file(const gchar *new_path, gchar **path, gchar **file,
+ GList **list, GList **collection_list)
{
+ gchar *path_parsed;
+
+ path_parsed = g_strdup(new_path);
+ parse_out_relatives(path_parsed);
+
+ if (file_extension_match(new_path, ".gqv"))
+ {
+ *collection_list = g_list_append(*collection_list, path_parsed);
+ }
+ else
+ {
+ if (!*path) *path = remove_level_from_path(path_parsed);
+ if (!*file) *file = g_strdup(path_parsed);
+ *list = g_list_append(*list, path_parsed);
+ }
+}
+
+static void parse_command_line(int argc, char *argv[], gchar **path, gchar **file,
+ GList **cmd_list, GList **collection_list)
+{
+ GList *list = NULL;
+ GList *remote_list = NULL;
+ gint remote_do = FALSE;
+
if (argc > 1)
{
gint i;
i = 1;
while (i < argc)
{
- gchar *cmd_line = argv[i];
- gchar *cmd_all = g_strconcat(base_dir, "/", cmd_line, NULL);
+ const gchar *cmd_line = argv[i];
+ gchar *cmd_all = concat_dir_and_file(base_dir, cmd_line);
if (!*path && cmd_line[0] == '/' && isdir(cmd_line))
{
{
*path = g_strdup(cmd_all);
}
- else if (!*file && cmd_line[0] == '/' && isfile(cmd_line))
+ else if (cmd_line[0] == '/' && isfile(cmd_line))
{
- g_free(*path);
- *path = remove_level_from_path(cmd_line);
- *file = g_strdup(cmd_line);
+ parse_command_line_add_file(cmd_line, path, file, &list, collection_list);
}
- else if (!*file && isfile(cmd_all))
+ else if (isfile(cmd_all))
{
- g_free(*path);
- *path = remove_level_from_path(cmd_all);
- *file = g_strdup(cmd_all);
+ parse_command_line_add_file(cmd_all, path, file, &list, collection_list);
}
else if (strcmp(cmd_line, "--debug") == 0)
{
- debug = TRUE;
- printf("debugging output enabled\n");
+ /* we now increment the debug state for verbosity */
+ debug++;
+ printf("debugging output enabled (level %d)\n", debug);
}
else if (strcmp(cmd_line, "+t") == 0 ||
strcmp(cmd_line, "--with-tools") == 0)
{
tools_float = FALSE;
tools_hidden = FALSE;
+
+ remote_list = g_list_append(remote_list, "+t");
}
else if (strcmp(cmd_line, "-t") == 0 ||
strcmp(cmd_line, "--without-tools") == 0)
{
tools_hidden = TRUE;
+
+ remote_list = g_list_append(remote_list, "-t");
}
else if (strcmp(cmd_line, "-f") == 0 ||
strcmp(cmd_line, "--fullscreen") == 0)
{
startup_in_slideshow = TRUE;
}
+ else if (strcmp(cmd_line, "-l") == 0 ||
+ strcmp(cmd_line, "--list") == 0)
+ {
+ startup_command_line_collection = TRUE;
+ }
+ else if (strcmp(cmd_line, "-r") == 0 ||
+ strcmp(cmd_line, "--remote") == 0)
+ {
+ if (!remote_do)
+ {
+ remote_do = TRUE;
+ remote_list = gqview_remote_build_list(remote_list, argc, argv);
+ }
+ }
+ else if (strcmp(cmd_line, "-rh") == 0 ||
+ strcmp(cmd_line, "--remote-help") == 0)
+ {
+ gqview_remote_help();
+ exit (0);
+ }
+ else if (strcmp(cmd_line, "--blank") == 0)
+ {
+ startup_blank = TRUE;
+ }
+ else if (strcmp(cmd_line, "-v") == 0 ||
+ strcmp(cmd_line, "--version") == 0)
+ {
+ printf("GQview %s\n", VERSION);
+ exit (0);
+ }
+ else if (strcmp(cmd_line, "--alternate") == 0)
+ {
+ /* enable faster experimental algorithm */
+ printf("Alternate similarity algorithm enabled\n");
+ image_sim_alternate_set(TRUE);
+ }
else if (strcmp(cmd_line, "-h") == 0 ||
strcmp(cmd_line, "--help") == 0)
{
- printf("GQview version %s\n", VERSION);
- printf(_("Usage: gqview [options] [path]\n\n"));
- printf(_("valid options are:\n"));
- printf(_(" +t, --with-tools force show of tools\n"));
- printf(_(" -t, --without-tools force hide of tools\n"));
- printf(_(" -f, --fullscreen start in full screen mode\n"));
- printf(_(" -s, --slideshow start in slideshow mode\n"));
- printf(_(" --debug turn on debug output\n"));
- printf(_(" -h, --help show this message\n\n"));
+ printf("GQview %s\n", VERSION);
+ print_term(_("Usage: gqview [options] [path]\n\n"));
+ print_term(_("valid options are:\n"));
+ print_term(_(" +t, --with-tools force show of tools\n"));
+ print_term(_(" -t, --without-tools force hide of tools\n"));
+ print_term(_(" -f, --fullscreen start in full screen mode\n"));
+ print_term(_(" -s, --slideshow start in slideshow mode\n"));
+ print_term(_(" -l, --list open collection window for command line\n"));
+ print_term(_(" -r, --remote send following commands to open window\n"));
+ print_term(_(" -rh,--remote-help print remote command list\n"));
+ print_term(_(" --debug turn on debug output\n"));
+ print_term(_(" -v, --version print version info\n"));
+ print_term(_(" -h, --help show this message\n\n"));
+
+#if 0
+ /* these options are not officially supported!
+ * only for testing new features, no need to translate them */
+ print_term( " --alternate use alternate similarity algorithm\n");
+#endif
+
exit (0);
}
- else
+ else if (!remote_do)
{
- printf(_("invalid or ignored: %s\nUse -help for options\n"), cmd_line);
+ gchar *buf;
+
+ buf = g_strdup_printf(_("invalid or ignored: %s\nUse --help for options\n"), cmd_line);
+ print_term(buf);
+ g_free(buf);
}
+
g_free(cmd_all);
i++;
}
parse_out_relatives(*path);
parse_out_relatives(*file);
}
+
+ if (remote_do)
+ {
+ gqview_remote_control(argv[0], remote_list, *path, list, *collection_list);
+ }
+ g_list_free(remote_list);
+
+ if (list && list->next)
+ {
+ *cmd_list = list;
+ }
+ else
+ {
+ path_list_free(list);
+ *cmd_list = NULL;
+ }
}
/*
*-----------------------------------------------------------------------------
*/
-static void setup_default_options()
+#define RC_HISTORY_NAME "history"
+
+static void keys_load(void)
{
+ gchar *path;
+
+ path = g_strconcat(homedir(), "/", GQVIEW_RC_DIR, "/", RC_HISTORY_NAME, NULL);
+ history_list_load(path);
+ g_free(path);
+}
+
+static void keys_save(void)
+{
+ gchar *path;
+
+ path = g_strconcat(homedir(), "/", GQVIEW_RC_DIR, "/", RC_HISTORY_NAME, NULL);
+ history_list_save(path);
+ g_free(path);
+}
+
+static void check_for_home_path(gchar *path)
+{
+ gchar *buf;
+
+ buf = g_strconcat(homedir(), "/", path, NULL);
+ if (!isdir(buf))
+ {
+ gchar *tmp;
+
+ tmp = g_strdup_printf(_("Creating GQview dir:%s\n"), buf);
+ print_term(tmp);
+ g_free(tmp);
+
+ if (!mkdir_utf8(buf, 0755))
+ {
+ tmp = g_strdup_printf(_("Could not create dir:%s\n"), buf);
+ print_term(tmp);
+ g_free(tmp);
+ }
+ }
+ g_free(buf);
+}
+
+static void setup_default_options(void)
+{
+ gchar *path;
gint i;
- for(i=0; i<8; i++)
+ for (i = 0; i < GQVIEW_EDITOR_SLOTS; i++)
{
editor_name[i] = NULL;
editor_command[i] = NULL;
}
- editor_name[0] = g_strdup(_("The Gimp"));
- editor_command[0] = g_strdup("gimp");
-
- editor_name[1] = g_strdup(_("Electric Eyes"));
- editor_command[1] = g_strdup("ee");
+ editor_reset_defaults();
- editor_name[2] = g_strdup(_("XV"));
- editor_command[2] = g_strdup("xv");
+ bookmark_add_default(_("Home"), homedir());
+ path = concat_dir_and_file(homedir(), "Desktop");
+ bookmark_add_default(_("Desktop"), path);
+ g_free(path);
+ path = concat_dir_and_file(homedir(), GQVIEW_RC_DIR_COLLECTIONS);
+ bookmark_add_default(_("Collections"), path);
+ g_free(path);
- editor_name[3] = g_strdup(_("Xpaint"));
- editor_command[3] = g_strdup("xpaint");
-
- custom_filter = g_strdup(".eim;");
+ g_free(safe_delete_path);
+ safe_delete_path = concat_dir_and_file(homedir(), GQVIEW_RC_DIR_TRASH);
}
-void exit_gqview()
+static void exit_gqview_final(void)
{
- full_screen_stop();
+ gchar *path;
+ gchar *pathl;
+ LayoutWindow *lw = NULL;
+
+ remote_close(gqview_remote);
- gdk_window_get_position (mainwindow->window, &main_window_x, &main_window_y);
- gdk_window_get_size(mainwindow->window, &main_window_w, &main_window_h);
+ collect_manager_flush();
- if (toolwindow)
+ if (layout_valid(&lw))
{
- gdk_window_get_position (toolwindow->window, &float_window_x, &float_window_y);
- gdk_window_get_size(toolwindow->window, &float_window_w, &float_window_h);
+ main_window_maximized = window_maximized(lw->window);
+ if (!main_window_maximized)
+ {
+ layout_geometry_get(NULL, &main_window_x, &main_window_y,
+ &main_window_w, &main_window_h);
+ }
}
+
+ layout_geometry_get_dividers(NULL, &window_hdivider_pos, &window_vdivider_pos);
+
+ layout_views_get(NULL, &layout_view_tree, &layout_view_icons);
+
+ thumbnails_enabled = layout_thumb_get(NULL);
+ layout_sort_get(NULL, &file_sort_method, &file_sort_ascending);
+
+ layout_geometry_get_tools(NULL, &float_window_x, &float_window_y,
+ &float_window_w, &float_window_h, &float_window_divider);
+ layout_tools_float_get(NULL, &tools_float, &tools_hidden);
+ toolbar_hidden = layout_toolbar_hidden(NULL);
+
save_options();
+ keys_save();
+
+ path = g_strconcat(homedir(), "/", GQVIEW_RC_DIR, "/accels", NULL);
+ pathl = path_from_utf8(path);
+ gtk_accel_map_save(pathl);
+ g_free(pathl);
+ g_free(path);
gtk_main_quit();
}
+static GenericDialog *exit_dialog = NULL;
+
+static void exit_confirm_cancel_cb(GenericDialog *gd, gpointer data)
+{
+ exit_dialog = NULL;
+ generic_dialog_close(gd);
+}
+
+static void exit_confirm_exit_cb(GenericDialog *gd, gpointer data)
+{
+ exit_dialog = NULL;
+ generic_dialog_close(gd);
+ exit_gqview_final();
+}
+
+static gint exit_confirm_dlg(void)
+{
+ GtkWidget *parent;
+ LayoutWindow *lw;
+
+ if (exit_dialog)
+ {
+ gtk_window_present(GTK_WINDOW(exit_dialog->dialog));
+ return TRUE;
+ }
+
+ if (!collection_window_modified_exists()) return FALSE;
+
+ parent = NULL;
+ lw = NULL;
+ if (layout_valid(&lw))
+ {
+ parent = lw->window;
+ }
+
+ exit_dialog = generic_dialog_new(_("GQview - exit"),
+ "GQview", "exit", parent, FALSE,
+ exit_confirm_cancel_cb, NULL);
+ generic_dialog_add_message(exit_dialog, GTK_STOCK_DIALOG_QUESTION,
+ _("Quit GQview"), _("Collections have been modified. Quit anyway?"));
+ generic_dialog_add_button(exit_dialog, GTK_STOCK_QUIT, NULL, exit_confirm_exit_cb, TRUE);
+
+ gtk_widget_show(exit_dialog->dialog);
+
+ return TRUE;
+}
+
+void exit_gqview(void)
+{
+ layout_image_full_screen_stop(NULL);
+
+ if (exit_confirm_dlg()) return;
+
+ exit_gqview_final();
+}
+
int main (int argc, char *argv[])
{
+ LayoutWindow *lw;
+ gchar *path = NULL;
gchar *cmd_path = NULL;
gchar *cmd_file = NULL;
+ GList *cmd_list = NULL;
+ GList *collection_list = NULL;
+ CollectionData *first_collection = NULL;
+ gchar *buf;
+ gchar *bufl;
/* setup locale, i18n */
gtk_set_locale();
bindtextdomain (PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (PACKAGE, "UTF-8");
textdomain (PACKAGE);
/* setup random seed for random slideshow */
- srand (time (0));
+ srand(time(NULL));
- gtk_init (&argc, &argv);
- gdk_imlib_init();
-
- /* push the correct color depths to gtk, (for 8-bit psuedo color displays)
- * they should be popped, too, I guess...
- */
- gtk_widget_push_visual(gdk_imlib_get_visual());
- gtk_widget_push_colormap(gdk_imlib_get_colormap());
+#if 0
+ printf("GQview %s, This is a beta release.\n", VERSION);
+#endif
+ layout_order = g_strdup("123");
setup_default_options();
load_options();
- parse_command_line(argc, argv, &cmd_path, &cmd_file);
+ parse_command_line(argc, argv, &cmd_path, &cmd_file, &cmd_list, &collection_list);
+
+ gtk_init (&argc, &argv);
+
+ if (gtk_major_version < GTK_MAJOR_VERSION ||
+ (gtk_major_version == GTK_MAJOR_VERSION && gtk_minor_version < GTK_MINOR_VERSION) )
+ {
+ gchar *msg;
+ print_term("!!! This is a friendly warning.\n");
+ print_term("!!! The version of GTK+ in use now is older than when GQview was compiled.\n");
+ msg = g_strdup_printf("!!! compiled with GTK+-%d.%d\n", GTK_MAJOR_VERSION, GTK_MINOR_VERSION);
+ print_term(msg);
+ g_free(msg);
+ msg = g_strdup_printf("!!! running with GTK+-%d.%d\n", gtk_major_version, gtk_minor_version);
+ print_term(msg);
+ g_free(msg);
+ print_term("!!! GQview may quit unexpectedly with a relocation error.\n");
+ }
+
+ check_for_home_path(GQVIEW_RC_DIR);
+ check_for_home_path(GQVIEW_RC_DIR_COLLECTIONS);
+ check_for_home_path(GQVIEW_CACHE_RC_THUMB);
+ check_for_home_path(GQVIEW_CACHE_RC_METADATA);
- if (cmd_path)
- current_path = g_strdup(cmd_path);
+ keys_load();
+ filter_add_defaults();
+ filter_rebuild();
+
+ buf = g_strconcat(homedir(), "/", GQVIEW_RC_DIR, "/accels", NULL);
+ bufl = path_from_utf8(buf);
+ gtk_accel_map_load(bufl);
+ g_free(bufl);
+ g_free(buf);
+
+ if (startup_blank)
+ {
+ g_free(cmd_path);
+ cmd_path = NULL;
+ g_free(cmd_file);
+ cmd_file = NULL;
+ path_list_free(cmd_list);
+ cmd_list = NULL;
+ path_list_free(collection_list);
+ collection_list = NULL;
+
+ path = NULL;
+ }
+ else if (cmd_path)
+ {
+ path = g_strdup(cmd_path);
+ }
else if (startup_path_enable && startup_path && isdir(startup_path))
- current_path = g_strdup(startup_path);
+ {
+ path = g_strdup(startup_path);
+ }
else
- current_path = get_current_dir();
+ {
+ path = get_current_dir();
+ }
+
+ lw = layout_new(NULL, tools_float, tools_hidden);
+ layout_sort_set(lw, file_sort_method, file_sort_ascending);
+
+ if (collection_list && !startup_command_line_collection)
+ {
+ GList *work;
- create_main_window();
- update_edit_menus(mainwindow_accel_grp);
- rebuild_file_filter();
- filelist_refresh();
+ work = collection_list;
+ while (work)
+ {
+ CollectWindow *cw;
+ const gchar *path;
+
+ path = work->data;
+ work = work->next;
- init_dnd();
+ cw = collection_window_new(path);
+ if (!first_collection && cw) first_collection = cw->cd;
+ }
+ }
- while(gtk_events_pending()) gtk_main_iteration();
- image_change_to(cmd_file);
+ if (cmd_list ||
+ (startup_command_line_collection && collection_list))
+ {
+ CollectionData *cd;
+ GList *work;
+
+ if (startup_command_line_collection)
+ {
+ CollectWindow *cw;
+
+ cw = collection_window_new("");
+ cd = cw->cd;
+ }
+ else
+ {
+ cd = collection_new(""); /* if we pass NULL, untitled counter is falsely increm. */
+ gqview_command_collection = cd;
+ }
+
+ g_free(cd->path);
+ cd->path = NULL;
+ g_free(cd->name);
+ cd->name = g_strdup(_("Command line"));
+
+ collection_path_changed(cd);
+
+ work = cmd_list;
+ while (work)
+ {
+ collection_add(cd, (gchar *)work->data, FALSE);
+ work = work->next;
+ }
+
+ work = collection_list;
+ while (work)
+ {
+ collection_load(cd, (gchar *)work->data, TRUE);
+ work = work->next;
+ }
+
+ layout_set_path(lw, path);
+ if (cd->list) layout_image_set_collection(lw, cd, cd->list->data);
+
+ /* mem leak, we never unref this collection when !startup_command_line_collection
+ * (the image view of the main window does not hold a ref to the collection)
+ * this is sort of unavoidable, for if it did hold a ref, next/back
+ * may not work as expected when closing collection windows.
+ *
+ * collection_unref(cd);
+ */
+
+ }
+ else if (cmd_file)
+ {
+ layout_set_path(lw, cmd_file);
+ }
+ else
+ {
+ layout_set_path(lw, path);
+ if (first_collection)
+ {
+ layout_image_set_collection(lw, first_collection,
+ collection_get_first(first_collection));
+ }
+ }
g_free(cmd_path);
g_free(cmd_file);
+ path_list_free(cmd_list);
+ path_list_free(collection_list);
+ g_free(path);
- if (startup_full_screen) full_screen_toggle();
- if (startup_in_slideshow) slideshow_start();
+ if (startup_full_screen) layout_image_full_screen_start(lw);
+ if (startup_in_slideshow) layout_image_slideshow_start(lw);
+
+ buf = g_strconcat(homedir(), "/", GQVIEW_RC_DIR, "/.command", NULL);
+ gqview_remote = remote_server_open(buf);
+ remote_server_subscribe(gqview_remote, gqview_remote_cb, NULL);
+ g_free(buf);
gtk_main ();
return 0;
}
-