133c89af1Smrg/*
233c89af1Smrg
333c89af1SmrgCopyright 1990, 1998  The Open Group
433c89af1Smrg
533c89af1SmrgPermission to use, copy, modify, distribute, and sell this software and its
633c89af1Smrgdocumentation for any purpose is hereby granted without fee, provided that
733c89af1Smrgthe above copyright notice appear in all copies and that both that
833c89af1Smrgcopyright notice and this permission notice appear in supporting
933c89af1Smrgdocumentation.
1033c89af1Smrg
1133c89af1SmrgThe above copyright notice and this permission notice shall be included
1233c89af1Smrgin all copies or substantial portions of the Software.
1333c89af1Smrg
1433c89af1SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1533c89af1SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1633c89af1SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1733c89af1SmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
1833c89af1SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1933c89af1SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2033c89af1SmrgOTHER DEALINGS IN THE SOFTWARE.
2133c89af1Smrg
2233c89af1SmrgExcept as contained in this notice, the name of The Open Group shall
2333c89af1Smrgnot be used in advertising or otherwise to promote the sale, use or
2433c89af1Smrgother dealings in this Software without prior written authorization
2533c89af1Smrgfrom The Open Group.
2633c89af1Smrg
2733c89af1Smrg*/
2833c89af1Smrg
2933c89af1Smrg
3033c89af1Smrg/*
3133c89af1Smrg * This file contains the code to communicate with the client that is
3233c89af1Smrg * being edited.
3333c89af1Smrg */
3433c89af1Smrg
3538d718bdSmrg#ifdef HAVE_CONFIG_H
3638d718bdSmrg# include "config.h"
3738d718bdSmrg#endif
3838d718bdSmrg
3933c89af1Smrg#include <X11/Intrinsic.h>
4033c89af1Smrg#include <X11/StringDefs.h>	/* Get standard string definitions. */
4133c89af1Smrg#include <X11/Xatom.h>
4233c89af1Smrg#include <X11/cursorfont.h>	/* For crosshair cursor. */
4333c89af1Smrg#include <X11/Xproto.h>
4433c89af1Smrg#include <X11/Xos.h>		/* for XtNewString */
4533c89af1Smrg
4633c89af1Smrg#include <stdio.h>
4733c89af1Smrg#include <X11/Xmu/Error.h>
4833c89af1Smrg#include <X11/Xmu/WinUtil.h>
4933c89af1Smrg
5033c89af1Smrg#include "editresP.h"
5133c89af1Smrg
5233c89af1Smrg/*
5333c89af1Smrg * static Globals.
5433c89af1Smrg */
5533c89af1Smrg
5633c89af1Smrgstatic Atom atom_comm, atom_command, atom_resource_editor, atom_client_value;
5733c89af1Smrgstatic Atom atom_editres_protocol;
5833c89af1Smrg
5933c89af1Smrgstatic void ClientTimedOut ( XtPointer data, XtIntervalId * id );
6033c89af1Smrgstatic void TellUserAboutMessage ( Widget label, ResCommand command );
61ad47b356Smrgstatic Boolean ConvertCommand ( Widget w, Atom * selection, Atom * target,
62ad47b356Smrg				Atom * type_ret, XtPointer *value_ret,
6333c89af1Smrg				unsigned long * length_ret, int * format_ret );
6433c89af1Smrgstatic void SelectionDone ( Widget w, Atom *sel, Atom *targ );
6533c89af1Smrgstatic void LoseSelection ( Widget w, Atom * sel );
66ad47b356Smrgstatic void GetClientValue ( Widget w, XtPointer data, Atom *selection,
67ad47b356Smrg			     Atom *type, XtPointer value,
6833c89af1Smrg			     unsigned long *length, int * format );
6933c89af1Smrgstatic void BuildHeader ( CurrentClient * client_data );
7033c89af1Smrgstatic Event * BuildEvent ( ProtocolStream * stream );
7133c89af1Smrgstatic void FreeEvent ( Event * event );
7233c89af1Smrgstatic char * DispatchEvent ( Event * event );
7333c89af1Smrg
7433c89af1Smrg
7533c89af1Smrg
7633c89af1Smrg/*	Function Name: ClientTimedOut
7733c89af1Smrg *	Description: Called if the client takes too long to take our selection.
78ad47b356Smrg *	Arguments: data - The widget that owns the client
7933c89af1Smrg *                        communication selection.
8033c89af1Smrg *                 id - *** UNUSED ***
8133c89af1Smrg *	Returns: none.
8233c89af1Smrg */
8333c89af1Smrg
8433c89af1Smrg/* ARGSUSED */
8533c89af1Smrgstatic void
86278eca22SmrgClientTimedOut(XtPointer data, XtIntervalId *id)
8733c89af1Smrg{
8833c89af1Smrg  char msg[BUFSIZ];
8933c89af1Smrg  Widget w = (Widget) data;
90ad47b356Smrg
9133c89af1Smrg  global_client.ident = NO_IDENT;
92ad47b356Smrg  XtDisownSelection(w, global_client.atom,
9333c89af1Smrg		    XtLastTimestampProcessed(XtDisplay(w)));
94ad47b356Smrg
95ad47b356Smrg  snprintf(msg, sizeof(msg), res_labels[4], "the Editres Protocol.");
9633c89af1Smrg  SetMessage(global_screen_data.info_label, msg);
9733c89af1Smrg}
9833c89af1Smrg
9933c89af1Smrg
10033c89af1Smrg
10133c89af1Smrg/*	Function Name: GetClientWindow
10233c89af1Smrg *	Description: Gets the Client's window by asking the user.
10333c89af1Smrg *	Arguments: w - a widget.
10433c89af1Smrg *	Returns: a clients window, or None.
10533c89af1Smrg */
10633c89af1Smrg
107ad47b356SmrgWindow
108278eca22SmrgGetClientWindow(Widget w, int *x, int *y)
10933c89af1Smrg{
11033c89af1Smrg  int status;
11133c89af1Smrg  Cursor cursor;
11233c89af1Smrg  XEvent event;
11333c89af1Smrg  int buttons = 0;
11433c89af1Smrg  Display * dpy = XtDisplayOfObject(w);
11533c89af1Smrg  Window target_win = None, root = RootWindowOfScreen(XtScreenOfObject(w));
11633c89af1Smrg  XtAppContext app = XtWidgetToApplicationContext(w);
117ad47b356Smrg
11833c89af1Smrg  /* Make the target cursor */
11933c89af1Smrg  cursor = XCreateFontCursor(dpy, XC_crosshair);
120ad47b356Smrg
12133c89af1Smrg  /* Grab the pointer using target cursor, letting it room all over */
12233c89af1Smrg  status = XGrabPointer(dpy, root, False,
12333c89af1Smrg			ButtonPressMask|ButtonReleaseMask, GrabModeSync,
12433c89af1Smrg			GrabModeAsync, root, cursor, CurrentTime);
12533c89af1Smrg  if (status != GrabSuccess) {
12633c89af1Smrg    SetMessage(global_screen_data.info_label, res_labels[5]);
12733c89af1Smrg    return(None);
12833c89af1Smrg  }
129ad47b356Smrg
13033c89af1Smrg  /* Let the user select a window... */
13133c89af1Smrg  while ((target_win == None) || (buttons != 0)) {
13233c89af1Smrg    /* allow one more event */
13333c89af1Smrg    XAllowEvents(dpy, SyncPointer, CurrentTime);
13433c89af1Smrg    XtAppNextEvent(app, &event);
13533c89af1Smrg    switch (event.type) {
13633c89af1Smrg    case ButtonPress:
13733c89af1Smrg      if (event.xbutton.window != root) {
13833c89af1Smrg	XtDispatchEvent(&event);
13933c89af1Smrg	break;
14033c89af1Smrg      }
141ad47b356Smrg
14233c89af1Smrg      if (target_win == None) {
14333c89af1Smrg	target_win = event.xbutton.subwindow; /* window selected */
14433c89af1Smrg	if (x != NULL)
14533c89af1Smrg	  *x = event.xbutton.x_root;
14633c89af1Smrg	if (y != NULL)
14733c89af1Smrg	  *y = event.xbutton.y_root;
14833c89af1Smrg      }
14933c89af1Smrg      buttons++;
15033c89af1Smrg      break;
15133c89af1Smrg    case ButtonRelease:
15233c89af1Smrg      if (event.xbutton.window != root) {
15333c89af1Smrg	XtDispatchEvent(&event);
15433c89af1Smrg	break;
15533c89af1Smrg      }
156ad47b356Smrg
15733c89af1Smrg      if (buttons > 0) /* There may have been some
15833c89af1Smrg			  down before we started */
15933c89af1Smrg	buttons--;
16033c89af1Smrg      break;
16133c89af1Smrg    default:
16233c89af1Smrg      XtDispatchEvent(&event);
16333c89af1Smrg      break;
16433c89af1Smrg    }
165ad47b356Smrg  }
166ad47b356Smrg
16733c89af1Smrg  XUngrabPointer(dpy, CurrentTime);      /* Done with pointer */
168ad47b356Smrg
16933c89af1Smrg  return(XmuClientWindow(dpy, target_win));
17033c89af1Smrg}
17133c89af1Smrg
17233c89af1Smrg
17333c89af1Smrg
17433c89af1Smrg/*	Function Name: SetCommand
175ad47b356Smrg *	Description: Causes this widget to own the resource editor's
17633c89af1Smrg *                   command selection.
17733c89af1Smrg *	Arguments: w - the widget that will own the selection.
17833c89af1Smrg *                 command - command to send to client.
17933c89af1Smrg *                 msg - message to prompt the user to select a client.
18033c89af1Smrg *	Returns: none.
18133c89af1Smrg */
18233c89af1Smrg
18333c89af1Smrg/* ARGSUSED */
18433c89af1Smrgvoid
185352bf44eSmrgSetCommand(Widget w, ResCommand command, String msg)
18633c89af1Smrg{
18733c89af1Smrg  XClientMessageEvent client_event;
18833c89af1Smrg  Display * dpy = XtDisplay(w);
189ad47b356Smrg
190ad47b356Smrg  if (msg == NULL)
19133c89af1Smrg    msg = res_labels[6];
192ad47b356Smrg
19333c89af1Smrg  SetMessage(global_screen_data.info_label, msg);
194ad47b356Smrg
19533c89af1Smrg  if (global_client.window == None)
196ad47b356Smrg    if ( (global_client.window = GetClientWindow(w, NULL, NULL)) == None)
19733c89af1Smrg      return;
19833c89af1Smrg
19933c89af1Smrg  global_client.ident = GetNewIdent();
200ad47b356Smrg
20133c89af1Smrg  global_client.command = command;
20233c89af1Smrg  global_client.atom = atom_comm;
20333c89af1Smrg
204ad47b356Smrg  BuildHeader(&(global_client));
20533c89af1Smrg
206ad47b356Smrg  if (!XtOwnSelection(w, global_client.atom, CurrentTime, ConvertCommand,
20733c89af1Smrg		      LoseSelection, SelectionDone))
20833c89af1Smrg    SetMessage(global_screen_data.info_label,
20933c89af1Smrg	       res_labels[7]);
21033c89af1Smrg
21133c89af1Smrg  client_event.window = global_client.window;
21233c89af1Smrg  client_event.type = ClientMessage;
21333c89af1Smrg  client_event.message_type = atom_resource_editor;
21433c89af1Smrg  client_event.format = EDITRES_SEND_EVENT_FORMAT;
21533c89af1Smrg  client_event.data.l[0] = XtLastTimestampProcessed(dpy);
21633c89af1Smrg  client_event.data.l[1] = global_client.atom;
21733c89af1Smrg  client_event.data.l[2] = (long) global_client.ident;
21833c89af1Smrg  client_event.data.l[3] = global_effective_protocol_version;
219ad47b356Smrg
22033c89af1Smrg  global_error_code = NO_ERROR;                 /* Reset Error code. */
22133c89af1Smrg  global_old_error_handler = XSetErrorHandler(HandleXErrors);
22233c89af1Smrg  global_serial_num = NextRequest(dpy);
223ad47b356Smrg
224ad47b356Smrg  XSendEvent(dpy, global_client.window, FALSE, (long) 0,
22533c89af1Smrg	     (XEvent *) &client_event);
226ad47b356Smrg
22733c89af1Smrg  XSync(dpy, FALSE);
22833c89af1Smrg  XSetErrorHandler(global_old_error_handler);
22933c89af1Smrg  if (global_error_code == NO_WINDOW) {
230ad47b356Smrg    char error_buf[BUFSIZ] =
231ad47b356Smrg        "The communication window with the"
232ad47b356Smrg        " application is no longer available\n"
233ad47b356Smrg        "Please select a new widget tree.";
234ad47b356Smrg
23533c89af1Smrg    global_error_code = NO_ERROR;	/* Reset Error code. */
23633c89af1Smrg    global_client.window = None;
23733c89af1Smrg    SetCommand(w, LocalSendWidgetTree, error_buf);
23833c89af1Smrg    return;
239ad47b356Smrg  }
240ad47b356Smrg
24133c89af1Smrg  TellUserAboutMessage(global_screen_data.info_label, command);
24233c89af1Smrg  global_client.timeout = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
243ad47b356Smrg					  CLIENT_TIME_OUT,
24433c89af1Smrg					  ClientTimedOut, (XtPointer) w);
24533c89af1Smrg}
24633c89af1Smrg
24733c89af1Smrg
24833c89af1Smrg
24933c89af1Smrg/*	Function Name: TellUserAboutMessage
25033c89af1Smrg *	Description: Informs the user that we have sent a message to the client
25133c89af1Smrg *	Arguments: label - the info label.
25233c89af1Smrg *                 command - command that we have executed.
25333c89af1Smrg *	Returns: none.
25433c89af1Smrg */
25533c89af1Smrg
25633c89af1Smrgstatic void
257278eca22SmrgTellUserAboutMessage(Widget label, ResCommand command)
25833c89af1Smrg{
259352bf44eSmrg    char msg[BUFSIZ];
260352bf44eSmrg    const char *str;
26133c89af1Smrg
26233c89af1Smrg    switch(command) {
26333c89af1Smrg    case LocalSendWidgetTree:
26433c89af1Smrg	str = " asking for widget tree";
26533c89af1Smrg	break;
26633c89af1Smrg    case LocalSetValues:
26733c89af1Smrg	str = " asking it to perform SetValues()";
26833c89af1Smrg	break;
26933c89af1Smrg    case LocalFlashWidget:
27033c89af1Smrg    case LocalGetGeometry:
27133c89af1Smrg	str = " asking it to perform GetGeometry()";
27233c89af1Smrg	break;
27333c89af1Smrg    case LocalGetResources:
27433c89af1Smrg	str = " asking it to get a widget's resource list";
27533c89af1Smrg	break;
27633c89af1Smrg    case LocalFindChild:
27733c89af1Smrg	str = " asking it to find the child Widget.";
27833c89af1Smrg	break;
27933c89af1Smrg    default:
28033c89af1Smrg	str = "";
28133c89af1Smrg	break;
28233c89af1Smrg    }
28333c89af1Smrg
284ad47b356Smrg    snprintf(msg, sizeof(msg), res_labels[8], str);
28533c89af1Smrg    SetMessage(label, msg);
28633c89af1Smrg}
28733c89af1Smrg
28833c89af1Smrg
28933c89af1Smrg
29033c89af1Smrg/*	Function Name: ConvertCommand
29133c89af1Smrg *	Description: Converts the command string into a selection that can
29233c89af1Smrg *                   be sent to the client.
29333c89af1Smrg *	Arguments: (see Xt)
29433c89af1Smrg *	Returns: TRUE if we could convert the selection and target asked for.
29533c89af1Smrg */
29633c89af1Smrg
29733c89af1Smrg/* ARGSUSED */
29833c89af1Smrgstatic Boolean
299278eca22SmrgConvertCommand(Widget w, Atom *selection, Atom *target, Atom *type_ret,
300278eca22Smrg	       XtPointer *value_ret, unsigned long *length_ret, int *format_ret)
30133c89af1Smrg{
30233c89af1Smrg    if ((*selection != atom_comm) || (*target != atom_command))
30333c89af1Smrg	return(FALSE);
30433c89af1Smrg
30533c89af1Smrg    *type_ret = atom_editres_protocol;
30633c89af1Smrg    *value_ret = (XtPointer) global_client.stream.real_top;
30733c89af1Smrg    *length_ret = global_client.stream.size + HEADER_SIZE;
30833c89af1Smrg    *format_ret = EDITRES_FORMAT;
309ad47b356Smrg
31033c89af1Smrg    return(TRUE);
31133c89af1Smrg}
31233c89af1Smrg
31333c89af1Smrg
31433c89af1Smrg
31533c89af1Smrg/*	Function Name: SelectionDone
31633c89af1Smrg *	Description: done with the selection.
31733c89af1Smrg *	Arguments: *** UNUSED ***
31833c89af1Smrg *	Returns: none.
31933c89af1Smrg */
32033c89af1Smrg
32133c89af1Smrg/* ARGSUSED */
32233c89af1Smrgstatic void
323278eca22SmrgSelectionDone(Widget w, Atom *sel, Atom *targ)
32433c89af1Smrg{
325352bf44eSmrg    /* Keep the toolkit from automatically freeing the selection value */
32633c89af1Smrg}
32733c89af1Smrg
32833c89af1Smrg
32933c89af1Smrg
33033c89af1Smrg/*	Function Name: LoseSelection
33133c89af1Smrg *	Description: Called when we have lost the selection, asks client
33233c89af1Smrg *                   for the selection value.
33333c89af1Smrg *	Arguments: w - the widget that just lost the selection.
33433c89af1Smrg *                 sel - the selection.
33533c89af1Smrg *	Returns: none.
33633c89af1Smrg */
33733c89af1Smrg
33833c89af1Smrgstatic void
339278eca22SmrgLoseSelection(Widget w, Atom *sel)
34033c89af1Smrg{
34133c89af1Smrg    if (global_client.timeout != 0) {
34233c89af1Smrg	XtRemoveTimeOut(global_client.timeout);
34333c89af1Smrg	global_client.timeout = 0;
34433c89af1Smrg    }
34533c89af1Smrg
34633c89af1Smrg    XtGetSelectionValue(w, *sel, atom_client_value, GetClientValue,
34733c89af1Smrg			NULL, XtLastTimestampProcessed(XtDisplay(w)));
34833c89af1Smrg}
34933c89af1Smrg
35033c89af1Smrg
35133c89af1Smrg
35233c89af1Smrg/*	Function Name: GetClientValue
35333c89af1Smrg *	Description: Gets the value out of the client, and does good things
35433c89af1Smrg *                   to it.
35533c89af1Smrg *	Arguments: w - the widget that asked for the selection.
35633c89af1Smrg *                 data - client_data *** UNUSED ***.
35733c89af1Smrg *                 sel - the selection.
35833c89af1Smrg *                 type - the type of the selection.
35933c89af1Smrg *                 value - the selection's value.
36033c89af1Smrg *                 length - the length of the selection's value.
36133c89af1Smrg *                 format - the format of the selection.
36233c89af1Smrg *	Returns: none.
36333c89af1Smrg */
36433c89af1Smrg
36533c89af1Smrgstatic Boolean reset_protocol_level = True;
36633c89af1Smrg
36733c89af1Smrg/* ARGSUSED */
36833c89af1Smrgstatic void
369278eca22SmrgGetClientValue(Widget w, XtPointer data, Atom *selection, Atom *type,
370278eca22Smrg	       XtPointer value, unsigned long *length, int *format)
37133c89af1Smrg{
37233c89af1Smrg    Event * event;
37333c89af1Smrg    ProtocolStream alloc_stream, *stream;
37433c89af1Smrg    unsigned char ident, error_code;
37533c89af1Smrg    char * error_str = NULL, msg[BUFSIZ];
37633c89af1Smrg
37733c89af1Smrg    if (*length == 0)
37833c89af1Smrg	return;
37933c89af1Smrg
38033c89af1Smrg    stream = &alloc_stream;	/* easier to think of it this way... */
38133c89af1Smrg
38233c89af1Smrg    stream->current = stream->top = (unsigned char *) value;
38333c89af1Smrg    stream->size = HEADER_SIZE;		/* size of header. */
38433c89af1Smrg
38533c89af1Smrg    /*
38633c89af1Smrg     * Retrieve the Header.
38733c89af1Smrg     */
38833c89af1Smrg
38933c89af1Smrg    if (*length < HEADER_SIZE) {
39033c89af1Smrg	SetMessage(global_screen_data.info_label,
39133c89af1Smrg		   res_labels[9]);
39233c89af1Smrg	return;
39333c89af1Smrg    }
39433c89af1Smrg
39533c89af1Smrg    (void) _XEditResGet8(stream, &ident);
39633c89af1Smrg    if (global_client.ident != ident) {
39733c89af1Smrg#ifdef DEBUG
39833c89af1Smrg	if (global_resources.debug)
39933c89af1Smrg	    printf("Incorrect ident from client.\n");
400ad47b356Smrg#endif
401ad47b356Smrg	if (!XtOwnSelection(w, *selection, CurrentTime, ConvertCommand,
40233c89af1Smrg			    LoseSelection, SelectionDone))
40333c89af1Smrg	    SetMessage(global_screen_data.info_label,
40433c89af1Smrg		       res_labels[10]);
40533c89af1Smrg	return;
40633c89af1Smrg    }
40733c89af1Smrg
408ad47b356Smrg    (void) _XEditResGet8(stream, &error_code);
40933c89af1Smrg    (void) _XEditResGet32(stream, &(stream->size));
41033c89af1Smrg    stream->top = stream->current; /* reset stream to top of value.*/
41133c89af1Smrg
41233c89af1Smrg    switch ((int) error_code) {
41333c89af1Smrg    case PartialSuccess:
41433c89af1Smrg/*****
41533c89af1Smrg        if (global_client.command == LocalSendWidgetTree &&
41633c89af1Smrg	    global_effective_protocol_version < CURRENT_PROTOCOL_VERSION)
41733c89af1Smrg	  ++global_effective_protocol_version;
41833c89af1Smrg*****/
41933c89af1Smrg	if ((event = BuildEvent(stream)) != NULL) {
42033c89af1Smrg	    error_str = DispatchEvent(event);
42133c89af1Smrg	    FreeEvent(event);
42233c89af1Smrg	}
42333c89af1Smrg	else {
424ad47b356Smrg	    snprintf(msg, sizeof(msg), "Unable to unpack protocol request.");
42533c89af1Smrg	    error_str = XtNewString(msg);
42633c89af1Smrg	}
42733c89af1Smrg	break;
42833c89af1Smrg    case Failure:
42933c89af1Smrg	error_str = GetFailureMessage(stream);
43033c89af1Smrg	break;
43133c89af1Smrg    case ProtocolMismatch:
43233c89af1Smrg	error_str = ProtocolFailure(stream);
43333c89af1Smrg	--global_effective_protocol_version;
434352bf44eSmrg        /* normally protocol version is reset to current during a SendWidgetTree
435352bf44eSmrg         * request, however, after a protocol failure this is skipped once for
43633c89af1Smrg         * a retry.
43733c89af1Smrg         */
43833c89af1Smrg	reset_protocol_level = False;
43933c89af1Smrg	SetCommand(w, LocalSendWidgetTree, NULL);
44033c89af1Smrg	break;
44133c89af1Smrg    default:
442ad47b356Smrg	snprintf(msg, sizeof(msg), res_labels[11], (int) error_code);
44333c89af1Smrg	SetMessage(global_screen_data.info_label, msg);
44433c89af1Smrg	break;
44533c89af1Smrg    }
44633c89af1Smrg
44733c89af1Smrg    if (error_str == NULL) {
44833c89af1Smrg	WNode * top;
449ad47b356Smrg
45033c89af1Smrg	if (global_tree_info == NULL)
45133c89af1Smrg	    return;
452ad47b356Smrg
45333c89af1Smrg	top = global_tree_info->top_node;
454ad47b356Smrg	snprintf(msg, sizeof(msg), res_labels[12], top->name, top->class);
45533c89af1Smrg	SetMessage(global_screen_data.info_label, msg);
45633c89af1Smrg	return;
45733c89af1Smrg    }
45833c89af1Smrg    SetMessage(global_screen_data.info_label, error_str);
45933c89af1Smrg    XtFree(error_str);
46033c89af1Smrg}
46133c89af1Smrg
46233c89af1Smrg
46333c89af1Smrg
46433c89af1Smrg/*	Function Name: BuildHeader
46533c89af1Smrg *	Description: Puts the header into the message.
46633c89af1Smrg *	Arguments: client_data - the client data.
46733c89af1Smrg *	Returns: none.
46833c89af1Smrg */
46933c89af1Smrg
47033c89af1Smrgstatic void
471278eca22SmrgBuildHeader(CurrentClient *client_data)
47233c89af1Smrg{
47333c89af1Smrg    unsigned long old_alloc, old_size;
47433c89af1Smrg    unsigned char * old_current;
47533c89af1Smrg    EditresCommand command;
47633c89af1Smrg    ProtocolStream * stream = &(client_data->stream);
47733c89af1Smrg
47833c89af1Smrg    /*
47933c89af1Smrg     * We have cleverly keep enough space at the top of the header
48033c89af1Smrg     * for the return protocol stream, so all we have to do is
48133c89af1Smrg     * fill in the space.
48233c89af1Smrg     */
48333c89af1Smrg
484ad47b356Smrg    /*
48533c89af1Smrg     * Fool the insert routines into putting the header in the right
48633c89af1Smrg     * place while being damn sure not to realloc (that would be very bad.
48733c89af1Smrg     */
488ad47b356Smrg
48933c89af1Smrg    old_current = stream->current;
49033c89af1Smrg    old_alloc = stream->alloc;
49133c89af1Smrg    old_size = stream->size;
49233c89af1Smrg
49333c89af1Smrg    stream->current = stream->real_top;
494ad47b356Smrg    stream->alloc = stream->size + (2 * HEADER_SIZE);
495ad47b356Smrg
49633c89af1Smrg    _XEditResPut8(stream, client_data->ident);
49733c89af1Smrg    switch(client_data->command) {
498ad47b356Smrg    case LocalSendWidgetTree:
499ad47b356Smrg        if (reset_protocol_level) global_effective_protocol_version =
50033c89af1Smrg	  CURRENT_PROTOCOL_VERSION;
50133c89af1Smrg        reset_protocol_level = True;
50233c89af1Smrg	command = SendWidgetTree;
50333c89af1Smrg	break;
50433c89af1Smrg    case LocalSetValues:
50533c89af1Smrg	command = SetValues;
50633c89af1Smrg	break;
50733c89af1Smrg    case LocalFlashWidget:
50833c89af1Smrg	command = GetGeometry;
50933c89af1Smrg	break;
51033c89af1Smrg    case LocalGetResources:
51133c89af1Smrg	command = GetResources;
51233c89af1Smrg	break;
51333c89af1Smrg    case LocalFindChild:
51433c89af1Smrg	command = FindChild;
51533c89af1Smrg	break;
51633c89af1Smrg    case LocalGetValues:
51733c89af1Smrg	command = GetValues;
51833c89af1Smrg	break;
51933c89af1Smrg    default:
52033c89af1Smrg	command = SendWidgetTree;
52133c89af1Smrg	break;
52233c89af1Smrg    }
523ad47b356Smrg
52433c89af1Smrg    _XEditResPut8(stream, (unsigned char) command);
52533c89af1Smrg    _XEditResPut32(stream, old_size);
52633c89af1Smrg
52733c89af1Smrg    stream->alloc = old_alloc;
52833c89af1Smrg    stream->current = old_current;
52933c89af1Smrg    stream->size = old_size;
53033c89af1Smrg}
53133c89af1Smrg
53233c89af1Smrg
53333c89af1Smrg
53433c89af1Smrg/*	Function Name: BuildEvent
535ad47b356Smrg *	Description: Builds the event structure from the
53633c89af1Smrg *	Arguments: stream - the protocol data stream.
53733c89af1Smrg *	Returns: event - the event.
53833c89af1Smrg */
53933c89af1Smrg
540ad47b356Smrgstatic Event *
541278eca22SmrgBuildEvent(ProtocolStream *stream)
54233c89af1Smrg{
54333c89af1Smrg    int i;
54433c89af1Smrg    Event * event = (Event *) XtCalloc(sizeof(Event), 1);
54533c89af1Smrg
54633c89af1Smrg    /*
54733c89af1Smrg     * The return value will be different depending upon the
54833c89af1Smrg     * request sent out.
54933c89af1Smrg     */
55033c89af1Smrg
55133c89af1Smrg    switch(global_client.command) {
55233c89af1Smrg    case LocalSendWidgetTree:
55333c89af1Smrg        {
55433c89af1Smrg	    SendWidgetTreeEvent * send_event = (SendWidgetTreeEvent *) event;
55533c89af1Smrg
55633c89af1Smrg	    send_event->type = SendWidgetTree;
55733c89af1Smrg
55833c89af1Smrg	    if (!_XEditResGet16(stream, &(send_event->num_entries)))
55933c89af1Smrg		goto done;
560ad47b356Smrg
56133c89af1Smrg	    send_event->info = (WidgetTreeInfo *)
56233c89af1Smrg		                XtCalloc(sizeof(WidgetTreeInfo),
56333c89af1Smrg					 send_event->num_entries);
56433c89af1Smrg
56533c89af1Smrg	    for (i = 0; i < (int)send_event->num_entries; i++) {
56633c89af1Smrg		WidgetTreeInfo * info = send_event->info + i;
56733c89af1Smrg		if (!(_XEditResGetWidgetInfo(stream, &(info->widgets)) &&
56833c89af1Smrg		      _XEditResGetString8(stream, &(info->name)) &&
56933c89af1Smrg		      _XEditResGetString8(stream, &(info->class)) &&
570ad47b356Smrg		      _XEditResGet32(stream, &(info->window))))
57133c89af1Smrg		{
57233c89af1Smrg		    goto done;
57333c89af1Smrg		}
57433c89af1Smrg	    }
57533c89af1Smrg
576ad47b356Smrg	    if (global_effective_protocol_version ==
57733c89af1Smrg		CURRENT_PROTOCOL_VERSION) {
57833c89af1Smrg				/* get toolkit type and reset if necessary */
57933c89af1Smrg	      if (!_XEditResGetString8(stream, &(send_event->toolkit)))
58033c89af1Smrg 	        goto done;
58133c89af1Smrg	    }
58233c89af1Smrg	    /* set the command menu entries senitive */
58333c89af1Smrg	    SetEntriesSensitive(&CM_entries[CM_OFFSET], CM_NUM, True);
58433c89af1Smrg	    /* set the tree menu entries senitive */
58533c89af1Smrg	    SetEntriesSensitive(TM_entries, TM_NUM, True);
586ad47b356Smrg	    if (global_effective_protocol_version ==
58733c89af1Smrg		CURRENT_PROTOCOL_VERSION) {
588ad47b356Smrg	      if (!strcmp(send_event->toolkit, "InterViews"))
58933c89af1Smrg	        RebuildMenusAndLabel("iv");
590ad47b356Smrg            }
59133c89af1Smrg            else
59233c89af1Smrg              RebuildMenusAndLabel("xt");
59333c89af1Smrg	}
59433c89af1Smrg	break;
59533c89af1Smrg    case LocalSetValues:
59633c89af1Smrg        {
59733c89af1Smrg	    SetValuesEvent * sv_event = (SetValuesEvent *) event;
59833c89af1Smrg
59933c89af1Smrg	    sv_event->type = SetValues;
60033c89af1Smrg
60133c89af1Smrg	    if (!_XEditResGet16(stream, &(sv_event->num_entries)))
60233c89af1Smrg		goto done;
603ad47b356Smrg
60433c89af1Smrg	    sv_event->info = (SetValuesInfo *) XtCalloc(sizeof(SetValuesInfo),
60533c89af1Smrg							sv_event->num_entries);
60633c89af1Smrg
60733c89af1Smrg	    for (i = 0; i < (int)sv_event->num_entries; i++) {
60833c89af1Smrg		SetValuesInfo * info = sv_event->info + i;
60933c89af1Smrg		if (!(_XEditResGetWidgetInfo(stream, &(info->widgets)) &&
61033c89af1Smrg		      _XEditResGetString8(stream, &(info->message))))
61133c89af1Smrg		{
61233c89af1Smrg		    goto done;
61333c89af1Smrg		}
61433c89af1Smrg	    }
61533c89af1Smrg	}
61633c89af1Smrg	break;
61733c89af1Smrg    case LocalGetResources:
61833c89af1Smrg        {
61933c89af1Smrg	    GetResourcesEvent * res_event = (GetResourcesEvent *) event;
620ad47b356Smrg
62133c89af1Smrg	    res_event->type = GetGeometry;
62233c89af1Smrg
62333c89af1Smrg	    if (!_XEditResGet16(stream, &(res_event->num_entries)))
62433c89af1Smrg		goto done;
62533c89af1Smrg
626ad47b356Smrg	    res_event->info = (GetResourcesInfo *)
62733c89af1Smrg		                   XtCalloc(sizeof(GetResourcesInfo),
62833c89af1Smrg					    res_event->num_entries);
62933c89af1Smrg
63033c89af1Smrg	    for (i = 0; i < (int)res_event->num_entries; i++) {
63133c89af1Smrg		GetResourcesInfo * res_info = res_event->info + i;
63233c89af1Smrg		if (!(_XEditResGetWidgetInfo(stream, &(res_info->widgets)) &&
63333c89af1Smrg		      _XEditResGetBoolean(stream, &(res_info->error))))
63433c89af1Smrg		{
63533c89af1Smrg		    goto done;
63633c89af1Smrg		}
63733c89af1Smrg		if (res_info->error) {
638ad47b356Smrg		    if (!_XEditResGetString8(stream, &(res_info->message)))
63933c89af1Smrg			goto done;
64033c89af1Smrg		}
64133c89af1Smrg		else {
64233c89af1Smrg		    unsigned int j;
64333c89af1Smrg
64433c89af1Smrg		    if (!_XEditResGet16(stream, &(res_info->num_resources)))
64533c89af1Smrg			goto done;
64633c89af1Smrg
647ad47b356Smrg		    res_info->res_info = (ResourceInfo *)
64833c89af1Smrg			                  XtCalloc(sizeof(ResourceInfo),
64933c89af1Smrg						   res_info->num_resources);
65033c89af1Smrg
65133c89af1Smrg		    for (j = 0; j < res_info->num_resources; j++) {
65233c89af1Smrg			unsigned char temp;
65333c89af1Smrg			ResourceInfo * info = res_info->res_info + j;
65433c89af1Smrg			if (!(_XEditResGetResType(stream, &(temp)) &&
65533c89af1Smrg			      _XEditResGetString8(stream, &(info->name)) &&
65633c89af1Smrg			      _XEditResGetString8(stream, &(info->class)) &&
65733c89af1Smrg			      _XEditResGetString8(stream, &(info->type))))
65833c89af1Smrg			{
65933c89af1Smrg			    goto done;
66033c89af1Smrg			}
66133c89af1Smrg			else
66233c89af1Smrg			    info->res_type = (ResourceType) temp;
66333c89af1Smrg		    } /* for */
66433c89af1Smrg		} /* else */
66533c89af1Smrg	    } /* for */
66633c89af1Smrg	}
66733c89af1Smrg	break;
66833c89af1Smrg    case LocalFlashWidget:
66933c89af1Smrg    case LocalGetGeometry:
67033c89af1Smrg        {
67133c89af1Smrg	    GetGeomEvent * geom_event = (GetGeomEvent *) event;
67233c89af1Smrg
67333c89af1Smrg	    geom_event->type = GetGeometry;
67433c89af1Smrg
67533c89af1Smrg	    if (!_XEditResGet16(stream, &(geom_event->num_entries)))
67633c89af1Smrg		goto done;
677ad47b356Smrg
67833c89af1Smrg	    geom_event->info = (GetGeomInfo *) XtCalloc(sizeof(GetGeomInfo),
67933c89af1Smrg						      geom_event->num_entries);
68033c89af1Smrg
68133c89af1Smrg	    for (i = 0; i < (int)geom_event->num_entries; i++) {
68233c89af1Smrg		GetGeomInfo * info = geom_event->info + i;
68333c89af1Smrg		if (!(_XEditResGetWidgetInfo(stream, &(info->widgets)) &&
68433c89af1Smrg		      _XEditResGetBoolean(stream, &(info->error))))
68533c89af1Smrg		{
68633c89af1Smrg		    goto done;
68733c89af1Smrg		}
68833c89af1Smrg		if (info->error) {
68933c89af1Smrg		    if (!_XEditResGetString8(stream, &(info->message)))
69033c89af1Smrg			goto done;
69133c89af1Smrg		}
69233c89af1Smrg		else {
693352bf44eSmrg		    if (!(_XEditResGetBoolean(stream, &(info->visible)) &&
69433c89af1Smrg			  _XEditResGetSigned16(stream, &(info->x)) &&
69533c89af1Smrg			  _XEditResGetSigned16(stream, &(info->y)) &&
69633c89af1Smrg			  _XEditResGet16(stream, &(info->width)) &&
69733c89af1Smrg			  _XEditResGet16(stream, &(info->height)) &&
69833c89af1Smrg			  _XEditResGet16(stream, &(info->border_width))))
69933c89af1Smrg		    {
70033c89af1Smrg			goto done;
70133c89af1Smrg		    }
70233c89af1Smrg		}
70333c89af1Smrg	    }
70433c89af1Smrg	}
70533c89af1Smrg	break;
70633c89af1Smrg    case LocalFindChild:
70733c89af1Smrg        {
70833c89af1Smrg	    FindChildEvent * find_event = (FindChildEvent *) event;
70933c89af1Smrg
71033c89af1Smrg	    find_event->type = FindChild;
71133c89af1Smrg
71233c89af1Smrg	    if (!_XEditResGetWidgetInfo(stream, &(find_event->widgets)))
71333c89af1Smrg		goto done;
71433c89af1Smrg	}
71533c89af1Smrg	break;
71633c89af1Smrg    case LocalGetValues: /* This is for REPLY... */
71733c89af1Smrg	{
71833c89af1Smrg	  Arg args[1];
71933c89af1Smrg	  GetValuesEvent * gv_event = (GetValuesEvent *) event;
720ad47b356Smrg
72133c89af1Smrg	  gv_event->type = GetValues;
722ad47b356Smrg
72333c89af1Smrg	  if (!_XEditResGet16(stream, &(gv_event->num_entries)))
72433c89af1Smrg	    goto done;
72533c89af1Smrg
72633c89af1Smrg	  gv_event->info = (GetValuesInfo*)XtCalloc(sizeof(GetValuesInfo),1);
72733c89af1Smrg
72833c89af1Smrg	  {
72933c89af1Smrg	    GetValuesInfo * info = gv_event->info;
73033c89af1Smrg	    if (!(_XEditResGetString8(stream, &(info->value))))
73133c89af1Smrg	      {
73233c89af1Smrg		goto done;
73333c89af1Smrg	      }
73433c89af1Smrg
73533c89af1Smrg	    /* set the string value of the asciitext widget. note that only
73633c89af1Smrg             * one active node is dealt with here.  This is ok because only
73733c89af1Smrg	     * one node can be active when the resource box is up.
73833c89af1Smrg	     */
73933c89af1Smrg
74033c89af1Smrg	    XtSetArg (args[0], XtNstring, info->value);
74133c89af1Smrg
74233c89af1Smrg	    XtSetValues(
74333c89af1Smrg	      global_tree_info->active_nodes[0]->resources->res_box->value_wid,
74433c89af1Smrg 	      args, 1
74533c89af1Smrg	    );
74633c89af1Smrg	  }
74733c89af1Smrg	}
74833c89af1Smrg	break;
74933c89af1Smrg
75033c89af1Smrg    default:
75133c89af1Smrg	goto done;
75233c89af1Smrg    }
75333c89af1Smrg
75433c89af1Smrg    return(event);
75533c89af1Smrg
75633c89af1Smrg done:
75733c89af1Smrg    FreeEvent(event);
75833c89af1Smrg    return(NULL);
75933c89af1Smrg}
76033c89af1Smrg
76133c89af1Smrg
76233c89af1Smrg
76333c89af1Smrg/*	Function Name: FreeEvent
764ad47b356Smrg *	Description: Frees all memory associated with the event.
76533c89af1Smrg *	Arguments: event - the event.
76633c89af1Smrg *	Returns: none.
76733c89af1Smrg *
76833c89af1Smrg * NOTE: XtFree() returns w/o freeing if ptr is NULL.
76933c89af1Smrg */
77033c89af1Smrg
77133c89af1Smrgstatic void
772278eca22SmrgFreeEvent(Event *event)
77333c89af1Smrg{
77433c89af1Smrg    unsigned int i;
77533c89af1Smrg
77633c89af1Smrg    switch(event->any_event.type) {
77733c89af1Smrg    case SendWidgetTree:
77833c89af1Smrg        {
77933c89af1Smrg	    SendWidgetTreeEvent * send_event = (SendWidgetTreeEvent *) event;
78033c89af1Smrg	    WidgetTreeInfo * info = send_event->info;
781ad47b356Smrg
78233c89af1Smrg	    if (info != NULL) {
78333c89af1Smrg		for (i = 0; i < send_event->num_entries; i++, info++) {
78433c89af1Smrg		    XtFree((char *)info->widgets.ids);
78533c89af1Smrg		    XtFree(info->name);
78633c89af1Smrg		    XtFree(info->class);
78733c89af1Smrg		}
78833c89af1Smrg		XtFree((char *)send_event->info);
78933c89af1Smrg	    }
79033c89af1Smrg	}
79133c89af1Smrg	break;
79233c89af1Smrg    case SetValues:
79333c89af1Smrg        {
79433c89af1Smrg	    SetValuesEvent * sv_event = (SetValuesEvent *) event;
79533c89af1Smrg	    SetValuesInfo * info = sv_event->info;
796ad47b356Smrg
79733c89af1Smrg	    if (info != NULL) {
79833c89af1Smrg		for (i = 0; i < sv_event->num_entries; i++, info++) {
79933c89af1Smrg		    XtFree((char *)info->widgets.ids);
80033c89af1Smrg		    XtFree(info->message);
80133c89af1Smrg		}
80233c89af1Smrg		XtFree((char *)sv_event->info);
80333c89af1Smrg	    }
80433c89af1Smrg	}
80533c89af1Smrg	break;
80633c89af1Smrg    case GetResources:
80733c89af1Smrg        {
80833c89af1Smrg	    GetResourcesEvent * get_event = (GetResourcesEvent *) event;
80933c89af1Smrg	    GetResourcesInfo * info = get_event->info;
81033c89af1Smrg
81133c89af1Smrg	    if (info != NULL) {
81233c89af1Smrg		for (i = 0; i < get_event->num_entries; i++, info++) {
81333c89af1Smrg		    XtFree((char *)info->widgets.ids);
814ad47b356Smrg		    if (info->error)
81533c89af1Smrg			XtFree(info->message);
81633c89af1Smrg		    else {
81733c89af1Smrg			unsigned int j;
81833c89af1Smrg			ResourceInfo * res_info = info->res_info;
819ad47b356Smrg
82033c89af1Smrg			if (res_info != NULL) {
821ad47b356Smrg			    for (j = 0;
822ad47b356Smrg				 j < info->num_resources; j++, res_info++)
82333c89af1Smrg			    {
82433c89af1Smrg				XtFree(res_info->name);
82533c89af1Smrg				XtFree(res_info->class);
82633c89af1Smrg				XtFree(res_info->type);
82733c89af1Smrg			    }
82833c89af1Smrg			    XtFree((char *)info->res_info);
82933c89af1Smrg			}
83033c89af1Smrg		    }
831ad47b356Smrg		}
83233c89af1Smrg		XtFree((char *)get_event->info);
83333c89af1Smrg	    }
83433c89af1Smrg	}
83533c89af1Smrg	break;
83633c89af1Smrg    case GetGeometry:
83733c89af1Smrg        {
83833c89af1Smrg	    GetGeomEvent * geom_event = (GetGeomEvent *) event;
83933c89af1Smrg	    GetGeomInfo * info = geom_event->info;
84033c89af1Smrg
84133c89af1Smrg	    if (info != NULL) {
84233c89af1Smrg		for (i = 0; i < geom_event->num_entries; i++, info++) {
84333c89af1Smrg		    XtFree((char *)info->widgets.ids);
844ad47b356Smrg		    if (info->error)
84533c89af1Smrg			XtFree(info->message);
84633c89af1Smrg		}
84733c89af1Smrg		XtFree((char *)geom_event->info);
84833c89af1Smrg	    }
84933c89af1Smrg	}
85033c89af1Smrg	break;
85133c89af1Smrg    case FindChild:
85233c89af1Smrg        {
85333c89af1Smrg	    FindChildEvent * find_event = (FindChildEvent *) event;
854ad47b356Smrg
85533c89af1Smrg	    XtFree((char *)find_event->widgets.ids);
85633c89af1Smrg	}
85733c89af1Smrg	break;
85833c89af1Smrg    default:
85933c89af1Smrg	break;
86033c89af1Smrg    }
86133c89af1Smrg}
86233c89af1Smrg
86333c89af1Smrg
86433c89af1Smrg
86533c89af1Smrg/*	Function Name: DispatchEvent
86633c89af1Smrg *	Description: Handles the event, calling the proper function.
86733c89af1Smrg *	Arguments: event - the event.
86833c89af1Smrg *	Returns: one.
86933c89af1Smrg */
870ad47b356Smrg
87133c89af1Smrgstatic char *
872278eca22SmrgDispatchEvent(Event *event)
87333c89af1Smrg{
87433c89af1Smrg    char * error = NULL;
87533c89af1Smrg
87633c89af1Smrg    switch(global_client.command) {
87733c89af1Smrg    case LocalSendWidgetTree:
87833c89af1Smrg	BuildVisualTree(global_tree_parent, event);
87933c89af1Smrg	break;
88033c89af1Smrg    case LocalSetValues:
88133c89af1Smrg	error = PrintSetValuesError(event);
88233c89af1Smrg	break;
88333c89af1Smrg    case LocalFlashWidget:
88433c89af1Smrg	error = HandleFlashWidget(event);
88533c89af1Smrg	break;
88633c89af1Smrg    case LocalGetResources:
88733c89af1Smrg	error = HandleGetResources(event);
88833c89af1Smrg	break;
88933c89af1Smrg    case LocalFindChild:
89033c89af1Smrg	DisplayChild(event);
89133c89af1Smrg	break;
89233c89af1Smrg    case LocalGetValues:
89333c89af1Smrg	break;
89433c89af1Smrg    default:
89533c89af1Smrg        {
89633c89af1Smrg	    char msg[BUFSIZ];
897ad47b356Smrg	    snprintf(msg, sizeof(msg), "Internal error: Unknown command %d.",
898ad47b356Smrg                     global_client.command);
89933c89af1Smrg	    error = XtNewString(msg);
90033c89af1Smrg	}
90133c89af1Smrg	break;
90233c89af1Smrg    }
90333c89af1Smrg    return(error);
90433c89af1Smrg}
90533c89af1Smrg
90633c89af1Smrg
90733c89af1Smrg
90833c89af1Smrg/*	Function Name: InternAtoms
90933c89af1Smrg *	Description: interns all static atoms.
91033c89af1Smrg *	Arguments: display - the current display.
91133c89af1Smrg *	Returns: none.
91233c89af1Smrg */
91333c89af1Smrg
91433c89af1Smrgvoid
915278eca22SmrgInternAtoms(Display * dpy)
91633c89af1Smrg{
91733c89af1Smrg    atom_comm = XInternAtom(dpy, EDITRES_COMM_ATOM, False);
91833c89af1Smrg    atom_command = XInternAtom(dpy, EDITRES_COMMAND_ATOM, False);
91933c89af1Smrg    atom_resource_editor = XInternAtom(dpy, EDITRES_NAME, False);
92033c89af1Smrg    atom_client_value = XInternAtom(dpy, EDITRES_CLIENT_VALUE, False);
92133c89af1Smrg    atom_editres_protocol = XInternAtom(dpy, EDITRES_PROTOCOL_ATOM, False);
92233c89af1Smrg}
92333c89af1Smrg
92433c89af1SmrgResIdent
925278eca22SmrgGetNewIdent(void)
92633c89af1Smrg{
92733c89af1Smrg    static ResIdent ident = 1;
92833c89af1Smrg
92933c89af1Smrg    return(ident++);
93033c89af1Smrg}
931