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