summaryrefslogtreecommitdiff
path: root/window.c
diff options
context:
space:
mode:
Diffstat (limited to 'window.c')
-rw-r--r--window.c288
1 files changed, 207 insertions, 81 deletions
diff --git a/window.c b/window.c
index b8bf703..224927b 100644
--- a/window.c
+++ b/window.c
@@ -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;