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