Mercurial > hg > xemacs-beta
comparison src/scrollbar.c @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | ac2d302a0011 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
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>. | |
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 /* This file has been Mule-ized. */ | |
27 | |
28 #include <config.h> | |
29 #include "lisp.h" | |
30 | |
31 #include "buffer.h" | |
32 #include "commands.h" | |
33 #include "scrollbar.h" | |
34 #include "device.h" | |
35 #include "frame.h" | |
36 #include "glyphs.h" | |
37 #include "window.h" | |
38 | |
39 Lisp_Object Qinit_scrollbar_from_resources; | |
40 | |
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; | |
48 | |
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; | |
56 | |
57 #define DEFAULT_SCROLLBAR_WIDTH 15 | |
58 #define DEFAULT_SCROLLBAR_HEIGHT 15 | |
59 | |
60 /* Width of the scrollbar. */ | |
61 Lisp_Object Vscrollbar_width; | |
62 | |
63 /* Height of the scrollbar. */ | |
64 Lisp_Object Vscrollbar_height; | |
65 | |
66 Lisp_Object Vscrollbar_pointer_glyph; | |
67 | |
68 static void update_scrollbar_instance (struct window *w, int vertical, | |
69 struct scrollbar_instance *instance); | |
70 | |
71 | |
72 static void | |
73 free_scrollbar_instance (struct scrollbar_instance *instance, | |
74 struct frame *frame) | |
75 { | |
76 if (!instance) | |
77 return; | |
78 else | |
79 { | |
80 struct device *d = XDEVICE (frame->device); | |
81 | |
82 MAYBE_DEVMETH (d, free_scrollbar_instance, (instance)); | |
83 xfree (instance); | |
84 } | |
85 } | |
86 | |
87 static void | |
88 free_window_mirror_scrollbars (struct window_mirror *mir) | |
89 { | |
90 struct frame *f = mir->frame; | |
91 free_scrollbar_instance (mir->scrollbar_vertical_instance, f); | |
92 mir->scrollbar_vertical_instance = 0; | |
93 free_scrollbar_instance (mir->scrollbar_horizontal_instance, f); | |
94 mir->scrollbar_horizontal_instance = 0; | |
95 } | |
96 | |
97 static struct window_mirror * | |
98 free_scrollbars_loop (Lisp_Object window, struct window_mirror *mir) | |
99 { | |
100 struct window_mirror *retval = NULL; | |
101 | |
102 while (mir) | |
103 { | |
104 struct scrollbar_instance *vinst = mir->scrollbar_vertical_instance; | |
105 struct scrollbar_instance *hinst = mir->scrollbar_horizontal_instance; | |
106 struct frame *f; | |
107 | |
108 assert (!NILP (window)); | |
109 f = XFRAME (XWINDOW (window)->frame); | |
110 | |
111 if (mir->vchild) | |
112 { | |
113 retval = free_scrollbars_loop (XWINDOW (window)->vchild, | |
114 mir->vchild); | |
115 } | |
116 else if (mir->hchild) | |
117 { | |
118 retval = free_scrollbars_loop (XWINDOW (window)->hchild, | |
119 mir->hchild); | |
120 } | |
121 | |
122 if (retval != NULL) | |
123 return retval; | |
124 | |
125 if (hinst || vinst) | |
126 free_window_mirror_scrollbars (mir); | |
127 | |
128 mir = mir->next; | |
129 window = XWINDOW (window)->next; | |
130 } | |
131 | |
132 return NULL; | |
133 } | |
134 | |
135 /* Destroy all scrollbars associated with FRAME. Only called from | |
136 delete_frame_internal. | |
137 */ | |
138 #define FREE_FRAME_SCROLLBARS_INTERNAL(cache) \ | |
139 do { \ | |
140 while (FRAME_SB_##cache (f)) \ | |
141 { \ | |
142 struct scrollbar_instance *tofree = FRAME_SB_##cache (f); \ | |
143 FRAME_SB_##cache (f) = FRAME_SB_##cache (f)->next; \ | |
144 tofree->next = NULL; \ | |
145 free_scrollbar_instance (tofree, f); \ | |
146 } \ | |
147 } while (0) | |
148 | |
149 void | |
150 free_frame_scrollbars (struct frame *f) | |
151 { | |
152 if (!HAS_FRAMEMETH_P (f, create_scrollbar_instance)) | |
153 return; | |
154 | |
155 if (f->mirror_dirty) | |
156 update_frame_window_mirror (f); | |
157 | |
158 free_scrollbars_loop (f->root_window, f->root_mirror); | |
159 | |
160 FREE_FRAME_SCROLLBARS_INTERNAL (VCACHE); | |
161 FREE_FRAME_SCROLLBARS_INTERNAL (HCACHE); | |
162 } | |
163 #undef FREE_FRAME_SCROLLBARS_INTERNAL | |
164 | |
165 | |
166 static struct scrollbar_instance * | |
167 create_scrollbar_instance (struct frame *f, int vertical) | |
168 { | |
169 struct device *d = XDEVICE (f->device); | |
170 struct scrollbar_instance *instance = | |
171 (struct scrollbar_instance *) xmalloc (sizeof (*instance)); | |
172 | |
173 memset (instance, 0, sizeof (*instance)); | |
174 MAYBE_DEVMETH (d, create_scrollbar_instance, (f, vertical, instance)); | |
175 | |
176 return instance; | |
177 } | |
178 | |
179 | |
180 #define GET_SCROLLBAR_INSTANCE_INTERNAL(cache) \ | |
181 do { \ | |
182 if (FRAME_SB_##cache (f)) \ | |
183 { \ | |
184 struct scrollbar_instance *retval = FRAME_SB_##cache (f); \ | |
185 FRAME_SB_##cache (f) = FRAME_SB_##cache (f)->next; \ | |
186 retval->next = NULL; \ | |
187 return retval; \ | |
188 } \ | |
189 } while (0) | |
190 | |
191 static struct scrollbar_instance * | |
192 get_scrollbar_instance (struct frame *f, int vertical) | |
193 { | |
194 /* Check if there are any available scrollbars already in existence. */ | |
195 if (vertical) | |
196 GET_SCROLLBAR_INSTANCE_INTERNAL (VCACHE); | |
197 else | |
198 GET_SCROLLBAR_INSTANCE_INTERNAL (HCACHE); | |
199 | |
200 return create_scrollbar_instance (f, vertical); | |
201 } | |
202 #undef GET_SCROLLBAR_INSTANCE_INTERNAL | |
203 | |
204 #define RELEASE_SCROLLBAR_INSTANCE_INTERNAL(cache) \ | |
205 do { \ | |
206 if (!FRAME_SB_##cache (f)) \ | |
207 { \ | |
208 instance->next = NULL; \ | |
209 FRAME_SB_##cache (f) = instance; \ | |
210 } \ | |
211 else \ | |
212 { \ | |
213 instance->next = FRAME_SB_##cache (f); \ | |
214 FRAME_SB_##cache (f) = instance; \ | |
215 } \ | |
216 } while (0) | |
217 | |
218 static void | |
219 release_scrollbar_instance (struct frame *f, int vertical, | |
220 struct scrollbar_instance *instance) | |
221 { | |
222 /* #### should we do "instance->mir = 0;" for safety? */ | |
223 if (vertical) | |
224 RELEASE_SCROLLBAR_INSTANCE_INTERNAL (VCACHE); | |
225 else | |
226 RELEASE_SCROLLBAR_INSTANCE_INTERNAL (HCACHE); | |
227 } | |
228 #undef RELEASE_SCROLLBAR_INSTANCE_INTERNAL | |
229 | |
230 #ifdef MEMORY_USAGE_STATS | |
231 | |
232 int | |
233 compute_scrollbar_instance_usage (struct device *d, | |
234 struct scrollbar_instance *inst, | |
235 struct overhead_stats *ovstats) | |
236 { | |
237 int total = 0; | |
238 | |
239 total += DEVMETH (d, compute_scrollbar_instance_usage, (d, inst, ovstats)); | |
240 | |
241 while (inst) | |
242 { | |
243 total += malloced_storage_size (inst, sizeof (*inst), ovstats); | |
244 inst = inst->next; | |
245 } | |
246 | |
247 return total; | |
248 } | |
249 | |
250 #endif /* MEMORY_USAGE_STATS */ | |
251 | |
252 void | |
253 update_window_scrollbars (struct window *w, struct window_mirror *mirror, | |
254 int active, int horiz_only) | |
255 { | |
256 struct frame *f = XFRAME (w->frame); | |
257 struct device *d = XDEVICE (f->device); | |
258 | |
259 if (!HAS_DEVMETH_P (d, create_scrollbar_instance)) | |
260 return; | |
261 | |
262 in_display++; | |
263 | |
264 /* It is possible for this to get called from the mirror update | |
265 routines. In that case the structure is in an indeterminate | |
266 state but we know exactly what struct we are working with. So we | |
267 pass it in in that case. We also take advantage of it at some | |
268 other points where we know what the mirror struct is. */ | |
269 if (!mirror) | |
270 mirror = find_window_mirror (w); | |
271 | |
272 if (!mirror->scrollbar_vertical_instance && active) | |
273 mirror->scrollbar_vertical_instance = get_scrollbar_instance (f, 1); | |
274 | |
275 if (!mirror->scrollbar_horizontal_instance && active) | |
276 mirror->scrollbar_horizontal_instance = get_scrollbar_instance (f, 0); | |
277 | |
278 if (!horiz_only && mirror->scrollbar_vertical_instance) | |
279 { | |
280 int size = (active ? window_scrollbar_width (w) : 0); | |
281 struct scrollbar_instance *instance; | |
282 | |
283 instance = mirror->scrollbar_vertical_instance; | |
284 instance->scrollbar_is_active = active; | |
285 instance->mirror = mirror; | |
286 | |
287 if (active && size) | |
288 update_scrollbar_instance (w, 1, instance); | |
289 MAYBE_DEVMETH (d, update_scrollbar_instance_status, | |
290 (w, active, size, instance)); | |
291 | |
292 if (!active) | |
293 { | |
294 release_scrollbar_instance (f, 1, instance); | |
295 mirror->scrollbar_vertical_instance = NULL; | |
296 } | |
297 } | |
298 | |
299 if (mirror->scrollbar_horizontal_instance) | |
300 { | |
301 int size = (active ? window_scrollbar_height (w) : 0); | |
302 struct scrollbar_instance *instance; | |
303 | |
304 instance = mirror->scrollbar_horizontal_instance; | |
305 instance->scrollbar_is_active = active; | |
306 instance->mirror = mirror; | |
307 | |
308 if (active && size) | |
309 update_scrollbar_instance (w, 0, instance); | |
310 MAYBE_DEVMETH (d, update_scrollbar_instance_status, | |
311 (w, active, size, instance)); | |
312 | |
313 if (!active) | |
314 { | |
315 release_scrollbar_instance (f, 0, instance); | |
316 mirror->scrollbar_horizontal_instance = NULL; | |
317 } | |
318 } | |
319 | |
320 in_display--; | |
321 } | |
322 | |
323 void | |
324 release_window_mirror_scrollbars (struct window_mirror *mir) | |
325 { | |
326 struct device *d = XDEVICE (mir->frame->device); | |
327 | |
328 if (!HAS_DEVMETH_P (d, create_scrollbar_instance)) | |
329 return; | |
330 | |
331 if (mir->scrollbar_vertical_instance) | |
332 { | |
333 release_scrollbar_instance (mir->frame, 1, | |
334 mir->scrollbar_vertical_instance); | |
335 MAYBE_DEVMETH (d, release_scrollbar_instance, | |
336 (mir->scrollbar_vertical_instance)); | |
337 } | |
338 mir->scrollbar_vertical_instance = 0; | |
339 | |
340 if (mir->scrollbar_horizontal_instance) | |
341 { | |
342 release_scrollbar_instance (mir->frame, 0, | |
343 mir->scrollbar_horizontal_instance); | |
344 MAYBE_DEVMETH (d, release_scrollbar_instance, | |
345 (mir->scrollbar_horizontal_instance)); | |
346 } | |
347 mir->scrollbar_horizontal_instance = 0; | |
348 } | |
349 | |
350 /* This check needs to be done in the device-specific side. */ | |
351 #define UPDATE_DATA_FIELD(field, value) \ | |
352 if (instance->field != value) {\ | |
353 instance->field = value;\ | |
354 instance->scrollbar_instance_changed = 1;\ | |
355 }\ | |
356 | |
357 /* | |
358 * If w->sb_point is on the top line then return w->sb_point else | |
359 * return w->start. If flag, then return beginning point of line | |
360 * which w->sb_point lies on. | |
361 */ | |
362 static Bufpos | |
363 scrollbar_point (struct window *w, int flag) | |
364 { | |
365 Bufpos start_pos, end_pos, sb_pos; | |
366 Lisp_Object buf; | |
367 struct buffer *b; | |
368 | |
369 if (NILP (w->buffer)) /* non-leaf window */ | |
370 return 0; | |
371 | |
372 start_pos = marker_position (w->start[CURRENT_DISP]); | |
373 sb_pos = marker_position (w->sb_point); | |
374 | |
375 if (!flag && sb_pos < start_pos) | |
376 return start_pos; | |
377 | |
378 buf = get_buffer (w->buffer, 0); | |
379 if (!NILP (buf)) | |
380 b = XBUFFER (buf); | |
381 else | |
382 return start_pos; | |
383 | |
384 if (flag) | |
385 end_pos = find_next_newline_no_quit (b, sb_pos, -1); | |
386 else | |
387 end_pos = find_next_newline_no_quit (b, start_pos, 1); | |
388 | |
389 if (flag) | |
390 return end_pos; | |
391 else if (sb_pos > end_pos) | |
392 return start_pos; | |
393 else | |
394 return sb_pos; | |
395 } | |
396 | |
397 /* | |
398 * Update a window's horizontal or vertical scrollbar. | |
399 */ | |
400 static void | |
401 update_scrollbar_instance (struct window *w, int vertical, | |
402 struct scrollbar_instance *instance) | |
403 { | |
404 struct frame *f = XFRAME (w->frame); | |
405 struct device *d = XDEVICE (f->device); | |
406 struct buffer *b = XBUFFER (w->buffer); | |
407 Bufpos start_pos, end_pos, sb_pos; | |
408 int scrollbar_width = window_scrollbar_width (w); | |
409 int scrollbar_height = window_scrollbar_height (w); | |
410 | |
411 int new_line_increment = -1, new_page_increment = -1; | |
412 int new_minimum = -1, new_maximum = -1; | |
413 int new_slider_size = -1, new_slider_position = -1; | |
414 int new_width = -1, new_height = -1, new_x = -1, new_y = -1; | |
415 struct window *new_window = 0; /* kludge city */ | |
416 | |
417 end_pos = BUF_Z (b) - w->window_end_pos[CURRENT_DISP]; | |
418 sb_pos = scrollbar_point (w, 0); | |
419 start_pos = sb_pos; | |
420 | |
421 /* The end position must be strictly greater than the start | |
422 position, at least for the Motify scrollbar. It shouldn't hurt | |
423 anything for other scrollbar implementations. */ | |
424 if (end_pos <= start_pos) | |
425 end_pos = start_pos + 1; | |
426 | |
427 if (vertical) | |
428 { | |
429 new_height = WINDOW_TEXT_HEIGHT (w); | |
430 new_width = scrollbar_width; | |
431 } | |
432 else | |
433 { | |
434 new_height = scrollbar_height; | |
435 new_width = WINDOW_TEXT_WIDTH (w); | |
436 } | |
437 | |
438 /* If the height and width are not greater than 0, then later on the | |
439 Motif widgets will bitch and moan. */ | |
440 if (new_height <= 0) | |
441 new_height = 1; | |
442 if (new_width <= 0) | |
443 new_width = 1; | |
444 | |
445 assert (instance->mirror && XWINDOW (real_window(instance->mirror, 0)) == w); | |
446 | |
447 /* Only character-based scrollbars are implemented at the moment. | |
448 Line-based will be implemented in the future. */ | |
449 | |
450 instance->scrollbar_is_active = 1; | |
451 new_line_increment = 1; | |
452 new_page_increment = 1; | |
453 | |
454 if (!DEVMETH_OR_GIVEN (d, inhibit_scrollbar_thumb_size_change, (), 0)) | |
455 { | |
456 int x_offset, y_offset; | |
457 | |
458 /* Scrollbars are always the farthest from the text area. */ | |
459 if (vertical) | |
460 { | |
461 x_offset = (f->scrollbar_on_left | |
462 ? WINDOW_LEFT (w) | |
463 : WINDOW_RIGHT (w) - scrollbar_width); | |
464 y_offset = WINDOW_TEXT_TOP (w) + f->scrollbar_y_offset; | |
465 } | |
466 else | |
467 { | |
468 x_offset = WINDOW_TEXT_LEFT (w); | |
469 y_offset = f->scrollbar_y_offset + | |
470 (f->scrollbar_on_top | |
471 ? WINDOW_TOP (w) | |
472 : WINDOW_TEXT_BOTTOM (w) + window_bottom_toolbar_height (w)); | |
473 } | |
474 | |
475 new_x = x_offset; | |
476 new_y = y_offset; | |
477 } | |
478 | |
479 /* A disabled scrollbar has its slider sized to the entire height of | |
480 the scrollbar. Currently the minibuffer scrollbar is | |
481 disabled. */ | |
482 if (!MINI_WINDOW_P (w) && vertical) | |
483 { | |
484 if (!DEVMETH_OR_GIVEN (d, inhibit_scrollbar_thumb_size_change, (), 0)) | |
485 { | |
486 new_minimum = BUF_BEGV (b); | |
487 new_maximum = max (BUF_ZV (b), new_minimum + 1); | |
488 new_slider_size = min ((end_pos - start_pos), | |
489 (new_maximum - new_minimum)); | |
490 new_slider_position = sb_pos; | |
491 new_window = w; | |
492 } | |
493 } | |
494 else if (!MINI_WINDOW_P (w)) | |
495 { | |
496 /* The minus one is to account for the truncation glyph. */ | |
497 int wcw = window_char_width (w, 0) - 1; | |
498 int max_width, max_slide; | |
499 | |
500 if (w->max_line_len < wcw) | |
501 { | |
502 max_width = 1; | |
503 max_slide = 1; | |
504 wcw = 1; | |
505 } | |
506 else | |
507 { | |
508 max_width = w->max_line_len + 2; | |
509 max_slide = max_width - wcw; | |
510 } | |
511 | |
512 new_minimum = 0; | |
513 new_maximum = max_width; | |
514 new_slider_size = wcw; | |
515 new_slider_position = min (w->hscroll, max_slide); | |
516 } | |
517 else | |
518 { | |
519 new_minimum = 1; | |
520 new_maximum = 2; | |
521 new_slider_size = 1; | |
522 new_slider_position = 1; | |
523 instance->scrollbar_is_active = 0; | |
524 } | |
525 | |
526 DEVMETH (d, update_scrollbar_instance_values, (w, instance, | |
527 new_line_increment, | |
528 new_page_increment, | |
529 new_minimum, | |
530 new_maximum, | |
531 new_slider_size, | |
532 new_slider_position, | |
533 new_width, new_height, | |
534 new_x, new_y)); | |
535 } | |
536 | |
537 void | |
538 init_frame_scrollbars (struct frame *f) | |
539 { | |
540 struct device *d = XDEVICE (f->device); | |
541 | |
542 if (HAS_DEVMETH_P (d, create_scrollbar_instance)) | |
543 { | |
544 Lisp_Object frame = Qnil; | |
545 | |
546 XSETFRAME (frame, f); | |
547 call_critical_lisp_code (XDEVICE (FRAME_DEVICE (f)), | |
548 Qinit_scrollbar_from_resources, | |
549 frame); | |
550 } | |
551 } | |
552 | |
553 void | |
554 init_device_scrollbars (struct device *d) | |
555 { | |
556 if (HAS_DEVMETH_P (d, create_scrollbar_instance)) | |
557 { | |
558 Lisp_Object device = Qnil; | |
559 | |
560 XSETDEVICE (device, d); | |
561 call_critical_lisp_code (d, | |
562 Qinit_scrollbar_from_resources, | |
563 device); | |
564 } | |
565 } | |
566 | |
567 void | |
568 init_global_scrollbars (struct device *d) | |
569 { | |
570 if (HAS_DEVMETH_P (d, create_scrollbar_instance)) | |
571 { | |
572 call_critical_lisp_code (d, | |
573 Qinit_scrollbar_from_resources, | |
574 Qglobal); | |
575 } | |
576 } | |
577 | |
578 | |
579 /* This function is called as a result of a change to the | |
580 `scrollbar-width' specifier. */ | |
581 static void | |
582 scrollbar_width_changed_in_frame (Lisp_Object specifier, struct frame *f, | |
583 Lisp_Object oldval) | |
584 { | |
585 MAYBE_FRAMEMETH (f, scrollbar_width_changed_in_frame, | |
586 (specifier, f, oldval)); | |
587 } | |
588 | |
589 /* This function is called as a result of a change to the | |
590 `scrollbar-height' specifier. */ | |
591 static void | |
592 scrollbar_height_changed_in_frame (Lisp_Object specifier, struct frame *f, | |
593 Lisp_Object oldval) | |
594 { | |
595 MAYBE_FRAMEMETH (f, scrollbar_height_changed_in_frame, | |
596 (specifier, f, oldval)); | |
597 } | |
598 | |
599 /* This function is called as a result of a change to the | |
600 `scrollbar-pointer' glyph. */ | |
601 static void | |
602 scrollbar_pointer_changed_in_window (Lisp_Object specifier, struct window *w, | |
603 Lisp_Object oldval) | |
604 { | |
605 struct frame *f = XFRAME (WINDOW_FRAME (w)); | |
606 | |
607 if (f->init_finished) | |
608 MAYBE_FRAMEMETH (f, scrollbar_pointer_changed_in_window, (w)); | |
609 } | |
610 | |
611 /* #### | |
612 | |
613 All of the following stuff is functions that handle scrollbar | |
614 actions. All of it should be moved into Lisp. This may require | |
615 adding some badly-needed primitives. */ | |
616 | |
617 /********** vertical scrollbar stuff **********/ | |
618 | |
619 /* | |
620 * If the original point is still visible, put the cursor back there. | |
621 * Otherwise, when scrolling down stick it at the beginning of the | |
622 * first visible line and when scrolling up stick it at the beginning | |
623 * of the last visible line. | |
624 */ | |
625 | |
626 /* #### This function should be moved into Lisp */ | |
627 static void | |
628 scrollbar_reset_cursor (Lisp_Object win, Lisp_Object orig_pt) | |
629 { | |
630 /* When this function is called we know that start is already | |
631 accurate. We know this because either set-window-start or | |
632 recenter was called immediately prior to it being called. */ | |
633 Lisp_Object buf; | |
634 Bufpos start_pos = XINT (Fwindow_start (win)); | |
635 Bufpos ptint = XINT (orig_pt); | |
636 struct window *w = XWINDOW (win); | |
637 int selected = ((w == XWINDOW (Fselected_window (XFRAME (w->frame)->device))) | |
638 ? 1 | |
639 : 0); | |
640 | |
641 buf = Fwindow_buffer (win); | |
642 if (NILP (buf)) | |
643 return; /* the window was deleted out from under us */ | |
644 | |
645 if (ptint < XINT (Fwindow_start (win))) | |
646 { | |
647 if (selected) | |
648 Fgoto_char (make_int (start_pos), buf); | |
649 else | |
650 Fset_window_point (win, make_int (start_pos)); | |
651 } | |
652 else if (!point_would_be_visible (XWINDOW (win), start_pos, ptint)) | |
653 { | |
654 Fmove_to_window_line (make_int (-1), win); | |
655 | |
656 if (selected) | |
657 Fbeginning_of_line (Qnil, buf); | |
658 else | |
659 { | |
660 /* #### Taken from forward-line. */ | |
661 Bufpos pos; | |
662 | |
663 pos = find_next_newline (XBUFFER (buf), | |
664 marker_position (w->pointm[CURRENT_DISP]), | |
665 -1); | |
666 Fset_window_point (win, make_int (pos)); | |
667 } | |
668 } | |
669 else | |
670 { | |
671 if (selected) | |
672 Fgoto_char (orig_pt, buf); | |
673 else | |
674 Fset_window_point (win, orig_pt); | |
675 } | |
676 } | |
677 | |
678 DEFUN ("scrollbar-line-up", Fscrollbar_line_up, Sscrollbar_line_up, 1, 1, 0 /* | |
679 Function called when the line-up arrow on the scrollbar is clicked. | |
680 This is the little arrow at the top of the scrollbar. One argument, the | |
681 scrollbar's window. You can advise this function to change the scrollbar | |
682 behavior. | |
683 */ ) | |
684 (window) | |
685 Lisp_Object window; | |
686 { | |
687 CHECK_LIVE_WINDOW (window); | |
688 window_scroll (window, make_int (1), -1, ERROR_ME_NOT); | |
689 zmacs_region_stays = 1; | |
690 return Qnil; | |
691 } | |
692 | |
693 DEFUN ("scrollbar-line-down", Fscrollbar_line_down, Sscrollbar_line_down, | |
694 1, 1, 0 /* | |
695 Function called when the line-down arrow on the scrollbar is clicked. | |
696 This is the little arrow at the bottom of the scrollbar. One argument, the | |
697 scrollbar's window. You can advise this function to change the scrollbar | |
698 behavior. | |
699 */ ) | |
700 (window) | |
701 Lisp_Object window; | |
702 { | |
703 CHECK_LIVE_WINDOW (window); | |
704 window_scroll (window, make_int (1), 1, ERROR_ME_NOT); | |
705 zmacs_region_stays = 1; | |
706 return Qnil; | |
707 } | |
708 | |
709 DEFUN ("scrollbar-page-up", Fscrollbar_page_up, Sscrollbar_page_up, | |
710 1, 1, 0 /* | |
711 Function called when the user gives the \"page-up\" scrollbar action. | |
712 (The way this is done can vary from scrollbar to scrollbar.) One argument, | |
713 a cons containing the scrollbar's window and a value (#### document me! | |
714 This value is nil for Motif/Lucid scrollbars and a number for Athena | |
715 scrollbars). You can advise this function to change the scrollbar | |
716 behavior. | |
717 */ ) | |
718 (object) | |
719 Lisp_Object object; | |
720 { | |
721 Lisp_Object window = Fcar (object); | |
722 | |
723 CHECK_LIVE_WINDOW (window); | |
724 /* Motif and Athena scrollbars behave differently, but in accordance | |
725 with their standard behaviors. It is not possible to hide the | |
726 differences down in lwlib because knowledge of XEmacs buffer and | |
727 cursor motion routines is necessary. */ | |
728 #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID) | |
729 window_scroll (window, Qnil, -1, ERROR_ME_NOT); | |
730 #else /* Athena */ | |
731 { | |
732 Bufpos bufpos; | |
733 Lisp_Object value = Fcdr (object); | |
734 | |
735 CHECK_INT (value); | |
736 Fmove_to_window_line (Qzero, window); | |
737 /* can't use Fvertical_motion() because it moves the buffer point | |
738 rather than the window's point. | |
739 | |
740 #### It does? Why does it take a window argument then? */ | |
741 bufpos = vmotion (XWINDOW (window), XINT (Fwindow_point (window)), | |
742 XINT (value), 0); | |
743 Fset_window_point (window, make_int (bufpos)); | |
744 Frecenter (Qzero, window); | |
745 } | |
746 #endif /* Athena */ | |
747 zmacs_region_stays = 1; | |
748 return Qnil; | |
749 } | |
750 | |
751 DEFUN ("scrollbar-page-down", Fscrollbar_page_down, Sscrollbar_page_down, | |
752 1, 1, 0 /* | |
753 Function called when the user gives the \"page-down\" scrollbar action. | |
754 (The way this is done can vary from scrollbar to scrollbar.) One argument, | |
755 a cons containing the scrollbar's window and a value (#### document me! | |
756 This value is nil for Motif/Lucid scrollbars and a number for Athena | |
757 scrollbars). You can advise this function to change the scrollbar | |
758 behavior. | |
759 */ ) | |
760 (object) | |
761 Lisp_Object object; | |
762 { | |
763 Lisp_Object window = Fcar (object); | |
764 | |
765 CHECK_LIVE_WINDOW (window); | |
766 /* Motif and Athena scrollbars behave differently, but in accordance | |
767 with their standard behaviors. It is not possible to hide the | |
768 differences down in lwlib because knowledge of XEmacs buffer and | |
769 cursor motion routines is necessary. */ | |
770 #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID) | |
771 window_scroll (window, Qnil, 1, ERROR_ME_NOT); | |
772 #else /* Athena */ | |
773 { | |
774 Lisp_Object value = Fcdr (object); | |
775 CHECK_INT (value); | |
776 Fmove_to_window_line (value, window); | |
777 Frecenter (Qzero, window); | |
778 } | |
779 #endif /* Athena */ | |
780 zmacs_region_stays = 1; | |
781 return Qnil; | |
782 } | |
783 | |
784 DEFUN ("scrollbar-to-top", Fscrollbar_to_top, Sscrollbar_to_top, | |
785 1, 1, 0 /* | |
786 Function called when the user gives the \"to-top\" scrollbar action. | |
787 (The way this is done can vary from scrollbar to scrollbar.). One argument, | |
788 the scrollbar's window. You can advise this function to change the | |
789 scrollbar behavior. | |
790 */ ) | |
791 (window) | |
792 Lisp_Object window; | |
793 { | |
794 Lisp_Object orig_pt; | |
795 | |
796 orig_pt = Fwindow_point (window); | |
797 Fset_window_point (window, Fpoint_min (Fwindow_buffer (window))); | |
798 Frecenter (Qzero, window); | |
799 scrollbar_reset_cursor (window, orig_pt); | |
800 zmacs_region_stays = 1; | |
801 return Qnil; | |
802 } | |
803 | |
804 DEFUN ("scrollbar-to-bottom", Fscrollbar_to_bottom, Sscrollbar_to_bottom, | |
805 1, 1, 0 /* | |
806 Function called when the user gives the \"to-bottom\" scrollbar action. | |
807 (The way this is done can vary from scrollbar to scrollbar.). One argument, | |
808 the scrollbar's window. You can advise this function to change the | |
809 scrollbar behavior. | |
810 */ ) | |
811 (window) | |
812 Lisp_Object window; | |
813 { | |
814 Lisp_Object orig_pt; | |
815 | |
816 orig_pt = Fwindow_point (window); | |
817 Fset_window_point (window, Fpoint_max (Fwindow_buffer (window))); | |
818 Frecenter (Qzero, window); | |
819 scrollbar_reset_cursor (window, orig_pt); | |
820 zmacs_region_stays = 1; | |
821 return Qnil; | |
822 } | |
823 | |
824 DEFUN ("scrollbar-vertical-drag", Fscrollbar_vertical_drag, | |
825 Sscrollbar_vertical_drag, 1, 1, 0 /* | |
826 Function called when the user drags the vertical scrollbar thumb. | |
827 One argument, a cons containing the scrollbar's window and a value | |
828 (#### document me!). You can advise this function to change the | |
829 scrollbar behavior. | |
830 */ ) | |
831 (object) | |
832 Lisp_Object object; | |
833 { | |
834 Bufpos start_pos; | |
835 Lisp_Object orig_pt; | |
836 Lisp_Object window = Fcar (object); | |
837 Lisp_Object value = Fcdr (object); | |
838 | |
839 orig_pt = Fwindow_point (window); | |
840 Fset_marker (XWINDOW (window)->sb_point, value, Fwindow_buffer (window)); | |
841 start_pos = scrollbar_point (XWINDOW (window), 1); | |
842 Fset_window_start (window, make_int (start_pos), Qnil); | |
843 scrollbar_reset_cursor (window, orig_pt); | |
844 zmacs_region_stays = 1; | |
845 return Qnil; | |
846 } | |
847 | |
848 DEFUN ("scrollbar-set-hscroll", Fscrollbar_set_hscroll, Sscrollbar_set_hscroll, | |
849 2, 2, 0 /* | |
850 Sets WINDOW's hscroll position to VALUE. | |
851 This ensures that VALUE is in the proper range for the horizontal scrollbar. | |
852 */ ) | |
853 (window, value) | |
854 Lisp_Object window, value; | |
855 { | |
856 struct window *w; | |
857 int hscroll, wcw, max_len; | |
858 | |
859 CHECK_LIVE_WINDOW (window); | |
860 if (!EQ (value, Qmax)) | |
861 CHECK_INT (value); | |
862 | |
863 w = XWINDOW (window); | |
864 wcw = window_char_width (w, 0) - 1; | |
865 max_len = w->max_line_len + 1; | |
866 | |
867 if (EQ (value, Qmax) || (XINT (value) > (max_len - wcw))) | |
868 hscroll = max_len - wcw; | |
869 else | |
870 hscroll = XINT (value); | |
871 | |
872 /* Can't allow this out of set-window-hscroll's acceptable range. */ | |
873 if (hscroll < 0) | |
874 hscroll = 0; | |
875 else if (hscroll >= (1 << (SHORTBITS - 1))) | |
876 hscroll = (1 << (SHORTBITS - 1)) - 1; | |
877 | |
878 if (hscroll != w->hscroll) | |
879 Fset_window_hscroll (window, make_int (hscroll)); | |
880 | |
881 return Qnil; | |
882 } | |
883 | |
884 | |
885 /************************************************************************/ | |
886 /* initialization */ | |
887 /************************************************************************/ | |
888 | |
889 void | |
890 syms_of_scrollbar (void) | |
891 { | |
892 defsymbol (&Qscrollbar_line_up, "scrollbar-line-up"); | |
893 defsymbol (&Qscrollbar_line_down, "scrollbar-line-down"); | |
894 defsymbol (&Qscrollbar_page_up, "scrollbar-page-up"); | |
895 defsymbol (&Qscrollbar_page_down, "scrollbar-page-down"); | |
896 defsymbol (&Qscrollbar_to_top, "scrollbar-to-top"); | |
897 defsymbol (&Qscrollbar_to_bottom, "scrollbar-to-bottom"); | |
898 defsymbol (&Qscrollbar_vertical_drag, "scrollbar-vertical-drag"); | |
899 | |
900 defsymbol (&Qscrollbar_char_left, "scrollbar-char-left"); | |
901 defsymbol (&Qscrollbar_char_right, "scrollbar-char-right"); | |
902 defsymbol (&Qscrollbar_page_left, "scrollbar-page-left"); | |
903 defsymbol (&Qscrollbar_page_right, "scrollbar-page-right"); | |
904 defsymbol (&Qscrollbar_to_left, "scrollbar-to-left"); | |
905 defsymbol (&Qscrollbar_to_right, "scrollbar-to-right"); | |
906 defsymbol (&Qscrollbar_horizontal_drag, "scrollbar-horizontal-drag"); | |
907 | |
908 defsymbol (&Qinit_scrollbar_from_resources, "init-scrollbar-from-resources"); | |
909 | |
910 /* #### All these functions should be moved into Lisp. | |
911 See comment above. */ | |
912 defsubr (&Sscrollbar_line_up); | |
913 defsubr (&Sscrollbar_line_down); | |
914 defsubr (&Sscrollbar_page_up); | |
915 defsubr (&Sscrollbar_page_down); | |
916 defsubr (&Sscrollbar_to_top); | |
917 defsubr (&Sscrollbar_to_bottom); | |
918 defsubr (&Sscrollbar_vertical_drag); | |
919 | |
920 defsubr (&Sscrollbar_set_hscroll); | |
921 } | |
922 | |
923 void | |
924 vars_of_scrollbar (void) | |
925 { | |
926 DEFVAR_LISP ("scrollbar-pointer-glyph", &Vscrollbar_pointer_glyph /* | |
927 *The shape of the mouse-pointer when over a scrollbar. | |
928 This is a glyph; use `set-glyph-image' to change it. | |
929 If unspecified in a particular domain, the window-system-provided | |
930 default pointer is used. | |
931 */ ); | |
932 | |
933 Fprovide (intern ("scrollbar")); | |
934 } | |
935 | |
936 void | |
937 specifier_vars_of_scrollbar (void) | |
938 { | |
939 DEFVAR_SPECIFIER ("scrollbar-width", &Vscrollbar_width /* | |
940 *Width of vertical scrollbars. | |
941 This is a specifier; use `set-specifier' to change it. | |
942 */ ); | |
943 Vscrollbar_width = Fmake_specifier (Qnatnum); | |
944 set_specifier_fallback | |
945 (Vscrollbar_width, | |
946 list1 (Fcons (Qnil, make_int (DEFAULT_SCROLLBAR_WIDTH)))); | |
947 set_specifier_caching (Vscrollbar_width, | |
948 slot_offset (struct window, | |
949 scrollbar_width), | |
950 some_window_value_changed, | |
951 slot_offset (struct frame, | |
952 scrollbar_width), | |
953 scrollbar_width_changed_in_frame); | |
954 | |
955 DEFVAR_SPECIFIER ("scrollbar-height", &Vscrollbar_height /* | |
956 *Height of horizontal scrollbars. | |
957 This is a specifier; use `set-specifier' to change it. | |
958 */ ); | |
959 Vscrollbar_height = Fmake_specifier (Qnatnum); | |
960 set_specifier_fallback | |
961 (Vscrollbar_height, | |
962 list1 (Fcons (Qnil, make_int (DEFAULT_SCROLLBAR_HEIGHT)))); | |
963 set_specifier_caching (Vscrollbar_height, | |
964 slot_offset (struct window, | |
965 scrollbar_height), | |
966 some_window_value_changed, | |
967 slot_offset (struct frame, | |
968 scrollbar_height), | |
969 scrollbar_height_changed_in_frame); | |
970 } | |
971 | |
972 void | |
973 complex_vars_of_scrollbar (void) | |
974 { | |
975 Vscrollbar_pointer_glyph = Fmake_glyph_internal (Qpointer); | |
976 | |
977 set_specifier_caching (XGLYPH (Vscrollbar_pointer_glyph)->image, | |
978 slot_offset (struct window, | |
979 scrollbar_pointer), | |
980 scrollbar_pointer_changed_in_window, | |
981 0, 0); | |
982 } |