///////////////////////////////////////////// // 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" WinMgr::WinMgr () { topWindow = 0; lastWindow = 0; focusWindow = 0; } WinMgr::~WinMgr () { } Novawm_Window::Novawm_Window () { window = 0; titlebar = 0; kill = 0; stretch = 0; hide = 0; tChild = 0; title = "Unnamed"; ignoreTransient = false; nTChildren = 0; desktop = winmgr->cDesktop; hasTitlebar = true; isTransient = false; size_hints = 0; prev = 0; next = 0; } Novawm_Window::~Novawm_Window () { } void WinMgr::NewWindow (Window x11_window) { XWindowAttributes win_attrib; XSetWindowAttributes set_attrib; long dummy; char *name; unsigned long udummy; Atom adummy; int idummy; MotifHints *motif_hints = NULL; Window tranWin = None; Novawm_Window *win = new Novawm_Window; XGrabServer (display); XGetWindowAttributes (display, x11_window, &win_attrib); if(win_attrib.override_redirect == true) { delete win; XUnmapWindow(display,x11_window); return; } XFetchName (display, x11_window, &name); if (!name) win->title = "Unknown"; else win->title = name; win->hasTitlebar = true; win->x = win_attrib.x; win->y = win_attrib.y; win->width = win_attrib.width; win->height = win_attrib.height; if (win->y < 20) win->y = 20; win->orig_width = win_attrib.width; win->orig_height = win_attrib.height; win->nTChildren = 0; win->window = x11_window; win->size_hints = XAllocSizeHints (); XGetWMNormalHints (display, x11_window, win->size_hints, &dummy); /* if (win->width > win->size_hints->max_width) * win->width = win->size_hints->max_width; * * if (win->width < win->size_hints->min_width) * win->width = win->size_hints->min_width; * * if (win->height > win->size_hints->max_height) * win->height = win->size_hints->max_height; * * if (win->height < win->size_hints->min_height) * win->height = win->size_hints->min_height; * */ if (win_attrib.border_width > 0) { win->width += win_attrib.border_width * 2; win->height += win_attrib.border_width * 2; } if (win->width > XDisplayWidth (display, screen)) win->width = XDisplayWidth (display, screen); if (win->height > XDisplayHeight (display, screen)) win->height = XDisplayHeight (display, screen); XGetTransientForHint (display, win->window, &tranWin); if (tranWin) win->isTransient = true; else win->isTransient = false; Novawm_Window *parent = winmgr->WindowSearch (tranWin); if (parent) { parent->nTChildren++; if (parent->nTChildren == 1) parent->tChild = new Window; parent->tChild[parent->nTChildren - 1] = x11_window; } XGetWindowProperty (display, win->window, motifAtom, 0L, 20L, false, motifAtom, &adummy, &idummy, &udummy, &udummy, (unsigned char **) &motif_hints); if (motif_hints) { if ((motif_hints->flags & (1l << 1)) && (!(motif_hints->decorations & (1l << 0)))) { if ((motif_hints->decorations & (1l << 3)) == 0) win->hasTitlebar = false; else win->hasTitlebar = true; } } XFree(motif_hints); set_attrib.do_not_propagate_mask = ButtonPressMask|ButtonReleaseMask|ButtonMotionMask; set_attrib.event_mask = ExposureMask | ButtonPressMask | ButtonReleaseMask | PropertyChangeMask | SubstructureRedirectMask | FocusChangeMask | SubstructureNotifyMask | EnterWindowMask | LeaveWindowMask; set_attrib.background_pixel = COLOR_MAIN; //BlackPixel (display, screen); set_attrib.override_redirect = false;//true; if (win->hasTitlebar == true) win->titlebar = XCreateWindow (display, root, win->x, win->y - 20, win->width, win->height + 20, 0, DefaultDepth (display, screen), CopyFromParent, DefaultVisual (display, screen), CWBackPixel | CWEventMask | CWOverrideRedirect |CWDontPropagate, &set_attrib); XAddToSaveSet (display, win->window); XChangeWindowAttributes(display,win->window, CWDontPropagate, &set_attrib); XSelectInput (display, win->window, PropertyChangeMask | FocusChangeMask); if (win->hasTitlebar == true) XReparentWindow (display, win->window, win->titlebar, 0, 20); if (topWindow == 0) topWindow = win; win->prev = lastWindow; if (lastWindow != 0) lastWindow->next = win; lastWindow = win; win->next = 0; XSync (display, false); //XMapRaised(display,win->titlebar); if((win->GetState() == NormalState)|| (win->GetState() == WithdrawnState)) { if(win->GetState() == NormalState) { printf("Give Focus\n"); SetFocus(win); } if(win->GetState() == WithdrawnState) Hide(win); } else { Hide(win); } printf("---------------------\n"); Redraw (win); XUngrabServer (display); SetFocus (win); } Novawm_Window * WinMgr::WindowSearch (Window x11_window) { if (x11_window == root || x11_window == rootMenu.menuWindow () || x11_window == windowMenu.menuWindow ()) return 0; for (Novawm_Window * SearchWin = topWindow; SearchWin; SearchWin = SearchWin->next) { if ((SearchWin->window == x11_window) || (SearchWin->titlebar == x11_window)) //|| // (SearchWin->stretch == x11_window) || // (SearchWin->kill == x11_window) || // (SearchWin->hide == x11_window)) { return SearchWin; } } return 0; } void WinMgr::Redraw (Novawm_Window * novawm_window) { XClearWindow (display, novawm_window->titlebar); XDrawString (display, novawm_window->titlebar, novawm_gc, 4, 13, novawm_window->title, strlen (novawm_window->title)); //Draw Raised Border for the titlebar XDrawLine (display,novawm_window->titlebar,novawm_gc,0,0,0,20); XDrawLine (display,novawm_window->titlebar,novawm_gc,0,0, novawm_window->width,0); XSetForeground (display,novawm_gc,BlackPixel(display,screen)); XDrawLine (display,novawm_window->titlebar,novawm_gc,1,19, novawm_window->width,19); XDrawLine (display,novawm_window->titlebar,novawm_gc, novawm_window->width-1,1,novawm_window->width-1,20); XSetForeground (display,novawm_gc,WhitePixel(display,screen)); } void WinMgr::Move (Novawm_Window * novawm_window) { XEvent event; XConfigureEvent configEvent; Window wdummy; int x, y, winx, winy; unsigned int mdummy; int idummy; XGrabPointer (display, novawm_window->titlebar, false, ButtonReleaseMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, None, MoveCursor, CurrentTime); //XGrabServer (display); XQueryPointer (display, novawm_window->titlebar, &wdummy, &wdummy, &x, &y, &winx, &winy, &mdummy); configEvent.type = ConfigureNotify; configEvent.event = novawm_window->window; configEvent.window = novawm_window->window; configEvent.width = novawm_window->width; configEvent.height = novawm_window->height; configEvent.border_width = 0; configEvent.above = Below; configEvent.override_redirect = false; while (1) { XMaskEvent (display, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &event); switch (event.type) { //case Expose: For redrawing window contents as they get erased // wmevents.RedrawTitlebar(WindowSearch(event.xexpose.window)); // break; case MotionNotify: XQueryPointer (display, novawm_window->titlebar, &wdummy, &wdummy, &x, &y, &idummy, &idummy, &mdummy); XMoveWindow (display, novawm_window->titlebar, x - winx, y - winy); //wmevents.RedrawTitlebar (novawm_window); //wmevents.RedrawNovabar (); novawm_window->x = x; novawm_window->y = y; break; case ButtonRelease: novawm_window->x = x; novawm_window->y = y; //XUngrabServer (display); XUngrabPointer (display, CurrentTime); configEvent.x = x; configEvent.y = y; XSendEvent (display, novawm_window->window, false, StructureNotifyMask, (XEvent *) & configEvent); //Update the Window return; break; } } } void WinMgr::Stretch (Novawm_Window * novawm_window) { XConfigureEvent configEvent; configEvent.type = ConfigureNotify; configEvent.event = novawm_window->window; configEvent.window = novawm_window->window; configEvent.x = novawm_window->x; configEvent.y = novawm_window->y; configEvent.border_width = 0; configEvent.above = Below; configEvent.override_redirect = false; //Check if it is already stretched if ((novawm_window->width != novawm_window->orig_width) && (novawm_window->height != novawm_window->orig_height)) { if (novawm_window->hasTitlebar != true) //Has no titlebar { novawm_window->width = novawm_window->orig_width; novawm_window->height = novawm_window->orig_height; configEvent.width = novawm_window->orig_width; configEvent.height = novawm_window->orig_height; XResizeWindow (display, novawm_window->window, novawm_window->orig_width, novawm_window->orig_height); XSendEvent (display, novawm_window->window, false, StructureNotifyMask, (XEvent *) & configEvent); return; } else //Has a titlebar { novawm_window->width = novawm_window->orig_width; novawm_window->height = novawm_window->orig_height; configEvent.width = novawm_window->orig_width; configEvent.height = novawm_window->orig_height; XResizeWindow (display, novawm_window->window, novawm_window->orig_width, novawm_window->orig_height); XResizeWindow (display, novawm_window->titlebar, novawm_window->orig_width, novawm_window->orig_height + 20); XSendEvent (display, novawm_window->window, false, StructureNotifyMask, (XEvent *) & configEvent); return; } } //Stretch to fullscreen else { if (novawm_window->hasTitlebar != true) //Has no titlebar { } else { novawm_window->x = 0; novawm_window->y = 0; novawm_window->orig_width = novawm_window->width; novawm_window->orig_height = novawm_window->height; novawm_window->width = XDisplayWidth (display, screen); novawm_window->height = XDisplayHeight (display, screen) - 20; configEvent.width = XDisplayWidth (display, screen); configEvent.height = XDisplayHeight (display, screen) - 20; configEvent.x = 0; configEvent.y = 0; XMoveWindow (display, novawm_window->titlebar, 0, 0); XResizeWindow (display, novawm_window->window, XDisplayWidth (display, screen), XDisplayHeight (display, screen) - 20); XResizeWindow (display, novawm_window->titlebar, XDisplayWidth (display, screen), XDisplayHeight (display, screen)); XSendEvent (display, novawm_window->window, false, StructureNotifyMask, (XEvent *) & configEvent); return; } } } void WinMgr::Raise (Novawm_Window * novawm_window) { if (!novawm_window) return; novawm_window->SetState(NormalState); if (novawm_window->hasTitlebar != true) XMapRaised (display, novawm_window->window); else { XMapRaised (display, novawm_window->titlebar); XMapRaised (display, novawm_window->window); } if(novawm_window->ignoreTransient != true) { if (novawm_window->nTChildren > 0) { for (int i = 0; i < novawm_window->nTChildren; i++) { //Raise any windows transient to this one Raise (WindowSearch (novawm_window->tChild[i])); } } } } void WinMgr::SetFocus (Novawm_Window * novawm_window) { focusWindow = novawm_window; Raise (novawm_window); } void WinMgr::Hide (Novawm_Window * novawm_window) { if(!novawm_window) return; if (novawm_window->hasTitlebar != true) XUnmapWindow (display, novawm_window->window); else XUnmapWindow (display, novawm_window->titlebar); novawm_window->SetState (WithdrawnState); if (novawm_window->nTChildren > 0) { for (int i = 0; i < novawm_window->nTChildren; i++) { //Hide any windows transient to this one Hide (WindowSearch (novawm_window->tChild[i])); } } //if(focusWindow == novawm_window && novawm_window->prev) //SetFocus(novawm_window->prev); SetFocus (0); } void WinMgr::Resize (Novawm_Window * novawm_window) { XEvent event; XConfigureEvent configEvent; Window wdummy; XWindowAttributes win_attrib; int x, y, winx, winy; unsigned int mdummy; int idummy; XGrabPointer (display, novawm_window->titlebar, false, ButtonReleaseMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, None, MoveCursor, CurrentTime); XGrabServer (display); XQueryPointer (display, novawm_window->titlebar, &wdummy, &wdummy, &x, &y, &winx, &winy, &mdummy); configEvent.type = ConfigureNotify; configEvent.event = novawm_window->window; configEvent.window = novawm_window->window; configEvent.width = novawm_window->width; configEvent.height = novawm_window->height; configEvent.border_width = 0; configEvent.above = Below; configEvent.override_redirect = false; XGetWindowAttributes (display, novawm_window->window, &win_attrib); //I added this because of problems with the wrong values //Update size values novawm_window->width = win_attrib.width; novawm_window->height = win_attrib.height; novawm_window->orig_width = win_attrib.width; novawm_window->orig_height = win_attrib.height; XWarpPointer (display, None, root, 0, 0, 0, 0, novawm_window->x + novawm_window->width - 20, novawm_window->y + novawm_window->height + 22); while (1) { XMaskEvent (display, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &event); switch (event.type) { case MotionNotify: XQueryPointer (display, root, &wdummy, &wdummy, &idummy, &idummy, &x, &y, &mdummy); XResizeWindow (display, novawm_window->titlebar, x - novawm_window->x - 2, y - novawm_window->y - 2); XResizeWindow (display, novawm_window->window, x - novawm_window->x - 2, y - novawm_window->y - 26); novawm_window->width = x - novawm_window->x - 2; novawm_window->height = y - novawm_window->y - 26; novawm_window->orig_width = x - novawm_window->x - 2; novawm_window->orig_height = y - novawm_window->y - 26; break; case ButtonRelease: XUngrabServer (display); XUngrabPointer (display, CurrentTime); configEvent.width = novawm_window->width; configEvent.height = novawm_window->height; XSendEvent (display, novawm_window->window, false, StructureNotifyMask, (XEvent *) & configEvent); return; break; } } } void WinMgr::Kill (Novawm_Window * novawm_window) { Atom *pCheck; XEvent deleteEvent; int nProtocols; if (!novawm_window) return; deleteEvent.type = ClientMessage; deleteEvent.xclient.window = novawm_window->window; deleteEvent.xclient.message_type = protocolAtom; deleteEvent.xclient.format = 32; deleteEvent.xclient.data.l[0] = deleteAtom; deleteEvent.xclient.data.l[1] = CurrentTime; int deleted = 0; if (!novawm_window->window) { XDestroyWindow (display, novawm_window->titlebar); novawm_window->Destroy (); } XGetWMProtocols (display, novawm_window->window, &pCheck, &nProtocols); for (int i = 0; i < nProtocols; i++) { if (pCheck[i] == deleteAtom) { deleted = 1; XSendEvent (display, novawm_window->window, false, NoEventMask, &deleteEvent); // unmapignore++; break; } } if (pCheck) XFree (pCheck); if (deleted != 1) //The Window doesn't support the Delete Protocol { XKillClient (display, novawm_window->window); //Safe? //unmapignore++; } } void WinMgr::Create_ListMenu (int menu_x, int menu_y) { listMenu.Clear (); //Clear the menu if (!topWindow) //There are no windows to manage { listMenu.AddItem ("No windows to manage!"); return; } nListWindow = 0; /* if(listWindow != 0) { printf("novawm: debug: list menu wasn't cleared! Aborting...\n"); delete listWindow; listWindow = 0; // return; } */ //listWindow = new Novawm_Window *; for (Novawm_Window * currentWindow = topWindow; currentWindow; currentWindow = currentWindow->next) { if(currentWindow->isTransient != true) { listMenu.AddItem (currentWindow->title); nListWindow++; } } listMenu.Create (menu_x, menu_y); } void WinMgr::listMenu_Click (int item) { if (item > nListWindow && item < 0) return; int i = 0; for (Novawm_Window * cWindow = topWindow; cWindow || i >= nListWindow; cWindow = cWindow->next) { if(cWindow->isTransient != true) { if (i == item) { SetFocus (cWindow); break; } i++; } //listWindow[item]); } //Clear list nListWindow = 0; // if(listWindow) // delete listWindow; //listWindow = 0; } void Novawm_Window::Destroy () { //XRemoveFromSaveSet (display, window); if (prev) prev->next = next; if (next) next->prev = prev; if (winmgr->topWindow == this) winmgr->topWindow = prev; if (winmgr->lastWindow == this) winmgr->lastWindow = prev; if (winmgr->focusWindow == this) winmgr->SetFocus (prev); delete this; } int Novawm_Window::GetState () { Atom gState; int format; unsigned long dummy; long *data; int get_state = WithdrawnState; XGetWindowProperty (display, window, stateAtom, 0L, 2L, false, stateAtom, &gState, &format, &dummy, &dummy, (unsigned char **) &data); if(data) get_state = *data; printf("STATE %d\n",get_state); XFree (data); return get_state; } void Novawm_Window::SetState (int set_state) { CARD32 data[2]; state = set_state; data[0] = set_state; data[1] = None; XChangeProperty (display, window, stateAtom, stateAtom, 32, PropModeReplace, (unsigned char *) data, 2); printf("STATE %d\n",GetState()); }