Skip to content

[Windows] Use frameless window to implement fullscreen #456

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
YuiHrsw opened this issue May 9, 2024 · 1 comment · May be fixed by #531
Open

[Windows] Use frameless window to implement fullscreen #456

YuiHrsw opened this issue May 9, 2024 · 1 comment · May be fixed by #531

Comments

@YuiHrsw
Copy link

YuiHrsw commented May 9, 2024

The current setFullscreen() function on Windows may show the native window border as described in #211 and the application content may flicker after setFullscreen(true), Sometimes it may freeze the UI.

On windows, there is another way to make application fullscreen:

1.Set the application to use frameless window.
2.Set the window size to the screen size.
3.Make the window cover the whole screen.

The windows taskbar will automatically hide itself.

I use the window_size package to get screen size:

              var info = await getCurrentScreen();
              if (info != null) {
                await windowManager.setAsFrameless();
                await windowManager.setPosition(Offset.zero);
                await windowManager.setSize(
                  Size(
                    info.frame.width / info.scaleFactor,
                    info.frame.height / info.scaleFactor,
                  ),
                );
              }

When the application is maximized, use the original way to set fullscreen.
This code to enter fullscreen mode works fine on my computer.

Could you provide an option to use this way to set fullscreen on windows?

@YuiHrsw YuiHrsw changed the title Use frameless window to implement fullscreen on windows [Windows] Use frameless window to implement fullscreen on windows May 9, 2024
@YuiHrsw YuiHrsw changed the title [Windows] Use frameless window to implement fullscreen on windows [Windows] Use frameless window to implement fullscreen May 9, 2024
@YuiHrsw
Copy link
Author

YuiHrsw commented Feb 12, 2025

Since window_manager depends on screen_retriever,
the code can be simplified:

on enter:

if (Platform.isWindows &&
    !await windowManager.isMaximized()) {
  AppStorage().windowPos = await windowManager.getPosition();
  AppStorage().windowSize = await windowManager.getSize();
  var info = (await screenRetriever.getPrimaryDisplay());
  await windowManager.setAsFrameless();
  await windowManager.setPosition(Offset.zero);
  await windowManager.setSize(info.size);
} else {
  windowManager.setFullScreen(true);
}

on exit:

if (Platform.isWindows && !await windowManager.isMaximized()) {
  windowManager.setSize(AppStorage().windowSize);
  windowManager.setTitleBarStyle(TitleBarStyle.hidden);
  windowManager.setPosition(AppStorage().windowPos);
} else {
  windowManager.setFullScreen(false);
}

It works well on my own project. (no flicker & freeze, native titlebar won't appear on enter/exit fullscreen)
but in this way, I have to maintain isfullscreen property and window size & position.

I tried edit the plugin c++ code like this:

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

  HWND mainWindow = GetMainWindow();

  // 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)
  // https://github.com./alexmercerind/media_kit/blob/1226bcff36eab27cb17d60c33e9c15ca489c1f06/media_kit_video/windows/utils.cc

  // Save current window state if not already fullscreen.
  if (!g_is_window_fullscreen) {
    // Save current window information.
    g_maximized_before_fullscreen = ::IsZoomed(mainWindow);
    g_style_before_fullscreen = GetWindowLong(mainWindow, GWL_STYLE);
    ::GetWindowRect(mainWindow, &g_frame_before_fullscreen);
    g_title_bar_style_before_fullscreen = title_bar_style_;
  }

  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);
      SetAsFrameless();
      ::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 {  // Restore from fullscreen
    // if (!g_maximized_before_fullscreen)
    //   Restore();
    ::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);
      ::SetWindowPos(flutter_view, nullptr, rect.left, rect.top,
                     rect.right - rect.left, rect.bottom - rect.top,
                     SWP_NOACTIVATE | SWP_NOZORDER);
      if (g_maximized_before_fullscreen)
        PostMessage(mainWindow, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
    } else {
      // ::SetWindowPos(
      //     mainWindow, nullptr, g_frame_before_fullscreen.left,
      //     g_frame_before_fullscreen.top,
      //     g_frame_before_fullscreen.right - g_frame_before_fullscreen.left,
      //     g_frame_before_fullscreen.bottom - g_frame_before_fullscreen.top,
      //     SWP_NOACTIVATE | SWP_NOZORDER);

      // SetSize
      SetWindowPos(mainWindow, nullptr, 0, 0,
            g_frame_before_fullscreen.right - g_frame_before_fullscreen.left,
            g_frame_before_fullscreen.bottom - g_frame_before_fullscreen.top,
                    SWP_NOMOVE);
      // SetTitlebarStyle
      title_bar_style_ = g_title_bar_style_before_fullscreen;
      is_frameless_ = false;
      MARGINS margins = {0, 0, 0, 0};
      RECT rect1;
      GetWindowRect(mainWindow, &rect1);
      DwmExtendFrameIntoClientArea(mainWindow, &margins);
      SetWindowPos(mainWindow, nullptr, rect1.left, rect1.top, 0, 0,
            SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE |
            SWP_FRAMECHANGED);
      // SetPosition
      SetWindowPos(mainWindow, nullptr, g_frame_before_fullscreen.left,
        g_frame_before_fullscreen.top, 0, 0,
                SWP_NOSIZE);
    }
  }
}

However, it only works fine on enter fullscreen (no flicker & freeze) but the native titlebar still appear momentarily on exit.
Does anyone know how to fix this?

flutter doctor output:

[✓] Flutter (Channel stable, 3.27.3, on Microsoft Windows [版本 10.0.22631.4751], locale zh-CN)
[✓] Windows Version (Installed version of Windows is version 10 or higher)
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[✓] Chrome - develop for the web
[✓] Visual Studio - develop Windows apps (Visual Studio Community 2022 17.12.4)
[!] Android Studio (not installed)
[✓] Proxy Configuration
[✓] Connected device (3 available)
[✓] Network resources

something may be useful

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants