@@ -40,7 +40,7 @@ struct window_wl {
40
40
cairo_t * c_ctx ;
41
41
};
42
42
43
- struct wl_ctx ctx ;
43
+ struct wl_ctx ctx = { 0 } ;
44
44
45
45
static void surface_handle_enter (void * data , struct wl_surface * surface ,
46
46
struct wl_output * wl_output ) {
@@ -83,13 +83,32 @@ 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
+ }
92
95
96
+ ctx .configured = true;
97
+
98
+ send_frame ();
99
+ }
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
+ // TODO We currently don't support the compositor
107
+ // providing us with a size different to our requested size.
108
+ // Therefore just ignore the suggested surface size.
109
+ }
110
+
111
+ static void surface_handle_closed (void ) {
93
112
if (ctx .surface )
94
113
wl_surface_destroy (ctx .surface );
95
114
ctx .surface = NULL ;
@@ -111,11 +130,53 @@ static void layer_surface_handle_closed(void *data,
111
130
}
112
131
}
113
132
133
+ static void layer_surface_handle_closed (void * data ,
134
+ struct zwlr_layer_surface_v1 * surface ) {
135
+ LOG_I ("Destroying layer" );
136
+ if (ctx .layer_surface )
137
+ zwlr_layer_surface_v1_destroy (ctx .layer_surface );
138
+ ctx .layer_surface = NULL ;
139
+
140
+ surface_handle_closed ();
141
+ }
142
+
143
+ static void xdg_toplevel_handle_close (void * data ,
144
+ struct xdg_toplevel * surface ) {
145
+ LOG_I ("Destroying layer" );
146
+ if (ctx .xdg_toplevel )
147
+ xdg_toplevel_destroy (ctx .xdg_toplevel );
148
+ ctx .xdg_toplevel = NULL ;
149
+ if (ctx .xdg_surface )
150
+ xdg_surface_destroy (ctx .xdg_surface );
151
+ ctx .xdg_surface = NULL ;
152
+
153
+ surface_handle_closed ();
154
+ }
155
+
156
+ static void xdg_wm_base_handle_ping (void * data ,
157
+ struct xdg_wm_base * xdg_wm_base ,
158
+ uint32_t serial ) {
159
+ xdg_wm_base_pong (ctx .xdg_shell , serial );
160
+ }
161
+
114
162
static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
115
163
.configure = layer_surface_handle_configure ,
116
164
.closed = layer_surface_handle_closed ,
117
165
};
118
166
167
+ static const struct xdg_wm_base_listener xdg_wm_base_listener = {
168
+ .ping = xdg_wm_base_handle_ping ,
169
+ };
170
+
171
+ static const struct xdg_surface_listener xdg_surface_listener = {
172
+ .configure = xdg_surface_handle_configure ,
173
+ };
174
+
175
+ static const struct xdg_toplevel_listener xdg_toplevel_listener = {
176
+ .configure = xdg_toplevel_handle_configure ,
177
+ .close = xdg_toplevel_handle_close ,
178
+ };
179
+
119
180
// Warning, can return NULL
120
181
static struct dunst_output * get_configured_output (void ) {
121
182
int n = 0 ;
@@ -164,6 +225,10 @@ static void handle_global(void *data, struct wl_registry *registry,
164
225
} else if (strcmp (interface , zwlr_layer_shell_v1_interface .name ) == 0 ) {
165
226
ctx .layer_shell = wl_registry_bind (registry , name ,
166
227
& zwlr_layer_shell_v1_interface , 1 );
228
+ } else if (strcmp (interface , xdg_wm_base_interface .name ) == 0 ) {
229
+ ctx .xdg_shell = wl_registry_bind (registry , name ,
230
+ & xdg_wm_base_interface , 1 );
231
+ xdg_wm_base_add_listener (ctx .xdg_shell , & xdg_wm_base_listener , NULL );
167
232
} else if (strcmp (interface , wl_seat_interface .name ) == 0 ) {
168
233
create_seat (registry , name , version );
169
234
LOG_D ("Binding to seat %i" , name );
@@ -263,8 +328,12 @@ bool wl_init(void) {
263
328
return false;
264
329
}
265
330
if (ctx .layer_shell == NULL ) {
266
- LOG_W ("compositor doesn't support zwlr_layer_shell_v1" );
267
- return false;
331
+ if (ctx .xdg_shell == NULL ) {
332
+ LOG_W ("compositor doesn't support zwlr_layer_shell_v1 or xdg_shell" );
333
+ return false;
334
+ } else {
335
+ LOG_W ("compositor doesn't support zwlr_layer_shell_v1, falling back to xdg_shell. Notification window position will be set by the compositor." );
336
+ }
268
337
}
269
338
if (wl_list_empty (& ctx .seats )) {
270
339
LOG_W ("no seat was found, so dunst cannot see input" );
@@ -335,6 +404,12 @@ void wl_deinit(void) {
335
404
if (ctx .layer_surface != NULL ) {
336
405
g_clear_pointer (& ctx .layer_surface , zwlr_layer_surface_v1_destroy );
337
406
}
407
+ if (ctx .xdg_toplevel != NULL ) {
408
+ g_clear_pointer (& ctx .xdg_toplevel , xdg_toplevel_destroy );
409
+ }
410
+ if (ctx .xdg_surface != NULL ) {
411
+ g_clear_pointer (& ctx .xdg_surface , xdg_surface_destroy );
412
+ }
338
413
if (ctx .frame_callback ) {
339
414
g_clear_pointer (& ctx .frame_callback , wl_callback_destroy );
340
415
}
@@ -376,6 +451,9 @@ void wl_deinit(void) {
376
451
if (ctx .layer_shell )
377
452
g_clear_pointer (& ctx .layer_shell , zwlr_layer_shell_v1_destroy );
378
453
454
+ if (ctx .xdg_shell )
455
+ g_clear_pointer (& ctx .xdg_shell , xdg_wm_base_destroy );
456
+
379
457
if (ctx .compositor )
380
458
g_clear_pointer (& ctx .compositor , wl_compositor_destroy );
381
459
@@ -426,6 +504,14 @@ static void send_frame(void) {
426
504
zwlr_layer_surface_v1_destroy (ctx .layer_surface );
427
505
ctx .layer_surface = NULL ;
428
506
}
507
+ if (ctx .xdg_toplevel != NULL ) {
508
+ xdg_toplevel_destroy (ctx .xdg_toplevel );
509
+ ctx .xdg_toplevel = NULL ;
510
+ }
511
+ if (ctx .xdg_surface != NULL ) {
512
+ xdg_surface_destroy (ctx .xdg_surface );
513
+ ctx .xdg_surface = NULL ;
514
+ }
429
515
if (ctx .surface != NULL ) {
430
516
wl_surface_destroy (ctx .surface );
431
517
ctx .surface = NULL ;
@@ -458,20 +544,32 @@ static void send_frame(void) {
458
544
// If we've made it here, there is something to draw. If the surface
459
545
// doesn't exist (this is the first notification, or we moved to a
460
546
// different output), we need to create it.
461
- if (ctx .layer_surface == NULL ) {
462
- struct wl_output * wl_output = NULL ;
463
- if (output != NULL ) {
464
- wl_output = output -> wl_output ;
465
- }
547
+ if (ctx .layer_surface == NULL && ctx .xdg_surface == NULL ) {
466
548
ctx .layer_surface_output = output ;
467
549
ctx .surface = wl_compositor_create_surface (ctx .compositor );
468
550
wl_surface_add_listener (ctx .surface , & surface_listener , NULL );
469
551
470
- ctx .layer_surface = zwlr_layer_shell_v1_get_layer_surface (
471
- ctx .layer_shell , ctx .surface , wl_output ,
472
- settings .layer , "notifications" );
473
- zwlr_layer_surface_v1_add_listener (ctx .layer_surface ,
474
- & layer_surface_listener , NULL );
552
+ if (ctx .layer_shell ) {
553
+ struct wl_output * wl_output = NULL ;
554
+ if (output != NULL ) {
555
+ wl_output = output -> wl_output ;
556
+ }
557
+
558
+ ctx .layer_surface = zwlr_layer_shell_v1_get_layer_surface (
559
+ ctx .layer_shell , ctx .surface , wl_output ,
560
+ settings .layer , "notifications" );
561
+ zwlr_layer_surface_v1_add_listener (ctx .layer_surface ,
562
+ & layer_surface_listener , NULL );
563
+ } else {
564
+ ctx .xdg_surface = xdg_wm_base_get_xdg_surface (
565
+ ctx .xdg_shell , ctx .surface );
566
+ xdg_surface_add_listener (ctx .xdg_surface , & xdg_surface_listener , NULL );
567
+
568
+ ctx .xdg_toplevel = xdg_surface_get_toplevel (ctx .xdg_surface );
569
+ xdg_toplevel_set_title (ctx .xdg_toplevel , "Dunst" );
570
+ xdg_toplevel_set_app_id (ctx .xdg_toplevel , "org.knopwob.dunst" );
571
+ xdg_toplevel_add_listener (ctx .xdg_toplevel , & xdg_toplevel_listener , NULL );
572
+ }
475
573
476
574
// Because we're creating a new surface, we aren't going to draw
477
575
// anything into it during this call. We don't know what size the
@@ -483,13 +581,22 @@ static void send_frame(void) {
483
581
// block to let it set the size for us.
484
582
}
485
583
486
- assert (ctx .layer_surface );
584
+ assert (ctx .layer_surface || ctx . xdg_surface );
487
585
488
586
// We now want to resize the surface if it isn't the right size. If the
489
587
// surface is brand new, it doesn't even have a size yet. If it already
490
588
// exists, we might need to resize if the list of notifications has changed
491
589
// since the last time we drew.
492
- if (ctx .height != height || ctx .width != width ) {
590
+ // We only do this for layer_surface, as xdg_surface only needs configuration
591
+ // using xdg_surface_set_window_geometry if it differs from the buffer dimension.
592
+ // Furthermore mutter intersects the buffer dimension and the window geometry.
593
+ // As we directly do a commit+roundtrip, mutter will complain, as the missing
594
+ // buffer causes a 0,0 intersection and also causes a size of 0,0 in the
595
+ // configure event.
596
+ if (ctx .layer_surface && (ctx .height != height || ctx .width != width )) {
597
+ // TODO If the surface is already configured we should rather
598
+ // adjust to the size the compositor requested instead of just trying
599
+ // to set our preferred size again.
493
600
struct dimensions dim = ctx .cur_dim ;
494
601
// Set window size
495
602
zwlr_layer_surface_v1_set_size (ctx .layer_surface ,
@@ -507,6 +614,14 @@ static void send_frame(void) {
507
614
settings .offset .y , // bottom
508
615
settings .offset .x );// left
509
616
617
+ // TODO Check if this is really necessary, as it causes an infinite
618
+ // loop if the compositor doesn't configure our desired surface size
619
+ // Without it wlroots 0.18.2 creates a wrong configure serial error
620
+ // which seems to be caused by an ack_configure without an commit.
621
+ ctx .configured = false;
622
+ }
623
+
624
+ if (!ctx .configured ) {
510
625
wl_surface_commit (ctx .surface );
511
626
512
627
// Now we're going to bail without drawing anything. This gives the
@@ -518,9 +633,6 @@ static void send_frame(void) {
518
633
// layer surface will exist and the height will hopefully match what
519
634
// we asked for. That means we won't return here, and will actually
520
635
// draw into the surface down below.
521
- // TODO: If the compositor doesn't send a configure with the size we
522
- // requested, we'll enter an infinite loop. We need to keep track of
523
- // the fact that a request was sent separately from what height we are.
524
636
wl_display_roundtrip (ctx .display );
525
637
return ;
526
638
}
@@ -556,6 +668,8 @@ static const struct wl_callback_listener frame_listener = {
556
668
557
669
static void schedule_frame_and_commit (void ) {
558
670
if (ctx .frame_callback ) {
671
+ // don't commit, as it probably won't make it to the display and
672
+ // therefore waste resources
559
673
return ;
560
674
}
561
675
if (ctx .surface == NULL ) {
0 commit comments