aewm++-1.1.2/0000755000014400001440000000000010205770477011601 5ustar majicusersaewm++-1.1.2/Makefile0000644000014400001440000000163310204531061013223 0ustar majicusersCC = g++ ADDITIONAL_CFLAGS = -g -O2 -march=i686 -Wall prefix = /usr INCLUDES = -I$/usr/X11R6 LDPATH = -L/usr/X11R6/lib LIBS = -lXext -lX11 # SHAPE = Shape Extension # NEED_SETENV = Does your Unix not support the setenv function? Use this! DEFINES = -DSHAPE #-DNEED_SETENV HEADERS = aewm.hh \ client.hh \ windowmanager.hh \ basemenu.hh \ windowmenu.hh \ genericmenu.hh \ iconmenu.hh OBJS = windowmanager.o \ client.o \ main.o \ basemenu.o \ genericmenu.o \ iconmenu.o \ windowmenu.o all: aewm++ aewm++: $(OBJS) $(CC) $(OBJS) $(LDPATH) $(LIBS) -o $@ $(OBJS): %.o: %.cc $(HEADERS) $(CC) $(CFLAGS) $(ADDITIONAL_CFLAGS) $(DEFINES) $(INCLUDES) -c $< -o $@ install: all mkdir -p $(DESTDIR)$(prefix)/bin mkdir -p $(DESTDIR)$(prefix)/man/man1 install -s aewm++ $(DESTDIR)$(prefix)/bin clean: rm -f aewm++ $(OBJS) core aewm++-1.1.2/LICENSE0000644000014400001440000000151110150542220012562 0ustar majicusersThis software is licensed under the terms of the GNU GPL which can be read in full at: http://www.gnu.org/licenses/licenses.html#GPL /* * 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. */ aewm++-1.1.2/README0000644000014400001440000002225210203032725012445 0ustar majicusersNeeds Updating - (This doc is pretty old circa 15 May 2003) aewm++ - The C++ version of aewm ====================================================================== Why was this done? ------------------ This was done for the simple fact that the C version of aewm spawned many new window managers. In other words it is a great peice of code in which to hack. Hopefully by having a C++ version of it, it will inspire even more C++ programmers to hack it into yet more window managers. What does it do? ---------------- The C++ version does everything the C version does and more. The programs in the goodies directory were discarded. The reason for this is they are obsolete if you use fspanel and appbar. If you want these programs then download the aewm source code. In the future I plan on starting my own goodies directory where I will distribute appbar, and other little goodies to complement aewm++. aewm++ provides window maximization, iconification, shading and virtual desktops in addition to the regular aewm features. By default aewm++ starts with 4 virtual desktops (or workspaces if you like). Switching is done via the page up and page down keys while mouse pointer is over the root window. You can specify more virtual desktops by passing the -md to aewm++ at runtime. aewm++ is designed for a 3 button mouse or a 2 button mouse with 3 button emulation on. Window maximization is done by double clicking with the first mouse button on the titlebar, double clicking on a maximized window restores it to its original position and size. Shading a window is done by middle clicking on the titlebar. Do this again and the window will become unshaded. To iconify a window simply press the first mouse button on the little box at the right edge of the titlebar. aewm++ doesn't provide any native way to uniconify windows. If used in conjunction with fspanel it works nicely. As of version 1.0.13 there is now an icon menu. If you middle click on the root window you will see the icon menu if you have clients that are iconified. If no clients are iconified you will see nothing. If you middle click on the root window again while the menu is open it will hide. Icons for the current desktop are the only ones that show. Once you switch desktops whatever icons on that desktop will show. Install ------- tar xvzf aewm++-version.tar.gz cd aewm++-version make su make install To uninstall do: make uninstall Edit your ~/.xinitrc and add: exec aewm++ ------------------------------- Frank Hale ****************************** ****************************** **ORIGINAL AEWM README BELOW** ****************************** ****************************** aewm - An X11 Window Manager ====================================================================== aewm is a minimalistic window manager for X11. I wrote it mostly to learn about X and the ICCCM, but also to fight software bloat. Instead of expanding to fill your entire "desktop environment", aewm's main purpose is to get out of your way and allow you to use other programs to control things like menus, icons, backgrounds, cursors, root backgrounds, and so on. It doesn't do "themes", or have much in the way of configuration. This is a philosophical statement; it's better to do your work than distract yourself with pretty little borders around it. I myself haven't changed the default background color in, well, ever. Another goal I had in writing aewm was to create an easily readable and hackable implementation of the ICCCM. While I'm not 100% there yet, I think I've at least made the dense jungle of Xlib a bit more understandable. You are encouraged to take the code and do your own thing with it. For this reason I chose a liberal license that should allow you to add your favorite GPL or BSD flavour if you see fit. I was planning on using the name "swim" (Simple WIndow Manager), but someone snapped that up while I was getting the code ready for general consumption. "ae" doesn't really stand for anything, but I am a big fan of Autechre. ;-) The latest release is at http://www.red-bean.com/~decklin/aewm/. Installation ====================================================================== Before compiling, check the default (DEF_foo) options in aewm.h, and the defines in the Makefile. DEF_FONT is of particular interest; make sure that it is defined to something that exists on your system. You can turn -DSHAPE off if you don't have the Shape extension, and -DMWM_HINTS on if you have the Lesstif or Motif headers installed. "make" will compile everything, and "make install" will install it. The goodies/ directory must be compiled separately. I've decided not to use imake or autoconf because the Makefiles they generate are nearly impossible to read, and I wanted to learn how to do it myself. If you need to hack the Makefile in order to get it to work, please email me so I can take your configuration into account. Using It ====================================================================== aewm adds a titlebar with a small box on the right to each window. The availible commands are as follows: Button Titlebar Box ------ -------- -------- 1 Raise Hide 2 Move Resize 3 Lower Delete Each button will also start a different program when you click on the root window. These programs can be defined with the -new1, -new2, and -new3 options. aewm places new windows based on the position of the mouse. If your mouse is in the center of the the screen, a new window will be centered; as you move the mouse to a side or corner, the position of the window will move there. Please note that there is no `unhide' operation to undo the `hide' operation. You'll need one of the goodies for that. Goodies ====================================================================== The goodies directory has been deleted. All of the default aewm goodies have been deleted. If you want them download aewm source code. The reason for this is because I don't plan on changing any of them so its redundant to include them here. In the future a new goodies directory will be created with my own programs to complement aewm++. Caveats ====================================================================== aewm is really not meant for 2-button mice. If you are stuck with one, make sure you can emulate a third button by chording, and try running xmodmap -e 'pointer = 1 3 2'. This will make your right button be #2, and a chord #3. I have a few 3 button mice lying around so you can always ask me to mail you one. ;-) The Makefiles may cause problems with non-GNU or out-of-date versions of make. If you have problems, try upgrading first, or just substituting `gmake' for `make'. Acknowledgements ====================================================================== In case this sounds familiar, it is. This project would have been nearly impossible without the greatly appreciated work of David Hogan on 9wm, which I based my design on. I can't thank him enough. > The latest version of 9wm is held at ftp://ftp.cs.su.oz.au/dhog/9wm. > 9wm was written by David Hogan (dhog@cs.su.oz.au), a postgraduate > student at the Basser Department of Computer Science, University of > Sydney (http://www.cs.su.oz.au/basser_home.html). Thanks to Christophe Tronche for HTML-ifying the ICCCM and other essential X documentation (http://www.tronche.com/gui/x/). Adam Sampson wrote the initial code for MWM hints and menu-ified goodies. License - Below is the license aewm is under. I have gotten permission from Decklin to release my changes under the GNU GPL. ====================================================================== Copyright (c) 1998-2001 Decklin Foster. THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS", WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES OF ANY KIND. IN NO EVENT SHALL THE AUTHOR BE HELD LIABLE FOR ANY DAMAGES CONNECTED WITH THE USE OF THIS PROGRAM. You are granted permission to copy, publish, distribute, and/or sell copies of this program and any modified versions or derived works, provided that this copyright and notice are not removed or altered. Portions of the code were based on 9wm, which contains this license: > 9wm is free software, and is Copyright (c) 1994 by David Hogan. > Permission is granted to all sentient beings to use this software, > to make copies of it, and to distribute those copies, provided > that: > > (1) the copyright and licence notices are left intact > (2) the recipients are aware that it is free software > (3) any unapproved changes in functionality are either > (i) only distributed as patches > or (ii) distributed as a new program which is not called 9wm > and whose documentation gives credit where it is due > (4) the author is not held responsible for any defects > or shortcomings in the software, or damages caused by it. > > There is no warranty for this software. Have a nice day. Author ====================================================================== aewm is maintained by Decklin Foster . If you have bug reports, comments, flames, want permission to change the license, or are just bored, send me email. Your messages are appreciated (but do read the thing above about virtual desktops ;-). aewm++-1.1.2/main.cc0000644000014400001440000000154410203275070013023 0ustar majicusers/* * frankhale@gmail.com * http://frankhale.org * * This code is released under the GPL license www.gnu.org */ #include "aewm.hh" // Dunno where I ripped this from. Kudos to the author whoever he is! void forkExec(char *cmd) { if(! (strlen(cmd)>0)) return; pid_t pid = fork(); switch (pid) { case 0: execlp("/bin/sh", "sh", "-c", cmd, NULL); cerr << "exec failed, cleaning up child" << endl; exit(1); case -1: cerr << "can't fork" << endl; } } int handleXError(Display *dpy, XErrorEvent *e) { if (e->error_code == BadAccess && e->resourceid == RootWindow(dpy, DefaultScreen(dpy)) ) { cerr << "root window unavailable (maybe another wm is running?)" << endl; exit(1); } return 0; } int main(int argc, char **argv) { WindowManager aewm(argc, argv); return 0; } aewm++-1.1.2/basemenu.cc0000644000014400001440000003210310203275015013670 0ustar majicusers/* * frankhale@gmail.com * http://frankhale.org * * This code is released under the GPL license www.gnu.org */ #include "aewm.hh" BaseMenu::BaseMenu(Display * dpy) { initializeMenu(dpy); } void BaseMenu::initializeMenu(Display *d) { dpy = d; screen = DefaultScreen(dpy); depth = DefaultDepth(dpy, screen); visual = DefaultVisual(dpy, screen); root = RootWindow(dpy, screen); item_window = None; x=0; y=0; x_move=0; y_move=0; width=1; height=1; total_item_height=0; is_visible=false; curs = XCreateFontCursor(dpy, XC_left_ptr); direction=0; ascent=0; descent=0; counter=0; bottom_edge=false; right_edge=false; item_width=0; item_height=0; xres=0; yres=0; curr=NULL; enterOnce=false; xres = WidthOfScreen(ScreenOfDisplay(dpy, screen)); yres = HeightOfScreen(ScreenOfDisplay(dpy, screen)); font = XLoadQueryFont(dpy, DEF_FONT); // Colors XColor dummy; XAllocNamedColor(dpy, DefaultColormap(dpy, screen), DEFAULT_FOREGROUND_COLOR, &xforeground_color, &dummy); XAllocNamedColor(dpy, DefaultColormap(dpy, screen), DEFAULT_BACKGROUND_COLOR, &xbackground_color, &dummy); XAllocNamedColor(dpy, DefaultColormap(dpy, screen), DEFAULT_BORDER_COLOR, &xborder_color, &dummy); XAllocNamedColor(dpy, DefaultColormap(dpy, screen), DEFAULT_MENUITEM_SELECT_COLOR, &xmenuselect_color, &dummy); create_mask = CWBackPixmap | CWBackPixel | CWBorderPixel | CWOverrideRedirect | CWEventMask; attrib.background_pixmap = None; attrib.background_pixel = xbackground_color.pixel; attrib.border_pixel = xborder_color.pixel; attrib.override_redirect = true; attrib.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | EnterWindowMask | LeaveWindowMask; total_item_height=1; item_width = width; item_height = font->ascent + font->descent + 8; item_window = XCreateWindow( dpy, root, x, y, width, height, 1, depth, InputOutput, visual, create_mask, &attrib ); XGCValues gv; gv.function = GXcopy; gv.foreground = wm->getFGColor().pixel; gv.font = font->fid; gc = XCreateGC(dpy, item_window, GCFunction|GCForeground|GCFont, &gv); select_gc = XCreateGC (dpy, item_window, 0, NULL); XDefineCursor(dpy, item_window, curs); enterOnce = true; } BaseMenu::~BaseMenu() { mi.clear(); XDestroyWindow(dpy, item_window); XFreeCursor(dpy, curs); XFreeFont(dpy, font); XFreeGC(dpy, gc); XFreeGC(dpy, select_gc); } // This updates all graphics contexts, gradient pixmaps and determines placement of all menu items. void BaseMenu::updateMenu() { int temp_width=0; int temp_ascent=0; int temp_descent=0; unsigned int count=0; unsigned int charcount=0; int text_width=0; total_item_height=1; list::iterator it; for(it = mi.begin(); it != mi.end(); it++) { charcount = (*it)->name.length(); XTextExtents( font, (*it)->name.c_str(), charcount, &direction, &temp_ascent, &temp_descent, &overall ); if(charcount > count) { count = charcount; temp_width = overall.width; temp_ascent = overall.ascent; temp_descent = overall.descent; width = temp_width + 35; item_width = temp_ascent + temp_descent + 4; height = item_height * mi.size(); text_width = temp_width; } (*it)->item_x = (width/2) - (text_width/2); (*it)->item_y = (item_height/2) + total_item_height + 2; total_item_height += item_height; } XClearWindow(dpy, item_window); XSetWindowBackground (dpy, item_window, xbackground_color.pixel); testMenuEdgeDetect(this); if (y + height >= yres) bottom_edge=True; else bottom_edge=False; if(bottom_edge) XMoveWindow(dpy, item_window, x, yres - height - item_height - 4); XResizeWindow(dpy, item_window, width, height); redraw(); } void BaseMenu::hide() { XUnmapWindow(dpy, item_window); is_visible=false; } // Redraws the entire contents of the menu. void BaseMenu::redraw() { list::iterator it; for(it = mi.begin(); it != mi.end(); it++) { if((*it)->name == "separator") { draw3DLine(item_window, 0, (*it)->item_y-5, width, (*it)->item_y-5); } else { setForeground(xforeground_color.pixel); // Set the gc so it has a black color XDrawString(dpy, item_window, gc, (*it)->item_x, (*it)->item_y + 2, (*it)->name.c_str(), (*it)->name.length()); if((*it)->sub) { XDrawRectangle(dpy, item_window, gc, width - 16, (*it)->item_y - 7, 8, 8); } } } } // Redraws a single menu item on the menu. void BaseMenu::redraw(BaseMenuItem *i) { if(i->name == "separator") { draw3DLine(item_window, 0, i->item_y-5, width, i->item_y-5); } else { setForeground(xforeground_color.pixel); XDrawString(dpy, item_window, gc, i->item_x, i->item_y + 2, i->name.c_str(), i->name.length()); if(i->sub) { XDrawRectangle(dpy, item_window, gc, width - 16, i->item_y - 7, 8, 8); } } } void BaseMenu::insert(std::string n, BaseMenu *sub) { BaseMenuItem *item = new BaseMenuItem(); item->name = n; item->sub = sub; // defaults item->is_selected=False; item->exec = ""; item->function = 0; item->item_x = item->item_y = 0; mi.push_back(item); } void BaseMenu::insert(std::string n, std::string exec, int func) { BaseMenuItem *item = new BaseMenuItem(); const char* temp = exec.c_str(); if(temp[0] == '~') { std::string exec_temp = getenv("HOME"); exec_temp += temp; exec = temp; } item->exec = exec; item->name = n; item->function = func; // defaults item->is_selected=False; item->sub = None; item->item_x = item->item_y = 0; mi.push_back(item); } void BaseMenu::insert(std::string n, std::string exec, BaseMenu *sub, int func) { BaseMenuItem *item = new BaseMenuItem(); const char* temp = exec.c_str(); if(temp[0] == '~') { std::string exec_temp = getenv("HOME"); exec_temp += temp; exec = temp; } item->exec = exec; item->name = n; item->is_selected=False; item->sub = sub; item->function = func; item->item_x = item->item_y = 0; mi.push_back(item); } void BaseMenu::insert(BaseMenuItem *item) { if(item) mi.push_back(item); } int BaseMenu::remove(BaseMenuItem* element) { mi.remove(element); updateMenu(); return mi.size(); } void BaseMenu::removeAll() { mi.clear(); updateMenu(); } void BaseMenu::execute(std::string s) { if(! (s == "")) { pid_t pid = fork(); switch (pid) { case 0: execlp("/bin/sh", "sh", "-c", s.c_str(), NULL); cerr << "exec failed, cleaning up child" << endl; exit(1); case -1: cerr << "can't fork" << endl; } } } void BaseMenu::show() { int mouse_x=0; int mouse_y=0; // Gets the coordinates of the mouse getMousePosition(&mouse_x, &mouse_y); // Check to make sure menu will be displayed on the screen. if (mouse_x + width > xres) { x = xres - width - 1; right_edge=true; } else { x = mouse_x; right_edge=false; } if (mouse_y + height > yres) { y = yres - height; bottom_edge=true; } else { y = mouse_y; bottom_edge=false; } // Move the menu to the position of the mouse pointer XMoveWindow(dpy, item_window, x, y); // Show the menu windows XMapRaised(dpy, item_window); is_visible=true; } void BaseMenu::getMousePosition(int *x, int *y) { Window dw1=None; Window dw2=None; int t1=0; int t2=0; unsigned int t3=0; XQueryPointer(dpy, root, &dw1, &dw2, x, y, &t1, &t2, &t3); } void BaseMenu::show(int nx, int ny) { x = nx; y = ny; XMoveWindow(dpy, item_window, x, y); // Show the menu window XMapRaised(dpy, item_window); XClearWindow(dpy, item_window); is_visible=true; } void BaseMenu::showSub(BaseMenu *sub, int nx, int ny) { sub->x = nx; sub->y = ny; XMoveWindow(dpy, sub->item_window, sub->x, sub->y); // Show the menu window XMapRaised(dpy, sub->item_window); sub->is_visible=true; } void BaseMenu::hide(BaseMenu *sub) { if (sub->is_visible) { // hide the menu windows XUnmapWindow(dpy, sub->item_window); sub->is_visible=false; } } BaseMenuItem *BaseMenu::findMenuItem(int x, int y) { int item_xpos2=0; int item_ypos2=0; if(mi.size()) { list::iterator it; for(it = mi.begin(); it != mi.end(); it++) { item_xpos2 = width-1; item_ypos2 = (*it)->item_y + item_height - 15; if ( (x >= (*it)->item_x - 14) && (x < item_xpos2) && (y >= (*it)->item_y - 14) && (y < item_ypos2) ) { return (*it); } } } return NULL; } void BaseMenu::handleButtonPressEvent(XButtonEvent *e) { switch (e->button) { case Button1: if (curr) handleButton1Press(curr); break; case Button2: if(curr) handleButton2Press(curr); break; case Button3: if (curr) handleButton3Press(curr); break; } } void BaseMenu::handleButtonReleaseEvent(XButtonEvent *e) { switch (e->button) { case Button1: if (curr) handleButton1Release(curr); break; case Button2: if (curr) handleButton2Release(curr); break; case Button3: if (curr) handleButton3Release(curr); break; } } void BaseMenu::setMenuPos(int nx, int ny) { x = nx; y = ny; XMoveWindow(dpy, item_window, x, y); } void BaseMenu::selectMenuItem(unsigned long col) { setForeground( col ); if (! (curr->name == "separator")) { XFillRectangle(dpy, item_window, gc, 0, curr->item_y - 15, item_width - item_height - 2, item_height + 3 ); } } void BaseMenu::hideSubmenus() { list temp_mi; list::iterator it; for(it = mi.begin(); it != mi.end(); it++) { if ((*it)->sub && (*it)->sub->is_visible) { (*it)->sub->hide((*it)->sub); temp_mi = (*it)->sub->mi; // Oh yeah isn't this good programming practice? LOOP: //LinkedListIterator n(temp_mi); list::iterator n_it; for(n_it = temp_mi.begin(); n_it != temp_mi.end(); n_it++) { if((*n_it)->sub && (*n_it)->sub->is_visible) { (*n_it)->sub->hide((*n_it)->sub); temp_mi = (*n_it)->sub->mi; // I love goto's goto LOOP; } } } } } void BaseMenu::handleEnterNotify(XCrossingEvent *e) { if(curr) { hideSubmenus(); // Hide the submenu's which are visible but not needed anymore. selectMenuItem( xmenuselect_color.pixel ); if(curr->sub) { testMenuEdgeDetect(curr->sub); if(curr->sub->right_edge) { if(curr->sub->bottom_edge) { showSub(curr->sub, x - curr->sub->width - 1, yres - curr->sub->height); } else showSub(curr->sub, x - curr->sub->width - 1, y + curr->item_y - item_height + 5 ); } else { if(curr->sub->bottom_edge) { showSub(curr->sub, x + width + 1, xres - curr->sub->height + item_height ); } else { showSub(curr->sub, x + width + 1, y + curr->item_y - item_height + 5 ); } } } redraw(curr); } } void BaseMenu::handleLeaveNotify(XCrossingEvent *e) { if(curr) { selectMenuItem( xbackground_color.pixel ); redraw(curr); curr = NULL; } } void BaseMenu::hideAllVisibleSubmenus() { hide(this); hideSubmenus(); } void BaseMenu::handleExposeEvent(XExposeEvent *e) { if(e->count == 0) redraw(); } void BaseMenu::handleMotionNotifyEvent(XMotionEvent *e) { XEvent temp; if(e->window == item_window) { BaseMenuItem *i = findMenuItem(e->x, e->y); if (i && enterOnce) { curr = i; handleEnterNotify(&temp.xcrossing); enterOnce=false; } else { BaseMenuItem *i = findMenuItem(e->x, e->y); if (i != curr) { handleLeaveNotify(&temp.xcrossing); curr = i; enterOnce=true; } } } } void BaseMenu::testMenuEdgeDetect(BaseMenu *sub) { int mouse_x=0; int mouse_y=0; bool rightEdge=False; bool bottomEdge=False; // Gets the coordinates of the mouse getMousePosition(&mouse_x, &mouse_y); rightEdge = ( ( x + sub->width + 150 ) < xres ) ? true : false; bottomEdge = ( mouse_y + sub->height >= yres ) ? true : false; if (mouse_y + sub->height >= yres ) { //cout << " Menu is at bottom edge " << endl; bottomEdge = true; } else { //cout << " mouse_y + sub->menu.height = " << mouse_y + sub->menu.height // << " wm->getYRes() = " << wm->getYRes() << endl; bottomEdge = false; } // Check to make sure menu will be displayed on the screen. if (rightEdge) sub->right_edge=false; else sub->right_edge=true; if (bottomEdge) sub->bottom_edge=true; else sub->bottom_edge=false; } void BaseMenu::setForeground (unsigned long pixel) { XSetForeground (dpy, gc, pixel); } void BaseMenu::draw3DLine(Window win, int x1, int y1, int x2, int y2) { //setForeground(3); setForeground(xforeground_color.pixel); XDrawLine(dpy, win, gc, x1, y1, x2, y2); //setForeground(4); setForeground(xbackground_color.pixel); XDrawLine(dpy, win, gc, x1, y1-1, x2, y2-1); } aewm++-1.1.2/basemenu.hh0000644000014400001440000001014710203275131013705 0ustar majicusers/* * frankhale@gmail.com * http://frankhale.org * * This code is released under the GPL license www.gnu.org */ #ifndef _BASEMENU_HH_ #define _BASEMENU_HH_ #include "aewm.hh" #define DEFAULT_MENUITEM_SELECT_COLOR "slategrey" #define DEFAULT_FOREGROUND_COLOR "black" #define DEFAULT_BACKGROUND_COLOR "#dddddd" #define DEFAULT_BORDER_COLOR "black" // Not all have been implemented yet (for basemenu) enum { SEND_TO_DESKTOP=0, // EXECUTE_COMMAND=1, // MAXIMIZE=2, // ICONIFY=3, // UNICONIFY=4, // CLOSE=5, // LOWER=6, // SHADE=7 // SHOW=8 }; class BaseMenu; class BaseMenuItem { public: BaseMenuItem() { client = NULL; icon = None; name = ""; exec = ""; function = 0; is_selected = false; item_x = 0; item_y = 0; index = 0; sub = NULL; } Client *client; Window icon; // this menu item may be pointing to an icon for use // in an icon list or something. std::string name; // name showing on menu. std::string exec; // command to execute when clicked. int item_x; int item_y; int function; int index; bool is_selected; BaseMenu *sub; // submenu this item points to. }; class BaseMenu { protected: list mi; Display *dpy; Window root; Visual *visual; int depth; unsigned int screen; // Menu specific stuff ========================== Window item_window; int x, y, x_move, y_move; unsigned int width,height, total_item_height; bool is_visible; // ============================================== XSetWindowAttributes attrib; unsigned long create_mask; XColor xforeground_color, xbackground_color, xborder_color, xmenuselect_color; Cursor curs; GC gc; GC select_gc; XFontStruct *font; XCharStruct overall; int direction; int ascent; int descent; int counter; bool bottom_edge; bool right_edge; unsigned int item_width,item_height; unsigned int xres, yres; // Used to know which item to paint. BaseMenuItem *curr; // This is for our synthetic enter event and we only want this to happen once. // This is set to true once we detect the mouse has entered the item window. bool enterOnce; public: BaseMenu(Display * dpy); virtual ~BaseMenu(); inline list getMenuItemList() const { return mi; } inline int getItemCount() const { return mi.size(); } inline bool isVisible() const { return is_visible; } void setMenuPos(int x, int y); void show(); void show(int x, int y); void showSub(BaseMenu *sub, int x, int y); void hide(BaseMenu *sub); void hideAllVisibleSubmenus(); void updateMenu(); virtual void insert(std::string n, BaseMenu *sub); virtual void insert(std::string n, std::string exec, int func); virtual void insert(std::string n, std::string exec, BaseMenu *sub, int func); virtual void insert(BaseMenuItem *item); int remove(BaseMenuItem *element); void removeAll(); BaseMenuItem *findMenuItem(int x, int y); virtual void handleButtonPressEvent(XButtonEvent *e); virtual void handleButtonReleaseEvent(XButtonEvent *e); void handleEnterNotify(XCrossingEvent *e); void handleLeaveNotify(XCrossingEvent *e); void handleExposeEvent(XExposeEvent *e); void handleMotionNotifyEvent(XMotionEvent *e); // The menu item behavoir is defined with these // virtual functions in a derived class. virtual void handleButton1Press(BaseMenuItem *curr){} virtual void handleButton2Press(BaseMenuItem *curr){} virtual void handleButton3Press(BaseMenuItem *curr){} virtual void handleButton1Release(BaseMenuItem *curr){} virtual void handleButton2Release(BaseMenuItem *curr){} virtual void handleButton3Release(BaseMenuItem *curr){} void execute(std::string s); inline Window getMenuWindow() const { return item_window; } virtual void redraw(); void hide(); private: void initializeMenu(Display *display); virtual void redraw(BaseMenuItem *m); void selectMenuItem(unsigned long col); void getMousePosition(int *x, int *y); void testMenuEdgeDetect(BaseMenu *sub); // Not meant to be called directly by subclasses! Used internally. void hideSubmenus(); void setForeground (unsigned long pixel); void draw3DLine(Window win, int x1, int y1, int x2, int y2); }; #endif aewm++-1.1.2/aewm.hh0000644000014400001440000000457510205770147013060 0ustar majicusers/* * frankhale@gmail.com * http://frankhale.org * * This code is released under the GPL license www.gnu.org */ #ifndef _AEWM_HH_ #define _AEWM_HH_ #define WINDOW_MANAGER_NAME "aewm++" #define VERSION "1.1.2" #define RELEASE_DATE "19 February, 2005" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef SHAPE #include #endif using std::list; using std::string; using std::cout; using std::cerr; using std::endl; #define DEF_FONT "Fixed" #define DEF_FG "#ffffff" #define DEF_BG "slategrey" #define DEF_FC "#dddddd" #define DEF_BD "#000000" #define FOCUSED_BORDER_COLOR "#000000" #define UNFOCUSED_BORDER_COLOR "#888888" #define FOCUSED_WINDOW_TITLE_COLOR "#FFFFFF" #define DEF_NEW1 "xterm -ls -sb -bg black -fg white" #define DEF_BW 1 #define SPACE 3 #define MINSIZE 15 #define EDGE_SNAP "true" #define SNAP 5 #define TEXT_JUSTIFY "center" #define WIRE_MOVE "true" #define MAX_DESKTOPS 4 #define DEF_FM "click" #define DEF_WP "mouse" #define TRANSIENT_WINDOW_HEIGHT 8 // MOTIF hints #define MwmHintsDecorations (1l << 1) #define MwmDecorAll (1l << 0) #define MwmDecorBorder (1l << 1) #define MwmDecorTitle (1l << 3) #define PropMwmHintsElements 3 typedef struct MwmHints { unsigned long flags, functions, decorations; } MwmHints; enum { LEFT_JUSTIFY, CENTER_JUSTIFY, RIGHT_JUSTIFY }; enum { FOCUS_FOLLOW, FOCUS_SLOPPY, FOCUS_CLICK }; enum { APPLY_GRAVITY=1, REMOVE_GRAVITY=-1 }; enum { PIXELS=0, INCREMENTS=1 }; // Shorthand for wordy function calls #define setmouse(w, x, y) XWarpPointer(dpy, None, w, 0, 0, 0, 0, x, y) #define Ungrab() XUngrabPointer(dpy, CurrentTime) #define Grab(w, mask, curs) (XGrabPointer(dpy, w, False, mask, \ GrabModeAsync, GrabModeAsync, None, curs, CurrentTime) == GrabSuccess) // Border width accessor to handle hints/no hints #define BW (has_border ? wm->getOptBW() : 0) // defined in main.cc void forkExec(char *); int handleXError(Display *, XErrorEvent *); class Client; #include "basemenu.hh" #include "genericmenu.hh" #include "windowmenu.hh" #include "iconmenu.hh" #include "client.hh" #include "windowmanager.hh" #endif // _AEWM_HH_ aewm++-1.1.2/windowmanager.cc0000644000014400001440000007151210205767765014766 0ustar majicusers/* * frankhale@gmail.com * http://frankhale.org * * This code is released under the GPL license www.gnu.org */ #include "aewm.hh" WindowManager* wm; #define AEWM_KEY_ALT_COUNT 4 KeySym WindowManager::alt_keys[]= { XK_Delete, XK_End, XK_Page_Up, XK_Page_Down, XK_1, XK_2, XK_3, XK_4, XK_5, XK_6, XK_7, XK_8, XK_9 }; WindowManager::WindowManager(int argc, char** argv) { wm = this; current_desktop=0; focused_client=NULL; parseCommandLine(argc, argv); if(max_desktops <= 0) max_desktops=MAX_DESKTOPS; setupSignalHandlers(); setupDisplay(); scanWins(); // If there are any iconified clients, add them to the icon menu. updateIconMenu(); doEventLoop(); } void WindowManager::parseCommandLine(int argc, char** argv) { // Make the default options equal something opt_font = DEF_FONT; opt_fm = DEF_FM; opt_fg = DEF_FG; opt_fc = DEF_FC; opt_bg = DEF_BG; opt_bd = DEF_BD; opt_tj = TEXT_JUSTIFY; opt_wm = WIRE_MOVE; opt_es = EDGE_SNAP; opt_new1 = DEF_NEW1; opt_bw = DEF_BW; opt_wp = DEF_WP; opt_display=NULL; max_desktops=MAX_DESKTOPS; #define OPT_STR(name, variable) \ if (strcmp(argv[i], name) == 0 && i+1, -fn , -fg|-bg|-bd , " << endl; cerr << " -bw , -md , -tj , -wm ," << endl; cerr << " -new1|-new2 , -fm (follow|sloppy|click), -wp (mouse|random), -usage, -help" << endl; exit(0); } if(strcmp(argv[i], "-help")==0) { cerr << "help: " << WINDOW_MANAGER_NAME << endl << endl; cerr << "-display specifies a display to start the window manager on, The default is display :0." << endl; cerr << "-fn is the font which to use for displaying window title names, icon names and such." << endl; cerr << "-fg, -bg and -bd are colors you wish the foreground, background and border to be for window titlebars." << endl; cerr << "-bw is the border width of the window." << endl; cerr << "-md is the number of maximum virtual desktops, the default is 4." << endl; cerr << "-tj is the text justify variable, its default is center, but you can specify left or right also." << endl; cerr << "-new1 and -new2 are commands you wish the first and second mouse buttons to execute when pressed on the root window." << endl; cerr << "-fm is the focus model you want to use, the default is click to focus." << endl; cerr << "-wp is the window placement model you want to use, the default is place by mouse." << endl; cerr << "-es is for edge snapping, pass either true or false here." << endl; cerr << "-usage prints a reduced version of this information." << endl; cerr << "-help prints this message." << endl << 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; // Set window placement model if (strcmp(opt_wp,"random")==0) rand_window_placement = true; else if (strcmp(opt_wp,"mouse")==0) rand_window_placement = false; else rand_window_placement = false; } void WindowManager::setupSignalHandlers() { signal(SIGINT, sigHandler); signal(SIGTERM, sigHandler); signal(SIGHUP, sigHandler); signal(SIGCHLD, sigHandler); } void WindowManager::setCurrentDesktop(int desk) { if ( (desk < max_desktops) && (desk > 0) ) current_desktop = desk; updateIconMenu(); } void WindowManager::addClientToIconMenu(Client *c) { icon_menu->hide(); if(c->belongsToWhichDesktop() == current_desktop) icon_menu->addThisClient(c); icon_menu->updateMenu(); } void WindowManager::removeClientFromIconMenu(Client *c) { icon_menu->hide(); icon_menu->removeClientFromIconMenu(c); icon_menu->updateMenu(); } void WindowManager::updateClientNameOnIconMenu(Client *c) { icon_menu->updateClientName(c); } void WindowManager::updateIconMenu() { icon_menu->hide(); icon_menu->removeAll(); list::iterator it; for(it = client_list.begin(); it != client_list.end(); it++) { if((*it)->belongsToWhichDesktop() == current_desktop) { if((!(*it)->isTransient()) && ((*it)->hasWindowDecorations())) icon_menu->addThisClient(*it); } } icon_menu->updateMenu(); } void WindowManager::goToDesktop(int d) { unsigned int nwins, i; Window dummyw1, dummyw2, *wins; Client* c; if( (d < max_desktops) && (d >= 0) ) { current_desktop = d; updateIconMenu(); XSetInputFocus(dpy, _button_proxy_win, RevertToNone, CurrentTime); // Preserve stacking order XQueryTree(dpy, root, &dummyw1, &dummyw2, &wins, &nwins); for (i = 0; i < nwins; i++) { c = findClient(wins[i]); if(c) { if(c->belongsToWhichDesktop() == current_desktop) { if(! (c->isIconified())) c->unhide(); } else { if(! (c->isIconified())) c->hide(); } } } XFree(wins); } } void WindowManager::scanWins(void) { unsigned int nwins, i; Window dummyw1, dummyw2, *wins; XWindowAttributes attr; Client *c=NULL; 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) { client_window_list.push_back(wins[i]); c = new Client(dpy, wins[i]); } } XFree(wins); XMapWindow(dpy, _button_proxy_win); grabKeys(_button_proxy_win); XSetInputFocus(dpy, _button_proxy_win, RevertToNone, CurrentTime); } void WindowManager::setupDisplay() { 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); } screen = DefaultScreen(dpy); root = RootWindow(dpy, screen); XSetErrorHandler(handleXError); // 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); XSetWindowAttributes pattr; pattr.override_redirect=True; _button_proxy_win=XCreateSimpleWindow(dpy, root, -80, -80, 24, 24,0,0,0); XChangeWindowAttributes(dpy, _button_proxy_win, CWOverrideRedirect, &pattr); 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); XAllocNamedColor(dpy, DefaultColormap(dpy, screen), FOCUSED_BORDER_COLOR, &focused_border, &dummyc); XAllocNamedColor(dpy, DefaultColormap(dpy, screen), UNFOCUSED_BORDER_COLOR, &unfocused_border, &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); 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 = unfocused_border.pixel; gv.font = font->fid; unfocused_gc = XCreateGC(dpy, root, GCForeground|GCFont, &gv); gv.foreground = fg.pixel; gv.font = font->fid; focused_title_gc = XCreateGC(dpy, root, 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 = SubstructureRedirectMask | SubstructureNotifyMask | ColormapChangeMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask | EnterWindowMask | LeaveWindowMask | PropertyChangeMask | ButtonMotionMask ; XChangeWindowAttributes(dpy, root, CWEventMask, &sattr); grabKeys(root); window_menu = new WindowMenu(dpy); icon_menu = new IconMenu(dpy); } void WindowManager::doEventLoop() { XEvent ev; for (;;) { XNextEvent(dpy, &ev); switch (ev.type) { case KeyPress: handleKeyPressEvent(&ev); break; case ButtonPress: handleButtonPressEvent(&ev); break; case ButtonRelease: handleButtonReleaseEvent(&ev); break; case ConfigureRequest: handleConfigureRequestEvent(&ev); break; case MotionNotify: handleMotionNotifyEvent(&ev); break; case MapRequest: handleMapRequestEvent(&ev); break; case UnmapNotify: handleUnmapNotifyEvent(&ev); break; case DestroyNotify: handleDestroyNotifyEvent(&ev); break; case EnterNotify: handleEnterNotifyEvent(&ev); break; case LeaveNotify: handleLeaveNotifyEvent(&ev); break; case FocusIn: handleFocusInEvent(&ev); break; case FocusOut: handleFocusOutEvent(&ev); break; case ClientMessage: handleClientMessageEvent(&ev); break; case ColormapNotify: handleColormapNotifyEvent(&ev); break; case PropertyNotify: handlePropertyNotifyEvent(&ev); break; case Expose: handleExposeEvent(&ev); break; #ifdef SHAPE default: handleDefaultEvent(&ev); break; #endif } } } void WindowManager::grabKeys(Window w) { int max_desktop_keys=max_desktops; if (max_desktops>9) { max_desktop_keys=9; } for(int i=0;i9) { max_desktop_keys=9; } for(int i=0;ixkey.keycode,0); if (ks==NoSymbol) return; switch(ks) { case XK_Delete: cerr << WINDOW_MANAGER_NAME << " is restarting..." << endl; restart(); break; case XK_End: cerr << WINDOW_MANAGER_NAME << " is quitting." << endl; quitNicely(); break; case XK_Page_Up: if( current_desktop < max_desktops - 1 ) { current_desktop++; goToDesktop(current_desktop); } break; case XK_Page_Down: if( current_desktop > 0 ) { current_desktop--; goToDesktop(current_desktop); } break; } if (ks >= XK_1 && ks <= XK_1+(unsigned)max_desktops && ks - XK_1 <= (unsigned)9) /* no two digit keys */ { if( (unsigned)current_desktop != ks - XK_1 ) { (unsigned)current_desktop = ks - XK_1; goToDesktop(current_desktop); } } } void WindowManager::handleButtonPressEvent(XEvent *ev) { if (ev->xbutton.window == root) { switch (ev->xbutton.button) { case Button1: if(icon_menu->isVisible()) icon_menu->hide(); break; case Button2: if(icon_menu->getItemCount()) { if(icon_menu->isVisible()) icon_menu->hide(); else icon_menu->show(); } break; case Button3: forkExec(opt_new1); if(icon_menu->isVisible()) icon_menu->hide(); break; } } else { Client* c = findClient(ev->xbutton.window); if(c && c->hasWindowDecorations()) { if( (ev->xbutton.button == Button1) && (ev->xbutton.type==ButtonPress) && (ev->xbutton.state==Mod1Mask) && (c->getFrameWindow() == ev->xbutton.window) ) { if (!Grab(c->getFrameWindow(), PointerMotionMask|ButtonReleaseMask, wm->getMoveCursor())) return; } } switch (focus_model) { case FOCUS_FOLLOW: case FOCUS_SLOPPY: if(c) { c->handleButtonEvent(&ev->xbutton); focused_client = c; } break; case FOCUS_CLICK: // if this is the first time the client window's clicked, focus it if(c && c != focused_client) { XSetInputFocus(dpy, c->getAppWindow(), RevertToNone, CurrentTime); focused_client = c; } // otherwise, handle the button click as usual if(c && c == focused_client) c->handleButtonEvent(&ev->xbutton); break; } BaseMenu* mu = window_menu->findMenu(ev->xbutton.window); if(!mu) mu = icon_menu->findMenu(ev->xbutton.window); if(mu) mu->handleButtonPressEvent(&ev->xbutton); } if(ev->xbutton.window==root) XSendEvent(dpy, _button_proxy_win, False, SubstructureNotifyMask, ev); } void WindowManager::handleButtonReleaseEvent(XEvent *ev) { Client* c = findClient(ev->xbutton.window); if(c) { Ungrab(); c->handleButtonEvent(&ev->xbutton); } else { BaseMenu* mu = window_menu->findMenu(ev->xbutton.window); if(!mu) mu = icon_menu->findMenu(ev->xbutton.window); if(mu) { mu->hide(); mu->handleButtonReleaseEvent(&ev->xbutton); } } if(ev->xbutton.window==root) XSendEvent(dpy, _button_proxy_win, False, SubstructureNotifyMask, ev); } void WindowManager::handleConfigureRequestEvent(XEvent *ev) { Client* c = findClient(ev->xconfigurerequest.window); if(c) c->handleConfigureRequest(&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::handleMotionNotifyEvent(XEvent *ev) { Client* c = findClient(ev->xmotion.window); if(c) c->handleMotionNotifyEvent(&ev->xmotion); else { BaseMenu* mu = window_menu->findMenu(ev->xmotion.window); if(!mu) mu = icon_menu->findMenu(ev->xmotion.window); if(mu) mu->handleMotionNotifyEvent(&ev->xmotion); } } void WindowManager::handleMapRequestEvent(XEvent *ev) { Client* c = findClient(ev->xmaprequest.window); if(c) c->handleMapRequest(&ev->xmaprequest); else { client_window_list.push_back(ev->xmaprequest.window); c = new Client(dpy, ev->xmaprequest.window); updateIconMenu(); } } void WindowManager::handleUnmapNotifyEvent(XEvent *ev) { Client* c = findClient(ev->xunmap.window); if(c) { c->handleUnmapEvent(&ev->xunmap); // if unmapping it, note that it's no longer focused focused_client = NULL; } } void WindowManager::handleDestroyNotifyEvent(XEvent *ev) { Client* c = findClient(ev->xdestroywindow.window); if(c) { c->handleDestroyEvent(&ev->xdestroywindow); // if destroying it, note that it's no longer focused focused_client = NULL; } } void WindowManager::handleEnterNotifyEvent(XEvent *ev) { BaseMenu* mu = window_menu->findMenu(ev->xcrossing.window); if(!mu) mu = icon_menu->findMenu(ev->xcrossing.window); if(mu) mu->handleEnterNotify(&ev->xcrossing); else { Client* c = findClient(ev->xcrossing.window); switch (focus_model) { case FOCUS_FOLLOW: if(c) { c->handleEnterEvent(&ev->xcrossing); focused_client = c; } else XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); break; case FOCUS_SLOPPY: // if the pointer's not on a client now, don't change focus if(c) { c->handleEnterEvent(&ev->xcrossing); focused_client = c; } break; } } } void WindowManager::handleLeaveNotifyEvent(XEvent *ev) { BaseMenu* mu = window_menu->findMenu(ev->xcrossing.window); if(!mu) mu = icon_menu->findMenu(ev->xcrossing.window); if(mu) mu->handleLeaveNotify(&ev->xcrossing); } void WindowManager::handleFocusInEvent(XEvent *ev) { if((ev->xfocus.mode==NotifyGrab) || (ev->xfocus.mode==NotifyUngrab)) return; list::iterator iter; for(iter=client_window_list.begin(); iter != client_window_list.end(); iter++) { if(ev->xfocus.window == (*iter)) { Client *c = findClient( (*iter) ); if(c) { unfocusAnyStrayClients(); c->handleFocusInEvent(&ev->xfocus); focused_client = c; grabKeys( (*iter) ); } } else { if(ev->xfocus.window==root && focus_model==FOCUS_FOLLOW) unfocusAnyStrayClients(); } } } void WindowManager::handleFocusOutEvent(XEvent *ev) { list::iterator iter; for(iter=client_window_list.begin(); iter != client_window_list.end(); iter++) { if(ev->xfocus.window == (*iter)) { Client *c = findClient( (*iter) ); if(c) { focused_client = NULL; ungrabKeys( (*iter) ); return; } } } if(focus_model == FOCUS_CLICK) focusPreviousWindowInStackingOrder(); else if(focus_model == FOCUS_SLOPPY && client_list.size()) { unsigned int nwins; Window dummyw1, dummyw2, *wins; Client *c=NULL; XQueryTree(dpy, root, &dummyw1, &dummyw2, &wins, &nwins); for (unsigned int i = 0; i < nwins; i++) { c = findClient(wins[i]); if(c) { if(c->belongsToWhichDesktop()==current_desktop) { focusPreviousWindowInStackingOrder(); return; } } } XSetInputFocus(dpy, PointerRoot, RevertToNone, CurrentTime); } } void WindowManager::handleClientMessageEvent(XEvent *ev) { Client* c = findClient(ev->xclient.window); if(c) c->handleClientMessage(&ev->xclient); } void WindowManager::handleColormapNotifyEvent(XEvent *ev) { Client* c = findClient(ev->xcolormap.window); if(c) c->handleColormapChange(&ev->xcolormap); } void WindowManager::handlePropertyNotifyEvent(XEvent *ev) { Client* c = findClient(ev->xproperty.window); if(c) c->handlePropertyChange(&ev->xproperty); } void WindowManager::handleExposeEvent(XEvent *ev) { BaseMenu* mu = window_menu->findMenu(ev->xexpose.window); if(!mu) mu = icon_menu->findMenu(ev->xexpose.window); if(mu) mu->handleExposeEvent(&ev->xexpose); else { Client* c = findClient(ev->xexpose.window); if(c) c->handleExposeEvent(&ev->xexpose); } } void WindowManager::handleDefaultEvent(XEvent *ev) { Client* c = findClient(ev->xany.window); if(c) { if (shape && ev->type == shape_event) c->handleShapeChange((XShapeEvent *)&ev); } } void WindowManager::unfocusAnyStrayClients() { // To prevent two windows titlebars from being painted with the focus color we // will prevent that from happening by setting all windows to false. list::iterator iter; for(iter=client_list.begin(); iter != client_list.end(); iter++) (*iter)->setFocus(false); } void WindowManager::focusPreviousWindowInStackingOrder() { unsigned int nwins, i; Window dummyw1, dummyw2, *wins; Client* c=NULL; XSetInputFocus(dpy, _button_proxy_win, RevertToNone, CurrentTime); XQueryTree(dpy, root, &dummyw1, &dummyw2, &wins, &nwins); if(client_list.size()) { list client_list_for_current_desktop; for (i = 0; i < nwins; i++) { c = findClient(wins[i]); if(c) { if((c->belongsToWhichDesktop()==current_desktop && c->hasWindowDecorations() && (c->isIconified() == false) )) client_list_for_current_desktop.push_back(c); } } if(client_list_for_current_desktop.size()) { list::iterator iter = client_list_for_current_desktop.end(); iter--; if( (*iter) ) { XSetInputFocus(dpy, (*iter)->getAppWindow(), RevertToNone, CurrentTime); client_list_for_current_desktop.clear(); XFree(wins); return; } } } XFree(wins); } 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::addClient(Client *c) { client_list.push_back(c); } void WindowManager::removeClient(Client* c) { removeClientFromIconMenu(c); client_window_list.remove(c->getAppWindow()); client_list.remove(c); } Client* WindowManager::findClient(Window w) { if(client_list.size()) { list::iterator iter = client_list.begin(); for(; iter != client_list.end(); iter++) { if (w == (*iter)->getTitleWindow() || w == (*iter)->getFrameWindow() || w == (*iter)->getAppWindow()) return (*iter); } } return NULL; } void WindowManager::findTransientsToMapOrUnmap(Window win, bool hide) { list::iterator iter; if(client_list.size()) { for(iter=client_list.begin(); iter!= client_list.end(); iter++) { if((*iter)->getTransientWindow() == win) { if(hide) { if(! (*iter)->isIconified()) (*iter)->iconify(); } else { if((*iter)->isIconified()) (*iter)->unhide(); } } } } } void WindowManager::restart() { cleanup(); execl("/bin/sh", "sh", "-c", command_line.c_str(), 0); } void WindowManager::quitNicely() { cleanup(); exit(0); } void WindowManager::cleanup() { cerr << WINDOW_MANAGER_NAME << " is cleaning up.... " << endl; unsigned int nwins, i; Window dummyw1, dummyw2, *wins; Client* c; XDestroyWindow(dpy, _button_proxy_win); ungrabKeys(root); // 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 window_menu; delete icon_menu; XFreeFont(dpy, font); XFreeCursor(dpy, move_curs); XFreeCursor(dpy, arrow_curs); XFreeGC(dpy, invert_gc); XFreeGC(dpy, border_gc); XFreeGC(dpy, string_gc); XFreeGC(dpy, unfocused_gc); XFreeGC(dpy, focused_title_gc); XInstallColormap(dpy, DefaultColormap(dpy, screen)); XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); XCloseDisplay(dpy); } /* If we can't find a wm->wm_state we're going to have to assume * Withdrawn. This is not exactly optimal, since we can't really * distinguish between the case where no WM has run yet and when the * state was explicitly removed (Clients are allowed to either set the * atom to Withdrawn or just remove it... yuck.) */ long WindowManager::getWMState(Window window) { Atom real_type; int real_format; unsigned long items_read, items_left; long *data, state = WithdrawnState; if (XGetWindowProperty(dpy, window, atom_wm_state, 0L, 2L, False, wm->atom_wm_state, &real_type, &real_format, &items_read, &items_left, (unsigned char **) &data) == Success && items_read) { state = *data; XFree(data); } return state; } /* Attempt to follow the ICCCM by explicity specifying 32 bits for * this property. Does this goof up on 64 bit systems? */ void WindowManager::setWMState(Window window, int state) { CARD32 data[2]; data[0] = state; data[1] = None; // Icon? We don't need no steenking icon. XChangeProperty(dpy, window, atom_wm_state, atom_wm_state, 32, PropModeReplace, (unsigned char *)data, 2); } // The name of this function is a bit misleading: if the client // doesn't listen to WM_DELETE then we just terminate it with extreme // prejudice. void WindowManager::sendWMDelete(Window window) { int i, n, found = 0; Atom *protocols; if (XGetWMProtocols(dpy, window, &protocols, &n)) { for (i=0; iatom_mwm_hints, &real_type, &real_format, &items_read, &items_left, (unsigned char **) &data) == Success && items_read >= PropMwmHintsElements) { return data; } else return NULL; } void WindowManager::sigHandler(int signal) { switch (signal) { case SIGINT: case SIGTERM: wm->quitNicely(); break; case SIGHUP: wm->restart(); break; case SIGCHLD: wait(NULL); break; } } aewm++-1.1.2/windowmanager.hh0000644000014400001440000001250110205770024014747 0ustar majicusers/* * frankhale@gmail.com * http://frankhale.org * * This code is released under the GPL license www.gnu.org */ #ifndef _WINDOWMANAGER_HH_ #define _WINDOWMANAGER_HH_ #include "aewm.hh" class WindowManager { private: /* member variables */ list client_list; list client_window_list; WindowMenu *window_menu; IconMenu *icon_menu; Client* focused_client; XFontStruct *font; GC invert_gc, string_gc, border_gc, unfocused_gc, focused_title_gc; XColor fg, bg, bd, fc; XColor focused_border, unfocused_border; Cursor move_curs, arrow_curs; Display *dpy; Window root; Window _button_proxy_win; int screen; int current_desktop; // The screen max resolutions (x,y) int xres; int yres; #ifdef SHAPE int shape, shape_event; #endif string command_line; int max_desktops; int focus_model; char *opt_display, *opt_font, *opt_fc, *opt_fg, *opt_fm, *opt_bg, *opt_bd, *opt_tj, *opt_wm, *opt_wp, *opt_es, *opt_new1; int opt_bw; int opt_text_justify; bool wire_move; bool rand_window_placement; bool edge_snap; static KeySym alt_keys[]; public: /* member variables */ Atom atom_wm_state; Atom atom_wm_change_state; Atom atom_wm_protos; Atom atom_wm_delete; Atom atom_wm_cmapwins; Atom atom_wm_takefocus; // Atom for motif hints Atom atom_mwm_hints; private: /* Member Functions */ void setupSignalHandlers(); void setupDisplay(); void cleanup(); void doEventLoop(); void scanWins(); void handleKeyPressEvent(XEvent *ev); void handleButtonPressEvent(XEvent *ev); void handleButtonReleaseEvent(XEvent *ev); void handleConfigureRequestEvent(XEvent *ev); void handleMotionNotifyEvent(XEvent *ev); void handleMapRequestEvent(XEvent *ev); void handleUnmapNotifyEvent(XEvent *ev); void handleDestroyNotifyEvent(XEvent *ev); void handleEnterNotifyEvent(XEvent *ev); void handleLeaveNotifyEvent(XEvent *ev); void handleFocusInEvent(XEvent *ev); void handleFocusOutEvent(XEvent *ev); void handleClientMessageEvent(XEvent *ev); void handleColormapNotifyEvent(XEvent *ev); void handlePropertyNotifyEvent(XEvent *ev); void handleExposeEvent(XEvent *ev); void handleDefaultEvent(XEvent *ev); public: /* Member Functions */ WindowManager(int argc, char** argv); void parseCommandLine(int argc, char** argv); void quitNicely(); void restart(); Client* getFocusedClient() { return focused_client; } inline list getClientList() const { return client_list; } void addClient(Client *c); void removeClient(Client* c); Client* findClient(Window w); void focusPreviousWindowInStackingOrder(); void unfocusAnyStrayClients(); void findTransientsToMapOrUnmap(Window win, bool hide); inline WindowMenu* getWindowMenu() const { return window_menu; } inline IconMenu* getIconMenu() const { return icon_menu; } void updateIconMenu(); void addClientToIconMenu(Client *c); void updateClientNameOnIconMenu(Client *c); void removeClientFromIconMenu(Client *c); inline XFontStruct* getFont() const { return font; } inline GC getInvertGC() const { return invert_gc; } inline GC getStringGC() const { return string_gc; } inline GC getBorderGC() const { return border_gc; } inline GC getUnfocusedGC() const { return unfocused_gc; } inline GC getFocusedTitleGC() const { return focused_title_gc;} inline Cursor getMoveCursor() const { return move_curs; } inline Cursor getArrowCursor() const { return arrow_curs; } inline XColor getFGColor() const { return fg; } inline XColor getFCColor() const { return fc; } inline XColor getBGColor() const { return bg; } inline XColor getBDColor() const { return bd; } inline XColor getFocusedBorderColor() const { return focused_border; } inline XColor getUnFocusedBorderColor() const { return unfocused_border; } #ifdef SHAPE inline int getShape() const { return shape; } inline int getShapeEvent() const { return shape_event; } #endif long getWMState(Window window); void setWMState(Window window, int state); void sendWMDelete(Window window); int sendXMessage(Window w, Atom a, long mask, long x); MwmHints* getMWMHints(Window w); void getMousePosition(int *x, int *y); void goToDesktop(int d); inline int getCurrentDesktop() const { return current_desktop; } void setCurrentDesktop(int desk); // Returns a number corresponding to the current focus model. inline int getFocusModel() const { return focus_model; } // Accepts a number corresponding to a new focus model. inline void setFocusModel(int new_fm) { switch (new_fm) { case FOCUS_FOLLOW: case FOCUS_SLOPPY: case FOCUS_CLICK: focus_model = new_fm; break; default: focus_model=FOCUS_CLICK; break; } //if (new_fm == FOCUS_FOLLOW || new_fm == FOCUS_SLOPPY || new_fm == FOCUS_CLICK) focus_model = new_fm; } inline int getTextJustify() const { return opt_text_justify; } inline bool getWireMove() const { return wire_move; } inline bool getEdgeSnap() const { return edge_snap; } inline bool getRandPlacement() const { return rand_window_placement; } inline int getMaxDesktops() const { return max_desktops; } void setMaxDesktops(int max_desks) { max_desktops=max_desks; } inline int getOptBW() const { return opt_bw; } void grabKeys(Window w); void ungrabKeys(Window w); static void sigHandler(int signal); }; extern WindowManager *wm; #endif aewm++-1.1.2/client.cc0000644000014400001440000006510610205770332013364 0ustar majicusers/* * frankhale@gmail.com * http://frankhale.org * * This code is released under the GPL license www.gnu.org */ #include "aewm.hh" Client::Client(Display *d, Window new_client) { initialize(d); wm->addClient(this); makeNewClient(new_client); } Client::~Client() { removeClient(); } void Client::initialize(Display *d) { dpy = d; belongs_to_desktop = 0; name = NULL; window = None; frame = None; title = None; trans = None; window_menu = NULL; x = 1; y = 1; width = 1; height = 1; ignore_unmap = 0; pointer_x = 0; pointer_y = 0; old_cx = 0; old_cy = 0; wire_move = wm->getWireMove(); #ifdef SHAPE has_been_shaped = false; #endif has_title = true; has_border = true; has_focus = false; is_iconified = false; // Extra Window States is_shaded = false; is_maximized = false; is_visible = false; is_being_dragged = false; do_drawoutline_once = false; is_being_resized = false; last_button1_time = 0; old_x = 0; old_y = 0; old_width = 1; old_height = 1; direction = 0; ascent = 0; descent = 0; text_width = 0; text_justify = 0; justify_style = wm->getTextJustify(); screen = DefaultScreen(dpy); root = RootWindow(dpy, screen); xres = WidthOfScreen(ScreenOfDisplay(dpy, screen)); yres = HeightOfScreen(ScreenOfDisplay(dpy, screen)); button_pressed = false; } void Client::getXClientName() { if(name) XFree(name); XFetchName(dpy, window, &name); if(name==NULL) { name = "no name"; } else { XTextExtents(wm->getFont(), name , strlen(name), &direction, &ascent, &descent, &overall); text_width = overall.width; } } // Set up a client structure for the new (not-yet-mapped) window. The // confusing bit is that we have to ignore 2 unmap events if the // client was already mapped but has IconicState set (for instance, // when we are the second window manager in a session). That's // because there's one for the reparent (which happens on all viewable // windows) and then another for the unmapping itself. void Client::makeNewClient(Window w) { XWindowAttributes attr; XWMHints *hints; MwmHints *mhints; long dummy; XGrabServer(dpy); window = w; getXClientName(); XGetTransientForHint(dpy, window, &trans); XGetWindowAttributes(dpy, window, &attr); x = attr.x; y = attr.y; width = attr.width; height = attr.height; border_width = attr.border_width; cmap = attr.colormap; size = XAllocSizeHints(); XGetWMNormalHints(dpy, window, size, &dummy); old_x = x; old_y = y; old_width = width; old_height = height; if ((mhints = wm->getMWMHints(window))) { if (mhints->flags & MwmHintsDecorations && !(mhints->decorations & MwmDecorAll)) { has_title = mhints->decorations & MwmDecorTitle; has_border = mhints->decorations & MwmDecorBorder; } XFree(mhints); } if (attr.map_state == IsViewable) ignore_unmap++; { initPosition(); if ((hints = XGetWMHints(dpy, w))) { if (hints->flags & StateHint) wm->setWMState(window, hints->initial_state); else wm->setWMState(window, NormalState); XFree(hints); } } window_menu = wm->getWindowMenu(); gravitate(APPLY_GRAVITY); reparent(); if(belongs_to_desktop == -1) { belongs_to_desktop = wm->getCurrentDesktop(); } if (wm->getWMState(window) == IconicState) iconify(); else //if (wm->getWMState(window) == NormalState || wm->getWMState(window) == WithdrawnState) { unhide(); if(wm->getFocusModel() == FOCUS_CLICK) XSetInputFocus(dpy, window, RevertToNone, CurrentTime); } XSync(dpy, False); XUngrabServer(dpy); } void Client::removeClient() { XGrabServer(dpy); if(trans) XSetInputFocus(dpy, trans, RevertToNone, CurrentTime); XUngrabButton(dpy, AnyButton, AnyModifier, frame); gravitate(REMOVE_GRAVITY); XReparentWindow(dpy, window, root, x, y); XDestroyWindow(dpy, title); XDestroyWindow(dpy, frame); if (name) XFree(name); if (size) XFree(size); XSync(dpy, False); XUngrabServer(dpy); window_menu->hide(); wm->removeClient(this); } // For a regular window, trans is None (false), and we include // enough space to draw the title. For a transient window we just make // a tiny strip. int Client::theight() { if (!has_title) return 0; int title_size = wm->getFont()->ascent + wm->getFont()->descent + SPACE; if(trans) return TRANSIENT_WINDOW_HEIGHT; // size for transient titlebar heights not to big, not too small else return title_size; } // This is called whenever we update our Client stuff. void Client::sendConfig() { XConfigureEvent ce; ce.type = ConfigureNotify; ce.event = window; ce.window = window; ce.x = x; ce.y = y; ce.width = width; ce.height = height; ce.border_width = border_width; //ce.above = (is_always_on_top) ? Above : Below; ce.override_redirect = False; XSendEvent(dpy, window, False, StructureNotifyMask, (XEvent *)&ce); } void Client::redraw() { if (!has_title) return; GC gc; if(has_focus) gc = wm->getBorderGC(); else gc = wm->getUnfocusedGC(); XDrawLine(dpy, title, gc, 0, theight() - BW + BW/2, width, theight() - BW + BW/2); XDrawLine(dpy, title, gc, width - theight()+ BW/2, 0, width - theight()+ BW/2, theight()); if(has_focus) gc = wm->getFocusedTitleGC(); if (!trans && name) { switch(justify_style) { case LEFT_JUSTIFY: text_justify = SPACE; break; case CENTER_JUSTIFY: text_justify = ( (width / 2) - (text_width / 2) ); break; case RIGHT_JUSTIFY: text_justify = width - text_width - 25; break; } if(name!=NULL) { XDrawString(dpy, title, gc, text_justify, wm->getFont()->ascent+1, name, strlen(name)); } } } // Window gravity is a mess to explain, but we don't need to do much // about it since we're using X borders. For NorthWest et al, the top // left corner of the window when there is no WM needs to match up // with the top left of our fram once we manage it, and likewise with // SouthWest and the bottom right (these are the only values I ever // use, but the others should be obvious.) Our titlebar is on the top // so we only have to adjust in the first case. void Client::gravitate(int multiplier) { int dy = 0; int gravity = (size->flags & PWinGravity) ? size->win_gravity : NorthWestGravity; switch (gravity) { case NorthWestGravity: case NorthEastGravity: case NorthGravity: dy = theight(); break; case CenterGravity: dy = theight()/2; break; } y += multiplier * dy; } /* Well, the man pages for the shape extension say nothing, but I was * able to find a shape.PS.Z on the x.org FTP site. What we want to do * here is make the window shape be a boolean OR (or union, if you * prefer) of the client's shape and our titlebar. The titlebar * requires both a bound and a clip because it has a border -- the X * server will paint the border in the region between the two. (I knew * that using X borders would get me eventually... ;-)) */ #ifdef SHAPE void Client::setShape() { int n=0, order=0; XRectangle temp, *dummy; dummy = XShapeGetRectangles(dpy, window, ShapeBounding, &n, &order); if (n > 1) { XShapeCombineShape(dpy, frame, ShapeBounding, 0, theight(), window, ShapeBounding, ShapeSet); temp.x = -BW; temp.y = -BW; temp.width = width + 2*BW; temp.height = theight() + BW; XShapeCombineRectangles(dpy, frame, ShapeBounding, 0, 0, &temp, 1, ShapeUnion, YXBanded); temp.x = 0; temp.y = 0; temp.width = width; temp.height = theight() - BW; XShapeCombineRectangles(dpy, frame, ShapeClip, 0, theight(), &temp, 1, ShapeUnion, YXBanded); has_been_shaped = 1; } else if (has_been_shaped) { // I can't find a 'remove all shaping' function... temp.x = -BW; temp.y = -BW; temp.width = width + 2*BW; temp.height = height + theight() + 2*BW; XShapeCombineRectangles(dpy, frame, ShapeBounding, 0, 0, &temp, 1, ShapeSet, YXBanded); } XFree(dummy); } #endif void Client::iconify() { if (!ignore_unmap) ignore_unmap++; if(has_focus) setFocus(false); XUnmapWindow(dpy, window); XUnmapWindow(dpy, title); XUnmapWindow(dpy, frame); is_iconified=true; wm->setWMState(window, IconicState); if(!trans) { wm->findTransientsToMapOrUnmap(window, true); } is_visible=false; } void Client::hide() { if (!ignore_unmap) ignore_unmap++; if(has_focus) setFocus(false); if(window_menu->isVisible()) window_menu->hide(); XUnmapWindow(dpy, window); XUnmapWindow(dpy, title); XUnmapWindow(dpy, frame); wm->setWMState(window, WithdrawnState); is_visible=false; } void Client::unhide() { if(belongs_to_desktop == wm->getCurrentDesktop()) { XMapRaised(dpy, window); XMapRaised(dpy, title); XMapRaised(dpy, frame); if(is_iconified) { is_iconified=false; } wm->setWMState(window, NormalState); if(!trans) wm->findTransientsToMapOrUnmap(window, false); if(wm->getFocusModel() == FOCUS_CLICK) XSetInputFocus(dpy, window, RevertToNone, CurrentTime); is_visible=true; } } // This function sets up the initial position of windows when they are mapped // for the first time. It still needs some work done to it to make it more // aware of _NET_WM_STRUT's // // // XSizeHints structure definition // // typedef struct { // long flags; // int x, y; // int width, height; // int min_width, min_height; // int max_width, max_height; // int width_inc, height_inc; // struct { // int x; // int y; // } min_aspect, max_aspect; // int base_width, base_height; // int win_gravity; // // } XSizeHints; // void Client::initPosition() { int mouse_x, mouse_y; unsigned int w, h; unsigned int border_width, depth; XWindowAttributes attr; XGetWindowAttributes(dpy, window, &attr); if (attr.map_state == IsViewable) return; XGetGeometry(dpy, window, &root, &x, &y, &w, &h, &border_width, &depth); width = (int)w; height = (int)h; if (size->flags & PPosition) { if(!x) x = size->x; if(!y) y = size->y; } else { if (size->flags & USPosition) { if(!x) x = size->x; if(!y) y = size->y; } else if ( (x==0) || (y==0) ) { if( width>=xres && height>=yres ) { x=0; y=0; width=xres; height=yres-theight(); } else { wm->getMousePosition(&mouse_x, &mouse_y); if(mouse_x && mouse_y) { if (wm->getRandPlacement()) { x = (rand() % (unsigned int) ((xres - width) * 0.94)) + ((unsigned int) (xres * 0.03)); y = (rand() % (unsigned int) ((yres - height) * 0.94)) + ((unsigned int) (yres * 0.03)); } else { x = (int) (((long) (xres - width) * (long) mouse_x) / (long) xres); y = (int) (((long) (yres - height - theight()) * (long) mouse_y) / (long) yres); y = (yflags & PMaxSize) { width = size->max_width; height = size->max_height; XMoveResizeWindow(dpy, frame, x, y-theight(), width, height+theight()); } else { x=0; y=0; width=xres; height=yres; XMoveResizeWindow(dpy, frame, x, y, width, height); y = theight(); height -= theight(); } is_maximized=true; } else { x=old_x; y=old_y; width=old_width; height=old_height; XMoveResizeWindow(dpy, frame, old_x, old_y - theight(), old_width, old_height + theight()); is_maximized=false; if(is_shaded) is_shaded=false; } XResizeWindow(dpy, title, width, theight()); XResizeWindow(dpy, window, width, height); sendConfig(); } void Client::handleMotionNotifyEvent(XMotionEvent *ev) { int nx=0, ny=0; if((ev->state & Button1Mask) && (wm->getFocusedClient() == this)) { if(! do_drawoutline_once && wire_move) { XGrabServer(dpy); drawOutline(); do_drawoutline_once=true; is_being_dragged=true; } if(wire_move) drawOutline(); nx = old_cx + (ev->x_root - pointer_x); ny = old_cy + (ev->y_root - pointer_y); if(wm->getEdgeSnap()) { // Move beyond edges of screen if(nx == xres - width) nx = xres - width + 1; else if(nx == 0) nx = -1; if(ny == yres - SNAP) ny = yres - SNAP - 1; else if(ny == theight()) ny = theight() - 1; // Snap to edges of screen if( (nx + width >= xres - SNAP) && (nx + width <= xres) ) nx = xres - width; else if( (nx <= SNAP) && (nx >= 0) ) nx = 0; if(is_shaded) { if( (ny >= yres - SNAP) && (ny <= yres) ) ny = yres; else if( (ny - theight() <= SNAP) && (ny - theight() >= 0)) ny = theight(); } else { if( (ny + height >= yres - SNAP) && (ny + height <= yres) ) ny = yres - height; else if( (ny - theight() <= SNAP) && (ny - theight() >= 0)) ny = theight(); } } x=nx; y=ny; if(!wire_move) { XMoveWindow(dpy, frame, nx, ny-theight()); sendConfig(); } if(wire_move) drawOutline(); } else if(ev->state & Button2Mask) { if(! is_being_resized) { int in_box = (ev->x >= width - theight()) && (ev->y <= theight()); if(! in_box) return; } if(! do_drawoutline_once) { XGrabServer(dpy); is_being_resized=true; do_drawoutline_once=true; drawOutline(); setmouse(frame, width, height+theight()); } else { if((ev->x > 50) && (ev->y > 50)) { drawOutline(); width = ev->x; height = ev->y - theight(); getIncsize(&width, &height, PIXELS); if (size->flags & PMinSize) { if (width < size->min_width) width = size->min_width; if (height < size->min_height) height = size->min_height; if(width<100) width=100; if(height<50) height=50; } if (size->flags & PMaxSize) { if (width > size->max_width) width = size->max_width; if (height > size->max_height) height = size->max_height; if(width>xres) width=xres; if(height>yres) height=yres; } drawOutline(); } } } } void Client::drawOutline() { if(! is_shaded) { XDrawRectangle(dpy, root, wm->getInvertGC(), x + BW/2, y - theight() + BW/2, width + BW, height + theight() + BW); XDrawRectangle(dpy, root, wm->getInvertGC(), x + BW/2 + 4, y - theight() + BW/2 + 4, width + BW - 8, height + theight() + BW - 8); } else { XDrawRectangle(dpy, root, wm->getInvertGC(), x + BW/2, y - theight() + BW/2, width + BW, theight() + BW); } } // If the window in question has a ResizeInc int, then it wants to be // resized in multiples of some (x,y). Here we set x_ret and y_ret to // the number of multiples (if mode == INCREMENTS) or the correct size // in pixels for said multiples (if mode == PIXELS). int Client::getIncsize(int *x_ret, int *y_ret, int mode) { int basex, basey; if (size->flags & PResizeInc) { basex = (size->flags & PBaseSize) ? size->base_width : (size->flags & PMinSize) ? size->min_width : 0; basey = (size->flags & PBaseSize) ? size->base_height : (size->flags & PMinSize) ? size->min_height : 0; if (mode == PIXELS) { *x_ret = width - ((width - basex) % size->width_inc); *y_ret = height - ((height - basey) % size->height_inc); } else // INCREMENTS { *x_ret = (width - basex) / size->width_inc; *y_ret = (height - basey) / size->height_inc; } return 1; } return 0; } // This function makes it so only the titlebar shows. void Client::shade() { raise(); if(! is_shaded) { XResizeWindow(dpy, frame, width, theight() - 1); is_shaded=true; } else { XResizeWindow(dpy, frame, width, height + theight()); is_shaded=false; } } // Because we are redirecting the root window, we get ConfigureRequest // events from both clients we're handling and ones that we aren't. // For clients we manage, we need to fiddle with the frame and the // client window, and for unmanaged windows we have to pass along // everything unchanged. Thankfully, we can reuse (a) the // XWindowChanges struct and () the code to configure the client // window in both cases. // // Most of the assignments here are going to be garbage, but only the // ones that are masked in by e->value_mask will be looked at by the X // server. void Client::handleConfigureRequest(XConfigureRequestEvent *e) { XWindowChanges wc; gravitate(REMOVE_GRAVITY); if (e->value_mask & CWX) x = e->x; if (e->value_mask & CWY) y = e->y; if (e->value_mask & CWWidth) width = e->width; if (e->value_mask & CWHeight) height = e->height; gravitate(APPLY_GRAVITY); wc.x = x; wc.y = y - theight(); wc.width = width; wc.height = height + theight(); wc.border_width = BW; wc.sibling = e->above; wc.stack_mode = e->detail; XConfigureWindow(dpy, frame, e->value_mask, &wc); if(! is_shaded) { XMoveResizeWindow(dpy, frame,x,y-theight(), width, height+theight()); XResizeWindow(dpy, title, width, theight()); XMoveResizeWindow(dpy, window,0,theight(),width,height); } // If an app wants to place his window in a bogus position // like offscreen then fix its position. Lets see if this // works out okay. Warez and Porn sites have a bad habit // of trying to place the Mozilla browser window titlebar // just offscreen so you can't close the window. // The bastards! if( (x + width > xres) || (height + theight() > yres) || (x > xres) || (y > yres) || (x < 0) || (y < 0) ) initPosition(); #ifdef SHAPE if (e->value_mask & (CWWidth|CWHeight)) setShape(); #endif sendConfig(); if (e->value_mask & CWY) wc.x = 0; if (e->value_mask & CWY) wc.y = theight(); if (e->value_mask & CWWidth) wc.width = e->width; if (e->value_mask & CWHeight) wc.height = e->height; wc.sibling = e->above; wc.stack_mode = e->detail; XConfigureWindow(dpy, e->window, e->value_mask, &wc); } void Client::handleMapRequest(XMapRequestEvent *e) { unhide(); } void Client::handleUnmapEvent(XUnmapEvent *e) { if (! ignore_unmap) delete this; } // This happens when a window is iconified and destroys itself. An // Unmap event wouldn't happen in that case because the window is // already unmapped. void Client::handleDestroyEvent(XDestroyWindowEvent *e) { delete this; } // If a client wants to iconify itself (boo! hiss!) it must send a // special kind of ClientMessage. We might set up other handlers here // but there's nothing else required by the ICCCM. void Client::handleClientMessage(XClientMessageEvent *e) { if (e->message_type == wm->atom_wm_change_state && e->format == 32 && e->data.l[0] == IconicState) iconify(); } void Client::handlePropertyChange(XPropertyEvent *e) { long dummy; switch (e->atom) { case XA_WM_NAME: getXClientName(); wm->updateClientNameOnIconMenu(this); XClearWindow(dpy, title); redraw(); break; case XA_WM_NORMAL_HINTS: XGetWMNormalHints(dpy, window, size, &dummy); break; case XA_WM_TRANSIENT_FOR: if(!trans) XGetTransientForHint(dpy, window, &trans); break; } } void Client::reparent() { XSetWindowAttributes pattr; XGrabServer(dpy); pattr.background_pixel = wm->getFCColor().pixel; pattr.border_pixel = wm->getBDColor().pixel; pattr.do_not_propagate_mask = ButtonPressMask|ButtonReleaseMask|ButtonMotionMask; pattr.override_redirect=False; pattr.event_mask = ButtonMotionMask | SubstructureRedirectMask | SubstructureNotifyMask | ButtonPressMask | ButtonReleaseMask | ExposureMask | EnterWindowMask | LeaveWindowMask ; int b_w = BW; if(border_width) { b_w = border_width; XSetWindowBorderWidth(dpy, window, 0); } else { b_w = BW; } frame = XCreateWindow(dpy, root, x, y - theight(), width, height + theight(), b_w, DefaultDepth(dpy, screen ), CopyFromParent, DefaultVisual(dpy, screen ), CWOverrideRedirect|CWDontPropagate|CWBackPixel|CWBorderPixel|CWEventMask, &pattr); // This window is used to house the window title and title bar button title = XCreateWindow(dpy, frame, 0, 0, width, theight(), 0, DefaultDepth(dpy, screen ), CopyFromParent, DefaultVisual(dpy, screen ), CWOverrideRedirect|CWDontPropagate|CWBackPixel|CWBorderPixel|CWEventMask, &pattr); #ifdef SHAPE if (wm->getShape()) { XShapeSelectInput(dpy, window, ShapeNotifyMask); setShape(); } #endif // We don't want these masks to be propagated down to the frame XChangeWindowAttributes(dpy, window, CWDontPropagate, &pattr); XSelectInput(dpy, window, FocusChangeMask|PropertyChangeMask); XReparentWindow(dpy, window, frame, 0, theight()); XGrabButton(dpy, Button1, AnyModifier, frame, 1, ButtonPressMask|ButtonReleaseMask, GrabModeSync, GrabModeAsync, None, None); sendConfig(); XSync(dpy, false); XUngrabServer(dpy); } // This function handles the button events. // Remember this is designed for a 3 button mouse and to the way I like // the buttons laid out. If you want something different then edit // this until your heart is content. void Client::handleButtonEvent(XButtonEvent *e) { int in_box; // Formula to tell if the pointer is in the little // box on the right edge of the window. This box is // the iconify button, resize button and close button. in_box = (e->x >= width - theight()) && (e->y <= theight()); // Used to compute the pointer position on click // used in the motion handler when doing a window move. old_cx = x; old_cy = y; pointer_x = e->x_root; pointer_y = e->y_root; // Allow us to get clicks from anywhere on the window // so click to raise works. XAllowEvents(dpy, ReplayPointer, CurrentTime); window_menu->hide(); switch (e->button) { case Button4: case Button5: { if(is_being_resized) { drawOutline(); do_drawoutline_once=false; is_being_resized=false; XResizeWindow(dpy, frame, width, height + theight()); XResizeWindow(dpy, title, width, theight()); XResizeWindow(dpy, window, width, height); sendConfig(); XUngrabServer(dpy); XSync(dpy, False); return; } } break; case Button1: { if (e->type == ButtonPress) { if(e->window == window || e->subwindow == window) { raise(); } if (e->window == title) { window_menu->hideAllVisibleSubmenus(); if (in_box) { if(!trans) { window_menu->hide(); iconify(); } } else raise(); } } if (e->type == ButtonRelease) { if(is_being_dragged) { is_being_dragged=false; do_drawoutline_once=false; drawOutline(); XMoveWindow(dpy, frame, x, y-theight()); sendConfig(); XUngrabServer(dpy); XSync(dpy, False); } // Check for a double click then maximize // the window. if(e->time-last_button1_time<250) { maximize(); last_button1_time=0; return; } else last_button1_time=e->time; } } break; case Button2: { if(e->window == title) { if(in_box) { if(e->type == ButtonPress) { if(is_shaded) shade(); raise(); } } } if(e->type == ButtonRelease) { if(is_being_resized) { drawOutline(); do_drawoutline_once=false; is_being_resized=false; XResizeWindow(dpy, frame, width, height + theight()); XResizeWindow(dpy, title, width, theight()); XResizeWindow(dpy, window, width, height); sendConfig(); XUngrabServer(dpy); XSync(dpy, False); return; } if( (e->window == title) && (!in_box) ) shade(); } } break; case Button3: { if(e->window == title) { if (e->type == ButtonRelease) { if (in_box) wm->sendWMDelete(window); else { if(! trans) { window_menu->setThisClient(this); window_menu->show(); } } } } } break; } } void Client::handleEnterEvent(XCrossingEvent *e) { XSetInputFocus(dpy, window, RevertToNone, CurrentTime); } void Client::handleFocusInEvent(XFocusChangeEvent *e) { wm->sendXMessage(window, wm->atom_wm_protos, SubstructureRedirectMask, wm->atom_wm_takefocus ); XInstallColormap(dpy, cmap); setFocus(true); } void Client::setFocus(bool focus) { has_focus=focus; if (has_title) { if(has_focus) { XSetWindowBackground(dpy, title, wm->getBGColor().pixel); XSetWindowBorder(dpy, frame, wm->getFocusedBorderColor().pixel); } else { XSetWindowBackground(dpy, title, wm->getFCColor().pixel); XSetWindowBorder(dpy, frame, wm->getUnFocusedBorderColor().pixel); } XClearWindow(dpy, title); redraw(); } } void Client::handleColormapChange(XColormapEvent *e) { if (e->c_new) { cmap = e->colormap; XInstallColormap(dpy, cmap); } } // If we were covered by multiple windows, we will usually get // multiple expose events, so ignore them unless e->count (the number // of outstanding exposes) is zero. void Client::handleExposeEvent(XExposeEvent *e) { if (e->count == 0) redraw(); } #ifdef SHAPE void Client::handleShapeChange(XShapeEvent *e) { setShape(); } #endif void Client::setDesktop(int desk) { belongs_to_desktop=desk; if(belongs_to_desktop != wm->getCurrentDesktop()) { hide(); } } void Client::raise() { XWindowChanges wc; wc.stack_mode = Above; XConfigureWindow(dpy, frame, CWStackMode, &wc); } void Client::lower() { XWindowChanges wc; wc.stack_mode = Below; XConfigureWindow(dpy, window, CWStackMode, &wc); } aewm++-1.1.2/client.hh0000644000014400001440000000715010203275122013364 0ustar majicusers/* * frankhale@gmail.com * http://frankhale.org * * This code is released under the GPL license www.gnu.org */ #ifndef _CLIENT_HH_ #define _CLIENT_HH_ #include "aewm.hh" class Client { private: /* Member Variables */ Display *dpy; Window root; XSizeHints *size; Colormap cmap; int screen; // Screen resolution int xres; int yres; char *name; // Name used to display in titlebar Window window; // actual client window Window frame; // parent window which we reparent the client to Window title; // window which holds title Window trans; // window id for which this client is transient for WindowMenu *window_menu; // menu which lets us change the clients // virtual desktop. // The position and dimensions of the client window int x; int y; int width; int height; int border_width; // The old position and dimensions of the client, used // in the maximize function. int old_x; int old_y; int old_width; int old_height; bool has_focus; bool has_title; bool has_border; bool is_being_dragged; bool is_being_resized; bool do_drawoutline_once; // used for wire move bool wire_move; // Do we wanna move clients by wire or opaque? bool is_shaded; bool is_iconified; bool is_maximized; bool is_visible; #ifdef SHAPE bool has_been_shaped; #endif int belongs_to_desktop; Time last_button1_time; int ignore_unmap; // For window title placement XCharStruct overall; int direction; int ascent; int descent; int text_width; int text_justify; int justify_style; // Used in client move int pointer_x, pointer_y; int old_cx, old_cy; bool button_pressed; private: /* Member Functions */ void initialize(Display *d); void redraw(); void sweep(); void drawOutline(); int getIncsize(int *, int *, int); void initPosition(); void reparent(); int theight(); void sendConfig(); void gravitate(int); #ifdef SHAPE void setShape(); #endif public: /* Member Functions */ Client(Display *d, Window new_client); ~Client(); void getXClientName(); void makeNewClient(Window); void removeClient(); char* getClientName() const { return name; } char* getClientIconName() const { return name; } // for now just return name Window getFrameWindow() const { return frame; } Window getAppWindow() const { return window; } Window getTitleWindow() const { return title; } Window getTransientWindow() const { return trans; } bool isTransient() { if(trans) return true; else return false; } bool hasWindowDecorations() const { return has_title; } bool hasFocus() const { return has_focus; } int belongsToWhichDesktop() const { return belongs_to_desktop;} bool isIconified() const { return is_iconified; } bool isVisible() const { return is_visible; } void raise(); void lower(); void setFocus(bool focus); // (decieving name) Only paints the titlebar in the focus color void hide(); void unhide(); void iconify(); void shade(); void maximize(); void setDesktop(int desk); void handleButtonEvent(XButtonEvent *); void handleConfigureRequest(XConfigureRequestEvent *); void handleMapRequest(XMapRequestEvent *); void handleUnmapEvent(XUnmapEvent *); void handleDestroyEvent(XDestroyWindowEvent *); void handleClientMessage(XClientMessageEvent *); void handlePropertyChange(XPropertyEvent *); void handleEnterEvent(XCrossingEvent *); void handleColormapChange(XColormapEvent *); void handleExposeEvent(XExposeEvent *); void handleFocusInEvent(XFocusChangeEvent *); void handleMotionNotifyEvent(XMotionEvent *); #ifdef SHAPE void handleShapeChange(XShapeEvent *); #endif }; #endif aewm++-1.1.2/genericmenu.cc0000644000014400001440000000111610203275116014374 0ustar majicusers/* * frankhale@gmail.com * http://frankhale.org * * This code is released under the GPL license www.gnu.org */ #include "aewm.hh" GenericMenu::GenericMenu(Display * dpy) : BaseMenu(dpy) { } GenericMenu::~GenericMenu() { menuList.clear(); } BaseMenu* GenericMenu::findMenu(Window w) { if (w && w != DefaultRootWindow(dpy)) { if(menuList.size()) { list::iterator menu_it; for(menu_it = menuList.begin(); menu_it != menuList.end(); menu_it++) { if (w == (*menu_it)->getMenuWindow()) { return (*menu_it); } } } } return NULL; } aewm++-1.1.2/genericmenu.hh0000644000014400001440000000053710203275112014410 0ustar majicusers/* * frankhale@gmail.com * http://frankhale.org * * This code is released under the GPL license www.gnu.org */ class GenericMenu : public BaseMenu { public: list menuList; public: GenericMenu(Display * dpy); virtual ~GenericMenu(); BaseMenu* findMenu(Window w); void addToMenuList(BaseMenu* m) { menuList.push_back(m); } }; aewm++-1.1.2/ChangeLog0000644000014400001440000000174210205770477013357 0ustar majicusers(Development Branch Of aewm++) The current development may look from the outside of regressing to earlier times by the code/feature removal. This is true however the code is being cleaned up and the focus is being pushed more towards minimalism than anything else. I want to make this as solid and small as possible! -- 1.1.2 (19 Feb 2005) * Some code clean up and the pretty'ing up of the focused and unfocused windows. 1.1.1 (11 Feb 2005) * More code clean up! 1.1.0 (10 Feb 2005) * Going back to basics. I stripped out all the extended window and gnome hints. If you are running aewm++ chances are you don't even use apps that need EWMH's. I've had this support in there for a long time and the only thing I ever used that needed it was the little taskbar app I hacked to add strut support. aewm++ is a minimal wm and it's being refocused to that role. EWMH's did little more than complicate the current code base. * Did some code clean up in the menu code aewm++-1.1.2/windowmenu.cc0000644000014400001440000000160210203275041014264 0ustar majicusers/* * frankhale@gmail.com * http://frankhale.org * * This code is released under the GPL license www.gnu.org */ #include "aewm.hh" WindowMenu::WindowMenu(Display * dpy) : GenericMenu(dpy) { updateWindowMenu(); } void WindowMenu::updateWindowMenu() { char* temp = new char[wm->getMaxDesktops()]; for(int i=0; igetMaxDesktops(); i++) { sprintf(temp, "%d", i); insert(temp,"", SEND_TO_DESKTOP); } delete [] temp; updateMenu(); addToMenuList(this); } void WindowMenu::handleButtonReleaseEvent(XButtonEvent *e) { int desktop=0; GenericMenu::handleButtonReleaseEvent(e); switch (e->button) { case Button1: if (curr) { switch( curr->function ) { case SEND_TO_DESKTOP: desktop = atoi(curr->name.c_str()); if(client) client->setDesktop(desktop); hideAllVisibleSubmenus(); break; } } break; } } aewm++-1.1.2/windowmenu.hh0000644000014400001440000000066210203275034014305 0ustar majicusers/* * frankhale@gmail.com * http://frankhale.org * * This code is released under the GPL license www.gnu.org */ #ifndef _WINDOWMENU_HH #define _WINDOWMENU_HH #include "aewm.hh" class WindowMenu : public GenericMenu { private: Client *client; public: WindowMenu(Display * dpy); virtual void handleButtonReleaseEvent(XButtonEvent *e); void updateWindowMenu(); void setThisClient(Client *c) { client = c; } }; #endif aewm++-1.1.2/iconmenu.cc0000644000014400001440000000314510203275000013704 0ustar majicusers/* * frankhale@gmail.com * http://frankhale.org * * This code is released under the GPL license www.gnu.org */ #include "aewm.hh" IconMenu::IconMenu(Display * dpy) : GenericMenu(dpy) { updateMenu(); addToMenuList(this); } void IconMenu::handleButtonReleaseEvent(XButtonEvent *e) { GenericMenu::handleButtonReleaseEvent(e); switch (e->button) { case Button1: if (curr) { switch( curr->function ) { case SHOW: curr->client->unhide(); hideAllVisibleSubmenus(); break; } } break; } } void IconMenu::addThisClient(Client *c) { if(c) { BaseMenuItem *item = new BaseMenuItem(); item->client = c; if(c->getClientIconName() == NULL) { item->name = "untitled"; }else { item->name = c->getClientIconName(); } item->function=SHOW; insert(item); } } void IconMenu::updateClientName(Client *c) { list menuItemList = getMenuItemList(); list::iterator mit; for(mit = menuItemList.begin(); mit != menuItemList.end(); mit++) { if(*mit) { if((*mit)->client == c) { if(c->getClientIconName() == NULL) { (*mit)->name = "Untitled"; } else { (*mit)->name = c->getClientIconName(); } updateMenu(); } } } } void IconMenu::removeClientFromIconMenu(Client *c) { list menuItemList = getMenuItemList(); list::iterator mit; for(mit = menuItemList.begin(); mit != menuItemList.end(); mit++) { if(*mit) { if((*mit)->client == c) { remove(*mit); delete *mit; curr=NULL; break; } } } } aewm++-1.1.2/iconmenu.hh0000644000014400001440000000077410203274774013744 0ustar majicusers/* * frankhale@gmail.com * http://frankhale.org * * This code is released under the GPL license www.gnu.org */ #ifndef _ICONMENU_HH #define _ICONMENU_HH #include "aewm.hh" class IconMenu : public GenericMenu { private: Client *client; public: IconMenu(Display * dpy); virtual void handleButtonReleaseEvent(XButtonEvent *e); void setThisClient(Client *c) { client = c; } void addThisClient(Client *c); void removeClientFromIconMenu(Client *c); void updateClientName(Client *c); }; #endif