2 * xvkbd - Virtual Keyboard for X Window System
4 * Copyright (C) 2000 by Tom Sato <VEF00200@nifty.ne.jp>
5 * http://homepage3.nifty.com/tsato/
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 * See the GNU General Public License for more details.
17 * This code is derived from editres in X11R6 distribution.
22 #include <X11/Xmu/EditresP.h>
24 #include "resources.h"
26 #define EDITRES_PROTOCOL_VERSION 5 /* Editres Protocol version 1.1 */
27 #define EditresLocalSendWidgetTree 0 /* op code defined in Editres Protocol */
29 #define CLIENT_TIME_OUT 2000 /* 2sec */
31 static void RequestSendWidgetTree(Widget w); /* forward */
32 static void LoseSelection(Widget w, Atom *sel); /* forward */
34 static Atom atom_comm = None;
35 static Atom atom_command = None;
36 static Atom atom_resource_editor = None;
37 static Atom atom_editres_protocol = None;
38 static Atom atom_client_value = None;
40 static ResIdent client_ident = 1;
42 static Window client_window = None;
43 static ProtocolStream client_stream;
44 static int effective_protocol_version;
46 static Boolean waiting_response;
49 * List of widgets will be stored in widget_list[], and number
50 * of widgets will be stored in num_widget_list.
52 static int num_widget_list = 0;
54 static struct WidgetList {
61 } *widget_list = NULL;
65 * This function will be called when the client requests the
66 * value of the selection.
68 static Boolean ConvertCommand(Widget w,
69 Atom *selection, Atom *target, Atom *type_ret,
70 XtPointer *value_ret, unsigned long *length_ret,
73 if ((*selection != atom_comm) || (*target != atom_command))
76 *type_ret = atom_editres_protocol;
77 *value_ret = (XtPointer)client_stream.real_top;
78 *length_ret = client_stream.size + HEADER_SIZE;
79 *format_ret = EDITRES_FORMAT;
85 * Read response to the Editres LocalSendWidgetTree request
86 * and make list of the widgets.
87 * If appres.list is TRUE, list of all widgets will be printed
90 static void GetClientValue(Widget w, XtPointer data,
91 Atom *selection, Atom *type, XtPointer value,
92 unsigned long *length, int *format)
94 ProtocolStream stream;
95 unsigned char ident, version, error_code;
96 unsigned short num_entries;
98 char *name, *class, *err_msg;
102 if (*length == 0) return;
104 stream.current = stream.top = (unsigned char *)value;
105 stream.size = HEADER_SIZE;
107 if (*length < HEADER_SIZE) {
108 fprintf(stderr, "%s: incorrectly formatted message from client\n",
113 _XEditResGet8(&stream, &ident);
114 if (client_ident != ident) {
115 fprintf(stderr, "%s: wincorrect ident from client\n", PROGRAM_NAME);
116 if (!XtOwnSelection(w, *selection, CurrentTime,
117 ConvertCommand, LoseSelection, NULL))
118 fprintf(stderr, "%s: XtOwnSelection() failed\n", PROGRAM_NAME);
122 _XEditResGet8(&stream, &error_code);
123 _XEditResGet32(&stream, &stream.size);
124 stream.top = stream.current; /* reset stream to top of value */
126 switch ((int) error_code) {
128 if (widget_list != NULL) {
129 for (i = 0; i < num_widget_list; i++) {
130 XtFree(widget_list[i].name);
131 XtFree(widget_list[i].class);
132 XtFree(widget_list[i].path);
134 XtFree((void *)widget_list);
138 if (_XEditResGet16(&stream, &num_entries)) {
139 widget_list = (struct WidgetList *)XtMalloc(sizeof(struct WidgetList)
141 num_widget_list = num_entries;
142 for (i = 0; i < num_entries; i++) {
143 if (!(_XEditResGetWidgetInfo(&stream, &widgets) &&
144 _XEditResGetString8(&stream, &name) &&
145 _XEditResGetString8(&stream, &class) &&
146 _XEditResGet32(&stream, &window))) {
150 widget_list[i].window = window;
151 widget_list[i].id = widgets.ids[widgets.num_widgets - 1];
152 if (widgets.num_widgets < 2) widget_list[i].parent = 0;
153 else widget_list[i].parent = widgets.ids[widgets.num_widgets - 2];
154 widget_list[i].name = XtNewString(name);
155 widget_list[i].class = XtNewString(class);
157 widget_list[i].path = NULL;
158 if (widget_list[i].parent != 0) {
159 for (j = 0; j < i; j++) {
160 if (widget_list[j].id == widget_list[i].parent) {
161 widget_list[i].path = XtMalloc(strlen(widget_list[j].path)
162 + strlen(widget_list[i].name) + 2);
163 sprintf(widget_list[i].path, "%s.%s",
164 widget_list[j].path, widget_list[i].name);
169 if (widget_list[i].path == NULL) {
170 widget_list[i].path = XtMalloc(strlen(widget_list[i].name) + 2);
171 sprintf(widget_list[i].path, "%s%s",
172 (widget_list[i].parent != 0) ? "*" : "",
173 widget_list[i].name);
175 if (appres.list_widgets) {
176 fprintf(stdout, "0x%08lx 0x%08lx (%s) %s\n",
177 (long)widget_list[i].window, (long)widget_list[i].id,
178 widget_list[i].class, widget_list[i].path);
183 case ProtocolMismatch:
184 if (!_XEditResGet8(&stream, &version)) {
185 fprintf(stderr, "%s: unable to unpack protocol request\n", PROGRAM_NAME);
186 } else if (version == effective_protocol_version) {
187 fprintf(stderr, "%s: internal error - ProtocolMismatch\n", PROGRAM_NAME);
189 fprintf(stderr, "%s: protocol version mismatch (requested=%d, supported=%d)\n",
190 PROGRAM_NAME, (int)effective_protocol_version, (int)version);
191 effective_protocol_version = version;
192 RequestSendWidgetTree(w);
196 if (!_XEditResGetString8(&stream, &err_msg)) {
197 fprintf(stderr, "%s: unable to unpack protocol request\n", PROGRAM_NAME);
199 fprintf(stderr, "%s: %s\n", PROGRAM_NAME, err_msg);
203 fprintf(stderr, "%s: unknown error code %d\n", PROGRAM_NAME, (int)error_code);
206 waiting_response = FALSE;
210 * This will be called when selection "EditresComm", and will
211 * call GetClientValue() via XtGetSelectionValue().
213 * The selection is owned by this program when send the request
214 * to the client, and will be lost when the client responded to
217 static void LoseSelection(Widget w, Atom *sel)
219 XtGetSelectionValue(w, *sel, atom_client_value, GetClientValue,
220 NULL, XtLastTimestampProcessed(XtDisplay(w)));
224 * Send the Editres LocalSendWidgetTree request to the client.
226 static void RequestSendWidgetTree(Widget w)
228 XClientMessageEvent client_event;
230 client_ident = client_ident + 1;
232 _XEditResResetStream(&client_stream);
233 client_stream.current = client_stream.real_top;
234 client_stream.alloc = client_stream.size + (2 * HEADER_SIZE);
236 _XEditResPut8(&client_stream, client_ident);
237 _XEditResPut8(&client_stream, (unsigned char)EditresLocalSendWidgetTree);
238 _XEditResPut32(&client_stream, client_stream.size);
240 if (!XtOwnSelection(w, atom_comm, CurrentTime,
241 ConvertCommand, LoseSelection, NULL))
242 fprintf(stderr, "%s: XtOwnSelection() failed\n", PROGRAM_NAME);
244 client_event.window = client_window;
245 client_event.type = ClientMessage;
246 client_event.message_type = atom_resource_editor;
247 client_event.format = EDITRES_SEND_EVENT_FORMAT;
248 client_event.data.l[0] = XtLastTimestampProcessed(XtDisplay(w));
249 client_event.data.l[1] = atom_comm;
250 client_event.data.l[2] = (long)client_ident;
251 client_event.data.l[3] = effective_protocol_version;
253 XSendEvent(XtDisplay(w), client_event.window, FALSE, (long)0,
254 (XEvent *)&client_event);
258 * Clients which doesn't support Editres protocol will not respond
259 * to the LocalSendWidgetTree request - we must detect it as timeout.
261 static void ClientTimeOut(XtPointer client_data, XtIntervalId *id)
263 fprintf(stderr, "%s: client 0x%lx didn't responded to Editres Protocol request\n",
264 PROGRAM_NAME, (long)client_window);
265 waiting_response = FALSE;
269 * Find a widget which name matches the specified pattern, and
270 * return the window-id of the widget. If there are two or more
271 * matched widgets, one of them will be returned.
273 * If name of the widget to be matched is "foo.bar.zot", the pattern
274 * (argument "name") can be "zot", "bar.zot" or "foo.bar.zot".
275 * The pattern can leaded with "*" such as "*zot", but "*" can't be
276 * used between the words (i.e., "foo*zot" is not allowed).
278 Window FindWidget(Widget w, Window client, const char *name)
281 XtAppContext app_con;
282 XtIntervalId timer_id;
284 int pattern_len, inx, i;
286 if (waiting_response) {
287 fprintf(stderr, "%s: list widget requested recursively (ignored)\n",
293 fprintf(stderr, "%s: list widget tree for window 0x%lx\n",
294 PROGRAM_NAME, (long)client);
296 if (atom_comm == None) {
297 Display *dpy = XtDisplay(w);
298 atom_comm = XInternAtom(dpy, EDITRES_COMM_ATOM, False);
299 atom_command = XInternAtom(dpy, EDITRES_COMMAND_ATOM, False);
300 atom_resource_editor = XInternAtom(dpy, EDITRES_NAME, False);
301 atom_editres_protocol = XInternAtom(dpy, EDITRES_PROTOCOL_ATOM, False);
302 atom_client_value = XInternAtom(dpy, EDITRES_CLIENT_VALUE, False);
305 client_window = client;
306 effective_protocol_version = EDITRES_PROTOCOL_VERSION;
307 app_con = XtWidgetToApplicationContext(w);
309 timer_id = XtAppAddTimeOut(app_con, CLIENT_TIME_OUT, ClientTimeOut, NULL);
310 waiting_response = TRUE;
311 RequestSendWidgetTree(w);
312 while (waiting_response) {
313 XtAppNextEvent(app_con, &event);
314 XtDispatchEvent(&event);
316 XtRemoveTimeOut(timer_id);
318 if (widget_list != NULL && strlen(name) != 0) {
320 if (pattern[0] == '*') pattern = pattern + 1;
321 if (strchr(pattern, '*') != NULL)
322 fprintf(stderr, "%s: pattern should not include \"*\": %s\n",
324 pattern_len = strlen(pattern);
325 for (i = 0; i < num_widget_list; i++) {
327 fprintf(stderr, "FindWidget: %s\n", widget_list[i].path);
328 inx = strlen(widget_list[i].path) - pattern_len;
330 if (1 <= inx && widget_list[i].path[inx - 1] != '.'
331 && widget_list[i].path[inx - 1] != '*') continue;
332 if (strcmp(&widget_list[i].path[inx], pattern) == 0) break;
335 if (i < num_widget_list) {
337 fprintf(stderr, "%s: matched widget: %s (id=0x%lx, window=0x%lx)\n",
338 PROGRAM_NAME, widget_list[i].path,
339 (long)widget_list[i].id, (long)widget_list[i].window);
340 return widget_list[i].window;
343 if (appres.debug && widget_list == NULL)
344 fprintf(stderr, "FindWidget: couldn't get widget list\n");
345 if (strlen(name) != 0) {
346 fprintf(stderr, "%s: no widget matched to pattern \"%s\"\n",