Mike Small
4de2773058
For now that means to behave as if RandomPlacement is true and UsePPosition is non-zero (use PPosition if the window position isn't (0,0).
1155 lines
34 KiB
C
1155 lines
34 KiB
C
/*****************************************************************************/
|
|
/*
|
|
|
|
Copyright 1989,1998 The Open Group
|
|
|
|
Permission to use, copy, modify, distribute, and sell this software and its
|
|
documentation for any purpose is hereby granted without fee, provided that
|
|
the above copyright notice appear in all copies and that both that
|
|
copyright notice and this permission notice appear in supporting
|
|
documentation.
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of The Open Group shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from The Open Group.
|
|
|
|
*/
|
|
/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
|
|
/** Salt Lake City, Utah **/
|
|
/** Cambridge, Massachusetts **/
|
|
/** **/
|
|
/** All Rights Reserved **/
|
|
/** **/
|
|
/** Permission to use, copy, modify, and distribute this software and **/
|
|
/** its documentation for any purpose and without fee is hereby **/
|
|
/** granted, provided that the above copyright notice appear in all **/
|
|
/** copies and that both that copyright notice and this permis- **/
|
|
/** sion notice appear in supporting documentation, and that the **/
|
|
/** name of Evans & Sutherland not be used in advertising **/
|
|
/** in publicity pertaining to distribution of the software without **/
|
|
/** specific, written prior permission. **/
|
|
/** **/
|
|
/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
|
|
/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
|
|
/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
|
|
/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
|
|
/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
|
|
/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
|
|
/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
|
|
/** OR PERFORMANCE OF THIS SOFTWARE. **/
|
|
/*****************************************************************************/
|
|
|
|
|
|
/**********************************************************************
|
|
*
|
|
* Add a new window, put the titlbar and other stuff around
|
|
* the window
|
|
*
|
|
* 31-Mar-88 Tom LaStrange Initial Version.
|
|
*
|
|
**********************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include "twm.h"
|
|
#include <X11/Xatom.h>
|
|
#include "util.h"
|
|
#include "resize.h"
|
|
#include "parse.h"
|
|
#include "list.h"
|
|
#include "events.h"
|
|
#include "menus.h"
|
|
#include "screen.h"
|
|
#include "session.h"
|
|
#include "add_window.h"
|
|
|
|
#define gray_width 2
|
|
#define gray_height 2
|
|
static char gray_bits[] = {
|
|
0x02, 0x01};
|
|
|
|
int AddingX;
|
|
int AddingY;
|
|
int AddingW;
|
|
int AddingH;
|
|
|
|
static int PlaceX = 50;
|
|
static int PlaceY = 50;
|
|
|
|
static void do_add_binding ( int button, int context, int modifier, int func );
|
|
static Window CreateHighlightWindow ( TwmWindow *tmp_win );
|
|
static void CreateWindowTitlebarButtons ( TwmWindow *tmp_win );
|
|
|
|
|
|
char NoName[] = "Untitled"; /* name if no name is specified */
|
|
|
|
|
|
/**
|
|
* map gravity to (x,y) offset signs for adding to x and y when window is
|
|
* mapped to get proper placement.
|
|
*
|
|
* \param tmp window from which to get gravity
|
|
* \param xp,yp return values
|
|
*
|
|
*/
|
|
void
|
|
GetGravityOffsets (TwmWindow *tmp, int *xp, int *yp)
|
|
{
|
|
static struct _gravity_offset {
|
|
int x, y;
|
|
} gravity_offsets[11] = {
|
|
{ 0, 0 }, /* ForgetGravity */
|
|
{ -1, -1 }, /* NorthWestGravity */
|
|
{ 0, -1 }, /* NorthGravity */
|
|
{ 1, -1 }, /* NorthEastGravity */
|
|
{ -1, 0 }, /* WestGravity */
|
|
{ 0, 0 }, /* CenterGravity */
|
|
{ 1, 0 }, /* EastGravity */
|
|
{ -1, 1 }, /* SouthWestGravity */
|
|
{ 0, 1 }, /* SouthGravity */
|
|
{ 1, 1 }, /* SouthEastGravity */
|
|
{ 0, 0 }, /* StaticGravity */
|
|
};
|
|
register int g = ((tmp->hints.flags & PWinGravity)
|
|
? tmp->hints.win_gravity : NorthWestGravity);
|
|
|
|
if (g < ForgetGravity || g > StaticGravity) {
|
|
*xp = *yp = 0;
|
|
} else {
|
|
*xp = gravity_offsets[g].x;
|
|
*yp = gravity_offsets[g].y;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
* add a new window to the twm list.
|
|
*
|
|
* \return pointer to the TwmWindow structure
|
|
*
|
|
* \param w the window id of the window to add
|
|
*/
|
|
TwmWindow *
|
|
AddWindow(Window w)
|
|
{
|
|
TwmWindow *tmp_win; /* new twm window structure */
|
|
unsigned long valuemask; /* mask for create windows */
|
|
XSetWindowAttributes attributes; /* attributes for create windows */
|
|
int random_placement; /* don't know where to put the window */
|
|
int gravx, gravy; /* gravity signs for positioning */
|
|
int namelen;
|
|
int bw2;
|
|
short saved_x, saved_y, restore_icon_x, restore_icon_y;
|
|
unsigned short saved_width, saved_height;
|
|
Bool restore_iconified = 0;
|
|
Bool restore_icon_info_present = 0;
|
|
int restoredFromPrevSession;
|
|
Bool width_ever_changed_by_user;
|
|
Bool height_ever_changed_by_user;
|
|
char *name;
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "AddWindow: w = 0x%lx\n", (unsigned long)w);
|
|
#endif
|
|
|
|
/* allocate space for the twm window */
|
|
tmp_win = calloc(1, sizeof(TwmWindow));
|
|
if (tmp_win == NULL)
|
|
{
|
|
fprintf (stderr, "%s: Unable to allocate memory to manage window ID %lx.\n",
|
|
ProgramName, w);
|
|
return NULL;
|
|
}
|
|
tmp_win->w = w;
|
|
tmp_win->zoomed = ZOOM_NONE;
|
|
tmp_win->cmaps.number_cwins = 0;
|
|
|
|
XSelectInput(dpy, tmp_win->w, PropertyChangeMask);
|
|
|
|
XGetWindowAttributes(dpy, tmp_win->w, &tmp_win->attr);
|
|
|
|
if (!I18N_FetchName(dpy, tmp_win->w, &name))
|
|
name = NULL;
|
|
tmp_win->class = NoClass;
|
|
XGetClassHint(dpy, tmp_win->w, &tmp_win->class);
|
|
FetchWmProtocols (tmp_win);
|
|
FetchWmColormapWindows (tmp_win);
|
|
|
|
if (name == NULL)
|
|
tmp_win->name = strdup(NoName);
|
|
else {
|
|
tmp_win->name = strdup(name);
|
|
free(name);
|
|
}
|
|
|
|
if (GetWindowConfig (tmp_win,
|
|
&saved_x, &saved_y, &saved_width, &saved_height,
|
|
&restore_iconified, &restore_icon_info_present,
|
|
&restore_icon_x, &restore_icon_y,
|
|
&width_ever_changed_by_user, &height_ever_changed_by_user))
|
|
{
|
|
tmp_win->attr.x = saved_x;
|
|
tmp_win->attr.y = saved_y;
|
|
|
|
tmp_win->widthEverChangedByUser = width_ever_changed_by_user;
|
|
tmp_win->heightEverChangedByUser = height_ever_changed_by_user;
|
|
|
|
if (width_ever_changed_by_user)
|
|
tmp_win->attr.width = saved_width;
|
|
|
|
if (height_ever_changed_by_user)
|
|
tmp_win->attr.height = saved_height;
|
|
|
|
restoredFromPrevSession = 1;
|
|
}
|
|
else
|
|
{
|
|
tmp_win->widthEverChangedByUser = False;
|
|
tmp_win->heightEverChangedByUser = False;
|
|
|
|
restoredFromPrevSession = 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* do initial clip; should look at window gravity
|
|
*/
|
|
if (tmp_win->attr.width > Scr->MaxWindowWidth)
|
|
tmp_win->attr.width = Scr->MaxWindowWidth;
|
|
if (tmp_win->attr.height > Scr->MaxWindowHeight)
|
|
tmp_win->attr.height = Scr->MaxWindowHeight;
|
|
|
|
tmp_win->wmhints = XGetWMHints(dpy, tmp_win->w);
|
|
|
|
if (tmp_win->wmhints)
|
|
{
|
|
if (restore_iconified)
|
|
{
|
|
tmp_win->wmhints->initial_state = IconicState;
|
|
tmp_win->wmhints->flags |= StateHint;
|
|
}
|
|
|
|
if (restore_icon_info_present)
|
|
{
|
|
tmp_win->wmhints->icon_x = restore_icon_x;
|
|
tmp_win->wmhints->icon_y = restore_icon_y;
|
|
tmp_win->wmhints->flags |= IconPositionHint;
|
|
}
|
|
}
|
|
|
|
if (tmp_win->wmhints && (tmp_win->wmhints->flags & WindowGroupHint))
|
|
tmp_win->group = tmp_win->wmhints->window_group;
|
|
else
|
|
tmp_win->group = tmp_win->w/* NULL */;
|
|
|
|
/*
|
|
* The July 27, 1988 draft of the ICCCM ignores the size and position
|
|
* fields in the WM_NORMAL_HINTS property.
|
|
*/
|
|
|
|
tmp_win->transient = Transient(tmp_win->w, &tmp_win->transientfor);
|
|
|
|
tmp_win->nameChanged = 0;
|
|
if (tmp_win->class.res_name == NULL)
|
|
tmp_win->class.res_name = NoName;
|
|
if (tmp_win->class.res_class == NULL)
|
|
tmp_win->class.res_class = NoName;
|
|
|
|
tmp_win->full_name = strdup(tmp_win->name);
|
|
namelen = strlen (tmp_win->name);
|
|
|
|
tmp_win->stackmode = Scr->StackMode &&
|
|
(!(short)(long) LookInList(Scr->NoStackModeL, tmp_win->full_name,
|
|
&tmp_win->class));
|
|
|
|
tmp_win->auto_raise = (short)(long) LookInList(Scr->AutoRaise,
|
|
tmp_win->full_name,
|
|
&tmp_win->class);
|
|
if (tmp_win->auto_raise) Scr->NumAutoRaises++;
|
|
|
|
if (LookInList(Scr->WindowRingL, tmp_win->full_name, &tmp_win->class)) {
|
|
if (Scr->Ring) {
|
|
tmp_win->ring.next = Scr->Ring->ring.next;
|
|
if (Scr->Ring->ring.next->ring.prev)
|
|
Scr->Ring->ring.next->ring.prev = tmp_win;
|
|
Scr->Ring->ring.next = tmp_win;
|
|
tmp_win->ring.prev = Scr->Ring;
|
|
} else {
|
|
tmp_win->ring.next = tmp_win->ring.prev = Scr->Ring = tmp_win;
|
|
}
|
|
} else
|
|
tmp_win->ring.next = tmp_win->ring.prev = NULL;
|
|
tmp_win->ring.cursor_valid = False;
|
|
|
|
tmp_win->squeeze = HasShape;
|
|
tmp_win->old_bw = tmp_win->attr.border_width;
|
|
|
|
if (Scr->ClientBorderWidth) {
|
|
tmp_win->frame_bw = tmp_win->old_bw;
|
|
} else {
|
|
tmp_win->frame_bw = Scr->BorderWidth;
|
|
}
|
|
bw2 = tmp_win->frame_bw * 2;
|
|
|
|
tmp_win->title_height = Scr->TitleHeight + tmp_win->frame_bw;
|
|
if (Scr->NoTitlebar)
|
|
tmp_win->title_height = 0;
|
|
if (LookInList(Scr->MakeTitle, tmp_win->full_name, &tmp_win->class))
|
|
tmp_win->title_height = Scr->TitleHeight + tmp_win->frame_bw;
|
|
if (LookInList(Scr->NoTitle, tmp_win->full_name, &tmp_win->class))
|
|
tmp_win->title_height = 0;
|
|
|
|
/* if it is a transient window, don't put a title on it */
|
|
if (tmp_win->transient && !Scr->DecorateTransients)
|
|
tmp_win->title_height = 0;
|
|
|
|
if (LookInList(Scr->StartIconified, tmp_win->full_name, &tmp_win->class))
|
|
{
|
|
if (!tmp_win->wmhints)
|
|
{
|
|
tmp_win->wmhints = malloc(sizeof(XWMHints));
|
|
tmp_win->wmhints->flags = 0;
|
|
}
|
|
tmp_win->wmhints->initial_state = IconicState;
|
|
tmp_win->wmhints->flags |= StateHint;
|
|
}
|
|
|
|
GetWindowSizeHints (tmp_win);
|
|
|
|
if (restoredFromPrevSession)
|
|
{
|
|
/*
|
|
* When restoring window positions from the previous session,
|
|
* we always use NorthWest gravity.
|
|
*/
|
|
|
|
gravx = gravy = -1;
|
|
}
|
|
else
|
|
{
|
|
GetGravityOffsets(tmp_win, &gravx, &gravy);
|
|
}
|
|
|
|
/*
|
|
* Random placement is used when...
|
|
*
|
|
* o the window is not a transient, and
|
|
*
|
|
* o a USPosition was not requested, and
|
|
*
|
|
* o a PPosition was not requested or it was and the window is not at (0,0)
|
|
*
|
|
* According to twm's man page, not respecting PPosition = (0,0)
|
|
* avoids problems with old toolkits.
|
|
*/
|
|
random_placement = !tmp_win->transient && !(tmp_win->hints.flags & USPosition)
|
|
&& !((tmp_win->hints.flags & PPosition)
|
|
&& (tmp_win->attr.x != 0 || tmp_win->attr.y != 0));
|
|
|
|
/*
|
|
* set window position
|
|
*/
|
|
if (HandlingEvents && random_placement && !restoredFromPrevSession) {
|
|
if ((PlaceX + tmp_win->attr.width) > Scr->MyDisplayWidth)
|
|
PlaceX = 50;
|
|
if ((PlaceY + tmp_win->attr.height) > Scr->MyDisplayHeight)
|
|
PlaceY = 50;
|
|
|
|
tmp_win->attr.x = PlaceX;
|
|
tmp_win->attr.y = PlaceY;
|
|
PlaceX += 30;
|
|
PlaceY += 30;
|
|
} else { /* put it where asked, mod title bar */
|
|
/* if the gravity is towards the top, move it by the title height */
|
|
if (gravy < 0) tmp_win->attr.y -= gravy * tmp_win->title_height;
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr, " position window %d, %d %dx%d\n",
|
|
tmp_win->attr.x,
|
|
tmp_win->attr.y,
|
|
tmp_win->attr.width,
|
|
tmp_win->attr.height);
|
|
#endif
|
|
|
|
if (!Scr->ClientBorderWidth) { /* need to adjust for twm borders */
|
|
int delta = tmp_win->attr.border_width - tmp_win->frame_bw;
|
|
tmp_win->attr.x += gravx * delta;
|
|
tmp_win->attr.y += gravy * delta;
|
|
}
|
|
|
|
tmp_win->title_width = tmp_win->attr.width;
|
|
|
|
if (tmp_win->old_bw) XSetWindowBorderWidth (dpy, tmp_win->w, 0);
|
|
|
|
tmp_win->name_width = MyFont_TextWidth(&Scr->TitleBarFont, tmp_win->name,
|
|
namelen);
|
|
|
|
if (!I18N_GetIconName(dpy, tmp_win->w, &name)) {
|
|
tmp_win->icon_name = strdup(tmp_win->name);
|
|
} else {
|
|
if (name == NULL) {
|
|
tmp_win->icon_name = strdup(tmp_win->name);
|
|
} else {
|
|
tmp_win->icon_name = strdup(name);
|
|
free(name);
|
|
}
|
|
}
|
|
|
|
tmp_win->iconified = FALSE;
|
|
tmp_win->icon = FALSE;
|
|
tmp_win->icon_on = FALSE;
|
|
|
|
XGrabServer(dpy);
|
|
|
|
/*
|
|
* Make sure the client window still exists. We don't want to leave an
|
|
* orphan frame window if it doesn't. Since we now have the server
|
|
* grabbed, the window can't disappear later without having been
|
|
* reparented, so we'll get a DestroyNotify for it. We won't have
|
|
* gotten one for anything up to here, however.
|
|
*/
|
|
if (XGetGeometry(dpy, tmp_win->w, &JunkRoot, &JunkX, &JunkY,
|
|
&JunkWidth, &JunkHeight, &JunkBW, &JunkDepth) == 0)
|
|
{
|
|
free(tmp_win);
|
|
XUngrabServer(dpy);
|
|
return(NULL);
|
|
}
|
|
|
|
/* add the window into the twm list */
|
|
tmp_win->next = Scr->TwmRoot.next;
|
|
if (Scr->TwmRoot.next != NULL)
|
|
Scr->TwmRoot.next->prev = tmp_win;
|
|
tmp_win->prev = &Scr->TwmRoot;
|
|
Scr->TwmRoot.next = tmp_win;
|
|
|
|
/* get all the colors for the window */
|
|
|
|
tmp_win->border = Scr->BorderColor;
|
|
tmp_win->icon_border = Scr->IconBorderColor;
|
|
tmp_win->border_tile.fore = Scr->BorderTileC.fore;
|
|
tmp_win->border_tile.back = Scr->BorderTileC.back;
|
|
tmp_win->title.fore = Scr->TitleC.fore;
|
|
tmp_win->title.back = Scr->TitleC.back;
|
|
tmp_win->iconc.fore = Scr->IconC.fore;
|
|
tmp_win->iconc.back = Scr->IconC.back;
|
|
|
|
GetColorFromList(Scr->BorderColorL, tmp_win->full_name, &tmp_win->class,
|
|
&tmp_win->border);
|
|
GetColorFromList(Scr->IconBorderColorL, tmp_win->full_name, &tmp_win->class,
|
|
&tmp_win->icon_border);
|
|
GetColorFromList(Scr->BorderTileForegroundL, tmp_win->full_name,
|
|
&tmp_win->class, &tmp_win->border_tile.fore);
|
|
GetColorFromList(Scr->BorderTileBackgroundL, tmp_win->full_name,
|
|
&tmp_win->class, &tmp_win->border_tile.back);
|
|
GetColorFromList(Scr->TitleForegroundL, tmp_win->full_name, &tmp_win->class,
|
|
&tmp_win->title.fore);
|
|
GetColorFromList(Scr->TitleBackgroundL, tmp_win->full_name, &tmp_win->class,
|
|
&tmp_win->title.back);
|
|
GetColorFromList(Scr->IconForegroundL, tmp_win->full_name, &tmp_win->class,
|
|
&tmp_win->iconc.fore);
|
|
GetColorFromList(Scr->IconBackgroundL, tmp_win->full_name, &tmp_win->class,
|
|
&tmp_win->iconc.back);
|
|
|
|
|
|
/* create windows */
|
|
|
|
tmp_win->frame_x = tmp_win->attr.x + tmp_win->old_bw - tmp_win->frame_bw;
|
|
tmp_win->frame_y = tmp_win->attr.y - tmp_win->title_height +
|
|
tmp_win->old_bw - tmp_win->frame_bw;
|
|
tmp_win->frame_width = tmp_win->attr.width;
|
|
tmp_win->frame_height = tmp_win->attr.height + tmp_win->title_height;
|
|
|
|
valuemask = CWBackPixmap | CWBorderPixel | CWCursor | CWEventMask;
|
|
attributes.background_pixmap = None;
|
|
attributes.border_pixel = tmp_win->border;
|
|
attributes.cursor = Scr->FrameCursor;
|
|
attributes.event_mask = (SubstructureRedirectMask |
|
|
ButtonPressMask | ButtonReleaseMask |
|
|
EnterWindowMask | LeaveWindowMask);
|
|
if (tmp_win->attr.save_under) {
|
|
attributes.save_under = True;
|
|
valuemask |= CWSaveUnder;
|
|
}
|
|
|
|
tmp_win->frame = XCreateWindow (dpy, Scr->Root, tmp_win->frame_x,
|
|
tmp_win->frame_y,
|
|
(unsigned int) tmp_win->frame_width,
|
|
(unsigned int) tmp_win->frame_height,
|
|
(unsigned int) tmp_win->frame_bw,
|
|
Scr->d_depth,
|
|
(unsigned int) CopyFromParent,
|
|
Scr->d_visual, valuemask, &attributes);
|
|
|
|
if (tmp_win->title_height)
|
|
{
|
|
valuemask = (CWEventMask | CWBorderPixel | CWBackPixel);
|
|
attributes.event_mask = (KeyPressMask | ButtonPressMask |
|
|
ButtonReleaseMask | ExposureMask);
|
|
attributes.border_pixel = tmp_win->border;
|
|
attributes.background_pixel = tmp_win->title.back;
|
|
tmp_win->title_w = XCreateWindow (dpy, tmp_win->frame,
|
|
-tmp_win->frame_bw,
|
|
-tmp_win->frame_bw,
|
|
(unsigned int) tmp_win->attr.width,
|
|
(unsigned int) Scr->TitleHeight,
|
|
(unsigned int) tmp_win->frame_bw,
|
|
Scr->d_depth,
|
|
(unsigned int) CopyFromParent,
|
|
Scr->d_visual, valuemask,
|
|
&attributes);
|
|
}
|
|
else {
|
|
tmp_win->title_w = 0;
|
|
tmp_win->squeeze = False;
|
|
}
|
|
|
|
tmp_win->gray = XCreatePixmapFromBitmapData(dpy, Scr->Root,
|
|
gray_bits, gray_width, gray_height,
|
|
tmp_win->border_tile.fore, tmp_win->border_tile.back,
|
|
Scr->d_depth);
|
|
|
|
SetBorder (tmp_win, False);
|
|
|
|
|
|
if (tmp_win->title_w) {
|
|
CreateWindowTitlebarButtons (tmp_win);
|
|
ComputeTitleLocation(tmp_win);
|
|
XMoveWindow (dpy, tmp_win->title_w,
|
|
tmp_win->title_x, tmp_win->title_y);
|
|
XDefineCursor(dpy, tmp_win->title_w, Scr->TitleCursor);
|
|
}
|
|
|
|
valuemask = (CWEventMask | CWDontPropagate);
|
|
attributes.event_mask = (StructureNotifyMask | PropertyChangeMask |
|
|
ColormapChangeMask | VisibilityChangeMask |
|
|
EnterWindowMask | LeaveWindowMask);
|
|
attributes.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask;
|
|
XChangeWindowAttributes (dpy, tmp_win->w, valuemask, &attributes);
|
|
|
|
if (HasShape)
|
|
XShapeSelectInput (dpy, tmp_win->w, ShapeNotifyMask);
|
|
|
|
if (tmp_win->title_w) {
|
|
XMapWindow (dpy, tmp_win->title_w);
|
|
}
|
|
|
|
if (HasShape) {
|
|
int xws, yws, xbs, ybs;
|
|
unsigned wws, hws, wbs, hbs;
|
|
int boundingShaped, clipShaped;
|
|
|
|
XShapeSelectInput(dpy, tmp_win->w, ShapeNotifyMask);
|
|
XShapeQueryExtents(dpy, tmp_win->w,
|
|
&boundingShaped, &xws, &yws, &wws, &hws,
|
|
&clipShaped, &xbs, &ybs, &wbs, &hbs);
|
|
tmp_win->wShaped = boundingShaped;
|
|
}
|
|
|
|
XReparentWindow(dpy, tmp_win->w, tmp_win->frame, 0, tmp_win->title_height);
|
|
/*
|
|
* Reparenting generates an UnmapNotify event, followed by a MapNotify.
|
|
* Set the map state to FALSE to prevent a transition back to
|
|
* WithdrawnState in HandleUnmapNotify. Map state gets set correctly
|
|
* again in HandleMapNotify.
|
|
*/
|
|
tmp_win->mapped = FALSE;
|
|
|
|
SetupFrame (tmp_win, tmp_win->frame_x, tmp_win->frame_y,
|
|
tmp_win->frame_width, tmp_win->frame_height, -1, True);
|
|
|
|
/* wait until the window is iconified and the icon window is mapped
|
|
* before creating the icon window
|
|
*/
|
|
tmp_win->icon_w = (Window) 0;
|
|
|
|
GrabButtons(tmp_win);
|
|
GrabKeys(tmp_win);
|
|
|
|
XSaveContext(dpy, tmp_win->w, TwmContext, (caddr_t) tmp_win);
|
|
XSaveContext(dpy, tmp_win->w, ScreenContext, (caddr_t) Scr);
|
|
XSaveContext(dpy, tmp_win->frame, TwmContext, (caddr_t) tmp_win);
|
|
XSaveContext(dpy, tmp_win->frame, ScreenContext, (caddr_t) Scr);
|
|
if (tmp_win->title_height)
|
|
{
|
|
int i;
|
|
int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
|
|
|
|
XSaveContext(dpy, tmp_win->title_w, TwmContext, (caddr_t) tmp_win);
|
|
XSaveContext(dpy, tmp_win->title_w, ScreenContext, (caddr_t) Scr);
|
|
for (i = 0; i < nb; i++) {
|
|
XSaveContext(dpy, tmp_win->titlebuttons[i].window, TwmContext,
|
|
(caddr_t) tmp_win);
|
|
XSaveContext(dpy, tmp_win->titlebuttons[i].window, ScreenContext,
|
|
(caddr_t) Scr);
|
|
}
|
|
if (tmp_win->hilite_w)
|
|
{
|
|
XSaveContext(dpy, tmp_win->hilite_w, TwmContext, (caddr_t)tmp_win);
|
|
XSaveContext(dpy, tmp_win->hilite_w, ScreenContext, (caddr_t)Scr);
|
|
}
|
|
}
|
|
|
|
XUngrabServer(dpy);
|
|
|
|
/* if we were in the middle of a menu activated function, regrab
|
|
* the pointer
|
|
*/
|
|
if (RootFunction)
|
|
ReGrab();
|
|
|
|
return (tmp_win);
|
|
}
|
|
|
|
|
|
/**
|
|
* checks to see if we should really put a twm frame on the window
|
|
*
|
|
* \return TRUE - go ahead and place the window
|
|
* \return FALSE - don't frame the window
|
|
* \param w the window to check
|
|
*/
|
|
int
|
|
MappedNotOverride(Window w)
|
|
{
|
|
XWindowAttributes wa;
|
|
|
|
XGetWindowAttributes(dpy, w, &wa);
|
|
return ((wa.map_state != IsUnmapped) && (wa.override_redirect != True));
|
|
}
|
|
|
|
|
|
/**
|
|
* attach default bindings so that naive users don't get messed up if they
|
|
* provide a minimal twmrc.
|
|
*/
|
|
static void do_add_binding (int button, int context, int modifier, int func)
|
|
{
|
|
MouseButton *mb = &Scr->Mouse[button][context][modifier];
|
|
|
|
if (mb->func) return; /* already defined */
|
|
|
|
mb->func = func;
|
|
mb->item = NULL;
|
|
}
|
|
|
|
void
|
|
AddDefaultBindings (void)
|
|
{
|
|
/*
|
|
* The bindings are stored in Scr->Mouse, indexed by
|
|
* Mouse[button_number][C_context][modifier].
|
|
*/
|
|
|
|
#define NoModifierMask 0
|
|
|
|
do_add_binding (Button1, C_TITLE, NoModifierMask, F_MOVE);
|
|
do_add_binding (Button1, C_ICON, NoModifierMask, F_ICONIFY);
|
|
|
|
do_add_binding (Button2, C_TITLE, NoModifierMask, F_RAISELOWER);
|
|
do_add_binding (Button2, C_ICON, NoModifierMask, F_ICONIFY);
|
|
|
|
#undef NoModifierMask
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
* grab needed buttons for the window
|
|
*
|
|
* \param[in] tmp_win the twm window structure to use
|
|
*/
|
|
void
|
|
GrabButtons(TwmWindow *tmp_win)
|
|
{
|
|
int i, j;
|
|
|
|
for (i = 0; i < MAX_BUTTONS+1; i++)
|
|
{
|
|
for (j = 0; j < MOD_SIZE; j++)
|
|
{
|
|
if (Scr->Mouse[i][C_WINDOW][j].func != 0)
|
|
{
|
|
/* twm used to do this grab on the application main window,
|
|
* tmp_win->w . This was not ICCCM complient and was changed.
|
|
*/
|
|
XGrabButton(dpy, i, j, tmp_win->frame,
|
|
True, ButtonPressMask | ButtonReleaseMask,
|
|
GrabModeAsync, GrabModeAsync, None,
|
|
Scr->FrameCursor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* grab needed keys for the window
|
|
*
|
|
* \param[in] tmp_win the twm window structure to use
|
|
*/
|
|
void
|
|
GrabKeys(TwmWindow *tmp_win)
|
|
{
|
|
FuncKey *tmp;
|
|
|
|
for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
|
|
{
|
|
switch (tmp->cont)
|
|
{
|
|
case C_WINDOW:
|
|
XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->w, True,
|
|
GrabModeAsync, GrabModeAsync);
|
|
break;
|
|
|
|
case C_ICON:
|
|
if (tmp_win->icon_w)
|
|
XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->icon_w, True,
|
|
GrabModeAsync, GrabModeAsync);
|
|
|
|
case C_TITLE:
|
|
if (tmp_win->title_w)
|
|
XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->title_w, True,
|
|
GrabModeAsync, GrabModeAsync);
|
|
break;
|
|
|
|
case C_NAME:
|
|
XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->w, True,
|
|
GrabModeAsync, GrabModeAsync);
|
|
if (tmp_win->icon_w)
|
|
XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->icon_w, True,
|
|
GrabModeAsync, GrabModeAsync);
|
|
if (tmp_win->title_w)
|
|
XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->title_w, True,
|
|
GrabModeAsync, GrabModeAsync);
|
|
break;
|
|
/*
|
|
case C_ROOT:
|
|
XGrabKey(dpy, tmp->keycode, tmp->mods, Scr->Root, True,
|
|
GrabModeAsync, GrabModeAsync);
|
|
break;
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
|
|
static Window CreateHighlightWindow (TwmWindow *tmp_win)
|
|
{
|
|
XSetWindowAttributes attributes;
|
|
int h = (Scr->TitleHeight - 2 * Scr->FramePadding);
|
|
Window w;
|
|
|
|
/* Use an even gray pattern. */
|
|
Scr->hilitePm = XCreateBitmapFromData (dpy, tmp_win->title_w,
|
|
gray_bits, gray_width,
|
|
gray_height);
|
|
Scr->hilite_pm_width = gray_width;
|
|
Scr->hilite_pm_height = gray_height;
|
|
attributes.background_pixel = tmp_win->title.fore;
|
|
|
|
w = XCreateWindow (dpy, tmp_win->title_w, 0, Scr->FramePadding,
|
|
(unsigned int) Scr->TBInfo.width, (unsigned int) h,
|
|
(unsigned int) 0,
|
|
Scr->d_depth, (unsigned int) CopyFromParent,
|
|
Scr->d_visual, CWBackPixel, &attributes);
|
|
return w;
|
|
}
|
|
|
|
|
|
void ComputeCommonTitleOffsets (void)
|
|
{
|
|
int buttonwidth = (Scr->TBInfo.width + Scr->TBInfo.pad);
|
|
|
|
Scr->TBInfo.leftx = Scr->TBInfo.rightoff = Scr->FramePadding;
|
|
if (Scr->TBInfo.nleft > 0)
|
|
Scr->TBInfo.leftx += Scr->ButtonIndent;
|
|
Scr->TBInfo.titlex = (Scr->TBInfo.leftx +
|
|
(Scr->TBInfo.nleft * buttonwidth) - Scr->TBInfo.pad +
|
|
Scr->TitlePadding);
|
|
if (Scr->TBInfo.nright > 0)
|
|
Scr->TBInfo.rightoff += (Scr->ButtonIndent +
|
|
((Scr->TBInfo.nright * buttonwidth) -
|
|
Scr->TBInfo.pad));
|
|
}
|
|
|
|
void ComputeWindowTitleOffsets (TwmWindow *tmp_win, int width, Bool squeeze)
|
|
{
|
|
tmp_win->highlightx = (Scr->TBInfo.titlex + tmp_win->name_width);
|
|
if (tmp_win->hilite_w || Scr->TBInfo.nright > 0)
|
|
tmp_win->highlightx += Scr->TitlePadding;
|
|
tmp_win->rightx = width - Scr->TBInfo.rightoff;
|
|
if (squeeze && tmp_win->squeeze) {
|
|
int rx = (tmp_win->highlightx +
|
|
(tmp_win->hilite_w
|
|
? Scr->TBInfo.width * 2 : 0) +
|
|
(Scr->TBInfo.nright > 0 ? Scr->TitlePadding : 0) +
|
|
Scr->FramePadding);
|
|
if (rx < tmp_win->rightx)
|
|
tmp_win->rightx = rx;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* calculate the position of the title window. We need to take the frame_bw
|
|
* into account since we want (0,0) of the title window to line up with (0,0)
|
|
* of the frame window.
|
|
*/
|
|
void ComputeTitleLocation(TwmWindow *tmp)
|
|
{
|
|
tmp->title_x = -tmp->frame_bw;
|
|
tmp->title_y = -tmp->frame_bw;
|
|
}
|
|
|
|
|
|
static void CreateWindowTitlebarButtons(TwmWindow *tmp_win)
|
|
{
|
|
unsigned long valuemask; /* mask for create windows */
|
|
XSetWindowAttributes attributes; /* attributes for create windows */
|
|
int leftx, rightx, y;
|
|
TitleButton *tb;
|
|
int nb;
|
|
|
|
if (tmp_win->title_height == 0)
|
|
{
|
|
tmp_win->hilite_w = 0;
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* create the title bar windows; let the event handler deal with painting
|
|
* so that we don't have to spend two pixmaps (or deal with hashing)
|
|
*/
|
|
ComputeWindowTitleOffsets (tmp_win, tmp_win->attr.width, False);
|
|
|
|
leftx = y = Scr->TBInfo.leftx;
|
|
rightx = tmp_win->rightx;
|
|
|
|
attributes.win_gravity = NorthWestGravity;
|
|
attributes.background_pixel = tmp_win->title.back;
|
|
attributes.border_pixel = tmp_win->title.fore;
|
|
attributes.event_mask = (ButtonPressMask | ButtonReleaseMask |
|
|
ExposureMask);
|
|
attributes.cursor = Scr->ButtonCursor;
|
|
valuemask = (CWWinGravity | CWBackPixel | CWBorderPixel | CWEventMask |
|
|
CWCursor);
|
|
|
|
tmp_win->titlebuttons = NULL;
|
|
nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
|
|
if (nb > 0) {
|
|
tmp_win->titlebuttons = malloc (nb * sizeof(TBWindow));
|
|
if (!tmp_win->titlebuttons) {
|
|
fprintf (stderr, "%s: unable to allocate %d titlebuttons\n",
|
|
ProgramName, nb);
|
|
} else {
|
|
TBWindow *tbw;
|
|
int boxwidth = (Scr->TBInfo.width + Scr->TBInfo.pad);
|
|
unsigned int h = (Scr->TBInfo.width - Scr->TBInfo.border * 2);
|
|
|
|
for (tb = Scr->TBInfo.head, tbw = tmp_win->titlebuttons; tb;
|
|
tb = tb->next, tbw++) {
|
|
int x;
|
|
if (tb->rightside) {
|
|
x = rightx;
|
|
rightx += boxwidth;
|
|
attributes.win_gravity = NorthEastGravity;
|
|
} else {
|
|
x = leftx;
|
|
leftx += boxwidth;
|
|
attributes.win_gravity = NorthWestGravity;
|
|
}
|
|
tbw->window = XCreateWindow (dpy, tmp_win->title_w, x, y, h, h,
|
|
(unsigned int) Scr->TBInfo.border,
|
|
0, (unsigned int) CopyFromParent,
|
|
(Visual *) CopyFromParent,
|
|
valuemask, &attributes);
|
|
tbw->info = tb;
|
|
}
|
|
}
|
|
}
|
|
|
|
tmp_win->hilite_w = CreateHighlightWindow(tmp_win);
|
|
|
|
XMapSubwindows(dpy, tmp_win->title_w);
|
|
if (tmp_win->hilite_w)
|
|
XUnmapWindow(dpy, tmp_win->hilite_w);
|
|
}
|
|
|
|
|
|
void
|
|
SetHighlightPixmap (char *filename)
|
|
{
|
|
Pixmap pm = GetBitmap (filename);
|
|
|
|
if (pm) {
|
|
if (Scr->hilitePm) {
|
|
XFreePixmap (dpy, Scr->hilitePm);
|
|
}
|
|
Scr->hilitePm = pm;
|
|
Scr->hilite_pm_width = JunkWidth;
|
|
Scr->hilite_pm_height = JunkHeight;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
FetchWmProtocols (TwmWindow *tmp)
|
|
{
|
|
unsigned long flags = 0L;
|
|
Atom *protocols = NULL;
|
|
int n;
|
|
|
|
if (XGetWMProtocols (dpy, tmp->w, &protocols, &n)) {
|
|
register int i;
|
|
register Atom *ap;
|
|
|
|
for (i = 0, ap = protocols; i < n; i++, ap++) {
|
|
if (*ap == _XA_WM_TAKE_FOCUS) flags |= DoesWmTakeFocus;
|
|
if (*ap == _XA_WM_SAVE_YOURSELF) flags |= DoesWmSaveYourself;
|
|
if (*ap == _XA_WM_DELETE_WINDOW) flags |= DoesWmDeleteWindow;
|
|
}
|
|
if (protocols) XFree (protocols);
|
|
}
|
|
tmp->protocols = flags;
|
|
}
|
|
|
|
TwmColormap *
|
|
CreateTwmColormap(Colormap c)
|
|
{
|
|
TwmColormap *cmap;
|
|
cmap = malloc(sizeof(TwmColormap));
|
|
if (!cmap ||
|
|
XSaveContext(dpy, c, ColormapContext, (caddr_t) cmap)) {
|
|
if (cmap) free(cmap);
|
|
return (NULL);
|
|
}
|
|
cmap->c = c;
|
|
cmap->state = 0;
|
|
cmap->install_req = 0;
|
|
cmap->w = None;
|
|
cmap->refcnt = 1;
|
|
return (cmap);
|
|
}
|
|
|
|
ColormapWindow *
|
|
CreateColormapWindow(Window w, Bool creating_parent, Bool property_window)
|
|
{
|
|
ColormapWindow *cwin;
|
|
TwmColormap *cmap;
|
|
XWindowAttributes attributes;
|
|
|
|
cwin = malloc(sizeof(ColormapWindow));
|
|
if (cwin) {
|
|
if (!XGetWindowAttributes(dpy, w, &attributes) ||
|
|
XSaveContext(dpy, w, ColormapContext, (caddr_t) cwin)) {
|
|
free(cwin);
|
|
return (NULL);
|
|
}
|
|
|
|
if (XFindContext(dpy, attributes.colormap, ColormapContext,
|
|
(caddr_t *)&cwin->colormap) == XCNOENT) {
|
|
cwin->colormap = cmap = CreateTwmColormap(attributes.colormap);
|
|
if (!cmap) {
|
|
XDeleteContext(dpy, w, ColormapContext);
|
|
free(cwin);
|
|
return (NULL);
|
|
}
|
|
} else {
|
|
cwin->colormap->refcnt++;
|
|
}
|
|
|
|
cwin->w = w;
|
|
/*
|
|
* Assume that windows in colormap list are
|
|
* obscured if we are creating the parent window.
|
|
* Otherwise, we assume they are unobscured.
|
|
*/
|
|
cwin->visibility = creating_parent ?
|
|
VisibilityPartiallyObscured : VisibilityUnobscured;
|
|
cwin->refcnt = 1;
|
|
|
|
/*
|
|
* If this is a ColormapWindow property window and we
|
|
* are not monitoring ColormapNotify or VisibilityNotify
|
|
* events, we need to.
|
|
*/
|
|
if (property_window &&
|
|
(attributes.your_event_mask &
|
|
(ColormapChangeMask|VisibilityChangeMask)) !=
|
|
(ColormapChangeMask|VisibilityChangeMask)) {
|
|
XSelectInput(dpy, w, attributes.your_event_mask |
|
|
(ColormapChangeMask|VisibilityChangeMask));
|
|
}
|
|
}
|
|
|
|
return (cwin);
|
|
}
|
|
|
|
void
|
|
FetchWmColormapWindows (TwmWindow *tmp)
|
|
{
|
|
register int i, j;
|
|
Window *cmap_windows = NULL;
|
|
Bool can_free_cmap_windows = False;
|
|
int number_cmap_windows = 0;
|
|
ColormapWindow **cwins = NULL;
|
|
int previously_installed;
|
|
|
|
number_cmap_windows = 0;
|
|
|
|
if (/* SUPPRESS 560 */(previously_installed =
|
|
(Scr->cmapInfo.cmaps == &tmp->cmaps && tmp->cmaps.number_cwins))) {
|
|
cwins = tmp->cmaps.cwins;
|
|
for (i = 0; i < tmp->cmaps.number_cwins; i++)
|
|
cwins[i]->colormap->state = 0;
|
|
}
|
|
|
|
if (XGetWMColormapWindows (dpy, tmp->w, &cmap_windows,
|
|
&number_cmap_windows) &&
|
|
number_cmap_windows > 0) {
|
|
|
|
can_free_cmap_windows = False;
|
|
/*
|
|
* check if the top level is in the list, add to front if not
|
|
*/
|
|
for (i = 0; i < number_cmap_windows; i++) {
|
|
if (cmap_windows[i] == tmp->w) break;
|
|
}
|
|
if (i == number_cmap_windows) { /* not in list */
|
|
Window *new_cmap_windows =
|
|
malloc (sizeof(Window) * (number_cmap_windows + 1));
|
|
|
|
if (!new_cmap_windows) {
|
|
fprintf (stderr,
|
|
"%s: unable to allocate %d element colormap window array\n",
|
|
ProgramName, number_cmap_windows+1);
|
|
goto done;
|
|
}
|
|
new_cmap_windows[0] = tmp->w; /* add to front */
|
|
for (i = 0; i < number_cmap_windows; i++) { /* append rest */
|
|
new_cmap_windows[i+1] = cmap_windows[i];
|
|
}
|
|
XFree (cmap_windows);
|
|
can_free_cmap_windows = True; /* do not use XFree any more */
|
|
cmap_windows = new_cmap_windows;
|
|
number_cmap_windows++;
|
|
}
|
|
|
|
cwins = malloc(sizeof(ColormapWindow *) * number_cmap_windows);
|
|
if (cwins) {
|
|
for (i = 0; i < number_cmap_windows; i++) {
|
|
|
|
/*
|
|
* Copy any existing entries into new list.
|
|
*/
|
|
for (j = 0; j < tmp->cmaps.number_cwins; j++) {
|
|
if (tmp->cmaps.cwins[j]->w == cmap_windows[i]) {
|
|
cwins[i] = tmp->cmaps.cwins[j];
|
|
cwins[i]->refcnt++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If the colormap window is not being pointed by
|
|
* some other applications colormap window list,
|
|
* create a new entry.
|
|
*/
|
|
if (j == tmp->cmaps.number_cwins) {
|
|
if (XFindContext(dpy, cmap_windows[i], ColormapContext,
|
|
(caddr_t *)&cwins[i]) == XCNOENT) {
|
|
if ((cwins[i] = CreateColormapWindow(cmap_windows[i],
|
|
(Bool) tmp->cmaps.number_cwins == 0,
|
|
True)) == NULL) {
|
|
int k;
|
|
for (k = i + 1; k < number_cmap_windows; k++)
|
|
cmap_windows[k-1] = cmap_windows[k];
|
|
i--;
|
|
number_cmap_windows--;
|
|
}
|
|
} else
|
|
cwins[i]->refcnt++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* No else here, in case we bailed out of clause above.
|
|
*/
|
|
if (number_cmap_windows == 0) {
|
|
|
|
number_cmap_windows = 1;
|
|
|
|
cwins = malloc(sizeof(ColormapWindow *));
|
|
if (XFindContext(dpy, tmp->w, ColormapContext, (caddr_t *)&cwins[0]) ==
|
|
XCNOENT) {
|
|
cwins[0] = CreateColormapWindow(tmp->w,
|
|
(Bool) tmp->cmaps.number_cwins == 0, False);
|
|
if (cwins[0] == NULL)
|
|
number_cmap_windows = 0;
|
|
} else
|
|
cwins[0]->refcnt++;
|
|
}
|
|
|
|
if (tmp->cmaps.number_cwins)
|
|
free_cwins(tmp);
|
|
|
|
tmp->cmaps.cwins = cwins;
|
|
tmp->cmaps.number_cwins = number_cmap_windows;
|
|
if (number_cmap_windows > 1)
|
|
tmp->cmaps.scoreboard =
|
|
calloc(1, ColormapsScoreboardLength(&tmp->cmaps));
|
|
|
|
if (previously_installed)
|
|
InstallWindowColormaps(PropertyNotify, (TwmWindow *) NULL);
|
|
|
|
done:
|
|
if (cmap_windows) {
|
|
if (can_free_cmap_windows)
|
|
free (cmap_windows);
|
|
else
|
|
XFree (cmap_windows);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void GetWindowSizeHints (TwmWindow *tmp)
|
|
{
|
|
long supplied = 0;
|
|
|
|
if (!XGetWMNormalHints (dpy, tmp->w, &tmp->hints, &supplied))
|
|
tmp->hints.flags = 0;
|
|
|
|
if (tmp->hints.flags & PResizeInc) {
|
|
if (tmp->hints.width_inc == 0) tmp->hints.width_inc = 1;
|
|
if (tmp->hints.height_inc == 0) tmp->hints.height_inc = 1;
|
|
}
|
|
|
|
if (!(supplied & PWinGravity) && (tmp->hints.flags & USPosition)) {
|
|
static int gravs[] = { SouthEastGravity, SouthWestGravity,
|
|
NorthEastGravity, NorthWestGravity };
|
|
int right = tmp->attr.x + tmp->attr.width + 2 * tmp->old_bw;
|
|
int bottom = tmp->attr.y + tmp->attr.height + 2 * tmp->old_bw;
|
|
tmp->hints.win_gravity =
|
|
gravs[((Scr->MyDisplayHeight - bottom < tmp->title_height) ? 0 : 2) |
|
|
((Scr->MyDisplayWidth - right < tmp->title_height) ? 0 : 1)];
|
|
tmp->hints.flags |= PWinGravity;
|
|
}
|
|
}
|