diff options
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.2 | 1364 |
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); |