#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xatom.h>
#include <X11/cursorfont.h>
#include <X11/Xproto.h>
#include <X11/Xos.h>
#include <stdio.h>
#include <X11/Xmu/Error.h>
#include <X11/Xmu/WinUtil.h>
#include "editresP.h"
static Atom atom_comm, atom_command, atom_resource_editor, atom_client_value;
static Atom atom_editres_protocol;
extern Widget CM_entries[NUM_CM_ENTRIES], TM_entries[NUM_TM_ENTRIES];
static void ClientTimedOut ( XtPointer data, XtIntervalId * id );
static void TellUserAboutMessage ( Widget label, ResCommand command );
static Boolean ConvertCommand ( Widget w, Atom * selection, Atom * target,
Atom * type_ret, XtPointer *value_ret,
unsigned long * length_ret, int * format_ret );
static void SelectionDone ( Widget w, Atom *sel, Atom *targ );
static void LoseSelection ( Widget w, Atom * sel );
static void GetClientValue ( Widget w, XtPointer data, Atom *selection,
Atom *type, XtPointer value,
unsigned long *length, int * format );
static void BuildHeader ( CurrentClient * client_data );
static Event * BuildEvent ( ProtocolStream * stream );
static void FreeEvent ( Event * event );
static char * DispatchEvent ( Event * event );
static void
ClientTimedOut(data, id)
XtPointer data;
XtIntervalId * id;
{
char msg[BUFSIZ];
Widget w = (Widget) data;
global_client.ident = NO_IDENT;
XtDisownSelection(w, global_client.atom,
XtLastTimestampProcessed(XtDisplay(w)));
sprintf(msg, res_labels[4],
"the Editres Protocol.");
SetMessage(global_screen_data.info_label, msg);
}
Window
GetClientWindow(w, x, y)
Widget w;
int *x, *y;
{
int status;
Cursor cursor;
XEvent event;
int buttons = 0;
Display * dpy = XtDisplayOfObject(w);
Window target_win = None, root = RootWindowOfScreen(XtScreenOfObject(w));
XtAppContext app = XtWidgetToApplicationContext(w);
cursor = XCreateFontCursor(dpy, XC_crosshair);
status = XGrabPointer(dpy, root, False,
ButtonPressMask|ButtonReleaseMask, GrabModeSync,
GrabModeAsync, root, cursor, CurrentTime);
if (status != GrabSuccess) {
SetMessage(global_screen_data.info_label, res_labels[5]);
return(None);
}
while ((target_win == None) || (buttons != 0)) {
XAllowEvents(dpy, SyncPointer, CurrentTime);
XtAppNextEvent(app, &event);
switch (event.type) {
case ButtonPress:
if (event.xbutton.window != root) {
XtDispatchEvent(&event);
break;
}
if (target_win == None) {
target_win = event.xbutton.subwindow;
if (x != NULL)
*x = event.xbutton.x_root;
if (y != NULL)
*y = event.xbutton.y_root;
}
buttons++;
break;
case ButtonRelease:
if (event.xbutton.window != root) {
XtDispatchEvent(&event);
break;
}
if (buttons > 0)
buttons--;
break;
default:
XtDispatchEvent(&event);
break;
}
}
XUngrabPointer(dpy, CurrentTime);
return(XmuClientWindow(dpy, target_win));
}
void
SetCommand(w, command, msg)
Widget w;
ResCommand command;
char * msg;
{
XClientMessageEvent client_event;
Display * dpy = XtDisplay(w);
if (msg == NULL)
msg = res_labels[6];
SetMessage(global_screen_data.info_label, msg);
if (global_client.window == None)
if ( (global_client.window = GetClientWindow(w, NULL, NULL)) == None)
return;
global_client.ident = GetNewIdent();
global_client.command = command;
global_client.atom = atom_comm;
BuildHeader(&(global_client));
if (!XtOwnSelection(w, global_client.atom, CurrentTime, ConvertCommand,
LoseSelection, SelectionDone))
SetMessage(global_screen_data.info_label,
res_labels[7]);
client_event.window = global_client.window;
client_event.type = ClientMessage;
client_event.message_type = atom_resource_editor;
client_event.format = EDITRES_SEND_EVENT_FORMAT;
client_event.data.l[0] = XtLastTimestampProcessed(dpy);
client_event.data.l[1] = global_client.atom;
client_event.data.l[2] = (long) global_client.ident;
client_event.data.l[3] = global_effective_protocol_version;
global_error_code = NO_ERROR;
global_old_error_handler = XSetErrorHandler(HandleXErrors);
global_serial_num = NextRequest(dpy);
XSendEvent(dpy, global_client.window, FALSE, (long) 0,
(XEvent *) &client_event);
XSync(dpy, FALSE);
XSetErrorHandler(global_old_error_handler);
if (global_error_code == NO_WINDOW) {
char error_buf[BUFSIZ];
global_error_code = NO_ERROR;
sprintf(error_buf, "The communication window with%s%s.",
" application is no longer available\n",
"Please select a new widget tree");
global_client.window = None;
SetCommand(w, LocalSendWidgetTree, error_buf);
return;
}
TellUserAboutMessage(global_screen_data.info_label, command);
global_client.timeout = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
CLIENT_TIME_OUT,
ClientTimedOut, (XtPointer) w);
}
static void
TellUserAboutMessage(label, command)
Widget label;
ResCommand command;
{
char msg[BUFSIZ], *str;
switch(command) {
case LocalSendWidgetTree:
str = " asking for widget tree";
break;
case LocalSetValues:
str = " asking it to perform SetValues()";
break;
case LocalFlashWidget:
case LocalGetGeometry:
str = " asking it to perform GetGeometry()";
break;
case LocalGetResources:
str = " asking it to get a widget's resource list";
break;
case LocalFindChild:
str = " asking it to find the child Widget.";
break;
default:
str = "";
break;
}
sprintf(msg, res_labels[8], str);
SetMessage(label, msg);
}
static Boolean
ConvertCommand(w,selection,target,type_ret, value_ret, length_ret, format_ret)
Widget w;
Atom * selection, * target, * type_ret;
XtPointer *value_ret;
unsigned long * length_ret;
int * format_ret;
{
if ((*selection != atom_comm) || (*target != atom_command))
return(FALSE);
*type_ret = atom_editres_protocol;
*value_ret = (XtPointer) global_client.stream.real_top;
*length_ret = global_client.stream.size + HEADER_SIZE;
*format_ret = EDITRES_FORMAT;
return(TRUE);
}
static void
SelectionDone(w, sel, targ)
Widget w;
Atom *sel, *targ;
{
}
static void
LoseSelection(w, sel)
Widget w;
Atom * sel;
{
if (global_client.timeout != 0) {
XtRemoveTimeOut(global_client.timeout);
global_client.timeout = 0;
}
XtGetSelectionValue(w, *sel, atom_client_value, GetClientValue,
NULL, XtLastTimestampProcessed(XtDisplay(w)));
}
static Boolean reset_protocol_level = True;
static void
GetClientValue(w, data, selection, type, value, length, format)
Widget w;
XtPointer data, value;
Atom *selection, *type;
unsigned long *length;
int * format;
{
Event * event;
ProtocolStream alloc_stream, *stream;
unsigned char ident, error_code;
char * error_str = NULL, msg[BUFSIZ];
if (*length == 0)
return;
stream = &alloc_stream;
stream->current = stream->top = (unsigned char *) value;
stream->size = HEADER_SIZE;
if (*length < HEADER_SIZE) {
SetMessage(global_screen_data.info_label,
res_labels[9]);
return;
}
(void) _XEditResGet8(stream, &ident);
if (global_client.ident != ident) {
#ifdef DEBUG
if (global_resources.debug)
printf("Incorrect ident from client.\n");
#endif
if (!XtOwnSelection(w, *selection, CurrentTime, ConvertCommand,
LoseSelection, SelectionDone))
SetMessage(global_screen_data.info_label,
res_labels[10]);
return;
}
(void) _XEditResGet8(stream, &error_code);
(void) _XEditResGet32(stream, &(stream->size));
stream->top = stream->current;
switch ((int) error_code) {
case PartialSuccess:
if ((event = BuildEvent(stream)) != NULL) {
error_str = DispatchEvent(event);
FreeEvent(event);
}
else {
sprintf(msg, "Unable to unpack protocol request.");
error_str = XtNewString(msg);
}
break;
case Failure:
error_str = GetFailureMessage(stream);
break;
case ProtocolMismatch:
error_str = ProtocolFailure(stream);
--global_effective_protocol_version;
reset_protocol_level = False;
SetCommand(w, LocalSendWidgetTree, NULL);
break;
default:
sprintf(msg, res_labels[11], (int) error_code);
SetMessage(global_screen_data.info_label, msg);
break;
}
if (error_str == NULL) {
WNode * top;
if (global_tree_info == NULL)
return;
top = global_tree_info->top_node;
sprintf(msg, res_labels[12], top->name, top->class);
SetMessage(global_screen_data.info_label, msg);
return;
}
SetMessage(global_screen_data.info_label, error_str);
XtFree(error_str);
}
static void
BuildHeader(client_data)
CurrentClient * client_data;
{
unsigned long old_alloc, old_size;
unsigned char * old_current;
EditresCommand command;
ProtocolStream * stream = &(client_data->stream);
old_current = stream->current;
old_alloc = stream->alloc;
old_size = stream->size;
stream->current = stream->real_top;
stream->alloc = stream->size + (2 * HEADER_SIZE);
_XEditResPut8(stream, client_data->ident);
switch(client_data->command) {
case LocalSendWidgetTree:
if (reset_protocol_level) global_effective_protocol_version =
CURRENT_PROTOCOL_VERSION;
reset_protocol_level = True;
command = SendWidgetTree;
break;
case LocalSetValues:
command = SetValues;
break;
case LocalFlashWidget:
command = GetGeometry;
break;
case LocalGetResources:
command = GetResources;
break;
case LocalFindChild:
command = FindChild;
break;
case LocalGetValues:
command = GetValues;
break;
default:
command = SendWidgetTree;
break;
}
_XEditResPut8(stream, (unsigned char) command);
_XEditResPut32(stream, old_size);
stream->alloc = old_alloc;
stream->current = old_current;
stream->size = old_size;
}
static Event *
BuildEvent(stream)
ProtocolStream * stream;
{
int i;
Event * event = (Event *) XtCalloc(sizeof(Event), 1);
switch(global_client.command) {
case LocalSendWidgetTree:
{
SendWidgetTreeEvent * send_event = (SendWidgetTreeEvent *) event;
send_event->type = SendWidgetTree;
if (!_XEditResGet16(stream, &(send_event->num_entries)))
goto done;
send_event->info = (WidgetTreeInfo *)
XtCalloc(sizeof(WidgetTreeInfo),
send_event->num_entries);
for (i = 0; i < (int)send_event->num_entries; i++) {
WidgetTreeInfo * info = send_event->info + i;
if (!(_XEditResGetWidgetInfo(stream, &(info->widgets)) &&
_XEditResGetString8(stream, &(info->name)) &&
_XEditResGetString8(stream, &(info->class)) &&
_XEditResGet32(stream, &(info->window))))
{
goto done;
}
}
if (global_effective_protocol_version ==
CURRENT_PROTOCOL_VERSION) {
if (!_XEditResGetString8(stream, &(send_event->toolkit)))
goto done;
}
SetEntriesSensitive(&CM_entries[CM_OFFSET], CM_NUM, True);
SetEntriesSensitive(TM_entries, TM_NUM, True);
if (global_effective_protocol_version ==
CURRENT_PROTOCOL_VERSION) {
if (!strcmp(send_event->toolkit, "InterViews"))
RebuildMenusAndLabel("iv");
}
else
RebuildMenusAndLabel("xt");
}
break;
case LocalSetValues:
{
SetValuesEvent * sv_event = (SetValuesEvent *) event;
sv_event->type = SetValues;
if (!_XEditResGet16(stream, &(sv_event->num_entries)))
goto done;
sv_event->info = (SetValuesInfo *) XtCalloc(sizeof(SetValuesInfo),
sv_event->num_entries);
for (i = 0; i < (int)sv_event->num_entries; i++) {
SetValuesInfo * info = sv_event->info + i;
if (!(_XEditResGetWidgetInfo(stream, &(info->widgets)) &&
_XEditResGetString8(stream, &(info->message))))
{
goto done;
}
}
}
break;
case LocalGetResources:
{
GetResourcesEvent * res_event = (GetResourcesEvent *) event;
res_event->type = GetGeometry;
if (!_XEditResGet16(stream, &(res_event->num_entries)))
goto done;
res_event->info = (GetResourcesInfo *)
XtCalloc(sizeof(GetResourcesInfo),
res_event->num_entries);
for (i = 0; i < (int)res_event->num_entries; i++) {
GetResourcesInfo * res_info = res_event->info + i;
if (!(_XEditResGetWidgetInfo(stream, &(res_info->widgets)) &&
_XEditResGetBoolean(stream, &(res_info->error))))
{
goto done;
}
if (res_info->error) {
if (!_XEditResGetString8(stream, &(res_info->message)))
goto done;
}
else {
unsigned int j;
if (!_XEditResGet16(stream, &(res_info->num_resources)))
goto done;
res_info->res_info = (ResourceInfo *)
XtCalloc(sizeof(ResourceInfo),
res_info->num_resources);
for (j = 0; j < res_info->num_resources; j++) {
unsigned char temp;
ResourceInfo * info = res_info->res_info + j;
if (!(_XEditResGetResType(stream, &(temp)) &&
_XEditResGetString8(stream, &(info->name)) &&
_XEditResGetString8(stream, &(info->class)) &&
_XEditResGetString8(stream, &(info->type))))
{
goto done;
}
else
info->res_type = (ResourceType) temp;
}
}
}
}
break;
case LocalFlashWidget:
case LocalGetGeometry:
{
GetGeomEvent * geom_event = (GetGeomEvent *) event;
geom_event->type = GetGeometry;
if (!_XEditResGet16(stream, &(geom_event->num_entries)))
goto done;
geom_event->info = (GetGeomInfo *) XtCalloc(sizeof(GetGeomInfo),
geom_event->num_entries);
for (i = 0; i < (int)geom_event->num_entries; i++) {
GetGeomInfo * info = geom_event->info + i;
if (!(_XEditResGetWidgetInfo(stream, &(info->widgets)) &&
_XEditResGetBoolean(stream, &(info->error))))
{
goto done;
}
if (info->error) {
if (!_XEditResGetString8(stream, &(info->message)))
goto done;
}
else {
if (!(_XEditResGetBoolean(stream, &(info->visable)) &&
_XEditResGetSigned16(stream, &(info->x)) &&
_XEditResGetSigned16(stream, &(info->y)) &&
_XEditResGet16(stream, &(info->width)) &&
_XEditResGet16(stream, &(info->height)) &&
_XEditResGet16(stream, &(info->border_width))))
{
goto done;
}
}
}
}
break;
case LocalFindChild:
{
FindChildEvent * find_event = (FindChildEvent *) event;
find_event->type = FindChild;
if (!_XEditResGetWidgetInfo(stream, &(find_event->widgets)))
goto done;
}
break;
case LocalGetValues:
{
Arg args[1];
GetValuesEvent * gv_event = (GetValuesEvent *) event;
gv_event->type = GetValues;
if (!_XEditResGet16(stream, &(gv_event->num_entries)))
goto done;
gv_event->info = (GetValuesInfo*)XtCalloc(sizeof(GetValuesInfo),1);
{
GetValuesInfo * info = gv_event->info;
if (!(_XEditResGetString8(stream, &(info->value))))
{
goto done;
}
XtSetArg (args[0], XtNstring, info->value);
XtSetValues(
global_tree_info->active_nodes[0]->resources->res_box->value_wid,
args, 1
);
}
}
break;
default:
goto done;
}
return(event);
done:
FreeEvent(event);
return(NULL);
}
static void
FreeEvent(event)
Event * event;
{
unsigned int i;
switch(event->any_event.type) {
case SendWidgetTree:
{
SendWidgetTreeEvent * send_event = (SendWidgetTreeEvent *) event;
WidgetTreeInfo * info = send_event->info;
if (info != NULL) {
for (i = 0; i < send_event->num_entries; i++, info++) {
XtFree((char *)info->widgets.ids);
XtFree(info->name);
XtFree(info->class);
}
XtFree((char *)send_event->info);
}
}
break;
case SetValues:
{
SetValuesEvent * sv_event = (SetValuesEvent *) event;
SetValuesInfo * info = sv_event->info;
if (info != NULL) {
for (i = 0; i < sv_event->num_entries; i++, info++) {
XtFree((char *)info->widgets.ids);
XtFree(info->message);
}
XtFree((char *)sv_event->info);
}
}
break;
case GetResources:
{
GetResourcesEvent * get_event = (GetResourcesEvent *) event;
GetResourcesInfo * info = get_event->info;
if (info != NULL) {
for (i = 0; i < get_event->num_entries; i++, info++) {
XtFree((char *)info->widgets.ids);
if (info->error)
XtFree(info->message);
else {
unsigned int j;
ResourceInfo * res_info = info->res_info;
if (res_info != NULL) {
for (j = 0;
j < info->num_resources; j++, res_info++)
{
XtFree(res_info->name);
XtFree(res_info->class);
XtFree(res_info->type);
}
XtFree((char *)info->res_info);
}
}
}
XtFree((char *)get_event->info);
}
}
break;
case GetGeometry:
{
GetGeomEvent * geom_event = (GetGeomEvent *) event;
GetGeomInfo * info = geom_event->info;
if (info != NULL) {
for (i = 0; i < geom_event->num_entries; i++, info++) {
XtFree((char *)info->widgets.ids);
if (info->error)
XtFree(info->message);
}
XtFree((char *)geom_event->info);
}
}
break;
case FindChild:
{
FindChildEvent * find_event = (FindChildEvent *) event;
XtFree((char *)find_event->widgets.ids);
}
break;
default:
break;
}
}
static char *
DispatchEvent(event)
Event * event;
{
char * error = NULL;
switch(global_client.command) {
case LocalSendWidgetTree:
BuildVisualTree(global_tree_parent, event);
break;
case LocalSetValues:
error = PrintSetValuesError(event);
break;
case LocalFlashWidget:
error = HandleFlashWidget(event);
break;
case LocalGetResources:
error = HandleGetResources(event);
break;
case LocalFindChild:
DisplayChild(event);
break;
case LocalGetValues:
break;
default:
{
char msg[BUFSIZ];
sprintf(msg, "Internal error: Unknown command %d.",
global_client.command);
error = XtNewString(msg);
}
break;
}
return(error);
}
void
InternAtoms(dpy)
Display * dpy;
{
atom_comm = XInternAtom(dpy, EDITRES_COMM_ATOM, False);
atom_command = XInternAtom(dpy, EDITRES_COMMAND_ATOM, False);
atom_resource_editor = XInternAtom(dpy, EDITRES_NAME, False);
atom_client_value = XInternAtom(dpy, EDITRES_CLIENT_VALUE, False);
atom_editres_protocol = XInternAtom(dpy, EDITRES_PROTOCOL_ATOM, False);
}
ResIdent
GetNewIdent()
{
static ResIdent ident = 1;
return(ident++);
}