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