From 7a6b3d0fb793864a1f5deb5a22de78a4dced652d Mon Sep 17 00:00:00 2001 From: Noah Friedman Date: Sun, 21 Aug 2016 14:03:46 -0700 Subject: Fix interpretation of signed vs unsigned values when retrieving X Window properties, and make sure the full value is returned when not parsed. New subr to export type and format information about X Window properties to lisp. * src/xselect.c (selection_data_to_lisp_data): Treat any data as unsigned unless its actual type is INTEGER. CARDINALs, in particular, are unsigned. * src/xfns.c (Fx_change_window_property): If value is a string, ignore any provided format and force to 8. (x_window_property_intern): If returning value as a string, the length is actual_size times the actual format of each element, which is not necessarily bytes. (Fx_window_property_attributes): New subr. (syms_of_xfns): Declare it. --- src/xfns.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/xselect.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 106 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/xfns.c b/src/xfns.c index ccea20eef9..8860a21e67 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -5113,6 +5113,7 @@ FRAME. Default is to change on the edit X window. */) if (INT_MAX < SBYTES (value)) error ("VALUE too long"); nelements = SBYTES (value); + element_format = 8; /* ignore any provided format */ } block_input (); @@ -5223,7 +5224,7 @@ x_window_property_intern (struct frame *f, } if (NILP (vector_ret_p)) - prop_value = make_string ((char *) tmp_data, actual_size); + prop_value = make_string ((char *) tmp_data, (actual_format / 8) * actual_size); else prop_value = x_property_data_to_lisp (f, tmp_data, @@ -5310,6 +5311,62 @@ no value of TYPE (always string in the MS Windows case). */) return prop_value; } +DEFUN ("x-window-property-attributes", Fx_window_property_attributes, Sx_window_property_attributes, + 1, 3, 0, + doc: /* Retrieve metadata about window property PROP on FRAME. +If FRAME is nil or omitted, use the selected frame. +If SOURCE is non-nil, get the property on that window instead of from +FRAME. The number 0 denotes the root window. + +Return value is nil if FRAME hasn't a property with name PROP. +Otherwise, the return value is a vector with the following fields: + +0. The property type, as an integer. The symbolic name of + the type can be obtained with `x-get-atom-name'. +1. The format of each element; one of 8, 16, or 32. +2. The length of the property, in number of elements. */) + (Lisp_Object prop, Lisp_Object frame, Lisp_Object source) +{ + struct frame *f = decode_window_system_frame (frame); + Window target_window = FRAME_X_WINDOW (f); + Atom prop_atom; + Lisp_Object prop_attr = Qnil; + Atom actual_type; + int actual_format; + unsigned long actual_size, bytes_remaining; + unsigned char *tmp_data = NULL; + int rc; + + CHECK_STRING (prop); + + if (! NILP (source)) + { + CONS_TO_INTEGER (source, Window, target_window); + if (! target_window) + target_window = FRAME_DISPLAY_INFO (f)->root_window; + } + + block_input (); + + prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SSDATA (prop), False); + rc = XGetWindowProperty (FRAME_X_DISPLAY (f), target_window, + prop_atom, 0, 0, False, AnyPropertyType, + &actual_type, &actual_format, &actual_size, + &bytes_remaining, &tmp_data); + if (rc == Success && actual_format != 0) + { + XFree (tmp_data); + + prop_attr = Fmake_vector (make_number (3), Qnil); + ASET (prop_attr, 0, make_number (actual_type)); + ASET (prop_attr, 1, make_number (actual_format)); + ASET (prop_attr, 2, make_number (bytes_remaining / (actual_format / 8))); + } + + unblock_input (); + return prop_attr; +} + /*********************************************************************** Tool tips ***********************************************************************/ @@ -6966,6 +7023,7 @@ When using Gtk+ tooltips, the tooltip face is not used. */); defsubr (&Sx_change_window_property); defsubr (&Sx_delete_window_property); defsubr (&Sx_window_property); + defsubr (&Sx_window_property_attributes); defsubr (&Sxw_display_color_p); defsubr (&Sx_display_grayscale_p); diff --git a/src/xselect.c b/src/xselect.c index 616d12c7ca..156888a540 100644 --- a/src/xselect.c +++ b/src/xselect.c @@ -1612,11 +1612,24 @@ selection_data_to_lisp_data (struct x_display_info *dpyinfo, /* Convert a single 16-bit number or a small 32-bit number to a Lisp_Int. If the number is 32 bits and won't fit in a Lisp_Int, convert it to a cons of integers, 16 bits in each half. + + INTEGER is a signed type, CARDINAL is unsigned. + Assume any other types are unsigned as well. */ else if (format == 32 && size == sizeof (int)) - return INTEGER_TO_CONS (((int *) data) [0]); + { + if (type == XA_INTEGER) + return INTEGER_TO_CONS (((int *) data) [0]); + else + return INTEGER_TO_CONS (((unsigned int *) data) [0]); + } else if (format == 16 && size == sizeof (short)) - return make_number (((short *) data) [0]); + { + if (type == XA_INTEGER) + return make_number (((short *) data) [0]); + else + return make_number (((unsigned short *) data) [0]); + } /* Convert any other kind of data to a vector of numbers, represented as above (as an integer, or a cons of two 16 bit integers.) @@ -1626,11 +1639,22 @@ selection_data_to_lisp_data (struct x_display_info *dpyinfo, ptrdiff_t i; Lisp_Object v = make_uninit_vector (size / 2); - for (i = 0; i < size / 2; i++) - { - short j = ((short *) data) [i]; - ASET (v, i, make_number (j)); - } + if (type == XA_INTEGER) + { + for (i = 0; i < size / 2; i++) + { + short j = ((short *) data) [i]; + ASET (v, i, make_number (j)); + } + } + else + { + for (i = 0; i < size / 2; i++) + { + unsigned short j = ((unsigned short *) data) [i]; + ASET (v, i, make_number (j)); + } + } return v; } else @@ -1638,11 +1662,22 @@ selection_data_to_lisp_data (struct x_display_info *dpyinfo, ptrdiff_t i; Lisp_Object v = make_uninit_vector (size / X_LONG_SIZE); - for (i = 0; i < size / X_LONG_SIZE; i++) - { - int j = ((int *) data) [i]; - ASET (v, i, INTEGER_TO_CONS (j)); - } + if (type == XA_INTEGER) + { + for (i = 0; i < size / X_LONG_SIZE; i++) + { + int j = ((int *) data) [i]; + ASET (v, i, INTEGER_TO_CONS (j)); + } + } + else + { + for (i = 0; i < size / X_LONG_SIZE; i++) + { + unsigned int j = ((unsigned int *) data) [i]; + ASET (v, i, INTEGER_TO_CONS (j)); + } + } return v; } } -- cgit v1.2.3