From 0a687e620e1e7e07dec1e726b89fd2216274a956 Mon Sep 17 00:00:00 2001 From: Søren Sandmann Date: Wed, 12 Mar 2008 22:50:24 -0400 Subject: Add open dialog --- TODO | 4 +- siv.c | 20 ++--- siv.h | 7 +- window.c | 256 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 253 insertions(+), 34 deletions(-) diff --git a/TODO b/TODO index 8b52637..7966b4c 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,6 @@ - Make sure filenames are escaped if they contains [ or ] -- Open +- Set mimetypes in open dialog - Dragging @@ -14,3 +14,5 @@ Done: - Meta data - Save adjustment positions + +- Open diff --git a/siv.c b/siv.c index b899845..a523743 100644 --- a/siv.c +++ b/siv.c @@ -15,10 +15,10 @@ struct App GHashTable *meta_data; }; -static void -warning (GtkWidget *parent_window, - const gchar *format, - ...) +void +app_show_warning (GtkWidget *parent_window, + const gchar *format, + ...) { va_list args; char *message; @@ -292,7 +292,7 @@ app_new (int argc, char **argv) } else { - window_show (window); + window_show (window, GDK_CURRENT_TIME); } } @@ -303,7 +303,7 @@ app_new (int argc, char **argv) } else { - window_show (window_new (app)); + window_show (window_new (app), GDK_CURRENT_TIME); } if (app->n_windows == 1) @@ -334,10 +334,10 @@ main (int argc, if (!g_file_test (GLADE_FILE, G_FILE_TEST_EXISTS)) { - warning (NULL, - APPLICATION_NAME " was not compiled or installed correctly.\n" - "\n" - "Running \"make install\" may solve this problem.\n"); + app_show_warning (NULL, + APPLICATION_NAME " was not compiled or installed correctly.\n" + "\n" + "Running \"make install\" may solve this problem.\n"); return FALSE; } diff --git a/siv.h b/siv.h index e311257..a5afac9 100644 --- a/siv.h +++ b/siv.h @@ -53,13 +53,18 @@ void app_set_meta_data (App *data, int vadj, int hadj); +/* Doesn't really belong in the app namespace */ +void app_show_warning (GtkWidget *parent_window, + const gchar *format, + ...); /* Window */ Window * window_new (App *app); gboolean window_load_file (Window *window, const char *file, GError **err); -void window_show (Window *window); +void window_show (Window *window, + guint32 time); void window_free (Window *window); #endif diff --git a/window.c b/window.c index b71820a..d0764a6 100644 --- a/window.c +++ b/window.c @@ -1,7 +1,9 @@ #include #include +#include #include "siv.h" + #define MIN_ZOOM -80 #define MAX_ZOOM 65 @@ -298,52 +300,71 @@ rebuild (Window *window) gtk_widget_queue_draw (get_widget (window, "drawing_area")); } +static void +zoom (Window *window, int delta) +{ + GtkWidget *z; + + if (delta == 0) + return; + + if (delta < 0) + z = get_widget (window, "zoom_out"); + else + z = get_widget (window, "zoom_in"); + + if (GTK_WIDGET_SENSITIVE (z)) + { + window->zoom_level += delta; + + rebuild (window); + } +} + static void on_zoom_in (GtkWidget *widget, Window *window) { - window->zoom_level += 5; - rebuild (window); + zoom (window, 5); }; static void on_zoom_out (GtkWidget *widget, Window *window) { - window->zoom_level -= 5; - rebuild (window); + zoom (window, -5); }; static void on_zoom_normal (GtkWidget *widget, Window *window) { - window->zoom_level = 0; - rebuild (window); + zoom (window, -window->zoom_level); }; -static void -on_various (GtkWidget *widget, Window *window) -{ - rebuild (window); -} - static gboolean on_scroll (GtkWidget *widget, GdkEventScroll *event, Window *window) { if (event->state & GDK_CONTROL_MASK) { if (event->direction == GDK_SCROLL_UP) - window->zoom_level += 1; + { + zoom (window, 1); + return TRUE; + } else if (event->direction == GDK_SCROLL_DOWN) - window->zoom_level -= 1; - else - return FALSE; - - rebuild (window); - return TRUE; + { + zoom (window, -1); + return TRUE; + } } return FALSE; } +static void +on_various (GtkWidget *widget, Window *window) +{ + rebuild (window); +} + static void on_size_allocate (GtkWidget *widget, GtkAllocation *allocation, gpointer data) { @@ -421,7 +442,106 @@ on_close (GtkWidget *widget, gpointer data) window_free (window); } - + +static void +set_busy (GtkWidget *widget, + gboolean busy) +{ + GdkCursor *cursor; + GdkWindow *window; + + if (busy) + cursor = gdk_cursor_new (GDK_WATCH); + else + cursor = NULL; + + if (GTK_IS_TEXT_VIEW (widget)) + window = gtk_text_view_get_window (GTK_TEXT_VIEW (widget), GTK_TEXT_WINDOW_TEXT); + else + window = widget->window; + + gdk_window_set_cursor (window, cursor); + + if (cursor) + gdk_cursor_unref (cursor); + + gdk_display_flush (gdk_display_get_default ()); +} + +static void +show_could_not_open (Window *window, + const char *filename, + GError *err) +{ + app_show_warning (get_widget (window, "main_window"), + "Could not open %s: %s", + filename, + err->message); +} + +static void +on_open (GtkWidget *widget, gpointer data) +{ + Window *window = data; + gchar *filename = NULL; + GtkWidget *dialog; + + set_busy (get_widget (window, "main_window"), TRUE); + + dialog = gtk_file_chooser_dialog_new ("Open", + get_widget (window, "main_window"), + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + + set_busy (get_widget (window, "main_window"), FALSE); + +retry: + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + { + GError *err = NULL; + Window *target; + gboolean success; + + if (window->original) + target = window_new (window->app); + else + target = window; + + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); + + set_busy (dialog, TRUE); + + success = window_load_file (target, filename, &err); + + if (success) + { + if (target != window) + window_show (target, gtk_get_current_event_time()); + } + else + { + show_could_not_open (window, filename, err); + + g_error_free (err); + + if (window != target) + window_free (target); + } + + set_busy (dialog, FALSE); + g_free (filename); + + if (!success) + goto retry; + } + + gtk_widget_destroy (dialog); +} + static void connect_signals (Window *window) { @@ -454,6 +574,7 @@ connect_signals (Window *window) { "drawing_area", "expose_event", G_CALLBACK (on_expose) }, { "drawing_area", "scroll_event", G_CALLBACK (on_scroll) }, { "drawing_area", "size_allocate", G_CALLBACK (on_size_allocate) }, + { "menu_open", "activate", G_CALLBACK (on_open) }, }; for (i = 0; i < G_N_ELEMENTS (connections); ++i) @@ -497,12 +618,99 @@ set_defaults (Window *window) gtk_check_menu_item_set_active (get_widget (window, "menu_no"), TRUE); } +/* Cut and paste from GLib */ +static char * +canonicalize_filename (const char *filename) +{ + char *canon, *start, *p, *q; + char *cwd; + int i; + + if (!g_path_is_absolute (filename)) + { + cwd = g_get_current_dir (); + canon = g_build_filename (cwd, filename, NULL); + g_free (cwd); + } + else + canon = g_strdup (filename); + + start = (char *)g_path_skip_root (canon); + + /* POSIX allows double slashes at the start to + * mean something special (as does windows too). + * So, "//" != "/", but more than two slashes + * is treated as "/". + */ + i = 0; + for (p = start - 1; + (p >= canon) && + G_IS_DIR_SEPARATOR (*p); + p--) + i++; + if (i > 2) + { + i -= 1; + start -= i; + memmove (start, start+i, strlen (start+i)+1); + } + + p = start; + while (*p != 0) + { + if (p[0] == '.' && (p[1] == 0 || G_IS_DIR_SEPARATOR (p[1]))) + { + memmove (p, p+1, strlen (p+1)+1); + } + else if (p[0] == '.' && p[1] == '.' && (p[2] == 0 || G_IS_DIR_SEPARATOR (p[2]))) + { + q = p + 2; + /* Skip previous separator */ + + p = p - 2; + if (p < start) + p = start; + while (p > start && !G_IS_DIR_SEPARATOR (*p)) + p--; + if (G_IS_DIR_SEPARATOR (*p)) + *p++ = G_DIR_SEPARATOR; + memmove (p, q, strlen (q)+1); + } + else + { + /* Skip until next separator */ + while (*p != 0 && !G_IS_DIR_SEPARATOR (*p)) + p++; + + if (*p != 0) + { + /* Canonicalize one separator */ + *p++ = G_DIR_SEPARATOR; + } + } + + /* Remove additional separators */ + q = p; + while (*q && G_IS_DIR_SEPARATOR (*q)) + q++; + + if (p != q) + memmove (p, q, strlen (q)+1); + } + + /* Remove trailing slashes */ + if (p > start && G_IS_DIR_SEPARATOR (*(p-1))) + *(p-1) = 0; + + return canon; +} + gboolean window_load_file (Window *window, const char *filename, GError **err) { GdkPixbuf *pixbuf; - window->filename = g_strdup (filename); + window->filename = canonicalize_filename (filename); pixbuf = gdk_pixbuf_new_from_file (filename, err); @@ -521,6 +729,8 @@ window_load_file (Window *window, const char *filename, GError **err) if (data) { GtkCheckMenuItem *item; + + g_print ("moving to %d %d\n", data->window_x, data->window_y); gtk_window_move (get_widget (window, "main_window"), data->window_x, data->window_y); @@ -616,7 +826,7 @@ window_free (Window *window) } void -window_show (Window *window) +window_show (Window *window, guint32 time) { GtkAdjustment *vadj, *hadj; @@ -631,4 +841,6 @@ window_show (Window *window) gtk_adjustment_set_value (vadj, window->vadj); gtk_adjustment_set_value (hadj, window->hadj); + + gtk_window_present_with_time (get_widget (window, "main_window"), time); } -- cgit v1.2.3