1/*
2
3Copyright 1989, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25*/
26
27/*
28 * Author:  Chris D. Peterson, Dave Sternlicht, MIT X Consortium
29 */
30
31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34#include <X11/IntrinsicP.h>	/* To get into the composite and core widget
35				   structures. */
36#include <X11/ObjectP.h>	/* For XtIs<Classname> macros. */
37#include <X11/StringDefs.h>	/* for XtRString. */
38#include <X11/ShellP.h>		/* for Application Shell Widget class. */
39
40#include <X11/Xatom.h>
41#include <X11/Xos.h>		/* for strcpy declaration */
42#include <X11/Xfuncs.h>
43#include <X11/Xmu/EditresP.h>
44#include <X11/Xmd.h>
45#include <X11/Xmu/CharSet.h>
46#include <X11/Xmu/SysUtil.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50
51#define _XEditResPutBool _XEditResPut8
52#define _XEditResPutResourceType _XEditResPut8
53
54/*
55 * Types
56 */
57typedef enum {
58    BlockNone,
59    BlockSetValues,
60    BlockAll
61} EditresBlock;
62
63typedef struct _SetValuesEvent {
64    EditresCommand type;		/* first field must be type */
65    WidgetInfo *widgets;
66    unsigned short num_entries;		/* number of set values requests */
67    char *name;
68    char *res_type;
69    XtPointer value;
70    unsigned short value_len;
71} SetValuesEvent;
72
73typedef struct _SVErrorInfo {
74    SetValuesEvent *event;
75    ProtocolStream *stream;
76    unsigned short *count;
77    WidgetInfo *entry;
78} SVErrorInfo;
79
80typedef struct _GetValuesEvent {
81    EditresCommand type;		/* first field must be type */
82    WidgetInfo *widgets;
83    unsigned short num_entries;		/* number of get values requests */
84    char *name;
85} GetValuesEvent;
86
87typedef struct _FindChildEvent {
88    EditresCommand type;		/* first field must be type */
89    WidgetInfo *widgets;
90    short x, y;
91} FindChildEvent;
92
93typedef struct _GenericGetEvent {
94    EditresCommand type;		/* first field must be type */
95    WidgetInfo *widgets;
96    unsigned short num_entries;		/* number of set values requests */
97} GenericGetEvent, GetResEvent, GetGeomEvent;
98
99/*
100 * Common to all events
101 */
102typedef struct _AnyEvent {
103    EditresCommand type;		/* first field must be type */
104    WidgetInfo *widgets;
105} AnyEvent;
106
107/*
108 * The event union
109 */
110typedef union _EditresEvent {
111    AnyEvent any_event;
112    SetValuesEvent set_values_event;
113    GetResEvent get_resources_event;
114    GetGeomEvent get_geometry_event;
115    FindChildEvent find_child_event;
116} EditresEvent;
117
118typedef struct _Globals {
119    EditresBlock block;
120    SVErrorInfo error_info;
121    ProtocolStream stream;
122    ProtocolStream *command_stream;	/* command stream */
123#if defined(LONG64) || defined(WORD64)
124    unsigned long base_address;
125#endif
126} Globals;
127
128#define CURRENT_PROTOCOL_VERSION 5L
129
130#define streq(a,b) (strcmp((a), (b)) == 0)
131
132/*
133 * Prototypes
134 */
135static Widget _FindChild(Widget, int, int);
136static void _XEditresGetStringValues(Widget, Arg*, int);
137static XtPointer BuildReturnPacket(ResIdent, EditResError, ProtocolStream*);
138static void CommandDone(Widget, Atom*, Atom*);
139static Boolean ConvertReturnCommand(Widget, Atom*, Atom*, Atom*, XtPointer*,
140				    unsigned long*, int*);
141static Boolean CvtStringToBlock(Display*, XrmValue*, Cardinal*,
142				XrmValue*, XrmValue*, XtPointer*);
143static EditresEvent *BuildEvent(Widget, Atom, XtPointer, ResIdent,
144				unsigned long);
145static _Xconst char *DoFindChild(Widget, EditresEvent*, ProtocolStream*);
146static _Xconst char *DoGetGeometry(Widget, EditresEvent*, ProtocolStream*);
147static _Xconst char *DoGetResources(Widget, EditresEvent*, ProtocolStream*);
148static _Xconst char *DoSetValues(Widget, EditresEvent*, ProtocolStream*);
149static void DumpChildren(Widget, ProtocolStream*, unsigned short*);
150static _Xconst char *DumpValues(Widget, EditresEvent*, ProtocolStream*);
151static _Xconst char *DumpWidgets(Widget, EditresEvent*, ProtocolStream*);
152static void ExecuteCommand(Widget, Atom, ResIdent, EditresEvent*);
153static void ExecuteGetGeometry(Widget, ProtocolStream*);
154static void ExecuteGetResources(Widget w, ProtocolStream *stream);
155static void ExecuteSetValues(Widget, SetValuesEvent*, WidgetInfo*,
156			     ProtocolStream*, unsigned short*);
157static void FreeEvent(EditresEvent*);
158static void GetCommand(Widget w, XtPointer, Atom*, Atom*, XtPointer,
159		       unsigned long*, int*);
160static void HandleToolkitErrors(String, String, String, String,
161				String*, Cardinal*);
162static void InsertWidget(ProtocolStream*, Widget);
163static Bool IsChild(Widget, Widget, Widget);
164static Bool isApplicationShell(Widget);
165static void LoadResources(Widget);
166static Bool PositionInChild(Widget, int, int);
167static int qcmp_widget_list(register _Xconst void*, register _Xconst void*);
168static void SendCommand(Widget, Atom, ResIdent, EditResError,
169			ProtocolStream*);
170static void SendFailure(Widget, Atom, ResIdent, _Xconst char*);
171static _Xconst char *VerifyWidget(Widget, WidgetInfo*);
172
173/*
174 * External
175 */
176void _XEditResCheckMessages(Widget, XtPointer, XEvent*, Boolean*);
177
178/*
179 * Initialization
180 */
181static Atom res_editor_command, res_editor_protocol, client_value;
182static Globals globals;
183
184/************************************************************
185 * Resource Editor Communication Code
186 ************************************************************/
187/*
188 * Function:
189 *	_XEditResCheckMessages
190 *
191 * Parameters:
192 *	data  - unused
193 *	event - The X Event that triggered this handler
194 *	cont  - unused
195 *
196 * Description:
197 *	  This callback routine is set on all shell widgets, and checks to
198 *	see if a client message event has come from the resource editor.
199 */
200/*ARGSUSED*/
201void
202_XEditResCheckMessages(Widget w, XtPointer data, XEvent *event, Boolean *cont)
203{
204    Time time;
205    ResIdent ident;
206    static Boolean first_time = False;
207    static Atom res_editor, res_comm;
208    Display *dpy;
209
210    if (event->type == ClientMessage)
211    {
212	XClientMessageEvent * c_event = (XClientMessageEvent *)event;
213	dpy = XtDisplay(w);
214
215	if (!first_time)
216	{
217	    Atom atoms[4];
218	    static _Xconst char *names[] = {
219		EDITRES_NAME, EDITRES_COMMAND_ATOM,
220		EDITRES_PROTOCOL_ATOM, EDITRES_CLIENT_VALUE
221	    };
222
223	    first_time = True;
224	    XInternAtoms(dpy, (char **) names, 4, False, atoms);
225	    res_editor = atoms[0];
226	    res_editor_command = atoms[1];
227	    res_editor_protocol = atoms[2];
228	  /* Used in later procedures */
229	    client_value = atoms[3];
230	    LoadResources(w);
231	}
232
233	if ((c_event->message_type != res_editor)
234	    || (c_event->format != EDITRES_SEND_EVENT_FORMAT))
235	    return;
236
237	time = c_event->data.l[0];
238	res_comm = c_event->data.l[1];
239	ident = (ResIdent) c_event->data.l[2];
240	if (c_event->data.l[3] != CURRENT_PROTOCOL_VERSION)
241	{
242	    _XEditResResetStream(&globals.stream);
243	    _XEditResPut8(&globals.stream,
244			  (unsigned int) CURRENT_PROTOCOL_VERSION);
245	    SendCommand(w, res_comm, ident, ProtocolMismatch, &globals.stream);
246	    return;
247	}
248
249	XtGetSelectionValue(w, res_comm, res_editor_command,
250			    GetCommand, (XtPointer)(long)ident, time);
251    }
252}
253
254/*
255 * Function:
256 *	BuildEvent
257 *
258 * Parameters:
259 *	w      - widget to own selection, in case of error
260 *	sel    - selection to send error message beck in
261 *	data   - the data for the request
262 *	ident  - the id number we are looking for
263 *	length - length of request
264 *
265 * Description:
266 *	  Takes the info out the protocol stream an constructs
267 *                   the proper event structure.
268 *
269 * Returns:
270 *	the event, or NULL
271 */
272#if defined(ERROR_MESSAGE)
273#undef ERROR_MESSAGE
274#endif
275#define ERROR_MESSAGE "Client: Improperly formatted protocol request"
276static EditresEvent *
277BuildEvent(Widget w, Atom sel, XtPointer data, ResIdent ident,
278	   unsigned long length)
279{
280    EditresEvent *event;
281    ProtocolStream alloc_stream, *stream;
282    unsigned char temp;
283    register unsigned int i;
284
285    stream = &alloc_stream;
286    stream->current = stream->top = (unsigned char *)data;
287    stream->size = HEADER_SIZE;		/* size of header */
288
289    /*
290     * Retrieve the Header
291     */
292    if (length < HEADER_SIZE)
293    {
294	SendFailure(w, sel, ident, ERROR_MESSAGE);
295	return (NULL);
296    }
297
298    (void)_XEditResGet8(stream, &temp);
299    if (temp != ident)			/* Id's don't match, ignore request */
300	return (NULL);
301
302    event = (EditresEvent *)XtCalloc(sizeof(EditresEvent), 1);
303
304    (void)_XEditResGet8(stream, &temp);
305    event->any_event.type = (EditresCommand)temp;
306    (void)_XEditResGet32(stream, &stream->size);
307    stream->top = stream->current;	/* reset stream to top of value */
308
309    /*
310     * Now retrieve the data segment
311     */
312    switch(event->any_event.type)
313    {
314    case SendWidgetTree:
315	break;			/* no additional info */
316    case SetValues:
317        {
318	    SetValuesEvent *sv_event = (SetValuesEvent *)event;
319
320	    if (!(_XEditResGetString8(stream, &sv_event->name)
321		  && _XEditResGetString8(stream, &sv_event->res_type)))
322		goto done;
323
324	    /*
325	     * Since we need the value length, we have to pull the
326	     * value out by hand
327	     */
328	    if (!_XEditResGet16(stream, &sv_event->value_len))
329		goto done;
330
331	    sv_event->value = XtMalloc(sizeof(char) * (sv_event->value_len + 1));
332
333	    for (i = 0; i < sv_event->value_len; i++)
334		if (!_XEditResGet8(stream, (unsigned char *)sv_event->value + i))
335		    goto done;
336
337	    ((char*)sv_event->value)[i] = '\0';
338
339	    if (!_XEditResGet16(stream, &sv_event->num_entries))
340		goto done;
341
342	    sv_event->widgets = (WidgetInfo *)
343		XtCalloc(sizeof(WidgetInfo), sv_event->num_entries);
344
345	    for (i = 0; i < sv_event->num_entries; i++)
346		if (!_XEditResGetWidgetInfo(stream, sv_event->widgets + i))
347		    goto done;
348	}
349	break;
350    case FindChild:
351	{
352	    FindChildEvent *find_event = (FindChildEvent *)event;
353
354	    find_event->widgets = (WidgetInfo *)XtCalloc(sizeof(WidgetInfo), 1);
355
356	    if (!(_XEditResGetWidgetInfo(stream, find_event->widgets)
357		  && _XEditResGetSigned16(stream, &find_event->x)
358		  && _XEditResGetSigned16(stream, &find_event->y)))
359		goto done;
360	}
361	break;
362    case GetGeometry:
363    case GetResources:
364	{
365	    GenericGetEvent *get_event = (GenericGetEvent *)event;
366
367	    if (!_XEditResGet16(stream, &get_event->num_entries))
368		goto done;
369
370	    get_event->widgets = (WidgetInfo *)
371		XtCalloc(sizeof(WidgetInfo), get_event->num_entries);
372
373	    for (i = 0; i < get_event->num_entries; i++)
374		if (!_XEditResGetWidgetInfo(stream, get_event->widgets + i))
375		    goto done;
376	}
377	break;
378    case GetValues:
379	{
380	    GetValuesEvent *gv_event = (GetValuesEvent *)event;
381
382	    _XEditResGetString8(stream, &gv_event->name);
383	    _XEditResGet16(stream, &gv_event->num_entries);
384	    gv_event->widgets = (WidgetInfo *)
385		XtCalloc(sizeof(WidgetInfo), gv_event->num_entries);
386	    _XEditResGetWidgetInfo(stream, gv_event->widgets);
387	}
388        break;
389    default:
390	{
391	    char buf[BUFSIZ];
392
393	    XmuSnprintf(buf, sizeof(buf),
394			"Unknown Protocol request %d.", event->any_event.type);
395	    SendFailure(w, sel, ident, buf);
396	    FreeEvent(event);
397	    return (NULL);
398	}
399    }
400
401    return (event);
402
403  done:
404    SendFailure(w, sel, ident, ERROR_MESSAGE);
405    FreeEvent(event);
406    return (NULL);
407}
408
409/*
410 * Function:
411 *	FreeEvent
412 *
413 * Parameters:
414 *	event - event to free
415 *
416 * Description:
417 *	Frees the event structure and any other pieces in it that need freeing.
418 */
419static void
420FreeEvent(EditresEvent *event)
421{
422    if (event->any_event.widgets != NULL)
423    {
424	XtFree((char *)event->any_event.widgets->ids);
425	XtFree((char *)event->any_event.widgets);
426    }
427
428    if (event->any_event.type == SetValues)
429    {
430	XtFree(event->set_values_event.name);
431	XtFree(event->set_values_event.res_type);
432    }
433
434    XtFree((char *)event);
435}
436
437/*
438 * Function:
439 *	GetCommand
440 *
441 * Parameters:
442 *	(See Xt XtConvertSelectionProc)
443 *	data - contains the ident number for the command
444 *
445 * Description:
446 *	Gets the Command out of the selection asserted by the resource manager.
447 */
448/*ARGSUSED*/
449static void
450GetCommand(Widget w, XtPointer data, Atom *selection, Atom *type,
451	   XtPointer value, unsigned long *length, int *format)
452{
453    ResIdent ident = (ResIdent)(long)data;
454    EditresEvent *event;
455
456    if (*type != res_editor_protocol || *format != EDITRES_FORMAT)
457	return;
458
459    if ((event = BuildEvent(w, *selection, value, ident, *length)) != NULL)
460    {
461	ExecuteCommand(w, *selection, ident, event);
462	FreeEvent(event);
463    }
464}
465
466/*
467 * Function:
468 *	ExecuteCommand
469 *
470 * Parameters:
471 *	w	- widget
472 *	command	- the command to execute
473 *	value	- the associated with the command
474 *
475 * Description:
476 *	Executes a command string received from the resource editor.
477 */
478/*ARGSUSED*/
479static void
480ExecuteCommand(Widget w, Atom sel, ResIdent ident, EditresEvent *event)
481{
482    _Xconst char *(*func)(Widget, EditresEvent*, ProtocolStream*);
483    _Xconst char *str;
484
485    if (globals.block == BlockAll)
486    {
487	SendFailure(w, sel, ident,
488		    "This client has blocked all Editres commands.");
489	return;
490    }
491    else if (globals.block == BlockSetValues
492	     && event->any_event.type == SetValues)
493    {
494	SendFailure(w, sel, ident,
495		    "This client has blocked all SetValues requests.");
496	return;
497    }
498
499    switch(event->any_event.type)
500    {
501    case SendWidgetTree:
502#if defined(LONG64) || defined(WORD64)
503	globals.base_address = (unsigned long)w & 0xFFFFFFFF00000000;
504#endif
505	func = DumpWidgets;
506	break;
507    case SetValues:
508	func = DoSetValues;
509	break;
510    case FindChild:
511	func = DoFindChild;
512	break;
513    case GetGeometry:
514	func = DoGetGeometry;
515	break;
516    case GetResources:
517	func = DoGetResources;
518	break;
519    case GetValues:
520        func = DumpValues;
521    break;
522    default:
523        {
524	    char buf[BUFSIZ];
525
526	    XmuSnprintf(buf, sizeof(buf),
527			"Unknown Protocol request %d.",event->any_event.type);
528	    SendFailure(w, sel, ident, buf);
529	    return;
530	}
531    }
532
533    _XEditResResetStream(&globals.stream);
534    if ((str = (*func)(w, event, &globals.stream)) == NULL)
535	SendCommand(w, sel, ident, PartialSuccess, &globals.stream);
536    else
537	SendFailure(w, sel, ident, str);
538}
539
540/*
541 * Function:
542 *	ConvertReturnCommand
543 *
544 * Parameters:
545 *	w	   - the widget that owns the selection
546 *	selection  - selection to convert
547 *	target	   - target type for this selection
548 *	type_ret   - type of the selection
549 *	value_ret  - selection value
550 *	length_ret - length of this selection
551 *	format_ret - the format the selection is in
552 *
553 * Description:
554 *	Converts a selection
555 *
556 * Returns:
557 *	True if conversion was successful
558 */
559/*ARGSUSED*/
560static Boolean
561ConvertReturnCommand(Widget w, Atom *selection, Atom *target, Atom *type_ret,
562		     XtPointer *value_ret, unsigned long *length_ret,
563		     int *format_ret)
564{
565    /*
566     * I assume the intrinsics give me the correct selection back
567     */
568    if ((*target != client_value))
569	return (False);
570
571    *type_ret = res_editor_protocol;
572    *value_ret = (XtPointer)globals.command_stream->real_top;
573    *length_ret = globals.command_stream->size + HEADER_SIZE;
574    *format_ret = EDITRES_FORMAT;
575
576  return (True);
577}
578
579/*
580 * Function:
581 *	CommandDone
582 *
583 * Parameters:
584 *	widget	  - unused
585 *	selection - unused
586 *	target	  - unused
587 *
588 * Description:
589 *	done with the selection
590 */
591/*ARGSUSED*/
592static void
593CommandDone(Widget widget, Atom *selection, Atom *target)
594{
595    /* Keep the toolkit from automatically freeing the selection value */
596}
597
598/*
599 * Function:
600 *	SendFailure
601 *
602 * Parameters:
603 *	w     - widget to own the selection
604 *	sel   - selection to assert
605 *	ident - identifier
606 *	str   - error message
607 *
608 * Description:
609 *	Sends a failure message
610 */
611static void
612SendFailure(Widget w, Atom sel, ResIdent ident, _Xconst char *str)
613{
614    _XEditResResetStream(&globals.stream);
615    _XEditResPutString8(&globals.stream, str);
616    SendCommand(w, sel, ident, Failure, &globals.stream);
617}
618
619/*
620 * Function:
621 *	BuildReturnPacket
622 *
623 * Parameters:
624 *	ident   - identifier
625 *	command - command code
626 *	stream  - protocol stream
627 * Description:
628 *	Builds a return packet, given the data to send
629 *
630 * Returns:
631 *	packet to send
632 */
633static XtPointer
634BuildReturnPacket(ResIdent ident, EditResError error, ProtocolStream *stream)
635{
636    long old_alloc, old_size;
637    unsigned char *old_current;
638
639    /*
640     * We have cleverly keep enough space at the top of the header
641     * for the return protocol stream, so all we have to do is
642     * fill in the space
643     */
644    /*
645     * Fool the insert routines into putting the header in the right
646     * place while being damn sure not to realloc (that would be very bad.)
647     */
648    old_current = stream->current;
649    old_alloc = stream->alloc;
650    old_size = stream->size;
651
652    stream->current = stream->real_top;
653    stream->alloc = stream->size + (2 * HEADER_SIZE);
654
655    _XEditResPut8(stream, ident);
656    _XEditResPut8(stream, (unsigned char)error);
657    _XEditResPut32(stream, old_size);
658
659    stream->alloc = old_alloc;
660    stream->current = old_current;
661    stream->size = old_size;
662
663    return ((XtPointer)stream->real_top);
664}
665
666/*
667 * Function:
668 *	SendCommand
669 * Parameters:
670 *	w	- widget to own the selection
671 *	sel	- selection to assert
672 *	ident   - identifier
673 *	command - command code
674 *	stream  - protocol stream
675 *
676 * Description:
677 *	Builds a return command line
678 */
679static void
680SendCommand(Widget w, Atom sel, ResIdent ident, EditResError error,
681	    ProtocolStream *stream)
682{
683    BuildReturnPacket(ident, error, stream);
684    globals.command_stream = stream;
685
686    /*
687     * I REALLY want to own the selection.  Since this was not triggered
688     * by a user action, and I am the only one using this atom it is safe to
689     * use CurrentTime
690     */
691    XtOwnSelection(w, sel, CurrentTime, ConvertReturnCommand, NULL, CommandDone);
692}
693
694/************************************************************
695 * Generic Utility Functions
696 ************************************************************/
697static int
698qcmp_widget_list(register _Xconst void *left, register _Xconst void *right)
699{
700    return (char *)*(Widget **)left - (char *)*(Widget **)right;
701}
702
703/*
704 * Function:
705 *	FindChildren
706 *
707 * Parameters:
708 *	parent   - parent widget
709 *	children - list of children
710 *	normal   - return normal children
711 *	popup    - return popup children
712 *	extra	 - return extra children
713 *
714 * Description:
715 *	Returns all children (popup, normal and otherwise) of this widget
716 *
717 * Returns:
718 *	number of children
719 */
720static int
721FindChildren(Widget parent, Widget **children, Bool normal, Bool popup,
722	     Bool extra)
723{
724    CompositeWidget cw = (CompositeWidget)parent;
725    Cardinal i, num_children, current = 0;
726    Widget *extra_widgets = NULL;
727    Cardinal num_extra = 0;
728
729    num_children = 0;
730
731    if (XtIsWidget(parent) && popup)
732	num_children += parent->core.num_popups;
733
734    if (XtIsComposite(parent) && normal)
735	num_children += cw->composite.num_children;
736
737    if (XtIsWidget(parent) && extra)
738    {
739	XtResourceList norm_list, cons_list;
740	Cardinal num_norm, num_cons;
741	Arg args[1];
742	Widget widget;
743
744	XtGetResourceList(XtClass(parent), &norm_list, &num_norm);
745
746	if (XtParent(parent) != NULL)
747	    XtGetConstraintResourceList(XtClass(XtParent(parent)),
748					&cons_list, &num_cons);
749	else
750	    num_cons = 0;
751
752	extra_widgets = (Widget *)XtMalloc(sizeof(Widget));
753	for (i = 0; i < num_norm; i++)
754	    if (strcmp(norm_list[i].resource_type, XtRWidget) == 0)
755	    {
756		widget = NULL;
757		XtSetArg(args[0], norm_list[i].resource_name, &widget);
758		XtGetValues(parent, args, 1);
759		if (widget && XtParent(widget) == parent)
760		{
761		    ++num_extra;
762		    extra_widgets = (Widget *) XtRealloc(
763			(char *)extra_widgets, num_extra * sizeof(Widget));
764		    extra_widgets[num_extra - 1] = widget;
765		}
766	    }
767	for (i = 0; i < num_cons; i++)
768	    if (strcmp(cons_list[i].resource_type, XtRWidget) == 0)
769	    {
770		widget = NULL;
771		XtSetArg(args[0], cons_list[i].resource_name, &widget);
772		XtGetValues(parent, args, 1);
773		if (widget && XtParent(widget) == parent)
774		{
775		    ++num_extra;
776		    extra_widgets = (Widget *) XtRealloc(
777			(char *)extra_widgets, num_extra * sizeof(Widget));
778		    extra_widgets[num_extra - 1] = widget;
779		}
780	    }
781	if (num_norm)
782	    XtFree((char *)norm_list);
783	if (num_cons)
784	    XtFree((char *)cons_list);
785    }
786
787    if ((num_children + num_extra) == 0)
788    {
789	*children = NULL;
790	return (0);
791    }
792
793    *children = (Widget *)XtMalloc(sizeof(Widget) * (num_children + num_extra));
794
795    if (XtIsComposite(parent) && normal)
796	for (i = 0; i < cw->composite.num_children; i++, current++)
797	    (*children)[current] = cw->composite.children[i];
798
799    if (XtIsWidget(parent) && popup)
800	for (i = 0; i < parent->core.num_popups; i++, current++)
801	    (*children)[current] = parent->core.popup_list[i];
802
803    if (num_extra)
804    /* Check for dups */
805    {
806	Cardinal j, old_num_extra = num_extra;
807
808	qsort(extra_widgets, num_extra, sizeof(Widget), qcmp_widget_list);
809	for (i = 0; i < num_extra - 1; i++)
810	    while (i < num_extra - 1 &&
811		   extra_widgets[i] == extra_widgets[i + 1])
812	    {
813		memmove(&extra_widgets[i], &extra_widgets[i + 1],
814			(num_extra - i) * sizeof(Widget));
815		--num_extra;
816	    }
817
818	for (i = 0; i < num_children; i++)
819	    for (j = 0; j < num_extra; j++)
820		if ((*children)[i] == extra_widgets[j])
821		{
822		    if ((j + 1) < num_extra)
823			memmove(&extra_widgets[j], &extra_widgets[j + 1],
824				(num_extra - j) * sizeof(Widget));
825		    --num_extra;
826		}
827
828	if (old_num_extra != num_extra)
829	    *children = (Widget *)XtRealloc((char *)*children, sizeof(Widget)
830					    * (num_children + num_extra));
831
832	if (num_extra)
833	    memcpy(&(*children)[num_children], extra_widgets,
834		   sizeof(Widget) * num_extra);
835    }
836    if (extra_widgets)
837	XtFree((char *)extra_widgets);
838    if (num_children + num_extra == 0)
839    {
840	XtFree((char *)*children);
841	*children = NULL;
842    }
843
844    return (num_children + num_extra);
845}
846
847/*
848 * Function:
849 *	IsChild
850 *
851 * parameters:
852 *	top    - top of the tree
853 *	parent - parent widget
854 *	child  - child widget
855 *
856 * Description:
857 *	Check to see of child is a child of parent
858 */
859static Bool
860IsChild(Widget top, Widget parent, Widget child)
861{
862    int i, num_children;
863    Widget *children;
864
865    if (parent == NULL)
866	return (top == child);
867
868    num_children = FindChildren(parent, &children, True, True, True);
869
870    for (i = 0; i < num_children; i++)
871	if (children[i] == child)
872	{
873	    XtFree((char *)children);
874	    return (True);
875	}
876
877    XtFree((char *)children);
878    return (False);
879}
880
881/*
882 * Function:
883 *	VerifyWidget
884 *
885 * Parameters:
886 *	w    - any widget in the tree
887 *	info - info about the widget to verify
888 *
889 * Description:
890 *	Makes sure all the widgets still exist
891 */
892static _Xconst char *
893VerifyWidget(Widget w, WidgetInfo *info)
894{
895    Widget top;
896    register int count;
897    register Widget parent;
898    register unsigned long *child;
899
900    for (top = w; XtParent(top) != NULL; top = XtParent(top))
901	;
902
903    parent = NULL;
904    child = info->ids;
905    count = 0;
906
907    while (True)
908    {
909	if (!IsChild(top, parent, (Widget) *child))
910	    return ("This widget no longer exists in the client.");
911
912	if (++count == info->num_widgets)
913	    break;
914
915	parent = (Widget)*child++;
916    }
917
918    info->real_widget = (Widget)*child;
919
920    return (NULL);
921}
922
923/************************************************************
924 * Code to Perform SetValues operations
925 ************************************************************/
926/*
927 * Function:
928 *	DoSetValues
929 *
930 * Parameters:
931 *	w      - a widget in the tree
932 *	event  - event that caused this action
933 *	stream - protocol stream to add
934 *
935 * Description:
936 *	Performs the setvalues requested
937 *
938 * Returns:
939 *	NULL
940 */
941static _Xconst char *
942DoSetValues(Widget w, EditresEvent *event, ProtocolStream *stream)
943{
944    _Xconst char *str;
945    register unsigned i;
946    unsigned short count = 0;
947    SetValuesEvent *sv_event = (SetValuesEvent *)event;
948
949    _XEditResPut16(stream, count);  /* insert 0, will be overwritten later */
950
951    for (i = 0; i < sv_event->num_entries; i++)
952    {
953	if ((str = VerifyWidget(w, &sv_event->widgets[i])) != NULL)
954	{
955	    _XEditResPutWidgetInfo(stream, &sv_event->widgets[i]);
956	    _XEditResPutString8(stream, str);
957	    count++;
958	}
959	else
960	    ExecuteSetValues(sv_event->widgets[i].real_widget,
961			     sv_event, sv_event->widgets + i, stream, &count);
962    }
963
964    /*
965     * Overwrite the first 2 bytes with the real count.
966     */
967    *(stream->top) = count >> XER_NBBY;
968    *(stream->top + 1) = count;
969
970    return (NULL);
971}
972
973/*
974 * Function:
975 *	HandleToolkitErrors
976 *
977 * Parameters:
978 *	name	   - name of the error
979 *	type	   - type of the error
980 *	class	   - class of the error
981 *	msg	   - the default message
982 *	params	   - the extra parameters for this message
983 *	num_params - ""
984 *
985 *	Description: Handles X Toolkit Errors.
986 */
987/* ARGSUSED */
988static void
989HandleToolkitErrors(String name, String type, String class, String msg,
990		    String *params, Cardinal *num_params)
991{
992    SVErrorInfo *info = &globals.error_info;
993    char buf[BUFSIZ];
994
995    if (streq(name, "unknownType"))
996	XmuSnprintf(buf, sizeof(buf),
997		    "The `%s' resource is not used by this widget.",
998		    info->event->name);
999    else if (streq(name, "noColormap"))
1000	XmuSnprintf(buf, sizeof(buf), msg, params[0]);
1001    else if (streq(name, "conversionFailed") || streq(name, "conversionError"))
1002    {
1003	if (streq((String)info->event->value, XtRString))
1004	    XmuSnprintf(buf, sizeof(buf),
1005			"Could not convert the string '%s' for the `%s' "
1006			"resource.", (String)info->event->value,
1007			info->event->name);
1008	else
1009	    XmuSnprintf(buf, sizeof(buf),
1010			"Could not convert the `%s' resource.",
1011			info->event->name);
1012    }
1013    else
1014	XmuSnprintf(buf, sizeof(buf),
1015		    "Name: %s, Type: %s, Class: %s, Msg: %s",
1016		    name, type, class, msg);
1017
1018    /*
1019     * Insert this info into the protocol stream, and update the count
1020     */
1021    (*(info->count))++;
1022    _XEditResPutWidgetInfo(info->stream, info->entry);
1023    _XEditResPutString8(info->stream, buf);
1024}
1025
1026/*
1027 * Function:
1028 *	ExecuteSetValues
1029 *
1030 * Parameters:
1031 *	w	 - widget to perform the set_values on
1032 *	sv_event - set values event
1033 *	sv_info  - set_value info
1034 *.
1035 * Description:
1036 *	Performs a setvalues for a given command
1037 */
1038static void
1039ExecuteSetValues(Widget w, SetValuesEvent *sv_event, WidgetInfo *entry,
1040		 ProtocolStream *stream, unsigned short *count)
1041{
1042    XtErrorMsgHandler old;
1043    SVErrorInfo *info = &globals.error_info;
1044
1045    info->event = sv_event;	/* No data can be passed to */
1046    info->stream = stream;	/* an error handler, so we */
1047    info->count = count;	/* have to use a global */
1048    info->entry = entry;
1049
1050    old = XtAppSetWarningMsgHandler(XtWidgetToApplicationContext(w),
1051				    HandleToolkitErrors);
1052
1053    XtVaSetValues(w, XtVaTypedArg,
1054		  sv_event->name, sv_event->res_type,
1055		  sv_event->value, sv_event->value_len,
1056		  NULL);
1057
1058    (void)XtAppSetWarningMsgHandler(XtWidgetToApplicationContext(w), old);
1059}
1060
1061/************************************************************
1062 * Code for Creating and dumping widget tree.
1063 ************************************************************/
1064/* Function:
1065 *	DumpWidgets
1066 *
1067 * Parameters:
1068 *	w      - a widget in the tree
1069 *	event  - event that caused this action
1070 *	stream - protocol stream to add
1071 *
1072 * Description:
1073 *	  Given a widget it builds a protocol packet containing the entire
1074 *	widget hierarchy.
1075 *
1076 * Returns:
1077 *	NULL
1078 */
1079#define TOOLKIT_TYPE ("Xt")
1080/*ARGSUSED*/
1081static _Xconst char *
1082DumpWidgets(Widget w, EditresEvent *event, ProtocolStream *stream)
1083{
1084    unsigned short count = 0;
1085
1086    /* Find Tree's root */
1087    for (; XtParent(w) != NULL; w = XtParent(w))
1088	;
1089
1090    /*
1091     * hold space for count, overwritten later
1092     */
1093    _XEditResPut16(stream, (unsigned int)0);
1094
1095    DumpChildren(w, stream, &count);
1096
1097    /*
1098     * write out toolkit type
1099     */
1100    _XEditResPutString8(stream, TOOLKIT_TYPE);
1101
1102    /*
1103     * Overwrite the first 2 bytes with the real count
1104     */
1105    *(stream->top) = count >> XER_NBBY;
1106    *(stream->top + 1) = count;
1107
1108    return (NULL);
1109}
1110
1111/*
1112 * Function:
1113 *	 DumpChildren
1114 *
1115 * Parameters:
1116 *	w      - widget to dump
1117 *	stream - stream to dump to
1118 *	count  - number of dumps we have performed
1119 *
1120 * Description:
1121 *	Adds a child's name to the list.
1122 */
1123/* This is a trick/kludge.  To make shared libraries happier (linking
1124 * against Xmu but not linking against Xt, and apparently even work
1125 * as we desire on SVR4, we need to avoid an explicit data reference
1126 * to applicationShellWidgetClass.  XtIsTopLevelShell is known
1127 * (implementation dependent assumption!) to use a bit flag.  So we
1128 * go that far.  Then, we test whether it is an applicationShellWidget
1129 * class by looking for an explicit class name.  Seems pretty safe.
1130 */
1131static Bool
1132isApplicationShell(Widget w)
1133{
1134    register WidgetClass c;
1135
1136    if (!XtIsTopLevelShell(w))
1137	return (False);
1138    for (c = XtClass(w); c; c = c->core_class.superclass)
1139      if (strcmp(c->core_class.class_name, "ApplicationShell") == 0)
1140	  return (True);
1141
1142    return (False);
1143}
1144
1145static void
1146DumpChildren(Widget w, ProtocolStream *stream, unsigned short *count)
1147{
1148    int i, num_children;
1149    Widget *children;
1150    unsigned long window;
1151    String c_class;
1152
1153    (*count)++;
1154
1155    InsertWidget(stream, w);		/* Insert the widget into the stream */
1156
1157    _XEditResPutString8(stream, XtName(w)); /* Insert name */
1158
1159    if (isApplicationShell(w))
1160	c_class = ((ApplicationShellWidget)w)->application.class;
1161    else
1162	c_class = XtClass(w)->core_class.class_name;
1163
1164    _XEditResPutString8(stream, c_class);	/* Insert class */
1165
1166    if (XtIsWidget(w))
1167	if (XtIsRealized(w))
1168	    window = XtWindow(w);
1169	else
1170	    window = EDITRES_IS_UNREALIZED;
1171    else
1172	window = EDITRES_IS_OBJECT;
1173
1174    _XEditResPut32(stream, window);		/* Insert window id */
1175
1176    /*
1177     * Find children and recurse
1178     */
1179    num_children = FindChildren(w, &children, True, True, True);
1180    for (i = 0; i < num_children; i++)
1181	DumpChildren(children[i], stream, count);
1182
1183    XtFree((char *)children);
1184}
1185
1186/************************************************************
1187 * Code for getting the geometry of widgets
1188 ************************************************************/
1189/*
1190 * Function:
1191 *	DoGetGeometry
1192 *
1193 * Parameters:
1194 *	w      - widget in the tree
1195 *	event  - event that caused this action
1196 *	stream - protocol stream to add
1197 *
1198 * Description:
1199 *	Retrieves the Geometry of each specified widget.
1200 *
1201 * Returns:
1202 *	NULL
1203 */
1204static _Xconst char *
1205DoGetGeometry(Widget w, EditresEvent *event, ProtocolStream *stream)
1206{
1207    unsigned i;
1208    _Xconst char *str;
1209    GetGeomEvent *geom_event = (GetGeomEvent *)event;
1210
1211    _XEditResPut16(stream, geom_event->num_entries);
1212
1213    for (i = 0; i < geom_event->num_entries; i++)
1214    {
1215	/*
1216	 * Send out the widget id
1217	 */
1218	_XEditResPutWidgetInfo(stream, &geom_event->widgets[i]);
1219
1220	if ((str = VerifyWidget(w, &geom_event->widgets[i])) != NULL)
1221	{
1222	    _XEditResPutBool(stream, True);	/* an error occurred */
1223	    _XEditResPutString8(stream, str);	/* set message */
1224	}
1225	else
1226	    ExecuteGetGeometry(geom_event->widgets[i].real_widget, stream);
1227    }
1228
1229    return (NULL);
1230}
1231
1232/*
1233 * Function:
1234 *	ExecuteGetGeometry
1235 *
1236 * Parameters:
1237 *	w      - widget to get geometry
1238 *	stream - stream to append to
1239 *
1240 * Description:
1241 *	Gets the geometry for each widget specified.
1242 *
1243 * Returns:
1244 *	True if no error occurred.
1245 */
1246static void
1247ExecuteGetGeometry(Widget w, ProtocolStream *stream)
1248{
1249    int i;
1250    Boolean mapped_when_man;
1251    Dimension width, height, border_width;
1252    Arg args[8];
1253    Cardinal num_args = 0;
1254    Position x, y;
1255
1256    if (!XtIsRectObj(w) || (XtIsWidget(w) && !XtIsRealized(w)))
1257    {
1258	_XEditResPutBool(stream, False);	/* no error */
1259	_XEditResPutBool(stream, False);	/* not visible */
1260	for (i = 0; i < 5; i++)		/* fill in extra space with 0's */
1261	    _XEditResPut16(stream, 0);
1262	return;
1263    }
1264
1265    XtSetArg(args[num_args], XtNwidth, &width); num_args++;
1266    XtSetArg(args[num_args], XtNheight, &height); num_args++;
1267    XtSetArg(args[num_args], XtNborderWidth, &border_width); num_args++;
1268    XtSetArg(args[num_args], XtNmappedWhenManaged, &mapped_when_man);
1269    num_args++;
1270    XtGetValues(w, args, num_args);
1271
1272    if (!(XtIsManaged(w) && mapped_when_man) && XtIsWidget(w))
1273    {
1274	XWindowAttributes attrs;
1275
1276	/*
1277	 * The toolkit does not maintain mapping state, we have
1278	 * to go to the server
1279	 */
1280	if (XGetWindowAttributes(XtDisplay(w), XtWindow(w), &attrs) != 0)
1281	{
1282	    if (attrs.map_state != IsViewable)
1283	    {
1284		_XEditResPutBool(stream, False);	/* no error */
1285		_XEditResPutBool(stream, False);	/* not visible */
1286		for (i = 0; i < 5; i++)	/* fill in extra space with 0's */
1287		    _XEditResPut16(stream, 0);
1288		return;
1289	    }
1290	}
1291	else
1292	{
1293	    _XEditResPut8(stream, True); /* Error occurred. */
1294	    _XEditResPutString8(stream, "XGetWindowAttributes failed.");
1295	    return;
1296	}
1297    }
1298
1299    XtTranslateCoords(w, -((int) border_width), -((int) border_width), &x, &y);
1300
1301    _XEditResPutBool(stream, False);	/* no error */
1302    _XEditResPutBool(stream, True);	/* Visible */
1303    _XEditResPut16(stream, x);
1304    _XEditResPut16(stream, y);
1305    _XEditResPut16(stream, width);
1306    _XEditResPut16(stream, height);
1307    _XEditResPut16(stream, border_width);
1308}
1309
1310/************************************************************
1311 * Code for executing FindChild
1312 ************************************************************/
1313/*
1314 * Function:
1315 *	PositionInChild
1316 *
1317 * Parameters:
1318 *	child - child widget to check
1319 *	x     - location of point to check in the parent's coord space
1320 *	y     - ""
1321 *
1322 * Description:
1323 *	Returns true if this location is in the child.
1324 */
1325static Bool
1326PositionInChild(Widget child, int x, int y)
1327{
1328    Arg args[6];
1329    Cardinal num;
1330    Dimension width, height, border_width;
1331    Position child_x, child_y;
1332    Boolean mapped_when_managed;
1333
1334    if (!XtIsRectObj(child))	/* we must at least be a rect obj */
1335	return (False);
1336
1337    num = 0;
1338    XtSetArg(args[num], XtNmappedWhenManaged, &mapped_when_managed); num++;
1339    XtSetArg(args[num], XtNwidth, &width); num++;
1340    XtSetArg(args[num], XtNheight, &height); num++;
1341    XtSetArg(args[num], XtNx, &child_x); num++;
1342    XtSetArg(args[num], XtNy, &child_y); num++;
1343    XtSetArg(args[num], XtNborderWidth, &border_width); num++;
1344    XtGetValues(child, args, num);
1345
1346    /*
1347     * The only way we will know of the widget is mapped is to see if
1348     * mapped when managed is True and this is a managed child.  Otherwise
1349     * we will have to ask the server if this window is mapped
1350     */
1351    if (XtIsWidget(child) && !(mapped_when_managed && XtIsManaged(child)))
1352    {
1353	XWindowAttributes attrs;
1354
1355	if (XGetWindowAttributes(XtDisplay(child), XtWindow(child), &attrs)
1356	    &&  attrs.map_state != IsViewable)
1357	return (False);
1358    }
1359
1360    return ((x >= child_x)
1361	    && (x <= (child_x + (Position)width + 2 * (Position)border_width))
1362	    && (y >= child_y)
1363	    && (y <= (child_y + (Position)height + 2 * (Position)border_width)));
1364}
1365
1366/*
1367 * Function:
1368 *	_FindChild
1369 *
1370 * Parameters:
1371 *	parent - widget that is known to contain the point specified
1372 *	x      - point in coordinates relative to the widget specified
1373 *	y      - ""
1374 *
1375 * Description:
1376 *	Finds the child that actually contains the point shown.
1377 */
1378static Widget
1379_FindChild(Widget parent, int x, int y)
1380{
1381    Widget *children;
1382    int i = FindChildren(parent, &children, True, False, True);
1383
1384    while (i > 0)
1385    {
1386	i--;
1387
1388	if (PositionInChild(children[i], x, y))
1389	{
1390	    Widget child = children[i];
1391
1392	    XtFree((char *)children);
1393	    return (_FindChild(child, x - child->core.x, y - child->core.y));
1394	}
1395    }
1396
1397    XtFree((char *)children);
1398
1399    return (parent);
1400}
1401
1402/*
1403 * Function:
1404 *	DoFindChild
1405 *
1406 * Parameters:
1407 *	w      - widget in the tree
1408 *	event  - event that caused this action
1409 *	stream - protocol stream to add
1410 * Description:
1411 *	Finds the child that contains the location specified.
1412 *
1413 * Returns:
1414 *	  An allocated error message if something went horribly wrong and
1415 *	no set values were performed, else NULL.
1416 */
1417static _Xconst char *
1418DoFindChild(Widget w, EditresEvent *event, ProtocolStream *stream)
1419{
1420    _Xconst char *str;
1421    Widget parent, child;
1422    Position parent_x, parent_y;
1423    FindChildEvent *find_event = (FindChildEvent *)event;
1424
1425    if ((str = VerifyWidget(w, find_event->widgets)) != NULL)
1426	return (str);
1427
1428    parent = find_event->widgets->real_widget;
1429
1430    XtTranslateCoords(parent, (Position) 0, (Position) 0,
1431		      &parent_x, &parent_y);
1432
1433    child = _FindChild(parent, find_event->x - (int) parent_x,
1434		       find_event->y - (int) parent_y);
1435
1436    InsertWidget(stream, child);
1437
1438    return (NULL);
1439}
1440
1441/************************************************************
1442 * Procedures for performing GetResources
1443 ************************************************************/
1444/*
1445 * Function:
1446 *	DoGetResources
1447 *
1448 * Parameters:
1449 *	w      - widget in the tree
1450 *	event  - event that caused this action
1451 *	stream - protocol stream to add
1452 *
1453 * Description:
1454 *	Gets the Resources associated with the widgets passed.
1455 *
1456 * Returns:
1457 *	NULL
1458 */
1459static _Xconst char *
1460DoGetResources(Widget w, EditresEvent *event, ProtocolStream *stream)
1461{
1462    unsigned int i;
1463    _Xconst char *str;
1464    GetResEvent *res_event = (GetResEvent *)event;
1465
1466    _XEditResPut16(stream, res_event->num_entries); /* number of replies */
1467
1468    for (i = 0; i < res_event->num_entries; i++)
1469    {
1470	/*
1471	 * Send out the widget id
1472	 */
1473	_XEditResPutWidgetInfo(stream, &res_event->widgets[i]);
1474	if ((str = VerifyWidget(w, &res_event->widgets[i])) != NULL)
1475	{
1476	    _XEditResPutBool(stream, True);	/* an error occurred */
1477	    _XEditResPutString8(stream, str);	/* set message */
1478	}
1479	else
1480	{
1481	    _XEditResPutBool(stream, False);	/* no error occurred */
1482	    ExecuteGetResources(res_event->widgets[i].real_widget, stream);
1483	}
1484    }
1485
1486    return (NULL);
1487}
1488
1489/* Function:
1490 *	ExecuteGetResources
1491 *
1492 * Parameters:
1493 *	w      - widget to get resources on
1494 *	stream - protocol stream
1495 *
1496 * Description:
1497 *	Gets the resources for any individual widget
1498 */
1499static void
1500ExecuteGetResources(Widget w, ProtocolStream *stream)
1501{
1502    XtResourceList norm_list, cons_list;
1503    Cardinal num_norm, num_cons;
1504    register Cardinal i;
1505
1506    /*
1507     * Get Normal Resources
1508     */
1509    XtGetResourceList(XtClass(w), &norm_list, &num_norm);
1510
1511    if (XtParent(w) != NULL)
1512	XtGetConstraintResourceList(XtClass(XtParent(w)), &cons_list,&num_cons);
1513    else
1514	num_cons = 0;
1515
1516    _XEditResPut16(stream, num_norm + num_cons);	/* how many resources */
1517
1518    /*
1519     * Insert all the normal resources
1520     */
1521    for (i = 0; i < num_norm; i++)
1522    {
1523	_XEditResPutResourceType(stream, NormalResource);
1524	_XEditResPutString8(stream, norm_list[i].resource_name);
1525	_XEditResPutString8(stream, norm_list[i].resource_class);
1526	_XEditResPutString8(stream, norm_list[i].resource_type);
1527    }
1528    XtFree((char *)norm_list);
1529
1530    /*
1531     * Insert all the constraint resources
1532     */
1533    if (num_cons > 0)
1534    {
1535	for (i = 0; i < num_cons; i++)
1536	{
1537	    _XEditResPutResourceType(stream, ConstraintResource);
1538	    _XEditResPutString8(stream, cons_list[i].resource_name);
1539	    _XEditResPutString8(stream, cons_list[i].resource_class);
1540	    _XEditResPutString8(stream, cons_list[i].resource_type);
1541	}
1542	XtFree((char *)cons_list);
1543    }
1544}
1545
1546/*
1547 * Function:
1548 *	DumpValues
1549 *
1550 * Parameters:
1551 *	event  - event that caused this action
1552 *	stream - protocol stream to add
1553 *
1554 * Description:
1555 *	Returns resource values to the resource editor.
1556 *
1557 * Returns:
1558 *	NULL
1559 */
1560/*ARGSUSED*/
1561static _Xconst char *
1562DumpValues(Widget w, EditresEvent* event, ProtocolStream* stream)
1563{
1564    _Xconst char *str;
1565    Arg warg[1];
1566    _Xconst _XtString res_value = NULL;
1567    GetValuesEvent *gv_event = (GetValuesEvent *)event;
1568
1569    /* put the count in the stream */
1570    _XEditResPut16(stream, (unsigned int)1);
1571
1572    /*
1573     * Get the resource of the widget asked for by the
1574     * resource editor and insert it into the stream
1575     */
1576    XtSetArg(warg[0], gv_event->name, &res_value);
1577
1578    if ((str = VerifyWidget(w, &gv_event->widgets[0])) != NULL)
1579	_XEditResPutString8(stream, str);
1580    else
1581    {
1582	_XEditresGetStringValues(gv_event->widgets[0].real_widget, warg, 1);
1583	if (!res_value)
1584	    res_value = "NoValue";
1585	_XEditResPutString8(stream, res_value);
1586    }
1587
1588    return (NULL);
1589}
1590
1591/************************************************************
1592 * Code for inserting values into the protocol stream
1593 ************************************************************/
1594/*
1595 * Function:
1596 *	InsertWidget
1597 *
1598 * Parameters:
1599 *	stream - protocol stream
1600 *	w      - widget to insert
1601 *
1602 * Description:
1603 *	  Inserts the full parent hierarchy of this widget into the protocol
1604 *	stream as a widget list.
1605 */
1606static void
1607InsertWidget(ProtocolStream *stream, Widget w)
1608{
1609    Widget temp;
1610    unsigned long *widget_list;
1611    register int i, num_widgets;
1612
1613    for (temp = w, i = 0; temp != NULL; temp = XtParent(temp), i++)
1614	;
1615
1616    num_widgets = i;
1617    widget_list = (unsigned long *)XtMalloc(sizeof(unsigned long) * num_widgets);
1618
1619    /*
1620     * Put the widgets into the list
1621     * make sure that they are inserted in the list from parent -> child
1622     */
1623    for (i--, temp = w; temp != NULL; temp = XtParent(temp), i--)
1624    widget_list[i] = (unsigned long)temp;
1625
1626    _XEditResPut16(stream, num_widgets);	/* insert number of widgets */
1627    for (i = 0; i < num_widgets; i++)		/* insert Widgets themselves */
1628	_XEditResPut32(stream, widget_list[i]);
1629
1630    XtFree((char *)widget_list);
1631}
1632
1633/************************************************************
1634 * All of the following routines are public
1635 ************************************************************/
1636/*
1637 * Function:
1638 *	_XEditResPutString8
1639 *
1640 * Parameters:
1641 *	stream - stream to insert string into
1642 *	str    - string to insert
1643 *
1644 * Description:
1645 *	Inserts a string into the protocol stream.
1646 */
1647void
1648_XEditResPutString8(ProtocolStream *stream, _Xconst char *str)
1649{
1650    int i, len = strlen(str);
1651
1652    _XEditResPut16(stream, len);
1653    for (i = 0; i < len; i++, str++)
1654	_XEditResPut8(stream, *str);
1655}
1656
1657/*
1658 * Function:
1659 *	_XEditResPut8
1660 *
1661 * Parameters:
1662 *	stream - stream to insert string into
1663 *	value  - value to insert
1664 *
1665 * Description:
1666 *	Inserts an 8 bit integer into the protocol stream.
1667 */
1668void
1669_XEditResPut8(ProtocolStream *stream, unsigned int value)
1670{
1671    unsigned char temp;
1672
1673    if (stream->size >= stream->alloc)
1674    {
1675	stream->alloc += 100;
1676	stream->real_top = (unsigned char *)
1677	    XtRealloc((char *)stream->real_top, stream->alloc + HEADER_SIZE);
1678	stream->top = stream->real_top + HEADER_SIZE;
1679	stream->current = stream->top + stream->size;
1680    }
1681
1682    temp = (unsigned char) (value & BYTE_MASK);
1683    *((stream->current)++) = temp;
1684    (stream->size)++;
1685}
1686
1687/*
1688 * Function:
1689 *	_XEditResPut16
1690 *
1691 * Arguments:
1692 *	stream - stream to insert string into
1693 *	value  - value to insert
1694 *
1695 * Description:
1696 *	Inserts a 16 bit integer into the protocol stream.
1697 */
1698void
1699_XEditResPut16(ProtocolStream *stream, unsigned int value)
1700{
1701    _XEditResPut8(stream, (value >> XER_NBBY) & BYTE_MASK);
1702    _XEditResPut8(stream, value & BYTE_MASK);
1703}
1704
1705/*
1706 * Function:
1707 *	_XEditResPut32
1708 *
1709 * Arguments:
1710 *	stream - stream to insert string into
1711 *	value  - value to insert
1712 *
1713 * Description:
1714 *	Inserts a 32 bit integer into the protocol stream.
1715 */
1716void
1717_XEditResPut32(ProtocolStream *stream, unsigned long value)
1718{
1719    int i;
1720
1721    for (i = 3; i >= 0; i--)
1722	_XEditResPut8(stream, (value >> (XER_NBBY * i)) & BYTE_MASK);
1723}
1724
1725/*
1726 * Function:
1727 *	_XEditResPutWidgetInfo
1728 *
1729 * Parameters:
1730 *	stream - stream to insert widget info into
1731 *	info   - info to insert
1732 *
1733 * Description:
1734 *	Inserts the widget info into the protocol stream.
1735 */
1736void
1737_XEditResPutWidgetInfo(ProtocolStream *stream, WidgetInfo *info)
1738{
1739    unsigned int i;
1740
1741    _XEditResPut16(stream, info->num_widgets);
1742    for (i = 0; i < info->num_widgets; i++)
1743	_XEditResPut32(stream, info->ids[i]);
1744}
1745
1746/************************************************************
1747 * Code for retrieving values from the protocol stream
1748 ************************************************************/
1749/*
1750 * Function:
1751 *	_XEditResResetStream
1752 *
1753 * Parameters:
1754 *	stream - stream to reset
1755 *
1756 * Description:
1757 *	Resets the protocol stream.
1758 */
1759void
1760_XEditResResetStream(ProtocolStream *stream)
1761{
1762    stream->current = stream->top;
1763    stream->size = 0;
1764    if (stream->real_top == NULL)
1765    {
1766	stream->real_top = (unsigned char *)
1767	    XtRealloc((char *)stream->real_top, stream->alloc + HEADER_SIZE);
1768	stream->top = stream->real_top + HEADER_SIZE;
1769	stream->current = stream->top + stream->size;
1770    }
1771}
1772
1773/*
1774 * NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
1775 *
1776 * The only modified field if the "current" field
1777 *
1778 * The only fields that must be set correctly are the "current", "top"
1779 * and "size" fields.
1780 */
1781/*
1782 * Function:
1783 *	_XEditResGet8
1784 *
1785 * Parameters:
1786 *	stream - protocol stream
1787 *	value  - a pointer to value to return
1788 *
1789 * Description:
1790 *	Retrieves an unsigned 8 bit value from the protocol stream.
1791 *
1792 * Returns:
1793 *	True if successful
1794 */
1795Bool
1796_XEditResGet8(ProtocolStream *stream, unsigned char *value)
1797{
1798    if (stream->size < (unsigned long)(stream->current - stream->top))
1799	return (False);
1800
1801    *value = *((stream->current)++);
1802    return (True);
1803}
1804
1805/*
1806 * Function:
1807 *	_XEditResGet16
1808 *
1809 * Parameters:
1810 *	stream - protocol stream
1811 *	value  - pointer to return value
1812 *
1813 * Description:
1814 *	Retrieves an unsigned 16 bit value from the protocol stream.
1815 *
1816 * Returns:
1817 *	True if successful
1818 */
1819Bool
1820_XEditResGet16(ProtocolStream *stream, unsigned short *value)
1821{
1822    unsigned char temp1, temp2;
1823
1824    if (!(_XEditResGet8(stream, &temp1) && _XEditResGet8(stream, &temp2)))
1825	return (False);
1826
1827    *value = ((unsigned short)temp1 << XER_NBBY) + (unsigned short)temp2;
1828    return (True);
1829}
1830
1831/*
1832 * Function:
1833 *	_XEditResGetSigned16
1834 *
1835 * Parameters:
1836 *	stream - protocol stream
1837 *	value  - pointer to return value
1838 *
1839 * Description:
1840 *	Retrieves an signed 16 bit value from the protocol stream.
1841 *
1842 * Returns:
1843 *	True if successful
1844 */
1845Bool
1846_XEditResGetSigned16(ProtocolStream *stream, short *value)
1847{
1848    unsigned char temp1, temp2;
1849
1850    if (!(_XEditResGet8(stream, &temp1) && _XEditResGet8(stream, &temp2)))
1851	return (False);
1852
1853    if (temp1 & (1 << (XER_NBBY - 1)))	/* If the sign bit is active */
1854    {
1855      *value = -1;			/* store all 1's */
1856      *value &= (temp1 << XER_NBBY);	/* Now and in the MSB */
1857      *value &= temp2;			/* and LSB */
1858    }
1859    else
1860	*value = ((unsigned short)temp1 << XER_NBBY) + (unsigned short)temp2;
1861
1862    return (True);
1863}
1864
1865/*
1866 * Function:
1867 *	_XEditResGet32
1868 *
1869 * Parameters:
1870 *	stream - protocol stream
1871 *	value  - pointer to return value
1872 *
1873 * Description:
1874 *	Retrieves an unsigned 32 bit value from the protocol stream.
1875 *
1876 * Returns:
1877 *	True if successful
1878 */
1879Bool
1880_XEditResGet32(ProtocolStream *stream, unsigned long *value)
1881{
1882    unsigned short temp1, temp2;
1883
1884    if (!(_XEditResGet16(stream, &temp1) && _XEditResGet16(stream, &temp2)))
1885	return (False);
1886
1887    *value = ((unsigned long)temp1 << (XER_NBBY * 2)) + (unsigned long)temp2;
1888    return (True);
1889}
1890
1891/* Function:
1892 *	_XEditResGetString8
1893 *
1894 * Parameters:
1895 *	stream - protocol stream
1896 *	str    - string to retrieve
1897 *
1898 * Description:
1899 *	Retrieves an 8 bit string value from the protocol stream.
1900 *
1901 * Returns:
1902 *	True if retrieval was successful
1903 */
1904Bool
1905_XEditResGetString8(ProtocolStream *stream, char **str)
1906{
1907    unsigned short len;
1908    register unsigned i;
1909
1910    if (!_XEditResGet16(stream, &len))
1911	return (False);
1912
1913    *str = XtMalloc(sizeof(char) * (len + 1));
1914
1915    for (i = 0; i < len; i++)
1916    {
1917	if (!_XEditResGet8(stream, (unsigned char *)*str + i))
1918	{
1919	    XtFree(*str);
1920	    *str = NULL;
1921	    return (False);
1922	}
1923    }
1924    (*str)[i] = '\0';
1925
1926    return (True);
1927}
1928
1929/*
1930 * Function:
1931 *	_XEditResGetWidgetInfo
1932 *
1933 * Parameters:
1934 *	stream - protocol stream
1935 *	info   - widget info struct to store into
1936 *
1937 * Description:
1938 *	  Retrieves the list of widgets that follow and stores them in the
1939 *	widget info structure provided.
1940 *
1941 * Returns:
1942 *	True if retrieval was successful
1943 */
1944Bool
1945_XEditResGetWidgetInfo(ProtocolStream *stream, WidgetInfo *info)
1946{
1947    unsigned int i;
1948
1949    if (!_XEditResGet16(stream, &info->num_widgets))
1950	return (False);
1951
1952    info->ids = (unsigned long *)XtMalloc(sizeof(long) * info->num_widgets);
1953
1954    for (i = 0; i < info->num_widgets; i++)
1955    {
1956	if (!_XEditResGet32(stream, info->ids + i))
1957	{
1958	    XtFree((char *)info->ids);
1959	    info->ids = NULL;
1960	    return (False);
1961	}
1962#if defined(LONG64) || defined(WORD64)
1963	info->ids[i] |= globals.base_address;
1964#endif
1965    }
1966    return (True);
1967}
1968
1969/************************************************************
1970 * Code for Loading the EditresBlock resource
1971 ************************************************************/
1972/*
1973 * Function:
1974 *	CvtStringToBlock
1975 *
1976 * Parameters:
1977 *	dpy	       - display
1978 *	args	       - unused
1979 *	num_args       - unused
1980 *	from_val       - value to convert
1981 *	to_val	       - where to store
1982 *	converter_data - unused
1983 *
1984 * Description:
1985 *	Converts a string to an editres block value.
1986 *
1987 * Returns:
1988 *	True if conversion was successful
1989 */
1990/*ARGSUSED*/
1991static Boolean
1992CvtStringToBlock(Display *dpy, XrmValue *args, Cardinal *num_args,
1993		 XrmValue *from_val, XrmValue *to_val,
1994		 XtPointer *converter_data)
1995{
1996    char ptr[16];
1997    static EditresBlock block;
1998
1999    XmuNCopyISOLatin1Lowered(ptr, from_val->addr, sizeof(ptr));
2000
2001    if (streq(ptr, "none"))
2002	block = BlockNone;
2003    else if (streq(ptr, "setvalues"))
2004	block = BlockSetValues;
2005    else if (streq(ptr, "all"))
2006	block = BlockAll;
2007    else
2008    {
2009	Cardinal num_params = 1;
2010	String params[1];
2011
2012	params[0] = from_val->addr;
2013	XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
2014			"CvtStringToBlock", "unknownValue", "EditresError",
2015			"Could not convert string \"%s\" to EditresBlock.",
2016			params, &num_params);
2017	return FALSE;
2018    }
2019
2020    if (to_val->addr != NULL)
2021    {
2022	if (to_val->size < sizeof(EditresBlock))
2023	{
2024	    to_val->size = sizeof(EditresBlock);
2025	    return FALSE;
2026	}
2027	*(EditresBlock *)(to_val->addr) = block;
2028    }
2029    else
2030	to_val->addr = (XtPointer)block;
2031
2032    to_val->size = sizeof(EditresBlock);
2033    return TRUE;
2034}
2035
2036#define XtREditresBlock		"EditresBlock"
2037/*
2038 * Function:
2039 *	LoadResources
2040 *
2041 * Parameters:
2042 *	w - any widget in the tree
2043 *
2044 * Description:
2045 *	  Loads a global resource the determines of this application should
2046 *	allow Editres requests.
2047 */
2048static void
2049LoadResources(Widget w)
2050{
2051    static XtResource resources[] = {
2052        {"editresBlock", "EditresBlock", XtREditresBlock, sizeof(EditresBlock),
2053	 XtOffsetOf(Globals, block), XtRImmediate, (XtPointer)BlockNone}
2054    };
2055
2056    for (; XtParent(w) != NULL; w = XtParent(w))
2057	;
2058
2059    XtAppSetTypeConverter(XtWidgetToApplicationContext(w),
2060			  XtRString, XtREditresBlock, CvtStringToBlock,
2061			  NULL, 0, XtCacheAll, NULL);
2062
2063    XtGetApplicationResources(w, (XtPointer)&globals, resources,
2064			      XtNumber(resources), NULL, 0);
2065}
2066
2067/*
2068 * Function:
2069 *	_XEditresGetStringValues
2070 *
2071 * Parameters:
2072 *	w	- widget
2073 *	warg	- where to store result
2074 *	numargs	- unused
2075 */
2076/*ARGSUSED*/
2077static void
2078_XEditresGetStringValues(Widget w, Arg *warg, int numargs)
2079{
2080    static char buffer[32];
2081    XtResourceList res_list;
2082    Cardinal num_res;
2083    XtResource *res = NULL;
2084    long value;
2085    Cardinal i;
2086    const char *string = "";
2087    Arg args[1];
2088    XrmValue to, from;
2089
2090    /*
2091     * Look for the resource
2092     */
2093    XtGetResourceList(XtClass(w), &res_list, &num_res);
2094    for (i = 0; i < num_res; i++)
2095	if (strcmp(res_list[i].resource_name, warg->name) == 0)
2096	{
2097	    res = &res_list[i];
2098	    break;
2099	}
2100
2101    if (res == NULL && XtParent(w) != NULL)
2102    {
2103	XtFree((char *)res_list);
2104	XtGetConstraintResourceList(XtClass(XtParent(w)), &res_list, &num_res);
2105	for (i = 0; i < num_res; i++)
2106	    if (strcmp(res_list[i].resource_name, warg->name) == 0)
2107	    {
2108		res = &res_list[i];
2109		break;
2110	    }
2111    }
2112
2113    if (res == NULL)
2114    {
2115	/* Couldn't find resource */
2116
2117	XtFree((char *)res_list);
2118	*(XtPointer *)warg->value = NULL;
2119	return;
2120    }
2121
2122    /* try to get the value in the proper size */
2123    switch (res->resource_size)
2124    {
2125#ifdef LONG64
2126	long v8;
2127#endif
2128	int v4;
2129	short v2;
2130	char v1;
2131
2132    case 1:
2133	XtSetArg(args[0], res->resource_name, &v1);
2134	XtGetValues(w, args, 1);
2135	value = (int)v1;
2136	break;
2137    case 2:
2138	XtSetArg(args[0], res->resource_name, &v2);
2139	XtGetValues(w, args, 1);
2140	value = (int)v2;
2141	break;
2142    case 4:
2143	XtSetArg(args[0], res->resource_name, &v4);
2144	XtGetValues(w, args, 1);
2145	value = (int)v4;
2146	break;
2147#ifdef LONG64
2148    case 8:
2149	XtSetArg(args[0], res->resource_name, &v8);
2150	XtGetValues(w, args, 1);
2151	value = (long)v8;
2152	break;
2153#endif
2154    default:
2155	fprintf(stderr, "_XEditresGetStringValues: bad size %d\n",
2156		res->resource_size);
2157	string = "bad size";
2158	*(char **)(warg->value) = (char *) string;
2159	XtFree((char *)res_list);
2160	return;
2161    }
2162
2163    /*
2164     * If the resource is already String, no conversion needed
2165     */
2166    if (strcmp(XtRString, res->resource_type) == 0)
2167    {
2168	if (value == 0)
2169	    string = "(null)";
2170	else
2171	    string = (char *)value;
2172    }
2173    else
2174    {
2175	from.size = res->resource_size;
2176	from.addr = (XPointer)&value;
2177	to.addr = NULL;
2178	to.size = 0;
2179
2180	if (XtConvertAndStore(w,res->resource_type, &from, XtRString, &to))
2181	    string = to.addr;
2182	else
2183	{
2184	    string = buffer;
2185	    /*
2186	     * Conversion failed, fall back to representing it as integer
2187	     */
2188	    switch (res->resource_size)
2189	    {
2190	    case sizeof(char):
2191		XmuSnprintf(buffer, sizeof(buffer), "%d", (int)(value & 0xff));
2192		break;
2193	    case sizeof(short):
2194		XmuSnprintf(buffer, sizeof(buffer), "%d", (int)(value & 0xffff));
2195		break;
2196	    case sizeof(int):
2197		XmuSnprintf(buffer, sizeof(buffer), "0x%08x", (int)value);
2198		break;
2199#ifdef LONG64
2200	    case sizeof(long):
2201		XmuSnprintf(buffer, sizeof(buffer), "0x%016lx", value);
2202		break;
2203#endif
2204	    }
2205	}
2206    }
2207
2208    if (string == NULL)
2209	string = "";
2210
2211    *(char **)(warg->value) = (char *) string;
2212    XtFree((char *)res_list);
2213}
2214