/*
* windowmanager.cc
* Copyright (C) 2000 Frank Hale
* frankhale@yahoo.com
* http://sapphire.sourceforge.net/
*
* Updated: 1 Feb 2002
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "aewm.hh"
WindowManager* wm;
using namespace std;
#define AEWM_KEY_ALT_COUNT 23
KeySym WindowManager::AltKeys[]={
XK_y, XK_u, XK_b, XK_n,
XK_h, XK_j, XK_k, XK_l,
XK_a, XK_f,
XK_z, XK_x, XK_c,
XK_o, XK_m,
XK_space,
XK_Tab,
XK_Return,
XK_Escape,
XK_Delete,
XK_End,
XK_Page_Up,
XK_Page_Down};
WindowManager::WindowManager(int argc, char** argv)
{
int i;
struct sigaction act;
// Set the global window manager object to this please =)
wm = this;
window_manager_name=(char *)"jewel";
// Make the default options equal something
opt_font = (char *)DEF_FONT;
opt_fm = (char *)DEF_FM;
opt_fg = (char *)DEF_FG;
opt_fc = (char *)DEF_FC;
opt_bg = (char *)DEF_BG;
opt_bd = (char *)DEF_BD;
opt_tj = (char *)TEXT_JUSTIFY;
opt_wm = (char *)WIRE_MOVE;
opt_es = (char *)EDGE_SNAP;
opt_newkey = (char *)DEF_NEWKEY;
opt_new1 = (char *)DEF_NEW1;
opt_new2 = (char *)DEF_NEW2;
opt_bw = DEF_BW;
opt_display=NULL;
maxDesktops=MAX_DESKTOPS;
// These macro's are nice to test values passed in
// the command line arguments
#define OPT_STR(name, variable) \
if (strcmp(argv[i], name) == 0 && i+1<argc) { \
variable = argv[++i]; \
continue; \
}
#define OPT_INT(name, variable) \
if (strcmp(argv[i], name) == 0 && i+1<argc) { \
variable = atoi(argv[++i]); \
continue; \
}
for (i = 0; i < argc; i++)
command_line = command_line + argv[i] + " ";
// Get the args and test for different options
for (i = 1; i < argc; i++)
{
OPT_STR("-fn", opt_font)
OPT_STR("-fg", opt_fg)
OPT_STR("-bg", opt_bg)
OPT_STR("-fc", opt_fc)
OPT_STR("-fm", opt_fm)
OPT_STR("-bd", opt_bd)
OPT_INT("-bw", opt_bw)
OPT_STR("-tj", opt_tj)
OPT_STR("-wm", opt_wm)
OPT_STR("-es", opt_es)
OPT_INT("-md", maxDesktops)
OPT_STR("-newkey", opt_newkey)
OPT_STR("-new1", opt_new1)
OPT_STR("-new2", opt_new2)
OPT_STR("-display", opt_display)
if (strcmp(argv[i], "-version") == 0) {
cout << window_manager_name << ": version " << VERSION << EXTRA_VERSION_INFO << endl;
exit(0);
}
if(strcmp(argv[i], "-usage")==0) {
cerr << "usage: jewel [options]" << endl;
cerr << " options are: -display <display>, -fn <font>, -fg|-bg|-bd <color>, " << endl;
cerr << " -bw <width>, -md <max desktops>, -mw <true|false> -tj <left|center|right>," << endl;
cerr << " -wm <true|false>, -new1|-new2|-newkey <cmd>, -fm <follow|sloppy|click>, -usage" << endl;
exit(0);
}
}
// Set the focus model based on user defined option
if (strcmp(opt_fm, "follow")==0) setFocusModel(FOCUS_FOLLOW);
else if (strcmp(opt_fm, "sloppy")==0) setFocusModel(FOCUS_SLOPPY);
else if (strcmp(opt_fm, "click")==0) setFocusModel(FOCUS_CLICK);
else setFocusModel(FOCUS_SLOPPY);
// Set up the window title justification per user defined option
if(strcmp(opt_tj, "left")==0) opt_text_justify = LEFT_JUSTIFY;
else if(strcmp(opt_tj, "center")==0) opt_text_justify = CENTER_JUSTIFY;
else if(strcmp(opt_tj, "right")==0) opt_text_justify = RIGHT_JUSTIFY;
else opt_text_justify = LEFT_JUSTIFY;
// Set wire move based on user defined option
if(strcmp(opt_wm, "true")==0) wire_move=true;
else if(strcmp(opt_wm, "false")==0) wire_move=false;
else wire_move=false;
// Set edge snapping based on user defined option
if(strcmp(opt_es, "true")==0) edge_snap=true;
else if(strcmp(opt_es, "false")==0) edge_snap=false;
else edge_snap=false;
// Don't let the user request more virtual desktops then
// our max desktop setting.
if(maxDesktops <= 0) maxDesktops=MAX_DESKTOPS;
// The current desktop on start is Zero
currentDesktop=0;
// The focused client is NULL (no clients yet!)
focusedClient=NULL;
clientCount=-1;
master_strut = new Strut;
master_strut->east = 0;
master_strut->west = 0;
master_strut->north = 0;
master_strut->south = 0;
clientStruts = new list<Strut *>;
// Set up the signal handlers so we can catch signals
// and respond accordingly.
act.sa_handler = sigHandler;
act.sa_flags = 0;
sigaction(SIGTERM, &act, NULL);
sigaction(SIGINT, &act, NULL);
sigaction(SIGHUP, &act, NULL);
sigaction(SIGCHLD, &act, NULL);
// The client list holds all client objects which
// represent X applications. Clients paint the titlebars
// and window decorations and manage the windows
// associated with the X application.
clientList = new list<Client *>;
setupDisplay();
scanWins();
updateIconMenu();
doEventLoop();
}
// The destructor cleans up allocated memory and exits cleanly. Hopefully! =)
WindowManager::~WindowManager()
{
}
void WindowManager::setFocusModel(int new_fm)
{
if (new_fm == FOCUS_FOLLOW || new_fm == FOCUS_SLOPPY || new_fm == FOCUS_CLICK)
focusModel = new_fm;
}
void WindowManager::grabKeys(Window w)
{
//MJR: Mask changed
for(int i=0;i<AEWM_KEY_ALT_COUNT;i++) {
XGrabKey(dpy,XKeysymToKeycode(dpy,AltKeys[i]), (ControlMask|Mod1Mask),w,True,GrabModeAsync,GrabModeAsync);
XGrabKey(dpy,XKeysymToKeycode(dpy,AltKeys[i]), (ControlMask|Mod1Mask|NumLockMask),w,True,GrabModeAsync,GrabModeAsync);
}
}
void WindowManager::ungrabKeys(Window w)
{
//MJR: mask changed
for(int i=0;i<AEWM_KEY_ALT_COUNT;i++) {
XUngrabKey(dpy,XKeysymToKeycode(dpy,AltKeys[i]), (ControlMask|Mod1Mask),w);
XUngrabKey(dpy,XKeysymToKeycode(dpy,AltKeys[i]), (ControlMask|Mod1Mask|NumLockMask),w);
}
}
void WindowManager::focusFocusedClient()
{
Window focus_win;
int revert;
Client *c;
XGetInputFocus(dpy, &focus_win, &revert);
c = findClient(focus_win);
if (focusedClient && focusedClient != c)
{
XSetInputFocus(dpy, focusedClient->getAppWindow(), RevertToNone, CurrentTime);
#ifdef DEBUG
cerr << "Focused client ";
if (focusedClient->getClientName())
cerr << focusedClient->getClientName() << endl;
else
cerr << "no name" << endl;
#endif
}
else if (!focusedClient && focus_win != gnome_button_proxy_win)
{
XSetInputFocus(dpy, gnome_button_proxy_win, RevertToNone, CurrentTime);
#ifdef DEBUG
cerr << "Focused gnome_button_proxy_win" << endl;
#endif
}
}
void WindowManager::setFocusedClient(Client *c)
{
if (!blockFocusChange) focusedClient = c;
}
void WindowManager::unsetFocusedClient()
{
Window p_root, p_par, *p_win;
Client* cand = NULL;
unsigned int n;
//MJR: FIXME: needs some work to find sensible focusee
XQueryTree(dpy, root, &p_root, &p_par, &p_win, &n);
//MJR: Find uppermost one with border
while (n>0)
{
cand = findClient(p_win[--n]);
if ((cand != NULL) && (cand->hasWindowDecorations())) n=0;
}
focusedClient = cand;
XFree(p_win);
}
void WindowManager::setFocusedClientUnderPointer()
{
Window p_root, p_win;
int x, y, win_x, win_y;
unsigned int mask;
XQueryPointer(dpy, root, &p_root, &p_win, &x, &y, &win_x, &win_y, &mask);
focusedClient = findClient(p_win);
}
void WindowManager::setCurrentDesktop(int desk)
{
if ( (desk < maxDesktops) && (desk > 0) ) currentDesktop = desk;
updateIconMenu();
}
void WindowManager::addClientToIconMenu(Client *c)
{
iconmenu->hide();
updateIconMenu();
}
void WindowManager::removeClientFromIconMenu(Client *c)
{
iconmenu->hide();
updateIconMenu();
}
void WindowManager::updateIconMenu()
{
list<Client *> *normalWindows = new list<Client *>;
list<Client *> *iconWindows = new list<Client *>;
iconmenu->hide();
iconmenu->removeAll();
iconmenu->initialSetup();
for(it = clientList->begin(); it != clientList->end(); it++)
{
if((*it)->belongsToWhichDesktop() == currentDesktop)
{
if((*it)->isIconified())
{
iconWindows->push_back((*it));
}
else {
normalWindows->push_back((*it));
}
}
}
if ( ! iconWindows->empty() ) {
iconmenu->insert("separator", "Icon List", -1);
for ( it = iconWindows->begin(); it != iconWindows->end(); it++ ) {
iconmenu->addThisClient((*it));
}
}
if ( !normalWindows->empty() ) {
iconmenu->insert("separator", "Window List", -1);
for ( it = normalWindows->begin(); it != normalWindows->end(); it++ ) {
iconmenu->addThisClient((*it));
}
}
iconmenu->updateIconMenu();
}
void WindowManager::goToDesktop(int d)
{
unsigned int nwins, i;
Window dummyw1, dummyw2, *wins;
Client* c;
if( (d < maxDesktops) && (d >= 0) )
{
currentDesktop = d;
updateIconMenu();
setGnomeHint(root, atom_gnome_win_workspace, currentDesktop);
setExtendedWMHint(root, atom_extended_net_current_desktop, currentDesktop);
// Preserve stacking order
XQueryTree(dpy, root, &dummyw1, &dummyw2, &wins, &nwins);
for (i = 0; i < nwins; i++)
{
c = findClient(wins[i]);
if(c)
{
if(! c->isSticky())
{
if(c->belongsToWhichDesktop() == currentDesktop)
{
if(! (c->isIconified()))
c->unhide();
}
else
{
if(! (c->isIconified()))
c->hide();
}
}
}
}
XFree(wins);
switch (focusModel)
{
case FOCUS_FOLLOW:
case FOCUS_SLOPPY:
unsetFocusedClient();
setFocusedClientUnderPointer();
break;
case FOCUS_CLICK:
unsetFocusedClient();
break;
}
}
}
void WindowManager::scanWins(void)
{
unsigned int nwins, i;
Window dummyw1, dummyw2, *wins;
XWindowAttributes attr;
Client *c=None;
XQueryTree(dpy, root, &dummyw1, &dummyw2, &wins, &nwins);
for(i = 0; i < nwins; i++)
{
XGetWindowAttributes(dpy, wins[i], &attr);
if (!attr.override_redirect && attr.map_state == IsViewable)
c = new Client(dpy, wins[i], clientList);
}
XFree(wins);
XMapWindow(dpy, gnome_button_proxy_win);
grabKeys(gnome_button_proxy_win);
unsetFocusedClient();
}
void WindowManager::setupDisplay(void)
{
XColor dummyc;
XGCValues gv;
XSetWindowAttributes sattr;
#ifdef SHAPE
int dummy;
#endif
if (opt_display)
setenv("DISPLAY", opt_display, 1);
else
opt_display = getenv("DISPLAY");
dpy = XOpenDisplay(opt_display);
if (!dpy) {
cerr << "can't open display! check your DISPLAY variable." << endl;
exit(1);
}
XSetErrorHandler(handleXError);
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
xres = WidthOfScreen(ScreenOfDisplay(dpy, screen));
yres = HeightOfScreen(ScreenOfDisplay(dpy, screen));
// BJP: Find the NumLockMask for keycombos
NumLockMask = 0;
unsigned int modmasks[] = {
Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
};
int row,col;
XModifierKeymap *mods;
mods = XGetModifierMapping(dpy);
for (row = 3; row < 8; row++) {
for (col = 0; col < mods->max_keypermod; col++) {
KeyCode code = mods->modifiermap[(row * mods->max_keypermod) + col];
if (code == 0) { continue; }
switch (XKeycodeToKeysym(dpy, code, 0)) {
case XK_Num_Lock:
NumLockMask |= modmasks[row - 3];
}
}
}
XFreeModifiermap (mods);
// ICCCM atoms
atom_wm_state = XInternAtom(dpy, "WM_STATE", False);
atom_wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False);
atom_wm_protos = XInternAtom(dpy, "WM_PROTOCOLS", False);
atom_wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
atom_wm_cmapwins = XInternAtom(dpy, "WM_COLORMAP_WINDOWS", False);
atom_wm_takefocus = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
// Motif hints
atom_mwm_hints = XInternAtom(dpy, "_MOTIF_WM_HINTS", False);
// GNOME atoms
atom_gnome_win_client_list = XInternAtom(dpy, "_WIN_CLIENT_LIST", False);
atom_gnome_win_state = XInternAtom(dpy, "_WIN_STATE", False);
atom_gnome_win_hints = XInternAtom(dpy, "_WIN_HINTS", False);
atom_gnome_win_layer = XInternAtom(dpy, "_WIN_LAYER", False);
atom_gnome_win_supporting_wm_check = XInternAtom(dpy, "_WIN_SUPPORTING_WM_CHECK", False);
atom_gnome_win_desktop_button_proxy= XInternAtom(dpy, "_WIN_DESKTOP_BUTTON_PROXY", False);
atom_gnome_win_workspace = XInternAtom(dpy, "_WIN_WORKSPACE", False);
atom_gnome_win_workspace_count = XInternAtom(dpy, "_WIN_WORKSPACE_COUNT", False);
atom_gnome_win_protocols = XInternAtom(dpy, "_WIN_PROTOCOLS", False);
gnome_check_win=XCreateSimpleWindow(dpy, root, -200, -200, 5, 5, 0, 0, 0);
gnome_button_proxy_win=XCreateSimpleWindow(dpy, root, -80, -80, 24, 24,0,0,0);
XChangeProperty(dpy, gnome_button_proxy_win, atom_gnome_win_desktop_button_proxy, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&gnome_button_proxy_win, 1);
/* Set up GNOME properties */
setGnomeHint(gnome_check_win, atom_gnome_win_supporting_wm_check, gnome_check_win);
setGnomeHint(root, atom_gnome_win_supporting_wm_check, gnome_check_win);
setGnomeHint(gnome_check_win, atom_gnome_win_desktop_button_proxy, gnome_check_win);
setGnomeHint(root, atom_gnome_win_desktop_button_proxy, gnome_check_win);
setGnomeHint(root, atom_gnome_win_workspace_count, maxDesktops);
setGnomeHint(root, atom_gnome_win_workspace, 0);
Atom gnome_protocols[5];
gnome_protocols[0] = atom_gnome_win_state;
gnome_protocols[1] = atom_gnome_win_hints;
gnome_protocols[2] = atom_gnome_win_client_list;
gnome_protocols[3] = atom_gnome_win_workspace;
gnome_protocols[4] = atom_gnome_win_workspace_count;
XChangeProperty(dpy, root, atom_gnome_win_protocols, XA_ATOM, 32, PropModeReplace,
(unsigned char *)gnome_protocols, 5);
// Extended WM Hints
atom_extended_net_supported = XInternAtom(dpy, "_NET_SUPPORTED", False);
atom_extended_net_client_list = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
atom_extended_net_client_list_stacking = XInternAtom(dpy, "_NET_CLIENT_LIST_STACKING", False);
atom_extended_net_number_of_desktops = XInternAtom(dpy, "_NET_NUMBER_OF_DESKTOPS", False);
atom_extended_net_desktop_geometry = XInternAtom(dpy, "_NET_DESKTOP_GEOMETRY", False);
atom_extended_net_desktop_viewport = XInternAtom(dpy, "_NET_DESKTOP_VIEWPORT", False);
atom_extended_net_current_desktop = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False);
//atom_extended_net_desktop_names = XInternAtom(dpy, "_NET_DESKTOP_NAMES", False);
atom_extended_net_active_window = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
atom_extended_net_workarea = XInternAtom(dpy, "_NET_WORKAREA", False);
atom_extended_net_supporting_wm_check = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
//atom_extended_net_virtual_roots = XInternAtom(dpy, "_NET_VIRTUAL_ROOTS", False);
atom_extended_net_close_window = XInternAtom(dpy, "_NET_CLOSE_WINDOW", False);
//atom_extended_net_wm_moveresize = XInternAtom(dpy, "_NET_WM_MOVERESIZE", False);
atom_extended_net_wm_name = XInternAtom(dpy, "_NET_WM_NAME", False);
//atom_extended_net_wm_visible_name = XInternAtom(dpy, "_NET_WM_VISIBLE_NAME", False);
//atom_extended_net_wm_icon_name = XInternAtom(dpy, "_NET_WM_ICON_NAME", False);
//atom_extended_net_wm_visible_icon_name = XInternAtom(dpy, "_NET_WM_VISIBLE_ICON_NAME", False);
atom_extended_net_wm_desktop = XInternAtom(dpy, "_NET_WM_DESKTOP", False);
//atom_extended_net_wm_window_type = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
//atom_extended_net_wm_window_type_desktop = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
//atom_extended_net_wm_window_type_dock = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);
//atom_extended_net_wm_window_type_toolbar = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False);
//atom_extended_net_wm_window_type_menu = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_MENU", False);
//atom_extended_net_wm_window_type_dialog = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
//atom_extended_net_wm_window_type_normal = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False);
atom_extended_net_wm_state = XInternAtom(dpy, "_NET_WM_STATE", False);
atom_extended_net_wm_state_modal = XInternAtom(dpy, "_NET_WM_STATE_MODAL", False);
atom_extended_net_wm_state_sticky = XInternAtom(dpy, "_NET_WM_STATE_STICKY", False);
atom_extended_net_wm_state_maximized_vert = XInternAtom(dpy, "_NET_WM_STATE_MAXIMIZED_VERT", False);
atom_extended_net_wm_state_maximized_horz = XInternAtom(dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
atom_extended_net_wm_state_shaded = XInternAtom(dpy, "_NET_WM_STATE_SHADED", False);
// Looked wrong, changed and fixed, hopefully. BJP 22042002
// atom_extended_net_wm_state_skip_taskbar = XInternAtom(dpy, "_NET_WM_STATE_SKIP_TOOLBAR", False);
atom_extended_net_wm_state_skip_taskbar = XInternAtom(dpy, "_NET_WM_STATE_SKIP_TASKBAR", False);
// Looked wrong, changed and fixed, hopefully. BJP 22042002
// atom_extended_net_wm_state_skip_pager = XInternAtom(dpy, "_NET_WM_STATE_PAGER", False);
atom_extended_net_wm_state_skip_pager = XInternAtom(dpy, "_NET_WM_STATE_SKIP_PAGER", False);
atom_extended_net_wm_strut = XInternAtom(dpy, "_NET_WM_STRUT", False);
//atom_extended_net_wm_icon_geometry = XInternAtom(dpy, "_NET_WM_ICON_GEOMETRY", False);
//atom_extended_net_wm_icon = XInternAtom(dpy, "_NET_WM_ICON", False);
//atom_extended_net_wm_pid = XInternAtom(dpy, "_NET_WM_PID", False);
//atom_extended_net_wm_handled_icons = XInternAtom(dpy, "_NET_WM_HANDLED_ICONS", False);
//atom_extended_net_wm_ping = XInternAtom(dpy, "_NET_WM_PING", False);
// This window is does nothing more than store properties which let
// other apps know we are supporting the extended wm hints
extended_hints_win=XCreateSimpleWindow(dpy, root, -200, -200, 5, 5, 0, 0, 0);
XSetWindowAttributes pattr;
pattr.override_redirect=True;
XChangeWindowAttributes(dpy, extended_hints_win, CWOverrideRedirect, &pattr);
XChangeWindowAttributes(dpy, gnome_check_win, CWOverrideRedirect, &pattr);
setExtendedWMHintString(extended_hints_win, atom_extended_net_wm_name, window_manager_name);
setExtendedWMHint(extended_hints_win, atom_extended_net_supporting_wm_check, extended_hints_win);
setExtendedWMHint(root, atom_extended_net_supporting_wm_check, extended_hints_win);
setExtendedNetSupported();
setExtendedWMHint(root, atom_extended_net_number_of_desktops, maxDesktops);
setExtendedNetDesktopGeometry();
setExtendedNetDesktopViewport();
setExtendedWMHint(root, atom_extended_net_current_desktop, 0);
XAllocNamedColor(dpy, DefaultColormap(dpy, screen), opt_fg, &fg, &dummyc);
XAllocNamedColor(dpy, DefaultColormap(dpy, screen), opt_bg, &bg, &dummyc);
XAllocNamedColor(dpy, DefaultColormap(dpy, screen), opt_bd, &bd, &dummyc);
XAllocNamedColor(dpy, DefaultColormap(dpy, screen), opt_fc, &fc, &dummyc);
font = XLoadQueryFont(dpy, opt_font);
if (!font) font = XLoadQueryFont(dpy, DEF_FONT);
if (!font) { cerr << "DEF_FONT not found, aborting." << endl; exit(1); }
#ifdef SHAPE
shape = XShapeQueryExtension(dpy, &shape_event, &dummy);
#endif
move_curs = XCreateFontCursor(dpy, XC_fleur);
resize_curs = XCreateFontCursor(dpy, XC_plus);
arrow_curs = XCreateFontCursor(dpy, XC_left_ptr);
XDefineCursor(dpy, root, arrow_curs);
gv.function = GXcopy;
gv.foreground = fg.pixel;
gv.font = font->fid;
string_gc = XCreateGC(dpy, root, GCFunction|GCForeground|GCFont, &gv);
gv.foreground = bd.pixel;
gv.line_width = opt_bw;
border_gc = XCreateGC(dpy, root, GCFunction|GCForeground|GCLineWidth, &gv);
gv.foreground = fg.pixel;
gv.function = GXinvert;
gv.subwindow_mode = IncludeInferiors;
invert_gc = XCreateGC(dpy, root, GCForeground|GCFunction|GCSubwindowMode|GCLineWidth|GCFont, &gv);
sattr.event_mask = ChildMask |
ColormapChangeMask |
ButtonMask |
FocusChangeMask |
EnterWindowMask |
LeaveWindowMask |
PropertyChangeMask |
ButtonMotionMask ;
XChangeWindowAttributes(dpy, root, CWEventMask, &sattr);
windowmenu = new WindowMenu();
iconmenu = new IconMenu();
// grabKeys(root);
}
/* We may want to put in some sort of check for unknown events at some
* point. TWM has an interesting and different way of doing this... */
// In the original aewm code client functions searched for a client to operate
// on. This is bad in my opinion. The Window Manager functions should find
// a client based on the XEvent and then dispatch events to it. I believe
// this to be a better way to do it. Though the other way works just fine
// as well.
void WindowManager::doEventLoop()
{
XEvent ev;
BaseMenu *mu=NULL;
Client *c=NULL;
for (;;)
{
blockFocusChange = false;
XNextEvent(dpy, &ev);
switch (ev.type)
{
case KeyPress:
{
#ifdef DEBUG
cerr << "KeyPress" << endl;
#endif
keyPressEvent(ev);
}
break;
case ButtonPress:
{
#ifdef DEBUG
cerr << "ButtonPress" << endl;
#endif
buttonPressEvent(ev, mu, c);
focusFocusedClient();
}
break;
case ButtonRelease:
{
#ifdef DEBUG
cerr << "ButtonRelease" << endl;
#endif
buttonReleaseEvent(ev, mu, c);
}
break;
case ConfigureRequest:
{
#ifdef DEBUG
cerr << "ConfigureRequest" << endl;
#endif
configureRequestEvent(ev, c);
}
break;
case MotionNotify:
{
#ifdef DEBUG
cerr << "MotionNotify" << endl;
#endif
motionNotifyEvent(ev, mu, c);
}
break;
case MapNotify:
{
#ifdef DEBUG
cerr << "MapNotify" << endl;
#endif
mapNotifyEvent(ev, c);
}
break;
case MapRequest:
{
#ifdef DEBUG
cerr << "MapRequest" << endl;
#endif
mapRequestEvent(ev, c);
}
break;
case UnmapNotify:
{
#ifdef DEBUG
cerr << "UnmapNotify" << endl;
#endif
unmapNotifyEvent(ev, c);
}
break;
case DestroyNotify:
{
#ifdef DEBUG
cerr << "DestroyNotify" << endl;
#endif
destroyNotifyEvent(ev, c);
}
break;
case EnterNotify:
{
#ifdef DEBUG
cerr << "EnterNotify" << endl;
#endif
enterNotifyEvent(ev, mu, c);
focusFocusedClient();
}
break;
case LeaveNotify:
{
#ifdef DEBUG
cerr << "LeaveNotify" << endl;
#endif
leaveNotifyEvent(ev, mu);
focusFocusedClient();
}
break;
case FocusIn:
{
#ifdef DEBUG
cerr << "FocusIn" << endl;
#endif
focusInEvent(ev, c);
}
break;
case FocusOut:
{
#ifdef DEBUG
cerr << "FocusOut" << endl;
#endif
focusOutEvent(ev, c);
}
break;
case ClientMessage:
{
#ifdef DEBUG
cerr << "ClientMessage" << endl;
#endif
clientMessageEvent(ev, c);
}
break;
case ColormapNotify:
{
#ifdef DEBUG
cerr << "ColormapNotify" << endl;
#endif
colormapNotifyEvent(ev, c);
}
break;
case PropertyNotify:
{
#ifdef DEBUG
cerr << "PropertyNotify" << endl;
#endif
propertyNotifyEvent(ev, c);
}
break;
case Expose:
{
#ifdef DEBUG
cerr << "Expose" << endl;
#endif
exposeEvent(ev, mu, c);
focusFocusedClient();
}
break;
#ifdef SHAPE
default:
{
#ifdef DEBUG
cerr << "(default)" << endl;
#endif
defaultEvent(ev, c);
}
break;
#endif
}
}
}
void WindowManager::keyPressEvent(XEvent& ev)
{
KeySym ks;
ks=XKeycodeToKeysym(dpy,ev.xkey.keycode,0);
if (ks==NoSymbol) return;
switch(ks)
{
case XK_y:
{
if (focusedClient)
{
#ifdef DEBUG
cerr << "Moving client to top left corner..." << endl;
#endif
focusedClient->moveToCorner(TOP_LEFT);
focusedClient->warpToTitlebarCenter();
}
}
break;
case XK_u:
{
if (focusedClient)
{
#ifdef DEBUG
cerr << "Moving client to top right corner..." << endl;
#endif
focusedClient->moveToCorner(TOP_RIGHT);
focusedClient->warpToTitlebarCenter();
}
}
break;
case XK_b:
{
if (focusedClient)
{
#ifdef DEBUG
cerr << "Moving client to bottom left corner..." << endl;
#endif
focusedClient->moveToCorner(BOTTOM_LEFT);
focusedClient->warpToTitlebarCenter();
}
}
break;
case XK_n:
{
if (focusedClient)
{
#ifdef DEBUG
cerr << "Moving client to bottom right corner..." << endl;
#endif
focusedClient->moveToCorner(BOTTOM_RIGHT);
focusedClient->warpToTitlebarCenter();
}
}
break;
case XK_h:
{
if (focusedClient)
{
#ifdef DEBUG
cerr << "Moving client left 10 pixels..." << endl;
#endif
focusedClient->moveInIncrement(10, LEFT);
focusedClient->warpToTitlebarCenter();
}
}
break;
case XK_j:
{
if (focusedClient)
{
#ifdef DEBUG
cerr << "Moving client down 10 pixels..." << endl;
#endif
focusedClient->moveInIncrement(10, DOWN);
focusedClient->warpToTitlebarCenter();
}
}
break;
case XK_k:
{
if (focusedClient)
{
#ifdef DEBUG
cerr << "Moving client up 10 pixels..." << endl;
#endif
focusedClient->moveInIncrement(10, UP);
focusedClient->warpToTitlebarCenter();
}
}
break;
case XK_l:
{
if (focusedClient)
{
#ifdef DEBUG
cerr << "Moving client right 10 pixels..." << endl;
#endif
focusedClient->moveInIncrement(10, RIGHT);
focusedClient->warpToTitlebarCenter();
}
}
break;
case XK_a:
{
if (focusedClient)
{
#ifdef DEBUG
cerr << "Iconifying client..." << endl;
#endif
focusedClient->iconify();
}
}
break;
case XK_f:
{
if (focusedClient)
{
#ifdef DEBUG
cerr << "Making client (un)sticky..." << endl;
#endif
focusedClient->stick(DISALLOW_STICKY_TRANS);
}
}
break;
case XK_z:
{
if (focusedClient)
{
#ifdef DEBUG
cerr << "Horizontally (un)maximizing client..." << endl;
#endif
focusedClient->maximize_horizontal();
focusedClient->warpToTitlebarCenter();
}
}
break;
case XK_x:
{
if (focusedClient)
{
#ifdef DEBUG
cerr << "Fully (un)maximizing client..." << endl;
#endif
focusedClient->maximize();
focusedClient->warpToTitlebarCenter();
}
}
break;
case XK_c:
{
if (focusedClient)
{
#ifdef DEBUG
cerr << "Vertically (un)maximizing client..." << endl;
#endif
focusedClient->maximize_vertical();
focusedClient->warpToTitlebarCenter();
}
}
break;
case XK_o:
{
if(iconmenu->getItemCount())
{
#ifdef DEBUG
cerr << "Hiding/showing icon menu..." << endl;
#endif
if (iconmenu->is_visible())
iconmenu->hide();
else
iconmenu->show();
}
}
break;
case XK_m:
{
if (focusedClient)
{
#ifdef DEBUG
cerr << "Hiding/showing window menu..." << endl;
#endif
focusedClient->warpToTitlebarCenter();
windowmenu->setThisClient(focusedClient);
if (windowmenu->is_visible())
windowmenu->hide();
else
windowmenu->show();
}
}
break;
case XK_space:
{
if (focusedClient)
{
#ifdef DEBUG
cerr << "(Un)shading client..." << endl;
#endif
focusedClient->shade();
focusedClient->warpToTitlebarCenter();
}
}
break;
case XK_Tab:
{
#ifdef DEBUG
cerr << "Switching to next client..." << endl;
#endif
focusNextWindowInStackingOrder();
// it's not guaranteed that there will be something focused...
// for example, if all the windows are minimized
if (focusedClient)
focusedClient->warpToTitlebarCenter();
}
break;
case XK_Return:
{
#ifdef DEBUG
cerr << "Spawning client \"" << opt_newkey << "\"..." << endl;
#endif
forkExec(opt_newkey);
}
break;
case XK_Escape:
{
if (focusedClient)
{
#ifdef DEBUG
cerr << "Deleting client..." << endl;
#endif
focusedClient->send_wm_delete();
}
}
break;
case XK_Delete:
cerr << "aewm++ is restarting..." << endl;
restart();
break;
case XK_End:
cerr << "aewm++ is quitting." << endl;
quitNicely();
break;
case XK_Page_Up:
{
if( currentDesktop < maxDesktops - 1 )
{
currentDesktop++;
#ifdef DEBUG
cerr << "Switching to desktop " << currentDesktop << "..." << endl;
#endif
goToDesktop(currentDesktop);
}
}
break;
case XK_Page_Down:
{
if( currentDesktop > 0 )
{
currentDesktop--;
#ifdef DEBUG
cerr << "Switching to desktop " << currentDesktop << "..." << endl;
#endif
goToDesktop(currentDesktop);
}
}
break;
}
}
void WindowManager::buttonPressEvent(XEvent& ev, BaseMenu *mu, Client *c)
{
c = findClient(ev.xbutton.window);
if (ev.xbutton.window == root)
{
switch (ev.xbutton.button)
{
case Button1:
forkExec(opt_new1);
if(iconmenu->is_visible())
iconmenu->hide();
if(windowmenu->is_visible())
windowmenu->hide();
break;
case Button2:
if(iconmenu->getItemCount())
{
if(iconmenu->is_visible())
iconmenu->hide();
else
iconmenu->show();
if(windowmenu->is_visible())
windowmenu->hide();
}
break;
case Button3:
forkExec(opt_new2);
if(iconmenu->is_visible())
iconmenu->hide();
if(windowmenu->is_visible())
windowmenu->hide();
break;
//DLR: Mousewheel support
//MJR: Only on left edge, order reversed to match PgUp/PgDn
case Button5:
if( (currentDesktop > 0) && (ev.xbutton.y < 32))
{
currentDesktop--;
#ifdef DEBUG
cerr << "Switching to desktop " << currentDesktop << "..." << endl;
#endif
goToDesktop(currentDesktop);
}
break;
case Button4:
if( ( currentDesktop < maxDesktops - 1 ) && (ev.xbutton.y < 32))
{
currentDesktop++;
#ifdef DEBUG
cerr << "Switching to desktop " << currentDesktop << "..." << endl;
#endif
goToDesktop(currentDesktop);
}
break;
}
}
else
{
switch (focusModel)
{
case FOCUS_FOLLOW:
case FOCUS_SLOPPY:
// focus the window and handle the button click
if(c)
{
setFocusedClient(c);
c->handle_button_event(&ev.xbutton);
}
break;
case FOCUS_CLICK:
// the first time the window's clicked,
// focus it; handle the button click
// unconditionally
if(c)
{
if(c != focusedClient)
setFocusedClient(c);
c->handle_button_event(&ev.xbutton);
}
break;
}
mu = windowmenu->findMenu(ev.xbutton.window);
if(!mu)
mu = iconmenu->findMenu(ev.xbutton.window);
if(mu)
mu->handle_button_press_event(&ev.xbutton);
}
if(ev.xbutton.window == root)
XSendEvent(dpy, gnome_button_proxy_win, False, SubstructureNotifyMask, &ev);
}
void WindowManager::buttonReleaseEvent(XEvent& ev, BaseMenu *mu, Client *c)
{
c = findClient(ev.xbutton.window);
if(c)
c->handle_button_event(&ev.xbutton);
else
{
mu = windowmenu->findMenu(ev.xbutton.window);
if(!mu)
mu = iconmenu->findMenu(ev.xbutton.window);
if(mu)
{
mu->hide();
mu->handle_button_release_event(&ev.xbutton);
}
}
if(ev.xbutton.window == root)
XSendEvent(dpy, gnome_button_proxy_win, False, SubstructureNotifyMask, &ev);
}
void WindowManager::configureRequestEvent(XEvent& ev, Client *c)
{
c = findClient(ev.xconfigurerequest.window);
if(c)
c->handle_configure_request(&ev.xconfigurerequest);
else
{
// Since this window isn't yet a client lets delegate
// the configure request back to the window so it can
// use it.
XWindowChanges wc;
wc.x = ev.xconfigurerequest.x;
wc.y = ev.xconfigurerequest.y;
wc.width = ev.xconfigurerequest.width;
wc.height = ev.xconfigurerequest.height;
wc.sibling = ev.xconfigurerequest.above;
wc.stack_mode = ev.xconfigurerequest.detail;
XConfigureWindow(dpy, ev.xconfigurerequest.window, ev.xconfigurerequest.value_mask, &wc);
}
}
void WindowManager::motionNotifyEvent(XEvent& ev, BaseMenu *mu, Client *c)
{
c = findClient(ev.xmotion.window);
if(c)
c->handle_motion_notify_event(&ev.xmotion);
mu = windowmenu->findMenu(ev.xmotion.window);
if(!mu)
mu = iconmenu->findMenu(ev.xmotion.window);
if(mu)
mu->handle_motion_notify_event(&ev.xmotion);
}
void WindowManager::mapNotifyEvent(XEvent& ev, Client *c)
{
c = findClient(ev.xmap.window);
if(c)
setFocusedClient(c);
}
void WindowManager::mapRequestEvent(XEvent& ev, Client *c)
{
bool newClient = false;
c = findClient(ev.xmaprequest.window);
if(c)
c->handle_map_request(&ev.xmaprequest);
else
{
c = new Client(dpy, ev.xmaprequest.window, clientList);
newClient = true;
}
if (newClient)
setFocusedClient(c);
updateIconMenu();
}
void WindowManager::unmapNotifyEvent(XEvent& ev, Client *c)
{
c = findClient(ev.xunmap.window);
if(c)
{
c->handle_unmap_event(&ev.xunmap);
switch (focusModel)
{
case FOCUS_FOLLOW:
// focus under pointer
case FOCUS_SLOPPY:
// focus under pointer
setFocusedClientUnderPointer();
break;
case FOCUS_CLICK:
// focus root
unsetFocusedClient();
break;
}
}
}
void WindowManager::destroyNotifyEvent(XEvent& ev, Client *c)
{
c = findClient(ev.xdestroywindow.window);
if(c)
{
c->handle_destroy_event(&ev.xdestroywindow);
removeClientFromIconMenu(c);
switch (focusModel)
{
case FOCUS_FOLLOW:
// focus under pointer
case FOCUS_SLOPPY:
// focus under pointer
setFocusedClientUnderPointer();
break;
case FOCUS_CLICK:
// focus root
unsetFocusedClient();
break;
}
}
if ( iconmenu->is_visible()) {
iconmenu->hide();
updateIconMenu();
}
else {
updateIconMenu();
}
}
void WindowManager::enterNotifyEvent(XEvent& ev, BaseMenu *mu, Client *c)
{
c = findClient(ev.xcrossing.window);
mu = windowmenu->findMenu(ev.xcrossing.window);
if(!mu)
mu = iconmenu->findMenu(ev.xcrossing.window);
if(mu)
mu->handle_enter_notify(&ev.xcrossing);
switch (focusModel)
{
case FOCUS_FOLLOW:
// focus the entered window; focus root if there
// is none
if(c)
setFocusedClient(c);
else
unsetFocusedClient();
break;
case FOCUS_SLOPPY:
// focus the entered window
if(c)
setFocusedClient(c);
break;
case FOCUS_CLICK:
// don't change focus
break;
}
}
void WindowManager::leaveNotifyEvent(XEvent& ev, BaseMenu *mu)
{
mu = windowmenu->findMenu(ev.xcrossing.window);
if(!mu)
mu = iconmenu->findMenu(ev.xcrossing.window);
if(mu) mu->handle_leave_notify(&ev.xcrossing);
switch (focusModel)
{
case FOCUS_FOLLOW:
// focus window under pointer
setFocusedClientUnderPointer();
break;
case FOCUS_SLOPPY:
case FOCUS_CLICK:
// don't change focus
break;
}
}
void WindowManager::focusInEvent(XEvent& ev, Client *c)
{
c = findClient(ev.xfocus.window);
if(c)
{
unfocusAnyStrayClients();
c->handle_focus_in_event(&ev.xfocus);
c->set_focus(true);
setFocusedClient(c);
blockFocusChange = true;
grabKeys(ev.xfocus.window);
}
}
void WindowManager::focusOutEvent(XEvent& ev, Client *c)
{
c = findClient(ev.xfocus.window);
// don't take focus from the currently focused client
if(c && c != focusedClient)
{
c->handle_focus_out_event(&ev.xfocus);
c->set_focus(false);
unsetFocusedClient();
blockFocusChange = true;
ungrabKeys(ev.xfocus.window);
}
}
void WindowManager::clientMessageEvent(XEvent& ev, Client *c)
{
c = findClient(ev.xclient.window);
if(c)
c->handle_client_message(&ev.xclient);
if(ev.xclient.window == root)
{
if(ev.xclient.message_type == atom_gnome_win_workspace && ev.xclient.format == 32)
goToDesktop(ev.xclient.data.l[0]);
if(ev.xclient.message_type == atom_extended_net_current_desktop && ev.xclient.format == 32)
goToDesktop(ev.xclient.data.l[0]);
if(ev.xclient.message_type == atom_gnome_win_workspace_count && ev.xclient.format == 32)
maxDesktops = ev.xclient.data.l[0];
if(ev.xclient.message_type == atom_extended_net_number_of_desktops && ev.xclient.format == 32)
maxDesktops = ev.xclient.data.l[0];
}
}
void WindowManager::colormapNotifyEvent(XEvent& ev, Client *c)
{
c = findClient(ev.xcolormap.window);
if(c)
c->handle_colormap_change(&ev.xcolormap);
}
void WindowManager::propertyNotifyEvent(XEvent& ev, Client *c)
{
c = findClient(ev.xproperty.window);
if(c)
c->handle_property_change(&ev.xproperty);
}
void WindowManager::exposeEvent(XEvent& ev, BaseMenu *mu, Client *c)
{
mu = windowmenu->findMenu(ev.xexpose.window);
if(!mu)
mu = iconmenu->findMenu(ev.xexpose.window);
if(mu)
mu->handle_expose_event(&ev.xexpose);
c = findClient(ev.xexpose.window);
if(c)
c->handle_expose_event(&ev.xexpose);
}
void WindowManager::defaultEvent(XEvent& ev, Client *c)
{
c = findClient(ev.xany.window);
if(c)
{
if (shape && ev.type == shape_event)
c->handle_shape_change((XShapeEvent *)&ev);
}
}
void WindowManager::focusNextWindowInStackingOrder()
{
Client *c = focusedClient;
bool noClient;
unsigned int cycles = 0;
if (!c)
noClient = true;
else
noClient = false;
if(!clientList->empty())
{
if (clientList->size() < 2 && !noClient)
{
#ifdef DEBUG
cerr << "Fewer than two clients and a client's already focused; returning." << endl;
#endif
return;
}
it = clientList->begin();
if (noClient) {
c = *it;
}
// find the client in the list...
it = find(clientList->begin(), clientList->end(), c);
if ( it == clientList->end()) {
it = clientList->begin();
}
do {
cycles++;
if ( it == clientList->end() ) {
it = clientList->begin();
}
else {
it++;
if ( it == clientList->end() ) {
it = clientList->begin();
}
}
} while (cycles < clientList->size() && (shouldSkipThisWindow((*it)->getAppWindow()) || (*it)->isIconified() || (*it)->belongsToWhichDesktop() != currentDesktop));
#ifdef DEBUG
if ( c != NULL ) {
cerr << "Original client: " << c->getClientName() << endl;
}
else {
cerr << "No original client: " << endl;
}
cerr << "Current client: " << (*it)->getClientName() << endl;
cerr << "Ending client: " << (*it)->getClientName() << endl;
cerr.flush();
#endif
// if we found a suitable "next client", raise and focus
// it; otherwise, leave focus where it is
if ( cycles < clientList->size() && !(it == clientList->end()) && !shouldSkipThisWindow((*it)->getAppWindow()) && !(*it)->isIconified() && (*it)->belongsToWhichDesktop() == currentDesktop && !shouldSkipThisWindow((*it)->getAppWindow())) {
c = *it;
c->raise();
setFocusedClient(c);
}
return;
}
}
int WindowManager::shouldSkipThisWindow(Window w)
{
NetWMStates* netwm_state;
unsigned long gnome_state;
netwm_state = getExtendedNetWMStates(w);
if (netwm_state)
{
if (netwm_state->skip_taskbar || netwm_state->skip_pager)
return true;
}
gnome_state = getHint(w, atom_gnome_win_hints);
if (gnome_state)
{
if ((gnome_state & WIN_STATE_SKIP_FOCUS) || (gnome_state & WIN_STATE_SKIP_WINLIST) || (gnome_state & WIN_STATE_SKIP_TASKBAR))
return true;
}
return false;
}
void WindowManager::unfocusAnyStrayClients()
{
// To prevent two windows titlebars from being painted with the
// focus color we will set all windows to false.
for(it = clientList->begin(); it != clientList->end(); it++)
(*it)->set_focus(false);
}
void WindowManager::getMousePosition(int *x, int *y)
{
Window mouse_root, mouse_win;
int win_x, win_y;
unsigned int mask;
XQueryPointer(dpy, root, &mouse_root, &mouse_win, x, y, &win_x, &win_y, &mask);
}
void WindowManager::restackOnTopWindows()
{
if(clientList->size() > 1)
{
for(it = clientList->begin(); it != clientList->end(); it++)
{
if ((*it)->isAlwaysOnTop()) (*it)->raise();
}
}
}
Client* WindowManager::findClient(Window w)
{
if (w && w != root) {
if(!clientList->empty())
{
it = find_if(clientList->begin(), clientList->end(), ClientWindow_eq(&w));
if ( it != clientList->end() ) {
return *it;
}
}
}
return NULL;
}
void WindowManager::findTransientsToMapOrUnmap(Window win, bool hide)
{
list<Client *>::iterator cit;
if(!clientList->empty())
{
for(cit = clientList->begin(); cit != clientList->end(); cit++)
{
if((*cit)->getTransientWindow() == win)
{
if(hide)
{
if(! (*cit)->isIconified())
(*cit)->iconify();
}
else
{
if((*cit)->isIconified())
(*cit)->unhide();
}
}
}
}
}
void WindowManager::findTransientsToRaiseOrLower(Window win, bool low)
{
list<Client *>::iterator cit;
if(!clientList->empty())
{
for(cit = clientList->begin(); cit != clientList->end(); cit++)
{
if((*cit)->getTransientWindow() == win)
{
if(low)
(*cit)->lower();
else
(*cit)->raise();
}
}
}
}
void WindowManager::findTransientsToStickOrUnstick(Window win, bool stick)
{
list<Client *>::iterator cit;
if(!clientList->empty())
{
for(cit = clientList->begin(); cit != clientList->end(); cit++)
{
if((*cit)->getTransientWindow() == win)
{
if(stick)
{
if(! (*cit)->isSticky())
(*cit)->stick(ALLOW_STICKY_TRANS);
}
else
{
if((*cit)->isSticky())
(*cit)->stick(ALLOW_STICKY_TRANS);
}
}
}
}
}
void WindowManager::setGnomeHint(Window w, int a, long value)
{
XChangeProperty(dpy, w, a, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&value, 1);
}
unsigned long WindowManager::getHint(Window w, int a)
{
Atom real_type;
int real_format;
unsigned long items_read, items_left;
unsigned long value=0;
unsigned char *data = NULL;
XGetWindowProperty (dpy, w, a, 0, 0x7fffffff, False,
XA_CARDINAL, &real_type, &real_format, &items_read,
&items_left, &data);
if (data) {
value = (unsigned long) *data;
XFree(data);
}
return value;
}
void WindowManager::updateClientList()
{
int i=0, client_count=0;
CARD32 *wins=NULL;
Window *extended_wins=NULL;
for(it = clientList->begin(); it != clientList->end(); it++)
{
// We don't want to include transients in our client list
if(! ((*it)->getTransientWindow())) client_count++;
}
wins = new CARD32[client_count];
extended_wins = new Window[client_count];
if(wins == NULL)
{
cerr << "Memory allocation failed in function update_gnome_client." << endl;
exit(1);
}
for(it = clientList->begin(); it != clientList->end(); it++)
{
// We don't want to include transients in our client list
if(! ((*it)->getTransientWindow()))
{
Window t = (*it)->getAppWindow();
wins[i] = t;
extended_wins[i] = t;
i++;
}
}
XChangeProperty(dpy, root, atom_gnome_win_client_list, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)wins, client_count);
XChangeProperty(dpy, root, atom_extended_net_client_list, XA_WINDOW, 32, PropModeReplace, (unsigned char*)extended_wins, client_count);
XChangeProperty(dpy, root, atom_extended_net_client_list_stacking, XA_WINDOW, 32, PropModeReplace, (unsigned char*)extended_wins, client_count);
delete [] wins;
delete [] extended_wins;
}
int WindowManager::sendExtendedHintMessage(Window w, Atom a, long mask, long int data[])
{
XEvent e;
e.type = ClientMessage;
e.xclient.window = w;
e.xclient.message_type = a;
e.xclient.format = 32;
// xclient.data.l is a long int[5]
e.xclient.data.l[0] = data[0];
e.xclient.data.l[1] = data[1];
e.xclient.data.l[2] = data[2];
//e.xclient.data.l[3] = data[3];
//e.xclient.data.l[4] = data[4];
return XSendEvent(dpy,
w,
False,
SubstructureNotifyMask|SubstructureRedirectMask,
&e);
}
void WindowManager::setExtendedWMHint(Window w, int a, long value)
{
XChangeProperty(dpy, w, a, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&value, 1);
}
void WindowManager::setExtendedWMHintString(Window w, int a, char* value)
{
XChangeProperty(
dpy,
w,
a,
XA_STRING,
8,
PropModeReplace,
(unsigned char*) value,
strlen (value));
}
// Borrowed from:
//
// http://capderec.udg.es:81/ebt-bin/nph-dweb/dynaweb/SGI_Developer/XLib_PG/%40Generic__BookTextView/45827
Status WindowManager::getExtendedWMHintString(Window w, int a, char** name)
{
Atom actual_type;
int actual_format;
unsigned long nitems;
unsigned long leftover;
unsigned char *data = NULL;
if (XGetWindowProperty(dpy, w, a, 0L, (long)BUFSIZ,
False, XA_STRING, &actual_type, &actual_format,
&nitems, &leftover, &data) != Success) {
*name = NULL;
return (0);
}
if ( (actual_type == XA_STRING) && (actual_format == 8) ) {
/* The data returned by XGetWindowProperty is guaranteed
* to contain one extra byte that is null terminated to
* make retrieving string properties easy */
*name = (char *)data;
return(1);
}
if (data) XFree ((char *)data);
*name = NULL;
return(0);
}
void WindowManager::setExtendedNetSupported()
{
int total_net_supported = 22;
Atom net_supported_list[] = {
atom_extended_net_supported,
atom_extended_net_client_list,
atom_extended_net_client_list_stacking,
atom_extended_net_number_of_desktops,
atom_extended_net_desktop_geometry,
atom_extended_net_desktop_viewport,
atom_extended_net_current_desktop,
//atom_extended_net_desktop_names,
atom_extended_net_active_window,
atom_extended_net_workarea,
atom_extended_net_supporting_wm_check,
//atom_extended_net_virtual_roots,
atom_extended_net_close_window,
//atom_extended_net_wm_moveresize,
atom_extended_net_wm_name,
//atom_extended_net_wm_visible_name,
//atom_extended_net_wm_icon_name,
//atom_extended_net_wm_visible_icon_name,
atom_extended_net_wm_desktop,
//atom_extended_net_wm_window_type,
//atom_extended_net_wm_window_type_desktop,
//atom_extended_net_wm_window_type_dock,
//atom_extended_net_wm_window_type_toolbar,
//atom_extended_net_wm_window_type_menu,
//atom_extended_net_wm_window_type_dialog,
//atom_extended_net_wm_window_type_normal,
atom_extended_net_wm_state,
atom_extended_net_wm_state_modal,
atom_extended_net_wm_state_sticky,
atom_extended_net_wm_state_maximized_vert,
atom_extended_net_wm_state_maximized_horz,
atom_extended_net_wm_state_shaded,
atom_extended_net_wm_state_skip_taskbar,
atom_extended_net_wm_state_skip_pager,
atom_extended_net_wm_strut,
//atom_extended_net_wm_icon_geometry,
//atom_extended_net_wm_icon,
//atom_extended_net_wm_pid,
//atom_extended_net_wm_handled_icons,
//atom_extended_net_wm_ping
};
XChangeProperty(dpy, root, atom_extended_net_supported, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)net_supported_list, total_net_supported);
}
void WindowManager::setExtendedNetDesktopGeometry()
{
CARD32 geometry[] = { xres, yres };
XChangeProperty(dpy, root, atom_extended_net_desktop_geometry, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)geometry, 2);
}
void WindowManager::setExtendedNetDesktopViewport()
{
CARD32 viewport[] = { 0, 0 };
XChangeProperty(dpy, root, atom_extended_net_desktop_viewport, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)viewport, 2);
}
void WindowManager::setExtendedNetActiveWindow(Window w)
{
setExtendedWMHint(root, atom_extended_net_active_window, w);
}
void WindowManager::setExtendedNetWorkArea()
{
int work_x, work_y, work_width, work_height;
work_x = master_strut->west;
work_y = master_strut->north;
work_width = xres - master_strut->east - work_x;
work_height = yres - master_strut->south - work_y;
CARD32 workarea[] = { work_x, work_y, work_width, work_height };
XChangeProperty(dpy, root, atom_extended_net_workarea, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)workarea, 4);
}
void* WindowManager::getExtendedNetPropertyData(Window win, Atom prop, Atom type, int *items)
{
Atom type_ret;
int format_ret;
unsigned long items_ret;
unsigned long after_ret;
unsigned char *prop_data;
prop_data = 0;
XGetWindowProperty (dpy, win, prop, 0, 0x7fffffff, False,
type, &type_ret, &format_ret, &items_ret,
&after_ret, &prop_data);
if (items)
*items = items_ret;
return prop_data;
}
NetWMStates* WindowManager::getExtendedNetWMStates(Window win)
{
NetWMStates *win_state;
win_state = new NetWMStates;
win_state->modal=false;
win_state->sticky=false;
win_state->max_vert=false;
win_state->max_horz=false;
win_state->shaded=false;
win_state->skip_taskbar=false;
win_state->skip_pager=false;
int num=0;
//Atom* states;
//unsigned long *state;
/*states = (Atom*) getExtendedNetPropertyData(win,
atom_extended_net_wm_state,
XA_ATOM,
&num);*/
if ( getExtendedNetPropertyData(win, atom_extended_net_wm_state_modal, XA_CARDINAL, &num) ) win_state->modal=true;
if ( getExtendedNetPropertyData(win, atom_extended_net_wm_state_sticky, XA_CARDINAL, &num) ) win_state->sticky=true;
if ( getExtendedNetPropertyData(win, atom_extended_net_wm_state_maximized_vert, XA_CARDINAL, &num) ) win_state->max_vert=true;
if ( getExtendedNetPropertyData(win, atom_extended_net_wm_state_maximized_horz, XA_CARDINAL, &num) ) win_state->max_horz=true;
if ( getExtendedNetPropertyData(win, atom_extended_net_wm_state_shaded, XA_CARDINAL, &num) ) win_state->shaded=true;
if ( getExtendedNetPropertyData(win, atom_extended_net_wm_state_skip_taskbar, XA_CARDINAL, &num) ) win_state->skip_taskbar=true;
if ( getExtendedNetPropertyData(win, atom_extended_net_wm_state_skip_pager, XA_CARDINAL, &num) ) win_state->skip_pager=true;
// if(states!=NULL)
// {
// for (int a = 0; a < NET_WM_STATE_MAX_STATES; a++) {
// if(states[a]==atom_extended_net_wm_state_modal) win_state->modal=true;
// if(states[a]==atom_extended_net_wm_state_sticky) win_state->sticky=true;
// if(states[a]==atom_extended_net_wm_state_maximized_vert) win_state->max_vert=true;
// if(states[a]==atom_extended_net_wm_state_maximized_horz) win_state->max_horz=true;
// if(states[a]==atom_extended_net_wm_state_shaded) win_state->shaded=true;
// if(states[a]==atom_extended_net_wm_state_skip_taskbar) win_state->skip_taskbar=true;
// if(states[a]==atom_extended_net_wm_state_skip_pager) win_state->skip_pager=true;
// }
// }
return win_state;
}
void WindowManager::setExtendedNetWMState(
Window win,
bool modal,
bool sticky,
bool max_vert,
bool max_horz,
bool shaded,
bool skip_taskbar,
bool skip_pager
)
{
//atom_extended_net_wm_state_modal,
//atom_extended_net_wm_state_sticky,
//atom_extended_net_wm_state_maximized_vert,
//atom_extended_net_wm_state_maximized_horz,
//atom_extended_net_wm_state_shaded,
//atom_extended_net_wm_state_skip_taskbar,
//atom_extended_net_wm_state_skip_pager,
//int counter=0;
if(modal)
net_wm_states[0] = atom_extended_net_wm_state_modal;
else
net_wm_states[0] = 0;
if(sticky)
net_wm_states[1] = atom_extended_net_wm_state_sticky;
else
net_wm_states[1] = 0;
if(max_vert)
net_wm_states[2] = atom_extended_net_wm_state_maximized_vert;
else
net_wm_states[2] = 0;
if(max_horz)
net_wm_states[3] = atom_extended_net_wm_state_maximized_horz;
else
net_wm_states[3] = 0;
if(shaded)
net_wm_states[4] = atom_extended_net_wm_state_shaded;
else
net_wm_states[4] = 0;
if(skip_taskbar)
net_wm_states[5] = atom_extended_net_wm_state_skip_taskbar;
else
net_wm_states[5] = 0;
if(skip_pager)
net_wm_states[6] = atom_extended_net_wm_state_skip_pager;
else
net_wm_states[6] = 0;
//if (counter < NET_WM_STATE_MAX_STATES)
//{
// for(;counter < NET_WM_STATE_MAX_STATES; counter++)
// net_wm_states[counter] = 0;
//}
XChangeProperty(dpy, win, atom_extended_net_wm_state, XA_ATOM, 32, PropModeReplace, (unsigned char *) net_wm_states, NET_WM_STATE_MAX_STATES);
}
void WindowManager::addStrut(Strut *new_strut)
{
clientStruts->push_back(new_strut);
if(!clientStruts->empty())
{
for(struts_it = clientStruts->begin(); struts_it != clientStruts->end(); struts_it++)
{
if(master_strut->east < (*struts_it)->east) master_strut->east = (*struts_it)->east;
if(master_strut->west < (*struts_it)->west) master_strut->west = (*struts_it)->west;
if(master_strut->north < (*struts_it)->north) master_strut->north = (*struts_it)->north;
if(master_strut->south < (*struts_it)->south) master_strut->south = (*struts_it)->south;
}
}
setExtendedNetWorkArea();
}
void WindowManager::removeStrut(Strut *rem_strut)
{
if(!clientStruts->empty())
clientStruts->remove(rem_strut);
master_strut->east = 0;
master_strut->west = 0;
master_strut->north = 0;
master_strut->south = 0;
if(!clientStruts->empty())
{
for(struts_it = clientStruts->begin(); struts_it != clientStruts->end(); struts_it++)
{
if(master_strut->east < (*struts_it)->east) master_strut->east = (*struts_it)->east;
if(master_strut->west < (*struts_it)->west) master_strut->west = (*struts_it)->west;
if(master_strut->north < (*struts_it)->north) master_strut->north = (*struts_it)->north;
if(master_strut->south < (*struts_it)->south) master_strut->south = (*struts_it)->south;
}
}
setExtendedNetWorkArea();
}
int WindowManager::findExtendedDesktopHint(Window win)
{
int desktop=-1;
desktop = getDesktopHint(win, atom_extended_net_wm_desktop);
return desktop;
}
int WindowManager::findGnomeDesktopHint(Window win)
{
int desktop=-1;
desktop = getDesktopHint(win, atom_gnome_win_workspace);
return desktop;
}
long WindowManager::getDesktopHint(Window win, int a)
{
Atom real_type;
int real_format;
unsigned long items_read, items_left;
long *data=NULL, value=-1;
if(XGetWindowProperty(dpy, win, a, 0L, 1L, False,
XA_CARDINAL, &real_type,
&real_format, &items_read,
&items_left,
(unsigned char **)&data)==Success && items_read)
{
value=*data;
XFree(data);
}
return value;
}
void WindowManager::restart()
{
cleanup();
execl("/bin/sh", "sh", "-c", command_line.c_str(), 0);
}
void WindowManager::quitNicely()
{
cleanup();
exit(0);
}
void WindowManager::cleanup()
{
unsigned int nwins, i;
Window dummyw1, dummyw2, *wins;
Client* c;
// ungrabKeys(root);
XDestroyWindow(dpy, gnome_button_proxy_win);
XDestroyWindow(dpy, gnome_check_win);
XDestroyWindow(dpy, extended_hints_win);
// Preserve stacking order when removing the clients
// from the list.
XQueryTree(dpy, root, &dummyw1, &dummyw2, &wins, &nwins);
for (i = 0; i < nwins; i++)
{
c = findClient(wins[i]);
if(c)
{
XMapWindow(dpy, c->getAppWindow());
delete c;
}
}
XFree(wins);
delete windowmenu;
delete iconmenu;
delete clientList;
delete master_strut;
delete clientStruts;
XFreeFont(dpy, font);
XFreeCursor(dpy, move_curs);
XFreeCursor(dpy, resize_curs);
XFreeGC(dpy, invert_gc);
XFreeGC(dpy, border_gc);
XFreeGC(dpy, string_gc);
XInstallColormap(dpy, DefaultColormap(dpy, screen));
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
XCloseDisplay(dpy);
}
syntax highlighted by Code2HTML, v. 0.9.1