@@ -83,13 +83,47 @@ static void layer_surface_handle_configure(void *data,
83
83
send_frame ();
84
84
}
85
85
86
- static void layer_surface_handle_closed (void * data ,
87
- struct zwlr_layer_surface_v1 * surface ) {
88
- LOG_I ("Destroying layer" );
89
- if (ctx .layer_surface )
90
- zwlr_layer_surface_v1_destroy (ctx .layer_surface );
91
- ctx .layer_surface = NULL ;
86
+ static void xdg_surface_handle_configure (void * data ,
87
+ struct xdg_surface * surface ,
88
+ uint32_t serial ) {
89
+ xdg_surface_ack_configure (ctx .xdg_surface , serial );
90
+
91
+ if (ctx .configured ) {
92
+ wl_surface_commit (ctx .surface );
93
+ return ;
94
+ }
95
+
96
+ ctx .configured = true;
97
+
98
+ send_frame ();
99
+ }
92
100
101
+ static void xdg_toplevel_handle_configure (void * data ,
102
+ struct xdg_toplevel * xdg_toplevel ,
103
+ int32_t width ,
104
+ int32_t height ,
105
+ struct wl_array * states ) {
106
+ if (width == ctx .width && height == ctx .height ) {
107
+ return ;
108
+ }
109
+
110
+ ctx .configured = false;
111
+ ctx .width = width ;
112
+ ctx .height = height ;
113
+ }
114
+
115
+ static void xdg_toplevel_wm_capabilities (void * data ,
116
+ struct xdg_toplevel * xdg_toplevel ,
117
+ struct wl_array * capabilities ) {
118
+ }
119
+
120
+ static void xdg_toplevel_handle_configure_bounds (void * data ,
121
+ struct xdg_toplevel * xdg_toplevel ,
122
+ int32_t width ,
123
+ int32_t height ) {
124
+ }
125
+
126
+ static void surface_handle_closed (void ) {
93
127
if (ctx .surface )
94
128
wl_surface_destroy (ctx .surface );
95
129
ctx .surface = NULL ;
@@ -111,11 +145,46 @@ static void layer_surface_handle_closed(void *data,
111
145
}
112
146
}
113
147
148
+ static void layer_surface_handle_closed (void * data ,
149
+ struct zwlr_layer_surface_v1 * surface ) {
150
+ LOG_I ("Destroying layer" );
151
+ if (ctx .layer_surface )
152
+ zwlr_layer_surface_v1_destroy (ctx .layer_surface );
153
+ ctx .layer_surface = NULL ;
154
+
155
+ surface_handle_closed ();
156
+ }
157
+
158
+ static void xdg_toplevel_handle_close (void * data ,
159
+ struct xdg_toplevel * surface ) {
160
+ LOG_I ("Destroying layer" );
161
+ if (ctx .xdg_toplevel )
162
+ xdg_toplevel_destroy (ctx .xdg_toplevel );
163
+ ctx .xdg_toplevel = NULL ;
164
+ if (ctx .xdg_surface )
165
+ xdg_surface_destroy (ctx .xdg_surface );
166
+ ctx .xdg_surface = NULL ;
167
+
168
+ surface_handle_closed ();
169
+ }
170
+
114
171
static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
115
172
.configure = layer_surface_handle_configure ,
116
173
.closed = layer_surface_handle_closed ,
117
174
};
118
175
176
+ static const struct xdg_surface_listener xdg_surface_listener = {
177
+ .configure = xdg_surface_handle_configure ,
178
+ };
179
+
180
+ static const struct xdg_toplevel_listener xdg_toplevel_listener = {
181
+ .configure = xdg_toplevel_handle_configure ,
182
+ .close = xdg_toplevel_handle_close ,
183
+ .configure_bounds = xdg_toplevel_handle_configure_bounds ,
184
+ .wm_capabilities = xdg_toplevel_wm_capabilities ,
185
+ };
186
+
187
+
119
188
// Warning, can return NULL
120
189
static struct dunst_output * get_configured_output (void ) {
121
190
int n = 0 ;
@@ -164,6 +233,9 @@ static void handle_global(void *data, struct wl_registry *registry,
164
233
} else if (strcmp (interface , zwlr_layer_shell_v1_interface .name ) == 0 ) {
165
234
ctx .layer_shell = wl_registry_bind (registry , name ,
166
235
& zwlr_layer_shell_v1_interface , 1 );
236
+ } else if (strcmp (interface , xdg_wm_base_interface .name ) == 0 ) {
237
+ ctx .xdg_shell = wl_registry_bind (registry , name ,
238
+ & xdg_wm_base_interface , 5 );
167
239
} else if (strcmp (interface , wl_seat_interface .name ) == 0 ) {
168
240
create_seat (registry , name , version );
169
241
LOG_D ("Binding to seat %i" , name );
@@ -262,8 +334,12 @@ bool wl_init(void) {
262
334
return false;
263
335
}
264
336
if (ctx .layer_shell == NULL ) {
265
- LOG_W ("compositor doesn't support zwlr_layer_shell_v1" );
266
- return false;
337
+ if (ctx .xdg_shell == NULL ) {
338
+ LOG_W ("compositor doesn't support zwlr_layer_shell_v1 or xdg_shell" );
339
+ return false;
340
+ } else {
341
+ LOG_W ("compositor doesn't support zwlr_layer_shell_v1, falling back to xdg_shell. Notification window position will be set by the compositor." );
342
+ }
267
343
}
268
344
if (wl_list_empty (& ctx .seats )) {
269
345
LOG_W ("no seat was found, so dunst cannot see input" );
@@ -334,6 +410,12 @@ void wl_deinit(void) {
334
410
if (ctx .layer_surface != NULL ) {
335
411
g_clear_pointer (& ctx .layer_surface , zwlr_layer_surface_v1_destroy );
336
412
}
413
+ if (ctx .xdg_toplevel != NULL ) {
414
+ g_clear_pointer (& ctx .xdg_toplevel , xdg_toplevel_destroy );
415
+ }
416
+ if (ctx .xdg_surface != NULL ) {
417
+ g_clear_pointer (& ctx .xdg_surface , xdg_surface_destroy );
418
+ }
337
419
if (ctx .surface != NULL ) {
338
420
g_clear_pointer (& ctx .surface , wl_surface_destroy );
339
421
}
@@ -371,6 +453,9 @@ void wl_deinit(void) {
371
453
if (ctx .layer_shell )
372
454
g_clear_pointer (& ctx .layer_shell , zwlr_layer_shell_v1_destroy );
373
455
456
+ if (ctx .xdg_shell )
457
+ g_clear_pointer (& ctx .xdg_shell , xdg_wm_base_destroy );
458
+
374
459
if (ctx .compositor )
375
460
g_clear_pointer (& ctx .compositor , wl_compositor_destroy );
376
461
@@ -411,6 +496,14 @@ static void send_frame(void) {
411
496
zwlr_layer_surface_v1_destroy (ctx .layer_surface );
412
497
ctx .layer_surface = NULL ;
413
498
}
499
+ if (ctx .xdg_toplevel != NULL ) {
500
+ xdg_toplevel_destroy (ctx .xdg_toplevel );
501
+ ctx .xdg_toplevel = NULL ;
502
+ }
503
+ if (ctx .xdg_surface != NULL ) {
504
+ xdg_surface_destroy (ctx .xdg_surface );
505
+ ctx .xdg_surface = NULL ;
506
+ }
414
507
if (ctx .surface != NULL ) {
415
508
wl_surface_destroy (ctx .surface );
416
509
ctx .surface = NULL ;
@@ -443,20 +536,31 @@ static void send_frame(void) {
443
536
// If we've made it here, there is something to draw. If the surface
444
537
// doesn't exist (this is the first notification, or we moved to a
445
538
// different output), we need to create it.
446
- if (ctx .layer_surface == NULL ) {
447
- struct wl_output * wl_output = NULL ;
448
- if (output != NULL ) {
449
- wl_output = output -> wl_output ;
450
- }
539
+ if (ctx .layer_surface == NULL && ctx .xdg_surface == NULL ) {
451
540
ctx .layer_surface_output = output ;
452
541
ctx .surface = wl_compositor_create_surface (ctx .compositor );
453
542
wl_surface_add_listener (ctx .surface , & surface_listener , NULL );
454
543
455
- ctx .layer_surface = zwlr_layer_shell_v1_get_layer_surface (
456
- ctx .layer_shell , ctx .surface , wl_output ,
457
- settings .layer , "notifications" );
458
- zwlr_layer_surface_v1_add_listener (ctx .layer_surface ,
459
- & layer_surface_listener , NULL );
544
+ if (ctx .layer_shell ) {
545
+ struct wl_output * wl_output = NULL ;
546
+ if (output != NULL ) {
547
+ wl_output = output -> wl_output ;
548
+ }
549
+
550
+ ctx .layer_surface = zwlr_layer_shell_v1_get_layer_surface (
551
+ ctx .layer_shell , ctx .surface , wl_output ,
552
+ settings .layer , "notifications" );
553
+ zwlr_layer_surface_v1_add_listener (ctx .layer_surface ,
554
+ & layer_surface_listener , NULL );
555
+ } else {
556
+ ctx .xdg_surface = xdg_wm_base_get_xdg_surface (
557
+ ctx .xdg_shell , ctx .surface );
558
+ xdg_surface_add_listener (ctx .xdg_surface , & xdg_surface_listener , NULL );
559
+
560
+ ctx .xdg_toplevel = xdg_surface_get_toplevel (ctx .xdg_surface );
561
+ xdg_toplevel_set_app_id (ctx .xdg_toplevel , "org.knopwob.dunst" );
562
+ xdg_toplevel_add_listener (ctx .xdg_toplevel , & xdg_toplevel_listener , NULL );
563
+ }
460
564
461
565
// Because we're creating a new surface, we aren't going to draw
462
566
// anything into it during this call. We don't know what size the
@@ -468,46 +572,50 @@ static void send_frame(void) {
468
572
// block to let it set the size for us.
469
573
}
470
574
471
- assert (ctx .layer_surface );
575
+ assert (ctx .layer_surface || ctx . xdg_surface );
472
576
473
577
// We now want to resize the surface if it isn't the right size. If the
474
578
// surface is brand new, it doesn't even have a size yet. If it already
475
579
// exists, we might need to resize if the list of notifications has changed
476
580
// since the last time we drew.
477
581
if (ctx .height != height || ctx .width != width ) {
478
582
struct dimensions dim = ctx .cur_dim ;
479
- // Set window size
480
- zwlr_layer_surface_v1_set_size (ctx .layer_surface ,
583
+ if (ctx .layer_surface ) {
584
+ // Set window size
585
+ zwlr_layer_surface_v1_set_size (ctx .layer_surface ,
481
586
dim .w , dim .h );
482
587
483
- // Put the window at the right position
484
- zwlr_layer_surface_v1_set_anchor (ctx .layer_surface ,
485
- settings .origin );
486
- zwlr_layer_surface_v1_set_margin (ctx .layer_surface ,
487
- // Offsets where no anchors are specified are
488
- // ignored. We can safely assume the offset is
489
- // positive.
490
- settings .offset .y , // top
491
- settings .offset .x , // right
492
- settings .offset .y , // bottom
493
- settings .offset .x );// left
588
+ // Put the window at the right position
589
+ zwlr_layer_surface_v1_set_anchor (ctx .layer_surface ,
590
+ settings .origin );
591
+ zwlr_layer_surface_v1_set_margin (ctx .layer_surface ,
592
+ // Offsets where no anchors are specified are
593
+ // ignored. We can safely assume the offset is
594
+ // positive.
595
+ settings .offset .y , // top
596
+ settings .offset .x , // right
597
+ settings .offset .y , // bottom
598
+ settings .offset .x );// left
599
+ } else {
600
+ // Just set the window size, as positioning is not part of the xdg-shell protocol
601
+ xdg_surface_set_window_geometry (ctx .xdg_surface , 0 , 0 , dim .w , dim .h );
602
+ }
494
603
495
604
wl_surface_commit (ctx .surface );
496
605
497
- // Now we're going to bail without drawing anything. This gives the
498
- // compositor a chance to create the surface and tell us what size we
499
- // were actually granted, which may be smaller than what we asked for
500
- // depending on the screen size and layout of other layer surfaces.
501
- // This information is provided in layer_surface_handle_configure,
502
- // which will then call send_frame again. When that call happens, the
503
- // layer surface will exist and the height will hopefully match what
504
- // we asked for. That means we won't return here, and will actually
505
- // draw into the surface down below.
506
- // TODO: If the compositor doesn't send a configure with the size we
507
- // requested, we'll enter an infinite loop. We need to keep track of
508
- // the fact that a request was sent separately from what height we are.
509
- wl_display_roundtrip (ctx .display );
510
- return ;
606
+ if (!ctx .configured ) {
607
+ // Now we're going to bail without drawing anything. This gives the
608
+ // compositor a chance to create the surface and tell us what size we
609
+ // were actually granted, which may be smaller than what we asked for
610
+ // depending on the screen size and layout of other layer surfaces.
611
+ // This information is provided in layer_surface_handle_configure,
612
+ // which will then call send_frame again. When that call happens, the
613
+ // layer surface will exist and the height will hopefully match what
614
+ // we asked for. That means we won't return here, and will actually
615
+ // draw into the surface down below.
616
+ wl_display_roundtrip (ctx .display );
617
+ return ;
618
+ }
511
619
}
512
620
513
621
assert (ctx .configured );
0 commit comments