event handler timer. After upgrading my kernel recently I noticed that dnotify has been depreciated, so I decided to try and implement the new inotify code in Window Maker instead. During testing, I also found that one of the timers which was removed (the one causing the most wake-ups), calling delayedAction, was responsible for handling signals. Basically with this timer removed, signals were only handled after an X event occurs. After looking at the delayedAction function, I couldn't see the purpose of it. It certainly wouldn't cause any delay as it was called by the timer every 500ms, so there is no time correlation with when a signal was received. Also, it appeared to count the signals and call DispatchEvent for each one, but it appears DispatchEvent would just handle the most recent signal and take action on that. The signals handled by delayedAction are the various exit and reset signals, so only one need to be handled. I therefore have commented out delayedAction (it wasn't called by any other procedure) and added a call to DispatchEvent imediately after the signal is registered, in handleExitSig. I'm not sure what problems this may cause with dead children - these are only cleaned up after an Xevent now that the timer is removed- but I haven't observed any problems since a few months ago.
236 lines
5.7 KiB
C
236 lines
5.7 KiB
C
/*
|
|
* Window Maker window manager
|
|
*
|
|
* Copyright (c) 1997-2003 Alfredo K. Kojima
|
|
*
|
|
* 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 "wconfig.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xutil.h>
|
|
|
|
#include "WindowMaker.h"
|
|
#include "window.h"
|
|
#include "client.h"
|
|
#include "funcs.h"
|
|
#include "properties.h"
|
|
#include "session.h"
|
|
#include "winspector.h"
|
|
#include "wmspec.h"
|
|
|
|
extern Atom _XA_WM_DELETE_WINDOW;
|
|
extern Time LastTimestamp;
|
|
extern int wScreenCount;
|
|
|
|
|
|
static void wipeDesktop(WScreen *scr);
|
|
|
|
|
|
/*
|
|
*----------------------------------------------------------------------
|
|
* Shutdown-
|
|
* Exits the window manager cleanly. If mode is WSLogoutMode,
|
|
* the whole X session will be closed, by killing all clients if
|
|
* no session manager is running or by asking a shutdown to
|
|
* it if its present.
|
|
*
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
void
|
|
Shutdown(WShutdownMode mode)
|
|
{
|
|
int i;
|
|
extern int inotifyFD;
|
|
|
|
switch (mode) {
|
|
case WSLogoutMode:
|
|
#ifdef XSMP_ENABLED
|
|
wSessionRequestShutdown();
|
|
break;
|
|
#else
|
|
/* fall through */
|
|
#endif
|
|
case WSKillMode:
|
|
case WSExitMode:
|
|
/* if there is no session manager, send SAVE_YOURSELF to
|
|
* the clients */
|
|
#if 0
|
|
#ifdef XSMP_ENABLED
|
|
if (!wSessionIsManaged())
|
|
#endif
|
|
for (i = 0; i < wScreenCount; i++) {
|
|
WScreen *scr;
|
|
|
|
scr = wScreenWithNumber(i);
|
|
if (scr) {
|
|
wSessionSendSaveYourself(scr);
|
|
}
|
|
}
|
|
#endif
|
|
close(inotifyFD);
|
|
for (i = 0; i < wScreenCount; i++) {
|
|
WScreen *scr;
|
|
|
|
scr = wScreenWithNumber(i);
|
|
if (scr) {
|
|
if (scr->helper_pid)
|
|
kill(scr->helper_pid, SIGKILL);
|
|
|
|
/* if the session is not being managed, save restart info */
|
|
#ifdef XSMP_ENABLED
|
|
if (!wSessionIsManaged())
|
|
#endif
|
|
wSessionSaveClients(scr);
|
|
|
|
wScreenSaveState(scr);
|
|
|
|
if (mode == WSKillMode)
|
|
wipeDesktop(scr);
|
|
else
|
|
RestoreDesktop(scr);
|
|
}
|
|
}
|
|
ExecExitScript();
|
|
Exit(0);
|
|
break;
|
|
|
|
case WSRestartPreparationMode:
|
|
for (i=0; i<wScreenCount; i++) {
|
|
WScreen *scr;
|
|
|
|
close(inotifyFD);
|
|
scr = wScreenWithNumber(i);
|
|
if (scr) {
|
|
if (scr->helper_pid)
|
|
kill(scr->helper_pid, SIGKILL);
|
|
wScreenSaveState(scr);
|
|
RestoreDesktop(scr);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
restoreWindows(WMBag *bag, WMBagIterator iter)
|
|
{
|
|
WCoreWindow *next;
|
|
WCoreWindow *core;
|
|
WWindow *wwin;
|
|
|
|
|
|
if (iter == NULL) {
|
|
core = WMBagFirst(bag, &iter);
|
|
} else {
|
|
core = WMBagNext(bag, &iter);
|
|
}
|
|
|
|
if (core == NULL)
|
|
return;
|
|
|
|
restoreWindows(bag, iter);
|
|
|
|
/* go to the end of the list */
|
|
while (core->stacking->under)
|
|
core = core->stacking->under;
|
|
|
|
while (core) {
|
|
next = core->stacking->above;
|
|
|
|
if (core->descriptor.parent_type==WCLASS_WINDOW) {
|
|
Window window;
|
|
|
|
wwin = core->descriptor.parent;
|
|
window = wwin->client_win;
|
|
wUnmanageWindow(wwin, !wwin->flags.internal_window, False);
|
|
XMapWindow(dpy, window);
|
|
}
|
|
core = next;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*----------------------------------------------------------------------
|
|
* RestoreDesktop--
|
|
* Puts the desktop in a usable state when exiting.
|
|
*
|
|
* Side effects:
|
|
* All frame windows are removed and windows are reparented
|
|
* back to root. Windows that are outside the screen are
|
|
* brought to a viable place.
|
|
*
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
void
|
|
RestoreDesktop(WScreen *scr)
|
|
{
|
|
if (scr->helper_pid > 0) {
|
|
kill(scr->helper_pid, SIGTERM);
|
|
scr->helper_pid = 0;
|
|
}
|
|
|
|
XGrabServer(dpy);
|
|
wDestroyInspectorPanels();
|
|
|
|
/* reparent windows back to the root window, keeping the stacking order */
|
|
restoreWindows(scr->stacking_list, NULL);
|
|
|
|
XUngrabServer(dpy);
|
|
XSetInputFocus(dpy, PointerRoot, RevertToParent, CurrentTime);
|
|
wColormapInstallForWindow(scr, NULL);
|
|
PropCleanUp(scr->root_win);
|
|
wNETWMCleanup(scr);
|
|
XSync(dpy, 0);
|
|
}
|
|
|
|
|
|
/*
|
|
*----------------------------------------------------------------------
|
|
* wipeDesktop--
|
|
* Kills all windows in a screen. Send DeleteWindow to all windows
|
|
* that support it and KillClient on all windows that don't.
|
|
*
|
|
* Side effects:
|
|
* All managed windows are closed.
|
|
*
|
|
* TODO: change to XQueryTree()
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
static void
|
|
wipeDesktop(WScreen *scr)
|
|
{
|
|
WWindow *wwin;
|
|
|
|
wwin = scr->focused_window;
|
|
while (wwin) {
|
|
if (wwin->protocols.DELETE_WINDOW)
|
|
wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW, LastTimestamp);
|
|
else
|
|
wClientKill(wwin);
|
|
wwin = wwin->prev;
|
|
}
|
|
XSync(dpy, False);
|
|
}
|
|
|