Add sqlite store

Optimize android quick action

Optimize backup and restore

Optimize more details
This commit is contained in:
chen08209
2025-12-16 11:23:09 +08:00
parent 243b3037d9
commit 2fbb96f5c1
214 changed files with 15659 additions and 10751 deletions

7
windows/.gitignore vendored
View File

@@ -15,10 +15,3 @@ x86/
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
build/
out/
.idea/
.vs/
.vscode/

View File

@@ -8,7 +8,7 @@ set(BINARY_NAME "FlClash")
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake.
cmake_policy(SET CMP0063 NEW)
cmake_policy(VERSION 3.14...3.25)
# Define build configuration option.
get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
@@ -81,15 +81,9 @@ install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
# libclash.so
# FlClash
set(CLASH_DIR "../libclash/windows")
# if(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
# elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM" OR CMAKE_SYSTEM_PROCESSOR MATCHES "armv[0-9]+")
# elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "x86")
# set(CLASH_DIR "../libclash/windows/x86")
# endif()
install(PROGRAMS "${CLASH_DIR}/FlClashCore.exe" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
@@ -105,6 +99,12 @@ if(PLUGIN_BUNDLED_LIBRARIES)
COMPONENT Runtime)
endif()
# Copy the native assets provided by the build.dart from all packages.
set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/")
install(DIRECTORY "${NATIVE_ASSETS_DIR}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
# Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")

3
windows/flutter/generated_plugin_registrant.cc Executable file → Normal file
View File

@@ -14,6 +14,7 @@
#include <hotkey_manager_windows/hotkey_manager_windows_plugin_c_api.h>
#include <proxy/proxy_plugin_c_api.h>
#include <screen_retriever_windows/screen_retriever_windows_plugin_c_api.h>
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
#include <tray_manager/tray_manager_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h>
#include <window_ext/window_ext_plugin_c_api.h>
@@ -36,6 +37,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("ProxyPluginCApi"));
ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("ScreenRetrieverWindowsPluginCApi"));
Sqlite3FlutterLibsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin"));
TrayManagerPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("TrayManagerPlugin"));
UrlLauncherWindowsRegisterWithRegistrar(

0
windows/flutter/generated_plugin_registrant.h Executable file → Normal file
View File

1
windows/flutter/generated_plugins.cmake Executable file → Normal file
View File

@@ -11,6 +11,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
hotkey_manager_windows
proxy
screen_retriever_windows
sqlite3_flutter_libs
tray_manager
url_launcher_windows
window_ext

View File

@@ -6,8 +6,6 @@ project(runner LANGUAGES CXX)
# work.
#
# Any new source files that you add to the application should be added here.
add_executable(${BINARY_NAME} WIN32
"flutter_window.cpp"
"main.cpp"
@@ -21,6 +19,7 @@ add_executable(${BINARY_NAME} WIN32
# Apply the standard set of build settings. This can be removed for applications
# that need different build settings.
apply_standard_settings(${BINARY_NAME})
# Add preprocessor definitions for the build version.
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"")
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}")

View File

@@ -93,7 +93,7 @@ BEGIN
VALUE "FileDescription", "FlClash" "\0"
VALUE "FileVersion", VERSION_AS_STRING "\0"
VALUE "InternalName", "clash" "\0"
VALUE "LegalCopyright", "Copyright (C) 2023 com.follow. All rights reserved." "\0"
VALUE "LegalCopyright", "Copyright (C) 2025 com.follow. All rights reserved." "\0"
VALUE "OriginalFilename", "FlClash.exe" "\0"
VALUE "ProductName", "clash" "\0"
VALUE "ProductVersion", VERSION_AS_STRING "\0"

View File

@@ -9,12 +9,6 @@
<application>
<!-- Windows 10 and Windows 11 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
</application>
</compatibility>
</assembly>

View File

@@ -45,13 +45,13 @@ std::string Utf8FromUtf16(const wchar_t* utf16_string) {
if (utf16_string == nullptr) {
return std::string();
}
int target_length = ::WideCharToMultiByte(
unsigned int target_length = ::WideCharToMultiByte(
CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
-1, nullptr, 0, nullptr, nullptr)
-1; // remove the trailing null character
int input_length = (int)wcslen(utf16_string);
std::string utf8_string;
if (target_length <= 0 || target_length > utf8_string.max_size()) {
if (target_length == 0 || target_length > utf8_string.max_size()) {
return utf8_string;
}
utf8_string.resize(target_length);

View File

@@ -1,13 +1,11 @@
#include "win32_window.h"
#include "app_links/app_links_plugin_c_api.h"
#include <dwmapi.h>
#include <flutter_windows.h>
#include "resource.h"
namespace
{
namespace {
/// Window attribute that enables dark mode window decorations.
///
@@ -18,60 +16,53 @@ namespace
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
#endif
constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW";
constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW";
/// Registry key for app theme preference.
///
/// A value of 0 indicates apps should use dark mode. A non-zero or missing
/// value indicates apps should use light mode.
constexpr const wchar_t kGetPreferredBrightnessRegKey[] =
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme";
/// Registry key for app theme preference.
///
/// A value of 0 indicates apps should use dark mode. A non-zero or missing
/// value indicates apps should use light mode.
constexpr const wchar_t kGetPreferredBrightnessRegKey[] =
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme";
// The number of Win32Window objects that currently exist.
static int g_active_window_count = 0;
// The number of Win32Window objects that currently exist.
static int g_active_window_count = 0;
using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd);
using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd);
// Scale helper to convert logical scaler values to physical using passed in
// scale factor
int Scale(int source, double scale_factor)
{
return static_cast<int>(source * scale_factor);
// Scale helper to convert logical scaler values to physical using passed in
// scale factor
int Scale(int source, double scale_factor) {
return static_cast<int>(source * scale_factor);
}
// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module.
// This API is only needed for PerMonitor V1 awareness mode.
void EnableFullDpiSupportIfAvailable(HWND hwnd) {
HMODULE user32_module = LoadLibraryA("User32.dll");
if (!user32_module) {
return;
}
// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module.
// This API is only needed for PerMonitor V1 awareness mode.
void EnableFullDpiSupportIfAvailable(HWND hwnd)
{
HMODULE user32_module = LoadLibraryA("User32.dll");
if (!user32_module)
{
return;
}
auto enable_non_client_dpi_scaling =
reinterpret_cast<EnableNonClientDpiScaling *>(
GetProcAddress(user32_module, "EnableNonClientDpiScaling"));
if (enable_non_client_dpi_scaling != nullptr)
{
enable_non_client_dpi_scaling(hwnd);
}
FreeLibrary(user32_module);
auto enable_non_client_dpi_scaling =
reinterpret_cast<EnableNonClientDpiScaling*>(
GetProcAddress(user32_module, "EnableNonClientDpiScaling"));
if (enable_non_client_dpi_scaling != nullptr) {
enable_non_client_dpi_scaling(hwnd);
}
FreeLibrary(user32_module);
}
} // namespace
} // namespace
// Manages the Win32Window's window class registration.
class WindowClassRegistrar
{
public:
class WindowClassRegistrar {
public:
~WindowClassRegistrar() = default;
// Returns the singleton registrar instance.
static WindowClassRegistrar *GetInstance()
{
if (!instance_)
{
static WindowClassRegistrar* GetInstance() {
if (!instance_) {
instance_ = new WindowClassRegistrar();
}
return instance_;
@@ -79,26 +70,24 @@ public:
// Returns the name of the window class, registering the class if it hasn't
// previously been registered.
const wchar_t *GetWindowClass();
const wchar_t* GetWindowClass();
// Unregisters the window class. Should only be called if there are no
// instances of the window.
void UnregisterWindowClass();
private:
private:
WindowClassRegistrar() = default;
static WindowClassRegistrar *instance_;
static WindowClassRegistrar* instance_;
bool class_registered_ = false;
};
WindowClassRegistrar *WindowClassRegistrar::instance_ = nullptr;
WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr;
const wchar_t *WindowClassRegistrar::GetWindowClass()
{
if (!class_registered_)
{
const wchar_t* WindowClassRegistrar::GetWindowClass() {
if (!class_registered_) {
WNDCLASS window_class{};
window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
window_class.lpszClassName = kWindowClassName;
@@ -117,35 +106,26 @@ const wchar_t *WindowClassRegistrar::GetWindowClass()
return kWindowClassName;
}
void WindowClassRegistrar::UnregisterWindowClass()
{
void WindowClassRegistrar::UnregisterWindowClass() {
UnregisterClass(kWindowClassName, nullptr);
class_registered_ = false;
}
Win32Window::Win32Window()
{
Win32Window::Win32Window() {
++g_active_window_count;
}
Win32Window::~Win32Window()
{
Win32Window::~Win32Window() {
--g_active_window_count;
Destroy();
}
bool Win32Window::Create(const std::wstring &title,
const Point &origin,
const Size &size)
{
if (SendAppLinkToInstance(title))
{
return false;
}
bool Win32Window::Create(const std::wstring& title,
const Point& origin,
const Size& size) {
Destroy();
const wchar_t *window_class =
const wchar_t* window_class =
WindowClassRegistrar::GetInstance()->GetWindowClass();
const POINT target_point = {static_cast<LONG>(origin.x),
@@ -160,8 +140,7 @@ bool Win32Window::Create(const std::wstring &title,
Scale(size.width, scale_factor), Scale(size.height, scale_factor),
nullptr, nullptr, GetModuleHandle(nullptr), this);
if (!window)
{
if (!window) {
return false;
}
@@ -170,66 +149,24 @@ bool Win32Window::Create(const std::wstring &title,
return OnCreate();
}
bool Win32Window::Show()
{
bool Win32Window::Show() {
return ShowWindow(window_handle_, SW_SHOWNORMAL);
}
bool Win32Window::SendAppLinkToInstance(const std::wstring &title)
{
// Find our exact window
HWND hwnd = ::FindWindow(kWindowClassName, title.c_str());
if (hwnd)
{
// Dispatch new link to current window
SendAppLink(hwnd);
// (Optional) Restore our window to front in same state
WINDOWPLACEMENT place = {sizeof(WINDOWPLACEMENT)};
GetWindowPlacement(hwnd, &place);
switch (place.showCmd)
{
case SW_SHOWMAXIMIZED:
ShowWindow(hwnd, SW_SHOWMAXIMIZED);
break;
case SW_SHOWMINIMIZED:
ShowWindow(hwnd, SW_RESTORE);
break;
default:
ShowWindow(hwnd, SW_NORMAL);
break;
}
SetWindowPos(0, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE);
SetForegroundWindow(hwnd);
// Window has been found, don't create another one.
return true;
}
return false;
}
// static
LRESULT CALLBACK Win32Window::WndProc(HWND const window,
UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept
{
if (message == WM_NCCREATE)
{
auto window_struct = reinterpret_cast<CREATESTRUCT *>(lparam);
LPARAM const lparam) noexcept {
if (message == WM_NCCREATE) {
auto window_struct = reinterpret_cast<CREATESTRUCT*>(lparam);
SetWindowLongPtr(window, GWLP_USERDATA,
reinterpret_cast<LONG_PTR>(window_struct->lpCreateParams));
auto that = static_cast<Win32Window *>(window_struct->lpCreateParams);
auto that = static_cast<Win32Window*>(window_struct->lpCreateParams);
EnableFullDpiSupportIfAvailable(window);
that->window_handle_ = window;
}
else if (Win32Window *that = GetThisFromHandle(window))
{
} else if (Win32Window* that = GetThisFromHandle(window)) {
return that->MessageHandler(window, message, wparam, lparam);
}
@@ -240,80 +177,68 @@ LRESULT
Win32Window::MessageHandler(HWND hwnd,
UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept
{
switch (message)
{
case WM_DESTROY:
window_handle_ = nullptr;
Destroy();
if (quit_on_close_)
{
PostQuitMessage(0);
LPARAM const lparam) noexcept {
switch (message) {
case WM_DESTROY:
window_handle_ = nullptr;
Destroy();
if (quit_on_close_) {
PostQuitMessage(0);
}
return 0;
case WM_DPICHANGED: {
auto newRectSize = reinterpret_cast<RECT*>(lparam);
LONG newWidth = newRectSize->right - newRectSize->left;
LONG newHeight = newRectSize->bottom - newRectSize->top;
SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth,
newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
return 0;
}
return 0;
case WM_DPICHANGED:
{
auto newRectSize = reinterpret_cast<RECT *>(lparam);
LONG newWidth = newRectSize->right - newRectSize->left;
LONG newHeight = newRectSize->bottom - newRectSize->top;
SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth,
newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
return 0;
}
case WM_SIZE:
{
RECT rect = GetClientArea();
if (child_content_ != nullptr)
{
// Size and position the child window.
MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left,
rect.bottom - rect.top, TRUE);
case WM_SIZE: {
RECT rect = GetClientArea();
if (child_content_ != nullptr) {
// Size and position the child window.
MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left,
rect.bottom - rect.top, TRUE);
}
return 0;
}
return 0;
}
case WM_ACTIVATE:
if (child_content_ != nullptr)
{
SetFocus(child_content_);
}
return 0;
case WM_ACTIVATE:
if (child_content_ != nullptr) {
SetFocus(child_content_);
}
return 0;
case WM_DWMCOLORIZATIONCOLORCHANGED:
UpdateTheme(hwnd);
return 0;
case WM_DWMCOLORIZATIONCOLORCHANGED:
UpdateTheme(hwnd);
return 0;
}
return DefWindowProc(window_handle_, message, wparam, lparam);
}
void Win32Window::Destroy()
{
void Win32Window::Destroy() {
OnDestroy();
if (window_handle_)
{
if (window_handle_) {
DestroyWindow(window_handle_);
window_handle_ = nullptr;
}
if (g_active_window_count == 0)
{
if (g_active_window_count == 0) {
WindowClassRegistrar::GetInstance()->UnregisterWindowClass();
}
}
Win32Window *Win32Window::GetThisFromHandle(HWND const window) noexcept
{
return reinterpret_cast<Win32Window *>(
Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {
return reinterpret_cast<Win32Window*>(
GetWindowLongPtr(window, GWLP_USERDATA));
}
void Win32Window::SetChildContent(HWND content)
{
void Win32Window::SetChildContent(HWND content) {
child_content_ = content;
SetParent(content, window_handle_);
RECT frame = GetClientArea();
@@ -324,36 +249,30 @@ void Win32Window::SetChildContent(HWND content)
SetFocus(child_content_);
}
RECT Win32Window::GetClientArea()
{
RECT Win32Window::GetClientArea() {
RECT frame;
GetClientRect(window_handle_, &frame);
return frame;
}
HWND Win32Window::GetHandle()
{
HWND Win32Window::GetHandle() {
return window_handle_;
}
void Win32Window::SetQuitOnClose(bool quit_on_close)
{
void Win32Window::SetQuitOnClose(bool quit_on_close) {
quit_on_close_ = quit_on_close;
}
bool Win32Window::OnCreate()
{
bool Win32Window::OnCreate() {
// No-op; provided for subclasses.
return true;
}
void Win32Window::OnDestroy()
{
void Win32Window::OnDestroy() {
// No-op; provided for subclasses.
}
void Win32Window::UpdateTheme(HWND const window)
{
void Win32Window::UpdateTheme(HWND const window) {
DWORD light_mode;
DWORD light_mode_size = sizeof(light_mode);
LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey,
@@ -361,8 +280,7 @@ void Win32Window::UpdateTheme(HWND const window)
RRF_RT_REG_DWORD, nullptr, &light_mode,
&light_mode_size);
if (result == ERROR_SUCCESS)
{
if (result == ERROR_SUCCESS) {
BOOL enable_dark_mode = light_mode == 0;
DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE,
&enable_dark_mode, sizeof(enable_dark_mode));

View File

@@ -10,18 +10,15 @@
// A class abstraction for a high DPI-aware Win32 Window. Intended to be
// inherited from by classes that wish to specialize with custom
// rendering and input handling
class Win32Window
{
public:
struct Point
{
class Win32Window {
public:
struct Point {
unsigned int x;
unsigned int y;
Point(unsigned int x, unsigned int y) : x(x), y(y) {}
};
struct Size
{
struct Size {
unsigned int width;
unsigned int height;
Size(unsigned int width, unsigned int height)
@@ -37,7 +34,7 @@ public:
// consistent size this function will scale the inputted width and height as
// as appropriate for the default monitor. The window is invisible until
// |Show| is called. Returns true if the window was created successfully.
bool Create(const std::wstring &title, const Point &origin, const Size &size);
bool Create(const std::wstring& title, const Point& origin, const Size& size);
// Show the current window. Returns true if the window was successfully shown.
bool Show();
@@ -58,7 +55,7 @@ public:
// Return a RECT representing the bounds of the current client area.
RECT GetClientArea();
protected:
protected:
// Processes and route salient window messages for mouse handling,
// size change and DPI. Delegates handling of these to member overloads that
// inheriting classes can handle.
@@ -74,11 +71,9 @@ protected:
// Called when Destroy is called.
virtual void OnDestroy();
private:
private:
friend class WindowClassRegistrar;
bool SendAppLinkToInstance(const std::wstring &title);
// OS callback called by message pump. Handles the WM_NCCREATE message which
// is passed when the non-client area is being created and enables automatic
// non-client DPI scaling so that the non-client area automatically
@@ -90,7 +85,7 @@ private:
LPARAM const lparam) noexcept;
// Retrieves a class instance pointer for |window|
static Win32Window *GetThisFromHandle(HWND const window) noexcept;
static Win32Window* GetThisFromHandle(HWND const window) noexcept;
// Update the window frame's theme to match the system theme.
static void UpdateTheme(HWND const window);
@@ -104,4 +99,4 @@ private:
HWND child_content_ = nullptr;
};
#endif // RUNNER_WIN32_WINDOW_H_
#endif // RUNNER_WIN32_WINDOW_H_