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