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.
This commit is contained in:
Simon Fels 2018-05-18 13:47:16 +02:00
commit bdc2a24f88
6 changed files with 112 additions and 9 deletions

View file

@ -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

View file

@ -0,0 +1,30 @@
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#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<unsigned int>(current_density()) / static_cast<unsigned int>(DensityType::medium);
}
} // namespace graphics
} // namespace anbox

View file

@ -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

View file

@ -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 <boost/throw_exception.hpp>
@ -25,6 +26,14 @@
#include <mir_toolkit/mir_client_library.h>
#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> &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> &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<Window*>(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;

View file

@ -62,6 +62,11 @@ class Window : public std::enable_shared_from_this<Window>, 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> observer_;
EGLNativeDisplayType native_display_;

View file

@ -35,10 +35,8 @@ void BootPropertiesMessageProcessor::handle_command(
void BootPropertiesMessageProcessor::list_properties() {
std::vector<std::string> 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<int>(graphics::DensityType::medium)),
// device we're running on
utils::string_format("ro.sf.lcd_density=%d", static_cast<int>(graphics::current_density())),
};
for (const auto &prop : properties) {