1 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
2 /******************************************************************
3
4 Copyright (C) 1994-1995 Sun Microsystems, Inc.
5 Copyright (C) 1993-1994 Hewlett-Packard Company
6 Copyright (C) 2014 Peng Huang <shawn.p.huang@gmail.com>
7 Copyright (C) 2014 Red Hat, Inc.
8
9 Permission to use, copy, modify, distribute, and sell this software
10 and its documentation for any purpose is hereby granted without fee,
11 provided that the above copyright notice appear in all copies and
12 that both that copyright notice and this permission notice appear
13 in supporting documentation, and that the name of Sun Microsystems, Inc.
14 and Hewlett-Packard not be used in advertising or publicity pertaining to
15 distribution of the software without specific, written prior permission.
16 Sun Microsystems, Inc. and Hewlett-Packard make no representations about
17 the suitability of this software for any purpose. It is provided "as is"
18 without express or implied warranty.
19
20 SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
21 WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
22 WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
23 SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
24 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
25 RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
26 CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
27 IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28
29 Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
30
31 This version tidied and debugged by Steve Underwood May 1999
32
33 ******************************************************************/
34
35 #include "i18nX.h"
36 #include "FrameMgr.h"
37 #include "Xi18n.h"
38 #include "XimFunc.h"
39
40 extern Xi18nClient *_Xi18nFindClient (NimfXim *, CARD16);
41 extern Xi18nClient *_Xi18nNewClient (NimfXim *);
42 extern void _Xi18nDeleteClient (NimfXim *, CARD16);
43 extern unsigned long _Xi18nLookupPropertyOffset (Xi18nOffsetCache *, Atom);
44 extern void _Xi18nSetPropertyOffset (Xi18nOffsetCache *, Atom, unsigned long);
45
46 #define XCM_DATA_LIMIT 20
47
48 typedef struct _XClient
49 {
50 Window client_win; /* client window */
51 Window accept_win; /* accept window */
52 } XClient;
53
NewXClient(NimfXim * xim,Window new_client)54 static XClient *NewXClient (NimfXim *xim, Window new_client)
55 {
56 Xi18nClient *client = _Xi18nNewClient (xim);
57 XClient *x_client;
58
59 x_client = (XClient *) malloc (sizeof (XClient));
60 x_client->client_win = new_client;
61 x_client->accept_win = XCreateSimpleWindow (xim->display,
62 DefaultRootWindow (xim->display),
63 0, 0, 1, 1, 0, 0, 0);
64 client->trans_rec = x_client;
65 return ((XClient *) x_client);
66 }
67
ReadXIMMessage(NimfXim * xim,XClientMessageEvent * ev,int * connect_id)68 static unsigned char *ReadXIMMessage (NimfXim *xim,
69 XClientMessageEvent *ev,
70 int *connect_id)
71 {
72 Xi18nClient *client = xim->address.clients;
73 XClient *x_client = NULL;
74 FrameMgr fm;
75 extern XimFrameRec packet_header_fr[];
76 unsigned char *p = NULL;
77 unsigned char *p1;
78
79 while (client != NULL) {
80 x_client = (XClient *) client->trans_rec;
81 if (x_client->accept_win == ev->window) {
82 *connect_id = client->connect_id;
83 break;
84 }
85 client = client->next;
86 }
87
88 if (ev->format == 8) {
89 /* ClientMessage only */
90 XimProtoHdr *hdr = (XimProtoHdr *) ev->data.b;
91 unsigned char *rec = (unsigned char *) (hdr + 1);
92 register int total_size;
93 CARD8 major_opcode;
94 CARD8 minor_opcode;
95 CARD16 length;
96 extern int _Xi18nNeedSwap (NimfXim *, CARD16);
97
98 if (client->byte_order == '?')
99 {
100 if (hdr->major_opcode != XIM_CONNECT)
101 return (unsigned char *) NULL; /* can do nothing */
102 client->byte_order = (CARD8) rec[0];
103 }
104
105 fm = FrameMgrInit (packet_header_fr,
106 (char *) hdr,
107 _Xi18nNeedSwap (xim, *connect_id));
108 total_size = FrameMgrGetTotalSize (fm);
109 /* get data */
110 FrameMgrGetToken (fm, major_opcode);
111 FrameMgrGetToken (fm, minor_opcode);
112 FrameMgrGetToken (fm, length);
113 FrameMgrFree (fm);
114
115 if ((p = (unsigned char *) malloc (total_size + length * 4)) == NULL)
116 return (unsigned char *) NULL;
117
118 p1 = p;
119 memmove (p1, &major_opcode, sizeof (CARD8));
120 p1 += sizeof (CARD8);
121 memmove (p1, &minor_opcode, sizeof (CARD8));
122 p1 += sizeof (CARD8);
123 memmove (p1, &length, sizeof (CARD16));
124 p1 += sizeof (CARD16);
125 memmove (p1, rec, length * 4);
126 }
127 else if (ev->format == 32) {
128 /* ClientMessage and WindowProperty */
129 unsigned long length = (unsigned long) ev->data.l[0];
130 Atom atom = (Atom) ev->data.l[1];
131 int return_code;
132 Atom actual_type_ret;
133 int actual_format_ret;
134 unsigned long bytes_after_ret;
135 unsigned char *prop;
136 unsigned long nitems;
137 Xi18nOffsetCache *offset_cache = &client->offset_cache;
138 unsigned long offset;
139 unsigned long end;
140 unsigned long long_begin;
141 unsigned long long_end;
142
143 if (length == 0) {
144 fprintf (stderr, "%s: invalid length 0\n", __func__);
145 return NULL;
146 }
147
148 offset = _Xi18nLookupPropertyOffset (offset_cache, atom);
149 end = offset + length;
150
151 /* The property data is retrieved in 32-bit chunks */
152 long_begin = offset / 4;
153 long_end = (end + 3) / 4;
154 return_code = XGetWindowProperty (xim->display,
155 x_client->accept_win,
156 atom,
157 long_begin,
158 long_end - long_begin,
159 True,
160 AnyPropertyType,
161 &actual_type_ret,
162 &actual_format_ret,
163 &nitems,
164 &bytes_after_ret,
165 &prop);
166 if (return_code != Success || actual_format_ret == 0 || nitems == 0) {
167 if (return_code == Success)
168 XFree (prop);
169 fprintf (stderr,
170 "(XIM-IMdkit) ERROR: XGetWindowProperty failed.\n"
171 "Protocol data is likely to be inconsistent.\n");
172 _Xi18nSetPropertyOffset (offset_cache, atom, 0);
173 return (unsigned char *) NULL;
174 }
175 /* Update the offset to read next time as needed */
176 if (bytes_after_ret > 0)
177 _Xi18nSetPropertyOffset (offset_cache, atom, offset + length);
178 else
179 _Xi18nSetPropertyOffset (offset_cache, atom, 0);
180 /* if hit, it might be an error */
181 if ((p = (unsigned char *) malloc (length)) == NULL)
182 return (unsigned char *) NULL;
183
184 memcpy (p, prop + (offset % 4), length);
185 XFree (prop);
186 }
187 return (unsigned char *) p;
188 }
189
ReadXConnectMessage(NimfXim * xim,XClientMessageEvent * ev)190 void ReadXConnectMessage (NimfXim *xim, XClientMessageEvent *ev)
191 {
192 XEvent event;
193 Window new_client = ev->data.l[0];
194 CARD32 major_version = ev->data.l[1];
195 CARD32 minor_version = ev->data.l[2];
196 XClient *x_client = NewXClient (xim, new_client);
197
198 if (ev->window != xim->im_window)
199 return; /* incorrect connection request */
200
201 if (major_version != 0 || minor_version != 0)
202 {
203 major_version =
204 minor_version = 0;
205 /* Only supporting only-CM & Property-with-CM method */
206 }
207 /*endif*/
208 event.xclient.type = ClientMessage;
209 event.xclient.display = xim->display;
210 event.xclient.window = new_client;
211 event.xclient.message_type = xim->_xconnect;
212 event.xclient.format = 32;
213 event.xclient.data.l[0] = x_client->accept_win;
214 event.xclient.data.l[1] = major_version;
215 event.xclient.data.l[2] = minor_version;
216 event.xclient.data.l[3] = XCM_DATA_LIMIT;
217
218 XSendEvent (xim->display,
219 new_client,
220 False,
221 NoEventMask,
222 &event);
223 XFlush (xim->display);
224 }
225
MakeNewAtom(CARD16 connect_id,char * atomName)226 static char *MakeNewAtom (CARD16 connect_id, char *atomName)
227 {
228 static uint8_t sequence = 0;
229
230 sprintf (atomName,
231 "_server%d_%d",
232 connect_id,
233 ((sequence > 20) ? (sequence = 0) : (0x1f & sequence)));
234 sequence++;
235 return atomName;
236 }
237
Xi18nXSend(NimfXim * xim,CARD16 connect_id,unsigned char * reply,long length)238 Bool Xi18nXSend (NimfXim *xim,
239 CARD16 connect_id,
240 unsigned char *reply,
241 long length)
242 {
243 Xi18nClient *client = _Xi18nFindClient (xim, connect_id);
244 XClient *x_client = (XClient *) client->trans_rec;
245 XEvent event;
246
247 event.type = ClientMessage;
248 event.xclient.window = x_client->client_win;
249 event.xclient.message_type = xim->_protocol;
250
251 if (length > XCM_DATA_LIMIT)
252 {
253 Atom atom;
254 char atomName[16];
255 Atom actual_type_ret;
256 int actual_format_ret;
257 int return_code;
258 unsigned long nitems_ret;
259 unsigned long bytes_after_ret;
260 unsigned char *win_data;
261
262 event.xclient.format = 32;
263 atom = XInternAtom (xim->display,
264 MakeNewAtom (connect_id, atomName),
265 False);
266 return_code = XGetWindowProperty (xim->display,
267 x_client->client_win,
268 atom,
269 0L,
270 10000L,
271 False,
272 XA_STRING,
273 &actual_type_ret,
274 &actual_format_ret,
275 &nitems_ret,
276 &bytes_after_ret,
277 &win_data);
278 if (return_code != Success)
279 return False;
280 /*endif*/
281 if (win_data)
282 XFree ((char *) win_data);
283 /*endif*/
284 XChangeProperty (xim->display,
285 x_client->client_win,
286 atom,
287 XA_STRING,
288 8,
289 PropModeAppend,
290 (unsigned char *) reply,
291 length);
292 event.xclient.data.l[0] = length;
293 event.xclient.data.l[1] = atom;
294 }
295 else
296 {
297 unsigned char buffer[XCM_DATA_LIMIT];
298 int i;
299
300 event.xclient.format = 8;
301
302 /* Clear unused field with NULL */
303 memmove(buffer, reply, length);
304 for (i = length; i < XCM_DATA_LIMIT; i++)
305 buffer[i] = (char) 0;
306 /*endfor*/
307 length = XCM_DATA_LIMIT;
308 memmove (event.xclient.data.b, buffer, length);
309 }
310 XSendEvent (xim->display,
311 x_client->client_win,
312 False,
313 NoEventMask,
314 &event);
315 XFlush (xim->display);
316 return True;
317 }
318
CheckCMEvent(Display * display,XEvent * event,XPointer arg)319 static Bool CheckCMEvent (Display *display, XEvent *event, XPointer arg)
320 {
321 NimfXim *xim = NIMF_XIM (arg);
322
323 if ((event->type == ClientMessage) &&
324 (event->xclient.message_type == xim->_protocol))
325 return True;
326
327 return False;
328 }
329
Xi18nXWait(NimfXim * xim,CARD16 connect_id,CARD8 major_opcode,CARD8 minor_opcode)330 Bool Xi18nXWait (NimfXim *xim,
331 CARD16 connect_id,
332 CARD8 major_opcode,
333 CARD8 minor_opcode)
334 {
335 XEvent event;
336 Xi18nClient *client = _Xi18nFindClient (xim, connect_id);
337 XClient *x_client = (XClient *) client->trans_rec;
338
339 for (;;)
340 {
341 unsigned char *packet;
342 XimProtoHdr *hdr;
343 int connect_id_ret = 0;
344
345 XIfEvent (xim->display,
346 &event,
347 CheckCMEvent,
348 (XPointer) xim);
349 if (event.xclient.window == x_client->accept_win)
350 {
351 if ((packet = ReadXIMMessage (xim,
352 (XClientMessageEvent *) & event,
353 &connect_id_ret))
354 == (unsigned char*) NULL)
355 {
356 return False;
357 }
358 /*endif*/
359 hdr = (XimProtoHdr *)packet;
360
361 if ((hdr->major_opcode == major_opcode)
362 &&
363 (hdr->minor_opcode == minor_opcode))
364 {
365 XFree (packet);
366 return True;
367 }
368 else if (hdr->major_opcode == XIM_ERROR)
369 {
370 XFree (packet);
371 return False;
372 }
373
374 XFree (packet);
375 }
376 /*endif*/
377 }
378 /*endfor*/
379 }
380
Xi18nXDisconnect(NimfXim * xim,CARD16 connect_id)381 Bool Xi18nXDisconnect (NimfXim *xim, CARD16 connect_id)
382 {
383 Xi18nClient *client = _Xi18nFindClient (xim, connect_id);
384 XClient *x_client = (XClient *) client->trans_rec;
385
386 XDestroyWindow (xim->display, x_client->accept_win);
387 XFree (x_client);
388 _Xi18nDeleteClient (xim, connect_id);
389 return True;
390 }
391
WaitXIMProtocol(NimfXim * xim,XEvent * ev)392 Bool WaitXIMProtocol (NimfXim *xim,
393 XEvent *ev)
394 {
395 extern void _Xi18nMessageHandler (NimfXim *, CARD16, unsigned char *, Bool *);
396 Bool delete = True;
397 unsigned char *packet;
398 int connect_id = 0;
399
400 if (((XClientMessageEvent *) ev)->message_type
401 == xim->_protocol)
402 {
403 if ((packet = ReadXIMMessage (xim,
404 (XClientMessageEvent *) ev,
405 &connect_id))
406 == (unsigned char *) NULL)
407 {
408 return False;
409 }
410 /*endif*/
411 _Xi18nMessageHandler (xim, connect_id, packet, &delete);
412 if (delete == True)
413 XFree (packet);
414 /*endif*/
415 return True;
416 }
417 /*endif*/
418 return False;
419 }
420