Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ migrate_working_dir/
*.ipr
*.iws
.idea/

.vscode

3 changes: 3 additions & 0 deletions packages/window_proc_delegate/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 0.0.3
* Fix crash on multi engine

## 0.0.2
* Removed engine-specific message restriction - messages are now delivered to all registered delegates
* Fixed crash issue when unregistering delegates
Expand Down
12 changes: 12 additions & 0 deletions packages/window_proc_delegate/example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';

import 'package:window_proc_delegate/window_proc_delegate.dart';
import 'package:desktop_multi_window/desktop_multi_window.dart';

void main() {
runApp(const MyApp());
Expand Down Expand Up @@ -84,6 +85,12 @@ class _MyAppState extends State<MyApp> {
}
}

void _createChildWindow() async {
await WindowController.create(
WindowConfiguration(hiddenAtLaunch: false, arguments: ''),
);
}

@override
Widget build(BuildContext context) {
return MaterialApp(
Expand All @@ -106,6 +113,11 @@ class _MyAppState extends State<MyApp> {
onPressed: _delegateId != null ? _unregisterDelegate : null,
child: const Text('Unregister Delegate'),
),
const SizedBox(width: 8),
ElevatedButton(
onPressed: _createChildWindow,
child: const Text('Create Child Window'),
),
],
),
const SizedBox(height: 8),
Expand Down
10 changes: 9 additions & 1 deletion packages/window_proc_delegate/example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.8"
desktop_multi_window:
dependency: "direct main"
description:
name: desktop_multi_window
sha256: "60ba38725b8887b60e44d15afdcf0c3813568b5da2ccaf1e7f6fd09a380a6e24"
url: "https://pub.dev"
source: hosted
version: "0.3.0"
fake_async:
dependency: transitive
description:
Expand Down Expand Up @@ -269,7 +277,7 @@ packages:
path: ".."
relative: true
source: path
version: "0.0.1"
version: "0.0.3"
sdks:
dart: ">=3.10.0 <4.0.0"
flutter: ">=3.18.0-18.0.pre.54"
55 changes: 1 addition & 54 deletions packages/window_proc_delegate/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,68 +18,15 @@ dependencies:
sdk: flutter

window_proc_delegate:
# When depending on this package from a real application you should use:
# window_proc_delegate: ^x.y.z
# See https://dart.dev/tools/pub/dependencies#version-constraints
# The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version.
path: ../

# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
desktop_multi_window: ^0.3.0

dev_dependencies:
integration_test:
sdk: flutter
flutter_test:
sdk: flutter

# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^6.0.0

# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec

# The following section is specific to Flutter packages.
flutter:

# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true

# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg

# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/to/resolution-aware-images

# For details regarding adding assets from package dependencies, see
# https://flutter.dev/to/asset-from-package

# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/to/font-from-package
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@

#include "generated_plugin_registrant.h"

#include <desktop_multi_window/desktop_multi_window_plugin.h>
#include <window_proc_delegate/window_proc_delegate_plugin_c_api.h>

void RegisterPlugins(flutter::PluginRegistry* registry) {
DesktopMultiWindowPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("DesktopMultiWindowPlugin"));
WindowProcDelegatePluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("WindowProcDelegatePluginCApi"));
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#

