lyx_mirror/development/autotests/xvkbd/findwidget.c
Tommaso Cucinotta 1f51de3cd1 Added custom xvkbd for avoiding typing into other windows.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37439 a592a061-630c-0410-9148-cb99ea01b6c8
2011-02-02 23:18:16 +00:00

352 lines
12 KiB
C

/*
* xvkbd - Virtual Keyboard for X Window System
*
* Copyright (C) 2000 by Tom Sato <VEF00200@nifty.ne.jp>
* http://homepage3.nifty.com/tsato/
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* This code is derived from editres in X11R6 distribution.
*/
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xmu/EditresP.h>
#include "resources.h"
#define EDITRES_PROTOCOL_VERSION 5 /* Editres Protocol version 1.1 */
#define EditresLocalSendWidgetTree 0 /* op code defined in Editres Protocol */
#define CLIENT_TIME_OUT 2000 /* 2sec */
static void RequestSendWidgetTree(Widget w); /* forward */
static void LoseSelection(Widget w, Atom *sel); /* forward */
static Atom atom_comm = None;
static Atom atom_command = None;
static Atom atom_resource_editor = None;
static Atom atom_editres_protocol = None;
static Atom atom_client_value = None;
static ResIdent client_ident = 1;
static Window client_window = None;
static ProtocolStream client_stream;
static int effective_protocol_version;
static Boolean waiting_response;
/*
* List of widgets will be stored in widget_list[], and number
* of widgets will be stored in num_widget_list.
*/
static int num_widget_list = 0;
static struct WidgetList {
Window window;
unsigned long id;
unsigned long parent;
char *name;
char *class;
char *path;
} *widget_list = NULL;
/*
* This function will be called when the client requests the
* value of the selection.
*/
static Boolean ConvertCommand(Widget w,
Atom *selection, Atom *target, Atom *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)client_stream.real_top;
*length_ret = client_stream.size + HEADER_SIZE;
*format_ret = EDITRES_FORMAT;
return(TRUE);
}
/*
* Read response to the Editres LocalSendWidgetTree request
* and make list of the widgets.
* If appres.list is TRUE, list of all widgets will be printed
* to the stdout.
*/
static void GetClientValue(Widget w, XtPointer data,
Atom *selection, Atom *type, XtPointer value,
unsigned long *length, int *format)
{
ProtocolStream stream;
unsigned char ident, version, error_code;
unsigned short num_entries;
WidgetInfo widgets;
char *name, *class, *err_msg;
unsigned long window;
int i, j;
if (*length == 0) return;
stream.current = stream.top = (unsigned char *)value;
stream.size = HEADER_SIZE;
if (*length < HEADER_SIZE) {
fprintf(stderr, "%s: incorrectly formatted message from client\n",
PROGRAM_NAME);
return;
}
_XEditResGet8(&stream, &ident);
if (client_ident != ident) {
fprintf(stderr, "%s: wincorrect ident from client\n", PROGRAM_NAME);
if (!XtOwnSelection(w, *selection, CurrentTime,
ConvertCommand, LoseSelection, NULL))
fprintf(stderr, "%s: XtOwnSelection() failed\n", PROGRAM_NAME);
return;
}
_XEditResGet8(&stream, &error_code);
_XEditResGet32(&stream, &stream.size);
stream.top = stream.current; /* reset stream to top of value */
switch ((int) error_code) {
case PartialSuccess:
if (widget_list != NULL) {
for (i = 0; i < num_widget_list; i++) {
XtFree(widget_list[i].name);
XtFree(widget_list[i].class);
XtFree(widget_list[i].path);
}
XtFree((void *)widget_list);
widget_list = NULL;
}
if (_XEditResGet16(&stream, &num_entries)) {
widget_list = (struct WidgetList *)XtMalloc(sizeof(struct WidgetList)
* num_entries);
num_widget_list = num_entries;
for (i = 0; i < num_entries; i++) {
if (!(_XEditResGetWidgetInfo(&stream, &widgets) &&
_XEditResGetString8(&stream, &name) &&
_XEditResGetString8(&stream, &class) &&
_XEditResGet32(&stream, &window))) {
num_widget_list = i;
break;
}
widget_list[i].window = window;
widget_list[i].id = widgets.ids[widgets.num_widgets - 1];
if (widgets.num_widgets < 2) widget_list[i].parent = 0;
else widget_list[i].parent = widgets.ids[widgets.num_widgets - 2];
widget_list[i].name = XtNewString(name);
widget_list[i].class = XtNewString(class);
widget_list[i].path = NULL;
if (widget_list[i].parent != 0) {
for (j = 0; j < i; j++) {
if (widget_list[j].id == widget_list[i].parent) {
widget_list[i].path = XtMalloc(strlen(widget_list[j].path)
+ strlen(widget_list[i].name) + 2);
sprintf(widget_list[i].path, "%s.%s",
widget_list[j].path, widget_list[i].name);
break;
}
}
}
if (widget_list[i].path == NULL) {
widget_list[i].path = XtMalloc(strlen(widget_list[i].name) + 2);
sprintf(widget_list[i].path, "%s%s",
(widget_list[i].parent != 0) ? "*" : "",
widget_list[i].name);
}
if (appres.list_widgets) {
fprintf(stdout, "0x%08lx 0x%08lx (%s) %s\n",
(long)widget_list[i].window, (long)widget_list[i].id,
widget_list[i].class, widget_list[i].path);
}
}
}
break;
case ProtocolMismatch:
if (!_XEditResGet8(&stream, &version)) {
fprintf(stderr, "%s: unable to unpack protocol request\n", PROGRAM_NAME);
} else if (version == effective_protocol_version) {
fprintf(stderr, "%s: internal error - ProtocolMismatch\n", PROGRAM_NAME);
} else {
fprintf(stderr, "%s: protocol version mismatch (requested=%d, supported=%d)\n",
PROGRAM_NAME, (int)effective_protocol_version, (int)version);
effective_protocol_version = version;
RequestSendWidgetTree(w);
}
break;
case Failure:
if (!_XEditResGetString8(&stream, &err_msg)) {
fprintf(stderr, "%s: unable to unpack protocol request\n", PROGRAM_NAME);
} else {
fprintf(stderr, "%s: %s\n", PROGRAM_NAME, err_msg);
}
break;
default:
fprintf(stderr, "%s: unknown error code %d\n", PROGRAM_NAME, (int)error_code);
break;
}
waiting_response = FALSE;
}
/*
* This will be called when selection "EditresComm", and will
* call GetClientValue() via XtGetSelectionValue().
*
* The selection is owned by this program when send the request
* to the client, and will be lost when the client responded to
* the request.
*/
static void LoseSelection(Widget w, Atom *sel)
{
XtGetSelectionValue(w, *sel, atom_client_value, GetClientValue,
NULL, XtLastTimestampProcessed(XtDisplay(w)));
}
/*
* Send the Editres LocalSendWidgetTree request to the client.
*/
static void RequestSendWidgetTree(Widget w)
{
XClientMessageEvent client_event;
client_ident = client_ident + 1;
_XEditResResetStream(&client_stream);
client_stream.current = client_stream.real_top;
client_stream.alloc = client_stream.size + (2 * HEADER_SIZE);
_XEditResPut8(&client_stream, client_ident);
_XEditResPut8(&client_stream, (unsigned char)EditresLocalSendWidgetTree);
_XEditResPut32(&client_stream, client_stream.size);
if (!XtOwnSelection(w, atom_comm, CurrentTime,
ConvertCommand, LoseSelection, NULL))
fprintf(stderr, "%s: XtOwnSelection() failed\n", PROGRAM_NAME);
client_event.window = 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(XtDisplay(w));
client_event.data.l[1] = atom_comm;
client_event.data.l[2] = (long)client_ident;
client_event.data.l[3] = effective_protocol_version;
XSendEvent(XtDisplay(w), client_event.window, FALSE, (long)0,
(XEvent *)&client_event);
}
/*
* Clients which doesn't support Editres protocol will not respond
* to the LocalSendWidgetTree request - we must detect it as timeout.
*/
static void ClientTimeOut(XtPointer client_data, XtIntervalId *id)
{
fprintf(stderr, "%s: client 0x%lx didn't responded to Editres Protocol request\n",
PROGRAM_NAME, (long)client_window);
waiting_response = FALSE;
}
/*
* Find a widget which name matches the specified pattern, and
* return the window-id of the widget. If there are two or more
* matched widgets, one of them will be returned.
*
* If name of the widget to be matched is "foo.bar.zot", the pattern
* (argument "name") can be "zot", "bar.zot" or "foo.bar.zot".
* The pattern can leaded with "*" such as "*zot", but "*" can't be
* used between the words (i.e., "foo*zot" is not allowed).
*/
Window FindWidget(Widget w, Window client, const char *name)
{
XEvent event;
XtAppContext app_con;
XtIntervalId timer_id;
const char *pattern;
int pattern_len, inx, i;
if (waiting_response) {
fprintf(stderr, "%s: list widget requested recursively (ignored)\n",
PROGRAM_NAME);
return None;
}
if (appres.debug)
fprintf(stderr, "%s: list widget tree for window 0x%lx\n",
PROGRAM_NAME, (long)client);
if (atom_comm == None) {
Display *dpy = XtDisplay(w);
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_editres_protocol = XInternAtom(dpy, EDITRES_PROTOCOL_ATOM, False);
atom_client_value = XInternAtom(dpy, EDITRES_CLIENT_VALUE, False);
}
client_window = client;
effective_protocol_version = EDITRES_PROTOCOL_VERSION;
app_con = XtWidgetToApplicationContext(w);
timer_id = XtAppAddTimeOut(app_con, CLIENT_TIME_OUT, ClientTimeOut, NULL);
waiting_response = TRUE;
RequestSendWidgetTree(w);
while (waiting_response) {
XtAppNextEvent(app_con, &event);
XtDispatchEvent(&event);
}
XtRemoveTimeOut(timer_id);
if (widget_list != NULL && strlen(name) != 0) {
pattern = name;
if (pattern[0] == '*') pattern = pattern + 1;
if (strchr(pattern, '*') != NULL)
fprintf(stderr, "%s: pattern should not include \"*\": %s\n",
PROGRAM_NAME, name);
pattern_len = strlen(pattern);
for (i = 0; i < num_widget_list; i++) {
if (appres.debug)
fprintf(stderr, "FindWidget: %s\n", widget_list[i].path);
inx = strlen(widget_list[i].path) - pattern_len;
if (0 <= inx) {
if (1 <= inx && widget_list[i].path[inx - 1] != '.'
&& widget_list[i].path[inx - 1] != '*') continue;
if (strcmp(&widget_list[i].path[inx], pattern) == 0) break;
}
}
if (i < num_widget_list) {
if (appres.debug)
fprintf(stderr, "%s: matched widget: %s (id=0x%lx, window=0x%lx)\n",
PROGRAM_NAME, widget_list[i].path,
(long)widget_list[i].id, (long)widget_list[i].window);
return widget_list[i].window;
}
}
if (appres.debug && widget_list == NULL)
fprintf(stderr, "FindWidget: couldn't get widget list\n");
if (strlen(name) != 0) {
fprintf(stderr, "%s: no widget matched to pattern \"%s\"\n",
PROGRAM_NAME, name);
}
return None;
}