1943 lines
56 KiB
C
1943 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 "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 /* compile with -I/usr/include/X11 AND
|
|
-I/usr/include/X11/extensions to work on
|
|
machines having shapes.h in either place */
|
|
#include <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 */
|