comparison src/scrollbar-gtk.c @ 462:0784d089fdc9 r21-2-46

Import from CVS: tag r21-2-46
author cvs
date Mon, 13 Aug 2007 11:44:37 +0200
parents
children 77fb0aa0e69f
comparison
equal deleted inserted replaced
461:120ed4009e51 462:0784d089fdc9
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>.
6
7 This file is part of XEmacs.
8
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
12 later version.
13
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
17 for more details.
18
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. */
23
24 /* Synched up with: Not in FSF. */
25 /* Gtk version by William M. Perry */
26
27 #include <config.h>
28 #include "lisp.h"
29
30 #include "console-gtk.h"
31 #include "glyphs-gtk.h"
32 #include "gui-gtk.h"
33 #include "scrollbar-gtk.h"
34
35 #include "frame.h"
36 #include "window.h"
37
38 static gboolean scrollbar_cb (GtkAdjustment *adj, gpointer user_data);
39
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;
45
46 static int vertical_drag_in_progress;
47
48
49 /* A device method. */
50 static int
51 gtk_inhibit_scrollbar_slider_size_change (void)
52 {
53 return inhibit_slider_size_change;
54 }
55
56 /* A device method. */
57 static void
58 gtk_free_scrollbar_instance (struct scrollbar_instance *instance)
59 {
60 if (SCROLLBAR_GTK_WIDGET (instance))
61 {
62 gtk_widget_hide_all (SCROLLBAR_GTK_WIDGET (instance));
63 gtk_widget_destroy (SCROLLBAR_GTK_WIDGET (instance));
64 }
65
66 if (instance->scrollbar_data)
67 xfree (instance->scrollbar_data);
68 }
69
70 /* A device method. */
71 static void
72 gtk_release_scrollbar_instance (struct scrollbar_instance *instance)
73 {
74 /* It won't hurt to hide it all the time, will it? */
75 gtk_widget_hide_all (SCROLLBAR_GTK_WIDGET (instance));
76 }
77
78 static gboolean
79 scrollbar_drag_hack_cb (GtkWidget *w, GdkEventButton *ev, gpointer v)
80 {
81 vertical_drag_in_progress = (int) v;
82 inhibit_slider_size_change = (int) v;
83 return (FALSE);
84 }
85
86 /* A device method. */
87 static void
88 gtk_create_scrollbar_instance (struct frame *f, int vertical,
89 struct scrollbar_instance *instance)
90 {
91 GtkAdjustment *adj = GTK_ADJUSTMENT (gtk_adjustment_new (0,0,0,0,0,0));
92 GtkScrollbar *sb = NULL;
93
94 /* initialize the X specific data section. */
95 instance->scrollbar_data = xnew_and_zero (struct gtk_scrollbar_data);
96
97 SCROLLBAR_GTK_ID (instance) = new_gui_id ();
98 SCROLLBAR_GTK_VDRAG_ORIG_VALUE (instance) = -1;
99 SCROLLBAR_GTK_LAST_VALUE (instance) = adj->value;
100
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);
104
105 sb = GTK_SCROLLBAR (vertical ? gtk_vscrollbar_new (adj) : gtk_hscrollbar_new (adj));
106 SCROLLBAR_GTK_WIDGET (instance) = GTK_WIDGET (sb);
107
108 gtk_signal_connect (GTK_OBJECT (adj),"value-changed",
109 GTK_SIGNAL_FUNC (scrollbar_cb), (gpointer) vertical);
110
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);
115
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));
118 }
119
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; \
125 }
126
127 /* A device method. */
128 /* #### The -1 check is such a hack. */
129 static void
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,
135 int new_slider_size,
136 int new_slider_position,
137 int new_scrollbar_width,
138 int new_scrollbar_height,
139 int new_scrollbar_x, int new_scrollbar_y)
140 {
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);
151
152 if (w && !vertical_drag_in_progress)
153 {
154 int new_vov = SCROLLBAR_GTK_POS_DATA (inst).slider_position;
155 int new_vows = marker_position (w->start[CURRENT_DISP]);
156
157 if (SCROLLBAR_GTK_VDRAG_ORIG_VALUE (inst) != new_vov)
158 {
159 SCROLLBAR_GTK_VDRAG_ORIG_VALUE (inst) = new_vov;
160 inst->scrollbar_instance_changed = 1;
161 }
162 if (SCROLLBAR_GTK_VDRAG_ORIG_WINDOW_START (inst) != new_vows)
163 {
164 SCROLLBAR_GTK_VDRAG_ORIG_WINDOW_START (inst) = new_vows;
165 inst->scrollbar_instance_changed = 1;
166 }
167 }
168 }
169
170 /* Used by gtk_update_scrollbar_instance_status. */
171 static void
172 update_one_widget_scrollbar_pointer (struct window *w, GtkWidget *wid)
173 {
174 if (!wid->window)
175 gtk_widget_realize (wid);
176
177 if (POINTER_IMAGE_INSTANCEP (w->scrollbar_pointer))
178 {
179 gdk_window_set_cursor (GET_GTK_WIDGET_WINDOW (wid),
180 XIMAGE_INSTANCE_GTK_CURSOR (w->scrollbar_pointer));
181 gdk_flush ();
182 }
183 }
184
185 /* A device method. */
186 static void
187 gtk_update_scrollbar_instance_status (struct window *w, int active, int size,
188 struct scrollbar_instance *instance)
189 {
190 struct frame *f = XFRAME (w->frame);
191 GtkWidget *wid = SCROLLBAR_GTK_WIDGET (instance);
192 gboolean managed = GTK_WIDGET_MAPPED (wid);
193
194 if (active && size)
195 {
196 if (instance->scrollbar_instance_changed)
197 {
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);
201 int modified_p = 0;
202
203 /* We do not want to update the size all the time if we can
204 help it. This cuts down on annoying flicker.
205 */
206 if ((wid->allocation.width != pos_data->scrollbar_width) ||
207 (wid->allocation.height != pos_data->scrollbar_height))
208 {
209 gtk_widget_set_usize (wid,
210 pos_data->scrollbar_width,
211 pos_data->scrollbar_height);
212 modified_p = 1;
213 }
214
215 /* Ditto for the x/y position. */
216 if ((wid->allocation.x != pos_data->scrollbar_x) ||
217 (wid->allocation.y != pos_data->scrollbar_y))
218 {
219 gtk_fixed_move (GTK_FIXED (FRAME_GTK_TEXT_WIDGET (f)),
220 wid,
221 pos_data->scrollbar_x,
222 pos_data->scrollbar_y);
223 modified_p = 1;
224 }
225
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;
232
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.
237 */
238 if (!modified_p)
239 gtk_range_slider_update (GTK_RANGE (wid));
240
241 instance->scrollbar_instance_changed = 0;
242 }
243
244 if (!managed)
245 {
246 gtk_widget_show (wid);
247 update_one_widget_scrollbar_pointer (w, wid);
248 }
249 }
250 else if (managed)
251 {
252 gtk_widget_hide (wid);
253 }
254 }
255
256 enum gtk_scrollbar_loop
257 {
258 GTK_FIND_SCROLLBAR_WINDOW_MIRROR,
259 GTK_SET_SCROLLBAR_POINTER,
260 GTK_WINDOW_IS_SCROLLBAR,
261 GTK_UPDATE_FRAME_SCROLLBARS
262 };
263
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)
268 {
269 struct window_mirror *retval = NULL;
270
271 while (mir)
272 {
273 struct scrollbar_instance *vinstance = mir->scrollbar_vertical_instance;
274 struct scrollbar_instance *hinstance = mir->scrollbar_horizontal_instance;
275 struct window *w = XWINDOW (window);
276
277 if (mir->vchild)
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);
281 if (retval)
282 return retval;
283
284 if (hinstance || vinstance)
285 {
286 switch (type)
287 {
288 case GTK_FIND_SCROLLBAR_WINDOW_MIRROR:
289 if ((vinstance && SCROLLBAR_GTK_ID (vinstance) == id) ||
290 (hinstance && SCROLLBAR_GTK_ID (hinstance) == id))
291 return mir;
292 break;
293 case GTK_UPDATE_FRAME_SCROLLBARS:
294 if (!mir->vchild && !mir->hchild)
295 update_window_scrollbars (w, mir, 1, 0);
296 break;
297 case GTK_SET_SCROLLBAR_POINTER:
298 if (!mir->vchild && !mir->hchild)
299 {
300 GtkWidget *widget;
301
302 widget = SCROLLBAR_GTK_WIDGET (hinstance);
303 if (widget && GTK_WIDGET_MAPPED (widget))
304 update_one_widget_scrollbar_pointer (w, widget);
305
306 widget = SCROLLBAR_GTK_WIDGET (vinstance);
307 if (widget && GTK_WIDGET_MAPPED (widget))
308 update_one_widget_scrollbar_pointer (w, widget);
309 }
310 break;
311 case GTK_WINDOW_IS_SCROLLBAR:
312 if (!mir->vchild && !mir->hchild)
313 {
314 GtkWidget *widget;
315
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;
320
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;
325 }
326 break;
327 default:
328 abort ();
329 }
330 }
331
332 mir = mir->next;
333 window = w->next;
334 }
335
336 return NULL;
337 }
338
339 /* Used by callbacks. */
340 static struct window_mirror *
341 find_scrollbar_window_mirror (struct frame *f, GUI_ID id)
342 {
343 if (f->mirror_dirty)
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);
347 }
348
349 static gboolean
350 scrollbar_cb (GtkAdjustment *adj, gpointer user_data)
351 {
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;
361
362 if (!f)
363 return(FALSE);
364
365 mirror = find_scrollbar_window_mirror (f, id);
366 if (!mirror)
367 return(FALSE);
368
369 win = real_window (mirror, 1);
370
371 if (NILP (win))
372 return(FALSE);
373 instance = vertical ? mirror->scrollbar_vertical_instance : mirror->scrollbar_horizontal_instance;
374 frame = WINDOW_FRAME (XWINDOW (win));
375
376 inhibit_slider_size_change = 0;
377 switch (GTK_RANGE (SCROLLBAR_GTK_WIDGET (instance))->scroll_type)
378 {
379 case GTK_SCROLL_PAGE_BACKWARD:
380 event_type = vertical ? Qscrollbar_page_up : Qscrollbar_page_left;
381 event_data = Fcons (win, Qnil);
382 break;
383 case GTK_SCROLL_PAGE_FORWARD:
384 event_type = vertical ? Qscrollbar_page_down : Qscrollbar_page_right;
385 event_data = Fcons (win, Qnil);
386 break;
387 case GTK_SCROLL_STEP_FORWARD:
388 event_type = vertical ? Qscrollbar_line_down : Qscrollbar_char_right;
389 event_data = win;
390 break;
391 case GTK_SCROLL_STEP_BACKWARD:
392 event_type = vertical ? Qscrollbar_line_up : Qscrollbar_char_left;
393 event_data = win;
394 break;
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));
400 break;
401 default:
402 abort();
403 }
404
405 signal_special_gtk_user_event (frame, event_type, event_data);
406
407 return (TRUE);
408 }
409
410 static void
411 gtk_scrollbar_pointer_changed_in_window (struct window *w)
412 {
413 Lisp_Object window;
414
415 XSETWINDOW (window, w);
416 gtk_scrollbar_loop (GTK_SET_SCROLLBAR_POINTER, window, find_window_mirror (w),
417 0, (GdkWindow *) NULL);
418 }
419
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*/
423 void
424 gtk_update_frame_scrollbars (struct frame *f)
425 {
426 /* Consider this code to be "in_display" so that we abort() if Fsignal()
427 gets called. */
428 in_display++;
429 gtk_scrollbar_loop (GTK_UPDATE_FRAME_SCROLLBARS, f->root_window, f->root_mirror,
430 0, (GdkWindow *) NULL);
431 in_display--;
432 if (in_display < 0) abort ();
433 }
434
435 #ifdef MEMORY_USAGE_STATS
436 static int
437 gtk_compute_scrollbar_instance_usage (struct device *d,
438 struct scrollbar_instance *inst,
439 struct overhead_stats *ovstats)
440 {
441 int total = 0;
442
443 while (inst)
444 {
445 struct gtk_scrollbar_data *data =
446 (struct gtk_scrollbar_data *) inst->scrollbar_data;
447
448 total += malloced_storage_size (data, sizeof (*data), ovstats);
449 inst = inst->next;
450 }
451
452 return total;
453 }
454
455 #endif /* MEMORY_USAGE_STATS */
456
457
458 /************************************************************************/
459 /* initialization */
460 /************************************************************************/
461
462 void
463 console_type_create_scrollbar_gtk (void)
464 {
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 */
475 }
476
477 void
478 vars_of_scrollbar_gtk (void)
479 {
480 Fprovide (intern ("gtk-scrollbars"));
481 }