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

« back to all changes in this revision

Viewing changes to src/functions.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
/* functions.c -- useful window manager Lisp functions
 
2
   $Id: functions.c,v 1.91 2001/10/22 06:26:19 jsh Exp $
 
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
}