rendering correctly with backing window but some issues re pixel density, scroll & foregrounding on start
This commit is contained in:
@@ -2,6 +2,7 @@ import 'dart:async';
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'package:polyvox_filament/animations/animation_data.dart';
|
import 'package:polyvox_filament/animations/animation_data.dart';
|
||||||
|
|
||||||
@@ -14,7 +15,7 @@ import 'package:path_provider/path_provider.dart';
|
|||||||
import 'package:polyvox_filament/widgets/filament_gesture_detector.dart';
|
import 'package:polyvox_filament/widgets/filament_gesture_detector.dart';
|
||||||
import 'package:polyvox_filament/widgets/filament_widget.dart';
|
import 'package:polyvox_filament/widgets/filament_widget.dart';
|
||||||
|
|
||||||
void main() {
|
void main() async {
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,8 +31,10 @@ class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
// showPerformanceOverlay: true,
|
// showPerformanceOverlay: true,
|
||||||
color: Colors.white,
|
home: Scaffold(
|
||||||
home: Scaffold(backgroundColor: Colors.white, body: ExampleWidget()));
|
body:
|
||||||
|
ExampleWidget()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,9 @@ public:
|
|||||||
|
|
||||||
void doRender() {
|
void doRender() {
|
||||||
render(_viewer, 0, nullptr, nullptr, nullptr);
|
render(_viewer, 0, nullptr, nullptr, nullptr);
|
||||||
_renderCallback(_renderCallbackOwner);
|
if(_renderCallback) {
|
||||||
|
_renderCallback(_renderCallbackOwner);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setFrameIntervalInMilliseconds(float frameIntervalInMilliseconds) {
|
void setFrameIntervalInMilliseconds(float frameIntervalInMilliseconds) {
|
||||||
|
|||||||
@@ -19,6 +19,14 @@ class TextureDetails {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class FilamentController {
|
abstract class FilamentController {
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Whether a Flutter Texture widget should be inserted into the widget hierarchy.
|
||||||
|
/// This will be false on certain platforms where we use a transparent window underlay.
|
||||||
|
/// Used internally by [FilamentWidget]; you probably don't need to access this property directly.
|
||||||
|
///
|
||||||
|
bool get requiresTextureWidget;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// The Flutter texture ID and dimensions for current texture in use.
|
/// The Flutter texture ID and dimensions for current texture in use.
|
||||||
/// This is only used by [FilamentWidget]; you shouldn't need to access directly yourself.
|
/// This is only used by [FilamentWidget]; you shouldn't need to access directly yourself.
|
||||||
|
|||||||
@@ -4,16 +4,21 @@ import 'dart:io';
|
|||||||
import 'dart:ui' as ui;
|
import 'dart:ui' as ui;
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:ffi/ffi.dart';
|
import 'package:ffi/ffi.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
import 'package:polyvox_filament/filament_controller.dart';
|
import 'package:polyvox_filament/filament_controller.dart';
|
||||||
|
|
||||||
import 'package:polyvox_filament/animations/animation_data.dart';
|
import 'package:polyvox_filament/animations/animation_data.dart';
|
||||||
import 'package:polyvox_filament/generated_bindings.dart';
|
import 'package:polyvox_filament/generated_bindings.dart';
|
||||||
|
|
||||||
|
// ignore: constant_identifier_names
|
||||||
const FilamentEntity _FILAMENT_ASSET_ERROR = 0;
|
const FilamentEntity _FILAMENT_ASSET_ERROR = 0;
|
||||||
|
|
||||||
class FilamentControllerFFI extends FilamentController {
|
class FilamentControllerFFI extends FilamentController {
|
||||||
late MethodChannel _channel = MethodChannel("app.polyvox.filament/event");
|
|
||||||
|
final _channel = const MethodChannel("app.polyvox.filament/event");
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get requiresTextureWidget => !Platform.isWindows;
|
||||||
|
|
||||||
double _pixelRatio = 1.0;
|
double _pixelRatio = 1.0;
|
||||||
|
|
||||||
@@ -25,9 +30,11 @@ class FilamentControllerFFI extends FilamentController {
|
|||||||
|
|
||||||
final String? uberArchivePath;
|
final String? uberArchivePath;
|
||||||
|
|
||||||
|
@override
|
||||||
Stream<bool> get hasViewer => _hasViewerController.stream;
|
Stream<bool> get hasViewer => _hasViewerController.stream;
|
||||||
final _hasViewerController = StreamController<bool>();
|
final _hasViewerController = StreamController<bool>();
|
||||||
|
|
||||||
|
@override
|
||||||
Stream<FilamentEntity> get pickResult => _pickResultController.stream;
|
Stream<FilamentEntity> get pickResult => _pickResultController.stream;
|
||||||
final _pickResultController = StreamController<FilamentEntity>.broadcast();
|
final _pickResultController = StreamController<FilamentEntity>.broadcast();
|
||||||
|
|
||||||
@@ -48,7 +55,7 @@ class FilamentControllerFFI extends FilamentController {
|
|||||||
_resizeTimer?.cancel();
|
_resizeTimer?.cancel();
|
||||||
_resizingWidth = call.arguments[0];
|
_resizingWidth = call.arguments[0];
|
||||||
_resizingHeight = call.arguments[1];
|
_resizingHeight = call.arguments[1];
|
||||||
_resizeTimer = Timer(Duration(milliseconds: 500), () async {
|
_resizeTimer = Timer(const Duration(milliseconds: 500), () async {
|
||||||
await resize(_resizingWidth!, _resizingHeight!);
|
await resize(_resizingWidth!, _resizingHeight!);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -160,7 +167,7 @@ class FilamentControllerFFI extends FilamentController {
|
|||||||
|
|
||||||
print("Using flutterTextureId $flutterTextureId, surface $surfaceAddress and nativeTexture $nativeTexture");
|
print("Using flutterTextureId $flutterTextureId, surface $surfaceAddress and nativeTexture $nativeTexture");
|
||||||
|
|
||||||
if (Platform.isWindows) {
|
if (Platform.isWindows && requiresTextureWidget) {
|
||||||
_driver = Pointer<Void>.fromAddress(
|
_driver = Pointer<Void>.fromAddress(
|
||||||
await _channel.invokeMethod("getDriverPlatform"));
|
await _channel.invokeMethod("getDriverPlatform"));
|
||||||
}
|
}
|
||||||
@@ -275,6 +282,10 @@ class FilamentControllerFFI extends FilamentController {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future resize(int width, int height, {double scaleFactor = 1.0}) async {
|
Future resize(int width, int height, {double scaleFactor = 1.0}) async {
|
||||||
|
|
||||||
|
if(Platform.isWindows) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// we defer to the FilamentWidget to ensure that every call to [resize] is synchronized
|
// we defer to the FilamentWidget to ensure that every call to [resize] is synchronized
|
||||||
// so this exception should never be thrown (right?)
|
// so this exception should never be thrown (right?)
|
||||||
if (textureDetails.value == null) {
|
if (textureDetails.value == null) {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class _RenderResizeObserver extends RenderProxyBox {
|
|||||||
void performLayout() async {
|
void performLayout() async {
|
||||||
super.performLayout();
|
super.performLayout();
|
||||||
if (size.width != _oldSize.width || size.height != _oldSize.height) {
|
if (size.width != _oldSize.width || size.height != _oldSize.height) {
|
||||||
onLayoutChangedCallback(size);
|
onLayoutChangedCallback(size);
|
||||||
_oldSize = Size(size.width, size.height);
|
_oldSize = Size(size.width, size.height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,7 +87,7 @@ class _FilamentWidgetState extends State<FilamentWidget> {
|
|||||||
|
|
||||||
return ResizeObserver(
|
return ResizeObserver(
|
||||||
onResized: (newSize) {
|
onResized: (newSize) {
|
||||||
if(!Platform.isWindows) {
|
if (!Platform.isWindows) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||||
@@ -124,10 +124,10 @@ class _SizedFilamentWidget extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _SizedFilamentWidgetState extends State<_SizedFilamentWidget> {
|
class _SizedFilamentWidgetState extends State<_SizedFilamentWidget> {
|
||||||
|
|
||||||
String? _error;
|
String? _error;
|
||||||
|
|
||||||
late final AppLifecycleListener _appLifecycleListener;
|
late final AppLifecycleListener _appLifecycleListener;
|
||||||
AppLifecycleState? _lastState;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -136,9 +136,6 @@ class _SizedFilamentWidgetState extends State<_SizedFilamentWidget> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||||
if (!kReleaseMode) {
|
|
||||||
await Future.delayed(Duration(seconds: 2));
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
await widget.controller.createViewer(widget.width, widget.height);
|
await widget.controller.createViewer(widget.width, widget.height);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -171,7 +168,7 @@ class _SizedFilamentWidgetState extends State<_SizedFilamentWidget> {
|
|||||||
var width = size.width.ceil();
|
var width = size.width.ceil();
|
||||||
var height = size.height.ceil();
|
var height = size.height.ceil();
|
||||||
while (_resizing) {
|
while (_resizing) {
|
||||||
await Future.delayed(Duration(milliseconds: 20));
|
await Future.delayed(const Duration(milliseconds: 20));
|
||||||
}
|
}
|
||||||
_resizing = true;
|
_resizing = true;
|
||||||
await widget.controller.resize(width, height);
|
await widget.controller.resize(width, height);
|
||||||
@@ -237,7 +234,6 @@ class _SizedFilamentWidgetState extends State<_SizedFilamentWidget> {
|
|||||||
await widget.controller.setRendering(_wasRenderingOnInactive);
|
await widget.controller.setRendering(_wasRenderingOnInactive);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_lastState = state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -252,31 +248,55 @@ class _SizedFilamentWidgetState extends State<_SizedFilamentWidget> {
|
|||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ListenableBuilder(listenable: widget.controller.textureDetails, builder: (BuildContext ctx, Widget? wdgt) {
|
if (!widget.controller.requiresTextureWidget) {
|
||||||
|
|
||||||
if (widget.controller.textureDetails.value == null) {
|
|
||||||
return Stack(children: [
|
|
||||||
Positioned.fill(child: widget.initial ?? Container(color: Colors.red))
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
// see [FilamentControllerFFI.resize] for an explanation of how we deal with resizing
|
|
||||||
var texture = Texture(
|
|
||||||
key: ObjectKey("texture_${widget.controller.textureDetails.value!.textureId}"),
|
|
||||||
textureId: widget.controller.textureDetails.value!.textureId,
|
|
||||||
filterQuality: FilterQuality.none,
|
|
||||||
freeze: false,
|
|
||||||
);
|
|
||||||
|
|
||||||
return Stack(children: [
|
return Stack(children: [
|
||||||
Positioned.fill(
|
Positioned.fill(child: CustomPaint(painter: TransparencyPainter()))
|
||||||
child: Platform.isLinux || Platform.isWindows
|
|
||||||
? Transform(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
transform: Matrix4.rotationX(
|
|
||||||
pi), // TODO - this rotation is due to OpenGL texture coordinate working in a different space from Flutter, can we move this to the C++ side somewhere?
|
|
||||||
child: texture)
|
|
||||||
: texture)
|
|
||||||
]);
|
]);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
return ListenableBuilder(
|
||||||
|
listenable: widget.controller.textureDetails,
|
||||||
|
builder: (BuildContext ctx, Widget? wdgt) {
|
||||||
|
if (widget.controller.textureDetails.value == null) {
|
||||||
|
return Stack(children: [
|
||||||
|
Positioned.fill(
|
||||||
|
child: widget.initial ?? Container(color: Colors.red))
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
// see [FilamentControllerFFI.resize] for an explanation of how we deal with resizing
|
||||||
|
var texture = Texture(
|
||||||
|
key: ObjectKey(
|
||||||
|
"texture_${widget.controller.textureDetails.value!.textureId}"),
|
||||||
|
textureId: widget.controller.textureDetails.value!.textureId,
|
||||||
|
filterQuality: FilterQuality.none,
|
||||||
|
freeze: false,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Stack(children: [
|
||||||
|
Positioned.fill(
|
||||||
|
child: Platform.isLinux || Platform.isWindows
|
||||||
|
? Transform(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
transform: Matrix4.rotationX(
|
||||||
|
pi), // TODO - this rotation is due to OpenGL texture coordinate working in a different space from Flutter, can we move this to the C++ side somewhere?
|
||||||
|
child: texture)
|
||||||
|
: texture)
|
||||||
|
]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TransparencyPainter extends CustomPainter {
|
||||||
|
@override
|
||||||
|
void paint(Canvas canvas, Size size) {
|
||||||
|
canvas.drawRect(
|
||||||
|
Rect.fromLTWH(0, 0, size.width, size.height),
|
||||||
|
Paint()
|
||||||
|
..blendMode = BlendMode.clear
|
||||||
|
..color = const Color(0x00000000),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,21 +23,19 @@ list(APPEND PLUGIN_SOURCES
|
|||||||
)
|
)
|
||||||
|
|
||||||
set(USE_ANGLE FALSE)
|
set(USE_ANGLE FALSE)
|
||||||
|
|
||||||
if(!USE_ANGLE)
|
|
||||||
set(WGL_USE_BACKING_WINDOW TRUE)
|
set(WGL_USE_BACKING_WINDOW TRUE)
|
||||||
endif()
|
|
||||||
|
|
||||||
if(USE_ANGLE)
|
if(USE_ANGLE)
|
||||||
add_compile_definitions(USE_ANGLE)
|
add_compile_definitions(USE_ANGLE)
|
||||||
list(APPEND PLUGIN_SOURCES "flutter_angle_texture.cpp" "egl_context.cpp" )
|
list(APPEND PLUGIN_SOURCES "flutter_angle_texture.cpp" "egl_context.cpp" )
|
||||||
else()
|
else()
|
||||||
list(APPEND PLUGIN_SOURCES "wgl_context.cpp")
|
add_compile_definitions(WGL_USE_BACKING_WINDOW)
|
||||||
if(WGL_USE_BACKING_WINDOW)
|
list(APPEND PLUGIN_SOURCES "wgl_context.cpp" "opengl_texture_buffer.cpp" "backing_window.cpp")
|
||||||
list(APPEND PLUGIN_SOURCES "utils.cc" "backing_window.cpp")
|
# if(WGL_USE_BACKING_WINDOW)
|
||||||
else()
|
# list(APPEND PLUGIN_SOURCES )
|
||||||
list(APPEND PLUGIN_SOURCES "opengl_texture_buffer.cpp")
|
# else()
|
||||||
endif()
|
# list(APPEND PLUGIN_SOURCES )
|
||||||
|
# endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Define the plugin library target. Its name must not be changed (see comment
|
# Define the plugin library target. Its name must not be changed (see comment
|
||||||
|
|||||||
@@ -1,5 +1,18 @@
|
|||||||
#include "backing_window.h"
|
#include "backing_window.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iostream>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <Commctrl.h>
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <dwmapi.h>
|
||||||
|
#include <ShObjIdl.h>
|
||||||
|
|
||||||
|
#pragma comment(lib, "dwmapi.lib")
|
||||||
|
#pragma comment(lib, "comctl32.lib")
|
||||||
|
|
||||||
namespace polyvox_filament {
|
namespace polyvox_filament {
|
||||||
|
|
||||||
static constexpr auto kClassName = L"FLUTTER_FILAMENT_WINDOW";
|
static constexpr auto kClassName = L"FLUTTER_FILAMENT_WINDOW";
|
||||||
@@ -9,6 +22,116 @@ static WPARAM last_wm_size_wparam_ = SIZE_RESTORED;
|
|||||||
uint64_t last_thread_time_ = 0;
|
uint64_t last_thread_time_ = 0;
|
||||||
static constexpr auto kNativeViewPositionAndShowDelay = 300;
|
static constexpr auto kNativeViewPositionAndShowDelay = 300;
|
||||||
|
|
||||||
|
typedef enum _WINDOWCOMPOSITIONATTRIB {
|
||||||
|
WCA_UNDEFINED = 0,
|
||||||
|
WCA_NCRENDERING_ENABLED = 1,
|
||||||
|
WCA_NCRENDERING_POLICY = 2,
|
||||||
|
WCA_TRANSITIONS_FORCEDISABLED = 3,
|
||||||
|
WCA_ALLOW_NCPAINT = 4,
|
||||||
|
WCA_CAPTION_BUTTON_BOUNDS = 5,
|
||||||
|
WCA_NONCLIENT_RTL_LAYOUT = 6,
|
||||||
|
WCA_FORCE_ICONIC_REPRESENTATION = 7,
|
||||||
|
WCA_EXTENDED_FRAME_BOUNDS = 8,
|
||||||
|
WCA_HAS_ICONIC_BITMAP = 9,
|
||||||
|
WCA_THEME_ATTRIBUTES = 10,
|
||||||
|
WCA_NCRENDERING_EXILED = 11,
|
||||||
|
WCA_NCADORNMENTINFO = 12,
|
||||||
|
WCA_EXCLUDED_FROM_LIVEPREVIEW = 13,
|
||||||
|
WCA_VIDEO_OVERLAY_ACTIVE = 14,
|
||||||
|
WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15,
|
||||||
|
WCA_DISALLOW_PEEK = 16,
|
||||||
|
WCA_CLOAK = 17,
|
||||||
|
WCA_CLOAKED = 18,
|
||||||
|
WCA_ACCENT_POLICY = 19,
|
||||||
|
WCA_FREEZE_REPRESENTATION = 20,
|
||||||
|
WCA_EVER_UNCLOAKED = 21,
|
||||||
|
WCA_VISUAL_OWNER = 22,
|
||||||
|
WCA_HOLOGRAPHIC = 23,
|
||||||
|
WCA_EXCLUDED_FROM_DDA = 24,
|
||||||
|
WCA_PASSIVEUPDATEMODE = 25,
|
||||||
|
WCA_USEDARKMODECOLORS = 26,
|
||||||
|
WCA_LAST = 27
|
||||||
|
} WINDOWCOMPOSITIONATTRIB;
|
||||||
|
|
||||||
|
typedef struct _WINDOWCOMPOSITIONATTRIBDATA {
|
||||||
|
WINDOWCOMPOSITIONATTRIB Attrib;
|
||||||
|
PVOID pvData;
|
||||||
|
SIZE_T cbData;
|
||||||
|
} WINDOWCOMPOSITIONATTRIBDATA;
|
||||||
|
|
||||||
|
typedef enum _ACCENT_STATE {
|
||||||
|
ACCENT_DISABLED = 0,
|
||||||
|
ACCENT_ENABLE_GRADIENT = 1,
|
||||||
|
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
|
||||||
|
ACCENT_ENABLE_BLURBEHIND = 3,
|
||||||
|
ACCENT_ENABLE_ACRYLICBLURBEHIND = 4,
|
||||||
|
ACCENT_ENABLE_HOSTBACKDROP = 5,
|
||||||
|
ACCENT_INVALID_STATE = 6
|
||||||
|
} ACCENT_STATE;
|
||||||
|
|
||||||
|
typedef struct _ACCENT_POLICY {
|
||||||
|
ACCENT_STATE AccentState;
|
||||||
|
DWORD AccentFlags;
|
||||||
|
DWORD GradientColor;
|
||||||
|
DWORD AnimationId;
|
||||||
|
} ACCENT_POLICY;
|
||||||
|
|
||||||
|
typedef BOOL(WINAPI* _GetWindowCompositionAttribute)(
|
||||||
|
HWND, WINDOWCOMPOSITIONATTRIBDATA*);
|
||||||
|
typedef BOOL(WINAPI* _SetWindowCompositionAttribute)(
|
||||||
|
HWND, WINDOWCOMPOSITIONATTRIBDATA*);
|
||||||
|
|
||||||
|
static _SetWindowCompositionAttribute g_set_window_composition_attribute = NULL;
|
||||||
|
static bool g_set_window_composition_attribute_initialized = false;
|
||||||
|
|
||||||
|
typedef LONG NTSTATUS, *PNTSTATUS;
|
||||||
|
#define STATUS_SUCCESS (0x00000000)
|
||||||
|
|
||||||
|
typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
|
||||||
|
|
||||||
|
RTL_OSVERSIONINFOW GetWindowsVersion() {
|
||||||
|
HMODULE hmodule = ::GetModuleHandleW(L"ntdll.dll");
|
||||||
|
if (hmodule) {
|
||||||
|
RtlGetVersionPtr rtl_get_version_ptr =
|
||||||
|
(RtlGetVersionPtr)::GetProcAddress(hmodule, "RtlGetVersion");
|
||||||
|
if (rtl_get_version_ptr != nullptr) {
|
||||||
|
RTL_OSVERSIONINFOW rovi = {0};
|
||||||
|
rovi.dwOSVersionInfoSize = sizeof(rovi);
|
||||||
|
if (STATUS_SUCCESS == rtl_get_version_ptr(&rovi)) {
|
||||||
|
return rovi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RTL_OSVERSIONINFOW rovi = {0};
|
||||||
|
return rovi;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetWindowComposition(HWND window, int32_t accent_state,
|
||||||
|
int32_t gradient_color) {
|
||||||
|
// TODO: Look for a better available API.
|
||||||
|
if (GetWindowsVersion().dwBuildNumber >= 18362) {
|
||||||
|
if (!g_set_window_composition_attribute_initialized) {
|
||||||
|
auto user32 = ::GetModuleHandleA("user32.dll");
|
||||||
|
if (user32) {
|
||||||
|
g_set_window_composition_attribute =
|
||||||
|
reinterpret_cast<_SetWindowCompositionAttribute>(
|
||||||
|
::GetProcAddress(user32, "SetWindowCompositionAttribute"));
|
||||||
|
if (g_set_window_composition_attribute) {
|
||||||
|
g_set_window_composition_attribute_initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ACCENT_POLICY accent = {static_cast<ACCENT_STATE>(accent_state), 2,
|
||||||
|
static_cast<DWORD>(gradient_color), 0};
|
||||||
|
WINDOWCOMPOSITIONATTRIBDATA data;
|
||||||
|
data.Attrib = WCA_ACCENT_POLICY;
|
||||||
|
data.pvData = &accent;
|
||||||
|
data.cbData = sizeof(accent);
|
||||||
|
g_set_window_composition_attribute(window, &data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
LRESULT NativeViewSubclassProc(HWND window, UINT message, WPARAM wparam,
|
LRESULT NativeViewSubclassProc(HWND window, UINT message, WPARAM wparam,
|
||||||
LPARAM lparam, UINT_PTR subclass_id,
|
LPARAM lparam, UINT_PTR subclass_id,
|
||||||
DWORD_PTR ref_data) noexcept {
|
DWORD_PTR ref_data) noexcept {
|
||||||
@@ -17,11 +140,12 @@ LRESULT NativeViewSubclassProc(HWND window, UINT message, WPARAM wparam,
|
|||||||
// Prevent erasing of |window| when it is unfocused and minimized or
|
// Prevent erasing of |window| when it is unfocused and minimized or
|
||||||
// moved out of screen etc.
|
// moved out of screen etc.
|
||||||
return 1;
|
return 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case WM_SIZE: {
|
case WM_SIZE: {
|
||||||
// Prevent unnecessary maxmize, minimize or restore messages for |window|.
|
// Prevent unnecessary maxmize, minimize or restore messages for |window|.
|
||||||
// Since it is |SetParent|'ed into native view container.
|
|
||||||
return 1;
|
return 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -32,6 +156,8 @@ LRESULT NativeViewSubclassProc(HWND window, UINT message, WPARAM wparam,
|
|||||||
LRESULT CALLBACK FilamentWindowProc(HWND const window, UINT const message,
|
LRESULT CALLBACK FilamentWindowProc(HWND const window, UINT const message,
|
||||||
WPARAM const wparam,
|
WPARAM const wparam,
|
||||||
LPARAM const lparam) noexcept {
|
LPARAM const lparam) noexcept {
|
||||||
|
// std::cout << "FILAMENT WINDOW EVENT " << message << std::endl;
|
||||||
|
|
||||||
switch (message) {
|
switch (message) {
|
||||||
case WM_MOUSEMOVE: {
|
case WM_MOUSEMOVE: {
|
||||||
std::cout << "FILAMENT MOUSE MOVE" << std::endl;
|
std::cout << "FILAMENT MOUSE MOVE" << std::endl;
|
||||||
@@ -56,14 +182,14 @@ LRESULT CALLBACK FilamentWindowProc(HWND const window, UINT const message,
|
|||||||
std::cout << "FILAMENT ERASE BKGND" << std::endl;
|
std::cout << "FILAMENT ERASE BKGND" << std::endl;
|
||||||
// Prevent erasing of |window| when it is unfocused and minimized or
|
// Prevent erasing of |window| when it is unfocused and minimized or
|
||||||
// moved out of screen etc.
|
// moved out of screen etc.
|
||||||
return 1;
|
break;
|
||||||
}
|
}
|
||||||
case WM_SIZE:
|
case WM_SIZE:
|
||||||
case WM_MOVE:
|
case WM_MOVE:
|
||||||
case WM_MOVING:
|
case WM_MOVING:
|
||||||
case WM_ACTIVATE:
|
case WM_ACTIVATE:
|
||||||
case WM_WINDOWPOSCHANGED: {
|
case WM_WINDOWPOSCHANGED: {
|
||||||
std::cout << "FILAMENT POS CHANGED" << std::endl;
|
// std::cout << "FILAMENT POS CHANGED" << std::endl;
|
||||||
// NativeViewCore::GetInstance()->SetHitTestBehavior(0);
|
// NativeViewCore::GetInstance()->SetHitTestBehavior(0);
|
||||||
auto user_data = ::GetWindowLongPtr(window, GWLP_USERDATA);
|
auto user_data = ::GetWindowLongPtr(window, GWLP_USERDATA);
|
||||||
if (user_data) {
|
if (user_data) {
|
||||||
@@ -83,168 +209,178 @@ LRESULT CALLBACK FilamentWindowProc(HWND const window, UINT const message,
|
|||||||
return ::DefWindowProc(window, message, wparam, lparam);
|
return ::DefWindowProc(window, message, wparam, lparam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BackingWindow::BackingWindow(flutter::PluginRegistrarWindows *pluginRegistrar,
|
||||||
|
int initialWidth, int initialHeight) {
|
||||||
|
// a Flutter application actually has two windows - the innner window contains the FlutterView.
|
||||||
|
// although we will use the outer window for various events, we always position things relative to the inner window.
|
||||||
|
_flutterViewWindow = pluginRegistrar->GetView()->GetNativeWindow();
|
||||||
|
_flutterRootWindow = ::GetAncestor(_flutterViewWindow, GA_ROOT);
|
||||||
|
|
||||||
class BackingWindow {
|
RECT flutterChildRect;
|
||||||
|
::GetWindowRect(_flutterViewWindow, &flutterChildRect);
|
||||||
|
// ::GetClientRect(flutterWindow, &flutterChildRect);
|
||||||
|
|
||||||
BackingWindow::BackingWindow(
|
std::cout << "child rect " << flutterChildRect.left << " " << flutterChildRect.top << " " << flutterChildRect.right << " " << flutterChildRect.bottom << std::endl;
|
||||||
flutter::PluginRegistrarWindows *pluginRegistrar,
|
|
||||||
int initialWidth,
|
|
||||||
int initialHeight) {
|
|
||||||
// get the root Flutter window
|
|
||||||
HWND flutterWindow = pluginRegistrar->GetView()->GetNativeWindow();
|
|
||||||
_flutterRootWindow = ::GetAncestor(flutterWindow, GA_ROOT);
|
|
||||||
|
|
||||||
// set composition to allow transparency
|
// set composition to allow transparency
|
||||||
flutternativeview::SetWindowComposition(_flutterRootWindow, 6, 0);
|
SetWindowComposition(_flutterRootWindow, 6, 0);
|
||||||
|
|
||||||
// register a top-level WindowProcDelegate to handle window events
|
// register a top-level WindowProcDelegate to handle window events
|
||||||
pluginRegistrar->RegisterTopLevelWindowProcDelegate([=](HWND hwnd,
|
pluginRegistrar->RegisterTopLevelWindowProcDelegate([=](HWND hwnd,
|
||||||
UINT message,
|
UINT message,
|
||||||
WPARAM wparam,
|
WPARAM wparam,
|
||||||
LPARAM lparam) {
|
LPARAM lparam) {
|
||||||
switch (message) {
|
// std::cout << "TOP LEVEL EVENT " << message << std::endl;
|
||||||
case WM_ACTIVATE: {
|
switch (message) {
|
||||||
std::cout << "WM_ACTIVATE" << std::endl;
|
case WM_MOUSEMOVE: {
|
||||||
RECT window_rect;
|
// std::cout << "FLUTTER MOUSE MOVE" << std::endl;
|
||||||
::GetWindowRect(_flutterRootWindow, &window_rect);
|
break;
|
||||||
// Position |native_view| such that it's z order is behind |window_| &
|
}
|
||||||
// redraw aswell.
|
case WM_ACTIVATE: {
|
||||||
::SetWindowPos(_windowHandle, _flutterRootWindow, window_rect.left,
|
std::cout << "WM_ACTIVATE" << std::endl;
|
||||||
window_rect.top, window_rect.right - window_rect.left,
|
RECT rootWindowRect;
|
||||||
window_rect.bottom - window_rect.top, SWP_NOACTIVATE);
|
::GetWindowRect(_flutterViewWindow, &rootWindowRect);
|
||||||
break;
|
// Position |native_view| such that it's z order is behind |window_| &
|
||||||
}
|
// redraw aswell.
|
||||||
case WM_SIZE: {
|
::SetWindowPos(_windowHandle, _flutterRootWindow, rootWindowRect.left,
|
||||||
std::cout << "WM_SIZE" << std::endl;
|
rootWindowRect.top, rootWindowRect.right - rootWindowRect.left,
|
||||||
|
rootWindowRect.bottom - rootWindowRect.top, SWP_NOACTIVATE);
|
||||||
// Handle Windows's minimize & maximize animations properly.
|
break;
|
||||||
// Since |SetWindowPos| & other Win32 APIs on |native_view_container_|
|
|
||||||
// do not re-produce the same DWM animations like actual user
|
|
||||||
// interractions on the |window_| do (though both windows are overlapped
|
|
||||||
// tightly but maximize and minimze animations can't be mimiced for the
|
|
||||||
// both of them at the same time), the best solution is to make the
|
|
||||||
// |window_| opaque & hide |native_view_container_| & alter it's position.
|
|
||||||
// After that, finally make |native_view_container_| visible again &
|
|
||||||
// |window_| transparent again. This approach is not perfect, but it's the
|
|
||||||
// best we can do. The minimize & maximize animations on the |window_|
|
|
||||||
// look good with just a slight glitch on the visible native views. In
|
|
||||||
// future, maybe replacing the |NativeView| widget (Flutter-side) with
|
|
||||||
// equivalent window screenshot will result in a totally seamless
|
|
||||||
// experience.
|
|
||||||
if (wparam != SIZE_RESTORED || last_wm_size_wparam_ == SIZE_MINIMIZED ||
|
|
||||||
last_wm_size_wparam_ == SIZE_MAXIMIZED ||
|
|
||||||
was_window_hidden_due_to_minimize_) {
|
|
||||||
was_window_hidden_due_to_minimize_ = false;
|
|
||||||
// Minimize condition is handled separately inside |WM_WINDOWPOSCHANGED|
|
|
||||||
// case, since we don't want to cause unnecessary redraws (& show/hide)
|
|
||||||
// when user is resizing the window by dragging the window border.
|
|
||||||
SetWindowComposition(_flutterRootWindow, 0, 0);
|
|
||||||
::ShowWindow(_windowHandle, SW_HIDE);
|
|
||||||
last_thread_time_ =
|
|
||||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
||||||
std::chrono::system_clock::now().time_since_epoch())
|
|
||||||
.count();
|
|
||||||
std::thread(
|
|
||||||
[=](uint64_t time) {
|
|
||||||
if (time < last_thread_time_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::this_thread::sleep_for(
|
|
||||||
std::chrono::milliseconds(kNativeViewPositionAndShowDelay));
|
|
||||||
SetWindowComposition(_flutterRootWindow, 6, 0);
|
|
||||||
// Handling SIZE_MINIMIZED separately.
|
|
||||||
if (wparam != SIZE_MINIMIZED) {
|
|
||||||
::ShowWindow(_windowHandle, SW_SHOWNOACTIVATE);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
last_thread_time_)
|
|
||||||
.detach();
|
|
||||||
}
|
|
||||||
last_wm_size_wparam_ = wparam;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Keep |native_view_container_| behind the |window_|.
|
|
||||||
case WM_MOVE:
|
|
||||||
case WM_MOVING:
|
|
||||||
case WM_WINDOWPOSCHANGED: {
|
|
||||||
std::cout << "FLUTTER WINDOWPOSCHANGED"<< std::endl;
|
|
||||||
RECT window_rect;
|
|
||||||
::GetWindowRect(_flutterRootWindow, &window_rect);
|
|
||||||
if (window_rect.right - window_rect.left > 0 &&
|
|
||||||
window_rect.bottom - window_rect.top > 0) {
|
|
||||||
::SetWindowPos(_windowHandle, _flutterRootWindow, window_rect.left,
|
|
||||||
window_rect.top, window_rect.right - window_rect.left,
|
|
||||||
window_rect.bottom - window_rect.top, SWP_NOACTIVATE);
|
|
||||||
// |window_| is minimized.
|
|
||||||
if (window_rect.left < 0 && window_rect.top < 0 &&
|
|
||||||
window_rect.right < 0 && window_rect.bottom < 0) {
|
|
||||||
// Hide |native_view_container_| to prevent showing
|
|
||||||
// |native_view_container_| before |window_| placement
|
|
||||||
// i.e when restoring window after clicking the taskbar icon.
|
|
||||||
SetWindowComposition(_flutterRootWindow, 0, 0);
|
|
||||||
::ShowWindow(_windowHandle, SW_HIDE);
|
|
||||||
was_window_hidden_due_to_minimize_ = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WM_CLOSE: {
|
|
||||||
// close
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
});
|
|
||||||
|
|
||||||
// create the HWND for Filament
|
|
||||||
auto window_class = WNDCLASSEX{};
|
|
||||||
::SecureZeroMemory(&window_class, sizeof(window_class));
|
|
||||||
window_class.cbSize = sizeof(window_class);
|
|
||||||
window_class.style = CS_HREDRAW | CS_VREDRAW;
|
|
||||||
window_class.lpfnWndProc = FilamentWindowProc;
|
|
||||||
window_class.hInstance = 0;
|
|
||||||
window_class.lpszClassName = kClassName;
|
|
||||||
window_class.hCursor = ::LoadCursorW(nullptr, IDC_ARROW);
|
|
||||||
window_class.hbrBackground = ::CreateSolidBrush(RGB(0, 255, 0));
|
|
||||||
::RegisterClassExW(&window_class);
|
|
||||||
_windowHandle =
|
|
||||||
::CreateWindow(kClassName, kWindowName, WS_OVERLAPPEDWINDOW, 0, 0, initialWidth, initialHeight,
|
|
||||||
nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
|
|
||||||
|
|
||||||
// Disable DWM animations
|
|
||||||
auto disable_window_transitions = TRUE;
|
|
||||||
DwmSetWindowAttribute(_windowHandle, DWMWA_TRANSITIONS_FORCEDISABLED,
|
|
||||||
&disable_window_transitions,
|
|
||||||
sizeof(disable_window_transitions));
|
|
||||||
|
|
||||||
::SetWindowSubclass(_windowHandle, NativeViewSubclassProc, 69420,
|
|
||||||
NULL); // what does this do?
|
|
||||||
|
|
||||||
auto style = ::GetWindowLongPtr(_windowHandle, GWL_STYLE);
|
|
||||||
style &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX |
|
|
||||||
WS_EX_APPWINDOW);
|
|
||||||
::SetWindowLongPtr(_windowHandle, GWL_STYLE, style);
|
|
||||||
|
|
||||||
RECT flutterWindowRect;
|
|
||||||
::GetClientRect(_flutterRootWindow, &flutterWindowRect);
|
|
||||||
|
|
||||||
::SetWindowLongPtr(_windowHandle, GWLP_USERDATA,
|
|
||||||
reinterpret_cast<LONG>(_flutterRootWindow));
|
|
||||||
|
|
||||||
::SetWindowPos(_windowHandle, _flutterRootWindow, flutterWindowRect.left,
|
|
||||||
flutterWindowRect.top, initialWidth, initialHeight, SWP_SHOWWINDOW);
|
|
||||||
// flutterWindowRect.right - flutterWindowRect.left,
|
|
||||||
// flutterWindowRect.bottom - flutterWindowRect.top, SWP_SHOWWINDOW);
|
|
||||||
::ShowWindow(_windowHandle, SW_SHOW);
|
|
||||||
::ShowWindow(_flutterRootWindow, SW_SHOW);
|
|
||||||
::SetFocus(_flutterRootWindow);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
case WM_SIZE: {
|
||||||
|
std::cout << "WM_SIZE" << std::endl;
|
||||||
|
|
||||||
BackingWindow::GetHandle() {
|
// Handle Windows's minimize & maximize animations properly.
|
||||||
return _windowHandle;
|
// Since |SetWindowPos| & other Win32 APIs on |native_view_container_|
|
||||||
|
// do not re-produce the same DWM animations like actual user
|
||||||
|
// interractions on the |window_| do (though both windows are overlapped
|
||||||
|
// tightly but maximize and minimze animations can't be mimiced for the
|
||||||
|
// both of them at the same time), the best solution is to make the
|
||||||
|
// |window_| opaque & hide |native_view_container_| & alter it's position.
|
||||||
|
// After that, finally make |native_view_container_| visible again &
|
||||||
|
// |window_| transparent again. This approach is not perfect, but it's the
|
||||||
|
// best we can do. The minimize & maximize animations on the |window_|
|
||||||
|
// look good with just a slight glitch on the visible native views. In
|
||||||
|
// future, maybe replacing the |NativeView| widget (Flutter-side) with
|
||||||
|
// equivalent window screenshot will result in a totally seamless
|
||||||
|
// experience.
|
||||||
|
if (wparam != SIZE_RESTORED || last_wm_size_wparam_ == SIZE_MINIMIZED ||
|
||||||
|
last_wm_size_wparam_ == SIZE_MAXIMIZED ||
|
||||||
|
was_window_hidden_due_to_minimize_) {
|
||||||
|
was_window_hidden_due_to_minimize_ = false;
|
||||||
|
// Minimize condition is handled separately inside |WM_WINDOWPOSCHANGED|
|
||||||
|
// case, since we don't want to cause unnecessary redraws (& show/hide)
|
||||||
|
// when user is resizing the window by dragging the window border.
|
||||||
|
SetWindowComposition(_flutterRootWindow, 0, 0);
|
||||||
|
::ShowWindow(_windowHandle, SW_HIDE);
|
||||||
|
last_thread_time_ =
|
||||||
|
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
|
std::chrono::system_clock::now().time_since_epoch())
|
||||||
|
.count();
|
||||||
|
std::thread(
|
||||||
|
[=](uint64_t time) {
|
||||||
|
if (time < last_thread_time_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(
|
||||||
|
std::chrono::milliseconds(kNativeViewPositionAndShowDelay));
|
||||||
|
SetWindowComposition(_flutterRootWindow, 6, 0);
|
||||||
|
// Handling SIZE_MINIMIZED separately.
|
||||||
|
if (wparam != SIZE_MINIMIZED) {
|
||||||
|
::ShowWindow(_windowHandle, SW_SHOWNOACTIVATE);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
last_thread_time_)
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
last_wm_size_wparam_ = wparam;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
// Keep |native_view_container_| behind the |window_|.
|
||||||
|
case WM_MOVE:
|
||||||
|
case WM_MOVING:
|
||||||
|
case WM_WINDOWPOSCHANGED: {
|
||||||
|
RECT rootWindowRect;
|
||||||
|
::GetWindowRect(_flutterViewWindow, &rootWindowRect);
|
||||||
|
// std::cout << "FLUTTER WINDOWPOSCHANGED TO " << rootWindowRect.left << " " << rootWindowRect.top << " " << rootWindowRect.right << " " << rootWindowRect.bottom << std::endl;
|
||||||
|
if (rootWindowRect.right - rootWindowRect.left > 0 &&
|
||||||
|
rootWindowRect.bottom - rootWindowRect.top > 0) {
|
||||||
|
::SetWindowPos(_windowHandle, _flutterRootWindow, rootWindowRect.left,
|
||||||
|
rootWindowRect.top, rootWindowRect.right - rootWindowRect.left,
|
||||||
|
rootWindowRect.bottom - rootWindowRect.top, SWP_NOACTIVATE);
|
||||||
|
// |window_| is minimized.
|
||||||
|
if (rootWindowRect.left < 0 && rootWindowRect.top < 0 &&
|
||||||
|
rootWindowRect.right < 0 && rootWindowRect.bottom < 0) {
|
||||||
|
// Hide |native_view_container_| to prevent showing
|
||||||
|
// |native_view_container_| before |window_| placement
|
||||||
|
// i.e when restoring window after clicking the taskbar icon.
|
||||||
|
SetWindowComposition(_flutterRootWindow, 0, 0);
|
||||||
|
::ShowWindow(_windowHandle, SW_HIDE);
|
||||||
|
was_window_hidden_due_to_minimize_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WM_CLOSE: {
|
||||||
|
// close
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
});
|
||||||
|
|
||||||
|
// create the HWND for Filament
|
||||||
|
auto window_class = WNDCLASSEX{};
|
||||||
|
::SecureZeroMemory(&window_class, sizeof(window_class));
|
||||||
|
window_class.cbSize = sizeof(window_class);
|
||||||
|
window_class.style = CS_HREDRAW | CS_VREDRAW;
|
||||||
|
window_class.lpfnWndProc = FilamentWindowProc;
|
||||||
|
window_class.hInstance = 0;
|
||||||
|
window_class.lpszClassName = kClassName;
|
||||||
|
window_class.hCursor = ::LoadCursorW(nullptr, IDC_ARROW);
|
||||||
|
window_class.hbrBackground = ::CreateSolidBrush(0);
|
||||||
|
::RegisterClassExW(&window_class);
|
||||||
|
_windowHandle = ::CreateWindow(kClassName, kWindowName, WS_OVERLAPPEDWINDOW,
|
||||||
|
0, 0, initialWidth, initialHeight, nullptr,
|
||||||
|
nullptr, GetModuleHandle(nullptr), nullptr);
|
||||||
|
|
||||||
|
// Disable DWM animations
|
||||||
|
auto disable_window_transitions = TRUE;
|
||||||
|
DwmSetWindowAttribute(_windowHandle, DWMWA_TRANSITIONS_FORCEDISABLED,
|
||||||
|
&disable_window_transitions,
|
||||||
|
sizeof(disable_window_transitions));
|
||||||
|
|
||||||
|
::SetWindowSubclass(_windowHandle, NativeViewSubclassProc, 69420,
|
||||||
|
NULL); // what does this do?
|
||||||
|
|
||||||
|
auto style = ::GetWindowLongPtr(_windowHandle, GWL_STYLE);
|
||||||
|
style &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX |
|
||||||
|
WS_EX_APPWINDOW);
|
||||||
|
::SetWindowLongPtr(_windowHandle, GWL_STYLE, style);
|
||||||
|
|
||||||
|
RECT flutterViewRect;
|
||||||
|
::GetClientRect(_flutterViewWindow, &flutterViewRect);
|
||||||
|
|
||||||
|
::SetWindowLongPtr(_windowHandle, GWLP_USERDATA,
|
||||||
|
reinterpret_cast<LONG>(_flutterRootWindow));
|
||||||
|
|
||||||
|
::SetWindowPos(_windowHandle, _flutterRootWindow, flutterViewRect.left,
|
||||||
|
flutterViewRect.top, flutterViewRect.right - flutterViewRect.left, flutterViewRect.bottom - flutterViewRect.top,
|
||||||
|
SWP_NOACTIVATE);
|
||||||
|
|
||||||
|
// remove taskbar entry for the window we created
|
||||||
|
ITaskbarList3* taskbar = nullptr;
|
||||||
|
::CoCreateInstance(CLSID_TaskbarList, 0, CLSCTX_INPROC_SERVER,
|
||||||
|
IID_PPV_ARGS(&taskbar));
|
||||||
|
taskbar->DeleteTab(_windowHandle);
|
||||||
|
taskbar->Release();
|
||||||
|
|
||||||
|
::ShowWindow(_windowHandle, SW_SHOW);
|
||||||
|
::ShowWindow(_flutterRootWindow, SW_SHOW);
|
||||||
|
::SetFocus(_flutterRootWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HWND BackingWindow::GetHandle() { return _windowHandle; }
|
||||||
|
} // namespace polyvox_filament
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ class BackingWindow {
|
|||||||
private:
|
private:
|
||||||
HWND _windowHandle;
|
HWND _windowHandle;
|
||||||
HWND _flutterRootWindow;
|
HWND _flutterRootWindow;
|
||||||
}
|
HWND _flutterViewWindow;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -36,8 +36,6 @@
|
|||||||
#include <dwmapi.h>
|
#include <dwmapi.h>
|
||||||
#include <wrl.h>
|
#include <wrl.h>
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
#include "flutter_render_context.h"
|
#include "flutter_render_context.h"
|
||||||
|
|
||||||
#if USE_ANGLE
|
#if USE_ANGLE
|
||||||
@@ -181,7 +179,7 @@ void PolyvoxFilamentPlugin::CreateTexture(
|
|||||||
_context = std::make_unique<WGLContext>(_pluginRegistrar, _textureRegistrar);
|
_context = std::make_unique<WGLContext>(_pluginRegistrar, _textureRegistrar);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
//_context->CreateTexture(width, height, std::move(result));
|
_context->CreateTexture(width, height, std::move(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PolyvoxFilamentPlugin::DestroyTexture(
|
void PolyvoxFilamentPlugin::DestroyTexture(
|
||||||
@@ -228,14 +226,15 @@ void PolyvoxFilamentPlugin::HandleMethodCall(
|
|||||||
} else if (methodCall.method_name() == "destroyTexture") {
|
} else if (methodCall.method_name() == "destroyTexture") {
|
||||||
DestroyTexture(methodCall, std::move(result));
|
DestroyTexture(methodCall, std::move(result));
|
||||||
} else if (methodCall.method_name() == "getRenderCallback") {
|
} else if (methodCall.method_name() == "getRenderCallback") {
|
||||||
|
flutter::EncodableList resultList;
|
||||||
#if !ANGLE && WGL_USE_BACKING_WINDOW
|
#if !ANGLE && WGL_USE_BACKING_WINDOW
|
||||||
result->Success(nullptr);
|
resultList.push_back(flutter::EncodableValue((int64_t)nullptr));
|
||||||
|
resultList.push_back(flutter::EncodableValue((int64_t)nullptr));
|
||||||
#else
|
#else
|
||||||
flutter::EncodableList resultList;
|
|
||||||
resultList.push_back(flutter::EncodableValue((int64_t)&render_callback));
|
resultList.push_back(flutter::EncodableValue((int64_t)&render_callback));
|
||||||
resultList.push_back(flutter::EncodableValue((int64_t)this));
|
resultList.push_back(flutter::EncodableValue((int64_t)this));
|
||||||
result->Success(resultList);
|
|
||||||
#endif
|
#endif
|
||||||
|
result->Success(resultList);
|
||||||
} else if (methodCall.method_name() == "getDriverPlatform") {
|
} else if (methodCall.method_name() == "getDriverPlatform") {
|
||||||
#ifdef USE_ANGLE
|
#ifdef USE_ANGLE
|
||||||
result->Success(flutter::EncodableValue((int64_t)_platform));
|
result->Success(flutter::EncodableValue((int64_t)_platform));
|
||||||
|
|||||||
130
windows/utils.cc
130
windows/utils.cc
@@ -1,130 +0,0 @@
|
|||||||
// This file is a part of flutter_native_view
|
|
||||||
// (https://github.com/alexmercerind/flutter_native_view).
|
|
||||||
//
|
|
||||||
// Copyright (c) 2022, Hitesh Kumar Saini <saini123hitesh@gmail.com>.
|
|
||||||
// All rights reserved.
|
|
||||||
// Use of this source code is governed by MIT license that can be found in the
|
|
||||||
// LICENSE file.
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#pragma comment(lib, "dwmapi.lib")
|
|
||||||
#pragma comment(lib, "comctl32.lib")
|
|
||||||
|
|
||||||
namespace flutternativeview {
|
|
||||||
|
|
||||||
typedef enum _WINDOWCOMPOSITIONATTRIB {
|
|
||||||
WCA_UNDEFINED = 0,
|
|
||||||
WCA_NCRENDERING_ENABLED = 1,
|
|
||||||
WCA_NCRENDERING_POLICY = 2,
|
|
||||||
WCA_TRANSITIONS_FORCEDISABLED = 3,
|
|
||||||
WCA_ALLOW_NCPAINT = 4,
|
|
||||||
WCA_CAPTION_BUTTON_BOUNDS = 5,
|
|
||||||
WCA_NONCLIENT_RTL_LAYOUT = 6,
|
|
||||||
WCA_FORCE_ICONIC_REPRESENTATION = 7,
|
|
||||||
WCA_EXTENDED_FRAME_BOUNDS = 8,
|
|
||||||
WCA_HAS_ICONIC_BITMAP = 9,
|
|
||||||
WCA_THEME_ATTRIBUTES = 10,
|
|
||||||
WCA_NCRENDERING_EXILED = 11,
|
|
||||||
WCA_NCADORNMENTINFO = 12,
|
|
||||||
WCA_EXCLUDED_FROM_LIVEPREVIEW = 13,
|
|
||||||
WCA_VIDEO_OVERLAY_ACTIVE = 14,
|
|
||||||
WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15,
|
|
||||||
WCA_DISALLOW_PEEK = 16,
|
|
||||||
WCA_CLOAK = 17,
|
|
||||||
WCA_CLOAKED = 18,
|
|
||||||
WCA_ACCENT_POLICY = 19,
|
|
||||||
WCA_FREEZE_REPRESENTATION = 20,
|
|
||||||
WCA_EVER_UNCLOAKED = 21,
|
|
||||||
WCA_VISUAL_OWNER = 22,
|
|
||||||
WCA_HOLOGRAPHIC = 23,
|
|
||||||
WCA_EXCLUDED_FROM_DDA = 24,
|
|
||||||
WCA_PASSIVEUPDATEMODE = 25,
|
|
||||||
WCA_USEDARKMODECOLORS = 26,
|
|
||||||
WCA_LAST = 27
|
|
||||||
} WINDOWCOMPOSITIONATTRIB;
|
|
||||||
|
|
||||||
typedef struct _WINDOWCOMPOSITIONATTRIBDATA {
|
|
||||||
WINDOWCOMPOSITIONATTRIB Attrib;
|
|
||||||
PVOID pvData;
|
|
||||||
SIZE_T cbData;
|
|
||||||
} WINDOWCOMPOSITIONATTRIBDATA;
|
|
||||||
|
|
||||||
typedef enum _ACCENT_STATE {
|
|
||||||
ACCENT_DISABLED = 0,
|
|
||||||
ACCENT_ENABLE_GRADIENT = 1,
|
|
||||||
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
|
|
||||||
ACCENT_ENABLE_BLURBEHIND = 3,
|
|
||||||
ACCENT_ENABLE_ACRYLICBLURBEHIND = 4,
|
|
||||||
ACCENT_ENABLE_HOSTBACKDROP = 5,
|
|
||||||
ACCENT_INVALID_STATE = 6
|
|
||||||
} ACCENT_STATE;
|
|
||||||
|
|
||||||
typedef struct _ACCENT_POLICY {
|
|
||||||
ACCENT_STATE AccentState;
|
|
||||||
DWORD AccentFlags;
|
|
||||||
DWORD GradientColor;
|
|
||||||
DWORD AnimationId;
|
|
||||||
} ACCENT_POLICY;
|
|
||||||
|
|
||||||
typedef BOOL(WINAPI* _GetWindowCompositionAttribute)(
|
|
||||||
HWND, WINDOWCOMPOSITIONATTRIBDATA*);
|
|
||||||
typedef BOOL(WINAPI* _SetWindowCompositionAttribute)(
|
|
||||||
HWND, WINDOWCOMPOSITIONATTRIBDATA*);
|
|
||||||
|
|
||||||
static _SetWindowCompositionAttribute g_set_window_composition_attribute = NULL;
|
|
||||||
static bool g_set_window_composition_attribute_initialized = false;
|
|
||||||
|
|
||||||
typedef LONG NTSTATUS, *PNTSTATUS;
|
|
||||||
#define STATUS_SUCCESS (0x00000000)
|
|
||||||
|
|
||||||
typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
|
|
||||||
|
|
||||||
RTL_OSVERSIONINFOW GetWindowsVersion() {
|
|
||||||
HMODULE hmodule = ::GetModuleHandleW(L"ntdll.dll");
|
|
||||||
if (hmodule) {
|
|
||||||
RtlGetVersionPtr rtl_get_version_ptr =
|
|
||||||
(RtlGetVersionPtr)::GetProcAddress(hmodule, "RtlGetVersion");
|
|
||||||
if (rtl_get_version_ptr != nullptr) {
|
|
||||||
RTL_OSVERSIONINFOW rovi = {0};
|
|
||||||
rovi.dwOSVersionInfoSize = sizeof(rovi);
|
|
||||||
if (STATUS_SUCCESS == rtl_get_version_ptr(&rovi)) {
|
|
||||||
return rovi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RTL_OSVERSIONINFOW rovi = {0};
|
|
||||||
return rovi;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetWindowComposition(HWND window, int32_t accent_state,
|
|
||||||
int32_t gradient_color) {
|
|
||||||
// TODO: Look for a better available API.
|
|
||||||
if (GetWindowsVersion().dwBuildNumber >= 18362) {
|
|
||||||
std::cout << "got win ver" << std::endl;
|
|
||||||
if (!g_set_window_composition_attribute_initialized) {
|
|
||||||
std::cout << "not init" << std::endl;
|
|
||||||
auto user32 = ::GetModuleHandleA("user32.dll");
|
|
||||||
if (user32) {
|
|
||||||
std::cout << "user32" << std::endl;
|
|
||||||
g_set_window_composition_attribute =
|
|
||||||
reinterpret_cast<_SetWindowCompositionAttribute>(
|
|
||||||
::GetProcAddress(user32, "SetWindowCompositionAttribute"));
|
|
||||||
if (g_set_window_composition_attribute) {
|
|
||||||
std::cout << "set" << std::endl;
|
|
||||||
g_set_window_composition_attribute_initialized = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ACCENT_POLICY accent = {static_cast<ACCENT_STATE>(accent_state), 2,
|
|
||||||
static_cast<DWORD>(gradient_color), 0};
|
|
||||||
WINDOWCOMPOSITIONATTRIBDATA data;
|
|
||||||
data.Attrib = WCA_ACCENT_POLICY;
|
|
||||||
data.pvData = &accent;
|
|
||||||
data.cbData = sizeof(accent);
|
|
||||||
g_set_window_composition_attribute(window, &data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace flutternativeview
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
// This file is a part of flutter_native_view
|
|
||||||
// (https://github.com/alexmercerind/flutter_native_view).
|
|
||||||
//
|
|
||||||
// Copyright (c) 2022, Hitesh Kumar Saini <saini123hitesh@gmail.com>.
|
|
||||||
// All rights reserved.
|
|
||||||
// Use of this source code is governed by MIT license that can be found in the
|
|
||||||
// LICENSE file.
|
|
||||||
|
|
||||||
#include <dwmapi.h>
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace flutternativeview {
|
|
||||||
|
|
||||||
RTL_OSVERSIONINFOW GetWindowsVersion();
|
|
||||||
|
|
||||||
void SetWindowComposition(HWND window, int32_t accent_state,
|
|
||||||
int32_t gradient_color);
|
|
||||||
|
|
||||||
} // namespace flutternativeview
|
|
||||||
@@ -9,7 +9,8 @@
|
|||||||
namespace polyvox_filament {
|
namespace polyvox_filament {
|
||||||
|
|
||||||
WGLContext::WGLContext(flutter::PluginRegistrarWindows *pluginRegistrar,
|
WGLContext::WGLContext(flutter::PluginRegistrarWindows *pluginRegistrar,
|
||||||
flutter::TextureRegistrar *textureRegistrar) {
|
flutter::TextureRegistrar *textureRegistrar)
|
||||||
|
: _pluginRegistrar(pluginRegistrar), _textureRegistrar(textureRegistrar) {
|
||||||
|
|
||||||
auto hwnd = pluginRegistrar->GetView()->GetNativeWindow();
|
auto hwnd = pluginRegistrar->GetView()->GetNativeWindow();
|
||||||
|
|
||||||
@@ -99,27 +100,24 @@ void WGLContext::CreateTexture(
|
|||||||
uint32_t width, uint32_t height,
|
uint32_t width, uint32_t height,
|
||||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
|
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
|
||||||
|
|
||||||
#ifdef WGL_USE_BACKING_WINDOW
|
#if WGL_USE_BACKING_WINDOW
|
||||||
_backingWindow = std::make_unique<BackingWindow>()
|
_backingWindow = std::make_unique<BackingWindow>(
|
||||||
: std::vector<flutter::EncodableValue> resultList;
|
_pluginRegistrar, static_cast<int>(width), static_cast<int>(height));
|
||||||
|
std::vector<flutter::EncodableValue> resultList;
|
||||||
resultList.push_back(flutter::EncodableValue((int64_t) nullptr));
|
resultList.push_back(flutter::EncodableValue((int64_t) nullptr));
|
||||||
resultList.push_back(
|
resultList.push_back(
|
||||||
flutter::EncodableValue((int64_t)_backingWindow->GetHandle()));
|
flutter::EncodableValue((int64_t)_backingWindow->GetHandle()));
|
||||||
resultList.push_back(flutter::EncodableValue((int64_t) nullptr));
|
resultList.push_back(flutter::EncodableValue((int64_t) nullptr));
|
||||||
result->Success(resultList);
|
result->Success(resultList);
|
||||||
}
|
|
||||||
else {
|
|
||||||
result->Error("FOO", "ERROR", nullptr);
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
if (_active.get()) {
|
if (_active.get()) {
|
||||||
result->Error("ERROR",
|
result->Error("ERROR",
|
||||||
"Texture already exists. You must call destroyTexture before "
|
"Texture already exists. You must call destroyTexture before "
|
||||||
"attempting to create a new one.");
|
"attempting to create a new one.");
|
||||||
} else {
|
} else {
|
||||||
_active = std::make_unique<OpenGLTextureBuffer>(_pluginRegistrar, _textureRegistrar,
|
_active = std::make_unique<OpenGLTextureBuffer>(
|
||||||
std::move(result), width, height,
|
_pluginRegistrar, _textureRegistrar, std::move(result), width, height,
|
||||||
_context);
|
_context);
|
||||||
|
|
||||||
if (_active->flutterTextureId != -1) {
|
if (_active->flutterTextureId != -1) {
|
||||||
std::vector<flutter::EncodableValue> resultList;
|
std::vector<flutter::EncodableValue> resultList;
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ namespace polyvox_filament {
|
|||||||
void CreateTexture(uint32_t width, uint32_t height, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
|
void CreateTexture(uint32_t width, uint32_t height, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
|
||||||
void* GetSharedContext();
|
void* GetSharedContext();
|
||||||
private:
|
private:
|
||||||
|
flutter::PluginRegistrarWindows* _pluginRegistrar = nullptr;
|
||||||
|
flutter::TextureRegistrar* _textureRegistrar = nullptr;
|
||||||
HGLRC _context = NULL;
|
HGLRC _context = NULL;
|
||||||
#if WGL_USE_BACKING_WINDOW
|
#if WGL_USE_BACKING_WINDOW
|
||||||
std::unique_ptr<BackingWindow> _backingWindow = nullptr;
|
std::unique_ptr<BackingWindow> _backingWindow = nullptr;
|
||||||
|
|||||||
Reference in New Issue
Block a user