Mercurial > hg > xemacs-beta
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/epoch.c Mon Aug 13 08:45:50 2007 +0200 @@ -0,0 +1,1385 @@ +/* Epoch functionality. + Copyright (C) 1985-1995 Free Software Foundation, Inc. + Copyright (C) 1996 Ben Wing. + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Not in FSF. */ + +#include <config.h> +#include "lisp.h" + +#include "console-x.h" +#include "objects-x.h" +#include "events.h" +#include "frame.h" + +Lisp_Object Qx_property_change, Qx_client_message, Qx_map, Qx_unmap; +Lisp_Object Vepoch_event, Vepoch_event_handler; + + +/************************************************************************/ +/* X resources */ +/************************************************************************/ + +Lisp_Object Qx_resource_live_p; + +#define XX_RESOURCE(x) XRECORD (x, x_resource, struct Lisp_X_Resource) +#define XSETX_RESOURCE(x, p) XSETRECORD (x, p, x_resource) +#define X_RESOURCEP(x) RECORDP (x, x_resource) +#define GC_X_RESOURCEP(x) GC_RECORDP (x, x_resource) +#define CHECK_X_RESOURCE(x) CHECK_RECORD (x, x_resource) + +#define X_RESOURCE_LIVE_P(xr) (DEVICE_LIVE_P (XDEVICE ((xr)->device))) +#define CHECK_LIVE_X_RESOURCE(x) \ + do { CHECK_X_RESOURCE (x); \ + if (!X_RESOURCE_LIVE_P (XX_RESOURCE (x))) \ + x = wrong_type_argument (Qx_resource_live_p, (x)); \ + } while (0) + +struct Lisp_X_Resource +{ + struct lcrecord_header header; + + XID xid; + Atom type; + Lisp_Object device; +}; + +Lisp_Object Qx_resourcep; +static Lisp_Object mark_x_resource (Lisp_Object, void (*) (Lisp_Object)); +static void print_x_resource (Lisp_Object, Lisp_Object, int); +static void finalize_x_resource (void *, int); +static int x_resource_equal (Lisp_Object o1, Lisp_Object o2, int depth); +static unsigned long x_resource_hash (Lisp_Object obj, int depth); +DEFINE_LRECORD_IMPLEMENTATION ("x-resource", x_resource, + mark_x_resource, print_x_resource, + finalize_x_resource, x_resource_equal, + x_resource_hash, struct Lisp_X_Resource); + +static Lisp_Object +mark_x_resource (Lisp_Object obj, void (*markobj) (Lisp_Object)) +{ + return XX_RESOURCE (obj)->device; +} + +static void +print_x_resource (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag) +{ + char buf[100]; + Bufbyte *default_string = "Resource"; + Lisp_Object atom_symbol; + Lisp_Object device = XX_RESOURCE (obj)->device; + + if (print_readably) + { + if (!DEVICE_LIVE_P (XDEVICE (device))) + error ("printing unreadable object #<dead x-resource>"); + else + error ("printing unreadable object #<x-resource 0x%x>", + (unsigned int) XX_RESOURCE (obj)->xid); + } + + if (!DEVICE_LIVE_P (XDEVICE (device))) + write_c_string ("#<dead x-resource>", printcharfun); + else + { + atom_symbol = x_atom_to_symbol (XDEVICE (device), + XX_RESOURCE (obj)->type); + sprintf (buf, "#<x-resource %s on ", + (NILP (atom_symbol) + ? default_string + : string_data (XSTRING (Fsymbol_name (atom_symbol))))); + write_c_string (buf, printcharfun); + print_internal (device, printcharfun, escapeflag); + sprintf (buf, " 0x%x>",(unsigned int) XX_RESOURCE (obj)->xid); + write_c_string (buf, printcharfun); + } +} + +static void +finalize_x_resource (void *header, int for_disksave) +{ +} + +static int +x_resource_equal (Lisp_Object o1, Lisp_Object o2, int depth) +{ + return (XX_RESOURCE (o1)->xid == XX_RESOURCE (o2)->xid && + EQ (XX_RESOURCE (o1)->device, XX_RESOURCE (o2)->device)); +} + +static unsigned long +x_resource_hash (Lisp_Object obj, int depth) +{ + return HASH2 (XX_RESOURCE (obj)->xid, + internal_hash (XX_RESOURCE (obj)->device, depth)); +} + +/* + * Epoch equivalent: epoch::resourcep + */ +DEFUN ("x-resource-p", Fx_resource_p, Sx_resource_p, 1, 1, 0 /* +Return non-nil if OBJECT is an X resource object. +*/ ) + (object) + Lisp_Object object; +{ + return (X_RESOURCEP (object) ? Qt : Qnil); +} + +DEFUN ("x-resource-live-p", Fx_resource_live_p, Sx_resource_live_p, 1, 1, 0 /* +Return non-nil if OBJECT is a live X resource object. +That means that the X resource's device is live. +*/ ) + (object) + Lisp_Object object; +{ + return (X_RESOURCEP (object) && + X_RESOURCE_LIVE_P (XX_RESOURCE (object)) ? Qt : Qnil); +} + +DEFUN ("x-resource-device", Fx_resource_device, Sx_resource_device, 1, 1, 0 /* +Return the device that OBJECT (an X resource object) exists on. +*/ ) + (object) + Lisp_Object object; +{ + CHECK_LIVE_X_RESOURCE (object); + return XX_RESOURCE (object)->device; +} + +/* + * Epoch equivalent: epoch::set-resource-type +*/ +DEFUN ("set-x-resource-type", Fset_x_resource_type, Sset_x_resource_type, + 2, 2, 0 /* +Set the type of RESOURCE to TYPE. The new type must be an atom. +*/ ) + (resource, type) + Lisp_Object resource, type; +{ + CHECK_LIVE_X_RESOURCE (resource); + CHECK_LIVE_X_RESOURCE (type); + + if (XX_RESOURCE (type)->type != XA_ATOM) + error ("New type must be an atom"); + + XX_RESOURCE (resource)->type = XX_RESOURCE (type)->xid; + return resource; +} + +static Lisp_Object +make_x_resource (XID xid, Atom type, Lisp_Object device) +{ + struct Lisp_X_Resource *xr = + alloc_lcrecord (sizeof (struct Lisp_X_Resource), lrecord_x_resource); + Lisp_Object val; + + xr->xid = xid; + xr->type = type; + xr->device = device; + XSETX_RESOURCE (val, xr); + + return val; +} + +static Lisp_Object +get_symbol_or_string_as_symbol (Lisp_Object name) +{ + retry: + if (SYMBOLP (name)) + return name; + else if (STRINGP (name)) + return Fintern (name, Qnil); + else + { + signal_simple_continuable_error ("Must be symbol or string", + name); + goto retry; + } + return Qnil; /* not reached */ +} + +/* + * Epoch equivalent: epoch::intern-atom + */ +DEFUN ("x-intern-atom", Fx_intern_atom, Sx_intern_atom, 1, 2, 0 /* +Convert a string or symbol into an atom and return as an X resource. +Optional argument DEVICE specifies the display connection and defaults +to the selected device. +*/ ) + (name, device) + Lisp_Object name, device; +{ + Atom atom; + struct device *d = decode_x_device (device); + + XSETDEVICE (device, d); + atom = symbol_to_x_atom (d, get_symbol_or_string_as_symbol (name), 0); + return make_x_resource (atom, XA_ATOM, device); +} + +/* + * Epoch equivalent: epoch::unintern-atom + */ +DEFUN ("x-atom-name", Fx_atom_name, Sx_atom_name, 1, 1, 0 /* +Return the name of an X atom resource as a string. +*/ ) + (atom) + Lisp_Object atom; +{ + Lisp_Object val; + + CHECK_LIVE_X_RESOURCE (atom); + if (XX_RESOURCE (atom)->type != XA_ATOM) + signal_simple_error ("Resource is not an atom", atom); + + val = x_atom_to_symbol (XDEVICE (XX_RESOURCE (atom)->device), + XX_RESOURCE (atom)->xid); + if (NILP (val)) + return Qnil; + return Fsymbol_name (val); +} + +/* + * Epoch equivalent: epoch::string-to-resource + */ +DEFUN ("string-to-x-resource", Fstring_to_x_resource, + Sstring_to_x_resource, 2, 3, 0 /* +Convert a numeric STRING to an X-RESOURCE. +STRING is assumed to represent a 32-bit numer value. X-RESOURCE must be +an X atom. Optional BASE argument should be a number between 2 and 36, +specifying the base for converting STRING. +*/ ) + (string, type, base) + Lisp_Object string, type, base; +{ + XID xid; + struct Lisp_X_Resource *xr; + char *ptr; + int b; + + CHECK_STRING (string); + CHECK_LIVE_X_RESOURCE (type); + + if (NILP (base)) + b = 0; + else + { + CHECK_INT (base); + b = XINT (base); + check_int_range (b, 2, 36); + } + + if (XX_RESOURCE (type)->type != XA_ATOM) + error ("Resource must be an atom"); + xr = XX_RESOURCE (type); + + xid = (XID) strtol ((CONST char *) string_data (XSTRING (string)), &ptr, b); + + return ((ptr == (char *) string_data (XSTRING (string))) + ? Qnil + : make_x_resource (xid, xr->xid, xr->device)); +} + +/* + * Epoch equivalent: epoch::resource-to-type + */ +DEFUN ("x-resource-to-type", Fx_resource_to_type, Sx_resource_to_type, + 1, 1, 0 /* +Return an x-resource of type ATOM whose value is the type of the argument +*/ ) + (resource) + Lisp_Object resource; +{ + struct Lisp_X_Resource *xr; + + CHECK_LIVE_X_RESOURCE (resource); + xr = XX_RESOURCE (resource); + + return make_x_resource (xr->type, XA_ATOM, xr->device); +} + +/* internal crap stolen from Epoch */ +static char LongToStringBuffer[33]; /* can't have statics inside functions! */ +static char * +long_to_string (unsigned long n, unsigned int base) +{ + char *digit = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + char *s = LongToStringBuffer + 32; /* at most 33 characters in binary */ + + *s = 0; /* terminate */ + while (n) /* something there */ + { + *--s = digit[n % base]; /* store bottom digit */ + n /= base; /* shift right */ + } + if (*s == 0) *--s = '0'; /* in case nothing was put in string */ + return s; +} + +/* + * Epoch equivalent: epoch::resource-to-string + */ +DEFUN ("x-resource-to-string", Fx_resource_to_string, Sx_resource_to_string, + 1, 2, 0 /* +Convert the xid of RESOURCE to a numeric string. +Optional BASE specifies the base for the conversion (2..36 inclusive) +*/ ) + (resource, base) + Lisp_Object resource, base; +{ + int cbase = 10; + + CHECK_LIVE_X_RESOURCE (resource); + if (!NILP (base)) + { + CHECK_INT (base); + cbase = XINT (base); + check_int_range (cbase, 2, 36); + } + + return build_string (long_to_string (XX_RESOURCE (resource)->xid, cbase)); +} + +/* + * Epoch equivalent: epoch::xid-of-frame + */ +DEFUN ("x-id-of-frame", Fx_id_of_frame, Sx_id_of_frame, 0, 1, 0 /* +Return the window ID of FRAME as an x-resource. +This differs from `x-window-id' in that its return value is an +x-resource rather than a string. +*/ ) + (frame) + Lisp_Object frame; +{ + struct frame *f = decode_x_frame (frame); + + return make_x_resource (XtWindow (FRAME_X_SHELL_WIDGET (f)), XA_WINDOW, + FRAME_DEVICE (f)); +} + +/* Given a frame or ID X resource, return the X window and device + it refers to. If text_p is non-zero, the window returned corresponds + to the text widget of the frame rather than the shell widget. */ + +static void +epoch_get_window_and_device (Lisp_Object frame, Window *window, + Lisp_Object *device, int text_p) +{ + if (X_RESOURCEP (frame)) + { + CHECK_LIVE_X_RESOURCE (frame); + if (XX_RESOURCE (frame)->type != XA_WINDOW) + error ("Frame resource must be of type WINDOW"); + *window = XX_RESOURCE (frame)->xid; + *device = XX_RESOURCE (frame)->device; + } + else + { + struct frame *f = decode_x_frame (frame); + + XSETFRAME (frame, f); + if (text_p) + *window = XtWindow (FRAME_X_TEXT_WIDGET (f)); + else + *window = XX_RESOURCE (Fx_id_of_frame (frame))->xid; + *device = FRAME_DEVICE (f); + } + +} + +/* + * Epoch equivalent: epoch::query-tree +*/ +DEFUN ("x-query-tree", Fx_query_tree, Sx_query_tree, 0, 1, 0 /* +Return the portion of the window tree adjacent to FRAME. +Return value is the list ( ROOT PARENT . CHILDREN ). The FRAME arg +can either be a frame object or an x-resource of type window. +*/ ) + (frame) + Lisp_Object frame; +{ + Window win; + Window root, parent, *children; + unsigned int count; + int retval; + Lisp_Object val; + Lisp_Object device; + + epoch_get_window_and_device (frame, &win, &device, 0); + + retval = + XQueryTree (DEVICE_X_DISPLAY (XDEVICE (device)), win, &root, &parent, + &children, &count); + + /* Thank you, X-Consortium. XQueryTree doesn't return Success like everyone + * else, it returns 1. (Success is defined to be 0 in the standard header + * files) + */ + if (!retval) return Qnil; + + val = Qnil; + while (count) + val = Fcons (make_x_resource (children[--count], XA_WINDOW, device), val); + + XFree (children); + + return Fcons (make_x_resource (root, XA_WINDOW, device), + Fcons ((parent + ? make_x_resource (parent, XA_WINDOW, device) + : Qnil), + val)); +} + +/* more internal crap stolen from Epoch */ + +static void +verify_vector_has_consistent_type (Lisp_Object vector) +{ + int i; /* vector index */ + XID rtype; /* X_resource type (if vector of + X_resources) */ + int length; /* vector length */ + struct Lisp_Vector *v = XVECTOR (vector); + Lisp_Object *element; + Lisp_Object sample; + Lisp_Object type_obj; /* base type of vector elements */ + Lisp_Object device; + + sample = v->contents[0]; + type_obj = sample; + if (X_RESOURCEP (sample)) + { + CHECK_LIVE_X_RESOURCE (sample); + rtype = XX_RESOURCE (sample)->type; + device = XX_RESOURCE (sample)->device; + } + length = v->size; + element = v->contents; + + for (i = 1; i < length; ++i, ++element) + { + QUIT; + if (X_RESOURCEP (type_obj)) + CHECK_LIVE_X_RESOURCE (type_obj); + if ((XTYPE (*element) != XTYPE (type_obj)) + || (LRECORDP (type_obj) && + (XRECORD_LHEADER (*element)->implementation != + XRECORD_LHEADER (type_obj)->implementation)) + || (X_RESOURCEP (type_obj) && + (rtype != XX_RESOURCE (*element)->type + || !EQ (device, XX_RESOURCE (*element)->device)))) + error ("Vector has inconsistent types"); + } +} + +static void +verify_list_has_consistent_type (Lisp_Object list) +{ + Lisp_Object type_obj; + XID rtype; /* X_resource type (if vector of + X_resources) */ + Lisp_Object temp = Fcar (list); + Lisp_Object device; + + type_obj = temp; + if (X_RESOURCEP (temp)) + { + CHECK_LIVE_X_RESOURCE (temp); + rtype = XX_RESOURCE (temp)->type; + device = XX_RESOURCE (temp)->device; + } + list = Fcdr (list); + + for ( ; !NILP (list) ; list = Fcdr (list)) + { + QUIT; + temp = Fcar (list); + if (X_RESOURCEP (temp)) + CHECK_LIVE_X_RESOURCE (temp); + if ((XTYPE (temp) != XTYPE (type_obj)) + || (LRECORDP (type_obj) && + (XRECORD_LHEADER (temp)->implementation != + XRECORD_LHEADER (type_obj)->implementation)) + || (X_RESOURCEP (type_obj) && + (rtype != XX_RESOURCE (temp)->type + || !EQ (device, XX_RESOURCE (temp)->device)))) + error ("List has inconsistent types"); + } +} + +#define BYTESIZE 8 +/* 16 bit types */ +typedef short int int16; +typedef short unsigned int uint16; + +/* the Calculate functions return allocated memory that must be free'd. + I tried to use alloca, but that fails. Sigh. +*/ +static void * +calculate_vector_property (Lisp_Object vector, unsigned long *count, + Atom *type, int *format) +{ + /* !!#### This function has not been Mule-ized */ + int length; + unsigned int size,tsize; + int i; + struct Lisp_Vector *v; + void *addr; + + v = XVECTOR (vector); + *count = length = v->size; + + switch (XTYPE (v->contents[0])) + { + case Lisp_Int: + *type = XA_INTEGER; + if (*format != 8 && *format != 16) *format = 32; + size = *format * length; + addr = (void *) xmalloc (size); + for ( i = 0 ; i < length ; ++i ) + switch (*format) + { + case 32 : + ((int *)addr)[i] = XINT (v->contents[i]); + break; + case 16 : + ((int16 *)addr)[i] = XINT (v->contents[i]); + break; + case 8 : + ((char *)addr)[i] = XINT (v->contents[i]); + break; + } + break; + + case Lisp_Record: + if (X_RESOURCEP (v->contents[0])) + { + CHECK_LIVE_X_RESOURCE (v->contents[0]); + size = BYTESIZE * sizeof (XID) * length; + *format = BYTESIZE * sizeof (XID); + *type = XX_RESOURCE (v->contents[0])->type; + addr = (void *) xmalloc (size); + for ( i = 0 ; i < length ; ++i ) + ( (XID *) addr) [i] = XX_RESOURCE (v->contents[i])->xid; + } + break; + + case Lisp_String: + *format = BYTESIZE * sizeof (char); + *type = XA_STRING; + for ( i=0, size=0 ; i < length ; ++i ) + size += (string_length (XSTRING (v->contents[i])) + + 1); /* include null */ + addr = (void *) xmalloc (size); + *count = size; + for ( i = 0 , size = 0 ; i < length ; ++i ) + { + tsize = string_length (XSTRING (v->contents[i])) + 1; + memmove (((char *) addr), string_data (XSTRING (v->contents[i])), + tsize); + size += tsize; + } + break; + + default: + error ("Invalid type for conversion"); + } + return addr; +} + +static void * +calculate_list_property (Lisp_Object list, unsigned long *count, + Atom *type, int *format) +{ + /* !!#### This function has not been Mule-ized */ + int length; + unsigned int size, tsize; + int i; + Lisp_Object tlist,temp; + void *addr; + + *count = length = XINT (Flength (list)); + + switch (XTYPE (Fcar (list))) + { + case Lisp_Int: + *type = XA_INTEGER; + if (*format != 8 && *format != 16) *format = 32; + size = *format * length; + addr = (void *) xmalloc (size); + for ( i = 0 ; i < length ; ++i, list = Fcdr (list)) + switch (*format) + { + case 32 : ((int *)addr)[i] = XINT (Fcar (list)); break; + case 16 : ((int16 *)addr)[i] = XINT (Fcar (list)); break; + case 8 : ((char *)addr)[i] = XINT (Fcar (list)); break; + } + break; + + case Lisp_Record: + if (X_RESOURCEP (Fcar (list))) + { + Lisp_Object car = Fcar (list); + CHECK_LIVE_X_RESOURCE (car); + size = BYTESIZE * sizeof (XID) * length; + *format = BYTESIZE * sizeof (XID); + *type = XX_RESOURCE (Fcar (list))->type; + addr = (void *) xmalloc (size); + for ( i = 0 ; i < length ; ++i, list = Fcdr (list)) + { + Lisp_Object carr = Fcar (list); + CHECK_LIVE_X_RESOURCE (carr); + ((XID *)addr)[i] = XX_RESOURCE (carr)->xid; + } + } + break; + + case Lisp_String: + *format = BYTESIZE * sizeof (char); + *type = XA_STRING; + for ( i=0, size=0 , tlist=list ; i < length ; ++i, tlist = Fcdr (tlist) ) + size += string_length (XSTRING (Fcar (tlist))) + 1; /* include null */ + addr = (void *) xmalloc (size); + *count = size; + for ( i=0, size=0, tlist=list ; i < length ; + ++i , tlist = Fcdr (tlist) ) + { + temp = Fcar (tlist); + tsize = string_length (XSTRING (temp)) + 1; + memmove (((char *) addr), string_data (XSTRING (temp)), tsize); + size += tsize; + } + break; + + default: + error ("Invalid type for conversion"); + } + return addr; +} + +/* Returns whether the conversion was successful or not */ +static int +convert_elisp_to_x (Lisp_Object value, void **addr, unsigned long *count, + Atom *type, int *format, int *free_storage) +{ + /* !!#### This function has not been Mule-ized */ + if (VECTORP (value)) + verify_vector_has_consistent_type (value); + else if (CONSP (value)) + verify_list_has_consistent_type (value); + + *free_storage = 0; + switch (XTYPE (value)) + { + case Lisp_String: + *format = BYTESIZE; + *type = XA_STRING; + *count = strlen ((CONST char *) string_data (XSTRING (value))) + 1; + *addr = (void *) string_data (XSTRING (value)); + break; + + case Lisp_Int: + *type = XA_INTEGER; + *count = 1; + *free_storage = 1; + *addr = (void *) xmalloc (sizeof (int)); + /* This is ugly - + * we have to deal with the possibility of different formats + */ + switch (*format) + { + default : + case 32 : + *format = 32; + *((int *)(*addr)) = XINT (value); + break; + case 16 : + *((int16 *)(*addr)) = XINT (value); + break; + case 8 : + *((char *)(*addr)) = XINT (value); + break; + } + break; + + case Lisp_Record: + if (X_RESOURCEP (value)) + { + CHECK_LIVE_X_RESOURCE (value); + *format = sizeof (XID) * BYTESIZE; + *type = XX_RESOURCE (value)->type; + *count = 1; + *addr = (void *) & (XX_RESOURCE (value)->xid); + } + break; + + case Lisp_Cons: + *addr = calculate_list_property (value, count, type, format); + *free_storage = 1; /* above allocates storage */ + break; + + case Lisp_Vector: + *addr = calculate_vector_property (value, count, type, format); + *free_storage = 1; /* above allocates storage */ + break; + + default : + error ("Improper type for conversion"); + } + + return 1; +} + +static Lisp_Object +format_size_hints (XSizeHints *hints) +{ + Lisp_Object result; + struct Lisp_Vector *v; + + result = Fmake_vector (make_int (6), Qnil); + v = XVECTOR (result); + + /* ugly but straightforward - just step through the members and flags + * and stick in the ones that are there + */ + if (hints->flags & (PPosition|USPosition)) + v->contents[0] = Fcons (make_int (hints->x), make_int (hints->y)); + if (hints->flags & (PSize|USSize)) + v->contents[1] = Fcons (make_int (hints->width), + make_int (hints->height)); + if (hints->flags & PMinSize) + v->contents[2] = Fcons (make_int (hints->min_width), + make_int (hints->min_height)); + if (hints->flags & PMaxSize) + v->contents[3] = Fcons (make_int (hints->max_width), + make_int (hints->max_height)); + if (hints->flags & PResizeInc) + v->contents[4] = Fcons (make_int (hints->width_inc), + make_int (hints->height_inc)); + if (hints->flags & PAspect) + v->contents[5] = Fcons (make_int (hints->min_aspect.x), + Fcons (make_int (hints->min_aspect.y), + Fcons (make_int (hints->max_aspect.x), + make_int (hints->max_aspect.y)))); + + return result; +} + +static Lisp_Object +format_string_property (char *buffer, unsigned long count) +{ + /* !!#### This function has not been Mule-ized */ + Lisp_Object value = Qnil; /* data */ + Lisp_Object temp; /* temp value holder */ + int len; /* length of current string */ + char *strend; + + while (count) + { + strend = memchr (buffer, 0, (int) count); + len = strend ? strend - buffer : count; + if (len) + { + temp = make_string ((Bufbyte *) buffer, len); + value = Fcons (temp, value); + } + buffer = strend + 1; /* skip null, or leaving loop if no null */ + count -= len + !!strend; + } + + return (NILP (Fcdr (value)) + ? Fcar (value) + : Fnreverse (value)); +} + +static Lisp_Object +format_integer_32_property (long *buff, unsigned long count) +{ + Lisp_Object value = Qnil; /* return value */ + while (count) + value = Fcons (make_int (buff[--count]), value); + + return (NILP (Fcdr (value)) + ? Fcar (value) + : value); +} + +static Lisp_Object +format_integer_16_property (int16 *buff, unsigned long count) +{ + Lisp_Object value = Qnil; /* return value */ + + while (count) + value = Fcons (make_int (buff[--count]), value); + + return (NILP (Fcdr (value)) + ? Fcar (value) + : value); +} + +static Lisp_Object +format_integer_8_property (char *buff, unsigned long count) +{ + Lisp_Object value = Qnil; /* return value */ + + while (count) + value = Fcons (make_int (buff[--count]), value); + + return (NILP (Fcdr (value)) + ? Fcar (value) + : value); +} + +static Lisp_Object +format_integer_property (void *buff, unsigned long count, int format) +{ + switch (format) + { + case 8: + return format_integer_8_property ((char *) buff, count); + break; + case 16: + return format_integer_16_property ((int16 *) buff, count); + break; + case 32: + return format_integer_32_property ((long *) buff, count); + break; + default: + return Qnil; + } +} + +static Lisp_Object +format_cardinal_32_property (unsigned long *buff, unsigned long count) +{ + Lisp_Object value = Qnil; /* return value */ + + while (count) + value = Fcons (make_int (buff[--count]), value); + + return (NILP (Fcdr (value)) + ? Fcar (value) + : value); +} + +static Lisp_Object +format_cardinal_16_property (uint16 *buff, unsigned long count) +{ + Lisp_Object value = Qnil; /* return value */ + + while (count) + value = Fcons (make_int (buff[--count]), value); + + return (NILP (Fcdr (value)) + ? Fcar (value) + : value); +} + +static Lisp_Object +format_cardinal_8_property (unsigned char *buff, unsigned long count) +{ + Lisp_Object value = Qnil; /* return value */ + + while (count) + value = Fcons (make_int (buff[--count]), value); + + return (NILP (Fcdr (value)) + ? Fcar (value) + : value); +} + +static Lisp_Object +format_cardinal_property (void *buff, unsigned long count, int format) +{ + switch (format) + { + case 8: + return format_cardinal_8_property ((unsigned char *) buff, count); + break; + case 16: + return format_cardinal_16_property ((uint16 *) buff, count); + break; + case 32: + return format_cardinal_32_property ((unsigned long *) buff, count); + default: + return Qnil; + } +} + +static Lisp_Object +format_unknown_property (struct device *d, void *buff, unsigned long count, + Atom type, int format) +{ + Lisp_Object value = Qnil; /* return value */ + Lisp_Object device = Qnil; + + XSETDEVICE (device, d); + + switch (format) + { + case 32: + { + XID *xid = (XID *) buff; + int non_zero = 0; + while (count--) + if (non_zero || xid[count]) + { + value = Fcons (make_x_resource (xid[count], type, device), + value); + non_zero = 1; + } + } + break; + } + + return (NILP (Fcdr (value)) + ? Fcar (value) + : value); +} + +static Lisp_Object +convert_x_to_elisp (struct device *d, void *buffer, unsigned long count, + Atom type, int format) +{ + /* !!#### This function has not been Mule-ized */ + Lisp_Object value = Qnil; + + switch (type) + { + case None: + value = Qnil; + break; + case XA_STRING: + value = format_string_property (buffer, count); + break; + case XA_INTEGER: + value = format_integer_property ((long *) buffer, count, format); + break; + case XA_CARDINAL: + value = format_cardinal_property ((unsigned long *) buffer, + count, format); + break; + case XA_WM_SIZE_HINTS: + value = format_size_hints ((XSizeHints *) buffer); + break; + default: + value = format_unknown_property (d, (void *) buffer, count, type, + format); + break; + } + + return value; +} + +/* get a property given its atom, device, and window */ +static Lisp_Object +raw_get_property (struct device *d, Window win, Atom prop) +{ + /* !!#### This function has not been Mule-ized */ + Lisp_Object value = Qnil; + Atom actual_type; + int actual_format; + unsigned char *buffer; + unsigned long count, remaining; + int zret; + Display *dpy = DEVICE_X_DISPLAY (d); + + zret = XGetWindowProperty (dpy, win, prop, + 0L, 1024L, False, AnyPropertyType, + &actual_type, &actual_format, + &count, &remaining, &buffer); + + /* If remaining is set, then there's more of the property to get. + Let's just do the whole read again, this time with enough space + to get it all. */ + if (zret == Success && remaining > 0) + { + XFree (buffer); + zret = XGetWindowProperty (dpy, win, prop, + 0L, 1024L + ((remaining + 3) / 4), + False, AnyPropertyType, + &actual_type, &actual_format, + &count, &remaining, &buffer); + } + + if (zret != Success) + return Qnil; /* failed */ + + value = convert_x_to_elisp (d, buffer, count, actual_type, actual_format); + + XFree (buffer); + return value; +} + +/* + * Epoch equivalent: epoch::get-property + */ +DEFUN ("x-get-property", Fx_get_property, Sx_get_property, 1, 2, 0 /* +Retrieve the X window property for a frame. Arguments are +PROPERTY: must be a string or an X-resource of type ATOM. +FRAME: (optional) If present, must be a frame object, a frame id, or +and X-resource of type WINDOW. Defaults to the current frame. +Returns the value of the property, or nil if the property couldn't +be retrieved. +*/ ) + (name, frame) + Lisp_Object name, frame; +{ + Atom prop = None; + Lisp_Object device; + Display *dpy; + Window win; + + /* We can't use Fx_id_of_frame because it returns the xid of + the shell widget. But the property change has to take place + on the edit widget in order for a PropertyNotify event to + be generated */ + epoch_get_window_and_device (frame, &win, &device, 1); + dpy = DEVICE_X_DISPLAY (XDEVICE (device)); + + if (STRINGP (name) || SYMBOLP (name)) + { + prop = symbol_to_x_atom (XDEVICE (device), + get_symbol_or_string_as_symbol (name), + 1); + } + else if (X_RESOURCEP (name)) + { + CHECK_LIVE_X_RESOURCE (name); + if (XX_RESOURCE (name)->type != XA_ATOM) + error ("Property must be an ATOM X-resource"); + prop = XX_RESOURCE (name)->xid; + } + else + error ("Property must be a string or X-resource ATOM"); + + if (prop == None) + return Qnil; + + /* now we have the atom, let's ask for the property! */ + return raw_get_property (XDEVICE (device), win, prop); +} + +static Lisp_Object +raw_set_property (Display *dpy, Window win, Atom prop, Lisp_Object value) +{ + /* !!#### This function has not been Mule-ized */ + Atom actual_type; /* X type of items */ + int actual_format; /* size of data items (8,16,32) */ + unsigned long count; /* Number of data items */ + void* addr; /* address of data item array */ + int zret; /* X call return value */ + int free_storage; /* set if addr points at non-malloc'd store */ + + actual_format = 0; /* don't force a particular format */ + convert_elisp_to_x (value, &addr, &count, &actual_type, &actual_format, + &free_storage); + + zret = XChangeProperty (dpy, win, prop, actual_type, actual_format, + PropModeReplace, (char *) addr, count); + XFlush (dpy); + + if (free_storage) + xfree (addr); + + return value; +} + +DEFUN ("x-set-property", Fx_set_property, Sx_set_property, 2, 3, 0 /* +Set a named property for a frame. The first argument (required) +is the name of the property. The second is the value to set the propery +to. The third (optional) is the frame, default is +the current frame. +*/ ) + (name, value, frame) + Lisp_Object name, value, frame; +{ + Atom prop = None; /* name of the property */ + Lisp_Object device; + Display *dpy; + Window win; + + /* We can't use Fx_id_of_frame because it returns the xid of + the shell widget. But the property change has to take place + on the edit widget in order for a PropertyNotify event to + be generated */ + epoch_get_window_and_device (frame, &win, &device, 1); + dpy = DEVICE_X_DISPLAY (XDEVICE (device)); + + /* parse the atom name, either a string or an actual atom */ + if (STRINGP (name) || SYMBOLP (name)) + { + prop = symbol_to_x_atom (XDEVICE (device), + get_symbol_or_string_as_symbol (name), + 0); + } + else if (X_RESOURCEP (name)) + { + CHECK_LIVE_X_RESOURCE (name); + if (XX_RESOURCE (name)->type != XA_ATOM) + error ("Property must be an X-resource ATOM"); + prop = XX_RESOURCE (name)->xid; + } + else + error ("Property must be a string or X-resource ATOM"); + + if (prop == None) + return Qnil; + + /* that's it. Now set it */ + return raw_set_property (dpy, win, prop, value); +} + +/* + * Epoch equivalent: epoch::send-client-message + */ +DEFUN ("x-send-client-message", Fx_send_client_message, Sx_send_client_message, + 1, 5, 0 /* +Send a client message to DEST, marking it as being from SOURCE. +The message is DATA of TYPE with FORMAT. If TYPE and FORMAT are omitted, +they are deduced from DATA. If SOURCE is nil, the current frame is used. +*/ ) + (dest, source, data, type, format) + Lisp_Object dest, source, data, type, format; +{ + /* !!#### This function has not been Mule-ized */ + int actual_format = 0; + Atom actual_type; + unsigned long count; + void *addr; + int free_storage; + XEvent ev; + Lisp_Object result; + Window dest_win; + Lisp_Object dest_device; + Window src_win; + Lisp_Object src_device; + Display *dpy; + + epoch_get_window_and_device (dest, &dest_win, &dest_device, 0); + + if (NILP (source)) + /* This catches a return of nil */ + XSETFRAME (source, device_selected_frame (XDEVICE (dest_device))); + + epoch_get_window_and_device (source, &src_win, &src_device, 0); + + if (!EQ (src_device, dest_device)) + error ("Destination and source must be on the same device"); + + dpy = DEVICE_X_DISPLAY (XDEVICE (dest_device)); + + ev.xclient.window = src_win; + + /* check format before data, because it can cause the data format to vary */ + if (!NILP (format)) + { + CHECK_INT (format); + actual_format = XINT (format); + if (actual_format != 8 && actual_format != 16 && actual_format != 32) + error ("Format must be 8, 16, or 32, or nil"); + } + + /* clear out any cruft */ + memset ((char *) &ev.xclient.data, 0, 20); + + /* look for the data */ + if (!NILP (data)) + { + convert_elisp_to_x (data, &addr, &count, &actual_type, &actual_format, + &free_storage); + if ((count * actual_format) > 20*8) + { + if (free_storage) + xfree (addr); + error ("Data is too big to fit in a client message"); + } + memmove (&ev.xclient.data, (char *)addr, count * (actual_format/8)); + if (free_storage) + xfree (addr); + } + + if (!NILP (type)) + { + CHECK_LIVE_X_RESOURCE (type); + if (XX_RESOURCE (type)->type != XA_ATOM) + error ("Resource for message type must be an atom"); + actual_type = XX_RESOURCE (type)->xid; + } + + ev.xany.type = ClientMessage; + ev.xclient.message_type = actual_type; + ev.xclient.format = actual_format; + /* There's no better way to set the mask than to hard code the correct + * width bit pattern. 1L<<24 == OwnerGrabButtonMask, is the largest + * This is the word from the X-consortium. + */ + result = (XSendEvent (dpy, dest_win, False, (1L<<25)-1L,&ev) + ? Qt + : Qnil); + XFlush (dpy); + return result; +} + +/* + * These duplicate the needed functionality from the Epoch event handler. + */ +static Lisp_Object +read_client_message (struct device *d, XClientMessageEvent *cm) +{ + Lisp_Object result; + Lisp_Object device = Qnil; + + XSETDEVICE (device, d); + if (!cm->format) /* this is probably a sign of a bug somewhere else */ + result = Qnil; + else + result = Fcons (make_x_resource (cm->message_type, XA_ATOM, device), + Fcons (make_x_resource (cm->window, XA_WINDOW, device), + convert_x_to_elisp (d, (void *) cm->data.b, + (20*8)/cm->format, + cm->message_type, + cm->format))); + + return result; +} + +static Lisp_Object +read_property_event (XPropertyEvent *pe, Lisp_Object frame) +{ + Lisp_Object result, value; + struct frame *f = XFRAME (frame); + struct device *d = XDEVICE (FRAME_DEVICE (f)); + Lisp_Object atom; + + atom = x_atom_to_symbol (d, pe->atom); + + /* didn't get a name, blow this one off */ + if (NILP (atom)) + return Qnil; + + /* We can't use Fx_id_of_frame because it returns the xid of + the shell widget. But the property change has to take place + on the edit widget in order for a PropertyNotify event to + be generated */ + value = raw_get_property (d, XtWindow (FRAME_X_TEXT_WIDGET (f)), + pe->atom); + result = Fcons (Fsymbol_name (atom), value); + + return result; +} + +void dispatch_epoch_event (struct frame *f, XEvent *event, Lisp_Object type); +void +dispatch_epoch_event (struct frame *f, XEvent *event, Lisp_Object type) +{ + /* This function can GC */ + struct Lisp_Vector *evp; + struct device *d = XDEVICE (FRAME_DEVICE (f)); + + if (NILP (Vepoch_event_handler)) + return; + + if (!VECTORP (Vepoch_event) || XVECTOR (Vepoch_event)->size < 3) + Vepoch_event = Fmake_vector (make_int (3), Qnil); + evp = XVECTOR (Vepoch_event); + + XSETFRAME (evp->contents[2], f); + + if (EQ (type, Qx_property_change)) + { + evp->contents[0] = Qx_property_change; + evp->contents[1] = + read_property_event (&event->xproperty, evp->contents[2]); + } + else if (EQ (type, Qx_client_message)) + { + evp->contents[0] = Qx_client_message; + evp->contents[1] = read_client_message (d, &event->xclient); + } + else if (EQ (type, Qx_map)) + { + evp->contents[0] = Qx_map; + evp->contents[1] = Qt; + } + else if (EQ (type, Qx_unmap)) + { + evp->contents[0] = Qx_unmap; + evp->contents[1] = Qnil; + } + else + { + Vepoch_event = Qnil; + } + + if (NILP (Vepoch_event)) + return; + + Ffuncall (1, &Vepoch_event_handler); + + Vepoch_event = Qnil; + return; +} + + +void +syms_of_epoch (void) +{ + defsubr (&Sx_intern_atom); + defsubr (&Sx_atom_name); + defsubr (&Sstring_to_x_resource); + defsubr (&Sx_resource_to_type); + defsubr (&Sx_resource_to_string); + defsubr (&Sx_id_of_frame); + defsubr (&Sx_query_tree); + defsubr (&Sx_get_property); + defsubr (&Sx_set_property); + defsubr (&Sx_send_client_message); + defsubr (&Sx_resource_p); + defsubr (&Sx_resource_device); + defsubr (&Sx_resource_live_p); + defsubr (&Sset_x_resource_type); + + defsymbol (&Qx_resourcep, "x-resource-p"); + defsymbol (&Qx_resource_live_p, "x-resource-live-p"); + defsymbol (&Qx_property_change, "x-property-change"); + defsymbol (&Qx_client_message, "x-client-message"); + defsymbol (&Qx_map, "x-map"); + defsymbol (&Qx_unmap, "x-unmap"); +} + +void +vars_of_epoch (void) +{ + Fprovide (intern ("epoch")); + + DEFVAR_LISP ("epoch-event-handler", &Vepoch_event_handler /* +If this variable is not nil, then it is assumed to have +a function in it. When an epoch event is received for a frame, this +function is called. +*/ ); + Vepoch_event_handler = Qnil; + + DEFVAR_LISP ("epoch-event", &Vepoch_event /* +Bound to the value of the current event when epoch-event-handler is called. +*/ ); + Vepoch_event = Qnil; +}