From bdc2a24f88a232181d75467ac06cd6d9c3b9aa41 Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Fri, 18 May 2018 13:47:16 +0200 Subject: [PATCH] Add support for client side decorations This implements client side window decorations of our windows. The title bar of our windows is now drawn by Android and we simply map out the title bar area hit test area to SDL to detect when the other wants to move the window or resize it. --- src/CMakeLists.txt | 1 + src/anbox/graphics/density.cpp | 30 ++++++++ src/anbox/graphics/density.h | 3 + src/anbox/platform/sdl/window.cpp | 76 +++++++++++++++++-- src/anbox/platform/sdl/window.h | 5 ++ .../boot_properties_message_processor.cpp | 6 +- 6 files changed, 112 insertions(+), 9 deletions(-) create mode 100644 src/anbox/graphics/density.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3e2817b..82b130c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -126,6 +126,7 @@ set(SOURCES anbox/graphics/buffer_queue.cpp anbox/graphics/buffered_io_stream.cpp anbox/graphics/gl_renderer_server.cpp + anbox/graphics/density.cpp anbox/graphics/density.h anbox/graphics/rect.cpp anbox/graphics/layer_composer.cpp diff --git a/src/anbox/graphics/density.cpp b/src/anbox/graphics/density.cpp new file mode 100644 index 0000000..3ce2bf7 --- /dev/null +++ b/src/anbox/graphics/density.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "anbox/graphics/density.h" + +namespace anbox { +namespace graphics { +DensityType current_density() { + return DensityType::medium; +} + +int dp_to_pixel(unsigned int dp) { + return dp * static_cast(current_density()) / static_cast(DensityType::medium); +} +} // namespace graphics +} // namespace anbox diff --git a/src/anbox/graphics/density.h b/src/anbox/graphics/density.h index 4338dc4..f662caa 100644 --- a/src/anbox/graphics/density.h +++ b/src/anbox/graphics/density.h @@ -35,6 +35,9 @@ enum class DensityType { xhigh = 360, xxhigh = 480, }; + +DensityType current_density(); +int dp_to_pixel(unsigned int dp); } // namespace graphics } // namespace anbox diff --git a/src/anbox/platform/sdl/window.cpp b/src/anbox/platform/sdl/window.cpp index 1343d5b..8bb5c26 100644 --- a/src/anbox/platform/sdl/window.cpp +++ b/src/anbox/platform/sdl/window.cpp @@ -16,8 +16,9 @@ */ #include "anbox/platform/sdl/window.h" -#include "anbox/logger.h" #include "anbox/wm/window_state.h" +#include "anbox/graphics/density.h" +#include "anbox/logger.h" #include @@ -25,6 +26,14 @@ #include #endif +namespace { +constexpr const int window_resize_border{30}; +constexpr const int top_drag_area{50}; +constexpr const int button_size{32}; +constexpr const int button_margin{5}; +constexpr const int button_padding{4}; +} + namespace anbox { namespace platform { namespace sdl { @@ -43,15 +52,14 @@ Window::Window(const std::shared_ptr &renderer, observer_(observer), native_display_(0), native_window_(0) { - - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); // NOTE: We don't furce GL initialization of the window as this will // be take care of by the Renderer when we attach to it. On EGL // initializing GL here will cause a surface to be created and the // renderer will attempt to create one too which will not work as // only a single surface per EGLNativeWindowType is supported. - std::uint32_t flags = 0; + std::uint32_t flags = SDL_WINDOW_BORDERLESS; if (resizable) flags |= SDL_WINDOW_RESIZABLE; @@ -64,6 +72,9 @@ Window::Window(const std::shared_ptr &renderer, BOOST_THROW_EXCEPTION(std::runtime_error(message)); } + if (SDL_SetWindowHitTest(window_, &Window::on_window_hit, this) < 0) + BOOST_THROW_EXCEPTION(std::runtime_error("Failed to register for window hit test")); + SDL_SysWMinfo info; SDL_VERSION(&info.version); SDL_GetWindowWMInfo(window_, &info); @@ -92,6 +103,58 @@ Window::~Window() { if (window_) SDL_DestroyWindow(window_); } +SDL_HitTestResult Window::on_window_hit(SDL_Window *window, const SDL_Point *pt, void *data) { + auto platform_window = reinterpret_cast(data); + + int w = 0, h = 0; + SDL_GetWindowSize(window, &w, &h); + + const auto border_size = graphics::dp_to_pixel(window_resize_border); + const auto top_drag_area_height = graphics::dp_to_pixel(top_drag_area); + const auto button_area_width = graphics::dp_to_pixel(button_size + button_padding * 2 + button_margin * 2); + + if (pt->y < top_drag_area_height) { + if (pt->x > w - button_area_width && pt->x < w) { + platform_window->close(); + return SDL_HITTEST_NORMAL; + } else if (pt->x > w - button_area_width * 2 && pt->x < w - button_area_width) { + platform_window->switch_window_state(); + return SDL_HITTEST_NORMAL; + } + return SDL_HITTEST_DRAGGABLE; + } else if (pt->x < border_size && pt->y < border_size) + return SDL_HITTEST_RESIZE_TOPLEFT; + else if (pt->x > window_resize_border && pt->x < w - border_size && pt->y < border_size) + return SDL_HITTEST_RESIZE_TOP; + else if (pt->x > w - border_size && pt->y < border_size) + return SDL_HITTEST_RESIZE_TOPRIGHT; + else if (pt->x > w - border_size && pt->y > border_size && pt->y < h - border_size) + return SDL_HITTEST_RESIZE_RIGHT; + else if (pt->x > w - border_size && pt->y > h - border_size) + return SDL_HITTEST_RESIZE_BOTTOMRIGHT; + else if (pt->x < w - border_size && pt->x > border_size && pt->y > h - border_size) + return SDL_HITTEST_RESIZE_BOTTOM; + else if (pt->x < border_size && pt->y > h - border_size) + return SDL_HITTEST_RESIZE_BOTTOMLEFT; + else if (pt->x < border_size && pt->y < h - border_size && pt->y > border_size) + return SDL_HITTEST_RESIZE_LEFT; + + return SDL_HITTEST_NORMAL; +} + +void Window::close() { + if (observer_) + observer_->window_deleted(id_); +} + +void Window::switch_window_state() { + const auto flags = SDL_GetWindowFlags(window_); + if (flags & SDL_WINDOW_MAXIMIZED) + SDL_RestoreWindow(window_); + else + SDL_MaximizeWindow(window_); +} + void Window::process_event(const SDL_Event &event) { switch (event.window.event) { case SDL_WINDOWEVENT_FOCUS_GAINED: @@ -114,7 +177,10 @@ void Window::process_event(const SDL_Event &event) { case SDL_WINDOWEVENT_HIDDEN: break; case SDL_WINDOWEVENT_CLOSE: - if (observer_) observer_->window_deleted(id_); + if (observer_) + observer_->window_deleted(id_); + + close(); break; default: break; diff --git a/src/anbox/platform/sdl/window.h b/src/anbox/platform/sdl/window.h index b44a7cb..6849425 100644 --- a/src/anbox/platform/sdl/window.h +++ b/src/anbox/platform/sdl/window.h @@ -62,6 +62,11 @@ class Window : public std::enable_shared_from_this, public wm::Window { std::uint32_t window_id() const; private: + static SDL_HitTestResult on_window_hit(SDL_Window *window, const SDL_Point *pt, void *data); + + void close(); + void switch_window_state(); + Id id_; std::shared_ptr observer_; EGLNativeDisplayType native_display_; diff --git a/src/anbox/qemu/boot_properties_message_processor.cpp b/src/anbox/qemu/boot_properties_message_processor.cpp index 783b568..897bc00 100644 --- a/src/anbox/qemu/boot_properties_message_processor.cpp +++ b/src/anbox/qemu/boot_properties_message_processor.cpp @@ -35,10 +35,8 @@ void BootPropertiesMessageProcessor::handle_command( void BootPropertiesMessageProcessor::list_properties() { std::vector properties = { // TODO(morphis): Using HDPI here for now but should be adjusted to the - // device - // we're running on. - utils::string_format("ro.sf.lcd_density=%d", - static_cast(graphics::DensityType::medium)), + // device we're running on + utils::string_format("ro.sf.lcd_density=%d", static_cast(graphics::current_density())), }; for (const auto &prop : properties) {