@@ -14,6 +14,8 @@ const configpkg = @import("../../config.zig");
14
14
const font = @import ("../../font/main.zig" );
15
15
const input = @import ("../../input.zig" );
16
16
const CoreSurface = @import ("../../Surface.zig" );
17
+ const gtk = @import ("gtk" );
18
+ const gobject = @import ("gobject" );
17
19
18
20
const App = @import ("App.zig" );
19
21
const Color = configpkg .Config .Color ;
@@ -73,6 +75,7 @@ pub const DerivedConfig = struct {
73
75
gtk_wide_tabs : bool ,
74
76
gtk_toolbar_style : configpkg.Config.GtkToolbarStyle ,
75
77
78
+ title : ? [:0 ]const u8 ,
76
79
maximize : bool ,
77
80
fullscreen : bool ,
78
81
window_decoration : configpkg.Config.WindowDecoration ,
@@ -88,6 +91,7 @@ pub const DerivedConfig = struct {
88
91
.gtk_wide_tabs = config .@"gtk-wide-tabs" ,
89
92
.gtk_toolbar_style = config .@"gtk-toolbar-style" ,
90
93
94
+ .title = config .title ,
91
95
.maximize = config .maximize ,
92
96
.fullscreen = config .fullscreen ,
93
97
.window_decoration = config .@"window-decoration" ,
@@ -130,17 +134,10 @@ pub fn init(self: *Window, app: *App) !void {
130
134
131
135
self .window = @ptrCast (@alignCast (gtk_widget ));
132
136
133
- c .gtk_window_set_title (self .window , "Ghostty" );
134
- c .gtk_window_set_default_size (self .window , 1000 , 600 );
135
- c .gtk_widget_add_css_class (gtk_widget , "window" );
136
- c .gtk_widget_add_css_class (gtk_widget , "terminal-window" );
137
-
138
137
// GTK4 grabs F10 input by default to focus the menubar icon. We want
139
138
// to disable this so that terminal programs can capture F10 (such as htop)
140
139
c .gtk_window_set_handle_menubar_accel (self .window , 0 );
141
140
142
- c .gtk_window_set_icon_name (self .window , build_config .bundle_id );
143
-
144
141
// Create our box which will hold our widgets in the main content area.
145
142
const box = c .gtk_box_new (c .GTK_ORIENTATION_VERTICAL , 0 );
146
143
@@ -353,11 +350,7 @@ pub fn init(self: *Window, app: *App) !void {
353
350
if (! self .config .gtk_wide_tabs ) c .adw_tab_bar_set_expand_tabs (tab_bar , 0 );
354
351
}
355
352
356
- // If we want the window to be maximized, we do that here.
357
- if (self .config .maximize ) c .gtk_window_maximize (self .window );
358
-
359
- // If we are in fullscreen mode, new windows start fullscreen.
360
- if (self .config .fullscreen ) c .gtk_window_fullscreen (self .window );
353
+ try self .initAppearance ();
361
354
362
355
// Show the window
363
356
c .gtk_widget_show (gtk_widget );
@@ -367,9 +360,13 @@ pub fn updateConfig(
367
360
self : * Window ,
368
361
config : * const configpkg.Config ,
369
362
) ! void {
370
- // avoid multiple reconfigs when we have many surfaces contained in this
371
- // window using the integer value of config as a simple marker to know if
372
- // we've "seen" this particular config before
363
+ // HACK:
364
+ // Avoid multiple reconfigs when we have many surfaces contained in this
365
+ // window using the integer value of the config pointer as a simple marker
366
+ // to know if we've "seen" this particular config before.
367
+ //
368
+ // For the long run we should try to make the flow of config updates saner
369
+ // and avoid manual deduplication. See #5947 for more information.
373
370
const this_config = @intFromPtr (config );
374
371
if (self .last_config == this_config ) return ;
375
372
self .last_config = this_config ;
@@ -380,23 +377,47 @@ pub fn updateConfig(
380
377
try self .syncAppearance ();
381
378
}
382
379
380
+ /// Initializes the appearance of the window.
381
+ ///
382
+ /// Not all appearance changes *should* be applied when a config option is
383
+ /// reloaded (for instance, the maximize and fullscreen settings should only
384
+ /// apply to new windows), so we apply them here.
385
+ pub fn initAppearance (self : * Window ) ! void {
386
+ // FIXME: Remove once self.window has been migrated to use zig-gobject
387
+ const window : * gtk.Window = @ptrCast (self .window );
388
+
389
+ window .setTitle (self .config .title orelse "Ghostty" );
390
+ window .setDefaultSize (1000 , 600 );
391
+ window .as (gtk .Widget ).addCssClass ("window" );
392
+ window .as (gtk .Widget ).addCssClass ("terminal-window" );
393
+ window .setIconName (build_config .bundle_id );
394
+
395
+ if (self .config .maximize ) window .maximize ();
396
+ if (self .config .fullscreen ) window .fullscreen ();
397
+
398
+ try self .syncAppearance ();
399
+ }
400
+
383
401
/// Updates appearance based on config settings. Will be called once upon window
384
402
/// realization, every time the config is reloaded, and every time a window state
385
403
/// is toggled (un-/maximized, un-/fullscreened, window decorations toggled, etc.)
386
404
///
387
405
/// TODO: Many of the initial style settings in `create` could possibly be made
388
406
/// reactive by moving them here.
389
407
pub fn syncAppearance (self : * Window ) ! void {
408
+ // FIXME: Remove once self.window has been migrated to use zig-gobject
409
+ const window : * gtk.Window = @ptrCast (self .window );
410
+
390
411
const csd_enabled = self .winproto .clientSideDecorationEnabled ();
391
- c . gtk_window_set_decorated ( self . window , @intFromBool (csd_enabled ));
412
+ window . setDecorated ( @intFromBool (csd_enabled ));
392
413
393
414
// Fix any artifacting that may occur in window corners. The .ssd CSS
394
415
// class is defined in the GtkWindow documentation:
395
416
// https://docs.gtk.org/gtk4/class.Window.html#css-nodes. A definition
396
417
// for .ssd is provided by GTK and Adwaita.
397
- toggleCssClass (@ptrCast ( self . window ) , "csd" , csd_enabled );
398
- toggleCssClass (@ptrCast ( self . window ) , "ssd" , ! csd_enabled );
399
- toggleCssClass (@ptrCast ( self . window ) , "no-border-radius" , ! csd_enabled );
418
+ toggleCssClass (window , "csd" , csd_enabled );
419
+ toggleCssClass (window , "ssd" , ! csd_enabled );
420
+ toggleCssClass (window , "no-border-radius" , ! csd_enabled );
400
421
401
422
self .headerbar .setVisible (visible : {
402
423
// Never display the header bar when CSDs are disabled.
@@ -414,7 +435,7 @@ pub fn syncAppearance(self: *Window) !void {
414
435
});
415
436
416
437
toggleCssClass (
417
- @ptrCast ( self . window ) ,
438
+ window ,
418
439
"background" ,
419
440
self .config .background_opacity >= 1 ,
420
441
);
@@ -423,7 +444,7 @@ pub fn syncAppearance(self: *Window) !void {
423
444
// GTK version is before 4.16. The conditional is because above 4.16
424
445
// we use GTK CSS color variables.
425
446
toggleCssClass (
426
- @ptrCast ( self . window ) ,
447
+ window ,
427
448
"window-theme-ghostty" ,
428
449
! version .atLeast (4 , 16 , 0 ) and self .config .window_theme == .ghostty ,
429
450
);
@@ -451,23 +472,17 @@ pub fn syncAppearance(self: *Window) !void {
451
472
self .winproto .syncAppearance () catch | err | {
452
473
log .warn ("failed to sync winproto appearance error={}" , .{err });
453
474
};
454
-
455
- toggleCssClass (
456
- @ptrCast (self .window ),
457
- "background" ,
458
- self .config .background_opacity >= 1 ,
459
- );
460
475
}
461
476
462
477
fn toggleCssClass (
463
- widget : * c.GtkWidget ,
478
+ widget : anytype ,
464
479
class : [:0 ]const u8 ,
465
480
v : bool ,
466
481
) void {
467
482
if (v ) {
468
- c . gtk_widget_add_css_class ( widget , class );
483
+ widget . as ( gtk . Widget ). addCssClass ( class );
469
484
} else {
470
- c . gtk_widget_remove_css_class ( widget , class );
485
+ widget . as ( gtk . Widget ). removeCssClass ( class );
471
486
}
472
487
}
473
488
0 commit comments