1 /**
2  *
3  * $Id: BaseClass.c,v 1.1 2004/08/28 19:22:43 dannybackx Exp $
4  *
5  * Copyright (C) 1995 Free Software Foundation, Inc.
6  * Copyright (C) 1995-2001 LessTif Development Team
7  *
8  * This file is part of the GNU LessTif Library.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public
21  * License along with this library; if not, write to the Free
22  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  **/
25 
26 static const char rcsid[] = "$Id: BaseClass.c,v 1.1 2004/08/28 19:22:43 dannybackx Exp $";
27 
28 #include <LTconfig.h>
29 
30 #include <stdio.h>
31 #include <string.h>
32 
33 #include <XmI/XmI.h>
34 #include <Xm/XmP.h>
35 #include <Xm/BaseClassP.h>
36 #include <Xm/DisplayP.h>
37 #include <Xm/ExtObjectP.h>
38 #include <Xm/ScreenP.h>
39 #include <Xm/MenuShellP.h>
40 #include <Xm/DragIconP.h>
41 #include <Xm/DropTransP.h>
42 #include <Xm/VendorSEP.h>
43 #include <Xm/DropSMgrP.h>
44 #include <Xm/DialogS.h>
45 
46 #include <X11/RectObjP.h>
47 #include <X11/Xutil.h>
48 
49 #include <XmI/DebugUtil.h>
50 
51 
52 /* For the prototype police */
53 
54 extern XmWrapperData	_XmGetWrapperData(WidgetClass wc);
55 extern void		_XmFreeWrapperData(XmWrapperData data);
56 
57 /* Some global data */
58 XrmQuark XmQmotif = 0;
59 int _XmInheritClass = 0;
60 XmBaseClassExt *_Xm_fastPtr=0;
61 
62 /*
63  * credit where credit is due.  A good portion of the changes made today come
64  * from a patch submitted by Harald Albrecht.  Don't blame him if you don't
65  * like the coding style, though -- that's my fault (MLM).
66  * Danny gets the credit for the XContext hint, though.
67  */
68 extern XmGenericClassExt *
_XmGetClassExtensionPtr(XmGenericClassExt * listHeadPtr,XrmQuark owner)69 _XmGetClassExtensionPtr(XmGenericClassExt *listHeadPtr,
70 			XrmQuark owner)
71 {
72     XmGenericClassExt *ext = listHeadPtr;
73 
74     while (ext && *ext && ((*ext)->record_type != owner))
75     {
76 	ext = (XmGenericClassExt *)&((*ext)->next_extension);
77     }
78 
79     return ext;
80 }
81 
82 
83 extern Boolean
_XmIsSlowSubclass(WidgetClass wc,unsigned int bit)84 _XmIsSlowSubclass(WidgetClass wc,
85 		  unsigned int bit)
86 {
87     XmBaseClassExt *bce;
88 
89     bce = (XmBaseClassExt *)_XmGetBaseClassExtPtr(wc, XmQmotif);
90 
91     if (!bce || !*bce)
92     {
93 	return False;
94     }
95 
96     if (_XmGetFlagsBit((*bce)->flags, bit))
97     {
98 	return True;
99     }
100 
101     return False;
102 }
103 
104 
105 /*
106  * Check a widget class for being a real (core) LessTif widget class. We
107  * consider application defined classes as not being standard (beep) widget
108  * classes.
109  */
110 extern Boolean
_XmIsStandardMotifWidgetClass(WidgetClass wc)111 _XmIsStandardMotifWidgetClass(WidgetClass wc)
112 {
113     XmBaseClassExt *bclass, *super;
114     unsigned char *flags, *sflags;
115     int i;
116 
117     /*
118      * If the widget class in question has no extension record it is
119      * apparently no real LessTif widget class.
120      */
121     bclass = (XmBaseClassExt *)_XmGetBaseClassExtPtr(wc, XmQmotif);
122 
123     if ((bclass == NULL) || (*bclass == NULL))
124     {
125 	return False;
126     }
127 
128     super = (XmBaseClassExt *)_XmGetBaseClassExtPtr(wc->core_class.superclass,
129 						    XmQmotif);
130 
131     /*
132      * If our superclass has no extension record then we may be either
133      * a primitive or manager widget. But we're nice and just check for
134      * one of the fast subclass bits set. If we find a bit set, we assume
135      * for a standard motif class. But we consider only standard motif
136      * flags and not the application defined bits from bit 129 upwards.
137      */
138     if ((super == NULL) || (*super == NULL))
139     {
140 	flags = (*bclass)->flags;
141 
142 	for (i = XmLAST_FAST_SUBCLASS_BIT << 3; i >= 0; i--)
143 	{
144 	    if (flags[i] != 0)
145 	    {
146 		return True;
147 	    }
148 	}
149 
150 	return False;
151     }
152 
153     /*
154      * Now make sure that the fast subclass flags differ at least in one bit.
155      * We only consider the standard motif flags, not the possible application
156      * defined bits from bit 129 on.
157      */
158     flags = (*bclass)->flags;
159     sflags = (*super)->flags;
160 
161     for (i = XmLAST_FAST_SUBCLASS_BIT << 3; i >= 0; i--)
162     {
163 	if (flags[i] != sflags[i])
164 	{
165 	    return True;
166 	}
167     }
168 
169     return False;
170 }
171 
172 
173 /*
174  * according to Harald, this is for backwards compatibility only.  A local
175  * function, BaseClassPartInitialize(), provides the functionality that
176  * used to be here.
177  */
178 extern void
_XmBaseClassPartInitialize(WidgetClass wc)179 _XmBaseClassPartInitialize(WidgetClass wc)
180 {
181 }
182 
183 /* -----------------------------------------------
184  * Widget extension stuff
185  *
186  * why do I always forget about XContexts?  Thanks, guys.
187  * 022296 - Harald pointed out to me today that some of these contexts will
188  * be used when the widget is unitialized, therefore XtWindow(widget) will
189  * return NULL.  Not really a problem with the way they are currently used
190  * (prehook push, posthook pop), but it will be a problem with, say,
191  * VendorShellExt if we set the extension when the widget is unrealized, and
192  * do a get when the widget is realized (the XID part of the context call will
193  * be wrong, thus we won't get the right [if any] context data).  Also, since
194  * they're unitialized, all will use the XID null value, and no longer be
195  * unique.  He suggested that I might get around this problem by using the
196  * widget as the XID, which should take care of the uniqueness problem.  Even
197  * though the methods for, e.g., get_values/set_values have other Widget values,
198  * we know that the program keeps the same value for the life of the widget,
199  * so we should be okay.  Better not use this in class_part_initialize, though.
200  * But then again, why would you...
201  */
202 typedef struct _WidgetStack
203 {
204     struct _WidgetStack *next;
205     XmWidgetExtData data;
206 }
207 XmWidgetExtDataStackRec, *XmWidgetExtDataStackPtr;
208 
209 /*
210  * associate a context with an extension type.
211  */
212 static XContext extContexts[XmDEFAULT_EXTENSION + 1] = { 0 };
213 
214 
215 static XContext
FindAssociatedContext(unsigned int extType)216 FindAssociatedContext(unsigned int extType)
217 {
218     if (extType > XmDEFAULT_EXTENSION)
219     {
220 	_XmError(NULL, "Bad extension type for WidgetExtData.");
221     }
222 
223     if (extContexts[extType] != 0)
224     {
225 	return extContexts[extType];
226     }
227 
228     extContexts[extType] = XUniqueContext();
229 
230     return extContexts[extType];
231 }
232 
233 
234 /*
235  * nondestructively fetch an Extension data record.  Hey Danny, this
236  * looks like a good way to find the VendorShellExt without looping
237  * through Composite children!  Whadaya think?
238  */
239 extern XmWidgetExtData
_XmGetWidgetExtData(Widget widget,unsigned char extType)240 _XmGetWidgetExtData(Widget widget, unsigned char extType)
241 {
242     XContext c = FindAssociatedContext(extType);
243     XmWidgetExtDataStackPtr node;
244 
245     if (XFindContext(XtDisplay(widget), (XID)widget, c, (XPointer *)&node) != 0)
246     {
247 	return NULL;
248     }
249 
250     return node->data;
251 }
252 
253 
254 extern void
_XmFreeWidgetExtData(Widget widget)255 _XmFreeWidgetExtData(Widget widget)
256 {
257 }
258 
259 
260 /*
261  * apparently, these can be chained...
262  */
263 extern void
_XmPushWidgetExtData(Widget widget,XmWidgetExtData data,unsigned char extType)264 _XmPushWidgetExtData(Widget widget,
265 		     XmWidgetExtData data,
266 		     unsigned char extType)
267 {
268     XContext c = FindAssociatedContext(extType);
269     XmWidgetExtDataStackPtr head = NULL, node;
270 
271     node = (XmWidgetExtDataStackPtr)XtCalloc(1,
272 					     sizeof(XmWidgetExtDataStackRec));
273     node->data = data;
274 
275     XFindContext(XtDisplay(widget), (XID)widget, c, (XPointer *)&head);
276 
277     node->next = head;
278 
279     XSaveContext(XtDisplay(widget), (XID)widget, c, (XPointer)node);
280 }
281 
282 
283 extern void
_XmPopWidgetExtData(Widget widget,XmWidgetExtData * dataRtn,unsigned char extType)284 _XmPopWidgetExtData(Widget widget,
285 		    XmWidgetExtData *dataRtn,
286 		    unsigned char extType)
287 {
288     XContext c = FindAssociatedContext(extType);
289     XmWidgetExtDataStackPtr node;
290 
291     if (XFindContext(XtDisplay(widget), (XID)widget, c, (XPointer *)&node) != 0)
292     {
293 	/*
294 	 * Only print this message if the widget is not in the process
295 	 * of being destroyed.
296 	 * This is a case in which the message doesn't make sense...
297 	 */
298 	if (! widget->core.being_destroyed)
299 		_XmError(widget, "No ExtNode to pop!");
300 
301 	*dataRtn = NULL;
302 
303 	return;
304     }
305 
306     if (node->next)
307     {
308 	XSaveContext(XtDisplay(widget), (XID)widget, c,
309 		     (XPointer)node->next);
310     }
311     else
312     {
313 	XDeleteContext(XtDisplay(widget), (XID)widget, c);
314     }
315 
316     *dataRtn = node->data;
317 
318     XtFree((char *)node);
319 }
320 
321 
322 /* -------------------------------------------------------------
323  * Wrapper functions.
324  */
325 /*
326  * Returns the top-most entry on the per-widget-class stack without
327  * removing it from the stack. If the stack is empty or doesn't exists
328  * yet, the entry and the stacks are created on the fly.
329  */
330 XmWrapperData
_XmGetWrapperData(WidgetClass wc)331 _XmGetWrapperData(WidgetClass wc)
332 {
333     XmBaseClassExt *ext, bce;
334 
335     ext = (XmBaseClassExt *)_XmGetBaseClassExtPtr(wc, XmQmotif);
336 
337     if (*ext)
338     {
339 	bce = *ext;
340 
341 	if (bce->version < XmBaseClassExtVersion)
342 	{
343 	    return (XmWrapperData)NULL;
344 	}
345     }
346     else
347     {
348 	bce = (XmBaseClassExt)XtCalloc(1, sizeof(XmBaseClassExtRec));
349 
350 	bce->next_extension = NULL;
351 	bce->record_type = XmQmotif;
352 	bce->version = XmBaseClassExtVersion;
353 	bce->record_size = sizeof(XmBaseClassExtRec);
354 
355 	*ext = bce;
356     }
357 
358     /*
359      * If the wrapper data is missing, create a clean wrapper on-the-fly.
360      */
361     if (bce->wrapperData == NULL)
362     {
363 	bce->wrapperData = (XmWrapperData)XtCalloc(1, sizeof(XmWrapperDataRec));
364     }
365 
366     return bce->wrapperData;
367 }
368 
369 
370 /*
371  * This isn't really necessary! Better fold this into the source at the
372  * appropiate places. Or make it a simple #define --aldi
373  *
374  * MLM: True, but I understand the sentiment.  The four functions taken
375  * together "black box" the interface.  Good information hiding...
376  */
377 extern void
_XmFreeWrapperData(XmWrapperData data)378 _XmFreeWrapperData(XmWrapperData data)
379 {
380     XtFree((char *)data);
381 }
382 
383 
384 /*
385  * Push information about the hooked function pointer on a per-widget-class
386  * stack.
387  *
388  * BTW - The _XmXXXWrapperData() functions should really be static, as
389  * no-one outside this module should be allowed to call them. They are
390  * considered private and no-one outside this module should ever need
391  * them. --aldi
392  *
393  * I made Push and Pop static, but left Get and Free global, after testing
394  * linkage with M*tif.
395  */
396 static XmWrapperData
_XmPushWrapperData(WidgetClass wc)397 _XmPushWrapperData(WidgetClass wc)
398 {
399     XmBaseClassExt *ext, bce;
400     XmWrapperData wrapper = NULL;
401 
402     /*
403      * Try to find the class extension record and if you can't find one,
404      * create one. If we found one, then make sure, it has the right
405      * version number. This way, a widget class with no base class ext.
406      * record will get a fresh one just on-the-fly.
407      */
408     ext = (XmBaseClassExt *)_XmGetBaseClassExtPtr(wc, XmQmotif);
409 
410     /*
411      * Remark: As we do not hand over a NULL pointer to
412      * _XmGetBaseClassExtPtr(), we never get back a NULL pointer. So de-
413      * referencing the pointer returned by _XmGetBaseClassExtPtr() is
414      * just fine here.
415      */
416     if (!*ext)
417     {
418 	bce = (XmBaseClassExt)XtMalloc(sizeof(XmBaseClassExtRec));
419 
420 	bce->next_extension = NULL;
421 	bce->record_type = XmQmotif;
422 	bce->version = XmBaseClassExtVersion;
423 	bce->record_size = sizeof(XmBaseClassExtRec);
424 	bce->wrapperData = NULL;
425 
426 	*ext = bce;
427     }
428 
429     bce = *ext;
430 
431     if (bce->version < XmBaseClassExtVersion)
432     {
433 	return wrapper;
434     }
435 
436     /*
437      * If there is already some wrapper data in the list, then clone the
438      * head wrapper entry of the list. Otherwise allocate a fresh one
439      * filled with zeros.
440      */
441     if (bce->wrapperData != NULL)
442     {
443 	wrapper = (XmWrapperData)XtMalloc(sizeof(XmWrapperDataRec));
444 
445 	memcpy(wrapper, bce->wrapperData, sizeof(XmWrapperDataRec));
446 
447 	wrapper->widgetClass = wc;
448 	wrapper->next = bce->wrapperData;
449     }
450     else
451     {
452 	wrapper = (XmWrapperData)XtMalloc(sizeof(XmWrapperDataRec));
453 
454 	memset(wrapper, 0, sizeof(XmWrapperDataRec));
455     }
456 
457     bce->wrapperData = wrapper;
458 
459     return wrapper;
460 }
461 
462 
463 /*
464  * Pop data from the per-widget-class stack. The wrapper data is *NOT*
465  * freed but instead a pointer to it is returned to the caller. Thus, it's
466  * the caller's responsiblity to free the data later on. And to say it
467  * loud and clear: the wrapper is removen from the list but the memory
468  * isn't freed.
469  */
470 static XmWrapperData
_XmPopWrapperData(WidgetClass wc)471 _XmPopWrapperData(WidgetClass wc)
472 {
473     XmBaseClassExt *ext;
474     XmWrapperData wrapper;
475 
476     ext = (XmBaseClassExt *)_XmGetBaseClassExtPtr(wc, XmQmotif);
477     wrapper = (*ext)->wrapperData;
478 
479     if (wrapper)
480     {
481 	(*ext)->wrapperData = wrapper->next;
482     }
483 
484     return wrapper;
485 }
486 
487 
488 /* ---------------------------------------------------------------------
489  * Following is the realize wrapper stuff. Whereas the wrapper system
490  * for hooking the class_part_init, initialize, set_values and get_values
491  * methods is somewhat... clean, the realize wrapper stuff is going
492  * real dirty! The main reason why this had becoming so clumpsy is to
493  * cope with the way realize methods may be chained up to a class'
494  * superclass:
495  * In principle, there are two ways of chaining. The first one needs
496  * some more work but is also a clean way for chaining (`clean' in the
497  * presence of the wrapper mechanism):
498  *   - DON'T let core_class.realize initially point to your own realize
499  *     method! Use XtInheritRealize instead for a start.
500  *   - During your class_part_init method, core_class.realize has been
501  *     resolved to point to your superclass' realize method. So save
502  *     this pointer in a safe place (probably within your class record).
503  *     Place a pointer to your own realize method into core_class.realize.
504  *   - DON'T use your superclass' core_class.realize pointer but use
505  *     the pointer saved in the step before.
506  * Then in the ClassPartInitLeafWrapper we could have saved the realize
507  * pointer to a wrapper data block and put a pointer to a wrapper into
508  * core_class.realize. The wrapper then in turn had only to ask the widget
509  * for its class and use the realize proc as specified in the wrapper for
510  * that widget class.
511  * FORGET IT! (sigh)
512  * Almost 100% of the widget code available uses a second chaining method:
513  *   - Put a pointer to your realize method into core_class.realize.
514  *   - When chaining, just use core_class.super_class->core_class.realize.
515  * While this is appearently easier to code it renders all attempts useless
516  * to cleanly hook the realize proc. Sigh (once again, I'm repeating myself).
517  * The only solution for this misery that don't break existing code is:
518  * Each wrapper entry gets a distinct level number. That number identifies
519  * on what level below the vendorShell widget class a widget class resides.
520  * In order to assign that number to a wrapper we need a separate wrapper
521  * for each level (that is what the RealizeWrapper<#> procs are good for).
522  * This level number indicates which core_class.realize was intended to
523  * be called.
524  *
525  * All these explanations do apply to the geometry_handler and resize
526  * wrappers, too (sigh, once more...).
527  */
528 
529 /*
530  * Allow for 7 levels of descendants below the vendor shell widget
531  * class. This is an arbitrary setting, but compatible with M*tif.
532  */
533 static void RealizeWrapper(Widget w, XtValueMask *ValueMask,
534 			   XSetWindowAttributes *Attribs,
535 			   int IntentedWrapperDepth);
536 /*
537  * Almost the same as above, but now for the resize stuff.
538  */
539 static void ResizeWrapper(Widget w, int IntentedWrapperDepth);
540 
541 /*
542  * Just as above, but now for the geometry handler stuff.
543  */
544 static XtGeometryResult GeometryHandlerWrapper(Widget w,
545 					       XtWidgetGeometry *request,
546 					       XtWidgetGeometry *reply,
547 					       int IntentedWrapperDepth);
548 
549 /*
550  * max depths for the wrappers
551  */
552 #define MAX_REALIZE_WRAPPER_DEPTH	7
553 #define MAX_RESIZE_WRAPPER_DEPTH	10
554 #define MAX_GEOM_WRAPPER_DEPTH		9
555 
556 /*
557  * shorthand
558  */
559 #define MAKE_REALIZE_WRAPPER(Level) \
560     static void RealizeWrapper##Level(Widget w, XtValueMask *ValueMask, \
561                                       XSetWindowAttributes *Attribs) \
562     { RealizeWrapper(w, ValueMask, Attribs, Level); }
563 
564 #define MAKE_RESIZE_WRAPPER(Level) \
565     static void ResizeWrapper##Level(Widget w) \
566     { ResizeWrapper(w, Level); }
567 
568 
569 #define MAKE_GEOM_WRAPPER(Level) \
570     static XtGeometryResult GeometryHandlerWrapper##Level(Widget w, \
571                                               XtWidgetGeometry *request, \
572                                               XtWidgetGeometry *reply) \
573     { return GeometryHandlerWrapper(w, request, reply, Level); }
574 
575 /*
576  * definitions
577  */
578 MAKE_REALIZE_WRAPPER(0)
579 MAKE_REALIZE_WRAPPER(1)
580 MAKE_REALIZE_WRAPPER(2)
581 MAKE_REALIZE_WRAPPER(3)
582 MAKE_REALIZE_WRAPPER(4)
583 MAKE_REALIZE_WRAPPER(5)
584 MAKE_REALIZE_WRAPPER(6)
585 MAKE_REALIZE_WRAPPER(7)
586 
587 MAKE_RESIZE_WRAPPER(0)
588 MAKE_RESIZE_WRAPPER(1)
589 MAKE_RESIZE_WRAPPER(2)
590 MAKE_RESIZE_WRAPPER(3)
591 MAKE_RESIZE_WRAPPER(4)
592 MAKE_RESIZE_WRAPPER(5)
593 MAKE_RESIZE_WRAPPER(6)
594 MAKE_RESIZE_WRAPPER(7)
595 MAKE_RESIZE_WRAPPER(8)
596 MAKE_RESIZE_WRAPPER(9)
597 MAKE_RESIZE_WRAPPER(10)
598 
599 MAKE_GEOM_WRAPPER(0)
600 MAKE_GEOM_WRAPPER(1)
601 MAKE_GEOM_WRAPPER(2)
602 MAKE_GEOM_WRAPPER(3)
603 MAKE_GEOM_WRAPPER(4)
604 MAKE_GEOM_WRAPPER(5)
605 MAKE_GEOM_WRAPPER(6)
606 MAKE_GEOM_WRAPPER(7)
607 MAKE_GEOM_WRAPPER(8)
608 MAKE_GEOM_WRAPPER(9)
609 
610 static XtRealizeProc RealizeWrappers[] =
611 {
612     RealizeWrapper0,
613     RealizeWrapper1,
614     RealizeWrapper2,
615     RealizeWrapper3,
616     RealizeWrapper4,
617     RealizeWrapper5,
618     RealizeWrapper6,
619     RealizeWrapper7
620 };
621 
622 static XtWidgetProc ResizeWrappers[] =
623 {
624     ResizeWrapper0,
625     ResizeWrapper1,
626     ResizeWrapper2,
627     ResizeWrapper3,
628     ResizeWrapper4,
629     ResizeWrapper5,
630     ResizeWrapper6,
631     ResizeWrapper7,
632     ResizeWrapper8,
633     ResizeWrapper9,
634     ResizeWrapper10
635 };
636 
637 static XtGeometryHandler GeometryWrappers[] =
638 {
639     GeometryHandlerWrapper0,
640     GeometryHandlerWrapper1,
641     GeometryHandlerWrapper2,
642     GeometryHandlerWrapper3,
643     GeometryHandlerWrapper4,
644     GeometryHandlerWrapper5,
645     GeometryHandlerWrapper6,
646     GeometryHandlerWrapper7,
647     GeometryHandlerWrapper8,
648     GeometryHandlerWrapper9
649 };
650 
651 
652 /*
653  * Returns a widget class' depth in relation to the vendor shell widget
654  * class. Any direct subclass of the vendor shell widget class is
655  * considered to be of depth #1. Any widget class not derived from the
656  * vendor shell class will result in an error message. This is much
657  * securer than bombing later with a NULL pointer or even worse getting
658  * strange results and no-one knows why...
659  */
660 static int
RealizeDepth(WidgetClass MyWc)661 RealizeDepth(WidgetClass MyWc)
662 {
663     int depth = 0;
664     WidgetClass wc = MyWc;
665 
666     while ((wc != NULL) && (wc != (WidgetClass)vendorShellWidgetClass))
667     {
668 	depth++;
669 	wc = wc->core_class.superclass;
670     }
671 
672     if (wc == NULL)
673     {
674 	_XmError(NULL,
675 		 "PANIC: widget class \"%s\" tried to take part in the\n"
676 		 "realize posthook mechanism but is not a descendant class of\n"
677 		 "vendorShellWidgetClass.",
678 		 MyWc->core_class.class_name);
679     }
680 
681     if (depth > MAX_REALIZE_WRAPPER_DEPTH)
682     {
683 	_XmError(NULL,
684 		 "SORRY: widget class \"%s\" is subclassed too deep from\n"
685 		 "the vendorShellWidgetClass. Current depth is %i whereas the\n"
686 		 "allowed maximum depth is %d.",
687 		 MyWc->core_class.class_name,
688 		 depth, MAX_REALIZE_WRAPPER_DEPTH);
689     }
690 
691     return depth;
692 }
693 
694 
695 /*
696  * Almost the same as the previous function, but this time the levels
697  * are the distance from the rectObject widget class.
698  */
699 static int
ResizeDepth(WidgetClass MyWc)700 ResizeDepth(WidgetClass MyWc)
701 {
702     int depth = 0;
703     WidgetClass wc = MyWc;
704 
705     while ((wc != NULL) && (wc != (WidgetClass)rectObjClass))
706     {
707 	depth++;
708 	wc = wc->core_class.superclass;
709     }
710 
711     if (wc == NULL)
712     {
713 	/* yes, there are commas missing in the following lines.  No, it's
714 	 * not a mistake.  Let the compiler join the lines.
715 	 */
716 	_XmError(NULL,
717 		 "PANIC: widget class \"%s\" tried to take part in the\n"
718 		 "resize posthook mechanism but is not a descendant class of\n"
719 		 "rectObject. Something strange is happening!",
720 		 MyWc->core_class.class_name);
721     }
722 
723     if (depth >MAX_RESIZE_WRAPPER_DEPTH)
724     {
725 	_XmError(NULL,
726 		 "SORRY: widget class \"%s\" is subclassed too deep from\n"
727 		 "the rectObject widget class. Current depth is %i whereas\n"
728 		 "the allowed maximum depth is %d.",
729 		 MyWc->core_class.class_name,
730 		 depth, MAX_RESIZE_WRAPPER_DEPTH);
731     }
732 
733     return depth;
734 }
735 
736 
737 /*
738  * Same as above, but this time for the geometry handler stuff.
739  */
740 static int
GeomDepth(WidgetClass MyWc)741 GeomDepth(WidgetClass MyWc)
742 {
743     int depth = 0;
744     WidgetClass wc = MyWc;
745 
746     while ((wc != NULL) && (wc != (WidgetClass)rectObjClass))
747     {
748 	depth++;
749 	wc = wc->core_class.superclass;
750     }
751 
752     if (wc == NULL)
753     {
754 	_XmError(NULL,
755 		 "PANIC: widget class \"%s\" tried to take part in the\n"
756 		 "geometry manager posthook mechanism but is not a descendant\n"
757 		 "class of rectObject. Something strange is happening!",
758 		 MyWc->core_class.class_name);
759     }
760 
761     if (depth >MAX_GEOM_WRAPPER_DEPTH)
762     {
763 	_XmError(NULL,
764 		 "SORRY: widget class \"%s\" is subclassed too deep from\n"
765 		 "the rectObject widget class. Current depth is %i whereas\n"
766 		 "the allowed maximum depth is %d.",
767 		 MyWc->core_class.class_name,
768 		 depth, MAX_GEOM_WRAPPER_DEPTH);
769     }
770 
771     return depth;
772 }
773 
774 
775 /*
776  * Initialize the base class extension record of a widget class. The base
777  * class extension record specifies various hooks and other nasty things.
778  * And a widget class can inherit these nasties from its ancestors. This
779  * what we implement here. You know: the failures of the parents will be
780  * punished 'til the fifth generation...
781  *
782  * This function is private to this module! No need to export it... or
783  * someone else may really call it --aldi
784  *
785  * The next static extension record just serves as a reservoir for zeros
786  * (respective NULLs). It is used whenever a widget's superclass has no
787  * extension record.
788  */
789 static XmBaseClassExtRec DummySuperClassExtension = { 0 };
790 
791 static void (*ObjectClassPartInit)(WidgetClass c) = NULL;
792 static Boolean (*ObjectSetValues)(Widget old, Widget request, Widget new_w,
793 				  ArgList args, Cardinal *num_args) = NULL;
794 
795 
796 /*
797  * Much the same as XtIsSubclass(). But this time it checks whether a
798  * widget *class* is a subclass of some other class. This function is
799  * useful not only to us, but also to others. That may be the reason why
800  * M*tif 2.0 now exports it.
801  */
802 Boolean
_XmIsSubclassOf(WidgetClass wc,WidgetClass sclass)803 _XmIsSubclassOf(WidgetClass wc, WidgetClass sclass)
804 {
805     WidgetClass parent = wc;
806 
807     while (parent && parent != sclass)
808     {
809 	parent = parent->core_class.superclass;
810     }
811 
812     if (parent == sclass)
813     {
814 	return True;
815     }
816 
817     return False;
818 }
819 
820 
821 /*
822  * figure out if this widget class is one of those that needs inheritance
823  * wrapper help.
824  */
825 static void
ResolveWrappers(WidgetClass wc,WidgetClass sclass)826 ResolveWrappers(WidgetClass wc, WidgetClass sclass)
827 {
828     XmWrapperData Wrapper, SuperWrapper;
829 
830     Wrapper = _XmGetWrapperData(wc);
831     SuperWrapper = _XmGetWrapperData(sclass);
832 
833     /*
834      * Only the vendor shell class and its subclasses will take part in
835      * the realize wrapper game...
836      */
837     if (_XmIsSubclassOf(wc, vendorShellWidgetClass))
838     {
839 
840 	/*
841 	 * If the widget class wants to inherit the realize method from
842 	 * its superclass then use the function pointer stored with the
843 	 * superclass' extension record. Otherwise use the pointer as
844 	 * specified in the class record and store it in the extension
845 	 * record. The extension record will always hold the real pointer
846 	 * whereas the core_class.realize field points to a wrapper.
847 	 * NOTE: we assert here vendorShellWidgetClass->core_class.realize
848 	 *       is NOT (to repeat: NOT) set to XtInheritRealize!!!
849 	 */
850 	if (wc->core_class.realize == XtInheritRealize)
851 	{
852 	    if (SuperWrapper->realize)
853 	    {
854 		Wrapper->realize = SuperWrapper->realize;
855 	    }
856 	    else
857 	    {
858 		Wrapper->realize = sclass->core_class.realize;
859 	    }
860 	}
861 	else
862 	{
863 	    Wrapper->realize = wc->core_class.realize;
864 	}
865 
866 	wc->core_class.realize = RealizeWrappers[RealizeDepth(wc)];
867     }
868 
869     if (_XmIsSubclassOf(wc, rectObjClass))
870     {
871 
872 	if (wc->core_class.resize == XtInheritResize)
873 	{
874 	    if (SuperWrapper->resize)
875 	    {
876 		Wrapper->resize = SuperWrapper->resize;
877 	    }
878 	    else
879 	    {
880 		Wrapper->resize = sclass->core_class.resize;
881 	    }
882 	}
883 	else
884 	{
885 	    Wrapper->resize = wc->core_class.resize;
886 	}
887 
888 	wc->core_class.resize = ResizeWrappers[ResizeDepth(wc)];
889     }
890 
891 #define C_C(wc) ((CompositeClassRec *) wc)
892 
893     if (_XmIsSubclassOf(wc, compositeWidgetClass))
894     {
895 	if (C_C(wc)->composite_class.geometry_manager ==
896 	    XtInheritGeometryManager)
897 	{
898 	    if (SuperWrapper->geometry_manager)
899 	    {
900 		Wrapper->geometry_manager = SuperWrapper->geometry_manager;
901 	    }
902 	    else
903 	    {
904 		Wrapper->geometry_manager =
905 		    C_C(sclass)->composite_class.geometry_manager;
906 	    }
907 	}
908 	else
909 	{
910 	    Wrapper->geometry_manager =
911 		C_C(wc)->composite_class.geometry_manager;
912 	}
913 
914 	C_C(wc)->composite_class.geometry_manager =
915 	    GeometryWrappers[GeomDepth(wc)];
916     }
917 #undef C_C
918 }
919 
920 
921 static XmBaseClassExt *
BaseClassPartInitialize(WidgetClass wc)922 BaseClassPartInitialize(WidgetClass wc)
923 {
924     XmBaseClassExt *ext = NULL, *sext = NULL;
925     XmBaseClassExt new_ext, super_ext;
926     Boolean need_ext = False;
927     WidgetClass sclass;
928     Boolean need_wrappers = False;
929 
930     /*
931      * Some widget classes desperatly need a base class extension record
932      * despite the fact that their superclass has no extension record.
933      * The widget classes concerned of that problem are those with
934      * superclasses which are  Xt 'kernel' classes. And the Xt intrinsics
935      * have no knowledge of the dreaded things we're doing here... Sigh,
936      * in former times all things were better!
937      *
938      * --aldi: Testing M*tif's bce records using the wctest programs shows
939      * that the list of widget classes below is more than sufficient. Running
940      * wctest indicates that all these widget classes have their own bce
941      * record anyway. So the test below is overcautious -- at least when
942      * LessTif has reached a certain quality and all those widget classes
943      * have their own bce records attached to their class records.
944      */
945     if (wc == (WidgetClass)&vendorShellClassRec ||	/* wmShell:: */
946 	wc == (WidgetClass)&xmPrimitiveClassRec ||	/* core:: */
947 	wc == (WidgetClass)&xmGadgetClassRec ||		/* rectObj:: */
948 	wc == (WidgetClass)&xmManagerClassRec ||	/* constraint:: */
949 	wc == (WidgetClass)&xmDisplayClassRec ||	/* applicationShell:: */
950 	wc == (WidgetClass)&xmScreenClassRec ||		/* core:: */
951 	wc == (WidgetClass)&xmMenuShellClassRec ||	/* overrideShell:: */
952 	wc == (WidgetClass)&xmExtClassRec)		/* object:: */
953     {
954 	need_ext = True;
955     }
956     else if (wc == (WidgetClass)&rectObjClassRec ||
957 	     wc == (WidgetClass)&compositeClassRec)
958     {
959 	need_wrappers = True;
960     }
961 
962     /*
963      * Ask for a base class extension record of the widget class to be
964      * initialized. Also ask the superclass for its base class extension
965      * record.
966      */
967     sclass = wc->core_class.superclass;
968 
969     ext = _XmGetBaseClassExtPtr(wc, XmQmotif);
970 
971     /*
972      * If someone really should instanciate an Object...
973      */
974     if (sclass)
975     {
976 	sext = _XmGetBaseClassExtPtr(sclass, XmQmotif);
977     }
978 
979     DEBUGOUT(_LtDebug(__FILE__, NULL,
980 		      "BaseClassPartInit on %s with %s base ext rec.\n",
981 		      wc->core_class.class_name,
982 		      (ext && *ext) ? "a" : "NO!"));
983 
984     DEBUGOUT(_LtDebug(__FILE__, NULL,
985 		      "BaseClassPartInit: sclass %s with %s base ext rec.\n",
986 		      wc->core_class.superclass->core_class.class_name,
987 		      (sext && *sext) ? "a" : "NO!"));
988 
989     /*
990      * If the superclass doesn't have a base class extension record and
991      * our widget class hasn't a base class extension record either and
992      * it doesn't need one at all, say goodby to it all! We do hereby
993      * sort out all those crazy widget classes which have an extension
994      * record but are not subclassed of any LessTif widget class.
995      */
996     if (!need_ext)
997     {
998 
999 	if (need_wrappers)
1000 	{
1001 	    ResolveWrappers(wc, sclass);
1002 	    return ext;
1003 	}
1004 
1005 	if (!sext || !*sext)
1006 	{
1007 
1008 	    /*
1009 	     * Unfortunatly, the set_values, get_values and initialize
1010 	     * hooks may trigger nevertheless.
1011 	     */
1012 	    if (ext && *ext)
1013 	    {
1014 		_XmWarning(NULL,
1015 			   "Widget class %s has a base extension record, but\n\
1016 			its superclass %s has not. Using the hook mechanism\n\
1017 			will cause trouble.\n",
1018 			   wc->core_class.class_name,
1019 			   wc->core_class.superclass->core_class.class_name);
1020 
1021 		return (XmBaseClassExt *)NULL;
1022 	    }
1023 	}
1024     }
1025 
1026     /*
1027      * The next one should never happen! Or something very bad is going on.
1028      */
1029     if (!ext)
1030     {
1031 	return (XmBaseClassExt *)NULL;
1032     }
1033 
1034     if (!*ext)
1035     {
1036 	/*
1037 	 * In case this widget class has no class extension record
1038 	 * but needs one for LessTif's sake, set up a base class
1039 	 * extension record and therefore force the use of default
1040 	 * hook procedures.
1041 	 * The whole bunch here is necessary in order to support application
1042 	 * defined widget classes which are inherited from widget classes
1043 	 * of the LessTif 'core'. So every user contributed class gets
1044 	 * a base class extension record if it does not already have one.
1045 	 *
1046 	 * MLM: Is this really true?  Run-time testing of TearOffButton seemed
1047 	 * to indicate that this class had no base extension...
1048 	 */
1049 	XmBaseClassExt p;
1050 	DEBUGOUT(_LtDebug(__FILE__, NULL,
1051 			  "BaseClassPartInit(): %s got bce record on the fly\n",
1052 			  wc->core_class.class_name));
1053 
1054 	*ext = p = (XmBaseClassExt)XtCalloc(sizeof(XmBaseClassExtRec), 1);
1055 	p->record_type = XmQmotif;
1056 	p->version = XmBaseClassExtVersion;
1057 	p->record_size = sizeof(XmBaseClassExtRec);
1058 	p->classPartInitPrehook = XmInheritClassPartInitPrehook;
1059 	p->classPartInitPosthook = XmInheritClassPartInitPosthook;
1060 	p->initializePrehook = XmInheritInitializePrehook;
1061 	p->initializePosthook = XmInheritInitializePosthook;
1062 	p->setValuesPrehook = XmInheritSetValuesPrehook;
1063 	p->setValuesPosthook = XmInheritSetValuesPosthook;
1064 	p->getValuesPrehook = XmInheritGetValuesPrehook;
1065 	p->getValuesPosthook = XmInheritGetValuesPosthook;
1066 	p->secondaryObjectClass = XmInheritClass;
1067 	p->secondaryObjectCreate = XmInheritSecObjectCreate;
1068 	p->getSecResData = XmInheritGetSecResData;
1069 	p->widgetNavigable = XmInheritWidgetNavigable;
1070 	p->focusChange = XmInheritFocusChange;
1071     }
1072 
1073     /*
1074      * Let us be notorious and always clean the flags. The flags have
1075      * to be set during the class_part_init method of a widget class.
1076      */
1077     memset((*ext)->flags, 0, 32);
1078 
1079     /*
1080      * If the superclass hasn't a base class extension record, use
1081      * a dummy record filled with NULLs. This way we never end up with
1082      * unintentionally unresolved XtInherits. On the other side the
1083      * message XtInherit spits out when it gets accidently called may
1084      * help more than a silent ignore.
1085      */
1086     new_ext = *ext;
1087 
1088     if (!*sext)
1089     {
1090 	super_ext = &DummySuperClassExtension;
1091     }
1092     else
1093     {
1094 	super_ext = *sext;
1095 
1096 	if (super_ext == NULL)
1097 	{
1098 	    super_ext = &DummySuperClassExtension;
1099 	}
1100     }
1101 
1102     if (new_ext->classPartInitPrehook == XmInheritClassPartInitPrehook)
1103     {
1104 	new_ext->classPartInitPrehook = super_ext->classPartInitPrehook;
1105     }
1106 
1107     if (new_ext->classPartInitPosthook == XmInheritClassPartInitPosthook)
1108     {
1109 	new_ext->classPartInitPosthook = super_ext->classPartInitPosthook;
1110     }
1111 
1112     if (new_ext->initializePrehook == XmInheritInitializePrehook)
1113     {
1114 	new_ext->initializePrehook = super_ext->initializePrehook;
1115     }
1116 
1117     if (new_ext->initializePosthook == XmInheritInitializePosthook)
1118     {
1119 	new_ext->initializePosthook = super_ext->initializePosthook;
1120     }
1121 
1122     if (new_ext->setValuesPrehook == XmInheritSetValuesPrehook)
1123     {
1124 	new_ext->setValuesPrehook = super_ext->setValuesPrehook;
1125     }
1126 
1127     if (new_ext->setValuesPosthook == XmInheritSetValuesPosthook)
1128     {
1129 	new_ext->setValuesPosthook = super_ext->setValuesPosthook;
1130     }
1131 
1132     if (new_ext->secondaryObjectClass == XmInheritClass)
1133     {
1134 	new_ext->secondaryObjectClass = super_ext->secondaryObjectClass;
1135     }
1136 
1137     if (new_ext->secondaryObjectCreate == XmInheritSecObjectCreate)
1138     {
1139 	new_ext->secondaryObjectCreate = super_ext->secondaryObjectCreate;
1140     }
1141 
1142     if (new_ext->getValuesPrehook == XmInheritGetValuesPrehook)
1143     {
1144 	new_ext->getValuesPrehook = super_ext->getValuesPrehook;
1145     }
1146 
1147     if (new_ext->getValuesPosthook == XmInheritGetValuesPosthook)
1148     {
1149 	new_ext->getValuesPosthook = super_ext->getValuesPosthook;
1150     }
1151 
1152     if (new_ext->widgetNavigable == XmInheritWidgetNavigable)
1153     {
1154 	new_ext->widgetNavigable = super_ext->widgetNavigable;
1155     }
1156 
1157     if (new_ext->focusChange == XmInheritFocusChange)
1158     {
1159 	new_ext->focusChange = super_ext->focusChange;
1160     }
1161 
1162     if (new_ext->getSecResData == XmInheritGetSecResData)
1163     {
1164 	new_ext->getSecResData = super_ext->getSecResData;
1165     }
1166 
1167     ResolveWrappers(wc, sclass);
1168 
1169     return ext;
1170 }
1171 
1172 
1173 /*
1174  * A wrapper shrinked over a widget class' realize procedure. This is
1175  * called from the RealizeWrapper<#> funcions with the last param
1176  * "WrapperDepth" specifying the wrapper number the cpu was taking.
1177  */
1178 static void
RealizeWrapper(Widget w,XtValueMask * ValueMask,XSetWindowAttributes * Attribs,int IntentedWrapperDepth)1179 RealizeWrapper(Widget w, XtValueMask *ValueMask,
1180 	       XSetWindowAttributes *Attribs, int IntentedWrapperDepth)
1181 {
1182     int WindUp;
1183     WidgetClass wc = XtClass(w);
1184     XmWidgetExtData ext;
1185     XmWrapperData wrap;
1186 
1187     /*
1188      * If someone tries to fool us, return immediatly. This is just
1189      * defensive programming... and will effectively hide the real
1190      * cause of the core dump suddenly appearing lateron...
1191      */
1192     if (!XtIsSubclass(w, vendorShellWidgetClass))
1193     {
1194 	return;
1195     }
1196 
1197     /*
1198      * Call the real realize procedure. We can't never stumple over
1199      * a XtInherit pointer because the vendor shell widget class has
1200      * its own realize procedure. NULL pointers aren't allowed either.
1201      * Well, in theory _XmGetWrapperData may fail to locate a valid
1202      * wrapper data block and create one on the fly which contains
1203      * only NULL pointers. Thus, I'm defensive once again and catch
1204      * such catastrophies.
1205      */
1206     WindUp = RealizeDepth(wc) - IntentedWrapperDepth;
1207 
1208     if (WindUp > 0)
1209     {
1210 	do
1211 	{
1212 	    wc = wc->core_class.superclass;
1213 	}
1214 	while (--WindUp > 0);
1215     }
1216 
1217     wrap = _XmGetWrapperData(wc);
1218     if (wrap == NULL || wrap->realize == NULL)
1219     {
1220 	_XmError(w, "PANIC: no realize procedure specified for this widget.");
1221     }
1222 
1223     wrap->realize(w, ValueMask, Attribs);
1224 
1225     ext = _XmGetWidgetExtData(w, XmSHELL_EXTENSION);
1226 
1227 /*    if (ext != NULL && ext->widget != NULL && !XmIsDialogShell(w)) */
1228     if (ext != NULL && ext->widget != NULL && wc != xmDialogShellWidgetClass)
1229     {
1230 	/*
1231 	 * Check for a callback list to be executed (the only exception
1232 	 * is the XmDialogShell class which has no such callback list).
1233 	 */
1234 	XtCallCallbackList(ext->widget,
1235 			   VSEP_RealizeCallback(ext->widget),
1236 			   NULL);
1237     }
1238 }
1239 
1240 
1241 static void
ResizeWrapper(Widget w,int IntentedWrapperDepth)1242 ResizeWrapper(Widget w, int IntentedWrapperDepth)
1243 {
1244     int WindUp;
1245     WidgetClass wc = XtClass(w);
1246     XmWrapperData WrapperData;
1247     Boolean need_navig = False;
1248     static Boolean recurse = False;
1249 
1250     WindUp = ResizeDepth(wc) - IntentedWrapperDepth;
1251 
1252     if (WindUp > 0)
1253     {
1254 	do
1255 	{
1256 	    wc = wc->core_class.superclass;
1257 	}
1258 	while (--WindUp > 0);
1259     }
1260 
1261     /* _XmNavigResize is only used for shell widgets */
1262     if (XtParent(w) != NULL && XtIsShell(XtParent(w)))
1263     {
1264 	need_navig = True;
1265     }
1266 
1267     /*
1268      * For the resize wrapper it is just fine to have no resize method.
1269      */
1270     WrapperData = _XmGetWrapperData(wc);
1271 
1272     if (WrapperData != NULL && WrapperData->resize != NULL)
1273     {
1274 	if (!recurse && _XmDropSiteWrapperCandidate(w))
1275 	{
1276 	    recurse = True;
1277 
1278 	    XmDropSiteStartUpdate(w);
1279 	    WrapperData->resize(w);
1280 	    XmDropSiteEndUpdate(w);
1281 
1282 	    recurse = False;
1283 	}
1284 	else
1285 	{
1286 	    WrapperData->resize(w);
1287 	}
1288     }
1289 
1290     if (need_navig)
1291     {
1292 	_XmNavigResize(w);
1293     }
1294 }
1295 
1296 
1297 /*
1298  * fun with GeoUtils showed me why this was broken.  Remember how a
1299  * geometry manager is called with the child requesting the change?
1300  * Well, guess which Widget class we should use....  The parent's!
1301  */
1302 static XtGeometryResult
GeometryHandlerWrapper(Widget w,XtWidgetGeometry * request,XtWidgetGeometry * reply,int IntentedWrapperDepth)1303 GeometryHandlerWrapper(Widget w, XtWidgetGeometry *request,
1304 		       XtWidgetGeometry *reply, int IntentedWrapperDepth)
1305 {
1306     int WindUp;
1307     WidgetClass wc = XtClass(XtParent(w));
1308     XmWrapperData WrapperData;
1309     static Boolean recurse = False;
1310     XtGeometryResult ret;
1311 
1312     DEBUGOUT(_LtDebug(__FILE__, w, "GeometryHandlerWrapper(%d) : request %s\n",
1313 		      IntentedWrapperDepth, _LtDebugWidgetGeometry2String(request)));
1314 
1315     WindUp = GeomDepth(wc) - IntentedWrapperDepth;
1316 
1317     if (WindUp > 0)
1318     {
1319 	do
1320 	{
1321 	    wc = wc->core_class.superclass;
1322 	}
1323 	while (--WindUp > 0);
1324     }
1325 
1326     WrapperData = _XmGetWrapperData(wc);
1327 
1328     if (WrapperData == NULL || WrapperData->geometry_manager == NULL)
1329     {
1330 	_XmError(XtParent(w),
1331 		 "PANIC: no geometry_manager procedure "
1332 		 "specified for this widget: %s:%s.",
1333 		 XtClass(XtParent(w))->core_class.class_name,
1334 		 XtName(XtParent(w)));
1335     }
1336 
1337     if (!recurse && _XmDropSiteWrapperCandidate(w))
1338     {
1339 	recurse = True;
1340 
1341 	XmDropSiteStartUpdate(w);
1342 	ret = WrapperData->geometry_manager(w, request, reply);
1343 	XmDropSiteEndUpdate(w);
1344 
1345 	recurse = False;
1346     }
1347     else
1348     {
1349 	ret = WrapperData->geometry_manager(w, request, reply);
1350     }
1351 
1352     return ret;
1353 }
1354 
1355 
1356 /* ---------------------------------------------------------------------
1357  * Following is the implementation of the hook wrapper mechanism. In
1358  * order to do pre- and post-processing before/after a widget's class
1359  * methods have been called a wrapper mechanism is used: every wrapper
1360  * consists of a root and a leaf function. The root function replaces
1361  * whatever method installed in the object class and is setup by
1362  * _XmInitializeExtensions(). The pointers to the old methods are
1363  * stored in some global variables in order to call them later in the
1364  * root wrapper level. That root wrapper then checks for a pre-hook and
1365  * call it if one is available. The root wrapper also replaces the
1366  * function pointer to a class method that would have been called as
1367  * the last method by a pointer to the leaf wrapper. In turn, the leaf
1368  * wrapper then calls that last method, restores the original function
1369  * pointer and calls the post-hook function. Any questions remaining...?
1370  */
1371 
1372 
1373 /*
1374  * This is the ClassPartInit method's post-hook. It calls the last
1375  * ClassPartInit method in the chain and then restores the original
1376  * function pointer to that particular last method.
1377  */
1378 static void
ClassPartInitLeafWrapper(WidgetClass widget_class)1379 ClassPartInitLeafWrapper(WidgetClass widget_class)
1380 {
1381     XmBaseClassExt *bce = NULL;
1382     XmWrapperData wrap;
1383 
1384     bce = ((XmBaseClassExt *)_XmGetBaseClassExtPtr(widget_class, XmQmotif));
1385 
1386     if (!bce || !*bce)
1387     {
1388 	return;
1389     }
1390 
1391     wrap = (XmWrapperData)(*bce)->wrapperData;
1392 
1393     if (wrap->classPartInitLeaf)
1394     {
1395 	(wrap->classPartInitLeaf)(widget_class);
1396     }
1397 
1398     if ((*bce)->classPartInitPosthook)
1399     {
1400 	((*bce)->classPartInitPosthook)(widget_class);
1401     }
1402 
1403     widget_class->core_class.class_part_initialize = wrap->classPartInitLeaf;
1404 
1405     wrap->classPartInitLeaf = NULL;
1406 }
1407 
1408 
1409 /*
1410  * This ClassPartInit pre-hook is called as the first method whenever a
1411  * new widget class gets initialized.
1412  *
1413  * HEY! What about recursion?! I hope that no-one ever initializes
1414  * another widget class from within his class part init method (and that
1415  * widget class is a subclass of the current widget class).
1416  */
1417 static void
ClassPartInitRootWrapper(WidgetClass widget_class)1418 ClassPartInitRootWrapper(WidgetClass widget_class)
1419 {
1420     XmBaseClassExt *bce = NULL;
1421     XmWrapperData wrap;
1422 
1423     bce = BaseClassPartInitialize(widget_class);
1424 
1425     if (!bce || !*bce)
1426     {
1427 	if (ObjectClassPartInit)
1428 	{
1429 	    (ObjectClassPartInit)(widget_class);
1430 	}
1431 
1432 	return;
1433     }
1434 
1435     if ((*bce)->classPartInitPrehook)
1436     {
1437 	((*bce)->classPartInitPrehook)(widget_class);
1438     }
1439 
1440     if (ObjectClassPartInit)
1441     {
1442 	(ObjectClassPartInit)(widget_class);
1443     }
1444 
1445     if ((*bce)->classPartInitPosthook)
1446     {
1447 	wrap = _XmGetWrapperData(widget_class);
1448 
1449 	if (widget_class->core_class.class_part_initialize !=
1450 	    ClassPartInitLeafWrapper)
1451 	{
1452 
1453 	    wrap->classPartInitLeaf =
1454 		widget_class->core_class.class_part_initialize;
1455 
1456 	    widget_class->core_class.class_part_initialize =
1457 		ClassPartInitLeafWrapper;
1458 	}
1459     }
1460 }
1461 
1462 
1463 /*
1464  * Initialize posthook stuff.
1465  * it is called just before the last init has been called and then redirects
1466  * the control to the last one before activating the post-hook.
1467  */
1468 static void
InitializeLeafWrapper(Widget request,Widget new_w,ArgList args,Cardinal * num_args)1469 InitializeLeafWrapper(Widget request, Widget new_w,
1470 		      ArgList args, Cardinal *num_args)
1471 {
1472     WidgetClass wc = XtClass(new_w);
1473     XmBaseClassExt *bce = NULL;
1474     XmWrapperData wrap;
1475 
1476     bce = ((XmBaseClassExt *)_XmGetBaseClassExtPtr(wc, XmQmotif));
1477 
1478     if (!bce || !*bce)
1479     {
1480 	return;
1481     }
1482 
1483     if ((*bce)->initializePosthook)
1484     {
1485 
1486 	/*
1487 	 * If we're not a shell and our parent is constraint, then
1488 	 * the hook was installed in the class record's constraint part of
1489 	 * our parent.
1490 	 * MLM:  Ahhh.  Somebody said something about this, but I missed the
1491 	 * real meaning.
1492 	 */
1493 	if (!XtIsShell(new_w) && XtParent(new_w) &&
1494 	    XtIsConstraint(XtParent(new_w)))
1495 	{
1496 	    wc = XtClass(XtParent(new_w));
1497 
1498 	    wrap = _XmPopWrapperData(wc);
1499 
1500 	    ((ConstraintClassRec *)wc)->constraint_class.initialize =
1501 		wrap->initializeLeaf;
1502 	}
1503 	else
1504 	{
1505 	    wrap = _XmPopWrapperData(wc);
1506 
1507 	    wc->core_class.initialize = wrap->initializeLeaf;
1508 	}
1509 
1510 	if (wrap->initializeLeaf)
1511 	{
1512 	    (wrap->initializeLeaf)(request, new_w, args, num_args);
1513 	}
1514 
1515 	((*bce)->initializePosthook)(request, new_w, args, num_args);
1516 
1517 	_XmFreeWrapperData(wrap);
1518     }
1519 }
1520 
1521 
1522 /*
1523  * The initialze pre-hook is called on any fresh widget instance before
1524  * any other initialize method has ever seen this new_w widget.
1525  */
1526 static void
InitializeRootWrapper(Widget request,Widget new_w,ArgList args,Cardinal * num_args)1527 InitializeRootWrapper(Widget request, Widget new_w,
1528 		      ArgList args, Cardinal *num_args)
1529 {
1530     WidgetClass wc = XtClass(new_w);
1531     XmBaseClassExt *bce = NULL;
1532     XmWrapperData wrap;
1533 
1534     bce = ((XmBaseClassExt *)_XmGetBaseClassExtPtr(wc, XmQmotif));
1535 
1536     if (!bce || !*bce)
1537     {
1538 	return;
1539     }
1540 
1541     /*
1542      * If there is a pre-hook... call it! And if there's a post-hook
1543      * hook it up! But don't forget to check for a constraint parent.
1544      * In this case the parent's constraint initialize method will
1545      * be called after the widget's initialize method (+ superclasses)
1546      * has been called.
1547      */
1548     if ((*bce)->initializePrehook)
1549     {
1550 	((*bce)->initializePrehook)(request, new_w, args, num_args);
1551     }
1552 
1553     if ((*bce)->initializePosthook)
1554     {
1555 	if (!XtIsShell(new_w) && XtParent(new_w) &&
1556 	    XtIsConstraint(XtParent(new_w)))
1557 	{
1558 	    wc = XtClass(XtParent(new_w));
1559 	    wrap = _XmPushWrapperData(wc);
1560 
1561 	    wrap->initializeLeaf =
1562 		((ConstraintClassRec *)wc)->constraint_class.initialize;
1563 
1564 	    ((ConstraintClassRec *)wc)->constraint_class.initialize
1565 		= InitializeLeafWrapper;
1566 	}
1567 	else
1568 	{
1569 	    wrap = _XmPushWrapperData(wc);
1570 
1571 	    wrap->initializeLeaf = wc->core_class.initialize;
1572 
1573 	    wc->core_class.initialize = InitializeLeafWrapper;
1574 	}
1575     }
1576 }
1577 
1578 
1579 /*
1580  * This is the set_values post-hook. It is called as the last set_values
1581  * method in the chain and in turn calls the real last set_values method
1582  * and the post-hook. 'nuff said.
1583  */
1584 static Boolean
SetValuesLeafWrapper(Widget old,Widget request,Widget new_w,ArgList args,Cardinal * num_args)1585 SetValuesLeafWrapper(Widget old, Widget request, Widget new_w,
1586 		     ArgList args, Cardinal *num_args)
1587 {
1588     WidgetClass wc = XtClass(new_w);
1589     XmBaseClassExt *bce = NULL;
1590     XmWrapperData wrap;
1591     Boolean refresh = False;
1592 
1593     bce = ((XmBaseClassExt *)_XmGetBaseClassExtPtr(wc, XmQmotif));
1594 
1595     if (!bce || !*bce)
1596 	return False;
1597 
1598     if ((*bce)->setValuesPosthook)
1599     {
1600 	if (!XtIsShell(new_w) && XtParent(new_w) &&
1601 	    XtIsConstraint(XtParent(new_w)))
1602 	{
1603 	    wrap = _XmPopWrapperData(XtClass(XtParent(new_w)));
1604 	    wc = XtClass(XtParent(new_w));
1605 	    (((ConstraintClassRec *)wc)->constraint_class.set_values)
1606 		= wrap->setValuesLeaf;
1607 	}
1608 	else
1609 	{
1610 	    wrap = _XmPopWrapperData(wc);
1611 
1612 	    wc->core_class.set_values = wrap->setValuesLeaf;
1613 	}
1614 
1615 	if (wrap->setValuesLeaf != NULL)
1616 	{
1617 	    refresh = wrap->setValuesLeaf(old, request, new_w, args, num_args);
1618 	}
1619 
1620 	refresh |= (*bce)->setValuesPosthook(old, request, new_w,
1621 					     args, num_args);
1622 
1623 	_XmFreeWrapperData(wrap);
1624     }
1625 
1626     return refresh;
1627 }
1628 
1629 
1630 /*
1631  * This SetValues pre-hook is called before any set_values methods whenever
1632  * a XtSetValues() call occures. We then call the registered pre-hook for
1633  * this widget class -- if there is one. And if there is a registered
1634  * post-hook we'll install a special post-hook proc. This proc is then
1635  * called as the last set_values method and calls then the original
1636  * set_values handler as well as the post-hook.
1637  */
1638 static Boolean
SetValuesRootWrapper(Widget old,Widget request,Widget new_w,ArgList args,Cardinal * num_args)1639 SetValuesRootWrapper(Widget old, Widget request, Widget new_w,
1640 		     ArgList args, Cardinal *num_args)
1641 {
1642     WidgetClass wc = XtClass(request);
1643     XmBaseClassExt *bce = NULL;
1644     XmWrapperData wrap;
1645     Boolean refresh = False;
1646 
1647     bce = ((XmBaseClassExt *)_XmGetBaseClassExtPtr(wc, XmQmotif));
1648 
1649     if (!bce || !*bce)
1650     {
1651 	if (ObjectSetValues)
1652 	{
1653 	    return (ObjectSetValues) (old, request, new_w, args, num_args);
1654 	}
1655     }
1656 
1657     if ((*bce)->setValuesPrehook)
1658     {
1659 	refresh = ((*bce)->setValuesPrehook)(old, request, new_w,
1660 					     args, num_args);
1661     }
1662 
1663     /*
1664      * If this widget has a constraint resources, then the
1665      * setValues method of our parent will be called after all the
1666      * setValues methods of our class and superclasses. In that
1667      * case we have to hook in the setValues method of the parent.
1668      */
1669     if ((*bce)->setValuesPosthook)
1670     {
1671 	if (!XtIsShell(new_w) && XtParent(new_w) &&
1672 	    XtIsConstraint(XtParent(new_w)))
1673 	{
1674 	    wrap = _XmPushWrapperData(XtClass(XtParent(new_w)));
1675 
1676 	    wc = XtClass(XtParent(new_w));
1677 
1678 	    wrap->setValuesLeaf
1679 		= ((ConstraintClassRec *)wc)->constraint_class.set_values;
1680 
1681 	    (((ConstraintClassRec *)wc)->constraint_class.set_values)
1682 		= SetValuesLeafWrapper;
1683 	}
1684 	else
1685 	{
1686 	    wrap = _XmPushWrapperData(wc);
1687 
1688 	    wrap->setValuesLeaf = wc->core_class.set_values;
1689 
1690 	    wc->core_class.set_values = SetValuesLeafWrapper;
1691 	}
1692     }
1693 
1694     if (ObjectSetValues)
1695     {
1696 	refresh |= (ObjectSetValues)(old, request, new_w, args, num_args);
1697     }
1698 
1699     return refresh;
1700 }
1701 
1702 
1703 /*
1704  * The GetValues post-hook is called after any get_values_hook methods of
1705  * the current widget's class and superclasses. But it is called BEFORE any
1706  * potential parent's constraint get_values_hook method. Yeah, what a
1707  * design!
1708  */
1709 static void
GetValuesLeafWrapper(Widget w,ArgList args,Cardinal * num_args)1710 GetValuesLeafWrapper(Widget w, ArgList args, Cardinal *num_args)
1711 {
1712     WidgetClass wc = XtClass(w);
1713     XmBaseClassExt *bce = NULL;
1714     XmWrapperData wrap;
1715 
1716     bce = ((XmBaseClassExt *)_XmGetBaseClassExtPtr(wc, XmQmotif));
1717 
1718     if (!bce || !*bce)
1719     {
1720 	return;
1721     }
1722 
1723     if ((*bce)->getValuesPosthook)
1724     {
1725 	wrap = _XmPopWrapperData(wc);
1726 
1727 	wc->core_class.get_values_hook = wrap->getValuesLeaf;
1728 
1729 	if (wrap->getValuesLeaf)
1730 	{
1731 	    (wrap->getValuesLeaf)(w, args, num_args);
1732 	}
1733 
1734 	((*bce)->getValuesPosthook)(w, args, num_args);
1735 
1736 	_XmFreeWrapperData(wrap);
1737     }
1738 }
1739 
1740 
1741 /*
1742  * The GetValues pre-hook is called before any other get_values_hook method.
1743  * But there's a problem with the post-hook function. It isn't called as the
1744  * last function in the chain in SOME circumstances. If a widget uses the
1745  * constraint get_values_hook by defining the appropiate extensions record
1746  * then the hook will be called BEFORE all constraint get_values_hook(s).
1747  * The csf did a clean design, really. Clean of operability. So let us stick
1748  * at 100% compatibility for two (IMHO maybe silly) reasons:
1749  * 1. The whole pre- & post-hook stuff is undocumented, so don't you dare
1750  *    to use it with your self-written widgets. And even if the stuff would
1751  *    have been documented, you surely wouldn't dare to use it either...
1752  * 2. The LessTif widgets don't need the post-hook to be called AFTER all
1753  *    constraint get_values_hooks. So we simply don't worry about it.
1754  * BTW - shall we consider recursive operations? Argh, I'm going crazy
1755  * on this!! --aldi
1756  * MLM: Yes, you have to consider recursion.  If you don't, people who do
1757  * a GetValues, for example, in initialize methods will be in extreme pain.
1758  * I had to change _XmGetUnitType because of this (it used to do a GetValues,
1759  * but is called from ImportArgs in ResInd).
1760  * MLM 2:  I looked, and the Constraint class adds a separate GetValues
1761  * hook.  What is done with that?
1762  */
1763 static void
GetValuesRootWrapper(Widget w,ArgList args,Cardinal * num_args)1764 GetValuesRootWrapper(Widget w, ArgList args, Cardinal *num_args)
1765 {
1766     WidgetClass wc = XtClass(w);
1767     XmBaseClassExt *bce = NULL;
1768     XmWrapperData wrap;
1769 
1770     bce = ((XmBaseClassExt *)_XmGetBaseClassExtPtr(wc, XmQmotif));
1771 
1772     if (!bce || !*bce)
1773     {
1774 	return;
1775     }
1776 
1777     if ((*bce)->getValuesPrehook)
1778     {
1779 	((*bce)->getValuesPrehook)(w, args, num_args);
1780     }
1781 
1782     if ((*bce)->getValuesPosthook)
1783     {
1784 	wrap = _XmPushWrapperData(wc);
1785 
1786 	wrap->getValuesLeaf = wc->core_class.get_values_hook;
1787 
1788 	wc->core_class.get_values_hook = GetValuesLeafWrapper;
1789     }
1790 }
1791 
1792 
1793 /*
1794  * Initialize the dreaded extension mechanism. This new extension is needed
1795  * in LessTif in order to pre- or postprocess some toolkit operations. This
1796  * initialization is done only once during the creation of the first
1797  * vendorShell.
1798  * MLM: Possibly, but I'm gonna make sure it's called by putting in the
1799  * lesstif core widgets -- Gadget, Primitive, Manager, VendorShell.
1800  */
1801 extern void
_XmInitializeExtensions(void)1802 _XmInitializeExtensions(void)
1803 {
1804     /* We want to use the same as Motif, so our
1805      * widgets can be used with theirs. -- Chris */
1806     if (XmQmotif == 0)
1807     {
1808 	XmQmotif = XrmStringToQuark("OSF_MOTIF");
1809     }
1810 
1811     /* for why this happens, see testXm/baseclass/test3.c */
1812     if (ObjectClassPartInit == NULL)
1813     {
1814 
1815 	ObjectClassPartInit = objectClassRec.object_class.class_part_initialize;
1816 	ObjectSetValues = objectClassRec.object_class.set_values;
1817 
1818 	objectClassRec.object_class.class_part_initialize
1819 	    = ClassPartInitRootWrapper;
1820 	objectClassRec.object_class.initialize = InitializeRootWrapper;
1821 	objectClassRec.object_class.set_values = SetValuesRootWrapper;
1822 	objectClassRec.object_class.get_values_hook = GetValuesRootWrapper;
1823     }
1824 }
1825 
1826 
1827 /*
1828  * Assumption: widgets that have subresources use this as a helper
1829  * function when their getSecResData BaseClassExt function is called.
1830  * Testing shows that the resources are uncompiled -- thus the call
1831  * to _XmTransformSubResources...  Note the two allocations, and their
1832  * relationship to testXm/baseclass/test5.c.  Now to figure out who uses
1833  * it.
1834  */
1835 extern Cardinal
_XmSecondaryResourceData(XmBaseClassExt bce,XmSecondaryResourceData ** secResDataRtn,XtPointer client_data,String name,String class_name,XmResourceBaseProc basefunctionpointer)1836 _XmSecondaryResourceData(XmBaseClassExt bce,
1837 			 XmSecondaryResourceData **secResDataRtn,
1838 			 XtPointer client_data,
1839 			 String name,
1840 			 String class_name,
1841 			 XmResourceBaseProc basefunctionpointer)
1842 {
1843     XmSecondaryResourceData sec, *sd;
1844     WidgetClass wc;
1845 
1846     if (!bce)
1847     {
1848 	return 0;
1849     }
1850 
1851     if (!bce->secondaryObjectClass)
1852     {
1853 	return 0;
1854     }
1855 
1856     sec = (XmSecondaryResourceData)XtCalloc(1,
1857 					    sizeof(XmSecondaryResourceDataRec));
1858 
1859     wc = bce->secondaryObjectClass;
1860 
1861     sec->name = name;
1862     sec->res_class = class_name;
1863     sec->client_data = client_data;
1864     sec->base_proc = basefunctionpointer;
1865 
1866     _XmTransformSubResources(wc->core_class.resources,
1867 			     wc->core_class.num_resources,
1868 			     &sec->resources, &sec->num_resources);
1869 
1870     sd = (XmSecondaryResourceData *)XtMalloc(sizeof(XmSecondaryResourceData));
1871 
1872     *sd = sec;
1873     *secResDataRtn = sd;
1874 
1875     return 1;
1876 }
1877 
1878 
1879 /*
1880  * Testing shows that calling this function before and after instantiation
1881  * of a widget results in uncompiled resources.  So I assume that this
1882  * guy can "decompile" resources (test by instantiating a subpart).
1883  * Unfortunately, a call to GetSubresources will compile the list (broken,
1884  * broken, broken), and this call won't work if you haven't instantiated
1885  * an object (the "owner" field in the BaseClassExt isn't set until
1886  * class_intialize), thus the following crap.
1887  */
1888 extern void
_XmTransformSubResources(XtResourceList comp_resources,Cardinal num_comp_resources,XtResourceList * resources,Cardinal * num_resources)1889 _XmTransformSubResources(XtResourceList comp_resources,
1890 			 Cardinal num_comp_resources,
1891 			 XtResourceList *resources,
1892 			 Cardinal *num_resources)
1893 {
1894     XtResourceList res;
1895     Cardinal i;
1896 
1897     if (num_comp_resources == 0)
1898     {
1899 	*resources = NULL;
1900 	*num_resources = 0;
1901 	return;
1902     }
1903 
1904     res = (XtResourceList)XtCalloc(num_comp_resources, sizeof(XtResource));
1905 
1906     if ((int)(comp_resources[0].resource_offset) >= 0)
1907     {
1908 	memcpy(res, comp_resources, sizeof(XtResource) * num_comp_resources);
1909     }
1910     else
1911     {
1912 	/*
1913 	 * invert the compilation: ripped off from GetResList.c (X11R6).
1914 	 */
1915 	for (i = 0; i < num_comp_resources; i++)
1916 	{
1917 	    res[i].resource_name
1918 		= XrmQuarkToString((XrmQuark)(long)comp_resources[i].resource_name);
1919 	    res[i].resource_class
1920 		= XrmQuarkToString((XrmQuark)(long)comp_resources[i].resource_class);
1921 	    res[i].resource_type
1922 		= XrmQuarkToString((XrmQuark)(long)comp_resources[i].resource_type);
1923 	    /* MLM: sigh.  For want of a nail...  I coulda saved myself days if
1924 	     * I'da done this in the first place */
1925 	    res[i].resource_size
1926 		= comp_resources[i].resource_size;
1927 	    res[i].resource_offset
1928 		= -((int)comp_resources[i].resource_offset + 1);
1929 	    res[i].default_type
1930 		= XrmQuarkToString((XrmQuark)(long)comp_resources[i].default_type);
1931 	    res[i].default_addr
1932 		= comp_resources[i].default_addr;
1933 	}
1934     }
1935 
1936     *resources = res;
1937     *num_resources = num_comp_resources;
1938 }
1939 
1940 
1941 /*
1942  * lo and behold, there is a man page for this one.
1943  * According to OSF/Motif Programmer's Reference, page 1-539, there are
1944  * three things to free: the resources, the block, and the block array
1945  * (see testXm/baseclass/test5.c).
1946  */
1947 extern Cardinal
XmGetSecondaryResourceData(WidgetClass w_class,XmSecondaryResourceData ** secondaryDataRtn)1948 XmGetSecondaryResourceData(WidgetClass w_class,
1949 			   XmSecondaryResourceData **secondaryDataRtn)
1950 
1951 {
1952     XmBaseClassExt *bce = NULL;
1953 
1954     DEBUGOUT(_LtDebug(__FILE__, NULL,
1955 		      "XmGetSecondaryResourceData() called on %s.\n",
1956 		      w_class->core_class.class_name));
1957 
1958     bce = _XmGetBaseClassExtPtr(w_class, XmQmotif);
1959 
1960     if (!bce || !*bce)
1961     {
1962 	return 0;
1963     }
1964 
1965     if ((*bce)->getSecResData == NULL)
1966     {
1967 	return 0;
1968     }
1969 
1970     return ((*bce)->getSecResData)(w_class, secondaryDataRtn);
1971 }
1972