From b0346085291c180dcfb4fa3123703ba85acb3827 Mon Sep 17 00:00:00 2001 From: Alex Zhuohao He Date: Tue, 3 Dec 2024 11:45:49 -0500 Subject: [PATCH 1/4] update .py and .pyx by adding new window arguments --- openage/game/main.py | 21 +++++++++++++++++++++ openage/game/main_cpp.pyx | 8 +++++++- openage/main/main.py | 21 +++++++++++++++++++++ openage/main/main_cpp.pyx | 8 +++++++- 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/openage/game/main.py b/openage/game/main.py index 0fdf007259..44b74ee058 100644 --- a/openage/game/main.py +++ b/openage/game/main.py @@ -36,6 +36,19 @@ def init_subparser(cli: ArgumentParser) -> None: help="Check if the assets are up to date" ) + cli.add_argument( + "--window-size", nargs=2, type=int, default=[1024, 768], + metavar=('WIDTH', 'HEIGHT'), + help="initial window size in pixels, e.g., --window-size 1024 768") + + cli.add_argument( + "--vsync", action='store_true', + help="enable vertical synchronization") + + cli.add_argument( + "--window-mode", choices=["fullscreen", "borderless", "windowed"], default="windowed", + help="set the window mode: fullscreen, borderless, or windowed (default)") + def main(args, error): """ @@ -98,5 +111,13 @@ def main(args, error): # encode modpacks as bytes for the C++ interface args.modpacks = [modpack.encode('utf-8') for modpack in args.modpacks] + # Pass window parameters to engine + args.window_args = { + "width": args.window_size[0], + "height": args.window_size[1], + "vsync": args.vsync, + "window_mode": args.window_mode, + } + # start the game, continue in main_cpp.pyx! return run_game(args, root) diff --git a/openage/game/main_cpp.pyx b/openage/game/main_cpp.pyx index e7697b0ddb..d37545f87c 100644 --- a/openage/game/main_cpp.pyx +++ b/openage/game/main_cpp.pyx @@ -1,4 +1,4 @@ -# Copyright 2015-2023 the openage authors. See copying.md for legal info. +# Copyright 2015-2024 the openage authors. See copying.md for legal info. from cpython.ref cimport PyObject from libcpp.string cimport string @@ -37,6 +37,12 @@ def run_game(args, root_path): else: args_cpp.mods = vector[string]() + # window + args_cpp.window_args.width = args.window_args["width"] + args_cpp.window_args.height = args.window_args["height"] + args_cpp.window_args.vsync = args.window_args["vsync"] + args_cpp.window_args.mode = args.window_args["window_mode"].encode('utf-8') + # run the game! with nogil: result = run_game_cpp(args_cpp) diff --git a/openage/main/main.py b/openage/main/main.py index fbeb527ee4..5fa628c3e5 100644 --- a/openage/main/main.py +++ b/openage/main/main.py @@ -28,6 +28,19 @@ def init_subparser(cli: ArgumentParser): "--modpacks", nargs="+", type=str, help="list of modpacks to load") + cli.add_argument( + "--window-size", nargs=2, type=int, default=[1024, 768], + metavar=('WIDTH', 'HEIGHT'), + help="initial window size in pixels, e.g., --window-size 1024 768") + + cli.add_argument( + "--vsync", action='store_true', + help="enable vertical synchronization") + + cli.add_argument( + "--window-mode", choices=["fullscreen", "borderless", "windowed"], default="windowed", + help="set the window mode: fullscreen, borderless, or windowed (default)") + def main(args, error): """ @@ -106,5 +119,13 @@ def main(args, error): else: args.modpacks = [query_modpack(list(available_modpacks.keys())).encode("utf-8")] + # Pass window parameters to engine + args.window_args = { + "width": args.window_size[0], + "height": args.window_size[1], + "vsync": args.vsync, + "window_mode": args.window_mode, + } + # start the game, continue in main_cpp.pyx! return run_game(args, root) diff --git a/openage/main/main_cpp.pyx b/openage/main/main_cpp.pyx index e7697b0ddb..d37545f87c 100644 --- a/openage/main/main_cpp.pyx +++ b/openage/main/main_cpp.pyx @@ -1,4 +1,4 @@ -# Copyright 2015-2023 the openage authors. See copying.md for legal info. +# Copyright 2015-2024 the openage authors. See copying.md for legal info. from cpython.ref cimport PyObject from libcpp.string cimport string @@ -37,6 +37,12 @@ def run_game(args, root_path): else: args_cpp.mods = vector[string]() + # window + args_cpp.window_args.width = args.window_args["width"] + args_cpp.window_args.height = args.window_args["height"] + args_cpp.window_args.vsync = args.window_args["vsync"] + args_cpp.window_args.mode = args.window_args["window_mode"].encode('utf-8') + # run the game! with nogil: result = run_game_cpp(args_cpp) From a4335bef262429aa43fb75e0af0d9daee2bb47a0 Mon Sep 17 00:00:00 2001 From: Alex Zhuohao He Date: Wed, 4 Dec 2024 16:24:20 -0500 Subject: [PATCH 2/4] update main, engine, window and presenter to get window arguments passed from py --- libopenage/engine/engine.cpp | 7 ++++--- libopenage/engine/engine.h | 6 +++++- libopenage/main.cpp | 22 ++++++++++++++++++++-- libopenage/main.h | 22 +++++++++++++++++++++- libopenage/presenter/presenter.cpp | 13 ++++--------- libopenage/presenter/presenter.h | 8 ++++++-- libopenage/renderer/opengl/window.cpp | 15 +++++++++++++++ libopenage/renderer/window.h | 11 +++++++++++ 8 files changed, 86 insertions(+), 18 deletions(-) diff --git a/libopenage/engine/engine.cpp b/libopenage/engine/engine.cpp index fa2c251b4d..dc787ebcf1 100644 --- a/libopenage/engine/engine.cpp +++ b/libopenage/engine/engine.cpp @@ -1,4 +1,4 @@ -// Copyright 2023-2023 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #include "engine.h" @@ -16,7 +16,8 @@ namespace openage::engine { Engine::Engine(mode mode, const util::Path &root_dir, const std::vector &mods, - bool debug_graphics) : + bool debug_graphics, + const renderer::window_settings &window_settings) : running{true}, run_mode{mode}, root_dir{root_dir}, @@ -56,7 +57,7 @@ Engine::Engine(mode mode, // if presenter is used, run it in a separate thread if (this->run_mode == mode::FULL) { this->threads.emplace_back([&, debug_graphics]() { - this->presenter->run(debug_graphics); + this->presenter->run(debug_graphics, window_settings); // Make sure that the presenter gets destructed in the same thread // otherwise OpenGL complains about missing contexts diff --git a/libopenage/engine/engine.h b/libopenage/engine/engine.h index 1fe4298061..d324fe4fda 100644 --- a/libopenage/engine/engine.h +++ b/libopenage/engine/engine.h @@ -9,6 +9,8 @@ #include "util/path.h" +#include + // TODO: Remove custom jthread definition when clang/libc++ finally supports it #if __llvm__ #if !__cpp_lib_jthread @@ -72,11 +74,13 @@ class Engine { * @param root_dir openage root directory. * @param mods The mods to load. * @param debug_graphics If true, enable OpenGL debug logging. + * @param window_settings window display setting */ Engine(mode mode, const util::Path &root_dir, const std::vector &mods, - bool debug_graphics = false); + bool debug_graphics = false, + const renderer::window_settings &window_settings = {}); // engine should not be copied or moved Engine(const Engine &) = delete; diff --git a/libopenage/main.cpp b/libopenage/main.cpp index e7794be40c..f8e6b45f3f 100644 --- a/libopenage/main.cpp +++ b/libopenage/main.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. +// Copyright 2015-2024 the openage authors. See copying.md for legal info. #include "main.h" @@ -31,7 +31,25 @@ int run_game(const main_arguments &args) { run_mode = openage::engine::Engine::mode::HEADLESS; } - openage::engine::Engine engine{run_mode, args.root_path, args.mods, args.gl_debug}; + // convert window arguments to window settings + renderer::window_settings win_settings = {}; + win_settings.width = args.window_args.width; + win_settings.height = args.window_args.height; + win_settings.vsync = args.window_args.vsync; + + renderer::window_mode wmode; + if (args.window_args.mode == "fullscreen") { + wmode = renderer::window_mode::FULLSCREEN; + } + else if (args.window_args.mode == "borderless") { + wmode = renderer::window_mode::BORDERLESS; + } + else { + wmode = renderer::window_mode::WINDOWED; + } + win_settings.mode = wmode; + + openage::engine::Engine engine{run_mode, args.root_path, args.mods, args.gl_debug, win_settings}; engine.loop(); diff --git a/libopenage/main.h b/libopenage/main.h index 0e60c386cc..e99b374642 100644 --- a/libopenage/main.h +++ b/libopenage/main.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. +// Copyright 2015-2024 the openage authors. See copying.md for legal info. #pragma once @@ -16,6 +16,24 @@ namespace openage { +/** + * Window parameters struct. + * + * pxd: + * + * cppclass window_arguments: + * int width + * int height + * bool vsync + * string mode + */ +struct window_arguments { + int width; + int height; + bool vsync; + std::string mode; +}; + /** * Used for passing arguments to run_game. * @@ -26,12 +44,14 @@ namespace openage { * bool gl_debug * bool headless * vector[string] mods + * window_arguments window_args */ struct main_arguments { util::Path root_path; bool gl_debug; bool headless; std::vector mods; + window_arguments window_args; }; diff --git a/libopenage/presenter/presenter.cpp b/libopenage/presenter/presenter.cpp index a37362be95..6d77a72710 100644 --- a/libopenage/presenter/presenter.cpp +++ b/libopenage/presenter/presenter.cpp @@ -32,7 +32,6 @@ #include "renderer/stages/skybox/render_stage.h" #include "renderer/stages/terrain/render_stage.h" #include "renderer/stages/world/render_stage.h" -#include "renderer/window.h" #include "time/time_loop.h" #include "util/path.h" @@ -48,10 +47,10 @@ Presenter::Presenter(const util::Path &root_dir, time_loop{time_loop} {} -void Presenter::run(bool debug_graphics) { +void Presenter::run(bool debug_graphics, const renderer::window_settings &window_settings) { log::log(INFO << "Presenter: Launching subsystems..."); - this->init_graphics(debug_graphics); + this->init_graphics(debug_graphics, window_settings); this->init_input(); @@ -93,18 +92,14 @@ std::shared_ptr Presenter::init_window_system() { return std::make_shared(); } -void Presenter::init_graphics(bool debug) { +void Presenter::init_graphics(bool debug, const renderer::window_settings &window_settings) { log::log(INFO << "Presenter: Initializing graphics subsystems..."); // Start up rendering framework this->gui_app = this->init_window_system(); // Window and renderer - renderer::window_settings settings; - settings.width = 1024; - settings.height = 768; - settings.debug = debug; - this->window = renderer::Window::create("openage presenter test", settings); + this->window = renderer::Window::create("openage presenter test", window_settings); this->renderer = this->window->make_renderer(); // Asset mangement diff --git a/libopenage/presenter/presenter.h b/libopenage/presenter/presenter.h index b43d4fc60f..6f45800a32 100644 --- a/libopenage/presenter/presenter.h +++ b/libopenage/presenter/presenter.h @@ -7,6 +7,9 @@ #include "util/path.h" +#include + + namespace qtgui { class GuiApplication; } @@ -88,8 +91,9 @@ class Presenter { * Start the presenter and initialize subsystems. * * @param debug_graphics If true, enable OpenGL debug logging. + * @param window_settings window display setting */ - void run(bool debug_graphics = false); + void run(bool debug_graphics = false, const renderer::window_settings &window_settings = {}); /** * Set the game simulation controlled by this presenter. @@ -120,7 +124,7 @@ class Presenter { * - main renderer * - component renderers (Terrain, Game Entities, GUI) */ - void init_graphics(bool debug = false); + void init_graphics(bool debug = false, const renderer::window_settings &window_settings = {}); /** * Initialize the GUI. diff --git a/libopenage/renderer/opengl/window.cpp b/libopenage/renderer/opengl/window.cpp index 5f75717540..d832c49337 100644 --- a/libopenage/renderer/opengl/window.cpp +++ b/libopenage/renderer/opengl/window.cpp @@ -57,6 +57,21 @@ GlWindow::GlWindow(const std::string &title, this->window->setFormat(format); this->window->create(); + // set display mode + switch (settings.mode) { + case window_mode::FULLSCREEN: + this->window->showFullScreen(); + break; + case window_mode::BORDERLESS: + this->window->setFlags(this->window->flags() | Qt::FramelessWindowHint); + this->window->show(); + break; + case window_mode::WINDOWED: + default: + this->window->showNormal(); + break; + } + this->context = std::make_shared(this->window, settings.debug); if (not this->context->get_raw_context()->isValid()) { throw Error{MSG(err) << "Failed to create Qt OpenGL context."}; diff --git a/libopenage/renderer/window.h b/libopenage/renderer/window.h index 71960e2d17..6f34aa58e3 100644 --- a/libopenage/renderer/window.h +++ b/libopenage/renderer/window.h @@ -21,6 +21,15 @@ namespace openage::renderer { class WindowEventHandler; +/** + * Modes for window display. + */ +enum class window_mode { + FULLSCREEN, + BORDERLESS, + WINDOWED +}; + /** * Settings for creating a window. */ @@ -35,6 +44,8 @@ struct window_settings { bool vsync = true; // If true, enable debug logging for the selected backend. bool debug = false; + // Display mode for the window. + window_mode mode = window_mode::FULLSCREEN; }; From 87da14ecafb6f043c62e230b00900251b763e725 Mon Sep 17 00:00:00 2001 From: Alex Zhuohao He Date: Fri, 6 Dec 2024 10:20:13 -0500 Subject: [PATCH 3/4] Address review feedback: fix formatting, remove redundant debug arg, and change display mode setting method. --- libopenage/engine/engine.cpp | 5 ++--- libopenage/engine/engine.h | 6 ++---- libopenage/main.cpp | 8 ++++++-- libopenage/presenter/presenter.cpp | 6 +++--- libopenage/presenter/presenter.h | 10 ++++------ libopenage/renderer/opengl/window.cpp | 14 ++++++++------ libopenage/renderer/window.h | 2 +- openage/game/main.py | 6 +++--- openage/main/main.py | 6 +++--- 9 files changed, 32 insertions(+), 31 deletions(-) diff --git a/libopenage/engine/engine.cpp b/libopenage/engine/engine.cpp index dc787ebcf1..02c0dd87d3 100644 --- a/libopenage/engine/engine.cpp +++ b/libopenage/engine/engine.cpp @@ -16,7 +16,6 @@ namespace openage::engine { Engine::Engine(mode mode, const util::Path &root_dir, const std::vector &mods, - bool debug_graphics, const renderer::window_settings &window_settings) : running{true}, run_mode{mode}, @@ -56,8 +55,8 @@ Engine::Engine(mode mode, // if presenter is used, run it in a separate thread if (this->run_mode == mode::FULL) { - this->threads.emplace_back([&, debug_graphics]() { - this->presenter->run(debug_graphics, window_settings); + this->threads.emplace_back([&]() { + this->presenter->run(window_settings); // Make sure that the presenter gets destructed in the same thread // otherwise OpenGL complains about missing contexts diff --git a/libopenage/engine/engine.h b/libopenage/engine/engine.h index d324fe4fda..0231054628 100644 --- a/libopenage/engine/engine.h +++ b/libopenage/engine/engine.h @@ -7,9 +7,9 @@ #include #include +#include "renderer/window.h" #include "util/path.h" -#include // TODO: Remove custom jthread definition when clang/libc++ finally supports it #if __llvm__ @@ -73,13 +73,11 @@ class Engine { * @param mode The run mode to use. * @param root_dir openage root directory. * @param mods The mods to load. - * @param debug_graphics If true, enable OpenGL debug logging. - * @param window_settings window display setting + * @param window_settings The settings to customize the display window (e.g. size, display mode, vsync). */ Engine(mode mode, const util::Path &root_dir, const std::vector &mods, - bool debug_graphics = false, const renderer::window_settings &window_settings = {}); // engine should not be copied or moved diff --git a/libopenage/main.cpp b/libopenage/main.cpp index f8e6b45f3f..2147cbe4e0 100644 --- a/libopenage/main.cpp +++ b/libopenage/main.cpp @@ -44,12 +44,16 @@ int run_game(const main_arguments &args) { else if (args.window_args.mode == "borderless") { wmode = renderer::window_mode::BORDERLESS; } - else { + else if (args.window_args.mode == "windowed") { wmode = renderer::window_mode::WINDOWED; } + else { + throw Error(MSG(err) << "Invalid window mode: " << args.window_args.mode); + } win_settings.mode = wmode; + win_settings.debug = args.gl_debug; - openage::engine::Engine engine{run_mode, args.root_path, args.mods, args.gl_debug, win_settings}; + openage::engine::Engine engine{run_mode, args.root_path, args.mods, win_settings}; engine.loop(); diff --git a/libopenage/presenter/presenter.cpp b/libopenage/presenter/presenter.cpp index 6d77a72710..6db1e23136 100644 --- a/libopenage/presenter/presenter.cpp +++ b/libopenage/presenter/presenter.cpp @@ -47,10 +47,10 @@ Presenter::Presenter(const util::Path &root_dir, time_loop{time_loop} {} -void Presenter::run(bool debug_graphics, const renderer::window_settings &window_settings) { +void Presenter::run(const renderer::window_settings &window_settings) { log::log(INFO << "Presenter: Launching subsystems..."); - this->init_graphics(debug_graphics, window_settings); + this->init_graphics(window_settings); this->init_input(); @@ -92,7 +92,7 @@ std::shared_ptr Presenter::init_window_system() { return std::make_shared(); } -void Presenter::init_graphics(bool debug, const renderer::window_settings &window_settings) { +void Presenter::init_graphics(const renderer::window_settings &window_settings) { log::log(INFO << "Presenter: Initializing graphics subsystems..."); // Start up rendering framework diff --git a/libopenage/presenter/presenter.h b/libopenage/presenter/presenter.h index 6f45800a32..a4b5dec68e 100644 --- a/libopenage/presenter/presenter.h +++ b/libopenage/presenter/presenter.h @@ -5,10 +5,9 @@ #include #include +#include "renderer/window.h" #include "util/path.h" -#include - namespace qtgui { class GuiApplication; @@ -90,10 +89,9 @@ class Presenter { /** * Start the presenter and initialize subsystems. * - * @param debug_graphics If true, enable OpenGL debug logging. - * @param window_settings window display setting + * @param window_settings The settings to customize the display window (e.g. size, display mode, vsync). */ - void run(bool debug_graphics = false, const renderer::window_settings &window_settings = {}); + void run(const renderer::window_settings &window_settings = {}); /** * Set the game simulation controlled by this presenter. @@ -124,7 +122,7 @@ class Presenter { * - main renderer * - component renderers (Terrain, Game Entities, GUI) */ - void init_graphics(bool debug = false, const renderer::window_settings &window_settings = {}); + void init_graphics(const renderer::window_settings &window_settings = {}); /** * Initialize the GUI. diff --git a/libopenage/renderer/opengl/window.cpp b/libopenage/renderer/opengl/window.cpp index d832c49337..46772e14d9 100644 --- a/libopenage/renderer/opengl/window.cpp +++ b/libopenage/renderer/opengl/window.cpp @@ -58,18 +58,20 @@ GlWindow::GlWindow(const std::string &title, this->window->create(); // set display mode + // Reset to a known state + this->window->setWindowState(Qt::WindowNoState); switch (settings.mode) { - case window_mode::FULLSCREEN: - this->window->showFullScreen(); + case window_mode::WINDOWED: + this->window->setFlags(this->window->flags() & ~Qt::FramelessWindowHint); break; case window_mode::BORDERLESS: this->window->setFlags(this->window->flags() | Qt::FramelessWindowHint); - this->window->show(); break; - case window_mode::WINDOWED: - default: - this->window->showNormal(); + case window_mode::FULLSCREEN: + this->window->setWindowState(Qt::WindowFullScreen); break; + default: + throw Error{MSG(err) << "Invalid window mode."}; } this->context = std::make_shared(this->window, settings.debug); diff --git a/libopenage/renderer/window.h b/libopenage/renderer/window.h index 6f34aa58e3..e3465bef4d 100644 --- a/libopenage/renderer/window.h +++ b/libopenage/renderer/window.h @@ -45,7 +45,7 @@ struct window_settings { // If true, enable debug logging for the selected backend. bool debug = false; // Display mode for the window. - window_mode mode = window_mode::FULLSCREEN; + window_mode mode = window_mode::WINDOWED; }; diff --git a/openage/game/main.py b/openage/game/main.py index 44b74ee058..1ad1378426 100644 --- a/openage/game/main.py +++ b/openage/game/main.py @@ -39,15 +39,15 @@ def init_subparser(cli: ArgumentParser) -> None: cli.add_argument( "--window-size", nargs=2, type=int, default=[1024, 768], metavar=('WIDTH', 'HEIGHT'), - help="initial window size in pixels, e.g., --window-size 1024 768") + help="Initial window size in pixels") cli.add_argument( "--vsync", action='store_true', - help="enable vertical synchronization") + help="Enable vertical synchronization") cli.add_argument( "--window-mode", choices=["fullscreen", "borderless", "windowed"], default="windowed", - help="set the window mode: fullscreen, borderless, or windowed (default)") + help="Set the window mode") def main(args, error): diff --git a/openage/main/main.py b/openage/main/main.py index 5fa628c3e5..05266ec744 100644 --- a/openage/main/main.py +++ b/openage/main/main.py @@ -31,15 +31,15 @@ def init_subparser(cli: ArgumentParser): cli.add_argument( "--window-size", nargs=2, type=int, default=[1024, 768], metavar=('WIDTH', 'HEIGHT'), - help="initial window size in pixels, e.g., --window-size 1024 768") + help="Initial window size in pixels") cli.add_argument( "--vsync", action='store_true', - help="enable vertical synchronization") + help="Enable vertical synchronization") cli.add_argument( "--window-mode", choices=["fullscreen", "borderless", "windowed"], default="windowed", - help="set the window mode: fullscreen, borderless, or windowed (default)") + help="Set the window mode") def main(args, error): From 8094dc6ab19affc544200804f65feb0a9e25c0ae Mon Sep 17 00:00:00 2001 From: Alex Zhuohao He Date: Sat, 7 Dec 2024 11:39:32 -0500 Subject: [PATCH 4/4] remove redundant window.setFlags() and pass window_settings to presenter by value --- libopenage/presenter/presenter.cpp | 2 +- libopenage/presenter/presenter.h | 2 +- libopenage/renderer/opengl/window.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libopenage/presenter/presenter.cpp b/libopenage/presenter/presenter.cpp index 6db1e23136..9775b62d9b 100644 --- a/libopenage/presenter/presenter.cpp +++ b/libopenage/presenter/presenter.cpp @@ -47,7 +47,7 @@ Presenter::Presenter(const util::Path &root_dir, time_loop{time_loop} {} -void Presenter::run(const renderer::window_settings &window_settings) { +void Presenter::run(const renderer::window_settings window_settings) { log::log(INFO << "Presenter: Launching subsystems..."); this->init_graphics(window_settings); diff --git a/libopenage/presenter/presenter.h b/libopenage/presenter/presenter.h index a4b5dec68e..2059daeed0 100644 --- a/libopenage/presenter/presenter.h +++ b/libopenage/presenter/presenter.h @@ -91,7 +91,7 @@ class Presenter { * * @param window_settings The settings to customize the display window (e.g. size, display mode, vsync). */ - void run(const renderer::window_settings &window_settings = {}); + void run(const renderer::window_settings window_settings = {}); /** * Set the game simulation controlled by this presenter. diff --git a/libopenage/renderer/opengl/window.cpp b/libopenage/renderer/opengl/window.cpp index 46772e14d9..548575dd2d 100644 --- a/libopenage/renderer/opengl/window.cpp +++ b/libopenage/renderer/opengl/window.cpp @@ -62,7 +62,7 @@ GlWindow::GlWindow(const std::string &title, this->window->setWindowState(Qt::WindowNoState); switch (settings.mode) { case window_mode::WINDOWED: - this->window->setFlags(this->window->flags() & ~Qt::FramelessWindowHint); + // nothing to do because it's the default break; case window_mode::BORDERLESS: this->window->setFlags(this->window->flags() | Qt::FramelessWindowHint);