1 /* -*- Mode: C; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3 -*- */
2
3 /*
4 * GImageView
5 * Copyright (C) 2001 Takuro Ashie
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * $Id: gimv_scrolled.c,v 1.3 2004/09/21 08:44:32 makeinu Exp $
22 */
23
24 /*
25 * These codes are mostly taken from Another X image viewer.
26 *
27 * Another X image viewer Author:
28 * David Ramboz <dramboz@users.sourceforge.net>
29 */
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include "gtk2-compat.h"
36 #include "gimv_scrolled.h"
37
38 /* for auto-scroll and auto-expand at drag */
39 #define AUTO_SCROLL_TIMEOUT 100
40 #define AUTO_SCROLL_EDGE_WIDTH 20
41 #define AUTO_SCROLL_SCALE_RATE 32 /* times / pixel */
42 typedef gboolean (*desirable_fn) (GimvScrolled *scrolled, gint x, gint y);
43 typedef gboolean (*scroll_fn) (gpointer data);
44
45 #define bw(widget) GTK_CONTAINER(widget)->border_width
46
47 #ifdef USE_GTK2
48 # define WIDGET_DRAW(widget, area) gdk_window_invalidate_rect (widget->window, area, TRUE)
49 #else
50 # define WIDGET_DRAW(widget, area) (gtk_signal_emit_by_name (GTK_OBJECT(widget), "draw", area))
51 #endif
52
53 #define adjustment_check_value(value, adj) \
54 { \
55 if (value < adj->lower) \
56 value = adj->lower; \
57 if (value > adj->upper - adj->page_size) \
58 value = adj->upper - adj->page_size; \
59 }
60
61 enum {
62 ADJUST_ADJUSTMENTS,
63 LAST_SIGNAL
64 };
65
66 static void gimv_scrolled_class_init (GimvScrolledClass *klass);
67 static void gimv_scrolled_init (GimvScrolled *scrolled);
68 static void gimv_scrolled_set_scroll_adjustments (GtkWidget *widget,
69 GtkAdjustment *hadjustment,
70 GtkAdjustment *vadjustment);
71 static gint gimv_scrolled_button_press (GtkWidget *widget,
72 GdkEventButton *event);
73 static gint gimv_scrolled_button_release (GtkWidget *widget,
74 GdkEventButton *event);
75 static gint gimv_scrolled_motion_notify (GtkWidget *widget,
76 GdkEventMotion *event);
77 static gint gimv_scrolled_drag_motion (GtkWidget *widget,
78 GdkDragContext *context,
79 gint x,
80 gint y,
81 guint time);
82 static void gimv_scrolled_drag_leave (GtkWidget *dirtree,
83 GdkDragContext *context,
84 guint time);
85
86 static void hadjustment_value_changed (GtkAdjustment *hadjustment,
87 gpointer data);
88 static void vadjustment_value_changed (GtkAdjustment *vadjustment,
89 gpointer data);
90 static gboolean horizontal_timeout (gpointer data);
91 static gboolean vertical_timeout (gpointer data);
92 #ifndef USE_GTK2
93 static void check_exposures (GtkWidget *widget);
94 #endif /* USE_GTK2 */
95
96
97 static GtkWidgetClass *parent_class = NULL;
98 static guint gimv_scrolled_signals [LAST_SIGNAL] = {0};
99
100
101 GtkType
gimv_scrolled_get_type(void)102 gimv_scrolled_get_type (void)
103 {
104 static GtkType type = 0;
105
106 if (!type) {
107 static const GtkTypeInfo type_info = {
108 "GimvScrolled",
109 sizeof (GimvScrolled),
110 sizeof (GimvScrolledClass),
111 (GtkClassInitFunc) gimv_scrolled_class_init,
112 (GtkObjectInitFunc) gimv_scrolled_init,
113 /* reserved_1 */ NULL,
114 /* reserved_2 */ NULL,
115 (GtkClassInitFunc) NULL,
116 };
117
118 type = gtk_type_unique (GTK_TYPE_CONTAINER, &type_info);
119 }
120
121 return type;
122 }
123
124
125 static void
gimv_scrolled_class_init(GimvScrolledClass * klass)126 gimv_scrolled_class_init (GimvScrolledClass *klass)
127 {
128 GtkObjectClass *object_class;
129 GtkWidgetClass *widget_class;
130 GtkContainerClass *container_class;
131
132 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
133
134 object_class = (GtkObjectClass*) klass;
135 widget_class = (GtkWidgetClass*) klass;
136 container_class = (GtkContainerClass*) klass;
137
138 widget_class->set_scroll_adjustments_signal =
139 gtk_signal_new ("set_scroll_adjustments",
140 GTK_RUN_LAST,
141 GTK_CLASS_TYPE(object_class),
142 GTK_SIGNAL_OFFSET(GimvScrolledClass, set_scroll_adjustments),
143 gtk_marshal_NONE__POINTER_POINTER,
144 GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
145
146 gimv_scrolled_signals[ADJUST_ADJUSTMENTS] =
147 gtk_signal_new ("adjust_adjustments",
148 GTK_RUN_FIRST,
149 GTK_CLASS_TYPE(object_class),
150 GTK_SIGNAL_OFFSET(GimvScrolledClass, adjust_adjustments),
151 gtk_marshal_NONE__NONE,
152 GTK_TYPE_NONE, 0);
153
154 widget_class->button_press_event = gimv_scrolled_button_press;
155 widget_class->button_release_event = gimv_scrolled_button_release;
156 widget_class->motion_notify_event = gimv_scrolled_motion_notify;
157 widget_class->drag_motion = gimv_scrolled_drag_motion;
158 widget_class->drag_leave = gimv_scrolled_drag_leave;
159
160 klass->set_scroll_adjustments = gimv_scrolled_set_scroll_adjustments;
161 klass->adjust_adjustments = NULL;
162 }
163
164 static void
gimv_scrolled_init(GimvScrolled * scrolled)165 gimv_scrolled_init (GimvScrolled *scrolled)
166 {
167 scrolled->x_offset = 0;
168 scrolled->y_offset = 0;
169 scrolled->h_adjustment = NULL;
170 scrolled->v_adjustment = NULL;
171 scrolled->freeze_count = 0;
172 scrolled->copy_gc = NULL;
173
174 /* for auto scroll */
175 scrolled->autoscroll_flags = 0;
176 scrolled->scroll_edge_x = AUTO_SCROLL_EDGE_WIDTH;
177 scrolled->scroll_edge_y = AUTO_SCROLL_EDGE_WIDTH;
178 scrolled->x_step = -1;
179 scrolled->y_step = -1;
180 scrolled->x_interval = AUTO_SCROLL_TIMEOUT;
181 scrolled->y_interval = AUTO_SCROLL_TIMEOUT;
182 scrolled->pressed = FALSE;
183 scrolled->drag_start_vx = -1;
184 scrolled->drag_start_vy = -1;
185 scrolled->drag_motion_x = -1;
186 scrolled->drag_motion_y = -1;
187 scrolled->step_scale = 0.0;
188 scrolled->hscroll_timer_id = -1;
189 scrolled->vscroll_timer_id = -1;
190 }
191
192 void
gimv_scrolled_realize(GimvScrolled * scrolled)193 gimv_scrolled_realize (GimvScrolled *scrolled)
194 {
195 g_return_if_fail (scrolled && GTK_WIDGET(scrolled)->window);
196
197 scrolled->copy_gc = gdk_gc_new (GTK_WIDGET(scrolled)->window);
198 gdk_gc_set_exposures (scrolled->copy_gc, TRUE);
199 }
200
201 void
gimv_scrolled_unrealize(GimvScrolled * scrolled)202 gimv_scrolled_unrealize (GimvScrolled *scrolled)
203 {
204 g_return_if_fail (scrolled);
205
206 gdk_gc_destroy (scrolled->copy_gc);
207 }
208
209 static void
hadjustment_value_changed(GtkAdjustment * hadjustment,gpointer data)210 hadjustment_value_changed (GtkAdjustment *hadjustment,
211 gpointer data)
212 {
213 GimvScrolled *scrolled;
214 GtkWidget *widget;
215 GdkRectangle area;
216 int value, diff;
217
218 widget = GTK_WIDGET(data);
219 scrolled = GIMV_SCROLLED(data);
220
221 if (!GTK_WIDGET_DRAWABLE(widget) || scrolled->x_offset == hadjustment->value)
222 return;
223
224 value = hadjustment->value;
225
226 if (value < 0)
227 value = 0;
228
229 if (scrolled->freeze_count) {
230 scrolled->x_offset = value;
231 return;
232 }
233
234 if (value > scrolled->x_offset) {
235 diff = value - scrolled->x_offset;
236
237 if (diff >= widget->allocation.width) {
238 scrolled->x_offset = value;
239 WIDGET_DRAW(widget, NULL);
240 return;
241 }
242
243 if (diff > 0 && !scrolled->freeze_count)
244 gdk_window_copy_area (widget->window,
245 scrolled->copy_gc,
246 0, 0,
247 widget->window,
248 diff, 0,
249 widget->allocation.width - 2 * bw (widget) - diff,
250 widget->allocation.height - 2 * bw (widget));
251
252 area.x = widget->allocation.width - 2 * bw (widget) - diff;
253 area.y = 0;
254 area.width = diff;
255 area.height = widget->allocation.height - 2 * bw (widget);
256
257 } else {
258 diff = scrolled->x_offset - value;
259
260 if (diff >= widget->allocation.width) {
261 scrolled->x_offset = value;
262 WIDGET_DRAW(widget, NULL);
263 return;
264 }
265
266 if (diff > 0)
267 gdk_window_copy_area (widget->window,
268 scrolled->copy_gc,
269 diff, 0,
270 widget->window,
271 0, 0,
272 widget->allocation.width - 2 * bw (widget) - diff,
273 widget->allocation.height - 2 * bw (widget));
274
275 area.x = 0;
276 area.y = 0;
277 area.width = diff;
278 area.height = widget->allocation.height - 2 * bw (widget);
279 }
280
281
282 if (diff > 0) {
283 scrolled->x_offset = value;
284 #ifndef USE_GTK2
285 check_exposures (widget);
286 #endif /* USE_GTK2 */
287 /* WIDGET_DRAW(widget, &area); */
288 WIDGET_DRAW(widget, NULL);
289 }
290 }
291
292
293 static void
vadjustment_value_changed(GtkAdjustment * vadjustment,gpointer data)294 vadjustment_value_changed (GtkAdjustment *vadjustment,
295 gpointer data)
296 {
297 GimvScrolled *scrolled;
298 GtkWidget *widget;
299 GdkRectangle area;
300 int value, diff;
301
302 widget = GTK_WIDGET(data);
303 scrolled = GIMV_SCROLLED(data);
304
305 if (!GTK_WIDGET_DRAWABLE(widget) || scrolled->y_offset == vadjustment->value)
306 return;
307
308 value = vadjustment->value;
309
310 if (value < 0)
311 value = 0;
312
313 if (scrolled->freeze_count) {
314 scrolled->y_offset = value;
315 return;
316 }
317
318 if (value > scrolled->y_offset) {
319 diff = value - scrolled->y_offset;
320
321 if (diff >= widget->allocation.height) {
322 scrolled->y_offset = value;
323 WIDGET_DRAW(widget, NULL);
324 return;
325 }
326
327 if (diff > 0)
328 gdk_window_copy_area (widget->window,
329 scrolled->copy_gc,
330 0, 0,
331 widget->window,
332 0, diff,
333 widget->allocation.width - 2 * bw (widget),
334 widget->allocation.height - 2 * bw (widget) - diff);
335
336 area.x = 0;
337 area.y = widget->allocation.height - 2 * bw (widget) - diff;
338 area.width = widget->allocation.width - 2 * bw (widget);
339 area.height = diff;
340
341 } else {
342 diff = scrolled->y_offset - value;
343
344 if (diff >= widget->allocation.height) {
345 scrolled->y_offset = value;
346 WIDGET_DRAW(widget, NULL);
347 return;
348 }
349
350 if (diff > 0)
351 gdk_window_copy_area (widget->window,
352 scrolled->copy_gc,
353 0, diff,
354 widget->window,
355 0, 0,
356 widget->allocation.width - 2 * bw (widget),
357 widget->allocation.height - 2 * bw (widget) - diff);
358
359 area.x = 0;
360 area.y = 0;
361 area.width = widget->allocation.width - 2 * bw (widget);
362 area.height = diff;
363 }
364
365
366 if (diff > 0) {
367 scrolled->y_offset = value;
368 #ifndef USE_GTK2
369 check_exposures (widget);
370 #endif /* USE_GTK2 */
371 /* WIDGET_DRAW(widget, &area); */
372 WIDGET_DRAW(widget, NULL);
373 }
374 }
375
376 static void
gimv_scrolled_set_scroll_adjustments(GtkWidget * widget,GtkAdjustment * hadjustment,GtkAdjustment * vadjustment)377 gimv_scrolled_set_scroll_adjustments (GtkWidget *widget,
378 GtkAdjustment *hadjustment,
379 GtkAdjustment *vadjustment)
380 {
381 GimvScrolled *scrolled;
382 scrolled = GIMV_SCROLLED(widget);
383
384 if (scrolled->h_adjustment != hadjustment) {
385 if (scrolled->h_adjustment) {
386 gtk_signal_disconnect_by_data (GTK_OBJECT(scrolled->h_adjustment),
387 scrolled);
388 gtk_object_unref (GTK_OBJECT(scrolled->h_adjustment));
389 }
390
391 scrolled->h_adjustment = hadjustment;
392
393 if (hadjustment) {
394 gtk_object_ref (GTK_OBJECT(hadjustment));
395 gtk_signal_connect (GTK_OBJECT(hadjustment),
396 "value_changed",
397 (GtkSignalFunc) hadjustment_value_changed,
398 scrolled);
399 }
400 }
401
402
403 if (scrolled->v_adjustment != vadjustment) {
404 if (scrolled->v_adjustment) {
405 gtk_signal_disconnect_by_data (GTK_OBJECT(scrolled->v_adjustment),
406 scrolled);
407 gtk_object_unref (GTK_OBJECT(scrolled->v_adjustment));
408 }
409
410 scrolled->v_adjustment = vadjustment;
411
412 if (vadjustment) {
413 gtk_object_ref (GTK_OBJECT(vadjustment));
414 gtk_signal_connect (GTK_OBJECT(vadjustment),
415 "value_changed",
416 (GtkSignalFunc) vadjustment_value_changed,
417 scrolled);
418 }
419 }
420
421 gtk_signal_emit (GTK_OBJECT(scrolled),
422 gimv_scrolled_signals[ADJUST_ADJUSTMENTS]);
423 }
424
425 void
gimv_scrolled_freeze(GimvScrolled * scrolled)426 gimv_scrolled_freeze (GimvScrolled *scrolled)
427 {
428 g_return_if_fail (scrolled);
429 g_return_if_fail (scrolled->freeze_count != (guint) -1);
430
431 scrolled->freeze_count ++;
432 }
433
434 void
gimv_scrolled_thawn(GimvScrolled * scrolled)435 gimv_scrolled_thawn (GimvScrolled *scrolled)
436 {
437 g_return_if_fail (scrolled);
438 g_return_if_fail (scrolled->freeze_count);
439
440 scrolled->freeze_count --;
441 if (!scrolled->freeze_count) {
442 gtk_signal_emit (GTK_OBJECT(scrolled),
443 gimv_scrolled_signals [ADJUST_ADJUSTMENTS]);
444 gtk_widget_draw (GTK_WIDGET(scrolled), NULL);
445 }
446 }
447
448
449 #ifndef USE_GTK2
450 /* from gtkclist.c */
451 static void
check_exposures(GtkWidget * widget)452 check_exposures (GtkWidget *widget)
453 {
454 GdkEvent *event;
455
456 if (!GTK_WIDGET_REALIZED (widget))
457 return;
458
459 /*
460 * Make sure graphics expose events are processed before scrolling
461 * again
462 */
463 while ((event = gdk_event_get_graphics_expose (widget->window)) != NULL) {
464 gtk_widget_event (widget, event);
465 if (event->expose.count == 0) {
466 gdk_event_free (event);
467 break;
468 }
469 gdk_event_free (event);
470 }
471 }
472 #endif /* USE_GTK2 */
473
474
475 void
gimv_scrolled_page_up(GimvScrolled * scrolled)476 gimv_scrolled_page_up (GimvScrolled *scrolled)
477 {
478 GtkAdjustment *vadj;
479
480 g_return_if_fail (scrolled);
481 g_return_if_fail (GIMV_IS_SCROLLED (scrolled));
482
483 vadj = scrolled->v_adjustment;
484
485 vadj->value -= vadj->page_size;
486 adjustment_check_value (vadj->value, vadj);
487
488 gtk_signal_emit_by_name (GTK_OBJECT(vadj), "value_changed");
489 }
490
491
492 void
gimv_scrolled_page_down(GimvScrolled * scrolled)493 gimv_scrolled_page_down (GimvScrolled *scrolled)
494 {
495 GtkAdjustment *vadj;
496
497 g_return_if_fail (scrolled);
498 g_return_if_fail (GIMV_IS_SCROLLED (scrolled));
499
500 vadj = scrolled->v_adjustment;
501
502 vadj->value += vadj->page_size;
503 adjustment_check_value (vadj->value, vadj);
504
505 gtk_signal_emit_by_name (GTK_OBJECT(vadj), "value_changed");
506 }
507
508
509 void
gimv_scrolled_page_left(GimvScrolled * scrolled)510 gimv_scrolled_page_left (GimvScrolled *scrolled)
511 {
512 GtkAdjustment *hadj;
513
514 g_return_if_fail (scrolled);
515 g_return_if_fail (GIMV_IS_SCROLLED (scrolled));
516
517 hadj = scrolled->h_adjustment;
518
519 hadj->value -= hadj->page_size;
520 adjustment_check_value (hadj->value, hadj);
521
522 gtk_signal_emit_by_name (GTK_OBJECT(hadj), "value_changed");
523 }
524
525
526 void
gimv_scrolled_page_right(GimvScrolled * scrolled)527 gimv_scrolled_page_right (GimvScrolled *scrolled)
528 {
529 GtkAdjustment *hadj;
530
531 g_return_if_fail (scrolled);
532 g_return_if_fail (GIMV_IS_SCROLLED (scrolled));
533
534 hadj = scrolled->h_adjustment;
535 hadj->value = hadj->value;
536
537 hadj->value += hadj->page_size;
538 adjustment_check_value (hadj->value, hadj);
539
540 gtk_signal_emit_by_name (GTK_OBJECT(hadj), "value_changed");
541 }
542
543
544 /******************************************************************************
545 *
546 * for auto scroll related functions
547 *
548 ******************************************************************************/
549 enum
550 {
551 HORIZONTAL,
552 VERTICAL
553 };
554
555 static void
cancel_auto_scroll(GimvScrolled * scrolled)556 cancel_auto_scroll (GimvScrolled *scrolled)
557 {
558 g_return_if_fail (scrolled);
559 g_return_if_fail (GIMV_IS_SCROLLED (scrolled));
560
561 /* horizontal */
562 if (scrolled->hscroll_timer_id != -1){
563 gtk_timeout_remove (scrolled->hscroll_timer_id);
564 scrolled->hscroll_timer_id = -1;
565 }
566
567 /* vertival */
568 if (scrolled->vscroll_timer_id != -1){
569 gtk_timeout_remove (scrolled->vscroll_timer_id);
570 scrolled->vscroll_timer_id = -1;
571 }
572 }
573
574
575 static gboolean
scrolling_is_desirable(GimvScrolled * scrolled,gint direction,gint x,gint y,gfloat * scale)576 scrolling_is_desirable (GimvScrolled *scrolled, gint direction,
577 gint x, gint y, gfloat *scale)
578 {
579 GtkAdjustment *adj;
580 gint pos, edge_width, flags;
581 gfloat upper;
582
583 flags = scrolled->autoscroll_flags;
584
585 if (direction == HORIZONTAL) {
586 if (!(flags & GIMV_SCROLLED_AUTO_SCROLL_HORIZONTAL)
587 && !(flags & GIMV_SCROLLED_AUTO_SCROLL_BOTH))
588 {
589 return FALSE;
590 }
591
592 adj = scrolled->h_adjustment;
593 pos = x;
594 edge_width = scrolled->scroll_edge_x;
595 } else if (direction == VERTICAL) {
596 if (!(flags & GIMV_SCROLLED_AUTO_SCROLL_VERTICAL)
597 && !(flags & GIMV_SCROLLED_AUTO_SCROLL_BOTH))
598 {
599 return FALSE;
600 }
601
602 adj = scrolled->v_adjustment;
603 pos = y;
604 edge_width = scrolled->scroll_edge_y;
605 } else {
606 return FALSE;
607 }
608
609 upper = adj->upper - adj->page_size;
610
611 if ((pos < edge_width) && (adj->value > adj->lower)) {
612 if (scale)
613 *scale = 1 + (0 - pos) / AUTO_SCROLL_SCALE_RATE;
614 return TRUE;
615 } else if ((pos > (adj->page_size - edge_width)) && (adj->value < upper)) {
616 if (scale)
617 *scale = 1 + (pos - adj->page_size) / AUTO_SCROLL_SCALE_RATE;
618 return TRUE;
619 }
620
621 return 0;
622 }
623
624
625 static gboolean
vertical_timeout(gpointer data)626 vertical_timeout (gpointer data)
627 {
628 GimvScrolled *scrolled = data;
629 GtkAdjustment *vadj;
630 gint step;
631
632 vadj = scrolled->v_adjustment;
633
634 if (scrolled->y_step < 0)
635 step = vadj->step_increment;
636 else
637 step = scrolled->y_step;
638
639 step *= scrolled->step_scale;
640
641 if (scrolled->drag_motion_y < scrolled->scroll_edge_y)
642 vadj->value = vadj->value - step;
643 else
644 vadj->value = vadj->value + step;
645
646 adjustment_check_value (vadj->value, vadj);
647 gtk_signal_emit_by_name (GTK_OBJECT(vadj), "value_changed");
648
649 return TRUE;
650 }
651
652
653 static gboolean
horizontal_timeout(gpointer data)654 horizontal_timeout (gpointer data)
655 {
656 GimvScrolled *scrolled = data;
657 GtkAdjustment *hadj;
658 gint step;
659
660 hadj = scrolled->h_adjustment;
661
662 if (scrolled->x_step < 0)
663 step = hadj->step_increment;
664 else
665 step = scrolled->x_step;
666
667 step *= scrolled->step_scale;
668
669 if (scrolled->drag_motion_x < scrolled->scroll_edge_x)
670 hadj->value = hadj->value - step;
671 else
672 hadj->value = hadj->value + step;
673
674 adjustment_check_value (hadj->value, hadj);
675 gtk_signal_emit_by_name (GTK_OBJECT(hadj), "value_changed");
676
677 return TRUE;
678 }
679
680
681 static void
setup_drag_scroll(GimvScrolled * scrolled,gint x,gint y)682 setup_drag_scroll (GimvScrolled *scrolled,
683 gint x, gint y)
684 {
685 GtkAdjustment *hadj, *vadj;
686 gboolean desirable;
687
688 hadj = scrolled->h_adjustment;
689 vadj = scrolled->v_adjustment;
690
691 cancel_auto_scroll (scrolled);
692
693 scrolled->drag_motion_x = x;
694 scrolled->drag_motion_y = y;
695
696 /* horizonal */
697 desirable = scrolling_is_desirable (scrolled, HORIZONTAL,
698 x, y, &scrolled->step_scale);
699
700 if (desirable)
701 scrolled->hscroll_timer_id
702 = gtk_timeout_add (scrolled->x_interval,
703 horizontal_timeout, scrolled);
704
705 /* vertical */
706 desirable = scrolling_is_desirable (scrolled, VERTICAL,
707 x, y, &scrolled->step_scale);
708
709 if (desirable)
710 scrolled->vscroll_timer_id
711 = gtk_timeout_add (scrolled->y_interval,
712 vertical_timeout, scrolled);
713 }
714
715
716 static gint
gimv_scrolled_button_press(GtkWidget * widget,GdkEventButton * event)717 gimv_scrolled_button_press (GtkWidget *widget, GdkEventButton *event)
718 {
719 GimvScrolled *scrolled;
720
721 g_return_val_if_fail (widget && event, FALSE);
722 g_return_val_if_fail (GIMV_IS_SCROLLED(widget), FALSE);
723
724 scrolled = GIMV_SCROLLED (widget);
725
726 scrolled->pressed = TRUE;
727 scrolled->drag_start_vx = GIMV_SCROLLED_VX (scrolled, (gint) event->x);
728 scrolled->drag_start_vy = GIMV_SCROLLED_VY (scrolled, (gint) event->y);
729
730 return FALSE;
731 }
732
733
734 static gint
gimv_scrolled_button_release(GtkWidget * widget,GdkEventButton * event)735 gimv_scrolled_button_release (GtkWidget *widget, GdkEventButton *event)
736 {
737 g_return_val_if_fail (widget && event, FALSE);
738 g_return_val_if_fail (GIMV_IS_SCROLLED(widget), FALSE);
739
740 gimv_scrolled_stop_auto_scroll (GIMV_SCROLLED (widget));
741
742 return FALSE;
743 }
744
745
746 static gint
gimv_scrolled_motion_notify(GtkWidget * widget,GdkEventMotion * event)747 gimv_scrolled_motion_notify (GtkWidget *widget, GdkEventMotion *event)
748 {
749 GimvScrolled *scrolled;
750 gint flags;
751 gboolean pressed;
752
753 g_return_val_if_fail (widget && event, FALSE);
754 g_return_val_if_fail (GIMV_IS_SCROLLED(widget), FALSE);
755
756 scrolled = GIMV_SCROLLED (widget);
757
758 flags = scrolled->autoscroll_flags;
759 pressed = scrolled->pressed;
760
761 scrolled->drag_motion_x = event->x;
762 scrolled->drag_motion_y = event->y;
763
764 if ((pressed && (flags & GIMV_SCROLLED_AUTO_SCROLL_MOTION))
765 || (flags & GIMV_SCROLLED_AUTO_SCROLL_MOTION_ALL))
766 {
767 setup_drag_scroll (scrolled, (gint) event->x, (gint) event->y);
768 }
769
770 return FALSE;
771 }
772
773
774 static gint
gimv_scrolled_drag_motion(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time)775 gimv_scrolled_drag_motion (GtkWidget *widget,
776 GdkDragContext *context,
777 gint x,
778 gint y,
779 guint time)
780 {
781 GimvScrolled *scrolled;
782 gint flags;
783
784 g_return_val_if_fail (widget && context, FALSE);
785 g_return_val_if_fail (GIMV_IS_SCROLLED(widget), FALSE);
786
787 scrolled = GIMV_SCROLLED (widget);
788
789 flags = scrolled->autoscroll_flags;
790
791 if (flags & GIMV_SCROLLED_AUTO_SCROLL_DND) {
792 setup_drag_scroll (GIMV_SCROLLED (widget), x, y);
793 }
794
795 return FALSE;
796 }
797
798
799 static void
gimv_scrolled_drag_leave(GtkWidget * widget,GdkDragContext * context,guint time)800 gimv_scrolled_drag_leave (GtkWidget *widget,
801 GdkDragContext *context,
802 guint time)
803 {
804 g_return_if_fail (widget && context);
805 g_return_if_fail (GIMV_IS_SCROLLED(widget));
806
807 cancel_auto_scroll (GIMV_SCROLLED (widget));
808 }
809
810
811 void
gimv_scrolled_set_auto_scroll(GimvScrolled * scrolled,GimvScrolledAutoScrollFlags flags)812 gimv_scrolled_set_auto_scroll (GimvScrolled *scrolled,
813 GimvScrolledAutoScrollFlags flags)
814 {
815 g_return_if_fail (scrolled);
816 g_return_if_fail (GIMV_IS_SCROLLED(scrolled));
817
818 scrolled->autoscroll_flags |= flags;
819 }
820
821
822 void
gimv_scrolled_unset_auto_scroll(GimvScrolled * scrolled)823 gimv_scrolled_unset_auto_scroll (GimvScrolled *scrolled)
824 {
825 g_return_if_fail (scrolled);
826 g_return_if_fail (GIMV_IS_SCROLLED(scrolled));
827
828 scrolled->autoscroll_flags = 0;
829 }
830
831
832 void
gimv_scrolled_set_auto_scroll_edge_width(GimvScrolled * scrolled,gint x_edge,gint y_edge)833 gimv_scrolled_set_auto_scroll_edge_width (GimvScrolled *scrolled,
834 gint x_edge,
835 gint y_edge)
836 {
837 g_return_if_fail (scrolled);
838 g_return_if_fail (GIMV_IS_SCROLLED(scrolled));
839
840 if (x_edge < 0)
841 scrolled->scroll_edge_x = AUTO_SCROLL_EDGE_WIDTH;
842 else
843 scrolled->scroll_edge_x = x_edge;
844
845 if (y_edge < 0)
846 scrolled->scroll_edge_y = AUTO_SCROLL_EDGE_WIDTH;
847 else
848 scrolled->scroll_edge_y = y_edge;
849 }
850
851
852 void
gimv_scrolled_set_h_auto_scroll_resolution(GimvScrolled * scrolled,gint step,gint interval)853 gimv_scrolled_set_h_auto_scroll_resolution (GimvScrolled *scrolled,
854 gint step,
855 gint interval)
856 {
857 g_return_if_fail (scrolled);
858 g_return_if_fail (GIMV_IS_SCROLLED(scrolled));
859
860 scrolled->x_step = step;
861 if (interval <= 0)
862 scrolled->x_interval = AUTO_SCROLL_TIMEOUT;
863 else
864 scrolled->x_interval = interval;
865 }
866
867
868 void
gimv_scrolled_set_v_auto_scroll_resolution(GimvScrolled * scrolled,gint step,gint interval)869 gimv_scrolled_set_v_auto_scroll_resolution (GimvScrolled *scrolled,
870 gint step,
871 gint interval)
872 {
873 g_return_if_fail (scrolled);
874 g_return_if_fail (GIMV_IS_SCROLLED(scrolled));
875
876 scrolled->y_step = step;
877 if (interval <= 0)
878 scrolled->y_interval = AUTO_SCROLL_TIMEOUT;
879 else
880 scrolled->y_interval = interval;
881 }
882
883
884 gboolean
gimv_scrolled_is_dragging(GimvScrolled * scrolled)885 gimv_scrolled_is_dragging (GimvScrolled *scrolled)
886 {
887 g_return_val_if_fail (scrolled, FALSE);
888 g_return_val_if_fail (scrolled, FALSE);
889
890 if (scrolled->pressed
891 && scrolled->drag_motion_x >= 0
892 && scrolled->drag_motion_y >= 0)
893 {
894 return TRUE;
895 }
896
897 return FALSE;
898 }
899
900
901 void
gimv_scrolled_stop_auto_scroll(GimvScrolled * scrolled)902 gimv_scrolled_stop_auto_scroll (GimvScrolled *scrolled)
903 {
904 g_return_if_fail (scrolled);
905 g_return_if_fail (GIMV_IS_SCROLLED(scrolled));
906
907 cancel_auto_scroll (scrolled);
908
909 scrolled->pressed = FALSE;
910 scrolled->drag_start_vx = -1;
911 scrolled->drag_start_vy = -1;
912 scrolled->drag_motion_x = -1;
913 scrolled->drag_motion_y = -1;
914 }
915