/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/****************************************************************************
* This module is all original code
* by Rob Nation
* Copyright 1993, Robert Nation
* You may use this code for any purpose, as long as the original
* copyright remains in the source code and all documentation
****************************************************************************/
/***********************************************************************
*
* fvwm window border drawing code
*
***********************************************************************/
#include "config.h"
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include "libs/fvwmlib.h"
#include "libs/FShape.h"
#include "fvwm.h"
#include "externs.h"
#include "events.h"
#include "cursor.h"
#include "functions.h"
#include "bindings.h"
#include "misc.h"
#include "screen.h"
#include "defaults.h"
#include "geometry.h"
#include "borders.h"
#include "builtins.h"
#include "icons.h"
#include "module_interface.h"
#include "libs/Colorset.h"
typedef struct
{
int relief_width;
GC relief_gc;
GC shadow_gc;
Pixel fore_color;
Pixel back_color;
Pixmap back_pixmap;
XSetWindowAttributes attributes;
unsigned long valuemask;
Pixmap texture_pixmap;
XSetWindowAttributes notex_attributes;
unsigned long notex_valuemask;
struct
{
unsigned has_color_changed : 1;
} flags;
} common_decorations_type;
XGCValues Globalgcv;
unsigned long Globalgcm;
extern Window PressedW;
/* used by several drawing functions */
static void ClipClear(Window win, XRectangle *rclip, Bool do_flush_expose)
{
if (rclip)
{
XClearArea(
dpy, win, rclip->x, rclip->y, rclip->width, rclip->height, False);
}
else
{
if (do_flush_expose)
{
flush_expose(win);
}
XClearWindow(dpy, win);
}
return;
}
/***********************************************************************
* change by KitS@bartley.demon.co.uk to correct popups off title buttons
*
* Procedure:
*ButtonPosition - find the actual position of the button
* since some buttons may be disabled
*
* Returned Value:
*The button count from left or right taking in to account
*that some buttons may not be enabled for this window
*
* Inputs:
* context - context as per the global Context
* t - the window (FvwmWindow) to test against
*
***********************************************************************/
int ButtonPosition(int context, FvwmWindow *t)
{
int i = 0;
int buttons = -1;
int end = Scr.nr_left_buttons;
if (context & C_RALL)
{
i = 1;
end = Scr.nr_right_buttons;
}
{
for (; i / 2 < end; i += 2)
{
if (t->button_w[i])
{
buttons++;
}
/* is this the button ? */
if (((1 << i) * C_L1) & context)
return buttons;
}
}
/* you never know... */
return 0;
}
static void change_window_background(
Window w, unsigned long valuemask, XSetWindowAttributes *attributes)
{
XChangeWindowAttributes(dpy, w, valuemask, attributes);
XClearWindow(dpy, w);
}
/****************************************************************************
*
* Draws a little pattern within a window (more complex)
*
****************************************************************************/
static void DrawLinePattern(
Window win, GC ReliefGC, GC ShadowGC, Pixel fore_color, Pixel back_color,
struct vector_coords *coords, int w, int h)
{
int i;
/* It is rare, so evaluate this only when needed */
GC fore_GC = NULL, back_GC = NULL;
if (coords->use_fgbg)
{
Globalgcv.foreground = fore_color;
Globalgcm = GCForeground;
XChangeGC(dpy, Scr.ScratchGC3, Globalgcm, &Globalgcv);
fore_GC = Scr.ScratchGC3;
Globalgcv.foreground = back_color;
XChangeGC(dpy, Scr.ScratchGC4, Globalgcm, &Globalgcv);
back_GC = Scr.ScratchGC4;
}
for (i = 1; i < coords->num; ++i)
{
XDrawLine(dpy,win,
(coords->use_fgbg & (1 << i))
? (coords->line_style & (1 << i)) ? fore_GC : back_GC
: (coords->line_style & (1 << i)) ? ReliefGC : ShadowGC,
w * coords->x[i-1]/100,
h * coords->y[i-1]/100,
w * coords->x[i]/100,
h * coords->y[i]/100);
}
}
/* used by DrawButton() */
static void clip_button_pixmap(
int *ox, int *oy, int *cw, int *ch, int*cx, int *cy, XRectangle *rclip)
{
if (rclip)
{
if (rclip->x > *cx)
{
*ox = (rclip->x - *cx);
*cx += *ox;
*cw -= *ox;
}
if (*cx + *cw > rclip->x + rclip->width)
{
*cw = rclip->x - *cx + rclip->width;
}
if (rclip->y > *cy)
{
*oy = (rclip->y - *cy);
*cy += *oy;
*ch -= *oy;
}
if (*cy + *ch > rclip->y + rclip->height)
{
*ch = rclip->y - *cy + rclip->height;
}
}
return;
}
/****************************************************************************
*
* Redraws buttons (veliaa@rpi.edu)
*
****************************************************************************/
static void DrawButton(
FvwmWindow *t, Window win, int w, int h, DecorFace *df, GC ReliefGC,
GC ShadowGC, Pixel fore_color, Pixel back_color, Bool is_lowest,
mwm_flags stateflags, int left1right0, XRectangle *rclip,
Pixmap *pbutton_background_pixmap)
{
register DecorFaceType type = DFS_FACE_TYPE(df->style);
Picture *p;
int border = 0;
int x;
int y;
int width;
int height;
/* Note: it is assumed that ReliefGC and ShadowGC are already clipped with
* the rclip rectangle when this function is called. */
switch (type)
{
case SimpleButton:
break;
case SolidButton:
if (pbutton_background_pixmap)
{
XSetWindowBackground(dpy, win, df->u.back);
*pbutton_background_pixmap = None;
}
ClipClear(win, rclip, True);
break;
case VectorButton:
case DefaultVectorButton:
if(HAS_MWM_BUTTONS(t) &&
((stateflags & MWM_DECOR_MAXIMIZE && IS_MAXIMIZED(t)) ||
(stateflags & MWM_DECOR_SHADE && IS_SHADED(t)) ||
(stateflags & MWM_DECOR_STICK && IS_STICKY(t))))
{
DrawLinePattern(win, ShadowGC, ReliefGC, fore_color, back_color,
&df->u.vector, w, h);
}
else
{
DrawLinePattern(win, ReliefGC, ShadowGC, fore_color, back_color,
&df->u.vector, w, h);
}
break;
#ifdef MINI_ICONS
case MiniIconButton:
case PixmapButton:
case TiledPixmapButton:
if (type == PixmapButton || type == TiledPixmapButton)
{
p = df->u.p;
}
else
{
if (!t->mini_icon)
break;
p = t->mini_icon;
}
#else
case PixmapButton:
case TiledPixmapButton:
p = df->u.p;
#endif /* MINI_ICONS */
if (DFS_BUTTON_RELIEF(df->style) == DFS_BUTTON_IS_FLAT)
border = 0;
else
border = HAS_MWM_BORDER(t) ? 1 : 2;
x = border;
y = border;
width = w - border * 2;
height = h - border * 2;
if (is_lowest && !p->mask && pbutton_background_pixmap)
{
if (type == TiledPixmapButton ||
(p && p->width >= width && p->height >= height))
{
/* better performance: set a background pixmap if possible, i.e. if the
* decoration is the lowest one in the button and it has no transparent
* parts and it is tiled or bigger than the button */
if (*pbutton_background_pixmap != p->picture)
{
*pbutton_background_pixmap = p->picture;
XSetWindowBackgroundPixmap(dpy, win, p->picture);
ClipClear(win, rclip, True);
}
else
{
ClipClear(win, rclip, True);
}
break;
}
}
else if (pbutton_background_pixmap && *pbutton_background_pixmap != None)
{
XSetWindowBackgroundPixmap(dpy, win, None);
if (pbutton_background_pixmap)
{
*pbutton_background_pixmap = None;
flush_expose(win);
XClearWindow(dpy, win);
}
}
if (type != TiledPixmapButton)
{
if (DFS_H_JUSTIFICATION(df->style) == JUST_RIGHT)
x += (int)(width - p->width);
else if (DFS_H_JUSTIFICATION(df->style) == JUST_CENTER)
/* round up for left buttons, down for right buttons */
x += (int)(width - p->width + left1right0) / 2;
if (DFS_V_JUSTIFICATION(df->style) == JUST_BOTTOM)
y += (int)(height - p->height);
else if (DFS_V_JUSTIFICATION(df->style) == JUST_CENTER)
/* round up */
y += (int)(height - p->height + 1) / 2;
if (x < border)
x = border;
if (y < border)
y = border;
if (width > p->width)
width = p->width;
if (height > p->height)
height = p->height;
if (width > w - x - border)
width = w - x - border;
if (height > h - y - border)
height = h - y - border;
}
XSetClipMask(dpy, Scr.TransMaskGC, p->mask);
XSetClipOrigin(dpy, Scr.TransMaskGC, x, y);
if (type != TiledPixmapButton)
{
int cx = x;
int cy = y;
int cw = width;
int ch = height;
int ox = 0;
int oy = 0;
clip_button_pixmap(&ox, &oy, &cw, &ch, &cx, &cy, rclip);
if (cw > 0 && ch > 0)
{
XCopyArea(
dpy, p->picture, win, Scr.TransMaskGC, ox, oy, cw, ch, cx, cy);
}
}
else
{
int xi;
int yi;
for (yi = border; yi < height; yi += p->height)
{
for (xi = border; xi < width; xi += p->width)
{
int lw = width - xi;
int lh = height - yi;
int cx;
int cy;
int cw;
int ch;
int ox;
int oy;
if (lw > p->width)
lw = p->width;
if (lh > p->height)
lh = p->height;
if (rclip)
{
if (xi + lw <= rclip->x || xi >= rclip->x + rclip->width ||
yi + lh <= rclip->y || yi >= rclip->y + rclip->height)
{
continue;
}
}
cx = xi;
cy = yi;
cw = lw;
ch = lh;
ox = 0;
oy = 0;
clip_button_pixmap(&ox, &oy, &cw, &ch, &cx, &cy, rclip);
if (cw > 0 && ch > 0)
{
XSetClipOrigin(dpy, Scr.TransMaskGC, xi, yi);
XCopyArea(dpy, p->picture, win, Scr.TransMaskGC,
ox, oy, cw, ch, cx, cy);
}
}
}
}
XSetClipMask(dpy, Scr.TransMaskGC, None);
break;
case GradientButton:
{
unsigned int g_width;
unsigned int g_height;
if (!rclip)
{
flush_expose(win);
}
XSetClipMask(dpy, Scr.TransMaskGC, None);
/* find out the size the pixmap should be */
CalculateGradientDimensions(
dpy, win, df->u.grad.npixels, df->u.grad.gradient_type,
&g_width, &g_height);
/* draw the gradient directly into the window */
CreateGradientPixmap(
dpy, win, Scr.TransMaskGC, df->u.grad.gradient_type, g_width, g_height,
df->u.grad.npixels, df->u.grad.pixels, win, 0, 0, w, h, rclip);
}
break;
default:
fvwm_msg(ERR, "DrawButton", "unknown button type");
break;
}
return;
}
/* rules to get button state */
static enum ButtonState get_button_state(
Bool has_focus, Bool toggled, Window w)
{
if (Scr.gs.use_active_down_buttons)
{
if (Scr.gs.use_inactive_buttons && !has_focus)
{
return (toggled) ? BS_ToggledInactive : BS_Inactive;
}
else
{
if (PressedW == w)
{
return (toggled) ? BS_ToggledActiveDown : BS_ActiveDown;
}
else
{
return (toggled) ? BS_ToggledActiveUp : BS_ActiveUp;
}
}
}
else
{
if (Scr.gs.use_inactive_buttons && !has_focus)
{
return (toggled) ? BS_ToggledInactive : BS_Inactive;
}
else
{
return (toggled) ? BS_ToggledActiveUp : BS_ActiveUp;
}
}
}
static const char ulgc[] = { 1, 0, 0, 0x7f, 2, 1, 1 };
static const char brgc[] = { 1, 1, 2, 0x7f, 0, 0, 3 };
/* called twice by RedrawBorder */
static void draw_frame_relief(
FvwmWindow *t, GC rgc, GC sgc, GC tgc, GC dgc, int w_dout, int w_hiout,
int w_trout, int w_c, int w_trin, int w_shin, int w_din)
{
int i;
int offset = 0;
int width = t->frame_g.width - 1;
int height = t->frame_g.height - 1;
int w[7];
GC gc[4];
w[0] = w_dout;
w[1] = w_hiout;
w[2] = w_trout;
w[3] = w_c;
w[4] = w_trin;
w[5] = w_shin;
w[6] = w_din;
gc[0] = rgc;
gc[1] = sgc;
gc[2] = tgc;
gc[3] = dgc;
for (i = 0; i < 7; i++)
{
if (ulgc[i] != 0x7f && w[i] > 0)
{
RelieveRectangle(
dpy, t->decor_w, offset, offset, width, height, gc[(int)ulgc[i]],
gc[(int)brgc[i]], w[i]);
}
offset += w[i];
width -= 2 * w[i];
height -= 2 * w[i];
}
}
/****************************************************************************
*
* Redraws the windows borders
*
****************************************************************************/
static void RedrawBorder(
common_decorations_type *cd, FvwmWindow *t, Bool has_focus, int force,
Window expose_win, XRectangle *rclip)
{
static GC tgc = None;
int i;
GC rgc;
GC sgc;
DecorFaceStyle *borderstyle;
Bool is_reversed = False;
Bool is_clipped = False;
int w_dout;
int w_hiout;
int w_trout;
int w_c;
int w_trin;
int w_shin;
int w_din;
int sum;
int trim;
if (tgc == None && !HAS_MWM_BORDER(t))
{
XGCValues xgcv;
xgcv.function = GXnoop;
xgcv.plane_mask = 0;
tgc = fvwmlib_XCreateGC(dpy, t->frame, GCFunction | GCPlaneMask, &xgcv);
}
/*
* draw the border; resize handles are InputOnly so draw in the decor_w and
* it will show through. The entire border is redrawn so flush all exposes
* up to this point.
*/
#if 0
flush_expose(t->decor_w);
#endif
if (t->boundary_width < 2)
{
/*
* for mono - put a black border on
*/
if (Pdepth <2)
{
XSetWindowBackgroundPixmap(dpy, t->decor_w, cd->back_pixmap);
XClearWindow(dpy, t->decor_w);
}
else
{
if (cd->texture_pixmap != None)
XSetWindowBackgroundPixmap(dpy, t->decor_w, cd->texture_pixmap);
XClearWindow(dpy, t->decor_w);
}
return;
}
/*
* for color, make it the color of the decoration background
*/
/* get the border style bits */
borderstyle = (has_focus) ?
&GetDecor(t, BorderStyle.active.style) :
&GetDecor(t, BorderStyle.inactive.style);
is_reversed ^= (borderstyle->flags.button_relief == DFS_BUTTON_IS_SUNK);
if (is_reversed)
{
sgc = cd->relief_gc;
rgc = cd->shadow_gc;
}
else
{
rgc = cd->relief_gc;
sgc = cd->shadow_gc;
}
/*
* remove any lines drawn in the border if hidden handles or noinset and if
* a handle was pressed
*/
if (PressedW == None &&
(DFS_HAS_NO_INSET(*borderstyle) ||
DFS_HAS_HIDDEN_HANDLES(*borderstyle)))
{
ClipClear(t->decor_w, rclip, False);
}
/*
* Nothing to do if flat
*/
if (borderstyle->flags.button_relief == DFS_BUTTON_IS_FLAT)
return;
/*
* draw the inside relief
*/
if (HAS_MWM_BORDER(t))
{
/* MWM borders look like this:
*
* HHCCCCS from outside to inside on the left and top border
* SSCCCCH from outside to inside on the bottom and right border
* |||||||
* |||||||__ w_shin (inner shadow area)
* ||||||___ w_c (transparent area)
* |||||____ w_c (transparent area)
* ||||_____ w_c (transparent area)
* |||______ w_c (transparent area)
* ||_______ w_hiout (outer hilight area)
* |________ w_hiout (outer hilight area)
*
*
* C = original colour
* H = hilight
* S = shadow
*/
w_dout = 0;
w_hiout = 2;
w_trout = 0;
w_trin = 0;
w_shin = 1;
w_din = 0;
sum = 3;
trim = sum - t->boundary_width + 1;
}
else
{
/* Fvwm borders look like this:
*
* SHHCCSS from outside to inside on the left and top border
* SSCCHHS from outside to inside on the bottom and right border
* |||||||
* |||||||__ w_din (inner dark area)
* ||||||___ w_shin (inner shadow area)
* |||||____ w_trin (inner transparent/shadow area)
* ||||_____ w_c (transparent area)
* |||______ w_trout (outer transparent/hilight area)
* ||_______ w_hiout (outer hilight area)
* |________ w_dout (outer dark area)
*
* C = original colour
* H = hilight
* S = shadow
*
* reduced to 5 pixels it looks like this:
*
* SHHCS
* SSCHS
* |||||
* |||||__ w_din (inner dark area)
* ||||___ w_trin (inner transparent/shadow area)
* |||____ w_trout (outer transparent/hilight area)
* ||_____ w_hiout (outer hilight area)
* |______ w_dout (outer dark area)
*/
w_dout = 1;
w_hiout = 1;
w_trout = 1;
w_trin = 1;
w_shin = 1;
w_din = 1;
/* w_trout + w_trin counts only as one pixel of border because they let one
* pixel of the original colour shine through. */
sum = 6;
trim = sum - t->boundary_width;
}
if (DFS_HAS_NO_INSET(*borderstyle))
{
w_shin = 0;
sum--;
trim--;
if (w_trin)
{
w_trout = 0;
w_trin = 0;
w_din = 0;
w_hiout = 1;
sum -= 2;
trim -= 2;
}
}
/* If the border is too thin to accomodate the standard look, we remove parts
* of the border so that at least one pixel of the original colour is
* visible. We make an exception for windows with a border width of 2,
* though. */
if ((!IS_SHADED(t) || HAS_TITLE(t)) && t->boundary_width == 2)
trim--;
if (trim < 0)
trim = 0;
for ( ; trim > 0; trim--)
{
if (w_hiout > 1)
w_hiout--;
else if (w_shin > 0)
w_shin--;
else if (w_hiout > 0)
w_hiout--;
else if (w_trout > 0)
{
w_trout = 0;
w_trin = 0;
w_din = 0;
w_hiout = 1;
}
sum--;
}
w_c = t->boundary_width - sum;
if (rclip)
{
XSetClipRectangles(dpy, rgc, 0, 0, rclip, 1, Unsorted);
XSetClipRectangles(dpy, sgc, 0, 0, rclip, 1, Unsorted);
is_clipped = True;
}
draw_frame_relief(
t, rgc, sgc, tgc, sgc,
w_dout, w_hiout, w_trout, w_c, w_trin, w_shin, w_din);
/*
* draw the handle marks
*/
/* draw the handles as eight marks around the border */
if (HAS_BORDER(t) && (t->boundary_width > 1) &&
!DFS_HAS_HIDDEN_HANDLES(*borderstyle))
{
/* MWM border windows have thin 3d effects
* FvwmBorders have 3 pixels top/left, 2 bot/right so this makes
* calculating the length of the marks difficult, top and bottom
* marks for FvwmBorders are different if NoInset is specified */
int inset = (w_shin || w_din);
XSegment marks[8];
int k;
/*
* draw the relief
*/
for (k = 0; k < cd->relief_width; k++)
{
int loff = k;
int boff = k + w_dout + 1;
int length = t->boundary_width - boff - inset;
if (length < 0)
break;
/* hilite marks */
i = 0;
/* top left */
marks[i].x1 = t->visual_corner_width + loff;
marks[i].x2 = t->visual_corner_width + loff;
marks[i].y1 = w_dout;
marks[i].y2 = marks[i].y1 + length;
i++;
/* top right */
marks[i].x1 = t->frame_g.width - t->visual_corner_width + loff;
marks[i].x2 = t->frame_g.width - t->visual_corner_width + loff;
marks[i].y1 = w_dout;
marks[i].y2 = marks[i].y1 + length;
i++;
/* bot left */
marks[i].x1 = t->visual_corner_width + loff;
marks[i].x2 = t->visual_corner_width + loff;
marks[i].y1 = t->frame_g.height - boff;
marks[i].y2 = marks[i].y1 - length;
i++;
/* bot right */
marks[i].x1 = t->frame_g.width - t->visual_corner_width + loff;
marks[i].x2 = t->frame_g.width - t->visual_corner_width + loff;
marks[i].y1 = t->frame_g.height - boff;
marks[i].y2 = marks[i].y1 - length;
i++;
if (!IS_SHADED(t))
{
/* left top */
marks[i].x1 = w_dout;
marks[i].x2 = marks[i].x1 + length;
marks[i].y1 = t->visual_corner_width + loff;
marks[i].y2 = t->visual_corner_width + loff;
i++;
/* left bot */
marks[i].x1 = w_dout;
marks[i].x2 = marks[i].x1 + length;
marks[i].y1 = t->frame_g.height-t->visual_corner_width + loff;
marks[i].y2 = t->frame_g.height-t->visual_corner_width + loff;
i++;
/* right top */
marks[i].x1 = t->frame_g.width - boff;
marks[i].x2 = marks[i].x1 - length;
marks[i].y1 = t->visual_corner_width + loff;
marks[i].y2 = t->visual_corner_width + loff;
i++;
/* right bot */
marks[i].x1 = t->frame_g.width - boff;
marks[i].x2 = marks[i].x1 - length;
marks[i].y1 = t->frame_g.height-t->visual_corner_width + loff;
marks[i].y2 = t->frame_g.height-t->visual_corner_width + loff;
i++;
}
XDrawSegments(dpy, t->decor_w, rgc, marks, i);
/* shadow marks, reuse the array (XDrawSegments doesn't trash it) */
i = 0;
loff = 1 + k + k;
/* top left */
marks[i].x1 -= loff;
marks[i].x2 -= loff;
marks[i].y1 += k;
marks[i].y2 += k;
i++;
/* top right */
marks[i].x1 -= loff;
marks[i].x2 -= loff;
marks[i].y1 += k;
marks[i].y2 += k;
i++;
/* bot left */
marks[i].x1 -= loff;
marks[i].x2 -= loff;
marks[i].y1 += k;
marks[i].y2 += k;
i++;
/* bot right */
marks[i].x1 -= loff;
marks[i].x2 -= loff;
marks[i].y1 += k;
marks[i].y2 += k;
i++;
if (!IS_SHADED(t))
{
/* left top */
marks[i].x1 += k;
marks[i].x2 += k;
marks[i].y1 -= loff;
marks[i].y2 -= loff;
i++;
/* left bot */
marks[i].x1 += k;
marks[i].x2 += k;
marks[i].y1 -= loff;
marks[i].y2 -= loff;
i++;
/* right top */
marks[i].x1 += k;
marks[i].x2 += k;
marks[i].y1 -= loff;
marks[i].y2 -= loff;
i++;
/* right bot */
marks[i].x1 += k;
marks[i].x2 += k;
marks[i].y1 -= loff;
marks[i].y2 -= loff;
i++;
}
XDrawSegments(dpy, t->decor_w, sgc, marks, i);
}
}
/*
* now draw the pressed in part on top if we have depressable borders
*/
/* a bit hacky to draw twice but you should see the code it replaces, never
* mind the esoterics, feel the thin-ness */
if ((HAS_BORDER(t) || PressedW == t->decor_w || PressedW == t->frame) &&
HAS_DEPRESSABLE_BORDER(t))
{
XRectangle r;
Bool is_pressed = False;
if (PressedW == t->sides[0])
{
/* top */
r.x = t->visual_corner_width;
r.y = 1;
r.width = t->frame_g.width - 2 * t->visual_corner_width;
r.height = t->boundary_width - 1;
is_pressed = True;
}
else if (PressedW == t->sides[1])
{
/* right */
if (!IS_SHADED(t))
{
r.x = t->frame_g.width - t->boundary_width;
r.y = t->visual_corner_width;
r.width = t->boundary_width - 1;
r.height = t->frame_g.height - 2 * t->visual_corner_width;
is_pressed = True;
}
}
else if (PressedW == t->sides[2])
{
/* bottom */
r.x = t->visual_corner_width;
r.y = t->frame_g.height - t->boundary_width;
r.width = t->frame_g.width - 2 * t->visual_corner_width;
r.height = t->boundary_width - 1;
is_pressed = True;
}
else if (PressedW == t->sides[3])
{
/* left */
if (!IS_SHADED(t))
{
r.x = 1;
r.y = t->visual_corner_width;
r.width = t->boundary_width - 1;
r.height = t->frame_g.height - 2 * t->visual_corner_width;
is_pressed = True;
}
}
else if (PressedW == t->corners[0])
{
/* top left */
r.x = 1;
r.y = 1;
r.width = t->visual_corner_width - 1;
r.height = t->visual_corner_width - 1;
is_pressed = True;
}
else if (PressedW == t->corners[1])
{
/* top right */
r.x = t->frame_g.width - t->visual_corner_width;
r.y = 1;
r.width = t->visual_corner_width - 1;
r.height = t->visual_corner_width - 1;
is_pressed = True;
}
else if (PressedW == t->corners[2])
{
/* bottom left */
r.x = 1;
r.y = t->frame_g.height - t->visual_corner_width;
r.width = t->visual_corner_width - 1;
r.height = t->visual_corner_width - 1;
is_pressed = True;
}
else if (PressedW == t->corners[3])
{
/* bottom right */
r.x = t->frame_g.width - t->visual_corner_width;
r.y = t->frame_g.height - t->visual_corner_width;
r.width = t->visual_corner_width - 1;
r.height = t->visual_corner_width - 1;
is_pressed = True;
}
else if (PressedW == t->decor_w || PressedW == t->frame)
{
/* whole border */
r.x = 1;
r.y = 1;
r.width = t->frame_g.width - 2;
r.height = t->frame_g.height - 2;
is_pressed = True;
}
if (is_pressed == True)
{
Bool is_not_empty = True;
if (rclip)
{
is_not_empty = intersect_xrectangles(&r, rclip);
}
if (is_not_empty)
{
XSetClipRectangles(dpy, rgc, 0, 0, &r, 1, Unsorted);
XSetClipRectangles(dpy, sgc, 0, 0, &r, 1, Unsorted);
draw_frame_relief(
t, sgc, rgc, tgc, sgc,
w_dout, w_hiout, w_trout, w_c, w_trin, w_shin, w_din);
is_clipped = True;
}
}
}
if (is_clipped)
{
XSetClipMask(dpy, rgc, None);
XSetClipMask(dpy, sgc, None);
}
return;
}
/****************************************************************************
*
* Redraws the window buttons
*
****************************************************************************/
static void RedrawButtons(
common_decorations_type *cd, FvwmWindow *t, Bool has_focus, int force,
Window expose_win, XRectangle *rclip)
{
int i;
Bool is_lowest = True;
Pixmap *pass_bg_pixmap;
/* Note: the rclip rectangle is not used in this function. Buttons are usually
* so small that it makes not much sense to limit drawing to a clip rectangle.
*/
/*
* draw buttons
*/
for (i = 0; i < NUMBER_OF_BUTTONS; i++)
{
if (t->button_w[i] != None && (((i & 1) && i / 2 < Scr.nr_right_buttons) ||
(!(i & 1) && i / 2 < Scr.nr_left_buttons)))
{
mwm_flags stateflags =
TB_MWM_DECOR_FLAGS(GetDecor(t, buttons[i]));
Bool toggled =
(HAS_MWM_BUTTONS(t) &&
((stateflags & MWM_DECOR_MAXIMIZE && IS_MAXIMIZED(t)) ||
(stateflags & MWM_DECOR_SHADE && IS_SHADED(t)) ||
(stateflags & MWM_DECOR_STICK && IS_STICKY(t))));
enum ButtonState bs =
get_button_state(has_focus, toggled, t->button_w[i]);
DecorFace *df = &TB_STATE(GetDecor(t, buttons[i]))[bs];
if(flush_expose(t->button_w[i]) || expose_win == t->button_w[i] ||
expose_win == None || cd->flags.has_color_changed)
{
int is_inverted = (PressedW == t->button_w[i]);
if (DFS_USE_BORDER_STYLE(df->style))
{
XChangeWindowAttributes(
dpy, t->button_w[i], cd->valuemask, &cd->attributes);
if (df->u.p)
{
t->button_background_pixmap[i] = df->u.p->picture;
}
if (df->u.p && df->u.p->picture)
{
pass_bg_pixmap = NULL;
}
else
{
pass_bg_pixmap = &t->button_background_pixmap[i];
}
}
else
{
XChangeWindowAttributes(
dpy, t->button_w[i], cd->notex_valuemask, &cd->notex_attributes);
t->button_background_pixmap[i] = None;
pass_bg_pixmap = &t->button_background_pixmap[i];
}
XClearWindow(dpy, t->button_w[i]);
if (DFS_USE_TITLE_STYLE(df->style))
{
DecorFace *tsdf = &TB_STATE(GetDecor(t, titlebar))[bs];
is_lowest = True;
#ifdef MULTISTYLE
for (; tsdf; tsdf = tsdf->next)
#endif
{
DrawButton(t, t->button_w[i], t->title_g.height, t->title_g.height,
tsdf, cd->relief_gc, cd->shadow_gc,
cd->fore_color, cd->back_color, is_lowest,
TB_MWM_DECOR_FLAGS(GetDecor(t, buttons[i])), 1, NULL,
pass_bg_pixmap);
is_lowest = False;
}
}
is_lowest = True;
#ifdef MULTISTYLE
for (; df; df = df->next)
#endif
{
DrawButton(t, t->button_w[i], t->title_g.height, t->title_g.height,
df, cd->relief_gc, cd->shadow_gc,
cd->fore_color, cd->back_color, is_lowest,
TB_MWM_DECOR_FLAGS(GetDecor(t, buttons[i])), 1, NULL,
pass_bg_pixmap);
is_lowest = False;
}
{
Bool reverse = is_inverted;
switch (DFS_BUTTON_RELIEF(
TB_STATE(GetDecor(t, buttons[i]))[bs].style))
{
case DFS_BUTTON_IS_SUNK:
reverse = !is_inverted;
case DFS_BUTTON_IS_UP:
RelieveRectangle2(
dpy, t->button_w[i], 0, 0, t->title_g.height - 1,
t->title_g.height - 1, (reverse ? cd->shadow_gc : cd->relief_gc),
(reverse ? cd->relief_gc : cd->shadow_gc), cd->relief_width);
break;
default:
/* flat */
break;
}
}
}
} /* if (HAS_BUTTON(i))*/
} /* for */
}
/****************************************************************************
*
* Redraws just the title bar
*
****************************************************************************/
static void RedrawTitle(
common_decorations_type *cd, FvwmWindow *t, Bool has_focus, XRectangle *rclip)
{
int hor_off;
int w;
int i;
enum ButtonState title_state;
DecorFaceStyle *tb_style;
Pixmap *pass_bg_pixmap;
GC rgc = cd->relief_gc;
GC sgc = cd->shadow_gc;
Bool reverse = False;
Bool is_clipped = False;
Bool toggled =
(HAS_MWM_BUTTONS(t) &&
((TB_HAS_MWM_DECOR_MAXIMIZE(GetDecor(t, titlebar)) && IS_MAXIMIZED(t))||
(TB_HAS_MWM_DECOR_SHADE(GetDecor(t, titlebar)) && IS_SHADED(t)) ||
(TB_HAS_MWM_DECOR_STICK(GetDecor(t, titlebar)) && IS_STICKY(t))));
if (PressedW == t->title_w)
{
GC tgc;
tgc = sgc;
sgc = rgc;
rgc = tgc;
}
#if 0
flush_expose(t->title_w);
#endif
if (t->name != (char *)NULL)
{
#ifdef I18N_MB /* cannot use macro here, rewriting... */
w = XmbTextEscapement(t->title_font.fontset,t->name, strlen(t->name));
#else
w = XTextWidth(t->title_font.font, t->name, strlen(t->name));
#endif
if (w > t->title_g.width - 12)
w = t->title_g.width - 4;
if (w < 0)
w = 0;
}
else
{
w = 0;
}
title_state = get_button_state(has_focus, toggled, t->title_w);
tb_style = &TB_STATE(GetDecor(t, titlebar))[title_state].style;
switch (TB_JUSTIFICATION(GetDecor(t, titlebar)))
{
case JUST_LEFT:
hor_off = WINDOW_TITLE_TEXT_OFFSET;
break;
case JUST_RIGHT:
hor_off = t->title_g.width - w - WINDOW_TITLE_TEXT_OFFSET;
break;
case JUST_CENTER:
default:
hor_off = (t->title_g.width - w) / 2;
break;
}
NewFontAndColor(
t->title_font.font->fid, cd->fore_color, cd->back_color);
/* the next bit tries to minimize redraw (veliaa@rpi.edu) */
/* we need to check for UseBorderStyle for the titlebar */
{
DecorFace *df = (has_focus) ?
&GetDecor(t,BorderStyle.active) : &GetDecor(t,BorderStyle.inactive);
if (DFS_USE_BORDER_STYLE(*tb_style) &&
DFS_FACE_TYPE(df->style) == TiledPixmapButton &&
df->u.p)
{
XSetWindowBackgroundPixmap(dpy, t->title_w, df->u.p->picture);
t->title_background_pixmap = df->u.p->picture;
pass_bg_pixmap = NULL;
}
else
{
pass_bg_pixmap = &t->title_background_pixmap;
}
}
ClipClear(t->title_w, rclip, False);
if (rclip)
{
XSetClipRectangles(dpy, rgc, 0, 0, rclip, 1, Unsorted);
XSetClipRectangles(dpy, sgc, 0, 0, rclip, 1, Unsorted);
XSetClipRectangles(dpy, Scr.TitleGC, 0, 0, rclip, 1, Unsorted);
is_clipped = True;
}
/*
* draw title
*/
if (Pdepth < 2)
{
/* for mono, we clear an area in the title bar where the window
* title goes, so that its more legible. For color, no need */
RelieveRectangle(
dpy, t->title_w, 0, 0, hor_off - 3, t->title_g.height - 1, rgc, sgc,
cd->relief_width);
RelieveRectangle(
dpy, t->title_w, hor_off + w + 2, 0, t->title_g.width - w - hor_off - 3,
t->title_g.height - 1, rgc, sgc, cd->relief_width);
XFillRectangle(
dpy, t->title_w, ((PressedW == t->title_w) ? sgc : rgc), hor_off - 2, 0,
w+4,t->title_g.height);
XDrawLine(
dpy, t->title_w, sgc, hor_off + w + 1, 0, hor_off + w + 1,
t->title_g.height);
if(t->name != (char *)NULL)
#ifdef I18N_MB
XmbDrawString(dpy, t->title_w, t->title_font.fontset,
Scr.TitleGC, hor_off,
t->title_font.y + 1, t->name, strlen(t->name));
#else
XDrawString(dpy, t->title_w, Scr.TitleGC, hor_off,
t->title_font.y + 1, t->name, strlen(t->name));
#endif
}
else
{
DecorFace *df = &TB_STATE(GetDecor(t, titlebar))[title_state];
/* draw compound titlebar (veliaa@rpi.edu) */
Bool is_lowest = True;
if (PressedW == t->title_w)
{
#ifdef MULTISTYLE
for (; df; df = df->next)
#endif
{
DrawButton(
t, t->title_w, t->title_g.width, t->title_g.height, df, sgc,
rgc, cd->fore_color, cd->back_color, is_lowest, 0, 1, rclip,
pass_bg_pixmap);
is_lowest = False;
}
}
else
{
#ifdef MULTISTYLE
for (; df; df = df->next)
#endif
{
DrawButton(
t, t->title_w, t->title_g.width, t->title_g.height, df, rgc,
sgc, cd->fore_color, cd->back_color, is_lowest, 0, 1, rclip,
pass_bg_pixmap);
is_lowest = False;
}
}
/*
* draw title relief
*/
switch (DFS_BUTTON_RELIEF(*tb_style))
{
case DFS_BUTTON_IS_SUNK:
reverse = 1;
case DFS_BUTTON_IS_UP:
RelieveRectangle2(
dpy, t->title_w, 0, 0, t->title_g.width - 1, t->title_g.height - 1,
(reverse) ? sgc : rgc, (reverse) ? rgc : sgc, cd->relief_width);
break;
default:
/* flat */
break;
}
#ifdef I18N_MB
if(t->name != (char *)NULL)
XmbDrawString(dpy, t->title_w, t->title_font.fontset,
Scr.TitleGC, hor_off,
t->title_font.y + 1, t->name, strlen(t->name));
#else
if(t->name != (char *)NULL)
XDrawString(dpy, t->title_w, Scr.TitleGC, hor_off,
t->title_font.y + 1, t->name, strlen(t->name));
#endif
}
/*
* draw the 'sticky' lines
*/
if (IS_STICKY(t) || HAS_STIPPLED_TITLE(t))
{
/* an odd number of lines every WINDOW_TITLE_STICK_VERT_DIST pixels */
int num =
(int)(t->title_g.height / WINDOW_TITLE_STICK_VERT_DIST / 2) * 2 - 1;
int min = t->title_g.height / 2 - num * 2 + 1;
int max =
t->title_g.height / 2 + num * 2 - WINDOW_TITLE_STICK_VERT_DIST + 1;
int left_x = WINDOW_TITLE_STICK_OFFSET;
int left_w = hor_off - left_x - WINDOW_TITLE_TO_STICK_GAP;
int right_x = hor_off + w + WINDOW_TITLE_TO_STICK_GAP - 1;
int right_w = t->title_g.width - right_x - WINDOW_TITLE_STICK_OFFSET;
if (left_w < WINDOW_TITLE_STICK_MIN_WIDTH)
{
left_x = 0;
left_w = WINDOW_TITLE_STICK_MIN_WIDTH;
}
if (right_w < WINDOW_TITLE_STICK_MIN_WIDTH)
{
right_w = WINDOW_TITLE_STICK_MIN_WIDTH;
right_x = t->title_g.width - WINDOW_TITLE_STICK_MIN_WIDTH - 1;
}
for (i = min; i <= max; i += WINDOW_TITLE_STICK_VERT_DIST)
{
if (left_w > 0)
{
RelieveRectangle(
dpy, t->title_w, left_x, i, left_w, 1, sgc, rgc, 1);
}
if (right_w > 0)
{
RelieveRectangle(
dpy, t->title_w, right_x, i, right_w, 1, sgc, rgc, 1);
}
}
}
if (is_clipped)
{
XSetClipMask(dpy, rgc, None);
XSetClipMask(dpy, sgc, None);
XSetClipMask(dpy, Scr.TitleGC, None);
}
return;
}
void SetupTitleBar(FvwmWindow *tmp_win, int w, int h)
{
XWindowChanges xwc;
unsigned long xwcm;
int i;
int buttons = 0;
int ww = tmp_win->frame_g.width - 2 * tmp_win->boundary_width;
int rest = 0;
int bw;
if (HAS_BOTTOM_TITLE(tmp_win))
{
tmp_win->title_g.y =
h - tmp_win->boundary_width - tmp_win->title_g.height;
tmp_win->title_top_height = 0;
}
else
{
tmp_win->title_g.y = tmp_win->boundary_width;
tmp_win->title_top_height = tmp_win->title_g.height;
}
tmp_win->title_g.x = tmp_win->boundary_width;
xwcm = CWX | CWY | CWHeight | CWWidth;
xwc.y = tmp_win->title_g.y;
xwc.width = tmp_win->title_g.height;
xwc.height = tmp_win->title_g.height;
for (i = 0; i < NUMBER_OF_BUTTONS; i++)
{
if (tmp_win->button_w[i])
buttons++;
}
ww = tmp_win->frame_g.width - 2 * tmp_win->boundary_width -
tmp_win->title_g.width;
if (ww < buttons * xwc.width)
{
xwc.width = ww / buttons;
if (xwc.width < 1)
xwc.width = 1;
if (xwc.width > tmp_win->title_g.height)
xwc.width = tmp_win->title_g.height;
rest = ww - buttons * xwc.width;
if (rest > 0)
xwc.width++;
}
/* left */
xwc.x = tmp_win->boundary_width;
for (i = 0; i < NUMBER_OF_BUTTONS; i += 2)
{
if (tmp_win->button_w[i] != None)
{
if (xwc.x + xwc.width < w - tmp_win->boundary_width)
{
XConfigureWindow(dpy, tmp_win->button_w[i], xwcm, &xwc);
xwc.x += xwc.width;
tmp_win->title_g.x += xwc.width;
}
else
{
xwc.x = -tmp_win->title_g.height;
XConfigureWindow(dpy, tmp_win->button_w[i], xwcm, &xwc);
}
rest--;
if (rest == 0)
{
xwc.width--;
}
}
}
bw = xwc.width;
/* title */
if (tmp_win->title_g.width <= 0 || ww < 0)
tmp_win->title_g.x = -10;
xwc.x = tmp_win->title_g.x;
xwc.width = tmp_win->title_g.width;
XConfigureWindow(dpy, tmp_win->title_w, xwcm, &xwc);
/* right */
xwc.width = bw;
xwc.x = w - tmp_win->boundary_width - xwc.width;
for (i = 1 ; i < NUMBER_OF_BUTTONS; i += 2)
{
if (tmp_win->button_w[i] != None)
{
if (xwc.x > tmp_win->boundary_width)
{
XConfigureWindow(dpy, tmp_win->button_w[i], xwcm, &xwc);
xwc.x -= xwc.width;
}
else
{
xwc.x = -tmp_win->title_g.height;
XConfigureWindow(dpy, tmp_win->button_w[i], xwcm, &xwc);
}
rest--;
if (rest == 0)
{
xwc.width--;
xwc.x++;
}
}
}
return;
}
static void get_common_decorations(
common_decorations_type *cd, FvwmWindow *t, draw_window_parts draw_parts,
Bool has_focus, int force, Window expose_win, Bool is_border,
Bool do_change_gcs)
{
color_quad *draw_colors;
if (has_focus)
{
/* are we using textured borders? */
if (DFS_FACE_TYPE(
GetDecor(t, BorderStyle.active.style)) == TiledPixmapButton)
{
cd->texture_pixmap = GetDecor(t, BorderStyle.active.u.p->picture);
}
cd->back_pixmap= Scr.gray_pixmap;
if (is_border)
draw_colors = &(t->border_hicolors);
else
draw_colors = &(t->hicolors);
}
else
{
if (DFS_FACE_TYPE(GetDecor(t, BorderStyle.inactive.style)) ==
TiledPixmapButton)
{
cd->texture_pixmap = GetDecor(t, BorderStyle.inactive.u.p->picture);
}
if(IS_STICKY(t))
cd->back_pixmap = Scr.sticky_gray_pixmap;
else
cd->back_pixmap = Scr.light_gray_pixmap;
if (is_border)
draw_colors = &(t->border_colors);
else
draw_colors = &(t->colors);
}
cd->fore_color = draw_colors->fore;
cd->back_color = draw_colors->back;
if (do_change_gcs)
{
Globalgcv.foreground = draw_colors->hilight;
Globalgcm = GCForeground;
XChangeGC(dpy, Scr.ScratchGC1, Globalgcm, &Globalgcv);
cd->relief_gc = Scr.ScratchGC1;
Globalgcv.foreground = draw_colors->shadow;
XChangeGC(dpy, Scr.ScratchGC2, Globalgcm, &Globalgcv);
cd->shadow_gc = Scr.ScratchGC2;
}
/* MWMBorder style means thin 3d effects */
cd->relief_width = (HAS_MWM_BORDER(t) ? 1 : 2);
if (cd->texture_pixmap)
{
cd->attributes.background_pixmap = cd->texture_pixmap;
cd->valuemask = CWBackPixmap;
if (Pdepth < 2)
{
cd->notex_attributes.background_pixmap = cd->back_pixmap;
cd->notex_valuemask = CWBackPixmap;
}
else
{
cd->notex_attributes.background_pixel = cd->back_color;
cd->notex_valuemask = CWBackPixel;
}
}
else
{
if (Pdepth < 2)
{
cd->attributes.background_pixmap = cd->back_pixmap;
cd->valuemask = CWBackPixmap;
cd->notex_attributes.background_pixmap = cd->back_pixmap;
cd->notex_valuemask = CWBackPixmap;
}
else
{
cd->attributes.background_pixel = cd->back_color;
cd->valuemask = CWBackPixel;
cd->notex_attributes.background_pixel = cd->back_color;
cd->notex_valuemask = CWBackPixel;
}
}
}
void draw_clipped_decorations(
FvwmWindow *t, draw_window_parts draw_parts, Bool has_focus, int force,
Window expose_win, XRectangle *rclip)
{
common_decorations_type cd;
Bool is_frame_redraw_allowed = False;
Bool is_button_redraw_allowed = False;
Bool is_title_redraw_allowed = False;
Bool do_redraw_title = False;
Bool do_redraw_buttons = False;
Bool do_change_gcs = False;
if (!t)
return;
memset(&cd, 0, sizeof(cd));
if (force || expose_win == None)
{
is_frame_redraw_allowed = True;
is_button_redraw_allowed = True;
is_title_redraw_allowed = True;
}
else if (expose_win == t->title_w)
is_title_redraw_allowed = True;
else if (expose_win == t->frame || expose_win == t->decor_w)
/* sides and corners are InputOnly and incapable of triggering Expose events
*/
{
is_frame_redraw_allowed = True;
}
else if (expose_win != None)
is_button_redraw_allowed = True;
if (has_focus)
{
/* don't re-draw just for kicks */
if(!force && Scr.Hilite == t)
{
is_frame_redraw_allowed = False;
is_button_redraw_allowed = False;
is_title_redraw_allowed = False;
}
else
{
if (Scr.Hilite != t || force > 1)
cd.flags.has_color_changed = True;
if (Scr.Hilite != t && Scr.Hilite != NULL)
{
/* make sure that the previously highlighted window got
* unhighlighted */
DrawDecorations(Scr.Hilite, DRAW_ALL, False, True, None);
}
Scr.Hilite = t;
}
}
else
{
/* don't re-draw just for kicks */
if (!force && Scr.Hilite != t)
{
is_frame_redraw_allowed = False;
is_button_redraw_allowed = False;
is_title_redraw_allowed = False;
}
else if (Scr.Hilite == t || force > 1)
{
cd.flags.has_color_changed = True;
Scr.Hilite = NULL;
}
}
if(IS_ICONIFIED(t))
{
DrawIconWindow(t);
return;
}
/* calculate some values and flags */
if ((draw_parts & DRAW_TITLE) && HAS_TITLE(t) && is_title_redraw_allowed)
{
do_redraw_title = True;
do_change_gcs = True;
}
if ((draw_parts & DRAW_BUTTONS) && HAS_TITLE(t) && is_button_redraw_allowed)
{
do_redraw_buttons = True;
do_change_gcs = True;
}
get_common_decorations(
&cd, t, draw_parts, has_focus, force, expose_win, False, do_change_gcs);
/* redraw */
if (cd.flags.has_color_changed && HAS_TITLE(t))
{
if (!do_redraw_title || !rclip)
{
if (t->title_background_pixmap == None || force)
{
change_window_background(
t->title_w, cd.notex_valuemask, &cd.notex_attributes);
t->title_background_pixmap = None;
}
}
}
if (do_redraw_buttons)
{
RedrawButtons(&cd, t, has_focus, force, expose_win, rclip);
}
if (do_redraw_title)
{
RedrawTitle(&cd, t, has_focus, rclip);
}
if (cd.flags.has_color_changed ||
((draw_parts & DRAW_FRAME) && (is_frame_redraw_allowed)))
{
get_common_decorations(
&cd, t, draw_parts, has_focus, force, expose_win, True, True);
if (!rclip || !IS_WINDOW_BORDER_DRAWN(t))
{
change_window_background(t->decor_w, cd.valuemask, &cd.attributes);
SET_WINDOW_BORDER_DRAWN(t, 1);
rclip = NULL;
}
RedrawBorder(&cd, t, has_focus, force, expose_win, rclip);
}
/* Sync to make the change look fast! */
XSync(dpy,0);
}
void DrawDecorations(
FvwmWindow *t, draw_window_parts draw_parts, Bool has_focus, int force,
Window expose_win)
{
draw_clipped_decorations(t, draw_parts, has_focus, force, expose_win, NULL);
return;
}
/***********************************************************************
*
* Procedure:
* SetupFrame - set window sizes
*
* Inputs:
* tmp_win - the FvwmWindow pointer
* x - the x coordinate of the upper-left outer corner of the frame
* y - the y coordinate of the upper-left outer corner of the frame
* w - the width of the frame window w/o border
* h - the height of the frame window w/o border
*
* Special Considerations:
* This routine will check to make sure the window is not completely
* off the display, if it is, it'll bring some of it back on.
*
* The tmp_win->frame_XXX variables should NOT be updated with the
* values of x,y,w,h prior to calling this routine, since the new
* values are compared against the old to see whether a synthetic
* ConfigureNotify event should be sent. (It should be sent if the
* window was moved but not resized.)
*
************************************************************************/
void SetupFrame(
FvwmWindow *tmp_win, int x, int y, int w, int h, Bool sendEvent)
{
XWindowChanges xwc;
unsigned long xwcm;
int i;
Bool is_resized = False;
Bool is_moved = False;
int xwidth;
int ywidth;
int left;
int right;
int shaded = IS_SHADED(tmp_win);
int xmove_sign;
int ymove_sign;
int xsize_sign;
int ysize_sign;
int i0 = 0;
int i1 = 0;
int id = 0;
int dx;
int dy;
int px;
int py;
int decor_gravity;
Bool is_order_reversed = False;
#ifdef FVWM_DEBUG_MSGS
fvwm_msg(DBG,"SetupFrame",
"Routine Entered (x == %d, y == %d, w == %d, h == %d)",
x, y, w, h);
#endif
if (w < 1)
{
w = 1;
}
if (h < 1)
{
h = 1;
}
if (w != tmp_win->frame_g.width || h != tmp_win->frame_g.height)
is_resized = True;
if (x != tmp_win->frame_g.x || y != tmp_win->frame_g.y)
is_moved = True;
/*
* According to the July 27, 1988 ICCCM draft, we should send a
* "synthetic" ConfigureNotify event to the client if the window
* was moved but not resized.
*/
if (is_moved && !is_resized)
sendEvent = True;
/* optimization code for opaque resize */
#define SIGN(x) (((x) < 0) ? -1 : !!(x))
xmove_sign = SIGN(x - tmp_win->frame_g.x);
ymove_sign = SIGN(y - tmp_win->frame_g.y);
xsize_sign = SIGN(w - tmp_win->frame_g.width);
ysize_sign = SIGN(h - tmp_win->frame_g.height);
#undef SIGN
if (HAS_BOTTOM_TITLE(tmp_win))
{
decor_gravity = SouthEastGravity;
}
else
{
decor_gravity = NorthWestGravity;
}
if (xsize_sign != 0 || ysize_sign != 0)
{
if (ysize_sign == 0 || xsize_sign > 0)
is_order_reversed = (xsize_sign >= 0);
else
is_order_reversed = (ysize_sign >= 0);
}
else
{
is_order_reversed = False;
}
/*
* Set up the title geometry first
*/
if (is_resized)
{
left = tmp_win->nr_left_buttons;
right = tmp_win->nr_right_buttons;
tmp_win->title_g.width = w - (left + right) * tmp_win->title_g.height
- 2 * tmp_win->boundary_width;
if(tmp_win->title_g.width < 1)
tmp_win->title_g.width = 1;
}
/*
* Now set up the client, the parent and the frame window
*/
set_decor_gravity(
tmp_win, decor_gravity, NorthWestGravity, NorthWestGravity);
tmp_win->attr.width = w - 2 * tmp_win->boundary_width;
tmp_win->attr.height =
h - tmp_win->title_g.height - 2*tmp_win->boundary_width;
if (tmp_win->attr.height <= 1 || tmp_win->attr.width <= 1)
is_order_reversed = 0;
px = tmp_win->boundary_width;
py = tmp_win->boundary_width + tmp_win->title_top_height;
dx = 0;
dy = 0;
if (is_order_reversed && decor_gravity == SouthEastGravity)
{
dx = tmp_win->frame_g.width - w;
dy = tmp_win->frame_g.height - h;
}
if (is_order_reversed)
{
i0 = 3;
i1 = -1;
id = -1;
}
else
{
i0 = 0;
i1 = 4;
id = 1;
}
for (i = i0; i != i1; i += id)
{
switch(i)
{
case 0:
XMoveResizeWindow(dpy, tmp_win->frame, x, y, w, h);
break;
case 1:
if (!shaded)
{
XMoveResizeWindow(
dpy, tmp_win->Parent, px, py, max(tmp_win->attr.width, 1),
max(tmp_win->attr.height, 1));
}
else
{
XMoveWindow(dpy, tmp_win->Parent, px, py);
}
break;
case 2:
if (!shaded)
{
XResizeWindow(
dpy, tmp_win->w, max(tmp_win->attr.width, 1),
max(tmp_win->attr.height, 1));
/* This reduces flickering */
XSync(dpy, 0);
}
else if (HAS_BOTTOM_TITLE(tmp_win))
{
rectangle big_g;
big_g = (IS_MAXIMIZED(tmp_win)) ? tmp_win->max_g : tmp_win->normal_g;
get_relative_geometry(&big_g, &big_g);
XMoveWindow(dpy, tmp_win->w, 0, 1 - big_g.height +
2 * tmp_win->boundary_width + tmp_win->title_g.height);
}
else
{
XMoveWindow(dpy, tmp_win->w, 0, 0);
}
break;
case 3:
XMoveResizeWindow(dpy, tmp_win->decor_w, dx, dy, w, h);
break;
}
}
set_decor_gravity(
tmp_win, NorthWestGravity, NorthWestGravity, NorthWestGravity);
XMoveWindow(dpy, tmp_win->decor_w, 0, 0);
tmp_win->frame_g.x = x;
tmp_win->frame_g.y = y;
tmp_win->frame_g.width = w;
tmp_win->frame_g.height = h;
/*
* Set up the decoration windows
*/
if (is_resized)
{
if (HAS_TITLE(tmp_win))
{
SetupTitleBar(tmp_win, w, h);
}
if(HAS_BORDER(tmp_win))
{
int add;
tmp_win->visual_corner_width = tmp_win->corner_width;
if(w < 2*tmp_win->corner_width)
tmp_win->visual_corner_width = w / 3;
if (h < 2*tmp_win->corner_width && !shaded)
tmp_win->visual_corner_width = h / 3;
xwidth = w - 2 * tmp_win->visual_corner_width;
ywidth = h - 2 * tmp_win->visual_corner_width;
xwcm = CWWidth | CWHeight | CWX | CWY;
if(xwidth<2)
xwidth = 2;
if(ywidth<2)
ywidth = 2;
if (IS_SHADED(tmp_win))
add = tmp_win->visual_corner_width / 3;
else
add = 0;
for(i = 0; i < 4; i++)
{
if(i==0)
{
xwc.x = tmp_win->visual_corner_width;
xwc.y = 0;
xwc.height = tmp_win->boundary_width;
xwc.width = xwidth;
}
else if (i==1)
{
xwc.x = w - tmp_win->boundary_width;
xwc.y = tmp_win->visual_corner_width;
if (IS_SHADED(tmp_win))
{
xwc.y /= 3;
xwc.height = add + 2;
}
else
{
xwc.height = ywidth;
}
xwc.width = tmp_win->boundary_width;
}
else if(i==2)
{
xwc.x = tmp_win->visual_corner_width;
xwc.y = h - tmp_win->boundary_width;
xwc.height = tmp_win->boundary_width;
xwc.width = xwidth;
}
else
{
xwc.x = 0;
xwc.y = tmp_win->visual_corner_width;
if (IS_SHADED(tmp_win))
{
xwc.y /= 3;
xwc.height = add + 2;
}
else
{
xwc.height = ywidth;
}
xwc.width = tmp_win->boundary_width;
}
XConfigureWindow(dpy, tmp_win->sides[i], xwcm, &xwc);
}
xwcm = CWX|CWY|CWWidth|CWHeight;
xwc.width = tmp_win->visual_corner_width;
xwc.height = tmp_win->visual_corner_width;
for(i = 0; i < 4; i++)
{
if (i & 0x1)
xwc.x = w - tmp_win->visual_corner_width;
else
xwc.x = 0;
if (i & 0x2)
xwc.y = h - tmp_win->visual_corner_width + add;
else
xwc.y = -add;
XConfigureWindow(dpy, tmp_win->corners[i], xwcm, &xwc);
}
}
}
/*
* Set up window shape
*/
if (FShapesSupported && tmp_win->wShaped && is_resized)
{
SetShape(tmp_win, w);
}
/*
* Send ConfigureNotify
*/
XSync(dpy,0);
/* must not send events to shaded windows because this might cause them to
* look at their current geometry */
if (sendEvent && !shaded)
{
SendConfigureNotify(tmp_win, x, y, w, h, 0, True);
#ifdef FVWM_DEBUG_MSGS
fvwm_msg(DBG,"SetupFrame","Sent ConfigureNotify (w == %d, h == %d)",
w,h);
#endif
}
XSync(dpy,0);
BroadcastConfig(M_CONFIGURE_WINDOW,tmp_win);
#if 0
fprintf(stderr,"sf: window '%s'\n", tmp_win->name);
fprintf(stderr," frame: %5d %5d, %4d x %4d\n", tmp_win->frame_g.x, tmp_win->frame_g.y, tmp_win->frame_g.width, tmp_win->frame_g.height);
fprintf(stderr," normal: %5d %5d, %4d x %4d\n", tmp_win->normal_g.x, tmp_win->normal_g.y, tmp_win->normal_g.width, tmp_win->normal_g.height);
if (IS_MAXIMIZED(tmp_win))
fprintf(stderr," max: %5d %5d, %4d x %4d, %5d %5d\n", tmp_win->max_g.x, tmp_win->max_g.y, tmp_win->max_g.width, tmp_win->max_g.height, tmp_win->max_offset.x, tmp_win->max_offset.y);
#endif
}
void ForceSetupFrame(
FvwmWindow *tmp_win, int x, int y, int w, int h, Bool sendEvent)
{
tmp_win->frame_g.x = x + 1;
tmp_win->frame_g.y = y + 1;
tmp_win->frame_g.width = 0;
tmp_win->frame_g.height = 0;
SetupFrame(tmp_win, x, y, w, h, sendEvent);
}
void set_decor_gravity(
FvwmWindow *tmp_win, int gravity, int parent_gravity, int client_gravity)
{
int valuemask = CWWinGravity;
XSetWindowAttributes xcwa;
int i;
xcwa.win_gravity = client_gravity;
XChangeWindowAttributes(dpy, tmp_win->w, valuemask, &xcwa);
xcwa.win_gravity = parent_gravity;
XChangeWindowAttributes(dpy, tmp_win->Parent, valuemask, &xcwa);
xcwa.win_gravity = gravity;
XChangeWindowAttributes(dpy, tmp_win->decor_w, valuemask, &xcwa);
if (HAS_TITLE(tmp_win))
{
int left_gravity;
int right_gravity;
if (gravity == StaticGravity || gravity == ForgetGravity)
{
left_gravity = gravity;
right_gravity = gravity;
}
else
{
/* West...Gravity */
left_gravity = gravity - ((gravity - 1) % 3);
/* East...Gravity */
right_gravity = left_gravity + 2;
}
xcwa.win_gravity = left_gravity;
XChangeWindowAttributes(dpy, tmp_win->title_w, valuemask, &xcwa);
for (i = 0; i < NUMBER_OF_BUTTONS; i++)
{
if (i == NR_LEFT_BUTTONS)
xcwa.win_gravity = right_gravity;
if (tmp_win->button_w[i])
XChangeWindowAttributes(dpy, tmp_win->button_w[i], valuemask, &xcwa);
}
}
}
/****************************************************************************
*
* Sets up the shaped window borders
*
****************************************************************************/
void SetShape(FvwmWindow *tmp_win, int w)
{
if (FShapesSupported)
{
if (tmp_win->wShaped)
{
XRectangle rect;
FShapeCombineShape(
dpy, tmp_win->frame, FShapeBounding, tmp_win->boundary_width,
tmp_win->title_top_height + tmp_win->boundary_width, tmp_win->w,
FShapeBounding, FShapeSet);
if (tmp_win->title_w)
{
/* windows w/ titles */
rect.x = tmp_win->boundary_width;
rect.y = tmp_win->title_g.y;
rect.width = w - 2*tmp_win->boundary_width;
rect.height = tmp_win->title_g.height;
FShapeCombineRectangles(
dpy, tmp_win->frame, FShapeBounding, 0, 0, &rect, 1, FShapeUnion,
Unsorted);
}
}
else
{
/* unset shape */
FShapeCombineMask(
dpy, tmp_win->frame, FShapeBounding, 0, 0, None, FShapeSet);
}
}
}
/****************************************************************************
*
* Sets the allowed button states
*
****************************************************************************/
void CMD_ButtonState(F_CMD_ARGS)
{
char *token;
while ((token = PeekToken(action, &action)))
{
static char first = True;
if (!token && first)
{
Scr.gs.use_active_down_buttons = DEFAULT_USE_ACTIVE_DOWN_BUTTONS;
Scr.gs.use_inactive_buttons = DEFAULT_USE_INACTIVE_BUTTONS;
return;
}
first = False;
if (StrEquals("activedown", token))
{
Scr.gs.use_active_down_buttons =
ParseToggleArgument(action, &action, DEFAULT_USE_ACTIVE_DOWN_BUTTONS,
True);
}
else if (StrEquals("inactive", token))
{
Scr.gs.use_inactive_buttons =
ParseToggleArgument(action, &action, DEFAULT_USE_INACTIVE_BUTTONS,
True);
}
else
{
Scr.gs.use_active_down_buttons = DEFAULT_USE_ACTIVE_DOWN_BUTTONS;
Scr.gs.use_inactive_buttons = DEFAULT_USE_INACTIVE_BUTTONS;
fvwm_msg(ERR, "cmd_button_state", "unknown button state %s\n", token);
return;
}
}
return;
}
/****************************************************************************
*
* Sets the border style (veliaa@rpi.edu)
*
****************************************************************************/
void CMD_BorderStyle(F_CMD_ARGS)
{
char *parm;
char *prev;
#ifdef USEDECOR
FvwmDecor *decor = Scr.cur_decor ? Scr.cur_decor : &Scr.DefaultDecor;
#else
FvwmDecor *decor = &Scr.DefaultDecor;
#endif
Scr.flags.do_need_window_update = 1;
decor->flags.has_changed = 1;
for (prev = action; (parm = PeekToken(action, &action)); prev = action)
{
if (StrEquals(parm, "active") || StrEquals(parm, "inactive"))
{
int len;
char *end, *tmp;
DecorFace tmpdf, *df;
memset(&tmpdf.style, 0, sizeof(tmpdf.style));
DFS_FACE_TYPE(tmpdf.style) = SimpleButton;
#ifdef MULTISTYLE
tmpdf.next = NULL;
#endif
#ifdef MINI_ICONS
tmpdf.u.p = NULL;
#endif
if (StrEquals(parm,"active"))
df = &decor->BorderStyle.active;
else
df = &decor->BorderStyle.inactive;
df->flags.has_changed = 1;
while (isspace(*action))
++action;
if (*action != '(')
{
if (!*action)
{
fvwm_msg(ERR,"SetBorderStyle",
"error in %s border specification", parm);
return;
}
while (isspace(*action))
++action;
if (ReadDecorFace(action, &tmpdf,-1,True))
{
FreeDecorFace(dpy, df);
*df = tmpdf;
}
break;
}
end = strchr(++action, ')');
if (!end)
{
fvwm_msg(ERR,"SetBorderStyle",
"error in %s border specification", parm);
return;
}
len = end - action + 1;
tmp = safemalloc(len);
strncpy(tmp, action, len - 1);
tmp[len - 1] = 0;
ReadDecorFace(tmp, df,-1,True);
free(tmp);
action = end + 1;
}
else if (strcmp(parm,"--")==0)
{
if (ReadDecorFace(prev, &decor->BorderStyle.active,-1,True))
ReadDecorFace(prev, &decor->BorderStyle.inactive,-1,False);
decor->BorderStyle.active.flags.has_changed = 1;
decor->BorderStyle.inactive.flags.has_changed = 1;
break;
}
else
{
DecorFace tmpdf;
memset(&tmpdf.style, 0, sizeof(tmpdf.style));
DFS_FACE_TYPE(tmpdf.style) = SimpleButton;
#ifdef MULTISTYLE
tmpdf.next = NULL;
#endif
#ifdef MINI_ICONS
tmpdf.u.p = NULL;
#endif
if (ReadDecorFace(prev, &tmpdf,-1,True))
{
FreeDecorFace(dpy,&decor->BorderStyle.active);
decor->BorderStyle.active = tmpdf;
ReadDecorFace(prev, &decor->BorderStyle.inactive,-1,False);
decor->BorderStyle.active.flags.has_changed = 1;
decor->BorderStyle.inactive.flags.has_changed = 1;
}
break;
}
}
}
syntax highlighted by Code2HTML, v. 0.9.1