Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

flutter asan support #575

Merged
merged 4 commits into from
Jan 19, 2025
Merged
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
17 changes: 16 additions & 1 deletion CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,24 @@
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
}
},
{
"name": "dev-flutter-asan",
"description": "Builds the flutter frontend (ASAN)",
"binaryDir": "${sourceDir}/build-dev-flutter-asan",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"KDDockWidgets_WERROR": "ON",
"KDDockWidgets_USE_LLD": "ON",
"KDDockWidgets_DEVELOPER_MODE": "ON"
},
"inherits": [
"flutter-base",
"asan-base"
]
},
{
"name": "dev-flutter",
"description": "Builds the KDDW layouting for usage with flutter",
"description": "Builds the flutter frontend",
"binaryDir": "${sourceDir}/build-dev-flutter",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
Expand Down
6 changes: 6 additions & 0 deletions src/flutter/dart/lib/models/DropArea.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,13 @@ class DropArea implements ffi.Finalizable {

void _addGroup(Group group) {
_groups.add(group);
group.dropArea = this;
layoutChanged.emit();
}

void _removeGroup(Group group) {
_groups.remove(group);

Bindings.instance.nativeLibrary
.remove_guest(_hostCpp.cast(), group.guestCpp.cast());
layoutChanged.emit();
Expand Down Expand Up @@ -145,6 +147,10 @@ class DropArea implements ffi.Finalizable {
return false;
}

bool containsGroup(Group group) {
return _groups.contains(group);
}

List<Group> get groups {
return _groups;
}
Expand Down
25 changes: 25 additions & 0 deletions src/flutter/dart/lib/models/FloatingItem.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,34 @@ class FloatingItem implements ItemWithTitleBar {
return dropArea.groups.length > 1;
}

bool containsGroup(Group group) {
return dropArea.containsGroup(group);
}

void addGroup(Group group) {
dropArea._addGroup(group);
}

@override
void close() {
_groupCountChangedConnection.disconnect();
DockRegistry.instance.removeFloatingItem(this);
}

@override
bool isFloating() {
// A floating window is floating
return true;
}

@override
void unfloat() {
// attach floating window into main window again
}

@override
void float() {
// a floating window is already floating
throw "unreachable";
}
}
51 changes: 48 additions & 3 deletions src/flutter/dart/lib/models/Group.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,12 @@ class Group extends GeometryItem implements ffi.Finalizable, ItemWithTitleBar {
List<DockItem> items = [];
late final TitleBar titlebar;

final ffi.Pointer<void> _hostCpp;
late final ffi.Pointer<void> guestCpp;

final titleChanged = Signal0();
DropArea dropArea;

Group(this.dropArea, {super.geometry}) : _hostCpp = dropArea.hostPtr {
Group(this.dropArea, {super.geometry}) {
titlebar = TitleBar(this);

final callbackPointer = ffi.Pointer.fromFunction<
Expand All @@ -58,7 +57,7 @@ class Group extends GeometryItem implements ffi.Finalizable, ItemWithTitleBar {

groupInCtor = this;
guestCpp = Bindings.instance.nativeLibrary
.create_guest(this._hostCpp.cast(), callbackPointer);
.create_guest(dropArea.hostPtr.cast(), callbackPointer);
groupInCtor = null;

_instances[guestCpp.address] = WeakReference<Group>(this);
Expand Down Expand Up @@ -160,8 +159,54 @@ class Group extends GeometryItem implements ffi.Finalizable, ItemWithTitleBar {
}
}

/// Returns the floating item this group is in, if any.
/// It might be inside the main window, in which case this returns null
FloatingItem? floatingItem() {
for (var floatingItem in DockRegistry.instance.floatingItems) {
if (floatingItem.containsGroup(this)) return floatingItem;
}

return null;
}

/// If false, then it's inside the main window
bool isInFloatingWindow() {
return floatingItem() != null;
}

@override
void close() {
dropArea._removeGroup(this);
}

/// A group is floating if:
/// It's in a floating window without nesting
/// i.e: it's the only group
/// i.e: it can't be detached into a floating window
@override
bool isFloating() {
final fi = floatingItem();
if (fi == null) {
return false;
} else {
return fi.dropArea.groups.length == 1;
}
}

@override
void unfloat() {
// a group is already attached
throw "unreachable";
}

@override
void float() {
// transform the group into a floating window
if (isFloating()) return;

dropArea._removeGroup(this);

final floatingItem = FloatingItem();
floatingItem.addGroup(this);
}
}
21 changes: 20 additions & 1 deletion src/flutter/dart/lib/models/TitleBar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ part of kddockwidgets;
abstract class ItemWithTitleBar {
// called when close button on the titlebar is clicked
void close();

// whether the titlebar is attached to a floating window or group
bool isFloating();

// detaches into a floating window
void float();

// docks a floating window into the main drop area
void unfloat();
}

class TitleBar {
Expand All @@ -29,7 +38,17 @@ class TitleBar {
_itemWithTitleBar.close();
}

void onFloatClicked() {}
void onFloatClicked() {
if (isFloating()) {
_itemWithTitleBar.unfloat();
} else {
_itemWithTitleBar.float();
}
}

void onMouseEvent(PointerEvent ev) {}

bool isFloating() {
return _itemWithTitleBar.isFloating();
}
}
17 changes: 17 additions & 0 deletions src/flutter/dart/lib/private/kddw_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,23 @@ class NativeLibrary {
late final _delete_guest =
_delete_guestPtr.asFunction<void Function(ffi.Pointer<ffi.Void>)>();

void set_guest_host(
ffi.Pointer<ffi.Void> host,
ffi.Pointer<ffi.Void> guest,
) {
return _set_guest_host(
host,
guest,
);
}

late final _set_guest_hostPtr = _lookup<
ffi.NativeFunction<
ffi.Void Function(
ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>>('set_guest_host');
late final _set_guest_host = _set_guest_hostPtr.asFunction<
void Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>();

void insert_item(
ffi.Pointer<ffi.Void> host,
ffi.Pointer<ffi.Void> guest,
Expand Down
42 changes: 42 additions & 0 deletions src/flutter/dart/test/models/floatingitem_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
This file is part of KDDockWidgets.

SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
Author: Sérgio Martins <[email protected]>

SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only

Contact KDAB at <[email protected]> for commercial licensing options.
*/

import 'package:flutter_test/flutter_test.dart';
import 'package:KDDockWidgets/KDDockWidgets.dart';
import 'package:KDDockWidgets/private/Bindings.dart';

void main() {
group('FloatingItem', () {
test('isFloating', () {
var dropArea = DropArea();
final dockName = "dock1";
expect(dropArea.containsDockItem(dockName), false);
var dock = DockItem(uniqueName: dockName);
dropArea.addDockItem(dock, Location.LocationOnTop);

var group = dropArea.groups.first;
// It's docked, so not floating yet
expect(group.isFloating(), false);
expect(dropArea.groups.length, 1);
expect(group.dropArea, dropArea);

// Undock:
group.titlebar.onFloatClicked();
expect(group.isFloating(), true);
expect(dropArea.groups.length, 0);
expect(group.dropArea != dropArea, true);

// Redock:
// group.titlebar.onFloatClicked();
// expect(group.isFloating(), false);
});
});
}
9 changes: 9 additions & 0 deletions src/flutter/kddw_bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ class Guest : public KDDockWidgets::Core::LayoutingGuest
return;

_layoutingHost = parent;
_item->setHost(parent);
}

Core::LayoutingHost *host() const override
Expand Down Expand Up @@ -242,6 +243,14 @@ void delete_guest(void *guest)
delete reinterpret_cast<Guest *>(guest);
}

void set_guest_host(void *_host, void *_guest)
{
auto host = reinterpret_cast<Host *>(_host);
auto guest = reinterpret_cast<Guest *>(_guest);

guest->setHost(host);
}

void validate_enum(int location)
{
auto loc = static_cast<KDDockWidgets::Location>(location);
Expand Down
1 change: 1 addition & 0 deletions src/flutter/kddw_bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ DOCKS_EXPORT void *create_host();
DOCKS_EXPORT void delete_host(void *host);
DOCKS_EXPORT void *create_guest(void *host, void (*callback)(void *guest, int x, int y, int width, int height, int is_visible));
DOCKS_EXPORT void delete_guest(void *host);
DOCKS_EXPORT void set_guest_host(void *host, void *guest);
DOCKS_EXPORT void insert_item(void *host, void *guest, int location);
DOCKS_EXPORT void insert_item_relative_to(void *host, void *guest, void *relativeToGuest, int location);
DOCKS_EXPORT void remove_guest(void *host, void *guest);
Expand Down
Loading