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