list(APPEND FLUTTER_PLUGIN_LIST
desktop_multi_window
window_proc_delegate
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <optional>

#include "desktop_multi_window/desktop_multi_window_plugin.h"
#include "flutter/generated_plugin_registrant.h"

FlutterWindow::FlutterWindow(const flutter::DartProject& project)
Expand All @@ -25,11 +26,15 @@ bool FlutterWindow::OnCreate() {
return false;
}
RegisterPlugins(flutter_controller_->engine());
DesktopMultiWindowSetWindowCreatedCallback([](void* controller) {
auto* flutter_view_controller =
reinterpret_cast<flutter::FlutterViewController*>(controller);
auto* registry = flutter_view_controller->engine();
RegisterPlugins(registry);
});
SetChildContent(flutter_controller_->view()->GetNativeWindow());

flutter_controller_->engine()->SetNextFrameCallback([&]() {
this->Show();
});
flutter_controller_->engine()->SetNextFrameCallback([&]() { this->Show(); });

// Flutter can complete the first frame before the "show window" callback is
// registered. The following call ensures a frame is pending to ensure the
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:ffi' as ffi;
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:flutter/foundation.dart';
import 'windows_message.dart';
import '../window_proc_delegate.dart';
Expand Down Expand Up @@ -33,6 +34,8 @@ external void setCallback(

bool _initialized = false;
bool _dartApiInitialized = false;
bool _engineIdInitialized = false;
final MethodChannel _channel = MethodChannel('window_proc_delegate');

void ensureNativeLibraryInitialized() {
if (_dartApiInitialized) return;
Expand All @@ -51,6 +54,29 @@ void ensureNativeLibraryInitialized() {
}
}

/// Ensures the plugin's engine ID is initialized.
///
/// This method registers the current engine ID with the native plugin.
/// It can be called early in application startup to ensure the plugin
/// is ready before any delegates are registered.
///
/// If not called explicitly, the engine ID will be set automatically
/// when the first delegate is registered.
Future<void> ensureInitializeEngineId() async {
if (!Platform.isWindows) return;

if (_engineIdInitialized) return;

final int engineId = PlatformDispatcher.instance.engineId!;
try {
await _channel.invokeMethod('setEngineId', engineId);
_engineIdInitialized = true;
} catch (e) {
debugPrint('Failed to set engine ID: $e');
rethrow;
}
}

void initialize(
List<WindowProcDelegateCallback?> delegates,
void Function(ffi.Pointer<WindowsMessage>) handleWindowProc,
Expand All @@ -69,8 +95,11 @@ void initialize(

// Get the engine ID and register the native callback
try {
final engineId = PlatformDispatcher.instance.engineId!;
final int engineId = PlatformDispatcher.instance.engineId!;
setCallback(engineId, nativeCallable.nativeFunction);

// Set engine ID asynchronously (fire-and-forget with error handling)
ensureInitializeEngineId();
} catch (e) {
debugPrint('Failed to set callback: $e');
}
Expand Down
2 changes: 2 additions & 0 deletions packages/window_proc_delegate/lib/window_proc_delegate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import 'dart:ffi' as ffi;
import 'src/windows_message.dart';
import 'src/window_proc_delegate_internal.dart' as internal;

export 'src/window_proc_delegate_internal.dart' show ensureInitializeEngineId;

/// Signature for a WindowProc delegate callback.
///
/// The callback receives the window message parameters:
Expand Down
2 changes: 1 addition & 1 deletion packages/window_proc_delegate/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: window_proc_delegate
description: A Flutter plugin that allows you to hook into Windows WindowProc messages from Dart code.
version: 0.0.2
version: 0.0.3
homepage: https://github.com/boyan01/packages

environment:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,22 @@
#define FLUTTER_PLUGIN_WINDOW_PROC_DELEGATE_PLUGIN_C_API_H_

#include <flutter_plugin_registrar.h>
#include <stdint.h>
#include <windows.h>

#ifdef FLUTTER_PLUGIN_IMPL
#define FLUTTER_PLUGIN_EXPORT __declspec(dllexport)
#else
#define FLUTTER_PLUGIN_EXPORT __declspec(dllimport)
#endif

// Forward declaration
namespace window_proc_delegate {
struct WindowsMessage;
}

#if defined(__cplusplus)
extern "C" {
#endif

// Callback signature for Dart WindowProc delegate
typedef void (*DartWindowProcCallbackC)(
window_proc_delegate::WindowsMessage* message);

FLUTTER_PLUGIN_EXPORT void WindowProcDelegatePluginCApiRegisterWithRegistrar(
FlutterDesktopPluginRegistrarRef registrar);

FLUTTER_PLUGIN_EXPORT void WindowProcDelegateSetCallback(
int64_t engineId, DartWindowProcCallbackC callback);

FLUTTER_PLUGIN_EXPORT intptr_t WindowProcDelegateInitDartApi(void* data);

#if defined(__cplusplus)
} // extern "C"
#endif

// C++ only functions (not in extern "C")
#if defined(__cplusplus)
#include <functional>

namespace window_proc_delegate {
typedef std::function<void(WindowsMessage*)> DartWindowProcCallback;
}

// Get the callback for a specific engine ID
window_proc_delegate::DartWindowProcCallback GetCallbackForEngine(
int64_t engineId);

// Get all registered callbacks
std::vector<window_proc_delegate::DartWindowProcCallback> GetAllCallbacks();

#endif

#endif // FLUTTER_PLUGIN_WINDOW_PROC_DELEGATE_PLUGIN_C_API_H_
Loading