]> git.lyx.org Git - lyx.git/blob - development/autotests/xvkbd/findwidget.c
ctests: mark failing LyXHTML tests as "lyxbugs"
[lyx.git] / development / autotests / xvkbd / findwidget.c
1 /*
2  * xvkbd - Virtual Keyboard for X Window System
3  *
4  * Copyright (C) 2000 by Tom Sato <VEF00200@nifty.ne.jp>
5  * http://homepage3.nifty.com/tsato/
6  *
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.
11  *
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.
16  *
17  * This code is derived from editres in X11R6 distribution.
18  */
19
20 #include <stdio.h>
21 #include <X11/Xlib.h>
22 #include <X11/Xmu/EditresP.h>
23
24 #include "resources.h"
25
26 #define EDITRES_PROTOCOL_VERSION 5  /* Editres Protocol version 1.1 */
27 #define EditresLocalSendWidgetTree 0  /* op code defined in Editres Protocol */
28
29 #define CLIENT_TIME_OUT 2000  /* 2sec */
30
31 static void RequestSendWidgetTree(Widget w);  /* forward */
32 static void LoseSelection(Widget w, Atom *sel);  /* forward */
33
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;
39
40 static ResIdent client_ident = 1;
41
42 static Window client_window = None;
43 static ProtocolStream client_stream;
44 static int effective_protocol_version;
45
46 static Boolean waiting_response;
47
48 /*
49  * List of widgets will be stored in widget_list[], and number
50  * of widgets will be stored in num_widget_list.
51  */
52 static int num_widget_list = 0;
53
54 static struct WidgetList {
55   Window window;
56   unsigned long id;
57   unsigned long parent;
58   char *name;
59   char *class;
60   char *path;
61 } *widget_list = NULL;
62
63
64 /*
65  * This function will be called when the client requests the
66  * value of the selection.
67  */
68 static Boolean ConvertCommand(Widget w,
69                       Atom *selection, Atom *target, Atom *type_ret,
70                       XtPointer *value_ret, unsigned long *length_ret,
71                       int *format_ret)
72 {
73   if ((*selection != atom_comm) || (*target != atom_command))
74     return(FALSE);
75
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;
80
81   return(TRUE);
82 }
83
84 /*
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
88  * to the stdout.
89  */
90 static void GetClientValue(Widget w, XtPointer data,
91                            Atom *selection, Atom *type, XtPointer value,
92                            unsigned long *length, int *format)
93 {
94   ProtocolStream stream;
95   unsigned char ident, version, error_code;
96   unsigned short num_entries;
97   WidgetInfo widgets;
98   char *name, *class, *err_msg;
99   unsigned long window;
100   int i, j;
101
102   if (*length == 0) return;
103
104   stream.current = stream.top = (unsigned char *)value;
105   stream.size = HEADER_SIZE;
106
107   if (*length < HEADER_SIZE) {
108     fprintf(stderr, "%s: incorrectly formatted message from client\n",
109             PROGRAM_NAME);
110     return;
111   }
112
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);
119     return;
120   }
121
122   _XEditResGet8(&stream, &error_code);
123   _XEditResGet32(&stream, &stream.size);
124   stream.top = stream.current;  /* reset stream to top of value */
125
126   switch ((int) error_code) {
127   case PartialSuccess:
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);
133       }
134       XtFree((void *)widget_list);
135       widget_list = NULL;
136     }
137
138     if (_XEditResGet16(&stream, &num_entries)) {
139       widget_list = (struct WidgetList *)XtMalloc(sizeof(struct WidgetList)
140                                                   * num_entries);
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))) {
147           num_widget_list = i;
148           break;
149         }
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);
156
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);
165               break;
166             }
167           }
168         }
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);
174         }
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);
179         }
180       }
181     }
182     break;
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);
188     } else {
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);
193     }
194     break;
195   case Failure:
196     if (!_XEditResGetString8(&stream, &err_msg)) {
197       fprintf(stderr, "%s: unable to unpack protocol request\n", PROGRAM_NAME);
198     } else {
199       fprintf(stderr, "%s: %s\n", PROGRAM_NAME, err_msg);
200     }
201     break;
202   default:
203     fprintf(stderr, "%s: unknown error code %d\n", PROGRAM_NAME, (int)error_code);
204     break;
205   }
206   waiting_response = FALSE;
207 }
208
209 /*
210  * This will be called when selection "EditresComm", and will
211  * call GetClientValue() via XtGetSelectionValue().
212  *
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
215  * the request.
216  */
217 static void LoseSelection(Widget w, Atom *sel)
218 {
219   XtGetSelectionValue(w, *sel, atom_client_value, GetClientValue,
220                       NULL, XtLastTimestampProcessed(XtDisplay(w)));
221 }
222
223 /*
224  * Send the Editres LocalSendWidgetTree request to the client.
225  */
226 static void RequestSendWidgetTree(Widget w)
227 {
228   XClientMessageEvent client_event;
229
230   client_ident = client_ident + 1;
231
232   _XEditResResetStream(&client_stream);
233   client_stream.current = client_stream.real_top;
234   client_stream.alloc = client_stream.size + (2 * HEADER_SIZE);
235
236   _XEditResPut8(&client_stream, client_ident);
237   _XEditResPut8(&client_stream, (unsigned char)EditresLocalSendWidgetTree);
238   _XEditResPut32(&client_stream, client_stream.size);
239
240   if (!XtOwnSelection(w, atom_comm, CurrentTime,
241                       ConvertCommand, LoseSelection, NULL))
242     fprintf(stderr, "%s: XtOwnSelection() failed\n", PROGRAM_NAME);
243
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;
252
253   XSendEvent(XtDisplay(w), client_event.window, FALSE, (long)0,
254              (XEvent *)&client_event);
255 }
256
257 /*
258  * Clients which doesn't support Editres protocol will not respond
259  * to the LocalSendWidgetTree request - we must detect it as timeout.
260  */
261 static void ClientTimeOut(XtPointer client_data, XtIntervalId *id)
262 {
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;
266 }
267
268 /*
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.
272  *
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).
277  */
278 Window FindWidget(Widget w, Window client, const char *name)
279 {
280   XEvent event;
281   XtAppContext app_con;
282   XtIntervalId timer_id;
283   const char *pattern;
284   int pattern_len, inx, i;
285
286   if (waiting_response) {
287     fprintf(stderr, "%s: list widget requested recursively (ignored)\n",
288             PROGRAM_NAME);
289     return None;
290   }
291
292   if (appres.debug)
293     fprintf(stderr, "%s: list widget tree for window 0x%lx\n",
294             PROGRAM_NAME, (long)client);
295
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);
303   }
304
305   client_window = client;
306   effective_protocol_version = EDITRES_PROTOCOL_VERSION;
307   app_con = XtWidgetToApplicationContext(w);
308
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);
315   }
316   XtRemoveTimeOut(timer_id);
317
318   if (widget_list != NULL && strlen(name) != 0) {
319     pattern = name;
320     if (pattern[0] == '*') pattern = pattern + 1;
321     if (strchr(pattern, '*') != NULL)
322       fprintf(stderr, "%s: pattern should not include \"*\": %s\n",
323               PROGRAM_NAME, name);
324     pattern_len = strlen(pattern);
325     for (i = 0; i < num_widget_list; i++) {
326       if (appres.debug)
327         fprintf(stderr, "FindWidget: %s\n", widget_list[i].path);
328       inx = strlen(widget_list[i].path) - pattern_len;
329       if (0 <= inx) {
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;
333       }
334     }
335     if (i < num_widget_list) {
336       if (appres.debug)
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;
341     }
342   }
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",
347             PROGRAM_NAME, name);
348   }
349
350   return None;
351 }