1 /* Generic scrollbar implementation.
2 Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3 Copyright (C) 1995 Free Software Foundation, Inc.
4 Copyright (C) 1995 Sun Microsystems, Inc.
5 Copyright (C) 1995 Darrell Kindred <dkindred+@cmu.edu>.
7 This file is part of SXEmacs
9 SXEmacs is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 SXEmacs is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
23 /* Synched up with: Not in FSF. */
25 /* This file has been Mule-ized. */
32 #include "scrollbar.h"
39 Lisp_Object Qinit_scrollbar_from_resources;
41 Lisp_Object Qscrollbar_line_up;
42 Lisp_Object Qscrollbar_line_down;
43 Lisp_Object Qscrollbar_page_up;
44 Lisp_Object Qscrollbar_page_down;
45 Lisp_Object Qscrollbar_to_top;
46 Lisp_Object Qscrollbar_to_bottom;
47 Lisp_Object Qscrollbar_vertical_drag;
49 Lisp_Object Qscrollbar_char_left;
50 Lisp_Object Qscrollbar_char_right;
51 Lisp_Object Qscrollbar_page_left;
52 Lisp_Object Qscrollbar_page_right;
53 Lisp_Object Qscrollbar_to_left;
54 Lisp_Object Qscrollbar_to_right;
55 Lisp_Object Qscrollbar_horizontal_drag;
57 #define DEFAULT_SCROLLBAR_WIDTH 15
58 #define DEFAULT_SCROLLBAR_HEIGHT 15
60 /* Width and height of the scrollbar. */
61 Lisp_Object Vscrollbar_width;
62 Lisp_Object Vscrollbar_height;
64 /* Scrollbar visibility specifiers */
65 Lisp_Object Vhorizontal_scrollbar_visible_p;
66 Lisp_Object Vvertical_scrollbar_visible_p;
68 /* Scrollbar location specifiers */
69 Lisp_Object Vscrollbar_on_left_p;
70 Lisp_Object Vscrollbar_on_top_p;
72 Lisp_Object Vscrollbar_pointer_glyph;
74 EXFUN(Fcenter_to_window_line, 2);
76 static void update_scrollbar_instance(struct window *w, int vertical,
77 struct scrollbar_instance *instance);
80 free_scrollbar_instance(struct scrollbar_instance *instance,
86 struct device *d = XDEVICE(frame->device);
88 MAYBE_DEVMETH(d, free_scrollbar_instance, (instance));
93 static void free_window_mirror_scrollbars(struct window_mirror *mir)
95 free_scrollbar_instance(mir->scrollbar_vertical_instance, mir->frame);
96 mir->scrollbar_vertical_instance = 0;
98 free_scrollbar_instance(mir->scrollbar_horizontal_instance, mir->frame);
99 mir->scrollbar_horizontal_instance = 0;
102 static struct window_mirror *free_scrollbars_loop(Lisp_Object window,
103 struct window_mirror *mir)
105 struct window_mirror *retval = NULL;
108 assert(!NILP(window));
111 retval = free_scrollbars_loop(XWINDOW(window)->vchild,
113 } else if (mir->hchild) {
114 retval = free_scrollbars_loop(XWINDOW(window)->hchild,
121 if (mir->scrollbar_vertical_instance ||
122 mir->scrollbar_horizontal_instance)
123 free_window_mirror_scrollbars(mir);
126 window = XWINDOW(window)->next;
132 /* Destroy all scrollbars associated with FRAME. Only called from
133 delete_frame_internal. */
134 void free_frame_scrollbars(struct frame *f)
136 if (!HAS_FRAMEMETH_P(f, create_scrollbar_instance))
140 update_frame_window_mirror(f);
142 free_scrollbars_loop(f->root_window, f->root_mirror);
144 while (FRAME_SB_VCACHE(f)) {
145 struct scrollbar_instance *tofree = FRAME_SB_VCACHE(f);
146 FRAME_SB_VCACHE(f) = FRAME_SB_VCACHE(f)->next;
148 free_scrollbar_instance(tofree, f);
151 while (FRAME_SB_HCACHE(f)) {
152 struct scrollbar_instance *tofree = FRAME_SB_HCACHE(f);
153 FRAME_SB_HCACHE(f) = FRAME_SB_HCACHE(f)->next;
155 free_scrollbar_instance(tofree, f);
159 static struct scrollbar_instance *create_scrollbar_instance(struct frame *f,
162 struct device *d = XDEVICE(f->device);
163 struct scrollbar_instance *instance =
164 xnew_and_zero(struct scrollbar_instance);
166 MAYBE_DEVMETH(d, create_scrollbar_instance, (f, vertical, instance));
171 #define GET_SCROLLBAR_INSTANCE_INTERNAL(cache) \
173 if (FRAME_SB_##cache (f)) \
175 struct scrollbar_instance *retval = FRAME_SB_##cache (f); \
176 FRAME_SB_##cache (f) = FRAME_SB_##cache (f)->next; \
177 retval->next = NULL; \
182 static struct scrollbar_instance *get_scrollbar_instance(struct frame *f,
185 /* Check if there are any available scrollbars already in existence. */
187 GET_SCROLLBAR_INSTANCE_INTERNAL(VCACHE);
189 GET_SCROLLBAR_INSTANCE_INTERNAL(HCACHE);
191 return create_scrollbar_instance(f, vertical);
194 #undef GET_SCROLLBAR_INSTANCE_INTERNAL
196 #define RELEASE_SCROLLBAR_INSTANCE_INTERNAL(cache) \
198 if (!FRAME_SB_##cache (f)) \
200 instance->next = NULL; \
201 FRAME_SB_##cache (f) = instance; \
205 instance->next = FRAME_SB_##cache (f); \
206 FRAME_SB_##cache (f) = instance; \
211 release_scrollbar_instance(struct frame *f, int vertical,
212 struct scrollbar_instance *instance)
214 /* #### should we do "instance->mir = 0;" for safety? */
216 RELEASE_SCROLLBAR_INSTANCE_INTERNAL(VCACHE);
218 RELEASE_SCROLLBAR_INSTANCE_INTERNAL(HCACHE);
221 #undef RELEASE_SCROLLBAR_INSTANCE_INTERNAL
223 #if defined MEMORY_USAGE_STATS && !(defined HAVE_BDWGC && defined EF_USE_BDWGC)
226 compute_scrollbar_instance_usage(struct device *d,
227 struct scrollbar_instance *inst,
228 struct overhead_stats *ovstats)
232 if (HAS_DEVMETH_P(d, compute_scrollbar_instance_usage))
233 total += DEVMETH (d, compute_scrollbar_instance_usage, (d, inst, ovstats));
236 total += malloced_storage_size(inst, sizeof(*inst), ovstats);
243 #endif /* MEMORY_USAGE_STATS */
246 update_window_scrollbars(struct window *w, struct window_mirror *mirror,
247 int active, int horiz_only)
249 struct frame *f = XFRAME(w->frame);
250 struct device *d = XDEVICE(f->device);
252 if (!HAS_DEVMETH_P(d, create_scrollbar_instance))
257 /* It is possible for this to get called from the mirror update
258 routines. In that case the structure is in an indeterminate
259 state but we know exactly what struct we are working with. So we
260 pass it in in that case. We also take advantage of it at some
261 other points where we know what the mirror struct is. */
263 mirror = find_window_mirror(w);
265 if (!mirror->scrollbar_vertical_instance && active)
266 mirror->scrollbar_vertical_instance =
267 get_scrollbar_instance(f, 1);
269 if (!mirror->scrollbar_horizontal_instance && active)
270 mirror->scrollbar_horizontal_instance =
271 get_scrollbar_instance(f, 0);
273 if (!horiz_only && mirror->scrollbar_vertical_instance) {
274 int size = (active ? window_scrollbar_width(w) : 0);
275 struct scrollbar_instance *instance;
277 instance = mirror->scrollbar_vertical_instance;
278 instance->scrollbar_is_active = active;
279 instance->mirror = mirror;
282 update_scrollbar_instance(w, 1, instance);
283 MAYBE_DEVMETH(d, update_scrollbar_instance_status,
284 (w, active, size, instance));
287 release_scrollbar_instance(f, 1, instance);
288 mirror->scrollbar_vertical_instance = NULL;
292 if (mirror->scrollbar_horizontal_instance) {
293 int size = (active ? window_scrollbar_height(w) : 0);
294 struct scrollbar_instance *instance;
296 instance = mirror->scrollbar_horizontal_instance;
297 instance->scrollbar_is_active = active;
298 instance->mirror = mirror;
301 update_scrollbar_instance(w, 0, instance);
302 MAYBE_DEVMETH(d, update_scrollbar_instance_status,
303 (w, active, size, instance));
306 release_scrollbar_instance(f, 0, instance);
307 mirror->scrollbar_horizontal_instance = NULL;
314 void release_window_mirror_scrollbars(struct window_mirror *mir)
316 struct device *d = XDEVICE(mir->frame->device);
318 if (!HAS_DEVMETH_P(d, create_scrollbar_instance))
321 if (mir->scrollbar_vertical_instance) {
322 release_scrollbar_instance(mir->frame, 1,
323 mir->scrollbar_vertical_instance);
324 MAYBE_DEVMETH(d, release_scrollbar_instance,
325 (mir->scrollbar_vertical_instance));
327 mir->scrollbar_vertical_instance = 0;
329 if (mir->scrollbar_horizontal_instance) {
330 release_scrollbar_instance(mir->frame, 0,
331 mir->scrollbar_horizontal_instance);
332 MAYBE_DEVMETH(d, release_scrollbar_instance,
333 (mir->scrollbar_horizontal_instance));
335 mir->scrollbar_horizontal_instance = 0;
339 * If w->sb_point is on the top line then return w->sb_point else
340 * return w->start. If flag, then return beginning point of line
341 * which w->sb_point lies on.
343 static Bufpos scrollbar_point(struct window *w, int flag)
345 Bufpos start_pos, end_pos, sb_pos;
349 if (NILP(w->buffer)) /* non-leaf window */
352 start_pos = marker_position(w->start[CURRENT_DISP]);
353 sb_pos = marker_position(w->sb_point);
355 if (!flag && sb_pos < start_pos)
358 buf = emacs_get_buffer(w->buffer, 0);
365 end_pos = find_next_newline_no_quit(b, sb_pos, -1);
367 end_pos = find_next_newline_no_quit(b, start_pos, 1);
371 else if (sb_pos > end_pos)
378 * Update a window's horizontal or vertical scrollbar.
381 update_scrollbar_instance(struct window *w, int vertical,
382 struct scrollbar_instance *instance)
384 struct frame *f = XFRAME(w->frame);
385 struct device *d = XDEVICE(f->device);
386 struct buffer *b = XBUFFER(w->buffer);
387 Bufpos start_pos, end_pos, sb_pos;
388 int scrollbar_width = window_scrollbar_width(w);
389 int scrollbar_height = window_scrollbar_height(w);
391 int new_line_increment = -1, new_page_increment = -1;
392 int new_minimum = -1, new_maximum = -1;
393 int new_slider_size = -1, new_slider_position = -1;
394 int new_width = -1, new_height = -1, new_x = -1, new_y = -1;
395 struct window *new_window = 0; /* #### currently unused */
397 end_pos = BUF_Z(b) - w->window_end_pos[CURRENT_DISP];
398 sb_pos = scrollbar_point(w, 0);
401 /* The end position must be strictly greater than the start
402 position, at least for the Motify scrollbar. It shouldn't hurt
403 anything for other scrollbar implementations. */
404 if (end_pos <= start_pos)
405 end_pos = start_pos + 1;
408 new_height = WINDOW_TEXT_HEIGHT(w);
409 new_width = scrollbar_width;
411 new_height = scrollbar_height;
412 new_width = WINDOW_TEXT_WIDTH(w);
415 /* If the height and width are not greater than 0, then later on the
416 Motif widgets will bitch and moan. */
423 /* fuck, just for an assertion? */
424 Lisp_Object tmp = real_window(instance->mirror, 0);
425 assert(instance->mirror && XWINDOW(tmp) == w);
428 /* Only character-based scrollbars are implemented at the moment.
429 Line-based will be implemented in the future. */
431 instance->scrollbar_is_active = 1;
432 new_line_increment = 1;
433 new_page_increment = 1;
435 /* We used to check for inhibit_scrollbar_slider_size_change here,
436 but that seems bogus. */
438 int x_offset, y_offset;
440 /* Scrollbars are always the farthest from the text area, barring
443 if (!NILP(w->scrollbar_on_left_p)) {
444 x_offset = WINDOW_LEFT(w);
446 x_offset = WINDOW_RIGHT(w) - scrollbar_width;
447 if (window_needs_vertical_divider(w))
448 x_offset -= window_divider_width(w);
450 y_offset = WINDOW_TEXT_TOP(w) + f->scrollbar_y_offset;
452 x_offset = WINDOW_TEXT_LEFT(w);
453 y_offset = f->scrollbar_y_offset;
455 if (!NILP(w->scrollbar_on_top_p)) {
456 y_offset += WINDOW_TOP(w);
458 y_offset += WINDOW_TEXT_BOTTOM(w);
466 /* A disabled scrollbar has its slider sized to the entire height of
467 the scrollbar. Currently the minibuffer scrollbar is
469 if (!MINI_WINDOW_P(w) && vertical) {
470 if (!DEVMETH_OR_GIVEN
471 (d, inhibit_scrollbar_slider_size_change, (), 0)) {
472 new_minimum = BUF_BEGV(b);
473 new_maximum = max(BUF_ZV(b), new_minimum + 1);
474 new_slider_size = min((end_pos - start_pos),
475 (new_maximum - new_minimum));
476 new_slider_position = sb_pos;
479 } else if (!MINI_WINDOW_P(w)) {
480 /* The minus one is to account for the truncation glyph. */
481 int wcw = window_char_width(w, 0) - 1;
482 int max_width, max_slide;
484 if (w->max_line_len < wcw) {
489 max_width = w->max_line_len + 2;
490 max_slide = max_width - wcw;
494 new_maximum = max_width;
495 new_slider_size = wcw;
496 new_slider_position = min(w->hscroll, max_slide);
497 } else { /* MINI_WINDOW_P (w) */
502 new_slider_position = 1;
503 instance->scrollbar_is_active = 0;
506 DEVMETH(d, update_scrollbar_instance_values, (w, instance,
513 new_width, new_height,
517 void init_frame_scrollbars(struct frame *f)
519 struct device *d = XDEVICE(f->device);
521 if (HAS_DEVMETH_P(d, create_scrollbar_instance)) {
522 int depth = unlock_ghost_specifiers_protected();
525 call_critical_lisp_code(XDEVICE(FRAME_DEVICE(f)),
526 Qinit_scrollbar_from_resources, frame);
527 unbind_to(depth, Qnil);
531 void init_device_scrollbars(struct device *d)
533 if (HAS_DEVMETH_P(d, create_scrollbar_instance)) {
534 int depth = unlock_ghost_specifiers_protected();
536 XSETDEVICE(device, d);
537 call_critical_lisp_code(d,
538 Qinit_scrollbar_from_resources, device);
539 unbind_to(depth, Qnil);
543 void init_global_scrollbars(struct device *d)
545 if (HAS_DEVMETH_P(d, create_scrollbar_instance)) {
546 int depth = unlock_ghost_specifiers_protected();
547 call_critical_lisp_code(d,
548 Qinit_scrollbar_from_resources,
550 unbind_to(depth, Qnil);
555 vertical_scrollbar_changed_in_window(Lisp_Object specifier,
556 struct window *w, Lisp_Object oldval)
558 /* Hold on your cerebella guys. If we always show the dividers,
559 changing scrollbar affects only how the text and scrollbar are
560 laid out in the window. If we do not want the dividers to show up
561 always, then we mark more drastic change, because changing
562 divider appearance changes lotta things. Although we actually need
563 to do this only if the scrollbar has appeared or disappeared
564 completely at either window edge, we do this always, as users
565 usually do not reposition scrollbars 200 times a second or so. Do
567 if (NILP(w->vertical_divider_always_visible_p))
568 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED(XFRAME(WINDOW_FRAME(w)));
570 MARK_WINDOWS_CHANGED(w);
573 /* This function is called as a result of a change to the
574 `scrollbar-pointer' glyph. */
576 scrollbar_pointer_changed_in_window(Lisp_Object specifier, struct window *w,
579 struct frame *f = XFRAME(WINDOW_FRAME(w));
581 if (f->init_finished)
582 MAYBE_FRAMEMETH(f, scrollbar_pointer_changed_in_window, (w));
587 All of the following stuff is functions that handle scrollbar
588 actions. All of it should be moved into Lisp. This may require
589 adding some badly-needed primitives. */
591 /********** vertical scrollbar stuff **********/
594 * If the original point is still visible, put the cursor back there.
595 * Otherwise, when scrolling down stick it at the beginning of the
596 * first visible line and when scrolling up stick it at the beginning
597 * of the last visible line.
600 /* #### This function should be moved into Lisp */
601 static void scrollbar_reset_cursor(Lisp_Object win, Lisp_Object orig_pt)
603 /* When this function is called we know that start is already
604 accurate. We know this because either set-window-start or
605 recenter was called immediately prior to it being called. */
607 Bufpos start_pos = XINT(Fwindow_start(win));
608 Bufpos ptint = XINT(orig_pt);
609 struct window *w = XWINDOW(win);
610 Lisp_Object tmp_win = Fselected_window(XFRAME(w->frame)->device);
611 int selected = ((w == XWINDOW(tmp_win)) ? 1 : 0);
613 buf = Fwindow_buffer(win);
615 return; /* the window was deleted out from under us */
617 if (ptint < XINT(Fwindow_start(win))) {
619 Fgoto_char(make_int(start_pos), buf);
621 Fset_window_point(win, make_int(start_pos));
622 } else if (!point_would_be_visible(XWINDOW(win), start_pos, ptint)) {
623 Fmove_to_window_line(make_int(-1), win);
626 Fbeginning_of_line(Qnil, buf);
628 /* #### Taken from forward-line. */
631 pos = find_next_newline(XBUFFER(buf),
636 Fset_window_point(win, make_int(pos));
640 Fgoto_char(orig_pt, buf);
642 Fset_window_point(win, orig_pt);
646 DEFUN("scrollbar-line-up", Fscrollbar_line_up, 1, 1, 0, /*
647 Function called when the line-up arrow on the scrollbar is clicked.
648 This is the little arrow at the top of the scrollbar. One argument, the
649 scrollbar's window. You can advise this function to change the scrollbar
654 CHECK_LIVE_WINDOW(window);
655 window_scroll(window, make_int(1), -1, ERROR_ME_NOT);
656 zmacs_region_stays = 1;
660 DEFUN("scrollbar-line-down", Fscrollbar_line_down, 1, 1, 0, /*
661 Function called when the line-down arrow on the scrollbar is clicked.
662 This is the little arrow at the bottom of the scrollbar. One argument, the
663 scrollbar's window. You can advise this function to change the scrollbar
668 CHECK_LIVE_WINDOW(window);
669 window_scroll(window, make_int(1), 1, ERROR_ME_NOT);
670 zmacs_region_stays = 1;
674 DEFUN("scrollbar-page-up", Fscrollbar_page_up, 1, 1, 0, /*
675 Function called when the user gives the "page-up" scrollbar action.
676 \(The way this is done can vary from scrollbar to scrollbar.) One argument,
677 a cons containing the scrollbar's window and a value (#### document me!
678 This value is nil for Motif/Lucid scrollbars and a number for Athena
679 scrollbars). You can advise this function to change the scrollbar
684 Lisp_Object window = Fcar(object);
686 CHECK_LIVE_WINDOW(window);
687 /* Motif and Athena scrollbars behave differently, but in accordance
688 with their standard behaviors. It is not possible to hide the
689 differences down in lwlib because knowledge of SXEmacs buffer and
690 cursor motion routines is necessary. */
692 if (NILP(XCDR(object)))
693 window_scroll(window, Qnil, -1, ERROR_ME_NOT);
696 Lisp_Object value = Fcdr(object);
699 Fmove_to_window_line(Qzero, window);
700 /* can't use Fvertical_motion() because it moves the buffer point
701 rather than the window's point.
703 #### It does? Why does it take a window argument then? */
704 bufpos = vmotion(XWINDOW(window), XINT(Fwindow_point(window)),
706 Fset_window_point(window, make_int(bufpos));
707 Fcenter_to_window_line(Qzero, window);
710 zmacs_region_stays = 1;
714 DEFUN("scrollbar-page-down", Fscrollbar_page_down, 1, 1, 0, /*
715 Function called when the user gives the "page-down" scrollbar action.
716 \(The way this is done can vary from scrollbar to scrollbar.) One argument,
717 a cons containing the scrollbar's window and a value (#### document me!
718 This value is nil for Motif/Lucid scrollbars and a number for Athena
719 scrollbars). You can advise this function to change the scrollbar
724 Lisp_Object window = Fcar(object);
726 CHECK_LIVE_WINDOW(window);
727 /* Motif and Athena scrollbars behave differently, but in accordance
728 with their standard behaviors. It is not possible to hide the
729 differences down in lwlib because knowledge of SXEmacs buffer and
730 cursor motion routines is necessary. */
732 if (NILP(XCDR(object)))
733 window_scroll(window, Qnil, 1, ERROR_ME_NOT);
735 Lisp_Object value = Fcdr(object);
737 Fmove_to_window_line(value, window);
738 Fcenter_to_window_line(Qzero, window);
741 zmacs_region_stays = 1;
745 DEFUN("scrollbar-to-top", Fscrollbar_to_top, 1, 1, 0, /*
746 Function called when the user invokes the "to-top" scrollbar action.
747 The way this is done can vary from scrollbar to scrollbar, but
748 C-button1 on the up-arrow is very common. One argument, the
749 scrollbar's window. You can advise this function to change the
754 Lisp_Object orig_pt = Fwindow_point(window);
755 Fset_window_point(window, Fpoint_min(Fwindow_buffer(window)));
756 Fcenter_to_window_line(Qzero, window);
757 scrollbar_reset_cursor(window, orig_pt);
758 zmacs_region_stays = 1;
762 DEFUN("scrollbar-to-bottom", Fscrollbar_to_bottom, 1, 1, 0, /*
763 Function called when the user invokes the "to-bottom" scrollbar action.
764 The way this is done can vary from scrollbar to scrollbar, but
765 C-button1 on the down-arrow is very common. One argument, the
766 scrollbar's window. You can advise this function to change the
771 Lisp_Object orig_pt = Fwindow_point(window);
772 Fset_window_point(window, Fpoint_max(Fwindow_buffer(window)));
773 Fcenter_to_window_line(make_int(-3), window);
774 scrollbar_reset_cursor(window, orig_pt);
775 zmacs_region_stays = 1;
779 DEFUN("scrollbar-vertical-drag", Fscrollbar_vertical_drag, 1, 1, 0, /*
780 Function called when the user drags the vertical scrollbar slider.
781 One argument, a cons containing the scrollbar's window and a value
782 between point-min and point-max. You can advise this function to
783 change the scrollbar behavior.
789 Lisp_Object window = Fcar(object);
790 Lisp_Object value = Fcdr(object);
792 orig_pt = Fwindow_point(window);
793 Fset_marker(XWINDOW(window)->sb_point, value, Fwindow_buffer(window));
794 start_pos = scrollbar_point(XWINDOW(window), 1);
795 Fset_window_start(window, make_int(start_pos), Qnil);
796 scrollbar_reset_cursor(window, orig_pt);
797 Fsit_for(Qzero, Qnil);
798 zmacs_region_stays = 1;
802 DEFUN("scrollbar-set-hscroll", Fscrollbar_set_hscroll, 2, 2, 0, /*
803 Set WINDOW's hscroll position to VALUE.
804 This ensures that VALUE is in the proper range for the horizontal scrollbar.
809 int hscroll, wcw, max_len;
811 CHECK_LIVE_WINDOW(window);
812 if (!EQ(value, Qmax))
816 wcw = window_char_width(w, 0) - 1;
817 /* #### We should be able to scroll further right as long as there is
818 a visible truncation glyph. This calculation for max is bogus. */
819 max_len = w->max_line_len + 2;
821 if (EQ(value, Qmax) || (XINT(value) > (max_len - wcw)))
822 hscroll = max_len - wcw;
824 hscroll = XINT(value);
826 /* Can't allow this out of set-window-hscroll's acceptable range. */
827 /* #### What hell on the earth this code limits scroll size to the
828 machine-dependent SHORT size? -- kkm */
831 else if (hscroll >= (1 << (SXE_SHORTBITS - 1)) - 1)
832 hscroll = (1 << (SXE_SHORTBITS - 1)) - 1;
834 if (hscroll != w->hscroll)
835 Fset_window_hscroll(window, make_int(hscroll));
840 /************************************************************************/
842 /************************************************************************/
844 void syms_of_scrollbar(void)
846 defsymbol(&Qscrollbar_line_up, "scrollbar-line-up");
847 defsymbol(&Qscrollbar_line_down, "scrollbar-line-down");
848 defsymbol(&Qscrollbar_page_up, "scrollbar-page-up");
849 defsymbol(&Qscrollbar_page_down, "scrollbar-page-down");
850 defsymbol(&Qscrollbar_to_top, "scrollbar-to-top");
851 defsymbol(&Qscrollbar_to_bottom, "scrollbar-to-bottom");
852 defsymbol(&Qscrollbar_vertical_drag, "scrollbar-vertical-drag");
854 defsymbol(&Qscrollbar_char_left, "scrollbar-char-left");
855 defsymbol(&Qscrollbar_char_right, "scrollbar-char-right");
856 defsymbol(&Qscrollbar_page_left, "scrollbar-page-left");
857 defsymbol(&Qscrollbar_page_right, "scrollbar-page-right");
858 defsymbol(&Qscrollbar_to_left, "scrollbar-to-left");
859 defsymbol(&Qscrollbar_to_right, "scrollbar-to-right");
860 defsymbol(&Qscrollbar_horizontal_drag, "scrollbar-horizontal-drag");
862 defsymbol(&Qinit_scrollbar_from_resources,
863 "init-scrollbar-from-resources");
865 /* #### All these functions should be moved into Lisp.
866 See comment above. */
867 DEFSUBR(Fscrollbar_line_up);
868 DEFSUBR(Fscrollbar_line_down);
869 DEFSUBR(Fscrollbar_page_up);
870 DEFSUBR(Fscrollbar_page_down);
871 DEFSUBR(Fscrollbar_to_top);
872 DEFSUBR(Fscrollbar_to_bottom);
873 DEFSUBR(Fscrollbar_vertical_drag);
875 DEFSUBR(Fscrollbar_set_hscroll);
878 void vars_of_scrollbar(void)
880 DEFVAR_LISP("scrollbar-pointer-glyph", &Vscrollbar_pointer_glyph /*
881 *The shape of the mouse-pointer when over a scrollbar.
882 This is a glyph; use `set-glyph-image' to change it.
883 If unspecified in a particular domain, the window-system-provided
884 default pointer is used.
887 Fprovide(intern("scrollbar"));
890 void specifier_vars_of_scrollbar(void)
892 DEFVAR_SPECIFIER("scrollbar-width", &Vscrollbar_width /*
893 *Width of vertical scrollbars.
894 This is a specifier; use `set-specifier' to change it.
896 Vscrollbar_width = make_magic_specifier(Qnatnum);
897 set_specifier_fallback
899 list1(Fcons(Qnil, make_int(DEFAULT_SCROLLBAR_WIDTH))));
900 set_specifier_caching(Vscrollbar_width,
901 offsetof(struct window, scrollbar_width),
902 vertical_scrollbar_changed_in_window,
903 offsetof(struct frame, scrollbar_width),
904 frame_size_slipped, 0);
906 DEFVAR_SPECIFIER("scrollbar-height", &Vscrollbar_height /*
907 *Height of horizontal scrollbars.
908 This is a specifier; use `set-specifier' to change it.
910 Vscrollbar_height = make_magic_specifier(Qnatnum);
911 set_specifier_fallback
913 list1(Fcons(Qnil, make_int(DEFAULT_SCROLLBAR_HEIGHT))));
914 set_specifier_caching(Vscrollbar_height,
915 offsetof(struct window, scrollbar_height),
916 some_window_value_changed,
917 offsetof(struct frame, scrollbar_height),
918 frame_size_slipped, 0);
920 DEFVAR_SPECIFIER("horizontal-scrollbar-visible-p", &Vhorizontal_scrollbar_visible_p /*
921 *Whether the horizontal scrollbar is visible.
922 This is a specifier; use `set-specifier' to change it.
924 Vhorizontal_scrollbar_visible_p = Fmake_specifier(Qboolean);
925 set_specifier_fallback(Vhorizontal_scrollbar_visible_p,
926 list1(Fcons(Qnil, Qt)));
927 set_specifier_caching(Vhorizontal_scrollbar_visible_p,
928 offsetof(struct window,
929 horizontal_scrollbar_visible_p),
930 some_window_value_changed,
931 offsetof(struct frame,
932 horizontal_scrollbar_visible_p),
933 frame_size_slipped, 0);
935 DEFVAR_SPECIFIER("vertical-scrollbar-visible-p", &Vvertical_scrollbar_visible_p /*
936 *Whether the vertical scrollbar is visible.
937 This is a specifier; use `set-specifier' to change it.
939 Vvertical_scrollbar_visible_p = Fmake_specifier(Qboolean);
940 set_specifier_fallback(Vvertical_scrollbar_visible_p,
941 list1(Fcons(Qnil, Qt)));
942 set_specifier_caching(Vvertical_scrollbar_visible_p,
943 offsetof(struct window,
944 vertical_scrollbar_visible_p),
945 vertical_scrollbar_changed_in_window,
946 offsetof(struct frame,
947 vertical_scrollbar_visible_p),
948 frame_size_slipped, 0);
950 DEFVAR_SPECIFIER("scrollbar-on-left-p", &Vscrollbar_on_left_p /*
951 *Whether the vertical scrollbar is on the left side of window or frame.
952 This is a specifier; use `set-specifier' to change it.
954 Vscrollbar_on_left_p = Fmake_specifier(Qboolean);
957 /* Kludge. Under X, we want athena scrollbars on the left,
958 while all other scrollbars go on the right by default. */
959 Lisp_Object fallback = list1(Fcons(Qnil, Qnil));
960 #if defined (HAVE_X_WINDOWS) \
961 && !defined (LWLIB_SCROLLBARS_MOTIF) \
962 && !defined (LWLIB_SCROLLBARS_LUCID) \
963 && !defined (LWLIB_SCROLLBARS_ATHENA3D)
965 fallback = Fcons(Fcons(list1(Qx), Qt), fallback);
967 set_specifier_fallback(Vscrollbar_on_left_p, fallback);
970 set_specifier_caching(Vscrollbar_on_left_p,
971 offsetof(struct window, scrollbar_on_left_p),
972 vertical_scrollbar_changed_in_window,
973 offsetof(struct frame, scrollbar_on_left_p),
974 frame_size_slipped, 0);
976 DEFVAR_SPECIFIER("scrollbar-on-top-p", &Vscrollbar_on_top_p /*
977 *Whether the horizontal scrollbar is on the top side of window or frame.
978 This is a specifier; use `set-specifier' to change it.
980 Vscrollbar_on_top_p = Fmake_specifier(Qboolean);
981 set_specifier_fallback(Vscrollbar_on_top_p, list1(Fcons(Qnil, Qnil)));
982 set_specifier_caching(Vscrollbar_on_top_p,
983 offsetof(struct window, scrollbar_on_top_p),
984 some_window_value_changed,
985 offsetof(struct frame, scrollbar_on_top_p),
986 frame_size_slipped, 0);
989 void complex_vars_of_scrollbar(void)
991 Vscrollbar_pointer_glyph = Fmake_glyph_internal(Qpointer);
993 set_specifier_caching(XGLYPH(Vscrollbar_pointer_glyph)->image,
994 offsetof(struct window, scrollbar_pointer),
995 scrollbar_pointer_changed_in_window, 0, 0, 0);