@@ -9,6 +9,7 @@ const adw = @import("adw");
9
9
const gtk = @import ("gtk" );
10
10
const gio = @import ("gio" );
11
11
const gobject = @import ("gobject" );
12
+ const glib = @import ("glib" );
12
13
13
14
const Allocator = std .mem .Allocator ;
14
15
const build_config = @import ("../../build_config.zig" );
@@ -1239,6 +1240,74 @@ pub fn showDesktopNotification(
1239
1240
c .g_application_send_notification (g_app , body .ptr , notification );
1240
1241
}
1241
1242
1243
+ /// Handle bell features.
1244
+ pub fn bell (self : * Surface ) void {
1245
+ if (self .app .config .@"bell-features" .system ) system : {
1246
+ // Handle "system" beep by calling the GTK "beep" API.
1247
+
1248
+ // FIXME: when surface is converted to zig-gobject
1249
+ const native = gtk .Widget .getNative (@ptrCast (@alignCast (self .overlay ))) orelse break :system ;
1250
+ const surface = native .getSurface () orelse break :system ;
1251
+ surface .beep ();
1252
+ }
1253
+ if (self .app .config .@"bell-features" .audio ) audio : {
1254
+ // Play a user-specified audio file.
1255
+
1256
+ const pathname , const optional = switch (self .app .config .@"bell-audio" orelse break :audio ) {
1257
+ .optional = > | path | .{ path , true },
1258
+ .required = > | path | .{ path , false },
1259
+ };
1260
+
1261
+ std .debug .assert (std .fs .path .isAbsolute (pathname ));
1262
+ const media_file = gtk .MediaFile .newForFilename (pathname );
1263
+
1264
+ if (! optional ) {
1265
+ _ = gobject .Object .signals .notify .connect (
1266
+ media_file ,
1267
+ ? * anyopaque ,
1268
+ gtkStreamError ,
1269
+ null ,
1270
+ .{ .detail = "error" },
1271
+ );
1272
+ }
1273
+ _ = gobject .Object .signals .notify .connect (
1274
+ media_file ,
1275
+ ? * anyopaque ,
1276
+ gtkStreamEnded ,
1277
+ null ,
1278
+ .{ .detail = "ended" },
1279
+ );
1280
+
1281
+ const media_stream = media_file .as (gtk .MediaStream );
1282
+ media_stream .setVolume (1.0 );
1283
+ media_stream .play ();
1284
+ }
1285
+ }
1286
+
1287
+ /// Handle a stream that is in an error state.
1288
+ fn gtkStreamError (media_file : * gtk.MediaFile , _ : * gobject.ParamSpec , _ : ? * anyopaque ) callconv (.C ) void {
1289
+ const path = path : {
1290
+ const file = media_file .getFile () orelse break :path null ;
1291
+ break :path file .getPath ();
1292
+ };
1293
+ defer if (path ) | p | glib .free (p );
1294
+
1295
+ const media_stream = media_file .as (gtk .MediaStream );
1296
+ const err = media_stream .getError () orelse return ;
1297
+
1298
+ log .warn ("error playing bell from {s}: {s} {d} {s}" , .{
1299
+ path orelse "<<unknown>>" ,
1300
+ glib .quarkToString (err .f_domain ),
1301
+ err .f_code ,
1302
+ err .f_message orelse "" ,
1303
+ });
1304
+ }
1305
+
1306
+ /// Stream is finished, release the memory.
1307
+ fn gtkStreamEnded (media_file : * gtk.MediaFile , _ : * gobject.ParamSpec , _ : ? * anyopaque ) callconv (.C ) void {
1308
+ media_file .unref ();
1309
+ }
1310
+
1242
1311
fn gtkRealize (area : * c.GtkGLArea , ud : ? * anyopaque ) callconv (.C ) void {
1243
1312
log .debug ("gl surface realized" , .{});
1244
1313
0 commit comments