746 lines
18 KiB
C++
746 lines
18 KiB
C++
|
|
||
|
#include "Border.h"
|
||
|
#include "Client.h"
|
||
|
#include "Manager.h"
|
||
|
#include "Rotated.h"
|
||
|
|
||
|
// These are degenerate initialisations, don't change them
|
||
|
int Border::m_tabWidth = -1;
|
||
|
XRotFontStruct *Border::m_tabFont = 0;
|
||
|
GC Border::m_drawGC = 0;
|
||
|
|
||
|
unsigned long Border::m_foregroundPixel;
|
||
|
unsigned long Border::m_backgroundPixel;
|
||
|
unsigned long Border::m_frameBackgroundPixel;
|
||
|
unsigned long Border::m_buttonBackgroundPixel;
|
||
|
unsigned long Border::m_borderPixel;
|
||
|
|
||
|
static int borderCounter = 0;
|
||
|
|
||
|
|
||
|
declareList(RectangleList, XRectangle);
|
||
|
implementList(RectangleList, XRectangle);
|
||
|
|
||
|
class BorderRectangleList : public RectangleList
|
||
|
{
|
||
|
public:
|
||
|
BorderRectangleList() { }
|
||
|
~BorderRectangleList() { }
|
||
|
|
||
|
void appendRect(int x, int y, int w, int h);
|
||
|
};
|
||
|
|
||
|
void BorderRectangleList::appendRect(int x, int y, int w, int h)
|
||
|
{
|
||
|
XRectangle r;
|
||
|
r.x = x; r.y = y; r.width = w; r.height = h;
|
||
|
append(r);
|
||
|
}
|
||
|
|
||
|
|
||
|
Border::Border(Client *const c, Window child) :
|
||
|
m_client(c), m_parent(0), m_tab(0),
|
||
|
m_child(child), m_button(0), m_resize(0), m_label(0),
|
||
|
m_tabHeight(-1), m_prevW(-1), m_prevH(-1)
|
||
|
{
|
||
|
m_parent = root();
|
||
|
|
||
|
if (m_tabFont == 0) {
|
||
|
|
||
|
if (!(m_tabFont = XRotLoadFont(display(), CONFIG_NICE_FONT, 90.0)) &&
|
||
|
!(m_tabFont = XRotLoadFont(display(), CONFIG_NASTY_FONT, 90.0))) {
|
||
|
windowManager()->fatal
|
||
|
("couldn't load default rotated font, bailing out");
|
||
|
}
|
||
|
|
||
|
m_tabWidth = m_tabFont->height + 4;
|
||
|
if (m_tabWidth < TAB_TOP_HEIGHT * 2 + 8) {
|
||
|
m_tabWidth = TAB_TOP_HEIGHT * 2 + 8;
|
||
|
}
|
||
|
|
||
|
m_foregroundPixel = windowManager()->allocateColour
|
||
|
(CONFIG_TAB_FOREGROUND, "tab foreground");
|
||
|
m_backgroundPixel = windowManager()->allocateColour
|
||
|
(CONFIG_TAB_BACKGROUND, "tab background");
|
||
|
m_frameBackgroundPixel = windowManager()->allocateColour
|
||
|
(CONFIG_FRAME_BACKGROUND, "frame background");
|
||
|
m_buttonBackgroundPixel = windowManager()->allocateColour
|
||
|
(CONFIG_BUTTON_BACKGROUND, "button background");
|
||
|
m_borderPixel = windowManager()->allocateColour
|
||
|
(CONFIG_BORDERS, "border");
|
||
|
|
||
|
XGCValues values;
|
||
|
values.foreground = m_foregroundPixel;
|
||
|
values.background = m_backgroundPixel;
|
||
|
values.function = GXcopy;
|
||
|
values.line_width = 0;
|
||
|
values.subwindow_mode = IncludeInferiors;
|
||
|
|
||
|
m_drawGC = XCreateGC(display(), root(),
|
||
|
GCForeground | GCBackground | GCFunction |
|
||
|
GCLineWidth | GCSubwindowMode,
|
||
|
&values);
|
||
|
|
||
|
if (!m_drawGC) {
|
||
|
windowManager()->fatal("couldn't allocate border GC");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
++borderCounter;
|
||
|
}
|
||
|
|
||
|
|
||
|
Border::~Border()
|
||
|
{
|
||
|
if (m_parent != root()) {
|
||
|
if (!m_parent) fprintf(stderr,"wm2: zero parent in Border::~Border\n");
|
||
|
else {
|
||
|
XDestroyWindow(display(), m_tab);
|
||
|
XDestroyWindow(display(), m_button);
|
||
|
XDestroyWindow(display(), m_parent);
|
||
|
|
||
|
// bad window if its parent has already gone:
|
||
|
XDestroyWindow(display(), m_resize);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (m_label) free(m_label);
|
||
|
|
||
|
if (--borderCounter == 0) {
|
||
|
XFreeGC(display(), m_drawGC);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void Border::fatal(char *s)
|
||
|
{
|
||
|
windowManager()->fatal(s);
|
||
|
}
|
||
|
|
||
|
|
||
|
Display *Border::display()
|
||
|
{
|
||
|
return m_client->display();
|
||
|
}
|
||
|
|
||
|
|
||
|
WindowManager *Border::windowManager()
|
||
|
{
|
||
|
return m_client->windowManager();
|
||
|
}
|
||
|
|
||
|
|
||
|
Window Border::root()
|
||
|
{
|
||
|
return m_client->root();
|
||
|
}
|
||
|
|
||
|
|
||
|
void Border::expose(XExposeEvent *e)
|
||
|
{
|
||
|
if (e->window != m_tab) return;
|
||
|
drawLabel();
|
||
|
}
|
||
|
|
||
|
|
||
|
void Border::drawLabel()
|
||
|
{
|
||
|
if (m_label) {
|
||
|
XClearWindow(display(), m_tab);
|
||
|
XRotDrawString(display(), m_tabFont, m_tab, m_drawGC,
|
||
|
2 + m_tabFont->max_ascent, m_tabHeight - 1,
|
||
|
m_label, strlen(m_label));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
Boolean Border::isTransient(void)
|
||
|
{
|
||
|
return m_client->isTransient();
|
||
|
}
|
||
|
|
||
|
|
||
|
Boolean Border::isFixedSize(void)
|
||
|
{
|
||
|
return m_client->isFixedSize();
|
||
|
}
|
||
|
|
||
|
|
||
|
void Border::fixTabHeight(int maxHeight)
|
||
|
{
|
||
|
m_tabHeight = 0x7fff;
|
||
|
maxHeight -= m_tabWidth; // for diagonal
|
||
|
|
||
|
if (m_label) free(m_label);
|
||
|
m_label = NewString(m_client->label());
|
||
|
|
||
|
if (m_label) {
|
||
|
m_tabHeight =
|
||
|
XRotTextWidth(m_tabFont, m_label, strlen(m_label)) + 6 + m_tabWidth;
|
||
|
}
|
||
|
|
||
|
if (m_tabHeight <= maxHeight) return;
|
||
|
|
||
|
if (m_label) free(m_label);
|
||
|
m_label = m_client->iconName() ?
|
||
|
NewString(m_client->iconName()) : NewString("incognito");
|
||
|
|
||
|
int len = strlen(m_label);
|
||
|
m_tabHeight = XRotTextWidth(m_tabFont, m_label, len) + 6 + m_tabWidth;
|
||
|
if (m_tabHeight <= maxHeight) return;
|
||
|
|
||
|
char *newLabel = (char *)malloc(len + 4);
|
||
|
|
||
|
do {
|
||
|
strlcpy(newLabel, m_label, len + 4);
|
||
|
strlcat(newLabel, "...", len + 4);
|
||
|
m_tabHeight = XRotTextWidth(m_tabFont, newLabel,
|
||
|
strlen(newLabel)) + 6 + m_tabWidth;
|
||
|
--len;
|
||
|
|
||
|
} while (m_tabHeight > maxHeight && len > 2);
|
||
|
|
||
|
free(m_label);
|
||
|
m_label = newLabel;
|
||
|
|
||
|
if (m_tabHeight > maxHeight) m_tabHeight = maxHeight;
|
||
|
}
|
||
|
|
||
|
|
||
|
void Border::shapeTransientParent(int w, int h)
|
||
|
{
|
||
|
XRectangle r;
|
||
|
|
||
|
r.x = xIndent() - 1; r.y = yIndent() - 1;
|
||
|
r.width = w + 2; r.height = h + 2;
|
||
|
|
||
|
XShapeCombineRectangles
|
||
|
(display(), m_parent, ShapeBounding, 0, 0, &r, 1, ShapeSet, YXBanded);
|
||
|
|
||
|
r.x = xIndent(); r.y = yIndent();
|
||
|
r.width = w; r.height = h;
|
||
|
|
||
|
XShapeCombineRectangles
|
||
|
(display(), m_parent, ShapeClip, 0, 0, &r, 1, ShapeSet, YXBanded);
|
||
|
}
|
||
|
|
||
|
|
||
|
void Border::setTransientFrameVisibility(Boolean visible, int w, int h)
|
||
|
{
|
||
|
int i;
|
||
|
BorderRectangleList rl;
|
||
|
|
||
|
rl.appendRect(0, 0, w + 1, yIndent() - 1);
|
||
|
for (i = 1; i < yIndent(); ++i) {
|
||
|
rl.appendRect(w + 1, i - 1, i + 1, 1);
|
||
|
}
|
||
|
rl.appendRect(0, yIndent() - 1, xIndent() - 1, h - yIndent() + 2);
|
||
|
for (i = 1; i < yIndent(); ++i) {
|
||
|
rl.appendRect(i - 1, h, 1, i + 2);
|
||
|
}
|
||
|
|
||
|
XShapeCombineRectangles
|
||
|
(display(), m_parent, ShapeBounding,
|
||
|
0, 0, rl.array(0, rl.count()), rl.count(),
|
||
|
visible ? ShapeUnion : ShapeSubtract, YXSorted);
|
||
|
|
||
|
rl.remove_all();
|
||
|
|
||
|
rl.appendRect(1, 1, w, yIndent() - 2);
|
||
|
for (i = 2; i < yIndent(); ++i) {
|
||
|
rl.appendRect(w + 1, i - 1, i, 1);
|
||
|
}
|
||
|
rl.appendRect(1, yIndent() - 1, xIndent() - 2, h - yIndent() + 1);
|
||
|
for (i = 2; i < yIndent(); ++i) {
|
||
|
rl.appendRect(i - 1, h, 1, i + 1);
|
||
|
}
|
||
|
|
||
|
XShapeCombineRectangles
|
||
|
(display(), m_parent, ShapeClip,
|
||
|
0, 0, rl.array(0, rl.count()), rl.count(),
|
||
|
visible ? ShapeUnion : ShapeSubtract, YXSorted);
|
||
|
}
|
||
|
|
||
|
|
||
|
void Border::shapeParent(int w, int h)
|
||
|
{
|
||
|
int i;
|
||
|
int mainRect;
|
||
|
BorderRectangleList rl;
|
||
|
|
||
|
if (isTransient()) {
|
||
|
shapeTransientParent(w, h);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Bounding rectangles -- clipping will be the same except for
|
||
|
// child window border
|
||
|
|
||
|
// top of tab
|
||
|
rl.appendRect(0, 0, w + m_tabWidth + 1, TAB_TOP_HEIGHT + 2);
|
||
|
|
||
|
// struts in tab, left...
|
||
|
rl.appendRect(0, TAB_TOP_HEIGHT + 1,
|
||
|
TAB_TOP_HEIGHT + 2, m_tabWidth - TAB_TOP_HEIGHT*2 - 1);
|
||
|
|
||
|
// ...and right
|
||
|
rl.appendRect(m_tabWidth - TAB_TOP_HEIGHT, TAB_TOP_HEIGHT + 1,
|
||
|
TAB_TOP_HEIGHT + 2, m_tabWidth - TAB_TOP_HEIGHT*2 - 1);
|
||
|
|
||
|
mainRect = rl.count();
|
||
|
rl.appendRect(xIndent() - 1, yIndent() - 1, w + 2, h + 2);
|
||
|
|
||
|
// main tab
|
||
|
rl.appendRect(0, m_tabWidth - TAB_TOP_HEIGHT, m_tabWidth + 2,
|
||
|
m_tabHeight - m_tabWidth + TAB_TOP_HEIGHT);
|
||
|
|
||
|
// diagonal
|
||
|
for (i = 1; i < m_tabWidth - 1; ++i) {
|
||
|
rl.appendRect(i, m_tabHeight + i - 1, m_tabWidth - i + 2, 1);
|
||
|
}
|
||
|
|
||
|
XShapeCombineRectangles
|
||
|
(display(), m_parent, ShapeBounding,
|
||
|
0, 0, rl.array(0, rl.count()), rl.count(), ShapeSet, YXSorted);
|
||
|
|
||
|
rl.item(mainRect).x ++;
|
||
|
rl.item(mainRect).y ++;
|
||
|
rl.item(mainRect).width -= 2;
|
||
|
rl.item(mainRect).height -= 2;
|
||
|
|
||
|
XShapeCombineRectangles
|
||
|
(display(), m_parent, ShapeClip,
|
||
|
0, 0, rl.array(0, rl.count()), rl.count(), ShapeSet, YXSorted);
|
||
|
}
|
||
|
|
||
|
|
||
|
void Border::shapeTab(int w, int)
|
||
|
{
|
||
|
int i;
|
||
|
BorderRectangleList rl;
|
||
|
|
||
|
if (isTransient()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Bounding rectangles
|
||
|
|
||
|
rl.appendRect(0, 0, w + m_tabWidth + 1, TAB_TOP_HEIGHT + 2);
|
||
|
rl.appendRect(0, TAB_TOP_HEIGHT + 1, TAB_TOP_HEIGHT + 2,
|
||
|
m_tabWidth - TAB_TOP_HEIGHT*2 - 1);
|
||
|
|
||
|
rl.appendRect(m_tabWidth - TAB_TOP_HEIGHT, TAB_TOP_HEIGHT + 1,
|
||
|
TAB_TOP_HEIGHT + 2, m_tabWidth - TAB_TOP_HEIGHT*2 - 1);
|
||
|
|
||
|
rl.appendRect(0, m_tabWidth - TAB_TOP_HEIGHT, m_tabWidth + 2,
|
||
|
m_tabHeight - m_tabWidth + TAB_TOP_HEIGHT);
|
||
|
|
||
|
for (i = 1; i < m_tabWidth - 1; ++i) {
|
||
|
rl.appendRect(i, m_tabHeight + i - 1, m_tabWidth - i + 2, 1);
|
||
|
}
|
||
|
|
||
|
XShapeCombineRectangles
|
||
|
(display(), m_tab, ShapeBounding,
|
||
|
0, 0, rl.array(0, rl.count()), rl.count(), ShapeSet, YXSorted);
|
||
|
|
||
|
rl.remove_all();
|
||
|
|
||
|
// Clipping rectangles
|
||
|
|
||
|
rl.appendRect(1, 1, w + m_tabWidth - 1, TAB_TOP_HEIGHT);
|
||
|
|
||
|
rl.appendRect(1, TAB_TOP_HEIGHT + 1, TAB_TOP_HEIGHT,
|
||
|
m_tabWidth + TAB_TOP_HEIGHT*2 - 1);
|
||
|
|
||
|
rl.appendRect(m_tabWidth - TAB_TOP_HEIGHT + 1, TAB_TOP_HEIGHT + 1,
|
||
|
TAB_TOP_HEIGHT, m_tabWidth + TAB_TOP_HEIGHT*2 - 1);
|
||
|
|
||
|
rl.appendRect(1, m_tabWidth - TAB_TOP_HEIGHT + 1, m_tabWidth,
|
||
|
m_tabHeight - m_tabWidth + TAB_TOP_HEIGHT - 1);
|
||
|
|
||
|
for (i = 1; i < m_tabWidth - 2; ++i) {
|
||
|
rl.appendRect(i + 1, m_tabHeight + i - 1, m_tabWidth - i, 1);
|
||
|
}
|
||
|
|
||
|
XShapeCombineRectangles
|
||
|
(display(), m_tab, ShapeClip,
|
||
|
0, 0, rl.array(0, rl.count()), rl.count(), ShapeSet, YXSorted);
|
||
|
}
|
||
|
|
||
|
|
||
|
void Border::resizeTab(int h)
|
||
|
{
|
||
|
int i;
|
||
|
XRectangle r;
|
||
|
BorderRectangleList rl;
|
||
|
int shorter, longer, operation;
|
||
|
|
||
|
if (isTransient()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int prevTabHeight = m_tabHeight;
|
||
|
fixTabHeight(h);
|
||
|
if (m_tabHeight == prevTabHeight) return;
|
||
|
|
||
|
XWindowChanges wc;
|
||
|
wc.height = m_tabHeight + 2 + m_tabWidth;
|
||
|
XConfigureWindow(display(), m_tab, CWHeight, &wc);
|
||
|
|
||
|
if (m_tabHeight > prevTabHeight) {
|
||
|
|
||
|
shorter = prevTabHeight;
|
||
|
longer = m_tabHeight;
|
||
|
operation = ShapeUnion;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
shorter = m_tabHeight;
|
||
|
longer = prevTabHeight + m_tabWidth;
|
||
|
operation = ShapeSubtract;
|
||
|
}
|
||
|
|
||
|
r.x = 0; r.y = shorter /*- 2*/;
|
||
|
r.width = m_tabWidth + 2; r.height = longer - shorter;
|
||
|
|
||
|
XShapeCombineRectangles(display(), m_parent, ShapeBounding,
|
||
|
0, 0, &r, 1, operation, YXBanded);
|
||
|
|
||
|
XShapeCombineRectangles(display(), m_parent, ShapeClip,
|
||
|
0, 0, &r, 1, operation, YXBanded);
|
||
|
|
||
|
XShapeCombineRectangles(display(), m_tab, ShapeBounding,
|
||
|
0, 0, &r, 1, operation, YXBanded);
|
||
|
|
||
|
r.x ++; r.width -= 2;
|
||
|
|
||
|
XShapeCombineRectangles(display(), m_tab, ShapeClip,
|
||
|
0, 0, &r, 1, operation, YXBanded);
|
||
|
|
||
|
if (m_client->isActive()) {
|
||
|
// restore a bit of the frame edge
|
||
|
r.x = m_tabWidth + 1; r.y = shorter;
|
||
|
r.width = FRAME_WIDTH - 1; r.height = longer - shorter;
|
||
|
XShapeCombineRectangles(display(), m_parent, ShapeBounding,
|
||
|
0, 0, &r, 1, ShapeUnion, YXBanded);
|
||
|
}
|
||
|
|
||
|
for (i = 1; i < m_tabWidth - 1; ++i) {
|
||
|
rl.appendRect(i, m_tabHeight + i - 1, m_tabWidth - i + 2, 1);
|
||
|
}
|
||
|
|
||
|
XShapeCombineRectangles
|
||
|
(display(), m_parent, ShapeBounding,
|
||
|
0, 0, rl.array(0, rl.count()), rl.count(), ShapeUnion, YXBanded);
|
||
|
|
||
|
XShapeCombineRectangles
|
||
|
(display(), m_parent, ShapeClip,
|
||
|
0, 0, rl.array(0, rl.count()), rl.count(), ShapeUnion, YXBanded);
|
||
|
|
||
|
XShapeCombineRectangles
|
||
|
(display(), m_tab, ShapeBounding,
|
||
|
0, 0, rl.array(0, rl.count()), rl.count(), ShapeUnion, YXBanded);
|
||
|
|
||
|
if (rl.count() < 2) return;
|
||
|
|
||
|
for (i = 0; i < rl.count() - 1; ++i) {
|
||
|
rl.item(i).x ++; rl.item(i).width -= 2;
|
||
|
}
|
||
|
|
||
|
XShapeCombineRectangles
|
||
|
(display(), m_tab, ShapeClip,
|
||
|
0, 0, rl.array(0, rl.count() - 1), rl.count() - 1,
|
||
|
ShapeUnion, YXBanded);
|
||
|
}
|
||
|
|
||
|
|
||
|
void Border::shapeResize()
|
||
|
{
|
||
|
int i;
|
||
|
BorderRectangleList rl;
|
||
|
|
||
|
for (i = 0; i < FRAME_WIDTH*2; ++i) {
|
||
|
rl.appendRect(FRAME_WIDTH*2 - i - 1, i, i + 1, 1);
|
||
|
}
|
||
|
|
||
|
XShapeCombineRectangles
|
||
|
(display(), m_resize, ShapeBounding, 0, 0,
|
||
|
rl.array(0, rl.count()), rl.count(), ShapeSet, YXBanded);
|
||
|
|
||
|
rl.remove_all();
|
||
|
|
||
|
for (i = 1; i < FRAME_WIDTH*2; ++i) {
|
||
|
rl.appendRect(FRAME_WIDTH*2 - i, i, i, 1);
|
||
|
}
|
||
|
|
||
|
XShapeCombineRectangles
|
||
|
(display(), m_resize, ShapeClip, 0, 0,
|
||
|
rl.array(0, rl.count()), rl.count(), ShapeSet, YXBanded);
|
||
|
|
||
|
rl.remove_all();
|
||
|
|
||
|
for (i = 0; i < FRAME_WIDTH*2 - 3; ++i) {
|
||
|
rl.appendRect(FRAME_WIDTH*2 - i - 1, i + 3, 1, 1);
|
||
|
}
|
||
|
|
||
|
XShapeCombineRectangles
|
||
|
(display(), m_resize, ShapeClip, 0, 0,
|
||
|
rl.array(0, rl.count()), rl.count(), ShapeSubtract, YXBanded);
|
||
|
|
||
|
windowManager()->installCursorOnWindow
|
||
|
(WindowManager::DownrightCursor, m_resize);
|
||
|
}
|
||
|
|
||
|
|
||
|
void Border::setFrameVisibility(Boolean visible, int w, int h)
|
||
|
{
|
||
|
BorderRectangleList rl;
|
||
|
|
||
|
if (CONFIG_PROD_SHAPE) {
|
||
|
shapeParent(w, h);
|
||
|
shapeTab(w, h);
|
||
|
}
|
||
|
|
||
|
if (isTransient()) {
|
||
|
setTransientFrameVisibility(visible, w, h);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Bounding rectangles
|
||
|
|
||
|
rl.appendRect(m_tabWidth + w + 1, 0, FRAME_WIDTH + 1, FRAME_WIDTH);
|
||
|
|
||
|
rl.appendRect(m_tabWidth + 2, TAB_TOP_HEIGHT + 2, w,
|
||
|
FRAME_WIDTH - TAB_TOP_HEIGHT - 2);
|
||
|
|
||
|
// for button
|
||
|
int ww = m_tabWidth - TAB_TOP_HEIGHT*2 - 4;
|
||
|
rl.appendRect((m_tabWidth + 2 - ww) / 2, (m_tabWidth+2 - ww) / 2, ww, ww);
|
||
|
|
||
|
rl.appendRect(m_tabWidth + 2, FRAME_WIDTH,
|
||
|
FRAME_WIDTH - 2, m_tabHeight + m_tabWidth - FRAME_WIDTH - 2);
|
||
|
|
||
|
// swap last two if sorted wrong
|
||
|
if (rl.item(rl.count()-2).y > rl.item(rl.count()-1).y) {
|
||
|
rl.append(rl.item(rl.count()-2));
|
||
|
rl.remove(rl.count()-3);
|
||
|
}
|
||
|
|
||
|
int final = rl.count();
|
||
|
rl.append(rl.item(final-1));
|
||
|
rl.item(final).x -= 1;
|
||
|
rl.item(final).y += rl.item(final).height;
|
||
|
rl.item(final).width += 1;
|
||
|
rl.item(final).height = h - rl.item(final).height + 2;
|
||
|
|
||
|
XShapeCombineRectangles(display(), m_parent, ShapeBounding,
|
||
|
0, 0, rl.array(0, rl.count()), rl.count(),
|
||
|
visible ? ShapeUnion : ShapeSubtract, YXSorted);
|
||
|
rl.remove_all();
|
||
|
|
||
|
// Clip rectangles
|
||
|
|
||
|
rl.appendRect(m_tabWidth + w + 1, 1, FRAME_WIDTH, FRAME_WIDTH - 1);
|
||
|
|
||
|
rl.appendRect(m_tabWidth + 2, TAB_TOP_HEIGHT + 2, w,
|
||
|
FRAME_WIDTH - TAB_TOP_HEIGHT - 2);
|
||
|
|
||
|
// for button
|
||
|
ww = m_tabWidth - TAB_TOP_HEIGHT*2 - 6;
|
||
|
rl.appendRect((m_tabWidth + 2 - ww) / 2, (m_tabWidth+2 - ww) / 2, ww, ww);
|
||
|
|
||
|
rl.appendRect(m_tabWidth + 2, FRAME_WIDTH,
|
||
|
FRAME_WIDTH - 2, h - FRAME_WIDTH);
|
||
|
|
||
|
// swap last two if sorted wrong
|
||
|
if (rl.item(rl.count()-2).y > rl.item(rl.count()-1).y) {
|
||
|
rl.append(rl.item(rl.count()-2));
|
||
|
rl.remove(rl.count()-3);
|
||
|
}
|
||
|
|
||
|
rl.appendRect(m_tabWidth + 2, h, FRAME_WIDTH - 2, FRAME_WIDTH + 1);
|
||
|
|
||
|
XShapeCombineRectangles(display(), m_parent, ShapeClip,
|
||
|
0, 0, rl.array(0, rl.count()), rl.count(),
|
||
|
visible ? ShapeUnion : ShapeSubtract, YXSorted);
|
||
|
rl.remove_all();
|
||
|
|
||
|
if (visible && !isFixedSize()) {
|
||
|
XMapRaised(display(), m_resize);
|
||
|
} else {
|
||
|
XUnmapWindow(display(), m_resize);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void Border::configure(int x, int y, int w, int h,
|
||
|
unsigned long mask, int detail,
|
||
|
Boolean force) // must reshape everything
|
||
|
{
|
||
|
if (!m_parent || m_parent == root()) {
|
||
|
|
||
|
// create windows, then shape them afterwards
|
||
|
|
||
|
m_parent = XCreateSimpleWindow
|
||
|
(display(), root(), 1, 1, 1, 1, 0,
|
||
|
m_borderPixel, m_frameBackgroundPixel);
|
||
|
|
||
|
m_tab = XCreateSimpleWindow
|
||
|
(display(), m_parent, 1, 1, 1, 1, 0,
|
||
|
m_borderPixel, m_backgroundPixel);
|
||
|
|
||
|
m_button = XCreateSimpleWindow
|
||
|
(display(), m_parent, 1, 1, 1, 1, 0,
|
||
|
m_borderPixel, m_buttonBackgroundPixel);
|
||
|
|
||
|
m_resize = XCreateWindow
|
||
|
(display(), m_child, 1, 1, FRAME_WIDTH*2, FRAME_WIDTH*2, 0,
|
||
|
CopyFromParent, InputOutput, CopyFromParent, 0L, 0);
|
||
|
|
||
|
shapeResize();
|
||
|
|
||
|
XSelectInput(display(), m_parent,
|
||
|
SubstructureRedirectMask | SubstructureNotifyMask |
|
||
|
ButtonPressMask | ButtonReleaseMask);
|
||
|
|
||
|
if (!isTransient()) {
|
||
|
XSelectInput(display(), m_tab,
|
||
|
ExposureMask | ButtonPressMask | ButtonReleaseMask |
|
||
|
EnterWindowMask/* | LeaveWindowMask*/);
|
||
|
}
|
||
|
|
||
|
XSelectInput(display(), m_button,
|
||
|
ButtonPressMask | ButtonReleaseMask/* | LeaveWindowMask*/);
|
||
|
XSelectInput(display(), m_resize, ButtonPressMask | ButtonReleaseMask);
|
||
|
mask |= CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
|
||
|
}
|
||
|
|
||
|
XWindowChanges wc;
|
||
|
wc.x = x - xIndent();
|
||
|
wc.y = y - yIndent();
|
||
|
wc.width = w + xIndent() + 1;
|
||
|
wc.height = h + yIndent() + 1;
|
||
|
wc.border_width = 0;
|
||
|
wc.sibling = None;
|
||
|
wc.stack_mode = detail;
|
||
|
XConfigureWindow(display(), m_parent, mask, &wc);
|
||
|
|
||
|
unsigned long rmask = 0L;
|
||
|
if (mask & CWWidth) rmask |= CWX;
|
||
|
if (mask & CWHeight) rmask |= CWY;
|
||
|
wc.x = w - FRAME_WIDTH*2;
|
||
|
wc.y = h - FRAME_WIDTH*2;
|
||
|
XConfigureWindow(display(), m_resize, rmask, &wc);
|
||
|
|
||
|
if (force ||
|
||
|
(m_prevW < 0 || m_prevH < 0) ||
|
||
|
((mask & (CWWidth | CWHeight)) && (w != m_prevW || h != m_prevH))) {
|
||
|
|
||
|
int prevTabHeight = m_tabHeight;
|
||
|
if (isTransient()) m_tabHeight = 10; // arbitrary
|
||
|
else fixTabHeight(h);
|
||
|
|
||
|
shapeParent(w, h);
|
||
|
setFrameVisibility(m_client->isActive(), w, h);
|
||
|
|
||
|
if (force ||
|
||
|
prevTabHeight != m_tabHeight || m_prevW < 0 || m_prevH < 0) {
|
||
|
|
||
|
wc.x = 0;
|
||
|
wc.y = 0;
|
||
|
wc.width = w + xIndent();
|
||
|
wc.height = m_tabHeight + 2 + m_tabWidth;
|
||
|
XConfigureWindow(display(), m_tab, mask, &wc);
|
||
|
shapeTab(w, h);
|
||
|
}
|
||
|
|
||
|
m_prevW = w;
|
||
|
m_prevH = h;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
resizeTab(h);
|
||
|
}
|
||
|
|
||
|
wc.x = TAB_TOP_HEIGHT + 2;
|
||
|
wc.y = wc.x;
|
||
|
wc.width = wc.height = m_tabWidth - TAB_TOP_HEIGHT*2 - 4;
|
||
|
XConfigureWindow(display(), m_button, mask, &wc);
|
||
|
}
|
||
|
|
||
|
|
||
|
void Border::moveTo(int x, int y)
|
||
|
{
|
||
|
XWindowChanges wc;
|
||
|
wc.x = x - xIndent();
|
||
|
wc.y = y - yIndent();
|
||
|
XConfigureWindow(display(), m_parent, CWX | CWY, &wc);
|
||
|
}
|
||
|
|
||
|
|
||
|
void Border::map()
|
||
|
{
|
||
|
if (m_parent == root()) {
|
||
|
fprintf(stderr, "wm2: bad parent in Border::map()\n");
|
||
|
} else {
|
||
|
XMapWindow(display(), m_parent);
|
||
|
|
||
|
if (!isTransient()) {
|
||
|
XMapWindow(display(), m_tab);
|
||
|
XMapWindow(display(), m_button);
|
||
|
if (!isFixedSize()) XMapWindow(display(), m_resize);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void Border::mapRaised()
|
||
|
{
|
||
|
if (m_parent == root()) {
|
||
|
fprintf(stderr, "wm2: bad parent in Border::mapRaised()\n");
|
||
|
} else {
|
||
|
XMapRaised(display(), m_parent);
|
||
|
|
||
|
if (!isTransient()) {
|
||
|
XMapWindow(display(), m_tab);
|
||
|
XMapRaised(display(), m_button);
|
||
|
if (!isFixedSize()) XMapRaised(display(), m_resize);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void Border::lower()
|
||
|
{
|
||
|
XLowerWindow(display(), m_parent);
|
||
|
}
|
||
|
|
||
|
|
||
|
void Border::unmap()
|
||
|
{
|
||
|
if (m_parent == root()) {
|
||
|
fprintf(stderr, "wm2: bad parent in Border::unmap()\n");
|
||
|
} else {
|
||
|
XUnmapWindow(display(), m_parent);
|
||
|
|
||
|
if (!isTransient()) {
|
||
|
XUnmapWindow(display(), m_tab);
|
||
|
XUnmapWindow(display(), m_button);
|
||
|
// XUnmapWindow(display(), m_resize); // no, will unmap with parent
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void Border::decorate(Boolean active, int w, int h)
|
||
|
{
|
||
|
setFrameVisibility(active, w, h);
|
||
|
}
|
||
|
|
||
|
|
||
|
void Border::reparent()
|
||
|
{
|
||
|
XReparentWindow(display(), m_child, m_parent, xIndent(), yIndent());
|
||
|
}
|
||
|
|