diff options
Diffstat (limited to 'window.c')
-rw-r--r-- | window.c | 288 |
1 files changed, 207 insertions, 81 deletions
@@ -1,13 +1,14 @@ #include <math.h> #include <gtk/gtk.h> #include <string.h> +#include <gdk/gdkx.h> #include "siv.h" #define MIN_ZOOM -80 #define MAX_ZOOM 65 -struct Window +struct SivWindow { GladeXML * xml; char * filename; @@ -27,10 +28,14 @@ struct Window gboolean dragging; int drag_x; int drag_y; + double start_x; + double start_y; + + guint32 last_motion_time; }; static void * -get_widget (Window *window, const char *name) +get_widget (SivWindow *window, const char *name) { void *result = glade_xml_get_widget (window->xml, name); @@ -40,14 +45,26 @@ get_widget (Window *window, const char *name) return result; } +static GtkAdjustment * +get_hadj (SivWindow *window) +{ + return gtk_scrolled_window_get_hadjustment (get_widget (window, "scrolled_window")); +} + +static GtkAdjustment * +get_vadj (SivWindow *window) +{ + return gtk_scrolled_window_get_vadjustment (get_widget (window, "scrolled_window")); +} + static double -get_scale (Window *window) +get_scale (SivWindow *window) { return pow (1.05, window->zoom_level); } static void -compute_size (Window *window, int *w, int *h) +compute_size (SivWindow *window, int *w, int *h) { int d; double scale; @@ -65,7 +82,12 @@ static void initialize_bg (GtkWidget *drawing_area, GdkRegion *region) { GdkWindowObject *private = (GdkWindowObject *)drawing_area->window; - GdkGC *gc = gdk_gc_new (drawing_area->window); + GdkGC *gc; + + if (gdk_region_empty (region)) + return; + + gc = gdk_gc_new (drawing_area->window); gdk_gc_set_rgb_fg_color (gc, &(private->bg_color)); gdk_gc_set_clip_region (gc, region); @@ -76,7 +98,7 @@ initialize_bg (GtkWidget *drawing_area, GdkRegion *region) } static void -paint_rect (GtkWidget *drawing_area, GdkRectangle *area, Window *window) +paint_rect (GtkWidget *drawing_area, GdkRectangle *area, SivWindow *window) { GdkPixbuf *tmp; GdkInterpType interp; @@ -85,6 +107,8 @@ paint_rect (GtkWidget *drawing_area, GdkRectangle *area, Window *window) GdkRectangle image; guint32 color1, color2; GdkRegion *bg_reg, *image_reg; + GdkPixmap *pixmap; + GdkGC *gc; gdk_window_get_size (drawing_area->window, &window_width, &window_height); @@ -146,34 +170,55 @@ paint_rect (GtkWidget *drawing_area, GdkRectangle *area, Window *window) dest.x - image.x, dest.y - image.y, 16, color1, color2); - gdk_draw_pixbuf (drawing_area->window, NULL, - tmp, 0, 0, dest.x, dest.y, dest.width, dest.height, GDK_RGB_DITHER_NONE, 0, 0); - + pixmap = gdk_pixmap_new (drawing_area->window, dest.width, dest.height, -1); + + gdk_draw_pixbuf (pixmap, NULL, + tmp, 0, 0, 0, 0, dest.width, dest.height, GDK_RGB_DITHER_NONE, + 0, 0); + + gc = gdk_gc_new (drawing_area->window); + gdk_draw_drawable (drawing_area->window, gc, pixmap, + 0, 0, dest.x, dest.y, dest.width, dest.height); + g_object_unref (gc); + g_object_unref (pixmap); + g_object_unref (tmp); } static gboolean -on_expose (GtkWidget *drawing_area, GdkEventExpose *expose, Window *window) +on_expose (GtkWidget *drawing_area, GdkEventExpose *expose, SivWindow *window) { GdkRectangle *rects; - GdkGC *gc; int n_rects; int i; if (!GTK_WIDGET_DRAWABLE (get_widget (window, "drawing_area"))) - return; + return FALSE; if (!window->original) { initialize_bg (drawing_area, expose->region); - return; + return FALSE; } - gdk_region_get_rectangles (expose->region, &rects, &n_rects); +#if 0 + paint_rect (drawing_area, &(expose->area), window); +#endif + gdk_region_get_rectangles (expose->region, &rects, &n_rects); + +#if 0 + g_print ("expose\n"); +#endif for (i = 0; i < n_rects; ++i) + { +#if 0 + g_print (" %d %d %d %d\n", rects[i].x, rects[i].y, rects[i].width, rects[i].height); +#endif + paint_rect (drawing_area, &(rects[i]), window); - + } + g_free (rects); return TRUE; @@ -194,7 +239,7 @@ adjust_adjustment (GtkAdjustment *adj, int old_size, int new_size) } static void -set_sensitivity (Window *window) +set_sensitivity (SivWindow *window) { gboolean can_zoom_out = FALSE; gboolean can_zoom_in = FALSE; @@ -237,7 +282,7 @@ set_sensitivity (Window *window) } static void -set_title (Window *window) +set_title (SivWindow *window) { if (window->filename && window->original) { @@ -254,7 +299,7 @@ set_title (Window *window) } static void -save_meta_data (Window *window) +save_meta_data (SivWindow *window) { int x, y, width, height; @@ -262,7 +307,6 @@ save_meta_data (Window *window) { BackgroundType bg; gboolean smooth; - GtkAdjustment *hadj, *vadj; gtk_window_get_position (get_widget (window, "main_window"), &x, &y); gtk_window_get_size (get_widget (window, "main_window"), &width, &height); @@ -286,20 +330,18 @@ save_meta_data (Window *window) smooth = gtk_check_menu_item_get_active (get_widget (window, "menu_smooth_image")); - vadj = gtk_scrolled_window_get_vadjustment (get_widget (window, "scrolled_window")); - hadj = gtk_scrolled_window_get_hadjustment (get_widget (window, "scrolled_window")); - app_set_meta_data (window->app, window->filename, x, y, width, height, smooth, bg, window->zoom_level, - vadj->value, hadj->value); + get_vadj (window)->value, + get_hadj (window)->value); } } static void -rebuild (Window *window) +rebuild (SivWindow *window) { if (window->zoom_level < MIN_ZOOM) window->zoom_level = MIN_ZOOM; @@ -316,8 +358,8 @@ rebuild (Window *window) gtk_widget_hide (get_widget (window, "scrolled_window")); - hadj = gtk_scrolled_window_get_hadjustment (get_widget (window, "scrolled_window")); - vadj = gtk_scrolled_window_get_vadjustment (get_widget (window, "scrolled_window")); + hadj = get_hadj (window); + vadj = get_vadj (window); if (window->first) { @@ -350,7 +392,7 @@ rebuild (Window *window) } static void -zoom (Window *window, int delta) +zoom (SivWindow *window, int delta) { GtkWidget *z; @@ -371,25 +413,25 @@ zoom (Window *window, int delta) } static void -on_zoom_in (GtkWidget *widget, Window *window) +on_zoom_in (GtkWidget *widget, SivWindow *window) { zoom (window, 5); }; static void -on_zoom_out (GtkWidget *widget, Window *window) +on_zoom_out (GtkWidget *widget, SivWindow *window) { zoom (window, -5); }; static void -on_zoom_normal (GtkWidget *widget, Window *window) +on_zoom_normal (GtkWidget *widget, SivWindow *window) { zoom (window, -window->zoom_level); }; static gboolean -on_scroll (GtkWidget *widget, GdkEventScroll *event, Window *window) +on_scroll (GtkWidget *widget, GdkEventScroll *event, SivWindow *window) { if (event->state & GDK_CONTROL_MASK) { @@ -409,88 +451,170 @@ on_scroll (GtkWidget *widget, GdkEventScroll *event, Window *window) } static gboolean -on_mouse_press (GtkWidget *widget, GdkEventButton *button, Window *window) +on_mouse_press (GtkWidget *widget, GdkEventButton *button, SivWindow *window) { if (button->button == 1) { + GdkCursor *hand = gdk_cursor_new (GDK_FLEUR); + if (gdk_pointer_grab (widget->window, FALSE, - GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK, - NULL, NULL, + NULL, hand, button->time) == GDK_GRAB_SUCCESS) { - g_print ("You clicked\n"); window->dragging = TRUE; - window->drag_x = button->x; - window->drag_y = button->y; - } - else - { - g_print ("grab fail\n"); + window->drag_x = button->x_root; + window->drag_y = button->y_root; + window->start_x = get_hadj (window)->value; + window->start_y = get_vadj (window)->value; + + gdk_cursor_unref (hand); } } + + return TRUE; } static gboolean -on_mouse_release (GtkWidget *widget, GdkEventButton *button, Window *window) +on_mouse_release (GtkWidget *widget, GdkEventButton *button, SivWindow *window) { if (button->button == 1) { - g_print ("You released %d\n", button->time); gdk_pointer_ungrab (button->time); window->dragging = FALSE; } + + return TRUE; } -static void -change_adjustment (GtkAdjustment *adj, int dv) +typedef struct +{ + Window window; + guint32 last_motion_time; + gboolean stop_compressing; +} EventScannerData; + +static Bool +get_motion_time (Display *dpy, + XEvent *xevent, + XPointer arg) { - double new = adj->value + dv; + EventScannerData *esd = (EventScannerData *)arg; + + if (esd->stop_compressing) + return FALSE; - new = CLAMP (new, adj->lower, adj->upper - adj->page_size); + if (esd->window != xevent->xany.window) + { + esd->stop_compressing = TRUE; + return FALSE; + } - gtk_adjustment_set_value (adj, new); + if (xevent->type == MotionNotify) + { + esd->last_motion_time = xevent->xmotion.time; + return FALSE; + } + + if (xevent->type == EnterNotify || + xevent->type == LeaveNotify) + { + esd->last_motion_time = xevent->xcrossing.time; + return FALSE; + } + + return FALSE; } static void -on_mouse_motion (GtkWidget *widget, GdkEventMotion *motion, Window *window) +set_adjustment (GtkAdjustment *adj, int dv) { - if (window->dragging) + dv = CLAMP (dv, adj->lower, adj->upper - adj->page_size); + + gtk_adjustment_set_value (adj, dv); +} + +static gboolean +use_this_motion_notify (GdkWindow *window, + guint32 event_time, + guint32 *motion_notify_time) +{ + if (*motion_notify_time) { - GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment (get_widget (window, "scrolled_window")); - GtkAdjustment *hadj = gtk_scrolled_window_get_hadjustment (get_widget (window, "scrolled_window")); - int x, y; + if (event_time == *motion_notify_time) + { + *motion_notify_time = 0; -#if 0 - g_print ("motion: %d\n", motion->time); -#endif + return TRUE; + } + else + { + /* There are more motion events already queued up */ + + return FALSE; + } + } + else + { + Display *dpy = gdk_x11_get_default_xdisplay(); + EventScannerData esd = { GDK_WINDOW_XWINDOW (window), 0, FALSE }; + XEvent dummy; + + XCheckIfEvent (dpy, &dummy, get_motion_time, (XPointer)&esd); - if (motion->is_hint) + if (esd.last_motion_time == 0) { - gtk_widget_get_pointer (widget, &x, &y); + return TRUE; } else { - x = motion->x; - y = motion->y; + *motion_notify_time = esd.last_motion_time; + return FALSE; } + } +} + +static void +handle_motion (SivWindow *window, guint32 time, int x, int y) +{ + GtkWidget *widget = get_widget (window, "drawing_area"); + + if (!use_this_motion_notify (widget->window, time, &(window->last_motion_time))) + return; + + if (window->dragging) + { + GtkAdjustment *vadj = get_vadj (window); + GtkAdjustment *hadj = get_hadj (window); + int dx = window->drag_x - x; + int dy = window->drag_y - y; gdk_window_freeze_updates (widget->window); - - change_adjustment (hadj, window->drag_x - x); - change_adjustment (vadj, window->drag_y - y); + + set_adjustment (hadj, window->start_x + dx); + set_adjustment (vadj, window->start_y + dy); gdk_window_thaw_updates (widget->window); - - gdk_window_process_updates (widget->window, TRUE); } } static void -on_various (GtkWidget *widget, Window *window) +on_motion (GtkWidget *widget, GdkEventMotion *motion, SivWindow *window) +{ + handle_motion (window, motion->time, motion->x_root, motion->y_root); +} + +static void +on_crossing (GtkWidget *widget, GdkEventCrossing *crossing, SivWindow *window) +{ + handle_motion (window, crossing->time, crossing->x_root, crossing->y_root); +} + +static void +on_various (GtkWidget *widget, SivWindow *window) { rebuild (window); } @@ -498,7 +622,7 @@ on_various (GtkWidget *widget, Window *window) static void on_size_allocate (GtkWidget *widget, GtkAllocation *allocation, gpointer data) { - Window *window = data; + SivWindow *window = data; if (window->allocation.width == 0 || window->allocation.height == 0) { @@ -560,7 +684,7 @@ on_size_allocate (GtkWidget *widget, GtkAllocation *allocation, gpointer data) static void on_close_event (GtkWidget *widget, GdkEvent *event, gpointer data) { - Window *window = data; + SivWindow *window = data; window_free (window); } @@ -568,7 +692,7 @@ on_close_event (GtkWidget *widget, GdkEvent *event, gpointer data) static void on_close (GtkWidget *widget, gpointer data) { - Window *window = data; + SivWindow *window = data; window_free (window); } @@ -599,7 +723,7 @@ set_busy (GtkWidget *widget, } static void -show_could_not_open (Window *window, +show_could_not_open (SivWindow *window, const char *filename, GError *err) { @@ -612,7 +736,7 @@ show_could_not_open (Window *window, static void on_open (GtkWidget *widget, gpointer data) { - Window *window = data; + SivWindow *window = data; gchar *filename = NULL; GtkWidget *dialog; @@ -633,7 +757,7 @@ retry: if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { GError *err = NULL; - Window *target; + SivWindow *target; gboolean success; if (window->original) @@ -676,7 +800,7 @@ static void on_about (GtkWidget *widget, gpointer data) { #define OSLASH "\303\270" - Window *window = data; + SivWindow *window = data; gtk_show_about_dialog (get_widget (window, "main_window"), "program-name", APPLICATION_NAME, @@ -686,7 +810,7 @@ on_about (GtkWidget *widget, gpointer data) } static void -connect_signals (Window *window) +connect_signals (SivWindow *window) { int i; @@ -719,7 +843,9 @@ connect_signals (Window *window) { "drawing_area", "size_allocate", G_CALLBACK (on_size_allocate) }, { "drawing_area", "button_press_event", G_CALLBACK (on_mouse_press) }, { "drawing_area", "button_release_event", G_CALLBACK (on_mouse_release) }, - { "drawing_area", "motion_notify_event", G_CALLBACK (on_mouse_motion) }, + { "drawing_area", "motion_notify_event", G_CALLBACK (on_motion) }, + { "drawing_area", "leave_notify_event", G_CALLBACK (on_crossing) }, + { "drawing_area", "enter_notify_event", G_CALLBACK (on_crossing) }, { "menu_open", "activate", G_CALLBACK (on_open) }, { "menu_about", "activate", G_CALLBACK (on_about) }, }; @@ -736,7 +862,7 @@ connect_signals (Window *window) } static void -set_defaults (Window *window) +set_defaults (SivWindow *window) { GtkWidget *widget = get_widget (window, "main_window"); GdkScreen *screen = gtk_widget_get_screen (widget); @@ -853,7 +979,7 @@ canonicalize_filename (const char *filename) } gboolean -window_load_file (Window *window, const char *filename, GError **err) +window_load_file (SivWindow *window, const char *filename, GError **err) { GdkPixbuf *pixbuf; @@ -921,10 +1047,10 @@ window_load_file (Window *window, const char *filename, GError **err) } } -Window * +SivWindow * window_new (App *app) { - Window *window = g_new0 (Window, 1); + SivWindow *window = g_new0 (SivWindow, 1); window->xml = glade_xml_new (GLADE_FILE, NULL, NULL); window->app = app; @@ -955,7 +1081,7 @@ window_new (App *app) } void -window_free (Window *window) +window_free (SivWindow *window) { if (window->filename) save_meta_data (window); @@ -976,7 +1102,7 @@ window_free (Window *window) } void -window_show (Window *window, guint32 time) +window_show (SivWindow *window, guint32 time) { GtkAdjustment *vadj, *hadj; |