Skip to content

Commit

Permalink
fix #396: (windows) fullscreen/unfullscreen events, disable minimize …
Browse files Browse the repository at this point in the history
…on fullscreen (#409)

- Fixed a bug where the newest implementation of fullscreen/unfullscreen broke the window listener events.
- Disables minimize when window is fullscreen. This mimics the behavior of Chromium.
  • Loading branch information
wisetarman authored Jan 28, 2024
1 parent 9d2a78f commit b3b1417
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 79 deletions.
75 changes: 38 additions & 37 deletions windows/window_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,10 @@ bool WindowManager::IsMinimized() {
}

void WindowManager::Minimize() {
if (IsFullScreen()) { // Like chromium, we don't want to minimize fullscreen
// windows
return;
}
HWND mainWindow = GetMainWindow();
WINDOWPLACEMENT windowPlacement;
GetWindowPlacement(mainWindow, &windowPlacement);
Expand Down Expand Up @@ -352,7 +356,7 @@ int WindowManager::IsDocked() {

double WindowManager::GetDpiForHwnd(HWND hWnd) {
auto monitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
UINT newDpiX = 96; // Default values
UINT newDpiX = 96; // Default values
UINT newDpiY = 96;

// Dynamically load shcore.dll and get the GetDpiForMonitor function address
Expand All @@ -362,21 +366,22 @@ double WindowManager::GetDpiForHwnd(HWND hWnd) {
typedef HRESULT (*GetDpiForMonitor)(HMONITOR, int, UINT*, UINT*);

GetDpiForMonitor GetDpiForMonitorFunc =
(GetDpiForMonitor)GetProcAddress(shcore, "GetDpiForMonitor");
(GetDpiForMonitor)GetProcAddress(shcore, "GetDpiForMonitor");

if (GetDpiForMonitorFunc) {
// Use the loaded function if available
const int MDT_EFFECTIVE_DPI = 0;
if (FAILED(GetDpiForMonitorFunc(monitor, MDT_EFFECTIVE_DPI, &newDpiX, &newDpiY))) {
if (FAILED(GetDpiForMonitorFunc(monitor, MDT_EFFECTIVE_DPI, &newDpiX,
&newDpiY))) {
// If it fails, set the default values again
newDpiX = 96;
newDpiY = 96;
}
}
FreeLibrary(shcore);
}
return ((double) newDpiX);
}
return ((double)newDpiX);
}

void WindowManager::Dock(const flutter::EncodableMap& args) {
HWND mainWindow = GetMainWindow();
Expand Down Expand Up @@ -468,7 +473,6 @@ void PASCAL WindowManager::AppBarQuerySetPos(HWND hwnd,
}

BOOL WindowManager::RegisterAccessBar(HWND hwnd, BOOL fRegister) {

APPBARDATA abd;

// Specify the structure size and handle to the appbar.
Expand Down Expand Up @@ -550,8 +554,8 @@ void WindowManager::SetFullScreen(const flutter::EncodableMap& args) {

// Previously inspired by how Chromium does this
// https://src.chromium.org/viewvc/chrome/trunk/src/ui/views/win/fullscreen_handler.cc?revision=247204&view=markup
// Instead, we use a modified implementation of how the media_kit package implements this
// (we got permission from the author, I believe)
// Instead, we use a modified implementation of how the media_kit package
// implements this (we got permission from the author, I believe)
// https://github.com/alexmercerind/media_kit/blob/1226bcff36eab27cb17d60c33e9c15ca489c1f06/media_kit_video/windows/utils.cc

// Save current window state if not already fullscreen.
Expand All @@ -563,35 +567,40 @@ void WindowManager::SetFullScreen(const flutter::EncodableMap& args) {
g_title_bar_style_before_fullscreen = title_bar_style_;
}

if (isFullScreen) {
g_is_window_fullscreen = isFullScreen;

if (isFullScreen) { // Set to fullscreen
::SendMessage(mainWindow, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
if (!is_frameless_) {
auto monitor = MONITORINFO{};
auto placement = WINDOWPLACEMENT{};
monitor.cbSize = sizeof(MONITORINFO);
placement.length = sizeof(WINDOWPLACEMENT);
::GetWindowPlacement(mainWindow, &placement);
::GetMonitorInfo(::MonitorFromWindow(mainWindow, MONITOR_DEFAULTTONEAREST),
&monitor);
::SetWindowLongPtr(mainWindow, GWL_STYLE, g_style_before_fullscreen & ~WS_OVERLAPPEDWINDOW);
::SetWindowPos(mainWindow, HWND_TOP, monitor.rcMonitor.left,
monitor.rcMonitor.top, monitor.rcMonitor.right - monitor.rcMonitor.left,
monitor.rcMonitor.bottom - monitor.rcMonitor.top,
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
auto monitor = MONITORINFO{};
auto placement = WINDOWPLACEMENT{};
monitor.cbSize = sizeof(MONITORINFO);
placement.length = sizeof(WINDOWPLACEMENT);
::GetWindowPlacement(mainWindow, &placement);
::GetMonitorInfo(
::MonitorFromWindow(mainWindow, MONITOR_DEFAULTTONEAREST), &monitor);
::SetWindowLongPtr(mainWindow, GWL_STYLE,
g_style_before_fullscreen & ~WS_OVERLAPPEDWINDOW);
::SetWindowPos(mainWindow, HWND_TOP, monitor.rcMonitor.left,
monitor.rcMonitor.top,
monitor.rcMonitor.right - monitor.rcMonitor.left,
monitor.rcMonitor.bottom - monitor.rcMonitor.top,
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
}
} else {
} else { // Restore from fullscreen
if (!g_maximized_before_fullscreen)
Restore();
::SetWindowLongPtr(mainWindow, GWL_STYLE, g_style_before_fullscreen | WS_OVERLAPPEDWINDOW);
::SetWindowLongPtr(mainWindow, GWL_STYLE,
g_style_before_fullscreen | WS_OVERLAPPEDWINDOW);
if (::IsZoomed(mainWindow)) {
// Refresh the parent mainWindow.
::SetWindowPos(mainWindow, nullptr, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
SWP_FRAMECHANGED);
auto rect = RECT{};
::GetClientRect(mainWindow, &rect);
auto flutter_view =
::FindWindowEx(mainWindow, nullptr, kFlutterViewWindowClassName, nullptr);
auto flutter_view = ::FindWindowEx(mainWindow, nullptr,
kFlutterViewWindowClassName, nullptr);
::SetWindowPos(flutter_view, nullptr, rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top,
SWP_NOACTIVATE | SWP_NOZORDER);
Expand All @@ -606,8 +615,6 @@ void WindowManager::SetFullScreen(const flutter::EncodableMap& args) {
SWP_NOACTIVATE | SWP_NOZORDER);
}
}

g_is_window_fullscreen = isFullScreen;
}

void WindowManager::SetAspectRatio(const flutter::EncodableMap& args) {
Expand Down Expand Up @@ -838,22 +845,16 @@ void WindowManager::SetAlwaysOnTop(const flutter::EncodableMap& args) {
}

bool WindowManager::IsAlwaysOnBottom() {
return is_always_on_bottom_;
return is_always_on_bottom_;
}

void WindowManager::SetAlwaysOnBottom(const flutter::EncodableMap& args) {
is_always_on_bottom_ =
std::get<bool>(args.at(flutter::EncodableValue("isAlwaysOnBottom")));

SetWindowPos(
GetMainWindow(),
is_always_on_bottom_ ? HWND_BOTTOM : HWND_NOTOPMOST,
0,
0,
0,
0,
SWP_NOMOVE | SWP_NOSIZE
);
SetWindowPos(GetMainWindow(),
is_always_on_bottom_ ? HWND_BOTTOM : HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE);
}

std::string WindowManager::GetTitle() {
Expand Down
82 changes: 40 additions & 42 deletions windows/window_manager_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,15 @@ std::optional<LRESULT> WindowManagerPlugin::HandleWindowProc(HWND hWnd,
std::optional<LRESULT> result = std::nullopt;

if (message == WM_DPICHANGED) {
window_manager->pixel_ratio_ = (float) LOWORD(wParam) / USER_DEFAULT_SCREEN_DPI;
window_manager->pixel_ratio_ =
(float)LOWORD(wParam) / USER_DEFAULT_SCREEN_DPI;
}

if (wParam && message == WM_NCCALCSIZE) {
if (window_manager->IsFullScreen() && window_manager->title_bar_style_ != "normal") {
if (window_manager->IsFullScreen() &&
window_manager->title_bar_style_ != "normal") {
if (window_manager->is_frameless_) {
NCCALCSIZE_PARAMS* sz = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
NCCALCSIZE_PARAMS* sz = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
sz->rgrc[0].left += 8;
sz->rgrc[0].top += 8;
sz->rgrc[0].right -= 8;
Expand Down Expand Up @@ -166,21 +168,17 @@ std::optional<LRESULT> WindowManagerPlugin::HandleWindowProc(HWND hWnd,
MINMAXINFO* info = reinterpret_cast<MINMAXINFO*>(lParam);
// For the special "unconstrained" values, leave the defaults.
if (window_manager->minimum_size_.x != 0)
info->ptMinTrackSize.x =
static_cast<LONG> (window_manager->minimum_size_.x *
window_manager->pixel_ratio_);
info->ptMinTrackSize.x = static_cast<LONG>(
window_manager->minimum_size_.x * window_manager->pixel_ratio_);
if (window_manager->minimum_size_.y != 0)
info->ptMinTrackSize.y =
static_cast<LONG> (window_manager->minimum_size_.y *
window_manager->pixel_ratio_);
info->ptMinTrackSize.y = static_cast<LONG>(
window_manager->minimum_size_.y * window_manager->pixel_ratio_);
if (window_manager->maximum_size_.x != -1)
info->ptMaxTrackSize.x =
static_cast<LONG> (window_manager->maximum_size_.x *
window_manager->pixel_ratio_);
info->ptMaxTrackSize.x = static_cast<LONG>(
window_manager->maximum_size_.x * window_manager->pixel_ratio_);
if (window_manager->maximum_size_.y != -1)
info->ptMaxTrackSize.y =
static_cast<LONG> (window_manager->maximum_size_.y *
window_manager->pixel_ratio_);
info->ptMaxTrackSize.y = static_cast<LONG>(
window_manager->maximum_size_.y * window_manager->pixel_ratio_);
result = 0;
} else if (message == WM_NCACTIVATE) {
if (wParam == TRUE) {
Expand Down Expand Up @@ -268,31 +266,31 @@ std::optional<LRESULT> WindowManagerPlugin::HandleWindowProc(HWND hWnd,
rect->bottom = bottom;
}
} else if (message == WM_SIZE) {
LONG_PTR gwlStyle =
GetWindowLongPtr(window_manager->GetMainWindow(), GWL_STYLE);
if ((gwlStyle & (WS_CAPTION | WS_THICKFRAME)) == 0 &&
wParam == SIZE_MAXIMIZED) {
if (window_manager->IsFullScreen() && wParam == SIZE_MAXIMIZED &&
window_manager->last_state != STATE_FULLSCREEN_ENTERED) {
_EmitEvent("enter-full-screen");
window_manager->last_state = STATE_FULLSCREEN_ENTERED;
} else if (window_manager->last_state == STATE_FULLSCREEN_ENTERED &&
wParam == SIZE_RESTORED) {
} else if (!window_manager->IsFullScreen() && wParam == SIZE_RESTORED &&
window_manager->last_state == STATE_FULLSCREEN_ENTERED) {
window_manager->ForceChildRefresh();
_EmitEvent("leave-full-screen");
window_manager->last_state = STATE_NORMAL;
} else if (wParam == SIZE_MAXIMIZED) {
_EmitEvent("maximize");
window_manager->last_state = STATE_MAXIMIZED;
} else if (wParam == SIZE_MINIMIZED) {
_EmitEvent("minimize");
window_manager->last_state = STATE_MINIMIZED;
return 0;
} else if (wParam == SIZE_RESTORED) {
if (window_manager->last_state == STATE_MAXIMIZED) {
_EmitEvent("unmaximize");
window_manager->last_state = STATE_NORMAL;
} else if (window_manager->last_state == STATE_MINIMIZED) {
_EmitEvent("restore");
window_manager->last_state = STATE_NORMAL;
} else if (window_manager->last_state != STATE_FULLSCREEN_ENTERED) {
if (wParam == SIZE_MAXIMIZED) {
_EmitEvent("maximize");
window_manager->last_state = STATE_MAXIMIZED;
} else if (wParam == SIZE_MINIMIZED) {
_EmitEvent("minimize");
window_manager->last_state = STATE_MINIMIZED;
return 0;
} else if (wParam == SIZE_RESTORED) {
if (window_manager->last_state == STATE_MAXIMIZED) {
_EmitEvent("unmaximize");
window_manager->last_state = STATE_NORMAL;
} else if (window_manager->last_state == STATE_MINIMIZED) {
_EmitEvent("restore");
window_manager->last_state = STATE_NORMAL;
}
}
}
} else if (message == WM_CLOSE) {
Expand All @@ -308,13 +306,13 @@ std::optional<LRESULT> WindowManagerPlugin::HandleWindowProc(HWND hWnd,
}
} else if (message == WM_WINDOWPOSCHANGED) {
if (window_manager->IsAlwaysOnBottom()) {
const flutter::EncodableMap& args = {
{flutter::EncodableValue("isAlwaysOnBottom"),
flutter::EncodableValue(true)}};
window_manager->SetAlwaysOnBottom(args);
}
const flutter::EncodableMap& args = {
{flutter::EncodableValue("isAlwaysOnBottom"),
flutter::EncodableValue(true)}};
window_manager->SetAlwaysOnBottom(args);
}
}

return result;
}

Expand Down Expand Up @@ -561,7 +559,7 @@ void WindowManagerPlugin::HandleMethodCall(
} else {
result->NotImplemented();
}
}
}

} // namespace

Expand Down

0 comments on commit b3b1417

Please sign in to comment.