~ubuntu-branches/ubuntu/lucid/sawfish/lucid-updates

« back to all changes in this revision

Viewing changes to src/frames.c

  • Committer: Bazaar Package Importer
  • Author(s): Christian Marillat
  • Date: 2002-01-20 17:42:28 UTC
  • Revision ID: james.westby@ubuntu.com-20020120174228-4q1ydztbkvfq1ht2
Tags: upstream-1.0.1.20020116
ImportĀ upstreamĀ versionĀ 1.0.1.20020116

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* frames.c -- window frame manipulation
 
2
   $Id: frames.c,v 1.101 2001/02/20 00:04:57 jsh Exp $
 
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, "right");
 
57
DEFSYM(bottom, "left");
 
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
}