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