936eba1f2b19f09c0417c87959077dd9bd90b893
[iec.git] / src / type3_AndroidCloud / anbox-master / src / anbox / platform / sdl / window.cpp
1 /*
2  * Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
3  *
4  * This program is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 3, as published
6  * by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranties of
10  * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11  * PURPOSE.  See the GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program.  If not, see <http://www.gnu.org/licenses/>.
15  *
16  */
17
18 #include "anbox/platform/sdl/window.h"
19 #include "anbox/wm/window_state.h"
20 #include "anbox/graphics/density.h"
21 #include "anbox/logger.h"
22
23 #include <boost/throw_exception.hpp>
24
25 #if defined(MIR_SUPPORT)
26 #include <mir_toolkit/mir_client_library.h>
27 #endif
28
29 namespace {
30 constexpr const int window_resize_border{10};
31 constexpr const int top_drag_area{42};
32 constexpr const int button_size{32};
33 constexpr const int button_margin{5};
34 constexpr const int button_padding{0};
35 }
36
37 namespace anbox {
38 namespace platform {
39 namespace sdl {
40 Window::Id Window::Invalid{-1};
41
42 Window::Observer::~Observer() {}
43
44 Window::Window(const std::shared_ptr<Renderer> &renderer,
45                const Id &id, const wm::Task::Id &task,
46                const std::shared_ptr<Observer> &observer,
47                const graphics::Rect &frame,
48                const std::string &title,
49                bool resizable,
50                bool borderless)
51     : wm::Window(renderer, task, frame, title),
52       id_(id),
53       observer_(observer),
54       native_display_(0),
55       native_window_(0) {
56   SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
57
58   // NOTE: We don't furce GL initialization of the window as this will
59   // be take care of by the Renderer when we attach to it. On EGL
60   // initializing GL here will cause a surface to be created and the
61   // renderer will attempt to create one too which will not work as
62   // only a single surface per EGLNativeWindowType is supported.
63   std::uint32_t flags = 0;
64   if (borderless)
65     flags |= SDL_WINDOW_BORDERLESS;
66   if (resizable)
67     flags |= SDL_WINDOW_RESIZABLE;
68
69   window_ = SDL_CreateWindow(title.c_str(),
70                              frame.left(), frame.top(),
71                              frame.width(), frame.height(),
72                              flags);
73   if (!window_) {
74     const auto message = utils::string_format("Failed to create window: %s", SDL_GetError());
75     BOOST_THROW_EXCEPTION(std::runtime_error(message));
76   }
77
78   // If we create a window with border (server-side decoration), We
79   // should not set hit test handler beacuse we don't need to simulate
80   // the behavior of the title bar and resize area.
81   if (borderless && utils::get_env_value("ANBOX_NO_SDL_WINDOW_HIT_TEST", "false") == "false")
82     if (SDL_SetWindowHitTest(window_, &Window::on_window_hit, this) < 0)
83       BOOST_THROW_EXCEPTION(std::runtime_error("Failed to register for window hit test"));
84
85   SDL_SysWMinfo info;
86   SDL_VERSION(&info.version);
87   SDL_GetWindowWMInfo(window_, &info);
88   switch (info.subsystem) {
89 #if defined(X11_SUPPORT)
90     case SDL_SYSWM_X11:
91       native_display_ = static_cast<EGLNativeDisplayType>(info.info.x11.display);
92       native_window_ = static_cast<EGLNativeWindowType>(info.info.x11.window);
93       break;
94 #endif
95 #if defined(WAYLAND_SUPPORT)
96     case SDL_SYSWM_WAYLAND:
97       native_display_ = reinterpret_cast<EGLNativeDisplayType>(info.info.wl.display);
98       native_window_ = reinterpret_cast<EGLNativeWindowType>(info.info.wl.surface);
99       break;
100 #endif
101 #if defined(MIR_SUPPORT)
102     case SDL_SYSWM_MIR: {
103       native_display_ = static_cast<EGLNativeDisplayType>(mir_connection_get_egl_native_display(info.info.mir.connection));
104       auto buffer_stream = mir_surface_get_buffer_stream(info.info.mir.surface);
105       native_window_ = reinterpret_cast<EGLNativeWindowType>(mir_buffer_stream_get_egl_native_window(buffer_stream));
106       break;
107     }
108 #endif
109     default:
110       ERROR("Unknown subsystem (%d)", info.subsystem);
111       BOOST_THROW_EXCEPTION(std::runtime_error("SDL subsystem not supported"));
112   }
113
114   SDL_ShowWindow(window_);
115 }
116
117 Window::~Window() {
118   if (window_) SDL_DestroyWindow(window_);
119 }
120
121 SDL_HitTestResult Window::on_window_hit(SDL_Window *window, const SDL_Point *pt, void *data) {
122   auto platform_window = reinterpret_cast<Window*>(data);
123
124   int w = 0, h = 0;
125   SDL_GetWindowSize(window, &w, &h);
126
127   const auto border_size = graphics::dp_to_pixel(window_resize_border);
128   const auto top_drag_area_height = graphics::dp_to_pixel(top_drag_area);
129   const auto button_area_width = graphics::dp_to_pixel(button_size + button_padding * 2 + button_margin * 2);
130   const auto flags = SDL_GetWindowFlags(window);
131
132   if (flags & SDL_WINDOW_FULLSCREEN)
133       return SDL_HITTEST_NORMAL;
134
135   if (!(flags & SDL_WINDOW_RESIZABLE)) {
136     if (pt->y < border_size)
137       return SDL_HITTEST_DRAGGABLE;
138     else
139       return SDL_HITTEST_NORMAL;
140   }
141
142   if (pt->y < top_drag_area_height) {
143     if (pt->x > w - button_area_width && pt->x < w) {
144       platform_window->close();
145       return SDL_HITTEST_NORMAL;
146     } else if (pt->x > w - button_area_width * 2 && pt->x < w - button_area_width) {
147       platform_window->switch_window_state();
148       return SDL_HITTEST_NORMAL;
149     }
150     return SDL_HITTEST_DRAGGABLE;
151   }
152
153   if (flags & SDL_WINDOW_MAXIMIZED)
154     return SDL_HITTEST_NORMAL;
155
156   if (pt->x < border_size && pt->y < border_size)
157       return SDL_HITTEST_RESIZE_TOPLEFT;
158   else if (pt->x > border_size && pt->x < w - border_size && pt->y < border_size)
159       return SDL_HITTEST_RESIZE_TOP;
160   else if (pt->x > w - border_size && pt->y < border_size)
161       return SDL_HITTEST_RESIZE_TOPRIGHT;
162   else if (pt->x > w - border_size && pt->y > border_size && pt->y < h - border_size)
163       return SDL_HITTEST_RESIZE_RIGHT;
164   else if (pt->x > w - border_size && pt->y > h - border_size)
165       return SDL_HITTEST_RESIZE_BOTTOMRIGHT;
166   else if (pt->x < w - border_size && pt->x > border_size && pt->y > h - border_size)
167       return SDL_HITTEST_RESIZE_BOTTOM;
168   else if (pt->x < border_size && pt->y > h - border_size)
169       return SDL_HITTEST_RESIZE_BOTTOMLEFT;
170   else if (pt->x < border_size && pt->y < h - border_size && pt->y > border_size)
171       return SDL_HITTEST_RESIZE_LEFT;
172
173   return SDL_HITTEST_NORMAL;
174 }
175
176 void Window::close() {
177   if (observer_)
178     observer_->window_deleted(id_);
179 }
180
181 void Window::switch_window_state() {
182   const auto flags = SDL_GetWindowFlags(window_);
183   if (flags & SDL_WINDOW_MAXIMIZED)
184     SDL_RestoreWindow(window_);
185   else
186     SDL_MaximizeWindow(window_);
187 }
188
189 void Window::process_event(const SDL_Event &event) {
190   switch (event.window.event) {
191     case SDL_WINDOWEVENT_FOCUS_GAINED:
192       if (observer_) observer_->window_wants_focus(id_);
193       break;
194     case SDL_WINDOWEVENT_FOCUS_LOST:
195       break;
196     // Not need to listen for SDL_WINDOWEVENT_RESIZED here as the
197     // SDL_WINDOWEVENT_SIZE_CHANGED is always sent.
198     case SDL_WINDOWEVENT_SIZE_CHANGED:
199       if (observer_)
200         observer_->window_resized(id_, event.window.data1, event.window.data2);
201       break;
202     case SDL_WINDOWEVENT_MOVED:
203       if (observer_)
204         observer_->window_moved(id_, event.window.data1, event.window.data2);
205       break;
206     case SDL_WINDOWEVENT_SHOWN:
207       break;
208     case SDL_WINDOWEVENT_HIDDEN:
209       break;
210     case SDL_WINDOWEVENT_CLOSE:
211       close();
212       break;
213     default:
214       break;
215   }
216 }
217
218 EGLNativeWindowType Window::native_handle() const { return native_window_; }
219
220 Window::Id Window::id() const { return id_; }
221
222 std::uint32_t Window::window_id() const { return SDL_GetWindowID(window_); }
223 } // namespace sdl
224 } // namespace platform
225 } // namespace anbox