comparison src/epoch.c @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children 9ee227acff29
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
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 }