1 /* scrollbar implementation -- X interface.
2 Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3 Copyright (C) 1994 Amdhal Corporation.
4 Copyright (C) 1995 Sun Microsystems, Inc.
5 Copyright (C) 1995 Darrell Kindred <dkindred+@cmu.edu>.
7 This file is part of XEmacs.
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
24 /* Synched up with: Not in FSF. */
25 /* Gtk version by William M. Perry */
30 #include "console-gtk.h"
31 #include "glyphs-gtk.h"
33 #include "scrollbar-gtk.h"
38 static gboolean scrollbar_cb (GtkAdjustment *adj, gpointer user_data);
40 /* Used to prevent changing the size of the slider while drag
41 scrolling, under Motif. This is necessary because the Motif
42 scrollbar is incredibly stupid about updating the slider and causes
43 lots of flicker if it is done too often. */
44 static int inhibit_slider_size_change;
46 static int vertical_drag_in_progress;
49 /* A device method. */
51 gtk_inhibit_scrollbar_slider_size_change (void)
53 return inhibit_slider_size_change;
56 /* A device method. */
58 gtk_free_scrollbar_instance (struct scrollbar_instance *instance)
60 if (SCROLLBAR_GTK_WIDGET (instance))
62 gtk_widget_hide_all (SCROLLBAR_GTK_WIDGET (instance));
63 gtk_widget_destroy (SCROLLBAR_GTK_WIDGET (instance));
66 if (instance->scrollbar_data)
67 xfree (instance->scrollbar_data);
70 /* A device method. */
72 gtk_release_scrollbar_instance (struct scrollbar_instance *instance)
74 /* It won't hurt to hide it all the time, will it? */
75 gtk_widget_hide_all (SCROLLBAR_GTK_WIDGET (instance));
79 scrollbar_drag_hack_cb (GtkWidget *w, GdkEventButton *ev, gpointer v)
81 vertical_drag_in_progress = (int) v;
82 inhibit_slider_size_change = (int) v;
86 /* A device method. */
88 gtk_create_scrollbar_instance (struct frame *f, int vertical,
89 struct scrollbar_instance *instance)
91 GtkAdjustment *adj = GTK_ADJUSTMENT (gtk_adjustment_new (0,0,0,0,0,0));
92 GtkScrollbar *sb = NULL;
94 /* initialize the X specific data section. */
95 instance->scrollbar_data = xnew_and_zero (struct gtk_scrollbar_data);
97 SCROLLBAR_GTK_ID (instance) = new_gui_id ();
98 SCROLLBAR_GTK_VDRAG_ORIG_VALUE (instance) = -1;
99 SCROLLBAR_GTK_LAST_VALUE (instance) = adj->value;
101 gtk_object_set_data (GTK_OBJECT (adj), "xemacs::gui_id", (void *) SCROLLBAR_GTK_ID (instance));
102 gtk_object_set_data (GTK_OBJECT (adj), "xemacs::frame", f);
103 gtk_object_set_data (GTK_OBJECT (adj), "xemacs::sb_instance", instance);
105 sb = GTK_SCROLLBAR (vertical ? gtk_vscrollbar_new (adj) : gtk_hscrollbar_new (adj));
106 SCROLLBAR_GTK_WIDGET (instance) = GTK_WIDGET (sb);
108 gtk_signal_connect (GTK_OBJECT (adj),"value-changed",
109 GTK_SIGNAL_FUNC (scrollbar_cb), (gpointer) vertical);
111 gtk_signal_connect (GTK_OBJECT (sb), "button-press-event",
112 GTK_SIGNAL_FUNC (scrollbar_drag_hack_cb), (gpointer) 1);
113 gtk_signal_connect (GTK_OBJECT (sb), "button-release-event",
114 GTK_SIGNAL_FUNC (scrollbar_drag_hack_cb), (gpointer) 0);
116 gtk_fixed_put (GTK_FIXED (FRAME_GTK_TEXT_WIDGET (f)), SCROLLBAR_GTK_WIDGET (instance), 0, 0);
117 gtk_widget_hide (SCROLLBAR_GTK_WIDGET (instance));
120 #define UPDATE_DATA_FIELD(field) \
121 if (new_##field >= 0 && \
122 SCROLLBAR_GTK_POS_DATA (inst).field != new_##field) { \
123 SCROLLBAR_GTK_POS_DATA (inst).field = new_##field; \
124 inst->scrollbar_instance_changed = 1; \
127 /* A device method. */
128 /* #### The -1 check is such a hack. */
130 gtk_update_scrollbar_instance_values (struct window *w,
131 struct scrollbar_instance *inst,
132 int new_line_increment,
133 int new_page_increment,
134 int new_minimum, int new_maximum,
136 int new_slider_position,
137 int new_scrollbar_width,
138 int new_scrollbar_height,
139 int new_scrollbar_x, int new_scrollbar_y)
141 UPDATE_DATA_FIELD (line_increment);
142 UPDATE_DATA_FIELD (page_increment);
143 UPDATE_DATA_FIELD (minimum);
144 UPDATE_DATA_FIELD (maximum);
145 UPDATE_DATA_FIELD (slider_size);
146 UPDATE_DATA_FIELD (slider_position);
147 UPDATE_DATA_FIELD (scrollbar_width);
148 UPDATE_DATA_FIELD (scrollbar_height);
149 UPDATE_DATA_FIELD (scrollbar_x);
150 UPDATE_DATA_FIELD (scrollbar_y);
152 if (w && !vertical_drag_in_progress)
154 int new_vov = SCROLLBAR_GTK_POS_DATA (inst).slider_position;
155 int new_vows = marker_position (w->start[CURRENT_DISP]);
157 if (SCROLLBAR_GTK_VDRAG_ORIG_VALUE (inst) != new_vov)
159 SCROLLBAR_GTK_VDRAG_ORIG_VALUE (inst) = new_vov;
160 inst->scrollbar_instance_changed = 1;
162 if (SCROLLBAR_GTK_VDRAG_ORIG_WINDOW_START (inst) != new_vows)
164 SCROLLBAR_GTK_VDRAG_ORIG_WINDOW_START (inst) = new_vows;
165 inst->scrollbar_instance_changed = 1;
170 /* Used by gtk_update_scrollbar_instance_status. */
172 update_one_widget_scrollbar_pointer (struct window *w, GtkWidget *wid)
175 gtk_widget_realize (wid);
177 if (POINTER_IMAGE_INSTANCEP (w->scrollbar_pointer))
179 gdk_window_set_cursor (GET_GTK_WIDGET_WINDOW (wid),
180 XIMAGE_INSTANCE_GTK_CURSOR (w->scrollbar_pointer));
185 /* A device method. */
187 gtk_update_scrollbar_instance_status (struct window *w, int active, int size,
188 struct scrollbar_instance *instance)
190 struct frame *f = XFRAME (w->frame);
191 GtkWidget *wid = SCROLLBAR_GTK_WIDGET (instance);
192 gboolean managed = GTK_WIDGET_MAPPED (wid);
196 if (instance->scrollbar_instance_changed)
198 /* Need to set the height, width, and position of the widget */
199 GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (wid));
200 scrollbar_values *pos_data = & SCROLLBAR_GTK_POS_DATA (instance);
203 /* We do not want to update the size all the time if we can
204 help it. This cuts down on annoying flicker.
206 if ((wid->allocation.width != pos_data->scrollbar_width) ||
207 (wid->allocation.height != pos_data->scrollbar_height))
209 gtk_widget_set_usize (wid,
210 pos_data->scrollbar_width,
211 pos_data->scrollbar_height);
215 /* Ditto for the x/y position. */
216 if ((wid->allocation.x != pos_data->scrollbar_x) ||
217 (wid->allocation.y != pos_data->scrollbar_y))
219 gtk_fixed_move (GTK_FIXED (FRAME_GTK_TEXT_WIDGET (f)),
221 pos_data->scrollbar_x,
222 pos_data->scrollbar_y);
226 adj->lower = pos_data->minimum;
227 adj->upper = pos_data->maximum;
228 adj->page_increment = pos_data->slider_size + 1;
229 adj->step_increment = w->max_line_len - 1;
230 adj->page_size = pos_data->slider_size + 1;
231 adj->value = pos_data->slider_position;
233 /* But, if we didn't resize or move the scrollbar, the
234 widget will not get redrawn correctly when the user
235 scrolls around in the XEmacs frame manually. So we
236 update the slider manually here.
239 gtk_range_slider_update (GTK_RANGE (wid));
241 instance->scrollbar_instance_changed = 0;
246 gtk_widget_show (wid);
247 update_one_widget_scrollbar_pointer (w, wid);
252 gtk_widget_hide (wid);
256 enum gtk_scrollbar_loop
258 GTK_FIND_SCROLLBAR_WINDOW_MIRROR,
259 GTK_SET_SCROLLBAR_POINTER,
260 GTK_WINDOW_IS_SCROLLBAR,
261 GTK_UPDATE_FRAME_SCROLLBARS
264 static struct window_mirror *
265 gtk_scrollbar_loop (enum gtk_scrollbar_loop type, Lisp_Object window,
266 struct window_mirror *mir,
267 GUI_ID id, GdkWindow *x_win)
269 struct window_mirror *retval = NULL;
273 struct scrollbar_instance *vinstance = mir->scrollbar_vertical_instance;
274 struct scrollbar_instance *hinstance = mir->scrollbar_horizontal_instance;
275 struct window *w = XWINDOW (window);
278 retval = gtk_scrollbar_loop (type, w->vchild, mir->vchild, id, x_win);
279 else if (mir->hchild)
280 retval = gtk_scrollbar_loop (type, w->hchild, mir->hchild, id, x_win);
284 if (hinstance || vinstance)
288 case GTK_FIND_SCROLLBAR_WINDOW_MIRROR:
289 if ((vinstance && SCROLLBAR_GTK_ID (vinstance) == id) ||
290 (hinstance && SCROLLBAR_GTK_ID (hinstance) == id))
293 case GTK_UPDATE_FRAME_SCROLLBARS:
294 if (!mir->vchild && !mir->hchild)
295 update_window_scrollbars (w, mir, 1, 0);
297 case GTK_SET_SCROLLBAR_POINTER:
298 if (!mir->vchild && !mir->hchild)
302 widget = SCROLLBAR_GTK_WIDGET (hinstance);
303 if (widget && GTK_WIDGET_MAPPED (widget))
304 update_one_widget_scrollbar_pointer (w, widget);
306 widget = SCROLLBAR_GTK_WIDGET (vinstance);
307 if (widget && GTK_WIDGET_MAPPED (widget))
308 update_one_widget_scrollbar_pointer (w, widget);
311 case GTK_WINDOW_IS_SCROLLBAR:
312 if (!mir->vchild && !mir->hchild)
316 widget = SCROLLBAR_GTK_WIDGET (hinstance);
317 if (widget && GTK_WIDGET_MAPPED (widget) &&
318 GET_GTK_WIDGET_WINDOW (widget) == x_win)
319 return (struct window_mirror *) 1;
321 widget = SCROLLBAR_GTK_WIDGET (vinstance);
322 if (widget && GTK_WIDGET_MAPPED (widget) &&
323 GET_GTK_WIDGET_WINDOW (widget) == x_win)
324 return (struct window_mirror *) 1;
339 /* Used by callbacks. */
340 static struct window_mirror *
341 find_scrollbar_window_mirror (struct frame *f, GUI_ID id)
344 update_frame_window_mirror (f);
345 return gtk_scrollbar_loop (GTK_FIND_SCROLLBAR_WINDOW_MIRROR, f->root_window,
346 f->root_mirror, id, (GdkWindow *) NULL);
350 scrollbar_cb (GtkAdjustment *adj, gpointer user_data)
352 /* This function can GC */
353 int vertical = (int) user_data;
354 struct frame *f = gtk_object_get_data (GTK_OBJECT (adj), "xemacs::frame");
355 struct scrollbar_instance *instance = gtk_object_get_data (GTK_OBJECT (adj), "xemacs::sb_instance");
356 GUI_ID id = (GUI_ID) gtk_object_get_data (GTK_OBJECT (adj), "xemacs::gui_id");
357 Lisp_Object win, frame;
358 struct window_mirror *mirror;
359 Lisp_Object event_type = Qnil;
360 Lisp_Object event_data = Qnil;
365 mirror = find_scrollbar_window_mirror (f, id);
369 win = real_window (mirror, 1);
373 instance = vertical ? mirror->scrollbar_vertical_instance : mirror->scrollbar_horizontal_instance;
374 frame = WINDOW_FRAME (XWINDOW (win));
376 inhibit_slider_size_change = 0;
377 switch (GTK_RANGE (SCROLLBAR_GTK_WIDGET (instance))->scroll_type)
379 case GTK_SCROLL_PAGE_BACKWARD:
380 event_type = vertical ? Qscrollbar_page_up : Qscrollbar_page_left;
381 event_data = Fcons (win, Qnil);
383 case GTK_SCROLL_PAGE_FORWARD:
384 event_type = vertical ? Qscrollbar_page_down : Qscrollbar_page_right;
385 event_data = Fcons (win, Qnil);
387 case GTK_SCROLL_STEP_FORWARD:
388 event_type = vertical ? Qscrollbar_line_down : Qscrollbar_char_right;
391 case GTK_SCROLL_STEP_BACKWARD:
392 event_type = vertical ? Qscrollbar_line_up : Qscrollbar_char_left;
395 case GTK_SCROLL_NONE:
396 case GTK_SCROLL_JUMP:
397 inhibit_slider_size_change = 1;
398 event_type = vertical ? Qscrollbar_vertical_drag : Qscrollbar_horizontal_drag;
399 event_data = Fcons (win, make_int ((int)adj->value));
405 signal_special_gtk_user_event (frame, event_type, event_data);
411 gtk_scrollbar_pointer_changed_in_window (struct window *w)
415 XSETWINDOW (window, w);
416 gtk_scrollbar_loop (GTK_SET_SCROLLBAR_POINTER, window, find_window_mirror (w),
417 0, (GdkWindow *) NULL);
420 /* #### BILL!!! This comment is not true for Gtk - should it be? */
421 /* Make sure that all scrollbars on frame are up-to-date. Called
422 directly from gtk_set_frame_properties in frame-gtk.c*/
424 gtk_update_frame_scrollbars (struct frame *f)
426 /* Consider this code to be "in_display" so that we abort() if Fsignal()
429 gtk_scrollbar_loop (GTK_UPDATE_FRAME_SCROLLBARS, f->root_window, f->root_mirror,
430 0, (GdkWindow *) NULL);
432 if (in_display < 0) abort ();
435 #ifdef MEMORY_USAGE_STATS
437 gtk_compute_scrollbar_instance_usage (struct device *d,
438 struct scrollbar_instance *inst,
439 struct overhead_stats *ovstats)
445 struct gtk_scrollbar_data *data =
446 (struct gtk_scrollbar_data *) inst->scrollbar_data;
448 total += malloced_storage_size (data, sizeof (*data), ovstats);
455 #endif /* MEMORY_USAGE_STATS */
458 /************************************************************************/
460 /************************************************************************/
463 console_type_create_scrollbar_gtk (void)
465 CONSOLE_HAS_METHOD (gtk, inhibit_scrollbar_slider_size_change);
466 CONSOLE_HAS_METHOD (gtk, free_scrollbar_instance);
467 CONSOLE_HAS_METHOD (gtk, release_scrollbar_instance);
468 CONSOLE_HAS_METHOD (gtk, create_scrollbar_instance);
469 CONSOLE_HAS_METHOD (gtk, update_scrollbar_instance_values);
470 CONSOLE_HAS_METHOD (gtk, update_scrollbar_instance_status);
471 CONSOLE_HAS_METHOD (gtk, scrollbar_pointer_changed_in_window);
472 #ifdef MEMORY_USAGE_STATS
473 CONSOLE_HAS_METHOD (gtk, compute_scrollbar_instance_usage);
474 #endif /* MEMORY_USAGE_STATS */
478 vars_of_scrollbar_gtk (void)
480 Fprovide (intern ("gtk-scrollbars"));