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:typed_data';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:permission_handler/permission_handler.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_widget.dart';
|
||||
|
||||
void main() {
|
||||
void main() async {
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
@@ -30,8 +31,10 @@ class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
// showPerformanceOverlay: true,
|
||||
color: Colors.white,
|
||||
home: Scaffold(backgroundColor: Colors.white, body: ExampleWidget()));
|
||||
home: Scaffold(
|
||||
body:
|
||||
ExampleWidget()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,9 @@ public:
|
||||
|
||||
void doRender() {
|
||||
render(_viewer, 0, nullptr, nullptr, nullptr);
|
||||
_renderCallback(_renderCallbackOwner);
|
||||
if(_renderCallback) {
|
||||
_renderCallback(_renderCallbackOwner);
|
||||
}
|
||||
}
|
||||
|
||||
void setFrameIntervalInMilliseconds(float frameIntervalInMilliseconds) {
|
||||
|
||||
@@ -19,6 +19,14 @@ class TextureDetails {
|
||||
}
|
||||
|
||||
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.
|
||||
/// 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 'package:flutter/services.dart';
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'package:polyvox_filament/filament_controller.dart';
|
||||
|
||||
import 'package:polyvox_filament/animations/animation_data.dart';
|
||||
import 'package:polyvox_filament/generated_bindings.dart';
|
||||
|
||||
// ignore: constant_identifier_names
|
||||
const FilamentEntity _FILAMENT_ASSET_ERROR = 0;
|
||||
|
||||
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;
|
||||
|
||||
@@ -25,9 +30,11 @@ class FilamentControllerFFI extends FilamentController {
|
||||
|
||||
final String? uberArchivePath;
|
||||
|
||||
@override
|
||||
Stream<bool> get hasViewer => _hasViewerController.stream;
|
||||
final _hasViewerController = StreamController<bool>();
|
||||
|
||||
@override
|
||||
Stream<FilamentEntity> get pickResult => _pickResultController.stream;
|
||||
final _pickResultController = StreamController<FilamentEntity>.broadcast();
|
||||
|
||||
@@ -48,7 +55,7 @@ class FilamentControllerFFI extends FilamentController {
|
||||
_resizeTimer?.cancel();
|
||||
_resizingWidth = call.arguments[0];
|
||||
_resizingHeight = call.arguments[1];
|
||||
_resizeTimer = Timer(Duration(milliseconds: 500), () async {
|
||||
_resizeTimer = Timer(const Duration(milliseconds: 500), () async {
|
||||
await resize(_resizingWidth!, _resizingHeight!);
|
||||
});
|
||||
|
||||
@@ -160,7 +167,7 @@ class FilamentControllerFFI extends FilamentController {
|
||||
|
||||
print("Using flutterTextureId $flutterTextureId, surface $surfaceAddress and nativeTexture $nativeTexture");
|
||||
|
||||
if (Platform.isWindows) {
|
||||
if (Platform.isWindows && requiresTextureWidget) {
|
||||
_driver = Pointer<Void>.fromAddress(
|
||||
await _channel.invokeMethod("getDriverPlatform"));
|
||||
}
|
||||
@@ -275,6 +282,10 @@ class FilamentControllerFFI extends FilamentController {
|
||||
|
||||
@override
|
||||
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
|
||||
// so this exception should never be thrown (right?)
|
||||
if (textureDetails.value == null) {
|
||||
|
||||
@@ -42,7 +42,7 @@ class _RenderResizeObserver extends RenderProxyBox {
|
||||
void performLayout() async {
|
||||
super.performLayout();
|
||||
if (size.width != _oldSize.width || size.height != _oldSize.height) {
|
||||
onLayoutChangedCallback(size);
|
||||
onLayoutChangedCallback(size);
|
||||
_oldSize = Size(size.width, size.height);
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ class _FilamentWidgetState extends State<FilamentWidget> {
|
||||
|
||||
return ResizeObserver(
|
||||
onResized: (newSize) {
|
||||
if(!Platform.isWindows) {
|
||||
if (!Platform.isWindows) {
|
||||
return;
|
||||
}
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
@@ -124,10 +124,10 @@ class _SizedFilamentWidget extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _SizedFilamentWidgetState extends State<_SizedFilamentWidget> {
|
||||
|
||||
String? _error;
|
||||
|
||||
late final AppLifecycleListener _appLifecycleListener;
|
||||
AppLifecycleState? _lastState;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -136,9 +136,6 @@ class _SizedFilamentWidgetState extends State<_SizedFilamentWidget> {
|
||||
);
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||
if (!kReleaseMode) {
|
||||
await Future.delayed(Duration(seconds: 2));
|
||||
}
|
||||
try {
|
||||
await widget.controller.createViewer(widget.width, widget.height);
|
||||
} catch (err) {
|
||||
@@ -171,7 +168,7 @@ class _SizedFilamentWidgetState extends State<_SizedFilamentWidget> {
|
||||
var width = size.width.ceil();
|
||||
var height = size.height.ceil();
|
||||
while (_resizing) {
|
||||
await Future.delayed(Duration(milliseconds: 20));
|
||||
await Future.delayed(const Duration(milliseconds: 20));
|
||||
}
|
||||
_resizing = true;
|
||||
await widget.controller.resize(width, height);
|
||||
@@ -237,7 +234,6 @@ class _SizedFilamentWidgetState extends State<_SizedFilamentWidget> {
|
||||
await widget.controller.setRendering(_wasRenderingOnInactive);
|
||||
break;
|
||||
}
|
||||
_lastState = state;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -252,31 +248,55 @@ class _SizedFilamentWidgetState extends State<_SizedFilamentWidget> {
|
||||
]));
|
||||
}
|
||||
|
||||
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,
|
||||
);
|
||||
|
||||
if (!widget.controller.requiresTextureWidget) {
|
||||
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)
|
||||
Positioned.fill(child: CustomPaint(painter: TransparencyPainter()))
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
if(!USE_ANGLE)
|
||||
set(WGL_USE_BACKING_WINDOW TRUE)
|
||||
endif()
|
||||
|
||||
if(USE_ANGLE)
|
||||
add_compile_definitions(USE_ANGLE)
|
||||
list(APPEND PLUGIN_SOURCES "flutter_angle_texture.cpp" "egl_context.cpp" )
|
||||
else()
|
||||
list(APPEND PLUGIN_SOURCES "wgl_context.cpp")
|
||||
if(WGL_USE_BACKING_WINDOW)
|
||||
list(APPEND PLUGIN_SOURCES "utils.cc" "backing_window.cpp")
|
||||
else()
|
||||
list(APPEND PLUGIN_SOURCES "opengl_texture_buffer.cpp")
|
||||
endif()
|
||||
add_compile_definitions(WGL_USE_BACKING_WINDOW)
|
||||
list(APPEND PLUGIN_SOURCES "wgl_context.cpp" "opengl_texture_buffer.cpp" "backing_window.cpp")
|
||||
# if(WGL_USE_BACKING_WINDOW)
|
||||
# list(APPEND PLUGIN_SOURCES )
|
||||
# else()
|
||||
# list(APPEND PLUGIN_SOURCES )
|
||||
# endif()
|
||||
endif()
|
||||
|
||||
# Define the plugin library target. Its name must not be changed (see comment
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
#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 {
|
||||
|
||||
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;
|
||||
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,
|
||||
LPARAM lparam, UINT_PTR subclass_id,
|
||||
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
|
||||
// moved out of screen etc.
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
case WM_SIZE: {
|
||||
// Prevent unnecessary maxmize, minimize or restore messages for |window|.
|
||||
// Since it is |SetParent|'ed into native view container.
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
@@ -32,6 +156,8 @@ LRESULT NativeViewSubclassProc(HWND window, UINT message, WPARAM wparam,
|
||||
LRESULT CALLBACK FilamentWindowProc(HWND const window, UINT const message,
|
||||
WPARAM const wparam,
|
||||
LPARAM const lparam) noexcept {
|
||||
// std::cout << "FILAMENT WINDOW EVENT " << message << std::endl;
|
||||
|
||||
switch (message) {
|
||||
case WM_MOUSEMOVE: {
|
||||
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;
|
||||
// Prevent erasing of |window| when it is unfocused and minimized or
|
||||
// moved out of screen etc.
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
case WM_SIZE:
|
||||
case WM_MOVE:
|
||||
case WM_MOVING:
|
||||
case WM_ACTIVATE:
|
||||
case WM_WINDOWPOSCHANGED: {
|
||||
std::cout << "FILAMENT POS CHANGED" << std::endl;
|
||||
// std::cout << "FILAMENT POS CHANGED" << std::endl;
|
||||
// NativeViewCore::GetInstance()->SetHitTestBehavior(0);
|
||||
auto user_data = ::GetWindowLongPtr(window, GWLP_USERDATA);
|
||||
if (user_data) {
|
||||
@@ -83,168 +209,178 @@ LRESULT CALLBACK FilamentWindowProc(HWND const window, UINT const message,
|
||||
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(
|
||||
flutter::PluginRegistrarWindows *pluginRegistrar,
|
||||
int initialWidth,
|
||||
int initialHeight) {
|
||||
// get the root Flutter window
|
||||
HWND flutterWindow = pluginRegistrar->GetView()->GetNativeWindow();
|
||||
_flutterRootWindow = ::GetAncestor(flutterWindow, GA_ROOT);
|
||||
std::cout << "child rect " << flutterChildRect.left << " " << flutterChildRect.top << " " << flutterChildRect.right << " " << flutterChildRect.bottom << std::endl;
|
||||
|
||||
// set composition to allow transparency
|
||||
flutternativeview::SetWindowComposition(_flutterRootWindow, 6, 0);
|
||||
// set composition to allow transparency
|
||||
SetWindowComposition(_flutterRootWindow, 6, 0);
|
||||
|
||||
// register a top-level WindowProcDelegate to handle window events
|
||||
pluginRegistrar->RegisterTopLevelWindowProcDelegate([=](HWND hwnd,
|
||||
UINT message,
|
||||
WPARAM wparam,
|
||||
LPARAM lparam) {
|
||||
switch (message) {
|
||||
case WM_ACTIVATE: {
|
||||
std::cout << "WM_ACTIVATE" << std::endl;
|
||||
RECT window_rect;
|
||||
::GetWindowRect(_flutterRootWindow, &window_rect);
|
||||
// Position |native_view| such that it's z order is behind |window_| &
|
||||
// redraw aswell.
|
||||
::SetWindowPos(_windowHandle, _flutterRootWindow, window_rect.left,
|
||||
window_rect.top, window_rect.right - window_rect.left,
|
||||
window_rect.bottom - window_rect.top, SWP_NOACTIVATE);
|
||||
break;
|
||||
}
|
||||
case WM_SIZE: {
|
||||
std::cout << "WM_SIZE" << std::endl;
|
||||
|
||||
// Handle Windows's minimize & maximize animations properly.
|
||||
// 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);
|
||||
}
|
||||
// register a top-level WindowProcDelegate to handle window events
|
||||
pluginRegistrar->RegisterTopLevelWindowProcDelegate([=](HWND hwnd,
|
||||
UINT message,
|
||||
WPARAM wparam,
|
||||
LPARAM lparam) {
|
||||
// std::cout << "TOP LEVEL EVENT " << message << std::endl;
|
||||
switch (message) {
|
||||
case WM_MOUSEMOVE: {
|
||||
// std::cout << "FLUTTER MOUSE MOVE" << std::endl;
|
||||
break;
|
||||
}
|
||||
case WM_ACTIVATE: {
|
||||
std::cout << "WM_ACTIVATE" << std::endl;
|
||||
RECT rootWindowRect;
|
||||
::GetWindowRect(_flutterViewWindow, &rootWindowRect);
|
||||
// Position |native_view| such that it's z order is behind |window_| &
|
||||
// redraw aswell.
|
||||
::SetWindowPos(_windowHandle, _flutterRootWindow, rootWindowRect.left,
|
||||
rootWindowRect.top, rootWindowRect.right - rootWindowRect.left,
|
||||
rootWindowRect.bottom - rootWindowRect.top, SWP_NOACTIVATE);
|
||||
break;
|
||||
}
|
||||
case WM_SIZE: {
|
||||
std::cout << "WM_SIZE" << std::endl;
|
||||
|
||||
BackingWindow::GetHandle() {
|
||||
return _windowHandle;
|
||||
// Handle Windows's minimize & maximize animations properly.
|
||||
// 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:
|
||||
HWND _windowHandle;
|
||||
HWND _flutterRootWindow;
|
||||
}
|
||||
HWND _flutterViewWindow;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -36,8 +36,6 @@
|
||||
#include <dwmapi.h>
|
||||
#include <wrl.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include "flutter_render_context.h"
|
||||
|
||||
#if USE_ANGLE
|
||||
@@ -181,7 +179,7 @@ void PolyvoxFilamentPlugin::CreateTexture(
|
||||
_context = std::make_unique<WGLContext>(_pluginRegistrar, _textureRegistrar);
|
||||
#endif
|
||||
}
|
||||
//_context->CreateTexture(width, height, std::move(result));
|
||||
_context->CreateTexture(width, height, std::move(result));
|
||||
}
|
||||
|
||||
void PolyvoxFilamentPlugin::DestroyTexture(
|
||||
@@ -228,14 +226,15 @@ void PolyvoxFilamentPlugin::HandleMethodCall(
|
||||
} else if (methodCall.method_name() == "destroyTexture") {
|
||||
DestroyTexture(methodCall, std::move(result));
|
||||
} else if (methodCall.method_name() == "getRenderCallback") {
|
||||
flutter::EncodableList resultList;
|
||||
#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
|
||||
flutter::EncodableList resultList;
|
||||
resultList.push_back(flutter::EncodableValue((int64_t)&render_callback));
|
||||
resultList.push_back(flutter::EncodableValue((int64_t)this));
|
||||
result->Success(resultList);
|
||||
#endif
|
||||
result->Success(resultList);
|
||||
} else if (methodCall.method_name() == "getDriverPlatform") {
|
||||
#ifdef USE_ANGLE
|
||||
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 {
|
||||
|
||||
WGLContext::WGLContext(flutter::PluginRegistrarWindows *pluginRegistrar,
|
||||
flutter::TextureRegistrar *textureRegistrar) {
|
||||
flutter::TextureRegistrar *textureRegistrar)
|
||||
: _pluginRegistrar(pluginRegistrar), _textureRegistrar(textureRegistrar) {
|
||||
|
||||
auto hwnd = pluginRegistrar->GetView()->GetNativeWindow();
|
||||
|
||||
@@ -99,27 +100,24 @@ void WGLContext::CreateTexture(
|
||||
uint32_t width, uint32_t height,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
|
||||
|
||||
#ifdef WGL_USE_BACKING_WINDOW
|
||||
_backingWindow = std::make_unique<BackingWindow>()
|
||||
: std::vector<flutter::EncodableValue> resultList;
|
||||
#if WGL_USE_BACKING_WINDOW
|
||||
_backingWindow = std::make_unique<BackingWindow>(
|
||||
_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)_backingWindow->GetHandle()));
|
||||
resultList.push_back(flutter::EncodableValue((int64_t) nullptr));
|
||||
result->Success(resultList);
|
||||
}
|
||||
else {
|
||||
result->Error("FOO", "ERROR", nullptr);
|
||||
}
|
||||
#else
|
||||
if (_active.get()) {
|
||||
result->Error("ERROR",
|
||||
"Texture already exists. You must call destroyTexture before "
|
||||
"attempting to create a new one.");
|
||||
} else {
|
||||
_active = std::make_unique<OpenGLTextureBuffer>(_pluginRegistrar, _textureRegistrar,
|
||||
std::move(result), width, height,
|
||||
_context);
|
||||
_active = std::make_unique<OpenGLTextureBuffer>(
|
||||
_pluginRegistrar, _textureRegistrar, std::move(result), width, height,
|
||||
_context);
|
||||
|
||||
if (_active->flutterTextureId != -1) {
|
||||
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* GetSharedContext();
|
||||
private:
|
||||
flutter::PluginRegistrarWindows* _pluginRegistrar = nullptr;
|
||||
flutter::TextureRegistrar* _textureRegistrar = nullptr;
|
||||
HGLRC _context = NULL;
|
||||
#if WGL_USE_BACKING_WINDOW
|
||||
std::unique_ptr<BackingWindow> _backingWindow = nullptr;
|
||||
|
||||
Reference in New Issue
Block a user