comm.c revision 988795be
1/*
2
3Copyright 1990, 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
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27*/
28
29
30/*
31 * This file contains the code to communicate with the client that is
32 * being edited.
33 */
34
35#include <X11/Intrinsic.h>
36#include <X11/StringDefs.h>	/* Get standard string definitions. */
37#include <X11/Xatom.h>
38#include <X11/cursorfont.h>	/* For crosshair cursor. */
39#include <X11/Xproto.h>
40#include <X11/Xos.h>		/* for XtNewString */
41
42#include <stdio.h>
43#include <X11/Xmu/Error.h>
44#include <X11/Xmu/WinUtil.h>
45
46#include "editresP.h"
47
48/*
49 * static Globals.
50 */
51
52static Atom atom_comm, atom_command, atom_resource_editor, atom_client_value;
53static Atom atom_editres_protocol;
54
55extern Widget CM_entries[NUM_CM_ENTRIES], TM_entries[NUM_TM_ENTRIES];
56
57static void ClientTimedOut ( XtPointer data, XtIntervalId * id );
58static void TellUserAboutMessage ( Widget label, ResCommand command );
59static Boolean ConvertCommand ( Widget w, Atom * selection, Atom * target,
60				Atom * type_ret, XtPointer *value_ret,
61				unsigned long * length_ret, int * format_ret );
62static void SelectionDone ( Widget w, Atom *sel, Atom *targ );
63static void LoseSelection ( Widget w, Atom * sel );
64static void GetClientValue ( Widget w, XtPointer data, Atom *selection,
65			     Atom *type, XtPointer value,
66			     unsigned long *length, int * format );
67static void BuildHeader ( CurrentClient * client_data );
68static Event * BuildEvent ( ProtocolStream * stream );
69static void FreeEvent ( Event * event );
70static char * DispatchEvent ( Event * event );
71
72
73
74/*	Function Name: ClientTimedOut
75 *	Description: Called if the client takes too long to take our selection.
76 *	Arguments: data - The widget that owns the client
77 *                        communication selection.
78 *                 id - *** UNUSED ***
79 *	Returns: none.
80 */
81
82/* ARGSUSED */
83static void
84ClientTimedOut(XtPointer data, XtIntervalId *id)
85{
86  char msg[BUFSIZ];
87  Widget w = (Widget) data;
88
89  global_client.ident = NO_IDENT;
90  XtDisownSelection(w, global_client.atom,
91		    XtLastTimestampProcessed(XtDisplay(w)));
92
93  sprintf(msg, res_labels[4],
94	  "the Editres Protocol.");
95  SetMessage(global_screen_data.info_label, msg);
96}
97
98
99
100/*	Function Name: GetClientWindow
101 *	Description: Gets the Client's window by asking the user.
102 *	Arguments: w - a widget.
103 *	Returns: a clients window, or None.
104 */
105
106Window
107GetClientWindow(Widget w, int *x, int *y)
108{
109  int status;
110  Cursor cursor;
111  XEvent event;
112  int buttons = 0;
113  Display * dpy = XtDisplayOfObject(w);
114  Window target_win = None, root = RootWindowOfScreen(XtScreenOfObject(w));
115  XtAppContext app = XtWidgetToApplicationContext(w);
116
117  /* Make the target cursor */
118  cursor = XCreateFontCursor(dpy, XC_crosshair);
119
120  /* Grab the pointer using target cursor, letting it room all over */
121  status = XGrabPointer(dpy, root, False,
122			ButtonPressMask|ButtonReleaseMask, GrabModeSync,
123			GrabModeAsync, root, cursor, CurrentTime);
124  if (status != GrabSuccess) {
125    SetMessage(global_screen_data.info_label, res_labels[5]);
126    return(None);
127  }
128
129  /* Let the user select a window... */
130  while ((target_win == None) || (buttons != 0)) {
131    /* allow one more event */
132    XAllowEvents(dpy, SyncPointer, CurrentTime);
133    XtAppNextEvent(app, &event);
134    switch (event.type) {
135    case ButtonPress:
136      if (event.xbutton.window != root) {
137	XtDispatchEvent(&event);
138	break;
139      }
140
141      if (target_win == None) {
142	target_win = event.xbutton.subwindow; /* window selected */
143	if (x != NULL)
144	  *x = event.xbutton.x_root;
145	if (y != NULL)
146	  *y = event.xbutton.y_root;
147      }
148      buttons++;
149      break;
150    case ButtonRelease:
151      if (event.xbutton.window != root) {
152	XtDispatchEvent(&event);
153	break;
154      }
155
156      if (buttons > 0) /* There may have been some
157			  down before we started */
158	buttons--;
159      break;
160    default:
161      XtDispatchEvent(&event);
162      break;
163    }
164  }
165
166  XUngrabPointer(dpy, CurrentTime);      /* Done with pointer */
167
168  return(XmuClientWindow(dpy, target_win));
169}
170
171
172
173/*	Function Name: SetCommand
174 *	Description: Causes this widget to own the resource editor's
175 *                   command selection.
176 *	Arguments: w - the widget that will own the selection.
177 *                 command - command to send to client.
178 *                 msg - message to prompt the user to select a client.
179 *	Returns: none.
180 */
181
182/* ARGSUSED */
183void
184SetCommand(Widget w, ResCommand command, char *msg)
185{
186  XClientMessageEvent client_event;
187  Display * dpy = XtDisplay(w);
188
189  if (msg == NULL)
190    msg = res_labels[6];
191
192  SetMessage(global_screen_data.info_label, msg);
193
194  if (global_client.window == None)
195    if ( (global_client.window = GetClientWindow(w, NULL, NULL)) == None)
196      return;
197
198  global_client.ident = GetNewIdent();
199
200  global_client.command = command;
201  global_client.atom = atom_comm;
202
203  BuildHeader(&(global_client));
204
205  if (!XtOwnSelection(w, global_client.atom, CurrentTime, ConvertCommand,
206		      LoseSelection, SelectionDone))
207    SetMessage(global_screen_data.info_label,
208	       res_labels[7]);
209
210  client_event.window = global_client.window;
211  client_event.type = ClientMessage;
212  client_event.message_type = atom_resource_editor;
213  client_event.format = EDITRES_SEND_EVENT_FORMAT;
214  client_event.data.l[0] = XtLastTimestampProcessed(dpy);
215  client_event.data.l[1] = global_client.atom;
216  client_event.data.l[2] = (long) global_client.ident;
217  client_event.data.l[3] = global_effective_protocol_version;
218
219  global_error_code = NO_ERROR;                 /* Reset Error code. */
220  global_old_error_handler = XSetErrorHandler(HandleXErrors);
221  global_serial_num = NextRequest(dpy);
222
223  XSendEvent(dpy, global_client.window, FALSE, (long) 0,
224	     (XEvent *) &client_event);
225
226  XSync(dpy, FALSE);
227  XSetErrorHandler(global_old_error_handler);
228  if (global_error_code == NO_WINDOW) {
229    char error_buf[BUFSIZ];
230
231    global_error_code = NO_ERROR;	/* Reset Error code. */
232    sprintf(error_buf, "The communication window with%s%s.",
233	    " application is no longer available\n",
234	    "Please select a new widget tree");
235
236    global_client.window = None;
237    SetCommand(w, LocalSendWidgetTree, error_buf);
238    return;
239  }
240
241  TellUserAboutMessage(global_screen_data.info_label, command);
242  global_client.timeout = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
243					  CLIENT_TIME_OUT,
244					  ClientTimedOut, (XtPointer) w);
245}
246
247
248
249/*	Function Name: TellUserAboutMessage
250 *	Description: Informs the user that we have sent a message to the client
251 *	Arguments: label - the info label.
252 *                 command - command that we have executed.
253 *	Returns: none.
254 */
255
256static void
257TellUserAboutMessage(Widget label, ResCommand command)
258{
259    char msg[BUFSIZ], *str;
260
261    switch(command) {
262    case LocalSendWidgetTree:
263	str = " asking for widget tree";
264	break;
265    case LocalSetValues:
266	str = " asking it to perform SetValues()";
267	break;
268    case LocalFlashWidget:
269    case LocalGetGeometry:
270	str = " asking it to perform GetGeometry()";
271	break;
272    case LocalGetResources:
273	str = " asking it to get a widget's resource list";
274	break;
275    case LocalFindChild:
276	str = " asking it to find the child Widget.";
277	break;
278    default:
279	str = "";
280	break;
281    }
282
283    sprintf(msg, res_labels[8], str);
284    SetMessage(label, msg);
285}
286
287
288
289/*	Function Name: ConvertCommand
290 *	Description: Converts the command string into a selection that can
291 *                   be sent to the client.
292 *	Arguments: (see Xt)
293 *	Returns: TRUE if we could convert the selection and target asked for.
294 */
295
296/* ARGSUSED */
297static Boolean
298ConvertCommand(Widget w, Atom *selection, Atom *target, Atom *type_ret,
299	       XtPointer *value_ret, unsigned long *length_ret, int *format_ret)
300{
301    if ((*selection != atom_comm) || (*target != atom_command))
302	return(FALSE);
303
304    *type_ret = atom_editres_protocol;
305    *value_ret = (XtPointer) global_client.stream.real_top;
306    *length_ret = global_client.stream.size + HEADER_SIZE;
307    *format_ret = EDITRES_FORMAT;
308
309    return(TRUE);
310}
311
312
313
314/*	Function Name: SelectionDone
315 *	Description: done with the selection.
316 *	Arguments: *** UNUSED ***
317 *	Returns: none.
318 */
319
320/* ARGSUSED */
321static void
322SelectionDone(Widget w, Atom *sel, Atom *targ)
323{
324    /* Keep the toolkit from automaticaly freeing the selection value */
325}
326
327
328
329/*	Function Name: LoseSelection
330 *	Description: Called when we have lost the selection, asks client
331 *                   for the selection value.
332 *	Arguments: w - the widget that just lost the selection.
333 *                 sel - the selection.
334 *	Returns: none.
335 */
336
337static void
338LoseSelection(Widget w, Atom *sel)
339{
340    if (global_client.timeout != 0) {
341	XtRemoveTimeOut(global_client.timeout);
342	global_client.timeout = 0;
343    }
344
345    XtGetSelectionValue(w, *sel, atom_client_value, GetClientValue,
346			NULL, XtLastTimestampProcessed(XtDisplay(w)));
347}
348
349
350
351/*	Function Name: GetClientValue
352 *	Description: Gets the value out of the client, and does good things
353 *                   to it.
354 *	Arguments: w - the widget that asked for the selection.
355 *                 data - client_data *** UNUSED ***.
356 *                 sel - the selection.
357 *                 type - the type of the selection.
358 *                 value - the selection's value.
359 *                 length - the length of the selection's value.
360 *                 format - the format of the selection.
361 *	Returns: none.
362 */
363
364static Boolean reset_protocol_level = True;
365
366/* ARGSUSED */
367static void
368GetClientValue(Widget w, XtPointer data, Atom *selection, Atom *type,
369	       XtPointer value, unsigned long *length, int *format)
370{
371    Event * event;
372    ProtocolStream alloc_stream, *stream;
373    unsigned char ident, error_code;
374    char * error_str = NULL, msg[BUFSIZ];
375
376    if (*length == 0)
377	return;
378
379    stream = &alloc_stream;	/* easier to think of it this way... */
380
381    stream->current = stream->top = (unsigned char *) value;
382    stream->size = HEADER_SIZE;		/* size of header. */
383
384    /*
385     * Retrieve the Header.
386     */
387
388    if (*length < HEADER_SIZE) {
389	SetMessage(global_screen_data.info_label,
390		   res_labels[9]);
391	return;
392    }
393
394    (void) _XEditResGet8(stream, &ident);
395    if (global_client.ident != ident) {
396#ifdef DEBUG
397	if (global_resources.debug)
398	    printf("Incorrect ident from client.\n");
399#endif
400	if (!XtOwnSelection(w, *selection, CurrentTime, ConvertCommand,
401			    LoseSelection, SelectionDone))
402	    SetMessage(global_screen_data.info_label,
403		       res_labels[10]);
404	return;
405    }
406
407    (void) _XEditResGet8(stream, &error_code);
408    (void) _XEditResGet32(stream, &(stream->size));
409    stream->top = stream->current; /* reset stream to top of value.*/
410
411    switch ((int) error_code) {
412    case PartialSuccess:
413/*****
414        if (global_client.command == LocalSendWidgetTree &&
415	    global_effective_protocol_version < CURRENT_PROTOCOL_VERSION)
416	  ++global_effective_protocol_version;
417*****/
418	if ((event = BuildEvent(stream)) != NULL) {
419	    error_str = DispatchEvent(event);
420	    FreeEvent(event);
421	}
422	else {
423	    sprintf(msg, "Unable to unpack protocol request.");
424	    error_str = XtNewString(msg);
425	}
426	break;
427    case Failure:
428	error_str = GetFailureMessage(stream);
429	break;
430    case ProtocolMismatch:
431	error_str = ProtocolFailure(stream);
432	--global_effective_protocol_version;
433	/* normaly protocol version is reset to current during a SendWidgetTree
434         * request, however, after a protocol failure this is skiped once for
435         * a retry.
436         */
437	reset_protocol_level = False;
438	SetCommand(w, LocalSendWidgetTree, NULL);
439	break;
440    default:
441	sprintf(msg, res_labels[11], (int) error_code);
442	SetMessage(global_screen_data.info_label, msg);
443	break;
444    }
445
446    if (error_str == NULL) {
447	WNode * top;
448
449	if (global_tree_info == NULL)
450	    return;
451
452	top = global_tree_info->top_node;
453	sprintf(msg, res_labels[12], top->name, top->class);
454	SetMessage(global_screen_data.info_label, msg);
455	return;
456    }
457    SetMessage(global_screen_data.info_label, error_str);
458    XtFree(error_str);
459}
460
461
462
463/*	Function Name: BuildHeader
464 *	Description: Puts the header into the message.
465 *	Arguments: client_data - the client data.
466 *	Returns: none.
467 */
468
469static void
470BuildHeader(CurrentClient *client_data)
471{
472    unsigned long old_alloc, old_size;
473    unsigned char * old_current;
474    EditresCommand command;
475    ProtocolStream * stream = &(client_data->stream);
476
477    /*
478     * We have cleverly keep enough space at the top of the header
479     * for the return protocol stream, so all we have to do is
480     * fill in the space.
481     */
482
483    /*
484     * Fool the insert routines into putting the header in the right
485     * place while being damn sure not to realloc (that would be very bad.
486     */
487
488    old_current = stream->current;
489    old_alloc = stream->alloc;
490    old_size = stream->size;
491
492    stream->current = stream->real_top;
493    stream->alloc = stream->size + (2 * HEADER_SIZE);
494
495    _XEditResPut8(stream, client_data->ident);
496    switch(client_data->command) {
497    case LocalSendWidgetTree:
498        if (reset_protocol_level) global_effective_protocol_version =
499	  CURRENT_PROTOCOL_VERSION;
500        reset_protocol_level = True;
501	command = SendWidgetTree;
502	break;
503    case LocalSetValues:
504	command = SetValues;
505	break;
506    case LocalFlashWidget:
507	command = GetGeometry;
508	break;
509    case LocalGetResources:
510	command = GetResources;
511	break;
512    case LocalFindChild:
513	command = FindChild;
514	break;
515    case LocalGetValues:
516	command = GetValues;
517	break;
518    default:
519	command = SendWidgetTree;
520	break;
521    }
522
523    _XEditResPut8(stream, (unsigned char) command);
524    _XEditResPut32(stream, old_size);
525
526    stream->alloc = old_alloc;
527    stream->current = old_current;
528    stream->size = old_size;
529}
530
531
532
533/*	Function Name: BuildEvent
534 *	Description: Builds the event structure from the
535 *	Arguments: stream - the protocol data stream.
536 *	Returns: event - the event.
537 */
538
539static Event *
540BuildEvent(ProtocolStream *stream)
541{
542    int i;
543    Event * event = (Event *) XtCalloc(sizeof(Event), 1);
544
545    /*
546     * The return value will be different depending upon the
547     * request sent out.
548     */
549
550    switch(global_client.command) {
551    case LocalSendWidgetTree:
552        {
553	    SendWidgetTreeEvent * send_event = (SendWidgetTreeEvent *) event;
554
555	    send_event->type = SendWidgetTree;
556
557	    if (!_XEditResGet16(stream, &(send_event->num_entries)))
558		goto done;
559
560	    send_event->info = (WidgetTreeInfo *)
561		                XtCalloc(sizeof(WidgetTreeInfo),
562					 send_event->num_entries);
563
564	    for (i = 0; i < (int)send_event->num_entries; i++) {
565		WidgetTreeInfo * info = send_event->info + i;
566		if (!(_XEditResGetWidgetInfo(stream, &(info->widgets)) &&
567		      _XEditResGetString8(stream, &(info->name)) &&
568		      _XEditResGetString8(stream, &(info->class)) &&
569		      _XEditResGet32(stream, &(info->window))))
570		{
571		    goto done;
572		}
573	    }
574
575	    if (global_effective_protocol_version ==
576		CURRENT_PROTOCOL_VERSION) {
577				/* get toolkit type and reset if necessary */
578	      if (!_XEditResGetString8(stream, &(send_event->toolkit)))
579 	        goto done;
580	    }
581	    /* set the command menu entries senitive */
582	    SetEntriesSensitive(&CM_entries[CM_OFFSET], CM_NUM, True);
583	    /* set the tree menu entries senitive */
584	    SetEntriesSensitive(TM_entries, TM_NUM, True);
585	    if (global_effective_protocol_version ==
586		CURRENT_PROTOCOL_VERSION) {
587	      if (!strcmp(send_event->toolkit, "InterViews"))
588	        RebuildMenusAndLabel("iv");
589            }
590            else
591              RebuildMenusAndLabel("xt");
592	}
593	break;
594    case LocalSetValues:
595        {
596	    SetValuesEvent * sv_event = (SetValuesEvent *) event;
597
598	    sv_event->type = SetValues;
599
600	    if (!_XEditResGet16(stream, &(sv_event->num_entries)))
601		goto done;
602
603	    sv_event->info = (SetValuesInfo *) XtCalloc(sizeof(SetValuesInfo),
604							sv_event->num_entries);
605
606	    for (i = 0; i < (int)sv_event->num_entries; i++) {
607		SetValuesInfo * info = sv_event->info + i;
608		if (!(_XEditResGetWidgetInfo(stream, &(info->widgets)) &&
609		      _XEditResGetString8(stream, &(info->message))))
610		{
611		    goto done;
612		}
613	    }
614	}
615	break;
616    case LocalGetResources:
617        {
618	    GetResourcesEvent * res_event = (GetResourcesEvent *) event;
619
620	    res_event->type = GetGeometry;
621
622	    if (!_XEditResGet16(stream, &(res_event->num_entries)))
623		goto done;
624
625	    res_event->info = (GetResourcesInfo *)
626		                   XtCalloc(sizeof(GetResourcesInfo),
627					    res_event->num_entries);
628
629	    for (i = 0; i < (int)res_event->num_entries; i++) {
630		GetResourcesInfo * res_info = res_event->info + i;
631		if (!(_XEditResGetWidgetInfo(stream, &(res_info->widgets)) &&
632		      _XEditResGetBoolean(stream, &(res_info->error))))
633		{
634		    goto done;
635		}
636		if (res_info->error) {
637		    if (!_XEditResGetString8(stream, &(res_info->message)))
638			goto done;
639		}
640		else {
641		    unsigned int j;
642
643		    if (!_XEditResGet16(stream, &(res_info->num_resources)))
644			goto done;
645
646		    res_info->res_info = (ResourceInfo *)
647			                  XtCalloc(sizeof(ResourceInfo),
648						   res_info->num_resources);
649
650		    for (j = 0; j < res_info->num_resources; j++) {
651			unsigned char temp;
652			ResourceInfo * info = res_info->res_info + j;
653			if (!(_XEditResGetResType(stream, &(temp)) &&
654			      _XEditResGetString8(stream, &(info->name)) &&
655			      _XEditResGetString8(stream, &(info->class)) &&
656			      _XEditResGetString8(stream, &(info->type))))
657			{
658			    goto done;
659			}
660			else
661			    info->res_type = (ResourceType) temp;
662		    } /* for */
663		} /* else */
664	    } /* for */
665	}
666	break;
667    case LocalFlashWidget:
668    case LocalGetGeometry:
669        {
670	    GetGeomEvent * geom_event = (GetGeomEvent *) event;
671
672	    geom_event->type = GetGeometry;
673
674	    if (!_XEditResGet16(stream, &(geom_event->num_entries)))
675		goto done;
676
677	    geom_event->info = (GetGeomInfo *) XtCalloc(sizeof(GetGeomInfo),
678						      geom_event->num_entries);
679
680	    for (i = 0; i < (int)geom_event->num_entries; i++) {
681		GetGeomInfo * info = geom_event->info + i;
682		if (!(_XEditResGetWidgetInfo(stream, &(info->widgets)) &&
683		      _XEditResGetBoolean(stream, &(info->error))))
684		{
685		    goto done;
686		}
687		if (info->error) {
688		    if (!_XEditResGetString8(stream, &(info->message)))
689			goto done;
690		}
691		else {
692		    if (!(_XEditResGetBoolean(stream, &(info->visable)) &&
693			  _XEditResGetSigned16(stream, &(info->x)) &&
694			  _XEditResGetSigned16(stream, &(info->y)) &&
695			  _XEditResGet16(stream, &(info->width)) &&
696			  _XEditResGet16(stream, &(info->height)) &&
697			  _XEditResGet16(stream, &(info->border_width))))
698		    {
699			goto done;
700		    }
701		}
702	    }
703	}
704	break;
705    case LocalFindChild:
706        {
707	    FindChildEvent * find_event = (FindChildEvent *) event;
708
709	    find_event->type = FindChild;
710
711	    if (!_XEditResGetWidgetInfo(stream, &(find_event->widgets)))
712		goto done;
713	}
714	break;
715    case LocalGetValues: /* This is for REPLY... */
716	{
717	  Arg args[1];
718	  GetValuesEvent * gv_event = (GetValuesEvent *) event;
719
720	  gv_event->type = GetValues;
721
722	  if (!_XEditResGet16(stream, &(gv_event->num_entries)))
723	    goto done;
724
725	  gv_event->info = (GetValuesInfo*)XtCalloc(sizeof(GetValuesInfo),1);
726
727	  {
728	    GetValuesInfo * info = gv_event->info;
729	    if (!(_XEditResGetString8(stream, &(info->value))))
730	      {
731		goto done;
732	      }
733
734	    /* set the string value of the asciitext widget. note that only
735             * one active node is dealt with here.  This is ok because only
736	     * one node can be active when the resource box is up.
737	     */
738
739	    XtSetArg (args[0], XtNstring, info->value);
740
741	    XtSetValues(
742	      global_tree_info->active_nodes[0]->resources->res_box->value_wid,
743 	      args, 1
744	    );
745	  }
746	}
747	break;
748
749    default:
750	goto done;
751    }
752
753    return(event);
754
755 done:
756    FreeEvent(event);
757    return(NULL);
758}
759
760
761
762/*	Function Name: FreeEvent
763 *	Description: Frees all memory associated with the event.
764 *	Arguments: event - the event.
765 *	Returns: none.
766 *
767 * NOTE: XtFree() returns w/o freeing if ptr is NULL.
768 */
769
770static void
771FreeEvent(Event *event)
772{
773    unsigned int i;
774
775    switch(event->any_event.type) {
776    case SendWidgetTree:
777        {
778	    SendWidgetTreeEvent * send_event = (SendWidgetTreeEvent *) event;
779	    WidgetTreeInfo * info = send_event->info;
780
781	    if (info != NULL) {
782		for (i = 0; i < send_event->num_entries; i++, info++) {
783		    XtFree((char *)info->widgets.ids);
784		    XtFree(info->name);
785		    XtFree(info->class);
786		}
787		XtFree((char *)send_event->info);
788	    }
789	}
790	break;
791    case SetValues:
792        {
793	    SetValuesEvent * sv_event = (SetValuesEvent *) event;
794	    SetValuesInfo * info = sv_event->info;
795
796	    if (info != NULL) {
797		for (i = 0; i < sv_event->num_entries; i++, info++) {
798		    XtFree((char *)info->widgets.ids);
799		    XtFree(info->message);
800		}
801		XtFree((char *)sv_event->info);
802	    }
803	}
804	break;
805    case GetResources:
806        {
807	    GetResourcesEvent * get_event = (GetResourcesEvent *) event;
808	    GetResourcesInfo * info = get_event->info;
809
810	    if (info != NULL) {
811		for (i = 0; i < get_event->num_entries; i++, info++) {
812		    XtFree((char *)info->widgets.ids);
813		    if (info->error)
814			XtFree(info->message);
815		    else {
816			unsigned int j;
817			ResourceInfo * res_info = info->res_info;
818
819			if (res_info != NULL) {
820			    for (j = 0;
821				 j < info->num_resources; j++, res_info++)
822			    {
823				XtFree(res_info->name);
824				XtFree(res_info->class);
825				XtFree(res_info->type);
826			    }
827			    XtFree((char *)info->res_info);
828			}
829		    }
830		}
831		XtFree((char *)get_event->info);
832	    }
833	}
834	break;
835    case GetGeometry:
836        {
837	    GetGeomEvent * geom_event = (GetGeomEvent *) event;
838	    GetGeomInfo * info = geom_event->info;
839
840	    if (info != NULL) {
841		for (i = 0; i < geom_event->num_entries; i++, info++) {
842		    XtFree((char *)info->widgets.ids);
843		    if (info->error)
844			XtFree(info->message);
845		}
846		XtFree((char *)geom_event->info);
847	    }
848	}
849	break;
850    case FindChild:
851        {
852	    FindChildEvent * find_event = (FindChildEvent *) event;
853
854	    XtFree((char *)find_event->widgets.ids);
855	}
856	break;
857    default:
858	break;
859    }
860}
861
862
863
864/*	Function Name: DispatchEvent
865 *	Description: Handles the event, calling the proper function.
866 *	Arguments: event - the event.
867 *	Returns: one.
868 */
869
870static char *
871DispatchEvent(Event *event)
872{
873    char * error = NULL;
874
875    switch(global_client.command) {
876    case LocalSendWidgetTree:
877	BuildVisualTree(global_tree_parent, event);
878	break;
879    case LocalSetValues:
880	error = PrintSetValuesError(event);
881	break;
882    case LocalFlashWidget:
883	error = HandleFlashWidget(event);
884	break;
885    case LocalGetResources:
886	error = HandleGetResources(event);
887	break;
888    case LocalFindChild:
889	DisplayChild(event);
890	break;
891    case LocalGetValues:
892	break;
893    default:
894        {
895	    char msg[BUFSIZ];
896	    sprintf(msg, "Internal error: Unknown command %d.",
897		    global_client.command);
898	    error = XtNewString(msg);
899	}
900	break;
901    }
902    return(error);
903}
904
905
906
907/*	Function Name: InternAtoms
908 *	Description: interns all static atoms.
909 *	Arguments: display - the current display.
910 *	Returns: none.
911 */
912
913void
914InternAtoms(Display * dpy)
915{
916    atom_comm = XInternAtom(dpy, EDITRES_COMM_ATOM, False);
917    atom_command = XInternAtom(dpy, EDITRES_COMMAND_ATOM, False);
918    atom_resource_editor = XInternAtom(dpy, EDITRES_NAME, False);
919    atom_client_value = XInternAtom(dpy, EDITRES_CLIENT_VALUE, False);
920    atom_editres_protocol = XInternAtom(dpy, EDITRES_PROTOCOL_ATOM, False);
921}
922
923ResIdent
924GetNewIdent(void)
925{
926    static ResIdent ident = 1;
927
928    return(ident++);
929}
930
931