Bug fix: Segfault when meeting FocusIn/Out from destoryed windows

I found compton segfaults sometimes when starting from .xinitrc.
Debugging reveals my conky window was just reparented to a fvwm's
frame window before compton picked up a FocusOut event on this conky
window that has just been destroyed in the event queue. find_win()
call in ev_focus_in/out() returned a NULL pointer. When it tried to
use the pointer segfault happens.

- Add extra check to ev_focus_in/out() to stop the segfault.

- Reset window event mask on window reparenting to a non-root window to
  minimize wrong events.

- More abstraction for determining window event mask.
This commit is contained in:
Richard Grenville 2012-09-13 22:30:18 +08:00
parent 18b3a96d0b
commit 271d894eae
1 changed files with 28 additions and 6 deletions

View File

@ -704,6 +704,21 @@ should_ignore(Display *dpy, unsigned long sequence) {
* Windows
*/
long determine_evmask(Display *dpy, Window wid, enum win_evmode_t mode) {
long evmask = NoEventMask;
if (WIN_EVMODE_FRAME == mode || find_win(dpy, wid)) {
evmask |= PropertyChangeMask;
if (track_focus)
evmask |= FocusChangeMask;
}
if (WIN_EVMODE_CLIENT == mode || find_client_win(dpy, wid)) {
evmask |= PropertyChangeMask;
}
return evmask;
}
static win *
find_win(Display *dpy, Window id) {
win *w;
@ -1439,10 +1454,7 @@ map_win(Display *dpy, Window id,
/* select before reading the property
so that no property changes are lost */
if (!override_redirect) {
long evmask = PropertyChangeMask;
if (track_focus)
evmask |= FocusChangeMask;
XSelectInput(dpy, id, evmask);
XSelectInput(dpy, id, determine_evmask(dpy, id, WIN_EVMODE_FRAME));
// Notify compton when the shape of a window changes
if (shape_exists) {
XShapeSelectInput(dpy, id, ShapeNotifyMask);
@ -1785,8 +1797,7 @@ add_win(Display *dpy, Window id, Window prev, Bool override_redirect) {
get_frame_extents(dpy, cw,
&new->left_width, &new->right_width,
&new->top_width, &new->bottom_width);
if (id != cw)
XSelectInput(dpy, cw, PropertyChangeMask);
XSelectInput(dpy, cw, determine_evmask(dpy, id, WIN_EVMODE_CLIENT));
}
}
@ -2301,6 +2312,10 @@ inline static void
ev_focus_in(XFocusChangeEvent *ev) {
win *w = find_win(dpy, ev->window);
// To deal with events sent from windows just destroyed
if (!w)
return;
w->focused = True;
calc_opacity(dpy, w, False);
calc_dim(dpy, w);
@ -2319,7 +2334,11 @@ ev_focus_out(XFocusChangeEvent *ev) {
win *w = find_win(dpy, ev->window);
// To deal with events sent from windows just destroyed
if (!w)
return;
w->focused = False;
calc_opacity(dpy, w, False);
calc_dim(dpy, w);
}
@ -2358,6 +2377,9 @@ ev_reparent_notify(XReparentEvent *ev) {
add_win(dpy, ev->window, 0, ev->override_redirect);
} else {
destroy_win(dpy, ev->window, True);
// Reset event mask in case something wrong happens
XSelectInput(dpy, ev->window,
determine_evmask(dpy, ev->window, WIN_EVMODE_UNKNOWN));
}
}