@@ -2277,6 +2277,8 @@ static void
2277
2277
unmap_win (session_t * ps , win * w ) {
2278
2278
if (!w || IsUnmapped == w -> a .map_state ) return ;
2279
2279
2280
+ if (w -> destroyed ) return ;
2281
+
2280
2282
// One last synchronization
2281
2283
if (w -> paint .pixmap )
2282
2284
xr_sync (ps , w -> paint .pixmap , & w -> fence );
@@ -3204,17 +3206,18 @@ circulate_win(session_t *ps, XCirculateEvent *ce) {
3204
3206
}
3205
3207
3206
3208
static void
3207
- finish_destroy_win (session_t * ps , Window id ) {
3208
- win * * prev = NULL , * w = NULL ;
3209
+ finish_destroy_win (session_t * ps , win * w ) {
3210
+ assert (w -> destroyed );
3211
+ win * * prev = NULL , * i = NULL ;
3209
3212
3210
3213
#ifdef DEBUG_EVENTS
3211
- printf_dbgf ("(%#010lx): Starting...\n" , id );
3214
+ printf_dbgf ("(%#010lx): Starting...\n" , w -> id );
3212
3215
#endif
3213
3216
3214
- for (prev = & ps -> list ; (w = * prev ); prev = & w -> next ) {
3215
- if (w -> id == id && w -> destroyed ) {
3217
+ for (prev = & ps -> list ; (i = * prev ); prev = & i -> next ) {
3218
+ if (w == i ) {
3216
3219
#ifdef DEBUG_EVENTS
3217
- printf_dbgf ("(%#010lx \"%s\"): %p\n" , id , w -> name , w );
3220
+ printf_dbgf ("(%#010lx \"%s\"): %p\n" , w -> id , w -> name , w );
3218
3221
#endif
3219
3222
3220
3223
finish_unmap_win (ps , w );
@@ -3240,7 +3243,7 @@ finish_destroy_win(session_t *ps, Window id) {
3240
3243
3241
3244
static void
3242
3245
destroy_callback (session_t * ps , win * w ) {
3243
- finish_destroy_win (ps , w -> id );
3246
+ finish_destroy_win (ps , w );
3244
3247
}
3245
3248
3246
3249
static void
@@ -3320,7 +3323,8 @@ xerror(Display __attribute__((unused)) *dpy, XErrorEvent *ev) {
3320
3323
3321
3324
if (ev -> request_code == ps -> composite_opcode
3322
3325
&& ev -> minor_code == X_CompositeRedirectSubwindows ) {
3323
- fprintf (stderr , "Another composite manager is already running\n" );
3326
+ fprintf (stderr , "Another composite manager is already running "
3327
+ "(and does not handle _NET_WM_CM_Sn correctly)\n" );
3324
3328
exit (1 );
3325
3329
}
3326
3330
@@ -4348,6 +4352,16 @@ ev_screen_change_notify(session_t *ps,
4348
4352
}
4349
4353
}
4350
4354
4355
+ inline static void
4356
+ ev_selection_clear (session_t * ps ,
4357
+ XSelectionClearEvent __attribute__((unused )) * ev ) {
4358
+ // The only selection we own is the _NET_WM_CM_Sn selection.
4359
+ // If we lose that one, we should exit.
4360
+ fprintf (stderr , "Another composite manager started and "
4361
+ "took the _NET_WM_CM_Sn selection.\n" );
4362
+ exit (1 );
4363
+ }
4364
+
4351
4365
#if defined(DEBUG_EVENTS ) || defined(DEBUG_RESTACK )
4352
4366
/**
4353
4367
* Get a window's name from window ID.
@@ -4440,6 +4454,9 @@ ev_handle(session_t *ps, XEvent *ev) {
4440
4454
case PropertyNotify :
4441
4455
ev_property_notify (ps , (XPropertyEvent * )ev );
4442
4456
break ;
4457
+ case SelectionClear :
4458
+ ev_selection_clear (ps , (XSelectionClearEvent * )ev );
4459
+ break ;
4443
4460
default :
4444
4461
if (ps -> shape_exists && ev -> type == ps -> shape_event ) {
4445
4462
ev_shape_notify (ps , (XShapeEvent * ) ev );
@@ -4892,6 +4909,7 @@ register_cm(session_t *ps) {
4892
4909
if (!ps -> o .no_x_selection ) {
4893
4910
unsigned len = strlen (REGISTER_PROP ) + 2 ;
4894
4911
int s = ps -> scr ;
4912
+ Atom atom ;
4895
4913
4896
4914
while (s >= 10 ) {
4897
4915
++ len ;
@@ -4901,7 +4919,13 @@ register_cm(session_t *ps) {
4901
4919
char * buf = malloc (len );
4902
4920
snprintf (buf , len , REGISTER_PROP "%d" , ps -> scr );
4903
4921
buf [len - 1 ] = '\0' ;
4904
- XSetSelectionOwner (ps -> dpy , get_atom (ps , buf ), ps -> reg_win , 0 );
4922
+ atom = get_atom (ps , buf );
4923
+
4924
+ if (XGetSelectionOwner (ps -> dpy , atom ) != None ) {
4925
+ fprintf (stderr , "Another composite manager is already running\n" );
4926
+ return false;
4927
+ }
4928
+ XSetSelectionOwner (ps -> dpy , atom , ps -> reg_win , 0 );
4905
4929
free (buf );
4906
4930
}
4907
4931
0 commit comments