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