From d62c137ee0fa05b7d2b0045c5b2b9a434d08d384 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Sun, 8 Mar 2020 21:43:16 -0400 Subject: [PATCH] removed lots of stuff --- .gitignore | 2 + ChangeLog | 486 ---------------- Imakefile | 29 - build.sh | 2 + client.c | 967 ++++++++++--------------------- cursor.c | 60 +- disp.c | 1361 ++++++++++++++++++++------------------------ ewmh.c | 856 ++++++++++------------------ lwm | Bin 60576 -> 56428 bytes lwm.c | 612 +++++++------------- lwm.h | 274 +++------ lwm.man | 96 ---- manage.c | 874 +++++++++++----------------- shape.c => mouse.c | 35 +- no_xmkmf_makefile | 48 -- 15 files changed, 1869 insertions(+), 3833 deletions(-) create mode 100644 .gitignore delete mode 100644 ChangeLog delete mode 100644 Imakefile create mode 100755 build.sh delete mode 100644 lwm.man rename shape.c => mouse.c (73%) delete mode 100644 no_xmkmf_makefile 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 12e9c0380f915c58d5402f2e2527a42ed46ad6ea..d0ecf68d598e589a12bc46b677fa1e993a4febb2 100755 GIT binary patch literal 56428 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�Ibh;OS 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 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 -- 2.55.0