summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'x11-wm/sawfish-merlin/files/x.c.patch-merlin-1.0.2')
-rw-r--r--x11-wm/sawfish-merlin/files/x.c.patch-merlin-1.0.21364
1 files changed, 1364 insertions, 0 deletions
diff --git a/x11-wm/sawfish-merlin/files/x.c.patch-merlin-1.0.2 b/x11-wm/sawfish-merlin/files/x.c.patch-merlin-1.0.2
new file mode 100644
index 000000000000..f77cfa8bbfa0
--- /dev/null
+++ b/x11-wm/sawfish-merlin/files/x.c.patch-merlin-1.0.2
@@ -0,0 +1,1364 @@
+#
+# version -0.8.4
+#
+# Copyright (C) 2000-2001 merlin <merlin@merlin.org>
+#
+# Built from sawfish 1.00.
+#
+# *********************
+# ** HERE BE DRAGONS **
+# *********************
+#
+# This code contains horrendous hacks. It introduces the high
+# probability of crashing your Window Manager and Rendering it
+# Unstable and Destroying your Valuable Work and Property.
+#
+# Tnis is unlikely to work with earlier or later versions of
+# Sawfish.
+#
+# Sawfish was not written with code of this nature on mind.
+#
+# More to the point, Sawfish was written with the express
+# intention of this NOT EVER being done. As a result, this
+# Software introduces the EXTREME PROBABILITY of FAILURE that
+# DOES NOT EXIST in Sawfish itself.
+#
+# ******************
+# ** INSTALLATION **
+# ******************
+#
+# I assume that you have a recent copy of the Sawfish
+# source unpacked somewhere.
+#
+# Change into the `src' directory.
+# cd sawfish-x.yz/src/
+#
+# Run patch against this file to patch x.c:
+# patch -p1 < /path/to/x.c.patch
+#
+# Compile and install Sawfish.
+# make
+# make install
+#
+# Restart Sawfish.
+#
+# Alternatively, you might want to install sawfish using
+# some package manager, such as apt or RPM. Then you can
+# build and locally install just the patched library using
+# the following technique:
+# make
+# mkdir -p ~/.sawfish/lib/sawfish/wm/util
+# cp src/.libs/x.* ~/.sawfish/lib
+# cp src/.libs/x.* ~/.sawfish/lib/sawfish/wm/util
+#
+# You'll also need to add the following line to the *start*
+# of your ~/.sawfishrc:
+# (setq dl-load-path (cons "~/.sawfish/lib" dl-load-path))
+#
+# Restart Sawfish.
+#
+# ******************
+# ** HERE BE BUGS **
+# ******************
+#
+# Many XLib features are unimplemented and misimplemented.
+#
+# My understanding of rep modules is incomplete and erroneous.
+#
+# In order to support managed windows I introduced many hacks with
+# UNKNOWN CONSEQUENCES.
+#
+# This code allows you to emulate being a distinct X application when you
+# are in fact just a tiny part of a Window Manager that knows NOTHING
+# about you. As a result, expect Window Management not to work as it
+# should, and expect Your Application not to work as it should. You won't
+# get events that you expect, you will get events that you don't and the
+# Window Manager will simply not operate 100% as it should.
+#
+# In particular, if you create a managed window then it will probably be
+# useless to you; you'll want to cover it with a child.
+#
+# One day I'll chop this off so it is a separate rep module that allows
+# you to write standalone XLib applications that are not bastard,
+# deformed monstrosities sprouting from the side of something beautiful.
+#
+# - merlin
+
+Index: src/x.c
+===================================================================
+RCS file: /cvs/gnome/sawfish/src/x.c,v
+retrieving revision 1.22
+diff -u -r1.22 x.c
+--- src/x.c 2001/04/11 21:01:03 1.22
++++ src/x.c 2001/09/09 11:57:09
+@@ -6,6 +6,9 @@
+ Originally written by merlin <merlin@merlin.org>, with additions
+ from John Harper
+
++ Then patched again by merlin to add some wicked functions:
++ x.c#pl:merlin/-0.8.4
++
+ This file is part of sawmill.
+
+ sawmill is free software; you can redistribute it and/or modify it
+@@ -72,6 +75,7 @@
+ int is_pixmap : 1;
+ int is_bitmap : 1; /* depth == 1 */
+ int width, height;
++ repv plist;
+ } Lisp_X_Window;
+
+ #define X_XDRAWABLEP(v) rep_CELL16_TYPEP(v, x_window_type)
+@@ -82,6 +86,8 @@
+ #define X_PIXMAPP(v) (X_DRAWABLEP (v) && VX_DRAWABLE (v)->is_pixmap)
+ #define X_BITMAPP(v) (X_DRAWABLEP (v) && VX_DRAWABLE (v)->is_bitmap)
+
++#define ANY_WINDOWP(w) (rep_INTEGERP(w) || X_WINDOWP(w) || (WINDOWP(w) && VWIN(w)->id != 0))
++
+ static Lisp_X_GC *x_gc_list = NULL;
+ int x_gc_type;
+
+@@ -115,6 +121,36 @@
+ DEFSYM (clip_mask, "clip-mask");
+ DEFSYM (clip_x_origin, "clip-x-origin");
+ DEFSYM (clip_y_origin, "clip-y-origin");
++DEFSYM (sibling, "sibling");
++DEFSYM (stack_mode, "stack-mode");
++DEFSYM (override_redirect, "override-redirect");
++DEFSYM (save_under, "save-under");
++DEFSYM (event_mask, "event-mask");
++DEFSYM (parent, "parent");
++DEFSYM (raise_lowest, "raise-lowest");
++DEFSYM (lower_highest, "lower-highest");
++
++DEFSYM (serial, "serial");
++DEFSYM (send_event, "send-event");
++DEFSYM (window, "window");
++DEFSYM (event, "event");
++DEFSYM (subwindow, "subwindow");
++DEFSYM (time, "time");
++DEFSYM (x_root, "x-root");
++DEFSYM (y_root, "y-root");
++DEFSYM (state, "state");
++DEFSYM (keycode, "keycode");
++DEFSYM (same_screen, "same-screen");
++DEFSYM (button, "button");
++DEFSYM (is_hint, "is-hint");
++DEFSYM (focus, "focus");
++DEFSYM (mode, "mode");
++DEFSYM (detail, "detail");
++DEFSYM (count, "count");
++DEFSYM (message_type, "message-type");
++DEFSYM (format, "format");
++DEFSYM (data, "data");
++DEFSYM (above, "above");
+
+ DEFSYM (LineSolid, "line-solid");
+ DEFSYM (LineOnOffDash, "line-on-off-dash");
+@@ -216,7 +252,60 @@
+ return GXcopy;
+ }
+
++static Atom
++x_symbol_atom (repv symbol) {
++ return XInternAtom (dpy, rep_STR (rep_SYM (symbol)->name), False);
++}
++
+
++/* Symbol matching Functions */
++
++typedef struct {
++ unsigned int value;
++ char *str;
++} x_value_str;
++
++static repv
++x_value_match (unsigned int value, x_value_str *match) {
++ while (match->str) {
++ if (value == match->value)
++ return Fintern (rep_string_dup (match->str), Qnil);
++ ++ match;
++ }
++ return Qnil;
++}
++
++static repv
++x_valuemask_match (unsigned int value, x_value_str *match) {
++ repv result = Qnil;
++ while (match->str) {
++ if (value & match->value)
++ result = Fcons (Fintern (rep_string_dup (match->str), Qnil), result);
++ ++ match;
++ }
++ return result;
++}
++
++typedef struct {
++ char *str;
++ unsigned int value;
++} x_str_value;
++
++static int
++x_symbol_match (repv symbol, x_str_value *match) {
++ char *tmp;
++ if (!rep_SYMBOLP (symbol))
++ return -1;
++ tmp = rep_STR (rep_SYM (symbol)->name);
++ while (match->str) {
++ if (!strcmp (match->str, tmp))
++ return match->value;
++ ++ match;
++ }
++ return -1;
++}
++
++
+ /* GC Functions */
+
+ static long
+@@ -470,6 +559,16 @@
+ return Qt;
+ }
+
++DEFUN ("x-free-gc", Fx_free_gc, Sx_free_gc, (repv gc), rep_Subr1) /*
++::doc:sawfish.wm.util.x#x-free-gc::
++x-free-gc X-GC
++
++Free the X-GC. Same as x-destroy-gc.
++::end:: */
++{
++ return Fx_destroy_gc (gc);
++}
++
+ DEFUN ("x-gc-p", Fx_gc_p, Sx_gc_p, (repv gc), rep_Subr1) /*
+ ::doc:sawfish.wm.util.x#x-gc-p::
+ x-gcp ARG
+@@ -483,6 +582,15 @@
+
+ /* Window functions */
+
++static x_str_value x_stack_mode_matches[] = {
++ { "above", Above },
++ { "below", Below },
++ { "top-if", TopIf },
++ { "bottom-if", BottomIf },
++ { "opposite", Opposite },
++ { 0, 0 }
++};
++
+ static long
+ x_window_parse_changes (XWindowChanges *changes, repv attrs)
+ {
+@@ -520,6 +628,24 @@
+ changes->border_width = rep_INT (rep_CDR (tem));
+ changesMask |= CWBorderWidth;
+ }
++ else if (car == Qsibling)
++ {
++ Window sibling = window_from_arg (rep_CDR (tem));
++ if (sibling)
++ {
++ changes->sibling = sibling;
++ changesMask |= CWSibling;
++ }
++ }
++ else if (car == Qstack_mode)
++ {
++ int stack_mode = x_symbol_match (rep_CDR (tem), x_stack_mode_matches);
++ if (stack_mode != -1)
++ {
++ changes->stack_mode = stack_mode;
++ changesMask |= CWStackMode;
++ }
++ }
+ }
+
+ attrs = rep_CDR (attrs);
+@@ -537,6 +663,35 @@
+ w->height = changes->height;
+ }
+
++static x_str_value x_event_mask_matches[] = {
++ { "key-press", KeyPressMask },
++ { "key-release", KeyReleaseMask },
++ { "button-press", ButtonPressMask },
++ { "button-release", ButtonReleaseMask },
++ { "enter-window", EnterWindowMask },
++ { "leave-window", LeaveWindowMask },
++ { "pointer-motion", PointerMotionMask },
++ { "pointer-motion-hint", PointerMotionHintMask },
++ { "button-1-motion", Button1MotionMask },
++ { "button-2-motion", Button2MotionMask },
++ { "button-3-motion", Button3MotionMask },
++ { "button-4-motion", Button4MotionMask },
++ { "button-5-motion", Button5MotionMask },
++ { "button-motion", ButtonMotionMask },
++ { "keymap-state", KeymapStateMask },
++ { "exposure", ExposureMask },
++ { "visibility-change", VisibilityChangeMask },
++ { "structure-notify", StructureNotifyMask },
++ { "resize-redirect", ResizeRedirectMask },
++ { "substructure-notify", SubstructureNotifyMask },
++ { "substructure-redirect", SubstructureRedirectMask },
++ { "focus-change", FocusChangeMask },
++ { "property-change", PropertyChangeMask },
++ { "colormap-change", ColormapChangeMask },
++ { "owner-grab-button", OwnerGrabButtonMask },
++ { 0, 0 }
++};
++
+ static long
+ x_window_parse_attributes (XSetWindowAttributes *attributes, repv attrs)
+ {
+@@ -559,6 +714,28 @@
+ attributes->border_pixel = VCOLOR (rep_CDR (tem))->pixel;
+ attributesMask |= CWBorderPixel;
+ }
++ else if (car == Qoverride_redirect)
++ {
++ attributes->override_redirect = rep_NILP(rep_CDR(tem)) ? False : True;
++ attributesMask |= CWOverrideRedirect;
++ }
++ else if (car == Qsave_under)
++ {
++ attributes->save_under = rep_NILP(rep_CDR(tem)) ? False : True;
++ attributesMask |= CWSaveUnder;
++ }
++ else if ((car == Qevent_mask) && rep_LISTP(rep_CDR(tem)))
++ {
++ repv evl = rep_CDR (tem);
++ attributes->event_mask = 0;
++ while (rep_CONSP (evl)) {
++ int mask = x_symbol_match (rep_CAR (evl), x_event_mask_matches);
++ if (mask != -1)
++ attributes->event_mask |= mask;
++ evl = rep_CDR (evl);
++ }
++ attributesMask |= CWEventMask;
++ }
+ }
+
+ attrs = rep_CDR (attrs);
+@@ -567,32 +744,265 @@
+ return attributesMask;
+ }
+
++/* inefficient */
++static x_value_str x_event_type_matches[] = {
++ { KeyPress, "key-press" },
++ { KeyRelease, "key-release" },
++ { ButtonPress, "button-press" },
++ { ButtonRelease, "button-release" },
++ { MotionNotify, "motion-notify" },
++ { EnterNotify, "enter-notify" },
++ { LeaveNotify, "leave-notify" },
++ { FocusIn, "focus-in" },
++ { FocusOut, "focus-out" },
++ { KeymapNotify, "keymap-notify" },
++ { Expose, "expose" },
++ { GraphicsExpose, "graphics-expose" },
++ { NoExpose, "no-expose" },
++ { VisibilityNotify, "visibility-notify" },
++ { CreateNotify, "create-notify" },
++ { DestroyNotify, "destroy-notify" },
++ { UnmapNotify, "unmap-notify" },
++ { MapNotify, "map-notify" },
++ { MapRequest, "map-request" },
++ { ReparentNotify, "reparent-notify" },
++ { ConfigureNotify, "configure-notify" },
++ { ConfigureRequest, "configure-request" },
++ { GravityNotify, "gravity-notify" },
++ { ResizeRequest, "resize-request" },
++ { CirculateNotify, "circulate-notify" },
++ { CirculateRequest, "circulate-request" },
++ { PropertyNotify, "property-notify" },
++ { SelectionClear, "selection-clear" },
++ { SelectionRequest, "selection-request" },
++ { SelectionNotify, "selection-notify" },
++ { ColormapNotify, "colormap-notify" },
++ { ClientMessage, "client-message" },
++ { MappingNotify, "mapping-notify" },
++ { 0, 0 }
++};
++
++static x_value_str x_crossing_mode_matches[] = {
++ { NotifyNormal, "notify-normal" },
++ { NotifyGrab, "notify-grab" },
++ { NotifyUngrab, "notify-ungrab" },
++ { 0, 0 }
++};
++
++static x_value_str x_crossing_detail_matches[] = {
++ { NotifyAncestor, "notify-ancestor" },
++ { NotifyVirtual, "notify-virtual" },
++ { NotifyInferior, "notify-inferior" },
++ { NotifyNonlinear, "notify-nonlinear" },
++ { NotifyNonlinearVirtual, "notify-nonlinear-virtual" },
++ { 0, 0 }
++};
++
++static x_value_str x_motion_is_hint_matches[] = {
++ { NotifyNormal, "notify-normal" },
++ { NotifyHint, "notify-hint" },
++ { 0, 0 }
++};
++
++static x_value_str x_button_matches[] = {
++ { Button1, "button-1" },
++ { Button2, "button-2" },
++ { Button3, "button-3" },
++ { Button4, "button-4" },
++ { Button5, "button-5" },
++ { 0, 0 }
++};
++
++static x_value_str x_state_matches[] = {
++ { Button1Mask, "button-1" },
++ { Button2Mask, "button-2" },
++ { Button3Mask, "button-3" },
++ { Button4Mask, "button-4" },
++ { Button5Mask, "button-5" },
++ { ShiftMask, "shift" },
++ { LockMask, "lock" },
++ { ControlMask, "control" },
++ { Mod1Mask, "mod-1" },
++ { Mod2Mask, "mod-2" },
++ { Mod3Mask, "mod-3" },
++ { Mod4Mask, "mod-4" },
++ { Mod5Mask, "mod-5" },
++ { 0, 0 }
++};
++
++static repv
++x_encode_keysym (unsigned int keycode, unsigned int state) {
++ KeySym sym = NoSymbol;
++ char *name;
++ if (state & ShiftMask)
++ sym = XKeycodeToKeysym (dpy, keycode, 1);
++ if (sym == NoSymbol)
++ sym = XKeycodeToKeysym (dpy, keycode, 0);
++ /* I don't reset the shift modifier!!! */
++ name = XKeysymToString (sym);
++ return name ? Fintern (rep_string_dup (name), Qnil) : Qnil;
++}
++
++#define ALIST_PRE(A,B,C) A = Fcons (Fcons (B, C), A)
++
++static repv x_window_or_int_from_id (Window window) {
++ repv tmp = x_window_from_id (window);
++ if (tmp == Qnil)
++ tmp = rep_MAKE_INT (window);
++ return tmp;
++}
++
++static repv
++x_encode_event (XEvent *ev)
++{
++ repv event = Qnil, data = Qnil;
++
++ ALIST_PRE (event, Qserial, rep_make_long_uint (ev->xany.serial));
++ ALIST_PRE (event, Qsend_event, ev->xany.send_event ? Qt : Qnil);
++ ALIST_PRE (event, Qwindow, x_window_from_id (ev->xany.window));
++
++ switch (ev->type) {
++ case KeyPress:
++ case KeyRelease:
++ ALIST_PRE (event, Qroot, x_window_or_int_from_id (ev->xkey.root));
++ ALIST_PRE (event, Qsubwindow, x_window_or_int_from_id (ev->xkey.subwindow));
++ ALIST_PRE (event, Qtime, rep_make_long_uint (ev->xkey.time));
++ ALIST_PRE (event, Qx, rep_MAKE_INT (ev->xkey.x));
++ ALIST_PRE (event, Qy, rep_MAKE_INT (ev->xkey.y));
++ ALIST_PRE (event, Qx_root, rep_MAKE_INT (ev->xkey.x_root));
++ ALIST_PRE (event, Qy_root, rep_MAKE_INT (ev->xkey.y_root));
++ ALIST_PRE (event, Qstate, x_valuemask_match (ev->xkey.state, x_state_matches));
++ ALIST_PRE (event, Qkeycode, x_encode_keysym (ev->xkey.keycode, ev->xkey.state));
++ ALIST_PRE (event, Qsame_screen, ev->xkey.same_screen ? Qt : Qnil);
++ break;
++
++ case ButtonPress:
++ case ButtonRelease:
++ ALIST_PRE (event, Qroot, x_window_or_int_from_id (ev->xbutton.root));
++ ALIST_PRE (event, Qsubwindow, x_window_or_int_from_id (ev->xbutton.subwindow));
++ ALIST_PRE (event, Qtime, rep_make_long_uint (ev->xbutton.time));
++ ALIST_PRE (event, Qx, rep_MAKE_INT (ev->xbutton.x));
++ ALIST_PRE (event, Qy, rep_MAKE_INT (ev->xbutton.y));
++ ALIST_PRE (event, Qx_root, rep_MAKE_INT (ev->xbutton.x_root));
++ ALIST_PRE (event, Qy_root, rep_MAKE_INT (ev->xbutton.y_root));
++ ALIST_PRE (event, Qstate, x_valuemask_match (ev->xbutton.state, x_state_matches));
++ ALIST_PRE (event, Qbutton, x_value_match (ev->xbutton.button, x_button_matches));
++ ALIST_PRE (event, Qsame_screen, ev->xbutton.same_screen ? Qt : Qnil);
++ break;
++
++ case MotionNotify:
++ ALIST_PRE (event, Qroot, x_window_or_int_from_id (ev->xmotion.root));
++ ALIST_PRE (event, Qsubwindow, x_window_or_int_from_id (ev->xmotion.subwindow));
++ ALIST_PRE (event, Qtime, rep_make_long_uint (ev->xmotion.time));
++ ALIST_PRE (event, Qx, rep_MAKE_INT (ev->xmotion.x));
++ ALIST_PRE (event, Qy, rep_MAKE_INT (ev->xmotion.y));
++ ALIST_PRE (event, Qx_root, rep_MAKE_INT (ev->xmotion.x_root));
++ ALIST_PRE (event, Qy_root, rep_MAKE_INT (ev->xmotion.y_root));
++ ALIST_PRE (event, Qstate, x_valuemask_match (ev->xmotion.state, x_state_matches));
++ ALIST_PRE (event, Qis_hint, x_value_match (ev->xmotion.is_hint, x_motion_is_hint_matches));
++ ALIST_PRE (event, Qsame_screen, ev->xmotion.same_screen ? Qt : Qnil);
++ break;
++
++ case EnterNotify:
++ case LeaveNotify:
++ ALIST_PRE (event, Qroot, x_window_or_int_from_id (ev->xcrossing.root));
++ ALIST_PRE (event, Qsubwindow, x_window_or_int_from_id (ev->xcrossing.subwindow));
++ ALIST_PRE (event, Qtime, rep_make_long_uint (ev->xcrossing.time));
++ ALIST_PRE (event, Qx, rep_MAKE_INT (ev->xcrossing.x));
++ ALIST_PRE (event, Qy, rep_MAKE_INT (ev->xcrossing.y));
++ ALIST_PRE (event, Qx_root, rep_MAKE_INT (ev->xcrossing.x_root));
++ ALIST_PRE (event, Qy_root, rep_MAKE_INT (ev->xcrossing.y_root));
++ ALIST_PRE (event, Qmode, x_value_match (ev->xcrossing.mode, x_crossing_mode_matches));
++ ALIST_PRE (event, Qdetail, x_value_match (ev->xcrossing.detail, x_crossing_detail_matches));
++ ALIST_PRE (event, Qsame_screen, ev->xcrossing.same_screen ? Qt : Qnil);
++ ALIST_PRE (event, Qfocus, ev->xcrossing.focus ? Qt : Qnil);
++ ALIST_PRE (event, Qstate, x_valuemask_match (ev->xcrossing.state, x_state_matches));
++ break;
++
++ case Expose:
++ ALIST_PRE (event, Qx, rep_MAKE_INT (ev->xexpose.x));
++ ALIST_PRE (event, Qy, rep_MAKE_INT (ev->xexpose.y));
++ ALIST_PRE (event, Qwidth, rep_MAKE_INT (ev->xexpose.width));
++ ALIST_PRE (event, Qheight, rep_MAKE_INT (ev->xexpose.height));
++ ALIST_PRE (event, Qcount, rep_MAKE_INT (ev->xexpose.count));
++ break;
++
++ case DestroyNotify:
++ ALIST_PRE (event, Qevent, x_window_or_int_from_id (ev->xdestroywindow.event));
++ ALIST_PRE (event, Qwindow, x_window_or_int_from_id (ev->xdestroywindow.window));
++ break;
++
++ case ConfigureNotify:
++ ALIST_PRE (event, Qevent, x_window_or_int_from_id (ev->xconfigure.event));
++ ALIST_PRE (event, Qwindow, x_window_or_int_from_id (ev->xconfigure.window));
++ ALIST_PRE (event, Qx, rep_MAKE_INT (ev->xconfigure.x));
++ ALIST_PRE (event, Qy, rep_MAKE_INT (ev->xconfigure.y));
++ ALIST_PRE (event, Qwidth, rep_MAKE_INT (ev->xconfigure.width));
++ ALIST_PRE (event, Qheight, rep_MAKE_INT (ev->xconfigure.height));
++ ALIST_PRE (event, Qborder_width, rep_MAKE_INT (ev->xconfigure.border_width));
++ ALIST_PRE (event, Qabove, x_window_or_int_from_id (ev->xconfigure.above));
++ ALIST_PRE (event, Qoverride_redirect, ev->xconfigure.override_redirect ? Qt : Qnil);
++ break;
++
++ case ClientMessage:
++ ALIST_PRE (event, Qmessage_type, x_atom_symbol (ev->xclient.message_type));
++ ALIST_PRE (event, Qformat, rep_MAKE_INT (ev->xclient.format));
++ data = Qnil;
++ switch (ev->xclient.format) {
++ int i;
++
++ case 8: /* not a string because length unknown */
++ data = Fmake_vector (rep_MAKE_INT (20), Qnil);
++ for (i = 0; i < 20; ++ i)
++ rep_VECTI (data, i) = rep_MAKE_INT (ev->xclient.data.b[i]);
++ break;
++
++ case 16:
++ data = Fmake_vector (rep_MAKE_INT (10), Qnil);
++ for (i = 0; i < 10; ++ i)
++ rep_VECTI (data, i) = rep_MAKE_INT (ev->xclient.data.s[i]);
++ break;
++
++ case 32:
++ data = Fmake_vector (rep_MAKE_INT (5), Qnil);
++ for (i = 0; i < 5; ++ i) /* decoding atoms makes little sense */
++ rep_VECTI (data, i) = rep_MAKE_INT (ev->xclient.data.l[i]);
++ break;
++ }
++ ALIST_PRE (event, Qdata, data);
++ break;
++ }
++
++ /*
++ not done...
++ FocusIn FocusOut KeymapNotify GraphicsExpose NoExpose VisibilityNotify
++ CreateNotify UnmapNotify MapNotify MapRequest ReparentNotify
++ ConfigureRequest GravityNotify ResizeRequest CirculateNotify
++ CirculateRequest PropertyNotify SelectionClear SelectionRequest
++ SelectionNotify ColormapNotify MappingNotify
++ */
++
++ return event;
++}
++
+ static void
+ x_window_event_handler (XEvent *ev)
+ {
+ repv win = x_window_from_id (ev->xany.window);
+ if (win != Qnil && VX_DRAWABLE (win)->event_handler != Qnil)
+ {
+- repv type = Qnil, args = Qnil;
+- switch (ev->type)
+- {
+- case Expose:
+- /* Since we don't provide a method of detecting which
+- part of the window to redraw, ignore all but the last
+- expose event. (Another option is to set the clip
+- rectangle?) */
+- if (ev->xexpose.count == 0)
+- type = Qexpose;
+- break;
+-
+- /* XXX other event types..? */
+- }
+- if (type != Qnil)
+- {
+- args = Fcons (type, Fcons (win, args));
+- rep_funcall (VX_DRAWABLE (win)->event_handler, args, rep_FALSE);
+- }
++ repv type = x_value_match (ev->type, x_event_type_matches);
++ repv event = x_encode_event (ev);
++ repv args = Fcons (type, Fcons (win, Fcons (event, Qnil)));
++ /* Note that in Sawfish 0.34+, expose events whose count is non
++ * zero are silently suppressed. I don't do that because I
++ * supply the count. Which means that other people's expose
++ * handlers will be called multiply... */
++ rep_funcall (VX_DRAWABLE(win)->event_handler, args, rep_FALSE);
+ }
++
++ if (ev->type < LASTEvent && event_handlers[ev->type] != 0)
++ event_handlers[ev->type] (ev);
+ }
+
+ static Lisp_X_Window *
+@@ -608,10 +1018,37 @@
+ w->height = height;
+ w->is_window = w->is_pixmap = w->is_bitmap = 0;
+ w->event_handler = Qnil;
++ w->plist = Qnil;
+ XSaveContext (dpy, id, x_drawable_context, (XPointer) w);
+ return w;
+ }
+
++DEFUN ("x-reparent-window", Fx_reparent_window, Sx_reparent_window,
++ (repv win, repv parent, repv xy), rep_Subr3) /*
++::doc:sawfish.wm.util.x#x-create-window::
++x-create-window WINDOW PARENT (X . Y)
++
++Reparents a windows.
++::end:: */
++{
++ Window _win, _parent;
++ int _x, _y;
++
++ rep_DECLARE1(win, ANY_WINDOWP);
++ rep_DECLARE (2, parent, (parent == Qnil) || ANY_WINDOWP (parent));
++ rep_DECLARE (3, xy, rep_CONSP (xy)
++ && rep_INTP (rep_CAR (xy)) && rep_INTP (rep_CDR (xy)));
++
++ _win = window_from_arg (win);
++ _parent = (parent == Qnil) ? root_window : window_from_arg (parent);
++ _x = rep_INT (rep_CAR (xy));
++ _y = rep_INT (rep_CDR (xy));
++
++ XReparentWindow (dpy, _win, _parent, _x, _y);
++
++ return Qt;
++}
++
+ DEFUN ("x-create-window", Fx_create_window, Sx_create_window,
+ (repv xy, repv wh, repv bw, repv attrs, repv ev), rep_Subr5) /*
+ ::doc:sawfish.wm.util.x#x-create-window::
+@@ -619,12 +1056,15 @@
+
+ Creates a new X-WINDOW with the specified position, dimensions and
+ border width. ATTRS should be a list of cons cells mapping attributes
+-to values. Known attributes are `background' and `border-color'. The
+-window is created unmapped.
++to values. Known attributes include the symbols `x', `y',
++`width', `height', `border-width', `sibling' and `stack-mode'. Valid
++values for stack-mode are `above', `below', `top-if', `bottom-if' and
++`opposite'. The window is created unmapped.
+ ::end:: */
+ {
+ Lisp_X_Window *w;
+- Window id;
++ repv parent = Qnil;
++ Window id, _parent;
+ XSetWindowAttributes attributes;
+ long attributesMask;
+ int _x, _y, _w, _h, _bw;
+@@ -636,6 +1076,11 @@
+ rep_DECLARE3 (bw, rep_INTP);
+ rep_DECLARE4 (attrs, rep_LISTP);
+
++ if (rep_CONSP (attrs) && (Fassq (Qparent, attrs) != Qnil))
++ parent = rep_CDR (Fassq (Qparent, attrs));
++ if (!(_parent = window_from_arg (parent)))
++ _parent = root_window;
++
+ _x = rep_INT (rep_CAR (xy));
+ _y = rep_INT (rep_CDR (xy));
+ _w = rep_INT (rep_CAR (wh));
+@@ -643,19 +1088,21 @@
+ _bw = rep_INT (bw);
+
+ attributesMask = x_window_parse_attributes (&attributes, attrs);
+- attributes.override_redirect = True;
+- attributes.event_mask = ExposureMask;
+- attributes.colormap = image_cmap;
++ if (! (attributesMask & CWOverrideRedirect))
++ {
++ attributes.override_redirect = True;
++ attributesMask |= CWOverrideRedirect;
++ }
+ if (! (attributesMask & CWBorderPixel))
+ {
+ attributes.border_pixel = BlackPixel (dpy,
+ BlackPixel (dpy, screen_num));
+ attributesMask |= CWBorderPixel;
+ }
+-
+- attributesMask |= CWOverrideRedirect | CWEventMask | CWColormap;
++ attributes.colormap = image_cmap;
++ attributesMask |= CWOverrideRedirect;
+
+- id = XCreateWindow (dpy, root_window, _x, _y, _w, _h, _bw,
++ id = XCreateWindow (dpy, _parent, _x, _y, _w, _h, _bw,
+ image_depth, InputOutput, image_visual,
+ attributesMask, &attributes);
+
+@@ -708,6 +1155,37 @@
+ return rep_VAL (w);
+ }
+
++DEFUN("x-map-notify", Fx_map_notify, Sx_map_notify, (repv win), rep_Subr1) /*
++::doc:sawfish.wm.util.x#x-map-notify::
++x-map-notify X-WINDOW
++::end:: */
++{
++ XEvent fake = { MapNotify }; /* ouch the pain */
++ rep_DECLARE1(win, ANY_WINDOWP);
++
++ fake.xmap.window = window_from_arg (win);
++ fake.xmap.event = fake.xmap.window;
++
++ event_handlers[MapNotify] (&fake);
++
++ return Qt;
++}
++
++DEFUN("x-map-request", Fx_map_request, Sx_map_request, (repv win), rep_Subr1) /*
++::doc:sawfish.wm.util.x#x-map-request::
++x-map-request X-WINDOW
++::end:: */
++{
++ XEvent fake = { MapRequest }; /* ouch the pain */
++ rep_DECLARE1(win, ANY_WINDOWP);
++
++ fake.xmaprequest.window = window_from_arg (win);
++
++ event_handlers[MapRequest] (&fake);
++
++ return Qt;
++}
++
+ DEFUN ("x-map-window", Fx_map_window, Sx_map_window,
+ (repv win, repv unraised), rep_Subr2) /*
+ ::doc:sawfish.wm.util.x#x-map-window::
+@@ -722,6 +1200,38 @@
+ return Qt;
+ }
+
++DEFUN ("x-x-map-window", Fx_x_map_window, Sx_x_map_window, (repv win), rep_Subr1) /*
++::doc:sawfish.wm.util.x#x-x-map-window::
++x-x-map-window X-WINDOW
++
++The real XMapWindow.
++::end:: */
++{
++ rep_DECLARE1 (win, ANY_WINDOWP);
++ XMapWindow (dpy, window_from_arg (win));
++ return Qt;
++}
++
++DEFUN("x-map-raised", Fx_map_raised, Sx_map_raised, (repv win), rep_Subr1) /*
++::doc:sawfish.wm.util.x#x-map-raised::
++x-map-raised X-WINDOW
++::end:: */
++{
++ rep_DECLARE1(win, X_WINDOWP);
++ XMapRaised (dpy, VX_DRAWABLE(win)->id);
++ return Qt;
++}
++
++DEFUN("x-map-subwindows", Fx_map_subwindows, Sx_map_subwindows, (repv win), rep_Subr1) /*
++::doc:sawfish.wm.util.x#x-map-subwindows::
++x-map-subwindows X-WINDOW
++::end:: */
++{
++ rep_DECLARE1(win, X_WINDOWP);
++ XMapSubwindows (dpy, VX_DRAWABLE(win)->id);
++ return Qt;
++}
++
+ DEFUN ("x-unmap-window", Fx_unmap_window,
+ Sx_unmap_window, (repv win), rep_Subr1) /*
+ ::doc:sawfish.wm.util.x#x-unmap-window::
+@@ -733,6 +1243,50 @@
+ return Qt;
+ }
+
++DEFUN("x-unmap-subwindows", Fx_unmap_subwindows, Sx_unmap_subwindows, (repv win), rep_Subr1) /*
++::doc:sawfish.wm.util.x#x-unmap-subwindows::
++x-unmap-subwindows X-WINDOW
++::end:: */
++{
++ rep_DECLARE1(win, X_WINDOWP);
++ XUnmapSubwindows (dpy, VX_DRAWABLE(win)->id);
++ return Qt;
++}
++
++DEFUN("x-configure-request", Fx_configure_request, Sx_configure_request, (repv window, repv attrs), rep_Subr2) /*
++::doc:sawfish.wm.util.x#x-configure-request::
++x-configure-request WINDOW ATTRS
++::end:: */
++{
++ XWindowChanges changes;
++ long changesMask;
++
++ rep_DECLARE1(window, X_WINDOWP);
++ rep_DECLARE2(attrs, rep_LISTP);
++
++ changesMask = x_window_parse_changes (&changes, attrs);
++
++ if (changesMask)
++ {
++ XEvent fake = { ConfigureRequest };
++
++ fake.xconfigurerequest.display = dpy;
++ fake.xconfigurerequest.window = VX_DRAWABLE(window)->id;
++ fake.xconfigurerequest.x = changes.x;
++ fake.xconfigurerequest.y = changes.y;
++ fake.xconfigurerequest.width = changes.width;
++ fake.xconfigurerequest.height = changes.height;
++ fake.xconfigurerequest.border_width = changes.border_width;
++ fake.xconfigurerequest.above = changes.sibling;
++ fake.xconfigurerequest.detail = changes.stack_mode;
++ fake.xconfigurerequest.value_mask = changesMask;
++
++ event_handlers[ConfigureRequest] (&fake);
++ }
++
++ return Qt;
++}
++
+ DEFUN ("x-configure-window", Fx_configure_window,
+ Sx_configure_window, (repv window, repv attrs), rep_Subr2) /*
+ ::doc:sawfish.wm.util.x#x-configure-window::
+@@ -740,20 +1294,22 @@
+
+ Reconfigures the X-WINDOW. ATTRS should be an alist mapping attribute
+ names to values. Known attributes include the symbols `x', `y',
+-`width', `height' and `border-width'.
++`width', `height', `border-width', `sibling' and `stack-mode'. Valid
++values for stack-mode are `above', `below', `top-if', `bottom-if' and
++`opposite'.
+ ::end:: */
+ {
+ XWindowChanges changes;
+ long changesMask;
+
+- rep_DECLARE1 (window, X_WINDOWP);
++ rep_DECLARE1 (window, ANY_WINDOWP);
+ rep_DECLARE2 (attrs, rep_LISTP);
+
+ changesMask = x_window_parse_changes (&changes, attrs);
+
+ if (changesMask)
+ {
+- XConfigureWindow (dpy, VX_DRAWABLE (window)->id,
++ XConfigureWindow (dpy, window_from_arg (window),
+ changesMask, &changes);
+ x_window_note_changes (VX_DRAWABLE (window), changesMask, &changes);
+ }
+@@ -774,20 +1330,118 @@
+ XSetWindowAttributes attributes;
+ long attributesMask;
+
+- rep_DECLARE1 (window, X_WINDOWP);
++ rep_DECLARE1 (window, ANY_WINDOWP);
+ rep_DECLARE2 (attrs, rep_LISTP);
+
+ attributesMask = x_window_parse_attributes (&attributes, attrs);
+
+ if (attributesMask)
+ {
+- XChangeWindowAttributes (dpy, VX_DRAWABLE (window)->id,
++ XChangeWindowAttributes (dpy, window_from_arg (window),
+ attributesMask, &attributes);
+ }
+
+ return Qt;
+ }
+
++DEFUN("x-x-raise-window", Fx_x_raise_window, Sx_x_raise_window, (repv window), rep_Subr1) /*
++::doc:sawfish.wm.util.x#x-x-raise-window::
++x-x-raise-window WINDOW
++
++The real XRaiseWindow. Raises the X-WINDOW.
++::end:: */
++{
++ rep_DECLARE1(window, X_WINDOWP);
++
++ XRaiseWindow (dpy, VX_DRAWABLE(window)->id);
++
++ return Qt;
++}
++
++DEFUN("x-x-lower-window", Fx_x_lower_window, Sx_x_lower_window, (repv window), rep_Subr1) /*
++::doc:sawfish.wm.util.x#x-x-lower-window::
++x-x-lower-window WINDOW
++
++The real XLowerWindow. Lowers the X-WINDOW.
++::end:: */
++{
++ rep_DECLARE1(window, X_WINDOWP);
++
++ XLowerWindow (dpy, VX_DRAWABLE(window)->id);
++
++ return Qt;
++}
++
++DEFUN("x-circulate-subwindows", Fx_circulate_subwindows, Sx_circulate_subwindows, (repv window, repv direction), rep_Subr2) /*
++::doc:sawfish.wm.util.x#x-circulate-subwindows::
++x-circulate-subwindows WINDOW DIRECTION
++
++Circulates the subwindows of the X-WINDOW in DIRECTION
++for either `raise-lowest' or `lower-highest'.
++::end:: */
++{
++ int _direction;
++
++ rep_DECLARE1(window, X_WINDOWP);
++ rep_DECLARE(2, direction, (direction == Qraise_lowest) || (direction == Qlower_highest));
++ _direction = (direction == Qraise_lowest) ? RaiseLowest : LowerHighest;
++
++ XCirculateSubwindows (dpy, VX_DRAWABLE(window)->id, _direction);
++
++ return Qt;
++}
++
++DEFUN("x-circulate-subwindows-up", Fx_circulate_subwindows_up, Sx_circulate_subwindows_up, (repv window), rep_Subr1) /*
++::doc:sawfish.wm.util.x#x-circulate-subwindows-up::
++x-circulate-subwindows-up WINDOW
++
++Circulates up the subwindows of the X-WINDOW.
++::end:: */
++{
++ rep_DECLARE1(window, X_WINDOWP);
++
++ XCirculateSubwindowsUp (dpy, VX_DRAWABLE(window)->id);
++
++ return Qt;
++}
++
++DEFUN("x-circulate-subwindows-down", Fx_circulate_subwindows_down, Sx_circulate_subwindows_down, (repv window), rep_Subr1) /*
++::doc:sawfish.wm.util.x#x-circulate-subwindows-down::
++x-circulate-subwindows-down WINDOW
++
++Circulates down the subwindows of the X-WINDOW.
++::end:: */
++{
++ rep_DECLARE1(window, X_WINDOWP);
++
++ XCirculateSubwindowsDown (dpy, VX_DRAWABLE(window)->id);
++
++ return Qt;
++}
++
++DEFUN("x-restack-windows", Fx_restack_windows, Sx_restack_windows, (repv list), rep_Subr1) /*
++::doc:sawfish.wm.util.x#x-restack-windows::
++x-restack-windows LIST
++
++Restacks the LIST of X-WINDOWs.
++::end:: */
++{
++ Window *windows;
++ int n = 0;
++
++ rep_DECLARE1(list, rep_LISTP);
++
++ windows = alloca (rep_INT (Flength (list)) * sizeof (Window));
++ while (rep_CONSP (list)) {
++ if (X_WINDOWP (rep_CAR (list)))
++ windows[n ++] = VX_DRAWABLE (rep_CAR (list))->id;
++ list = rep_CDR (list);
++ }
++ XRestackWindows (dpy, windows, n);
++
++ return Qt;
++}
++
+ DEFUN ("x-destroy-drawable", Fx_destroy_drawable,
+ Sx_destroy_drawable, (repv drawable), rep_Subr1) /*
+ ::doc:sawfish.wm.util.x#x-destroy-drawable::
+@@ -959,6 +1613,268 @@
+ }
+
+
++/* Lisp property functions */
++
++DEFUN ("x-window-put", Fx_window_put, Sx_window_put, (repv window, repv key, repv value), rep_Subr3) /*
++::doc:sawfish.wm.util.x#x-window-put::
++x-window-put WINDOW KEY VALUE
++
++Stores the specified VALUE in the specified WINDOW under the specified
++(symbolic) KEY.
++::end:: */
++{
++ repv plist, ptr;
++
++ rep_DECLARE1(window, X_WINDOWP);
++ rep_DECLARE2(key, rep_SYMBOLP);
++
++ ptr = plist = VX_DRAWABLE(window)->plist;
++ while (ptr != Qnil) {
++ repv cons = rep_CAR (ptr);
++ if (rep_CAR (cons) == key) {
++ rep_CDR (cons) = value;
++ return Qt;
++ }
++ ptr = rep_CDR (ptr);
++ }
++ VX_DRAWABLE(window)->plist = Fcons (Fcons (key, value), plist);
++
++ return Qt;
++}
++
++DEFUN ("x-window-get", Fx_window_get, Sx_window_get, (repv window, repv key), rep_Subr2) /*
++::doc:sawfish.wm.util.x#x-window-get::
++x-window-get WINDOW KEY
++
++Gets the value stored in the specified WINDOW under the specified
++(symbolic) KEY.
++::end:: */
++{
++ repv plist, ptr;
++
++ rep_DECLARE1(window, X_WINDOWP);
++ rep_DECLARE2(key, rep_SYMBOLP);
++
++ ptr = plist = VX_DRAWABLE(window)->plist;
++ while (ptr != Qnil) {
++ repv cons = rep_CAR (ptr);
++ if (rep_CAR (cons) == key)
++ return rep_CDR (cons);
++ ptr = rep_CDR (ptr);
++ }
++
++ return Qnil;
++}
++
++
++/* X property functions */
++
++DEFUN("x-set-text-property", Fx_set_text_property, Sx_set_text_property, (repv window, repv textv, repv property), rep_Subr3) /*
++::doc:sawfish.wm.util.x#x-set-text-property::
++x-set-text-property X-WINDOW TEXTV PROPERTY
++
++Sets the specified PROPERTY on the specified X-WINDOW to the specified
++value TEXTV, a vector of strings.
++::end:: */
++{
++ Atom _prop;
++ int i, n;
++ char **_textv;
++ XTextProperty textprop;
++
++ rep_DECLARE1 (window, X_WINDOWP);
++ rep_DECLARE2 (textv, rep_VECTORP);
++ n = rep_VECT_LEN (textv);
++ for (i = 0; i < n; ++ i)
++ rep_DECLARE (2, textv, rep_STRINGP (rep_VECTI (textv, i)));
++ rep_DECLARE3 (property, rep_SYMBOLP);
++
++ _prop = x_symbol_atom (property);
++ _textv = alloca (n * sizeof (char *));
++ for (i = 0; i < n; ++ i)
++ _textv[i] = rep_STR (rep_VECTI (textv, i));
++ if (!XStringListToTextProperty (_textv, n, &textprop))
++ return Qnil;
++
++ XSetTextProperty (dpy, VX_DRAWABLE(window)->id, &textprop, _prop);
++ XFree (textprop.value);
++
++ return Qt;
++}
++
++DEFUN("x-get-text-property", Fx_get_text_property, Sx_get_text_property, (repv window, repv property), rep_Subr2) /*
++::doc:sawfish.wm.util.x#x-get-text-property::
++x-get-text-property X-WINDOW PROPERTY
++
++Gets the specified PROPERTY of the specified X-WINDOW as a vector
++of strings.
++::end:: */
++{
++ Atom _prop;
++ XTextProperty textprop;
++ int i, n;
++ char **_textv;
++ repv textv;
++
++ rep_DECLARE1 (window, ANY_WINDOWP);
++ rep_DECLARE2 (property, rep_SYMBOLP);
++
++ _prop = x_symbol_atom (property);
++ if (!XGetTextProperty (dpy, window_from_arg (window), &textprop, _prop))
++ return Qnil;
++ if (!XTextPropertyToStringList (&textprop, &_textv, &n)) {
++ XFree (textprop.value);
++ return Qnil;
++ }
++ XFree (textprop.value);
++ textv = Fmake_vector (rep_MAKE_INT (n), Qnil);
++ for (i = 0; i < n; ++ i)
++ rep_VECTI (textv, i) = rep_string_dup (_textv[i]);
++ XFreeStringList (_textv);
++
++ return textv;
++}
++
++DEFUN("x-list-properties", Fx_list_properties, Sx_list_properties, (repv window), rep_Subr1) /*
++::doc:sawfish.wm.util.x#x-list-properties::
++x-list-properties X-WINDOW
++
++Returns a list of the properties of the specified X-WINDOW.
++::end:: */
++{
++ Atom *atoms;
++ char **_props;
++ repv props = Qnil;
++ int i, n;
++
++ rep_DECLARE1 (window, X_WINDOWP);
++
++ atoms = XListProperties (dpy, VX_DRAWABLE(window)->id, &n);
++ if (!atoms)
++ return Qnil;
++ _props = alloca (n * sizeof (char *));
++ if (!XGetAtomNames (dpy, atoms, n, _props)) {
++ XFree (atoms);
++ return Qnil;
++ }
++ XFree (atoms);
++ for (i = n - 1; i >= 0; -- i)
++ props = Fcons (Fintern (rep_string_dup (_props[i]), Qnil), props);
++ for (i = 0; i < n; ++ i)
++ XFree (_props[i]);
++
++ return props;
++}
++
++static x_str_value x_change_property_mode_matches[] = {
++ { "prop-mode-replace", PropModeReplace },
++ { "prop-mode-prepend", PropModePrepend },
++ { "prop-mode-append", PropModeAppend },
++ { 0, 0 }
++};
++
++#define nDECLARE(index,arg, assert) {\
++ rep_DECLARE (index, args, rep_CONSP (args));\
++ arg = rep_CAR (args);\
++ args = rep_CDR (args);\
++ rep_DECLARE (index, arg, assert);\
++}
++
++DEFUN("x-change-property", Fx_change_property, Sx_change_property, (repv args), rep_SubrN) /*
++::doc:sawfish.wm.util.x#x-change-property::
++x-change-property X-WINDOW PROPERTY TYPE FORMAT MODE DATAV
++
++Sets the specified PROPERTY in the specified X-WINDOW to the
++specified TYPE vector value DATAV in format FORMAT. MODE can be
++`prop-mode-replace', `prop-mode-prepend' or `prop-mode-append'.
++::end:: */
++{
++ repv window, property, type, format, mode, datav;
++ Window _window;
++ Atom _property, _type;
++ int _format, _mode;
++ void *_data;
++ int i, n;
++
++ nDECLARE (1, window, ANY_WINDOWP (window));
++ _window = window_from_arg (window);
++ nDECLARE (2, property, rep_SYMBOLP (property));
++ _property = x_symbol_atom (property);
++ nDECLARE (3, type, rep_SYMBOLP (type));
++ _type = x_symbol_atom (type);
++ nDECLARE (4, format, rep_INTP (format));
++ _format = rep_INT (format);
++ rep_DECLARE (4, format, (_format == 8) || (_format == 16) || (_format == 32));;
++ nDECLARE (5, mode, rep_SYMBOLP (mode));
++ _mode = x_symbol_match (mode, x_change_property_mode_matches);
++ rep_DECLARE (5, mode, (_mode != -1));
++ nDECLARE (6, datav, rep_VECTORP (datav));
++ n = rep_VECT_LEN (datav);
++ for (i = 0; i < n; ++ i)
++ rep_DECLARE (6, datav, rep_INTP (rep_VECTI (datav, i)));
++
++ _data = alloca (n * 4);
++ for (i = 0; i < n; ++ i) {
++ int datum = rep_INT (rep_VECTI (datav, i));
++ if (format == 8)
++ ((char *) _data)[i] = (char) datum;
++ else if (format == 16)
++ ((short *) _data)[i] = (short) datum;
++ else
++ ((int *) _data)[i] = datum;
++ }
++ XChangeProperty (dpy, _window, _property, _type, _format, _mode, _data, n);
++
++ return Qt;
++}
++
++DEFUN("x-rotate-window-properties", Fx_rotate_window_properties, Sx_rotate_window_properties, (repv window, repv list, repv npos), rep_Subr3) /*
++::doc:sawfish.wm.util.x#x-rotate-window-properties::
++x-rotate-window-properties X-WINDOW PROPERTIES NPOS
++
++Rotates the values of the specified list of X-WINDOW PROPERTIES by NPOS.
++::end:: */
++{
++ Atom *atoms;
++ int n = 0;
++ int _npos;
++
++ rep_DECLARE1 (window, X_WINDOWP);
++ rep_DECLARE2 (list, rep_LISTP);
++ rep_DECLARE3 (npos, rep_INTP);
++
++ _npos = rep_INT (npos);
++
++ atoms = alloca (rep_INT (Flength (list)) * sizeof (Atom));
++ while (rep_CONSP (list)) {
++ if (rep_SYMBOLP (rep_CAR (list)))
++ atoms[n ++] = x_symbol_atom (rep_CAR (list));
++ list = rep_CDR (list);
++ }
++ XRotateWindowProperties (dpy, VX_DRAWABLE(window)->id, atoms, n, _npos);
++
++ return Qt;
++}
++
++DEFUN("x-delete-property", Fx_delete_property, Sx_delete_property, (repv window, repv property), rep_Subr2) /*
++::doc:sawfish.wm.util.x#x-delete-property::
++x-delete-property X-WINDOW PROPERTY
++
++Deletes the specified PROPERTY from the specified X-WINDOW.
++::end:: */
++{
++ Atom _prop;
++
++ rep_DECLARE1 (window, ANY_WINDOWP);
++ rep_DECLARE2 (property, rep_SYMBOLP);
++
++ _prop = x_symbol_atom (property);
++ XDeleteProperty (dpy, window_from_arg (window), _prop);
++
++ return Qt;
++}
++
++
+ /* Drawing functions */
+
+ DEFUN ("x-clear-window", Fx_clear_window,
+@@ -1425,6 +2341,7 @@
+ x_window_mark (repv obj)
+ {
+ rep_MARKVAL (VX_DRAWABLE (obj)->event_handler);
++ rep_MARKVAL (VX_DRAWABLE (obj)->plist);
+ }
+
+ static void
+@@ -1470,6 +2387,7 @@
+ rep_ADD_SUBR (Sx_create_root_xor_gc);
+ rep_ADD_SUBR (Sx_change_gc);
+ rep_ADD_SUBR (Sx_destroy_gc);
++ rep_ADD_SUBR (Sx_free_gc);
+ rep_ADD_SUBR (Sx_gc_p);
+
+ x_drawable_context = XUniqueContext ();
+@@ -1479,12 +2397,26 @@
+ x_window_sweep, x_window_mark,
+ 0, 0, 0, 0, 0, 0, 0);
+ rep_ADD_SUBR (Sx_create_window);
++ rep_ADD_SUBR (Sx_reparent_window);
+ rep_ADD_SUBR (Sx_create_pixmap);
+ rep_ADD_SUBR (Sx_create_bitmap);
++ rep_ADD_SUBR (Sx_map_request);
++ rep_ADD_SUBR (Sx_map_notify);
+ rep_ADD_SUBR (Sx_map_window);
++ rep_ADD_SUBR (Sx_x_map_window);
++ rep_ADD_SUBR (Sx_map_raised);
++ rep_ADD_SUBR (Sx_map_subwindows);
+ rep_ADD_SUBR (Sx_unmap_window);
++ rep_ADD_SUBR (Sx_unmap_subwindows);
++ rep_ADD_SUBR (Sx_configure_request);
+ rep_ADD_SUBR (Sx_configure_window);
+ rep_ADD_SUBR (Sx_change_window_attributes);
++ rep_ADD_SUBR (Sx_x_raise_window);
++ rep_ADD_SUBR (Sx_x_lower_window);
++ rep_ADD_SUBR (Sx_circulate_subwindows);
++ rep_ADD_SUBR (Sx_circulate_subwindows_up);
++ rep_ADD_SUBR (Sx_circulate_subwindows_down);
++ rep_ADD_SUBR (Sx_restack_windows);
+ rep_ADD_SUBR (Sx_destroy_drawable);
+ rep_ADD_SUBR (Sx_destroy_window);
+ rep_ADD_SUBR (Sx_drawable_p);
+@@ -1498,6 +2430,16 @@
+ rep_ADD_SUBR (Sx_window_back_buffer);
+ rep_ADD_SUBR (Sx_window_swap_buffers);
+
++ rep_ADD_SUBR (Sx_window_put);
++ rep_ADD_SUBR (Sx_window_get);
++
++ rep_ADD_SUBR (Sx_set_text_property);
++ rep_ADD_SUBR (Sx_get_text_property);
++ rep_ADD_SUBR (Sx_list_properties);
++ rep_ADD_SUBR (Sx_change_property);
++ rep_ADD_SUBR (Sx_rotate_window_properties);
++ rep_ADD_SUBR (Sx_delete_property);
++
+ rep_ADD_SUBR (Sx_clear_window);
+ rep_ADD_SUBR (Sx_draw_string);
+ rep_ADD_SUBR (Sx_draw_line);
+@@ -1534,6 +2476,36 @@
+ rep_INTERN (clip_mask);
+ rep_INTERN (clip_x_origin);
+ rep_INTERN (clip_y_origin);
++ rep_INTERN (sibling);
++ rep_INTERN (stack_mode);
++ rep_INTERN (override_redirect);
++ rep_INTERN (save_under);
++ rep_INTERN (event_mask);
++ rep_INTERN (parent);
++
++ rep_INTERN (serial);
++ rep_INTERN (send_event);
++ rep_INTERN (event);
++ rep_INTERN (window);
++ rep_INTERN (subwindow);
++ rep_INTERN (time);
++ rep_INTERN (x_root);
++ rep_INTERN (y_root);
++ rep_INTERN (state);
++ rep_INTERN (keycode);
++ rep_INTERN (same_screen);
++ rep_INTERN (button);
++ rep_INTERN (is_hint);
++ rep_INTERN (focus);
++ rep_INTERN (mode);
++ rep_INTERN (detail);
++ rep_INTERN (count);
++ rep_INTERN (message_type);
++ rep_INTERN (format);
++ rep_INTERN (data);
++ rep_INTERN (above);
++ rep_INTERN (raise_lowest);
++ rep_INTERN (lower_highest);
+
+ rep_INTERN (LineSolid);
+ rep_INTERN (LineOnOffDash);