comparison src/scrollbar-x.c @ 428:3ecd8885ac67 r21-2-22

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