#include "Manager.h"
#include "Client.h"
#include <string.h>
#include <X11/Xproto.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "Cursors.h"
#include <X11/keysym.h>
#include <gnome.h>
#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, "<request-code-%d>", 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;
}
syntax highlighted by Code2HTML, v. 0.9.1