diff --git a/android/service/platform_api_stub.cpp b/android/service/platform_api_stub.cpp index 4d351bd27790d04d61ffc783fdc4a43959078b22..b86835d122d471c92591cd809a324ea29ea39dbe 100644 --- a/android/service/platform_api_stub.cpp +++ b/android/service/platform_api_stub.cpp @@ -64,6 +64,7 @@ void PlatformApiStub::update_window_state(const WindowStateUpdate &state) { out->set_frame_bottom(in.frame.bottom); out->set_task_id(in.task_id); out->set_stack_id(in.stack_id); + out->set_videofullscreen(false); }; for (const auto &window : state.updated_windows) { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4369c7c8949ff01f139866a4084e12dcd9085e53..0f06ab9176f9396fa04562b54687d7652bd0e54b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -277,6 +277,8 @@ set(SOURCES anbox/platform/sdl/sdl_wrapper.h anbox/platform/sdl/window.cpp anbox/platform/sdl/window.h + anbox/platform/sdl/toast_window.cpp + anbox/platform/sdl/toast_window.h anbox/protobuf/anbox_bridge.proto anbox/protobuf/anbox_container.proto diff --git a/src/anbox/bridge/platform_api_skeleton.cpp b/src/anbox/bridge/platform_api_skeleton.cpp index 1274754ebb936406e0165095f6d51f0fd9ba73cc..d0d11f0e5410e656f1ba8a1f2f485a60a7a27074 100644 --- a/src/anbox/bridge/platform_api_skeleton.cpp +++ b/src/anbox/bridge/platform_api_skeleton.cpp @@ -84,7 +84,8 @@ void PlatformApiSkeleton::handle_window_state_update_event(const anbox::protobuf graphics::Rect(window.frame_left(), window.frame_top(), window.frame_right(), window.frame_bottom()), window.package_name(), wm::Task::Id(window.task_id()), - wm::Stack::Id(window.stack_id())); + wm::Stack::Id(window.stack_id()), + window.has_videofullscreen() && window.videofullscreen()); }; wm::WindowState::List updated; diff --git a/src/anbox/cmds/session_manager.cpp b/src/anbox/cmds/session_manager.cpp index d9c76efca4efcb5a4dbc41859c10f6daab9ff445..856a364f0c42f5d708e78923cdd9d893cb48bda3 100644 --- a/src/anbox/cmds/session_manager.cpp +++ b/src/anbox/cmds/session_manager.cpp @@ -196,6 +196,7 @@ anbox::cmds::SessionManager::SessionManager() platform->set_window_manager(window_manager); platform->set_renderer(gl_server->renderer()); + platform->create_toast_window(); window_manager->setup(); android_api_stub->set_platform(platform); diff --git a/src/anbox/graphics/multi_window_composer_strategy.cpp b/src/anbox/graphics/multi_window_composer_strategy.cpp index 7d2cbb6fc4c67e06577e3a8392253891a0dbcab8..03ff56e6c340008d6a13086b5576c841fdca391a 100644 --- a/src/anbox/graphics/multi_window_composer_strategy.cpp +++ b/src/anbox/graphics/multi_window_composer_strategy.cpp @@ -18,6 +18,7 @@ #include "anbox/graphics/multi_window_composer_strategy.h" #include "anbox/wm/manager.h" #include "anbox/utils.h" +#include "anbox/logger.h" namespace anbox { namespace graphics { @@ -25,10 +26,27 @@ MultiWindowComposerStrategy::MultiWindowComposerStrategy(const std::shared_ptr, RenderableList> MultiWindowComposerStrategy::process_layers(const RenderableList &renderables) { WindowRenderableList win_layers; + bool bGetToast = false; // if don't have toast frame, tell wm to hide toast_window for (const auto &renderable : renderables) { // Ignore all surfaces which are not meant for a task - if (!utils::string_starts_with(renderable.name(), "org.anbox.surface.")) + if (renderable.name() == "Toast") { + if (bGetToast) { + WARNING("Toast! toast choosed"); + continue; + } + auto w = wm_->update_toast_window(renderable.screen_position()); + if (w) { + win_layers.insert({w, {renderable}}); + } else { + ERROR("Toast! get toast window error"); + continue; + } + bGetToast = true; + continue; + } + if (!utils::string_starts_with(renderable.name(), "org.anbox.surface.")) { continue; + } wm::Task::Id task_id = 0; if (sscanf(renderable.name().c_str(), "org.anbox.surface.%d", &task_id) != 1 || !task_id) @@ -36,7 +54,6 @@ std::map, RenderableList> MultiWindowComposerStrateg auto w = wm_->find_window_for_task(task_id); if (!w) continue; - if (win_layers.find(w) == win_layers.end()) { win_layers.insert({w, {renderable}}); continue; @@ -44,6 +61,9 @@ std::map, RenderableList> MultiWindowComposerStrateg win_layers[w].push_back(renderable); } + if (!bGetToast) { // hide toast window + wm_->update_toast_window(Rect(0, 0, 0, 0)); + } for (auto &w : win_layers) { const auto &renderables = w.second; diff --git a/src/anbox/platform/base_platform.h b/src/anbox/platform/base_platform.h index 244bafee62569dd8a22063a8d045f0161f5c823a..2e3b50d810cf17ea5d1f2bef84de63a8bf8ab261 100644 --- a/src/anbox/platform/base_platform.h +++ b/src/anbox/platform/base_platform.h @@ -72,6 +72,7 @@ class BasePlatform { virtual void set_renderer(const std::shared_ptr &renderer) = 0; virtual void set_window_manager(const std::shared_ptr &window_manager) = 0; + virtual void create_toast_window() = 0; virtual bool restore_app(const std::string &package_name) = 0; virtual bool supports_multi_window() const = 0; diff --git a/src/anbox/platform/null/platform.cpp b/src/anbox/platform/null/platform.cpp index 41b04654729277b2ae4c01f40da60916890356c2..446564dd102e106456af9386c0b6de2b60cf5a75 100644 --- a/src/anbox/platform/null/platform.cpp +++ b/src/anbox/platform/null/platform.cpp @@ -87,5 +87,10 @@ std::string NullPlatform::ime_socket_file() const { ERROR("Not implemented"); return ""; } + +void NullPlatform::create_toast_window() { + ERROR("Not implemented"); +} + } // namespace wm } // namespace anbox diff --git a/src/anbox/platform/null/platform.h b/src/anbox/platform/null/platform.h index 7e53c7261f73cbaf35fb19507ecb24cdd39d6abc..8476091df238fc8cd5771c71a95d0c1295e7090b 100644 --- a/src/anbox/platform/null/platform.h +++ b/src/anbox/platform/null/platform.h @@ -36,6 +36,7 @@ class NullPlatform : public BasePlatform { std::shared_ptr create_audio_source() override; void set_renderer(const std::shared_ptr &renderer) override; void set_window_manager(const std::shared_ptr &window_manager) override; + void create_toast_window() override; bool supports_multi_window() const override; int get_user_window_event() const override; std::string ime_socket_file() const override; diff --git a/src/anbox/platform/sdl/platform.cpp b/src/anbox/platform/sdl/platform.cpp index e55d335b9e4c93dea45600d111565f8e516b1313..78bf4b360d087c5c104a76fbac09bfdf4718920c 100644 --- a/src/anbox/platform/sdl/platform.cpp +++ b/src/anbox/platform/sdl/platform.cpp @@ -26,6 +26,7 @@ #include "anbox/platform/sdl/audio_sink.h" #include "anbox/platform/alsa/audio_source.h" #include "anbox/system_configuration.h" +#include "anbox/platform/sdl/toast_window.h" #include "anbox/wm/manager.h" @@ -155,6 +156,20 @@ void Platform::set_renderer(const std::shared_ptr &renderer) { renderer_ = renderer; } +void Platform::create_toast_window() { + /* This is used to create window to show toast message in android. + * In normal time, it is hided. When a toast frame comes in, show toast window. + * Run create_toast_window after set_renderer and set_window_manager, if not toast_window + * will have no use. + */ + auto w = std::make_shared(renderer_, anbox::graphics::Rect(0, 0, 0, 0)); + if (window_manager_) { + window_manager_->set_toast_window(w); + } else { + WARNING("toast window set failed!!!"); + } +} + void Platform::set_window_manager(const std::shared_ptr &window_manager) { window_manager_ = window_manager; } diff --git a/src/anbox/platform/sdl/platform.h b/src/anbox/platform/sdl/platform.h index 406afecec4d956c2736bdd0e09f84054c10f12cb..5d7b3b54cc3e721c230956112621e87aa3f70bef 100644 --- a/src/anbox/platform/sdl/platform.h +++ b/src/anbox/platform/sdl/platform.h @@ -63,6 +63,7 @@ class Platform : public std::enable_shared_from_this, void set_renderer(const std::shared_ptr &renderer) override; void set_window_manager(const std::shared_ptr &window_manager) override; + void create_toast_window() override; void set_clipboard_data(const ClipboardData &data) override; ClipboardData get_clipboard_data() override; diff --git a/src/anbox/platform/sdl/toast_window.cpp b/src/anbox/platform/sdl/toast_window.cpp new file mode 100644 index 0000000000000000000000000000000000000000..90632bf3e44a8c8bad3cb241058a1951f229d46e --- /dev/null +++ b/src/anbox/platform/sdl/toast_window.cpp @@ -0,0 +1,68 @@ +#include "anbox/platform/sdl/toast_window.h" +#include "anbox/logger.h" + +namespace anbox { +namespace platform { +namespace sdl { + +ToastWindow::ToastWindow(const std::shared_ptr &renderer, const graphics::Rect &frame) + : wm::Window(renderer, 0, frame, "toast") { + window_ = SDL_CreateWindow("toast", frame.left(), frame.top(), frame.width(), frame.height(), + SDL_WINDOW_BORDERLESS | SDL_WINDOW_TOOLTIP); + if (!window_) { + const auto message = utils::string_format("Failed to create window: %s", SDL_GetError()); + return; + } + + SDL_SysWMinfo info; + SDL_VERSION(&info.version); + SDL_GetWindowWMInfo(window_, &info); + switch (info.subsystem) { +#if defined(X11_SUPPORT) + case SDL_SYSWM_X11: + native_display_ = static_cast(info.info.x11.display); + set_native_handle(static_cast(info.info.x11.window)); + break; +#endif +#if defined(WAYLAND_SUPPORT) + case SDL_SYSWM_WAYLAND: + native_display_ = reinterpret_cast(info.info.wl.display); + set_native_handle(reinterpret_cast(info.info.wl.surface)); + break; +#endif +#if defined(MIR_SUPPORT) + case SDL_SYSWM_MIR: { + native_display_ = static_cast(mir_connection_get_egl_native_display(info.info.mir.connection)); + auto buffer_stream = mir_surface_get_buffer_stream(info.info.mir.surface); + set_native_handle(reinterpret_cast(mir_buffer_stream_get_egl_native_window(buffer_stream))); + break; + } +#endif + default: + ERROR("Unknown subsystem (%d)", info.subsystem); + } + SDL_HideWindow(window_); + + attach(); +} + +ToastWindow::~ToastWindow() { + release(); +} + +void ToastWindow::update_state(const wm::WindowState::List &states) { + auto state = states[0]; + if (state.stack() == wm::Stack::Id::Default) { + SDL_HideWindow(window_); + return; + } + if (frame() != state.frame()) { + SDL_SetWindowSize(window_, state.frame().width(), state.frame().height()); + SDL_SetWindowPosition(window_, state.frame().left(), state.frame().top()); + update_frame(state.frame()); + } + SDL_ShowWindow(window_); +} +} // namespace sdl +} // namespace platform +} // namespace anbox diff --git a/src/anbox/platform/sdl/toast_window.h b/src/anbox/platform/sdl/toast_window.h new file mode 100644 index 0000000000000000000000000000000000000000..7f1f703524838ea26e12f34823e1b7d58971749b --- /dev/null +++ b/src/anbox/platform/sdl/toast_window.h @@ -0,0 +1,29 @@ + +#ifndef ANBOX_PLATFORM_SDL_TOAST_WINDOW_H_ +#define ANBOX_PLATFORM_SDL_TOAST_WINDOW_H_ + +#include "anbox/wm/window.h" +#include "anbox/platform/sdl/sdl_wrapper.h" + +class Renderer; + +namespace anbox { +namespace platform { +namespace sdl { +class ToastWindow : public std::enable_shared_from_this, public wm::Window { + public: + ToastWindow(const std::shared_ptr &renderer, + const graphics::Rect &frame); + ~ToastWindow(); + + void update_state(const wm::WindowState::List &states) override; + + private: + SDL_Window *window_; + EGLNativeDisplayType native_display_; +}; +} // namespace sdl +} // namespace platform +} // namespace anbox + +#endif diff --git a/src/anbox/platform/sdl/window.cpp b/src/anbox/platform/sdl/window.cpp index d57bd24bc0f181014883ba32f53638fdd740af46..d249238067eedb468a317c8bbbc111266f1dc3b7 100755 --- a/src/anbox/platform/sdl/window.cpp +++ b/src/anbox/platform/sdl/window.cpp @@ -157,6 +157,9 @@ Window::~Window() { } bool Window::title_event_filter(int x, int y) { + if (fullscreen_) { + return false; + } std::vector dis_area; { std::lock_guard l(mutex_); @@ -174,6 +177,10 @@ bool Window::title_event_filter(int x, int y) { SDL_HitTestResult Window::on_window_hit(SDL_Window *window, const SDL_Point *pt, void *data) { auto platform_window = reinterpret_cast(data); + if (platform_window->get_fullscreen()) { + return SDL_HITTEST_NORMAL; + } + int w = 0, h = 0; SDL_GetWindowSize(window, &w, &h); @@ -344,6 +351,19 @@ void Window::setResizing(bool resizing) { } void Window::update_state(const wm::WindowState::List &states) { + for (auto ws : states) + { + if (!fullscreen_ && ws.videofullscreen()) { + SDL_SetWindowFullscreen(window_, SDL_WINDOW_FULLSCREEN_DESKTOP); + fullscreen_ = true; + } else if (fullscreen_ && !ws.videofullscreen()) { + SDL_SetWindowFullscreen(window_, 0); + fullscreen_ = false; + } + if (fullscreen_) { + return; + } + } if (!initialized.load() && !states.empty()) { int w = 0; int h = 0; diff --git a/src/anbox/platform/sdl/window.h b/src/anbox/platform/sdl/window.h index 6e03ed6fcaf5d4f4f4abe51ca2abfe7a7540f31a..40b25556380dc3bee8b4bfae81c3a7bfe686d9ee 100755 --- a/src/anbox/platform/sdl/window.h +++ b/src/anbox/platform/sdl/window.h @@ -83,6 +83,7 @@ class Window : public std::enable_shared_from_this, public wm::Window { void setResizing(bool resizing) override; void restore_window(); + bool get_fullscreen() { return fullscreen_; } Id id() const; std::uint32_t window_id() const; Uint32 GetWindowFlags(){return SDL_GetWindowFlags(window_);} @@ -111,6 +112,7 @@ class Window : public std::enable_shared_from_this, public wm::Window { std::uint32_t visible_property; std::vector dis_area_; std::mutex mutex_; + bool fullscreen_ = false; }; } // namespace sdl } // namespace platform diff --git a/src/anbox/protobuf/anbox_bridge.proto b/src/anbox/protobuf/anbox_bridge.proto index 993ae5ede1d4f97597272472edfdf36299dc29af..f9269bf0f1947d676c52bde74eea69ba4f4e258c 100644 --- a/src/anbox/protobuf/anbox_bridge.proto +++ b/src/anbox/protobuf/anbox_bridge.proto @@ -78,6 +78,7 @@ message WindowStateUpdateEvent { required int32 frame_bottom = 7; required int32 task_id = 8; required int32 stack_id = 9; + required bool videoFullscreen = 10; } repeated WindowState windows = 1; repeated WindowState removed_windows = 2; diff --git a/src/anbox/wm/manager.h b/src/anbox/wm/manager.h index 133539c4c4ba16891979bb35e86aaf75e663963a..c6963fab7962dad5862a8b6503617917e70d1013 100644 --- a/src/anbox/wm/manager.h +++ b/src/anbox/wm/manager.h @@ -41,10 +41,12 @@ class Manager { virtual void remove_task(const Task::Id &task) = 0; virtual void insert_task(const Task::Id &task, std::shared_ptr pt) = 0; virtual void erase_task(const Task::Id &task) = 0; + virtual std::shared_ptr update_toast_window(const anbox::graphics::Rect &rect) = 0; virtual std::string get_title(const std::string &package_name) = 0; // FIXME only applies for the multi-window case virtual std::shared_ptr find_window_for_task(const Task::Id &task) = 0; + virtual void set_toast_window(std::shared_ptr tw) = 0; }; } // namespace wm } // namespace anbox diff --git a/src/anbox/wm/multi_window_manager.cpp b/src/anbox/wm/multi_window_manager.cpp index 013c6ec1eb375811cf5ac8b9833aac705b91873b..e223741084a4f4c78db33ed4473a11e910dad359 100755 --- a/src/anbox/wm/multi_window_manager.cpp +++ b/src/anbox/wm/multi_window_manager.cpp @@ -44,7 +44,7 @@ void MultiWindowManager::apply_window_state_update(const WindowState::List &upda for (const auto &window : updated) { // Ignore all windows which are not part of the freeform task stack - if (window.stack() != Stack::Id::Freeform) continue; + if (window.stack() != Stack::Id::Freeform && window.stack() != Stack::Id::Fullscreen) continue; // And also those which don't have a surface mapped at the moment if (!window.has_surface()) continue; @@ -150,5 +150,29 @@ std::string MultiWindowManager::get_title(const std::string &package_name) { return package_name; } } + +std::shared_ptr MultiWindowManager::update_toast_window(const anbox::graphics::Rect &rect) { + auto stack = wm::Stack::Id::Freeform; + if (rect == graphics::Rect(0, 0, 0, 0)) { + stack = wm::Stack::Id::Default; + } + auto update_window = wm::WindowState{ + wm::Display::Id{0}, + true, + rect, + "", + wm::Task::Id{0}, + stack, + }; + if (toast_window_) { + toast_window_->update_state({update_window}); + } + return toast_window_; +} + +void MultiWindowManager::set_toast_window(std::shared_ptr tw) { + toast_window_ = tw; +} + } // namespace wm } // namespace anbox diff --git a/src/anbox/wm/multi_window_manager.h b/src/anbox/wm/multi_window_manager.h index 4bbb0dcdf180b7c65b448c20f17f46d2b328bb3a..1031816ddb2fa7234595a30db57b50d1c6fb434a 100755 --- a/src/anbox/wm/multi_window_manager.h +++ b/src/anbox/wm/multi_window_manager.h @@ -53,6 +53,8 @@ class MultiWindowManager : public Manager { void remove_task(const Task::Id &task) override; void insert_task(const Task::Id &task, std::shared_ptr pt) override; void erase_task(const Task::Id &task) override; + std::shared_ptr update_toast_window(const anbox::graphics::Rect &rect) override; + void set_toast_window(std::shared_ptr tw) override; std::string get_title(const std::string &package_name) override; private: @@ -61,6 +63,7 @@ class MultiWindowManager : public Manager { std::shared_ptr android_api_stub_; std::shared_ptr app_db_; std::map> windows_; + std::shared_ptr toast_window_; }; } // namespace wm } // namespace anbox diff --git a/src/anbox/wm/single_window_manager.cpp b/src/anbox/wm/single_window_manager.cpp index 1e644abe1f8c878c085ed635581290d686b7bb88..32d521db9bb435545a7ef3d87e0d14c3e602f926 100644 --- a/src/anbox/wm/single_window_manager.cpp +++ b/src/anbox/wm/single_window_manager.cpp @@ -89,5 +89,15 @@ std::string SingleWindowManager::get_title(const std::string &package_name) { (void)package_name; return ""; } + +std::shared_ptr SingleWindowManager::update_toast_window(const anbox::graphics::Rect &rect) { + (void)rect; + return nullptr; +} + +void SingleWindowManager::set_toast_window(std::shared_ptr tw) { + (void)tw; +} + } // namespace wm } // namespace anbox diff --git a/src/anbox/wm/single_window_manager.h b/src/anbox/wm/single_window_manager.h index c9d7a5566de3b4b7ce0b159191f65cd6c8c89bd2..4857dbbb11e410b56d9159e80fc825539c5b8f4d 100644 --- a/src/anbox/wm/single_window_manager.h +++ b/src/anbox/wm/single_window_manager.h @@ -53,6 +53,8 @@ class SingleWindowManager : public Manager { void insert_task(const Task::Id &task, std::shared_ptr pt) override; void erase_task(const Task::Id &task) override; std::string get_title(const std::string &package_name) override; + std::shared_ptr update_toast_window(const anbox::graphics::Rect &rect) override; + void set_toast_window(std::shared_ptr tw) override; private: std::weak_ptr platform_; diff --git a/src/anbox/wm/window_state.cpp b/src/anbox/wm/window_state.cpp index e35b83ca5354befa09565c72864adaa2e58b37c0..69a1bfead71c4ca91653ce80efd9d73b0cb13cf3 100644 --- a/src/anbox/wm/window_state.cpp +++ b/src/anbox/wm/window_state.cpp @@ -30,13 +30,15 @@ WindowState::WindowState() WindowState::WindowState(const Display::Id &display, bool has_surface, const graphics::Rect &frame, const std::string &package_name, const Task::Id &task, - const Stack::Id &stack) + const Stack::Id &stack, + const bool videofullscreen) : display_(display), has_surface_(has_surface), frame_(frame), package_name_(package_name), task_(task), - stack_(stack) {} + stack_(stack), + videofullscreen_(videofullscreen) {} WindowState::~WindowState() {} } // namespace wm diff --git a/src/anbox/wm/window_state.h b/src/anbox/wm/window_state.h index ca24b8d5d80179eff4d1db880420fb89f73dbb2d..a6b1c3d0058191b862b71e1a459a494978918534 100644 --- a/src/anbox/wm/window_state.h +++ b/src/anbox/wm/window_state.h @@ -35,11 +35,12 @@ class WindowState { WindowState(); WindowState(const Display::Id &display, bool has_surface, const graphics::Rect &frame, const std::string &package_name, - const Task::Id &task, const Stack::Id &stack); + const Task::Id &task, const Stack::Id &stack, const bool videofullscreen = false); ~WindowState(); Display::Id display() const { return display_; } bool has_surface() const { return has_surface_; } + bool videofullscreen() const { return videofullscreen_; } graphics::Rect frame() const { return frame_; } std::string package_name() const { return package_name_; } Task::Id task() const { return task_; } @@ -52,6 +53,7 @@ class WindowState { std::string package_name_; Task::Id task_; Stack::Id stack_; + bool videofullscreen_; }; } // namespace wm } // namespace anbox