From: Michael D. Lowis Date: Mon, 9 Mar 2020 01:43:16 +0000 (-0400) Subject: removed lots of stuff X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=d62c137ee0fa05b7d2b0045c5b2b9a434d08d384;p=proto%2Flwm.git removed lots of stuff --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4829287 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +tags +lwm diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index 0bc30a0..0000000 --- a/ChangeLog +++ /dev/null @@ -1,486 +0,0 @@ -Change Log for "lwm" - -2016-02-12 jfc York - Patches from Greg Kenneky and other fixes for fullscreen windows. - - Released lvm-1.2.4. - -2013-07-09 jfc York - Applied a couple of minor patches suggested by Jari Aalto, the - Debian package maintainer. - - Released lwm-1.2.3. - - -2009-11-24 jfc York - Released lwm-1.2.2. - -2009-11-20 jfc York - Improved performance by only checking for pending X events when the - socket it ready for reading. - - Fixed applyGravity() bug that caused frameless windows to be - mis-positioned. - - Applied a workaround in destroy() to avoid error reports when closing - windows. - -2005-01-28 jfc York - - Applied a patch from Chris Reece that ensures that the popup - menu does not disappear off the bottom of the screen. - -2004-09-30 jfc York - - Fixed an issue with IRIX 6.5 and lwm, where the root menu could - not be used because motion events had coordinates with respect to - the popup, not the root. Fixed by explicitly using the root window - coordinates. - - Released lwm-1.2.1. - -2004-09-28 jfc York - - Added missing -lSM to no_xmkmf_makefile. - -2003-12-09 jfc York - - Fixed bug (reported by Matthew Wilcox) where windows with extremely - long names could cause the pop menu to be unusable. Fixed by - maintaining a separate, shortened name for the menu, if - necessary ("this is a very very [...] ry long window name"). This - takes no account of UTF-8 names as yet. - -2003-12-08 jfc York - - Fixed bug (reported by Eugene Wong) where resizing the top of - a window would cause it to jump up several pixels. The height of - the titlebar was not being considered when calculating mouse - motion in reshaping_motionnotify(). - - Modified manage() to avoid autoplacing windows during - initialisation. - - Released lwm-1.2.0. - -2003-12-03 jfc York - - Applied patch from Elliott that gives focus to new windows in - click-to-focus mode. - - Changed the buttonpress code in disp.c to ignore scroll wheel - "clicks". - - Modified Client_Remove so that, in click-to-focus mode, it - refocuses on the most sensible window (either the top window, - or the window that the closing window was a transient for). - - Attempted to fix the edit placement bug by adding titleHeight() - to the supplied X coordinate during a ConfigureRequest event, - and not attempting to fix clients that don't supply a border - width during a configure request. - - Fixed fullscreen-mode bug where galeon windows appeared to jump - up and to the left after the first click. - - Released lwm-1.1.7. - -2003-11-28 jfc York - - Changed the behaviour when unhiding a window in click-to-focus mode. - An unhidden window now automatically gets focus in this mode. - - Fixed a small bug in the session management code that could - cause a crash when lwm quit. - - Moved a call to ewmh_set_client_list make before ewmh was - initialised. - - Changed lwm's behaviour when minimising windows. Button three must - now be pressed and released before the window is hidden (or - moved to the bottom of the stack). This ensures that lwm swallows - all the events generated during the operation, and allows the user - to back out of the operation by moving the mouse out of the window - before releasing the button. - - Removed include of Xm/MwmUtil.h in manage.c, and the HAVE_MOTIF - kludge from the Imakefile, in favour of copying the few lines - that are required from Xm/MwmUtil.h (LessTif, so hopefully no - licensing issues). - - Fixed bug that caused the last cursor displayed in a frame - to be incorrectly used when moving into the frame when the - root menu was on screen. This is done by brute force - - see Client_ResetAllCursors(). - - Released lwm-1.1.6. - -2003-11-26 jfc York - - Fixed bug in Client_MakeSane that caused occasional crashes - during window moves/resizing. Should investigate why it occasionally - gets called with a NULL client. - -2003-11-03 jfc York - - Added an entry for LeaveNotify in the dispatch table (disp.c). - -2003-08-13 jfc York - - Removed "error" message when lwm fails to connect to a session - manager. This isn't actually an error and the message is confusing. - -2003-08-01 jfc York - - Fixed bug that allowed clients to grab the focus and confuse lwm. - - Cleaned up the code for raising and lowering clients, and added - code to prevent a client from being raised above its transients. - - Retired disp.old, and CLOSE_PATCH.txt. - - Added an edge resistance to the workarea, so that window may - be moved to the edge of the workarea without precise mousing, - as requested by MAD. EDGE_RESIST in lwm.h defines the number of - pixels of resistance and may be safely set to zero. - - Released lwm-1.1.5. - -2003-07-31 jfc York - - In click-to-focus mode, always draw the box in the frame. - -2003-07-29 jfc York - - Added a click-to-focus mode. The default remains (sloppy) - enter-to-focus. - - Released lwm-1.1.4. - - -2003-07-28 jfc York - - Updated no_xmkmf_makefile to reflect the changes made since 1.01. - -2003-07-10 jfc York - - Fixed a bug in manage.c than prevented lwm compiling on systems - with no variety of Motif installed. If this means you, remove - _DHAVE_MOTIF from Imakefile. - - Released lwm-1.1.3. - -2003-07-08 jfc York - - Added support for NET_MOVERESIZE, but I cannot find any - applications the want to use it, apart from the keyboard - variants. I don't know what to do about the keyboard move/resize. - -2003-07-03 jfc York - - Fixed a few buglets thrown up by running lwm through the compiler - with all warnings on. - -2003-07-02 jfc York - - In Client_MakeSane(), added a check to prevent windows being - moved into a position where they might be completely obscured - by panels/docks. - - Changed ewmh_set_strut() to run Client_MakeSane() across all - clients when the work area changes. This avoids clients getting - lost behind panels/docks. - - Added support for _NET_WM_STATE_ABOVE and - _NET_WM_STATE_BELOW. Added fix_stack() to maintain the window - stack as dictated by the EWMH spec. - -2003-07-01 jfc York - - Added support for _NET_WM_STRUT. lwm now maintains _NET_WORKAREA - correctly, and takes the reserved space into account in its - window placing algorithm. - - Released lwm-1.1.2. - -2003-06-30 jfc York - - Fixed bug that caused tk menus to be badly placed placed by - sending a configure notify where appropriate in setactive(). - - Removed compile time option of prepending window title's with - the client machines's name (PREPEND_CLIENT_MACHINE). - - Added i18n support for window titles, using UTF8 names from - _NET_WM_NAME where available and supported (ie XFree86). - - Added code in disp.c to change the pointer in some areas of the - frame to indicate the action taken by button1. I didn't allow the - "move" pointer in the titlebar because it looked nasty. Added - the xkill pointer for the the box. This was a TODO item. - -2003-06-28 jfc York - - Added GPL headers to all the source files. - - Released lwm-1.1.1. - -2003-06-27 jfc York - - Fixed the bug where each GTK window generated an extra - window when lwm shut down by unmapping all the clients in - Client_FreeAll(). Elliott thinks this is bad magic, and that - the X server should lose the windows, but this doesn't happen - with XFree86. - - Fixed bug, reported by Ed Porter, that caused moving the mouse - wheel to generate xterms. Wheel mice generate button press events - on buttons 4 and 5 and shell() wasn't taking this into account. - - Fixed silly bug in motifWouldDecorate(): windows should have a - frame is MWM_DECOR_ALL is set. - -2003-06-26 jfc York - - Shaped windows now work again. I'm not sure what I changed - to break it, but the fix was to process shaped windows in - scanWindowTree (they were previously ignored). They had to be - clients anyway, if they were to appear in _NET_CLIENT_LIST. - -2003-06-25 jfc York - - Fixed bug that caused frameless windows to be immoveable. - - In manage.c, allowed lwm to fall back on Motif hints when - deciding if a window should have a frame, if _NET_WM_WINDOW_TYPE - is not set. This breaks the EWMH spec, in that a window - without _NET_WM_WINDOW_TYPE should be assumed to have - _NET_WM_WINDOW_TYPE_NORMAL, but it's the only way for older - apps to indicate that they don't want decorating, and in the - absence of Motif hints the default state is - _NET_WM_WINDOW_TYPE_NORMAL. - -2003-06-24 jfc York - - Fixed the following TODO item: - allow users to back out of closing a window if - they leave the box before letting go of the button. - Implemented by adding an extra wm_closing_window mode rather - than adding to the Client structure, as per AMidthune's - patch. Not sure which is the better solution, though. - - Added initial support for _NET_WM_STATE, but only for - _NET_WM_STATE_SKIP_TASKBAR, _NET_WM_STATE_SKIP_PAGER and - _NET_WM_HIDDEN. - - Added simple hardwired _NET_WM_ALLOWED_ACTIONS support, and - support for the _NET_CLOSE_WINDOW client message. - - First attempt an _WM_STATE_FULLSCREEN and a full-screen mode. - It's not quite right yet, but useable. - - -2003-06-23 jfc York - - Fixed some silly bugs in the session management code. - - Added initial EWMH code using the 1.2 spec: - http://www.freedesktop.org/standards/wm-spec/1.2/html/ - Initial support covers the mechanisms for announcing support - for EWMH (_NET_SUPPORTED, _NET_SUPPORTING_WM_CHECK), the - client list and active client (_NET_CLIENT_LIST and - _NET_ACTIVE_WINDOW), and the window type (_NET_WM_WINDOW_TYPE). - Windows may now be frameless if their window type indicates. - -2003-06-21 jfc York - - Added session management so that GNOME2's gnome-session does - not wait a long timeout when starting the window manager. - -2000-02-08 enh Basel - - Tried out a patch from Robert Bauer so that it's possible to move - windows with button 1, if you're in the ``titlebar'' (i.e. not touching - the top border). This makes it easier for Windows users to cope - with lwm, and easier for those with two-button mice (or laptops) - too. At the moment, "mv disp.old disp.c" will give back the old - behaviour. - -1999-11-11 enh Basel - - Fixed a cut-and-paste bug in client.c that made the check for - a window being too large or too small wrong. This bug was found - by Mike Meyer. - -1999-09-22 enh Basel - - Altered the button-press code so that it's now easier for unhappy - users to alter which button performs which function. Simply edit - lwm.h and modify the three relevant #define statements. - -1999-07-19 enh Basel - - Added a handler for circulation events so that other programs - can offer "Alt-Tab" functionality. - -1999-07-08 enh Basel - - Fixed the cosmetic problem with titlebars of dialogue boxes. If - this looks to be OK, I can think about another lwm release. - -1999-06-10 enh Basel - - Incorporated bug fix by Adrian Colley regarding the attempt in - manage.c to call XSetWindowBorderWidth on an InputOnly window, - and moved the #include of after so that - lwm can compile on Solaris 2.6. Cosmetic change to move the close - box to line up with the client window. The effect is spoilt if the - child insists on drawing a black border around itself, though. - -1999-02-07 enh Basel - - Title-bars no longer pop up and down. An inactive window has a - grey title instead. This means less load on the server, no annoying - "I want to type the information from one window's title-bar into - the current window but can't" syndrome, and a final solution to - the race condition that's been with us since the very beginning. - - The size feedback no longer pops up as soon as you grab a window, - because that made it almost impossible to grab a window without - resizing it. - -1998-11-03 enh Basel - - The size feedback now pops up as soon as you grab a window, - rather than waiting for you to actually move. - -1998-10-06 enh Basel - - Al pointed out that my Sun actually has two framebuffers. One - monitor-lugging later, and I suddenly have a need for a window - manager that can cope with multiple screens. And here it is! - -1998-05-29 enh Basel - - Fixed window minimum/maximum height code so that it no longer - includes the title decoration. Menu now pops down if a window - disappears while the menu is up. - -1998-03-23 enh Basel - - Removed unused constant. A little tidying up, renaming. Some - debugging code removed. The width of the size-feedback window - is now calculated at run-time depending on the size of the screen. - -1998-02-05 enh Basel - - Fixed bug found by Marty Olevitch: lwm's automatic window - placement heuristics broke down when either the right or bottom - of the display were reached. - Changed menu placement to ensure that the menu is fully - on-screen. - -1998-01-06 enh Basel - - Fixed bug found by J. Han whereby lwm dumped core if a window - disappeared while being reshaped. - -1997-09-01 enh Basel - - "Push to back" functionality moved from button 3 click in box - to button 3 click anywhere in frame with Shift held down. - -1997-08-29 enh Basel - - Simple version numbering introduced. - -1997-08-25 enh Basel - - Fixed stupid mistake introduced with the last change, with regard - to setting the input focus. - -1997-08-22 enh Basel - - Xt applications (strictly, applications whose window title is - the same as their class hint resource name) no longer have a - title bar. This means it's more awkward to kill them, but that - they don't have pointless decoration. - -1997-08-07 enh Basel - - Bug related to hiding windows fixed. - -1997-08-06 enh Basel - - The size indictor now has the correct GC settings. Whoops! - Improved handling of WM_NORMAL_HINTS. Amongst other things, - this means that size reporting of xterm et al is more reliable. - -1997-07-31 enh Basel - - Reshaping now uses the popup to display the current width and - height of the window being reshaped (in whatever units it uses). - -1997-07-04 enh Swanwick - - Clicking button 3 on the "box" pushes the window to the bottom. - Changing image in xv no longer causes the window to gravitate to - the southeast. There's an ICCCM convention that clients should - set the border width with each ConfigureWindow request. As usual, - many clients fail to follow this convention. I get the distinct - impression that the very reason for the existance of the Xt - library is because the X11 protocol and ICCCM are so messy and - involved that the only way to make X11 bearable was to write - this code once and for all. The menu code has been rewritten, - changing as a side-effect the order in which hidden windows - appear on the menu. The rewrite now means that the order is very - easy to change for experiments like alphabetical ordering etc. I - like it as it is: a stack. - -1997-06-24 enh York - - Now handles NoExpose events. Better protocol error reporting. - Default minimum size calculation improved. - -1997-06-23 enh York - - Both button 1 and 2 can now have commands associated with them. - See the documentation for details. Windows whose minimum and - maximum sizes are identical can no longer be resized. The - oscillation race condition is now less likely to occur. Some - dead code removed. - -1997-05-25 enh York - - lwm now does the right thing with respect to hidden windows on - exit and startup. a hidden window is now re-hidden if lwm exits - and is then restarted. - -1997-05-21 enh York - - Fixed a bug that meant a client could confuse lwm by remapping - a hidden window: the menu of hidden windows wasn't being updated. - -1997-05-16 enh York - - A bug relating to ConfigureRequests on the current window caused - the title-bar to be redrawn incorrectly. Once again, this came - to light with xv. - - The "New Shell" command has gone from the button 3 menu, and - button 2 now performs this function. - -1997-05-09 enh York - - This version fixes a bug relating to ConfigureRequests. Client - windows that were resized under program control were resized, - but the client was misinformed as to what change had actually - taken place. xv's optimised redraw, for example, missed out on - part of the window because of this. - The behaviour with regard to hidden windows on exit has also - changed. They're now remapped, but lowered in the window stack. - This means that you don't lose them, but that they don't - obliterate the more important windows on your screen if you kill - the window manager. - -- Initial announcement on comp.windows.x.announce - diff --git a/Imakefile b/Imakefile deleted file mode 100644 index da76f1c..0000000 --- a/Imakefile +++ /dev/null @@ -1,29 +0,0 @@ -XCOMM lwm, a window manager for X11 -XCOMM Copyright (C) 1997-2016 Elliott Hughes, James Carter -XCOMM -XCOMM This program is free software; you can redistribute it and/or -XCOMM modify it under the terms of the GNU General Public License -XCOMM as published by the Free Software Foundation; either version 2 -XCOMM of the License, or (at your option) any later version. -XCOMM -XCOMM This program is distributed in the hope that it will be useful, -XCOMM but WITHOUT ANY WARRANTY; without even the implied warranty of -XCOMM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -XCOMM GNU General Public License for more details. -XCOMM -XCOMM You should have received a copy of the GNU General Public License -XCOMM along with this program; if not, write to the Free Software -XCOMM Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -INCLUDES = -I$(TOP) -DEPLIBS = $(DEPXLIB) $(DEPSMLIB) -LOCAL_LIBRARIES = $(XLIB) $(SMLIB) -lICE -DEFINES = -DSHAPE - -HEADERS = lwm.h ewmh.h -SRCS = lwm.c manage.c mouse.c client.c cursor.c error.c disp.c shape.c resource.c session.c ewmh.c -OBJS = ${SRCS:.c=.o} - -ComplexProgramTarget(lwm) - -${OBJS}: ${HEADERS} diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..623d39d --- /dev/null +++ b/build.sh @@ -0,0 +1,2 @@ +#!/bin/sh +cc -g -o lwm *.c -I. -I/usr/X11/include/ -L/usr/X11/lib -lX11 -lICE -lSM diff --git a/client.c b/client.c index e7bf09e..9189d38 100644 --- a/client.c +++ b/client.c @@ -35,749 +35,404 @@ Client *current; Client *last_focus = NULL; static Client *clients; - -static int popup_width; /* The width of the size-feedback window. */ - Edge interacting_edge; static void sendClientMessage(Window, Atom, long, long); Client * -client_head(void) { - return clients; +Client_List(void) { + return clients; } void -setactive(Client *c, int on, long timestamp) { - int inhibit; - - if (c == 0 || hidden(c)) - return; - - inhibit = !c->framed; - - if (!inhibit) { - XMoveResizeWindow(dpy, c->parent, - c->size.x, c->size.y - titleHeight(), - c->size.width, c->size.height + titleHeight()); - XMoveWindow(dpy, c->window, border, border + titleHeight()); - sendConfigureNotify(c); - } - - if (on && c->accepts_focus) { - XSetInputFocus(dpy, c->window, RevertToPointerRoot, CurrentTime); - if (c->proto & Ptakefocus) - sendClientMessage(c->window, wm_protocols, - wm_take_focus, timestamp); - if (focus_mode == focus_click) { - XUngrabButton(dpy, AnyButton, AnyModifier, c->window); - } - cmapfocus(c); - } - - /* FIXME: is this sensible? */ - if (on && !c->accepts_focus) { - XSetInputFocus(dpy, None, RevertToPointerRoot, CurrentTime); - } - - if (!on && focus_mode == focus_click) - XGrabButton(dpy, AnyButton, AnyModifier, c->window, False, - ButtonPressMask | ButtonReleaseMask, GrabModeAsync, - GrabModeSync, None, None); - - if (!inhibit) - Client_DrawBorder(c, on); +Client_SetActive(Client *c, int on, long timestamp) { + int inhibit; + + if (c == 0) + return; + + inhibit = !c->framed; + + if (!inhibit) { + XMoveResizeWindow(dpy, c->parent, + c->size.x, c->size.y - titleHeight(), + c->size.width, c->size.height + titleHeight()); + XMoveWindow(dpy, c->window, border, border + titleHeight()); + sendConfigureNotify(c); + } + + if (on && Client_HasFlags(c, F_ACCEPT_FOCUS)) { + XSetInputFocus(dpy, c->window, RevertToPointerRoot, CurrentTime); + if (Client_HasFlags(c, F_EWMH_TAKE_FOCUS)) + sendClientMessage(c->window, wm_protocols, + wm_take_focus, timestamp); + } + + /* FIXME: is this sensible? */ + if (on && !Client_HasFlags(c, F_ACCEPT_FOCUS)) { + XSetInputFocus(dpy, None, RevertToPointerRoot, CurrentTime); + } + + if (!inhibit) + Client_DrawFrame(c, on); } void -Client_DrawBorder(Client *c, int active) { - int quarter = (border + titleHeight()) / 4; - - if (c->parent == c->screen->root || c->parent == 0 || - c->framed == False || c->wstate.fullscreen == True) - return; - - XSetWindowBackground(dpy, c->parent, - active ? c->screen->black : c->screen->gray); - XClearWindow(dpy, c->parent); - - /* Draw the ``box''. */ - if (active || focus_mode == focus_click) { - XDrawRectangle(dpy, c->parent, c->screen->gc, - quarter + 2, quarter, 2 * quarter, 2 * quarter); - } - - /* Draw window title. */ - if (c->name != 0) { -#ifdef X_HAVE_UTF8_STRING - if (c->name_utf8 == True) - Xutf8DrawString(dpy, c->parent, font_set, - c->screen->gc, border + 2 + (3 * quarter), - 2 + ascent(font_set_ext), - c->name, c->namelen); - else -#endif - XmbDrawString(dpy, c->parent, font_set, - c->screen->gc, border + 2 + (3 * quarter), - 2 + ascent(font_set_ext), - c->name, c->namelen); - } +Client_DrawFrame(Client *c, int active) { + int quarter = (border + titleHeight()) / 4; + + if (c->parent == c->screen->root || c->parent == 0 || c->framed == False) + return; + + XSetWindowBackground(dpy, c->parent, + active ? c->screen->black : c->screen->gray); + XClearWindow(dpy, c->parent); + + /* Draw window title. */ + if (c->name != 0) { + Xutf8DrawString(dpy, c->parent, font_set, + c->screen->gc, border + 2 + (3 * quarter), + 2 + ascent(font_set_ext), + c->name, c->namelen); + } } Client * Client_Get(Window w) { - Client * c; + Client * c; - if (w == 0 || (getScreenFromRoot(w) != 0)) - return 0; + if (w == 0 || (getScreenFromRoot(w) != 0)) + return 0; - /* Search for the client corresponding to this window. */ - for (c = clients; c; c = c->next) - if (c->window == w || c->parent == w) - return c; + /* Search for the client corresponding to this window. */ + for (c = clients; c; c = c->next) + if (c->window == w || c->parent == w) + return c; - /* Not found. */ - return 0; + /* Not found. */ + return 0; } Client * Client_Add(Window w, Window root) { - Client * c; - - if (w == 0 || w == root) - return 0; - - /* Search for the client corresponding to this window. */ - for (c = clients; c != 0; c = c->next) - if (c->window == w || c->parent == w) - return c; - - c = calloc(1, sizeof *c); - c->window = w; - c->parent = root; - c->framed = False; - c->hidden = False; - c->state = WithdrawnState; - c->internal_state = INormal; - c->cmap = None; - c->name = 0; - c->menu_name = 0; - c->cursor = ENone; - c->wtype = WTypeNone; - c->wstate.skip_taskbar = False; - c->wstate.skip_pager = False; - c->wstate.fullscreen = False; - c->wstate.above = False; - c->wstate.below = False; - c->strut.left = 0; - c->strut.right = 0; - c->strut.top = 0; - c->strut.bottom = 0; - c->ncmapwins = 0; - c->cmapwins = 0; - c->wmcmaps = 0; - c->accepts_focus = 1; - c->next = clients; - - /* Add to head of list of clients. */ - clients = c; - return clients; + Client * c; + + if (w == 0 || w == root) + return 0; + + /* Search for the client corresponding to this window. */ + for (c = clients; c != 0; c = c->next) + if (c->window == w || c->parent == w) + return c; + + c = calloc(1, sizeof *c); + c->window = w; + c->parent = root; + c->framed = False; + c->state = WithdrawnState; + c->internal_state = INormal; + c->name = 0; + c->cursor = ENone; + c->wtype = WTypeNone; + c->flags |= F_ACCEPT_FOCUS; + c->next = clients; + + /* Add to head of list of clients. */ + clients = c; + return clients; } void Client_Remove(Client *c) { - Client * cc; - ScreenInfo *screen = c->screen; - - if (c == 0) - return; - - /* Remove the client from our client list. */ - if (c == clients) - clients = c->next; - for (cc = clients; cc && cc->next; cc = cc->next) { - if (cc->next == c) - cc->next = cc->next->next; - } - - /* Remove it from the hidden list if it's hidden. */ - if (hidden(c)) { - /* Al Smith points out that you also want to get rid of the menu - * so you can be sure that if you let go on an item, you always - * get the corresponding window. */ - if (mode == wm_menu_up) { - XUnmapWindow(dpy, current_screen->popup); - mode = wm_idle; - } - } - - /* A deleted window can no longer be the current window. */ - if (c == current || (current == NULL && c == last_focus)) { - Client *focus = NULL; - - /* As pointed out by J. Han, if a window disappears while it's - * being reshaped you need to get rid of the size indicator. */ - if (c == current && mode == wm_reshaping) { - XUnmapWindow(dpy, current_screen->popup); - mode = wm_idle; - } - if (focus_mode == focus_click) { - /* Try and find the window that this was a transient - * for, else focus on the top client. */ - if (c->trans != None) { - focus = Client_Get(c->trans); - } - if (!focus) { - Window dw1; - Window dw2; - Window *wins; - unsigned int nwins; - - XQueryTree(dpy, c->screen->root, &dw1, - &dw2, &wins, &nwins); - while (nwins) { - focus = Client_Get(wins[nwins -1]); - if (focus) break; - nwins--; - } - if (wins) XFree(wins); - } - } - Client_Focus(focus, CurrentTime); - } - - if (getScreenFromRoot(c->parent) == 0) - XDestroyWindow(dpy, c->parent); - - if (c->ncmapwins != 0) { - XFree(c->cmapwins); - free(c->wmcmaps); - } - - if (c->name != 0) - free(c->name); - if (c->menu_name != 0) - free(c->name); - - free(c); - - ewmh_set_client_list(screen); - ewmh_set_strut(screen); + Client * cc; + ScreenInfo *screen = c->screen; + + if (c == 0) + return; + + /* Remove the client from our client list. */ + if (c == clients) + clients = c->next; + for (cc = clients; cc && cc->next; cc = cc->next) { + if (cc->next == c) + cc->next = cc->next->next; + } + + /* A deleted window can no longer be the current window. */ + if (c == current || (current == NULL && c == last_focus)) { + Client *focus = NULL; + Client_Focus(focus, CurrentTime); + } + + if (getScreenFromRoot(c->parent) == 0) + XDestroyWindow(dpy, c->parent); + + if (c->name != 0) + free(c->name); + free(c); + + ewmh_set_client_list(screen); } void Client_MakeSane(Client *c, Edge edge, int *x, int *y, int *dx, int *dy) { - Bool horizontal_ok = True; - Bool vertical_ok = True; - - if (edge != ENone) { - /* - * Make sure we're not making the window too small. - */ - if (*dx < c->size.min_width) - horizontal_ok = False; - if (*dy < c->size.min_height) - vertical_ok = False; - - /* - * Make sure we're not making the window too large. - */ - if (c->size.flags & PMaxSize) { - if (*dx > c->size.max_width) - horizontal_ok = False; - if (*dy > c->size.max_height) - vertical_ok = False; - } - - /* - * Make sure the window's width & height are multiples of - * the width & height increments (not including the base size). - */ - - if (c->size.width_inc > 1) { - int apparent_dx = *dx - 2 * border - c->size.base_width; - int x_fix = apparent_dx % c->size.width_inc; - - switch (edge) { - case ELeft: - case ETopLeft: - case EBottomLeft: - *x += x_fix; - /*FALLTHROUGH*/ - case ERight: - case ETopRight: - case EBottomRight: - *dx -= x_fix; - break; - default: break; - } - } - - if (c->size.height_inc > 1) { - int apparent_dy = *dy - 2 * border - c->size.base_height; - int y_fix = apparent_dy % c->size.height_inc; - - switch (edge) { - case ETop: - case ETopLeft: - case ETopRight: - *y += y_fix; - /*FALLTHROUGH*/ - case EBottom: - case EBottomLeft: - case EBottomRight: - *dy -= y_fix; - break; - default: break; - } - } - - /* - * Check that we may change the client horizontally and vertically. - */ - - if (c->size.width_inc == 0) - horizontal_ok = False; - if (c->size.height_inc == 0) - vertical_ok = False; - } - - /* Ensure that at least one border is not entirely within the - * reserved areas. Keeping clients completely within the - * the workarea is too restrictive, but this measure means they - * should always be accessible. - * Of course all of this is only applicable if the client doesn't - * set a strut itself. jfc - */ - if (c->strut.left == 0 && c->strut.right == 0 && - c->strut.top == 0 && c->strut.bottom == 0) { - if ((int)(*y + border) >= - (int)(c->screen->display_height - - c->screen->strut.bottom)) { - *y = c->screen->display_height - - c->screen->strut.bottom -border; - } - if ((int)(*y + c->size.height - border) <= - (int)c->screen->strut.top) { - *y = c->screen->strut.top + border - c->size.height; - } - if ((int)(*x + border) >= - (int)(c->screen->display_width - - c->screen->strut.right)) { - *x = c->screen->display_width - - c->screen->strut.right -border; - } - if ((int)(*x + c->size.width - border) <= - (int)c->screen->strut.left) { - *x = c->screen->strut.left + border - c->size.width; - } - } - - /* - * Introduce a resistance to the workarea edge, so that windows may - * be "thrown" to the edge of the workarea without precise mousing, - * as requested by MAD. - */ - if (*x < (int)c->screen->strut.left && - *x > ((int)c->screen->strut.left - EDGE_RESIST)) { - *x = (int)c->screen->strut.left; - } - if ((*x + c->size.width) > - (int)(c->screen->display_width - c->screen->strut.right) && - (*x + c->size.width) < - (int)(c->screen->display_width - c->screen->strut.right + EDGE_RESIST)) { - *x = (int)(c->screen->display_width - c->screen->strut.right - - c->size.width); - } - if ((*y - titleHeight()) < (int)c->screen->strut.top && - (*y - titleHeight()) > - ((int)c->screen->strut.top - EDGE_RESIST)) { - *y = (int)c->screen->strut.top + titleHeight(); - } - if ((*y + c->size.height) > - (int)(c->screen->display_height - c->screen->strut.bottom) && - (*y + c->size.height) < - (int)(c->screen->display_height - c->screen->strut.bottom + EDGE_RESIST)) { - *y = (int)(c->screen->display_height - c->screen->strut.bottom - - c->size.height); - } - - /* - * Update that part of the client information that we're happy with. - */ - if (interacting_edge != ENone) { - if (horizontal_ok) { - c->size.x = *x; - c->size.width = *dx; - } - if (vertical_ok) { - c->size.y = *y; - c->size.height = *dy; - } - } else { - if (horizontal_ok) - c->size.x = *x; - if (vertical_ok) - c->size.y = *y; - } -} - -void -size_expose(void) { - int width, height; - char buf[4*2 + 3 + 1]; - - width = current->size.width - 2*border; - height = current->size.height - 2*border; - - /* This dance ensures that we report 80x24 for an xterm even when - * it has a scrollbar. */ - if (current->size.flags & (PMinSize|PBaseSize) && current->size.flags & PResizeInc) { - if (current->size.flags & PBaseSize) { - width -= current->size.base_width; - height -= current->size.base_height; - } else { - width -= current->size.min_width; - height -= current->size.min_height; - } - } - - if (current->size.width_inc != 0) - width /= current->size.width_inc; - if (current->size.height_inc != 0) - height /= current->size.height_inc; - - snprintf(buf, sizeof(buf), "%i x %i", width, height); - XmbDrawString(dpy, current_screen->popup, popup_font_set, - current_screen->size_gc, - (popup_width - popupWidth(buf, strlen(buf))) / 2, - ascent(popup_font_set_ext) + 1, buf, strlen(buf)); + Bool horizontal_ok = True; + Bool vertical_ok = True; + + if (edge != ENone) { + /* + * Make sure we're not making the window too small. + */ + if (*dx < c->size.min_width) + horizontal_ok = False; + if (*dy < c->size.min_height) + vertical_ok = False; + + /* + * Make sure we're not making the window too large. + */ + if (c->size.flags & PMaxSize) { + if (*dx > c->size.max_width) + horizontal_ok = False; + if (*dy > c->size.max_height) + vertical_ok = False; + } + + /* + * Make sure the window's width & height are multiples of + * the width & height increments (not including the base size). + */ + + if (c->size.width_inc > 1) { + int apparent_dx = *dx - 2 * border - c->size.base_width; + int x_fix = apparent_dx % c->size.width_inc; + + switch (edge) { + case ELeft: + case ETopLeft: + case EBottomLeft: + *x += x_fix; + /*FALLTHROUGH*/ + case ERight: + case ETopRight: + case EBottomRight: + *dx -= x_fix; + break; + default: break; + } + } + + if (c->size.height_inc > 1) { + int apparent_dy = *dy - 2 * border - c->size.base_height; + int y_fix = apparent_dy % c->size.height_inc; + + switch (edge) { + case ETop: + case ETopLeft: + case ETopRight: + *y += y_fix; + /*FALLTHROUGH*/ + case EBottom: + case EBottomLeft: + case EBottomRight: + *dy -= y_fix; + break; + default: break; + } + } + + /* + * Check that we may change the client horizontally and vertically. + */ + + if (c->size.width_inc == 0) + horizontal_ok = False; + if (c->size.height_inc == 0) + vertical_ok = False; + } + + /* + * Update that part of the client information that we're happy with. + */ + if (interacting_edge != ENone) { + if (horizontal_ok) { + c->size.x = *x; + c->size.width = *dx; + } + if (vertical_ok) { + c->size.y = *y; + c->size.height = *dy; + } + } else { + if (horizontal_ok) + c->size.x = *x; + if (vertical_ok) + c->size.y = *y; + } } static void Client_OpaquePrimitive(Client *c, Edge edge) { - Cursor cursor; - int ox, oy; - - if (c == 0 /*|| c != current*/) - return; - - /* Find out where we've got hold of the window. */ - getMousePosition(&ox, &oy); - ox = c->size.x - ox; - oy = c->size.y - oy; - - cursor = getEdgeCursor(edge); - XChangeActivePointerGrab(dpy, ButtonMask | PointerMotionHintMask | - ButtonMotionMask | OwnerGrabButtonMask, cursor, CurrentTime); - - /* - * Store some state so that we can get back into the main event - * dispatching thing. - */ - interacting_edge = edge; - start_x = ox; - start_y = oy; - mode = wm_reshaping; - ewmh_set_client_list(c->screen); + Cursor cursor; + int ox, oy; + + if (c == 0 /*|| c != current*/) + return; + + /* Find out where we've got hold of the window. */ + getMousePosition(&ox, &oy); + ox = c->size.x - ox; + oy = c->size.y - oy; + + cursor = getEdgeCursor(edge); + XChangeActivePointerGrab(dpy, ButtonMask | PointerMotionHintMask | + ButtonMotionMask | OwnerGrabButtonMask, cursor, CurrentTime); + + /* + * Store some state so that we can get back into the main event + * dispatching thing. + */ + interacting_edge = edge; + start_x = ox; + start_y = oy; + mode = wm_reshaping; + ewmh_set_client_list(c->screen); } void Client_Lower(Client *c) { - if (c == 0) return; + if (c == 0) return; - XLowerWindow(dpy, c->window); - if (c->framed) XLowerWindow(dpy, c->parent); - ewmh_set_client_list(c->screen); + XLowerWindow(dpy, c->window); + if (c->framed) XLowerWindow(dpy, c->parent); + ewmh_set_client_list(c->screen); } void Client_Raise(Client *c) { - Client * trans; + Client * trans; - if (c == 0) return; + if (c == 0) return; - if (c->framed) XRaiseWindow(dpy, c->parent); - XRaiseWindow(dpy, c->window); + if (c->framed) XRaiseWindow(dpy, c->parent); + XRaiseWindow(dpy, c->window); - for (trans = clients; trans != NULL; trans = trans->next) { - if (trans->trans != c->window && - !(c->framed == True && trans->trans == c->parent)) - continue; - if (trans->framed) XRaiseWindow(dpy, trans->parent); - XRaiseWindow(dpy, trans->window); - } + for (trans = clients; trans != NULL; trans = trans->next) { + if (trans->trans != c->window && + !(c->framed == True && trans->trans == c->parent)) + continue; + if (trans->framed) XRaiseWindow(dpy, trans->parent); + XRaiseWindow(dpy, trans->window); + } - ewmh_set_client_list(c->screen); + ewmh_set_client_list(c->screen); } void Client_Close(Client *c) { - if (c == 0) - return; - - /* - * Terminate the client nicely if possible. Be brutal otherwise. - */ - if (c->proto & Pdelete) { - sendClientMessage(c->window, wm_protocols, wm_delete, CurrentTime); - } else { - XKillClient(dpy, c->window); - } + if (c == 0) return; + if (Client_HasFlags(c, F_EWMH_DELETE)) { + sendClientMessage(c->window, wm_protocols, wm_delete, CurrentTime); + } else { + XKillClient(dpy, c->window); + } } void Client_SetState(Client *c, int state) { - long data[2]; + long data[2]; - data[0] = (long) state; - data[1] = (long) None; + data[0] = (long) state; + data[1] = (long) None; - c->state = state; - XChangeProperty(dpy, c->window, wm_state, wm_state, 32, - PropModeReplace, (unsigned char *) data, 2); - ewmh_set_state(c); -} - -static void -sendClientMessage(Window w, Atom a, long data0, long data1) { - XEvent ev; - long mask; - - memset(&ev, 0, sizeof(ev)); - ev.xclient.type = ClientMessage; - ev.xclient.window = w; - ev.xclient.message_type = a; - ev.xclient.format = 32; - ev.xclient.data.l[0] = data0; - ev.xclient.data.l[1] = data1; - mask = (getScreenFromRoot(w) != 0) ? SubstructureRedirectMask : 0L; - - XSendEvent(dpy, w, False, mask, &ev); + c->state = state; } extern void Client_ResetAllCursors(void) { - Client *c; - XSetWindowAttributes attr; - - for (c = clients; c; c = c->next) { - if (c->framed != True) continue; - attr.cursor = c->screen->root_cursor; - XChangeWindowAttributes(dpy, c->parent, - CWCursor, &attr); - c->cursor = ENone; - } -} - -extern void -Client_FreeAll(void) { - Client *c; - XWindowChanges wc; - - for (c = clients; c; c = c->next) { - int not_mapped = !normal(c); - - /* elliott thinks leaving window unmapped causes the x server - * to lose them when the window manager quits. it doesn't - * happen to me with XFree86's Xnest, but unmapping the - * windows stops gtk window generating an extra window when - * the window manager quits. - * who is right? only time will tell.... - */ - XUnmapWindow(dpy, c->parent); - XUnmapWindow(dpy, c->window); - /* Remap the window if it's hidden. - if (not_mapped) { - XMapWindow(dpy, c->parent); - XMapWindow(dpy, c->window); - } */ - - /* Reparent it, and then push it to the bottom if it was hidden. */ - XReparentWindow(dpy, c->window, c->screen->root, c->size.x, c->size.y); - if (not_mapped) - XLowerWindow(dpy, c->window); - - /* Give it back its initial border width. */ - wc.border_width = c->border; - XConfigureWindow(dpy, c->window, CWBorderWidth, &wc); - } -} - -extern void -Client_ColourMap(XEvent *e) { - int i; - Client * c; - - for (c = clients; c; c = c->next) { - for (i = 0; i < c->ncmapwins; i++) { - if (c->cmapwins[i] == e->xcolormap.window) { - c->wmcmaps[i] = e->xcolormap.colormap; - if (c == current) - cmapfocus(c); - return; - } - } - } + Client *c; + XSetWindowAttributes attr; + + for (c = clients; c; c = c->next) { + if (c->framed != True) continue; + attr.cursor = c->screen->root_cursor; + XChangeWindowAttributes(dpy, c->parent, + CWCursor, &attr); + c->cursor = ENone; + } } extern void Client_ReshapeEdge(Client *c, Edge e) { - Client_OpaquePrimitive(c, e); + Client_OpaquePrimitive(c, e); } extern void Client_Move(Client *c) { - Client_OpaquePrimitive(c, ENone); + Client_OpaquePrimitive(c, ENone); } extern int -hidden(Client *c) { - return c->state == IconicState; -} - -extern int -withdrawn(Client *c) { - return c->state == WithdrawnState; -} - -extern int -normal(Client *c) { - return c->state == NormalState; +Client_IsState(Client *c, int state) +{ + return c->state == state; } extern void -Client_EnterFullScreen(Client *c) { - XWindowChanges fs; - - memcpy(&c->return_size, &c->size, sizeof(XSizeHints)); - if (c->framed) { - c->size.x = fs.x = -border; - c->size.y = fs.y = -border; - c->size.width = fs.width = - c->screen->display_width + 2 * border; - c->size.height = fs.height = - c->screen->display_height + 2 * border; - XConfigureWindow(dpy, c->parent, - CWX | CWY | CWWidth | CWHeight, &fs); - - fs.x = border; - fs.y = border; - fs.width = c->screen->display_width; - fs.height = c->screen->display_height; - XConfigureWindow(dpy, c->window, - CWX | CWY | CWWidth | CWHeight, &fs); - XRaiseWindow(dpy,c->parent); - } else { - c->size.x = c->size.y = fs.x = fs.y = 0; - c->size.width = fs.width = c->screen->display_width; - c->size.height = fs.height = c->screen->display_height; - XConfigureWindow(dpy, c->window, - CWX | CWY | CWWidth | CWHeight, &fs); - XRaiseWindow(dpy,c->window); - } - sendConfigureNotify(c); +Client_Focus(Client *c, Time time) { + if (current) { + Client_SetActive(current, 0, 0L); + XDeleteProperty(dpy, current->screen->root, + ewmh_atom[_NET_ACTIVE_WINDOW]); + } + + if (!c && current) { + last_focus = current; + } else { + last_focus = NULL; + } + current = c; + if (c) { + Client_SetActive(current, 1, time); + XChangeProperty(dpy, current->screen->root, + ewmh_atom[_NET_ACTIVE_WINDOW], + XA_WINDOW, 32, PropModeReplace, + (unsigned char *)¤t->window, 1); + } } extern void -Client_ExitFullScreen(Client *c) { - XWindowChanges fs; - - memcpy(&c->size, &c->return_size, sizeof(XSizeHints)); - if (c->framed == True) { - fs.x = c->size.x; - fs.y = c->size.y - titleHeight(); - fs.width = c->size.width; - fs.height = c->size.height + titleHeight(); - XConfigureWindow(dpy, c->parent, - CWX | CWY | CWWidth | CWHeight, &fs); - - fs.x = border; - fs.y = border + titleHeight(); - fs.width = c->size.width -(2 * border); - fs.height = c->size.height -(2 * border); - XConfigureWindow(dpy, c->window, - CWX | CWY | CWWidth | CWHeight, &fs); - } else { - fs.x = c->size.x; - fs.y = c->size.y; - fs.width = c->size.width; - fs.height = c->size.height; - XConfigureWindow(dpy, c->window, - CWX | CWY | CWWidth | CWHeight, &fs); - } - sendConfigureNotify(c); +Client_Name(Client *c, const char *name) { + if (c->name) free(c->name); + c->name = strdup((char *) name); + c->namelen = strlen(c->name); } -extern void -Client_Focus(Client *c, Time time) { - if (current) { - setactive(current, 0, 0L); - XDeleteProperty(dpy, current->screen->root, - ewmh_atom[_NET_ACTIVE_WINDOW]); - } - - if (!c && current) { - last_focus = current; - } else { - last_focus = NULL; - } - current = c; - if (c) { - setactive(current, 1, time); - XChangeProperty(dpy, current->screen->root, - ewmh_atom[_NET_ACTIVE_WINDOW], - XA_WINDOW, 32, PropModeReplace, - (unsigned char *)¤t->window, 1); - } - - if (focus_mode == focus_click) - Client_Raise(c); +int Client_HasFlags(Client* c, int flags) { + return ((c->flags & flags) == flags); } -extern void -Client_Name(Client *c, const char *name, Bool is_utf8) { - int tx; - static const char dots[] = " [...] "; - int cut; - - if (c->name) free(c->name); - c->name = strdup((char *) name); - c->namelen = strlen(c->name); - c->name_utf8 = is_utf8; - - if (c->menu_name) free(c->menu_name); - c->menu_name = 0; - tx = titleWidth(popup_font_set, c); - if (tx <= (c->screen->display_width - (c->screen->display_width / 10))) - return; - - /* the menu entry for this client will not fit on the display - * (minus 10% for saftey), so produced a truncated version... - */ - cut = 5; - do { - if (c->menu_name) { - free(c->menu_name); - c->menu_name = 0; - } - if (cut >= (strlen(c->name) / 2)) break; - c->menu_name = strdup(c->name); - /* FIXME: this is not UTF-8 safe! */ - sprintf(&c->menu_name[(strlen(c->name) / 2) - cut], dots); - strcat(c->menu_name, - &c->name[(strlen(c->name) / 2) + cut]); - c->menu_namelen = strlen(c->menu_name); - cut++; - tx = titleWidth(popup_font_set, c); - if (!tx) break; - } while (tx > - (c->screen->display_width - (c->screen->display_width / 10))); +static void +sendClientMessage(Window w, Atom a, long data0, long data1) { + XEvent ev; + long mask; + + memset(&ev, 0, sizeof(ev)); + ev.xclient.type = ClientMessage; + ev.xclient.window = w; + ev.xclient.message_type = a; + ev.xclient.format = 32; + ev.xclient.data.l[0] = data0; + ev.xclient.data.l[1] = data1; + mask = (getScreenFromRoot(w) != 0) ? SubstructureRedirectMask : 0L; + + XSendEvent(dpy, w, False, mask, &ev); } + diff --git a/cursor.c b/cursor.c index f528095..a689f95 100644 --- a/cursor.c +++ b/cursor.c @@ -28,50 +28,50 @@ typedef struct CursorMapping CursorMapping; struct CursorMapping { - Edge edge; - int font_char; + Edge edge; + int font_char; }; static CursorMapping cursor_map[] = { - {ETopLeft, XC_top_left_corner}, - {ETop, XC_top_side}, - {ETopRight, XC_top_right_corner}, - {ERight, XC_right_side}, - {ENone, XC_fleur}, - {ELeft, XC_left_side}, - {EBottomLeft, XC_bottom_left_corner}, - {EBottom, XC_bottom_side}, - {EBottomRight, XC_bottom_right_corner}, - {ENone, 0}, + {ETopLeft, XC_top_left_corner}, + {ETop, XC_top_side}, + {ETopRight, XC_top_right_corner}, + {ERight, XC_right_side}, + {ENone, XC_fleur}, + {ELeft, XC_left_side}, + {EBottomLeft, XC_bottom_left_corner}, + {EBottom, XC_bottom_side}, + {EBottomRight, XC_bottom_right_corner}, + {ENone, 0}, }; extern void initialiseCursors(int screen) { - XColor red, white, exact; - Colormap cmp; - int i; + XColor red, white, exact; + Colormap cmp; + int i; - cmp = DefaultColormap(dpy, screen); + cmp = DefaultColormap(dpy, screen); - XAllocNamedColor(dpy, cmp, "red", &red, &exact); - XAllocNamedColor(dpy, cmp, "white", &white, &exact); + XAllocNamedColor(dpy, cmp, "red", &red, &exact); + XAllocNamedColor(dpy, cmp, "white", &white, &exact); - screens[screen].root_cursor = XCreateFontCursor(dpy, XC_left_ptr); - XRecolorCursor(dpy, screens[screen].root_cursor, &red, &white); + screens[screen].root_cursor = XCreateFontCursor(dpy, XC_left_ptr); + XRecolorCursor(dpy, screens[screen].root_cursor, &red, &white); - screens[screen].box_cursor = XCreateFontCursor(dpy, XC_draped_box); - XRecolorCursor(dpy, screens[screen].box_cursor, &red, &white); + screens[screen].box_cursor = XCreateFontCursor(dpy, XC_draped_box); + XRecolorCursor(dpy, screens[screen].box_cursor, &red, &white); - for (i = 0; cursor_map[i].font_char != 0; i++) { - Edge e = cursor_map[i].edge; - screens[screen].cursor_map[e] = - XCreateFontCursor(dpy, cursor_map[i].font_char); - XRecolorCursor(dpy, screens[screen].cursor_map[e], - &red, &white); - } + for (i = 0; cursor_map[i].font_char != 0; i++) { + Edge e = cursor_map[i].edge; + screens[screen].cursor_map[e] = + XCreateFontCursor(dpy, cursor_map[i].font_char); + XRecolorCursor(dpy, screens[screen].cursor_map[e], + &red, &white); + } } extern Cursor getEdgeCursor(Edge edge) { - return screens[0].cursor_map[edge]; + return screens[0].cursor_map[edge]; } diff --git a/disp.c b/disp.c index bdf1d9d..44c9189 100644 --- a/disp.c +++ b/disp.c @@ -31,60 +31,57 @@ #include "ewmh.h" /* - * Dispatcher for main event loop. + * Dispatcher for main event loop. */ typedef struct Disp Disp; struct Disp { - int type; - void (*handler)(XEvent *); + int type; + void (*handler)(XEvent *); }; static void expose(XEvent *); static void buttonpress(XEvent *); -static void buttonrelease(XEvent *); +static void buttonrelease(XEvent *ev); static void focuschange(XEvent *); static void maprequest(XEvent *); static void configurereq(XEvent *); static void unmap(XEvent *); static void destroy(XEvent *); static void clientmessage(XEvent *); -static void colormap(XEvent *); static void property(XEvent *); static void reparent(XEvent *); static void enter(XEvent *); static void circulaterequest(XEvent *); static void motionnotify(XEvent *); - -void reshaping_motionnotify(XEvent *); +static void reshaping_motionnotify(XEvent *); static Disp disps[] = { - {Expose, expose}, - {MotionNotify, motionnotify}, - {ButtonPress, buttonpress}, - {ButtonRelease, buttonrelease}, - {FocusIn, focuschange}, - {FocusOut, focuschange}, - {MapRequest, maprequest}, - {ConfigureRequest, configurereq}, - {UnmapNotify, unmap}, - {DestroyNotify, destroy}, - {ClientMessage, clientmessage}, - {ColormapNotify, colormap}, - {PropertyNotify, property}, - {ReparentNotify, reparent}, - {EnterNotify, enter}, - {CirculateRequest, circulaterequest}, - {LeaveNotify, 0}, - {ConfigureNotify, 0}, - {CreateNotify, 0}, - {GravityNotify, 0}, - {MapNotify, 0}, - {MappingNotify, 0}, - {SelectionClear, 0}, - {SelectionNotify, 0}, - {SelectionRequest, 0}, - {NoExpose, 0}, + {Expose, expose}, + {MotionNotify, motionnotify}, + {ButtonPress, buttonpress}, + {ButtonRelease, buttonrelease}, + {FocusIn, focuschange}, + {FocusOut, focuschange}, + {MapRequest, maprequest}, + {ConfigureRequest, configurereq}, + {UnmapNotify, unmap}, + {DestroyNotify, destroy}, + {ClientMessage, clientmessage}, + {PropertyNotify, property}, + {ReparentNotify, reparent}, + {EnterNotify, enter}, + {CirculateRequest, circulaterequest}, + {LeaveNotify, 0}, + {ConfigureNotify, 0}, + {CreateNotify, 0}, + {GravityNotify, 0}, + {MapNotify, 0}, + {MappingNotify, 0}, + {SelectionClear, 0}, + {SelectionNotify, 0}, + {SelectionRequest, 0}, + {NoExpose, 0}, }; /** @@ -95,790 +92,642 @@ static Client *pending=NULL; extern void dispatch(XEvent * ev) { - Disp * p; - - for (p = disps; p < disps + sizeof(disps)/sizeof(disps[0]); p++) { - if (p->type == ev->type) { - if (p->handler != 0) - p->handler(ev); - return; - } - } - - if (!shapeEvent(ev)) - fprintf(stderr, "%s: unknown event %d\n", argv0, ev->type); + Disp * p; + + for (p = disps; p < disps + sizeof(disps)/sizeof(disps[0]); p++) { + if (p->type == ev->type) { + if (p->handler != 0) + p->handler(ev); + return; + } + } + + fprintf(stderr, "%s: unknown event %d\n", argv0, ev->type); } static void expose(XEvent * ev) { - Client * c; - Window w; /* Window the expose event is for. */ - - /* Only handle the last in a group of Expose events. */ - if (ev->xexpose.count != 0) return; - - w = ev->xexpose.window; - - /* - * We don't draw on the root window so that people can have - * their favourite Spice Girls backdrop... - */ - if (getScreenFromRoot(w) != 0) - return; - - /* Decide what needs redrawing: window frame or menu? */ - if (current_screen && w == current_screen->popup) { - if (mode == wm_reshaping && current != 0) - size_expose(); - } else { - c = Client_Get(w); - if (c != 0) { - Client_DrawBorder(c, c == current); - } - } + Client * c; + Window w; /* Window the expose event is for. */ + + /* Only handle the last in a group of Expose events. */ + if (ev->xexpose.count != 0) return; + + w = ev->xexpose.window; + + /* + * We don't draw on the root window so that people can have + * their favourite Spice Girls backdrop... + */ + if (getScreenFromRoot(w) != 0) + return; + + /* redraw window frame */ + c = Client_Get(w); + if (c != 0) { + Client_DrawFrame(c, c == current); + } } static void buttonpress(XEvent *ev) { - Client *c; - XButtonEvent *e = &ev->xbutton; - int quarter; - - /* If we're getting it already, we're not in the market for more. */ - if (mode != wm_idle) { - /* but allow a button press to cancel a move/resize, - * to satify the EWMH advisory to allow a second mechanism - * of completing move/resize operations, due to a race. - * (section 4.3) sucky! - */ - if (mode == wm_reshaping) { - mode = wm_idle; - } - return; - } - - c = Client_Get(e->window); - - if (c && c != current && focus_mode == focus_click) { - /* Click is not on current window, - * and in click-to-focus mode, so change focus - */ - Client_Focus(c, e->time); - } - - /*move this test up to disable scroll to focus*/ - if (e->button >= 4 && e->button <= 7) { - return; - } - - if (c && c == current && (e->window == c->parent)) { - /* Click went to our frame around a client. */ - - /* The ``box''. */ - quarter = (border + titleHeight()) / 4; - if (e->x > (quarter + 2) && e->x < (3 + 3*quarter) && e->y > quarter && e->y <= 3*quarter) { - /*Client_Close(c);*/ - pending = c; - mode = wm_closing_window; - return; - } - - /* Somewhere in the rest of the frame. */ - if (e->button == HIDE_BUTTON) { - pending = c; - mode = wm_hiding_window; - return; - } - if (e->button == MOVE_BUTTON) { - Client_Move(c); - return; - } - if (e->button == RESHAPE_BUTTON) { - XMapWindow(dpy, c->parent); - Client_Raise(c); - - /* Lasciate ogni speranza voi ch'entrate... */ - - if (e->x <= border && e->y <= border) { - Client_ReshapeEdge(c, ETopLeft); - } else if (e->x >= (c->size.width - border) && e->y <= border) { - Client_ReshapeEdge(c, ETopRight); - } else if (e->x >= (c->size.width - border) && e->y >= (c->size.height + titleHeight() - border)) { - Client_ReshapeEdge(c, EBottomRight); - } else if (e->x <= border && e->y >= (c->size.height + titleHeight() - border)) { - Client_ReshapeEdge(c, EBottomLeft); - } else if (e->x > border && e->x < (c->size.width - border) && e->y < border) { - Client_ReshapeEdge(c, ETop); - } else if (e->x > border && e->x < (c->size.width - border) && e->y >= border && e->y < (titleHeight() + border)) { - Client_Move(c); - } else if (e->x > (c->size.width - border) && e->y > border && e->y < (c->size.height + titleHeight() - border)) { - Client_ReshapeEdge(c, ERight); - } else if (e->x > border && e->x < (c->size.width - border) && e->y > (c->size.height - border)) { - Client_ReshapeEdge(c, EBottom); - } else if (e->x < border && e->y > border && e->y < (c->size.height + titleHeight() - border)) { - Client_ReshapeEdge(c, ELeft); - } - return; - } - return; - } - - /* Deal with root window button presses. */ - if (e->window == e->root) { - if (e->button == Button3) { - cmapfocus(0); - } else { - shell(getScreenFromRoot(e->root), e->button, e->x, e->y); - } - } + Client *c; + XButtonEvent *e = &ev->xbutton; + int quarter; + + /* If we're getting it already, we're not in the market for more. */ + if (mode != wm_idle) { + /* but allow a button press to cancel a move/resize, + * to satify the EWMH advisory to allow a second mechanism + * of completing move/resize operations, due to a race. + * (section 4.3) sucky! + */ + if (mode == wm_reshaping) { + mode = wm_idle; + } + return; + } + + c = Client_Get(e->window); + + /*move this test up to disable scroll to focus*/ + if (e->button >= 4 && e->button <= 7) { + return; + } + + if (c && c == current && (e->window == c->parent)) { + /* Click went to our frame around a client. */ + if (e->button == Button1) { + XMapWindow(dpy, c->parent); + Client_Raise(c); + if (e->x <= border && e->y <= border) { + Client_ReshapeEdge(c, ETopLeft); + } else if (e->x >= (c->size.width - border) && e->y <= border) { + Client_ReshapeEdge(c, ETopRight); + } else if (e->x >= (c->size.width - border) && e->y >= (c->size.height + titleHeight() - border)) { + Client_ReshapeEdge(c, EBottomRight); + } else if (e->x <= border && e->y >= (c->size.height + titleHeight() - border)) { + Client_ReshapeEdge(c, EBottomLeft); + } else if (e->x > border && e->x < (c->size.width - border) && e->y < border) { + Client_ReshapeEdge(c, ETop); + } else if (e->x > border && e->x < (c->size.width - border) && e->y >= border && e->y < (titleHeight() + border)) { + Client_Move(c); + } else if (e->x > (c->size.width - border) && e->y > border && e->y < (c->size.height + titleHeight() - border)) { + Client_ReshapeEdge(c, ERight); + } else if (e->x > border && e->x < (c->size.width - border) && e->y > (c->size.height - border)) { + Client_ReshapeEdge(c, EBottom); + } else if (e->x < border && e->y > border && e->y < (c->size.height + titleHeight() - border)) { + Client_ReshapeEdge(c, ELeft); + } + return; + } else if (e->button == Button2) { + Client_Close(c); + } + return; + } } static void buttonrelease(XEvent *ev) { - XButtonEvent *e = &ev->xbutton; - int quarter; - - if (mode == wm_reshaping) - XUnmapWindow(dpy, current_screen->popup); - else if (mode == wm_closing_window) { - /* was the button released within the window's box?*/ - quarter = (border + titleHeight()) / 4; - if (pending != NULL && - (e->window == pending->parent) && - (e->x > (quarter + 2) && - e->x < (3 + 3*quarter) && - e->y > quarter && e->y <= 3*quarter)) - Client_Close(pending); - pending = NULL; - } else if (mode == wm_hiding_window) { - /* was the button release within the window's frame? */ - if (pending != NULL && - (e->window == pending->parent) && - (e->x >= 0) && (e->y >= 0) && - (e->x <= pending->size.width) && - (e->y <= (pending->size.height + titleHeight()))) { - if (e->state & ShiftMask) { - Client_Lower(pending); - } - } - pending = NULL; - } - - mode = wm_idle; + mode = wm_idle; } static void circulaterequest(XEvent *ev) { - XCirculateRequestEvent * e = &ev->xcirculaterequest; - Client * c; - - c = Client_Get(e->window); - - if (c == 0) { - if (e->place == PlaceOnTop) { - XRaiseWindow(e->display, e->window); - } else { - XLowerWindow(e->display, e->window); - } - } else { - if (e->place == PlaceOnTop) { - Client_Raise(c); - } else { - Client_Lower(c); - } - } + XCirculateRequestEvent * e = &ev->xcirculaterequest; + Client * c = Client_Get(e->window); + + if (c == 0) { + if (e->place == PlaceOnTop) { + XRaiseWindow(e->display, e->window); + } else { + XLowerWindow(e->display, e->window); + } + } else { + if (e->place == PlaceOnTop) { + Client_Raise(c); + } else { + Client_Lower(c); + } + } } static void maprequest(XEvent *ev) { - Client * c; - XMapRequestEvent * e = &ev->xmaprequest; - - c = Client_Get(e->window); - - if (c == 0 || c->window != e->window) { - int screen; - for (screen = 0; screen < screen_count; screen++) - scanWindowTree(screen); - c = Client_Get(e->window); - if (c == 0 || c->window != e->window) { - fprintf(stderr, "MapRequest for non-existent window!\n"); - return; - } - } - - switch (c->state) { - case WithdrawnState: - if (getScreenFromRoot(c->parent) != 0) { - manage(c, 0); - break; - } - if (c->framed == True) { - XReparentWindow(dpy, c->window, c->parent, border, - border + titleHeight()); - } else { - XReparentWindow(dpy, c->window, c->parent, - c->size.x, c->size.y); - } - XAddToSaveSet(dpy, c->window); - /*FALLTHROUGH*/ - case NormalState: - XMapWindow(dpy, c->parent); - XMapWindow(dpy, c->window); - Client_Raise(c); - Client_SetState(c, NormalState); - break; - } - ewmh_set_client_list(c->screen); + Client * c; + XMapRequestEvent * e = &ev->xmaprequest; + + c = Client_Get(e->window); + + if (c == 0 || c->window != e->window) { + int screen; + for (screen = 0; screen < screen_count; screen++) + scanWindowTree(screen); + c = Client_Get(e->window); + if (c == 0 || c->window != e->window) { + fprintf(stderr, "MapRequest for non-existent window!\n"); + return; + } + } + + switch (c->state) { + case WithdrawnState: + if (getScreenFromRoot(c->parent) != 0) { + manage(c, 0); + break; + } + if (c->framed == True) { + XReparentWindow(dpy, c->window, c->parent, border, + border + titleHeight()); + } else { + XReparentWindow(dpy, c->window, c->parent, + c->size.x, c->size.y); + } + XAddToSaveSet(dpy, c->window); + /*FALLTHROUGH*/ + case NormalState: + XMapWindow(dpy, c->parent); + XMapWindow(dpy, c->window); + Client_Raise(c); + Client_SetState(c, NormalState); + break; + } + ewmh_set_client_list(c->screen); } static void unmap(XEvent *ev) { - Client *c; - XUnmapEvent *e = &ev->xunmap; - - c = Client_Get(e->window); - if (c == 0) return; - - /* - * In the description of the ReparentWindow request we read: "If the window - * is mapped, an UnmapWindow request is performed automatically first". This - * might seem stupid, but it's the way it is. While a reparenting is pending - * we ignore UnmapWindow requests. - */ - if (c->internal_state == IPendingReparenting) { - c->internal_state = INormal; - return; - } - - /* "This time it's the real thing." */ - - if (c->state == IconicState) { - /* - * Is this a hidden window disappearing? If not, then we - * aren't interested because it's an unmap request caused - * by our hiding a window. - */ - } else { - /* This is a plain unmap, so withdraw the window. */ - withdraw(c); - } - - c->internal_state = INormal; + Client *c; + XUnmapEvent *e = &ev->xunmap; + + c = Client_Get(e->window); + if (c == 0) return; + + /* + * In the description of the ReparentWindow request we read: "If the window + * is mapped, an UnmapWindow request is performed automatically first". This + * might seem stupid, but it's the way it is. While a reparenting is pending + * we ignore UnmapWindow requests. + */ + if (c->internal_state == IPendingReparenting) { + c->internal_state = INormal; + return; + } + + /* This is a plain unmap, so withdraw the window. */ + withdraw(c); + + c->internal_state = INormal; } static void configurereq(XEvent *ev) { - XWindowChanges wc; - Client *c; - XConfigureRequestEvent *e = &ev->xconfigurerequest; - - c = Client_Get(e->window); - - - if (c && c->window == e->window) { - /* - * ICCCM section 4.1.5 says that the x and y coordinates here - * will have been "adjusted for the border width". - * NOTE: this may not be the only place to bear this in mind. - */ - if (e->value_mask & CWBorderWidth) { - e->x -= e->border_width; - e->y -= e->border_width; - } else { - /* - * The ICCCM also says that clients should always set the - * border width in a configure request. As usual, many don't. - */ - /* adding one seems a bit arbitrary and makes edit - drift by one pixel*/ - /*e->x--;*/ - /*e->y--;*/ - } - - if (e->value_mask & CWX) { - c->size.x = e->x; - } - if (e->value_mask & CWY) { - c->size.y = e->y; - if (c->framed == True) - c->size.y += titleHeight(); - } - if (e->value_mask & CWWidth) { - c->size.width = e->width; - if (c->framed == True) - c->size.width += 2 * border; - } - if (e->value_mask & CWHeight) { - c->size.height = e->height; - if (c->framed == True) - c->size.height += 2 * border; - } - if (e->value_mask & CWBorderWidth) - c->border = e->border_width; - - if (getScreenFromRoot(c->parent) == 0) { - wc.x = c->size.x; - wc.y = c->size.y; - if (c->framed == True) - wc.y -= titleHeight(); - wc.width = c->size.width; - wc.height = c->size.height; - if (c->framed == True) - wc.height += titleHeight(); - wc.border_width = 1; - wc.sibling = e->above; - wc.stack_mode = e->detail; - - XConfigureWindow(dpy, e->parent, e->value_mask, &wc); - sendConfigureNotify(c); - } - } - if (c && (c->internal_state == INormal) && (c->framed == True)) { - wc.x = border; - wc.y = border; - } else { - wc.x = e->x; - wc.y = e->y; - } - - wc.width = e->width; - wc.height = e->height; - wc.border_width = 0; - wc.sibling = e->above; - wc.stack_mode = e->detail; - e->value_mask |= CWBorderWidth; - - XConfigureWindow(dpy, e->window, e->value_mask, &wc); - - if (c) { - if (c->framed == True) { - XMoveResizeWindow(dpy, c->parent, - c->size.x, c->size.y - titleHeight(), - c->size.width, c->size.height + titleHeight()); - XMoveWindow(dpy, c->window, - border, border + titleHeight()); - } else { - XMoveResizeWindow(dpy, c->window, - c->size.x, c->size.y, - c->size.width, c->size.height); - } - } + XWindowChanges wc; + Client *c; + XConfigureRequestEvent *e = &ev->xconfigurerequest; + + c = Client_Get(e->window); + + + if (c && c->window == e->window) { + /* + * ICCCM section 4.1.5 says that the x and y coordinates here + * will have been "adjusted for the border width". + * NOTE: this may not be the only place to bear this in mind. + */ + if (e->value_mask & CWBorderWidth) { + e->x -= e->border_width; + e->y -= e->border_width; + } else { + /* + * The ICCCM also says that clients should always set the + * border width in a configure request. As usual, many don't. + */ + /* adding one seems a bit arbitrary and makes edit + drift by one pixel*/ + /*e->x--;*/ + /*e->y--;*/ + } + + if (e->value_mask & CWX) { + c->size.x = e->x; + } + if (e->value_mask & CWY) { + c->size.y = e->y; + if (c->framed == True) + c->size.y += titleHeight(); + } + if (e->value_mask & CWWidth) { + c->size.width = e->width; + if (c->framed == True) + c->size.width += 2 * border; + } + if (e->value_mask & CWHeight) { + c->size.height = e->height; + if (c->framed == True) + c->size.height += 2 * border; + } + if (e->value_mask & CWBorderWidth) + c->border = e->border_width; + + if (getScreenFromRoot(c->parent) == 0) { + wc.x = c->size.x; + wc.y = c->size.y; + if (c->framed == True) + wc.y -= titleHeight(); + wc.width = c->size.width; + wc.height = c->size.height; + if (c->framed == True) + wc.height += titleHeight(); + wc.border_width = 1; + wc.sibling = e->above; + wc.stack_mode = e->detail; + + XConfigureWindow(dpy, e->parent, e->value_mask, &wc); + sendConfigureNotify(c); + } + } + if (c && (c->internal_state == INormal) && (c->framed == True)) { + wc.x = border; + wc.y = border; + } else { + wc.x = e->x; + wc.y = e->y; + } + + wc.width = e->width; + wc.height = e->height; + wc.border_width = 0; + wc.sibling = e->above; + wc.stack_mode = e->detail; + e->value_mask |= CWBorderWidth; + + XConfigureWindow(dpy, e->window, e->value_mask, &wc); + + if (c) { + if (c->framed == True) { + XMoveResizeWindow(dpy, c->parent, + c->size.x, c->size.y - titleHeight(), + c->size.width, c->size.height + titleHeight()); + XMoveWindow(dpy, c->window, + border, border + titleHeight()); + } else { + XMoveResizeWindow(dpy, c->window, + c->size.x, c->size.y, + c->size.width, c->size.height); + } + } } static void destroy(XEvent *ev) { - Client * c; - Window w = ev->xdestroywindow.window; + Client * c; + Window w = ev->xdestroywindow.window; - c = Client_Get(w); - if (c == 0) - return; + c = Client_Get(w); + if (c == 0) + return; - ignore_badwindow = 1; - Client_Remove(c); - ignore_badwindow = 0; + ignore_badwindow = 1; + Client_Remove(c); + ignore_badwindow = 0; } static void clientmessage(XEvent *ev) { - Client * c; - XClientMessageEvent * e = &ev->xclient; - - c = Client_Get(e->window); - if (c == 0) return; - if (e->message_type == wm_change_state) { - return; - } - if (e->message_type == ewmh_atom[_NET_WM_STATE] && - e->format == 32) { - ewmh_change_state(c, e->data.l[0], e->data.l[1]); - ewmh_change_state(c, e->data.l[0], e->data.l[2]); - return; - } - if (e->message_type == ewmh_atom[_NET_ACTIVE_WINDOW] && - e->format == 32) { - /* An EWMH enabled application has asked for this client - * to be made the active window. The window is raised, and - * focus given if the focus mode is click (focusing on a - * window other than the one the pointer is in makes no - * sense when the focus mode is enter). - */ - XMapWindow(dpy, c->parent); - Client_Raise(c); - if (c != current && focus_mode == focus_click) - Client_Focus(c, CurrentTime); - return; - } - if (e->message_type == ewmh_atom[_NET_CLOSE_WINDOW] && - e->format == 32) { - Client_Close(c); - return; - } - if (e->message_type == ewmh_atom[_NET_MOVERESIZE_WINDOW] && - e->format == 32) { - XEvent ev; - - /* FIXME: ok, so this is a bit of a hack */ - ev.xconfigurerequest.window = e->window; - ev.xconfigurerequest.x = e->data.l[1]; - ev.xconfigurerequest.y = e->data.l[2]; - ev.xconfigurerequest.width = e->data.l[3]; - ev.xconfigurerequest.height = e->data.l[4]; - ev.xconfigurerequest.value_mask = 0; - if (e->data.l[0] & (1 << 8)) - ev.xconfigurerequest.value_mask |= CWX; - if (e->data.l[0] & (1 << 9)) - ev.xconfigurerequest.value_mask |= CWY; - if (e->data.l[0] & (1 << 10)) - ev.xconfigurerequest.value_mask |= CWWidth; - if (e->data.l[0] & (1 << 11)) - ev.xconfigurerequest.value_mask |= CWHeight; - configurereq(&ev); - return; - } - if (e->message_type == ewmh_atom[_NET_WM_MOVERESIZE] && - e->format == 32) { - Edge edge = E_LAST; - EWMHDirection direction = e->data.l[2]; -/* - int x_root = e->data.l[0]; - int y_root = e->data.l[1]; -*/ - - - /* before we can do any resizing, make the window visible */ - XMapWindow(dpy, c->parent); - Client_Raise(c); - /* FIXME: we're ignorning x_root, y_root and button! */ - switch (direction) { - case DSizeTopLeft: - edge = ETopLeft; - break; - case DSizeTop: - edge = ETop; - break; - case DSizeTopRight: - edge = ETopRight; - break; - case DSizeRight: - edge = ERight; - break; - case DSizeBottomRight: - edge = EBottomRight; - break; - case DSizeBottom: - edge = EBottom; - break; - case DSizeBottomLeft: - edge = EBottomLeft; - break; - case DSizeLeft: - edge = ELeft; - break; - case DMove: - edge = ENone; - break; - case DSizeKeyboard: - /* FIXME: don't know how to deal with this */ - edge = E_LAST; - break; - case DMoveKeyboard: -#if 0 -/* need to do a release and this is too broken for that */ - /* don't believe i'm doing this. mouse warping - * sucks! - */ - XWarpPointer(dpy, c->screen->root, c->window, - x_root, y_root, - c->screen->display_width, - c->screen->display_height, - c->size.width / 2, c->size.height / 2); - edge = ENone; -#endif - edge = E_LAST; - break; - default: - edge = E_LAST; - fprintf(stderr, "%s: received _NET_WM_MOVERESIZE" - " with bad direction", argv0); - break; - } - switch (edge) { - case E_LAST: - break; - case ENone: - Client_Move(c); - break; - default: - Client_ReshapeEdge(c, edge); - break; - } - } -} - -static void -colormap(XEvent *ev) { - Client * c; - XColormapEvent * e = &ev->xcolormap; - - if (e->new) { - c = Client_Get(e->window); - if (c) { - c->cmap = e->colormap; - if (c == current) - cmapfocus(c); - } else { - Client_ColourMap(ev); - } - } + Client * c; + XClientMessageEvent * e = &ev->xclient; + + c = Client_Get(e->window); + if (c == 0) return; + if (e->message_type == ewmh_atom[_NET_ACTIVE_WINDOW] && + e->format == 32) { + /* An EWMH enabled application has asked for this client + * to be made the active window. The window is raised, and + * focus given if the focus mode is click (focusing on a + * window other than the one the pointer is in makes no + * sense when the focus mode is enter). + */ + XMapWindow(dpy, c->parent); + Client_Raise(c); + return; + } + if (e->message_type == ewmh_atom[_NET_CLOSE_WINDOW] && + e->format == 32) { + Client_Close(c); + return; + } + if (e->message_type == ewmh_atom[_NET_MOVERESIZE_WINDOW] && + e->format == 32) { + XEvent ev; + + /* FIXME: ok, so this is a bit of a hack */ + ev.xconfigurerequest.window = e->window; + ev.xconfigurerequest.x = e->data.l[1]; + ev.xconfigurerequest.y = e->data.l[2]; + ev.xconfigurerequest.width = e->data.l[3]; + ev.xconfigurerequest.height = e->data.l[4]; + ev.xconfigurerequest.value_mask = 0; + if (e->data.l[0] & (1 << 8)) + ev.xconfigurerequest.value_mask |= CWX; + if (e->data.l[0] & (1 << 9)) + ev.xconfigurerequest.value_mask |= CWY; + if (e->data.l[0] & (1 << 10)) + ev.xconfigurerequest.value_mask |= CWWidth; + if (e->data.l[0] & (1 << 11)) + ev.xconfigurerequest.value_mask |= CWHeight; + configurereq(&ev); + return; + } + if (e->message_type == ewmh_atom[_NET_WM_MOVERESIZE] && + e->format == 32) { + Edge edge = E_LAST; + EWMHDirection direction = e->data.l[2]; + + /* before we can do any resizing, make the window visible */ + XMapWindow(dpy, c->parent); + Client_Raise(c); + /* FIXME: we're ignorning x_root, y_root and button! */ + switch (direction) { + case DSizeTopLeft: + edge = ETopLeft; + break; + case DSizeTop: + edge = ETop; + break; + case DSizeTopRight: + edge = ETopRight; + break; + case DSizeRight: + edge = ERight; + break; + case DSizeBottomRight: + edge = EBottomRight; + break; + case DSizeBottom: + edge = EBottom; + break; + case DSizeBottomLeft: + edge = EBottomLeft; + break; + case DSizeLeft: + edge = ELeft; + break; + case DMove: + edge = ENone; + break; + case DSizeKeyboard: + /* FIXME: don't know how to deal with this */ + edge = E_LAST; + break; + case DMoveKeyboard: + edge = E_LAST; + break; + default: + edge = E_LAST; + fprintf(stderr, "%s: received _NET_WM_MOVERESIZE" + " with bad direction", argv0); + break; + } + switch (edge) { + case E_LAST: + break; + case ENone: + Client_Move(c); + break; + default: + Client_ReshapeEdge(c, edge); + break; + } + } } static void property(XEvent * ev) { - Client * c; - XPropertyEvent * e = &ev->xproperty; - - c = Client_Get(e->window); - if (c == 0) - return; - - if (e->atom == _mozilla_url || e->atom == XA_WM_NAME) { - getWindowName(c); - setactive(c, c == current, 0L); - } else if (e->atom == XA_WM_TRANSIENT_FOR) { - getTransientFor(c); - } else if (e->atom == XA_WM_NORMAL_HINTS) { - getNormalHints(c); - } else if (e->atom == wm_colormaps) { - getColourmaps(c); - if (c == current) - cmapfocus(c); - } else if (e->atom == ewmh_atom[_NET_WM_STRUT]) { - ewmh_get_strut(c); - } else if (e->atom == ewmh_atom[_NET_WM_STATE]) { - // Received notice that client wants to change its state - // update internal wstate tracking - Bool wasFullscreen = c->wstate.fullscreen; - ewmh_get_state(c); - // make any changes requested - if (c->wstate.fullscreen == True && wasFullscreen == False) Client_EnterFullScreen(c); - else if (c->wstate.fullscreen == False && wasFullscreen == True) Client_ExitFullScreen(c); - } + Client * c; + XPropertyEvent * e = &ev->xproperty; + + c = Client_Get(e->window); + if (c == 0) + return; + + if (e->atom == XA_WM_NAME) { + getWindowName(c); + Client_SetActive(c, c == current, 0L); + } else if (e->atom == XA_WM_TRANSIENT_FOR) { + getTransientFor(c); + } else if (e->atom == XA_WM_NORMAL_HINTS) { + getNormalHints(c); + } } static void reparent(XEvent *ev) { - Client * c; - XReparentEvent * e = &ev->xreparent; + Client * c; + XReparentEvent * e = &ev->xreparent; - if (getScreenFromRoot(e->event) == 0 || e->override_redirect || getScreenFromRoot(e->parent) != 0) - return; + if (getScreenFromRoot(e->event) == 0 || e->override_redirect || getScreenFromRoot(e->parent) != 0) + return; - c = Client_Get(e->window); - if (c != 0 && (getScreenFromRoot(c->parent) != 0 || withdrawn(c))) - Client_Remove(c); + c = Client_Get(e->window); + if (c != 0 && (getScreenFromRoot(c->parent) != 0 || Client_IsState(c, WithdrawnState))) + Client_Remove(c); } static void focuschange(XEvent *ev) { - Client *c; - Window focus_window; - int revert_to; - - if (ev->type == FocusOut) return; - - XGetInputFocus(dpy, &focus_window, &revert_to); - if (focus_window == PointerRoot || focus_window == None) { - if (current) Client_Focus(NULL, CurrentTime); - return; - } - c = Client_Get(focus_window); - if (c && c != current) { - Client_Focus(c, CurrentTime); - } - return; + Client *c; + Window focus_window; + int revert_to; + + if (ev->type == FocusOut) return; + + XGetInputFocus(dpy, &focus_window, &revert_to); + if (focus_window == PointerRoot || focus_window == None) { + if (current) Client_Focus(NULL, CurrentTime); + return; + } + c = Client_Get(focus_window); + if (c && c != current) { + Client_Focus(c, CurrentTime); + } + return; } static void enter(XEvent *ev) { - Client *c; - - c = Client_Get(ev->xcrossing.window); - if (c == 0 || mode != wm_idle) - return; - - if (c->framed == True) { - XSetWindowAttributes attr; - - attr.cursor = c->screen->root_cursor; - XChangeWindowAttributes(dpy, c->parent, - CWCursor, &attr); - c->cursor = ENone; - } - if (c != current && !c->hidden && focus_mode == focus_enter) { - /* Entering a new window in enter focus mode, so take focus */ - Client_Focus(c, ev->xcrossing.time); - } + Client *c; + + c = Client_Get(ev->xcrossing.window); + if (c == 0 || mode != wm_idle) + return; + + if (c->framed == True) { + XSetWindowAttributes attr; + + attr.cursor = c->screen->root_cursor; + XChangeWindowAttributes(dpy, c->parent, + CWCursor, &attr); + c->cursor = ENone; + } + if (c != current) { + /* Entering a new window in enter focus mode, so take focus */ + Client_Focus(c, ev->xcrossing.time); + } } static void motionnotify(XEvent *ev) { - if (mode == wm_reshaping) - reshaping_motionnotify(ev); - else if (mode == wm_idle) { - XMotionEvent *e = &ev->xmotion; - Client *c = Client_Get(e->window); - Edge edge = ENone; - int quarter = (border + titleHeight()) / 4; - - if (c && (e->window == c->parent) && - (e->subwindow != c->window) && - mode == wm_idle) { - /* mouse moved in a frame we manage - check cursor */ - if (e->x > (quarter + 2) - && e->x < (3 + 3*quarter) - && e->y > quarter && e->y <= 3*quarter) { - edge = E_LAST; - } else if (e->x <= border && e->y <= border) { - edge = ETopLeft; - } else if (e->x >= (c->size.width - border) - && e->y <= border) { - edge = ETopRight; - } else if (e->x >= (c->size.width - border) - && e->y >= - (c->size.height + titleHeight() - border)) { - edge = EBottomRight; - } else if (e->x <= border && - e->y >= - (c->size.height + titleHeight() - border)) { - edge = EBottomLeft; - } else if (e->x > border && - e->x < (c->size.width - border) - && e->y < border) { - edge = ETop; - } else if (e->x > border && - e->x < (c->size.width - border) - && e->y >= border - && e->y < (titleHeight() + border)) { - edge = ENone; - } else if (e->x > (c->size.width - border) - && e->y > border - && e->y < - (c->size.height + titleHeight() - border)) { - edge = ERight; - } else if (e->x > border - && e->x < (c->size.width - border) - && e->y > (c->size.height - border)) { - edge = EBottom; - } else if (e->x < border - && e->y > border - && e->y < - (c->size.height + titleHeight() - border)) { - edge = ELeft; - } - if (c->cursor != edge) { - XSetWindowAttributes attr; - - if (edge == ENone) { - attr.cursor = - c->screen->root_cursor; - } else if (edge == E_LAST) { - attr.cursor = - c->screen->box_cursor; - } else { - attr.cursor = - c->screen->cursor_map[edge]; - } - XChangeWindowAttributes(dpy, c->parent, - CWCursor, &attr); - c->cursor = edge; - } - } - } + if (mode == wm_reshaping) + reshaping_motionnotify(ev); + else if (mode == wm_idle) { + XMotionEvent *e = &ev->xmotion; + Client *c = Client_Get(e->window); + Edge edge = ENone; + int quarter = (border + titleHeight()) / 4; + + if (c && (e->window == c->parent) && + (e->subwindow != c->window) && + mode == wm_idle) { + /* mouse moved in a frame we manage - check cursor */ + if (e->x > (quarter + 2) + && e->x < (3 + 3*quarter) + && e->y > quarter && e->y <= 3*quarter) { + edge = E_LAST; + } else if (e->x <= border && e->y <= border) { + edge = ETopLeft; + } else if (e->x >= (c->size.width - border) + && e->y <= border) { + edge = ETopRight; + } else if (e->x >= (c->size.width - border) + && e->y >= + (c->size.height + titleHeight() - border)) { + edge = EBottomRight; + } else if (e->x <= border && + e->y >= + (c->size.height + titleHeight() - border)) { + edge = EBottomLeft; + } else if (e->x > border && + e->x < (c->size.width - border) + && e->y < border) { + edge = ETop; + } else if (e->x > border && + e->x < (c->size.width - border) + && e->y >= border + && e->y < (titleHeight() + border)) { + edge = ENone; + } else if (e->x > (c->size.width - border) + && e->y > border + && e->y < + (c->size.height + titleHeight() - border)) { + edge = ERight; + } else if (e->x > border + && e->x < (c->size.width - border) + && e->y > (c->size.height - border)) { + edge = EBottom; + } else if (e->x < border + && e->y > border + && e->y < + (c->size.height + titleHeight() - border)) { + edge = ELeft; + } + if (c->cursor != edge) { + XSetWindowAttributes attr; + + if (edge == ENone) { + attr.cursor = c->screen->root_cursor; + } else { + attr.cursor = c->screen->cursor_map[edge]; + } + XChangeWindowAttributes(dpy, c->parent, + CWCursor, &attr); + c->cursor = edge; + } + } + } } /*ARGSUSED*/ -void +static void reshaping_motionnotify(XEvent* ev) { - int nx; /* New x. */ - int ny; /* New y. */ - int ox; /* Original x. */ - int oy; /* Original y. */ - int ndx; /* New width. */ - int ndy; /* New height. */ - int odx; /* Original width. */ - int ody; /* Original height. */ - int pointer_x; - int pointer_y; - - if (mode != wm_reshaping || !current) return; - - getMousePosition(&pointer_x, &pointer_y); - - if (interacting_edge != ENone) { - nx = ox = current->size.x; - ny = oy = current->size.y; - ndx = odx = current->size.width; - ndy = ody = current->size.height; - - /* Vertical. */ - switch (interacting_edge) { - case ETop: - case ETopLeft: - case ETopRight: - pointer_y += titleHeight(); - ndy += (current->size.y - pointer_y); - ny = pointer_y; - break; - case EBottom: - case EBottomLeft: - case EBottomRight: - ndy = pointer_y - current->size.y; - break; - default: break; - } - - /* Horizontal. */ - switch (interacting_edge) { - case ERight: - case ETopRight: - case EBottomRight: - ndx = pointer_x - current->size.x; - break; - case ELeft: - case ETopLeft: - case EBottomLeft: - ndx += (current->size.x - pointer_x); - nx = pointer_x; - break; - default: break; - } - - Client_MakeSane(current, interacting_edge, &nx, &ny, &ndx, &ndy); - XMoveResizeWindow(dpy, current->parent, - current->size.x, current->size.y - titleHeight(), - current->size.width, current->size.height + titleHeight()); - if (current->size.width == odx && current->size.height == ody) { - if (current->size.x != ox || current->size.y != oy) - sendConfigureNotify(current); - } else - XMoveResizeWindow(dpy, current->window, - border, border + titleHeight(), - current->size.width - 2 * border, - current->size.height - 2 * border); - } else { - nx = pointer_x + start_x; - ny = pointer_y + start_y; - - Client_MakeSane(current, interacting_edge, &nx, &ny, 0, 0); - if (current->framed == True) { - XMoveWindow(dpy, current->parent, - current->size.x, - current->size.y - titleHeight()); - } else { - XMoveWindow(dpy, current->parent, - current->size.x, current->size.y); - } - sendConfigureNotify(current); - } + int nx; /* New x. */ + int ny; /* New y. */ + int ox; /* Original x. */ + int oy; /* Original y. */ + int ndx; /* New width. */ + int ndy; /* New height. */ + int odx; /* Original width. */ + int ody; /* Original height. */ + int pointer_x; + int pointer_y; + + if (mode != wm_reshaping || !current) return; + + getMousePosition(&pointer_x, &pointer_y); + + if (interacting_edge != ENone) { + nx = ox = current->size.x; + ny = oy = current->size.y; + ndx = odx = current->size.width; + ndy = ody = current->size.height; + + /* Vertical. */ + switch (interacting_edge) { + case ETop: + case ETopLeft: + case ETopRight: + pointer_y += titleHeight(); + ndy += (current->size.y - pointer_y); + ny = pointer_y; + break; + case EBottom: + case EBottomLeft: + case EBottomRight: + ndy = pointer_y - current->size.y; + break; + default: break; + } + + /* Horizontal. */ + switch (interacting_edge) { + case ERight: + case ETopRight: + case EBottomRight: + ndx = pointer_x - current->size.x; + break; + case ELeft: + case ETopLeft: + case EBottomLeft: + ndx += (current->size.x - pointer_x); + nx = pointer_x; + break; + default: break; + } + + Client_MakeSane(current, interacting_edge, &nx, &ny, &ndx, &ndy); + XMoveResizeWindow(dpy, current->parent, + current->size.x, current->size.y - titleHeight(), + current->size.width, current->size.height + titleHeight()); + if (current->size.width == odx && current->size.height == ody) { + if (current->size.x != ox || current->size.y != oy) + sendConfigureNotify(current); + } else + XMoveResizeWindow(dpy, current->window, + border, border + titleHeight(), + current->size.width - 2 * border, + current->size.height - 2 * border); + } else { + nx = pointer_x + start_x; + ny = pointer_y + start_y; + + Client_MakeSane(current, interacting_edge, &nx, &ny, 0, 0); + if (current->framed == True) { + XMoveWindow(dpy, current->parent, + current->size.x, + current->size.y - titleHeight()); + } else { + XMoveWindow(dpy, current->parent, + current->size.x, current->size.y); + } + sendConfigureNotify(current); + } } diff --git a/ewmh.c b/ewmh.c index e6bb1b3..54f1b74 100644 --- a/ewmh.c +++ b/ewmh.c @@ -1,17 +1,17 @@ /* * lwm, a window manager for X11 * Copyright (C) 1997-2016 Elliott Hughes, James Carter - * + * * 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 (at your option) 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. @@ -34,376 +34,248 @@ Atom utf8_string; void ewmh_init(void) { - /* build half a million EWMH atoms */ - ewmh_atom[_NET_SUPPORTED] = - XInternAtom(dpy, "_NET_SUPPORTED", False); - ewmh_atom[_NET_CLIENT_LIST] = - XInternAtom(dpy, "_NET_CLIENT_LIST", False); - ewmh_atom[_NET_CLIENT_LIST_STACKING] = - XInternAtom(dpy, "_NET_CLIENT_LIST_STACKING", False); - ewmh_atom[_NET_NUMBER_OF_DESKTOPS] = - XInternAtom(dpy, "_NET_NUMBER_OF_DESKTOPS", False); - ewmh_atom[_NET_DESKTOP_GEOMETRY] = - XInternAtom(dpy, "_NET_DESKTOP_GEOMETRY", False); - ewmh_atom[_NET_DESKTOP_VIEWPORT] = - XInternAtom(dpy, "_NET_DESKTOP_VIEWPORT", False); - ewmh_atom[_NET_CURRENT_DESKTOP] = - XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False); - ewmh_atom[_NET_ACTIVE_WINDOW] = - XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); - ewmh_atom[_NET_WORKAREA] = - XInternAtom(dpy, "_NET_WORKAREA", False); - ewmh_atom[_NET_SUPPORTING_WM_CHECK] = - XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); - ewmh_atom[_NET_CLOSE_WINDOW] = - XInternAtom(dpy, "_NET_CLOSE_WINDOW", False); - ewmh_atom[_NET_MOVERESIZE_WINDOW] = - XInternAtom(dpy, "_NET_MOVERESIZE_WINDOW", False); - ewmh_atom[_NET_WM_MOVERESIZE] = - XInternAtom(dpy, "_NET_WM_MOVERESIZE", False); - ewmh_atom[_NET_WM_NAME] = - XInternAtom(dpy, "_NET_WM_NAME", False); - ewmh_atom[_NET_WM_WINDOW_TYPE] = - XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); - ewmh_atom[_NET_WM_STATE] = - XInternAtom(dpy, "_NET_WM_STATE", False); - ewmh_atom[_NET_WM_ALLOWED_ACTIONS] = - XInternAtom(dpy, "_NET_WM_ALLOWED_ACTIONS", False); - ewmh_atom[_NET_WM_STRUT] = - XInternAtom(dpy, "_NET_WM_STRUT", False); - ewmh_atom[_NET_WM_WINDOW_TYPE_DESKTOP] = - XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False); - ewmh_atom[_NET_WM_WINDOW_TYPE_DOCK] = - XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); - ewmh_atom[_NET_WM_WINDOW_TYPE_TOOLBAR] = - XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False); - ewmh_atom[_NET_WM_WINDOW_TYPE_MENU] = - XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_MENU", False); - ewmh_atom[_NET_WM_WINDOW_TYPE_UTILITY] = - XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_UTILITY", False); - ewmh_atom[_NET_WM_WINDOW_TYPE_SPLASH] = - XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False); - ewmh_atom[_NET_WM_WINDOW_TYPE_DIALOG] = - XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); - ewmh_atom[_NET_WM_WINDOW_TYPE_NORMAL] = - XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False); - ewmh_atom[_NET_WM_STATE_SKIP_TASKBAR] = - XInternAtom(dpy, "_NET_WM_STATE_SKIP_TASKBAR", False); - ewmh_atom[_NET_WM_STATE_SKIP_PAGER] = - XInternAtom(dpy, "_NET_WM_STATE_SKIP_PAGER", False); - ewmh_atom[_NET_WM_STATE_HIDDEN] = - XInternAtom(dpy, "_NET_WM_STATE_HIDDEN", False); - ewmh_atom[_NET_WM_STATE_FULLSCREEN] = - XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); - ewmh_atom[_NET_WM_ACTION_MOVE] = - XInternAtom(dpy, "_NET_WM_ACTION_MOVE", False); - ewmh_atom[_NET_WM_ACTION_RESIZE] = - XInternAtom(dpy, "_NET_WM_ACTION_RESIZE", False); - ewmh_atom[_NET_WM_ACTION_FULLSCREEN] = - XInternAtom(dpy, "_NET_WM_ACTION_FULLSCREEN", False); - ewmh_atom[_NET_WM_ACTION_CLOSE] = - XInternAtom(dpy, "_NET_WM_ACTION_CLOSE", False); - utf8_string = XInternAtom(dpy, "UTF8_STRING", False); + /* build half a million EWMH atoms */ + ewmh_atom[_NET_SUPPORTED] = + XInternAtom(dpy, "_NET_SUPPORTED", False); + ewmh_atom[_NET_CLIENT_LIST] = + XInternAtom(dpy, "_NET_CLIENT_LIST", False); + ewmh_atom[_NET_CLIENT_LIST_STACKING] = + XInternAtom(dpy, "_NET_CLIENT_LIST_STACKING", False); + ewmh_atom[_NET_NUMBER_OF_DESKTOPS] = + XInternAtom(dpy, "_NET_NUMBER_OF_DESKTOPS", False); + ewmh_atom[_NET_DESKTOP_GEOMETRY] = + XInternAtom(dpy, "_NET_DESKTOP_GEOMETRY", False); + ewmh_atom[_NET_DESKTOP_VIEWPORT] = + XInternAtom(dpy, "_NET_DESKTOP_VIEWPORT", False); + ewmh_atom[_NET_CURRENT_DESKTOP] = + XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False); + ewmh_atom[_NET_ACTIVE_WINDOW] = + XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); + ewmh_atom[_NET_WORKAREA] = + XInternAtom(dpy, "_NET_WORKAREA", False); + ewmh_atom[_NET_SUPPORTING_WM_CHECK] = + XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); + ewmh_atom[_NET_CLOSE_WINDOW] = + XInternAtom(dpy, "_NET_CLOSE_WINDOW", False); + ewmh_atom[_NET_MOVERESIZE_WINDOW] = + XInternAtom(dpy, "_NET_MOVERESIZE_WINDOW", False); + ewmh_atom[_NET_WM_MOVERESIZE] = + XInternAtom(dpy, "_NET_WM_MOVERESIZE", False); + ewmh_atom[_NET_WM_NAME] = + XInternAtom(dpy, "_NET_WM_NAME", False); + ewmh_atom[_NET_WM_WINDOW_TYPE] = + XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); + ewmh_atom[_NET_WM_STATE] = + XInternAtom(dpy, "_NET_WM_STATE", False); + ewmh_atom[_NET_WM_ALLOWED_ACTIONS] = + XInternAtom(dpy, "_NET_WM_ALLOWED_ACTIONS", False); + ewmh_atom[_NET_WM_STRUT] = + XInternAtom(dpy, "_NET_WM_STRUT", False); + ewmh_atom[_NET_WM_WINDOW_TYPE_DESKTOP] = + XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False); + ewmh_atom[_NET_WM_WINDOW_TYPE_DOCK] = + XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); + ewmh_atom[_NET_WM_WINDOW_TYPE_TOOLBAR] = + XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False); + ewmh_atom[_NET_WM_WINDOW_TYPE_MENU] = + XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_MENU", False); + ewmh_atom[_NET_WM_WINDOW_TYPE_UTILITY] = + XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_UTILITY", False); + ewmh_atom[_NET_WM_WINDOW_TYPE_SPLASH] = + XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False); + ewmh_atom[_NET_WM_WINDOW_TYPE_DIALOG] = + XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); + ewmh_atom[_NET_WM_WINDOW_TYPE_NORMAL] = + XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False); + ewmh_atom[_NET_WM_STATE_SKIP_TASKBAR] = + XInternAtom(dpy, "_NET_WM_STATE_SKIP_TASKBAR", False); + ewmh_atom[_NET_WM_STATE_SKIP_PAGER] = + XInternAtom(dpy, "_NET_WM_STATE_SKIP_PAGER", False); + ewmh_atom[_NET_WM_STATE_HIDDEN] = + XInternAtom(dpy, "_NET_WM_STATE_HIDDEN", False); + ewmh_atom[_NET_WM_STATE_FULLSCREEN] = + XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); + ewmh_atom[_NET_WM_ACTION_MOVE] = + XInternAtom(dpy, "_NET_WM_ACTION_MOVE", False); + ewmh_atom[_NET_WM_ACTION_RESIZE] = + XInternAtom(dpy, "_NET_WM_ACTION_RESIZE", False); + ewmh_atom[_NET_WM_ACTION_FULLSCREEN] = + XInternAtom(dpy, "_NET_WM_ACTION_FULLSCREEN", False); + ewmh_atom[_NET_WM_ACTION_CLOSE] = + XInternAtom(dpy, "_NET_WM_ACTION_CLOSE", False); + utf8_string = XInternAtom(dpy, "UTF8_STRING", False); } void ewmh_init_screens(void) { - int i; - unsigned long data[4]; - - /* announce EWMH compatibility on all acreens */ - for (i = 0; i < screen_count; i++) { - screens[i].ewmh_set_client_list = False; - screens[i].ewmh_compat = XCreateSimpleWindow(dpy, - screens[i].root, - -200, -200, 1, 1, - 0, 0, 0); - XChangeProperty(dpy, screens[i].ewmh_compat, - ewmh_atom[_NET_WM_NAME], - utf8_string, 8, PropModeReplace, - "lwm", 3); - - /* set root window properties */ - XChangeProperty(dpy, screens[i].root, - ewmh_atom[_NET_SUPPORTED], - XA_ATOM, 32, PropModeReplace, - (unsigned char *)ewmh_atom, EWMH_ATOM_LAST); - - XChangeProperty(dpy, screens[i].root, - ewmh_atom[_NET_SUPPORTING_WM_CHECK], - XA_WINDOW, 32, PropModeReplace, - (unsigned char *)&screens[i].ewmh_compat, 1); - - data[0] = 1; - XChangeProperty(dpy, screens[i].root, - ewmh_atom[_NET_NUMBER_OF_DESKTOPS], - XA_CARDINAL, 32, PropModeReplace, - (unsigned char*)data, 1); - - data[0] = screens[i].display_width; - data[1] = screens[i].display_height; - XChangeProperty(dpy, screens[i].root, - ewmh_atom[_NET_DESKTOP_GEOMETRY], - XA_CARDINAL, 32, PropModeReplace, - (unsigned char*)data, 2); - - data[0] = 0; - data[1] = 0; - XChangeProperty(dpy, screens[i].root, - ewmh_atom[_NET_DESKTOP_VIEWPORT], - XA_CARDINAL, 32, PropModeReplace, - (unsigned char*)data, 2); - - data[0] = 0; - XChangeProperty(dpy, screens[i].root, - ewmh_atom[_NET_CURRENT_DESKTOP], - XA_CARDINAL, 32, PropModeReplace, - (unsigned char*)data, 1); - - ewmh_set_strut(&screens[i]); - ewmh_set_client_list(&screens[i]); - } + int i; + unsigned long data[4]; + + /* announce EWMH compatibility on all acreens */ + for (i = 0; i < screen_count; i++) { + screens[i].ewmh_set_client_list = False; + screens[i].ewmh_compat = XCreateSimpleWindow(dpy, + screens[i].root, + -200, -200, 1, 1, + 0, 0, 0); + XChangeProperty(dpy, screens[i].ewmh_compat, + ewmh_atom[_NET_WM_NAME], + utf8_string, 8, PropModeReplace, + (unsigned char*)"lwm", 3); + + /* set root window properties */ + XChangeProperty(dpy, screens[i].root, + ewmh_atom[_NET_SUPPORTED], + XA_ATOM, 32, PropModeReplace, + (unsigned char *)ewmh_atom, EWMH_ATOM_LAST); + + XChangeProperty(dpy, screens[i].root, + ewmh_atom[_NET_SUPPORTING_WM_CHECK], + XA_WINDOW, 32, PropModeReplace, + (unsigned char *)&screens[i].ewmh_compat, 1); + + data[0] = 1; + XChangeProperty(dpy, screens[i].root, + ewmh_atom[_NET_NUMBER_OF_DESKTOPS], + XA_CARDINAL, 32, PropModeReplace, + (unsigned char*)data, 1); + + data[0] = screens[i].display_width; + data[1] = screens[i].display_height; + XChangeProperty(dpy, screens[i].root, + ewmh_atom[_NET_DESKTOP_GEOMETRY], + XA_CARDINAL, 32, PropModeReplace, + (unsigned char*)data, 2); + + data[0] = 0; + data[1] = 0; + XChangeProperty(dpy, screens[i].root, + ewmh_atom[_NET_DESKTOP_VIEWPORT], + XA_CARDINAL, 32, PropModeReplace, + (unsigned char*)data, 2); + + data[0] = 0; + XChangeProperty(dpy, screens[i].root, + ewmh_atom[_NET_CURRENT_DESKTOP], + XA_CARDINAL, 32, PropModeReplace, + (unsigned char*)data, 1); + + ewmh_set_client_list(&screens[i]); + } } EWMHWindowType ewmh_get_window_type(Window w) { - Atom rt; - Atom *type; - int fmt; - unsigned long n; - unsigned long extra; - int i; - EWMHWindowType ret; - - i = XGetWindowProperty(dpy, w, - ewmh_atom[_NET_WM_WINDOW_TYPE], - 0, 100, False, XA_ATOM, &rt, &fmt, &n, &extra, - (unsigned char **)&type); - if (i != Success || type == NULL) - return WTypeNone; - ret = WTypeNone; - for (; n; n--) { - if (type[n - 1] == - ewmh_atom[_NET_WM_WINDOW_TYPE_DESKTOP]) { - ret = WTypeDesktop; - break; - } - if (type[n - 1] == - ewmh_atom[_NET_WM_WINDOW_TYPE_DOCK]) { - ret = WTypeDock; - break; - } - if (type[n - 1] == - ewmh_atom[_NET_WM_WINDOW_TYPE_TOOLBAR]) { - ret = WTypeToolbar; - break; - } - if (type[n - 1] == - ewmh_atom[_NET_WM_WINDOW_TYPE_MENU]) { - ret = WTypeMenu; - break; - } - if (type[n - 1] == - ewmh_atom[_NET_WM_WINDOW_TYPE_UTILITY]) { - ret = WTypeUtility; - break; - } - if (type[n - 1] == - ewmh_atom[_NET_WM_WINDOW_TYPE_SPLASH]) { - ret = WTypeSplash; - break; - } - if (type[n - 1] == - ewmh_atom[_NET_WM_WINDOW_TYPE_DIALOG]) { - ret = WTypeDialog; - break; - } - if (type[n - 1] == - ewmh_atom[_NET_WM_WINDOW_TYPE_NORMAL]) { - ret = WTypeNormal; - break; - } - } - XFree(type); - return ret; + Atom rt; + Atom *type; + int fmt; + unsigned long n; + unsigned long extra; + int i; + EWMHWindowType ret; + + i = XGetWindowProperty(dpy, w, + ewmh_atom[_NET_WM_WINDOW_TYPE], + 0, 100, False, XA_ATOM, &rt, &fmt, &n, &extra, + (unsigned char **)&type); + if (i != Success || type == NULL) + return WTypeNone; + ret = WTypeNone; + for (; n; n--) { + if (type[n - 1] == + ewmh_atom[_NET_WM_WINDOW_TYPE_DESKTOP]) { + ret = WTypeDesktop; + break; + } + if (type[n - 1] == + ewmh_atom[_NET_WM_WINDOW_TYPE_DOCK]) { + ret = WTypeDock; + break; + } + if (type[n - 1] == + ewmh_atom[_NET_WM_WINDOW_TYPE_TOOLBAR]) { + ret = WTypeToolbar; + break; + } + if (type[n - 1] == + ewmh_atom[_NET_WM_WINDOW_TYPE_MENU]) { + ret = WTypeMenu; + break; + } + if (type[n - 1] == + ewmh_atom[_NET_WM_WINDOW_TYPE_UTILITY]) { + ret = WTypeUtility; + break; + } + if (type[n - 1] == + ewmh_atom[_NET_WM_WINDOW_TYPE_SPLASH]) { + ret = WTypeSplash; + break; + } + if (type[n - 1] == + ewmh_atom[_NET_WM_WINDOW_TYPE_DIALOG]) { + ret = WTypeDialog; + break; + } + if (type[n - 1] == + ewmh_atom[_NET_WM_WINDOW_TYPE_NORMAL]) { + ret = WTypeNormal; + break; + } + } + XFree(type); + return ret; } Bool ewmh_get_window_name(Client *c) { -#ifdef X_HAVE_UTF8_STRING - Atom rt; - char *name; - int fmt; - unsigned long n; - unsigned long extra; - int i; - - i = XGetWindowProperty(dpy, c->window, - ewmh_atom[_NET_WM_NAME], - 0, 100, False, utf8_string, &rt, &fmt, &n, &extra, - (unsigned char **)&name); - if (i != Success || name == NULL) - return False; - Client_Name(c, name, True); - XFree(name); - return True; -#else - return False; -#endif + Atom rt; + char *name; + int fmt; + unsigned long n; + unsigned long extra; + int i; + + i = XGetWindowProperty(dpy, c->window, + ewmh_atom[_NET_WM_NAME], + 0, 100, False, utf8_string, &rt, &fmt, &n, &extra, + (unsigned char **)&name); + if (i != Success || name == NULL) + return False; + Client_Name(c, name); + XFree(name); + return True; } Bool ewmh_hasframe(Client *c) { - switch (c->wtype) { - case WTypeDesktop: - case WTypeDock: - case WTypeMenu: - case WTypeSplash: - return False; - default: - return True; - } -} - -void -ewmh_get_state(Client *c) { - Atom rt; - Atom *state; - int fmt; - unsigned long n; - unsigned long extra; - int i; - - if (c == NULL) return; - i = XGetWindowProperty(dpy, c->window, - ewmh_atom[_NET_WM_STATE], - 0, 100, False, XA_ATOM, &rt, &fmt, &n, &extra, - (unsigned char **)&state); - if (i != Success || state == NULL) return; - c->wstate.skip_taskbar = False; - c->wstate.skip_pager = False; - c->wstate.fullscreen = False; - c->wstate.above = False; - c->wstate.below = False; - for (; n; n--) { - if (state[n - 1] == - ewmh_atom[_NET_WM_STATE_SKIP_TASKBAR]) - c->wstate.skip_taskbar = True; - if (state[n - 1] == - ewmh_atom[_NET_WM_STATE_SKIP_PAGER]) - c->wstate.skip_pager = True; - if (state[n - 1] == - ewmh_atom[_NET_WM_STATE_FULLSCREEN]) - c->wstate.fullscreen = True; - if (state[n - 1] == - ewmh_atom[_NET_WM_STATE_ABOVE]) - c->wstate.above = True; - if (state[n - 1] == - ewmh_atom[_NET_WM_STATE_BELOW]) - c->wstate.below = True; - } - XFree(state); + switch (c->wtype) { + case WTypeDesktop: + case WTypeDock: + case WTypeMenu: + case WTypeSplash: + return False; + default: + return True; + } } static Bool new_state(unsigned long action, Bool current) { - enum Action {remove, add, toggle}; - - switch (action) { - case remove: - return False; - case add: - return True; - case toggle: - if (current == True) return False; else return True; - } - fprintf(stderr,"%s: bad action in _NET_WM_STATE (%d)\n", - argv0, (int) action); - return current; -} - -void -ewmh_change_state(Client *c, unsigned long action, - unsigned long atom) { - Atom *a = (Atom *)&atom; - - if (atom == 0) return; - if (*a == ewmh_atom[_NET_WM_STATE_SKIP_TASKBAR]) - c->wstate.skip_taskbar = - new_state(action, c->wstate.skip_taskbar); - if (*a == ewmh_atom[_NET_WM_STATE_SKIP_PAGER]) - c->wstate.skip_pager = - new_state(action, c->wstate.skip_pager); - if (*a == ewmh_atom[_NET_WM_STATE_FULLSCREEN]) { - Bool was_fullscreen = c->wstate.fullscreen; - - c->wstate.fullscreen = - new_state(action, c->wstate.fullscreen); - if (was_fullscreen == False && - c->wstate.fullscreen == True) Client_EnterFullScreen(c); - if (was_fullscreen == True && - c->wstate.fullscreen == False) Client_ExitFullScreen(c); - } - if (*a == ewmh_atom[_NET_WM_STATE_ABOVE]) - c->wstate.above = - new_state(action, c->wstate.above); - if (*a == ewmh_atom[_NET_WM_STATE_BELOW]) - c->wstate.below = - new_state(action, c->wstate.below); - ewmh_set_state(c); - - /* may have to shuffle windows in the stack after a change of state */ - ewmh_set_client_list(c->screen); -} - -void -ewmh_set_state(Client *c) { - int atoms = 0; - Atom *a = NULL; - int i = 0; - - if (c == NULL) return; - - if (c->state != WithdrawnState) { - if (c->hidden == True) atoms++; - if (c->wstate.skip_taskbar == True) atoms++; - if (c->wstate.skip_pager == True) atoms++; - if (c->wstate.fullscreen == True) atoms++; - if (c->wstate.above == True) atoms++; - if (c->wstate.below == True) atoms++; - if (atoms > 0) a = malloc(sizeof(Atom) * atoms); - - if (c->hidden == True) { - a[i] = ewmh_atom[_NET_WM_STATE_HIDDEN]; - i++; - } - if (c->wstate.skip_taskbar == True) { - a[i] = ewmh_atom[_NET_WM_STATE_SKIP_TASKBAR]; - i++; - } - if (c->wstate.skip_pager == True) { - a[i] = ewmh_atom[_NET_WM_STATE_SKIP_PAGER]; - i++; - } - if (c->wstate.fullscreen == True) { - a[i] = ewmh_atom[_NET_WM_STATE_FULLSCREEN]; - i++; - } - if (c->wstate.above == True) { - a[i] = ewmh_atom[_NET_WM_STATE_ABOVE]; - i++; - } - if (c->wstate.below == True) { - a[i] = ewmh_atom[_NET_WM_STATE_BELOW]; - i++; - } - } - - XChangeProperty(dpy, c->window, ewmh_atom[_NET_WM_STATE], - XA_ATOM, 32, PropModeReplace, (unsigned char *)a, atoms); - if (a != NULL) free(a); - + enum Action {remove, add, toggle}; + + switch (action) { + case remove: + return False; + case add: + return True; + case toggle: + if (current == True) return False; else return True; + } + fprintf(stderr,"%s: bad action in _NET_WM_STATE (%d)\n", + argv0, (int) action); + return current; } void @@ -412,166 +284,21 @@ ewmh_set_allowed(Client *c) /* FIXME: this is dumb - the allowed actions should be calculuated * but for now, anything goes. */ - Atom action[4]; - - action[0] = ewmh_atom[_NET_WM_ACTION_MOVE]; - action[1] = ewmh_atom[_NET_WM_ACTION_RESIZE]; - action[2] = ewmh_atom[_NET_WM_ACTION_FULLSCREEN]; - action[3] = ewmh_atom[_NET_WM_ACTION_CLOSE]; - XChangeProperty(dpy, c->window, ewmh_atom[_NET_WM_ALLOWED_ACTIONS], - XA_ATOM, 32, PropModeReplace, (unsigned char *)action, 4); -} - -void -ewmh_set_strut(ScreenInfo *screen) { - Client *c; - EWMHStrut strut; - unsigned long data[4]; - /* FIXME: add parameter to MakeSane rather than this hack */ - Edge backup; - - /* find largest reserved areas */ - strut.left = 0; - strut.right = 0; - strut.top = 0; - strut.bottom = 0; - for (c = client_head(); c; c = c->next) { - if (c->screen != screen) continue; - if (c->strut.left > strut.left) strut.left = c->strut.left; - if (c->strut.right > strut.right) strut.right = c->strut.right; - if (c->strut.top > strut.top) strut.top = c->strut.top; - if (c->strut.bottom > strut.bottom) - strut.bottom = c->strut.bottom; - } - - /* if the reservered aread have not changed then we're done */ - if ( screen->strut.left == strut.left && - screen->strut.right == strut.right && - screen->strut.top == strut.top && - screen->strut.bottom == strut.bottom) return; - - /* apply the new strut */ - screen->strut.left = strut.left; - screen->strut.right = strut.right; - screen->strut.top = strut.top; - screen->strut.bottom = strut.bottom; - - /* set the new workarea */ - data[0] = strut.left; - data[1] = strut.top; - data[2] = screen->display_width - (strut.left + strut.right); - data[3] = screen->display_height - (strut.top + strut.bottom); - XChangeProperty(dpy, screen->root, - ewmh_atom[_NET_WORKAREA], - XA_CARDINAL, 32, PropModeReplace, - (unsigned char*)data, 4); - - /* ensure no window fully occupy reserved areas */ - for (c = client_head(); c; c = c->next) { - int x = c->size.x; - int y = c->size.y; - - if (c->wstate.fullscreen == True) continue; - backup = interacting_edge; - interacting_edge = ENone; - Client_MakeSane(c, ENone, &x, &y, 0, 0); - interacting_edge = backup; - if (c->framed == True) { - XMoveWindow(dpy, c->parent, - c->size.x, - c->size.y - titleHeight()); - } else { - XMoveWindow(dpy, c->parent, - c->size.x, c->size.y); - } - sendConfigureNotify(c); - } - -} - -/* - * get _NET_WM_STRUT and if it is available recalulate the screens - * reserved areas. the EWMH spec isn't clear about what we should do - * about hidden windows. It seems silly to reserve space for an invisible - * window, but the spec allows it. Ho Hum... jfc - */ -void -ewmh_get_strut(Client *c) { - Atom rt; - unsigned long *strut; - int fmt; - unsigned long n; - unsigned long extra; - int i; - - if (c == NULL) return; - i = XGetWindowProperty(dpy, c->window, - ewmh_atom[_NET_WM_STRUT], - 0, 5, False, XA_CARDINAL, &rt, &fmt, &n, &extra, - (unsigned char **)&strut); - if (i != Success || strut == NULL || n < 4) return; - c->strut.left = (unsigned int) strut[0]; - c->strut.right = (unsigned int) strut[1]; - c->strut.top = (unsigned int) strut[2]; - c->strut.bottom = (unsigned int) strut[3]; - ewmh_set_strut(c->screen); -} - -/* fix stack forces each window on the screen to be in the right place in - * the window stack as indicated in the EWMH spec version 1.2 (section 7.10). - */ -static void -fix_stack(ScreenInfo *screen) { - Client *c; - - /* this is pretty dumb. we should query the tree and only move - * those windows that require it. doing it regardless liek this - * causes the desktop to flicker - */ - - /* first lower clients with _NET_WM_STATE_BELOW */ - for (c = client_head(); c; c = c->next) { - if (c->wstate.below == False) continue; - Client_Lower(c); - } - - /* lower desktops - they are always the lowest */ - for (c = client_head(); c; c = c->next) { - if (c->wtype != WTypeDesktop) continue; - Client_Lower(c); - break; /* only one desktop, surely */ - } - - /* raise clients with _NET_WM_STATE_ABOVE and docks - * (unless marked with _NET_WM_STATE_BELOW) - */ - for (c = client_head(); c; c = c->next) { - if (!(c->wstate.above == True || - (c->wtype == WTypeDock && - c->wstate.below == False))) - continue; - Client_Raise(c); - } - - /* raise fullscreens - they're always on top */ - /* Misam Saki reports problems with this and believes fullscreens - * should not be automatically raised. - * - * However if the code below is removed then the panel is raised above - * fullscreens, which is not desirable. - */ - for (c = client_head(); c; c = c->next) { - if (c->wstate.fullscreen == False) continue; - Client_Raise(c); - } + Atom action[4]; + + action[0] = ewmh_atom[_NET_WM_ACTION_MOVE]; + action[1] = ewmh_atom[_NET_WM_ACTION_RESIZE]; + action[2] = ewmh_atom[_NET_WM_ACTION_FULLSCREEN]; + action[3] = ewmh_atom[_NET_WM_ACTION_CLOSE]; + XChangeProperty(dpy, c->window, ewmh_atom[_NET_WM_ALLOWED_ACTIONS], + XA_ATOM, 32, PropModeReplace, (unsigned char *)action, 4); } - static Bool valid_for_client_list(ScreenInfo *screen, Client *c) { - if (c->screen != screen) return False; - if (c->state == WithdrawnState) return False; - return True; + if (c->screen != screen) return False; + if (c->state == WithdrawnState) return False; + return True; } /* @@ -583,61 +310,60 @@ valid_for_client_list(ScreenInfo *screen, Client *c) { */ void ewmh_set_client_list(ScreenInfo *screen) { - int no_clients=0; - Window *client_list=NULL; - Window *stacked_client_list=NULL; - Client *c; - - if (screen == NULL || screen->ewmh_set_client_list == True) return; - screen->ewmh_set_client_list = True; - fix_stack(screen); - for (c = client_head(); c; c = c->next) { - if (valid_for_client_list(screen, c) == True) no_clients++; - } - if (no_clients > 0) { - int i; - Window dw1; - Window dw2; - Window *wins; - unsigned int win; - unsigned int nwins; - - client_list = malloc(sizeof(Window) * no_clients); - i = no_clients - 1; /* array starts with oldest */ - for (c = client_head(); c; c = c->next) { - if (valid_for_client_list(screen, c) == True) { - client_list[i] = c->window; - i--; - if (i < 0) break; - } - } - - stacked_client_list = malloc(sizeof(Window) * no_clients); - i = 0; - XQueryTree(dpy, screen->root, &dw1, &dw2, &wins, &nwins); - for (win = 0; win < nwins; win++) { - c = Client_Get(wins[win]); - if (!c) continue; - if (valid_for_client_list(screen, c) == True) { - stacked_client_list[i] = c->window; - i++; - if (i >= no_clients) break; - } - } - if ( nwins > 0 ) XFree(wins); - - } - XChangeProperty(dpy, screen->root, - ewmh_atom[_NET_CLIENT_LIST], - XA_WINDOW, 32, PropModeReplace, - (unsigned char*)client_list, no_clients); - XChangeProperty(dpy, screen->root, - ewmh_atom[_NET_CLIENT_LIST_STACKING], - XA_WINDOW, 32, PropModeReplace, - (unsigned char*)stacked_client_list, no_clients); - if (no_clients > 0 ) { - free(client_list); - free(stacked_client_list); - } - screen->ewmh_set_client_list = False; + int no_clients=0; + Window *client_list=NULL; + Window *stacked_client_list=NULL; + Client *c; + + if (screen == NULL || screen->ewmh_set_client_list == True) return; + screen->ewmh_set_client_list = True; + for (c = Client_List(); c; c = c->next) { + if (valid_for_client_list(screen, c) == True) no_clients++; + } + if (no_clients > 0) { + int i; + Window dw1; + Window dw2; + Window *wins; + unsigned int win; + unsigned int nwins; + + client_list = malloc(sizeof(Window) * no_clients); + i = no_clients - 1; /* array starts with oldest */ + for (c = Client_List(); c; c = c->next) { + if (valid_for_client_list(screen, c) == True) { + client_list[i] = c->window; + i--; + if (i < 0) break; + } + } + + stacked_client_list = malloc(sizeof(Window) * no_clients); + i = 0; + XQueryTree(dpy, screen->root, &dw1, &dw2, &wins, &nwins); + for (win = 0; win < nwins; win++) { + c = Client_Get(wins[win]); + if (!c) continue; + if (valid_for_client_list(screen, c) == True) { + stacked_client_list[i] = c->window; + i++; + if (i >= no_clients) break; + } + } + if ( nwins > 0 ) XFree(wins); + + } + XChangeProperty(dpy, screen->root, + ewmh_atom[_NET_CLIENT_LIST], + XA_WINDOW, 32, PropModeReplace, + (unsigned char*)client_list, no_clients); + XChangeProperty(dpy, screen->root, + ewmh_atom[_NET_CLIENT_LIST_STACKING], + XA_WINDOW, 32, PropModeReplace, + (unsigned char*)stacked_client_list, no_clients); + if (no_clients > 0 ) { + free(client_list); + free(stacked_client_list); + } + screen->ewmh_set_client_list = False; } diff --git a/lwm b/lwm index 12e9c03..d0ecf68 100755 Binary files a/lwm and b/lwm differ diff --git a/lwm.c b/lwm.c index 662dfcd..64359ec 100644 --- a/lwm.c +++ b/lwm.c @@ -36,22 +36,19 @@ #include "lwm.h" -Mode mode; /* The window manager's mode. (See "lwm.h".) */ -int start_x; /* The X position where the mode changed. */ -int start_y; /* The Y position where the mode changed. */ - -Display * dpy; /* The connection to the X server. */ -int screen_count; /* The number of screens. */ -ScreenInfo * screens; /* Information about these screens. */ +char *font_name = DEFAULT_TITLE_FONT; /* User's choice of titlebar font. */ +int border = DEFAULT_BORDER; /* User's choice of border size. */ +Mode mode; /* The window manager's mode. (See "lwm.h".) */ +int start_x; /* The X position where the mode changed. */ +int start_y; /* The Y position where the mode changed. */ + +Display * dpy; /* The connection to the X server. */ +int screen_count; /* The number of screens. */ +ScreenInfo * screens; /* Information about these screens. */ ScreenInfo * current_screen; -XFontSet font_set = NULL; /* Font set for title var */ +XFontSet font_set = NULL; /* Font set for title var */ XFontSetExtents *font_set_ext = NULL; -XFontSet popup_font_set = NULL; /* Font set for popups */ -XFontSetExtents *popup_font_set_ext = NULL; - -Bool shape; /* Does server have Shape Window extension? */ -int shape_event; /* ShapeEvent event type. */ /* Atoms we're interested in. See the ICCCM for more information. */ Atom wm_state; @@ -62,422 +59,235 @@ Atom wm_take_focus; Atom wm_colormaps; Atom compound_text; -/** Netscape uses this to give information about the URL it's displaying. */ -Atom _mozilla_url; - -/* - * if we're really short of a clue we might look at motif hints, and - * we're not going to link with motif, so we'll have to do it by hand - */ -Atom motif_wm_hints; - char *argv0; static void initScreens(void); static void initScreen(int); -char *font_name; /* User's choice of titlebar font. */ -char *popup_font_name; /* User's choice of menu font. */ -char *btn1_command; /* User's choice of button 1 command. */ -char *btn2_command; /* User's choice of button 2 command. */ -int border; /* User's choice of border size. */ -FocusMode focus_mode; /* User's choice of focus mode (default enter) */ - -void getMousePosition(int * x, int * y) { - Window root, child; - int t1, t2; - unsigned int b; - - /* It doesn't matter which root window we give this call. */ - XQueryPointer(dpy, screens[0].root, &root, &child, x, y, &t1, &t2, &b); - current_screen = getScreenFromRoot(root); -} - -void parseResources(void) { - /* Set our fall-back defaults. */ - font_name = DEFAULT_TITLE_FONT; - popup_font_name = DEFAULT_POPUP_FONT; - border = DEFAULT_BORDER; - btn1_command = 0; - btn2_command = DEFAULT_TERMINAL; - focus_mode = focus_enter; -} - -int main(int argc, char *argv[]) { - XEvent ev; - struct sigaction sa; - int dpy_fd, max_fd; - - argv0 = argv[0]; - - mode = wm_initialising; - - /* Open a connection to the X server. */ - dpy = XOpenDisplay(NULL); - if (dpy == 0) - panic("can't open display."); - - parseResources(); - - /* Set up an error handler. */ - XSetErrorHandler(errorHandler); - - /* Set up signal handlers. */ - signal(SIGTERM, Terminate); - signal(SIGINT, Terminate); - signal(SIGHUP, Terminate); - - /* Ignore SIGCHLD. */ - sa.sa_handler = SIG_IGN; -#ifdef SA_NOCLDWAIT - sa.sa_flags = SA_NOCLDWAIT; -#else - sa.sa_flags = 0; -#endif - sigemptyset(&sa.sa_mask); - sigaction(SIGCHLD, &sa, 0); - - /* Internalize useful atoms. */ - wm_state = XInternAtom(dpy, "WM_STATE", False); - wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False); - wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False); - wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False); - wm_take_focus = XInternAtom(dpy, "WM_TAKE_FOCUS", False); - wm_colormaps = XInternAtom(dpy, "WM_COLORMAP_WINDOWS", False); - compound_text = XInternAtom(dpy, "COMPOUND_TEXT", False); - - _mozilla_url = XInternAtom(dpy, "_MOZILLA_URL", False); - - motif_wm_hints = XInternAtom(dpy, "_MOTIF_WM_HINTS", False); - - ewmh_init(); - - /* - * Get fonts for our titlebar and our popup window. We try to - * get Lucida, but if we can't we make do with fixed because everyone - * has that. - */ - { - /* FIXME: do these need to be freed? */ - char **missing; - char *def; - int missing_count; - - font_set = XCreateFontSet(dpy, font_name, - &missing, &missing_count, &def); - if (font_set == NULL) - font_set = XCreateFontSet(dpy, "fixed", - &missing, &missing_count, &def); - if (font_set == NULL) - panic("unable to create font set for title font"); - if (missing_count > 0) - fprintf(stderr,"%s: warning: missing %d charset" - "%s for title font\n", argv0, missing_count, - (missing_count == 1)?"":"s"); - font_set_ext = XExtentsOfFontSet(font_set); - - popup_font_set = XCreateFontSet(dpy, popup_font_name, - &missing, &missing_count, &def); - if (popup_font_set == NULL) - popup_font_set = XCreateFontSet(dpy, "fixed", - &missing, &missing_count, &def); - if (popup_font_set == NULL) - panic("unable to create font set for popup font"); - if (missing_count > 0) - fprintf(stderr,"%s: warning: missing %d charset" - "%s for popup font\n", argv0, missing_count, - (missing_count == 1)?"":"s"); - popup_font_set_ext = XExtentsOfFontSet(popup_font_set); - } - - initScreens(); - ewmh_init_screens(); - - /* See if the server has the Shape Window extension. */ - shape = serverSupportsShapes(); - - /* - * Initialisation is finished, but we start off not interacting with the - * user. - */ - mode = wm_idle; - - /* - * The main event loop. - */ - dpy_fd = ConnectionNumber(dpy); - max_fd = dpy_fd + 1; - for (;;) { - fd_set readfds; - - FD_ZERO(&readfds); - FD_SET(dpy_fd, &readfds); - if (select(max_fd, &readfds, NULL, NULL, NULL) > -1) { - if (FD_ISSET(dpy_fd, &readfds)) { - while (XPending(dpy)) { - XNextEvent(dpy, &ev); - dispatch(&ev); - } - } - } - } +/*ARGSUSED*/ +extern int +main(int argc, char *argv[]) { + XEvent ev; + argv0 = argv[0]; + mode = wm_initialising; + + /* Open a connection to the X server. */ + dpy = XOpenDisplay(NULL); + if (dpy == 0) + panic("can't open display."); + + /* Set up an error handler. */ + XSetErrorHandler(errorHandler); + + /* Internalize useful atoms. */ + wm_state = XInternAtom(dpy, "WM_STATE", False); + wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False); + wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False); + wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + wm_take_focus = XInternAtom(dpy, "WM_TAKE_FOCUS", False); + wm_colormaps = XInternAtom(dpy, "WM_COLORMAP_WINDOWS", False); + compound_text = XInternAtom(dpy, "COMPOUND_TEXT", False); + ewmh_init(); + + /* + * Get fonts for our titlebar and our popup window. We try to + * get Lucida, but if we can't we make do with fixed because everyone + * has that. + */ + { + /* FIXME: do these need to be freed? */ + char **missing; + char *def; + int missing_count; + + font_set = XCreateFontSet(dpy, font_name, + &missing, &missing_count, &def); + if (font_set == NULL) + font_set = XCreateFontSet(dpy, "fixed", + &missing, &missing_count, &def); + if (font_set == NULL) + panic("unable to create font set for title font"); + if (missing_count > 0) + fprintf(stderr,"%s: warning: missing %d charset" + "%s for title font\n", argv0, missing_count, + (missing_count == 1)?"":"s"); + font_set_ext = XExtentsOfFontSet(font_set); + } + + initScreens(); + ewmh_init_screens(); + + /* + * Initialisation is finished, but we start off not interacting with the + * user. + */ + mode = wm_idle; + + /* + * The main event loop. + */ + for (;;) + { + XNextEvent(dpy, &ev); + dispatch(&ev); + } } void sendConfigureNotify(Client *c) { - XConfigureEvent ce; - - ce.type = ConfigureNotify; - ce.event = c->window; - ce.window = c->window; - if (c->framed == True) { - ce.x = c->size.x + border; - ce.y = c->size.y + border; - ce.width = c->size.width - 2 * border; - ce.height = c->size.height - 2 * border; - ce.border_width = c->border; - } else { - ce.x = c->size.x; - ce.y = c->size.y; - ce.width = c->size.width; - ce.height = c->size.height; - ce.border_width = c->border; - } - ce.above = None; - ce.override_redirect = 0; - XSendEvent(dpy, c->window, False, StructureNotifyMask, (XEvent *) &ce); + XConfigureEvent ce; + ce.type = ConfigureNotify; + ce.event = c->window; + ce.window = c->window; + if (c->framed == True) { + ce.x = c->size.x + border; + ce.y = c->size.y + border; + ce.width = c->size.width - 2 * border; + ce.height = c->size.height - 2 * border; + ce.border_width = c->border; + } else { + ce.x = c->size.x; + ce.y = c->size.y; + ce.width = c->size.width; + ce.height = c->size.height; + ce.border_width = c->border; + } + ce.above = None; + ce.override_redirect = 0; + XSendEvent(dpy, c->window, False, StructureNotifyMask, (XEvent *) &ce); } extern void scanWindowTree(int screen) { - unsigned int i; - unsigned int nwins; - Client * c; - Window dw1; - Window dw2; - Window * wins; - XWindowAttributes attr; - - XQueryTree(dpy, screens[screen].root, &dw1, &dw2, &wins, &nwins); - for (i = 0; i < nwins; i++) { - XGetWindowAttributes(dpy, wins[i], &attr); - if (attr.override_redirect /*|| isShaped(wins[i])*/ || wins[i] == screens[screen].popup) - continue; - c = Client_Add(wins[i], screens[screen].root); - if (c != 0 && c->window == wins[i]) { - c->screen = &screens[screen]; - c->size.x = attr.x; - c->size.y = attr.y; -/* we'll leave it until it's managed - if (c->framed == True) { - c->size.x -= border; - c->size.y -= border; - } -*/ - c->size.width = attr.width; - c->size.height = attr.height; -/* we'll leave it until it's managed - if (c->framed == True) { - c->size.width += 2 * border; - c->size.height += 2 * border; - } -*/ - c->border = attr.border_width; - if (attr.map_state == IsViewable) { - c->internal_state = IPendingReparenting; - manage(c, 1); - } - } - } - XFree(wins); -} - -/*ARGSUSED*/ -extern void -shell(ScreenInfo * screen, int button, int x, int y) { - char * command = NULL; - char * sh; - - /* Get the command we're to execute. Give up if there isn't one. */ - if (button == Button1) - command = btn1_command; - if (button == Button2) - command = btn2_command; - if (command == NULL) - return; - - sh = getenv("SHELL"); - if (sh == 0) - sh = "/bin/sh"; - - switch (fork()) { - case 0: /* Child. */ - close(ConnectionNumber(dpy)); - if (screen && screen->display_spec != 0) - putenv(screen->display_spec); - execl(sh, sh, "-c", command, NULL); - fprintf(stderr, "%s: can't exec \"%s -c %s\"\n", argv0, sh, - command); - execlp("xterm", "xterm", NULL); - exit(EXIT_FAILURE); - case -1: /* Error. */ - fprintf(stderr, "%s: couldn't fork\n", argv0); - break; - } + unsigned int i; + unsigned int nwins; + Client * c; + Window dw1; + Window dw2; + Window * wins; + XWindowAttributes attr; + + XQueryTree(dpy, screens[screen].root, &dw1, &dw2, &wins, &nwins); + for (i = 0; i < nwins; i++) { + XGetWindowAttributes(dpy, wins[i], &attr); + if (attr.override_redirect) + continue; + c = Client_Add(wins[i], screens[screen].root); + if (c != 0 && c->window == wins[i]) { + c->screen = &screens[screen]; + c->size.x = attr.x; + c->size.y = attr.y; + c->size.width = attr.width; + c->size.height = attr.height; + c->border = attr.border_width; + if (attr.map_state == IsViewable) { + c->internal_state = IPendingReparenting; + manage(c, 1); + } + } + } + XFree(wins); } extern int titleHeight(void) { - return font_set_ext->max_logical_extent.height; + return font_set_ext->max_logical_extent.height; } extern int ascent(XFontSetExtents *font_set_ext) { - return abs(font_set_ext->max_logical_extent.y); -} - -extern int -popupHeight(void) { - return popup_font_set_ext->max_logical_extent.height; + return abs(font_set_ext->max_logical_extent.y); } extern int titleWidth(XFontSet font_set, Client *c) { - XRectangle ink; - XRectangle logical; - char *name; - int namelen; - - if (c == NULL) return 0; - if (c->menu_name == NULL) { - name = c->name; - namelen = c->namelen; - } else { - name = c->menu_name; - namelen = c->menu_namelen; - } - if (name == NULL) return 0; -#ifdef X_HAVE_UTF8_STRING - if (c->name_utf8 == True) - Xutf8TextExtents(font_set, name, namelen, - &ink, &logical); - else -#endif - XmbTextExtents(font_set, name, namelen, - &ink, &logical); - - return logical.width; -} - -extern int -popupWidth(char *string, int string_length) { - XRectangle ink; - XRectangle logical; - - XmbTextExtents(popup_font_set, string, string_length, - &ink, &logical); - - return logical.width; + XRectangle ink; + XRectangle logical; + char *name; + int namelen; + + if (c == NULL) return 0; + name = c->name; + namelen = c->namelen; + if (name == NULL) return 0; + Xutf8TextExtents(font_set, name, namelen, + &ink, &logical); + + return logical.width; } static void initScreens(void) { - int screen; - - /* Find out how many screens we've got, and allocate space for their info. */ - screen_count = ScreenCount(dpy); - screens = (ScreenInfo *) malloc(screen_count * sizeof(ScreenInfo)); - - /* Go through the screens one-by-one, initialising them. */ - for (screen = 0; screen < screen_count; screen++) { - initialiseCursors(screen); - initScreen(screen); - scanWindowTree(screen); - } + int screen; + + /* Find out how many screens we've got, and allocate space for their info. */ + screen_count = ScreenCount(dpy); + screens = (ScreenInfo *) malloc(screen_count * sizeof(ScreenInfo)); + + /* Go through the screens one-by-one, initialising them. */ + for (screen = 0; screen < screen_count; screen++) { + initialiseCursors(screen); + initScreen(screen); + scanWindowTree(screen); + } } static void initScreen(int screen) { - XGCValues gv; - XSetWindowAttributes attr; - XColor colour, exact; - int len; - char * display_string = DisplayString(dpy); - char * colon = strrchr(display_string, ':'); - char * dot = NULL; - - /* Set the DISPLAY specification. */ - if (colon) { - dot = strrchr(colon, '.'); - len = 9 + strlen(display_string) + ((dot == 0) ? 2 : 0) + 10; - screens[screen].display_spec = (char *) malloc(len); - sprintf(screens[screen].display_spec, "DISPLAY=%s", display_string); - if (dot == 0) dot = screens[screen].display_spec + len - 3; - else dot = strrchr(screens[screen].display_spec, '.'); - sprintf(dot, ".%i", screen); - } else { - screens[screen].display_spec = 0; - } - - /* Find the root window. */ - screens[screen].root = RootWindow(dpy, screen); - screens[screen].display_width = DisplayWidth(dpy, screen); - screens[screen].display_height = DisplayHeight(dpy, screen); - screens[screen].strut.left = 0; - screens[screen].strut.right = 0; - screens[screen].strut.top = 0; - screens[screen].strut.bottom = 0; - - /* Get the pixel values of the only two colours we use. */ - screens[screen].black = BlackPixel(dpy, screen); - screens[screen].white = WhitePixel(dpy, screen); - XAllocNamedColor(dpy, DefaultColormap(dpy, screen), "DimGray", &colour, &exact); - screens[screen].gray = colour.pixel; - - /* Set up root (frame) GC's. */ - gv.foreground = screens[screen].black ^ screens[screen].white; - gv.background = screens[screen].white; - gv.function = GXxor; - gv.line_width = 1; - gv.subwindow_mode = IncludeInferiors; - screens[screen].gc_thin = XCreateGC(dpy, screens[screen].root, - GCForeground | GCBackground | GCFunction | - GCLineWidth | GCSubwindowMode, &gv); - - gv.line_width = 2; - screens[screen].gc = XCreateGC(dpy, screens[screen].root, - GCForeground | GCBackground | GCFunction | - GCLineWidth | GCSubwindowMode, &gv); - - /* Create a window for our popup. */ - screens[screen].popup = XCreateSimpleWindow(dpy, screens[screen].root, - 0, 0, 1, 1, 1, screens[screen].black, screens[screen].white); - attr.event_mask = ButtonMask | ButtonMotionMask | ExposureMask; - XChangeWindowAttributes(dpy, screens[screen].popup, CWEventMask, &attr); - - /* Create menu GC. */ - gv.line_width = 1; - screens[screen].menu_gc = XCreateGC(dpy, screens[screen].popup, - GCForeground | GCBackground | GCFunction | - GCLineWidth | GCSubwindowMode, &gv); - - /* Create size indicator GC. */ - gv.foreground = screens[screen].black; - gv.function = GXcopy; - screens[screen].size_gc = XCreateGC(dpy, screens[screen].popup, - GCForeground | GCBackground | GCFunction | - GCLineWidth | GCSubwindowMode, &gv); - - /* Announce our interest in the root window. */ - attr.cursor = screens[screen].root_cursor; - attr.event_mask = SubstructureRedirectMask | SubstructureNotifyMask | - ColormapChangeMask | ButtonPressMask | PropertyChangeMask | - EnterWindowMask; - XChangeWindowAttributes(dpy, screens[screen].root, CWCursor | - CWEventMask, &attr); - - /* Make sure all our communication to the server got through. */ - XSync(dpy, False); + XGCValues gv; + XSetWindowAttributes attr; + XColor colour, exact; + int len; + char * display_string = DisplayString(dpy); + char * colon = strrchr(display_string, ':'); + char * dot = NULL; + + /* Set the DISPLAY specification. */ + if (colon) { + dot = strrchr(colon, '.'); + len = 9 + strlen(display_string) + ((dot == 0) ? 2 : 0) + 10; + screens[screen].display_spec = (char *) malloc(len); + sprintf(screens[screen].display_spec, "DISPLAY=%s", display_string); + if (dot == 0) dot = screens[screen].display_spec + len - 3; + else dot = strrchr(screens[screen].display_spec, '.'); + sprintf(dot, ".%i", screen); + } else { + screens[screen].display_spec = 0; + } + + /* Find the root window. */ + screens[screen].root = RootWindow(dpy, screen); + screens[screen].display_width = DisplayWidth(dpy, screen); + screens[screen].display_height = DisplayHeight(dpy, screen); + + /* Get the pixel values of the only two colours we use. */ + screens[screen].black = BlackPixel(dpy, screen); + screens[screen].white = WhitePixel(dpy, screen); + XAllocNamedColor(dpy, DefaultColormap(dpy, screen), "DimGray", &colour, &exact); + screens[screen].gray = colour.pixel; + + /* Set up root (frame) GC's. */ + gv.foreground = screens[screen].black ^ screens[screen].white; + gv.background = screens[screen].white; + gv.function = GXxor; + gv.line_width = 1; + gv.subwindow_mode = IncludeInferiors; + + gv.line_width = 2; + screens[screen].gc = XCreateGC(dpy, screens[screen].root, + GCForeground | GCBackground | GCFunction | + GCLineWidth | GCSubwindowMode, &gv); + + /* Announce our interest in the root window. */ + attr.cursor = screens[screen].root_cursor; + attr.event_mask = SubstructureRedirectMask | SubstructureNotifyMask | + ColormapChangeMask | ButtonPressMask | PropertyChangeMask | + EnterWindowMask; + XChangeWindowAttributes(dpy, screens[screen].root, CWCursor | + CWEventMask, &attr); + + /* Make sure all our communication to the server got through. */ + XSync(dpy, False); } /** @@ -485,11 +295,11 @@ Find the screen for which root is the root window. */ ScreenInfo * getScreenFromRoot(Window root) { - int screen; + int screen; - for (screen = 0; screen < screen_count; screen++) - if (screens[screen].root == root) - return &screens[screen]; + for (screen = 0; screen < screen_count; screen++) + if (screens[screen].root == root) + return &screens[screen]; - return 0; + return 0; } diff --git a/lwm.h b/lwm.h index 136350b..30de4e4 100644 --- a/lwm.h +++ b/lwm.h @@ -20,15 +20,8 @@ /* --- Administrator-configurable defaults. --- */ #define DEFAULT_TITLE_FONT "-*-lucida-bold-r-normal-sans-14-*-*-*-p-*-iso10646-1" -#define DEFAULT_POPUP_FONT "-*-lucida-medium-r-normal-sans-12-*-*-*-p-*-iso10646-1" -#define DEFAULT_TERMINAL "xterm" -#define DEFAULT_BORDER 6 - -#define HIDE_BUTTON Button3 -#define MOVE_BUTTON Button2 -#define RESHAPE_BUTTON Button1 - -#define EDGE_RESIST 32 +#define DEFAULT_TERMINAL "xterm" +#define DEFAULT_BORDER 3 /* --- End of administrator-configurable defaults. --- */ @@ -45,28 +38,15 @@ * initialising. */ typedef enum { - wm_initialising, - wm_idle, - wm_reshaping, - wm_menu_up, - wm_closing_window, - wm_hiding_window + wm_initialising, + wm_idle, + wm_reshaping, } Mode; /** Window internal state. Yuck. */ typedef enum { - IPendingReparenting, INormal -} IState ; - - -/** -* Focus mode, may me (and defaults to) enter where entering a window gives -* that window input focus, or click where a window must be explicitly clicked -* to give it the focus. -*/ -typedef enum { - focus_enter, focus_click -} FocusMode; + IPendingReparenting, INormal +} IState; /** * Window edge, used in resizing. The `edge' ENone is used to signify a @@ -74,20 +54,20 @@ typedef enum { * this isn't a special case to be treated separately. */ typedef enum { - ETopLeft, ETop, ETopRight, - ERight, ENone, ELeft, - EBottomLeft, EBottom, EBottomRight, - E_LAST + ETopLeft, ETop, ETopRight, + ERight, ENone, ELeft, + EBottomLeft, EBottom, EBottomRight, + E_LAST } Edge ; /** * EWMH direction for _NET_WM_MOVERESIZE */ typedef enum { - DSizeTopLeft, DSizeTop, DSizeTopRight, - DSizeRight, DSizeBottomRight, DSizeBottom, - DSizeBottomLeft, DSizeLeft, DMove, - DSizeKeyboard, DMoveKeyboard + DSizeTopLeft, DSizeTop, DSizeTopRight, + DSizeRight, DSizeBottomRight, DSizeBottom, + DSizeBottomLeft, DSizeLeft, DMove, + DSizeKeyboard, DMoveKeyboard } EWMHDirection; /** @@ -96,119 +76,57 @@ typedef enum { * hints should be used instead. */ typedef enum { - WTypeDesktop, WTypeDock, WTypeToolbar, - WTypeMenu, WTypeUtility, WTypeSplash, - WTypeDialog, WTypeNormal, WTypeNone + WTypeDesktop, WTypeDock, WTypeToolbar, + WTypeMenu, WTypeUtility, WTypeSplash, + WTypeDialog, WTypeNormal, WTypeNone } EWMHWindowType; -/** -* EWMH window state, See section 5.7 of the EWMH specification (1.2). -* lwm does not support all states. _NET_WM_STATE_HIDDEN is taken from -* Client.hidden. -*/ -typedef struct { - Bool skip_taskbar; - Bool skip_pager; - Bool fullscreen; - Bool above; - Bool below; -} EWMHWindowState; - -/** -* EWMH "strut", or area on each edge of the screen reserved for docking -* bars/panels. -*/ -typedef struct { - unsigned int left; - unsigned int right; - unsigned int top; - unsigned int bottom; -} EWMHStrut; - /** * Screen information. */ typedef struct ScreenInfo ScreenInfo; struct ScreenInfo { - Window root; - Window popup; - Window ewmh_compat; - - int display_width; /* The width of the screen. */ - int display_height; /* The height of the screen. */ - EWMHStrut strut; /* reserved areas */ - - GC gc; /* The default GC. */ - GC gc_thin; /* The default GC but with thinner lines. */ - GC menu_gc; /* The GC for the popup window (menu). */ - GC size_gc; /* The GC for the popup window (sizing). */ - - unsigned long black; /* Black pixel value. */ - unsigned long white; /* White pixel value. */ - unsigned long gray; /* Gray pixel value. */ - - Cursor root_cursor; - Cursor box_cursor; - - Cursor cursor_map[E_LAST]; - - Bool ewmh_set_client_list; /* hack to prevent recursion */ - - char * display_spec; + Window root; + Window ewmh_compat; + int display_width; /* The width of the screen. */ + int display_height; /* The height of the screen. */ + GC gc; /* The default GC. */ + unsigned long black; /* Black pixel value. */ + unsigned long white; /* White pixel value. */ + unsigned long gray; /* Gray pixel value. */ + + Cursor root_cursor; + Cursor box_cursor; + Cursor cursor_map[E_LAST]; + Bool ewmh_set_client_list; /* hack to prevent recursion */ + char * display_spec; }; -typedef struct Client Client; -struct Client { - Window window; /* Client's window. */ - Window parent; /* Window manager frame. */ - Window trans; /* Window that client is a transient for. */ - - Bool framed; /* True is lwm is maintaining a frame */ - - Client * next; /* Next window in client list. */ - - int border; /* Client's original border width. */ - - XSizeHints size; /* Client's current geometry information. */ - XSizeHints return_size; /* Client's old geometry information. */ - int state; /* Window state. See ICCCM and */ - - Bool hidden; /* True if this client is hidden. */ - IState internal_state; - int proto; - - int accepts_focus; /* Does this window want keyboard events? */ - - char * name; /* Name used for title in frame. */ - int namelen; - char * menu_name; /* Name used in root popup */ - int menu_namelen; - Bool name_utf8; - - ScreenInfo * screen; - - Edge cursor; /* indicates which cursor is being used for parent window */ - - EWMHWindowType wtype; - EWMHWindowState wstate; - EWMHStrut strut; /* reserved areas */ - - /* Colourmap scum. */ - Colormap cmap; - int ncmapwins; - Window * cmapwins; - Colormap * wmcmaps; -}; - - -/* - * c->proto is a bitarray of these - */ +/* Client flags for EWMH protocols and window behavior */ enum { - Pdelete = 1, - Ptakefocus = 2 + F_ACCEPT_FOCUS = (1 << 0), + F_EWMH_DELETE = (1 << 1), + F_EWMH_TAKE_FOCUS = (1 << 2), }; +typedef struct Client { + strcut Client* next; /* Next window in client list. */ + Window window; /* Client's window. */ + Window parent; /* Window manager frame. */ + Window trans; /* Window that client is a transient for. */ + Bool framed; /* True is lwm is maintaining a frame */ + int border; /* Client's original border width. */ + XSizeHints size; /* Client's current geometry information. */ + int state; /* Window state. See ICCCM and */ + int flags; /* Flags governing client behavior */ + char * name; /* Name used for title in frame. */ + int namelen; /* Length of client name */ + Edge cursor; /* indicates which cursor is being used for parent window */ + IState internal_state; + ScreenInfo * screen; + EWMHWindowType wtype; +} Client; + /* * This should really have been in X.h --- if you select both ButtonPress * and ButtonRelease events, the server makes an automatic grab on the @@ -216,7 +134,9 @@ enum { */ #define ButtonMask (ButtonPressMask | ButtonReleaseMask) -/* lwm.c */ +/* lwm.c */ +extern char *font_name; +extern int border; extern Mode mode; extern int start_x; extern int start_y; @@ -226,39 +146,29 @@ extern ScreenInfo * screens; extern ScreenInfo * current_screen; extern XFontSet font_set; extern XFontSetExtents *font_set_ext; -extern XFontSet popup_font_set; -extern XFontSetExtents *popup_font_set_ext; -extern Atom _mozilla_url; -extern Atom motif_wm_hints; extern Atom wm_state; extern Atom wm_change_state; extern Atom wm_protocols; extern Atom wm_delete; extern Atom wm_take_focus; -extern Atom wm_colormaps; extern Atom compound_text; -extern Bool shape; -extern int shape_event; extern char *argv0; -extern void shell(ScreenInfo *, int, int, int); extern void sendConfigureNotify(Client *); extern int titleHeight(void); extern int titleWidth(XFontSet font_set, Client *c); -extern int popupHeight(void); -extern int popupWidth(char *string, int string_length); extern int ascent(XFontSetExtents *font_set_ext); extern ScreenInfo * getScreenFromRoot(Window); extern void scanWindowTree(int); -/* client.c */ -extern Client *client_head(void); +/* client.c */ extern Edge interacting_edge; +extern Client *current; +extern Client *Client_List(void); extern Client *Client_Get(Window); extern Client *Client_Add(Window, Window); extern void Client_MakeSane(Client *, Edge, int *, int *, int *, int *); -extern void Client_DrawBorder(Client *, int); -extern void setactive(Client *, int, long); -extern void size_expose(void); +extern void Client_DrawFrame(Client *, int); +extern void Client_SetActive(Client *, int, long); extern void Client_ReshapeEdge(Client *, Edge); extern void Client_Move(Client*); extern void Client_SetState(Client *, int); @@ -266,82 +176,40 @@ extern void Client_Raise(Client *); extern void Client_Lower(Client *); extern void Client_Close(Client *); extern void Client_Remove(Client *); -extern void Client_FreeAll(void); -extern void Client_ColourMap(XEvent*); -extern void Client_EnterFullScreen(Client *c); -extern void Client_ExitFullScreen(Client *c); extern void Client_Focus(Client *c, Time time); extern void Client_ResetAllCursors(void); -extern void Client_Name(Client *c, const char *name, Bool is_utf8); -extern int hidden(Client *); -extern int withdrawn(Client *); -extern int normal(Client *); -extern void update_client_list(ScreenInfo *screen); -extern Client *current; +extern void Client_Name(Client *c, const char *name); +extern int Client_IsState(Client*, int); +extern int Client_HasFlags(Client*, int); -/* cursor.c */ +/* cursor.c */ extern Cursor getEdgeCursor(Edge edge); extern void initialiseCursors(int); -/* disp.c */ +/* disp.c */ extern void dispatch(XEvent *); -extern void reshaping_motionnotify(XEvent *); -/* error.c */ +/* error.c */ extern int ignore_badwindow; extern int errorHandler(Display *, XErrorEvent *); extern void panic(char*); -/* manage.c */ +/* manage.c */ extern void getWindowName(Client *); extern void getNormalHints(Client *); -extern Bool motifWouldDecorate(Client *); extern void manage(Client *, int); extern void withdraw(Client *); -extern void cmapfocus(Client *); -extern void getColourmaps(Client *); extern void getTransientFor(Client *); -extern void Terminate(int); -/* mouse.c */ +/* mouse.c */ extern void getMousePosition(int *, int *); -extern void hide(Client *); -extern void unhidec(Client *, int); -extern int menu_whichitem(int, int); -extern void menuhit(XButtonEvent *); -extern void unhide(int, int); -extern void menu_expose(void); -extern void menu_motionnotify(XEvent *); -extern void menu_buttonrelease(XEvent *); - -/* shape.c */ -extern int shapeEvent(XEvent *); -extern int serverSupportsShapes(void); -extern int isShaped(Window); -extern void setShape(Client *); - -/* resource.c */ -extern char *font_name; -extern char *popup_font_name; -extern char *btn1_command; -extern char *btn2_command; -extern int border; -extern FocusMode focus_mode; -extern char * sdup(char *); -extern void parseResources(void); -/* ewmh.c */ +/* ewmh.c */ extern Atom ewmh_atom[]; extern void ewmh_init(void); extern void ewmh_init_screens(void); extern EWMHWindowType ewmh_get_window_type(Window w); extern Bool ewmh_get_window_name(Client *c); extern Bool ewmh_hasframe(Client *c); -extern void ewmh_set_state(Client *c); -extern void ewmh_get_state(Client *c); -extern void ewmh_change_state(Client *c, unsigned long action, - unsigned long atom); extern void ewmh_set_allowed(Client *c); extern void ewmh_set_client_list(ScreenInfo *screen); -extern void ewmh_get_strut(Client *c); -extern void ewmh_set_strut(ScreenInfo *screen); diff --git a/lwm.man b/lwm.man deleted file mode 100644 index a527498..0000000 --- a/lwm.man +++ /dev/null @@ -1,96 +0,0 @@ -.\" lwm, a window manager for X11 -.\" Copyright (C) 1997-2016 Elliott Hughes, James Carter -.\" -.\" 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 (at your option) 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. -.\" -.TH LWM 1 -.SH NAME -lwm \- Lightweight Window Manager for the X Window System -.SH SYNTAX -\fBlwm \fP[ \fB\-s\fP \fIsession-id\fP ] -.SH DESCRIPTION -\fILwm\fP is a window manager for the X Window System. It provides enough -features to allow the user to manage their windows, and no more. -.PP -Windows are surrounded by a frame with a -titlebar at the top next to a small box. The frame is a grey colour for -all windows except that which has the input focus, where it is black. -.PP -In the default configuration, \fIlwm\fP uses the enter-to-focus scheme, where -moving the pointer into a window gives that window the input focus. -\fILwm\fP may also be configured to use the click-to-focus scheme, where a -window must be clicked on (with any button) to receive the input focus. Clicking -on a window in this mode causes the window to be raised. Note that a click -used to focus a window is always swallowed by \fIlwm\fP, so clicking a -button in a new window requires two clicks. -.PP -A button 1 click on a window frame brings that window to the top. Dragging -button 1 on the frame of a resizable window repositions that edge of -the window. If a corner rather than an edge is dragged, then both edges -forming the corner are repositioned. While you're reshaping a window, -a little window pops up to show you the window's current size. -.PP -In the default configuration, button 1 on the root window does nothing. -.PP -Button 2 is used to drag a window by its frame, repositioning the window -but maintaining its position in the window stack. -.PP -In the default configuration, button 2 on the root window brings up a -new shell. -.PP -A button 3 click on a window frame hides that window. Pressing -button 3 on the root window brings up a menu of all the hidden windows. -Releasing the button while over an item will unhide the named window. -.PP -A button 3 click in the frame while Shift is held down pushes the window -to the back, under any other windows. (Users with 4-button mice are -encouraged to use their fourth button for this function.) -.PP -A click with any button inside the little white box in a window's frame -can be used to close the window. -.SH OPTIONS -\fILwm\fP accepts the following command line options: -.PP -.TP 8 -.B \-s -specifies a client ID for the X Session Management system, and is used -exclusively by session managers. -.SH RESOURCES -\fILwm\fP understands the following X resources: -.TP 12 -.B titlefont -font used in window titles -.TP 12 -.B popupFont -font used in popup window (menu/size indicator) -.TP 12 -.B border -width in pixels of window borders -.TP 12 -.B button1 -program spawned when button 1 is clicked on the root window -.TP 12 -.B button2 -program spawned when button 2 is clicked on the root window -.TP 12 -.B focus -focus mode, one of "enter" for enter-to-focus (or sloppy focus), or -"click" for click-to-focus -.SH "SEE ALSO" -.PP -X(7) -.SH AUTHORS -Elliott Hughes , -James Carter diff --git a/manage.c b/manage.c index 9f8e4f9..26ba3b5 100644 --- a/manage.c +++ b/manage.c @@ -26,20 +26,6 @@ #include #include -/* These are Motif definitions from Xm/MwmUtil.h, but Motif isn't available - everywhere. */ -#define MWM_HINTS_FUNCTIONS (1L << 0) -#define MWM_HINTS_DECORATIONS (1L << 1) -#define MWM_HINTS_INPUT_MODE (1L << 2) -#define MWM_HINTS_STATUS (1L << 3) -#define MWM_DECOR_ALL (1L << 0) -#define MWM_DECOR_BORDER (1L << 1) -#define MWM_DECOR_RESIZEH (1L << 2) -#define MWM_DECOR_TITLE (1L << 3) -#define MWM_DECOR_MENU (1L << 4) -#define MWM_DECOR_MINIMIZE (1L << 5) -#define MWM_DECOR_MAXIMIZE (1L << 6) - #include "lwm.h" static int getProperty(Window, Atom, Atom, long, unsigned char **); @@ -50,560 +36,372 @@ static void applyGravity(Client *); void manage(Client * c, int mapped) { - int state; - XWMHints * hints; - XWindowAttributes current_attr; - XSetWindowAttributes attr; - - /* For WM_PROTOCOLS handling. */ - Atom * protocols; - int n; - int p; - - /* Where auto-placement is going to put the next window. */ - static int auto_x = 100; - static int auto_y = 100; - - /* get the EWMH window type, as this might overrule some hints */ - c->wtype = ewmh_get_window_type(c->window); - /* get in the initial EWMH state */ - ewmh_get_state(c); - /* set EWMH allowable actions, now we intend to manage this window */ - ewmh_set_allowed(c); - /* is this window to have a frame? */ - if (c->wtype == WTypeNone) { - /* this breaks the ewmh spec (section 5.6) because in the - * absence of a _NET_WM_WINDOW_TYPE, _WM_WINDOW_TYPE_NORMAL - * must be taken. bummer. - */ - c->framed = motifWouldDecorate(c); - } else { - c->framed = ewmh_hasframe(c); - } - if (isShaped(c->window)) c->framed = False; - - /* get the EWMH strut - if there is one */ - ewmh_get_strut(c); - - /* - * Get the hints, window name, and normal hints (see ICCCM - * section 4.1.2.3). - */ - hints = XGetWMHints(dpy, c->window); - - getWindowName(c); - getNormalHints(c); - - /* - * Get the colourmaps associated with this window. Get the window - * attribute colourmap first, then look to see if the - * WM_COLORMAP_WINDOWS property has been used to specify - * windows needing colourmaps that differ from the top-level - * colourmap. (See ICCCM section 4.1.8.) - */ - XGetWindowAttributes(dpy, c->window, ¤t_attr); - c->cmap = current_attr.colormap; - - getColourmaps(c); - - /* - * Scan the list of atoms on WM_PROTOCOLS to see which of the - * protocols that we understand the client is prepared to - * participate in. (See ICCCM section 4.1.2.7.) - */ - if (XGetWMProtocols(dpy, c->window, &protocols, &n) != 0) { - for (p = 0; p < n; p++) { - if (protocols[p] == wm_delete) { - c->proto |= Pdelete; - } else if (protocols[p] == wm_take_focus) { - c->proto |= Ptakefocus; - } - } - - XFree(protocols); - } - - /* Get the WM_TRANSIENT_FOR property (see ICCCM section 4.1.2.6). */ - getTransientFor(c); - - /* Work out details for the Client structure from the hints. */ - if (hints && (hints->flags & InputHint)) - c->accepts_focus = hints->input; - if (c->proto | Ptakefocus) - /* WM_TAKE_FOCUS overrides normal hints */ - c->accepts_focus = True; - - if (!getWindowState(c->window, &state)) - state = hints ? hints->initial_state : NormalState; - - /* - * Sort out the window's position. - */ - { - Window root_window; - int x, y; - unsigned int w, h; - unsigned int border_width, depth; - - XGetGeometry(dpy, c->window, &root_window, &x, &y, &w, &h, - &border_width, &depth); - - /* - * Do the size first. - * - * "The size specifiers refer to the width and height of the - * client excluding borders" -- ICCCM 4.1.2.3. - */ - c->size.width = w; - c->size.height = h; - if (c->framed == True) { - c->size.width += 2 * border; - c->size.height += 2 * border; - } - - /* - * THIS IS A HACK! - * - * OpenGL programs have a habit of appearing smaller than their - * minimum sizes, which they don't like. - */ - if (c->size.width < c->size.min_width) - c->size.width = c->size.min_width; - if (c->size.height < c->size.min_height) - c->size.height = c->size.min_height; - - /* Do the position next. */ - - /* - * If we have a user-specified position for a top-level window, - * or a program-specified position for a dialogue box, we'll - * take it. We'll also just take it during initialisation, - * since the previous manage probably placed its windows - * sensibly. - */ - if (c->trans != None && c->size.flags & PPosition) { - /* It's a "dialogue box". Trust it. */ - c->size.x = x; - c->size.y = y; - } else if ((c->size.flags & USPosition) || - c->framed == False || mode == wm_initialising ) { - /* Use the specified window position. */ - c->size.x = x; - c->size.y = y; - - /* - * We need to be careful of the right-hand edge and - * bottom. We can use the window gravity (if specified) - * to handle this. (See section 4.1.2.3 of the ICCCM.) - */ - applyGravity(c); - } else { - /* No position was specified: use the auto-placement - * heuristics. */ - - /* firstly, make sure auto_x and auto_y are outside - * strut */ - if (auto_x < c->screen->strut.left) - auto_x = c->screen->strut.left; - if (auto_y < c->screen->strut.top) - auto_y = c->screen->strut.top; - - if ((auto_x + c->size.width) > - (c->screen->display_width - - c->screen->strut.right) && - (c->size.width <= - (c->screen->display_width - - c->screen->strut.left - - c->screen->strut.right))) { - /* - * If the window wouldn't fit using normal - * auto-placement but is small enough to fit - * horizontally, then centre the window - * horizontally. - */ - c->size.x = (c->screen->display_width - - c->size.width) / 2; - auto_x = c->screen->strut.left + 20; - } else { - c->size.x = auto_x; - auto_x += 10; - if (auto_x > (c->screen->display_width / 2)) - auto_x = c->screen->strut.left + 20; - } - - if (((auto_y + c->size.height) > - (c->screen->display_height - - c->screen->strut.bottom)) && - (c->size.height <= - (c->screen->display_height - - c->screen->strut.top - - c->screen->strut.bottom))) { - /* - * If the window wouldn't fit using normal - * auto-placement but is small enough to fit - * vertically, then centre the window - * vertically. - */ - c->size.y = (c->screen->display_height - - c->size.height) / 2; - auto_y = c->screen->strut.top + 20; - } else { - c->size.y = auto_y; - auto_y += 10; - if (auto_y > (c->screen->display_height / 2)) - auto_y = c->screen->strut.top + 20; - } - } - } - - if (hints) - XFree(hints); - - /* - * Do all the reparenting and stuff. - */ - - if (c->framed == True) { - c->parent = XCreateSimpleWindow(dpy, c->screen->root, - c->size.x, c->size.y - titleHeight(), - c->size.width, c->size.height + titleHeight(), - 1, c->screen->black, c->screen->white); - - attr.event_mask = ExposureMask | EnterWindowMask | ButtonMask | - SubstructureRedirectMask | SubstructureNotifyMask | - PointerMotionMask; - XChangeWindowAttributes(dpy, c->parent, CWEventMask, &attr); - - XResizeWindow(dpy, c->window, c->size.width - 2 * border, - c->size.height - 2 * border); - } - - /* - * Stupid X11 doesn't let us change border width in the above - * call. It's a window attribute, but it's somehow second-class. - * - * As pointed out by Adrian Colley, we can't change the window - * border width at all for InputOnly windows. - */ - if (current_attr.class != InputOnly) - XSetWindowBorderWidth(dpy, c->window, 0); - - attr.event_mask = ColormapChangeMask | EnterWindowMask | - PropertyChangeMask | FocusChangeMask; - attr.win_gravity = StaticGravity; - attr.do_not_propagate_mask = ButtonMask; - XChangeWindowAttributes(dpy, c->window, - CWEventMask | CWWinGravity | CWDontPropagate, &attr); - - if (c->framed == True) { - XReparentWindow(dpy, c->window, c->parent, - border, border + titleHeight()); - } else { - XReparentWindow(dpy, c->window, c->parent, - c->size.x, c->size.y); - } - - setShape(c); - - XAddToSaveSet(dpy, c->window); - if (state == IconicState) { - } else { - /* Map the new window in the relevant state. */ - c->hidden = False; - XMapWindow(dpy, c->parent); - XMapWindow(dpy, c->window); - setactive(c, (focus_mode == focus_click) ? 1 : 0, 0L); - Client_SetState(c, NormalState); - } - - if (c->wstate.fullscreen == True) Client_EnterFullScreen(c); - - if (current != c) - cmapfocus(current); + int state; + XWMHints * hints; + XWindowAttributes current_attr; + XSetWindowAttributes attr; + + /* For WM_PROTOCOLS handling. */ + Atom * protocols; + int n; + int p; + + /* Where auto-placement is going to put the next window. */ + static int auto_x = 100; + static int auto_y = 100; + + /* get the EWMH window type, as this might overrule some hints */ + c->wtype = ewmh_get_window_type(c->window); + /* set EWMH allowable actions, now we intend to manage this window */ + ewmh_set_allowed(c); + /* is this window to have a frame? */ + c->framed = ewmh_hasframe(c); + + /* + * Get the hints, window name, and normal hints (see ICCCM + * section 4.1.2.3). + */ + hints = XGetWMHints(dpy, c->window); + + getWindowName(c); + getNormalHints(c); + + /* + * Get the colourmaps associated with this window. Get the window + * attribute colourmap first, then look to see if the + * WM_COLORMAP_WINDOWS property has been used to specify + * windows needing colourmaps that differ from the top-level + * colourmap. (See ICCCM section 4.1.8.) + */ + XGetWindowAttributes(dpy, c->window, ¤t_attr); + + /* + * Scan the list of atoms on WM_PROTOCOLS to see which of the + * protocols that we understand the client is prepared to + * participate in. (See ICCCM section 4.1.2.7.) + */ + if (XGetWMProtocols(dpy, c->window, &protocols, &n) != 0) { + for (p = 0; p < n; p++) { + if (protocols[p] == wm_delete) { + c->flags |= F_EWMH_DELETE; + } else if (protocols[p] == wm_take_focus) { + c->flags |= F_EWMH_TAKE_FOCUS; + } + } + XFree(protocols); + } + + /* Get the WM_TRANSIENT_FOR property (see ICCCM section 4.1.2.6). */ + getTransientFor(c); + + /* Work out details for the Client structure from the hints. */ + if (hints && (hints->flags & InputHint)) + c->flags |= F_ACCEPT_FOCUS; + if (Client_HasFlags(c, F_EWMH_TAKE_FOCUS)) + c->flags |= F_ACCEPT_FOCUS; + + if (!getWindowState(c->window, &state)) + state = hints ? hints->initial_state : NormalState; + + /* + * Sort out the window's position. + */ + { + Window root_window; + int x, y; + unsigned int w, h; + unsigned int border_width, depth; + + XGetGeometry(dpy, c->window, &root_window, &x, &y, &w, &h, + &border_width, &depth); + + /* + * Do the size first. + * + * "The size specifiers refer to the width and height of the + * client excluding borders" -- ICCCM 4.1.2.3. + */ + c->size.width = w; + c->size.height = h; + if (c->framed == True) { + c->size.width += 2 * border; + c->size.height += 2 * border; + } + + /* + * THIS IS A HACK! + * + * OpenGL programs have a habit of appearing smaller than their + * minimum sizes, which they don't like. + */ + if (c->size.width < c->size.min_width) + c->size.width = c->size.min_width; + if (c->size.height < c->size.min_height) + c->size.height = c->size.min_height; + + /* Do the position next. */ + + /* + * If we have a user-specified position for a top-level window, + * or a program-specified position for a dialogue box, we'll + * take it. We'll also just take it during initialisation, + * since the previous manage probably placed its windows + * sensibly. + */ + if (c->trans != None && c->size.flags & PPosition) { + /* It's a "dialogue box". Trust it. */ + c->size.x = x; + c->size.y = y; + } else if ((c->size.flags & USPosition) || + c->framed == False || mode == wm_initialising ) { + /* Use the specified window position. */ + c->size.x = x; + c->size.y = y; + + /* + * We need to be careful of the right-hand edge and + * bottom. We can use the window gravity (if specified) + * to handle this. (See section 4.1.2.3 of the ICCCM.) + */ + applyGravity(c); + } + } + + if (hints) + XFree(hints); + + /* + * Do all the reparenting and stuff. + */ + + if (c->framed == True) { + c->parent = XCreateSimpleWindow(dpy, c->screen->root, + c->size.x, c->size.y - titleHeight(), + c->size.width, c->size.height + titleHeight(), + 1, c->screen->black, c->screen->white); + + attr.event_mask = ExposureMask | EnterWindowMask | ButtonMask | + SubstructureRedirectMask | SubstructureNotifyMask | + PointerMotionMask; + XChangeWindowAttributes(dpy, c->parent, CWEventMask, &attr); + + XResizeWindow(dpy, c->window, c->size.width - 2 * border, + c->size.height - 2 * border); + } + + /* + * Stupid X11 doesn't let us change border width in the above + * call. It's a window attribute, but it's somehow second-class. + * + * As pointed out by Adrian Colley, we can't change the window + * border width at all for InputOnly windows. + */ + if (current_attr.class != InputOnly) + XSetWindowBorderWidth(dpy, c->window, 0); + + attr.event_mask = EnterWindowMask | + PropertyChangeMask | FocusChangeMask; + attr.win_gravity = StaticGravity; + attr.do_not_propagate_mask = ButtonMask; + XChangeWindowAttributes(dpy, c->window, + CWEventMask | CWWinGravity | CWDontPropagate, &attr); + + if (c->framed == True) { + XReparentWindow(dpy, c->window, c->parent, + border, border + titleHeight()); + } else { + XReparentWindow(dpy, c->window, c->parent, + c->size.x, c->size.y); + } + + XAddToSaveSet(dpy, c->window); + /* Map the new window in the relevant state. */ + XMapWindow(dpy, c->parent); + XMapWindow(dpy, c->window); + Client_SetActive(c, 0, 0L); + Client_SetState(c, NormalState); } static void applyGravity(Client *c) { - if (c->framed == False) return; /* only required for framed windows*/ - if (c->size.flags & PWinGravity) { - switch (c->size.win_gravity) { - case NorthEastGravity: - c->size.x -= 2 * border; - break; - case SouthWestGravity: - c->size.y -= 2 * border; - break; - case SouthEastGravity: - c->size.x -= 2 * border; - c->size.y -= 2 * border; - break; - } - } + if (c->framed == False) return; /* only required for framed windows*/ + if (c->size.flags & PWinGravity) { + switch (c->size.win_gravity) { + case NorthEastGravity: + c->size.x -= 2 * border; + break; + case SouthWestGravity: + c->size.y -= 2 * border; + break; + case SouthEastGravity: + c->size.x -= 2 * border; + c->size.y -= 2 * border; + break; + } + } } void getTransientFor(Client *c) { - Window trans = None; + Window trans = None; - XGetTransientForHint(dpy, c->window, &trans); - c->trans = trans; + XGetTransientForHint(dpy, c->window, &trans); + c->trans = trans; } void withdraw(Client *c) { - if (c->parent != c->screen->root) { - XUnmapWindow(dpy, c->parent); - XReparentWindow(dpy, c->parent, c->screen->root, c->size.x, c->size.y); - } - - XRemoveFromSaveSet(dpy, c->window); - Client_SetState(c, WithdrawnState); - - /* - * Flush and ignore any errors. X11 sends us an UnmapNotify before it - * sends us a DestroyNotify. That means we can get here without knowing - * whether the relevant window still exists. - */ - ignore_badwindow = 1; - XSync(dpy, False); - ignore_badwindow = 0; -} - -static void -installColourmap(Colormap cmap) { - if (cmap == None) - cmap = DefaultColormap(dpy, DefaultScreen(dpy)); - XInstallColormap(dpy, cmap); -} - -void -cmapfocus(Client * c) { - int i; - int found; - Client *cc; - - if (c == 0) - installColourmap(None); - else if (c->ncmapwins != 0) { - found = 0; - for (i = c->ncmapwins - 1; i >= 0; i--) { - installColourmap(c->wmcmaps[i]); - if (c->cmapwins[i] == c->window) - found++; - } - if (!found) - installColourmap(c->cmap); - } else if (c->trans != None && (cc = Client_Get(c->trans)) != 0 && - cc->ncmapwins != 0) - cmapfocus(cc); - else - installColourmap(c->cmap); -} - -void -getColourmaps(Client *c) { - int n; - int i; - Window *cw; - XWindowAttributes attr; - - if (c == 0) - return; - - n = getProperty(c->window, wm_colormaps, XA_WINDOW, 100L, (unsigned char **) &cw); - if (c->ncmapwins != 0) { - XFree(c->cmapwins); - free(c->wmcmaps); - } - if (n <= 0) { - c->ncmapwins = 0; - return; - } - c->ncmapwins = n; - c->cmapwins = cw; - - c->wmcmaps = (Colormap *) malloc(n * sizeof(Colormap)); - for (i = 0; i < n; i++) { - if (cw[i] == c->window) { - c->wmcmaps[i] = c->cmap; - } else { - XSelectInput(dpy, cw[i], ColormapChangeMask); - XGetWindowAttributes(dpy, cw[i], &attr); - c->wmcmaps[i] = attr.colormap; - } - } -} - -/*ARGSUSED*/ -void -Terminate(int signal) { - /* Set all clients free. */ - Client_FreeAll(); - - /* Give up the input focus and the colourmap. */ - XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); - installColourmap(None); - - XCloseDisplay(dpy); - exit(signal ? EXIT_FAILURE : EXIT_SUCCESS); + if (c->parent != c->screen->root) { + XUnmapWindow(dpy, c->parent); + XReparentWindow(dpy, c->parent, c->screen->root, c->size.x, c->size.y); + } + + XRemoveFromSaveSet(dpy, c->window); + Client_SetState(c, WithdrawnState); + + /* + * Flush and ignore any errors. X11 sends us an UnmapNotify before it + * sends us a DestroyNotify. That means we can get here without knowing + * whether the relevant window still exists. + */ + ignore_badwindow = 1; + XSync(dpy, False); + ignore_badwindow = 0; } - static int getProperty(Window w, Atom a, Atom type, long len, unsigned char **p) { - Atom real_type; - int format; - unsigned long n; - unsigned long extra; - int status; - - /* - * len is in 32-bit multiples. - */ - status = XGetWindowProperty(dpy, w, a, 0L, len, False, type, &real_type, &format, &n, &extra, p); - if (status != Success || *p == 0) - return -1; - if (n == 0) - XFree(*p); - /* - * could check real_type, format, extra here... - */ - return n; + Atom real_type; + int format; + unsigned long n; + unsigned long extra; + int status; + + /* + * len is in 32-bit multiples. + */ + status = XGetWindowProperty(dpy, w, a, 0L, len, False, type, &real_type, &format, &n, &extra, p); + if (status != Success || *p == 0) + return -1; + if (n == 0) + XFree(*p); + /* + * could check real_type, format, extra here... + */ + return n; } void getWindowName(Client *c) { - char * name; - Atom actual_type; - int format; - unsigned long n; - unsigned long extra; - int was_nameless; - - if (c == 0) - return; - - was_nameless = (c->name == 0); - - if (ewmh_get_window_name(c) == False && - XGetWindowProperty(dpy, c->window, _mozilla_url, 0L, 100L, False, AnyPropertyType, &actual_type, &format, &n, &extra, (unsigned char **) &name) == Success && name && *name != '\0' && n != 0) { - Client_Name(c, name, False); - XFree(name); - } else if (XGetWindowProperty(dpy, c->window, XA_WM_NAME, 0L, 100L, False, AnyPropertyType, &actual_type, &format, &n, &extra, (unsigned char **) &name) == Success && name && *name != '\0' && n != 0) { - /* That rather unpleasant condition is necessary because xwsh uses - * COMPOUND_TEXT rather than STRING for its WM_NAME property, - * and anonymous xwsh windows are annoying. - */ - if (actual_type == compound_text && memcmp(name, "\x1b\x28\x42", 3) == 0) { - Client_Name(c, name + 3, False); - } else { - Client_Name(c, name, False); - } - XFree(name); - } - - if (!was_nameless) - Client_DrawBorder(c, c == current); + char * name; + Atom actual_type; + int format; + unsigned long n; + unsigned long extra; + int was_nameless; + + if (c == 0) + return; + + was_nameless = (c->name == 0); + + if (ewmh_get_window_name(c) == False) { + if (XGetWindowProperty(dpy, c->window, XA_WM_NAME, 0L, 100L, False, AnyPropertyType, &actual_type, &format, &n, &extra, (unsigned char **) &name) == Success && name && *name != '\0' && n != 0) { + /* That rather unpleasant condition is necessary because xwsh uses + * COMPOUND_TEXT rather than STRING for its WM_NAME property, + * and anonymous xwsh windows are annoying. + */ + if (actual_type == compound_text && memcmp(name, "\x1b\x28\x42", 3) == 0) { + Client_Name(c, name + 3); + } else { + Client_Name(c, name); + } + XFree(name); + } + } + + if (!was_nameless) + Client_DrawFrame(c, c == current); } void getNormalHints(Client *c) { - int x, y, w, h; - long msize; - - /* We have to be a little careful here. The ICCCM says that the x, y - * and width, height components aren't used. So we use them. That means - * that we need to save and restore them whenever we fill the size - * struct. */ - x = c->size.x; - y = c->size.y; - w = c->size.width; - h = c->size.height; - - /* Do the get. */ - if (XGetWMNormalHints(dpy, c->window, &c->size, &msize) == 0) - c->size.flags = 0; - - if (c->framed == True) { - /* - * Correct the minimum allowable size of this client to take - * account of the window border. - */ - if (c->size.flags & PMinSize) { - c->size.min_width += 2 * border; - c->size.min_height += 2 * border; - } else { - c->size.flags |= PMinSize; - c->size.min_width = 2 * (2 * border); - if (c->accepts_focus) - c->size.min_height = 2 * (2*border); - else - c->size.min_height = 2 * (2*border); - } - - /* - * Correct the maximum allowable size of this client to take - * account of the window border. - */ - if (c->size.flags & PMaxSize) { - c->size.max_width += 2 * border; - c->size.max_height += 2 * border; - } - } - - /* - * Ensure that the base width & height and the width & height increments - * are set correctly so that we don't have to do this in MakeSane. - */ - if (!(c->size.flags & PBaseSize)) - c->size.base_width = c->size.base_height = 0; - - if (!(c->size.flags & PResizeInc)) - c->size.width_inc = c->size.height_inc = 1; - - /* - * If the client gives identical minimum and maximum sizes, we don't - * want the user to resize in that direction. - */ - if (c->size.min_width == c->size.max_width) - c->size.width_inc = 0; - - if (c->size.min_height == c->size.max_height) - c->size.height_inc = 0; - - /* Restore the window-manager bits. */ - c->size.x = x; - c->size.y = y; - c->size.width = w; - c->size.height = h; + int x, y, w, h; + long msize; + + /* We have to be a little careful here. The ICCCM says that the x, y + * and width, height components aren't used. So we use them. That means + * that we need to save and restore them whenever we fill the size + * struct. */ + x = c->size.x; + y = c->size.y; + w = c->size.width; + h = c->size.height; + + /* Do the get. */ + if (XGetWMNormalHints(dpy, c->window, &c->size, &msize) == 0) + c->size.flags = 0; + + if (c->framed == True) { + /* + * Correct the minimum allowable size of this client to take + * account of the window border. + */ + if (c->size.flags & PMinSize) { + c->size.min_width += 2 * border; + c->size.min_height += 2 * border; + } else { + c->size.flags |= PMinSize; + c->size.min_width = 2 * (2 * border); + c->size.min_height = 2 * (2 * border); + } + + /* + * Correct the maximum allowable size of this client to take + * account of the window border. + */ + if (c->size.flags & PMaxSize) { + c->size.max_width += 2 * border; + c->size.max_height += 2 * border; + } + } + + /* + * Ensure that the base width & height and the width & height increments + * are set correctly so that we don't have to do this in MakeSane. + */ + if (!(c->size.flags & PBaseSize)) + c->size.base_width = c->size.base_height = 0; + + if (!(c->size.flags & PResizeInc)) + c->size.width_inc = c->size.height_inc = 1; + + /* + * If the client gives identical minimum and maximum sizes, we don't + * want the user to resize in that direction. + */ + if (c->size.min_width == c->size.max_width) + c->size.width_inc = 0; + + if (c->size.min_height == c->size.max_height) + c->size.height_inc = 0; + + /* Restore the window-manager bits. */ + c->size.x = x; + c->size.y = y; + c->size.width = w; + c->size.height = h; } static int getWindowState(Window w, int *state) { - long *p = 0; + long *p = 0; - if (getProperty(w, wm_state, wm_state, 2L, (unsigned char **) &p) <= 0) - return 0; + if (getProperty(w, wm_state, wm_state, 2L, (unsigned char **) &p) <= 0) + return 0; - *state = (int) *p; - XFree(p); - return 1; + *state = (int) *p; + XFree(p); + return 1; } - -extern Bool -motifWouldDecorate(Client *c) { - unsigned long *p = 0; - Bool ret = True; /* if all else fails - decorate */ - - if (getProperty(c->window, motif_wm_hints, motif_wm_hints, - 5L, (unsigned char **) &p) <= 0) - return ret; - - if ((p[0] & MWM_HINTS_DECORATIONS) && - !(p[2] & (MWM_DECOR_BORDER | MWM_DECOR_ALL))) - ret = False; - - XFree(p); - return ret; -} diff --git a/shape.c b/mouse.c similarity index 73% rename from shape.c rename to mouse.c index 2b06189..6ab33b3 100644 --- a/shape.c +++ b/mouse.c @@ -19,38 +19,23 @@ #include #include -#include -#include - -#include #include +#include #include #include -#ifdef SHAPE -#include -#endif #include "lwm.h" +#include "ewmh.h" -/*ARGSUSED*/ -extern void -setShape(Client *c) { -} +void +getMousePosition(int * x, int * y) { + Window root, child; + int t1, t2; + unsigned int b; -/*ARGSUSED*/ -extern int -shapeEvent(XEvent *ev) { - return 0; + /* It doesn't matter which root window we give this call. */ + XQueryPointer(dpy, screens[0].root, &root, &child, x, y, &t1, &t2, &b); + current_screen = getScreenFromRoot(root); } -/*ARGSUSED*/ -extern int -isShaped(Window w) { - return 0; -} - -extern int -serverSupportsShapes(void) { - return 0; -} diff --git a/no_xmkmf_makefile b/no_xmkmf_makefile deleted file mode 100644 index d184e5c..0000000 --- a/no_xmkmf_makefile +++ /dev/null @@ -1,48 +0,0 @@ -# Sample Makefile for lwm. - -# You ought to be using the Imakefile (xmkmf;make) but -# if Imake isn't set up properly on your system, this might -# help you out. I used to use it on an SGI. - -# Uncomment these lines to use gcc. -#CC = gcc -#CFLAGS = -ansi -pedantic -Wall -DSHAPE - -# Uncomment these lines to use SGI cc. -#CC = cc -#CFLAGS = -fullwarn -g -DSHAPE - -# Uncomment these for Solaris Sun Studio, choose your architecture. -#CC = cc -#CFLAGS = -Xa -fast -xarch=v8a -#CFLAGS = -Xa -fast -xarch=386 - -DEFINES = - -# Bennett Todd (bet@lehman.com) says this helped him compile on -# Solaris 2.5.1, avoiding a problem with . -#DEFINES = -D_POSIX_C_SOURCE=2 - -# Add any strange libraries your system needs here. -LDFLAGS = -lXext -lX11 -lICE -lSM - -# ----------------------------------------------------------------------------- - -OFILES = client.o cursor.o disp.o error.o ewmh.o lwm.o manage.o mouse.o \ - resource.o session.o shape.o -HFILES = lwm.h ewmh.h - -# ----------------------------------------------------------------------------- - -all: lwm - -lwm: $(OFILES) - $(CC) $(CFLAGS) $(DEFINES) -o lwm $(OFILES) $(LDFLAGS) - -install: lwm - cp lwm /usr/local/bin - -$(OFILES): $(HFILES) - -clean: - rm -f lwm *.o core