mirror of
https://github.com/edeproject/ede.git
synced 2023-08-10 21:13:03 +03:00
Evoke will now correctly shutdown (try) all running windows, when
session should be logged out. Previous version (althought commented) was closing all windows (buttons and rest are counted too), not their main window. Thanks to some old code from babaya project I found, XmuClientWindow is what I needed, so emulation is provided to avoid linking with libXmu. Also added some more signals to detect quitting. Pending issue: I'm getting strange sound driver locks when X are started via evoke. This is un-reporoduceable when evoke is started from gui console. This still needs to be investigate.
This commit is contained in:
parent
841a106a28
commit
00f5f2d59a
@ -133,6 +133,64 @@ int get_string_property_value(Atom at, char* txt, int txt_len) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is re-implementation of XmuClientWindow() so I don't have to link code with libXmu.
|
||||
* XmuClientWindow() will return parent window of given window; this is used so we don't
|
||||
* send delete message to some button or else, but it's parent.
|
||||
*/
|
||||
Window mu_try_children(Display* dpy, Window win, Atom wm_state) {
|
||||
Atom real;
|
||||
Window root, parent;
|
||||
Window* children = 0;
|
||||
Window ret = 0;
|
||||
unsigned int nchildren;
|
||||
unsigned char* prop;
|
||||
unsigned long n, extra;
|
||||
int format;
|
||||
|
||||
if(!XQueryTree(dpy, win, &root, &parent, &children, &nchildren))
|
||||
return 0;
|
||||
|
||||
for(unsigned int i = 0; (i < nchildren) && !ret; i++) {
|
||||
prop = NULL;
|
||||
XGetWindowProperty(dpy, children[i], wm_state, 0, 0, False, AnyPropertyType,
|
||||
&real, &format, &n, &extra, (unsigned char**)&prop);
|
||||
if(prop)
|
||||
XFree(prop);
|
||||
if(real)
|
||||
ret = children[i];
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; (i < nchildren) && !ret; i++)
|
||||
ret = mu_try_children(dpy, win, wm_state);
|
||||
|
||||
if(children)
|
||||
XFree(children);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Window mu_client_window(Display* dpy, Window win, Atom wm_state) {
|
||||
Atom real;
|
||||
int format;
|
||||
unsigned long n, extra;
|
||||
unsigned char* prop;
|
||||
int status = XGetWindowProperty(dpy, win, wm_state, 0, 0, False, AnyPropertyType,
|
||||
&real, &format, &n, &extra, (unsigned char**)&prop);
|
||||
if(prop)
|
||||
XFree(prop);
|
||||
|
||||
if(status != Success)
|
||||
return win;
|
||||
|
||||
if(real)
|
||||
return win;
|
||||
|
||||
Window w = mu_try_children(dpy, win, wm_state);
|
||||
if(!w) w = win;
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
void service_watcher_cb(int pid, int signum) {
|
||||
EvokeService::instance()->service_watcher(pid, signum);
|
||||
}
|
||||
@ -385,20 +443,6 @@ void EvokeService::setup_atoms(Display* d) {
|
||||
}
|
||||
|
||||
void EvokeService::quit_x11(void) {
|
||||
int ret = edelib::ask(_("Nice quitting is not implemented yet and this will forcefully kill\nall running applications. Make sure to save what needs to be saved.\nSo, would you like to continue ?"));
|
||||
if(ret)
|
||||
stop();
|
||||
#if 0
|
||||
/*
|
||||
* This code is working, but not as I would like to see.
|
||||
* It will (mostly) call XKillClient() for _every_ window
|
||||
* (including i.e. buttons in some app), and that is not
|
||||
* nice way to say good bye. This must be implemented in
|
||||
* wm since it only knows what is actuall window and what not.
|
||||
* For now quit_x11() will simply quit itself, quitting X11
|
||||
* session (if it holds it), which will in turn forcefully kill
|
||||
* all windows.
|
||||
*/
|
||||
Window dummy, *wins;
|
||||
Window root = RootWindow(fl_display, fl_screen);
|
||||
unsigned int n;
|
||||
@ -408,42 +452,55 @@ void EvokeService::quit_x11(void) {
|
||||
|
||||
Atom _wm_protocols = XInternAtom(fl_display, "WM_PROTOCOLS", False);
|
||||
Atom _wm_delete_window = XInternAtom(fl_display, "WM_DELETE_WINDOW", False);
|
||||
Atom* protocols;
|
||||
int np;
|
||||
Atom _wm_state = XInternAtom(fl_display, "WM_STATE", False);
|
||||
XWindowAttributes attr;
|
||||
XEvent ev;
|
||||
bool have_quit = 0;
|
||||
|
||||
for(unsigned int i = 0; i < n; i++) {
|
||||
if(wins[i] == root)
|
||||
continue;
|
||||
if(XGetWindowAttributes(fl_display, wins[i], &attr) && (attr.map_state == IsViewable))
|
||||
wins[i] = mu_client_window(fl_display, wins[i], _wm_state);
|
||||
else
|
||||
wins[i] = 0;
|
||||
}
|
||||
|
||||
have_quit = 0;
|
||||
if(XGetWMProtocols(fl_display, wins[i], &protocols, &np)) {
|
||||
for(int j = 0; j < np; j++) {
|
||||
if(protocols[j] == _wm_delete_window) {
|
||||
have_quit = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Hm... probably we should first quit known processes started by us
|
||||
* then rest of the X familly
|
||||
*/
|
||||
for(unsigned int i = 0; i < n; i++) {
|
||||
if(wins[i]) {
|
||||
EVOKE_LOG("closing %i window\n", i);
|
||||
|
||||
if(have_quit) {
|
||||
// FIXME: check WM_PROTOCOLS before sending WM_DELETE_WINDOW ???
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.xclient.type = ClientMessage;
|
||||
ev.xclient.window = wins[i];
|
||||
ev.xclient.message_type = _wm_protocols;
|
||||
ev.xclient.format = 32;
|
||||
ev.xclient.data.l[0] = (long)_wm_delete_window;
|
||||
ev.xclient.data.l[1] = (long)fl_event_time;
|
||||
ev.xclient.data.l[1] = CurrentTime;
|
||||
XSendEvent(fl_display, wins[i], False, 0L, &ev);
|
||||
} else {
|
||||
|
||||
EVOKE_LOG("%i window closed\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
XSync(fl_display, False);
|
||||
sleep(1);
|
||||
|
||||
// kill remaining windows
|
||||
for(unsigned int i = 0; i < n; i++) {
|
||||
if(wins[i]) {
|
||||
EVOKE_LOG("killing remaining %i window\n", i);
|
||||
XKillClient(fl_display, wins[i]);
|
||||
}
|
||||
}
|
||||
|
||||
XFree((void*)wins);
|
||||
XSync(fl_display, False);
|
||||
|
||||
XFree(wins);
|
||||
EVOKE_LOG("now close myself\n");
|
||||
stop();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@ -456,9 +513,10 @@ void EvokeService::service_watcher(int pid, int signum) {
|
||||
|
||||
if(signum == SPAWN_CHILD_CRASHED) {
|
||||
EvokeProcess pc;
|
||||
bool ret;
|
||||
|
||||
mutex.lock();
|
||||
bool ret = find_and_unregister_process(pid, pc);
|
||||
ret = find_and_unregister_process(pid, pc);
|
||||
mutex.unlock();
|
||||
|
||||
if(ret) {
|
||||
@ -678,9 +736,9 @@ int EvokeService::handle(const XEvent* ev) {
|
||||
|
||||
int dw = DisplayWidth(fl_display, fl_screen);
|
||||
int dh = DisplayHeight(fl_display, fl_screen);
|
||||
|
||||
printf("got %i\n", logout_dialog(dw, dh));
|
||||
// quit_x11();
|
||||
// TODO: add XDM service permissions
|
||||
printf("got %i\n", logout_dialog(dw, dh, 1, 1));
|
||||
//quit_x11();
|
||||
} else
|
||||
logfile->printf("Got _EDE_EVOKE_SHUTDOWN_ALL with bad code (%i). Ignoring...\n", val);
|
||||
return 1;
|
||||
|
@ -10,6 +10,9 @@
|
||||
|
||||
SubDir TOP evoke ;
|
||||
|
||||
# use SIGHUP for now as default
|
||||
ObjectC++Flags evoke.cpp : -DUSE_SIGHUP ;
|
||||
|
||||
SOURCE = evoke.cpp EvokeService.cpp Spawn.cpp Splash.cpp Log.cpp Logout.cpp Crash.cpp Autostart.cpp ;
|
||||
|
||||
LinkAgainst evoke : -lao -lvorbis -lvorbisfile -lmad ;
|
||||
|
@ -23,10 +23,10 @@
|
||||
#include <string.h> // memset
|
||||
|
||||
static int logout_ret;
|
||||
static Fl_Double_Window* win;
|
||||
static Fl_Round_Button* rb1;
|
||||
static Fl_Round_Button* rb2;
|
||||
static Fl_Round_Button* rb3;
|
||||
static Fl_Double_Window* win;
|
||||
static Fl_Round_Button* rb1;
|
||||
static Fl_Round_Button* rb2;
|
||||
static Fl_Round_Button* rb3;
|
||||
|
||||
unsigned char* take_x11_screenshot(unsigned char *p, int X, int Y, int w, int h, int alpha);
|
||||
unsigned char* make_darker(unsigned char *p, int X, int Y, int w, int h);
|
||||
|
@ -33,12 +33,9 @@ void sigchld_handler(int sig) {
|
||||
int pid, status;
|
||||
do {
|
||||
errno = 0;
|
||||
//pid = waitpid(WAIT_ANY, &status, WNOHANG | WUNTRACED);
|
||||
pid = waitpid(WAIT_ANY, &status, WNOHANG);
|
||||
|
||||
if(global_watch != 0) {
|
||||
printf("==> sigchld_handler() got %i\n", status);
|
||||
|
||||
if(WIFEXITED(status))
|
||||
status = WEXITSTATUS(status);
|
||||
else if(WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV)
|
||||
@ -99,6 +96,7 @@ int spawn_program(const char* cmd, SignalWatch wf, pid_t* child_pid_ret, const c
|
||||
close(1); dup(nulldev);
|
||||
close(2); dup(nulldev);
|
||||
|
||||
errno = 0;
|
||||
if(execve(argv[0], argv, environ) == -1) {
|
||||
close(nulldev);
|
||||
// should not get here
|
||||
|
@ -3,31 +3,32 @@
|
||||
[evoke]
|
||||
Startup = edewm,eiconman,eworkpanel,xscreensaver
|
||||
DataDirectory = data
|
||||
#ImagesDirectory = /home/sanel/blentavo/EDE/ede2/evoke/images
|
||||
# DataDirectory = /home/sanel/blentavo/EDE/ede2/evoke/data
|
||||
Splash = splash-alpha1.png
|
||||
Sound = startup.ogg
|
||||
# Sound = Startup1_2.ogg
|
||||
# Sound = Startup1_2.ogg
|
||||
|
||||
[edewm]
|
||||
Icon = edewm.png
|
||||
Exec = gvim
|
||||
#Exec = edewm
|
||||
# Exec = edewm
|
||||
Description = window manager
|
||||
|
||||
[eiconman]
|
||||
Icon = eiconman.png
|
||||
Exec = mozilla
|
||||
# Exec = /home/sanel/blentavo/EDE/ede2/eiconman/eiconman
|
||||
# Exec = /home/sanel/blentavo/EDE/ede2/eiconman/eiconman
|
||||
# Exec = eiconman
|
||||
Description = desktop
|
||||
|
||||
[eworkpanel]
|
||||
Icon = eworkpanel.png
|
||||
Exec = mrxvt -bg black
|
||||
# Exec = eworkpanel
|
||||
# Exec = eworkpanel
|
||||
Description = panel
|
||||
|
||||
[xscreensaver]
|
||||
Icon = xscreensaver.png
|
||||
Exec = rxvt
|
||||
# Exec = xscreensaver -nosplash
|
||||
# Exec = xscreensaver -nosplash
|
||||
Description = screensaver
|
||||
|
@ -166,9 +166,20 @@ int main(int argc, char** argv) {
|
||||
|
||||
service->setup_atoms(fl_display);
|
||||
|
||||
signal(SIGINT, quit_signal);
|
||||
signal(SIGINT, quit_signal);
|
||||
signal(SIGTERM, quit_signal);
|
||||
signal(SIGKILL, quit_signal);
|
||||
signal(SIGQUIT, quit_signal);
|
||||
|
||||
#ifdef USE_SIGHUP
|
||||
/*
|
||||
* This is mostly used when we get request to shutdown session and close/kill all windows.
|
||||
* If evoke is started from gui console (xterm, rxvt), closing that window we will get
|
||||
* SIGHUP since terminal will disconnect all controlling processes. On other hand, if evoke
|
||||
* is started as session carrier (eg. run from xinitrc), this is not needed.
|
||||
*/
|
||||
signal(SIGHUP, quit_signal);
|
||||
#endif
|
||||
|
||||
service->start();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user