//////////////////////////////////////////////
// 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"
void
Events::NovaWM_EventLoop ()
{
XEvent event;
fd_set fd;
struct timeval tv;
time_t now;
struct tm *lt;
int i;
int xfd = ConnectionNumber (display);
while (1)
{
now = time (0);
lt = gmtime (&now);
tv.tv_usec = 0;
tv.tv_sec = 60 - lt->tm_sec;
FD_ZERO (&fd);
FD_SET (xfd, &fd);
if (select (xfd + 1, &fd, 0, 0, &tv) == 0)
novawm.UpdateClock ();
while (XPending (display))
{
XNextEvent (display, &event);
switch (event.type)
{
case Expose:
Event_Expose (&event.xexpose);
break;
case ButtonPress:
Event_ButtonDown (&event.xbutton);
break;
case ButtonRelease:
Event_ButtonUp (&event.xbutton);
break;
case MotionNotify:
Event_Motion (&event.xcrossing);
break;
case MapRequest:
Event_Map (&event.xmaprequest);
break;
case UnmapNotify:
Event_Unmap (&event.xunmap);
break;
case DestroyNotify:
Event_Destroy (&event.xdestroywindow);
break;
case ConfigureRequest:
Event_Configure (&event.xconfigurerequest);
break;
case PropertyNotify:
Event_Property (&event.xproperty);
break;
case ColormapNotify:
Event_Colormap (&event.xcolormap);
break;
case ClientMessage:
Event_ClientMessage (&event.xclient);
break;
case FocusIn:
Event_FocusIn (&event.xfocus);
break;
case FocusOut:
Event_FocusOut (&event.xfocus);
break;
case EnterNotify:
Event_EnterWindow (&event.xcrossing);
break;
case LeaveNotify:
Event_LeaveWindow (&event.xcrossing);
break;
case KeyRelease:
Event_KeyUp (&event.xkey);
}
}
}
}
void
Events::Event_Expose (XExposeEvent * event)
{
#ifdef DEBUG
//printf ("DEBUG Expose()\n");
#endif
Novawm_Window *window = winmgr.WindowSearch (event->window);
if (event->window == rootMenu.menuWindow ())
{
rootMenu.DrawItems ();
}
if (event->window == listMenu.menuWindow ())
{
listMenu.DrawItems ();
}
if (event->window == windowMenu.menuWindow ())
{
windowMenu.DrawItems ();
}
if ((event->window == novawm.NovaBar)
|| (event->window == novawm.nbClock)
|| (event->window == novawm.nbCurWin)
|| (event->window == novawm.nbListButton)
|| (event->window == novawm.nbButton))
{
//This was added for Nautilus problems but removed
//because the bar would show up in full screen apps(like games)
//XRaiseWindow (display, novawm.NovaBar);
novawm.DrawBar ();
}
if (event->window == novawm.nbWinList)
novawm.DrawWinList ();
if (!window)
return;
winmgr.Redraw (window);
}
void
Events::Event_ButtonDown (XButtonEvent * event)
{
#ifdef DEBUG
printf ("DEBUG ButtonDown()\n");
#endif
if ((event->window == novawm.nbListButton) ||
(event->window == novawm.nbButton) ||
(event->window == novawm.nbWLstScrllUp) ||
(event->window == novawm.nbWLstScrllDwn))
{
DrawDown (event->window);
return;
}
Novawm_Window *window = winmgr.WindowSearch (event->window);
if (!window)
return;
// window->ignoreTransient = true;
// winmgr.SetFocus (window);
// window->ignoreTransient = false;
if (cfg.disableBar == true)
{
if (listMenu.isOpen () == true)
listMenu.Destroy ();
if (windowMenu.isOpen () == true)
windowMenu.Destroy ();
if (rootMenu.isOpen () == true)
rootMenu.Destroy ();
}
//Check the titlebar buttons
if (event->button == Button1)
{
if ((event->window == window->kill) ||
(event->window == window->stretch) ||
(event->window == window->hide))
{
DrawDown (event->window);
return;
}
}
XAllowEvents (display, ReplayPointer, CurrentTime);
if (window != winmgr.focusWindow) //Raise and give focus to the window
{
window->ignoreTransient = true;
winmgr.SetFocus (window);
window->ignoreTransient = false;
return;
}
if (event->y > 18) //Make sure it IS on the titlebar
return;
if (event->button == Button1 && window->titlebar == event->window)
{
window->ignoreTransient = true;
winmgr.SetFocus (window);
window->ignoreTransient = false;
winmgr.Move (window);
}
}
void
Events::Event_ButtonUp (XButtonEvent * event)
{
#ifdef DEBUG
printf ("DEBUG ButtonUp()\n");
#endif
if (downWindow)
{
if (event->window == novawm.nbButton)
{
downWindow = None;
novawm.DrawBar ();
}
else
{
DrawUp (downWindow);
downWindow = None;
}
}
//Always close the menus after another click
if (novaMenu.isOpen () == true)
{
if (event->window == novaMenu.menuWindow ())
novawm.novaMenu_Click (novaMenu.GetSelection ());
novaMenu.Destroy ();
}
if (rootMenu.isOpen () == true)
{
if (event->window == rootMenu.menuWindow ())
rootMenu_Click (rootMenu.GetSelection ());
rootMenu.Destroy ();
}
if (listMenu.isOpen () == true)
{
if (event->window == listMenu.menuWindow ())
winmgr.listMenu_Click (listMenu.GetSelection ());
listMenu.Destroy ();
}
if (windowMenu.isOpen () == true)
{
if (event->window == windowMenu.menuWindow ())
windowMenu_Click (windowMenu.GetSelection ());
windowMenu.Destroy ();
}
if (cfg.disableBar == true)
{
if (event->window == root && event->button == Button2)
{
if (listMenu.isOpen () != true)
winmgr.Create_ListMenu (event->x_root, event->y_root);
else
{
winmgr.nListWindow = 0;
// if(winmgr.listWindow)
// delete winmgr.listWindow;
listMenu.Destroy ();
}
}
if (event->window == root && event->button == Button3)
{
if (rootMenu.isOpen () != true)
rootMenu.Create (event->x_root, event->y_root);
else
rootMenu.Destroy ();
}
}
if (event->window == novawm.nbButton)
if (novaMenu.isOpen () != true)
novaMenu.Create (novawm.bar_x, NOVABAR_HEIGHT + 1);
else
novaMenu.Destroy ();
if (event->window == novawm.nbWLstScrllUp)
novawm.List_Scroll (-1);
if (event->window == novawm.nbWLstScrllDwn)
novawm.List_Scroll (1);
//Get selection and close window list
if ((novawm.lstItems >= 0)
&& (event->window != novawm.nbWLstScrllDwn) &&
(event->window != novawm.nbWLstScrllUp) &&
(event->window != novawm.nbWLstScrllBar))
{
//A item is selected, give it focus
if ((novawm.selItem + novawm.topItem >= 0)
&& (novawm.selItem + novawm.topItem <= novawm.lstItems)
&& (event->window == novawm.nbWLstItemWin))
{
//The selection handling here is the same with the menu.
winmgr.listMenu_Click (novawm.selItem + novawm.topItem);
}
//Close the window list
novawm.DestroyWinList ();
}
if (event->window == novawm.nbListButton)
{
novawm.CreateWinList ();
return;
}
Novawm_Window *window = winmgr.WindowSearch (event->window);
if (!window)
return;
//Check the titlebar buttons
if (event->window == window->kill)
winmgr.Kill (window);
if (event->window == window->stretch)
winmgr.Stretch (window);
if (event->window == window->hide)
winmgr.Hide (window);
if (event->window == window->titlebar && event->button == Button2)
window->Shade ();
if (event->window == window->titlebar && event->button == Button3)
{
if (windowMenu.isOpen () != true)
windowMenu.Create (event->x_root, event->y_root);
else
windowMenu.Destroy ();
}
}
void
Events::Event_Map (XMapRequestEvent * event)
{
#ifdef DEBUG
printf ("DEBUG: Map()\n");
#endif
Novawm_Window *window = winmgr.WindowSearch (event->window);
if (!window)
{
winmgr.NewWindow (event->window);
return;
}
winmgr.NewWindow (event->window);
if (window->hasTitlebar == true)
XMapWindow (display, window->titlebar);
XMapWindow (display, window->window);
window->SetState (NormalState);
}
void
Events::Event_Unmap (XUnmapEvent * event)
{
#ifdef DEBUG
printf ("DEBUG Unmap()\n");
#endif
Novawm_Window *window = winmgr.WindowSearch (event->window);
if (winmgr.Find_UnmapIgnore (event->window) == 1)
{
#ifdef DEBUG
printf ("novawm: DEBUG: ignoring unmap\n");
#endif
winmgr.RemoveUnmapIgnore (event->window); //unmapignore--;
return;
}
XUnmapWindow(display,event->window);
if (!window)
{
#ifdef DEBUG
printf ("DEBUG: Ignoring unmanaged window.\n");
#endif
// XUnmapWindow (display, event->window);
return;
}
#ifdef DEBUG
printf ("DEBUG: Unmap() -- Destroying window.\n");
#endif
window->Destroy ();
}
void
Events::Event_Motion (XCrossingEvent * event)
{
//#ifdef DEBUG
// printf("DEBUG Motion()\n");
//#endif
if (event->window == novawm.nbWLstItemWin)
novawm.HighlightListItem (event->y);
if (event->window == rootMenu.menuWindow ())
rootMenu.HighlightItem (event->x, event->y);
if (event->window == windowMenu.menuWindow ())
windowMenu.HighlightItem (event->x, event->y);
if (event->window == novaMenu.menuWindow ())
novaMenu.HighlightItem (event->x, event->y);
if (event->window == listMenu.menuWindow ())
listMenu.HighlightItem (event->x, event->y);
}
void
Events::Event_Destroy (XDestroyWindowEvent * event)
{
#ifdef DEBUG
printf ("DEBUG Destroy()\n");
#endif
Novawm_Window *win = winmgr.WindowSearch (event->window);
if (!win) //Ignore destroy events of unmanaged windows
{
// XDestroyWindow (display, event->window);
return;
}
win->Destroy ();
}
void
Events::Event_Configure (XConfigureRequestEvent * event)
{
#ifdef DEBUG
printf ("DEBUG Configure()\n");
#endif
Novawm_Window *window = winmgr.WindowSearch (event->window);
XWindowChanges winchange;
winchange.x = event->x;
winchange.y = event->y;
winchange.width = event->width;
winchange.height = event->height;
winchange.sibling = event->above;
winchange.stack_mode = event->detail;
if (!window) //Not Managed
{
XConfigureWindow (display, event->window, event->value_mask,
&winchange);
XRaiseWindow (display, event->window);
// winmgr.NewWindow (event->window);
}
else //Managed
{
window->x = event->x;
window->y = event->y;
window->orig_x = event->x;
window->orig_y = event->y;
window->width = event->width;
window->height = event->height;
window->orig_width = event->width;
window->orig_height = event->height;
if (window->hasTitlebar != true) //Doesn't have a titlebar
{
XMoveWindow (display, window->window, event->x, event->y);
}
else //Has a titlebar
{
XMoveWindow (display, window->titlebar, event->x, event->y);
XResizeWindow (display, window->titlebar,
event->width, event->height + 20);
}
XResizeWindow (display, window->window, event->width, event->height);
//Move the titlebar buttons
XMoveWindow (display, window->kill, window->width - 19, 3);
XMoveWindow (display, window->stretch, window->width - 37, 3);
XMoveWindow (display, window->hide, window->width - 54, 3);
//XRaiseWindow (display, window->titlebar);
//XRaiseWindow (display, window->window);
window->ignoreTransient = true;
winmgr.SetFocus (window);
window->ignoreTransient = false;
}
}
void
Events::Event_Property (XPropertyEvent * event)
{
char *title;
#ifdef DEBUG
printf ("DEBUG Property()\n");
#endif
Novawm_Window *window = winmgr.WindowSearch (event->window);
if (!window)
return;
if (event->atom == XA_WM_NAME)
{
XFetchName (display, window->window, &title);
if (!title)
window->title = "Unknown";
else
window->title = title;
XClearWindow (display, window->titlebar);
winmgr.Redraw (window);
novawm.DrawBar ();
}
}
void
Events::Event_Colormap (XColormapEvent * event)
{
#ifdef DEBUG
printf ("DEBUG ColormapNotify()\n");
#endif
Novawm_Window *window = winmgr.WindowSearch (event->window);
if (!window)
return;
if (event->c_new) //New Colormap
{
window->colorMap = event->c_new;
XInstallColormap (display, event->c_new);
}
}
void
Events::Event_ClientMessage (XClientMessageEvent * event)
{
#ifdef DEBUG
printf ("DEBUG ClientMessage()\n");
#endif
#ifdef _WIN_GNOME_SUPPORT
if ((event->message_type == winProtocols_Workspace) &&
(event->window == root))
{
winmgr.SetDesktop (event->data.l[0]);
return;
}
#endif
Novawm_Window *window = winmgr.WindowSearch (event->window);
if (!window)
return;
if (event->message_type == netStateAtom)
{
if ((event->data.l[1] == netStateStickyAtom)
|| (event->data.l[2] == netStateStickyAtom))
{
if (event->data.l[0] == _NET_WM_STATE_ADD)
window->isSticky = true;
if (event->data.l[0] == _NET_WM_STATE_REMOVE)
window->isSticky = false;
if (event->data.l[0] == _NET_WM_STATE_TOGGLE)
window->isSticky = (window->isSticky) ? true : false;
}
}
if (event->message_type == netDesktopAtom)
{
winmgr.SendToDesktop (window, event->data.l[0]);
return;
}
#ifdef _WIN_GNOME_SUPPORT
if (event->message_type == winProtocols_Workspace)
{
winmgr.SendToDesktop (window, event->data.l[0]);
return;
}
#endif
if (event->data.l[0] == IconicState)
{
winmgr.Hide (window);
}
if (event->data.l[0] == NormalState)
{
winmgr.SetFocus (window);
}
}
void
Events::Event_FocusIn (XFocusChangeEvent * event)
{
#ifdef DEBUG
printf ("DEBUG: FocusIn()\n");
#endif
Novawm_Window *window = winmgr.WindowSearch (event->window);
if (!window)
return;
//protocolAtom,SubstructureRedirectMask,takefocusAtom
XEvent sendEvent;
sendEvent.type = ClientMessage;
sendEvent.xclient.window = window->window;
sendEvent.xclient.message_type = protocolAtom;
sendEvent.xclient.format = 32;
sendEvent.xclient.data.l[0] = takefocusAtom;
XSendEvent (display, window->window, false, SubstructureRedirectMask,
&sendEvent);
//Grab the previous desktop key
XGrabKey (display, XKeysymToKeycode (display, XK_bracketleft),
ControlMask, event->window, true, GrabModeAsync, GrabModeAsync);
//Grab the next desktop key
XGrabKey (display, XKeysymToKeycode (display, XK_bracketright),
ControlMask, event->window, true, GrabModeAsync, GrabModeAsync);
//Set the colormap (Only added colormap support for a few programs)
XInstallColormap (display, window->colorMap);
/* XGrabButton(display,Button1,AnyModifier,
window->window,
1,ButtonPressMask,
GrabModeSync,GrabModeAsync,
None,None);
*/
}
void
Events::Event_FocusOut (XFocusChangeEvent * event)
{
#ifdef DEBUG
printf ("DEBUG FocusOut\n");
#endif
Novawm_Window *window = winmgr.WindowSearch (event->window);
if (!window)
return;
if (event->mode == NotifyNormal)
{
winmgr.focusWindow = 0;
}
//Grab the previous desktop key
XUngrabKey (display, XKeysymToKeycode (display, XK_bracketleft),
ControlMask, event->window);
//Grab the next desktop key
XUngrabKey (display, XKeysymToKeycode (display, XK_bracketright),
ControlMask, event->window);
XSetInputFocus (display, root, RevertToNone, CurrentTime);
// XUngrabButton(display,Button1,AnyModifier,
// window->window);
}
void
Events::Event_EnterWindow (XCrossingEvent * event)
{
Novawm_Window *window = winmgr.WindowSearch (event->window);
if (!window)
return;
if (focusType == 0)
XSetInputFocus (display, window->window, RevertToNone, CurrentTime);
if (event->window == window->hide)
XSetInputFocus (display, window->hide, RevertToNone, CurrentTime);
if (event->window == window->stretch)
XSetInputFocus (display, window->stretch, RevertToNone, CurrentTime);
if (event->window == window->kill)
XSetInputFocus (display, window->kill, RevertToNone, CurrentTime);
}
void
Events::Event_LeaveWindow (XCrossingEvent * event)
{
Novawm_Window *window = winmgr.WindowSearch (event->window);
if (!window)
return;
if ((event->window == window->kill)
|| (event->window == window->stretch)
|| (event->window == window->hide))
XSetInputFocus (display, window->window, RevertToNone, CurrentTime);
}
void
Events::Event_KeyUp (XKeyEvent * event)
{
#ifdef DEBUG
printf ("DEBUG: KeyUp()\n");
#endif
KeySym keysym = XKeycodeToKeysym (display, event->keycode, 0);
switch (keysym)
{
case XK_bracketleft:
winmgr.SetDesktop (winmgr.cDesktop - 1);
break;
case XK_bracketright:
winmgr.SetDesktop (winmgr.cDesktop + 1);
break;
}
}
void
Events::rootMenu_Click (int item)
{
if (item == 0) //xterm
novawm.Run ("xterm");
if (item == 5) //Restart
novawm.Restart ();
if (item == 6) //Shutdown
novawm.Shutdown ();
}
void
Events::windowMenu_Click (int item)
{
if (item == 0)
{
winmgr.Hide (winmgr.focusWindow);
}
if (item == 1)
winmgr.Stretch (winmgr.focusWindow);
if (item == 2)
winmgr.Resize (winmgr.focusWindow);
if (item == 3)
winmgr.Kill (winmgr.focusWindow);
//Item 4 is the divider/splitter line
if (item == 5)
winmgr.SendToDesktop (winmgr.focusWindow, 0);
if (item == 6)
winmgr.SendToDesktop (winmgr.focusWindow, 1);
if (item == 7)
winmgr.SendToDesktop (winmgr.focusWindow, 2);
if (item == 8)
winmgr.SendToDesktop (winmgr.focusWindow, 3);
if (item == 9)
winmgr.SendToDesktop (winmgr.focusWindow, winmgr.cDesktop + 1);
if (item == 10)
winmgr.SendToDesktop (winmgr.focusWindow, winmgr.cDesktop - 1);
}
//The following DrawDown() and DrawUp() functions were mainly
//created button borders
//This is to simplify drawing a lowered/down border of a window
void
Events::DrawDown (Window window)
{
#ifdef DEBUG
//printf ("DEBUG: DrawDown()\n");
#endif
XWindowAttributes win_attrib;
XGetWindowAttributes (display, window, &win_attrib);
downWindow = window;
XSetForeground (display, novawm_gc, BlackPixel (display, screen));
XDrawLine (display, window, novawm_gc, 0, 0, win_attrib.width, 0);
XDrawLine (display, window, novawm_gc, 0, 0, 0, win_attrib.height);
XSetForeground (display, novawm_gc, WhitePixel (display, screen));
XDrawLine (display, window, novawm_gc, 0, win_attrib.height - 1,
win_attrib.width, win_attrib.height - 1);
XDrawLine (display, window, novawm_gc, win_attrib.width - 1, 1,
win_attrib.width - 1, win_attrib.height);
}
//This is to simplify drawing a raised/up border of a window
void
Events::DrawUp (Window window)
{
#ifdef DEBUG
//printf ("DEBUG: DrawUp()\n");
#endif
XWindowAttributes win_attrib;
XGetWindowAttributes (display, window, &win_attrib);
downWindow = window;
XSetForeground (display, novawm_gc, BlackPixel (display, screen));
XDrawLine (display, window, novawm_gc, 0, win_attrib.height - 1,
win_attrib.width, win_attrib.height - 1);
XDrawLine (display, window, novawm_gc, win_attrib.width - 1, 1,
win_attrib.width - 1, win_attrib.height);
XSetForeground (display, novawm_gc, WhitePixel (display, screen));
XDrawLine (display, window, novawm_gc, 0, 0, win_attrib.width, 0);
XDrawLine (display, window, novawm_gc, 0, 0, 0, win_attrib.height);
}
syntax highlighted by Code2HTML, v. 0.9.1