diff --git a/.github/VOUCHED.td b/.github/VOUCHED.td index 423517a15..33e39a19e 100644 --- a/.github/VOUCHED.td +++ b/.github/VOUCHED.td @@ -46,6 +46,7 @@ alexfeijoo44 alexjuca alosarjos amadeus +and-rs andrejdaskalov anhthang anmitalidev @@ -211,6 +212,7 @@ marrocco-simone masterflitzer matkotiric mattn +mgsloan micaeljarniac michielvk miguelelgallo diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index f7b076bf0..60a2e80e9 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -160,7 +160,7 @@ jobs: - name: Setup Sparkle env: - SPARKLE_VERSION: 2.9.0 + SPARKLE_VERSION: 2.9.4 run: | mkdir -p .action/sparkle cd .action/sparkle @@ -328,7 +328,7 @@ jobs: - name: Setup Sparkle env: - SPARKLE_VERSION: 2.9.0 + SPARKLE_VERSION: 2.9.4 run: | mkdir -p .action/sparkle cd .action/sparkle diff --git a/.github/workflows/release-tip.yml b/.github/workflows/release-tip.yml index 5cda284bb..d4e6b7162 100644 --- a/.github/workflows/release-tip.yml +++ b/.github/workflows/release-tip.yml @@ -591,7 +591,7 @@ jobs: # Setup Sparkle - name: Setup Sparkle env: - SPARKLE_VERSION: 2.9.0 + SPARKLE_VERSION: 2.9.4 run: | mkdir -p .action/sparkle cd .action/sparkle @@ -847,7 +847,7 @@ jobs: # Setup Sparkle - name: Setup Sparkle env: - SPARKLE_VERSION: 2.9.0 + SPARKLE_VERSION: 2.9.4 run: | mkdir -p .action/sparkle cd .action/sparkle @@ -1044,7 +1044,7 @@ jobs: # Setup Sparkle - name: Setup Sparkle env: - SPARKLE_VERSION: 2.9.0 + SPARKLE_VERSION: 2.9.4 run: | mkdir -p .action/sparkle cd .action/sparkle diff --git a/macos/Ghostty.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/macos/Ghostty.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 6e450d9bc..feb7b4ba0 100644 --- a/macos/Ghostty.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/macos/Ghostty.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -6,8 +6,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/sparkle-project/Sparkle", "state" : { - "revision" : "21d8df80440b1ca3b65fa82e40782f1e5a9e6ba2", - "version" : "2.9.0" + "revision" : "b6496a74a087257ef5e6da1c5b29a447a60f5bd7", + "version" : "2.9.4" } } ], diff --git a/src/apprt/gtk/class/surface.zig b/src/apprt/gtk/class/surface.zig index 59d8ed0f7..9d45bc6ce 100644 --- a/src/apprt/gtk/class/surface.zig +++ b/src/apprt/gtk/class/surface.zig @@ -1577,7 +1577,11 @@ pub const Surface = extern struct { // https://gitlab.gnome.org/GNOME/libadwaita/-/commit/a7738a4d269bfdf4d8d5429ca73ccdd9b2450421 // https://gitlab.gnome.org/GNOME/libadwaita/-/commit/9759d3fd81129608dd78116001928f2aed974ead if (gtk_xft_dpi <= 0) { - log.warn("gtk-xft-dpi has invalid value ({}), using default", .{gtk_xft_dpi}); + // -1 is a valid value which specifies default scale. + // https://docs.gtk.org/gtk4/property.Settings.gtk-xft-dpi.html + if (gtk_xft_dpi != -1) { + log.warn("gtk-xft-dpi has invalid value ({}), using default", .{gtk_xft_dpi}); + } break :xft_scale 1.0; } diff --git a/src/renderer/generic.zig b/src/renderer/generic.zig index 2c9fb1093..2a81f42b4 100644 --- a/src/renderer/generic.zig +++ b/src/renderer/generic.zig @@ -1194,8 +1194,6 @@ pub fn Renderer(comptime GraphicsAPI: type) type { const should_run = // Non-visible windows never vsync self.visible and - // Non-focused windows only render on-demand - self.focused and // Only vsync if we have cell changes or animation (self.cells_rebuilt or self.animationWake() != null); diff --git a/src/terminal/kitty/graphics_image.zig b/src/terminal/kitty/graphics_image.zig index 489b672e3..945a127db 100644 --- a/src/terminal/kitty/graphics_image.zig +++ b/src/terminal/kitty/graphics_image.zig @@ -210,6 +210,15 @@ pub const LoadingImage = struct { return error.UnsupportedMedium; } + // POSIX shared memory names must begin with a slash, contain at + // least one character after it, contain no other slashes, and fit + // within NAME_MAX. Some shm_open implementations accept names + // without the leading slash, but the Kitty protocol does not. + if (!validSharedMemoryName(path, posix.NAME_MAX)) { + log.warn("invalid shared memory name", .{}); + return error.InvalidData; + } + // Since we're only supporting posix then max_path_bytes should // be enough to stack allocate the path. var buf: [std.fs.max_path_bytes]u8 = undefined; @@ -831,6 +840,16 @@ pub const Rect = struct { } }; +/// Returns whether a name follows the POSIX shared memory name format. +fn validSharedMemoryName(name: []const u8, name_max: usize) bool { + if (name.len < 2 or name.len > name_max or name[0] != '/') return false; + for (name[1..]) |c| { + if (c == '/' or c == 0) return false; + } + + return true; +} + /// Returns true if `path` is `dir` or is contained within it, requiring a /// path-separator boundary so similarly prefixed directories do not match. fn isPathInDir(dir: []const u8, path: []const u8) bool { @@ -852,6 +871,53 @@ test "temporary file path must be inside directory" { try testing.expect(!isPathInDir("/custom/tmp", "/custom/tmp-suffix/tty-graphics-protocol-image.data")); } +test "shared memory names follow POSIX rules" { + const testing = std.testing; + + try testing.expect(validSharedMemoryName("/kitty", 8)); + try testing.expect(validSharedMemoryName("/1234567", 8)); + + try testing.expect(!validSharedMemoryName("", 8)); + try testing.expect(!validSharedMemoryName("/", 8)); + try testing.expect(!validSharedMemoryName("kitty", 8)); + try testing.expect(!validSharedMemoryName("/kitty/image", 16)); + try testing.expect(!validSharedMemoryName("/kitty\x00image", 16)); + try testing.expect(!validSharedMemoryName("/12345678", 8)); +} + +test "image load rejects invalid POSIX shared memory names" { + if (comptime builtin.abi.isAndroid() or + builtin.target.os.tag == .windows or + !builtin.link_libc) + { + return error.SkipZigTest; + } + + const testing = std.testing; + const alloc = testing.allocator; + + var cmd: command.Command = .{ + .control = .{ .transmit = .{ + .format = .rgb, + .medium = .shared_memory, + .width = 1, + .height = 1, + .image_id = 31, + } }, + .data = try alloc.dupe(u8, "kitty-without-leading-slash"), + }; + defer cmd.deinit(alloc); + + try testing.expectError( + error.InvalidData, + LoadingImage.init(testing.io, alloc, &cmd, .{ + .file = false, + .temporary_file = .disabled, + .shared_memory = true, + }), + ); +} + test "shared memory range with offset and size" { const testing = std.testing;