lwm-1.2.2/0000755000242100017500000000000011302774502011274 5ustar jamesstafflwm-1.2.2/shape.c0000644000242100017500000000407311302774502012544 0ustar jamesstaff/* * lwm, a window manager for X11 * Copyright (C) 1997-2003 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. */ #include #include #include #include #include #include #include #include #ifdef SHAPE #include #endif #include "lwm.h" /*ARGSUSED*/ extern void setShape(Client *c) { #ifdef SHAPE int n; int order; XRectangle *rect; if (shape) { XShapeSelectInput(dpy, c->window, ShapeNotifyMask); rect = XShapeGetRectangles(dpy, c->window, ShapeBounding, &n, &order); if (n > 1) XShapeCombineShape(dpy, c->parent, ShapeBounding, border - 1, border - 1, c->window, ShapeBounding, ShapeSet); XFree(rect); } #else #endif } /*ARGSUSED*/ extern int shapeEvent(XEvent *ev) { #ifdef SHAPE if (shape && ev->type == shape_event) { Client *c; XShapeEvent *e = (XShapeEvent *)ev; c = Client_Get(e->window); if (c != 0) setShape(c); return 1; } #else #endif return 0; } /*ARGSUSED*/ extern int isShaped(Window w) { #ifdef SHAPE int n; int order; XRectangle *rect; rect = XShapeGetRectangles(dpy, w, ShapeBounding, &n, &order); XFree(rect); return (n > 1); #else return 0; #endif } extern int serverSupportsShapes(void) { #ifdef SHAPE int shape_error; return XShapeQueryExtension(dpy, &shape_event, &shape_error); #else return 0; #endif } lwm-1.2.2/ewmh.c0000644000242100017500000004205611302774502012407 0ustar jamesstaff/* * lwm, a window manager for X11 * Copyright (C) 1997-2003 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. */ #include #include #include #include #include #include #include #include #include "lwm.h" #include "ewmh.h" Atom ewmh_atom[EWMH_ATOM_LAST]; 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); } 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]); } } 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; } 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 } 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); } 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); } void 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 */ for (c = client_head(); c; c = c->next) { if (c->wstate.fullscreen == False) continue; Client_Raise(c); } } static Bool valid_for_client_list(ScreenInfo *screen, Client *c) { if (c->screen != screen) return False; if (c->state == WithdrawnState) return False; return True; } /* * update_client_list updates the properties on the root window used by * task lists and pagers. * * it should be called whenever the window stack is modified, or when clients * are hidden or unhidden. */ 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; } lwm-1.2.2/COPYING0000644000242100017500000004312411302774502012333 0ustar jamesstaff GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. lwm-1.2.2/TODO0000644000242100017500000000004511302774502011763 0ustar jamesstaffuse XFT extensions where available? lwm-1.2.2/ChangeLog0000644000242100017500000003644611302774502013063 0ustar jamesstaffChange Log for "lwm" 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 - lwm-1.2.2/AUTHORS0000644000242100017500000000011111302774502012335 0ustar jamesstaffenh Elliott Hughes ehughes@bluearc.com jfc James Carter james@jfc.org.uk lwm-1.2.2/BUGS0000644000242100017500000000326011302774502011760 0ustar jamesstaffwe're possibly being a bit overzealous about maintaining the window stack, with lots of flickering windows as a result. it's particularly noticeable when you're running a desktop - but then that's a stupid thing to do anyway. not sure how to fix it without maintaining a lot more data about the window stack. reported by corey holcomb-hockin: lwm producues messages like this when popups appear: lwm: protocol request X_ConfigureWindow on resource 0xa0000e failed: BadWindow (invalid Window parameter) lwm: protocol request X_SendEvent on resource 0xa0000e failed: BadWindow (invalid Window parameter) lwm: protocol request X_ConfigureWindow on resource 0xa0000e failed: BadWindow (invalid Window parameter) lwm: protocol request X_SendEvent on resource 0xa0000e failed: BadWindow (invalid Window parameter) lwm: protocol request X_SetInputFocus on resource 0xa0000e failed: BadWindow (invalid Window parameter) lwm: protocol request X_SetInputFocus on resource 0x8000de failed: BadMatch (invalid parameter attributes) martin and elliott still have window problems with edit, although it's better than it was. apparently the window is now placed correctly, but gets larger between successive runs. i can't reproduce this, unfortunately. chris reports that positioning a window on the bottom or right edge of a screen and then resizing the edge opposite to that touching the edge of the screen causes the window to jump in 1 unit (pixel or character depending on the application). also, and possibly related, holding button 1 to resize any edge apart from the right, and then moving the mouse along that edge (ie. perpendicular to the normal movement for resizing) causes the window to shrink one unit. lwm-1.2.2/resource.c0000644000242100017500000000616511302774502013277 0ustar jamesstaff/* * lwm, a window manager for X11 * Copyright (C) 1997-2003 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. */ #include #include #include #include #include #include #include #include #include #include #include #include "lwm.h" 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) */ char * sdup(char *p) { char *s ; s = malloc(strlen(p) + 1); if(s == 0) panic("malloc failed."); return strcpy(s, p); } extern void parseResources(void) { XrmDatabase db; XrmValue value; char *resource_manager; char *type; /* 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; resource_manager = XResourceManagerString(dpy); if (resource_manager == 0) return; XrmInitialize(); db = XrmGetStringDatabase(resource_manager); if (db == 0) return; /* Fonts. */ if (XrmGetResource(db, "lwm.titleFont", "Font", &type, &value) == True) if (strcmp(type, "String") == 0) font_name = sdup((char *) value.addr); if (XrmGetResource(db, "lwm.popupFont", "Font", &type, &value) == True) if (strcmp(type, "String") == 0) popup_font_name = sdup((char *) value.addr); /* Window border width. */ if(XrmGetResource(db, "lwm.border", "Border", &type, &value) == True) if (strcmp(type, "String") == 0) border = (int) strtol((char *) value.addr, (char **) 0, 0); /* The button commands. */ if (XrmGetResource(db, "lwm.button1", "Command", &type, &value) == True) if (strcmp(type, "String") == 0) btn1_command = sdup((char *) value.addr); if (XrmGetResource(db, "lwm.button2", "Command", &type, &value) == True) if (strcmp(type, "String") == 0) btn2_command = sdup((char *) value.addr); /* The focus mode */ if (XrmGetResource(db, "lwm.focus", "FocusMode", &type, &value) == True && strcmp(type, "String") == 0) { if (strcmp(value.addr, "enter") == 0) focus_mode = focus_enter; if (strcmp(value.addr, "click") == 0) focus_mode = focus_click; } } lwm-1.2.2/README0000644000242100017500000000015711302774502012157 0ustar jamesstaffThis is lwm, a window manager for X. See INSTALL for install instructions and COPYRIGHT for license details. lwm-1.2.2/client.c0000644000242100017500000004627111302774502012730 0ustar jamesstaff/* * lwm, a window manager for X11 * Copyright (C) 1997-2003 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. */ #include #include #include #include #include #include #include #include #include #include "lwm.h" #include "ewmh.h" 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; } 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); } 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 * Client_Get(Window w) { Client * c; 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; /* 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; } 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)) { unhidec(c, 0); /* 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); } 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 Client_SizeFeedback(void) { int x, y; char buf[4*2 + 3 + 1]; /* Make the popup 10% wider than the widest string it needs to show. */ snprintf(buf, sizeof(buf), "%i x %i", current_screen->display_width, current_screen->display_height); popup_width = popupWidth(buf, strlen(buf)); popup_width += popup_width/10; /* Put the popup in the right place to report on the window's size. */ getMousePosition(&x, &y); XMoveResizeWindow(dpy, current_screen->popup, x + 8, y + 8, popup_width, popupHeight() + 1); XMapRaised(dpy, current_screen->popup); /* * Ensure that the popup contents get redrawn. Eventually, the function * size_expose will get called to do the actual redraw. */ XClearArea(dpy, current_screen->popup, 0, 0, 0, 0, True); } 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)); } 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); } void Client_Lower(Client *c) { if (c == 0) return; XLowerWindow(dpy, c->window); if (c->framed) XLowerWindow(dpy, c->parent); ewmh_set_client_list(c->screen); } void Client_Raise(Client *c) { Client * trans; if (c == 0) return; 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); } 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); } } void Client_SetState(Client *c, int state) { long data[2]; 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); } 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; } } } } extern void Client_ReshapeEdge(Client *c, Edge e) { Client_OpaquePrimitive(c, e); } extern void Client_Move(Client *c) { 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; } 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 + titleHeight() + 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); } 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); } 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); } 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 = sdup((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 = sdup(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))); } lwm-1.2.2/Imakefile0000644000242100017500000000220511302774502013104 0ustar jamesstaffXCOMM lwm, a window manager for X11 XCOMM Copyright (C) 1997-2003 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) 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} lwm-1.2.2/no_xmkmf_makefile0000644000242100017500000000226411302774502014676 0ustar jamesstaff# 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 lwm-1.2.2/lwm.c0000644000242100017500000003100711302774502012240 0ustar jamesstaff/* * lwm, a window manager for X11 * Copyright (C) 1997-2003 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #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. */ ScreenInfo * current_screen; 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; Atom wm_change_state; Atom wm_protocols; Atom wm_delete; 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); /*ARGSUSED*/ extern int main(int argc, char *argv[]) { XEvent ev; struct sigaction sa; int dpy_fd, max_fd; argv0 = argv[0]; mode = wm_initialising; setlocale(LC_ALL,""); /* 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(); session_init(argc, argv); /* 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; if (ice_fd > dpy_fd) max_fd = ice_fd + 1; for (;;) { fd_set readfds; FD_ZERO(&readfds); FD_SET(dpy_fd, &readfds); if (ice_fd > 0) FD_SET(ice_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); } } if (ice_fd > 0 && FD_ISSET(ice_fd, &readfds)) { session_process(); } } } } 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); } 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; } } extern int titleHeight(void) { 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; } 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; } 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); } } 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 = strrchr(display_string, '.'); /* Set the DISPLAY specification. */ if (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); } /** Find the screen for which root is the root window. */ ScreenInfo * getScreenFromRoot(Window root) { int screen; for (screen = 0; screen < screen_count; screen++) if (screens[screen].root == root) return &screens[screen]; return 0; } lwm-1.2.2/cursor.c0000644000242100017500000000424611302774502012763 0ustar jamesstaff/* * lwm, a window manager for X11 * Copyright (C) 1997-2003 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. */ #include #include #include #include #include #include "lwm.h" typedef struct CursorMapping CursorMapping; struct CursorMapping { 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}, }; extern void initialiseCursors(int screen) { XColor red, white, exact; Colormap cmp; int i; cmp = DefaultColormap(dpy, screen); 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].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); } } extern Cursor getEdgeCursor(Edge edge) { return screens[0].cursor_map[edge]; } lwm-1.2.2/disp.c0000644000242100017500000005300411302774502012401 0ustar jamesstaff/* * lwm, a window manager for X11 * Copyright (C) 1997-2003 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. */ #include #include #include #include #include #include #include #include #include "lwm.h" #include "ewmh.h" /* * Dispatcher for main event loop. */ typedef struct Disp Disp; struct Disp { int type; void (*handler)(XEvent *); }; static void expose(XEvent *); static void buttonpress(XEvent *); static void buttonrelease(XEvent *); 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 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}, }; /** * pending it the client in which an action has been started by a mouse press * and we are waiting for the button to be released before performing the action */ 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); } 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_menu_up) menu_expose(); else if (mode == wm_reshaping && current != 0) size_expose(); } else { c = Client_Get(w); if (c != 0) { Client_DrawBorder(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); menuhit(e); } else { shell(getScreenFromRoot(e->root), e->button, e->x, e->y); } } } static void buttonrelease(XEvent *ev) { XButtonEvent *e = &ev->xbutton; int quarter; if (mode == wm_menu_up) menu_buttonrelease(ev); else 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); } else { hide(pending); } } pending = NULL; } 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); } } } 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; } } unhidec(c, 1); 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. */ if (e->send_event) unhidec(c, 0); /* It's a hidden window disappearing. */ } else { /* 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); } } } static void destroy(XEvent *ev) { Client * c; Window w = ev->xdestroywindow.window; c = Client_Get(w); if (c == 0) return; 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) { if (e->format == 32 && e->data.l[0] == IconicState && normal(c)) hide(c); 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). */ if (hidden(c)) unhidec(c,1); 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 */ if (hidden(c)) unhidec(c,1); 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); } } } 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); } } static void reparent(XEvent *ev) { Client * c; XReparentEvent * e = &ev->xreparent; 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); } 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; } 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); } } static void motionnotify(XEvent *ev) { if (mode == wm_reshaping) reshaping_motionnotify(ev); else if (mode == wm_menu_up) menu_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; } } } } /*ARGSUSED*/ 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; Client_SizeFeedback(); /* 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); } } lwm-1.2.2/ewmh.h0000644000242100017500000000533211302774502012410 0ustar jamesstaff/* * lwm, a window manager for X11 * Copyright (C) 1997-2003 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. */ /** * These are indexes into the ewmh_atom array. Only atoms actually supported * by lwm should be included here because _NET_SUPPORTED is built from the * ewmh_atom array. */ typedef enum { /* root window properties */ _NET_SUPPORTED, _NET_CLIENT_LIST, _NET_CLIENT_LIST_STACKING, _NET_NUMBER_OF_DESKTOPS, _NET_DESKTOP_GEOMETRY, _NET_DESKTOP_VIEWPORT, _NET_CURRENT_DESKTOP, /*_NET_DESKTOP_NAMES,*/ _NET_ACTIVE_WINDOW, _NET_WORKAREA, _NET_SUPPORTING_WM_CHECK, /*_NET_VIRTUAL_ROOTS,*/ /*_NET_DESKTOP_LAYOUT,*/ /*_NET_SHOWING_DESKTOP,*/ /* other root window messages */ _NET_CLOSE_WINDOW, _NET_MOVERESIZE_WINDOW, _NET_WM_MOVERESIZE, /* application window properties */ _NET_WM_NAME, /*_NET_WM_VISIBLE_NAME,*/ /*_NET_WM_ICON_NAME,*/ /*_NET_WM_VISIBLE_ICON_NAME,*/ /*_NET_WM_DESKTOP,*/ _NET_WM_WINDOW_TYPE, _NET_WM_STATE, _NET_WM_ALLOWED_ACTIONS, _NET_WM_STRUT, /*_NET_WM_ICON_GEOMETRY,*/ /*_NET_WM_ICON,*/ /*_NET_WM_PID,*/ /*_NET_WM_HANDLED_ICONS,*/ /* window types for _NET_WM_WINDOW_TYPE */ _NET_WM_WINDOW_TYPE_DESKTOP, _NET_WM_WINDOW_TYPE_DOCK, _NET_WM_WINDOW_TYPE_TOOLBAR, _NET_WM_WINDOW_TYPE_MENU, _NET_WM_WINDOW_TYPE_UTILITY, _NET_WM_WINDOW_TYPE_SPLASH, _NET_WM_WINDOW_TYPE_DIALOG, _NET_WM_WINDOW_TYPE_NORMAL, /* window states for _NET_WM_STATE */ /*_NET_WM_STATE_MODAL,*/ /*_NET_WM_STATE_STICKY,*/ /*_NET_WM_STATE_MAXIMISED_VERT,*/ /*_NET_WM_STATE_MAXIMISED_HORZ,*/ /*_NET_WM_STATE_SHADED,*/ _NET_WM_STATE_SKIP_TASKBAR, _NET_WM_STATE_SKIP_PAGER, _NET_WM_STATE_HIDDEN, _NET_WM_STATE_FULLSCREEN, _NET_WM_STATE_ABOVE, _NET_WM_STATE_BELOW, /* allowed actions for _NET_WM_ALLOWED_ACTIONS */ _NET_WM_ACTION_MOVE, _NET_WM_ACTION_RESIZE, /*_NET_WM_ACTION_MINIMIZE,*/ /*_NET_WM_ACTION_SHADE,*/ /*_NET_WM_ACTION_STICK,*/ /*_NET_WM_ACTION_MAXIMIZE_HORIZ,*/ /*_NET_WM_ACTION_MAXIMIZE_VERT,*/ _NET_WM_ACTION_FULLSCREEN, /*_NET_WM_ACTION_CHANGE_DESKTOP,*/ _NET_WM_ACTION_CLOSE, EWMH_ATOM_LAST } EWMHAtom; lwm-1.2.2/mouse.c0000644000242100017500000001633411302774502012577 0ustar jamesstaff/* * lwm, a window manager for X11 * Copyright (C) 1997-2003 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. */ #include #include #include #include #include #include #include "lwm.h" #include "ewmh.h" static int current_item; /* Last known selected menu item. -1 if none. */ typedef struct menuitem menuitem; struct menuitem { Client * client; menuitem * next; }; static menuitem * hidden_menu = 0; static void getMenuDimensions(int *, int *, int *); 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); } int menu_whichitem(int x, int y) { int width; /* Width of menu. */ int height; /* Height of each menu item. */ int length; /* Number of items on the menu. */ getMenuDimensions(&width, &height, &length); /* * Translate to popup window coordinates. We do this ourselves to avoid * a round trip to the server. */ x -= start_x; y -= start_y; /* * Are we outside the menu? */ if (x < 0 || x > width || y < 0 || y >= length * height) return -1; return y / height; } static void getMenuDimensions(int *width, int *height, int *length) { int w; /* Widest string so far. */ int i; /* Menu item. */ menuitem *m = hidden_menu; w = 0; for (i = 0; m != 0; m = m->next, i++) { int tw = titleWidth(popup_font_set, m->client) + 4; if (tw > w) w = tw; } *width = w + border; *height = popupHeight(); *length = i; } void menuhit(XButtonEvent *e) { int width; /* Width of menu. */ int height; /* Height of each menu item. */ int length; /* Number of menu items. */ if (hidden_menu == 0) return; Client_ResetAllCursors(); current_screen = getScreenFromRoot(e->root); getMenuDimensions(&width, &height, &length); /* * Arrange for centre of first menu item to be under pointer, * unless that would put the menu offscreen. */ start_x = e->x - width / 2; start_y = e->y - height / 2; if (start_x + width > current_screen->display_width) start_x = current_screen->display_width - width; if (start_x < 0) start_x = 0; if (start_y + (height * length) > current_screen->display_height) start_y = current_screen->display_height - (height * length); if (start_y < 0) start_y = 0; current_item = menu_whichitem(e->x_root, e->y_root); XMoveResizeWindow(dpy, current_screen->popup, start_x, start_y, width, length * height); XMapRaised(dpy, current_screen->popup); XChangeActivePointerGrab(dpy, ButtonMask | ButtonMotionMask | OwnerGrabButtonMask, None, CurrentTime); mode = wm_menu_up; } void hide(Client *c) { menuitem *newitem; if (c == 0) return; /* Create new menu item, and thread it on the menu. */ newitem = (menuitem *) malloc(sizeof(menuitem)); if (newitem == 0) return; newitem->client = c; newitem->next = hidden_menu; hidden_menu = newitem; /* Actually hide the window. */ XUnmapWindow(dpy, c->parent); XUnmapWindow(dpy, c->window); c->hidden = True; /* If the window was the current window, it isn't any more... */ if (c == current) Client_Focus(NULL, CurrentTime); Client_SetState(c, IconicState); } void unhide(int n, int map) { Client *c; menuitem *prev = 0; menuitem *m = hidden_menu; /* Find the nth client. */ if (n < 0) return; while (n-- > 0 && m != 0) { prev = m; m = m->next; } if (m == 0) return; c = m->client; /* Remove the item from the menu, and dispose of it. */ if (prev == 0) { hidden_menu = m->next; } else { prev->next = m->next; } free(m); c->hidden = False; /* Unhide it. */ if (map) { XMapWindow(dpy, c->parent); XMapWindow(dpy, c->window); Client_Raise(c); Client_SetState(c, NormalState); if (focus_mode == focus_click) { /* it feels right that the unhidden window gets focus*/ Client_Focus(c, CurrentTime); } } } void unhidec(Client *c, int map) { int i = 0; menuitem *m = hidden_menu; if (c == 0) return; /* My goodness, how the world sucks. */ while (m != 0) { if (m->client == c) { unhide(i, map); return; } m = m->next; i++; } } void menu_expose(void) { int i; /* Menu item being drawn. */ int width; /* Width of each item. */ int height; /* Height of each item. */ int length; /* Number of menu items. */ menuitem *m; getMenuDimensions(&width, &height, &length); /* Redraw the labels. */ for (m = hidden_menu, i = 0; m != 0; m = m->next, i++) { int tx = (width - titleWidth(popup_font_set, m->client)) / 2; int ty = i * height + ascent(popup_font_set_ext); char *name; int namelen; if (m->client->menu_name == NULL) { name = m->client->name; namelen = m->client->namelen; } else { name = m->client->menu_name; namelen = m->client->menu_namelen; } #ifdef X_HAVE_UTF8_STRING if (m->client->name_utf8 == True) Xutf8DrawString(dpy, m->client->screen->popup, popup_font_set, current_screen->menu_gc, tx, ty, name, namelen); else #endif XmbDrawString(dpy, m->client->screen->popup, popup_font_set, current_screen->menu_gc, tx, ty, name, namelen); } /* Highlight current item if there is one. */ if (current_item >= 0 && current_item < length) XFillRectangle(dpy, current_screen->popup, current_screen->menu_gc, 0, current_item * height, width, height); } void menu_motionnotify(XEvent* ev) { int old; /* Old menu position. */ int width; /* Width of menu. */ int height; /* Height of each menu item. */ int length; /* Number of menu items. */ XButtonEvent *e = &ev->xbutton; getMenuDimensions(&width, &height, &length); old = current_item; current_item = menu_whichitem(e->x_root, e->y_root); if (current_item == old) return; /* Unhighlight the old position, if it was on the menu. */ if (old >= 0 && old < length) XFillRectangle(dpy, current_screen->popup, current_screen->menu_gc, 0, old * height, width, height); /* Highlight the new position, if it's on the menu. */ if (current_item >= 0 && current_item < length) XFillRectangle(dpy, current_screen->popup, current_screen->menu_gc, 0, current_item * height, width, height); } void menu_buttonrelease(XEvent *ev) { int n; /* Menu item. */ /* * Work out which menu item the button was released over. */ n = menu_whichitem(ev->xbutton.x_root, ev->xbutton.y_root); /* Hide the menu until it's needed again. */ XUnmapWindow(dpy, current_screen->popup);/*BUG?*/ /* Do the menu thing (of unhiding windows). */ unhide(n, 1); if (current) { cmapfocus(current); } } lwm-1.2.2/manage.c0000644000242100017500000003700711302774502012677 0ustar jamesstaff/* * lwm, a window manager for X11 * Copyright (C) 1997-2003 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. */ #include #include #include #include #include #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 **); static int getWindowState(Window, int *); static void applyGravity(Client *); /*ARGSUSED*/ 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) { hide(c); } 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); } 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; } } } void getTransientFor(Client *c) { Window trans = None; 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); session_end(); if (signal) { exit(EXIT_FAILURE); } else { exit(EXIT_SUCCESS); } } 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; } 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); } 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; } static int getWindowState(Window w, int *state) { long *p = 0; if (getProperty(w, wm_state, wm_state, 2L, (unsigned char **) &p) <= 0) return 0; *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; } lwm-1.2.2/INSTALL0000755000242100017500000000024111302774502012325 0ustar jamesstaff#!/bin/cat Installing lwm 1. Compile lwm: xmkmf ; make ; strip lwm 2. Copy the binary to where you want it. 3. Edit your Xsession or whatever to call lwm. lwm-1.2.2/session.c0000644000242100017500000001445411302774502013133 0ustar jamesstaff/* * lwm, a window manager for X11 * Copyright (C) 1997-2003 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. */ #include #include #include #include #include #include #include #include #include #include #include "lwm.h" typedef struct { SmProp p; SmPropValue v; } SmProperty; int ice_fd=-1; static IceConn ice_conn; static void *smc_conn = NULL; static int session_argc; static char **session_argv; static char *client_id = NULL; static void ice_error(IceConn c) { /* i only bother catching ice i/o errors because metacity claims the * default handler calls exit. twm doesn't bother, so it might not * be necessary. */ fprintf(stderr,"%s: ICE I/O error\n",argv0); } static void session_save_yourself(SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast) { int i; SmProperty program; SmProperty user_id; SmProperty restart_style_hint; SmProperty pid; SmProperty gsm_priority; SmProp clone_command; SmProp restart_command; enum prop_nums { prop_program, prop_user_id, prop_restart_style_hint, prop_pid, prop_gsm_priority, prop_clone_command, prop_restart_command, prop_LAST }; SmProp *props[prop_LAST]; struct passwd *pw; char hint = SmRestartImmediately; char pid_s[32]; char priority = 20; program.p.name = SmProgram; program.p.type = SmARRAY8; program.p.num_vals = 1; program.p.vals = &program.v; program.v.value = "lwm"; program.v.length = 3; props[prop_program] = &program.p; pw = getpwuid(getuid()); user_id.p.name = SmUserID; user_id.p.type = SmARRAY8; user_id.p.num_vals = 1; user_id.p.vals = &user_id.v; user_id.v.value = pw ? pw->pw_name : NULL ; user_id.v.length = pw ? strlen(pw->pw_name) : 0; props[prop_user_id] = &user_id.p; restart_style_hint.p.name = SmRestartStyleHint; restart_style_hint.p.type = SmCARD8; restart_style_hint.p.num_vals = 1; restart_style_hint.p.vals = &restart_style_hint.v; restart_style_hint.v.value = &hint; restart_style_hint.v.length = 1; props[prop_restart_style_hint] = &restart_style_hint.p; snprintf(pid_s, sizeof(pid_s), "%d", getpid()); pid.p.name = SmProcessID; pid.p.type = SmARRAY8; pid.p.num_vals = 1; pid.p.vals = &pid.v; pid.v.value = pid_s; pid.v.length = strlen(pid_s); props[prop_pid] = &pid.p; gsm_priority.p.name = "_GSM_Priority"; gsm_priority.p.type = SmCARD8; gsm_priority.p.num_vals = 1; gsm_priority.p.vals = &gsm_priority.v; gsm_priority.v.value = &priority; gsm_priority.v.length = 1; props[prop_gsm_priority] = &gsm_priority.p; clone_command.name = SmCloneCommand; clone_command.type = SmLISTofARRAY8; clone_command.num_vals = session_argc; clone_command.vals = (SmPropValue *) malloc(sizeof(SmPropValue) * session_argc); for (i=0; i < session_argc; i++) { clone_command.vals[i].value = session_argv[i]; clone_command.vals[i].length = strlen(session_argv[i]); } props[prop_clone_command] = &clone_command; restart_command.name = SmRestartCommand; restart_command.type = SmLISTofARRAY8; restart_command.num_vals = session_argc + 2; restart_command.vals = (SmPropValue *) malloc(sizeof(SmPropValue) * (session_argc + 2)); for (i=0; i < session_argc; i++) { restart_command.vals[i].value = session_argv[i]; restart_command.vals[i].length = strlen(session_argv[i]); } restart_command.vals[i].value = "-s"; restart_command.vals[i].length = 2; i++; restart_command.vals[i].value = client_id; restart_command.vals[i].length = strlen(client_id); props[prop_restart_command] = &restart_command; SmcSetProperties(smc_conn, prop_LAST, props); free(clone_command.vals); free(restart_command.vals); SmcSaveYourselfDone(smc_conn, True); } void session_end(void) { if (smc_conn == NULL) return; SmcCloseConnection(smc_conn,0,NULL); } static void session_die(SmcConn smc_conn, SmPointer client_data) { Terminate(0); } static void session_save_complete(SmcConn smc_conn, SmPointer client_data) { } static void session_shutdown_cancelled(SmcConn smc_conn, SmPointer client_data) { } void session_init(int argc, char *argv[]) { int i; char *previd = NULL; char err[256]; unsigned long mask; SmcCallbacks callbacks; session_argv = (char **) malloc(sizeof(char *) * (argc + 2)); session_argc = 0; for (i = 0; i < argc; i++) { if (i != 0 && strcmp(argv[i], "-s") == 0) { if ((i + 1) < argc) { i++; previd = argv[i]; } } else { session_argv[session_argc] = argv[i]; session_argc++; } } mask = SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask; callbacks.save_yourself.callback=session_save_yourself; callbacks.save_yourself.client_data=NULL; callbacks.die.callback = session_die; callbacks.die.client_data = NULL; callbacks.save_complete.callback = session_save_complete; callbacks.save_complete.client_data = NULL; callbacks.shutdown_cancelled.callback = session_shutdown_cancelled; callbacks.shutdown_cancelled.client_data = NULL; smc_conn = SmcOpenConnection(NULL, NULL, SmProtoMajor, SmProtoMinor, mask, &callbacks, previd, &client_id, sizeof(err) - 1, err); if (smc_conn == NULL) { /* this isn't actually an error, and can cause confusion fprintf(stderr, "%s: could not connect to session manager - %s\n", argv0, err); */ return; } if (client_id == NULL) { fprintf(stderr, "%s: session manager returned NULL connection\n", argv0); return; } IceSetIOErrorHandler(ice_error); ice_conn = SmcGetIceConnection(smc_conn); ice_fd = IceConnectionNumber(ice_conn); } void session_process(void) { IceProcessMessages(ice_conn, NULL, NULL); } lwm-1.2.2/lwm.h0000644000242100017500000002406511302774502012253 0ustar jamesstaff/* * lwm, a window manager for X11 * Copyright (C) 1997-2003 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. */ /* --- 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 /* --- End of administrator-configurable defaults. --- */ /* * Window manager mode. wm is in one of five modes: it's either getting * user input to move/reshape a window, getting user input to make a * selection from the menu, waiting for user input to confirm a window close * (by releasing a mouse button after prssing it in a window's box), * waiting for user input to confirm a window hide (by releasing a mouse * button after prssing it in a window's frame), * or it's `idle' --- responding to events arriving * from the server, but not directly interacting with the user. * OK, so I lied: there's a sixth mode so that we can tell when wm's still * initialising. */ typedef enum { wm_initialising, wm_idle, wm_reshaping, wm_menu_up, wm_closing_window, wm_hiding_window } 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; /** * Window edge, used in resizing. The `edge' ENone is used to signify a * window move rather than a resize. The code is sufficiently similar that * this isn't a special case to be treated separately. */ typedef enum { 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 } EWMHDirection; /** * EWMH window type. See section 5.6 of the EWMH specification (1.2). * WTypeNone indicates that no EWMH window type as been set and MOTIF * hints should be used instead. */ typedef enum { 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; }; 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 */ enum { Pdelete = 1, Ptakefocus = 2 }; /* * This should really have been in X.h --- if you select both ButtonPress * and ButtonRelease events, the server makes an automatic grab on the * pressed button for you. This is almost always exactly what you want. */ #define ButtonMask (ButtonPressMask | ButtonReleaseMask) /* lwm.c */ extern Mode mode; extern int start_x; extern int start_y; extern Display * dpy; extern int screen_count; 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); extern Edge interacting_edge; 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 Client_SizeFeedback(void); extern void size_expose(void); extern void Client_ReshapeEdge(Client *, Edge); extern void Client_Move(Client*); extern void Client_SetState(Client *, int); 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; /* cursor.c */ extern Cursor getEdgeCursor(Edge edge); extern void initialiseCursors(int); /* disp.c */ extern void dispatch(XEvent *); extern void reshaping_motionnotify(XEvent *); /* error.c */ extern int ignore_badwindow; extern int errorHandler(Display *, XErrorEvent *); extern void panic(char*); /* 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 */ 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); /* session.c */ extern int ice_fd; extern void session_init(int argc, char *argv[]); extern void session_process(void); extern void session_end(void); /* 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); lwm-1.2.2/lwm.man0000644000242100017500000000717211302774502012577 0ustar jamesstaff.\" lwm, a window manager for X11 .\" Copyright (C) 1997-2003 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. The various items unhide the named hidden 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 lwm-1.2.2/error.c0000644000242100017500000000342011302774502012570 0ustar jamesstaff/* * lwm, a window manager for X11 * Copyright (C) 1997-2003 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. */ #include #include #include #include #include #include #include "lwm.h" int ignore_badwindow; void panic(char *s) { fprintf(stderr, "%s: %s\n", argv0, s); exit(EXIT_FAILURE); } int errorHandler(Display *d, XErrorEvent *e) { char msg[80]; char req[80]; char number[80]; if (mode == wm_initialising && e->request_code == X_ChangeWindowAttributes && e->error_code == BadAccess) panic("another window manager is already running."); if (ignore_badwindow && (e->error_code == BadWindow || e->error_code == BadColor)) return 0; XGetErrorText(d, e->error_code, msg, sizeof(msg)); sprintf(number, "%d", e->request_code); XGetErrorDatabaseText(d, "XRequest", number, number, req, sizeof(req)); fprintf(stderr, "%s: protocol request %s on resource %#x failed: %s\n", argv0, req, (unsigned int) e->resourceid, msg); if (mode == wm_initialising) panic("can't initialise."); return 0; }