//////////////////////////////////////////////
// NovaWM - Nova Window Manager for X11 //
//////////////////////////////////////////////
// By: Tim Walters //
//////////////////////////////////////////////
// Copyright (C) 2001-2002 Tim Walters //
//////////////////////////////////////////////
////////////////////////////////////////////////////////////////
//This code is released under the terms of the GNU GPL. Refer //
//to the license file included with this source code. //
////////////////////////////////////////////////////////////////
#include "novawm.h"
#include "icon_hide.xpm"
#include "icon_stretch.xpm"
#include "icon_close.xpm"
Display *display;
int screen;
Window root;
unsigned int mainPixel;
Cursor Arrow;
Cursor MoveCursor;
Cursor ResizeCursor;
Cursor ResizeRightCursor;
Cursor ResizeDownCursor;
GC novawm_gc;
XColor color_grey;
XColor color_blue;
XColor color_red;
XColor color_darkblue;
XColor color_navyblue;
XFontStruct *novawmFont;
XFontStruct *nbFont;
Atom stateAtom;
Atom deleteAtom;
Atom protocolAtom;
Atom motifAtom;
Atom novawmAtom;
Atom takefocusAtom;
Atom changestateAtom;
Atom gnomeSupportAtom;
Pixmap killPixmap;
Pixmap stretchPixmap;
Pixmap hidePixmap;
GC killIconGC;
GC stretchIconGC;
GC hideIconGC;
Window gnomeSupportWindow;
NovaWM_Menu rootMenu;
NovaWM_Menu windowMenu;
NovaWM_Menu listMenu;
NovaWM_Menu novaMenu;
Atom netStateAtom;
Atom netSupportAtom;
Atom netClientListAtom;
Atom netDesktopAtom;
Atom netStateStickyAtom;
Atom netStateShadedAtom;
Atom netStateHiddenAtom;
Atom netStateSkipBarAtom;
Atom netStateFloatingAtom;
Atom netStateFullscreenAtom;
Atom netSupportedAtom;
NovaWM novawm;
Events events;
WinMgr winmgr;
Config cfg;
int focusType;
#ifdef _WIN_GNOME_SUPPORT
Atom winProtocolsAtom;
Atom winProtocols_ClientList;
Atom winProtocols_Workspace;
Atom winProtocols_WorkspaceCount;
Atom winProtocols_Layer;
Atom winProtocols_State;
Atom winProtocols_Hints;
Atom winProtocols_AppState;
Atom winProtocols_ExpandedSize;
#endif
static void
signal_handle (int signal)
{
switch (signal)
{
case SIGTERM:
printf ("NovaWM: Caught SIGTERM! Shutting down...\n");
novawm.Shutdown ();
break;
case SIGSEGV:
printf ("NovaWM: Caught SIGSEGV (Segmentation Fault) !! Attempting to quit quickly...\n");
novawm.Quick_Shutdown ();
exit (0);
break;
}
}
int
ErrorHandler (Display * dsp, XErrorEvent * event)
{
char text[300];
if ((event->error_code == BadAccess) && (event->resourceid == root))
{
fprintf (stderr,
"NovaWM: Another window manager is already running on that display.\n");
exit (1);
}
XGetErrorText (display, event->error_code, text, sizeof (text));
return 0;
}
char *displayName;
int
main (int argc, char *argv[])
{
bool badop = true;
displayName = NULL;
int timeFormat = 1;
cfg.disableBar = false;
printf ("Nova Window Manager\n");
printf ("Author: Tim Walters\n");
printf ("E-Mail: realmi2@yahoo.com\n");
for (int i = 1; i < argc; i++)
{
if (strcmp (argv[i], "--version") == 0)
{
printf ("NovaWM Version: " VERSION "\n");
return 0;
}
if (strcmp (argv[i], "-version") == 0)
{
printf ("NovaWM Version: " VERSION "\n");
return 0;
}
if (strcmp (argv[i], "-display") == 0)
{
displayName = argv[i + 1];
setenv ("DISPLAY", displayName, true);
badop = false;
}
if (strcmp (argv[i], "--display") == 0)
{
displayName = argv[i + 1];
badop = false;
}
if (strcmp (argv[i], "-timeformat") == 0)
{
timeFormat = atoi (argv[i + 1]);
badop = false;
}
if (strcmp (argv[i], "--timeformat") == 0)
{
timeFormat = atoi (argv[i + 1]);
badop = false;
}
if (strcmp (argv[i], "--disable-bar") == 0)
{
cfg.disableBar = true;
badop = false;
}
if (strcmp (argv[i], "--help") == 0)
{
printf ("Options:\n");
printf ("\t--version\t\tShows NovaWM Version information.\n");
printf ("\t--help\t\t\tShows this message.\n");
printf ("\t--timeformat 1|2\tSets the time format.\n");
printf ("\t--display displayname\tSets the X Display\n");
printf ("\t--disable-bar\tDisables NovaBar(Root menus are provided).\n");
return 0;
}
if (badop == true)
{
printf ("Bad Option!\n");
printf ("Options:\n");
printf ("\t--version\t\tShows NovaWM Version information.\n");
printf ("\t--help\t\t\tShows this message.\n");
printf ("\t--timeformat 1|2\tSets the time format.\n");
printf ("\t--display displayname\tSets the X Display\n");
printf ("\t--disable-bar\tDisables NovaBar(Root menus are provided).\n");
return 0;
}
}
focusType = 1;
void (*signal_handler) (int);
signal_handler = signal (SIGSEGV, signal_handle);
signal_handler = signal (SIGTERM, signal_handle);
//winmgr = new WinMgr;
cfg.mainColor = COLOR_MAIN;
cfg.LoadConfig ();
novawm.X11_Init ();
novawm.WM_Start ();
// cfg.disableBar = disableBar;
events.NovaWM_EventLoop ();
return (0);
}
void
NovaWM::X11_Init ()
{
XGCValues gcvalues;
XColor cdummy;
display = XOpenDisplay (displayName);
if (!display)
{
printf ("novawm: failed to open display: %s\n", displayName);
exit (0);
}
screen = DefaultScreen (display);
root = RootWindow (display, screen);
XSetErrorHandler (ErrorHandler);
XSetWindowAttributes attributes;
attributes.event_mask =
ButtonPressMask | ButtonReleaseMask | SubstructureNotifyMask |
SubstructureRedirectMask | PropertyChangeMask |
PointerMotionMask | FocusChangeMask | EnterWindowMask |
LeaveWindowMask;
XChangeWindowAttributes (display, root, CWEventMask, &attributes);
Arrow = XCreateFontCursor (display, XC_left_ptr);
MoveCursor = XCreateFontCursor (display, XC_fleur);
XDefineCursor (display, root, Arrow);
novawmFont = XLoadQueryFont (display, "lucidasans-12");
if (!novawmFont)
{
printf ("Failed to load font!\n");
novawmFont = XLoadQueryFont (display, "fixed");
}
nbFont = XLoadQueryFont (display, "lucidasans-10");
gcvalues.function = GXcopy;
gcvalues.foreground = WhitePixel (display, screen);
gcvalues.line_width = 1;
gcvalues.font = novawmFont->fid;
novawm_gc =
XCreateGC (display, root,
GCFunction | GCForeground | GCLineWidth | GCFont,
&gcvalues);
XColor tmpColor;
XAllocNamedColor (display, DefaultColormap (display, screen),
cfg.mainColor.c_str (), &tmpColor, &cdummy);
mainPixel = tmpColor.pixel;
}
void
NovaWM::WM_Start ()
{
Window wdummy;
Window *windows;
unsigned int nchildren = 0;
unsigned int i = 0;
stateAtom = XInternAtom (display, "WM_STATE", false);
deleteAtom = XInternAtom (display, "WM_DELETE_WINDOW", false);
protocolAtom = XInternAtom (display, "WM_PROTOCOLS", false);
motifAtom = XInternAtom (display, "_MOTIF_WM_HINTS", false);
takefocusAtom = XInternAtom (display, "WM_TAKE_FOCUS", false);
changestateAtom = XInternAtom (display, "WM_CHANGE_STATE", false);
novawmAtom = XInternAtom (display, "NOVAWM_HINTS", false);
netSupportAtom =
XInternAtom (display, "_NET_SUPPORTING_WM_CHECK", false);
netStateAtom = XInternAtom (display, "_NET_WM_STATE", false);
netClientListAtom = XInternAtom (display, "_NET_CLIENT_LIST", false);
netDesktopAtom = XInternAtom (display, "_NET_WM_DESKTOP", false);
netStateStickyAtom =
XInternAtom (display, "_NET_WM_STATE_STICKY", false);
netStateShadedAtom =
XInternAtom (display, "_NET_WM_STATE_SHADED", false);
netStateHiddenAtom =
XInternAtom (display, "_NET_WM_STATE_HIDDEN", false);
netStateSkipBarAtom =
XInternAtom (display, "_NET_WM_STATE_SKIP_TASKBAR", false);
netStateFloatingAtom =
XInternAtom (display, "_NET_WM_STATE_FLOATING", false);
netStateFullscreenAtom =
XInternAtom (display, "_NET_WM_STATE_FULLSCREEN", false);
#ifdef _WIN_GNOME_SUPPORT
//GNOME Support
gnomeSupportAtom =
XInternAtom (display, "_WIN_SUPPORTING_WM_CHECK", false);
winProtocolsAtom = XInternAtom (display, "_WIN_PROTOCOLS", false);
winProtocols_ClientList =
XInternAtom (display, "_WIN_CLIENT_LIST", false);
winProtocols_Workspace =
XInternAtom (display, "_WIN_WORKSPACE", false);
winProtocols_WorkspaceCount =
XInternAtom (display, "_WIN_WORKSPACE_COUNT", false);
winProtocols_State = XInternAtom (display, "_WIN_STATE", false);
winProtocols_Layer = XInternAtom (display, "_WIN_LAYER", false);
#endif
//Setup the menus
//Setup the Root Menu
rootMenu.AddItem ("xterm");
rootMenu.AddItem ("?+MENU_SPLIT+?");
rootMenu.AddItem ("Iconify Window");
rootMenu.AddItem ("Kill Window");
rootMenu.AddItem ("?+MENU_SPLIT+?");
rootMenu.AddItem ("Restart");
rootMenu.AddItem ("Exit");
//Setup the Window Menu
windowMenu.AddItem ("Hide");
windowMenu.AddItem ("Maximize");
windowMenu.AddItem ("Resize");
windowMenu.AddItem ("Kill");
windowMenu.AddItem ("?+MENU_SPLIT+?");
windowMenu.AddItem ("Send to Desktop 1");
windowMenu.AddItem ("Send to Desktop 2");
windowMenu.AddItem ("Send to Desktop 3");
windowMenu.AddItem ("Send to Desktop 4");
windowMenu.AddItem ("Send to Next Desktop");
windowMenu.AddItem ("Send to Previous Desktop");
//The NovaBar Menu/NovaMenu looks better with the smaller font
novaMenu.SetFont (nbFont);
novaMenu.SetItemHeight (12);
novaMenu.AddItem ("?+MENU_SPLIT+?");
novaMenu.AddItem ("Restart");
novaMenu.AddItem ("Exit");
winmgr.maxDesktops = 10;
winmgr.nDesktops = 1;
winmgr.nClients = 0;
XSetInputFocus (display, root, RevertToNone, CurrentTime);
//Grab the previous desktop key
XGrabKey (display, XKeysymToKeycode (display, XK_bracketleft),
ControlMask, root, true, GrabModeAsync, GrabModeAsync);
//Grab the next desktop key
XGrabKey (display, XKeysymToKeycode (display, XK_bracketright),
ControlMask, root, true, GrabModeAsync, GrabModeAsync);
winmgr.SetDesktop (0);
//Create a window with the _WIN_SUPPORTING_WM_CHECK to be a GNOME
//Compliant Window Manager.
gnomeSupportWindow =
XCreateSimpleWindow (display, root, -200, -200, 5, 5, 0, 0,
0);
#ifdef _WIN_GNOME_SUPPORT
XChangeProperty (display, gnomeSupportWindow, gnomeSupportAtom,
XA_CARDINAL, 32, PropModeReplace,
(unsigned char *) &gnomeSupportWindow, 1);
XChangeProperty (display, root, gnomeSupportAtom, XA_CARDINAL, 32,
PropModeReplace,
(unsigned char *) &gnomeSupportWindow, 1);
#endif
//Do the same for _NET_SUPPORTING_WM_CHECK for ICCCM Compliance
XChangeProperty (display, root, netSupportAtom, XA_CARDINAL, 32,
PropModeReplace,
(unsigned char *) &gnomeSupportWindow, 1);
XChangeProperty (display, netSupportAtom, gnomeSupportAtom,
XA_CARDINAL, 32, PropModeReplace,
(unsigned char *) &gnomeSupportWindow, 1);
#ifdef _WIN_GNOME_SUPPORT
Atom winProtocolsList[7];
winProtocolsList[0] = winProtocols_ClientList;
winProtocolsList[1] = winProtocols_WorkspaceCount;
winProtocolsList[2] = winProtocols_WorkspaceCount;
//Set the _WIN_PROTOCOLS list to the root window (GNOME Support)
XChangeProperty (display, root, winProtocolsAtom, XA_ATOM, 32,
PropModeReplace, (unsigned char *) winProtocolsList,
3);
//Set the number of desktops
CARD32 desktopNum = (CARD32) winmgr.nDesktops;
XChangeProperty (display, root,
winProtocols_WorkspaceCount,
XA_CARDINAL, 32, PropModeReplace,
(unsigned char *) &desktopNum, 1);
#endif
//Load the button icons
killPixmap = LoadXPM (icon_close_xpm, 16, 16, &killIconGC);
stretchPixmap = LoadXPM (icon_stretch_xpm, 16, 16, &stretchIconGC);
hidePixmap = LoadXPM (icon_hide_xpm, 16, 16, &hideIconGC);
//Reparent all windows
XQueryTree (display, root, &wdummy, &wdummy, &windows, &nchildren);
for (i = 0; i < nchildren; i++)
{
if (windows[i] && windows[i] != gnomeSupportWindow)
winmgr.NewWindow (windows[i]);
}
XFree (windows);
CreateBar ();
}
void
NovaWM::Restart ()
{
#ifdef DEBUG
printf ("DEBUG: Restart()\n");
#endif
// for (Novawm_Window * DLWindow = winmgr.topWindow; DLWindow;
// DLWindow = DLWindow->prev)
for (list < Novawm_Window * >::const_iterator i =
winmgr.novawm_window_List.begin ();
i != winmgr.novawm_window_List.end (); ++i)
{
if ((*i)->hasTitlebar == true)
{
XReparentWindow (display, (*i)->window, root, (*i)->x,
(*i)->y);
XDestroyWindow (display, (*i)->titlebar);
}
(*i)->Destroy ();
}
DestroyBar ();
XFreeFont (display, novawmFont);
XFreeGC (display, novawm_gc);
XFreeCursor (display, Arrow);
XFreeCursor (display, ResizeCursor);
XFreeCursor (display, ResizeRightCursor);
XFreeCursor (display, ResizeDownCursor);
XFreePixmap (display, killPixmap);
XFreePixmap (display, stretchPixmap);
XFreePixmap (display, hidePixmap);
XSetInputFocus (display, root, RevertToPointerRoot, CurrentTime);
//Grab the previous desktop key
XUngrabKey (display, XKeysymToKeycode (display, XK_bracketleft),
ControlMask, root);
//Grab the next desktop key
XUngrabKey (display, XKeysymToKeycode (display, XK_bracketright),
ControlMask, root);
// delete winmgr;
XCloseDisplay (display);
Run ("novawm");
}
void
NovaWM::Quick_Shutdown ()
{
//If this is not called it seems that you can't give
//any window input focus after a seg fault
// XSetInputFocus(display,root,RevertToPointerRoot,CurrentTime);
//XCloseDisplay() is not called here because for
//some reason it can be another source of seg faults
//which means a call to this function will be looped.
exit (0);
}
void
NovaWM::Shutdown ()
{
#ifdef DEBUG
printf ("DEBUG: Shutdown()\n");
#endif
XSetInputFocus (display, root, RevertToPointerRoot, CurrentTime);
//for (Novawm_Window * DLWindow = winmgr.topWindow; DLWindow;
// DLWindow = DLWindow->prev)
for (list < Novawm_Window * >::const_iterator i =
winmgr.novawm_window_List.begin ();
i != winmgr.novawm_window_List.end (); ++i)
{
if ((*i)->hasTitlebar == true)
{
XReparentWindow (display, (*i)->window, root, (*i)->x,
(*i)->y);
XDestroyWindow (display, (*i)->titlebar);
}
(*i)->Destroy ();
}
#ifdef DEBUG
printf ("NovaWM DEBUG: Freeing Menu Execution List...\n");
#endif
cfg.itemExec.clear ();
DestroyBar ();
XFreeFont (display, novawmFont);
XFreeGC (display, novawm_gc);
XSetInputFocus (display, PointerRoot, RevertToPointerRoot,
CurrentTime);
//Grab the previous desktop key
XUngrabKey (display, XKeysymToKeycode (display, XK_bracketleft),
ControlMask, root);
//Grab the next desktop key
XUngrabKey (display, XKeysymToKeycode (display, XK_bracketright),
ControlMask, root);
// delete winmgr;
XCloseDisplay (display);
exit (0);
}
void
NovaWM::Run (char *command)
{
pid_t procid = fork ();
switch (procid)
{
case 0:
execlp ("/bin/sh", "sh", "-c", command, NULL);
printf ("Failed to execute program.\n");
exit (1);
case -1:
printf ("Failed to fork\n");
}
}
//Modifies a XPM and replaces Transparent/None pixels with MAIN_COLOR
char **
XPM_FillTransp (char **xpm, int width, int height)
{
char *newColor = 0;
newColor = (char *) malloc (16); //new char;
if (!newColor)
{
printf ("NovaWM CRITICAL ERROR: XPM_FillTransp(): Your system appears to have run out of memory. NovaWM will now exit.\n");
exit (0);
}
snprintf (newColor, 16, " c %s", cfg.mainColor.c_str ());
xpm[1] = newColor;
return xpm;
}
Pixmap
NovaWM::LoadXPM (char **xpm_data, int width, int height, GC * xpmgc)
{
GC xpm_gc;
XGCValues gc_values;
gc_values.function = GXcopy;
gc_values.foreground = mainPixel; //BlackPixel (display, screen);
gc_values.background = mainPixel;
printf ("NovaWM: Fixing XPM Icon...\n");
XPM_FillTransp (xpm_data, width, height);
Pixmap pmap =
XCreatePixmap (display, gnomeSupportWindow, width,
height, DefaultDepth (display, screen));
XpmAttributes attributes;
Pixmap xmask;
attributes.valuemask = XpmColormap | XpmCloseness;
attributes.colormap = DefaultColormap (display, screen);
attributes.closeness = 65535;
if (XpmCreatePixmapFromData
(display, gnomeSupportWindow, xpm_data, &pmap, &xmask,
&attributes) != XpmSuccess)
return 0;
xpm_gc = XCreateGC (display, pmap,
GCFunction | GCForeground | GCBackground,
&gc_values);
XSetFillStyle (display, xpm_gc, FillTiled);
XSetTile (display, xpm_gc, pmap);
XSetClipMask (display, xpm_gc, xmask);
*xpmgc = xpm_gc;
return pmap;
}
void
NovaWM::SetNetSupported ()
{
#define NET_SUPPORTED_ATOMS 10
/*Atom supported_Net_Atoms[NET_SUPPORTED_ATOMS] = {
netSupportedAtom, netClientListAtom,
net
};*/
}
syntax highlighted by Code2HTML, v. 0.9.1