;;; xlib-xc.el --- X Connection. ;; Copyright (C) 2003-2005 by XWEM Org. ;; Author: Zajcev Evgeny ;; Created: 18 October 2003 ;; Keywords: xlib, xwem ;; X-CVS: $Id: xlib-xc.el,v 1.7 2005-04-04 19:55:29 lg Exp $ ;; X-URL: http://lgarc.narod.ru/xwem/index.html ;; This file is part of XWEM. ;; XWEM 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. ;; XWEM 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 ;;; Commentary: ;; ;;; Code: (eval-when-compile (require 'cl) (mapc (lambda (el) (autoload el "xlib-xwin")) '(X-Win-event-handlers X-Win-EventHandler-runall make-X-Rect X-Win-find-or-make X-Atom-find-or-make X-Win-p)) ) (require 'xlib-math) (require 'xlib-const) (defvar X-Dpy-dpys-list nil "List of all opened displays.") (defstruct X-Visual id class bits-per-rgb cmap-entries red-mask green-mask blue-mask) (defstruct X-Depth depth visuals) ; List of X-Visual (defstruct X-Screen dpy ; display root ; Root window colormap white-pixel black-pixel root-event-mask ; Event mask for root window visualid backingstores save-unders width height ; in pixels mwidth mheight ; in millimeters min-maps max-maps default-gc root-depth ; Root depth depths ; List of X-Depth ) (defstruct X-ScreenFormat depth bits-per-pixel scanline-pad) (defstruct (X-Dpy (:predicate X-Dpy-isxdpy-p)) proc ; process, which holds X connection log-buffer ; buffer for logs, when debugging is non-nil properties ; User defined plist ;; Protecting section (readings 0) ; non-zero mean we are in reading mode evq ; saved events queue, normally should be nil snd-queue ; Send queue, each call to ; `X-Dpy-send' adds data to ; this queue (parse-guess-dispatcher 'X-Dpy-parse-message-guess) (events-dispatcher 'X-Dpy-default-events-dispatcher) event-handlers ; event handlers, same as in X-Win message-buffer ;; X section name ; display name proto-maj proto-min ; major and minor numbers for X protocol vendor ; Vendor string min-keycode max-keycode ; keycodes allowed resource-base resource-mask (resource-id 1) (rseq-id 0) ; requests sequence number max-request-size ; Maximum request size allowed motion-bufsize byte-order ; Images byte order bitmap-scanline-unit bitmap-scanline-pad bitmap-bit-order formats ; List of X-ScreenFormat (default-screen 0) ; default screen number screens ; List of X-Screen error-hooks ; Hooks called when X error occurs ;; Various display lists atoms ; list of atoms windows ; list of windows fonts ; list of opened fonts extensions ; list of extensions ) (defmacro X-Dpy-put-property (xdpy prop val) "Put property PROP with value VAL in XDPY's properties list." `(setf (X-Dpy-properties ,xdpy) (plist-put (X-Dpy-properties ,xdpy) ,prop ,val))) (defmacro X-Dpy-get-property (xdpy prop) "Get property PROP from XDPY's properties list." `(plist-get (X-Dpy-properties ,xdpy) ,prop)) (defsetf X-Dpy-get-property X-Dpy-put-property) (defmacro X-Dpy-rem-property (xdpy prop) "Remove property PROP from XDPY's properties list." `(setf (X-Dpy-properties ,xdpy) (plist-remprop (X-Dpy-properties ,xdpy) ,prop))) (defsubst X-Dpy-EventHandler-add (dpy handler &optional priority evtypes-list) "To DPY's event handlers list add HANDLER." (setf (X-Dpy-event-handlers dpy) (X-EventHandler-add (X-Dpy-event-handlers dpy) handler priority evtypes-list))) (defsubst X-Dpy-EventHandler-isset (dpy handler &optional priority evtypes-list) "Return non-nil if on DPY event HANDLER is set." (X-EventHandler-isset (X-Dpy-event-handlers dpy) handler priority evtypes-list)) (defsubst X-Dpy-EventHandler-rem (dpy handler &optional priority evtypes-list) "From DPY's event handlers list, remove HANDLER." (setf (X-Dpy-event-handlers dpy) (X-EventHandler-rem (X-Dpy-event-handlers dpy) handler priority evtypes-list))) (defsubst X-Dpy-EventHandler-enable (dpy handler &optional priority evtypes-list) "In DPY's list of event handlers activate HANDLER." (X-EventHandler-enable (X-Dpy-event-handlers dpy) handler priority evtypes-list)) (defsubst X-Dpy-EventHandler-disable (dpy handler &optional priority evtypes-list) "In DPY's list of event handlers disable HANDLER." (X-EventHandler-disable (X-Dpy-event-handlers dpy) handler priority evtypes-list)) (defsubst X-Dpy-EventHandler-runall (dpy xev) "Run all DPY's event handlers on XEV. Signal `X-Events-stop' to stop events processing." (X-EventHandler-runall (X-Dpy-event-handlers dpy) xev)) ;; Formats operations (defun X-formatfind (xdpy depth) "On display XDPY find proper X-ScreenFormat for gived DEPTH." (let ((formats (X-Dpy-formats xdpy))) (while (and formats (not (= depth (X-ScreenFormat-depth (car formats))))) (setq formats (cdr formats))) (car formats))) (defun X-formatint (xdpy depth num) "On display XDPY convert NUM to string." (let ((fmt (X-formatfind xdpy depth)) bpp cfun) (if (not (X-ScreenFormat-p fmt)) "" (setq bpp (/ (X-ScreenFormat-bits-per-pixel fmt) 8)) (setq cfun (intern (format "int->string%d" bpp))) (funcall cfun num)))) (defun X-formatpad (xdpy depth str) "Return padded STR." (let ((fmt (X-formatfind xdpy depth)) bp) ;; XXX Can't deal with bits (if (not (X-ScreenFormat-p fmt)) ;; XXX Assume depth is 1 for bitmaps str (setq bp (/ (X-ScreenFormat-scanline-pad fmt) 8)) (concat str (make-string (% (- bp (% (length str) bp)) bp) ?\x00))))) (defun X-Dpy-p (xdpy &optional sig) "Return non-nil if XDPY is X display. If SIG is given and XDPY is not X display, SIG will be signaled." (let ((isdpy (X-Dpy-isxdpy-p xdpy))) (if (and (not isdpy) sig) (signal 'wrong-type-argument (list sig 'X-Dpy-p xdpy)) isdpy))) (defun X-Dpy-get-id (xdpy) "Get id to be used on X display XDPY." (X-Dpy-p xdpy 'X-Dpy-get-id) (let* ((newid (X-Dpy-resource-id xdpy)) (newword (float 0)) (bitcnt 0) ;bit counter in mask (idcnt 0) ;bit counter in id (servmask (X-Dpy-resource-mask xdpy)) ;service mask (our unique bits) (servbase (X-Dpy-resource-base xdpy))) ;service base (always set) ;; we can say <30 because top 3 bits are always 0 (while (< bitcnt 30) ;while there is more in the mask (if (Xtest servmask (Xmask bitcnt)) (progn (if (Xtest newid (Xmask idcnt)) ;set bit in id if it is ;set in the id value. (setq newword (Xmask-or newword (Xmask bitcnt)))) (setq idcnt (1+ idcnt)))) ;inc idcnt when we have a mask match (setq bitcnt (1+ bitcnt))) ;always inc bitmask cnter (incf (X-Dpy-resource-id xdpy)) ;inc to next id counter value (Xmask-or newword servbase))) ;return the id with base attached ;;; Process functions (defun X-Dpy-create-connection (dname dnum) "Create X connection to display with name DNAME and number DNUM." (let* ((xcon (open-network-stream (format "X-%s:%d" dname dnum) nil ; no buffer dname (+ 6000 dnum))) (xdpy (make-X-Dpy :proc xcon :name (format "%s:%d" dname dnum)))) (set-process-filter xcon 'X-Dpy-filter) (set-process-sentinel xcon 'X-Dpy-sentinel) (add-to-list 'X-Dpy-dpys-list xdpy) xdpy)) (defun X-Dpy-find-dpy (proc) "Find xdpy by process PROC." (let ((dpys X-Dpy-dpys-list)) (while (and dpys (not (eq proc (X-Dpy-proc (car dpys))))) (setq dpys (cdr dpys))) (car dpys))) (defun X-Dpy-filter (proc out) "Filter for X nework connections." (let ((xdpy (X-Dpy-find-dpy proc))) (X-Dpy-p xdpy 'X-Dpy-filter) (setf (X-Dpy-message-buffer xdpy) (concat (X-Dpy-message-buffer xdpy) out)) (funcall (X-Dpy-parse-guess-dispatcher xdpy) xdpy))) (defun X-Dpy-sentinel (proc &optional event) "Sentinel for X connections." (let ((xdpy (X-Dpy-find-dpy proc))) (X-Dpy-p xdpy 'X-Dpy-sentinel) (message "X: Removing process %S" proc) (sit-for 1) (delete-process proc) (setq X-Dpy-dpys-list (delq xdpy X-Dpy-dpys-list)))) (defun X-Dpy-close (xdpy) "Close connection associated with XDPY." (X-Dpy-p xdpy 'X-Dpy-close) (X-Dpy-send-flush xdpy) (X-Dpy-sentinel (X-Dpy-proc xdpy))) ;; Logging ;; Supported routines are: ;; x-display - display related ;; x-error - X Errors related ;; x-event - X Event related ;; x-tray - X tray related ;; x-misc - Misc stuff ;; x-record - RECORD extension (defun X-Dpy-set-log-routines (xdpy routines) "Set XDPY's log routines to ROUTINES." (X-Dpy-put-property xdpy 'log-routines routines)) (defun X-Dpy-get-log-routines (xdpy) "Return XDPY's log routines." (X-Dpy-get-property xdpy 'log-routines)) (defun X-Dpy-has-log-routine-p (xdpy routine) "Return non-nil if XDPY has log ROUTINE." (memq routine (X-Dpy-get-log-routines xdpy))) (defun X-Dpy-log (xdpy routine &rest args) "Put a ROUTINE's message in the in the log buffer specified by XDPY. If XDPY is nil, then put into current buffer. Log additional ARGS as well." (X-Dpy-p xdpy 'X-Dpy-log) (when (and (X-Dpy-log-buffer xdpy) (X-Dpy-has-log-routine-p xdpy routine) (bufferp (get-buffer-create (X-Dpy-log-buffer xdpy)))) (with-current-buffer (get-buffer-create (X-Dpy-log-buffer xdpy)) (save-excursion (goto-char (point-min)) (insert (format "%d %S: " (nth 1 (current-time)) routine)) (insert (apply 'format (mapcar 'eval args))) (insert "\n"))))) (defun X-Dpy-log-verbatim (xdpy arg) (X-Dpy-p xdpy 'X-Dpy-log-verbatim) (when (bufferp (X-Dpy-log-buffer xdpy)) (with-current-buffer (X-Dpy-log-buffer xdpy) (goto-char (point-min)) (insert "[" arg "]" "\n")) )) ;;; Sending/receiving functions (defun X-Dpy-send-flush (xdpy) "Send XDPY's send buffer to X server." (process-send-string (X-Dpy-proc xdpy) (mapconcat 'identity (nreverse (X-Dpy-snd-queue xdpy)) "")) (setf (X-Dpy-snd-queue xdpy) nil)) (defun X-Dpy-send (xdpy s) "Send the X server DPY the string S. Increase request id rseq-id. There is special mode when we are collecting X output to send it all at once." (setf (X-Dpy-snd-queue xdpy) (cons s (X-Dpy-snd-queue xdpy))) (enqueue-eval-event 'X-Dpy-send-flush xdpy) ;; increase request sequence number (incf (X-Dpy-rseq-id xdpy))) ;;; Sending section (defmacro X-Force-char-num (maybechar) "Force MAYBECHAR to be a number for XEmacs platform." ;; This is an annoying XEmacs problem To bad it slows down ;; Emacs too. (if (fboundp 'characterp) (list 'if (list 'characterp maybechar) (list 'setq maybechar (list 'char-to-int maybechar))))) (defconst X-byte-order ?l "Byte order used by emacs X. B MSB, l LSB.") (defconst X-protocol-minor-version 0 "Minor version of client.") (defconst X-protocol-major-version 11 "Major version of client.") (defconst X-client-to-open (list [1 X-byte-order] [1 0] ;unused [2 X-protocol-major-version] [2 X-protocol-minor-version] [2 0] ;auth name [2 0] ;auth data [2 0] ;unused ;; No auth name or data, so empty ) "XStruct list of sizes when opening a connection.") (defun X-Create-message (message-s &optional pad-notneed) "Takes the MESSAGE-S structure and builds a net string. MESSAGE-S is a list of vectors and symbols which formulate the message to be sent to the XServer. Each vector is of this form: [ SIZE VALUE ] SIZE is the number of BYTES used by the message. VALUE is the lisp object whose value is to take up SIZE bytes. If VALUE or SIZE is a symbol or list, extract that elements value. If the resulting value is still a list or symbol, extract it's value until it is no longer a symbol or a list. If VALUE is a number, massage it to the correct size. If VALUE is a string, append that string verbatum. If VALUE is nil, fill it with that many NULL characters. When PAD-NOTNEED is non-nil, then do not pad to 4 bytes." (let ((gc-cons-threshold most-positive-fixnum) ;inhibit gc'ing (news nil) (ts nil) (tvec nil) (tval nil) (tlen nil)) (while message-s (setq tvec (car message-s)) (setq tval (aref tvec 1)) (setq tlen (aref tvec 0)) ;; Check for symbols, or symbols containing symbols. (while (and tlen (or (listp tlen) (symbolp tlen))) (setq tlen (eval tlen))) ;; Check for symbols, or symbols containing symbols. (while (and (not (null tval)) ; nil symbol allowed (not (eq tval t)) ; t symbol allowed (or (listp tval) (symbolp tval))) (setq tval (eval tval))) ;; Fix XEmacs 20 broken characters (X-Force-char-num tval) ;; Numbers, put in. (cond ;; numbers get converted based on size. ((numberp tval) (cond ((= tlen 1) (setq ts (int->string1 tval))) ((= tlen 2) (setq ts (int->string tval))) ((= tlen 4) (setq ts (int->string4 tval))) (t (error "Wrong size for a message part to be a number!")))) ;; strings get appended onto the end. ((stringp tval) (setq ts tval)) ;; nil is usually filler, so stuff on some 0s ((eq tval nil) (setq ts (make-string tlen ?\x00))) ;; t is alias for True ((eq tval t) (setq ts (concat (make-string (- tlen 1) ?\x00) (make-string 1 ?\x01)))) ;; some sort of error (t (error "Invalid type to be put into an Xmessage"))) (setq ts (concat ts "\0\0\0\0")) ; make sure we fill length req. (setq ts (substring ts 0 tlen)) (setq news (concat news ts)) (setq message-s (cdr message-s))) ;; pad the message (if (and (not pad-notneed) (/= (% (length news) 4) 0)) (let ((s "\0\0\0\0")) (setq news (concat news (substring s 0 (- 4 (% (length news) 4))))))) news)) ;;;; NEW stuff, X types declarations ;; Not yet workable. ;; Why is this needed? Gives flexibility in implementing and ;; accessing X server and its resources. ;; Autogenerator can be written, which will generate types according ;; to proto.TXT or other papers. (defmacro define-X-type (type type-description) "Define new X value type. TYPE-DESCRIPTION is list where car of it is one of: `type' - Specifies static type, next values are - LENGTH VALUE-PACKER VALUE-EXTRACTOR. `resource' - Specifies some resource which has PREDICATE and ID-EXTRACTOR functions. `alias' - Alias to some already defined type. `enum' - for use by SETofXXXX types. `struct' - Define stucture. `or' - One of other type. " `(put (quote ,type) 'X-type-description ,type-description)) (defun X-type-pack (dpy type val) (let* ((xtd (or (and (listp type) type) (get type 'X-type-description))) (xt (car xtd))) (cond ((and (eq xt 'resource) (funcall (cadr xtd) val)) (int32->string (funcall (caddr xtd) val))) ((eq xt 'type) (funcall (caddr xtd) val)) ((and (eq xt 'enum) (memq val (cddr xtd))) (int->string val)) ((eq xt 'alias) (X-type-pack dpy (cadr xtd) val)) ((eq xt 'listof) (apply 'concat (mapcar #'(lambda (el) (X-type-pack dpy (cadr xtd) el)) val))) ((eq xt 'setof) (funcall (cond ((= (cadr xtd) 1) 'int->string1) ((= (cadr xtd) 2) 'int->string2) ((= (cadr xtd) 4) 'int->string4)) (apply 'Xmask-or val))) ((eq xt 'struct) (apply 'concat (mapcar #'(lambda (tt) (X-type-pack dpy (cdr tt) (funcall (car tt) val))) (cddr xt)))) ((eq xt 'or) (setq xt (cdr xt)) (let (orval) (while (and xt (not orval)) (setq orval (X-type-pack dpy (car xt) val) xt (cdr xt))) orval))))) (defun X-type-extract (dpy type &optional llen) (let* ((xtd (or (and (listp type) type) (get type 'X-type-description))) (xt (car xtd))) (cond ((eq xt 'resource) (funcall (cadddr xtd) dpy (string->int32 (X-Dpy-grab-bytes dpy 4)))) ((eq xt 'type) (funcall (cadddr xtd) (X-Dpy-grab-bytes dpy (cadr xtd)))) ((eq xt 'enum) (string->int (X-Dpy-grab-bytes dpy (cadr xtd)))) ((eq xt 'alias) (X-type-extract dpy (cadr xtd))) ((eq xt 'listof) (when (numberp llen) (let (rval) (while (> llen 0) (setq rval (X-type-extract dpy (cadr xtd))) (decf llen)) rval))) ((eq xt 'setof) (let ((smask (funcall (cond ((= (cadr xtd) 1) 'string1->int) ((= (cadr xtd) 2) 'string->int) ((= (cadr xtd) 4) 'string4->int)) (X-Dpy-grab-bytes dpy (cadr xtd)))) (dd (get (caddr xtd) 'X-type-description)) (cmask 1) rval) (when (eq (car dd) 'enum) (setq dd (cddr dd)) (while dd (when (Xtest smask cmask) (setq rval (cons (car dd) rval))) (setq cmask (lsh cmask 1) dd (cdr dd)))) rval)) ((eq xt 'struct) (let ((rval (funcall (cadr xtd)))) (mapc #'(lambda (tt) (eval `(setf (,(car tt) rval) (X-type-extract dpy ,(cdr tt))))) (cdr xtd)) rval))))) ;; Add some built-in types (define-X-type WINDOW '(resource X-Win-p X-Win-id X-Win-find-or-make)) (define-X-type PIXMAP '(resource X-Pixmap-p X-Pixmap-id X-Pixmap-find-or-make)) (define-X-type CURSOR '(resource X-Cursor-p X-Cursor-id X-Cursor-find-or-make)) (define-X-type FONT '(resource X-Font-p X-Font-id X-Font-find)) (define-X-type GCONTEXT '(resource X-Gc-p X-Gc-id ignore)) (define-X-type COLORMAP '(resource X-Colormap-p X-Colormap-id)) (define-X-type DRAWABLE '(or WINDOW PIXMAP)) (define-X-type FONTABLE '(or FONT GCONTEXT)) (define-X-type ATOM '(resource X-Atom-p X-Atom-id X-Atom-find-or-make)) (define-X-type VISUALID '(resource X-Visual-p X-Visual-id ignore)) (define-X-type BYTE '(type 1 char-to-string string-to-char)) (define-X-type INT8 '(type 1 x-int8->string x-string->int8)) (define-X-type INT16 '(type 2 x-int16->string x-string->int16)) (define-X-type INT32 '(type 4 x-int32->string x-string->int32)) (define-X-type CARD8 '(type 1 x-card8->string x-string->card8)) (define-X-type CARD16 '(type 2 x-card16->string x-string->card16)) (define-X-type CARD32 '(type 4 x-card32->string x-string->card32)) (define-X-type TIMESTAMP '(alias CARD32)) (define-X-type BITGRAVITY (list 'enum 1 X-ForgetGravity X-StaticGravity X-NorthWestGravity X-NorthGravity X-NorthEastGravity X-WestGravity X-CenterGravity X-EastGravity X-SouthWestGravity X-SouthGravity X-SouthEastGravity)) (define-X-type WINGRAVITY (list 'enum 1 X-UnmapGravity X-StaticGravity X-NorthWestGravity X-NorthGravity X-NorthEastGravity X-WestGravity X-CenterGravity X-EastGravity X-SouthWestGravity X-SouthGravity X-SouthEastGravity)) (define-X-type BOOL (list 'enum 1 X-True X-False)) (define-X-type EVENT (list 'enum 4 XM-KeyPress XM-KeyRelease XM-OwnerGrabButton XM-ButtonPress XM-ButtonRelease XM-EnterWindow XM-LeaveWindow XM-PointerMotion XM-PointerMotionHint XM-Button1Motion XM-Button2Motion XM-Button3Motion XM-Button4Motion XM-Button5Motion XM-ButtonMotion XM-Exposure XM-VisibilityChange XM-StructureNotify XM-ResizeRedirect XM-SubstructureNotify XM-SubstructureRedirect XM-FocusChange XM-PropertyChange XM-ColormapChange XM-KeymapState)) (define-X-type POINTEREVENT (list 'enum 4 XM-ButtonPress XM-ButtonRelease XM-EnterWindow XM-LeaveWindow XM-PointerMotion XM-PointerMotionHint XM-Button1Motion XM-Button2Motion XM-Button3Motion XM-Button4Motion XM-Button5Motion XM-ButtonMotion XM-KeymapState)) (define-X-type DEVICEEVENT (list 'enum 4 XM-KeyPress XM-KeyRelease XM-ButtonPress XM-ButtonRelease XM-PointerMotion XM-Button1Motion XM-Button2Motion XM-Button3Motion XM-Button4Motion XM-Button5Motion XM-ButtonMotion)) (define-X-type KEYSYM '(alias INT32)) (define-X-type KEYCODE '(alias CARD8)) (define-X-type BUTTON '(alias CARD8)) (define-X-type KEYMASK (list 'enum 2 X-Shift X-Lock X-Control X-Mod1 X-Mod2 X-Mod3 X-Mod4 X-Mod5)) (define-X-type BUTMASK (list 'enum 2 X-Button1 X-Button2 X-Button3 X-Button4 X-Button5)) (define-X-type KEYBUTMASK '(or KEYMASK BUTMASK)) (defun make-X-Char2B () (make-string 2 ?\x00)) (defun X-Char2B-byte0 (c2b) (aref c2b 0)) (defsetf X-Char2B-byte0 (c2b) (b) `(aset ,c2b 0 ,b)) (defun X-Char2B-byte1 (c2b) (aref c2b 1)) (defsetf X-Char2B-byte1 (c2b) (b) `(aset ,c2b 1 ,b)) (define-X-type CHAR2B '(struct X-Char2B (X-Char2B-byte0 . BYTE) (X-Char2B-byte1 . BYTE))) (define-X-type STRING8 '(listof BYTE)) (define-X-type STRING16 '(listof CHAR2B)) (define-X-type POINT '(struct X-Point (X-Point-x . INT16) (X-Point-y . INT16))) (define-X-type RECTANGLE '(struct X-Rect (X-Rect-x . INT16) (X-Rect-y . INT16) (X-Rect-width . CARD16) (X-Rect-height . CARD16))) (define-X-type ARC '(struct X-Arc (X-Arc-x . INT16) (X-Arc-y . INT16) (X-Arc-width . CARD16) (X-Arc-height . CARD16) (X-Arc-angle1 . INT16) (X-Arc-angle2 . INT16))) (defun make-X-Host () (vector nil nil)) (defun X-Host-family (h) (aref h 0)) (defsetf X-Host-family (h) (f) `(aset ,h 0 ,f)) (defun X-Host-address (h) (aref h 1)) (defsetf X-Host-address (h) (a) `(aset ,h 1 ,a)) (define-X-type HOST `(struct X-Host (X-Host-family . (enum 1 ,X-FamilyInternet ,X-FamilyDECnet ,X-FamilyChaos)) (X-Host-address . STRING8))) (defun X-Create-Message (message-s &optional pad-notneed) "Takes the MESSAGE-S structure and builds a net string. MESSAGE-S is a list of vectors and symbols which formulate the message to be sent to the XServer. Each vector is of this form: [ SIZE VALUE ] SIZE is the number of BYTES used by the message. VALUE is the lisp object whose value is to take up SIZE bytes. If VALUE or SIZE is a symbol or list, extract that elements value. If the resulting value is still a list or symbol, extract it's value until it is no longer a symbol or a list. If VALUE is a number, massage it to the correct size. If VALUE is a string, append that string verbatum. If VALUE is nil, fill it with that many NULL characters. When PAD-NOTNEED is non-nil, then do not pad to 4 bytes." (let ((gc-cons-threshold most-positive-fixnum) ;inhibit gc'ing (news "") ; resulting message (padlen 0) ; resulting message padlen (if needed) (tlen nil) (ttype nil) (tval nil)) (while message-s (if (= (length (car message-s)) 2) (setq tlen 1 ttype (aref (car message-s) 0) tval (aref (car message-s) 1)) (setq tlen (aref (car message-s) 0) ttype (aref (car message-s) 1) tval (aref (car message-s) 2))) ;; Check for symbols, or symbols containing symbols. (while (and (not (null tval)) ; nil symbol allowed (not (eq tval t)) ; t symbol allowed (or (listp tval) (symbolp tval))) (setq tval (eval tval))) (while (> tlen 0) (cond ((eq tval nil) (setq tval (make-string tlen ?\x00))) ((eq tval t) (setq tval (concat (make-string (- tlen 1) ?\x00) (make-string 1 ?\x01)))) (t (setq tval (X-type-pack nil ttype tval)))) (setq news (concat news tval)) (decf tlen)) (setq message-s (cdr message-s))) ;; pad the message (if (and (not pad-notneed) (/= (setq padlen (% (length news) 4)) 0)) (concat news (make-string (- 4 padlen) ?\x00)) news))) (defun X-Parse-Message (dpy message-s) ;; TODO: write me using `X-type-extract' ) (provide 'xlib-xc) ;;; xlib-xc.el ends here