LCOV - code coverage report
Current view: top level - xenolith/platform/linux - XLPlatformLinuxWaylandView.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 644 0.0 %
Date: 2024-04-26 09:30:07 Functions: 0 46 0.0 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       3             : 
       4             :  Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  of this software and associated documentation files (the "Software"), to deal
       6             :  in the Software without restriction, including without limitation the rights
       7             :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             :  copies of the Software, and to permit persons to whom the Software is
       9             :  furnished to do so, subject to the following conditions:
      10             : 
      11             :  The above copyright notice and this permission notice shall be included in
      12             :  all copies or substantial portions of the Software.
      13             : 
      14             :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      20             :  THE SOFTWARE.
      21             :  **/
      22             : 
      23             : #include "XLPlatformLinuxWaylandView.h"
      24             : 
      25             : #include <linux/input.h>
      26             : 
      27             : #ifndef XL_WAYLAND_LOG
      28             : #if XL_WAYLAND_DEBUG
      29             : #define XL_WAYLAND_LOG(...) log::debug("Wayland", __VA_ARGS__)
      30             : #else
      31             : #define XL_WAYLAND_LOG(...)
      32             : #endif
      33             : #endif
      34             : 
      35             : namespace STAPPLER_VERSIONIZED stappler::xenolith::platform {
      36             : 
      37             : static struct wl_surface_listener s_WaylandSurfaceListener{
      38           0 :         [] (void *data, wl_surface *surface, wl_output *output) {
      39           0 :                 ((WaylandView *)data)->handleSurfaceEnter(surface, output);
      40           0 :         },
      41           0 :         [] (void *data, wl_surface *surface, wl_output *output) {
      42           0 :                 ((WaylandView *)data)->handleSurfaceLeave(surface, output);
      43           0 :         },
      44             : };
      45             : 
      46             : static const wl_callback_listener s_WaylandSurfaceFrameListener{
      47           0 :         [] (void *data, wl_callback *wl_callback, uint32_t callback_data) {
      48           0 :                 ((WaylandView *)data)->handleSurfaceFrameDone(wl_callback, callback_data);
      49           0 :         },
      50             : };
      51             : 
      52             : static xdg_surface_listener const s_XdgSurfaceListener{
      53           0 :         [] (void *data, xdg_surface *xdg_surface, uint32_t serial) {
      54           0 :                 ((WaylandView *)data)->handleSurfaceConfigure(xdg_surface, serial);
      55           0 :         },
      56             : };
      57             : 
      58             : static const xdg_toplevel_listener s_XdgToplevelListener{
      59           0 :         [] (void *data, xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, wl_array *states) {
      60           0 :                 ((WaylandView *)data)->handleToplevelConfigure(xdg_toplevel, width, height, states);
      61           0 :         },
      62           0 :         [] (void* data, struct xdg_toplevel* xdg_toplevel) {
      63           0 :                 ((WaylandView *)data)->handleToplevelClose(xdg_toplevel);
      64           0 :         },
      65           0 :         [] (void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height) {
      66           0 :                 ((WaylandView *)data)->handleToplevelBounds(xdg_toplevel, width, height);
      67           0 :         }
      68             : };
      69             : 
      70           0 : WaylandView::WaylandView(WaylandLibrary *lib, ViewInterface *view, StringView name, StringView bundleName, URect rect) {
      71           0 :         _display = Rc<WaylandDisplay>::create(lib);
      72             : 
      73           0 :         _view = view;
      74           0 :         _currentExtent = Extent2(rect.width, rect.height);
      75             : 
      76           0 :         _surface = _display->createSurface(this);
      77           0 :         if (_surface) {
      78           0 :                 _display->wayland->wl_surface_set_user_data(_surface, this);
      79           0 :                 _display->wayland->wl_surface_add_listener(_surface, &s_WaylandSurfaceListener, this);
      80             : 
      81           0 :                 auto region = _display->wayland->wl_compositor_create_region(_display->compositor);
      82           0 :                 _display->wayland->wl_region_add(region, 0, 0, _currentExtent.width, _currentExtent.height);
      83           0 :                 _display->wayland->wl_surface_set_opaque_region(_surface, region);
      84             : 
      85           0 :                 _xdgSurface = _display->wayland->xdg_wm_base_get_xdg_surface(_display->xdgWmBase, _surface);
      86             : 
      87           0 :                 _display->wayland->xdg_surface_add_listener(_xdgSurface, &s_XdgSurfaceListener, this);
      88           0 :                 _toplevel = _display->wayland->xdg_surface_get_toplevel(_xdgSurface);
      89           0 :                 _display->wayland->xdg_toplevel_set_title(_toplevel, name.data());
      90           0 :                 _display->wayland->xdg_toplevel_set_app_id(_toplevel, bundleName.data());
      91           0 :                 _display->wayland->xdg_toplevel_add_listener(_toplevel, &s_XdgToplevelListener, this);
      92             : 
      93           0 :                 if (_clientSizeDecoration) {
      94           0 :                         createDecorations();
      95             :                 }
      96             : 
      97           0 :                 _display->wayland->wl_surface_commit(_surface);
      98           0 :                 _display->wayland->wl_region_destroy(region);
      99             :         }
     100             : 
     101           0 :         uint32_t rate = 60000;
     102           0 :         for (auto &it : _display->outputs) {
     103           0 :                 rate = std::max(rate, uint32_t(it->mode.refresh));
     104             :         }
     105           0 :         _screenFrameInterval = 1'000'000'000ULL / rate;
     106           0 : }
     107             : 
     108           0 : WaylandView::~WaylandView() {
     109           0 :         _iconMaximized = nullptr;
     110           0 :         _decors.clear();
     111           0 :         if (_toplevel) {
     112           0 :                 _display->wayland->xdg_toplevel_destroy(_toplevel);
     113           0 :                 _toplevel = nullptr;
     114             :         }
     115           0 :         if (_xdgSurface) {
     116           0 :                 _display->wayland->xdg_surface_destroy(_xdgSurface);
     117           0 :                 _xdgSurface = nullptr;
     118             :         }
     119           0 :         if (_surface) {
     120           0 :                 _display->destroySurface(_surface);
     121           0 :                 _surface = nullptr;
     122             :         }
     123           0 :         _display = nullptr;
     124           0 : }
     125             : 
     126           0 : bool WaylandView::poll(bool frameReady) {
     127           0 :         if (_shouldClose) {
     128           0 :                 return false;
     129             :         }
     130             : 
     131           0 :         if (_display->seatDirty) {
     132           0 :                 _display->seat->update();
     133             :         }
     134             : 
     135           0 :         if (frameReady && ((_continuousRendering && _state.test(XDG_TOPLEVEL_STATE_ACTIVATED))  || _scheduleNext)) {
     136           0 :                 auto frame = _display->wayland->wl_surface_frame(_surface);
     137           0 :                 _display->wayland->wl_callback_add_listener(frame, &s_WaylandSurfaceFrameListener, this);
     138           0 :                 _display->wayland->wl_surface_commit(_surface);
     139           0 :                 _scheduleNext = false;
     140             :         }
     141             : 
     142           0 :         _display->flush();
     143             : 
     144           0 :         if (!_shouldClose) {
     145           0 :                 if (!_keys.empty()) {
     146           0 :                         handleKeyRepeat();
     147             :                 }
     148             :         }
     149             : 
     150           0 :         return !_shouldClose;
     151             : }
     152             : 
     153           0 : int WaylandView::getSocketFd() const {
     154           0 :         return _display->getSocketFd();
     155             : }
     156             : 
     157           0 : uint64_t WaylandView::getScreenFrameInterval() const {
     158             :         // On Wayland, limit on full interval causes vblank miss due Mailbox implementation, so, limit on half-interval
     159             :         // Mailbox do appropriate sync even without specified frame interval, it's just a little help for engine
     160           0 :         return _screenFrameInterval /*/ 2*/;
     161             : }
     162             : 
     163           0 : void WaylandView::mapWindow() {
     164           0 :         _display->flush();
     165           0 : }
     166             : 
     167           0 : void WaylandView::handleSurfaceEnter(wl_surface *surface, wl_output *output) {
     168           0 :         if (!_display->wayland->ownsProxy(output)) {
     169           0 :                 return;
     170             :         }
     171             : 
     172           0 :         auto out = (WaylandOutput *)_display->wayland->wl_output_get_user_data(output);
     173           0 :         if (out) {
     174           0 :                 _activeOutputs.emplace(out);
     175             :                 XL_WAYLAND_LOG("handleSurfaceEnter: output: ", out->description());
     176             :         }
     177             : }
     178             : 
     179           0 : void WaylandView::handleSurfaceLeave(wl_surface *surface, wl_output *output) {
     180           0 :         if (!_display->wayland->ownsProxy(output)) {
     181           0 :                 return;
     182             :         }
     183             : 
     184           0 :         auto out = (WaylandOutput *)_display->wayland->wl_output_get_user_data(output);
     185           0 :         if (out) {
     186           0 :                 _activeOutputs.erase(out);
     187             :                 XL_WAYLAND_LOG("handleSurfaceLeave: output: ", out->description());
     188             :         }
     189             : }
     190             : 
     191           0 : void WaylandView::handleSurfaceConfigure(xdg_surface *surface, uint32_t serial) {
     192             :         XL_WAYLAND_LOG("handleSurfaceConfigure: serial: ", serial);
     193           0 :         _configureSerial = serial;
     194           0 : }
     195             : 
     196           0 : void WaylandView::handleToplevelConfigure(xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, wl_array *states) {
     197           0 :         StringStream stream;
     198           0 :         stream << "handleToplevelConfigure: width: " << width << ", height: " << height << ";";
     199             : 
     200           0 :         auto oldState = _state;
     201           0 :         _state.reset();
     202             : 
     203           0 :         for (uint32_t *it = (uint32_t *)states->data; (const char *)it < ((const char *) states->data + states->size); ++ it) {
     204           0 :                 _state.set(*it);
     205           0 :                 switch (*it) {
     206           0 :                 case XDG_TOPLEVEL_STATE_MAXIMIZED: stream << " MAXIMIZED;"; break;
     207           0 :                 case XDG_TOPLEVEL_STATE_FULLSCREEN: stream << " FULLSCREEN;"; break;
     208           0 :                 case XDG_TOPLEVEL_STATE_RESIZING: stream << " RESIZING;"; break;
     209           0 :                 case XDG_TOPLEVEL_STATE_ACTIVATED: stream << " ACTIVATED;"; break;
     210           0 :                 case XDG_TOPLEVEL_STATE_TILED_LEFT: stream << " TILED_LEFT;"; break;
     211           0 :                 case XDG_TOPLEVEL_STATE_TILED_RIGHT: stream << " TILED_RIGHT;"; break;
     212           0 :                 case XDG_TOPLEVEL_STATE_TILED_TOP: stream << " TILED_TOP;"; break;
     213           0 :                 case XDG_TOPLEVEL_STATE_TILED_BOTTOM: stream << " TILED_BOTTOM;"; break;
     214             :                 }
     215             :         }
     216             : 
     217           0 :         if (_state.test(XDG_TOPLEVEL_STATE_ACTIVATED) != oldState.test(XDG_TOPLEVEL_STATE_ACTIVATED)) {
     218           0 :                 _view->handleInputEvent(core::InputEventData::BoolEvent(core::InputEventName::FocusGain, _state.test(XDG_TOPLEVEL_STATE_ACTIVATED)));
     219             :         }
     220             : 
     221           0 :         if (width && height) {
     222           0 :                 if (_currentExtent.width != uint32_t(width) || _currentExtent.height != uint32_t(height)) {
     223           0 :                         _currentExtent.width = width;
     224           0 :                         _currentExtent.height = height - DecorOffset - DecorInset;
     225           0 :                         _view->deprecateSwapchain();
     226             : 
     227           0 :                         stream << "surface: " << _currentExtent.width << " " << _currentExtent.height;
     228             :                 }
     229             :         }
     230             : 
     231           0 :         auto checkVisible = [&, this] (WaylandDecorationName name) {
     232           0 :                 switch (name) {
     233           0 :                 case WaylandDecorationName::RightSide:
     234           0 :                         if (_state.test(XDG_TOPLEVEL_STATE_MAXIMIZED)) { return false; }
     235           0 :                         if (_state.test(XDG_TOPLEVEL_STATE_TILED_RIGHT)) { return false; }
     236           0 :                         break;
     237           0 :                 case WaylandDecorationName::TopRigntCorner:
     238           0 :                         if (_state.test(XDG_TOPLEVEL_STATE_MAXIMIZED)) { return false; }
     239           0 :                         if (_state.test(XDG_TOPLEVEL_STATE_TILED_TOP) && _state.test(XDG_TOPLEVEL_STATE_TILED_RIGHT)) { return false; }
     240           0 :                         break;
     241           0 :                 case WaylandDecorationName::TopSide:
     242           0 :                         if (_state.test(XDG_TOPLEVEL_STATE_MAXIMIZED)) { return false; }
     243           0 :                         if (_state.test(XDG_TOPLEVEL_STATE_TILED_TOP)) { return false; }
     244           0 :                         break;
     245           0 :                 case WaylandDecorationName::TopLeftCorner:
     246           0 :                         if (_state.test(XDG_TOPLEVEL_STATE_MAXIMIZED)) { return false; }
     247           0 :                         if (_state.test(XDG_TOPLEVEL_STATE_TILED_TOP) && _state.test(XDG_TOPLEVEL_STATE_TILED_LEFT)) { return false; }
     248           0 :                         break;
     249           0 :                 case WaylandDecorationName::BottomRightCorner:
     250           0 :                         if (_state.test(XDG_TOPLEVEL_STATE_MAXIMIZED)) { return false; }
     251           0 :                         if (_state.test(XDG_TOPLEVEL_STATE_TILED_BOTTOM) && _state.test(XDG_TOPLEVEL_STATE_TILED_RIGHT)) { return false; }
     252           0 :                         break;
     253           0 :                 case WaylandDecorationName::BottomSide:
     254           0 :                         if (_state.test(XDG_TOPLEVEL_STATE_MAXIMIZED)) { return false; }
     255           0 :                         if (_state.test(XDG_TOPLEVEL_STATE_TILED_BOTTOM)) { return false; }
     256           0 :                         break;
     257           0 :                 case WaylandDecorationName::BottomLeftCorner:
     258           0 :                         if (_state.test(XDG_TOPLEVEL_STATE_MAXIMIZED)) { return false; }
     259           0 :                         if (_state.test(XDG_TOPLEVEL_STATE_TILED_BOTTOM) && _state.test(XDG_TOPLEVEL_STATE_TILED_LEFT)) { return false; }
     260           0 :                         break;
     261           0 :                 case WaylandDecorationName::LeftSide:
     262           0 :                         if (_state.test(XDG_TOPLEVEL_STATE_MAXIMIZED)) { return false; }
     263           0 :                         if (_state.test(XDG_TOPLEVEL_STATE_TILED_LEFT)) { return false; }
     264           0 :                         break;
     265           0 :                 default:
     266           0 :                         break;
     267             :                 }
     268           0 :                 return true;
     269           0 :         };
     270             : 
     271           0 :         for (auto &it : _decors) {
     272           0 :                 it->setActive(_state.test(XDG_TOPLEVEL_STATE_ACTIVATED));
     273           0 :                 it->setVisible(checkVisible(it->name));
     274             :         }
     275             : 
     276             :         XL_WAYLAND_LOG(stream.str());
     277           0 : }
     278             : 
     279           0 : void WaylandView::handleToplevelClose(xdg_toplevel *xdg_toplevel) {
     280             :         XL_WAYLAND_LOG("handleToplevelClose");
     281           0 :         _shouldClose = true;
     282           0 : }
     283             : 
     284           0 : void WaylandView::handleToplevelBounds(xdg_toplevel *xdg_toplevel, int32_t width, int32_t height) {
     285             :         XL_WAYLAND_LOG("handleToplevelBounds: width: ", width, ", height: ", height);
     286           0 : }
     287             : 
     288           0 : void WaylandView::handleSurfaceFrameDone(wl_callback *frame, uint32_t data) {
     289           0 :         _display->wayland->wl_callback_destroy(frame);
     290           0 : }
     291             : 
     292           0 : void WaylandView::handlePointerEnter(wl_fixed_t surface_x, wl_fixed_t surface_y) {
     293           0 :         if (!_pointerInit || _display->seat->hasPointerFrames) {
     294           0 :                 auto &ev = _pointerEvents.emplace_back(PointerEvent{ PointerEvent::Enter });
     295           0 :                 ev.enter.x = surface_x;
     296           0 :                 ev.enter.y = surface_y;
     297             :         } else {
     298           0 :                 _view->handleInputEvent(core::InputEventData::BoolEvent(core::InputEventName::PointerEnter, true,
     299           0 :                                 Vec2(float(wl_fixed_to_double(surface_x)), float(_currentExtent.height - wl_fixed_to_double(surface_y)))));
     300             : 
     301           0 :                 _surfaceX = wl_fixed_to_double(surface_x);
     302           0 :                 _surfaceY = wl_fixed_to_double(surface_y);
     303             :         }
     304             : 
     305             :         XL_WAYLAND_LOG("handlePointerEnter: x: ", wl_fixed_to_int(surface_x), ", y: ", wl_fixed_to_int(surface_y));
     306           0 : }
     307             : 
     308           0 : void WaylandView::handlePointerLeave() {
     309           0 :         if (!_pointerInit) {
     310           0 :                 _pointerInit = true;
     311           0 :                 if (!_display->seat->hasPointerFrames) {
     312           0 :                         handlePointerFrame();
     313             :                 }
     314             :         }
     315             : 
     316           0 :         handlePointerFrame(); // drop pending events
     317           0 :         _view->handleInputEvent(core::InputEventData::BoolEvent(core::InputEventName::PointerEnter, false,
     318           0 :                         Vec2(float(_surfaceX), float(_currentExtent.height - _surfaceY))));
     319           0 : }
     320             : 
     321           0 : void WaylandView::handlePointerMotion(uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
     322             :         // XL_WAYLAND_LOG("handlePointerMotion: x: ", wl_fixed_to_int(surface_x), ", y: ", wl_fixed_to_int(surface_y));
     323             : 
     324           0 :         if (!_pointerInit) {
     325           0 :                 _pointerInit = true;
     326           0 :                 if (!_display->seat->hasPointerFrames) {
     327           0 :                         handlePointerFrame();
     328             :                 }
     329             :         }
     330             : 
     331           0 :         if (_display->seat->hasPointerFrames) {
     332           0 :                 auto &ev = _pointerEvents.emplace_back(PointerEvent{ PointerEvent::Motion });
     333           0 :                 ev.motion.time = time;
     334           0 :                 ev.motion.x = surface_x;
     335           0 :                 ev.motion.y = surface_y;
     336             :         } else {
     337           0 :                 _view->handleInputEvent(core::InputEventData({
     338             :                         maxOf<uint32_t>(),
     339             :                         core::InputEventName::MouseMove,
     340             :                         core::InputMouseButton::None,
     341           0 :                         _activeModifiers,
     342           0 :                         float(wl_fixed_to_double(surface_x)),
     343           0 :                         float(_currentExtent.height - wl_fixed_to_double(surface_y))
     344             :                 }));
     345             : 
     346           0 :                 _surfaceX = wl_fixed_to_double(surface_x);
     347           0 :                 _surfaceY = wl_fixed_to_double(surface_y);
     348             :         }
     349           0 : }
     350             : 
     351           0 : static core::InputMouseButton getButton(uint32_t button) {
     352           0 :         switch (button) {
     353           0 :         case BTN_LEFT: return core::InputMouseButton::MouseLeft; break;
     354           0 :         case BTN_RIGHT: return core::InputMouseButton::MouseRight; break;
     355           0 :         case BTN_MIDDLE: return core::InputMouseButton::MouseMiddle; break;
     356           0 :         default:
     357           0 :                 return core::InputMouseButton(toInt(core::InputMouseButton::Mouse8) + (button - 0x113));
     358             :                 break;
     359             :         }
     360             :         return core::InputMouseButton::None;
     361             : }
     362             : 
     363           0 : void WaylandView::handlePointerButton(uint32_t serial, uint32_t time, uint32_t button, uint32_t state) {
     364           0 :         if (!_pointerInit) {
     365           0 :                 return;
     366             :         }
     367             : 
     368             :         XL_WAYLAND_LOG("handlePointerButton");
     369           0 :         if (_display->seat->hasPointerFrames) {
     370           0 :                 auto &ev = _pointerEvents.emplace_back(PointerEvent{ PointerEvent::Button });
     371           0 :                 ev.button.serial = serial;
     372           0 :                 ev.button.time = time;
     373           0 :                 ev.button.button = button;
     374           0 :                 ev.button.state = state;
     375             :         } else {
     376           0 :                 _view->handleInputEvent(core::InputEventData({
     377             :                         button,
     378           0 :                         ((state == WL_POINTER_BUTTON_STATE_PRESSED) ? core::InputEventName::Begin : core::InputEventName::End),
     379           0 :                         getButton(button),
     380           0 :                         _activeModifiers,
     381           0 :                         float(_surfaceX),
     382           0 :                         float(_currentExtent.height - _surfaceY)
     383             :                 }));
     384             :         }
     385             : }
     386             : 
     387           0 : void WaylandView::handlePointerAxis(uint32_t time, uint32_t axis, wl_fixed_t value) {
     388           0 :         if (!_pointerInit) {
     389           0 :                 return;
     390             :         }
     391             : 
     392           0 :         if (_display->seat->hasPointerFrames) {
     393           0 :                 auto &ev = _pointerEvents.emplace_back(PointerEvent{ PointerEvent::Axis });
     394           0 :                 ev.axis.time = time;
     395           0 :                 ev.axis.axis = axis;
     396           0 :                 ev.axis.value = value;
     397             :         } else {
     398           0 :                 core::InputMouseButton btn = core::InputMouseButton::None;
     399           0 :                 auto val = wl_fixed_to_int(value);
     400           0 :                 switch (axis) {
     401           0 :                 case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
     402           0 :                         if (val < 0) {
     403           0 :                                 btn = core::InputMouseButton::MouseScrollUp;
     404             :                         } else {
     405           0 :                                 btn = core::InputMouseButton::MouseScrollDown;
     406             :                         }
     407           0 :                         break;
     408           0 :                 case WL_POINTER_AXIS_VERTICAL_SCROLL:
     409           0 :                         if (val > 0) {
     410           0 :                                 btn = core::InputMouseButton::MouseScrollRight;
     411             :                         } else {
     412           0 :                                 btn = core::InputMouseButton::MouseScrollLeft;
     413             :                         }
     414           0 :                         break;
     415             :                 }
     416             : 
     417           0 :                 core::InputEventData event({
     418           0 :                         toInt(btn),
     419             :                         core::InputEventName::Scroll,
     420             :                         btn,
     421           0 :                         _activeModifiers,
     422           0 :                         float(_surfaceX),
     423           0 :                         float(_currentExtent.height - _surfaceY)
     424           0 :                 });
     425             : 
     426           0 :                 switch (axis) {
     427           0 :                 case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
     428           0 :                         event.point.valueX = float(wl_fixed_to_double(value));
     429           0 :                         event.point.valueY = 0.0f;
     430           0 :                         break;
     431           0 :                 case WL_POINTER_AXIS_VERTICAL_SCROLL:
     432           0 :                         event.point.valueX = 0.0f;
     433           0 :                         event.point.valueY = -float(wl_fixed_to_double(value));
     434           0 :                         break;
     435             :                 }
     436             : 
     437           0 :                 _view->handleInputEvent(event);
     438             :         }
     439             : }
     440             : 
     441           0 : void WaylandView::handlePointerAxisSource(uint32_t axis_source) {
     442           0 :         if (!_pointerInit) {
     443           0 :                 return;
     444             :         }
     445             : 
     446           0 :         auto &ev = _pointerEvents.emplace_back(PointerEvent{ PointerEvent::AxisSource });
     447           0 :         ev.axisSource.axis_source = axis_source;
     448             : }
     449             : 
     450           0 : void WaylandView::handlePointerAxisStop(uint32_t time, uint32_t axis) {
     451           0 :         if (!_pointerInit) {
     452           0 :                 return;
     453             :         }
     454             : 
     455           0 :         auto &ev = _pointerEvents.emplace_back(PointerEvent{ PointerEvent::AxisStop });
     456           0 :         ev.axisStop.time = time;
     457           0 :         ev.axisStop.axis = axis;
     458             : }
     459             : 
     460           0 : void WaylandView::handlePointerAxisDiscrete(uint32_t axis, int32_t discrete) {
     461           0 :         if (!_pointerInit) {
     462           0 :                 return;
     463             :         }
     464             : 
     465           0 :         auto &ev = _pointerEvents.emplace_back(PointerEvent{ PointerEvent::AxisDiscrete });
     466           0 :         ev.axisDiscrete.axis = axis;
     467           0 :         ev.axisDiscrete.discrete = discrete;
     468             : }
     469             : 
     470           0 : void WaylandView::handlePointerFrame() {
     471           0 :         if (!_pointerInit || _pointerEvents.empty()) {
     472           0 :                 return;
     473             :         }
     474             : 
     475           0 :         Vector<core::InputEventData> inputEvents;
     476             : 
     477           0 :         bool positionChanged = false;
     478           0 :         double x = 0.0f;
     479           0 :         double y = 0.0f;
     480             : 
     481           0 :         core::InputMouseButton axisBtn = core::InputMouseButton::None;
     482           0 :         uint32_t axisSource = 0;
     483           0 :         bool hasAxis = false;
     484           0 :         double axisX = 0.0f;
     485           0 :         double axisY = 0.0f;
     486             : 
     487           0 :         for (auto &it : _pointerEvents) {
     488           0 :                 switch (it.event) {
     489           0 :                 case PointerEvent::None: break;
     490           0 :                 case PointerEvent::Enter:
     491           0 :                         inputEvents.emplace_back(core::InputEventData::BoolEvent(core::InputEventName::PointerEnter, true,
     492           0 :                                         Vec2(float(wl_fixed_to_double(it.enter.x)), float(_currentExtent.height - wl_fixed_to_double(it.enter.y)))));
     493           0 :                         positionChanged = true;
     494           0 :                         x = wl_fixed_to_double(it.enter.x);
     495           0 :                         y = wl_fixed_to_double(it.enter.y);
     496           0 :                         break;
     497           0 :                 case PointerEvent::Leave:
     498           0 :                         break;
     499           0 :                 case PointerEvent::Motion:
     500           0 :                         positionChanged = true;
     501           0 :                         x = wl_fixed_to_double(it.motion.x);
     502           0 :                         y = wl_fixed_to_double(it.motion.y);
     503           0 :                         break;
     504           0 :                 case PointerEvent::Button:
     505           0 :                         break;
     506           0 :                 case PointerEvent::Axis:
     507           0 :                         switch (it.axis.axis) {
     508           0 :                         case WL_POINTER_AXIS_VERTICAL_SCROLL:
     509           0 :                                 hasAxis = true;
     510           0 :                                 axisY -= wl_fixed_to_double(it.axis.value);
     511           0 :                                 if (wl_fixed_to_int(it.axis.value) < 0) {
     512           0 :                                         axisBtn = core::InputMouseButton::MouseScrollUp;
     513             :                                 } else {
     514           0 :                                         axisBtn = core::InputMouseButton::MouseScrollDown;
     515             :                                 }
     516           0 :                                 break;
     517           0 :                         case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
     518           0 :                                 hasAxis = true;
     519           0 :                                 axisX += wl_fixed_to_double(it.axis.value);
     520           0 :                                 if (wl_fixed_to_int(it.axis.value) > 0) {
     521           0 :                                         axisBtn = core::InputMouseButton::MouseScrollRight;
     522             :                                 } else {
     523           0 :                                         axisBtn = core::InputMouseButton::MouseScrollLeft;
     524             :                                 }
     525           0 :                                 break;
     526           0 :                         default: break;
     527             :                         }
     528           0 :                         break;
     529           0 :                 case PointerEvent::AxisSource:
     530           0 :                         axisSource = it.axisSource.axis_source;
     531           0 :                         break;
     532           0 :                 case PointerEvent::AxisStop:
     533           0 :                         break;
     534           0 :                 case PointerEvent::AxisDiscrete:
     535           0 :                         break;
     536             :                 }
     537             :         }
     538             : 
     539           0 :         if (positionChanged) {
     540           0 :                 inputEvents.emplace_back(core::InputEventData({
     541             :                         maxOf<uint32_t>(),
     542             :                         core::InputEventName::MouseMove,
     543             :                         core::InputMouseButton::None,
     544           0 :                         _activeModifiers,
     545           0 :                         float(x),
     546           0 :                         float(_currentExtent.height - y)
     547             :                 }));
     548             : 
     549           0 :                 _surfaceX = x;
     550           0 :                 _surfaceY = y;
     551             :         }
     552             : 
     553           0 :         if (hasAxis) {
     554           0 :                 auto &event = inputEvents.emplace_back(core::InputEventData({
     555             :                         axisSource,
     556             :                         core::InputEventName::Scroll,
     557             :                         axisBtn,
     558           0 :                         _activeModifiers,
     559           0 :                         float(_surfaceX),
     560           0 :                         float(_currentExtent.height - _surfaceY)
     561             :                 }));
     562             : 
     563           0 :                 event.point.valueX = float(axisX);
     564           0 :                 event.point.valueY = float(axisY);
     565             :         }
     566             : 
     567           0 :         for (auto &it : _pointerEvents) {
     568           0 :                 switch (it.event) {
     569           0 :                 case PointerEvent::None: break;
     570           0 :                 case PointerEvent::Enter: break;
     571           0 :                 case PointerEvent::Leave:
     572           0 :                         inputEvents.emplace_back(core::InputEventData::BoolEvent(core::InputEventName::PointerEnter, false,
     573           0 :                                         Vec2(float(_surfaceX), float(_currentExtent.height - _surfaceY))));
     574           0 :                         break;
     575           0 :                 case PointerEvent::Motion: break;
     576           0 :                 case PointerEvent::Button:
     577           0 :                         inputEvents.emplace_back(core::InputEventData({
     578           0 :                                 it.button.button,
     579           0 :                                 ((it.button.state == WL_POINTER_BUTTON_STATE_PRESSED) ? core::InputEventName::Begin : core::InputEventName::End),
     580           0 :                                 getButton(it.button.button),
     581           0 :                                 _activeModifiers,
     582           0 :                                 float(_surfaceX),
     583           0 :                                 float(_currentExtent.height - _surfaceY)
     584             :                         }));
     585           0 :                         break;
     586           0 :                 case PointerEvent::Axis: break;
     587           0 :                 case PointerEvent::AxisSource: break;
     588           0 :                 case PointerEvent::AxisStop: break;
     589           0 :                 case PointerEvent::AxisDiscrete: break;
     590             :                 }
     591             :         }
     592             : 
     593           0 :         if (!inputEvents.empty()) {
     594           0 :                 _view->handleInputEvents(move(inputEvents));
     595             :         }
     596           0 :         _pointerEvents.clear();
     597           0 : }
     598             : 
     599           0 : void WaylandView::handleKeyboardEnter(Vector<uint32_t> &&keys, uint32_t depressed, uint32_t latched, uint32_t locked) {
     600           0 :         handleKeyModifiers(depressed, latched, locked);
     601           0 :         uint32_t n = 1;
     602           0 :         for (auto &it : keys) {
     603           0 :                 handleKey(n, it, WL_KEYBOARD_KEY_STATE_PRESSED);
     604           0 :                 ++ n;
     605             :         }
     606           0 : }
     607             : 
     608           0 : void WaylandView::handleKeyboardLeave() {
     609           0 :         Vector<core::InputEventData> events;
     610           0 :         uint32_t n = 1;
     611           0 :         for (auto &it : _keys) {
     612           0 :                 core::InputEventData event({
     613             :                         n,
     614             :                         core::InputEventName::KeyCanceled,
     615             :                         core::InputMouseButton::None,
     616           0 :                         _activeModifiers,
     617           0 :                         float(_surfaceX),
     618           0 :                         float(_currentExtent.height - _surfaceY)
     619           0 :                 });
     620             : 
     621           0 :                 event.key.keycode = _display->seat->translateKey(it.second.scancode);
     622           0 :                 event.key.keysym = it.second.scancode;
     623           0 :                 event.key.keychar = it.second.codepoint;
     624             : 
     625           0 :                 events.emplace_back(move(event));
     626             : 
     627           0 :                 ++ n;
     628             :         }
     629             : 
     630           0 :         if (!events.empty()) {
     631           0 :                 _view->handleInputEvents(move(events));
     632             :         }
     633           0 : }
     634             : 
     635           0 : void WaylandView::handleKey(uint32_t time, uint32_t scancode, uint32_t state) {
     636           0 :         core::InputEventData event({
     637             :                 time,
     638           0 :                 (state == WL_KEYBOARD_KEY_STATE_PRESSED) ? core::InputEventName::KeyPressed : core::InputEventName::KeyReleased,
     639             :                                 core::InputMouseButton::None,
     640           0 :                 _activeModifiers,
     641           0 :                 float(_surfaceX),
     642           0 :                 float(_currentExtent.height - _surfaceY)
     643           0 :         });
     644             : 
     645           0 :         event.key.keycode = _display->seat->translateKey(scancode);
     646           0 :         event.key.compose = core::InputKeyComposeState::Nothing;
     647           0 :         event.key.keysym = scancode;
     648           0 :         event.key.keychar = 0;
     649             : 
     650           0 :         const xkb_keysym_t *keysyms = nullptr;
     651           0 :         const xkb_keycode_t keycode = scancode + 8;
     652             : 
     653           0 :         if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
     654           0 :                 char32_t codepoint = 0;
     655           0 :                 if (_display->xkb && _view->isInputEnabled()) {
     656           0 :                         if (_display->xkb->xkb_state_key_get_syms(_display->seat->state, keycode, &keysyms) == 1) {
     657           0 :                                 const xkb_keysym_t keysym = _display->seat->composeSymbol(keysyms[0], event.key.compose);
     658           0 :                                 const uint32_t cp = _display->xkb->xkb_keysym_to_utf32(keysym);
     659           0 :                                 if (cp != 0 && keysym != XKB_KEY_NoSymbol) {
     660           0 :                                         codepoint = cp;
     661             :                                 }
     662             :                         }
     663             :                 }
     664             : 
     665           0 :                 auto it = _keys.emplace(scancode, KeyData{
     666             :                         scancode,
     667             :                         codepoint,
     668           0 :                         platform::clock(core::ClockType::Monotonic),
     669             :                         false
     670           0 :                 }).first;
     671             : 
     672           0 :                 if (_display->xkb && _display->xkb->xkb_keymap_key_repeats(
     673           0 :                                 _display->xkb->xkb_state_get_keymap(_display->seat->state), keycode)) {
     674           0 :                         it->second.repeats = true;
     675             :                 }
     676             :         } else {
     677           0 :                 auto it = _keys.find(scancode);
     678           0 :                 if (it == _keys.end()) {
     679           0 :                         return;
     680             :                 }
     681             : 
     682           0 :                 event.key.keychar = it->second.codepoint;
     683           0 :                 _keys.erase(it);
     684             :         }
     685             : 
     686           0 :         _view->handleInputEvent(move(event));
     687             : }
     688             : 
     689           0 : void WaylandView::handleKeyModifiers(uint32_t depressed, uint32_t latched, uint32_t locked) {
     690           0 :         if (!_display->seat->state) {
     691           0 :                 return;
     692             :         }
     693             : 
     694           0 :         _activeModifiers = core::InputModifier::None;
     695           0 :         if (_display->xkb->xkb_state_mod_index_is_active(_display->seat->state,
     696           0 :                         _display->seat->keyState.controlIndex, XKB_STATE_MODS_EFFECTIVE) == 1) {
     697           0 :                 _activeModifiers |= core::InputModifier::Ctrl;
     698             :         }
     699             : 
     700           0 :         if (_display->xkb->xkb_state_mod_index_is_active(_display->seat->state,
     701           0 :                         _display->seat->keyState.altIndex, XKB_STATE_MODS_EFFECTIVE) == 1) {
     702           0 :                 _activeModifiers |= core::InputModifier::Alt;
     703             :         }
     704             : 
     705           0 :         if (_display->xkb->xkb_state_mod_index_is_active(_display->seat->state,
     706           0 :                         _display->seat->keyState.shiftIndex, XKB_STATE_MODS_EFFECTIVE) == 1) {
     707           0 :                 _activeModifiers |= core::InputModifier::Shift;
     708             :         }
     709             : 
     710           0 :         if (_display->xkb->xkb_state_mod_index_is_active(_display->seat->state,
     711           0 :                         _display->seat->keyState.superIndex, XKB_STATE_MODS_EFFECTIVE) == 1) {
     712           0 :                 _activeModifiers |= core::InputModifier::Mod4;
     713             :         }
     714             : 
     715           0 :         if (_display->xkb->xkb_state_mod_index_is_active(_display->seat->state,
     716           0 :                         _display->seat->keyState.capsLockIndex, XKB_STATE_MODS_EFFECTIVE) == 1) {
     717           0 :                 _activeModifiers |= core::InputModifier::CapsLock;
     718             :         }
     719             : 
     720           0 :         if (_display->xkb->xkb_state_mod_index_is_active(_display->seat->state,
     721           0 :                         _display->seat->keyState.numLockIndex, XKB_STATE_MODS_EFFECTIVE) == 1) {
     722           0 :                 _activeModifiers |= core::InputModifier::NumLock;
     723             :         }
     724             : }
     725             : 
     726           0 : void WaylandView::handleKeyRepeat() {
     727           0 :         Vector<core::InputEventData> events;
     728           0 :         auto spawnRepeatEvent = [&, this] (const KeyData &it) {
     729           0 :                 core::InputEventData event({
     730           0 :                         uint32_t(events.size() + 1),
     731             :                         core::InputEventName::KeyRepeated,
     732             :                         core::InputMouseButton::None,
     733           0 :                         _activeModifiers,
     734           0 :                         float(_surfaceX),
     735           0 :                         float(_currentExtent.height - _surfaceY)
     736           0 :                 });
     737             : 
     738           0 :                 event.key.keycode = _display->seat->translateKey(it.scancode);
     739           0 :                 event.key.keysym = it.scancode;
     740           0 :                 event.key.keychar = it.codepoint;
     741             : 
     742           0 :                 events.emplace_back(move(event));
     743           0 :         };
     744             : 
     745           0 :         uint64_t repeatDelay = _display->seat->keyState.keyRepeatDelay;
     746           0 :         uint64_t repeatInterval = _display->seat->keyState.keyRepeatInterval;
     747           0 :         auto t = platform::clock(core::ClockType::Monotonic);
     748           0 :         for (auto &it : _keys) {
     749           0 :                 if (it.second.repeats) {
     750           0 :                         if (!it.second.lastRepeat) {
     751           0 :                                 auto dt = t - it.second.time;
     752           0 :                                 if (dt > repeatDelay * 1000) {
     753           0 :                                         dt -= repeatDelay * 1000;
     754           0 :                                         it.second.lastRepeat = t - dt;
     755             :                                 }
     756             :                         }
     757           0 :                         if (it.second.lastRepeat) {
     758           0 :                                 auto dt = t - it.second.lastRepeat;
     759           0 :                                 while (dt > repeatInterval) {
     760           0 :                                         spawnRepeatEvent(it.second);
     761           0 :                                         dt -= repeatInterval;
     762           0 :                                         it.second.lastRepeat += repeatInterval;
     763             :                                 }
     764             :                         }
     765             :                 }
     766             :         }
     767             : 
     768           0 :         if (!events.empty()) {
     769           0 :                 _view->handleInputEvents(move(events));
     770             :         }
     771           0 : }
     772             : 
     773           0 : void WaylandView::handleDecorationPress(WaylandDecoration *decor, uint32_t serial, bool released) {
     774           0 :         auto switchMaximized = [&, this] {
     775           0 :                 if (!_state.test(XDG_TOPLEVEL_STATE_MAXIMIZED)) {
     776           0 :                         _display->wayland->xdg_toplevel_set_maximized(_toplevel);
     777           0 :                         _iconMaximized->setAlternative(true);
     778             :                 } else {
     779           0 :                         _display->wayland->xdg_toplevel_unset_maximized(_toplevel);
     780           0 :                         _iconMaximized->setAlternative(false);
     781             :                 }
     782           0 :         };
     783           0 :         switch (decor->name) {
     784           0 :         case WaylandDecorationName::IconClose:
     785           0 :                 _shouldClose = true;
     786           0 :                 return;
     787             :                 break;
     788           0 :         case WaylandDecorationName::IconMaximize:
     789           0 :                 switchMaximized();
     790           0 :                 return;
     791             :                 break;
     792           0 :         case WaylandDecorationName::IconMinimize:
     793           0 :                 _display->wayland->xdg_toplevel_set_minimized(_toplevel);
     794           0 :                 return;
     795           0 :         default:
     796           0 :                 break;
     797             :         }
     798           0 :         uint32_t edges = 0;
     799           0 :         switch (decor->image) {
     800           0 :         case WaylandCursorImage::RightSide: edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; break;
     801           0 :         case WaylandCursorImage::TopRigntCorner: edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; break;
     802           0 :         case WaylandCursorImage::TopSide: edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP; break;
     803           0 :         case WaylandCursorImage::TopLeftCorner: edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; break;
     804           0 :         case WaylandCursorImage::BottomRightCorner: edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT; break;
     805           0 :         case WaylandCursorImage::BottomSide: edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM; break;
     806           0 :         case WaylandCursorImage::BottomLeftCorner: edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT; break;
     807           0 :         case WaylandCursorImage::LeftSide: edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT; break;
     808           0 :         case WaylandCursorImage::LeftPtr:
     809           0 :                 if (released) {
     810           0 :                         switchMaximized();
     811           0 :                         return;
     812             :                 }
     813           0 :                 break;
     814           0 :         case WaylandCursorImage::Max:
     815           0 :                 break;
     816             :         }
     817             : 
     818           0 :         if (edges != 0) {
     819           0 :                 _display->wayland->xdg_toplevel_resize(_toplevel, _display->seat->seat, serial, edges);
     820             :         } else {
     821           0 :                 _display->wayland->xdg_toplevel_move(_toplevel, _display->seat->seat, serial);
     822             :         }
     823             : }
     824             : 
     825           0 : void WaylandView::scheduleFrame() {
     826           0 :         _scheduleNext = true;
     827           0 : }
     828             : 
     829           0 : void WaylandView::onSurfaceInfo(core::SurfaceInfo &info) const {
     830           0 :         info.currentExtent = _currentExtent;
     831           0 : }
     832             : 
     833           0 : void WaylandView::createDecorations() {
     834           0 :         if (!_display->viewporter || !_clientSizeDecoration) {
     835           0 :                 return;
     836             :         }
     837             : 
     838           0 :         WaylandShm::ShadowBuffers buf;
     839           0 :         if (!_display->shm->allocateDecorations(&buf, DecorWidth, DecorInset, Color::Grey_100, Color::Grey_200)) {
     840           0 :                 return;
     841             :         }
     842             : 
     843           0 :         _decors.emplace_back(Rc<WaylandDecoration>::create(this, move(buf.top), move(buf.topActive), WaylandDecorationName::TopSide));
     844           0 :         _decors.emplace_back(Rc<WaylandDecoration>::create(this, move(buf.bottom), move(buf.bottomActive), WaylandDecorationName::BottomSide));
     845           0 :         _decors.emplace_back(Rc<WaylandDecoration>::create(this, move(buf.left), move(buf.leftActive), WaylandDecorationName::LeftSide));
     846           0 :         _decors.emplace_back(Rc<WaylandDecoration>::create(this, move(buf.right), move(buf.rightActive), WaylandDecorationName::RightSide));
     847           0 :         _decors.emplace_back(Rc<WaylandDecoration>::create(this, move(buf.topLeft), move(buf.topLeftActive), WaylandDecorationName::TopLeftCorner));
     848           0 :         _decors.emplace_back(Rc<WaylandDecoration>::create(this, move(buf.topRight), move(buf.topRightActive), WaylandDecorationName::TopRigntCorner));
     849           0 :         _decors.emplace_back(Rc<WaylandDecoration>::create(this, move(buf.bottomLeft), move(buf.bottomLeftActive), WaylandDecorationName::BottomLeftCorner));
     850           0 :         _decors.emplace_back(Rc<WaylandDecoration>::create(this, move(buf.bottomRight), move(buf.bottomRightActive), WaylandDecorationName::BottomRightCorner));
     851           0 :         _decors.emplace_back(Rc<WaylandDecoration>::create(this, move(buf.headerLeft), move(buf.headerLeftActive), WaylandDecorationName::HeaderLeft));
     852           0 :         _decors.emplace_back(Rc<WaylandDecoration>::create(this, move(buf.headerRight), move(buf.headerRightActive), WaylandDecorationName::HeaderRight));
     853           0 :         _decors.emplace_back(Rc<WaylandDecoration>::create(this, Rc<WaylandBuffer>(buf.headerCenter), Rc<WaylandBuffer>(buf.headerCenterActive), WaylandDecorationName::HeaderCenter));
     854           0 :         _decors.emplace_back(Rc<WaylandDecoration>::create(this, Rc<WaylandBuffer>(buf.headerCenter), Rc<WaylandBuffer>(buf.headerCenterActive), WaylandDecorationName::HeaderBottom));
     855           0 :         _decors.emplace_back(Rc<WaylandDecoration>::create(this, move(buf.iconClose), move(buf.iconCloseActive), WaylandDecorationName::IconClose));
     856           0 :         _iconMaximized = _decors.emplace_back(Rc<WaylandDecoration>::create(this, move(buf.iconMaximize), move(buf.iconMaximizeActive), WaylandDecorationName::IconMaximize));
     857           0 :         _iconMaximized->setAltBuffers(move(buf.iconRestore), move(buf.iconRestoreActive));
     858             : 
     859           0 :         _decors.emplace_back(Rc<WaylandDecoration>::create(this, move(buf.iconMinimize), move(buf.iconMinimizeActive), WaylandDecorationName::IconMinimize));
     860           0 : }
     861             : 
     862           0 : void WaylandView::commit(uint32_t width, uint32_t height) {
     863           0 :         bool dirty = _commitedExtent.width != width || _commitedExtent.height != height || _configureSerial != maxOf<uint32_t>();
     864             : 
     865           0 :         if (!dirty) {
     866           0 :                 for (auto &it : _decors) {
     867           0 :                         if (it->dirty) {
     868           0 :                                 dirty = true;
     869           0 :                                 break;
     870             :                         }
     871             :                 }
     872             :         }
     873             : 
     874           0 :         if (!dirty) {
     875           0 :                 return;
     876             :         }
     877             : 
     878           0 :         StringStream stream;
     879           0 :         stream << "commit: " << width << " " << height << ";";
     880           0 :         if (_configureSerial != maxOf<uint32_t>()) {
     881           0 :                 _display->wayland->xdg_toplevel_set_min_size(_toplevel, DecorWidth * 2 + IconSize * 3, DecorWidth * 2  + DecorOffset);
     882           0 :                 _display->wayland->xdg_surface_set_window_geometry(_xdgSurface, 0, -DecorInset - DecorOffset,
     883           0 :                                 width, height + DecorInset + DecorOffset);
     884             : 
     885           0 :                 _display->wayland->xdg_surface_ack_configure(_xdgSurface, _configureSerial);
     886           0 :                 stream << " configure: " << _configureSerial << ";";
     887           0 :                 _configureSerial = maxOf<uint32_t>();
     888             :         }
     889             : 
     890           0 :         _commitedExtent.width = width;
     891           0 :         _commitedExtent.height = height;
     892             : 
     893           0 :         auto insetWidth = _commitedExtent.width - DecorInset * 2;
     894           0 :         auto insetHeight = _commitedExtent.height - DecorInset;
     895           0 :         auto cornerSize = DecorWidth + DecorInset;
     896             : 
     897           0 :         for (auto &it : _decors) {
     898           0 :                 switch (it->name) {
     899           0 :                 case WaylandDecorationName::TopSide:
     900           0 :                         it->setGeometry(DecorInset, - DecorWidth - DecorInset, insetWidth, DecorWidth);
     901           0 :                         break;
     902           0 :                 case WaylandDecorationName::BottomSide:
     903           0 :                         it->setGeometry(DecorInset, _commitedExtent.height, insetWidth, DecorWidth);
     904           0 :                         break;
     905           0 :                 case WaylandDecorationName::LeftSide:
     906           0 :                         it->setGeometry(- DecorWidth, 0, DecorWidth, insetHeight);
     907           0 :                         break;
     908           0 :                 case WaylandDecorationName::RightSide:
     909           0 :                         it->setGeometry(_commitedExtent.width, 0, DecorWidth, insetHeight);
     910           0 :                         break;
     911           0 :                 case WaylandDecorationName::TopLeftCorner:
     912           0 :                         it->setGeometry(- DecorWidth, - DecorWidth - DecorInset, cornerSize, cornerSize);
     913           0 :                         break;
     914           0 :                 case WaylandDecorationName::TopRigntCorner:
     915           0 :                         it->setGeometry(_commitedExtent.width - DecorInset, - DecorWidth - DecorInset, cornerSize, cornerSize);
     916           0 :                         break;
     917           0 :                 case WaylandDecorationName::BottomLeftCorner:
     918           0 :                         it->setGeometry(- DecorWidth, _commitedExtent.height - DecorInset, cornerSize, cornerSize);
     919           0 :                         break;
     920           0 :                 case WaylandDecorationName::BottomRightCorner:
     921           0 :                         it->setGeometry(_commitedExtent.width - DecorInset, _commitedExtent.height - DecorInset, cornerSize, cornerSize);
     922           0 :                         break;
     923           0 :                 case WaylandDecorationName::HeaderLeft:
     924           0 :                         it->setGeometry(0, - DecorInset - DecorOffset, DecorInset, DecorInset);
     925           0 :                         break;
     926           0 :                 case WaylandDecorationName::HeaderRight:
     927           0 :                         it->setGeometry(_commitedExtent.width - DecorInset, - DecorInset - DecorOffset, DecorInset, DecorInset);
     928           0 :                         break;
     929           0 :                 case WaylandDecorationName::HeaderCenter:
     930           0 :                         it->setGeometry(DecorInset, - DecorInset - DecorOffset, _commitedExtent.width - DecorInset * 2, DecorInset);
     931           0 :                         break;
     932           0 :                 case WaylandDecorationName::HeaderBottom:
     933           0 :                         it->setGeometry(0, - DecorOffset, _commitedExtent.width, DecorOffset);
     934           0 :                         break;
     935           0 :                 case WaylandDecorationName::IconClose:
     936           0 :                         it->setGeometry(_commitedExtent.width - (IconSize + 4), -IconSize, IconSize, IconSize);
     937           0 :                         break;
     938           0 :                 case WaylandDecorationName::IconMaximize:
     939           0 :                         it->setGeometry(_commitedExtent.width - (IconSize + 4) * 2, -IconSize, IconSize, IconSize);
     940           0 :                         break;
     941           0 :                 case WaylandDecorationName::IconMinimize:
     942           0 :                         it->setGeometry(_commitedExtent.width - (IconSize + 4) * 3, -IconSize, IconSize, IconSize);
     943           0 :                         break;
     944           0 :                 default:
     945           0 :                         break;
     946             :                 }
     947             :         }
     948             : 
     949           0 :         bool surfacesDirty = false;
     950           0 :         for (auto &it : _decors) {
     951           0 :                 if (it->commit()) {
     952           0 :                         surfacesDirty = true;
     953             :                 }
     954             :         }
     955           0 :         if (surfacesDirty) {
     956           0 :                 stream << " Surfaces Dirty;";
     957             :         }
     958             : 
     959             :         XL_WAYLAND_LOG(stream.str());
     960           0 : }
     961             : 
     962           0 : void WaylandView::readFromClipboard(Function<void(BytesView, StringView)> &&, Ref *) {
     963             : 
     964           0 : }
     965             : 
     966           0 : void WaylandView::writeToClipboard(BytesView, StringView contentType) {
     967             : 
     968           0 : }
     969             : 
     970             : }

Generated by: LCOV version 1.14