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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.DS_Store
.dart_tool/
.idea/

.packages
.pub/
Expand Down
79 changes: 23 additions & 56 deletions bitsdojo_window/lib/src/widgets/window_button.dart
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
import 'dart:io' show Platform;

import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/material.dart';

import './mouse_state_builder.dart';
import '../icons/icons.dart';
import '../app_window.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'dart:io' show Platform;
import '../icons/icons.dart';
import './mouse_state_builder.dart';

typedef WindowButtonIconBuilder = Widget Function(
WindowButtonContext buttonContext);
typedef WindowButtonBuilder = Widget Function(
WindowButtonContext buttonContext, Widget icon);
typedef WindowButtonIconBuilder = Widget Function(WindowButtonContext buttonContext);
typedef WindowButtonBuilder = Widget Function(WindowButtonContext buttonContext, Widget icon);

class WindowButtonContext {
BuildContext context;
MouseState mouseState;
Color? backgroundColor;
Color iconColor;
WindowButtonContext(
{required this.context,
required this.mouseState,
this.backgroundColor,
required this.iconColor});
WindowButtonContext({required this.context, required this.mouseState, this.backgroundColor, required this.iconColor});
}

class WindowButtonColors {
Expand Down Expand Up @@ -66,7 +61,7 @@ class WindowButton extends StatelessWidget {
{Key? key,
WindowButtonColors? colors,
this.builder,
@required this.iconBuilder,
required this.iconBuilder,
this.padding,
this.onPressed,
this.animate = false})
Expand Down Expand Up @@ -105,29 +100,21 @@ class WindowButton extends StatelessWidget {
backgroundColor: getBackgroundColor(mouseState),
iconColor: getIconColor(mouseState));

var icon = (this.iconBuilder != null)
? this.iconBuilder!(buttonContext)
: Container();
var icon = (this.iconBuilder != null) ? this.iconBuilder!(buttonContext) : Container();
double borderSize = appWindow.borderSize;
double defaultPadding =
(appWindow.titleBarHeight - borderSize) / 3 - (borderSize / 2);
double defaultPadding = (appWindow.titleBarHeight - borderSize) / 3 - (borderSize / 2);
// Used when buttonContext.backgroundColor is null, allowing the AnimatedContainer to fade-out smoothly.
var fadeOutColor =
getBackgroundColor(MouseState()..isMouseOver = true).withOpacity(0);
var fadeOutColor = getBackgroundColor(MouseState()..isMouseOver = true).withValues(alpha: 0);
var padding = this.padding ?? EdgeInsets.all(defaultPadding);
var animationMs =
mouseState.isMouseOver ? (animate ? 100 : 0) : (animate ? 200 : 0);
var animationMs = mouseState.isMouseOver ? (animate ? 100 : 0) : (animate ? 200 : 0);
Widget iconWithPadding = Padding(padding: padding, child: icon);
iconWithPadding = AnimatedContainer(
curve: Curves.easeOut,
duration: Duration(milliseconds: animationMs),
color: buttonContext.backgroundColor ?? fadeOutColor,
child: iconWithPadding);
var button = (this.builder != null)
? this.builder!(buttonContext, icon)
: iconWithPadding;
return SizedBox(
width: buttonSize.width, height: buttonSize.height, child: button);
var button = (this.builder != null) ? this.builder!(buttonContext, icon) : iconWithPadding;
return SizedBox(width: buttonSize.width, height: buttonSize.height, child: button);
},
onPressed: () {
if (this.onPressed != null) this.onPressed!();
Expand All @@ -137,47 +124,32 @@ class WindowButton extends StatelessWidget {
}

class MinimizeWindowButton extends WindowButton {
MinimizeWindowButton(
{Key? key,
WindowButtonColors? colors,
VoidCallback? onPressed,
bool? animate})
MinimizeWindowButton({Key? key, WindowButtonColors? colors, VoidCallback? onPressed, bool? animate})
: super(
key: key,
colors: colors,
animate: animate ?? false,
iconBuilder: (buttonContext) =>
MinimizeIcon(color: buttonContext.iconColor),
iconBuilder: (buttonContext) => MinimizeIcon(color: buttonContext.iconColor),
onPressed: onPressed ?? () => appWindow.minimize());
}

class MaximizeWindowButton extends WindowButton {
MaximizeWindowButton(
{Key? key,
WindowButtonColors? colors,
VoidCallback? onPressed,
bool? animate})
MaximizeWindowButton({Key? key, WindowButtonColors? colors, VoidCallback? onPressed, bool? animate})
: super(
key: key,
colors: colors,
animate: animate ?? false,
iconBuilder: (buttonContext) =>
MaximizeIcon(color: buttonContext.iconColor),
iconBuilder: (buttonContext) => MaximizeIcon(color: buttonContext.iconColor),
onPressed: onPressed ?? () => appWindow.maximizeOrRestore());
}

class RestoreWindowButton extends WindowButton {
RestoreWindowButton(
{Key? key,
WindowButtonColors? colors,
VoidCallback? onPressed,
bool? animate})
RestoreWindowButton({Key? key, WindowButtonColors? colors, VoidCallback? onPressed, bool? animate})
: super(
key: key,
colors: colors,
animate: animate ?? false,
iconBuilder: (buttonContext) =>
RestoreIcon(color: buttonContext.iconColor),
iconBuilder: (buttonContext) => RestoreIcon(color: buttonContext.iconColor),
onPressed: onPressed ?? () => appWindow.maximizeOrRestore());
}

Expand All @@ -188,16 +160,11 @@ final _defaultCloseButtonColors = WindowButtonColors(
iconMouseOver: Color(0xFFFFFFFF));

class CloseWindowButton extends WindowButton {
CloseWindowButton(
{Key? key,
WindowButtonColors? colors,
VoidCallback? onPressed,
bool? animate})
CloseWindowButton({Key? key, WindowButtonColors? colors, VoidCallback? onPressed, bool? animate})
: super(
key: key,
colors: colors ?? _defaultCloseButtonColors,
animate: animate ?? false,
iconBuilder: (buttonContext) =>
CloseIcon(color: buttonContext.iconColor),
iconBuilder: (buttonContext) => CloseIcon(color: buttonContext.iconColor),
onPressed: onPressed ?? () => appWindow.close());
}
6 changes: 3 additions & 3 deletions bitsdojo_window/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
name: bitsdojo_window
description: A package to help with creating custom windows with Flutter desktop (custom border, titlebar and minimize/maximize/close buttons) and common desktop window operations (show/hide/position on screen) for Windows and macOS
version: 0.1.6
version: 1.0.0
homepage: https://www.bitsdojo.com
repository: https://github.com/bitsdojo/bitsdojo_window

environment:
sdk: ">=2.17.0 <4.0.0"
flutter: ">=1.20.0"
sdk: ">=3.0.0 <4.0.0"
flutter: ">=3.41.0"

flutter:
plugin:
Expand Down
37 changes: 15 additions & 22 deletions bitsdojo_window_linux/lib/src/native_api.dart
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
library bitsdojo_window_linux;

import 'dart:ffi';

import 'package:ffi/ffi.dart';

final DynamicLibrary _appExecutable = DynamicLibrary.executable();

// getAppWindowHandle
typedef IntPtr TGetAppWindowHandle();
typedef DGetAppWindowHandle = int Function();
final DGetAppWindowHandle getAppWindowHandle =
_theAPI.ref.getAppWindowHandle.asFunction();
final DGetAppWindowHandle getAppWindowHandle = _theAPI.ref.getAppWindowHandle.asFunction();

// getScreenRect
typedef Void TGetScreenRect(IntPtr window, Pointer<Int32> x, Pointer<Int32> y,
Pointer<Int32> width, Pointer<Int32> height);
typedef DGetScreenRect = void Function(int window, Pointer<Int32> x,
Pointer<Int32> y, Pointer<Int32> width, Pointer<Int32> height);
typedef Void TGetScreenRect(
IntPtr window, Pointer<Int32> x, Pointer<Int32> y, Pointer<Int32> width, Pointer<Int32> height);
typedef DGetScreenRect = void Function(
int window, Pointer<Int32> x, Pointer<Int32> y, Pointer<Int32> width, Pointer<Int32> height);
final DGetScreenRect getScreenRect = _theAPI.ref.getScreenRect.asFunction();

// getScaleFactor
Expand All @@ -25,8 +25,7 @@ final DGetScaleFactor getScaleFactor = _theAPI.ref.getScaleFactor.asFunction();

// getPosition
typedef Void TGetPosition(IntPtr window, Pointer<Int32> x, Pointer<Int32> y);
typedef DGetPosition = void Function(
int window, Pointer<Int32> x, Pointer<Int32> y);
typedef DGetPosition = void Function(int window, Pointer<Int32> x, Pointer<Int32> y);
final DGetPosition getPosition = _theAPI.ref.getPosition.asFunction();

// setPosition
Expand All @@ -35,21 +34,17 @@ typedef DSetPosition = void Function(int window, int x, int y);
final DSetPosition setPosition = _theAPI.ref.setPosition.asFunction();

// getSize
typedef Void TGetSize(
IntPtr window, Pointer<Int32> width, Pointer<Int32> height);
typedef DGetSize = void Function(
int window, Pointer<Int32> width, Pointer<Int32> height);
typedef Void TGetSize(IntPtr window, Pointer<Int32> width, Pointer<Int32> height);
typedef DGetSize = void Function(int window, Pointer<Int32> width, Pointer<Int32> height);
final DGetSize getSize = _theAPI.ref.getSize.asFunction();

// setSize
typedef Void TSetSize(IntPtr window, Int32 width, Int32 height);
typedef DSetSize = void Function(int window, int width, int height);
final DSetSize setSize = _theAPI.ref.setSize.asFunction();
// setRect
typedef Void TSetRect(
IntPtr window, Int32 x, Int32 y, Int32 width, Int32 height);
typedef DSetRect = void Function(
int window, int x, int y, int width, int height);
typedef Void TSetRect(IntPtr window, Int32 x, Int32 y, Int32 width, Int32 height);
typedef DSetRect = void Function(int window, int x, int y, int width, int height);
final DSetRect setRect = _theAPI.ref.setRect.asFunction();

// setMinSize
Expand Down Expand Up @@ -85,15 +80,14 @@ final DMaximizeWindow maximizeWindow = _theAPI.ref.maximizeWindow.asFunction();
// unmaximizeWindow
typedef Void TUnmaximizeWindow(IntPtr window);
typedef DUnmaximizeWindow = void Function(int window);
final DMaximizeWindow unmaximizeWindow =
_theAPI.ref.unmaximizeWindow.asFunction();
final DMaximizeWindow unmaximizeWindow = _theAPI.ref.unmaximizeWindow.asFunction();

// setWindowTitle
typedef Void TSetWindowTitle(IntPtr window, Pointer<Utf8> title);
typedef DSetWindowTitle = void Function(int window, Pointer<Utf8> title);
final DSetWindowTitle setWindowTitle = _theAPI.ref.setWindowTitle.asFunction();

class BDWAPI extends Struct {
base class BDWAPI extends Struct {
external Pointer<NativeFunction<TGetAppWindowHandle>> getAppWindowHandle;
external Pointer<NativeFunction<TGetScreenRect>> getScreenRect;
external Pointer<NativeFunction<TGetScaleFactor>> getScaleFactor;
Expand All @@ -114,8 +108,7 @@ class BDWAPI extends Struct {

typedef Pointer<BDWAPI> TBitsdojoWindowAPI();

final TBitsdojoWindowAPI bitsdojoWindowAPI = _appExecutable
.lookup<NativeFunction<TBitsdojoWindowAPI>>("bitsdojo_window_api")
.asFunction();
final TBitsdojoWindowAPI bitsdojoWindowAPI =
_appExecutable.lookup<NativeFunction<TBitsdojoWindowAPI>>("bitsdojo_window_api").asFunction();

final Pointer<BDWAPI> _theAPI = bitsdojoWindowAPI();
38 changes: 16 additions & 22 deletions bitsdojo_window_linux/lib/src/window.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import 'dart:ffi' hide Size;
import 'package:flutter/painting.dart';

import 'package:bitsdojo_window_platform_interface/bitsdojo_window_platform_interface.dart';
import 'package:ffi/ffi.dart';
import 'package:flutter/painting.dart';

import './native_api.dart' as native;
import './gtk.dart';
import 'package:bitsdojo_window_platform_interface/bitsdojo_window_platform_interface.dart';
import './native_api.dart' as native;

var isInsideDoWhenWindowReady = false;

Expand All @@ -23,10 +23,9 @@ class CachedWindowInfo {

Rect getScreenRectForWindow(int handle) {
Pointer<Int32> gtkRect = malloc.allocate(sizeOf<Int32>() * 4);
native.getScreenRect(handle, gtkRect.elementAt(0), gtkRect.elementAt(1),
gtkRect.elementAt(2), gtkRect.elementAt(3));
Rect result = Rect.fromLTWH(gtkRect[0].toDouble(), gtkRect[1].toDouble(),
gtkRect[2].toDouble(), gtkRect[3].toDouble());
native.getScreenRect(handle, gtkRect + 0, gtkRect + 1, gtkRect + 2, gtkRect + 3);
Rect result =
Rect.fromLTWH(gtkRect[0].toDouble(), gtkRect[1].toDouble(), gtkRect[2].toDouble(), gtkRect[3].toDouble());
malloc.free(gtkRect);

return result;
Expand Down Expand Up @@ -70,10 +69,10 @@ class GtkWindow extends DesktopWindow {
}

Pointer<Int32> gtkRect = malloc.allocate(sizeOf<Int32>() * 4);
native.getPosition(handle!, gtkRect.elementAt(0), gtkRect.elementAt(1));
native.getSize(handle!, gtkRect.elementAt(2), gtkRect.elementAt(3));
Rect result = Rect.fromLTWH(gtkRect[0].toDouble(), gtkRect[1].toDouble(),
gtkRect[2].toDouble(), gtkRect[3].toDouble());
native.getPosition(handle!, gtkRect + 0, gtkRect + 1);
native.getSize(handle!, gtkRect + 2, gtkRect + 3);
Rect result =
Rect.fromLTWH(gtkRect[0].toDouble(), gtkRect[1].toDouble(), gtkRect[2].toDouble(), gtkRect[3].toDouble());

malloc.free(gtkRect);
return result;
Expand All @@ -83,8 +82,7 @@ class GtkWindow extends DesktopWindow {
set rect(Rect newRect) {
if (!isValidHandle(handle, "set rectangle")) return;
_cached.rect = newRect;
native.setRect(handle!, newRect.left.toInt(), newRect.top.toInt(),
newRect.width.toInt(), newRect.height.toInt());
native.setRect(handle!, newRect.left.toInt(), newRect.top.toInt(), newRect.width.toInt(), newRect.height.toInt());
}

@override
Expand All @@ -96,8 +94,7 @@ class GtkWindow extends DesktopWindow {
}

Pointer<Int32> nativeResult = malloc.allocate(sizeOf<Int32>() * 2);
native.getSize(
handle!, nativeResult.elementAt(0), nativeResult.elementAt(1));
native.getSize(handle!, nativeResult + 0, nativeResult + 1);
Size result = Size(nativeResult[0].toDouble(), nativeResult[1].toDouble());
malloc.free(nativeResult);
final gotSize = getLogicalSize(result);
Expand Down Expand Up @@ -126,7 +123,7 @@ class GtkWindow extends DesktopWindow {
double get scaleFactor {
if (!isValidHandle(handle, "get scaleFactor")) return 1;
Pointer<Int32> scaleFactorPtr = malloc.allocate(sizeOf<Int32>());
native.getScaleFactor(handle!, scaleFactorPtr.elementAt(0));
native.getScaleFactor(handle!, scaleFactorPtr + 1);
double result = scaleFactorPtr[0].toDouble();
malloc.free(scaleFactorPtr);
return result;
Expand Down Expand Up @@ -183,8 +180,7 @@ class GtkWindow extends DesktopWindow {
//TODO - add handling for setting minSize to null
return;
}
native.setMinSize(
handle!, _minSize!.width.toInt(), _minSize!.height.toInt());
native.setMinSize(handle!, _minSize!.width.toInt(), _minSize!.height.toInt());
}

@override
Expand All @@ -196,8 +192,7 @@ class GtkWindow extends DesktopWindow {
//TODO - add handling for setting maxSize to null
return;
}
native.setMaxSize(
handle!, _maxSize!.width.toInt(), _maxSize!.height.toInt());
native.setMaxSize(handle!, _maxSize!.width.toInt(), _maxSize!.height.toInt());
}

@override
Expand Down Expand Up @@ -232,8 +227,7 @@ class GtkWindow extends DesktopWindow {
_cached.rect = Rect.fromLTWH(left, top, width, height);

if (_alignment == null) {
native.setSize(
handle!, sizeToSet.width.toInt(), sizeToSet.height.toInt());
native.setSize(handle!, sizeToSet.width.toInt(), sizeToSet.height.toInt());
//native.setWindowSize(handle!, sizeToSet);
} else {
final sizeOnScreen = getSizeOnScreen((sizeToSet));
Expand Down
8 changes: 4 additions & 4 deletions bitsdojo_window_linux/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
name: bitsdojo_window_linux
description: Linux implementation of the bitsdojo_window plugin.
version: 0.1.4
version: 1.0.0
homepage: https://www.bitsdojo.com
repository: https://github.com/bitsdojo/bitsdojo_window

environment:
sdk: ">=2.17.0 <4.0.0"
flutter: ">=1.20.0"
sdk: ">=3.0.0 <4.0.0"
flutter: ">=3.41.0"

dependencies:
flutter:
sdk: flutter
bitsdojo_window_platform_interface:
^0.1.2
#path: ../bitsdojo_window_platform_interface
ffi: ^2.0.0
ffi: ^2.2.0

dev_dependencies:
flutter_test:
Expand Down
Loading