aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsimonb <simonb>2007-08-09 03:45:31 (GMT)
committersimonb <simonb>2007-08-09 03:45:31 (GMT)
commita0f44b9e9a7c2e401e2cf1ef80fed98acf1d7e44 (patch)
tree2c2658372e5e85c2d0c186f7080e9534430af633
parenta04eed16c5287c11e565ecb25f465b96d6f61279 (diff)
downloadfluxbox-a0f44b9e9a7c2e401e2cf1ef80fed98acf1d7e44.zip
fluxbox-a0f44b9e9a7c2e401e2cf1ef80fed98acf1d7e44.tar.bz2
Fix handling of Shape, stage 2 (more involved/complete handling)
-rw-r--r--ChangeLog6
-rw-r--r--src/FbWinFrame.cc39
-rw-r--r--src/FbWinFrame.hh7
-rw-r--r--src/Shape.cc334
-rw-r--r--src/Shape.hh26
-rw-r--r--src/Window.cc64
-rw-r--r--src/Window.hh3
7 files changed, 279 insertions, 200 deletions
diff --git a/ChangeLog b/ChangeLog
index fed2ab2..7dd6ee5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,12 @@
1 (Format: Year/Month/Day) 1 (Format: Year/Month/Day)
2Changes for 1.0.0: 2Changes for 1.0.0:
3*07/08/09: 3*07/08/09:
4 * Fix shaping handling, stage 2, (Simon)
5 - rewrite the core of the Shape handling so that it properly
6 merges client and frame shapes. Fixes all sorts of odd shaping
7 behaviour, and incidentally xeyes now gets a visible frame
8 (not having the frame was actually a bug).
9 Shape.hh/cc FbWinFrame.hh/cc Window.hh/cc
4 * Fix shaping handling, stage 1, (Simon) 10 * Fix shaping handling, stage 1, (Simon)
5 - do borders properly with rounded corners 11 - do borders properly with rounded corners
6 - propagate client clip mask as well as bounding mask 12 - propagate client clip mask as well as bounding mask
diff --git a/src/FbWinFrame.cc b/src/FbWinFrame.cc
index d3b3d2f..fbf1102 100644
--- a/src/FbWinFrame.cc
+++ b/src/FbWinFrame.cc
@@ -96,8 +96,8 @@ FbWinFrame::FbWinFrame(BScreen &screen, FbWinFrameTheme &theme, FbTk::ImageContr
96 m_unfocused_alpha(0), 96 m_unfocused_alpha(0),
97 m_double_click_time(0), 97 m_double_click_time(0),
98 m_themelistener(*this), 98 m_themelistener(*this),
99 m_shape(new Shape(m_window, theme.shapePlace())), 99 m_shape(m_window, theme.shapePlace()),
100 m_disable_shape(false) { 100 m_disable_themeshape(false) {
101 m_theme.reconfigSig().attach(&m_themelistener); 101 m_theme.reconfigSig().attach(&m_themelistener);
102 init(); 102 init();
103} 103}
@@ -210,7 +210,7 @@ void FbWinFrame::show() {
210 210
211 if (m_need_render) { 211 if (m_need_render) {
212 renderAll(); 212 renderAll();
213 applyAll(); 213 applyAll();
214 clearAll(); 214 clearAll();
215 } 215 }
216 216
@@ -235,8 +235,7 @@ void FbWinFrame::shade() {
235 m_window.resize(m_window.width(), m_titlebar.height()); 235 m_window.resize(m_window.width(), m_titlebar.height());
236 alignTabs(); 236 alignTabs();
237 // need to update our shape 237 // need to update our shape
238 if ( m_shape.get() ) 238 m_shape.update();
239 m_shape->update();
240 } else { // should be unshaded 239 } else { // should be unshaded
241 m_window.resize(m_window.width(), m_height_before_shade); 240 m_window.resize(m_window.width(), m_height_before_shade);
242 reconfigure(); 241 reconfigure();
@@ -1122,26 +1121,28 @@ void FbWinFrame::reconfigure() {
1122 m_need_render = true; 1121 m_need_render = true;
1123 } 1122 }
1124 1123
1125 if (m_shape.get() && theme().shapePlace() == Shape::NONE || m_disable_shape) 1124 if (m_disable_themeshape)
1126 m_shape.reset(0); 1125 m_shape.setPlaces(Shape::NONE);
1127 else if (m_shape.get() == 0 && theme().shapePlace() != Shape::NONE) 1126 else
1128 m_shape.reset(new Shape(window(), theme().shapePlace())); 1127 m_shape.setPlaces(theme().shapePlace());
1129 else if (m_shape.get())
1130 m_shape->setPlaces(theme().shapePlace());
1131 1128
1132 if (m_shape.get()) 1129 m_shape.setShapeOffsets(0, titlebarHeight());
1133 m_shape->update();
1134 1130
1135 // titlebar stuff rendered already by reconftitlebar 1131 // titlebar stuff rendered already by reconftitlebar
1136} 1132}
1137 1133
1138void FbWinFrame::setUseShape(bool value) { 1134void FbWinFrame::setUseShape(bool value) {
1139 m_disable_shape = !value; 1135 m_disable_themeshape = !value;
1136
1137 if (m_disable_themeshape)
1138 m_shape.setPlaces(Shape::NONE);
1139 else
1140 m_shape.setPlaces(theme().shapePlace());
1141
1142}
1140 1143
1141 if (m_shape.get() && m_disable_shape) 1144void FbWinFrame::setShapingClient(FbTk::FbWindow *win, bool always_update) {
1142 m_shape.reset(0); 1145 m_shape.setShapeSource(win, 0, titlebarHeight(), always_update);
1143 else if (m_shape.get() == 0 && !m_disable_shape)
1144 m_shape.reset(new Shape(window(), theme().shapePlace()));
1145} 1146}
1146 1147
1147unsigned int FbWinFrame::buttonHeight() const { 1148unsigned int FbWinFrame::buttonHeight() const {
@@ -1452,7 +1453,7 @@ void FbWinFrame::init() {
1452 if (theme().handleWidth() == 0) 1453 if (theme().handleWidth() == 0)
1453 m_use_handle = false; 1454 m_use_handle = false;
1454 1455
1455 m_disable_shape = false; 1456 m_disable_themeshape = false;
1456 1457
1457 m_current_label = 0; // no focused button at first 1458 m_current_label = 0; // no focused button at first
1458 1459
diff --git a/src/FbWinFrame.hh b/src/FbWinFrame.hh
index 87c290c..1eefe42 100644
--- a/src/FbWinFrame.hh
+++ b/src/FbWinFrame.hh
@@ -33,6 +33,7 @@
33#include "FbTk/XLayerItem.hh" 33#include "FbTk/XLayerItem.hh"
34#include "FbTk/TextButton.hh" 34#include "FbTk/TextButton.hh"
35#include "Container.hh" 35#include "Container.hh"
36#include "Shape.hh"
36 37
37#include <vector> 38#include <vector>
38#include <list> 39#include <list>
@@ -197,6 +198,8 @@ public:
197 198
198 void reconfigure(); 199 void reconfigure();
199 void setUseShape(bool value); 200 void setUseShape(bool value);
201 void setShapingClient(FbTk::FbWindow *win, bool always_update);
202 void updateShape() { m_shape.update(); }
200 203
201 /** 204 /**
202 @name accessors 205 @name accessors
@@ -403,9 +406,9 @@ private:
403 FbWinFrame &m_frame; 406 FbWinFrame &m_frame;
404 }; 407 };
405 ThemeListener m_themelistener; 408 ThemeListener m_themelistener;
406 std::auto_ptr<Shape> m_shape; 409 Shape m_shape;
407 bool m_disable_shape;
408 410
411 bool m_disable_themeshape;
409}; 412};
410 413
411#endif // FBWINFRAME_HH 414#endif // FBWINFRAME_HH
diff --git a/src/Shape.cc b/src/Shape.cc
index a073b9f..7198d00 100644
--- a/src/Shape.cc
+++ b/src/Shape.cc
@@ -48,25 +48,13 @@
48 48
49using std::min; 49using std::min;
50 50
51// ignore_border basically means do clip shape instead of bounding shape 51namespace {
52FbTk::FbPixmap *Shape::createShape(bool ignore_border) { 52/* rows is an array of 8 bytes, i.e. 8x8 bits */
53 if (m_win->window() == 0 || m_shapeplaces == 0 || 53Pixmap makePixmap(FbTk::FbWindow &drawable, const unsigned char rows[]) {
54 m_win->width() < 3 || m_win->height() < 3)
55 return 0;
56
57 static char left_bits[] = { 0xc0, 0xf8, 0xfc, 0xfe, 0xfe, 0xfe, 0xff, 0xff };
58 static char right_bits[] = { 0x03, 0x1f, 0x3f, 0x7f, 0x7f, 0x7f, 0xff, 0xff};
59 static char bottom_left_bits[] = { 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfc, 0xf8, 0xc0 };
60 static char bottom_right_bits[] = { 0xff, 0xff, 0x7f, 0x7f, 0x7f, 0x3f, 0x1f, 0x03 };
61
62 const int borderw = m_win->borderWidth();
63 const int win_width = m_win->width() + (ignore_border?0:2*borderw);
64 const int win_height = m_win->height() + (ignore_border?0:2*borderw);
65 const int pixmap_width = min(8, win_width);
66 const int pixmap_height = min(8, win_height);
67 54
68 Display *disp = FbTk::App::instance()->display(); 55 Display *disp = FbTk::App::instance()->display();
69 const size_t data_size = win_width * win_height; 56
57 const size_t data_size = 8 * 8;
70 // we use calloc here so we get consistent C alloc/free with XDestroyImage 58 // we use calloc here so we get consistent C alloc/free with XDestroyImage
71 // and no warnings in valgrind :) 59 // and no warnings in valgrind :)
72 char *data = (char *)calloc(data_size, sizeof (char)); 60 char *data = (char *)calloc(data_size, sizeof (char));
@@ -76,74 +64,50 @@ FbTk::FbPixmap *Shape::createShape(bool ignore_border) {
76 memset(data, 0xFF, data_size); 64 memset(data, 0xFF, data_size);
77 65
78 XImage *ximage = XCreateImage(disp, 66 XImage *ximage = XCreateImage(disp,
79 DefaultVisual(disp, m_win->screenNumber()), 67 DefaultVisual(disp, drawable.screenNumber()),
80 1, 68 1,
81 XYPixmap, 0, 69 XYPixmap, 0,
82 data, 70 data,
83 win_width, win_height, 71 8, 8,
84 32, 0); 72 32, 0);
85 if (ximage == 0) 73 if (ximage == 0)
86 return 0; 74 return 0;
87 75
88 XInitImage(ximage); 76 XInitImage(ximage);
89 77
90 // shape corners 78 for (int y=0; y<8; y++) {
91 79 for (int x=0; x<8; x++) {
92 if (m_shapeplaces & Shape::TOPLEFT) { 80 XPutPixel(ximage, x, y, (rows[y] & (0x01 << x)) ? 0 : 1); // inverted, it is subtracted
93 for (int y=0; y<pixmap_height; y++) {
94 for (int x=0; x<pixmap_width; x++) {
95 XPutPixel(ximage, x, y, (left_bits[y] & (0x01 << x)) ? 1 : 0);
96 }
97 }
98 }
99
100 if (m_shapeplaces & Shape::TOPRIGHT) {
101 for (int y=0; y<pixmap_height; y++) {
102 for (int x=0; x<pixmap_width; x++) {
103 XPutPixel(ximage, x + win_width - pixmap_width, y,
104 (right_bits[y] & (0x01 << x)) ? 1 : 0);
105 }
106 } 81 }
107 } 82 }
108 83
109 if (m_shapeplaces & Shape::BOTTOMLEFT) { 84 FbTk::FbPixmap pm(drawable, 8, 8, 1);
110 for (int y=0; y<pixmap_height; y++) { 85 FbTk::GContext gc(pm);
111 for (int x=0; x<pixmap_width; x++) {
112 XPutPixel(ximage, x, y + win_height - pixmap_height,
113 (bottom_left_bits[y] & (0x01 << x)) ? 1 : 0);
114 }
115 }
116 }
117
118 if (m_shapeplaces & Shape::BOTTOMRIGHT) {
119 for (int y=0; y<pixmap_height; y++) {
120 for (int x=0; x<pixmap_width; x++) {
121 XPutPixel(ximage, x + win_width - pixmap_width, y + win_height - pixmap_height,
122 (bottom_right_bits[y] & (0x01 << x)) ? 1 : 0);
123 }
124 }
125 }
126
127 FbTk::FbPixmap *pm = new FbTk::FbPixmap(*m_win, win_width, win_height, 1);
128
129
130 FbTk::GContext gc(*pm);
131 86
132 XPutImage(disp, pm->drawable(), gc.gc(), ximage, 0, 0, 0, 0, 87 XPutImage(disp, pm.drawable(), gc.gc(), ximage, 0, 0, 0, 0,
133 win_width, win_height); 88 8, 8);
134 89
135 XDestroyImage(ximage); 90 XDestroyImage(ximage);
136 91
137 return pm; 92 return pm.release();
138
139} 93}
140 94
95};
96
97std::vector<Shape::CornerPixmaps> Shape::s_corners;
98
141Shape::Shape(FbTk::FbWindow &win, int shapeplaces): 99Shape::Shape(FbTk::FbWindow &win, int shapeplaces):
142 m_win(&win), 100 m_win(&win),
101 m_shapesource(0),
102 m_shapesource_xoff(0),
103 m_shapesource_yoff(0),
143 m_shapeplaces(shapeplaces) { 104 m_shapeplaces(shapeplaces) {
144 105
145 m_clipshape.reset(createShape(true)); 106#ifdef SHAPE
146 m_boundingshape.reset(createShape(false)); 107 initCorners(win.screenNumber());
108#endif
109
110 update();
147} 111}
148 112
149Shape::~Shape() { 113Shape::~Shape() {
@@ -157,19 +121,32 @@ Shape::~Shape() {
157 0, 0, 121 0, 0,
158 0, 122 0,
159 ShapeSet); 123 ShapeSet);
160 // Reset shape of window 124 XShapeCombineMask(FbTk::App::instance()->display(),
161 if (m_boundingshape.get()) { 125 m_win->window(),
162 XShapeCombineMask(FbTk::App::instance()->display(), 126 ShapeBounding,
163 m_win->window(), 127 0, 0,
164 ShapeBounding, 128 0,
165 0, 0, 129 ShapeSet);
166 0, 130 }
167 ShapeSet);
168 }
169 }
170#endif // SHAPE 131#endif // SHAPE
171} 132}
172 133
134void Shape::initCorners(int screen_num) {
135 if (s_corners.size() == 0)
136 s_corners.resize(ScreenCount(FbTk::App::instance()->display()));
137
138 static const unsigned char left_bits[] = { 0xc0, 0xf8, 0xfc, 0xfe, 0xfe, 0xfe, 0xff, 0xff };
139 static const unsigned char right_bits[] = { 0x03, 0x1f, 0x3f, 0x7f, 0x7f, 0x7f, 0xff, 0xff};
140 static const unsigned char bottom_left_bits[] = { 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfc, 0xf8, 0xc0 };
141 static const unsigned char bottom_right_bits[] = { 0xff, 0xff, 0x7f, 0x7f, 0x7f, 0x3f, 0x1f, 0x03 };
142
143 s_corners[screen_num].topleft = ::makePixmap(*m_win, left_bits);
144 s_corners[screen_num].topright = ::makePixmap(*m_win, right_bits);
145 s_corners[screen_num].botleft = ::makePixmap(*m_win, bottom_left_bits);
146 s_corners[screen_num].botright = ::makePixmap(*m_win, bottom_right_bits);
147
148}
149
173void Shape::setPlaces(int shapeplaces) { 150void Shape::setPlaces(int shapeplaces) {
174 m_shapeplaces = shapeplaces; 151 m_shapeplaces = shapeplaces;
175} 152}
@@ -177,41 +154,144 @@ void Shape::setPlaces(int shapeplaces) {
177void Shape::update() { 154void Shape::update() {
178 if (m_win == 0 || m_win->window() == 0) 155 if (m_win == 0 || m_win->window() == 0)
179 return; 156 return;
157
180#ifdef SHAPE 158#ifdef SHAPE
181 if (m_clipshape.get() == 0 || 159 /**
182 m_win->width() != clipWidth() || 160 * Set the client's shape in position,
183 m_win->height() != clipHeight()) { 161 * or wipe the shape and return.
184 m_clipshape.reset(createShape(true)); 162 */
163 Display *display = FbTk::App::instance()->display();
164 int bw = m_win->borderWidth();
165 int width = m_win->width();
166 int height = m_win->height();
167
168 if (m_shapesource == 0 && m_shapeplaces == 0) {
169 /* clear the shape and return */
170 XShapeCombineMask(display,
171 m_win->window(), ShapeClip,
172 0, 0,
173 None, ShapeSet);
174 XShapeCombineMask(display,
175 m_win->window(), ShapeBounding,
176 0, 0,
177 None, ShapeSet);
178 return;
185 } 179 }
186 if (m_boundingshape.get() == 0 ||
187 (m_win->width()+m_win->borderWidth()*2) != width() ||
188 (m_win->height()+m_win->borderWidth()*2) != height()) {
189 if (m_win->borderWidth() != 0)
190 m_boundingshape.reset(createShape(false));
191 else
192 m_boundingshape.reset(0);
193 180
181 XRectangle rect;
182 rect.x = 0;
183 rect.y = 0;
184 rect.width = width;
185 rect.height = height;
186
187 XShapeCombineRectangles(display,
188 m_win->window(), ShapeClip,
189 0, 0, /* offsets */
190 &rect,
191 1, /* number of rectangles */
192 ShapeSet, /* op */
193 2 /* ordering: YXSorted... only 1: doesn't matter */ );
194
195 rect.x = -bw;
196 rect.y = -bw;
197 rect.width = width+2*bw;
198 rect.height = height+2*bw;
199
200 XShapeCombineRectangles(display,
201 m_win->window(), ShapeBounding,
202 0, 0, /* offsets */
203 &rect,
204 1, /* number of rectangles */
205 ShapeSet, /* op */
206 2 /* ordering: YXSorted... only 1: doesn't matter */ );
207
208 if (m_shapesource != 0) {
209
210 /*
211 Copy the shape from the source.
212 We achieve this by subtracting the client-area size from the shape, and then
213 unioning in the client's mask.
214 */
215 rect.x = m_shapesource_xoff;
216 rect.y = m_shapesource_yoff;
217 rect.width = m_shapesource->width();
218 rect.height = m_shapesource->height();
219
220 XShapeCombineRectangles(display,
221 m_win->window(), ShapeClip,
222 0, 0, /* offsets */
223 &rect,
224 1, /* number of rectangles */
225 ShapeSubtract, /* op */
226 2 /* ordering: YXSorted... only 1: doesn't matter */ );
227
228 XShapeCombineShape(display,
229 m_win->window(), ShapeClip,
230 rect.x, rect.y, // xOff, yOff
231 m_shapesource->window(),
232 ShapeClip, ShapeUnion);
233
234 /*
235 Now the bounding rectangle. Note that the frame has a shared border with the region above the
236 client (i.e. titlebar), so we don't want to wipe the shared border, hence the adjustments.
237 */
238 rect.x = m_shapesource_xoff; // note that the full bounding region is already offset by a -borderwidth!
239 rect.y = m_shapesource_yoff;
240 rect.width = m_shapesource->width(); // we don't wipe the outer bounding region [i think]
241 rect.height = m_shapesource->height();
242
243 // we want to delete the client area, dont care about borders really
244 XShapeCombineRectangles(display,
245 m_win->window(), ShapeBounding,
246 0, 0, /* offsets */
247 &rect,
248 1, /* number of rectangles */
249 ShapeSubtract, /* op */
250 2 /* ordering: YXSorted... only 1: doesn't matter */ );
251
252 XShapeCombineShape(display,
253 m_win->window(), ShapeBounding,
254 rect.x , rect.y, // xOff, yOff
255 m_shapesource->window(),
256 ShapeBounding, ShapeUnion);
194 } 257 }
195 258
196 // the m_shape can be = 0 which will just raeset the shape mask
197 // and make the window normal
198 XShapeCombineMask(FbTk::App::instance()->display(),
199 m_win->window(),
200 ShapeClip,
201 0, 0,
202 (m_clipshape.get() != 0)? m_clipshape->drawable() : 0,
203 ShapeSet);
204
205 // the m_shape can be = 0 which will just raeset the shape mask
206 // and make the window normal
207 XShapeCombineMask(FbTk::App::instance()->display(),
208 m_win->window(),
209 ShapeBounding,
210 -m_win->borderWidth(), -m_win->borderWidth(),
211 (m_boundingshape.get() != 0)? m_boundingshape->drawable() :
212 ((m_clipshape.get() != 0)? m_clipshape->drawable(): 0),
213 ShapeSet);
214 259
260 CornerPixmaps &corners = s_corners[m_win->screenNumber()];
261#define SHAPECORNER(corner, x, y, shapekind) \
262 XShapeCombineMask(FbTk::App::instance()->display(), \
263 m_win->window(), \
264 shapekind, \
265 x, y, \
266 corners.corner.drawable(), \
267 ShapeSubtract);
268
269 /**
270 * Set the top corners if the y offset is nonzero.
271 */
272 if (m_shapesource == 0 || m_shapesource_yoff != 0) {
273 if (m_shapeplaces & TOPLEFT) {
274 SHAPECORNER(topleft, 0, 0, ShapeClip);
275 SHAPECORNER(topleft, -bw, -bw, ShapeBounding);
276 }
277 if (m_shapeplaces & TOPRIGHT) {
278 SHAPECORNER(topright, width-8, 0, ShapeClip);
279 SHAPECORNER(topright, width+bw-8, -bw, ShapeBounding);
280 }
281 }
282
283 // note that the bottom corners y-vals are offset by 8 (the height of the corner pixmaps)
284 if (m_shapesource == 0 || (m_shapesource_yoff+(signed) m_shapesource->height()) < height
285 || m_shapesource_yoff >= height /* shaded */) {
286 if (m_shapeplaces & BOTTOMLEFT) {
287 SHAPECORNER(botleft, 0, height-8, ShapeClip);
288 SHAPECORNER(botleft, -bw, height+bw-8, ShapeBounding);
289 }
290 if (m_shapeplaces & BOTTOMRIGHT) {
291 SHAPECORNER(botright, width-8, height-8, ShapeClip);
292 SHAPECORNER(botright, width+bw-8, height+bw-8, ShapeBounding);
293 }
294 }
215 295
216#endif // SHAPE 296#endif // SHAPE
217 297
@@ -222,6 +302,41 @@ void Shape::setWindow(FbTk::FbWindow &win) {
222 update(); 302 update();
223} 303}
224 304
305/**
306 * set the shape source to the given window.
307 * This is purely for client windows at the moment, where the offsets and height/width of the
308 * target window and the source window are used to determine whether to shape a given corner.
309 *
310 * (note: xoffset will always be zero, and widths always match, so we ignore those)
311 *
312 * i.e. if the yoffset is not zero, then the top corners are shaped.
313 * if the target height is bigger than the source plus yoffset, then the bottom corners are
314 * shaped.
315 *
316 * If *either* the top or bottom corners are not shaped due to this, but a shape source window
317 * is given, then the bounding shape has the borders alongside the source window deleted, otherwise
318 * they are left hanging outside the client's shape.
319 */
320void Shape::setShapeSource(FbTk::FbWindow *win, int xoff, int yoff, bool always_update) {
321 if (win != 0 && !isShaped(*win)) {
322 win = 0;
323 if (m_shapesource == 0 && !always_update)
324 return;
325 }
326
327 // even if source is same, want to update the shape on it
328 m_shapesource = win;
329 m_shapesource_xoff = xoff;
330 m_shapesource_yoff = yoff;
331 update();
332}
333
334void Shape::setShapeOffsets(int xoff, int yoff) {
335 m_shapesource_xoff = xoff;
336 m_shapesource_yoff = yoff;
337 update();
338}
339
225void Shape::setShapeNotify(const FbTk::FbWindow &win) { 340void Shape::setShapeNotify(const FbTk::FbWindow &win) {
226#ifdef SHAPE 341#ifdef SHAPE
227 XShapeSelectInput(FbTk::App::instance()->display(), 342 XShapeSelectInput(FbTk::App::instance()->display(),
@@ -248,18 +363,3 @@ bool Shape::isShaped(const FbTk::FbWindow &win) {
248 return (shaped != 0 ? true : false); 363 return (shaped != 0 ? true : false);
249} 364}
250 365
251unsigned int Shape::width() const {
252 return m_boundingshape.get() ? m_boundingshape->width() : 0;
253}
254
255unsigned int Shape::height() const {
256 return m_boundingshape.get() ? m_boundingshape->height() : 0;
257}
258
259unsigned int Shape::clipWidth() const {
260 return m_clipshape.get() ? m_clipshape->width() : 0;
261}
262
263unsigned int Shape::clipHeight() const {
264 return m_clipshape.get() ? m_clipshape->height() : 0;
265}
diff --git a/src/Shape.hh b/src/Shape.hh
index c8db79a..5f26d05 100644
--- a/src/Shape.hh
+++ b/src/Shape.hh
@@ -24,12 +24,14 @@
24#ifndef SHAPE_HH 24#ifndef SHAPE_HH
25#define SHAPE_HH 25#define SHAPE_HH
26 26
27#include "FbTk/FbPixmap.hh"
28
27#include <X11/Xlib.h> 29#include <X11/Xlib.h>
28#include <memory> 30#include <memory>
31#include <vector>
29 32
30namespace FbTk { 33namespace FbTk {
31class FbWindow; 34class FbWindow;
32class FbPixmap;
33} 35}
34 36
35/// creates round corners on windows 37/// creates round corners on windows
@@ -51,6 +53,10 @@ public:
51 void update(); 53 void update();
52 /// assign a new window 54 /// assign a new window
53 void setWindow(FbTk::FbWindow &win); 55 void setWindow(FbTk::FbWindow &win);
56 /// Assign a window to merge our shape with.
57 /// (note that this is currently specific to frames)
58 void setShapeSource(FbTk::FbWindow *win, int xoff, int yoff, bool always_update);
59 void setShapeOffsets(int xoff, int yoff);
54 unsigned int width() const; 60 unsigned int width() const;
55 unsigned int height() const; 61 unsigned int height() const;
56 unsigned int clipWidth() const; 62 unsigned int clipWidth() const;
@@ -60,11 +66,21 @@ public:
60 /// @return true if window has shape 66 /// @return true if window has shape
61 static bool isShaped(const FbTk::FbWindow &win); 67 static bool isShaped(const FbTk::FbWindow &win);
62private: 68private:
63 FbTk::FbPixmap *createShape(bool clipshape); // true for clip, false for bounding
64
65 FbTk::FbWindow *m_win; ///< window to be shaped 69 FbTk::FbWindow *m_win; ///< window to be shaped
66 std::auto_ptr<FbTk::FbPixmap> m_clipshape; ///< our shape pixmap 70 FbTk::FbWindow *m_shapesource; ///< window to pull shape from
67 std::auto_ptr<FbTk::FbPixmap> m_boundingshape; ///< our shape pixmap 71 int m_shapesource_xoff, m_shapesource_yoff;
72
73 void initCorners(int screen_num);
74
75 struct CornerPixmaps {
76 FbTk::FbPixmap topleft;
77 FbTk::FbPixmap topright;
78 FbTk::FbPixmap botleft;
79 FbTk::FbPixmap botright;
80 };
81
82 // unfortunately, we need a separate pixmap per screen
83 static std::vector<CornerPixmaps> s_corners;
68 int m_shapeplaces; ///< places to shape 84 int m_shapeplaces; ///< places to shape
69 85
70}; 86};
diff --git a/src/Window.cc b/src/Window.cc
index ab917da..9ee1c5e 100644
--- a/src/Window.cc
+++ b/src/Window.cc
@@ -268,7 +268,6 @@ FluxboxWindow::FluxboxWindow(WinClient &client, FbWinFrameTheme &tm,
268 m_old_decoration_mask(0), 268 m_old_decoration_mask(0),
269 m_client(&client), 269 m_client(&client),
270 m_toggled_decos(false), 270 m_toggled_decos(false),
271 m_shaped(false),
272 m_icon_hidden(false), 271 m_icon_hidden(false),
273 m_focus_hidden(false), 272 m_focus_hidden(false),
274 m_old_pos_x(0), m_old_pos_y(0), 273 m_old_pos_x(0), m_old_pos_y(0),
@@ -350,16 +349,10 @@ void FluxboxWindow::init() {
350 m_client->setFluxboxWindow(this); 349 m_client->setFluxboxWindow(this);
351 m_client->setGroupLeftWindow(None); // nothing to the left. 350 m_client->setGroupLeftWindow(None); // nothing to the left.
352 351
353 // check for shape extension and whether the window is shaped
354 m_shaped = false;
355
356 if (Fluxbox::instance()->haveShape()) { 352 if (Fluxbox::instance()->haveShape()) {
357 Shape::setShapeNotify(winClient()); 353 Shape::setShapeNotify(winClient());
358 m_shaped = Shape::isShaped(winClient());
359 } 354 }
360 355
361 frame().setUseShape(!m_shaped);
362
363 //!! TODO init of client should be better 356 //!! TODO init of client should be better
364 // we don't want to duplicate code here and in attachClient 357 // we don't want to duplicate code here and in attachClient
365 m_clientlist.push_back(m_client); 358 m_clientlist.push_back(m_client);
@@ -548,36 +541,12 @@ void FluxboxWindow::init() {
548 // no focus default 541 // no focus default
549 setFocusFlag(false); 542 setFocusFlag(false);
550 543
551 if (m_shaped)
552 shape();
553
554 setupWindow(); 544 setupWindow();
555 545
556 FbTk::App::instance()->sync(false); 546 FbTk::App::instance()->sync(false);
557 547
558} 548}
559 549
560/// apply shape to this window
561void FluxboxWindow::shape() {
562#ifdef SHAPE
563 if (m_shaped) {
564 XShapeCombineShape(display,
565 frame().window().window(), ShapeClip,
566 0, frame().clientArea().y(), // xOff, yOff
567 m_client->window(),
568 ShapeClip, ShapeSet);
569 XShapeCombineShape(display,
570 frame().window().window(), ShapeBounding,
571 0, frame().clientArea().y(), // xOff, yOff
572 m_client->window(),
573 ShapeBounding, ShapeSet);
574 XFlush(display);
575 }
576#endif // SHAPE
577
578}
579
580
581/// attach a client to this window and destroy old window 550/// attach a client to this window and destroy old window
582void FluxboxWindow::attachClient(WinClient &client, int x, int y) { 551void FluxboxWindow::attachClient(WinClient &client, int x, int y) {
583 //!! TODO: check for isGroupable in client 552 //!! TODO: check for isGroupable in client
@@ -995,8 +964,10 @@ bool FluxboxWindow::setCurrentClient(WinClient &client, bool setinput) {
995 if (!button) 964 if (!button)
996 return false; 965 return false;
997 966
998 if (&client != m_client) 967 if (&client != m_client) {
999 m_screen.focusControl().setScreenFocusedWindow(client); 968 m_screen.focusControl().setScreenFocusedWindow(client);
969 frame().setShapingClient(&client, false);
970 }
1000 m_client = &client; 971 m_client = &client;
1001 m_client->raise(); 972 m_client->raise();
1002 m_client->focusSig().notify(); 973 m_client->focusSig().notify();
@@ -1042,6 +1013,8 @@ void FluxboxWindow::associateClientWindow(bool use_attrs,
1042 updateTitleFromClient(*m_client); 1013 updateTitleFromClient(*m_client);
1043 updateIconNameFromClient(*m_client); 1014 updateIconNameFromClient(*m_client);
1044 1015
1016 frame().setShapingClient(m_client, false);
1017
1045 if (use_attrs) 1018 if (use_attrs)
1046 frame().moveResizeForClient(x, y, 1019 frame().moveResizeForClient(x, y,
1047 width, height, gravity, client_bw); 1020 width, height, gravity, client_bw);
@@ -1299,7 +1272,6 @@ void FluxboxWindow::moveResize(int new_x, int new_y,
1299 sendConfigureNotify(); 1272 sendConfigureNotify();
1300 } 1273 }
1301 1274
1302 shape();
1303 1275
1304 if (!moving) { 1276 if (!moving) {
1305 m_last_resize_x = new_x; 1277 m_last_resize_x = new_x;
@@ -1319,8 +1291,6 @@ void FluxboxWindow::moveResizeForClient(int new_x, int new_y,
1319 shaded = false; 1291 shaded = false;
1320 sendConfigureNotify(); 1292 sendConfigureNotify();
1321 1293
1322 shape();
1323
1324 if (!moving) { 1294 if (!moving) {
1325 m_last_resize_x = new_x; 1295 m_last_resize_x = new_x;
1326 m_last_resize_y = new_y; 1296 m_last_resize_y = new_y;
@@ -1617,7 +1587,7 @@ void FluxboxWindow::setFullscreen(bool flag) {
1617 1587
1618 fullscreen = false; 1588 fullscreen = false;
1619 1589
1620 frame().setUseShape(!m_shaped); 1590 frame().setUseShape(true);
1621 if (m_toggled_decos) { 1591 if (m_toggled_decos) {
1622 if (m_old_decoration_mask & DECORM_TITLEBAR) 1592 if (m_old_decoration_mask & DECORM_TITLEBAR)
1623 setDecoration(DECOR_NONE); 1593 setDecoration(DECOR_NONE);
@@ -2342,24 +2312,10 @@ void FluxboxWindow::handleEvent(XEvent &event) {
2342#endif // DEBUG 2312#endif // DEBUG
2343 XShapeEvent *shape_event = (XShapeEvent *)&event; 2313 XShapeEvent *shape_event = (XShapeEvent *)&event;
2344 2314
2345 if (shape_event->kind != ShapeBounding) 2315 if (shape_event->shaped)
2346 break; 2316 frame().setShapingClient(m_client, true);
2347 2317 else
2348 if (shape_event->shaped) { 2318 frame().setShapingClient(0, true);
2349 m_shaped = true;
2350 shape();
2351 } else {
2352 m_shaped = false;
2353 // set no shape
2354 XShapeCombineMask(display,
2355 frame().window().window(), ShapeClip,
2356 0, 0,
2357 None, ShapeSet);
2358 XShapeCombineMask(display,
2359 frame().window().window(), ShapeBounding,
2360 0, 0,
2361 None, ShapeSet);
2362 }
2363 2319
2364 FbTk::App::instance()->sync(false); 2320 FbTk::App::instance()->sync(false);
2365 break; 2321 break;
diff --git a/src/Window.hh b/src/Window.hh
index 15de2bb..92431ab 100644
--- a/src/Window.hh
+++ b/src/Window.hh
@@ -454,8 +454,6 @@ private:
454 void updateButtons(); 454 void updateButtons();
455 455
456 void init(); 456 void init();
457 /// applies a shape mask to the window if it has one
458 void shape();
459 void updateClientLeftWindow(); 457 void updateClientLeftWindow();
460 void grabButtons(); 458 void grabButtons();
461 459
@@ -560,7 +558,6 @@ private:
560 bool resize, move, iconify, maximize, close, tabable; 558 bool resize, move, iconify, maximize, close, tabable;
561 } functions; 559 } functions;
562 560
563 bool m_shaped; ///< if the window is shaped with a mask
564 bool m_icon_hidden; ///< if the window is in the iconbar 561 bool m_icon_hidden; ///< if the window is in the iconbar
565 bool m_focus_hidden; ///< if the window is in the NextWindow list 562 bool m_focus_hidden; ///< if the window is in the NextWindow list
566 int m_old_pos_x, m_old_pos_y; ///< old position so we can restore from maximized 563 int m_old_pos_x, m_old_pos_y; ///< old position so we can restore from maximized