Mercurial > hg > xemacs-beta
comparison lwlib/lwlib-Xaw.c @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | bcdc7deadc19 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 /* The lwlib interface to Athena widgets. | |
2 Copyright (C) 1993, 1994 Free Software Foundation, Inc. | |
3 | |
4 This file is part of the Lucid Widget Library. | |
5 | |
6 The Lucid Widget Library is free software; you can redistribute it and/or | |
7 modify it under the terms of the GNU General Public License as published by | |
8 the Free Software Foundation; either version 1, or (at your option) | |
9 any later version. | |
10 | |
11 The Lucid Widget Library is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 GNU General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with GNU Emacs; see the file COPYING. If not, write to | |
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
19 | |
20 #include <stdio.h> | |
21 | |
22 #include "lwlib-Xaw.h" | |
23 | |
24 #include <X11/StringDefs.h> | |
25 #include <X11/IntrinsicP.h> | |
26 #include <X11/CoreP.h> | |
27 #include <X11/Shell.h> | |
28 | |
29 #ifdef SCROLLBARS_ATHENA | |
30 #include <X11/Xaw/Scrollbar.h> | |
31 #endif | |
32 #ifdef DIALOGS_ATHENA | |
33 #include <X11/Xaw/Dialog.h> | |
34 #include <X11/Xaw/Form.h> | |
35 #include <X11/Xaw/Command.h> | |
36 #include <X11/Xaw/Label.h> | |
37 #endif | |
38 | |
39 #include <X11/Xatom.h> | |
40 | |
41 static void xaw_generic_callback (Widget, XtPointer, XtPointer); | |
42 | |
43 | |
44 Boolean | |
45 lw_xaw_widget_p (Widget widget) | |
46 { | |
47 return (0 | |
48 #ifdef SCROLLBARS_ATHENA | |
49 || XtIsSubclass (widget, scrollbarWidgetClass) | |
50 #endif | |
51 #ifdef DIALOGS_ATHENA | |
52 || XtIsSubclass (widget, dialogWidgetClass) | |
53 #endif | |
54 ); | |
55 } | |
56 | |
57 #ifdef SCROLLBARS_ATHENA | |
58 static void | |
59 xaw_update_scrollbar (widget_instance *instance, Widget widget, | |
60 widget_value *val) | |
61 { | |
62 if (val->scrollbar_data) | |
63 { | |
64 scrollbar_values *data = val->scrollbar_data; | |
65 float widget_shown, widget_topOfThumb; | |
66 float new_shown, new_topOfThumb; | |
67 | |
68 /* | |
69 * First size and position the scrollbar widget. | |
70 */ | |
71 XtVaSetValues (widget, | |
72 XtNx, data->scrollbar_x, | |
73 XtNy, data->scrollbar_y, | |
74 XtNwidth, data->scrollbar_width, | |
75 XtNheight, data->scrollbar_height, | |
76 0); | |
77 | |
78 /* | |
79 * Now the size the scrollbar's slider. | |
80 */ | |
81 | |
82 XtVaGetValues (widget, | |
83 XtNtopOfThumb, &widget_topOfThumb, | |
84 XtNshown, &widget_shown, | |
85 0); | |
86 | |
87 new_shown = (double) data->slider_size / | |
88 (double) (data->maximum - data->minimum); | |
89 | |
90 new_topOfThumb = (double) (data->slider_position - data->minimum) / | |
91 (double) (data->maximum - data->minimum); | |
92 | |
93 if (new_shown > 1.0) | |
94 new_shown = 1.0; | |
95 if (new_shown < 0) | |
96 new_shown = 0; | |
97 | |
98 if (new_topOfThumb > 1.0) | |
99 new_topOfThumb = 1.0; | |
100 if (new_topOfThumb < 0) | |
101 new_topOfThumb = 0; | |
102 | |
103 if (new_shown != widget_shown || new_topOfThumb != widget_topOfThumb) | |
104 XawScrollbarSetThumb (widget, new_topOfThumb, new_shown); | |
105 } | |
106 } | |
107 #endif /* SCROLLBARS_ATHENA */ | |
108 | |
109 void | |
110 xaw_update_one_widget (widget_instance *instance, Widget widget, | |
111 widget_value *val, Boolean deep_p) | |
112 { | |
113 if (0) | |
114 ; | |
115 #ifdef SCROLLBARS_ATHENA | |
116 else if (XtIsSubclass (widget, scrollbarWidgetClass)) | |
117 { | |
118 xaw_update_scrollbar (instance, widget, val); | |
119 } | |
120 #endif | |
121 #ifdef DIALOGS_ATHENA | |
122 else if (XtIsSubclass (widget, dialogWidgetClass)) | |
123 { | |
124 XtVaSetValues (widget, XtNlabel, val->contents->value, 0); | |
125 } | |
126 else if (XtIsSubclass (widget, commandWidgetClass)) | |
127 { | |
128 Dimension bw = 0; | |
129 XtVaGetValues (widget, XtNborderWidth, &bw, 0); | |
130 if (bw == 0) | |
131 /* Don't let buttons end up with 0 borderwidth, that's ugly... | |
132 Yeah, all this should really be done through app-defaults files | |
133 or fallback resources, but that's a whole different can of worms | |
134 that I don't feel like opening right now. Making Athena widgets | |
135 not look like shit is just entirely too much work. | |
136 */ | |
137 XtVaSetValues (widget, XtNborderWidth, 1, 0); | |
138 | |
139 XtVaSetValues (widget, | |
140 XtNlabel, val->value, | |
141 XtNsensitive, val->enabled, | |
142 /* Force centered button text. Se above. */ | |
143 XtNjustify, XtJustifyCenter, | |
144 0); | |
145 | |
146 XtRemoveAllCallbacks (widget, XtNcallback); | |
147 XtAddCallback (widget, XtNcallback, xaw_generic_callback, instance); | |
148 } | |
149 #endif | |
150 } | |
151 | |
152 void | |
153 xaw_update_one_value (widget_instance *instance, Widget widget, | |
154 widget_value *val) | |
155 { | |
156 /* This function is not used by the scrollbars and those are the only | |
157 Athena widget implemented at the moment so do nothing. */ | |
158 return; | |
159 } | |
160 | |
161 void | |
162 xaw_destroy_instance (widget_instance *instance) | |
163 { | |
164 #ifdef DIALOGS_ATHENA | |
165 if (XtIsSubclass (instance->widget, dialogWidgetClass)) | |
166 /* Need to destroy the Shell too. */ | |
167 XtDestroyWidget (XtParent (instance->widget)); | |
168 else | |
169 #endif | |
170 XtDestroyWidget (instance->widget); | |
171 } | |
172 | |
173 void | |
174 xaw_popup_menu (Widget widget, XEvent *event) | |
175 { | |
176 /* An Athena menubar has not been implemented. */ | |
177 return; | |
178 } | |
179 | |
180 void | |
181 xaw_pop_instance (widget_instance *instance, Boolean up) | |
182 { | |
183 Widget widget = instance->widget; | |
184 | |
185 if (up) | |
186 { | |
187 #ifdef DIALOGS_ATHENA | |
188 if (XtIsSubclass (widget, dialogWidgetClass)) | |
189 { | |
190 /* For dialogs, we need to call XtPopup on the parent instead | |
191 of calling XtManageChild on the widget. | |
192 Also we need to hack the shell's WM_PROTOCOLS to get it to | |
193 understand what the close box is supposed to do!! | |
194 */ | |
195 Display *dpy = XtDisplay (widget); | |
196 Widget shell = XtParent (widget); | |
197 Atom props [2]; | |
198 int i = 0; | |
199 props [i++] = XInternAtom (dpy, "WM_DELETE_WINDOW", False); | |
200 XChangeProperty (dpy, XtWindow (shell), | |
201 XInternAtom (dpy, "WM_PROTOCOLS", False), | |
202 XA_ATOM, 32, PropModeAppend, | |
203 (unsigned char *) props, i); | |
204 | |
205 /* Center the widget in its parent. Why isn't this kind of crap | |
206 done automatically? I thought toolkits were supposed to make | |
207 life easier? | |
208 */ | |
209 { | |
210 unsigned int x, y, w, h; | |
211 Widget topmost = instance->parent; | |
212 w = shell->core.width; | |
213 h = shell->core.height; | |
214 while (topmost->core.parent && XtIsRealized (topmost->core.parent)) | |
215 topmost = topmost->core.parent; | |
216 if (topmost->core.width < w) x = topmost->core.x; | |
217 else x = topmost->core.x + ((topmost->core.width - w) / 2); | |
218 if (topmost->core.height < h) y = topmost->core.y; | |
219 else y = topmost->core.y + ((topmost->core.height - h) / 2); | |
220 XtMoveWidget (shell, x, y); | |
221 } | |
222 | |
223 /* Finally, pop it up. */ | |
224 XtPopup (shell, XtGrabNonexclusive); | |
225 } | |
226 else | |
227 #endif /* DIALOGS_ATHENA */ | |
228 XtManageChild (widget); | |
229 } | |
230 else | |
231 { | |
232 #ifdef DIALOGS_ATHENA | |
233 if (XtIsSubclass (widget, dialogWidgetClass)) | |
234 XtUnmanageChild (XtParent (widget)); | |
235 else | |
236 #endif | |
237 XtUnmanageChild (widget); | |
238 } | |
239 } | |
240 | |
241 | |
242 #ifdef DIALOGS_ATHENA | |
243 /* Dialog boxes */ | |
244 | |
245 static char overrideTrans[] = | |
246 "<Message>WM_PROTOCOLS: lwlib_delete_dialog()"; | |
247 static XtActionProc wm_delete_window (Widget shell, XtPointer closure, | |
248 XtPointer call_data); | |
249 static XtActionsRec xaw_actions [] = { | |
250 {"lwlib_delete_dialog", (XtActionProc) wm_delete_window} | |
251 }; | |
252 static Boolean actions_initted = False; | |
253 | |
254 static Widget | |
255 make_dialog (CONST char* name, Widget parent, Boolean pop_up_p, | |
256 CONST char* shell_title, CONST char* icon_name, | |
257 Boolean text_input_slot, | |
258 Boolean radio_box, Boolean list, | |
259 int left_buttons, int right_buttons) | |
260 { | |
261 Arg av [20]; | |
262 int ac = 0; | |
263 int i, bc; | |
264 char button_name [255]; | |
265 Widget shell; | |
266 Widget dialog; | |
267 Widget button; | |
268 XtTranslations override; | |
269 | |
270 if (! pop_up_p) abort (); /* not implemented */ | |
271 if (text_input_slot) abort (); /* not implemented */ | |
272 if (radio_box) abort (); /* not implemented */ | |
273 if (list) abort (); /* not implemented */ | |
274 | |
275 if (! actions_initted) | |
276 { | |
277 XtAppContext app = XtWidgetToApplicationContext (parent); | |
278 XtAppAddActions (app, xaw_actions, | |
279 sizeof (xaw_actions) / sizeof (xaw_actions[0])); | |
280 actions_initted = True; | |
281 } | |
282 | |
283 override = XtParseTranslationTable (overrideTrans); | |
284 | |
285 ac = 0; | |
286 XtSetArg (av[ac], XtNtitle, shell_title); ac++; | |
287 XtSetArg (av[ac], XtNallowShellResize, True); ac++; | |
288 XtSetArg (av[ac], XtNtransientFor, parent); ac++; | |
289 shell = XtCreatePopupShell ("dialog", transientShellWidgetClass, | |
290 parent, av, ac); | |
291 XtOverrideTranslations (shell, override); | |
292 | |
293 ac = 0; | |
294 dialog = XtCreateManagedWidget (name, dialogWidgetClass, shell, av, ac); | |
295 | |
296 bc = 0; | |
297 button = 0; | |
298 for (i = 0; i < left_buttons; i++) | |
299 { | |
300 ac = 0; | |
301 XtSetArg (av [ac], XtNfromHoriz, button); ac++; | |
302 XtSetArg (av [ac], XtNleft, XtChainLeft); ac++; | |
303 XtSetArg (av [ac], XtNright, XtChainLeft); ac++; | |
304 XtSetArg (av [ac], XtNtop, XtChainBottom); ac++; | |
305 XtSetArg (av [ac], XtNbottom, XtChainBottom); ac++; | |
306 XtSetArg (av [ac], XtNresizable, True); ac++; | |
307 sprintf (button_name, "button%d", ++bc); | |
308 button = XtCreateManagedWidget (button_name, commandWidgetClass, | |
309 dialog, av, ac); | |
310 } | |
311 if (right_buttons) | |
312 { | |
313 /* Create a separator | |
314 | |
315 I want the separator to take up the slack between the buttons on | |
316 the right and the buttons on the left (that is I want the buttons | |
317 after the separator to be packed against the right edge of the | |
318 window) but I can't seem to make it do it. | |
319 */ | |
320 ac = 0; | |
321 XtSetArg (av [ac], XtNfromHoriz, button); ac++; | |
322 /* XtSetArg (av [ac], XtNfromVert, XtNameToWidget (dialog, "label")); ac++; */ | |
323 XtSetArg (av [ac], XtNleft, XtChainLeft); ac++; | |
324 XtSetArg (av [ac], XtNright, XtChainRight); ac++; | |
325 XtSetArg (av [ac], XtNtop, XtChainBottom); ac++; | |
326 XtSetArg (av [ac], XtNbottom, XtChainBottom); ac++; | |
327 XtSetArg (av [ac], XtNlabel, ""); ac++; | |
328 XtSetArg (av [ac], XtNwidth, 30); ac++; /* #### aaack!! */ | |
329 XtSetArg (av [ac], XtNborderWidth, 0); ac++; | |
330 XtSetArg (av [ac], XtNshapeStyle, XmuShapeRectangle); ac++; | |
331 XtSetArg (av [ac], XtNresizable, False); ac++; | |
332 XtSetArg (av [ac], XtNsensitive, False); ac++; | |
333 button = XtCreateManagedWidget ("separator", | |
334 /* labelWidgetClass, */ | |
335 /* This has to be Command to fake out | |
336 the Dialog widget... */ | |
337 commandWidgetClass, | |
338 dialog, av, ac); | |
339 } | |
340 for (i = 0; i < right_buttons; i++) | |
341 { | |
342 ac = 0; | |
343 XtSetArg (av [ac], XtNfromHoriz, button); ac++; | |
344 XtSetArg (av [ac], XtNleft, XtChainRight); ac++; | |
345 XtSetArg (av [ac], XtNright, XtChainRight); ac++; | |
346 XtSetArg (av [ac], XtNtop, XtChainBottom); ac++; | |
347 XtSetArg (av [ac], XtNbottom, XtChainBottom); ac++; | |
348 XtSetArg (av [ac], XtNresizable, True); ac++; | |
349 sprintf (button_name, "button%d", ++bc); | |
350 button = XtCreateManagedWidget (button_name, commandWidgetClass, | |
351 dialog, av, ac); | |
352 } | |
353 | |
354 return dialog; | |
355 } | |
356 | |
357 Widget | |
358 xaw_create_dialog (widget_instance* instance) | |
359 { | |
360 char *name = instance->info->type; | |
361 Widget parent = instance->parent; | |
362 Widget widget; | |
363 Boolean pop_up_p = instance->pop_up_p; | |
364 CONST char *shell_name = 0; | |
365 CONST char *icon_name = 0; | |
366 Boolean text_input_slot = False; | |
367 Boolean radio_box = False; | |
368 Boolean list = False; | |
369 int total_buttons; | |
370 int left_buttons = 0; | |
371 int right_buttons = 1; | |
372 | |
373 switch (name [0]) { | |
374 case 'E': case 'e': | |
375 icon_name = "dbox-error"; | |
376 shell_name = "Error"; | |
377 break; | |
378 | |
379 case 'I': case 'i': | |
380 icon_name = "dbox-info"; | |
381 shell_name = "Information"; | |
382 break; | |
383 | |
384 case 'L': case 'l': | |
385 list = True; | |
386 icon_name = "dbox-question"; | |
387 shell_name = "Prompt"; | |
388 break; | |
389 | |
390 case 'P': case 'p': | |
391 text_input_slot = True; | |
392 icon_name = "dbox-question"; | |
393 shell_name = "Prompt"; | |
394 break; | |
395 | |
396 case 'Q': case 'q': | |
397 icon_name = "dbox-question"; | |
398 shell_name = "Question"; | |
399 break; | |
400 } | |
401 | |
402 total_buttons = name [1] - '0'; | |
403 | |
404 if (name [3] == 'T' || name [3] == 't') | |
405 { | |
406 text_input_slot = False; | |
407 radio_box = True; | |
408 } | |
409 else if (name [3]) | |
410 right_buttons = name [4] - '0'; | |
411 | |
412 left_buttons = total_buttons - right_buttons; | |
413 | |
414 widget = make_dialog (name, parent, pop_up_p, | |
415 shell_name, icon_name, text_input_slot, radio_box, | |
416 list, left_buttons, right_buttons); | |
417 | |
418 return widget; | |
419 } | |
420 #endif /* DIALOGS_ATHENA */ | |
421 | |
422 | |
423 static void | |
424 xaw_generic_callback (Widget widget, XtPointer closure, XtPointer call_data) | |
425 { | |
426 widget_instance *instance = (widget_instance *) closure; | |
427 Widget instance_widget; | |
428 LWLIB_ID id; | |
429 XtPointer user_data; | |
430 | |
431 lw_internal_update_other_instances (widget, closure, call_data); | |
432 | |
433 if (! instance) | |
434 return; | |
435 if (widget->core.being_destroyed) | |
436 return; | |
437 | |
438 instance_widget = instance->widget; | |
439 if (!instance_widget) | |
440 return; | |
441 | |
442 id = instance->info->id; | |
443 | |
444 #if 0 | |
445 user_data = NULL; | |
446 XtVaGetValues (widget, XtNuserData, &user_data, 0); | |
447 #else | |
448 /* Damn! Athena doesn't give us a way to hang our own data on the | |
449 buttons, so we have to go find it... I guess this assumes that | |
450 all instances of a button have the same call data. */ | |
451 { | |
452 widget_value *val = instance->info->val->contents; | |
453 char *name = XtName (widget); | |
454 while (val) | |
455 { | |
456 if (val->name && !strcmp (val->name, name)) | |
457 break; | |
458 val = val->next; | |
459 } | |
460 if (! val) abort (); | |
461 user_data = val->call_data; | |
462 } | |
463 #endif | |
464 | |
465 if (instance->info->selection_cb) | |
466 instance->info->selection_cb (widget, id, user_data); | |
467 } | |
468 | |
469 #ifdef DIALOGS_ATHENA | |
470 | |
471 static XtActionProc | |
472 wm_delete_window (Widget shell, XtPointer closure, XtPointer call_data) | |
473 { | |
474 LWLIB_ID id; | |
475 Widget *kids = 0; | |
476 Widget widget; | |
477 if (! XtIsSubclass (shell, shellWidgetClass)) | |
478 abort (); | |
479 XtVaGetValues (shell, XtNchildren, &kids, 0); | |
480 if (!kids || !*kids) | |
481 abort (); | |
482 widget = kids [0]; | |
483 if (! XtIsSubclass (widget, dialogWidgetClass)) | |
484 abort (); | |
485 id = lw_get_widget_id (widget); | |
486 if (! id) abort (); | |
487 | |
488 { | |
489 widget_info *info = lw_get_widget_info (id); | |
490 if (! info) abort (); | |
491 if (info->selection_cb) | |
492 info->selection_cb (widget, id, (XtPointer) -1); | |
493 } | |
494 | |
495 lw_destroy_all_widgets (id); | |
496 return NULL; | |
497 } | |
498 | |
499 #endif /* DIALOGS_ATHENA */ | |
500 | |
501 | |
502 /* Scrollbars */ | |
503 | |
504 #ifdef SCROLLBARS_ATHENA | |
505 static void | |
506 xaw_scrollbar_scroll (Widget widget, XtPointer closure, XtPointer call_data) | |
507 { | |
508 widget_instance *instance = (widget_instance *) closure; | |
509 LWLIB_ID id; | |
510 scroll_event event_data; | |
511 | |
512 if (!instance || widget->core.being_destroyed) | |
513 return; | |
514 | |
515 id = instance->info->id; | |
516 event_data.slider_value = (int) call_data; | |
517 event_data.time = 0; | |
518 | |
519 if ((int) call_data > 0) | |
520 event_data.action = SCROLLBAR_PAGE_DOWN; | |
521 else | |
522 event_data.action = SCROLLBAR_PAGE_UP; | |
523 | |
524 if (instance->info->pre_activate_cb) | |
525 instance->info->pre_activate_cb (widget, id, (XtPointer) &event_data); | |
526 } | |
527 | |
528 static void | |
529 xaw_scrollbar_jump (Widget widget, XtPointer closure, XtPointer call_data) | |
530 { | |
531 widget_instance *instance = (widget_instance *) closure; | |
532 LWLIB_ID id; | |
533 scroll_event event_data; | |
534 scrollbar_values *val = | |
535 (scrollbar_values *) instance->info->val->scrollbar_data; | |
536 float percent; | |
537 | |
538 if (!instance || widget->core.being_destroyed) | |
539 return; | |
540 | |
541 id = instance->info->id; | |
542 | |
543 percent = * (float *) call_data; | |
544 event_data.slider_value = | |
545 (int) (percent * (float) (val->maximum - val->minimum)) + val->minimum; | |
546 | |
547 event_data.time = 0; | |
548 event_data.action = SCROLLBAR_DRAG; | |
549 | |
550 if (instance->info->pre_activate_cb) | |
551 instance->info->pre_activate_cb (widget, id, (XtPointer) &event_data); | |
552 } | |
553 | |
554 static Widget | |
555 xaw_create_scrollbar (widget_instance *instance, int vertical) | |
556 { | |
557 Arg av[20]; | |
558 int ac = 0; | |
559 Widget scrollbar; | |
560 | |
561 /* #### This is tacked onto the with and height and completely | |
562 screws our geometry management. We should probably make the | |
563 top-level aware of this so that people could have a border but so | |
564 few people use the Athena scrollbar now that it really isn't | |
565 worth the effort, at least not at the moment. */ | |
566 XtSetArg (av [ac], XtNborderWidth, 0); ac++; | |
567 if (vertical) | |
568 { | |
569 XtSetArg (av [ac], XtNorientation, XtorientVertical); ac++; | |
570 } | |
571 else | |
572 { | |
573 XtSetArg (av [ac], XtNorientation, XtorientHorizontal); ac++; | |
574 } | |
575 | |
576 scrollbar = | |
577 XtCreateWidget (instance->info->name, scrollbarWidgetClass, | |
578 instance->parent, av, ac); | |
579 | |
580 XtRemoveAllCallbacks (scrollbar, "jumpProc"); | |
581 XtRemoveAllCallbacks (scrollbar, "scrollProc"); | |
582 | |
583 XtAddCallback (scrollbar, "jumpProc", xaw_scrollbar_jump, | |
584 (XtPointer) instance); | |
585 XtAddCallback (scrollbar, "scrollProc", xaw_scrollbar_scroll, | |
586 (XtPointer) instance); | |
587 | |
588 return scrollbar; | |
589 } | |
590 | |
591 static Widget | |
592 xaw_create_vertical_scrollbar (widget_instance *instance) | |
593 { | |
594 return xaw_create_scrollbar (instance, 1); | |
595 } | |
596 | |
597 static Widget | |
598 xaw_create_horizontal_scrollbar (widget_instance *instance) | |
599 { | |
600 return xaw_create_scrollbar (instance, 0); | |
601 } | |
602 #endif /* SCROLLBARS_ATHENA */ | |
603 | |
604 widget_creation_entry | |
605 xaw_creation_table [] = | |
606 { | |
607 #ifdef SCROLLBARS_ATHENA | |
608 {"vertical-scrollbar", xaw_create_vertical_scrollbar}, | |
609 {"horizontal-scrollbar", xaw_create_horizontal_scrollbar}, | |
610 #endif | |
611 {NULL, NULL} | |
612 }; |