summaryrefslogtreecommitdiff
path: root/window.c
diff options
context:
space:
mode:
Diffstat (limited to 'window.c')
-rw-r--r--window.c256
1 files changed, 234 insertions, 22 deletions
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);
}