Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,11 @@ jobs:

- name: Override frida-swift with local FridaCore.xcframework
run: |
# Stay on the same frida-swift revision as Package.swift /
# Package.resolved. Cloning tip-of-main regenerates bindings that
# no longer match this tree.
git clone https://github.com/frida/frida-swift.git $RUNNER_TEMP/frida-swift
git -C $RUNNER_TEMP/frida-swift checkout 467d0360c2cc8ae7db9444316656b4154d22213d
cp -R $RUNNER_TEMP/FridaCore.xcframework $RUNNER_TEMP/frida-swift/
python3 - <<'PY'
import os, re
Expand Down Expand Up @@ -344,11 +348,15 @@ jobs:

- name: Generate agent bundle
run: |
# Fork PRs do not receive Apple signing secrets. Disable signing so
# LumaBundleCompiler still builds without a local codesign identity.
xcodebuild \
-project Luma.xcodeproj \
-scheme AgentBundle \
-configuration Release \
-derivedDataPath build/.derived \
CODE_SIGN_IDENTITY=- \
CODE_SIGNING_ALLOWED=NO \
build

- name: Build
Expand Down Expand Up @@ -602,7 +610,11 @@ jobs:

- name: Override frida-swift with local FridaCore.xcframework
run: |
# Stay on the same frida-swift revision as Package.swift /
# Package.resolved. Cloning tip-of-main regenerates bindings that
# no longer match this tree.
git clone https://github.com/frida/frida-swift.git $RUNNER_TEMP/frida-swift
git -C $RUNNER_TEMP/frida-swift checkout 467d0360c2cc8ae7db9444316656b4154d22213d
cp -R $RUNNER_TEMP/FridaCore.xcframework $RUNNER_TEMP/frida-swift/
python3 - <<'PY'
import os, re
Expand Down Expand Up @@ -643,11 +655,15 @@ jobs:

- name: Generate agent bundle
run: |
# Fork PRs do not receive Apple signing secrets. Disable signing so
# LumaBundleCompiler still builds without a local codesign identity.
xcodebuild \
-project Luma.xcodeproj \
-scheme AgentBundle \
-configuration Release \
-derivedDataPath build/.derived-ios \
CODE_SIGN_IDENTITY=- \
CODE_SIGNING_ALLOWED=NO \
build

- name: Build (unsigned, iOS Simulator)
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 58 additions & 0 deletions Luma.xcodeproj/xcshareddata/xcschemes/AgentBundle.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "2620"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0CAB00010000000000000001"
BuildableName = "AgentBundle"
BlueprintName = "AgentBundle"
ReferencedContainer = "container:Luma.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
11 changes: 10 additions & 1 deletion LumaGtk/Sources/LumaGtk/MainWindow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3062,7 +3062,16 @@ final class MainWindow: InstrumentUIHost {
}

private func activateGroupChild(sessionID: UUID, group: SessionSidebarGroup, key: String) {
groupChildActions[groupChildActionKey(sessionID: sessionID, group: group, key: key)]?()
let actionKey = groupChildActionKey(sessionID: sessionID, group: group, key: key)
// Browse-all opens a popover; keep that off the ListBox signal stack.
if key == "browse" {
Task { @MainActor [weak self] in
await Task.yield()
self?.groupChildActions[actionKey]?()
}
return
}
groupChildActions[actionKey]?()
}

private func toggleGroupExpansion(sessionID: UUID, group: SessionSidebarGroup) {
Expand Down
48 changes: 38 additions & 10 deletions LumaGtk/Sources/LumaGtk/SidebarBrowserPopover.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ final class SidebarBrowserPopover<Item> {
private var query: String = ""
private var filterTask: Task<Void, Never>?
private var refreshGeneration: UInt = 0
private var isChoosing = false

private static var visibleRowLimit: Int { 250 }
// Cap first paint so Windows GTK is not forced to allocate a huge ListBox
// while the popover is still mapping.
private static var visibleRowLimit: Int { 150 }

init(
items: [Item],
Expand Down Expand Up @@ -73,7 +76,7 @@ final class SidebarBrowserPopover<Item> {
key.onKeyPressed { [weak self] _, keyval, _, _ in
MainActor.assumeIsolated {
if Int32(keyval) == Gdk.keyEscape {
self?.dismiss()
self?.scheduleDismiss()
return true
}
return false
Expand Down Expand Up @@ -101,7 +104,7 @@ final class SidebarBrowserPopover<Item> {
MainActor.assumeIsolated { self?.chooseFirstMatch() }
}
searchEntry.onStopSearch { [weak self] _ in
MainActor.assumeIsolated { self?.dismiss() }
MainActor.assumeIsolated { self?.scheduleDismiss() }
}
column.append(child: searchEntry)

Expand All @@ -119,7 +122,9 @@ final class SidebarBrowserPopover<Item> {
let index = Int(row.index)
guard index >= 0, index < self.entries.count else { return }
if case .item(let item) = self.entries[index] {
self.choose(item)
// Defer dismiss/unparent until after row-activated finishes;
// tearing the popover down mid-emission faults inside GTK.
self.scheduleChoose(item)
}
}
}
Expand All @@ -132,9 +137,15 @@ final class SidebarBrowserPopover<Item> {
self.popover = popover
self.listBox = listBox

refreshList()
// Map the empty popover first, then fill rows on a later turn so the
// initial present is not competing with a large ListBox rebuild.
popover.popup()
_ = searchEntry.grabFocus()
Task { @MainActor [weak self] in
await Task.yield()
guard let self, self.popover != nil else { return }
self.refreshList()
}
}

private func scheduleRefresh() {
Expand Down Expand Up @@ -261,18 +272,32 @@ final class SidebarBrowserPopover<Item> {
private func chooseFirstMatch() {
for entry in entries {
if case .item(let item) = entry {
choose(item)
scheduleChoose(item)
return
}
}
}

private func choose(_ item: Item) {
dismiss()
onChoose(item)
private func scheduleChoose(_ item: Item) {
guard !isChoosing else { return }
isChoosing = true
Task { @MainActor [weak self] in
await Task.yield()
guard let self else { return }
self.dismiss()
self.onChoose(item)
}
}

private func scheduleDismiss() {
Task { @MainActor [weak self] in
await Task.yield()
self?.dismiss()
}
}

private func dismiss() {
guard popover != nil else { return }
popover?.popdown()
cleanup()
}
Expand All @@ -281,7 +306,10 @@ final class SidebarBrowserPopover<Item> {
filterTask?.cancel()
filterTask = nil
refreshGeneration &+= 1
popover?.unparent()
isChoosing = false
if let popover {
popover.unparent()
}
popover = nil
listBox = nil
retainer = nil
Expand Down
6 changes: 5 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ let package = Package(
.executable(name: "LumaBundleCompiler", targets: ["LumaBundleCompiler"]),
],
dependencies: [
.package(url: "https://github.com/frida/frida-swift", branch: "main"),
// Pin to the revision recorded in Package.resolved. Floating on
// branch main pulled a regenerated Frida API that does not match
// this tree (and Apple CI clones tip-of-main when injecting the
// local FridaCore.xcframework).
.package(url: "https://github.com/frida/frida-swift", revision: "467d0360c2cc8ae7db9444316656b4154d22213d"),
.package(url: "https://github.com/apple/swift-crypto", .upToNextMajor(from: "3.0.0")),
.package(url: "https://github.com/groue/GRDB.swift", .upToNextMajor(from: "7.0.0")),
.package(url: "https://github.com/radareorg/SwiftyR2", branch: "main"),
Expand Down
Loading