////////////////////////////////////////////// // 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 };*/ }