summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann <sandmann@redhat.com>2008-03-12 22:50:24 -0400
committerSøren Sandmann <sandmann@redhat.com>2008-03-12 22:50:24 -0400
commit0a687e620e1e7e07dec1e726b89fd2216274a956 (patch)
treee59da6bc9efcfcc1088aadb0fffd04e39a6eae5a
parentef80f835a6229e5b6701a10e9474f38d5fac6311 (diff)
Add open dialog
-rw-r--r--TODO4
-rw-r--r--siv.c20
-rw-r--r--siv.h7
-rw-r--r--window.c256
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 <math.h>
#include <gtk/gtk.h>
+#include <string.h>
#include "siv.h"
+
#define MIN_ZOOM -80
#define MAX_ZOOM 65
@@ -299,52 +301,71 @@ rebuild (Window *window)
}
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)
{
Window *window = 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);
}