diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f5f81f3..1f14c32d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,13 +67,6 @@ set_package_properties(UDev PROPERTIES DESCRIPTION "The UDev Libraries" PURPOSE "Allows support for UPower backend in PowerDevil - STRONGLY RECOMMENDED" ) -macro_optional_find_package(Wayland) -set_package_properties(Wayland PROPERTIES DESCRIPTION "The Wayland Client and Server libraries" - URL "http://wayland.freedesktop.org" - TYPE OPTIONAL - PURPOSE "Required for building KWin with Wayland support" - ) - if(Q_WS_X11) find_package(XCB REQUIRED) set_package_properties(XCB PROPERTIES DESCRIPTION "X protocol C-language Binding" diff --git a/cmake/modules/FindWayland.cmake b/cmake/modules/FindWayland.cmake deleted file mode 100644 index 00c17a3c..00000000 --- a/cmake/modules/FindWayland.cmake +++ /dev/null @@ -1,62 +0,0 @@ -# Try to find Wayland on a Unix system -# -# This will define: -# -# WAYLAND_FOUND - True if Wayland is found -# WAYLAND_LIBRARIES - Link these to use Wayland -# WAYLAND_INCLUDE_DIR - Include directory for Wayland -# WAYLAND_DEFINITIONS - Compiler flags for using Wayland -# -# In addition the following more fine grained variables will be defined: -# -# WAYLAND_CLIENT_FOUND WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES -# WAYLAND_SERVER_FOUND WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES -# WAYLAND_EGL_FOUND WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES -# -# Copyright (c) 2013 Martin Gräßlin -# -# Redistribution and use is allowed according to the terms of the BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. - -IF (NOT WIN32) - IF (WAYLAND_INCLUDE_DIR AND WAYLAND_LIBRARIES) - # In the cache already - SET(WAYLAND_FIND_QUIETLY TRUE) - ENDIF () - - # Use pkg-config to get the directories and then use these values - # in the FIND_PATH() and FIND_LIBRARY() calls - FIND_PACKAGE(PkgConfig) - PKG_CHECK_MODULES(PKG_WAYLAND QUIET wayland-client wayland-server wayland-egl) - - SET(WAYLAND_DEFINITIONS ${PKG_WAYLAND_CFLAGS}) - - FIND_PATH(WAYLAND_CLIENT_INCLUDE_DIR NAMES wayland-client.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) - FIND_PATH(WAYLAND_SERVER_INCLUDE_DIR NAMES wayland-server.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) - FIND_PATH(WAYLAND_EGL_INCLUDE_DIR NAMES wayland-egl.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) - - FIND_LIBRARY(WAYLAND_CLIENT_LIBRARIES NAMES wayland-client HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) - FIND_LIBRARY(WAYLAND_SERVER_LIBRARIES NAMES wayland-server HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) - FIND_LIBRARY(WAYLAND_EGL_LIBRARIES NAMES wayland-egl HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) - - set(WAYLAND_INCLUDE_DIR ${WAYLAND_CLIENT_INCLUDE_DIR} ${WAYLAND_SERVER_INCLUDE_DIR} ${WAYLAND_EGL_INCLUDE_DIR}) - - set(WAYLAND_LIBRARIES ${WAYLAND_CLIENT_LIBRARIES} ${WAYLAND_SERVER_LIBRARIES} ${WAYLAND_EGL_LIBRARIES}) - - list(REMOVE_DUPLICATES WAYLAND_INCLUDE_DIR) - - include(FindPackageHandleStandardArgs) - - FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_CLIENT DEFAULT_MSG WAYLAND_CLIENT_LIBRARIES WAYLAND_CLIENT_INCLUDE_DIR) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_SERVER DEFAULT_MSG WAYLAND_SERVER_LIBRARIES WAYLAND_SERVER_INCLUDE_DIR) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_EGL DEFAULT_MSG WAYLAND_EGL_LIBRARIES WAYLAND_EGL_INCLUDE_DIR) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND DEFAULT_MSG WAYLAND_LIBRARIES WAYLAND_INCLUDE_DIR) - - MARK_AS_ADVANCED( - WAYLAND_INCLUDE_DIR WAYLAND_LIBRARIES - WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES - WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES - WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES - ) - -ENDIF () diff --git a/config-workspace.h.cmake b/config-workspace.h.cmake index b3ba37d5..4a2dcbf4 100644 --- a/config-workspace.h.cmake +++ b/config-workspace.h.cmake @@ -119,9 +119,6 @@ /* Define to 1 if you have the `vsnprintf' function. */ #cmakedefine HAVE_VSNPRINTF 1 -/* Define to 1 if you have the Wayland libraries. */ -#cmakedefine WAYLAND_FOUND 1 - /* KDE's default home directory */ #cmakedefine KDE_DEFAULT_HOME "${KDE_DEFAULT_HOME}" diff --git a/kwin/CMakeLists.txt b/kwin/CMakeLists.txt index 3bb84778..5a1c2a74 100644 --- a/kwin/CMakeLists.txt +++ b/kwin/CMakeLists.txt @@ -50,10 +50,6 @@ endif() include_directories(${XCB_INCLUDE_DIR}) -if(WAYLAND_FOUND AND KWIN_HAVE_EGL) - include_directories(${WAYLAND_INCLUDE_DIR}) -endif() - # for things that are also used by kwin libraries configure_file(libkwineffects/kwinconfig.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/libkwineffects/kwinconfig.h ) # for kwin internal things @@ -168,10 +164,6 @@ if(KWIN_HAVE_EGL) set(kwin_KDEINIT_SRCS ${kwin_KDEINIT_SRCS} eglonxbackend.cpp) endif() -if(WAYLAND_FOUND AND KWIN_HAVE_EGL) - set(kwin_KDEINIT_SRCS ${kwin_KDEINIT_SRCS} egl_wayland_backend.cpp) -endif() - kde4_add_kcfg_files(kwin_KDEINIT_SRCS settings.kcfgc) qt4_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.KWin.xml dbusinterface.h KWin::DBusInterface ) @@ -227,13 +219,6 @@ set(kwin_XCB_LIBS ${XCB_KEYSYMS_LIBRARIES} ) -set(kwin_WAYLAND_LIBS - ${WAYLAND_CLIENT_LIBRARIES} - ${WAYLAND_EGL_LIBRARIES} - ${XCB_SHM_LIBRARIES} - ${XCB_XTEST_LIBRARIES} -) - set(kwin_OPENGL_LIBS ) find_library(XF86VM_LIBRARY Xxf86vm) @@ -256,10 +241,6 @@ set(kwinLibs ${kwin_OPENGL_LIBS} ) -if(WAYLAND_FOUND AND KWIN_HAVE_EGL) - set(kwinLibs ${kwinLibs} ${kwin_WAYLAND_LIBS}) -endif() - kde4_add_kdeinit_executable( kwin ${kwin_KDEINIT_SRCS}) target_link_libraries(kdeinit_kwin ${kwinLibs}) diff --git a/kwin/egl_wayland_backend.cpp b/kwin/egl_wayland_backend.cpp deleted file mode 100644 index cd4dd9d9..00000000 --- a/kwin/egl_wayland_backend.cpp +++ /dev/null @@ -1,1007 +0,0 @@ -/******************************************************************** - KWin - the KDE window manager - This file is part of the KDE project. - -Copyright (C) 2013 Martin Gräßlin - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY 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 . -*********************************************************************/ -#define WL_EGL_PLATFORM 1 -#include "egl_wayland_backend.h" -// kwin -#include "cursor.h" -#include "options.h" -// kwin libs -#include -// KDE -#include -#include -// Qt -#include -// xcb -#include -// Wayland -#include -// system -#include -#include -#include -#include -#include - -namespace KWin -{ - -namespace Wayland -{ - -/** - * Callback for announcing global objects in the registry - **/ -static void registryHandleGlobal(void *data, struct wl_registry *registry, - uint32_t name, const char *interface, uint32_t version) -{ - Q_UNUSED(version) - WaylandBackend *d = reinterpret_cast(data); - - if (strcmp(interface, "wl_compositor") == 0) { - d->setCompositor(reinterpret_cast(wl_registry_bind(registry, name, &wl_compositor_interface, 1))); - } else if (strcmp(interface, "wl_shell") == 0) { - d->setShell(reinterpret_cast(wl_registry_bind(registry, name, &wl_shell_interface, 1))); - } else if (strcmp(interface, "wl_seat") == 0) { - d->createSeat(name); - } else if (strcmp(interface, "wl_shm") == 0) { - d->createShm(name); - } - kDebug(1212) << "Wayland Interface: " << interface; -} - -/** - * Callback for removal of global objects in the registry - **/ -static void registryHandleGlobalRemove(void *data, struct wl_registry *registry, uint32_t name) -{ - Q_UNUSED(data) - Q_UNUSED(registry) - Q_UNUSED(name) - // TODO: implement me -} - -/** - * Call back for ping from Wayland Shell. - **/ -static void handlePing(void *data, struct wl_shell_surface *shellSurface, uint32_t serial) -{ - Q_UNUSED(shellSurface); - reinterpret_cast(data)->ping(serial); -} - -/** - * Callback for a configure request for a shell surface - **/ -static void handleConfigure(void *data, struct wl_shell_surface *shellSurface, uint32_t edges, int32_t width, int32_t height) -{ - Q_UNUSED(shellSurface) - Q_UNUSED(edges) - WaylandBackend *display = reinterpret_cast(data); - wl_egl_window_resize(display->overlay(), width, height, 0, 0); - // TODO: this information should probably go into Screens -} - -/** - * Callback for popups - not needed, we don't have popups - **/ -static void handlePopupDone(void *data, struct wl_shell_surface *shellSurface) -{ - Q_UNUSED(data) - Q_UNUSED(shellSurface) -} - -static void seatHandleCapabilities(void *data, wl_seat *seat, uint32_t capabilities) -{ - WaylandSeat *s = reinterpret_cast(data); - if (seat != s->seat()) { - return; - } - s->changed(capabilities); -} - -static void pointerHandleEnter(void *data, wl_pointer *pointer, uint32_t serial, wl_surface *surface, - wl_fixed_t sx, wl_fixed_t sy) -{ - Q_UNUSED(data) - Q_UNUSED(pointer) - Q_UNUSED(surface) - Q_UNUSED(sx) - Q_UNUSED(sy) - WaylandSeat *seat = reinterpret_cast(data); - seat->pointerEntered(serial); -} - -static void pointerHandleLeave(void *data, wl_pointer *pointer, uint32_t serial, wl_surface *surface) -{ - Q_UNUSED(data) - Q_UNUSED(pointer) - Q_UNUSED(serial) - Q_UNUSED(surface) -} - -static void pointerHandleMotion(void *data, wl_pointer *pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy) -{ - Q_UNUSED(data) - Q_UNUSED(pointer) - Q_UNUSED(time) - xcb_test_fake_input(connection(), XCB_MOTION_NOTIFY, 0, XCB_TIME_CURRENT_TIME, XCB_WINDOW_NONE, - wl_fixed_to_int(sx), wl_fixed_to_int(sy), 0); -} - -static void pointerHandleButton(void *data, wl_pointer *pointer, uint32_t serial, uint32_t time, - uint32_t button, uint32_t state) -{ - Q_UNUSED(data) - Q_UNUSED(pointer) - Q_UNUSED(serial) - Q_UNUSED(time) - uint8_t type = XCB_BUTTON_PRESS; - if (state == WL_POINTER_BUTTON_STATE_RELEASED) { - type = XCB_BUTTON_RELEASE; - } - // TODO: there must be a better way for mapping - uint8_t xButton = 0; - switch (button) { - case BTN_LEFT: - xButton = XCB_BUTTON_INDEX_1; - break; - case BTN_RIGHT: - xButton = XCB_BUTTON_INDEX_3; - break; - case BTN_MIDDLE: - xButton = XCB_BUTTON_INDEX_2; - break; - default: - // TODO: add more buttons - return; - } - xcb_test_fake_input(connection(), type, xButton, XCB_TIME_CURRENT_TIME, XCB_WINDOW_NONE, 0, 0, 0); -} - -static void pointerHandleAxis(void *data, wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) -{ - Q_UNUSED(data) - Q_UNUSED(pointer) - Q_UNUSED(time) - uint8_t xButton = 0; - const int delta = wl_fixed_to_int(value); - if (delta == 0) { - return; - } - switch (axis) { - case WL_POINTER_AXIS_VERTICAL_SCROLL: - xButton = delta > 0 ? XCB_BUTTON_INDEX_5 : XCB_BUTTON_INDEX_4; - break; - case WL_POINTER_AXIS_HORIZONTAL_SCROLL: - // no enum values defined for buttons larger than 5 - xButton = delta > 0 ? 7 : 6; - break; - default: - // doesn't exist - return; - } - for (int i = 0; i < qAbs(delta); ++i) { - xcb_test_fake_input(connection(), XCB_BUTTON_PRESS, xButton, XCB_TIME_CURRENT_TIME, XCB_WINDOW_NONE, 0, 0, 0); - xcb_test_fake_input(connection(), XCB_BUTTON_RELEASE, xButton, XCB_TIME_CURRENT_TIME, XCB_WINDOW_NONE, 0, 0, 0); - } -} - -static void keyboardHandleKeymap(void *data, wl_keyboard *keyboard, - uint32_t format, int fd, uint32_t size) -{ - Q_UNUSED(data) - Q_UNUSED(keyboard) - Q_UNUSED(format) - Q_UNUSED(fd) - Q_UNUSED(size) -} - -static void keyboardHandleEnter(void *data, wl_keyboard *keyboard, - uint32_t serial, wl_surface *surface, - wl_array *keys) -{ - Q_UNUSED(data) - Q_UNUSED(keyboard) - Q_UNUSED(serial) - Q_UNUSED(surface) - Q_UNUSED(keys) -} - -static void keyboardHandleLeave(void *data, wl_keyboard *keyboard, uint32_t serial, wl_surface *surface) -{ - Q_UNUSED(data) - Q_UNUSED(keyboard) - Q_UNUSED(serial) - Q_UNUSED(surface) -} - -static void keyboardHandleKey(void *data, wl_keyboard *keyboard, uint32_t serial, uint32_t time, - uint32_t key, uint32_t state) -{ - Q_UNUSED(data) - Q_UNUSED(keyboard) - Q_UNUSED(serial) - Q_UNUSED(time) - uint8_t type = XCB_KEY_PRESS; - if (state == WL_KEYBOARD_KEY_STATE_RELEASED) { - type = XCB_KEY_RELEASE; - } - xcb_test_fake_input(connection(), type, key + 8 /*magic*/, XCB_TIME_CURRENT_TIME, XCB_WINDOW_NONE, 0, 0, 0); -} - -static void keyboardHandleModifiers(void *data, wl_keyboard *keyboard, uint32_t serial, uint32_t modsDepressed, - uint32_t modsLatched, uint32_t modsLocked, uint32_t group) -{ - Q_UNUSED(data) - Q_UNUSED(keyboard) - Q_UNUSED(serial) - Q_UNUSED(modsDepressed) - Q_UNUSED(modsLatched) - Q_UNUSED(modsLocked) - Q_UNUSED(group) -} - -// handlers -static const struct wl_registry_listener s_registryListener = { - registryHandleGlobal, - registryHandleGlobalRemove -}; - -static const struct wl_shell_surface_listener s_shellSurfaceListener = { - handlePing, - handleConfigure, - handlePopupDone -}; - -static const struct wl_pointer_listener s_pointerListener = { - pointerHandleEnter, - pointerHandleLeave, - pointerHandleMotion, - pointerHandleButton, - pointerHandleAxis -}; - -static const struct wl_keyboard_listener s_keyboardListener = { - keyboardHandleKeymap, - keyboardHandleEnter, - keyboardHandleLeave, - keyboardHandleKey, - keyboardHandleModifiers, -}; - -static const struct wl_seat_listener s_seatListener = { - seatHandleCapabilities -}; - -CursorData::CursorData(ShmPool *pool) - : m_cursor(NULL) - , m_valid(init(pool)) -{ -} - -CursorData::~CursorData() -{ -} - -bool CursorData::init(ShmPool *pool) -{ - QScopedPointer cursor( - xcb_xfixes_get_cursor_image_reply(connection(), - xcb_xfixes_get_cursor_image_unchecked(connection()), - NULL)); - if (cursor.isNull()) { - return false; - } - - QImage cursorImage((uchar *) xcb_xfixes_get_cursor_image_cursor_image(cursor.data()), cursor->width, cursor->height, - QImage::Format_ARGB32_Premultiplied); - if (cursorImage.isNull()) { - return false; - } - m_size = QSize(cursor->width, cursor->height); - - m_cursor = pool->createBuffer(cursorImage); - if (!m_cursor) { - kDebug(1212) << "Creating cursor buffer failed"; - return false; - } - - m_hotSpot = QPoint(cursor->xhot, cursor->yhot); - return true; -} - -X11CursorTracker::X11CursorTracker(wl_pointer *pointer, WaylandBackend *backend, QObject* parent) - : QObject(parent) - , m_pointer(pointer) - , m_backend(backend) - , m_cursor(wl_compositor_create_surface(backend->compositor())) - , m_enteredSerial(0) - , m_lastX11Cursor(0) -{ - Cursor::self()->startCursorTracking(); - connect(Cursor::self(), SIGNAL(cursorChanged(uint32_t)), SLOT(cursorChanged(uint32_t))); -} - -X11CursorTracker::~X11CursorTracker() -{ - Cursor::self()->stopCursorTracking(); - if (m_cursor) { - wl_surface_destroy(m_cursor); - } -} - -void X11CursorTracker::cursorChanged(uint32_t serial) -{ - if (m_lastX11Cursor == serial) { - // not changed; - return; - } - m_lastX11Cursor = serial; - QHash::iterator it = m_cursors.find(serial); - if (it != m_cursors.end()) { - installCursor(it.value()); - return; - } - ShmPool *pool = m_backend->shmPool(); - if (!pool) { - return; - } - CursorData cursor(pool); - if (cursor.isValid()) { - // TODO: discard unused cursors after some time? - m_cursors.insert(serial, cursor); - } - installCursor(cursor); -} - -void X11CursorTracker::installCursor(const CursorData& cursor) -{ - wl_pointer_set_cursor(m_pointer, m_enteredSerial, m_cursor, cursor.hotSpot().x(), cursor.hotSpot().y()); - wl_surface_attach(m_cursor, cursor.cursor(), 0, 0); - wl_surface_damage(m_cursor, 0, 0, cursor.size().width(), cursor.size().height()); - wl_surface_commit(m_cursor); -} - -void X11CursorTracker::setEnteredSerial(uint32_t serial) -{ - m_enteredSerial = serial; -} - -void X11CursorTracker::resetCursor() -{ - QHash::iterator it = m_cursors.find(m_lastX11Cursor); - if (it != m_cursors.end()) { - installCursor(it.value()); - } -} - -ShmPool::ShmPool(wl_shm *shm) - : m_shm(shm) - , m_pool(NULL) - , m_poolData(NULL) - , m_size(1024 * 1024) // TODO: useful size? - , m_tmpFile(new KTemporaryFile()) - , m_valid(createPool()) - , m_offset(0) -{ -} - -ShmPool::~ShmPool() -{ - if (m_poolData) { - munmap(m_poolData, m_size); - } - if (m_pool) { - wl_shm_pool_destroy(m_pool); - } - if (m_shm) { - wl_shm_destroy(m_shm); - } -} - -bool ShmPool::createPool() -{ - if (!m_tmpFile->open()) { - kDebug(1212) << "Could not open temporary file for Shm pool"; - return false; - } - if (ftruncate(m_tmpFile->handle(), m_size) < 0) { - kDebug(1212) << "Could not set size for Shm pool file"; - return false; - } - m_poolData = mmap(NULL, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_tmpFile->handle(), 0); - m_pool = wl_shm_create_pool(m_shm, m_tmpFile->handle(), m_size); - - if (!m_poolData || !m_pool) { - kDebug(1212) << "Creating Shm pool failed"; - return false; - } - m_tmpFile->close(); - return true; -} - -wl_buffer *ShmPool::createBuffer(const QImage& image) -{ - if (image.isNull() || !m_valid) { - return NULL; - } - // TODO: test whether buffer needs resizing - wl_buffer *buffer = wl_shm_pool_create_buffer(m_pool, m_offset, image.width(), image.height(), - image.bytesPerLine(), WL_SHM_FORMAT_ARGB8888); - if (buffer) { - memcpy((char *)m_poolData + m_offset, image.bits(), image.byteCount()); - m_offset += image.byteCount(); - } - return buffer; -} - -WaylandSeat::WaylandSeat(wl_seat *seat, WaylandBackend *backend) - : m_seat(seat) - , m_pointer(NULL) - , m_keyboard(NULL) - , m_cursorTracker() - , m_backend(backend) -{ - if (m_seat) { - wl_seat_add_listener(m_seat, &s_seatListener, this); - } -} - -WaylandSeat::~WaylandSeat() -{ - destroyPointer(); - destroyKeyboard(); - if (m_seat) { - wl_seat_destroy(m_seat); - } -} - -void WaylandSeat::destroyPointer() -{ - if (m_pointer) { - wl_pointer_destroy(m_pointer); - m_pointer = NULL; - m_cursorTracker.reset(); - } -} - -void WaylandSeat::destroyKeyboard() -{ - if (m_keyboard) { - wl_keyboard_destroy(m_keyboard); - m_keyboard = NULL; - } -} - -void WaylandSeat::changed(uint32_t capabilities) -{ - if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && !m_pointer) { - m_pointer = wl_seat_get_pointer(m_seat); - wl_pointer_add_listener(m_pointer, &s_pointerListener, this); - m_cursorTracker.reset(new X11CursorTracker(m_pointer, m_backend)); - } else if (!(capabilities & WL_SEAT_CAPABILITY_POINTER)) { - destroyPointer(); - } - if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) { - m_keyboard = wl_seat_get_keyboard(m_seat); - wl_keyboard_add_listener(m_keyboard, &s_keyboardListener, this); - } else if (!(capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) { - destroyKeyboard(); - } -} - -void WaylandSeat::pointerEntered(uint32_t serial) -{ - if (m_cursorTracker.isNull()) { - return; - } - m_cursorTracker->setEnteredSerial(serial); -} - -void WaylandSeat::resetCursor() -{ - if (!m_cursorTracker.isNull()) { - m_cursorTracker->resetCursor(); - } -} - -WaylandBackend::WaylandBackend() - : QObject(NULL) - , m_display(wl_display_connect(NULL)) - , m_registry(wl_display_get_registry(m_display)) - , m_compositor(NULL) - , m_shell(NULL) - , m_surface(NULL) - , m_overlay(NULL) - , m_shellSurface(NULL) - , m_seat() - , m_shm() -{ - kDebug(1212) << "Created Wayland display"; - // setup the registry - wl_registry_add_listener(m_registry, &s_registryListener, this); - wl_display_dispatch(m_display); - int fd = wl_display_get_fd(m_display); - QSocketNotifier *notifier = new QSocketNotifier(fd, QSocketNotifier::Read, this); - connect(notifier, SIGNAL(activated(int)), SLOT(readEvents())); -} - -WaylandBackend::~WaylandBackend() -{ - if (m_overlay) { - wl_egl_window_destroy(m_overlay); - } - if (m_shellSurface) { - wl_shell_surface_destroy(m_shellSurface); - } - if (m_surface) { - wl_surface_destroy(m_surface); - } - if (m_shell) { - wl_shell_destroy(m_shell); - } - if (m_compositor) { - wl_compositor_destroy(m_compositor); - } - if (m_registry) { - wl_registry_destroy(m_registry); - } - if (m_display) { - wl_display_flush(m_display); - wl_display_disconnect(m_display); - } - kDebug(1212) << "Destroyed Wayland display"; -} - -void WaylandBackend::readEvents() -{ - // TODO: this still seems to block - wl_display_flush(m_display); - wl_display_dispatch(m_display); -} - -void WaylandBackend::createSeat(uint32_t name) -{ - wl_seat *seat = reinterpret_cast(wl_registry_bind(m_registry, name, &wl_seat_interface, 1)); - m_seat.reset(new WaylandSeat(seat, this)); -} - -bool WaylandBackend::createSurface() -{ - m_surface = wl_compositor_create_surface(m_compositor); - if (!m_surface) { - kError(1212) << "Creating Wayland Surface failed"; - return false; - } - // map the surface as fullscreen - m_shellSurface = wl_shell_get_shell_surface(m_shell, m_surface); - wl_shell_surface_add_listener(m_shellSurface, &s_shellSurfaceListener, this); - - // TODO: do something better than displayWidth/displayHeight - m_overlay = wl_egl_window_create(m_surface, displayWidth(), displayHeight()); - if (!m_overlay) { - kError(1212) << "Creating Wayland Egl window failed"; - return false; - } - wl_shell_surface_set_fullscreen(m_shellSurface, WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, NULL); - - return true; -} - -void WaylandBackend::createShm(uint32_t name) -{ - m_shm.reset(new ShmPool(reinterpret_cast(wl_registry_bind(m_registry, name, &wl_shm_interface, 1)))); - if (!m_shm->isValid()) { - m_shm.reset(); - } -} - -void WaylandBackend::ping(uint32_t serial) -{ - wl_shell_surface_pong(m_shellSurface, serial); - if (!m_seat.isNull()) { - m_seat->resetCursor(); - } -} - -} - -EglWaylandBackend::EglWaylandBackend() - : OpenGLBackend() - , m_context(EGL_NO_CONTEXT) - , m_wayland(new Wayland::WaylandBackend) -{ - kDebug(1212) << "Connected to Wayland display?" << (m_wayland->display() ? "yes" : "no" ); - if (!m_wayland->display()) { - setFailed("Could not connect to Wayland compositor"); - return; - } - initializeEgl(); - init(); - // Egl is always direct rendering - setIsDirectRendering(true); - - kWarning(1212) << "Using Wayland rendering backend"; - kWarning(1212) << "This is a highly experimental backend, do not use for productive usage!"; - kWarning(1212) << "Please do not report any issues you might encounter when using this backend!"; -} - -EglWaylandBackend::~EglWaylandBackend() -{ - cleanupGL(); - checkGLError("Cleanup"); - eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglDestroyContext(m_display, m_context); - eglDestroySurface(m_display, m_surface); - eglTerminate(m_display); - eglReleaseThread(); -} - -bool EglWaylandBackend::initializeEgl() -{ - m_display = eglGetDisplay(m_wayland->display()); - if (m_display == EGL_NO_DISPLAY) - return false; - - EGLint major, minor; - if (eglInitialize(m_display, &major, &minor) == EGL_FALSE) - return false; - EGLint error = eglGetError(); - if (error != EGL_SUCCESS) { - kWarning(1212) << "Error during eglInitialize " << error; - return false; - } - kDebug(1212) << "Egl Initialize succeeded"; - -#ifdef KWIN_HAVE_OPENGLES - eglBindAPI(EGL_OPENGL_ES_API); -#else - if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) { - kError(1212) << "bind OpenGL API failed"; - return false; - } -#endif - kDebug(1212) << "EGL version: " << major << "." << minor; - return true; -} - -void EglWaylandBackend::init() -{ - if (!initRenderingContext()) { - setFailed("Could not initialize rendering context"); - return; - } - - initEGL(); - GLPlatform *glPlatform = GLPlatform::instance(); - glPlatform->detect(EglPlatformInterface); - glPlatform->printResults(); - initGL(EglPlatformInterface); -} - -bool EglWaylandBackend::initRenderingContext() -{ - initBufferConfigs(); - -#ifdef KWIN_HAVE_OPENGLES - const EGLint context_attribs[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, - EGL_NONE - }; - - m_context = eglCreateContext(m_display, m_config, EGL_NO_CONTEXT, context_attribs); -#else - const EGLint context_attribs_31_core[] = { - EGL_CONTEXT_MAJOR_VERSION_KHR, 3, - EGL_CONTEXT_MINOR_VERSION_KHR, 1, - EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, - EGL_NONE - }; - - const EGLint context_attribs_legacy[] = { - EGL_NONE - }; - - const QByteArray eglExtensions = eglQueryString(m_display, EGL_EXTENSIONS); - const QList extensions = eglExtensions.split(' '); - - // Try to create a 3.1 core context - if (options->glCoreProfile() && extensions.contains("EGL_KHR_create_context")) - m_context = eglCreateContext(m_display, m_config, EGL_NO_CONTEXT, context_attribs_31_core); - - if (m_context == EGL_NO_CONTEXT) - m_context = eglCreateContext(m_display, m_config, EGL_NO_CONTEXT, context_attribs_legacy); -#endif - - if (m_context == EGL_NO_CONTEXT) { - kError(1212) << "Create Context failed"; - return false; - } - - if (!m_wayland->createSurface()) { - return false; - } - - m_surface = eglCreateWindowSurface(m_display, m_config, m_wayland->overlay(), NULL); - if (m_surface == EGL_NO_SURFACE) { - kError(1212) << "Create Window Surface failed"; - return false; - } - - return makeContextCurrent(); -} - -bool EglWaylandBackend::makeContextCurrent() -{ - if (eglMakeCurrent(m_display, m_surface, m_surface, m_context) == EGL_FALSE) { - kError(1212) << "Make Context Current failed"; - return false; - } - - EGLint error = eglGetError(); - if (error != EGL_SUCCESS) { - kWarning(1212) << "Error occurred while creating context " << error; - return false; - } - return true; -} - -bool EglWaylandBackend::initBufferConfigs() -{ - const EGLint config_attribs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RED_SIZE, 1, - EGL_GREEN_SIZE, 1, - EGL_BLUE_SIZE, 1, - EGL_ALPHA_SIZE, 0, -#ifdef KWIN_HAVE_OPENGLES - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, -#else - EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, -#endif - EGL_CONFIG_CAVEAT, EGL_NONE, - EGL_NONE, - }; - - EGLint count; - EGLConfig configs[1024]; - if (eglChooseConfig(m_display, config_attribs, configs, 1, &count) == EGL_FALSE) { - kError(1212) << "choose config failed"; - return false; - } - if (count != 1) { - kError(1212) << "choose config did not return a config" << count; - return false; - } - m_config = configs[0]; - - return true; -} - -void EglWaylandBackend::present() -{ - setLastDamage(QRegion()); - // need to dispatch pending events as eglSwapBuffers can block - wl_display_dispatch_pending(m_wayland->display()); - wl_display_flush(m_wayland->display()); - eglSwapBuffers(m_display, m_surface); -} - -void EglWaylandBackend::screenGeometryChanged(const QSize &size) -{ - Q_UNUSED(size) - // no backend specific code needed - // TODO: base implementation in OpenGLBackend -} - -SceneOpenGL::TexturePrivate *EglWaylandBackend::createBackendTexture(SceneOpenGL::Texture *texture) -{ - return new EglWaylandTexture(texture, this); -} - -QRegion EglWaylandBackend::prepareRenderingFrame() -{ - if (!lastDamage().isEmpty()) - present(); - - eglWaitNative(EGL_CORE_NATIVE_ENGINE); - startRenderTimer(); - - return QRegion(); -} - -void EglWaylandBackend::endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) -{ - setLastDamage(renderedRegion); - glFlush(); -} - -Shm *EglWaylandBackend::shm() -{ - if (m_shm.isNull()) { - m_shm.reset(new Shm); - } - return m_shm.data(); -} - -/************************************************ - * EglTexture - ************************************************/ - -EglWaylandTexture::EglWaylandTexture(KWin::SceneOpenGL::Texture *texture, KWin::EglWaylandBackend *backend) - : SceneOpenGL::TexturePrivate() - , q(texture) - , m_backend(backend) - , m_referencedPixmap(XCB_PIXMAP_NONE) -{ - m_target = GL_TEXTURE_2D; -} - -EglWaylandTexture::~EglWaylandTexture() -{ -} - -OpenGLBackend *EglWaylandTexture::backend() -{ - return m_backend; -} - -void EglWaylandTexture::findTarget() -{ - if (m_target != GL_TEXTURE_2D) { - m_target = GL_TEXTURE_2D; - } -} - -bool EglWaylandTexture::loadTexture(const Pixmap &pix, const QSize &size, int depth) -{ - // HACK: egl wayland platform doesn't support texture from X11 pixmap through the KHR_image_pixmap - // extension. To circumvent this problem we copy the pixmap content into a SHM image and from there - // to the OpenGL texture. This is a temporary solution. In future we won't need to get the content - // from X11 pixmaps. That's what we have XWayland for to get the content into a nice Wayland buffer. - Q_UNUSED(depth) - if (pix == XCB_PIXMAP_NONE) - return false; - m_referencedPixmap = pix; - - Shm *shm = m_backend->shm(); - if (!shm->isValid()) { - return false; - } - - xcb_shm_get_image_cookie_t cookie = xcb_shm_get_image_unchecked(connection(), pix, 0, 0, size.width(), - size.height(), ~0, XCB_IMAGE_FORMAT_Z_PIXMAP, shm->segment(), 0); - - glGenTextures(1, &m_texture); - q->setWrapMode(GL_CLAMP_TO_EDGE); - q->setFilter(GL_LINEAR); - q->bind(); - - ScopedCPointer image(xcb_shm_get_image_reply(connection(), cookie, NULL)); - if (image.isNull()) { - return false; - } - - // TODO: other formats -#ifndef KWIN_HAVE_OPENGLES - glTexImage2D(m_target, 0, GL_RGBA8, size.width(), size.height(), 0, - GL_BGRA, GL_UNSIGNED_BYTE, shm->buffer()); -#endif - - q->unbind(); - checkGLError("load texture"); - q->setYInverted(true); - m_size = size; - updateMatrix(); - return true; -} - -bool EglWaylandTexture::update(const QRegion &damage) -{ - if (m_referencedPixmap == XCB_PIXMAP_NONE) { - return false; - } - - Shm *shm = m_backend->shm(); - if (!shm->isValid()) { - return false; - } - - // TODO: optimize by only updating the damaged areas - const QRect &damagedRect = damage.boundingRect(); - xcb_shm_get_image_cookie_t cookie = xcb_shm_get_image_unchecked(connection(), m_referencedPixmap, - damagedRect.x(), damagedRect.y(), damagedRect.width(), damagedRect.height(), - ~0, XCB_IMAGE_FORMAT_Z_PIXMAP, shm->segment(), 0); - - q->bind(); - - ScopedCPointer image(xcb_shm_get_image_reply(connection(), cookie, NULL)); - if (image.isNull()) { - return false; - } - - // TODO: other formats -#ifndef KWIN_HAVE_OPENGLES - glTexSubImage2D(m_target, 0, damagedRect.x(), damagedRect.y(), damagedRect.width(), damagedRect.height(), GL_BGRA, GL_UNSIGNED_BYTE, shm->buffer()); -#endif - - q->unbind(); - checkGLError("update texture"); - return true; -} - -Shm::Shm() - : m_shmId(-1) - , m_buffer(NULL) - , m_segment(XCB_NONE) - , m_valid(false) -{ - m_valid = init(); -} - -Shm::~Shm() -{ - if (m_valid) { - xcb_shm_detach(connection(), m_segment); - shmdt(m_buffer); - } -} - -bool Shm::init() -{ - const xcb_query_extension_reply_t *ext = xcb_get_extension_data(connection(), &xcb_shm_id); - if (!ext || !ext->present) { - kDebug(1212) << "SHM extension not available"; - return false; - } - ScopedCPointer version(xcb_shm_query_version_reply(connection(), - xcb_shm_query_version_unchecked(connection()), NULL)); - if (version.isNull()) { - kDebug(1212) << "Failed to get SHM extension version information"; - return false; - } - const int MAXSIZE = 4096 * 2048 * 4; // TODO check there are not larger windows - m_shmId = shmget(IPC_PRIVATE, MAXSIZE, IPC_CREAT | 0600); - if (m_shmId < 0) { - kDebug(1212) << "Failed to allocate SHM segment"; - return false; - } - m_buffer = shmat(m_shmId, NULL, 0 /*read/write*/); - if (-1 == reinterpret_cast(m_buffer)) { - kDebug(1212) << "Failed to attach SHM segment"; - shmctl(m_shmId, IPC_RMID, NULL); - return false; - } - shmctl(m_shmId, IPC_RMID, NULL); - - m_segment = xcb_generate_id(connection()); - const xcb_void_cookie_t cookie = xcb_shm_attach_checked(connection(), m_segment, m_shmId, false); - ScopedCPointer error(xcb_request_check(connection(), cookie)); - if (!error.isNull()) { - kDebug(1212) << "xcb_shm_attach error: " << error->error_code; - shmdt(m_buffer); - return false; - } - - return true; -} - -} // namespace diff --git a/kwin/egl_wayland_backend.h b/kwin/egl_wayland_backend.h deleted file mode 100644 index 719da4b6..00000000 --- a/kwin/egl_wayland_backend.h +++ /dev/null @@ -1,359 +0,0 @@ -/******************************************************************** - KWin - the KDE window manager - This file is part of the KDE project. - -Copyright (C) 2013 Martin Gräßlin - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY 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 . -*********************************************************************/ -#ifndef KWIN_EGL_WAYLAND_BACKEND_H -#define KWIN_EGL_WAYLAND_BACKEND_H -#include "scene_opengl.h" -// wayland -#include -#include -// xcb -#include - -class KTemporaryFile; -struct wl_buffer; -struct wl_shm; - -namespace KWin -{ - -namespace Wayland -{ -class ShmPool; -class WaylandBackend; - -class CursorData -{ -public: - CursorData(ShmPool *pool); - ~CursorData(); - bool isValid() const; - const QPoint &hotSpot() const; - const QSize &size() const; - wl_buffer *cursor() const; -private: - bool init(ShmPool *pool); - wl_buffer *m_cursor; - QPoint m_hotSpot; - QSize m_size; - bool m_valid; -}; - -class X11CursorTracker : public QObject -{ - Q_OBJECT -public: - explicit X11CursorTracker(wl_pointer *pointer, WaylandBackend *backend, QObject* parent = 0); - virtual ~X11CursorTracker(); - void setEnteredSerial(uint32_t serial); - void resetCursor(); -private Q_SLOTS: - void cursorChanged(uint32_t serial); -private: - void installCursor(const CursorData &cursor); - wl_pointer *m_pointer; - QHash m_cursors; - WaylandBackend *m_backend; - wl_surface *m_cursor; - uint32_t m_enteredSerial; - uint32_t m_installedCursor; - uint32_t m_lastX11Cursor; -}; - -class ShmPool -{ -public: - ShmPool(wl_shm *shm); - ~ShmPool(); - bool isValid() const; - wl_buffer *createBuffer(const QImage &image); -private: - bool createPool(); - wl_shm *m_shm; - wl_shm_pool *m_pool; - void *m_poolData; - size_t m_size; - QScopedPointer m_tmpFile; - bool m_valid; - int m_offset; -}; - -class WaylandSeat -{ -public: - WaylandSeat(wl_seat *seat, WaylandBackend *backend); - virtual ~WaylandSeat(); - - void changed(uint32_t capabilities); - wl_seat *seat(); - void pointerEntered(uint32_t serial); - void resetCursor(); -private: - void destroyPointer(); - void destroyKeyboard(); - wl_seat *m_seat; - wl_pointer *m_pointer; - wl_keyboard *m_keyboard; - QScopedPointer m_cursorTracker; - WaylandBackend *m_backend; -}; - -/** -* @brief Class encapsulating all Wayland data structures needed by the Egl backend. -* -* It creates the connection to the Wayland Compositor, set's up the registry and creates -* the Wayland surface and it's shell and egl mapping. -*/ -class WaylandBackend : public QObject -{ - Q_OBJECT -public: - WaylandBackend(); - virtual ~WaylandBackend(); - wl_display *display(); - wl_registry *registry(); - void setCompositor(wl_compositor *c); - wl_compositor *compositor(); - void setShell(wl_shell *s); - wl_shell *shell(); - wl_egl_window *overlay(); - ShmPool *shmPool(); - void createSeat(uint32_t name); - void createShm(uint32_t name); - void ping(uint32_t serial); - - bool createSurface(); -private Q_SLOTS: - void readEvents(); -private: - wl_display *m_display; - wl_registry *m_registry; - wl_compositor *m_compositor; - wl_shell *m_shell; - wl_surface *m_surface; - wl_egl_window *m_overlay; - wl_shell_surface *m_shellSurface; - QScopedPointer m_seat; - QScopedPointer m_shm; -}; - -inline -bool CursorData::isValid() const -{ - return m_valid; -} - -inline -const QPoint& CursorData::hotSpot() const -{ - return m_hotSpot; -} - -inline -wl_buffer* CursorData::cursor() const -{ - return m_cursor; -} - -inline -const QSize& CursorData::size() const -{ - return m_size; -} - -inline -wl_seat *WaylandSeat::seat() -{ - return m_seat; -} - -inline -bool ShmPool::isValid() const -{ - return m_valid; -} - -inline -wl_display *WaylandBackend::display() -{ - return m_display; -} - -inline -wl_registry *WaylandBackend::registry() -{ - return m_registry; -} - -inline -void WaylandBackend::setCompositor(wl_compositor *c) -{ - m_compositor = c; -} - -inline -wl_compositor *WaylandBackend::compositor() -{ - return m_compositor; -} - -inline -wl_egl_window *WaylandBackend::overlay() -{ - return m_overlay; -} - -inline -void WaylandBackend::setShell(wl_shell *s) -{ - m_shell = s; -} - -inline -wl_shell *WaylandBackend::shell() -{ - return m_shell; -} - -inline -ShmPool* WaylandBackend::shmPool() -{ - return m_shm.data(); -} - -} // namespace Wayland - -class Shm; - -/** - * @brief OpenGL Backend using Egl on a Wayland surface. - * - * This Backend is the basis for a session compositor running on top of a Wayland system compositor. - * It creates a Surface as large as the screen and maps it as a fullscreen shell surface on the - * system compositor. The OpenGL context is created on the Wayland surface, so for rendering X11 is - * not involved. - * - * At the moment the backend is still rather limited. For getting textures from pixmap it uses the - * XShm library. This is currently a hack and only as proof of concept till we support texture from - * Wayland buffers. From then on we should use XWayland for texture mapping. - * - * Also in repainting the backend is currently still rather limited. Only supported mode is fullscreen - * repaints, which is obviously not optimal. Best solution is probably to go for buffer_age extension - * and make it the only available solution next to fullscreen repaints. - **/ -class EglWaylandBackend : public OpenGLBackend -{ -public: - EglWaylandBackend(); - virtual ~EglWaylandBackend(); - virtual void screenGeometryChanged(const QSize &size); - virtual SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture *texture); - virtual QRegion prepareRenderingFrame(); - virtual void endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion); - Shm *shm(); - -protected: - virtual void present(); - -private: - void init(); - bool initializeEgl(); - bool initBufferConfigs(); - bool initRenderingContext(); - bool makeContextCurrent(); - EGLDisplay m_display; - EGLConfig m_config; - EGLSurface m_surface; - EGLContext m_context; - QScopedPointer m_wayland; - QScopedPointer m_shm; - friend class EglWaylandTexture; -}; - -/** - * @brief Texture using an EGLImageKHR. - **/ -class EglWaylandTexture : public SceneOpenGL::TexturePrivate -{ -public: - virtual ~EglWaylandTexture(); - virtual void findTarget(); - virtual bool loadTexture(const Pixmap& pix, const QSize& size, int depth); - virtual OpenGLBackend *backend(); - virtual bool update(const QRegion &damage); - -private: - friend class EglWaylandBackend; - EglWaylandTexture(SceneOpenGL::Texture *texture, EglWaylandBackend *backend); - SceneOpenGL::Texture *q; - EglWaylandBackend *m_backend; - /** - * The Pixmap of the window content. Get's updated in loadTexture. - */ - xcb_pixmap_t m_referencedPixmap; -}; - -/** - * @brief Small helper class to encapsulate SHM related functionality. - * - */ -class Shm -{ -public: - Shm(); - ~Shm(); - int shmId() const; - void *buffer() const; - xcb_shm_seg_t segment() const; - bool isValid() const; -private: - bool init(); - int m_shmId; - void *m_buffer; - xcb_shm_seg_t m_segment; - bool m_valid; -}; - -inline -void *Shm::buffer() const -{ - return m_buffer; -} - -inline -bool Shm::isValid() const -{ - return m_valid; -} - -inline -xcb_shm_seg_t Shm::segment() const -{ - return m_segment; -} - -inline -int Shm::shmId() const -{ - return m_shmId; -} - -} // namespace - -#endif // KWIN_EGL_ON_X_BACKEND_H diff --git a/kwin/scene_opengl.cpp b/kwin/scene_opengl.cpp index 77aec3c0..f91a1342 100644 --- a/kwin/scene_opengl.cpp +++ b/kwin/scene_opengl.cpp @@ -26,9 +26,6 @@ along with this program. If not, see . #include "eglonxbackend.h" // for Wayland #include "config-workspace.h" -#ifdef WAYLAND_FOUND -#include "egl_wayland_backend.h" -#endif #endif #ifndef KWIN_HAVE_OPENGLES #include "glxbackend.h" @@ -224,15 +221,7 @@ SceneOpenGL *SceneOpenGL::createScene() break; case EglPlatformInterface: #ifdef KWIN_HAVE_EGL -#ifdef WAYLAND_FOUND - if (qstrcmp(envOpenGLInterface, "egl_wayland") == 0) { - backend = new EglWaylandBackend(); - } else { - backend = new EglOnXBackend(); - } -#else backend = new EglOnXBackend(); -#endif #endif break; default: