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
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -653,14 +653,14 @@ Makes the window not show in the taskbar / dock.
Sets progress value in progress bar. Valid range is [0, 1.0].


##### hasShadow `macos`
##### hasShadow `macos` `windows`

Returns `bool` - Whether the window has a shadow.
Returns `bool` - Whether the window has a shadow. On Windows, always returns true unless window is frameless.


##### setHasShadow `macos`
##### setHasShadow `macos` `windows`

Sets whether the window should have a shadow.
Sets whether the window should have a shadow. On Windows, doesn't do anything unless window is frameless.


##### getOpacity `macos` `windows`
Expand Down
8 changes: 4 additions & 4 deletions lib/src/window_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -531,16 +531,16 @@ class WindowManager {
await _channel.invokeMethod('setProgressBar', arguments);
}

/// Returns `bool` - Whether the window has a shadow.
/// Returns `bool` - Whether the window has a shadow. On Windows, always returns true unless window is frameless.
///
/// @platforms macos
/// @platforms macos,windows
Future<bool> hasShadow() async {
return await _channel.invokeMethod('hasShadow');
}

/// Sets whether the window should have a shadow.
/// Sets whether the window should have a shadow. On Windows, doesn't do anything unless window is frameless.
///
/// @platforms macos
/// @platforms macos,windows
Future<void> setHasShadow(bool hasShadow) async {
final Map<String, dynamic> arguments = {
'hasShadow': hasShadow,
Expand Down
57 changes: 22 additions & 35 deletions windows/window_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class WindowManager {

int last_state = STATE_NORMAL;

bool has_shadow_ = false;
bool is_frameless_ = false;
bool is_prevent_close_ = false;
double aspect_ratio_ = 0;
Expand Down Expand Up @@ -127,28 +128,12 @@ void WindowManager::SetAsFrameless() {
HWND hWnd = GetMainWindow();

RECT rect;
MARGINS margins = {0, 0, 0, 0};

GetWindowRect(hWnd, &rect);
SetWindowLong(hWnd, GWL_STYLE,
WS_POPUP | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU |
WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_VISIBLE);
DwmExtendFrameIntoClientArea(hWnd, &margins);
SetWindowPos(hWnd, nullptr, rect.left, rect.top, rect.right - rect.left,
rect.bottom - rect.top,
SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE |
SWP_FRAMECHANGED);

flutter::EncodableMap args = flutter::EncodableMap();
args[flutter::EncodableValue("backgroundColorA")] =
flutter::EncodableValue(0);
args[flutter::EncodableValue("backgroundColorR")] =
flutter::EncodableValue(0);
args[flutter::EncodableValue("backgroundColorG")] =
flutter::EncodableValue(0);
args[flutter::EncodableValue("backgroundColorB")] =
flutter::EncodableValue(0);
SetBackgroundColor(args);
}

void WindowManager::WaitUntilReadyToShow() {
Expand Down Expand Up @@ -569,31 +554,15 @@ void WindowManager::SetTitle(const flutter::EncodableMap& args) {
void WindowManager::SetTitleBarStyle(const flutter::EncodableMap& args) {
title_bar_style_ =
std::get<std::string>(args.at(flutter::EncodableValue("titleBarStyle")));

HWND hWnd = GetMainWindow();
DWORD gwlStyle = GetWindowLong(hWnd, GWL_STYLE);
// Enables the ability to go from setAsFrameless() to
// TitleBarStyle.normal/hidden
is_frameless_ = false;
if (title_bar_style_ == "hidden") {
gwlStyle = WS_POPUP | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU |
WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_VISIBLE;
SetWindowLong(hWnd, GWL_STYLE, gwlStyle);
BOOL composition_enabled = FALSE;
bool success = DwmIsCompositionEnabled(&composition_enabled) == S_OK;
if (composition_enabled && success) {
static const MARGINS shadow_state[2]{{0, 0, 0, 0}, {1, 1, 1, 1}};
DwmExtendFrameIntoClientArea(hWnd, &shadow_state[0]);
ShowWindow(hWnd, SW_SHOW);
}
} else {
gwlStyle = WS_OVERLAPPEDWINDOW | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU |
WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE;
SetWindowLong(hWnd, GWL_STYLE, gwlStyle);
}

MARGINS margins = {0, 0, 0, 0};
HWND hWnd = GetMainWindow();
RECT rect;
GetWindowRect(hWnd, &rect);
DwmExtendFrameIntoClientArea(hWnd, &margins);
SetWindowPos(hWnd, nullptr, rect.left, rect.top, 0, 0,
SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE |
SWP_FRAMECHANGED);
Expand Down Expand Up @@ -653,6 +622,24 @@ void WindowManager::SetProgressBar(const flutter::EncodableMap& args) {
}
}

bool WindowManager::HasShadow() {
if (is_frameless_)
return has_shadow_;
return true;
}

void WindowManager::SetHasShadow(const flutter::EncodableMap& args) {
if (is_frameless_) {
has_shadow_ = std::get<bool>(args.at(flutter::EncodableValue("hasShadow")));

HWND hWnd = GetMainWindow();

MARGINS margins[2]{{0, 0, 0, 0}, {0, 0, 1, 0}};

DwmExtendFrameIntoClientArea(hWnd, &margins[has_shadow_]);
}
}

double WindowManager::GetOpacity() {
return opacity_;
}
Expand Down
37 changes: 24 additions & 13 deletions windows/window_manager_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,48 +109,51 @@ std::optional<LRESULT> WindowManagerPlugin::HandleWindowProc(HWND hWnd,
std::optional<LRESULT> result = std::nullopt;

if (message == WM_NCCALCSIZE) {
// This must always be first or else the one of other two ifs will execute
// when window is in full screen and we don't want that
if (wParam && window_manager->IsFullScreen()) {
NCCALCSIZE_PARAMS* sz = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
sz->rgrc[0].bottom -= 3;
return (WVR_HREDRAW | WVR_VREDRAW);
return 0;
}

// This must always be before handling title_bar_style_ == "hidden" so
// the if TitleBarStyle.hidden doesn't get executed.
if (wParam && window_manager->is_frameless_) {
SetWindowLong(hWnd, 0, 0);
NCCALCSIZE_PARAMS* sz = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
// Add borders when maximized so app doesn't get cut off.
if (window_manager->IsMaximized()) {
sz->rgrc[0].left += 8;
sz->rgrc[0].top += 8;
sz->rgrc[0].right -= 8;
sz->rgrc[0].bottom -= 9;
}
// This cuts the app at the bottom by one pixel but that's necessary to
// prevent jitter when resizing the app
sz->rgrc[0].bottom += 1;
return (WVR_HREDRAW | WVR_VREDRAW);
return 0;
}

// This must always be last.
if (wParam && window_manager->title_bar_style_ == "hidden") {
WINDOWPLACEMENT wPos;
wPos.length = sizeof(wPos);
GetWindowPlacement(hWnd, &wPos);
RECT borderThickness;
SetRectEmpty(&borderThickness);
AdjustWindowRectEx(&borderThickness,
GetWindowLongPtr(hWnd, GWL_STYLE) & WS_POPUP, FALSE,
NULL);
NCCALCSIZE_PARAMS* sz = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);

// Add 8 pixel to the top border when maximized so the app isn't cut off
// Top resize border is still not working.
if (window_manager->IsMaximized()) {
sz->rgrc[0].top += 8;
} else {
// on windows 10, if set to 0, there's a white line at the top
// of the app and I've yet to find a way to remove that.
sz->rgrc[0].top += IsWindows11OrGreater() ? 0 : 1;
}
sz->rgrc[0].right -= 8;
sz->rgrc[0].bottom -= 8;
sz->rgrc[0].left -= -8;

return (WVR_HREDRAW | WVR_VREDRAW);
// Previously (WVR_HREDRAW | WVR_VREDRAW), but returning 0 or 1 doesn't
// actually break anything so I've set it to 0. Unless someone pointed a
// problem in the future.
return 0;
}
} else if (message == WM_NCHITTEST) {
if (!window_manager->is_resizable_) {
Expand Down Expand Up @@ -458,6 +461,14 @@ void WindowManagerPlugin::HandleMethodCall(
std::get<flutter::EncodableMap>(*method_call.arguments());
window_manager->SetProgressBar(args);
result->Success(flutter::EncodableValue(true));
} else if (method_name.compare("hasShadow") == 0) {
bool value = window_manager->HasShadow();
result->Success(flutter::EncodableValue(value));
} else if (method_name.compare("setHasShadow") == 0) {
const flutter::EncodableMap& args =
std::get<flutter::EncodableMap>(*method_call.arguments());
window_manager->SetHasShadow(args);
result->Success(flutter::EncodableValue(true));
} else if (method_name.compare("getOpacity") == 0) {
double value = window_manager->GetOpacity();
result->Success(flutter::EncodableValue(value));
Expand Down