wm2-4+svn20090216/0000755000131400013140000000000011146242315011461 5ustar brlbrlwm2-4+svn20090216/listmacro2.h0000644000131400013140000000323707716703355013734 0ustar brlbrl #ifndef _LISTMACRO_H_ #define _LISTMACRO_H_ #include // assumes efficient realloc() #define declarePList(List, T) \ typedef T *T##_pointer; \ declareList(List, T##_pointer); #define implementPList(List, T) \ typedef T *T##_pointer; \ implementList(List, T##_pointer); #define declareList(List, T) \ class List { \ public: \ List(); \ ~List(); \ \ long count() const { return m_count; } \ T &item(long index) const { \ assert(index >= 0 && index < m_count); \ return m_items[index]; \ } \ T *array(long index, long count) { \ return m_items + index; \ } \ \ void append(const T &); \ void remove(long index); \ void remove_all(); \ void move_to_start(long index); \ \ private: \ T *m_items; \ long m_count; \ }; #define implementList(List, T) \ \ List::List() : m_items(0), m_count(0) { } \ \ List::~List() { remove_all(); } \ \ void List::append(const T &item) { \ if (m_items) { \ m_items = (T *)realloc(m_items, (m_count + 1) * sizeof(T)); \ } else { \ m_items = (T *)malloc(sizeof(T)); \ } \ assert(m_items); \ m_items[m_count++] = (T)item; \ } \ \ void List::remove(long index) { \ assert(index >= 0 && index < m_count); \ memcpy(m_items+index, m_items+index+1, (m_count-index-1) * sizeof(T)); \ m_items = (T *)realloc(m_items, (m_count - 1) * sizeof(T)); \ --m_count; \ } \ \ void List::remove_all() { \ while (m_count > 0) remove(0); \ } \ \ void List::move_to_start(long index) { \ assert(index >= 0 && index < m_count); \ T temp = item(index); \ if (index > 0) memcpy(m_items+1, m_items, index * sizeof(T)); \ m_items[0] = temp; \ } #endif wm2-4+svn20090216/Main.C0000644000131400013140000000047607716160604012470 0ustar brlbrl #include "Manager.h" #include "Client.h" #include "Border.h" int main(int argc, char **argv) { int i; if (argc > 1) { for (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; } wm2-4+svn20090216/Client.h0000644000131400013140000000761410703436542013065 0ustar brlbrl #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(Boolean = True); void hide(); void unhide(Boolean map); void rename(); void kill(); void mapRaised(); // without activating void lower(); 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; } const char *label() { return m_label; } const char *name() { return m_name; } const char *iconName() { return m_iconName; } void sendMessage(Atom, long); void sendConfigureNotify(); void activateAndWarp(); void focusIfAppropriate(Boolean); void selectOnMotion(Window, Boolean); /* 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 eventColormap(XColormapEvent *); void eventProperty(XPropertyEvent *); void eventEnter(XCrossingEvent *); void eventFocusIn(XFocusInEvent *); void eventExposure(XExposeEvent *); protected: // cravenly submitting to gcc's warnings ~Client(); private: 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 &); Boolean coordsInHole(int, int); int m_state; int m_protocol; Boolean m_managed; Boolean m_reparenting; Boolean m_stubborn; // keeps popping itself to the front Time m_lastPopTime; 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); // 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 wm2-4+svn20090216/Manager.h0000644000131400013140000000645307716161304013222 0ustar brlbrl #ifndef _MANAGER_H_ #define _MANAGER_H_ #include "General.h" #include "listmacro2.h" class Client; declarePList(ClientList, Client); class WindowManager { public: WindowManager(); ~WindowManager(); void fatal(const char *); // for call from Client and within: Client *windowToClient(Window, Boolean create = False); Client *activeClient() { return m_activeClient; } Boolean raiseTransients(Client *); // true if raised any Time timestamp(Boolean reset); void clearFocus(); 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); unsigned long allocateColour(char *, char *); void considerFocusChange(Client *, Window, Time timestamp); void stopConsideringFocus(); // 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 circulate(Boolean activeFirst); Boolean m_focusChanging; // checking times for focus change Client *m_focusCandidate; Window m_focusCandidateWindow; Time m_focusTimestamp; // time of last crossing event Boolean m_focusPointerMoved; Boolean m_focusPointerNowStill; void checkDelaysForFocus(); 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 *); }; #endif wm2-4+svn20090216/Client.C0000644000131400013140000003647107716703355013034 0ustar brlbrl #include "Manager.h" #include "Client.h" #include 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_managed(False), m_reparenting(False), m_stubborn(False), m_lastPopTime(0L), 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()->setActiveClient(0);// 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); // zeros are iffy, should be calling some Manager method int dw = DisplayWidth(display(), 0), dh = DisplayHeight(display(), 0); 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; } if (m_w > dw - 8) m_w = dw - 8; if (m_h > dh - 8) m_h = dh - 8; if (m_x > dw - m_border->xIndent()) { m_x = dw - m_border->xIndent(); } if (m_y > dh - m_border->yIndent()) { m_y = dh - 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); m_managed = True; if (shouldHide) hide(); else { XMapWindow(d, m_window); m_border->map(); setState(NormalState); if (CONFIG_CLICK_TO_FOCUS || (m_transient != None && activeClient() && activeClient()->m_window == m_transient)) { activate(); mapRaised(); } else { deactivate(); } } if (activeClient() && !isActive()) { activeClient()->installColormap(); } if (CONFIG_AUTO_RAISE) { m_windowManager->stopConsideringFocus(); focusIfAppropriate(False); } } void Client::selectOnMotion(Window w, Boolean select) { if (!CONFIG_AUTO_RAISE) return; if (!w || w == root()) return; if (w == m_window || m_border->hasWindow(w)) { XSelectInput(display(), m_window, // not "w" ColormapChangeMask | EnterWindowMask | PropertyChangeMask | FocusChangeMask | (select ? PointerMotionMask : 0L)); } else { XSelectInput(display(), w, select ? PointerMotionMask : 0L); } } 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 (!m_managed || isHidden() || isWithdrawn()) return; if (isActive()) { decorate(True); if (CONFIG_AUTO_RAISE || 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_AUTO_RAISE || 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; } 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_managed) { 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) { if (windowManager()->windowToClient(t) == this) { fprintf(stderr, "wm2: warning: client \"%s\" thinks it's a transient " "for\nitself -- ignoring WM_TRANSIENT_FOR property...\n", m_label ? m_label : "(no name)"); m_transient = None; } else { 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 (isActive()) windowManager()->setActiveClient(0); if (isActive()) 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_AUTO_RAISE) focusIfAppropriate(False); else 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(Boolean changeState) { // fprintf(stderr,"withdrawing\n"); m_border->unmap(); gravitate(True); XReparentWindow(display(), m_window, root(), m_x, m_y); gravitate(False); if (changeState) { 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); } void Client::lower() { m_border->lower(); } wm2-4+svn20090216/Events.C0000644000131400013140000003250207716703355013051 0ustar brlbrl #include "Manager.h" #include "Client.h" int WindowManager::loop() { XEvent ev; m_looping = True; while (m_looping) { nextEvent(&ev); m_currentTime = CurrentTime; if( !m_looping ) break; 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: if (CONFIG_AUTO_RAISE && m_focusChanging) { if (!m_focusPointerMoved) m_focusPointerMoved = True; else m_focusPointerNowStill = False; } break; case FocusOut: case ConfigureNotify: case MapNotify: case MappingNotify: break; default: // if (ev.type == m_shapeEvent) eventShapeNotify((XShapeEvent *)&ev); if (ev.type == m_shapeEvent) { fprintf(stderr, "wm2: shaped windows are not supported\n"); } 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; int r; if (!m_signalled) { waiting: 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; #ifdef hpux #define select(a,b,c,d,e) select((a),(int *)(b),(c),(d),(e)) #endif if (select(fd + 1, &rfds, NULL, NULL, &t) == 1) { XNextEvent(m_display, e); return; } XFlush(m_display); FD_SET(fd, &rfds); t.tv_sec = 0; t.tv_usec = 20000; if ((r = select(fd + 1, &rfds, NULL, NULL, (m_focusChanging) ? &t : (struct timeval *)NULL)) == 1) { XNextEvent(m_display, e); return; } if (CONFIG_AUTO_RAISE && m_focusChanging) { // timeout on select checkDelaysForFocus(); } if (r == 0) goto waiting; 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::checkDelaysForFocus() { if (!CONFIG_AUTO_RAISE) return; Time t = timestamp(True); if (m_focusPointerMoved) { // only raise when pointer stops if (t < m_focusTimestamp || t - m_focusTimestamp > CONFIG_POINTER_STOPPED_DELAY) { if (m_focusPointerNowStill) { m_focusCandidate->focusIfAppropriate(True); // if (m_focusCandidate->isNormal()) m_focusCandidate->mapRaised(); // stopConsideringFocus(); } else m_focusPointerNowStill = True; // until proven false } } else { if (t < m_focusTimestamp || t - m_focusTimestamp > CONFIG_AUTO_RAISE_DELAY) { m_focusCandidate->focusIfAppropriate(True); // if (m_focusCandidate->isNormal()) m_focusCandidate->mapRaised(); // stopConsideringFocus(); } } } void WindowManager::considerFocusChange(Client *c, Window w, Time timestamp) { if (!CONFIG_AUTO_RAISE) return; if (m_focusChanging) { stopConsideringFocus(); } m_focusChanging = True; m_focusTimestamp = timestamp; m_focusCandidate = c; m_focusCandidateWindow = w; // we need to wait until at least one pointer-motion event has // come in before we can start to wonder if the pointer's // stopped moving -- otherwise we'll be caught out by all the // windows for which we don't get motion events at all m_focusPointerMoved = False; m_focusPointerNowStill = False; m_focusCandidate->selectOnMotion(m_focusCandidateWindow, True); } void WindowManager::stopConsideringFocus() { if (!CONFIG_AUTO_RAISE) return; m_focusChanging = False; if (m_focusChanging && m_focusCandidateWindow) { m_focusCandidate->selectOnMotion(m_focusCandidateWindow, False); } } void Client::focusIfAppropriate(Boolean ifActive) { if (!CONFIG_AUTO_RAISE) return; if (!m_managed || !isNormal()) return; if (!ifActive && isActive()) return; Window rw, cw; int rx, ry, cx, cy; unsigned int k; XQueryPointer(display(), root(), &rw, &cw, &rx, &ry, &cx, &cy, &k); if (hasWindow(cw)) { activate(); mapRaised(); m_windowManager->stopConsideringFocus(); } } 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_managed) { 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()) { if (CONFIG_AUTO_RAISE) { m_windowManager->stopConsideringFocus(); if (!m_stubborn) { // outstubborn stubborn windows Time popTime = windowManager()->timestamp(True); if (m_lastPopTime > 0L && popTime > m_lastPopTime && popTime - m_lastPopTime < 2000) { // 2 pops in 2 seconds m_stubborn = True; m_lastPopTime = 0L; fprintf(stderr, "wm2: client \"%s\" declared stubborn\n", label()); } else { m_lastPopTime = popTime; } mapRaised(); } } else { 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(); if (CONFIG_AUTO_RAISE) m_windowManager->stopConsideringFocus(); XAddToSaveSet(display(), m_window); XMapWindow(display(), m_window); mapRaised(); setState(NormalState); if (CONFIG_CLICK_TO_FOCUS) activate(); break; case NormalState: XMapWindow(display(), m_window); mapRaised(); if (CONFIG_CLICK_TO_FOCUS) activate(); break; case IconicState: if (CONFIG_AUTO_RAISE) m_windowManager->stopConsideringFocus(); unhide(True); break; } } void WindowManager::eventUnmap(XUnmapEvent *e) { Client *c = windowToClient(e->window); if (c) c->eventUnmap(e); } void Client::eventUnmap(XUnmapEvent *e) { 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; m_stubborn = False; } void WindowManager::eventCreate(XCreateWindowEvent *e) { if (e->override_redirect) return; windowToClient(e->window, True); } void WindowManager::eventDestroy(XDestroyWindowEvent *e) { Client *c = windowToClient(e->window); if (c) { if (CONFIG_AUTO_RAISE && m_focusChanging && c == m_focusCandidate) { m_focusChanging = False; } 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->type != EnterNotify) return; while (XCheckMaskEvent(m_display, EnterWindowMask, (XEvent *)e)); m_currentTime = e->time; // not CurrentTime Client *c = windowToClient(e->window); if (c) c->eventEnter(e); } void Client::eventEnter(XCrossingEvent *e) { // first, big checks so as not to allow focus to change "through" // the hole in the tab if (!isActive() && activeClient() && activeClient()->isNormal() && !activeClient()->isTransient()) { int x, y; Window c; XTranslateCoordinates (display(), activeClient()->parent(), e->window, 0, 0, &x, &y, &c); if (activeClient()->coordsInHole(e->x - x, e->y - y)) return; } if (e->type == EnterNotify) { if (!isActive() && !CONFIG_CLICK_TO_FOCUS) { activate(); if (CONFIG_AUTO_RAISE) { windowManager()->considerFocusChange(this, m_window, e->time); } else if (CONFIG_RAISE_ON_FOCUS) { mapRaised(); } } } } Boolean Client::coordsInHole(int x, int y) // relative to parent { return m_border->coordsInHole(x, y); } Boolean Border::coordsInHole(int x, int y) // this is all a bit of a hack { return (x > 1 && x < m_tabWidth-1 && y > 1 && y < m_tabWidth-1); } 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(); mapRaised(); } } 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); } } wm2-4+svn20090216/Buttons.C0000644000131400013140000004125307716161304013236 0ustar brlbrl #include "Manager.h" #include "Client.h" #include #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) { if (e->button == Button3) { circulate(e->window == e->root); return; } Client *c = windowToClient(e->window); if (e->window == e->root) { if (e->button == Button1) menu(e); } else if (c) { c->eventButton(e); return; } } void WindowManager::circulate(Boolean activeFirst) { Client *c = 0; if (activeFirst) c = m_activeClient; if (!c) { int i, j; if (!m_activeClient) i = -1; else { for (i = 0; i < m_clients.count(); ++i) { if (m_clients.item(i) == m_activeClient) break; } if (i >= m_clients.count()-1) i = -1; } for (j = i + 1; (!m_clients.item(j)->isNormal() || m_clients.item(j)->isTransient()); ++j) { if (j >= m_clients.count() - 1) j = -1; if (j == i) return; // no suitable clients } c = m_clients.item(j); } c->activateAndWarp(); } void Client::activateAndWarp() { mapRaised(); ensureVisible(); XWarpPointer(display(), None, parent(), 0, 0, 0, 0, m_border->xIndent() / 2, m_border->xIndent() + 8); activate(); } 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; Boolean allowExit = False; #define MENU_LABEL(n) ((n)==0 ? m_menuCreateLabel : \ (allowExit && ((n) > clients.count())) ? "[Exit wm2]" \ : 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 mx = DisplayWidth (display(), m_screenNumber) - 1; int my = DisplayHeight(display(), m_screenNumber) - 1; allowExit = ((e->x > mx-3) && (e->y > my-3)); if (allowExit) n += 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; 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 == n-1 && allowExit) { m_signalled = True; return; } 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 - TAB_TOP_HEIGHT*2 - 4; XFillRectangle(display(), m_button, m_drawGC, 0, 0, buttonSize, buttonSize); while (!done) { found = False; if (tdiff > CONFIG_DESTROY_WINDOW_DELAY && 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(); } wm2-4+svn20090216/README0000644000131400013140000001432507716703355012364 0ustar brlbrl wm2 -- a window manager ======================= wm2 is a 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. This release ============ This is the fourth release of wm2, made in March 1997. It differs in some ways from the first, second and third releases. Building wm2 ============ You will need a Unix machine, X libraries and a C++ compiler such as gcc. You will also need a mouse, with at least one 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 X server, because of the use of shaped windows, but it shouldn't place too much of a load on other aspects of your system. Inspect the file Config.h. If any of the settings (fonts, colours and "xterm" application name) in this file are unlikely to work with your system, change them. Ensure that CONFIG_NASTY_FONT is set to something which is unlikely not to be found. Edit the Makefile to suit the requirements of your system, and run "make depend" followed by "make". This should build wm2. On certain systems you may need to edit the source to overcome problems with the location of non-POSIX functions such as putenv() and select(). Using wm2 ========= To run wm2, make sure you're not already running a window manager, make sure the DISPLAY variable is correctly set, and then execute the file "wm2". There are no command-line options or X resources, and there is no start-up file. If your X server doesn't support the Shape extension, wm2 will exit (and will never work on your server); if it can't find the required fonts or allocate the required colours, it will also exit (but you should be able to fix this by changing the definitions in Config.h and recompiling). Available window manipulations are: -- To focus a window: depends on the focus policy you selected in Config.h before compiling. See "Focus policy", below. -- To raise a window: click on its tab or frame, unless you have auto-raise on focus set in Config.h. -- To move a window: make sure it's in focus, then click and drag on its tab. -- To hide a window: make sure it's in focus, then click on the button at the top of its tab. -- To recover a hidden window: click left button on the root window for the root menu, and choose the window you want. -- To start a new xterm: use the first item on root menu ("New"). -- To delete a window: make sure it's in focus, click on the button on the tab, hold the mouse button for at least a second and a half until the cursor changes to a cross, then release. (I know, it's not very easy. On the other hand, things like Windows-95 tend to obscure the fact that most windows already have a perfectly good Close option. If the default delay doesn't suit you, change it in Config.h and recompile.) -- To resize a window: make sure it's in focus, then click and drag on its bottom-right corner. For a constrained resize, click and drag on the bottom-left or top-right corner of the enclosing window frame. -- To flip around amongst the windows on-screen: click with the right mouse button on the root window or on any window's frame or tab. -- To exit from wm2: move the mouse pointer to the very edge of the screen at the extreme lower-right corner, and click left button on the root window for the root menu. The menu should have an extra option labelled "Exit wm2"; select this. All move and resize operations are opaque. Focus policy ============ Config.h contains settings for focus policy. There are three things you can define to either True or False: CONFIG_CLICK_TO_FOCUS, CONFIG_RAISE_ON_FOCUS and CONFIG_AUTO_RAISE. The first two are connected: together they define a focus policy. The third is a separate focus policy on its own and will only work if the first two are both False. CONFIG_AUTO_RAISE differs from (!CONFIG_CLICK_TO_FOCUS && CONFIG_RAISE_ON_FOCUS) only in that it provides a short delay before raising each window. The delay is also definable in Config.h. Pixmaps ======= This fourth release of wm2 no longer supports frame background pixmaps. If you want them, consider using wmx (available from the same place as wm2) instead. xterm ===== Some versions of xterm and rxvt run badly with wm2. If you use xterm and find that it refreshes the window excessively slowly, you might like to try experimenting with a different terminal emulation program. I think it might help to ensure that the scrollbar is on the right-hand side of the rxvt window and is thick enough that wmx's resize handle doesn't obscure any of the text area. Credits ======= wm2 was written by Chris Cannam, recycling a lot of code and structure from "9wm" by David Hogan (see http://www.cs.su.oz.au/~dhog/ ). 9wm is written in C, so very little of the code is used verbatim, but the intention was to reuse and a lot of the resulting code is recognisable. (Also 9wm's minimalism was rather inspiring.) I've made enough changes to make it very probable that any bugs you find will be my fault rather than David's. wm2 also uses version 2.0 of Alan Richardson's "xvertext" font-rotation routines. The sideways tabs on the window frames were Andy Green's idea. If you want to hack the code into something else for your own amusement, please go ahead. Feel free to modify and redistribute, as long as you retain the original copyrights as appropriate. Bugs ==== The principal bug is that wm2 now has too many features. That aside, if you find a bug, please report it to me (preferably with a fix). Chris Cannam, cannam@all-day-breakfast.com http://www.all-day-breakfast.com/wm2/ wm2-4+svn20090216/General.h0000644000131400013140000000235507716703355013232 0ustar brlbrl #ifndef _GENERAL_H_ #define _GENERAL_H_ #include #include #include #ifdef _POSIX_SOURCE #undef _POSIX_SOURCE #endif #ifndef __FreeBSD__ #define _POSIX_SOURCE 1 #endif #include #include #include #include #include #include #include #include #include #include #include // 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 (*)(...)) #define SIGNAL_CALLBACK_TYPE (void (*)(int)) #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 wm2-4+svn20090216/Border.C0000644000131400013140000004403007716703355013021 0ustar brlbrl #include "Border.h" #include "Client.h" #include "Manager.h" #include "Rotated.h" // These are degenerate initialisations, don't change them int Border::m_tabWidth = -1; XRotFontStruct *Border::m_tabFont = 0; GC Border::m_drawGC = 0; unsigned long Border::m_foregroundPixel; unsigned long Border::m_backgroundPixel; unsigned long Border::m_frameBackgroundPixel; unsigned long Border::m_buttonBackgroundPixel; unsigned long Border::m_borderPixel; static int borderCounter = 0; declareList(RectangleList, XRectangle); implementList(RectangleList, XRectangle); class BorderRectangleList : public RectangleList { public: BorderRectangleList() { } ~BorderRectangleList() { } void appendRect(int x, int y, int w, int h); }; void BorderRectangleList::appendRect(int x, int y, int w, int h) { XRectangle r; r.x = x; r.y = y; r.width = w; r.height = h; append(r); } Border::Border(Client *const c, Window child) : m_client(c), m_parent(0), m_tab(0), m_child(child), m_button(0), m_resize(0), m_label(0), m_prevW(-1), m_prevH(-1), m_tabHeight(-1) { m_parent = root(); if (m_tabFont == 0) { if (!(m_tabFont = XRotLoadFont(display(), CONFIG_NICE_FONT, 90.0)) && !(m_tabFont = XRotLoadFont(display(), CONFIG_NASTY_FONT, 90.0))) { windowManager()->fatal ("couldn't load default rotated font, bailing out"); } m_tabWidth = m_tabFont->height + 4; if (m_tabWidth < TAB_TOP_HEIGHT * 2 + 8) { m_tabWidth = TAB_TOP_HEIGHT * 2 + 8; } m_foregroundPixel = windowManager()->allocateColour (CONFIG_TAB_FOREGROUND, "tab foreground"); m_backgroundPixel = windowManager()->allocateColour (CONFIG_TAB_BACKGROUND, "tab background"); m_frameBackgroundPixel = windowManager()->allocateColour (CONFIG_FRAME_BACKGROUND, "frame background"); m_buttonBackgroundPixel = windowManager()->allocateColour (CONFIG_BUTTON_BACKGROUND, "button background"); m_borderPixel = windowManager()->allocateColour (CONFIG_BORDERS, "border"); XGCValues values; values.foreground = m_foregroundPixel; values.background = m_backgroundPixel; values.function = GXcopy; values.line_width = 0; values.subwindow_mode = IncludeInferiors; m_drawGC = XCreateGC(display(), root(), GCForeground | GCBackground | GCFunction | GCLineWidth | GCSubwindowMode, &values); if (!m_drawGC) { windowManager()->fatal("couldn't allocate border GC"); } } ++borderCounter; } Border::~Border() { if (m_parent != root()) { if (!m_parent) fprintf(stderr,"wm2: zero parent in Border::~Border\n"); else { XDestroyWindow(display(), m_tab); XDestroyWindow(display(), m_button); XDestroyWindow(display(), m_parent); // bad window if its parent has already gone: XDestroyWindow(display(), m_resize); } } if (m_label) free(m_label); if (--borderCounter == 0) { XFreeGC(display(), m_drawGC); } } void Border::fatal(char *s) { windowManager()->fatal(s); } Display *Border::display() { return m_client->display(); } WindowManager *Border::windowManager() { return m_client->windowManager(); } Window Border::root() { return m_client->root(); } void Border::expose(XExposeEvent *e) { if (e->window != m_tab) return; drawLabel(); } void Border::drawLabel() { if (m_label) { XClearWindow(display(), m_tab); XRotDrawString(display(), m_tabFont, m_tab, m_drawGC, 2 + m_tabFont->max_ascent, m_tabHeight - 1, m_label, strlen(m_label)); } } Boolean Border::isTransient(void) { return m_client->isTransient(); } Boolean Border::isFixedSize(void) { return m_client->isFixedSize(); } void Border::fixTabHeight(int maxHeight) { m_tabHeight = 0x7fff; maxHeight -= m_tabWidth; // for diagonal if (m_label) free(m_label); m_label = NewString(m_client->label()); if (m_label) { m_tabHeight = XRotTextWidth(m_tabFont, m_label, strlen(m_label)) + 6 + m_tabWidth; } if (m_tabHeight <= maxHeight) return; if (m_label) free(m_label); m_label = m_client->iconName() ? NewString(m_client->iconName()) : NewString("incognito"); int len = strlen(m_label); m_tabHeight = XRotTextWidth(m_tabFont, m_label, len) + 6 + m_tabWidth; if (m_tabHeight <= maxHeight) return; char *newLabel = (char *)malloc(len + 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; } void Border::shapeTransientParent(int w, int h) { XRectangle r; r.x = xIndent() - 1; r.y = yIndent() - 1; r.width = w + 2; r.height = h + 2; XShapeCombineRectangles (display(), m_parent, ShapeBounding, 0, 0, &r, 1, ShapeSet, YXBanded); r.x = xIndent(); r.y = yIndent(); r.width = w; r.height = h; XShapeCombineRectangles (display(), m_parent, ShapeClip, 0, 0, &r, 1, ShapeSet, YXBanded); } void Border::setTransientFrameVisibility(Boolean visible, int w, int h) { int i; BorderRectangleList rl; rl.appendRect(0, 0, w + 1, yIndent() - 1); for (i = 1; i < yIndent(); ++i) { rl.appendRect(w + 1, i - 1, i + 1, 1); } rl.appendRect(0, yIndent() - 1, xIndent() - 1, h - yIndent() + 2); for (i = 1; i < yIndent(); ++i) { rl.appendRect(i - 1, h, 1, i + 2); } XShapeCombineRectangles (display(), m_parent, ShapeBounding, 0, 0, rl.array(0, rl.count()), rl.count(), visible ? ShapeUnion : ShapeSubtract, YXSorted); rl.remove_all(); rl.appendRect(1, 1, w, yIndent() - 2); for (i = 2; i < yIndent(); ++i) { rl.appendRect(w + 1, i - 1, i, 1); } rl.appendRect(1, yIndent() - 1, xIndent() - 2, h - yIndent() + 1); for (i = 2; i < yIndent(); ++i) { rl.appendRect(i - 1, h, 1, i + 1); } XShapeCombineRectangles (display(), m_parent, ShapeClip, 0, 0, rl.array(0, rl.count()), rl.count(), visible ? ShapeUnion : ShapeSubtract, YXSorted); } void Border::shapeParent(int w, int h) { int i; int mainRect; BorderRectangleList rl; if (isTransient()) { shapeTransientParent(w, h); return; } // Bounding rectangles -- clipping will be the same except for // child window border // top of tab rl.appendRect(0, 0, w + m_tabWidth + 1, TAB_TOP_HEIGHT + 2); // struts in tab, left... rl.appendRect(0, TAB_TOP_HEIGHT + 1, TAB_TOP_HEIGHT + 2, m_tabWidth - TAB_TOP_HEIGHT*2 - 1); // ...and right rl.appendRect(m_tabWidth - TAB_TOP_HEIGHT, TAB_TOP_HEIGHT + 1, TAB_TOP_HEIGHT + 2, m_tabWidth - TAB_TOP_HEIGHT*2 - 1); mainRect = rl.count(); rl.appendRect(xIndent() - 1, yIndent() - 1, w + 2, h + 2); // main tab rl.appendRect(0, m_tabWidth - TAB_TOP_HEIGHT, m_tabWidth + 2, m_tabHeight - m_tabWidth + TAB_TOP_HEIGHT); // diagonal for (i = 1; i < m_tabWidth - 1; ++i) { rl.appendRect(i, m_tabHeight + i - 1, m_tabWidth - i + 2, 1); } XShapeCombineRectangles (display(), m_parent, ShapeBounding, 0, 0, rl.array(0, rl.count()), rl.count(), ShapeSet, YXSorted); rl.item(mainRect).x ++; rl.item(mainRect).y ++; rl.item(mainRect).width -= 2; rl.item(mainRect).height -= 2; XShapeCombineRectangles (display(), m_parent, ShapeClip, 0, 0, rl.array(0, rl.count()), rl.count(), ShapeSet, YXSorted); } void Border::shapeTab(int w, int) { int i; BorderRectangleList rl; if (isTransient()) { return; } // Bounding rectangles rl.appendRect(0, 0, w + m_tabWidth + 1, TAB_TOP_HEIGHT + 2); rl.appendRect(0, TAB_TOP_HEIGHT + 1, TAB_TOP_HEIGHT + 2, m_tabWidth - TAB_TOP_HEIGHT*2 - 1); rl.appendRect(m_tabWidth - TAB_TOP_HEIGHT, TAB_TOP_HEIGHT + 1, TAB_TOP_HEIGHT + 2, m_tabWidth - TAB_TOP_HEIGHT*2 - 1); rl.appendRect(0, m_tabWidth - TAB_TOP_HEIGHT, m_tabWidth + 2, m_tabHeight - m_tabWidth + TAB_TOP_HEIGHT); for (i = 1; i < m_tabWidth - 1; ++i) { rl.appendRect(i, m_tabHeight + i - 1, m_tabWidth - i + 2, 1); } XShapeCombineRectangles (display(), m_tab, ShapeBounding, 0, 0, rl.array(0, rl.count()), rl.count(), ShapeSet, YXSorted); rl.remove_all(); // Clipping rectangles rl.appendRect(1, 1, w + m_tabWidth - 1, TAB_TOP_HEIGHT); rl.appendRect(1, TAB_TOP_HEIGHT + 1, TAB_TOP_HEIGHT, m_tabWidth + TAB_TOP_HEIGHT*2 - 1); rl.appendRect(m_tabWidth - TAB_TOP_HEIGHT + 1, TAB_TOP_HEIGHT + 1, TAB_TOP_HEIGHT, m_tabWidth + TAB_TOP_HEIGHT*2 - 1); rl.appendRect(1, m_tabWidth - TAB_TOP_HEIGHT + 1, m_tabWidth, m_tabHeight - m_tabWidth + TAB_TOP_HEIGHT - 1); for (i = 1; i < m_tabWidth - 2; ++i) { rl.appendRect(i + 1, m_tabHeight + i - 1, m_tabWidth - i, 1); } XShapeCombineRectangles (display(), m_tab, ShapeClip, 0, 0, rl.array(0, rl.count()), rl.count(), ShapeSet, YXSorted); } void Border::resizeTab(int h) { int i; XRectangle r; BorderRectangleList rl; int shorter, longer, operation; if (isTransient()) { return; } int prevTabHeight = m_tabHeight; fixTabHeight(h); if (m_tabHeight == prevTabHeight) return; XWindowChanges wc; wc.height = m_tabHeight + 2 + m_tabWidth; XConfigureWindow(display(), m_tab, CWHeight, &wc); if (m_tabHeight > prevTabHeight) { shorter = prevTabHeight; longer = m_tabHeight; operation = ShapeUnion; } else { shorter = m_tabHeight; longer = prevTabHeight + m_tabWidth; operation = ShapeSubtract; } r.x = 0; r.y = shorter /*- 2*/; r.width = m_tabWidth + 2; r.height = longer - shorter; XShapeCombineRectangles(display(), m_parent, ShapeBounding, 0, 0, &r, 1, operation, YXBanded); XShapeCombineRectangles(display(), m_parent, ShapeClip, 0, 0, &r, 1, operation, YXBanded); XShapeCombineRectangles(display(), m_tab, ShapeBounding, 0, 0, &r, 1, operation, YXBanded); r.x ++; r.width -= 2; XShapeCombineRectangles(display(), m_tab, ShapeClip, 0, 0, &r, 1, operation, YXBanded); if (m_client->isActive()) { // restore a bit of the frame edge r.x = m_tabWidth + 1; r.y = shorter; r.width = FRAME_WIDTH - 1; r.height = longer - shorter; XShapeCombineRectangles(display(), m_parent, ShapeBounding, 0, 0, &r, 1, ShapeUnion, YXBanded); } for (i = 1; i < m_tabWidth - 1; ++i) { rl.appendRect(i, m_tabHeight + i - 1, m_tabWidth - i + 2, 1); } XShapeCombineRectangles (display(), m_parent, ShapeBounding, 0, 0, rl.array(0, rl.count()), rl.count(), ShapeUnion, YXBanded); XShapeCombineRectangles (display(), m_parent, ShapeClip, 0, 0, rl.array(0, rl.count()), rl.count(), ShapeUnion, YXBanded); XShapeCombineRectangles (display(), m_tab, ShapeBounding, 0, 0, rl.array(0, rl.count()), rl.count(), ShapeUnion, YXBanded); if (rl.count() < 2) return; for (i = 0; i < rl.count() - 1; ++i) { rl.item(i).x ++; rl.item(i).width -= 2; } XShapeCombineRectangles (display(), m_tab, ShapeClip, 0, 0, rl.array(0, rl.count() - 1), rl.count() - 1, ShapeUnion, YXBanded); } void Border::shapeResize() { int i; BorderRectangleList rl; for (i = 0; i < FRAME_WIDTH*2; ++i) { rl.appendRect(FRAME_WIDTH*2 - i - 1, i, i + 1, 1); } XShapeCombineRectangles (display(), m_resize, ShapeBounding, 0, 0, rl.array(0, rl.count()), rl.count(), ShapeSet, YXBanded); rl.remove_all(); for (i = 1; i < FRAME_WIDTH*2; ++i) { rl.appendRect(FRAME_WIDTH*2 - i, i, i, 1); } XShapeCombineRectangles (display(), m_resize, ShapeClip, 0, 0, rl.array(0, rl.count()), rl.count(), ShapeSet, YXBanded); rl.remove_all(); for (i = 0; i < FRAME_WIDTH*2 - 3; ++i) { rl.appendRect(FRAME_WIDTH*2 - i - 1, i + 3, 1, 1); } XShapeCombineRectangles (display(), m_resize, ShapeClip, 0, 0, rl.array(0, rl.count()), rl.count(), ShapeSubtract, YXBanded); windowManager()->installCursorOnWindow (WindowManager::DownrightCursor, m_resize); } void Border::setFrameVisibility(Boolean visible, int w, int h) { BorderRectangleList rl; if (CONFIG_PROD_SHAPE) { shapeParent(w, h); shapeTab(w, h); } if (isTransient()) { setTransientFrameVisibility(visible, w, h); return; } // Bounding rectangles rl.appendRect(m_tabWidth + w + 1, 0, FRAME_WIDTH + 1, FRAME_WIDTH); rl.appendRect(m_tabWidth + 2, TAB_TOP_HEIGHT + 2, w, FRAME_WIDTH - TAB_TOP_HEIGHT - 2); // for button int ww = m_tabWidth - TAB_TOP_HEIGHT*2 - 4; rl.appendRect((m_tabWidth + 2 - ww) / 2, (m_tabWidth+2 - ww) / 2, ww, ww); rl.appendRect(m_tabWidth + 2, FRAME_WIDTH, FRAME_WIDTH - 2, m_tabHeight + m_tabWidth - FRAME_WIDTH - 2); // swap last two if sorted wrong if (rl.item(rl.count()-2).y > rl.item(rl.count()-1).y) { rl.append(rl.item(rl.count()-2)); rl.remove(rl.count()-3); } int final = rl.count(); rl.append(rl.item(final-1)); rl.item(final).x -= 1; rl.item(final).y += rl.item(final).height; rl.item(final).width += 1; rl.item(final).height = h - rl.item(final).height + 2; XShapeCombineRectangles(display(), m_parent, ShapeBounding, 0, 0, rl.array(0, rl.count()), rl.count(), visible ? ShapeUnion : ShapeSubtract, YXSorted); rl.remove_all(); // Clip rectangles rl.appendRect(m_tabWidth + w + 1, 1, FRAME_WIDTH, FRAME_WIDTH - 1); rl.appendRect(m_tabWidth + 2, TAB_TOP_HEIGHT + 2, w, FRAME_WIDTH - TAB_TOP_HEIGHT - 2); // for button ww = m_tabWidth - TAB_TOP_HEIGHT*2 - 6; rl.appendRect((m_tabWidth + 2 - ww) / 2, (m_tabWidth+2 - ww) / 2, ww, ww); rl.appendRect(m_tabWidth + 2, FRAME_WIDTH, FRAME_WIDTH - 2, h - FRAME_WIDTH); // swap last two if sorted wrong if (rl.item(rl.count()-2).y > rl.item(rl.count()-1).y) { rl.append(rl.item(rl.count()-2)); rl.remove(rl.count()-3); } rl.appendRect(m_tabWidth + 2, h, FRAME_WIDTH - 2, FRAME_WIDTH + 1); XShapeCombineRectangles(display(), m_parent, ShapeClip, 0, 0, rl.array(0, rl.count()), rl.count(), visible ? ShapeUnion : ShapeSubtract, YXSorted); rl.remove_all(); if (visible && !isFixedSize()) { XMapRaised(display(), m_resize); } else { XUnmapWindow(display(), m_resize); } } void Border::configure(int x, int y, int w, int h, unsigned long mask, int detail, Boolean force) // must reshape everything { if (!m_parent || m_parent == root()) { // create windows, then shape them afterwards m_parent = XCreateSimpleWindow (display(), root(), 1, 1, 1, 1, 0, m_borderPixel, m_frameBackgroundPixel); m_tab = XCreateSimpleWindow (display(), m_parent, 1, 1, 1, 1, 0, m_borderPixel, m_backgroundPixel); m_button = XCreateSimpleWindow (display(), m_parent, 1, 1, 1, 1, 0, m_borderPixel, m_buttonBackgroundPixel); m_resize = XCreateWindow (display(), m_child, 1, 1, FRAME_WIDTH*2, FRAME_WIDTH*2, 0, CopyFromParent, InputOutput, CopyFromParent, 0L, 0); shapeResize(); XSelectInput(display(), m_parent, SubstructureRedirectMask | SubstructureNotifyMask | ButtonPressMask | ButtonReleaseMask); if (!isTransient()) { XSelectInput(display(), m_tab, ExposureMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask/* | LeaveWindowMask*/); } XSelectInput(display(), m_button, ButtonPressMask | ButtonReleaseMask/* | LeaveWindowMask*/); XSelectInput(display(), m_resize, ButtonPressMask | ButtonReleaseMask); mask |= CWX | CWY | CWWidth | CWHeight | CWBorderWidth; } XWindowChanges wc; wc.x = x - xIndent(); wc.y = y - yIndent(); wc.width = w + xIndent() + 1; wc.height = h + yIndent() + 1; wc.border_width = 0; wc.sibling = None; wc.stack_mode = detail; XConfigureWindow(display(), m_parent, mask, &wc); unsigned long rmask = 0L; if (mask & CWWidth) rmask |= CWX; if (mask & CWHeight) rmask |= CWY; wc.x = w - FRAME_WIDTH*2; wc.y = h - FRAME_WIDTH*2; XConfigureWindow(display(), m_resize, rmask, &wc); if (force || (m_prevW < 0 || m_prevH < 0) || ((mask & (CWWidth | CWHeight)) && (w != m_prevW || h != m_prevH))) { int prevTabHeight = m_tabHeight; if (isTransient()) m_tabHeight = 10; // arbitrary else fixTabHeight(h); shapeParent(w, h); setFrameVisibility(m_client->isActive(), w, h); if (force || w != m_prevW || prevTabHeight != m_tabHeight || m_prevW < 0 || m_prevH < 0) { wc.x = 0; wc.y = 0; wc.width = w + xIndent(); wc.height = m_tabHeight + 2 + m_tabWidth; XConfigureWindow(display(), m_tab, mask, &wc); shapeTab(w, h); } m_prevW = w; m_prevH = h; } else { resizeTab(h); } wc.x = TAB_TOP_HEIGHT + 2; wc.y = wc.x; wc.width = wc.height = m_tabWidth - TAB_TOP_HEIGHT*2 - 4; XConfigureWindow(display(), m_button, mask, &wc); } void Border::moveTo(int x, int y) { XWindowChanges wc; wc.x = x - xIndent(); wc.y = y - yIndent(); XConfigureWindow(display(), m_parent, CWX | CWY, &wc); } void Border::map() { if (m_parent == root()) { fprintf(stderr, "wm2: bad parent in Border::map()\n"); } else { XMapWindow(display(), m_parent); if (!isTransient()) { XMapWindow(display(), m_tab); XMapWindow(display(), m_button); if (!isFixedSize()) XMapWindow(display(), m_resize); } } } void Border::mapRaised() { if (m_parent == root()) { fprintf(stderr, "wm2: bad parent in Border::mapRaised()\n"); } else { XMapRaised(display(), m_parent); if (!isTransient()) { XMapWindow(display(), m_tab); XMapRaised(display(), m_button); if (!isFixedSize()) XMapRaised(display(), m_resize); } } } void Border::lower() { XLowerWindow(display(), m_parent); } void Border::unmap() { if (m_parent == root()) { fprintf(stderr, "wm2: bad parent in Border::unmap()\n"); } else { XUnmapWindow(display(), m_parent); if (!isTransient()) { XUnmapWindow(display(), m_tab); XUnmapWindow(display(), m_button); // XUnmapWindow(display(), m_resize); // no, will unmap with parent } } } void Border::decorate(Boolean active, int w, int h) { setFrameVisibility(active, w, h); } void Border::reparent() { XReparentWindow(display(), m_child, m_parent, xIndent(), yIndent()); } wm2-4+svn20090216/Config.h0000644000131400013140000000350507716161304013050 0ustar brlbrl #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" #define CONFIG_EVERYTHING_ON_ROOT_MENU False // You can't have CLICK_TO_FOCUS without RAISE_ON_FOCUS but the other // combinations should be okay. If you set AUTO_RAISE you must leave // the other two False; you'll then get focus-follows, auto-raise, and // a delay on auto-raise as configured in the DELAY settings below. #define CONFIG_CLICK_TO_FOCUS False #define CONFIG_RAISE_ON_FOCUS False #define CONFIG_AUTO_RAISE False // milliseconds. In theory these only apply when using AUTO_RAISE, // not when just using RAISE_ON_FOCUS without CLICK_TO_FOCUS. First // of these is the usual delay before raising; second is the delay // after the pointer has stopped moving (only applicable over simple X // windows such as xvt). #define CONFIG_AUTO_RAISE_DELAY 400 #define CONFIG_POINTER_STOPPED_DELAY 80 #define CONFIG_DESTROY_WINDOW_DELAY 1500L #define CONFIG_TAB_FOREGROUND "black" #define CONFIG_TAB_BACKGROUND "gray80" #define CONFIG_FRAME_BACKGROUND "gray95" #define CONFIG_BUTTON_BACKGROUND "gray95" #define CONFIG_BORDERS "black" #define CONFIG_MENU_FOREGROUND "black" #define CONFIG_MENU_BACKGROUND "gray80" #define CONFIG_MENU_BORDERS "black" #define CONFIG_FRAME_THICKNESS 7 // If CONFIG_PROD_SHAPE is True, all frame element shapes will be // recalculated afresh every time their focus changes. This will // probably slow things down hideously, but has been reported as // necessary on some systems (possibly SunOS 4.x with OpenWindows). #define CONFIG_PROD_SHAPE False #endif wm2-4+svn20090216/Border.h0000644000131400013140000000475507716161304013070 0ustar brlbrl #ifndef _BORDER_H_ #define _BORDER_H_ #include "General.h" #include "Rotated.h" class Client; class WindowManager; // These distances exclude the 1-pixel borders. You could probably // change these a certain amount before breaking the shoddy code in // the rest of this file. #define TAB_TOP_HEIGHT 2 #define FRAME_WIDTH CONFIG_FRAME_THICKNESS #define TRANSIENT_FRAME_WIDTH 4 // NB frameTopHeight = frameHeight-tabTopHeight class Border { // friend of client public: Border(Client *const, Window child); ~Border(); void map(); void unmap(); void lower(); 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() ? TRANSIENT_FRAME_WIDTH + 1 : FRAME_WIDTH + 1; } int xIndent() { return isTransient() ? TRANSIENT_FRAME_WIDTH + 1 : m_tabWidth + FRAME_WIDTH + 1; } Boolean coordsInHole(int, int); // in Events.C of all places 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 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 wm2-4+svn20090216/Rotated.h0000644000131400013140000000417307716160340013246 0ustar brlbrl/* ************************************************************************ */ /* Header file for the `xvertext' routines. Copyright (c) 1992 Alan Richardson (mppa3@uk.ac.sussex.syma) */ /* ************************************************************************ */ #ifndef _XVERTEXT_INCLUDED_ #define _XVERTEXT_INCLUDED_ #define XV_VERSION 2.0 #define XV_COPYRIGHT "xvertext routines Copyright (c) 1992 Alan Richardson" /* ---------------------------------------------------------------------- */ /* *** The font structures *** */ struct BitmapStruct { int bit_w; int bit_h; Pixmap bm; }; struct XRotCharStruct { int ascent; int descent; int lbearing; int rbearing; int width; BitmapStruct glyph; }; struct XRotFontStruct { int dir; int height; int max_ascent; int max_descent; int max_char; int min_char; char *name; XFontStruct *xfontstruct; XRotCharStruct per_char[95]; }; /* ---------------------------------------------------------------------- */ extern float XRotVersion(char *, int); extern XRotFontStruct *XRotLoadFont(Display *, char *, float); extern void XRotUnloadFont(Display *, XRotFontStruct *); extern int XRotTextWidth(XRotFontStruct *, char *, int); extern void XRotDrawString(Display *, XRotFontStruct *, Drawable, GC, int, int, char *, int); extern void XRotDrawAlignedString(Display *, XRotFontStruct *, Drawable, GC, int, int, char *, int); /* ---------------------------------------------------------------------- */ #define TLEFT 1 #define TCENTRE 2 #define TRIGHT 3 #define MLEFT 4 #define MCENTRE 5 #define MRIGHT 6 #define BLEFT 7 #define BCENTRE 8 #define BRIGHT 9 /* ---------------------------------------------------------------------- */ extern int xv_errno; #define XV_NOFONT 1 /* no such font on X server */ #define XV_NOMEM 2 /* couldn't do malloc */ #define XV_NOXIMAGE 3 /* couldn't create an XImage */ /* ---------------------------------------------------------------------- */ #else extern int xv_errno; #endif wm2-4+svn20090216/Cursors.h0000644000131400013140000000664407716160340013311 0ustar brlbrl #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 wm2-4+svn20090216/Makefile0000644000131400013140000000065707716704661013150 0ustar brlbrl LIBS = -L/usr/X11R6/lib -lXext -lX11 -lXt -lXmu -lSM -lICE -lm INCS = -I/usr/X11R6/include CC = gcc CCC = g++ CFLAGS = -O2 -Wall $(INCS) OBJECTS = Border.o Buttons.o Client.o Events.o Main.o Manager.o Rotated.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 core distclean: clean rm -f wm2 wm2.old *~ wm2-4+svn20090216/Rotated.C0000644000131400013140000004023307716703355013207 0ustar brlbrl/* ********************************************************************** */ /* xvertext, Copyright (c) 1992 Alan Richardson (mppa3@uk.ac.sussex.syma) * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both the * copyright notice and this permission notice appear in supporting * documentation. All work developed as a consequence of the use of * this program should duly acknowledge such use. No representations are * made about the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty. */ /* ********************************************************************** */ #include #include #include #include #include #include "Rotated.h" /* ---------------------------------------------------------------------- */ int xv_errno; static char *my_strdup(char *); static char *my_strtok(char *, char *); /* ---------------------------------------------------------------------- */ /* *** Routine to mimic `strdup()' (some machines don't have it) *** */ static char *my_strdup(char *str) { char *s; if (str == NULL) return NULL; s = (char *)malloc((unsigned)(strlen(str)+1)); /* this error is highly unlikely ... */ if (s == NULL) { fprintf(stderr, "Fatal error: my_strdup(): Couldn't do malloc (gulp!)\n"); exit(1); } strcpy(s, str); return s; } /* ---------------------------------------------------------------------- */ /* *** Routine to replace `strtok' : this one returns a zero length string if it encounters two consecutive delimiters *** */ static char *my_strtok(char *str1, char *str2) { char *ret; size_t i, j, stop; static size_t start, len; static char *stext; /* this error should never occur ... */ if (str2 == NULL) { fprintf(stderr, "Fatal error: my_strtok(): recieved null delimiter string\n"); exit(1); } /* initialise if str1 not NULL ... */ if (str1 != NULL) { start = 0; stext = str1; len = strlen(str1); } /* run out of tokens ? ... */ if (start >= len) return NULL; /* loop through characters ... */ for (i = start; i < len; i++) { /* loop through delimiters ... */ stop = 0; for (j = 0; j < strlen(str2); j++) if (stext[i] == str2[j]) stop = 1; if (stop) break; } stext[i] = '\0'; ret = stext + start; start = i+1; return ret; } /* ---------------------------------------------------------------------- */ /* *** Routine to return version/copyright information *** */ float XRotVersion(char *str, int n) { if (str != NULL) strncpy(str, XV_COPYRIGHT, n); return XV_VERSION; } /* ---------------------------------------------------------------------- */ /* *** Load the rotated version of a given font *** */ XRotFontStruct *XRotLoadFont(Display *dpy, char *fontname, float angle) { char val; XImage *I1, *I2; Pixmap canvas; Window root; int screen; GC font_gc; char text[3];/*, errstr[300];*/ XFontStruct *fontstruct; XRotFontStruct *rotfont; int ichar, i, j, index, boxlen = 60, dir; int vert_w, vert_h, vert_len, bit_w, bit_h, bit_len; int min_char, max_char; unsigned char *vertdata, *bitdata; int ascent, descent, lbearing, rbearing; int on = 1, off = 0; /* make angle positive ... */ if (angle < 0) do angle += 360; while (angle < 0); /* get nearest vertical or horizontal direction ... */ dir = (int)((angle+45.)/90.)%4; /* useful macros ... */ screen = DefaultScreen(dpy); root = DefaultRootWindow(dpy); /* create the depth 1 canvas bitmap ... */ canvas = XCreatePixmap(dpy, root, boxlen, boxlen, 1); /* create a GC ... */ font_gc = XCreateGC(dpy, canvas, 0, 0); XSetBackground(dpy, font_gc, off); /* load the font ... */ fontstruct = XLoadQueryFont(dpy, fontname); if (fontstruct == NULL) { xv_errno = XV_NOFONT; return NULL; } XSetFont(dpy, font_gc, fontstruct->fid); /* allocate space for rotated font ... */ rotfont = (XRotFontStruct *)malloc((unsigned)sizeof(XRotFontStruct)); if (rotfont == NULL) { xv_errno = XV_NOMEM; return NULL; } /* determine which characters are defined in font ... */ min_char = fontstruct->min_char_or_byte2; max_char = fontstruct->max_char_or_byte2; /* we only want printing characters ... */ if (min_char<32) min_char = 32; if (max_char>126) max_char = 126; /* some overall font data ... */ rotfont->name = my_strdup(fontname); rotfont->dir = dir; rotfont->min_char = min_char; rotfont->max_char = max_char; rotfont->max_ascent = fontstruct->max_bounds.ascent; rotfont->max_descent = fontstruct->max_bounds.descent; rotfont->height = rotfont->max_ascent+rotfont->max_descent; /* remember xfontstruct for `normal' text ... */ if (dir == 0) rotfont->xfontstruct = fontstruct; else { /* font needs rotation ... */ /* loop through each character ... */ for (ichar = min_char; ichar <= max_char; ichar++) { index = ichar-fontstruct->min_char_or_byte2; /* per char dimensions ... */ ascent = rotfont->per_char[ichar-32].ascent = fontstruct->per_char[index].ascent; descent = rotfont->per_char[ichar-32].descent = fontstruct->per_char[index].descent; lbearing = rotfont->per_char[ichar-32].lbearing = fontstruct->per_char[index].lbearing; rbearing = rotfont->per_char[ichar-32].rbearing = fontstruct->per_char[index].rbearing; rotfont->per_char[ichar-32].width = fontstruct->per_char[index].width; /* some space chars have zero body, but a bitmap can't have ... */ if (!ascent && !descent) ascent = rotfont->per_char[ichar-32].ascent = 1; if (!lbearing && !rbearing) rbearing = rotfont->per_char[ichar-32].rbearing = 1; /* glyph width and height when vertical ... */ vert_w = rbearing-lbearing; vert_h = ascent+descent; /* width in bytes ... */ vert_len = (vert_w-1)/8+1; XSetForeground(dpy, font_gc, off); XFillRectangle(dpy, canvas, font_gc, 0, 0, boxlen, boxlen); /* draw the character centre top right on canvas ... */ sprintf(text, "%c", ichar); XSetForeground(dpy, font_gc, on); XDrawImageString(dpy, canvas, font_gc, boxlen/2 - lbearing, boxlen/2 - descent, text, 1); /* reserve memory for first XImage ... */ vertdata = (unsigned char *) malloc((unsigned)(vert_len*vert_h)); if (vertdata == NULL) { xv_errno = XV_NOMEM; return NULL; } /* create the XImage ... */ I1 = XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap, 0, (char *)vertdata, vert_w, vert_h, 8, 0); if (I1 == NULL) { xv_errno = XV_NOXIMAGE; return NULL; } I1->byte_order = I1->bitmap_bit_order = MSBFirst; /* extract character from canvas ... */ XGetSubImage(dpy, canvas, boxlen/2, boxlen/2-vert_h, vert_w, vert_h, 1, XYPixmap, I1, 0, 0); I1->format = XYBitmap; /* width, height of rotated character ... */ if (dir == 2) { bit_w = vert_w; bit_h = vert_h; } else { bit_w = vert_h; bit_h = vert_w; } /* width in bytes ... */ bit_len = (bit_w-1)/8 + 1; rotfont->per_char[ichar-32].glyph.bit_w = bit_w; rotfont->per_char[ichar-32].glyph.bit_h = bit_h; /* reserve memory for the rotated image ... */ bitdata = (unsigned char *)calloc((unsigned)(bit_h*bit_len), 1); if (bitdata == NULL) { xv_errno = XV_NOMEM; return NULL; } /* create the image ... */ I2 = XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap, 0, (char *)bitdata, bit_w, bit_h, 8, 0); if (I2 == NULL) { xv_errno = XV_NOXIMAGE; return NULL; } I2->byte_order = I2->bitmap_bit_order = MSBFirst; /* map vertical data to rotated character ... */ for (j = 0; j < bit_h; j++) { for (i = 0; i < bit_w; i++) { /* map bits ... */ if (dir == 1) val = vertdata[i*vert_len + (vert_w-j-1)/8] & (128>>((vert_w-j-1)%8)); else if (dir == 2) val = vertdata[(vert_h-j-1)*vert_len + (vert_w-i-1)/8] & (128>>((vert_w-i-1)%8)); else val = vertdata[(vert_h-i-1)*vert_len + j/8] & (128>>(j%8)); if (val) bitdata[j*bit_len + i/8] = bitdata[j*bit_len + i/8] | (128>>(i%8)); } } /* create this character's bitmap ... */ rotfont->per_char[ichar-32].glyph.bm = XCreatePixmap(dpy, root, bit_w, bit_h, 1); /* put the image into the bitmap ... */ XPutImage(dpy, rotfont->per_char[ichar-32].glyph.bm, font_gc, I2, 0, 0, 0, 0, bit_w, bit_h); /* free the image and data ... */ XDestroyImage(I1); XDestroyImage(I2); /* free((char *)bitdata); -- XDestroyImage does this free((char *)vertdata);*/ } XFreeFont(dpy, fontstruct); } /* free pixmap and GC ... */ XFreePixmap(dpy, canvas); XFreeGC(dpy, font_gc); return rotfont; } /* ---------------------------------------------------------------------- */ /* *** Free the resources associated with a rotated font *** */ void XRotUnloadFont(Display *dpy, XRotFontStruct *rotfont) { int ichar; if (rotfont->dir == 0) XFreeFont(dpy, rotfont->xfontstruct); else /* loop through each character, freeing its pixmap ... */ for (ichar = rotfont->min_char-32; ichar <= rotfont->max_char-32; ichar++) XFreePixmap(dpy, rotfont->per_char[ichar].glyph.bm); /* rotfont should never be referenced again ... */ free((char *)rotfont->name); free((char *)rotfont); } /* ---------------------------------------------------------------------- */ /* *** Return the width of a string *** */ int XRotTextWidth(XRotFontStruct *rotfont, char *str, int len) { int i, width = 0, ichar; if (str == NULL) return 0; if (rotfont->dir == 0) width = XTextWidth(rotfont->xfontstruct, str, strlen(str)); else for (i = 0; i= 0 && ichar<95) width += rotfont->per_char[ichar].width; } return width; } /* ---------------------------------------------------------------------- */ /* *** A front end to XRotPaintString : mimics XDrawString *** */ void XRotDrawString(Display *dpy, XRotFontStruct *rotfont, Drawable drawable, GC gc, int x, int y, char *str, int len) { static GC my_gc = 0; int i, xp, yp, dir, ichar; if (str == NULL || len<1) return; dir = rotfont->dir; if (my_gc == 0) my_gc = XCreateGC(dpy, drawable, 0, 0); XCopyGC(dpy, gc, GCForeground|GCBackground, my_gc); /* a horizontal string is easy ... */ if (dir == 0) { XSetFillStyle(dpy, my_gc, FillSolid); XSetFont(dpy, my_gc, rotfont->xfontstruct->fid); XDrawString(dpy, drawable, my_gc, x, y, str, len); return; } /* vertical or upside down ... */ XSetFillStyle(dpy, my_gc, FillStippled); /* loop through each character in string ... */ for (i = 0; i= 0 && ichar<95) { /* suitable offset ... */ if (dir == 1) { xp = x-rotfont->per_char[ichar].ascent; yp = y-rotfont->per_char[ichar].rbearing; } else if (dir == 2) { xp = x-rotfont->per_char[ichar].rbearing; yp = y-rotfont->per_char[ichar].descent+1; } else { xp = x-rotfont->per_char[ichar].descent+1; yp = y+rotfont->per_char[ichar].lbearing; } /* draw the glyph ... */ XSetStipple(dpy, my_gc, rotfont->per_char[ichar].glyph.bm); XSetTSOrigin(dpy, my_gc, xp, yp); XFillRectangle(dpy, drawable, my_gc, xp, yp, rotfont->per_char[ichar].glyph.bit_w, rotfont->per_char[ichar].glyph.bit_h); /* advance position ... */ if (dir == 1) y -= rotfont->per_char[ichar].width; else if (dir == 2) x -= rotfont->per_char[ichar].width; else y += rotfont->per_char[ichar].width; } } } /* ---------------------------------------------------------------------- */ /* *** A front end to XRotPaintAlignedString : uses XRotDrawString *** */ void XRotDrawAlignedString(Display *dpy, XRotFontStruct *rotfont, Drawable drawable, GC gc, int x, int y, char *text, int align) { int xp = 0, yp = 0, dir; size_t i; int nl = 1, max_width = 0, this_width; char *str1, *str2 = "\n\0", *str3; if (text == NULL) return; dir = rotfont->dir; /* count number of sections in string ... */ for (i = 0; imax_width) max_width = XRotTextWidth(rotfont, str3, strlen(str3)); } while (str3 != NULL); /* calculate vertical starting point according to alignment policy and rotation angle ... */ if (dir == 0) { if (align == TLEFT || align == TCENTRE || align == TRIGHT) yp = y+rotfont->max_ascent; else if (align == BLEFT || align == BCENTRE || align == BRIGHT) yp = y-(nl-1)*rotfont->height - rotfont->max_descent; else yp = y-(nl-1)/2*rotfont->height + rotfont->max_ascent - rotfont->height/2 - ((nl%2 == 0)?rotfont->height/2:0); } else if (dir == 1) { if (align == TLEFT || align == TCENTRE || align == TRIGHT) xp = x+rotfont->max_ascent; else if (align == BLEFT || align == BCENTRE || align == BRIGHT) xp = x-(nl-1)*rotfont->height - rotfont->max_descent; else xp = x-(nl-1)/2*rotfont->height + rotfont->max_ascent - rotfont->height/2 - ((nl%2 == 0)?rotfont->height/2:0); } else if (dir == 2) { if (align == TLEFT || align == TCENTRE || align == TRIGHT) yp = y-rotfont->max_ascent; else if (align == BLEFT || align == BCENTRE || align == BRIGHT) yp = y+(nl-1)*rotfont->height + rotfont->max_descent; else yp = y+(nl-1)/2*rotfont->height - rotfont->max_ascent + rotfont->height/2 + ((nl%2 == 0)?rotfont->height/2:0); } else { if (align == TLEFT || align == TCENTRE || align == TRIGHT) xp = x-rotfont->max_ascent; else if (align == BLEFT || align == BCENTRE || align == BRIGHT) xp = x+(nl-1)*rotfont->height + rotfont->max_descent; else xp = x+(nl-1)/2*rotfont->height - rotfont->max_ascent + rotfont->height/2 + ((nl%2 == 0)?rotfont->height/2:0); } free(str1); str1 = my_strdup(text); str3 = my_strtok(str1, str2); /* loop through each section in the string ... */ do { /* width of this section ... */ this_width = XRotTextWidth(rotfont, str3, strlen(str3)); /* horizontal alignment ... */ if (dir == 0) { if (align == TLEFT || align == MLEFT || align == BLEFT) xp = x; else if (align == TCENTRE || align == MCENTRE || align == BCENTRE) xp = x-this_width/2; else xp = x-max_width; } else if (dir == 1) { if (align == TLEFT || align == MLEFT || align == BLEFT) yp = y; else if (align == TCENTRE || align == MCENTRE || align == BCENTRE) yp = y+this_width/2; else yp = y+max_width; } else if (dir == 2) { if (align == TLEFT || align == MLEFT || align == BLEFT) xp = x; else if (align == TCENTRE || align == MCENTRE || align == BCENTRE) xp = x+this_width/2; else xp = x+max_width; } else { if (align == TLEFT || align == MLEFT || align == BLEFT) yp = y; else if (align == TCENTRE || align == MCENTRE || align == BCENTRE) yp = y-this_width/2; else yp = y-max_width; } /* draw the section ... */ XRotDrawString(dpy, rotfont, drawable, gc, xp, yp, str3, strlen(str3)); str3 = my_strtok((char *)NULL, str2); /* advance position ... */ if (dir == 0) yp += rotfont->height; else if (dir == 1) xp += rotfont->height; else if (dir == 2) yp -= rotfont->height; else xp -= rotfont->height; } while (str3 != NULL); free(str1); } wm2-4+svn20090216/Manager.C0000644000131400013140000003416007716704661013162 0ustar brlbrl #include "Manager.h" #include "Client.h" #include #include #include #include #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), m_focusChanging(False) { fprintf(stderr, "\nwm2: Copyright (c) 1996-7 Chris Cannam." " Not a release\n" " Parts derived from 9wm Copyright (c) 1994-96 David Hogan\n" " %s\n Copying and redistribution encouraged. " "No warranty.\n\n", XV_COPYRIGHT); if (CONFIG_AUTO_RAISE) { if (CONFIG_CLICK_TO_FOCUS) { fatal("can't have auto-raise-with-delay with click-to-focus"); } else if (CONFIG_RAISE_ON_FOCUS) { fatal("can't have raise-on-focus AND auto-raise-with-delay"); } else { fprintf(stderr, " Focus follows, auto-raise with delay. "); } } else { if (CONFIG_CLICK_TO_FOCUS) { if (CONFIG_RAISE_ON_FOCUS) { fprintf(stderr, " Click to focus. "); } else { fatal("can't have click-to-focus without raise-on-focus"); } } else { if (CONFIG_RAISE_ON_FOCUS) { fprintf(stderr, " Focus follows, auto-raise. "); } else { fprintf(stderr, " Focus follows pointer. "); } } } if (CONFIG_EVERYTHING_ON_ROOT_MENU) { fprintf(stderr, "All clients on menu.\n"); } else { fprintf(stderr, "Hidden clients only on menu.\n"); } if (CONFIG_PROD_SHAPE) { fprintf(stderr, " Shape prodding on. "); } else { fprintf(stderr, " Shape prodding off. "); } fprintf(stderr, "\n (To reconfigure, simply edit and recompile.)\n\n"); 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, "", 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)); XColor black, white, temp; if (!XAllocNamedColor(m_display, m_defaultColormap, "black", &black, &temp)) fatal("couldn't load colour \"black\"!"); if (!XAllocNamedColor(m_display, m_defaultColormap, "white", &white, &temp)) fatal("couldn't load colour \"white\"!"); 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); m_menuForegroundPixel = allocateColour(CONFIG_MENU_FOREGROUND, "menu foreground"); m_menuBackgroundPixel = allocateColour(CONFIG_MENU_BACKGROUND, "menu background"); m_menuBorderPixel = allocateColour(CONFIG_MENU_BORDERS, "menu border"); 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); } unsigned long WindowManager::allocateColour(char *name, char *desc) { XColor nearest, ideal; if (!XAllocNamedColor (display(), DefaultColormap(display(), m_screenNumber), name, &nearest, &ideal)) { char error[100]; sprintf(error, "couldn't load %s colour", desc); fatal(error); } return nearest.pixel; } 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); } Time 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)) { return m_clients.item(i); } } if (!create) return 0; else { Client *newC = new Client(this, w); m_clients.append(newC); return newC; } } void WindowManager::installColormap(Colormap cmap) { if (cmap == None) { XInstallColormap(m_display, m_defaultColormap); } else { XInstallColormap(m_display, cmap); } } void WindowManager::clearFocus() { static Window w = 0; Client *active = activeClient(); if (CONFIG_AUTO_RAISE || !CONFIG_CLICK_TO_FOCUS) { setActiveClient(0); return; } if (active) { setActiveClient(0); active->deactivate(); for (Client *c = active->revertTo(); c; c = c->revertTo()) { if (c->isNormal()) { c->activate(); return; } } installColormap(None); } 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); } 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); }