Skip to content

Commit 3e1be70

Browse files
committed
Fix window resizing for Gtk3Backend with custom widget and hours of debugging
This took almost as long as the rest of the Gtk3Backend implementation process combined 💀 but that's a taste of Gtk 3 I guess.
1 parent e23a6d5 commit 3e1be70

File tree

16 files changed

+379
-188
lines changed

16 files changed

+379
-188
lines changed

Package.swift

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,10 @@ let package = Package(
215215
dependencies: ["Gtk"],
216216
resources: [.copy("GTK.png")]
217217
),
218+
.target(
219+
name: "GtkCustomWidgets",
220+
dependencies: ["CGtk"]
221+
),
218222
.executableTarget(
219223
name: "GtkCodeGen",
220224
dependencies: [
@@ -231,7 +235,7 @@ let package = Package(
231235
),
232236
.target(
233237
name: "Gtk3",
234-
dependencies: ["CGtk3"],
238+
dependencies: ["CGtk3", "Gtk3CustomWidgets"],
235239
exclude: ["LICENSE.md"],
236240
swiftSettings: gtkSwiftSettings
237241
),
@@ -240,6 +244,10 @@ let package = Package(
240244
dependencies: ["Gtk3"],
241245
resources: [.copy("GTK.png")]
242246
),
247+
.target(
248+
name: "Gtk3CustomWidgets",
249+
dependencies: ["CGtk3"]
250+
),
243251
.macro(
244252
name: "HotReloadingMacrosPlugin",
245253
dependencies: [
@@ -250,10 +258,6 @@ let package = Package(
250258
],
251259
swiftSettings: swiftSettings
252260
),
253-
.target(
254-
name: "GtkCustomWidgets",
255-
dependencies: ["CGtk"]
256-
),
257261
] + swift510Targets
258262
)
259263

Sources/Gtk/Widgets/CustomRootWidget.swift

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
11
import CGtk
22
import GtkCustomWidgets
33

4-
final class CallbackBox {
5-
let callback: () -> Void
6-
7-
init(callback: @escaping () -> Void) {
8-
self.callback = callback
9-
}
10-
}
11-
124
/// A custom widget made specifically for SwiftCrossUI. This widget provides the
135
/// control of window and pane resizing that SwiftCrossUI requires.
146
public class CustomRootWidget: Widget {
@@ -39,17 +31,6 @@ public class CustomRootWidget: Widget {
3931
)
4032
}
4133

42-
public func setNaturalSize(
43-
naturalWidth: Int,
44-
naturalHeight: Int
45-
) {
46-
gtk_custom_root_widget_set_natural_size(
47-
castedPointer(),
48-
gint(naturalWidth),
49-
gint(naturalHeight)
50-
)
51-
}
52-
5334
public func preemptAllocatedSize(
5435
allocatedWidth: Int,
5536
allocatedHeight: Int

Sources/Gtk/Widgets/Window.swift

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@ public class Window: Widget {
1717
self.widgetPointer = pointer
1818
}
1919

20-
// public static var rootWindow: Window {
21-
// gdk_display_get_default()
22-
// return Window(pointer: UnsafeMutablePointer<GtkWidget>(gdk_screen_get_root_window(gdk_screen_get_default())))
23-
// }
24-
2520
@GObjectProperty(named: "title") public var title: String?
2621

2722
public var defaultSize: Size {

Sources/Gtk3/Utility/CSS/CSSProvider.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ public class CSSProvider {
1111
) {
1212
pointer = gtk_css_provider_new()
1313
self.context = context
14+
g_object_ref(context)
1415
gtk_style_context_add_provider(context, OpaquePointer(pointer), priority)
1516
}
1617

1718
deinit {
1819
gtk_style_context_remove_provider(context, OpaquePointer(pointer))
20+
g_object_unref(context)
1921
}
2022

2123
/// Loads data into css_provider.

Sources/Gtk3/Widgets/Bin.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@
33
//
44

55
open class Bin: Container {
6-
public func getChild() -> Widget? {
7-
widgets.last
6+
public var child: Widget?
7+
8+
public func setChild(to widget: Widget) {
9+
if let child {
10+
remove(child)
11+
}
12+
self.child = widget
13+
add(widget)
814
}
915
}
Lines changed: 58 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,65 @@
1-
// import CGtk3
2-
// import GtkCustomWidgets
1+
import CGtk3
2+
import Gtk3CustomWidgets
33

4-
// final class CallbackBox {
5-
// let callback: () -> Void
4+
/// A custom widget made specifically for SwiftCrossUI. This widget provides the
5+
/// control of window and pane resizing that SwiftCrossUI requires.
6+
public class CustomRootWidget: Widget {
7+
public var child: Widget?
68

7-
// init(callback: @escaping () -> Void) {
8-
// self.callback = callback
9-
// }
10-
// }
9+
override public init() {
10+
super.init()
11+
widgetPointer = gtk_custom_root_widget_new()
12+
}
1113

12-
// /// A custom widget made specifically for SwiftCrossUI. This widget provides the
13-
// /// control of window and pane resizing that SwiftCrossUI requires.
14-
// public class CustomRootWidget: Widget {
15-
// public var child: Widget?
14+
public func setChild(to widget: Widget) {
15+
if let child {
16+
child.parentWidget = nil
17+
}
18+
gtk_custom_root_widget_set_child(castedPointer(), widget.widgetPointer)
19+
child = widget
20+
widget.parentWidget = self
21+
}
1622

17-
// override public init() {
18-
// super.init()
19-
// widgetPointer = gtk_custom_root_widget_new()
20-
// }
23+
public func setMinimumSize(
24+
minimumWidth: Int,
25+
minimumHeight: Int
26+
) {
27+
gtk_custom_root_widget_set_minimum_size(
28+
castedPointer(),
29+
gint(minimumWidth),
30+
gint(minimumHeight)
31+
)
32+
}
2133

22-
// public func setChild(to widget: Widget) {
23-
// if let child {
24-
// child.parentWidget = nil
25-
// }
26-
// gtk_custom_root_widget_set_child(castedPointer(), widget.widgetPointer)
27-
// child = widget
28-
// widget.parentWidget = self
29-
// }
34+
public func preemptAllocatedSize(
35+
allocatedWidth: Int,
36+
allocatedHeight: Int
37+
) {
38+
gtk_custom_root_widget_preempt_allocated_size(
39+
castedPointer(),
40+
gint(allocatedWidth),
41+
gint(allocatedHeight)
42+
)
43+
}
3044

31-
// public func setMinimumSize(
32-
// minimumWidth: Int,
33-
// minimumHeight: Int
34-
// ) {
35-
// gtk_custom_root_widget_set_minimum_size(
36-
// castedPointer(),
37-
// gint(minimumWidth),
38-
// gint(minimumHeight)
39-
// )
40-
// }
45+
public func getSize() -> Size {
46+
var width: gint = 0
47+
var height: gint = 0
48+
gtk_custom_root_widget_get_size(castedPointer(), &width, &height)
49+
return Size(width: Int(width), height: Int(height))
50+
}
4151

42-
// public func setNaturalSize(
43-
// naturalWidth: Int,
44-
// naturalHeight: Int
45-
// ) {
46-
// gtk_custom_root_widget_set_natural_size(
47-
// castedPointer(),
48-
// gint(naturalWidth),
49-
// gint(naturalHeight)
50-
// )
51-
// }
52-
53-
// public func preemptAllocatedSize(
54-
// allocatedWidth: Int,
55-
// allocatedHeight: Int
56-
// ) {
57-
// gtk_custom_root_widget_preempt_allocated_size(
58-
// castedPointer(),
59-
// gint(allocatedWidth),
60-
// gint(allocatedHeight)
61-
// )
62-
// }
63-
64-
// public func getSize() -> Size {
65-
// var width: gint = 0
66-
// var height: gint = 0
67-
// gtk_custom_root_widget_get_size(castedPointer(), &width, &height)
68-
// return Size(width: Int(width), height: Int(height))
69-
// }
70-
71-
// public func setResizeHandler(_ handler: @escaping (Size) -> Void) {
72-
// let box = SignalBox1<Size>(callback: handler)
73-
// gtk_custom_root_widget_set_resize_callback(
74-
// castedPointer(),
75-
// { data, size in
76-
// SignalBox1<Size>.run(
77-
// data!,
78-
// Size(width: Int(size.width), height: Int(size.height))
79-
// )
80-
// },
81-
// Unmanaged.passRetained(box).toOpaque()
82-
// )
83-
// }
84-
// }
52+
public func setResizeHandler(_ handler: @escaping (Size) -> Void) {
53+
let box = SignalBox1<Size>(callback: handler)
54+
gtk_custom_root_widget_set_resize_callback(
55+
castedPointer(),
56+
{ data, size in
57+
SignalBox1<Size>.run(
58+
data!,
59+
Size(width: Int(size.width), height: Int(size.height))
60+
)
61+
},
62+
Unmanaged.passRetained(box).toOpaque()
63+
)
64+
}
65+
}

Sources/Gtk3/Widgets/ScrolledWindow.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import CGtk3
22

33
public class ScrolledWindow: Bin {
4-
var child: Widget?
5-
64
public override init() {
75
super.init()
86
widgetPointer = gtk_scrolled_window_new(nil, nil)

Sources/Gtk3/Widgets/Viewport.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import CGtk3
22

33
public class Viewport: Bin {
4-
var child: Widget?
5-
64
public override init() {
75
super.init()
86
widgetPointer = gtk_viewport_new(nil, nil)

Sources/Gtk3/Widgets/Window.swift

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
import CGtk3
66

77
public class Window: Bin {
8-
public var child: Widget?
9-
108
override public init() {
119
super.init()
1210
widgetPointer = gtk_window_new(GTK_WINDOW_TOPLEVEL)
@@ -17,11 +15,6 @@ public class Window: Bin {
1715
self.widgetPointer = pointer
1816
}
1917

20-
// public static var rootWindow: Window {
21-
// gdk_display_get_default()
22-
// return Window(pointer: UnsafeMutablePointer<GtkWidget>(gdk_screen_get_root_window(gdk_screen_get_default())))
23-
// }
24-
2518
@GObjectProperty(named: "title") public var title: String?
2619

2720
public var defaultSize: Size {
@@ -50,7 +43,11 @@ public class Window: Bin {
5043
// just the current size of the window, except when the window is in full
5144
// screen, in which case the 'default size' is the size that the window
5245
// should return to when it leaves full screen.
53-
defaultSize = newValue
46+
defaultSize = Size(
47+
width: newValue.width,
48+
height: newValue.height
49+
)
50+
gtk_window_resize(castedPointer(), gint(newValue.width), gint(newValue.height))
5451
}
5552
}
5653

Sources/Gtk3Backend/Gtk3Backend.swift

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -73,41 +73,36 @@ public final class Gtk3Backend: AppBackend {
7373
}
7474

7575
public func setChild(ofWindow window: Window, to child: Widget) {
76-
window.add(child)
76+
let container = CustomRootWidget()
77+
container.setChild(to: child)
78+
window.setChild(to: container)
7779
}
7880

7981
public func size(ofWindow window: Window) -> SIMD2<Int> {
80-
let size = window.size
82+
let child = window.child! as! CustomRootWidget
83+
let size = child.getSize()
8184
return SIMD2(size.width, size.height)
8285
}
8386

8487
public func setSize(ofWindow window: Window, to newSize: SIMD2<Int>) {
85-
let windowSize = window.defaultSize
86-
let childSize = window.defaultSize
87-
let decorationsSize = SIMD2(
88-
windowSize.width - childSize.width,
89-
windowSize.height - childSize.height
90-
)
91-
window.size = Size(
92-
width: decorationsSize.x + newSize.x,
93-
height: decorationsSize.y + newSize.y
94-
)
95-
// child.preemptAllocatedSize(allocatedWidth: newSize.x, allocatedHeight: newSize.y)
88+
let child = window.child! as! CustomRootWidget
89+
window.size = Size(width: newSize.x, height: newSize.y)
90+
child.preemptAllocatedSize(allocatedWidth: newSize.x, allocatedHeight: newSize.y)
9691
}
9792

9893
public func setMinimumSize(ofWindow window: Window, to minimumSize: SIMD2<Int>) {
99-
window.setMinimumSize(to: Size(width: minimumSize.x, height: minimumSize.y))
94+
let child = window.child! as! CustomRootWidget
95+
child.setMinimumSize(minimumWidth: minimumSize.x, minimumHeight: minimumSize.y)
10096
}
10197

10298
public func setResizeHandler(
10399
ofWindow window: Window,
104100
to action: @escaping (_ newSize: SIMD2<Int>) -> Void
105101
) {
106-
// TODO: Handle window resizing
107-
// let child = window.getChild() as! CustomRootWidget
108-
// child.setResizeHandler { size in
109-
// action(SIMD2(size.width, size.height))
110-
// }
102+
let child = window.child! as! CustomRootWidget
103+
child.setResizeHandler { size in
104+
action(SIMD2(size.width, size.height))
105+
}
111106
}
112107

113108
public func show(window: Window) {

0 commit comments

Comments
 (0)