comparison src/scrollbar-x.c @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children 0293115a14e9
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
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
26 #include <config.h>
27 #include "lisp.h"
28
29 #include "console-x.h"
30 #include "glyphs-x.h"
31 #include "EmacsFrame.h"
32 #include "EmacsManager.h"
33 #include "gui-x.h"
34 #include "scrollbar-x.h"
35
36 #include "frame.h"
37 #include "window.h"
38
39 static void x_update_vertical_scrollbar_callback (Widget widget, LWLIB_ID id,
40 XtPointer client_data);
41 static void x_update_horizontal_scrollbar_callback (Widget widget, LWLIB_ID id,
42 XtPointer client_data);
43
44 /* Used to prevent changing the size of the thumb while drag
45 scrolling, under Motif. This is necessary because the Motif
46 scrollbar is incredibly stupid about updating the thumb and causes
47 lots of flicker if it is done too often. */
48 static int inhibit_thumb_size_change;
49
50 #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID)
51 static int vertical_drag_in_progress;
52 #endif
53
54
55 /* A device method. */
56 static int
57 x_inhibit_scrollbar_thumb_size_change (void)
58 {
59 #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID)
60 return inhibit_thumb_size_change;
61 #else
62 return 0;
63 #endif
64 }
65
66 /* A device method. */
67 static void
68 x_free_scrollbar_instance (struct scrollbar_instance *instance)
69 {
70 if (SCROLLBAR_X_NAME (instance))
71 xfree (SCROLLBAR_X_NAME (instance));
72
73 if (SCROLLBAR_X_WIDGET (instance))
74 {
75 if (XtIsManaged (SCROLLBAR_X_WIDGET (instance)))
76 XtUnmanageChild (SCROLLBAR_X_WIDGET (instance));
77
78 lw_destroy_all_widgets (SCROLLBAR_X_ID (instance));
79 }
80
81 if (instance->scrollbar_data)
82 xfree (instance->scrollbar_data);
83 }
84
85 /* A device method. */
86 static void
87 x_release_scrollbar_instance (struct scrollbar_instance *instance)
88 {
89 if (XtIsManaged (SCROLLBAR_X_WIDGET (instance)))
90 XtUnmanageChild (SCROLLBAR_X_WIDGET (instance));
91 }
92
93 /* A device method. */
94 static void
95 x_create_scrollbar_instance (struct frame *f, int vertical,
96 struct scrollbar_instance *instance)
97 {
98 char buffer[32];
99
100 /* initialize the X specific data section. */
101 instance->scrollbar_data = malloc_type_and_zero (struct x_scrollbar_data);
102
103 SCROLLBAR_X_ID (instance) = new_lwlib_id ();
104 sprintf (buffer, "scrollbar_%d", SCROLLBAR_X_ID (instance));
105 SCROLLBAR_X_NAME (instance) = xstrdup (buffer);
106 #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID)
107 SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) = -1;
108 #endif
109
110 if (vertical)
111 {
112 SCROLLBAR_X_WIDGET (instance) =
113 lw_create_widget ("vertical-scrollbar", SCROLLBAR_X_NAME (instance),
114 SCROLLBAR_X_ID (instance),
115 NULL, FRAME_X_CONTAINER_WIDGET (f), 0,
116 x_update_vertical_scrollbar_callback, NULL, NULL);
117 }
118 else
119 {
120 SCROLLBAR_X_WIDGET (instance) =
121 lw_create_widget ("horizontal-scrollbar", SCROLLBAR_X_NAME (instance),
122 SCROLLBAR_X_ID (instance),
123 NULL, FRAME_X_CONTAINER_WIDGET (f), 0,
124 x_update_horizontal_scrollbar_callback, NULL, NULL);
125 }
126 }
127
128 #define UPDATE_DATA_FIELD(field) \
129 if (new_##field >= 0 && \
130 SCROLLBAR_X_POS_DATA (inst).field != new_##field) { \
131 SCROLLBAR_X_POS_DATA (inst).field = new_##field; \
132 inst->scrollbar_instance_changed = 1; \
133 }
134
135 /* A device method. */
136 /* #### The -1 check is such a hack. */
137 static void
138 x_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,
143 int new_slider_size,
144 int new_slider_position,
145 int new_scrollbar_width,
146 int new_scrollbar_height,
147 int new_scrollbar_x, int new_scrollbar_y)
148 {
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);
159
160 #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID)
161 if (w && !vertical_drag_in_progress)
162 {
163 int new_vov = SCROLLBAR_X_POS_DATA (inst).slider_position;
164 int new_vows = marker_position (w->start[CURRENT_DISP]);
165
166 if (SCROLLBAR_X_VDRAG_ORIG_VALUE (inst) != new_vov)
167 {
168 SCROLLBAR_X_VDRAG_ORIG_VALUE (inst) = new_vov;
169 inst->scrollbar_instance_changed = 1;
170 }
171 if (SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (inst) != new_vows)
172 {
173 SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (inst) = new_vows;
174 inst->scrollbar_instance_changed = 1;
175 }
176 }
177 #endif
178 }
179
180 /* Used by x_update_scrollbar_instance_status. */
181 static void
182 update_one_scrollbar_bs (struct frame *f, Widget sb_widget)
183 {
184 Boolean use_backing_store;
185
186 XtVaGetValues (FRAME_X_TEXT_WIDGET (f),
187 XtNuseBackingStore, &use_backing_store, 0);
188
189 if (use_backing_store && sb_widget)
190 {
191 unsigned long mask = CWBackingStore;
192 XSetWindowAttributes attrs;
193
194 attrs.backing_store = Always;
195 XChangeWindowAttributes (XtDisplay (sb_widget),
196 XtWindow (sb_widget),
197 mask,
198 &attrs);
199 }
200 }
201
202 /* Create a widget value structure for passing down to lwlib so that
203 it can update the scrollbar widgets. Used by
204 x_update_scrollbar_instance_status. */
205 static widget_value *
206 scrollbar_instance_to_widget_value (struct scrollbar_instance *instance)
207 {
208 widget_value *wv;
209
210 wv = xmalloc_widget_value ();
211 /* #### maybe should add malloc_scrollbar_values to resource these? */
212 wv->scrollbar_data = (scrollbar_values *)
213 xmalloc (sizeof (scrollbar_values));
214
215 wv->name = SCROLLBAR_X_NAME (instance);
216 wv->value = 0;
217 wv->key = 0;
218 wv->enabled = instance->scrollbar_is_active;
219 wv->selected = 0;
220 wv->call_data = NULL;
221
222 *wv->scrollbar_data = SCROLLBAR_X_POS_DATA (instance);
223
224 wv->next = NULL;
225
226 return wv;
227 }
228
229 /* Used by x_update_scrollbar_instance_status. */
230 static void
231 update_one_widget_scrollbar_pointer (struct window *w, Widget wid)
232 {
233 if (POINTER_IMAGE_INSTANCEP (w->scrollbar_pointer))
234 {
235 XDefineCursor (XtDisplay (wid), XtWindow (wid),
236 XIMAGE_INSTANCE_X_CURSOR (w->scrollbar_pointer));
237 XSync (XtDisplay (wid), False);
238 }
239 }
240
241 /* A device method. */
242 static void
243 x_update_scrollbar_instance_status (struct window *w, int active, int size,
244 struct scrollbar_instance *instance)
245 {
246 struct frame *f = XFRAME (w->frame);
247 char managed = XtIsManaged (SCROLLBAR_X_WIDGET (instance));
248
249 if (active && size)
250 {
251 widget_value *wv = scrollbar_instance_to_widget_value (instance);
252
253 if (instance->scrollbar_instance_changed)
254 {
255 lw_modify_all_widgets (SCROLLBAR_X_ID (instance), wv, 0);
256 instance->scrollbar_instance_changed = 0;
257 }
258
259 if (!managed)
260 {
261 XtManageChild (SCROLLBAR_X_WIDGET (instance));
262 if (XtWindow (SCROLLBAR_X_WIDGET (instance)))
263 {
264 /* Raise this window so that it's visible on top of the
265 text window below it. */
266 XRaiseWindow (XtDisplay (SCROLLBAR_X_WIDGET (instance)),
267 XtWindow (SCROLLBAR_X_WIDGET (instance)));
268 update_one_widget_scrollbar_pointer
269 (w, SCROLLBAR_X_WIDGET (instance));
270 if (!SCROLLBAR_X_BACKING_STORE_INITIALIZED (instance))
271 {
272 update_one_scrollbar_bs (f, SCROLLBAR_X_WIDGET (instance));
273 SCROLLBAR_X_BACKING_STORE_INITIALIZED (instance) = 1;
274 }
275 }
276 }
277
278 if (!wv->scrollbar_data) abort ();
279 xfree (wv->scrollbar_data);
280 wv->scrollbar_data = 0;
281 free_widget_value (wv);
282 }
283 else if (managed)
284 {
285 XtUnmanageChild (SCROLLBAR_X_WIDGET (instance));
286 }
287 }
288
289 /* A device method. */
290 static void
291 x_scrollbar_width_changed_in_frame (Lisp_Object specifier, struct frame *f,
292 Lisp_Object oldval)
293 {
294 XtWidgetGeometry req, repl;
295 Lisp_Object newval = f->scrollbar_width;
296
297 in_specifier_change_function++;
298
299 /* We want the text area to stay the same size. So, we query the
300 current size and then adjust it for the change in the scrollbar
301 width. */
302
303 /* mirror the value in the frame resources, unless it was already
304 done. */
305 if (!in_resource_setting)
306 XtVaSetValues (FRAME_X_TEXT_WIDGET (f), XtNscrollBarWidth,
307 XINT (newval), 0);
308
309 if (XtIsRealized (FRAME_X_CONTAINER_WIDGET (f)))
310 {
311 req.request_mode = 0;
312
313 /* the query-geometry method looks at the current value of
314 f->scrollbar_width, so temporarily set it back to the old
315 one. */
316 f->scrollbar_width = oldval;
317 XtQueryGeometry (FRAME_X_CONTAINER_WIDGET (f), &req, &repl);
318 f->scrollbar_width = newval;
319
320 repl.width += XINT (newval) - XINT (oldval);
321 EmacsManagerChangeSize (FRAME_X_CONTAINER_WIDGET (f), repl.width,
322 repl.height);
323 }
324
325 in_specifier_change_function--;
326 }
327
328 /* A device method. */
329 static void
330 x_scrollbar_height_changed_in_frame (Lisp_Object specifier, struct frame *f,
331 Lisp_Object oldval)
332 {
333 XtWidgetGeometry req, repl;
334 Lisp_Object newval = f->scrollbar_height;
335
336 in_specifier_change_function++;
337
338 /* We want the text area to stay the same size. So, we query the
339 current size and then adjust it for the change in the scrollbar
340 height. */
341
342 /* mirror the value in the frame resources, unless it was already
343 done. Also don't do it if this is the when the frame is being
344 created -- the widgets don't even exist yet, and even if they
345 did, we wouldn't want to overwrite the resource information
346 (which might specify a user preference). */
347 if (!in_resource_setting)
348 XtVaSetValues (FRAME_X_TEXT_WIDGET (f), XtNscrollBarHeight,
349 XINT (newval), 0);
350
351 if (XtIsRealized (FRAME_X_CONTAINER_WIDGET (f)))
352 {
353 req.request_mode = 0;
354
355 /* the query-geometry method looks at the current value of
356 f->scrollbar_height, so temporarily set it back to the old
357 one. */
358 f->scrollbar_height = oldval;
359 XtQueryGeometry (FRAME_X_CONTAINER_WIDGET (f), &req, &repl);
360 f->scrollbar_height = newval;
361
362 repl.height += XINT (newval) - XINT (oldval);
363 EmacsManagerChangeSize (FRAME_X_CONTAINER_WIDGET (f), repl.width,
364 repl.height);
365 }
366
367 in_specifier_change_function--;
368 }
369
370 enum x_scrollbar_loop
371 {
372 X_FIND_SCROLLBAR_WINDOW_MIRROR,
373 X_SET_SCROLLBAR_POINTER,
374 X_WINDOW_IS_SCROLLBAR,
375 X_UPDATE_FRAME_SCROLLBARS
376 };
377
378 static struct window_mirror *
379 x_scrollbar_loop (enum x_scrollbar_loop type, Lisp_Object window,
380 struct window_mirror *mir,
381 LWLIB_ID id, Window x_win)
382 {
383 struct window_mirror *retval = NULL;
384
385 while (mir)
386 {
387 struct scrollbar_instance *vinstance = mir->scrollbar_vertical_instance;
388 struct scrollbar_instance *hinstance =
389 mir->scrollbar_horizontal_instance;
390 struct frame *f;
391
392 assert (!NILP (window));
393 f = XFRAME (XWINDOW (window)->frame);
394
395 if (mir->vchild)
396 {
397 retval = x_scrollbar_loop (type, XWINDOW (window)->vchild,
398 mir->vchild, id, x_win);
399 }
400 else if (mir->hchild)
401 {
402 retval = x_scrollbar_loop (type, XWINDOW (window)->hchild,
403 mir->hchild, id, x_win);
404 }
405
406 if (retval != NULL)
407 return retval;
408
409 if (hinstance || vinstance)
410 {
411 switch (type)
412 {
413 case X_FIND_SCROLLBAR_WINDOW_MIRROR:
414 if ((vinstance && SCROLLBAR_X_ID (vinstance) == id)
415 || (hinstance && SCROLLBAR_X_ID (hinstance) == id))
416 {
417 return mir;
418 }
419 break;
420 case X_UPDATE_FRAME_SCROLLBARS:
421 if (!mir->vchild && !mir->hchild)
422 update_window_scrollbars (XWINDOW (window), mir, 1, 0);
423 break;
424 case X_SET_SCROLLBAR_POINTER:
425 if (!mir->vchild && !mir->hchild)
426 {
427 int loop;
428
429 for (loop = 0; loop < 2; loop++)
430 {
431 Widget widget;
432
433 if (loop)
434 widget = SCROLLBAR_X_WIDGET (vinstance);
435 else
436 widget = SCROLLBAR_X_WIDGET (hinstance);
437
438 if (widget && XtIsManaged (widget))
439 {
440 update_one_widget_scrollbar_pointer
441 (XWINDOW (window), widget);
442 }
443 }
444 }
445 break;
446 case X_WINDOW_IS_SCROLLBAR:
447 if (!mir->vchild && !mir->hchild)
448 {
449 int loop;
450
451 for (loop = 0; loop < 2; loop++)
452 {
453 Widget widget;
454
455 if (loop)
456 widget = SCROLLBAR_X_WIDGET (vinstance);
457 else
458 widget = SCROLLBAR_X_WIDGET (hinstance);
459
460 if (widget && XtIsManaged (widget))
461 {
462 if (XtWindow (widget) == x_win)
463 return (struct window_mirror *) 1;
464 }
465 }
466 }
467 break;
468 default:
469 abort ();
470 }
471 }
472
473 mir = mir->next;
474 window = XWINDOW (window)->next;
475 }
476
477 return NULL;
478 }
479
480 /* Used by callbacks. */
481 static struct window_mirror *
482 find_scrollbar_window_mirror (struct frame *f, LWLIB_ID id)
483 {
484 if (f->mirror_dirty)
485 update_frame_window_mirror (f);
486 return x_scrollbar_loop (X_FIND_SCROLLBAR_WINDOW_MIRROR, f->root_window,
487 f->root_mirror, id, (Window) NULL);
488 }
489
490 /*
491 * This is the only callback provided for vertical scrollbars. It
492 * should be able to handle all of the scrollbar events in
493 * scroll_action (see lwlib.h). The client data will be of type
494 * scroll_event (see lwlib.h). */
495 static void
496 x_update_vertical_scrollbar_callback (Widget widget, LWLIB_ID id,
497 XtPointer client_data)
498 {
499 /* This function can GC */
500 scroll_event *data = (scroll_event *) client_data;
501 struct device *d = get_device_from_display (XtDisplay (widget));
502 struct frame *f = x_any_window_to_frame (d, XtWindow (widget));
503 Lisp_Object win;
504 struct scrollbar_instance *instance;
505 struct window_mirror *mirror;
506
507 if (!f)
508 return;
509
510 mirror = find_scrollbar_window_mirror (f, id);
511 win = real_window (mirror, 1);
512
513 if (NILP (win))
514 return;
515 instance = mirror->scrollbar_vertical_instance;
516
517 /* It seems that this is necessary whenever signal_special_Xt_user_event()
518 is called. #### Why??? */
519 DEVICE_X_MOUSE_TIMESTAMP (d) = DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d);
520
521 switch (data->action)
522 {
523 case SCROLLBAR_LINE_UP:
524 signal_special_Xt_user_event (win, Qscrollbar_line_up, win);
525 break;
526
527 case SCROLLBAR_LINE_DOWN:
528 signal_special_Xt_user_event (win, Qscrollbar_line_down, win);
529 break;
530
531 /* The Athena scrollbar paging behavior is that of xterms.
532 Depending on where you click the size of the page varies.
533 Motif always does a standard Emacs page. */
534 case SCROLLBAR_PAGE_UP:
535 #if !defined (LWLIB_SCROLLBARS_MOTIF) && !defined (LWLIB_SCROLLBARS_LUCID)
536 {
537 double tmp = ((double) data->slider_value /
538 (double) SCROLLBAR_X_POS_DATA(instance).scrollbar_height);
539 double line = tmp *
540 (double) window_displayed_height (XWINDOW (win));
541
542 if (line > -1.0)
543 line = -1.0;
544 signal_special_Xt_user_event (win, Qscrollbar_page_up,
545 Fcons (win, make_int ((int) line)));
546 }
547 #else
548 signal_special_Xt_user_event (win, Qscrollbar_page_up,
549 Fcons (win, Qnil));
550 #endif
551 break;
552
553 case SCROLLBAR_PAGE_DOWN:
554 #if !defined (LWLIB_SCROLLBARS_MOTIF) && !defined (LWLIB_SCROLLBARS_LUCID)
555 {
556 double tmp = ((double) data->slider_value /
557 (double) SCROLLBAR_X_POS_DATA(instance).scrollbar_height);
558 double line = tmp *
559 (double) window_displayed_height (XWINDOW (win));
560
561 if (SCROLLBAR_X_POS_DATA(instance).maximum >
562 (SCROLLBAR_X_POS_DATA(instance).slider_size + SCROLLBAR_X_POS_DATA(instance).slider_position))
563 {
564 if (line < 1.0)
565 line = 1.0;
566 signal_special_Xt_user_event (win, Qscrollbar_page_down,
567 Fcons (win,
568 make_int ((int) line)));
569 }
570 }
571 #else
572 signal_special_Xt_user_event (win, Qscrollbar_page_down,
573 Fcons (win, Qnil));
574 #endif
575 break;
576
577 case SCROLLBAR_TOP:
578 signal_special_Xt_user_event (win, Qscrollbar_to_top, win);
579 break;
580
581 case SCROLLBAR_BOTTOM:
582 signal_special_Xt_user_event (win, Qscrollbar_to_bottom, win);
583 break;
584
585
586 case SCROLLBAR_CHANGE:
587 inhibit_thumb_size_change = 0;
588 #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID)
589 vertical_drag_in_progress = 0;
590 SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) = data->slider_value;
591 SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance) =
592 XINT (Fwindow_start (win));
593 #endif
594 break;
595
596 case SCROLLBAR_DRAG:
597 {
598 int value;
599
600 inhibit_thumb_size_change = 1;
601
602 #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID)
603 /* Doing drags with Motif-like scrollbars is a mess, since we
604 want to avoid having the window position jump when you
605 first grab the scrollbar, but we also want to ensure that
606 you can scroll all the way to the top or bottom of the
607 buffer. This can all be replaced with something sane when
608 we get line-based scrolling. */
609
610 vertical_drag_in_progress = 1;
611
612 if (SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) < 0)
613 {
614 SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) = data->slider_value;
615 SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance) =
616 XINT (Fwindow_start (win));
617 }
618
619 /* Could replace this piecewise linear scrolling with a
620 quadratic through the three points, but I'm not sure that
621 would feel any nicer in practice. */
622 if (data->slider_value < SCROLLBAR_X_VDRAG_ORIG_VALUE (instance))
623 {
624 /* We've dragged up; slide linearly from original position to
625 window-start=data.minimum, slider-value=data.minimum. */
626
627 if (SCROLLBAR_X_VDRAG_ORIG_VALUE (instance)
628 <= SCROLLBAR_X_POS_DATA (instance).minimum)
629 {
630 /* shouldn't get here, but just in case */
631 value = SCROLLBAR_X_POS_DATA (instance).minimum;
632 }
633 else
634 {
635 value = (SCROLLBAR_X_POS_DATA (instance).minimum
636 + (((double)
637 (SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance)
638 - SCROLLBAR_X_POS_DATA (instance).minimum)
639 * (data->slider_value -
640 SCROLLBAR_X_POS_DATA (instance).minimum))
641 / (SCROLLBAR_X_VDRAG_ORIG_VALUE (instance)
642 - SCROLLBAR_X_POS_DATA (instance).minimum)));
643 }
644 }
645 else
646 {
647 /* We've dragged down; slide linearly from original position to
648 window-start=data.maximum, slider-value=data.maximum. */
649
650 if (SCROLLBAR_X_VDRAG_ORIG_VALUE (instance)
651 >= (SCROLLBAR_X_POS_DATA (instance).maximum -
652 SCROLLBAR_X_POS_DATA (instance).slider_size))
653 {
654 /* avoid divide by zero */
655 value = SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance);
656 }
657 else
658 {
659 value = (SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance)
660 + (((double) (SCROLLBAR_X_POS_DATA (instance).maximum
661 - SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance))
662 * (data->slider_value
663 - SCROLLBAR_X_VDRAG_ORIG_VALUE (instance)))
664 / (SCROLLBAR_X_POS_DATA (instance).maximum
665 - SCROLLBAR_X_POS_DATA (instance).slider_size
666 - SCROLLBAR_X_VDRAG_ORIG_VALUE (instance))));
667 }
668 }
669 #else
670 value = data->slider_value;
671 #endif
672
673 if (value >= SCROLLBAR_X_POS_DATA (instance).maximum)
674 value = SCROLLBAR_X_POS_DATA (instance).maximum - 1;
675 if (value < SCROLLBAR_X_POS_DATA (instance).minimum)
676 value = SCROLLBAR_X_POS_DATA (instance).minimum;
677
678 signal_special_Xt_user_event (win, Qscrollbar_vertical_drag,
679 Fcons (win, make_int (value)));
680 }
681 break;
682
683 }
684 }
685
686 /*
687 * This is the only callback provided for horizontal scrollbars. It
688 * should be able to handle all of the scrollbar events in
689 * scroll_action (see lwlib.h). The client data will be of type
690 * scroll_event (see lwlib.h). */
691 static void
692 x_update_horizontal_scrollbar_callback (Widget widget, LWLIB_ID id,
693 XtPointer client_data)
694 {
695 scroll_event *data = (scroll_event *) client_data;
696 struct device *d = get_device_from_display (XtDisplay (widget));
697 struct frame *f = x_any_window_to_frame (d, XtWindow (widget));
698 Lisp_Object win;
699 struct window_mirror *mirror;
700
701 if (!f)
702 return;
703
704 mirror = find_scrollbar_window_mirror (f, id);
705 win = real_window (mirror, 1);
706
707 if (NILP (win))
708 return;
709
710 /* It seems that this is necessary whenever signal_special_Xt_user_event()
711 is called. #### Why??? */
712 DEVICE_X_MOUSE_TIMESTAMP (d) = DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d);
713
714 switch (data->action)
715 {
716 case SCROLLBAR_LINE_UP:
717 signal_special_Xt_user_event (win, Qscrollbar_char_left, win);
718 break;
719 case SCROLLBAR_LINE_DOWN:
720 signal_special_Xt_user_event (win, Qscrollbar_char_right, win);
721 break;
722 case SCROLLBAR_PAGE_UP:
723 signal_special_Xt_user_event (win, Qscrollbar_page_left, win);
724 break;
725 case SCROLLBAR_PAGE_DOWN:
726 signal_special_Xt_user_event (win, Qscrollbar_page_right, win);
727 break;
728 case SCROLLBAR_TOP:
729 signal_special_Xt_user_event (win, Qscrollbar_to_left, win);
730 break;
731 case SCROLLBAR_BOTTOM:
732 signal_special_Xt_user_event (win, Qscrollbar_to_right, win);
733 break;
734 case SCROLLBAR_CHANGE:
735 inhibit_thumb_size_change = 0;
736 break;
737 case SCROLLBAR_DRAG:
738 inhibit_thumb_size_change = 1;
739 /* #### Fix the damn toolkit code so they all work the same way.
740 Lucid is the one mostly wrong.*/
741 #if defined (LWLIB_SCROLLBARS_LUCID)
742 signal_special_Xt_user_event (win, Qscrollbar_horizontal_drag,
743 (Fcons
744 (win, make_int (data->slider_value))));
745 #else
746 signal_special_Xt_user_event (win, Qscrollbar_horizontal_drag,
747 (Fcons
748 (win,
749 make_int (data->slider_value - 1))));
750 #endif
751 break;
752 default:
753 break;
754 }
755 }
756
757 static void
758 x_scrollbar_pointer_changed_in_window (struct window *w)
759 {
760 Lisp_Object window = Qnil;
761
762 XSETWINDOW (window, w);
763 x_scrollbar_loop (X_SET_SCROLLBAR_POINTER, window, find_window_mirror (w),
764 0, (Window) NULL);
765 }
766
767 /* Called directly from x_any_window_to_frame in frame-x.c */
768 EMACS_INT
769 x_window_is_scrollbar (struct frame *f, Window win)
770 {
771 if (!FRAME_X_P (f))
772 return 0;
773
774 if (f->mirror_dirty)
775 update_frame_window_mirror (f);
776 return (EMACS_INT) x_scrollbar_loop (X_WINDOW_IS_SCROLLBAR, f->root_window,
777 f->root_mirror, 0, win);
778 }
779
780 /* Make sure that all scrollbars on frame are up-to-date. Called
781 directly from x_set_frame_properties in frame-x.c*/
782 void
783 x_update_frame_scrollbars (struct frame *f)
784 {
785 /* Consider this code to be "in_display" so that we abort() if Fsignal()
786 gets called. */
787 in_display++;
788 x_scrollbar_loop (X_UPDATE_FRAME_SCROLLBARS, f->root_window, f->root_mirror,
789 0, (Window) NULL);
790 in_display--;
791 if (in_display < 0) abort ();
792 }
793
794 #ifdef MEMORY_USAGE_STATS
795
796 static int
797 x_compute_scrollbar_instance_usage (struct device *d,
798 struct scrollbar_instance *inst,
799 struct overhead_stats *ovstats)
800 {
801 int total = 0;
802
803 while (inst)
804 {
805 struct x_scrollbar_data *data =
806 (struct x_scrollbar_data *) inst->scrollbar_data;
807
808 total += malloced_storage_size (data, sizeof (*data), ovstats);
809 total += malloced_storage_size (data->name, 1 + strlen (data->name),
810 ovstats);
811 inst = inst->next;
812 }
813
814 return total;
815 }
816
817 #endif /* MEMORY_USAGE_STATS */
818
819
820 /************************************************************************/
821 /* initialization */
822 /************************************************************************/
823
824 void
825 console_type_create_scrollbar_x (void)
826 {
827 CONSOLE_HAS_METHOD (x, inhibit_scrollbar_thumb_size_change);
828 CONSOLE_HAS_METHOD (x, free_scrollbar_instance);
829 CONSOLE_HAS_METHOD (x, release_scrollbar_instance);
830 CONSOLE_HAS_METHOD (x, create_scrollbar_instance);
831 CONSOLE_HAS_METHOD (x, update_scrollbar_instance_values);
832 CONSOLE_HAS_METHOD (x, update_scrollbar_instance_status);
833 CONSOLE_HAS_METHOD (x, scrollbar_width_changed_in_frame);
834 CONSOLE_HAS_METHOD (x, scrollbar_height_changed_in_frame);
835 CONSOLE_HAS_METHOD (x, scrollbar_pointer_changed_in_window);
836 #ifdef MEMORY_USAGE_STATS
837 CONSOLE_HAS_METHOD (x, compute_scrollbar_instance_usage);
838 #endif /* MEMORY_USAGE_STATS */
839 }
840
841 void
842 vars_of_scrollbar_x (void)
843 {
844 #if defined (LWLIB_SCROLLBARS_LUCID)
845 Fprovide (intern ("lucid-scrollbars"));
846 #elif defined (LWLIB_SCROLLBARS_MOTIF)
847 Fprovide (intern ("motif-scrollbars"));
848 #elif defined (LWLIB_SCROLLBARS_ATHENA)
849 Fprovide (intern ("athena-scrollbars"));
850 #endif
851 }