0
|
1 /* Epoch functionality.
|
|
2 Copyright (C) 1985-1995 Free Software Foundation, Inc.
|
|
3 Copyright (C) 1996 Ben Wing.
|
|
4
|
|
5 This file is part of XEmacs.
|
|
6
|
|
7 XEmacs is free software; you can redistribute it and/or modify it
|
|
8 under the terms of the GNU General Public License as published by the
|
|
9 Free Software Foundation; either version 2, or (at your option) any
|
|
10 later version.
|
|
11
|
|
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
|
|
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
15 for more details.
|
|
16
|
|
17 You should have received a copy of the GNU General Public License
|
|
18 along with XEmacs; see the file COPYING. If not, write to
|
|
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
20 Boston, MA 02111-1307, USA. */
|
|
21
|
|
22 /* Synched up with: Not in FSF. */
|
|
23
|
|
24 #include <config.h>
|
|
25 #include "lisp.h"
|
|
26
|
|
27 #include "console-x.h"
|
|
28 #include "objects-x.h"
|
|
29 #include "events.h"
|
|
30 #include "frame.h"
|
|
31
|
|
32 Lisp_Object Qx_property_change, Qx_client_message, Qx_map, Qx_unmap;
|
|
33 Lisp_Object Vepoch_event, Vepoch_event_handler;
|
|
34
|
|
35
|
|
36 /************************************************************************/
|
|
37 /* X resources */
|
|
38 /************************************************************************/
|
|
39
|
|
40 Lisp_Object Qx_resource_live_p;
|
|
41
|
|
42 #define XX_RESOURCE(x) XRECORD (x, x_resource, struct Lisp_X_Resource)
|
|
43 #define XSETX_RESOURCE(x, p) XSETRECORD (x, p, x_resource)
|
|
44 #define X_RESOURCEP(x) RECORDP (x, x_resource)
|
|
45 #define GC_X_RESOURCEP(x) GC_RECORDP (x, x_resource)
|
|
46 #define CHECK_X_RESOURCE(x) CHECK_RECORD (x, x_resource)
|
|
47
|
|
48 #define X_RESOURCE_LIVE_P(xr) (DEVICE_LIVE_P (XDEVICE ((xr)->device)))
|
|
49 #define CHECK_LIVE_X_RESOURCE(x) \
|
|
50 do { CHECK_X_RESOURCE (x); \
|
|
51 if (!X_RESOURCE_LIVE_P (XX_RESOURCE (x))) \
|
|
52 x = wrong_type_argument (Qx_resource_live_p, (x)); \
|
|
53 } while (0)
|
|
54
|
|
55 struct Lisp_X_Resource
|
|
56 {
|
|
57 struct lcrecord_header header;
|
|
58
|
|
59 XID xid;
|
|
60 Atom type;
|
|
61 Lisp_Object device;
|
|
62 };
|
|
63
|
|
64 Lisp_Object Qx_resourcep;
|
|
65 static Lisp_Object mark_x_resource (Lisp_Object, void (*) (Lisp_Object));
|
|
66 static void print_x_resource (Lisp_Object, Lisp_Object, int);
|
|
67 static void finalize_x_resource (void *, int);
|
|
68 static int x_resource_equal (Lisp_Object o1, Lisp_Object o2, int depth);
|
|
69 static unsigned long x_resource_hash (Lisp_Object obj, int depth);
|
|
70 DEFINE_LRECORD_IMPLEMENTATION ("x-resource", x_resource,
|
|
71 mark_x_resource, print_x_resource,
|
|
72 finalize_x_resource, x_resource_equal,
|
|
73 x_resource_hash, struct Lisp_X_Resource);
|
|
74
|
|
75 static Lisp_Object
|
|
76 mark_x_resource (Lisp_Object obj, void (*markobj) (Lisp_Object))
|
|
77 {
|
|
78 return XX_RESOURCE (obj)->device;
|
|
79 }
|
|
80
|
|
81 static void
|
|
82 print_x_resource (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
|
|
83 {
|
|
84 char buf[100];
|
|
85 Bufbyte *default_string = "Resource";
|
|
86 Lisp_Object atom_symbol;
|
|
87 Lisp_Object device = XX_RESOURCE (obj)->device;
|
|
88
|
|
89 if (print_readably)
|
|
90 {
|
|
91 if (!DEVICE_LIVE_P (XDEVICE (device)))
|
|
92 error ("printing unreadable object #<dead x-resource>");
|
|
93 else
|
|
94 error ("printing unreadable object #<x-resource 0x%x>",
|
|
95 (unsigned int) XX_RESOURCE (obj)->xid);
|
|
96 }
|
|
97
|
|
98 if (!DEVICE_LIVE_P (XDEVICE (device)))
|
|
99 write_c_string ("#<dead x-resource>", printcharfun);
|
|
100 else
|
|
101 {
|
|
102 atom_symbol = x_atom_to_symbol (XDEVICE (device),
|
|
103 XX_RESOURCE (obj)->type);
|
|
104 sprintf (buf, "#<x-resource %s on ",
|
|
105 (NILP (atom_symbol)
|
|
106 ? default_string
|
|
107 : string_data (XSTRING (Fsymbol_name (atom_symbol)))));
|
|
108 write_c_string (buf, printcharfun);
|
|
109 print_internal (device, printcharfun, escapeflag);
|
|
110 sprintf (buf, " 0x%x>",(unsigned int) XX_RESOURCE (obj)->xid);
|
|
111 write_c_string (buf, printcharfun);
|
|
112 }
|
|
113 }
|
|
114
|
|
115 static void
|
|
116 finalize_x_resource (void *header, int for_disksave)
|
|
117 {
|
|
118 }
|
|
119
|
|
120 static int
|
|
121 x_resource_equal (Lisp_Object o1, Lisp_Object o2, int depth)
|
|
122 {
|
|
123 return (XX_RESOURCE (o1)->xid == XX_RESOURCE (o2)->xid &&
|
|
124 EQ (XX_RESOURCE (o1)->device, XX_RESOURCE (o2)->device));
|
|
125 }
|
|
126
|
|
127 static unsigned long
|
|
128 x_resource_hash (Lisp_Object obj, int depth)
|
|
129 {
|
|
130 return HASH2 (XX_RESOURCE (obj)->xid,
|
|
131 internal_hash (XX_RESOURCE (obj)->device, depth));
|
|
132 }
|
|
133
|
|
134 /*
|
|
135 * Epoch equivalent: epoch::resourcep
|
|
136 */
|
|
137 DEFUN ("x-resource-p", Fx_resource_p, Sx_resource_p, 1, 1, 0 /*
|
|
138 Return non-nil if OBJECT is an X resource object.
|
|
139 */ )
|
|
140 (object)
|
|
141 Lisp_Object object;
|
|
142 {
|
|
143 return (X_RESOURCEP (object) ? Qt : Qnil);
|
|
144 }
|
|
145
|
|
146 DEFUN ("x-resource-live-p", Fx_resource_live_p, Sx_resource_live_p, 1, 1, 0 /*
|
|
147 Return non-nil if OBJECT is a live X resource object.
|
|
148 That means that the X resource's device is live.
|
|
149 */ )
|
|
150 (object)
|
|
151 Lisp_Object object;
|
|
152 {
|
|
153 return (X_RESOURCEP (object) &&
|
|
154 X_RESOURCE_LIVE_P (XX_RESOURCE (object)) ? Qt : Qnil);
|
|
155 }
|
|
156
|
|
157 DEFUN ("x-resource-device", Fx_resource_device, Sx_resource_device, 1, 1, 0 /*
|
|
158 Return the device that OBJECT (an X resource object) exists on.
|
|
159 */ )
|
|
160 (object)
|
|
161 Lisp_Object object;
|
|
162 {
|
|
163 CHECK_LIVE_X_RESOURCE (object);
|
|
164 return XX_RESOURCE (object)->device;
|
|
165 }
|
|
166
|
|
167 /*
|
|
168 * Epoch equivalent: epoch::set-resource-type
|
|
169 */
|
|
170 DEFUN ("set-x-resource-type", Fset_x_resource_type, Sset_x_resource_type,
|
|
171 2, 2, 0 /*
|
|
172 Set the type of RESOURCE to TYPE. The new type must be an atom.
|
|
173 */ )
|
|
174 (resource, type)
|
|
175 Lisp_Object resource, type;
|
|
176 {
|
|
177 CHECK_LIVE_X_RESOURCE (resource);
|
|
178 CHECK_LIVE_X_RESOURCE (type);
|
|
179
|
|
180 if (XX_RESOURCE (type)->type != XA_ATOM)
|
|
181 error ("New type must be an atom");
|
|
182
|
|
183 XX_RESOURCE (resource)->type = XX_RESOURCE (type)->xid;
|
|
184 return resource;
|
|
185 }
|
|
186
|
|
187 static Lisp_Object
|
|
188 make_x_resource (XID xid, Atom type, Lisp_Object device)
|
|
189 {
|
|
190 struct Lisp_X_Resource *xr =
|
|
191 alloc_lcrecord (sizeof (struct Lisp_X_Resource), lrecord_x_resource);
|
|
192 Lisp_Object val;
|
|
193
|
|
194 xr->xid = xid;
|
|
195 xr->type = type;
|
|
196 xr->device = device;
|
|
197 XSETX_RESOURCE (val, xr);
|
|
198
|
|
199 return val;
|
|
200 }
|
|
201
|
|
202 static Lisp_Object
|
|
203 get_symbol_or_string_as_symbol (Lisp_Object name)
|
|
204 {
|
|
205 retry:
|
|
206 if (SYMBOLP (name))
|
|
207 return name;
|
|
208 else if (STRINGP (name))
|
|
209 return Fintern (name, Qnil);
|
|
210 else
|
|
211 {
|
|
212 signal_simple_continuable_error ("Must be symbol or string",
|
|
213 name);
|
|
214 goto retry;
|
|
215 }
|
|
216 return Qnil; /* not reached */
|
|
217 }
|
|
218
|
|
219 /*
|
|
220 * Epoch equivalent: epoch::intern-atom
|
|
221 */
|
|
222 DEFUN ("x-intern-atom", Fx_intern_atom, Sx_intern_atom, 1, 2, 0 /*
|
|
223 Convert a string or symbol into an atom and return as an X resource.
|
|
224 Optional argument DEVICE specifies the display connection and defaults
|
|
225 to the selected device.
|
|
226 */ )
|
|
227 (name, device)
|
|
228 Lisp_Object name, device;
|
|
229 {
|
|
230 Atom atom;
|
|
231 struct device *d = decode_x_device (device);
|
|
232
|
|
233 XSETDEVICE (device, d);
|
|
234 atom = symbol_to_x_atom (d, get_symbol_or_string_as_symbol (name), 0);
|
|
235 return make_x_resource (atom, XA_ATOM, device);
|
|
236 }
|
|
237
|
|
238 /*
|
|
239 * Epoch equivalent: epoch::unintern-atom
|
|
240 */
|
|
241 DEFUN ("x-atom-name", Fx_atom_name, Sx_atom_name, 1, 1, 0 /*
|
|
242 Return the name of an X atom resource as a string.
|
|
243 */ )
|
|
244 (atom)
|
|
245 Lisp_Object atom;
|
|
246 {
|
|
247 Lisp_Object val;
|
|
248
|
|
249 CHECK_LIVE_X_RESOURCE (atom);
|
|
250 if (XX_RESOURCE (atom)->type != XA_ATOM)
|
|
251 signal_simple_error ("Resource is not an atom", atom);
|
|
252
|
|
253 val = x_atom_to_symbol (XDEVICE (XX_RESOURCE (atom)->device),
|
|
254 XX_RESOURCE (atom)->xid);
|
|
255 if (NILP (val))
|
|
256 return Qnil;
|
|
257 return Fsymbol_name (val);
|
|
258 }
|
|
259
|
|
260 /*
|
|
261 * Epoch equivalent: epoch::string-to-resource
|
|
262 */
|
|
263 DEFUN ("string-to-x-resource", Fstring_to_x_resource,
|
|
264 Sstring_to_x_resource, 2, 3, 0 /*
|
|
265 Convert a numeric STRING to an X-RESOURCE.
|
|
266 STRING is assumed to represent a 32-bit numer value. X-RESOURCE must be
|
|
267 an X atom. Optional BASE argument should be a number between 2 and 36,
|
|
268 specifying the base for converting STRING.
|
|
269 */ )
|
|
270 (string, type, base)
|
|
271 Lisp_Object string, type, base;
|
|
272 {
|
|
273 XID xid;
|
|
274 struct Lisp_X_Resource *xr;
|
|
275 char *ptr;
|
|
276 int b;
|
|
277
|
|
278 CHECK_STRING (string);
|
|
279 CHECK_LIVE_X_RESOURCE (type);
|
|
280
|
|
281 if (NILP (base))
|
|
282 b = 0;
|
|
283 else
|
|
284 {
|
|
285 CHECK_INT (base);
|
|
286 b = XINT (base);
|
|
287 check_int_range (b, 2, 36);
|
|
288 }
|
|
289
|
|
290 if (XX_RESOURCE (type)->type != XA_ATOM)
|
|
291 error ("Resource must be an atom");
|
|
292 xr = XX_RESOURCE (type);
|
|
293
|
|
294 xid = (XID) strtol ((CONST char *) string_data (XSTRING (string)), &ptr, b);
|
|
295
|
|
296 return ((ptr == (char *) string_data (XSTRING (string)))
|
|
297 ? Qnil
|
|
298 : make_x_resource (xid, xr->xid, xr->device));
|
|
299 }
|
|
300
|
|
301 /*
|
|
302 * Epoch equivalent: epoch::resource-to-type
|
|
303 */
|
|
304 DEFUN ("x-resource-to-type", Fx_resource_to_type, Sx_resource_to_type,
|
|
305 1, 1, 0 /*
|
|
306 Return an x-resource of type ATOM whose value is the type of the argument
|
|
307 */ )
|
|
308 (resource)
|
|
309 Lisp_Object resource;
|
|
310 {
|
|
311 struct Lisp_X_Resource *xr;
|
|
312
|
|
313 CHECK_LIVE_X_RESOURCE (resource);
|
|
314 xr = XX_RESOURCE (resource);
|
|
315
|
|
316 return make_x_resource (xr->type, XA_ATOM, xr->device);
|
|
317 }
|
|
318
|
|
319 /* internal crap stolen from Epoch */
|
|
320 static char LongToStringBuffer[33]; /* can't have statics inside functions! */
|
|
321 static char *
|
|
322 long_to_string (unsigned long n, unsigned int base)
|
|
323 {
|
|
324 char *digit = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
325 char *s = LongToStringBuffer + 32; /* at most 33 characters in binary */
|
|
326
|
|
327 *s = 0; /* terminate */
|
|
328 while (n) /* something there */
|
|
329 {
|
|
330 *--s = digit[n % base]; /* store bottom digit */
|
|
331 n /= base; /* shift right */
|
|
332 }
|
|
333 if (*s == 0) *--s = '0'; /* in case nothing was put in string */
|
|
334 return s;
|
|
335 }
|
|
336
|
|
337 /*
|
|
338 * Epoch equivalent: epoch::resource-to-string
|
|
339 */
|
|
340 DEFUN ("x-resource-to-string", Fx_resource_to_string, Sx_resource_to_string,
|
|
341 1, 2, 0 /*
|
|
342 Convert the xid of RESOURCE to a numeric string.
|
|
343 Optional BASE specifies the base for the conversion (2..36 inclusive)
|
|
344 */ )
|
|
345 (resource, base)
|
|
346 Lisp_Object resource, base;
|
|
347 {
|
|
348 int cbase = 10;
|
|
349
|
|
350 CHECK_LIVE_X_RESOURCE (resource);
|
|
351 if (!NILP (base))
|
|
352 {
|
|
353 CHECK_INT (base);
|
|
354 cbase = XINT (base);
|
|
355 check_int_range (cbase, 2, 36);
|
|
356 }
|
|
357
|
|
358 return build_string (long_to_string (XX_RESOURCE (resource)->xid, cbase));
|
|
359 }
|
|
360
|
|
361 /*
|
|
362 * Epoch equivalent: epoch::xid-of-frame
|
|
363 */
|
|
364 DEFUN ("x-id-of-frame", Fx_id_of_frame, Sx_id_of_frame, 0, 1, 0 /*
|
|
365 Return the window ID of FRAME as an x-resource.
|
|
366 This differs from `x-window-id' in that its return value is an
|
|
367 x-resource rather than a string.
|
|
368 */ )
|
|
369 (frame)
|
|
370 Lisp_Object frame;
|
|
371 {
|
|
372 struct frame *f = decode_x_frame (frame);
|
|
373
|
|
374 return make_x_resource (XtWindow (FRAME_X_SHELL_WIDGET (f)), XA_WINDOW,
|
|
375 FRAME_DEVICE (f));
|
|
376 }
|
|
377
|
|
378 /* Given a frame or ID X resource, return the X window and device
|
|
379 it refers to. If text_p is non-zero, the window returned corresponds
|
|
380 to the text widget of the frame rather than the shell widget. */
|
|
381
|
|
382 static void
|
|
383 epoch_get_window_and_device (Lisp_Object frame, Window *window,
|
|
384 Lisp_Object *device, int text_p)
|
|
385 {
|
|
386 if (X_RESOURCEP (frame))
|
|
387 {
|
|
388 CHECK_LIVE_X_RESOURCE (frame);
|
|
389 if (XX_RESOURCE (frame)->type != XA_WINDOW)
|
|
390 error ("Frame resource must be of type WINDOW");
|
|
391 *window = XX_RESOURCE (frame)->xid;
|
|
392 *device = XX_RESOURCE (frame)->device;
|
|
393 }
|
|
394 else
|
|
395 {
|
|
396 struct frame *f = decode_x_frame (frame);
|
|
397
|
|
398 XSETFRAME (frame, f);
|
|
399 if (text_p)
|
|
400 *window = XtWindow (FRAME_X_TEXT_WIDGET (f));
|
|
401 else
|
|
402 *window = XX_RESOURCE (Fx_id_of_frame (frame))->xid;
|
|
403 *device = FRAME_DEVICE (f);
|
|
404 }
|
|
405
|
|
406 }
|
|
407
|
|
408 /*
|
|
409 * Epoch equivalent: epoch::query-tree
|
|
410 */
|
|
411 DEFUN ("x-query-tree", Fx_query_tree, Sx_query_tree, 0, 1, 0 /*
|
|
412 Return the portion of the window tree adjacent to FRAME.
|
|
413 Return value is the list ( ROOT PARENT . CHILDREN ). The FRAME arg
|
|
414 can either be a frame object or an x-resource of type window.
|
|
415 */ )
|
|
416 (frame)
|
|
417 Lisp_Object frame;
|
|
418 {
|
|
419 Window win;
|
|
420 Window root, parent, *children;
|
|
421 unsigned int count;
|
|
422 int retval;
|
|
423 Lisp_Object val;
|
|
424 Lisp_Object device;
|
|
425
|
|
426 epoch_get_window_and_device (frame, &win, &device, 0);
|
|
427
|
|
428 retval =
|
|
429 XQueryTree (DEVICE_X_DISPLAY (XDEVICE (device)), win, &root, &parent,
|
|
430 &children, &count);
|
|
431
|
|
432 /* Thank you, X-Consortium. XQueryTree doesn't return Success like everyone
|
|
433 * else, it returns 1. (Success is defined to be 0 in the standard header
|
|
434 * files)
|
|
435 */
|
|
436 if (!retval) return Qnil;
|
|
437
|
|
438 val = Qnil;
|
|
439 while (count)
|
|
440 val = Fcons (make_x_resource (children[--count], XA_WINDOW, device), val);
|
|
441
|
|
442 XFree (children);
|
|
443
|
|
444 return Fcons (make_x_resource (root, XA_WINDOW, device),
|
|
445 Fcons ((parent
|
|
446 ? make_x_resource (parent, XA_WINDOW, device)
|
|
447 : Qnil),
|
|
448 val));
|
|
449 }
|
|
450
|
|
451 /* more internal crap stolen from Epoch */
|
|
452
|
|
453 static void
|
|
454 verify_vector_has_consistent_type (Lisp_Object vector)
|
|
455 {
|
|
456 int i; /* vector index */
|
|
457 XID rtype; /* X_resource type (if vector of
|
|
458 X_resources) */
|
|
459 int length; /* vector length */
|
|
460 struct Lisp_Vector *v = XVECTOR (vector);
|
|
461 Lisp_Object *element;
|
|
462 Lisp_Object sample;
|
|
463 Lisp_Object type_obj; /* base type of vector elements */
|
|
464 Lisp_Object device;
|
|
465
|
|
466 sample = v->contents[0];
|
|
467 type_obj = sample;
|
|
468 if (X_RESOURCEP (sample))
|
|
469 {
|
|
470 CHECK_LIVE_X_RESOURCE (sample);
|
|
471 rtype = XX_RESOURCE (sample)->type;
|
|
472 device = XX_RESOURCE (sample)->device;
|
|
473 }
|
|
474 length = v->size;
|
|
475 element = v->contents;
|
|
476
|
|
477 for (i = 1; i < length; ++i, ++element)
|
|
478 {
|
|
479 QUIT;
|
|
480 if (X_RESOURCEP (type_obj))
|
|
481 CHECK_LIVE_X_RESOURCE (type_obj);
|
|
482 if ((XTYPE (*element) != XTYPE (type_obj))
|
|
483 || (LRECORDP (type_obj) &&
|
|
484 (XRECORD_LHEADER (*element)->implementation !=
|
|
485 XRECORD_LHEADER (type_obj)->implementation))
|
|
486 || (X_RESOURCEP (type_obj) &&
|
|
487 (rtype != XX_RESOURCE (*element)->type
|
|
488 || !EQ (device, XX_RESOURCE (*element)->device))))
|
|
489 error ("Vector has inconsistent types");
|
|
490 }
|
|
491 }
|
|
492
|
|
493 static void
|
|
494 verify_list_has_consistent_type (Lisp_Object list)
|
|
495 {
|
|
496 Lisp_Object type_obj;
|
|
497 XID rtype; /* X_resource type (if vector of
|
|
498 X_resources) */
|
|
499 Lisp_Object temp = Fcar (list);
|
|
500 Lisp_Object device;
|
|
501
|
|
502 type_obj = temp;
|
|
503 if (X_RESOURCEP (temp))
|
|
504 {
|
|
505 CHECK_LIVE_X_RESOURCE (temp);
|
|
506 rtype = XX_RESOURCE (temp)->type;
|
|
507 device = XX_RESOURCE (temp)->device;
|
|
508 }
|
|
509 list = Fcdr (list);
|
|
510
|
|
511 for ( ; !NILP (list) ; list = Fcdr (list))
|
|
512 {
|
|
513 QUIT;
|
|
514 temp = Fcar (list);
|
|
515 if (X_RESOURCEP (temp))
|
|
516 CHECK_LIVE_X_RESOURCE (temp);
|
|
517 if ((XTYPE (temp) != XTYPE (type_obj))
|
|
518 || (LRECORDP (type_obj) &&
|
|
519 (XRECORD_LHEADER (temp)->implementation !=
|
|
520 XRECORD_LHEADER (type_obj)->implementation))
|
|
521 || (X_RESOURCEP (type_obj) &&
|
|
522 (rtype != XX_RESOURCE (temp)->type
|
|
523 || !EQ (device, XX_RESOURCE (temp)->device))))
|
|
524 error ("List has inconsistent types");
|
|
525 }
|
|
526 }
|
|
527
|
|
528 #define BYTESIZE 8
|
|
529 /* 16 bit types */
|
|
530 typedef short int int16;
|
|
531 typedef short unsigned int uint16;
|
|
532
|
|
533 /* the Calculate functions return allocated memory that must be free'd.
|
|
534 I tried to use alloca, but that fails. Sigh.
|
|
535 */
|
|
536 static void *
|
|
537 calculate_vector_property (Lisp_Object vector, unsigned long *count,
|
|
538 Atom *type, int *format)
|
|
539 {
|
|
540 /* !!#### This function has not been Mule-ized */
|
|
541 int length;
|
|
542 unsigned int size,tsize;
|
|
543 int i;
|
|
544 struct Lisp_Vector *v;
|
|
545 void *addr;
|
|
546
|
|
547 v = XVECTOR (vector);
|
|
548 *count = length = v->size;
|
|
549
|
|
550 switch (XTYPE (v->contents[0]))
|
|
551 {
|
|
552 case Lisp_Int:
|
|
553 *type = XA_INTEGER;
|
|
554 if (*format != 8 && *format != 16) *format = 32;
|
|
555 size = *format * length;
|
|
556 addr = (void *) xmalloc (size);
|
|
557 for ( i = 0 ; i < length ; ++i )
|
|
558 switch (*format)
|
|
559 {
|
|
560 case 32 :
|
|
561 ((int *)addr)[i] = XINT (v->contents[i]);
|
|
562 break;
|
|
563 case 16 :
|
|
564 ((int16 *)addr)[i] = XINT (v->contents[i]);
|
|
565 break;
|
|
566 case 8 :
|
|
567 ((char *)addr)[i] = XINT (v->contents[i]);
|
|
568 break;
|
|
569 }
|
|
570 break;
|
|
571
|
|
572 case Lisp_Record:
|
|
573 if (X_RESOURCEP (v->contents[0]))
|
|
574 {
|
|
575 CHECK_LIVE_X_RESOURCE (v->contents[0]);
|
|
576 size = BYTESIZE * sizeof (XID) * length;
|
|
577 *format = BYTESIZE * sizeof (XID);
|
|
578 *type = XX_RESOURCE (v->contents[0])->type;
|
|
579 addr = (void *) xmalloc (size);
|
|
580 for ( i = 0 ; i < length ; ++i )
|
|
581 ( (XID *) addr) [i] = XX_RESOURCE (v->contents[i])->xid;
|
|
582 }
|
|
583 break;
|
|
584
|
|
585 case Lisp_String:
|
|
586 *format = BYTESIZE * sizeof (char);
|
|
587 *type = XA_STRING;
|
|
588 for ( i=0, size=0 ; i < length ; ++i )
|
|
589 size += (string_length (XSTRING (v->contents[i])) +
|
|
590 1); /* include null */
|
|
591 addr = (void *) xmalloc (size);
|
|
592 *count = size;
|
|
593 for ( i = 0 , size = 0 ; i < length ; ++i )
|
|
594 {
|
|
595 tsize = string_length (XSTRING (v->contents[i])) + 1;
|
|
596 memmove (((char *) addr), string_data (XSTRING (v->contents[i])),
|
|
597 tsize);
|
|
598 size += tsize;
|
|
599 }
|
|
600 break;
|
|
601
|
|
602 default:
|
|
603 error ("Invalid type for conversion");
|
|
604 }
|
|
605 return addr;
|
|
606 }
|
|
607
|
|
608 static void *
|
|
609 calculate_list_property (Lisp_Object list, unsigned long *count,
|
|
610 Atom *type, int *format)
|
|
611 {
|
|
612 /* !!#### This function has not been Mule-ized */
|
|
613 int length;
|
|
614 unsigned int size, tsize;
|
|
615 int i;
|
|
616 Lisp_Object tlist,temp;
|
|
617 void *addr;
|
|
618
|
|
619 *count = length = XINT (Flength (list));
|
|
620
|
|
621 switch (XTYPE (Fcar (list)))
|
|
622 {
|
|
623 case Lisp_Int:
|
|
624 *type = XA_INTEGER;
|
|
625 if (*format != 8 && *format != 16) *format = 32;
|
|
626 size = *format * length;
|
|
627 addr = (void *) xmalloc (size);
|
|
628 for ( i = 0 ; i < length ; ++i, list = Fcdr (list))
|
|
629 switch (*format)
|
|
630 {
|
|
631 case 32 : ((int *)addr)[i] = XINT (Fcar (list)); break;
|
|
632 case 16 : ((int16 *)addr)[i] = XINT (Fcar (list)); break;
|
|
633 case 8 : ((char *)addr)[i] = XINT (Fcar (list)); break;
|
|
634 }
|
|
635 break;
|
|
636
|
|
637 case Lisp_Record:
|
|
638 if (X_RESOURCEP (Fcar (list)))
|
|
639 {
|
|
640 Lisp_Object car = Fcar (list);
|
|
641 CHECK_LIVE_X_RESOURCE (car);
|
|
642 size = BYTESIZE * sizeof (XID) * length;
|
|
643 *format = BYTESIZE * sizeof (XID);
|
|
644 *type = XX_RESOURCE (Fcar (list))->type;
|
|
645 addr = (void *) xmalloc (size);
|
|
646 for ( i = 0 ; i < length ; ++i, list = Fcdr (list))
|
|
647 {
|
|
648 Lisp_Object carr = Fcar (list);
|
|
649 CHECK_LIVE_X_RESOURCE (carr);
|
|
650 ((XID *)addr)[i] = XX_RESOURCE (carr)->xid;
|
|
651 }
|
|
652 }
|
|
653 break;
|
|
654
|
|
655 case Lisp_String:
|
|
656 *format = BYTESIZE * sizeof (char);
|
|
657 *type = XA_STRING;
|
|
658 for ( i=0, size=0 , tlist=list ; i < length ; ++i, tlist = Fcdr (tlist) )
|
|
659 size += string_length (XSTRING (Fcar (tlist))) + 1; /* include null */
|
|
660 addr = (void *) xmalloc (size);
|
|
661 *count = size;
|
|
662 for ( i=0, size=0, tlist=list ; i < length ;
|
|
663 ++i , tlist = Fcdr (tlist) )
|
|
664 {
|
|
665 temp = Fcar (tlist);
|
|
666 tsize = string_length (XSTRING (temp)) + 1;
|
|
667 memmove (((char *) addr), string_data (XSTRING (temp)), tsize);
|
|
668 size += tsize;
|
|
669 }
|
|
670 break;
|
|
671
|
|
672 default:
|
|
673 error ("Invalid type for conversion");
|
|
674 }
|
|
675 return addr;
|
|
676 }
|
|
677
|
|
678 /* Returns whether the conversion was successful or not */
|
|
679 static int
|
|
680 convert_elisp_to_x (Lisp_Object value, void **addr, unsigned long *count,
|
|
681 Atom *type, int *format, int *free_storage)
|
|
682 {
|
|
683 /* !!#### This function has not been Mule-ized */
|
|
684 if (VECTORP (value))
|
|
685 verify_vector_has_consistent_type (value);
|
|
686 else if (CONSP (value))
|
|
687 verify_list_has_consistent_type (value);
|
|
688
|
|
689 *free_storage = 0;
|
|
690 switch (XTYPE (value))
|
|
691 {
|
|
692 case Lisp_String:
|
|
693 *format = BYTESIZE;
|
|
694 *type = XA_STRING;
|
|
695 *count = strlen ((CONST char *) string_data (XSTRING (value))) + 1;
|
|
696 *addr = (void *) string_data (XSTRING (value));
|
|
697 break;
|
|
698
|
|
699 case Lisp_Int:
|
|
700 *type = XA_INTEGER;
|
|
701 *count = 1;
|
|
702 *free_storage = 1;
|
|
703 *addr = (void *) xmalloc (sizeof (int));
|
|
704 /* This is ugly -
|
|
705 * we have to deal with the possibility of different formats
|
|
706 */
|
|
707 switch (*format)
|
|
708 {
|
|
709 default :
|
|
710 case 32 :
|
|
711 *format = 32;
|
|
712 *((int *)(*addr)) = XINT (value);
|
|
713 break;
|
|
714 case 16 :
|
|
715 *((int16 *)(*addr)) = XINT (value);
|
|
716 break;
|
|
717 case 8 :
|
|
718 *((char *)(*addr)) = XINT (value);
|
|
719 break;
|
|
720 }
|
|
721 break;
|
|
722
|
|
723 case Lisp_Record:
|
|
724 if (X_RESOURCEP (value))
|
|
725 {
|
|
726 CHECK_LIVE_X_RESOURCE (value);
|
|
727 *format = sizeof (XID) * BYTESIZE;
|
|
728 *type = XX_RESOURCE (value)->type;
|
|
729 *count = 1;
|
|
730 *addr = (void *) & (XX_RESOURCE (value)->xid);
|
|
731 }
|
|
732 break;
|
|
733
|
|
734 case Lisp_Cons:
|
|
735 *addr = calculate_list_property (value, count, type, format);
|
|
736 *free_storage = 1; /* above allocates storage */
|
|
737 break;
|
|
738
|
|
739 case Lisp_Vector:
|
|
740 *addr = calculate_vector_property (value, count, type, format);
|
|
741 *free_storage = 1; /* above allocates storage */
|
|
742 break;
|
|
743
|
|
744 default :
|
|
745 error ("Improper type for conversion");
|
|
746 }
|
|
747
|
|
748 return 1;
|
|
749 }
|
|
750
|
|
751 static Lisp_Object
|
|
752 format_size_hints (XSizeHints *hints)
|
|
753 {
|
|
754 Lisp_Object result;
|
|
755 struct Lisp_Vector *v;
|
|
756
|
|
757 result = Fmake_vector (make_int (6), Qnil);
|
|
758 v = XVECTOR (result);
|
|
759
|
|
760 /* ugly but straightforward - just step through the members and flags
|
|
761 * and stick in the ones that are there
|
|
762 */
|
|
763 if (hints->flags & (PPosition|USPosition))
|
|
764 v->contents[0] = Fcons (make_int (hints->x), make_int (hints->y));
|
|
765 if (hints->flags & (PSize|USSize))
|
|
766 v->contents[1] = Fcons (make_int (hints->width),
|
|
767 make_int (hints->height));
|
|
768 if (hints->flags & PMinSize)
|
|
769 v->contents[2] = Fcons (make_int (hints->min_width),
|
|
770 make_int (hints->min_height));
|
|
771 if (hints->flags & PMaxSize)
|
|
772 v->contents[3] = Fcons (make_int (hints->max_width),
|
|
773 make_int (hints->max_height));
|
|
774 if (hints->flags & PResizeInc)
|
|
775 v->contents[4] = Fcons (make_int (hints->width_inc),
|
|
776 make_int (hints->height_inc));
|
|
777 if (hints->flags & PAspect)
|
|
778 v->contents[5] = Fcons (make_int (hints->min_aspect.x),
|
|
779 Fcons (make_int (hints->min_aspect.y),
|
|
780 Fcons (make_int (hints->max_aspect.x),
|
|
781 make_int (hints->max_aspect.y))));
|
|
782
|
|
783 return result;
|
|
784 }
|
|
785
|
|
786 static Lisp_Object
|
|
787 format_string_property (char *buffer, unsigned long count)
|
|
788 {
|
|
789 /* !!#### This function has not been Mule-ized */
|
|
790 Lisp_Object value = Qnil; /* data */
|
|
791 Lisp_Object temp; /* temp value holder */
|
|
792 int len; /* length of current string */
|
|
793 char *strend;
|
|
794
|
|
795 while (count)
|
|
796 {
|
|
797 strend = memchr (buffer, 0, (int) count);
|
|
798 len = strend ? strend - buffer : count;
|
|
799 if (len)
|
|
800 {
|
|
801 temp = make_string ((Bufbyte *) buffer, len);
|
|
802 value = Fcons (temp, value);
|
|
803 }
|
|
804 buffer = strend + 1; /* skip null, or leaving loop if no null */
|
|
805 count -= len + !!strend;
|
|
806 }
|
|
807
|
|
808 return (NILP (Fcdr (value))
|
|
809 ? Fcar (value)
|
|
810 : Fnreverse (value));
|
|
811 }
|
|
812
|
|
813 static Lisp_Object
|
|
814 format_integer_32_property (long *buff, unsigned long count)
|
|
815 {
|
|
816 Lisp_Object value = Qnil; /* return value */
|
|
817 while (count)
|
|
818 value = Fcons (make_int (buff[--count]), value);
|
|
819
|
|
820 return (NILP (Fcdr (value))
|
|
821 ? Fcar (value)
|
|
822 : value);
|
|
823 }
|
|
824
|
|
825 static Lisp_Object
|
|
826 format_integer_16_property (int16 *buff, unsigned long count)
|
|
827 {
|
|
828 Lisp_Object value = Qnil; /* return value */
|
|
829
|
|
830 while (count)
|
|
831 value = Fcons (make_int (buff[--count]), value);
|
|
832
|
|
833 return (NILP (Fcdr (value))
|
|
834 ? Fcar (value)
|
|
835 : value);
|
|
836 }
|
|
837
|
|
838 static Lisp_Object
|
|
839 format_integer_8_property (char *buff, unsigned long count)
|
|
840 {
|
|
841 Lisp_Object value = Qnil; /* return value */
|
|
842
|
|
843 while (count)
|
|
844 value = Fcons (make_int (buff[--count]), value);
|
|
845
|
|
846 return (NILP (Fcdr (value))
|
|
847 ? Fcar (value)
|
|
848 : value);
|
|
849 }
|
|
850
|
|
851 static Lisp_Object
|
|
852 format_integer_property (void *buff, unsigned long count, int format)
|
|
853 {
|
|
854 switch (format)
|
|
855 {
|
|
856 case 8:
|
|
857 return format_integer_8_property ((char *) buff, count);
|
|
858 break;
|
|
859 case 16:
|
|
860 return format_integer_16_property ((int16 *) buff, count);
|
|
861 break;
|
|
862 case 32:
|
|
863 return format_integer_32_property ((long *) buff, count);
|
|
864 break;
|
|
865 default:
|
|
866 return Qnil;
|
|
867 }
|
|
868 }
|
|
869
|
|
870 static Lisp_Object
|
|
871 format_cardinal_32_property (unsigned long *buff, unsigned long count)
|
|
872 {
|
|
873 Lisp_Object value = Qnil; /* return value */
|
|
874
|
|
875 while (count)
|
|
876 value = Fcons (make_int (buff[--count]), value);
|
|
877
|
|
878 return (NILP (Fcdr (value))
|
|
879 ? Fcar (value)
|
|
880 : value);
|
|
881 }
|
|
882
|
|
883 static Lisp_Object
|
|
884 format_cardinal_16_property (uint16 *buff, unsigned long count)
|
|
885 {
|
|
886 Lisp_Object value = Qnil; /* return value */
|
|
887
|
|
888 while (count)
|
|
889 value = Fcons (make_int (buff[--count]), value);
|
|
890
|
|
891 return (NILP (Fcdr (value))
|
|
892 ? Fcar (value)
|
|
893 : value);
|
|
894 }
|
|
895
|
|
896 static Lisp_Object
|
|
897 format_cardinal_8_property (unsigned char *buff, unsigned long count)
|
|
898 {
|
|
899 Lisp_Object value = Qnil; /* return value */
|
|
900
|
|
901 while (count)
|
|
902 value = Fcons (make_int (buff[--count]), value);
|
|
903
|
|
904 return (NILP (Fcdr (value))
|
|
905 ? Fcar (value)
|
|
906 : value);
|
|
907 }
|
|
908
|
|
909 static Lisp_Object
|
|
910 format_cardinal_property (void *buff, unsigned long count, int format)
|
|
911 {
|
|
912 switch (format)
|
|
913 {
|
|
914 case 8:
|
|
915 return format_cardinal_8_property ((unsigned char *) buff, count);
|
|
916 break;
|
|
917 case 16:
|
|
918 return format_cardinal_16_property ((uint16 *) buff, count);
|
|
919 break;
|
|
920 case 32:
|
|
921 return format_cardinal_32_property ((unsigned long *) buff, count);
|
|
922 default:
|
|
923 return Qnil;
|
|
924 }
|
|
925 }
|
|
926
|
|
927 static Lisp_Object
|
|
928 format_unknown_property (struct device *d, void *buff, unsigned long count,
|
|
929 Atom type, int format)
|
|
930 {
|
|
931 Lisp_Object value = Qnil; /* return value */
|
|
932 Lisp_Object device = Qnil;
|
|
933
|
|
934 XSETDEVICE (device, d);
|
|
935
|
|
936 switch (format)
|
|
937 {
|
|
938 case 32:
|
|
939 {
|
|
940 XID *xid = (XID *) buff;
|
|
941 int non_zero = 0;
|
|
942 while (count--)
|
|
943 if (non_zero || xid[count])
|
|
944 {
|
|
945 value = Fcons (make_x_resource (xid[count], type, device),
|
|
946 value);
|
|
947 non_zero = 1;
|
|
948 }
|
|
949 }
|
|
950 break;
|
|
951 }
|
|
952
|
|
953 return (NILP (Fcdr (value))
|
|
954 ? Fcar (value)
|
|
955 : value);
|
|
956 }
|
|
957
|
|
958 static Lisp_Object
|
|
959 convert_x_to_elisp (struct device *d, void *buffer, unsigned long count,
|
|
960 Atom type, int format)
|
|
961 {
|
|
962 /* !!#### This function has not been Mule-ized */
|
|
963 Lisp_Object value = Qnil;
|
|
964
|
|
965 switch (type)
|
|
966 {
|
|
967 case None:
|
|
968 value = Qnil;
|
|
969 break;
|
|
970 case XA_STRING:
|
|
971 value = format_string_property (buffer, count);
|
|
972 break;
|
|
973 case XA_INTEGER:
|
|
974 value = format_integer_property ((long *) buffer, count, format);
|
|
975 break;
|
|
976 case XA_CARDINAL:
|
|
977 value = format_cardinal_property ((unsigned long *) buffer,
|
|
978 count, format);
|
|
979 break;
|
|
980 case XA_WM_SIZE_HINTS:
|
|
981 value = format_size_hints ((XSizeHints *) buffer);
|
|
982 break;
|
|
983 default:
|
|
984 value = format_unknown_property (d, (void *) buffer, count, type,
|
|
985 format);
|
|
986 break;
|
|
987 }
|
|
988
|
|
989 return value;
|
|
990 }
|
|
991
|
|
992 /* get a property given its atom, device, and window */
|
|
993 static Lisp_Object
|
|
994 raw_get_property (struct device *d, Window win, Atom prop)
|
|
995 {
|
|
996 /* !!#### This function has not been Mule-ized */
|
|
997 Lisp_Object value = Qnil;
|
|
998 Atom actual_type;
|
|
999 int actual_format;
|
|
1000 unsigned char *buffer;
|
|
1001 unsigned long count, remaining;
|
|
1002 int zret;
|
|
1003 Display *dpy = DEVICE_X_DISPLAY (d);
|
|
1004
|
|
1005 zret = XGetWindowProperty (dpy, win, prop,
|
|
1006 0L, 1024L, False, AnyPropertyType,
|
|
1007 &actual_type, &actual_format,
|
|
1008 &count, &remaining, &buffer);
|
|
1009
|
|
1010 /* If remaining is set, then there's more of the property to get.
|
|
1011 Let's just do the whole read again, this time with enough space
|
|
1012 to get it all. */
|
|
1013 if (zret == Success && remaining > 0)
|
|
1014 {
|
|
1015 XFree (buffer);
|
|
1016 zret = XGetWindowProperty (dpy, win, prop,
|
|
1017 0L, 1024L + ((remaining + 3) / 4),
|
|
1018 False, AnyPropertyType,
|
|
1019 &actual_type, &actual_format,
|
|
1020 &count, &remaining, &buffer);
|
|
1021 }
|
|
1022
|
|
1023 if (zret != Success)
|
|
1024 return Qnil; /* failed */
|
|
1025
|
|
1026 value = convert_x_to_elisp (d, buffer, count, actual_type, actual_format);
|
|
1027
|
|
1028 XFree (buffer);
|
|
1029 return value;
|
|
1030 }
|
|
1031
|
|
1032 /*
|
|
1033 * Epoch equivalent: epoch::get-property
|
|
1034 */
|
|
1035 DEFUN ("x-get-property", Fx_get_property, Sx_get_property, 1, 2, 0 /*
|
|
1036 Retrieve the X window property for a frame. Arguments are
|
|
1037 PROPERTY: must be a string or an X-resource of type ATOM.
|
|
1038 FRAME: (optional) If present, must be a frame object, a frame id, or
|
|
1039 and X-resource of type WINDOW. Defaults to the current frame.
|
|
1040 Returns the value of the property, or nil if the property couldn't
|
|
1041 be retrieved.
|
|
1042 */ )
|
|
1043 (name, frame)
|
|
1044 Lisp_Object name, frame;
|
|
1045 {
|
|
1046 Atom prop = None;
|
|
1047 Lisp_Object device;
|
|
1048 Display *dpy;
|
|
1049 Window win;
|
|
1050
|
|
1051 /* We can't use Fx_id_of_frame because it returns the xid of
|
|
1052 the shell widget. But the property change has to take place
|
|
1053 on the edit widget in order for a PropertyNotify event to
|
|
1054 be generated */
|
|
1055 epoch_get_window_and_device (frame, &win, &device, 1);
|
|
1056 dpy = DEVICE_X_DISPLAY (XDEVICE (device));
|
|
1057
|
|
1058 if (STRINGP (name) || SYMBOLP (name))
|
|
1059 {
|
|
1060 prop = symbol_to_x_atom (XDEVICE (device),
|
|
1061 get_symbol_or_string_as_symbol (name),
|
|
1062 1);
|
|
1063 }
|
|
1064 else if (X_RESOURCEP (name))
|
|
1065 {
|
|
1066 CHECK_LIVE_X_RESOURCE (name);
|
|
1067 if (XX_RESOURCE (name)->type != XA_ATOM)
|
|
1068 error ("Property must be an ATOM X-resource");
|
|
1069 prop = XX_RESOURCE (name)->xid;
|
|
1070 }
|
|
1071 else
|
|
1072 error ("Property must be a string or X-resource ATOM");
|
|
1073
|
|
1074 if (prop == None)
|
|
1075 return Qnil;
|
|
1076
|
|
1077 /* now we have the atom, let's ask for the property! */
|
|
1078 return raw_get_property (XDEVICE (device), win, prop);
|
|
1079 }
|
|
1080
|
|
1081 static Lisp_Object
|
|
1082 raw_set_property (Display *dpy, Window win, Atom prop, Lisp_Object value)
|
|
1083 {
|
|
1084 /* !!#### This function has not been Mule-ized */
|
|
1085 Atom actual_type; /* X type of items */
|
|
1086 int actual_format; /* size of data items (8,16,32) */
|
|
1087 unsigned long count; /* Number of data items */
|
|
1088 void* addr; /* address of data item array */
|
|
1089 int zret; /* X call return value */
|
|
1090 int free_storage; /* set if addr points at non-malloc'd store */
|
|
1091
|
|
1092 actual_format = 0; /* don't force a particular format */
|
|
1093 convert_elisp_to_x (value, &addr, &count, &actual_type, &actual_format,
|
|
1094 &free_storage);
|
|
1095
|
|
1096 zret = XChangeProperty (dpy, win, prop, actual_type, actual_format,
|
|
1097 PropModeReplace, (char *) addr, count);
|
|
1098 XFlush (dpy);
|
|
1099
|
|
1100 if (free_storage)
|
|
1101 xfree (addr);
|
|
1102
|
|
1103 return value;
|
|
1104 }
|
|
1105
|
|
1106 DEFUN ("x-set-property", Fx_set_property, Sx_set_property, 2, 3, 0 /*
|
|
1107 Set a named property for a frame. The first argument (required)
|
|
1108 is the name of the property. The second is the value to set the propery
|
|
1109 to. The third (optional) is the frame, default is
|
|
1110 the current frame.
|
|
1111 */ )
|
|
1112 (name, value, frame)
|
|
1113 Lisp_Object name, value, frame;
|
|
1114 {
|
|
1115 Atom prop = None; /* name of the property */
|
|
1116 Lisp_Object device;
|
|
1117 Display *dpy;
|
|
1118 Window win;
|
|
1119
|
|
1120 /* We can't use Fx_id_of_frame because it returns the xid of
|
|
1121 the shell widget. But the property change has to take place
|
|
1122 on the edit widget in order for a PropertyNotify event to
|
|
1123 be generated */
|
|
1124 epoch_get_window_and_device (frame, &win, &device, 1);
|
|
1125 dpy = DEVICE_X_DISPLAY (XDEVICE (device));
|
|
1126
|
|
1127 /* parse the atom name, either a string or an actual atom */
|
|
1128 if (STRINGP (name) || SYMBOLP (name))
|
|
1129 {
|
|
1130 prop = symbol_to_x_atom (XDEVICE (device),
|
|
1131 get_symbol_or_string_as_symbol (name),
|
|
1132 0);
|
|
1133 }
|
|
1134 else if (X_RESOURCEP (name))
|
|
1135 {
|
|
1136 CHECK_LIVE_X_RESOURCE (name);
|
|
1137 if (XX_RESOURCE (name)->type != XA_ATOM)
|
|
1138 error ("Property must be an X-resource ATOM");
|
|
1139 prop = XX_RESOURCE (name)->xid;
|
|
1140 }
|
|
1141 else
|
|
1142 error ("Property must be a string or X-resource ATOM");
|
|
1143
|
|
1144 if (prop == None)
|
|
1145 return Qnil;
|
|
1146
|
|
1147 /* that's it. Now set it */
|
|
1148 return raw_set_property (dpy, win, prop, value);
|
|
1149 }
|
|
1150
|
|
1151 /*
|
|
1152 * Epoch equivalent: epoch::send-client-message
|
|
1153 */
|
|
1154 DEFUN ("x-send-client-message", Fx_send_client_message, Sx_send_client_message,
|
|
1155 1, 5, 0 /*
|
|
1156 Send a client message to DEST, marking it as being from SOURCE.
|
|
1157 The message is DATA of TYPE with FORMAT. If TYPE and FORMAT are omitted,
|
|
1158 they are deduced from DATA. If SOURCE is nil, the current frame is used.
|
|
1159 */ )
|
|
1160 (dest, source, data, type, format)
|
|
1161 Lisp_Object dest, source, data, type, format;
|
|
1162 {
|
|
1163 /* !!#### This function has not been Mule-ized */
|
|
1164 int actual_format = 0;
|
|
1165 Atom actual_type;
|
|
1166 unsigned long count;
|
|
1167 void *addr;
|
|
1168 int free_storage;
|
|
1169 XEvent ev;
|
|
1170 Lisp_Object result;
|
|
1171 Window dest_win;
|
|
1172 Lisp_Object dest_device;
|
|
1173 Window src_win;
|
|
1174 Lisp_Object src_device;
|
|
1175 Display *dpy;
|
|
1176
|
|
1177 epoch_get_window_and_device (dest, &dest_win, &dest_device, 0);
|
|
1178
|
|
1179 if (NILP (source))
|
|
1180 /* This catches a return of nil */
|
|
1181 XSETFRAME (source, device_selected_frame (XDEVICE (dest_device)));
|
|
1182
|
|
1183 epoch_get_window_and_device (source, &src_win, &src_device, 0);
|
|
1184
|
|
1185 if (!EQ (src_device, dest_device))
|
|
1186 error ("Destination and source must be on the same device");
|
|
1187
|
|
1188 dpy = DEVICE_X_DISPLAY (XDEVICE (dest_device));
|
|
1189
|
|
1190 ev.xclient.window = src_win;
|
|
1191
|
|
1192 /* check format before data, because it can cause the data format to vary */
|
|
1193 if (!NILP (format))
|
|
1194 {
|
|
1195 CHECK_INT (format);
|
|
1196 actual_format = XINT (format);
|
|
1197 if (actual_format != 8 && actual_format != 16 && actual_format != 32)
|
|
1198 error ("Format must be 8, 16, or 32, or nil");
|
|
1199 }
|
|
1200
|
|
1201 /* clear out any cruft */
|
|
1202 memset ((char *) &ev.xclient.data, 0, 20);
|
|
1203
|
|
1204 /* look for the data */
|
|
1205 if (!NILP (data))
|
|
1206 {
|
|
1207 convert_elisp_to_x (data, &addr, &count, &actual_type, &actual_format,
|
|
1208 &free_storage);
|
|
1209 if ((count * actual_format) > 20*8)
|
|
1210 {
|
|
1211 if (free_storage)
|
|
1212 xfree (addr);
|
|
1213 error ("Data is too big to fit in a client message");
|
|
1214 }
|
|
1215 memmove (&ev.xclient.data, (char *)addr, count * (actual_format/8));
|
|
1216 if (free_storage)
|
|
1217 xfree (addr);
|
|
1218 }
|
|
1219
|
|
1220 if (!NILP (type))
|
|
1221 {
|
|
1222 CHECK_LIVE_X_RESOURCE (type);
|
|
1223 if (XX_RESOURCE (type)->type != XA_ATOM)
|
|
1224 error ("Resource for message type must be an atom");
|
|
1225 actual_type = XX_RESOURCE (type)->xid;
|
|
1226 }
|
|
1227
|
|
1228 ev.xany.type = ClientMessage;
|
|
1229 ev.xclient.message_type = actual_type;
|
|
1230 ev.xclient.format = actual_format;
|
|
1231 /* There's no better way to set the mask than to hard code the correct
|
|
1232 * width bit pattern. 1L<<24 == OwnerGrabButtonMask, is the largest
|
|
1233 * This is the word from the X-consortium.
|
|
1234 */
|
|
1235 result = (XSendEvent (dpy, dest_win, False, (1L<<25)-1L,&ev)
|
|
1236 ? Qt
|
|
1237 : Qnil);
|
|
1238 XFlush (dpy);
|
|
1239 return result;
|
|
1240 }
|
|
1241
|
|
1242 /*
|
|
1243 * These duplicate the needed functionality from the Epoch event handler.
|
|
1244 */
|
|
1245 static Lisp_Object
|
|
1246 read_client_message (struct device *d, XClientMessageEvent *cm)
|
|
1247 {
|
|
1248 Lisp_Object result;
|
|
1249 Lisp_Object device = Qnil;
|
|
1250
|
|
1251 XSETDEVICE (device, d);
|
|
1252 if (!cm->format) /* this is probably a sign of a bug somewhere else */
|
|
1253 result = Qnil;
|
|
1254 else
|
|
1255 result = Fcons (make_x_resource (cm->message_type, XA_ATOM, device),
|
|
1256 Fcons (make_x_resource (cm->window, XA_WINDOW, device),
|
|
1257 convert_x_to_elisp (d, (void *) cm->data.b,
|
|
1258 (20*8)/cm->format,
|
|
1259 cm->message_type,
|
|
1260 cm->format)));
|
|
1261
|
|
1262 return result;
|
|
1263 }
|
|
1264
|
|
1265 static Lisp_Object
|
|
1266 read_property_event (XPropertyEvent *pe, Lisp_Object frame)
|
|
1267 {
|
|
1268 Lisp_Object result, value;
|
|
1269 struct frame *f = XFRAME (frame);
|
|
1270 struct device *d = XDEVICE (FRAME_DEVICE (f));
|
|
1271 Lisp_Object atom;
|
|
1272
|
|
1273 atom = x_atom_to_symbol (d, pe->atom);
|
|
1274
|
|
1275 /* didn't get a name, blow this one off */
|
|
1276 if (NILP (atom))
|
|
1277 return Qnil;
|
|
1278
|
|
1279 /* We can't use Fx_id_of_frame because it returns the xid of
|
|
1280 the shell widget. But the property change has to take place
|
|
1281 on the edit widget in order for a PropertyNotify event to
|
|
1282 be generated */
|
|
1283 value = raw_get_property (d, XtWindow (FRAME_X_TEXT_WIDGET (f)),
|
|
1284 pe->atom);
|
|
1285 result = Fcons (Fsymbol_name (atom), value);
|
|
1286
|
|
1287 return result;
|
|
1288 }
|
|
1289
|
|
1290 void dispatch_epoch_event (struct frame *f, XEvent *event, Lisp_Object type);
|
|
1291 void
|
|
1292 dispatch_epoch_event (struct frame *f, XEvent *event, Lisp_Object type)
|
|
1293 {
|
|
1294 /* This function can GC */
|
|
1295 struct Lisp_Vector *evp;
|
|
1296 struct device *d = XDEVICE (FRAME_DEVICE (f));
|
|
1297
|
|
1298 if (NILP (Vepoch_event_handler))
|
|
1299 return;
|
|
1300
|
|
1301 if (!VECTORP (Vepoch_event) || XVECTOR (Vepoch_event)->size < 3)
|
|
1302 Vepoch_event = Fmake_vector (make_int (3), Qnil);
|
|
1303 evp = XVECTOR (Vepoch_event);
|
|
1304
|
|
1305 XSETFRAME (evp->contents[2], f);
|
|
1306
|
|
1307 if (EQ (type, Qx_property_change))
|
|
1308 {
|
|
1309 evp->contents[0] = Qx_property_change;
|
|
1310 evp->contents[1] =
|
|
1311 read_property_event (&event->xproperty, evp->contents[2]);
|
|
1312 }
|
|
1313 else if (EQ (type, Qx_client_message))
|
|
1314 {
|
|
1315 evp->contents[0] = Qx_client_message;
|
|
1316 evp->contents[1] = read_client_message (d, &event->xclient);
|
|
1317 }
|
|
1318 else if (EQ (type, Qx_map))
|
|
1319 {
|
|
1320 evp->contents[0] = Qx_map;
|
|
1321 evp->contents[1] = Qt;
|
|
1322 }
|
|
1323 else if (EQ (type, Qx_unmap))
|
|
1324 {
|
|
1325 evp->contents[0] = Qx_unmap;
|
|
1326 evp->contents[1] = Qnil;
|
|
1327 }
|
|
1328 else
|
|
1329 {
|
|
1330 Vepoch_event = Qnil;
|
|
1331 }
|
|
1332
|
|
1333 if (NILP (Vepoch_event))
|
|
1334 return;
|
|
1335
|
|
1336 Ffuncall (1, &Vepoch_event_handler);
|
|
1337
|
|
1338 Vepoch_event = Qnil;
|
|
1339 return;
|
|
1340 }
|
|
1341
|
|
1342
|
|
1343 void
|
|
1344 syms_of_epoch (void)
|
|
1345 {
|
|
1346 defsubr (&Sx_intern_atom);
|
|
1347 defsubr (&Sx_atom_name);
|
|
1348 defsubr (&Sstring_to_x_resource);
|
|
1349 defsubr (&Sx_resource_to_type);
|
|
1350 defsubr (&Sx_resource_to_string);
|
|
1351 defsubr (&Sx_id_of_frame);
|
|
1352 defsubr (&Sx_query_tree);
|
|
1353 defsubr (&Sx_get_property);
|
|
1354 defsubr (&Sx_set_property);
|
|
1355 defsubr (&Sx_send_client_message);
|
|
1356 defsubr (&Sx_resource_p);
|
|
1357 defsubr (&Sx_resource_device);
|
|
1358 defsubr (&Sx_resource_live_p);
|
|
1359 defsubr (&Sset_x_resource_type);
|
|
1360
|
|
1361 defsymbol (&Qx_resourcep, "x-resource-p");
|
|
1362 defsymbol (&Qx_resource_live_p, "x-resource-live-p");
|
|
1363 defsymbol (&Qx_property_change, "x-property-change");
|
|
1364 defsymbol (&Qx_client_message, "x-client-message");
|
|
1365 defsymbol (&Qx_map, "x-map");
|
|
1366 defsymbol (&Qx_unmap, "x-unmap");
|
|
1367 }
|
|
1368
|
|
1369 void
|
|
1370 vars_of_epoch (void)
|
|
1371 {
|
|
1372 Fprovide (intern ("epoch"));
|
|
1373
|
|
1374 DEFVAR_LISP ("epoch-event-handler", &Vepoch_event_handler /*
|
|
1375 If this variable is not nil, then it is assumed to have
|
|
1376 a function in it. When an epoch event is received for a frame, this
|
|
1377 function is called.
|
|
1378 */ );
|
|
1379 Vepoch_event_handler = Qnil;
|
|
1380
|
|
1381 DEFVAR_LISP ("epoch-event", &Vepoch_event /*
|
|
1382 Bound to the value of the current event when epoch-event-handler is called.
|
|
1383 */ );
|
|
1384 Vepoch_event = Qnil;
|
|
1385 }
|