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