diff options
Diffstat (limited to 'src/compositor/wayland_wrapper/qwlshellsurface.cpp')
-rw-r--r-- | src/compositor/wayland_wrapper/qwlshellsurface.cpp | 158 |
1 files changed, 149 insertions, 9 deletions
diff --git a/src/compositor/wayland_wrapper/qwlshellsurface.cpp b/src/compositor/wayland_wrapper/qwlshellsurface.cpp index a1e6bb37..9b61d60b 100644 --- a/src/compositor/wayland_wrapper/qwlshellsurface.cpp +++ b/src/compositor/wayland_wrapper/qwlshellsurface.cpp @@ -65,28 +65,41 @@ void Shell::bind_func(struct wl_client *client, void *data, wl_client_add_object(client,&wl_shell_interface,&shell_interface,id,data); } +ShellSurfacePopupGrabber *Shell::getPopupGrabber(InputDevice *input) +{ + if (!m_popupGrabber.contains(input)) + m_popupGrabber.insert(input, new ShellSurfacePopupGrabber(input)); + + return m_popupGrabber.value(input); +} + void Shell::get_shell_surface(struct wl_client *client, struct wl_resource *shell_resource, uint32_t id, struct wl_resource *surface_super) { - Q_UNUSED(shell_resource); + Shell *shell = static_cast<Shell*>(shell_resource->data); Surface *surface = Surface::fromResource(surface_super); - new ShellSurface(client,id,surface); + new ShellSurface(shell, client, id, surface); } const struct wl_shell_interface Shell::shell_interface = { Shell::get_shell_surface }; -ShellSurface::ShellSurface(wl_client *client, uint32_t id, Surface *surface) +ShellSurface::ShellSurface(Shell *shell, wl_client *client, uint32_t id, Surface *surface) : wl_shell_surface(client, id) + , m_shell(shell) , m_surface(surface) , m_resizeGrabber(0) , m_moveGrabber(0) + , m_popupGrabber(0) , m_transientParent(0) , m_xOffset(0) , m_yOffset(0) + , m_windowType(QWaylandSurface::None) + , m_popupLocation() + , m_popupSerial() { surface->setShellSurface(this); } @@ -96,6 +109,13 @@ void ShellSurface::sendConfigure(uint32_t edges, int32_t width, int32_t height) send_configure(edges, width, height); } +void ShellSurface::ping() +{ + uint32_t serial = wl_display_next_serial(m_surface->compositor()->wl_display()); + m_pings.insert(serial); + send_ping(serial); +} + Surface *ShellSurface::surface() const { return m_surface; @@ -150,8 +170,26 @@ void ShellSurface::setOffset(const QPointF &offset) m_yOffset = offset.y(); } +QWaylandSurface::WindowType ShellSurface::windowType() const +{ + return m_windowType; +} + +void ShellSurface::mapPopup() +{ + if (m_popupGrabber->grabSerial() == m_popupSerial) { + m_popupGrabber->addPopup(this); + } else { + send_popup_done(); + m_popupGrabber->setClient(0); + } +} + void ShellSurface::shell_surface_destroy_resource(Resource *) { + if (m_popupGrabber) + m_popupGrabber->removePopup(this); + delete this; } @@ -209,6 +247,11 @@ void ShellSurface::shell_surface_set_toplevel(Resource *resource) m_xOffset = 0; m_yOffset = 0; + if (m_windowType != QWaylandSurface::Toplevel) { + m_windowType = QWaylandSurface::Toplevel; + emit m_surface->waylandSurface()->windowTypeChanged(m_windowType); + } + if (m_surface->extendedSurface()) m_surface->extendedSurface()->setVisibility(QWindow::Windowed, false); } @@ -229,6 +272,11 @@ void ShellSurface::shell_surface_set_transient(Resource *resource, if (flags & WL_SHELL_SURFACE_TRANSIENT_INACTIVE) surface()->setTransientInactive(true); + if (m_windowType != QWaylandSurface::Transient) { + m_windowType = QWaylandSurface::Transient; + emit m_surface->waylandSurface()->windowTypeChanged(m_windowType); + } + if (m_surface->extendedSurface()) m_surface->extendedSurface()->setVisibility(QWindow::AutomaticVisibility, false); } @@ -249,16 +297,24 @@ void ShellSurface::shell_surface_set_fullscreen(Resource *resource, m_surface->extendedSurface()->setVisibility(QWindow::FullScreen, false); } -void ShellSurface::shell_surface_set_popup(Resource *resource, wl_resource *input_device, uint32_t time, wl_resource *parent, int32_t x, int32_t y, uint32_t flags) +void ShellSurface::shell_surface_set_popup(Resource *resource, wl_resource *input_device, uint32_t serial, wl_resource *parent, int32_t x, int32_t y, uint32_t flags) { Q_UNUSED(resource); Q_UNUSED(input_device); - Q_UNUSED(time); - Q_UNUSED(parent); - Q_UNUSED(x); - Q_UNUSED(y); Q_UNUSED(flags); + InputDevice *input = InputDevice::fromSeatResource(input_device); + m_popupGrabber = m_shell->getPopupGrabber(input); + + m_popupSerial = serial; + m_transientParent = Surface::fromResource(parent)->shellSurface(); + m_popupLocation = QPointF(x, y); + + if (m_windowType != QWaylandSurface::Popup) { + m_windowType = QWaylandSurface::Popup; + emit m_surface->waylandSurface()->windowTypeChanged(m_windowType); + } + if (m_surface->extendedSurface()) m_surface->extendedSurface()->setVisibility(QWindow::AutomaticVisibility, false); } @@ -279,7 +335,10 @@ void ShellSurface::shell_surface_pong(Resource *resource, uint32_t serial) { Q_UNUSED(resource); - Q_UNUSED(serial); + if (m_pings.remove(serial)) + emit m_surface->waylandSurface()->pong(); + else + qWarning("Received an unexpected pong!"); } void ShellSurface::shell_surface_set_title(Resource *resource, @@ -381,6 +440,87 @@ void ShellSurfaceMoveGrabber::button(uint32_t time, Qt::MouseButton button, uint } } +ShellSurfacePopupGrabber::ShellSurfacePopupGrabber(InputDevice *inputDevice) + : PointerGrabber() + , m_inputDevice(inputDevice) + , m_client(0) + , m_surfaces() + , m_initialUp(false) +{ +} + +uint32_t ShellSurfacePopupGrabber::grabSerial() const +{ + return m_inputDevice->pointerDevice()->grabSerial(); +} + +struct ::wl_client *ShellSurfacePopupGrabber::client() const +{ + return m_client; +} + +void ShellSurfacePopupGrabber::setClient(struct ::wl_client *client) +{ + m_client = client; +} + +void ShellSurfacePopupGrabber::addPopup(ShellSurface *surface) +{ + if (m_surfaces.isEmpty()) { + m_client = surface->resource()->client(); + + if (m_inputDevice->pointerDevice()->buttonPressed()) + m_initialUp = false; + + m_surfaces.append(surface); + m_inputDevice->pointerDevice()->startGrab(this); + } else { + m_surfaces.append(surface); + } +} + +void ShellSurfacePopupGrabber::removePopup(ShellSurface *surface) +{ + if (m_surfaces.isEmpty()) + return; + + m_surfaces.removeOne(surface); + if (m_surfaces.isEmpty()) + m_inputDevice->pointerDevice()->endGrab(); +} + +void ShellSurfacePopupGrabber::focus() +{ + if (m_pointer->current() && m_pointer->current()->resource()->client() == m_client) + m_pointer->setFocus(m_pointer->current(), m_pointer->currentPosition()); + else + m_pointer->setFocus(0, QPointF()); +} + +void ShellSurfacePopupGrabber::motion(uint32_t time) +{ + m_pointer->motion(time); +} + +void ShellSurfacePopupGrabber::button(uint32_t time, Qt::MouseButton button, uint32_t state) +{ + if (m_pointer->focusResource()) { + m_pointer->sendButton(time, button, state); + } else if (state == QtWaylandServer::wl_pointer::button_state_pressed && + (m_initialUp || time - m_pointer->grabTime() > 500) && + m_pointer->currentGrab() == this) { + m_pointer->endGrab(); + Q_FOREACH (ShellSurface *surface, m_surfaces) { + surface->send_popup_done(); + } + m_surfaces.clear(); + } + + if (state == QtWaylandServer::wl_pointer::button_state_released) + m_initialUp = true; +} + + } QT_END_NAMESPACE |