Japanese translation of message catalog for Sawfish Window-Manager
Révision | 2d04c16ab155d09e5f2508fe76394bcc751b13fc (tree) |
---|---|
l'heure | 2002-03-21 16:50:37 |
Auteur | John Harper <jsh@src....> |
Commiter | John Harper |
Merged changes from HEAD (up to current location of gnome-2-merged-HEAD tag)
@@ -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 | + | |
1 | 43 | 2002-03-17 T?vo Leedj?v <toivo@linux.ee> |
2 | 44 | |
3 | 45 | * po/et.po: Updated Estonian translation. |
@@ -66,7 +108,7 @@ | ||
66 | 108 | |
67 | 109 | 2002-01-04 Pablo Saratxaga <pablo@mandrakesoft.com> |
68 | 110 | |
69 | - * configure.in: Added "eu" to ALL_LINGUAS | |
111 | + * configure.in: Added "eu" to ALL_LINGUAS | |
70 | 112 | |
71 | 113 | 2001-12-17 Germ? Poo-Caama? <gpoo@ubiobio.cl> |
72 | 114 |
@@ -249,25 +249,15 @@ else | ||
249 | 249 | fi |
250 | 250 | AC_SUBST(REP_GTK_GNOME) |
251 | 251 | |
252 | -dnl Check for Doug Lea's malloc in libc, otherwise compile dlmalloc.c | |
252 | +dnl Check for Doug Lea's malloc in libc | |
253 | 253 | doug_lea_malloc=yes |
254 | 254 | AC_CHECK_FUNC(malloc_get_state, , doug_lea_malloc=no) |
255 | 255 | AC_CHECK_FUNC(malloc_set_state, , doug_lea_malloc=no) |
256 | 256 | 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) | |
271 | 261 | else |
272 | 262 | AC_DEFINE(DOUG_LEA_MALLOC) |
273 | 263 | AC_DEFINE(LIBC_MALLOC) |
@@ -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 | + | |
1 | 23 | 2002-01-10 Sander Vesik <sander.vesik@sun.com> |
2 | 24 | |
3 | 25 | * image.c: gdk_pixbuf_new_from_file now takes two parameters |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |