Mercurial > hg > xemacs-beta
annotate src/scrollbar-x.c @ 5157:1fae11d56ad2
redo memory-usage mechanism, add way of dynamically initializing Lisp objects
-------------------- ChangeLog entries follow: --------------------
lisp/ChangeLog addition:
2010-03-18 Ben Wing <ben@xemacs.org>
* diagnose.el (show-memory-usage):
Rewrite to take into account API changes in memory-usage functions.
src/ChangeLog addition:
2010-03-18 Ben Wing <ben@xemacs.org>
* alloc.c:
* alloc.c (disksave_object_finalization_1):
* alloc.c (lisp_object_storage_size):
* alloc.c (listu):
* alloc.c (listn):
* alloc.c (Fobject_memory_usage_stats):
* alloc.c (compute_memusage_stats_length):
* alloc.c (Fobject_memory_usage):
* alloc.c (Ftotal_object_memory_usage):
* alloc.c (malloced_storage_size):
* alloc.c (common_init_alloc_early):
* alloc.c (reinit_alloc_objects_early):
* alloc.c (reinit_alloc_early):
* alloc.c (init_alloc_once_early):
* alloc.c (syms_of_alloc):
* alloc.c (reinit_vars_of_alloc):
* buffer.c:
* buffer.c (struct buffer_stats):
* buffer.c (compute_buffer_text_usage):
* buffer.c (compute_buffer_usage):
* buffer.c (buffer_memory_usage):
* buffer.c (buffer_objects_create):
* buffer.c (syms_of_buffer):
* buffer.c (vars_of_buffer):
* console-impl.h (struct console_methods):
* dynarr.c (Dynarr_memory_usage):
* emacs.c (main_1):
* events.c (clear_event_resource):
* extents.c:
* extents.c (compute_buffer_extent_usage):
* extents.c (extent_objects_create):
* extents.h:
* faces.c:
* faces.c (compute_face_cachel_usage):
* faces.c (face_objects_create):
* faces.h:
* general-slots.h:
* glyphs.c:
* glyphs.c (compute_glyph_cachel_usage):
* glyphs.c (glyph_objects_create):
* glyphs.h:
* lisp.h:
* lisp.h (struct usage_stats):
* lrecord.h:
* lrecord.h (enum lrecord_type):
* lrecord.h (struct lrecord_implementation):
* lrecord.h (MC_ALLOC_CALL_FINALIZER_FOR_DISKSAVE):
* lrecord.h (DEFINE_DUMPABLE_LISP_OBJECT):
* lrecord.h (DEFINE_DUMPABLE_SIZABLE_LISP_OBJECT):
* lrecord.h (DEFINE_DUMPABLE_FROB_BLOCK_LISP_OBJECT):
* lrecord.h (DEFINE_DUMPABLE_FROB_BLOCK_SIZABLE_LISP_OBJECT):
* lrecord.h (DEFINE_DUMPABLE_INTERNAL_LISP_OBJECT):
* lrecord.h (DEFINE_DUMPABLE_SIZABLE_INTERNAL_LISP_OBJECT):
* lrecord.h (DEFINE_NODUMP_LISP_OBJECT):
* lrecord.h (DEFINE_NODUMP_SIZABLE_LISP_OBJECT):
* lrecord.h (DEFINE_NODUMP_FROB_BLOCK_LISP_OBJECT):
* lrecord.h (DEFINE_NODUMP_FROB_BLOCK_SIZABLE_LISP_OBJECT):
* lrecord.h (DEFINE_NODUMP_INTERNAL_LISP_OBJECT):
* lrecord.h (DEFINE_NODUMP_SIZABLE_INTERNAL_LISP_OBJECT):
* lrecord.h (MAKE_LISP_OBJECT):
* lrecord.h (DEFINE_DUMPABLE_MODULE_LISP_OBJECT):
* lrecord.h (DEFINE_DUMPABLE_MODULE_SIZABLE_LISP_OBJECT):
* lrecord.h (DEFINE_NODUMP_MODULE_LISP_OBJECT):
* lrecord.h (DEFINE_NODUMP_MODULE_SIZABLE_LISP_OBJECT):
* lrecord.h (MAKE_MODULE_LISP_OBJECT):
* lrecord.h (INIT_LISP_OBJECT):
* lrecord.h (INIT_MODULE_LISP_OBJECT):
* lrecord.h (UNDEF_LISP_OBJECT):
* lrecord.h (UNDEF_MODULE_LISP_OBJECT):
* lrecord.h (DECLARE_LISP_OBJECT):
* lrecord.h (DECLARE_MODULE_API_LISP_OBJECT):
* lrecord.h (DECLARE_MODULE_LISP_OBJECT):
* lstream.c:
* lstream.c (syms_of_lstream):
* lstream.c (vars_of_lstream):
* marker.c:
* marker.c (compute_buffer_marker_usage):
* mc-alloc.c (mc_alloced_storage_size):
* mc-alloc.h:
* mule-charset.c:
* mule-charset.c (struct charset_stats):
* mule-charset.c (compute_charset_usage):
* mule-charset.c (charset_memory_usage):
* mule-charset.c (mule_charset_objects_create):
* mule-charset.c (syms_of_mule_charset):
* mule-charset.c (vars_of_mule_charset):
* redisplay.c:
* redisplay.c (compute_rune_dynarr_usage):
* redisplay.c (compute_display_block_dynarr_usage):
* redisplay.c (compute_glyph_block_dynarr_usage):
* redisplay.c (compute_display_line_dynarr_usage):
* redisplay.c (compute_line_start_cache_dynarr_usage):
* redisplay.h:
* scrollbar-gtk.c (gtk_compute_scrollbar_instance_usage):
* scrollbar-msw.c (mswindows_compute_scrollbar_instance_usage):
* scrollbar-x.c (x_compute_scrollbar_instance_usage):
* scrollbar.c (compute_scrollbar_instance_usage):
* scrollbar.h:
* symbols.c:
* symbols.c (reinit_symbol_objects_early):
* symbols.c (init_symbols_once_early):
* symbols.c (reinit_symbols_early):
* symbols.c (defsymbol_massage_name_1):
* symsinit.h:
* ui-gtk.c:
* ui-gtk.c (emacs_gtk_object_getprop):
* ui-gtk.c (emacs_gtk_object_putprop):
* ui-gtk.c (ui_gtk_objects_create):
* unicode.c (compute_from_unicode_table_size_1):
* unicode.c (compute_to_unicode_table_size_1):
* unicode.c (compute_from_unicode_table_size):
* unicode.c (compute_to_unicode_table_size):
* window.c:
* window.c (struct window_stats):
* window.c (compute_window_mirror_usage):
* window.c (compute_window_usage):
* window.c (window_memory_usage):
* window.c (window_objects_create):
* window.c (syms_of_window):
* window.c (vars_of_window):
* window.h:
Redo memory-usage mechanism, make it general; add way of dynamically
initializing Lisp object types -- OBJECT_HAS_METHOD(), similar to
CONSOLE_HAS_METHOD().
(1) Create OBJECT_HAS_METHOD(), OBJECT_HAS_PROPERTY() etc. for
specifying that a Lisp object type has a particular method or
property. Call such methods with OBJECT_METH, MAYBE_OBJECT_METH,
OBJECT_METH_OR_GIVEN; retrieve properties with OBJECT_PROPERTY.
Methods that formerly required a DEFINE_*GENERAL_LISP_OBJECT() to
specify them (getprop, putprop, remprop, plist, disksave) now
instead use the dynamic-method mechanism. The main benefit of
this is that new methods or properties can be added without
requiring that the declaration statements of all existing methods
be modified. We have to make the `struct lrecord_implementation'
non-const, but I don't think this should have any effect on speed --
the only possible method that's really speed-critical is the
mark method, and we already extract those out into a separate
(non-const) array for increased cache locality.
Object methods need to be reinitialized after pdump, so we put
them in separate functions such as face_objects_create(),
extent_objects_create() and call them appropriately from emacs.c
The only current object property (`memusage_stats_list') that
objects can specify is a Lisp object and gets staticpro()ed so it
only needs to be set during dump time, but because it references
symbols that might not exist in a syms_of_() function, we
initialize it in vars_of_(). There is also an object property
(`num_extra_memusage_stats') that is automatically initialized based
on `memusage_stats_list'; we do that in reinit_vars_of_alloc(),
which is called after all vars_of_() functions are called.
`disksaver' method was renamed `disksave' to correspond with the
name normally given to the function (e.g. disksave_lstream()).
(2) Generalize the memory-usage mechanism in `buffer-memory-usage',
`window-memory-usage', `charset-memory-usage' into an object-type-
specific mechanism called by a single function
`object-memory-usage'. (Former function `object-memory-usage'
renamed to `total-object-memory-usage'). Generalize the mechanism
of different "slices" so that we can have different "classes" of
memory described and different "slices" onto each class; `t'
separates classes, `nil' separates slices. Currently we have
three classes defined: the memory of an object itself,
non-Lisp-object memory associated with the object (e.g. arrays or
dynarrs stored as fields in the object), and Lisp-object memory
associated with the object (other internal Lisp objects stored in
the object). This isn't completely finished yet and we might need
to further separate the "other internal Lisp objects" class into
two classes.
The memory-usage mechanism uses a `struct usage_stats' (renamed
from `struct overhead_stats') to describe a malloc-view onto a set
of allocated memory (listing how much was requested and various
types of overhead) and a more general `struct generic_usage_stats'
(with a `struct usage_stats' in it) to hold all statistics about
object memory. `struct generic_usage_stats' contains an array of
32 Bytecounts, which are statistics of unspecified semantics. The
intention is that individual types declare a corresponding struct
(e.g. `struct window_stats') with the same structure but with
specific fields in place of the array, corresponding to specific
statistics. The number of such statistics is an object property
computed from the list of tags (Lisp symbols describing the
statistics) stored in `memusage_stats_list'. The idea here is to
allow particular object types to customize the number and
semantics of the statistics where completely avoiding consing.
This doesn't matter so much yet, but the intention is to have the
memory usage of all objects computed at the end of GC, at the same
time as other statistics are currently computed. The values for
all statistics for a single type would be added up to compute
aggregate values for all objects of a specific type. To make this
efficient, we can't allow any memory allocation at all.
(3) Create some additional functions for creating lists that
specify the elements directly as args rather than indirectly through
an array: listn() (number of args given), listu() (list terminated
by Qunbound).
(4) Delete a bit of remaining unused C window_config stuff, also
unused lrecord_type_popup_data.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Thu, 18 Mar 2010 10:50:06 -0500 |
parents | 6f2158fa75ed |
children | 6c6d78781d59 |
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>. | |
5050
6f2158fa75ed
Fix quick-build, use asserts() in place of ABORT()
Ben Wing <ben@xemacs.org>
parents:
4976
diff
changeset
|
6 Copyright (C) 2010 Ben Wing. |
428 | 7 |
8 This file is part of XEmacs. | |
9 | |
10 XEmacs is free software; you can redistribute it and/or modify it | |
11 under the terms of the GNU General Public License as published by the | |
12 Free Software Foundation; either version 2, or (at your option) any | |
13 later version. | |
14 | |
15 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
18 for more details. | |
19 | |
20 You should have received a copy of the GNU General Public License | |
21 along with XEmacs; see the file COPYING. If not, write to | |
22 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
23 Boston, MA 02111-1307, USA. */ | |
24 | |
25 /* Synched up with: Not in FSF. */ | |
26 | |
442 | 27 /* This file Mule-ized (more like Mule-verified) by Ben Wing, 7-8-00. */ |
28 | |
428 | 29 #include <config.h> |
30 #include "lisp.h" | |
31 | |
872 | 32 #include "device-impl.h" |
33 #include "frame-impl.h" | |
800 | 34 #include "window.h" |
35 | |
872 | 36 #include "console-x-impl.h" |
428 | 37 #include "glyphs-x.h" |
38 #include "scrollbar-x.h" | |
39 | |
800 | 40 #include "EmacsFrame.h" |
428 | 41 |
42 static void x_update_vertical_scrollbar_callback (Widget widget, LWLIB_ID id, | |
43 XtPointer client_data); | |
44 static void x_update_horizontal_scrollbar_callback (Widget widget, LWLIB_ID id, | |
45 XtPointer client_data); | |
46 | |
47 /* Used to prevent changing the size of the slider while drag | |
48 scrolling, under Motif. This is necessary because the Motif | |
49 scrollbar is incredibly stupid about updating the slider and causes | |
50 lots of flicker if it is done too often. */ | |
51 static int inhibit_slider_size_change; | |
52 int stupid_vertical_scrollbar_drag_hack; | |
53 | |
54 /* Doesn't work with athena */ | |
55 #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID) | |
56 static int vertical_drag_in_progress; | |
57 #endif | |
58 | |
59 | |
60 /* A device method. */ | |
61 static int | |
62 x_inhibit_scrollbar_slider_size_change (void) | |
63 { | |
64 /* Doesn't work with Athena */ | |
65 #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID) | |
66 return inhibit_slider_size_change; | |
67 #else | |
68 return 0; | |
69 #endif | |
70 } | |
71 | |
72 /* A device method. */ | |
73 static void | |
74 x_free_scrollbar_instance (struct scrollbar_instance *instance) | |
75 { | |
3462 | 76 if (instance->scrollbar_data) |
428 | 77 { |
3462 | 78 if (SCROLLBAR_X_NAME (instance)) |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
3462
diff
changeset
|
79 xfree (SCROLLBAR_X_NAME (instance)); |
428 | 80 |
3462 | 81 if (SCROLLBAR_X_WIDGET (instance)) |
82 { | |
83 if (XtIsManaged (SCROLLBAR_X_WIDGET (instance))) | |
84 XtUnmanageChild (SCROLLBAR_X_WIDGET (instance)); | |
428 | 85 |
3462 | 86 lw_destroy_all_widgets (SCROLLBAR_X_ID (instance)); |
87 } | |
88 | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
3462
diff
changeset
|
89 xfree (instance->scrollbar_data); |
3462 | 90 } |
428 | 91 } |
92 | |
93 /* A device method. */ | |
94 static void | |
95 x_release_scrollbar_instance (struct scrollbar_instance *instance) | |
96 { | |
97 if (XtIsManaged (SCROLLBAR_X_WIDGET (instance))) | |
98 XtUnmanageChild (SCROLLBAR_X_WIDGET (instance)); | |
99 } | |
100 | |
101 /* A device method. */ | |
102 static void | |
103 x_create_scrollbar_instance (struct frame *f, int vertical, | |
104 struct scrollbar_instance *instance) | |
105 { | |
106 char buffer[32]; | |
107 | |
108 /* initialize the X specific data section. */ | |
109 instance->scrollbar_data = xnew_and_zero (struct x_scrollbar_data); | |
110 | |
111 SCROLLBAR_X_ID (instance) = new_lwlib_id (); | |
112 sprintf (buffer, "scrollbar_%d", SCROLLBAR_X_ID (instance)); | |
113 SCROLLBAR_X_NAME (instance) = xstrdup (buffer); | |
114 #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID) || \ | |
115 defined (LWLIB_SCROLLBARS_ATHENA3D) | |
116 SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) = -1; | |
117 #endif | |
118 | |
119 if (vertical) | |
120 { | |
121 SCROLLBAR_X_WIDGET (instance) = | |
122 lw_create_widget ("vertical-scrollbar", SCROLLBAR_X_NAME (instance), | |
123 SCROLLBAR_X_ID (instance), | |
124 NULL, FRAME_X_CONTAINER_WIDGET (f), 0, | |
125 x_update_vertical_scrollbar_callback, NULL, NULL); | |
126 } | |
127 else | |
128 { | |
129 SCROLLBAR_X_WIDGET (instance) = | |
130 lw_create_widget ("horizontal-scrollbar", SCROLLBAR_X_NAME (instance), | |
131 SCROLLBAR_X_ID (instance), | |
132 NULL, FRAME_X_CONTAINER_WIDGET (f), 0, | |
133 x_update_horizontal_scrollbar_callback, NULL, NULL); | |
134 } | |
135 } | |
136 | |
137 #define UPDATE_DATA_FIELD(field) \ | |
138 if (new_##field >= 0 && \ | |
139 SCROLLBAR_X_POS_DATA (inst).field != new_##field) { \ | |
140 SCROLLBAR_X_POS_DATA (inst).field = new_##field; \ | |
141 inst->scrollbar_instance_changed = 1; \ | |
142 } | |
143 | |
144 /* A device method. */ | |
145 /* #### The -1 check is such a hack. */ | |
146 static void | |
147 x_update_scrollbar_instance_values (struct window *w, | |
148 struct scrollbar_instance *inst, | |
149 int new_line_increment, | |
150 int new_page_increment, | |
151 int new_minimum, int new_maximum, | |
152 int new_slider_size, | |
153 int new_slider_position, | |
154 int new_scrollbar_width, | |
155 int new_scrollbar_height, | |
156 int new_scrollbar_x, int new_scrollbar_y) | |
157 { | |
158 UPDATE_DATA_FIELD (line_increment); | |
159 UPDATE_DATA_FIELD (page_increment); | |
160 UPDATE_DATA_FIELD (minimum); | |
161 UPDATE_DATA_FIELD (maximum); | |
162 UPDATE_DATA_FIELD (slider_size); | |
163 UPDATE_DATA_FIELD (slider_position); | |
164 UPDATE_DATA_FIELD (scrollbar_width); | |
165 UPDATE_DATA_FIELD (scrollbar_height); | |
166 UPDATE_DATA_FIELD (scrollbar_x); | |
167 UPDATE_DATA_FIELD (scrollbar_y); | |
168 | |
169 /* This doesn't work with Athena, why? */ | |
170 #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID) | |
171 if (w && !vertical_drag_in_progress) | |
172 { | |
173 int new_vov = SCROLLBAR_X_POS_DATA (inst).slider_position; | |
174 int new_vows = marker_position (w->start[CURRENT_DISP]); | |
175 | |
176 if (SCROLLBAR_X_VDRAG_ORIG_VALUE (inst) != new_vov) | |
177 { | |
178 SCROLLBAR_X_VDRAG_ORIG_VALUE (inst) = new_vov; | |
179 inst->scrollbar_instance_changed = 1; | |
180 } | |
181 if (SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (inst) != new_vows) | |
182 { | |
183 SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (inst) = new_vows; | |
184 inst->scrollbar_instance_changed = 1; | |
185 } | |
186 } | |
187 #endif | |
188 } | |
189 | |
190 /* Used by x_update_scrollbar_instance_status. */ | |
191 static void | |
192 update_one_scrollbar_bs (struct frame *f, Widget sb_widget) | |
193 { | |
194 Boolean use_backing_store; | |
195 | |
196 Xt_GET_VALUE (FRAME_X_TEXT_WIDGET (f), XtNuseBackingStore, &use_backing_store); | |
197 | |
198 if (use_backing_store && sb_widget) | |
199 { | |
200 unsigned long mask = CWBackingStore; | |
201 XSetWindowAttributes attrs; | |
202 | |
203 attrs.backing_store = Always; | |
204 XChangeWindowAttributes (XtDisplay (sb_widget), | |
205 XtWindow (sb_widget), | |
206 mask, | |
207 &attrs); | |
208 } | |
209 } | |
210 | |
211 /* Create a widget value structure for passing down to lwlib so that | |
212 it can update the scrollbar widgets. Used by | |
213 x_update_scrollbar_instance_status. */ | |
214 static widget_value * | |
215 scrollbar_instance_to_widget_value (struct scrollbar_instance *instance) | |
216 { | |
217 widget_value *wv; | |
218 | |
219 wv = xmalloc_widget_value (); | |
220 /* #### maybe should add malloc_scrollbar_values to resource these? */ | |
221 wv->scrollbar_data = xnew (scrollbar_values); | |
222 | |
223 wv->name = SCROLLBAR_X_NAME (instance); | |
436 | 224 wv->name = xstrdup (wv->name); |
428 | 225 wv->value = 0; |
226 wv->key = 0; | |
227 wv->enabled = instance->scrollbar_is_active; | |
228 wv->selected = 0; | |
229 wv->call_data = NULL; | |
230 | |
231 *wv->scrollbar_data = SCROLLBAR_X_POS_DATA (instance); | |
232 | |
233 wv->next = NULL; | |
234 | |
235 return wv; | |
236 } | |
237 | |
238 /* Used by x_update_scrollbar_instance_status. */ | |
239 static void | |
240 update_one_widget_scrollbar_pointer (struct window *w, Widget wid) | |
241 { | |
242 if (POINTER_IMAGE_INSTANCEP (w->scrollbar_pointer)) | |
243 { | |
244 XDefineCursor (XtDisplay (wid), XtWindow (wid), | |
245 XIMAGE_INSTANCE_X_CURSOR (w->scrollbar_pointer)); | |
246 XSync (XtDisplay (wid), False); | |
247 } | |
248 } | |
249 | |
250 /* A device method. */ | |
251 static void | |
252 x_update_scrollbar_instance_status (struct window *w, int active, int size, | |
253 struct scrollbar_instance *instance) | |
254 { | |
255 struct frame *f = XFRAME (w->frame); | |
256 Boolean managed = XtIsManaged (SCROLLBAR_X_WIDGET (instance)); | |
257 | |
258 if (active && size) | |
259 { | |
260 widget_value *wv = scrollbar_instance_to_widget_value (instance); | |
261 | |
262 if (instance->scrollbar_instance_changed) | |
263 { | |
264 lw_modify_all_widgets (SCROLLBAR_X_ID (instance), wv, 0); | |
265 instance->scrollbar_instance_changed = 0; | |
266 } | |
267 | |
268 if (!managed) | |
269 { | |
270 XtManageChild (SCROLLBAR_X_WIDGET (instance)); | |
271 if (XtWindow (SCROLLBAR_X_WIDGET (instance))) | |
272 { | |
273 /* Raise this window so that it's visible on top of the | |
274 text window below it. */ | |
275 XRaiseWindow (XtDisplay (SCROLLBAR_X_WIDGET (instance)), | |
276 XtWindow (SCROLLBAR_X_WIDGET (instance))); | |
277 update_one_widget_scrollbar_pointer | |
278 (w, SCROLLBAR_X_WIDGET (instance)); | |
279 if (!SCROLLBAR_X_BACKING_STORE_INITIALIZED (instance)) | |
280 { | |
281 update_one_scrollbar_bs (f, SCROLLBAR_X_WIDGET (instance)); | |
282 SCROLLBAR_X_BACKING_STORE_INITIALIZED (instance) = 1; | |
283 } | |
284 } | |
285 } | |
286 | |
5050
6f2158fa75ed
Fix quick-build, use asserts() in place of ABORT()
Ben Wing <ben@xemacs.org>
parents:
4976
diff
changeset
|
287 assert (wv->scrollbar_data); |
436 | 288 free_widget_value_tree (wv); |
428 | 289 } |
290 else if (managed) | |
291 { | |
292 #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID) | |
293 /* This isn't needed with Athena Scrollbars. It might not be needed */ | |
294 /* with Motif scrollbars (it is apparently needed with Lesstif). */ | |
295 XtUngrabKeyboard (SCROLLBAR_X_WIDGET (instance), CurrentTime); | |
296 #endif | |
297 XtUnmanageChild (SCROLLBAR_X_WIDGET (instance)); | |
298 } | |
299 } | |
300 | |
301 enum x_scrollbar_loop | |
302 { | |
303 X_FIND_SCROLLBAR_WINDOW_MIRROR, | |
304 X_SET_SCROLLBAR_POINTER, | |
305 X_WINDOW_IS_SCROLLBAR, | |
306 X_UPDATE_FRAME_SCROLLBARS | |
307 }; | |
308 | |
309 static struct window_mirror * | |
310 x_scrollbar_loop (enum x_scrollbar_loop type, Lisp_Object window, | |
311 struct window_mirror *mir, | |
312 LWLIB_ID id, Window x_win) | |
313 { | |
314 struct window_mirror *retval = NULL; | |
315 | |
316 while (mir) | |
317 { | |
318 struct scrollbar_instance *vinstance = mir->scrollbar_vertical_instance; | |
319 struct scrollbar_instance *hinstance = mir->scrollbar_horizontal_instance; | |
320 struct window *w = XWINDOW (window); | |
321 | |
322 if (mir->vchild) | |
323 retval = x_scrollbar_loop (type, w->vchild, mir->vchild, id, x_win); | |
324 else if (mir->hchild) | |
325 retval = x_scrollbar_loop (type, w->hchild, mir->hchild, id, x_win); | |
326 if (retval) | |
327 return retval; | |
328 | |
329 if (hinstance || vinstance) | |
330 { | |
331 switch (type) | |
332 { | |
333 case X_FIND_SCROLLBAR_WINDOW_MIRROR: | |
334 if ((vinstance && SCROLLBAR_X_ID (vinstance) == id) || | |
335 (hinstance && SCROLLBAR_X_ID (hinstance) == id)) | |
336 return mir; | |
337 break; | |
338 case X_UPDATE_FRAME_SCROLLBARS: | |
339 if (!mir->vchild && !mir->hchild) | |
340 update_window_scrollbars (w, mir, 1, 0); | |
341 break; | |
342 case X_SET_SCROLLBAR_POINTER: | |
343 if (!mir->vchild && !mir->hchild) | |
344 { | |
345 Widget widget; | |
346 | |
347 widget = SCROLLBAR_X_WIDGET (hinstance); | |
348 if (widget && XtIsManaged (widget)) | |
349 update_one_widget_scrollbar_pointer (w, widget); | |
350 | |
351 widget = SCROLLBAR_X_WIDGET (vinstance); | |
352 if (widget && XtIsManaged (widget)) | |
353 update_one_widget_scrollbar_pointer (w, widget); | |
354 } | |
355 break; | |
356 case X_WINDOW_IS_SCROLLBAR: | |
357 if (!mir->vchild && !mir->hchild) | |
358 { | |
359 Widget widget; | |
360 | |
361 widget = SCROLLBAR_X_WIDGET (hinstance); | |
362 if (widget && XtIsManaged (widget) && | |
363 XtWindow (widget) == x_win) | |
364 return (struct window_mirror *) 1; | |
365 | |
366 widget = SCROLLBAR_X_WIDGET (vinstance); | |
367 if (widget && XtIsManaged (widget) && | |
368 XtWindow (widget) == x_win) | |
369 return (struct window_mirror *) 1; | |
370 } | |
371 break; | |
372 default: | |
2500 | 373 ABORT (); |
428 | 374 } |
375 } | |
376 | |
377 mir = mir->next; | |
378 window = w->next; | |
379 } | |
380 | |
381 return NULL; | |
382 } | |
383 | |
384 /* Used by callbacks. */ | |
385 static struct window_mirror * | |
386 find_scrollbar_window_mirror (struct frame *f, LWLIB_ID id) | |
387 { | |
388 if (f->mirror_dirty) | |
389 update_frame_window_mirror (f); | |
390 return x_scrollbar_loop (X_FIND_SCROLLBAR_WINDOW_MIRROR, f->root_window, | |
617 | 391 XWINDOW_MIRROR (f->root_mirror), id, (Window) NULL); |
428 | 392 } |
393 | |
394 /* | |
395 * This is the only callback provided for vertical scrollbars. It | |
396 * should be able to handle all of the scrollbar events in | |
397 * scroll_action (see lwlib.h). The client data will be of type | |
398 * scroll_event (see lwlib.h). */ | |
399 static void | |
400 x_update_vertical_scrollbar_callback (Widget widget, LWLIB_ID id, | |
401 XtPointer client_data) | |
402 { | |
403 /* This function can GC */ | |
404 scroll_event *data = (scroll_event *) client_data; | |
405 struct device *d = get_device_from_display (XtDisplay (widget)); | |
406 struct frame *f = x_any_window_to_frame (d, XtWindow (widget)); | |
407 Lisp_Object win, frame; | |
408 struct scrollbar_instance *instance; | |
409 struct window_mirror *mirror; | |
410 | |
411 if (!f) | |
412 return; | |
413 | |
414 mirror = find_scrollbar_window_mirror (f, id); | |
442 | 415 if (!mirror) |
416 return; | |
417 | |
428 | 418 win = real_window (mirror, 1); |
419 | |
420 if (NILP (win)) | |
421 return; | |
422 instance = mirror->scrollbar_vertical_instance; | |
423 frame = WINDOW_FRAME (XWINDOW (win)); | |
424 | |
425 /* It seems that this is necessary whenever signal_special_Xt_user_event() | |
426 is called. #### Why??? */ | |
427 DEVICE_X_MOUSE_TIMESTAMP (d) = DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d); | |
428 | |
429 switch (data->action) | |
430 { | |
431 case SCROLLBAR_LINE_UP: | |
432 signal_special_Xt_user_event (frame, Qscrollbar_line_up, win); | |
433 break; | |
434 | |
435 case SCROLLBAR_LINE_DOWN: | |
436 signal_special_Xt_user_event (frame, Qscrollbar_line_down, win); | |
437 break; | |
438 | |
439 /* The Athena scrollbar paging behavior is that of xterms. | |
440 Depending on where you click the size of the page varies. | |
441 Motif always does a standard Emacs page. */ | |
442 case SCROLLBAR_PAGE_UP: | |
443 #if !defined (LWLIB_SCROLLBARS_MOTIF) && !defined (LWLIB_SCROLLBARS_LUCID) && \ | |
444 !defined (LWLIB_SCROLLBARS_ATHENA3D) | |
445 { | |
446 double tmp = ((double) data->slider_value / | |
447 (double) SCROLLBAR_X_POS_DATA(instance).scrollbar_height); | |
448 double line = tmp * | |
449 (double) window_displayed_height (XWINDOW (win)); | |
450 | |
451 if (line > -1.0) | |
452 line = -1.0; | |
453 signal_special_Xt_user_event (frame, Qscrollbar_page_up, | |
454 Fcons (win, make_int ((int) line))); | |
455 } | |
456 #else | |
457 signal_special_Xt_user_event (frame, Qscrollbar_page_up, | |
458 Fcons (win, Qnil)); | |
459 #endif | |
460 break; | |
461 | |
462 case SCROLLBAR_PAGE_DOWN: | |
463 #if !defined (LWLIB_SCROLLBARS_MOTIF) && !defined (LWLIB_SCROLLBARS_LUCID) && \ | |
464 !defined (LWLIB_SCROLLBARS_ATHENA3D) | |
465 { | |
466 double tmp = ((double) data->slider_value / | |
467 (double) SCROLLBAR_X_POS_DATA(instance).scrollbar_height); | |
468 double line = tmp * | |
469 (double) window_displayed_height (XWINDOW (win)); | |
470 | |
471 if (SCROLLBAR_X_POS_DATA(instance).maximum > | |
472 (SCROLLBAR_X_POS_DATA(instance).slider_size + SCROLLBAR_X_POS_DATA(instance).slider_position)) | |
473 { | |
474 if (line < 1.0) | |
475 line = 1.0; | |
476 signal_special_Xt_user_event (frame, Qscrollbar_page_down, | |
477 Fcons (win, | |
478 make_int ((int) line))); | |
479 } | |
480 } | |
481 #else | |
482 signal_special_Xt_user_event (frame, Qscrollbar_page_down, | |
483 Fcons (win, Qnil)); | |
484 #endif | |
485 break; | |
486 | |
487 case SCROLLBAR_TOP: | |
488 signal_special_Xt_user_event (frame, Qscrollbar_to_top, win); | |
489 break; | |
490 | |
491 case SCROLLBAR_BOTTOM: | |
492 signal_special_Xt_user_event (frame, Qscrollbar_to_bottom, win); | |
493 break; | |
494 | |
495 | |
496 case SCROLLBAR_CHANGE: | |
497 inhibit_slider_size_change = 0; | |
498 #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID) | |
499 vertical_drag_in_progress = 0; | |
500 SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) = data->slider_value; | |
501 SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance) = | |
502 XINT (Fwindow_start (win)); | |
503 #else | |
504 stupid_vertical_scrollbar_drag_hack = 0; | |
505 #endif | |
506 break; | |
507 | |
508 case SCROLLBAR_DRAG: | |
509 { | |
510 int value; | |
511 | |
512 inhibit_slider_size_change = 1; | |
513 | |
514 #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID) | |
515 /* Doing drags with Motif-like scrollbars is a mess, since we | |
516 want to avoid having the window position jump when you | |
517 first grab the scrollbar, but we also want to ensure that | |
518 you can scroll all the way to the top or bottom of the | |
519 buffer. This can all be replaced with something sane when | |
520 we get line-based scrolling. */ | |
521 | |
522 vertical_drag_in_progress = 1; | |
523 | |
524 if (SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) < 0) | |
525 { | |
526 SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) = data->slider_value; | |
527 SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance) = | |
528 XINT (Fwindow_start (win)); | |
529 } | |
530 | |
531 /* Could replace this piecewise linear scrolling with a | |
532 quadratic through the three points, but I'm not sure that | |
533 would feel any nicer in practice. */ | |
534 if (data->slider_value < SCROLLBAR_X_VDRAG_ORIG_VALUE (instance)) | |
535 { | |
536 /* We've dragged up; slide linearly from original position to | |
537 window-start=data.minimum, slider-value=data.minimum. */ | |
538 | |
539 if (SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) | |
540 <= SCROLLBAR_X_POS_DATA (instance).minimum) | |
541 { | |
542 /* shouldn't get here, but just in case */ | |
543 value = SCROLLBAR_X_POS_DATA (instance).minimum; | |
544 } | |
545 else | |
546 { | |
547 value = (int) | |
548 (SCROLLBAR_X_POS_DATA (instance).minimum | |
549 + (((double) | |
550 (SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance) | |
551 - SCROLLBAR_X_POS_DATA (instance).minimum) | |
552 * (data->slider_value - | |
553 SCROLLBAR_X_POS_DATA (instance).minimum)) | |
554 / (SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) | |
555 - SCROLLBAR_X_POS_DATA (instance).minimum))); | |
556 } | |
557 } | |
558 else | |
559 { | |
560 /* We've dragged down; slide linearly from original position to | |
561 window-start=data.maximum, slider-value=data.maximum. */ | |
562 | |
563 if (SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) | |
564 >= (SCROLLBAR_X_POS_DATA (instance).maximum - | |
565 SCROLLBAR_X_POS_DATA (instance).slider_size)) | |
566 { | |
567 /* avoid divide by zero */ | |
568 value = SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance); | |
569 } | |
570 else | |
571 { | |
572 value = (int) | |
573 (SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance) | |
574 + (((double) | |
575 (SCROLLBAR_X_POS_DATA (instance).maximum | |
576 - SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance)) | |
577 * (data->slider_value | |
578 - SCROLLBAR_X_VDRAG_ORIG_VALUE (instance))) | |
579 / (SCROLLBAR_X_POS_DATA (instance).maximum | |
580 - SCROLLBAR_X_POS_DATA (instance).slider_size | |
581 - SCROLLBAR_X_VDRAG_ORIG_VALUE (instance)))); | |
582 } | |
583 } | |
584 #else | |
585 stupid_vertical_scrollbar_drag_hack = 0; | |
586 value = data->slider_value; | |
587 #endif | |
588 | |
589 if (value >= SCROLLBAR_X_POS_DATA (instance).maximum) | |
590 value = SCROLLBAR_X_POS_DATA (instance).maximum - 1; | |
591 if (value < SCROLLBAR_X_POS_DATA (instance).minimum) | |
592 value = SCROLLBAR_X_POS_DATA (instance).minimum; | |
593 | |
594 signal_special_Xt_user_event (frame, Qscrollbar_vertical_drag, | |
595 Fcons (win, make_int (value))); | |
596 } | |
597 break; | |
598 | |
599 } | |
600 } | |
601 | |
602 /* | |
603 * This is the only callback provided for horizontal scrollbars. It | |
604 * should be able to handle all of the scrollbar events in | |
605 * scroll_action (see lwlib.h). The client data will be of type | |
606 * scroll_event (see lwlib.h). */ | |
607 static void | |
608 x_update_horizontal_scrollbar_callback (Widget widget, LWLIB_ID id, | |
609 XtPointer client_data) | |
610 { | |
611 scroll_event *data = (scroll_event *) client_data; | |
612 struct device *d = get_device_from_display (XtDisplay (widget)); | |
613 struct frame *f = x_any_window_to_frame (d, XtWindow (widget)); | |
614 Lisp_Object win, frame; | |
615 struct window_mirror *mirror; | |
616 | |
617 if (!f) | |
618 return; | |
619 | |
620 mirror = find_scrollbar_window_mirror (f, id); | |
442 | 621 if (!mirror) |
622 return; | |
623 | |
428 | 624 win = real_window (mirror, 1); |
625 | |
626 if (NILP (win)) | |
627 return; | |
628 frame = WINDOW_FRAME (XWINDOW (win)); | |
629 | |
630 /* It seems that this is necessary whenever signal_special_Xt_user_event() | |
631 is called. #### Why??? */ | |
632 DEVICE_X_MOUSE_TIMESTAMP (d) = DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d); | |
633 | |
634 switch (data->action) | |
635 { | |
636 case SCROLLBAR_LINE_UP: | |
637 signal_special_Xt_user_event (frame, Qscrollbar_char_left, win); | |
638 break; | |
639 case SCROLLBAR_LINE_DOWN: | |
640 signal_special_Xt_user_event (frame, Qscrollbar_char_right, win); | |
641 break; | |
642 case SCROLLBAR_PAGE_UP: | |
643 signal_special_Xt_user_event (frame, Qscrollbar_page_left, win); | |
644 break; | |
645 case SCROLLBAR_PAGE_DOWN: | |
646 signal_special_Xt_user_event (frame, Qscrollbar_page_right, win); | |
647 break; | |
648 case SCROLLBAR_TOP: | |
649 signal_special_Xt_user_event (frame, Qscrollbar_to_left, win); | |
650 break; | |
651 case SCROLLBAR_BOTTOM: | |
652 signal_special_Xt_user_event (frame, Qscrollbar_to_right, win); | |
653 break; | |
654 case SCROLLBAR_CHANGE: | |
655 inhibit_slider_size_change = 0; | |
656 break; | |
657 case SCROLLBAR_DRAG: | |
658 inhibit_slider_size_change = 1; | |
659 /* #### Fix the damn toolkit code so they all work the same way. | |
660 Lucid is the one mostly wrong.*/ | |
661 #if defined (LWLIB_SCROLLBARS_LUCID) || defined (LWLIB_SCROLLBARS_ATHENA3D) | |
662 signal_special_Xt_user_event (frame, Qscrollbar_horizontal_drag, | |
663 (Fcons | |
664 (win, make_int (data->slider_value)))); | |
665 #else | |
666 signal_special_Xt_user_event (frame, Qscrollbar_horizontal_drag, | |
667 (Fcons | |
668 (win, | |
669 make_int (data->slider_value - 1)))); | |
670 #endif | |
671 break; | |
672 default: | |
673 break; | |
674 } | |
675 } | |
676 | |
677 static void | |
678 x_scrollbar_pointer_changed_in_window (struct window *w) | |
679 { | |
793 | 680 Lisp_Object window = wrap_window (w); |
428 | 681 |
682 x_scrollbar_loop (X_SET_SCROLLBAR_POINTER, window, find_window_mirror (w), | |
683 0, (Window) NULL); | |
684 } | |
685 | |
686 /* Make sure that all scrollbars on frame are up-to-date. Called | |
687 directly from x_set_frame_properties in frame-x.c*/ | |
688 void | |
689 x_update_frame_scrollbars (struct frame *f) | |
690 { | |
617 | 691 x_scrollbar_loop (X_UPDATE_FRAME_SCROLLBARS, f->root_window, |
692 XWINDOW_MIRROR (f->root_mirror), 0, (Window) NULL); | |
428 | 693 } |
694 | |
695 #ifdef MEMORY_USAGE_STATS | |
696 | |
697 static int | |
2286 | 698 x_compute_scrollbar_instance_usage (struct device *UNUSED (d), |
428 | 699 struct scrollbar_instance *inst, |
5157
1fae11d56ad2
redo memory-usage mechanism, add way of dynamically initializing Lisp objects
Ben Wing <ben@xemacs.org>
parents:
5050
diff
changeset
|
700 struct usage_stats *ustats) |
428 | 701 { |
702 int total = 0; | |
703 | |
704 while (inst) | |
705 { | |
706 struct x_scrollbar_data *data = | |
707 (struct x_scrollbar_data *) inst->scrollbar_data; | |
708 | |
5157
1fae11d56ad2
redo memory-usage mechanism, add way of dynamically initializing Lisp objects
Ben Wing <ben@xemacs.org>
parents:
5050
diff
changeset
|
709 total += malloced_storage_size (data, sizeof (*data), ustats); |
3024 | 710 total += malloced_storage_size (data->name, 1 + strlen (data->name), |
5157
1fae11d56ad2
redo memory-usage mechanism, add way of dynamically initializing Lisp objects
Ben Wing <ben@xemacs.org>
parents:
5050
diff
changeset
|
711 ustats); |
428 | 712 inst = inst->next; |
713 } | |
714 | |
715 return total; | |
716 } | |
717 | |
718 #endif /* MEMORY_USAGE_STATS */ | |
719 | |
720 | |
721 /************************************************************************/ | |
722 /* initialization */ | |
723 /************************************************************************/ | |
724 | |
725 void | |
726 console_type_create_scrollbar_x (void) | |
727 { | |
728 CONSOLE_HAS_METHOD (x, inhibit_scrollbar_slider_size_change); | |
729 CONSOLE_HAS_METHOD (x, free_scrollbar_instance); | |
730 CONSOLE_HAS_METHOD (x, release_scrollbar_instance); | |
731 CONSOLE_HAS_METHOD (x, create_scrollbar_instance); | |
732 CONSOLE_HAS_METHOD (x, update_scrollbar_instance_values); | |
733 CONSOLE_HAS_METHOD (x, update_scrollbar_instance_status); | |
734 CONSOLE_HAS_METHOD (x, scrollbar_pointer_changed_in_window); | |
735 #ifdef MEMORY_USAGE_STATS | |
736 CONSOLE_HAS_METHOD (x, compute_scrollbar_instance_usage); | |
737 #endif /* MEMORY_USAGE_STATS */ | |
738 } | |
739 | |
740 void | |
741 reinit_vars_of_scrollbar_x (void) | |
742 { | |
743 stupid_vertical_scrollbar_drag_hack = 1; | |
744 } | |
745 | |
746 void | |
747 vars_of_scrollbar_x (void) | |
748 { | |
749 #if defined (LWLIB_SCROLLBARS_LUCID) | |
750 Fprovide (intern ("lucid-scrollbars")); | |
751 #elif defined (LWLIB_SCROLLBARS_MOTIF) | |
752 Fprovide (intern ("motif-scrollbars")); | |
753 #elif defined (LWLIB_SCROLLBARS_ATHENA) | |
754 Fprovide (intern ("athena-scrollbars")); | |
755 #endif | |
756 } |