A => Border.C +808 -0
@@ 0,0 1,808 @@
+
+#include "Border.h"
+#include "Client.h"
+#include "Manager.h"
+#include "Rotated.h"
+
+// These distances all exclude the 1-pixel borders. You could
+// probably change these a certain amount before breaking the shoddy
+// code in the rest of this file.
+
+int Border::m_tabTopHeight = 2;
+int Border::m_frameWidth = 7;
+int Border::m_transientFrameWidth = 4;
+
+// 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;
+
+
+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 < m_tabTopHeight * 2 + 8) {
+ m_tabWidth = m_tabTopHeight * 2 + 8;
+ }
+
+ int screen = 0; // !!
+ XColor nearest, ideal;
+
+ if (!XAllocNamedColor(display(), DefaultColormap(display(), screen),
+ CONFIG_TAB_FOREGROUND, &nearest, &ideal)) {
+ fatal("couldn't load tab foreground colour");
+ } else m_foregroundPixel = nearest.pixel;
+
+ if (!XAllocNamedColor(display(), DefaultColormap(display(), screen),
+ CONFIG_TAB_BACKGROUND, &nearest, &ideal)) {
+ fatal("couldn't load tab background colour");
+ } else m_backgroundPixel = nearest.pixel;
+
+ if (!XAllocNamedColor(display(), DefaultColormap(display(), screen),
+ CONFIG_FRAME_BACKGROUND, &nearest, &ideal)) {
+ fatal("couldn't load frame background colour");
+ } else m_frameBackgroundPixel = nearest.pixel;
+
+ if (!XAllocNamedColor(display(), DefaultColormap(display(), screen),
+ CONFIG_BUTTON_BACKGROUND, &nearest, &ideal)) {
+ fatal("couldn't load button background colour");
+ } else m_buttonBackgroundPixel = nearest.pixel;
+
+ if (!XAllocNamedColor(display(), DefaultColormap(display(), screen),
+ CONFIG_BORDERS, &nearest, &ideal)) {
+ fatal("couldn't load border colour");
+ } else m_borderPixel = nearest.pixel;
+
+ 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");
+ }
+ }
+}
+
+
+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);
+}
+
+
+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 + 3);
+
+ do {
+ strncpy(newLabel, m_label, len - 1);
+ strcpy(newLabel + len - 1, "...");
+ 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;
+}
+
+
+declareList(RectangleList, XRectangle);
+implementList(RectangleList, XRectangle);
+
+
+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;
+ XRectangle r;
+ RectangleList rl;
+
+ r.x = 0; r.y = 0;
+ r.width = w + 1; r.height = yIndent() - 1;
+ rl.append(r);
+
+ for (i = 1; i < yIndent(); ++i) {
+ r.x = w + 1; r.y = i - 1;
+ r.width = i + 1; r.height = 1;
+ rl.append(r);
+ }
+
+ r.x = 0; r.y = yIndent() - 1;
+ r.width = xIndent() - 1; r.height = h - yIndent() + 2;
+ rl.append(r);
+
+ for (i = 1; i < yIndent(); ++i) {
+ r.x = i - 1; r.y = h;
+ r.width = 1; r.height = i + 2;
+ rl.append(r);
+ }
+
+ XShapeCombineRectangles
+ (display(), m_parent, ShapeBounding,
+ 0, 0, rl.array(0, rl.count()), rl.count(),
+ visible ? ShapeUnion : ShapeSubtract, YXSorted);
+
+ rl.remove_all();
+
+ r.x = 1; r.y = 1;
+ r.width = w; r.height = yIndent() - 2;
+ rl.append(r);
+
+ for (i = 2; i < yIndent(); ++i) {
+ r.x = w + 1; r.y = i - 1;
+ r.width = i; r.height = 1;
+ rl.append(r);
+ }
+
+ r.x = 1; r.y = yIndent() - 1;
+ r.width = xIndent() - 2; r.height = h - yIndent() + 1;
+ rl.append(r);
+
+ for (i = 2; i < yIndent(); ++i) {
+ r.x = i - 1; r.y = h;
+ r.width = 1; r.height = i + 1;
+ rl.append(r);
+ }
+
+ 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;
+ XRectangle r;
+ int mainRect;
+ RectangleList rl;
+
+ if (isTransient()) {
+ shapeTransientParent(w, h);
+ return;
+ }
+
+ // Bounding rectangles -- clipping will be the same except for
+ // child window border
+
+ // top of tab
+ r.x = 0; r.y = 0;
+ r.width = w + m_tabWidth + 1; r.height = m_tabTopHeight + 2;
+ rl.append(r);
+
+ // struts in tab, left...
+ r.x = 0; r.y = m_tabTopHeight + 1;
+ r.width = m_tabTopHeight + 2; r.height = m_tabWidth - m_tabTopHeight*2 - 1;
+ rl.append(r);
+
+ // ...and right
+ r.x = m_tabWidth - m_tabTopHeight; r.y = m_tabTopHeight + 1;
+ r.width = m_tabTopHeight + 2; r.height = m_tabWidth - m_tabTopHeight*2 - 1;
+ rl.append(r);
+
+ // main window
+ r.x = xIndent() - 1; r.y = yIndent() - 1;
+ r.width = w + 2; r.height = h + 2;
+ mainRect = rl.count();
+ rl.append(r);
+
+ // main tab
+ r.x = 0; r.y = m_tabWidth - m_tabTopHeight;
+ r.width = m_tabWidth + 2;
+ r.height = m_tabHeight - m_tabWidth + m_tabTopHeight;
+ rl.append(r);
+
+ // diagonal
+ for (i = 1; i < m_tabWidth - 1; ++i) {
+ r.x = i; r.y = m_tabHeight + i - 1;
+ r.width = m_tabWidth - i + 2; r.height = 1;
+ rl.append(r);
+ }
+
+ 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;
+ XRectangle r;
+ RectangleList rl;
+
+ if (isTransient()) {
+ return;
+ }
+
+ // Bounding rectangles
+
+ r.x = 0; r.y = 0;
+ r.width = w + m_tabWidth + 1; r.height = m_tabTopHeight + 2;
+ rl.append(r);
+
+ r.x = 0; r.y = m_tabTopHeight + 1;
+ r.width = m_tabTopHeight + 2; r.height = m_tabWidth - m_tabTopHeight*2 - 1;
+ rl.append(r);
+
+ r.x = m_tabWidth - m_tabTopHeight; r.y = m_tabTopHeight + 1;
+ r.width = m_tabTopHeight + 2; r.height = m_tabWidth - m_tabTopHeight*2 - 1;
+ rl.append(r);
+
+ r.x = 0; r.y = m_tabWidth - m_tabTopHeight;
+ r.width = m_tabWidth + 2;
+ r.height = m_tabHeight - m_tabWidth + m_tabTopHeight;
+ rl.append(r);
+
+ for (i = 1; i < m_tabWidth - 1; ++i) {
+ r.x = i; r.y = m_tabHeight + i - 1;
+ r.width = m_tabWidth - i + 2; r.height = 1;
+ rl.append(r);
+ }
+
+ XShapeCombineRectangles
+ (display(), m_tab, ShapeBounding,
+ 0, 0, rl.array(0, rl.count()), rl.count(), ShapeSet, YXSorted);
+
+ rl.remove_all();
+
+ // Clipping rectangles
+
+ r.x = 1; r.y = 1;
+ r.width = w + m_tabWidth - 1; r.height = m_tabTopHeight;
+ rl.append(r);
+
+ r.x = 1; r.y = m_tabTopHeight + 1;
+ r.width = m_tabTopHeight; r.height = m_tabWidth + m_tabTopHeight*2 - 1;
+ rl.append(r);
+
+ r.x = m_tabWidth - m_tabTopHeight + 1; r.y = m_tabTopHeight + 1;
+ r.width = m_tabTopHeight; r.height = m_tabWidth + m_tabTopHeight*2 - 1;
+ rl.append(r);
+
+ r.x = 1; r.y = m_tabWidth - m_tabTopHeight + 1;
+ r.width = m_tabWidth;
+ r.height = m_tabHeight - m_tabWidth + m_tabTopHeight - 1;
+ rl.append(r);
+
+ for (i = 1; i < m_tabWidth - 2; ++i) {
+ r.x = i + 1; r.y = m_tabHeight + i - 1;
+ r.width = m_tabWidth - i; r.height = 1;
+ rl.append(r);
+ }
+
+ XShapeCombineRectangles
+ (display(), m_tab, ShapeClip,
+ 0, 0, rl.array(0, rl.count()), rl.count(), ShapeSet, YXSorted);
+
+// XSync(display(), False);
+}
+
+
+void Border::resizeTab(int h)
+{
+ int i;
+ XRectangle r;
+ RectangleList 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);
+
+ // restore a bit of the frame edge
+ r.x = m_tabWidth + 1; r.y = shorter;
+ r.width = m_frameWidth - 1; r.height = longer - shorter;
+ XShapeCombineRectangles(display(), m_parent, ShapeBounding,
+ 0, 0, &r, 1, ShapeUnion, YXBanded);
+
+ for (i = 1; i < m_tabWidth - 1; ++i) {
+ r.x = i; r.y = m_tabHeight + i - 3;
+ r.width = m_tabWidth - i + 2; r.height = 1;
+ rl.append(r);
+ }
+
+ 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);
+
+// XSync(display(), False);
+}
+
+
+void Border::shapeResize()
+{
+ int i;
+ XRectangle r;
+ RectangleList rl;
+
+ for (i = 0; i < m_frameWidth*2; ++i) {
+ r.x = m_frameWidth*2 - i - 1; r.y = i; r.width = i + 1; r.height = 1;
+ rl.append(r);
+ }
+
+ XShapeCombineRectangles
+ (display(), m_resize, ShapeBounding, 0, 0,
+ rl.array(0, rl.count()), rl.count(), ShapeSet, YXBanded);
+
+ rl.remove_all();
+
+ for (i = 1; i < m_frameWidth*2; ++i) {
+ r.x = m_frameWidth*2 - i; r.y = i; r.width = i; r.height = 1;
+ rl.append(r);
+ }
+
+ XShapeCombineRectangles
+ (display(), m_resize, ShapeClip, 0, 0,
+ rl.array(0, rl.count()), rl.count(), ShapeSet, YXBanded);
+
+ rl.remove_all();
+
+ for (i = 0; i < m_frameWidth*2 - 3; ++i) {
+ r.x = m_frameWidth*2 - i - 1; r.y = i + 3; r.width = 1; r.height = 1;
+ rl.append(r);
+ }
+
+ 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)
+{
+ XRectangle r;
+ RectangleList rl;
+
+ if (isTransient()) {
+ setTransientFrameVisibility(visible, w, h);
+ return;
+ }
+
+ // Bounding rectangles
+
+ r.x = m_tabWidth + w + 1; r.y = 0;
+ r.width = m_frameWidth + 1; r.height = m_frameWidth;
+ rl.append(r);
+
+ r.x = m_tabWidth + 2; r.y = m_tabTopHeight + 2;
+ r.width = w; r.height = m_frameWidth - m_tabTopHeight - 2;
+ rl.append(r);
+
+ // for button
+ r.width = r.height = m_tabWidth - m_tabTopHeight*2 - 4;
+ r.x = r.y = (m_tabWidth + 2 - r.width) / 2;
+ rl.append(r);
+
+ r.x = m_tabWidth + 2; r.y = m_frameWidth;
+ r.width = m_frameWidth - 2;
+ r.height = m_tabHeight + m_tabWidth - m_frameWidth - 2;
+ rl.append(r);
+
+ // 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);
+ }
+
+ r.x -= 1; r.y += r.height;
+ r.width += 1; r.height = h - r.height + 2;
+ rl.append(r);
+
+ XShapeCombineRectangles(display(), m_parent, ShapeBounding,
+ 0, 0, rl.array(0, rl.count()), rl.count(),
+ visible ? ShapeUnion : ShapeSubtract, YXSorted);
+ rl.remove_all();
+
+ // Clip rectangles
+
+ r.x = m_tabWidth + w + 1; r.y = 1;
+ r.width = m_frameWidth; r.height = m_frameWidth - 1;
+ rl.append(r);
+
+ r.x = m_tabWidth + 2; r.y = m_tabTopHeight + 2;
+ r.width = w; r.height = m_frameWidth - m_tabTopHeight - 2;
+ rl.append(r);
+
+ // for button
+ r.width = r.height = m_tabWidth - m_tabTopHeight*2 - 6;
+ r.x = r.y = (m_tabWidth + 2 - r.width) / 2;
+ rl.append(r);
+
+ r.x = m_tabWidth + 2; r.y = m_frameWidth;
+ r.width = m_frameWidth - 2; r.height = h - m_frameWidth;
+ rl.append(r);
+
+ // 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);
+ }
+
+ r.x = m_tabWidth + 2; r.y = h;
+ r.width = m_frameWidth - 2; r.height = m_frameWidth + 1;
+ rl.append(r);
+
+ 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);
+ }
+
+// XSync(display(), False); // doesn't seem to help much
+}
+
+
+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, m_frameWidth*2, m_frameWidth*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 - m_frameWidth*2;
+ wc.y = h - m_frameWidth*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 = wc.y = m_tabTopHeight + 2;
+ wc.width = wc.height = m_tabWidth - m_tabTopHeight*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::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());
+}
+
A => Border.h +93 -0
@@ 0,0 1,93 @@
+
+#ifndef _BORDER_H_
+#define _BORDER_H_
+
+#include "General.h"
+#include "Rotated.h"
+
+class Client;
+class WindowManager;
+
+class Border { // friend of client
+public:
+ Border(Client *const, Window child);
+ ~Border();
+
+
+ void map();
+ void unmap();
+ void mapRaised();
+ void decorate(Boolean active, int w, int h);
+ void reparent();
+ void configure(int x, int y, int w, int h, unsigned long mask, int detail,
+ Boolean force = False);
+ void moveTo(int x, int y);
+
+ WindowManager *windowManager(); // calls into Client
+ Boolean isTransient(); // calls into Client
+ Boolean isFixedSize(); // calls into Client
+ Window parent() { return m_parent; }
+ Boolean hasWindow(Window w) {
+ return (w != root() && (w == m_parent || w == m_tab ||
+ w == m_button || w == m_resize));
+ }
+
+ Display *display();
+ Window root();
+
+ void expose(XExposeEvent *);
+ void eventButton(XButtonEvent *); // in Buttons.C
+
+ int yIndent() {
+ return isTransient() ? m_transientFrameWidth + 1 : m_frameWidth + 1;
+ }
+ int xIndent() {
+ return isTransient() ? m_transientFrameWidth + 1 :
+ m_tabWidth + m_frameWidth + 1;
+ }
+
+private:
+ Client *m_client;
+
+ Window m_parent;
+ Window m_tab;
+ Window m_child;
+ Window m_button;
+ Window m_resize;
+
+ void fatal(char *);
+
+ char *m_label;
+
+ void fixTabHeight(int);
+ void drawLabel();
+
+ void setFrameVisibility(Boolean, int, int);
+ void setTransientFrameVisibility(Boolean, int, int);
+ void shapeParent(int, int);
+ void shapeTransientParent(int, int);
+ void shapeTab(int, int);
+ void resizeTab(int); // for rename without changing window size
+ void shapeResize();
+
+ int m_prevW;
+ int m_prevH;
+
+private:
+ int m_tabHeight; // depends on the label
+ static int m_tabWidth; // depends on the label font
+ static int m_tabTopHeight;
+ static int m_frameWidth; // NB frameTopHeight = frameHeight-tabTopHeight
+ static int m_transientFrameWidth;
+ static XRotFontStruct *m_tabFont;
+ static GC m_drawGC;
+ static unsigned long m_foregroundPixel;
+ static unsigned long m_backgroundPixel;
+ static unsigned long m_frameBackgroundPixel;
+ static unsigned long m_buttonBackgroundPixel;
+ static unsigned long m_borderPixel;
+};
+
+
+#endif
+
A => Buttons.C +681 -0
@@ 0,0 1,681 @@
+
+#include "Manager.h"
+#include "Client.h"
+#include <sys/time.h>
+
+#define AllButtonMask ( Button1Mask | Button2Mask | Button3Mask \
+ | Button4Mask | Button5Mask )
+#define ButtonMask ( ButtonPressMask | ButtonReleaseMask )
+#define DragMask ( ButtonMask | ButtonMotionMask )
+#define MenuMask ( ButtonMask | ButtonMotionMask | ExposureMask )
+#define MenuGrabMask ( ButtonMask | ButtonMotionMask | StructureNotifyMask )
+
+
+void WindowManager::eventButton(XButtonEvent *e)
+{
+ Client *c = windowToClient(e->window);
+
+ if (e->window == e->root) {
+
+ if (e->button == Button1) menu(e);
+
+ } else if (c) {
+
+ c->eventButton(e);
+ return;
+ }
+}
+
+
+void Client::eventButton(XButtonEvent *e)
+{
+ if (e->type != ButtonPress) return;
+
+ mapRaised();
+
+ if (e->button == Button1) {
+ if (m_border->hasWindow(e->window)) {
+
+ m_border->eventButton(e);
+ }
+ }
+
+ if (!isNormal() || isActive() || e->send_event) return;
+ activate();
+}
+
+
+static int nobuttons(XButtonEvent *e) // straight outta 9wm
+{
+ int state;
+ state = (e->state & AllButtonMask);
+ return (e->type == ButtonRelease) && (state & (state - 1)) == 0;
+}
+
+
+int WindowManager::attemptGrab(Window w, Window constrain, int mask, int t)
+{
+ int status;
+ if (t == 0) t = timestamp(False);
+ status = XGrabPointer(display(), w, False, mask, GrabModeAsync,
+ GrabModeAsync, constrain, None, t);
+ return status;
+}
+
+
+void WindowManager::releaseGrab(XButtonEvent *e)
+{
+ XEvent ev;
+ if (!nobuttons(e)) {
+ for (;;) {
+ XMaskEvent(display(), ButtonMask | ButtonMotionMask, &ev);
+ if (ev.type == MotionNotify) continue;
+ e = &ev.xbutton;
+ if (nobuttons(e)) break;
+ }
+ }
+
+ XUngrabPointer(display(), e->time);
+ m_currentTime = e->time;
+}
+
+
+void WindowManager::menu(XButtonEvent *e)
+{
+ if (e->window == m_menuWindow) return;
+
+ int i;
+ ClientList clients;
+
+#define MENU_LABEL(n) ((n)==0? m_menuCreateLabel : clients.item((n)-1)->label())
+
+ for (i = 0; i < m_hiddenClients.count(); ++i) {
+ clients.append(m_hiddenClients.item(i));
+ }
+ int nh = clients.count() + 1;
+
+ if (CONFIG_EVERYTHING_ON_ROOT_MENU) {
+ for (i = 0; i < m_clients.count(); ++i) {
+ if (m_clients.item(i)->isNormal())
+ clients.append(m_clients.item(i));
+ }
+ }
+ int n = clients.count() + 1;
+
+ int width, maxWidth = 10;
+ for (i = 0; i < n; ++i) {
+ width = XTextWidth(m_menuFont, MENU_LABEL(i), strlen(MENU_LABEL(i)));
+ if (width > maxWidth) maxWidth = width;
+ }
+ maxWidth += 32;
+
+ int selecting = -1, prev = -1;
+ int entryHeight = m_menuFont->ascent + m_menuFont->descent + 4;
+ int totalHeight = entryHeight * n + 13;
+ int x = e->x - maxWidth/2;
+ int y = e->y - 2;
+ int mx = DisplayWidth (display(), m_screenNumber) - 1;
+ int my = DisplayHeight(display(), m_screenNumber) - 1;
+ Boolean warp = False;
+
+ if (x < 0) {
+ e->x -= x; x = 0; warp = True;
+ } else if (x + maxWidth >= mx) {
+ e->x -= x + maxWidth - mx; x = mx - maxWidth; warp = True;
+ }
+
+ if (y < 0) {
+ e->y -= y; y = 0; warp = True;
+ } else if (y + totalHeight >= my) {
+ e->y -= y + totalHeight - my; y = my - totalHeight; warp = True;
+ }
+
+ if (warp) XWarpPointer(display(), None, root(),
+ None, None, None, None, e->x, e->y);
+
+ XMoveResizeWindow(display(), m_menuWindow, x, y, maxWidth, totalHeight);
+ XSelectInput(display(), m_menuWindow, MenuMask);
+ XMapRaised(display(), m_menuWindow);
+
+ if (attemptGrab(m_menuWindow, None, MenuGrabMask, e->time) != GrabSuccess){
+ XUnmapWindow(display(), m_menuWindow);
+ return;
+ }
+
+ Boolean done = False;
+ Boolean drawn = False;
+ XEvent event;
+
+ while (!done) {
+ XMaskEvent(display(), MenuMask, &event);
+
+ switch (event.type) {
+
+ default:
+ fprintf(stderr, "wm2: unknown event type %d\n", event.type);
+ break;
+
+ case ButtonPress:
+ break;
+
+ case ButtonRelease:
+ if (drawn) {
+
+ if (event.xbutton.button != e->button) break;
+ x = event.xbutton.x;
+ y = event.xbutton.y - 11;
+ i = y / entryHeight;
+
+ if (selecting >= 0 && y >= selecting * entryHeight - 3 &&
+ y <= (selecting+1) * entryHeight - 3) i = selecting;
+
+ if (x < 0 || x > maxWidth || y < -3) i = -1;
+ else if (i < 0 || i >= n) i = -1;
+
+ } else {
+ selecting = -1;
+ }
+
+ if (!nobuttons(&event.xbutton)) i = -1;
+ releaseGrab(&event.xbutton);
+ XUnmapWindow(display(), m_menuWindow);
+ selecting = i;
+ done = True;
+ break;
+
+ case MotionNotify:
+ if (!drawn) break;
+ x = event.xbutton.x;
+ y = event.xbutton.y - 11;
+ prev = selecting;
+ selecting = y / entryHeight;
+
+ if (prev >= 0 && y >= prev * entryHeight - 3 &&
+ y <= (prev+1) * entryHeight - 3) selecting = prev;
+
+ if (x < 0 || x > maxWidth || y < -3) selecting = -1;
+ else if (selecting < 0 || selecting > n) selecting = -1;
+
+ if (selecting == prev) break;
+
+ if (prev >= 0 && prev < n) {
+ XFillRectangle(display(), m_menuWindow, m_menuGC,
+ 4, prev * entryHeight + 9,
+ maxWidth - 8, entryHeight);
+ }
+
+ if (selecting >= 0 && selecting < n) {
+ XFillRectangle(display(), m_menuWindow, m_menuGC,
+ 4, selecting * entryHeight + 9,
+ maxWidth - 8, entryHeight);
+ }
+
+ break;
+
+ case Expose:
+ XClearWindow(display(), m_menuWindow);
+
+ XDrawRectangle(display(), m_menuWindow, m_menuGC, 2, 7,
+ maxWidth - 5, totalHeight - 10);
+
+ for (i = 0; i < n; ++i) {
+
+ int dx = XTextWidth(m_menuFont, MENU_LABEL(i),
+ strlen(MENU_LABEL(i)));
+ int dy = i * entryHeight + m_menuFont->ascent + 10;
+
+ if (i >= nh) {
+ XDrawString(display(), m_menuWindow, m_menuGC,
+ maxWidth - 8 - dx, dy,
+ MENU_LABEL(i), strlen(MENU_LABEL(i)));
+ } else {
+ XDrawString(display(), m_menuWindow, m_menuGC, 8,
+ dy, MENU_LABEL(i), strlen(MENU_LABEL(i)));
+ }
+ }
+
+ if (selecting >= 0 && selecting < n) {
+ XFillRectangle(display(), m_menuWindow, m_menuGC,
+ 4, selecting * entryHeight + 9,
+ maxWidth - 8, entryHeight);
+ }
+
+ drawn = True;
+ }
+ }
+
+ if (selecting >= 0) {
+ if (selecting == 0) {
+ spawn();
+ } else if (selecting < nh) {
+ clients.item(selecting - 1)->unhide(True);
+ } else if (selecting < n) {
+ if (CONFIG_CLICK_TO_FOCUS) {
+ clients.item(selecting - 1)->activate();
+ } else {
+ clients.item(selecting - 1)->mapRaised();
+ }
+ clients.item(selecting - 1)->ensureVisible();
+ }
+ }
+
+ clients.remove_all();
+ return;
+}
+
+
+void WindowManager::showGeometry(int x, int y)
+{
+ char string[20];
+ sprintf(string, "%d %d\n", x, y);
+ int width = XTextWidth(m_menuFont, string, strlen(string)) + 8;
+ int height = m_menuFont->ascent + m_menuFont->descent + 8;
+ int mx = DisplayWidth (display(), m_screenNumber) - 1;
+ int my = DisplayHeight(display(), m_screenNumber) - 1;
+
+ XMoveResizeWindow(display(), m_menuWindow,
+ (mx - width) / 2, (my - height) / 2, width, height);
+ XClearWindow(display(), m_menuWindow);
+ XMapRaised(display(), m_menuWindow);
+
+ XDrawString(display(), m_menuWindow, m_menuGC, 4, 4 + m_menuFont->ascent,
+ string, strlen(string));
+}
+
+
+void WindowManager::removeGeometry()
+{
+ XUnmapWindow(display(), m_menuWindow);
+}
+
+
+void Client::move(XButtonEvent *e)
+{
+ int x = -1, y = -1, xoff, yoff;
+ Boolean done = False;
+
+ if (m_windowManager->attemptGrab
+ (root(), None, DragMask, e->time) != GrabSuccess) {
+ return;
+ }
+
+ xoff = m_border->xIndent() - e->x;
+ yoff = m_border->yIndent() - e->y;
+
+ XEvent event;
+ Boolean found;
+ Boolean doSomething = False;
+ struct timeval sleepval;
+
+ while (!done) {
+
+ found = False;
+
+ while (XCheckMaskEvent(display(), DragMask | ExposureMask, &event)) {
+ found = True;
+ if (event.type != MotionNotify) break;
+ }
+
+ if (!found) {
+ sleepval.tv_sec = 0;
+ sleepval.tv_usec = 50000;
+ select(0, 0, 0, 0, &sleepval);
+ continue;
+ }
+
+ switch (event.type) {
+
+ default:
+ fprintf(stderr, "wm2: unknown event type %d\n", event.type);
+ break;
+
+ case Expose:
+ m_windowManager->eventExposure(&event.xexpose);
+ break;
+
+ case ButtonPress:
+ // don't like this
+ XUngrabPointer(display(), event.xbutton.time);
+ doSomething = False;
+ done = True;
+ break;
+
+ case ButtonRelease:
+
+ x = event.xbutton.x; y = event.xbutton.y;
+ if (!nobuttons(&event.xbutton)) doSomething = False;
+
+// XUngrabPointer(display(), event.xbutton.time);
+ m_windowManager->releaseGrab(&event.xbutton);
+ done = True;
+ break;
+
+ case MotionNotify:
+ x = event.xbutton.x; y = event.xbutton.y;
+ if (x + xoff != m_x || y + yoff != m_y) {
+ windowManager()->showGeometry(x + xoff, y + yoff);
+ m_border->moveTo(x + xoff, y + yoff);
+ doSomething = True;
+ }
+ break;
+ }
+ }
+
+ windowManager()->removeGeometry();
+
+ if (x >= 0 && doSomething) {
+ m_x = x + xoff;
+ m_y = y + yoff;
+ }
+
+ if (CONFIG_CLICK_TO_FOCUS) activate();
+ m_border->moveTo(m_x, m_y);
+ sendConfigureNotify();
+}
+
+
+void Client::fixResizeDimensions(int &w, int &h, int &dw, int &dh)
+{
+ if (w < 50) w = 50;
+ if (h < 50) h = 50;
+
+ if (m_sizeHints.flags & PResizeInc) {
+ w = m_minWidth + (((w - m_minWidth) / m_sizeHints.width_inc) *
+ m_sizeHints.width_inc);
+ h = m_minHeight + (((h - m_minHeight) / m_sizeHints.height_inc) *
+ m_sizeHints.height_inc);
+
+ dw = (w - m_minWidth) / m_sizeHints.width_inc;
+ dh = (h - m_minHeight) / m_sizeHints.height_inc;
+ } else {
+ dw = w; dh = h;
+ }
+
+ if (m_sizeHints.flags & PMaxSize) {
+ if (w > m_sizeHints.max_width) w = m_sizeHints.max_width;
+ if (h > m_sizeHints.max_height) h = m_sizeHints.max_height;
+ }
+
+ if (w < m_minWidth) w = m_minWidth;
+ if (h < m_minHeight) h = m_minHeight;
+}
+
+
+void Client::resize(XButtonEvent *e, Boolean horizontal, Boolean vertical)
+{
+ if (isFixedSize()) return;
+
+ if (m_windowManager->attemptGrab
+ (root(), None, DragMask, e->time) != GrabSuccess) {
+ return;
+ }
+
+ if (vertical && horizontal)
+ m_windowManager->installCursor(WindowManager::DownrightCursor);
+ else if (vertical)
+ m_windowManager->installCursor(WindowManager::DownCursor);
+ else
+ m_windowManager->installCursor(WindowManager::RightCursor);
+
+ Window dummy;
+ XTranslateCoordinates(display(), e->window, parent(),
+ e->x, e->y, &e->x, &e->y, &dummy);
+
+ int xorig = e->x;
+ int yorig = e->y;
+ int x = xorig;
+ int y = yorig;
+ int w = m_w, h = m_h;
+ int prevW, prevH;
+ int dw, dh;
+
+ XEvent event;
+ Boolean found;
+ Boolean doSomething = False;
+ Boolean done = False;
+ struct timeval sleepval;
+
+ while (!done) {
+
+ found = False;
+
+ while (XCheckMaskEvent(display(), DragMask | ExposureMask, &event)) {
+ found = True;
+ if (event.type != MotionNotify) break;
+ }
+
+ if (!found) {
+ sleepval.tv_sec = 0;
+ sleepval.tv_usec = 50000;
+ select(0, 0, 0, 0, &sleepval);
+ continue;
+ }
+
+ switch (event.type) {
+
+ default:
+ fprintf(stderr, "wm2: unknown event type %d\n", event.type);
+ break;
+
+ case Expose:
+ m_windowManager->eventExposure(&event.xexpose);
+ break;
+
+ case ButtonPress:
+ // don't like this
+ XUngrabPointer(display(), event.xbutton.time);
+ done = True;
+ break;
+
+ case ButtonRelease:
+
+ x = event.xbutton.x; y = event.xbutton.y;
+
+ if (!nobuttons(&event.xbutton)) x = -1;
+ m_windowManager->releaseGrab(&event.xbutton);
+
+ done = True;
+ break;
+
+ case MotionNotify:
+ x = event.xbutton.x; y = event.xbutton.y;
+
+ if (vertical && horizontal) {
+ prevH = h; h = y - m_y;
+ prevW = w; w = x - m_x;
+ fixResizeDimensions(w, h, dw, dh);
+ if (h == prevH && w == prevW) break;
+ m_border->configure(m_x, m_y, w, h, CWWidth | CWHeight, 0);
+ windowManager()->showGeometry(dw, dh);
+ doSomething = True;
+
+ } else if (vertical) {
+ prevH = h; h = y - m_y;
+ fixResizeDimensions(w, h, dw, dh);
+ if (h == prevH) break;
+ m_border->configure(m_x, m_y, w, h, CWHeight, 0);
+ windowManager()->showGeometry(dw, dh);
+ doSomething = True;
+
+ } else {
+ prevW = w; w = x - m_x;
+ fixResizeDimensions(w, h, dw, dh);
+ if (w == prevW) break;
+ m_border->configure(m_x, m_y, w, h, CWWidth, 0);
+ windowManager()->showGeometry(dw, dh);
+ doSomething = True;
+ }
+
+ break;
+ }
+ }
+
+ if (doSomething) {
+
+ windowManager()->removeGeometry();
+
+ if (vertical && horizontal) {
+ m_w = x - m_x;
+ m_h = y - m_y;
+ fixResizeDimensions(m_w, m_h, dw, dh);
+ m_border->configure(m_x, m_y, m_w, m_h, CWWidth|CWHeight, 0, True);
+ } else if (vertical) {
+ m_h = y - m_y;
+ fixResizeDimensions(m_w, m_h, dw, dh);
+ m_border->configure(m_x, m_y, m_w, m_h, CWHeight, 0, True);
+ } else {
+ m_w = x - m_x;
+ fixResizeDimensions(m_w, m_h, dw, dh);
+ m_border->configure(m_x, m_y, m_w, m_h, CWWidth, 0, True);
+ }
+
+ XMoveResizeWindow(display(), m_window,
+ m_border->xIndent(), m_border->yIndent(), m_w, m_h);
+
+ sendConfigureNotify();
+ }
+
+ m_windowManager->installCursor(WindowManager::NormalCursor);
+}
+
+
+void Client::moveOrResize(XButtonEvent *e)
+{
+ if (e->x < m_border->xIndent() && e->y > m_h) {
+ resize(e, False, True);
+ } else if (e->y < m_border->yIndent() &&
+ e->x > m_w + m_border->xIndent() - m_border->yIndent()) { //hack
+ resize(e, True, False);
+ } else {
+ move(e);
+ }
+}
+
+
+void Border::eventButton(XButtonEvent *e)
+{
+ if (e->window == m_parent) {
+
+ if (!m_client->isActive()) return;
+ if (isTransient()) {
+ if (e->x >= xIndent() && e->y >= yIndent()) {
+ return;
+ } else {
+ m_client->move(e);
+ return;
+ }
+ }
+
+ m_client->moveOrResize(e);
+ return;
+
+ } else if (e->window == m_tab) {
+ m_client->move(e);
+ return;
+ }
+
+ if (e->window == m_resize) {
+ m_client->resize(e, True, True);
+ return;
+ }
+
+ if (e->window != m_button || e->type == ButtonRelease) return;
+
+ if (windowManager()->attemptGrab(m_button, None, MenuGrabMask, e->time)
+ != GrabSuccess) {
+ return;
+ }
+
+ XEvent event;
+ Boolean found;
+ Boolean done = False;
+ struct timeval sleepval;
+ unsigned long tdiff = 0L;
+ int x = e->x;
+ int y = e->y;
+ int action = 1;
+ int buttonSize = m_tabWidth - m_tabTopHeight*2 - 4;
+
+ XFillRectangle(display(), m_button, m_drawGC, 0, 0, buttonSize, buttonSize);
+
+ while (!done) {
+
+ found = False;
+
+ if (tdiff > 1500L && action == 1) {
+ windowManager()->installCursor(WindowManager::DeleteCursor);
+ action = 2;
+ }
+
+ while (XCheckMaskEvent(display(), MenuMask, &event)) {
+ found = True;
+ if (event.type != MotionNotify) break;
+ }
+
+ if (!found) {
+ sleepval.tv_sec = 0;
+ sleepval.tv_usec = 50000;
+ select(0, 0, 0, 0, &sleepval);
+ tdiff += 50;
+ continue;
+ }
+
+ switch (event.type) {
+
+ default:
+ fprintf(stderr, "wm2: unknown event type %d\n", event.type);
+ break;
+
+ case Expose:
+ windowManager()->eventExposure(&event.xexpose);
+ break;
+
+ case ButtonPress:
+ break;
+
+ case ButtonRelease:
+
+ if (!nobuttons(&event.xbutton)) {
+ action = 0;
+ }
+
+ if (x < 0 || y < 0 || x >= buttonSize || y >= buttonSize) {
+ action = 0;
+ }
+
+ windowManager()->releaseGrab(&event.xbutton);
+ done = True;
+ break;
+
+ case MotionNotify:
+ tdiff = event.xmotion.time - e->time;
+ if (tdiff > 5000L) tdiff = 5001L; // in case of overflow!
+
+ x = event.xmotion.x;
+ y = event.xmotion.y;
+
+ if (action == 0 || action == 2) {
+ if (x < 0 || y < 0 || x >= buttonSize || y >= buttonSize) {
+ windowManager()->installCursor(WindowManager::NormalCursor);
+ action = 0;
+ } else {
+ windowManager()->installCursor(WindowManager::DeleteCursor);
+ action = 2;
+ }
+ }
+
+ break;
+ }
+ }
+
+ XClearWindow(display(), m_button);
+ windowManager()->installCursor(WindowManager::NormalCursor);
+
+ if (tdiff > 5000L) { // do nothing, they dithered too long
+ return;
+ }
+
+ if (action == 1) m_client->hide();
+ else if (action == 2) m_client->kill();
+}
+
A => Client.C +714 -0
@@ 0,0 1,714 @@
+
+#include "Manager.h"
+#include "Client.h"
+
+#include <X11/Xutil.h>
+
+const char *const Client::m_defaultLabel = "incognito";
+
+
+
+Client::Client(WindowManager *const wm, Window w) :
+ m_window(w),
+ m_transient(None),
+ m_revert(0),
+ m_fixedSize(False),
+ m_state(WithdrawnState),
+ m_initialising(False),
+ m_reparenting(False),
+ m_colormap(None),
+ m_colormapWinCount(0),
+ m_colormapWindows(NULL),
+ m_windowColormaps(NULL),
+ m_windowManager(wm)
+{
+ XWindowAttributes attr;
+ XGetWindowAttributes(display(), m_window, &attr);
+
+ m_x = attr.x;
+ m_y = attr.y;
+ m_w = attr.width;
+ m_h = attr.height;
+ m_bw = attr.border_width;
+ m_name = m_iconName = 0;
+ m_sizeHints.flags = 0L;
+
+ m_label = NewString(m_defaultLabel);
+ m_border = new Border(this, w);
+
+ if (attr.map_state == IsViewable) manage(True);
+}
+
+
+Client::~Client()
+{
+ // empty
+}
+
+
+void Client::release()
+{
+ // assume wm called for this, and will remove me from its list itself
+
+// fprintf(stderr, "deleting client %p\n",this);
+
+ if (m_window == None) {
+ fprintf(stderr,
+ "wm2: invalid parent in Client::release (released twice?)\n");
+ }
+
+ windowManager()->skipInRevert(this, m_revert);
+
+// fprintf(stderr, "deleting %lx\n",m_window);
+
+ if (isHidden()) unhide(False);
+
+ delete m_border;
+ m_window = None;
+
+ if (isActive()) {
+ if (CONFIG_CLICK_TO_FOCUS) {
+ if (m_revert) {
+ windowManager()->setActiveClient(m_revert);
+ m_revert->activate();
+ } else windowManager()->clearFocus();
+ } else {
+ windowManager()->setActiveClient(0);
+ }
+ }
+
+ if (m_colormapWinCount > 0) {
+ XFree((char *)m_colormapWindows);
+ free((char *)m_windowColormaps); // not allocated through X
+ }
+
+ if (m_iconName) XFree(m_iconName);
+ if (m_name) XFree(m_name);
+ if (m_label) free((void *)m_label);
+
+ delete this;
+}
+
+
+void Client::unreparent()
+{
+ XWindowChanges wc;
+
+ if (!isWithdrawn()) {
+ gravitate(True);
+ XReparentWindow(display(), m_window, root(), m_x, m_y);
+ }
+
+ wc.border_width = m_bw;
+ XConfigureWindow(display(), m_window, CWBorderWidth, &wc);
+
+ XSync(display(), True);
+}
+
+
+void Client::installColormap()
+{
+ Client *cc = 0;
+ int i, found;
+
+ if (m_colormapWinCount != 0) {
+
+ found = 0;
+
+ for (i = m_colormapWinCount - 1; i >= 0; --i) {
+ windowManager()->installColormap(m_windowColormaps[i]);
+ if (m_colormapWindows[i] == m_window) ++found;
+ }
+
+ if (found == 0) {
+ windowManager()->installColormap(m_colormap);
+ }
+
+ } else if (m_transient != None &&
+ (cc = windowManager()->windowToClient(m_transient))) {
+
+ cc->installColormap();
+ } else {
+ windowManager()->installColormap(m_colormap);
+ }
+}
+
+
+void Client::manage(Boolean mapped)
+{
+ Boolean shouldHide, reshape;
+ XWMHints *hints;
+ Display *d = display();
+ long mSize;
+ int state;
+
+ XSelectInput(d, m_window, ColormapChangeMask | EnterWindowMask |
+ PropertyChangeMask | FocusChangeMask);
+
+ m_iconName = getProperty(XA_WM_ICON_NAME);
+ m_name = getProperty(XA_WM_NAME);
+ setLabel();
+
+ getColormaps();
+ getProtocols();
+ getTransient();
+
+ hints = XGetWMHints(d, m_window);
+
+ if (!getState(&state)) {
+ state = hints ? hints->initial_state : NormalState;
+ }
+
+ shouldHide = (state == IconicState);
+ if (hints) XFree(hints);
+
+ if (XGetWMNormalHints(d, m_window, &m_sizeHints, &mSize) == 0 ||
+ m_sizeHints.flags == 0) {
+ m_sizeHints.flags = PSize;
+ }
+
+ m_fixedSize = False;
+// if ((m_sizeHints.flags & (USSize | PSize))) m_fixedSize = True;
+ if ((m_sizeHints.flags & (PMinSize | PMaxSize)) == (PMinSize | PMaxSize) &&
+ (m_sizeHints.min_width == m_sizeHints.max_width &&
+ m_sizeHints.min_height == m_sizeHints.max_height)) m_fixedSize = True;
+
+ reshape = !mapped;
+
+ if (m_fixedSize) {
+ if ((m_sizeHints.flags & USPosition)) reshape = False;
+ if ((m_sizeHints.flags & PPosition) && shouldHide) reshape = False;
+ if ((m_transient != None)) reshape = False;
+ }
+
+ if ((m_sizeHints.flags & PBaseSize)) {
+ m_minWidth = m_sizeHints.base_width;
+ m_minHeight = m_sizeHints.base_height;
+ } else if ((m_sizeHints.flags & PMinSize)) {
+ m_minWidth = m_sizeHints.min_width;
+ m_minHeight = m_sizeHints.min_height;
+ } else {
+ m_minWidth = m_minHeight = 50;
+ }
+
+ // act
+
+ gravitate(False);
+
+ if (m_w < m_minWidth) {
+ m_w = m_minWidth; m_fixedSize = False; reshape = True;
+ }
+ if (m_h < m_minHeight) {
+ m_h = m_minHeight; m_fixedSize = False; reshape = True;
+ }
+
+ // zeros are iffy, should be calling some Manager method
+
+ if (m_x > DisplayWidth(display(), 0) - m_border->xIndent()) {
+ m_x = DisplayWidth(display(), 0) - m_border->xIndent();
+ }
+
+ if (m_y > DisplayHeight(display(), 0) - m_border->yIndent()) {
+ m_y = DisplayHeight(display(), 0) - m_border->yIndent();
+ }
+
+ if (m_x < m_border->xIndent()) m_x = m_border->xIndent();
+ if (m_y < m_border->yIndent()) m_y = m_border->yIndent();
+
+ m_border->configure(m_x, m_y, m_w, m_h, 0L, Above);
+
+ if (mapped) m_reparenting = True;
+ if (reshape && !m_fixedSize) XResizeWindow(d, m_window, m_w, m_h);
+ XSetWindowBorderWidth(d, m_window, 0);
+
+ m_border->reparent();
+
+ // (support for shaped windows absent)
+
+ XAddToSaveSet(d, m_window);
+
+ if (shouldHide) hide();
+ else {
+ XMapWindow(d, m_window);
+ m_border->map();
+
+ if (CONFIG_CLICK_TO_FOCUS ||
+ (m_transient != None && activeClient() &&
+ activeClient()->m_window == m_transient)) {
+ activate();
+ } else {
+ deactivate();
+ }
+
+ setState(NormalState);
+ }
+
+ if (activeClient() && !isActive()) {
+ activeClient()->installColormap();
+ }
+
+ m_initialising = True;
+}
+
+
+void Client::decorate(Boolean active)
+{
+ m_border->decorate(active, m_w, m_h);
+}
+
+
+void Client::activate()
+{
+// fprintf(stderr, "Client::activate (this = %p, window = %x, parent = %x)\n",
+// this, m_window, parent());
+
+ if (parent() == root()) {
+ fprintf(stderr, "wm2: warning: bad parent in Client::activate\n");
+ return;
+ }
+
+ if (isActive()) {
+ decorate(True);
+ if (CONFIG_RAISE_ON_FOCUS) mapRaised();
+ return;
+ }
+
+ if (activeClient()) {
+ activeClient()->deactivate();
+ // & some other-screen business
+ }
+
+ XUngrabButton(display(), AnyButton, AnyModifier, parent());
+
+ XSetInputFocus(display(), m_window, RevertToPointerRoot,
+ windowManager()->timestamp(False));
+
+ if (m_protocol & PtakeFocus) {
+ sendMessage(Atoms::wm_protocols, Atoms::wm_takeFocus);
+ }
+
+ // now set revert of window that reverts to this one so as to
+ // revert to the window this one used to revert to (huh?)
+
+ windowManager()->skipInRevert(this, m_revert);
+
+ m_revert = activeClient();
+ while (m_revert && !m_revert->isNormal()) m_revert = m_revert->revertTo();
+
+ windowManager()->setActiveClient(this);
+ if (CONFIG_RAISE_ON_FOCUS) mapRaised();
+ decorate(True);
+
+ installColormap(); // new!
+}
+
+
+void Client::deactivate() // called from wm?
+{
+// fprintf(stderr,
+// "Client::deactivate (this = %p, window = %x, parent = %x)\n",
+// this, m_window, parent());
+
+ if (parent() == root()) {
+ fprintf(stderr, "wm2: warning: bad parent in Client::deactivate\n");
+ return;
+ }
+
+ XGrabButton(display(), AnyButton, AnyModifier, parent(), False,
+ ButtonPressMask | ButtonReleaseMask,
+ GrabModeAsync, GrabModeSync, None, None);
+
+ decorate(False);
+}
+
+
+void Client::sendMessage(Atom a, long l)
+{
+ XEvent ev;
+ int status;
+ long mask;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.xclient.type = ClientMessage;
+ ev.xclient.window = m_window;
+ ev.xclient.message_type = a;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = l;
+ ev.xclient.data.l[1] = windowManager()->timestamp(False);
+ mask = 0L;
+ status = XSendEvent(display(), m_window, False, mask, &ev);
+
+ if (status == 0) {
+ fprintf(stderr, "wm2: warning: Client::sendMessage failed\n");
+ }
+}
+
+
+static int getProperty_aux(Display *d, Window w, Atom a, Atom type, long len,
+ unsigned char **p)
+{
+ Atom realType;
+ int format;
+ unsigned long n, extra;
+ int status;
+
+ status = XGetWindowProperty(d, w, a, 0L, len, False, type, &realType,
+ &format, &n, &extra, p);
+
+ if (status != Success || *p == 0) return -1;
+ if (n == 0) XFree((void *) *p);
+
+ return n;
+}
+
+
+char *Client::getProperty(Atom a)
+{
+ unsigned char *p;
+ if (getProperty_aux(display(), m_window, a, XA_STRING, 100L, &p) <= 0) {
+ return NULL;
+ }
+ return (char *)p;
+}
+
+
+int Client::getAtomProperty(Atom a, Atom type)
+{
+ char **p, *x;
+ if (getProperty_aux(display(), m_window, a, type, 1L,
+ (unsigned char **)&p) <= 0) {
+ return 0;
+ }
+
+ x = *p;
+ XFree((void *)p);
+ return (int)x;
+}
+
+
+int Client::getIntegerProperty(Atom a)
+{
+ return getAtomProperty(a, XA_INTEGER);
+}
+
+
+void Client::setState(int state)
+{
+ m_state = state;
+
+// fprintf(stderr, "state set to %d\n",state);
+
+ long data[2];
+ data[0] = (long)state;
+ data[1] = (long)None;
+
+ XChangeProperty(display(), m_window, Atoms::wm_state, Atoms::wm_state,
+ 32, PropModeReplace, (unsigned char *)data, 2);
+}
+
+
+Boolean Client::getState(int *state)
+{
+ long *p = 0;
+
+ if (getProperty_aux(display(), m_window, Atoms::wm_state, Atoms::wm_state,
+ 2L, (unsigned char **)&p) <= 0) {
+ return False;
+ }
+
+ *state = (int) *p;
+ XFree((char *)p);
+ return True;
+}
+
+
+void Client::getProtocols()
+{
+ long n;
+ Atom *p;
+
+ m_protocol = 0;
+ if ((n = getProperty_aux(display(), m_window, Atoms::wm_protocols, XA_ATOM,
+ 20L, (unsigned char **)&p)) <= 0) {
+ return;
+ }
+
+ for (int i = 0; i < n; ++i) {
+ if (p[i] == Atoms::wm_delete) {
+ m_protocol |= Pdelete;
+ } else if (p[i] == Atoms::wm_takeFocus) {
+ m_protocol |= PtakeFocus;
+ }
+ }
+
+ XFree((char *) p);
+}
+
+
+void Client::gravitate(Boolean invert)
+{
+ int gravity;
+ int w = 0, h = 0, xdelta, ydelta;
+
+ // possibly shouldn't work if we haven't been managed yet?
+
+ gravity = NorthWestGravity;
+ if (m_sizeHints.flags & PWinGravity) gravity = m_sizeHints.win_gravity;
+
+ xdelta = m_bw - m_border->xIndent();
+ ydelta = m_bw - m_border->yIndent();
+
+ // note that right and bottom borders have indents of 1
+
+ switch (gravity) {
+
+ case NorthWestGravity:
+ break;
+
+ case NorthGravity:
+ w = xdelta;
+ break;
+
+ case NorthEastGravity:
+ w = xdelta + m_bw-1;
+ break;
+
+ case WestGravity:
+ h = ydelta;
+ break;
+
+ case CenterGravity:
+ case StaticGravity:
+ w = xdelta;
+ h = ydelta;
+ break;
+
+ case EastGravity:
+ w = xdelta + m_bw-1;
+ h = ydelta;
+ break;
+
+ case SouthWestGravity:
+ h = ydelta + m_bw-1;
+ break;
+
+ case SouthGravity:
+ w = xdelta;
+ h = ydelta + m_bw-1;
+ break;
+
+ case SouthEastGravity:
+ w = xdelta + m_bw-1;
+ h = ydelta + m_bw-1;
+ break;
+
+ default:
+ fprintf(stderr, "wm2: bad window gravity %d for window 0x%lx\n",
+ gravity, m_window);
+ return;
+ }
+
+ w += m_border->xIndent();
+ h += m_border->yIndent();
+
+ if (invert) { w = -w; h = -h; }
+
+ m_x += w;
+ m_y += h;
+}
+
+
+Boolean Client::setLabel(void)
+{
+ const char *newLabel;
+
+ if (m_name) newLabel = m_name;
+ else if (m_iconName) newLabel = m_iconName;
+ else newLabel = m_defaultLabel;
+
+ if (!m_label) {
+
+ m_label = NewString(newLabel);
+ return True;
+
+ } else if (strcmp(m_label, newLabel)) {
+
+ free((void *)m_label);
+ m_label = NewString(newLabel);
+ return True;
+
+ } else return True;//False;// dammit!
+}
+
+
+void Client::getColormaps(void)
+{
+ int i, n;
+ Window *cw;
+ XWindowAttributes attr;
+
+ if (!m_initialising) {
+ XGetWindowAttributes(display(), m_window, &attr);
+ m_colormap = attr.colormap;
+
+// fprintf(stderr, "colormap for %s is %p\n",m_label, (void *)m_colormap);
+ }
+
+ n = getProperty_aux(display(), m_window, Atoms::wm_colormaps, XA_WINDOW,
+ 100L, (unsigned char **)&cw);
+
+ if (m_colormapWinCount != 0) {
+ XFree((char *)m_colormapWindows);
+ free((char *)m_windowColormaps);
+ }
+
+ if (n <= 0) {
+ m_colormapWinCount = 0;
+ return;
+ }
+
+ m_colormapWinCount = n;
+ m_colormapWindows = cw;
+
+ m_windowColormaps = (Colormap *)malloc(n * sizeof(Colormap));
+
+ for (i = 0; i < n; ++i) {
+ if (cw[i] == m_window) {
+ m_windowColormaps[i] = m_colormap;
+ } else {
+ XSelectInput(display(), cw[i], ColormapChangeMask);
+ XGetWindowAttributes(display(), cw[i], &attr);
+ m_windowColormaps[i] = attr.colormap;
+ }
+ }
+}
+
+
+void Client::getTransient()
+{
+ Window t = None;
+
+ if (XGetTransientForHint(display(), m_window, &t) != 0) {
+ m_transient = t;
+ } else {
+ m_transient = None;
+ }
+}
+
+
+void Client::hide()
+{
+ if (isHidden()) {
+ fprintf(stderr, "wm2: Client already hidden in Client::hide\n");
+ return;
+ }
+
+ m_border->unmap();
+ XUnmapWindow(display(), m_window);
+
+ if (activeClient() == this) windowManager()->clearFocus();
+
+ setState(IconicState);
+ windowManager()->addToHiddenList(this);
+}
+
+
+void Client::unhide(Boolean map)
+{
+ if (!isHidden()) {
+ fprintf(stderr, "wm2: Client not hidden in Client::unhide\n");
+ return;
+ }
+
+ windowManager()->removeFromHiddenList(this);
+
+ if (map) {
+ setState(NormalState);
+ XMapWindow(display(), m_window);
+ mapRaised();
+
+ if (CONFIG_CLICK_TO_FOCUS) activate();
+ }
+}
+
+
+void Client::sendConfigureNotify()
+{
+ XConfigureEvent ce;
+
+ ce.type = ConfigureNotify;
+ ce.event = m_window;
+ ce.window = m_window;
+
+ ce.x = m_x;
+ ce.y = m_y;
+ ce.width = m_w;
+ ce.height = m_h;
+ ce.border_width = m_bw;
+ ce.above = None;
+ ce.override_redirect = 0;
+
+ XSendEvent(display(), m_window, False, StructureNotifyMask, (XEvent*)&ce);
+}
+
+
+void Client::withdraw()
+{
+ m_border->unmap();
+
+ gravitate(True);
+ XReparentWindow(display(), m_window, root(), m_x, m_y);
+
+// delete m_border;
+// m_border = new Border(this, m_window);
+// m_parent = root();
+
+ gravitate(False);
+
+ XRemoveFromSaveSet(display(), m_window);
+ setState(WithdrawnState);
+
+ ignoreBadWindowErrors = True;
+ XSync(display(), False);
+ ignoreBadWindowErrors = False;
+}
+
+
+void Client::rename()
+{
+ m_border->configure(0, 0, m_w, m_h, CWWidth | CWHeight, Above);
+}
+
+
+void Client::mapRaised()
+{
+ m_border->mapRaised();
+ windowManager()->raiseTransients(this);
+}
+
+
+void Client::kill()
+{
+ if (m_protocol & Pdelete) {
+ sendMessage(Atoms::wm_protocols, Atoms::wm_delete);
+ } else {
+ XKillClient(display(), m_window);
+ }
+}
+
+
+void Client::ensureVisible()
+{
+ int mx = DisplayWidth(display(), 0) - 1; // hack
+ int my = DisplayHeight(display(), 0) - 1;
+ int px = m_x;
+ int py = m_y;
+
+ if (m_x + m_w > mx) m_x = mx - m_w;
+ if (m_y + m_h > my) m_y = my - m_h;
+ if (m_x < 0) m_x = 0;
+ if (m_y < 0) m_y = 0;
+
+ if (m_x != px || m_y != py) m_border->moveTo(m_x, m_y);
+}
+
A => Client.h +146 -0
@@ 0,0 1,146 @@
+
+#ifndef _CLIENT_H_
+#define _CLIENT_H_
+
+#include "General.h"
+#include "Manager.h"
+#include "Border.h"
+
+
+class Client {
+public:
+ Client(WindowManager *const, Window);
+ void release();
+
+ /* for call from WindowManager: */
+
+ void activate(); /* active() */
+ void deactivate(); /* setactive(0) */
+ void gravitate(Boolean invert);
+ void installColormap();
+ void unreparent();
+ void withdraw();
+ void hide();
+ void unhide(Boolean map);
+ void rename();
+ void kill();
+ void mapRaised(); // without activating
+
+ void move(XButtonEvent *); // event for grab timestamp & coords
+ void resize(XButtonEvent *, Boolean, Boolean);
+ void moveOrResize(XButtonEvent *);
+ void ensureVisible(); // make sure x, y are on-screen
+
+ void manage(Boolean mapped);
+ Boolean hasWindow(Window w) {
+ return ((m_window == w) || m_border->hasWindow(w));
+ }
+
+ Client *revertTo() { return m_revert; }
+ void setRevertTo(Client *c) { m_revert = c; }
+
+ Boolean isHidden() { return (m_state == IconicState); }
+ Boolean isWithdrawn() { return (m_state == WithdrawnState); }
+ Boolean isNormal() { return (m_state == NormalState); }
+ Boolean isTransient() { return (m_transient != None); }
+ Window transientFor() { return m_transient; }
+ Boolean isFixedSize() { return m_fixedSize; }
+
+ Boolean isInitialising() { return m_initialising; }
+ Boolean isReparenting() { return m_reparenting; }
+
+ const char *label() { return m_label; }
+ const char *name() { return m_name; }
+ const char *iconName() { return m_iconName; }
+
+ void sendMessage(Atom, long);
+ void sendConfigureNotify();
+
+ /* for call from within: */
+
+ void fatal(char *m) { m_windowManager->fatal(m); }
+ Display *display() { return m_windowManager->display(); }
+ Window parent() { return m_border->parent(); }
+ Window root() { return m_windowManager->root(); }
+ Client *activeClient() { return m_windowManager->activeClient(); }
+ Boolean isActive() { return (activeClient() == this); }
+
+ WindowManager *windowManager() { return m_windowManager; }
+
+ // for call from equivalent wm functions in Events.C:
+
+ void eventButton(XButtonEvent *);
+ void eventMapRequest(XMapRequestEvent *);
+ void eventConfigureRequest(XConfigureRequestEvent *);
+ void eventUnmap(XUnmapEvent *);
+ void eventCreate(XCreateWindowEvent *);
+ void eventColormap(XColormapEvent *);
+ void eventProperty(XPropertyEvent *);
+ void eventEnter(XCrossingEvent *);
+ void eventFocusIn(XFocusInEvent *);
+// void eventShapeNotify(XShapeEvent *);
+ void eventExposure(XExposeEvent *);
+
+private:
+ // gcc says: class Client only defines a private destructor and
+ // has no friends. I don't think that's very nice of gcc. My
+ // code always has plenty of friends.
+ ~Client();
+
+ Window m_window;
+ Window m_transient;
+ Border *m_border;
+
+ Client *m_revert;
+
+ int m_x;
+ int m_y;
+ int m_w;
+ int m_h;
+ int m_bw;
+
+ XSizeHints m_sizeHints;
+ Boolean m_fixedSize;
+ int m_minWidth;
+ int m_minHeight;
+ void fixResizeDimensions(int &, int &, int &, int &);
+
+ int m_state;
+ int m_protocol;
+ Boolean m_initialising;
+ Boolean m_reparenting;
+
+ char *m_name;
+ char *m_iconName;
+ const char *m_label; // alias: one of (instance,class,name,iconName)
+ static const char *const m_defaultLabel;
+
+ Colormap m_colormap;
+ int m_colormapWinCount;
+ Window *m_colormapWindows;
+ Colormap *m_windowColormaps;
+
+ WindowManager *const m_windowManager;
+
+ char *getProperty(Atom);
+ int getAtomProperty(Atom, Atom);
+ int getIntegerProperty(Atom);
+
+ // accessors
+ Boolean getState(int *);
+ void setState(int);
+
+ // internal instantiation requests
+ Boolean setLabel(void); // returns True if changed
+ void getColormaps(void);
+ void getProtocols(void);
+ void getTransient(void);
+
+ void decorate(Boolean active);
+};
+
+#define Pdelete 1
+#define PtakeFocus 2
+
+#endif
+
A => Config.h +31 -0
@@ 0,0 1,31 @@
+
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+#define CONFIG_NICE_FONT "-*-lucida-bold-r-*-*-14-*-75-75-*-*-*-*"
+#define CONFIG_NICE_MENU_FONT "-*-lucida-medium-r-*-*-14-*-75-75-*-*-*-*"
+#define CONFIG_NASTY_FONT "fixed"
+
+#define CONFIG_EXEC_USING_SHELL False
+#define CONFIG_NEW_WINDOW_COMMAND "xterm"
+
+// You can't have CLICK_TO_FOCUS True with RAISE_ON_FOCUS False, but
+// the other three combinations seem to work
+
+#define CONFIG_CLICK_TO_FOCUS False
+#define CONFIG_RAISE_ON_FOCUS False
+
+#define CONFIG_TAB_FOREGROUND "black"
+#define CONFIG_TAB_BACKGROUND "gray80"
+#define CONFIG_FRAME_BACKGROUND "white"
+#define CONFIG_BUTTON_BACKGROUND "white"
+#define CONFIG_BORDERS "black"
+
+#define CONFIG_MENU_FOREGROUND "black"
+#define CONFIG_MENU_BACKGROUND "gray80"
+#define CONFIG_MENU_BORDERS "black"
+
+#define CONFIG_EVERYTHING_ON_ROOT_MENU True
+
+#endif
+
A => Cursors.h +85 -0
@@ 0,0 1,85 @@
+
+#ifndef _WM2_CURSORS_H_
+#define _WM2_CURSORS_H_
+
+#define cursor_width 16
+#define cursor_height 16
+#define cursor_x_hot 1
+#define cursor_y_hot 1
+static unsigned char cursor_bits[] = {
+ 0x00, 0x00, 0x06, 0x00, 0x1e, 0x00, 0x7c, 0x00, 0xfc, 0x01, 0xf8, 0x07,
+ 0xf8, 0x1f, 0xf0, 0x07, 0xf0, 0x03, 0xe0, 0x07, 0xe0, 0x0e, 0x40, 0x1c,
+ 0x40, 0x38, 0x00, 0x70, 0x00, 0x20, 0x00, 0x00};
+
+#define cursor_mask_width 16
+#define cursor_mask_height 16
+static unsigned char cursor_mask_bits[] = {
+ 0x07, 0x00, 0x1f, 0x00, 0x7f, 0x00, 0xfe, 0x01, 0xfe, 0x07, 0xfc, 0x1f,
+ 0xfc, 0x3f, 0xf8, 0x1f, 0xf8, 0x07, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x3e,
+ 0xe0, 0x7c, 0x40, 0xf8, 0x00, 0x70, 0x00, 0x20};
+
+#define ninja_cross_width 16
+#define ninja_cross_height 16
+#define ninja_cross_x_hot 7
+#define ninja_cross_y_hot 7
+static unsigned char ninja_cross_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x10, 0x3c, 0x18, 0x38, 0x0c, 0x70, 0x06,
+ 0xe0, 0x07, 0xc0, 0x03, 0xc0, 0x01, 0xe0, 0x03, 0x70, 0x06, 0x38, 0x06,
+ 0x1c, 0x0c, 0x08, 0x18, 0x00, 0x10, 0x00, 0x00};
+
+#define ninja_cross_mask_width 16
+#define ninja_cross_mask_height 16
+static unsigned char ninja_cross_mask_bits[] = {
+ 0x00, 0x00, 0x18, 0x10, 0x3c, 0x38, 0x7e, 0x3c, 0x7c, 0x1e, 0xf8, 0x0f,
+ 0xf0, 0x0f, 0xe0, 0x07, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0x7c, 0x0f,
+ 0x3e, 0x1e, 0x1c, 0x3c, 0x08, 0x38, 0x00, 0x10};
+
+#define cursor_right_width 16
+#define cursor_right_height 16
+#define cursor_right_x_hot 13
+#define cursor_right_y_hot 7
+static unsigned char cursor_right_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x80, 0x03,
+ 0x80, 0x0f, 0xfe, 0x3f, 0xfe, 0x3f, 0x80, 0x0f, 0x80, 0x03, 0xc0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+#define cursor_right_mask_width 16
+#define cursor_right_mask_height 16
+static unsigned char cursor_right_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0xe0, 0x03, 0xc0, 0x0f,
+ 0xfe, 0x3f, 0xff, 0x7f, 0xff, 0x7f, 0xfe, 0x3f, 0xc0, 0x0f, 0xe0, 0x03,
+ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+#define cursor_down_width 16
+#define cursor_down_height 16
+#define cursor_down_x_hot 7
+#define cursor_down_y_hot 13
+static unsigned char cursor_down_bits[] = {
+ 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
+ 0x90, 0x09, 0xf0, 0x0f, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0xc0, 0x03,
+ 0x80, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00};
+
+#define cursor_down_mask_width 16
+#define cursor_down_mask_height 16
+static unsigned char cursor_down_mask_bits[] = {
+ 0x80, 0x01, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xd0, 0x0b,
+ 0xf8, 0x1f, 0xf8, 0x1f, 0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x07, 0xe0, 0x07,
+ 0xc0, 0x03, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00};
+
+#define cursor_down_right_width 16
+#define cursor_down_right_height 16
+#define cursor_down_right_x_hot 13
+#define cursor_down_right_y_hot 13
+static unsigned char cursor_down_right_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x70, 0x00,
+ 0xe0, 0x04, 0xc0, 0x05, 0x80, 0x0f, 0x00, 0x0f, 0xc0, 0x1f, 0x00, 0x1f,
+ 0x00, 0x3c, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00};
+
+#define cursor_down_right_mask_width 16
+#define cursor_down_right_mask_height 16
+static unsigned char cursor_down_right_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x70, 0x00, 0xf8, 0x04,
+ 0xf0, 0x0f, 0xe0, 0x0f, 0xc0, 0x1f, 0xc0, 0x1f, 0xe0, 0x3f, 0xc0, 0x3f,
+ 0x00, 0x7f, 0x00, 0x7c, 0x00, 0x70, 0x00, 0x00};
+
+#endif
A => Events.C +537 -0
@@ 0,0 1,537 @@
+
+#include "Manager.h"
+#include "Client.h"
+
+
+// hack:
+static unsigned long swallowNextEnterEvent = 0L;
+
+
+int WindowManager::loop()
+{
+ XEvent ev;
+ m_looping = True;
+
+ while (m_looping) {
+
+ nextEvent(&ev);
+ m_currentTime = CurrentTime;
+
+ switch (ev.type) {
+
+ case ButtonPress:
+ eventButton(&ev.xbutton);
+ break;
+
+ case ButtonRelease:
+ break;
+
+ case MapRequest:
+ eventMapRequest(&ev.xmaprequest);
+ break;
+
+ case ConfigureRequest:
+ eventConfigureRequest(&ev.xconfigurerequest);
+ break;
+
+ case UnmapNotify:
+ eventUnmap(&ev.xunmap);
+ break;
+
+ case CreateNotify:
+ eventCreate(&ev.xcreatewindow);
+ break;
+
+ case DestroyNotify:
+ eventDestroy(&ev.xdestroywindow);
+ break;
+
+ case ClientMessage:
+ eventClient(&ev.xclient);
+ break;
+
+ case ColormapNotify:
+ eventColormap(&ev.xcolormap);
+ break;
+
+ case PropertyNotify:
+ eventProperty(&ev.xproperty);
+ break;
+
+ case SelectionClear:
+ fprintf(stderr, "wm2: SelectionClear (this should not happen)\n");
+ break;
+
+ case SelectionNotify:
+ fprintf(stderr, "wm2: SelectionNotify (this should not happen)\n");
+ break;
+
+ case SelectionRequest:
+ fprintf(stderr, "wm2: SelectionRequest (this should not happen)\n");
+ break;
+
+ case EnterNotify:
+ case LeaveNotify:
+ eventEnter(&ev.xcrossing);
+ break;
+
+ case ReparentNotify:
+ eventReparent(&ev.xreparent);
+ break;
+
+ case FocusIn:
+ eventFocusIn(&ev.xfocus);
+ break;
+
+ case Expose: // might be wm tab
+ eventExposure(&ev.xexpose);
+ break;
+
+ case MotionNotify:
+ case FocusOut:
+ case ConfigureNotify:
+ case MapNotify:
+ case MappingNotify:
+
+#ifdef DEBUG_EV
+ trace("ignore", 0, &ev);
+#endif
+ break;
+
+ default:
+ if (ev.type == m_shapeEvent) eventShapeNotify((XShapeEvent *)&ev);
+ else fprintf(stderr, "wm2: unsupported event type %d\n", ev.type);
+ break;
+ }
+ }
+
+ release();
+ return m_returnCode;
+}
+
+
+void WindowManager::nextEvent(XEvent *e)
+{
+ int fd;
+ fd_set rfds;
+ struct timeval t;
+
+ if (!m_signalled) {
+
+ if (QLength(m_display) > 0) {
+ XNextEvent(m_display, e);
+ return;
+ }
+
+ fd = ConnectionNumber(m_display);
+ memset((void *)&rfds, 0, sizeof(fd_set)); // SGI's FD_ZERO is fucked
+ FD_SET(fd, &rfds);
+ t.tv_sec = t.tv_usec = 0;
+
+ if (select(fd + 1, &rfds, NULL, NULL, &t) == 1) {
+ XNextEvent(m_display, e);
+ return;
+ }
+
+ XFlush(m_display);
+ FD_SET(fd, &rfds);
+
+ if (select(fd + 1, &rfds, NULL, NULL, NULL) == 1) {
+ XNextEvent(m_display, e);
+ return;
+ }
+
+ if (errno != EINTR || !m_signalled) {
+ perror("wm2: select failed");
+ m_looping = False;
+ }
+ }
+
+ fprintf(stderr, "wm2: signal caught, exiting\n");
+ m_looping = False;
+ m_returnCode = 0;
+}
+
+
+void WindowManager::eventConfigureRequest(XConfigureRequestEvent *e)
+{
+ XWindowChanges wc;
+ Client *c = windowToClient(e->window);
+
+ e->value_mask &= ~CWSibling;
+ if (c) c->eventConfigureRequest(e);
+ else {
+
+ wc.x = e->x;
+ wc.y = e->y;
+ wc.width = e->width;
+ wc.height = e->height;
+ wc.border_width = 0;
+ wc.sibling = None;
+ wc.stack_mode = Above;
+ e->value_mask &= ~CWStackMode;
+ e->value_mask |= CWBorderWidth;
+
+ XConfigureWindow(display(), e->window, e->value_mask, &wc);
+ }
+}
+
+
+void Client::eventConfigureRequest(XConfigureRequestEvent *e)
+{
+ XWindowChanges wc;
+ Boolean raise = False;
+
+ e->value_mask &= ~CWSibling;
+
+ gravitate(True);
+
+ if (e->value_mask & CWX) m_x = e->x;
+ if (e->value_mask & CWY) m_y = e->y;
+ if (e->value_mask & CWWidth) m_w = e->width;
+ if (e->value_mask & CWHeight) m_h = e->height;
+ if (e->value_mask & CWBorderWidth) m_bw = e->border_width;
+
+ gravitate(False);
+
+ if (e->value_mask & CWStackMode) {
+ if (e->detail == Above) raise = True;
+ e->value_mask &= ~CWStackMode;
+ }
+
+ if (parent() != root() && m_window == e->window) {
+ m_border->configure(m_x, m_y, m_w, m_h, e->value_mask, e->detail);
+ sendConfigureNotify();
+ }
+
+ if (m_initialising) {
+ wc.x = m_border->xIndent();
+ wc.y = m_border->yIndent();
+ } else {
+ wc.x = e->x;
+ wc.y = e->y;
+ }
+
+ wc.width = e->width;
+ wc.height = e->height;
+ wc.border_width = 0;
+ wc.sibling = None;
+ wc.stack_mode = Above;
+ e->value_mask &= ~CWStackMode;
+ e->value_mask |= CWBorderWidth;
+
+ XConfigureWindow(display(), e->window, e->value_mask, &wc);
+
+ // if parent==root, it's not managed yet -- & it'll be raised when it is
+ if (raise && parent() != root()) {
+ mapRaised();
+ if (CONFIG_CLICK_TO_FOCUS) activate();
+ }
+}
+
+
+void WindowManager::eventMapRequest(XMapRequestEvent *e)
+{
+ Client *c = windowToClient(e->window);
+
+ // some stuff for multi-screen fuckups here, omitted
+
+ if (c) c->eventMapRequest(e);
+ else {
+ fprintf(stderr, "wm2: bad map request for window %lx\n", e->window);
+ }
+}
+
+
+void Client::eventMapRequest(XMapRequestEvent *)
+{
+ switch(m_state) {
+
+ case WithdrawnState:
+ if (parent() == root()) {
+ manage(False);
+ return;
+ }
+
+ m_border->reparent();
+
+ XAddToSaveSet(display(), m_window);
+ // fall through
+
+ case NormalState:
+ XMapWindow(display(), m_window);
+ mapRaised();
+ setState(NormalState);
+
+ if (CONFIG_CLICK_TO_FOCUS)/* ||
+ (m_transient != None && activeClient() &&
+ m_transient == activeClient()->m_window))*/ {
+ activate();
+ }
+ break;
+
+ case IconicState:
+ unhide(True);
+ break;
+ }
+}
+
+
+void WindowManager::eventUnmap(XUnmapEvent *e)
+{
+ Client *c = windowToClient(e->window);
+ if (c) c->eventUnmap(e);
+}
+
+
+void Client::eventUnmap(XUnmapEvent *e)
+{
+ swallowNextEnterEvent = 0L;
+
+ switch (m_state) {
+
+ case IconicState:
+ if (e->send_event) {
+ unhide(False);
+ withdraw();
+ }
+ break;
+
+ case NormalState:
+ if (isActive()) m_windowManager->clearFocus();
+ if (!m_reparenting) withdraw();
+ break;
+ }
+
+ m_reparenting = False;
+}
+
+
+void WindowManager::eventCreate(XCreateWindowEvent *e)
+{
+ if (e->override_redirect) return;
+ Client *c = windowToClient(e->window, True);
+ if (c) c->eventCreate(e);
+}
+
+
+void Client::eventCreate(XCreateWindowEvent *)
+{
+ if (!CONFIG_CLICK_TO_FOCUS) {
+ Window r, ch;
+ int x = -1, y = -1, wx, wy;
+ unsigned int k;
+ XQueryPointer(display(), root(), &r, &ch, &x, &y, &wx, &wy, &k);
+ if (x > m_x && y > m_y && x < m_x + m_w && y < m_y + m_h) {
+ activate();
+ }
+ }
+}
+
+
+void WindowManager::eventDestroy(XDestroyWindowEvent *e)
+{
+ Client *c = windowToClient(e->window);
+
+ if (c) {
+ swallowNextEnterEvent = 0L;
+
+ for (int i = m_clients.count()-1; i >= 0; --i) {
+ if (m_clients.item(i) == c) {
+ m_clients.remove(i);
+ break;
+ }
+ }
+
+ c->release();
+
+ ignoreBadWindowErrors = True;
+ XSync(display(), False);
+ ignoreBadWindowErrors = False;
+ }
+}
+
+
+void WindowManager::eventClient(XClientMessageEvent *e)
+{
+ Client *c = windowToClient(e->window);
+
+ if (e->message_type == Atoms::wm_changeState) {
+ if (c && e->format == 32 && e->data.l[0] == IconicState && c != 0) {
+ if (c->isNormal()) c->hide();
+ return;
+ }
+ }
+
+ fprintf(stderr, "wm2: unexpected XClientMessageEvent, type 0x%lx, "
+ "window 0x%lx\n", e->message_type, e->window);
+}
+
+
+void WindowManager::eventColormap(XColormapEvent *e)
+{
+ Client *c = windowToClient(e->window);
+ int i;
+
+ if (e->c_new) { // this field is called "new" in the old C++-unaware Xlib
+
+ if (c) c->eventColormap(e);
+ else {
+ for (i = 0; i < m_clients.count(); ++i) {
+ m_clients.item(i)->eventColormap(e);
+ }
+ }
+ }
+}
+
+
+void Client::eventColormap(XColormapEvent *e)
+{
+ if (e->window == m_window || e->window == parent()) {
+
+ m_colormap = e->colormap;
+ if (isActive()) installColormap();
+
+ } else {
+
+ for (int i = 0; i < m_colormapWinCount; ++i) {
+ if (m_colormapWindows[i] == e->window) {
+ m_windowColormaps[i] = e->colormap;
+ if (isActive()) installColormap();
+ return;
+ }
+ }
+ }
+}
+
+
+void WindowManager::eventProperty(XPropertyEvent *e)
+{
+ Client *c = windowToClient(e->window);
+ if (c) c->eventProperty(e);
+}
+
+
+void Client::eventProperty(XPropertyEvent *e)
+{
+ Atom a = e->atom;
+ Boolean shouldDelete = (e->state == PropertyDelete);
+
+ switch (a) {
+
+ case XA_WM_ICON_NAME:
+ if (m_iconName) XFree((char *)m_iconName);
+ m_iconName = shouldDelete ? 0 : getProperty(a);
+ if (setLabel()) rename();
+ return;
+
+ case XA_WM_NAME:
+ if (m_name) XFree((char *)m_name);
+ m_name = shouldDelete ? 0 : getProperty(a);
+ if (setLabel()) rename();
+ return;
+
+ case XA_WM_TRANSIENT_FOR:
+ getTransient();
+ return;
+ }
+
+ if (a == Atoms::wm_colormaps) {
+ getColormaps();
+ if (isActive()) installColormap();
+ }
+}
+
+
+void WindowManager::eventReparent(XReparentEvent *e)
+{
+ if (e->override_redirect) return;
+ (void)windowToClient(e->window, True); // create if absent
+
+ // odd screen complications, omitted
+}
+
+
+void WindowManager::eventEnter(XCrossingEvent *e)
+{
+// if (e->detail == NotifyVirtual || e->detail == NotifyNonlinearVirtual) {
+// return;
+// }
+
+ m_currentTime = e->time; // not CurrentTime
+
+ Client *c = windowToClient(e->window);
+ if (c) c->eventEnter(e);
+}
+
+
+void Client::eventEnter(XCrossingEvent *e)
+{
+ long s = swallowNextEnterEvent;
+
+ if (s == 0L && e->type == LeaveNotify) {
+
+ if (!CONFIG_CLICK_TO_FOCUS &&
+ e->window != m_window && e->window != parent() &&
+ // must be tab or button
+ ((e->x > 1 && e->x < m_border->xIndent() &&
+ e->y > 1 && e->y < m_border->xIndent()) ||
+ (e->x > m_border->xIndent() - m_border->yIndent() &&
+ e->x < m_border->xIndent() + m_w &&
+ e->y > 1 && e->y < m_border->yIndent()))) {
+
+ swallowNextEnterEvent = e->time; // so you can reach the button!
+ }
+ return;
+
+ } else if (s != 0L) {
+
+ swallowNextEnterEvent = 0L;
+
+ if (e->time <= s || e->time - s < 500L) {
+ return;
+ }
+ }
+
+ if (e->type == EnterNotify && !isActive() && !CONFIG_CLICK_TO_FOCUS) {
+ activate();
+ }
+}
+
+
+void WindowManager::eventFocusIn(XFocusInEvent *e)
+{
+ if (e->detail != NotifyNonlinearVirtual) return;
+ Client *c = windowToClient(e->window);
+
+ if (c) c->eventFocusIn(e);
+}
+
+
+void Client::eventFocusIn(XFocusInEvent *e)
+{
+ if (m_window == e->window && !isActive()) {
+ activate();
+ }
+}
+
+
+void WindowManager::eventExposure(XExposeEvent *e)
+{
+ if (e->count != 0) return;
+ Client *c = windowToClient(e->window);
+ if (c) c->eventExposure(e);
+}
+
+
+void Client::eventExposure(XExposeEvent *e)
+{
+ if (m_border->hasWindow(e->window)) {
+ m_border->expose(e);
+ }
+}
+
+
+
+// don't handle these (yet?)
+void WindowManager::eventShapeNotify(XShapeEvent *) { }
A => General.h +58 -0
@@ 0,0 1,58 @@
+
+#ifndef _GENERAL_H_
+#define _GENERAL_H_
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#define _POSIX_SOURCE 1
+
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xos.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+
+#include <X11/extensions/shape.h>
+
+// True and False are defined in Xlib.h
+typedef char Boolean;
+
+#define NewString(x) (strcpy((char *)malloc(strlen(x)+1),(x)))
+
+#ifndef SIGNAL_CALLBACK_TYPE
+#define SIGNAL_CALLBACK_TYPE (void (*)(...))
+#endif
+
+#define signal(x,y) \
+ do { \
+ struct sigaction sAct; \
+ (void)sigemptyset(&sAct.sa_mask); \
+ sAct.sa_flags = 0; \
+ sAct.sa_handler = (SIGNAL_CALLBACK_TYPE(y)); \
+ (void)sigaction((x), &sAct, NULL); \
+ } while (0)
+
+#include "Config.h"
+
+class Atoms {
+public:
+ static Atom wm_state;
+ static Atom wm_changeState;
+ static Atom wm_protocols;
+ static Atom wm_delete;
+ static Atom wm_takeFocus;
+ static Atom wm_colormaps;
+ static Atom wm2_running;
+};
+
+extern Boolean ignoreBadWindowErrors; // tidiness hack
+
+#endif
A => Main.C +15 -0
@@ 0,0 1,15 @@
+
+#include "Manager.h"
+
+int main(int argc, char **argv)
+{
+ if (argc > 1) {
+ for (int i = strlen(argv[0])-1; i > 0 && argv[0][i] != '/'; --i);
+ fprintf(stderr, "usage: %s\n", argv[0] + (i > 0) + i);
+ exit(2);
+ }
+
+ WindowManager manager;
+ return 0;
+}
+
A => Makefile +111 -0
@@ 0,0 1,111 @@
+
+LIBS = -lXext -lX11 -lXmu -lm
+CC = ncc
+CCC = NCC
+CFLAGS = -O2
+OBJECTS = Border.o Buttons.o Client.o Events.o Main.o Manager.o Rotated.o listimpl.o
+
+.c.o:
+ $(CC) -c $(CFLAGS) $<
+
+.C.o:
+ $(CCC) -c $(CFLAGS) $<
+
+wm2: $(OBJECTS)
+ $(CCC) -o wm2 $(OBJECTS) $(LIBS)
+
+depend:
+ makedepend -- $(CFLAGS) -- *.C
+
+clean:
+ rm -f *.o wm2 core
+
+# DO NOT DELETE
+
+Border.o: Border.h General.h /usr/include/unistd.h /usr/include/sys/types.h
+Border.o: /usr/include/sgidefs.h /usr/include/sys/bsd_types.h
+Border.o: /usr/include/sys/select.h /usr/include/sys/time.h
+Border.o: /usr/include/stdio.h /usr/include/signal.h
+Border.o: /usr/include/sys/signal.h /usr/include/sys/siginfo.h
+Border.o: /usr/include/errno.h /usr/include/sys/errno.h /usr/include/stdlib.h
+Border.o: /usr/include/X11/X.h /usr/include/X11/Xlib.h
+Border.o: /usr/include/X11/Xfuncproto.h /usr/include/X11/Xosdefs.h
+Border.o: /usr/include/stddef.h /usr/include/X11/Xos.h /usr/include/string.h
+Border.o: /usr/include/fcntl.h /usr/include/sys/fcntl.h
+Border.o: /usr/include/X11/Xutil.h /usr/include/X11/Xatom.h
+Border.o: /usr/include/X11/extensions/shape.h Config.h Rotated.h Client.h
+Border.o: Manager.h listmacro.h
+Buttons.o: Manager.h General.h /usr/include/unistd.h /usr/include/sys/types.h
+Buttons.o: /usr/include/sgidefs.h /usr/include/sys/bsd_types.h
+Buttons.o: /usr/include/sys/select.h /usr/include/sys/time.h
+Buttons.o: /usr/include/stdio.h /usr/include/signal.h
+Buttons.o: /usr/include/sys/signal.h /usr/include/sys/siginfo.h
+Buttons.o: /usr/include/errno.h /usr/include/sys/errno.h
+Buttons.o: /usr/include/stdlib.h /usr/include/X11/X.h /usr/include/X11/Xlib.h
+Buttons.o: /usr/include/X11/Xfuncproto.h /usr/include/X11/Xosdefs.h
+Buttons.o: /usr/include/stddef.h /usr/include/X11/Xos.h /usr/include/string.h
+Buttons.o: /usr/include/fcntl.h /usr/include/sys/fcntl.h
+Buttons.o: /usr/include/X11/Xutil.h /usr/include/X11/Xatom.h
+Buttons.o: /usr/include/X11/extensions/shape.h Config.h listmacro.h Client.h
+Buttons.o: Border.h Rotated.h
+Client.o: Manager.h General.h /usr/include/unistd.h /usr/include/sys/types.h
+Client.o: /usr/include/sgidefs.h /usr/include/sys/bsd_types.h
+Client.o: /usr/include/sys/select.h /usr/include/sys/time.h
+Client.o: /usr/include/stdio.h /usr/include/signal.h
+Client.o: /usr/include/sys/signal.h /usr/include/sys/siginfo.h
+Client.o: /usr/include/errno.h /usr/include/sys/errno.h /usr/include/stdlib.h
+Client.o: /usr/include/X11/X.h /usr/include/X11/Xlib.h
+Client.o: /usr/include/X11/Xfuncproto.h /usr/include/X11/Xosdefs.h
+Client.o: /usr/include/stddef.h /usr/include/X11/Xos.h /usr/include/string.h
+Client.o: /usr/include/fcntl.h /usr/include/sys/fcntl.h
+Client.o: /usr/include/X11/Xutil.h /usr/include/X11/Xatom.h
+Client.o: /usr/include/X11/extensions/shape.h Config.h listmacro.h Client.h
+Client.o: Border.h Rotated.h
+Events.o: Manager.h General.h /usr/include/unistd.h /usr/include/sys/types.h
+Events.o: /usr/include/sgidefs.h /usr/include/sys/bsd_types.h
+Events.o: /usr/include/sys/select.h /usr/include/sys/time.h
+Events.o: /usr/include/stdio.h /usr/include/signal.h
+Events.o: /usr/include/sys/signal.h /usr/include/sys/siginfo.h
+Events.o: /usr/include/errno.h /usr/include/sys/errno.h /usr/include/stdlib.h
+Events.o: /usr/include/X11/X.h /usr/include/X11/Xlib.h
+Events.o: /usr/include/X11/Xfuncproto.h /usr/include/X11/Xosdefs.h
+Events.o: /usr/include/stddef.h /usr/include/X11/Xos.h /usr/include/string.h
+Events.o: /usr/include/fcntl.h /usr/include/sys/fcntl.h
+Events.o: /usr/include/X11/Xutil.h /usr/include/X11/Xatom.h
+Events.o: /usr/include/X11/extensions/shape.h Config.h listmacro.h Client.h
+Events.o: Border.h Rotated.h
+Main.o: Manager.h General.h /usr/include/unistd.h /usr/include/sys/types.h
+Main.o: /usr/include/sgidefs.h /usr/include/sys/bsd_types.h
+Main.o: /usr/include/sys/select.h /usr/include/sys/time.h
+Main.o: /usr/include/stdio.h /usr/include/signal.h /usr/include/sys/signal.h
+Main.o: /usr/include/sys/siginfo.h /usr/include/errno.h
+Main.o: /usr/include/sys/errno.h /usr/include/stdlib.h /usr/include/X11/X.h
+Main.o: /usr/include/X11/Xlib.h /usr/include/X11/Xfuncproto.h
+Main.o: /usr/include/X11/Xosdefs.h /usr/include/stddef.h
+Main.o: /usr/include/X11/Xos.h /usr/include/string.h /usr/include/fcntl.h
+Main.o: /usr/include/sys/fcntl.h /usr/include/X11/Xutil.h
+Main.o: /usr/include/X11/Xatom.h /usr/include/X11/extensions/shape.h Config.h
+Main.o: listmacro.h
+Manager.o: Manager.h General.h /usr/include/unistd.h /usr/include/sys/types.h
+Manager.o: /usr/include/sgidefs.h /usr/include/sys/bsd_types.h
+Manager.o: /usr/include/sys/select.h /usr/include/sys/time.h
+Manager.o: /usr/include/stdio.h /usr/include/signal.h
+Manager.o: /usr/include/sys/signal.h /usr/include/sys/siginfo.h
+Manager.o: /usr/include/errno.h /usr/include/sys/errno.h
+Manager.o: /usr/include/stdlib.h /usr/include/X11/X.h /usr/include/X11/Xlib.h
+Manager.o: /usr/include/X11/Xfuncproto.h /usr/include/X11/Xosdefs.h
+Manager.o: /usr/include/stddef.h /usr/include/X11/Xos.h /usr/include/string.h
+Manager.o: /usr/include/fcntl.h /usr/include/sys/fcntl.h
+Manager.o: /usr/include/X11/Xutil.h /usr/include/X11/Xatom.h
+Manager.o: /usr/include/X11/extensions/shape.h Config.h listmacro.h Client.h
+Manager.o: Border.h Rotated.h /usr/include/X11/Xproto.h
+Manager.o: /usr/include/X11/Xmd.h /usr/include/X11/Xprotostr.h
+Manager.o: /usr/include/sys/wait.h Cursors.h
+Rotated.o: /usr/include/X11/Xlib.h /usr/include/sys/types.h
+Rotated.o: /usr/include/sgidefs.h /usr/include/sys/bsd_types.h
+Rotated.o: /usr/include/sys/select.h /usr/include/X11/X.h
+Rotated.o: /usr/include/X11/Xfuncproto.h /usr/include/X11/Xosdefs.h
+Rotated.o: /usr/include/stddef.h /usr/include/X11/Xutil.h
+Rotated.o: /usr/include/stdlib.h /usr/include/string.h /usr/include/stdio.h
+Rotated.o: Rotated.h
+listimpl.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/sgidefs.h
A => Manager.C +534 -0
@@ 0,0 1,534 @@
+
+#include "Manager.h"
+#include "Client.h"
+#include <string.h>
+#include <X11/Xproto.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include "Cursors.h"
+
+Atom Atoms::wm_state;
+Atom Atoms::wm_changeState;
+Atom Atoms::wm_protocols;
+Atom Atoms::wm_delete;
+Atom Atoms::wm_takeFocus;
+Atom Atoms::wm_colormaps;
+Atom Atoms::wm2_running;
+
+int WindowManager::m_signalled = False;
+Boolean WindowManager::m_initialising = False;
+Boolean ignoreBadWindowErrors;
+
+const char *const WindowManager::m_menuCreateLabel = "New";
+
+implementPList(ClientList, Client);
+
+
+WindowManager::WindowManager() :
+ m_menuGC(0), m_menuWindow(0), m_menuFont(0)
+{
+ fprintf(stderr, "wm2: Copyright (c) 1996 Chris Cannam\n"
+ " Parts derived from 9wm Copyright (c) 1994-96 David Hogan\n"
+ " %s\n Copying and redistribution encouraged. "
+ "No warranty\n\n", XV_COPYRIGHT);
+
+ m_display = XOpenDisplay(NULL);
+ if (!m_display) fatal("can't open display");
+
+ m_shell = (char *)getenv("SHELL");
+ if (!m_shell) m_shell = NewString("/bin/sh");
+
+ m_initialising = True;
+ XSetErrorHandler(errorHandler);
+ ignoreBadWindowErrors = False;
+
+ // 9wm does more, I think for nohup
+ signal(SIGTERM, sigHandler);
+ signal(SIGINT, sigHandler);
+ signal(SIGHUP, sigHandler);
+
+ m_currentTime = -1;
+ m_activeClient = 0;
+
+ Atoms::wm_state = XInternAtom(m_display, "WM_STATE", False);
+ Atoms::wm_changeState= XInternAtom(m_display, "WM_CHANGE_STATE", False);
+ Atoms::wm_protocols = XInternAtom(m_display, "WM_PROTOCOLS", False);
+ Atoms::wm_delete = XInternAtom(m_display, "WM_DELETE_WINDOW", False);
+ Atoms::wm_takeFocus = XInternAtom(m_display, "WM_TAKE_FOCUS", False);
+ Atoms::wm_colormaps = XInternAtom(m_display, "WM_COLORMAP_WINDOWS", False);
+ Atoms::wm2_running = XInternAtom(m_display, "_WM2_RUNNING", False);
+
+ int dummy;
+ if (!XShapeQueryExtension(m_display, &m_shapeEvent, &dummy))
+ fatal("no shape extension, can't run without it");
+
+ // we only cope with one screen!
+ initialiseScreen();
+
+ XSetSelectionOwner(m_display, Atoms::wm2_running,
+ m_menuWindow, timestamp(True));
+ XSync(m_display, False);
+ m_initialising = False;
+ m_returnCode = 0;
+
+ clearFocus();
+ scanInitialWindows();
+
+ loop();
+}
+
+
+WindowManager::~WindowManager()
+{
+ // empty
+}
+
+
+void WindowManager::release()
+{
+ if (m_returnCode != 0) return; // hasty exit
+
+ ClientList normalList, unparentList;
+ Client *c;
+ int i;
+
+ for (i = 0; i < m_clients.count(); ++i) {
+ c = m_clients.item(i);
+// fprintf(stderr, "client %d is %p\n", i, c);
+
+ if (c->isNormal()) normalList.append(c);
+ else unparentList.append(c);
+ }
+
+ for (i = normalList.count()-1; i >= 0; --i) {
+ unparentList.append(normalList.item(i));
+ }
+
+ m_clients.remove_all();
+
+ for (i = 0; i < unparentList.count(); ++i) {
+// fprintf(stderr, "unparenting client %p\n",unparentList.item(i));
+ unparentList.item(i)->unreparent();
+ unparentList.item(i)->release();
+ unparentList.item(i) = 0;
+ }
+
+ XSetInputFocus(m_display, PointerRoot, RevertToPointerRoot,
+ timestamp(False));
+ installColormap(None);
+
+ XFreeCursor(m_display, m_cursor);
+ XFreeCursor(m_display, m_xCursor);
+ XFreeCursor(m_display, m_vCursor);
+ XFreeCursor(m_display, m_hCursor);
+ XFreeCursor(m_display, m_vhCursor);
+
+ XFreeFont(m_display, m_menuFont);
+ XFreeGC(m_display, m_menuGC);
+
+ XCloseDisplay(m_display);
+}
+
+
+void WindowManager::fatal(const char *message)
+{
+ fprintf(stderr, "wm2: ");
+ perror(message);
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+
+int WindowManager::errorHandler(Display *d, XErrorEvent *e)
+{
+ if (m_initialising && (e->request_code == X_ChangeWindowAttributes) &&
+ e->error_code == BadAccess) {
+ fprintf(stderr, "wm2: another window manager running?\n");
+ exit(1);
+ }
+
+ // ugh
+ if (ignoreBadWindowErrors == True && e->error_code == BadWindow) return 0;
+
+ char msg[100], number[30], request[100];
+ XGetErrorText(d, e->error_code, msg, 100);
+ sprintf(number, "%d", e->request_code);
+ XGetErrorDatabaseText(d, "XRequest", number, "", request, 100);
+
+ if (request[0] == '\0') sprintf(request, "<request-code-%d>",
+ e->request_code);
+
+ fprintf(stderr, "wm2: %s (0x%lx): %s\n", request, e->resourceid, msg);
+
+ if (m_initialising) {
+ fprintf(stderr, "wm2: failure during initialisation, abandoning\n");
+ exit(1);
+ }
+
+ return 0;
+}
+
+
+static Cursor makeCursor(Display *d, Window w,
+ unsigned char *bits, unsigned char *mask_bits,
+ int width, int height, int xhot, int yhot,
+ XColor *fg, XColor *bg)
+{
+ Pixmap pixmap =
+ XCreateBitmapFromData(d, w, (const char *)bits, width, height);
+
+ Pixmap mask =
+ XCreateBitmapFromData(d, w, (const char *)mask_bits, width, height);
+
+ Cursor cursor = XCreatePixmapCursor(d, pixmap, mask, fg, bg, xhot, yhot);
+ XFreePixmap(d, pixmap);
+ XFreePixmap(d, mask);
+
+ return cursor;
+}
+
+
+void WindowManager::initialiseScreen()
+{
+ int i = 0;
+ m_screenNumber = i;
+
+ m_root = RootWindow(m_display, i);
+ m_defaultColormap = DefaultColormap(m_display, i);
+ m_minimumColormaps = MinCmapsOfScreen(ScreenOfDisplay(m_display, i));
+
+ unsigned long blackPixel = BlackPixel(m_display, i);
+ unsigned long whitePixel = WhitePixel(m_display, i);
+
+ XColor black = { blackPixel, 0, 0, 0, 7, ' ' };
+ XColor white = { whitePixel, 0xffff, 0xffff, 0xffff, 7, ' ' };
+
+ m_cursor = makeCursor
+ (m_display, m_root, cursor_bits, cursor_mask_bits,
+ cursor_width, cursor_height, cursor_x_hot,
+ cursor_y_hot, &black, &white);
+
+ m_xCursor = makeCursor
+ (m_display, m_root, ninja_cross_bits, ninja_cross_mask_bits,
+ ninja_cross_width, ninja_cross_height, ninja_cross_x_hot,
+ ninja_cross_y_hot, &black, &white);
+
+ m_hCursor = makeCursor
+ (m_display, m_root, cursor_right_bits, cursor_right_mask_bits,
+ cursor_right_width, cursor_right_height, cursor_right_x_hot,
+ cursor_right_y_hot, &black, &white);
+
+ m_vCursor = makeCursor
+ (m_display, m_root, cursor_down_bits, cursor_down_mask_bits,
+ cursor_down_width, cursor_down_height, cursor_down_x_hot,
+ cursor_down_y_hot, &black, &white);
+
+ m_vhCursor = makeCursor
+ (m_display, m_root, cursor_down_right_bits, cursor_down_right_mask_bits,
+ cursor_down_right_width, cursor_down_right_height,
+ cursor_down_right_x_hot, cursor_down_right_y_hot, &black, &white);
+
+ XSetWindowAttributes attr;
+ attr.cursor = m_cursor;
+ attr.event_mask = SubstructureRedirectMask | SubstructureNotifyMask |
+ ColormapChangeMask | ButtonPressMask | ButtonReleaseMask |
+ PropertyChangeMask;
+ XChangeWindowAttributes(m_display, m_root, CWCursor | CWEventMask, &attr);
+ XSync(m_display, False);
+
+ XColor nearest, ideal;
+
+ if (!XAllocNamedColor(m_display, m_defaultColormap,
+ CONFIG_MENU_FOREGROUND, &nearest, &ideal)) {
+ fatal("couldn't load menu foreground colour");
+ } else m_menuForegroundPixel = nearest.pixel;
+
+ if (!XAllocNamedColor(m_display, m_defaultColormap,
+ CONFIG_MENU_BACKGROUND, &nearest, &ideal)) {
+ fatal("couldn't load menu background colour");
+ } else m_menuBackgroundPixel = nearest.pixel;
+
+ if (!XAllocNamedColor(m_display, m_defaultColormap,
+ CONFIG_MENU_BORDERS, &nearest, &ideal)) {
+ fatal("couldn't load menu border colour");
+ } else m_menuBorderPixel = nearest.pixel;
+
+ m_menuWindow = XCreateSimpleWindow
+ (m_display, m_root, 0, 0, 1, 1, 1,
+ m_menuBorderPixel, m_menuBackgroundPixel);
+
+ if (DoesSaveUnders(ScreenOfDisplay(m_display, m_screenNumber))) {
+ XSetWindowAttributes attr;
+ attr.save_under = True;
+ XChangeWindowAttributes(m_display, m_menuWindow, CWSaveUnder, &attr);
+ }
+
+ XGCValues values;
+ values.background = m_menuBackgroundPixel;
+ values.foreground = m_menuForegroundPixel ^ m_menuBackgroundPixel;
+ values.function = GXxor;
+ values.line_width = 0;
+ values.subwindow_mode = IncludeInferiors;
+
+ m_menuFont = XLoadQueryFont(display(), CONFIG_NICE_MENU_FONT);
+ if (!m_menuFont) m_menuFont = XLoadQueryFont(display(),
+ CONFIG_NASTY_FONT);
+ if (!m_menuFont) fatal("couldn't load default menu font\n");
+
+ values.font = m_menuFont->fid;
+ m_menuGC = XCreateGC
+ (display(), root(), GCForeground | GCBackground |
+ GCFunction | GCLineWidth | GCSubwindowMode | GCFont, &values);
+}
+
+
+void WindowManager::installCursor(RootCursor c)
+{
+ installCursorOnWindow(c, m_root);
+}
+
+
+void WindowManager::installCursorOnWindow(RootCursor c, Window w)
+{
+ XSetWindowAttributes attr;
+
+ switch (c) {
+ case DeleteCursor: attr.cursor = m_xCursor; break;
+ case DownCursor: attr.cursor = m_vCursor; break;
+ case RightCursor: attr.cursor = m_hCursor; break;
+ case DownrightCursor: attr.cursor = m_vhCursor; break;
+ case NormalCursor: attr.cursor = m_cursor; break;
+ }
+
+ XChangeWindowAttributes(m_display, w, CWCursor, &attr);
+}
+
+
+int WindowManager::timestamp(Boolean reset)
+{
+ if (reset) m_currentTime = CurrentTime;
+
+ if (m_currentTime == CurrentTime) {
+
+ XEvent event;
+ XChangeProperty(m_display, m_root, Atoms::wm2_running,
+ Atoms::wm2_running, 8, PropModeAppend,
+ (unsigned char *)"", 0);
+ XMaskEvent(m_display, PropertyChangeMask, &event);
+
+ m_currentTime = event.xproperty.time;
+ }
+
+ return m_currentTime;
+}
+
+void WindowManager::sigHandler()
+{
+ m_signalled = True;
+}
+
+void WindowManager::scanInitialWindows()
+{
+ unsigned int i, n;
+ Window w1, w2, *wins;
+ XWindowAttributes attr;
+
+ XQueryTree(m_display, m_root, &w1, &w2, &wins, &n);
+
+ for (i = 0; i < n; ++i) {
+
+ XGetWindowAttributes(m_display, wins[i], &attr);
+ if (attr.override_redirect || wins[i] == m_menuWindow) continue;
+
+ (void)windowToClient(wins[i], True);
+ }
+
+ XFree((void *)wins);
+}
+
+Client *WindowManager::windowToClient(Window w, Boolean create)
+{
+ if (w == 0) return 0;
+
+ for (int i = m_clients.count()-1; i >= 0; --i) {
+
+ if (m_clients.item(i)->hasWindow(w)) {
+
+// fprintf(stderr, "WindowManager::windowToClient: located %p (\"%s\")\n",
+// m_clients.item(i), m_clients.item(i)->label());
+
+ return m_clients.item(i);
+ }
+ }
+
+ if (!create) return 0;
+ else {
+ Client *newC = new Client(this, w);
+ m_clients.append(newC);
+
+// fprintf(stderr, "I now have %d clients\n", (int)m_clients.count());
+
+ return newC;
+ }
+}
+
+void WindowManager::installColormap(Colormap cmap)
+{
+ if (cmap == None) {
+ XInstallColormap(m_display, m_defaultColormap);
+ } else {
+ XInstallColormap(m_display, cmap);
+ }
+}
+
+void WindowManager::clearColormapFocus()
+{
+ installColormap(None);
+}
+
+void WindowManager::clearFocus()
+{
+ static Window w = 0;
+ Client *active = activeClient();
+
+ if (!CONFIG_CLICK_TO_FOCUS) return;
+
+ if (active) {
+
+ setActiveClient(0);
+ active->deactivate();
+
+ for (Client *c = active->revertTo(); c; c = c->revertTo()) {
+ if (c->isNormal()) {
+ c->activate();
+ return;
+ }
+ }
+
+ clearColormapFocus();
+ }
+
+ if (w == 0) {
+
+ XSetWindowAttributes attr;
+ int mask = CWOverrideRedirect;
+ attr.override_redirect = 1;
+
+ w = XCreateWindow(display(), root(), 0, 0, 1, 1, 0,
+ CopyFromParent, InputOnly, CopyFromParent,
+ mask, &attr);
+
+ XMapWindow(display(), w);
+ }
+
+ XSetInputFocus(display(), w, RevertToPointerRoot, timestamp(False));
+}
+
+
+void WindowManager::skipInRevert(Client *c, Client *myRevert)
+{
+ for (int i = 0; i < m_clients.count(); ++i) {
+ if (m_clients.item(i) != c &&
+ m_clients.item(i)->revertTo() == c) {
+ m_clients.item(i)->setRevertTo(myRevert);
+ }
+ }
+}
+
+
+void WindowManager::addToHiddenList(Client *c)
+{
+ for (int i = 0; i < m_hiddenClients.count(); ++i) {
+ if (m_hiddenClients.item(i) == c) return;
+ }
+
+ m_hiddenClients.append(c);
+}
+
+
+void WindowManager::removeFromHiddenList(Client *c)
+{
+ for (int i = 0; i < m_hiddenClients.count(); ++i) {
+ if (m_hiddenClients.item(i) == c) {
+ m_hiddenClients.remove(i);
+ return;
+ }
+ }
+}
+
+
+Boolean WindowManager::raiseTransients(Client *c)
+{
+ Client *first = 0;
+
+ if (!c->isNormal()) return False;
+
+ for (int i = 0; i < m_clients.count(); ++i) {
+
+ if (m_clients.item(i)->isNormal() &&
+ m_clients.item(i)->isTransient()) {
+
+ if (c->hasWindow(m_clients.item(i)->transientFor())) {
+
+ if (!first) first = m_clients.item(i);
+ else m_clients.item(i)->mapRaised();
+ }
+ }
+ }
+
+ if (first) {
+ first->mapRaised();
+ return True;
+ } else {
+ return False;
+ }
+}
+
+#ifdef sgi
+extern "C" {
+extern int putenv(char *); /* not POSIX */
+}
+#endif
+
+void WindowManager::spawn()
+{
+ // strange code thieved from 9wm to avoid leaving zombies
+
+ char *displayName = DisplayString(m_display);
+
+ if (fork() == 0) {
+ if (fork() == 0) {
+
+ close(ConnectionNumber(m_display));
+
+ // if you don't have putenv, miss out this next
+ // conditional and its contents
+
+ if (displayName && (displayName[0] != '\0')) {
+
+ char *pstring = (char *)malloc(strlen(displayName) + 10);
+ sprintf(pstring, "DISPLAY=%s", displayName);
+ putenv(pstring);
+ free(pstring);
+ }
+
+ if (CONFIG_EXEC_USING_SHELL) {
+ execl(m_shell, m_shell, "-c", CONFIG_NEW_WINDOW_COMMAND, 0);
+ fprintf(stderr, "wm2: exec %s", m_shell);
+ perror(" failed");
+ }
+
+ execlp(CONFIG_NEW_WINDOW_COMMAND, CONFIG_NEW_WINDOW_COMMAND, 0);
+ fprintf(stderr, "wm2: exec %s", CONFIG_NEW_WINDOW_COMMAND);
+ perror(" failed");
+
+ execlp("xterm", "xterm", "-ut", 0);
+ perror("wm2: exec xterm failed");
+ exit(1);
+ }
+ exit(0);
+ }
+ wait((int *) 0);
+}
+
+
A => Manager.h +124 -0
@@ 0,0 1,124 @@
+
+#ifndef _MANAGER_H_
+#define _MANAGER_H_
+
+#include "General.h"
+#include "listmacro.h"
+
+class Client;
+declarePList(ClientList, Client);
+
+
+class WindowManager {
+public:
+ WindowManager();
+ ~WindowManager();
+
+ void clearFocus();
+ void clearColormapFocus();
+
+ void fatal(const char *);
+
+ int timestamp(Boolean reset);
+ Boolean initialising() { return m_initialising; }
+
+ // for call from Client and within:
+
+ Client *windowToClient(Window, Boolean create = False);
+ Client *selectClient(Boolean needRelease, Boolean *shift);
+ Client *activeClient() { return m_activeClient; }
+ Boolean raiseTransients(Client *); // true if raised any
+
+ void setActiveClient(Client *const c) { m_activeClient = c; }
+
+ void addToHiddenList(Client *);
+ void removeFromHiddenList(Client *);
+ void skipInRevert(Client *, Client *);
+
+ Display *display() { return m_display; }
+ Window root() { return m_root; }
+
+ enum RootCursor {
+ NormalCursor, DeleteCursor, DownCursor, RightCursor, DownrightCursor
+ };
+
+ void installCursor(RootCursor);
+ void installCursorOnWindow(RootCursor, Window);
+ void installColormap(Colormap);
+
+ // shouldn't really be public
+ int attemptGrab(Window, Window, int, int);
+ void releaseGrab(XButtonEvent *);
+ void eventExposure(XExposeEvent *); // for exposures during client grab
+ void showGeometry(int, int);
+ void removeGeometry();
+
+private:
+ int loop();
+ void release();
+
+ Display *m_display;
+ int m_screenNumber;
+
+ Window m_root;
+
+ Colormap m_defaultColormap;
+ int m_minimumColormaps;
+
+ Cursor m_cursor;
+ Cursor m_xCursor;
+ Cursor m_vCursor;
+ Cursor m_hCursor;
+ Cursor m_vhCursor;
+
+ char *m_terminal;
+ char *m_shell;
+
+ ClientList m_clients;
+ ClientList m_hiddenClients;
+ Client *m_activeClient;
+
+ int m_shapeEvent;
+ int m_currentTime;
+
+ Boolean m_looping;
+ int m_returnCode;
+
+ static Boolean m_initialising;
+ static int errorHandler(Display *, XErrorEvent *);
+ static void sigHandler();
+ static int m_signalled;
+
+ void initialiseScreen();
+ void scanInitialWindows();
+
+ GC m_menuGC;
+ Window m_menuWindow;
+ XFontStruct *m_menuFont;
+ unsigned long m_menuForegroundPixel;
+ unsigned long m_menuBackgroundPixel;
+ unsigned long m_menuBorderPixel;
+ static const char *const m_menuCreateLabel;
+ const char *const menuLabel(int);
+ void menu(XButtonEvent *);
+ void spawn();
+
+ void nextEvent(XEvent *); // return
+
+ void eventButton(XButtonEvent *);
+ void eventMapRequest(XMapRequestEvent *);
+ void eventConfigureRequest(XConfigureRequestEvent *);
+ void eventUnmap(XUnmapEvent *);
+ void eventCreate(XCreateWindowEvent *);
+ void eventDestroy(XDestroyWindowEvent *);
+ void eventClient(XClientMessageEvent *);
+ void eventColormap(XColormapEvent *);
+ void eventProperty(XPropertyEvent *);
+ void eventEnter(XCrossingEvent *);
+ void eventReparent(XReparentEvent *);
+ void eventFocusIn(XFocusInEvent *);
+ void eventShapeNotify(XShapeEvent *);
+};
+
+#endif
+
A => README +132 -0
@@ 0,0 1,132 @@
+
+wm2 -- a window manager
+=======================
+
+wm2 is a new window manager for X. It provides an unusual style of
+window decoration and as little functionality as I feel comfortable
+with in a window manager. wm2 is not configurable, except by editing
+the source and recompiling the code, and is really intended for people
+who don't particularly want their window manager to be too friendly.
+
+wm2 provides:
+
+ -- Decorative frames for your windows.
+
+ -- The ability to move, resize, hide and restore windows.
+
+ -- No icons.
+
+ -- No configurable root menus, buttons or mouse or keyboard bindings.
+
+ -- No virtual desktop, toolbars or integrated applications.
+
+
+Building wm2
+============
+
+You will need a Unix machine, X libraries and a C++ compiler such as
+gcc. You will also need a mouse, with a button. Your X server and
+libraries must be R4 or newer and must support the Shape extension.
+wm2 does NOT support multi-screen displays, because I don't have
+anything to test multi-screen code on.
+
+wm2 makes relatively heavy demands on the performance of your