Generic_Window_Manager/client.c

1942 lines
56 KiB
C

/* Copyright 1989 GROUPE BULL -- See license conditions in file COPYRIGHT
* Copyright 1989 Massachusetts Institute of Technology
*/
/*********************************************************\
* *
* BULL WINDOW MANAGER for X11 . *
* *
* MODULE defining the ClientWindow Object Class. *
* *
\*********************************************************/
/* includes */
#include <stdio.h>
#include <string.h>
#include "EXTERN.h"
#include "wool.h"
#include "wl_atom.h"
#include "wl_string.h"
#include "wl_list.h"
#include "wl_number.h"
#include "wl_func.h"
#include "gwm.h"
#include "wl_event.h"
#include "wl_fsm.h"
#include "wl_pixmap.h"
#include "wl_cursor.h"
#include "wl_client.h"
#ifdef SHAPE
#include <X11/extensions/shape.h>
extern WindowIsShaped();
#endif /* SHAPE */
/* local constants */
/* external */
extern Wob SetUpClientWindow();
extern Bar NewBar(), BarOpen();
extern Wob LookUpWob();
extern ClientWindow LookUpClient();
extern UserAskWindow();
extern UserMessage();
extern FSMAction();
extern WOOL_METHOD WLMenu[];
extern XError(), NoXError();
extern Window FindToplevelWindow();
extern ClientWindow DecoratedWindow();
/* local */
extern ClientWindowEventHandler(), UpdateClientWindowGeometry();
extern ReconfigureClientWindow();
ClientWindow NewClientWindow(), NewClientWindowIcon(),
window_is_still_alive(), NewIconWindow();
extern ClientWindowOpen(), ClientWindowClose();
WOB_METHOD ClientWindowClass[] = {
0, /* METHODS_ARRAY */
WobEval,
WobPrint,
WobRelease,
WobExecute,
WobSet,
WobGetCValue,
ClientWindowOpen,
ClientWindowClose,
ClientWindowEventHandler,
(WOB_METHOD) wool_undefined_method_1,
WobGetDimensions,
(WOB_METHOD) wool_undefined_method_2,
(WOB_METHOD) wool_undefined_method_2,
ReconfigureClientWindow,
(WOB_METHOD) wool_undefined_method_2,
(WOB_METHOD) wool_undefined_method_1,
(WOB_METHOD) wool_undefined_method_1,
(WOB_METHOD) wool_undefined_method_1,
(WOB_METHOD) wool_undefined_method_1,
(WOB_METHOD) wool_undefined_method_1
};
/* routines */
/*
* To decorate a window, we must:
* - see if it is decorable
* - get all info about it
* - decorate it via NewClientWindow
*/
ClientWindow
DecorateWindow(window, parent, must_save_set, being_mapped)
Window window;
ClientWindow parent;
int must_save_set; /* 0 for screen, 1 for windows */
int being_mapped; /* 0 for decorating by reference */
{
ClientWindow cw;
WOOL_Client wl_client;
int local_zrt_size = zrt_size;
XWindowAttributes wa;
Wob oldTargetWob = TargetWob;
wa.override_redirect = 0;
/* if window has died meanwhile, abort */
if (TrapXErrors(XGetWindowAttributes(dpy, window, &wa))
|| wa.override_redirect) /* do not manage override_redirect wins */
return NULL;
/* be careful, we might have decorated it in beetween */
if(cw = (ClientWindow) LookUpClient(window))
return cw;
GWM_window_being_decorated = cw = NewClientWindow(parent, window);
{
save_wool_error_resume_point(); /* contains decls */
if (set_wool_error_resume_point()) {
restore_wool_error_resume_point();
return 0; /* aborts if window dies */
}
SetTarget(cw);
UpdateAllCachedProperties(cw); /* some preliminar get_properties */
cw -> colormap = wa.colormap; /* update attributes */
MatchWoolDescription(cw, &wl_client); /* get the descriptions */
UpdateClientWindowFields(cw, wl_client);
UpdateClientWindowGeometry(cw); /* sets bars,etc */
if (must_save_set && !(cw -> client_wob)) /* in case of GWM dying */
XChangeSaveSet(dpy, window, SetModeInsert);
ClientWindowRecordClient(cw); /* it */
ClientWindowOpen(cw, being_mapped); /* create the windows */
zrt_gc(local_zrt_size);
SetTarget(oldTargetWob);
restore_wool_error_resume_point();
return cw;
}
}
/* The icon window is realized only on the first call to "iconify-window" or
* "window-icon".
* return icon or 0 if wool error
*/
ClientWindow
RealizeIconWindow(cw)
ClientWindow cw;
{
WOOL_Client wl_icon;
ClientWindow icon;
wl_icon = (WOOL_Client)
(cw -> icon_description -> type == WLClient ? cw -> icon_description :
(WOOL_OBJECT) wool_eval_and_catch_errors(cw -> icon_description));
if (!wl_icon || wl_icon -> type != WLClient) {
ShowUndecoratedWindow(cw);
wool_print(wl_icon ? wl_icon : (WOOL_Client) NIL_STRING);
wool_newline();
wool_error("bad %s description!", "icon");
}
GWM_window_being_decorated = icon = NewIconWindow(cw);
SetTarget(icon);
icon -> cached_props = cw -> cached_props;
UpdateClientWindowFields(icon, wl_icon);
MakeIconWindow(cw); /* makes central plug */
if(icon -> client) {
ClientWindowRecordClient(icon);
if (!icon -> client_wob)
XChangeSaveSet(dpy, icon->client, SetModeInsert);
}
UpdateClientWindowGeometry(icon);
decrease_reference(cw -> icon_description);
cw -> icon_description = NULL;
UpdateClientWindowIconSize(icon);
ClientWindowOpen(icon, 1);
return icon;
}
/* Creates a wob for that new client window.
*/
ClientWindow
NewClientWindow(parent, window)
ClientWindow parent;
Window window;
{
ClientWindow cw = (ClientWindow) NewWob(sizeof(struct _ClientWindow));
cw -> parent = (Wob) parent;
cw -> screen = parent -> screen;
cw -> status = ClientWindowStatus;
cw -> client = window;
cw -> window = cw;
cw -> client_wob = LookUpWob(window);
cw -> type = ClientWindowClass;
return cw;
}
ClientWindow
NewIconWindow(cw)
ClientWindow cw;
{
ClientWindow icon =
(ClientWindow) NewWob(sizeof(struct _ClientWindow));
cw -> icon = icon;
icon -> parent = cw -> parent;
icon -> screen = cw -> screen;
icon -> window = cw;
icon -> icon = icon;
icon -> status = IconStatus;
icon -> type = ClientWindowClass;
return icon;
}
/*
* updates now the properties cached in the ClientWindow structure and icon
*/
#define CWSTR(a) (((WOOL_String)(cw -> a)) -> string)
UpdateAllCachedProperties(cw)
ClientWindow cw;
{
Window window = cw -> client;
char *machinename;
XClassHint classhints;
Atom actualtype;
int actualformat;
unsigned long nitems;
unsigned long bytesafter;
CWCachedProperties cprops = (CWCachedProperties)
Malloc(sizeof(struct _CWCachedProperties));
/* get all fixed properties */
bzero(cprops, sizeof(struct _CWCachedProperties));
cw -> cached_props = cprops;
classhints.res_name = classhints.res_class = NULL;
if(XGetWindowProperty(dpy, window, XA_WM_CLIENT_MACHINE, 0,
MAX_TEMP_STRING_SIZE,
False, XA_STRING, &actualtype, &actualformat,
&nitems, &bytesafter, (unsigned char **) &machinename))
longjmp(wool_goes_here_on_error, 1);
if (machinename) {
char *p = machinename;
while(*p) { /* truncates to first dot field */
if (*p == '.') {
*p = '\0';
break;
}
p++;
}
increase_reference(cprops -> machinename = (WOOL_OBJECT)
WLString_make(machinename));
XFree(machinename);
} else
increase_reference(cprops -> machinename = (WOOL_OBJECT)
DefaultMachineName);
XGetClassHint(dpy, window, &classhints);
increase_reference(cprops -> clientclass = (classhints.res_class ?
(WOOL_OBJECT) WLString_make(classhints.res_class)
: (WOOL_OBJECT) DefaultClientClass));
increase_reference(cprops -> clientname = (classhints.res_name ?
(WOOL_OBJECT) WLString_make(classhints.res_name)
: (WOOL_OBJECT) DefaultClientName));
if (classhints.res_name)
XFree(classhints.res_name);
if (classhints.res_class)
XFree(classhints.res_class);
/* update all variable props */
Update_XA_WM_NAME(cw);
Update_XA_WM_ICON_NAME(cw);
Update_XA_WM_HINTS(cw);
Update_XA_WM_NORMAL_HINTS(cw);
Update_XA_WM_TRANSIENT_FOR(cw);
Update_XA_WM_COLORMAP_WINDOWS(cw);
Update_XA_WM_PROTOCOLS(cw);
GetPreviousWM_STATE(cw); /* get the previous WM_STATE if any */
UpdateClientWindowSize(cw); /* check window real size */
}
/*
* update ONE property
* cw MUST be a window, not an icon
*/
UpdateCachedProperty(cw, property_atom)
ClientWindow cw;
Atom property_atom;
{
switch (property_atom) { /* predefined atoms */
case XA_WM_NAME:
Update_XA_WM_NAME(cw);
break;
case XA_WM_ICON_NAME:
Update_XA_WM_ICON_NAME(cw);
break;
case XA_WM_HINTS:
Update_XA_WM_HINTS(cw);
break;
case XA_WM_NORMAL_HINTS:
Update_XA_WM_NORMAL_HINTS(cw);
break;
case XA_WM_TRANSIENT_FOR:
Update_XA_WM_TRANSIENT_FOR(cw);
break;
default: /* non-predefined props */
if (property_atom == XA_WM_COLORMAP_WINDOWS)
Update_XA_WM_COLORMAP_WINDOWS(cw);
else if (property_atom == XA_WM_PROTOCOLS)
Update_XA_WM_PROTOCOLS(cw);
}
}
/* individual methods to update or create cached properties
*/
#if defined(X11R1)||defined(X11R2)||defined(X11R3)||defined(X11R4)||defined(X11R5)
Update_XA_WM_NAME(cw)
ClientWindow cw;
{
char *name = 0;
XFetchName(dpy, cw -> client, &(name));
decrease_reference(cw -> cached_props -> windowname);
if (!(name) || (*(name) == '\0'))
increase_reference(cw -> cached_props -> windowname = (WOOL_OBJECT)
DefaultWindowName);
else {
increase_reference(cw -> cached_props -> windowname = (WOOL_OBJECT)
WLString_make(name));
XFree(name);
}
}
Update_XA_WM_ICON_NAME(cw)
ClientWindow cw;
{
char *name = 0;
XGetIconName(dpy, cw -> client, &name);
if (cw -> cached_props -> iconname) {
decrease_reference(cw -> cached_props -> iconname);
}
if (!(name) || (*(name) == '\0')) {
increase_reference(cw -> cached_props -> iconname = (WOOL_OBJECT)
DefaultIconName);
} else {
increase_reference(cw -> cached_props -> iconname = (WOOL_OBJECT)
WLString_make(name));
XFree(name);
}
}
#else /* X11R6 or later */
Update_XA_WM_NAME(cw)
ClientWindow cw;
{
char *name = 0;
XTextProperty text_prop;
char **list_return = 0;
int count_return;
if (! XGetWMName(dpy, cw -> client, &text_prop));
else {
/* incantation from twm/add_window.c */
if (text_prop.value) text_prop.nitems =
strlen((char *)text_prop.value);
if ( XmbTextPropertyToTextList(
dpy,
&text_prop,
&list_return,
&count_return) < Success);
else {
if (!list_return || !(*list_return));
else name = *list_return;
}
}
decrease_reference(cw -> cached_props -> windowname);
if (!(name) || (*(name) == '\0'))
increase_reference(cw -> cached_props -> windowname = (WOOL_OBJECT)
DefaultWindowName);
else {
increase_reference(cw -> cached_props -> windowname = (WOOL_OBJECT)
WLString_make(name));
}
if (list_return) XFreeStringList(list_return);
}
Update_XA_WM_ICON_NAME(cw)
ClientWindow cw;
{
char *name = 0;
XTextProperty text_prop;
char **list_return = 0;
int count_return;
if (! XGetWMIconName(dpy, cw -> client, &text_prop));
else {
/* incantation from twm/add_window.c */
if (text_prop.value) text_prop.nitems =
strlen((char *)text_prop.value);
if ( XmbTextPropertyToTextList(
dpy,
&text_prop,
&list_return,
&count_return) < Success);
else {
if (!list_return || !(*list_return));
else name = *list_return;
}
}
if (cw -> cached_props -> iconname) {
decrease_reference(cw -> cached_props -> iconname);
}
if (!(name) || (*(name) == '\0')) {
increase_reference(cw -> cached_props -> iconname = (WOOL_OBJECT)
DefaultIconName);
} else {
increase_reference(cw -> cached_props -> iconname = (WOOL_OBJECT)
WLString_make(name));
}
if (list_return) XFreeStringList(list_return);
}
#endif /* X11R6 or later */
Update_XA_WM_HINTS(cw)
ClientWindow cw;
{
XWMHints *windowhints, *wm_hints;
ClientWindow group_leader;
if (windowhints = XGetWMHints(dpy, cw -> client)) {
if (GWM_backup_old_property)
bcopy(&(cw -> cached_props -> wm_hints),
&GWM_backup_of_old_property, sizeof(XWMHints));
bcopy(windowhints, wm_hints = &(cw -> cached_props -> wm_hints),
sizeof(XWMHints));
/* window groups */
if ((windowhints -> flags & WindowGroupHint)
&& windowhints -> window_group
&& (cw -> status & ClientWindowStatus)) {
if (windowhints -> window_group == cw->client)
AddWindowToGroupLeader(cw, cw);
else if (group_leader =
DecoratedWindow(windowhints -> window_group)) {
if (group_leader -> status & ClientWindowStatus)
AddWindowToGroupLeader(cw, group_leader);
}
}
/* check validity of hints */
if (wm_hints->flags & IconWindowHint && !(wm_hints->icon_window))
wm_hints->flags &= ~IconWindowHint;
if (wm_hints->flags & IconPixmapHint && !(wm_hints->icon_pixmap))
wm_hints->flags &= ~IconPixmapHint;
if (wm_hints->flags & IconMaskHint && !(wm_hints->icon_mask))
wm_hints->flags &= ~IconMaskHint;
XFree(windowhints);
}
}
Update_XA_WM_NORMAL_HINTS(cw)
ClientWindow cw;
{
long supplied = 0;
#ifdef NOBASEDIMS
if (!XGetNormalHints(dpy, cw -> client,
&(cw -> cached_props -> normal_hints))) {
cw -> cached_props -> normal_hints.flags = 0;
}
#else /* NOBASEDIMS */
if (!XGetWMNormalHints(dpy, cw -> client,
&(cw -> cached_props -> normal_hints),
&supplied)) {
cw -> cached_props -> normal_hints.flags = 0;
}
if (supplied & PBaseSize) {
supplied = 1;
} else {
supplied = 0;
}
#endif /* NOBASEDIMS */
cw -> cached_props -> new_normal_hints = supplied;
CheckConsistency(&(cw -> cached_props -> normal_hints));
}
Update_XA_WM_TRANSIENT_FOR(cw)
ClientWindow cw;
{
ClientWindow main_cw;
Window transient_for;
decrease_reference(cw -> cached_props -> transient_for);
XSync(dpy, 0);
XSetErrorHandler(NoXError);
ErrorStatus = 0;
XGetTransientForHint(dpy, cw -> client, &transient_for);
XSync(dpy, 0);
XSetErrorHandler(XError);
if (ErrorStatus)
longjmp(wool_goes_here_on_error, 1); /* problem appeared */
if (transient_for) {
if (transient_for != Context -> root
&& transient_for != cw -> client
&& (main_cw = DecoratedWindow(transient_for))) {
increase_reference(cw -> cached_props -> transient_for =
(WOOL_OBJECT) WLNumber_make(main_cw));
} else {
cw -> cached_props -> transient_for = 0;
}
} else {
cw -> cached_props -> transient_for = 0;
}
}
Update_XA_WM_COLORMAP_WINDOWS(cw)
ClientWindow cw;
{
Atom actualtype;
int actualformat;
unsigned long nitems;
unsigned long bytesafter;
Window *colormap_windows = NULL, *old_colormap_windows;
int result, i;
result = GwmSilentXGetWindowProperty(dpy, cw -> client,
XA_WM_COLORMAP_WINDOWS, 0, WM_COLORMAP_WINDOWS_PROP_Length,
False, XA_WM_COLORMAP_WINDOWS, &actualtype,
&actualformat, &nitems, &bytesafter, &colormap_windows);
if(result == Success && nitems &&
actualtype != None && actualformat == 32){
old_colormap_windows = cw -> cached_props -> colormap_windows;
cw -> cached_props -> colormap_windows =
(Window *) Malloc ((nitems+1) * sizeof (Window));
cw -> cached_props -> colormap_windows_size = 1;
cw -> cached_props -> colormap_windows[0] = cw -> client;
for(i = 0; i< nitems; i++)
if(colormap_windows[i] != cw -> client
&& !LookUpClient(colormap_windows[i])) {
cw -> cached_props -> colormap_windows[
cw -> cached_props -> colormap_windows_size++] =
colormap_windows[i];
if (colormap_windows[i] != cw -> client) {
XSelectInput(dpy, colormap_windows[i], ColormapChangeMask);
}
}
if(cw -> cached_props -> colormap_windows_size == 1){
Free(cw -> cached_props -> colormap_windows);
cw -> cached_props -> colormap_windows_size = 0;
} else {
if (Context -> InstalledColormapCW == cw)
XInstallColormap(dpy,
cw -> cached_props -> colormap_windows[0]);
}
cw -> cached_props -> colormap_windows_index = 0;
if(old_colormap_windows)
Free(old_colormap_windows);
}
if(colormap_windows && result == Success)
XFree(colormap_windows);
}
Update_XA_WM_PROTOCOLS(cw)
ClientWindow cw;
{
Atom actualtype;
int actualformat;
unsigned long nitems;
unsigned long bytesafter;
Window *protocols = NULL;
int result, i;
result = GwmSilentXGetWindowProperty(dpy, cw -> client,
XA_WM_PROTOCOLS, 0, WM_PROTOCOLS_PROP_Length,
False, XA_ATOM, &actualtype,
&actualformat, &nitems, &bytesafter, &protocols);
if (result == Success && nitems &&
actualtype != None && actualformat == 32) {
cw -> cached_props -> wm_take_focus = 0;
cw -> cached_props -> wm_save_yourself = 0;
cw -> cached_props -> wm_delete_window = 0;
for (i = 0; i < nitems; i++) {
if ((protocols[i] == XA_WM_TAKE_FOCUS)
&& !(cw -> ignore_take_focus))
cw -> cached_props -> wm_take_focus = 1;
else if (protocols[i] == XA_WM_SAVE_YOURSELF)
cw -> cached_props -> wm_save_yourself = 1;
else if (protocols[i] == XA_WM_DELETE_WINDOW)
cw -> cached_props -> wm_delete_window = 1;
}
}
if (protocols && result == Success)
XFree(protocols);
}
/*
* release their storage
*/
FreeCachedProperties(cprops)
CWCachedProperties cprops;
{
int local_zrt_size = zrt_size;
decrease_reference(cprops -> machinename);
decrease_reference(cprops -> clientclass);
decrease_reference(cprops -> clientname);
decrease_reference(cprops -> windowname);
decrease_reference(cprops -> iconname);
decrease_reference(cprops -> transient_for);
DelayedFree(cprops);
zrt_gc(local_zrt_size);
}
void
Set_XA_WM_STATE(cw, state)
ClientWindow cw;
int state;
{
struct _WM_STATE_PROP wm_state;
int trap_x_errors = 0;
if (state == -1) {
if (cw -> mapped)
wm_state.state = WM_STATE_Normal;
else if ((cw -> icon && cw -> icon -> mapped)
|| (cw -> cached_props -> user_icon &&
cw -> cached_props -> user_icon -> mapped))
wm_state.state = WM_STATE_Iconified;
else {
wm_state.state = WM_STATE_Withdrawn;
trap_x_errors = 1;
}
}
else {
wm_state.state = state;
if (state == WM_STATE_Withdrawn)
trap_x_errors = 1;
}
if (wm_state.state != cw -> cached_props -> wm_state) {
cw -> cached_props -> wm_state = wm_state.state;
wm_state.icon = (cw -> icon ?
cw -> icon -> hook :
(cw -> cached_props -> user_icon ?
cw -> cached_props -> user_icon -> hook : 0));
if (trap_x_errors)
XSetErrorHandler(NoXError);
XChangeProperty(dpy, cw -> client, XA_WM_STATE, XA_WM_STATE,
32, PropModeReplace, (unsigned char *)&wm_state, WM_STATE_PROP_Length);
if (trap_x_errors) {
XSync(dpy, 0);
XSetErrorHandler(XError);
}
}
}
/* Updating WM_STATE is setting it on the window
* returns state
*/
int
Update_XA_WM_STATE(cw)
ClientWindow cw;
{
cw = cw -> window;
if (!(cw -> client_wob || cw -> cached_props -> user_icon)) {
Set_XA_WM_STATE(cw, -1);
return cw -> cached_props -> wm_state;
} else
return WM_STATE_Normal;
}
/* first time a window is mapped, decode the WM_STATE from previous wm
*/
GetPreviousWM_STATE(cw)
ClientWindow cw;
{
Atom actualtype;
int actualformat;
unsigned long nitems;
unsigned long bytesafter;
WM_STATE_PROP wm_state;
if (GWM_ProcessingExistingWindows
&&
Success == XGetWindowProperty(dpy, cw -> client, XA_WM_STATE, 0,
WM_STATE_PROP_Length, False,
XA_WM_STATE, &actualtype,
&actualformat, &nitems, &bytesafter,
(unsigned char **)&wm_state)
&& nitems && wm_state) {
cw -> cached_props -> wm_hints.flags |= StateHint;
cw -> cached_props -> wm_hints.initial_state = wm_state -> state;
XFree(wm_state);
}
}
/*
* copies information from descriptor to client
*/
UpdateClientWindowBar(parent, field, wl_bar, dir)
ClientWindow parent;
Bar *field;
WOOL_Bar wl_bar;
int dir;
{
wl_bar = (WOOL_Bar) wool_type_or_evaluate(wl_bar, WLBar);
if (wl_bar == (WOOL_Bar) NIL)
*field = NULL;
else {
*field = NewBar(parent, wl_bar, dir);
}
}
UpdateClientWindowFields(cw, wl_client)
ClientWindow cw;
WOOL_Client wl_client;
{
cw -> inner_borderwidth = wl_client -> inner_borderwidth;
cw -> box.borderwidth = wl_client -> borderwidth;
cw -> box.borderpixel = wl_client -> borderpixel;
cw -> box.background = wl_client -> background;
UpdateClientWindowBar(cw, &(cw -> titlebar), wl_client -> titlebar,
HORIZONTAL);
UpdateClientWindowBar(cw, &(cw -> leftbar), wl_client -> leftbar,
VERTICAL);
UpdateClientWindowBar(cw, &(cw -> rightbar), wl_client -> rightbar,
VERTICAL);
UpdateClientWindowBar(cw, &(cw -> basebar), wl_client -> basebar,
HORIZONTAL);
increase_reference(cw -> cursor =
wool_type_or_evaluate(wl_client -> cursor, WLCursor));
increase_reference(cw -> bordertile =
wool_type_or_evaluate(wl_client -> bordertile, WLPixmap));
increase_reference(cw -> fsm =
wool_type_or_evaluate(wl_client -> fsm, WLFsm));
increase_reference(cw -> menu =
wool_type_or_evaluate(wl_client -> menu, WLMenu));
increase_reference(cw -> property = (WOOL_OBJECT) wl_client -> property);
increase_reference(cw -> opening = (WOOL_OBJECT) wl_client -> opening);
increase_reference(cw -> closing = (WOOL_OBJECT) wl_client -> closing);
increase_reference(cw -> grabs = (WOOL_OBJECT) wl_client -> grabs);
increase_reference(cw -> icon_plug =
(WOOL_OBJECT) wl_client -> icon_plug);
cw -> map_on_raise = wl_client -> map_on_raise;
cw -> ignore_take_focus = wl_client -> map_on_raise;
}
/*
* here we create or get the XWindow to put in the icon -> client field
*/
MakeIconWindow(cw)
ClientWindow cw;
{
WOOL_Plug wl_plug = (WOOL_Plug) cw -> icon -> icon_plug;
Plug plug;
wl_plug = (WOOL_Plug) WOOL_send(WOOL_eval, wl_plug, (wl_plug));
if (wl_plug -> type == WLNumber) { /* icon window managed by client */
cw -> icon -> client = (Window)
((WOOL_Number) wl_plug) -> number;
} else if (wl_plug -> type == WLPlug) { /* icon field is plug */
plug = (Plug) NewPlug(Context->rootWob, wl_plug);
UpdatePlugGeometry(plug);
PlugOpen(plug);
cw -> icon -> client = plug -> hook;
cw -> icon -> client_wob = (Wob) plug;
}
}
/*
* we set here the size of the cw before calling MatchWool, for dims queries
*/
UpdateClientWindowSize(cw)
ClientWindow cw;
{
Window root;
unsigned int depth, width, height;
int must_resize = 0;
if (!XGetGeometry(dpy, cw -> client, &root,
&(cw -> box.x), &(cw -> box.y),
&(cw -> box.width), &(cw -> box.height),
&(cw -> box.borderwidth), &depth))
longjmp(wool_goes_here_on_error, 1);
/* update cw fields */
cw -> inner_width = cw -> box.width;
cw -> inner_height = cw -> box.height;
cw -> old_inner_borderwidth = cw -> inner_borderwidth
= cw -> box.borderwidth;
/* update the size according to hints */
if (!GWM_ProcessingExistingWindows) {
if(!cw -> cached_props -> new_normal_hints) {
if (cw -> cached_props -> normal_hints.flags & USSize) {
if (cw -> inner_width != cw -> cached_props ->
normal_hints.width) {
must_resize = 1;
cw -> inner_width = cw -> cached_props ->
normal_hints.width;
}
if (cw -> inner_height != cw -> cached_props ->
normal_hints.height) {
must_resize = 1;
cw -> inner_height = cw -> cached_props ->
normal_hints.height;
}
} else if (cw -> cached_props -> normal_hints.flags & PSize) {
if (cw -> inner_width != cw -> cached_props ->
normal_hints.width && cw -> inner_width > 1) {
must_resize = 1;
cw -> inner_width = cw -> cached_props ->
normal_hints.width;
}
if (cw -> inner_height != cw -> cached_props ->
normal_hints.height && cw -> inner_height > 1) {
must_resize = 1;
cw -> inner_height = cw -> cached_props ->
normal_hints.height;
}
}
} else {
width = cw -> inner_width;
height = cw -> inner_height;
conform_to_hints(&(cw -> cached_props -> normal_hints),
&width, &height);
if ((cw -> inner_width != width) ||
(cw -> inner_height != height)) {
must_resize = 1;
cw -> inner_width = width;
cw -> inner_height = height;
}
}
}
if (must_resize)
XResizeWindow(dpy, cw -> client,
cw -> inner_width, cw -> inner_height);
}
/* before opening an icon, place it according to hints
*/
UpdateClientWindowIconSize(icon)
ClientWindow icon;
{
if (icon -> cached_props -> wm_hints.flags & IconPositionHint) {
icon -> box.x = icon -> cached_props -> wm_hints.icon_x;
icon -> box.y = icon -> cached_props -> wm_hints.icon_y;
}
}
/*
* Here we add physically all the gadgets around a client window.
* A new window is opened. (First Map Request, called from SetUpClient.)
* The description of the window to be created is in setup.
* Create the surrounding window.
* Set up window geometry, bars, plugs if any,
* reparent the client window.
*/
ClientWindowOpen(cw, being_mapped)
ClientWindow cw;
int being_mapped;
{
check_window_size(cw);
/* create the WOB windows, and map them */
cw -> curstate = (int) WOOL_send(WOOL_open, cw -> fsm, (cw -> fsm));
ObeyWinGravityHint(cw, 1); /* sets reparenting offsets */
{
XSetWindowAttributes xsw;
xsw.background_pixmap = None;
xsw.border_pixel = cw->box.borderpixel;
xsw.backing_store = NotUseful;
xsw.save_under = NotUseful;
cw -> hook =
XCreateWindow(dpy, Context -> root, cw -> box.x, cw -> box.y,
cw -> box.width, cw -> box.height,
cw -> box.borderwidth, CopyFromParent,
CopyFromParent, CopyFromParent,
CWBackPixmap | CWBorderPixel | CWBackingStore |
CWSaveUnder, &xsw);
}
cw -> status |= TopLevelXWindowStatus;
WobRecordHook(cw);
BarOpen(cw -> titlebar);
BarOpen(cw -> leftbar);
BarOpen(cw -> rightbar);
BarOpen(cw -> basebar);
if (cw -> cursor != NIL)
XDefineCursor(dpy, cw -> hook,
((WOOL_Cursor) cw -> cursor) -> cursor);
if (cw -> bordertile != NIL)
XSetWindowBorderPixmap(dpy, cw -> hook,
((WOOL_Pixmap) cw -> bordertile) -> pixmap);
/* put window in window list */
Context -> WindowCount++;
if (Context -> rootWob -> next)
Context -> rootWob -> next -> previous = cw;
cw -> next = Context -> rootWob -> next;
Context -> rootWob -> next = cw;
cw -> previous = Context -> rootWob;
#ifdef SHAPE
/* if we decorate a shaped window, reshape ourselves */
if (WindowIsShaped(cw))
ClientWindowSetShape(cw);
#endif /* SHAPE */
if (cw -> client) { /* Replace client Window */
unsigned int client_height, client_width, client_borderwidth;
int dummy;
XUnmapWindow(dpy, cw -> client);
XSetWindowBorderWidth(dpy, cw -> client, cw -> inner_borderwidth);
if (cw -> client_wob) {
cw -> client_wob -> parent = (Wob) cw;
cw -> client_wob -> status &= ~TopLevelXWindowStatus;
cw -> client_wob -> input_mask |= ClientClientMask;
XSelectInput(dpy, cw -> client, cw -> client_wob -> input_mask);
} else {
XSelectInput(dpy, cw -> client, ClientClientMask);
}
if (TrapXErrors(XReparentWindow(dpy, cw -> client, cw -> hook,
cw -> inner_x, cw -> inner_y))) {
cw -> client = 0;
ClientWindowClose(cw);
SetTarget(Context->rootWob);
return;
}
/* check if window hasn't been resized since deco */
if (!XGetGeometry(dpy, cw -> client,
(Window *)&dummy, &dummy, &dummy, &client_width,
&client_height, &client_borderwidth, (unsigned int *)&dummy))
longjmp(wool_goes_here_on_error, 1);
if (client_height != cw -> inner_height
|| client_width != cw -> inner_width
|| client_borderwidth != cw -> inner_borderwidth)
ReconfigureClientWindow(cw, cw -> client);
else
SendSyntheticMoveEvent(cw);
}
XSelectInput(dpy, cw -> hook, ClientMask |
((WOOL_Fsm) cw -> fsm) -> mask);
/* set global grabs */
WLClient_set_grabs(cw -> grabs, cw -> hook);
XSync(dpy, 0);
if (!GWM_window_being_decorated) { /* error while decorating? abort! */
SetTarget(Context->rootWob);
return;
}
GWM_window_being_decorated = 0;
/* process pending events */
if (!GWM_ProcessingExistingWindows && GWM_reenter_on_opens)
GWM_ProcessEvents(0);
/* execute "opening" WOOL code */
if (being_mapped && WobIsValid(cw)) {
ClientWindowExecuteOpening(cw);
}
}
ClientWindowExecuteOpening(cw)
ClientWindow cw;
{
int local_zrt_size = zrt_size;
if (cw -> opening) {
SetTarget(cw);
GWM_Window_being_opened = cw;
wool_eval_and_catch_errors_proc(cw -> opening);
GWM_Window_being_opened = 0;
decrease_reference(cw -> opening);
cw -> opening = NULL;
}
SetTarget(cw);
zrt_gc(local_zrt_size);
}
/*
* Take a client window, recursivly set geometry by the sons, and then
* set the bars geometry
*/
UpdateClientWindowGeometry(cw)
ClientWindow cw;
{
UpdateBarWidth(cw -> titlebar);
UpdateBarWidth(cw -> leftbar);
UpdateBarWidth(cw -> rightbar);
UpdateBarWidth(cw -> basebar);
ClientWindowComputeGeometry(cw);
ClientWindowComputeBarDims(cw);
UpdateBarLength(cw -> titlebar);
UpdateBarLength(cw -> leftbar);
UpdateBarLength(cw -> rightbar);
UpdateBarLength(cw -> basebar);
}
ClientWindowComputeGeometry(cw)
ClientWindow cw;
{
Window root;
int client_x, client_y;
unsigned int client_width, client_height;
unsigned int client_borderwidth, client_depth;
if (cw -> client) {
if (!XGetGeometry(dpy, cw -> client,
&root, &client_x, &client_y, &client_width, &client_height,
&client_borderwidth, &client_depth))
longjmp(wool_goes_here_on_error, 1);
#ifdef SHAPE
/* if we decorate a shaped window, do not touch borderwidth */
if (GWM_ShapeExtension) {
int xws, yws, xbs, ybs;
unsigned int wws, hws, wbs, hbs;
int boundingShaped, clipShaped;
XShapeSelectInput (dpy, cw -> client, True);
if (XShapeQueryExtents (dpy, cw -> client,
&boundingShaped, &xws, &yws, &wws, &hws,
&clipShaped, &xbs, &ybs, &wbs, &hbs)
&&boundingShaped) {
cw -> client_shaped = 1;
cw -> inner_borderwidth = 0;
}
}
#endif /* SHAPE */
cw -> old_inner_borderwidth = client_borderwidth;
if (cw -> inner_borderwidth == ((short) ANY))
cw -> inner_borderwidth = client_borderwidth;
else
client_borderwidth = cw -> inner_borderwidth;
cw -> inner_width = client_width;
cw -> inner_height = client_height;
} else {
NaturalBarLength(cw -> titlebar);
NaturalBarLength(cw -> leftbar);
NaturalBarLength(cw -> rightbar);
NaturalBarLength(cw -> basebar);
cw -> inner_borderwidth = 0;
if (cw -> leftbar || cw -> rightbar) {
cw -> inner_width = 0;
cw -> inner_height =
Max((cw -> leftbar ? cw -> leftbar -> box.height : 0),
(cw -> rightbar ? cw -> rightbar -> box.height : 0));
} else {
cw -> inner_height = 0;
cw -> inner_width =
Max((cw -> titlebar ? cw -> titlebar -> box.width : 0),
(cw -> basebar ? cw -> basebar -> box.width : 0));
}
}
}
ClientWindowComputeBarDims(cw)
ClientWindow cw;
{
int titleheight, baseheight, leftwidth, rightwidth;
cw -> box.width = cw -> inner_width + 2 * cw -> inner_borderwidth;
cw -> box.height = cw -> inner_height + 2 * cw -> inner_borderwidth;
/* Special hack */
if ((cw -> leftbar && cw -> leftbar -> ewidth) ||
(cw -> rightbar && cw -> rightbar -> ewidth)) {
int len;
UpdateBarWidth(cw -> leftbar);
UpdateBarWidth(cw -> rightbar);
len = Max(NaturalBarLength(cw -> titlebar),
NaturalBarLength(cw -> basebar));
len = len - cw -> inner_width -
(cw -> leftbar ? cw -> leftbar -> box.width
+ 2 * cw -> leftbar -> box.borderwidth : 0) -
(cw -> rightbar ? cw -> rightbar -> box.width
+ 2 * cw -> rightbar -> box.borderwidth : 0);
if (len < 0) len = 0;
if (!cw -> leftbar || !cw -> leftbar -> ewidth)
cw -> rightbar -> box.width += len;
else if (!cw -> rightbar || !cw -> rightbar -> ewidth)
cw -> leftbar -> box.width += len;
else {
int llen = len / 2, rlen = len - llen;
cw -> leftbar -> box.width += llen;
cw -> rightbar -> box.width += rlen;
}
}
titleheight = (cw -> titlebar ? cw -> titlebar -> box.height
+ 2 * cw -> titlebar -> box.borderwidth : 0);
baseheight = (cw -> basebar ? cw -> basebar -> box.height
+ 2 * cw -> basebar -> box.borderwidth : 0);
leftwidth = (cw -> leftbar ? cw -> leftbar -> box.width
+ 2 * cw -> leftbar -> box.borderwidth : 0);
rightwidth = (cw -> rightbar ? cw -> rightbar -> box.width
+ 2 * cw -> rightbar -> box.borderwidth : 0);
/* sets the dimensions of the box itself */
cw -> inner_x = leftwidth;
cw -> inner_y = titleheight;
cw -> box.width += leftwidth + rightwidth;
cw -> box.height += titleheight + baseheight;
/* set the titlebar (height and borderwidth are already set) */
if(cw -> titlebar) {
cw -> titlebar -> box.x = 0;
cw -> titlebar -> box.y = 0;
cw -> titlebar -> box.width =
cw -> box.width - 2 * cw -> titlebar -> box.borderwidth;
}
/* set the leftbar (width and borderwidth are already set) */
if(cw -> leftbar) {
cw -> leftbar -> box.x = 0;
cw -> leftbar -> box.y = titleheight;
cw -> leftbar -> box.height = cw -> box.height
- titleheight - baseheight
- 2 * cw -> leftbar -> box.borderwidth;
}
/* set the rightbar (width and borderwidth are already set) */
if(cw -> rightbar) {
cw -> rightbar -> box.x = cw -> box.width
- 2 * cw -> rightbar -> box.borderwidth
- cw -> rightbar -> box.width;
cw -> rightbar -> box.y = titleheight;
cw -> rightbar -> box.height = cw -> box.height
- titleheight - baseheight
- 2 * cw -> rightbar -> box.borderwidth;
}
/* set the basebar (height and borderwidth are already set) */
if(cw -> basebar) {
cw -> basebar -> box.x = 0;
cw -> basebar -> box.y = cw -> box.height - baseheight;
cw -> basebar -> box.width =
cw -> box.width - 2 * cw -> basebar -> box.borderwidth;
}
}
/* destroys all data concerning the window
* suppose that the client window is already destroyed, so we do not need to
* destroy it ourselves
*/
ClientWindowClose(cw)
ClientWindow cw;
{
int closeflag;
ClientWindow icon = cw -> icon;
CWCachedProperties cprops = cw -> cached_props;
if (cprops -> client_group)
RemoveWindowFromGroup(cw);
if (Context -> InstalledColormapCW == cw)
Context -> InstalledColormapCW = 0;
closeflag = ClientWindowClose_aux(cw -> window);
if (icon)
ClientWindowClose_aux(icon);
if (closeflag)
FreeCachedProperties(cprops);
if (TargetWindow == cw || TargetWindow == icon)
SetTarget(Context -> rootWob);
}
int
ClientWindowClose_aux(cw)
ClientWindow cw;
{
int local_zrt_size = zrt_size;
WOOL_OBJECT closing;
if (cw -> closing) { /* Otherwise this is already done */
SetTarget(cw);
closing = cw -> closing;
cw -> closing = 0;
if (!(GWM_is_ending || GWM_is_restarting))
wool_eval_and_catch_errors_proc(closing);
if (cw->client_wob)
WOOL_send(WOOL_close, cw->client_wob, (cw->client_wob));
BarClose(cw -> titlebar);
BarClose(cw -> leftbar);
BarClose(cw -> rightbar);
BarClose(cw -> basebar);
decrease_reference(cw -> opening);
decrease_reference(closing);
decrease_reference(cw -> grabs);
decrease_reference(cw -> icon_plug);
decrease_reference(cw -> icon_description);
/* remove from list */
if (cw -> previous) {
Context -> WindowCount--;
cw -> previous -> next = cw -> next;
if (cw -> next)
cw -> next -> previous = cw -> previous;
}
if (cw -> client)
XDeleteContext(dpy, cw -> client, client_context);
WobRelease(cw);
zrt_gc(local_zrt_size);
return 1;
}
return 0;
}
ClientWindowMap(cw)
ClientWindow cw;
{
if (cw && !(cw -> mapped)) {
if (cw -> client)
XMapWindow(dpy, cw -> client);
XMapWindow(dpy, cw -> hook);
cw -> mapped = 1;
Update_XA_WM_STATE(cw);
}
return;
}
ClientWindowUnmap(cw)
ClientWindow cw;
{
if (cw && cw -> mapped) {
XUnmapWindow(dpy, cw -> hook);
if (cw -> client && !cw -> client_wob)
XUnmapWindow(dpy, cw -> client);
cw -> mapped = 0;
Update_XA_WM_STATE(cw);
}
return;
}
ClientWindowInitialMap(cw)
ClientWindow cw;
{
int mapping = 1;
if (!cw || cw -> status & IconStatus)
return;
if (cw -> cached_props -> wm_hints.flags & StateHint) {
switch (cw -> cached_props -> wm_hints.initial_state) {
case WM_STATE_Iconified:
{
int local_zrt_size = zrt_size;
WOOL_OBJECT res;
if (TargetWindow != cw)
SetTarget(cw);
res = (WOOL_OBJECT)
wool_eval_and_catch_errors(WL_iconify_window_call);
zrt_gc(local_zrt_size);
mapping = res ? 0 : 1; /* map in case of errors */
}
break;
case WM_STATE_Withdrawn: /* ERROR! buggy clients */
/* we map, ignoring the bogus hint but printing a warning */
wool_warning1("GWM: window %s has a bogus hint WM_STATE_Withdrawn as its initial_map field in its WM_HINTS property!\n",
((WOOL_String) (cw -> cached_props -> windowname))
-> string);
break;
}
}
if (mapping) {
XMapWindow(dpy, cw -> hook);
cw -> mapped = 1;
if (cw -> client)
XMapWindow(dpy, cw -> client);
}
Update_XA_WM_STATE(cw);
}
int
Mapped(w)
Window w;
{
XWindowAttributes wa;
if (TrapXErrors(XGetWindowAttributes(dpy, w, &wa)))
return 0;
else
return (wa.map_state != IsUnmapped);
}
/* to make a window appear, we may have to de-iconify it*/
ShowClientWindow(cw)
ClientWindow cw;
{
if (!(cw->opening)) {
if(!(cw->mapped) &&
!(cw->status & IconStatus)) { /* client is mapping its window */
if (cw->icon) {
SetTarget(cw->icon);
{
int local_zrt_size = zrt_size;
WOOL_send(WOOL_eval, WL_iconify_window_call,
(WL_iconify_window_call));
zrt_gc(local_zrt_size);
}
} else {
XMapWindow(dpy, cw->hook);
cw->mapped = 1;
Update_XA_WM_STATE(cw);
}
}
} else { /* initial map */
ClientWindowExecuteOpening(cw);
ClientWindowInitialMap(cw);
}
}
ClientWindowEventHandler(cw, evt)
ClientWindow cw;
Event evt;
{
switch (evt -> type) {
case MapNotify: /* hook is mapped and were waiting for it */
if (evt -> xmap.window == cw -> hook
&& ((WOOL_Fsm) cw -> fsm) -> mask & StructureNotifyMask) {
WLFsm_action(cw -> fsm, cw, evt);
}
break;
case MapRequest:
XMapWindow(dpy, cw -> client);
ShowClientWindow(cw);
break;
/*
case UnmapNotify:
if (evt -> xunmap.window == cw -> client
&& cw -> mapped) {
XUnmapWindow(dpy, cw -> hook);
cw -> mapped = 0;
Update_XA_WM_STATE(cw);
}
break;
*/
case UnmapNotify: /* Withdraw the window */
if (evt -> xunmap.window == cw -> client
&& cw -> mapped) {
if (cw->icon)
ClientWindowUnmap(cw->icon);
ClientWindowUnmap(cw);
cw->cached_props->user_icon = 0;
UnDecorateWindow(cw, 1, 0);
}
break;
case ConfigureNotify:
if (evt -> xconfigure.window == cw -> client
&& evt -> xconfigure.event == cw -> hook
&& ((WOOL_Fsm) cw -> fsm) -> mask & SubstructureNotifyMask) {
WLFsm_action(cw -> fsm, cw, evt);
}
break;
case ConfigureRequest:
ConfigureRequestEventHandler(cw, evt);
break;
case DestroyNotify:
if (evt -> xdestroywindow.window == cw -> client
&& evt -> xdestroywindow.event == cw -> client) {
ClientWindowClose(cw);
}
break;
case ColormapNotify: /* if is the active one, re-install */
if (evt -> xcolormap.new) {
Colormap old_colormap = cw -> colormap;
SetTarget(cw);
cw -> colormap = evt -> xcolormap.colormap;
if (Context -> InstalledColormapCW == cw)
if (cw -> colormap)
XInstallColormap(dpy, cw -> colormap);
else if (old_colormap)
XInstallColormap(dpy, Context -> rootWob -> colormap);
} /* else install/uninstall result */
break;
case GWMUserEvent:
WLFsm_action(cw -> fsm, cw, evt);
if (GWM_Propagate_user_events) {
if (cw -> client_wob)
WOOL_send(WOOL_process_event, cw -> client_wob,
(cw -> client_wob, evt));
if (cw -> titlebar)
WOOL_send(WOOL_process_event, cw -> titlebar,
(cw -> titlebar, evt));
if (cw -> leftbar)
WOOL_send(WOOL_process_event, cw -> leftbar,
(cw -> leftbar, evt));
if (cw -> rightbar)
WOOL_send(WOOL_process_event, cw -> rightbar,
(cw -> rightbar, evt));
if (cw -> basebar)
WOOL_send(WOOL_process_event, cw -> basebar,
(cw -> basebar, evt));
}
break;
case ClientMessage: /* iccc: for iconifying window */
SetTarget(cw);
if (evt -> xclient.message_type == XA_WM_CHANGE_STATE
&& evt -> xclient.data.l[0] == IconicState) {
int local_zrt_size = zrt_size;
WOOL_send(WOOL_eval, WL_iconify_window_call,
(WL_iconify_window_call));
zrt_gc(local_zrt_size);
/* iccc: for deleting window */
} else if (evt -> xclient.message_type == XA_WM_PROTOCOLS
&& evt -> xclient.data.l[0] == (long) XA_WM_DELETE_WINDOW) {
ClientWindow icon = cw -> icon;
Wob old_wob = TargetWob;
ClientWindow old_client = TargetWindow;
ClientWindowClose(cw);
if (TargetWob == (Wob) Context -> rootWob
&& old_client != cw && old_client != icon)
SetTarget(old_wob);
} else {
WLFsm_action(cw -> fsm, cw, evt);
}
break;
case PropertyNotify:
SetTarget(cw);
if (evt -> xproperty.atom == XA_GWM_EXECUTE) {
WlExecGWM_EXECUTE();
} else {
GWM_backup_old_property = 1;
UpdateCachedProperty(cw -> window, evt -> xproperty.atom);
GWM_backup_old_property = 0;
WLFsm_action(cw -> fsm, cw, evt);
}
break;
default:
#ifdef SHAPE
if (GWM_ShapeExtension &&
evt -> type == GWM_ShapeEventBase + ShapeNotify)
ShapeNotifyEventHandler(cw, evt);
else
#endif /* SHAPE */
{
WLFsm_action(cw -> fsm, cw, evt);
}
}
}
/*
* ConfigureRequestEventHandler is used to decode what operation is really
* intended by the configure event to only perform the appropriate action
*/
/* TO_DO: do only one XConfigure...*/
ConfigureRequestEventHandler(cw, evt)
ClientWindow cw;
XConfigureRequestEvent *evt;
{
XWindowChanges values;
int real_configure_sent = evt -> value_mask
& (CWWidth | CWHeight | CWBorderWidth);
/* move: move hook */ /* MOVE HOOK */
if (evt -> value_mask & (CWX | CWY)) {
int xgrav, ygrav;
GetWinGravityHint(cw, &xgrav, &ygrav);
XMoveWindow(dpy, cw -> hook,
(evt -> value_mask & CWX ?
cw -> box.x = (xgrav == 0 ?
evt -> x - cw -> box.borderwidth :
evt -> x - cw -> inner_x
- cw -> box.borderwidth) :
cw -> box.x),
(evt -> value_mask & CWY ?
cw -> box.y = (ygrav == 0 ?
evt -> y - cw -> box.borderwidth :
evt -> y - cw -> inner_y
- cw -> box.borderwidth) :
cw -> box.y));
if(!real_configure_sent)
SendSyntheticMoveEvent(cw);
}
/* resize is handled via recomputing */
if (real_configure_sent) {
values.width = evt -> width;
values.height = evt -> height;
values.border_width = evt -> border_width;
XSync(dpy, 0);
XSetErrorHandler(NoXError);
ErrorStatus = 0;
XConfigureWindow(dpy, cw -> client,
evt -> value_mask & (CWWidth | CWHeight | CWBorderWidth),
&values);
XSync(dpy, 0);
XSetErrorHandler(XError);
if (ErrorStatus)
return; /* problem appeared */
ReconfigureClientWindow(cw, cw -> client);
}
/* stacking change is independant of the rest and done last */
if (evt -> value_mask & CWStackMode) {
Wob sibling = 0;
if (evt -> value_mask & CWSibling) { /* % to a sibling */
sibling = (Wob) LookUpClient(evt -> above);
if (!sibling)
sibling = (Wob) LookUpWob(evt -> above);
}
if (sibling) {
values.sibling = sibling->hook;
}
values.stack_mode = evt -> detail;
XConfigureWindow(dpy, cw -> hook,
evt -> value_mask & (CWStackMode | (sibling ? CWSibling : 0)),
&values);
if (cw->map_on_raise
&& (evt -> value_mask & CWStackMode)
&& (values.stack_mode == Above
|| values.stack_mode == TopIf)) {
ShowClientWindow(cw);
}
}
}
UnDecorateWindow(cw, must_reparent, remap)
ClientWindow cw;
int must_reparent; /* must reparent window back to root? */
int remap; /* must try to re-map window? */
{
Window client = cw -> window -> client;
Wob wob = cw -> window -> client_wob;
int oldbw = cw -> window -> old_inner_borderwidth;
int must_remap;
cw = cw -> window;
if (wob) {
wob -> parent = (Wob) Context -> rootWob;
}
if (remap)
must_remap = (Update_XA_WM_STATE(cw) == WM_STATE_Withdrawn ? 0 : 1);
else
must_remap = 0;
XSetErrorHandler(NoXError);
if (cw -> mapped)
XUnmapWindow(dpy, cw -> hook);
if (must_reparent) {
ObeyWinGravityHint(cw, 0);
XReparentWindow(dpy, client, Context -> root,
cw -> box.x, cw -> box.y);
SendSyntheticMoveEvent(cw);
if (!wob)
XRemoveFromSaveSet(dpy, client);
}
/* reparent icon-window if client created it */
if (cw->icon && cw->icon->client && (!cw->icon->client_wob)) {
XReparentWindow(dpy, cw->icon->client, Context -> root, 0, 0);
XRemoveFromSaveSet(dpy, cw->icon->client);
XUnmapWindow(dpy, cw->icon->client);
}
if (!cw -> client_shaped)
XSetWindowBorderWidth(dpy, client, oldbw);
if (cw -> client_wob)
cw -> client_wob -> status &= TopLevelXWindowStatus;
if (must_remap)
XMapWindow(dpy, cw -> client);
ClientWindowClose(cw);
XSync(dpy, 0);
XSetErrorHandler(XError);
}
/* if a decoration aborts, we must put it back on screen! */
ShowUndecoratedWindow(cw)
ClientWindow cw;
{
XSync(dpy, 0);
GWM_ProcessEvents(0); /* empty events */
if (cw) {
cw->mapped = 0; /* forces a remap */
ClientWindowMap(cw);
}
}
ReconfigureClientWindow(cw, culprit)
ClientWindow cw;
Wob culprit; /* cw, client or bar */
{
int x = cw -> box.x, y = cw -> box.y;
int inner_x = cw -> inner_x, inner_y = cw -> inner_y;
if (culprit == (Wob) cw -> client || culprit == cw -> client_wob
|| (!cw -> client)) {
ClientWindowComputeGeometry(cw);
}
ClientWindowComputeBarDims(cw);
/* if (culprit != (Wob) cw -> titlebar) */
ReconfigureBar(cw -> titlebar, cw);
/* if (culprit != (Wob) cw -> leftbar) */
ReconfigureBar(cw -> leftbar, cw);
/* if (culprit != (Wob) cw -> rightbar) */
ReconfigureBar(cw -> rightbar, cw);
/* if (culprit != (Wob) cw -> basebar) */
ReconfigureBar(cw -> basebar, cw);
XMoveResizeWindow(dpy, cw -> hook, cw -> box.x = x, cw -> box.y = y,
cw -> box.width, cw -> box.height);
if (inner_x != cw -> inner_x || inner_y != cw -> inner_y)
XMoveWindow(dpy, cw -> client, cw -> inner_x, cw -> inner_y);
#ifdef SHAPE
/* do not reshape if client reshaped, it will send an event later */
if (WindowIsShaped(cw) &&
!((culprit == (Wob) cw -> client) && !cw -> client_wob && cw -> client_shaped))
ClientWindowSetShape(cw);
#endif /* SHAPE */
}
/*
* transforms outer sizes in inner ones
*/
dims_outer_to_inner(cw, pw, ph)
ClientWindow cw;
int *pw, *ph;
{
*pw = *pw - (cw -> box.width - cw -> inner_width) - 2 * cw -> box.borderwidth;
*ph = *ph - (cw -> box.height - cw -> inner_height) - 2 * cw -> box.borderwidth;
}
/****************\
* *
* window groups *
* *
\****************/
/* Maintains the group list of a group_leader
* In the client_group field of the cw, we find:
* - for the leaded, the cw of the leader.
* - for the leader, the list (WOOL_List) of grouped sons
* first one being the leader itself
*/
AddWindowToGroupLeader(cw, group_leader)
ClientWindow cw, group_leader;
{
WOOL_List *gwlgp = (WOOL_List *) & (group_leader ->
cached_props -> client_group);
/* if leader's group is not yet initialised, do it */
if (!(*gwlgp)) {
if (cw != group_leader) { /* follower */
AddWindowToGroupLeader(group_leader, group_leader);
AddWindowToGroupLeader(cw, group_leader);
} else { /* leader */
increase_reference(*gwlgp = wool_list_make(1));
increase_reference((*gwlgp) -> list[0] = (WOOL_OBJECT)
WLNumber_make(group_leader));
}
/* leader is initialized */
} else if ((*gwlgp) -> type == WLList) {
int i;
WOOL_List old_list;
for (i = 0; i < (*gwlgp) -> size; i++)
if ((*gwlgp) -> list[i] == (WOOL_OBJECT) cw)
return;
old_list = *gwlgp;
increase_reference(*gwlgp = wool_list_make((*gwlgp) -> size + 1));
copy_n_objects(old_list -> list, (*gwlgp) -> list, old_list -> size);
decrease_reference(old_list);
increase_reference((*gwlgp) -> list[(*gwlgp) -> size - 1]
= (WOOL_OBJECT) WLNumber_make(cw));
if((cw -> cached_props -> client_group)
&& (cw -> cached_props -> client_group -> type == WLList))
decrease_reference(cw -> cached_props -> client_group);
cw -> cached_props -> client_group = (WOOL_OBJECT) group_leader;
}
}
/* called when a window is closed if client_group not void
*/
RemoveWindowFromGroup(cw)
ClientWindow cw;
{
WOOL_List *gwlgp = (WOOL_List *) & (cw ->
cached_props -> client_group), list;
int i;
if ((*gwlgp) -> type == WLList) { /* leader */
ClientWindow son;
list = (*gwlgp);
for (i = 0; i < list -> size; i++) {
son = (ClientWindow) ((WOOL_Number) list -> list[i]) -> number;
if (WobIsValid(son))
son -> cached_props -> client_group = NULL;
}
decrease_reference(list);
} else { /* follower */
ClientWindow leader = (ClientWindow) cw->cached_props->client_group;
list = (WOOL_List) leader -> cached_props -> client_group;
if (list -> type == WLList) {
cw -> cached_props -> client_group = NULL;
i = 0;
while (i < list -> size) {
if (((WOOL_Number) list -> list[i]) -> number == (Num) cw)
break;
i++;
}
if (i == list -> size) /* not in list (should not happen) */
return;
if (--(list -> size) == 1) { /* only leader remains in list
so destroy the list */
leader -> cached_props -> client_group = NULL;
decrease_reference(list);
} else { /* remove window from leader's list */
while (i++ < list -> size)
list -> list[i - 1] = list -> list[i];
}
}
}
}
/*
* wool interface
*/
WOOL_OBJECT
wool_window_group_get()
{
ClientWindow cw = TargetWindow -> window;
if (cw -> cached_props -> client_group) { /* group exists */
if (cw -> cached_props -> client_group -> type == WLList) { /* lead */
return cw -> cached_props -> client_group;
} else { /* follower */
WOOL_OBJECT group =
((ClientWindow) (cw -> cached_props -> client_group))
-> cached_props -> client_group;
if (group -> type == WLList) { /* sanity check */
return group;
} else {
cw -> cached_props -> client_group = 0;
return NIL;
}
}
} else { /* no group */
return NIL;
}
}
WOOL_OBJECT
wool_window_group_set(group_leader_num)
WOOL_Number group_leader_num;
{
ClientWindow cw = TargetWindow -> window;
ClientWindow group_leader;
if (group_leader_num -> type == WLNumber) {
group_leader = (ClientWindow) group_leader_num -> number;
} else if (group_leader_num -> type == WLList) {
group_leader = (ClientWindow)
((WOOL_Number) ((WOOL_List) group_leader_num) -> list[0])
-> number;
} else if(cw-> cached_props -> client_group) {
RemoveWindowFromGroup(cw);
return NIL;
}
AddWindowToGroupLeader(cw, group_leader);
return (WOOL_OBJECT) group_leader_num;
}
ClientWindow
ClientWindowLeader(cw)
ClientWindow cw;
{
if (cw->cached_props->client_group) { /* group exists */
if (cw->cached_props->client_group->type == WLList) { /* lead */
return cw;
} else { /* follower */
return (ClientWindow) (cw->cached_props->client_group);
}
} else {
return 0;
}
}
ClientWindowRecordClient(cw)
ClientWindow cw;
{
XSaveContext(dpy, cw -> client, client_context, (caddr_t)cw);
}
#ifdef SHAPE
/* non-rectangular extension:
* set the frame to the shape of client +bars
*/
WindowIsShaped(cw)
ClientWindow cw;
{
if (cw -> client_shaped)
return 1;
if (((cw -> titlebar) && (cw -> titlebar -> shaped)) ||
((cw -> basebar) && (cw -> basebar -> shaped)) ||
((cw -> leftbar) && (cw -> leftbar -> shaped)) ||
((cw -> rightbar) && (cw -> rightbar -> shaped)))
return 1;
return 0;
}
ClientWindowSetShape(cw)
ClientWindow cw;
{
XRectangle rect;
int initop = ShapeSet;
if (cw -> box.borderwidth && GWM_allow_border_on_shaped_windows) {
/* disabled for back compat */
rect.x = - cw -> box.borderwidth;
rect.y = - cw -> box.borderwidth;
rect.width = cw -> box.width + 2 * cw -> box.borderwidth;
rect.height = cw -> box.height + 2 * cw -> box.borderwidth;
XShapeCombineRectangles(dpy, cw -> hook, ShapeBounding,
0, 0,
&rect, 1, ShapeSet, 0);
rect.x = 0;
rect.y = 0;
rect.width = cw -> box.width;
rect.height = cw -> box.height;
XShapeCombineRectangles(dpy, cw -> hook, ShapeBounding,
0, 0,
&rect, 1, ShapeSubtract, 0);
initop = ShapeUnion;
}
if (cw -> client_shaped)
XShapeCombineShape (dpy, cw -> hook, ShapeBounding,
cw -> inner_x, cw -> inner_y,
cw -> client, ShapeBounding,
initop);
else {
rect.x = cw -> inner_x;
rect.y = cw -> inner_y;
rect.width = cw -> inner_width + 2 * cw -> inner_borderwidth;
rect.height = cw -> inner_height + 2 * cw -> inner_borderwidth;
XShapeCombineRectangles(dpy, cw -> hook, ShapeBounding,
0, 0,
&rect, 1, initop, 0);
}
if (cw -> titlebar)
XShapeCombineShape (dpy, cw -> hook, ShapeBounding,
cw -> titlebar -> box.borderwidth,
cw -> titlebar -> box.borderwidth,
cw -> titlebar -> hook, ShapeBounding,
ShapeUnion);
if (cw -> leftbar)
XShapeCombineShape (dpy, cw -> hook, ShapeBounding,
cw -> leftbar -> box.borderwidth,
cw -> leftbar -> box.borderwidth + cw -> inner_y,
cw -> leftbar -> hook, ShapeBounding,
ShapeUnion);
if (cw -> rightbar)
XShapeCombineShape (dpy, cw -> hook, ShapeBounding,
cw -> inner_x + cw -> inner_width
+ cw -> rightbar -> box.borderwidth
+ 2 * cw -> inner_borderwidth,
cw -> rightbar -> box.borderwidth + cw -> inner_y,
cw -> rightbar -> hook, ShapeBounding,
ShapeUnion);
if (cw -> basebar)
XShapeCombineShape (dpy, cw -> hook, ShapeBounding,
cw -> basebar -> box.borderwidth,
cw -> inner_y + cw -> inner_height
+ cw -> basebar -> box.borderwidth
+ 2 * cw -> inner_borderwidth,
cw -> basebar -> hook, ShapeBounding,
ShapeUnion);
}
/* what to do if shape changes
*/
ShapeNotifyEventHandler(cw, evt)
ClientWindow cw;
XShapeEvent *evt;
{
if (evt -> kind == ShapeBounding && evt -> window == cw -> client) {
cw -> client_shaped = evt -> shaped;
if (WindowIsShaped(cw))
ClientWindowSetShape(cw);
else
XShapeCombineMask (dpy, cw -> hook, ShapeBounding,
0, 0, None, ShapeSet);
}
}
WOOL_OBJECT
wool_window_has_shaped_client()
{
if (TargetWindow -> client_shaped)
return TRU;
else
return NIL;
}
#endif /* SHAPE */