1
/* functions.c -- useful window manager Lisp functions
2
$Id: functions.c,v 1.91 2001/10/22 06:26:19 jsh Exp $
4
Copyright (C) 1999 John Harper <john@dcs.warwick.ac.uk>
6
This file is part of sawmill.
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)
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.
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. */
22
/* Define this to fake two side-by-side Xinerama style heads */
25
/* AIX requires this to be the first thing in the file. */
36
# ifndef alloca /* predefined by HP cc +Olibcalls */
44
#include <X11/Xatom.h>
46
/* Number of outstanding server grabs made; only when this is zero is
47
the server ungrabbed. */
48
static int server_grabs;
50
static int xinerama_heads;
52
#ifdef HAVE_X11_EXTENSIONS_XINERAMA_H
53
# include <X11/extensions/Xinerama.h>
54
static XineramaScreenInfo *xinerama_head_info;
56
static XineramaScreenInfo debug_heads[2] = {
57
{ 0, 0, 0, 512, 768 },
58
{ 0, 512, 0, 512, 768 }
60
static int debug_nheads = 2;
62
static int xinerama_event_base, xinerama_error_base;
67
DEFSYM(after_restacking_hook, "after-restacking-hook");
68
DEFSYM(position, "position");
69
DEFSYM(spacing, "spacing");
70
DEFSYM(window, "window");
73
DEFUN("restack-windows", Frestack_windows, Srestack_windows,
74
(repv list), rep_Subr1) /*
75
::doc:sawfish.wm.windows.subrs#restack-windows::
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.
86
rep_DECLARE1(list, rep_LISTP);
87
for (ptr = list; rep_CONSP (ptr); ptr = rep_CDR (ptr))
89
if (!WINDOWP (rep_CAR (ptr)))
90
return rep_signal_arg_error (list, 1);
99
while (rep_CONSP (ptr))
101
Lisp_Window *this = VWIN (rep_CAR (ptr));
103
if (!WINDOW_IS_GONE_P (this))
105
if (pred != 0 && !WINDOW_IS_GONE_P (pred))
107
remove_from_stacking_list (this);
108
insert_in_stacking_list_below (this, pred);
110
/* This works because it tries to stack relative to
111
the window above THIS first; which we just set */
112
restack_window (this);
124
Fcall_hook (Qafter_restacking_hook, Qnil, Qnil);
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]
133
Raise WINDOW so that it is above window ABOVE. If ABOVE is undefined,
134
raise WINDOW to the top of the stacking order.
137
rep_DECLARE1 (win, WINDOWP);
139
if (!WINDOW_IS_GONE_P (VWIN (win)))
143
if (!WINDOW_IS_GONE_P (VWIN (above)))
145
remove_from_stacking_list (VWIN (win));
146
insert_in_stacking_list_above (VWIN (win), VWIN (above));
151
remove_from_stacking_list (VWIN (win));
152
insert_in_stacking_list_above_all (VWIN (win));
154
restack_window (VWIN (win));
155
Fcall_hook (Qafter_restacking_hook, Qnil, Qnil);
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]
165
Lower WINDOW so that it is below window BELOW. If BELOW is undefined,
166
lower WINDOW to the bottom of the stacking order.
169
rep_DECLARE1 (win, WINDOWP);
171
if (!WINDOW_IS_GONE_P (VWIN (win)))
175
if (!WINDOW_IS_GONE_P (VWIN (below)))
177
remove_from_stacking_list (VWIN (win));
178
insert_in_stacking_list_below (VWIN (win), VWIN (below));
183
remove_from_stacking_list (VWIN (win));
184
insert_in_stacking_list_below_all (VWIN (win));
186
restack_window (VWIN (win));
187
Fcall_hook (Qafter_restacking_hook, Qnil, Qnil);
192
DEFUN("x-kill-client", Fx_kill_client, Sx_kill_client,
193
(repv win), rep_Subr1)
195
Window w = x_win_from_arg (win);
197
return WINDOWP(win) ? Qnil : rep_signal_arg_error (win, 1);
198
XKillClient (dpy, w);
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
206
Destroy WINDOW with out giving the owning application any warning.
208
WINDOW may be a window object or a numeric window id.
212
XDestroyWindow (dpy, VWIN(win)->id);
213
else if (rep_INTEGERP(win))
214
XDestroyWindow (dpy, rep_get_long_uint (win));
216
return rep_signal_arg_error (win, 1);
220
DEFUN("warp-cursor", Fwarp_cursor, Swarp_cursor, (repv x, repv y), rep_Subr2) /*
221
::doc:sawfish.wm.misc#warp-cursor::
224
Move the mouse pointer to position (X, Y) relative to the origin of the
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)
233
XWarpPointer (dpy, None, root_window,
234
0, 0, 0, 0, rep_INT(x), rep_INT(y));
235
invalidate_cached_mouse_position ();
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
247
Move the top-left corner of window object WINDOW to (X, Y).
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))
255
VWIN(win)->attr.x = rep_INT(x);
256
VWIN(win)->attr.y = rep_INT(y);
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);
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
271
Set the dimensions of window object WINDOW to (WIDTH, HEIGHT).
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);
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
290
Reconfigure the geometry of window object WINDOW as specified.
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);
309
fix_window_size (VWIN(win));
310
VWIN (win)->pending_configure = 0;
312
if (moved && !resized)
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));
319
Fcall_window_hook (Qwindow_moved_hook, win, Qnil, Qnil);
321
Fcall_window_hook (Qwindow_resized_hook, win, Qnil, Qnil);
325
DEFUN("grab-server", Fgrab_server, Sgrab_server, (void), rep_Subr0) /*
326
::doc:sawfish.wm.misc#grab-server::
329
Prevent any other clients from accessing the X server. See `ungrab-server'.
332
if (server_grabs++ == 0)
336
rep_mark_input_pending (ConnectionNumber (dpy));
341
DEFUN("ungrab-server", Fungrab_server, Sungrab_server, (void), rep_Subr0) /*
342
::doc:sawfish.wm.misc#ungrab-server::
345
After a call to `grab-server' this will allow other clients to access
348
Note that calls to `grab-server' and `ungrab-server' _nest_.
351
if (--server_grabs == 0)
359
DEFUN("server-grabbed-p", Fserver_grabbed_p,
360
Sserver_grabbed_p, (void), rep_Subr0) /*
361
::doc:sawfish.wm.misc#server-grabbed-p::
364
Return t if the server is currently grabbed.
367
return (server_grabs > 0) ? Qt : Qnil;
370
/* Call this when the server may have been ungrabbed prematurely (imlib
375
if (server_grabs > 0)
382
DEFUN("grab-pointer", Fgrab_pointer, Sgrab_pointer,
383
(repv win, repv cursor, repv ptr_sync, repv kbd_sync, repv confine_to),
385
::doc:sawfish.wm.events#grab-pointer::
386
grab-pointer [WINDOW] [CURSOR] [PTR-SYNC] [KBD-SYNC] [CONFINE-TO]
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.
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.
396
CONFINE-TO, if non-nil, is a visible window to confine the pointer to.
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.
406
Returns non-nil if the grab succeeded.
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);
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);
426
if (cursor != Qnil && !CURSORP(cursor))
428
cursor = Fget_cursor (cursor);
434
ret = XGrabPointer (dpy, g_win, False, POINTER_GRAB_EVENTS,
435
rep_NILP( ptr_sync) ? GrabModeAsync : GrabModeSync,
436
rep_NILP( kbd_sync) ? GrabModeAsync : GrabModeSync,
438
CURSORP(cursor) ? VCURSOR(cursor)->cursor : None,
440
if (ret == GrabNotViewable && (g_win != root_window || c_win != None))
442
/* fall back to the root window. */
448
DB(("grab-pointer: time=%lu ret=%d\n", last_event_time, ret));
449
return (ret == GrabSuccess) ? Qt : Qnil;
452
DEFUN("ungrab-pointer", Fungrab_pointer, Sungrab_pointer, (void), rep_Subr0) /*
453
::doc:sawfish.wm.events#ungrab-pointer::
456
Release the grab on the mouse pointer.
459
XUngrabPointer (dpy, last_event_time);
460
synthesize_button_release ();
461
DB(("ungrab-pointer: time=%lu\n", last_event_time));
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]
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.
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.
481
Returns non-nil if the grab succeeded.
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);
495
ret = XGrabKeyboard (dpy, g_win, False,
496
rep_NILP( ptr_sync) ? GrabModeAsync : GrabModeSync,
497
rep_NILP( kbd_sync) ? GrabModeAsync : GrabModeSync,
499
if (ret == GrabNotViewable && g_win != root_window)
501
/* fall back to the root window. */
506
DB(("grab-keyboard: time=%lu ret=%d\n", last_event_time, ret));
507
return (ret == GrabSuccess) ? Qt : Qnil;
510
DEFUN("ungrab-keyboard", Fungrab_keyboard,
511
Sungrab_keyboard, (void), rep_Subr0) /*
512
::doc:sawfish.wm.events#ungrab-keyboard::
515
Release the grab on the keyboard.
518
DB(("ungrab-keyboard: time=%lu\n", last_event_time));
519
XUngrabKeyboard (dpy, last_event_time);
523
DEFUN("screen-width", Fscreen_width, Sscreen_width, (void), rep_Subr0) /*
524
::doc:sawfish.wm.misc#screen-width::
527
Return the width of the root window (in pixels).
530
return rep_MAKE_INT(screen_width);
533
DEFUN("screen-height", Fscreen_height, Sscreen_height, (void), rep_Subr0) /*
534
::doc:sawfish.wm.misc#screen-height::
537
Return the height of the root window (in pixels).
540
return rep_MAKE_INT(screen_height);
543
DEFUN("sync-server", Fsync_server, Ssync_server, (void), rep_Subr0) /*
544
::doc:sawfish.wm.misc#sync-server::
547
Flush all pending X requests, don't wait for them to finish.
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
559
Delete the X property ATOM (a symbol) of WINDOW.
561
WINDOW may be the symbol `root', a window object or a numeric window id.
564
Window w = x_win_from_arg (win);
565
rep_DECLARE2(atom, rep_SYMBOLP);
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));
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
578
List all X properties (symbols) of WINDOW.
580
WINDOW may be the symbol `root', a window object or a numeric window id.
588
w = x_win_from_arg (win);
590
return WINDOWP(win) ? Qnil : rep_signal_arg_error (win, 1);
591
atoms = XListProperties (dpy, w, &count);
594
char **names = alloca (sizeof (char *) * count);
595
if (XGetAtomNames (dpy, atoms, count, names) != 0)
598
for (i = 0; i < count; i++)
600
ret = Fcons (Fintern (rep_string_dup (names[i]),
607
return Fnreverse (ret);
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
615
Return (TYPE FORMAT DATA) representing the X property PROPERTY (a
616
symbol) of WINDOW. If no such property exists, return nil.
618
WINDOW may be the symbol `root', a window object or a numeric window
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.
626
If TYPE is `ATOM' and FORMAT is 32, then DATA will be a vector of
627
symbols, representing the atoms read.
636
repv type_sym, ret_data = Qnil;
638
w = x_win_from_arg (win);
639
rep_DECLARE2(prop, rep_SYMBOLP);
641
return WINDOWP(win) ? Qnil : rep_signal_arg_error (win, 1);
642
a_prop = XInternAtom (dpy, rep_STR(rep_SYM(prop)->name), False);
644
/* First read the data.. */
646
long long_length = 32;
652
if (XGetWindowProperty (dpy, w, a_prop, 0, long_length, False,
653
AnyPropertyType, &type, &format,
654
&nitems, &bytes_after, &data) != Success)
658
if (bytes_after == 0)
660
long_length += (bytes_after / sizeof(u_long)) + 1;
664
/* Convert the type to a symbol */
665
type_sym = x_atom_symbol (type);
667
/* Then convert the contents to a vector or string */
675
ret_data = rep_string_dupn (data, nitems);
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]);
686
ret_data = Fmake_vector (rep_MAKE_INT(nitems), Qnil);
687
l_data = (u_long *)data;
688
for (i = 0; i < nitems; i++)
691
if (type == XA_ATOM && (name = x_atom_symbol (l_data[i])) != Qnil)
692
rep_VECTI(ret_data, i) = name;
694
rep_VECTI(ret_data, i) = rep_make_long_uint(l_data[i]);
700
return rep_list_3 (type_sym, rep_MAKE_INT(format), ret_data);
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
708
Set the X property PROPERTY (a symbol) of WINDOW to the array DATA.
710
WINDOW may be the symbol `root', a window object or a numeric window
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.
717
If TYPE is `ATOM' and FORMAT is 32, then any symbols in DATA will be
718
converted to their numeric X atoms.
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);
734
return WINDOWP(win) ? prop : rep_signal_arg_error (win, 1);
736
/* Convert to data array */
738
if (rep_STRINGP(data))
739
nitems = rep_STRING_LEN(data);
741
nitems = rep_VECT_LEN(data);
743
switch (rep_INT(format))
750
if (rep_STRINGP(data))
751
c_data = rep_STR (data);
754
c_data = alloca (nitems);
755
for (i = 0; i < nitems; i++)
756
c_data[i] = rep_STR(data)[i];
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));
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++)
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);
779
l_data[i] = rep_get_long_uint (rep_VECTI(data, i));
784
/* Overwrite property */
785
XChangeProperty (dpy, w, a_prop, a_type, rep_INT(format),
786
PropModeReplace, c_data, nitems);
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
798
XTextProperty t_prop;
801
w = x_win_from_arg (win);
802
rep_DECLARE2(prop, rep_SYMBOLP);
804
return WINDOWP(win) ? Qnil : rep_signal_arg_error (win, 1);
805
a_prop = XInternAtom (dpy, rep_STR(rep_SYM(prop)->name), False);
807
if (XGetTextProperty (dpy, w, &t_prop, a_prop) != 0)
811
if (XTextPropertyToStringList (&t_prop, &list, &count) != 0)
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);
819
XFree (t_prop.value);
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
833
XTextProperty t_prop;
837
w = x_win_from_arg (win);
838
rep_DECLARE2(prop, rep_SYMBOLP);
839
rep_DECLARE3(vect, rep_VECTORP);
841
return WINDOWP(win) ? Qnil : rep_signal_arg_error (win, 1);
842
a_prop = XInternAtom (dpy, rep_STR(rep_SYM(prop)->name), False);
844
count = rep_VECT_LEN(vect);
845
strings = alloca (sizeof (char *) * (count + 1));
846
for (i = 0; i < count; i++)
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));
852
if (XStringListToTextProperty (strings, count, &t_prop) != 0)
854
XSetTextProperty (dpy, w, &t_prop, a_prop);
855
XFree (t_prop.value);
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
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).
872
XClientMessageEvent ev;
873
Window w = x_win_from_arg (win);
875
rep_DECLARE2(type, rep_SYMBOLP);
876
rep_DECLARE(3, data, rep_STRINGP(data) || rep_VECTORP(data));
877
rep_DECLARE4(format, rep_INTP);
880
return WINDOWP(win) ? Qnil : rep_signal_arg_error (win, 1);
882
ev.type = ClientMessage;
884
ev.message_type = XInternAtom (dpy, rep_STR(rep_SYM(type)->name), False);
885
ev.format = rep_INT(format);
887
switch (rep_INT(format))
892
if (rep_STRINGP(data))
893
memcpy (rep_STR(data), ev.data.b, MAX(rep_STRING_LEN(data), 20));
896
for (i = 0; i < rep_VECT_LEN(data) && i < 20; i++)
897
ev.data.b[i] = rep_INT(rep_VECTI(data, i));
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));
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));
916
XSendEvent (dpy, w, False, 0L, (XEvent *) &ev);
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
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.
928
Returns the window id of the new window.
931
Window parent_w = x_win_from_arg (parent);
933
rep_DECLARE2(x, rep_INTP);
934
rep_DECLARE3(y, rep_INTP);
935
rep_DECLARE4(width, rep_INTP);
936
rep_DECLARE5(height, rep_INTP);
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;
946
DEFUN("x-atom", Fx_atom, Sx_atom, (repv symbol), rep_Subr1) /*
947
::doc:sawfish.wm.misc#x-atom::
950
Return the integer identifying the X atom with the same name as SYMBOL.
953
rep_DECLARE1(symbol, rep_SYMBOLP);
954
return rep_MAKE_INT (XInternAtom (dpy, rep_STR(rep_SYM(symbol)->name),
958
DEFUN("x-atom-name", Fx_atom_name, Sx_atom_name, (repv atom), rep_Subr1) /*
959
::doc:sawfish.wm.misc#x-atom-name::
962
Return the symbol with the same name as the X atom identified by the
966
rep_DECLARE1(atom, rep_INTP);
967
return x_atom_symbol (rep_INT(atom));
970
DEFUN("root-window-id", Froot_window_id, Sroot_window_id, (void), rep_Subr0) /*
971
::doc:sawfish.wm.misc#root-window-id::
974
Returns the numeric id of the root window of the managed screen.
977
return rep_MAKE_INT (root_window);
981
/* xinerama support */
983
DEFUN ("head-count", Fhead_count, Shead_count, (void), rep_Subr0)
985
return rep_MAKE_INT (MAX (1, xinerama_heads));
988
DEFUN ("find-head", Ffind_head, Sfind_head, (repv x, repv y), rep_Subr2)
990
if (rep_CONSP (x) && y == Qnil)
995
rep_DECLARE (1, x, rep_INTP (x));
996
rep_DECLARE (2, y, rep_INTP (y));
998
#ifdef HAVE_X11_EXTENSIONS_XINERAMA_H
1001
for (i = 0; i < xinerama_heads; i++)
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)))
1010
return rep_MAKE_INT (i);
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)
1019
return rep_MAKE_INT (0);
1024
DEFUN ("head-dimensions", Fhead_dimensions,
1025
Shead_dimensions, (repv id), rep_Subr1)
1027
rep_DECLARE (1, id, rep_INTP (id));
1029
if (xinerama_heads == 0 && rep_INT (id) == 0)
1031
return Fcons (rep_MAKE_INT (screen_width),
1032
rep_MAKE_INT (screen_height));
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));
1047
DEFUN ("head-offset", Fhead_offset, Shead_offset, (repv id), rep_Subr1)
1049
rep_DECLARE (1, id, rep_INTP (id));
1051
if (xinerama_heads == 0 && rep_INT (id) == 0)
1053
return Fcons (rep_MAKE_INT (0), rep_MAKE_INT (0));
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));
1069
/* Displaying a `message' window */
1071
static Window message_win;
1075
repv text, fg, bg, font, justify;
1079
#define MSG_PAD_X 20
1080
#define MSG_PAD_Y 10
1083
refresh_message_window ()
1085
if (message_win != 0)
1092
values.foreground = VCOLOR(message.fg)->pixel;
1093
values.background = VCOLOR(message.bg)->pixel;
1094
mask = GCForeground | GCBackground;
1096
if (message.gc == 0)
1097
message.gc = XCreateGC (dpy, message_win, mask, &values);
1099
XChangeGC (dpy, message.gc, mask, &values);
1101
XClearWindow (dpy, message_win);
1103
ptr = rep_STR(message.text);
1106
char *end = strchr (ptr, '\n');
1109
end = ptr + strlen (ptr);
1110
if (message.justify == Qleft)
1114
int width = x_text_width (message.font, ptr, end - ptr);
1115
if (message.justify == Qright)
1116
offset = message.width - (width + MSG_PAD_X);
1118
offset = (message.width - width) / 2;
1120
x_draw_string (message_win, message.font,
1123
+ row * (VFONT(message.font)->ascent
1124
+ VFONT(message.font)->descent
1126
+ VFONT(message.font)->ascent, ptr, end - ptr);
1136
message_event_handler (XEvent *ev)
1138
if (ev->type == Expose)
1139
refresh_message_window ();
1140
else if (ev->type == ButtonPress)
1141
Fdisplay_message (Qnil, Qnil);
1144
DEFSTRING(white, "white");
1145
DEFSTRING(black, "black");
1147
DEFUN("display-message", Fdisplay_message, Sdisplay_message,
1148
(repv text, repv attrs), rep_Subr2)
1152
if (message_win != 0)
1154
deregister_event_handler (message_win);
1155
XDestroyWindow (dpy, message_win);
1158
if (message.gc != 0)
1160
XFreeGC (dpy, message.gc);
1163
message.font = message.fg = message.bg = message.text = Qnil;
1171
rep_DECLARE1(text, rep_STRINGP);
1172
rep_DECLARE2(attrs, rep_LISTP);
1174
message.text = text;
1175
message.font = message.fg = message.bg = Qnil;
1176
message.justify = Qleft;
1177
message.spacing = 0;
1179
tem = Fassq (Qfont, attrs);
1180
if (tem && rep_CONSP(tem))
1182
message.font = rep_CDR(tem);
1183
if (!FONTP(message.font))
1185
message.font = Fget_font (message.font);
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);
1195
tem = Fassq (Qforeground, attrs);
1196
if (tem && rep_CONSP(tem))
1198
message.fg = rep_CDR(tem);
1199
if (!COLORP(message.fg))
1201
message.fg = Fget_color (message.fg);
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);
1211
tem = Fassq (Qbackground, attrs);
1212
if (tem && rep_CONSP(tem))
1214
message.bg = rep_CDR(tem);
1215
if (!COLORP(message.bg))
1217
message.bg = Fget_color (message.bg);
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);
1227
tem = Fassq (Qx_justify, attrs);
1228
if (tem && rep_CONSP(tem))
1229
message.justify = rep_CDR(tem);
1231
tem = Fassq (Qspacing, attrs);
1232
if (tem && rep_CONSP(tem) && rep_INTP(rep_CDR(tem)))
1233
message.spacing = rep_INT(rep_CDR(tem));
1236
char *ptr = rep_STR(text);
1237
int max_width = 0, rows = 0;
1239
int head_width, head_height;
1240
int head_xoff, head_yoff;
1244
char *end = strchr (ptr, '\n');
1246
end = ptr + strlen (ptr);
1247
text_width = x_text_width (message.font, ptr, end - ptr);
1248
max_width = MAX(max_width, text_width);
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);
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);
1265
if (head && head != Qnil)
1267
/* We have a head to centre on. */
1269
tem = Fhead_dimensions (head);
1272
head_width = rep_INT (rep_CAR (tem));
1273
head_height = rep_INT (rep_CDR (tem));
1275
tem = Fhead_offset (head);
1278
head_xoff = rep_INT (rep_CAR (tem));
1279
head_yoff = rep_INT (rep_CDR (tem));
1283
/* No head, just centre on the screen. */
1285
head_xoff = head_yoff = 0;
1286
head_width = screen_width;
1287
head_height = screen_height;
1290
x = head_xoff + ((head_width - message.width) / 2);
1291
y = head_yoff + ((head_height - height) / 2);
1294
tem = Fassq (Qposition, attrs);
1295
if (tem && rep_CONSP(tem))
1300
if (rep_INTP(rep_CAR(tem)))
1302
x = rep_INT(rep_CAR(tem));
1304
x += screen_width - message.width;
1306
if (rep_INTP(rep_CDR(tem)))
1308
y = rep_INT(rep_CDR(tem));
1310
y += screen_height - height;
1315
if (x + message.width > screen_width)
1316
x = MAX (0, screen_width - message.width - 4);
1319
if (y + height > screen_height)
1320
y = MAX (0, screen_height - height - 4);
1324
if (message_win == 0)
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,
1338
CWBackPixel | CWBorderPixel
1339
| CWOverrideRedirect | CWEventMask
1340
| CWColormap, &attr);
1341
if (message_win == 0)
1343
register_event_handler (message_win, message_event_handler);
1344
XMapRaised (dpy, message_win);
1348
XWindowChanges attr;
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,
1357
XSetWindowBackground (dpy, message_win, VCOLOR(message.bg)->pixel);
1358
refresh_message_window ();
1360
return rep_MAKE_INT(message_win);
1365
/* initialisation */
1368
functions_init (void)
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);
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);
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);
1417
rep_INTERN_SPECIAL(after_restacking_hook);
1418
rep_INTERN(position);
1419
rep_INTERN(spacing);
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);
1428
#ifdef HAVE_X11_EXTENSIONS_XINERAMA_H
1429
# ifndef TEST_XINERAMA
1432
if (XineramaQueryExtension (dpy, &xinerama_event_base,
1433
&xinerama_error_base))
1435
xinerama_head_info = XineramaQueryScreens (dpy, &xinerama_heads);
1439
xinerama_head_info = debug_heads;
1440
xinerama_heads = debug_nheads;
1446
functions_kill (void)
1448
if (message_win != 0)
1449
XDestroyWindow (dpy, message_win);