Fix handling of Shape, stage 2 (more involved/complete handling)
This commit is contained in:
parent
a04eed16c5
commit
a0f44b9e9a
7 changed files with 279 additions and 200 deletions
|
@ -1,6 +1,12 @@
|
|||
(Format: Year/Month/Day)
|
||||
Changes for 1.0.0:
|
||||
*07/08/09:
|
||||
* Fix shaping handling, stage 2, (Simon)
|
||||
- rewrite the core of the Shape handling so that it properly
|
||||
merges client and frame shapes. Fixes all sorts of odd shaping
|
||||
behaviour, and incidentally xeyes now gets a visible frame
|
||||
(not having the frame was actually a bug).
|
||||
Shape.hh/cc FbWinFrame.hh/cc Window.hh/cc
|
||||
* Fix shaping handling, stage 1, (Simon)
|
||||
- do borders properly with rounded corners
|
||||
- propagate client clip mask as well as bounding mask
|
||||
|
|
|
@ -96,8 +96,8 @@ FbWinFrame::FbWinFrame(BScreen &screen, FbWinFrameTheme &theme, FbTk::ImageContr
|
|||
m_unfocused_alpha(0),
|
||||
m_double_click_time(0),
|
||||
m_themelistener(*this),
|
||||
m_shape(new Shape(m_window, theme.shapePlace())),
|
||||
m_disable_shape(false) {
|
||||
m_shape(m_window, theme.shapePlace()),
|
||||
m_disable_themeshape(false) {
|
||||
m_theme.reconfigSig().attach(&m_themelistener);
|
||||
init();
|
||||
}
|
||||
|
@ -210,7 +210,7 @@ void FbWinFrame::show() {
|
|||
|
||||
if (m_need_render) {
|
||||
renderAll();
|
||||
applyAll();
|
||||
applyAll();
|
||||
clearAll();
|
||||
}
|
||||
|
||||
|
@ -235,8 +235,7 @@ void FbWinFrame::shade() {
|
|||
m_window.resize(m_window.width(), m_titlebar.height());
|
||||
alignTabs();
|
||||
// need to update our shape
|
||||
if ( m_shape.get() )
|
||||
m_shape->update();
|
||||
m_shape.update();
|
||||
} else { // should be unshaded
|
||||
m_window.resize(m_window.width(), m_height_before_shade);
|
||||
reconfigure();
|
||||
|
@ -1122,26 +1121,28 @@ void FbWinFrame::reconfigure() {
|
|||
m_need_render = true;
|
||||
}
|
||||
|
||||
if (m_shape.get() && theme().shapePlace() == Shape::NONE || m_disable_shape)
|
||||
m_shape.reset(0);
|
||||
else if (m_shape.get() == 0 && theme().shapePlace() != Shape::NONE)
|
||||
m_shape.reset(new Shape(window(), theme().shapePlace()));
|
||||
else if (m_shape.get())
|
||||
m_shape->setPlaces(theme().shapePlace());
|
||||
if (m_disable_themeshape)
|
||||
m_shape.setPlaces(Shape::NONE);
|
||||
else
|
||||
m_shape.setPlaces(theme().shapePlace());
|
||||
|
||||
if (m_shape.get())
|
||||
m_shape->update();
|
||||
m_shape.setShapeOffsets(0, titlebarHeight());
|
||||
|
||||
// titlebar stuff rendered already by reconftitlebar
|
||||
}
|
||||
|
||||
void FbWinFrame::setUseShape(bool value) {
|
||||
m_disable_shape = !value;
|
||||
m_disable_themeshape = !value;
|
||||
|
||||
if (m_shape.get() && m_disable_shape)
|
||||
m_shape.reset(0);
|
||||
else if (m_shape.get() == 0 && !m_disable_shape)
|
||||
m_shape.reset(new Shape(window(), theme().shapePlace()));
|
||||
if (m_disable_themeshape)
|
||||
m_shape.setPlaces(Shape::NONE);
|
||||
else
|
||||
m_shape.setPlaces(theme().shapePlace());
|
||||
|
||||
}
|
||||
|
||||
void FbWinFrame::setShapingClient(FbTk::FbWindow *win, bool always_update) {
|
||||
m_shape.setShapeSource(win, 0, titlebarHeight(), always_update);
|
||||
}
|
||||
|
||||
unsigned int FbWinFrame::buttonHeight() const {
|
||||
|
@ -1452,7 +1453,7 @@ void FbWinFrame::init() {
|
|||
if (theme().handleWidth() == 0)
|
||||
m_use_handle = false;
|
||||
|
||||
m_disable_shape = false;
|
||||
m_disable_themeshape = false;
|
||||
|
||||
m_current_label = 0; // no focused button at first
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "FbTk/XLayerItem.hh"
|
||||
#include "FbTk/TextButton.hh"
|
||||
#include "Container.hh"
|
||||
#include "Shape.hh"
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
@ -197,6 +198,8 @@ public:
|
|||
|
||||
void reconfigure();
|
||||
void setUseShape(bool value);
|
||||
void setShapingClient(FbTk::FbWindow *win, bool always_update);
|
||||
void updateShape() { m_shape.update(); }
|
||||
|
||||
/**
|
||||
@name accessors
|
||||
|
@ -403,9 +406,9 @@ private:
|
|||
FbWinFrame &m_frame;
|
||||
};
|
||||
ThemeListener m_themelistener;
|
||||
std::auto_ptr<Shape> m_shape;
|
||||
bool m_disable_shape;
|
||||
Shape m_shape;
|
||||
|
||||
bool m_disable_themeshape;
|
||||
};
|
||||
|
||||
#endif // FBWINFRAME_HH
|
||||
|
|
334
src/Shape.cc
334
src/Shape.cc
|
@ -48,25 +48,13 @@
|
|||
|
||||
using std::min;
|
||||
|
||||
// ignore_border basically means do clip shape instead of bounding shape
|
||||
FbTk::FbPixmap *Shape::createShape(bool ignore_border) {
|
||||
if (m_win->window() == 0 || m_shapeplaces == 0 ||
|
||||
m_win->width() < 3 || m_win->height() < 3)
|
||||
return 0;
|
||||
|
||||
static char left_bits[] = { 0xc0, 0xf8, 0xfc, 0xfe, 0xfe, 0xfe, 0xff, 0xff };
|
||||
static char right_bits[] = { 0x03, 0x1f, 0x3f, 0x7f, 0x7f, 0x7f, 0xff, 0xff};
|
||||
static char bottom_left_bits[] = { 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfc, 0xf8, 0xc0 };
|
||||
static char bottom_right_bits[] = { 0xff, 0xff, 0x7f, 0x7f, 0x7f, 0x3f, 0x1f, 0x03 };
|
||||
|
||||
const int borderw = m_win->borderWidth();
|
||||
const int win_width = m_win->width() + (ignore_border?0:2*borderw);
|
||||
const int win_height = m_win->height() + (ignore_border?0:2*borderw);
|
||||
const int pixmap_width = min(8, win_width);
|
||||
const int pixmap_height = min(8, win_height);
|
||||
namespace {
|
||||
/* rows is an array of 8 bytes, i.e. 8x8 bits */
|
||||
Pixmap makePixmap(FbTk::FbWindow &drawable, const unsigned char rows[]) {
|
||||
|
||||
Display *disp = FbTk::App::instance()->display();
|
||||
const size_t data_size = win_width * win_height;
|
||||
|
||||
const size_t data_size = 8 * 8;
|
||||
// we use calloc here so we get consistent C alloc/free with XDestroyImage
|
||||
// and no warnings in valgrind :)
|
||||
char *data = (char *)calloc(data_size, sizeof (char));
|
||||
|
@ -76,74 +64,50 @@ FbTk::FbPixmap *Shape::createShape(bool ignore_border) {
|
|||
memset(data, 0xFF, data_size);
|
||||
|
||||
XImage *ximage = XCreateImage(disp,
|
||||
DefaultVisual(disp, m_win->screenNumber()),
|
||||
DefaultVisual(disp, drawable.screenNumber()),
|
||||
1,
|
||||
XYPixmap, 0,
|
||||
data,
|
||||
win_width, win_height,
|
||||
8, 8,
|
||||
32, 0);
|
||||
if (ximage == 0)
|
||||
return 0;
|
||||
|
||||
XInitImage(ximage);
|
||||
|
||||
// shape corners
|
||||
|
||||
if (m_shapeplaces & Shape::TOPLEFT) {
|
||||
for (int y=0; y<pixmap_height; y++) {
|
||||
for (int x=0; x<pixmap_width; x++) {
|
||||
XPutPixel(ximage, x, y, (left_bits[y] & (0x01 << x)) ? 1 : 0);
|
||||
}
|
||||
for (int y=0; y<8; y++) {
|
||||
for (int x=0; x<8; x++) {
|
||||
XPutPixel(ximage, x, y, (rows[y] & (0x01 << x)) ? 0 : 1); // inverted, it is subtracted
|
||||
}
|
||||
}
|
||||
|
||||
if (m_shapeplaces & Shape::TOPRIGHT) {
|
||||
for (int y=0; y<pixmap_height; y++) {
|
||||
for (int x=0; x<pixmap_width; x++) {
|
||||
XPutPixel(ximage, x + win_width - pixmap_width, y,
|
||||
(right_bits[y] & (0x01 << x)) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
FbTk::FbPixmap pm(drawable, 8, 8, 1);
|
||||
FbTk::GContext gc(pm);
|
||||
|
||||
if (m_shapeplaces & Shape::BOTTOMLEFT) {
|
||||
for (int y=0; y<pixmap_height; y++) {
|
||||
for (int x=0; x<pixmap_width; x++) {
|
||||
XPutPixel(ximage, x, y + win_height - pixmap_height,
|
||||
(bottom_left_bits[y] & (0x01 << x)) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_shapeplaces & Shape::BOTTOMRIGHT) {
|
||||
for (int y=0; y<pixmap_height; y++) {
|
||||
for (int x=0; x<pixmap_width; x++) {
|
||||
XPutPixel(ximage, x + win_width - pixmap_width, y + win_height - pixmap_height,
|
||||
(bottom_right_bits[y] & (0x01 << x)) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FbTk::FbPixmap *pm = new FbTk::FbPixmap(*m_win, win_width, win_height, 1);
|
||||
|
||||
|
||||
FbTk::GContext gc(*pm);
|
||||
|
||||
XPutImage(disp, pm->drawable(), gc.gc(), ximage, 0, 0, 0, 0,
|
||||
win_width, win_height);
|
||||
XPutImage(disp, pm.drawable(), gc.gc(), ximage, 0, 0, 0, 0,
|
||||
8, 8);
|
||||
|
||||
XDestroyImage(ximage);
|
||||
|
||||
return pm;
|
||||
|
||||
return pm.release();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
std::vector<Shape::CornerPixmaps> Shape::s_corners;
|
||||
|
||||
Shape::Shape(FbTk::FbWindow &win, int shapeplaces):
|
||||
m_win(&win),
|
||||
m_shapesource(0),
|
||||
m_shapesource_xoff(0),
|
||||
m_shapesource_yoff(0),
|
||||
m_shapeplaces(shapeplaces) {
|
||||
|
||||
m_clipshape.reset(createShape(true));
|
||||
m_boundingshape.reset(createShape(false));
|
||||
#ifdef SHAPE
|
||||
initCorners(win.screenNumber());
|
||||
#endif
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
Shape::~Shape() {
|
||||
|
@ -157,19 +121,32 @@ Shape::~Shape() {
|
|||
0, 0,
|
||||
0,
|
||||
ShapeSet);
|
||||
// Reset shape of window
|
||||
if (m_boundingshape.get()) {
|
||||
XShapeCombineMask(FbTk::App::instance()->display(),
|
||||
m_win->window(),
|
||||
ShapeBounding,
|
||||
0, 0,
|
||||
0,
|
||||
ShapeSet);
|
||||
}
|
||||
}
|
||||
XShapeCombineMask(FbTk::App::instance()->display(),
|
||||
m_win->window(),
|
||||
ShapeBounding,
|
||||
0, 0,
|
||||
0,
|
||||
ShapeSet);
|
||||
}
|
||||
#endif // SHAPE
|
||||
}
|
||||
|
||||
void Shape::initCorners(int screen_num) {
|
||||
if (s_corners.size() == 0)
|
||||
s_corners.resize(ScreenCount(FbTk::App::instance()->display()));
|
||||
|
||||
static const unsigned char left_bits[] = { 0xc0, 0xf8, 0xfc, 0xfe, 0xfe, 0xfe, 0xff, 0xff };
|
||||
static const unsigned char right_bits[] = { 0x03, 0x1f, 0x3f, 0x7f, 0x7f, 0x7f, 0xff, 0xff};
|
||||
static const unsigned char bottom_left_bits[] = { 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfc, 0xf8, 0xc0 };
|
||||
static const unsigned char bottom_right_bits[] = { 0xff, 0xff, 0x7f, 0x7f, 0x7f, 0x3f, 0x1f, 0x03 };
|
||||
|
||||
s_corners[screen_num].topleft = ::makePixmap(*m_win, left_bits);
|
||||
s_corners[screen_num].topright = ::makePixmap(*m_win, right_bits);
|
||||
s_corners[screen_num].botleft = ::makePixmap(*m_win, bottom_left_bits);
|
||||
s_corners[screen_num].botright = ::makePixmap(*m_win, bottom_right_bits);
|
||||
|
||||
}
|
||||
|
||||
void Shape::setPlaces(int shapeplaces) {
|
||||
m_shapeplaces = shapeplaces;
|
||||
}
|
||||
|
@ -177,41 +154,144 @@ void Shape::setPlaces(int shapeplaces) {
|
|||
void Shape::update() {
|
||||
if (m_win == 0 || m_win->window() == 0)
|
||||
return;
|
||||
|
||||
#ifdef SHAPE
|
||||
if (m_clipshape.get() == 0 ||
|
||||
m_win->width() != clipWidth() ||
|
||||
m_win->height() != clipHeight()) {
|
||||
m_clipshape.reset(createShape(true));
|
||||
}
|
||||
if (m_boundingshape.get() == 0 ||
|
||||
(m_win->width()+m_win->borderWidth()*2) != width() ||
|
||||
(m_win->height()+m_win->borderWidth()*2) != height()) {
|
||||
if (m_win->borderWidth() != 0)
|
||||
m_boundingshape.reset(createShape(false));
|
||||
else
|
||||
m_boundingshape.reset(0);
|
||||
/**
|
||||
* Set the client's shape in position,
|
||||
* or wipe the shape and return.
|
||||
*/
|
||||
Display *display = FbTk::App::instance()->display();
|
||||
int bw = m_win->borderWidth();
|
||||
int width = m_win->width();
|
||||
int height = m_win->height();
|
||||
|
||||
if (m_shapesource == 0 && m_shapeplaces == 0) {
|
||||
/* clear the shape and return */
|
||||
XShapeCombineMask(display,
|
||||
m_win->window(), ShapeClip,
|
||||
0, 0,
|
||||
None, ShapeSet);
|
||||
XShapeCombineMask(display,
|
||||
m_win->window(), ShapeBounding,
|
||||
0, 0,
|
||||
None, ShapeSet);
|
||||
return;
|
||||
}
|
||||
|
||||
// the m_shape can be = 0 which will just raeset the shape mask
|
||||
// and make the window normal
|
||||
XShapeCombineMask(FbTk::App::instance()->display(),
|
||||
m_win->window(),
|
||||
ShapeClip,
|
||||
0, 0,
|
||||
(m_clipshape.get() != 0)? m_clipshape->drawable() : 0,
|
||||
ShapeSet);
|
||||
XRectangle rect;
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.width = width;
|
||||
rect.height = height;
|
||||
|
||||
// the m_shape can be = 0 which will just raeset the shape mask
|
||||
// and make the window normal
|
||||
XShapeCombineMask(FbTk::App::instance()->display(),
|
||||
m_win->window(),
|
||||
ShapeBounding,
|
||||
-m_win->borderWidth(), -m_win->borderWidth(),
|
||||
(m_boundingshape.get() != 0)? m_boundingshape->drawable() :
|
||||
((m_clipshape.get() != 0)? m_clipshape->drawable(): 0),
|
||||
ShapeSet);
|
||||
XShapeCombineRectangles(display,
|
||||
m_win->window(), ShapeClip,
|
||||
0, 0, /* offsets */
|
||||
&rect,
|
||||
1, /* number of rectangles */
|
||||
ShapeSet, /* op */
|
||||
2 /* ordering: YXSorted... only 1: doesn't matter */ );
|
||||
|
||||
rect.x = -bw;
|
||||
rect.y = -bw;
|
||||
rect.width = width+2*bw;
|
||||
rect.height = height+2*bw;
|
||||
|
||||
XShapeCombineRectangles(display,
|
||||
m_win->window(), ShapeBounding,
|
||||
0, 0, /* offsets */
|
||||
&rect,
|
||||
1, /* number of rectangles */
|
||||
ShapeSet, /* op */
|
||||
2 /* ordering: YXSorted... only 1: doesn't matter */ );
|
||||
|
||||
if (m_shapesource != 0) {
|
||||
|
||||
/*
|
||||
Copy the shape from the source.
|
||||
We achieve this by subtracting the client-area size from the shape, and then
|
||||
unioning in the client's mask.
|
||||
*/
|
||||
rect.x = m_shapesource_xoff;
|
||||
rect.y = m_shapesource_yoff;
|
||||
rect.width = m_shapesource->width();
|
||||
rect.height = m_shapesource->height();
|
||||
|
||||
XShapeCombineRectangles(display,
|
||||
m_win->window(), ShapeClip,
|
||||
0, 0, /* offsets */
|
||||
&rect,
|
||||
1, /* number of rectangles */
|
||||
ShapeSubtract, /* op */
|
||||
2 /* ordering: YXSorted... only 1: doesn't matter */ );
|
||||
|
||||
XShapeCombineShape(display,
|
||||
m_win->window(), ShapeClip,
|
||||
rect.x, rect.y, // xOff, yOff
|
||||
m_shapesource->window(),
|
||||
ShapeClip, ShapeUnion);
|
||||
|
||||
/*
|
||||
Now the bounding rectangle. Note that the frame has a shared border with the region above the
|
||||
client (i.e. titlebar), so we don't want to wipe the shared border, hence the adjustments.
|
||||
*/
|
||||
rect.x = m_shapesource_xoff; // note that the full bounding region is already offset by a -borderwidth!
|
||||
rect.y = m_shapesource_yoff;
|
||||
rect.width = m_shapesource->width(); // we don't wipe the outer bounding region [i think]
|
||||
rect.height = m_shapesource->height();
|
||||
|
||||
// we want to delete the client area, dont care about borders really
|
||||
XShapeCombineRectangles(display,
|
||||
m_win->window(), ShapeBounding,
|
||||
0, 0, /* offsets */
|
||||
&rect,
|
||||
1, /* number of rectangles */
|
||||
ShapeSubtract, /* op */
|
||||
2 /* ordering: YXSorted... only 1: doesn't matter */ );
|
||||
|
||||
XShapeCombineShape(display,
|
||||
m_win->window(), ShapeBounding,
|
||||
rect.x , rect.y, // xOff, yOff
|
||||
m_shapesource->window(),
|
||||
ShapeBounding, ShapeUnion);
|
||||
}
|
||||
|
||||
|
||||
CornerPixmaps &corners = s_corners[m_win->screenNumber()];
|
||||
#define SHAPECORNER(corner, x, y, shapekind) \
|
||||
XShapeCombineMask(FbTk::App::instance()->display(), \
|
||||
m_win->window(), \
|
||||
shapekind, \
|
||||
x, y, \
|
||||
corners.corner.drawable(), \
|
||||
ShapeSubtract);
|
||||
|
||||
/**
|
||||
* Set the top corners if the y offset is nonzero.
|
||||
*/
|
||||
if (m_shapesource == 0 || m_shapesource_yoff != 0) {
|
||||
if (m_shapeplaces & TOPLEFT) {
|
||||
SHAPECORNER(topleft, 0, 0, ShapeClip);
|
||||
SHAPECORNER(topleft, -bw, -bw, ShapeBounding);
|
||||
}
|
||||
if (m_shapeplaces & TOPRIGHT) {
|
||||
SHAPECORNER(topright, width-8, 0, ShapeClip);
|
||||
SHAPECORNER(topright, width+bw-8, -bw, ShapeBounding);
|
||||
}
|
||||
}
|
||||
|
||||
// note that the bottom corners y-vals are offset by 8 (the height of the corner pixmaps)
|
||||
if (m_shapesource == 0 || (m_shapesource_yoff+(signed) m_shapesource->height()) < height
|
||||
|| m_shapesource_yoff >= height /* shaded */) {
|
||||
if (m_shapeplaces & BOTTOMLEFT) {
|
||||
SHAPECORNER(botleft, 0, height-8, ShapeClip);
|
||||
SHAPECORNER(botleft, -bw, height+bw-8, ShapeBounding);
|
||||
}
|
||||
if (m_shapeplaces & BOTTOMRIGHT) {
|
||||
SHAPECORNER(botright, width-8, height-8, ShapeClip);
|
||||
SHAPECORNER(botright, width+bw-8, height+bw-8, ShapeBounding);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SHAPE
|
||||
|
||||
|
@ -222,6 +302,41 @@ void Shape::setWindow(FbTk::FbWindow &win) {
|
|||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* set the shape source to the given window.
|
||||
* This is purely for client windows at the moment, where the offsets and height/width of the
|
||||
* target window and the source window are used to determine whether to shape a given corner.
|
||||
*
|
||||
* (note: xoffset will always be zero, and widths always match, so we ignore those)
|
||||
*
|
||||
* i.e. if the yoffset is not zero, then the top corners are shaped.
|
||||
* if the target height is bigger than the source plus yoffset, then the bottom corners are
|
||||
* shaped.
|
||||
*
|
||||
* If *either* the top or bottom corners are not shaped due to this, but a shape source window
|
||||
* is given, then the bounding shape has the borders alongside the source window deleted, otherwise
|
||||
* they are left hanging outside the client's shape.
|
||||
*/
|
||||
void Shape::setShapeSource(FbTk::FbWindow *win, int xoff, int yoff, bool always_update) {
|
||||
if (win != 0 && !isShaped(*win)) {
|
||||
win = 0;
|
||||
if (m_shapesource == 0 && !always_update)
|
||||
return;
|
||||
}
|
||||
|
||||
// even if source is same, want to update the shape on it
|
||||
m_shapesource = win;
|
||||
m_shapesource_xoff = xoff;
|
||||
m_shapesource_yoff = yoff;
|
||||
update();
|
||||
}
|
||||
|
||||
void Shape::setShapeOffsets(int xoff, int yoff) {
|
||||
m_shapesource_xoff = xoff;
|
||||
m_shapesource_yoff = yoff;
|
||||
update();
|
||||
}
|
||||
|
||||
void Shape::setShapeNotify(const FbTk::FbWindow &win) {
|
||||
#ifdef SHAPE
|
||||
XShapeSelectInput(FbTk::App::instance()->display(),
|
||||
|
@ -248,18 +363,3 @@ bool Shape::isShaped(const FbTk::FbWindow &win) {
|
|||
return (shaped != 0 ? true : false);
|
||||
}
|
||||
|
||||
unsigned int Shape::width() const {
|
||||
return m_boundingshape.get() ? m_boundingshape->width() : 0;
|
||||
}
|
||||
|
||||
unsigned int Shape::height() const {
|
||||
return m_boundingshape.get() ? m_boundingshape->height() : 0;
|
||||
}
|
||||
|
||||
unsigned int Shape::clipWidth() const {
|
||||
return m_clipshape.get() ? m_clipshape->width() : 0;
|
||||
}
|
||||
|
||||
unsigned int Shape::clipHeight() const {
|
||||
return m_clipshape.get() ? m_clipshape->height() : 0;
|
||||
}
|
||||
|
|
26
src/Shape.hh
26
src/Shape.hh
|
@ -24,12 +24,14 @@
|
|||
#ifndef SHAPE_HH
|
||||
#define SHAPE_HH
|
||||
|
||||
#include "FbTk/FbPixmap.hh"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace FbTk {
|
||||
class FbWindow;
|
||||
class FbPixmap;
|
||||
}
|
||||
|
||||
/// creates round corners on windows
|
||||
|
@ -51,6 +53,10 @@ public:
|
|||
void update();
|
||||
/// assign a new window
|
||||
void setWindow(FbTk::FbWindow &win);
|
||||
/// Assign a window to merge our shape with.
|
||||
/// (note that this is currently specific to frames)
|
||||
void setShapeSource(FbTk::FbWindow *win, int xoff, int yoff, bool always_update);
|
||||
void setShapeOffsets(int xoff, int yoff);
|
||||
unsigned int width() const;
|
||||
unsigned int height() const;
|
||||
unsigned int clipWidth() const;
|
||||
|
@ -60,11 +66,21 @@ public:
|
|||
/// @return true if window has shape
|
||||
static bool isShaped(const FbTk::FbWindow &win);
|
||||
private:
|
||||
FbTk::FbPixmap *createShape(bool clipshape); // true for clip, false for bounding
|
||||
|
||||
FbTk::FbWindow *m_win; ///< window to be shaped
|
||||
std::auto_ptr<FbTk::FbPixmap> m_clipshape; ///< our shape pixmap
|
||||
std::auto_ptr<FbTk::FbPixmap> m_boundingshape; ///< our shape pixmap
|
||||
FbTk::FbWindow *m_shapesource; ///< window to pull shape from
|
||||
int m_shapesource_xoff, m_shapesource_yoff;
|
||||
|
||||
void initCorners(int screen_num);
|
||||
|
||||
struct CornerPixmaps {
|
||||
FbTk::FbPixmap topleft;
|
||||
FbTk::FbPixmap topright;
|
||||
FbTk::FbPixmap botleft;
|
||||
FbTk::FbPixmap botright;
|
||||
};
|
||||
|
||||
// unfortunately, we need a separate pixmap per screen
|
||||
static std::vector<CornerPixmaps> s_corners;
|
||||
int m_shapeplaces; ///< places to shape
|
||||
|
||||
};
|
||||
|
|
|
@ -268,7 +268,6 @@ FluxboxWindow::FluxboxWindow(WinClient &client, FbWinFrameTheme &tm,
|
|||
m_old_decoration_mask(0),
|
||||
m_client(&client),
|
||||
m_toggled_decos(false),
|
||||
m_shaped(false),
|
||||
m_icon_hidden(false),
|
||||
m_focus_hidden(false),
|
||||
m_old_pos_x(0), m_old_pos_y(0),
|
||||
|
@ -350,16 +349,10 @@ void FluxboxWindow::init() {
|
|||
m_client->setFluxboxWindow(this);
|
||||
m_client->setGroupLeftWindow(None); // nothing to the left.
|
||||
|
||||
// check for shape extension and whether the window is shaped
|
||||
m_shaped = false;
|
||||
|
||||
if (Fluxbox::instance()->haveShape()) {
|
||||
Shape::setShapeNotify(winClient());
|
||||
m_shaped = Shape::isShaped(winClient());
|
||||
}
|
||||
|
||||
frame().setUseShape(!m_shaped);
|
||||
|
||||
//!! TODO init of client should be better
|
||||
// we don't want to duplicate code here and in attachClient
|
||||
m_clientlist.push_back(m_client);
|
||||
|
@ -548,36 +541,12 @@ void FluxboxWindow::init() {
|
|||
// no focus default
|
||||
setFocusFlag(false);
|
||||
|
||||
if (m_shaped)
|
||||
shape();
|
||||
|
||||
setupWindow();
|
||||
|
||||
FbTk::App::instance()->sync(false);
|
||||
|
||||
}
|
||||
|
||||
/// apply shape to this window
|
||||
void FluxboxWindow::shape() {
|
||||
#ifdef SHAPE
|
||||
if (m_shaped) {
|
||||
XShapeCombineShape(display,
|
||||
frame().window().window(), ShapeClip,
|
||||
0, frame().clientArea().y(), // xOff, yOff
|
||||
m_client->window(),
|
||||
ShapeClip, ShapeSet);
|
||||
XShapeCombineShape(display,
|
||||
frame().window().window(), ShapeBounding,
|
||||
0, frame().clientArea().y(), // xOff, yOff
|
||||
m_client->window(),
|
||||
ShapeBounding, ShapeSet);
|
||||
XFlush(display);
|
||||
}
|
||||
#endif // SHAPE
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// attach a client to this window and destroy old window
|
||||
void FluxboxWindow::attachClient(WinClient &client, int x, int y) {
|
||||
//!! TODO: check for isGroupable in client
|
||||
|
@ -995,8 +964,10 @@ bool FluxboxWindow::setCurrentClient(WinClient &client, bool setinput) {
|
|||
if (!button)
|
||||
return false;
|
||||
|
||||
if (&client != m_client)
|
||||
if (&client != m_client) {
|
||||
m_screen.focusControl().setScreenFocusedWindow(client);
|
||||
frame().setShapingClient(&client, false);
|
||||
}
|
||||
m_client = &client;
|
||||
m_client->raise();
|
||||
m_client->focusSig().notify();
|
||||
|
@ -1042,6 +1013,8 @@ void FluxboxWindow::associateClientWindow(bool use_attrs,
|
|||
updateTitleFromClient(*m_client);
|
||||
updateIconNameFromClient(*m_client);
|
||||
|
||||
frame().setShapingClient(m_client, false);
|
||||
|
||||
if (use_attrs)
|
||||
frame().moveResizeForClient(x, y,
|
||||
width, height, gravity, client_bw);
|
||||
|
@ -1299,7 +1272,6 @@ void FluxboxWindow::moveResize(int new_x, int new_y,
|
|||
sendConfigureNotify();
|
||||
}
|
||||
|
||||
shape();
|
||||
|
||||
if (!moving) {
|
||||
m_last_resize_x = new_x;
|
||||
|
@ -1319,8 +1291,6 @@ void FluxboxWindow::moveResizeForClient(int new_x, int new_y,
|
|||
shaded = false;
|
||||
sendConfigureNotify();
|
||||
|
||||
shape();
|
||||
|
||||
if (!moving) {
|
||||
m_last_resize_x = new_x;
|
||||
m_last_resize_y = new_y;
|
||||
|
@ -1617,7 +1587,7 @@ void FluxboxWindow::setFullscreen(bool flag) {
|
|||
|
||||
fullscreen = false;
|
||||
|
||||
frame().setUseShape(!m_shaped);
|
||||
frame().setUseShape(true);
|
||||
if (m_toggled_decos) {
|
||||
if (m_old_decoration_mask & DECORM_TITLEBAR)
|
||||
setDecoration(DECOR_NONE);
|
||||
|
@ -2342,24 +2312,10 @@ void FluxboxWindow::handleEvent(XEvent &event) {
|
|||
#endif // DEBUG
|
||||
XShapeEvent *shape_event = (XShapeEvent *)&event;
|
||||
|
||||
if (shape_event->kind != ShapeBounding)
|
||||
break;
|
||||
|
||||
if (shape_event->shaped) {
|
||||
m_shaped = true;
|
||||
shape();
|
||||
} else {
|
||||
m_shaped = false;
|
||||
// set no shape
|
||||
XShapeCombineMask(display,
|
||||
frame().window().window(), ShapeClip,
|
||||
0, 0,
|
||||
None, ShapeSet);
|
||||
XShapeCombineMask(display,
|
||||
frame().window().window(), ShapeBounding,
|
||||
0, 0,
|
||||
None, ShapeSet);
|
||||
}
|
||||
if (shape_event->shaped)
|
||||
frame().setShapingClient(m_client, true);
|
||||
else
|
||||
frame().setShapingClient(0, true);
|
||||
|
||||
FbTk::App::instance()->sync(false);
|
||||
break;
|
||||
|
|
|
@ -454,8 +454,6 @@ private:
|
|||
void updateButtons();
|
||||
|
||||
void init();
|
||||
/// applies a shape mask to the window if it has one
|
||||
void shape();
|
||||
void updateClientLeftWindow();
|
||||
void grabButtons();
|
||||
|
||||
|
@ -560,7 +558,6 @@ private:
|
|||
bool resize, move, iconify, maximize, close, tabable;
|
||||
} functions;
|
||||
|
||||
bool m_shaped; ///< if the window is shaped with a mask
|
||||
bool m_icon_hidden; ///< if the window is in the iconbar
|
||||
bool m_focus_hidden; ///< if the window is in the NextWindow list
|
||||
int m_old_pos_x, m_old_pos_y; ///< old position so we can restore from maximized
|
||||
|
|
Loading…
Reference in a new issue