/* * 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, -fn , -fg|-bg|-bd , " << endl; cerr << " -bw , -md , -mw -tj ," << endl; cerr << " -wm , -new1|-new2|-newkey , -fm , -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; // 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; 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;igetAppWindow(), 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 *normalWindows = new list; list *iconWindows = new list; 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::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::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::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); }