#include "Manager.h" #include "Client.h" #include #include #include #include #include "Cursors.h" #include #include #define ACOUNT(x) (sizeof(x)/sizeof(x[0])) void initAtoms() {} Boolean WindowManager::m_looping = True; char *nice_font; bool click_to_focus; bool raise_on_focus; bool auto_raise; unsigned int auto_raise_delay; unsigned int CONFIG_POINTER_STOPPED_DELAY = 80; char *border_fg; char *frame_bg; char *button_bg; unsigned int title_size; unsigned int frame_size; 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; Atom Atoms::win_protocols; Atom Atoms::win_workspace; Atom Atoms::win_workspace_count; Atom Atoms::win_workspace_names; Atom Atoms::win_workarea; Atom Atoms::win_icons; Atom Atoms::win_state; Atom Atoms::win_layer; Atom Atoms::win_hints; Atom Atoms::win_supporting_wm_check; Atom Atoms::win_client_list; Atom Atoms::win_desktop_button_proxy; Atom Atoms::win_area; Atom Atoms::win_area_count; Atom Atoms::mwm_hints; int WindowManager::m_signalled = False; Boolean WindowManager::m_initialising = False; Boolean ignoreBadWindowErrors; implementPList(ClientList, Client); WindowManager::WindowManager() : m_focusChanging(False) { fprintf(stderr, "\nwmG: Copyright (c) 1999 Scott Barnes.\nDerived from wm2, created for Gnome, and written in C++\n\n"); m_display = XOpenDisplay(NULL); if(!m_display) fatal("can't open display"); m_initialising = True; XSetErrorHandler(errorHandler); ignoreBadWindowErrors = True; 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); Atoms::win_protocols = XInternAtom(m_display, "_WIN_PROTOCOLS", False); Atoms::win_workspace = XInternAtom(m_display, "_WIN_WORKSPACE", False); Atoms::win_workspace_count = XInternAtom(m_display, "_WIN_WORKSPACE_COUNT", False); Atoms::win_workspace_names = XInternAtom(m_display, "_WIN_WORKSPACE_NAMES", False); Atoms::win_workarea = XInternAtom(m_display, "_WIN_WORKAREA", False); Atoms::win_icons = XInternAtom(m_display, "_WIN_ICONS", False); Atoms::win_state = XInternAtom(m_display, "_WIN_STATE", False); Atoms::win_layer = XInternAtom(m_display, "_WIN_LAYER", False); Atoms::win_hints = XInternAtom(m_display, "_WIN_HINTS", False); Atoms::win_supporting_wm_check = XInternAtom(m_display, "_WIN_SUPPORTING_WM_CHECK", False); Atoms::win_client_list = XInternAtom(m_display, "_WIN_CLIENT_LIST", False); Atoms::win_desktop_button_proxy = XInternAtom(m_display, "_WIN_DESKTOP_BUTTON_PROXY", False); Atoms::win_area = XInternAtom(m_display, "_WIN_AREA", False); Atoms::win_area_count = XInternAtom(m_display, "_WIN_AREA_COUNT", False); Atoms::mwm_hints = XInternAtom(m_display, "_MOTIF_WM_HINTS", False); click_to_focus = gnome_config_get_bool("/wmG/properties/CLICK_TO_FOCUS=True"); if(click_to_focus == False) raise_on_focus = gnome_config_get_bool("/wmG/properties/RAISE_ON_FOCUS=True"); auto_raise = gnome_config_get_bool("/wmG/properties/AUTO_RAISE=False"); auto_raise_delay = gnome_config_get_int("/wmG/properties/AUTO_RAISE_DELAY=400"); title_size = gnome_config_get_int("/wmG/properties/TITLEBAR_SIZE=12"); frame_size = gnome_config_get_int("/wmG/properties/FRAME_SIZE=2"); border_fg = gnome_config_get_string("/wmG/properties/BORDER_COLOR=black"); frame_bg = gnome_config_get_string("/wmG/properties/FRAME_BACKGROUND=gray95"); button_bg = gnome_config_get_string("/wmG/properties/BUTTON_BACKGROUND=gray95"); int dummy; if(!XShapeQueryExtension(m_display, &m_shapeEvent, &dummy)) fatal("no shape extension, can't run without it"); initialiseScreen(); fprintf(stderr, "wmG: root window is %lx\n", m_root); unsigned int i = 0; Atom win_proto[11]; win_proto[i++] = Atoms::win_workspace; win_proto[i++] = Atoms::win_workspace_count; win_proto[i++] = Atoms::win_workspace_names; win_proto[i++] = Atoms::win_icons; win_proto[i++] = Atoms::win_workarea; win_proto[i++] = Atoms::win_state; win_proto[i++] = Atoms::win_hints; win_proto[i++] = Atoms::win_layer; win_proto[i++] = Atoms::win_supporting_wm_check; win_proto[i++] = Atoms::win_client_list; win_proto[i++] = Atoms::win_desktop_button_proxy; XChangeProperty(display(), m_root, Atoms::win_protocols, XA_ATOM, 32, PropModeReplace, (unsigned char *)win_proto, i); XSetWindowAttributes attr; int mask = CWOverrideRedirect; attr.override_redirect = TRUE; root_proxy = XCreateWindow(display(), root(), -5, -5, 5, 5, 0, CopyFromParent, InputOutput, CopyFromParent, mask, &attr); XSetWMProtocols(display(), root_proxy, &Atoms::wm_delete, 1); XMapWindow(display(), root_proxy); XChangeProperty(display(), m_root, Atoms::win_supporting_wm_check, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&root_proxy, 1); XChangeProperty(display(), root_proxy, Atoms::win_supporting_wm_check, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&root_proxy, 1); XChangeProperty(display(), m_root, Atoms::win_desktop_button_proxy, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)&root_proxy, 1); XChangeProperty(display(), root_proxy, Atoms::win_desktop_button_proxy, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)&root_proxy, 1); XSync(m_display, False); m_initialising = False; m_returnCode = 0; clearFocus(); scanInitialWindows(); loop(); } WindowManager::~WindowManager() {} void WindowManager::release() { if(m_returnCode != 0) return; ClientList normalList, unparentList; Client *c; int i; for(i = 0; i < m_clients.count(); ++i) { c = m_clients.item(i); 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) { 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); XCloseDisplay(m_display); } void WindowManager::fatal(const char *message) { fprintf(stderr, "wmG: "); 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, "wmG: another window manager running?\n"); exit(1); } 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, "wmG: %s (0x%lx): %s\n", request, e->resourceid, msg); if(m_initialising) { fprintf(stderr, "wmG: 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 | KeymapNotify | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PropertyChangeMask; XChangeWindowAttributes(m_display, m_root, CWCursor | CWEventMask, &attr); XSync(m_display, False); } 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); } else 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_looping = False; } 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)) (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(auto_raise || !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; } } void WindowManager::updateClientList() { long w; XID *ids; ids = new XID [m_clients.count()]; w = 0; for(long i = 0; i < m_clients.count(); i++) if(m_clients.item(i)->managed() && !m_clients.item(i)->isWithdrawn() && m_clients.item(i)->handle() != root_proxy) ids[w++] = m_clients.item(i)->handle(); XChangeProperty(display(), m_root, Atoms::win_client_list, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)ids, w); delete ids; }