Manager.C
#include "Manager.h"
#include "Menu.h"
#include "Client.h"
#if I18N
#include <X11/Xlocale.h>
#endif
10 #include <string.h>
#include <X11/Xproto.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "Cursors.h"
#include <X11/cursorfont.h>
Atom Atoms::wm_state;
Atom Atoms::wm_changeState;
20 Atom Atoms::wm_protocols;
Atom Atoms::wm_delete;
Atom Atoms::wm_takeFocus;
Atom Atoms::wm_colormaps;
Atom Atoms::wmx_running;
int WindowManager::m_signalled = False;
Boolean WindowManager::m_initialising = False;
Boolean ignoreBadWindowErrors;
30 implementPList(ClientList, Client);
WindowManager::WindowManager(int argc, char **argv) :
m_focusChanging(False),
m_altPressed(False)
{
char *home = getenv("HOME");
char *wmxdir = getenv("WMXDIR");
40 fprintf(stderr, "\nwmx: Copyright (c) 1996-9 Chris Cannam."
" Fifth release, Jan 1999\n"
" Parts derived from 9wm Copyright (c) 1994-96 David Hogan\n"
" Command menu code Copyright (c) 1997 Jeremy Fitzhardinge\n"
" Japanize code Copyright (c) 1998 Kazushi (Jam) Marukawa\n"
" Original keyboard-menu code Copyright (c) 1998 Nakayama Shintaro\n"
" Dynamic configuration code Copyright (c) 1998 Stefan `Sec' Zehl\n"
" %s\n Copying and redistribution encouraged. "
"No warranty.\n\n", XV_COPYRIGHT);
50 int i;
#if CONFIG_USE_SESSION_MANAGER != False
char *oldSessionId = 0;
#endif
if (argc > 1) {
#if CONFIG_USE_SESSION_MANAGER != False
// Damn! This means we have to support a command-line argument
if (argc == 3 && !strcmp(argv[1], "-clientId")) {
60 oldSessionId = argv[2];
} else {
#endif
for (i = strlen(argv[0])-1; i > 0 && argv[0][i] != '/'; --i);
fprintf(stderr, "\nwmx: Usage: %s [-clientId id]\n",
argv[0] + (i > 0) + i);
exit(2);
#if CONFIG_USE_SESSION_MANAGER != False
70 }
#endif
}
#if I18N
if (!setlocale(LC_ALL, ""))
fprintf(stderr,
"Warning: locale not supported by C library, locale unchanged\n");
if (!XSupportsLocale()) {
fprintf(stderr,
80 "Warning: locale not supported by Xlib, locale set to C\n");
setlocale(LC_ALL, "C");
}
if (!XSetLocaleModifiers(""))
fprintf(stderr,
"Warning: X locale modifiers not supported, using default\n");
char* ret_setlocale = setlocale(LC_ALL, NULL);
// re-query in case overwritten
#endif
90 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 {
100 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 {
110 fprintf(stderr, " Focus follows pointer. ");
}
}
}
if (CONFIG_EVERYTHING_ON_ROOT_MENU) {
fprintf(stderr, "All clients on menu. ");
} else {
fprintf(stderr, "Hidden clients only on menu. ");
}
120
if (CONFIG_USE_SESSION_MANAGER) {
fprintf(stderr, "Using session manager.");
} else {
fprintf(stderr, "No session manager.");
}
if (CONFIG_PROD_SHAPE) {
fprintf(stderr, "\n Shape prodding on. ");
} else {
130 fprintf(stderr, "\n Shape prodding off. ");
}
if (CONFIG_USE_PIXMAPS) {
fprintf(stderr, "Fancy borders. ");
} else {
fprintf(stderr, "Plain borders. ");
}
if (CONFIG_MAD_FEEDBACK) {
140 fprintf(stderr, "Skeletal feedback on. ");
} else {
fprintf(stderr, "Skeletal feedback off. ");
}
if (CONFIG_CHANNEL_SURF) {
fprintf(stderr, "Channels on.");
} else {
fprintf(stderr, "Channels off.");
}
150
if (CONFIG_USE_KEYBOARD) {
fprintf(stderr, "\n Keyboard controls available. ");
} else {
fprintf(stderr, "\n No keyboard controls. ");
}
if (CONFIG_USE_CHANNEL_KEYS) {
fprintf(stderr, "Quick keyboard channel-surf available. ");
} else {
160 fprintf(stderr, "No quick keyboard channel-surf. ");
}
fprintf(stderr, "\n Command menu taken from ");
if (wmxdir == NULL) {
fprintf(stderr, "%s/%s.", home, CONFIG_COMMAND_MENU);
} else {
if (*wmxdir == '/') {
fprintf(stderr, "%s.", wmxdir);
} else {
170 fprintf(stderr, "%s/%s.", home, wmxdir);
}
}
if (CONFIG_WANT_KEYBOARD_MENU) {
fprintf(stderr, " Keyboard menu available.");
} else {
fprintf(stderr, " No keyboard menu available.");
}
180 #if I18N
fprintf(stderr, "\n Operating system locale is \"%s\".",
ret_setlocale ? ret_setlocale : "(NULL)");
#endif
fprintf(stderr, "\n (To reconfigure, simply edit and recompile.)\n\n");
m_display = XOpenDisplay(NULL);
if (!m_display) fatal("can't open display");
190 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);
200 signal(SIGHUP, sigHandler);
m_currentTime = -1;
m_activeClient = 0;
m_channels = 2;
m_currentChannel = 1;
m_channelChangeTime = 0;
m_channelWindow = 0;
210 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::wmx_running = XInternAtom(m_display, "_WMX_RUNNING", False);
int dummy;
if (!XShapeQueryExtension(m_display, &m_shapeEvent, &dummy))
220 fatal("no shape extension, can't run without it");
// we only cope with one screen!
initialiseScreen();
XSetSelectionOwner(m_display, Atoms::wmx_running,
None, timestamp(True)); // used to have m_menuWindow
XSync(m_display, False);
m_initialising = False;
m_returnCode = 0;
230
#if CONFIG_USE_SESSION_MANAGER != False
initialiseSession(argv[0], oldSessionId);
#endif
clearFocus();
scanInitialWindows();
loop();
}
240
WindowManager::~WindowManager()
{
// empty
}
void WindowManager::release()
{
if (m_returnCode != 0) return; // hasty exit
250
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() || c->isNormalButElsewhere()) normalList.append(c);
260 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) {
270 // 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);
280 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);
Menu::cleanup(this);
XCloseDisplay(m_display);
}
290
void WindowManager::fatal(const char *message)
{
fprintf(stderr, "wmx: ");
perror(message);
fprintf(stderr, "\n");
exit(1);
}
300
int WindowManager::errorHandler(Display *d, XErrorEvent *e)
{
if (m_initialising && (e->request_code == X_ChangeWindowAttributes) &&
e->error_code == BadAccess) {
fprintf(stderr, "wmx: another window manager running?\n");
exit(1);
}
// ugh
310 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);
320 fprintf(stderr, "wmx: %s (0x%lx): %s\n", request, e->resourceid, msg);
if (m_initialising) {
fprintf(stderr, "wmx: failure during initialisation, abandoning\n");
exit(1);
}
return 0;
}
330
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, int fontIndex)
{
Cursor cursor;
if (CONFIG_USE_PLAIN_X_CURSORS) {
340 cursor = XCreateFontCursor(d, fontIndex);
} else {
Pixmap pixmap =
XCreateBitmapFromData(d, w, (const char *)bits, width, height);
Pixmap mask =
XCreateBitmapFromData(d, w, (const char *)mask_bits, width,height);
350 cursor = XCreatePixmapCursor(d, pixmap, mask, fg, bg, xhot, yhot);
XFreePixmap(d, pixmap);
XFreePixmap(d, mask);
}
return cursor;
}
360 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;
370
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, XC_top_left_arrow);
380
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, XC_X_cursor);
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, XC_right_side);
390
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, XC_bottom_side);
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,
400 XC_bottom_right_corner);
XSetWindowAttributes attr;
attr.cursor = m_cursor;
attr.event_mask = SubstructureRedirectMask | SubstructureNotifyMask |
ColormapChangeMask | ButtonPressMask | ButtonReleaseMask |
PropertyChangeMask | LeaveWindowMask | KeyPressMask | KeyReleaseMask;
XChangeWindowAttributes(m_display, m_root, CWCursor | CWEventMask, &attr);
XSync(m_display, False);
}
410
unsigned long WindowManager::allocateColour(char *name, char *desc)
{
XColor nearest, ideal;
if (!XAllocNamedColor
(display(), DefaultColormap(display(), m_screenNumber), name,
&nearest, &ideal)) {
420 char error[100];
sprintf(error, "couldn't load %s colour", desc);
fatal(error);
} else return nearest.pixel;
}
void WindowManager::installCursor(RootCursor c)
{
430 installCursorOnWindow(c, m_root);
}
void WindowManager::installCursorOnWindow(RootCursor c, Window w)
{
XSetWindowAttributes attr;
switch (c) {
case DeleteCursor: attr.cursor = m_xCursor; break;
440 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);
}
450 Time WindowManager::timestamp(Boolean reset)
{
if (reset) m_currentTime = CurrentTime;
if (m_currentTime == CurrentTime) {
XEvent event;
XChangeProperty(m_display, m_root, Atoms::wmx_running,
Atoms::wmx_running, 8, PropModeAppend,
(unsigned char *)"", 0);
460 XMaskEvent(m_display, PropertyChangeMask, &event);
m_currentTime = event.xproperty.time;
}
return m_currentTime;
}
void WindowManager::sigHandler()
{
470 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);
480
for (i = 0; i < n; ++i) {
XGetWindowAttributes(m_display, wins[i], &attr);
// if (attr.override_redirect || wins[i] == m_menuWindow) continue;
if (attr.override_redirect) continue;
(void)windowToClient(wins[i], True);
}
490 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)) {
500 return m_clients.item(i);
}
}
if (!create) return 0;
else {
Client *newC = new Client(this, w);
m_clients.append(newC);
if (m_currentChannel == m_channels) {
createNewChannel();
510 }
return newC;
}
}
void WindowManager::installColormap(Colormap cmap)
{
if (cmap == None) {
XInstallColormap(m_display, m_defaultColormap);
} else {
520 XInstallColormap(m_display, cmap);
}
}
void WindowManager::clearFocus()
{
static Window w = 0;
Client *active = activeClient();
if (CONFIG_AUTO_RAISE || !CONFIG_CLICK_TO_FOCUS) {
530 setActiveClient(0);
return;
}
if (active) {
setActiveClient(0);
active->deactivate();
for (Client *c = active->revertTo(); c; c = c->revertTo()) {
540 if (c->isNormal()) {
c->activate();
return;
}
}
installColormap(None);
}
if (w == 0) {
550
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);
560 }
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 &&
570 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) {
580 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) {
590 if (m_hiddenClients.item(i) == c) {
m_hiddenClients.remove(i);
return;
}
}
}
void WindowManager::hoistToTop(Client *c)
{
600 int i;
for (i = 0; i < m_orderedClients.count(); ++i) {
if (m_orderedClients.item(i) == c) {
m_orderedClients.move_to_start(i);
break;
}
}
if (i >= m_orderedClients.count()) {
610 m_orderedClients.append(c);
m_orderedClients.move_to_start(m_orderedClients.count()-1);
}
}
void WindowManager::hoistToBottom(Client *c)
{
int i;
620 for (i = 0; i < m_orderedClients.count(); ++i) {
if (m_orderedClients.item(i) == c) {
m_orderedClients.move_to_end(i);
break;
}
}
if (i >= m_orderedClients.count()) {
m_orderedClients.append(c);
// m_orderedClients.move_to_end(m_orderedClients.count()-1);
630 }
}
void WindowManager::removeFromOrderedList(Client *c)
{
for (int i = 0; i < m_orderedClients.count(); ++i) {
if (m_orderedClients.item(i) == c) {
m_orderedClients.remove(i);
return;
640 }
}
}
Boolean WindowManager::isTop(Client *c)
{
return (m_orderedClients.item(0) == c) ? True : False;
}
650 void WindowManager::withdrawGroup(Window groupParent, Client *omit, Boolean changeState)
{
for (int i = 0; i < m_orderedClients.count(); ++i) {
Client *ic = m_orderedClients.item(i);
if (ic->groupParent() == groupParent && !ic->isGroupParent() &&
ic != omit) {
ic->withdraw(changeState);
}
}
}
660
void WindowManager::hideGroup(Window groupParent, Client *omit)
{
for (int i = 0; i < m_orderedClients.count(); ++i) {
Client *ic = m_orderedClients.item(i);
if (ic->groupParent() == groupParent && !ic->isGroupParent() &&
ic != omit) {
ic->hide();
}
}
670 }
void WindowManager::unhideGroup(Window groupParent, Client *omit, Boolean map)
{
for (int i = 0; i < m_orderedClients.count(); ++i) {
Client *ic = m_orderedClients.item(i);
if (ic->groupParent() == groupParent && !ic->isGroupParent() &&
ic != omit) {
ic->unhide(map);
}
680 }
}
void WindowManager::killGroup(Window groupParent, Client *omit)
{
for (int i = 0; i < m_orderedClients.count(); ++i) {
Client *ic = m_orderedClients.item(i);
if (ic->groupParent() == groupParent && !ic->isGroupParent() &&
ic != omit) {
ic->kill();
690 }
}
}
Boolean WindowManager::raiseTransients(Client *c)
{
Client *first = 0;
if (!c->isNormal()) return False;
700
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();
710 }
}
}
if (first) {
first->mapRaised();
return True;
} else {
return False;
}
720 }
#ifdef sgi
extern "C" {
extern int putenv(char *); /* not POSIX */
}
#endif
void WindowManager::spawn(char *name, char *file)
{
730 // 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
740 // 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) {
750 if (file) execl(m_shell, m_shell, "-c", file, 0);
else execl(m_shell, m_shell, "-c", name, 0);
fprintf(stderr, "wmx: exec %s", m_shell);
perror(" failed");
}
if (file) {
execl(file, name, 0);
}
else {
760 if (strcmp(CONFIG_NEW_WINDOW_COMMAND, name)) {
execlp(name, name, 0);
}
else {
execlp(name, name, CONFIG_NEW_WINDOW_COMMAND_OPTIONS);
}
}
XBell(display(), 70);
fprintf(stderr, "wmx: exec %s:%s failed (errno %d)\n",
770 name, file, errno);
exit(1);
}
exit(0);
}
wait((int *) 0);
}
780