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 /* With gtk version > 1.2.8 the gtk code does not call
107 gtk_widget_request_size() on the newly created scrollbars
108 anymore (catering to theme engines).
109 #### Maybe it is better to postpone this call to just before
110 gtk_widget_show() is called on the scrollbar? */
111 #if GTK_MAJOR_VERSION == 1 && GTK_MINOR_VERSION == 2 && GTK_BINARY_AGE > 8
112 gtk_widget_size_request(GTK_WIDGET(sb), &(GTK_WIDGET(sb)->requisition));
114 SCROLLBAR_GTK_WIDGET (instance) = GTK_WIDGET (sb);
116 gtk_signal_connect (GTK_OBJECT (adj),"value-changed",
117 GTK_SIGNAL_FUNC (scrollbar_cb), (gpointer) vertical);
119 gtk_signal_connect (GTK_OBJECT (sb), "button-press-event",
120 GTK_SIGNAL_FUNC (scrollbar_drag_hack_cb), (gpointer) 1);
121 gtk_signal_connect (GTK_OBJECT (sb), "button-release-event",
122 GTK_SIGNAL_FUNC (scrollbar_drag_hack_cb), (gpointer) 0);
124 gtk_fixed_put (GTK_FIXED (FRAME_GTK_TEXT_WIDGET (f)), SCROLLBAR_GTK_WIDGET (instance), 0, 0);
125 gtk_widget_hide (SCROLLBAR_GTK_WIDGET (instance));
128 #define UPDATE_DATA_FIELD(field) \
129 if (new_##field >= 0 && \
130 SCROLLBAR_GTK_POS_DATA (inst).field != new_##field) { \
131 SCROLLBAR_GTK_POS_DATA (inst).field = new_##field; \
132 inst->scrollbar_instance_changed = 1; \
135 /* A device method. */
136 /* #### The -1 check is such a hack. */
138 gtk_update_scrollbar_instance_values (struct window *w,
139 struct scrollbar_instance *inst,
140 int new_line_increment,
141 int new_page_increment,
142 int new_minimum, int new_maximum,
144 int new_slider_position,
145 int new_scrollbar_width,
146 int new_scrollbar_height,
147 int new_scrollbar_x, int new_scrollbar_y)
149 UPDATE_DATA_FIELD (line_increment);
150 UPDATE_DATA_FIELD (page_increment);
151 UPDATE_DATA_FIELD (minimum);
152 UPDATE_DATA_FIELD (maximum);
153 UPDATE_DATA_FIELD (slider_size);
154 UPDATE_DATA_FIELD (slider_position);
155 UPDATE_DATA_FIELD (scrollbar_width);
156 UPDATE_DATA_FIELD (scrollbar_height);
157 UPDATE_DATA_FIELD (scrollbar_x);
158 UPDATE_DATA_FIELD (scrollbar_y);
160 if (w && !vertical_drag_in_progress)
162 int new_vov = SCROLLBAR_GTK_POS_DATA (inst).slider_position;
163 int new_vows = marker_position (w->start[CURRENT_DISP]);
165 if (SCROLLBAR_GTK_VDRAG_ORIG_VALUE (inst) != new_vov)
167 SCROLLBAR_GTK_VDRAG_ORIG_VALUE (inst) = new_vov;
168 inst->scrollbar_instance_changed = 1;
170 if (SCROLLBAR_GTK_VDRAG_ORIG_WINDOW_START (inst) != new_vows)
172 SCROLLBAR_GTK_VDRAG_ORIG_WINDOW_START (inst) = new_vows;
173 inst->scrollbar_instance_changed = 1;
178 /* Used by gtk_update_scrollbar_instance_status. */
180 update_one_widget_scrollbar_pointer (struct window *w, GtkWidget *wid)
183 gtk_widget_realize (wid);
185 if (POINTER_IMAGE_INSTANCEP (w->scrollbar_pointer))
187 gdk_window_set_cursor (GET_GTK_WIDGET_WINDOW (wid),
188 XIMAGE_INSTANCE_GTK_CURSOR (w->scrollbar_pointer));
193 /* A device method. */
195 gtk_update_scrollbar_instance_status (struct window *w, int active, int size,
196 struct scrollbar_instance *instance)
198 struct frame *f = XFRAME (w->frame);
199 GtkWidget *wid = SCROLLBAR_GTK_WIDGET (instance);
200 gboolean managed = GTK_WIDGET_MAPPED (wid);
204 if (instance->scrollbar_instance_changed)
206 /* Need to set the height, width, and position of the widget */
207 GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (wid));
208 scrollbar_values *pos_data = & SCROLLBAR_GTK_POS_DATA (instance);
211 /* We do not want to update the size all the time if we can
212 help it. This cuts down on annoying flicker.
214 if ((wid->allocation.width != pos_data->scrollbar_width) ||
215 (wid->allocation.height != pos_data->scrollbar_height))
217 gtk_widget_set_usize (wid,
218 pos_data->scrollbar_width,
219 pos_data->scrollbar_height);
223 /* Ditto for the x/y position. */
224 if ((wid->allocation.x != pos_data->scrollbar_x) ||
225 (wid->allocation.y != pos_data->scrollbar_y))
227 gtk_fixed_move (GTK_FIXED (FRAME_GTK_TEXT_WIDGET (f)),
229 pos_data->scrollbar_x,
230 pos_data->scrollbar_y);
234 adj->lower = pos_data->minimum;
235 adj->upper = pos_data->maximum;
236 adj->page_increment = pos_data->slider_size + 1;
237 adj->step_increment = w->max_line_len - 1;
238 adj->page_size = pos_data->slider_size + 1;
239 adj->value = pos_data->slider_position;
241 /* But, if we didn't resize or move the scrollbar, the
242 widget will not get redrawn correctly when the user
243 scrolls around in the XEmacs frame manually. So we
244 update the slider manually here.
247 gtk_range_slider_update (GTK_RANGE (wid));
249 instance->scrollbar_instance_changed = 0;
254 gtk_widget_show (wid);
255 update_one_widget_scrollbar_pointer (w, wid);
260 gtk_widget_hide (wid);
264 enum gtk_scrollbar_loop
266 GTK_FIND_SCROLLBAR_WINDOW_MIRROR,
267 GTK_SET_SCROLLBAR_POINTER,
268 GTK_WINDOW_IS_SCROLLBAR,
269 GTK_UPDATE_FRAME_SCROLLBARS
272 static struct window_mirror *
273 gtk_scrollbar_loop (enum gtk_scrollbar_loop type, Lisp_Object window,
274 struct window_mirror *mir,
275 GUI_ID id, GdkWindow *x_win)
277 struct window_mirror *retval = NULL;
281 struct scrollbar_instance *vinstance = mir->scrollbar_vertical_instance;
282 struct scrollbar_instance *hinstance = mir->scrollbar_horizontal_instance;
283 struct window *w = XWINDOW (window);
286 retval = gtk_scrollbar_loop (type, w->vchild, mir->vchild, id, x_win);
287 else if (mir->hchild)
288 retval = gtk_scrollbar_loop (type, w->hchild, mir->hchild, id, x_win);
292 if (hinstance || vinstance)
296 case GTK_FIND_SCROLLBAR_WINDOW_MIRROR:
297 if ((vinstance && SCROLLBAR_GTK_ID (vinstance) == id) ||
298 (hinstance && SCROLLBAR_GTK_ID (hinstance) == id))
301 case GTK_UPDATE_FRAME_SCROLLBARS:
302 if (!mir->vchild && !mir->hchild)
303 update_window_scrollbars (w, mir, 1, 0);
305 case GTK_SET_SCROLLBAR_POINTER:
306 if (!mir->vchild && !mir->hchild)
310 widget = SCROLLBAR_GTK_WIDGET (hinstance);
311 if (widget && GTK_WIDGET_MAPPED (widget))
312 update_one_widget_scrollbar_pointer (w, widget);
314 widget = SCROLLBAR_GTK_WIDGET (vinstance);
315 if (widget && GTK_WIDGET_MAPPED (widget))
316 update_one_widget_scrollbar_pointer (w, widget);
319 case GTK_WINDOW_IS_SCROLLBAR:
320 if (!mir->vchild && !mir->hchild)
324 widget = SCROLLBAR_GTK_WIDGET (hinstance);
325 if (widget && GTK_WIDGET_MAPPED (widget) &&
326 GET_GTK_WIDGET_WINDOW (widget) == x_win)
327 return (struct window_mirror *) 1;
329 widget = SCROLLBAR_GTK_WIDGET (vinstance);
330 if (widget && GTK_WIDGET_MAPPED (widget) &&
331 GET_GTK_WIDGET_WINDOW (widget) == x_win)
332 return (struct window_mirror *) 1;
347 /* Used by callbacks. */
348 static struct window_mirror *
349 find_scrollbar_window_mirror (struct frame *f, GUI_ID id)
352 update_frame_window_mirror (f);
353 return gtk_scrollbar_loop (GTK_FIND_SCROLLBAR_WINDOW_MIRROR, f->root_window,
354 f->root_mirror, id, (GdkWindow *) NULL);
358 scrollbar_cb (GtkAdjustment *adj, gpointer user_data)
360 /* This function can GC */
361 int vertical = (int) user_data;
362 struct frame *f = gtk_object_get_data (GTK_OBJECT (adj), "xemacs::frame");
363 struct scrollbar_instance *instance = gtk_object_get_data (GTK_OBJECT (adj), "xemacs::sb_instance");
364 GUI_ID id = (GUI_ID) gtk_object_get_data (GTK_OBJECT (adj), "xemacs::gui_id");
365 Lisp_Object win, frame;
366 struct window_mirror *mirror;
367 Lisp_Object event_type = Qnil;
368 Lisp_Object event_data = Qnil;
373 mirror = find_scrollbar_window_mirror (f, id);
377 win = real_window (mirror, 1);
381 instance = vertical ? mirror->scrollbar_vertical_instance : mirror->scrollbar_horizontal_instance;
382 frame = WINDOW_FRAME (XWINDOW (win));
384 inhibit_slider_size_change = 0;
385 switch (GTK_RANGE (SCROLLBAR_GTK_WIDGET (instance))->scroll_type)
387 case GTK_SCROLL_PAGE_BACKWARD:
388 event_type = vertical ? Qscrollbar_page_up : Qscrollbar_page_left;
389 event_data = Fcons (win, Qnil);
391 case GTK_SCROLL_PAGE_FORWARD:
392 event_type = vertical ? Qscrollbar_page_down : Qscrollbar_page_right;
393 event_data = Fcons (win, Qnil);
395 case GTK_SCROLL_STEP_FORWARD:
396 event_type = vertical ? Qscrollbar_line_down : Qscrollbar_char_right;
399 case GTK_SCROLL_STEP_BACKWARD:
400 event_type = vertical ? Qscrollbar_line_up : Qscrollbar_char_left;
403 case GTK_SCROLL_NONE:
404 case GTK_SCROLL_JUMP:
405 inhibit_slider_size_change = 1;
406 event_type = vertical ? Qscrollbar_vertical_drag : Qscrollbar_horizontal_drag;
407 event_data = Fcons (win, make_int ((int)adj->value));
413 signal_special_gtk_user_event (frame, event_type, event_data);
419 gtk_scrollbar_pointer_changed_in_window (struct window *w)
423 XSETWINDOW (window, w);
424 gtk_scrollbar_loop (GTK_SET_SCROLLBAR_POINTER, window, find_window_mirror (w),
425 0, (GdkWindow *) NULL);
428 /* #### BILL!!! This comment is not true for Gtk - should it be? */
429 /* Make sure that all scrollbars on frame are up-to-date. Called
430 directly from gtk_set_frame_properties in frame-gtk.c*/
432 gtk_update_frame_scrollbars (struct frame *f)
434 /* Consider this code to be "in_display" so that we abort() if Fsignal()
437 gtk_scrollbar_loop (GTK_UPDATE_FRAME_SCROLLBARS, f->root_window, f->root_mirror,
438 0, (GdkWindow *) NULL);
440 if (in_display < 0) abort ();
443 #ifdef MEMORY_USAGE_STATS
445 gtk_compute_scrollbar_instance_usage (struct device *d,
446 struct scrollbar_instance *inst,
447 struct overhead_stats *ovstats)
453 struct gtk_scrollbar_data *data =
454 (struct gtk_scrollbar_data *) inst->scrollbar_data;
456 total += malloced_storage_size (data, sizeof (*data), ovstats);
463 #endif /* MEMORY_USAGE_STATS */
466 /************************************************************************/
468 /************************************************************************/
471 console_type_create_scrollbar_gtk (void)
473 CONSOLE_HAS_METHOD (gtk, inhibit_scrollbar_slider_size_change);
474 CONSOLE_HAS_METHOD (gtk, free_scrollbar_instance);
475 CONSOLE_HAS_METHOD (gtk, release_scrollbar_instance);
476 CONSOLE_HAS_METHOD (gtk, create_scrollbar_instance);
477 CONSOLE_HAS_METHOD (gtk, update_scrollbar_instance_values);
478 CONSOLE_HAS_METHOD (gtk, update_scrollbar_instance_status);
479 CONSOLE_HAS_METHOD (gtk, scrollbar_pointer_changed_in_window);
480 #ifdef MEMORY_USAGE_STATS
481 CONSOLE_HAS_METHOD (gtk, compute_scrollbar_instance_usage);
482 #endif /* MEMORY_USAGE_STATS */
486 vars_of_scrollbar_gtk (void)
488 Fprovide (intern ("gtk-scrollbars"));