• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
Aucun tag

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Japanese translation of message catalog for Sawfish Window-Manager


Commit MetaInfo

Révision2d04c16ab155d09e5f2508fe76394bcc751b13fc (tree)
l'heure2002-03-21 16:50:37
AuteurJohn Harper <jsh@src....>
CommiterJohn Harper

Message de Log

Merged changes from HEAD (up to current location of gnome-2-merged-HEAD tag)

Change Summary

Modification

--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,45 @@
1+2002-03-19 John Harper <jsh@unfactored.org>
2+
3+ * Merged changes from HEAD:
4+
5+ 2002-03-17 T?vo Leedj?v <toivo@linux.ee>
6+
7+ * po/et.po: Updated Estonian translation.
8+
9+ 2002-03-17 T?vo Leedj?v <toivo@linux.ee>
10+
11+ * po/et.po: Added Estonian translation from gnome-2 branch.
12+
13+ 2002-03-15 Valek Filippov <frob@df.ru>
14+
15+ * ru.po: updated russian translation.
16+
17+ 2002-02-28 Hasbullah Bin Pit <sebol@ikhlas.com>
18+
19+ * po/ms.po: Added Malay Translation from gnome-2 branch
20+
21+ 2002-02-20 John Harper <jsh@unfactored.org>
22+
23+ * configure.in: don't ever compile our own dlmalloc, it breaks
24+ on too many platforms
25+
26+ 2002-02-01 Kjartan Maraas <kmaraas@gnome.org>
27+
28+ * po/no.po: Updated Norwegian (bokm?) translation.
29+
30+ 2002-01-31 Simos Xenitellis <simos@hellug.gr>
31+
32+ * po/el.po: Updated Greek translation.
33+
34+ 2002-01-23 Peteris Krisjanis <peteris.krisjanis@ttc.lv>
35+
36+ * po/lv.po: Updated Latvian translation.
37+
38+ 2002-01-15 Wang Jian <lark@linux.net.cn>
39+
40+ * po/zh_CN.po: Updated Simplified Chinese translation by
41+ Wang Li <charlesw1234@163.com>.
42+
143 2002-03-17 T?vo Leedj?v <toivo@linux.ee>
244
345 * po/et.po: Updated Estonian translation.
@@ -66,7 +108,7 @@
66108
67109 2002-01-04 Pablo Saratxaga <pablo@mandrakesoft.com>
68110
69- * configure.in: Added "eu" to ALL_LINGUAS
111+ * configure.in: Added "eu" to ALL_LINGUAS
70112
71113 2001-12-17 Germ? Poo-Caama? <gpoo@ubiobio.cl>
72114
--- a/configure.in
+++ b/configure.in
@@ -249,25 +249,15 @@ else
249249 fi
250250 AC_SUBST(REP_GTK_GNOME)
251251
252-dnl Check for Doug Lea's malloc in libc, otherwise compile dlmalloc.c
252+dnl Check for Doug Lea's malloc in libc
253253 doug_lea_malloc=yes
254254 AC_CHECK_FUNC(malloc_get_state, , doug_lea_malloc=no)
255255 AC_CHECK_FUNC(malloc_set_state, , doug_lea_malloc=no)
256256 if test "$doug_lea_malloc" = "no"; then
257- dnl dlmalloc is broken on Tru64, and may be broken on some
258- dnl solaris platforms
259- case ${host} in
260- *-dec-osf*)
261- AC_DEFINE(LIBC_MALLOC)
262- ;;
263- *-sparc-sun*)
264- AC_DEFINE(LIBC_MALLOC)
265- ;;
266- *)
267- LIBOBJS="${LIBOBJS} dlmalloc.o"
268- AC_DEFINE(DOUG_LEA_MALLOC)
269- ;;
270- esac
257+ dnl We used to compile our own version of dlmalloc on most
258+ dnl platforms that didn't have it in their libc. But the list
259+ dnl of exceptions was growing too long..
260+ AC_DEFINE(LIBC_MALLOC)
271261 else
272262 AC_DEFINE(DOUG_LEA_MALLOC)
273263 AC_DEFINE(LIBC_MALLOC)
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,25 @@
1+2002-03-19 John Harper <jsh@unfactored.org>
2+
3+ * Merged changes from HEAD:
4+
5+ 2002-03-01 John Harper <jsh@pixelslut.com>
6+
7+ * windows.c (manage_windows): unmap the window before faking
8+ the call to the map-request event handler. Fixes #67601 (causes
9+ the expected map-notify event to be sent when we later map it)
10+
11+ 2002-02-17 John Harper <jsh@unfactored.org>
12+
13+ * windows.c (remove_window): check for w->id == 0 immediately
14+ before calling remove_from_stacking_list (). Avoids triggering
15+ an assertion on logout (since remove_window () may be called
16+ recursively from the error handler!)
17+
18+ 2002-01-24 John Harper <jsh@unfactored.org>
19+
20+ * frames.c: fixed definitions of Qtop and Qbottom. This bug
21+ must have existed forever!
22+
123 2002-01-10 Sander Vesik <sander.vesik@sun.com>
224
325 * image.c: gdk_pixbuf_new_from_file now takes two parameters
--- /dev/null
+++ b/src/frames.c
@@ -0,0 +1,1950 @@
1+/* frames.c -- window frame manipulation
2+ $Id$
3+
4+ Copyright (C) 1999, 2000 John Harper <john@dcs.warwick.ac.uk>
5+
6+ This file is part of sawmill.
7+
8+ sawmill is free software; you can redistribute it and/or modify it
9+ under the terms of the GNU General Public License as published by
10+ the Free Software Foundation; either version 2, or (at your option)
11+ any later version.
12+
13+ sawmill is distributed in the hope that it will be useful, but
14+ WITHOUT ANY WARRANTY; without even the implied warranty of
15+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+ GNU General Public License for more details.
17+
18+ You should have received a copy of the GNU General Public License
19+ along with sawmill; see the file COPYING. If not, write to
20+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21+
22+/* AIX requires this to be the first thing in the file. */
23+#ifdef HAVE_CONFIG_H
24+#include <config.h>
25+#endif
26+#ifndef __GNUC__
27+# if HAVE_ALLOCA_H
28+# include <alloca.h>
29+# else
30+# ifdef _AIX
31+ #pragma alloca
32+# else
33+# ifndef alloca /* predefined by HP cc +Olibcalls */
34+ char *alloca ();
35+# endif
36+# endif
37+# endif
38+#endif
39+
40+#include "sawmill.h"
41+#include <X11/Xutil.h>
42+#include <X11/Xresource.h>
43+#include <X11/extensions/shape.h>
44+#include <assert.h>
45+
46+static XID window_fp_context;
47+
48+int frame_part_type;
49+static struct frame_part *allocated_parts;
50+
51+DEFSYM(internal, "internal");
52+DEFSYM(tiled, "tiled");
53+DEFSYM(center, "center");
54+DEFSYM(right, "right");
55+DEFSYM(left, "left");
56+DEFSYM(top, "top");
57+DEFSYM(bottom, "bottom");
58+DEFSYM(text, "text");
59+DEFSYM(x_justify, "x-justify");
60+DEFSYM(y_justify, "y-justify");
61+DEFSYM(background, "background");
62+DEFSYM(foreground, "foreground");
63+DEFSYM(renderer, "renderer");
64+DEFSYM(render_scale, "render-scale");
65+DEFSYM(font, "font");
66+DEFSYM(width, "width");
67+DEFSYM(height, "height");
68+DEFSYM(left_edge, "left-edge");
69+DEFSYM(top_edge, "top-edge");
70+DEFSYM(right_edge, "right-edge");
71+DEFSYM(bottom_edge, "bottom-edge");
72+DEFSYM(cursor, "cursor");
73+DEFSYM(focused, "focused");
74+DEFSYM(highlighted, "highlighted");
75+DEFSYM(clicked, "clicked");
76+DEFSYM(inactive, "inactive");
77+DEFSYM(inactive_highlighted, "inactive-highlighted");
78+DEFSYM(inactive_clicked, "inactive-clicked");
79+DEFSYM(hide_client, "hide-client");
80+DEFSYM(class, "class");
81+DEFSYM(removable, "removable");
82+DEFSYM(removed_classes, "removed-classes");
83+DEFSYM(frame_part_classes, "frame-part-classes");
84+DEFSYM(override_frame_part_classes, "override-frame-part-classes");
85+DEFSYM(below_client, "below-client");
86+DEFSYM(scale_foreground, "scale-foreground");
87+DEFSYM(hidden, "hidden");
88+
89+static repv state_syms[fps_MAX];
90+
91+static bool frame_draw_mutex;
92+bool frame_state_mutex;
93+
94+
95+/* type hooks */
96+
97+static struct frame_part *
98+fp_new (Lisp_Window *win, repv alist)
99+{
100+ struct frame_part *fp = rep_ALLOC_CELL (sizeof (struct frame_part));
101+ rep_data_after_gc += sizeof (struct frame_part);
102+ memset (fp, 0, sizeof (struct frame_part));
103+ fp->car = frame_part_type;
104+ fp->win = win;
105+ fp->alist = alist;
106+ fp->local_alist = Qnil;
107+ fp->next_alloc = allocated_parts;
108+ allocated_parts = fp;
109+ return fp;
110+}
111+
112+static int
113+fp_cmp (repv w1, repv w2)
114+{
115+ return w1 != w2;
116+}
117+
118+static void
119+fp_prin (repv stream, repv win)
120+{
121+ char buf[128];
122+ sprintf (buf, "#<frame-part %lx>", VPART(win)->id);
123+ rep_stream_puts (stream, buf, -1, FALSE);
124+}
125+
126+static void
127+fp_mark (repv obj)
128+{
129+ struct frame_part *fp;
130+ for (fp = VPART(obj); fp != 0; fp = fp->next)
131+ {
132+ int i;
133+ rep_MARKVAL(fp->alist);
134+ rep_MARKVAL(fp->local_alist);
135+ rep_MARKVAL(rep_VAL(fp->win));
136+ for (i = 0; i < fps_MAX; i++)
137+ {
138+ rep_MARKVAL(fp->font[i]);
139+ rep_MARKVAL(fp->fg[i]);
140+ rep_MARKVAL(fp->bg[i]);
141+ }
142+ rep_MARKVAL(rep_VAL(fp->cursor));
143+ rep_MARKVAL(rep_VAL(fp->renderer));
144+ rep_MARKVAL(rep_VAL(fp->rendered_image));
145+ rep_MARKVAL(fp->drawn.font);
146+ rep_MARKVAL(fp->drawn.text);
147+ rep_MARKVAL(fp->drawn.x_justify);
148+ rep_MARKVAL(fp->drawn.y_justify);
149+ rep_MARKVAL(fp->drawn.fg);
150+ rep_MARKVAL(fp->drawn.bg);
151+ }
152+}
153+
154+static void
155+fp_sweep (void)
156+{
157+ struct frame_part *fp = allocated_parts;
158+ allocated_parts = 0;
159+ while (fp != 0)
160+ {
161+ struct frame_part *next = fp->next_alloc;
162+ if (!rep_GC_CELL_MARKEDP(rep_VAL(fp)))
163+ {
164+ assert (fp->next == 0);
165+ assert (fp->id == 0);
166+#if 0
167+ /* XXX This assertion has been reported to trigger (when opening
168+ ddd and acroread -- both motif apps?). I don't see how this
169+ happens but since fp->id is zero and fp->win will get gc'd,
170+ we're not going to leak any resources, so.. */
171+ assert (fp->win == 0);
172+#endif
173+ rep_FREE_CELL(fp);
174+ }
175+ else
176+ {
177+ fp->next_alloc = allocated_parts;
178+ allocated_parts = fp;
179+ rep_GC_CLR_CELL(rep_VAL(fp));
180+ }
181+ fp = next;
182+ }
183+}
184+
185+
186+/* building frames from component lists
187+
188+ build the frame from the list of components. Each element
189+ in the list is an alist representing one component of the
190+ frame, possible tags include:
191+
192+ class . SYMBOL
193+
194+ background . IMAGE-OR-COLOR
195+ background . (NORMAL FOCUSED HIGHLIGHTED CLICKED)
196+ background . ((STATE . VALUE) ...)
197+ foreground . COLOR
198+ foreground . (NORMAL FOCUSED HIGHLIGHTED CLICKED)
199+ foreground . ((STATE . VALUE) ...)
200+
201+ renderer . FUNCTION
202+ render-scale . INTEGER
203+
204+ text . STRING-OR-FUNCTION-OR-NIL
205+ x-justify . left OR right OR center OR NUMBER
206+ y-justify . top OR bottom OR center OR NUMBER
207+
208+ font . FONT
209+ font . (NORMAL FOCUSED HIGHLIGHTED CLICKED)
210+ font . ((STATE . FONT) ...)
211+
212+ left-edge . POSITION-REL-LEFT
213+ right-edge . POSITION-REL-RIGHT
214+ top-edge . POSITION-REL-TOP
215+ bottom-edge . POSITION-REL-BOTTOM
216+ height . PIXELS
217+ width . PIXELS
218+
219+ keymap . KEYMAP
220+ cursor . CURSOR-OR-CURSOR-DEF
221+
222+ below-client . t
223+ scale-foreground . t
224+
225+ STATE's are one of: inactive, focused, highlighted, clicked,
226+ inactive-highlighted, inactive-clicked.
227+
228+ Note that all numeric quantities may be defined dynamically by
229+ substituting a function */
230+
231+int
232+current_state (struct frame_part *fp)
233+{
234+ if (fp->clicked)
235+ {
236+ if (fp->win == focus_window)
237+ return fps_clicked;
238+ else
239+ return fps_inactive_clicked;
240+ }
241+ else if (fp->highlighted)
242+ {
243+ if (fp->win == focus_window)
244+ return fps_highlighted;
245+ else
246+ return fps_inactive_highlighted;
247+ }
248+ else if (fp->win == focus_window)
249+ return fps_focused;
250+ else
251+ return fps_inactive;
252+}
253+
254+/* Call FUN (ARG) with error protection in place. If an error occurs
255+ a message is printed, and ERROR-RETURN is returned, else just return
256+ the result of calling FUN. */
257+static repv
258+call_protectedly (repv (*fun)(repv), repv arg, repv error_return)
259+{
260+ rep_GC_root gc_error_return;
261+ repv result;
262+ rep_PUSHGC (gc_error_return, error_return);
263+ result = fun (arg);
264+ if (result == rep_NULL)
265+ {
266+ repv throw = rep_throw_value, stream;
267+ rep_throw_value = rep_NULL;
268+ stream = Fstderr_file();
269+ if (stream != rep_NULL)
270+ {
271+ rep_stream_puts (stream, "frame error: ", -1, rep_FALSE);
272+ if (rep_CAR (throw) == Qerror)
273+ throw = rep_CDR (throw);
274+ rep_print_val (stream, throw);
275+ rep_stream_putc (stream, '\n');
276+ }
277+ result = error_return;
278+ }
279+ rep_POPGC;
280+ return result;
281+}
282+
283+/* Call lisp function FUN with the single arg ARG, with error protection */
284+static repv
285+call_protectedly_1 (repv fun, repv arg, repv error_return)
286+{
287+ return call_protectedly (Ffuncall, rep_LIST_2 (fun, arg), error_return);
288+}
289+
290+static void
291+apply_mask (Drawable dest, int x_off, int y_off,
292+ int dest_width, int dest_height,
293+ Pixmap src, int src_width, int src_height)
294+{
295+ if (dest_width - x_off >= src_width
296+ && dest_height - y_off >= src_height)
297+ {
298+ /* No need for a temporary buffer */
299+ XShapeCombineMask (dpy, dest, ShapeBounding,
300+ x_off, y_off, src, ShapeUnion);
301+ }
302+ else
303+ {
304+ Pixmap tem = XCreatePixmap (dpy, src, dest_width - x_off,
305+ dest_height - y_off, 1);
306+ XGCValues gcv;
307+ GC gc = XCreateGC (dpy, tem, 0, &gcv);
308+ XCopyArea (dpy, src, tem, gc, 0, 0,
309+ dest_width - x_off, dest_height - y_off, 0, 0);
310+ XShapeCombineMask (dpy, dest, ShapeBounding,
311+ x_off, y_off, tem, ShapeUnion);
312+ XFreeGC (dpy, gc);
313+ XFreePixmap (dpy, tem);
314+ }
315+}
316+
317+/* Construct the frame window's shape mask from the union of all
318+ individual shapes (frame parts and the client window, if appropriate).
319+ If ATOMIC is true, then the frame shape is changed _once_ only, using
320+ a temporary buffer to construct the new shape, then copying it
321+ to the frame. */
322+void
323+set_frame_shapes (Lisp_Window *w, bool atomic)
324+{
325+ Window shape_win;
326+ int nrects, nparts;
327+ XRectangle *rects;
328+ struct frame_part *fp;
329+
330+ if (atomic)
331+ {
332+ XSetWindowAttributes wa;
333+ int wamask;
334+ wa.colormap = image_cmap;
335+ wa.border_pixel = BlackPixel (dpy, screen_num);
336+ wamask = CWColormap | CWBorderPixel;
337+ shape_win = XCreateWindow (dpy, root_window, -100, -100,
338+ w->frame_width, w->frame_height,
339+ 0, image_depth, InputOutput,
340+ image_visual, wamask, &wa);
341+ }
342+ else
343+ shape_win = w->frame;
344+
345+ nparts = 0;
346+ for (fp = w->frame_parts; fp != 0; fp = fp->next)
347+ nparts++;
348+ nrects = 0;
349+ rects = alloca (sizeof (XRectangle) * (nparts + 1));
350+
351+ rects[0].x = rects[0].y = 0;
352+ rects[0].width = w->frame_width;
353+ rects[0].height = w->frame_height;
354+ XShapeCombineRectangles (dpy, shape_win, ShapeBounding,
355+ 0, 0, rects, 1, ShapeSubtract, Unsorted);
356+
357+ if (!w->client_hidden)
358+ {
359+ if (w->shaped)
360+ {
361+ XShapeCombineShape (dpy, shape_win, ShapeBounding,
362+ -w->frame_x, -w->frame_y, w->id,
363+ ShapeBounding, ShapeSet);
364+ }
365+ else
366+ {
367+ rects[nrects].x = -w->frame_x;
368+ rects[nrects].y = -w->frame_y;
369+ rects[nrects].width = w->attr.width;
370+ rects[nrects].height = w->attr.height;
371+ nrects++;
372+ }
373+ }
374+
375+ for (fp = w->frame_parts; fp != 0 && !WINDOW_IS_GONE_P (w); fp = fp->next)
376+ {
377+ Pixmap pixmap, mask;
378+ int state = current_state (fp);
379+
380+ if (fp->width <= 0 || fp->height <= 0)
381+ continue;
382+
383+ if (IMAGEP(fp->bg[state]))
384+ {
385+ bool tiled = FALSE;
386+ Lisp_Image *image = VIMAGE(fp->bg[state]);
387+ repv tem;
388+
389+ tem = Fimage_get (rep_VAL(image), Qtiled);
390+ if (tem && tem != Qnil)
391+ tiled = TRUE;
392+
393+ if (tiled)
394+ {
395+ image_render (image, image_width (image), image_height (image),
396+ &pixmap, &mask);
397+ }
398+ else
399+ {
400+ image_render (image, fp->width, fp->height, &pixmap, &mask);
401+ }
402+
403+ if (mask != 0)
404+ {
405+ int width = !tiled ? fp->width : image_width (image);
406+ int height = !tiled ? fp->height : image_height (image);
407+ int x_off = fp->x - w->frame_x;
408+ int y_off = fp->y - w->frame_y;
409+
410+ apply_mask (shape_win, x_off, y_off,
411+ x_off + fp->width, y_off + fp->height,
412+ mask, width, height);
413+
414+ if (tiled)
415+ {
416+ int x = width, y = 0;
417+ while (y < fp->height)
418+ {
419+ while (x < fp->width)
420+ {
421+ apply_mask (shape_win, x_off + x, y_off + y,
422+ x_off + fp->width, y_off + fp->height,
423+ mask, width, height);
424+ x += width;
425+ }
426+ y += height;
427+ x = 0;
428+ }
429+ }
430+ }
431+ else
432+ {
433+ rects[nrects].x = fp->x - w->frame_x;
434+ rects[nrects].y = fp->y - w->frame_y;
435+ rects[nrects].width = fp->width;
436+ rects[nrects].height = fp->height;
437+ nrects++;
438+ }
439+ image_free_pixmaps (image, pixmap, mask);
440+ }
441+ else
442+ {
443+ rects[nrects].x = fp->x - w->frame_x;
444+ rects[nrects].y = fp->y - w->frame_y;
445+ rects[nrects].width = fp->width;
446+ rects[nrects].height = fp->height;
447+ nrects++;
448+ }
449+ }
450+
451+ if (nrects > 0)
452+ {
453+ XShapeCombineRectangles (dpy, shape_win, ShapeBounding, 0, 0, rects,
454+ nrects, ShapeUnion, Unsorted);
455+ }
456+
457+ if (atomic)
458+ {
459+ XShapeCombineShape (dpy, w->frame, ShapeBounding,
460+ 0, 0, shape_win, ShapeBounding, ShapeSet);
461+ XDestroyWindow (dpy, shape_win);
462+ }
463+
464+ w->pending_reshape = 0;
465+}
466+
467+/* Queue an atomic reshape for the frame of W. It will happen sometime
468+ in the near future. */
469+void
470+queue_reshape_frame (Lisp_Window *w)
471+{
472+ w->pending_reshape = 1;
473+}
474+
475+void
476+commit_queued_reshapes (void)
477+{
478+ Lisp_Window *w;
479+ for (w = window_list; w != 0; w = w->next)
480+ {
481+ if (!WINDOW_IS_GONE_P (w) && w->pending_reshape)
482+ set_frame_shapes (w, TRUE);
483+ }
484+}
485+
486+/* Draw the background of the frame-part FP. This is either a solid color
487+ or an image (scaled or tiled) */
488+static void
489+set_frame_part_bg (struct frame_part *fp)
490+{
491+ int state = current_state (fp);
492+ repv bg = fp->bg[state];
493+ Lisp_Window *win = fp->win;
494+
495+ if (fp->id == 0)
496+ return;
497+
498+ if (fp->renderer != Qnil && IMAGEP(fp->rendered_image))
499+ {
500+ bg = fp->rendered_image;
501+ if (fp->rendered_state != state)
502+ {
503+ rep_call_lisp2 (fp->renderer, bg, state_syms[state]);
504+ fp->rendered_state = state;
505+ }
506+ fp->drawn.bg = Qnil;
507+ }
508+
509+ if (WINDOW_IS_GONE_P (win))
510+ return;
511+
512+ if (COLORP(bg))
513+ {
514+ if (bg != fp->drawn.bg)
515+ {
516+ XGCValues gcv;
517+ gcv.foreground = VCOLOR(bg)->pixel;
518+ XChangeGC (dpy, fp->gc, GCForeground, &gcv);
519+ XFillRectangle (dpy, fp->id, fp->gc, 0, 0, fp->width, fp->height);
520+ fp->drawn.bg = bg;
521+ fp->drawn.fg = rep_NULL;
522+ }
523+ }
524+ else if (IMAGEP(bg))
525+ {
526+ Lisp_Image *image = VIMAGE(bg);
527+ Pixmap bg_pixmap, bg_mask;
528+ bool tiled = FALSE;
529+ repv tem;
530+
531+ if (fp->drawn.bg == bg)
532+ return;
533+
534+ tem = Fimage_get (rep_VAL(image), Qtiled);
535+ if (tem && tem != Qnil)
536+ tiled = TRUE;
537+
538+ if (tiled)
539+ {
540+ image_render (image, image_width (image), image_height (image),
541+ &bg_pixmap, &bg_mask);
542+ }
543+ else
544+ {
545+ image_render (image, fp->width, fp->height, &bg_pixmap, &bg_mask);
546+ }
547+
548+ /* Some of the Imlib_ functions call XSync on our display. In turn
549+ this can cause the error handler to run if a window has been
550+ deleted. This then invalidates the window we're updating */
551+ if (WINDOW_IS_GONE_P (win))
552+ return;
553+
554+ if (bg_mask == 0)
555+ {
556+ /* No mask, so we always want to force the rectangle
557+ including the frame part to be shown.. */
558+ XRectangle rect;
559+ rect.x = rect.y = 0;
560+ rect.width = fp->width;
561+ rect.height = fp->height;
562+ XShapeCombineRectangles (dpy, fp->id, ShapeBounding,
563+ 0, 0, &rect, 1, ShapeSet, Unsorted);
564+ }
565+
566+ if (!tiled)
567+ {
568+ XCopyArea (dpy, bg_pixmap, fp->id, fp->gc, 0, 0,
569+ fp->width, fp->height, 0, 0);
570+ if (bg_mask != 0)
571+ {
572+ XShapeCombineMask (dpy, fp->id, ShapeBounding,
573+ 0, 0, bg_mask, ShapeSet);
574+ }
575+ }
576+ else
577+ {
578+ Window tem = 0;
579+ int y = 0;
580+ if (bg_mask != 0)
581+ {
582+ XRectangle rect;
583+ XSetWindowAttributes wa;
584+ int wamask;
585+ wa.colormap = image_cmap;
586+ wa.border_pixel = BlackPixel (dpy, screen_num);
587+ wamask = CWColormap | CWBorderPixel;
588+ tem = XCreateWindow (dpy, win->frame, -100, -100,
589+ fp->width, fp->height,
590+ 0, image_depth, InputOutput,
591+ image_visual, wamask, &wa);
592+ rect.x = rect.y = 0;
593+ rect.width = fp->width;
594+ rect.height = fp->height;
595+ XShapeCombineRectangles (dpy, tem, ShapeBounding, 0, 0,
596+ &rect, 1, ShapeSubtract, Unsorted);
597+ }
598+ while (y < fp->height)
599+ {
600+ int x = 0;
601+ int width = image_width (image);
602+ int height = image_height (image);
603+ while (x < fp->width)
604+ {
605+ XCopyArea (dpy, bg_pixmap, fp->id, fp->gc,
606+ 0, 0, width, height, x, y);
607+ if (bg_mask != 0)
608+ {
609+ XShapeCombineMask (dpy, tem, ShapeBounding,
610+ x, y, bg_mask, ShapeUnion);
611+ }
612+ x += width;
613+ }
614+ y += height;
615+ }
616+ if (bg_mask != 0)
617+ {
618+ XShapeCombineShape (dpy, fp->id, ShapeBounding, 0, 0,
619+ tem, ShapeBounding, ShapeSet);
620+ XDestroyWindow (dpy, tem);
621+ }
622+ }
623+ image_free_pixmaps (image, bg_pixmap, bg_mask);
624+
625+ /* Imlib sometimes calls XSync (), which could hide events
626+ from select () */
627+ rep_mark_input_pending (ConnectionNumber(dpy));
628+
629+ fp->drawn.bg = bg;
630+ fp->drawn.fg = rep_NULL;
631+
632+ queue_reshape_frame (fp->win);
633+ }
634+ else if (Ffunctionp (bg) != Qnil)
635+ {
636+ rep_call_lisp1 (bg, rep_VAL(fp));
637+ fp->drawn.bg = bg;
638+ fp->drawn.fg = rep_NULL;
639+ }
640+ else
641+ fp->drawn.bg = Qnil;
642+}
643+
644+/* Draw the foreground pixels in frame-part FP. */
645+static void
646+set_frame_part_fg (struct frame_part *fp)
647+{
648+ int state = current_state (fp);
649+ repv font = fp->font[state], fg = fp->fg[state];
650+ XGCValues gcv;
651+ u_long gcv_mask = 0;
652+ repv string = rep_NULL;
653+ int length = 0, width, height, x, y;
654+ Lisp_Window *win = fp->win;
655+
656+ if (fp->id == 0)
657+ return;
658+
659+ if (fg != Qnil && Ffunctionp (fg) != Qnil)
660+ {
661+ rep_call_lisp1 (fg, rep_VAL(fp));
662+ }
663+ else if (IMAGEP(fg) || fp->text != Qnil)
664+ {
665+ if (!COLORP(fg) && !IMAGEP(fg))
666+ fg = global_symbol_value (Qdefault_foreground);
667+ if (!FONTP(font))
668+ {
669+ font = global_symbol_value (Qdefault_font);
670+ if (!FONTP(font))
671+ goto out;
672+ }
673+
674+ if (IMAGEP(fg))
675+ {
676+ if (fp->scale_foreground)
677+ {
678+ width = fp->width;
679+ height = fp->height;
680+ }
681+ else
682+ {
683+ width = image_width (VIMAGE(fg));
684+ height = image_height (VIMAGE(fg));
685+ }
686+ }
687+ else
688+ {
689+ if (rep_STRINGP(fp->text))
690+ {
691+ string = fp->text;
692+ length = rep_STRING_LEN(fp->text);
693+ }
694+ else
695+ {
696+ repv result = rep_call_lisp1 (fp->text, rep_VAL(fp->win));
697+ if (!result || !rep_STRINGP(result))
698+ return;
699+ string = result;
700+ length = rep_STRING_LEN(result);
701+ }
702+
703+ width = x_text_width (font, rep_STR(string), length);
704+ height = VFONT(font)->ascent + VFONT(font)->descent;
705+ }
706+
707+ if (fp->x_justify == Qcenter)
708+ x = MAX(0, (fp->width - width) / 2);
709+ else if (fp->x_justify == Qright)
710+ x = MAX(0, fp->width - width);
711+ else if (rep_INTP(fp->x_justify))
712+ {
713+ x = rep_INT(fp->x_justify);
714+ if (x < 0)
715+ x = MAX(0, fp->width + x - width);
716+ }
717+ else
718+ x = 0;
719+
720+ if (fp->y_justify == Qcenter)
721+ y = MAX(0, (fp->height - height) / 2);
722+ else if (fp->y_justify == Qbottom)
723+ y = MAX(0, fp->height - height);
724+ else if (rep_INTP(fp->y_justify))
725+ {
726+ y = rep_INT(fp->y_justify);
727+ if (y < 0)
728+ y = MAX(0, fp->height + y - height);
729+ }
730+ else
731+ y = 0;
732+
733+ if (IMAGEP(fg))
734+ {
735+ Pixmap fg_pixmap, fg_mask;
736+
737+ if (fp->drawn.fg == fg
738+ && fp->drawn.x_justify == fp->x_justify
739+ && fp->drawn.y_justify == fp->y_justify)
740+ {
741+ return;
742+ }
743+ else if (fp->drawn.fg != rep_NULL)
744+ {
745+ /* there's something drawn in this part already,
746+ update the background to clear it */
747+ fp->drawn.bg = rep_NULL;
748+ set_frame_part_bg (fp);
749+ }
750+
751+ image_render (VIMAGE(fg), width, height,
752+ &fg_pixmap, &fg_mask);
753+
754+ /* Some of the Imlib_ functions call XSync on our display. In turn
755+ this can cause the error handler to run if a window has been
756+ deleted. This then invalidates the window we're updating */
757+ if (WINDOW_IS_GONE_P (win))
758+ return;
759+
760+ if (fg_pixmap)
761+ {
762+ if (fg_mask)
763+ {
764+ gcv.clip_mask = fg_mask;
765+ gcv.clip_x_origin = x;
766+ gcv.clip_y_origin = y;
767+ gcv_mask |= GCClipMask | GCClipXOrigin | GCClipYOrigin;
768+ }
769+
770+ XChangeGC (dpy, fp->gc, gcv_mask, &gcv);
771+ XCopyArea (dpy, fg_pixmap, fp->id, fp->gc,
772+ 0, 0, MIN(fp->width, width),
773+ MIN(fp->height, height), x, y);
774+ if (fg_mask)
775+ {
776+ gcv.clip_mask = None;
777+ gcv.clip_x_origin = 0;
778+ gcv.clip_y_origin = 0;
779+ XChangeGC (dpy, fp->gc, GCClipMask | GCClipXOrigin
780+ | GCClipYOrigin, &gcv);
781+ }
782+ image_free_pixmaps (VIMAGE(fg), fg_pixmap, fg_mask);
783+ }
784+ /* Imlib sometimes calls XSync (), which could hide events
785+ from select () */
786+ rep_mark_input_pending (ConnectionNumber(dpy));
787+
788+ fp->drawn.text = Qnil;
789+ }
790+ else if (COLORP(fg) && FONTP(font))
791+ {
792+ if ((fp->drawn.text == string
793+ || Fequal (fp->drawn.text, string) != Qnil)
794+ && fp->drawn.font == font && fp->drawn.fg == fg
795+ && fp->drawn.x_justify == fp->x_justify
796+ && fp->drawn.y_justify == fp->y_justify)
797+ {
798+ return;
799+ }
800+ else if (fp->drawn.fg != rep_NULL)
801+ {
802+ /* there's something drawn in this part already,
803+ update the background to clear it */
804+ fp->drawn.bg = rep_NULL;
805+ set_frame_part_bg (fp);
806+ }
807+
808+ if (COLORP(fg))
809+ {
810+ gcv.foreground = VCOLOR(fg)->pixel;
811+ gcv_mask |= GCForeground;
812+ }
813+
814+ XChangeGC (dpy, fp->gc, gcv_mask, &gcv);
815+ x_draw_string (fp->id, font, fp->gc, x, y + VFONT(font)->ascent,
816+ rep_STR(string), length);
817+
818+ fp->drawn.text = string;
819+ }
820+ }
821+out:
822+ fp->drawn.font = font;
823+ fp->drawn.fg = fg;
824+ fp->drawn.x_justify = fp->x_justify;
825+ fp->drawn.y_justify = fp->y_justify;
826+}
827+
828+/* Redraw FP. */
829+void
830+refresh_frame_part (struct frame_part *fp)
831+{
832+ if (!frame_draw_mutex)
833+ {
834+ Lisp_Window *w = fp->win;
835+ if (w == 0) /* XXX why is this needed? */
836+ return;
837+
838+ if (fp->drawn.width != fp->width || fp->drawn.height != fp->height)
839+ fp->drawn.bg = rep_NULL;
840+
841+ if (!WINDOW_IS_GONE_P (w) && fp->id != 0)
842+ set_frame_part_bg (fp);
843+ if (!WINDOW_IS_GONE_P (w) && fp->id != 0)
844+ set_frame_part_fg (fp);
845+
846+ fp->drawn.width = fp->width;
847+ fp->drawn.height = fp->height;
848+ fp->pending_refresh = 0;
849+ }
850+ else
851+ fp->pending_refresh = 1;
852+}
853+
854+/* Redraw frame parts in W. */
855+void
856+refresh_frame_parts (Lisp_Window *w)
857+{
858+ struct frame_part *fp;
859+ for (fp = w->frame_parts; !WINDOW_IS_GONE_P (w) && fp != 0; fp = fp->next)
860+ refresh_frame_part (fp);
861+}
862+
863+/* Find the frame-part that is drawn in window ID */
864+struct frame_part *
865+find_frame_part_by_window (Window id)
866+{
867+ struct frame_part *fp;
868+ return XFindContext (dpy, id, window_fp_context, (XPointer *)&fp) ? 0 : fp;
869+}
870+
871+/* Destroy the window frame of W, assuming it's a frame-part derived frame */
872+static void
873+frame_part_destroyer (Lisp_Window *w)
874+{
875+ struct frame_part *fp, *next;
876+ for (fp = w->frame_parts; fp != 0; fp = next)
877+ {
878+ if (fp->clicked)
879+ {
880+ /* This is necessary so that clicked_frame_part is cleared. */
881+ bool old_mutex = frame_draw_mutex;
882+ frame_draw_mutex = TRUE;
883+ unclick_current_fp ();
884+ XUngrabPointer (dpy, last_event_time);
885+ frame_draw_mutex = old_mutex;
886+ }
887+
888+ if (fp->gc)
889+ {
890+ XFreeGC (dpy, fp->gc);
891+ fp->gc = 0;
892+ }
893+
894+ if (fp->id != 0)
895+ {
896+ XDeleteContext (dpy, fp->id, window_fp_context);
897+ XDestroyWindow (dpy, fp->id);
898+ fp->id = 0;
899+ }
900+
901+ fp->win = 0;
902+ next = fp->next;
903+ fp->next = 0;
904+ }
905+ w->frame_parts = 0;
906+}
907+
908+/* Handle the expose event EV for the frame part FP. */
909+void
910+frame_part_exposer (XExposeEvent *ev, struct frame_part *fp)
911+{
912+ if (ev->count == 0)
913+ {
914+ /* expose events override the drawing mutex,
915+ unless the server is grabbed.. */
916+ bool old_mutex = frame_draw_mutex;
917+ frame_draw_mutex = (Fserver_grabbed_p () != Qnil);
918+ fp->drawn.bg = rep_NULL;
919+ refresh_frame_part (fp);
920+ frame_draw_mutex = old_mutex;
921+ }
922+}
923+
924+static repv
925+fp_assq (struct frame_part *fp, repv prop,
926+ repv class_alist, repv ov_class_alist)
927+{
928+ repv tem;
929+
930+ tem = Fassq (prop, fp->local_alist);
931+ if (tem && tem != Qnil)
932+ return tem;
933+
934+ tem = Fassq (prop, ov_class_alist);
935+ if (tem && tem != Qnil)
936+ return tem;
937+
938+ tem = Fassq (prop, fp->alist);
939+ if (tem && tem != Qnil)
940+ return tem;
941+
942+ tem = Fassq (prop, class_alist);
943+ if (tem && tem != Qnil)
944+ return tem;
945+
946+ return Qnil;
947+}
948+
949+static repv
950+x_fp_assq (struct frame_part *fp, repv prop)
951+{
952+ repv ret = Qnil, class, tem;
953+
954+ ret = Fassq (prop, fp->local_alist);
955+ if (ret && ret != Qnil)
956+ return ret;
957+
958+ class = Fassq (Qclass, fp->alist);
959+ if (class && class != Qnil)
960+ class = rep_CDR(class);
961+ else
962+ class = rep_NULL;
963+
964+ tem = global_symbol_value (Qoverride_frame_part_classes);
965+ if (class != rep_NULL && rep_CONSP(tem))
966+ {
967+ tem = Fassq (class, tem);
968+ if (tem && tem != Qnil)
969+ ret = Fassq (prop, rep_CDR(tem));
970+ }
971+
972+ if (ret && ret == Qnil)
973+ ret = Fassq (prop, fp->alist);
974+
975+ if (ret && ret == Qnil)
976+ {
977+ tem = global_symbol_value (Qframe_part_classes);
978+ if (class != rep_NULL && rep_CONSP(tem))
979+ {
980+ tem = Fassq (class, tem);
981+ if (tem && tem != Qnil)
982+ ret = Fassq (prop, rep_CDR(tem));
983+ }
984+ }
985+
986+ return ret ? ret : Qnil;
987+}
988+
989+static repv
990+get_integer_prop (struct frame_part *fp, repv prop, repv class, repv ov_class)
991+{
992+ repv tem = fp_assq (fp, prop, class, ov_class);
993+ if (tem && tem != Qnil)
994+ {
995+ if (rep_INTP(rep_CDR(tem)))
996+ tem = rep_CDR(tem);
997+ else
998+ tem = call_protectedly_1 (rep_CDR(tem), rep_VAL(fp->win), Qnil);
999+ return rep_INTP(tem) ? tem : Qnil;
1000+ }
1001+ else
1002+ return Qnil;
1003+}
1004+
1005+static repv
1006+get_boolean_prop (struct frame_part *fp, repv prop, repv class, repv ov_class)
1007+{
1008+ repv tem = fp_assq (fp, prop, class, ov_class);
1009+ if (tem && tem != Qnil)
1010+ {
1011+ if (Ffunctionp (rep_CDR(tem)) == Qnil)
1012+ tem = rep_CDR(tem);
1013+ else
1014+ tem = call_protectedly_1 (rep_CDR(tem), rep_VAL(fp->win), Qnil);
1015+ return tem;
1016+ }
1017+ else
1018+ return Qnil;
1019+}
1020+
1021+static bool
1022+get_pattern_prop (struct frame_part *fp, repv *data, repv (*conv)(repv data),
1023+ repv prop, repv class, repv ov_class)
1024+{
1025+ int i;
1026+ repv tem;
1027+
1028+ tem = fp_assq (fp, prop, class, ov_class);
1029+ if (tem != Qnil)
1030+ {
1031+ if (Ffunctionp (rep_CDR(tem)) != Qnil)
1032+ tem = call_protectedly_1 (rep_CDR(tem), rep_VAL(fp->win), Qnil);
1033+ else
1034+ tem = rep_CDR(tem);
1035+ if (!rep_CONSP(tem))
1036+ {
1037+ /* single value pattern */
1038+ data[0] = tem;
1039+ for (i = 1; i < fps_MAX; i++)
1040+ data[i] = data[0];
1041+ }
1042+ else if (!rep_CONSP(rep_CAR(tem)))
1043+ {
1044+ /* list of four elements: (NORMAL FOCUSED HIGHLIGHTED CLICKED) */
1045+
1046+ static int map[4] = {
1047+ fps_inactive, fps_focused, fps_highlighted, fps_clicked
1048+ };
1049+
1050+ for (i = 0; i < 4; i++)
1051+ {
1052+ data[map[i]] = rep_CAR(tem);
1053+ if (rep_CONSP(rep_CDR(tem)))
1054+ tem = rep_CDR(tem);
1055+ }
1056+ }
1057+ else
1058+ {
1059+ /* alist of elements (STATE . VALUE) */
1060+
1061+ while (rep_CONSP(tem) && rep_CONSP(rep_CAR(tem)))
1062+ {
1063+ repv state = rep_CAR(rep_CAR(tem));
1064+ int idx = fps_none;
1065+
1066+ if (state == Qinactive)
1067+ idx = fps_inactive;
1068+ else if (state == Qfocused)
1069+ idx = fps_focused;
1070+ else if (state == Qhighlighted)
1071+ idx = fps_highlighted;
1072+ else if (state == Qclicked)
1073+ idx = fps_clicked;
1074+ else if (state == Qinactive_highlighted)
1075+ idx = fps_inactive_highlighted;
1076+ else if (state == Qinactive_clicked)
1077+ idx = fps_inactive_clicked;
1078+ if (idx != fps_none)
1079+ data[idx] = rep_CDR(rep_CAR(tem));
1080+
1081+ tem = rep_CDR(tem);
1082+ }
1083+ }
1084+
1085+ /* now handle string conversions */
1086+ for (i = 0; i < fps_MAX; i++)
1087+ {
1088+ if (rep_STRINGP(data[i]))
1089+ data[i] = call_protectedly (conv, data[i], Qnil);
1090+ }
1091+
1092+ /* now fill any gaps in the state table */
1093+ for (i = 0; i < fps_MAX; i++)
1094+ {
1095+ static int map[fps_MAX] = {
1096+ fps_inactive, fps_inactive, fps_focused,
1097+ fps_inactive, fps_highlighted, fps_inactive_highlighted
1098+ };
1099+
1100+ if (data[i] == Qnil)
1101+ data[i] = data[map[i]];
1102+ }
1103+ }
1104+ return TRUE;
1105+}
1106+
1107+static bool
1108+build_frame_part (struct frame_part *fp)
1109+{
1110+ Lisp_Window *w = fp->win;
1111+ repv class = Qnil, class_elt = Qnil, ov_class_elt = Qnil, tem;
1112+ rep_GC_root gc_class, gc_class_elt, gc_ov_class_elt;
1113+ bool had_left_edge = FALSE, had_top_edge = FALSE;
1114+ bool had_right_edge = FALSE, had_bottom_edge = FALSE;
1115+ bool ret = FALSE;
1116+ int i;
1117+
1118+ rep_PUSHGC(gc_class, class);
1119+ rep_PUSHGC(gc_class_elt, class_elt);
1120+ rep_PUSHGC(gc_ov_class_elt, ov_class_elt);
1121+
1122+ fp->width = fp->height = -1;
1123+ for (i = 0; i < fps_MAX; i++)
1124+ fp->fg[i] = fp->bg[i] = fp->font[i] = Qnil;
1125+
1126+ /* find the class of the part, and the alists of class-local state */
1127+ tem = Fassq (Qclass, fp->alist);
1128+ if (tem && tem != Qnil)
1129+ {
1130+ class = rep_CDR(tem);
1131+ tem = global_symbol_value (Qframe_part_classes);
1132+ if (rep_CONSP(tem))
1133+ {
1134+ tem = Fassq (class, tem);
1135+ if (tem && tem != Qnil)
1136+ class_elt = rep_CDR(tem);
1137+ }
1138+ tem = global_symbol_value (Qoverride_frame_part_classes);
1139+ if (rep_CONSP(tem))
1140+ {
1141+ tem = Fassq (class, tem);
1142+ if (tem && tem != Qnil)
1143+ ov_class_elt = rep_CDR(tem);
1144+ }
1145+ }
1146+
1147+ /* do we ignore this part? */
1148+ tem = get_boolean_prop (fp, Qhidden, class_elt, ov_class_elt);
1149+ if (tem != Qnil)
1150+ goto next_part;
1151+ tem = Fassq (Qremovable, fp->alist);
1152+ if (tem && tem != Qnil && rep_CDR(tem) != Qnil)
1153+ {
1154+ tem = Fwindow_get (rep_VAL(w), Qremoved_classes); /* XXX hoist */
1155+ if (tem && rep_CONSP(tem))
1156+ {
1157+ tem = Fmemq (class, tem);
1158+ if (tem && tem != Qnil)
1159+ goto next_part;
1160+ }
1161+ }
1162+
1163+ tem = get_boolean_prop (fp, Qbelow_client, class_elt, ov_class_elt);
1164+ fp->below_client = (tem && tem != Qnil);
1165+ tem = get_boolean_prop (fp, Qscale_foreground, class_elt, ov_class_elt);
1166+ fp->scale_foreground = (tem && tem != Qnil);
1167+
1168+ /* get text label */
1169+ tem = fp_assq (fp, Qtext, class_elt, ov_class_elt);
1170+ if (tem != Qnil)
1171+ fp->text = rep_CDR(tem);
1172+ else
1173+ fp->text = Qnil;
1174+ tem = fp_assq (fp, Qx_justify, class_elt, ov_class_elt);
1175+ if (tem != Qnil)
1176+ {
1177+ tem = rep_CDR(tem);
1178+ if (Ffunctionp (tem) != Qnil)
1179+ tem = call_protectedly_1 (tem, rep_VAL(w), Qnil);
1180+ fp->x_justify = tem;
1181+ }
1182+ else
1183+ fp->x_justify = Qnil;
1184+ tem = fp_assq (fp, Qy_justify, class_elt, ov_class_elt);
1185+ if (tem != Qnil)
1186+ {
1187+ tem = rep_CDR(tem);
1188+ if (Ffunctionp (tem) != Qnil)
1189+ tem = call_protectedly_1 (tem, rep_VAL(w), Qnil);
1190+ fp->y_justify = tem;
1191+ }
1192+ else
1193+ fp->y_justify = Qnil;
1194+
1195+ /* get cursor */
1196+ fp->cursor = Qnil;
1197+ tem = fp_assq (fp, Qcursor, class_elt, ov_class_elt);
1198+ if (tem != Qnil)
1199+ {
1200+ tem = rep_CDR(tem);
1201+ if (Ffunctionp (tem) != Qnil)
1202+ tem = call_protectedly_1 (tem, rep_VAL (w), Qnil);
1203+ if (!CURSORP(tem) && tem != Qnil)
1204+ tem = call_protectedly (Fget_cursor, tem, Qnil);
1205+ if (CURSORP(tem))
1206+ fp->cursor = tem;
1207+ }
1208+
1209+ /* get renderer function */
1210+ tem = fp_assq (fp, Qrenderer, class_elt, ov_class_elt);
1211+ if (tem != Qnil && Ffunctionp (rep_CDR(tem)) != Qnil)
1212+ {
1213+ fp->renderer = rep_CDR(tem);
1214+ tem = get_integer_prop (fp, Qrender_scale, class_elt, ov_class_elt);
1215+ if (tem != Qnil && rep_INT(tem) > 0)
1216+ fp->render_scale = rep_INT(tem);
1217+ else
1218+ fp->render_scale = 1;
1219+ }
1220+ else
1221+ fp->renderer = Qnil;
1222+
1223+ /* get background images or colors */
1224+ if (!get_pattern_prop (fp, fp->bg, Fget_color,
1225+ Qbackground, class_elt, ov_class_elt))
1226+ {
1227+ goto next_part;
1228+ }
1229+
1230+ /* get foreground colors or images */
1231+ if (!get_pattern_prop (fp, fp->fg, Fget_color,
1232+ Qforeground, class_elt, ov_class_elt))
1233+ {
1234+ goto next_part;
1235+ }
1236+
1237+ /* get fonts */
1238+ if (!get_pattern_prop (fp, fp->font, Fget_font,
1239+ Qfont, class_elt, ov_class_elt))
1240+ {
1241+ goto next_part;
1242+ }
1243+
1244+ /* If we have a background image for this part, take it as
1245+ the provisional dimensions of the part */
1246+ for (i = 0; i < fps_MAX; i++)
1247+ {
1248+ if (IMAGEP(fp->bg[i]))
1249+ {
1250+ fp->width = image_width (VIMAGE(fp->bg[i]));
1251+ fp->height = image_height (VIMAGE(fp->bg[i]));
1252+ break;
1253+ }
1254+ }
1255+
1256+ /* get dimensions.. */
1257+ tem = get_integer_prop (fp, Qwidth, class_elt, ov_class_elt);
1258+ if (tem != Qnil)
1259+ fp->width = rep_INT(tem);
1260+ tem = get_integer_prop (fp, Qheight, class_elt, ov_class_elt);
1261+ if (tem != Qnil)
1262+ fp->height = rep_INT(tem);
1263+ tem = get_integer_prop (fp, Qleft_edge, class_elt, ov_class_elt);
1264+ if (tem != Qnil)
1265+ {
1266+ fp->x = rep_INT(tem);
1267+ had_left_edge = TRUE;
1268+ }
1269+ tem = get_integer_prop (fp, Qtop_edge, class_elt, ov_class_elt);
1270+ if (tem != Qnil)
1271+ {
1272+ fp->y = rep_INT(tem);
1273+ had_top_edge = TRUE;
1274+ }
1275+ tem = get_integer_prop (fp, Qright_edge, class_elt, ov_class_elt);
1276+ if (tem != Qnil)
1277+ {
1278+ had_right_edge = TRUE;
1279+ if (had_left_edge)
1280+ fp->width = w->attr.width - rep_INT(tem) - fp->x;
1281+ else
1282+ fp->x = w->attr.width - rep_INT(tem) - fp->width;
1283+ }
1284+ tem = get_integer_prop (fp, Qbottom_edge, class_elt, ov_class_elt);
1285+ if (tem != Qnil)
1286+ {
1287+ had_bottom_edge = TRUE;
1288+ if (had_top_edge)
1289+ fp->height = w->attr.height - rep_INT(tem) - fp->y;
1290+ else
1291+ fp->y = w->attr.height - rep_INT(tem) - fp->height;
1292+ }
1293+
1294+ if (fp->width < 0)
1295+ fp->width = 0;
1296+ if (fp->height < 0)
1297+ fp->height = 0;
1298+
1299+ /* try to remove edges sticking out of small windows. if a part
1300+ specified by only one edge sticks out of the other edge, then
1301+ truncate it */
1302+
1303+ if (had_right_edge && !had_left_edge && fp->x < 0)
1304+ {
1305+ fp->width += fp->x;
1306+ fp->x = 0;
1307+ }
1308+ else if (had_left_edge && !had_right_edge
1309+ && fp->x + fp->width > w->attr.width)
1310+ {
1311+ fp->width = w->attr.width - fp->x;
1312+ }
1313+
1314+ if (had_bottom_edge && !had_top_edge && fp->y < 0)
1315+ {
1316+ fp->height += fp->y;
1317+ fp->y = 0;
1318+ }
1319+ else if (had_top_edge && !had_bottom_edge
1320+ && fp->y + fp->height > w->attr.height)
1321+ {
1322+ fp->height = w->attr.height - fp->y;
1323+ }
1324+
1325+ /* if we have a renderer function, create the image to
1326+ render into. */
1327+ if (fp->renderer != Qnil)
1328+ {
1329+ fp->rendered_image
1330+ = Fmake_sized_image (rep_MAKE_INT(fp->width / fp->render_scale),
1331+ rep_MAKE_INT(fp->height / fp->render_scale),
1332+ Qnil);
1333+ fp->rendered_state = fps_none;
1334+ }
1335+ else
1336+ fp->rendered_image = Qnil;
1337+
1338+ DB((" part: x=%d y=%d width=%d height=%d\n",
1339+ fp->x, fp->y, fp->width, fp->height));
1340+
1341+ ret = TRUE;
1342+
1343+next_part:
1344+ rep_POPGC; rep_POPGC; rep_POPGC;
1345+ return ret;
1346+}
1347+
1348+static void
1349+configure_frame_part (struct frame_part *fp)
1350+{
1351+ Lisp_Window *w = fp->win;
1352+ XSetWindowAttributes wa;
1353+ u_long wamask;
1354+ if (fp->id == 0)
1355+ {
1356+ if (fp->width > 0 && fp->height > 0)
1357+ {
1358+ XGCValues gcv;
1359+ wa.win_gravity = StaticGravity;
1360+ wa.bit_gravity = StaticGravity;
1361+ wa.colormap = image_cmap;
1362+ wa.border_pixel = BlackPixel (dpy, screen_num);
1363+ wamask = CWWinGravity | CWBitGravity | CWColormap | CWBorderPixel;
1364+ fp->id = XCreateWindow (dpy, w->frame,
1365+ fp->x - w->frame_x, fp->y - w->frame_y,
1366+ fp->width, fp->height,
1367+ 0, image_depth, InputOutput,
1368+ image_visual, wamask, &wa);
1369+ fp->gc = XCreateGC (dpy, fp->id, 0, &gcv);
1370+ XSelectInput (dpy, fp->id, FP_EVENTS);
1371+
1372+ if (!fp->below_client)
1373+ XMapRaised (dpy, fp->id);
1374+ else
1375+ {
1376+ XMapWindow (dpy, fp->id);
1377+ XLowerWindow (dpy, fp->id);
1378+ }
1379+
1380+ /* stash the fp in the window */
1381+ XSaveContext (dpy, fp->id, window_fp_context, (XPointer)fp);
1382+
1383+ fp->drawn.fg = rep_NULL;
1384+ fp->drawn.bg = rep_NULL;
1385+ }
1386+ }
1387+ else
1388+ {
1389+ if (fp->width > 0 && fp->height > 0)
1390+ {
1391+ XWindowChanges attr;
1392+ attr.x = fp->x - w->frame_x;
1393+ attr.y = fp->y - w->frame_y;
1394+ attr.width = fp->width;
1395+ attr.height = fp->height;
1396+ attr.stack_mode = fp->below_client ? Below : Above;
1397+ XConfigureWindow (dpy, fp->id, CWX | CWY | CWWidth
1398+ | CWHeight | CWStackMode, &attr);
1399+ /* Generate an Expose event for the window. */
1400+ XClearArea (dpy, fp->id, 0, 0, 0, 0, True);
1401+ }
1402+ else
1403+ {
1404+ XDestroyWindow (dpy, fp->id);
1405+ fp->id = 0;
1406+ XFreeGC (dpy, fp->gc);
1407+ fp->gc = 0;
1408+ }
1409+ }
1410+ if (fp->id != 0)
1411+ {
1412+ XDefineCursor (dpy, fp->id, (fp->cursor != Qnil)
1413+ ? VCURSOR(fp->cursor)->cursor : None);
1414+ }
1415+}
1416+
1417+/* Generate a frame-part frame for window W. If called for a window that
1418+ already has a frame, it will be rebuilt to the current window size. */
1419+static void
1420+list_frame_generator (Lisp_Window *w)
1421+{
1422+ repv gen_list = w->frame_style;
1423+ repv ptr = rep_NULL, tem;
1424+ struct frame_part **last_fp = 0;
1425+ struct frame_part *fp = 0;
1426+ rep_GC_root gc_win, gc_ptr;
1427+ repv win = rep_VAL(w);
1428+ bool regen; /* are we resizing the frame */
1429+ bool bigger;
1430+ int nparts = 0;
1431+ XSetWindowAttributes wa;
1432+ u_long wamask;
1433+ int old_x_off, old_y_off;
1434+
1435+ /* bounding box of frame */
1436+ int left_x, top_y, right_x, bottom_y;
1437+
1438+ tem = Fwindow_get (rep_VAL(w), Qhide_client);
1439+ if (tem && tem != Qnil)
1440+ w->client_hidden = 1;
1441+ else
1442+ w->client_hidden = 0;
1443+
1444+ left_x = top_y = 0;
1445+ if (!w->client_hidden)
1446+ {
1447+ right_x = w->attr.width;
1448+ bottom_y = w->attr.height;
1449+ }
1450+ else
1451+ right_x = bottom_y = 0;
1452+
1453+ DB(("list_frame_generator(%s)\n", rep_STR(w->name)));
1454+
1455+ while (gen_list != Qnil && rep_SYMBOLP(gen_list) && !rep_INTERRUPTP)
1456+ {
1457+ gen_list = Fsymbol_value (gen_list, Qt);
1458+ rep_TEST_INT;
1459+ }
1460+
1461+ rep_PUSHGC(gc_win, win);
1462+
1463+ /* construct the component list, and find the bounding box */
1464+
1465+ /* if w->destroy_frame is set then we're rebuilding an existing
1466+ frame */
1467+ if (w->destroy_frame == 0)
1468+ {
1469+ ptr = gen_list;
1470+ last_fp = &w->frame_parts;
1471+ assert (w->frame_parts == 0);
1472+ regen = FALSE;
1473+ }
1474+ else
1475+ {
1476+ fp = w->frame_parts;
1477+ regen = TRUE;
1478+ }
1479+
1480+ /* This loop is a bit weird. If we're building the frame from scratch
1481+ we loop over the Lisp list of frame part specs. Otherwise we loop
1482+ over the _actual_ list of frame parts */
1483+ rep_PUSHGC(gc_ptr, ptr);
1484+ while ((!regen && rep_CONSP(ptr))
1485+ || (regen && fp != 0))
1486+ {
1487+ rep_GC_root gc_fp;
1488+ repv fp_;
1489+ if (!regen)
1490+ fp = fp_new (w, rep_CAR (ptr));
1491+ fp_ = rep_VAL(fp);
1492+
1493+ rep_PUSHGC(gc_fp, fp_);
1494+ if (build_frame_part (fp))
1495+ {
1496+ /* expand frame bounding box */
1497+ left_x = MIN(left_x, fp->x);
1498+ right_x = MAX(right_x, fp->x + fp->width);
1499+ top_y = MIN(top_y, fp->y);
1500+ bottom_y = MAX(bottom_y, fp->y + fp->height);
1501+
1502+ if (!regen)
1503+ {
1504+ /* link in fp */
1505+ *last_fp = fp;
1506+ last_fp = &fp->next;
1507+ }
1508+
1509+ nparts++;
1510+ }
1511+ rep_POPGC; /* fp */
1512+
1513+ if (!regen)
1514+ ptr = rep_CDR(ptr);
1515+ else
1516+ fp = fp->next;
1517+ }
1518+ rep_POPGC; /* ptr */
1519+
1520+ bigger = (right_x - left_x > w->frame_width
1521+ || bottom_y - top_y > w->frame_height);
1522+
1523+ old_x_off = w->frame_x;
1524+ old_y_off = w->frame_y;
1525+
1526+ /* now we can find the size and offset of the frame. */
1527+ w->frame_width = right_x - left_x;
1528+ w->frame_height = bottom_y - top_y;
1529+ w->frame_x = left_x;
1530+ w->frame_y = top_y;
1531+
1532+ DB((" bounding box: x=%d y=%d width=%d height=%d\n",
1533+ left_x, top_y, w->frame_width, w->frame_height));
1534+
1535+ if (w->reparented && bigger)
1536+ set_frame_shapes (w, TRUE);
1537+
1538+ /* create the child-of-root frame window, or if it already exists,
1539+ configure it to the correct size.. */
1540+ if (w->frame == 0)
1541+ {
1542+ /* create the frame */
1543+ wa.override_redirect = True;
1544+ wa.colormap = image_cmap;
1545+ wa.border_pixel = BlackPixel (dpy, screen_num);
1546+ wamask = CWOverrideRedirect | CWColormap | CWBorderPixel;
1547+ w->frame = XCreateWindow (dpy, root_window, w->attr.x, w->attr.y,
1548+ w->frame_width, w->frame_height,
1549+ 0, image_depth, InputOutput,
1550+ image_visual, wamask, &wa);
1551+ }
1552+ else
1553+ {
1554+ /* adjust frame position to keep absolute client position constant */
1555+ w->attr.x += w->frame_x - old_x_off;
1556+ w->attr.y += w->frame_y - old_y_off;
1557+
1558+ XMoveResizeWindow (dpy, w->frame, w->attr.x, w->attr.y,
1559+ w->frame_width, w->frame_height);
1560+
1561+ if (w->reparented)
1562+ XMoveResizeWindow (dpy, w->id, -left_x, -top_y,
1563+ w->attr.width, w->attr.height);
1564+ else
1565+ XResizeWindow (dpy, w->id, w->attr.width, w->attr.height);
1566+ }
1567+
1568+ w->destroy_frame = frame_part_destroyer;
1569+ w->focus_change = refresh_frame_parts;
1570+ w->rebuild_frame = list_frame_generator;
1571+ w->property_change = refresh_frame_parts;
1572+
1573+ if (w->reparented)
1574+ XLowerWindow (dpy, w->id);
1575+
1576+ /* create/update windows for each part */
1577+ for (fp = w->frame_parts; fp != 0; fp = fp->next)
1578+ configure_frame_part (fp);
1579+
1580+ if (!w->reparented || !bigger)
1581+ set_frame_shapes (w, TRUE);
1582+
1583+ /* ICCCM says we must unmap the client window when it's hidden */
1584+ {
1585+ int unmap_client = (!w->visible || w->client_hidden);
1586+ if (w->client_unmapped != unmap_client)
1587+ {
1588+ before_local_map (w);
1589+ if (unmap_client)
1590+ XUnmapWindow (dpy, w->id);
1591+ else
1592+ XMapWindow (dpy, w->id);
1593+ w->client_unmapped = unmap_client;
1594+ after_local_map (w);
1595+ if (focus_window == w)
1596+ focus_on_window (w);
1597+ }
1598+ }
1599+
1600+ rep_POPGC; /* win */
1601+}
1602+
1603+/* Return the keymap associated with this frame part, or nil */
1604+repv
1605+get_keymap_for_frame_part (struct frame_part *fp)
1606+{
1607+ repv tem = x_fp_assq (fp, Qkeymap);
1608+ if (tem != Qnil)
1609+ tem = rep_CDR(tem);
1610+ return tem;
1611+}
1612+
1613+/* Mark all frame-parts of window W for gc. */
1614+void
1615+mark_frame_parts (Lisp_Window *w)
1616+{
1617+ struct frame_part *fp;
1618+ for (fp = w->frame_parts; fp != 0; fp = fp->next)
1619+ rep_MARKVAL (rep_VAL(fp));
1620+}
1621+
1622+/* Reset state of all frame parts in window W. */
1623+void
1624+reset_frame_parts (Lisp_Window *w)
1625+{
1626+ struct frame_part *fp;
1627+ for (fp = w->frame_parts; fp != 0; fp = fp->next)
1628+ {
1629+ int old_state = current_state (fp), new_state;
1630+ if (fp->clicked)
1631+ unclick_current_fp ();
1632+ fp->highlighted = 0;
1633+ new_state = current_state (fp);
1634+ if (new_state != old_state)
1635+ refresh_frame_part (fp);
1636+ }
1637+}
1638+
1639+/* Make sure stacking in frame is as desired after reparenting
1640+ the client into the frame */
1641+void
1642+restack_frame_parts (Lisp_Window *w)
1643+{
1644+ struct frame_part *fp;
1645+ XLowerWindow (dpy, w->id);
1646+ for (fp = w->frame_parts; fp != 0; fp = fp->next)
1647+ {
1648+ if (fp->id != 0 && fp->below_client)
1649+ XLowerWindow (dpy, fp->id);
1650+ }
1651+}
1652+
1653+
1654+/* creating window frames */
1655+
1656+/* Create a frame for window W. Called with the server grabbed. If
1657+ w->frame is non-zero, then we'll use this window to construct the
1658+ frame in, otherwise w->frame will be initialised with a new window */
1659+void
1660+create_window_frame (Lisp_Window *w)
1661+{
1662+ DB(("create_window_frame (%s)\n", rep_STR(w->name)));
1663+ if (w->frame_parts == 0)
1664+ {
1665+ w->destroy_frame = 0;
1666+ w->focus_change = 0;
1667+ w->rebuild_frame = 0;
1668+ w->property_change = 0;
1669+ list_frame_generator (w);
1670+ }
1671+ else
1672+ fprintf (stderr, "warning: reframing framed window: %lx\n", (long) w->id);
1673+}
1674+
1675+/* Destroy the frame of window W. If LEAVE-FRAME-WIN is non-zero, then
1676+ w->frame won't be destroyed */
1677+void
1678+destroy_window_frame (Lisp_Window *w, bool leave_frame_win)
1679+{
1680+ if (w->frame != 0)
1681+ {
1682+ if (w->destroy_frame != 0)
1683+ {
1684+ w->destroy_frame (w);
1685+ w->destroy_frame = 0;
1686+ }
1687+ if (!leave_frame_win && w->frame != 0)
1688+ {
1689+ XDestroyWindow (dpy, w->frame);
1690+ w->frame = 0;
1691+ }
1692+ }
1693+}
1694+
1695+
1696+/* Lisp functions */
1697+
1698+DEFUN("frame-draw-mutex", Fframe_draw_mutex,
1699+ Sframe_draw_mutex, (repv arg), rep_Subr1) /*
1700+::doc:sawfish.wm.frames.subrs#frame-draw-mutex::
1701+While this variable is non-nil no frame parts will be redrawn. When it is
1702+set to nil any pending redraws will take place.
1703+::end:: */
1704+{
1705+ repv ret = frame_draw_mutex ? Qt : Qnil;
1706+ frame_draw_mutex = (arg != Qnil);
1707+ if (!frame_draw_mutex)
1708+ {
1709+ Lisp_Window *w;
1710+ for (w = window_list; w != 0; w = w->next)
1711+ {
1712+ struct frame_part *fp;
1713+ for (fp = w->frame_parts; fp != 0; fp = fp->next)
1714+ {
1715+ if (fp->pending_refresh)
1716+ refresh_frame_part (fp);
1717+ }
1718+ }
1719+ }
1720+ return ret;
1721+}
1722+
1723+DEFUN("frame-state-mutex", Fframe_state_mutex,
1724+ Sframe_state_mutex, (repv arg), rep_Subr1) /*
1725+::doc:sawfish.wm.frames.subrs#frame-state-mutex::
1726+While this variable is non-nil the state of frame parts will not be
1727+altered when the pointer enters or leaves its window.
1728+::end:: */
1729+{
1730+ repv ret = frame_state_mutex ? Qt : Qnil;
1731+ frame_state_mutex = (arg != Qnil);
1732+ if (arg == Qclicked
1733+ && clicked_frame_part != 0
1734+ && !clicked_frame_part->clicked)
1735+ {
1736+ /* XXX hack alert */
1737+ clicked_frame_part->clicked = 1;
1738+ refresh_frame_part (clicked_frame_part);
1739+ }
1740+ return ret;
1741+}
1742+
1743+DEFUN("frame-part-get", Fframe_part_get,
1744+ Sframe_part_get, (repv part, repv prop), rep_Subr2) /*
1745+::doc:sawfish.wm.frames.subrs#frame-part-get::
1746+frame-part-get PART PROPERTY
1747+::end:: */
1748+{
1749+ repv tem;
1750+ rep_DECLARE1 (part, PARTP);
1751+ rep_DECLARE2 (prop, rep_SYMBOLP);
1752+ tem = x_fp_assq (VPART(part), prop);
1753+ return (tem != Qnil) ? rep_CDR(tem) : Qnil;
1754+}
1755+
1756+DEFUN("frame-part-put", Fframe_part_put, Sframe_part_put,
1757+ (repv part, repv prop, repv value), rep_Subr3)
1758+{
1759+ repv tem;
1760+ rep_DECLARE1(part, PARTP);
1761+ rep_DECLARE2(prop, rep_SYMBOLP);
1762+ tem = Fassq (prop, VPART(part)->local_alist);
1763+ if (tem != rep_NULL)
1764+ {
1765+ if (tem != Qnil)
1766+ rep_CDR (tem) = value;
1767+ else
1768+ VPART(part)->local_alist = Fcons (Fcons (prop, value),
1769+ VPART(part)->local_alist);
1770+ }
1771+ return value;
1772+}
1773+
1774+DEFUN("frame-part-window", Fframe_part_window,
1775+ Sframe_part_window, (repv part), rep_Subr1)
1776+{
1777+ rep_DECLARE1(part, PARTP);
1778+ return rep_VAL(VPART(part)->win);
1779+}
1780+
1781+DEFUN("frame-part-x-window", Fframe_part_x_window,
1782+ Sframe_part_x_window, (repv part), rep_Subr1)
1783+{
1784+ rep_DECLARE1(part, PARTP);
1785+ return VPART(part)->id != 0 ? rep_MAKE_INT(VPART(part)->id) : Qnil;
1786+}
1787+
1788+DEFUN("frame-part-position", Fframe_part_position,
1789+ Sframe_part_position, (repv part), rep_Subr1)
1790+{
1791+ rep_DECLARE1(part, PARTP);
1792+ return Fcons (rep_MAKE_INT(VPART(part)->x - VPART(part)->win->frame_x),
1793+ rep_MAKE_INT(VPART(part)->y - VPART(part)->win->frame_y));
1794+}
1795+
1796+DEFUN("frame-part-dimensions", Fframe_part_dimensions,
1797+ Sframe_part_dimensions, (repv part), rep_Subr1)
1798+{
1799+ rep_DECLARE1(part, PARTP);
1800+ return Fcons (rep_MAKE_INT(VPART(part)->width),
1801+ rep_MAKE_INT(VPART(part)->height));
1802+}
1803+
1804+DEFUN("frame-part-state", Fframe_part_state,
1805+ Sframe_part_state, (repv part), rep_Subr1)
1806+{
1807+ rep_DECLARE1(part, PARTP);
1808+ return state_syms[current_state (VPART(part))];
1809+}
1810+
1811+DEFUN("map-frame-parts", Fmap_frame_parts,
1812+ Smap_frame_parts, (repv fun, repv win), rep_Subr2)
1813+{
1814+ rep_GC_root gc_win;
1815+ struct frame_part *fp;
1816+
1817+ rep_DECLARE (1, fun, Ffunctionp (fun) != Qnil);
1818+ rep_DECLARE2 (win, WINDOWP);
1819+
1820+ rep_PUSHGC (gc_win, win);
1821+ fp = VWIN(win)->frame_parts;
1822+ while (fp != 0)
1823+ {
1824+ repv tem = rep_call_lisp1 (fun, rep_VAL(fp)); /* fun,fp protected */
1825+ if (tem == rep_NULL)
1826+ break;
1827+ fp = fp->next;
1828+ }
1829+ rep_POPGC;
1830+ return Qnil;
1831+}
1832+
1833+DEFUN("refresh-frame-part", Frefresh_frame_part,
1834+ Srefresh_frame_part, (repv part), rep_Subr1)
1835+{
1836+ rep_DECLARE1(part, PARTP);
1837+ if (VPART(part)->id != 0)
1838+ refresh_frame_part (VPART(part));
1839+ return Qt;
1840+}
1841+
1842+DEFUN("rebuild-frame-part", Frebuild_frame_part,
1843+ Srebuild_frame_part, (repv part), rep_Subr1)
1844+{
1845+ rep_GC_root gc_part;
1846+ rep_DECLARE1(part, PARTP);
1847+ rep_PUSHGC(gc_part, part);
1848+ if (build_frame_part (VPART(part)))
1849+ {
1850+ /* XXX what about reconfiguring the container window..? */
1851+ configure_frame_part (VPART(part));
1852+ queue_reshape_frame (VPART(part)->win);
1853+ }
1854+ rep_POPGC;
1855+ return Qt;
1856+}
1857+
1858+DEFUN("refresh-window", Frefresh_window,
1859+ Srefresh_window, (repv win), rep_Subr1)
1860+{
1861+ rep_DECLARE1(win, XWINDOWP);
1862+ if (!WINDOW_IS_GONE_P (VWIN(win)))
1863+ refresh_frame_parts (VWIN(win));
1864+ return Qt;
1865+}
1866+
1867+
1868+/* initialisation */
1869+
1870+void
1871+frames_init (void)
1872+{
1873+ repv tem;
1874+ frame_part_type = rep_register_new_type ("frame-part", fp_cmp, fp_prin,
1875+ fp_prin, fp_sweep, fp_mark, 0,
1876+ 0, 0, 0, 0, 0, 0);
1877+
1878+ tem = rep_push_structure ("sawfish.wm.frames.subrs");
1879+ rep_ADD_SUBR(Sframe_draw_mutex);
1880+ rep_ADD_SUBR(Sframe_state_mutex);
1881+ rep_ADD_SUBR(Sframe_part_get);
1882+ rep_ADD_SUBR(Sframe_part_put);
1883+ rep_ADD_SUBR(Sframe_part_window);
1884+ rep_ADD_SUBR(Sframe_part_x_window);
1885+ rep_ADD_SUBR(Sframe_part_position);
1886+ rep_ADD_SUBR(Sframe_part_dimensions);
1887+ rep_ADD_SUBR(Sframe_part_state);
1888+ rep_ADD_SUBR(Smap_frame_parts);
1889+ rep_ADD_SUBR(Srefresh_frame_part);
1890+ rep_ADD_SUBR(Srebuild_frame_part);
1891+ rep_pop_structure (tem);
1892+
1893+ tem = rep_push_structure ("sawfish.wm.windows.subrs");
1894+ rep_ADD_SUBR(Srefresh_window);
1895+ rep_pop_structure (tem);
1896+
1897+ rep_INTERN(internal);
1898+ rep_INTERN(tiled);
1899+ rep_INTERN(center);
1900+ rep_INTERN(right);
1901+ rep_INTERN(left);
1902+ rep_INTERN(top);
1903+ rep_INTERN(bottom);
1904+ rep_INTERN(text);
1905+ rep_INTERN(x_justify);
1906+ rep_INTERN(y_justify);
1907+ rep_INTERN(background);
1908+ rep_INTERN(foreground);
1909+ rep_INTERN(renderer);
1910+ rep_INTERN(render_scale);
1911+ rep_INTERN(font);
1912+ rep_INTERN(width);
1913+ rep_INTERN(height);
1914+ rep_INTERN(left_edge);
1915+ rep_INTERN(top_edge);
1916+ rep_INTERN(right_edge);
1917+ rep_INTERN(bottom_edge);
1918+ rep_INTERN(cursor);
1919+ rep_INTERN(focused);
1920+ rep_INTERN(highlighted);
1921+ rep_INTERN(clicked);
1922+ rep_INTERN(inactive);
1923+ rep_INTERN(inactive_highlighted);
1924+ rep_INTERN(inactive_clicked);
1925+ rep_INTERN(hide_client);
1926+ rep_INTERN(class);
1927+ rep_INTERN(removable);
1928+ rep_INTERN(removed_classes);
1929+ rep_INTERN(below_client);
1930+ rep_INTERN(scale_foreground);
1931+ rep_INTERN(hidden);
1932+
1933+ rep_INTERN_SPECIAL(frame_part_classes);
1934+ rep_INTERN_SPECIAL(override_frame_part_classes);
1935+
1936+ state_syms[fps_inactive] = Qnil;
1937+ state_syms[fps_focused] = Qfocused;
1938+ state_syms[fps_highlighted] = Qhighlighted;
1939+ state_syms[fps_clicked] = Qclicked;
1940+ state_syms[fps_inactive_highlighted] = Qinactive_highlighted;
1941+ state_syms[fps_inactive_clicked] = Qinactive_clicked;
1942+
1943+ if (!batch_mode_p ())
1944+ window_fp_context = XUniqueContext ();
1945+}
1946+
1947+void
1948+frames_kill (void)
1949+{
1950+}
--- /dev/null
+++ b/src/functions.c
@@ -0,0 +1,1450 @@
1+/* functions.c -- useful window manager Lisp functions
2+ $Id$
3+
4+ Copyright (C) 1999 John Harper <john@dcs.warwick.ac.uk>
5+
6+ This file is part of sawmill.
7+
8+ sawmill is free software; you can redistribute it and/or modify it
9+ under the terms of the GNU General Public License as published by
10+ the Free Software Foundation; either version 2, or (at your option)
11+ any later version.
12+
13+ sawmill is distributed in the hope that it will be useful, but
14+ WITHOUT ANY WARRANTY; without even the implied warranty of
15+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+ GNU General Public License for more details.
17+
18+ You should have received a copy of the GNU General Public License
19+ along with sawmill; see the file COPYING. If not, write to
20+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21+
22+/* Define this to fake two side-by-side Xinerama style heads */
23+#undef TEST_XINERAMA
24+
25+/* AIX requires this to be the first thing in the file. */
26+#ifdef HAVE_CONFIG_H
27+#include <config.h>
28+#endif
29+#ifndef __GNUC__
30+# if HAVE_ALLOCA_H
31+# include <alloca.h>
32+# else
33+# ifdef _AIX
34+ #pragma alloca
35+# else
36+# ifndef alloca /* predefined by HP cc +Olibcalls */
37+ char *alloca ();
38+# endif
39+# endif
40+# endif
41+#endif
42+
43+#include "sawmill.h"
44+#include <X11/Xatom.h>
45+
46+/* Number of outstanding server grabs made; only when this is zero is
47+ the server ungrabbed. */
48+static int server_grabs;
49+
50+static int xinerama_heads;
51+
52+#ifdef HAVE_X11_EXTENSIONS_XINERAMA_H
53+# include <X11/extensions/Xinerama.h>
54+ static XineramaScreenInfo *xinerama_head_info;
55+# ifdef TEST_XINERAMA
56+ static XineramaScreenInfo debug_heads[2] = {
57+ { 0, 0, 0, 512, 768 },
58+ { 0, 512, 0, 512, 768 }
59+ };
60+ static int debug_nheads = 2;
61+# else
62+ static int xinerama_event_base, xinerama_error_base;
63+# endif
64+#endif
65+
66+DEFSYM(root, "root");
67+DEFSYM(after_restacking_hook, "after-restacking-hook");
68+DEFSYM(position, "position");
69+DEFSYM(spacing, "spacing");
70+DEFSYM(window, "window");
71+DEFSYM(head, "head");
72+
73+DEFUN("restack-windows", Frestack_windows, Srestack_windows,
74+ (repv list), rep_Subr1) /*
75+::doc:sawfish.wm.windows.subrs#restack-windows::
76+restack-windows LIST
77+
78+Restack all windows in the list of windows LIST in the order they occur
79+in the list (from top to bottom). The stacking order of any unspecified
80+windows isn't affected.
81+::end:: */
82+{
83+ repv ptr;
84+ Lisp_Window *pred;
85+
86+ rep_DECLARE1(list, rep_LISTP);
87+ for (ptr = list; rep_CONSP (ptr); ptr = rep_CDR (ptr))
88+ {
89+ if (!WINDOWP (rep_CAR (ptr)))
90+ return rep_signal_arg_error (list, 1);
91+ }
92+
93+ if (list == Qnil)
94+ return Qt;
95+
96+ ptr = list;
97+ pred = 0;
98+
99+ while (rep_CONSP (ptr))
100+ {
101+ Lisp_Window *this = VWIN (rep_CAR (ptr));
102+
103+ if (!WINDOW_IS_GONE_P (this))
104+ {
105+ if (pred != 0 && !WINDOW_IS_GONE_P (pred))
106+ {
107+ remove_from_stacking_list (this);
108+ insert_in_stacking_list_below (this, pred);
109+
110+ /* This works because it tries to stack relative to
111+ the window above THIS first; which we just set */
112+ restack_window (this);
113+ }
114+ pred = this;
115+ }
116+
117+ ptr = rep_CDR (ptr);
118+
119+ rep_TEST_INT;
120+ if (rep_INTERRUPTP)
121+ return rep_NULL;
122+ }
123+
124+ Fcall_hook (Qafter_restacking_hook, Qnil, Qnil);
125+ return Qt;
126+}
127+
128+DEFUN("x-raise-window", Fx_raise_window, Sx_raise_window,
129+ (repv win, repv above), rep_Subr2) /*
130+::doc:sawfish.wm.windows.subrs#x-raise-window::
131+x-raise-window WINDOW [ABOVE]
132+
133+Raise WINDOW so that it is above window ABOVE. If ABOVE is undefined,
134+raise WINDOW to the top of the stacking order.
135+::end:: */
136+{
137+ rep_DECLARE1 (win, WINDOWP);
138+
139+ if (!WINDOW_IS_GONE_P (VWIN (win)))
140+ {
141+ if (WINDOWP (above))
142+ {
143+ if (!WINDOW_IS_GONE_P (VWIN (above)))
144+ {
145+ remove_from_stacking_list (VWIN (win));
146+ insert_in_stacking_list_above (VWIN (win), VWIN (above));
147+ }
148+ }
149+ else
150+ {
151+ remove_from_stacking_list (VWIN (win));
152+ insert_in_stacking_list_above_all (VWIN (win));
153+ }
154+ restack_window (VWIN (win));
155+ Fcall_hook (Qafter_restacking_hook, Qnil, Qnil);
156+ }
157+ return win;
158+}
159+
160+DEFUN("x-lower-window", Fx_lower_window, Sx_lower_window,
161+ (repv win, repv below), rep_Subr2) /*
162+::doc:sawfish.wm.windows.subrs#x-lower-window::
163+x-lower-window WINDOW [BELOW]
164+
165+Lower WINDOW so that it is below window BELOW. If BELOW is undefined,
166+lower WINDOW to the bottom of the stacking order.
167+::end:: */
168+{
169+ rep_DECLARE1 (win, WINDOWP);
170+
171+ if (!WINDOW_IS_GONE_P (VWIN (win)))
172+ {
173+ if (WINDOWP (below))
174+ {
175+ if (!WINDOW_IS_GONE_P (VWIN (below)))
176+ {
177+ remove_from_stacking_list (VWIN (win));
178+ insert_in_stacking_list_below (VWIN (win), VWIN (below));
179+ }
180+ }
181+ else
182+ {
183+ remove_from_stacking_list (VWIN (win));
184+ insert_in_stacking_list_below_all (VWIN (win));
185+ }
186+ restack_window (VWIN (win));
187+ Fcall_hook (Qafter_restacking_hook, Qnil, Qnil);
188+ }
189+ return win;
190+}
191+
192+DEFUN("x-kill-client", Fx_kill_client, Sx_kill_client,
193+ (repv win), rep_Subr1)
194+{
195+ Window w = x_win_from_arg (win);
196+ if (w == 0)
197+ return WINDOWP(win) ? Qnil : rep_signal_arg_error (win, 1);
198+ XKillClient (dpy, w);
199+ return win;
200+}
201+
202+DEFUN_INT("destroy-window", Fdestroy_window, Sdestroy_window, (repv win), rep_Subr1, "%W") /*
203+::doc:sawfish.wm.windows.subrs#destroy-window::
204+destroy-window WINDOW
205+
206+Destroy WINDOW with out giving the owning application any warning.
207+
208+WINDOW may be a window object or a numeric window id.
209+::end:: */
210+{
211+ if (WINDOWP(win))
212+ XDestroyWindow (dpy, VWIN(win)->id);
213+ else if (rep_INTEGERP(win))
214+ XDestroyWindow (dpy, rep_get_long_uint (win));
215+ else
216+ return rep_signal_arg_error (win, 1);
217+ return win;
218+}
219+
220+DEFUN("warp-cursor", Fwarp_cursor, Swarp_cursor, (repv x, repv y), rep_Subr2) /*
221+::doc:sawfish.wm.misc#warp-cursor::
222+warp-cursor X Y
223+
224+Move the mouse pointer to position (X, Y) relative to the origin of the
225+root window.
226+::end:: */
227+{
228+ rep_DECLARE1(x, rep_INTP);
229+ rep_DECLARE2(y, rep_INTP);
230+ if (rep_INT(x) >= 0 && rep_INT(x) < screen_width
231+ && rep_INT(y) >= 0 && rep_INT(y) < screen_height)
232+ {
233+ XWarpPointer (dpy, None, root_window,
234+ 0, 0, 0, 0, rep_INT(x), rep_INT(y));
235+ invalidate_cached_mouse_position ();
236+ return Qt;
237+ }
238+ else
239+ return Qnil;
240+}
241+
242+DEFUN("move-window-to", Fmove_window_to, Smove_window_to,
243+ (repv win, repv x, repv y), rep_Subr3) /*
244+::doc:sawfish.wm.windows.subrs#move-window-to::
245+move-window-to WINDOW X Y
246+
247+Move the top-left corner of window object WINDOW to (X, Y).
248+::end:: */
249+{
250+ rep_DECLARE1(win, WINDOWP);
251+ rep_DECLARE2(x, rep_INTP);
252+ rep_DECLARE3(y, rep_INTP);
253+ if (VWIN(win)->attr.x != rep_INT(x) || VWIN(win)->attr.y != rep_INT(y))
254+ {
255+ VWIN(win)->attr.x = rep_INT(x);
256+ VWIN(win)->attr.y = rep_INT(y);
257+ XMoveWindow (dpy,
258+ VWIN(win)->reparented ? VWIN(win)->frame : VWIN(win)->id,
259+ VWIN(win)->attr.x, VWIN(win)->attr.y);
260+ send_synthetic_configure (VWIN(win));
261+ Fcall_window_hook (Qwindow_moved_hook, win, Qnil, Qnil);
262+ }
263+ return win;
264+}
265+
266+DEFUN("resize-window-to", Fresize_window_to, Sresize_window_to,
267+ (repv win, repv width, repv height), rep_Subr3) /*
268+::doc:sawfish.wm.windows.subrs#resize-window-to::
269+resize-window-to WINDOW WIDTH HEIGHT
270+
271+Set the dimensions of window object WINDOW to (WIDTH, HEIGHT).
272+::end:: */
273+{
274+ rep_DECLARE1(win, WINDOWP);
275+ rep_DECLARE2(width, rep_INTP);
276+ rep_DECLARE3(height, rep_INTP);
277+ VWIN(win)->attr.width = rep_INT(width);
278+ VWIN(win)->attr.height = rep_INT(height);
279+ fix_window_size (VWIN(win));
280+ VWIN (win)->pending_configure = 0;
281+ Fcall_window_hook (Qwindow_resized_hook, win, Qnil, Qnil);
282+ return win;
283+}
284+
285+DEFUN("move-resize-window-to", Fmove_resize_window_to, Smove_resize_window_to,
286+ (repv win, repv x, repv y, repv width, repv height), rep_Subr5) /*
287+::doc:sawfish.wm.windows.subrs#move-resize-window-to::
288+move-resize-window-to WINDOW X Y WIDTH HEIGHT
289+
290+Reconfigure the geometry of window object WINDOW as specified.
291+::end:: */
292+{
293+ bool resized, moved;
294+ rep_DECLARE1(win, WINDOWP);
295+ rep_DECLARE2(x, rep_INTP);
296+ rep_DECLARE3(y, rep_INTP);
297+ rep_DECLARE4(width, rep_INTP);
298+ rep_DECLARE5(height, rep_INTP);
299+ moved = (VWIN(win)->attr.x != rep_INT(x)
300+ || VWIN(win)->attr.y != rep_INT(y));
301+ resized = (VWIN(win)->attr.width != rep_INT(width)
302+ || VWIN(win)->attr.height != rep_INT(height));
303+ VWIN(win)->attr.x = rep_INT(x);
304+ VWIN(win)->attr.y = rep_INT(y);
305+ VWIN(win)->attr.width = rep_INT(width);
306+ VWIN(win)->attr.height = rep_INT(height);
307+ if (resized)
308+ {
309+ fix_window_size (VWIN(win));
310+ VWIN (win)->pending_configure = 0;
311+ }
312+ if (moved && !resized)
313+ {
314+ XMoveWindow (dpy, VWIN(win)->reparented ? VWIN(win)->frame
315+ : VWIN(win)->id, VWIN(win)->attr.x, VWIN(win)->attr.y);
316+ send_synthetic_configure (VWIN(win));
317+ }
318+ if (moved)
319+ Fcall_window_hook (Qwindow_moved_hook, win, Qnil, Qnil);
320+ if (resized)
321+ Fcall_window_hook (Qwindow_resized_hook, win, Qnil, Qnil);
322+ return win;
323+}
324+
325+DEFUN("grab-server", Fgrab_server, Sgrab_server, (void), rep_Subr0) /*
326+::doc:sawfish.wm.misc#grab-server::
327+grab-server
328+
329+Prevent any other clients from accessing the X server. See `ungrab-server'.
330+::end:: */
331+{
332+ if (server_grabs++ == 0)
333+ {
334+ XGrabServer (dpy);
335+ XSync (dpy, False);
336+ rep_mark_input_pending (ConnectionNumber (dpy));
337+ }
338+ return Qt;
339+}
340+
341+DEFUN("ungrab-server", Fungrab_server, Sungrab_server, (void), rep_Subr0) /*
342+::doc:sawfish.wm.misc#ungrab-server::
343+ungrab-server
344+
345+After a call to `grab-server' this will allow other clients to access
346+the X server again.
347+
348+Note that calls to `grab-server' and `ungrab-server' _nest_.
349+::end:: */
350+{
351+ if (--server_grabs == 0)
352+ {
353+ XUngrabServer (dpy);
354+ XFlush (dpy);
355+ }
356+ return Qt;
357+}
358+
359+DEFUN("server-grabbed-p", Fserver_grabbed_p,
360+ Sserver_grabbed_p, (void), rep_Subr0) /*
361+::doc:sawfish.wm.misc#server-grabbed-p::
362+server-grabbed-p
363+
364+Return t if the server is currently grabbed.
365+::end:: */
366+{
367+ return (server_grabs > 0) ? Qt : Qnil;
368+}
369+
370+/* Call this when the server may have been ungrabbed prematurely (imlib
371+ lossage) */
372+void
373+regrab_server (void)
374+{
375+ if (server_grabs > 0)
376+ {
377+ server_grabs--;
378+ Fgrab_server ();
379+ }
380+}
381+
382+DEFUN("grab-pointer", Fgrab_pointer, Sgrab_pointer,
383+ (repv win, repv cursor, repv ptr_sync, repv kbd_sync, repv confine_to),
384+ rep_Subr5) /*
385+::doc:sawfish.wm.events#grab-pointer::
386+grab-pointer [WINDOW] [CURSOR] [PTR-SYNC] [KBD-SYNC] [CONFINE-TO]
387+
388+Grab the pointer and direct all pointer events to window object
389+WINDOW. If CURSOR is defined and a cursor object, display this whilst
390+the pointer is grabbed.
391+
392+If PTR-SYNC or KBD-SYNC is non-nil the pointer or the keyboard will be
393+frozen, i.e., the device will not produce events until either the grab
394+is released or events are re-enabled using allow-events.
395+
396+CONFINE-TO, if non-nil, is a visible window to confine the pointer to.
397+
398+If WINDOW is a window object corresponding to a visible window the
399+grab will be made on its frame. If WINDOW is an integer, it specifies the
400+window id of the grab window. Otherwise the grab will be made on the root
401+window. CONFINE-TO is interpreted similarly except that the default
402+is not to confine the pointer. If the window id of a non-viewable window
403+was specified for either WINDOW of CONFINE-TO the grab will be made on the
404+root window without confining the pointer.
405+
406+Returns non-nil if the grab succeeded.
407+::end:: */
408+{
409+ Window g_win, c_win;
410+ int ret;
411+
412+ if (WINDOWP(win) && VWIN(win)->visible)
413+ g_win = VWIN(win)->frame;
414+ else if (rep_INTP(win))
415+ g_win = rep_INT(win);
416+ else
417+ g_win = root_window;
418+
419+ if (WINDOWP(confine_to) && VWIN(confine_to)->visible)
420+ c_win = VWIN(confine_to)->frame;
421+ else if (rep_INTP(confine_to))
422+ c_win = rep_INT(confine_to);
423+ else
424+ c_win = None;
425+
426+ if (cursor != Qnil && !CURSORP(cursor))
427+ {
428+ cursor = Fget_cursor (cursor);
429+ if (!cursor)
430+ cursor = Qnil;
431+ }
432+
433+again:
434+ ret = XGrabPointer (dpy, g_win, False, POINTER_GRAB_EVENTS,
435+ rep_NILP( ptr_sync) ? GrabModeAsync : GrabModeSync,
436+ rep_NILP( kbd_sync) ? GrabModeAsync : GrabModeSync,
437+ c_win,
438+ CURSORP(cursor) ? VCURSOR(cursor)->cursor : None,
439+ last_event_time);
440+ if (ret == GrabNotViewable && (g_win != root_window || c_win != None))
441+ {
442+ /* fall back to the root window. */
443+ g_win = root_window;
444+ c_win = None;
445+ goto again;
446+ }
447+
448+ DB(("grab-pointer: time=%lu ret=%d\n", last_event_time, ret));
449+ return (ret == GrabSuccess) ? Qt : Qnil;
450+}
451+
452+DEFUN("ungrab-pointer", Fungrab_pointer, Sungrab_pointer, (void), rep_Subr0) /*
453+::doc:sawfish.wm.events#ungrab-pointer::
454+ungrab-pointer
455+
456+Release the grab on the mouse pointer.
457+::end:: */
458+{
459+ XUngrabPointer (dpy, last_event_time);
460+ synthesize_button_release ();
461+ DB(("ungrab-pointer: time=%lu\n", last_event_time));
462+ return Qt;
463+}
464+
465+DEFUN("grab-keyboard", Fgrab_keyboard, Sgrab_keyboard,
466+ (repv win, repv ptr_sync, repv kbd_sync), rep_Subr3) /*
467+::doc:sawfish.wm.events#grab-keyboard::
468+grab-keyboard [WINDOW] [PTR-SYNC] [KBD-SYNC]
469+
470+Grab the keyboard and direct all keyboard events to window object
471+WINDOW. If WINDOW is a window object corresponding to a visible
472+window the grab will be made on its frame. If WINDOW is an integer it
473+specifies the window id of the grab window. Otherwise the grab will
474+be made on the root window. If the window id of a non-viewable window
475+was specified the grab is made on the root window instead.
476+
477+If PTR-SYNC or KBD-SYNC is non-nil the pointer or the keyboard will be
478+frozen, i.e., the device will not produce events until either the grab
479+is released or events are re-enabled using allow-events.
480+
481+Returns non-nil if the grab succeeded.
482+::end:: */
483+{
484+ Window g_win;
485+ int ret;
486+
487+ if (WINDOWP(win) && VWIN(win)->visible)
488+ g_win = VWIN(win)->frame;
489+ else if (rep_INTP(win))
490+ g_win = rep_INT(win);
491+ else
492+ g_win = root_window;
493+
494+again:
495+ ret = XGrabKeyboard (dpy, g_win, False,
496+ rep_NILP( ptr_sync) ? GrabModeAsync : GrabModeSync,
497+ rep_NILP( kbd_sync) ? GrabModeAsync : GrabModeSync,
498+ last_event_time);
499+ if (ret == GrabNotViewable && g_win != root_window)
500+ {
501+ /* fall back to the root window. */
502+ g_win = root_window;
503+ goto again;
504+ }
505+
506+ DB(("grab-keyboard: time=%lu ret=%d\n", last_event_time, ret));
507+ return (ret == GrabSuccess) ? Qt : Qnil;
508+}
509+
510+DEFUN("ungrab-keyboard", Fungrab_keyboard,
511+ Sungrab_keyboard, (void), rep_Subr0) /*
512+::doc:sawfish.wm.events#ungrab-keyboard::
513+ungrab-keyboard
514+
515+Release the grab on the keyboard.
516+::end:: */
517+{
518+ DB(("ungrab-keyboard: time=%lu\n", last_event_time));
519+ XUngrabKeyboard (dpy, last_event_time);
520+ return Qt;
521+}
522+
523+DEFUN("screen-width", Fscreen_width, Sscreen_width, (void), rep_Subr0) /*
524+::doc:sawfish.wm.misc#screen-width::
525+screen-width
526+
527+Return the width of the root window (in pixels).
528+::end:: */
529+{
530+ return rep_MAKE_INT(screen_width);
531+}
532+
533+DEFUN("screen-height", Fscreen_height, Sscreen_height, (void), rep_Subr0) /*
534+::doc:sawfish.wm.misc#screen-height::
535+screen-height
536+
537+Return the height of the root window (in pixels).
538+::end:: */
539+{
540+ return rep_MAKE_INT(screen_height);
541+}
542+
543+DEFUN("sync-server", Fsync_server, Ssync_server, (void), rep_Subr0) /*
544+::doc:sawfish.wm.misc#sync-server::
545+sync-server
546+
547+Flush all pending X requests, don't wait for them to finish.
548+::end:: */
549+{
550+ XFlush (dpy);
551+ return Qt;
552+}
553+
554+DEFUN("delete-x-property", Fdelete_x_property, Sdelete_x_property,
555+ (repv win, repv atom), rep_Subr2) /*
556+::doc:sawfish.wm.misc#delete-x-property::
557+delete-x-property WINDOW ATOM
558+
559+Delete the X property ATOM (a symbol) of WINDOW.
560+
561+WINDOW may be the symbol `root', a window object or a numeric window id.
562+::end:: */
563+{
564+ Window w = x_win_from_arg (win);
565+ rep_DECLARE2(atom, rep_SYMBOLP);
566+ if (w == 0)
567+ return WINDOWP(win) ? atom : rep_signal_arg_error (win, 1);
568+ XDeleteProperty (dpy, w,
569+ XInternAtom (dpy, rep_STR(rep_SYM(atom)->name), False));
570+ return atom;
571+}
572+
573+DEFUN("list-x-properties", Flist_x_properties, Slist_x_properties,
574+ (repv win), rep_Subr1) /*
575+::doc:sawfish.wm.misc#list-x-properties::
576+list-x-properties WINDOW
577+
578+List all X properties (symbols) of WINDOW.
579+
580+WINDOW may be the symbol `root', a window object or a numeric window id.
581+::end:: */
582+{
583+ Window w;
584+ Atom *atoms;
585+ int count;
586+ repv ret = Qnil;
587+
588+ w = x_win_from_arg (win);
589+ if (w == 0)
590+ return WINDOWP(win) ? Qnil : rep_signal_arg_error (win, 1);
591+ atoms = XListProperties (dpy, w, &count);
592+ if (atoms != 0)
593+ {
594+ char **names = alloca (sizeof (char *) * count);
595+ if (XGetAtomNames (dpy, atoms, count, names) != 0)
596+ {
597+ int i;
598+ for (i = 0; i < count; i++)
599+ {
600+ ret = Fcons (Fintern (rep_string_dup (names[i]),
601+ rep_obarray), ret);
602+ XFree (names[i]);
603+ }
604+ }
605+ XFree (atoms);
606+ }
607+ return Fnreverse (ret);
608+}
609+
610+DEFUN("get-x-property", Fget_x_property, Sget_x_property,
611+ (repv win, repv prop), rep_Subr2) /*
612+::doc:sawfish.wm.misc#get-x-property::
613+get-x-property WINDOW PROPERTY
614+
615+Return (TYPE FORMAT DATA) representing the X property PROPERTY (a
616+symbol) of WINDOW. If no such property exists, return nil.
617+
618+WINDOW may be the symbol `root', a window object or a numeric window
619+id.
620+
621+TYPE is a symbol representing the atom defining the type of the
622+property. FORMAT is an integer, either 8, 16 or 32, defining the width
623+of the data items read. DATA is an array, either a string for an 8-bit
624+format, or a vector of integers.
625+
626+If TYPE is `ATOM' and FORMAT is 32, then DATA will be a vector of
627+symbols, representing the atoms read.
628+::end:: */
629+{
630+ Window w;
631+ Atom a_prop;
632+ Atom type;
633+ int format;
634+ u_long nitems;
635+ u_char *data = 0;
636+ repv type_sym, ret_data = Qnil;
637+
638+ w = x_win_from_arg (win);
639+ rep_DECLARE2(prop, rep_SYMBOLP);
640+ if (w == 0)
641+ return WINDOWP(win) ? Qnil : rep_signal_arg_error (win, 1);
642+ a_prop = XInternAtom (dpy, rep_STR(rep_SYM(prop)->name), False);
643+
644+ /* First read the data.. */
645+ {
646+ long long_length = 32;
647+ u_long bytes_after;
648+ while (1)
649+ {
650+ if (data != 0)
651+ XFree (data);
652+ if (XGetWindowProperty (dpy, w, a_prop, 0, long_length, False,
653+ AnyPropertyType, &type, &format,
654+ &nitems, &bytes_after, &data) != Success)
655+ return Qnil;
656+ if (type == None)
657+ return Qnil;
658+ if (bytes_after == 0)
659+ break;
660+ long_length += (bytes_after / sizeof(u_long)) + 1;
661+ }
662+ }
663+
664+ /* Convert the type to a symbol */
665+ type_sym = x_atom_symbol (type);
666+
667+ /* Then convert the contents to a vector or string */
668+ switch (format)
669+ {
670+ u_short *s_data;
671+ u_long *l_data;
672+ int i;
673+
674+ case 8:
675+ ret_data = rep_string_dupn (data, nitems);
676+ break;
677+
678+ case 16:
679+ ret_data = Fmake_vector (rep_MAKE_INT(nitems), Qnil);
680+ s_data = (u_short *)data;
681+ for (i = 0; i < nitems; i++)
682+ rep_VECTI(ret_data, i) = rep_MAKE_INT(s_data[i]);
683+ break;
684+
685+ case 32:
686+ ret_data = Fmake_vector (rep_MAKE_INT(nitems), Qnil);
687+ l_data = (u_long *)data;
688+ for (i = 0; i < nitems; i++)
689+ {
690+ repv name;
691+ if (type == XA_ATOM && (name = x_atom_symbol (l_data[i])) != Qnil)
692+ rep_VECTI(ret_data, i) = name;
693+ else
694+ rep_VECTI(ret_data, i) = rep_make_long_uint(l_data[i]);
695+ }
696+ break;
697+ }
698+ XFree (data);
699+
700+ return rep_list_3 (type_sym, rep_MAKE_INT(format), ret_data);
701+}
702+
703+DEFUN("set-x-property", Fset_x_property, Sset_x_property,
704+ (repv win, repv prop, repv data, repv type, repv format), rep_Subr5) /*
705+::doc:sawfish.wm.misc#set-x-property::
706+set-x-property WINDOW PROPERTY DATA TYPE FORMAT
707+
708+Set the X property PROPERTY (a symbol) of WINDOW to the array DATA.
709+
710+WINDOW may be the symbol `root', a window object or a numeric window
711+id.
712+
713+TYPE is a symbol representing the atom defining the type of the
714+property, FORMAT is either 8, 16 or 32 defining the width of the data
715+values. DATA is either a string or a vector of integers.
716+
717+If TYPE is `ATOM' and FORMAT is 32, then any symbols in DATA will be
718+converted to their numeric X atoms.
719+::end:: */
720+{
721+ Window w;
722+ Atom a_prop, a_type;
723+ u_long nitems;
724+ u_char *c_data = 0;
725+
726+ w = x_win_from_arg (win);
727+ rep_DECLARE2(prop, rep_SYMBOLP);
728+ a_prop = XInternAtom (dpy, rep_STR(rep_SYM(prop)->name), False);
729+ rep_DECLARE(3, data, rep_VECTORP(data) || rep_STRINGP(data));
730+ rep_DECLARE4(type, rep_SYMBOLP);
731+ a_type = XInternAtom (dpy, rep_STR(rep_SYM(type)->name), False);
732+ rep_DECLARE5(format, rep_INTP);
733+ if (w == 0)
734+ return WINDOWP(win) ? prop : rep_signal_arg_error (win, 1);
735+
736+ /* Convert to data array */
737+
738+ if (rep_STRINGP(data))
739+ nitems = rep_STRING_LEN(data);
740+ else
741+ nitems = rep_VECT_LEN(data);
742+
743+ switch (rep_INT(format))
744+ {
745+ int i;
746+ u_short *s_data;
747+ u_long *l_data;
748+
749+ case 8:
750+ if (rep_STRINGP(data))
751+ c_data = rep_STR (data);
752+ else
753+ {
754+ c_data = alloca (nitems);
755+ for (i = 0; i < nitems; i++)
756+ c_data[i] = rep_STR(data)[i];
757+ }
758+ break;
759+
760+ case 16:
761+ if (rep_STRINGP(data))
762+ return rep_signal_arg_error (data, 3);
763+ c_data = alloca (nitems * sizeof (u_short));
764+ s_data = (u_short *)c_data;
765+ for (i = 0; i < nitems; i++)
766+ s_data[i] = rep_INT(rep_VECTI(data, i));
767+ break;
768+
769+ case 32:
770+ if (rep_STRINGP(data))
771+ return rep_signal_arg_error (data, 3);
772+ c_data = alloca (nitems * sizeof (u_long));
773+ l_data = (u_long *)c_data;
774+ for (i = 0; i < nitems; i++)
775+ {
776+ if (a_type == XA_ATOM && rep_SYMBOLP(rep_VECTI(data, i)))
777+ l_data[i] = XInternAtom (dpy, rep_STR(rep_SYM(rep_VECTI(data, i))->name), False);
778+ else
779+ l_data[i] = rep_get_long_uint (rep_VECTI(data, i));
780+ }
781+ break;
782+ }
783+
784+ /* Overwrite property */
785+ XChangeProperty (dpy, w, a_prop, a_type, rep_INT(format),
786+ PropModeReplace, c_data, nitems);
787+ return prop;
788+}
789+
790+DEFUN("get-x-text-property", Fget_x_text_property, Sget_x_text_property,
791+ (repv win, repv prop), rep_Subr2) /*
792+::doc:sawfish.wm.misc#get-x-text-property::
793+get-x-text-property WINDOW PROPERTY
794+::end:: */
795+{
796+ Window w;
797+ Atom a_prop;
798+ XTextProperty t_prop;
799+ repv ret = Qnil;
800+
801+ w = x_win_from_arg (win);
802+ rep_DECLARE2(prop, rep_SYMBOLP);
803+ if (w == 0)
804+ return WINDOWP(win) ? Qnil : rep_signal_arg_error (win, 1);
805+ a_prop = XInternAtom (dpy, rep_STR(rep_SYM(prop)->name), False);
806+
807+ if (XGetTextProperty (dpy, w, &t_prop, a_prop) != 0)
808+ {
809+ char **list;
810+ int count;
811+ if (XTextPropertyToStringList (&t_prop, &list, &count) != 0)
812+ {
813+ int i;
814+ ret = Fmake_vector (rep_MAKE_INT(count), Qnil);
815+ for (i = 0; i < count; i++)
816+ rep_VECTI(ret, i) = rep_string_dup (list[i]);
817+ XFreeStringList (list);
818+ }
819+ XFree (t_prop.value);
820+ }
821+
822+ return ret;
823+}
824+
825+DEFUN("set-x-text-property", Fset_x_text_property, Sset_x_text_property,
826+ (repv win, repv prop, repv vect), rep_Subr3) /*
827+::doc:sawfish.wm.misc#set-x-text-prooperty::
828+set-x-text-property WINDOW PROPERTY STRING-VECTOR
829+::end:: */
830+{
831+ Window w;
832+ Atom a_prop;
833+ XTextProperty t_prop;
834+ char **strings;
835+ int count, i;
836+
837+ w = x_win_from_arg (win);
838+ rep_DECLARE2(prop, rep_SYMBOLP);
839+ rep_DECLARE3(vect, rep_VECTORP);
840+ if (w == 0)
841+ return WINDOWP(win) ? Qnil : rep_signal_arg_error (win, 1);
842+ a_prop = XInternAtom (dpy, rep_STR(rep_SYM(prop)->name), False);
843+
844+ count = rep_VECT_LEN(vect);
845+ strings = alloca (sizeof (char *) * (count + 1));
846+ for (i = 0; i < count; i++)
847+ {
848+ if (!rep_STRINGP(rep_VECTI(vect, i)))
849+ return rep_signal_arg_error (vect, 3);
850+ strings[i] = rep_STR(rep_VECTI(vect, i));
851+ }
852+ if (XStringListToTextProperty (strings, count, &t_prop) != 0)
853+ {
854+ XSetTextProperty (dpy, w, &t_prop, a_prop);
855+ XFree (t_prop.value);
856+ }
857+
858+ return Qt;
859+}
860+
861+DEFUN("send-client-message", Fsend_client_message, Ssend_client_message,
862+ (repv win, repv type, repv data, repv format), rep_Subr4) /*
863+::doc:sawfish.wm.events#send-client-message::
864+send-client-message WINDOW TYPE DATA FORMAT
865+
866+Send an X ClientMessage event to WINDOW (a window object or the symbol
867+`root'). It will be of the type TYPE (a symbol), contain the array of
868+integers DATA (i.e. a vector or a string), and it will be transferred as
869+FORMAT sized quantities (8, 16 or 32).
870+::end:: */
871+{
872+ XClientMessageEvent ev;
873+ Window w = x_win_from_arg (win);
874+
875+ rep_DECLARE2(type, rep_SYMBOLP);
876+ rep_DECLARE(3, data, rep_STRINGP(data) || rep_VECTORP(data));
877+ rep_DECLARE4(format, rep_INTP);
878+
879+ if (w == 0)
880+ return WINDOWP(win) ? Qnil : rep_signal_arg_error (win, 1);
881+
882+ ev.type = ClientMessage;
883+ ev.window = w;
884+ ev.message_type = XInternAtom (dpy, rep_STR(rep_SYM(type)->name), False);
885+ ev.format = rep_INT(format);
886+
887+ switch (rep_INT(format))
888+ {
889+ int i;
890+
891+ case 8:
892+ if (rep_STRINGP(data))
893+ memcpy (rep_STR(data), ev.data.b, MAX(rep_STRING_LEN(data), 20));
894+ else
895+ {
896+ for (i = 0; i < rep_VECT_LEN(data) && i < 20; i++)
897+ ev.data.b[i] = rep_INT(rep_VECTI(data, i));
898+ }
899+ break;
900+
901+ case 16:
902+ if (rep_STRINGP(data))
903+ return rep_signal_arg_error (data, 3);
904+ for (i = 0; i < rep_VECT_LEN(data) && i < 10; i++)
905+ ev.data.s[i] = rep_INT(rep_VECTI(data, i));
906+ break;
907+
908+ case 32:
909+ if (rep_STRINGP(data))
910+ return rep_signal_arg_error (data, 3);
911+ for (i = 0; i < rep_VECT_LEN(data) && i < 5; i++)
912+ ev.data.l[i] = rep_get_long_uint (rep_VECTI(data, i));
913+ break;
914+ }
915+
916+ XSendEvent (dpy, w, False, 0L, (XEvent *) &ev);
917+ return win;
918+}
919+
920+DEFUN("create-window", Fcreate_window, Screate_window,
921+ (repv parent, repv x, repv y, repv width, repv height), rep_Subr5) /*
922+::doc:sawfish.wm.misc#create-window::
923+create-window PARENT-WINDOW X Y WIDTH HEIGHT
924+
925+Create an unmapped window that is a child of PARENT-WINDOW (a window object,
926+an integer window id, or the symbol `root'), with the specified dimensions.
927+
928+Returns the window id of the new window.
929+::end:: */
930+{
931+ Window parent_w = x_win_from_arg (parent);
932+ Window id;
933+ rep_DECLARE2(x, rep_INTP);
934+ rep_DECLARE3(y, rep_INTP);
935+ rep_DECLARE4(width, rep_INTP);
936+ rep_DECLARE5(height, rep_INTP);
937+ if (parent_w == 0)
938+ return WINDOWP(parent) ? Qnil : rep_signal_arg_error (parent, 1);
939+ id = XCreateSimpleWindow (dpy, parent_w, rep_INT(x), rep_INT(y),
940+ rep_INT(width), rep_INT(height),
941+ 0, BlackPixel (dpy, screen_num),
942+ WhitePixel (dpy, screen_num));
943+ return id ? rep_MAKE_INT(id) : Qnil;
944+}
945+
946+DEFUN("x-atom", Fx_atom, Sx_atom, (repv symbol), rep_Subr1) /*
947+::doc:sawfish.wm.misc#x-atom::
948+x-atom SYMBOL
949+
950+Return the integer identifying the X atom with the same name as SYMBOL.
951+::end:: */
952+{
953+ rep_DECLARE1(symbol, rep_SYMBOLP);
954+ return rep_MAKE_INT (XInternAtom (dpy, rep_STR(rep_SYM(symbol)->name),
955+ False));
956+}
957+
958+DEFUN("x-atom-name", Fx_atom_name, Sx_atom_name, (repv atom), rep_Subr1) /*
959+::doc:sawfish.wm.misc#x-atom-name::
960+x-atom-name ATOM
961+
962+Return the symbol with the same name as the X atom identified by the
963+integer ATOM.
964+::end:: */
965+{
966+ rep_DECLARE1(atom, rep_INTP);
967+ return x_atom_symbol (rep_INT(atom));
968+}
969+
970+DEFUN("root-window-id", Froot_window_id, Sroot_window_id, (void), rep_Subr0) /*
971+::doc:sawfish.wm.misc#root-window-id::
972+root-window-id
973+
974+Returns the numeric id of the root window of the managed screen.
975+::end:: */
976+{
977+ return rep_MAKE_INT (root_window);
978+}
979+
980+
981+/* xinerama support */
982+
983+DEFUN ("head-count", Fhead_count, Shead_count, (void), rep_Subr0)
984+{
985+ return rep_MAKE_INT (MAX (1, xinerama_heads));
986+}
987+
988+DEFUN ("find-head", Ffind_head, Sfind_head, (repv x, repv y), rep_Subr2)
989+{
990+ if (rep_CONSP (x) && y == Qnil)
991+ {
992+ y = rep_CDR (x);
993+ x = rep_CAR (x);
994+ }
995+ rep_DECLARE (1, x, rep_INTP (x));
996+ rep_DECLARE (2, y, rep_INTP (y));
997+
998+#ifdef HAVE_X11_EXTENSIONS_XINERAMA_H
999+ {
1000+ int i;
1001+ for (i = 0; i < xinerama_heads; i++)
1002+ {
1003+ if ((xinerama_head_info[i].x_org <= rep_INT (x))
1004+ && (xinerama_head_info[i].y_org <= rep_INT (y))
1005+ && (xinerama_head_info[i].x_org
1006+ + xinerama_head_info[i].width > rep_INT (x))
1007+ && (xinerama_head_info[i].y_org
1008+ + xinerama_head_info[i].height > rep_INT (y)))
1009+ {
1010+ return rep_MAKE_INT (i);
1011+ }
1012+ }
1013+ }
1014+#endif
1015+ if (xinerama_heads == 0
1016+ && rep_INT (x) >= 0 && rep_INT (x) < screen_width
1017+ && rep_INT (y) >= 0 && rep_INT (y) < screen_height)
1018+ {
1019+ return rep_MAKE_INT (0);
1020+ }
1021+ return Qnil;
1022+}
1023+
1024+DEFUN ("head-dimensions", Fhead_dimensions,
1025+ Shead_dimensions, (repv id), rep_Subr1)
1026+{
1027+ rep_DECLARE (1, id, rep_INTP (id));
1028+
1029+ if (xinerama_heads == 0 && rep_INT (id) == 0)
1030+ {
1031+ return Fcons (rep_MAKE_INT (screen_width),
1032+ rep_MAKE_INT (screen_height));
1033+ }
1034+ else
1035+ {
1036+ rep_DECLARE (1, id, rep_INT (id) >= 0
1037+ && rep_INT (id) < xinerama_heads);
1038+#ifdef HAVE_X11_EXTENSIONS_XINERAMA_H
1039+ return Fcons (rep_MAKE_INT (xinerama_head_info[rep_INT(id)].width),
1040+ rep_MAKE_INT (xinerama_head_info[rep_INT(id)].height));
1041+#else
1042+ abort ();
1043+#endif
1044+ }
1045+}
1046+
1047+DEFUN ("head-offset", Fhead_offset, Shead_offset, (repv id), rep_Subr1)
1048+{
1049+ rep_DECLARE (1, id, rep_INTP (id));
1050+
1051+ if (xinerama_heads == 0 && rep_INT (id) == 0)
1052+ {
1053+ return Fcons (rep_MAKE_INT (0), rep_MAKE_INT (0));
1054+ }
1055+ else
1056+ {
1057+ rep_DECLARE (1, id, rep_INT (id) >= 0
1058+ && rep_INT (id) < xinerama_heads);
1059+#ifdef HAVE_X11_EXTENSIONS_XINERAMA_H
1060+ return Fcons (rep_MAKE_INT (xinerama_head_info[rep_INT(id)].x_org),
1061+ rep_MAKE_INT (xinerama_head_info[rep_INT(id)].y_org));
1062+#else
1063+ abort ();
1064+#endif
1065+ }
1066+}
1067+
1068+
1069+/* Displaying a `message' window */
1070+
1071+static Window message_win;
1072+
1073+static struct {
1074+ GC gc;
1075+ repv text, fg, bg, font, justify;
1076+ int width, spacing;
1077+} message;
1078+
1079+#define MSG_PAD_X 20
1080+#define MSG_PAD_Y 10
1081+
1082+static void
1083+refresh_message_window ()
1084+{
1085+ if (message_win != 0)
1086+ {
1087+ XGCValues values;
1088+ u_long mask;
1089+ char *ptr;
1090+ int row = 0;
1091+
1092+ values.foreground = VCOLOR(message.fg)->pixel;
1093+ values.background = VCOLOR(message.bg)->pixel;
1094+ mask = GCForeground | GCBackground;
1095+
1096+ if (message.gc == 0)
1097+ message.gc = XCreateGC (dpy, message_win, mask, &values);
1098+ else
1099+ XChangeGC (dpy, message.gc, mask, &values);
1100+
1101+ XClearWindow (dpy, message_win);
1102+
1103+ ptr = rep_STR(message.text);
1104+ while (*ptr != 0)
1105+ {
1106+ char *end = strchr (ptr, '\n');
1107+ int offset;
1108+ if (end == 0)
1109+ end = ptr + strlen (ptr);
1110+ if (message.justify == Qleft)
1111+ offset = MSG_PAD_X;
1112+ else
1113+ {
1114+ int width = x_text_width (message.font, ptr, end - ptr);
1115+ if (message.justify == Qright)
1116+ offset = message.width - (width + MSG_PAD_X);
1117+ else
1118+ offset = (message.width - width) / 2;
1119+ }
1120+ x_draw_string (message_win, message.font,
1121+ message.gc, offset,
1122+ MSG_PAD_Y
1123+ + row * (VFONT(message.font)->ascent
1124+ + VFONT(message.font)->descent
1125+ + message.spacing)
1126+ + VFONT(message.font)->ascent, ptr, end - ptr);
1127+ row++;
1128+ ptr = end;
1129+ if (*ptr == '\n')
1130+ ptr++;
1131+ }
1132+ }
1133+}
1134+
1135+static void
1136+message_event_handler (XEvent *ev)
1137+{
1138+ if (ev->type == Expose)
1139+ refresh_message_window ();
1140+ else if (ev->type == ButtonPress)
1141+ Fdisplay_message (Qnil, Qnil);
1142+}
1143+
1144+DEFSTRING(white, "white");
1145+DEFSTRING(black, "black");
1146+
1147+DEFUN("display-message", Fdisplay_message, Sdisplay_message,
1148+ (repv text, repv attrs), rep_Subr2)
1149+{
1150+ if (text == Qnil)
1151+ {
1152+ if (message_win != 0)
1153+ {
1154+ deregister_event_handler (message_win);
1155+ XDestroyWindow (dpy, message_win);
1156+ message_win = 0;
1157+ }
1158+ if (message.gc != 0)
1159+ {
1160+ XFreeGC (dpy, message.gc);
1161+ message.gc = 0;
1162+ }
1163+ message.font = message.fg = message.bg = message.text = Qnil;
1164+ return Qnil;
1165+ }
1166+ else
1167+ {
1168+ int height, x, y;
1169+ repv tem;
1170+
1171+ rep_DECLARE1(text, rep_STRINGP);
1172+ rep_DECLARE2(attrs, rep_LISTP);
1173+
1174+ message.text = text;
1175+ message.font = message.fg = message.bg = Qnil;
1176+ message.justify = Qleft;
1177+ message.spacing = 0;
1178+
1179+ tem = Fassq (Qfont, attrs);
1180+ if (tem && rep_CONSP(tem))
1181+ {
1182+ message.font = rep_CDR(tem);
1183+ if (!FONTP(message.font))
1184+ {
1185+ message.font = Fget_font (message.font);
1186+ if (!message.font)
1187+ return rep_NULL;
1188+ }
1189+ }
1190+ if (!FONTP(message.font))
1191+ message.font = global_symbol_value (Qdefault_font);
1192+ if (!FONTP(message.font))
1193+ return rep_signal_arg_error (Qfont, 1);
1194+
1195+ tem = Fassq (Qforeground, attrs);
1196+ if (tem && rep_CONSP(tem))
1197+ {
1198+ message.fg = rep_CDR(tem);
1199+ if (!COLORP(message.fg))
1200+ {
1201+ message.fg = Fget_color (message.fg);
1202+ if (!message.fg)
1203+ return rep_NULL;
1204+ }
1205+ }
1206+ if (!COLORP(message.fg))
1207+ message.fg = Fget_color (rep_VAL(&black));
1208+ if (!COLORP(message.fg))
1209+ return rep_signal_arg_error (Qforeground, 1);
1210+
1211+ tem = Fassq (Qbackground, attrs);
1212+ if (tem && rep_CONSP(tem))
1213+ {
1214+ message.bg = rep_CDR(tem);
1215+ if (!COLORP(message.bg))
1216+ {
1217+ message.bg = Fget_color (message.bg);
1218+ if (!message.bg)
1219+ return rep_NULL;
1220+ }
1221+ }
1222+ if (!COLORP(message.bg))
1223+ message.bg = Fget_color (rep_VAL(&white));
1224+ if (!COLORP(message.bg))
1225+ return rep_signal_arg_error (Qbackground, 1);
1226+
1227+ tem = Fassq (Qx_justify, attrs);
1228+ if (tem && rep_CONSP(tem))
1229+ message.justify = rep_CDR(tem);
1230+
1231+ tem = Fassq (Qspacing, attrs);
1232+ if (tem && rep_CONSP(tem) && rep_INTP(rep_CDR(tem)))
1233+ message.spacing = rep_INT(rep_CDR(tem));
1234+
1235+ {
1236+ char *ptr = rep_STR(text);
1237+ int max_width = 0, rows = 0;
1238+ repv head = Qnil;
1239+ int head_width, head_height;
1240+ int head_xoff, head_yoff;
1241+ while (*ptr != 0)
1242+ {
1243+ int text_width;
1244+ char *end = strchr (ptr, '\n');
1245+ if (end == 0)
1246+ end = ptr + strlen (ptr);
1247+ text_width = x_text_width (message.font, ptr, end - ptr);
1248+ max_width = MAX(max_width, text_width);
1249+ rows++;
1250+ ptr = end;
1251+ if (*ptr == '\n')
1252+ ptr++;
1253+ }
1254+ message.width = max_width + MSG_PAD_X * 2;
1255+ height = ((rep_INT(Ffont_height (message.font)) + message.spacing)
1256+ * rows + MSG_PAD_Y * 2);
1257+
1258+ /* Find the head to put the message on. */
1259+ tem = Fassq (Qhead, attrs);
1260+ if (tem && rep_CONSP (tem) && rep_INTP (rep_CDR (tem)))
1261+ head = rep_CDR (tem);
1262+ if (!head || head == Qnil)
1263+ head = Ffind_head (Fquery_pointer (Qnil), Qnil);
1264+
1265+ if (head && head != Qnil)
1266+ {
1267+ /* We have a head to centre on. */
1268+
1269+ tem = Fhead_dimensions (head);
1270+ if (!tem)
1271+ goto no_head;
1272+ head_width = rep_INT (rep_CAR (tem));
1273+ head_height = rep_INT (rep_CDR (tem));
1274+
1275+ tem = Fhead_offset (head);
1276+ if (!tem)
1277+ goto no_head;
1278+ head_xoff = rep_INT (rep_CAR (tem));
1279+ head_yoff = rep_INT (rep_CDR (tem));
1280+ }
1281+ else
1282+ {
1283+ /* No head, just centre on the screen. */
1284+ no_head:
1285+ head_xoff = head_yoff = 0;
1286+ head_width = screen_width;
1287+ head_height = screen_height;
1288+ }
1289+
1290+ x = head_xoff + ((head_width - message.width) / 2);
1291+ y = head_yoff + ((head_height - height) / 2);
1292+ }
1293+
1294+ tem = Fassq (Qposition, attrs);
1295+ if (tem && rep_CONSP(tem))
1296+ {
1297+ tem = rep_CDR(tem);
1298+ if (rep_CONSP(tem))
1299+ {
1300+ if (rep_INTP(rep_CAR(tem)))
1301+ {
1302+ x = rep_INT(rep_CAR(tem));
1303+ if (x < 0)
1304+ x += screen_width - message.width;
1305+ }
1306+ if (rep_INTP(rep_CDR(tem)))
1307+ {
1308+ y = rep_INT(rep_CDR(tem));
1309+ if (y < 0)
1310+ y += screen_height - height;
1311+ }
1312+ }
1313+ }
1314+
1315+ if (x + message.width > screen_width)
1316+ x = MAX (0, screen_width - message.width - 4);
1317+ else if (x < 4)
1318+ x = 4;
1319+ if (y + height > screen_height)
1320+ y = MAX (0, screen_height - height - 4);
1321+ else if (y < 4)
1322+ y = 4;
1323+
1324+ if (message_win == 0)
1325+ {
1326+ /* I tried setting save_under in here, but it just slows
1327+ down opaque window moves.. */
1328+ XSetWindowAttributes attr;
1329+ attr.override_redirect = True;
1330+ attr.background_pixel = VCOLOR(message.bg)->pixel;
1331+ attr.border_pixel = BlackPixel(dpy, screen_num);
1332+ attr.event_mask = ExposureMask | ButtonPressMask;
1333+ attr.colormap = image_cmap;
1334+ message_win = XCreateWindow (dpy, root_window, x, y,
1335+ message.width, height, 1,
1336+ image_depth, InputOutput,
1337+ image_visual,
1338+ CWBackPixel | CWBorderPixel
1339+ | CWOverrideRedirect | CWEventMask
1340+ | CWColormap, &attr);
1341+ if (message_win == 0)
1342+ return Qnil;
1343+ register_event_handler (message_win, message_event_handler);
1344+ XMapRaised (dpy, message_win);
1345+ }
1346+ else
1347+ {
1348+ XWindowChanges attr;
1349+ attr.x = x;
1350+ attr.y = y;
1351+ attr.width = message.width;
1352+ attr.height = height;
1353+ attr.stack_mode = TopIf;
1354+ XConfigureWindow (dpy, message_win,
1355+ CWX | CWY | CWWidth | CWHeight | CWStackMode,
1356+ &attr);
1357+ XSetWindowBackground (dpy, message_win, VCOLOR(message.bg)->pixel);
1358+ refresh_message_window ();
1359+ }
1360+ return rep_MAKE_INT(message_win);
1361+ }
1362+}
1363+
1364+
1365+/* initialisation */
1366+
1367+void
1368+functions_init (void)
1369+{
1370+ repv tem;
1371+
1372+ tem = rep_push_structure ("sawfish.wm.windows.subrs");
1373+ rep_ADD_SUBR(Srestack_windows);
1374+ rep_ADD_SUBR(Sx_raise_window);
1375+ rep_ADD_SUBR(Sx_lower_window);
1376+ rep_ADD_SUBR_INT(Sdestroy_window);
1377+ rep_ADD_SUBR(Smove_window_to);
1378+ rep_ADD_SUBR(Sresize_window_to);
1379+ rep_ADD_SUBR(Smove_resize_window_to);
1380+ rep_pop_structure (tem);
1381+
1382+ tem = rep_push_structure ("sawfish.wm.misc");
1383+ rep_ADD_SUBR(Sx_kill_client);
1384+ rep_ADD_SUBR(Swarp_cursor);
1385+ rep_ADD_SUBR(Sgrab_server);
1386+ rep_ADD_SUBR(Sungrab_server);
1387+ rep_ADD_SUBR(Sserver_grabbed_p);
1388+ rep_ADD_SUBR(Sscreen_width);
1389+ rep_ADD_SUBR(Sscreen_height);
1390+ rep_ADD_SUBR(Ssync_server);
1391+ rep_ADD_SUBR(Sdelete_x_property);
1392+ rep_ADD_SUBR(Slist_x_properties);
1393+ rep_ADD_SUBR(Sget_x_property);
1394+ rep_ADD_SUBR(Sset_x_property);
1395+ rep_ADD_SUBR(Sget_x_text_property);
1396+ rep_ADD_SUBR(Sset_x_text_property);
1397+ rep_ADD_SUBR(Screate_window);
1398+ rep_ADD_SUBR(Sx_atom);
1399+ rep_ADD_SUBR(Sx_atom_name);
1400+ rep_ADD_SUBR(Sroot_window_id);
1401+ rep_ADD_SUBR(Shead_count);
1402+ rep_ADD_SUBR(Sfind_head);
1403+ rep_ADD_SUBR(Shead_dimensions);
1404+ rep_ADD_SUBR(Shead_offset);
1405+ rep_ADD_SUBR(Sdisplay_message);
1406+ rep_pop_structure (tem);
1407+
1408+ tem = rep_push_structure ("sawfish.wm.events");
1409+ rep_ADD_SUBR(Sgrab_pointer);
1410+ rep_ADD_SUBR(Sungrab_pointer);
1411+ rep_ADD_SUBR(Sgrab_keyboard);
1412+ rep_ADD_SUBR(Sungrab_keyboard);
1413+ rep_ADD_SUBR(Ssend_client_message);
1414+ rep_pop_structure (tem);
1415+
1416+ rep_INTERN(root);
1417+ rep_INTERN_SPECIAL(after_restacking_hook);
1418+ rep_INTERN(position);
1419+ rep_INTERN(spacing);
1420+ rep_INTERN(head);
1421+
1422+ rep_mark_static (&message.text);
1423+ rep_mark_static (&message.fg);
1424+ rep_mark_static (&message.bg);
1425+ rep_mark_static (&message.font);
1426+ rep_mark_static (&message.justify);
1427+
1428+#ifdef HAVE_X11_EXTENSIONS_XINERAMA_H
1429+# ifndef TEST_XINERAMA
1430+ if (dpy != 0)
1431+ {
1432+ if (XineramaQueryExtension (dpy, &xinerama_event_base,
1433+ &xinerama_error_base))
1434+ {
1435+ xinerama_head_info = XineramaQueryScreens (dpy, &xinerama_heads);
1436+ }
1437+ }
1438+# else
1439+ xinerama_head_info = debug_heads;
1440+ xinerama_heads = debug_nheads;
1441+# endif
1442+#endif
1443+}
1444+
1445+void
1446+functions_kill (void)
1447+{
1448+ if (message_win != 0)
1449+ XDestroyWindow (dpy, message_win);
1450+}
--- /dev/null
+++ b/src/windows.c
@@ -0,0 +1,1631 @@
1+/* windows.c -- window manipulation
2+ $Id$
3+
4+ Copyright (C) 1999 John Harper <john@dcs.warwick.ac.uk>
5+
6+ This file is part of sawmill.
7+
8+ sawmill is free software; you can redistribute it and/or modify it
9+ under the terms of the GNU General Public License as published by
10+ the Free Software Foundation; either version 2, or (at your option)
11+ any later version.
12+
13+ sawmill is distributed in the hope that it will be useful, but
14+ WITHOUT ANY WARRANTY; without even the implied warranty of
15+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+ GNU General Public License for more details.
17+
18+ You should have received a copy of the GNU General Public License
19+ along with sawmill; see the file COPYING. If not, write to
20+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21+
22+#include "sawmill.h"
23+#include <assert.h>
24+#include <X11/extensions/shape.h>
25+
26+Lisp_Window *window_list;
27+int window_type;
28+
29+Lisp_Window *focus_window, *pending_focus_window;
30+
31+int pending_destroys;
32+
33+static bool initialising;
34+
35+DEFSYM(add_window_hook, "add-window-hook");
36+DEFSYM(before_add_window_hook, "before-add-window-hook");
37+DEFSYM(after_add_window_hook, "after-add-window-hook");
38+DEFSYM(place_window_hook, "place-window-hook");
39+DEFSYM(placed, "placed");
40+DEFSYM(after_framing_hook, "after-framing-hook");
41+DEFSYM(after_initialization_hook, "after-initialization-hook");
42+DEFSYM(remove_window_hook, "remove-window-hook");
43+
44+/* for visibility-notify-hook */
45+DEFSYM(fully_obscured, "fully-obscured");
46+DEFSYM(partially_obscured, "partially-obscured");
47+DEFSYM(unobscured, "unobscured");
48+
49+/* for window-size-hints */
50+DEFSYM(min_width, "min-width");
51+DEFSYM(min_height, "min-height");
52+DEFSYM(max_width, "max-width");
53+DEFSYM(max_height, "max-height");
54+DEFSYM(width_inc, "width-inc");
55+DEFSYM(height_inc, "height-inc");
56+DEFSYM(base_width, "base-width");
57+DEFSYM(base_height, "base-height");
58+DEFSYM(min_aspect, "min-aspect");
59+DEFSYM(max_aspect, "max-aspect");
60+DEFSYM(user_size, "user-size");
61+DEFSYM(program_size, "program-size");
62+DEFSYM(user_position, "user-position");
63+DEFSYM(program_position, "program-position");
64+DEFSYM(window_gravity, "window-gravity");
65+
66+/* for window-gravity */
67+DEFSYM(forget, "forget");
68+DEFSYM(static, "static");
69+DEFSYM(north_west, "north-west");
70+DEFSYM(north, "north");
71+DEFSYM(north_east, "north-east");
72+DEFSYM(west, "west");
73+DEFSYM(center, "center");
74+DEFSYM(east, "east");
75+DEFSYM(south_west, "south-west");
76+DEFSYM(south, "south");
77+DEFSYM(south_east, "south-east");
78+
79+static repv gravity_map[StaticGravity+1];
80+
81+struct prop_handler {
82+ struct prop_handler *next;
83+ repv prop;
84+ void (*callback) (Lisp_Window *w, repv prop, repv old, repv new);
85+};
86+
87+static struct prop_handler *prop_handlers;
88+
89+
90+/* utilities */
91+
92+/* Returns true if we should manage window ID */
93+bool
94+mapped_not_override_p (Window id)
95+{
96+ XWindowAttributes wa;
97+
98+ XGetWindowAttributes(dpy, id, &wa);
99+ return ((wa.map_state != IsUnmapped) && (wa.override_redirect != True));
100+}
101+
102+/* Returns true if the window's Input hint is set (or defaults to being set) */
103+static bool
104+window_input_hint_p (Lisp_Window *w)
105+{
106+ if (w->wmhints != 0 && (w->wmhints->flags & InputHint))
107+ return w->wmhints->input;
108+ else
109+ return TRUE;
110+}
111+
112+static Window queued_focus_id;
113+static int queued_focus_revert;
114+static Time queued_focus_time;
115+
116+void
117+commit_queued_focus_change (void)
118+{
119+ if (queued_focus_id != 0)
120+ {
121+ XSetInputFocus (dpy, queued_focus_id,
122+ queued_focus_revert, queued_focus_time);
123+ queued_focus_id = 0;
124+ }
125+}
126+
127+/* Give the input focus to window W, or to no window if W is null */
128+void
129+focus_on_window (Lisp_Window *w)
130+{
131+ if (w != 0 && !WINDOW_IS_GONE_P (w) && w->visible)
132+ {
133+ Window focus;
134+ DB(("focus_on_window (%s)\n", rep_STR(w->name)));
135+ if (!w->client_unmapped)
136+ {
137+ if (w->does_wm_take_focus)
138+ {
139+ DB((" sending WM_TAKE_FOCUS message\n"));
140+
141+ /* The -1 is an Ugly Hack. The problem is with the case
142+ where the window focuses itself after receiving the
143+ WM_TAKE_FOCUS message. If during the time between us
144+ sending the client message and the window focusing
145+ itself we focused another window using the same
146+ timestamp, the original window (that received the
147+ client message) will still get focused.
148+
149+ I'm assuming that it's unlikely that two events will
150+ arrive generating focus changes with timestamps that
151+ only differ by one.. */
152+
153+ send_client_message (w->id, xa_wm_take_focus,
154+ last_event_time - 1);
155+ queued_focus_time = last_event_time - 1; /* evil */
156+
157+ /* Only focus on the window if accepts-input is true */
158+ if (window_input_hint_p (w))
159+ focus = w->id;
160+ else
161+ focus = 0;
162+ }
163+ else
164+ focus = w->id;
165+ }
166+ else
167+ focus = w->frame;
168+ if (focus != 0)
169+ {
170+ queued_focus_id = focus;
171+ queued_focus_revert = RevertToParent;
172+ queued_focus_time = last_event_time;
173+ pending_focus_window = w;
174+ }
175+ }
176+ else
177+ {
178+ DB(("focus_on_window (nil)\n"));
179+ queued_focus_id = no_focus_window;
180+ queued_focus_revert = RevertToNone;
181+ queued_focus_time = last_event_time;
182+ pending_focus_window = 0;
183+ }
184+}
185+
186+/* Should be called when W is no longer focusable. */
187+void
188+focus_off_window (Lisp_Window *w)
189+{
190+ if (focus_window == w)
191+ {
192+ focus_window = 0;
193+ if (pending_focus_window == 0 || pending_focus_window == w)
194+ focus_on_window (0);
195+ }
196+ if (pending_focus_window == w)
197+ pending_focus_window = 0;
198+}
199+
200+/* Set flags in W relating to which window manager protocols are recognised
201+ by window W. */
202+void
203+get_window_protocols (Lisp_Window *w)
204+{
205+ Atom *prot;
206+ u_int n;
207+ w->does_wm_take_focus = 0;
208+ w->does_wm_delete_window = 0;
209+ if (XGetWMProtocols (dpy, w->id, &prot, &n) != 0)
210+ {
211+ int i;
212+ for (i = 0; i < n; i++)
213+ {
214+ if (prot[i] == xa_wm_take_focus)
215+ {
216+ w->does_wm_take_focus = 1;
217+ DB((" WM_TAKE_FOCUS is set\n"));
218+ }
219+ if (prot[i] == xa_wm_delete_window)
220+ {
221+ w->does_wm_delete_window = 1;
222+ DB((" WM_DELETE_WINDOW is set\n"));
223+ }
224+ }
225+ XFree (prot);
226+ }
227+}
228+
229+/* These two functions are used to bracket Xlib requests that would map,
230+ unmap, or reparent the client window. They ensure that any
231+ StructureNotifymask events generated between calling before_local_map ()
232+ and after_local_map () are discarded, but no others (so that we don't
233+ lose client-generated events) */
234+
235+void
236+before_local_map (Lisp_Window *w)
237+{
238+ Fgrab_server ();
239+ XSelectInput (dpy, w->id, CLIENT_EVENTS & ~StructureNotifyMask);
240+}
241+
242+void
243+after_local_map (Lisp_Window *w)
244+{
245+ XSelectInput (dpy, w->id, CLIENT_EVENTS);
246+ Fungrab_server ();
247+}
248+
249+
250+/* manipulating the Lisp window structures */
251+
252+/* Return the window object containing ID, or a null pointer */
253+Lisp_Window *
254+find_window_by_id (Window id)
255+{
256+ Lisp_Window *w;
257+ w = window_list;
258+ while (w != 0 && w->id != id && w->frame != id)
259+ w = w->next;
260+ if (w != 0 && WINDOW_IS_GONE_P (w))
261+ w = 0;
262+ if (w != 0)
263+ {
264+ DB(("find_window_by_id (%lx) --> %s\n", id,
265+ (w->name && rep_STRINGP(w->name))
266+ ? (char *) rep_STR(w->name) : ""));
267+ }
268+ return w;
269+}
270+
271+/* This is different to the above in that it could return a window
272+ that doesn't have a client window. */
273+Lisp_Window *
274+x_find_window_by_id (Window id)
275+{
276+ Lisp_Window *w;
277+ w = window_list;
278+ while (w != 0 && w->saved_id != id && w->frame != id)
279+ w = w->next;
280+ if (w != 0)
281+ {
282+ DB(("x_find_window_by_id (%lx) --> %s\n", id,
283+ (w->name && rep_STRINGP(w->name))
284+ ? (char *) rep_STR(w->name) : ""));
285+ }
286+ return w;
287+}
288+
289+void
290+install_window_frame (Lisp_Window *w)
291+{
292+ DB(("install_window_frame (%s)\n", rep_STR(w->name)));
293+ if (!w->reparented && w->frame != 0 && !WINDOW_IS_GONE_P (w))
294+ {
295+ XSelectInput (dpy, w->frame, FRAME_EVENTS);
296+
297+ before_local_map (w);
298+ XReparentWindow (dpy, w->id, w->frame, -w->frame_x, -w->frame_y);
299+ w->reparented = TRUE;
300+ after_local_map (w);
301+ restack_window (w);
302+
303+ XAddToSaveSet (dpy, w->id);
304+ restack_frame_parts (w);
305+ reset_frame_parts (w);
306+
307+ DB((" reparented to %lx [%dx%d%+d%+d]\n",
308+ w->frame, w->frame_width, w->frame_height,
309+ w->frame_x, w->frame_y));
310+ }
311+}
312+
313+void
314+remove_window_frame (Lisp_Window *w)
315+{
316+ DB(("remove_window_frame (%s)\n", rep_STR(w->name)));
317+ if (w->reparented && !WINDOW_IS_GONE_P (w))
318+ {
319+ /* reparent the subwindow back to the root window */
320+
321+ before_local_map (w);
322+ XReparentWindow (dpy, w->id, root_window, w->attr.x, w->attr.y);
323+ w->reparented = FALSE;
324+ after_local_map (w);
325+ restack_window (w);
326+
327+ if (!w->mapped)
328+ XRemoveFromSaveSet (dpy, w->id);
329+ }
330+}
331+
332+/* Add the top-level window ID to the manager's data structures */
333+Lisp_Window *
334+add_window (Window id)
335+{
336+ char *tem;
337+ Lisp_Window *w = rep_ALLOC_CELL(sizeof (Lisp_Window));
338+ if (w != 0)
339+ {
340+ rep_GC_root gc_win;
341+ repv win = rep_VAL(w);
342+ XWindowChanges xwc;
343+ u_int xwcm;
344+ long supplied;
345+ XTextProperty prop;
346+
347+ DB(("add_window (%lx)\n", id));
348+
349+ if (id == root_window)
350+ DB((" ** adding root window!?\n"));
351+
352+ rep_data_after_gc += sizeof (Lisp_Window);
353+ memset (w, 0, sizeof (Lisp_Window));
354+
355+ /* First initialise the Lisp stuff.. */
356+ w->next = window_list;
357+ window_list = w;
358+ w->car = window_type;
359+ w->id = id;
360+ w->saved_id = id;
361+ w->plist = Qnil;
362+ w->frame_style = Qnil;;
363+ w->icon_image = rep_NULL;
364+
365+ /* have to put it somewhere until it finds the right place */
366+ insert_in_stacking_list_above_all (w);
367+ restack_window (w);
368+
369+ /* ..now do the X11 stuff */
370+
371+ XSelectInput (dpy, id, CLIENT_EVENTS);
372+ XGetWindowAttributes (dpy, id, &w->attr);
373+ DB((" orig: width=%d height=%d x=%d y=%d\n",
374+ w->attr.width, w->attr.height, w->attr.x, w->attr.y));
375+
376+ if (XGetWMName (dpy, id, &prop) && prop.value)
377+ {
378+ if (prop.nitems > 0)
379+ {
380+ char **list;
381+ int count;
382+ prop.nitems = strlen(prop.value);
383+ if (XmbTextPropertyToTextList (dpy, &prop, &list, &count)
384+ >= Success)
385+ {
386+ if (count > 0)
387+ w->name = rep_string_dup (list[0]);
388+ XFreeStringList (list);
389+ }
390+ }
391+ XFree (prop.value);
392+ }
393+ if (w->name == 0)
394+ w->name = rep_null_string ();
395+ w->full_name = w->name;
396+ if (XGetIconName (dpy, id, &tem))
397+ {
398+ w->icon_name = rep_string_dup (tem);
399+ XFree (tem);
400+ }
401+ else
402+ w->icon_name = w->name;
403+
404+ w->wmhints = XGetWMHints (dpy, id);
405+ if (!XGetWMNormalHints (dpy, w->id, &w->hints, &supplied))
406+ w->hints.flags = 0;
407+ get_window_protocols (w);
408+ if (!XGetTransientForHint (dpy, w->id, &w->transient_for_hint))
409+ w->transient_for_hint = 0;
410+ if (!XGetWMColormapWindows (dpy, w->id,
411+ &w->cmap_windows, &w->n_cmap_windows))
412+ {
413+ w->n_cmap_windows = 0;
414+ }
415+
416+ {
417+ /* Is the window shaped? */
418+ int xws, yws, xbs, ybs;
419+ u_int wws, hws, wbs, hbs;
420+ int bounding, clip;
421+ XShapeSelectInput (dpy, w->id, ShapeNotifyMask);
422+ XShapeQueryExtents (dpy, w->id, &bounding, &xws, &yws, &wws, &hws,
423+ &clip, &xbs, &ybs, &wbs, &hbs);
424+ w->shaped = bounding ? 1 : 0;
425+ }
426+
427+ DB((" name=`%s' x=%d y=%d width=%d height=%d\n",
428+ rep_STR(w->name), w->attr.x, w->attr.y,
429+ w->attr.width, w->attr.height));
430+
431+ xwcm = CWX | CWX | CWWidth | CWHeight | CWBorderWidth;
432+ xwc.x = w->attr.x;
433+ xwc.y = w->attr.y;
434+ xwc.width = w->attr.width;
435+ xwc.height = w->attr.height;
436+ xwc.border_width = 0;
437+ XConfigureWindow (dpy, id, xwcm, &xwc);
438+
439+ w->visible = TRUE;
440+ w->mapped = TRUE; /* only called from map request */
441+
442+ if (initialising)
443+ Fwindow_put (rep_VAL (w), Qplaced, Qt);
444+
445+ /* ..then call the add-window-hook's.. */
446+ rep_PUSHGC(gc_win, win);
447+ Fcall_window_hook (Qbefore_add_window_hook, rep_VAL(w), Qnil, Qnil);
448+ Fcall_window_hook (Qadd_window_hook, rep_VAL(w), Qnil, Qnil);
449+ rep_POPGC;
450+
451+ /* In case the window disappeared during the hook call */
452+ if (!WINDOW_IS_GONE_P (w))
453+ {
454+ Fgrab_server ();
455+
456+ /* this is where we create and reparent the window frame */
457+ create_window_frame (w);
458+ install_window_frame (w);
459+
460+ /* this grabs bound events in the subwindow */
461+ grab_window_events (w, TRUE);
462+
463+ Fungrab_server ();
464+ }
465+ else
466+ emit_pending_destroys ();
467+
468+ if (!WINDOW_IS_GONE_P (w))
469+ {
470+ repv tem = Fwindow_get (rep_VAL(w), Qplaced);
471+ if (initialising || (tem && tem == Qnil))
472+ {
473+ /* ..then the place-window-hook.. */
474+ rep_PUSHGC(gc_win, win);
475+ Fcall_window_hook (Qplace_window_hook, rep_VAL(w), Qnil, Qor);
476+ rep_POPGC;
477+ }
478+ }
479+ Fwindow_put (rep_VAL(w), Qplaced, Qt);
480+
481+ if (!WINDOW_IS_GONE_P (w))
482+ Fcall_window_hook (Qafter_add_window_hook, rep_VAL(w), Qnil, Qnil);
483+
484+ if (!WINDOW_IS_GONE_P (w))
485+ {
486+ /* Tell the window where it ended up.. */
487+ send_synthetic_configure (w);
488+ }
489+ }
490+ return w;
491+}
492+
493+/* Remove W from the managed windows. If DESTROYED is nil, then the
494+ window will be reparented back to the root window */
495+void
496+remove_window (Lisp_Window *w, repv destroyed, repv from_error)
497+{
498+ DB(("remove_window (%s, %s)\n",
499+ rep_STR(w->name), destroyed == Qnil ? "nil" : "t"));
500+
501+ if (w->id != 0)
502+ {
503+ if (destroyed == Qnil && from_error == Qnil)
504+ {
505+ grab_window_events (w, FALSE);
506+ remove_window_frame (w);
507+
508+ /* Restore original border width of the client */
509+ XSetWindowBorderWidth (dpy, w->id, w->attr.border_width);
510+ }
511+
512+ if (from_error == Qnil)
513+ destroy_window_frame (w, FALSE);
514+
515+ if (!WINDOW_IS_GONE_P (w))
516+ remove_from_stacking_list (w);
517+
518+ w->id = 0;
519+ pending_destroys++;
520+
521+ /* gc will do the rest... */
522+ }
523+ else if (w->frame != 0 && from_error == Qnil)
524+ destroy_window_frame (w, FALSE);
525+
526+ /* We can lose the focus sometimes, notably after a was-focused
527+ window is closed while a keyboard grab exists.. (netscape) */
528+ if (from_error == Qnil)
529+ {
530+ Window focus;
531+ int revert_to;
532+ XGetInputFocus (dpy, &focus, &revert_to);
533+ if (focus == None || focus == PointerRoot)
534+ {
535+ DB (("lost focus (%ld)\n", focus));
536+ focus_on_window (pending_focus_window
537+ ? pending_focus_window : focus_window);
538+ }
539+ }
540+}
541+
542+void
543+fix_window_size (Lisp_Window *w)
544+{
545+ Fgrab_server ();
546+ if (w->frame != 0 && w->rebuild_frame != 0)
547+ w->rebuild_frame (w);
548+ else
549+ XResizeWindow (dpy, w->id, w->attr.width, w->attr.height);
550+ Fungrab_server ();
551+}
552+
553+/* Call destroy-notify-hook on any newly-dead windows */
554+void
555+emit_pending_destroys (void)
556+{
557+ if (pending_destroys > 0)
558+ {
559+ Lisp_Window *w;
560+ again:
561+ for (w = window_list; w != 0 && !rep_INTERRUPTP; w = w->next)
562+ {
563+ if (WINDOW_IS_GONE_P (w) && !w->destroyed)
564+ {
565+ w->destroyed = 1;
566+ Fcall_window_hook (Qdestroy_notify_hook,
567+ rep_VAL(w), Qnil, Qnil);
568+
569+ focus_off_window (w);
570+
571+ /* gc may have reordered the list, so we have to start
572+ at the beginning again.. */
573+ goto again;
574+ }
575+ }
576+ }
577+ pending_destroys = 0;
578+}
579+
580+
581+/* Lisp functions */
582+
583+DEFUN("window-get", Fwindow_get, Swindow_get,
584+ (repv win, repv prop), rep_Subr2) /*
585+::doc:sawfish.wm.windows.subrs#window-get::
586+window-get WINDOW PROPERTY
587+
588+Return the value of the property named PROPERTY (a symbol) of WINDOW.
589+
590+Note that these are Lisp properties not X properties.
591+::end:: */
592+{
593+ repv plist;
594+ rep_DECLARE1(win, XWINDOWP);
595+ plist = VWIN(win)->plist;
596+ while (rep_CONSP(plist) && rep_CONSP(rep_CDR(plist)))
597+ {
598+ if (rep_CAR(plist) == prop
599+ || (!rep_SYMBOLP(prop)
600+ && rep_value_cmp (rep_CAR(plist), prop) == 0))
601+ {
602+ return rep_CAR(rep_CDR(plist));
603+ }
604+ plist = rep_CDR(rep_CDR(plist));
605+ }
606+ return Qnil;
607+}
608+
609+DEFUN("map-window-properties", Fmap_window_properties,
610+ Smap_window_properties, (repv fun, repv win), rep_Subr2) /*
611+::doc:sawfish.wm.windows.subrs#map-window-properties::
612+map-window-properties FUNCTION WINDOW
613+
614+Call (FUNCTION PROPERTY VALUE) for all Lisp properties set on window
615+object WINDOW.
616+::end:: */
617+{
618+ repv ret = Qnil, plist;
619+ rep_GC_root gc_plist, gc_fun;
620+ rep_DECLARE2 (win, XWINDOWP);
621+ plist = VWIN(win)->plist;
622+ rep_PUSHGC (gc_plist, plist);
623+ rep_PUSHGC (gc_fun, fun);
624+ while (rep_CONSP(plist) && rep_CONSP(rep_CDR(plist)))
625+ {
626+ ret = rep_call_lisp2 (fun, rep_CAR (plist), rep_CADR (plist));
627+ if (ret == rep_NULL)
628+ break;
629+ plist = rep_CDDR (plist);
630+ }
631+ rep_POPGC; rep_POPGC;
632+ return ret;
633+}
634+
635+void
636+register_property_monitor (repv prop,
637+ void (*callback) (Lisp_Window *, repv, repv, repv))
638+{
639+ struct prop_handler *ph = rep_alloc (sizeof (struct prop_handler));
640+ ph->next = prop_handlers;
641+ prop_handlers = ph;
642+ ph->prop = prop;
643+ ph->callback = callback;
644+}
645+
646+DEFUN("window-put", Fwindow_put, Swindow_put,
647+ (repv win, repv prop, repv val), rep_Subr3) /*
648+::doc:sawfish.wm.windows.subrs#window-put::
649+window-put WINDOW PROPERTY VALUE
650+
651+Set the value of the property named PROPERTY (a symbol) of WINDOW to VALUE.
652+
653+Note that these are Lisp properties not X properties.
654+::end:: */
655+{
656+ repv plist;
657+ rep_DECLARE1(win, XWINDOWP);
658+ plist = VWIN(win)->plist;
659+ while (rep_CONSP(plist) && rep_CONSP(rep_CDR(plist)))
660+ {
661+ if (rep_CAR(plist) == prop
662+ || (!rep_SYMBOLP(prop)
663+ && rep_value_cmp (rep_CAR(plist), prop) == 0))
664+ {
665+ struct prop_handler *ph;
666+ for (ph = prop_handlers; ph != 0; ph = ph->next)
667+ {
668+ repv old = rep_CADR (plist);
669+ if (ph->prop == prop && old != val)
670+ ph->callback (VWIN (win), prop, old, val);
671+ }
672+ rep_CAR(rep_CDR(plist)) = val;
673+ return val;
674+ }
675+ plist = rep_CDR(rep_CDR(plist));
676+ }
677+ plist = Fcons(prop, Fcons(val, VWIN(win)->plist));
678+ if (plist != rep_NULL)
679+ VWIN(win)->plist = plist;
680+ return val;
681+}
682+
683+DEFUN("window-name", Fwindow_name, Swindow_name, (repv win), rep_Subr1) /*
684+::doc:sawfish.wm.windows.subrs#window-name::
685+window-name WINDOW
686+
687+Return the name of window object WINDOW.
688+::end:: */
689+{
690+ rep_DECLARE1(win, WINDOWP);
691+ return VWIN(win)->name;
692+}
693+
694+DEFUN("window-full-name", Fwindow_full_name, Swindow_full_name,
695+ (repv win), rep_Subr1) /*
696+::doc:sawfish.wm.windows.subrs#window-full-name::
697+window-full-name WINDOW
698+
699+Return the full name of window object WINDOW.
700+::end:: */
701+{
702+ rep_DECLARE1(win, WINDOWP);
703+ return VWIN(win)->full_name;
704+}
705+
706+DEFUN("window-icon-name", Fwindow_icon_name, Swindow_icon_name,
707+ (repv win), rep_Subr1) /*
708+::doc:sawfish.wm.windows.subrs#window-icon-name::
709+window-icon-name WINDOW
710+
711+Return the name of window object WINDOW's icon.
712+::end:: */
713+{
714+ rep_DECLARE1(win, WINDOWP);
715+ return VWIN(win)->icon_name;
716+}
717+
718+DEFUN("window-mapped-p", Fwindow_mapped_p, Swindow_mapped_p,
719+ (repv win), rep_Subr1) /*
720+::doc:sawfish.wm.windows.subrs#window-mapped-p::
721+window-mapped-p WINDOW
722+
723+Return t if the client window associated with object WINDOW is mapped.
724+(This doesn't necessarily mean that it is visible.)
725+::end:: */
726+{
727+ rep_DECLARE1(win, WINDOWP);
728+ return VWIN(win)->mapped ? Qt : Qnil;
729+}
730+
731+DEFUN("window-frame", Fwindow_frame, Swindow_frame, (repv win), rep_Subr1) /*
732+::doc:sawfish.wm.windows.subrs#window-frame::
733+window-frame WINDOW
734+
735+Return the frame object associated with WINDOW.
736+::end:: */
737+{
738+ rep_DECLARE1(win, WINDOWP);
739+ return VWIN(win)->frame_style;
740+}
741+
742+DEFUN("set-window-frame", Fset_window_frame, Sset_window_frame,
743+ (repv win, repv frame), rep_Subr2) /*
744+::doc:sawfish.wm.windows.subrs#set-window-frame::
745+set-window-frame WINDOW FRAME
746+
747+Set the frame associated with the window object WINDOW to FRAME (a
748+list). If the window is mapped the old frame will be destroyed and a
749+new frame constructed as specified by FRAME.
750+::end:: */
751+{
752+ rep_DECLARE1(win, WINDOWP);
753+ rep_DECLARE2(frame, rep_LISTP);
754+ Fgrab_server ();
755+
756+ if (VWIN(win)->reparented)
757+ destroy_window_frame (VWIN(win), TRUE);
758+
759+ VWIN(win)->frame_style = frame;
760+
761+ if (VWIN(win)->reparented)
762+ create_window_frame (VWIN(win));
763+
764+ Fungrab_server ();
765+ Fcall_window_hook (Qafter_framing_hook, win, Qnil, Qnil);
766+ return VWIN(win)->frame_style;
767+}
768+
769+DEFUN("rebuild-frame", Frebuild_frame, Srebuild_frame, (repv win), rep_Subr1) /*
770+::doc:sawfish.wm.windows.subrs#rebuild-frame::
771+rebuild-frame WINDOW
772+
773+Reinitialises and recalibrates the window frame of WINDOW.
774+::end:: */
775+{
776+ rep_DECLARE1(win, WINDOWP);
777+ if (VWIN(win)->frame != 0 && VWIN(win)->rebuild_frame != 0)
778+ {
779+ VWIN(win)->rebuild_frame (VWIN(win));
780+ refresh_frame_parts (VWIN(win));
781+ Fcall_window_hook (Qafter_framing_hook, win, Qnil, Qnil);
782+ }
783+ return win;
784+}
785+
786+DEFUN("window-position", Fwindow_position, Swindow_position,
787+ (repv win), rep_Subr1) /*
788+::doc:sawfish.wm.windows.subrs#window-position::
789+window-position WINDOW
790+
791+Return (X . Y) defining the current position of WINDOW.
792+::end:: */
793+{
794+ rep_DECLARE1(win, WINDOWP);
795+ return Fcons (rep_MAKE_INT(VWIN(win)->attr.x),
796+ rep_MAKE_INT(VWIN(win)->attr.y));
797+}
798+
799+DEFUN("window-dimensions", Fwindow_dimensions, Swindow_dimensions,
800+ (repv win), rep_Subr1) /*
801+::doc:sawfish.wm.windows.subrs#window-dimensions::
802+window-dimensions WINDOW
803+
804+Return (WIDTH . HEIGHT) defining the current dimensions of the client
805+window associated with WINDOW.
806+::end:: */
807+{
808+ rep_DECLARE1(win, WINDOWP);
809+ return Fcons (rep_MAKE_INT(VWIN(win)->attr.width),
810+ rep_MAKE_INT(VWIN(win)->attr.height));
811+}
812+
813+DEFUN("window-frame-dimensions", Fwindow_frame_dimensions,
814+ Swindow_frame_dimensions, (repv win), rep_Subr1) /*
815+::doc:sawfish.wm.windows.subrs#window-frame-dimensions::
816+window-frame-dimensions WINDOW
817+
818+Return (WIDTH . HEIGHT) defining the current dimensions of the frame
819+surrounding WINDOW.
820+::end:: */
821+{
822+ rep_DECLARE1(win, WINDOWP);
823+ if (VWIN(win)->reparented)
824+ {
825+ return Fcons (rep_MAKE_INT(VWIN(win)->frame_width),
826+ rep_MAKE_INT(VWIN(win)->frame_height));
827+ }
828+ else
829+ return Fwindow_dimensions (win);
830+}
831+
832+DEFUN("window-frame-offset", Fwindow_frame_offset,
833+ Swindow_frame_offset, (repv win), rep_Subr1) /*
834+::doc:sawfish.wm.windows.subrs#window-frame-offset::
835+window-frame-offset WINDOW
836+
837+Return (X . Y) defining the offset from the origin of the client window
838+associated with WINDOW to its frame window.
839+::end:: */
840+{
841+ rep_DECLARE1(win, WINDOWP);
842+ return Fcons (rep_MAKE_INT(VWIN(win)->frame_x),
843+ rep_MAKE_INT(VWIN(win)->frame_y));
844+}
845+
846+DEFUN("windowp", Fwindowp, Swindowp, (repv win), rep_Subr1) /*
847+::doc:sawfish.wm.windows.subrs#windowp::
848+windowp ARG
849+
850+Return t if ARG is a window object.
851+::end:: */
852+{
853+ return WINDOWP(win) ? Qt : Qnil;
854+}
855+
856+DEFUN("set-input-focus", Fset_input_focus, Sset_input_focus,
857+ (repv win), rep_Subr1) /*
858+::doc:sawfish.wm.windows.subrs#set-input-focus::
859+set-input-focus WINDOW
860+
861+Set the input focus to WINDOW. If WINDOW is nil, then no window will
862+have the focus.
863+::end:: */
864+{
865+ if (win != Qnil && win != Qroot)
866+ {
867+ rep_DECLARE1(win, WINDOWP);
868+ focus_on_window (VWIN(win));
869+ }
870+ else
871+ focus_on_window (0);
872+ return win;
873+}
874+
875+DEFUN("input-focus", Finput_focus, Sinput_focus, (void), rep_Subr0) /*
876+::doc:sawfish.wm.windows.subrs#input-focus::
877+input-focus
878+
879+Return the window object that has the input focus, or nil if none does.
880+::end:: */
881+{
882+ return (focus_window == 0) ? Qnil : rep_VAL(focus_window);
883+}
884+
885+DEFUN("window-wants-input-p", Fwindow_wants_input_p, Swindow_wants_input_p,
886+ (repv win), rep_Subr1) /*
887+::doc:sawfish.wm.windows.subrs#window-wants-input-p::
888+window-wants-input-p WINDOW
889+
890+Return t if the client window associated with object WINDOW has hinted
891+that it would like to be given the input focus when applicable.
892+::end:: */
893+{
894+ rep_DECLARE1(win, WINDOWP);
895+ if (VWIN(win)->does_wm_take_focus)
896+ return Qt;
897+ else
898+ return window_input_hint_p (VWIN (win)) ? Qt : Qnil;
899+}
900+
901+DEFUN("managed-windows", Fmanaged_windows, Smanaged_windows,
902+ (void), rep_Subr0) /*
903+::doc:sawfish.wm.windows.subrs#managed-windows::
904+managed-windows
905+
906+Return a list of all known client window objects.
907+::end:: */
908+{
909+ repv list = Qnil;
910+ Lisp_Window *w = window_list;
911+ while (w != 0)
912+ {
913+ if (!WINDOW_IS_GONE_P (w))
914+ list = Fcons (rep_VAL(w), list);
915+ w = w->next;
916+ }
917+ return list;
918+}
919+
920+DEFUN("get-window-by-id", Fget_window_by_id, Sget_window_by_id,
921+ (repv id), rep_Subr1) /*
922+::doc:sawfish.wm.windows.subrs#get-window-by-id::
923+get-window-by-id ID
924+
925+Return the window object associated with xid ID, or nil.
926+::end:: */
927+{
928+ Lisp_Window *w;
929+ rep_DECLARE1(id, rep_INTEGERP);
930+ w = find_window_by_id (rep_get_long_uint (id));
931+ return w ? rep_VAL(w) : Qnil;
932+}
933+
934+DEFUN("stacking-order", Fstacking_order, Sstacking_order, (void), rep_Subr0) /*
935+::doc:sawfish.wm.windows.subrs#stacking-order::
936+stacking-order
937+
938+Return a list of windows defining the current stacking order of all
939+client windows.
940+::end:: */
941+{
942+ return make_stacking_list ();
943+}
944+
945+DEFUN("window-visibility", Fwindow_visibility, Swindow_visibility,
946+ (repv win), rep_Subr1) /*
947+::doc:sawfish.wm.windows.subrs#window-visibility::
948+window-visibility WINDOW
949+
950+Return a symbol defining the visibility of WINDOW. Possible returned
951+symbols are `fully-obscured', `partially-obscured' or `unobscured'.
952+::end:: */
953+{
954+ repv sym = Qnil;
955+ rep_DECLARE1(win, WINDOWP);
956+ switch (VWIN(win)->frame_vis)
957+ {
958+ case VisibilityFullyObscured:
959+ sym = Qfully_obscured;
960+ break;
961+
962+ case VisibilityPartiallyObscured:
963+ sym = Qpartially_obscured;
964+ break;
965+
966+ case VisibilityUnobscured:
967+ sym = Qunobscured;
968+ break;
969+ }
970+ return sym;
971+}
972+
973+DEFUN("window-transient-p", Fwindow_transient_p, Swindow_transient_p,
974+ (repv win), rep_Subr1) /*
975+::doc:sawfish.wm.windows.subrs#window-transient-p::
976+window-transient-p WINDOW
977+
978+Return non-nil if WINDOW is a transient window. The returned value will
979+then be the numeric id of its parent window.
980+::end:: */
981+{
982+ rep_DECLARE1(win, WINDOWP);
983+ return (VWIN(win)->transient_for_hint
984+ ? rep_MAKE_INT(VWIN(win)->transient_for_hint) : Qnil);
985+}
986+
987+DEFUN("window-urgent-p", Fwindow_urgent_p, Swindow_urgent_p,
988+ (repv win), rep_Subr1) /*
989+::doc:sawfish.wm.windows.subrs#window-urgent-p::
990+window-urgent-p WINDOW
991+
992+Return true if the `Urgency' hint of the window associated with WINDOW
993+is set.
994+::end:: */
995+{
996+ rep_DECLARE1 (win, WINDOWP);
997+ return ((VWIN (win)->wmhints
998+ && VWIN (win)->wmhints->flags & XUrgencyHint) ? Qt : Qnil);
999+}
1000+
1001+DEFUN("window-shaped-p", Fwindow_shaped_p, Swindow_shaped_p,
1002+ (repv win), rep_Subr1) /*
1003+::doc:sawfish.wm.windows.subrs#window-shaped-p::
1004+window-shaped-p WINDOW
1005+
1006+Return non-nil if WINDOW is shaped.
1007+::end:: */
1008+{
1009+ rep_DECLARE1(win, WINDOWP);
1010+ return VWIN(win)->shaped ? Qt : Qnil;
1011+}
1012+
1013+DEFUN("hide-window", Fhide_window, Shide_window, (repv win), rep_Subr1) /*
1014+::doc:sawfish.wm.windows.subrs#hide-window::
1015+hide-window WINDOW
1016+
1017+Prevent WINDOW from being displayed. See `show-window'.
1018+::end:: */
1019+{
1020+ rep_DECLARE1(win, WINDOWP);
1021+ if (VWIN(win)->visible)
1022+ {
1023+ if (VWIN(win)->mapped)
1024+ {
1025+ if (VWIN(win)->frame)
1026+ XUnmapWindow (dpy, VWIN(win)->frame);
1027+ if (!VWIN(win)->client_unmapped)
1028+ {
1029+ before_local_map (VWIN(win));
1030+ XUnmapWindow (dpy, VWIN(win)->id);
1031+ VWIN(win)->client_unmapped = 1;
1032+ after_local_map (VWIN(win));
1033+ }
1034+ }
1035+ VWIN(win)->visible = 0;
1036+ reset_frame_parts (VWIN(win));
1037+ }
1038+ return win;
1039+}
1040+
1041+DEFUN("show-window", Fshow_window, Sshow_window, (repv win), rep_Subr1) /*
1042+::doc:sawfish.wm.windows.subrs#show-window::
1043+show-window WINDOW
1044+
1045+Ensure that WINDOW (if it has been mapped) is visible. See `hide-window'.
1046+::end:: */
1047+{
1048+ rep_DECLARE1(win, WINDOWP);
1049+ if (!VWIN(win)->visible)
1050+ {
1051+ if (VWIN(win)->mapped)
1052+ {
1053+ if (VWIN(win)->client_unmapped && !VWIN(win)->client_hidden)
1054+ {
1055+ before_local_map (VWIN(win));
1056+ XMapWindow (dpy, VWIN(win)->id);
1057+ VWIN(win)->client_unmapped = 0;
1058+ after_local_map (VWIN(win));
1059+ }
1060+ if (VWIN(win)->frame)
1061+ XMapWindow (dpy, VWIN(win)->frame);
1062+ }
1063+ VWIN(win)->visible = 1;
1064+ }
1065+ return win;
1066+}
1067+
1068+DEFUN("window-visible-p", Fwindow_visible_p, Swindow_visible_p,
1069+ (repv win), rep_Subr1) /*
1070+::doc:sawfish.wm.windows.subrs#window-visible-p::
1071+window-visible-p WINDOW
1072+
1073+Return t if WINDOW is currently visible (i.e. not hidden, see `hide-window').
1074+::end:: */
1075+{
1076+ rep_DECLARE1(win, WINDOWP);
1077+ return VWIN(win)->visible ? Qt : Qnil;
1078+}
1079+
1080+DEFUN("window-framed-p", Fwindow_framed_p, Swindow_framed_p,
1081+ (repv win), rep_Subr1) /*
1082+::doc:sawfish.wm.windows.subrs#window-framed-p::
1083+window-framed-p WINDOW
1084+
1085+Return t if WINDOW has been reparented to a frame window.
1086+::end:: */
1087+{
1088+ rep_DECLARE1(win, WINDOWP);
1089+ return VWIN(win)->reparented ? Qt : Qnil;
1090+}
1091+
1092+DEFUN("window-id", Fwindow_id, Swindow_id, (repv win), rep_Subr1) /*
1093+::doc:sawfish.wm.windows.subrs#window-id::
1094+window-id WINDOW
1095+
1096+Return the numeric id of the client window associated with object
1097+WINDOW. Returns nil if the client window has been deleted.
1098+::end:: */
1099+{
1100+ rep_DECLARE1(win, WINDOWP);
1101+ return VWIN(win)->id ? rep_MAKE_INT (VWIN(win)->id) : Qnil;
1102+}
1103+
1104+DEFUN("window-group-id", Fwindow_group_id, Swindow_group_id,
1105+ (repv win), rep_Subr1) /*
1106+::doc:sawfish.wm.windows.subrs#window-group-id::
1107+window-group-id WINDOW
1108+
1109+Return the numeric id defining the leader of the group that WINDOW is a
1110+member of, or nil if it is not a member of a group.
1111+::end:: */
1112+{
1113+ rep_DECLARE1(win, WINDOWP);
1114+ if (VWIN(win)->wmhints == 0)
1115+ return Qnil;
1116+ return ((VWIN(win)->wmhints->flags & WindowGroupHint)
1117+ ? rep_MAKE_INT (VWIN(win)->wmhints->window_group)
1118+ : Qnil);
1119+}
1120+
1121+DEFUN("window-border-width", Fwindow_border_width, Swindow_border_width,
1122+ (repv win), rep_Subr1) /*
1123+::doc:sawfish.wm.windows.subrs#window-border-width::
1124+window-border-width WINDOW
1125+::end:: */
1126+{
1127+ rep_DECLARE1(win, WINDOWP);
1128+ return rep_MAKE_INT(VWIN(win)->attr.border_width);
1129+}
1130+
1131+DEFUN("window-size-hints", Fwindow_size_hints, Swindow_size_hints,
1132+ (repv win), rep_Subr1) /*
1133+::doc:sawfish.wm.windows.subrs#window-size-hints::
1134+window-size-hints WINDOW
1135+
1136+Return an alist defining the size-hints specified by the client window
1137+associated with WINDOW. Possible keys in the alist are `min-height',
1138+`max-height', `min-width', `max-width', `height-inc', `width-inc',
1139+`min-aspect', `max-aspect', `base-height', `base-width',
1140+`user-position', `program-position', `user-size', `program-size',
1141+`window-gravity', `border-size'.
1142+::end:: */
1143+{
1144+ repv ret = Qnil;
1145+ XSizeHints *hints;
1146+ long flags;
1147+ rep_DECLARE1(win, WINDOWP);
1148+
1149+ hints = &VWIN(win)->hints;
1150+ flags = hints->flags;
1151+
1152+ /* Some sanity checking */
1153+ if ((flags & PMinSize)
1154+ && (hints->min_width <= 0 || hints->min_height <= 0))
1155+ flags &= ~PMinSize;
1156+ if ((flags & PMaxSize)
1157+ && (hints->max_width <= 0 || hints->max_height <= 0))
1158+ flags &= ~PMaxSize;
1159+ if ((flags & PResizeInc)
1160+ && (hints->width_inc <= 0 || hints->width_inc <= 0))
1161+ flags &= ~PResizeInc;
1162+ if ((flags & PBaseSize)
1163+ && (hints->base_width <= 0 || hints->base_height <= 0))
1164+ flags &= ~PBaseSize;
1165+
1166+ if (flags & PMinSize)
1167+ {
1168+ ret = Fcons (Fcons (Qmin_width, rep_MAKE_INT(hints->min_width)),
1169+ Fcons (Fcons (Qmin_height,
1170+ rep_MAKE_INT(hints->min_height)), ret));
1171+ }
1172+ if (flags & PMaxSize)
1173+ {
1174+ ret = Fcons (Fcons (Qmax_width, rep_MAKE_INT(hints->max_width)),
1175+ Fcons (Fcons (Qmax_height,
1176+ rep_MAKE_INT(hints->max_height)), ret));
1177+ }
1178+ if (flags & PResizeInc)
1179+ {
1180+ ret = Fcons (Fcons (Qwidth_inc, rep_MAKE_INT(hints->width_inc)),
1181+ Fcons (Fcons (Qheight_inc,
1182+ rep_MAKE_INT(hints->height_inc)), ret));
1183+ }
1184+ if (flags & PBaseSize)
1185+ {
1186+ ret = Fcons (Fcons (Qbase_width, rep_MAKE_INT(hints->base_width)),
1187+ Fcons (Fcons (Qbase_height,
1188+ rep_MAKE_INT(hints->base_height)), ret));
1189+ }
1190+ if (flags & PAspect)
1191+ {
1192+ ret = Fcons (Fcons (Qmin_aspect,
1193+ Fcons (rep_MAKE_INT(hints->min_aspect.x),
1194+ rep_MAKE_INT(hints->min_aspect.y))),
1195+ Fcons (Fcons (Qmax_aspect,
1196+ Fcons (rep_MAKE_INT(hints->max_aspect.x),
1197+ rep_MAKE_INT(hints->max_aspect.y))),
1198+ ret));
1199+ }
1200+ if (flags & USPosition)
1201+ ret = Fcons (Fcons (Quser_position, Qt), ret);
1202+ else if (flags & PPosition)
1203+ ret = Fcons (Fcons (Qprogram_position, Qt), ret);
1204+ if (flags & USSize)
1205+ ret = Fcons (Fcons (Quser_size, Qt), ret);
1206+ else if (flags & PSize)
1207+ ret = Fcons (Fcons (Qprogram_size, Qt), ret);
1208+ if ((flags & PWinGravity)
1209+ && hints->win_gravity >= ForgetGravity
1210+ && hints->win_gravity <= StaticGravity)
1211+ {
1212+ ret = Fcons (Fcons (Qwindow_gravity,
1213+ gravity_map[hints->win_gravity]), ret);
1214+ }
1215+ return ret;
1216+}
1217+
1218+DEFUN("call-window-hook", Fcall_window_hook, Scall_window_hook,
1219+ (repv hook, repv win, repv args, repv type), rep_Subr4) /*
1220+::doc:sawfish.wm.windows.subrs#call-window-hook::
1221+call-window-hook HOOK WINDOW &optional ARGS HOOK-TYPE
1222+
1223+Call HOOK for WINDOW with extra arguments ARGS. See `call-hook' for a
1224+description of HOOK-TYPE.
1225+::end:: */
1226+{
1227+ repv tem;
1228+ rep_GC_root gc_hook, gc_args, gc_type;
1229+ rep_DECLARE1(hook, rep_SYMBOLP);
1230+ rep_DECLARE2(win, XWINDOWP);
1231+ args = Fcons (win, args);
1232+ rep_PUSHGC(gc_hook, hook);
1233+ rep_PUSHGC(gc_args, args);
1234+ rep_PUSHGC(gc_type, type);
1235+ tem = Fwindow_get (win, hook);
1236+ if (tem && tem != Qnil)
1237+ {
1238+ tem = Fcall_hook (tem, args, type);
1239+ if (!tem || (type == Qand && tem == Qnil)
1240+ || (type == Qor && tem != Qnil))
1241+ {
1242+ goto out;
1243+ }
1244+ }
1245+ tem = Fcall_hook (hook, args, type);
1246+out:
1247+ rep_POPGC; rep_POPGC; rep_POPGC;
1248+ return tem;
1249+}
1250+
1251+DEFUN("window-icon-image", Fwindow_icon_image,
1252+ Swindow_icon_image, (repv win), rep_Subr1) /*
1253+::doc:sawfish.wm.windows.subrs#window-icon-image::
1254+window-icon-image WINDOW
1255+
1256+Returns an image object representing the icon currently associated with
1257+WINDOW. Returns the symbol `nil' if no such image.
1258+::end:: */
1259+{
1260+ rep_DECLARE1 (win, WINDOWP);
1261+
1262+ if (VWIN (win)->icon_image == rep_NULL)
1263+ {
1264+ Window pixmap_id = 0, mask_id = 0;
1265+
1266+ if (VWIN (win)->wmhints != 0)
1267+ {
1268+ if (VWIN (win)->wmhints->flags & IconPixmapHint
1269+ && VWIN (win)->wmhints->icon_pixmap != 0)
1270+ {
1271+ pixmap_id = VWIN (win)->wmhints->icon_pixmap;
1272+ }
1273+
1274+ if (VWIN (win)->wmhints->flags & IconMaskHint
1275+ && VWIN (win)->wmhints->icon_mask != 0)
1276+ {
1277+ mask_id = VWIN (win)->wmhints->icon_mask;
1278+ }
1279+ }
1280+
1281+ if (pixmap_id == 0 && !WINDOW_IS_GONE_P (VWIN (win)))
1282+ {
1283+ Atom actual_type;
1284+ int actual_format;
1285+ long nitems, bytes_after;
1286+ u_long *data = 0;
1287+
1288+ static Atom kwm_win_icon = 0;
1289+
1290+ if (kwm_win_icon == 0)
1291+ kwm_win_icon = XInternAtom (dpy, "KWM_WIN_ICON", False);
1292+
1293+ if (XGetWindowProperty (dpy, VWIN (win)->id, kwm_win_icon,
1294+ 0, 2, False, kwm_win_icon,
1295+ &actual_type, &actual_format,
1296+ &nitems, &bytes_after,
1297+ (u_char **) &data) == Success
1298+ && actual_type == kwm_win_icon
1299+ && bytes_after == 0)
1300+ {
1301+ pixmap_id = data[0];
1302+ mask_id = data[1];
1303+ }
1304+ if (data != 0)
1305+ XFree (data);
1306+ }
1307+
1308+ VWIN (win)->icon_image = Qnil;
1309+
1310+ if (pixmap_id != 0)
1311+ {
1312+ VWIN (win)->icon_image = (Fmake_image_from_x_drawable
1313+ (rep_MAKE_INT (pixmap_id),
1314+ mask_id ? rep_MAKE_INT (mask_id) : Qnil));
1315+ }
1316+ }
1317+
1318+ return VWIN (win)->icon_image;
1319+}
1320+
1321+DEFUN ("map-windows", Fmap_windows, Smap_windows, (repv fun), rep_Subr1) /*
1322+::doc:sawfish.wm.windows.subrs#map-windows::
1323+map-windows FUN
1324+
1325+Map the single-parameter function FUN over all existing windows.
1326+::end:: */
1327+{
1328+ repv w;
1329+ rep_GC_root gc_fun, gc_w;
1330+ repv ret = Qnil;
1331+
1332+ rep_PUSHGC (gc_fun, fun);
1333+ rep_PUSHGC (gc_w, w);
1334+ for (w = rep_VAL (window_list); w != rep_NULL; w = rep_VAL (VWIN(w)->next))
1335+ {
1336+ if (!WINDOW_IS_GONE_P (VWIN (w)))
1337+ {
1338+ ret = rep_call_lisp1 (fun, w);
1339+ if (ret == rep_NULL)
1340+ break;
1341+ }
1342+ }
1343+ rep_POPGC; rep_POPGC;
1344+ return ret;
1345+}
1346+
1347+DEFUN ("filter-windows", Ffilter_windows,
1348+ Sfilter_windows, (repv pred), rep_Subr1) /*
1349+::doc:sawfish.wm.windows.subrs#filter-windows::
1350+filter-windows PRED
1351+
1352+Return the list of windows that match the predicate function PRED.
1353+::end:: */
1354+{
1355+ repv w, output = Qnil, *ptr = &output;
1356+ rep_GC_root gc_pred, gc_w, gc_output;
1357+
1358+ rep_PUSHGC(gc_pred, pred);
1359+ rep_PUSHGC(gc_w, w);
1360+ rep_PUSHGC(gc_output, output);
1361+ for (w = rep_VAL (window_list); w != rep_NULL; w = rep_VAL (VWIN(w)->next))
1362+ {
1363+ if (!WINDOW_IS_GONE_P (VWIN (w)))
1364+ {
1365+ repv tem = rep_call_lisp1 (pred, w);
1366+ if (tem == rep_NULL)
1367+ {
1368+ output = rep_NULL;
1369+ break;
1370+ }
1371+ if (tem != Qnil)
1372+ {
1373+ *ptr = Fcons (w, Qnil);
1374+ ptr = rep_CDRLOC (*ptr);
1375+ }
1376+ }
1377+ }
1378+ rep_POPGC; rep_POPGC; rep_POPGC;
1379+ return output;
1380+}
1381+
1382+
1383+/* type hooks */
1384+
1385+static int
1386+window_cmp (repv w1, repv w2)
1387+{
1388+ return w1 != w2;
1389+}
1390+
1391+static void
1392+window_prin (repv stream, repv win)
1393+{
1394+ char buf[128];
1395+ sprintf (buf, "#<window %lx>", VWIN(win)->id);
1396+ rep_stream_puts (stream, buf, -1, FALSE);
1397+}
1398+
1399+static void
1400+window_mark (repv win)
1401+{
1402+ rep_MARKVAL(VWIN(win)->plist);
1403+ rep_MARKVAL(VWIN(win)->frame_style);
1404+ mark_frame_parts (VWIN(win));
1405+ rep_MARKVAL(VWIN(win)->name);
1406+ rep_MARKVAL(VWIN(win)->full_name);
1407+ rep_MARKVAL(VWIN(win)->icon_name);
1408+ rep_MARKVAL(VWIN(win)->icon_image);
1409+}
1410+
1411+static void
1412+window_mark_type (void)
1413+{
1414+ Lisp_Window *w;
1415+ struct prop_handler *ph;
1416+ for (w = window_list; w != 0; w = w->next)
1417+ {
1418+ if (!WINDOW_IS_GONE_P (w) || !w->destroyed)
1419+ rep_MARKVAL(rep_VAL(w));
1420+ }
1421+ for (ph = prop_handlers; ph != 0; ph = ph->next)
1422+ rep_MARKVAL (ph->prop);
1423+ rep_MARKVAL (rep_VAL (focus_window));
1424+}
1425+
1426+static void
1427+window_sweep (void)
1428+{
1429+ Lisp_Window **ptr = &window_list;
1430+ while (*ptr != 0)
1431+ {
1432+ Lisp_Window *w = *ptr;
1433+ if (!rep_GC_CELL_MARKEDP(rep_VAL(w)))
1434+ {
1435+ assert (!window_in_stacking_list_p (w));
1436+ destroy_window_frame (w, FALSE);
1437+ if (w->wmhints != 0)
1438+ XFree (w->wmhints);
1439+ if (w->n_cmap_windows > 0)
1440+ XFree (w->cmap_windows);
1441+ *ptr = w->next;
1442+ rep_FREE_CELL(w);
1443+ }
1444+ else
1445+ {
1446+ ptr = &(w->next);
1447+ rep_GC_CLR_CELL(rep_VAL(w));
1448+ }
1449+ }
1450+}
1451+
1452+
1453+/* initialisation */
1454+
1455+void
1456+manage_windows (void)
1457+{
1458+ Window root, parent, *children, focus;
1459+ unsigned int nchildren, i;
1460+ int revert_to;
1461+
1462+ Fgrab_server ();
1463+
1464+ XGetInputFocus (dpy, &focus, &revert_to);
1465+ if (focus == PointerRoot)
1466+ {
1467+ Window root, child;
1468+ Bool found;
1469+ int rx, ry, wx, wy;
1470+ unsigned mask;
1471+
1472+ found = XQueryPointer (dpy, DefaultRootWindow(dpy), &root,
1473+ &child, &rx, &ry, &wx, &wy, &mask);
1474+ if (!found)
1475+ {
1476+ found = XQueryPointer (dpy, root, &root, &child,
1477+ &rx, &ry, &wx, &wy, &mask);
1478+ }
1479+ focus = child;
1480+ }
1481+
1482+ XQueryTree (dpy, root_window, &root, &parent, &children, &nchildren);
1483+ initialising = TRUE;
1484+ for (i = 0; i < nchildren; i++)
1485+ {
1486+ if (mapped_not_override_p (children[i]))
1487+ {
1488+ XEvent fake;
1489+ Lisp_Window *w;
1490+ fake.xmaprequest.window = children[i];
1491+ /* Make sure the window is initially unmapped. We expect to
1492+ get map-notify events when we later remap it.. #67601 */
1493+ XUnmapWindow (dpy, children[i]);
1494+ map_request (&fake);
1495+ w = find_window_by_id (children[i]);
1496+ }
1497+ }
1498+ initialising = FALSE;
1499+ if (nchildren > 0)
1500+ XFree (children);
1501+
1502+ /* Try to keep the current focus state. */
1503+ focus_on_window (0);
1504+ if (focus != None)
1505+ {
1506+ Lisp_Window *w = find_window_by_id (focus);
1507+ if (w != 0)
1508+ focus_on_window (w);
1509+ }
1510+
1511+ Fungrab_server ();
1512+ Fcall_hook (Qafter_initialization_hook, Qnil, Qnil);
1513+}
1514+
1515+void
1516+windows_init (void)
1517+{
1518+ repv tem;
1519+ window_type = rep_register_new_type ("window", window_cmp, window_prin,
1520+ window_prin, window_sweep,
1521+ window_mark, window_mark_type,
1522+ 0, 0, 0, 0, 0, 0);
1523+
1524+ tem = rep_push_structure ("sawfish.wm.windows.subrs");
1525+ rep_ADD_SUBR(Swindow_get);
1526+ rep_ADD_SUBR(Smap_window_properties);
1527+ rep_ADD_SUBR(Swindow_put);
1528+ rep_ADD_SUBR(Swindow_name);
1529+ rep_ADD_SUBR(Swindow_full_name);
1530+ rep_ADD_SUBR(Swindow_icon_name);
1531+ rep_ADD_SUBR(Swindow_mapped_p);
1532+ rep_ADD_SUBR(Swindow_frame);
1533+ rep_ADD_SUBR(Sset_window_frame);
1534+ rep_ADD_SUBR(Srebuild_frame);
1535+ rep_ADD_SUBR(Swindow_position);
1536+ rep_ADD_SUBR(Swindow_dimensions);
1537+ rep_ADD_SUBR(Swindow_frame_dimensions);
1538+ rep_ADD_SUBR(Swindow_frame_offset);
1539+ rep_ADD_SUBR(Swindowp);
1540+ rep_ADD_SUBR(Sset_input_focus);
1541+ rep_ADD_SUBR(Sinput_focus);
1542+ rep_ADD_SUBR(Swindow_wants_input_p);
1543+ rep_ADD_SUBR(Smanaged_windows);
1544+ rep_ADD_SUBR(Sget_window_by_id);
1545+ rep_ADD_SUBR(Sstacking_order);
1546+ rep_ADD_SUBR(Swindow_visibility);
1547+ rep_ADD_SUBR(Swindow_transient_p);
1548+ rep_ADD_SUBR(Swindow_urgent_p);
1549+ rep_ADD_SUBR(Swindow_shaped_p);
1550+ rep_ADD_SUBR(Shide_window);
1551+ rep_ADD_SUBR(Sshow_window);
1552+ rep_ADD_SUBR(Swindow_visible_p);
1553+ rep_ADD_SUBR(Swindow_framed_p);
1554+ rep_ADD_SUBR(Swindow_id);
1555+ rep_ADD_SUBR(Swindow_group_id);
1556+ rep_ADD_SUBR(Swindow_size_hints);
1557+ rep_ADD_SUBR(Scall_window_hook);
1558+ rep_ADD_SUBR(Swindow_border_width);
1559+ rep_ADD_SUBR(Swindow_icon_image);
1560+ rep_ADD_SUBR(Smap_windows);
1561+ rep_ADD_SUBR(Sfilter_windows);
1562+ rep_pop_structure (tem);
1563+
1564+ rep_INTERN_SPECIAL(before_add_window_hook);
1565+ rep_INTERN_SPECIAL(add_window_hook);
1566+ rep_INTERN_SPECIAL(after_add_window_hook);
1567+ rep_INTERN_SPECIAL(place_window_hook);
1568+ rep_INTERN(placed);
1569+ rep_INTERN_SPECIAL(after_framing_hook);
1570+ rep_INTERN_SPECIAL(after_initialization_hook);
1571+ rep_INTERN_SPECIAL(remove_window_hook);
1572+
1573+ rep_INTERN(fully_obscured);
1574+ rep_INTERN(partially_obscured);
1575+ rep_INTERN(unobscured);
1576+
1577+ rep_INTERN(min_width);
1578+ rep_INTERN(min_height);
1579+ rep_INTERN(max_width);
1580+ rep_INTERN(max_height);
1581+ rep_INTERN(width_inc);
1582+ rep_INTERN(height_inc);
1583+ rep_INTERN(base_width);
1584+ rep_INTERN(base_height);
1585+ rep_INTERN(min_aspect);
1586+ rep_INTERN(max_aspect);
1587+ rep_INTERN(user_size);
1588+ rep_INTERN(user_position);
1589+ rep_INTERN(program_size);
1590+ rep_INTERN(program_position);
1591+ rep_INTERN(window_gravity);
1592+ rep_INTERN(forget);
1593+ rep_INTERN(static);
1594+ rep_INTERN(north_west);
1595+ rep_INTERN(north);
1596+ rep_INTERN(north_east);
1597+ rep_INTERN(west);
1598+ rep_INTERN(center);
1599+ rep_INTERN(east);
1600+ rep_INTERN(south_west);
1601+ rep_INTERN(south);
1602+ rep_INTERN(south_east);
1603+
1604+ gravity_map[ForgetGravity] = Qforget;
1605+ gravity_map[NorthWestGravity] = Qnorth_west;
1606+ gravity_map[NorthGravity] = Qnorth;
1607+ gravity_map[NorthEastGravity] = Qnorth_east;
1608+ gravity_map[WestGravity] = Qwest;
1609+ gravity_map[CenterGravity] = Qcenter;
1610+ gravity_map[EastGravity] = Qeast;
1611+ gravity_map[SouthWestGravity] = Qsouth_west;
1612+ gravity_map[SouthGravity] = Qsouth;
1613+ gravity_map[SouthEastGravity] = Qsouth_east;
1614+ gravity_map[StaticGravity] = Qstatic;
1615+}
1616+
1617+void
1618+windows_kill (void)
1619+{
1620+ Lisp_Window *w = window_list;
1621+ repv next;
1622+ rep_GC_root gc_next;
1623+ rep_PUSHGC (gc_next, next);
1624+ while (w != 0)
1625+ {
1626+ next = rep_VAL (w->next);
1627+ Fcall_window_hook (Qremove_window_hook, rep_VAL (w), Qnil, Qnil);
1628+ remove_window (w, Qnil, Qnil);
1629+ w = VWIN (next);
1630+ }
1631+}