Skip to content

Commit 59a30de

Browse files
committed
Add title bar style and control button APIs to window
Introduces title bar style support and window control button visibility APIs to the window abstraction. Updates native bindings and removes legacy window creation logic, switching to new native window creation functions. Also sets library type to dynamic in Swift Package manifests for iOS and macOS.
1 parent 5368bf8 commit 59a30de

File tree

6 files changed

+203
-129
lines changed

6 files changed

+203
-129
lines changed

packages/cnativeapi/ios/cnativeapi/Package.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ let package = Package(
1111
products: [
1212
.library(
1313
name: "cnativeapi",
14+
type: .dynamic,
1415
targets: ["cnativeapi"]
1516
)
1617
],

packages/cnativeapi/lib/src/bindings_generated.dart

Lines changed: 113 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,43 @@ class CNativeApiBindings {
6262
late final _native_accessibility_manager_is_enabled =
6363
_native_accessibility_manager_is_enabledPtr.asFunction<bool Function()>();
6464

65+
/// Window creation and destruction
66+
native_window_t native_window_create() {
67+
return _native_window_create();
68+
}
69+
70+
late final _native_window_createPtr =
71+
_lookup<ffi.NativeFunction<native_window_t Function()>>(
72+
'native_window_create',
73+
);
74+
late final _native_window_create = _native_window_createPtr
75+
.asFunction<native_window_t Function()>();
76+
77+
native_window_t native_window_create_from_native(
78+
ffi.Pointer<ffi.Void> native_window,
79+
) {
80+
return _native_window_create_from_native(native_window);
81+
}
82+
83+
late final _native_window_create_from_nativePtr =
84+
_lookup<
85+
ffi.NativeFunction<native_window_t Function(ffi.Pointer<ffi.Void>)>
86+
>('native_window_create_from_native');
87+
late final _native_window_create_from_native =
88+
_native_window_create_from_nativePtr
89+
.asFunction<native_window_t Function(ffi.Pointer<ffi.Void>)>();
90+
91+
void native_window_destroy(native_window_t window) {
92+
return _native_window_destroy(window);
93+
}
94+
95+
late final _native_window_destroyPtr =
96+
_lookup<ffi.NativeFunction<ffi.Void Function(native_window_t)>>(
97+
'native_window_destroy',
98+
);
99+
late final _native_window_destroy = _native_window_destroyPtr
100+
.asFunction<void Function(native_window_t)>();
101+
65102
/// Window basic operations
66103
int native_window_get_id(native_window_t window) {
67104
return _native_window_get_id(window);
@@ -592,6 +629,33 @@ class CNativeApiBindings {
592629
late final _native_window_is_closable = _native_window_is_closablePtr
593630
.asFunction<bool Function(native_window_t)>();
594631

632+
void native_window_set_window_control_buttons_visible(
633+
native_window_t window,
634+
bool visible,
635+
) {
636+
return _native_window_set_window_control_buttons_visible(window, visible);
637+
}
638+
639+
late final _native_window_set_window_control_buttons_visiblePtr =
640+
_lookup<ffi.NativeFunction<ffi.Void Function(native_window_t, ffi.Bool)>>(
641+
'native_window_set_window_control_buttons_visible',
642+
);
643+
late final _native_window_set_window_control_buttons_visible =
644+
_native_window_set_window_control_buttons_visiblePtr
645+
.asFunction<void Function(native_window_t, bool)>();
646+
647+
bool native_window_is_window_control_buttons_visible(native_window_t window) {
648+
return _native_window_is_window_control_buttons_visible(window);
649+
}
650+
651+
late final _native_window_is_window_control_buttons_visiblePtr =
652+
_lookup<ffi.NativeFunction<ffi.Bool Function(native_window_t)>>(
653+
'native_window_is_window_control_buttons_visible',
654+
);
655+
late final _native_window_is_window_control_buttons_visible =
656+
_native_window_is_window_control_buttons_visiblePtr
657+
.asFunction<bool Function(native_window_t)>();
658+
595659
void native_window_set_always_on_top(
596660
native_window_t window,
597661
bool always_on_top,
@@ -646,6 +710,37 @@ class CNativeApiBindings {
646710
late final _native_window_get_title = _native_window_get_titlePtr
647711
.asFunction<ffi.Pointer<ffi.Char> Function(native_window_t)>();
648712

713+
void native_window_set_title_bar_style(
714+
native_window_t window,
715+
native_title_bar_style_t style,
716+
) {
717+
return _native_window_set_title_bar_style(window, style.value);
718+
}
719+
720+
late final _native_window_set_title_bar_stylePtr =
721+
_lookup<
722+
ffi.NativeFunction<ffi.Void Function(native_window_t, ffi.UnsignedInt)>
723+
>('native_window_set_title_bar_style');
724+
late final _native_window_set_title_bar_style =
725+
_native_window_set_title_bar_stylePtr
726+
.asFunction<void Function(native_window_t, int)>();
727+
728+
native_title_bar_style_t native_window_get_title_bar_style(
729+
native_window_t window,
730+
) {
731+
return native_title_bar_style_t.fromValue(
732+
_native_window_get_title_bar_style(window),
733+
);
734+
}
735+
736+
late final _native_window_get_title_bar_stylePtr =
737+
_lookup<ffi.NativeFunction<ffi.UnsignedInt Function(native_window_t)>>(
738+
'native_window_get_title_bar_style',
739+
);
740+
late final _native_window_get_title_bar_style =
741+
_native_window_get_title_bar_stylePtr
742+
.asFunction<int Function(native_window_t)>();
743+
649744
void native_window_set_has_shadow(native_window_t window, bool has_shadow) {
650745
return _native_window_set_has_shadow(window, has_shadow);
651746
}
@@ -1553,7 +1648,7 @@ class CNativeApiBindings {
15531648
///
15541649
/// @example
15551650
/// ```c
1556-
/// native_window_t window = native_window_manager_create(&options);
1651+
/// native_window_t window = native_window_create();
15571652
/// native_point_t offset = {0, 10};
15581653
/// native_positioning_strategy_t strategy = native_positioning_strategy_relative_to_window(window,
15591654
/// &offset); native_menu_open(menu, strategy); native_positioning_strategy_free(strategy);
@@ -3562,19 +3657,6 @@ class CNativeApiBindings {
35623657
late final _native_tray_icon_list_free = _native_tray_icon_list_freePtr
35633658
.asFunction<void Function(native_tray_icon_list_t)>();
35643659

3565-
/// Create a new window with default settings
3566-
/// @return Window handle, or NULL if creation failed
3567-
native_window_t native_window_manager_create() {
3568-
return _native_window_manager_create();
3569-
}
3570-
3571-
late final _native_window_manager_createPtr =
3572-
_lookup<ffi.NativeFunction<native_window_t Function()>>(
3573-
'native_window_manager_create',
3574-
);
3575-
late final _native_window_manager_create = _native_window_manager_createPtr
3576-
.asFunction<native_window_t Function()>();
3577-
35783660
/// Get a window by its ID
35793661
/// @param window_id The window ID
35803662
/// @return Window handle, or NULL if not found
@@ -3888,6 +3970,23 @@ final class native_window_list_t extends ffi.Struct {
38883970
/// Opaque window handle
38893971
typedef native_window_t = ffi.Pointer<ffi.Void>;
38903972

3973+
/// Title bar style enumeration
3974+
enum native_title_bar_style_t {
3975+
NATIVE_TITLE_BAR_STYLE_NORMAL(0),
3976+
NATIVE_TITLE_BAR_STYLE_HIDDEN(1);
3977+
3978+
final int value;
3979+
const native_title_bar_style_t(this.value);
3980+
3981+
static native_title_bar_style_t fromValue(int value) => switch (value) {
3982+
0 => NATIVE_TITLE_BAR_STYLE_NORMAL,
3983+
1 => NATIVE_TITLE_BAR_STYLE_HIDDEN,
3984+
_ => throw ArgumentError(
3985+
"Unknown value for native_title_bar_style_t: $value",
3986+
),
3987+
};
3988+
}
3989+
38913990
/// Window ID type
38923991
typedef native_window_id_t = ffi.Long;
38933992
typedef Dartnative_window_id_t = int;

packages/cnativeapi/macos/cnativeapi/Package.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ let package = Package(
1111
products: [
1212
.library(
1313
name: "cnativeapi",
14+
type: .dynamic,
1415
targets: ["cnativeapi"]
1516
)
1617
],

packages/nativeapi/lib/src/window.dart

Lines changed: 87 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,29 @@
11
import 'dart:ffi' hide Size;
22
import 'package:ffi/ffi.dart' as ffi;
3-
import 'package:nativeapi/src/display_manager.dart';
43
import 'package:nativeapi/src/foundation/cnativeapi_bindings_mixin.dart';
54
import 'package:nativeapi/src/foundation/geometry.dart';
65
import 'package:nativeapi/src/foundation/native_handle_wrapper.dart';
76

7+
/// Title bar style options for windows.
8+
///
9+
/// Defines how a window's title bar should be displayed. This affects the
10+
/// appearance and visibility of the standard window title bar including the
11+
/// title text and window control buttons (minimize, maximize, close).
12+
///
13+
/// Platform behavior may vary:
14+
/// - Windows: Hidden style removes the title bar but may retain window borders
15+
/// - macOS: Hidden style creates a borderless window with transparent title bar
16+
/// - Linux: Hidden style removes window decorations entirely
17+
enum TitleBarStyle {
18+
/// Standard title bar with default platform appearance.
19+
/// Shows title text and standard window control buttons.
20+
normal,
21+
22+
/// Hidden title bar with no visible decorations.
23+
/// The window appears without a title bar, useful for custom chrome.
24+
hidden,
25+
}
26+
827
/// A cross-platform window abstraction.
928
///
1029
/// This class provides a unified interface for creating and managing windows
@@ -28,10 +47,14 @@ import 'package:nativeapi/src/foundation/native_handle_wrapper.dart';
2847
/// // Maximize the window
2948
/// window?.maximize();
3049
///
50+
/// // Set title bar style
51+
/// window?.titleBarStyle = TitleBarStyle.hidden;
52+
///
3153
/// // Get window properties
3254
/// final title = window?.title;
3355
/// final size = window?.size;
3456
/// final position = window?.position;
57+
/// final titleBarStyle = window?.titleBarStyle;
3558
/// ```
3659
class Window
3760
with CNativeApiBindingsMixin
@@ -238,22 +261,8 @@ class Window
238261
}
239262

240263
/// Centers the window on the primary screen.
241-
///
242-
/// This method calculates the center position based on the primary display's
243-
/// size and the window's current size, then sets the window position accordingly.
244264
void center() {
245-
final primaryDisplay = DisplayManager.instance.getPrimary();
246-
if (primaryDisplay == null) {
247-
return;
248-
}
249-
250-
final screenSize = primaryDisplay.size;
251-
final windowSize = size;
252-
253-
final centerX = (screenSize.width - windowSize.width) / 2;
254-
final centerY = (screenSize.height - windowSize.height) / 2;
255-
256-
setPosition(centerX, centerY);
265+
bindings.native_window_center(_nativeHandle);
257266
}
258267

259268
// === Window Properties ===
@@ -318,6 +327,41 @@ class Window
318327
return bindings.native_window_is_closable(_nativeHandle);
319328
}
320329

330+
/// Sets the visibility of window control buttons.
331+
///
332+
/// Controls the visibility of window control buttons (minimize, maximize, close)
333+
/// in the title bar. When hidden, the buttons are not visible but the window
334+
/// can still be controlled programmatically.
335+
///
336+
/// Platform availability:
337+
/// - macOS: ✅ Fully supported - Hides/shows the traffic light buttons
338+
/// - Windows: ❌ Not implemented
339+
/// - Linux: ❌ Not implemented
340+
/// - Android: ❌ Not applicable - Mobile apps don't have window control buttons
341+
/// - iOS: ❌ Not applicable - Mobile apps don't have window control buttons
342+
/// - OpenHarmony: ❌ Not applicable - Mobile apps don't have window control buttons
343+
set windowControlButtonsVisible(bool value) {
344+
bindings.native_window_set_window_control_buttons_visible(
345+
_nativeHandle,
346+
value,
347+
);
348+
}
349+
350+
/// Checks if the window control buttons are visible.
351+
///
352+
/// Platform availability:
353+
/// - macOS: ✅ Fully supported - Returns actual visibility state
354+
/// - Windows: ❌ Not implemented - Always returns true
355+
/// - Linux: ❌ Not implemented - Always returns true
356+
/// - Android: ❌ Not applicable - Always returns false
357+
/// - iOS: ❌ Not applicable - Always returns false
358+
/// - OpenHarmony: ❌ Not applicable - Always returns false
359+
bool get windowControlButtonsVisible {
360+
return bindings.native_window_is_window_control_buttons_visible(
361+
_nativeHandle,
362+
);
363+
}
364+
321365
/// Sets whether the window is always on top.
322366
set isAlwaysOnTop(bool value) {
323367
bindings.native_window_set_always_on_top(_nativeHandle, value);
@@ -349,6 +393,33 @@ class Window
349393
return title;
350394
}
351395

396+
/// Sets the window's title bar style.
397+
///
398+
/// Controls the appearance and visibility of the window's title bar.
399+
/// Use [TitleBarStyle.normal] for standard appearance or [TitleBarStyle.hidden]
400+
/// to hide the title bar for custom window chrome.
401+
///
402+
/// Platform behavior may vary:
403+
/// - Windows: Hidden style removes the title bar but may retain window borders
404+
/// - macOS: Hidden style creates a borderless window with transparent title bar
405+
/// - Linux: Hidden style removes window decorations entirely
406+
set titleBarStyle(TitleBarStyle value) {
407+
final nativeStyle = value == TitleBarStyle.hidden
408+
? native_title_bar_style_t.NATIVE_TITLE_BAR_STYLE_HIDDEN
409+
: native_title_bar_style_t.NATIVE_TITLE_BAR_STYLE_NORMAL;
410+
bindings.native_window_set_title_bar_style(_nativeHandle, nativeStyle);
411+
}
412+
413+
/// Gets the window's title bar style.
414+
TitleBarStyle get titleBarStyle {
415+
final nativeStyle = bindings.native_window_get_title_bar_style(
416+
_nativeHandle,
417+
);
418+
return nativeStyle == native_title_bar_style_t.NATIVE_TITLE_BAR_STYLE_HIDDEN
419+
? TitleBarStyle.hidden
420+
: TitleBarStyle.normal;
421+
}
422+
352423
/// Sets whether the window has a shadow.
353424
set hasShadow(bool value) {
354425
bindings.native_window_set_has_shadow(_nativeHandle, value);

0 commit comments

Comments
 (0)