diff --git a/bin/compton-trans b/bin/compton-trans index 612c35de2e..db41cf181f 100755 --- a/bin/compton-trans +++ b/bin/compton-trans @@ -114,7 +114,7 @@ fi if test x"$action" = x'reset'; then xwininfo -root -tree \ | sed -n 's/^ \(0x[[:xdigit:]]*\).*/\1/p' \ - | while IFS=$'\n' read wid; do + | while IFS=$(printf '\n') read wid; do xprop -id "$wid" -remove _NET_WM_WINDOW_OPACITY done exit 0 diff --git a/src/compton.c b/src/compton.c index 92935a3dba..8b4d7be1ed 100644 --- a/src/compton.c +++ b/src/compton.c @@ -2277,6 +2277,8 @@ static void unmap_win(session_t *ps, win *w) { if (!w || IsUnmapped == w->a.map_state) return; + if (w->destroyed) return; + // One last synchronization if (w->paint.pixmap) xr_sync(ps, w->paint.pixmap, &w->fence); @@ -3204,17 +3206,18 @@ circulate_win(session_t *ps, XCirculateEvent *ce) { } static void -finish_destroy_win(session_t *ps, Window id) { - win **prev = NULL, *w = NULL; +finish_destroy_win(session_t *ps, win *w) { + assert(w->destroyed); + win **prev = NULL, *i = NULL; #ifdef DEBUG_EVENTS - printf_dbgf("(%#010lx): Starting...\n", id); + printf_dbgf("(%#010lx): Starting...\n", w->id); #endif - for (prev = &ps->list; (w = *prev); prev = &w->next) { - if (w->id == id && w->destroyed) { + for (prev = &ps->list; (i = *prev); prev = &i->next) { + if (w == i) { #ifdef DEBUG_EVENTS - printf_dbgf("(%#010lx \"%s\"): %p\n", id, w->name, w); + printf_dbgf("(%#010lx \"%s\"): %p\n", w->id, w->name, w); #endif finish_unmap_win(ps, w); @@ -3240,7 +3243,7 @@ finish_destroy_win(session_t *ps, Window id) { static void destroy_callback(session_t *ps, win *w) { - finish_destroy_win(ps, w->id); + finish_destroy_win(ps, w); } static void @@ -3320,7 +3323,8 @@ xerror(Display __attribute__((unused)) *dpy, XErrorEvent *ev) { if (ev->request_code == ps->composite_opcode && ev->minor_code == X_CompositeRedirectSubwindows) { - fprintf(stderr, "Another composite manager is already running\n"); + fprintf(stderr, "Another composite manager is already running " + "(and does not handle _NET_WM_CM_Sn correctly)\n"); exit(1); } @@ -4348,6 +4352,16 @@ ev_screen_change_notify(session_t *ps, } } +inline static void +ev_selection_clear(session_t *ps, + XSelectionClearEvent __attribute__((unused)) *ev) { + // The only selection we own is the _NET_WM_CM_Sn selection. + // If we lose that one, we should exit. + fprintf(stderr, "Another composite manager started and " + "took the _NET_WM_CM_Sn selection.\n"); + exit(1); +} + #if defined(DEBUG_EVENTS) || defined(DEBUG_RESTACK) /** * Get a window's name from window ID. @@ -4440,6 +4454,9 @@ ev_handle(session_t *ps, XEvent *ev) { case PropertyNotify: ev_property_notify(ps, (XPropertyEvent *)ev); break; + case SelectionClear: + ev_selection_clear(ps, (XSelectionClearEvent *)ev); + break; default: if (ps->shape_exists && ev->type == ps->shape_event) { ev_shape_notify(ps, (XShapeEvent *) ev); @@ -4892,6 +4909,7 @@ register_cm(session_t *ps) { if (!ps->o.no_x_selection) { unsigned len = strlen(REGISTER_PROP) + 2; int s = ps->scr; + Atom atom; while (s >= 10) { ++len; @@ -4901,7 +4919,13 @@ register_cm(session_t *ps) { char *buf = malloc(len); snprintf(buf, len, REGISTER_PROP "%d", ps->scr); buf[len - 1] = '\0'; - XSetSelectionOwner(ps->dpy, get_atom(ps, buf), ps->reg_win, 0); + atom = get_atom(ps, buf); + + if (XGetSelectionOwner(ps->dpy, atom) != None) { + fprintf(stderr, "Another composite manager is already running\n"); + return false; + } + XSetSelectionOwner(ps->dpy, atom, ps->reg_win, 0); free(buf); } diff --git a/src/compton.h b/src/compton.h index 0e27a759f8..24ef2d5aeb 100644 --- a/src/compton.h +++ b/src/compton.h @@ -919,7 +919,7 @@ static void circulate_win(session_t *ps, XCirculateEvent *ce); static void -finish_destroy_win(session_t *ps, Window id); +finish_destroy_win(session_t *ps, win *w); static void destroy_callback(session_t *ps, win *w);