From 7f958b2b43f7e418f87c9ff7f17508bcd8d0f1ea Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Thu, 30 Nov 2023 13:29:39 -0500 Subject: [PATCH 01/93] i am trying, ok? --- linux/cc/ILayer.cc | 2 +- linux/cc/ILayer.hh | 2 +- linux/cc/ScreenInfo.cc | 2 +- script/build.py | 15 +- wayland/CMakeLists.txt | 43 + .../cc/AppX11.cc => wayland/cc/AppWayland.cc | 0 wayland/cc/AppWayland.hh | 35 + .../cc/ClipboardWayland.cc | 0 .../cc/KeyX11.cc => wayland/cc/KeyWayland.cc | 0 .../cc/KeyX11.hh => wayland/cc/KeyWayland.hh | 0 wayland/cc/LayerGLWayland.cc | 123 ++ .../cc/LayerRasterWayland.cc | 0 .../cc/MouseButtonWayland.cc | 0 .../cc/MouseButtonWayland.hh | 0 wayland/cc/WindowManagerWayland.cc | 330 +++ wayland/cc/WindowManagerWayland.hh | 96 + wayland/cc/WindowWayland.cc | 585 +++++ wayland/cc/WindowWayland.hh | 84 + wayland/cc/xdg-shell.c | 172 ++ wayland/cc/xdg-shell.h | 1884 +++++++++++++++++ wayland/java/WindowWayland.java | 235 ++ {linux => x11}/CMakeLists.txt | 4 +- x11/cc/AppX11.cc | 126 ++ {linux => x11}/cc/AppX11.hh | 0 x11/cc/ClipboardX11.cc | 125 ++ x11/cc/KeyX11.cc | 178 ++ x11/cc/KeyX11.hh | 14 + linux/cc/LayerGL.cc => x11/cc/LayerGLX11.cc | 0 x11/cc/LayerRasterX11.cc | 123 ++ x11/cc/MouseButtonX11.cc | 25 + x11/cc/MouseButtonX11.hh | 12 + {linux => x11}/cc/WindowManagerX11.cc | 0 {linux => x11}/cc/WindowManagerX11.hh | 0 {linux => x11}/cc/WindowX11.cc | 0 {linux => x11}/cc/WindowX11.hh | 0 {linux => x11}/cc/WindowX11MotifHints.hh | 0 {linux => x11}/java/WindowX11.java | 0 37 files changed, 4206 insertions(+), 9 deletions(-) create mode 100644 wayland/CMakeLists.txt rename linux/cc/AppX11.cc => wayland/cc/AppWayland.cc (100%) create mode 100644 wayland/cc/AppWayland.hh rename linux/cc/ClipboardX11.cc => wayland/cc/ClipboardWayland.cc (100%) rename linux/cc/KeyX11.cc => wayland/cc/KeyWayland.cc (100%) rename linux/cc/KeyX11.hh => wayland/cc/KeyWayland.hh (100%) create mode 100644 wayland/cc/LayerGLWayland.cc rename linux/cc/LayerRaster.cc => wayland/cc/LayerRasterWayland.cc (100%) rename linux/cc/MouseButtonX11.cc => wayland/cc/MouseButtonWayland.cc (100%) rename linux/cc/MouseButtonX11.hh => wayland/cc/MouseButtonWayland.hh (100%) create mode 100644 wayland/cc/WindowManagerWayland.cc create mode 100644 wayland/cc/WindowManagerWayland.hh create mode 100644 wayland/cc/WindowWayland.cc create mode 100644 wayland/cc/WindowWayland.hh create mode 100644 wayland/cc/xdg-shell.c create mode 100644 wayland/cc/xdg-shell.h create mode 100644 wayland/java/WindowWayland.java rename {linux => x11}/CMakeLists.txt (91%) create mode 100644 x11/cc/AppX11.cc rename {linux => x11}/cc/AppX11.hh (100%) create mode 100644 x11/cc/ClipboardX11.cc create mode 100644 x11/cc/KeyX11.cc create mode 100644 x11/cc/KeyX11.hh rename linux/cc/LayerGL.cc => x11/cc/LayerGLX11.cc (100%) create mode 100644 x11/cc/LayerRasterX11.cc create mode 100644 x11/cc/MouseButtonX11.cc create mode 100644 x11/cc/MouseButtonX11.hh rename {linux => x11}/cc/WindowManagerX11.cc (100%) rename {linux => x11}/cc/WindowManagerX11.hh (100%) rename {linux => x11}/cc/WindowX11.cc (100%) rename {linux => x11}/cc/WindowX11.hh (100%) rename {linux => x11}/cc/WindowX11MotifHints.hh (100%) rename {linux => x11}/java/WindowX11.java (100%) diff --git a/linux/cc/ILayer.cc b/linux/cc/ILayer.cc index 4f7d2d1e..6d4d4264 100644 --- a/linux/cc/ILayer.cc +++ b/linux/cc/ILayer.cc @@ -10,4 +10,4 @@ void jwm::ILayer::makeCurrent() { } void jwm::ILayer::makeCurrentForced() { _ourCurrentLayer = this; -} \ No newline at end of file +} diff --git a/linux/cc/ILayer.hh b/linux/cc/ILayer.hh index 5a22d209..81a32c2b 100644 --- a/linux/cc/ILayer.hh +++ b/linux/cc/ILayer.hh @@ -20,4 +20,4 @@ public: static ILayer* _ourCurrentLayer; }; -} // namespace jwm \ No newline at end of file +} // namespace jwm diff --git a/linux/cc/ScreenInfo.cc b/linux/cc/ScreenInfo.cc index ddcab4c6..f3aa1dee 100644 --- a/linux/cc/ScreenInfo.cc +++ b/linux/cc/ScreenInfo.cc @@ -4,4 +4,4 @@ jobject jwm::ScreenInfo::asJavaObject(JNIEnv* env) const { return jwm::classes::Screen::make(env, id, isPrimary, bounds, bounds, jwm::app.getScale()); -} \ No newline at end of file +} diff --git a/script/build.py b/script/build.py index 56e4cc3b..80882614 100755 --- a/script/build.py +++ b/script/build.py @@ -1,8 +1,8 @@ #! /usr/bin/env python3 import argparse, build_utils, common, glob, os, platform, subprocess, sys -def build_native(): - os.chdir(common.basedir + "/" + build_utils.system) +def build_native_system(system): + os.chdir(common.basedir + "/" + system) subprocess.check_call(["cmake", "-DCMAKE_BUILD_TYPE=Release", "-B", "build", @@ -24,10 +24,17 @@ def build_native(): build_utils.copy_newer('build/jwm_x64.dll', '../target/classes/jwm_x64.dll') return 0 - +def build_system(): + cur_system = build_utils.system; + if cur_system == "linux": + build_native_system("x11") + build_native_system("wayland") + else: + build_native_system(cur_system) + return 0 def build_java(): os.chdir(common.basedir) - sources = build_utils.files("linux/java/**/*.java", "macos/java/**/*.java", "shared/java/**/*.java", "windows/java/**/*.java",) + sources = build_utils.files("x11/java/**/*.java", "macos/java/**/*.java", "shared/java/**/*.java", "windows/java/**/*.java",) build_utils.javac(sources, "target/classes", classpath=common.deps_compile()) return 0 diff --git a/wayland/CMakeLists.txt b/wayland/CMakeLists.txt new file mode 100644 index 00000000..75249cdd --- /dev/null +++ b/wayland/CMakeLists.txt @@ -0,0 +1,43 @@ +cmake_minimum_required(VERSION 3.9) + +# prefer the newer GL library (GLVND) +cmake_policy(SET CMP0072 NEW) + +project(jwm LANGUAGES CXX) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +if(NOT JWM_ARCH) + if ("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "arm64") + set(JWM_ARCH "arm64") + else() + set(JWM_ARCH "x64") + endif() +endif() + +find_package(wayland-client REQUIRED) +find_package(decor REQUIRED) +find_package(wayland-cursor REQUIRED) +find_package(OpenGL REQUIRED) + +file(GLOB SOURCES_CXX ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/*.cc ${CMAKE_CURRENT_LIST_DIR}/cc/*.cc) +file(GLOB SOURCES_CXX_IMPL ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/impl/*.cc) +add_library(jwm SHARED ${SOURCES_OBJC} ${SOURCES_CXX} ${SOURCES_CXX_IMPL}) + +set(JAVA_HOME $ENV{JAVA_HOME}) +if (NOT JAVA_HOME) + file(GLOB JAVA_HOMES "/usr/lib/jvm/java-*") + if (JAVA_HOMES) + list(GET JAVA_HOMES 0 JAVA_HOME) + message(STATUS "Java home found automatically at ${JAVA_HOME}. Set JAVA_HOME environment variable to override.") + else() + message(FATAL_ERROR "Java home not found! Please set JAVA_HOME environment variable.") + endif() +endif() + +target_include_directories(jwm PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../shared/cc ../shared/linux ${JAVA_HOME}/include ${JAVA_HOME}/include/linux) +set_target_properties(jwm PROPERTIES OUTPUT_NAME "jwm_${JWM_ARCH}") + + +target_link_libraries(jwm PRIVATE wayland-client::wayland-client, decor::decor, wayland-cursor::wayland-cursor) +target_link_libraries(jwm PRIVATE OpenGL::GL) diff --git a/linux/cc/AppX11.cc b/wayland/cc/AppWayland.cc similarity index 100% rename from linux/cc/AppX11.cc rename to wayland/cc/AppWayland.cc diff --git a/wayland/cc/AppWayland.hh b/wayland/cc/AppWayland.hh new file mode 100644 index 00000000..d6953aae --- /dev/null +++ b/wayland/cc/AppWayland.hh @@ -0,0 +1,35 @@ +#pragma once + +#include "WindowManagerX11.hh" +#include +#include "Types.hh" +#include +#include "impl/Library.hh" +#include "ScreenInfo.hh" + +namespace jwm { + extern class AppX11 { + public: + + void init(JNIEnv* jniEnv); + void start(); + void terminate(); + + WindowManagerX11& getWindowManager() { + return wm; + } + + JNIEnv* getJniEnv() { + return _jniEnv; + } + + const std::vector& getScreens(); + + float getScale(); + + JNIEnv* _jniEnv; + WindowManagerX11 wm; + std::vector _screens; + + } app; +} diff --git a/linux/cc/ClipboardX11.cc b/wayland/cc/ClipboardWayland.cc similarity index 100% rename from linux/cc/ClipboardX11.cc rename to wayland/cc/ClipboardWayland.cc diff --git a/linux/cc/KeyX11.cc b/wayland/cc/KeyWayland.cc similarity index 100% rename from linux/cc/KeyX11.cc rename to wayland/cc/KeyWayland.cc diff --git a/linux/cc/KeyX11.hh b/wayland/cc/KeyWayland.hh similarity index 100% rename from linux/cc/KeyX11.hh rename to wayland/cc/KeyWayland.hh diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc new file mode 100644 index 00000000..aa78e4ee --- /dev/null +++ b/wayland/cc/LayerGLWayland.cc @@ -0,0 +1,123 @@ +#include +#include +#include +#include "impl/Library.hh" +#include "impl/RefCounted.hh" +#include "WindowX11.hh" +#include + +namespace jwm { + + class LayerGL: public RefCounted, public ILayer { + public: + WindowX11* fWindow; + GLXContext _context = nullptr; + using glXSwapIntervalEXT_t = void (*)(Display*, GLXDrawable, int); + glXSwapIntervalEXT_t _glXSwapIntervalEXT; + + LayerGL() = default; + virtual ~LayerGL() = default; + + void attach(WindowX11* window) { + if (window->_windowManager.getVisualInfo() == nullptr) { + throw std::runtime_error("layer not supported"); + } + + fWindow = jwm::ref(window); + fWindow->setLayer(this); + + if (_context == nullptr) { + _context = glXCreateContext(window->_windowManager.getDisplay(), + window->_windowManager.getVisualInfo(), + nullptr, + true); + + } + + makeCurrentForced(); + + _glXSwapIntervalEXT = reinterpret_cast(glXGetProcAddress(reinterpret_cast("glXSwapIntervalEXT"))); + setVsyncMode(VSYNC_ADAPTIVE); + } + + void setVsyncMode(VSync v) override { + + if (_glXSwapIntervalEXT) { + _glXSwapIntervalEXT(fWindow->_windowManager.getDisplay(), + fWindow->_x11Window, + v); + } + } + + void resize(int width, int height) { + glClearStencil(0); + glClearColor(0, 0, 0, 255); + glStencilMask(0xffffffff); + glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + glViewport(0, 0, width, height); + } + + void swapBuffers() { + glXSwapBuffers(fWindow->_windowManager.getDisplay(), fWindow->_x11Window); + } + + void close() override { + glXDestroyContext(fWindow->_windowManager.getDisplay(), _context); + jwm::unref(&fWindow); + } + + void makeCurrentForced() override { + ILayer::makeCurrentForced(); + glXMakeCurrent(fWindow->_windowManager.getDisplay(), + fWindow->_x11Window, + _context); + } + }; + +} // namespace jwm + +// JNI + +extern "C" JNIEXPORT jlong JNICALL Java_io_github_humbleui_jwm_LayerGL__1nMake + (JNIEnv* env, jclass jclass) { + jwm::LayerGL* instance = new jwm::LayerGL(); + return reinterpret_cast(instance); +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerGL__1nAttach + (JNIEnv* env, jobject obj, jobject windowObj) { + try { + jwm::LayerGL* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + jwm::WindowX11* window = reinterpret_cast(jwm::classes::Native::fromJava(env, windowObj)); + instance->attach(window); + } catch (const std::exception& e) { + jwm::classes::Throwable::throwLayerNotSupportedException(env, "Failed to init OpenGL"); + } +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerGL__1nReconfigure + (JNIEnv* env, jobject obj, jint width, jint height) { +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerGL__1nResize + (JNIEnv* env, jobject obj, jint width, jint height) { + jwm::LayerGL* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + instance->resize(width, height); +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerGL__1nMakeCurrent + (JNIEnv* env, jobject obj) { +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerGL__1nSwapBuffers + (JNIEnv* env, jobject obj) { + jwm::LayerGL* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + instance->swapBuffers(); +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerGL__1nClose + (JNIEnv* env, jobject obj) { + jwm::LayerGL* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + instance->close(); +} diff --git a/linux/cc/LayerRaster.cc b/wayland/cc/LayerRasterWayland.cc similarity index 100% rename from linux/cc/LayerRaster.cc rename to wayland/cc/LayerRasterWayland.cc diff --git a/linux/cc/MouseButtonX11.cc b/wayland/cc/MouseButtonWayland.cc similarity index 100% rename from linux/cc/MouseButtonX11.cc rename to wayland/cc/MouseButtonWayland.cc diff --git a/linux/cc/MouseButtonX11.hh b/wayland/cc/MouseButtonWayland.hh similarity index 100% rename from linux/cc/MouseButtonX11.hh rename to wayland/cc/MouseButtonWayland.hh diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc new file mode 100644 index 00000000..e8f799d3 --- /dev/null +++ b/wayland/cc/WindowManagerWayland.cc @@ -0,0 +1,330 @@ +#include "WindowManagerWayland.hh" +#include "WindowWayland.hh" +#include +#include +#include +#include +#include "AppWayland.hh" +#include +#include +#include +#include "KeyWayland.hh" +#include "MouseButtonWayland.hh" +#include "StringUTF16.hh" +#include +#include +#include "Log.hh" + +using namespace jwm; + + +WindowManagerWayland::WindowManagerWayland(): + display(wl_display_connect(nullptr)) { + registry = wl_display_get_registry(display); + wl_registry_listener registry_listener = { + .global = registryGlobalHandler, + .global_remove = registryGlobalHandlerRemove + }; + wl_registry_add_listener(registry, ®istry_listener, nullptr); + + wl_display_roundtrip(display); + + if (!(shm && xdgShell && compositor && deviceManager && seat)) { + // ??? + // Bad. Means our compositor no supportie : ( + throw std::system_error(1, std::system_category); + } + + { + wl_cursor_theme* cursor_theme = wl_cursor_theme_load(nullptr, 24, shm); + // TODO: what about if missing : ( + auto loadCursor = [&](const char* name) { + wl_cursor* cursor = wl_cursor_theme_get_cursor(cursor_theme, name); + wl_cursor_image* cursorImage = cursor->images[0]; + return wl_cursor_image_get_buffer(cursorImage); + } + + _cursors[static_cast(jwm::MouseCursor::ARROW )] = loadCursor("default"); + _cursors[static_cast(jwm::MouseCursor::CROSSHAIR )] = loadCursor("crosshair"); + _cursors[static_cast(jwm::MouseCursor::HELP )] = loadCursor("help"); + _cursors[static_cast(jwm::MouseCursor::POINTING_HAND )] = loadCursor("pointer"); + _cursors[static_cast(jwm::MouseCursor::IBEAM )] = loadCursor("text"); + _cursors[static_cast(jwm::MouseCursor::NOT_ALLOWED )] = loadCursor("not-allowed"); + _cursors[static_cast(jwm::MouseCursor::WAIT )] = loadCursor("watch"); + _cursors[static_cast(jwm::MouseCursor::RESIZE_NS )] = loadCursor("ns-resize"); + _cursors[static_cast(jwm::MouseCursor::RESIZE_WE )] = loadCursor("ew-resize"); + _cursors[static_cast(jwm::MouseCursor::RESIZE_NESW )] = loadCursor("nesw-resize"); + _cursors[static_cast(jwm::MouseCursor::RESIZE_NWSE )] = loadCursor("nwse-resize"); + } + +} + + + + +void WindowManagerWayland::runLoop() { + _runLoop = true; + XEvent ev; + + // buffer to read into; really only needs to be two characters long due to the notifyBool fast path, but longer doesn't hurt + char buf[100]; + // initialize a pipe to write to whenever this loop needs to process something new + int pipes[2]; + if (pipe(pipes)) { + printf("Failed to open pipe\n"); + return; + } + + notifyFD = pipes[1]; + fcntl(pipes[1], F_SETFL, O_NONBLOCK); // make sure notifyLoop doesn't block + // two polled items - the X11 event queue, and our event queue + struct pollfd ps[] = {{.fd=XConnectionNumber(display), .events=POLLIN}, {.fd=pipes[0], .events=POLLIN}}; + + while (_runLoop) { + while (XPending(display)) { + XNextEvent(display, &ev); + _processXEvent(ev); + if (jwm::classes::Throwable::exceptionThrown(app.getJniEnv())) + _runLoop = false; + } + _processCallbacks(); + + // block until the next X11 or our event + if (poll(&ps[0], 2, -1) < 0) { + printf("Error during poll\n"); + break; + } + + // clear pipe + if (ps[1].revents & POLLIN) { + while (read(pipes[0], buf, sizeof(buf)) == sizeof(buf)) { } + } + // clear fast path boolean; done after clearing the pipe so that, during event execution, new notifyLoop calls can still function + notifyBool.store(false); + // The events causing a notifyLoop anywhere between poll() end and here will be processed in all cases, as that's the next thing that happens + } + + notifyFD = -1; + close(pipes[0]); + close(pipes[1]); +} + +void WindowManagerWayland::notifyLoop() { + if (notifyFD==-1) return; + // fast notifyBool path to not make system calls when not necessary + if (!notifyBool.exchange(true)) { + char dummy[1] = {0}; + int unused = write(notifyFD, dummy, 1); // this really shouldn't fail, but if it does, the pipe should either be full (good), or dead (bad, but not our business) + } +} + +void WindowManagerWayland::_processCallbacks() { + { + // process ui thread callbacks + std::unique_lock lock(_taskQueueLock); + + while (!_taskQueue.empty()) { + auto callback = std::move(_taskQueue.front()); + _taskQueue.pop(); + lock.unlock(); + callback(); + lock.lock(); + } + } + { + // copy window list in case one closes any other, invalidating some iterator in _nativeWindowToMy + std::vector copy; + for (auto& p : _nativeWindowToMy) { + copy.push_back(p.second); + } + // process redraw requests + for (auto p : copy) { + if (p->isRedrawRequested()) { + p->unsetRedrawRequest(); + if (p->_layer) { + p->_layer->makeCurrent(); + } + p->dispatch(classes::EventFrame::kInstance); + } + } + } +} + +void WindowManagerWayland::registryHandleGlobal(void* data, wl_registry *registry, + uint32_t name, const char* interface, uint32_t version) { + if (strcmp(interface, "wl_compositor") == 0) { + compositor = wl_registry_bind(registry, name, + &wl_compositor_interface, 3); + } else if (strcmp(interface, "wl_shm") == 0) { + shm = wl_registry_bind(registry, name, + &wl_shm_interface, 1); + } else if (strcmp(interface, "zxdg_shell_v6") == 0) { + xdgShell = wl_registry_bind(registry, name, + &zxdg_shell_v6_interface, 1); + } else if (strcmp(interface, "wl_data_device_manager") == 0) { + deviceManager = wl_registry_bind(registry, name, + &wl_data_device_manager_interface, 1); + } else if (strcmp(interface, "wl_seat") == 0) { + seat = wl_registry_bind(registry, name, + &wl_seat_interface, 1); + } +} +void WindowManagerWayland::registryHandleGlobalRemove(void* data, wl_registry *registry, uint32_t name) { + // i do nothing : ) +} +std::vector WindowManagerWayland::getClipboardFormats() { + auto owner = XGetSelectionOwner(display, _atoms.CLIPBOARD); + if (owner == None) + { + return {}; + } + + assert(("create at least one window in order to use clipboard" && !_nativeWindowToMy.empty())); + + auto nativeHandle = _nativeWindowToMy.begin()->first; + assert(nativeHandle); + + XConvertSelection(display, + _atoms.CLIPBOARD, + _atoms.TARGETS, + _atoms.JWM_CLIPBOARD, + nativeHandle, + CurrentTime); + + XEvent ev; + + // fetch mime types + std::vector result; + + // using lambda here in order to break 2 loops + [&]{ + while (_runLoop) { + while (XPending(display)) { + XNextEvent(display, &ev); + if (ev.type == SelectionNotify) { + int format; + unsigned long count, lengthInBytes; + Atom type; + Atom* properties; + XGetWindowProperty(display, nativeHandle, _atoms.JWM_CLIPBOARD, 0, 1024 * sizeof(Atom), false, XA_ATOM, &type, &format, &count, &lengthInBytes, reinterpret_cast(&properties)); + + for (unsigned long i = 0; i < count; ++i) { + char* str = XGetAtomName(display, properties[i]); + if (str) { + std::string s = str; + // include only mime types + if (s.find('/') != std::string::npos) { + result.push_back(s); + } else if (s == "UTF8_STRING") { + // HACK: treat UTF8_STRING as text/plain under the hood + // avoid duplicates + std::string textPlain = "text/plain"; + if (std::find(result.begin(), result.end(), textPlain) != result.end()) { + result.push_back(textPlain); + } + } + XFree(str); + } + } + + XFree(properties); + return; + } else { + _processXEvent(ev); + } + + } + _processCallbacks(); + } + }(); + + // fetching data + + XDeleteProperty(display, nativeHandle, _atoms.JWM_CLIPBOARD); + return result; +} + +jwm::ByteBuf WindowManagerWayland::getClipboardContents(const std::string& type) { + auto nativeHandle = _nativeWindowToMy.begin()->first; + + XConvertSelection(display, + _atoms.CLIPBOARD, + XInternAtom(display, type.c_str(), false), + _atoms.JWM_CLIPBOARD, + nativeHandle, + CurrentTime); + XEvent ev; + while (_runLoop) { + while (XPending(display)) { + XNextEvent(display, &ev); + switch (ev.type) + { + case SelectionNotify: { + if (ev.xselection.property == None) { + return {}; + } + + Atom da, incr, type; + int di; + unsigned long size, length, count; + unsigned char* propRet = NULL; + + XGetWindowProperty(display, nativeHandle, _atoms.JWM_CLIPBOARD, 0, 0, False, AnyPropertyType, + &type, &di, &length, &size, &propRet); + XFree(propRet); + + // Clipboard data is too large and INCR mechanism not implemented + ByteBuf result; + if (type != _atoms.INCR) + { + XGetWindowProperty(display, nativeHandle, _atoms.JWM_CLIPBOARD, 0, size, False, AnyPropertyType, + &da, &di, &length, &count, &propRet); + + result = ByteBuf{ propRet, propRet + length }; + XFree(propRet); + return result; + } + XDeleteProperty(display, nativeHandle, _atoms.JWM_CLIPBOARD); + return result; + } + default: + _processXEvent(ev); + } + } + _processCallbacks(); + } + + XDeleteProperty(display, nativeHandle, _atoms.JWM_CLIPBOARD); + return {}; +} + +void WindowManagerWayland::registerWindow(WindowWayland* window) { + _nativeWindowToMy[window->_waylandWindow] = window; +} + +void WindowManagerWayland::unregisterWindow(WindowX11* window) { + auto it = _nativeWindowToMy.find(window->_waylandWindow); + if (it != _nativeWindowToMy.end()) { + _nativeWindowToMy.erase(it); + } +} + +void WindowManagerWayland::terminate() { + _runLoop = false; + notifyLoop(); +} + +void WindowManagerWayland::setClipboardContents(std::map&& c) { + assert(("create at least one window in order to use clipboard" && !_nativeWindowToMy.empty())); + _myClipboardContents = c; + ::Window window = _nativeWindowToMy.begin()->first; + XSetSelectionOwner(display, XA_PRIMARY, window, CurrentTime); + XSetSelectionOwner(display, _atoms.CLIPBOARD, window, CurrentTime); +} + +void WindowManagerWayland::enqueueTask(const std::function& task) { + std::unique_lock lock(_taskQueueLock); + _taskQueue.push(task); + _taskQueueNotify.notify_one(); + notifyLoop(); +} diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh new file mode 100644 index 00000000..a5c30afc --- /dev/null +++ b/wayland/cc/WindowManagerWayland.hh @@ -0,0 +1,96 @@ +#pragma once + +#include +#include +#include +#include +#include +#include "Types.hh" +#include +#include +#include +#include +#include "MouseCursor.hh" +#include +#include +#include "xdg_shell.h" + +namespace jwm { + class WindowWayland; + class WindowManagerWayland { + public: + WindowManagerWayland(); + + void runLoop(); + void terminate(); + + void registerWindow(WindowWayland* window); + void unregisterWindow(WindowWayland* window); + + // XVisualInfo* pickVisual(); + // static int _xerrorhandler(Display* dsp, XErrorEvent* error); + // void _xi2IterateDevices(); + + // XVisualInfo* getVisualInfo() const { return x11VisualInfo; } + // XSetWindowAttributes& getSWA() { return x11SWA; } + // XIM getIM() const { return _im; } + /* + int getX11VisualDepth() const { + if (x11VisualInfo) { + return x11VisualInfo->depth; + } + return DefaultDepth(display, 0); + } + Visual* getX11Visual() const { + if (x11VisualInfo) { + return x11VisualInfo->visual; + } + return DefaultVisual(display, 0); + } + */ + void enqueueTask(const std::function& task); + + void registryHandleGlobal(void* data, wl_registry *registry, + uint32_t name, const char* interface, uint32_t version); + void registryHandleGlobalRemove(void* data, wl_registry *registry, + uint32_t name); + + + + ByteBuf getClipboardContents(const std::string& type); + std::vector getClipboardFormats(); + + wl_display* display = nullptr + wl_registry* registry = nullptr + wl_shm* shm = nullptr; + zxdg_shell_v6* xdgShell = nullptr; + wl_compositor* compositor = nullptr; + wl_data_device_manager* deviceManager = nullptr; + wl_seat* seat = nullptr; + + // XVisualInfo* x11VisualInfo; + // XSetWindowAttributes x11SWA; + bool _runLoop; + int notifyFD = -1; + std::atomic_bool notifyBool{false}; + int lastMousePosX = 0; + int lastMousePosY = 0; + void mouseUpdate(WindowWayland* myWindow); + + std::map<::Window, WindowWayland*> _nativeWindowToMy; + std::map _myClipboardContents; + + + wl_surface* cursorSurface; + // Is holding all cursors in memory a good idea? + wl_buffer _cursors[static_cast(jwm::MouseCursor::COUNT)]; + + + std::mutex _taskQueueLock; + std::condition_variable _taskQueueNotify; + std::queue> _taskQueue; + + + void setClipboardContents(std::map&& c); + }; +} diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc new file mode 100644 index 00000000..4d1c525f --- /dev/null +++ b/wayland/cc/WindowWayland.cc @@ -0,0 +1,585 @@ +#include "WindowWayland.hh" +#include +#include +#include +#include "AppWayland.hh" +#include "impl/Library.hh" +#include "impl/JNILocal.hh" +#include + +using namespace jwm; + + +WindowWayland::WindowWayland(JNIEnv* env, WindowManagerWayland& windowManager): + jwm::Window(env), + _windowManager(windowManager) +{ +} + +WindowWayland::~WindowWayland() { + close(); +} + +void WindowWayland::setTitle(const std::string& title) { + XChangeProperty(_windowManager.getDisplay(), + _x11Window, + _windowManager.getAtoms()._NET_WM_NAME, + _windowManager.getAtoms().UTF8_STRING, + 8, + PropModeReplace, + reinterpret_cast(title.c_str()), + title.length()); +} + +void WindowX11::setTitlebarVisible(bool isVisible) { + MotifHints motifHints = {0}; + + motifHints.flags = MOTIF_HINTS_DECORATIONS; + motifHints.decorations = int(isVisible); + + XChangeProperty(_windowManager.getDisplay(), + _x11Window, + _windowManager.getAtoms()._MOTIF_WM_HINTS, + _windowManager.getAtoms()._MOTIF_WM_HINTS, + 32, + PropModeReplace, + (unsigned char*) &motifHints, + 5); +} + +void WindowX11::close() { + if (_x11Window) { + _windowManager.unregisterWindow(this); + XDestroyWindow(_windowManager.display, _x11Window); + _x11Window = 0; + } +} +void WindowX11::_xSendEventToWM(Atom atom, long a, long b, long c, long d, long e) const { + XEvent event = { 0 }; + event.type = ClientMessage; + event.xclient.window = _x11Window; + event.xclient.format = 32; // data is 32-bit longs + event.xclient.message_type = atom; + event.xclient.data.l[0] = a; + event.xclient.data.l[1] = b; + event.xclient.data.l[2] = c; + event.xclient.data.l[3] = d; + event.xclient.data.l[4] = e; + + XSendEvent(_windowManager.display, + DefaultRootWindow(_windowManager.display), + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event); +} +unsigned long WindowX11::_xGetWindowProperty(Atom property, Atom type, unsigned char** value) const { + Atom actualType; + int actualFormat; + unsigned long itemCount, bytesAfter; + + XGetWindowProperty(_windowManager.display, + _x11Window, + property, + 0, + std::numeric_limits::max(), + false, + type, + &actualType, + &actualFormat, + &itemCount, + &bytesAfter, + value); + + return itemCount; +} + +void WindowX11::maximize() { + XWindowAttributes wa; + XGetWindowAttributes(_windowManager.display, _x11Window, &wa); + + if (wa.map_state == IsViewable) { + _xSendEventToWM(_windowManager._atoms._NET_WM_STATE, + 1, + _windowManager._atoms._NET_WM_STATE_MAXIMIZED_HORZ, + _windowManager._atoms._NET_WM_STATE_MAXIMIZED_VERT, + 0, + 0); + } else { + Atom* states = nullptr; + unsigned long count = _xGetWindowProperty(_windowManager._atoms._NET_WM_STATE, + XA_ATOM, + reinterpret_cast(&states)); + + + Atom missing[2] = { + _windowManager._atoms._NET_WM_STATE_MAXIMIZED_VERT, + _windowManager._atoms._NET_WM_STATE_MAXIMIZED_HORZ + }; + unsigned long missingCount = 2; + + for (unsigned long i = 0; i < count; i++) + { + for (unsigned long j = 0; j < missingCount; j++) + { + if (states[i] == missing[j]) + { + missing[j] = missing[missingCount - 1]; + missingCount--; + } + } + } + + if (states) + XFree(states); + + if (!missingCount) + return; + + XChangeProperty(_windowManager.display, + _x11Window, + _windowManager._atoms._NET_WM_STATE, + XA_ATOM, + 32, + PropModeAppend, + (unsigned char*) missing, + missingCount); + } + XFlush(_windowManager.display); +} + +void WindowX11::minimize() { + XIconifyWindow(_windowManager.display, _x11Window, 0); +} + +void WindowX11::restore() { + if (_windowManager._atoms._NET_WM_STATE && + _windowManager._atoms._NET_WM_STATE_MAXIMIZED_VERT && + _windowManager._atoms._NET_WM_STATE_MAXIMIZED_HORZ) { + _xSendEventToWM(_windowManager._atoms._NET_WM_STATE, + 0, + _windowManager._atoms._NET_WM_STATE_MAXIMIZED_VERT, + _windowManager._atoms._NET_WM_STATE_MAXIMIZED_HORZ, + 1, + 0); + } +} + +void WindowX11::setFullScreen(bool isFullScreen) { + // NOTE: Largely borrowed from https://github.com/godotengine/godot/blob/f7cf9fb148140b86ee5795110373a0d55ff32860/platform/linuxbsd/x11/display_server_x11.cpp + Display* display = _windowManager.display; + + // Should the window be exclusively full screen (i.e. block out other popups). + // There isn't a HumbleUI setting for this, and my WM defaults to exclusive full-screen, + // (as does Windows, as I recall) so let's assume that we want the window to be exclusively fullscreen. + bool isExclusiveFullScreen = true; + + if (isFullScreen) { // and the window is not borderless: + // Remove window decorations to simulate full screen + MotifHints hints; + Atom property; + hints.flags = 2; + hints.decorations = 0; + property = XInternAtom(display, "_MOTIF_WM_HINTS", True); + if (property != None) { + XChangeProperty(display, _x11Window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); + } + } + + XEvent xev; + + memset(&xev, 0, sizeof(xev)); + xev.type = ClientMessage; + xev.xclient.window = _x11Window; + xev.xclient.message_type = _windowManager._atoms._NET_WM_STATE; + xev.xclient.format = 32; + xev.xclient.data.l[0] = isFullScreen ? _WM_ADD : _WM_REMOVE; + xev.xclient.data.l[1] = _windowManager._atoms._NET_WM_STATE_FULLSCREEN; + xev.xclient.data.l[2] = 0; + + XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); + + // set bypass compositor hint + Atom bypass_compositor = XInternAtom(display, "_NET_WM_BYPASS_COMPOSITOR", True); + unsigned long compositing_disable_on = 0; // By default, don't allow window compositing + + if (isFullScreen) { + // NOTE: Compositor flickers. May be an issue. + if (isExclusiveFullScreen) { + compositing_disable_on = 1; // Force compositing to disable for efficiency + } else { + compositing_disable_on = 2; // Force composition on to allow pop-up windows + } + } + + if (bypass_compositor != None) { + XChangeProperty(display, + _x11Window, + bypass_compositor, + XA_CARDINAL, + 32, + PropModeReplace, + (unsigned char *)&compositing_disable_on, + 1); + } + + XFlush(display); + + if (!isFullScreen) { + // Reset window decorations to their previous states + MotifHints hints; + Atom property; + hints.flags = 2; + hints.decorations = 1; // Add window borders back + property = XInternAtom(display, "_MOTIF_WM_HINTS", True); + if (property != None) { + XChangeProperty(display, + _x11Window, + property, + property, + 32, + PropModeReplace, + (unsigned char *)&hints, + 5); + } + } +} + +bool WindowX11::isFullScreen() { + // NOTE: Largely borrowed from https://github.com/godotengine/godot/blob/f7cf9fb148140b86ee5795110373a0d55ff32860/platform/linuxbsd/x11/display_server_x11.cpp + Display* display = _windowManager.display; + + Atom type; + int format; + unsigned long len; + unsigned long remaining; + unsigned char *data = nullptr; + bool retval = false; + + int result = XGetWindowProperty( + display, + _x11Window, + _windowManager._atoms._NET_WM_STATE, + 0, + 1024, + False, + XA_ATOM, + &type, + &format, + &len, + &remaining, + &data); + + if (result == Success) { + Atom *atoms = (Atom *)data; + for (uint64_t i = 0; i < len; i++) { + if (atoms[i] == _windowManager._atoms._NET_WM_STATE_FULLSCREEN) { + retval = true; + break; + } + } + XFree(data); + } + + return retval; +} + +void WindowX11::getDecorations(int& left, int& top, int& right, int& bottom) { + unsigned long* data = nullptr; + _xGetWindowProperty(_windowManager.getAtoms()._NET_FRAME_EXTENTS, XA_CARDINAL, reinterpret_cast(&data)); + if (data!=nullptr) { + left = data[0]; + top = data[2]; + right = data[1]; + bottom = data[3]; + XFree(data); + } else { + XWindowAttributes xwa; + XGetWindowAttributes(_windowManager.display, _x11Window, &xwa); + left = xwa.x; + top = xwa.y; + right = 0; + bottom = 0; + } +} + +void WindowX11::getContentPosition(int& posX, int& posY) { + int x, y; + ::Window child; + XTranslateCoordinates(_windowManager.display, + _x11Window, + XRootWindow(_windowManager.display, 0), + 0, 0, + &x, &y, + &child); + posX = x; + posY = y; + +} + +int WindowX11::getLeft() { + int x, y; + getContentPosition(x, y); + return x; +} + +int WindowX11::getTop() { + int x, y; + getContentPosition(x, y); + return y; +} + +int WindowX11::getWidth() { + return _width; +} + +int WindowX11::getHeight() { + return _height; +} + +float WindowX11::getScale() { + return jwm::app.getScale(); +} + +bool WindowX11::init() +{ + _x11Window = XCreateWindow(_windowManager.getDisplay(), + _windowManager.getScreen()->root, + 0, 0, + 800, 500, + 0, + _windowManager.getX11VisualDepth(), + InputOutput, + _windowManager.getX11Visual(), + CWColormap | CWEventMask | CWCursor, + &_windowManager.getSWA() + ); + + // tell X11 we want to handle close button + XSetWMProtocols(_windowManager.getDisplay(), + _x11Window, + &_windowManager.getAtoms().WM_DELETE_WINDOW, + WindowManagerX11::Atoms::PROTOCOL_COUNT); + + // IC + { + _ic = XCreateIC(_windowManager.getIM(), + XNInputStyle, + XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, + _x11Window, + nullptr); + + XSetICFocus(_ic); + } + + + + // XSync + { + XSyncValue value; + XSyncIntToValue(&value, 0); + _xsyncRequestCounter.counter = XSyncCreateCounter(_windowManager.getDisplay(), value); + XChangeProperty(_windowManager.getDisplay(), + _x11Window, + _windowManager.getAtoms()._NET_WM_SYNC_REQUEST_COUNTER, + XA_CARDINAL, + 32, + PropModeReplace, + (const unsigned char*)&_xsyncRequestCounter.counter, 1); + + } + _windowManager.registerWindow(this); + return true; +} + +void WindowX11::move(int left, int top) { + _posX = left; + _posY = top; + if (_visible) + XMoveWindow(_windowManager.display, _x11Window, left, top); +} + +void WindowX11::resize(int width, int height) { + _width = width; + _height = height; + if (_visible) { + XResizeWindow(_windowManager.display, _x11Window, width, height); + jwm::JNILocal eventWindowResize(app.getJniEnv(), classes::EventWindowResize::make(app.getJniEnv(), width, height, width, height)); + dispatch(eventWindowResize.get()); + } +} + +void WindowX11::setVisible(bool isVisible) { + if (_visible != isVisible) { + _visible = isVisible; + if (_visible) { + XMapWindow(_windowManager.getDisplay(), _x11Window); + if (_posX > 0 && _posY > 0) + move(_posX, _posY); + if (_width > 0 && _height > 0) + resize(_width, _height); + } else { + XUnmapWindow(_windowManager.getDisplay(), _x11Window); + } + } +} + +const ScreenInfo& WindowX11::getScreen() { + // in X11, there's no straightforward way to get screen of window. + // instead, we should do it manually using center point of the window and calculating which monitor this point + // belongs to. + + int centerX = getLeft() + getWidth() / 2; + int centerY = getTop() + getHeight() / 2; + for (auto& screen : jwm::app.getScreens()) { + if (screen.bounds.isPointInside(centerX, centerY)) { + return screen; + } + } + return *jwm::app.getScreens().begin(); +} + +void jwm::WindowX11::setCursor(jwm::MouseCursor cursor) { + if (auto x11Cursor = _windowManager._cursors[static_cast(cursor)]) { + XDefineCursor(_windowManager.display, _x11Window, x11Cursor); + } else { + XUndefineCursor(_windowManager.display, _x11Window); + } +} + +// JNI + +extern "C" JNIEXPORT jlong JNICALL Java_io_github_humbleui_jwm_WindowX11__1nMake + (JNIEnv* env, jclass jclass) { + std::unique_ptr instance = std::make_unique(env, jwm::app.getWindowManager()); + if (instance->init()) { + return reinterpret_cast(instance.release()); + } + return 0; +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nSetVisible + (JNIEnv* env, jobject obj, jboolean isVisible) { + + reinterpret_cast(jwm::classes::Native::fromJava(env, obj))->setVisible(isVisible); +} + +extern "C" JNIEXPORT jobject JNICALL Java_io_github_humbleui_jwm_WindowX11__1nGetWindowRect + (JNIEnv* env, jobject obj) { + jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + int left, top, right, bottom; + instance->getDecorations(left, top, right, bottom); + int x, y; + instance->getContentPosition(x, y); + return jwm::classes::IRect::toJavaXYWH( + env, + x-left, + y-top, + instance->getWidth()+left+right, + instance->getHeight()+top+bottom + ); +} + +extern "C" JNIEXPORT jobject JNICALL Java_io_github_humbleui_jwm_WindowX11__1nGetContentRect + (JNIEnv* env, jobject obj) { + jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + int left, top, right, bottom; + instance->getDecorations(left, top, right, bottom); + return jwm::classes::IRect::toJavaXYWH( + env, + left, + top, + instance->getWidth(), + instance->getHeight() + ); +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nSetWindowPosition + (JNIEnv* env, jobject obj, int left, int top) { + jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + instance->move(left, top); +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nSetWindowSize + (JNIEnv* env, jobject obj, int width, int height) { + jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + // TODO https://github.com/HumbleUI/JWM/issues/109 + instance->resize(width, height); +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nSetContentSize + (JNIEnv* env, jobject obj, int width, int height) { + jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + instance->resize(width, height); +} + +extern "C" JNIEXPORT jobject JNICALL Java_io_github_humbleui_jwm_WindowX11__1nGetScreen + (JNIEnv* env, jobject obj) { + jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + return instance->getScreen().asJavaObject(env); +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nRequestFrame + (JNIEnv* env, jobject obj) { + jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + instance->requestRedraw(); +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nMaximize + (JNIEnv* env, jobject obj) { + reinterpret_cast(jwm::classes::Native::fromJava(env, obj))->maximize(); +} + + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nMinimize + (JNIEnv* env, jobject obj) { + reinterpret_cast(jwm::classes::Native::fromJava(env, obj))->minimize(); +} + + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nRestore + (JNIEnv* env, jobject obj) { + reinterpret_cast(jwm::classes::Native::fromJava(env, obj))->restore(); +} + + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nClose + (JNIEnv* env, jobject obj) { + jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + instance->close(); +} +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nSetTitle + (JNIEnv* env, jobject obj, jbyteArray title) { + jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + + jbyte* bytes = env->GetByteArrayElements(title, nullptr); + std::string titleS = { bytes, bytes + env->GetArrayLength(title) }; + env->ReleaseByteArrayElements(title, bytes, 0); + + instance->setTitle(titleS); +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nSetTitlebarVisible + (JNIEnv* env, jobject obj, jboolean isVisible) { + jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + instance->setTitlebarVisible(isVisible); +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nSetMouseCursor + (JNIEnv* env, jobject obj, jint idx) { + jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + + instance->setCursor(static_cast(idx)); +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nSetFullScreen + (JNIEnv* env, jobject obj, jboolean isFullScreen) { + jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + instance->setFullScreen(isFullScreen); +} + +extern "C" JNIEXPORT jboolean JNICALL Java_io_github_humbleui_jwm_WindowX11__1nIsFullScreen + (JNIEnv* env, jobject obj) { + jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + return instance->isFullScreen(); +} diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh new file mode 100644 index 00000000..e47e27a0 --- /dev/null +++ b/wayland/cc/WindowWayland.hh @@ -0,0 +1,84 @@ +#pragma once + +#include +#include +#include "Window.hh" +#include "WindowManagerWayland.hh" +#include "ILayer.hh" +#include "ScreenInfo.hh" + +namespace jwm { + class WindowWayland: public jwm::Window { + public: + WindowWayland(JNIEnv* env, WindowManagerWayland& windowManager); + ~WindowWayland() override; + + void getDecorations(int& left, int& top, int& right, int& bottom); + void getContentPosition(int& posX, int& posY); + void setVisible(bool isVisible); + void close(); + bool init(); + int getLeft(); + int getTop(); + int getWidth(); + int getHeight(); + float getScale(); + void move(int left, int top); + void resize(int width, int height); + void requestRedraw() { + _isRedrawRequested = true; + _windowManager.notifyLoop(); + } + void unsetRedrawRequest() { + _isRedrawRequested = false; + } + bool isRedrawRequested() { + return _isRedrawRequested; + } + void setTitle(const std::string& title); + void setTitlebarVisible(bool isVisible); + + void maximize(); + void minimize(); + void restore(); + + void setFullScreen(bool isFullScreen); + bool isFullScreen(); + + XIC getIC() const { + return _ic; + } + void setCursor(jwm::MouseCursor cursor); + void setLayer(ILayer* layer) { + _layer = layer; + } + void _xSendEventToWM(Atom atom, long a, long b, long c, long d, long e) const; + unsigned long _xGetWindowProperty(Atom property, Atom type, unsigned char** value) const; + + const ScreenInfo& getScreen(); + + /** + * _NET_WM_SYNC_REQUEST (resize flicker fix) update request counter + */ + struct { + uint32_t lo = 0; + uint32_t hi = 0; + XID counter; + } _xsyncRequestCounter; + + int _posX = -1; + int _posY = -1; + int _width = -1; + int _height = -1; + int _WM_ADD = 1L; + int _WM_REMOVE = 0L; + bool _visible = false; + + bool _isRedrawRequested = false; + + WindowManagerWayland& _windowManager; + ILayer* _layer = nullptr; + ::Window _waylandWindow = 0; + XIC _ic; + }; +} diff --git a/wayland/cc/xdg-shell.c b/wayland/cc/xdg-shell.c new file mode 100644 index 00000000..68ea631f --- /dev/null +++ b/wayland/cc/xdg-shell.c @@ -0,0 +1,172 @@ +/* Generated by wayland-scanner 1.22.0 */ + +/* + * Copyright © 2008-2013 Kristian Høgsberg + * Copyright © 2013 Rafael Antognolli + * Copyright © 2013 Jasper St. Pierre + * Copyright © 2010-2013 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_output_interface; +extern const struct wl_interface wl_seat_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface zxdg_popup_v6_interface; +extern const struct wl_interface zxdg_positioner_v6_interface; +extern const struct wl_interface zxdg_surface_v6_interface; +extern const struct wl_interface zxdg_toplevel_v6_interface; + +static const struct wl_interface *xdg_shell_unstable_v6_types[] = { + NULL, + NULL, + NULL, + NULL, + &zxdg_positioner_v6_interface, + &zxdg_surface_v6_interface, + &wl_surface_interface, + &zxdg_toplevel_v6_interface, + &zxdg_popup_v6_interface, + &zxdg_surface_v6_interface, + &zxdg_positioner_v6_interface, + &zxdg_toplevel_v6_interface, + &wl_seat_interface, + NULL, + NULL, + NULL, + &wl_seat_interface, + NULL, + &wl_seat_interface, + NULL, + NULL, + &wl_output_interface, + &wl_seat_interface, + NULL, +}; + +static const struct wl_message zxdg_shell_v6_requests[] = { + { "destroy", "", xdg_shell_unstable_v6_types + 0 }, + { "create_positioner", "n", xdg_shell_unstable_v6_types + 4 }, + { "get_xdg_surface", "no", xdg_shell_unstable_v6_types + 5 }, + { "pong", "u", xdg_shell_unstable_v6_types + 0 }, +}; + +static const struct wl_message zxdg_shell_v6_events[] = { + { "ping", "u", xdg_shell_unstable_v6_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zxdg_shell_v6_interface = { + "zxdg_shell_v6", 1, + 4, zxdg_shell_v6_requests, + 1, zxdg_shell_v6_events, +}; + +static const struct wl_message zxdg_positioner_v6_requests[] = { + { "destroy", "", xdg_shell_unstable_v6_types + 0 }, + { "set_size", "ii", xdg_shell_unstable_v6_types + 0 }, + { "set_anchor_rect", "iiii", xdg_shell_unstable_v6_types + 0 }, + { "set_anchor", "u", xdg_shell_unstable_v6_types + 0 }, + { "set_gravity", "u", xdg_shell_unstable_v6_types + 0 }, + { "set_constraint_adjustment", "u", xdg_shell_unstable_v6_types + 0 }, + { "set_offset", "ii", xdg_shell_unstable_v6_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zxdg_positioner_v6_interface = { + "zxdg_positioner_v6", 1, + 7, zxdg_positioner_v6_requests, + 0, NULL, +}; + +static const struct wl_message zxdg_surface_v6_requests[] = { + { "destroy", "", xdg_shell_unstable_v6_types + 0 }, + { "get_toplevel", "n", xdg_shell_unstable_v6_types + 7 }, + { "get_popup", "noo", xdg_shell_unstable_v6_types + 8 }, + { "set_window_geometry", "iiii", xdg_shell_unstable_v6_types + 0 }, + { "ack_configure", "u", xdg_shell_unstable_v6_types + 0 }, +}; + +static const struct wl_message zxdg_surface_v6_events[] = { + { "configure", "u", xdg_shell_unstable_v6_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zxdg_surface_v6_interface = { + "zxdg_surface_v6", 1, + 5, zxdg_surface_v6_requests, + 1, zxdg_surface_v6_events, +}; + +static const struct wl_message zxdg_toplevel_v6_requests[] = { + { "destroy", "", xdg_shell_unstable_v6_types + 0 }, + { "set_parent", "?o", xdg_shell_unstable_v6_types + 11 }, + { "set_title", "s", xdg_shell_unstable_v6_types + 0 }, + { "set_app_id", "s", xdg_shell_unstable_v6_types + 0 }, + { "show_window_menu", "ouii", xdg_shell_unstable_v6_types + 12 }, + { "move", "ou", xdg_shell_unstable_v6_types + 16 }, + { "resize", "ouu", xdg_shell_unstable_v6_types + 18 }, + { "set_max_size", "ii", xdg_shell_unstable_v6_types + 0 }, + { "set_min_size", "ii", xdg_shell_unstable_v6_types + 0 }, + { "set_maximized", "", xdg_shell_unstable_v6_types + 0 }, + { "unset_maximized", "", xdg_shell_unstable_v6_types + 0 }, + { "set_fullscreen", "?o", xdg_shell_unstable_v6_types + 21 }, + { "unset_fullscreen", "", xdg_shell_unstable_v6_types + 0 }, + { "set_minimized", "", xdg_shell_unstable_v6_types + 0 }, +}; + +static const struct wl_message zxdg_toplevel_v6_events[] = { + { "configure", "iia", xdg_shell_unstable_v6_types + 0 }, + { "close", "", xdg_shell_unstable_v6_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zxdg_toplevel_v6_interface = { + "zxdg_toplevel_v6", 1, + 14, zxdg_toplevel_v6_requests, + 2, zxdg_toplevel_v6_events, +}; + +static const struct wl_message zxdg_popup_v6_requests[] = { + { "destroy", "", xdg_shell_unstable_v6_types + 0 }, + { "grab", "ou", xdg_shell_unstable_v6_types + 22 }, +}; + +static const struct wl_message zxdg_popup_v6_events[] = { + { "configure", "iiii", xdg_shell_unstable_v6_types + 0 }, + { "popup_done", "", xdg_shell_unstable_v6_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zxdg_popup_v6_interface = { + "zxdg_popup_v6", 1, + 2, zxdg_popup_v6_requests, + 2, zxdg_popup_v6_events, +}; + diff --git a/wayland/cc/xdg-shell.h b/wayland/cc/xdg-shell.h new file mode 100644 index 00000000..3f4d6846 --- /dev/null +++ b/wayland/cc/xdg-shell.h @@ -0,0 +1,1884 @@ +/* Generated by wayland-scanner 1.22.0 */ + +#ifndef XDG_SHELL_UNSTABLE_V6_CLIENT_PROTOCOL_H +#define XDG_SHELL_UNSTABLE_V6_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_xdg_shell_unstable_v6 The xdg_shell_unstable_v6 protocol + * @section page_ifaces_xdg_shell_unstable_v6 Interfaces + * - @subpage page_iface_zxdg_shell_v6 - create desktop-style surfaces + * - @subpage page_iface_zxdg_positioner_v6 - child surface positioner + * - @subpage page_iface_zxdg_surface_v6 - desktop user interface surface base interface + * - @subpage page_iface_zxdg_toplevel_v6 - toplevel surface + * - @subpage page_iface_zxdg_popup_v6 - short-lived, popup surfaces for menus + * @section page_copyright_xdg_shell_unstable_v6 Copyright + *
+ *
+ * Copyright © 2008-2013 Kristian Høgsberg
+ * Copyright © 2013      Rafael Antognolli
+ * Copyright © 2013      Jasper St. Pierre
+ * Copyright © 2010-2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_output; +struct wl_seat; +struct wl_surface; +struct zxdg_popup_v6; +struct zxdg_positioner_v6; +struct zxdg_shell_v6; +struct zxdg_surface_v6; +struct zxdg_toplevel_v6; + +#ifndef ZXDG_SHELL_V6_INTERFACE +#define ZXDG_SHELL_V6_INTERFACE +/** + * @page page_iface_zxdg_shell_v6 zxdg_shell_v6 + * @section page_iface_zxdg_shell_v6_desc Description + * + * xdg_shell allows clients to turn a wl_surface into a "real window" + * which can be dragged, resized, stacked, and moved around by the + * user. Everything about this interface is suited towards traditional + * desktop environments. + * @section page_iface_zxdg_shell_v6_api API + * See @ref iface_zxdg_shell_v6. + */ +/** + * @defgroup iface_zxdg_shell_v6 The zxdg_shell_v6 interface + * + * xdg_shell allows clients to turn a wl_surface into a "real window" + * which can be dragged, resized, stacked, and moved around by the + * user. Everything about this interface is suited towards traditional + * desktop environments. + */ +extern const struct wl_interface zxdg_shell_v6_interface; +#endif +#ifndef ZXDG_POSITIONER_V6_INTERFACE +#define ZXDG_POSITIONER_V6_INTERFACE +/** + * @page page_iface_zxdg_positioner_v6 zxdg_positioner_v6 + * @section page_iface_zxdg_positioner_v6_desc Description + * + * The xdg_positioner provides a collection of rules for the placement of a + * child surface relative to a parent surface. Rules can be defined to ensure + * the child surface remains within the visible area's borders, and to + * specify how the child surface changes its position, such as sliding along + * an axis, or flipping around a rectangle. These positioner-created rules are + * constrained by the requirement that a child surface must intersect with or + * be at least partially adjacent to its parent surface. + * + * See the various requests for details about possible rules. + * + * At the time of the request, the compositor makes a copy of the rules + * specified by the xdg_positioner. Thus, after the request is complete the + * xdg_positioner object can be destroyed or reused; further changes to the + * object will have no effect on previous usages. + * + * For an xdg_positioner object to be considered complete, it must have a + * non-zero size set by set_size, and a non-zero anchor rectangle set by + * set_anchor_rect. Passing an incomplete xdg_positioner object when + * positioning a surface raises an error. + * @section page_iface_zxdg_positioner_v6_api API + * See @ref iface_zxdg_positioner_v6. + */ +/** + * @defgroup iface_zxdg_positioner_v6 The zxdg_positioner_v6 interface + * + * The xdg_positioner provides a collection of rules for the placement of a + * child surface relative to a parent surface. Rules can be defined to ensure + * the child surface remains within the visible area's borders, and to + * specify how the child surface changes its position, such as sliding along + * an axis, or flipping around a rectangle. These positioner-created rules are + * constrained by the requirement that a child surface must intersect with or + * be at least partially adjacent to its parent surface. + * + * See the various requests for details about possible rules. + * + * At the time of the request, the compositor makes a copy of the rules + * specified by the xdg_positioner. Thus, after the request is complete the + * xdg_positioner object can be destroyed or reused; further changes to the + * object will have no effect on previous usages. + * + * For an xdg_positioner object to be considered complete, it must have a + * non-zero size set by set_size, and a non-zero anchor rectangle set by + * set_anchor_rect. Passing an incomplete xdg_positioner object when + * positioning a surface raises an error. + */ +extern const struct wl_interface zxdg_positioner_v6_interface; +#endif +#ifndef ZXDG_SURFACE_V6_INTERFACE +#define ZXDG_SURFACE_V6_INTERFACE +/** + * @page page_iface_zxdg_surface_v6 zxdg_surface_v6 + * @section page_iface_zxdg_surface_v6_desc Description + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides a base set of functionality required to construct user + * interface elements requiring management by the compositor, such as + * toplevel windows, menus, etc. The types of functionality are split into + * xdg_surface roles. + * + * Creating an xdg_surface does not set the role for a wl_surface. In order + * to map an xdg_surface, the client must create a role-specific object + * using, e.g., get_toplevel, get_popup. The wl_surface for any given + * xdg_surface can have at most one role, and may not be assigned any role + * not based on xdg_surface. + * + * A role must be assigned before any other requests are made to the + * xdg_surface object. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. + * + * Creating an xdg_surface from a wl_surface which has a buffer attached or + * committed is a client error, and any attempts by a client to attach or + * manipulate a buffer prior to the first xdg_surface.configure call must + * also be treated as errors. + * + * For a surface to be mapped by the compositor, the following conditions + * must be met: (1) the client has assigned an xdg_surface based role to the + * surface, (2) the client has set and committed the xdg_surface state and + * the role dependent state to the surface and (3) the client has committed a + * buffer to the surface. + * @section page_iface_zxdg_surface_v6_api API + * See @ref iface_zxdg_surface_v6. + */ +/** + * @defgroup iface_zxdg_surface_v6 The zxdg_surface_v6 interface + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides a base set of functionality required to construct user + * interface elements requiring management by the compositor, such as + * toplevel windows, menus, etc. The types of functionality are split into + * xdg_surface roles. + * + * Creating an xdg_surface does not set the role for a wl_surface. In order + * to map an xdg_surface, the client must create a role-specific object + * using, e.g., get_toplevel, get_popup. The wl_surface for any given + * xdg_surface can have at most one role, and may not be assigned any role + * not based on xdg_surface. + * + * A role must be assigned before any other requests are made to the + * xdg_surface object. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. + * + * Creating an xdg_surface from a wl_surface which has a buffer attached or + * committed is a client error, and any attempts by a client to attach or + * manipulate a buffer prior to the first xdg_surface.configure call must + * also be treated as errors. + * + * For a surface to be mapped by the compositor, the following conditions + * must be met: (1) the client has assigned an xdg_surface based role to the + * surface, (2) the client has set and committed the xdg_surface state and + * the role dependent state to the surface and (3) the client has committed a + * buffer to the surface. + */ +extern const struct wl_interface zxdg_surface_v6_interface; +#endif +#ifndef ZXDG_TOPLEVEL_V6_INTERFACE +#define ZXDG_TOPLEVEL_V6_INTERFACE +/** + * @page page_iface_zxdg_toplevel_v6 zxdg_toplevel_v6 + * @section page_iface_zxdg_toplevel_v6_desc Description + * + * This interface defines an xdg_surface role which allows a surface to, + * among other things, set window-like properties such as maximize, + * fullscreen, and minimize, set application-specific metadata like title and + * id, and well as trigger user interactive operations such as interactive + * resize and move. + * @section page_iface_zxdg_toplevel_v6_api API + * See @ref iface_zxdg_toplevel_v6. + */ +/** + * @defgroup iface_zxdg_toplevel_v6 The zxdg_toplevel_v6 interface + * + * This interface defines an xdg_surface role which allows a surface to, + * among other things, set window-like properties such as maximize, + * fullscreen, and minimize, set application-specific metadata like title and + * id, and well as trigger user interactive operations such as interactive + * resize and move. + */ +extern const struct wl_interface zxdg_toplevel_v6_interface; +#endif +#ifndef ZXDG_POPUP_V6_INTERFACE +#define ZXDG_POPUP_V6_INTERFACE +/** + * @page page_iface_zxdg_popup_v6 zxdg_popup_v6 + * @section page_iface_zxdg_popup_v6_desc Description + * + * A popup surface is a short-lived, temporary surface. It can be used to + * implement for example menus, popovers, tooltips and other similar user + * interface concepts. + * + * A popup can be made to take an explicit grab. See xdg_popup.grab for + * details. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. See the xdg_popup.popup_done + * event for details. + * + * Explicitly destroying the xdg_popup object will also dismiss the popup and + * unmap the surface. Clients that want to dismiss the popup when another + * surface of their own is clicked should dismiss the popup using the destroy + * request. + * + * The parent surface must have either the xdg_toplevel or xdg_popup surface + * role. + * + * A newly created xdg_popup will be stacked on top of all previously created + * xdg_popup surfaces associated with the same xdg_toplevel. + * + * The parent of an xdg_popup must be mapped (see the xdg_surface + * description) before the xdg_popup itself. + * + * The x and y arguments passed when creating the popup object specify + * where the top left of the popup should be placed, relative to the + * local surface coordinates of the parent surface. See + * xdg_surface.get_popup. An xdg_popup must intersect with or be at least + * partially adjacent to its parent surface. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_popup state to take effect. + * @section page_iface_zxdg_popup_v6_api API + * See @ref iface_zxdg_popup_v6. + */ +/** + * @defgroup iface_zxdg_popup_v6 The zxdg_popup_v6 interface + * + * A popup surface is a short-lived, temporary surface. It can be used to + * implement for example menus, popovers, tooltips and other similar user + * interface concepts. + * + * A popup can be made to take an explicit grab. See xdg_popup.grab for + * details. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. See the xdg_popup.popup_done + * event for details. + * + * Explicitly destroying the xdg_popup object will also dismiss the popup and + * unmap the surface. Clients that want to dismiss the popup when another + * surface of their own is clicked should dismiss the popup using the destroy + * request. + * + * The parent surface must have either the xdg_toplevel or xdg_popup surface + * role. + * + * A newly created xdg_popup will be stacked on top of all previously created + * xdg_popup surfaces associated with the same xdg_toplevel. + * + * The parent of an xdg_popup must be mapped (see the xdg_surface + * description) before the xdg_popup itself. + * + * The x and y arguments passed when creating the popup object specify + * where the top left of the popup should be placed, relative to the + * local surface coordinates of the parent surface. See + * xdg_surface.get_popup. An xdg_popup must intersect with or be at least + * partially adjacent to its parent surface. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_popup state to take effect. + */ +extern const struct wl_interface zxdg_popup_v6_interface; +#endif + +#ifndef ZXDG_SHELL_V6_ERROR_ENUM +#define ZXDG_SHELL_V6_ERROR_ENUM +enum zxdg_shell_v6_error { + /** + * given wl_surface has another role + */ + ZXDG_SHELL_V6_ERROR_ROLE = 0, + /** + * xdg_shell was destroyed before children + */ + ZXDG_SHELL_V6_ERROR_DEFUNCT_SURFACES = 1, + /** + * the client tried to map or destroy a non-topmost popup + */ + ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP = 2, + /** + * the client specified an invalid popup parent surface + */ + ZXDG_SHELL_V6_ERROR_INVALID_POPUP_PARENT = 3, + /** + * the client provided an invalid surface state + */ + ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE = 4, + /** + * the client provided an invalid positioner + */ + ZXDG_SHELL_V6_ERROR_INVALID_POSITIONER = 5, +}; +#endif /* ZXDG_SHELL_V6_ERROR_ENUM */ + +/** + * @ingroup iface_zxdg_shell_v6 + * @struct zxdg_shell_v6_listener + */ +struct zxdg_shell_v6_listener { + /** + * check if the client is alive + * + * The ping event asks the client if it's still alive. Pass the + * serial specified in the event back to the compositor by sending + * a "pong" request back with the specified serial. See + * xdg_shell.ping. + * + * Compositors can use this to determine if the client is still + * alive. It's unspecified what will happen if the client doesn't + * respond to the ping request, or in what timeframe. Clients + * should try to respond in a reasonable amount of time. + * + * A compositor is free to ping in any way it wants, but a client + * must always respond to any xdg_shell object it created. + * @param serial pass this to the pong request + */ + void (*ping)(void *data, + struct zxdg_shell_v6 *zxdg_shell_v6, + uint32_t serial); +}; + +/** + * @ingroup iface_zxdg_shell_v6 + */ +static inline int +zxdg_shell_v6_add_listener(struct zxdg_shell_v6 *zxdg_shell_v6, + const struct zxdg_shell_v6_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zxdg_shell_v6, + (void (**)(void)) listener, data); +} + +#define ZXDG_SHELL_V6_DESTROY 0 +#define ZXDG_SHELL_V6_CREATE_POSITIONER 1 +#define ZXDG_SHELL_V6_GET_XDG_SURFACE 2 +#define ZXDG_SHELL_V6_PONG 3 + +/** + * @ingroup iface_zxdg_shell_v6 + */ +#define ZXDG_SHELL_V6_PING_SINCE_VERSION 1 + +/** + * @ingroup iface_zxdg_shell_v6 + */ +#define ZXDG_SHELL_V6_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_shell_v6 + */ +#define ZXDG_SHELL_V6_CREATE_POSITIONER_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_shell_v6 + */ +#define ZXDG_SHELL_V6_GET_XDG_SURFACE_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_shell_v6 + */ +#define ZXDG_SHELL_V6_PONG_SINCE_VERSION 1 + +/** @ingroup iface_zxdg_shell_v6 */ +static inline void +zxdg_shell_v6_set_user_data(struct zxdg_shell_v6 *zxdg_shell_v6, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zxdg_shell_v6, user_data); +} + +/** @ingroup iface_zxdg_shell_v6 */ +static inline void * +zxdg_shell_v6_get_user_data(struct zxdg_shell_v6 *zxdg_shell_v6) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zxdg_shell_v6); +} + +static inline uint32_t +zxdg_shell_v6_get_version(struct zxdg_shell_v6 *zxdg_shell_v6) +{ + return wl_proxy_get_version((struct wl_proxy *) zxdg_shell_v6); +} + +/** + * @ingroup iface_zxdg_shell_v6 + * + * Destroy this xdg_shell object. + * + * Destroying a bound xdg_shell object while there are surfaces + * still alive created by this xdg_shell object instance is illegal + * and will result in a protocol error. + */ +static inline void +zxdg_shell_v6_destroy(struct zxdg_shell_v6 *zxdg_shell_v6) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_shell_v6, + ZXDG_SHELL_V6_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_shell_v6), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zxdg_shell_v6 + * + * Create a positioner object. A positioner object is used to position + * surfaces relative to some parent surface. See the interface description + * and xdg_surface.get_popup for details. + */ +static inline struct zxdg_positioner_v6 * +zxdg_shell_v6_create_positioner(struct zxdg_shell_v6 *zxdg_shell_v6) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) zxdg_shell_v6, + ZXDG_SHELL_V6_CREATE_POSITIONER, &zxdg_positioner_v6_interface, wl_proxy_get_version((struct wl_proxy *) zxdg_shell_v6), 0, NULL); + + return (struct zxdg_positioner_v6 *) id; +} + +/** + * @ingroup iface_zxdg_shell_v6 + * + * This creates an xdg_surface for the given surface. While xdg_surface + * itself is not a role, the corresponding surface may only be assigned + * a role extending xdg_surface, such as xdg_toplevel or xdg_popup. + * + * This creates an xdg_surface for the given surface. An xdg_surface is + * used as basis to define a role to a given surface, such as xdg_toplevel + * or xdg_popup. It also manages functionality shared between xdg_surface + * based surface roles. + * + * See the documentation of xdg_surface for more details about what an + * xdg_surface is and how it is used. + */ +static inline struct zxdg_surface_v6 * +zxdg_shell_v6_get_xdg_surface(struct zxdg_shell_v6 *zxdg_shell_v6, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) zxdg_shell_v6, + ZXDG_SHELL_V6_GET_XDG_SURFACE, &zxdg_surface_v6_interface, wl_proxy_get_version((struct wl_proxy *) zxdg_shell_v6), 0, NULL, surface); + + return (struct zxdg_surface_v6 *) id; +} + +/** + * @ingroup iface_zxdg_shell_v6 + * + * A client must respond to a ping event with a pong request or + * the client may be deemed unresponsive. See xdg_shell.ping. + */ +static inline void +zxdg_shell_v6_pong(struct zxdg_shell_v6 *zxdg_shell_v6, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_shell_v6, + ZXDG_SHELL_V6_PONG, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_shell_v6), 0, serial); +} + +#ifndef ZXDG_POSITIONER_V6_ERROR_ENUM +#define ZXDG_POSITIONER_V6_ERROR_ENUM +enum zxdg_positioner_v6_error { + /** + * invalid input provided + */ + ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT = 0, +}; +#endif /* ZXDG_POSITIONER_V6_ERROR_ENUM */ + +#ifndef ZXDG_POSITIONER_V6_ANCHOR_ENUM +#define ZXDG_POSITIONER_V6_ANCHOR_ENUM +enum zxdg_positioner_v6_anchor { + /** + * the center of the anchor rectangle + */ + ZXDG_POSITIONER_V6_ANCHOR_NONE = 0, + /** + * the top edge of the anchor rectangle + */ + ZXDG_POSITIONER_V6_ANCHOR_TOP = 1, + /** + * the bottom edge of the anchor rectangle + */ + ZXDG_POSITIONER_V6_ANCHOR_BOTTOM = 2, + /** + * the left edge of the anchor rectangle + */ + ZXDG_POSITIONER_V6_ANCHOR_LEFT = 4, + /** + * the right edge of the anchor rectangle + */ + ZXDG_POSITIONER_V6_ANCHOR_RIGHT = 8, +}; +#endif /* ZXDG_POSITIONER_V6_ANCHOR_ENUM */ + +#ifndef ZXDG_POSITIONER_V6_GRAVITY_ENUM +#define ZXDG_POSITIONER_V6_GRAVITY_ENUM +enum zxdg_positioner_v6_gravity { + /** + * center over the anchor edge + */ + ZXDG_POSITIONER_V6_GRAVITY_NONE = 0, + /** + * position above the anchor edge + */ + ZXDG_POSITIONER_V6_GRAVITY_TOP = 1, + /** + * position below the anchor edge + */ + ZXDG_POSITIONER_V6_GRAVITY_BOTTOM = 2, + /** + * position to the left of the anchor edge + */ + ZXDG_POSITIONER_V6_GRAVITY_LEFT = 4, + /** + * position to the right of the anchor edge + */ + ZXDG_POSITIONER_V6_GRAVITY_RIGHT = 8, +}; +#endif /* ZXDG_POSITIONER_V6_GRAVITY_ENUM */ + +#ifndef ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_ENUM +#define ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_ENUM +/** + * @ingroup iface_zxdg_positioner_v6 + * constraint adjustments + * + * The constraint adjustment value define ways the compositor will adjust + * the position of the surface, if the unadjusted position would result + * in the surface being partly constrained. + * + * Whether a surface is considered 'constrained' is left to the compositor + * to determine. For example, the surface may be partly outside the + * compositor's defined 'work area', thus necessitating the child surface's + * position be adjusted until it is entirely inside the work area. + * + * The adjustments can be combined, according to a defined precedence: 1) + * Flip, 2) Slide, 3) Resize. + */ +enum zxdg_positioner_v6_constraint_adjustment { + /** + * don't move the child surface when constrained + * + * Don't alter the surface position even if it is constrained on + * some axis, for example partially outside the edge of a monitor. + */ + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_NONE = 0, + /** + * move along the x axis until unconstrained + * + * Slide the surface along the x axis until it is no longer + * constrained. + * + * First try to slide towards the direction of the gravity on the x + * axis until either the edge in the opposite direction of the + * gravity is unconstrained or the edge in the direction of the + * gravity is constrained. + * + * Then try to slide towards the opposite direction of the gravity + * on the x axis until either the edge in the direction of the + * gravity is unconstrained or the edge in the opposite direction + * of the gravity is constrained. + */ + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1, + /** + * move along the y axis until unconstrained + * + * Slide the surface along the y axis until it is no longer + * constrained. + * + * First try to slide towards the direction of the gravity on the y + * axis until either the edge in the opposite direction of the + * gravity is unconstrained or the edge in the direction of the + * gravity is constrained. + * + * Then try to slide towards the opposite direction of the gravity + * on the y axis until either the edge in the direction of the + * gravity is unconstrained or the edge in the opposite direction + * of the gravity is constrained. + */ + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2, + /** + * invert the anchor and gravity on the x axis + * + * Invert the anchor and gravity on the x axis if the surface is + * constrained on the x axis. For example, if the left edge of the + * surface is constrained, the gravity is 'left' and the anchor is + * 'left', change the gravity to 'right' and the anchor to 'right'. + * + * If the adjusted position also ends up being constrained, the + * resulting position of the flip_x adjustment will be the one + * before the adjustment. + */ + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X = 4, + /** + * invert the anchor and gravity on the y axis + * + * Invert the anchor and gravity on the y axis if the surface is + * constrained on the y axis. For example, if the bottom edge of + * the surface is constrained, the gravity is 'bottom' and the + * anchor is 'bottom', change the gravity to 'top' and the anchor + * to 'top'. + * + * If the adjusted position also ends up being constrained, the + * resulting position of the flip_y adjustment will be the one + * before the adjustment. + */ + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8, + /** + * horizontally resize the surface + * + * Resize the surface horizontally so that it is completely + * unconstrained. + */ + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16, + /** + * vertically resize the surface + * + * Resize the surface vertically so that it is completely + * unconstrained. + */ + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32, +}; +#endif /* ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_ENUM */ + +#define ZXDG_POSITIONER_V6_DESTROY 0 +#define ZXDG_POSITIONER_V6_SET_SIZE 1 +#define ZXDG_POSITIONER_V6_SET_ANCHOR_RECT 2 +#define ZXDG_POSITIONER_V6_SET_ANCHOR 3 +#define ZXDG_POSITIONER_V6_SET_GRAVITY 4 +#define ZXDG_POSITIONER_V6_SET_CONSTRAINT_ADJUSTMENT 5 +#define ZXDG_POSITIONER_V6_SET_OFFSET 6 + + +/** + * @ingroup iface_zxdg_positioner_v6 + */ +#define ZXDG_POSITIONER_V6_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_positioner_v6 + */ +#define ZXDG_POSITIONER_V6_SET_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_positioner_v6 + */ +#define ZXDG_POSITIONER_V6_SET_ANCHOR_RECT_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_positioner_v6 + */ +#define ZXDG_POSITIONER_V6_SET_ANCHOR_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_positioner_v6 + */ +#define ZXDG_POSITIONER_V6_SET_GRAVITY_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_positioner_v6 + */ +#define ZXDG_POSITIONER_V6_SET_CONSTRAINT_ADJUSTMENT_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_positioner_v6 + */ +#define ZXDG_POSITIONER_V6_SET_OFFSET_SINCE_VERSION 1 + +/** @ingroup iface_zxdg_positioner_v6 */ +static inline void +zxdg_positioner_v6_set_user_data(struct zxdg_positioner_v6 *zxdg_positioner_v6, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zxdg_positioner_v6, user_data); +} + +/** @ingroup iface_zxdg_positioner_v6 */ +static inline void * +zxdg_positioner_v6_get_user_data(struct zxdg_positioner_v6 *zxdg_positioner_v6) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zxdg_positioner_v6); +} + +static inline uint32_t +zxdg_positioner_v6_get_version(struct zxdg_positioner_v6 *zxdg_positioner_v6) +{ + return wl_proxy_get_version((struct wl_proxy *) zxdg_positioner_v6); +} + +/** + * @ingroup iface_zxdg_positioner_v6 + * + * Notify the compositor that the xdg_positioner will no longer be used. + */ +static inline void +zxdg_positioner_v6_destroy(struct zxdg_positioner_v6 *zxdg_positioner_v6) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_positioner_v6, + ZXDG_POSITIONER_V6_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_positioner_v6), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zxdg_positioner_v6 + * + * Set the size of the surface that is to be positioned with the positioner + * object. The size is in surface-local coordinates and corresponds to the + * window geometry. See xdg_surface.set_window_geometry. + * + * If a zero or negative size is set the invalid_input error is raised. + */ +static inline void +zxdg_positioner_v6_set_size(struct zxdg_positioner_v6 *zxdg_positioner_v6, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_positioner_v6, + ZXDG_POSITIONER_V6_SET_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_positioner_v6), 0, width, height); +} + +/** + * @ingroup iface_zxdg_positioner_v6 + * + * Specify the anchor rectangle within the parent surface that the child + * surface will be placed relative to. The rectangle is relative to the + * window geometry as defined by xdg_surface.set_window_geometry of the + * parent surface. The rectangle must be at least 1x1 large. + * + * When the xdg_positioner object is used to position a child surface, the + * anchor rectangle may not extend outside the window geometry of the + * positioned child's parent surface. + * + * If a zero or negative size is set the invalid_input error is raised. + */ +static inline void +zxdg_positioner_v6_set_anchor_rect(struct zxdg_positioner_v6 *zxdg_positioner_v6, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_positioner_v6, + ZXDG_POSITIONER_V6_SET_ANCHOR_RECT, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_positioner_v6), 0, x, y, width, height); +} + +/** + * @ingroup iface_zxdg_positioner_v6 + * + * Defines a set of edges for the anchor rectangle. These are used to + * derive an anchor point that the child surface will be positioned + * relative to. If two orthogonal edges are specified (e.g. 'top' and + * 'left'), then the anchor point will be the intersection of the edges + * (e.g. the top left position of the rectangle); otherwise, the derived + * anchor point will be centered on the specified edge, or in the center of + * the anchor rectangle if no edge is specified. + * + * If two parallel anchor edges are specified (e.g. 'left' and 'right'), + * the invalid_input error is raised. + */ +static inline void +zxdg_positioner_v6_set_anchor(struct zxdg_positioner_v6 *zxdg_positioner_v6, uint32_t anchor) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_positioner_v6, + ZXDG_POSITIONER_V6_SET_ANCHOR, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_positioner_v6), 0, anchor); +} + +/** + * @ingroup iface_zxdg_positioner_v6 + * + * Defines in what direction a surface should be positioned, relative to + * the anchor point of the parent surface. If two orthogonal gravities are + * specified (e.g. 'bottom' and 'right'), then the child surface will be + * placed in the specified direction; otherwise, the child surface will be + * centered over the anchor point on any axis that had no gravity + * specified. + * + * If two parallel gravities are specified (e.g. 'left' and 'right'), the + * invalid_input error is raised. + */ +static inline void +zxdg_positioner_v6_set_gravity(struct zxdg_positioner_v6 *zxdg_positioner_v6, uint32_t gravity) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_positioner_v6, + ZXDG_POSITIONER_V6_SET_GRAVITY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_positioner_v6), 0, gravity); +} + +/** + * @ingroup iface_zxdg_positioner_v6 + * + * Specify how the window should be positioned if the originally intended + * position caused the surface to be constrained, meaning at least + * partially outside positioning boundaries set by the compositor. The + * adjustment is set by constructing a bitmask describing the adjustment to + * be made when the surface is constrained on that axis. + * + * If no bit for one axis is set, the compositor will assume that the child + * surface should not change its position on that axis when constrained. + * + * If more than one bit for one axis is set, the order of how adjustments + * are applied is specified in the corresponding adjustment descriptions. + * + * The default adjustment is none. + */ +static inline void +zxdg_positioner_v6_set_constraint_adjustment(struct zxdg_positioner_v6 *zxdg_positioner_v6, uint32_t constraint_adjustment) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_positioner_v6, + ZXDG_POSITIONER_V6_SET_CONSTRAINT_ADJUSTMENT, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_positioner_v6), 0, constraint_adjustment); +} + +/** + * @ingroup iface_zxdg_positioner_v6 + * + * Specify the surface position offset relative to the position of the + * anchor on the anchor rectangle and the anchor on the surface. For + * example if the anchor of the anchor rectangle is at (x, y), the surface + * has the gravity bottom|right, and the offset is (ox, oy), the calculated + * surface position will be (x + ox, y + oy). The offset position of the + * surface is the one used for constraint testing. See + * set_constraint_adjustment. + * + * An example use case is placing a popup menu on top of a user interface + * element, while aligning the user interface element of the parent surface + * with some user interface element placed somewhere in the popup surface. + */ +static inline void +zxdg_positioner_v6_set_offset(struct zxdg_positioner_v6 *zxdg_positioner_v6, int32_t x, int32_t y) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_positioner_v6, + ZXDG_POSITIONER_V6_SET_OFFSET, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_positioner_v6), 0, x, y); +} + +#ifndef ZXDG_SURFACE_V6_ERROR_ENUM +#define ZXDG_SURFACE_V6_ERROR_ENUM +enum zxdg_surface_v6_error { + ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED = 1, + ZXDG_SURFACE_V6_ERROR_ALREADY_CONSTRUCTED = 2, + ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER = 3, +}; +#endif /* ZXDG_SURFACE_V6_ERROR_ENUM */ + +/** + * @ingroup iface_zxdg_surface_v6 + * @struct zxdg_surface_v6_listener + */ +struct zxdg_surface_v6_listener { + /** + * suggest a surface change + * + * The configure event marks the end of a configure sequence. A + * configure sequence is a set of one or more events configuring + * the state of the xdg_surface, including the final + * xdg_surface.configure event. + * + * Where applicable, xdg_surface surface roles will during a + * configure sequence extend this event as a latched state sent as + * events before the xdg_surface.configure event. Such events + * should be considered to make up a set of atomically applied + * configuration states, where the xdg_surface.configure commits + * the accumulated state. + * + * Clients should arrange their surface for the new states, and + * then send an ack_configure request with the serial sent in this + * configure event at some point before committing the new surface. + * + * If the client receives multiple configure events before it can + * respond to one, it is free to discard all but the last event it + * received. + * @param serial serial of the configure event + */ + void (*configure)(void *data, + struct zxdg_surface_v6 *zxdg_surface_v6, + uint32_t serial); +}; + +/** + * @ingroup iface_zxdg_surface_v6 + */ +static inline int +zxdg_surface_v6_add_listener(struct zxdg_surface_v6 *zxdg_surface_v6, + const struct zxdg_surface_v6_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zxdg_surface_v6, + (void (**)(void)) listener, data); +} + +#define ZXDG_SURFACE_V6_DESTROY 0 +#define ZXDG_SURFACE_V6_GET_TOPLEVEL 1 +#define ZXDG_SURFACE_V6_GET_POPUP 2 +#define ZXDG_SURFACE_V6_SET_WINDOW_GEOMETRY 3 +#define ZXDG_SURFACE_V6_ACK_CONFIGURE 4 + +/** + * @ingroup iface_zxdg_surface_v6 + */ +#define ZXDG_SURFACE_V6_CONFIGURE_SINCE_VERSION 1 + +/** + * @ingroup iface_zxdg_surface_v6 + */ +#define ZXDG_SURFACE_V6_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_surface_v6 + */ +#define ZXDG_SURFACE_V6_GET_TOPLEVEL_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_surface_v6 + */ +#define ZXDG_SURFACE_V6_GET_POPUP_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_surface_v6 + */ +#define ZXDG_SURFACE_V6_SET_WINDOW_GEOMETRY_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_surface_v6 + */ +#define ZXDG_SURFACE_V6_ACK_CONFIGURE_SINCE_VERSION 1 + +/** @ingroup iface_zxdg_surface_v6 */ +static inline void +zxdg_surface_v6_set_user_data(struct zxdg_surface_v6 *zxdg_surface_v6, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zxdg_surface_v6, user_data); +} + +/** @ingroup iface_zxdg_surface_v6 */ +static inline void * +zxdg_surface_v6_get_user_data(struct zxdg_surface_v6 *zxdg_surface_v6) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zxdg_surface_v6); +} + +static inline uint32_t +zxdg_surface_v6_get_version(struct zxdg_surface_v6 *zxdg_surface_v6) +{ + return wl_proxy_get_version((struct wl_proxy *) zxdg_surface_v6); +} + +/** + * @ingroup iface_zxdg_surface_v6 + * + * Destroy the xdg_surface object. An xdg_surface must only be destroyed + * after its role object has been destroyed. If the role object still + * exists when this request is issued, the zxdg_shell_v6.defunct_surfaces + * is raised. + */ +static inline void +zxdg_surface_v6_destroy(struct zxdg_surface_v6 *zxdg_surface_v6) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_surface_v6, + ZXDG_SURFACE_V6_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_surface_v6), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zxdg_surface_v6 + * + * This creates an xdg_toplevel object for the given xdg_surface and gives + * the associated wl_surface the xdg_toplevel role. If the surface already + * had a role, the zxdg_shell_v6.role error is raised. + * + * See the documentation of xdg_toplevel for more details about what an + * xdg_toplevel is and how it is used. + */ +static inline struct zxdg_toplevel_v6 * +zxdg_surface_v6_get_toplevel(struct zxdg_surface_v6 *zxdg_surface_v6) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) zxdg_surface_v6, + ZXDG_SURFACE_V6_GET_TOPLEVEL, &zxdg_toplevel_v6_interface, wl_proxy_get_version((struct wl_proxy *) zxdg_surface_v6), 0, NULL); + + return (struct zxdg_toplevel_v6 *) id; +} + +/** + * @ingroup iface_zxdg_surface_v6 + * + * This creates an xdg_popup object for the given xdg_surface and gives the + * associated wl_surface the xdg_popup role. If the surface already + * had a role, the zxdg_shell_v6.role error is raised. + * + * See the documentation of xdg_popup for more details about what an + * xdg_popup is and how it is used. + */ +static inline struct zxdg_popup_v6 * +zxdg_surface_v6_get_popup(struct zxdg_surface_v6 *zxdg_surface_v6, struct zxdg_surface_v6 *parent, struct zxdg_positioner_v6 *positioner) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) zxdg_surface_v6, + ZXDG_SURFACE_V6_GET_POPUP, &zxdg_popup_v6_interface, wl_proxy_get_version((struct wl_proxy *) zxdg_surface_v6), 0, NULL, parent, positioner); + + return (struct zxdg_popup_v6 *) id; +} + +/** + * @ingroup iface_zxdg_surface_v6 + * + * The window geometry of a surface is its "visible bounds" from the + * user's perspective. Client-side decorations often have invisible + * portions like drop-shadows which should be ignored for the + * purposes of aligning, placing and constraining windows. + * + * The window geometry is double buffered, and will be applied at the + * time wl_surface.commit of the corresponding wl_surface is called. + * + * Once the window geometry of the surface is set, it is not possible to + * unset it, and it will remain the same until set_window_geometry is + * called again, even if a new subsurface or buffer is attached. + * + * If never set, the value is the full bounds of the surface, + * including any subsurfaces. This updates dynamically on every + * commit. This unset is meant for extremely simple clients. + * + * The arguments are given in the surface-local coordinate space of + * the wl_surface associated with this xdg_surface. + * + * The width and height must be greater than zero. Setting an invalid size + * will raise an error. When applied, the effective window geometry will be + * the set window geometry clamped to the bounding rectangle of the + * combined geometry of the surface of the xdg_surface and the associated + * subsurfaces. + */ +static inline void +zxdg_surface_v6_set_window_geometry(struct zxdg_surface_v6 *zxdg_surface_v6, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_surface_v6, + ZXDG_SURFACE_V6_SET_WINDOW_GEOMETRY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_surface_v6), 0, x, y, width, height); +} + +/** + * @ingroup iface_zxdg_surface_v6 + * + * When a configure event is received, if a client commits the + * surface in response to the configure event, then the client + * must make an ack_configure request sometime before the commit + * request, passing along the serial of the configure event. + * + * For instance, for toplevel surfaces the compositor might use this + * information to move a surface to the top left only when the client has + * drawn itself for the maximized or fullscreen state. + * + * If the client receives multiple configure events before it + * can respond to one, it only has to ack the last configure event. + * + * A client is not required to commit immediately after sending + * an ack_configure request - it may even ack_configure several times + * before its next surface commit. + * + * A client may send multiple ack_configure requests before committing, but + * only the last request sent before a commit indicates which configure + * event the client really is responding to. + * + * If an invalid serial is used, the zxdg_shell_v6.invalid_surface_state + * error is raised. + */ +static inline void +zxdg_surface_v6_ack_configure(struct zxdg_surface_v6 *zxdg_surface_v6, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_surface_v6, + ZXDG_SURFACE_V6_ACK_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_surface_v6), 0, serial); +} + +#ifndef ZXDG_TOPLEVEL_V6_RESIZE_EDGE_ENUM +#define ZXDG_TOPLEVEL_V6_RESIZE_EDGE_ENUM +/** + * @ingroup iface_zxdg_toplevel_v6 + * edge values for resizing + * + * These values are used to indicate which edge of a surface + * is being dragged in a resize operation. + */ +enum zxdg_toplevel_v6_resize_edge { + ZXDG_TOPLEVEL_V6_RESIZE_EDGE_NONE = 0, + ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP = 1, + ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM = 2, + ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT = 4, + ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_LEFT = 5, + ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_LEFT = 6, + ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT = 8, + ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_RIGHT = 9, + ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_RIGHT = 10, +}; +#endif /* ZXDG_TOPLEVEL_V6_RESIZE_EDGE_ENUM */ + +#ifndef ZXDG_TOPLEVEL_V6_STATE_ENUM +#define ZXDG_TOPLEVEL_V6_STATE_ENUM +/** + * @ingroup iface_zxdg_toplevel_v6 + * types of state on the surface + * + * The different state values used on the surface. This is designed for + * state values like maximized, fullscreen. It is paired with the + * configure event to ensure that both the client and the compositor + * setting the state can be synchronized. + * + * States set in this way are double-buffered. They will get applied on + * the next commit. + */ +enum zxdg_toplevel_v6_state { + /** + * the surface is maximized + * the surface is maximized + * + * The surface is maximized. The window geometry specified in the + * configure event must be obeyed by the client. If the window + * geometry is not obyed, the zxdg_shell_v6.invalid_surface_state + * error is raised. + */ + ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED = 1, + /** + * the surface is fullscreen + * the surface is fullscreen + * + * The surface is fullscreen. See set_fullscreen for more + * information. + */ + ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN = 2, + /** + * the surface is being resized + * the surface is being resized + * + * The surface is being resized. The window geometry specified in + * the configure event is a maximum; the client cannot resize + * beyond it. If the client attempts to resize above it, the + * zxdg_shell_v6.invalid_surface_state error is raised. Clients + * that have aspect ratio or cell sizing configuration can use a + * smaller size, however. + */ + ZXDG_TOPLEVEL_V6_STATE_RESIZING = 3, + /** + * the surface is now activated + * the surface is now activated + * + * Client window decorations should be painted as if the window + * is active. Do not assume this means that the window actually has + * keyboard or pointer focus. + */ + ZXDG_TOPLEVEL_V6_STATE_ACTIVATED = 4, +}; +#endif /* ZXDG_TOPLEVEL_V6_STATE_ENUM */ + +/** + * @ingroup iface_zxdg_toplevel_v6 + * @struct zxdg_toplevel_v6_listener + */ +struct zxdg_toplevel_v6_listener { + /** + * suggest a surface change + * + * This configure event asks the client to resize its toplevel + * surface or to change its state. The configured state should not + * be applied immediately. See xdg_surface.configure for details. + * + * The width and height arguments specify a hint to the window + * about how its surface should be resized in window geometry + * coordinates. See set_window_geometry. + * + * If the width or height arguments are zero, it means the client + * should decide its own window dimension. This may happen when the + * compositor needs to configure the state of the surface but + * doesn't have any information about any previous or expected + * dimension. + * + * The states listed in the event specify how the width/height + * arguments should be interpreted, and possibly how it should be + * drawn. + * + * Clients must send an ack_configure in response to this event. + * See xdg_surface.configure and xdg_surface.ack_configure for + * details. + */ + void (*configure)(void *data, + struct zxdg_toplevel_v6 *zxdg_toplevel_v6, + int32_t width, + int32_t height, + struct wl_array *states); + /** + * surface wants to be closed + * + * The close event is sent by the compositor when the user wants + * the surface to be closed. This should be equivalent to the user + * clicking the close button in client-side decorations, if your + * application has any. + * + * This is only a request that the user intends to close the + * window. The client may choose to ignore this request, or show a + * dialog to ask the user to save their data, etc. + */ + void (*close)(void *data, + struct zxdg_toplevel_v6 *zxdg_toplevel_v6); +}; + +/** + * @ingroup iface_zxdg_toplevel_v6 + */ +static inline int +zxdg_toplevel_v6_add_listener(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, + const struct zxdg_toplevel_v6_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zxdg_toplevel_v6, + (void (**)(void)) listener, data); +} + +#define ZXDG_TOPLEVEL_V6_DESTROY 0 +#define ZXDG_TOPLEVEL_V6_SET_PARENT 1 +#define ZXDG_TOPLEVEL_V6_SET_TITLE 2 +#define ZXDG_TOPLEVEL_V6_SET_APP_ID 3 +#define ZXDG_TOPLEVEL_V6_SHOW_WINDOW_MENU 4 +#define ZXDG_TOPLEVEL_V6_MOVE 5 +#define ZXDG_TOPLEVEL_V6_RESIZE 6 +#define ZXDG_TOPLEVEL_V6_SET_MAX_SIZE 7 +#define ZXDG_TOPLEVEL_V6_SET_MIN_SIZE 8 +#define ZXDG_TOPLEVEL_V6_SET_MAXIMIZED 9 +#define ZXDG_TOPLEVEL_V6_UNSET_MAXIMIZED 10 +#define ZXDG_TOPLEVEL_V6_SET_FULLSCREEN 11 +#define ZXDG_TOPLEVEL_V6_UNSET_FULLSCREEN 12 +#define ZXDG_TOPLEVEL_V6_SET_MINIMIZED 13 + +/** + * @ingroup iface_zxdg_toplevel_v6 + */ +#define ZXDG_TOPLEVEL_V6_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_v6 + */ +#define ZXDG_TOPLEVEL_V6_CLOSE_SINCE_VERSION 1 + +/** + * @ingroup iface_zxdg_toplevel_v6 + */ +#define ZXDG_TOPLEVEL_V6_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_v6 + */ +#define ZXDG_TOPLEVEL_V6_SET_PARENT_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_v6 + */ +#define ZXDG_TOPLEVEL_V6_SET_TITLE_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_v6 + */ +#define ZXDG_TOPLEVEL_V6_SET_APP_ID_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_v6 + */ +#define ZXDG_TOPLEVEL_V6_SHOW_WINDOW_MENU_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_v6 + */ +#define ZXDG_TOPLEVEL_V6_MOVE_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_v6 + */ +#define ZXDG_TOPLEVEL_V6_RESIZE_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_v6 + */ +#define ZXDG_TOPLEVEL_V6_SET_MAX_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_v6 + */ +#define ZXDG_TOPLEVEL_V6_SET_MIN_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_v6 + */ +#define ZXDG_TOPLEVEL_V6_SET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_v6 + */ +#define ZXDG_TOPLEVEL_V6_UNSET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_v6 + */ +#define ZXDG_TOPLEVEL_V6_SET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_v6 + */ +#define ZXDG_TOPLEVEL_V6_UNSET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_v6 + */ +#define ZXDG_TOPLEVEL_V6_SET_MINIMIZED_SINCE_VERSION 1 + +/** @ingroup iface_zxdg_toplevel_v6 */ +static inline void +zxdg_toplevel_v6_set_user_data(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zxdg_toplevel_v6, user_data); +} + +/** @ingroup iface_zxdg_toplevel_v6 */ +static inline void * +zxdg_toplevel_v6_get_user_data(struct zxdg_toplevel_v6 *zxdg_toplevel_v6) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zxdg_toplevel_v6); +} + +static inline uint32_t +zxdg_toplevel_v6_get_version(struct zxdg_toplevel_v6 *zxdg_toplevel_v6) +{ + return wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6); +} + +/** + * @ingroup iface_zxdg_toplevel_v6 + * + * Unmap and destroy the window. The window will be effectively + * hidden from the user's point of view, and all state like + * maximization, fullscreen, and so on, will be lost. + */ +static inline void +zxdg_toplevel_v6_destroy(struct zxdg_toplevel_v6 *zxdg_toplevel_v6) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, + ZXDG_TOPLEVEL_V6_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zxdg_toplevel_v6 + * + * Set the "parent" of this surface. This window should be stacked + * above a parent. The parent surface must be mapped as long as this + * surface is mapped. + * + * Parent windows should be set on dialogs, toolboxes, or other + * "auxiliary" surfaces, so that the parent is raised when the dialog + * is raised. + */ +static inline void +zxdg_toplevel_v6_set_parent(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, struct zxdg_toplevel_v6 *parent) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, + ZXDG_TOPLEVEL_V6_SET_PARENT, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0, parent); +} + +/** + * @ingroup iface_zxdg_toplevel_v6 + * + * Set a short title for the surface. + * + * This string may be used to identify the surface in a task bar, + * window list, or other user interface elements provided by the + * compositor. + * + * The string must be encoded in UTF-8. + */ +static inline void +zxdg_toplevel_v6_set_title(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, const char *title) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, + ZXDG_TOPLEVEL_V6_SET_TITLE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0, title); +} + +/** + * @ingroup iface_zxdg_toplevel_v6 + * + * Set an application identifier for the surface. + * + * The app ID identifies the general class of applications to which + * the surface belongs. The compositor can use this to group multiple + * surfaces together, or to determine how to launch a new application. + * + * For D-Bus activatable applications, the app ID is used as the D-Bus + * service name. + * + * The compositor shell will try to group application surfaces together + * by their app ID. As a best practice, it is suggested to select app + * ID's that match the basename of the application's .desktop file. + * For example, "org.freedesktop.FooViewer" where the .desktop file is + * "org.freedesktop.FooViewer.desktop". + * + * See the desktop-entry specification [0] for more details on + * application identifiers and how they relate to well-known D-Bus + * names and .desktop files. + * + * [0] http://standards.freedesktop.org/desktop-entry-spec/ + */ +static inline void +zxdg_toplevel_v6_set_app_id(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, const char *app_id) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, + ZXDG_TOPLEVEL_V6_SET_APP_ID, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0, app_id); +} + +/** + * @ingroup iface_zxdg_toplevel_v6 + * + * Clients implementing client-side decorations might want to show + * a context menu when right-clicking on the decorations, giving the + * user a menu that they can use to maximize or minimize the window. + * + * This request asks the compositor to pop up such a window menu at + * the given position, relative to the local surface coordinates of + * the parent surface. There are no guarantees as to what menu items + * the window menu contains. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. + */ +static inline void +zxdg_toplevel_v6_show_window_menu(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, + ZXDG_TOPLEVEL_V6_SHOW_WINDOW_MENU, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0, seat, serial, x, y); +} + +/** + * @ingroup iface_zxdg_toplevel_v6 + * + * Start an interactive, user-driven move of the surface. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. The passed + * serial is used to determine the type of interactive move (touch, + * pointer, etc). + * + * The server may ignore move requests depending on the state of + * the surface (e.g. fullscreen or maximized), or if the passed serial + * is no longer valid. + * + * If triggered, the surface will lose the focus of the device + * (wl_pointer, wl_touch, etc) used for the move. It is up to the + * compositor to visually indicate that the move is taking place, such as + * updating a pointer cursor, during the move. There is no guarantee + * that the device focus will return when the move is completed. + */ +static inline void +zxdg_toplevel_v6_move(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, struct wl_seat *seat, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, + ZXDG_TOPLEVEL_V6_MOVE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0, seat, serial); +} + +/** + * @ingroup iface_zxdg_toplevel_v6 + * + * Start a user-driven, interactive resize of the surface. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. The passed + * serial is used to determine the type of interactive resize (touch, + * pointer, etc). + * + * The server may ignore resize requests depending on the state of + * the surface (e.g. fullscreen or maximized). + * + * If triggered, the client will receive configure events with the + * "resize" state enum value and the expected sizes. See the "resize" + * enum value for more details about what is required. The client + * must also acknowledge configure events using "ack_configure". After + * the resize is completed, the client will receive another "configure" + * event without the resize state. + * + * If triggered, the surface also will lose the focus of the device + * (wl_pointer, wl_touch, etc) used for the resize. It is up to the + * compositor to visually indicate that the resize is taking place, + * such as updating a pointer cursor, during the resize. There is no + * guarantee that the device focus will return when the resize is + * completed. + * + * The edges parameter specifies how the surface should be resized, + * and is one of the values of the resize_edge enum. The compositor + * may use this information to update the surface position for + * example when dragging the top left corner. The compositor may also + * use this information to adapt its behavior, e.g. choose an + * appropriate cursor image. + */ +static inline void +zxdg_toplevel_v6_resize(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, struct wl_seat *seat, uint32_t serial, uint32_t edges) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, + ZXDG_TOPLEVEL_V6_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0, seat, serial, edges); +} + +/** + * @ingroup iface_zxdg_toplevel_v6 + * + * Set a maximum size for the window. + * + * The client can specify a maximum size so that the compositor does + * not try to configure the window beyond this size. + * + * The width and height arguments are in window geometry coordinates. + * See xdg_surface.set_window_geometry. + * + * Values set in this way are double-buffered. They will get applied + * on the next commit. + * + * The compositor can use this information to allow or disallow + * different states like maximize or fullscreen and draw accurate + * animations. + * + * Similarly, a tiling window manager may use this information to + * place and resize client windows in a more effective way. + * + * The client should not rely on the compositor to obey the maximum + * size. The compositor may decide to ignore the values set by the + * client and request a larger size. + * + * If never set, or a value of zero in the request, means that the + * client has no expected maximum size in the given dimension. + * As a result, a client wishing to reset the maximum size + * to an unspecified state can use zero for width and height in the + * request. + * + * Requesting a maximum size to be smaller than the minimum size of + * a surface is illegal and will result in a protocol error. + * + * The width and height must be greater than or equal to zero. Using + * strictly negative values for width and height will result in the + * zxdg_shell_v6.invalid_surface_state error being raised. + */ +static inline void +zxdg_toplevel_v6_set_max_size(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, + ZXDG_TOPLEVEL_V6_SET_MAX_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0, width, height); +} + +/** + * @ingroup iface_zxdg_toplevel_v6 + * + * Set a minimum size for the window. + * + * The client can specify a minimum size so that the compositor does + * not try to configure the window below this size. + * + * The width and height arguments are in window geometry coordinates. + * See xdg_surface.set_window_geometry. + * + * Values set in this way are double-buffered. They will get applied + * on the next commit. + * + * The compositor can use this information to allow or disallow + * different states like maximize or fullscreen and draw accurate + * animations. + * + * Similarly, a tiling window manager may use this information to + * place and resize client windows in a more effective way. + * + * The client should not rely on the compositor to obey the minimum + * size. The compositor may decide to ignore the values set by the + * client and request a smaller size. + * + * If never set, or a value of zero in the request, means that the + * client has no expected minimum size in the given dimension. + * As a result, a client wishing to reset the minimum size + * to an unspecified state can use zero for width and height in the + * request. + * + * Requesting a minimum size to be larger than the maximum size of + * a surface is illegal and will result in a protocol error. + * + * The width and height must be greater than or equal to zero. Using + * strictly negative values for width and height will result in the + * zxdg_shell_v6.invalid_surface_state error being raised. + */ +static inline void +zxdg_toplevel_v6_set_min_size(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, + ZXDG_TOPLEVEL_V6_SET_MIN_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0, width, height); +} + +/** + * @ingroup iface_zxdg_toplevel_v6 + * + * Maximize the surface. + * + * After requesting that the surface should be maximized, the compositor + * will respond by emitting a configure event with the "maximized" state + * and the required window geometry. The client should then update its + * content, drawing it in a maximized state, i.e. without shadow or other + * decoration outside of the window geometry. The client must also + * acknowledge the configure when committing the new content (see + * ack_configure). + * + * It is up to the compositor to decide how and where to maximize the + * surface, for example which output and what region of the screen should + * be used. + * + * If the surface was already maximized, the compositor will still emit + * a configure event with the "maximized" state. + * + * Note that unrelated compositor side state changes may cause + * configure events to be emitted at any time, meaning trying to + * match this request to a specific future configure event is + * futile. + */ +static inline void +zxdg_toplevel_v6_set_maximized(struct zxdg_toplevel_v6 *zxdg_toplevel_v6) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, + ZXDG_TOPLEVEL_V6_SET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0); +} + +/** + * @ingroup iface_zxdg_toplevel_v6 + * + * Unmaximize the surface. + * + * After requesting that the surface should be unmaximized, the compositor + * will respond by emitting a configure event without the "maximized" + * state. If available, the compositor will include the window geometry + * dimensions the window had prior to being maximized in the configure + * request. The client must then update its content, drawing it in a + * regular state, i.e. potentially with shadow, etc. The client must also + * acknowledge the configure when committing the new content (see + * ack_configure). + * + * It is up to the compositor to position the surface after it was + * unmaximized; usually the position the surface had before maximizing, if + * applicable. + * + * If the surface was already not maximized, the compositor will still + * emit a configure event without the "maximized" state. + * + * Note that unrelated changes in the state of compositor may cause + * configure events to be emitted by the compositor between processing + * this request and emitting corresponding configure event, so trying + * to match the request with the event is futile. + */ +static inline void +zxdg_toplevel_v6_unset_maximized(struct zxdg_toplevel_v6 *zxdg_toplevel_v6) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, + ZXDG_TOPLEVEL_V6_UNSET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0); +} + +/** + * @ingroup iface_zxdg_toplevel_v6 + * + * Make the surface fullscreen. + * + * You can specify an output that you would prefer to be fullscreen. + * If this value is NULL, it's up to the compositor to choose which + * display will be used to map this surface. + * + * If the surface doesn't cover the whole output, the compositor will + * position the surface in the center of the output and compensate with + * black borders filling the rest of the output. + */ +static inline void +zxdg_toplevel_v6_set_fullscreen(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, struct wl_output *output) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, + ZXDG_TOPLEVEL_V6_SET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0, output); +} + +/** + * @ingroup iface_zxdg_toplevel_v6 + */ +static inline void +zxdg_toplevel_v6_unset_fullscreen(struct zxdg_toplevel_v6 *zxdg_toplevel_v6) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, + ZXDG_TOPLEVEL_V6_UNSET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0); +} + +/** + * @ingroup iface_zxdg_toplevel_v6 + * + * Request that the compositor minimize your surface. There is no + * way to know if the surface is currently minimized, nor is there + * any way to unset minimization on this surface. + * + * If you are looking to throttle redrawing when minimized, please + * instead use the wl_surface.frame event for this, as this will + * also work with live previews on windows in Alt-Tab, Expose or + * similar compositor features. + */ +static inline void +zxdg_toplevel_v6_set_minimized(struct zxdg_toplevel_v6 *zxdg_toplevel_v6) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, + ZXDG_TOPLEVEL_V6_SET_MINIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0); +} + +#ifndef ZXDG_POPUP_V6_ERROR_ENUM +#define ZXDG_POPUP_V6_ERROR_ENUM +enum zxdg_popup_v6_error { + /** + * tried to grab after being mapped + */ + ZXDG_POPUP_V6_ERROR_INVALID_GRAB = 0, +}; +#endif /* ZXDG_POPUP_V6_ERROR_ENUM */ + +/** + * @ingroup iface_zxdg_popup_v6 + * @struct zxdg_popup_v6_listener + */ +struct zxdg_popup_v6_listener { + /** + * configure the popup surface + * + * This event asks the popup surface to configure itself given + * the configuration. The configured state should not be applied + * immediately. See xdg_surface.configure for details. + * + * The x and y arguments represent the position the popup was + * placed at given the xdg_positioner rule, relative to the upper + * left corner of the window geometry of the parent surface. + * @param x x position relative to parent surface window geometry + * @param y y position relative to parent surface window geometry + * @param width window geometry width + * @param height window geometry height + */ + void (*configure)(void *data, + struct zxdg_popup_v6 *zxdg_popup_v6, + int32_t x, + int32_t y, + int32_t width, + int32_t height); + /** + * popup interaction is done + * + * The popup_done event is sent out when a popup is dismissed by + * the compositor. The client should destroy the xdg_popup object + * at this point. + */ + void (*popup_done)(void *data, + struct zxdg_popup_v6 *zxdg_popup_v6); +}; + +/** + * @ingroup iface_zxdg_popup_v6 + */ +static inline int +zxdg_popup_v6_add_listener(struct zxdg_popup_v6 *zxdg_popup_v6, + const struct zxdg_popup_v6_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zxdg_popup_v6, + (void (**)(void)) listener, data); +} + +#define ZXDG_POPUP_V6_DESTROY 0 +#define ZXDG_POPUP_V6_GRAB 1 + +/** + * @ingroup iface_zxdg_popup_v6 + */ +#define ZXDG_POPUP_V6_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_popup_v6 + */ +#define ZXDG_POPUP_V6_POPUP_DONE_SINCE_VERSION 1 + +/** + * @ingroup iface_zxdg_popup_v6 + */ +#define ZXDG_POPUP_V6_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_popup_v6 + */ +#define ZXDG_POPUP_V6_GRAB_SINCE_VERSION 1 + +/** @ingroup iface_zxdg_popup_v6 */ +static inline void +zxdg_popup_v6_set_user_data(struct zxdg_popup_v6 *zxdg_popup_v6, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zxdg_popup_v6, user_data); +} + +/** @ingroup iface_zxdg_popup_v6 */ +static inline void * +zxdg_popup_v6_get_user_data(struct zxdg_popup_v6 *zxdg_popup_v6) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zxdg_popup_v6); +} + +static inline uint32_t +zxdg_popup_v6_get_version(struct zxdg_popup_v6 *zxdg_popup_v6) +{ + return wl_proxy_get_version((struct wl_proxy *) zxdg_popup_v6); +} + +/** + * @ingroup iface_zxdg_popup_v6 + * + * This destroys the popup. Explicitly destroying the xdg_popup + * object will also dismiss the popup, and unmap the surface. + * + * If this xdg_popup is not the "topmost" popup, a protocol error + * will be sent. + */ +static inline void +zxdg_popup_v6_destroy(struct zxdg_popup_v6 *zxdg_popup_v6) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_popup_v6, + ZXDG_POPUP_V6_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_popup_v6), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zxdg_popup_v6 + * + * This request makes the created popup take an explicit grab. An explicit + * grab will be dismissed when the user dismisses the popup, or when the + * client destroys the xdg_popup. This can be done by the user clicking + * outside the surface, using the keyboard, or even locking the screen + * through closing the lid or a timeout. + * + * If the compositor denies the grab, the popup will be immediately + * dismissed. + * + * This request must be used in response to some sort of user action like a + * button press, key press, or touch down event. The serial number of the + * event should be passed as 'serial'. + * + * The parent of a grabbing popup must either be an xdg_toplevel surface or + * another xdg_popup with an explicit grab. If the parent is another + * xdg_popup it means that the popups are nested, with this popup now being + * the topmost popup. + * + * Nested popups must be destroyed in the reverse order they were created + * in, e.g. the only popup you are allowed to destroy at all times is the + * topmost one. + * + * When compositors choose to dismiss a popup, they may dismiss every + * nested grabbing popup as well. When a compositor dismisses popups, it + * will follow the same dismissing order as required from the client. + * + * The parent of a grabbing popup must either be another xdg_popup with an + * active explicit grab, or an xdg_popup or xdg_toplevel, if there are no + * explicit grabs already taken. + * + * If the topmost grabbing popup is destroyed, the grab will be returned to + * the parent of the popup, if that parent previously had an explicit grab. + * + * If the parent is a grabbing popup which has already been dismissed, this + * popup will be immediately dismissed. If the parent is a popup that did + * not take an explicit grab, an error will be raised. + * + * During a popup grab, the client owning the grab will receive pointer + * and touch events for all their surfaces as normal (similar to an + * "owner-events" grab in X11 parlance), while the top most grabbing popup + * will always have keyboard focus. + */ +static inline void +zxdg_popup_v6_grab(struct zxdg_popup_v6 *zxdg_popup_v6, struct wl_seat *seat, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_popup_v6, + ZXDG_POPUP_V6_GRAB, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_popup_v6), 0, seat, serial); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/wayland/java/WindowWayland.java b/wayland/java/WindowWayland.java new file mode 100644 index 00000000..0fa0ce65 --- /dev/null +++ b/wayland/java/WindowWayland.java @@ -0,0 +1,235 @@ +package io.github.humbleui.jwm; + +import java.io.*; +import java.util.concurrent.*; +import java.util.function.*; +import lombok.*; +import org.jetbrains.annotations.*; +import io.github.humbleui.jwm.*; +import io.github.humbleui.jwm.impl.*; +import io.github.humbleui.types.*; + +public class WindowWayland extends Window { + @ApiStatus.Internal + public WindowWayland() { + super(_nMake()); + } + + @Override + public Window setTextInputEnabled(boolean enabled) { + assert _onUIThread() : "Should be run on UI thread"; + // TODO: impl me + return this; + } + + @Override + public void unmarkText() { + assert _onUIThread() : "Should be run on UI thread"; + // TODO: impl me! + } + + @Override + public IRect getWindowRect() { + assert _onUIThread() : "Should be run on UI thread"; + return _nGetWindowRect(); + } + + @Override + public IRect getContentRect() { + assert _onUIThread() : "Should be run on UI thread"; + return _nGetContentRect(); + } + + @Override + public Window setWindowPosition(int left, int top) { + assert _onUIThread() : "Should be run on UI thread"; + // _nSetWindowPosition(left, top); + // Unsupported under wayland rn + return this; + } + + @Override + public Window setWindowSize(int width, int height) { + assert _onUIThread() : "Should be run on UI thread"; + // _nSetWindowSize(width, height); + // Possibly unsupported? Hinting is possibly supported + return this; + } + + @Override + public Window setContentSize(int width, int height) { + assert _onUIThread() : "Should be run on UI thread"; + // _nSetContentSize(width, height); + // Possibly unsupported + return this; + } + + @Override + public Window setTitle(String title) { + assert _onUIThread() : "Should be run on UI thread"; + try { + _nSetTitle(title.getBytes("UTF-8")); + } catch (UnsupportedEncodingException ignored) {} + return this; + } + + @Override + public Window setIcon(File icon) { + // TODO #95 + return this; + } + + @Override + public Window setTitlebarVisible(boolean value) { + _nSetTitlebarVisible(value); + return this; + } + + @Override + public Window setVisible(boolean isVisible) { + assert _onUIThread() : "Should be run on UI thread"; + _nSetVisible(isVisible); + return super.setVisible(true); + } + + @Override + public Window hideMouseCursorUntilMoved(boolean value) { + // TODO impl me! + return this; + } + + @Override + public Window lockMouseCursor(boolean value) { + // TODO impl me! + return this; + } + + @Override + public Window setOpacity(float opacity) { + // TODO: impl me! + return this; + } + + @Override + public float getOpacity(){ + throw new UnsupportedOperationException("impl me!"); + } + + @Override + public Screen getScreen() { + assert _onUIThread() : "Should be run on UI thread"; + return _nGetScreen(); + } + + @Override + public void requestFrame() { + if (!isClosed()) { + App.runOnUIThread(() -> { + if (!isClosed()) { + _nRequestFrame(); + } + }); + } + } + + @Override + public void close() { + assert _onUIThread() && !isClosed(); + _nClose(); + super.close(); + } + + @Override + public Window maximize() { + _nMaximize(); + return this; + } + + @Override + public Window minimize() { + _nMinimize(); + return this; + } + + @Override + public Window focus() { + assert _onUIThread() : "Should be run on UI thread"; + // TODO implement + return this; + } + + @Override + public Window bringToFront() { + assert _onUIThread() : "Should be run on UI thread"; + // TODO implement + return this; + } + + @Override + public boolean isFront() { + assert _onUIThread() : "Should be run on UI thread"; + // TODO: impl me + return false; + } + + @Override + public ZOrder getZOrder() { + assert _onUIThread() : "Should be run on UI thread"; + return ZOrder.NORMAL; + } + + @Override + public Window setZOrder(ZOrder order) { + assert _onUIThread() : "Should be run on UI thread"; + // TODO implement + return this; + } + + @Override + public float getProgressBar() { + throw new UnsupportedOperationException("impl me!"); + } + + @Override + public Window setProgressBar(float progress) { + throw new UnsupportedOperationException("impl me!"); + } + + @Override + public Window restore() { + _nRestore(); + return this; + } + + @Override + public Window setFullScreen(boolean value) { + assert _onUIThread() : "Should be run on UI thread"; + _nSetFullScreen(value); + return this; + } + + @Override + public boolean isFullScreen() { + assert _onUIThread() : "Should be run on UI thread"; + return _nIsFullScreen(); + } + + @ApiStatus.Internal public static native long _nMake(); + @ApiStatus.Internal public native void _nSetVisible(boolean isVisible); + @ApiStatus.Internal public native IRect _nGetWindowRect(); + @ApiStatus.Internal public native IRect _nGetContentRect(); + // @ApiStatus.Internal public native void _nSetWindowPosition(int left, int top); + // @ApiStatus.Internal public native void _nSetWindowSize(int width, int height); + @ApiStatus.Internal public native void _nSetMouseCursor(int cursorId); + // @ApiStatus.Internal public native void _nSetContentSize(int width, int height); + @ApiStatus.Internal public native Screen _nGetScreen(); + @ApiStatus.Internal public native void _nRequestFrame(); + @ApiStatus.Internal public native void _nClose(); + @ApiStatus.Internal public native void _nMaximize(); + @ApiStatus.Internal public native void _nMinimize(); + @ApiStatus.Internal public native void _nRestore(); + @ApiStatus.Internal public native Screen _nSetTitle(byte[] title); + @ApiStatus.Internal public native void _nSetTitlebarVisible(boolean isVisible); + @ApiStatus.Internal public native void _nSetFullScreen(boolean isFullScreen); + @ApiStatus.Internal public native boolean _nIsFullScreen(); +} diff --git a/linux/CMakeLists.txt b/x11/CMakeLists.txt similarity index 91% rename from linux/CMakeLists.txt rename to x11/CMakeLists.txt index ef67fc66..e50d48e5 100644 --- a/linux/CMakeLists.txt +++ b/x11/CMakeLists.txt @@ -33,9 +33,9 @@ if (NOT JAVA_HOME) endif() endif() -target_include_directories(jwm PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../shared/cc ${JAVA_HOME}/include ${JAVA_HOME}/include/linux) +target_include_directories(jwm PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../shared/cc ../linux/cc ${JAVA_HOME}/include ${JAVA_HOME}/include/linux) set_target_properties(jwm PROPERTIES OUTPUT_NAME "jwm_${JWM_ARCH}") target_link_libraries(jwm PRIVATE X11::X11 X11::Xrandr X11::Xcursor X11::Xi) -target_link_libraries(jwm PRIVATE OpenGL::GL) \ No newline at end of file +target_link_libraries(jwm PRIVATE OpenGL::GL) diff --git a/x11/cc/AppX11.cc b/x11/cc/AppX11.cc new file mode 100644 index 00000000..9a1f03ec --- /dev/null +++ b/x11/cc/AppX11.cc @@ -0,0 +1,126 @@ +#include +#include "AppX11.hh" +#include +#include +#include +#include +#include +#include + +jwm::AppX11 jwm::app; + + +float jwm::AppX11::getScale() { + char *resourceString = XResourceManagerString(wm.display); + XrmDatabase db; + XrmValue value; + char *type = NULL; + + static struct once { + once() { + XrmInitialize(); + } + } once; + + if (resourceString) { + db = XrmGetStringDatabase(resourceString); + if (XrmGetResource(db, "Xft.dpi", "String", &type, &value)) { + if (value.addr) { + return atof(value.addr) / 96.f; + } + } + } + + return 1.f; +} + +void jwm::AppX11::init(JNIEnv* jniEnv) { + _jniEnv = jniEnv; +} + +void jwm::AppX11::start() { + wm.runLoop(); +} + +void jwm::AppX11::terminate() { + wm.terminate(); +} + +const std::vector& jwm::AppX11::getScreens() { + if (_screens.empty()) { + Display* display = getWindowManager().getDisplay(); + XRRScreenResources* resources = XRRGetScreenResources(display, getWindowManager().getRootWindow()); + RROutput primaryOutput = XRRGetOutputPrimary(display, getWindowManager().getRootWindow()); + int count = resources->ncrtc; + int primaryIdx = 0; + + float dpi = jwm::app.getScale(); + + for (int i = 0; i < count; ++i) { + XRRCrtcInfo* info = XRRGetCrtcInfo(display, resources, resources->crtcs[i]); + // skip empty monitors + if (info->width != 0) { + for (int j = 0; j < info->noutput; ++j) { + RROutput output = info->outputs[j]; + if (output == primaryOutput) { + primaryIdx = _screens.size(); + break; + } + } + + auto bounds = jwm::IRect::makeXYWH(info->x, info->y, info->width, info->height); + + ScreenInfo myScreenInfo = { + long(info->outputs[0]), + bounds, + false + }; + _screens.push_back(myScreenInfo); + } + + XRRFreeCrtcInfo(info); + } + XRRFreeScreenResources(resources); + _screens[primaryIdx].isPrimary = true; + } + return _screens; +} + +// JNI + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_App__1nStart(JNIEnv* env, jclass jclass, jobject launcher) { + jwm::app.init(env); + jwm::classes::Runnable::run(env, launcher); + jwm::app.start(); +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_App__1nTerminate(JNIEnv* env, jclass jclass) { + jwm::app.terminate(); +} + +extern"C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) { + return JNI_VERSION_1_2; +} + + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_App__1nRunOnUIThread + (JNIEnv* env, jclass cls, jobject callback) { + jobject callbackRef = env->NewGlobalRef(callback); + jwm::app.getWindowManager().enqueueTask([callbackRef] { + jwm::classes::Runnable::run(jwm::app.getJniEnv(), callbackRef); + jwm::app.getJniEnv()->DeleteGlobalRef(callbackRef); + }); +} + + +extern "C" JNIEXPORT jobjectArray JNICALL Java_io_github_humbleui_jwm_App__1nGetScreens(JNIEnv* env, jobject cls) noexcept { + auto& screens = jwm::app.getScreens(); + jobjectArray array = env->NewObjectArray(screens.size(), jwm::classes::Screen::kCls, 0); + float scale = jwm::app.getScale(); + size_t index = 0; + for (auto& screen : screens) { + env->SetObjectArrayElement(array, index++, screen.asJavaObject(env)); + } + + return array; +} diff --git a/linux/cc/AppX11.hh b/x11/cc/AppX11.hh similarity index 100% rename from linux/cc/AppX11.hh rename to x11/cc/AppX11.hh diff --git a/x11/cc/ClipboardX11.cc b/x11/cc/ClipboardX11.cc new file mode 100644 index 00000000..fd8c23d7 --- /dev/null +++ b/x11/cc/ClipboardX11.cc @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#include "AppX11.hh" +#include + +namespace jwm { + class ClipboardX11 { + public: + static ClipboardX11& inst() { + static ClipboardX11 s; + return s; + } + + jobjectArray getFormats(JNIEnv* env) const { + auto formats = jwm::app.getWindowManager().getClipboardFormats(); + if (formats.empty()) { + return nullptr; + } + + std::vector formatObjs; + + for (auto& format : formats) { + auto js = StringUTF16(format.c_str()).toJString(env); + formatObjs.push_back(classes::Clipboard::registerFormat(env, js.get())); + } + jobjectArray jniFormats = env->NewObjectArray(static_cast(formats.size()), classes::ClipboardFormat::kCls, nullptr); + + // fill java array + for (jsize i = 0; i < static_cast(formatObjs.size()); ++i) { + env->SetObjectArrayElement(jniFormats, i, formatObjs[i]); + } + + return jniFormats; + } + + jobject get(JNIEnv* env, jobjectArray formats) { + jsize formatsSize = env->GetArrayLength(formats); + for (jsize i = 0; i < formatsSize; ++i) { + jobject format = env->GetObjectArrayElement(formats, i); + if (format) { + jwm::StringUTF16 formatId = jwm::StringUTF16::makeFromJString(env, classes::ClipboardFormat::getFormatId(env, format)); + + + ByteBuf contents; + // HACK: prefer UTF8_STRING over text/plain and convert it to utf16 + if (formatId == "text/plain") { + contents = app.getWindowManager().getClipboardContents("UTF8_STRING"); + } + // TODO add another formats + if (contents.empty()) { + return nullptr; + } + JNILocal data(env, env->NewByteArray(static_cast(contents.size()))); + jbyte* bytes = env->GetByteArrayElements(data.get(), nullptr); + std::memcpy(bytes, contents.data(), contents.size()); + + env->ReleaseByteArrayElements(data.get(), bytes, 0); + + + JNILocal entry(env, classes::ClipboardEntry::make(env, format, data.get())); + return env->NewGlobalRef(entry.get()); + } + } + classes::Throwable::exceptionThrown(env); + return nullptr; + } + + + void set(JNIEnv* env, jobjectArray entries) { + jsize size = env->GetArrayLength(entries); + std::map contents; + for (jsize i = 0; i < size; ++i) { + jobject entry = env->GetObjectArrayElement(entries, i); + + if (entry) { + jobject format = classes::ClipboardEntry::getFormat(env, entry); + jbyteArray data = classes::ClipboardEntry::getData(env, entry); + jsize dataSize = env->GetArrayLength(data); + + StringUTF16 formatId = StringUTF16::makeFromJString(env, classes::ClipboardFormat::getFormatId(env, format)); + + ByteBuf resultBuffer; + { + jbyte* dataBytes = env->GetByteArrayElements(data, nullptr); + resultBuffer.insert(resultBuffer.end(), dataBytes, dataBytes + dataSize); + env->ReleaseByteArrayElements(data, dataBytes, JNI_ABORT); + } + + contents[formatId.toAscii()] = std::move(resultBuffer); + } + } + jwm::app.getWindowManager().setClipboardContents(std::move(contents)); + } + }; +} + + +// JNI + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_Clipboard__1nSet + (JNIEnv* env, jclass jclass, jobjectArray entries) { + return jwm::ClipboardX11::inst().set(env, entries); +} + +extern "C" JNIEXPORT jobject JNICALL Java_io_github_humbleui_jwm_Clipboard__1nGet + (JNIEnv* env, jclass jclass, jobjectArray formats) { + return jwm::ClipboardX11::inst().get(env, formats); +} + +extern "C" JNIEXPORT jobjectArray JNICALL Java_io_github_humbleui_jwm_Clipboard__1nGetFormats + (JNIEnv* env, jclass jclass) { + return jwm::ClipboardX11::inst().getFormats(env); +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_Clipboard__1nClear + (JNIEnv* env, jclass jclass) { + +} + +extern "C" JNIEXPORT jboolean JNICALL Java_io_github_humbleui_jwm_Clipboard__1nRegisterFormat + (JNIEnv* env, jclass jclass, jstring formatId) { + return true; +} \ No newline at end of file diff --git a/x11/cc/KeyX11.cc b/x11/cc/KeyX11.cc new file mode 100644 index 00000000..9a638c69 --- /dev/null +++ b/x11/cc/KeyX11.cc @@ -0,0 +1,178 @@ +#include "KeyX11.hh" +#include +#include +#include +#include +#include "KeyModifier.hh" + + +bool gKeyStates[(size_t) jwm::Key::_KEY_COUNT] = {0}; + +bool jwm::KeyX11::getKeyState(jwm::Key key) { + return gKeyStates[(size_t) key]; +} + +void jwm::KeyX11::setKeyState(jwm::Key key, bool isDown) { + gKeyStates[(size_t) key] = isDown; +} + +int jwm::KeyX11::getModifiers() { + int m = 0; + + if (getKeyState(jwm::Key::SHIFT )) m |= (int)jwm::KeyModifier::SHIFT; + if (getKeyState(jwm::Key::CONTROL )) m |= (int)jwm::KeyModifier::CONTROL; + if (getKeyState(jwm::Key::ALT )) m |= (int)jwm::KeyModifier::ALT; + if (getKeyState(jwm::Key::LINUX_META )) m |= (int)jwm::KeyModifier::LINUX_META; + if (getKeyState(jwm::Key::LINUX_SUPER)) m |= (int)jwm::KeyModifier::LINUX_SUPER; + + return m; +} + +int jwm::KeyX11::getModifiersFromMask(int mask) { + int m = getModifiers(); + + if (mask & ShiftMask ) m |= (int)jwm::KeyModifier::SHIFT; + if (mask & ControlMask) m |= (int)jwm::KeyModifier::CONTROL; + if (mask & Mod1Mask ) m |= (int)jwm::KeyModifier::ALT; + + return m; +} + +jwm::Key jwm::KeyX11::fromNative(uint32_t v) { + switch (v) { + // Modifiers + case XK_Caps_Lock: return Key::CAPS_LOCK; + case XK_Shift_R: + case XK_Shift_L: return Key::SHIFT; + case XK_Control_R: + case XK_Control_L: return Key::CONTROL; + case XK_Alt_R: + case XK_Alt_L: return Key::ALT; + // Key::WIN_LOGO + case XK_Super_L: + case XK_Super_R: return Key::LINUX_SUPER; + case XK_Meta_L: + case XK_Meta_R: return Key::LINUX_META; + // Key::MAC_COMMAND + // Key::MAC_OPTION + // Key::MAC_FN + + // Rest of the keys + case XK_Return: return Key::ENTER; + case XK_BackSpace: return Key::BACKSPACE; + case XK_Tab: return Key::TAB; + case XK_Cancel: return Key::CANCEL; + case XK_Clear: return Key::CLEAR; + case XK_Pause: return Key::PAUSE; + case XK_Escape: return Key::ESCAPE; + case XK_space: return Key::SPACE; + case XK_Page_Up: return Key::PAGE_UP; + case XK_Page_Down: return Key::PAGE_DOWN; + case XK_End: return Key::END; + case XK_Home: return Key::HOME; + case XK_Left: return Key::LEFT; + case XK_Up: return Key::UP; + case XK_Right: return Key::RIGHT; + case XK_Down: return Key::DOWN; + case XK_comma: return Key::COMMA; + case XK_minus: return Key::MINUS; + case XK_period: return Key::PERIOD; + case XK_slash: return Key::SLASH; + case XK_0: return Key::DIGIT0; + case XK_1: return Key::DIGIT1; + case XK_2: return Key::DIGIT2; + case XK_3: return Key::DIGIT3; + case XK_4: return Key::DIGIT4; + case XK_5: return Key::DIGIT5; + case XK_6: return Key::DIGIT6; + case XK_7: return Key::DIGIT7; + case XK_8: return Key::DIGIT8; + case XK_9: return Key::DIGIT9; + case XK_semicolon: return Key::SEMICOLON; + case XK_equal: return Key::EQUALS; + case XK_a: return Key::A; + case XK_b: return Key::B; + case XK_c: return Key::C; + case XK_d: return Key::D; + case XK_e: return Key::E; + case XK_f: return Key::F; + case XK_g: return Key::G; + case XK_h: return Key::H; + case XK_i: return Key::I; + case XK_j: return Key::J; + case XK_k: return Key::K; + case XK_l: return Key::L; + case XK_m: return Key::M; + case XK_n: return Key::N; + case XK_o: return Key::O; + case XK_p: return Key::P; + case XK_q: return Key::Q; + case XK_r: return Key::R; + case XK_s: return Key::S; + case XK_t: return Key::T; + case XK_u: return Key::U; + case XK_v: return Key::V; + case XK_w: return Key::W; + case XK_x: return Key::X; + case XK_y: return Key::Y; + case XK_z: return Key::Z; + case XK_bracketleft: return Key::OPEN_BRACKET; + case XK_backslash: return Key::BACK_SLASH; + case XK_bracketright: return Key::CLOSE_BRACKET; + case XK_KP_0: return Key::DIGIT0; + case XK_KP_1: return Key::DIGIT1; + case XK_KP_2: return Key::DIGIT2; + case XK_KP_3: return Key::DIGIT3; + case XK_KP_4: return Key::DIGIT4; + case XK_KP_5: return Key::DIGIT5; + case XK_KP_6: return Key::DIGIT6; + case XK_KP_7: return Key::DIGIT7; + case XK_KP_8: return Key::DIGIT8; + case XK_KP_9: return Key::DIGIT9; + case XK_multiply: return Key::MULTIPLY; + case XK_KP_Add: return Key::ADD; + case XK_KP_Separator: return Key::SEPARATOR; + case XK_KP_Subtract: return Key::MINUS; + case XK_KP_Decimal: return Key::PERIOD; + case XK_KP_Divide: return Key::SLASH; + case XK_KP_Delete: return Key::DEL; + case XK_Delete: return Key::DEL; + case XK_Num_Lock: return Key::NUM_LOCK; + case XK_Scroll_Lock: return Key::SCROLL_LOCK; + case XK_F1: return Key::F1; + case XK_F2: return Key::F2; + case XK_F3: return Key::F3; + case XK_F4: return Key::F4; + case XK_F5: return Key::F5; + case XK_F6: return Key::F6; + case XK_F7: return Key::F7; + case XK_F8: return Key::F8; + case XK_F9: return Key::F9; + case XK_F10: return Key::F10; + case XK_F11: return Key::F11; + case XK_F12: return Key::F12; + case XK_F13: return Key::F13; + case XK_F14: return Key::F14; + case XK_F15: return Key::F15; + case XK_F16: return Key::F16; + case XK_F17: return Key::F17; + case XK_F18: return Key::F18; + case XK_F19: return Key::F19; + case XK_F20: return Key::F20; + case XK_F21: return Key::F21; + case XK_F22: return Key::F22; + case XK_F23: return Key::F23; + case XK_F24: return Key::F24; + case XK_Print: return Key::PRINTSCREEN; + case XK_Insert: return Key::INSERT; + case XK_Help: return Key::HELP; + case XK_grave: return Key::BACK_QUOTE; + case XK_quoteright: return Key::QUOTE; + case XK_Menu: return Key::MENU; + // Key::KANA + // Key::VOLUME_UP + // Key::VOLUME_DOWN + // Key::MUTE + default: return Key::UNDEFINED; + } +} \ No newline at end of file diff --git a/x11/cc/KeyX11.hh b/x11/cc/KeyX11.hh new file mode 100644 index 00000000..ce03b165 --- /dev/null +++ b/x11/cc/KeyX11.hh @@ -0,0 +1,14 @@ +#pragma once + +#include +#include "Key.hh" + +namespace jwm { + namespace KeyX11 { + jwm::Key fromNative(uint32_t v); + bool getKeyState(jwm::Key key); + void setKeyState(jwm::Key key, bool isDown); + int getModifiers(); + int getModifiersFromMask(int mask); + } +} \ No newline at end of file diff --git a/linux/cc/LayerGL.cc b/x11/cc/LayerGLX11.cc similarity index 100% rename from linux/cc/LayerGL.cc rename to x11/cc/LayerGLX11.cc diff --git a/x11/cc/LayerRasterX11.cc b/x11/cc/LayerRasterX11.cc new file mode 100644 index 00000000..2ec70c85 --- /dev/null +++ b/x11/cc/LayerRasterX11.cc @@ -0,0 +1,123 @@ +// JNI + +#include +#include "impl/Library.hh" +#include "impl/RefCounted.hh" +#include "WindowX11.hh" + +namespace jwm { + class LayerRaster: public RefCounted, public ILayer { + public: + WindowX11* fWindow; + size_t _width = 0, _height = 0; + XImage* _xImage = nullptr; + GC _graphicsContext; + VSync _vsync = VSYNC_ENABLED; + + /** + * Using raw pointer here because XImage frees this buffer on XDestroyImage. + */ + uint8_t* _imageData = nullptr; + + LayerRaster() = default; + virtual ~LayerRaster() = default; + + void attach(WindowX11* window) { + fWindow = jwm::ref(window); + fWindow->setLayer(this); + + Display* d = fWindow->_windowManager.getDisplay(); + _graphicsContext = DefaultGC(d, DefaultScreen(d)); + } + + void resize(int width, int height) { + Display* d = fWindow->_windowManager.getDisplay(); + _width = width; + _height = height; + if (_xImage) { + XDestroyImage(_xImage); + } + _imageData = new uint8_t[width * height * sizeof(uint32_t)]; + _xImage = XCreateImage(d, CopyFromParent, DefaultDepth(d, DefaultScreen(d)), ZPixmap, 0, (char*)_imageData, width, height, 32, 0); + XInitImage(_xImage); + _xImage->byte_order = _xImage->bitmap_bit_order = LSBFirst; + } + + const void* getPixelsPtr() const { + return _imageData; + } + + int getRowBytes() const { + return _width * sizeof(uint32_t); + } + + void swapBuffers() { + XPutImage(fWindow->_windowManager.getDisplay(), fWindow->_x11Window, _graphicsContext, _xImage, 0, 0, 0, 0, _width, _height); + } + + void close() override { + if (_xImage) { + XDestroyImage(_xImage); + _xImage = nullptr; + } + jwm::unref(&fWindow); + } + + void makeCurrentForced() override { + ILayer::makeCurrentForced(); + } + + void setVsyncMode(VSync v) override { + _vsync = v; + } + }; +} + + +extern "C" JNIEXPORT jlong JNICALL Java_io_github_humbleui_jwm_LayerRaster__1nMake + (JNIEnv* env, jclass jclass) { + jwm::LayerRaster* instance = new jwm::LayerRaster; + return reinterpret_cast(instance); +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerRaster__1nAttach + (JNIEnv* env, jobject obj, jobject windowObj) { + jwm::LayerRaster* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + jwm::WindowX11* window = reinterpret_cast(jwm::classes::Native::fromJava(env, windowObj)); + instance->attach(window); +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerRaster__1nReconfigure + (JNIEnv* env, jobject obj) { + +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerRaster__1nResize + (JNIEnv* env, jobject obj, jint width, jint height) { + jwm::LayerRaster* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + instance->resize(width, height); +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerRaster__1nSwapBuffers + (JNIEnv* env, jobject obj) { + jwm::LayerRaster* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + instance->swapBuffers(); +} + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerRaster__1nClose + (JNIEnv* env, jobject obj) { + jwm::LayerRaster* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + instance->close(); +} + +extern "C" JNIEXPORT jlong JNICALL Java_io_github_humbleui_jwm_LayerRaster__1nGetPixelsPtr + (JNIEnv* env, jobject obj) { + jwm::LayerRaster* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + return reinterpret_cast(instance->getPixelsPtr()); +} + +extern "C" JNIEXPORT jlong JNICALL Java_io_github_humbleui_jwm_LayerRaster__1nGetRowBytes + (JNIEnv* env, jobject obj) { + jwm::LayerRaster* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + return static_cast(instance->getRowBytes()); +} \ No newline at end of file diff --git a/x11/cc/MouseButtonX11.cc b/x11/cc/MouseButtonX11.cc new file mode 100644 index 00000000..c1aa2c36 --- /dev/null +++ b/x11/cc/MouseButtonX11.cc @@ -0,0 +1,25 @@ +#include "MouseButtonX11.hh" + + +jwm::MouseButton jwm::MouseButtonX11::fromNative(uint32_t v) { + switch (v) { + case 1: return jwm::MouseButton::PRIMARY; + case 2: return jwm::MouseButton::MIDDLE; + case 3: return jwm::MouseButton::SECONDARY; + case 8: return jwm::MouseButton::BACK; + case 9: return jwm::MouseButton::FORWARD; + } + return jwm::MouseButton::PRIMARY; +} + +bool jwm::MouseButtonX11::isButton(uint32_t v) { + return v < 4 || v > 7; // mouse wheel buttons +} + +int jwm::MouseButtonX11::fromNativeMask(unsigned v) { + int res = 0; + if (v & 0x100) res |= int(jwm::MouseButton::PRIMARY); + if (v & 0x400) res |= int(jwm::MouseButton::SECONDARY); + if (v & 0x200) res |= int(jwm::MouseButton::MIDDLE); + return res; +} \ No newline at end of file diff --git a/x11/cc/MouseButtonX11.hh b/x11/cc/MouseButtonX11.hh new file mode 100644 index 00000000..898edda7 --- /dev/null +++ b/x11/cc/MouseButtonX11.hh @@ -0,0 +1,12 @@ +#pragma once + +#include +#include "MouseButton.hh" + +namespace jwm { + namespace MouseButtonX11 { + MouseButton fromNative(uint32_t v); + int fromNativeMask(unsigned v); + bool isButton(uint32_t v); + } +} \ No newline at end of file diff --git a/linux/cc/WindowManagerX11.cc b/x11/cc/WindowManagerX11.cc similarity index 100% rename from linux/cc/WindowManagerX11.cc rename to x11/cc/WindowManagerX11.cc diff --git a/linux/cc/WindowManagerX11.hh b/x11/cc/WindowManagerX11.hh similarity index 100% rename from linux/cc/WindowManagerX11.hh rename to x11/cc/WindowManagerX11.hh diff --git a/linux/cc/WindowX11.cc b/x11/cc/WindowX11.cc similarity index 100% rename from linux/cc/WindowX11.cc rename to x11/cc/WindowX11.cc diff --git a/linux/cc/WindowX11.hh b/x11/cc/WindowX11.hh similarity index 100% rename from linux/cc/WindowX11.hh rename to x11/cc/WindowX11.hh diff --git a/linux/cc/WindowX11MotifHints.hh b/x11/cc/WindowX11MotifHints.hh similarity index 100% rename from linux/cc/WindowX11MotifHints.hh rename to x11/cc/WindowX11MotifHints.hh diff --git a/linux/java/WindowX11.java b/x11/java/WindowX11.java similarity index 100% rename from linux/java/WindowX11.java rename to x11/java/WindowX11.java From f3ec23129814be60baacbb86bb5dff6541e5528b Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Thu, 30 Nov 2023 21:15:32 -0500 Subject: [PATCH 02/93] we've all sinned. some worse than others. --- macos/java/WindowMac.java | 5 + script/build.py | 2 +- shared/cc/StringUTF16.cc | 2 +- shared/cc/StringUTF16.hh | 1 + shared/java/Window.java | 1 + wayland/CMakeLists.txt | 15 +- wayland/cc/AppWayland.cc | 92 +- wayland/cc/AppWayland.hh | 14 +- wayland/cc/ClipboardWayland.cc | 28 +- wayland/cc/KeyWayland.cc | 23 +- wayland/cc/KeyWayland.hh | 4 +- wayland/cc/LayerGLWayland.cc | 76 +- wayland/cc/LayerRasterWayland.cc | 53 +- wayland/cc/MouseButtonWayland.cc | 22 +- wayland/cc/MouseButtonWayland.hh | 4 +- wayland/cc/ScreenInfo.cc | 5 + {linux => wayland}/cc/ScreenInfo.hh | 0 wayland/cc/ShmPool.cc | 92 ++ wayland/cc/ShmPool.hh | 25 + wayland/cc/WindowManagerWayland.cc | 232 ++- wayland/cc/WindowManagerWayland.hh | 26 +- wayland/cc/WindowWayland.cc | 492 ++---- wayland/cc/WindowWayland.hh | 9 +- wayland/cc/xdg-shell.c | 172 -- wayland/cc/xdg-shell.cc | 183 +++ wayland/cc/xdg-shell.h | 1884 ---------------------- wayland/cc/xdg-shell.hh | 2307 +++++++++++++++++++++++++++ wayland/java/WindowWayland.java | 17 +- windows/java/WindowWin32.java | 5 +- x11/CMakeLists.txt | 6 +- {linux => x11}/cc/ScreenInfo.cc | 1 - x11/cc/ScreenInfo.hh | 13 + x11/cc/WindowX11.cc | 8 +- x11/cc/WindowX11.hh | 2 +- x11/java/WindowX11.java | 6 + 35 files changed, 3075 insertions(+), 2752 deletions(-) create mode 100644 wayland/cc/ScreenInfo.cc rename {linux => wayland}/cc/ScreenInfo.hh (100%) create mode 100644 wayland/cc/ShmPool.cc create mode 100644 wayland/cc/ShmPool.hh delete mode 100644 wayland/cc/xdg-shell.c create mode 100644 wayland/cc/xdg-shell.cc delete mode 100644 wayland/cc/xdg-shell.h create mode 100644 wayland/cc/xdg-shell.hh rename {linux => x11}/cc/ScreenInfo.cc (99%) create mode 100644 x11/cc/ScreenInfo.hh diff --git a/macos/java/WindowMac.java b/macos/java/WindowMac.java index 645be065..297736fa 100644 --- a/macos/java/WindowMac.java +++ b/macos/java/WindowMac.java @@ -228,6 +228,11 @@ public Window restore() { return this; } + @Override + public float getScale() { + return this.getScreen().getScale(); + } + @Override public Window setFullScreen(boolean value) { assert _onUIThread() : "Should be run on UI thread"; diff --git a/script/build.py b/script/build.py index 80882614..ec528e66 100755 --- a/script/build.py +++ b/script/build.py @@ -24,7 +24,7 @@ def build_native_system(system): build_utils.copy_newer('build/jwm_x64.dll', '../target/classes/jwm_x64.dll') return 0 -def build_system(): +def build_native(): cur_system = build_utils.system; if cur_system == "linux": build_native_system("x11") diff --git a/shared/cc/StringUTF16.cc b/shared/cc/StringUTF16.cc index ac8522a4..a3b54b56 100644 --- a/shared/cc/StringUTF16.cc +++ b/shared/cc/StringUTF16.cc @@ -89,4 +89,4 @@ std::string jwm::StringUTF16::toAscii() const { result[i++] = static_cast(c); } return result; -} \ No newline at end of file +} diff --git a/shared/cc/StringUTF16.hh b/shared/cc/StringUTF16.hh index 84cde0e7..cf58976a 100644 --- a/shared/cc/StringUTF16.hh +++ b/shared/cc/StringUTF16.hh @@ -3,6 +3,7 @@ #include #include #include +#include namespace jwm { diff --git a/shared/java/Window.java b/shared/java/Window.java index dc78cb15..d156b949 100644 --- a/shared/java/Window.java +++ b/shared/java/Window.java @@ -68,6 +68,7 @@ public Window setLayer(@Nullable Layer layer) { return this; } + public abstract float getScale(); /** *

Enables complex text input on this window.

*

Passed value `true` or `false` enables or disables complex text input and IME on this window respectively.

diff --git a/wayland/CMakeLists.txt b/wayland/CMakeLists.txt index 75249cdd..8af35a72 100644 --- a/wayland/CMakeLists.txt +++ b/wayland/CMakeLists.txt @@ -15,12 +15,8 @@ if(NOT JWM_ARCH) endif() endif() -find_package(wayland-client REQUIRED) -find_package(decor REQUIRED) -find_package(wayland-cursor REQUIRED) -find_package(OpenGL REQUIRED) - -file(GLOB SOURCES_CXX ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/*.cc ${CMAKE_CURRENT_LIST_DIR}/cc/*.cc) +file(GLOB SOURCES_CXX ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/*.cc + ${CMAKE_CURRENT_LIST_DIR}/cc/*.cc ${CMAKE_CURRENT_LIST_DIR}/../linux/cc/*.cc) file(GLOB SOURCES_CXX_IMPL ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/impl/*.cc) add_library(jwm SHARED ${SOURCES_OBJC} ${SOURCES_CXX} ${SOURCES_CXX_IMPL}) @@ -35,9 +31,10 @@ if (NOT JAVA_HOME) endif() endif() -target_include_directories(jwm PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../shared/cc ../shared/linux ${JAVA_HOME}/include ${JAVA_HOME}/include/linux) +target_include_directories(jwm PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../shared/cc ${CMAKE_CURRENT_LIST_DIR}/../linux/cc ${JAVA_HOME}/include ${JAVA_HOME}/include/linux) set_target_properties(jwm PROPERTIES OUTPUT_NAME "jwm_${JWM_ARCH}") -target_link_libraries(jwm PRIVATE wayland-client::wayland-client, decor::decor, wayland-cursor::wayland-cursor) -target_link_libraries(jwm PRIVATE OpenGL::GL) +target_link_libraries(jwm PRIVATE wayland-client, decor, + wayland-cursor, xkbcommon) +target_link_libraries(jwm PRIVATE EGL, wayland-egl) diff --git a/wayland/cc/AppWayland.cc b/wayland/cc/AppWayland.cc index 9a1f03ec..dc075681 100644 --- a/wayland/cc/AppWayland.cc +++ b/wayland/cc/AppWayland.cc @@ -1,91 +1,23 @@ #include -#include "AppX11.hh" -#include +#include "AppWayland.hh" #include -#include -#include -#include -#include +#include -jwm::AppX11 jwm::app; +jwm::AppWayland jwm::app; -float jwm::AppX11::getScale() { - char *resourceString = XResourceManagerString(wm.display); - XrmDatabase db; - XrmValue value; - char *type = NULL; - - static struct once { - once() { - XrmInitialize(); - } - } once; - - if (resourceString) { - db = XrmGetStringDatabase(resourceString); - if (XrmGetResource(db, "Xft.dpi", "String", &type, &value)) { - if (value.addr) { - return atof(value.addr) / 96.f; - } - } - } - - return 1.f; -} - -void jwm::AppX11::init(JNIEnv* jniEnv) { +void jwm::AppWayland::init(JNIEnv* jniEnv) { _jniEnv = jniEnv; } -void jwm::AppX11::start() { +void jwm::AppWayland::start() { wm.runLoop(); } -void jwm::AppX11::terminate() { +void jwm::AppWayland::terminate() { wm.terminate(); } -const std::vector& jwm::AppX11::getScreens() { - if (_screens.empty()) { - Display* display = getWindowManager().getDisplay(); - XRRScreenResources* resources = XRRGetScreenResources(display, getWindowManager().getRootWindow()); - RROutput primaryOutput = XRRGetOutputPrimary(display, getWindowManager().getRootWindow()); - int count = resources->ncrtc; - int primaryIdx = 0; - - float dpi = jwm::app.getScale(); - - for (int i = 0; i < count; ++i) { - XRRCrtcInfo* info = XRRGetCrtcInfo(display, resources, resources->crtcs[i]); - // skip empty monitors - if (info->width != 0) { - for (int j = 0; j < info->noutput; ++j) { - RROutput output = info->outputs[j]; - if (output == primaryOutput) { - primaryIdx = _screens.size(); - break; - } - } - - auto bounds = jwm::IRect::makeXYWH(info->x, info->y, info->width, info->height); - - ScreenInfo myScreenInfo = { - long(info->outputs[0]), - bounds, - false - }; - _screens.push_back(myScreenInfo); - } - - XRRFreeCrtcInfo(info); - } - XRRFreeScreenResources(resources); - _screens[primaryIdx].isPrimary = true; - } - return _screens; -} - // JNI extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_App__1nStart(JNIEnv* env, jclass jclass, jobject launcher) { @@ -112,15 +44,9 @@ extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_App__1nRunOnUIThre }); } - -extern "C" JNIEXPORT jobjectArray JNICALL Java_io_github_humbleui_jwm_App__1nGetScreens(JNIEnv* env, jobject cls) noexcept { - auto& screens = jwm::app.getScreens(); - jobjectArray array = env->NewObjectArray(screens.size(), jwm::classes::Screen::kCls, 0); - float scale = jwm::app.getScale(); - size_t index = 0; - for (auto& screen : screens) { - env->SetObjectArrayElement(array, index++, screen.asJavaObject(env)); - } +// how awful +extern "C" JNIEXPORT jobjectArray JNICALL Java_io_github_humbleui_jwm_App__1nGetScreens(JNIEnv env*, jobject cls) noexcept { + jobjectArray array = env->NewObjectArray(0, jwm::classes::Screen::kCls, 0); return array; } diff --git a/wayland/cc/AppWayland.hh b/wayland/cc/AppWayland.hh index d6953aae..d0907b8c 100644 --- a/wayland/cc/AppWayland.hh +++ b/wayland/cc/AppWayland.hh @@ -1,6 +1,6 @@ #pragma once -#include "WindowManagerX11.hh" +#include "WindowManagerWayland.hh" #include #include "Types.hh" #include @@ -8,14 +8,14 @@ #include "ScreenInfo.hh" namespace jwm { - extern class AppX11 { + extern class AppWayland { public: void init(JNIEnv* jniEnv); void start(); void terminate(); - WindowManagerX11& getWindowManager() { + WindowManagerWayland& getWindowManager() { return wm; } @@ -23,13 +23,7 @@ namespace jwm { return _jniEnv; } - const std::vector& getScreens(); - - float getScale(); - JNIEnv* _jniEnv; - WindowManagerX11 wm; - std::vector _screens; - + WindowManagerWayland wm; } app; } diff --git a/wayland/cc/ClipboardWayland.cc b/wayland/cc/ClipboardWayland.cc index fd8c23d7..c32b1b51 100644 --- a/wayland/cc/ClipboardWayland.cc +++ b/wayland/cc/ClipboardWayland.cc @@ -2,18 +2,19 @@ #include #include #include -#include "AppX11.hh" +#include "AppWayland.hh" #include namespace jwm { - class ClipboardX11 { + class ClipboardWayland { public: - static ClipboardX11& inst() { - static ClipboardX11 s; + static ClipboardWayland& inst() { + static ClipboardWayland s; return s; } jobjectArray getFormats(JNIEnv* env) const { + /* auto formats = jwm::app.getWindowManager().getClipboardFormats(); if (formats.empty()) { return nullptr; @@ -31,11 +32,14 @@ namespace jwm { for (jsize i = 0; i < static_cast(formatObjs.size()); ++i) { env->SetObjectArrayElement(jniFormats, i, formatObjs[i]); } - - return jniFormats; + */ + // impl me : ) + jobjectArray formats = env->NewObjectArray(0, classes::ClipboardFormat::kCls, nullptr); + return format; } jobject get(JNIEnv* env, jobjectArray formats) { + /* jsize formatsSize = env->GetArrayLength(formats); for (jsize i = 0; i < formatsSize; ++i) { jobject format = env->GetObjectArrayElement(formats, i); @@ -63,12 +67,15 @@ namespace jwm { return env->NewGlobalRef(entry.get()); } } + */ + // impl me : ) classes::Throwable::exceptionThrown(env); return nullptr; } void set(JNIEnv* env, jobjectArray entries) { + /* jsize size = env->GetArrayLength(entries); std::map contents; for (jsize i = 0; i < size; ++i) { @@ -92,6 +99,7 @@ namespace jwm { } } jwm::app.getWindowManager().setClipboardContents(std::move(contents)); + */ // impl me : ) } }; } @@ -101,17 +109,17 @@ namespace jwm { extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_Clipboard__1nSet (JNIEnv* env, jclass jclass, jobjectArray entries) { - return jwm::ClipboardX11::inst().set(env, entries); + return jwm::ClipboardWayland::inst().set(env, entries); } extern "C" JNIEXPORT jobject JNICALL Java_io_github_humbleui_jwm_Clipboard__1nGet (JNIEnv* env, jclass jclass, jobjectArray formats) { - return jwm::ClipboardX11::inst().get(env, formats); + return jwm::ClipboardWayland::inst().get(env, formats); } extern "C" JNIEXPORT jobjectArray JNICALL Java_io_github_humbleui_jwm_Clipboard__1nGetFormats (JNIEnv* env, jclass jclass) { - return jwm::ClipboardX11::inst().getFormats(env); + return jwm::ClipboardWayland::inst().getFormats(env); } extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_Clipboard__1nClear @@ -122,4 +130,4 @@ extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_Clipboard__1nClear extern "C" JNIEXPORT jboolean JNICALL Java_io_github_humbleui_jwm_Clipboard__1nRegisterFormat (JNIEnv* env, jclass jclass, jstring formatId) { return true; -} \ No newline at end of file +} diff --git a/wayland/cc/KeyWayland.cc b/wayland/cc/KeyWayland.cc index 9a638c69..026e31c6 100644 --- a/wayland/cc/KeyWayland.cc +++ b/wayland/cc/KeyWayland.cc @@ -1,22 +1,17 @@ -#include "KeyX11.hh" -#include -#include -#include -#include +#include "KeyWayland.hh" #include "KeyModifier.hh" - bool gKeyStates[(size_t) jwm::Key::_KEY_COUNT] = {0}; -bool jwm::KeyX11::getKeyState(jwm::Key key) { +bool jwm::KeyWayland::getKeyState(jwm::Key key) { return gKeyStates[(size_t) key]; } -void jwm::KeyX11::setKeyState(jwm::Key key, bool isDown) { +void jwm::KeyWayland::setKeyState(jwm::Key key, bool isDown) { gKeyStates[(size_t) key] = isDown; } -int jwm::KeyX11::getModifiers() { +int jwm::KeyWayland::getModifiers() { int m = 0; if (getKeyState(jwm::Key::SHIFT )) m |= (int)jwm::KeyModifier::SHIFT; @@ -28,7 +23,7 @@ int jwm::KeyX11::getModifiers() { return m; } -int jwm::KeyX11::getModifiersFromMask(int mask) { +int jwm::KeyWayland::getModifiersFromMask(int mask) { int m = getModifiers(); if (mask & ShiftMask ) m |= (int)jwm::KeyModifier::SHIFT; @@ -38,7 +33,7 @@ int jwm::KeyX11::getModifiersFromMask(int mask) { return m; } -jwm::Key jwm::KeyX11::fromNative(uint32_t v) { +jwm::Key jwm::KeyWayland::fromNative(uint32_t v) { /* switch (v) { // Modifiers case XK_Caps_Lock: return Key::CAPS_LOCK; @@ -174,5 +169,7 @@ jwm::Key jwm::KeyX11::fromNative(uint32_t v) { // Key::VOLUME_DOWN // Key::MUTE default: return Key::UNDEFINED; - } -} \ No newline at end of file + } */ + // IMPL ME! + return Key::UNDEFINED: +} diff --git a/wayland/cc/KeyWayland.hh b/wayland/cc/KeyWayland.hh index ce03b165..bcbf02d8 100644 --- a/wayland/cc/KeyWayland.hh +++ b/wayland/cc/KeyWayland.hh @@ -4,11 +4,11 @@ #include "Key.hh" namespace jwm { - namespace KeyX11 { + namespace KeyWayland { jwm::Key fromNative(uint32_t v); bool getKeyState(jwm::Key key); void setKeyState(jwm::Key key, bool isDown); int getModifiers(); int getModifiersFromMask(int mask); } -} \ No newline at end of file +} diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index aa78e4ee..e8b96960 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -3,50 +3,59 @@ #include #include "impl/Library.hh" #include "impl/RefCounted.hh" -#include "WindowX11.hh" -#include +#include "WindowWayland.hh" +#include +#include namespace jwm { class LayerGL: public RefCounted, public ILayer { public: - WindowX11* fWindow; - GLXContext _context = nullptr; - using glXSwapIntervalEXT_t = void (*)(Display*, GLXDrawable, int); - glXSwapIntervalEXT_t _glXSwapIntervalEXT; + WindowWayland* fWindow; + wl_egl_window* _eglWindow = nullptr; + EGLContext _context = nullptr; + EGLDisplay _display = nullptr; + EGLSurface _surface = nullptr; - LayerGL() = default; - virtual ~LayerGL() = default; - - void attach(WindowX11* window) { - if (window->_windowManager.getVisualInfo() == nullptr) { - throw std::runtime_error("layer not supported"); - } + LayerGLWayland() = default; + virtual ~LayerGLWayland() = default; + void attach(WindowWayland* window) { fWindow = jwm::ref(window); fWindow->setLayer(this); + if (_display == nullptr) { + _display = eglGetPlatformDisplayEXT(EGL_PLATFORM_WAYLAND_KHR, window->_windowManager.display, EGL_NONE); + + eglInitialize(_display, nullptr, nullptr); + } if (_context == nullptr) { - _context = glXCreateContext(window->_windowManager.getDisplay(), - window->_windowManager.getVisualInfo(), - nullptr, - true); - + EGLint attrList[] = { + EGL_ALPHA_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_RED_SIZE, 8, + EGL_NONE + }; + EGLConfig config; + EGLint numConfig; + eglChooseConfig(_display, attrList, &config, 1, &numConfig); + // :troll: + _context = eglCreateContext(_display, + config, + EGL_NO_CONTEXT, + nullptr); + _eglWindow = wl_egl_window_create(window->_waylandWindow, window->getWidth(), window->getHeight()); + + _surface = eglCreatePlatformWindowSurface(_display, config, _eglWindow, nullptr); } makeCurrentForced(); - _glXSwapIntervalEXT = reinterpret_cast(glXGetProcAddress(reinterpret_cast("glXSwapIntervalEXT"))); - setVsyncMode(VSYNC_ADAPTIVE); } void setVsyncMode(VSync v) override { - - if (_glXSwapIntervalEXT) { - _glXSwapIntervalEXT(fWindow->_windowManager.getDisplay(), - fWindow->_x11Window, - v); - } + // vsync? what vsync? } void resize(int width, int height) { @@ -55,22 +64,25 @@ namespace jwm { glStencilMask(0xffffffff); glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - glViewport(0, 0, width, height); + // ??? + // glViewport(0, 0, width, height); + wl_egl_window_resize(_eglWindow, width, height, 0, 0); } void swapBuffers() { - glXSwapBuffers(fWindow->_windowManager.getDisplay(), fWindow->_x11Window); + eglSwapBuffers(fWindow->_windowManager.getDisplay(), _surface); } void close() override { - glXDestroyContext(fWindow->_windowManager.getDisplay(), _context); + eglDestroyContext(_display, _context); jwm::unref(&fWindow); } void makeCurrentForced() override { ILayer::makeCurrentForced(); - glXMakeCurrent(fWindow->_windowManager.getDisplay(), - fWindow->_x11Window, + eglMakeCurrent(_display, + _surface, + _surface, _context); } }; @@ -89,7 +101,7 @@ extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerGL__1nAttach (JNIEnv* env, jobject obj, jobject windowObj) { try { jwm::LayerGL* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); - jwm::WindowX11* window = reinterpret_cast(jwm::classes::Native::fromJava(env, windowObj)); + jwm::WindowWayland* window = reinterpret_cast(jwm::classes::Native::fromJava(env, windowObj)); instance->attach(window); } catch (const std::exception& e) { jwm::classes::Throwable::throwLayerNotSupportedException(env, "Failed to init OpenGL"); diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index 2ec70c85..f656709b 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -3,44 +3,40 @@ #include #include "impl/Library.hh" #include "impl/RefCounted.hh" -#include "WindowX11.hh" - +#include "WindowWayland.hh" +#include "ShmPool.hh" namespace jwm { class LayerRaster: public RefCounted, public ILayer { public: - WindowX11* fWindow; + WindowWayland* fWindow; size_t _width = 0, _height = 0; - XImage* _xImage = nullptr; - GC _graphicsContext; - VSync _vsync = VSYNC_ENABLED; - - /** - * Using raw pointer here because XImage frees this buffer on XDestroyImage. - */ + wl_buffer* _buffer = nullptr; uint8_t* _imageData = nullptr; + ShmPool _pool = nullptr; + VSync _vsync = VSYNC_ENABLED; LayerRaster() = default; virtual ~LayerRaster() = default; - void attach(WindowX11* window) { + void attach(WindowWayland* window) { fWindow = jwm::ref(window); fWindow->setLayer(this); - - Display* d = fWindow->_windowManager.getDisplay(); - _graphicsContext = DefaultGC(d, DefaultScreen(d)); } void resize(int width, int height) { - Display* d = fWindow->_windowManager.getDisplay(); + wl_display* d = fWindow->_windowManager.display; _width = width; _height = height; - if (_xImage) { - XDestroyImage(_xImage); + int bufSize = width * height * sizeof(uint32_t) * 2; + if (!_pool) { + _pool = new ShmPool(fWindow->_windowManager->shm, bufSize); } - _imageData = new uint8_t[width * height * sizeof(uint32_t)]; - _xImage = XCreateImage(d, CopyFromParent, DefaultDepth(d, DefaultScreen(d)), ZPixmap, 0, (char*)_imageData, width, height, 32, 0); - XInitImage(_xImage); - _xImage->byte_order = _xImage->bitmap_bit_order = LSBFirst; + _pool.grow(bufSize); + // LSBFirst means Little endian : ) + auto buf = _pool.createBuffer(0, width, height, width * sizeof(uint32_t), WL_SHM_FORMAT_ABRG8888); + + _buffer = buf.first; + _imageData = buf.second; } const void* getPixelsPtr() const { @@ -48,18 +44,21 @@ namespace jwm { } int getRowBytes() const { + return _width * sizeof(uint32_t); } void swapBuffers() { - XPutImage(fWindow->_windowManager.getDisplay(), fWindow->_x11Window, _graphicsContext, _xImage, 0, 0, 0, 0, _width, _height); + // : ) + wl_surface_damage_buffer(fWindow->_waylandWindow, 0, 0, UINT32_MAX, UINT32_MAX); } void close() override { - if (_xImage) { - XDestroyImage(_xImage); - _xImage = nullptr; + if (_buffer) { + wl_buffer_destroy(_buffer); + _buffer = nullptr; } + destroy _pool; jwm::unref(&fWindow); } @@ -83,7 +82,7 @@ extern "C" JNIEXPORT jlong JNICALL Java_io_github_humbleui_jwm_LayerRaster__1nMa extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerRaster__1nAttach (JNIEnv* env, jobject obj, jobject windowObj) { jwm::LayerRaster* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); - jwm::WindowX11* window = reinterpret_cast(jwm::classes::Native::fromJava(env, windowObj)); + jwm::WindowWayland* window = reinterpret_cast(jwm::classes::Native::fromJava(env, windowObj)); instance->attach(window); } @@ -120,4 +119,4 @@ extern "C" JNIEXPORT jlong JNICALL Java_io_github_humbleui_jwm_LayerRaster__1nGe (JNIEnv* env, jobject obj) { jwm::LayerRaster* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); return static_cast(instance->getRowBytes()); -} \ No newline at end of file +} diff --git a/wayland/cc/MouseButtonWayland.cc b/wayland/cc/MouseButtonWayland.cc index c1aa2c36..d2fcd79d 100644 --- a/wayland/cc/MouseButtonWayland.cc +++ b/wayland/cc/MouseButtonWayland.cc @@ -1,25 +1,25 @@ -#include "MouseButtonX11.hh" +#include "MouseButtonWayland.hh" -jwm::MouseButton jwm::MouseButtonX11::fromNative(uint32_t v) { +jwm::MouseButton jwm::MouseButtonWayland::fromNative(uint32_t v) { switch (v) { - case 1: return jwm::MouseButton::PRIMARY; - case 2: return jwm::MouseButton::MIDDLE; - case 3: return jwm::MouseButton::SECONDARY; - case 8: return jwm::MouseButton::BACK; - case 9: return jwm::MouseButton::FORWARD; + case 0x110: return jwm::MouseButton::PRIMARY; + case 0x112: return jwm::MouseButton::MIDDLE; + case 0x111: return jwm::MouseButton::SECONDARY; + case 0x116: return jwm::MouseButton::BACK; + case 0x115: return jwm::MouseButton::FORWARD; } return jwm::MouseButton::PRIMARY; } -bool jwm::MouseButtonX11::isButton(uint32_t v) { - return v < 4 || v > 7; // mouse wheel buttons +bool jwm::MouseButtonWayland::isButton(uint32_t v) { + return v >= 0x110 && v <= 0x116; // mouse wheel buttons } -int jwm::MouseButtonX11::fromNativeMask(unsigned v) { +int jwm::MouseButtonWayland::fromNativeMask(unsigned v) { int res = 0; if (v & 0x100) res |= int(jwm::MouseButton::PRIMARY); if (v & 0x400) res |= int(jwm::MouseButton::SECONDARY); if (v & 0x200) res |= int(jwm::MouseButton::MIDDLE); return res; -} \ No newline at end of file +} diff --git a/wayland/cc/MouseButtonWayland.hh b/wayland/cc/MouseButtonWayland.hh index 898edda7..1cf9f960 100644 --- a/wayland/cc/MouseButtonWayland.hh +++ b/wayland/cc/MouseButtonWayland.hh @@ -4,9 +4,9 @@ #include "MouseButton.hh" namespace jwm { - namespace MouseButtonX11 { + namespace MouseButtonWayland { MouseButton fromNative(uint32_t v); int fromNativeMask(unsigned v); bool isButton(uint32_t v); } -} \ No newline at end of file +} diff --git a/wayland/cc/ScreenInfo.cc b/wayland/cc/ScreenInfo.cc new file mode 100644 index 00000000..a7392e40 --- /dev/null +++ b/wayland/cc/ScreenInfo.cc @@ -0,0 +1,5 @@ +#include "ScreenInfo.hh" + +jobject jwm::ScreenInfo::asJavaObject(JNIEnv* env) const { + return jwm::classes::Screen::make(env, id, isPrimary, bounds, bounds, jwm::app.getScale()); +} diff --git a/linux/cc/ScreenInfo.hh b/wayland/cc/ScreenInfo.hh similarity index 100% rename from linux/cc/ScreenInfo.hh rename to wayland/cc/ScreenInfo.hh diff --git a/wayland/cc/ShmPool.cc b/wayland/cc/ShmPool.cc new file mode 100644 index 00000000..e2a3a334 --- /dev/null +++ b/wayland/cc/ShmPool.cc @@ -0,0 +1,92 @@ +#include "ShmPool.hh" +#include +#include +#include +#include +#include + +using namespace jwm; + +static void randname(char *buf) +{ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + long r = ts.tv_nsec; + for (int i = 0; i < 6; ++i) { + buf[i] = 'A'+(r&15)+(r&16)*2; + r >>= 5; + } +} +ShmPool::ShmPool(wl_shm* shm, size_t size): + _size(size) { + _fd = _allocateShmFile(size); + if (_fd < 0) { + // why : ( + throw std::system_error(EIO, "Couldn't allocate buffer"); + } + _pool = wl_shm_create_pool(shm, _fd, size); + _rawData = mmap(nullptr, size, + PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0); + + } +ShmPool::~ShmPool() { + wl_shm_pool_destroy(_pool); + close(_fd); +} + +void ShmPool::grow(size_t size) { + if (size <= _size) + return; + int ret; + do { + ret = ftruncate(_fd, size); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + // AAHHHHH! + throw std::system_error(EIO, "Couldn't grow buffer"); + } + uint8_t* newData = mmap(nullptr, size, + PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0); + // do I need to memcpy??? lets say no :troll: + // TODO: error checking :troll: + munmap(_rawData, _size); + _rawData = newData; + _size = size; + wl_shm_pool_resize(_pool, size); +} + +int ShmPool::_createShmFile() { + int retries = 100; + do { + char name[] = "/wl_shm-XXXXXX"; + randname(name + sizeof(name) - 7); + --retries; + int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); + if (fd >= 0) { + shm_unlink(name); + return fd; + } + } while (retries > 0 && errno == EEXIST); + return -1; +} + +int ShmPool::_allocateShmFile(size_t size) { + int fd = _createShmFile(); + if (fd < 0) + return -1; + int ret; + do { + ret = ftruncate(fd, size); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + close(fd); + return -1; + } + return fd; +} + +std::pair createBuffer(int offset, int width, int height, int stride, uint32_t format) { + wl_buffer* buffer = wl_shm_pool_create_buffer(_pool, offset, width, height, stride, format); + uint32_t* data = &_rawData[offset]; + return std::pair(buffer, data); +} diff --git a/wayland/cc/ShmPool.hh b/wayland/cc/ShmPool.hh new file mode 100644 index 00000000..ed67e1a5 --- /dev/null +++ b/wayland/cc/ShmPool.hh @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +namespace jwm { + class ShmPool { + public: + ShmPool(wl_shm* shm, size_t size); + ~ShmPool(); + + size_t _size; + int _fd; + wl_shm_pool* _pool; + uint8_t* _rawData; + + // grows current file to at least this size + void grow(size_t size); + + std::pair createBuffer(int offset, int width, int height, int stride, uint32_t format); + + int _createShmFile(); + int _allocateShmFile(size_t size); + }; +} diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index e8f799d3..a86f4650 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -14,6 +14,8 @@ #include #include #include "Log.hh" +#include "xdg-shell.hh" +#include using namespace jwm; @@ -35,13 +37,15 @@ WindowManagerWayland::WindowManagerWayland(): throw std::system_error(1, std::system_category); } + + { wl_cursor_theme* cursor_theme = wl_cursor_theme_load(nullptr, 24, shm); // TODO: what about if missing : ( auto loadCursor = [&](const char* name) { wl_cursor* cursor = wl_cursor_theme_get_cursor(cursor_theme, name); wl_cursor_image* cursorImage = cursor->images[0]; - return wl_cursor_image_get_buffer(cursorImage); + return cursorImage; } _cursors[static_cast(jwm::MouseCursor::ARROW )] = loadCursor("default"); @@ -55,8 +59,28 @@ WindowManagerWayland::WindowManagerWayland(): _cursors[static_cast(jwm::MouseCursor::RESIZE_WE )] = loadCursor("ew-resize"); _cursors[static_cast(jwm::MouseCursor::RESIZE_NESW )] = loadCursor("nesw-resize"); _cursors[static_cast(jwm::MouseCursor::RESIZE_NWSE )] = loadCursor("nwse-resize"); + + cursorSurface = wl_compositor_create_surface(compositor); + + wl_surface_attach(cursorSurface, + wl_cursor_get_image_buffer(_cursors[static_cast(jwm::MouseCursor::ARROW)]), 0, 0); + wl_surface_commit(cursorSurface); + } + + { + pointer = wl_seat_get_pointer(seat); + wl_pointer_listener pointerListener = { + .enter = pointerHandleEnter, + .leave = pointerHandleLeave, + .motion = pointerHandleMotion, + .button = pointerHandleButton, + .axis = pointerHandleAxis + }; + wl_pointer_add_listener(pointer, &pointerListener, nullptr); } + + } @@ -64,58 +88,11 @@ WindowManagerWayland::WindowManagerWayland(): void WindowManagerWayland::runLoop() { _runLoop = true; - XEvent ev; - - // buffer to read into; really only needs to be two characters long due to the notifyBool fast path, but longer doesn't hurt - char buf[100]; - // initialize a pipe to write to whenever this loop needs to process something new - int pipes[2]; - if (pipe(pipes)) { - printf("Failed to open pipe\n"); - return; - } - - notifyFD = pipes[1]; - fcntl(pipes[1], F_SETFL, O_NONBLOCK); // make sure notifyLoop doesn't block - // two polled items - the X11 event queue, and our event queue - struct pollfd ps[] = {{.fd=XConnectionNumber(display), .events=POLLIN}, {.fd=pipes[0], .events=POLLIN}}; + // who be out here running they loop while (_runLoop) { - while (XPending(display)) { - XNextEvent(display, &ev); - _processXEvent(ev); - if (jwm::classes::Throwable::exceptionThrown(app.getJniEnv())) - _runLoop = false; - } - _processCallbacks(); - - // block until the next X11 or our event - if (poll(&ps[0], 2, -1) < 0) { - printf("Error during poll\n"); - break; - } - - // clear pipe - if (ps[1].revents & POLLIN) { - while (read(pipes[0], buf, sizeof(buf)) == sizeof(buf)) { } - } - // clear fast path boolean; done after clearing the pipe so that, during event execution, new notifyLoop calls can still function - notifyBool.store(false); - // The events causing a notifyLoop anywhere between poll() end and here will be processed in all cases, as that's the next thing that happens } - notifyFD = -1; - close(pipes[0]); - close(pipes[1]); -} - -void WindowManagerWayland::notifyLoop() { - if (notifyFD==-1) return; - // fast notifyBool path to not make system calls when not necessary - if (!notifyBool.exchange(true)) { - char dummy[1] = {0}; - int unused = write(notifyFD, dummy, 1); // this really shouldn't fail, but if it does, the pipe should either be full (good), or dead (bad, but not our business) - } } void WindowManagerWayland::_processCallbacks() { @@ -133,7 +110,7 @@ void WindowManagerWayland::_processCallbacks() { } { // copy window list in case one closes any other, invalidating some iterator in _nativeWindowToMy - std::vector copy; + std::vector copy; for (auto& p : _nativeWindowToMy) { copy.push_back(p.second); } @@ -153,37 +130,123 @@ void WindowManagerWayland::_processCallbacks() { void WindowManagerWayland::registryHandleGlobal(void* data, wl_registry *registry, uint32_t name, const char* interface, uint32_t version) { if (strcmp(interface, "wl_compositor") == 0) { - compositor = wl_registry_bind(registry, name, + compositor = (wl_compositor*)wl_registry_bind(registry, name, &wl_compositor_interface, 3); } else if (strcmp(interface, "wl_shm") == 0) { - shm = wl_registry_bind(registry, name, + shm = (wl_shm*)wl_registry_bind(registry, name, &wl_shm_interface, 1); - } else if (strcmp(interface, "zxdg_shell_v6") == 0) { - xdgShell = wl_registry_bind(registry, name, - &zxdg_shell_v6_interface, 1); + } else if (strcmp(interface, "xdg_wm_base") == 0) { + xdgShell = (xdg_wm_base*)wl_registry_bind(registry, name, + &xdg_wm_base_interface, 1); } else if (strcmp(interface, "wl_data_device_manager") == 0) { - deviceManager = wl_registry_bind(registry, name, + deviceManager = (wl_data_device_manager*)wl_registry_bind(registry, name, &wl_data_device_manager_interface, 1); } else if (strcmp(interface, "wl_seat") == 0) { - seat = wl_registry_bind(registry, name, + seat = (wl_seat*)wl_registry_bind(registry, name, &wl_seat_interface, 1); } } void WindowManagerWayland::registryHandleGlobalRemove(void* data, wl_registry *registry, uint32_t name) { // i do nothing : ) } -std::vector WindowManagerWayland::getClipboardFormats() { - auto owner = XGetSelectionOwner(display, _atoms.CLIPBOARD); - if (owner == None) - { - return {}; + +void WindowManagerWayland::pointerHandleEnter(void* data, wl_pointer* pointer, uint32_t serial, + wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { + wl_cursor_image* image = _cursors[static_cast(jwm::MouseCursor::ARROW)]; + wl_pointer_set_cursor(cursor, serial, cursorSurface, image->hotspot_x, image->hotspot_y); + focusedSurface = surface; +} +void WindowManagerWayland::pointerHandleLeave(void* data, wl_pointer* pointer, uint32_t serial, + wl_surface *surface) { + focusedSurface = nullptr; + // ??? + mouseMask = 0; +} +void WindowManagerWayland::pointerHandleMotion(void* data, wl_pointer* pointer, + uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { + lastMousePosX = surface_x; + lastMousePosY = surface_y; + if (focusedSurface) { + ::WindowWayland* window = _nativeWindowToMy.find(focusedSurface)->second; + mouseUpdate(window, wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y), mouseMask); } - assert(("create at least one window in order to use clipboard" && !_nativeWindowToMy.empty())); - - auto nativeHandle = _nativeWindowToMy.begin()->first; - assert(nativeHandle); - +} +void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, + uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { + using namespace classes; + if (state == 0) { + // release + switch (button) { + // primary + case 0x110: + mouseMask &= ~0x100; + break; + // secondary + case 0x111: + mouseMask &= ~0x400; + break; + // middle + case 0x112: + mouseMask &= ~0x200; + break; + default: + break; + } + + if (MouseButtonWayland::isButton(button) && focusedSurface) { + jwm::JNILocal eventButton( + app.getJniEnv(), + EventMouseButton::make( + app.getJniEnv(), + MouseButtonWayland::fromNative(button), + false, + lastMousePosX, + lastMousePosY, + jwm::KeyWayland::getModifiers() + ) + ); + WindowWayland* window = _nativeWindowToMy.find(focusedSurface)->second; + window->dispatch(eventButton.get()); + } + } else { + // down + switch (button) { + // primary + case 0x110: + mouseMask |= 0x100; + break; + // secondary + case 0x111: + mouseMask |= 0x400; + break; + // middle + case 0x112: + mouseMask |= 0x200; + break; + default: + break; + } + + if (MouseButtonWayland::isButton(button) && focusedSurface) { + jwm::JNILocal eventButton( + app.getJniEnv(), + EventMouseButton::make( + app.getJniEnv(), + MouseButtonWayland::fromNative(button), + true, + lastMousePosX, + lastMousePosY, + jwm::KeyWayland::getModifiers() + ) + ); + WindowWayland* window = _nativeWindowToMy.find(focusedSurface)->second; + window->dispatch(eventButton.get()); + } + } +} +std::vector WindowManagerWayland::getClipboardFormats() { + /* XConvertSelection(display, _atoms.CLIPBOARD, _atoms.TARGETS, @@ -241,12 +304,32 @@ std::vector WindowManagerWayland::getClipboardFormats() { // fetching data XDeleteProperty(display, nativeHandle, _atoms.JWM_CLIPBOARD); + */ + std::vector result; return result; } - +void WindowManagerWayland::mouseUpdate(WindowWayland* myWindow, uint32_t x, uint32_t y, uint32_t mask) { + using namespace classes; + + // impl me : ) + int movementX = 0, movementY = 0; + jwm::JNILocal eventMove( + app.getJniEnv(), + EventMouseMove::make(app.getJniEnv(), + x, + y, + movementX, + movementY, + jwm::MouseButtonWayland::fromNativeMask(mask), + // impl me! + jwm::KeyWayland::getModifiersFromMask(0) + ) + ); + myWindow->dispatch(eventMove.get()); +} jwm::ByteBuf WindowManagerWayland::getClipboardContents(const std::string& type) { auto nativeHandle = _nativeWindowToMy.begin()->first; - + /* XConvertSelection(display, _atoms.CLIPBOARD, XInternAtom(display, type.c_str(), false), @@ -295,6 +378,7 @@ jwm::ByteBuf WindowManagerWayland::getClipboardContents(const std::string& type) } XDeleteProperty(display, nativeHandle, _atoms.JWM_CLIPBOARD); + */ return {}; } @@ -302,7 +386,7 @@ void WindowManagerWayland::registerWindow(WindowWayland* window) { _nativeWindowToMy[window->_waylandWindow] = window; } -void WindowManagerWayland::unregisterWindow(WindowX11* window) { +void WindowManagerWayland::unregisterWindow(WindowWayland* window) { auto it = _nativeWindowToMy.find(window->_waylandWindow); if (it != _nativeWindowToMy.end()) { _nativeWindowToMy.erase(it); @@ -311,15 +395,15 @@ void WindowManagerWayland::unregisterWindow(WindowX11* window) { void WindowManagerWayland::terminate() { _runLoop = false; - notifyLoop(); } void WindowManagerWayland::setClipboardContents(std::map&& c) { assert(("create at least one window in order to use clipboard" && !_nativeWindowToMy.empty())); _myClipboardContents = c; - ::Window window = _nativeWindowToMy.begin()->first; - XSetSelectionOwner(display, XA_PRIMARY, window, CurrentTime); - XSetSelectionOwner(display, _atoms.CLIPBOARD, window, CurrentTime); + // impl me : ) + auto window = _nativeWindowToMy.begin()->first; + // XSetSelectionOwner(display, XA_PRIMARY, window, CurrentTime); + // XSetSelectionOwner(display, _atoms.CLIPBOARD, window, CurrentTime); } void WindowManagerWayland::enqueueTask(const std::function& task) { diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index a5c30afc..1dfe03ec 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -13,7 +13,7 @@ #include "MouseCursor.hh" #include #include -#include "xdg_shell.h" +#include "xdg-shell.hh" namespace jwm { class WindowWayland; @@ -55,6 +55,18 @@ namespace jwm { void registryHandleGlobalRemove(void* data, wl_registry *registry, uint32_t name); + void pointerHandleEnter(void* data, wl_pointer *pointer, + uint32_t serial, wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y); + void pointerHandleLeave(void* data, wl_pointer *pointer, + uint32_t serial, wl_surface* surface); + void pointerHandleMotion(void* data, wl_pointer *pointer, + uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y); + void pointerHandleButton(void* data, wl_pointer *pointer, + uint32_t serial, uint32_t time, uint32_t button, + uint32_t state); + void pointerHandleAxis(void* data, wl_pointer *pointer, + uint32_t time, uint32_t axis, wl_fixed_t value); + ByteBuf getClipboardContents(const std::string& type); @@ -63,10 +75,12 @@ namespace jwm { wl_display* display = nullptr wl_registry* registry = nullptr wl_shm* shm = nullptr; - zxdg_shell_v6* xdgShell = nullptr; + xdg_wm_base* xdgShell = nullptr; wl_compositor* compositor = nullptr; wl_data_device_manager* deviceManager = nullptr; wl_seat* seat = nullptr; + wl_pointer* pointer = nullptr; + // XVisualInfo* x11VisualInfo; // XSetWindowAttributes x11SWA; @@ -75,15 +89,17 @@ namespace jwm { std::atomic_bool notifyBool{false}; int lastMousePosX = 0; int lastMousePosY = 0; - void mouseUpdate(WindowWayland* myWindow); + int mouseMask = 0; + void mouseUpdate(WindowWayland* myWindow, uint32_t x, uint32_t y, uint32_t mask); - std::map<::Window, WindowWayland*> _nativeWindowToMy; + std::map _nativeWindowToMy; std::map _myClipboardContents; wl_surface* cursorSurface; + wl_surface* focusedSurface = nullptr; // Is holding all cursors in memory a good idea? - wl_buffer _cursors[static_cast(jwm::MouseCursor::COUNT)]; + wl_cursor_image* _cursors[static_cast(jwm::MouseCursor::COUNT)]; std::mutex _taskQueueLock; diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index 4d1c525f..cc64c8cd 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -21,395 +21,95 @@ WindowWayland::~WindowWayland() { } void WindowWayland::setTitle(const std::string& title) { - XChangeProperty(_windowManager.getDisplay(), - _x11Window, - _windowManager.getAtoms()._NET_WM_NAME, - _windowManager.getAtoms().UTF8_STRING, - 8, - PropModeReplace, - reinterpret_cast(title.c_str()), - title.length()); -} - -void WindowX11::setTitlebarVisible(bool isVisible) { - MotifHints motifHints = {0}; - - motifHints.flags = MOTIF_HINTS_DECORATIONS; - motifHints.decorations = int(isVisible); - - XChangeProperty(_windowManager.getDisplay(), - _x11Window, - _windowManager.getAtoms()._MOTIF_WM_HINTS, - _windowManager.getAtoms()._MOTIF_WM_HINTS, - 32, - PropModeReplace, - (unsigned char*) &motifHints, - 5); -} - -void WindowX11::close() { - if (_x11Window) { - _windowManager.unregisterWindow(this); - XDestroyWindow(_windowManager.display, _x11Window); - _x11Window = 0; - } + // impl me : ) } -void WindowX11::_xSendEventToWM(Atom atom, long a, long b, long c, long d, long e) const { - XEvent event = { 0 }; - event.type = ClientMessage; - event.xclient.window = _x11Window; - event.xclient.format = 32; // data is 32-bit longs - event.xclient.message_type = atom; - event.xclient.data.l[0] = a; - event.xclient.data.l[1] = b; - event.xclient.data.l[2] = c; - event.xclient.data.l[3] = d; - event.xclient.data.l[4] = e; - - XSendEvent(_windowManager.display, - DefaultRootWindow(_windowManager.display), - False, - SubstructureNotifyMask | SubstructureRedirectMask, - &event); -} -unsigned long WindowX11::_xGetWindowProperty(Atom property, Atom type, unsigned char** value) const { - Atom actualType; - int actualFormat; - unsigned long itemCount, bytesAfter; - - XGetWindowProperty(_windowManager.display, - _x11Window, - property, - 0, - std::numeric_limits::max(), - false, - type, - &actualType, - &actualFormat, - &itemCount, - &bytesAfter, - value); - - return itemCount; -} - -void WindowX11::maximize() { - XWindowAttributes wa; - XGetWindowAttributes(_windowManager.display, _x11Window, &wa); - - if (wa.map_state == IsViewable) { - _xSendEventToWM(_windowManager._atoms._NET_WM_STATE, - 1, - _windowManager._atoms._NET_WM_STATE_MAXIMIZED_HORZ, - _windowManager._atoms._NET_WM_STATE_MAXIMIZED_VERT, - 0, - 0); - } else { - Atom* states = nullptr; - unsigned long count = _xGetWindowProperty(_windowManager._atoms._NET_WM_STATE, - XA_ATOM, - reinterpret_cast(&states)); - - - Atom missing[2] = { - _windowManager._atoms._NET_WM_STATE_MAXIMIZED_VERT, - _windowManager._atoms._NET_WM_STATE_MAXIMIZED_HORZ - }; - unsigned long missingCount = 2; - - for (unsigned long i = 0; i < count; i++) - { - for (unsigned long j = 0; j < missingCount; j++) - { - if (states[i] == missing[j]) - { - missing[j] = missing[missingCount - 1]; - missingCount--; - } - } - } - if (states) - XFree(states); - - if (!missingCount) - return; +void WindowWayland::setTitlebarVisible(bool isVisible) { + // impl me : ) +} - XChangeProperty(_windowManager.display, - _x11Window, - _windowManager._atoms._NET_WM_STATE, - XA_ATOM, - 32, - PropModeAppend, - (unsigned char*) missing, - missingCount); +void WindowWayland::close() { + if (_waylandWindow) { + _windowManager.unregisterWindow(this); + wl_surface_destroy(_waylandWindow); } - XFlush(_windowManager.display); } - -void WindowX11::minimize() { - XIconifyWindow(_windowManager.display, _x11Window, 0); +void WindowWayland::maximize() { + // impl me :) } -void WindowX11::restore() { - if (_windowManager._atoms._NET_WM_STATE && - _windowManager._atoms._NET_WM_STATE_MAXIMIZED_VERT && - _windowManager._atoms._NET_WM_STATE_MAXIMIZED_HORZ) { - _xSendEventToWM(_windowManager._atoms._NET_WM_STATE, - 0, - _windowManager._atoms._NET_WM_STATE_MAXIMIZED_VERT, - _windowManager._atoms._NET_WM_STATE_MAXIMIZED_HORZ, - 1, - 0); - } +void WindowWayland::minimize() { + // impl me : ) } -void WindowX11::setFullScreen(bool isFullScreen) { - // NOTE: Largely borrowed from https://github.com/godotengine/godot/blob/f7cf9fb148140b86ee5795110373a0d55ff32860/platform/linuxbsd/x11/display_server_x11.cpp - Display* display = _windowManager.display; - - // Should the window be exclusively full screen (i.e. block out other popups). - // There isn't a HumbleUI setting for this, and my WM defaults to exclusive full-screen, - // (as does Windows, as I recall) so let's assume that we want the window to be exclusively fullscreen. - bool isExclusiveFullScreen = true; - - if (isFullScreen) { // and the window is not borderless: - // Remove window decorations to simulate full screen - MotifHints hints; - Atom property; - hints.flags = 2; - hints.decorations = 0; - property = XInternAtom(display, "_MOTIF_WM_HINTS", True); - if (property != None) { - XChangeProperty(display, _x11Window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); - } - } - - XEvent xev; - - memset(&xev, 0, sizeof(xev)); - xev.type = ClientMessage; - xev.xclient.window = _x11Window; - xev.xclient.message_type = _windowManager._atoms._NET_WM_STATE; - xev.xclient.format = 32; - xev.xclient.data.l[0] = isFullScreen ? _WM_ADD : _WM_REMOVE; - xev.xclient.data.l[1] = _windowManager._atoms._NET_WM_STATE_FULLSCREEN; - xev.xclient.data.l[2] = 0; - - XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); - - // set bypass compositor hint - Atom bypass_compositor = XInternAtom(display, "_NET_WM_BYPASS_COMPOSITOR", True); - unsigned long compositing_disable_on = 0; // By default, don't allow window compositing - - if (isFullScreen) { - // NOTE: Compositor flickers. May be an issue. - if (isExclusiveFullScreen) { - compositing_disable_on = 1; // Force compositing to disable for efficiency - } else { - compositing_disable_on = 2; // Force composition on to allow pop-up windows - } - } - - if (bypass_compositor != None) { - XChangeProperty(display, - _x11Window, - bypass_compositor, - XA_CARDINAL, - 32, - PropModeReplace, - (unsigned char *)&compositing_disable_on, - 1); - } - - XFlush(display); - - if (!isFullScreen) { - // Reset window decorations to their previous states - MotifHints hints; - Atom property; - hints.flags = 2; - hints.decorations = 1; // Add window borders back - property = XInternAtom(display, "_MOTIF_WM_HINTS", True); - if (property != None) { - XChangeProperty(display, - _x11Window, - property, - property, - 32, - PropModeReplace, - (unsigned char *)&hints, - 5); - } - } +void WindowWayland::restore() { + // impl me } -bool WindowX11::isFullScreen() { - // NOTE: Largely borrowed from https://github.com/godotengine/godot/blob/f7cf9fb148140b86ee5795110373a0d55ff32860/platform/linuxbsd/x11/display_server_x11.cpp - Display* display = _windowManager.display; - - Atom type; - int format; - unsigned long len; - unsigned long remaining; - unsigned char *data = nullptr; - bool retval = false; - - int result = XGetWindowProperty( - display, - _x11Window, - _windowManager._atoms._NET_WM_STATE, - 0, - 1024, - False, - XA_ATOM, - &type, - &format, - &len, - &remaining, - &data); - - if (result == Success) { - Atom *atoms = (Atom *)data; - for (uint64_t i = 0; i < len; i++) { - if (atoms[i] == _windowManager._atoms._NET_WM_STATE_FULLSCREEN) { - retval = true; - break; - } - } - XFree(data); - } +void WindowWayland::setFullScreen(bool isFullScreen) { + // impl me : ) +} - return retval; +bool WindowWayland::isFullScreen() { + // impl me : ) + return false; } -void WindowX11::getDecorations(int& left, int& top, int& right, int& bottom) { - unsigned long* data = nullptr; - _xGetWindowProperty(_windowManager.getAtoms()._NET_FRAME_EXTENTS, XA_CARDINAL, reinterpret_cast(&data)); - if (data!=nullptr) { - left = data[0]; - top = data[2]; - right = data[1]; - bottom = data[3]; - XFree(data); - } else { - XWindowAttributes xwa; - XGetWindowAttributes(_windowManager.display, _x11Window, &xwa); - left = xwa.x; - top = xwa.y; - right = 0; - bottom = 0; - } +void WindowWayland::getDecorations(int& left, int& top, int& right, int& bottom) { + // impl me : ) } -void WindowX11::getContentPosition(int& posX, int& posY) { - int x, y; - ::Window child; - XTranslateCoordinates(_windowManager.display, - _x11Window, - XRootWindow(_windowManager.display, 0), - 0, 0, - &x, &y, - &child); - posX = x; - posY = y; +void WindowWayland::getContentPosition(int& posX, int& posY) { + posX = 0; + posY = 0; } -int WindowX11::getLeft() { +int WindowWayland::getLeft() { int x, y; getContentPosition(x, y); return x; } -int WindowX11::getTop() { +int WindowWayland::getTop() { int x, y; getContentPosition(x, y); return y; } -int WindowX11::getWidth() { +int WindowWayland::getWidth() { return _width; } -int WindowX11::getHeight() { +int WindowWayland::getHeight() { return _height; } -float WindowX11::getScale() { +float WindowWayland::getScale() { + // TODO: use surface scaling return jwm::app.getScale(); } -bool WindowX11::init() +bool WindowWayland::init() { - _x11Window = XCreateWindow(_windowManager.getDisplay(), - _windowManager.getScreen()->root, - 0, 0, - 800, 500, - 0, - _windowManager.getX11VisualDepth(), - InputOutput, - _windowManager.getX11Visual(), - CWColormap | CWEventMask | CWCursor, - &_windowManager.getSWA() - ); - - // tell X11 we want to handle close button - XSetWMProtocols(_windowManager.getDisplay(), - _x11Window, - &_windowManager.getAtoms().WM_DELETE_WINDOW, - WindowManagerX11::Atoms::PROTOCOL_COUNT); - - // IC - { - _ic = XCreateIC(_windowManager.getIM(), - XNInputStyle, - XIMPreeditNothing | XIMStatusNothing, - XNClientWindow, - _x11Window, - nullptr); - - XSetICFocus(_ic); - } - - + _waylandWindow = wl_compositor_create_surface(_windowManager.compositor); + + xdgSurface = xdg_wm_base_get_xdg_surface(_windowManager.xdgShell, _waylandWindow); + xdgTopLevel = xdg_surface_get_toplevel(xdgSurface); - // XSync - { - XSyncValue value; - XSyncIntToValue(&value, 0); - _xsyncRequestCounter.counter = XSyncCreateCounter(_windowManager.getDisplay(), value); - XChangeProperty(_windowManager.getDisplay(), - _x11Window, - _windowManager.getAtoms()._NET_WM_SYNC_REQUEST_COUNTER, - XA_CARDINAL, - 32, - PropModeReplace, - (const unsigned char*)&_xsyncRequestCounter.counter, 1); - - } _windowManager.registerWindow(this); return true; } -void WindowX11::move(int left, int top) { - _posX = left; - _posY = top; - if (_visible) - XMoveWindow(_windowManager.display, _x11Window, left, top); +void WindowWayland::move(int left, int top) { + // NO HAVING FUN! } -void WindowX11::resize(int width, int height) { - _width = width; - _height = height; - if (_visible) { - XResizeWindow(_windowManager.display, _x11Window, width, height); - jwm::JNILocal eventWindowResize(app.getJniEnv(), classes::EventWindowResize::make(app.getJniEnv(), width, height, width, height)); - dispatch(eventWindowResize.get()); - } +void WindowWayland::resize(int width, int height) { + // BOO! } -void WindowX11::setVisible(bool isVisible) { +void WindowWayland::setVisible(bool isVisible) { if (_visible != isVisible) { _visible = isVisible; if (_visible) { @@ -424,49 +124,41 @@ void WindowX11::setVisible(bool isVisible) { } } -const ScreenInfo& WindowX11::getScreen() { - // in X11, there's no straightforward way to get screen of window. - // instead, we should do it manually using center point of the window and calculating which monitor this point - // belongs to. - - int centerX = getLeft() + getWidth() / 2; - int centerY = getTop() + getHeight() / 2; - for (auto& screen : jwm::app.getScreens()) { - if (screen.bounds.isPointInside(centerX, centerY)) { - return screen; - } - } - return *jwm::app.getScreens().begin(); -} - -void jwm::WindowX11::setCursor(jwm::MouseCursor cursor) { - if (auto x11Cursor = _windowManager._cursors[static_cast(cursor)]) { - XDefineCursor(_windowManager.display, _x11Window, x11Cursor); +void jwm::WindowWayland::setCursor(jwm::MouseCursor cursor) { + if (auto wayCursor = _windowManager._cursors[static_cast(cursor)]) { + wl_surface_attach(_windowManager.cursorSurface, + wl_cursor_image_get_buffer(wayCursor->images[0]), + 0, 0); + wl_surface_commit(_windowManager.cursorSurface); + // TODO: hotspots? } else { - XUndefineCursor(_windowManager.display, _x11Window); + auto wayCursor = _windowManager.cursors[static_cast(jwm::MouseCursor::ARROW)]; + wl_surface_attach(_windowManager.cursorSurface, + wl_cursor_image_get_buffer(wayCursor->images[0]), 0, 0); + wl_surface_commit(_windowManager.cursorSurface); } } // JNI -extern "C" JNIEXPORT jlong JNICALL Java_io_github_humbleui_jwm_WindowX11__1nMake +extern "C" JNIEXPORT jlong JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nMake (JNIEnv* env, jclass jclass) { - std::unique_ptr instance = std::make_unique(env, jwm::app.getWindowManager()); + std::unique_ptr instance = std::make_unique(env, jwm::app.getWindowManager()); if (instance->init()) { return reinterpret_cast(instance.release()); } return 0; } -extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nSetVisible +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nSetVisible (JNIEnv* env, jobject obj, jboolean isVisible) { - reinterpret_cast(jwm::classes::Native::fromJava(env, obj))->setVisible(isVisible); + reinterpret_cast(jwm::classes::Native::fromJava(env, obj))->setVisible(isVisible); } -extern "C" JNIEXPORT jobject JNICALL Java_io_github_humbleui_jwm_WindowX11__1nGetWindowRect +extern "C" JNIEXPORT jobject JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nGetWindowRect (JNIEnv* env, jobject obj) { - jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); int left, top, right, bottom; instance->getDecorations(left, top, right, bottom); int x, y; @@ -480,9 +172,9 @@ extern "C" JNIEXPORT jobject JNICALL Java_io_github_humbleui_jwm_WindowX11__1nGe ); } -extern "C" JNIEXPORT jobject JNICALL Java_io_github_humbleui_jwm_WindowX11__1nGetContentRect +extern "C" JNIEXPORT jobject JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nGetContentRect (JNIEnv* env, jobject obj) { - jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); int left, top, right, bottom; instance->getDecorations(left, top, right, bottom); return jwm::classes::IRect::toJavaXYWH( @@ -494,63 +186,57 @@ extern "C" JNIEXPORT jobject JNICALL Java_io_github_humbleui_jwm_WindowX11__1nGe ); } -extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nSetWindowPosition +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nSetWindowPosition (JNIEnv* env, jobject obj, int left, int top) { - jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); instance->move(left, top); } -extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nSetWindowSize +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nSetWindowSize (JNIEnv* env, jobject obj, int width, int height) { - jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); // TODO https://github.com/HumbleUI/JWM/issues/109 instance->resize(width, height); } -extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nSetContentSize +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nSetContentSize (JNIEnv* env, jobject obj, int width, int height) { - jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); instance->resize(width, height); } -extern "C" JNIEXPORT jobject JNICALL Java_io_github_humbleui_jwm_WindowX11__1nGetScreen +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nRequestFrame (JNIEnv* env, jobject obj) { - jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); - return instance->getScreen().asJavaObject(env); -} - -extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nRequestFrame - (JNIEnv* env, jobject obj) { - jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); instance->requestRedraw(); } -extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nMaximize +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nMaximize (JNIEnv* env, jobject obj) { - reinterpret_cast(jwm::classes::Native::fromJava(env, obj))->maximize(); + reinterpret_cast(jwm::classes::Native::fromJava(env, obj))->maximize(); } -extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nMinimize +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nMinimize (JNIEnv* env, jobject obj) { - reinterpret_cast(jwm::classes::Native::fromJava(env, obj))->minimize(); + reinterpret_cast(jwm::classes::Native::fromJava(env, obj))->minimize(); } -extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nRestore +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nRestore (JNIEnv* env, jobject obj) { - reinterpret_cast(jwm::classes::Native::fromJava(env, obj))->restore(); + reinterpret_cast(jwm::classes::Native::fromJava(env, obj))->restore(); } -extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nClose +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nClose (JNIEnv* env, jobject obj) { - jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); instance->close(); } -extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nSetTitle +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nSetTitle (JNIEnv* env, jobject obj, jbyteArray title) { - jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); jbyte* bytes = env->GetByteArrayElements(title, nullptr); std::string titleS = { bytes, bytes + env->GetArrayLength(title) }; @@ -559,27 +245,33 @@ extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nSetTi instance->setTitle(titleS); } -extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nSetTitlebarVisible +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nSetTitlebarVisible (JNIEnv* env, jobject obj, jboolean isVisible) { - jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); instance->setTitlebarVisible(isVisible); } -extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nSetMouseCursor +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nSetMouseCursor (JNIEnv* env, jobject obj, jint idx) { - jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); instance->setCursor(static_cast(idx)); } -extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowX11__1nSetFullScreen +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nSetFullScreen (JNIEnv* env, jobject obj, jboolean isFullScreen) { - jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); instance->setFullScreen(isFullScreen); } -extern "C" JNIEXPORT jboolean JNICALL Java_io_github_humbleui_jwm_WindowX11__1nIsFullScreen +extern "C" JNIEXPORT jboolean JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nIsFullScreen (JNIEnv* env, jobject obj) { - jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); return instance->isFullScreen(); } + +extern "C" JNIEXPORT jfloat JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nGetScale + (JNIEnv* env, jobject obj) { + jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + return instance->getScale(); +} diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index e47e27a0..21fa1867 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -4,9 +4,9 @@ #include #include "Window.hh" #include "WindowManagerWayland.hh" -#include "ILayer.hh" +#include #include "ScreenInfo.hh" - +#include "xdg-shell.hh" namespace jwm { class WindowWayland: public jwm::Window { public: @@ -78,7 +78,8 @@ namespace jwm { WindowManagerWayland& _windowManager; ILayer* _layer = nullptr; - ::Window _waylandWindow = 0; - XIC _ic; + wl_surface* _waylandWindow = nullptr; + xdg_surface* xdgSurface = nullptr; + xdg_toplevel* xdgToplevel = nullptr; }; } diff --git a/wayland/cc/xdg-shell.c b/wayland/cc/xdg-shell.c deleted file mode 100644 index 68ea631f..00000000 --- a/wayland/cc/xdg-shell.c +++ /dev/null @@ -1,172 +0,0 @@ -/* Generated by wayland-scanner 1.22.0 */ - -/* - * Copyright © 2008-2013 Kristian Høgsberg - * Copyright © 2013 Rafael Antognolli - * Copyright © 2013 Jasper St. Pierre - * Copyright © 2010-2013 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include "wayland-util.h" - -#ifndef __has_attribute -# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ -#endif - -#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) -#define WL_PRIVATE __attribute__ ((visibility("hidden"))) -#else -#define WL_PRIVATE -#endif - -extern const struct wl_interface wl_output_interface; -extern const struct wl_interface wl_seat_interface; -extern const struct wl_interface wl_surface_interface; -extern const struct wl_interface zxdg_popup_v6_interface; -extern const struct wl_interface zxdg_positioner_v6_interface; -extern const struct wl_interface zxdg_surface_v6_interface; -extern const struct wl_interface zxdg_toplevel_v6_interface; - -static const struct wl_interface *xdg_shell_unstable_v6_types[] = { - NULL, - NULL, - NULL, - NULL, - &zxdg_positioner_v6_interface, - &zxdg_surface_v6_interface, - &wl_surface_interface, - &zxdg_toplevel_v6_interface, - &zxdg_popup_v6_interface, - &zxdg_surface_v6_interface, - &zxdg_positioner_v6_interface, - &zxdg_toplevel_v6_interface, - &wl_seat_interface, - NULL, - NULL, - NULL, - &wl_seat_interface, - NULL, - &wl_seat_interface, - NULL, - NULL, - &wl_output_interface, - &wl_seat_interface, - NULL, -}; - -static const struct wl_message zxdg_shell_v6_requests[] = { - { "destroy", "", xdg_shell_unstable_v6_types + 0 }, - { "create_positioner", "n", xdg_shell_unstable_v6_types + 4 }, - { "get_xdg_surface", "no", xdg_shell_unstable_v6_types + 5 }, - { "pong", "u", xdg_shell_unstable_v6_types + 0 }, -}; - -static const struct wl_message zxdg_shell_v6_events[] = { - { "ping", "u", xdg_shell_unstable_v6_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface zxdg_shell_v6_interface = { - "zxdg_shell_v6", 1, - 4, zxdg_shell_v6_requests, - 1, zxdg_shell_v6_events, -}; - -static const struct wl_message zxdg_positioner_v6_requests[] = { - { "destroy", "", xdg_shell_unstable_v6_types + 0 }, - { "set_size", "ii", xdg_shell_unstable_v6_types + 0 }, - { "set_anchor_rect", "iiii", xdg_shell_unstable_v6_types + 0 }, - { "set_anchor", "u", xdg_shell_unstable_v6_types + 0 }, - { "set_gravity", "u", xdg_shell_unstable_v6_types + 0 }, - { "set_constraint_adjustment", "u", xdg_shell_unstable_v6_types + 0 }, - { "set_offset", "ii", xdg_shell_unstable_v6_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface zxdg_positioner_v6_interface = { - "zxdg_positioner_v6", 1, - 7, zxdg_positioner_v6_requests, - 0, NULL, -}; - -static const struct wl_message zxdg_surface_v6_requests[] = { - { "destroy", "", xdg_shell_unstable_v6_types + 0 }, - { "get_toplevel", "n", xdg_shell_unstable_v6_types + 7 }, - { "get_popup", "noo", xdg_shell_unstable_v6_types + 8 }, - { "set_window_geometry", "iiii", xdg_shell_unstable_v6_types + 0 }, - { "ack_configure", "u", xdg_shell_unstable_v6_types + 0 }, -}; - -static const struct wl_message zxdg_surface_v6_events[] = { - { "configure", "u", xdg_shell_unstable_v6_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface zxdg_surface_v6_interface = { - "zxdg_surface_v6", 1, - 5, zxdg_surface_v6_requests, - 1, zxdg_surface_v6_events, -}; - -static const struct wl_message zxdg_toplevel_v6_requests[] = { - { "destroy", "", xdg_shell_unstable_v6_types + 0 }, - { "set_parent", "?o", xdg_shell_unstable_v6_types + 11 }, - { "set_title", "s", xdg_shell_unstable_v6_types + 0 }, - { "set_app_id", "s", xdg_shell_unstable_v6_types + 0 }, - { "show_window_menu", "ouii", xdg_shell_unstable_v6_types + 12 }, - { "move", "ou", xdg_shell_unstable_v6_types + 16 }, - { "resize", "ouu", xdg_shell_unstable_v6_types + 18 }, - { "set_max_size", "ii", xdg_shell_unstable_v6_types + 0 }, - { "set_min_size", "ii", xdg_shell_unstable_v6_types + 0 }, - { "set_maximized", "", xdg_shell_unstable_v6_types + 0 }, - { "unset_maximized", "", xdg_shell_unstable_v6_types + 0 }, - { "set_fullscreen", "?o", xdg_shell_unstable_v6_types + 21 }, - { "unset_fullscreen", "", xdg_shell_unstable_v6_types + 0 }, - { "set_minimized", "", xdg_shell_unstable_v6_types + 0 }, -}; - -static const struct wl_message zxdg_toplevel_v6_events[] = { - { "configure", "iia", xdg_shell_unstable_v6_types + 0 }, - { "close", "", xdg_shell_unstable_v6_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface zxdg_toplevel_v6_interface = { - "zxdg_toplevel_v6", 1, - 14, zxdg_toplevel_v6_requests, - 2, zxdg_toplevel_v6_events, -}; - -static const struct wl_message zxdg_popup_v6_requests[] = { - { "destroy", "", xdg_shell_unstable_v6_types + 0 }, - { "grab", "ou", xdg_shell_unstable_v6_types + 22 }, -}; - -static const struct wl_message zxdg_popup_v6_events[] = { - { "configure", "iiii", xdg_shell_unstable_v6_types + 0 }, - { "popup_done", "", xdg_shell_unstable_v6_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface zxdg_popup_v6_interface = { - "zxdg_popup_v6", 1, - 2, zxdg_popup_v6_requests, - 2, zxdg_popup_v6_events, -}; - diff --git a/wayland/cc/xdg-shell.cc b/wayland/cc/xdg-shell.cc new file mode 100644 index 00000000..03826cdc --- /dev/null +++ b/wayland/cc/xdg-shell.cc @@ -0,0 +1,183 @@ +/* Generated by wayland-scanner 1.22.0 */ + +/* + * Copyright © 2008-2013 Kristian Høgsberg + * Copyright © 2013 Rafael Antognolli + * Copyright © 2013 Jasper St. Pierre + * Copyright © 2010-2013 Intel Corporation + * Copyright © 2015-2017 Samsung Electronics Co., Ltd + * Copyright © 2015-2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_output_interface; +extern const struct wl_interface wl_seat_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface xdg_popup_interface; +extern const struct wl_interface xdg_positioner_interface; +extern const struct wl_interface xdg_surface_interface; +extern const struct wl_interface xdg_toplevel_interface; + +static const struct wl_interface *xdg_shell_types[] = { + NULL, + NULL, + NULL, + NULL, + &xdg_positioner_interface, + &xdg_surface_interface, + &wl_surface_interface, + &xdg_toplevel_interface, + &xdg_popup_interface, + &xdg_surface_interface, + &xdg_positioner_interface, + &xdg_toplevel_interface, + &wl_seat_interface, + NULL, + NULL, + NULL, + &wl_seat_interface, + NULL, + &wl_seat_interface, + NULL, + NULL, + &wl_output_interface, + &wl_seat_interface, + NULL, + &xdg_positioner_interface, + NULL, +}; + +static const struct wl_message xdg_wm_base_requests[] = { + { "destroy", "", xdg_shell_types + 0 }, + { "create_positioner", "n", xdg_shell_types + 4 }, + { "get_xdg_surface", "no", xdg_shell_types + 5 }, + { "pong", "u", xdg_shell_types + 0 }, +}; + +static const struct wl_message xdg_wm_base_events[] = { + { "ping", "u", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_wm_base_interface = { + "xdg_wm_base", 6, + 4, xdg_wm_base_requests, + 1, xdg_wm_base_events, +}; + +static const struct wl_message xdg_positioner_requests[] = { + { "destroy", "", xdg_shell_types + 0 }, + { "set_size", "ii", xdg_shell_types + 0 }, + { "set_anchor_rect", "iiii", xdg_shell_types + 0 }, + { "set_anchor", "u", xdg_shell_types + 0 }, + { "set_gravity", "u", xdg_shell_types + 0 }, + { "set_constraint_adjustment", "u", xdg_shell_types + 0 }, + { "set_offset", "ii", xdg_shell_types + 0 }, + { "set_reactive", "3", xdg_shell_types + 0 }, + { "set_parent_size", "3ii", xdg_shell_types + 0 }, + { "set_parent_configure", "3u", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_positioner_interface = { + "xdg_positioner", 6, + 10, xdg_positioner_requests, + 0, NULL, +}; + +static const struct wl_message xdg_surface_requests[] = { + { "destroy", "", xdg_shell_types + 0 }, + { "get_toplevel", "n", xdg_shell_types + 7 }, + { "get_popup", "n?oo", xdg_shell_types + 8 }, + { "set_window_geometry", "iiii", xdg_shell_types + 0 }, + { "ack_configure", "u", xdg_shell_types + 0 }, +}; + +static const struct wl_message xdg_surface_events[] = { + { "configure", "u", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_surface_interface = { + "xdg_surface", 6, + 5, xdg_surface_requests, + 1, xdg_surface_events, +}; + +static const struct wl_message xdg_toplevel_requests[] = { + { "destroy", "", xdg_shell_types + 0 }, + { "set_parent", "?o", xdg_shell_types + 11 }, + { "set_title", "s", xdg_shell_types + 0 }, + { "set_app_id", "s", xdg_shell_types + 0 }, + { "show_window_menu", "ouii", xdg_shell_types + 12 }, + { "move", "ou", xdg_shell_types + 16 }, + { "resize", "ouu", xdg_shell_types + 18 }, + { "set_max_size", "ii", xdg_shell_types + 0 }, + { "set_min_size", "ii", xdg_shell_types + 0 }, + { "set_maximized", "", xdg_shell_types + 0 }, + { "unset_maximized", "", xdg_shell_types + 0 }, + { "set_fullscreen", "?o", xdg_shell_types + 21 }, + { "unset_fullscreen", "", xdg_shell_types + 0 }, + { "set_minimized", "", xdg_shell_types + 0 }, +}; + +static const struct wl_message xdg_toplevel_events[] = { + { "configure", "iia", xdg_shell_types + 0 }, + { "close", "", xdg_shell_types + 0 }, + { "configure_bounds", "4ii", xdg_shell_types + 0 }, + { "wm_capabilities", "5a", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_toplevel_interface = { + "xdg_toplevel", 6, + 14, xdg_toplevel_requests, + 4, xdg_toplevel_events, +}; + +static const struct wl_message xdg_popup_requests[] = { + { "destroy", "", xdg_shell_types + 0 }, + { "grab", "ou", xdg_shell_types + 22 }, + { "reposition", "3ou", xdg_shell_types + 24 }, +}; + +static const struct wl_message xdg_popup_events[] = { + { "configure", "iiii", xdg_shell_types + 0 }, + { "popup_done", "", xdg_shell_types + 0 }, + { "repositioned", "3u", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_popup_interface = { + "xdg_popup", 6, + 3, xdg_popup_requests, + 3, xdg_popup_events, +}; + diff --git a/wayland/cc/xdg-shell.h b/wayland/cc/xdg-shell.h deleted file mode 100644 index 3f4d6846..00000000 --- a/wayland/cc/xdg-shell.h +++ /dev/null @@ -1,1884 +0,0 @@ -/* Generated by wayland-scanner 1.22.0 */ - -#ifndef XDG_SHELL_UNSTABLE_V6_CLIENT_PROTOCOL_H -#define XDG_SHELL_UNSTABLE_V6_CLIENT_PROTOCOL_H - -#include -#include -#include "wayland-client.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @page page_xdg_shell_unstable_v6 The xdg_shell_unstable_v6 protocol - * @section page_ifaces_xdg_shell_unstable_v6 Interfaces - * - @subpage page_iface_zxdg_shell_v6 - create desktop-style surfaces - * - @subpage page_iface_zxdg_positioner_v6 - child surface positioner - * - @subpage page_iface_zxdg_surface_v6 - desktop user interface surface base interface - * - @subpage page_iface_zxdg_toplevel_v6 - toplevel surface - * - @subpage page_iface_zxdg_popup_v6 - short-lived, popup surfaces for menus - * @section page_copyright_xdg_shell_unstable_v6 Copyright - *
- *
- * Copyright © 2008-2013 Kristian Høgsberg
- * Copyright © 2013      Rafael Antognolli
- * Copyright © 2013      Jasper St. Pierre
- * Copyright © 2010-2013 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- * 
- */ -struct wl_output; -struct wl_seat; -struct wl_surface; -struct zxdg_popup_v6; -struct zxdg_positioner_v6; -struct zxdg_shell_v6; -struct zxdg_surface_v6; -struct zxdg_toplevel_v6; - -#ifndef ZXDG_SHELL_V6_INTERFACE -#define ZXDG_SHELL_V6_INTERFACE -/** - * @page page_iface_zxdg_shell_v6 zxdg_shell_v6 - * @section page_iface_zxdg_shell_v6_desc Description - * - * xdg_shell allows clients to turn a wl_surface into a "real window" - * which can be dragged, resized, stacked, and moved around by the - * user. Everything about this interface is suited towards traditional - * desktop environments. - * @section page_iface_zxdg_shell_v6_api API - * See @ref iface_zxdg_shell_v6. - */ -/** - * @defgroup iface_zxdg_shell_v6 The zxdg_shell_v6 interface - * - * xdg_shell allows clients to turn a wl_surface into a "real window" - * which can be dragged, resized, stacked, and moved around by the - * user. Everything about this interface is suited towards traditional - * desktop environments. - */ -extern const struct wl_interface zxdg_shell_v6_interface; -#endif -#ifndef ZXDG_POSITIONER_V6_INTERFACE -#define ZXDG_POSITIONER_V6_INTERFACE -/** - * @page page_iface_zxdg_positioner_v6 zxdg_positioner_v6 - * @section page_iface_zxdg_positioner_v6_desc Description - * - * The xdg_positioner provides a collection of rules for the placement of a - * child surface relative to a parent surface. Rules can be defined to ensure - * the child surface remains within the visible area's borders, and to - * specify how the child surface changes its position, such as sliding along - * an axis, or flipping around a rectangle. These positioner-created rules are - * constrained by the requirement that a child surface must intersect with or - * be at least partially adjacent to its parent surface. - * - * See the various requests for details about possible rules. - * - * At the time of the request, the compositor makes a copy of the rules - * specified by the xdg_positioner. Thus, after the request is complete the - * xdg_positioner object can be destroyed or reused; further changes to the - * object will have no effect on previous usages. - * - * For an xdg_positioner object to be considered complete, it must have a - * non-zero size set by set_size, and a non-zero anchor rectangle set by - * set_anchor_rect. Passing an incomplete xdg_positioner object when - * positioning a surface raises an error. - * @section page_iface_zxdg_positioner_v6_api API - * See @ref iface_zxdg_positioner_v6. - */ -/** - * @defgroup iface_zxdg_positioner_v6 The zxdg_positioner_v6 interface - * - * The xdg_positioner provides a collection of rules for the placement of a - * child surface relative to a parent surface. Rules can be defined to ensure - * the child surface remains within the visible area's borders, and to - * specify how the child surface changes its position, such as sliding along - * an axis, or flipping around a rectangle. These positioner-created rules are - * constrained by the requirement that a child surface must intersect with or - * be at least partially adjacent to its parent surface. - * - * See the various requests for details about possible rules. - * - * At the time of the request, the compositor makes a copy of the rules - * specified by the xdg_positioner. Thus, after the request is complete the - * xdg_positioner object can be destroyed or reused; further changes to the - * object will have no effect on previous usages. - * - * For an xdg_positioner object to be considered complete, it must have a - * non-zero size set by set_size, and a non-zero anchor rectangle set by - * set_anchor_rect. Passing an incomplete xdg_positioner object when - * positioning a surface raises an error. - */ -extern const struct wl_interface zxdg_positioner_v6_interface; -#endif -#ifndef ZXDG_SURFACE_V6_INTERFACE -#define ZXDG_SURFACE_V6_INTERFACE -/** - * @page page_iface_zxdg_surface_v6 zxdg_surface_v6 - * @section page_iface_zxdg_surface_v6_desc Description - * - * An interface that may be implemented by a wl_surface, for - * implementations that provide a desktop-style user interface. - * - * It provides a base set of functionality required to construct user - * interface elements requiring management by the compositor, such as - * toplevel windows, menus, etc. The types of functionality are split into - * xdg_surface roles. - * - * Creating an xdg_surface does not set the role for a wl_surface. In order - * to map an xdg_surface, the client must create a role-specific object - * using, e.g., get_toplevel, get_popup. The wl_surface for any given - * xdg_surface can have at most one role, and may not be assigned any role - * not based on xdg_surface. - * - * A role must be assigned before any other requests are made to the - * xdg_surface object. - * - * The client must call wl_surface.commit on the corresponding wl_surface - * for the xdg_surface state to take effect. - * - * Creating an xdg_surface from a wl_surface which has a buffer attached or - * committed is a client error, and any attempts by a client to attach or - * manipulate a buffer prior to the first xdg_surface.configure call must - * also be treated as errors. - * - * For a surface to be mapped by the compositor, the following conditions - * must be met: (1) the client has assigned an xdg_surface based role to the - * surface, (2) the client has set and committed the xdg_surface state and - * the role dependent state to the surface and (3) the client has committed a - * buffer to the surface. - * @section page_iface_zxdg_surface_v6_api API - * See @ref iface_zxdg_surface_v6. - */ -/** - * @defgroup iface_zxdg_surface_v6 The zxdg_surface_v6 interface - * - * An interface that may be implemented by a wl_surface, for - * implementations that provide a desktop-style user interface. - * - * It provides a base set of functionality required to construct user - * interface elements requiring management by the compositor, such as - * toplevel windows, menus, etc. The types of functionality are split into - * xdg_surface roles. - * - * Creating an xdg_surface does not set the role for a wl_surface. In order - * to map an xdg_surface, the client must create a role-specific object - * using, e.g., get_toplevel, get_popup. The wl_surface for any given - * xdg_surface can have at most one role, and may not be assigned any role - * not based on xdg_surface. - * - * A role must be assigned before any other requests are made to the - * xdg_surface object. - * - * The client must call wl_surface.commit on the corresponding wl_surface - * for the xdg_surface state to take effect. - * - * Creating an xdg_surface from a wl_surface which has a buffer attached or - * committed is a client error, and any attempts by a client to attach or - * manipulate a buffer prior to the first xdg_surface.configure call must - * also be treated as errors. - * - * For a surface to be mapped by the compositor, the following conditions - * must be met: (1) the client has assigned an xdg_surface based role to the - * surface, (2) the client has set and committed the xdg_surface state and - * the role dependent state to the surface and (3) the client has committed a - * buffer to the surface. - */ -extern const struct wl_interface zxdg_surface_v6_interface; -#endif -#ifndef ZXDG_TOPLEVEL_V6_INTERFACE -#define ZXDG_TOPLEVEL_V6_INTERFACE -/** - * @page page_iface_zxdg_toplevel_v6 zxdg_toplevel_v6 - * @section page_iface_zxdg_toplevel_v6_desc Description - * - * This interface defines an xdg_surface role which allows a surface to, - * among other things, set window-like properties such as maximize, - * fullscreen, and minimize, set application-specific metadata like title and - * id, and well as trigger user interactive operations such as interactive - * resize and move. - * @section page_iface_zxdg_toplevel_v6_api API - * See @ref iface_zxdg_toplevel_v6. - */ -/** - * @defgroup iface_zxdg_toplevel_v6 The zxdg_toplevel_v6 interface - * - * This interface defines an xdg_surface role which allows a surface to, - * among other things, set window-like properties such as maximize, - * fullscreen, and minimize, set application-specific metadata like title and - * id, and well as trigger user interactive operations such as interactive - * resize and move. - */ -extern const struct wl_interface zxdg_toplevel_v6_interface; -#endif -#ifndef ZXDG_POPUP_V6_INTERFACE -#define ZXDG_POPUP_V6_INTERFACE -/** - * @page page_iface_zxdg_popup_v6 zxdg_popup_v6 - * @section page_iface_zxdg_popup_v6_desc Description - * - * A popup surface is a short-lived, temporary surface. It can be used to - * implement for example menus, popovers, tooltips and other similar user - * interface concepts. - * - * A popup can be made to take an explicit grab. See xdg_popup.grab for - * details. - * - * When the popup is dismissed, a popup_done event will be sent out, and at - * the same time the surface will be unmapped. See the xdg_popup.popup_done - * event for details. - * - * Explicitly destroying the xdg_popup object will also dismiss the popup and - * unmap the surface. Clients that want to dismiss the popup when another - * surface of their own is clicked should dismiss the popup using the destroy - * request. - * - * The parent surface must have either the xdg_toplevel or xdg_popup surface - * role. - * - * A newly created xdg_popup will be stacked on top of all previously created - * xdg_popup surfaces associated with the same xdg_toplevel. - * - * The parent of an xdg_popup must be mapped (see the xdg_surface - * description) before the xdg_popup itself. - * - * The x and y arguments passed when creating the popup object specify - * where the top left of the popup should be placed, relative to the - * local surface coordinates of the parent surface. See - * xdg_surface.get_popup. An xdg_popup must intersect with or be at least - * partially adjacent to its parent surface. - * - * The client must call wl_surface.commit on the corresponding wl_surface - * for the xdg_popup state to take effect. - * @section page_iface_zxdg_popup_v6_api API - * See @ref iface_zxdg_popup_v6. - */ -/** - * @defgroup iface_zxdg_popup_v6 The zxdg_popup_v6 interface - * - * A popup surface is a short-lived, temporary surface. It can be used to - * implement for example menus, popovers, tooltips and other similar user - * interface concepts. - * - * A popup can be made to take an explicit grab. See xdg_popup.grab for - * details. - * - * When the popup is dismissed, a popup_done event will be sent out, and at - * the same time the surface will be unmapped. See the xdg_popup.popup_done - * event for details. - * - * Explicitly destroying the xdg_popup object will also dismiss the popup and - * unmap the surface. Clients that want to dismiss the popup when another - * surface of their own is clicked should dismiss the popup using the destroy - * request. - * - * The parent surface must have either the xdg_toplevel or xdg_popup surface - * role. - * - * A newly created xdg_popup will be stacked on top of all previously created - * xdg_popup surfaces associated with the same xdg_toplevel. - * - * The parent of an xdg_popup must be mapped (see the xdg_surface - * description) before the xdg_popup itself. - * - * The x and y arguments passed when creating the popup object specify - * where the top left of the popup should be placed, relative to the - * local surface coordinates of the parent surface. See - * xdg_surface.get_popup. An xdg_popup must intersect with or be at least - * partially adjacent to its parent surface. - * - * The client must call wl_surface.commit on the corresponding wl_surface - * for the xdg_popup state to take effect. - */ -extern const struct wl_interface zxdg_popup_v6_interface; -#endif - -#ifndef ZXDG_SHELL_V6_ERROR_ENUM -#define ZXDG_SHELL_V6_ERROR_ENUM -enum zxdg_shell_v6_error { - /** - * given wl_surface has another role - */ - ZXDG_SHELL_V6_ERROR_ROLE = 0, - /** - * xdg_shell was destroyed before children - */ - ZXDG_SHELL_V6_ERROR_DEFUNCT_SURFACES = 1, - /** - * the client tried to map or destroy a non-topmost popup - */ - ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP = 2, - /** - * the client specified an invalid popup parent surface - */ - ZXDG_SHELL_V6_ERROR_INVALID_POPUP_PARENT = 3, - /** - * the client provided an invalid surface state - */ - ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE = 4, - /** - * the client provided an invalid positioner - */ - ZXDG_SHELL_V6_ERROR_INVALID_POSITIONER = 5, -}; -#endif /* ZXDG_SHELL_V6_ERROR_ENUM */ - -/** - * @ingroup iface_zxdg_shell_v6 - * @struct zxdg_shell_v6_listener - */ -struct zxdg_shell_v6_listener { - /** - * check if the client is alive - * - * The ping event asks the client if it's still alive. Pass the - * serial specified in the event back to the compositor by sending - * a "pong" request back with the specified serial. See - * xdg_shell.ping. - * - * Compositors can use this to determine if the client is still - * alive. It's unspecified what will happen if the client doesn't - * respond to the ping request, or in what timeframe. Clients - * should try to respond in a reasonable amount of time. - * - * A compositor is free to ping in any way it wants, but a client - * must always respond to any xdg_shell object it created. - * @param serial pass this to the pong request - */ - void (*ping)(void *data, - struct zxdg_shell_v6 *zxdg_shell_v6, - uint32_t serial); -}; - -/** - * @ingroup iface_zxdg_shell_v6 - */ -static inline int -zxdg_shell_v6_add_listener(struct zxdg_shell_v6 *zxdg_shell_v6, - const struct zxdg_shell_v6_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) zxdg_shell_v6, - (void (**)(void)) listener, data); -} - -#define ZXDG_SHELL_V6_DESTROY 0 -#define ZXDG_SHELL_V6_CREATE_POSITIONER 1 -#define ZXDG_SHELL_V6_GET_XDG_SURFACE 2 -#define ZXDG_SHELL_V6_PONG 3 - -/** - * @ingroup iface_zxdg_shell_v6 - */ -#define ZXDG_SHELL_V6_PING_SINCE_VERSION 1 - -/** - * @ingroup iface_zxdg_shell_v6 - */ -#define ZXDG_SHELL_V6_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_shell_v6 - */ -#define ZXDG_SHELL_V6_CREATE_POSITIONER_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_shell_v6 - */ -#define ZXDG_SHELL_V6_GET_XDG_SURFACE_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_shell_v6 - */ -#define ZXDG_SHELL_V6_PONG_SINCE_VERSION 1 - -/** @ingroup iface_zxdg_shell_v6 */ -static inline void -zxdg_shell_v6_set_user_data(struct zxdg_shell_v6 *zxdg_shell_v6, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) zxdg_shell_v6, user_data); -} - -/** @ingroup iface_zxdg_shell_v6 */ -static inline void * -zxdg_shell_v6_get_user_data(struct zxdg_shell_v6 *zxdg_shell_v6) -{ - return wl_proxy_get_user_data((struct wl_proxy *) zxdg_shell_v6); -} - -static inline uint32_t -zxdg_shell_v6_get_version(struct zxdg_shell_v6 *zxdg_shell_v6) -{ - return wl_proxy_get_version((struct wl_proxy *) zxdg_shell_v6); -} - -/** - * @ingroup iface_zxdg_shell_v6 - * - * Destroy this xdg_shell object. - * - * Destroying a bound xdg_shell object while there are surfaces - * still alive created by this xdg_shell object instance is illegal - * and will result in a protocol error. - */ -static inline void -zxdg_shell_v6_destroy(struct zxdg_shell_v6 *zxdg_shell_v6) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_shell_v6, - ZXDG_SHELL_V6_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_shell_v6), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_zxdg_shell_v6 - * - * Create a positioner object. A positioner object is used to position - * surfaces relative to some parent surface. See the interface description - * and xdg_surface.get_popup for details. - */ -static inline struct zxdg_positioner_v6 * -zxdg_shell_v6_create_positioner(struct zxdg_shell_v6 *zxdg_shell_v6) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) zxdg_shell_v6, - ZXDG_SHELL_V6_CREATE_POSITIONER, &zxdg_positioner_v6_interface, wl_proxy_get_version((struct wl_proxy *) zxdg_shell_v6), 0, NULL); - - return (struct zxdg_positioner_v6 *) id; -} - -/** - * @ingroup iface_zxdg_shell_v6 - * - * This creates an xdg_surface for the given surface. While xdg_surface - * itself is not a role, the corresponding surface may only be assigned - * a role extending xdg_surface, such as xdg_toplevel or xdg_popup. - * - * This creates an xdg_surface for the given surface. An xdg_surface is - * used as basis to define a role to a given surface, such as xdg_toplevel - * or xdg_popup. It also manages functionality shared between xdg_surface - * based surface roles. - * - * See the documentation of xdg_surface for more details about what an - * xdg_surface is and how it is used. - */ -static inline struct zxdg_surface_v6 * -zxdg_shell_v6_get_xdg_surface(struct zxdg_shell_v6 *zxdg_shell_v6, struct wl_surface *surface) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) zxdg_shell_v6, - ZXDG_SHELL_V6_GET_XDG_SURFACE, &zxdg_surface_v6_interface, wl_proxy_get_version((struct wl_proxy *) zxdg_shell_v6), 0, NULL, surface); - - return (struct zxdg_surface_v6 *) id; -} - -/** - * @ingroup iface_zxdg_shell_v6 - * - * A client must respond to a ping event with a pong request or - * the client may be deemed unresponsive. See xdg_shell.ping. - */ -static inline void -zxdg_shell_v6_pong(struct zxdg_shell_v6 *zxdg_shell_v6, uint32_t serial) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_shell_v6, - ZXDG_SHELL_V6_PONG, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_shell_v6), 0, serial); -} - -#ifndef ZXDG_POSITIONER_V6_ERROR_ENUM -#define ZXDG_POSITIONER_V6_ERROR_ENUM -enum zxdg_positioner_v6_error { - /** - * invalid input provided - */ - ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT = 0, -}; -#endif /* ZXDG_POSITIONER_V6_ERROR_ENUM */ - -#ifndef ZXDG_POSITIONER_V6_ANCHOR_ENUM -#define ZXDG_POSITIONER_V6_ANCHOR_ENUM -enum zxdg_positioner_v6_anchor { - /** - * the center of the anchor rectangle - */ - ZXDG_POSITIONER_V6_ANCHOR_NONE = 0, - /** - * the top edge of the anchor rectangle - */ - ZXDG_POSITIONER_V6_ANCHOR_TOP = 1, - /** - * the bottom edge of the anchor rectangle - */ - ZXDG_POSITIONER_V6_ANCHOR_BOTTOM = 2, - /** - * the left edge of the anchor rectangle - */ - ZXDG_POSITIONER_V6_ANCHOR_LEFT = 4, - /** - * the right edge of the anchor rectangle - */ - ZXDG_POSITIONER_V6_ANCHOR_RIGHT = 8, -}; -#endif /* ZXDG_POSITIONER_V6_ANCHOR_ENUM */ - -#ifndef ZXDG_POSITIONER_V6_GRAVITY_ENUM -#define ZXDG_POSITIONER_V6_GRAVITY_ENUM -enum zxdg_positioner_v6_gravity { - /** - * center over the anchor edge - */ - ZXDG_POSITIONER_V6_GRAVITY_NONE = 0, - /** - * position above the anchor edge - */ - ZXDG_POSITIONER_V6_GRAVITY_TOP = 1, - /** - * position below the anchor edge - */ - ZXDG_POSITIONER_V6_GRAVITY_BOTTOM = 2, - /** - * position to the left of the anchor edge - */ - ZXDG_POSITIONER_V6_GRAVITY_LEFT = 4, - /** - * position to the right of the anchor edge - */ - ZXDG_POSITIONER_V6_GRAVITY_RIGHT = 8, -}; -#endif /* ZXDG_POSITIONER_V6_GRAVITY_ENUM */ - -#ifndef ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_ENUM -#define ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_ENUM -/** - * @ingroup iface_zxdg_positioner_v6 - * constraint adjustments - * - * The constraint adjustment value define ways the compositor will adjust - * the position of the surface, if the unadjusted position would result - * in the surface being partly constrained. - * - * Whether a surface is considered 'constrained' is left to the compositor - * to determine. For example, the surface may be partly outside the - * compositor's defined 'work area', thus necessitating the child surface's - * position be adjusted until it is entirely inside the work area. - * - * The adjustments can be combined, according to a defined precedence: 1) - * Flip, 2) Slide, 3) Resize. - */ -enum zxdg_positioner_v6_constraint_adjustment { - /** - * don't move the child surface when constrained - * - * Don't alter the surface position even if it is constrained on - * some axis, for example partially outside the edge of a monitor. - */ - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_NONE = 0, - /** - * move along the x axis until unconstrained - * - * Slide the surface along the x axis until it is no longer - * constrained. - * - * First try to slide towards the direction of the gravity on the x - * axis until either the edge in the opposite direction of the - * gravity is unconstrained or the edge in the direction of the - * gravity is constrained. - * - * Then try to slide towards the opposite direction of the gravity - * on the x axis until either the edge in the direction of the - * gravity is unconstrained or the edge in the opposite direction - * of the gravity is constrained. - */ - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1, - /** - * move along the y axis until unconstrained - * - * Slide the surface along the y axis until it is no longer - * constrained. - * - * First try to slide towards the direction of the gravity on the y - * axis until either the edge in the opposite direction of the - * gravity is unconstrained or the edge in the direction of the - * gravity is constrained. - * - * Then try to slide towards the opposite direction of the gravity - * on the y axis until either the edge in the direction of the - * gravity is unconstrained or the edge in the opposite direction - * of the gravity is constrained. - */ - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2, - /** - * invert the anchor and gravity on the x axis - * - * Invert the anchor and gravity on the x axis if the surface is - * constrained on the x axis. For example, if the left edge of the - * surface is constrained, the gravity is 'left' and the anchor is - * 'left', change the gravity to 'right' and the anchor to 'right'. - * - * If the adjusted position also ends up being constrained, the - * resulting position of the flip_x adjustment will be the one - * before the adjustment. - */ - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X = 4, - /** - * invert the anchor and gravity on the y axis - * - * Invert the anchor and gravity on the y axis if the surface is - * constrained on the y axis. For example, if the bottom edge of - * the surface is constrained, the gravity is 'bottom' and the - * anchor is 'bottom', change the gravity to 'top' and the anchor - * to 'top'. - * - * If the adjusted position also ends up being constrained, the - * resulting position of the flip_y adjustment will be the one - * before the adjustment. - */ - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8, - /** - * horizontally resize the surface - * - * Resize the surface horizontally so that it is completely - * unconstrained. - */ - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16, - /** - * vertically resize the surface - * - * Resize the surface vertically so that it is completely - * unconstrained. - */ - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32, -}; -#endif /* ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_ENUM */ - -#define ZXDG_POSITIONER_V6_DESTROY 0 -#define ZXDG_POSITIONER_V6_SET_SIZE 1 -#define ZXDG_POSITIONER_V6_SET_ANCHOR_RECT 2 -#define ZXDG_POSITIONER_V6_SET_ANCHOR 3 -#define ZXDG_POSITIONER_V6_SET_GRAVITY 4 -#define ZXDG_POSITIONER_V6_SET_CONSTRAINT_ADJUSTMENT 5 -#define ZXDG_POSITIONER_V6_SET_OFFSET 6 - - -/** - * @ingroup iface_zxdg_positioner_v6 - */ -#define ZXDG_POSITIONER_V6_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_positioner_v6 - */ -#define ZXDG_POSITIONER_V6_SET_SIZE_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_positioner_v6 - */ -#define ZXDG_POSITIONER_V6_SET_ANCHOR_RECT_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_positioner_v6 - */ -#define ZXDG_POSITIONER_V6_SET_ANCHOR_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_positioner_v6 - */ -#define ZXDG_POSITIONER_V6_SET_GRAVITY_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_positioner_v6 - */ -#define ZXDG_POSITIONER_V6_SET_CONSTRAINT_ADJUSTMENT_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_positioner_v6 - */ -#define ZXDG_POSITIONER_V6_SET_OFFSET_SINCE_VERSION 1 - -/** @ingroup iface_zxdg_positioner_v6 */ -static inline void -zxdg_positioner_v6_set_user_data(struct zxdg_positioner_v6 *zxdg_positioner_v6, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) zxdg_positioner_v6, user_data); -} - -/** @ingroup iface_zxdg_positioner_v6 */ -static inline void * -zxdg_positioner_v6_get_user_data(struct zxdg_positioner_v6 *zxdg_positioner_v6) -{ - return wl_proxy_get_user_data((struct wl_proxy *) zxdg_positioner_v6); -} - -static inline uint32_t -zxdg_positioner_v6_get_version(struct zxdg_positioner_v6 *zxdg_positioner_v6) -{ - return wl_proxy_get_version((struct wl_proxy *) zxdg_positioner_v6); -} - -/** - * @ingroup iface_zxdg_positioner_v6 - * - * Notify the compositor that the xdg_positioner will no longer be used. - */ -static inline void -zxdg_positioner_v6_destroy(struct zxdg_positioner_v6 *zxdg_positioner_v6) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_positioner_v6, - ZXDG_POSITIONER_V6_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_positioner_v6), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_zxdg_positioner_v6 - * - * Set the size of the surface that is to be positioned with the positioner - * object. The size is in surface-local coordinates and corresponds to the - * window geometry. See xdg_surface.set_window_geometry. - * - * If a zero or negative size is set the invalid_input error is raised. - */ -static inline void -zxdg_positioner_v6_set_size(struct zxdg_positioner_v6 *zxdg_positioner_v6, int32_t width, int32_t height) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_positioner_v6, - ZXDG_POSITIONER_V6_SET_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_positioner_v6), 0, width, height); -} - -/** - * @ingroup iface_zxdg_positioner_v6 - * - * Specify the anchor rectangle within the parent surface that the child - * surface will be placed relative to. The rectangle is relative to the - * window geometry as defined by xdg_surface.set_window_geometry of the - * parent surface. The rectangle must be at least 1x1 large. - * - * When the xdg_positioner object is used to position a child surface, the - * anchor rectangle may not extend outside the window geometry of the - * positioned child's parent surface. - * - * If a zero or negative size is set the invalid_input error is raised. - */ -static inline void -zxdg_positioner_v6_set_anchor_rect(struct zxdg_positioner_v6 *zxdg_positioner_v6, int32_t x, int32_t y, int32_t width, int32_t height) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_positioner_v6, - ZXDG_POSITIONER_V6_SET_ANCHOR_RECT, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_positioner_v6), 0, x, y, width, height); -} - -/** - * @ingroup iface_zxdg_positioner_v6 - * - * Defines a set of edges for the anchor rectangle. These are used to - * derive an anchor point that the child surface will be positioned - * relative to. If two orthogonal edges are specified (e.g. 'top' and - * 'left'), then the anchor point will be the intersection of the edges - * (e.g. the top left position of the rectangle); otherwise, the derived - * anchor point will be centered on the specified edge, or in the center of - * the anchor rectangle if no edge is specified. - * - * If two parallel anchor edges are specified (e.g. 'left' and 'right'), - * the invalid_input error is raised. - */ -static inline void -zxdg_positioner_v6_set_anchor(struct zxdg_positioner_v6 *zxdg_positioner_v6, uint32_t anchor) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_positioner_v6, - ZXDG_POSITIONER_V6_SET_ANCHOR, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_positioner_v6), 0, anchor); -} - -/** - * @ingroup iface_zxdg_positioner_v6 - * - * Defines in what direction a surface should be positioned, relative to - * the anchor point of the parent surface. If two orthogonal gravities are - * specified (e.g. 'bottom' and 'right'), then the child surface will be - * placed in the specified direction; otherwise, the child surface will be - * centered over the anchor point on any axis that had no gravity - * specified. - * - * If two parallel gravities are specified (e.g. 'left' and 'right'), the - * invalid_input error is raised. - */ -static inline void -zxdg_positioner_v6_set_gravity(struct zxdg_positioner_v6 *zxdg_positioner_v6, uint32_t gravity) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_positioner_v6, - ZXDG_POSITIONER_V6_SET_GRAVITY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_positioner_v6), 0, gravity); -} - -/** - * @ingroup iface_zxdg_positioner_v6 - * - * Specify how the window should be positioned if the originally intended - * position caused the surface to be constrained, meaning at least - * partially outside positioning boundaries set by the compositor. The - * adjustment is set by constructing a bitmask describing the adjustment to - * be made when the surface is constrained on that axis. - * - * If no bit for one axis is set, the compositor will assume that the child - * surface should not change its position on that axis when constrained. - * - * If more than one bit for one axis is set, the order of how adjustments - * are applied is specified in the corresponding adjustment descriptions. - * - * The default adjustment is none. - */ -static inline void -zxdg_positioner_v6_set_constraint_adjustment(struct zxdg_positioner_v6 *zxdg_positioner_v6, uint32_t constraint_adjustment) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_positioner_v6, - ZXDG_POSITIONER_V6_SET_CONSTRAINT_ADJUSTMENT, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_positioner_v6), 0, constraint_adjustment); -} - -/** - * @ingroup iface_zxdg_positioner_v6 - * - * Specify the surface position offset relative to the position of the - * anchor on the anchor rectangle and the anchor on the surface. For - * example if the anchor of the anchor rectangle is at (x, y), the surface - * has the gravity bottom|right, and the offset is (ox, oy), the calculated - * surface position will be (x + ox, y + oy). The offset position of the - * surface is the one used for constraint testing. See - * set_constraint_adjustment. - * - * An example use case is placing a popup menu on top of a user interface - * element, while aligning the user interface element of the parent surface - * with some user interface element placed somewhere in the popup surface. - */ -static inline void -zxdg_positioner_v6_set_offset(struct zxdg_positioner_v6 *zxdg_positioner_v6, int32_t x, int32_t y) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_positioner_v6, - ZXDG_POSITIONER_V6_SET_OFFSET, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_positioner_v6), 0, x, y); -} - -#ifndef ZXDG_SURFACE_V6_ERROR_ENUM -#define ZXDG_SURFACE_V6_ERROR_ENUM -enum zxdg_surface_v6_error { - ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED = 1, - ZXDG_SURFACE_V6_ERROR_ALREADY_CONSTRUCTED = 2, - ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER = 3, -}; -#endif /* ZXDG_SURFACE_V6_ERROR_ENUM */ - -/** - * @ingroup iface_zxdg_surface_v6 - * @struct zxdg_surface_v6_listener - */ -struct zxdg_surface_v6_listener { - /** - * suggest a surface change - * - * The configure event marks the end of a configure sequence. A - * configure sequence is a set of one or more events configuring - * the state of the xdg_surface, including the final - * xdg_surface.configure event. - * - * Where applicable, xdg_surface surface roles will during a - * configure sequence extend this event as a latched state sent as - * events before the xdg_surface.configure event. Such events - * should be considered to make up a set of atomically applied - * configuration states, where the xdg_surface.configure commits - * the accumulated state. - * - * Clients should arrange their surface for the new states, and - * then send an ack_configure request with the serial sent in this - * configure event at some point before committing the new surface. - * - * If the client receives multiple configure events before it can - * respond to one, it is free to discard all but the last event it - * received. - * @param serial serial of the configure event - */ - void (*configure)(void *data, - struct zxdg_surface_v6 *zxdg_surface_v6, - uint32_t serial); -}; - -/** - * @ingroup iface_zxdg_surface_v6 - */ -static inline int -zxdg_surface_v6_add_listener(struct zxdg_surface_v6 *zxdg_surface_v6, - const struct zxdg_surface_v6_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) zxdg_surface_v6, - (void (**)(void)) listener, data); -} - -#define ZXDG_SURFACE_V6_DESTROY 0 -#define ZXDG_SURFACE_V6_GET_TOPLEVEL 1 -#define ZXDG_SURFACE_V6_GET_POPUP 2 -#define ZXDG_SURFACE_V6_SET_WINDOW_GEOMETRY 3 -#define ZXDG_SURFACE_V6_ACK_CONFIGURE 4 - -/** - * @ingroup iface_zxdg_surface_v6 - */ -#define ZXDG_SURFACE_V6_CONFIGURE_SINCE_VERSION 1 - -/** - * @ingroup iface_zxdg_surface_v6 - */ -#define ZXDG_SURFACE_V6_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_surface_v6 - */ -#define ZXDG_SURFACE_V6_GET_TOPLEVEL_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_surface_v6 - */ -#define ZXDG_SURFACE_V6_GET_POPUP_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_surface_v6 - */ -#define ZXDG_SURFACE_V6_SET_WINDOW_GEOMETRY_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_surface_v6 - */ -#define ZXDG_SURFACE_V6_ACK_CONFIGURE_SINCE_VERSION 1 - -/** @ingroup iface_zxdg_surface_v6 */ -static inline void -zxdg_surface_v6_set_user_data(struct zxdg_surface_v6 *zxdg_surface_v6, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) zxdg_surface_v6, user_data); -} - -/** @ingroup iface_zxdg_surface_v6 */ -static inline void * -zxdg_surface_v6_get_user_data(struct zxdg_surface_v6 *zxdg_surface_v6) -{ - return wl_proxy_get_user_data((struct wl_proxy *) zxdg_surface_v6); -} - -static inline uint32_t -zxdg_surface_v6_get_version(struct zxdg_surface_v6 *zxdg_surface_v6) -{ - return wl_proxy_get_version((struct wl_proxy *) zxdg_surface_v6); -} - -/** - * @ingroup iface_zxdg_surface_v6 - * - * Destroy the xdg_surface object. An xdg_surface must only be destroyed - * after its role object has been destroyed. If the role object still - * exists when this request is issued, the zxdg_shell_v6.defunct_surfaces - * is raised. - */ -static inline void -zxdg_surface_v6_destroy(struct zxdg_surface_v6 *zxdg_surface_v6) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_surface_v6, - ZXDG_SURFACE_V6_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_surface_v6), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_zxdg_surface_v6 - * - * This creates an xdg_toplevel object for the given xdg_surface and gives - * the associated wl_surface the xdg_toplevel role. If the surface already - * had a role, the zxdg_shell_v6.role error is raised. - * - * See the documentation of xdg_toplevel for more details about what an - * xdg_toplevel is and how it is used. - */ -static inline struct zxdg_toplevel_v6 * -zxdg_surface_v6_get_toplevel(struct zxdg_surface_v6 *zxdg_surface_v6) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) zxdg_surface_v6, - ZXDG_SURFACE_V6_GET_TOPLEVEL, &zxdg_toplevel_v6_interface, wl_proxy_get_version((struct wl_proxy *) zxdg_surface_v6), 0, NULL); - - return (struct zxdg_toplevel_v6 *) id; -} - -/** - * @ingroup iface_zxdg_surface_v6 - * - * This creates an xdg_popup object for the given xdg_surface and gives the - * associated wl_surface the xdg_popup role. If the surface already - * had a role, the zxdg_shell_v6.role error is raised. - * - * See the documentation of xdg_popup for more details about what an - * xdg_popup is and how it is used. - */ -static inline struct zxdg_popup_v6 * -zxdg_surface_v6_get_popup(struct zxdg_surface_v6 *zxdg_surface_v6, struct zxdg_surface_v6 *parent, struct zxdg_positioner_v6 *positioner) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) zxdg_surface_v6, - ZXDG_SURFACE_V6_GET_POPUP, &zxdg_popup_v6_interface, wl_proxy_get_version((struct wl_proxy *) zxdg_surface_v6), 0, NULL, parent, positioner); - - return (struct zxdg_popup_v6 *) id; -} - -/** - * @ingroup iface_zxdg_surface_v6 - * - * The window geometry of a surface is its "visible bounds" from the - * user's perspective. Client-side decorations often have invisible - * portions like drop-shadows which should be ignored for the - * purposes of aligning, placing and constraining windows. - * - * The window geometry is double buffered, and will be applied at the - * time wl_surface.commit of the corresponding wl_surface is called. - * - * Once the window geometry of the surface is set, it is not possible to - * unset it, and it will remain the same until set_window_geometry is - * called again, even if a new subsurface or buffer is attached. - * - * If never set, the value is the full bounds of the surface, - * including any subsurfaces. This updates dynamically on every - * commit. This unset is meant for extremely simple clients. - * - * The arguments are given in the surface-local coordinate space of - * the wl_surface associated with this xdg_surface. - * - * The width and height must be greater than zero. Setting an invalid size - * will raise an error. When applied, the effective window geometry will be - * the set window geometry clamped to the bounding rectangle of the - * combined geometry of the surface of the xdg_surface and the associated - * subsurfaces. - */ -static inline void -zxdg_surface_v6_set_window_geometry(struct zxdg_surface_v6 *zxdg_surface_v6, int32_t x, int32_t y, int32_t width, int32_t height) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_surface_v6, - ZXDG_SURFACE_V6_SET_WINDOW_GEOMETRY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_surface_v6), 0, x, y, width, height); -} - -/** - * @ingroup iface_zxdg_surface_v6 - * - * When a configure event is received, if a client commits the - * surface in response to the configure event, then the client - * must make an ack_configure request sometime before the commit - * request, passing along the serial of the configure event. - * - * For instance, for toplevel surfaces the compositor might use this - * information to move a surface to the top left only when the client has - * drawn itself for the maximized or fullscreen state. - * - * If the client receives multiple configure events before it - * can respond to one, it only has to ack the last configure event. - * - * A client is not required to commit immediately after sending - * an ack_configure request - it may even ack_configure several times - * before its next surface commit. - * - * A client may send multiple ack_configure requests before committing, but - * only the last request sent before a commit indicates which configure - * event the client really is responding to. - * - * If an invalid serial is used, the zxdg_shell_v6.invalid_surface_state - * error is raised. - */ -static inline void -zxdg_surface_v6_ack_configure(struct zxdg_surface_v6 *zxdg_surface_v6, uint32_t serial) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_surface_v6, - ZXDG_SURFACE_V6_ACK_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_surface_v6), 0, serial); -} - -#ifndef ZXDG_TOPLEVEL_V6_RESIZE_EDGE_ENUM -#define ZXDG_TOPLEVEL_V6_RESIZE_EDGE_ENUM -/** - * @ingroup iface_zxdg_toplevel_v6 - * edge values for resizing - * - * These values are used to indicate which edge of a surface - * is being dragged in a resize operation. - */ -enum zxdg_toplevel_v6_resize_edge { - ZXDG_TOPLEVEL_V6_RESIZE_EDGE_NONE = 0, - ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP = 1, - ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM = 2, - ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT = 4, - ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_LEFT = 5, - ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_LEFT = 6, - ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT = 8, - ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_RIGHT = 9, - ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_RIGHT = 10, -}; -#endif /* ZXDG_TOPLEVEL_V6_RESIZE_EDGE_ENUM */ - -#ifndef ZXDG_TOPLEVEL_V6_STATE_ENUM -#define ZXDG_TOPLEVEL_V6_STATE_ENUM -/** - * @ingroup iface_zxdg_toplevel_v6 - * types of state on the surface - * - * The different state values used on the surface. This is designed for - * state values like maximized, fullscreen. It is paired with the - * configure event to ensure that both the client and the compositor - * setting the state can be synchronized. - * - * States set in this way are double-buffered. They will get applied on - * the next commit. - */ -enum zxdg_toplevel_v6_state { - /** - * the surface is maximized - * the surface is maximized - * - * The surface is maximized. The window geometry specified in the - * configure event must be obeyed by the client. If the window - * geometry is not obyed, the zxdg_shell_v6.invalid_surface_state - * error is raised. - */ - ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED = 1, - /** - * the surface is fullscreen - * the surface is fullscreen - * - * The surface is fullscreen. See set_fullscreen for more - * information. - */ - ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN = 2, - /** - * the surface is being resized - * the surface is being resized - * - * The surface is being resized. The window geometry specified in - * the configure event is a maximum; the client cannot resize - * beyond it. If the client attempts to resize above it, the - * zxdg_shell_v6.invalid_surface_state error is raised. Clients - * that have aspect ratio or cell sizing configuration can use a - * smaller size, however. - */ - ZXDG_TOPLEVEL_V6_STATE_RESIZING = 3, - /** - * the surface is now activated - * the surface is now activated - * - * Client window decorations should be painted as if the window - * is active. Do not assume this means that the window actually has - * keyboard or pointer focus. - */ - ZXDG_TOPLEVEL_V6_STATE_ACTIVATED = 4, -}; -#endif /* ZXDG_TOPLEVEL_V6_STATE_ENUM */ - -/** - * @ingroup iface_zxdg_toplevel_v6 - * @struct zxdg_toplevel_v6_listener - */ -struct zxdg_toplevel_v6_listener { - /** - * suggest a surface change - * - * This configure event asks the client to resize its toplevel - * surface or to change its state. The configured state should not - * be applied immediately. See xdg_surface.configure for details. - * - * The width and height arguments specify a hint to the window - * about how its surface should be resized in window geometry - * coordinates. See set_window_geometry. - * - * If the width or height arguments are zero, it means the client - * should decide its own window dimension. This may happen when the - * compositor needs to configure the state of the surface but - * doesn't have any information about any previous or expected - * dimension. - * - * The states listed in the event specify how the width/height - * arguments should be interpreted, and possibly how it should be - * drawn. - * - * Clients must send an ack_configure in response to this event. - * See xdg_surface.configure and xdg_surface.ack_configure for - * details. - */ - void (*configure)(void *data, - struct zxdg_toplevel_v6 *zxdg_toplevel_v6, - int32_t width, - int32_t height, - struct wl_array *states); - /** - * surface wants to be closed - * - * The close event is sent by the compositor when the user wants - * the surface to be closed. This should be equivalent to the user - * clicking the close button in client-side decorations, if your - * application has any. - * - * This is only a request that the user intends to close the - * window. The client may choose to ignore this request, or show a - * dialog to ask the user to save their data, etc. - */ - void (*close)(void *data, - struct zxdg_toplevel_v6 *zxdg_toplevel_v6); -}; - -/** - * @ingroup iface_zxdg_toplevel_v6 - */ -static inline int -zxdg_toplevel_v6_add_listener(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, - const struct zxdg_toplevel_v6_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) zxdg_toplevel_v6, - (void (**)(void)) listener, data); -} - -#define ZXDG_TOPLEVEL_V6_DESTROY 0 -#define ZXDG_TOPLEVEL_V6_SET_PARENT 1 -#define ZXDG_TOPLEVEL_V6_SET_TITLE 2 -#define ZXDG_TOPLEVEL_V6_SET_APP_ID 3 -#define ZXDG_TOPLEVEL_V6_SHOW_WINDOW_MENU 4 -#define ZXDG_TOPLEVEL_V6_MOVE 5 -#define ZXDG_TOPLEVEL_V6_RESIZE 6 -#define ZXDG_TOPLEVEL_V6_SET_MAX_SIZE 7 -#define ZXDG_TOPLEVEL_V6_SET_MIN_SIZE 8 -#define ZXDG_TOPLEVEL_V6_SET_MAXIMIZED 9 -#define ZXDG_TOPLEVEL_V6_UNSET_MAXIMIZED 10 -#define ZXDG_TOPLEVEL_V6_SET_FULLSCREEN 11 -#define ZXDG_TOPLEVEL_V6_UNSET_FULLSCREEN 12 -#define ZXDG_TOPLEVEL_V6_SET_MINIMIZED 13 - -/** - * @ingroup iface_zxdg_toplevel_v6 - */ -#define ZXDG_TOPLEVEL_V6_CONFIGURE_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_toplevel_v6 - */ -#define ZXDG_TOPLEVEL_V6_CLOSE_SINCE_VERSION 1 - -/** - * @ingroup iface_zxdg_toplevel_v6 - */ -#define ZXDG_TOPLEVEL_V6_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_toplevel_v6 - */ -#define ZXDG_TOPLEVEL_V6_SET_PARENT_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_toplevel_v6 - */ -#define ZXDG_TOPLEVEL_V6_SET_TITLE_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_toplevel_v6 - */ -#define ZXDG_TOPLEVEL_V6_SET_APP_ID_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_toplevel_v6 - */ -#define ZXDG_TOPLEVEL_V6_SHOW_WINDOW_MENU_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_toplevel_v6 - */ -#define ZXDG_TOPLEVEL_V6_MOVE_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_toplevel_v6 - */ -#define ZXDG_TOPLEVEL_V6_RESIZE_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_toplevel_v6 - */ -#define ZXDG_TOPLEVEL_V6_SET_MAX_SIZE_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_toplevel_v6 - */ -#define ZXDG_TOPLEVEL_V6_SET_MIN_SIZE_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_toplevel_v6 - */ -#define ZXDG_TOPLEVEL_V6_SET_MAXIMIZED_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_toplevel_v6 - */ -#define ZXDG_TOPLEVEL_V6_UNSET_MAXIMIZED_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_toplevel_v6 - */ -#define ZXDG_TOPLEVEL_V6_SET_FULLSCREEN_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_toplevel_v6 - */ -#define ZXDG_TOPLEVEL_V6_UNSET_FULLSCREEN_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_toplevel_v6 - */ -#define ZXDG_TOPLEVEL_V6_SET_MINIMIZED_SINCE_VERSION 1 - -/** @ingroup iface_zxdg_toplevel_v6 */ -static inline void -zxdg_toplevel_v6_set_user_data(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) zxdg_toplevel_v6, user_data); -} - -/** @ingroup iface_zxdg_toplevel_v6 */ -static inline void * -zxdg_toplevel_v6_get_user_data(struct zxdg_toplevel_v6 *zxdg_toplevel_v6) -{ - return wl_proxy_get_user_data((struct wl_proxy *) zxdg_toplevel_v6); -} - -static inline uint32_t -zxdg_toplevel_v6_get_version(struct zxdg_toplevel_v6 *zxdg_toplevel_v6) -{ - return wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6); -} - -/** - * @ingroup iface_zxdg_toplevel_v6 - * - * Unmap and destroy the window. The window will be effectively - * hidden from the user's point of view, and all state like - * maximization, fullscreen, and so on, will be lost. - */ -static inline void -zxdg_toplevel_v6_destroy(struct zxdg_toplevel_v6 *zxdg_toplevel_v6) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, - ZXDG_TOPLEVEL_V6_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_zxdg_toplevel_v6 - * - * Set the "parent" of this surface. This window should be stacked - * above a parent. The parent surface must be mapped as long as this - * surface is mapped. - * - * Parent windows should be set on dialogs, toolboxes, or other - * "auxiliary" surfaces, so that the parent is raised when the dialog - * is raised. - */ -static inline void -zxdg_toplevel_v6_set_parent(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, struct zxdg_toplevel_v6 *parent) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, - ZXDG_TOPLEVEL_V6_SET_PARENT, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0, parent); -} - -/** - * @ingroup iface_zxdg_toplevel_v6 - * - * Set a short title for the surface. - * - * This string may be used to identify the surface in a task bar, - * window list, or other user interface elements provided by the - * compositor. - * - * The string must be encoded in UTF-8. - */ -static inline void -zxdg_toplevel_v6_set_title(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, const char *title) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, - ZXDG_TOPLEVEL_V6_SET_TITLE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0, title); -} - -/** - * @ingroup iface_zxdg_toplevel_v6 - * - * Set an application identifier for the surface. - * - * The app ID identifies the general class of applications to which - * the surface belongs. The compositor can use this to group multiple - * surfaces together, or to determine how to launch a new application. - * - * For D-Bus activatable applications, the app ID is used as the D-Bus - * service name. - * - * The compositor shell will try to group application surfaces together - * by their app ID. As a best practice, it is suggested to select app - * ID's that match the basename of the application's .desktop file. - * For example, "org.freedesktop.FooViewer" where the .desktop file is - * "org.freedesktop.FooViewer.desktop". - * - * See the desktop-entry specification [0] for more details on - * application identifiers and how they relate to well-known D-Bus - * names and .desktop files. - * - * [0] http://standards.freedesktop.org/desktop-entry-spec/ - */ -static inline void -zxdg_toplevel_v6_set_app_id(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, const char *app_id) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, - ZXDG_TOPLEVEL_V6_SET_APP_ID, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0, app_id); -} - -/** - * @ingroup iface_zxdg_toplevel_v6 - * - * Clients implementing client-side decorations might want to show - * a context menu when right-clicking on the decorations, giving the - * user a menu that they can use to maximize or minimize the window. - * - * This request asks the compositor to pop up such a window menu at - * the given position, relative to the local surface coordinates of - * the parent surface. There are no guarantees as to what menu items - * the window menu contains. - * - * This request must be used in response to some sort of user action - * like a button press, key press, or touch down event. - */ -static inline void -zxdg_toplevel_v6_show_window_menu(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, - ZXDG_TOPLEVEL_V6_SHOW_WINDOW_MENU, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0, seat, serial, x, y); -} - -/** - * @ingroup iface_zxdg_toplevel_v6 - * - * Start an interactive, user-driven move of the surface. - * - * This request must be used in response to some sort of user action - * like a button press, key press, or touch down event. The passed - * serial is used to determine the type of interactive move (touch, - * pointer, etc). - * - * The server may ignore move requests depending on the state of - * the surface (e.g. fullscreen or maximized), or if the passed serial - * is no longer valid. - * - * If triggered, the surface will lose the focus of the device - * (wl_pointer, wl_touch, etc) used for the move. It is up to the - * compositor to visually indicate that the move is taking place, such as - * updating a pointer cursor, during the move. There is no guarantee - * that the device focus will return when the move is completed. - */ -static inline void -zxdg_toplevel_v6_move(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, struct wl_seat *seat, uint32_t serial) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, - ZXDG_TOPLEVEL_V6_MOVE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0, seat, serial); -} - -/** - * @ingroup iface_zxdg_toplevel_v6 - * - * Start a user-driven, interactive resize of the surface. - * - * This request must be used in response to some sort of user action - * like a button press, key press, or touch down event. The passed - * serial is used to determine the type of interactive resize (touch, - * pointer, etc). - * - * The server may ignore resize requests depending on the state of - * the surface (e.g. fullscreen or maximized). - * - * If triggered, the client will receive configure events with the - * "resize" state enum value and the expected sizes. See the "resize" - * enum value for more details about what is required. The client - * must also acknowledge configure events using "ack_configure". After - * the resize is completed, the client will receive another "configure" - * event without the resize state. - * - * If triggered, the surface also will lose the focus of the device - * (wl_pointer, wl_touch, etc) used for the resize. It is up to the - * compositor to visually indicate that the resize is taking place, - * such as updating a pointer cursor, during the resize. There is no - * guarantee that the device focus will return when the resize is - * completed. - * - * The edges parameter specifies how the surface should be resized, - * and is one of the values of the resize_edge enum. The compositor - * may use this information to update the surface position for - * example when dragging the top left corner. The compositor may also - * use this information to adapt its behavior, e.g. choose an - * appropriate cursor image. - */ -static inline void -zxdg_toplevel_v6_resize(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, struct wl_seat *seat, uint32_t serial, uint32_t edges) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, - ZXDG_TOPLEVEL_V6_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0, seat, serial, edges); -} - -/** - * @ingroup iface_zxdg_toplevel_v6 - * - * Set a maximum size for the window. - * - * The client can specify a maximum size so that the compositor does - * not try to configure the window beyond this size. - * - * The width and height arguments are in window geometry coordinates. - * See xdg_surface.set_window_geometry. - * - * Values set in this way are double-buffered. They will get applied - * on the next commit. - * - * The compositor can use this information to allow or disallow - * different states like maximize or fullscreen and draw accurate - * animations. - * - * Similarly, a tiling window manager may use this information to - * place and resize client windows in a more effective way. - * - * The client should not rely on the compositor to obey the maximum - * size. The compositor may decide to ignore the values set by the - * client and request a larger size. - * - * If never set, or a value of zero in the request, means that the - * client has no expected maximum size in the given dimension. - * As a result, a client wishing to reset the maximum size - * to an unspecified state can use zero for width and height in the - * request. - * - * Requesting a maximum size to be smaller than the minimum size of - * a surface is illegal and will result in a protocol error. - * - * The width and height must be greater than or equal to zero. Using - * strictly negative values for width and height will result in the - * zxdg_shell_v6.invalid_surface_state error being raised. - */ -static inline void -zxdg_toplevel_v6_set_max_size(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, int32_t width, int32_t height) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, - ZXDG_TOPLEVEL_V6_SET_MAX_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0, width, height); -} - -/** - * @ingroup iface_zxdg_toplevel_v6 - * - * Set a minimum size for the window. - * - * The client can specify a minimum size so that the compositor does - * not try to configure the window below this size. - * - * The width and height arguments are in window geometry coordinates. - * See xdg_surface.set_window_geometry. - * - * Values set in this way are double-buffered. They will get applied - * on the next commit. - * - * The compositor can use this information to allow or disallow - * different states like maximize or fullscreen and draw accurate - * animations. - * - * Similarly, a tiling window manager may use this information to - * place and resize client windows in a more effective way. - * - * The client should not rely on the compositor to obey the minimum - * size. The compositor may decide to ignore the values set by the - * client and request a smaller size. - * - * If never set, or a value of zero in the request, means that the - * client has no expected minimum size in the given dimension. - * As a result, a client wishing to reset the minimum size - * to an unspecified state can use zero for width and height in the - * request. - * - * Requesting a minimum size to be larger than the maximum size of - * a surface is illegal and will result in a protocol error. - * - * The width and height must be greater than or equal to zero. Using - * strictly negative values for width and height will result in the - * zxdg_shell_v6.invalid_surface_state error being raised. - */ -static inline void -zxdg_toplevel_v6_set_min_size(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, int32_t width, int32_t height) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, - ZXDG_TOPLEVEL_V6_SET_MIN_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0, width, height); -} - -/** - * @ingroup iface_zxdg_toplevel_v6 - * - * Maximize the surface. - * - * After requesting that the surface should be maximized, the compositor - * will respond by emitting a configure event with the "maximized" state - * and the required window geometry. The client should then update its - * content, drawing it in a maximized state, i.e. without shadow or other - * decoration outside of the window geometry. The client must also - * acknowledge the configure when committing the new content (see - * ack_configure). - * - * It is up to the compositor to decide how and where to maximize the - * surface, for example which output and what region of the screen should - * be used. - * - * If the surface was already maximized, the compositor will still emit - * a configure event with the "maximized" state. - * - * Note that unrelated compositor side state changes may cause - * configure events to be emitted at any time, meaning trying to - * match this request to a specific future configure event is - * futile. - */ -static inline void -zxdg_toplevel_v6_set_maximized(struct zxdg_toplevel_v6 *zxdg_toplevel_v6) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, - ZXDG_TOPLEVEL_V6_SET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0); -} - -/** - * @ingroup iface_zxdg_toplevel_v6 - * - * Unmaximize the surface. - * - * After requesting that the surface should be unmaximized, the compositor - * will respond by emitting a configure event without the "maximized" - * state. If available, the compositor will include the window geometry - * dimensions the window had prior to being maximized in the configure - * request. The client must then update its content, drawing it in a - * regular state, i.e. potentially with shadow, etc. The client must also - * acknowledge the configure when committing the new content (see - * ack_configure). - * - * It is up to the compositor to position the surface after it was - * unmaximized; usually the position the surface had before maximizing, if - * applicable. - * - * If the surface was already not maximized, the compositor will still - * emit a configure event without the "maximized" state. - * - * Note that unrelated changes in the state of compositor may cause - * configure events to be emitted by the compositor between processing - * this request and emitting corresponding configure event, so trying - * to match the request with the event is futile. - */ -static inline void -zxdg_toplevel_v6_unset_maximized(struct zxdg_toplevel_v6 *zxdg_toplevel_v6) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, - ZXDG_TOPLEVEL_V6_UNSET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0); -} - -/** - * @ingroup iface_zxdg_toplevel_v6 - * - * Make the surface fullscreen. - * - * You can specify an output that you would prefer to be fullscreen. - * If this value is NULL, it's up to the compositor to choose which - * display will be used to map this surface. - * - * If the surface doesn't cover the whole output, the compositor will - * position the surface in the center of the output and compensate with - * black borders filling the rest of the output. - */ -static inline void -zxdg_toplevel_v6_set_fullscreen(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, struct wl_output *output) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, - ZXDG_TOPLEVEL_V6_SET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0, output); -} - -/** - * @ingroup iface_zxdg_toplevel_v6 - */ -static inline void -zxdg_toplevel_v6_unset_fullscreen(struct zxdg_toplevel_v6 *zxdg_toplevel_v6) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, - ZXDG_TOPLEVEL_V6_UNSET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0); -} - -/** - * @ingroup iface_zxdg_toplevel_v6 - * - * Request that the compositor minimize your surface. There is no - * way to know if the surface is currently minimized, nor is there - * any way to unset minimization on this surface. - * - * If you are looking to throttle redrawing when minimized, please - * instead use the wl_surface.frame event for this, as this will - * also work with live previews on windows in Alt-Tab, Expose or - * similar compositor features. - */ -static inline void -zxdg_toplevel_v6_set_minimized(struct zxdg_toplevel_v6 *zxdg_toplevel_v6) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_v6, - ZXDG_TOPLEVEL_V6_SET_MINIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_v6), 0); -} - -#ifndef ZXDG_POPUP_V6_ERROR_ENUM -#define ZXDG_POPUP_V6_ERROR_ENUM -enum zxdg_popup_v6_error { - /** - * tried to grab after being mapped - */ - ZXDG_POPUP_V6_ERROR_INVALID_GRAB = 0, -}; -#endif /* ZXDG_POPUP_V6_ERROR_ENUM */ - -/** - * @ingroup iface_zxdg_popup_v6 - * @struct zxdg_popup_v6_listener - */ -struct zxdg_popup_v6_listener { - /** - * configure the popup surface - * - * This event asks the popup surface to configure itself given - * the configuration. The configured state should not be applied - * immediately. See xdg_surface.configure for details. - * - * The x and y arguments represent the position the popup was - * placed at given the xdg_positioner rule, relative to the upper - * left corner of the window geometry of the parent surface. - * @param x x position relative to parent surface window geometry - * @param y y position relative to parent surface window geometry - * @param width window geometry width - * @param height window geometry height - */ - void (*configure)(void *data, - struct zxdg_popup_v6 *zxdg_popup_v6, - int32_t x, - int32_t y, - int32_t width, - int32_t height); - /** - * popup interaction is done - * - * The popup_done event is sent out when a popup is dismissed by - * the compositor. The client should destroy the xdg_popup object - * at this point. - */ - void (*popup_done)(void *data, - struct zxdg_popup_v6 *zxdg_popup_v6); -}; - -/** - * @ingroup iface_zxdg_popup_v6 - */ -static inline int -zxdg_popup_v6_add_listener(struct zxdg_popup_v6 *zxdg_popup_v6, - const struct zxdg_popup_v6_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) zxdg_popup_v6, - (void (**)(void)) listener, data); -} - -#define ZXDG_POPUP_V6_DESTROY 0 -#define ZXDG_POPUP_V6_GRAB 1 - -/** - * @ingroup iface_zxdg_popup_v6 - */ -#define ZXDG_POPUP_V6_CONFIGURE_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_popup_v6 - */ -#define ZXDG_POPUP_V6_POPUP_DONE_SINCE_VERSION 1 - -/** - * @ingroup iface_zxdg_popup_v6 - */ -#define ZXDG_POPUP_V6_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_zxdg_popup_v6 - */ -#define ZXDG_POPUP_V6_GRAB_SINCE_VERSION 1 - -/** @ingroup iface_zxdg_popup_v6 */ -static inline void -zxdg_popup_v6_set_user_data(struct zxdg_popup_v6 *zxdg_popup_v6, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) zxdg_popup_v6, user_data); -} - -/** @ingroup iface_zxdg_popup_v6 */ -static inline void * -zxdg_popup_v6_get_user_data(struct zxdg_popup_v6 *zxdg_popup_v6) -{ - return wl_proxy_get_user_data((struct wl_proxy *) zxdg_popup_v6); -} - -static inline uint32_t -zxdg_popup_v6_get_version(struct zxdg_popup_v6 *zxdg_popup_v6) -{ - return wl_proxy_get_version((struct wl_proxy *) zxdg_popup_v6); -} - -/** - * @ingroup iface_zxdg_popup_v6 - * - * This destroys the popup. Explicitly destroying the xdg_popup - * object will also dismiss the popup, and unmap the surface. - * - * If this xdg_popup is not the "topmost" popup, a protocol error - * will be sent. - */ -static inline void -zxdg_popup_v6_destroy(struct zxdg_popup_v6 *zxdg_popup_v6) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_popup_v6, - ZXDG_POPUP_V6_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_popup_v6), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_zxdg_popup_v6 - * - * This request makes the created popup take an explicit grab. An explicit - * grab will be dismissed when the user dismisses the popup, or when the - * client destroys the xdg_popup. This can be done by the user clicking - * outside the surface, using the keyboard, or even locking the screen - * through closing the lid or a timeout. - * - * If the compositor denies the grab, the popup will be immediately - * dismissed. - * - * This request must be used in response to some sort of user action like a - * button press, key press, or touch down event. The serial number of the - * event should be passed as 'serial'. - * - * The parent of a grabbing popup must either be an xdg_toplevel surface or - * another xdg_popup with an explicit grab. If the parent is another - * xdg_popup it means that the popups are nested, with this popup now being - * the topmost popup. - * - * Nested popups must be destroyed in the reverse order they were created - * in, e.g. the only popup you are allowed to destroy at all times is the - * topmost one. - * - * When compositors choose to dismiss a popup, they may dismiss every - * nested grabbing popup as well. When a compositor dismisses popups, it - * will follow the same dismissing order as required from the client. - * - * The parent of a grabbing popup must either be another xdg_popup with an - * active explicit grab, or an xdg_popup or xdg_toplevel, if there are no - * explicit grabs already taken. - * - * If the topmost grabbing popup is destroyed, the grab will be returned to - * the parent of the popup, if that parent previously had an explicit grab. - * - * If the parent is a grabbing popup which has already been dismissed, this - * popup will be immediately dismissed. If the parent is a popup that did - * not take an explicit grab, an error will be raised. - * - * During a popup grab, the client owning the grab will receive pointer - * and touch events for all their surfaces as normal (similar to an - * "owner-events" grab in X11 parlance), while the top most grabbing popup - * will always have keyboard focus. - */ -static inline void -zxdg_popup_v6_grab(struct zxdg_popup_v6 *zxdg_popup_v6, struct wl_seat *seat, uint32_t serial) -{ - wl_proxy_marshal_flags((struct wl_proxy *) zxdg_popup_v6, - ZXDG_POPUP_V6_GRAB, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_popup_v6), 0, seat, serial); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/wayland/cc/xdg-shell.hh b/wayland/cc/xdg-shell.hh new file mode 100644 index 00000000..ea75d476 --- /dev/null +++ b/wayland/cc/xdg-shell.hh @@ -0,0 +1,2307 @@ +/* Generated by wayland-scanner 1.22.0 */ + +#ifndef XDG_SHELL_CLIENT_PROTOCOL_H +#define XDG_SHELL_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_xdg_shell The xdg_shell protocol + * @section page_ifaces_xdg_shell Interfaces + * - @subpage page_iface_xdg_wm_base - create desktop-style surfaces + * - @subpage page_iface_xdg_positioner - child surface positioner + * - @subpage page_iface_xdg_surface - desktop user interface surface base interface + * - @subpage page_iface_xdg_toplevel - toplevel surface + * - @subpage page_iface_xdg_popup - short-lived, popup surfaces for menus + * @section page_copyright_xdg_shell Copyright + *
+ *
+ * Copyright © 2008-2013 Kristian Høgsberg
+ * Copyright © 2013      Rafael Antognolli
+ * Copyright © 2013      Jasper St. Pierre
+ * Copyright © 2010-2013 Intel Corporation
+ * Copyright © 2015-2017 Samsung Electronics Co., Ltd
+ * Copyright © 2015-2017 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_output; +struct wl_seat; +struct wl_surface; +struct xdg_popup; +struct xdg_positioner; +struct xdg_surface; +struct xdg_toplevel; +struct xdg_wm_base; + +#ifndef XDG_WM_BASE_INTERFACE +#define XDG_WM_BASE_INTERFACE +/** + * @page page_iface_xdg_wm_base xdg_wm_base + * @section page_iface_xdg_wm_base_desc Description + * + * The xdg_wm_base interface is exposed as a global object enabling clients + * to turn their wl_surfaces into windows in a desktop environment. It + * defines the basic functionality needed for clients and the compositor to + * create windows that can be dragged, resized, maximized, etc, as well as + * creating transient windows such as popup menus. + * @section page_iface_xdg_wm_base_api API + * See @ref iface_xdg_wm_base. + */ +/** + * @defgroup iface_xdg_wm_base The xdg_wm_base interface + * + * The xdg_wm_base interface is exposed as a global object enabling clients + * to turn their wl_surfaces into windows in a desktop environment. It + * defines the basic functionality needed for clients and the compositor to + * create windows that can be dragged, resized, maximized, etc, as well as + * creating transient windows such as popup menus. + */ +extern const struct wl_interface xdg_wm_base_interface; +#endif +#ifndef XDG_POSITIONER_INTERFACE +#define XDG_POSITIONER_INTERFACE +/** + * @page page_iface_xdg_positioner xdg_positioner + * @section page_iface_xdg_positioner_desc Description + * + * The xdg_positioner provides a collection of rules for the placement of a + * child surface relative to a parent surface. Rules can be defined to ensure + * the child surface remains within the visible area's borders, and to + * specify how the child surface changes its position, such as sliding along + * an axis, or flipping around a rectangle. These positioner-created rules are + * constrained by the requirement that a child surface must intersect with or + * be at least partially adjacent to its parent surface. + * + * See the various requests for details about possible rules. + * + * At the time of the request, the compositor makes a copy of the rules + * specified by the xdg_positioner. Thus, after the request is complete the + * xdg_positioner object can be destroyed or reused; further changes to the + * object will have no effect on previous usages. + * + * For an xdg_positioner object to be considered complete, it must have a + * non-zero size set by set_size, and a non-zero anchor rectangle set by + * set_anchor_rect. Passing an incomplete xdg_positioner object when + * positioning a surface raises an invalid_positioner error. + * @section page_iface_xdg_positioner_api API + * See @ref iface_xdg_positioner. + */ +/** + * @defgroup iface_xdg_positioner The xdg_positioner interface + * + * The xdg_positioner provides a collection of rules for the placement of a + * child surface relative to a parent surface. Rules can be defined to ensure + * the child surface remains within the visible area's borders, and to + * specify how the child surface changes its position, such as sliding along + * an axis, or flipping around a rectangle. These positioner-created rules are + * constrained by the requirement that a child surface must intersect with or + * be at least partially adjacent to its parent surface. + * + * See the various requests for details about possible rules. + * + * At the time of the request, the compositor makes a copy of the rules + * specified by the xdg_positioner. Thus, after the request is complete the + * xdg_positioner object can be destroyed or reused; further changes to the + * object will have no effect on previous usages. + * + * For an xdg_positioner object to be considered complete, it must have a + * non-zero size set by set_size, and a non-zero anchor rectangle set by + * set_anchor_rect. Passing an incomplete xdg_positioner object when + * positioning a surface raises an invalid_positioner error. + */ +extern const struct wl_interface xdg_positioner_interface; +#endif +#ifndef XDG_SURFACE_INTERFACE +#define XDG_SURFACE_INTERFACE +/** + * @page page_iface_xdg_surface xdg_surface + * @section page_iface_xdg_surface_desc Description + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides a base set of functionality required to construct user + * interface elements requiring management by the compositor, such as + * toplevel windows, menus, etc. The types of functionality are split into + * xdg_surface roles. + * + * Creating an xdg_surface does not set the role for a wl_surface. In order + * to map an xdg_surface, the client must create a role-specific object + * using, e.g., get_toplevel, get_popup. The wl_surface for any given + * xdg_surface can have at most one role, and may not be assigned any role + * not based on xdg_surface. + * + * A role must be assigned before any other requests are made to the + * xdg_surface object. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. + * + * Creating an xdg_surface from a wl_surface which has a buffer attached or + * committed is a client error, and any attempts by a client to attach or + * manipulate a buffer prior to the first xdg_surface.configure call must + * also be treated as errors. + * + * After creating a role-specific object and setting it up, the client must + * perform an initial commit without any buffer attached. The compositor + * will reply with initial wl_surface state such as + * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure + * event. The client must acknowledge it and is then allowed to attach a + * buffer to map the surface. + * + * Mapping an xdg_surface-based role surface is defined as making it + * possible for the surface to be shown by the compositor. Note that + * a mapped surface is not guaranteed to be visible once it is mapped. + * + * For an xdg_surface to be mapped by the compositor, the following + * conditions must be met: + * (1) the client has assigned an xdg_surface-based role to the surface + * (2) the client has set and committed the xdg_surface state and the + * role-dependent state to the surface + * (3) the client has committed a buffer to the surface + * + * A newly-unmapped surface is considered to have met condition (1) out + * of the 3 required conditions for mapping a surface if its role surface + * has not been destroyed, i.e. the client must perform the initial commit + * again before attaching a buffer. + * @section page_iface_xdg_surface_api API + * See @ref iface_xdg_surface. + */ +/** + * @defgroup iface_xdg_surface The xdg_surface interface + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides a base set of functionality required to construct user + * interface elements requiring management by the compositor, such as + * toplevel windows, menus, etc. The types of functionality are split into + * xdg_surface roles. + * + * Creating an xdg_surface does not set the role for a wl_surface. In order + * to map an xdg_surface, the client must create a role-specific object + * using, e.g., get_toplevel, get_popup. The wl_surface for any given + * xdg_surface can have at most one role, and may not be assigned any role + * not based on xdg_surface. + * + * A role must be assigned before any other requests are made to the + * xdg_surface object. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. + * + * Creating an xdg_surface from a wl_surface which has a buffer attached or + * committed is a client error, and any attempts by a client to attach or + * manipulate a buffer prior to the first xdg_surface.configure call must + * also be treated as errors. + * + * After creating a role-specific object and setting it up, the client must + * perform an initial commit without any buffer attached. The compositor + * will reply with initial wl_surface state such as + * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure + * event. The client must acknowledge it and is then allowed to attach a + * buffer to map the surface. + * + * Mapping an xdg_surface-based role surface is defined as making it + * possible for the surface to be shown by the compositor. Note that + * a mapped surface is not guaranteed to be visible once it is mapped. + * + * For an xdg_surface to be mapped by the compositor, the following + * conditions must be met: + * (1) the client has assigned an xdg_surface-based role to the surface + * (2) the client has set and committed the xdg_surface state and the + * role-dependent state to the surface + * (3) the client has committed a buffer to the surface + * + * A newly-unmapped surface is considered to have met condition (1) out + * of the 3 required conditions for mapping a surface if its role surface + * has not been destroyed, i.e. the client must perform the initial commit + * again before attaching a buffer. + */ +extern const struct wl_interface xdg_surface_interface; +#endif +#ifndef XDG_TOPLEVEL_INTERFACE +#define XDG_TOPLEVEL_INTERFACE +/** + * @page page_iface_xdg_toplevel xdg_toplevel + * @section page_iface_xdg_toplevel_desc Description + * + * This interface defines an xdg_surface role which allows a surface to, + * among other things, set window-like properties such as maximize, + * fullscreen, and minimize, set application-specific metadata like title and + * id, and well as trigger user interactive operations such as interactive + * resize and move. + * + * Unmapping an xdg_toplevel means that the surface cannot be shown + * by the compositor until it is explicitly mapped again. + * All active operations (e.g., move, resize) are canceled and all + * attributes (e.g. title, state, stacking, ...) are discarded for + * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to + * the state it had right after xdg_surface.get_toplevel. The client + * can re-map the toplevel by perfoming a commit without any buffer + * attached, waiting for a configure event and handling it as usual (see + * xdg_surface description). + * + * Attaching a null buffer to a toplevel unmaps the surface. + * @section page_iface_xdg_toplevel_api API + * See @ref iface_xdg_toplevel. + */ +/** + * @defgroup iface_xdg_toplevel The xdg_toplevel interface + * + * This interface defines an xdg_surface role which allows a surface to, + * among other things, set window-like properties such as maximize, + * fullscreen, and minimize, set application-specific metadata like title and + * id, and well as trigger user interactive operations such as interactive + * resize and move. + * + * Unmapping an xdg_toplevel means that the surface cannot be shown + * by the compositor until it is explicitly mapped again. + * All active operations (e.g., move, resize) are canceled and all + * attributes (e.g. title, state, stacking, ...) are discarded for + * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to + * the state it had right after xdg_surface.get_toplevel. The client + * can re-map the toplevel by perfoming a commit without any buffer + * attached, waiting for a configure event and handling it as usual (see + * xdg_surface description). + * + * Attaching a null buffer to a toplevel unmaps the surface. + */ +extern const struct wl_interface xdg_toplevel_interface; +#endif +#ifndef XDG_POPUP_INTERFACE +#define XDG_POPUP_INTERFACE +/** + * @page page_iface_xdg_popup xdg_popup + * @section page_iface_xdg_popup_desc Description + * + * A popup surface is a short-lived, temporary surface. It can be used to + * implement for example menus, popovers, tooltips and other similar user + * interface concepts. + * + * A popup can be made to take an explicit grab. See xdg_popup.grab for + * details. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. See the xdg_popup.popup_done + * event for details. + * + * Explicitly destroying the xdg_popup object will also dismiss the popup and + * unmap the surface. Clients that want to dismiss the popup when another + * surface of their own is clicked should dismiss the popup using the destroy + * request. + * + * A newly created xdg_popup will be stacked on top of all previously created + * xdg_popup surfaces associated with the same xdg_toplevel. + * + * The parent of an xdg_popup must be mapped (see the xdg_surface + * description) before the xdg_popup itself. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_popup state to take effect. + * @section page_iface_xdg_popup_api API + * See @ref iface_xdg_popup. + */ +/** + * @defgroup iface_xdg_popup The xdg_popup interface + * + * A popup surface is a short-lived, temporary surface. It can be used to + * implement for example menus, popovers, tooltips and other similar user + * interface concepts. + * + * A popup can be made to take an explicit grab. See xdg_popup.grab for + * details. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. See the xdg_popup.popup_done + * event for details. + * + * Explicitly destroying the xdg_popup object will also dismiss the popup and + * unmap the surface. Clients that want to dismiss the popup when another + * surface of their own is clicked should dismiss the popup using the destroy + * request. + * + * A newly created xdg_popup will be stacked on top of all previously created + * xdg_popup surfaces associated with the same xdg_toplevel. + * + * The parent of an xdg_popup must be mapped (see the xdg_surface + * description) before the xdg_popup itself. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_popup state to take effect. + */ +extern const struct wl_interface xdg_popup_interface; +#endif + +#ifndef XDG_WM_BASE_ERROR_ENUM +#define XDG_WM_BASE_ERROR_ENUM +enum xdg_wm_base_error { + /** + * given wl_surface has another role + */ + XDG_WM_BASE_ERROR_ROLE = 0, + /** + * xdg_wm_base was destroyed before children + */ + XDG_WM_BASE_ERROR_DEFUNCT_SURFACES = 1, + /** + * the client tried to map or destroy a non-topmost popup + */ + XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP = 2, + /** + * the client specified an invalid popup parent surface + */ + XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT = 3, + /** + * the client provided an invalid surface state + */ + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE = 4, + /** + * the client provided an invalid positioner + */ + XDG_WM_BASE_ERROR_INVALID_POSITIONER = 5, + /** + * the client didn’t respond to a ping event in time + */ + XDG_WM_BASE_ERROR_UNRESPONSIVE = 6, +}; +#endif /* XDG_WM_BASE_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_wm_base + * @struct xdg_wm_base_listener + */ +struct xdg_wm_base_listener { + /** + * check if the client is alive + * + * The ping event asks the client if it's still alive. Pass the + * serial specified in the event back to the compositor by sending + * a "pong" request back with the specified serial. See + * xdg_wm_base.pong. + * + * Compositors can use this to determine if the client is still + * alive. It's unspecified what will happen if the client doesn't + * respond to the ping request, or in what timeframe. Clients + * should try to respond in a reasonable amount of time. The + * “unresponsive” error is provided for compositors that wish + * to disconnect unresponsive clients. + * + * A compositor is free to ping in any way it wants, but a client + * must always respond to any xdg_wm_base object it created. + * @param serial pass this to the pong request + */ + void (*ping)(void *data, + struct xdg_wm_base *xdg_wm_base, + uint32_t serial); +}; + +/** + * @ingroup iface_xdg_wm_base + */ +static inline int +xdg_wm_base_add_listener(struct xdg_wm_base *xdg_wm_base, + const struct xdg_wm_base_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_wm_base, + (void (**)(void)) listener, data); +} + +#define XDG_WM_BASE_DESTROY 0 +#define XDG_WM_BASE_CREATE_POSITIONER 1 +#define XDG_WM_BASE_GET_XDG_SURFACE 2 +#define XDG_WM_BASE_PONG 3 + +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_PING_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_CREATE_POSITIONER_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_GET_XDG_SURFACE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_PONG_SINCE_VERSION 1 + +/** @ingroup iface_xdg_wm_base */ +static inline void +xdg_wm_base_set_user_data(struct xdg_wm_base *xdg_wm_base, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_wm_base, user_data); +} + +/** @ingroup iface_xdg_wm_base */ +static inline void * +xdg_wm_base_get_user_data(struct xdg_wm_base *xdg_wm_base) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_wm_base); +} + +static inline uint32_t +xdg_wm_base_get_version(struct xdg_wm_base *xdg_wm_base) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_wm_base); +} + +/** + * @ingroup iface_xdg_wm_base + * + * Destroy this xdg_wm_base object. + * + * Destroying a bound xdg_wm_base object while there are surfaces + * still alive created by this xdg_wm_base object instance is illegal + * and will result in a defunct_surfaces error. + */ +static inline void +xdg_wm_base_destroy(struct xdg_wm_base *xdg_wm_base) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_xdg_wm_base + * + * Create a positioner object. A positioner object is used to position + * surfaces relative to some parent surface. See the interface description + * and xdg_surface.get_popup for details. + */ +static inline struct xdg_positioner * +xdg_wm_base_create_positioner(struct xdg_wm_base *xdg_wm_base) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_CREATE_POSITIONER, &xdg_positioner_interface, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, NULL); + + return (struct xdg_positioner *) id; +} + +/** + * @ingroup iface_xdg_wm_base + * + * This creates an xdg_surface for the given surface. While xdg_surface + * itself is not a role, the corresponding surface may only be assigned + * a role extending xdg_surface, such as xdg_toplevel or xdg_popup. It is + * illegal to create an xdg_surface for a wl_surface which already has an + * assigned role and this will result in a role error. + * + * This creates an xdg_surface for the given surface. An xdg_surface is + * used as basis to define a role to a given surface, such as xdg_toplevel + * or xdg_popup. It also manages functionality shared between xdg_surface + * based surface roles. + * + * See the documentation of xdg_surface for more details about what an + * xdg_surface is and how it is used. + */ +static inline struct xdg_surface * +xdg_wm_base_get_xdg_surface(struct xdg_wm_base *xdg_wm_base, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_GET_XDG_SURFACE, &xdg_surface_interface, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, NULL, surface); + + return (struct xdg_surface *) id; +} + +/** + * @ingroup iface_xdg_wm_base + * + * A client must respond to a ping event with a pong request or + * the client may be deemed unresponsive. See xdg_wm_base.ping + * and xdg_wm_base.error.unresponsive. + */ +static inline void +xdg_wm_base_pong(struct xdg_wm_base *xdg_wm_base, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_PONG, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, serial); +} + +#ifndef XDG_POSITIONER_ERROR_ENUM +#define XDG_POSITIONER_ERROR_ENUM +enum xdg_positioner_error { + /** + * invalid input provided + */ + XDG_POSITIONER_ERROR_INVALID_INPUT = 0, +}; +#endif /* XDG_POSITIONER_ERROR_ENUM */ + +#ifndef XDG_POSITIONER_ANCHOR_ENUM +#define XDG_POSITIONER_ANCHOR_ENUM +enum xdg_positioner_anchor { + XDG_POSITIONER_ANCHOR_NONE = 0, + XDG_POSITIONER_ANCHOR_TOP = 1, + XDG_POSITIONER_ANCHOR_BOTTOM = 2, + XDG_POSITIONER_ANCHOR_LEFT = 3, + XDG_POSITIONER_ANCHOR_RIGHT = 4, + XDG_POSITIONER_ANCHOR_TOP_LEFT = 5, + XDG_POSITIONER_ANCHOR_BOTTOM_LEFT = 6, + XDG_POSITIONER_ANCHOR_TOP_RIGHT = 7, + XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT = 8, +}; +#endif /* XDG_POSITIONER_ANCHOR_ENUM */ + +#ifndef XDG_POSITIONER_GRAVITY_ENUM +#define XDG_POSITIONER_GRAVITY_ENUM +enum xdg_positioner_gravity { + XDG_POSITIONER_GRAVITY_NONE = 0, + XDG_POSITIONER_GRAVITY_TOP = 1, + XDG_POSITIONER_GRAVITY_BOTTOM = 2, + XDG_POSITIONER_GRAVITY_LEFT = 3, + XDG_POSITIONER_GRAVITY_RIGHT = 4, + XDG_POSITIONER_GRAVITY_TOP_LEFT = 5, + XDG_POSITIONER_GRAVITY_BOTTOM_LEFT = 6, + XDG_POSITIONER_GRAVITY_TOP_RIGHT = 7, + XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT = 8, +}; +#endif /* XDG_POSITIONER_GRAVITY_ENUM */ + +#ifndef XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM +#define XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM +/** + * @ingroup iface_xdg_positioner + * constraint adjustments + * + * The constraint adjustment value define ways the compositor will adjust + * the position of the surface, if the unadjusted position would result + * in the surface being partly constrained. + * + * Whether a surface is considered 'constrained' is left to the compositor + * to determine. For example, the surface may be partly outside the + * compositor's defined 'work area', thus necessitating the child surface's + * position be adjusted until it is entirely inside the work area. + * + * The adjustments can be combined, according to a defined precedence: 1) + * Flip, 2) Slide, 3) Resize. + */ +enum xdg_positioner_constraint_adjustment { + /** + * don't move the child surface when constrained + * + * Don't alter the surface position even if it is constrained on + * some axis, for example partially outside the edge of an output. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE = 0, + /** + * move along the x axis until unconstrained + * + * Slide the surface along the x axis until it is no longer + * constrained. + * + * First try to slide towards the direction of the gravity on the x + * axis until either the edge in the opposite direction of the + * gravity is unconstrained or the edge in the direction of the + * gravity is constrained. + * + * Then try to slide towards the opposite direction of the gravity + * on the x axis until either the edge in the direction of the + * gravity is unconstrained or the edge in the opposite direction + * of the gravity is constrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1, + /** + * move along the y axis until unconstrained + * + * Slide the surface along the y axis until it is no longer + * constrained. + * + * First try to slide towards the direction of the gravity on the y + * axis until either the edge in the opposite direction of the + * gravity is unconstrained or the edge in the direction of the + * gravity is constrained. + * + * Then try to slide towards the opposite direction of the gravity + * on the y axis until either the edge in the direction of the + * gravity is unconstrained or the edge in the opposite direction + * of the gravity is constrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2, + /** + * invert the anchor and gravity on the x axis + * + * Invert the anchor and gravity on the x axis if the surface is + * constrained on the x axis. For example, if the left edge of the + * surface is constrained, the gravity is 'left' and the anchor is + * 'left', change the gravity to 'right' and the anchor to 'right'. + * + * If the adjusted position also ends up being constrained, the + * resulting position of the flip_x adjustment will be the one + * before the adjustment. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X = 4, + /** + * invert the anchor and gravity on the y axis + * + * Invert the anchor and gravity on the y axis if the surface is + * constrained on the y axis. For example, if the bottom edge of + * the surface is constrained, the gravity is 'bottom' and the + * anchor is 'bottom', change the gravity to 'top' and the anchor + * to 'top'. + * + * The adjusted position is calculated given the original anchor + * rectangle and offset, but with the new flipped anchor and + * gravity values. + * + * If the adjusted position also ends up being constrained, the + * resulting position of the flip_y adjustment will be the one + * before the adjustment. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8, + /** + * horizontally resize the surface + * + * Resize the surface horizontally so that it is completely + * unconstrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16, + /** + * vertically resize the surface + * + * Resize the surface vertically so that it is completely + * unconstrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32, +}; +#endif /* XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM */ + +#define XDG_POSITIONER_DESTROY 0 +#define XDG_POSITIONER_SET_SIZE 1 +#define XDG_POSITIONER_SET_ANCHOR_RECT 2 +#define XDG_POSITIONER_SET_ANCHOR 3 +#define XDG_POSITIONER_SET_GRAVITY 4 +#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT 5 +#define XDG_POSITIONER_SET_OFFSET 6 +#define XDG_POSITIONER_SET_REACTIVE 7 +#define XDG_POSITIONER_SET_PARENT_SIZE 8 +#define XDG_POSITIONER_SET_PARENT_CONFIGURE 9 + + +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_ANCHOR_RECT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_ANCHOR_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_GRAVITY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_OFFSET_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_REACTIVE_SINCE_VERSION 3 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_PARENT_SIZE_SINCE_VERSION 3 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_PARENT_CONFIGURE_SINCE_VERSION 3 + +/** @ingroup iface_xdg_positioner */ +static inline void +xdg_positioner_set_user_data(struct xdg_positioner *xdg_positioner, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_positioner, user_data); +} + +/** @ingroup iface_xdg_positioner */ +static inline void * +xdg_positioner_get_user_data(struct xdg_positioner *xdg_positioner) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_positioner); +} + +static inline uint32_t +xdg_positioner_get_version(struct xdg_positioner *xdg_positioner) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_positioner); +} + +/** + * @ingroup iface_xdg_positioner + * + * Notify the compositor that the xdg_positioner will no longer be used. + */ +static inline void +xdg_positioner_destroy(struct xdg_positioner *xdg_positioner) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_xdg_positioner + * + * Set the size of the surface that is to be positioned with the positioner + * object. The size is in surface-local coordinates and corresponds to the + * window geometry. See xdg_surface.set_window_geometry. + * + * If a zero or negative size is set the invalid_input error is raised. + */ +static inline void +xdg_positioner_set_size(struct xdg_positioner *xdg_positioner, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, width, height); +} + +/** + * @ingroup iface_xdg_positioner + * + * Specify the anchor rectangle within the parent surface that the child + * surface will be placed relative to. The rectangle is relative to the + * window geometry as defined by xdg_surface.set_window_geometry of the + * parent surface. + * + * When the xdg_positioner object is used to position a child surface, the + * anchor rectangle may not extend outside the window geometry of the + * positioned child's parent surface. + * + * If a negative size is set the invalid_input error is raised. + */ +static inline void +xdg_positioner_set_anchor_rect(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_ANCHOR_RECT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, x, y, width, height); +} + +/** + * @ingroup iface_xdg_positioner + * + * Defines the anchor point for the anchor rectangle. The specified anchor + * is used derive an anchor point that the child surface will be + * positioned relative to. If a corner anchor is set (e.g. 'top_left' or + * 'bottom_right'), the anchor point will be at the specified corner; + * otherwise, the derived anchor point will be centered on the specified + * edge, or in the center of the anchor rectangle if no edge is specified. + */ +static inline void +xdg_positioner_set_anchor(struct xdg_positioner *xdg_positioner, uint32_t anchor) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_ANCHOR, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, anchor); +} + +/** + * @ingroup iface_xdg_positioner + * + * Defines in what direction a surface should be positioned, relative to + * the anchor point of the parent surface. If a corner gravity is + * specified (e.g. 'bottom_right' or 'top_left'), then the child surface + * will be placed towards the specified gravity; otherwise, the child + * surface will be centered over the anchor point on any axis that had no + * gravity specified. If the gravity is not in the ‘gravity’ enum, an + * invalid_input error is raised. + */ +static inline void +xdg_positioner_set_gravity(struct xdg_positioner *xdg_positioner, uint32_t gravity) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_GRAVITY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, gravity); +} + +/** + * @ingroup iface_xdg_positioner + * + * Specify how the window should be positioned if the originally intended + * position caused the surface to be constrained, meaning at least + * partially outside positioning boundaries set by the compositor. The + * adjustment is set by constructing a bitmask describing the adjustment to + * be made when the surface is constrained on that axis. + * + * If no bit for one axis is set, the compositor will assume that the child + * surface should not change its position on that axis when constrained. + * + * If more than one bit for one axis is set, the order of how adjustments + * are applied is specified in the corresponding adjustment descriptions. + * + * The default adjustment is none. + */ +static inline void +xdg_positioner_set_constraint_adjustment(struct xdg_positioner *xdg_positioner, uint32_t constraint_adjustment) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, constraint_adjustment); +} + +/** + * @ingroup iface_xdg_positioner + * + * Specify the surface position offset relative to the position of the + * anchor on the anchor rectangle and the anchor on the surface. For + * example if the anchor of the anchor rectangle is at (x, y), the surface + * has the gravity bottom|right, and the offset is (ox, oy), the calculated + * surface position will be (x + ox, y + oy). The offset position of the + * surface is the one used for constraint testing. See + * set_constraint_adjustment. + * + * An example use case is placing a popup menu on top of a user interface + * element, while aligning the user interface element of the parent surface + * with some user interface element placed somewhere in the popup surface. + */ +static inline void +xdg_positioner_set_offset(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_OFFSET, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, x, y); +} + +/** + * @ingroup iface_xdg_positioner + * + * When set reactive, the surface is reconstrained if the conditions used + * for constraining changed, e.g. the parent window moved. + * + * If the conditions changed and the popup was reconstrained, an + * xdg_popup.configure event is sent with updated geometry, followed by an + * xdg_surface.configure event. + */ +static inline void +xdg_positioner_set_reactive(struct xdg_positioner *xdg_positioner) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_REACTIVE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0); +} + +/** + * @ingroup iface_xdg_positioner + * + * Set the parent window geometry the compositor should use when + * positioning the popup. The compositor may use this information to + * determine the future state the popup should be constrained using. If + * this doesn't match the dimension of the parent the popup is eventually + * positioned against, the behavior is undefined. + * + * The arguments are given in the surface-local coordinate space. + */ +static inline void +xdg_positioner_set_parent_size(struct xdg_positioner *xdg_positioner, int32_t parent_width, int32_t parent_height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_PARENT_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, parent_width, parent_height); +} + +/** + * @ingroup iface_xdg_positioner + * + * Set the serial of an xdg_surface.configure event this positioner will be + * used in response to. The compositor may use this information together + * with set_parent_size to determine what future state the popup should be + * constrained using. + */ +static inline void +xdg_positioner_set_parent_configure(struct xdg_positioner *xdg_positioner, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_PARENT_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, serial); +} + +#ifndef XDG_SURFACE_ERROR_ENUM +#define XDG_SURFACE_ERROR_ENUM +enum xdg_surface_error { + /** + * Surface was not fully constructed + */ + XDG_SURFACE_ERROR_NOT_CONSTRUCTED = 1, + /** + * Surface was already constructed + */ + XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED = 2, + /** + * Attaching a buffer to an unconfigured surface + */ + XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER = 3, + /** + * Invalid serial number when acking a configure event + */ + XDG_SURFACE_ERROR_INVALID_SERIAL = 4, + /** + * Width or height was zero or negative + */ + XDG_SURFACE_ERROR_INVALID_SIZE = 5, + /** + * Surface was destroyed before its role object + */ + XDG_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT = 6, +}; +#endif /* XDG_SURFACE_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_surface + * @struct xdg_surface_listener + */ +struct xdg_surface_listener { + /** + * suggest a surface change + * + * The configure event marks the end of a configure sequence. A + * configure sequence is a set of one or more events configuring + * the state of the xdg_surface, including the final + * xdg_surface.configure event. + * + * Where applicable, xdg_surface surface roles will during a + * configure sequence extend this event as a latched state sent as + * events before the xdg_surface.configure event. Such events + * should be considered to make up a set of atomically applied + * configuration states, where the xdg_surface.configure commits + * the accumulated state. + * + * Clients should arrange their surface for the new states, and + * then send an ack_configure request with the serial sent in this + * configure event at some point before committing the new surface. + * + * If the client receives multiple configure events before it can + * respond to one, it is free to discard all but the last event it + * received. + * @param serial serial of the configure event + */ + void (*configure)(void *data, + struct xdg_surface *xdg_surface, + uint32_t serial); +}; + +/** + * @ingroup iface_xdg_surface + */ +static inline int +xdg_surface_add_listener(struct xdg_surface *xdg_surface, + const struct xdg_surface_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_surface, + (void (**)(void)) listener, data); +} + +#define XDG_SURFACE_DESTROY 0 +#define XDG_SURFACE_GET_TOPLEVEL 1 +#define XDG_SURFACE_GET_POPUP 2 +#define XDG_SURFACE_SET_WINDOW_GEOMETRY 3 +#define XDG_SURFACE_ACK_CONFIGURE 4 + +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_CONFIGURE_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_GET_TOPLEVEL_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_GET_POPUP_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_SET_WINDOW_GEOMETRY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_ACK_CONFIGURE_SINCE_VERSION 1 + +/** @ingroup iface_xdg_surface */ +static inline void +xdg_surface_set_user_data(struct xdg_surface *xdg_surface, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_surface, user_data); +} + +/** @ingroup iface_xdg_surface */ +static inline void * +xdg_surface_get_user_data(struct xdg_surface *xdg_surface) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_surface); +} + +static inline uint32_t +xdg_surface_get_version(struct xdg_surface *xdg_surface) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_surface); +} + +/** + * @ingroup iface_xdg_surface + * + * Destroy the xdg_surface object. An xdg_surface must only be destroyed + * after its role object has been destroyed, otherwise + * a defunct_role_object error is raised. + */ +static inline void +xdg_surface_destroy(struct xdg_surface *xdg_surface) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, + XDG_SURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_xdg_surface + * + * This creates an xdg_toplevel object for the given xdg_surface and gives + * the associated wl_surface the xdg_toplevel role. + * + * See the documentation of xdg_toplevel for more details about what an + * xdg_toplevel is and how it is used. + */ +static inline struct xdg_toplevel * +xdg_surface_get_toplevel(struct xdg_surface *xdg_surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, + XDG_SURFACE_GET_TOPLEVEL, &xdg_toplevel_interface, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, NULL); + + return (struct xdg_toplevel *) id; +} + +/** + * @ingroup iface_xdg_surface + * + * This creates an xdg_popup object for the given xdg_surface and gives + * the associated wl_surface the xdg_popup role. + * + * If null is passed as a parent, a parent surface must be specified using + * some other protocol, before committing the initial state. + * + * See the documentation of xdg_popup for more details about what an + * xdg_popup is and how it is used. + */ +static inline struct xdg_popup * +xdg_surface_get_popup(struct xdg_surface *xdg_surface, struct xdg_surface *parent, struct xdg_positioner *positioner) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, + XDG_SURFACE_GET_POPUP, &xdg_popup_interface, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, NULL, parent, positioner); + + return (struct xdg_popup *) id; +} + +/** + * @ingroup iface_xdg_surface + * + * The window geometry of a surface is its "visible bounds" from the + * user's perspective. Client-side decorations often have invisible + * portions like drop-shadows which should be ignored for the + * purposes of aligning, placing and constraining windows. + * + * The window geometry is double buffered, and will be applied at the + * time wl_surface.commit of the corresponding wl_surface is called. + * + * When maintaining a position, the compositor should treat the (x, y) + * coordinate of the window geometry as the top left corner of the window. + * A client changing the (x, y) window geometry coordinate should in + * general not alter the position of the window. + * + * Once the window geometry of the surface is set, it is not possible to + * unset it, and it will remain the same until set_window_geometry is + * called again, even if a new subsurface or buffer is attached. + * + * If never set, the value is the full bounds of the surface, + * including any subsurfaces. This updates dynamically on every + * commit. This unset is meant for extremely simple clients. + * + * The arguments are given in the surface-local coordinate space of + * the wl_surface associated with this xdg_surface, and may extend outside + * of the wl_surface itself to mark parts of the subsurface tree as part of + * the window geometry. + * + * When applied, the effective window geometry will be the set window + * geometry clamped to the bounding rectangle of the combined + * geometry of the surface of the xdg_surface and the associated + * subsurfaces. + * + * The effective geometry will not be recalculated unless a new call to + * set_window_geometry is done and the new pending surface state is + * subsequently applied. + * + * The width and height of the effective window geometry must be + * greater than zero. Setting an invalid size will raise an + * invalid_size error. + */ +static inline void +xdg_surface_set_window_geometry(struct xdg_surface *xdg_surface, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, + XDG_SURFACE_SET_WINDOW_GEOMETRY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, x, y, width, height); +} + +/** + * @ingroup iface_xdg_surface + * + * When a configure event is received, if a client commits the + * surface in response to the configure event, then the client + * must make an ack_configure request sometime before the commit + * request, passing along the serial of the configure event. + * + * For instance, for toplevel surfaces the compositor might use this + * information to move a surface to the top left only when the client has + * drawn itself for the maximized or fullscreen state. + * + * If the client receives multiple configure events before it + * can respond to one, it only has to ack the last configure event. + * Acking a configure event that was never sent raises an invalid_serial + * error. + * + * A client is not required to commit immediately after sending + * an ack_configure request - it may even ack_configure several times + * before its next surface commit. + * + * A client may send multiple ack_configure requests before committing, but + * only the last request sent before a commit indicates which configure + * event the client really is responding to. + * + * Sending an ack_configure request consumes the serial number sent with + * the request, as well as serial numbers sent by all configure events + * sent on this xdg_surface prior to the configure event referenced by + * the committed serial. + * + * It is an error to issue multiple ack_configure requests referencing a + * serial from the same configure event, or to issue an ack_configure + * request referencing a serial from a configure event issued before the + * event identified by the last ack_configure request for the same + * xdg_surface. Doing so will raise an invalid_serial error. + */ +static inline void +xdg_surface_ack_configure(struct xdg_surface *xdg_surface, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, + XDG_SURFACE_ACK_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, serial); +} + +#ifndef XDG_TOPLEVEL_ERROR_ENUM +#define XDG_TOPLEVEL_ERROR_ENUM +enum xdg_toplevel_error { + /** + * provided value is not a valid variant of the resize_edge enum + */ + XDG_TOPLEVEL_ERROR_INVALID_RESIZE_EDGE = 0, + /** + * invalid parent toplevel + */ + XDG_TOPLEVEL_ERROR_INVALID_PARENT = 1, + /** + * client provided an invalid min or max size + */ + XDG_TOPLEVEL_ERROR_INVALID_SIZE = 2, +}; +#endif /* XDG_TOPLEVEL_ERROR_ENUM */ + +#ifndef XDG_TOPLEVEL_RESIZE_EDGE_ENUM +#define XDG_TOPLEVEL_RESIZE_EDGE_ENUM +/** + * @ingroup iface_xdg_toplevel + * edge values for resizing + * + * These values are used to indicate which edge of a surface + * is being dragged in a resize operation. + */ +enum xdg_toplevel_resize_edge { + XDG_TOPLEVEL_RESIZE_EDGE_NONE = 0, + XDG_TOPLEVEL_RESIZE_EDGE_TOP = 1, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2, + XDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4, + XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT = 5, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT = 6, + XDG_TOPLEVEL_RESIZE_EDGE_RIGHT = 8, + XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT = 9, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT = 10, +}; +#endif /* XDG_TOPLEVEL_RESIZE_EDGE_ENUM */ + +#ifndef XDG_TOPLEVEL_STATE_ENUM +#define XDG_TOPLEVEL_STATE_ENUM +/** + * @ingroup iface_xdg_toplevel + * types of state on the surface + * + * The different state values used on the surface. This is designed for + * state values like maximized, fullscreen. It is paired with the + * configure event to ensure that both the client and the compositor + * setting the state can be synchronized. + * + * States set in this way are double-buffered. They will get applied on + * the next commit. + */ +enum xdg_toplevel_state { + /** + * the surface is maximized + * the surface is maximized + * + * The surface is maximized. The window geometry specified in the + * configure event must be obeyed by the client, or the + * xdg_wm_base.invalid_surface_state error is raised. + * + * The client should draw without shadow or other decoration + * outside of the window geometry. + */ + XDG_TOPLEVEL_STATE_MAXIMIZED = 1, + /** + * the surface is fullscreen + * the surface is fullscreen + * + * The surface is fullscreen. The window geometry specified in + * the configure event is a maximum; the client cannot resize + * beyond it. For a surface to cover the whole fullscreened area, + * the geometry dimensions must be obeyed by the client. For more + * details, see xdg_toplevel.set_fullscreen. + */ + XDG_TOPLEVEL_STATE_FULLSCREEN = 2, + /** + * the surface is being resized + * the surface is being resized + * + * The surface is being resized. The window geometry specified in + * the configure event is a maximum; the client cannot resize + * beyond it. Clients that have aspect ratio or cell sizing + * configuration can use a smaller size, however. + */ + XDG_TOPLEVEL_STATE_RESIZING = 3, + /** + * the surface is now activated + * the surface is now activated + * + * Client window decorations should be painted as if the window + * is active. Do not assume this means that the window actually has + * keyboard or pointer focus. + */ + XDG_TOPLEVEL_STATE_ACTIVATED = 4, + /** + * the surface’s left edge is tiled + * + * The window is currently in a tiled layout and the left edge is + * considered to be adjacent to another part of the tiling grid. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_LEFT = 5, + /** + * the surface’s right edge is tiled + * + * The window is currently in a tiled layout and the right edge + * is considered to be adjacent to another part of the tiling grid. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_RIGHT = 6, + /** + * the surface’s top edge is tiled + * + * The window is currently in a tiled layout and the top edge is + * considered to be adjacent to another part of the tiling grid. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_TOP = 7, + /** + * the surface’s bottom edge is tiled + * + * The window is currently in a tiled layout and the bottom edge + * is considered to be adjacent to another part of the tiling grid. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_BOTTOM = 8, + /** + * surface repaint is suspended + * + * The surface is currently not ordinarily being repainted; for + * example because its content is occluded by another window, or + * its outputs are switched off due to screen locking. + * @since 6 + */ + XDG_TOPLEVEL_STATE_SUSPENDED = 9, +}; +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_TOP_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_BOTTOM_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION 6 +#endif /* XDG_TOPLEVEL_STATE_ENUM */ + +#ifndef XDG_TOPLEVEL_WM_CAPABILITIES_ENUM +#define XDG_TOPLEVEL_WM_CAPABILITIES_ENUM +enum xdg_toplevel_wm_capabilities { + /** + * show_window_menu is available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU = 1, + /** + * set_maximized and unset_maximized are available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE = 2, + /** + * set_fullscreen and unset_fullscreen are available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN = 3, + /** + * set_minimized is available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE = 4, +}; +#endif /* XDG_TOPLEVEL_WM_CAPABILITIES_ENUM */ + +/** + * @ingroup iface_xdg_toplevel + * @struct xdg_toplevel_listener + */ +struct xdg_toplevel_listener { + /** + * suggest a surface change + * + * This configure event asks the client to resize its toplevel + * surface or to change its state. The configured state should not + * be applied immediately. See xdg_surface.configure for details. + * + * The width and height arguments specify a hint to the window + * about how its surface should be resized in window geometry + * coordinates. See set_window_geometry. + * + * If the width or height arguments are zero, it means the client + * should decide its own window dimension. This may happen when the + * compositor needs to configure the state of the surface but + * doesn't have any information about any previous or expected + * dimension. + * + * The states listed in the event specify how the width/height + * arguments should be interpreted, and possibly how it should be + * drawn. + * + * Clients must send an ack_configure in response to this event. + * See xdg_surface.configure and xdg_surface.ack_configure for + * details. + */ + void (*configure)(void *data, + struct xdg_toplevel *xdg_toplevel, + int32_t width, + int32_t height, + struct wl_array *states); + /** + * surface wants to be closed + * + * The close event is sent by the compositor when the user wants + * the surface to be closed. This should be equivalent to the user + * clicking the close button in client-side decorations, if your + * application has any. + * + * This is only a request that the user intends to close the + * window. The client may choose to ignore this request, or show a + * dialog to ask the user to save their data, etc. + */ + void (*close)(void *data, + struct xdg_toplevel *xdg_toplevel); + /** + * recommended window geometry bounds + * + * The configure_bounds event may be sent prior to a + * xdg_toplevel.configure event to communicate the bounds a window + * geometry size is recommended to constrain to. + * + * The passed width and height are in surface coordinate space. If + * width and height are 0, it means bounds is unknown and + * equivalent to as if no configure_bounds event was ever sent for + * this surface. + * + * The bounds can for example correspond to the size of a monitor + * excluding any panels or other shell components, so that a + * surface isn't created in a way that it cannot fit. + * + * The bounds may change at any point, and in such a case, a new + * xdg_toplevel.configure_bounds will be sent, followed by + * xdg_toplevel.configure and xdg_surface.configure. + * @since 4 + */ + void (*configure_bounds)(void *data, + struct xdg_toplevel *xdg_toplevel, + int32_t width, + int32_t height); + /** + * compositor capabilities + * + * This event advertises the capabilities supported by the + * compositor. If a capability isn't supported, clients should hide + * or disable the UI elements that expose this functionality. For + * instance, if the compositor doesn't advertise support for + * minimized toplevels, a button triggering the set_minimized + * request should not be displayed. + * + * The compositor will ignore requests it doesn't support. For + * instance, a compositor which doesn't advertise support for + * minimized will ignore set_minimized requests. + * + * Compositors must send this event once before the first + * xdg_surface.configure event. When the capabilities change, + * compositors must send this event again and then send an + * xdg_surface.configure event. + * + * The configured state should not be applied immediately. See + * xdg_surface.configure for details. + * + * The capabilities are sent as an array of 32-bit unsigned + * integers in native endianness. + * @param capabilities array of 32-bit capabilities + * @since 5 + */ + void (*wm_capabilities)(void *data, + struct xdg_toplevel *xdg_toplevel, + struct wl_array *capabilities); +}; + +/** + * @ingroup iface_xdg_toplevel + */ +static inline int +xdg_toplevel_add_listener(struct xdg_toplevel *xdg_toplevel, + const struct xdg_toplevel_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_toplevel, + (void (**)(void)) listener, data); +} + +#define XDG_TOPLEVEL_DESTROY 0 +#define XDG_TOPLEVEL_SET_PARENT 1 +#define XDG_TOPLEVEL_SET_TITLE 2 +#define XDG_TOPLEVEL_SET_APP_ID 3 +#define XDG_TOPLEVEL_SHOW_WINDOW_MENU 4 +#define XDG_TOPLEVEL_MOVE 5 +#define XDG_TOPLEVEL_RESIZE 6 +#define XDG_TOPLEVEL_SET_MAX_SIZE 7 +#define XDG_TOPLEVEL_SET_MIN_SIZE 8 +#define XDG_TOPLEVEL_SET_MAXIMIZED 9 +#define XDG_TOPLEVEL_UNSET_MAXIMIZED 10 +#define XDG_TOPLEVEL_SET_FULLSCREEN 11 +#define XDG_TOPLEVEL_UNSET_FULLSCREEN 12 +#define XDG_TOPLEVEL_SET_MINIMIZED 13 + +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CLOSE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION 4 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION 5 + +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_PARENT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_TITLE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_APP_ID_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SHOW_WINDOW_MENU_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_MOVE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_RESIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MAX_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MIN_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_UNSET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_UNSET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MINIMIZED_SINCE_VERSION 1 + +/** @ingroup iface_xdg_toplevel */ +static inline void +xdg_toplevel_set_user_data(struct xdg_toplevel *xdg_toplevel, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_toplevel, user_data); +} + +/** @ingroup iface_xdg_toplevel */ +static inline void * +xdg_toplevel_get_user_data(struct xdg_toplevel *xdg_toplevel) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_toplevel); +} + +static inline uint32_t +xdg_toplevel_get_version(struct xdg_toplevel *xdg_toplevel) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_toplevel); +} + +/** + * @ingroup iface_xdg_toplevel + * + * This request destroys the role surface and unmaps the surface; + * see "Unmapping" behavior in interface section for details. + */ +static inline void +xdg_toplevel_destroy(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set the "parent" of this surface. This surface should be stacked + * above the parent surface and all other ancestor surfaces. + * + * Parent surfaces should be set on dialogs, toolboxes, or other + * "auxiliary" surfaces, so that the parent is raised when the dialog + * is raised. + * + * Setting a null parent for a child surface unsets its parent. Setting + * a null parent for a surface which currently has no parent is a no-op. + * + * Only mapped surfaces can have child surfaces. Setting a parent which + * is not mapped is equivalent to setting a null parent. If a surface + * becomes unmapped, its children's parent is set to the parent of + * the now-unmapped surface. If the now-unmapped surface has no parent, + * its children's parent is unset. If the now-unmapped surface becomes + * mapped again, its parent-child relationship is not restored. + * + * The parent toplevel must not be one of the child toplevel's + * descendants, and the parent must be different from the child toplevel, + * otherwise the invalid_parent protocol error is raised. + */ +static inline void +xdg_toplevel_set_parent(struct xdg_toplevel *xdg_toplevel, struct xdg_toplevel *parent) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_PARENT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, parent); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set a short title for the surface. + * + * This string may be used to identify the surface in a task bar, + * window list, or other user interface elements provided by the + * compositor. + * + * The string must be encoded in UTF-8. + */ +static inline void +xdg_toplevel_set_title(struct xdg_toplevel *xdg_toplevel, const char *title) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_TITLE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, title); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set an application identifier for the surface. + * + * The app ID identifies the general class of applications to which + * the surface belongs. The compositor can use this to group multiple + * surfaces together, or to determine how to launch a new application. + * + * For D-Bus activatable applications, the app ID is used as the D-Bus + * service name. + * + * The compositor shell will try to group application surfaces together + * by their app ID. As a best practice, it is suggested to select app + * ID's that match the basename of the application's .desktop file. + * For example, "org.freedesktop.FooViewer" where the .desktop file is + * "org.freedesktop.FooViewer.desktop". + * + * Like other properties, a set_app_id request can be sent after the + * xdg_toplevel has been mapped to update the property. + * + * See the desktop-entry specification [0] for more details on + * application identifiers and how they relate to well-known D-Bus + * names and .desktop files. + * + * [0] https://standards.freedesktop.org/desktop-entry-spec/ + */ +static inline void +xdg_toplevel_set_app_id(struct xdg_toplevel *xdg_toplevel, const char *app_id) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_APP_ID, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, app_id); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Clients implementing client-side decorations might want to show + * a context menu when right-clicking on the decorations, giving the + * user a menu that they can use to maximize or minimize the window. + * + * This request asks the compositor to pop up such a window menu at + * the given position, relative to the local surface coordinates of + * the parent surface. There are no guarantees as to what menu items + * the window menu contains, or even if a window menu will be drawn + * at all. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. + */ +static inline void +xdg_toplevel_show_window_menu(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SHOW_WINDOW_MENU, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial, x, y); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Start an interactive, user-driven move of the surface. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. The passed + * serial is used to determine the type of interactive move (touch, + * pointer, etc). + * + * The server may ignore move requests depending on the state of + * the surface (e.g. fullscreen or maximized), or if the passed serial + * is no longer valid. + * + * If triggered, the surface will lose the focus of the device + * (wl_pointer, wl_touch, etc) used for the move. It is up to the + * compositor to visually indicate that the move is taking place, such as + * updating a pointer cursor, during the move. There is no guarantee + * that the device focus will return when the move is completed. + */ +static inline void +xdg_toplevel_move(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_MOVE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Start a user-driven, interactive resize of the surface. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. The passed + * serial is used to determine the type of interactive resize (touch, + * pointer, etc). + * + * The server may ignore resize requests depending on the state of + * the surface (e.g. fullscreen or maximized). + * + * If triggered, the client will receive configure events with the + * "resize" state enum value and the expected sizes. See the "resize" + * enum value for more details about what is required. The client + * must also acknowledge configure events using "ack_configure". After + * the resize is completed, the client will receive another "configure" + * event without the resize state. + * + * If triggered, the surface also will lose the focus of the device + * (wl_pointer, wl_touch, etc) used for the resize. It is up to the + * compositor to visually indicate that the resize is taking place, + * such as updating a pointer cursor, during the resize. There is no + * guarantee that the device focus will return when the resize is + * completed. + * + * The edges parameter specifies how the surface should be resized, and + * is one of the values of the resize_edge enum. Values not matching + * a variant of the enum will cause the invalid_resize_edge protocol error. + * The compositor may use this information to update the surface position + * for example when dragging the top left corner. The compositor may also + * use this information to adapt its behavior, e.g. choose an appropriate + * cursor image. + */ +static inline void +xdg_toplevel_resize(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, uint32_t edges) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial, edges); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set a maximum size for the window. + * + * The client can specify a maximum size so that the compositor does + * not try to configure the window beyond this size. + * + * The width and height arguments are in window geometry coordinates. + * See xdg_surface.set_window_geometry. + * + * Values set in this way are double-buffered. They will get applied + * on the next commit. + * + * The compositor can use this information to allow or disallow + * different states like maximize or fullscreen and draw accurate + * animations. + * + * Similarly, a tiling window manager may use this information to + * place and resize client windows in a more effective way. + * + * The client should not rely on the compositor to obey the maximum + * size. The compositor may decide to ignore the values set by the + * client and request a larger size. + * + * If never set, or a value of zero in the request, means that the + * client has no expected maximum size in the given dimension. + * As a result, a client wishing to reset the maximum size + * to an unspecified state can use zero for width and height in the + * request. + * + * Requesting a maximum size to be smaller than the minimum size of + * a surface is illegal and will result in an invalid_size error. + * + * The width and height must be greater than or equal to zero. Using + * strictly negative values for width or height will result in a + * invalid_size error. + */ +static inline void +xdg_toplevel_set_max_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MAX_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, width, height); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set a minimum size for the window. + * + * The client can specify a minimum size so that the compositor does + * not try to configure the window below this size. + * + * The width and height arguments are in window geometry coordinates. + * See xdg_surface.set_window_geometry. + * + * Values set in this way are double-buffered. They will get applied + * on the next commit. + * + * The compositor can use this information to allow or disallow + * different states like maximize or fullscreen and draw accurate + * animations. + * + * Similarly, a tiling window manager may use this information to + * place and resize client windows in a more effective way. + * + * The client should not rely on the compositor to obey the minimum + * size. The compositor may decide to ignore the values set by the + * client and request a smaller size. + * + * If never set, or a value of zero in the request, means that the + * client has no expected minimum size in the given dimension. + * As a result, a client wishing to reset the minimum size + * to an unspecified state can use zero for width and height in the + * request. + * + * Requesting a minimum size to be larger than the maximum size of + * a surface is illegal and will result in an invalid_size error. + * + * The width and height must be greater than or equal to zero. Using + * strictly negative values for width and height will result in a + * invalid_size error. + */ +static inline void +xdg_toplevel_set_min_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MIN_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, width, height); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Maximize the surface. + * + * After requesting that the surface should be maximized, the compositor + * will respond by emitting a configure event. Whether this configure + * actually sets the window maximized is subject to compositor policies. + * The client must then update its content, drawing in the configured + * state. The client must also acknowledge the configure when committing + * the new content (see ack_configure). + * + * It is up to the compositor to decide how and where to maximize the + * surface, for example which output and what region of the screen should + * be used. + * + * If the surface was already maximized, the compositor will still emit + * a configure event with the "maximized" state. + * + * If the surface is in a fullscreen state, this request has no direct + * effect. It may alter the state the surface is returned to when + * unmaximized unless overridden by the compositor. + */ +static inline void +xdg_toplevel_set_maximized(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Unmaximize the surface. + * + * After requesting that the surface should be unmaximized, the compositor + * will respond by emitting a configure event. Whether this actually + * un-maximizes the window is subject to compositor policies. + * If available and applicable, the compositor will include the window + * geometry dimensions the window had prior to being maximized in the + * configure event. The client must then update its content, drawing it in + * the configured state. The client must also acknowledge the configure + * when committing the new content (see ack_configure). + * + * It is up to the compositor to position the surface after it was + * unmaximized; usually the position the surface had before maximizing, if + * applicable. + * + * If the surface was already not maximized, the compositor will still + * emit a configure event without the "maximized" state. + * + * If the surface is in a fullscreen state, this request has no direct + * effect. It may alter the state the surface is returned to when + * unmaximized unless overridden by the compositor. + */ +static inline void +xdg_toplevel_unset_maximized(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_UNSET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Make the surface fullscreen. + * + * After requesting that the surface should be fullscreened, the + * compositor will respond by emitting a configure event. Whether the + * client is actually put into a fullscreen state is subject to compositor + * policies. The client must also acknowledge the configure when + * committing the new content (see ack_configure). + * + * The output passed by the request indicates the client's preference as + * to which display it should be set fullscreen on. If this value is NULL, + * it's up to the compositor to choose which display will be used to map + * this surface. + * + * If the surface doesn't cover the whole output, the compositor will + * position the surface in the center of the output and compensate with + * with border fill covering the rest of the output. The content of the + * border fill is undefined, but should be assumed to be in some way that + * attempts to blend into the surrounding area (e.g. solid black). + * + * If the fullscreened surface is not opaque, the compositor must make + * sure that other screen content not part of the same surface tree (made + * up of subsurfaces, popups or similarly coupled surfaces) are not + * visible below the fullscreened surface. + */ +static inline void +xdg_toplevel_set_fullscreen(struct xdg_toplevel *xdg_toplevel, struct wl_output *output) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, output); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Make the surface no longer fullscreen. + * + * After requesting that the surface should be unfullscreened, the + * compositor will respond by emitting a configure event. + * Whether this actually removes the fullscreen state of the client is + * subject to compositor policies. + * + * Making a surface unfullscreen sets states for the surface based on the following: + * * the state(s) it may have had before becoming fullscreen + * * any state(s) decided by the compositor + * * any state(s) requested by the client while the surface was fullscreen + * + * The compositor may include the previous window geometry dimensions in + * the configure event, if applicable. + * + * The client must also acknowledge the configure when committing the new + * content (see ack_configure). + */ +static inline void +xdg_toplevel_unset_fullscreen(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_UNSET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Request that the compositor minimize your surface. There is no + * way to know if the surface is currently minimized, nor is there + * any way to unset minimization on this surface. + * + * If you are looking to throttle redrawing when minimized, please + * instead use the wl_surface.frame event for this, as this will + * also work with live previews on windows in Alt-Tab, Expose or + * similar compositor features. + */ +static inline void +xdg_toplevel_set_minimized(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MINIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0); +} + +#ifndef XDG_POPUP_ERROR_ENUM +#define XDG_POPUP_ERROR_ENUM +enum xdg_popup_error { + /** + * tried to grab after being mapped + */ + XDG_POPUP_ERROR_INVALID_GRAB = 0, +}; +#endif /* XDG_POPUP_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_popup + * @struct xdg_popup_listener + */ +struct xdg_popup_listener { + /** + * configure the popup surface + * + * This event asks the popup surface to configure itself given + * the configuration. The configured state should not be applied + * immediately. See xdg_surface.configure for details. + * + * The x and y arguments represent the position the popup was + * placed at given the xdg_positioner rule, relative to the upper + * left corner of the window geometry of the parent surface. + * + * For version 2 or older, the configure event for an xdg_popup is + * only ever sent once for the initial configuration. Starting with + * version 3, it may be sent again if the popup is setup with an + * xdg_positioner with set_reactive requested, or in response to + * xdg_popup.reposition requests. + * @param x x position relative to parent surface window geometry + * @param y y position relative to parent surface window geometry + * @param width window geometry width + * @param height window geometry height + */ + void (*configure)(void *data, + struct xdg_popup *xdg_popup, + int32_t x, + int32_t y, + int32_t width, + int32_t height); + /** + * popup interaction is done + * + * The popup_done event is sent out when a popup is dismissed by + * the compositor. The client should destroy the xdg_popup object + * at this point. + */ + void (*popup_done)(void *data, + struct xdg_popup *xdg_popup); + /** + * signal the completion of a repositioned request + * + * The repositioned event is sent as part of a popup + * configuration sequence, together with xdg_popup.configure and + * lastly xdg_surface.configure to notify the completion of a + * reposition request. + * + * The repositioned event is to notify about the completion of a + * xdg_popup.reposition request. The token argument is the token + * passed in the xdg_popup.reposition request. + * + * Immediately after this event is emitted, xdg_popup.configure and + * xdg_surface.configure will be sent with the updated size and + * position, as well as a new configure serial. + * + * The client should optionally update the content of the popup, + * but must acknowledge the new popup configuration for the new + * position to take effect. See xdg_surface.ack_configure for + * details. + * @param token reposition request token + * @since 3 + */ + void (*repositioned)(void *data, + struct xdg_popup *xdg_popup, + uint32_t token); +}; + +/** + * @ingroup iface_xdg_popup + */ +static inline int +xdg_popup_add_listener(struct xdg_popup *xdg_popup, + const struct xdg_popup_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_popup, + (void (**)(void)) listener, data); +} + +#define XDG_POPUP_DESTROY 0 +#define XDG_POPUP_GRAB 1 +#define XDG_POPUP_REPOSITION 2 + +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_POPUP_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_REPOSITIONED_SINCE_VERSION 3 + +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_GRAB_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_REPOSITION_SINCE_VERSION 3 + +/** @ingroup iface_xdg_popup */ +static inline void +xdg_popup_set_user_data(struct xdg_popup *xdg_popup, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_popup, user_data); +} + +/** @ingroup iface_xdg_popup */ +static inline void * +xdg_popup_get_user_data(struct xdg_popup *xdg_popup) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_popup); +} + +static inline uint32_t +xdg_popup_get_version(struct xdg_popup *xdg_popup) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_popup); +} + +/** + * @ingroup iface_xdg_popup + * + * This destroys the popup. Explicitly destroying the xdg_popup + * object will also dismiss the popup, and unmap the surface. + * + * If this xdg_popup is not the "topmost" popup, the + * xdg_wm_base.not_the_topmost_popup protocol error will be sent. + */ +static inline void +xdg_popup_destroy(struct xdg_popup *xdg_popup) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup, + XDG_POPUP_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_xdg_popup + * + * This request makes the created popup take an explicit grab. An explicit + * grab will be dismissed when the user dismisses the popup, or when the + * client destroys the xdg_popup. This can be done by the user clicking + * outside the surface, using the keyboard, or even locking the screen + * through closing the lid or a timeout. + * + * If the compositor denies the grab, the popup will be immediately + * dismissed. + * + * This request must be used in response to some sort of user action like a + * button press, key press, or touch down event. The serial number of the + * event should be passed as 'serial'. + * + * The parent of a grabbing popup must either be an xdg_toplevel surface or + * another xdg_popup with an explicit grab. If the parent is another + * xdg_popup it means that the popups are nested, with this popup now being + * the topmost popup. + * + * Nested popups must be destroyed in the reverse order they were created + * in, e.g. the only popup you are allowed to destroy at all times is the + * topmost one. + * + * When compositors choose to dismiss a popup, they may dismiss every + * nested grabbing popup as well. When a compositor dismisses popups, it + * will follow the same dismissing order as required from the client. + * + * If the topmost grabbing popup is destroyed, the grab will be returned to + * the parent of the popup, if that parent previously had an explicit grab. + * + * If the parent is a grabbing popup which has already been dismissed, this + * popup will be immediately dismissed. If the parent is a popup that did + * not take an explicit grab, an error will be raised. + * + * During a popup grab, the client owning the grab will receive pointer + * and touch events for all their surfaces as normal (similar to an + * "owner-events" grab in X11 parlance), while the top most grabbing popup + * will always have keyboard focus. + */ +static inline void +xdg_popup_grab(struct xdg_popup *xdg_popup, struct wl_seat *seat, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup, + XDG_POPUP_GRAB, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), 0, seat, serial); +} + +/** + * @ingroup iface_xdg_popup + * + * Reposition an already-mapped popup. The popup will be placed given the + * details in the passed xdg_positioner object, and a + * xdg_popup.repositioned followed by xdg_popup.configure and + * xdg_surface.configure will be emitted in response. Any parameters set + * by the previous positioner will be discarded. + * + * The passed token will be sent in the corresponding + * xdg_popup.repositioned event. The new popup position will not take + * effect until the corresponding configure event is acknowledged by the + * client. See xdg_popup.repositioned for details. The token itself is + * opaque, and has no other special meaning. + * + * If multiple reposition requests are sent, the compositor may skip all + * but the last one. + * + * If the popup is repositioned in response to a configure event for its + * parent, the client should send an xdg_positioner.set_parent_configure + * and possibly an xdg_positioner.set_parent_size request to allow the + * compositor to properly constrain the popup. + * + * If the popup is repositioned together with a parent that is being + * resized, but not in response to a configure event, the client should + * send an xdg_positioner.set_parent_size request. + */ +static inline void +xdg_popup_reposition(struct xdg_popup *xdg_popup, struct xdg_positioner *positioner, uint32_t token) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup, + XDG_POPUP_REPOSITION, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), 0, positioner, token); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/wayland/java/WindowWayland.java b/wayland/java/WindowWayland.java index 0fa0ce65..53832795 100644 --- a/wayland/java/WindowWayland.java +++ b/wayland/java/WindowWayland.java @@ -31,13 +31,15 @@ public void unmarkText() { @Override public IRect getWindowRect() { assert _onUIThread() : "Should be run on UI thread"; - return _nGetWindowRect(); + // very very bad! + return IRect.makeXYWH(0, 0, 0, 0); } @Override public IRect getContentRect() { assert _onUIThread() : "Should be run on UI thread"; - return _nGetContentRect(); + // stop! + return IRect.makeXYWH(0, 0, 0, 0); } @Override @@ -118,7 +120,7 @@ public float getOpacity(){ @Override public Screen getScreen() { assert _onUIThread() : "Should be run on UI thread"; - return _nGetScreen(); + return new Screen(0, false, IRect.makeXYWH(0, 0, 0, 0), IRect.makeXYWH(0, 0, 0, 0), 1); } @Override @@ -214,6 +216,12 @@ public boolean isFullScreen() { return _nIsFullScreen(); } + @Override + public float getScale() { + assert _onUIThread() : "Should be run on UI Thread"; + return _nGetScale(); + } + @ApiStatus.Internal public static native long _nMake(); @ApiStatus.Internal public native void _nSetVisible(boolean isVisible); @ApiStatus.Internal public native IRect _nGetWindowRect(); @@ -222,7 +230,7 @@ public boolean isFullScreen() { // @ApiStatus.Internal public native void _nSetWindowSize(int width, int height); @ApiStatus.Internal public native void _nSetMouseCursor(int cursorId); // @ApiStatus.Internal public native void _nSetContentSize(int width, int height); - @ApiStatus.Internal public native Screen _nGetScreen(); + // @ApiStatus.Internal public native Screen _nGetScreen(); @ApiStatus.Internal public native void _nRequestFrame(); @ApiStatus.Internal public native void _nClose(); @ApiStatus.Internal public native void _nMaximize(); @@ -232,4 +240,5 @@ public boolean isFullScreen() { @ApiStatus.Internal public native void _nSetTitlebarVisible(boolean isVisible); @ApiStatus.Internal public native void _nSetFullScreen(boolean isFullScreen); @ApiStatus.Internal public native boolean _nIsFullScreen(); + @ApiStatus.Internal public native float _nGetScale(); } diff --git a/windows/java/WindowWin32.java b/windows/java/WindowWin32.java index 1379268e..496d97e7 100644 --- a/windows/java/WindowWin32.java +++ b/windows/java/WindowWin32.java @@ -172,7 +172,10 @@ public Window bringToFront() { _nBringToFront(); return this; } - + + public float getScale() { + return this.getScreen().getScale(); + } @Override public boolean isFront() { assert _onUIThread() : "Should be run on UI thread"; diff --git a/x11/CMakeLists.txt b/x11/CMakeLists.txt index e50d48e5..2157bd4b 100644 --- a/x11/CMakeLists.txt +++ b/x11/CMakeLists.txt @@ -18,7 +18,9 @@ endif() find_package(X11 REQUIRED) find_package(OpenGL REQUIRED) -file(GLOB SOURCES_CXX ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/*.cc ${CMAKE_CURRENT_LIST_DIR}/cc/*.cc) +file(GLOB SOURCES_CXX ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/*.cc + ${CMAKE_CURRENT_LIST_DIR}/cc/*.cc + ${CMAKE_CURRENT_LIST_DIR}/../linux/cc/*.cc) file(GLOB SOURCES_CXX_IMPL ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/impl/*.cc) add_library(jwm SHARED ${SOURCES_OBJC} ${SOURCES_CXX} ${SOURCES_CXX_IMPL}) @@ -33,7 +35,7 @@ if (NOT JAVA_HOME) endif() endif() -target_include_directories(jwm PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../shared/cc ../linux/cc ${JAVA_HOME}/include ${JAVA_HOME}/include/linux) +target_include_directories(jwm PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../shared/cc ${CMAKE_CURRENT_LIST_DIR}/../linux/cc ${JAVA_HOME}/include ${JAVA_HOME}/include/linux) set_target_properties(jwm PROPERTIES OUTPUT_NAME "jwm_${JWM_ARCH}") diff --git a/linux/cc/ScreenInfo.cc b/x11/cc/ScreenInfo.cc similarity index 99% rename from linux/cc/ScreenInfo.cc rename to x11/cc/ScreenInfo.cc index f3aa1dee..f1e56dc2 100644 --- a/linux/cc/ScreenInfo.cc +++ b/x11/cc/ScreenInfo.cc @@ -1,7 +1,6 @@ #include "ScreenInfo.hh" #include "AppX11.hh" - jobject jwm::ScreenInfo::asJavaObject(JNIEnv* env) const { return jwm::classes::Screen::make(env, id, isPrimary, bounds, bounds, jwm::app.getScale()); } diff --git a/x11/cc/ScreenInfo.hh b/x11/cc/ScreenInfo.hh new file mode 100644 index 00000000..947890a3 --- /dev/null +++ b/x11/cc/ScreenInfo.hh @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace jwm +{ + struct ScreenInfo { + long id; + IRect bounds; + bool isPrimary; + jobject asJavaObject(JNIEnv* env) const; + }; +} // namespace jwm diff --git a/x11/cc/WindowX11.cc b/x11/cc/WindowX11.cc index c73fba04..4c2605f2 100644 --- a/x11/cc/WindowX11.cc +++ b/x11/cc/WindowX11.cc @@ -338,9 +338,6 @@ int WindowX11::getHeight() { return _height; } -float WindowX11::getScale() { - return jwm::app.getScale(); -} bool WindowX11::init() { @@ -585,3 +582,8 @@ extern "C" JNIEXPORT jboolean JNICALL Java_io_github_humbleui_jwm_WindowX11__1nI jwm::WindowX11* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); return instance->isFullScreen(); } + +extern "C" JNIEXPORT jfloat JNICALL Java_io_github_humbleui_jwm_WindowX11__1nGetScale + (JNIEnv* env, jobject obj) { + return jwm::app.getScale(); +} diff --git a/x11/cc/WindowX11.hh b/x11/cc/WindowX11.hh index 55f5befe..e2fc7ea0 100644 --- a/x11/cc/WindowX11.hh +++ b/x11/cc/WindowX11.hh @@ -24,7 +24,7 @@ namespace jwm { int getTop(); int getWidth(); int getHeight(); - float getScale(); + void move(int left, int top); void resize(int width, int height); void requestRedraw() { diff --git a/x11/java/WindowX11.java b/x11/java/WindowX11.java index d60e0502..bc865777 100644 --- a/x11/java/WindowX11.java +++ b/x11/java/WindowX11.java @@ -211,6 +211,11 @@ public boolean isFullScreen() { return _nIsFullScreen(); } + @Override + public float getScale() { + return ; + } + @ApiStatus.Internal public static native long _nMake(); @ApiStatus.Internal public native void _nSetVisible(boolean isVisible); @ApiStatus.Internal public native IRect _nGetWindowRect(); @@ -229,4 +234,5 @@ public boolean isFullScreen() { @ApiStatus.Internal public native void _nSetTitlebarVisible(boolean isVisible); @ApiStatus.Internal public native void _nSetFullScreen(boolean isFullScreen); @ApiStatus.Internal public native boolean _nIsFullScreen(); + @ApiStatus.Internal public native float _nGetScale(); } From a10db21651ee0097d6af862dbbede917ec269625 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Sat, 2 Dec 2023 20:11:39 -0500 Subject: [PATCH 03/93] OH MY, SO MANY CHANGES --- linux/cc/ILayer.hh | 1 + script/build.py | 11 ++- script/clean.py | 8 +- script/run.py | 14 ++- shared/java/Layer.java | 2 +- shared/java/LayerGL.java | 2 +- shared/java/Platform.java | 10 +- shared/java/impl/Library.java | 5 +- wayland/CMakeLists.txt | 20 ++-- wayland/cc/AppWayland.cc | 2 +- wayland/cc/ClipboardWayland.cc | 2 +- wayland/cc/KeyWayland.cc | 16 ++-- wayland/cc/LayerGLWayland.cc | 16 +++- wayland/cc/LayerRasterWayland.cc | 15 +-- wayland/cc/ScreenInfo.cc | 4 +- wayland/cc/ShmPool.cc | 13 +-- wayland/cc/WindowManagerWayland.cc | 128 +++++++++++++++++--------- wayland/cc/WindowManagerWayland.hh | 20 ++-- wayland/cc/WindowWayland.cc | 143 +++++++++++++++++++++-------- wayland/cc/WindowWayland.hh | 39 +++++--- wayland/java/WindowWayland.java | 8 +- x11/CMakeLists.txt | 4 +- x11/cc/KeyX11.cc | 2 +- x11/cc/LayerGLX11.cc | 4 +- x11/cc/LayerRasterX11.cc | 4 +- x11/java/WindowX11.java | 3 +- 26 files changed, 328 insertions(+), 168 deletions(-) diff --git a/linux/cc/ILayer.hh b/linux/cc/ILayer.hh index 81a32c2b..f21346a4 100644 --- a/linux/cc/ILayer.hh +++ b/linux/cc/ILayer.hh @@ -15,6 +15,7 @@ public: virtual void makeCurrentForced(); virtual void setVsyncMode(VSync v) = 0; virtual void close() = 0; + virtual void resize(int width, int height); static ILayer* _ourCurrentLayer; diff --git a/script/build.py b/script/build.py index ec528e66..9954d826 100755 --- a/script/build.py +++ b/script/build.py @@ -19,6 +19,9 @@ def build_native_system(system): if os.path.exists('build/libjwm_x64.so'): build_utils.copy_newer('build/libjwm_x64.so', '../target/classes/libjwm_x64.so') + + if os.path.exists('build/libjwm_x64_wayland.so'): + build_utils.copy_newer('build/libjwm_x64_wayland.so', '../target/classes/libjwm_x64_wayland.so') if os.path.exists('build/jwm_x64.dll'): build_utils.copy_newer('build/jwm_x64.dll', '../target/classes/jwm_x64.dll') @@ -34,8 +37,12 @@ def build_native(): return 0 def build_java(): os.chdir(common.basedir) - sources = build_utils.files("x11/java/**/*.java", "macos/java/**/*.java", "shared/java/**/*.java", "windows/java/**/*.java",) - build_utils.javac(sources, "target/classes", classpath=common.deps_compile()) + sources = build_utils.files("x11/java/**/*.java", + "macos/java/**/*.java", + "shared/java/**/*.java", + "windows/java/**/*.java", + "wayland/java/**/*.java") + build_utils.javac(sources, "target/classes", classpath=common.deps_compile(), release="16") return 0 def main(): diff --git a/script/clean.py b/script/clean.py index 77a3870b..db328a9b 100755 --- a/script/clean.py +++ b/script/clean.py @@ -4,9 +4,13 @@ def main(): os.chdir(common.basedir) build_utils.rmdir("target") - build_utils.rmdir(build_utils.system + "/build") + if build_utils.system == "linux": + build_utils.rmdir("wayland/build") + build_utils.rmdir("x11/build") + else: + build_utils.rmdir(build_utils.system + "/build") build_utils.rmdir("examples/dashboard/target") return 0 if __name__ == '__main__': - sys.exit(main()) \ No newline at end of file + sys.exit(main()) diff --git a/script/run.py b/script/run.py index d4a282ef..98f3c0ee 100755 --- a/script/run.py +++ b/script/run.py @@ -32,9 +32,17 @@ def main(): ] else: classpath += [ - 'target/classes', - build_utils.system + '/build' - ] + 'target/classes' + ] + if build_utils.system == "linux": + classpath += [ + "wayland/build", + "x11/build" + ] + else: + classpath += [ + build_utils.system + '/build' + ] if args.skija_dir: classpath += [ diff --git a/shared/java/Layer.java b/shared/java/Layer.java index c3931abd..7099f9ba 100644 --- a/shared/java/Layer.java +++ b/shared/java/Layer.java @@ -47,4 +47,4 @@ default void swapBuffers() {} @Override default void close() {} -} \ No newline at end of file +} diff --git a/shared/java/LayerGL.java b/shared/java/LayerGL.java index 75aabb57..5162c70a 100644 --- a/shared/java/LayerGL.java +++ b/shared/java/LayerGL.java @@ -75,4 +75,4 @@ public void close() { @ApiStatus.Internal public native void _nResize(int width, int height); @ApiStatus.Internal public native void _nSwapBuffers(); @ApiStatus.Internal public native void _nClose(); -} \ No newline at end of file +} diff --git a/shared/java/Platform.java b/shared/java/Platform.java index 737fcaa8..cf923704 100644 --- a/shared/java/Platform.java +++ b/shared/java/Platform.java @@ -3,7 +3,8 @@ public enum Platform { WINDOWS, X11, - MACOS; + MACOS, + WAYLAND; public static final Platform CURRENT; static { @@ -13,8 +14,11 @@ public enum Platform { else if (os.contains("windows")) CURRENT = WINDOWS; else if (os.contains("nux") || os.contains("nix")) - CURRENT = X11; + if (System.getenv("WAYLAND_DISPLAY") != null) + CURRENT = WAYLAND; + else + CURRENT = X11; else throw new RuntimeException("Unsupported platform: " + os); } -} \ No newline at end of file +} diff --git a/shared/java/impl/Library.java b/shared/java/impl/Library.java index 7104fc59..43fd5cbc 100644 --- a/shared/java/impl/Library.java +++ b/shared/java/impl/Library.java @@ -46,7 +46,10 @@ public static synchronized void load() { } else if (Platform.CURRENT == Platform.X11) { File library = _extract("/", "libjwm_x64.so", tempDir); System.load(library.getAbsolutePath()); - } + } /*else if (Platform.CURRENT == Platform.WAYLAND) { + File library = _extract("/", "libjwm_x64_wayland.so", tempDir); + System.load(library.getAbsolutePath()); + }*/ if (tempDir.exists() && version == null) { Runtime.getRuntime().addShutdownHook(new Thread(() -> { diff --git a/wayland/CMakeLists.txt b/wayland/CMakeLists.txt index 8af35a72..95ca0ad2 100644 --- a/wayland/CMakeLists.txt +++ b/wayland/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.9) cmake_policy(SET CMP0072 NEW) project(jwm LANGUAGES CXX) -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) if(NOT JWM_ARCH) @@ -16,9 +16,16 @@ if(NOT JWM_ARCH) endif() file(GLOB SOURCES_CXX ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/*.cc - ${CMAKE_CURRENT_LIST_DIR}/cc/*.cc ${CMAKE_CURRENT_LIST_DIR}/../linux/cc/*.cc) + ${CMAKE_CURRENT_LIST_DIR}/../linux/cc/*.cc + ${CMAKE_CURRENT_LIST_DIR}/cc/*.cc ) file(GLOB SOURCES_CXX_IMPL ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/impl/*.cc) add_library(jwm SHARED ${SOURCES_OBJC} ${SOURCES_CXX} ${SOURCES_CXX_IMPL}) +find_library(WAYLAND_CLIENT_LIB wayland-client) +find_library(DECOR_LIB decor-0) +find_library(WAYLAND_CURSOR wayland-cursor) +find_library(XKBCOMMON xkbcommon) +find_library(EGL EGL) +find_library(WAYLAND_EGL wayland-egl) set(JAVA_HOME $ENV{JAVA_HOME}) if (NOT JAVA_HOME) @@ -32,9 +39,8 @@ if (NOT JAVA_HOME) endif() target_include_directories(jwm PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../shared/cc ${CMAKE_CURRENT_LIST_DIR}/../linux/cc ${JAVA_HOME}/include ${JAVA_HOME}/include/linux) -set_target_properties(jwm PROPERTIES OUTPUT_NAME "jwm_${JWM_ARCH}") +set_target_properties(jwm PROPERTIES OUTPUT_NAME "jwm_${JWM_ARCH}_wayland") - -target_link_libraries(jwm PRIVATE wayland-client, decor, - wayland-cursor, xkbcommon) -target_link_libraries(jwm PRIVATE EGL, wayland-egl) +target_link_libraries(jwm PRIVATE ${WAYLAND_CLIENT_LIB} ${DECOR_LIB} + ${WAYLAND_CURSOR} ${XKBCOMMON}) +target_link_libraries(jwm PRIVATE ${EGL} ${WAYLAND_EGL}) diff --git a/wayland/cc/AppWayland.cc b/wayland/cc/AppWayland.cc index dc075681..326963c0 100644 --- a/wayland/cc/AppWayland.cc +++ b/wayland/cc/AppWayland.cc @@ -45,7 +45,7 @@ extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_App__1nRunOnUIThre } // how awful -extern "C" JNIEXPORT jobjectArray JNICALL Java_io_github_humbleui_jwm_App__1nGetScreens(JNIEnv env*, jobject cls) noexcept { +extern "C" JNIEXPORT jobjectArray JNICALL Java_io_github_humbleui_jwm_App__1nGetScreens(JNIEnv* env, jobject cls) noexcept { jobjectArray array = env->NewObjectArray(0, jwm::classes::Screen::kCls, 0); return array; diff --git a/wayland/cc/ClipboardWayland.cc b/wayland/cc/ClipboardWayland.cc index c32b1b51..0d02345a 100644 --- a/wayland/cc/ClipboardWayland.cc +++ b/wayland/cc/ClipboardWayland.cc @@ -35,7 +35,7 @@ namespace jwm { */ // impl me : ) jobjectArray formats = env->NewObjectArray(0, classes::ClipboardFormat::kCls, nullptr); - return format; + return formats; } jobject get(JNIEnv* env, jobjectArray formats) { diff --git a/wayland/cc/KeyWayland.cc b/wayland/cc/KeyWayland.cc index 026e31c6..7a16be98 100644 --- a/wayland/cc/KeyWayland.cc +++ b/wayland/cc/KeyWayland.cc @@ -1,14 +1,14 @@ #include "KeyWayland.hh" #include "KeyModifier.hh" -bool gKeyStates[(size_t) jwm::Key::_KEY_COUNT] = {0}; +bool gKeyStates[(std::size_t) jwm::Key::_KEY_COUNT] = {0}; bool jwm::KeyWayland::getKeyState(jwm::Key key) { - return gKeyStates[(size_t) key]; + return gKeyStates[(std::size_t) key]; } void jwm::KeyWayland::setKeyState(jwm::Key key, bool isDown) { - gKeyStates[(size_t) key] = isDown; + gKeyStates[(std::size_t) key] = isDown; } int jwm::KeyWayland::getModifiers() { @@ -25,10 +25,10 @@ int jwm::KeyWayland::getModifiers() { int jwm::KeyWayland::getModifiersFromMask(int mask) { int m = getModifiers(); - - if (mask & ShiftMask ) m |= (int)jwm::KeyModifier::SHIFT; - if (mask & ControlMask) m |= (int)jwm::KeyModifier::CONTROL; - if (mask & Mod1Mask ) m |= (int)jwm::KeyModifier::ALT; + // ??? + // if (mask & ShiftMask ) m |= (int)jwm::KeyModifier::SHIFT; + // if (mask & ControlMask) m |= (int)jwm::KeyModifier::CONTROL; + // if (mask & Mod1Mask ) m |= (int)jwm::KeyModifier::ALT; return m; } @@ -171,5 +171,5 @@ jwm::Key jwm::KeyWayland::fromNative(uint32_t v) { /* default: return Key::UNDEFINED; } */ // IMPL ME! - return Key::UNDEFINED: + return Key::UNDEFINED; } diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index e8b96960..8e3f2ee2 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -5,6 +5,7 @@ #include "impl/RefCounted.hh" #include "WindowWayland.hh" #include +#include #include namespace jwm { @@ -17,14 +18,19 @@ namespace jwm { EGLDisplay _display = nullptr; EGLSurface _surface = nullptr; - LayerGLWayland() = default; - virtual ~LayerGLWayland() = default; + LayerGL() = default; + virtual ~LayerGL() = default; void attach(WindowWayland* window) { fWindow = jwm::ref(window); + if (window->_layer) { + // HACK: close window and reopen + window->close(); + window->init(); + } fWindow->setLayer(this); if (_display == nullptr) { - _display = eglGetPlatformDisplayEXT(EGL_PLATFORM_WAYLAND_KHR, window->_windowManager.display, EGL_NONE); + _display = eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_KHR, window->_windowManager.display, nullptr); eglInitialize(_display, nullptr, nullptr); @@ -58,7 +64,7 @@ namespace jwm { // vsync? what vsync? } - void resize(int width, int height) { + void resize(int width, int height) override { glClearStencil(0); glClearColor(0, 0, 0, 255); glStencilMask(0xffffffff); @@ -70,7 +76,7 @@ namespace jwm { } void swapBuffers() { - eglSwapBuffers(fWindow->_windowManager.getDisplay(), _surface); + eglSwapBuffers(_display, _surface); } void close() override { diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index f656709b..0462940e 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -5,6 +5,8 @@ #include "impl/RefCounted.hh" #include "WindowWayland.hh" #include "ShmPool.hh" +#include + namespace jwm { class LayerRaster: public RefCounted, public ILayer { public: @@ -12,7 +14,7 @@ namespace jwm { size_t _width = 0, _height = 0; wl_buffer* _buffer = nullptr; uint8_t* _imageData = nullptr; - ShmPool _pool = nullptr; + ShmPool* _pool = nullptr; VSync _vsync = VSYNC_ENABLED; LayerRaster() = default; @@ -23,17 +25,17 @@ namespace jwm { fWindow->setLayer(this); } - void resize(int width, int height) { + void resize(int width, int height) override { wl_display* d = fWindow->_windowManager.display; _width = width; _height = height; int bufSize = width * height * sizeof(uint32_t) * 2; if (!_pool) { - _pool = new ShmPool(fWindow->_windowManager->shm, bufSize); + _pool = new ShmPool(fWindow->_windowManager.shm, bufSize); } - _pool.grow(bufSize); + _pool->grow(bufSize); // LSBFirst means Little endian : ) - auto buf = _pool.createBuffer(0, width, height, width * sizeof(uint32_t), WL_SHM_FORMAT_ABRG8888); + auto buf = _pool->createBuffer(0, width, height, width * sizeof(uint32_t), WL_SHM_FORMAT_ABGR8888); _buffer = buf.first; _imageData = buf.second; @@ -58,7 +60,8 @@ namespace jwm { wl_buffer_destroy(_buffer); _buffer = nullptr; } - destroy _pool; + // ??? + // destroy _pool; jwm::unref(&fWindow); } diff --git a/wayland/cc/ScreenInfo.cc b/wayland/cc/ScreenInfo.cc index a7392e40..3dddf554 100644 --- a/wayland/cc/ScreenInfo.cc +++ b/wayland/cc/ScreenInfo.cc @@ -1,5 +1,5 @@ #include "ScreenInfo.hh" - +#include "AppWayland.hh" jobject jwm::ScreenInfo::asJavaObject(JNIEnv* env) const { - return jwm::classes::Screen::make(env, id, isPrimary, bounds, bounds, jwm::app.getScale()); + return jwm::classes::Screen::make(env, id, isPrimary, bounds, bounds, 1.0f); } diff --git a/wayland/cc/ShmPool.cc b/wayland/cc/ShmPool.cc index e2a3a334..0f42ed50 100644 --- a/wayland/cc/ShmPool.cc +++ b/wayland/cc/ShmPool.cc @@ -4,6 +4,7 @@ #include #include #include +#include using namespace jwm; @@ -22,10 +23,10 @@ ShmPool::ShmPool(wl_shm* shm, size_t size): _fd = _allocateShmFile(size); if (_fd < 0) { // why : ( - throw std::system_error(EIO, "Couldn't allocate buffer"); + throw std::system_error(EIO, std::generic_category(), "Couldn't allocate buffer"); } _pool = wl_shm_create_pool(shm, _fd, size); - _rawData = mmap(nullptr, size, + _rawData = (uint8_t*)mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0); } @@ -43,9 +44,9 @@ void ShmPool::grow(size_t size) { } while (ret < 0 && errno == EINTR); if (ret < 0) { // AAHHHHH! - throw std::system_error(EIO, "Couldn't grow buffer"); + throw std::system_error(EIO, std::generic_category(), "Couldn't grow buffer"); } - uint8_t* newData = mmap(nullptr, size, + uint8_t* newData = (uint8_t*)mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0); // do I need to memcpy??? lets say no :troll: // TODO: error checking :troll: @@ -85,8 +86,8 @@ int ShmPool::_allocateShmFile(size_t size) { return fd; } -std::pair createBuffer(int offset, int width, int height, int stride, uint32_t format) { +std::pair ShmPool::createBuffer(int offset, int width, int height, int stride, uint32_t format) { wl_buffer* buffer = wl_shm_pool_create_buffer(_pool, offset, width, height, stride, format); - uint32_t* data = &_rawData[offset]; + uint8_t* data = &_rawData[offset]; return std::pair(buffer, data); } diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index a86f4650..2c629633 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -17,6 +17,7 @@ #include "xdg-shell.hh" #include + using namespace jwm; @@ -24,17 +25,17 @@ WindowManagerWayland::WindowManagerWayland(): display(wl_display_connect(nullptr)) { registry = wl_display_get_registry(display); wl_registry_listener registry_listener = { - .global = registryGlobalHandler, - .global_remove = registryGlobalHandlerRemove + .global = WindowManagerWayland::registryHandleGlobal, + .global_remove = WindowManagerWayland::registryHandleGlobalRemove }; - wl_registry_add_listener(registry, ®istry_listener, nullptr); + wl_registry_add_listener(registry, ®istry_listener, this); wl_display_roundtrip(display); if (!(shm && xdgShell && compositor && deviceManager && seat)) { // ??? // Bad. Means our compositor no supportie : ( - throw std::system_error(1, std::system_category); + throw std::system_error(ENOTSUP, std::generic_category(), "Unsupported compositor"); } @@ -46,7 +47,7 @@ WindowManagerWayland::WindowManagerWayland(): wl_cursor* cursor = wl_cursor_theme_get_cursor(cursor_theme, name); wl_cursor_image* cursorImage = cursor->images[0]; return cursorImage; - } + }; _cursors[static_cast(jwm::MouseCursor::ARROW )] = loadCursor("default"); _cursors[static_cast(jwm::MouseCursor::CROSSHAIR )] = loadCursor("crosshair"); @@ -63,20 +64,20 @@ WindowManagerWayland::WindowManagerWayland(): cursorSurface = wl_compositor_create_surface(compositor); wl_surface_attach(cursorSurface, - wl_cursor_get_image_buffer(_cursors[static_cast(jwm::MouseCursor::ARROW)]), 0, 0); + wl_cursor_image_get_buffer(_cursors[static_cast(jwm::MouseCursor::ARROW)]), 0, 0); wl_surface_commit(cursorSurface); } { pointer = wl_seat_get_pointer(seat); wl_pointer_listener pointerListener = { - .enter = pointerHandleEnter, - .leave = pointerHandleLeave, - .motion = pointerHandleMotion, - .button = pointerHandleButton, - .axis = pointerHandleAxis + .enter = WindowManagerWayland::pointerHandleEnter, + .leave = WindowManagerWayland::pointerHandleLeave, + .motion = WindowManagerWayland::pointerHandleMotion, + .button = WindowManagerWayland::pointerHandleButton, + .axis = WindowManagerWayland::pointerHandleAxis }; - wl_pointer_add_listener(pointer, &pointerListener, nullptr); + wl_pointer_add_listener(pointer, &pointerListener, this); } @@ -88,10 +89,37 @@ WindowManagerWayland::WindowManagerWayland(): void WindowManagerWayland::runLoop() { _runLoop = true; + int pipes[2]; + char buf[100]; + if (pipe(pipes)) { + printf("failed to open pipe\n"); + return; + } + notifyFD = pipes[1]; + fcntl(pipes[1], F_SETFL, O_NONBLOCK); // notifyLoop no blockie : ) + struct pollfd myPoll = {.fd=pipes[0], .events=POLLIN}; // who be out here running they loop while (_runLoop) { + if (jwm::classes::Throwable::exceptionThrown(app.getJniEnv())) + _runLoop = false; + _processCallbacks(); + + // block until event : ) + if (poll(&myPoll, 1, -1) < 0) { + printf("error with pipe\n"); + break; + } + + if (myPoll.revents & POLLIN) { + while (read(pipes[0], buf, sizeof(buf) == sizeof(buf))) {} + } + notifyBool.store(false); } + + notifyFD = -1; + close(pipes[0]); + close(pipes[1]); } @@ -110,7 +138,7 @@ void WindowManagerWayland::_processCallbacks() { } { // copy window list in case one closes any other, invalidating some iterator in _nativeWindowToMy - std::vector copy; + std::vector copy; for (auto& p : _nativeWindowToMy) { copy.push_back(p.second); } @@ -129,20 +157,21 @@ void WindowManagerWayland::_processCallbacks() { void WindowManagerWayland::registryHandleGlobal(void* data, wl_registry *registry, uint32_t name, const char* interface, uint32_t version) { + WindowManagerWayland* self = (WindowManagerWayland*)data; if (strcmp(interface, "wl_compositor") == 0) { - compositor = (wl_compositor*)wl_registry_bind(registry, name, + self->compositor = (wl_compositor*)wl_registry_bind(registry, name, &wl_compositor_interface, 3); } else if (strcmp(interface, "wl_shm") == 0) { - shm = (wl_shm*)wl_registry_bind(registry, name, + self->shm = (wl_shm*)wl_registry_bind(registry, name, &wl_shm_interface, 1); } else if (strcmp(interface, "xdg_wm_base") == 0) { - xdgShell = (xdg_wm_base*)wl_registry_bind(registry, name, - &xdg_wm_base_interface, 1); + self->xdgShell = (xdg_wm_base*)wl_registry_bind(registry, name, + &xdg_wm_base_interface, 2); } else if (strcmp(interface, "wl_data_device_manager") == 0) { - deviceManager = (wl_data_device_manager*)wl_registry_bind(registry, name, + self->deviceManager = (wl_data_device_manager*)wl_registry_bind(registry, name, &wl_data_device_manager_interface, 1); } else if (strcmp(interface, "wl_seat") == 0) { - seat = (wl_seat*)wl_registry_bind(registry, name, + self->seat = (wl_seat*)wl_registry_bind(registry, name, &wl_seat_interface, 1); } } @@ -152,61 +181,65 @@ void WindowManagerWayland::registryHandleGlobalRemove(void* data, wl_registry *r void WindowManagerWayland::pointerHandleEnter(void* data, wl_pointer* pointer, uint32_t serial, wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { - wl_cursor_image* image = _cursors[static_cast(jwm::MouseCursor::ARROW)]; - wl_pointer_set_cursor(cursor, serial, cursorSurface, image->hotspot_x, image->hotspot_y); - focusedSurface = surface; + WindowManagerWayland* self = (WindowManagerWayland*)data; + wl_cursor_image* image = self->_cursors[static_cast(jwm::MouseCursor::ARROW)]; + wl_pointer_set_cursor(pointer, serial, self->cursorSurface, image->hotspot_x, image->hotspot_y); + self->focusedSurface = surface; } void WindowManagerWayland::pointerHandleLeave(void* data, wl_pointer* pointer, uint32_t serial, wl_surface *surface) { - focusedSurface = nullptr; + WindowManagerWayland* self = (WindowManagerWayland*)data; + self->focusedSurface = nullptr; // ??? - mouseMask = 0; + self->mouseMask = 0; } void WindowManagerWayland::pointerHandleMotion(void* data, wl_pointer* pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { - lastMousePosX = surface_x; - lastMousePosY = surface_y; - if (focusedSurface) { - ::WindowWayland* window = _nativeWindowToMy.find(focusedSurface)->second; - mouseUpdate(window, wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y), mouseMask); + WindowManagerWayland* self = (WindowManagerWayland*)data; + self->lastMousePosX = surface_x; + self->lastMousePosY = surface_y; + if (self->focusedSurface) { + ::WindowWayland* window = self->_nativeWindowToMy.find(self->focusedSurface)->second; + self->mouseUpdate(window, wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y), self->mouseMask); } } void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { using namespace classes; + WindowManagerWayland* self = (WindowManagerWayland*)data; if (state == 0) { // release switch (button) { // primary case 0x110: - mouseMask &= ~0x100; + self->mouseMask &= ~0x100; break; // secondary case 0x111: - mouseMask &= ~0x400; + self->mouseMask &= ~0x400; break; // middle case 0x112: - mouseMask &= ~0x200; + self->mouseMask &= ~0x200; break; default: break; } - if (MouseButtonWayland::isButton(button) && focusedSurface) { + if (MouseButtonWayland::isButton(button) && self->focusedSurface) { jwm::JNILocal eventButton( app.getJniEnv(), EventMouseButton::make( app.getJniEnv(), MouseButtonWayland::fromNative(button), false, - lastMousePosX, - lastMousePosY, + self->lastMousePosX, + self->lastMousePosY, jwm::KeyWayland::getModifiers() ) ); - WindowWayland* window = _nativeWindowToMy.find(focusedSurface)->second; + WindowWayland* window = self->_nativeWindowToMy.find(self->focusedSurface)->second; window->dispatch(eventButton.get()); } } else { @@ -214,33 +247,33 @@ void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, switch (button) { // primary case 0x110: - mouseMask |= 0x100; + self->mouseMask |= 0x100; break; // secondary case 0x111: - mouseMask |= 0x400; + self->mouseMask |= 0x400; break; // middle case 0x112: - mouseMask |= 0x200; + self->mouseMask |= 0x200; break; default: break; } - if (MouseButtonWayland::isButton(button) && focusedSurface) { + if (MouseButtonWayland::isButton(button) && self->focusedSurface) { jwm::JNILocal eventButton( app.getJniEnv(), EventMouseButton::make( app.getJniEnv(), MouseButtonWayland::fromNative(button), true, - lastMousePosX, - lastMousePosY, + self->lastMousePosX, + self->lastMousePosY, jwm::KeyWayland::getModifiers() ) ); - WindowWayland* window = _nativeWindowToMy.find(focusedSurface)->second; + WindowWayland* window = self->_nativeWindowToMy.find(self->focusedSurface)->second; window->dispatch(eventButton.get()); } } @@ -412,3 +445,12 @@ void WindowManagerWayland::enqueueTask(const std::function& task) { _taskQueueNotify.notify_one(); notifyLoop(); } + +void WindowManagerWayland::notifyLoop() { + if (notifyFD==-1) return; + // fast notifyBool path to not make system calls when not necessary + if (!notifyBool.exchange(true)) { + char dummy[1] = {0}; + int unused = write(notifyFD, dummy, 1); // this really shouldn't fail, but if it does, the pipe should either be full (good), or dead (bad, but not our business) + } +} diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index 1dfe03ec..25cfed88 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -48,23 +48,25 @@ namespace jwm { return DefaultVisual(display, 0); } */ + void _processCallbacks(); + void notifyLoop(); void enqueueTask(const std::function& task); - void registryHandleGlobal(void* data, wl_registry *registry, + static void registryHandleGlobal(void* data, wl_registry *registry, uint32_t name, const char* interface, uint32_t version); - void registryHandleGlobalRemove(void* data, wl_registry *registry, + static void registryHandleGlobalRemove(void* data, wl_registry *registry, uint32_t name); - void pointerHandleEnter(void* data, wl_pointer *pointer, + static void pointerHandleEnter(void* data, wl_pointer *pointer, uint32_t serial, wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y); - void pointerHandleLeave(void* data, wl_pointer *pointer, + static void pointerHandleLeave(void* data, wl_pointer *pointer, uint32_t serial, wl_surface* surface); - void pointerHandleMotion(void* data, wl_pointer *pointer, + static void pointerHandleMotion(void* data, wl_pointer *pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y); - void pointerHandleButton(void* data, wl_pointer *pointer, + static void pointerHandleButton(void* data, wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state); - void pointerHandleAxis(void* data, wl_pointer *pointer, + static void pointerHandleAxis(void* data, wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value); @@ -72,8 +74,8 @@ namespace jwm { ByteBuf getClipboardContents(const std::string& type); std::vector getClipboardFormats(); - wl_display* display = nullptr - wl_registry* registry = nullptr + wl_display* display = nullptr; + wl_registry* registry = nullptr; wl_shm* shm = nullptr; xdg_wm_base* xdgShell = nullptr; wl_compositor* compositor = nullptr; diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index cc64c8cd..ecbd2a92 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -5,7 +5,6 @@ #include "AppWayland.hh" #include "impl/Library.hh" #include "impl/JNILocal.hh" -#include using namespace jwm; @@ -20,6 +19,7 @@ WindowWayland::~WindowWayland() { close(); } + void WindowWayland::setTitle(const std::string& title) { // impl me : ) } @@ -57,6 +57,11 @@ bool WindowWayland::isFullScreen() { void WindowWayland::getDecorations(int& left, int& top, int& right, int& bottom) { // impl me : ) + left = 0; + right = 0; + top = 0; + bottom = 0; + } void WindowWayland::getContentPosition(int& posX, int& posY) { @@ -86,40 +91,52 @@ int WindowWayland::getHeight() { } float WindowWayland::getScale() { - // TODO: use surface scaling - return jwm::app.getScale(); + return _scale; } bool WindowWayland::init() { _waylandWindow = wl_compositor_create_surface(_windowManager.compositor); - - xdgSurface = xdg_wm_base_get_xdg_surface(_windowManager.xdgShell, _waylandWindow); - xdgTopLevel = xdg_surface_get_toplevel(xdgSurface); + wl_surface_listener surfaceListener = { + .enter = WindowWayland::surfaceEnter, + .leave = WindowWayland::surfaceLeave, + .preferred_buffer_scale = WindowWayland::surfacePreferredBufferScale, + .preferred_buffer_transform = WindowWayland::surfacePreferredBufferTransform + }; + wl_surface_add_listener(_waylandWindow, &surfaceListener, this); + xdgSurface = xdg_wm_base_get_xdg_surface(_windowManager.xdgShell, _waylandWindow); + xdg_surface_listener xdgSurfaceListener = { + .configure = WindowWayland::xdgSurfaceConfigure + }; + xdg_surface_add_listener(xdgSurface, &xdgSurfaceListener, this); + + xdgToplevel = xdg_surface_get_toplevel(xdgSurface); + xdg_toplevel_listener xdgToplevelListener = { + .configure = WindowWayland::xdgToplevelConfigure, + .close = WindowWayland::xdgToplevelClose, + .configure_bounds = WindowWayland::xdgToplevelConfigureBounds, + .wm_capabilities = WindowWayland::xdgToplevelWmCapabilities + }; + xdg_toplevel_add_listener(xdgToplevel, &xdgToplevelListener, this); _windowManager.registerWindow(this); return true; } -void WindowWayland::move(int left, int top) { - // NO HAVING FUN! -} - -void WindowWayland::resize(int width, int height) { - // BOO! +// ??? +void WindowWayland::recreate() +{ + close(); + init(); } void WindowWayland::setVisible(bool isVisible) { if (_visible != isVisible) { _visible = isVisible; if (_visible) { - XMapWindow(_windowManager.getDisplay(), _x11Window); - if (_posX > 0 && _posY > 0) - move(_posX, _posY); - if (_width > 0 && _height > 0) - resize(_width, _height); + // impl me :troll: } else { - XUnmapWindow(_windowManager.getDisplay(), _x11Window); + // impl me :troll: } } } @@ -127,18 +144,84 @@ void WindowWayland::setVisible(bool isVisible) { void jwm::WindowWayland::setCursor(jwm::MouseCursor cursor) { if (auto wayCursor = _windowManager._cursors[static_cast(cursor)]) { wl_surface_attach(_windowManager.cursorSurface, - wl_cursor_image_get_buffer(wayCursor->images[0]), + wl_cursor_image_get_buffer(wayCursor), 0, 0); wl_surface_commit(_windowManager.cursorSurface); // TODO: hotspots? } else { - auto wayCursor = _windowManager.cursors[static_cast(jwm::MouseCursor::ARROW)]; + auto otherCursor = _windowManager._cursors[static_cast(jwm::MouseCursor::ARROW)]; wl_surface_attach(_windowManager.cursorSurface, - wl_cursor_image_get_buffer(wayCursor->images[0]), 0, 0); + wl_cursor_image_get_buffer(otherCursor), 0, 0); wl_surface_commit(_windowManager.cursorSurface); } } +// what do??? +void jwm::WindowWayland::surfaceEnter(void* data, wl_surface* surface, wl_output* output) {} +void jwm::WindowWayland::surfaceLeave(void* data, wl_surface* surface, wl_output* output) {} +void jwm::WindowWayland::surfacePreferredBufferScale(void* data, wl_surface* surface, int factor) { + WindowWayland* self = (WindowWayland*) data; + if (factor < 1) { + return; + } + self->_scale = factor; + // do I pinky promise here? + // yes : ) + if (self->_layer) { + self->_layer->resize(self->_width * factor, self->_height * factor); + } + wl_surface_set_buffer_scale(surface, factor); +} +void jwm::WindowWayland::surfacePreferredBufferTransform(void* data, wl_surface* surface, uint32_t transform) {} + +void jwm::WindowWayland::xdgSurfaceConfigure(void* data, xdg_surface* surface, uint32_t serial) { + WindowWayland* self = (WindowWayland*) data; + // Commit state + if (self->_newWidth > 0 || self->_newHeight > 0) { + int goodWidth = self->_width, goodHeight = self->_height; + if (self->_newWidth > 0) + goodWidth = self->_newWidth; + if (self->_newHeight > 0) + goodHeight = self->_newHeight; + self->_adaptSize(goodWidth, goodHeight); + } + self->_newWidth = -1; + self->_newHeight = -1; + xdg_surface_ack_configure(surface, serial); +} +void jwm::WindowWayland::xdgToplevelConfigure(void* data, xdg_toplevel* toplevel, int width, int height, wl_array* states) { + WindowWayland* self = (WindowWayland*) data; + if (width > 0) { + self->_newWidth = width; + } + if (height > 0) { + self->_newHeight = height; + } + // honestly idrc about the state +} +void jwm::WindowWayland::xdgToplevelClose(void* data, xdg_toplevel* toplevel) { + // ??? + // Request close EVENTUALLY:TM: +} +void jwm::WindowWayland::xdgToplevelConfigureBounds(void* data, xdg_toplevel* toplevel, int width, int height) { + WindowWayland* self = (WindowWayland*) data; + if (width > 0) { + self->_newWidth = width; + } + if (height > 0) { + self->_newHeight = height; + } +} +void jwm::WindowWayland::xdgToplevelWmCapabilities(void* data, xdg_toplevel* toplevel, wl_array* array) { + // impl me : ) +} +void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { + _width = newWidth; + _height = newHeight; + if (_layer) { + _layer->resize(_width * _scale, _height * _scale); + } +} // JNI extern "C" JNIEXPORT jlong JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nMake @@ -186,24 +269,6 @@ extern "C" JNIEXPORT jobject JNICALL Java_io_github_humbleui_jwm_WindowWayland__ ); } -extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nSetWindowPosition - (JNIEnv* env, jobject obj, int left, int top) { - jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); - instance->move(left, top); -} - -extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nSetWindowSize - (JNIEnv* env, jobject obj, int width, int height) { - jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); - // TODO https://github.com/HumbleUI/JWM/issues/109 - instance->resize(width, height); -} - -extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nSetContentSize - (JNIEnv* env, jobject obj, int width, int height) { - jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); - instance->resize(width, height); -} extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nRequestFrame (JNIEnv* env, jobject obj) { diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index 21fa1867..c67e9add 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -7,6 +7,7 @@ #include #include "ScreenInfo.hh" #include "xdg-shell.hh" +#include namespace jwm { class WindowWayland: public jwm::Window { public: @@ -18,13 +19,12 @@ namespace jwm { void setVisible(bool isVisible); void close(); bool init(); + void recreate(); int getLeft(); int getTop(); int getWidth(); int getHeight(); float getScale(); - void move(int left, int top); - void resize(int width, int height); void requestRedraw() { _isRedrawRequested = true; _windowManager.notifyLoop(); @@ -45,33 +45,41 @@ namespace jwm { void setFullScreen(bool isFullScreen); bool isFullScreen(); - XIC getIC() const { - return _ic; - } void setCursor(jwm::MouseCursor cursor); void setLayer(ILayer* layer) { _layer = layer; } - void _xSendEventToWM(Atom atom, long a, long b, long c, long d, long e) const; - unsigned long _xGetWindowProperty(Atom property, Atom type, unsigned char** value) const; + const ScreenInfo& getScreen(); - /** - * _NET_WM_SYNC_REQUEST (resize flicker fix) update request counter - */ - struct { - uint32_t lo = 0; - uint32_t hi = 0; - XID counter; - } _xsyncRequestCounter; + static void surfaceEnter(void* data, wl_surface* surface, wl_output* output); + static void surfaceLeave(void* data, wl_surface* surface, wl_output* output); + static void surfacePreferredBufferScale(void* data, wl_surface* surface, int factor); + static void surfacePreferredBufferTransform(void* data, wl_surface* surface, uint32_t transform); + + static void xdgSurfaceConfigure(void* data, xdg_surface* surface, uint32_t serial); + + static void xdgToplevelConfigure(void* data, xdg_toplevel* toplevel, int width, int height, wl_array* states); + static void xdgToplevelClose(void* data, xdg_toplevel* toplevel); + static void xdgToplevelConfigureBounds(void* data, xdg_toplevel* toplevel, int width, int height); + static void xdgToplevelWmCapabilities(void* data, xdg_toplevel* toplevel, wl_array* capabilities); + + void _adaptSize(int newWidth, int newHeight); + int _posX = -1; int _posY = -1; int _width = -1; + int _newWidth = -1; + int _scale = 1; int _height = -1; + int _newHeight = -1; int _WM_ADD = 1L; int _WM_REMOVE = 0L; + bool _canMinimize = false; + bool _canMaximize = false; + bool _canFullscreen = false; bool _visible = false; bool _isRedrawRequested = false; @@ -81,5 +89,6 @@ namespace jwm { wl_surface* _waylandWindow = nullptr; xdg_surface* xdgSurface = nullptr; xdg_toplevel* xdgToplevel = nullptr; + libdecor_frame* _frame = nullptr; }; } diff --git a/wayland/java/WindowWayland.java b/wayland/java/WindowWayland.java index 53832795..056f7f45 100644 --- a/wayland/java/WindowWayland.java +++ b/wayland/java/WindowWayland.java @@ -45,16 +45,14 @@ public IRect getContentRect() { @Override public Window setWindowPosition(int left, int top) { assert _onUIThread() : "Should be run on UI thread"; - // _nSetWindowPosition(left, top); - // Unsupported under wayland rn + // no : ) return this; } @Override public Window setWindowSize(int width, int height) { assert _onUIThread() : "Should be run on UI thread"; - // _nSetWindowSize(width, height); - // Possibly unsupported? Hinting is possibly supported + // no : ) return this; } @@ -120,7 +118,7 @@ public float getOpacity(){ @Override public Screen getScreen() { assert _onUIThread() : "Should be run on UI thread"; - return new Screen(0, false, IRect.makeXYWH(0, 0, 0, 0), IRect.makeXYWH(0, 0, 0, 0), 1); + return new Screen(0, false, IRect.makeXYWH(0, 0, 0, 0), IRect.makeXYWH(0, 0, 0, 0), getScale()); } @Override diff --git a/x11/CMakeLists.txt b/x11/CMakeLists.txt index 2157bd4b..36bfff99 100644 --- a/x11/CMakeLists.txt +++ b/x11/CMakeLists.txt @@ -19,8 +19,8 @@ find_package(X11 REQUIRED) find_package(OpenGL REQUIRED) file(GLOB SOURCES_CXX ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/*.cc - ${CMAKE_CURRENT_LIST_DIR}/cc/*.cc - ${CMAKE_CURRENT_LIST_DIR}/../linux/cc/*.cc) + ${CMAKE_CURRENT_LIST_DIR}/../linux/cc/*.cc + ${CMAKE_CURRENT_LIST_DIR}/cc/*.cc) file(GLOB SOURCES_CXX_IMPL ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/impl/*.cc) add_library(jwm SHARED ${SOURCES_OBJC} ${SOURCES_CXX} ${SOURCES_CXX_IMPL}) diff --git a/x11/cc/KeyX11.cc b/x11/cc/KeyX11.cc index 9a638c69..30045e30 100644 --- a/x11/cc/KeyX11.cc +++ b/x11/cc/KeyX11.cc @@ -175,4 +175,4 @@ jwm::Key jwm::KeyX11::fromNative(uint32_t v) { // Key::MUTE default: return Key::UNDEFINED; } -} \ No newline at end of file +} diff --git a/x11/cc/LayerGLX11.cc b/x11/cc/LayerGLX11.cc index 4beb64eb..1b4b8e02 100644 --- a/x11/cc/LayerGLX11.cc +++ b/x11/cc/LayerGLX11.cc @@ -49,7 +49,7 @@ namespace jwm { } } - void resize(int width, int height) { + void resize(int width, int height) override { glClearStencil(0); glClearColor(0, 0, 0, 255); glStencilMask(0xffffffff); @@ -120,4 +120,4 @@ extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerGL__1nClose (JNIEnv* env, jobject obj) { jwm::LayerGL* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); instance->close(); -} \ No newline at end of file +} diff --git a/x11/cc/LayerRasterX11.cc b/x11/cc/LayerRasterX11.cc index 2ec70c85..cc22ea88 100644 --- a/x11/cc/LayerRasterX11.cc +++ b/x11/cc/LayerRasterX11.cc @@ -30,7 +30,7 @@ namespace jwm { _graphicsContext = DefaultGC(d, DefaultScreen(d)); } - void resize(int width, int height) { + void resize(int width, int height) override { Display* d = fWindow->_windowManager.getDisplay(); _width = width; _height = height; @@ -120,4 +120,4 @@ extern "C" JNIEXPORT jlong JNICALL Java_io_github_humbleui_jwm_LayerRaster__1nGe (JNIEnv* env, jobject obj) { jwm::LayerRaster* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); return static_cast(instance->getRowBytes()); -} \ No newline at end of file +} diff --git a/x11/java/WindowX11.java b/x11/java/WindowX11.java index bc865777..89d584c9 100644 --- a/x11/java/WindowX11.java +++ b/x11/java/WindowX11.java @@ -213,7 +213,8 @@ public boolean isFullScreen() { @Override public float getScale() { - return ; + assert _onUIThread() : "Should be run on UI thread"; + return _nGetScale(); } @ApiStatus.Internal public static native long _nMake(); From 4378e8c8492e4fc39d17dee9ba7be73d09cc25b2 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Sun, 3 Dec 2023 11:44:52 -0500 Subject: [PATCH 04/93] It's trying, at least --- examples/dashboard/java/Example.java | 7 ++++--- examples/dashboard/java/PanelRendering.java | 2 ++ linux/cc/ILayer.hh | 2 +- script/common.py | 4 ++-- script/run.py | 3 ++- shared/java/App.java | 2 ++ shared/java/impl/Library.java | 4 ++-- wayland/CMakeLists.txt | 7 +++++++ wayland/cc/LayerGLWayland.cc | 4 +++- wayland/cc/WindowManagerWayland.cc | 6 +++--- wayland/cc/WindowWayland.cc | 2 ++ wayland/cc/{xdg-shell.cc => xdg-shell.c} | 1 - wayland/java/WindowWayland.java | 4 ++-- 13 files changed, 32 insertions(+), 16 deletions(-) rename wayland/cc/{xdg-shell.cc => xdg-shell.c} (99%) diff --git a/examples/dashboard/java/Example.java b/examples/dashboard/java/Example.java index f8a2ee20..3df7cac5 100644 --- a/examples/dashboard/java/Example.java +++ b/examples/dashboard/java/Example.java @@ -53,10 +53,11 @@ public Example() { panelTheme = new PanelTheme(window); panelTouch = new PanelTouch(window); - var scale = window.getScreen().getScale(); + var scale = window.getScale(); int count = App._windows.size() - 1; - Screen screen = App.getScreens()[(count / 5) % App.getScreens().length]; - IRect bounds = screen.getWorkArea(); + // Screen screen = App.getScreens()[(count / 5) % App.getScreens().length]; + // IRect bounds = screen.getWorkArea(); + IRect bounds = new IRect(0, 0, 100, 100); window.setTitle("JWM Window #" + count); if (window instanceof WindowMac windowMac) { diff --git a/examples/dashboard/java/PanelRendering.java b/examples/dashboard/java/PanelRendering.java index 5ab882b4..4d215ccf 100644 --- a/examples/dashboard/java/PanelRendering.java +++ b/examples/dashboard/java/PanelRendering.java @@ -34,6 +34,8 @@ else if (Platform.CURRENT == Platform.WINDOWS) layers = new String[] { "LayerD3D12Skija", "LayerGLSkija", "SkijaLayerRaster" }; else if (Platform.CURRENT == Platform.X11) layers = new String[] { "LayerGLSkija", "LayerRasterSkija" }; + else if (Platform.CURRENT == Platform.WAYLAND) + layers = new String[] { "LayerGLSkija", "LayerRasterSkija" }; for (var layerName: layers) layersStatus.put(layerName, UNKNOWN); diff --git a/linux/cc/ILayer.hh b/linux/cc/ILayer.hh index f21346a4..5b8ee030 100644 --- a/linux/cc/ILayer.hh +++ b/linux/cc/ILayer.hh @@ -15,7 +15,7 @@ public: virtual void makeCurrentForced(); virtual void setVsyncMode(VSync v) = 0; virtual void close() = 0; - virtual void resize(int width, int height); + virtual void resize(int width, int height) = 0; static ILayer* _ourCurrentLayer; diff --git a/script/common.py b/script/common.py index a95ad202..36a5f31a 100644 --- a/script/common.py +++ b/script/common.py @@ -12,7 +12,7 @@ def deps_compile(): (args, _) = parser.parse_known_args() deps = [ - build_utils.fetch_maven('org.projectlombok', 'lombok', '1.18.22'), + build_utils.fetch_maven('org.projectlombok', 'lombok', '1.18.30'), build_utils.fetch_maven('org.jetbrains', 'annotations', '20.1.0') ] @@ -38,4 +38,4 @@ def deps_compile(): return deps -version = build_utils.get_arg("version") or build_utils.parse_ref() or build_utils.parse_sha() or "0.0.0-SNAPSHOT" \ No newline at end of file +version = build_utils.get_arg("version") or build_utils.parse_ref() or build_utils.parse_sha() or "0.0.0-SNAPSHOT" diff --git a/script/run.py b/script/run.py index 98f3c0ee..e90cbe7e 100755 --- a/script/run.py +++ b/script/run.py @@ -10,9 +10,10 @@ def main(): parser.add_argument('--skija-shared-jar', default=None) parser.add_argument('--skija-platform-jar', default=None) parser.add_argument('--types-dir', default=None) + parser.add_argument('--just-run', action='store_true') args = parser.parse_args() - if not args.jwm_version: + if not args.jwm_version and not args.just_run: build.main() if args.skija_dir: diff --git a/shared/java/App.java b/shared/java/App.java index 268ddc60..7a1c5a76 100644 --- a/shared/java/App.java +++ b/shared/java/App.java @@ -52,6 +52,8 @@ else if (Platform.CURRENT == Platform.MACOS) window = new WindowMac(); else if (Platform.CURRENT == Platform.X11) window = new WindowX11(); + else if (Platform.CURRENT == Platform.WAYLAND) + window = new WindowWayland(); else throw new RuntimeException("Unsupported platform: " + Platform.CURRENT); _windows.add(window); diff --git a/shared/java/impl/Library.java b/shared/java/impl/Library.java index 43fd5cbc..29a5da5d 100644 --- a/shared/java/impl/Library.java +++ b/shared/java/impl/Library.java @@ -46,10 +46,10 @@ public static synchronized void load() { } else if (Platform.CURRENT == Platform.X11) { File library = _extract("/", "libjwm_x64.so", tempDir); System.load(library.getAbsolutePath()); - } /*else if (Platform.CURRENT == Platform.WAYLAND) { + } else if (Platform.CURRENT == Platform.WAYLAND) { File library = _extract("/", "libjwm_x64_wayland.so", tempDir); System.load(library.getAbsolutePath()); - }*/ + } if (tempDir.exists() && version == null) { Runtime.getRuntime().addShutdownHook(new Thread(() -> { diff --git a/wayland/CMakeLists.txt b/wayland/CMakeLists.txt index 95ca0ad2..074e87d6 100644 --- a/wayland/CMakeLists.txt +++ b/wayland/CMakeLists.txt @@ -4,6 +4,7 @@ cmake_minimum_required(VERSION 3.9) cmake_policy(SET CMP0072 NEW) project(jwm LANGUAGES CXX) +project(xdgShell LANGUAGES C) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -19,6 +20,8 @@ file(GLOB SOURCES_CXX ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/*.cc ${CMAKE_CURRENT_LIST_DIR}/../linux/cc/*.cc ${CMAKE_CURRENT_LIST_DIR}/cc/*.cc ) file(GLOB SOURCES_CXX_IMPL ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/impl/*.cc) +file(GLOB SOURCES_C ${CMAKE_CURRENT_LIST_DIR}/cc/*.c) +add_library(xdgShell STATIC ${SOURCES_C}) add_library(jwm SHARED ${SOURCES_OBJC} ${SOURCES_CXX} ${SOURCES_CXX_IMPL}) find_library(WAYLAND_CLIENT_LIB wayland-client) find_library(DECOR_LIB decor-0) @@ -26,6 +29,7 @@ find_library(WAYLAND_CURSOR wayland-cursor) find_library(XKBCOMMON xkbcommon) find_library(EGL EGL) find_library(WAYLAND_EGL wayland-egl) +find_package(OpenGL REQUIRED) set(JAVA_HOME $ENV{JAVA_HOME}) if (NOT JAVA_HOME) @@ -41,6 +45,9 @@ endif() target_include_directories(jwm PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../shared/cc ${CMAKE_CURRENT_LIST_DIR}/../linux/cc ${JAVA_HOME}/include ${JAVA_HOME}/include/linux) set_target_properties(jwm PROPERTIES OUTPUT_NAME "jwm_${JWM_ARCH}_wayland") +target_link_libraries(jwm PUBLIC xdgShell) target_link_libraries(jwm PRIVATE ${WAYLAND_CLIENT_LIB} ${DECOR_LIB} ${WAYLAND_CURSOR} ${XKBCOMMON}) target_link_libraries(jwm PRIVATE ${EGL} ${WAYLAND_EGL}) +target_link_libraries(jwm PRIVATE OpenGL::GL) + diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index 8e3f2ee2..e8f8cbcb 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -72,7 +72,9 @@ namespace jwm { // ??? // glViewport(0, 0, width, height); - wl_egl_window_resize(_eglWindow, width, height, 0, 0); + // God is dead if _eglWindow is null + if (_eglWindow) + wl_egl_window_resize(_eglWindow, width, height, 0, 0); } void swapBuffers() { diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 2c629633..5789cb24 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -75,7 +75,7 @@ WindowManagerWayland::WindowManagerWayland(): .leave = WindowManagerWayland::pointerHandleLeave, .motion = WindowManagerWayland::pointerHandleMotion, .button = WindowManagerWayland::pointerHandleButton, - .axis = WindowManagerWayland::pointerHandleAxis + //.axis = WindowManagerWayland::pointerHandleAxis }; wl_pointer_add_listener(pointer, &pointerListener, this); } @@ -112,7 +112,7 @@ void WindowManagerWayland::runLoop() { } if (myPoll.revents & POLLIN) { - while (read(pipes[0], buf, sizeof(buf) == sizeof(buf))) {} + while (read(pipes[0], buf, sizeof(buf)) == sizeof(buf)) {} } notifyBool.store(false); } @@ -166,7 +166,7 @@ void WindowManagerWayland::registryHandleGlobal(void* data, wl_registry *registr &wl_shm_interface, 1); } else if (strcmp(interface, "xdg_wm_base") == 0) { self->xdgShell = (xdg_wm_base*)wl_registry_bind(registry, name, - &xdg_wm_base_interface, 2); + &xdg_wm_base_interface, 1); } else if (strcmp(interface, "wl_data_device_manager") == 0) { self->deviceManager = (wl_data_device_manager*)wl_registry_bind(registry, name, &wl_data_device_manager_interface, 1); diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index ecbd2a92..c28d52fc 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -100,8 +100,10 @@ bool WindowWayland::init() wl_surface_listener surfaceListener = { .enter = WindowWayland::surfaceEnter, .leave = WindowWayland::surfaceLeave, + #ifdef HAVE_WAYLAND_1_22 .preferred_buffer_scale = WindowWayland::surfacePreferredBufferScale, .preferred_buffer_transform = WindowWayland::surfacePreferredBufferTransform + #endif }; wl_surface_add_listener(_waylandWindow, &surfaceListener, this); diff --git a/wayland/cc/xdg-shell.cc b/wayland/cc/xdg-shell.c similarity index 99% rename from wayland/cc/xdg-shell.cc rename to wayland/cc/xdg-shell.c index 03826cdc..747c222a 100644 --- a/wayland/cc/xdg-shell.cc +++ b/wayland/cc/xdg-shell.c @@ -180,4 +180,3 @@ WL_PRIVATE const struct wl_interface xdg_popup_interface = { 3, xdg_popup_requests, 3, xdg_popup_events, }; - diff --git a/wayland/java/WindowWayland.java b/wayland/java/WindowWayland.java index 056f7f45..5c09dd50 100644 --- a/wayland/java/WindowWayland.java +++ b/wayland/java/WindowWayland.java @@ -32,14 +32,14 @@ public void unmarkText() { public IRect getWindowRect() { assert _onUIThread() : "Should be run on UI thread"; // very very bad! - return IRect.makeXYWH(0, 0, 0, 0); + return IRect.makeXYWH(0, 0, 100, 100); } @Override public IRect getContentRect() { assert _onUIThread() : "Should be run on UI thread"; // stop! - return IRect.makeXYWH(0, 0, 0, 0); + return IRect.makeXYWH(0, 0, 100, 100); } @Override From ff1d84a219262059b457c723f2aac80fc932b0ec Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Mon, 4 Dec 2023 09:33:52 -0500 Subject: [PATCH 05/93] Try work on event loop? --- wayland/cc/LayerGLWayland.cc | 5 +-- wayland/cc/LayerRasterWayland.cc | 29 +++++++++++++---- wayland/cc/WindowManagerWayland.cc | 38 ++++++++++++++++------ wayland/cc/WindowManagerWayland.hh | 1 + wayland/cc/WindowWayland.cc | 51 ++++++++++++++++++++++++++---- wayland/cc/WindowWayland.hh | 10 ++++++ 6 files changed, 110 insertions(+), 24 deletions(-) diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index e8f8cbcb..c2d07114 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -22,6 +22,7 @@ namespace jwm { virtual ~LayerGL() = default; void attach(WindowWayland* window) { + eglBindAPI(EGL_OPENGL_API); fWindow = jwm::ref(window); if (window->_layer) { // HACK: close window and reopen @@ -52,7 +53,7 @@ namespace jwm { EGL_NO_CONTEXT, nullptr); _eglWindow = wl_egl_window_create(window->_waylandWindow, window->getWidth(), window->getHeight()); - + // TODO: closed windows? _surface = eglCreatePlatformWindowSurface(_display, config, _eglWindow, nullptr); } @@ -71,7 +72,7 @@ namespace jwm { glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); // ??? - // glViewport(0, 0, width, height); + glViewport(0, 0, width, height); // God is dead if _eglWindow is null if (_eglWindow) wl_egl_window_resize(_eglWindow, width, height, 0, 0); diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index 0462940e..9bec31a2 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -23,22 +23,35 @@ namespace jwm { void attach(WindowWayland* window) { fWindow = jwm::ref(window); fWindow->setLayer(this); + // a default size : ) + resize(100, 100); } void resize(int width, int height) override { wl_display* d = fWindow->_windowManager.display; _width = width; _height = height; - int bufSize = width * height * sizeof(uint32_t) * 2; - if (!_pool) { - _pool = new ShmPool(fWindow->_windowManager.shm, bufSize); + int stride = width * sizeof(uint32_t); + int bufSize = stride * height * 2; + // TODO: better pool impl + if (_pool) { + delete _pool; } + _pool = new ShmPool(fWindow->_windowManager.shm, bufSize); + if (_buffer) { + wl_buffer_destroy(_buffer); + _imageData = nullptr; + } + _pool->grow(bufSize); // LSBFirst means Little endian : ) - auto buf = _pool->createBuffer(0, width, height, width * sizeof(uint32_t), WL_SHM_FORMAT_ABGR8888); - + // This will highly likely cause issues : ) + auto buf = _pool->createBuffer(0, width, height, stride, WL_SHM_FORMAT_ABGR8888); + _buffer = buf.first; _imageData = buf.second; + + } const void* getPixelsPtr() const { @@ -52,7 +65,8 @@ namespace jwm { void swapBuffers() { // : ) - wl_surface_damage_buffer(fWindow->_waylandWindow, 0, 0, UINT32_MAX, UINT32_MAX); + if (fWindow->_waylandWindow) + wl_surface_damage_buffer(fWindow->_waylandWindow, 0, 0, UINT32_MAX, UINT32_MAX); } void close() override { @@ -61,7 +75,7 @@ namespace jwm { _buffer = nullptr; } // ??? - // destroy _pool; + delete _pool; jwm::unref(&fWindow); } @@ -70,6 +84,7 @@ namespace jwm { } void setVsyncMode(VSync v) override { + // srsly, why do I need this _vsync = v; } }; diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 5789cb24..a7f9e5c2 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -32,14 +32,20 @@ WindowManagerWayland::WindowManagerWayland(): wl_display_roundtrip(display); + + if (!(shm && xdgShell && compositor && deviceManager && seat)) { // ??? // Bad. Means our compositor no supportie : ( throw std::system_error(ENOTSUP, std::generic_category(), "Unsupported compositor"); } - - - + + xdg_wm_base_listener xdgListener = { + .ping = WindowManagerWayland::xdgWmBasePing + }; + // frankly `this` is not needed here, but it needs a pointer anyway and it's + // good to have consistentcy. + xdg_wm_base_add_listener(xdgShell, &xdgListener, this); { wl_cursor_theme* cursor_theme = wl_cursor_theme_load(nullptr, 24, shm); // TODO: what about if missing : ( @@ -98,22 +104,29 @@ void WindowManagerWayland::runLoop() { } notifyFD = pipes[1]; fcntl(pipes[1], F_SETFL, O_NONBLOCK); // notifyLoop no blockie : ) - struct pollfd myPoll = {.fd=pipes[0], .events=POLLIN}; + struct pollfd ps[] = {{.fd=wl_display_get_fd(display), .events=POLLIN}, {.fd=pipes[0], .events=POLLIN}}; // who be out here running they loop while (_runLoop) { + printf("gi huys\n"); + wl_display_flush(display); if (jwm::classes::Throwable::exceptionThrown(app.getJniEnv())) _runLoop = false; + printf("try guys\n"); _processCallbacks(); // block until event : ) - if (poll(&myPoll, 1, -1) < 0) { + if (poll(&ps[0], 2, -1) < 0) { printf("error with pipe\n"); break; } - - if (myPoll.revents & POLLIN) { - while (read(pipes[0], buf, sizeof(buf)) == sizeof(buf)) {} + printf("why guys\n"); + if (ps[1].revents & POLLIN) { + while (read(pipes[0], buf, sizeof(buf)) == sizeof(buf)) { } + } + if (ps[0].revents & POLLIN) { + wl_display_dispatch(display); } + printf("hi guys? %i\n", _runLoop); notifyBool.store(false); } @@ -159,8 +172,9 @@ void WindowManagerWayland::registryHandleGlobal(void* data, wl_registry *registr uint32_t name, const char* interface, uint32_t version) { WindowManagerWayland* self = (WindowManagerWayland*)data; if (strcmp(interface, "wl_compositor") == 0) { + // EGL apparently requires at least a version of 4 here : ) self->compositor = (wl_compositor*)wl_registry_bind(registry, name, - &wl_compositor_interface, 3); + &wl_compositor_interface, 4); } else if (strcmp(interface, "wl_shm") == 0) { self->shm = (wl_shm*)wl_registry_bind(registry, name, &wl_shm_interface, 1); @@ -278,6 +292,9 @@ void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, } } } +void WindowManagerWayland::xdgWmBasePing(void* data, xdg_wm_base* base, uint32_t serial) { + xdg_wm_base_pong(base, serial); +} std::vector WindowManagerWayland::getClipboardFormats() { /* XConvertSelection(display, @@ -447,10 +464,13 @@ void WindowManagerWayland::enqueueTask(const std::function& task) { } void WindowManagerWayland::notifyLoop() { + // maybe just do nothing? + /* if (notifyFD==-1) return; // fast notifyBool path to not make system calls when not necessary if (!notifyBool.exchange(true)) { char dummy[1] = {0}; int unused = write(notifyFD, dummy, 1); // this really shouldn't fail, but if it does, the pipe should either be full (good), or dead (bad, but not our business) } + */ } diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index 25cfed88..dae2c083 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -69,6 +69,7 @@ namespace jwm { static void pointerHandleAxis(void* data, wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value); + static void xdgWmBasePing(void* data, xdg_wm_base* base, uint32_t serial); ByteBuf getClipboardContents(const std::string& type); diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index c28d52fc..911592b6 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -28,11 +28,22 @@ void WindowWayland::setTitlebarVisible(bool isVisible) { // impl me : ) } +// Closing is like... the exact same as being visible. WTH void WindowWayland::close() { if (_waylandWindow) { _windowManager.unregisterWindow(this); wl_surface_destroy(_waylandWindow); } + _waylandWindow = nullptr; + if (xdgSurface) { + xdg_surface_destroy(xdgSurface); + } + xdgSurface = nullptr; + if (xdgToplevel) { + xdg_toplevel_destroy(xdgToplevel); + } + xdgToplevel = nullptr; + } void WindowWayland::maximize() { // impl me :) @@ -93,8 +104,10 @@ int WindowWayland::getHeight() { float WindowWayland::getScale() { return _scale; } - -bool WindowWayland::init() +bool WindowWayland::init() { + return true; +} +void WindowWayland::show() { _waylandWindow = wl_compositor_create_surface(_windowManager.compositor); wl_surface_listener surfaceListener = { @@ -122,7 +135,6 @@ bool WindowWayland::init() }; xdg_toplevel_add_listener(xdgToplevel, &xdgToplevelListener, this); _windowManager.registerWindow(this); - return true; } // ??? @@ -136,9 +148,9 @@ void WindowWayland::setVisible(bool isVisible) { if (_visible != isVisible) { _visible = isVisible; if (_visible) { - // impl me :troll: + show(); } else { - // impl me :troll: + close(); } } } @@ -159,7 +171,17 @@ void jwm::WindowWayland::setCursor(jwm::MouseCursor cursor) { } // what do??? -void jwm::WindowWayland::surfaceEnter(void* data, wl_surface* surface, wl_output* output) {} +void jwm::WindowWayland::surfaceEnter(void* data, wl_surface* surface, wl_output* output) { + wl_output_listener listener = { + .geometry = WindowWayland::outputGeometry, + .mode = WindowWayland::outputMode, + .done = WindowWayland::outputDone, + .scale = WindowWayland::outputScale, + .name = WindowWayland::outputName, + .description = WindowWayland::outputDescription + }; + wl_output_add_listener(output, &listener, data); +} void jwm::WindowWayland::surfaceLeave(void* data, wl_surface* surface, wl_output* output) {} void jwm::WindowWayland::surfacePreferredBufferScale(void* data, wl_surface* surface, int factor) { WindowWayland* self = (WindowWayland*) data; @@ -217,6 +239,23 @@ void jwm::WindowWayland::xdgToplevelConfigureBounds(void* data, xdg_toplevel* to void jwm::WindowWayland::xdgToplevelWmCapabilities(void* data, xdg_toplevel* toplevel, wl_array* array) { // impl me : ) } +void jwm::WindowWayland::outputGeometry(void* data, wl_output* output, int x, int y, int pWidth, int pHeight, + int subpixel, const char* make, const char* model, int transform) {} +void jwm::WindowWayland::outputMode(void* data, wl_output* output, uint32_t flags, int width, int height, + int refresh) {} +void jwm::WindowWayland::outputDone(void* data, wl_output* output) {} +void jwm::WindowWayland::outputScale(void* data, wl_output* output, int factor) { + WindowWayland* self = reinterpret_cast(data); + self->_scale = factor; + if (self->_layer) { + self->_layer->resize(self->_width * factor, self->_height * factor); + if (self->_waylandWindow) { + wl_surface_set_buffer_scale(self->_waylandWindow, factor); + } + } +} +void jwm::WindowWayland::outputName(void* data, wl_output* output, const char* name) {} +void jwm::WindowWayland::outputDescription(void* data, wl_output* output, const char* desc) {} void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { _width = newWidth; _height = newHeight; diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index c67e9add..9658dfc7 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -19,6 +19,7 @@ namespace jwm { void setVisible(bool isVisible); void close(); bool init(); + void show(); void recreate(); int getLeft(); int getTop(); @@ -65,6 +66,15 @@ namespace jwm { static void xdgToplevelConfigureBounds(void* data, xdg_toplevel* toplevel, int width, int height); static void xdgToplevelWmCapabilities(void* data, xdg_toplevel* toplevel, wl_array* capabilities); + static void outputGeometry(void* data, wl_output* output, int x, int y, int physWidth, int physHeight, + int subpixelOrient, const char* make, const char* model, int transform); + static void outputMode(void* data, wl_output* output, uint32_t flags, int width, int height, int refresh); + static void outputDone(void* data, wl_output* output); + // YEAH THAT'S WHAT I'VE BEEN WAITING FOR + static void outputScale(void* data, wl_output* output, int factor); + static void outputName(void* data, wl_output* output, const char* name); + static void outputDescription(void* data, wl_output* output, const char* desc); + void _adaptSize(int newWidth, int newHeight); From 26823f21fde8e791bc9beae9f62afbdf45fb02b1 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Mon, 4 Dec 2023 10:28:25 -0500 Subject: [PATCH 06/93] Try attach buffer (xdg didn't like that) --- wayland/cc/ILayerWayland.hh | 10 ++++++++++ wayland/cc/LayerGLWayland.cc | 20 +++++++++++++------- wayland/cc/LayerRasterWayland.cc | 17 +++++++++++++---- wayland/cc/WindowManagerWayland.cc | 6 ------ wayland/cc/WindowWayland.cc | 5 +++++ wayland/cc/WindowWayland.hh | 8 +++++--- 6 files changed, 46 insertions(+), 20 deletions(-) create mode 100644 wayland/cc/ILayerWayland.hh diff --git a/wayland/cc/ILayerWayland.hh b/wayland/cc/ILayerWayland.hh new file mode 100644 index 00000000..45a0dafa --- /dev/null +++ b/wayland/cc/ILayerWayland.hh @@ -0,0 +1,10 @@ +#pragma once + +#include + +namespace jwm { + class ILayerWayland: public ILayer { + public: + virtual void attachBuffer() = 0; + }; +} diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index c2d07114..bf0e6ab9 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -7,16 +7,18 @@ #include #include #include +#include "ILayerWayland.hh" namespace jwm { - class LayerGL: public RefCounted, public ILayer { + class LayerGL: public RefCounted, public ILayerWayland { public: WindowWayland* fWindow; wl_egl_window* _eglWindow = nullptr; EGLContext _context = nullptr; EGLDisplay _display = nullptr; EGLSurface _surface = nullptr; + EGLConfig _config = nullptr; LayerGL() = default; virtual ~LayerGL() = default; @@ -44,17 +46,13 @@ namespace jwm { EGL_RED_SIZE, 8, EGL_NONE }; - EGLConfig config; EGLint numConfig; - eglChooseConfig(_display, attrList, &config, 1, &numConfig); + eglChooseConfig(_display, attrList, &_config, 1, &numConfig); // :troll: _context = eglCreateContext(_display, - config, + _config, EGL_NO_CONTEXT, nullptr); - _eglWindow = wl_egl_window_create(window->_waylandWindow, window->getWidth(), window->getHeight()); - // TODO: closed windows? - _surface = eglCreatePlatformWindowSurface(_display, config, _eglWindow, nullptr); } makeCurrentForced(); @@ -94,6 +92,14 @@ namespace jwm { _surface, _context); } + void attachBuffer() override { + if (fWindow && fWindow->_waylandWindow) { + if (!_eglWindow) { + _eglWindow = wl_egl_window_create(fWindow->_waylandWindow, fWindow->getWidth(), fWindow->getHeight()); + _surface = eglCreatePlatformWindowSurface(_display, _config, _eglWindow, nullptr); + } + } + } }; } // namespace jwm diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index 9bec31a2..431d6464 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -8,7 +8,7 @@ #include namespace jwm { - class LayerRaster: public RefCounted, public ILayer { + class LayerRaster: public RefCounted, public ILayerWayland { public: WindowWayland* fWindow; size_t _width = 0, _height = 0; @@ -50,8 +50,6 @@ namespace jwm { _buffer = buf.first; _imageData = buf.second; - - } const void* getPixelsPtr() const { @@ -65,8 +63,10 @@ namespace jwm { void swapBuffers() { // : ) - if (fWindow->_waylandWindow) + if (fWindow->_waylandWindow) { wl_surface_damage_buffer(fWindow->_waylandWindow, 0, 0, UINT32_MAX, UINT32_MAX); + wl_surface_commit(fWindow->_waylandWindow); + } } void close() override { @@ -87,6 +87,15 @@ namespace jwm { // srsly, why do I need this _vsync = v; } + + void attachBuffer() override { + if (fWindow) { + if (fWindow->_waylandWindow) { + wl_surface_attach(fWindow->_waylandWindow, _buffer, 0, 0); + wl_surface_commit(fWindow->_waylandWindow); + } + } + } }; } diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index a7f9e5c2..6b65294d 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -107,11 +107,9 @@ void WindowManagerWayland::runLoop() { struct pollfd ps[] = {{.fd=wl_display_get_fd(display), .events=POLLIN}, {.fd=pipes[0], .events=POLLIN}}; // who be out here running they loop while (_runLoop) { - printf("gi huys\n"); wl_display_flush(display); if (jwm::classes::Throwable::exceptionThrown(app.getJniEnv())) _runLoop = false; - printf("try guys\n"); _processCallbacks(); // block until event : ) @@ -119,14 +117,12 @@ void WindowManagerWayland::runLoop() { printf("error with pipe\n"); break; } - printf("why guys\n"); if (ps[1].revents & POLLIN) { while (read(pipes[0], buf, sizeof(buf)) == sizeof(buf)) { } } if (ps[0].revents & POLLIN) { wl_display_dispatch(display); } - printf("hi guys? %i\n", _runLoop); notifyBool.store(false); } @@ -465,12 +461,10 @@ void WindowManagerWayland::enqueueTask(const std::function& task) { void WindowManagerWayland::notifyLoop() { // maybe just do nothing? - /* if (notifyFD==-1) return; // fast notifyBool path to not make system calls when not necessary if (!notifyBool.exchange(true)) { char dummy[1] = {0}; int unused = write(notifyFD, dummy, 1); // this really shouldn't fail, but if it does, the pipe should either be full (good), or dead (bad, but not our business) } - */ } diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index 911592b6..c280afde 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -135,6 +135,10 @@ void WindowWayland::show() }; xdg_toplevel_add_listener(xdgToplevel, &xdgToplevelListener, this); _windowManager.registerWindow(this); + + wl_display_roundtrip(_windowManager.display); + if (_layer) + _layer->attachBuffer(); } // ??? @@ -200,6 +204,7 @@ void jwm::WindowWayland::surfacePreferredBufferTransform(void* data, wl_surface* void jwm::WindowWayland::xdgSurfaceConfigure(void* data, xdg_surface* surface, uint32_t serial) { WindowWayland* self = (WindowWayland*) data; + printf("hi guys"); // Commit state if (self->_newWidth > 0 || self->_newHeight > 0) { int goodWidth = self->_width, goodHeight = self->_height; diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index 9658dfc7..6bdbf174 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -4,7 +4,7 @@ #include #include "Window.hh" #include "WindowManagerWayland.hh" -#include +#include "ILayerWayland.hh" #include "ScreenInfo.hh" #include "xdg-shell.hh" #include @@ -47,8 +47,10 @@ namespace jwm { bool isFullScreen(); void setCursor(jwm::MouseCursor cursor); - void setLayer(ILayer* layer) { + void setLayer(ILayerWayland* layer) { _layer = layer; + if (_visible) + _layer->attachBuffer(); } @@ -95,7 +97,7 @@ namespace jwm { bool _isRedrawRequested = false; WindowManagerWayland& _windowManager; - ILayer* _layer = nullptr; + ILayerWayland* _layer = nullptr; wl_surface* _waylandWindow = nullptr; xdg_surface* xdgSurface = nullptr; xdg_toplevel* xdgToplevel = nullptr; From 2831f685f1ae7be765da5e52d206634de4e72a6f Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Mon, 4 Dec 2023 10:33:17 -0500 Subject: [PATCH 07/93] It now segfaults --- wayland/cc/WindowWayland.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index c280afde..efcebca0 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -136,9 +136,6 @@ void WindowWayland::show() xdg_toplevel_add_listener(xdgToplevel, &xdgToplevelListener, this); _windowManager.registerWindow(this); - wl_display_roundtrip(_windowManager.display); - if (_layer) - _layer->attachBuffer(); } // ??? @@ -217,6 +214,9 @@ void jwm::WindowWayland::xdgSurfaceConfigure(void* data, xdg_surface* surface, u self->_newWidth = -1; self->_newHeight = -1; xdg_surface_ack_configure(surface, serial); + if (self->_layer) { + self->_layer->attachBuffer(); + } } void jwm::WindowWayland::xdgToplevelConfigure(void* data, xdg_toplevel* toplevel, int width, int height, wl_array* states) { WindowWayland* self = (WindowWayland*) data; From cc7f89258609713e7c9f2afc66d8b85db84adf6c Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Tue, 5 Dec 2023 20:10:32 -0500 Subject: [PATCH 08/93] ok i'm trying --- examples/dashboard/java/PanelRendering.java | 2 +- wayland/cc/LayerRasterWayland.cc | 22 ++++++--- wayland/cc/ShmPool.cc | 7 ++- wayland/cc/ShmPool.hh | 1 + wayland/cc/WindowManagerWayland.cc | 55 ++++++++++++++++----- wayland/cc/WindowWayland.cc | 23 +++++---- wayland/cc/WindowWayland.hh | 2 - 7 files changed, 78 insertions(+), 34 deletions(-) diff --git a/examples/dashboard/java/PanelRendering.java b/examples/dashboard/java/PanelRendering.java index 4d215ccf..a40b4a0a 100644 --- a/examples/dashboard/java/PanelRendering.java +++ b/examples/dashboard/java/PanelRendering.java @@ -35,7 +35,7 @@ else if (Platform.CURRENT == Platform.WINDOWS) else if (Platform.CURRENT == Platform.X11) layers = new String[] { "LayerGLSkija", "LayerRasterSkija" }; else if (Platform.CURRENT == Platform.WAYLAND) - layers = new String[] { "LayerGLSkija", "LayerRasterSkija" }; + layers = new String[] { "LayerRasterSkija" }; for (var layerName: layers) layersStatus.put(layerName, UNKNOWN); diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index 431d6464..8e603f1c 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -16,6 +16,7 @@ namespace jwm { uint8_t* _imageData = nullptr; ShmPool* _pool = nullptr; VSync _vsync = VSYNC_ENABLED; + bool _attached = false; LayerRaster() = default; virtual ~LayerRaster() = default; @@ -35,21 +36,26 @@ namespace jwm { int bufSize = stride * height * 2; // TODO: better pool impl if (_pool) { - delete _pool; + _pool->close(); } _pool = new ShmPool(fWindow->_windowManager.shm, bufSize); + if (fWindow->_waylandWindow) { + wl_surface_attach(fWindow->_waylandWindow, nullptr, 0, 0); + } if (_buffer) { wl_buffer_destroy(_buffer); _imageData = nullptr; } - _pool->grow(bufSize); // LSBFirst means Little endian : ) // This will highly likely cause issues : ) - auto buf = _pool->createBuffer(0, width, height, stride, WL_SHM_FORMAT_ABGR8888); + auto buf = _pool->createBuffer(0, width, height, stride, WL_SHM_FORMAT_ARGB8888); _buffer = buf.first; _imageData = buf.second; + if (_attached) { + attachBuffer(); + } } const void* getPixelsPtr() const { @@ -63,8 +69,8 @@ namespace jwm { void swapBuffers() { // : ) - if (fWindow->_waylandWindow) { - wl_surface_damage_buffer(fWindow->_waylandWindow, 0, 0, UINT32_MAX, UINT32_MAX); + if (fWindow->_waylandWindow && _attached) { + wl_surface_damage_buffer(fWindow->_waylandWindow, 0, 0, INT32_MAX, INT32_MAX); wl_surface_commit(fWindow->_waylandWindow); } } @@ -75,7 +81,9 @@ namespace jwm { _buffer = nullptr; } // ??? - delete _pool; + if (_pool) { + _pool->close(); + } jwm::unref(&fWindow); } @@ -93,10 +101,12 @@ namespace jwm { if (fWindow->_waylandWindow) { wl_surface_attach(fWindow->_waylandWindow, _buffer, 0, 0); wl_surface_commit(fWindow->_waylandWindow); + _attached = true; } } } }; + } diff --git a/wayland/cc/ShmPool.cc b/wayland/cc/ShmPool.cc index 0f42ed50..b6c3a0de 100644 --- a/wayland/cc/ShmPool.cc +++ b/wayland/cc/ShmPool.cc @@ -31,8 +31,11 @@ ShmPool::ShmPool(wl_shm* shm, size_t size): } ShmPool::~ShmPool() { + +} +void ShmPool::close() { wl_shm_pool_destroy(_pool); - close(_fd); + ::close(_fd); } void ShmPool::grow(size_t size) { @@ -80,7 +83,7 @@ int ShmPool::_allocateShmFile(size_t size) { ret = ftruncate(fd, size); } while (ret < 0 && errno == EINTR); if (ret < 0) { - close(fd); + ::close(fd); return -1; } return fd; diff --git a/wayland/cc/ShmPool.hh b/wayland/cc/ShmPool.hh index ed67e1a5..402660b6 100644 --- a/wayland/cc/ShmPool.hh +++ b/wayland/cc/ShmPool.hh @@ -21,5 +21,6 @@ namespace jwm { int _createShmFile(); int _allocateShmFile(size_t size); + void close(); }; } diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 6b65294d..5354ce88 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -16,7 +16,7 @@ #include "Log.hh" #include "xdg-shell.hh" #include - +#include using namespace jwm; @@ -40,12 +40,13 @@ WindowManagerWayland::WindowManagerWayland(): throw std::system_error(ENOTSUP, std::generic_category(), "Unsupported compositor"); } - xdg_wm_base_listener xdgListener = { + struct xdg_wm_base_listener xdgListener = { .ping = WindowManagerWayland::xdgWmBasePing }; + // frankly `this` is not needed here, but it needs a pointer anyway and it's - // good to have consistentcy. - xdg_wm_base_add_listener(xdgShell, &xdgListener, this); + // good to have consistentcy. + // xdg_wm_base_add_listener(xdgShell, &xdgListener, this); { wl_cursor_theme* cursor_theme = wl_cursor_theme_load(nullptr, 24, shm); // TODO: what about if missing : ( @@ -76,12 +77,12 @@ WindowManagerWayland::WindowManagerWayland(): { pointer = wl_seat_get_pointer(seat); - wl_pointer_listener pointerListener = { + struct wl_pointer_listener pointerListener = { .enter = WindowManagerWayland::pointerHandleEnter, .leave = WindowManagerWayland::pointerHandleLeave, .motion = WindowManagerWayland::pointerHandleMotion, .button = WindowManagerWayland::pointerHandleButton, - //.axis = WindowManagerWayland::pointerHandleAxis + .axis = WindowManagerWayland::pointerHandleAxis }; wl_pointer_add_listener(pointer, &pointerListener, this); } @@ -104,26 +105,56 @@ void WindowManagerWayland::runLoop() { } notifyFD = pipes[1]; fcntl(pipes[1], F_SETFL, O_NONBLOCK); // notifyLoop no blockie : ) + struct pollfd wayland_out = {.fd=wl_display_get_fd(display),.events=POLLOUT}; struct pollfd ps[] = {{.fd=wl_display_get_fd(display), .events=POLLIN}, {.fd=pipes[0], .events=POLLIN}}; // who be out here running they loop while (_runLoop) { - wl_display_flush(display); + printf(": (\n"); if (jwm::classes::Throwable::exceptionThrown(app.getJniEnv())) _runLoop = false; _processCallbacks(); + while(wl_display_prepare_read(display) != 0) + wl_display_dispatch_pending(display); + // adapted from Waylock + while (true) { + int res = wl_display_flush(display); + if (res >= 0) + break; + + switch (errno) { + case EPIPE: + wl_display_read_events(display); + throw std::system_error(errno, std::generic_category(), "connection to wayland server unexpectedly terminated"); + break; + case EAGAIN: + if (poll(&wayland_out, 1, -1) < 0) { + throw std::system_error(EPIPE, std::generic_category(), "poll failed"); + } + break; + default: + throw std::system_error(errno, std::generic_category(), "failed to flush requests"); + break; + } + } // block until event : ) if (poll(&ps[0], 2, -1) < 0) { printf("error with pipe\n"); break; } + printf(": |\n"); if (ps[1].revents & POLLIN) { while (read(pipes[0], buf, sizeof(buf)) == sizeof(buf)) { } } if (ps[0].revents & POLLIN) { - wl_display_dispatch(display); + // WHY IN THE WORLD IS THIS CRASHING + wl_display_read_events(display); + } else { + wl_display_cancel_read(display); } + wl_display_dispatch_pending(display); notifyBool.store(false); + printf(": )\n"); } notifyFD = -1; @@ -155,7 +186,7 @@ void WindowManagerWayland::_processCallbacks() { for (auto p : copy) { if (p->isRedrawRequested()) { p->unsetRedrawRequest(); - if (p->_layer) { + if (p->_layer && p->_visible) { p->_layer->makeCurrent(); } p->dispatch(classes::EventFrame::kInstance); @@ -166,7 +197,7 @@ void WindowManagerWayland::_processCallbacks() { void WindowManagerWayland::registryHandleGlobal(void* data, wl_registry *registry, uint32_t name, const char* interface, uint32_t version) { - WindowManagerWayland* self = (WindowManagerWayland*)data; + WindowManagerWayland* self = reinterpret_cast(data); if (strcmp(interface, "wl_compositor") == 0) { // EGL apparently requires at least a version of 4 here : ) self->compositor = (wl_compositor*)wl_registry_bind(registry, name, @@ -176,7 +207,7 @@ void WindowManagerWayland::registryHandleGlobal(void* data, wl_registry *registr &wl_shm_interface, 1); } else if (strcmp(interface, "xdg_wm_base") == 0) { self->xdgShell = (xdg_wm_base*)wl_registry_bind(registry, name, - &xdg_wm_base_interface, 1); + &xdg_wm_base_interface, 2); } else if (strcmp(interface, "wl_data_device_manager") == 0) { self->deviceManager = (wl_data_device_manager*)wl_registry_bind(registry, name, &wl_data_device_manager_interface, 1); @@ -288,6 +319,8 @@ void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, } } } +void WindowManagerWayland::pointerHandleAxis(void* data, wl_pointer* pointer, + uint32_t time, uint32_t axis, wl_fixed_t value) {} void WindowManagerWayland::xdgWmBasePing(void* data, xdg_wm_base* base, uint32_t serial) { xdg_wm_base_pong(base, serial); } diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index efcebca0..300ad76a 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -11,7 +11,10 @@ using namespace jwm; WindowWayland::WindowWayland(JNIEnv* env, WindowManagerWayland& windowManager): jwm::Window(env), - _windowManager(windowManager) + _windowManager(windowManager), + // HACK: have a default height bc some compositors won't hecking tell me :sob: + _width(100), + _height(100) { } @@ -28,7 +31,7 @@ void WindowWayland::setTitlebarVisible(bool isVisible) { // impl me : ) } -// Closing is like... the exact same as being visible. WTH +// Closing is like... the exact same as hiding. WTH void WindowWayland::close() { if (_waylandWindow) { _windowManager.unregisterWindow(this); @@ -113,10 +116,8 @@ void WindowWayland::show() wl_surface_listener surfaceListener = { .enter = WindowWayland::surfaceEnter, .leave = WindowWayland::surfaceLeave, - #ifdef HAVE_WAYLAND_1_22 .preferred_buffer_scale = WindowWayland::surfacePreferredBufferScale, .preferred_buffer_transform = WindowWayland::surfacePreferredBufferTransform - #endif }; wl_surface_add_listener(_waylandWindow, &surfaceListener, this); @@ -133,9 +134,9 @@ void WindowWayland::show() .configure_bounds = WindowWayland::xdgToplevelConfigureBounds, .wm_capabilities = WindowWayland::xdgToplevelWmCapabilities }; - xdg_toplevel_add_listener(xdgToplevel, &xdgToplevelListener, this); + xdg_toplevel_add_listener(xdgToplevel, &xdgToplevelListener, this); _windowManager.registerWindow(this); - + wl_surface_commit(_waylandWindow); } // ??? @@ -173,6 +174,7 @@ void jwm::WindowWayland::setCursor(jwm::MouseCursor cursor) { // what do??? void jwm::WindowWayland::surfaceEnter(void* data, wl_surface* surface, wl_output* output) { + // doesn't crash : ) wl_output_listener listener = { .geometry = WindowWayland::outputGeometry, .mode = WindowWayland::outputMode, @@ -192,16 +194,13 @@ void jwm::WindowWayland::surfacePreferredBufferScale(void* data, wl_surface* sur self->_scale = factor; // do I pinky promise here? // yes : ) - if (self->_layer) { - self->_layer->resize(self->_width * factor, self->_height * factor); - } wl_surface_set_buffer_scale(surface, factor); + self->_adaptSize(self->_width, self->_height); } void jwm::WindowWayland::surfacePreferredBufferTransform(void* data, wl_surface* surface, uint32_t transform) {} void jwm::WindowWayland::xdgSurfaceConfigure(void* data, xdg_surface* surface, uint32_t serial) { WindowWayland* self = (WindowWayland*) data; - printf("hi guys"); // Commit state if (self->_newWidth > 0 || self->_newHeight > 0) { int goodWidth = self->_width, goodHeight = self->_height; @@ -229,8 +228,8 @@ void jwm::WindowWayland::xdgToplevelConfigure(void* data, xdg_toplevel* toplevel // honestly idrc about the state } void jwm::WindowWayland::xdgToplevelClose(void* data, xdg_toplevel* toplevel) { - // ??? - // Request close EVENTUALLY:TM: + WindowWayland* self = reinterpret_cast(data); + self->dispatch(classes::EventWindowCloseRequest::kInstance); } void jwm::WindowWayland::xdgToplevelConfigureBounds(void* data, xdg_toplevel* toplevel, int width, int height) { WindowWayland* self = (WindowWayland*) data; diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index 6bdbf174..53c22717 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -49,8 +49,6 @@ namespace jwm { void setCursor(jwm::MouseCursor cursor); void setLayer(ILayerWayland* layer) { _layer = layer; - if (_visible) - _layer->attachBuffer(); } From 9c35576e1d1afd8a24a50e9da3a80d3126380d2c Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Tue, 5 Dec 2023 21:06:07 -0500 Subject: [PATCH 09/93] IT SURE DOES OPEN --- wayland/CMakeLists.txt | 4 +- wayland/cc/WindowManagerWayland.cc | 52 +++++++++-------- wayland/cc/WindowManagerWayland.hh | 7 ++- wayland/cc/WindowWayland.cc | 56 ++++++++++--------- wayland/cc/WindowWayland.hh | 9 ++- wayland/cc/{ => xdg-shell}/xdg-shell.c | 21 ++----- .../{xdg-shell.hh => xdg-shell/xdg-shell.h} | 0 7 files changed, 76 insertions(+), 73 deletions(-) rename wayland/cc/{ => xdg-shell}/xdg-shell.c (90%) rename wayland/cc/{xdg-shell.hh => xdg-shell/xdg-shell.h} (100%) diff --git a/wayland/CMakeLists.txt b/wayland/CMakeLists.txt index 074e87d6..d323fd85 100644 --- a/wayland/CMakeLists.txt +++ b/wayland/CMakeLists.txt @@ -20,8 +20,8 @@ file(GLOB SOURCES_CXX ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/*.cc ${CMAKE_CURRENT_LIST_DIR}/../linux/cc/*.cc ${CMAKE_CURRENT_LIST_DIR}/cc/*.cc ) file(GLOB SOURCES_CXX_IMPL ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/impl/*.cc) -file(GLOB SOURCES_C ${CMAKE_CURRENT_LIST_DIR}/cc/*.c) -add_library(xdgShell STATIC ${SOURCES_C}) +file(GLOB SOURCES_XDG ${CMAKE_CURRENT_LIST_DIR}/cc/xdg-shell/*.c) +add_library(xdgShell STATIC ${SOURCES_XDG}) add_library(jwm SHARED ${SOURCES_OBJC} ${SOURCES_CXX} ${SOURCES_CXX_IMPL}) find_library(WAYLAND_CLIENT_LIB wayland-client) find_library(DECOR_LIB decor-0) diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 5354ce88..50b88e41 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -14,21 +14,30 @@ #include #include #include "Log.hh" -#include "xdg-shell.hh" #include #include using namespace jwm; +wl_registry_listener WindowManagerWayland::_registryListener = { + .global = WindowManagerWayland::registryHandleGlobal, + .global_remove = WindowManagerWayland::registryHandleGlobalRemove +}; +wl_pointer_listener WindowManagerWayland::_pointerListener = { + .enter = WindowManagerWayland::pointerHandleEnter, + .leave = WindowManagerWayland::pointerHandleLeave, + .motion = WindowManagerWayland::pointerHandleMotion, + .button = WindowManagerWayland::pointerHandleButton, + .axis = WindowManagerWayland::pointerHandleAxis +}; +xdg_wm_base_listener WindowManagerWayland::_xdgWmBaseListener = { + .ping = WindowManagerWayland::xdgWmBasePing +}; WindowManagerWayland::WindowManagerWayland(): display(wl_display_connect(nullptr)) { registry = wl_display_get_registry(display); - wl_registry_listener registry_listener = { - .global = WindowManagerWayland::registryHandleGlobal, - .global_remove = WindowManagerWayland::registryHandleGlobalRemove - }; - wl_registry_add_listener(registry, ®istry_listener, this); + wl_registry_add_listener(registry, &_registryListener, this); wl_display_roundtrip(display); @@ -40,13 +49,11 @@ WindowManagerWayland::WindowManagerWayland(): throw std::system_error(ENOTSUP, std::generic_category(), "Unsupported compositor"); } - struct xdg_wm_base_listener xdgListener = { - .ping = WindowManagerWayland::xdgWmBasePing - }; + // frankly `this` is not needed here, but it needs a pointer anyway and it's // good to have consistentcy. - // xdg_wm_base_add_listener(xdgShell, &xdgListener, this); + xdg_wm_base_add_listener(xdgShell, &_xdgWmBaseListener, this); { wl_cursor_theme* cursor_theme = wl_cursor_theme_load(nullptr, 24, shm); // TODO: what about if missing : ( @@ -77,14 +84,8 @@ WindowManagerWayland::WindowManagerWayland(): { pointer = wl_seat_get_pointer(seat); - struct wl_pointer_listener pointerListener = { - .enter = WindowManagerWayland::pointerHandleEnter, - .leave = WindowManagerWayland::pointerHandleLeave, - .motion = WindowManagerWayland::pointerHandleMotion, - .button = WindowManagerWayland::pointerHandleButton, - .axis = WindowManagerWayland::pointerHandleAxis - }; - wl_pointer_add_listener(pointer, &pointerListener, this); + + wl_pointer_add_listener(pointer, &_pointerListener, this); } @@ -109,7 +110,6 @@ void WindowManagerWayland::runLoop() { struct pollfd ps[] = {{.fd=wl_display_get_fd(display), .events=POLLIN}, {.fd=pipes[0], .events=POLLIN}}; // who be out here running they loop while (_runLoop) { - printf(": (\n"); if (jwm::classes::Throwable::exceptionThrown(app.getJniEnv())) _runLoop = false; _processCallbacks(); @@ -142,7 +142,6 @@ void WindowManagerWayland::runLoop() { printf("error with pipe\n"); break; } - printf(": |\n"); if (ps[1].revents & POLLIN) { while (read(pipes[0], buf, sizeof(buf)) == sizeof(buf)) { } } @@ -154,7 +153,6 @@ void WindowManagerWayland::runLoop() { } wl_display_dispatch_pending(display); notifyBool.store(false); - printf(": )\n"); } notifyFD = -1; @@ -198,20 +196,20 @@ void WindowManagerWayland::_processCallbacks() { void WindowManagerWayland::registryHandleGlobal(void* data, wl_registry *registry, uint32_t name, const char* interface, uint32_t version) { WindowManagerWayland* self = reinterpret_cast(data); - if (strcmp(interface, "wl_compositor") == 0) { + if (strcmp(interface, wl_compositor_interface.name) == 0) { // EGL apparently requires at least a version of 4 here : ) self->compositor = (wl_compositor*)wl_registry_bind(registry, name, &wl_compositor_interface, 4); - } else if (strcmp(interface, "wl_shm") == 0) { + } else if (strcmp(interface, wl_shm_interface.name) == 0) { self->shm = (wl_shm*)wl_registry_bind(registry, name, &wl_shm_interface, 1); - } else if (strcmp(interface, "xdg_wm_base") == 0) { + } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { self->xdgShell = (xdg_wm_base*)wl_registry_bind(registry, name, - &xdg_wm_base_interface, 2); - } else if (strcmp(interface, "wl_data_device_manager") == 0) { + &xdg_wm_base_interface, 1); + } else if (strcmp(interface, wl_data_device_manager_interface.name) == 0) { self->deviceManager = (wl_data_device_manager*)wl_registry_bind(registry, name, &wl_data_device_manager_interface, 1); - } else if (strcmp(interface, "wl_seat") == 0) { + } else if (strcmp(interface, wl_seat_interface.name) == 0) { self->seat = (wl_seat*)wl_registry_bind(registry, name, &wl_seat_interface, 1); } diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index dae2c083..a5ecf0ec 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -13,7 +13,7 @@ #include "MouseCursor.hh" #include #include -#include "xdg-shell.hh" +#include "xdg-shell/xdg-shell.h" namespace jwm { class WindowWayland; @@ -52,11 +52,15 @@ namespace jwm { void notifyLoop(); void enqueueTask(const std::function& task); + static wl_registry_listener _registryListener; + static void registryHandleGlobal(void* data, wl_registry *registry, uint32_t name, const char* interface, uint32_t version); static void registryHandleGlobalRemove(void* data, wl_registry *registry, uint32_t name); + static wl_pointer_listener _pointerListener; + static void pointerHandleEnter(void* data, wl_pointer *pointer, uint32_t serial, wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y); static void pointerHandleLeave(void* data, wl_pointer *pointer, @@ -69,6 +73,7 @@ namespace jwm { static void pointerHandleAxis(void* data, wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value); + static xdg_wm_base_listener _xdgWmBaseListener; static void xdgWmBasePing(void* data, xdg_wm_base* base, uint32_t serial); diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index 300ad76a..ab21dfc4 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -9,6 +9,31 @@ using namespace jwm; +wl_surface_listener WindowWayland::_surfaceListener = { + .enter = WindowWayland::surfaceEnter, + .leave = WindowWayland::surfaceLeave, + .preferred_buffer_scale = WindowWayland::surfacePreferredBufferScale, + .preferred_buffer_transform = WindowWayland::surfacePreferredBufferTransform +}; +xdg_surface_listener WindowWayland::_xdgSurfaceListener = { + .configure = WindowWayland::xdgSurfaceConfigure +}; + +xdg_toplevel_listener WindowWayland::_xdgToplevelListener = { + .configure = WindowWayland::xdgToplevelConfigure, + .close = WindowWayland::xdgToplevelClose, + .configure_bounds = WindowWayland::xdgToplevelConfigureBounds, + .wm_capabilities = WindowWayland::xdgToplevelWmCapabilities +}; + +wl_output_listener WindowWayland::_outputListener = { + .geometry = WindowWayland::outputGeometry, + .mode = WindowWayland::outputMode, + .done = WindowWayland::outputDone, + .scale = WindowWayland::outputScale, + .name = WindowWayland::outputName, + .description = WindowWayland::outputDescription +}; WindowWayland::WindowWayland(JNIEnv* env, WindowManagerWayland& windowManager): jwm::Window(env), _windowManager(windowManager), @@ -113,28 +138,13 @@ bool WindowWayland::init() { void WindowWayland::show() { _waylandWindow = wl_compositor_create_surface(_windowManager.compositor); - wl_surface_listener surfaceListener = { - .enter = WindowWayland::surfaceEnter, - .leave = WindowWayland::surfaceLeave, - .preferred_buffer_scale = WindowWayland::surfacePreferredBufferScale, - .preferred_buffer_transform = WindowWayland::surfacePreferredBufferTransform - }; - wl_surface_add_listener(_waylandWindow, &surfaceListener, this); + wl_surface_add_listener(_waylandWindow, &_surfaceListener, this); xdgSurface = xdg_wm_base_get_xdg_surface(_windowManager.xdgShell, _waylandWindow); - xdg_surface_listener xdgSurfaceListener = { - .configure = WindowWayland::xdgSurfaceConfigure - }; - xdg_surface_add_listener(xdgSurface, &xdgSurfaceListener, this); + xdg_surface_add_listener(xdgSurface, &_xdgSurfaceListener, this); xdgToplevel = xdg_surface_get_toplevel(xdgSurface); - xdg_toplevel_listener xdgToplevelListener = { - .configure = WindowWayland::xdgToplevelConfigure, - .close = WindowWayland::xdgToplevelClose, - .configure_bounds = WindowWayland::xdgToplevelConfigureBounds, - .wm_capabilities = WindowWayland::xdgToplevelWmCapabilities - }; - xdg_toplevel_add_listener(xdgToplevel, &xdgToplevelListener, this); + xdg_toplevel_add_listener(xdgToplevel, &_xdgToplevelListener, this); _windowManager.registerWindow(this); wl_surface_commit(_waylandWindow); } @@ -175,15 +185,7 @@ void jwm::WindowWayland::setCursor(jwm::MouseCursor cursor) { // what do??? void jwm::WindowWayland::surfaceEnter(void* data, wl_surface* surface, wl_output* output) { // doesn't crash : ) - wl_output_listener listener = { - .geometry = WindowWayland::outputGeometry, - .mode = WindowWayland::outputMode, - .done = WindowWayland::outputDone, - .scale = WindowWayland::outputScale, - .name = WindowWayland::outputName, - .description = WindowWayland::outputDescription - }; - wl_output_add_listener(output, &listener, data); + wl_output_add_listener(output, &_outputListener, data); } void jwm::WindowWayland::surfaceLeave(void* data, wl_surface* surface, wl_output* output) {} void jwm::WindowWayland::surfacePreferredBufferScale(void* data, wl_surface* surface, int factor) { diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index 53c22717..80723915 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -6,7 +6,7 @@ #include "WindowManagerWayland.hh" #include "ILayerWayland.hh" #include "ScreenInfo.hh" -#include "xdg-shell.hh" +#include "xdg-shell/xdg-shell.h" #include namespace jwm { class WindowWayland: public jwm::Window { @@ -100,5 +100,12 @@ namespace jwm { xdg_surface* xdgSurface = nullptr; xdg_toplevel* xdgToplevel = nullptr; libdecor_frame* _frame = nullptr; + + static wl_surface_listener _surfaceListener; + static xdg_surface_listener _xdgSurfaceListener; + static xdg_toplevel_listener _xdgToplevelListener; + + static wl_output_listener _outputListener; + }; } diff --git a/wayland/cc/xdg-shell.c b/wayland/cc/xdg-shell/xdg-shell.c similarity index 90% rename from wayland/cc/xdg-shell.c rename to wayland/cc/xdg-shell/xdg-shell.c index 747c222a..a91fb6ca 100644 --- a/wayland/cc/xdg-shell.c +++ b/wayland/cc/xdg-shell/xdg-shell.c @@ -32,16 +32,6 @@ #include #include "wayland-util.h" -#ifndef __has_attribute -# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ -#endif - -#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) -#define WL_PRIVATE __attribute__ ((visibility("hidden"))) -#else -#define WL_PRIVATE -#endif - extern const struct wl_interface wl_output_interface; extern const struct wl_interface wl_seat_interface; extern const struct wl_interface wl_surface_interface; @@ -90,7 +80,7 @@ static const struct wl_message xdg_wm_base_events[] = { { "ping", "u", xdg_shell_types + 0 }, }; -WL_PRIVATE const struct wl_interface xdg_wm_base_interface = { +WL_EXPORT const struct wl_interface xdg_wm_base_interface = { "xdg_wm_base", 6, 4, xdg_wm_base_requests, 1, xdg_wm_base_events, @@ -109,7 +99,7 @@ static const struct wl_message xdg_positioner_requests[] = { { "set_parent_configure", "3u", xdg_shell_types + 0 }, }; -WL_PRIVATE const struct wl_interface xdg_positioner_interface = { +WL_EXPORT const struct wl_interface xdg_positioner_interface = { "xdg_positioner", 6, 10, xdg_positioner_requests, 0, NULL, @@ -127,7 +117,7 @@ static const struct wl_message xdg_surface_events[] = { { "configure", "u", xdg_shell_types + 0 }, }; -WL_PRIVATE const struct wl_interface xdg_surface_interface = { +WL_EXPORT const struct wl_interface xdg_surface_interface = { "xdg_surface", 6, 5, xdg_surface_requests, 1, xdg_surface_events, @@ -157,7 +147,7 @@ static const struct wl_message xdg_toplevel_events[] = { { "wm_capabilities", "5a", xdg_shell_types + 0 }, }; -WL_PRIVATE const struct wl_interface xdg_toplevel_interface = { +WL_EXPORT const struct wl_interface xdg_toplevel_interface = { "xdg_toplevel", 6, 14, xdg_toplevel_requests, 4, xdg_toplevel_events, @@ -175,8 +165,9 @@ static const struct wl_message xdg_popup_events[] = { { "repositioned", "3u", xdg_shell_types + 0 }, }; -WL_PRIVATE const struct wl_interface xdg_popup_interface = { +WL_EXPORT const struct wl_interface xdg_popup_interface = { "xdg_popup", 6, 3, xdg_popup_requests, 3, xdg_popup_events, }; + diff --git a/wayland/cc/xdg-shell.hh b/wayland/cc/xdg-shell/xdg-shell.h similarity index 100% rename from wayland/cc/xdg-shell.hh rename to wayland/cc/xdg-shell/xdg-shell.h From 46d015ee044cd6364138eece330ed46164716980 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Tue, 5 Dec 2023 21:07:19 -0500 Subject: [PATCH 10/93] Revert from public glue to private glue --- wayland/cc/xdg-shell/xdg-shell.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/wayland/cc/xdg-shell/xdg-shell.c b/wayland/cc/xdg-shell/xdg-shell.c index a91fb6ca..03826cdc 100644 --- a/wayland/cc/xdg-shell/xdg-shell.c +++ b/wayland/cc/xdg-shell/xdg-shell.c @@ -32,6 +32,16 @@ #include #include "wayland-util.h" +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + extern const struct wl_interface wl_output_interface; extern const struct wl_interface wl_seat_interface; extern const struct wl_interface wl_surface_interface; @@ -80,7 +90,7 @@ static const struct wl_message xdg_wm_base_events[] = { { "ping", "u", xdg_shell_types + 0 }, }; -WL_EXPORT const struct wl_interface xdg_wm_base_interface = { +WL_PRIVATE const struct wl_interface xdg_wm_base_interface = { "xdg_wm_base", 6, 4, xdg_wm_base_requests, 1, xdg_wm_base_events, @@ -99,7 +109,7 @@ static const struct wl_message xdg_positioner_requests[] = { { "set_parent_configure", "3u", xdg_shell_types + 0 }, }; -WL_EXPORT const struct wl_interface xdg_positioner_interface = { +WL_PRIVATE const struct wl_interface xdg_positioner_interface = { "xdg_positioner", 6, 10, xdg_positioner_requests, 0, NULL, @@ -117,7 +127,7 @@ static const struct wl_message xdg_surface_events[] = { { "configure", "u", xdg_shell_types + 0 }, }; -WL_EXPORT const struct wl_interface xdg_surface_interface = { +WL_PRIVATE const struct wl_interface xdg_surface_interface = { "xdg_surface", 6, 5, xdg_surface_requests, 1, xdg_surface_events, @@ -147,7 +157,7 @@ static const struct wl_message xdg_toplevel_events[] = { { "wm_capabilities", "5a", xdg_shell_types + 0 }, }; -WL_EXPORT const struct wl_interface xdg_toplevel_interface = { +WL_PRIVATE const struct wl_interface xdg_toplevel_interface = { "xdg_toplevel", 6, 14, xdg_toplevel_requests, 4, xdg_toplevel_events, @@ -165,7 +175,7 @@ static const struct wl_message xdg_popup_events[] = { { "repositioned", "3u", xdg_shell_types + 0 }, }; -WL_EXPORT const struct wl_interface xdg_popup_interface = { +WL_PRIVATE const struct wl_interface xdg_popup_interface = { "xdg_popup", 6, 3, xdg_popup_requests, 3, xdg_popup_events, From 84ec8e61586df8fd0a895546b56773c5b2a3bd6e Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Tue, 5 Dec 2023 22:40:08 -0500 Subject: [PATCH 11/93] a whole lot of nothing --- examples/dashboard/java/PanelRendering.java | 2 +- wayland/cc/LayerGLWayland.cc | 6 +++++- wayland/cc/LayerRasterWayland.cc | 9 +++------ wayland/cc/ShmPool.cc | 3 ++- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/examples/dashboard/java/PanelRendering.java b/examples/dashboard/java/PanelRendering.java index a40b4a0a..4d215ccf 100644 --- a/examples/dashboard/java/PanelRendering.java +++ b/examples/dashboard/java/PanelRendering.java @@ -35,7 +35,7 @@ else if (Platform.CURRENT == Platform.WINDOWS) else if (Platform.CURRENT == Platform.X11) layers = new String[] { "LayerGLSkija", "LayerRasterSkija" }; else if (Platform.CURRENT == Platform.WAYLAND) - layers = new String[] { "LayerRasterSkija" }; + layers = new String[] { "LayerGLSkija", "LayerRasterSkija" }; for (var layerName: layers) layersStatus.put(layerName, UNKNOWN); diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index bf0e6ab9..e013cc31 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -6,6 +6,7 @@ #include "WindowWayland.hh" #include #include +#include #include #include "ILayerWayland.hh" @@ -26,12 +27,15 @@ namespace jwm { void attach(WindowWayland* window) { eglBindAPI(EGL_OPENGL_API); fWindow = jwm::ref(window); + bool shouldReopen = false; if (window->_layer) { // HACK: close window and reopen window->close(); - window->init(); + shouldReopen = window->_visible; } fWindow->setLayer(this); + if (shouldReopen) + window->show(); if (_display == nullptr) { _display = eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_KHR, window->_windowManager.display, nullptr); diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index 8e603f1c..20124c97 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -15,7 +15,6 @@ namespace jwm { wl_buffer* _buffer = nullptr; uint8_t* _imageData = nullptr; ShmPool* _pool = nullptr; - VSync _vsync = VSYNC_ENABLED; bool _attached = false; LayerRaster() = default; @@ -36,6 +35,8 @@ namespace jwm { int bufSize = stride * height * 2; // TODO: better pool impl if (_pool) { + // TODO: don't mem leak : ) + // This memleaks - munmap causes skija to error out : / _pool->close(); } _pool = new ShmPool(fWindow->_windowManager.shm, bufSize); @@ -47,8 +48,7 @@ namespace jwm { _imageData = nullptr; } - // LSBFirst means Little endian : ) - // This will highly likely cause issues : ) + // : ) auto buf = _pool->createBuffer(0, width, height, stride, WL_SHM_FORMAT_ARGB8888); _buffer = buf.first; @@ -68,7 +68,6 @@ namespace jwm { } void swapBuffers() { - // : ) if (fWindow->_waylandWindow && _attached) { wl_surface_damage_buffer(fWindow->_waylandWindow, 0, 0, INT32_MAX, INT32_MAX); wl_surface_commit(fWindow->_waylandWindow); @@ -92,8 +91,6 @@ namespace jwm { } void setVsyncMode(VSync v) override { - // srsly, why do I need this - _vsync = v; } void attachBuffer() override { diff --git a/wayland/cc/ShmPool.cc b/wayland/cc/ShmPool.cc index b6c3a0de..353c1d3d 100644 --- a/wayland/cc/ShmPool.cc +++ b/wayland/cc/ShmPool.cc @@ -31,11 +31,12 @@ ShmPool::ShmPool(wl_shm* shm, size_t size): } ShmPool::~ShmPool() { - + close(); } void ShmPool::close() { wl_shm_pool_destroy(_pool); ::close(_fd); + // munmap(_rawData, _size); } void ShmPool::grow(size_t size) { From 9c543c09ba61a567cf4f4dea639e75504a505e76 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Thu, 7 Dec 2023 14:29:36 -0500 Subject: [PATCH 12/93] Start switch to libdecor (crashes) --- script/build_utils.py | 4 +- script/run.py | 3 +- shared/java/skija/LayerGLSkija.java | 2 +- wayland/CMakeLists.txt | 2 +- wayland/cc/ILayerWayland.hh | 1 + wayland/cc/LayerGLWayland.cc | 40 +++++++++++--- wayland/cc/LayerRasterWayland.cc | 8 +-- wayland/cc/Output.cc | 31 +++++++++++ wayland/cc/Output.hh | 24 ++++++++ wayland/cc/ShmPool.cc | 2 +- wayland/cc/WindowManagerWayland.cc | 85 ++++++++++++++++++++++------- wayland/cc/WindowManagerWayland.hh | 8 ++- wayland/cc/WindowWayland.cc | 72 +++++++++++++++++++++--- wayland/cc/WindowWayland.hh | 9 +++ 14 files changed, 242 insertions(+), 49 deletions(-) create mode 100644 wayland/cc/Output.cc create mode 100644 wayland/cc/Output.hh diff --git a/script/build_utils.py b/script/build_utils.py index f32d3383..1067db9f 100644 --- a/script/build_utils.py +++ b/script/build_utils.py @@ -121,7 +121,7 @@ def jar(target: str, *content: List[Tuple[str, str]]) -> str: @functools.lru_cache(maxsize=1) def lombok(): - return fetch_maven('org.projectlombok', 'lombok', '1.18.22') + return fetch_maven('org.projectlombok', 'lombok', '1.18.30') def delombok(dirs: List[str], target: str, classpath: List[str] = [], modulepath: List[str] = []): sources = files(*[dir + "/**/*.java" for dir in dirs]) @@ -248,4 +248,4 @@ def fetch(path, data = None): "stagedRepositoryIds":[repo_id] }}) print('Success! Just released', repo_id) - return 0 \ No newline at end of file + return 0 diff --git a/script/run.py b/script/run.py index e90cbe7e..4ba67860 100755 --- a/script/run.py +++ b/script/run.py @@ -47,8 +47,7 @@ def main(): if args.skija_dir: classpath += [ - skija_dir + '/platform/build', - skija_dir + '/platform/target/classes', + skija_dir + '/platform/target/' + build_utils.system + '-' + build_utils.arch + '/classes', ] elif args.skija_platform_jar: classpath += [ diff --git a/shared/java/skija/LayerGLSkija.java b/shared/java/skija/LayerGLSkija.java index 9862a675..b543cd2f 100644 --- a/shared/java/skija/LayerGLSkija.java +++ b/shared/java/skija/LayerGLSkija.java @@ -82,4 +82,4 @@ public void close() { super.close(); } -} \ No newline at end of file +} diff --git a/wayland/CMakeLists.txt b/wayland/CMakeLists.txt index d323fd85..04947745 100644 --- a/wayland/CMakeLists.txt +++ b/wayland/CMakeLists.txt @@ -29,8 +29,8 @@ find_library(WAYLAND_CURSOR wayland-cursor) find_library(XKBCOMMON xkbcommon) find_library(EGL EGL) find_library(WAYLAND_EGL wayland-egl) +# find_library(OPENGL_ES2 GLESv2) find_package(OpenGL REQUIRED) - set(JAVA_HOME $ENV{JAVA_HOME}) if (NOT JAVA_HOME) file(GLOB JAVA_HOMES "/usr/lib/jvm/java-*") diff --git a/wayland/cc/ILayerWayland.hh b/wayland/cc/ILayerWayland.hh index 45a0dafa..d05ee848 100644 --- a/wayland/cc/ILayerWayland.hh +++ b/wayland/cc/ILayerWayland.hh @@ -6,5 +6,6 @@ namespace jwm { class ILayerWayland: public ILayer { public: virtual void attachBuffer() = 0; + virtual void swapBuffers() = 0; }; } diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index e013cc31..27f6c93c 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -4,10 +4,11 @@ #include "impl/Library.hh" #include "impl/RefCounted.hh" #include "WindowWayland.hh" +#include #include #include +#include #include -#include #include "ILayerWayland.hh" namespace jwm { @@ -16,6 +17,7 @@ namespace jwm { public: WindowWayland* fWindow; wl_egl_window* _eglWindow = nullptr; + wl_region* _region = nullptr; EGLContext _context = nullptr; EGLDisplay _display = nullptr; EGLSurface _surface = nullptr; @@ -37,29 +39,41 @@ namespace jwm { if (shouldReopen) window->show(); if (_display == nullptr) { - _display = eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_KHR, window->_windowManager.display, nullptr); + _display = eglGetDisplay(window->_windowManager.display); eglInitialize(_display, nullptr, nullptr); } if (_context == nullptr) { EGLint attrList[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_ALPHA_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_NONE }; + EGLint contextAttr[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE + }; EGLint numConfig; - eglChooseConfig(_display, attrList, &_config, 1, &numConfig); + if ( ( eglGetConfigs(_display, nullptr, 0, &numConfig) != EGL_TRUE) || (numConfig == 0) ) { + throw std::runtime_error("No configuration"); + } + if ( ( eglChooseConfig(_display, attrList, &_config, 1, &numConfig) != EGL_TRUE) || (numConfig != 1)) { + throw std::runtime_error("No/Amibguous configuration"); + } // :troll: _context = eglCreateContext(_display, _config, EGL_NO_CONTEXT, - nullptr); + contextAttr); + if ( _context == EGL_NO_CONTEXT ) { + throw std::runtime_error("Couldn't make context"); + } } - makeCurrentForced(); } @@ -80,7 +94,7 @@ namespace jwm { wl_egl_window_resize(_eglWindow, width, height, 0, 0); } - void swapBuffers() { + void swapBuffers() override { eglSwapBuffers(_display, _surface); } @@ -99,8 +113,17 @@ namespace jwm { void attachBuffer() override { if (fWindow && fWindow->_waylandWindow) { if (!_eglWindow) { + // _region = wl_compositor_create_region(fWindow->_windowManager.compositor); + // wl_region_add(_region, 0, 0, fWindow->getWidth(), fWindow->getHeight()); + // wl_surface_set_opaque_region(fWindow->_waylandWindow, _region); + _eglWindow = wl_egl_window_create(fWindow->_waylandWindow, fWindow->getWidth(), fWindow->getHeight()); - _surface = eglCreatePlatformWindowSurface(_display, _config, _eglWindow, nullptr); + _surface = eglCreateWindowSurface(_display, _config, _eglWindow, nullptr); + + if ( _eglWindow == EGL_NO_SURFACE ) { + throw std::runtime_error("couldn't get surface"); + } + makeCurrentForced(); } } } @@ -120,9 +143,12 @@ extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerGL__1nAttach (JNIEnv* env, jobject obj, jobject windowObj) { try { jwm::LayerGL* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + printf("instance good : )\n"); jwm::WindowWayland* window = reinterpret_cast(jwm::classes::Native::fromJava(env, windowObj)); + printf("window good : )\n"); instance->attach(window); } catch (const std::exception& e) { + printf("%s\n", e.what()); jwm::classes::Throwable::throwLayerNotSupportedException(env, "Failed to init OpenGL"); } } diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index 20124c97..4198d675 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -5,7 +5,7 @@ #include "impl/RefCounted.hh" #include "WindowWayland.hh" #include "ShmPool.hh" -#include +#include namespace jwm { class LayerRaster: public RefCounted, public ILayerWayland { @@ -47,9 +47,8 @@ namespace jwm { wl_buffer_destroy(_buffer); _imageData = nullptr; } - // : ) - auto buf = _pool->createBuffer(0, width, height, stride, WL_SHM_FORMAT_ARGB8888); + auto buf = _pool->createBuffer(0, width, height, stride, WL_SHM_FORMAT_XRGB8888); _buffer = buf.first; _imageData = buf.second; @@ -67,7 +66,7 @@ namespace jwm { return _width * sizeof(uint32_t); } - void swapBuffers() { + void swapBuffers() override { if (fWindow->_waylandWindow && _attached) { wl_surface_damage_buffer(fWindow->_waylandWindow, 0, 0, INT32_MAX, INT32_MAX); wl_surface_commit(fWindow->_waylandWindow); @@ -97,6 +96,7 @@ namespace jwm { if (fWindow) { if (fWindow->_waylandWindow) { wl_surface_attach(fWindow->_waylandWindow, _buffer, 0, 0); + wl_surface_damage_buffer(fWindow->_waylandWindow, 0, 0, INT32_MAX, INT32_MAX); wl_surface_commit(fWindow->_waylandWindow); _attached = true; } diff --git a/wayland/cc/Output.cc b/wayland/cc/Output.cc new file mode 100644 index 00000000..356aefe4 --- /dev/null +++ b/wayland/cc/Output.cc @@ -0,0 +1,31 @@ +#include "Output.hh" + +using namespace jwm; + +wl_output_listener Output::_outputListener = { + .geometry = Output::outputGeometry, + .mode = Output::outputMode, + .done = Output::outputDone, + .scale = Output::outputScale, + .name = Output::outputName, + .description = Output::outputDescription +}; +Output::Output(wl_output* output, uint32_t name): + _output(output), + _name(name) + { + wl_output_add_listener(output, &_outputListener, this); + } +void Output::outputGeometry(void* data, wl_output* output, int x, int y, int physWidth, int physHeight, + int subPixel, const char* make, const char* model, int transform) {} +void Output::outputMode(void* data, wl_output* output, uint32_t flags, int width, int height, int refresh) {} +void Output::outputDone(void* data, wl_output* output) {} +void Output::outputScale(void* data, wl_output* output, int factor) { + Output* self = reinterpret_cast(data); + self->scale = factor; +} +void Output::outputName(void* data, wl_output* output, const char* name) { + +} +void Output::outputDescription(void* data, wl_output* output, const char* desc) {} + diff --git a/wayland/cc/Output.hh b/wayland/cc/Output.hh new file mode 100644 index 00000000..1c6763b1 --- /dev/null +++ b/wayland/cc/Output.hh @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +namespace jwm { + class Output { + public: + Output(wl_output* output, uint32_t name); + + wl_output* _output; + uint32_t _name; + int scale = 1; + + static wl_output_listener _outputListener; + static void outputGeometry(void* data, wl_output* output, int x, int y, int physWidth, int physHeight, + int subPixel, const char* make, const char* model, int transform); + static void outputMode(void* data, wl_output* output, uint32_t flags, int width, int height, int refresh); + static void outputDone(void* data, wl_output* output); + static void outputScale(void* data, wl_output* output, int factor); + static void outputName(void* data, wl_output* output, const char* name); + static void outputDescription(void* data, wl_output* output, const char* desc); + }; +} diff --git a/wayland/cc/ShmPool.cc b/wayland/cc/ShmPool.cc index 353c1d3d..fa429540 100644 --- a/wayland/cc/ShmPool.cc +++ b/wayland/cc/ShmPool.cc @@ -25,9 +25,9 @@ ShmPool::ShmPool(wl_shm* shm, size_t size): // why : ( throw std::system_error(EIO, std::generic_category(), "Couldn't allocate buffer"); } - _pool = wl_shm_create_pool(shm, _fd, size); _rawData = (uint8_t*)mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0); + _pool = wl_shm_create_pool(shm, _fd, size); } ShmPool::~ShmPool() { diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 50b88e41..6ae31f55 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -16,6 +16,9 @@ #include "Log.hh" #include #include +#include "Output.hh" +#include +#include using namespace jwm; @@ -34,13 +37,16 @@ xdg_wm_base_listener WindowManagerWayland::_xdgWmBaseListener = { .ping = WindowManagerWayland::xdgWmBasePing }; +libdecor_interface WindowManagerWayland::_decorInterface = { + .error = WindowManagerWayland::libdecorError +}; WindowManagerWayland::WindowManagerWayland(): display(wl_display_connect(nullptr)) { registry = wl_display_get_registry(display); wl_registry_add_listener(registry, &_registryListener, this); wl_display_roundtrip(display); - + if (!(shm && xdgShell && compositor && deviceManager && seat)) { @@ -50,6 +56,7 @@ WindowManagerWayland::WindowManagerWayland(): } + decorCtx = libdecor_new(display, &_decorInterface); // frankly `this` is not needed here, but it needs a pointer anyway and it's // good to have consistentcy. @@ -107,7 +114,11 @@ void WindowManagerWayland::runLoop() { notifyFD = pipes[1]; fcntl(pipes[1], F_SETFL, O_NONBLOCK); // notifyLoop no blockie : ) struct pollfd wayland_out = {.fd=wl_display_get_fd(display),.events=POLLOUT}; - struct pollfd ps[] = {{.fd=wl_display_get_fd(display), .events=POLLIN}, {.fd=pipes[0], .events=POLLIN}}; + struct pollfd ps[] = { + {.fd=wl_display_get_fd(display), .events=POLLIN}, + {.fd=pipes[0], .events=POLLIN}, + {.fd=libdecor_get_fd(decorCtx), .events=POLLIN} + }; // who be out here running they loop while (_runLoop) { if (jwm::classes::Throwable::exceptionThrown(app.getJniEnv())) @@ -138,7 +149,7 @@ void WindowManagerWayland::runLoop() { } // block until event : ) - if (poll(&ps[0], 2, -1) < 0) { + if (poll(&ps[0], 3, -1) < 0) { printf("error with pipe\n"); break; } @@ -151,6 +162,9 @@ void WindowManagerWayland::runLoop() { } else { wl_display_cancel_read(display); } + if (ps[2].revents & POLLIN) { + libdecor_dispatch(decorCtx, -1); + } wl_display_dispatch_pending(display); notifyBool.store(false); } @@ -161,6 +175,11 @@ void WindowManagerWayland::runLoop() { } +void WindowManagerWayland::libdecorError(libdecor* context, enum libdecor_error error, const char* message) { + // ??? + fprintf(stderr, "Caught error (%d): %s\n", error, message); + throw std::runtime_error("lib decor error > : ("); +} void WindowManagerWayland::_processCallbacks() { { // process ui thread callbacks @@ -212,10 +231,22 @@ void WindowManagerWayland::registryHandleGlobal(void* data, wl_registry *registr } else if (strcmp(interface, wl_seat_interface.name) == 0) { self->seat = (wl_seat*)wl_registry_bind(registry, name, &wl_seat_interface, 1); + } else if (strcmp(interface, wl_output_interface.name) == 0) { + wl_output* output = (wl_output*)wl_registry_bind(registry, name, + &wl_output_interface, 2); + Output* good = new Output(output, name); + self->outputs.push_back(good); } } void WindowManagerWayland::registryHandleGlobalRemove(void* data, wl_registry *registry, uint32_t name) { - // i do nothing : ) + auto self = reinterpret_cast(data); + for (std::list::iterator it = self->outputs.begin(); it != self->outputs.end();) { + if ((*it)->_name == name) { + self->outputs.erase(it); + break; + } + ++it; + } } void WindowManagerWayland::pointerHandleEnter(void* data, wl_pointer* pointer, uint32_t serial, @@ -235,11 +266,11 @@ void WindowManagerWayland::pointerHandleLeave(void* data, wl_pointer* pointer, u void WindowManagerWayland::pointerHandleMotion(void* data, wl_pointer* pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { WindowManagerWayland* self = (WindowManagerWayland*)data; - self->lastMousePosX = surface_x; - self->lastMousePosY = surface_y; if (self->focusedSurface) { - ::WindowWayland* window = self->_nativeWindowToMy.find(self->focusedSurface)->second; - self->mouseUpdate(window, wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y), self->mouseMask); + ::WindowWayland* window = reinterpret_cast<::WindowWayland*>(wl_surface_get_user_data(self->focusedSurface)); + // God is dead if window is null + if (window) + self->mouseUpdate(window, wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y), self->mouseMask); } } @@ -247,19 +278,20 @@ void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { using namespace classes; WindowManagerWayland* self = (WindowManagerWayland*)data; + if (!self->focusedSurface) return; if (state == 0) { // release switch (button) { // primary - case 0x110: + case BTN_LEFT: self->mouseMask &= ~0x100; break; // secondary - case 0x111: + case BTN_RIGHT: self->mouseMask &= ~0x400; break; // middle - case 0x112: + case BTN_MIDDLE: self->mouseMask &= ~0x200; break; default: @@ -278,22 +310,23 @@ void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, jwm::KeyWayland::getModifiers() ) ); - WindowWayland* window = self->_nativeWindowToMy.find(self->focusedSurface)->second; - window->dispatch(eventButton.get()); + WindowWayland* window = reinterpret_cast(wl_surface_get_user_data(self->focusedSurface)); + if (window) + window->dispatch(eventButton.get()); } } else { // down switch (button) { // primary - case 0x110: + case BTN_LEFT: self->mouseMask |= 0x100; break; // secondary - case 0x111: + case BTN_RIGHT: self->mouseMask |= 0x400; break; // middle - case 0x112: + case BTN_MIDDLE: self->mouseMask |= 0x200; break; default: @@ -312,8 +345,10 @@ void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, jwm::KeyWayland::getModifiers() ) ); - WindowWayland* window = self->_nativeWindowToMy.find(self->focusedSurface)->second; - window->dispatch(eventButton.get()); + // me when this stuff is NULL : ( + WindowWayland* window = reinterpret_cast(wl_surface_get_user_data(self->focusedSurface)); + if (window) + window->dispatch(eventButton.get()); } } } @@ -387,9 +422,14 @@ std::vector WindowManagerWayland::getClipboardFormats() { } void WindowManagerWayland::mouseUpdate(WindowWayland* myWindow, uint32_t x, uint32_t y, uint32_t mask) { using namespace classes; - + if (!myWindow) + return; // impl me : ) + if (lastMousePosX == x && lastMousePosY == y) return; + lastMousePosX = x; + lastMousePosY = y; int movementX = 0, movementY = 0; + printf("mouse update: %i %i\n", x, y); jwm::JNILocal eventMove( app.getJniEnv(), EventMouseMove::make(app.getJniEnv(), @@ -399,10 +439,13 @@ void WindowManagerWayland::mouseUpdate(WindowWayland* myWindow, uint32_t x, uint movementY, jwm::MouseButtonWayland::fromNativeMask(mask), // impl me! - jwm::KeyWayland::getModifiersFromMask(0) + jwm::KeyWayland::getModifiers() ) ); - myWindow->dispatch(eventMove.get()); + auto foo = eventMove.get(); + printf("??? %x\n", foo); + myWindow->dispatch(foo); + printf("??????\n"); } jwm::ByteBuf WindowManagerWayland::getClipboardContents(const std::string& type) { auto nativeHandle = _nativeWindowToMy.begin()->first; diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index a5ecf0ec..4349347f 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -14,6 +14,9 @@ #include #include #include "xdg-shell/xdg-shell.h" +#include +#include "Output.hh" +#include namespace jwm { class WindowWayland; @@ -76,6 +79,8 @@ namespace jwm { static xdg_wm_base_listener _xdgWmBaseListener; static void xdgWmBasePing(void* data, xdg_wm_base* base, uint32_t serial); + static libdecor_interface _decorInterface; + static void libdecorError(libdecor* context, enum libdecor_error error, const char* message); ByteBuf getClipboardContents(const std::string& type); std::vector getClipboardFormats(); @@ -88,7 +93,8 @@ namespace jwm { wl_data_device_manager* deviceManager = nullptr; wl_seat* seat = nullptr; wl_pointer* pointer = nullptr; - + libdecor* decorCtx = nullptr; + std::list outputs; // XVisualInfo* x11VisualInfo; // XSetWindowAttributes x11SWA; diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index ab21dfc4..1dec4e34 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -34,12 +34,16 @@ wl_output_listener WindowWayland::_outputListener = { .name = WindowWayland::outputName, .description = WindowWayland::outputDescription }; +libdecor_frame_interface WindowWayland::_libdecorFrameInterface = { + .configure = WindowWayland::decorFrameConfigure, + .close = WindowWayland::decorFrameClose, + .commit = WindowWayland::decorFrameCommit, + .dismiss_popup = WindowWayland::decorFrameDismissPopup +}; + WindowWayland::WindowWayland(JNIEnv* env, WindowManagerWayland& windowManager): jwm::Window(env), - _windowManager(windowManager), - // HACK: have a default height bc some compositors won't hecking tell me :sob: - _width(100), - _height(100) + _windowManager(windowManager) { } @@ -139,12 +143,16 @@ void WindowWayland::show() { _waylandWindow = wl_compositor_create_surface(_windowManager.compositor); wl_surface_add_listener(_waylandWindow, &_surfaceListener, this); + // unsure if listener data and user data are the same, so i do this for safety : ) + wl_surface_set_user_data(_waylandWindow, this); + + // xdgSurface = xdg_wm_base_get_xdg_surface(_windowManager.xdgShell, _waylandWindow); + // xdg_surface_add_listener(xdgSurface, &_xdgSurfaceListener, this); - xdgSurface = xdg_wm_base_get_xdg_surface(_windowManager.xdgShell, _waylandWindow); - xdg_surface_add_listener(xdgSurface, &_xdgSurfaceListener, this); + // xdgToplevel = xdg_surface_get_toplevel(xdgSurface); + // xdg_toplevel_add_listener(xdgToplevel, &_xdgToplevelListener, this); - xdgToplevel = xdg_surface_get_toplevel(xdgSurface); - xdg_toplevel_add_listener(xdgToplevel, &_xdgToplevelListener, this); + _frame = libdecor_decorate(_windowManager.decorCtx, _waylandWindow, &_libdecorFrameInterface, this); _windowManager.registerWindow(this); wl_surface_commit(_waylandWindow); } @@ -185,7 +193,18 @@ void jwm::WindowWayland::setCursor(jwm::MouseCursor cursor) { // what do??? void jwm::WindowWayland::surfaceEnter(void* data, wl_surface* surface, wl_output* output) { // doesn't crash : ) - wl_output_add_listener(output, &_outputListener, data); + WindowWayland* self = reinterpret_cast(data); + + Output* good; + + for (auto o : self->_windowManager.outputs) { + if (o->_output == output) { + self->_scale = o->scale; + wl_surface_set_buffer_scale(surface, o->scale); + self->_adaptSize(self->_width, self->_height); + break; + } + } } void jwm::WindowWayland::surfaceLeave(void* data, wl_surface* surface, wl_output* output) {} void jwm::WindowWayland::surfacePreferredBufferScale(void* data, wl_surface* surface, int factor) { @@ -262,6 +281,41 @@ void jwm::WindowWayland::outputScale(void* data, wl_output* output, int factor) } void jwm::WindowWayland::outputName(void* data, wl_output* output, const char* name) {} void jwm::WindowWayland::outputDescription(void* data, wl_output* output, const char* desc) {} + +void jwm::WindowWayland::decorFrameConfigure(libdecor_frame* frame, libdecor_configuration* configuration, + void *userData) { + auto self = reinterpret_cast(userData); + int width = 0, height = 0; + + libdecor_configuration_get_content_size(configuration, frame, &width, &height); + + width = (width == 0) ? self->_floatingWidth : width; + height = (height == 0) ? self->_floatingHeight : height; + + libdecor_state* state = libdecor_state_new(width, height); + libdecor_frame_commit(frame, state, configuration); + libdecor_state_free(state); + + if (libdecor_frame_is_floating(frame)) { + self->_floatingWidth = width; + self->_floatingHeight = height; + } + + if (self->_layer) { + self->_layer->attachBuffer(); + } + self->_adaptSize(width, height); +} +void jwm::WindowWayland::decorFrameClose(libdecor_frame* frame, void* userData) { + WindowWayland* self = reinterpret_cast(userData); + self->dispatch(classes::EventWindowCloseRequest::kInstance); +} +void jwm::WindowWayland::decorFrameCommit(libdecor_frame* frame, void* userData) { + WindowWayland* self = reinterpret_cast(userData); + if (self->_layer) + self->dispatch(classes::EventFrame::kInstance); +} +void jwm::WindowWayland::decorFrameDismissPopup(libdecor_frame* frame, const char* seatName, void* userData) {} void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { _width = newWidth; _height = newHeight; diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index 80723915..db9dff9a 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -75,6 +75,12 @@ namespace jwm { static void outputName(void* data, wl_output* output, const char* name); static void outputDescription(void* data, wl_output* output, const char* desc); + + static void decorFrameConfigure(libdecor_frame* frame, libdecor_configuration* config, void* userData); + static void decorFrameClose(libdecor_frame* frame, void* userData); + static void decorFrameCommit(libdecor_frame* frame, void* userData); + static void decorFrameDismissPopup(libdecor_frame* frame, const char* seatName, void* userData); + void _adaptSize(int newWidth, int newHeight); @@ -87,6 +93,8 @@ namespace jwm { int _newHeight = -1; int _WM_ADD = 1L; int _WM_REMOVE = 0L; + int _floatingWidth = 400; + int _floatingHeight = 400; bool _canMinimize = false; bool _canMaximize = false; bool _canFullscreen = false; @@ -106,6 +114,7 @@ namespace jwm { static xdg_toplevel_listener _xdgToplevelListener; static wl_output_listener _outputListener; + static libdecor_frame_interface _libdecorFrameInterface; }; } From 7aa2820d97abafa76c8743f5fff0a3029b11d6c3 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Thu, 7 Dec 2023 18:24:35 -0500 Subject: [PATCH 13/93] Doesn't crash (doesn't render well) --- wayland/cc/LayerGLWayland.cc | 32 ++++++++--------- wayland/cc/WindowManagerWayland.cc | 56 ++++++++---------------------- wayland/cc/WindowManagerWayland.hh | 2 ++ wayland/cc/WindowWayland.cc | 42 +++++++++++++--------- wayland/cc/WindowWayland.hh | 4 ++- 5 files changed, 60 insertions(+), 76 deletions(-) diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index 27f6c93c..9d1cf492 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -27,28 +27,21 @@ namespace jwm { virtual ~LayerGL() = default; void attach(WindowWayland* window) { - eglBindAPI(EGL_OPENGL_API); fWindow = jwm::ref(window); - bool shouldReopen = false; - if (window->_layer) { - // HACK: close window and reopen - window->close(); - shouldReopen = window->_visible; - } fWindow->setLayer(this); - if (shouldReopen) - window->show(); if (_display == nullptr) { _display = eglGetDisplay(window->_windowManager.display); eglInitialize(_display, nullptr, nullptr); } + if ( eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) { + throw new std::runtime_error("Cannot bind EGL Api"); + } if (_context == nullptr) { EGLint attrList[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, - EGL_ALPHA_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, @@ -74,7 +67,7 @@ namespace jwm { } } - + makeCurrentForced(); } void setVsyncMode(VSync v) override { @@ -88,7 +81,7 @@ namespace jwm { glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); // ??? - glViewport(0, 0, width, height); + // glViewport(0, 0, width, height); // God is dead if _eglWindow is null if (_eglWindow) wl_egl_window_resize(_eglWindow, width, height, 0, 0); @@ -99,7 +92,16 @@ namespace jwm { } void close() override { + eglMakeCurrent(_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (_surface) { + eglDestroySurface(_display, _surface); + } + if (_eglWindow) { + wl_egl_window_destroy(_eglWindow); + } eglDestroyContext(_display, _context); + eglTerminate(_display); + jwm::unref(&fWindow); } @@ -116,15 +118,15 @@ namespace jwm { // _region = wl_compositor_create_region(fWindow->_windowManager.compositor); // wl_region_add(_region, 0, 0, fWindow->getWidth(), fWindow->getHeight()); // wl_surface_set_opaque_region(fWindow->_waylandWindow, _region); - + printf("%i %i\n", fWindow->getWidth(), fWindow->getHeight()); _eglWindow = wl_egl_window_create(fWindow->_waylandWindow, fWindow->getWidth(), fWindow->getHeight()); _surface = eglCreateWindowSurface(_display, _config, _eglWindow, nullptr); if ( _eglWindow == EGL_NO_SURFACE ) { throw std::runtime_error("couldn't get surface"); } - makeCurrentForced(); } + makeCurrentForced(); } } }; @@ -143,9 +145,7 @@ extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerGL__1nAttach (JNIEnv* env, jobject obj, jobject windowObj) { try { jwm::LayerGL* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); - printf("instance good : )\n"); jwm::WindowWayland* window = reinterpret_cast(jwm::classes::Native::fromJava(env, windowObj)); - printf("window good : )\n"); instance->attach(window); } catch (const std::exception& e) { printf("%s\n", e.what()); diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 6ae31f55..2df5df50 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -115,41 +115,16 @@ void WindowManagerWayland::runLoop() { fcntl(pipes[1], F_SETFL, O_NONBLOCK); // notifyLoop no blockie : ) struct pollfd wayland_out = {.fd=wl_display_get_fd(display),.events=POLLOUT}; struct pollfd ps[] = { - {.fd=wl_display_get_fd(display), .events=POLLIN}, + {.fd=libdecor_get_fd(decorCtx), .events=POLLIN}, {.fd=pipes[0], .events=POLLIN}, - {.fd=libdecor_get_fd(decorCtx), .events=POLLIN} }; // who be out here running they loop while (_runLoop) { if (jwm::classes::Throwable::exceptionThrown(app.getJniEnv())) _runLoop = false; _processCallbacks(); - while(wl_display_prepare_read(display) != 0) - wl_display_dispatch_pending(display); - // adapted from Waylock - while (true) { - int res = wl_display_flush(display); - if (res >= 0) - break; - - switch (errno) { - case EPIPE: - wl_display_read_events(display); - throw std::system_error(errno, std::generic_category(), "connection to wayland server unexpectedly terminated"); - break; - case EAGAIN: - if (poll(&wayland_out, 1, -1) < 0) { - throw std::system_error(EPIPE, std::generic_category(), "poll failed"); - } - break; - default: - throw std::system_error(errno, std::generic_category(), "failed to flush requests"); - break; - } - - } // block until event : ) - if (poll(&ps[0], 3, -1) < 0) { + if (poll(&ps[0], 2, -1) < 0) { printf("error with pipe\n"); break; } @@ -157,15 +132,8 @@ void WindowManagerWayland::runLoop() { while (read(pipes[0], buf, sizeof(buf)) == sizeof(buf)) { } } if (ps[0].revents & POLLIN) { - // WHY IN THE WORLD IS THIS CRASHING - wl_display_read_events(display); - } else { - wl_display_cancel_read(display); - } - if (ps[2].revents & POLLIN) { libdecor_dispatch(decorCtx, -1); } - wl_display_dispatch_pending(display); notifyBool.store(false); } @@ -248,13 +216,20 @@ void WindowManagerWayland::registryHandleGlobalRemove(void* data, wl_registry *r ++it; } } - +WindowWayland* WindowManagerWayland::getWindowForNative(wl_surface* surface) { + WindowWayland* myWindow = nullptr; + auto it = _nativeWindowToMy.find(surface); + if (it != _nativeWindowToMy.end()) + myWindow = it->second; + return myWindow; +} void WindowManagerWayland::pointerHandleEnter(void* data, wl_pointer* pointer, uint32_t serial, wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { WindowManagerWayland* self = (WindowManagerWayland*)data; wl_cursor_image* image = self->_cursors[static_cast(jwm::MouseCursor::ARROW)]; wl_pointer_set_cursor(pointer, serial, self->cursorSurface, image->hotspot_x, image->hotspot_y); - self->focusedSurface = surface; + if (self->getWindowForNative(surface)) + self->focusedSurface = surface; } void WindowManagerWayland::pointerHandleLeave(void* data, wl_pointer* pointer, uint32_t serial, wl_surface *surface) { @@ -267,7 +242,7 @@ void WindowManagerWayland::pointerHandleMotion(void* data, wl_pointer* pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { WindowManagerWayland* self = (WindowManagerWayland*)data; if (self->focusedSurface) { - ::WindowWayland* window = reinterpret_cast<::WindowWayland*>(wl_surface_get_user_data(self->focusedSurface)); + ::WindowWayland* window = self->getWindowForNative(self->focusedSurface); // God is dead if window is null if (window) self->mouseUpdate(window, wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y), self->mouseMask); @@ -310,7 +285,7 @@ void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, jwm::KeyWayland::getModifiers() ) ); - WindowWayland* window = reinterpret_cast(wl_surface_get_user_data(self->focusedSurface)); + WindowWayland* window = self->getWindowForNative(self->focusedSurface); if (window) window->dispatch(eventButton.get()); } @@ -346,7 +321,7 @@ void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, ) ); // me when this stuff is NULL : ( - WindowWayland* window = reinterpret_cast(wl_surface_get_user_data(self->focusedSurface)); + WindowWayland* window = self->getWindowForNative(self->focusedSurface); if (window) window->dispatch(eventButton.get()); } @@ -429,7 +404,6 @@ void WindowManagerWayland::mouseUpdate(WindowWayland* myWindow, uint32_t x, uint lastMousePosX = x; lastMousePosY = y; int movementX = 0, movementY = 0; - printf("mouse update: %i %i\n", x, y); jwm::JNILocal eventMove( app.getJniEnv(), EventMouseMove::make(app.getJniEnv(), @@ -443,9 +417,7 @@ void WindowManagerWayland::mouseUpdate(WindowWayland* myWindow, uint32_t x, uint ) ); auto foo = eventMove.get(); - printf("??? %x\n", foo); myWindow->dispatch(foo); - printf("??????\n"); } jwm::ByteBuf WindowManagerWayland::getClipboardContents(const std::string& type) { auto nativeHandle = _nativeWindowToMy.begin()->first; diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index 4349347f..eb872036 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -55,6 +55,8 @@ namespace jwm { void notifyLoop(); void enqueueTask(const std::function& task); + WindowWayland* getWindowForNative(wl_surface* surface); + static wl_registry_listener _registryListener; static void registryHandleGlobal(void* data, wl_registry *registry, diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index 1dec4e34..a9dbae2b 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -75,7 +75,11 @@ void WindowWayland::close() { xdg_toplevel_destroy(xdgToplevel); } xdgToplevel = nullptr; - + if (_frame) { + libdecor_frame_unref(_frame); + } + _frame = nullptr; + _configured = false; } void WindowWayland::maximize() { // impl me :) @@ -126,11 +130,11 @@ int WindowWayland::getTop() { } int WindowWayland::getWidth() { - return _width; + return _width <= 0 ? _floatingWidth : _width; } int WindowWayland::getHeight() { - return _height; + return _height <= 0 ? _floatingHeight : _height; } float WindowWayland::getScale() { @@ -152,16 +156,11 @@ void WindowWayland::show() // xdgToplevel = xdg_surface_get_toplevel(xdgSurface); // xdg_toplevel_add_listener(xdgToplevel, &_xdgToplevelListener, this); - _frame = libdecor_decorate(_windowManager.decorCtx, _waylandWindow, &_libdecorFrameInterface, this); _windowManager.registerWindow(this); - wl_surface_commit(_waylandWindow); -} - -// ??? -void WindowWayland::recreate() -{ - close(); - init(); + _frame = libdecor_decorate(_windowManager.decorCtx, _waylandWindow, &_libdecorFrameInterface, this); + _configured = false; + libdecor_frame_map(_frame); + libdecor_dispatch(_windowManager.decorCtx, -1); } void WindowWayland::setVisible(bool isVisible) { @@ -195,8 +194,6 @@ void jwm::WindowWayland::surfaceEnter(void* data, wl_surface* surface, wl_output // doesn't crash : ) WindowWayland* self = reinterpret_cast(data); - Output* good; - for (auto o : self->_windowManager.outputs) { if (o->_output == output) { self->_scale = o->scale; @@ -282,6 +279,12 @@ void jwm::WindowWayland::outputScale(void* data, wl_output* output, int factor) void jwm::WindowWayland::outputName(void* data, wl_output* output, const char* name) {} void jwm::WindowWayland::outputDescription(void* data, wl_output* output, const char* desc) {} +wl_callback_listener jwm::WindowWayland::_frameCallback = { + .done = [](void* data, wl_callback* cb, uint32_t cb_data) { + auto self = reinterpret_cast(data); + self->_adaptSize(self->_newWidth, self->_newHeight); + } +}; void jwm::WindowWayland::decorFrameConfigure(libdecor_frame* frame, libdecor_configuration* configuration, void *userData) { auto self = reinterpret_cast(userData); @@ -301,10 +304,15 @@ void jwm::WindowWayland::decorFrameConfigure(libdecor_frame* frame, libdecor_con self->_floatingHeight = height; } - if (self->_layer) { + if (!self->_configured && self->_layer) { self->_layer->attachBuffer(); } - self->_adaptSize(width, height); + self->_newWidth = width; + self->_newHeight = height; + wl_callback* callback = wl_surface_frame(self->_waylandWindow); + // Throttle frame + wl_callback_add_listener(callback, &_frameCallback, self); + self->_configured = true; } void jwm::WindowWayland::decorFrameClose(libdecor_frame* frame, void* userData) { WindowWayland* self = reinterpret_cast(userData); @@ -313,7 +321,7 @@ void jwm::WindowWayland::decorFrameClose(libdecor_frame* frame, void* userData) void jwm::WindowWayland::decorFrameCommit(libdecor_frame* frame, void* userData) { WindowWayland* self = reinterpret_cast(userData); if (self->_layer) - self->dispatch(classes::EventFrame::kInstance); + self->_layer->swapBuffers(); } void jwm::WindowWayland::decorFrameDismissPopup(libdecor_frame* frame, const char* seatName, void* userData) {} void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index db9dff9a..2ded4bd4 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -20,7 +20,6 @@ namespace jwm { void close(); bool init(); void show(); - void recreate(); int getLeft(); int getTop(); int getWidth(); @@ -99,6 +98,7 @@ namespace jwm { bool _canMaximize = false; bool _canFullscreen = false; bool _visible = false; + bool _configured = false; bool _isRedrawRequested = false; @@ -116,5 +116,7 @@ namespace jwm { static wl_output_listener _outputListener; static libdecor_frame_interface _libdecorFrameInterface; + static wl_callback_listener _frameCallback; + }; } From e42583de4bf7bfd43f652441b13820c9b9dffac8 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Thu, 7 Dec 2023 22:40:45 -0500 Subject: [PATCH 14/93] start input --- wayland/cc/KeyWayland.cc | 281 ++++++++++++++--------------- wayland/cc/KeyWayland.hh | 7 +- wayland/cc/LayerGLWayland.cc | 2 +- wayland/cc/LayerRasterWayland.cc | 2 - wayland/cc/Output.cc | 15 +- wayland/cc/Output.hh | 5 + wayland/cc/ScreenInfo.cc | 2 +- wayland/cc/ScreenInfo.hh | 1 + wayland/cc/WindowManagerWayland.cc | 204 ++++++++++++++------- wayland/cc/WindowManagerWayland.hh | 24 +++ wayland/cc/WindowWayland.cc | 59 +++++- wayland/cc/WindowWayland.hh | 4 +- wayland/java/WindowWayland.java | 15 +- 13 files changed, 393 insertions(+), 228 deletions(-) diff --git a/wayland/cc/KeyWayland.cc b/wayland/cc/KeyWayland.cc index 7a16be98..9c21f662 100644 --- a/wayland/cc/KeyWayland.cc +++ b/wayland/cc/KeyWayland.cc @@ -1,28 +1,23 @@ #include "KeyWayland.hh" #include "KeyModifier.hh" +#include +#include -bool gKeyStates[(std::size_t) jwm::Key::_KEY_COUNT] = {0}; +int jwm::KeyWayland::getModifiers(xkb_state* state) { -bool jwm::KeyWayland::getKeyState(jwm::Key key) { - return gKeyStates[(std::size_t) key]; -} - -void jwm::KeyWayland::setKeyState(jwm::Key key, bool isDown) { - gKeyStates[(std::size_t) key] = isDown; -} - -int jwm::KeyWayland::getModifiers() { int m = 0; - - if (getKeyState(jwm::Key::SHIFT )) m |= (int)jwm::KeyModifier::SHIFT; - if (getKeyState(jwm::Key::CONTROL )) m |= (int)jwm::KeyModifier::CONTROL; - if (getKeyState(jwm::Key::ALT )) m |= (int)jwm::KeyModifier::ALT; - if (getKeyState(jwm::Key::LINUX_META )) m |= (int)jwm::KeyModifier::LINUX_META; - if (getKeyState(jwm::Key::LINUX_SUPER)) m |= (int)jwm::KeyModifier::LINUX_SUPER; + + if (!state) + return 0; + if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_SHIFT, XKB_STATE_MODS_EFFECTIVE)) m |= (int)jwm::KeyModifier::SHIFT; + if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL , XKB_STATE_MODS_EFFECTIVE)) m |= (int)jwm::KeyModifier::CONTROL; + if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT , XKB_STATE_MODS_EFFECTIVE)) m |= (int)jwm::KeyModifier::ALT; + if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_LOGO , XKB_STATE_MODS_EFFECTIVE)) m |= (int)jwm::KeyModifier::LINUX_META; + if (xkb_state_mod_name_is_active(state, "Super" , XKB_STATE_MODS_EFFECTIVE)) m |= (int)jwm::KeyModifier::LINUX_SUPER; return m; } - +/* int jwm::KeyWayland::getModifiersFromMask(int mask) { int m = getModifiers(); // ??? @@ -31,145 +26,143 @@ int jwm::KeyWayland::getModifiersFromMask(int mask) { // if (mask & Mod1Mask ) m |= (int)jwm::KeyModifier::ALT; return m; -} +}*/ -jwm::Key jwm::KeyWayland::fromNative(uint32_t v) { /* +jwm::Key jwm::KeyWayland::fromNative(uint32_t v) { switch (v) { // Modifiers - case XK_Caps_Lock: return Key::CAPS_LOCK; - case XK_Shift_R: - case XK_Shift_L: return Key::SHIFT; - case XK_Control_R: - case XK_Control_L: return Key::CONTROL; - case XK_Alt_R: - case XK_Alt_L: return Key::ALT; + case XKB_KEY_Caps_Lock: return Key::CAPS_LOCK; + case XKB_KEY_Shift_R: + case XKB_KEY_Shift_L: return Key::SHIFT; + case XKB_KEY_Control_R: + case XKB_KEY_Control_L: return Key::CONTROL; + case XKB_KEY_Alt_R: + case XKB_KEY_Alt_L: return Key::ALT; // Key::WIN_LOGO - case XK_Super_L: - case XK_Super_R: return Key::LINUX_SUPER; - case XK_Meta_L: - case XK_Meta_R: return Key::LINUX_META; + case XKB_KEY_Super_L: + case XKB_KEY_Super_R: return Key::LINUX_SUPER; + case XKB_KEY_Meta_L: + case XKB_KEY_Meta_R: return Key::LINUX_META; // Key::MAC_COMMAND // Key::MAC_OPTION // Key::MAC_FN // Rest of the keys - case XK_Return: return Key::ENTER; - case XK_BackSpace: return Key::BACKSPACE; - case XK_Tab: return Key::TAB; - case XK_Cancel: return Key::CANCEL; - case XK_Clear: return Key::CLEAR; - case XK_Pause: return Key::PAUSE; - case XK_Escape: return Key::ESCAPE; - case XK_space: return Key::SPACE; - case XK_Page_Up: return Key::PAGE_UP; - case XK_Page_Down: return Key::PAGE_DOWN; - case XK_End: return Key::END; - case XK_Home: return Key::HOME; - case XK_Left: return Key::LEFT; - case XK_Up: return Key::UP; - case XK_Right: return Key::RIGHT; - case XK_Down: return Key::DOWN; - case XK_comma: return Key::COMMA; - case XK_minus: return Key::MINUS; - case XK_period: return Key::PERIOD; - case XK_slash: return Key::SLASH; - case XK_0: return Key::DIGIT0; - case XK_1: return Key::DIGIT1; - case XK_2: return Key::DIGIT2; - case XK_3: return Key::DIGIT3; - case XK_4: return Key::DIGIT4; - case XK_5: return Key::DIGIT5; - case XK_6: return Key::DIGIT6; - case XK_7: return Key::DIGIT7; - case XK_8: return Key::DIGIT8; - case XK_9: return Key::DIGIT9; - case XK_semicolon: return Key::SEMICOLON; - case XK_equal: return Key::EQUALS; - case XK_a: return Key::A; - case XK_b: return Key::B; - case XK_c: return Key::C; - case XK_d: return Key::D; - case XK_e: return Key::E; - case XK_f: return Key::F; - case XK_g: return Key::G; - case XK_h: return Key::H; - case XK_i: return Key::I; - case XK_j: return Key::J; - case XK_k: return Key::K; - case XK_l: return Key::L; - case XK_m: return Key::M; - case XK_n: return Key::N; - case XK_o: return Key::O; - case XK_p: return Key::P; - case XK_q: return Key::Q; - case XK_r: return Key::R; - case XK_s: return Key::S; - case XK_t: return Key::T; - case XK_u: return Key::U; - case XK_v: return Key::V; - case XK_w: return Key::W; - case XK_x: return Key::X; - case XK_y: return Key::Y; - case XK_z: return Key::Z; - case XK_bracketleft: return Key::OPEN_BRACKET; - case XK_backslash: return Key::BACK_SLASH; - case XK_bracketright: return Key::CLOSE_BRACKET; - case XK_KP_0: return Key::DIGIT0; - case XK_KP_1: return Key::DIGIT1; - case XK_KP_2: return Key::DIGIT2; - case XK_KP_3: return Key::DIGIT3; - case XK_KP_4: return Key::DIGIT4; - case XK_KP_5: return Key::DIGIT5; - case XK_KP_6: return Key::DIGIT6; - case XK_KP_7: return Key::DIGIT7; - case XK_KP_8: return Key::DIGIT8; - case XK_KP_9: return Key::DIGIT9; - case XK_multiply: return Key::MULTIPLY; - case XK_KP_Add: return Key::ADD; - case XK_KP_Separator: return Key::SEPARATOR; - case XK_KP_Subtract: return Key::MINUS; - case XK_KP_Decimal: return Key::PERIOD; - case XK_KP_Divide: return Key::SLASH; - case XK_KP_Delete: return Key::DEL; - case XK_Delete: return Key::DEL; - case XK_Num_Lock: return Key::NUM_LOCK; - case XK_Scroll_Lock: return Key::SCROLL_LOCK; - case XK_F1: return Key::F1; - case XK_F2: return Key::F2; - case XK_F3: return Key::F3; - case XK_F4: return Key::F4; - case XK_F5: return Key::F5; - case XK_F6: return Key::F6; - case XK_F7: return Key::F7; - case XK_F8: return Key::F8; - case XK_F9: return Key::F9; - case XK_F10: return Key::F10; - case XK_F11: return Key::F11; - case XK_F12: return Key::F12; - case XK_F13: return Key::F13; - case XK_F14: return Key::F14; - case XK_F15: return Key::F15; - case XK_F16: return Key::F16; - case XK_F17: return Key::F17; - case XK_F18: return Key::F18; - case XK_F19: return Key::F19; - case XK_F20: return Key::F20; - case XK_F21: return Key::F21; - case XK_F22: return Key::F22; - case XK_F23: return Key::F23; - case XK_F24: return Key::F24; - case XK_Print: return Key::PRINTSCREEN; - case XK_Insert: return Key::INSERT; - case XK_Help: return Key::HELP; - case XK_grave: return Key::BACK_QUOTE; - case XK_quoteright: return Key::QUOTE; - case XK_Menu: return Key::MENU; + case XKB_KEY_Return: return Key::ENTER; + case XKB_KEY_BackSpace: return Key::BACKSPACE; + case XKB_KEY_Tab: return Key::TAB; + case XKB_KEY_Cancel: return Key::CANCEL; + case XKB_KEY_Clear: return Key::CLEAR; + case XKB_KEY_Pause: return Key::PAUSE; + case XKB_KEY_Escape: return Key::ESCAPE; + case XKB_KEY_space: return Key::SPACE; + case XKB_KEY_Page_Up: return Key::PAGE_UP; + case XKB_KEY_Page_Down: return Key::PAGE_DOWN; + case XKB_KEY_End: return Key::END; + case XKB_KEY_Home: return Key::HOME; + case XKB_KEY_Left: return Key::LEFT; + case XKB_KEY_Up: return Key::UP; + case XKB_KEY_Right: return Key::RIGHT; + case XKB_KEY_Down: return Key::DOWN; + case XKB_KEY_comma: return Key::COMMA; + case XKB_KEY_minus: return Key::MINUS; + case XKB_KEY_period: return Key::PERIOD; + case XKB_KEY_slash: return Key::SLASH; + case XKB_KEY_0: return Key::DIGIT0; + case XKB_KEY_1: return Key::DIGIT1; + case XKB_KEY_2: return Key::DIGIT2; + case XKB_KEY_3: return Key::DIGIT3; + case XKB_KEY_4: return Key::DIGIT4; + case XKB_KEY_5: return Key::DIGIT5; + case XKB_KEY_6: return Key::DIGIT6; + case XKB_KEY_7: return Key::DIGIT7; + case XKB_KEY_8: return Key::DIGIT8; + case XKB_KEY_9: return Key::DIGIT9; + case XKB_KEY_semicolon: return Key::SEMICOLON; + case XKB_KEY_equal: return Key::EQUALS; + case XKB_KEY_a: return Key::A; + case XKB_KEY_b: return Key::B; + case XKB_KEY_c: return Key::C; + case XKB_KEY_d: return Key::D; + case XKB_KEY_e: return Key::E; + case XKB_KEY_f: return Key::F; + case XKB_KEY_g: return Key::G; + case XKB_KEY_h: return Key::H; + case XKB_KEY_i: return Key::I; + case XKB_KEY_j: return Key::J; + case XKB_KEY_k: return Key::K; + case XKB_KEY_l: return Key::L; + case XKB_KEY_m: return Key::M; + case XKB_KEY_n: return Key::N; + case XKB_KEY_o: return Key::O; + case XKB_KEY_p: return Key::P; + case XKB_KEY_q: return Key::Q; + case XKB_KEY_r: return Key::R; + case XKB_KEY_s: return Key::S; + case XKB_KEY_t: return Key::T; + case XKB_KEY_u: return Key::U; + case XKB_KEY_v: return Key::V; + case XKB_KEY_w: return Key::W; + case XKB_KEY_x: return Key::X; + case XKB_KEY_y: return Key::Y; + case XKB_KEY_z: return Key::Z; + case XKB_KEY_bracketleft: return Key::OPEN_BRACKET; + case XKB_KEY_backslash: return Key::BACK_SLASH; + case XKB_KEY_bracketright: return Key::CLOSE_BRACKET; + case XKB_KEY_KP_0: return Key::DIGIT0; + case XKB_KEY_KP_1: return Key::DIGIT1; + case XKB_KEY_KP_2: return Key::DIGIT2; + case XKB_KEY_KP_3: return Key::DIGIT3; + case XKB_KEY_KP_4: return Key::DIGIT4; + case XKB_KEY_KP_5: return Key::DIGIT5; + case XKB_KEY_KP_6: return Key::DIGIT6; + case XKB_KEY_KP_7: return Key::DIGIT7; + case XKB_KEY_KP_8: return Key::DIGIT8; + case XKB_KEY_KP_9: return Key::DIGIT9; + case XKB_KEY_multiply: return Key::MULTIPLY; + case XKB_KEY_KP_Add: return Key::ADD; + case XKB_KEY_KP_Separator: return Key::SEPARATOR; + case XKB_KEY_KP_Subtract: return Key::MINUS; + case XKB_KEY_KP_Decimal: return Key::PERIOD; + case XKB_KEY_KP_Divide: return Key::SLASH; + case XKB_KEY_KP_Delete: return Key::DEL; + case XKB_KEY_Delete: return Key::DEL; + case XKB_KEY_Num_Lock: return Key::NUM_LOCK; + case XKB_KEY_Scroll_Lock: return Key::SCROLL_LOCK; + case XKB_KEY_F1: return Key::F1; + case XKB_KEY_F2: return Key::F2; + case XKB_KEY_F3: return Key::F3; + case XKB_KEY_F4: return Key::F4; + case XKB_KEY_F5: return Key::F5; + case XKB_KEY_F6: return Key::F6; + case XKB_KEY_F7: return Key::F7; + case XKB_KEY_F8: return Key::F8; + case XKB_KEY_F9: return Key::F9; + case XKB_KEY_F10: return Key::F10; + case XKB_KEY_F11: return Key::F11; + case XKB_KEY_F12: return Key::F12; + case XKB_KEY_F13: return Key::F13; + case XKB_KEY_F14: return Key::F14; + case XKB_KEY_F15: return Key::F15; + case XKB_KEY_F16: return Key::F16; + case XKB_KEY_F17: return Key::F17; + case XKB_KEY_F18: return Key::F18; + case XKB_KEY_F19: return Key::F19; + case XKB_KEY_F20: return Key::F20; + case XKB_KEY_F21: return Key::F21; + case XKB_KEY_F22: return Key::F22; + case XKB_KEY_F23: return Key::F23; + case XKB_KEY_F24: return Key::F24; + case XKB_KEY_Print: return Key::PRINTSCREEN; + case XKB_KEY_Insert: return Key::INSERT; + case XKB_KEY_Help: return Key::HELP; + case XKB_KEY_grave: return Key::BACK_QUOTE; + case XKB_KEY_quoteright: return Key::QUOTE; + case XKB_KEY_Menu: return Key::MENU; // Key::KANA // Key::VOLUME_UP // Key::VOLUME_DOWN // Key::MUTE default: return Key::UNDEFINED; - } */ - // IMPL ME! - return Key::UNDEFINED; + } } diff --git a/wayland/cc/KeyWayland.hh b/wayland/cc/KeyWayland.hh index bcbf02d8..03009cc1 100644 --- a/wayland/cc/KeyWayland.hh +++ b/wayland/cc/KeyWayland.hh @@ -2,13 +2,12 @@ #include #include "Key.hh" +#include namespace jwm { namespace KeyWayland { jwm::Key fromNative(uint32_t v); - bool getKeyState(jwm::Key key); - void setKeyState(jwm::Key key, bool isDown); - int getModifiers(); - int getModifiersFromMask(int mask); + int getModifiers(xkb_state* state); + // int getModifiersFromMask(int mask); } } diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index 9d1cf492..44ba6e90 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -81,7 +81,7 @@ namespace jwm { glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); // ??? - // glViewport(0, 0, width, height); + glViewport(0, 0, width, height); // God is dead if _eglWindow is null if (_eglWindow) wl_egl_window_resize(_eglWindow, width, height, 0, 0); diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index 4198d675..590ad999 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -23,8 +23,6 @@ namespace jwm { void attach(WindowWayland* window) { fWindow = jwm::ref(window); fWindow->setLayer(this); - // a default size : ) - resize(100, 100); } void resize(int width, int height) override { diff --git a/wayland/cc/Output.cc b/wayland/cc/Output.cc index 356aefe4..91590ce5 100644 --- a/wayland/cc/Output.cc +++ b/wayland/cc/Output.cc @@ -16,9 +16,22 @@ Output::Output(wl_output* output, uint32_t name): { wl_output_add_listener(output, &_outputListener, this); } + +ScreenInfo Output::getScreenInfo() const { + return { + .id = _name, + .bounds = jwm::IRect::makeXYWH(0, 0, width, height), + .isPrimary = false, + .scale = scale + }; +} void Output::outputGeometry(void* data, wl_output* output, int x, int y, int physWidth, int physHeight, int subPixel, const char* make, const char* model, int transform) {} -void Output::outputMode(void* data, wl_output* output, uint32_t flags, int width, int height, int refresh) {} +void Output::outputMode(void* data, wl_output* output, uint32_t flags, int width, int height, int refresh) { + Output* self = reinterpret_cast(data); + self->width = width; + self->height = height; +} void Output::outputDone(void* data, wl_output* output) {} void Output::outputScale(void* data, wl_output* output, int factor) { Output* self = reinterpret_cast(data); diff --git a/wayland/cc/Output.hh b/wayland/cc/Output.hh index 1c6763b1..cf8c9381 100644 --- a/wayland/cc/Output.hh +++ b/wayland/cc/Output.hh @@ -2,6 +2,7 @@ #include #include +#include "ScreenInfo.hh" namespace jwm { class Output { @@ -11,6 +12,10 @@ namespace jwm { wl_output* _output; uint32_t _name; int scale = 1; + int width = 0; + int height = 0; + + ScreenInfo getScreenInfo() const; static wl_output_listener _outputListener; static void outputGeometry(void* data, wl_output* output, int x, int y, int physWidth, int physHeight, diff --git a/wayland/cc/ScreenInfo.cc b/wayland/cc/ScreenInfo.cc index 3dddf554..0dc625b2 100644 --- a/wayland/cc/ScreenInfo.cc +++ b/wayland/cc/ScreenInfo.cc @@ -1,5 +1,5 @@ #include "ScreenInfo.hh" #include "AppWayland.hh" jobject jwm::ScreenInfo::asJavaObject(JNIEnv* env) const { - return jwm::classes::Screen::make(env, id, isPrimary, bounds, bounds, 1.0f); + return jwm::classes::Screen::make(env, id, isPrimary, bounds, bounds, scale); } diff --git a/wayland/cc/ScreenInfo.hh b/wayland/cc/ScreenInfo.hh index 947890a3..99d3eb9d 100644 --- a/wayland/cc/ScreenInfo.hh +++ b/wayland/cc/ScreenInfo.hh @@ -8,6 +8,7 @@ namespace jwm long id; IRect bounds; bool isPrimary; + int scale; jobject asJavaObject(JNIEnv* env) const; }; } // namespace jwm diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 2df5df50..7e3a6f23 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -19,6 +19,9 @@ #include "Output.hh" #include #include +#include +#include +#include using namespace jwm; @@ -40,6 +43,18 @@ xdg_wm_base_listener WindowManagerWayland::_xdgWmBaseListener = { libdecor_interface WindowManagerWayland::_decorInterface = { .error = WindowManagerWayland::libdecorError }; +wl_keyboard_listener WindowManagerWayland::_keyboardListener = { + .keymap = WindowManagerWayland::keyboardKeymap, + .enter = WindowManagerWayland::keyboardEnter, + .leave = WindowManagerWayland::keyboardLeave, + .key = WindowManagerWayland::keyboardKey, + .modifiers = WindowManagerWayland::keyboardModifiers, + .repeat_info = WindowManagerWayland::keyboardRepeatInfo +}; +wl_seat_listener WindowManagerWayland::_seatListener = { + .capabilities = WindowManagerWayland::seatCapabilities, + .name = WindowManagerWayland::seatName +}; WindowManagerWayland::WindowManagerWayland(): display(wl_display_connect(nullptr)) { registry = wl_display_get_registry(display); @@ -55,9 +70,13 @@ WindowManagerWayland::WindowManagerWayland(): throw std::system_error(ENOTSUP, std::generic_category(), "Unsupported compositor"); } - + // ???: Moving this after libdecor_new causes input to not work + wl_seat_add_listener(seat, &_seatListener, this); + decorCtx = libdecor_new(display, &_decorInterface); + + wl_display_roundtrip(display); // frankly `this` is not needed here, but it needs a pointer anyway and it's // good to have consistentcy. xdg_wm_base_add_listener(xdgShell, &_xdgWmBaseListener, this); @@ -89,13 +108,6 @@ WindowManagerWayland::WindowManagerWayland(): wl_surface_commit(cursorSurface); } - { - pointer = wl_seat_get_pointer(seat); - - wl_pointer_add_listener(pointer, &_pointerListener, this); - } - - } @@ -245,7 +257,9 @@ void WindowManagerWayland::pointerHandleMotion(void* data, wl_pointer* pointer, ::WindowWayland* window = self->getWindowForNative(self->focusedSurface); // God is dead if window is null if (window) - self->mouseUpdate(window, wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y), self->mouseMask); + self->mouseUpdate(window, + wl_fixed_to_int(surface_x) * window->_scale, + wl_fixed_to_int(surface_y) * window->_scale, self->mouseMask); } } @@ -282,7 +296,7 @@ void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, false, self->lastMousePosX, self->lastMousePosY, - jwm::KeyWayland::getModifiers() + jwm::KeyWayland::getModifiers(self->_xkbState) ) ); WindowWayland* window = self->getWindowForNative(self->focusedSurface); @@ -317,7 +331,7 @@ void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, true, self->lastMousePosX, self->lastMousePosY, - jwm::KeyWayland::getModifiers() + jwm::KeyWayland::getModifiers(self->_xkbState) ) ); // me when this stuff is NULL : ( @@ -329,6 +343,122 @@ void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, } void WindowManagerWayland::pointerHandleAxis(void* data, wl_pointer* pointer, uint32_t time, uint32_t axis, wl_fixed_t value) {} +void WindowManagerWayland::keyboardKeymap(void* data, wl_keyboard* keyboard, uint32_t format, + int32_t fd, uint32_t size) { + auto self = reinterpret_cast(data); + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + close(fd); + fprintf(stderr, "no xkb keymap\n"); + return; + } + + char* map_str = reinterpret_cast(mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0)); + if (map_str == MAP_FAILED) { + close(fd); + fprintf(stderr, "keymap mmap failed: %s", strerror(errno)); + return; + } + + xkb_keymap* keymap = xkb_keymap_new_from_string( + self->_xkbContext, map_str, + XKB_KEYMAP_FORMAT_TEXT_V1, + XKB_KEYMAP_COMPILE_NO_FLAGS + ); + munmap(map_str, size); + close(fd); + + if (!keymap) { + return; + } + self->_xkbState = xkb_state_new(keymap); + + xkb_keymap_unref(keymap); +} +void WindowManagerWayland::keyboardEnter(void* data, wl_keyboard* keyboard, uint32_t serial, wl_surface* surface, + wl_array *keys) { + auto self = reinterpret_cast(data); + self->keyboardFocus = surface; +} +void WindowManagerWayland::keyboardLeave(void* data, wl_keyboard* keyboard, uint32_t serial, wl_surface* surface) { + auto self = reinterpret_cast(data); + self->keyboardFocus = nullptr; +} + +void WindowManagerWayland::keyboardKey(void* data, wl_keyboard* keyboard, uint32_t serial, uint32_t time, + uint32_t key, uint32_t state) +{ + auto self = reinterpret_cast(data); + if (!self->_xkbState) return; + const xkb_keysym_t *syms; + + if (xkb_state_key_get_syms(self->_xkbState, key + 8, &syms) != 1) + return; + jwm::Key jwmKey = KeyWayland::fromNative(syms[0]); + + // TODO: while unlikely, it could be possible that you can be entering text even if the + // pointer hasn't entered + if (self->focusedSurface) { + jwm::KeyLocation location; + JNILocal keyEvent( + app.getJniEnv(), + classes::EventKey::make( + app.getJniEnv(), + jwmKey, + state == WL_KEYBOARD_KEY_STATE_PRESSED, + KeyWayland::getModifiers(self->_xkbState), + location + ) + ); + auto window = self->getWindowForNative(self->keyboardFocus); + if (window) + window->dispatch(keyEvent.get()); + } + +} +void WindowManagerWayland::keyboardModifiers(void* data, wl_keyboard* keyboard, + uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, + uint32_t group) { + auto self = reinterpret_cast(data); + if (!self->_xkbState) return; + xkb_state_update_mask(self->_xkbState, + mods_depressed, mods_latched, mods_locked, + 0, 0, group); +} + +void WindowManagerWayland::keyboardRepeatInfo(void* data, wl_keyboard* keyboard, + int32_t rate, int32_t delay) { + // TODO: The client (for some godforsaken reason) is expected to handle repeating characters +} + +void WindowManagerWayland::seatCapabilities(void* data, wl_seat* seat, uint32_t capabilities) { + auto self = reinterpret_cast(data); + printf("%i", capabilities & WL_SEAT_CAPABILITY_POINTER); + if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && + !self->pointer) { + self->pointer = wl_seat_get_pointer(seat); + wl_pointer_add_listener(self->pointer, &_pointerListener, self); + } else if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && self->pointer) { + wl_pointer_release(self->pointer); + self->pointer = nullptr; + } + + if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && + !self->keyboard) { + printf("got da keyboard\n"); + self->keyboard = wl_seat_get_keyboard(seat); + self->_xkbContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + wl_keyboard_add_listener(self->keyboard, &_keyboardListener, self); + } else if (!(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && + self->keyboard) { + xkb_context_unref(self->_xkbContext); + wl_keyboard_release(self->keyboard); + self->keyboard = nullptr; + } +} +void WindowManagerWayland::seatName(void* data, wl_seat* seat, const char* name) { + // who cares +} void WindowManagerWayland::xdgWmBasePing(void* data, xdg_wm_base* base, uint32_t serial) { xdg_wm_base_pong(base, serial); } @@ -413,7 +543,7 @@ void WindowManagerWayland::mouseUpdate(WindowWayland* myWindow, uint32_t x, uint movementY, jwm::MouseButtonWayland::fromNativeMask(mask), // impl me! - jwm::KeyWayland::getModifiers() + jwm::KeyWayland::getModifiers(_xkbState) ) ); auto foo = eventMove.get(); @@ -421,56 +551,6 @@ void WindowManagerWayland::mouseUpdate(WindowWayland* myWindow, uint32_t x, uint } jwm::ByteBuf WindowManagerWayland::getClipboardContents(const std::string& type) { auto nativeHandle = _nativeWindowToMy.begin()->first; - /* - XConvertSelection(display, - _atoms.CLIPBOARD, - XInternAtom(display, type.c_str(), false), - _atoms.JWM_CLIPBOARD, - nativeHandle, - CurrentTime); - XEvent ev; - while (_runLoop) { - while (XPending(display)) { - XNextEvent(display, &ev); - switch (ev.type) - { - case SelectionNotify: { - if (ev.xselection.property == None) { - return {}; - } - - Atom da, incr, type; - int di; - unsigned long size, length, count; - unsigned char* propRet = NULL; - - XGetWindowProperty(display, nativeHandle, _atoms.JWM_CLIPBOARD, 0, 0, False, AnyPropertyType, - &type, &di, &length, &size, &propRet); - XFree(propRet); - - // Clipboard data is too large and INCR mechanism not implemented - ByteBuf result; - if (type != _atoms.INCR) - { - XGetWindowProperty(display, nativeHandle, _atoms.JWM_CLIPBOARD, 0, size, False, AnyPropertyType, - &da, &di, &length, &count, &propRet); - - result = ByteBuf{ propRet, propRet + length }; - XFree(propRet); - return result; - } - XDeleteProperty(display, nativeHandle, _atoms.JWM_CLIPBOARD); - return result; - } - default: - _processXEvent(ev); - } - } - _processCallbacks(); - } - - XDeleteProperty(display, nativeHandle, _atoms.JWM_CLIPBOARD); - */ return {}; } diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index eb872036..3b470ea2 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -17,6 +17,7 @@ #include #include "Output.hh" #include +#include namespace jwm { class WindowWayland; @@ -84,6 +85,25 @@ namespace jwm { static libdecor_interface _decorInterface; static void libdecorError(libdecor* context, enum libdecor_error error, const char* message); + static wl_keyboard_listener _keyboardListener; + static void keyboardKeymap(void* data, wl_keyboard* keyboard, + uint32_t format, int32_t fd, uint32_t size); + static void keyboardEnter(void* data, wl_keyboard* keyboard, + uint32_t serial, wl_surface* surface, wl_array* keys); + static void keyboardLeave(void* data, wl_keyboard* keyboard, uint32_t serial, + wl_surface* surface); + static void keyboardKey(void* data, wl_keyboard* keyboard, uint32_t serial, + uint32_t time, uint32_t key, uint32_t state); + static void keyboardModifiers(void* data, wl_keyboard* keyboard, uint32_t serial, + uint32_t modsDepressed, uint32_t modsLatched, uint32_t modLocked, + uint32_t group); + static void keyboardRepeatInfo(void* data, wl_keyboard* keyboard, int32_t rate, int32_t delay); + + static wl_seat_listener _seatListener; + + static void seatCapabilities(void* data, wl_seat* seat, uint32_t capabilities); + static void seatName(void* data, wl_seat* seat, const char* name); + ByteBuf getClipboardContents(const std::string& type); std::vector getClipboardFormats(); @@ -95,7 +115,10 @@ namespace jwm { wl_data_device_manager* deviceManager = nullptr; wl_seat* seat = nullptr; wl_pointer* pointer = nullptr; + wl_keyboard* keyboard = nullptr; libdecor* decorCtx = nullptr; + xkb_context* _xkbContext = nullptr; + xkb_state* _xkbState = nullptr; std::list outputs; // XVisualInfo* x11VisualInfo; @@ -114,6 +137,7 @@ namespace jwm { wl_surface* cursorSurface; wl_surface* focusedSurface = nullptr; + wl_surface* keyboardFocus = nullptr; // Is holding all cursors in memory a good idea? wl_cursor_image* _cursors[static_cast(jwm::MouseCursor::COUNT)]; diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index a9dbae2b..f95916f4 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -117,6 +117,21 @@ void WindowWayland::getContentPosition(int& posX, int& posY) { } +bool WindowWayland::resize(int width, int height) { + // Width and height are in absolute pixel units, and wayland will + // complain if you try to set a width/height that isn't a multiple of scale. + if ((width % _scale) != 0 || (height % _scale) != 0) + return false; + _width = width / _scale; + _height = height / _scale; + if (_visible) { + // HACK: while I could just dispatch here and save some cpu time, + // it's easier to just lease it out + _adaptSize(_width, _height); + } + return true; +} + int WindowWayland::getLeft() { int x, y; getContentPosition(x, y); @@ -130,11 +145,11 @@ int WindowWayland::getTop() { } int WindowWayland::getWidth() { - return _width <= 0 ? _floatingWidth : _width; + return (_width <= 0 ? _floatingWidth : _width) * _scale; } int WindowWayland::getHeight() { - return _height <= 0 ? _floatingHeight : _height; + return (_height <= 0 ? _floatingHeight : _height) * _scale; } float WindowWayland::getScale() { @@ -163,6 +178,18 @@ void WindowWayland::show() libdecor_dispatch(_windowManager.decorCtx, -1); } +ScreenInfo WindowWayland::getScreen() { + if (_output) { + return _output->getScreenInfo(); + } else { + return { + .id = -1, + .bounds = jwm::IRect::makeXYWH(0, 0, _width, _height), + .isPrimary = false, + .scale = _scale + }; + } +} void WindowWayland::setVisible(bool isVisible) { if (_visible != isVisible) { _visible = isVisible; @@ -196,6 +223,7 @@ void jwm::WindowWayland::surfaceEnter(void* data, wl_surface* surface, wl_output for (auto o : self->_windowManager.outputs) { if (o->_output == output) { + self->_output = o; self->_scale = o->scale; wl_surface_set_buffer_scale(surface, o->scale); self->_adaptSize(self->_width, self->_height); @@ -325,11 +353,26 @@ void jwm::WindowWayland::decorFrameCommit(libdecor_frame* frame, void* userData) } void jwm::WindowWayland::decorFrameDismissPopup(libdecor_frame* frame, const char* seatName, void* userData) {} void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { + using namespace classes; _width = newWidth; _height = newHeight; + int scaledWidth = _width * _scale; + int scaledHeight = _height * _scale; if (_layer) { - _layer->resize(_width * _scale, _height * _scale); + _layer->resize(scaledWidth, scaledHeight); } + + jwm::JNILocal eventWindowResize( + app.getJniEnv(), + EventWindowResize::make( + app.getJniEnv(), + scaledWidth, + scaledHeight, + scaledWidth, + scaledHeight + ) + ); + dispatch(eventWindowResize.get()); } // JNI @@ -348,6 +391,16 @@ extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nS reinterpret_cast(jwm::classes::Native::fromJava(env, obj))->setVisible(isVisible); } +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nSetContentSize + (JNIEnv* env, jobject obj, jint width, jint height) { + reinterpret_cast(jwm::classes::Native::fromJava(env, obj))->resize(width, height); +} +extern "C" JNIEXPORT jobject JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nGetScreen + (JNIEnv* env, jobject obj) { + jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + return instance->getScreen().asJavaObject(env); +} + extern "C" JNIEXPORT jobject JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nGetWindowRect (JNIEnv* env, jobject obj) { jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index 2ded4bd4..c7b6f679 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -17,6 +17,7 @@ namespace jwm { void getDecorations(int& left, int& top, int& right, int& bottom); void getContentPosition(int& posX, int& posY); void setVisible(bool isVisible); + bool resize(int width, int height); void close(); bool init(); void show(); @@ -51,7 +52,7 @@ namespace jwm { } - const ScreenInfo& getScreen(); + ScreenInfo getScreen(); static void surfaceEnter(void* data, wl_surface* surface, wl_output* output); static void surfaceLeave(void* data, wl_surface* surface, wl_output* output); @@ -108,6 +109,7 @@ namespace jwm { xdg_surface* xdgSurface = nullptr; xdg_toplevel* xdgToplevel = nullptr; libdecor_frame* _frame = nullptr; + Output* _output = nullptr; static wl_surface_listener _surfaceListener; static xdg_surface_listener _xdgSurfaceListener; diff --git a/wayland/java/WindowWayland.java b/wayland/java/WindowWayland.java index 5c09dd50..666bc04e 100644 --- a/wayland/java/WindowWayland.java +++ b/wayland/java/WindowWayland.java @@ -31,15 +31,13 @@ public void unmarkText() { @Override public IRect getWindowRect() { assert _onUIThread() : "Should be run on UI thread"; - // very very bad! - return IRect.makeXYWH(0, 0, 100, 100); + return _nGetWindowRect(); } @Override public IRect getContentRect() { assert _onUIThread() : "Should be run on UI thread"; - // stop! - return IRect.makeXYWH(0, 0, 100, 100); + return _nGetContentRect(); } @Override @@ -59,8 +57,7 @@ public Window setWindowSize(int width, int height) { @Override public Window setContentSize(int width, int height) { assert _onUIThread() : "Should be run on UI thread"; - // _nSetContentSize(width, height); - // Possibly unsupported + _nSetContentSize(width, height); return this; } @@ -118,7 +115,7 @@ public float getOpacity(){ @Override public Screen getScreen() { assert _onUIThread() : "Should be run on UI thread"; - return new Screen(0, false, IRect.makeXYWH(0, 0, 0, 0), IRect.makeXYWH(0, 0, 0, 0), getScale()); + return _nGetScreen(); } @Override @@ -227,8 +224,8 @@ public float getScale() { // @ApiStatus.Internal public native void _nSetWindowPosition(int left, int top); // @ApiStatus.Internal public native void _nSetWindowSize(int width, int height); @ApiStatus.Internal public native void _nSetMouseCursor(int cursorId); - // @ApiStatus.Internal public native void _nSetContentSize(int width, int height); - // @ApiStatus.Internal public native Screen _nGetScreen(); + @ApiStatus.Internal public native void _nSetContentSize(int width, int height); + @ApiStatus.Internal public native Screen _nGetScreen(); @ApiStatus.Internal public native void _nRequestFrame(); @ApiStatus.Internal public native void _nClose(); @ApiStatus.Internal public native void _nMaximize(); From db4c4d5fe3151b2abddaf36f91a2be2e5cf7f138 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Thu, 7 Dec 2023 23:52:36 -0500 Subject: [PATCH 15/93] remove xdg-shell --- wayland/CMakeLists.txt | 3 - wayland/cc/LayerRasterWayland.cc | 4 + wayland/cc/WindowManagerWayland.cc | 41 +- wayland/cc/WindowManagerWayland.hh | 4 - wayland/cc/WindowWayland.cc | 85 +- wayland/cc/WindowWayland.hh | 12 - wayland/cc/xdg-shell/xdg-shell.c | 183 --- wayland/cc/xdg-shell/xdg-shell.h | 2307 ---------------------------- 8 files changed, 39 insertions(+), 2600 deletions(-) delete mode 100644 wayland/cc/xdg-shell/xdg-shell.c delete mode 100644 wayland/cc/xdg-shell/xdg-shell.h diff --git a/wayland/CMakeLists.txt b/wayland/CMakeLists.txt index 04947745..a7ead2f8 100644 --- a/wayland/CMakeLists.txt +++ b/wayland/CMakeLists.txt @@ -20,8 +20,6 @@ file(GLOB SOURCES_CXX ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/*.cc ${CMAKE_CURRENT_LIST_DIR}/../linux/cc/*.cc ${CMAKE_CURRENT_LIST_DIR}/cc/*.cc ) file(GLOB SOURCES_CXX_IMPL ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/impl/*.cc) -file(GLOB SOURCES_XDG ${CMAKE_CURRENT_LIST_DIR}/cc/xdg-shell/*.c) -add_library(xdgShell STATIC ${SOURCES_XDG}) add_library(jwm SHARED ${SOURCES_OBJC} ${SOURCES_CXX} ${SOURCES_CXX_IMPL}) find_library(WAYLAND_CLIENT_LIB wayland-client) find_library(DECOR_LIB decor-0) @@ -45,7 +43,6 @@ endif() target_include_directories(jwm PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../shared/cc ${CMAKE_CURRENT_LIST_DIR}/../linux/cc ${JAVA_HOME}/include ${JAVA_HOME}/include/linux) set_target_properties(jwm PROPERTIES OUTPUT_NAME "jwm_${JWM_ARCH}_wayland") -target_link_libraries(jwm PUBLIC xdgShell) target_link_libraries(jwm PRIVATE ${WAYLAND_CLIENT_LIB} ${DECOR_LIB} ${WAYLAND_CURSOR} ${XKBCOMMON}) target_link_libraries(jwm PRIVATE ${EGL} ${WAYLAND_EGL}) diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index 590ad999..1e1d620c 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -23,9 +23,12 @@ namespace jwm { void attach(WindowWayland* window) { fWindow = jwm::ref(window); fWindow->setLayer(this); + // must have a default size for pointer initing : ) + resize(400, 400); } void resize(int width, int height) override { + printf("???\n"); wl_display* d = fWindow->_windowManager.display; _width = width; _height = height; @@ -53,6 +56,7 @@ namespace jwm { if (_attached) { attachBuffer(); } + makeCurrentForced(); } const void* getPixelsPtr() const { diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 7e3a6f23..a69e9126 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -36,9 +36,6 @@ wl_pointer_listener WindowManagerWayland::_pointerListener = { .button = WindowManagerWayland::pointerHandleButton, .axis = WindowManagerWayland::pointerHandleAxis }; -xdg_wm_base_listener WindowManagerWayland::_xdgWmBaseListener = { - .ping = WindowManagerWayland::xdgWmBasePing -}; libdecor_interface WindowManagerWayland::_decorInterface = { .error = WindowManagerWayland::libdecorError @@ -64,7 +61,7 @@ WindowManagerWayland::WindowManagerWayland(): - if (!(shm && xdgShell && compositor && deviceManager && seat)) { + if (!(shm && compositor && deviceManager && seat)) { // ??? // Bad. Means our compositor no supportie : ( throw std::system_error(ENOTSUP, std::generic_category(), "Unsupported compositor"); @@ -77,9 +74,6 @@ WindowManagerWayland::WindowManagerWayland(): wl_display_roundtrip(display); - // frankly `this` is not needed here, but it needs a pointer anyway and it's - // good to have consistentcy. - xdg_wm_base_add_listener(xdgShell, &_xdgWmBaseListener, this); { wl_cursor_theme* cursor_theme = wl_cursor_theme_load(nullptr, 24, shm); // TODO: what about if missing : ( @@ -202,9 +196,6 @@ void WindowManagerWayland::registryHandleGlobal(void* data, wl_registry *registr } else if (strcmp(interface, wl_shm_interface.name) == 0) { self->shm = (wl_shm*)wl_registry_bind(registry, name, &wl_shm_interface, 1); - } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { - self->xdgShell = (xdg_wm_base*)wl_registry_bind(registry, name, - &xdg_wm_base_interface, 1); } else if (strcmp(interface, wl_data_device_manager_interface.name) == 0) { self->deviceManager = (wl_data_device_manager*)wl_registry_bind(registry, name, &wl_data_device_manager_interface, 1); @@ -395,10 +386,9 @@ void WindowManagerWayland::keyboardKey(void* data, wl_keyboard* keyboard, uint32 if (xkb_state_key_get_syms(self->_xkbState, key + 8, &syms) != 1) return; jwm::Key jwmKey = KeyWayland::fromNative(syms[0]); - // TODO: while unlikely, it could be possible that you can be entering text even if the // pointer hasn't entered - if (self->focusedSurface) { + if (self->keyboardFocus && jwmKey != jwm::Key::UNDEFINED) { jwm::KeyLocation location; JNILocal keyEvent( app.getJniEnv(), @@ -414,6 +404,30 @@ void WindowManagerWayland::keyboardKey(void* data, wl_keyboard* keyboard, uint32 if (window) window->dispatch(keyEvent.get()); } + if (state != WL_KEYBOARD_KEY_STATE_PRESSED) return; + + char textBuffer[0x40]; + int count = xkb_state_key_get_utf8(self->_xkbState, key + 8, textBuffer, sizeof(textBuffer)-1); + // ??? + if (count >= sizeof(textBuffer) - 1) { + return; + } + if (count > 0) { + // ignore sinful control symbols + if (textBuffer[0] != 127 && textBuffer[0] > 0x1f) { + JNIEnv* env = app.getJniEnv(); + + jwm::StringUTF16 converted = reinterpret_cast(textBuffer); + jwm::JNILocal jtext = converted.toJString(env); + + jwm::JNILocal eventTextInput(env, classes::EventTextInput::make(env, jtext.get())); + + + auto window = self->getWindowForNative(self->keyboardFocus); + if (window) + window->dispatch(eventTextInput.get()); + } + } } void WindowManagerWayland::keyboardModifiers(void* data, wl_keyboard* keyboard, @@ -459,9 +473,6 @@ void WindowManagerWayland::seatCapabilities(void* data, wl_seat* seat, uint32_t void WindowManagerWayland::seatName(void* data, wl_seat* seat, const char* name) { // who cares } -void WindowManagerWayland::xdgWmBasePing(void* data, xdg_wm_base* base, uint32_t serial) { - xdg_wm_base_pong(base, serial); -} std::vector WindowManagerWayland::getClipboardFormats() { /* XConvertSelection(display, diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index 3b470ea2..c3baf58b 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -13,7 +13,6 @@ #include "MouseCursor.hh" #include #include -#include "xdg-shell/xdg-shell.h" #include #include "Output.hh" #include @@ -79,8 +78,6 @@ namespace jwm { static void pointerHandleAxis(void* data, wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value); - static xdg_wm_base_listener _xdgWmBaseListener; - static void xdgWmBasePing(void* data, xdg_wm_base* base, uint32_t serial); static libdecor_interface _decorInterface; static void libdecorError(libdecor* context, enum libdecor_error error, const char* message); @@ -110,7 +107,6 @@ namespace jwm { wl_display* display = nullptr; wl_registry* registry = nullptr; wl_shm* shm = nullptr; - xdg_wm_base* xdgShell = nullptr; wl_compositor* compositor = nullptr; wl_data_device_manager* deviceManager = nullptr; wl_seat* seat = nullptr; diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index f95916f4..eab791a5 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -15,16 +15,7 @@ wl_surface_listener WindowWayland::_surfaceListener = { .preferred_buffer_scale = WindowWayland::surfacePreferredBufferScale, .preferred_buffer_transform = WindowWayland::surfacePreferredBufferTransform }; -xdg_surface_listener WindowWayland::_xdgSurfaceListener = { - .configure = WindowWayland::xdgSurfaceConfigure -}; -xdg_toplevel_listener WindowWayland::_xdgToplevelListener = { - .configure = WindowWayland::xdgToplevelConfigure, - .close = WindowWayland::xdgToplevelClose, - .configure_bounds = WindowWayland::xdgToplevelConfigureBounds, - .wm_capabilities = WindowWayland::xdgToplevelWmCapabilities -}; wl_output_listener WindowWayland::_outputListener = { .geometry = WindowWayland::outputGeometry, @@ -67,14 +58,6 @@ void WindowWayland::close() { wl_surface_destroy(_waylandWindow); } _waylandWindow = nullptr; - if (xdgSurface) { - xdg_surface_destroy(xdgSurface); - } - xdgSurface = nullptr; - if (xdgToplevel) { - xdg_toplevel_destroy(xdgToplevel); - } - xdgToplevel = nullptr; if (_frame) { libdecor_frame_unref(_frame); } @@ -125,8 +108,6 @@ bool WindowWayland::resize(int width, int height) { _width = width / _scale; _height = height / _scale; if (_visible) { - // HACK: while I could just dispatch here and save some cpu time, - // it's easier to just lease it out _adaptSize(_width, _height); } return true; @@ -176,6 +157,8 @@ void WindowWayland::show() _configured = false; libdecor_frame_map(_frame); libdecor_dispatch(_windowManager.decorCtx, -1); + if (_width > 0 && _height > 0) + resize(_width * _scale, _height * _scale); } ScreenInfo WindowWayland::getScreen() { @@ -245,50 +228,6 @@ void jwm::WindowWayland::surfacePreferredBufferScale(void* data, wl_surface* sur } void jwm::WindowWayland::surfacePreferredBufferTransform(void* data, wl_surface* surface, uint32_t transform) {} -void jwm::WindowWayland::xdgSurfaceConfigure(void* data, xdg_surface* surface, uint32_t serial) { - WindowWayland* self = (WindowWayland*) data; - // Commit state - if (self->_newWidth > 0 || self->_newHeight > 0) { - int goodWidth = self->_width, goodHeight = self->_height; - if (self->_newWidth > 0) - goodWidth = self->_newWidth; - if (self->_newHeight > 0) - goodHeight = self->_newHeight; - self->_adaptSize(goodWidth, goodHeight); - } - self->_newWidth = -1; - self->_newHeight = -1; - xdg_surface_ack_configure(surface, serial); - if (self->_layer) { - self->_layer->attachBuffer(); - } -} -void jwm::WindowWayland::xdgToplevelConfigure(void* data, xdg_toplevel* toplevel, int width, int height, wl_array* states) { - WindowWayland* self = (WindowWayland*) data; - if (width > 0) { - self->_newWidth = width; - } - if (height > 0) { - self->_newHeight = height; - } - // honestly idrc about the state -} -void jwm::WindowWayland::xdgToplevelClose(void* data, xdg_toplevel* toplevel) { - WindowWayland* self = reinterpret_cast(data); - self->dispatch(classes::EventWindowCloseRequest::kInstance); -} -void jwm::WindowWayland::xdgToplevelConfigureBounds(void* data, xdg_toplevel* toplevel, int width, int height) { - WindowWayland* self = (WindowWayland*) data; - if (width > 0) { - self->_newWidth = width; - } - if (height > 0) { - self->_newHeight = height; - } -} -void jwm::WindowWayland::xdgToplevelWmCapabilities(void* data, xdg_toplevel* toplevel, wl_array* array) { - // impl me : ) -} void jwm::WindowWayland::outputGeometry(void* data, wl_output* output, int x, int y, int pWidth, int pHeight, int subpixel, const char* make, const char* model, int transform) {} void jwm::WindowWayland::outputMode(void* data, wl_output* output, uint32_t flags, int width, int height, @@ -297,12 +236,7 @@ void jwm::WindowWayland::outputDone(void* data, wl_output* output) {} void jwm::WindowWayland::outputScale(void* data, wl_output* output, int factor) { WindowWayland* self = reinterpret_cast(data); self->_scale = factor; - if (self->_layer) { - self->_layer->resize(self->_width * factor, self->_height * factor); - if (self->_waylandWindow) { - wl_surface_set_buffer_scale(self->_waylandWindow, factor); - } - } + self->dispatch(classes::EventWindowScreenChange::kInstance); } void jwm::WindowWayland::outputName(void* data, wl_output* output, const char* name) {} void jwm::WindowWayland::outputDescription(void* data, wl_output* output, const char* desc) {} @@ -320,16 +254,18 @@ void jwm::WindowWayland::decorFrameConfigure(libdecor_frame* frame, libdecor_con libdecor_configuration_get_content_size(configuration, frame, &width, &height); - width = (width == 0) ? self->_floatingWidth : width; - height = (height == 0) ? self->_floatingHeight : height; + width = (width <= 0) ? self->_floatingWidth : width; + height = (height <= 0) ? self->_floatingHeight : height; libdecor_state* state = libdecor_state_new(width, height); libdecor_frame_commit(frame, state, configuration); libdecor_state_free(state); if (libdecor_frame_is_floating(frame)) { - self->_floatingWidth = width; - self->_floatingHeight = height; + if (width > 0) + self->_floatingWidth = width; + if (height > 0) + self->_floatingHeight = height; } if (!self->_configured && self->_layer) { @@ -358,9 +294,6 @@ void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { _height = newHeight; int scaledWidth = _width * _scale; int scaledHeight = _height * _scale; - if (_layer) { - _layer->resize(scaledWidth, scaledHeight); - } jwm::JNILocal eventWindowResize( app.getJniEnv(), diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index c7b6f679..e04c366d 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -6,7 +6,6 @@ #include "WindowManagerWayland.hh" #include "ILayerWayland.hh" #include "ScreenInfo.hh" -#include "xdg-shell/xdg-shell.h" #include namespace jwm { class WindowWayland: public jwm::Window { @@ -59,13 +58,6 @@ namespace jwm { static void surfacePreferredBufferScale(void* data, wl_surface* surface, int factor); static void surfacePreferredBufferTransform(void* data, wl_surface* surface, uint32_t transform); - static void xdgSurfaceConfigure(void* data, xdg_surface* surface, uint32_t serial); - - static void xdgToplevelConfigure(void* data, xdg_toplevel* toplevel, int width, int height, wl_array* states); - static void xdgToplevelClose(void* data, xdg_toplevel* toplevel); - static void xdgToplevelConfigureBounds(void* data, xdg_toplevel* toplevel, int width, int height); - static void xdgToplevelWmCapabilities(void* data, xdg_toplevel* toplevel, wl_array* capabilities); - static void outputGeometry(void* data, wl_output* output, int x, int y, int physWidth, int physHeight, int subpixelOrient, const char* make, const char* model, int transform); static void outputMode(void* data, wl_output* output, uint32_t flags, int width, int height, int refresh); @@ -106,14 +98,10 @@ namespace jwm { WindowManagerWayland& _windowManager; ILayerWayland* _layer = nullptr; wl_surface* _waylandWindow = nullptr; - xdg_surface* xdgSurface = nullptr; - xdg_toplevel* xdgToplevel = nullptr; libdecor_frame* _frame = nullptr; Output* _output = nullptr; static wl_surface_listener _surfaceListener; - static xdg_surface_listener _xdgSurfaceListener; - static xdg_toplevel_listener _xdgToplevelListener; static wl_output_listener _outputListener; static libdecor_frame_interface _libdecorFrameInterface; diff --git a/wayland/cc/xdg-shell/xdg-shell.c b/wayland/cc/xdg-shell/xdg-shell.c deleted file mode 100644 index 03826cdc..00000000 --- a/wayland/cc/xdg-shell/xdg-shell.c +++ /dev/null @@ -1,183 +0,0 @@ -/* Generated by wayland-scanner 1.22.0 */ - -/* - * Copyright © 2008-2013 Kristian Høgsberg - * Copyright © 2013 Rafael Antognolli - * Copyright © 2013 Jasper St. Pierre - * Copyright © 2010-2013 Intel Corporation - * Copyright © 2015-2017 Samsung Electronics Co., Ltd - * Copyright © 2015-2017 Red Hat Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include "wayland-util.h" - -#ifndef __has_attribute -# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ -#endif - -#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) -#define WL_PRIVATE __attribute__ ((visibility("hidden"))) -#else -#define WL_PRIVATE -#endif - -extern const struct wl_interface wl_output_interface; -extern const struct wl_interface wl_seat_interface; -extern const struct wl_interface wl_surface_interface; -extern const struct wl_interface xdg_popup_interface; -extern const struct wl_interface xdg_positioner_interface; -extern const struct wl_interface xdg_surface_interface; -extern const struct wl_interface xdg_toplevel_interface; - -static const struct wl_interface *xdg_shell_types[] = { - NULL, - NULL, - NULL, - NULL, - &xdg_positioner_interface, - &xdg_surface_interface, - &wl_surface_interface, - &xdg_toplevel_interface, - &xdg_popup_interface, - &xdg_surface_interface, - &xdg_positioner_interface, - &xdg_toplevel_interface, - &wl_seat_interface, - NULL, - NULL, - NULL, - &wl_seat_interface, - NULL, - &wl_seat_interface, - NULL, - NULL, - &wl_output_interface, - &wl_seat_interface, - NULL, - &xdg_positioner_interface, - NULL, -}; - -static const struct wl_message xdg_wm_base_requests[] = { - { "destroy", "", xdg_shell_types + 0 }, - { "create_positioner", "n", xdg_shell_types + 4 }, - { "get_xdg_surface", "no", xdg_shell_types + 5 }, - { "pong", "u", xdg_shell_types + 0 }, -}; - -static const struct wl_message xdg_wm_base_events[] = { - { "ping", "u", xdg_shell_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface xdg_wm_base_interface = { - "xdg_wm_base", 6, - 4, xdg_wm_base_requests, - 1, xdg_wm_base_events, -}; - -static const struct wl_message xdg_positioner_requests[] = { - { "destroy", "", xdg_shell_types + 0 }, - { "set_size", "ii", xdg_shell_types + 0 }, - { "set_anchor_rect", "iiii", xdg_shell_types + 0 }, - { "set_anchor", "u", xdg_shell_types + 0 }, - { "set_gravity", "u", xdg_shell_types + 0 }, - { "set_constraint_adjustment", "u", xdg_shell_types + 0 }, - { "set_offset", "ii", xdg_shell_types + 0 }, - { "set_reactive", "3", xdg_shell_types + 0 }, - { "set_parent_size", "3ii", xdg_shell_types + 0 }, - { "set_parent_configure", "3u", xdg_shell_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface xdg_positioner_interface = { - "xdg_positioner", 6, - 10, xdg_positioner_requests, - 0, NULL, -}; - -static const struct wl_message xdg_surface_requests[] = { - { "destroy", "", xdg_shell_types + 0 }, - { "get_toplevel", "n", xdg_shell_types + 7 }, - { "get_popup", "n?oo", xdg_shell_types + 8 }, - { "set_window_geometry", "iiii", xdg_shell_types + 0 }, - { "ack_configure", "u", xdg_shell_types + 0 }, -}; - -static const struct wl_message xdg_surface_events[] = { - { "configure", "u", xdg_shell_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface xdg_surface_interface = { - "xdg_surface", 6, - 5, xdg_surface_requests, - 1, xdg_surface_events, -}; - -static const struct wl_message xdg_toplevel_requests[] = { - { "destroy", "", xdg_shell_types + 0 }, - { "set_parent", "?o", xdg_shell_types + 11 }, - { "set_title", "s", xdg_shell_types + 0 }, - { "set_app_id", "s", xdg_shell_types + 0 }, - { "show_window_menu", "ouii", xdg_shell_types + 12 }, - { "move", "ou", xdg_shell_types + 16 }, - { "resize", "ouu", xdg_shell_types + 18 }, - { "set_max_size", "ii", xdg_shell_types + 0 }, - { "set_min_size", "ii", xdg_shell_types + 0 }, - { "set_maximized", "", xdg_shell_types + 0 }, - { "unset_maximized", "", xdg_shell_types + 0 }, - { "set_fullscreen", "?o", xdg_shell_types + 21 }, - { "unset_fullscreen", "", xdg_shell_types + 0 }, - { "set_minimized", "", xdg_shell_types + 0 }, -}; - -static const struct wl_message xdg_toplevel_events[] = { - { "configure", "iia", xdg_shell_types + 0 }, - { "close", "", xdg_shell_types + 0 }, - { "configure_bounds", "4ii", xdg_shell_types + 0 }, - { "wm_capabilities", "5a", xdg_shell_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface xdg_toplevel_interface = { - "xdg_toplevel", 6, - 14, xdg_toplevel_requests, - 4, xdg_toplevel_events, -}; - -static const struct wl_message xdg_popup_requests[] = { - { "destroy", "", xdg_shell_types + 0 }, - { "grab", "ou", xdg_shell_types + 22 }, - { "reposition", "3ou", xdg_shell_types + 24 }, -}; - -static const struct wl_message xdg_popup_events[] = { - { "configure", "iiii", xdg_shell_types + 0 }, - { "popup_done", "", xdg_shell_types + 0 }, - { "repositioned", "3u", xdg_shell_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface xdg_popup_interface = { - "xdg_popup", 6, - 3, xdg_popup_requests, - 3, xdg_popup_events, -}; - diff --git a/wayland/cc/xdg-shell/xdg-shell.h b/wayland/cc/xdg-shell/xdg-shell.h deleted file mode 100644 index ea75d476..00000000 --- a/wayland/cc/xdg-shell/xdg-shell.h +++ /dev/null @@ -1,2307 +0,0 @@ -/* Generated by wayland-scanner 1.22.0 */ - -#ifndef XDG_SHELL_CLIENT_PROTOCOL_H -#define XDG_SHELL_CLIENT_PROTOCOL_H - -#include -#include -#include "wayland-client.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @page page_xdg_shell The xdg_shell protocol - * @section page_ifaces_xdg_shell Interfaces - * - @subpage page_iface_xdg_wm_base - create desktop-style surfaces - * - @subpage page_iface_xdg_positioner - child surface positioner - * - @subpage page_iface_xdg_surface - desktop user interface surface base interface - * - @subpage page_iface_xdg_toplevel - toplevel surface - * - @subpage page_iface_xdg_popup - short-lived, popup surfaces for menus - * @section page_copyright_xdg_shell Copyright - *
- *
- * Copyright © 2008-2013 Kristian Høgsberg
- * Copyright © 2013      Rafael Antognolli
- * Copyright © 2013      Jasper St. Pierre
- * Copyright © 2010-2013 Intel Corporation
- * Copyright © 2015-2017 Samsung Electronics Co., Ltd
- * Copyright © 2015-2017 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- * 
- */ -struct wl_output; -struct wl_seat; -struct wl_surface; -struct xdg_popup; -struct xdg_positioner; -struct xdg_surface; -struct xdg_toplevel; -struct xdg_wm_base; - -#ifndef XDG_WM_BASE_INTERFACE -#define XDG_WM_BASE_INTERFACE -/** - * @page page_iface_xdg_wm_base xdg_wm_base - * @section page_iface_xdg_wm_base_desc Description - * - * The xdg_wm_base interface is exposed as a global object enabling clients - * to turn their wl_surfaces into windows in a desktop environment. It - * defines the basic functionality needed for clients and the compositor to - * create windows that can be dragged, resized, maximized, etc, as well as - * creating transient windows such as popup menus. - * @section page_iface_xdg_wm_base_api API - * See @ref iface_xdg_wm_base. - */ -/** - * @defgroup iface_xdg_wm_base The xdg_wm_base interface - * - * The xdg_wm_base interface is exposed as a global object enabling clients - * to turn their wl_surfaces into windows in a desktop environment. It - * defines the basic functionality needed for clients and the compositor to - * create windows that can be dragged, resized, maximized, etc, as well as - * creating transient windows such as popup menus. - */ -extern const struct wl_interface xdg_wm_base_interface; -#endif -#ifndef XDG_POSITIONER_INTERFACE -#define XDG_POSITIONER_INTERFACE -/** - * @page page_iface_xdg_positioner xdg_positioner - * @section page_iface_xdg_positioner_desc Description - * - * The xdg_positioner provides a collection of rules for the placement of a - * child surface relative to a parent surface. Rules can be defined to ensure - * the child surface remains within the visible area's borders, and to - * specify how the child surface changes its position, such as sliding along - * an axis, or flipping around a rectangle. These positioner-created rules are - * constrained by the requirement that a child surface must intersect with or - * be at least partially adjacent to its parent surface. - * - * See the various requests for details about possible rules. - * - * At the time of the request, the compositor makes a copy of the rules - * specified by the xdg_positioner. Thus, after the request is complete the - * xdg_positioner object can be destroyed or reused; further changes to the - * object will have no effect on previous usages. - * - * For an xdg_positioner object to be considered complete, it must have a - * non-zero size set by set_size, and a non-zero anchor rectangle set by - * set_anchor_rect. Passing an incomplete xdg_positioner object when - * positioning a surface raises an invalid_positioner error. - * @section page_iface_xdg_positioner_api API - * See @ref iface_xdg_positioner. - */ -/** - * @defgroup iface_xdg_positioner The xdg_positioner interface - * - * The xdg_positioner provides a collection of rules for the placement of a - * child surface relative to a parent surface. Rules can be defined to ensure - * the child surface remains within the visible area's borders, and to - * specify how the child surface changes its position, such as sliding along - * an axis, or flipping around a rectangle. These positioner-created rules are - * constrained by the requirement that a child surface must intersect with or - * be at least partially adjacent to its parent surface. - * - * See the various requests for details about possible rules. - * - * At the time of the request, the compositor makes a copy of the rules - * specified by the xdg_positioner. Thus, after the request is complete the - * xdg_positioner object can be destroyed or reused; further changes to the - * object will have no effect on previous usages. - * - * For an xdg_positioner object to be considered complete, it must have a - * non-zero size set by set_size, and a non-zero anchor rectangle set by - * set_anchor_rect. Passing an incomplete xdg_positioner object when - * positioning a surface raises an invalid_positioner error. - */ -extern const struct wl_interface xdg_positioner_interface; -#endif -#ifndef XDG_SURFACE_INTERFACE -#define XDG_SURFACE_INTERFACE -/** - * @page page_iface_xdg_surface xdg_surface - * @section page_iface_xdg_surface_desc Description - * - * An interface that may be implemented by a wl_surface, for - * implementations that provide a desktop-style user interface. - * - * It provides a base set of functionality required to construct user - * interface elements requiring management by the compositor, such as - * toplevel windows, menus, etc. The types of functionality are split into - * xdg_surface roles. - * - * Creating an xdg_surface does not set the role for a wl_surface. In order - * to map an xdg_surface, the client must create a role-specific object - * using, e.g., get_toplevel, get_popup. The wl_surface for any given - * xdg_surface can have at most one role, and may not be assigned any role - * not based on xdg_surface. - * - * A role must be assigned before any other requests are made to the - * xdg_surface object. - * - * The client must call wl_surface.commit on the corresponding wl_surface - * for the xdg_surface state to take effect. - * - * Creating an xdg_surface from a wl_surface which has a buffer attached or - * committed is a client error, and any attempts by a client to attach or - * manipulate a buffer prior to the first xdg_surface.configure call must - * also be treated as errors. - * - * After creating a role-specific object and setting it up, the client must - * perform an initial commit without any buffer attached. The compositor - * will reply with initial wl_surface state such as - * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure - * event. The client must acknowledge it and is then allowed to attach a - * buffer to map the surface. - * - * Mapping an xdg_surface-based role surface is defined as making it - * possible for the surface to be shown by the compositor. Note that - * a mapped surface is not guaranteed to be visible once it is mapped. - * - * For an xdg_surface to be mapped by the compositor, the following - * conditions must be met: - * (1) the client has assigned an xdg_surface-based role to the surface - * (2) the client has set and committed the xdg_surface state and the - * role-dependent state to the surface - * (3) the client has committed a buffer to the surface - * - * A newly-unmapped surface is considered to have met condition (1) out - * of the 3 required conditions for mapping a surface if its role surface - * has not been destroyed, i.e. the client must perform the initial commit - * again before attaching a buffer. - * @section page_iface_xdg_surface_api API - * See @ref iface_xdg_surface. - */ -/** - * @defgroup iface_xdg_surface The xdg_surface interface - * - * An interface that may be implemented by a wl_surface, for - * implementations that provide a desktop-style user interface. - * - * It provides a base set of functionality required to construct user - * interface elements requiring management by the compositor, such as - * toplevel windows, menus, etc. The types of functionality are split into - * xdg_surface roles. - * - * Creating an xdg_surface does not set the role for a wl_surface. In order - * to map an xdg_surface, the client must create a role-specific object - * using, e.g., get_toplevel, get_popup. The wl_surface for any given - * xdg_surface can have at most one role, and may not be assigned any role - * not based on xdg_surface. - * - * A role must be assigned before any other requests are made to the - * xdg_surface object. - * - * The client must call wl_surface.commit on the corresponding wl_surface - * for the xdg_surface state to take effect. - * - * Creating an xdg_surface from a wl_surface which has a buffer attached or - * committed is a client error, and any attempts by a client to attach or - * manipulate a buffer prior to the first xdg_surface.configure call must - * also be treated as errors. - * - * After creating a role-specific object and setting it up, the client must - * perform an initial commit without any buffer attached. The compositor - * will reply with initial wl_surface state such as - * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure - * event. The client must acknowledge it and is then allowed to attach a - * buffer to map the surface. - * - * Mapping an xdg_surface-based role surface is defined as making it - * possible for the surface to be shown by the compositor. Note that - * a mapped surface is not guaranteed to be visible once it is mapped. - * - * For an xdg_surface to be mapped by the compositor, the following - * conditions must be met: - * (1) the client has assigned an xdg_surface-based role to the surface - * (2) the client has set and committed the xdg_surface state and the - * role-dependent state to the surface - * (3) the client has committed a buffer to the surface - * - * A newly-unmapped surface is considered to have met condition (1) out - * of the 3 required conditions for mapping a surface if its role surface - * has not been destroyed, i.e. the client must perform the initial commit - * again before attaching a buffer. - */ -extern const struct wl_interface xdg_surface_interface; -#endif -#ifndef XDG_TOPLEVEL_INTERFACE -#define XDG_TOPLEVEL_INTERFACE -/** - * @page page_iface_xdg_toplevel xdg_toplevel - * @section page_iface_xdg_toplevel_desc Description - * - * This interface defines an xdg_surface role which allows a surface to, - * among other things, set window-like properties such as maximize, - * fullscreen, and minimize, set application-specific metadata like title and - * id, and well as trigger user interactive operations such as interactive - * resize and move. - * - * Unmapping an xdg_toplevel means that the surface cannot be shown - * by the compositor until it is explicitly mapped again. - * All active operations (e.g., move, resize) are canceled and all - * attributes (e.g. title, state, stacking, ...) are discarded for - * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to - * the state it had right after xdg_surface.get_toplevel. The client - * can re-map the toplevel by perfoming a commit without any buffer - * attached, waiting for a configure event and handling it as usual (see - * xdg_surface description). - * - * Attaching a null buffer to a toplevel unmaps the surface. - * @section page_iface_xdg_toplevel_api API - * See @ref iface_xdg_toplevel. - */ -/** - * @defgroup iface_xdg_toplevel The xdg_toplevel interface - * - * This interface defines an xdg_surface role which allows a surface to, - * among other things, set window-like properties such as maximize, - * fullscreen, and minimize, set application-specific metadata like title and - * id, and well as trigger user interactive operations such as interactive - * resize and move. - * - * Unmapping an xdg_toplevel means that the surface cannot be shown - * by the compositor until it is explicitly mapped again. - * All active operations (e.g., move, resize) are canceled and all - * attributes (e.g. title, state, stacking, ...) are discarded for - * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to - * the state it had right after xdg_surface.get_toplevel. The client - * can re-map the toplevel by perfoming a commit without any buffer - * attached, waiting for a configure event and handling it as usual (see - * xdg_surface description). - * - * Attaching a null buffer to a toplevel unmaps the surface. - */ -extern const struct wl_interface xdg_toplevel_interface; -#endif -#ifndef XDG_POPUP_INTERFACE -#define XDG_POPUP_INTERFACE -/** - * @page page_iface_xdg_popup xdg_popup - * @section page_iface_xdg_popup_desc Description - * - * A popup surface is a short-lived, temporary surface. It can be used to - * implement for example menus, popovers, tooltips and other similar user - * interface concepts. - * - * A popup can be made to take an explicit grab. See xdg_popup.grab for - * details. - * - * When the popup is dismissed, a popup_done event will be sent out, and at - * the same time the surface will be unmapped. See the xdg_popup.popup_done - * event for details. - * - * Explicitly destroying the xdg_popup object will also dismiss the popup and - * unmap the surface. Clients that want to dismiss the popup when another - * surface of their own is clicked should dismiss the popup using the destroy - * request. - * - * A newly created xdg_popup will be stacked on top of all previously created - * xdg_popup surfaces associated with the same xdg_toplevel. - * - * The parent of an xdg_popup must be mapped (see the xdg_surface - * description) before the xdg_popup itself. - * - * The client must call wl_surface.commit on the corresponding wl_surface - * for the xdg_popup state to take effect. - * @section page_iface_xdg_popup_api API - * See @ref iface_xdg_popup. - */ -/** - * @defgroup iface_xdg_popup The xdg_popup interface - * - * A popup surface is a short-lived, temporary surface. It can be used to - * implement for example menus, popovers, tooltips and other similar user - * interface concepts. - * - * A popup can be made to take an explicit grab. See xdg_popup.grab for - * details. - * - * When the popup is dismissed, a popup_done event will be sent out, and at - * the same time the surface will be unmapped. See the xdg_popup.popup_done - * event for details. - * - * Explicitly destroying the xdg_popup object will also dismiss the popup and - * unmap the surface. Clients that want to dismiss the popup when another - * surface of their own is clicked should dismiss the popup using the destroy - * request. - * - * A newly created xdg_popup will be stacked on top of all previously created - * xdg_popup surfaces associated with the same xdg_toplevel. - * - * The parent of an xdg_popup must be mapped (see the xdg_surface - * description) before the xdg_popup itself. - * - * The client must call wl_surface.commit on the corresponding wl_surface - * for the xdg_popup state to take effect. - */ -extern const struct wl_interface xdg_popup_interface; -#endif - -#ifndef XDG_WM_BASE_ERROR_ENUM -#define XDG_WM_BASE_ERROR_ENUM -enum xdg_wm_base_error { - /** - * given wl_surface has another role - */ - XDG_WM_BASE_ERROR_ROLE = 0, - /** - * xdg_wm_base was destroyed before children - */ - XDG_WM_BASE_ERROR_DEFUNCT_SURFACES = 1, - /** - * the client tried to map or destroy a non-topmost popup - */ - XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP = 2, - /** - * the client specified an invalid popup parent surface - */ - XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT = 3, - /** - * the client provided an invalid surface state - */ - XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE = 4, - /** - * the client provided an invalid positioner - */ - XDG_WM_BASE_ERROR_INVALID_POSITIONER = 5, - /** - * the client didn’t respond to a ping event in time - */ - XDG_WM_BASE_ERROR_UNRESPONSIVE = 6, -}; -#endif /* XDG_WM_BASE_ERROR_ENUM */ - -/** - * @ingroup iface_xdg_wm_base - * @struct xdg_wm_base_listener - */ -struct xdg_wm_base_listener { - /** - * check if the client is alive - * - * The ping event asks the client if it's still alive. Pass the - * serial specified in the event back to the compositor by sending - * a "pong" request back with the specified serial. See - * xdg_wm_base.pong. - * - * Compositors can use this to determine if the client is still - * alive. It's unspecified what will happen if the client doesn't - * respond to the ping request, or in what timeframe. Clients - * should try to respond in a reasonable amount of time. The - * “unresponsive” error is provided for compositors that wish - * to disconnect unresponsive clients. - * - * A compositor is free to ping in any way it wants, but a client - * must always respond to any xdg_wm_base object it created. - * @param serial pass this to the pong request - */ - void (*ping)(void *data, - struct xdg_wm_base *xdg_wm_base, - uint32_t serial); -}; - -/** - * @ingroup iface_xdg_wm_base - */ -static inline int -xdg_wm_base_add_listener(struct xdg_wm_base *xdg_wm_base, - const struct xdg_wm_base_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) xdg_wm_base, - (void (**)(void)) listener, data); -} - -#define XDG_WM_BASE_DESTROY 0 -#define XDG_WM_BASE_CREATE_POSITIONER 1 -#define XDG_WM_BASE_GET_XDG_SURFACE 2 -#define XDG_WM_BASE_PONG 3 - -/** - * @ingroup iface_xdg_wm_base - */ -#define XDG_WM_BASE_PING_SINCE_VERSION 1 - -/** - * @ingroup iface_xdg_wm_base - */ -#define XDG_WM_BASE_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_wm_base - */ -#define XDG_WM_BASE_CREATE_POSITIONER_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_wm_base - */ -#define XDG_WM_BASE_GET_XDG_SURFACE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_wm_base - */ -#define XDG_WM_BASE_PONG_SINCE_VERSION 1 - -/** @ingroup iface_xdg_wm_base */ -static inline void -xdg_wm_base_set_user_data(struct xdg_wm_base *xdg_wm_base, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) xdg_wm_base, user_data); -} - -/** @ingroup iface_xdg_wm_base */ -static inline void * -xdg_wm_base_get_user_data(struct xdg_wm_base *xdg_wm_base) -{ - return wl_proxy_get_user_data((struct wl_proxy *) xdg_wm_base); -} - -static inline uint32_t -xdg_wm_base_get_version(struct xdg_wm_base *xdg_wm_base) -{ - return wl_proxy_get_version((struct wl_proxy *) xdg_wm_base); -} - -/** - * @ingroup iface_xdg_wm_base - * - * Destroy this xdg_wm_base object. - * - * Destroying a bound xdg_wm_base object while there are surfaces - * still alive created by this xdg_wm_base object instance is illegal - * and will result in a defunct_surfaces error. - */ -static inline void -xdg_wm_base_destroy(struct xdg_wm_base *xdg_wm_base) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base, - XDG_WM_BASE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_xdg_wm_base - * - * Create a positioner object. A positioner object is used to position - * surfaces relative to some parent surface. See the interface description - * and xdg_surface.get_popup for details. - */ -static inline struct xdg_positioner * -xdg_wm_base_create_positioner(struct xdg_wm_base *xdg_wm_base) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base, - XDG_WM_BASE_CREATE_POSITIONER, &xdg_positioner_interface, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, NULL); - - return (struct xdg_positioner *) id; -} - -/** - * @ingroup iface_xdg_wm_base - * - * This creates an xdg_surface for the given surface. While xdg_surface - * itself is not a role, the corresponding surface may only be assigned - * a role extending xdg_surface, such as xdg_toplevel or xdg_popup. It is - * illegal to create an xdg_surface for a wl_surface which already has an - * assigned role and this will result in a role error. - * - * This creates an xdg_surface for the given surface. An xdg_surface is - * used as basis to define a role to a given surface, such as xdg_toplevel - * or xdg_popup. It also manages functionality shared between xdg_surface - * based surface roles. - * - * See the documentation of xdg_surface for more details about what an - * xdg_surface is and how it is used. - */ -static inline struct xdg_surface * -xdg_wm_base_get_xdg_surface(struct xdg_wm_base *xdg_wm_base, struct wl_surface *surface) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base, - XDG_WM_BASE_GET_XDG_SURFACE, &xdg_surface_interface, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, NULL, surface); - - return (struct xdg_surface *) id; -} - -/** - * @ingroup iface_xdg_wm_base - * - * A client must respond to a ping event with a pong request or - * the client may be deemed unresponsive. See xdg_wm_base.ping - * and xdg_wm_base.error.unresponsive. - */ -static inline void -xdg_wm_base_pong(struct xdg_wm_base *xdg_wm_base, uint32_t serial) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base, - XDG_WM_BASE_PONG, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, serial); -} - -#ifndef XDG_POSITIONER_ERROR_ENUM -#define XDG_POSITIONER_ERROR_ENUM -enum xdg_positioner_error { - /** - * invalid input provided - */ - XDG_POSITIONER_ERROR_INVALID_INPUT = 0, -}; -#endif /* XDG_POSITIONER_ERROR_ENUM */ - -#ifndef XDG_POSITIONER_ANCHOR_ENUM -#define XDG_POSITIONER_ANCHOR_ENUM -enum xdg_positioner_anchor { - XDG_POSITIONER_ANCHOR_NONE = 0, - XDG_POSITIONER_ANCHOR_TOP = 1, - XDG_POSITIONER_ANCHOR_BOTTOM = 2, - XDG_POSITIONER_ANCHOR_LEFT = 3, - XDG_POSITIONER_ANCHOR_RIGHT = 4, - XDG_POSITIONER_ANCHOR_TOP_LEFT = 5, - XDG_POSITIONER_ANCHOR_BOTTOM_LEFT = 6, - XDG_POSITIONER_ANCHOR_TOP_RIGHT = 7, - XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT = 8, -}; -#endif /* XDG_POSITIONER_ANCHOR_ENUM */ - -#ifndef XDG_POSITIONER_GRAVITY_ENUM -#define XDG_POSITIONER_GRAVITY_ENUM -enum xdg_positioner_gravity { - XDG_POSITIONER_GRAVITY_NONE = 0, - XDG_POSITIONER_GRAVITY_TOP = 1, - XDG_POSITIONER_GRAVITY_BOTTOM = 2, - XDG_POSITIONER_GRAVITY_LEFT = 3, - XDG_POSITIONER_GRAVITY_RIGHT = 4, - XDG_POSITIONER_GRAVITY_TOP_LEFT = 5, - XDG_POSITIONER_GRAVITY_BOTTOM_LEFT = 6, - XDG_POSITIONER_GRAVITY_TOP_RIGHT = 7, - XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT = 8, -}; -#endif /* XDG_POSITIONER_GRAVITY_ENUM */ - -#ifndef XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM -#define XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM -/** - * @ingroup iface_xdg_positioner - * constraint adjustments - * - * The constraint adjustment value define ways the compositor will adjust - * the position of the surface, if the unadjusted position would result - * in the surface being partly constrained. - * - * Whether a surface is considered 'constrained' is left to the compositor - * to determine. For example, the surface may be partly outside the - * compositor's defined 'work area', thus necessitating the child surface's - * position be adjusted until it is entirely inside the work area. - * - * The adjustments can be combined, according to a defined precedence: 1) - * Flip, 2) Slide, 3) Resize. - */ -enum xdg_positioner_constraint_adjustment { - /** - * don't move the child surface when constrained - * - * Don't alter the surface position even if it is constrained on - * some axis, for example partially outside the edge of an output. - */ - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE = 0, - /** - * move along the x axis until unconstrained - * - * Slide the surface along the x axis until it is no longer - * constrained. - * - * First try to slide towards the direction of the gravity on the x - * axis until either the edge in the opposite direction of the - * gravity is unconstrained or the edge in the direction of the - * gravity is constrained. - * - * Then try to slide towards the opposite direction of the gravity - * on the x axis until either the edge in the direction of the - * gravity is unconstrained or the edge in the opposite direction - * of the gravity is constrained. - */ - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1, - /** - * move along the y axis until unconstrained - * - * Slide the surface along the y axis until it is no longer - * constrained. - * - * First try to slide towards the direction of the gravity on the y - * axis until either the edge in the opposite direction of the - * gravity is unconstrained or the edge in the direction of the - * gravity is constrained. - * - * Then try to slide towards the opposite direction of the gravity - * on the y axis until either the edge in the direction of the - * gravity is unconstrained or the edge in the opposite direction - * of the gravity is constrained. - */ - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2, - /** - * invert the anchor and gravity on the x axis - * - * Invert the anchor and gravity on the x axis if the surface is - * constrained on the x axis. For example, if the left edge of the - * surface is constrained, the gravity is 'left' and the anchor is - * 'left', change the gravity to 'right' and the anchor to 'right'. - * - * If the adjusted position also ends up being constrained, the - * resulting position of the flip_x adjustment will be the one - * before the adjustment. - */ - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X = 4, - /** - * invert the anchor and gravity on the y axis - * - * Invert the anchor and gravity on the y axis if the surface is - * constrained on the y axis. For example, if the bottom edge of - * the surface is constrained, the gravity is 'bottom' and the - * anchor is 'bottom', change the gravity to 'top' and the anchor - * to 'top'. - * - * The adjusted position is calculated given the original anchor - * rectangle and offset, but with the new flipped anchor and - * gravity values. - * - * If the adjusted position also ends up being constrained, the - * resulting position of the flip_y adjustment will be the one - * before the adjustment. - */ - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8, - /** - * horizontally resize the surface - * - * Resize the surface horizontally so that it is completely - * unconstrained. - */ - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16, - /** - * vertically resize the surface - * - * Resize the surface vertically so that it is completely - * unconstrained. - */ - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32, -}; -#endif /* XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM */ - -#define XDG_POSITIONER_DESTROY 0 -#define XDG_POSITIONER_SET_SIZE 1 -#define XDG_POSITIONER_SET_ANCHOR_RECT 2 -#define XDG_POSITIONER_SET_ANCHOR 3 -#define XDG_POSITIONER_SET_GRAVITY 4 -#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT 5 -#define XDG_POSITIONER_SET_OFFSET 6 -#define XDG_POSITIONER_SET_REACTIVE 7 -#define XDG_POSITIONER_SET_PARENT_SIZE 8 -#define XDG_POSITIONER_SET_PARENT_CONFIGURE 9 - - -/** - * @ingroup iface_xdg_positioner - */ -#define XDG_POSITIONER_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_positioner - */ -#define XDG_POSITIONER_SET_SIZE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_positioner - */ -#define XDG_POSITIONER_SET_ANCHOR_RECT_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_positioner - */ -#define XDG_POSITIONER_SET_ANCHOR_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_positioner - */ -#define XDG_POSITIONER_SET_GRAVITY_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_positioner - */ -#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_positioner - */ -#define XDG_POSITIONER_SET_OFFSET_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_positioner - */ -#define XDG_POSITIONER_SET_REACTIVE_SINCE_VERSION 3 -/** - * @ingroup iface_xdg_positioner - */ -#define XDG_POSITIONER_SET_PARENT_SIZE_SINCE_VERSION 3 -/** - * @ingroup iface_xdg_positioner - */ -#define XDG_POSITIONER_SET_PARENT_CONFIGURE_SINCE_VERSION 3 - -/** @ingroup iface_xdg_positioner */ -static inline void -xdg_positioner_set_user_data(struct xdg_positioner *xdg_positioner, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) xdg_positioner, user_data); -} - -/** @ingroup iface_xdg_positioner */ -static inline void * -xdg_positioner_get_user_data(struct xdg_positioner *xdg_positioner) -{ - return wl_proxy_get_user_data((struct wl_proxy *) xdg_positioner); -} - -static inline uint32_t -xdg_positioner_get_version(struct xdg_positioner *xdg_positioner) -{ - return wl_proxy_get_version((struct wl_proxy *) xdg_positioner); -} - -/** - * @ingroup iface_xdg_positioner - * - * Notify the compositor that the xdg_positioner will no longer be used. - */ -static inline void -xdg_positioner_destroy(struct xdg_positioner *xdg_positioner) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, - XDG_POSITIONER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_xdg_positioner - * - * Set the size of the surface that is to be positioned with the positioner - * object. The size is in surface-local coordinates and corresponds to the - * window geometry. See xdg_surface.set_window_geometry. - * - * If a zero or negative size is set the invalid_input error is raised. - */ -static inline void -xdg_positioner_set_size(struct xdg_positioner *xdg_positioner, int32_t width, int32_t height) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, - XDG_POSITIONER_SET_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, width, height); -} - -/** - * @ingroup iface_xdg_positioner - * - * Specify the anchor rectangle within the parent surface that the child - * surface will be placed relative to. The rectangle is relative to the - * window geometry as defined by xdg_surface.set_window_geometry of the - * parent surface. - * - * When the xdg_positioner object is used to position a child surface, the - * anchor rectangle may not extend outside the window geometry of the - * positioned child's parent surface. - * - * If a negative size is set the invalid_input error is raised. - */ -static inline void -xdg_positioner_set_anchor_rect(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y, int32_t width, int32_t height) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, - XDG_POSITIONER_SET_ANCHOR_RECT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, x, y, width, height); -} - -/** - * @ingroup iface_xdg_positioner - * - * Defines the anchor point for the anchor rectangle. The specified anchor - * is used derive an anchor point that the child surface will be - * positioned relative to. If a corner anchor is set (e.g. 'top_left' or - * 'bottom_right'), the anchor point will be at the specified corner; - * otherwise, the derived anchor point will be centered on the specified - * edge, or in the center of the anchor rectangle if no edge is specified. - */ -static inline void -xdg_positioner_set_anchor(struct xdg_positioner *xdg_positioner, uint32_t anchor) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, - XDG_POSITIONER_SET_ANCHOR, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, anchor); -} - -/** - * @ingroup iface_xdg_positioner - * - * Defines in what direction a surface should be positioned, relative to - * the anchor point of the parent surface. If a corner gravity is - * specified (e.g. 'bottom_right' or 'top_left'), then the child surface - * will be placed towards the specified gravity; otherwise, the child - * surface will be centered over the anchor point on any axis that had no - * gravity specified. If the gravity is not in the ‘gravity’ enum, an - * invalid_input error is raised. - */ -static inline void -xdg_positioner_set_gravity(struct xdg_positioner *xdg_positioner, uint32_t gravity) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, - XDG_POSITIONER_SET_GRAVITY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, gravity); -} - -/** - * @ingroup iface_xdg_positioner - * - * Specify how the window should be positioned if the originally intended - * position caused the surface to be constrained, meaning at least - * partially outside positioning boundaries set by the compositor. The - * adjustment is set by constructing a bitmask describing the adjustment to - * be made when the surface is constrained on that axis. - * - * If no bit for one axis is set, the compositor will assume that the child - * surface should not change its position on that axis when constrained. - * - * If more than one bit for one axis is set, the order of how adjustments - * are applied is specified in the corresponding adjustment descriptions. - * - * The default adjustment is none. - */ -static inline void -xdg_positioner_set_constraint_adjustment(struct xdg_positioner *xdg_positioner, uint32_t constraint_adjustment) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, - XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, constraint_adjustment); -} - -/** - * @ingroup iface_xdg_positioner - * - * Specify the surface position offset relative to the position of the - * anchor on the anchor rectangle and the anchor on the surface. For - * example if the anchor of the anchor rectangle is at (x, y), the surface - * has the gravity bottom|right, and the offset is (ox, oy), the calculated - * surface position will be (x + ox, y + oy). The offset position of the - * surface is the one used for constraint testing. See - * set_constraint_adjustment. - * - * An example use case is placing a popup menu on top of a user interface - * element, while aligning the user interface element of the parent surface - * with some user interface element placed somewhere in the popup surface. - */ -static inline void -xdg_positioner_set_offset(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, - XDG_POSITIONER_SET_OFFSET, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, x, y); -} - -/** - * @ingroup iface_xdg_positioner - * - * When set reactive, the surface is reconstrained if the conditions used - * for constraining changed, e.g. the parent window moved. - * - * If the conditions changed and the popup was reconstrained, an - * xdg_popup.configure event is sent with updated geometry, followed by an - * xdg_surface.configure event. - */ -static inline void -xdg_positioner_set_reactive(struct xdg_positioner *xdg_positioner) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, - XDG_POSITIONER_SET_REACTIVE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0); -} - -/** - * @ingroup iface_xdg_positioner - * - * Set the parent window geometry the compositor should use when - * positioning the popup. The compositor may use this information to - * determine the future state the popup should be constrained using. If - * this doesn't match the dimension of the parent the popup is eventually - * positioned against, the behavior is undefined. - * - * The arguments are given in the surface-local coordinate space. - */ -static inline void -xdg_positioner_set_parent_size(struct xdg_positioner *xdg_positioner, int32_t parent_width, int32_t parent_height) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, - XDG_POSITIONER_SET_PARENT_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, parent_width, parent_height); -} - -/** - * @ingroup iface_xdg_positioner - * - * Set the serial of an xdg_surface.configure event this positioner will be - * used in response to. The compositor may use this information together - * with set_parent_size to determine what future state the popup should be - * constrained using. - */ -static inline void -xdg_positioner_set_parent_configure(struct xdg_positioner *xdg_positioner, uint32_t serial) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, - XDG_POSITIONER_SET_PARENT_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, serial); -} - -#ifndef XDG_SURFACE_ERROR_ENUM -#define XDG_SURFACE_ERROR_ENUM -enum xdg_surface_error { - /** - * Surface was not fully constructed - */ - XDG_SURFACE_ERROR_NOT_CONSTRUCTED = 1, - /** - * Surface was already constructed - */ - XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED = 2, - /** - * Attaching a buffer to an unconfigured surface - */ - XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER = 3, - /** - * Invalid serial number when acking a configure event - */ - XDG_SURFACE_ERROR_INVALID_SERIAL = 4, - /** - * Width or height was zero or negative - */ - XDG_SURFACE_ERROR_INVALID_SIZE = 5, - /** - * Surface was destroyed before its role object - */ - XDG_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT = 6, -}; -#endif /* XDG_SURFACE_ERROR_ENUM */ - -/** - * @ingroup iface_xdg_surface - * @struct xdg_surface_listener - */ -struct xdg_surface_listener { - /** - * suggest a surface change - * - * The configure event marks the end of a configure sequence. A - * configure sequence is a set of one or more events configuring - * the state of the xdg_surface, including the final - * xdg_surface.configure event. - * - * Where applicable, xdg_surface surface roles will during a - * configure sequence extend this event as a latched state sent as - * events before the xdg_surface.configure event. Such events - * should be considered to make up a set of atomically applied - * configuration states, where the xdg_surface.configure commits - * the accumulated state. - * - * Clients should arrange their surface for the new states, and - * then send an ack_configure request with the serial sent in this - * configure event at some point before committing the new surface. - * - * If the client receives multiple configure events before it can - * respond to one, it is free to discard all but the last event it - * received. - * @param serial serial of the configure event - */ - void (*configure)(void *data, - struct xdg_surface *xdg_surface, - uint32_t serial); -}; - -/** - * @ingroup iface_xdg_surface - */ -static inline int -xdg_surface_add_listener(struct xdg_surface *xdg_surface, - const struct xdg_surface_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) xdg_surface, - (void (**)(void)) listener, data); -} - -#define XDG_SURFACE_DESTROY 0 -#define XDG_SURFACE_GET_TOPLEVEL 1 -#define XDG_SURFACE_GET_POPUP 2 -#define XDG_SURFACE_SET_WINDOW_GEOMETRY 3 -#define XDG_SURFACE_ACK_CONFIGURE 4 - -/** - * @ingroup iface_xdg_surface - */ -#define XDG_SURFACE_CONFIGURE_SINCE_VERSION 1 - -/** - * @ingroup iface_xdg_surface - */ -#define XDG_SURFACE_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_surface - */ -#define XDG_SURFACE_GET_TOPLEVEL_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_surface - */ -#define XDG_SURFACE_GET_POPUP_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_surface - */ -#define XDG_SURFACE_SET_WINDOW_GEOMETRY_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_surface - */ -#define XDG_SURFACE_ACK_CONFIGURE_SINCE_VERSION 1 - -/** @ingroup iface_xdg_surface */ -static inline void -xdg_surface_set_user_data(struct xdg_surface *xdg_surface, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) xdg_surface, user_data); -} - -/** @ingroup iface_xdg_surface */ -static inline void * -xdg_surface_get_user_data(struct xdg_surface *xdg_surface) -{ - return wl_proxy_get_user_data((struct wl_proxy *) xdg_surface); -} - -static inline uint32_t -xdg_surface_get_version(struct xdg_surface *xdg_surface) -{ - return wl_proxy_get_version((struct wl_proxy *) xdg_surface); -} - -/** - * @ingroup iface_xdg_surface - * - * Destroy the xdg_surface object. An xdg_surface must only be destroyed - * after its role object has been destroyed, otherwise - * a defunct_role_object error is raised. - */ -static inline void -xdg_surface_destroy(struct xdg_surface *xdg_surface) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, - XDG_SURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_xdg_surface - * - * This creates an xdg_toplevel object for the given xdg_surface and gives - * the associated wl_surface the xdg_toplevel role. - * - * See the documentation of xdg_toplevel for more details about what an - * xdg_toplevel is and how it is used. - */ -static inline struct xdg_toplevel * -xdg_surface_get_toplevel(struct xdg_surface *xdg_surface) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, - XDG_SURFACE_GET_TOPLEVEL, &xdg_toplevel_interface, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, NULL); - - return (struct xdg_toplevel *) id; -} - -/** - * @ingroup iface_xdg_surface - * - * This creates an xdg_popup object for the given xdg_surface and gives - * the associated wl_surface the xdg_popup role. - * - * If null is passed as a parent, a parent surface must be specified using - * some other protocol, before committing the initial state. - * - * See the documentation of xdg_popup for more details about what an - * xdg_popup is and how it is used. - */ -static inline struct xdg_popup * -xdg_surface_get_popup(struct xdg_surface *xdg_surface, struct xdg_surface *parent, struct xdg_positioner *positioner) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, - XDG_SURFACE_GET_POPUP, &xdg_popup_interface, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, NULL, parent, positioner); - - return (struct xdg_popup *) id; -} - -/** - * @ingroup iface_xdg_surface - * - * The window geometry of a surface is its "visible bounds" from the - * user's perspective. Client-side decorations often have invisible - * portions like drop-shadows which should be ignored for the - * purposes of aligning, placing and constraining windows. - * - * The window geometry is double buffered, and will be applied at the - * time wl_surface.commit of the corresponding wl_surface is called. - * - * When maintaining a position, the compositor should treat the (x, y) - * coordinate of the window geometry as the top left corner of the window. - * A client changing the (x, y) window geometry coordinate should in - * general not alter the position of the window. - * - * Once the window geometry of the surface is set, it is not possible to - * unset it, and it will remain the same until set_window_geometry is - * called again, even if a new subsurface or buffer is attached. - * - * If never set, the value is the full bounds of the surface, - * including any subsurfaces. This updates dynamically on every - * commit. This unset is meant for extremely simple clients. - * - * The arguments are given in the surface-local coordinate space of - * the wl_surface associated with this xdg_surface, and may extend outside - * of the wl_surface itself to mark parts of the subsurface tree as part of - * the window geometry. - * - * When applied, the effective window geometry will be the set window - * geometry clamped to the bounding rectangle of the combined - * geometry of the surface of the xdg_surface and the associated - * subsurfaces. - * - * The effective geometry will not be recalculated unless a new call to - * set_window_geometry is done and the new pending surface state is - * subsequently applied. - * - * The width and height of the effective window geometry must be - * greater than zero. Setting an invalid size will raise an - * invalid_size error. - */ -static inline void -xdg_surface_set_window_geometry(struct xdg_surface *xdg_surface, int32_t x, int32_t y, int32_t width, int32_t height) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, - XDG_SURFACE_SET_WINDOW_GEOMETRY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, x, y, width, height); -} - -/** - * @ingroup iface_xdg_surface - * - * When a configure event is received, if a client commits the - * surface in response to the configure event, then the client - * must make an ack_configure request sometime before the commit - * request, passing along the serial of the configure event. - * - * For instance, for toplevel surfaces the compositor might use this - * information to move a surface to the top left only when the client has - * drawn itself for the maximized or fullscreen state. - * - * If the client receives multiple configure events before it - * can respond to one, it only has to ack the last configure event. - * Acking a configure event that was never sent raises an invalid_serial - * error. - * - * A client is not required to commit immediately after sending - * an ack_configure request - it may even ack_configure several times - * before its next surface commit. - * - * A client may send multiple ack_configure requests before committing, but - * only the last request sent before a commit indicates which configure - * event the client really is responding to. - * - * Sending an ack_configure request consumes the serial number sent with - * the request, as well as serial numbers sent by all configure events - * sent on this xdg_surface prior to the configure event referenced by - * the committed serial. - * - * It is an error to issue multiple ack_configure requests referencing a - * serial from the same configure event, or to issue an ack_configure - * request referencing a serial from a configure event issued before the - * event identified by the last ack_configure request for the same - * xdg_surface. Doing so will raise an invalid_serial error. - */ -static inline void -xdg_surface_ack_configure(struct xdg_surface *xdg_surface, uint32_t serial) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, - XDG_SURFACE_ACK_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, serial); -} - -#ifndef XDG_TOPLEVEL_ERROR_ENUM -#define XDG_TOPLEVEL_ERROR_ENUM -enum xdg_toplevel_error { - /** - * provided value is not a valid variant of the resize_edge enum - */ - XDG_TOPLEVEL_ERROR_INVALID_RESIZE_EDGE = 0, - /** - * invalid parent toplevel - */ - XDG_TOPLEVEL_ERROR_INVALID_PARENT = 1, - /** - * client provided an invalid min or max size - */ - XDG_TOPLEVEL_ERROR_INVALID_SIZE = 2, -}; -#endif /* XDG_TOPLEVEL_ERROR_ENUM */ - -#ifndef XDG_TOPLEVEL_RESIZE_EDGE_ENUM -#define XDG_TOPLEVEL_RESIZE_EDGE_ENUM -/** - * @ingroup iface_xdg_toplevel - * edge values for resizing - * - * These values are used to indicate which edge of a surface - * is being dragged in a resize operation. - */ -enum xdg_toplevel_resize_edge { - XDG_TOPLEVEL_RESIZE_EDGE_NONE = 0, - XDG_TOPLEVEL_RESIZE_EDGE_TOP = 1, - XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2, - XDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4, - XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT = 5, - XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT = 6, - XDG_TOPLEVEL_RESIZE_EDGE_RIGHT = 8, - XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT = 9, - XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT = 10, -}; -#endif /* XDG_TOPLEVEL_RESIZE_EDGE_ENUM */ - -#ifndef XDG_TOPLEVEL_STATE_ENUM -#define XDG_TOPLEVEL_STATE_ENUM -/** - * @ingroup iface_xdg_toplevel - * types of state on the surface - * - * The different state values used on the surface. This is designed for - * state values like maximized, fullscreen. It is paired with the - * configure event to ensure that both the client and the compositor - * setting the state can be synchronized. - * - * States set in this way are double-buffered. They will get applied on - * the next commit. - */ -enum xdg_toplevel_state { - /** - * the surface is maximized - * the surface is maximized - * - * The surface is maximized. The window geometry specified in the - * configure event must be obeyed by the client, or the - * xdg_wm_base.invalid_surface_state error is raised. - * - * The client should draw without shadow or other decoration - * outside of the window geometry. - */ - XDG_TOPLEVEL_STATE_MAXIMIZED = 1, - /** - * the surface is fullscreen - * the surface is fullscreen - * - * The surface is fullscreen. The window geometry specified in - * the configure event is a maximum; the client cannot resize - * beyond it. For a surface to cover the whole fullscreened area, - * the geometry dimensions must be obeyed by the client. For more - * details, see xdg_toplevel.set_fullscreen. - */ - XDG_TOPLEVEL_STATE_FULLSCREEN = 2, - /** - * the surface is being resized - * the surface is being resized - * - * The surface is being resized. The window geometry specified in - * the configure event is a maximum; the client cannot resize - * beyond it. Clients that have aspect ratio or cell sizing - * configuration can use a smaller size, however. - */ - XDG_TOPLEVEL_STATE_RESIZING = 3, - /** - * the surface is now activated - * the surface is now activated - * - * Client window decorations should be painted as if the window - * is active. Do not assume this means that the window actually has - * keyboard or pointer focus. - */ - XDG_TOPLEVEL_STATE_ACTIVATED = 4, - /** - * the surface’s left edge is tiled - * - * The window is currently in a tiled layout and the left edge is - * considered to be adjacent to another part of the tiling grid. - * @since 2 - */ - XDG_TOPLEVEL_STATE_TILED_LEFT = 5, - /** - * the surface’s right edge is tiled - * - * The window is currently in a tiled layout and the right edge - * is considered to be adjacent to another part of the tiling grid. - * @since 2 - */ - XDG_TOPLEVEL_STATE_TILED_RIGHT = 6, - /** - * the surface’s top edge is tiled - * - * The window is currently in a tiled layout and the top edge is - * considered to be adjacent to another part of the tiling grid. - * @since 2 - */ - XDG_TOPLEVEL_STATE_TILED_TOP = 7, - /** - * the surface’s bottom edge is tiled - * - * The window is currently in a tiled layout and the bottom edge - * is considered to be adjacent to another part of the tiling grid. - * @since 2 - */ - XDG_TOPLEVEL_STATE_TILED_BOTTOM = 8, - /** - * surface repaint is suspended - * - * The surface is currently not ordinarily being repainted; for - * example because its content is occluded by another window, or - * its outputs are switched off due to screen locking. - * @since 6 - */ - XDG_TOPLEVEL_STATE_SUSPENDED = 9, -}; -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION 2 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION 2 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_STATE_TILED_TOP_SINCE_VERSION 2 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_STATE_TILED_BOTTOM_SINCE_VERSION 2 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION 6 -#endif /* XDG_TOPLEVEL_STATE_ENUM */ - -#ifndef XDG_TOPLEVEL_WM_CAPABILITIES_ENUM -#define XDG_TOPLEVEL_WM_CAPABILITIES_ENUM -enum xdg_toplevel_wm_capabilities { - /** - * show_window_menu is available - */ - XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU = 1, - /** - * set_maximized and unset_maximized are available - */ - XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE = 2, - /** - * set_fullscreen and unset_fullscreen are available - */ - XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN = 3, - /** - * set_minimized is available - */ - XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE = 4, -}; -#endif /* XDG_TOPLEVEL_WM_CAPABILITIES_ENUM */ - -/** - * @ingroup iface_xdg_toplevel - * @struct xdg_toplevel_listener - */ -struct xdg_toplevel_listener { - /** - * suggest a surface change - * - * This configure event asks the client to resize its toplevel - * surface or to change its state. The configured state should not - * be applied immediately. See xdg_surface.configure for details. - * - * The width and height arguments specify a hint to the window - * about how its surface should be resized in window geometry - * coordinates. See set_window_geometry. - * - * If the width or height arguments are zero, it means the client - * should decide its own window dimension. This may happen when the - * compositor needs to configure the state of the surface but - * doesn't have any information about any previous or expected - * dimension. - * - * The states listed in the event specify how the width/height - * arguments should be interpreted, and possibly how it should be - * drawn. - * - * Clients must send an ack_configure in response to this event. - * See xdg_surface.configure and xdg_surface.ack_configure for - * details. - */ - void (*configure)(void *data, - struct xdg_toplevel *xdg_toplevel, - int32_t width, - int32_t height, - struct wl_array *states); - /** - * surface wants to be closed - * - * The close event is sent by the compositor when the user wants - * the surface to be closed. This should be equivalent to the user - * clicking the close button in client-side decorations, if your - * application has any. - * - * This is only a request that the user intends to close the - * window. The client may choose to ignore this request, or show a - * dialog to ask the user to save their data, etc. - */ - void (*close)(void *data, - struct xdg_toplevel *xdg_toplevel); - /** - * recommended window geometry bounds - * - * The configure_bounds event may be sent prior to a - * xdg_toplevel.configure event to communicate the bounds a window - * geometry size is recommended to constrain to. - * - * The passed width and height are in surface coordinate space. If - * width and height are 0, it means bounds is unknown and - * equivalent to as if no configure_bounds event was ever sent for - * this surface. - * - * The bounds can for example correspond to the size of a monitor - * excluding any panels or other shell components, so that a - * surface isn't created in a way that it cannot fit. - * - * The bounds may change at any point, and in such a case, a new - * xdg_toplevel.configure_bounds will be sent, followed by - * xdg_toplevel.configure and xdg_surface.configure. - * @since 4 - */ - void (*configure_bounds)(void *data, - struct xdg_toplevel *xdg_toplevel, - int32_t width, - int32_t height); - /** - * compositor capabilities - * - * This event advertises the capabilities supported by the - * compositor. If a capability isn't supported, clients should hide - * or disable the UI elements that expose this functionality. For - * instance, if the compositor doesn't advertise support for - * minimized toplevels, a button triggering the set_minimized - * request should not be displayed. - * - * The compositor will ignore requests it doesn't support. For - * instance, a compositor which doesn't advertise support for - * minimized will ignore set_minimized requests. - * - * Compositors must send this event once before the first - * xdg_surface.configure event. When the capabilities change, - * compositors must send this event again and then send an - * xdg_surface.configure event. - * - * The configured state should not be applied immediately. See - * xdg_surface.configure for details. - * - * The capabilities are sent as an array of 32-bit unsigned - * integers in native endianness. - * @param capabilities array of 32-bit capabilities - * @since 5 - */ - void (*wm_capabilities)(void *data, - struct xdg_toplevel *xdg_toplevel, - struct wl_array *capabilities); -}; - -/** - * @ingroup iface_xdg_toplevel - */ -static inline int -xdg_toplevel_add_listener(struct xdg_toplevel *xdg_toplevel, - const struct xdg_toplevel_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) xdg_toplevel, - (void (**)(void)) listener, data); -} - -#define XDG_TOPLEVEL_DESTROY 0 -#define XDG_TOPLEVEL_SET_PARENT 1 -#define XDG_TOPLEVEL_SET_TITLE 2 -#define XDG_TOPLEVEL_SET_APP_ID 3 -#define XDG_TOPLEVEL_SHOW_WINDOW_MENU 4 -#define XDG_TOPLEVEL_MOVE 5 -#define XDG_TOPLEVEL_RESIZE 6 -#define XDG_TOPLEVEL_SET_MAX_SIZE 7 -#define XDG_TOPLEVEL_SET_MIN_SIZE 8 -#define XDG_TOPLEVEL_SET_MAXIMIZED 9 -#define XDG_TOPLEVEL_UNSET_MAXIMIZED 10 -#define XDG_TOPLEVEL_SET_FULLSCREEN 11 -#define XDG_TOPLEVEL_UNSET_FULLSCREEN 12 -#define XDG_TOPLEVEL_SET_MINIMIZED 13 - -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_CONFIGURE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_CLOSE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION 4 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION 5 - -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_SET_PARENT_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_SET_TITLE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_SET_APP_ID_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_SHOW_WINDOW_MENU_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_MOVE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_RESIZE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_SET_MAX_SIZE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_SET_MIN_SIZE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_SET_MAXIMIZED_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_UNSET_MAXIMIZED_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_SET_FULLSCREEN_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_UNSET_FULLSCREEN_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_SET_MINIMIZED_SINCE_VERSION 1 - -/** @ingroup iface_xdg_toplevel */ -static inline void -xdg_toplevel_set_user_data(struct xdg_toplevel *xdg_toplevel, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) xdg_toplevel, user_data); -} - -/** @ingroup iface_xdg_toplevel */ -static inline void * -xdg_toplevel_get_user_data(struct xdg_toplevel *xdg_toplevel) -{ - return wl_proxy_get_user_data((struct wl_proxy *) xdg_toplevel); -} - -static inline uint32_t -xdg_toplevel_get_version(struct xdg_toplevel *xdg_toplevel) -{ - return wl_proxy_get_version((struct wl_proxy *) xdg_toplevel); -} - -/** - * @ingroup iface_xdg_toplevel - * - * This request destroys the role surface and unmaps the surface; - * see "Unmapping" behavior in interface section for details. - */ -static inline void -xdg_toplevel_destroy(struct xdg_toplevel *xdg_toplevel) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_xdg_toplevel - * - * Set the "parent" of this surface. This surface should be stacked - * above the parent surface and all other ancestor surfaces. - * - * Parent surfaces should be set on dialogs, toolboxes, or other - * "auxiliary" surfaces, so that the parent is raised when the dialog - * is raised. - * - * Setting a null parent for a child surface unsets its parent. Setting - * a null parent for a surface which currently has no parent is a no-op. - * - * Only mapped surfaces can have child surfaces. Setting a parent which - * is not mapped is equivalent to setting a null parent. If a surface - * becomes unmapped, its children's parent is set to the parent of - * the now-unmapped surface. If the now-unmapped surface has no parent, - * its children's parent is unset. If the now-unmapped surface becomes - * mapped again, its parent-child relationship is not restored. - * - * The parent toplevel must not be one of the child toplevel's - * descendants, and the parent must be different from the child toplevel, - * otherwise the invalid_parent protocol error is raised. - */ -static inline void -xdg_toplevel_set_parent(struct xdg_toplevel *xdg_toplevel, struct xdg_toplevel *parent) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_SET_PARENT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, parent); -} - -/** - * @ingroup iface_xdg_toplevel - * - * Set a short title for the surface. - * - * This string may be used to identify the surface in a task bar, - * window list, or other user interface elements provided by the - * compositor. - * - * The string must be encoded in UTF-8. - */ -static inline void -xdg_toplevel_set_title(struct xdg_toplevel *xdg_toplevel, const char *title) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_SET_TITLE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, title); -} - -/** - * @ingroup iface_xdg_toplevel - * - * Set an application identifier for the surface. - * - * The app ID identifies the general class of applications to which - * the surface belongs. The compositor can use this to group multiple - * surfaces together, or to determine how to launch a new application. - * - * For D-Bus activatable applications, the app ID is used as the D-Bus - * service name. - * - * The compositor shell will try to group application surfaces together - * by their app ID. As a best practice, it is suggested to select app - * ID's that match the basename of the application's .desktop file. - * For example, "org.freedesktop.FooViewer" where the .desktop file is - * "org.freedesktop.FooViewer.desktop". - * - * Like other properties, a set_app_id request can be sent after the - * xdg_toplevel has been mapped to update the property. - * - * See the desktop-entry specification [0] for more details on - * application identifiers and how they relate to well-known D-Bus - * names and .desktop files. - * - * [0] https://standards.freedesktop.org/desktop-entry-spec/ - */ -static inline void -xdg_toplevel_set_app_id(struct xdg_toplevel *xdg_toplevel, const char *app_id) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_SET_APP_ID, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, app_id); -} - -/** - * @ingroup iface_xdg_toplevel - * - * Clients implementing client-side decorations might want to show - * a context menu when right-clicking on the decorations, giving the - * user a menu that they can use to maximize or minimize the window. - * - * This request asks the compositor to pop up such a window menu at - * the given position, relative to the local surface coordinates of - * the parent surface. There are no guarantees as to what menu items - * the window menu contains, or even if a window menu will be drawn - * at all. - * - * This request must be used in response to some sort of user action - * like a button press, key press, or touch down event. - */ -static inline void -xdg_toplevel_show_window_menu(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_SHOW_WINDOW_MENU, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial, x, y); -} - -/** - * @ingroup iface_xdg_toplevel - * - * Start an interactive, user-driven move of the surface. - * - * This request must be used in response to some sort of user action - * like a button press, key press, or touch down event. The passed - * serial is used to determine the type of interactive move (touch, - * pointer, etc). - * - * The server may ignore move requests depending on the state of - * the surface (e.g. fullscreen or maximized), or if the passed serial - * is no longer valid. - * - * If triggered, the surface will lose the focus of the device - * (wl_pointer, wl_touch, etc) used for the move. It is up to the - * compositor to visually indicate that the move is taking place, such as - * updating a pointer cursor, during the move. There is no guarantee - * that the device focus will return when the move is completed. - */ -static inline void -xdg_toplevel_move(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_MOVE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial); -} - -/** - * @ingroup iface_xdg_toplevel - * - * Start a user-driven, interactive resize of the surface. - * - * This request must be used in response to some sort of user action - * like a button press, key press, or touch down event. The passed - * serial is used to determine the type of interactive resize (touch, - * pointer, etc). - * - * The server may ignore resize requests depending on the state of - * the surface (e.g. fullscreen or maximized). - * - * If triggered, the client will receive configure events with the - * "resize" state enum value and the expected sizes. See the "resize" - * enum value for more details about what is required. The client - * must also acknowledge configure events using "ack_configure". After - * the resize is completed, the client will receive another "configure" - * event without the resize state. - * - * If triggered, the surface also will lose the focus of the device - * (wl_pointer, wl_touch, etc) used for the resize. It is up to the - * compositor to visually indicate that the resize is taking place, - * such as updating a pointer cursor, during the resize. There is no - * guarantee that the device focus will return when the resize is - * completed. - * - * The edges parameter specifies how the surface should be resized, and - * is one of the values of the resize_edge enum. Values not matching - * a variant of the enum will cause the invalid_resize_edge protocol error. - * The compositor may use this information to update the surface position - * for example when dragging the top left corner. The compositor may also - * use this information to adapt its behavior, e.g. choose an appropriate - * cursor image. - */ -static inline void -xdg_toplevel_resize(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, uint32_t edges) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial, edges); -} - -/** - * @ingroup iface_xdg_toplevel - * - * Set a maximum size for the window. - * - * The client can specify a maximum size so that the compositor does - * not try to configure the window beyond this size. - * - * The width and height arguments are in window geometry coordinates. - * See xdg_surface.set_window_geometry. - * - * Values set in this way are double-buffered. They will get applied - * on the next commit. - * - * The compositor can use this information to allow or disallow - * different states like maximize or fullscreen and draw accurate - * animations. - * - * Similarly, a tiling window manager may use this information to - * place and resize client windows in a more effective way. - * - * The client should not rely on the compositor to obey the maximum - * size. The compositor may decide to ignore the values set by the - * client and request a larger size. - * - * If never set, or a value of zero in the request, means that the - * client has no expected maximum size in the given dimension. - * As a result, a client wishing to reset the maximum size - * to an unspecified state can use zero for width and height in the - * request. - * - * Requesting a maximum size to be smaller than the minimum size of - * a surface is illegal and will result in an invalid_size error. - * - * The width and height must be greater than or equal to zero. Using - * strictly negative values for width or height will result in a - * invalid_size error. - */ -static inline void -xdg_toplevel_set_max_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_SET_MAX_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, width, height); -} - -/** - * @ingroup iface_xdg_toplevel - * - * Set a minimum size for the window. - * - * The client can specify a minimum size so that the compositor does - * not try to configure the window below this size. - * - * The width and height arguments are in window geometry coordinates. - * See xdg_surface.set_window_geometry. - * - * Values set in this way are double-buffered. They will get applied - * on the next commit. - * - * The compositor can use this information to allow or disallow - * different states like maximize or fullscreen and draw accurate - * animations. - * - * Similarly, a tiling window manager may use this information to - * place and resize client windows in a more effective way. - * - * The client should not rely on the compositor to obey the minimum - * size. The compositor may decide to ignore the values set by the - * client and request a smaller size. - * - * If never set, or a value of zero in the request, means that the - * client has no expected minimum size in the given dimension. - * As a result, a client wishing to reset the minimum size - * to an unspecified state can use zero for width and height in the - * request. - * - * Requesting a minimum size to be larger than the maximum size of - * a surface is illegal and will result in an invalid_size error. - * - * The width and height must be greater than or equal to zero. Using - * strictly negative values for width and height will result in a - * invalid_size error. - */ -static inline void -xdg_toplevel_set_min_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_SET_MIN_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, width, height); -} - -/** - * @ingroup iface_xdg_toplevel - * - * Maximize the surface. - * - * After requesting that the surface should be maximized, the compositor - * will respond by emitting a configure event. Whether this configure - * actually sets the window maximized is subject to compositor policies. - * The client must then update its content, drawing in the configured - * state. The client must also acknowledge the configure when committing - * the new content (see ack_configure). - * - * It is up to the compositor to decide how and where to maximize the - * surface, for example which output and what region of the screen should - * be used. - * - * If the surface was already maximized, the compositor will still emit - * a configure event with the "maximized" state. - * - * If the surface is in a fullscreen state, this request has no direct - * effect. It may alter the state the surface is returned to when - * unmaximized unless overridden by the compositor. - */ -static inline void -xdg_toplevel_set_maximized(struct xdg_toplevel *xdg_toplevel) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_SET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0); -} - -/** - * @ingroup iface_xdg_toplevel - * - * Unmaximize the surface. - * - * After requesting that the surface should be unmaximized, the compositor - * will respond by emitting a configure event. Whether this actually - * un-maximizes the window is subject to compositor policies. - * If available and applicable, the compositor will include the window - * geometry dimensions the window had prior to being maximized in the - * configure event. The client must then update its content, drawing it in - * the configured state. The client must also acknowledge the configure - * when committing the new content (see ack_configure). - * - * It is up to the compositor to position the surface after it was - * unmaximized; usually the position the surface had before maximizing, if - * applicable. - * - * If the surface was already not maximized, the compositor will still - * emit a configure event without the "maximized" state. - * - * If the surface is in a fullscreen state, this request has no direct - * effect. It may alter the state the surface is returned to when - * unmaximized unless overridden by the compositor. - */ -static inline void -xdg_toplevel_unset_maximized(struct xdg_toplevel *xdg_toplevel) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_UNSET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0); -} - -/** - * @ingroup iface_xdg_toplevel - * - * Make the surface fullscreen. - * - * After requesting that the surface should be fullscreened, the - * compositor will respond by emitting a configure event. Whether the - * client is actually put into a fullscreen state is subject to compositor - * policies. The client must also acknowledge the configure when - * committing the new content (see ack_configure). - * - * The output passed by the request indicates the client's preference as - * to which display it should be set fullscreen on. If this value is NULL, - * it's up to the compositor to choose which display will be used to map - * this surface. - * - * If the surface doesn't cover the whole output, the compositor will - * position the surface in the center of the output and compensate with - * with border fill covering the rest of the output. The content of the - * border fill is undefined, but should be assumed to be in some way that - * attempts to blend into the surrounding area (e.g. solid black). - * - * If the fullscreened surface is not opaque, the compositor must make - * sure that other screen content not part of the same surface tree (made - * up of subsurfaces, popups or similarly coupled surfaces) are not - * visible below the fullscreened surface. - */ -static inline void -xdg_toplevel_set_fullscreen(struct xdg_toplevel *xdg_toplevel, struct wl_output *output) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_SET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, output); -} - -/** - * @ingroup iface_xdg_toplevel - * - * Make the surface no longer fullscreen. - * - * After requesting that the surface should be unfullscreened, the - * compositor will respond by emitting a configure event. - * Whether this actually removes the fullscreen state of the client is - * subject to compositor policies. - * - * Making a surface unfullscreen sets states for the surface based on the following: - * * the state(s) it may have had before becoming fullscreen - * * any state(s) decided by the compositor - * * any state(s) requested by the client while the surface was fullscreen - * - * The compositor may include the previous window geometry dimensions in - * the configure event, if applicable. - * - * The client must also acknowledge the configure when committing the new - * content (see ack_configure). - */ -static inline void -xdg_toplevel_unset_fullscreen(struct xdg_toplevel *xdg_toplevel) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_UNSET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0); -} - -/** - * @ingroup iface_xdg_toplevel - * - * Request that the compositor minimize your surface. There is no - * way to know if the surface is currently minimized, nor is there - * any way to unset minimization on this surface. - * - * If you are looking to throttle redrawing when minimized, please - * instead use the wl_surface.frame event for this, as this will - * also work with live previews on windows in Alt-Tab, Expose or - * similar compositor features. - */ -static inline void -xdg_toplevel_set_minimized(struct xdg_toplevel *xdg_toplevel) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, - XDG_TOPLEVEL_SET_MINIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0); -} - -#ifndef XDG_POPUP_ERROR_ENUM -#define XDG_POPUP_ERROR_ENUM -enum xdg_popup_error { - /** - * tried to grab after being mapped - */ - XDG_POPUP_ERROR_INVALID_GRAB = 0, -}; -#endif /* XDG_POPUP_ERROR_ENUM */ - -/** - * @ingroup iface_xdg_popup - * @struct xdg_popup_listener - */ -struct xdg_popup_listener { - /** - * configure the popup surface - * - * This event asks the popup surface to configure itself given - * the configuration. The configured state should not be applied - * immediately. See xdg_surface.configure for details. - * - * The x and y arguments represent the position the popup was - * placed at given the xdg_positioner rule, relative to the upper - * left corner of the window geometry of the parent surface. - * - * For version 2 or older, the configure event for an xdg_popup is - * only ever sent once for the initial configuration. Starting with - * version 3, it may be sent again if the popup is setup with an - * xdg_positioner with set_reactive requested, or in response to - * xdg_popup.reposition requests. - * @param x x position relative to parent surface window geometry - * @param y y position relative to parent surface window geometry - * @param width window geometry width - * @param height window geometry height - */ - void (*configure)(void *data, - struct xdg_popup *xdg_popup, - int32_t x, - int32_t y, - int32_t width, - int32_t height); - /** - * popup interaction is done - * - * The popup_done event is sent out when a popup is dismissed by - * the compositor. The client should destroy the xdg_popup object - * at this point. - */ - void (*popup_done)(void *data, - struct xdg_popup *xdg_popup); - /** - * signal the completion of a repositioned request - * - * The repositioned event is sent as part of a popup - * configuration sequence, together with xdg_popup.configure and - * lastly xdg_surface.configure to notify the completion of a - * reposition request. - * - * The repositioned event is to notify about the completion of a - * xdg_popup.reposition request. The token argument is the token - * passed in the xdg_popup.reposition request. - * - * Immediately after this event is emitted, xdg_popup.configure and - * xdg_surface.configure will be sent with the updated size and - * position, as well as a new configure serial. - * - * The client should optionally update the content of the popup, - * but must acknowledge the new popup configuration for the new - * position to take effect. See xdg_surface.ack_configure for - * details. - * @param token reposition request token - * @since 3 - */ - void (*repositioned)(void *data, - struct xdg_popup *xdg_popup, - uint32_t token); -}; - -/** - * @ingroup iface_xdg_popup - */ -static inline int -xdg_popup_add_listener(struct xdg_popup *xdg_popup, - const struct xdg_popup_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) xdg_popup, - (void (**)(void)) listener, data); -} - -#define XDG_POPUP_DESTROY 0 -#define XDG_POPUP_GRAB 1 -#define XDG_POPUP_REPOSITION 2 - -/** - * @ingroup iface_xdg_popup - */ -#define XDG_POPUP_CONFIGURE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_popup - */ -#define XDG_POPUP_POPUP_DONE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_popup - */ -#define XDG_POPUP_REPOSITIONED_SINCE_VERSION 3 - -/** - * @ingroup iface_xdg_popup - */ -#define XDG_POPUP_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_popup - */ -#define XDG_POPUP_GRAB_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_popup - */ -#define XDG_POPUP_REPOSITION_SINCE_VERSION 3 - -/** @ingroup iface_xdg_popup */ -static inline void -xdg_popup_set_user_data(struct xdg_popup *xdg_popup, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) xdg_popup, user_data); -} - -/** @ingroup iface_xdg_popup */ -static inline void * -xdg_popup_get_user_data(struct xdg_popup *xdg_popup) -{ - return wl_proxy_get_user_data((struct wl_proxy *) xdg_popup); -} - -static inline uint32_t -xdg_popup_get_version(struct xdg_popup *xdg_popup) -{ - return wl_proxy_get_version((struct wl_proxy *) xdg_popup); -} - -/** - * @ingroup iface_xdg_popup - * - * This destroys the popup. Explicitly destroying the xdg_popup - * object will also dismiss the popup, and unmap the surface. - * - * If this xdg_popup is not the "topmost" popup, the - * xdg_wm_base.not_the_topmost_popup protocol error will be sent. - */ -static inline void -xdg_popup_destroy(struct xdg_popup *xdg_popup) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup, - XDG_POPUP_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_xdg_popup - * - * This request makes the created popup take an explicit grab. An explicit - * grab will be dismissed when the user dismisses the popup, or when the - * client destroys the xdg_popup. This can be done by the user clicking - * outside the surface, using the keyboard, or even locking the screen - * through closing the lid or a timeout. - * - * If the compositor denies the grab, the popup will be immediately - * dismissed. - * - * This request must be used in response to some sort of user action like a - * button press, key press, or touch down event. The serial number of the - * event should be passed as 'serial'. - * - * The parent of a grabbing popup must either be an xdg_toplevel surface or - * another xdg_popup with an explicit grab. If the parent is another - * xdg_popup it means that the popups are nested, with this popup now being - * the topmost popup. - * - * Nested popups must be destroyed in the reverse order they were created - * in, e.g. the only popup you are allowed to destroy at all times is the - * topmost one. - * - * When compositors choose to dismiss a popup, they may dismiss every - * nested grabbing popup as well. When a compositor dismisses popups, it - * will follow the same dismissing order as required from the client. - * - * If the topmost grabbing popup is destroyed, the grab will be returned to - * the parent of the popup, if that parent previously had an explicit grab. - * - * If the parent is a grabbing popup which has already been dismissed, this - * popup will be immediately dismissed. If the parent is a popup that did - * not take an explicit grab, an error will be raised. - * - * During a popup grab, the client owning the grab will receive pointer - * and touch events for all their surfaces as normal (similar to an - * "owner-events" grab in X11 parlance), while the top most grabbing popup - * will always have keyboard focus. - */ -static inline void -xdg_popup_grab(struct xdg_popup *xdg_popup, struct wl_seat *seat, uint32_t serial) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup, - XDG_POPUP_GRAB, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), 0, seat, serial); -} - -/** - * @ingroup iface_xdg_popup - * - * Reposition an already-mapped popup. The popup will be placed given the - * details in the passed xdg_positioner object, and a - * xdg_popup.repositioned followed by xdg_popup.configure and - * xdg_surface.configure will be emitted in response. Any parameters set - * by the previous positioner will be discarded. - * - * The passed token will be sent in the corresponding - * xdg_popup.repositioned event. The new popup position will not take - * effect until the corresponding configure event is acknowledged by the - * client. See xdg_popup.repositioned for details. The token itself is - * opaque, and has no other special meaning. - * - * If multiple reposition requests are sent, the compositor may skip all - * but the last one. - * - * If the popup is repositioned in response to a configure event for its - * parent, the client should send an xdg_positioner.set_parent_configure - * and possibly an xdg_positioner.set_parent_size request to allow the - * compositor to properly constrain the popup. - * - * If the popup is repositioned together with a parent that is being - * resized, but not in response to a configure event, the client should - * send an xdg_positioner.set_parent_size request. - */ -static inline void -xdg_popup_reposition(struct xdg_popup *xdg_popup, struct xdg_positioner *positioner, uint32_t token) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup, - XDG_POPUP_REPOSITION, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), 0, positioner, token); -} - -#ifdef __cplusplus -} -#endif - -#endif From 101d7c0bc2b464ba95f29617344da94a0ffa3e32 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Fri, 8 Dec 2023 15:32:40 -0500 Subject: [PATCH 16/93] screens, and other misc things --- examples/dashboard/java/Example.java | 6 +-- wayland/cc/AppWayland.cc | 10 +++- wayland/cc/LayerGLWayland.cc | 1 - wayland/cc/LayerRasterWayland.cc | 12 ++--- wayland/cc/WindowManagerWayland.cc | 10 +++- wayland/cc/WindowWayland.cc | 69 ++++++++++++++++++---------- wayland/cc/WindowWayland.hh | 13 ++++-- 7 files changed, 80 insertions(+), 41 deletions(-) diff --git a/examples/dashboard/java/Example.java b/examples/dashboard/java/Example.java index 3df7cac5..28150556 100644 --- a/examples/dashboard/java/Example.java +++ b/examples/dashboard/java/Example.java @@ -55,9 +55,9 @@ public Example() { var scale = window.getScale(); int count = App._windows.size() - 1; - // Screen screen = App.getScreens()[(count / 5) % App.getScreens().length]; - // IRect bounds = screen.getWorkArea(); - IRect bounds = new IRect(0, 0, 100, 100); + Screen screen = App.getScreens()[(count / 5) % App.getScreens().length]; + IRect bounds = screen.getWorkArea(); + // IRect bounds = new IRect(0, 0, 100, 100); window.setTitle("JWM Window #" + count); if (window instanceof WindowMac windowMac) { diff --git a/wayland/cc/AppWayland.cc b/wayland/cc/AppWayland.cc index 326963c0..6e5f68a9 100644 --- a/wayland/cc/AppWayland.cc +++ b/wayland/cc/AppWayland.cc @@ -46,7 +46,15 @@ extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_App__1nRunOnUIThre // how awful extern "C" JNIEXPORT jobjectArray JNICALL Java_io_github_humbleui_jwm_App__1nGetScreens(JNIEnv* env, jobject cls) noexcept { - jobjectArray array = env->NewObjectArray(0, jwm::classes::Screen::kCls, 0); + + + jobjectArray array = env->NewObjectArray(jwm::app.wm.outputs.size(), jwm::classes::Screen::kCls, 0); + size_t index = 0; + + for (auto& i : jwm::app.wm.outputs) { + env->SetObjectArrayElement(array, index++, i->getScreenInfo().asJavaObject(env)); + } + return array; } diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index 44ba6e90..474fa7a5 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -118,7 +118,6 @@ namespace jwm { // _region = wl_compositor_create_region(fWindow->_windowManager.compositor); // wl_region_add(_region, 0, 0, fWindow->getWidth(), fWindow->getHeight()); // wl_surface_set_opaque_region(fWindow->_waylandWindow, _region); - printf("%i %i\n", fWindow->getWidth(), fWindow->getHeight()); _eglWindow = wl_egl_window_create(fWindow->_waylandWindow, fWindow->getWidth(), fWindow->getHeight()); _surface = eglCreateWindowSurface(_display, _config, _eglWindow, nullptr); diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index 1e1d620c..8457d266 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -24,11 +24,10 @@ namespace jwm { fWindow = jwm::ref(window); fWindow->setLayer(this); // must have a default size for pointer initing : ) - resize(400, 400); + resize(window->getWidth(), window->getHeight()); } void resize(int width, int height) override { - printf("???\n"); wl_display* d = fWindow->_windowManager.display; _width = width; _height = height; @@ -41,9 +40,6 @@ namespace jwm { _pool->close(); } _pool = new ShmPool(fWindow->_windowManager.shm, bufSize); - if (fWindow->_waylandWindow) { - wl_surface_attach(fWindow->_waylandWindow, nullptr, 0, 0); - } if (_buffer) { wl_buffer_destroy(_buffer); _imageData = nullptr; @@ -56,7 +52,7 @@ namespace jwm { if (_attached) { attachBuffer(); } - makeCurrentForced(); + // makeCurrentForced(); } const void* getPixelsPtr() const { @@ -69,7 +65,7 @@ namespace jwm { } void swapBuffers() override { - if (fWindow->_waylandWindow && _attached) { + if (fWindow->_waylandWindow) { wl_surface_damage_buffer(fWindow->_waylandWindow, 0, 0, INT32_MAX, INT32_MAX); wl_surface_commit(fWindow->_waylandWindow); } @@ -97,8 +93,10 @@ namespace jwm { void attachBuffer() override { if (fWindow) { if (fWindow->_waylandWindow) { + printf("gataching \n"); wl_surface_attach(fWindow->_waylandWindow, _buffer, 0, 0); wl_surface_damage_buffer(fWindow->_waylandWindow, 0, 0, INT32_MAX, INT32_MAX); + wl_surface_set_buffer_scale(fWindow->_waylandWindow, fWindow->_scale); wl_surface_commit(fWindow->_waylandWindow); _attached = true; } diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index a69e9126..60238201 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -220,11 +220,19 @@ void WindowManagerWayland::registryHandleGlobalRemove(void* data, wl_registry *r } } WindowWayland* WindowManagerWayland::getWindowForNative(wl_surface* surface) { + // the tag makes it safe. Should:TM: be faster than searching a list every time + const char* const* tag = wl_proxy_get_tag((wl_proxy*) surface); + if (tag != &WindowWayland::_windowTag) { + return nullptr; + } + return reinterpret_cast(wl_surface_get_user_data(surface)); + /* WindowWayland* myWindow = nullptr; auto it = _nativeWindowToMy.find(surface); if (it != _nativeWindowToMy.end()) myWindow = it->second; return myWindow; + */ } void WindowManagerWayland::pointerHandleEnter(void* data, wl_pointer* pointer, uint32_t serial, wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { @@ -447,7 +455,6 @@ void WindowManagerWayland::keyboardRepeatInfo(void* data, wl_keyboard* keyboard, void WindowManagerWayland::seatCapabilities(void* data, wl_seat* seat, uint32_t capabilities) { auto self = reinterpret_cast(data); - printf("%i", capabilities & WL_SEAT_CAPABILITY_POINTER); if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && !self->pointer) { self->pointer = wl_seat_get_pointer(seat); @@ -459,7 +466,6 @@ void WindowManagerWayland::seatCapabilities(void* data, wl_seat* seat, uint32_t if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && !self->keyboard) { - printf("got da keyboard\n"); self->keyboard = wl_seat_get_keyboard(seat); self->_xkbContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS); wl_keyboard_add_listener(self->keyboard, &_keyboardListener, self); diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index eab791a5..e300b8d2 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -32,6 +32,8 @@ libdecor_frame_interface WindowWayland::_libdecorFrameInterface = { .dismiss_popup = WindowWayland::decorFrameDismissPopup }; +const char* WindowWayland::_windowTag = "WindowWayland"; + WindowWayland::WindowWayland(JNIEnv* env, WindowManagerWayland& windowManager): jwm::Window(env), _windowManager(windowManager) @@ -44,11 +46,15 @@ WindowWayland::~WindowWayland() { void WindowWayland::setTitle(const std::string& title) { - // impl me : ) + _title = title.c_str(); + if (_frame) + libdecor_frame_set_title(_frame, _title); } void WindowWayland::setTitlebarVisible(bool isVisible) { - // impl me : ) + _titlebarVisible = isVisible; + if (_frame) + libdecor_frame_set_visibility(_frame, isVisible); } // Closing is like... the exact same as hiding. WTH @@ -85,6 +91,11 @@ bool WindowWayland::isFullScreen() { return false; } +void WindowWayland::setLayer(ILayerWayland* layer) { + _layer = layer; + if (_visible) + _layer->attachBuffer(); +} void WindowWayland::getDecorations(int& left, int& top, int& right, int& bottom) { // impl me : ) left = 0; @@ -101,6 +112,9 @@ void WindowWayland::getContentPosition(int& posX, int& posY) { } bool WindowWayland::resize(int width, int height) { + // don't allow size to be set if currently tiled + if (!_floating && !_visible) + return false; // Width and height are in absolute pixel units, and wayland will // complain if you try to set a width/height that isn't a multiple of scale. if ((width % _scale) != 0 || (height % _scale) != 0) @@ -145,12 +159,7 @@ void WindowWayland::show() wl_surface_add_listener(_waylandWindow, &_surfaceListener, this); // unsure if listener data and user data are the same, so i do this for safety : ) wl_surface_set_user_data(_waylandWindow, this); - - // xdgSurface = xdg_wm_base_get_xdg_surface(_windowManager.xdgShell, _waylandWindow); - // xdg_surface_add_listener(xdgSurface, &_xdgSurfaceListener, this); - - // xdgToplevel = xdg_surface_get_toplevel(xdgSurface); - // xdg_toplevel_add_listener(xdgToplevel, &_xdgToplevelListener, this); + wl_proxy_set_tag((wl_proxy*) _waylandWindow, &_windowTag); _windowManager.registerWindow(this); _frame = libdecor_decorate(_windowManager.decorCtx, _waylandWindow, &_libdecorFrameInterface, this); @@ -159,6 +168,8 @@ void WindowWayland::show() libdecor_dispatch(_windowManager.decorCtx, -1); if (_width > 0 && _height > 0) resize(_width * _scale, _height * _scale); + setTitle(_title); + setTitlebarVisible(_titlebarVisible); } ScreenInfo WindowWayland::getScreen() { @@ -240,20 +251,22 @@ void jwm::WindowWayland::outputScale(void* data, wl_output* output, int factor) } void jwm::WindowWayland::outputName(void* data, wl_output* output, const char* name) {} void jwm::WindowWayland::outputDescription(void* data, wl_output* output, const char* desc) {} - wl_callback_listener jwm::WindowWayland::_frameCallback = { .done = [](void* data, wl_callback* cb, uint32_t cb_data) { auto self = reinterpret_cast(data); self->_adaptSize(self->_newWidth, self->_newHeight); } }; + void jwm::WindowWayland::decorFrameConfigure(libdecor_frame* frame, libdecor_configuration* configuration, void *userData) { auto self = reinterpret_cast(userData); int width = 0, height = 0; - + libdecor_window_state winState; + libdecor_configuration_get_content_size(configuration, frame, &width, &height); + width = (width <= 0) ? self->_floatingWidth : width; height = (height <= 0) ? self->_floatingHeight : height; @@ -261,21 +274,32 @@ void jwm::WindowWayland::decorFrameConfigure(libdecor_frame* frame, libdecor_con libdecor_frame_commit(frame, state, configuration); libdecor_state_free(state); - if (libdecor_frame_is_floating(frame)) { - if (width > 0) - self->_floatingWidth = width; - if (height > 0) - self->_floatingHeight = height; + if (libdecor_configuration_get_window_state(configuration, &winState)) { + self->_active = (winState & LIBDECOR_WINDOW_STATE_ACTIVE) != 0; + self->_maximized = (winState & LIBDECOR_WINDOW_STATE_MAXIMIZED) != 0; + self->_fullscreen = (winState & LIBDECOR_WINDOW_STATE_FULLSCREEN) != 0; + self->_floating = libdecor_frame_is_floating(frame); } + if (self->_width != width || self->_height != height) { + if (libdecor_frame_is_floating(frame)) { + if (width > 0) + self->_floatingWidth = width; + if (height > 0) + self->_floatingHeight = height; + } + + self->_newWidth = width; + self->_newHeight = height; + // This flat out breaks window if it isn't throttled + wl_callback* callback = wl_surface_frame(self->_waylandWindow); + // Throttle frame + wl_callback_add_listener(callback, &_frameCallback, self); + } if (!self->_configured && self->_layer) { self->_layer->attachBuffer(); } - self->_newWidth = width; - self->_newHeight = height; - wl_callback* callback = wl_surface_frame(self->_waylandWindow); - // Throttle frame - wl_callback_add_listener(callback, &_frameCallback, self); + self->_configured = true; } void jwm::WindowWayland::decorFrameClose(libdecor_frame* frame, void* userData) { @@ -284,8 +308,7 @@ void jwm::WindowWayland::decorFrameClose(libdecor_frame* frame, void* userData) } void jwm::WindowWayland::decorFrameCommit(libdecor_frame* frame, void* userData) { WindowWayland* self = reinterpret_cast(userData); - if (self->_layer) - self->_layer->swapBuffers(); + self->requestRedraw(); } void jwm::WindowWayland::decorFrameDismissPopup(libdecor_frame* frame, const char* seatName, void* userData) {} void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { @@ -399,7 +422,7 @@ extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nS jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); jbyte* bytes = env->GetByteArrayElements(title, nullptr); - std::string titleS = { bytes, bytes + env->GetArrayLength(title) }; + std::string titleS((const char*) bytes, env->GetArrayLength(title)); env->ReleaseByteArrayElements(title, bytes, 0); instance->setTitle(titleS); diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index e04c366d..8e2de85a 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -46,9 +46,7 @@ namespace jwm { bool isFullScreen(); void setCursor(jwm::MouseCursor cursor); - void setLayer(ILayerWayland* layer) { - _layer = layer; - } + void setLayer(ILayerWayland* layer); ScreenInfo getScreen(); @@ -92,8 +90,13 @@ namespace jwm { bool _canFullscreen = false; bool _visible = false; bool _configured = false; - + bool _active = false; + bool _maximized = false; + bool _fullscreen = false; + bool _floating = false; bool _isRedrawRequested = false; + const char* _title = ""; + bool _titlebarVisible = true; WindowManagerWayland& _windowManager; ILayerWayland* _layer = nullptr; @@ -108,5 +111,7 @@ namespace jwm { static wl_callback_listener _frameCallback; + static const char* _windowTag; + }; } From f7ba6380eeeed690087a351d10249b10e982b3b7 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Fri, 8 Dec 2023 17:03:40 -0500 Subject: [PATCH 17/93] title/titlebar :) --- wayland/CMakeLists.txt | 3 +-- wayland/cc/ShmPool.cc | 2 +- wayland/cc/WindowWayland.cc | 21 ++++++++++++++------- wayland/cc/WindowWayland.hh | 3 ++- wayland/java/WindowWayland.java | 9 ++++----- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/wayland/CMakeLists.txt b/wayland/CMakeLists.txt index a7ead2f8..47a98501 100644 --- a/wayland/CMakeLists.txt +++ b/wayland/CMakeLists.txt @@ -4,8 +4,7 @@ cmake_minimum_required(VERSION 3.9) cmake_policy(SET CMP0072 NEW) project(jwm LANGUAGES CXX) -project(xdgShell LANGUAGES C) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) if(NOT JWM_ARCH) diff --git a/wayland/cc/ShmPool.cc b/wayland/cc/ShmPool.cc index fa429540..13bfe5ef 100644 --- a/wayland/cc/ShmPool.cc +++ b/wayland/cc/ShmPool.cc @@ -93,5 +93,5 @@ int ShmPool::_allocateShmFile(size_t size) { std::pair ShmPool::createBuffer(int offset, int width, int height, int stride, uint32_t format) { wl_buffer* buffer = wl_shm_pool_create_buffer(_pool, offset, width, height, stride, format); uint8_t* data = &_rawData[offset]; - return std::pair(buffer, data); + return std::pair(buffer, data); } diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index e300b8d2..c2398aff 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -5,6 +5,8 @@ #include "AppWayland.hh" #include "impl/Library.hh" #include "impl/JNILocal.hh" +#include +#include using namespace jwm; @@ -36,7 +38,9 @@ const char* WindowWayland::_windowTag = "WindowWayland"; WindowWayland::WindowWayland(JNIEnv* env, WindowManagerWayland& windowManager): jwm::Window(env), - _windowManager(windowManager) + _windowManager(windowManager), + _title("") + { } @@ -46,9 +50,9 @@ WindowWayland::~WindowWayland() { void WindowWayland::setTitle(const std::string& title) { - _title = title.c_str(); + _title = title; if (_frame) - libdecor_frame_set_title(_frame, _title); + libdecor_frame_set_title(_frame, _title.c_str()); } void WindowWayland::setTitlebarVisible(bool isVisible) { @@ -418,13 +422,16 @@ extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nC instance->close(); } extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nSetTitle - (JNIEnv* env, jobject obj, jbyteArray title) { + (JNIEnv* env, jobject obj, jstring title) { jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); - jbyte* bytes = env->GetByteArrayElements(title, nullptr); - std::string titleS((const char*) bytes, env->GetArrayLength(title)); - env->ReleaseByteArrayElements(title, bytes, 0); + const jchar* bytes = env->GetStringChars(title, nullptr); + jsize length = env->GetStringLength(title); + std::u16string thingie = {reinterpret_cast(bytes), length}; + std::string titleS = std::wstring_convert< + std::codecvt_utf8_utf16, char16_t>{}.to_bytes(thingie); + env->ReleaseStringChars(title, bytes); instance->setTitle(titleS); } diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index 8e2de85a..fe119dda 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -7,6 +7,7 @@ #include "ILayerWayland.hh" #include "ScreenInfo.hh" #include +#include namespace jwm { class WindowWayland: public jwm::Window { public: @@ -95,7 +96,7 @@ namespace jwm { bool _fullscreen = false; bool _floating = false; bool _isRedrawRequested = false; - const char* _title = ""; + std::string _title; bool _titlebarVisible = true; WindowManagerWayland& _windowManager; diff --git a/wayland/java/WindowWayland.java b/wayland/java/WindowWayland.java index 666bc04e..74441875 100644 --- a/wayland/java/WindowWayland.java +++ b/wayland/java/WindowWayland.java @@ -50,7 +50,8 @@ public Window setWindowPosition(int left, int top) { @Override public Window setWindowSize(int width, int height) { assert _onUIThread() : "Should be run on UI thread"; - // no : ) + // TODO: don't assume bounds + setContentSize(width, height); return this; } @@ -64,9 +65,7 @@ public Window setContentSize(int width, int height) { @Override public Window setTitle(String title) { assert _onUIThread() : "Should be run on UI thread"; - try { - _nSetTitle(title.getBytes("UTF-8")); - } catch (UnsupportedEncodingException ignored) {} + _nSetTitle(title); return this; } @@ -231,7 +230,7 @@ public float getScale() { @ApiStatus.Internal public native void _nMaximize(); @ApiStatus.Internal public native void _nMinimize(); @ApiStatus.Internal public native void _nRestore(); - @ApiStatus.Internal public native Screen _nSetTitle(byte[] title); + @ApiStatus.Internal public native Screen _nSetTitle(String title); @ApiStatus.Internal public native void _nSetTitlebarVisible(boolean isVisible); @ApiStatus.Internal public native void _nSetFullScreen(boolean isFullScreen); @ApiStatus.Internal public native boolean _nIsFullScreen(); From 62a8da1bdd236692aad0ef01ff3bbba7371f4918 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Fri, 8 Dec 2023 17:38:40 -0500 Subject: [PATCH 18/93] Events for focus, maximize --- wayland/cc/WindowWayland.cc | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index c2398aff..177d5934 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -279,9 +279,30 @@ void jwm::WindowWayland::decorFrameConfigure(libdecor_frame* frame, libdecor_con libdecor_state_free(state); if (libdecor_configuration_get_window_state(configuration, &winState)) { - self->_active = (winState & LIBDECOR_WINDOW_STATE_ACTIVE) != 0; - self->_maximized = (winState & LIBDECOR_WINDOW_STATE_MAXIMIZED) != 0; - self->_fullscreen = (winState & LIBDECOR_WINDOW_STATE_FULLSCREEN) != 0; + bool active = (winState & LIBDECOR_WINDOW_STATE_ACTIVE) != 0; + bool maximized = (winState & LIBDECOR_WINDOW_STATE_MAXIMIZED) != 0; + bool fullscreen = (winState & LIBDECOR_WINDOW_STATE_FULLSCREEN) != 0; + // Some compositors (like weston) don't actually tell me on focus in and focus out. + // Libdecor simply sends an active at the beginning and keeps chugging. + if (active != self->_active) + if (active) + self->dispatch(classes::EventWindowFocusIn::kInstance); + else + self->dispatch(classes::EventWindowFocusOut::kInstance); + self->_active = active; + if (maximized != self->_maximized) + if (maximized) + self->dispatch(classes::EventWindowMaximize::kInstance); + self->_maximized = maximized; + // ??? + /* + if (fullscreen != self->_fullscreen) + if (fullscreen) + self->dispatch(classes::EventWindowFullScreenEnter::kInstance); + else + self->dispatch(classes::EventWindowFullScreenLeave::kInstance); + */ + self->_fullscreen = fullscreen; self->_floating = libdecor_frame_is_floating(frame); } if (self->_width != width || self->_height != height) { From 863fab0328392454e6e5e63bf4455f7e67ee20e9 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Sat, 9 Dec 2023 01:14:15 -0500 Subject: [PATCH 19/93] Partially working Raster --- shared/java/Window.java | 2 +- wayland/cc/AppWayland.cc | 13 ++- wayland/cc/AppWayland.hh | 6 +- wayland/cc/Buffer.cc | 101 ++++++++++++++++++++++ wayland/cc/Buffer.hh | 33 ++++++++ wayland/cc/ILayerWayland.hh | 1 + wayland/cc/LayerGLWayland.cc | 26 ++++-- wayland/cc/LayerRasterWayland.cc | 107 ++++++++++++------------ wayland/cc/ShmPool.cc | 2 +- wayland/cc/WindowManagerWayland.cc | 130 +++++++++++++---------------- wayland/cc/WindowManagerWayland.hh | 11 ++- wayland/cc/WindowWayland.cc | 62 ++++++++------ wayland/cc/WindowWayland.hh | 3 + 13 files changed, 334 insertions(+), 163 deletions(-) create mode 100644 wayland/cc/Buffer.cc create mode 100644 wayland/cc/Buffer.hh diff --git a/shared/java/Window.java b/shared/java/Window.java index d156b949..7b5ce0a4 100644 --- a/shared/java/Window.java +++ b/shared/java/Window.java @@ -423,7 +423,7 @@ public void accept(Event e) { if (e instanceof EventWindowScreenChange) { accept(new EventWindowResize(this)); - } else if (e instanceof EventWindowResize && Platform.CURRENT != Platform.X11) { + } else if (e instanceof EventWindowResize && Platform.CURRENT != Platform.X11 && Platform.CURRENT != Platform.WAYLAND) { accept(EventFrame.INSTANCE); } } diff --git a/wayland/cc/AppWayland.cc b/wayland/cc/AppWayland.cc index 6e5f68a9..e32a2575 100644 --- a/wayland/cc/AppWayland.cc +++ b/wayland/cc/AppWayland.cc @@ -2,12 +2,13 @@ #include "AppWayland.hh" #include #include - +#include jwm::AppWayland jwm::app; void jwm::AppWayland::init(JNIEnv* jniEnv) { - _jniEnv = jniEnv; + jint rs = jniEnv->GetJavaVM(&_javaVM); + assert(rs == JNI_OK); } void jwm::AppWayland::start() { @@ -18,6 +19,14 @@ void jwm::AppWayland::terminate() { wm.terminate(); } +JNIEnv* jwm::AppWayland::getJniEnv() { + JNIEnv* env; + // no-op on an already attached thread, so fast? + // makes it thread-safe (?) + jint rs = _javaVM->AttachCurrentThread((void**)&env, nullptr); + assert(rs == JNI_OK); + return env; +} // JNI extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_App__1nStart(JNIEnv* env, jclass jclass, jobject launcher) { diff --git a/wayland/cc/AppWayland.hh b/wayland/cc/AppWayland.hh index d0907b8c..2b5ba6f6 100644 --- a/wayland/cc/AppWayland.hh +++ b/wayland/cc/AppWayland.hh @@ -19,11 +19,9 @@ namespace jwm { return wm; } - JNIEnv* getJniEnv() { - return _jniEnv; - } + JNIEnv* getJniEnv(); - JNIEnv* _jniEnv; + JavaVM* _javaVM; WindowManagerWayland wm; } app; } diff --git a/wayland/cc/Buffer.cc b/wayland/cc/Buffer.cc new file mode 100644 index 00000000..35644145 --- /dev/null +++ b/wayland/cc/Buffer.cc @@ -0,0 +1,101 @@ +#include "Buffer.hh" +#include +#include +#include +#include +#include +using namespace jwm; + +wl_buffer_listener Buffer::_bufferListener = { + .release = [](void* data, wl_buffer* wlbuffer) { + auto buffer = reinterpret_cast(data); + delete buffer; + } +}; +static void randname(char *buf) +{ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + long r = ts.tv_nsec; + for (int i = 0; i < 6; ++i) { + buf[i] = 'A'+(r&15)+(r&16)*2; + r >>= 5; + } +} +static int _createShmFile() { + int retries = 100; + do { + char name[] = "/wl_shm-XXXXXX"; + randname(name + sizeof(name) - 7); + --retries; + int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); + if (fd >= 0) { + shm_unlink(name); + return fd; + } + } while (retries > 0 && errno == EEXIST); + return -1; +} + +static int _allocateShmFile(size_t size) { + int fd = _createShmFile(); + if (fd < 0) + return -1; + int ret; + do { + ret = ftruncate(fd, size); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + ::close(fd); + return -1; + } + return fd; +} +Buffer::Buffer(wl_buffer* buffer, + int width, + int height, + void *data, + size_t dataSize) : + _buffer(buffer), + _width(width), + _height(height), + _data(data), + _dataSize(dataSize) +{ + wl_buffer_add_listener(buffer, &_bufferListener, this); +} +Buffer::~Buffer() +{ + wl_buffer_destroy(_buffer); + munmap(_data, _dataSize); +} + +Buffer* Buffer::createShmBuffer(wl_shm* shm, int width, int height, uint32_t format) +{ + wl_shm_pool* pool; + int fd, size, stride; + void* data; + wl_buffer* buffer; + + stride = width * 4; + size = stride * height; + + fd = _allocateShmFile(size); + if (fd < 0) + return nullptr; + + data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) { + close(fd); + return nullptr; + } + + pool = wl_shm_create_pool(shm, fd, size); + + buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride, format); + + wl_shm_pool_destroy(pool); + close(fd); + + return new Buffer(buffer, width, height, data, size); +} diff --git a/wayland/cc/Buffer.hh b/wayland/cc/Buffer.hh new file mode 100644 index 00000000..d6bfe08c --- /dev/null +++ b/wayland/cc/Buffer.hh @@ -0,0 +1,33 @@ +#include +#include +#include + +namespace jwm { + class Buffer { + public: + Buffer(wl_buffer* buffer, + int width, + int height, + void *data, + size_t dataSize); + ~Buffer(); + wl_buffer* _buffer; + wl_buffer* getBuffer() const { + return _buffer; + } + int _width; + int _height; + void* _data; + void* getData() const { + return _data; + } + size_t _dataSize; + size_t getSize() { + return _dataSize; + } + + static wl_buffer_listener _bufferListener; + + static Buffer* createShmBuffer(wl_shm* shm, int width, int height, uint32_t format); + }; +} diff --git a/wayland/cc/ILayerWayland.hh b/wayland/cc/ILayerWayland.hh index d05ee848..68d2727f 100644 --- a/wayland/cc/ILayerWayland.hh +++ b/wayland/cc/ILayerWayland.hh @@ -7,5 +7,6 @@ namespace jwm { public: virtual void attachBuffer() = 0; virtual void swapBuffers() = 0; + virtual void detach() = 0; }; } diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index 474fa7a5..75562795 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -29,6 +29,11 @@ namespace jwm { void attach(WindowWayland* window) { fWindow = jwm::ref(window); fWindow->setLayer(this); + // HACK: reopen + bool visible = fWindow->_visible; + if (visible) { + fWindow->hide(); + } if (_display == nullptr) { _display = eglGetDisplay(window->_windowManager.display); @@ -66,6 +71,8 @@ namespace jwm { throw std::runtime_error("Couldn't make context"); } } + if (visible) + fWindow->show(); makeCurrentForced(); } @@ -92,13 +99,7 @@ namespace jwm { } void close() override { - eglMakeCurrent(_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (_surface) { - eglDestroySurface(_display, _surface); - } - if (_eglWindow) { - wl_egl_window_destroy(_eglWindow); - } + detach(); eglDestroyContext(_display, _context); eglTerminate(_display); @@ -128,6 +129,17 @@ namespace jwm { makeCurrentForced(); } } + void detach() override { + eglMakeCurrent(_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (_surface) { + eglDestroySurface(_display, _surface); + } + _surface = nullptr; + if (_eglWindow) { + wl_egl_window_destroy(_eglWindow); + } + _eglWindow = nullptr; + } }; } // namespace jwm diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index 8457d266..a0c35f8a 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -4,59 +4,41 @@ #include "impl/Library.hh" #include "impl/RefCounted.hh" #include "WindowWayland.hh" -#include "ShmPool.hh" +#include "Buffer.hh" #include +#include namespace jwm { class LayerRaster: public RefCounted, public ILayerWayland { public: WindowWayland* fWindow; size_t _width = 0, _height = 0; - wl_buffer* _buffer = nullptr; - uint8_t* _imageData = nullptr; - ShmPool* _pool = nullptr; + std::vector _imageData; bool _attached = false; LayerRaster() = default; virtual ~LayerRaster() = default; void attach(WindowWayland* window) { + // HACK: close and reopen fWindow = jwm::ref(window); fWindow->setLayer(this); - // must have a default size for pointer initing : ) - resize(window->getWidth(), window->getHeight()); + if (fWindow->_visible) { + fWindow->hide(); + fWindow->show(); + } + } void resize(int width, int height) override { - wl_display* d = fWindow->_windowManager.display; + // god is dead _width = width; _height = height; - int stride = width * sizeof(uint32_t); - int bufSize = stride * height * 2; - // TODO: better pool impl - if (_pool) { - // TODO: don't mem leak : ) - // This memleaks - munmap causes skija to error out : / - _pool->close(); - } - _pool = new ShmPool(fWindow->_windowManager.shm, bufSize); - if (_buffer) { - wl_buffer_destroy(_buffer); - _imageData = nullptr; - } - // : ) - auto buf = _pool->createBuffer(0, width, height, stride, WL_SHM_FORMAT_XRGB8888); - - _buffer = buf.first; - _imageData = buf.second; - if (_attached) { - attachBuffer(); - } - // makeCurrentForced(); + _imageData = std::vector(_width * _height * sizeof(uint32_t)); } const void* getPixelsPtr() const { - return _imageData; + return _imageData.data(); } int getRowBytes() const { @@ -64,22 +46,33 @@ namespace jwm { return _width * sizeof(uint32_t); } + // only way to really be sane with raster + // it's SO slow that i'll prob + static wl_callback_listener _frameCallback; + + void swapNow() { + auto buf = Buffer::createShmBuffer(fWindow->_windowManager.shm, _width, _height, WL_SHM_FORMAT_XRGB8888); + void* daData = buf->getData(); + size_t size = buf->getSize(); + memcpy(daData, _imageData.data(), size); + wl_surface_attach(fWindow->_waylandWindow, buf->getBuffer(), 0, 0); + wl_surface_damage_buffer(fWindow->_waylandWindow, 0, 0, INT32_MAX, INT32_MAX); + wl_surface_set_buffer_scale(fWindow->_waylandWindow, fWindow->_scale); + wl_surface_commit(fWindow->_waylandWindow); + + } void swapBuffers() override { - if (fWindow->_waylandWindow) { - wl_surface_damage_buffer(fWindow->_waylandWindow, 0, 0, INT32_MAX, INT32_MAX); - wl_surface_commit(fWindow->_waylandWindow); + if (_attached && fWindow->_waylandWindow) { + // all impls that I've seen have to make a new buffer every frame. + // God awful. Never use raster if you value performance. + // wl_callback* cb = wl_surface_frame(fWindow->_waylandWindow); + // wl_callback_add_listener(cb, &_frameCallback, this); + swapNow(); } } void close() override { - if (_buffer) { - wl_buffer_destroy(_buffer); - _buffer = nullptr; - } - // ??? - if (_pool) { - _pool->close(); - } + detach(); jwm::unref(&fWindow); } @@ -91,22 +84,31 @@ namespace jwm { } void attachBuffer() override { - if (fWindow) { - if (fWindow->_waylandWindow) { - printf("gataching \n"); - wl_surface_attach(fWindow->_waylandWindow, _buffer, 0, 0); - wl_surface_damage_buffer(fWindow->_waylandWindow, 0, 0, INT32_MAX, INT32_MAX); - wl_surface_set_buffer_scale(fWindow->_waylandWindow, fWindow->_scale); - wl_surface_commit(fWindow->_waylandWindow); - _attached = true; - } + _attached = true; + swapBuffers(); + } + + void detach() override { + if (fWindow && fWindow->_waylandWindow) { + wl_surface_attach(fWindow->_waylandWindow, nullptr, 0, 0); + wl_surface_commit(fWindow->_waylandWindow); } + _attached = false; + } + void reconfigure() { + swapBuffers(); } }; } +using namespace jwm; +wl_callback_listener LayerRaster::_frameCallback = { + .done = [](void* data, wl_callback* cb, uint32_t cbData) { + auto self = reinterpret_cast(data); + self->swapNow(); - + } +}; extern "C" JNIEXPORT jlong JNICALL Java_io_github_humbleui_jwm_LayerRaster__1nMake (JNIEnv* env, jclass jclass) { jwm::LayerRaster* instance = new jwm::LayerRaster; @@ -122,7 +124,8 @@ extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerRaster__1nAtt extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerRaster__1nReconfigure (JNIEnv* env, jobject obj) { - + jwm::LayerRaster* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + instance->reconfigure(); } extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerRaster__1nResize diff --git a/wayland/cc/ShmPool.cc b/wayland/cc/ShmPool.cc index 13bfe5ef..4366b45d 100644 --- a/wayland/cc/ShmPool.cc +++ b/wayland/cc/ShmPool.cc @@ -36,7 +36,7 @@ ShmPool::~ShmPool() { void ShmPool::close() { wl_shm_pool_destroy(_pool); ::close(_fd); - // munmap(_rawData, _size); + munmap(_rawData, _size); } void ShmPool::grow(size_t size) { diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 60238201..e22c774e 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -22,6 +22,7 @@ #include #include #include +#include using namespace jwm; @@ -69,7 +70,8 @@ WindowManagerWayland::WindowManagerWayland(): // ???: Moving this after libdecor_new causes input to not work wl_seat_add_listener(seat, &_seatListener, this); - + dataDevice = wl_data_device_manager_get_data_device(deviceManager, seat); + wl_data_device_add_listener(dataDevice, &_deviceListener, this); decorCtx = libdecor_new(display, &_decorInterface); @@ -119,7 +121,6 @@ void WindowManagerWayland::runLoop() { } notifyFD = pipes[1]; fcntl(pipes[1], F_SETFL, O_NONBLOCK); // notifyLoop no blockie : ) - struct pollfd wayland_out = {.fd=wl_display_get_fd(display),.events=POLLOUT}; struct pollfd ps[] = { {.fd=libdecor_get_fd(decorCtx), .events=POLLIN}, {.fd=pipes[0], .events=POLLIN}, @@ -128,18 +129,19 @@ void WindowManagerWayland::runLoop() { while (_runLoop) { if (jwm::classes::Throwable::exceptionThrown(app.getJniEnv())) _runLoop = false; - _processCallbacks(); // block until event : ) if (poll(&ps[0], 2, -1) < 0) { printf("error with pipe\n"); break; } - if (ps[1].revents & POLLIN) { - while (read(pipes[0], buf, sizeof(buf)) == sizeof(buf)) { } - } if (ps[0].revents & POLLIN) { libdecor_dispatch(decorCtx, -1); } + _processCallbacks(); + if (ps[1].revents & POLLIN) { + while (read(pipes[0], buf, sizeof(buf)) == sizeof(buf)) { } + } + notifyBool.store(false); } @@ -177,10 +179,12 @@ void WindowManagerWayland::_processCallbacks() { for (auto p : copy) { if (p->isRedrawRequested()) { p->unsetRedrawRequest(); - if (p->_layer && p->_visible) { - p->_layer->makeCurrent(); + if (p->_visible && p->_configured) { + if (p->_layer) { + p->_layer->makeCurrent(); + } + p->dispatch(classes::EventFrame::kInstance); } - p->dispatch(classes::EventFrame::kInstance); } } } @@ -377,10 +381,12 @@ void WindowManagerWayland::keyboardKeymap(void* data, wl_keyboard* keyboard, uin void WindowManagerWayland::keyboardEnter(void* data, wl_keyboard* keyboard, uint32_t serial, wl_surface* surface, wl_array *keys) { auto self = reinterpret_cast(data); + self->keyboardSerial = serial; self->keyboardFocus = surface; } void WindowManagerWayland::keyboardLeave(void* data, wl_keyboard* keyboard, uint32_t serial, wl_surface* surface) { auto self = reinterpret_cast(data); + self->keyboardSerial = -1; self->keyboardFocus = nullptr; } @@ -479,68 +485,49 @@ void WindowManagerWayland::seatCapabilities(void* data, wl_seat* seat, uint32_t void WindowManagerWayland::seatName(void* data, wl_seat* seat, const char* name) { // who cares } -std::vector WindowManagerWayland::getClipboardFormats() { - /* - XConvertSelection(display, - _atoms.CLIPBOARD, - _atoms.TARGETS, - _atoms.JWM_CLIPBOARD, - nativeHandle, - CurrentTime); - - XEvent ev; +wl_data_offer_listener WindowManagerWayland::_offerListener = { + .offer = [](void* data, wl_data_offer* offer, const char* mimeType) { + auto self = reinterpret_cast(data); + self->_currentMimeTypes.push_back(std::string(mimeType)); + } +}; +wl_data_device_listener WindowManagerWayland::_deviceListener = { + .data_offer = [](void* data, wl_data_device* device, wl_data_offer* offer) { + auto self = reinterpret_cast(data); + self->_currentMimeTypes = {}; + wl_data_offer_add_listener(offer, &_offerListener, data); + }, + .selection = [](void* data, wl_data_device* device, wl_data_offer* offer) { + auto self = reinterpret_cast(data); + self->_myClipboardContents = {}; + if (offer == nullptr) { + return; + } + for (auto i : self->_currentMimeTypes) { + int fds[2]; + pipe(fds); + wl_data_offer_receive(offer, i.c_str(), fds[1]); + wl_display_flush(self->display); + close(fds[1]); + ByteBuf res; + + + while (true) { + char buf[1024]; + ssize_t n = read(fds[0], buf, sizeof(buf)); + if (n <= 0) + break; + res.insert(res.end(), buf, buf + n); - // fetch mime types - std::vector result; - - // using lambda here in order to break 2 loops - [&]{ - while (_runLoop) { - while (XPending(display)) { - XNextEvent(display, &ev); - if (ev.type == SelectionNotify) { - int format; - unsigned long count, lengthInBytes; - Atom type; - Atom* properties; - XGetWindowProperty(display, nativeHandle, _atoms.JWM_CLIPBOARD, 0, 1024 * sizeof(Atom), false, XA_ATOM, &type, &format, &count, &lengthInBytes, reinterpret_cast(&properties)); - - for (unsigned long i = 0; i < count; ++i) { - char* str = XGetAtomName(display, properties[i]); - if (str) { - std::string s = str; - // include only mime types - if (s.find('/') != std::string::npos) { - result.push_back(s); - } else if (s == "UTF8_STRING") { - // HACK: treat UTF8_STRING as text/plain under the hood - // avoid duplicates - std::string textPlain = "text/plain"; - if (std::find(result.begin(), result.end(), textPlain) != result.end()) { - result.push_back(textPlain); - } - } - XFree(str); - } - } - - XFree(properties); - return; - } else { - _processXEvent(ev); - } - } - _processCallbacks(); + self->_myClipboardContents[i] = res; + close(fds[0]); } - }(); - - // fetching data - - XDeleteProperty(display, nativeHandle, _atoms.JWM_CLIPBOARD); - */ - std::vector result; - return result; + wl_data_offer_destroy(offer); + } +}; +std::vector WindowManagerWayland::getClipboardFormats() { + return { _currentMimeTypes.begin(), _currentMimeTypes.end()}; } void WindowManagerWayland::mouseUpdate(WindowWayland* myWindow, uint32_t x, uint32_t y, uint32_t mask) { using namespace classes; @@ -567,7 +554,10 @@ void WindowManagerWayland::mouseUpdate(WindowWayland* myWindow, uint32_t x, uint myWindow->dispatch(foo); } jwm::ByteBuf WindowManagerWayland::getClipboardContents(const std::string& type) { - auto nativeHandle = _nativeWindowToMy.begin()->first; + auto it = _myClipboardContents.find(type); + if (it != _myClipboardContents.end()) { + return it->second; + } return {}; } @@ -590,7 +580,6 @@ void WindowManagerWayland::setClipboardContents(std::map&& assert(("create at least one window in order to use clipboard" && !_nativeWindowToMy.empty())); _myClipboardContents = c; // impl me : ) - auto window = _nativeWindowToMy.begin()->first; // XSetSelectionOwner(display, XA_PRIMARY, window, CurrentTime); // XSetSelectionOwner(display, _atoms.CLIPBOARD, window, CurrentTime); } @@ -607,6 +596,7 @@ void WindowManagerWayland::notifyLoop() { if (notifyFD==-1) return; // fast notifyBool path to not make system calls when not necessary if (!notifyBool.exchange(true)) { + printf(" : )\n"); char dummy[1] = {0}; int unused = write(notifyFD, dummy, 1); // this really shouldn't fail, but if it does, the pipe should either be full (good), or dead (bad, but not our business) } diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index c3baf58b..ad363b43 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -101,6 +101,10 @@ namespace jwm { static void seatCapabilities(void* data, wl_seat* seat, uint32_t capabilities); static void seatName(void* data, wl_seat* seat, const char* name); + static wl_data_source_listener _sourceListener; + static wl_data_offer_listener _offerListener; + static wl_data_device_listener _deviceListener; + ByteBuf getClipboardContents(const std::string& type); std::vector getClipboardFormats(); @@ -109,16 +113,18 @@ namespace jwm { wl_shm* shm = nullptr; wl_compositor* compositor = nullptr; wl_data_device_manager* deviceManager = nullptr; + // no multiseat? wl_seat* seat = nullptr; wl_pointer* pointer = nullptr; wl_keyboard* keyboard = nullptr; + wl_data_device* dataDevice = nullptr; + wl_data_source* currentSource = nullptr; + uint32_t keyboardSerial = -1; libdecor* decorCtx = nullptr; xkb_context* _xkbContext = nullptr; xkb_state* _xkbState = nullptr; std::list outputs; - // XVisualInfo* x11VisualInfo; - // XSetWindowAttributes x11SWA; bool _runLoop; int notifyFD = -1; std::atomic_bool notifyBool{false}; @@ -129,6 +135,7 @@ namespace jwm { std::map _nativeWindowToMy; std::map _myClipboardContents; + std::list _currentMimeTypes; wl_surface* cursorSurface; diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index 177d5934..083e0bc2 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -61,13 +61,20 @@ void WindowWayland::setTitlebarVisible(bool isVisible) { libdecor_frame_set_visibility(_frame, isVisible); } -// Closing is like... the exact same as hiding. WTH void WindowWayland::close() { if (_waylandWindow) { _windowManager.unregisterWindow(this); wl_surface_destroy(_waylandWindow); } _waylandWindow = nullptr; + hide(); + // TODO: more destruction! +} +void WindowWayland::hide() { + _visible = false; + if (_layer) { + _layer->detach(); + } if (_frame) { libdecor_frame_unref(_frame); } @@ -91,14 +98,12 @@ void WindowWayland::setFullScreen(bool isFullScreen) { } bool WindowWayland::isFullScreen() { - // impl me : ) - return false; + return _fullscreen; } void WindowWayland::setLayer(ILayerWayland* layer) { _layer = layer; - if (_visible) - _layer->attachBuffer(); + } void WindowWayland::getDecorations(int& left, int& top, int& right, int& bottom) { // impl me : ) @@ -116,8 +121,10 @@ void WindowWayland::getContentPosition(int& posX, int& posY) { } bool WindowWayland::resize(int width, int height) { + if (width < 0 || height < 0) + return false; // don't allow size to be set if currently tiled - if (!_floating && !_visible) + if (!_floating) return false; // Width and height are in absolute pixel units, and wayland will // complain if you try to set a width/height that isn't a multiple of scale. @@ -144,21 +151,22 @@ int WindowWayland::getTop() { } int WindowWayland::getWidth() { - return (_width <= 0 ? _floatingWidth : _width) * _scale; + return getUnscaledWidth() * _scale; +} +int WindowWayland::getUnscaledWidth() { + return _width <= 0 ? _floatingWidth : _width; } - int WindowWayland::getHeight() { - return (_height <= 0 ? _floatingHeight : _height) * _scale; + return getUnscaledHeight() * _scale; +} +int WindowWayland::getUnscaledHeight() { + return _height <= 0 ? _floatingHeight : _height; } float WindowWayland::getScale() { return _scale; } bool WindowWayland::init() { - return true; -} -void WindowWayland::show() -{ _waylandWindow = wl_compositor_create_surface(_windowManager.compositor); wl_surface_add_listener(_waylandWindow, &_surfaceListener, this); // unsure if listener data and user data are the same, so i do this for safety : ) @@ -166,14 +174,17 @@ void WindowWayland::show() wl_proxy_set_tag((wl_proxy*) _waylandWindow, &_windowTag); _windowManager.registerWindow(this); - _frame = libdecor_decorate(_windowManager.decorCtx, _waylandWindow, &_libdecorFrameInterface, this); _configured = false; + return true; +} +void WindowWayland::show() +{ + _frame = libdecor_decorate(_windowManager.decorCtx, _waylandWindow, &_libdecorFrameInterface, this); libdecor_frame_map(_frame); libdecor_dispatch(_windowManager.decorCtx, -1); - if (_width > 0 && _height > 0) - resize(_width * _scale, _height * _scale); setTitle(_title); setTitlebarVisible(_titlebarVisible); + _visible = true; } ScreenInfo WindowWayland::getScreen() { @@ -194,7 +205,7 @@ void WindowWayland::setVisible(bool isVisible) { if (_visible) { show(); } else { - close(); + hide(); } } } @@ -224,7 +235,7 @@ void jwm::WindowWayland::surfaceEnter(void* data, wl_surface* surface, wl_output self->_output = o; self->_scale = o->scale; wl_surface_set_buffer_scale(surface, o->scale); - self->_adaptSize(self->_width, self->_height); + self->_adaptSize(self->getUnscaledWidth(), self->getUnscaledHeight()); break; } } @@ -239,7 +250,7 @@ void jwm::WindowWayland::surfacePreferredBufferScale(void* data, wl_surface* sur // do I pinky promise here? // yes : ) wl_surface_set_buffer_scale(surface, factor); - self->_adaptSize(self->_width, self->_height); + self->_adaptSize(self->getUnscaledWidth(), self->getUnscaledHeight()); } void jwm::WindowWayland::surfacePreferredBufferTransform(void* data, wl_surface* surface, uint32_t transform) {} @@ -321,10 +332,10 @@ void jwm::WindowWayland::decorFrameConfigure(libdecor_frame* frame, libdecor_con // Throttle frame wl_callback_add_listener(callback, &_frameCallback, self); } - if (!self->_configured && self->_layer) { - self->_layer->attachBuffer(); + if (!self->_configured && self->_visible) { + if (self->_layer) + self->_layer->attachBuffer(); } - self->_configured = true; } void jwm::WindowWayland::decorFrameClose(libdecor_frame* frame, void* userData) { @@ -333,7 +344,7 @@ void jwm::WindowWayland::decorFrameClose(libdecor_frame* frame, void* userData) } void jwm::WindowWayland::decorFrameCommit(libdecor_frame* frame, void* userData) { WindowWayland* self = reinterpret_cast(userData); - self->requestRedraw(); + wl_surface_commit(self->_waylandWindow); } void jwm::WindowWayland::decorFrameDismissPopup(libdecor_frame* frame, const char* seatName, void* userData) {} void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { @@ -342,7 +353,7 @@ void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { _height = newHeight; int scaledWidth = _width * _scale; int scaledHeight = _height * _scale; - + printf("%i %i\n", scaledWidth, scaledHeight); jwm::JNILocal eventWindowResize( app.getJniEnv(), EventWindowResize::make( @@ -354,6 +365,9 @@ void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { ) ); dispatch(eventWindowResize.get()); + // In Java Wayland doesn't actually cause a frame: + // however decorFrameCommit will cause a redraw anyway. + // Not doing it in wayland lets me not cause an exception on hide. } // JNI diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index fe119dda..cf72eacc 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -19,12 +19,15 @@ namespace jwm { void setVisible(bool isVisible); bool resize(int width, int height); void close(); + void hide(); bool init(); void show(); int getLeft(); int getTop(); int getWidth(); + int getUnscaledWidth(); int getHeight(); + int getUnscaledHeight(); float getScale(); void requestRedraw() { _isRedrawRequested = true; From f6fd997d2c49a2891785fc3ec1b554398fcbcfa1 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Sat, 9 Dec 2023 01:19:37 -0500 Subject: [PATCH 20/93] remove notify debug --- wayland/cc/WindowManagerWayland.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index e22c774e..f3ef2058 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -596,7 +596,6 @@ void WindowManagerWayland::notifyLoop() { if (notifyFD==-1) return; // fast notifyBool path to not make system calls when not necessary if (!notifyBool.exchange(true)) { - printf(" : )\n"); char dummy[1] = {0}; int unused = write(notifyFD, dummy, 1); // this really shouldn't fail, but if it does, the pipe should either be full (good), or dead (bad, but not our business) } From abe4eac0a8f3c953aebf9418ca9da28fa88f414b Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Sat, 9 Dec 2023 13:46:35 -0500 Subject: [PATCH 21/93] More roundtrips : ) --- script/package.py | 3 ++- wayland/cc/LayerRasterWayland.cc | 7 ++++--- wayland/cc/WindowManagerWayland.cc | 2 +- wayland/cc/WindowWayland.cc | 10 ++++++---- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/script/package.py b/script/package.py index 5bd1fa1f..adde3153 100755 --- a/script/package.py +++ b/script/package.py @@ -22,7 +22,8 @@ def main() -> Tuple[str, str, str]: jar = build_utils.jar(f"target/jwm-{common.version}.jar", ("target/classes", "."), ("target/maven", "META-INF")) build_utils.makedirs("target/src/io/github/humbleui/jwm") - shutil.copytree("linux/java", "target/src/io/github/humbleui/jwm", dirs_exist_ok=True) + shutil.copytree("x11/java", "target/src/io/github/humbleui/jwm", dirs_exist_ok=True) + shutil.copytree("wayland/java", "target/src/io/github/humbleui/jwm", dirs_exist_ok=True) shutil.copytree("macos/java", "target/src/io/github/humbleui/jwm", dirs_exist_ok=True) shutil.copytree("shared/java", "target/src/io/github/humbleui/jwm", dirs_exist_ok=True) shutil.copytree("windows/java", "target/src/io/github/humbleui/jwm", dirs_exist_ok=True) diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index a0c35f8a..e740e8cd 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -65,9 +65,10 @@ namespace jwm { if (_attached && fWindow->_waylandWindow) { // all impls that I've seen have to make a new buffer every frame. // God awful. Never use raster if you value performance. - // wl_callback* cb = wl_surface_frame(fWindow->_waylandWindow); - // wl_callback_add_listener(cb, &_frameCallback, this); - swapNow(); + wl_callback* cb = wl_surface_frame(fWindow->_waylandWindow); + wl_callback_add_listener(cb, &_frameCallback, this); + wl_display_roundtrip(fWindow->_windowManager.display); + // swapNow(); } } diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index f3ef2058..193fadb0 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -403,7 +403,7 @@ void WindowManagerWayland::keyboardKey(void* data, wl_keyboard* keyboard, uint32 // TODO: while unlikely, it could be possible that you can be entering text even if the // pointer hasn't entered if (self->keyboardFocus && jwmKey != jwm::Key::UNDEFINED) { - jwm::KeyLocation location; + jwm::KeyLocation location = jwm::KeyLocation::DEFAULT; JNILocal keyEvent( app.getJniEnv(), classes::EventKey::make( diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index 083e0bc2..6838a0e0 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -14,10 +14,12 @@ using namespace jwm; wl_surface_listener WindowWayland::_surfaceListener = { .enter = WindowWayland::surfaceEnter, .leave = WindowWayland::surfaceLeave, +#ifdef HAVE_WAYLAND_1_22 .preferred_buffer_scale = WindowWayland::surfacePreferredBufferScale, .preferred_buffer_transform = WindowWayland::surfacePreferredBufferTransform +#endif }; - + wl_output_listener WindowWayland::_outputListener = { .geometry = WindowWayland::outputGeometry, @@ -181,7 +183,7 @@ void WindowWayland::show() { _frame = libdecor_decorate(_windowManager.decorCtx, _waylandWindow, &_libdecorFrameInterface, this); libdecor_frame_map(_frame); - libdecor_dispatch(_windowManager.decorCtx, -1); + wl_display_roundtrip(_windowManager.display); setTitle(_title); setTitlebarVisible(_titlebarVisible); _visible = true; @@ -345,6 +347,7 @@ void jwm::WindowWayland::decorFrameClose(libdecor_frame* frame, void* userData) void jwm::WindowWayland::decorFrameCommit(libdecor_frame* frame, void* userData) { WindowWayland* self = reinterpret_cast(userData); wl_surface_commit(self->_waylandWindow); + wl_display_roundtrip(self->_windowManager.display); } void jwm::WindowWayland::decorFrameDismissPopup(libdecor_frame* frame, const char* seatName, void* userData) {} void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { @@ -353,7 +356,6 @@ void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { _height = newHeight; int scaledWidth = _width * _scale; int scaledHeight = _height * _scale; - printf("%i %i\n", scaledWidth, scaledHeight); jwm::JNILocal eventWindowResize( app.getJniEnv(), EventWindowResize::make( @@ -462,7 +464,7 @@ extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nS const jchar* bytes = env->GetStringChars(title, nullptr); jsize length = env->GetStringLength(title); - std::u16string thingie = {reinterpret_cast(bytes), length}; + std::u16string thingie = {reinterpret_cast(bytes), static_cast(length)}; std::string titleS = std::wstring_convert< std::codecvt_utf8_utf16, char16_t>{}.to_bytes(thingie); From 393e7088802cfd28783905a107b1ba37cfea1dbe Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Sat, 9 Dec 2023 14:17:24 -0500 Subject: [PATCH 22/93] Don't commit if no window : ) --- wayland/cc/WindowWayland.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index 6838a0e0..603b8321 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -346,8 +346,10 @@ void jwm::WindowWayland::decorFrameClose(libdecor_frame* frame, void* userData) } void jwm::WindowWayland::decorFrameCommit(libdecor_frame* frame, void* userData) { WindowWayland* self = reinterpret_cast(userData); - wl_surface_commit(self->_waylandWindow); - wl_display_roundtrip(self->_windowManager.display); + if (self->_waylandWindow) { + wl_surface_commit(self->_waylandWindow); + wl_display_roundtrip(self->_windowManager.display); + } } void jwm::WindowWayland::decorFrameDismissPopup(libdecor_frame* frame, const char* seatName, void* userData) {} void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { From 366363f587289e15187324b387a913d57da80508 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Mon, 11 Dec 2023 11:29:02 -0500 Subject: [PATCH 23/93] Make current before resize --- wayland/cc/LayerGLWayland.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index 75562795..dc67240b 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -82,6 +82,8 @@ namespace jwm { } void resize(int width, int height) override { + // Make current to avoid artifacts in other windows + makeCurrentForced(); glClearStencil(0); glClearColor(0, 0, 0, 255); glStencilMask(0xffffffff); From 952c76c5087161ccb6ac8b9c74059dfeb8a5aaaa Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Tue, 12 Dec 2023 10:38:15 -0500 Subject: [PATCH 24/93] Don't block on swap (fixes multiwindow render) --- wayland/cc/LayerGLWayland.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index dc67240b..91822996 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -70,10 +70,11 @@ namespace jwm { if ( _context == EGL_NO_CONTEXT ) { throw std::runtime_error("Couldn't make context"); } + // Don't block on swap + eglSwapInterval(_display, 0); } if (visible) fWindow->show(); - makeCurrentForced(); } @@ -97,7 +98,9 @@ namespace jwm { } void swapBuffers() override { + printf("before swap\n"); eglSwapBuffers(_display, _surface); + printf("after swap\n"); } void close() override { From ebafae5a9620c5112df9246cdf0513860cefd6e4 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Tue, 12 Dec 2023 14:40:53 -0500 Subject: [PATCH 25/93] Make multiwindow work --- script/build.py | 2 +- shared/cc/Window.cc | 1 + wayland/cc/LayerGLWayland.cc | 32 ++++++++++++++++++++---------- wayland/cc/WindowManagerWayland.hh | 4 +++- wayland/cc/WindowWayland.cc | 10 ++++++---- wayland/cc/WindowWayland.hh | 1 - 6 files changed, 32 insertions(+), 18 deletions(-) diff --git a/script/build.py b/script/build.py index 9954d826..589461fb 100755 --- a/script/build.py +++ b/script/build.py @@ -4,7 +4,7 @@ def build_native_system(system): os.chdir(common.basedir + "/" + system) subprocess.check_call(["cmake", - "-DCMAKE_BUILD_TYPE=Release", + "-DCMAKE_BUILD_TYPE=Debug", "-B", "build", "-G", "Ninja", "-DJWM_ARCH=" + build_utils.arch, diff --git a/shared/cc/Window.cc b/shared/cc/Window.cc index ce9c1f29..3567e77f 100644 --- a/shared/cc/Window.cc +++ b/shared/cc/Window.cc @@ -6,6 +6,7 @@ jwm::Window::~Window() { fEnv->DeleteGlobalRef(fWindow); + fWindow = nullptr; } void jwm::Window::dispatch(jobject event) { diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index 91822996..bb347e9b 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -22,11 +22,15 @@ namespace jwm { EGLDisplay _display = nullptr; EGLSurface _surface = nullptr; EGLConfig _config = nullptr; + bool _firstAttach = true; + bool _closed = false; LayerGL() = default; virtual ~LayerGL() = default; void attach(WindowWayland* window) { + // no idea why you would reopen it??? + _closed = false; fWindow = jwm::ref(window); fWindow->setLayer(this); // HACK: reopen @@ -34,12 +38,16 @@ namespace jwm { if (visible) { fWindow->hide(); } - if (_display == nullptr) { - _display = eglGetDisplay(window->_windowManager.display); + if (fWindow->_windowManager._eglDisplay == EGL_NO_DISPLAY) { + fWindow->_windowManager._eglDisplay = eglGetDisplay(window->_windowManager.display); - eglInitialize(_display, nullptr, nullptr); + eglInitialize(fWindow->_windowManager._eglDisplay, nullptr, nullptr); } + if (_firstAttach) { + _firstAttach = false; + } + _display = fWindow->_windowManager._eglDisplay; if ( eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) { throw new std::runtime_error("Cannot bind EGL Api"); } @@ -71,6 +79,7 @@ namespace jwm { throw std::runtime_error("Couldn't make context"); } // Don't block on swap + // Blocking here will freeze the app on sway. eglSwapInterval(_display, 0); } if (visible) @@ -84,7 +93,7 @@ namespace jwm { void resize(int width, int height) override { // Make current to avoid artifacts in other windows - makeCurrentForced(); + makeCurrent(); glClearStencil(0); glClearColor(0, 0, 0, 255); glStencilMask(0xffffffff); @@ -98,17 +107,19 @@ namespace jwm { } void swapBuffers() override { - printf("before swap\n"); eglSwapBuffers(_display, _surface); - printf("after swap\n"); } void close() override { + if (_closed) + return; + _closed = true; detach(); eglDestroyContext(_display, _context); - eglTerminate(_display); - + + _firstAttach = true; jwm::unref(&fWindow); + fWindow = nullptr; } void makeCurrentForced() override { @@ -121,9 +132,6 @@ namespace jwm { void attachBuffer() override { if (fWindow && fWindow->_waylandWindow) { if (!_eglWindow) { - // _region = wl_compositor_create_region(fWindow->_windowManager.compositor); - // wl_region_add(_region, 0, 0, fWindow->getWidth(), fWindow->getHeight()); - // wl_surface_set_opaque_region(fWindow->_waylandWindow, _region); _eglWindow = wl_egl_window_create(fWindow->_waylandWindow, fWindow->getWidth(), fWindow->getHeight()); _surface = eglCreateWindowSurface(_display, _config, _eglWindow, nullptr); @@ -181,6 +189,8 @@ extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerGL__1nResize extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerGL__1nMakeCurrent (JNIEnv* env, jobject obj) { + jwm::LayerGL* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + instance->makeCurrent(); } extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerGL__1nSwapBuffers diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index ad363b43..5dbcd7ab 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include @@ -17,6 +16,8 @@ #include "Output.hh" #include #include +#include +#include namespace jwm { class WindowWayland; @@ -123,6 +124,7 @@ namespace jwm { libdecor* decorCtx = nullptr; xkb_context* _xkbContext = nullptr; xkb_state* _xkbState = nullptr; + EGLDisplay _eglDisplay = EGL_NO_DISPLAY; std::list outputs; bool _runLoop; diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index 603b8321..a3ae16bf 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -47,7 +47,8 @@ WindowWayland::WindowWayland(JNIEnv* env, WindowManagerWayland& windowManager): } WindowWayland::~WindowWayland() { - close(); + // TODO: close gets called twice? + // close(); } @@ -64,12 +65,12 @@ void WindowWayland::setTitlebarVisible(bool isVisible) { } void WindowWayland::close() { + _windowManager.unregisterWindow(this); + hide(); if (_waylandWindow) { - _windowManager.unregisterWindow(this); wl_surface_destroy(_waylandWindow); } _waylandWindow = nullptr; - hide(); // TODO: more destruction! } void WindowWayland::hide() { @@ -264,7 +265,8 @@ void jwm::WindowWayland::outputDone(void* data, wl_output* output) {} void jwm::WindowWayland::outputScale(void* data, wl_output* output, int factor) { WindowWayland* self = reinterpret_cast(data); self->_scale = factor; - self->dispatch(classes::EventWindowScreenChange::kInstance); + if (self->_waylandWindow) + self->dispatch(classes::EventWindowScreenChange::kInstance); } void jwm::WindowWayland::outputName(void* data, wl_output* output, const char* name) {} void jwm::WindowWayland::outputDescription(void* data, wl_output* output, const char* desc) {} diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index cf72eacc..326838ee 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -52,7 +52,6 @@ namespace jwm { void setCursor(jwm::MouseCursor cursor); void setLayer(ILayerWayland* layer); - ScreenInfo getScreen(); static void surfaceEnter(void* data, wl_surface* surface, wl_output* output); From eb4527c549d772c087c3f5688c4a0cd9ad956d4c Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Tue, 12 Dec 2023 14:41:24 -0500 Subject: [PATCH 26/93] forgot to revert to release build --- script/build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/build.py b/script/build.py index 589461fb..9954d826 100755 --- a/script/build.py +++ b/script/build.py @@ -4,7 +4,7 @@ def build_native_system(system): os.chdir(common.basedir + "/" + system) subprocess.check_call(["cmake", - "-DCMAKE_BUILD_TYPE=Debug", + "-DCMAKE_BUILD_TYPE=Release", "-B", "build", "-G", "Ninja", "-DJWM_ARCH=" + build_utils.arch, From 7f6206a57032930ef0c9c053718bb361877a0f13 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Tue, 12 Dec 2023 14:52:35 -0500 Subject: [PATCH 27/93] Fully working rendering --- wayland/cc/LayerGLWayland.cc | 9 ++------- wayland/cc/LayerRasterWayland.cc | 20 +++++++++----------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index bb347e9b..db458347 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -33,11 +33,6 @@ namespace jwm { _closed = false; fWindow = jwm::ref(window); fWindow->setLayer(this); - // HACK: reopen - bool visible = fWindow->_visible; - if (visible) { - fWindow->hide(); - } if (fWindow->_windowManager._eglDisplay == EGL_NO_DISPLAY) { fWindow->_windowManager._eglDisplay = eglGetDisplay(window->_windowManager.display); @@ -82,8 +77,8 @@ namespace jwm { // Blocking here will freeze the app on sway. eglSwapInterval(_display, 0); } - if (visible) - fWindow->show(); + if (fWindow->_configured) + attachBuffer(); makeCurrentForced(); } diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index e740e8cd..8ca5664b 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -20,14 +20,11 @@ namespace jwm { virtual ~LayerRaster() = default; void attach(WindowWayland* window) { - // HACK: close and reopen fWindow = jwm::ref(window); fWindow->setLayer(this); - if (fWindow->_visible) { - fWindow->hide(); - fWindow->show(); - } - + resize(window->getWidth(), window->getHeight()); + if (fWindow->_configured) + attachBuffer(); } void resize(int width, int height) override { @@ -65,16 +62,17 @@ namespace jwm { if (_attached && fWindow->_waylandWindow) { // all impls that I've seen have to make a new buffer every frame. // God awful. Never use raster if you value performance. - wl_callback* cb = wl_surface_frame(fWindow->_waylandWindow); - wl_callback_add_listener(cb, &_frameCallback, this); - wl_display_roundtrip(fWindow->_windowManager.display); - // swapNow(); + // wl_callback* cb = wl_surface_frame(fWindow->_waylandWindow); + // wl_callback_add_listener(cb, &_frameCallback, this); + // wl_display_roundtrip(fWindow->_windowManager.display); + swapNow(); } } void close() override { detach(); jwm::unref(&fWindow); + fWindow = nullptr; } void makeCurrentForced() override { @@ -90,7 +88,7 @@ namespace jwm { } void detach() override { - if (fWindow && fWindow->_waylandWindow) { + if (_attached && fWindow && fWindow->_waylandWindow) { wl_surface_attach(fWindow->_waylandWindow, nullptr, 0, 0); wl_surface_commit(fWindow->_waylandWindow); } From 78cd01f5d27b4d20c769794d29c2550289d5683c Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Tue, 12 Dec 2023 17:03:11 -0500 Subject: [PATCH 28/93] Clean up, clipboard --- wayland/cc/ClipboardWayland.cc | 11 +++------- wayland/cc/WindowManagerWayland.cc | 34 +++++++++++++++++++++++++++--- wayland/cc/WindowWayland.cc | 7 ++++++ 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/wayland/cc/ClipboardWayland.cc b/wayland/cc/ClipboardWayland.cc index 0d02345a..92ca029f 100644 --- a/wayland/cc/ClipboardWayland.cc +++ b/wayland/cc/ClipboardWayland.cc @@ -14,7 +14,6 @@ namespace jwm { } jobjectArray getFormats(JNIEnv* env) const { - /* auto formats = jwm::app.getWindowManager().getClipboardFormats(); if (formats.empty()) { return nullptr; @@ -32,14 +31,10 @@ namespace jwm { for (jsize i = 0; i < static_cast(formatObjs.size()); ++i) { env->SetObjectArrayElement(jniFormats, i, formatObjs[i]); } - */ - // impl me : ) - jobjectArray formats = env->NewObjectArray(0, classes::ClipboardFormat::kCls, nullptr); - return formats; + return jniFormats; } jobject get(JNIEnv* env, jobjectArray formats) { - /* jsize formatsSize = env->GetArrayLength(formats); for (jsize i = 0; i < formatsSize; ++i) { jobject format = env->GetObjectArrayElement(formats, i); @@ -49,9 +44,11 @@ namespace jwm { ByteBuf contents; // HACK: prefer UTF8_STRING over text/plain and convert it to utf16 + /* if (formatId == "text/plain") { contents = app.getWindowManager().getClipboardContents("UTF8_STRING"); } + */ // TODO add another formats if (contents.empty()) { return nullptr; @@ -67,8 +64,6 @@ namespace jwm { return env->NewGlobalRef(entry.get()); } } - */ - // impl me : ) classes::Throwable::exceptionThrown(env); return nullptr; } diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 193fadb0..1a9db08f 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -576,12 +576,40 @@ void WindowManagerWayland::terminate() { _runLoop = false; } +wl_data_source_listener WindowManagerWayland::_sourceListener = { + .send = [](void* data, wl_data_source* source, + const char* mimeType, int fd) { + auto self = reinterpret_cast(data); + auto it = self->_myClipboardContents.find(std::string(mimeType)); + if (it != self->_myClipboardContents.end()) { + write(fd, it->second.data(), it->second.size()); + } + close(fd); + }, + .cancelled = [](void* data, wl_data_source* source) { + auto self = reinterpret_cast(data); + wl_data_source_destroy(source); + } +}; void WindowManagerWayland::setClipboardContents(std::map&& c) { assert(("create at least one window in order to use clipboard" && !_nativeWindowToMy.empty())); _myClipboardContents = c; - // impl me : ) - // XSetSelectionOwner(display, XA_PRIMARY, window, CurrentTime); - // XSetSelectionOwner(display, _atoms.CLIPBOARD, window, CurrentTime); + + // god is dead if data device manager is null + + currentSource = wl_data_device_manager_create_data_source(deviceManager); + + wl_data_source_add_listener(currentSource, &_sourceListener, this); + + _currentMimeTypes = {}; + for (auto it : c) { + _currentMimeTypes.push_back(it.first.c_str()); + wl_data_source_offer(currentSource, it.first.c_str()); + } + + if (keyboardSerial >= 0) + wl_data_device_set_selection(dataDevice, currentSource, keyboardSerial); + } void WindowManagerWayland::enqueueTask(const std::function& task) { diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index a3ae16bf..f11877eb 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -133,11 +133,18 @@ bool WindowWayland::resize(int width, int height) { // complain if you try to set a width/height that isn't a multiple of scale. if ((width % _scale) != 0 || (height % _scale) != 0) return false; + + // TODO: adapting size while visible causes issues? + // I've noticed the frame not updating + if (_visible) + return false; _width = width / _scale; _height = height / _scale; + /* if (_visible) { _adaptSize(_width, _height); } + */ return true; } From 460744e7ac92015787e8ce0c6ca84853878c76d3 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Tue, 12 Dec 2023 19:16:55 -0500 Subject: [PATCH 29/93] Half-baked mouse cursors --- .../dashboard/java/PanelMouseCursors.java | 2 +- shared/cc/MouseCursor.hh | 2 +- wayland/cc/WindowManagerWayland.cc | 38 ++-------- wayland/cc/WindowManagerWayland.hh | 1 + wayland/cc/WindowWayland.cc | 69 +++++++++++++++---- wayland/cc/WindowWayland.hh | 3 + 6 files changed, 70 insertions(+), 45 deletions(-) diff --git a/examples/dashboard/java/PanelMouseCursors.java b/examples/dashboard/java/PanelMouseCursors.java index ee104e0a..fc32b105 100644 --- a/examples/dashboard/java/PanelMouseCursors.java +++ b/examples/dashboard/java/PanelMouseCursors.java @@ -56,7 +56,7 @@ public void accept(Event e) { keepCursor = false; } else if (!keepCursor) { if (window._lastCursor != MouseCursor.ARROW) - window.requestFrame(); + window.requestFrame(); window.setMouseCursor(MouseCursor.ARROW); } lastInside = inside; diff --git a/shared/cc/MouseCursor.hh b/shared/cc/MouseCursor.hh index f7d798ce..8a3f0ab0 100644 --- a/shared/cc/MouseCursor.hh +++ b/shared/cc/MouseCursor.hh @@ -51,4 +51,4 @@ namespace jwm { } } -} \ No newline at end of file +} diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 1a9db08f..d5736d26 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -76,34 +76,7 @@ WindowManagerWayland::WindowManagerWayland(): wl_display_roundtrip(display); - { - wl_cursor_theme* cursor_theme = wl_cursor_theme_load(nullptr, 24, shm); - // TODO: what about if missing : ( - auto loadCursor = [&](const char* name) { - wl_cursor* cursor = wl_cursor_theme_get_cursor(cursor_theme, name); - wl_cursor_image* cursorImage = cursor->images[0]; - return cursorImage; - }; - - _cursors[static_cast(jwm::MouseCursor::ARROW )] = loadCursor("default"); - _cursors[static_cast(jwm::MouseCursor::CROSSHAIR )] = loadCursor("crosshair"); - _cursors[static_cast(jwm::MouseCursor::HELP )] = loadCursor("help"); - _cursors[static_cast(jwm::MouseCursor::POINTING_HAND )] = loadCursor("pointer"); - _cursors[static_cast(jwm::MouseCursor::IBEAM )] = loadCursor("text"); - _cursors[static_cast(jwm::MouseCursor::NOT_ALLOWED )] = loadCursor("not-allowed"); - _cursors[static_cast(jwm::MouseCursor::WAIT )] = loadCursor("watch"); - _cursors[static_cast(jwm::MouseCursor::RESIZE_NS )] = loadCursor("ns-resize"); - _cursors[static_cast(jwm::MouseCursor::RESIZE_WE )] = loadCursor("ew-resize"); - _cursors[static_cast(jwm::MouseCursor::RESIZE_NESW )] = loadCursor("nesw-resize"); - _cursors[static_cast(jwm::MouseCursor::RESIZE_NWSE )] = loadCursor("nwse-resize"); - - cursorSurface = wl_compositor_create_surface(compositor); - - wl_surface_attach(cursorSurface, - wl_cursor_image_get_buffer(_cursors[static_cast(jwm::MouseCursor::ARROW)]), 0, 0); - wl_surface_commit(cursorSurface); - } - + cursorSurface = wl_compositor_create_surface(compositor); } @@ -241,10 +214,12 @@ WindowWayland* WindowManagerWayland::getWindowForNative(wl_surface* surface) { void WindowManagerWayland::pointerHandleEnter(void* data, wl_pointer* pointer, uint32_t serial, wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { WindowManagerWayland* self = (WindowManagerWayland*)data; - wl_cursor_image* image = self->_cursors[static_cast(jwm::MouseCursor::ARROW)]; - wl_pointer_set_cursor(pointer, serial, self->cursorSurface, image->hotspot_x, image->hotspot_y); - if (self->getWindowForNative(surface)) + self->mouseSerial = serial; + if (self->getWindowForNative(surface)) { + WindowWayland* window = self->getWindowForNative(surface); + window->setCursor(jwm::MouseCursor::ARROW); self->focusedSurface = surface; + } } void WindowManagerWayland::pointerHandleLeave(void* data, wl_pointer* pointer, uint32_t serial, wl_surface *surface) { @@ -252,6 +227,7 @@ void WindowManagerWayland::pointerHandleLeave(void* data, wl_pointer* pointer, u self->focusedSurface = nullptr; // ??? self->mouseMask = 0; + self->mouseSerial = -1; } void WindowManagerWayland::pointerHandleMotion(void* data, wl_pointer* pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index 5dbcd7ab..6913fd37 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -120,6 +120,7 @@ namespace jwm { wl_keyboard* keyboard = nullptr; wl_data_device* dataDevice = nullptr; wl_data_source* currentSource = nullptr; + uint32_t mouseSerial = -1; uint32_t keyboardSerial = -1; libdecor* decorCtx = nullptr; xkb_context* _xkbContext = nullptr; diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index f11877eb..75c0a63c 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -44,6 +44,7 @@ WindowWayland::WindowWayland(JNIEnv* env, WindowManagerWayland& windowManager): _title("") { + _makeCursors(); } WindowWayland::~WindowWayland() { @@ -148,6 +149,49 @@ bool WindowWayland::resize(int width, int height) { return true; } + +void WindowWayland::_makeCursors() { + + if (theme) + wl_cursor_theme_destroy(theme); + theme = wl_cursor_theme_load(nullptr, 24 * _scale, _windowManager.shm); + +} +// cursed +wl_cursor* WindowWayland::_getCursorFor(jwm::MouseCursor cursor) { + switch (cursor) { + case jwm::MouseCursor::ARROW: + // works + return wl_cursor_theme_get_cursor(theme, "default"); + case jwm::MouseCursor::CROSSHAIR: + // works + return wl_cursor_theme_get_cursor(theme, "crosshair"); + case jwm::MouseCursor::HELP: + // sometimes works? + return wl_cursor_theme_get_cursor(theme, "help"); + case jwm::MouseCursor::POINTING_HAND: + // SHOULD work + return wl_cursor_theme_get_cursor(theme, "pointer"); + case jwm::MouseCursor::IBEAM: + // doesn't work at all + return wl_cursor_theme_get_cursor(theme, "text"); + case jwm::MouseCursor::NOT_ALLOWED: + return wl_cursor_theme_get_cursor(theme, "not-allowed"); + case jwm::MouseCursor::WAIT: + return wl_cursor_theme_get_cursor(theme, "watch"); + case jwm::MouseCursor::WIN_UPARROW: + return wl_cursor_theme_get_cursor(theme, "up-arrow"); + case jwm::MouseCursor::RESIZE_NS: + return wl_cursor_theme_get_cursor(theme, "ns-resize"); + case jwm::MouseCursor::RESIZE_WE: + return wl_cursor_theme_get_cursor(theme, "ew-resize"); + case jwm::MouseCursor::RESIZE_NESW: + return wl_cursor_theme_get_cursor(theme, "nesw-resize"); + case jwm::MouseCursor::RESIZE_NWSE: + return wl_cursor_theme_get_cursor(theme, "nwse-resize"); + } + return nullptr; +} int WindowWayland::getLeft() { int x, y; getContentPosition(x, y); @@ -221,18 +265,17 @@ void WindowWayland::setVisible(bool isVisible) { } void jwm::WindowWayland::setCursor(jwm::MouseCursor cursor) { - if (auto wayCursor = _windowManager._cursors[static_cast(cursor)]) { - wl_surface_attach(_windowManager.cursorSurface, - wl_cursor_image_get_buffer(wayCursor), - 0, 0); - wl_surface_commit(_windowManager.cursorSurface); - // TODO: hotspots? - } else { - auto otherCursor = _windowManager._cursors[static_cast(jwm::MouseCursor::ARROW)]; - wl_surface_attach(_windowManager.cursorSurface, - wl_cursor_image_get_buffer(otherCursor), 0, 0); - wl_surface_commit(_windowManager.cursorSurface); - } + printf("%s\n", jwm::mouseCursorToStr(cursor)); + // ????? + // Doesn't work for higher numbers??? + auto wayCursor = _getCursorFor(cursor)->images[0]; + wl_surface_attach(_windowManager.cursorSurface, + wl_cursor_image_get_buffer(wayCursor), + 0, 0); + wl_surface_set_buffer_scale(_windowManager.cursorSurface, _scale); + wl_surface_commit(_windowManager.cursorSurface); + wl_pointer_set_cursor(_windowManager.pointer, _windowManager.mouseSerial, _windowManager.cursorSurface, + wayCursor->hotspot_x / _scale, wayCursor->hotspot_y / _scale); } // what do??? @@ -378,6 +421,8 @@ void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { ) ); dispatch(eventWindowResize.get()); + + _makeCursors(); // In Java Wayland doesn't actually cause a frame: // however decorFrameCommit will cause a redraw anyway. // Not doing it in wayland lets me not cause an exception on hide. diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index 326838ee..6bdaaa75 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -52,6 +52,8 @@ namespace jwm { void setCursor(jwm::MouseCursor cursor); void setLayer(ILayerWayland* layer); + void _makeCursors(); + wl_cursor* _getCursorFor(jwm::MouseCursor cursor); ScreenInfo getScreen(); static void surfaceEnter(void* data, wl_surface* surface, wl_output* output); @@ -106,6 +108,7 @@ namespace jwm { wl_surface* _waylandWindow = nullptr; libdecor_frame* _frame = nullptr; Output* _output = nullptr; + wl_cursor_theme* theme = nullptr; static wl_surface_listener _surfaceListener; From cd600b01c0d3f630e80b89a5c5f5da8d450f84d3 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Tue, 12 Dec 2023 21:10:00 -0500 Subject: [PATCH 30/93] Squash merge upstream/main into wayland --- .github/workflows/build-deploy.yml | 1 + .github/workflows/rebuild-docker-image.yaml | 2 +- CHANGELOG.md | 13 +++ script/build_utils.py | 3 +- shared/cc/impl/JNILocal.hh | 2 +- x11/cc/KeyX11.cc | 99 ++++++++++++++++----- x11/cc/KeyX11.hh | 3 +- x11/cc/WindowManagerX11.cc | 14 ++- x11/cc/WindowX11.cc | 11 ++- 9 files changed, 113 insertions(+), 35 deletions(-) diff --git a/.github/workflows/build-deploy.yml b/.github/workflows/build-deploy.yml index ce4f93f7..d3b256a8 100644 --- a/.github/workflows/build-deploy.yml +++ b/.github/workflows/build-deploy.yml @@ -86,6 +86,7 @@ jobs: name: Deploy to Maven Central run: | echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import + gpg --list-keys python3 script/release.py --only java --ref ${{ github.ref }} env: GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} diff --git a/.github/workflows/rebuild-docker-image.yaml b/.github/workflows/rebuild-docker-image.yaml index 50a5e969..58b337e8 100644 --- a/.github/workflows/rebuild-docker-image.yaml +++ b/.github/workflows/rebuild-docker-image.yaml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out the repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Log in to Docker Hub uses: docker/login-action@v1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 87b16706..0b81607b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +# 0.4.16 - Dec 1, 2023 + +Added: + +- macOS: Window::bringToFront, ::isFront (#269, thx @Quezion) +- macOS: LayerMetal::GetMetalLayer (#275, thx @smallshen) +- X11: add held modifier info on mouse events when window isn't focused (#274, thx @dzaima) + +Fixed: + +- X11: Use XQueryPointer mouse position instead of XI_Motion fields (#272, thx @dzaima) +- X11: fix getScreenCoordinates (#218, #276, thx @TheDrawingCoder-Gamer) + # 0.4.15 - Apr 3, 2023 Added: diff --git a/script/build_utils.py b/script/build_utils.py index 1067db9f..4521ec61 100644 --- a/script/build_utils.py +++ b/script/build_utils.py @@ -9,7 +9,8 @@ def get_arg(name): return vars(args).get(name.replace("-", "_")) execdir = os.getcwd() -arch = get_arg("arch") or {'AMD64': 'x64', 'x86_64': 'x64', 'arm64': 'arm64'}[platform.machine()] +native_arch = {'AMD64': 'x64', 'x86_64': 'x64', 'arm64': 'arm64', 'aarch64': 'arm64'}[platform.machine()] +arch = get_arg("arch") or native_arch system = get_arg("system") or {'Darwin': 'macos', 'Linux': 'linux', 'Windows': 'windows'}[platform.system()] classpath_separator = ';' if platform.system() == 'Windows' else ':' mvn = "mvn.cmd" if platform.system() == "Windows" else "mvn" diff --git a/shared/cc/impl/JNILocal.hh b/shared/cc/impl/JNILocal.hh index 96e9ce59..f9e4852b 100644 --- a/shared/cc/impl/JNILocal.hh +++ b/shared/cc/impl/JNILocal.hh @@ -24,4 +24,4 @@ namespace jwm { JNIEnv* fEnv; T fRef; }; -} \ No newline at end of file +} diff --git a/x11/cc/KeyX11.cc b/x11/cc/KeyX11.cc index 30045e30..0071718d 100644 --- a/x11/cc/KeyX11.cc +++ b/x11/cc/KeyX11.cc @@ -38,21 +38,23 @@ int jwm::KeyX11::getModifiersFromMask(int mask) { return m; } -jwm::Key jwm::KeyX11::fromNative(uint32_t v) { +jwm::Key jwm::KeyX11::fromNative(uint32_t v, jwm::KeyLocation& location, int& modifiers) { + location = jwm::KeyLocation::DEFAULT; + modifiers = 0; switch (v) { // Modifiers case XK_Caps_Lock: return Key::CAPS_LOCK; - case XK_Shift_R: + case XK_Shift_R: location = jwm::KeyLocation::RIGHT; // fallthrough case XK_Shift_L: return Key::SHIFT; - case XK_Control_R: + case XK_Control_R: location = jwm::KeyLocation::RIGHT; // fallthrough case XK_Control_L: return Key::CONTROL; - case XK_Alt_R: + case XK_Alt_R: location = jwm::KeyLocation::RIGHT; // fallthrough case XK_Alt_L: return Key::ALT; // Key::WIN_LOGO - case XK_Super_L: - case XK_Super_R: return Key::LINUX_SUPER; - case XK_Meta_L: - case XK_Meta_R: return Key::LINUX_META; + case XK_Super_R: location = jwm::KeyLocation::RIGHT; // fallthrough + case XK_Super_L: return Key::LINUX_SUPER; + case XK_Meta_R: location = jwm::KeyLocation::RIGHT; // fallthrough + case XK_Meta_L: return Key::LINUX_META; // Key::MAC_COMMAND // Key::MAC_OPTION // Key::MAC_FN @@ -119,23 +121,25 @@ jwm::Key jwm::KeyX11::fromNative(uint32_t v) { case XK_bracketleft: return Key::OPEN_BRACKET; case XK_backslash: return Key::BACK_SLASH; case XK_bracketright: return Key::CLOSE_BRACKET; - case XK_KP_0: return Key::DIGIT0; - case XK_KP_1: return Key::DIGIT1; - case XK_KP_2: return Key::DIGIT2; - case XK_KP_3: return Key::DIGIT3; - case XK_KP_4: return Key::DIGIT4; - case XK_KP_5: return Key::DIGIT5; - case XK_KP_6: return Key::DIGIT6; - case XK_KP_7: return Key::DIGIT7; - case XK_KP_8: return Key::DIGIT8; - case XK_KP_9: return Key::DIGIT9; + case XK_KP_0: case XK_KP_Insert: location = jwm::KeyLocation::KEYPAD; return Key::DIGIT0; + case XK_KP_1: case XK_KP_End: location = jwm::KeyLocation::KEYPAD; return Key::DIGIT1; + case XK_KP_2: case XK_KP_Down: location = jwm::KeyLocation::KEYPAD; return Key::DIGIT2; + case XK_KP_3: case XK_KP_Page_Down: location = jwm::KeyLocation::KEYPAD; return Key::DIGIT3; + case XK_KP_4: case XK_KP_Left: location = jwm::KeyLocation::KEYPAD; return Key::DIGIT4; + case XK_KP_5: case XK_KP_Begin: location = jwm::KeyLocation::KEYPAD; return Key::DIGIT5; + case XK_KP_6: case XK_KP_Right: location = jwm::KeyLocation::KEYPAD; return Key::DIGIT6; + case XK_KP_7: case XK_KP_Home: location = jwm::KeyLocation::KEYPAD; return Key::DIGIT7; + case XK_KP_8: case XK_KP_Up: location = jwm::KeyLocation::KEYPAD; return Key::DIGIT8; + case XK_KP_9: case XK_KP_Page_Up: location = jwm::KeyLocation::KEYPAD; return Key::DIGIT9; + case XK_KP_Add: location = jwm::KeyLocation::KEYPAD; return Key::ADD; + case XK_KP_Separator: location = jwm::KeyLocation::KEYPAD; return Key::SEPARATOR; + case XK_KP_Subtract: location = jwm::KeyLocation::KEYPAD; return Key::MINUS; + case XK_KP_Decimal: location = jwm::KeyLocation::KEYPAD; return Key::PERIOD; + case XK_KP_Divide: location = jwm::KeyLocation::KEYPAD; return Key::SLASH; + case XK_KP_Delete: location = jwm::KeyLocation::KEYPAD; return Key::DEL; + case XK_KP_Enter: location = jwm::KeyLocation::KEYPAD; return Key::ENTER; + case XK_KP_Multiply: location = jwm::KeyLocation::KEYPAD; return Key::MULTIPLY; case XK_multiply: return Key::MULTIPLY; - case XK_KP_Add: return Key::ADD; - case XK_KP_Separator: return Key::SEPARATOR; - case XK_KP_Subtract: return Key::MINUS; - case XK_KP_Decimal: return Key::PERIOD; - case XK_KP_Divide: return Key::SLASH; - case XK_KP_Delete: return Key::DEL; case XK_Delete: return Key::DEL; case XK_Num_Lock: return Key::NUM_LOCK; case XK_Scroll_Lock: return Key::SCROLL_LOCK; @@ -173,6 +177,53 @@ jwm::Key jwm::KeyX11::fromNative(uint32_t v) { // Key::VOLUME_UP // Key::VOLUME_DOWN // Key::MUTE + case XK_exclam: modifiers = (int)jwm::KeyModifier::SHIFT; return Key::DIGIT1; + case XK_quotedbl: modifiers = (int)jwm::KeyModifier::SHIFT; return Key::QUOTE; + case XK_numbersign: modifiers = (int)jwm::KeyModifier::SHIFT; return Key::DIGIT3; + case XK_dollar: modifiers = (int)jwm::KeyModifier::SHIFT; return Key::DIGIT4; + case XK_percent: modifiers = (int)jwm::KeyModifier::SHIFT; return Key::DIGIT5; + case XK_ampersand: modifiers = (int)jwm::KeyModifier::SHIFT; return Key::DIGIT7; + case XK_parenleft: modifiers = (int)jwm::KeyModifier::SHIFT; return Key::DIGIT9; + case XK_parenright: modifiers = (int)jwm::KeyModifier::SHIFT; return Key::DIGIT0; + case XK_asterisk: modifiers = (int)jwm::KeyModifier::SHIFT; return Key::DIGIT8; + case XK_plus: return Key::ADD; + case XK_colon: modifiers = (int)jwm::KeyModifier::SHIFT; return Key::SEMICOLON; + case XK_less: modifiers = (int)jwm::KeyModifier::SHIFT; return Key::COMMA; + case XK_greater: modifiers = (int)jwm::KeyModifier::SHIFT; return Key::PERIOD; + case XK_question: modifiers = (int)jwm::KeyModifier::SHIFT; return Key::SLASH; + case XK_at: modifiers = (int)jwm::KeyModifier::SHIFT; return Key::DIGIT2; + case XK_asciicircum: modifiers = (int)jwm::KeyModifier::SHIFT; return Key::DIGIT6; + case XK_underscore: modifiers = (int)jwm::KeyModifier::SHIFT; return Key::MINUS; + case XK_braceleft: modifiers = (int)jwm::KeyModifier::SHIFT; return Key::OPEN_BRACKET; + case XK_bar: modifiers = (int)jwm::KeyModifier::SHIFT; return Key::BACK_SLASH; + case XK_braceright: modifiers = (int)jwm::KeyModifier::SHIFT; return Key::CLOSE_BRACKET; + case XK_asciitilde: modifiers = (int)jwm::KeyModifier::SHIFT; return Key::BACK_QUOTE; + case XK_A: return Key::A; + case XK_B: return Key::B; + case XK_C: return Key::C; + case XK_D: return Key::D; + case XK_E: return Key::E; + case XK_F: return Key::F; + case XK_G: return Key::G; + case XK_H: return Key::H; + case XK_I: return Key::I; + case XK_J: return Key::J; + case XK_K: return Key::K; + case XK_L: return Key::L; + case XK_M: return Key::M; + case XK_N: return Key::N; + case XK_O: return Key::O; + case XK_P: return Key::P; + case XK_Q: return Key::Q; + case XK_R: return Key::R; + case XK_S: return Key::S; + case XK_T: return Key::T; + case XK_U: return Key::U; + case XK_V: return Key::V; + case XK_W: return Key::W; + case XK_X: return Key::X; + case XK_Y: return Key::Y; + case XK_Z: return Key::Z; default: return Key::UNDEFINED; } } diff --git a/x11/cc/KeyX11.hh b/x11/cc/KeyX11.hh index ce03b165..5f02ede2 100644 --- a/x11/cc/KeyX11.hh +++ b/x11/cc/KeyX11.hh @@ -2,10 +2,11 @@ #include #include "Key.hh" +#include "KeyLocation.hh" namespace jwm { namespace KeyX11 { - jwm::Key fromNative(uint32_t v); + jwm::Key fromNative(uint32_t v, jwm::KeyLocation& location, int& modifiers); bool getKeyState(jwm::Key key); void setKeyState(jwm::Key key, bool isDown); int getModifiers(); diff --git a/x11/cc/WindowManagerX11.cc b/x11/cc/WindowManagerX11.cc index 6d38f024..a1457961 100644 --- a/x11/cc/WindowManagerX11.cc +++ b/x11/cc/WindowManagerX11.cc @@ -588,13 +588,16 @@ void WindowManagerX11::_processXEvent(XEvent& ev) { KeySym s = XLookupKeysym(&ev.xkey, 0); if (s != NoSymbol) { - jwm::Key key = KeyX11::fromNative(s); + int modifiers; + jwm::KeyLocation location; + jwm::Key key = KeyX11::fromNative(s, location, modifiers); jwm::KeyX11::setKeyState(key, true); jwm::JNILocal eventKey(app.getJniEnv(), EventKey::make(app.getJniEnv(), key, true, - jwm::KeyX11::getModifiers())); + jwm::KeyX11::getModifiers() | modifiers, + location)); myWindow->dispatch(eventKey.get()); } @@ -630,13 +633,16 @@ void WindowManagerX11::_processXEvent(XEvent& ev) { case KeyRelease: { // keyboard up KeySym s = XLookupKeysym(&ev.xkey, 0); - jwm::Key key = KeyX11::fromNative(s); + int modifiers; + jwm::KeyLocation location; + jwm::Key key = KeyX11::fromNative(s, location, modifiers); jwm::KeyX11::setKeyState(key, false); jwm::JNILocal eventKey(app.getJniEnv(), EventKey::make(app.getJniEnv(), key, false, - jwm::KeyX11::getModifiers())); + jwm::KeyX11::getModifiers() | modifiers, + location)); myWindow->dispatch(eventKey.get()); break; } diff --git a/x11/cc/WindowX11.cc b/x11/cc/WindowX11.cc index 4c2605f2..177d8e0e 100644 --- a/x11/cc/WindowX11.cc +++ b/x11/cc/WindowX11.cc @@ -8,7 +8,6 @@ #include #include - using namespace jwm; @@ -307,9 +306,14 @@ void WindowX11::getDecorations(int& left, int& top, int& right, int& bottom) { void WindowX11::getContentPosition(int& posX, int& posY) { int x, y; ::Window child; + XWindowAttributes wa; + + XGetWindowAttributes(_windowManager.display, _x11Window, &wa); + + XTranslateCoordinates(_windowManager.display, _x11Window, - XRootWindow(_windowManager.display, 0), + wa.root, 0, 0, &x, &y, &child); @@ -434,7 +438,8 @@ const ScreenInfo& WindowX11::getScreen() { if (screen.bounds.isPointInside(centerX, centerY)) { return screen; } - } + } + return *jwm::app.getScreens().begin(); } From f03b9f124594e2b43f4ef1cac3110b144ed75b2f Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Wed, 13 Dec 2023 22:42:32 -0500 Subject: [PATCH 31/93] Mouse works --- wayland/cc/WindowWayland.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index 75c0a63c..90111a15 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -149,13 +149,11 @@ bool WindowWayland::resize(int width, int height) { return true; } - void WindowWayland::_makeCursors() { if (theme) wl_cursor_theme_destroy(theme); theme = wl_cursor_theme_load(nullptr, 24 * _scale, _windowManager.shm); - } // cursed wl_cursor* WindowWayland::_getCursorFor(jwm::MouseCursor cursor) { @@ -265,17 +263,18 @@ void WindowWayland::setVisible(bool isVisible) { } void jwm::WindowWayland::setCursor(jwm::MouseCursor cursor) { - printf("%s\n", jwm::mouseCursorToStr(cursor)); // ????? // Doesn't work for higher numbers??? auto wayCursor = _getCursorFor(cursor)->images[0]; + auto buf = wl_cursor_image_get_buffer(wayCursor); wl_surface_attach(_windowManager.cursorSurface, wl_cursor_image_get_buffer(wayCursor), 0, 0); wl_surface_set_buffer_scale(_windowManager.cursorSurface, _scale); - wl_surface_commit(_windowManager.cursorSurface); + wl_surface_damage_buffer(_windowManager.cursorSurface, 0, 0, INT32_MAX, INT32_MAX); wl_pointer_set_cursor(_windowManager.pointer, _windowManager.mouseSerial, _windowManager.cursorSurface, wayCursor->hotspot_x / _scale, wayCursor->hotspot_y / _scale); + wl_surface_commit(_windowManager.cursorSurface); } // what do??? From 535f8a4a74bbdeefac5b04407fcdf42bd603fe3b Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Wed, 13 Dec 2023 22:51:58 -0500 Subject: [PATCH 32/93] LESS THREAD SAFETY --- wayland/cc/AppWayland.cc | 10 ++-------- wayland/cc/AppWayland.hh | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/wayland/cc/AppWayland.cc b/wayland/cc/AppWayland.cc index e32a2575..5bdde0a9 100644 --- a/wayland/cc/AppWayland.cc +++ b/wayland/cc/AppWayland.cc @@ -7,8 +7,7 @@ jwm::AppWayland jwm::app; void jwm::AppWayland::init(JNIEnv* jniEnv) { - jint rs = jniEnv->GetJavaVM(&_javaVM); - assert(rs == JNI_OK); + _jniEnv = jniEnv; } void jwm::AppWayland::start() { @@ -20,12 +19,7 @@ void jwm::AppWayland::terminate() { } JNIEnv* jwm::AppWayland::getJniEnv() { - JNIEnv* env; - // no-op on an already attached thread, so fast? - // makes it thread-safe (?) - jint rs = _javaVM->AttachCurrentThread((void**)&env, nullptr); - assert(rs == JNI_OK); - return env; + return _jniEnv; } // JNI diff --git a/wayland/cc/AppWayland.hh b/wayland/cc/AppWayland.hh index 2b5ba6f6..690a26f6 100644 --- a/wayland/cc/AppWayland.hh +++ b/wayland/cc/AppWayland.hh @@ -21,7 +21,7 @@ namespace jwm { JNIEnv* getJniEnv(); - JavaVM* _javaVM; + JNIEnv* _jniEnv; WindowManagerWayland wm; } app; } From 0909a7492fe7b37dc8bca1a8f4996dde05aa2bdf Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Wed, 13 Dec 2023 23:16:09 -0500 Subject: [PATCH 33/93] do not load cursor on resize --- wayland/cc/WindowWayland.cc | 5 +++-- wayland/cc/WindowWayland.hh | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index 90111a15..d78e47ee 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -420,8 +420,9 @@ void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { ) ); dispatch(eventWindowResize.get()); - - _makeCursors(); + if (_scale != _oldScale) + _makeCursors(); + _oldScale = _scale; // In Java Wayland doesn't actually cause a frame: // however decorFrameCommit will cause a redraw anyway. // Not doing it in wayland lets me not cause an exception on hide. diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index 6bdaaa75..b1b09384 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -84,6 +84,7 @@ namespace jwm { int _width = -1; int _newWidth = -1; int _scale = 1; + int _oldScale = 1; int _height = -1; int _newHeight = -1; int _WM_ADD = 1L; From 8349eb464a874d541698617910d3f299a076d215 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Thu, 14 Dec 2023 00:00:25 -0500 Subject: [PATCH 34/93] scrolling --- wayland/cc/WindowManagerWayland.cc | 51 ++++++++++++++++++++++++++++-- wayland/cc/WindowManagerWayland.hh | 3 ++ wayland/cc/WindowWayland.cc | 2 -- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index d5736d26..54e9b0cc 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -35,7 +35,38 @@ wl_pointer_listener WindowManagerWayland::_pointerListener = { .leave = WindowManagerWayland::pointerHandleLeave, .motion = WindowManagerWayland::pointerHandleMotion, .button = WindowManagerWayland::pointerHandleButton, - .axis = WindowManagerWayland::pointerHandleAxis + .axis = WindowManagerWayland::pointerHandleAxis, + .frame = [](void* data, wl_pointer* pointer) { + auto self = reinterpret_cast(data); + if (!self->focusedSurface) return; + if (self->_dX != 0.0f || self->_dY != 0.0f) { + auto env = app.getJniEnv(); + auto win = self->getWindowForNative(self->focusedSurface); + if (win) { + jwm::JNILocal eventAxis( + env, + jwm::classes::EventMouseScroll::make( + env, + self->_dX * win->_scale, + self->_dY * win->_scale, + 0.0f, + 0.0f, + 0.0f, + self->lastMousePosX, + self->lastMousePosY, + jwm::KeyWayland::getModifiers(self->_xkbState) + ) + ); + win->dispatch(eventAxis.get()); + + } + self->_dX = 0.0f; + self->_dY = 0.0f; + } + }, + .axis_source = [](void* data, wl_pointer* pointer, uint32_t source) {}, + .axis_stop = [](void* data, wl_pointer* pointer, uint32_t time, uint32_t axis) {}, + .axis_discrete = [](void* data, wl_pointer* pointer, uint32_t axis, int discrete) {} }; libdecor_interface WindowManagerWayland::_decorInterface = { @@ -178,7 +209,7 @@ void WindowManagerWayland::registryHandleGlobal(void* data, wl_registry *registr &wl_data_device_manager_interface, 1); } else if (strcmp(interface, wl_seat_interface.name) == 0) { self->seat = (wl_seat*)wl_registry_bind(registry, name, - &wl_seat_interface, 1); + &wl_seat_interface, 5); } else if (strcmp(interface, wl_output_interface.name) == 0) { wl_output* output = (wl_output*)wl_registry_bind(registry, name, &wl_output_interface, 2); @@ -321,7 +352,21 @@ void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, } } void WindowManagerWayland::pointerHandleAxis(void* data, wl_pointer* pointer, - uint32_t time, uint32_t axis, wl_fixed_t value) {} + uint32_t time, uint32_t axis, wl_fixed_t value) { + auto self = reinterpret_cast(data); + if (!self->focusedSurface) return; + + switch (axis) { + case WL_POINTER_AXIS_VERTICAL_SCROLL: + self->_dY += static_cast(wl_fixed_to_double(value)); + break; + case WL_POINTER_AXIS_HORIZONTAL_SCROLL: + self->_dX += static_cast(wl_fixed_to_double(value)); + break; + default: + break; + } +} void WindowManagerWayland::keyboardKeymap(void* data, wl_keyboard* keyboard, uint32_t format, int32_t fd, uint32_t size) { auto self = reinterpret_cast(data); diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index 6913fd37..8c5f73dd 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -133,6 +133,9 @@ namespace jwm { std::atomic_bool notifyBool{false}; int lastMousePosX = 0; int lastMousePosY = 0; + // god forgive me for using float + float _dX = 0.0f; + float _dY = 0.0f; int mouseMask = 0; void mouseUpdate(WindowWayland* myWindow, uint32_t x, uint32_t y, uint32_t mask); diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index d78e47ee..f4303a08 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -263,8 +263,6 @@ void WindowWayland::setVisible(bool isVisible) { } void jwm::WindowWayland::setCursor(jwm::MouseCursor cursor) { - // ????? - // Doesn't work for higher numbers??? auto wayCursor = _getCursorFor(cursor)->images[0]; auto buf = wl_cursor_image_get_buffer(wayCursor); wl_surface_attach(_windowManager.cursorSurface, From d9efd31c9d2c88ca0ef350dfcad0b78a28060343 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Fri, 15 Dec 2023 14:57:33 -0500 Subject: [PATCH 35/93] repeating (stalls) --- wayland/cc/Buffer.cc | 9 +- wayland/cc/Keyboard.cc | 166 +++++++++++++++ wayland/cc/Keyboard.hh | 49 +++++ wayland/cc/LayerRasterWayland.cc | 14 -- wayland/cc/WindowManagerWayland.cc | 315 +++++++++++------------------ wayland/cc/WindowManagerWayland.hh | 33 ++- wayland/cc/WindowWayland.cc | 10 +- 7 files changed, 359 insertions(+), 237 deletions(-) create mode 100644 wayland/cc/Keyboard.cc create mode 100644 wayland/cc/Keyboard.hh diff --git a/wayland/cc/Buffer.cc b/wayland/cc/Buffer.cc index 35644145..19ecf611 100644 --- a/wayland/cc/Buffer.cc +++ b/wayland/cc/Buffer.cc @@ -6,11 +6,12 @@ #include using namespace jwm; +static void bufRelease(void* data, wl_buffer* wlbuffer) { + auto buffer = reinterpret_cast(data); + delete buffer; +} wl_buffer_listener Buffer::_bufferListener = { - .release = [](void* data, wl_buffer* wlbuffer) { - auto buffer = reinterpret_cast(data); - delete buffer; - } + .release = bufRelease }; static void randname(char *buf) { diff --git a/wayland/cc/Keyboard.cc b/wayland/cc/Keyboard.cc new file mode 100644 index 00000000..a3a4a478 --- /dev/null +++ b/wayland/cc/Keyboard.cc @@ -0,0 +1,166 @@ +#include "Keyboard.hh" +#include "WindowManagerWayland.hh" +#include "WindowWayland.hh" +#include "KeyWayland.hh" +#include +#include +#include "StringUTF16.hh" +#include +#include +#include +#include +#include +#include "AppWayland.hh" +#include +using namespace jwm; + +// I've noticed that pointers to lambdas are null for some reason. +// No idea what's wrong. Going to cry myself to sleep tonight. +static void kbKeymap(void* data, wl_keyboard* kb, uint32_t format, int32_t fd, uint32_t size) { + auto self = reinterpret_cast(data); + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + close(fd); + fprintf(stderr, "no xkb keymap\n"); + return; + } + + char* map_str = reinterpret_cast(mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0)); + if (map_str == MAP_FAILED) { + close(fd); + fprintf(stderr, "keymap mmap failed: %s", strerror(errno)); + return; + } + + xkb_keymap* keymap = xkb_keymap_new_from_string( + self->_context, map_str, + XKB_KEYMAP_FORMAT_TEXT_V1, + XKB_KEYMAP_COMPILE_NO_FLAGS + ); + munmap(map_str, size); + close(fd); + + if (!keymap) { + return; + } + self->_state = xkb_state_new(keymap); + + xkb_keymap_unref(keymap); + +} +static void kbEnter(void* data, wl_keyboard* kb, uint32_t serial, wl_surface* surface, + wl_array *keys) { + auto self = reinterpret_cast(data); + auto win = self->_wm.getWindowForNative(surface); + if (!win) return; + self->_serial = serial; + self->_focus = win; + if (self->_state) { + // TODO: keys + } +} +static void kbLeave(void* data, wl_keyboard* kb, uint32_t serial, wl_surface* surface) { + auto self = reinterpret_cast(data); + self->_serial = -1; + self->_focus = nullptr; +} +static void kbKey(void* data, wl_keyboard* kb, uint32_t serial, uint32_t time, + uint32_t key, uint32_t state) { + auto self = reinterpret_cast(data); + if (!self->_state || !self->_focus) return; + + const xkb_keysym_t *syms; + + if (xkb_state_key_get_syms(self->_state, key + 8, &syms) != 1) + return; + jwm::Key jwmKey = KeyWayland::fromNative(syms[0]); + if (jwmKey != jwm::Key::UNDEFINED) { + jwm::KeyLocation location = jwm::KeyLocation::DEFAULT; + JNILocal keyEvent( + jwm::app.getJniEnv(), + classes::EventKey::make( + jwm::app.getJniEnv(), + jwmKey, + state == WL_KEYBOARD_KEY_STATE_PRESSED, + KeyWayland::getModifiers(self->_state), + location + ) + ); + self->_focus->dispatch(keyEvent.get()); + } + self->_repeatingText = false; + self->_repeating = false; + if (state != WL_KEYBOARD_KEY_STATE_PRESSED) { + self->_lastPress = std::chrono::time_point(); + self->_nextRepeat = std::chrono::time_point(); + return; + } + // ??? + self->_lastPress = std::chrono::steady_clock::now(); + self->_repeatKey = jwmKey; + if (self->_repeatRate > 0) { + self->_repeating = true; + self->_nextRepeat = self->_lastPress + std::chrono::milliseconds(self->_repeatDelay); + } + self->_wm.notifyLoop(); + char textBuffer[0x40]; + int count = xkb_state_key_get_utf8(self->_state, key + 8, textBuffer, sizeof(textBuffer)-1); + // ??? + if (count >= sizeof(textBuffer) - 1) { + return; + } + if (count > 0) { + // ignore sinful control symbols + if (textBuffer[0] != 127 && textBuffer[0] > 0x1f) { + JNIEnv* env = jwm::app.getJniEnv(); + + jwm::StringUTF16 converted = reinterpret_cast(textBuffer); + self->_repeatText = converted; + if (self->_repeatRate > 0) + self->_repeatingText = true; + jwm::JNILocal jtext = converted.toJString(env); + + jwm::JNILocal eventTextInput(env, classes::EventTextInput::make(env, jtext.get())); + + + self->_focus->dispatch(eventTextInput.get()); + } + } +} +void kbModifiers(void* data, wl_keyboard* kb, uint32_t serial, uint32_t mods_depressed, + uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { + auto self = reinterpret_cast(data); + if (!self->_state) return; + xkb_state_update_mask(self->_state, + mods_depressed, mods_latched, mods_locked, + 0, 0, group); +} +void kbRepeatInfo(void* data, wl_keyboard* kb, int32_t rate, int32_t delay) { + auto self = reinterpret_cast(data); + self->_repeatRate = rate; + self->_repeatDelay = delay; +} + +wl_keyboard_listener Keyboard::_keyboardListener = { + .keymap = kbKeymap, + .enter = kbEnter, + .leave = kbLeave, + .key = kbKey, + .modifiers = kbModifiers, + .repeat_info = kbRepeatInfo +}; +Keyboard::Keyboard(wl_keyboard* kb, WindowManagerWayland* wm): + _keyboard(kb), + _wm(*wm) +{ + wl_keyboard_add_listener(kb, &_keyboardListener, this); + _context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); +} + +Keyboard::~Keyboard() +{ + if (_keyboard) + wl_keyboard_release(_keyboard); + if (_context) + xkb_context_unref(_context); +} diff --git a/wayland/cc/Keyboard.hh b/wayland/cc/Keyboard.hh new file mode 100644 index 00000000..e2ee2408 --- /dev/null +++ b/wayland/cc/Keyboard.hh @@ -0,0 +1,49 @@ +#pragma once + +#include +#include +#include +#include "KeyWayland.hh" +#include "StringUTF16.hh" + +namespace jwm { + class WindowManagerWayland; + class WindowWayland; + class Keyboard { + public: + Keyboard(wl_keyboard* kb, jwm::WindowManagerWayland* wm); + ~Keyboard(); + + wl_keyboard* _keyboard; + wl_keyboard* getKeyboard() const { + return _keyboard; + } + xkb_context* _context = nullptr; + xkb_state* _state = nullptr; + xkb_state* getState() const { + return _state; + } + jwm::WindowWayland* _focus = nullptr; + jwm::WindowWayland* getFocus() const { + return _focus; + } + uint32_t _serial = 0; + uint32_t getSerial() const { + return _serial; + } + std::chrono::time_point _lastPress; + std::chrono::time_point _nextRepeat; + int32_t _repeatRate = 100; + int32_t _repeatDelay = 300; + + jwm::StringUTF16 _repeatText; + jwm::Key _repeatKey = jwm::Key::UNDEFINED; + bool _repeating = false; + bool _repeatingText = false; + + jwm::WindowManagerWayland& _wm; + + static wl_keyboard_listener _keyboardListener; + + }; +} diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index 8ca5664b..9993b387 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -43,10 +43,6 @@ namespace jwm { return _width * sizeof(uint32_t); } - // only way to really be sane with raster - // it's SO slow that i'll prob - static wl_callback_listener _frameCallback; - void swapNow() { auto buf = Buffer::createShmBuffer(fWindow->_windowManager.shm, _width, _height, WL_SHM_FORMAT_XRGB8888); void* daData = buf->getData(); @@ -62,9 +58,6 @@ namespace jwm { if (_attached && fWindow->_waylandWindow) { // all impls that I've seen have to make a new buffer every frame. // God awful. Never use raster if you value performance. - // wl_callback* cb = wl_surface_frame(fWindow->_waylandWindow); - // wl_callback_add_listener(cb, &_frameCallback, this); - // wl_display_roundtrip(fWindow->_windowManager.display); swapNow(); } } @@ -101,13 +94,6 @@ namespace jwm { } using namespace jwm; -wl_callback_listener LayerRaster::_frameCallback = { - .done = [](void* data, wl_callback* cb, uint32_t cbData) { - auto self = reinterpret_cast(data); - self->swapNow(); - - } -}; extern "C" JNIEXPORT jlong JNICALL Java_io_github_humbleui_jwm_LayerRaster__1nMake (JNIEnv* env, jclass jclass) { jwm::LayerRaster* instance = new jwm::LayerRaster; diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 54e9b0cc..efc0cb2b 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -23,6 +23,7 @@ #include #include #include +#include using namespace jwm; @@ -30,13 +31,7 @@ wl_registry_listener WindowManagerWayland::_registryListener = { .global = WindowManagerWayland::registryHandleGlobal, .global_remove = WindowManagerWayland::registryHandleGlobalRemove }; -wl_pointer_listener WindowManagerWayland::_pointerListener = { - .enter = WindowManagerWayland::pointerHandleEnter, - .leave = WindowManagerWayland::pointerHandleLeave, - .motion = WindowManagerWayland::pointerHandleMotion, - .button = WindowManagerWayland::pointerHandleButton, - .axis = WindowManagerWayland::pointerHandleAxis, - .frame = [](void* data, wl_pointer* pointer) { +static void pointerFrame(void* data, wl_pointer* pointer) { auto self = reinterpret_cast(data); if (!self->focusedSurface) return; if (self->_dX != 0.0f || self->_dY != 0.0f) { @@ -54,7 +49,7 @@ wl_pointer_listener WindowManagerWayland::_pointerListener = { 0.0f, self->lastMousePosX, self->lastMousePosY, - jwm::KeyWayland::getModifiers(self->_xkbState) + jwm::KeyWayland::getModifiers(self->getXkbState()) ) ); win->dispatch(eventAxis.get()); @@ -63,23 +58,26 @@ wl_pointer_listener WindowManagerWayland::_pointerListener = { self->_dX = 0.0f; self->_dY = 0.0f; } - }, - .axis_source = [](void* data, wl_pointer* pointer, uint32_t source) {}, - .axis_stop = [](void* data, wl_pointer* pointer, uint32_t time, uint32_t axis) {}, - .axis_discrete = [](void* data, wl_pointer* pointer, uint32_t axis, int discrete) {} +} +static void pointerAxisSource(void* data, wl_pointer* pointer, uint32_t source) {} +static void pointerAxisStop(void* data, wl_pointer* pointer, uint32_t time, uint32_t axis) {} +static void pointerAxisDiscrete(void* data, wl_pointer* pointer, uint32_t axis, int discrete) {} +// Lambdas turn into null pointers at runtime. God knows why. +wl_pointer_listener WindowManagerWayland::_pointerListener = { + .enter = WindowManagerWayland::pointerHandleEnter, + .leave = WindowManagerWayland::pointerHandleLeave, + .motion = WindowManagerWayland::pointerHandleMotion, + .button = WindowManagerWayland::pointerHandleButton, + .axis = WindowManagerWayland::pointerHandleAxis, + .frame = pointerFrame, + .axis_source = pointerAxisSource, + .axis_stop = pointerAxisStop, + .axis_discrete = pointerAxisDiscrete }; libdecor_interface WindowManagerWayland::_decorInterface = { .error = WindowManagerWayland::libdecorError }; -wl_keyboard_listener WindowManagerWayland::_keyboardListener = { - .keymap = WindowManagerWayland::keyboardKeymap, - .enter = WindowManagerWayland::keyboardEnter, - .leave = WindowManagerWayland::keyboardLeave, - .key = WindowManagerWayland::keyboardKey, - .modifiers = WindowManagerWayland::keyboardModifiers, - .repeat_info = WindowManagerWayland::keyboardRepeatInfo -}; wl_seat_listener WindowManagerWayland::_seatListener = { .capabilities = WindowManagerWayland::seatCapabilities, .name = WindowManagerWayland::seatName @@ -88,7 +86,6 @@ WindowManagerWayland::WindowManagerWayland(): display(wl_display_connect(nullptr)) { registry = wl_display_get_registry(display); wl_registry_add_listener(registry, &_registryListener, this); - wl_display_roundtrip(display); @@ -134,7 +131,21 @@ void WindowManagerWayland::runLoop() { if (jwm::classes::Throwable::exceptionThrown(app.getJniEnv())) _runLoop = false; // block until event : ) - if (poll(&ps[0], 2, -1) < 0) { + int timeout = -1; + if (_keyboard && _keyboard->_repeating) { + if (_keyboard->_repeatRate > 0) { + auto target = _keyboard->_nextRepeat; + auto now = std::chrono::steady_clock::now(); + if (now < target) + timeout = std::chrono::duration_cast(now - target).count(); + else { + auto ms = std::chrono::milliseconds(_keyboard->_repeatRate); + _keyboard->_nextRepeat += ms; + timeout = _keyboard->_repeatRate; + } + } + } + if (poll(&ps[0], 2, timeout) < 0) { printf("error with pipe\n"); break; } @@ -173,6 +184,31 @@ void WindowManagerWayland::_processCallbacks() { lock.lock(); } } + if (_keyboard && _keyboard->getFocus() && _keyboard->_repeating) { + auto now = std::chrono::steady_clock::now(); + if (now > _keyboard->_nextRepeat) { + auto focus = _keyboard->getFocus(); + auto env = jwm::app.getJniEnv(); + jwm::KeyLocation location = jwm::KeyLocation::DEFAULT; + JNILocal keyEvent( + env, + classes::EventKey::make( + env, + _keyboard->_repeatKey, + true, + KeyWayland::getModifiers(_keyboard->_state), + location + ) + ); + focus->dispatch(keyEvent.get()); + if (_keyboard->_repeatingText) { + jwm::JNILocal jtext = _keyboard->_repeatText.toJString(env); + jwm::JNILocal eventTextInput(env, classes::EventTextInput::make(env, jtext.get())); + + focus->dispatch(eventTextInput.get()); + } + } + } { // copy window list in case one closes any other, invalidating some iterator in _nativeWindowToMy std::vector copy; @@ -306,7 +342,7 @@ void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, false, self->lastMousePosX, self->lastMousePosY, - jwm::KeyWayland::getModifiers(self->_xkbState) + jwm::KeyWayland::getModifiers(self->getXkbState()) ) ); WindowWayland* window = self->getWindowForNative(self->focusedSurface); @@ -341,7 +377,7 @@ void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, true, self->lastMousePosX, self->lastMousePosY, - jwm::KeyWayland::getModifiers(self->_xkbState) + jwm::KeyWayland::getModifiers(self->getXkbState()) ) ); // me when this stuff is NULL : ( @@ -367,118 +403,6 @@ void WindowManagerWayland::pointerHandleAxis(void* data, wl_pointer* pointer, break; } } -void WindowManagerWayland::keyboardKeymap(void* data, wl_keyboard* keyboard, uint32_t format, - int32_t fd, uint32_t size) { - auto self = reinterpret_cast(data); - - if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { - close(fd); - fprintf(stderr, "no xkb keymap\n"); - return; - } - - char* map_str = reinterpret_cast(mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0)); - if (map_str == MAP_FAILED) { - close(fd); - fprintf(stderr, "keymap mmap failed: %s", strerror(errno)); - return; - } - - xkb_keymap* keymap = xkb_keymap_new_from_string( - self->_xkbContext, map_str, - XKB_KEYMAP_FORMAT_TEXT_V1, - XKB_KEYMAP_COMPILE_NO_FLAGS - ); - munmap(map_str, size); - close(fd); - - if (!keymap) { - return; - } - self->_xkbState = xkb_state_new(keymap); - - xkb_keymap_unref(keymap); -} -void WindowManagerWayland::keyboardEnter(void* data, wl_keyboard* keyboard, uint32_t serial, wl_surface* surface, - wl_array *keys) { - auto self = reinterpret_cast(data); - self->keyboardSerial = serial; - self->keyboardFocus = surface; -} -void WindowManagerWayland::keyboardLeave(void* data, wl_keyboard* keyboard, uint32_t serial, wl_surface* surface) { - auto self = reinterpret_cast(data); - self->keyboardSerial = -1; - self->keyboardFocus = nullptr; -} - -void WindowManagerWayland::keyboardKey(void* data, wl_keyboard* keyboard, uint32_t serial, uint32_t time, - uint32_t key, uint32_t state) -{ - auto self = reinterpret_cast(data); - if (!self->_xkbState) return; - const xkb_keysym_t *syms; - - if (xkb_state_key_get_syms(self->_xkbState, key + 8, &syms) != 1) - return; - jwm::Key jwmKey = KeyWayland::fromNative(syms[0]); - // TODO: while unlikely, it could be possible that you can be entering text even if the - // pointer hasn't entered - if (self->keyboardFocus && jwmKey != jwm::Key::UNDEFINED) { - jwm::KeyLocation location = jwm::KeyLocation::DEFAULT; - JNILocal keyEvent( - app.getJniEnv(), - classes::EventKey::make( - app.getJniEnv(), - jwmKey, - state == WL_KEYBOARD_KEY_STATE_PRESSED, - KeyWayland::getModifiers(self->_xkbState), - location - ) - ); - auto window = self->getWindowForNative(self->keyboardFocus); - if (window) - window->dispatch(keyEvent.get()); - } - if (state != WL_KEYBOARD_KEY_STATE_PRESSED) return; - - char textBuffer[0x40]; - int count = xkb_state_key_get_utf8(self->_xkbState, key + 8, textBuffer, sizeof(textBuffer)-1); - // ??? - if (count >= sizeof(textBuffer) - 1) { - return; - } - if (count > 0) { - // ignore sinful control symbols - if (textBuffer[0] != 127 && textBuffer[0] > 0x1f) { - JNIEnv* env = app.getJniEnv(); - - jwm::StringUTF16 converted = reinterpret_cast(textBuffer); - jwm::JNILocal jtext = converted.toJString(env); - - jwm::JNILocal eventTextInput(env, classes::EventTextInput::make(env, jtext.get())); - - - auto window = self->getWindowForNative(self->keyboardFocus); - if (window) - window->dispatch(eventTextInput.get()); - } - } - -} -void WindowManagerWayland::keyboardModifiers(void* data, wl_keyboard* keyboard, - uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, - uint32_t group) { - auto self = reinterpret_cast(data); - if (!self->_xkbState) return; - xkb_state_update_mask(self->_xkbState, - mods_depressed, mods_latched, mods_locked, - 0, 0, group); -} - -void WindowManagerWayland::keyboardRepeatInfo(void* data, wl_keyboard* keyboard, - int32_t rate, int32_t delay) { - // TODO: The client (for some godforsaken reason) is expected to handle repeating characters -} void WindowManagerWayland::seatCapabilities(void* data, wl_seat* seat, uint32_t capabilities) { auto self = reinterpret_cast(data); @@ -492,60 +416,60 @@ void WindowManagerWayland::seatCapabilities(void* data, wl_seat* seat, uint32_t } if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && - !self->keyboard) { - self->keyboard = wl_seat_get_keyboard(seat); - self->_xkbContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - wl_keyboard_add_listener(self->keyboard, &_keyboardListener, self); + !self->_keyboard) { + self->_keyboard = new Keyboard(wl_seat_get_keyboard(seat), self); } else if (!(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && - self->keyboard) { - xkb_context_unref(self->_xkbContext); - wl_keyboard_release(self->keyboard); - self->keyboard = nullptr; + self->_keyboard) { + self->_keyboard = nullptr; } } void WindowManagerWayland::seatName(void* data, wl_seat* seat, const char* name) { // who cares } +static void offerOffer(void* data, wl_data_offer* offer, const char* mimeType) { + auto self = reinterpret_cast(data); + self->_currentMimeTypes.push_back(std::string(mimeType)); +} wl_data_offer_listener WindowManagerWayland::_offerListener = { - .offer = [](void* data, wl_data_offer* offer, const char* mimeType) { - auto self = reinterpret_cast(data); - self->_currentMimeTypes.push_back(std::string(mimeType)); - } + .offer = offerOffer }; -wl_data_device_listener WindowManagerWayland::_deviceListener = { - .data_offer = [](void* data, wl_data_device* device, wl_data_offer* offer) { - auto self = reinterpret_cast(data); - self->_currentMimeTypes = {}; - wl_data_offer_add_listener(offer, &_offerListener, data); - }, - .selection = [](void* data, wl_data_device* device, wl_data_offer* offer) { - auto self = reinterpret_cast(data); - self->_myClipboardContents = {}; - if (offer == nullptr) { - return; - } - for (auto i : self->_currentMimeTypes) { - int fds[2]; - pipe(fds); - wl_data_offer_receive(offer, i.c_str(), fds[1]); - wl_display_flush(self->display); - close(fds[1]); - ByteBuf res; - - - while (true) { - char buf[1024]; - ssize_t n = read(fds[0], buf, sizeof(buf)); - if (n <= 0) - break; - res.insert(res.end(), buf, buf + n); +static void deviceDataOffer(void* data, wl_data_device* device, wl_data_offer* offer) { + auto self = reinterpret_cast(data); + self->_currentMimeTypes = {}; + wl_data_offer_add_listener(offer, &WindowManagerWayland::_offerListener, data); +} +static void deviceSelection(void* data, wl_data_device* device, wl_data_offer* offer) { + auto self = reinterpret_cast(data); + self->_myClipboardContents = {}; + if (offer == nullptr) { + return; + } + for (auto i : self->_currentMimeTypes) { + int fds[2]; + pipe(fds); + wl_data_offer_receive(offer, i.c_str(), fds[1]); + wl_display_flush(self->display); + close(fds[1]); + ByteBuf res; + + + while (true) { + char buf[1024]; + ssize_t n = read(fds[0], buf, sizeof(buf)); + if (n <= 0) + break; + res.insert(res.end(), buf, buf + n); - } - self->_myClipboardContents[i] = res; - close(fds[0]); } - wl_data_offer_destroy(offer); + self->_myClipboardContents[i] = res; + close(fds[0]); } + wl_data_offer_destroy(offer); +} +wl_data_device_listener WindowManagerWayland::_deviceListener = { + .data_offer = deviceDataOffer, + .selection = deviceSelection + }; std::vector WindowManagerWayland::getClipboardFormats() { return { _currentMimeTypes.begin(), _currentMimeTypes.end()}; @@ -568,7 +492,7 @@ void WindowManagerWayland::mouseUpdate(WindowWayland* myWindow, uint32_t x, uint movementY, jwm::MouseButtonWayland::fromNativeMask(mask), // impl me! - jwm::KeyWayland::getModifiers(_xkbState) + jwm::KeyWayland::getModifiers(getXkbState()) ) ); auto foo = eventMove.get(); @@ -597,20 +521,21 @@ void WindowManagerWayland::terminate() { _runLoop = false; } -wl_data_source_listener WindowManagerWayland::_sourceListener = { - .send = [](void* data, wl_data_source* source, - const char* mimeType, int fd) { - auto self = reinterpret_cast(data); - auto it = self->_myClipboardContents.find(std::string(mimeType)); - if (it != self->_myClipboardContents.end()) { - write(fd, it->second.data(), it->second.size()); - } - close(fd); - }, - .cancelled = [](void* data, wl_data_source* source) { - auto self = reinterpret_cast(data); - wl_data_source_destroy(source); +static void dataSourceSend(void* data, wl_data_source* source, const char* mimeType, int fd) { + auto self = reinterpret_cast(data); + auto it = self->_myClipboardContents.find(std::string(mimeType)); + if (it != self->_myClipboardContents.end()) { + write(fd, it->second.data(), it->second.size()); } + close(fd); +} +static void dataSourceCancelled(void* data, wl_data_source* source) { + auto self = reinterpret_cast(data); + wl_data_source_destroy(source); +} +wl_data_source_listener WindowManagerWayland::_sourceListener = { + .send = dataSourceSend, + .cancelled = dataSourceCancelled }; void WindowManagerWayland::setClipboardContents(std::map&& c) { assert(("create at least one window in order to use clipboard" && !_nativeWindowToMy.empty())); @@ -628,8 +553,8 @@ void WindowManagerWayland::setClipboardContents(std::map&& wl_data_source_offer(currentSource, it.first.c_str()); } - if (keyboardSerial >= 0) - wl_data_device_set_selection(dataDevice, currentSource, keyboardSerial); + if (getKeyboardSerial() > 0) + wl_data_device_set_selection(dataDevice, currentSource, getKeyboardSerial()); } diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index 8c5f73dd..e6547f85 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -18,6 +18,7 @@ #include #include #include +#include "Keyboard.hh" namespace jwm { class WindowWayland; @@ -83,20 +84,6 @@ namespace jwm { static libdecor_interface _decorInterface; static void libdecorError(libdecor* context, enum libdecor_error error, const char* message); - static wl_keyboard_listener _keyboardListener; - static void keyboardKeymap(void* data, wl_keyboard* keyboard, - uint32_t format, int32_t fd, uint32_t size); - static void keyboardEnter(void* data, wl_keyboard* keyboard, - uint32_t serial, wl_surface* surface, wl_array* keys); - static void keyboardLeave(void* data, wl_keyboard* keyboard, uint32_t serial, - wl_surface* surface); - static void keyboardKey(void* data, wl_keyboard* keyboard, uint32_t serial, - uint32_t time, uint32_t key, uint32_t state); - static void keyboardModifiers(void* data, wl_keyboard* keyboard, uint32_t serial, - uint32_t modsDepressed, uint32_t modsLatched, uint32_t modLocked, - uint32_t group); - static void keyboardRepeatInfo(void* data, wl_keyboard* keyboard, int32_t rate, int32_t delay); - static wl_seat_listener _seatListener; static void seatCapabilities(void* data, wl_seat* seat, uint32_t capabilities); @@ -117,14 +104,21 @@ namespace jwm { // no multiseat? wl_seat* seat = nullptr; wl_pointer* pointer = nullptr; - wl_keyboard* keyboard = nullptr; + Keyboard* _keyboard = nullptr; wl_data_device* dataDevice = nullptr; wl_data_source* currentSource = nullptr; - uint32_t mouseSerial = -1; - uint32_t keyboardSerial = -1; + uint32_t mouseSerial = 0; + uint32_t getKeyboardSerial() const { + if (_keyboard) + return _keyboard->getSerial(); + return 0; + } + xkb_state* getXkbState() const { + if (_keyboard) + return _keyboard->getState(); + return nullptr; + } libdecor* decorCtx = nullptr; - xkb_context* _xkbContext = nullptr; - xkb_state* _xkbState = nullptr; EGLDisplay _eglDisplay = EGL_NO_DISPLAY; std::list outputs; @@ -146,7 +140,6 @@ namespace jwm { wl_surface* cursorSurface; wl_surface* focusedSurface = nullptr; - wl_surface* keyboardFocus = nullptr; // Is holding all cursors in memory a good idea? wl_cursor_image* _cursors[static_cast(jwm::MouseCursor::COUNT)]; diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index f4303a08..5e451a70 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -317,11 +317,13 @@ void jwm::WindowWayland::outputScale(void* data, wl_output* output, int factor) } void jwm::WindowWayland::outputName(void* data, wl_output* output, const char* name) {} void jwm::WindowWayland::outputDescription(void* data, wl_output* output, const char* desc) {} + +static void frameCallbackDone(void* data, wl_callback* cb, uint32_t cb_data) { + auto self = reinterpret_cast(data); + self->_adaptSize(self->_newWidth, self->_newHeight); +} wl_callback_listener jwm::WindowWayland::_frameCallback = { - .done = [](void* data, wl_callback* cb, uint32_t cb_data) { - auto self = reinterpret_cast(data); - self->_adaptSize(self->_newWidth, self->_newHeight); - } + .done = frameCallbackDone }; void jwm::WindowWayland::decorFrameConfigure(libdecor_frame* frame, libdecor_configuration* configuration, From 81077866806a200018174162d7e7c1dc78fbdf3a Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Fri, 15 Dec 2023 15:56:16 -0500 Subject: [PATCH 36/93] lowercase keys --- wayland/cc/Keyboard.cc | 20 ++++++++++++-------- wayland/cc/Keyboard.hh | 1 + wayland/cc/WindowManagerWayland.cc | 12 ++++++++++++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/wayland/cc/Keyboard.cc b/wayland/cc/Keyboard.cc index a3a4a478..9b4fb405 100644 --- a/wayland/cc/Keyboard.cc +++ b/wayland/cc/Keyboard.cc @@ -45,8 +45,7 @@ static void kbKeymap(void* data, wl_keyboard* kb, uint32_t format, int32_t fd, u } self->_state = xkb_state_new(keymap); - xkb_keymap_unref(keymap); - + self->_keymap = keymap; } static void kbEnter(void* data, wl_keyboard* kb, uint32_t serial, wl_surface* surface, wl_array *keys) { @@ -70,10 +69,12 @@ static void kbKey(void* data, wl_keyboard* kb, uint32_t serial, uint32_t time, if (!self->_state || !self->_focus) return; const xkb_keysym_t *syms; - - if (xkb_state_key_get_syms(self->_state, key + 8, &syms) != 1) + + uint32_t keyCode = key + 8; + if (xkb_state_key_get_syms(self->_state, keyCode, &syms) != 1) return; - jwm::Key jwmKey = KeyWayland::fromNative(syms[0]); + auto lowerSym = xkb_keysym_to_lower(syms[0]); + jwm::Key jwmKey = KeyWayland::fromNative(lowerSym); if (jwmKey != jwm::Key::UNDEFINED) { jwm::KeyLocation location = jwm::KeyLocation::DEFAULT; JNILocal keyEvent( @@ -98,13 +99,14 @@ static void kbKey(void* data, wl_keyboard* kb, uint32_t serial, uint32_t time, // ??? self->_lastPress = std::chrono::steady_clock::now(); self->_repeatKey = jwmKey; - if (self->_repeatRate > 0) { + bool shouldRepeat = xkb_keymap_key_repeats(self->_keymap, keyCode) && (self->_repeatRate > 0); + if (shouldRepeat && (jwmKey != jwm::Key::UNDEFINED)) { self->_repeating = true; self->_nextRepeat = self->_lastPress + std::chrono::milliseconds(self->_repeatDelay); } self->_wm.notifyLoop(); char textBuffer[0x40]; - int count = xkb_state_key_get_utf8(self->_state, key + 8, textBuffer, sizeof(textBuffer)-1); + int count = xkb_state_key_get_utf8(self->_state, keyCode, textBuffer, sizeof(textBuffer)-1); // ??? if (count >= sizeof(textBuffer) - 1) { return; @@ -116,7 +118,7 @@ static void kbKey(void* data, wl_keyboard* kb, uint32_t serial, uint32_t time, jwm::StringUTF16 converted = reinterpret_cast(textBuffer); self->_repeatText = converted; - if (self->_repeatRate > 0) + if (shouldRepeat) self->_repeatingText = true; jwm::JNILocal jtext = converted.toJString(env); @@ -163,4 +165,6 @@ Keyboard::~Keyboard() wl_keyboard_release(_keyboard); if (_context) xkb_context_unref(_context); + if (_keymap) + xkb_keymap_unref(_keymap); } diff --git a/wayland/cc/Keyboard.hh b/wayland/cc/Keyboard.hh index e2ee2408..7b16522d 100644 --- a/wayland/cc/Keyboard.hh +++ b/wayland/cc/Keyboard.hh @@ -20,6 +20,7 @@ namespace jwm { } xkb_context* _context = nullptr; xkb_state* _state = nullptr; + xkb_keymap* _keymap = nullptr; xkb_state* getState() const { return _state; } diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index efc0cb2b..92e8be9d 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -190,6 +190,17 @@ void WindowManagerWayland::_processCallbacks() { auto focus = _keyboard->getFocus(); auto env = jwm::app.getJniEnv(); jwm::KeyLocation location = jwm::KeyLocation::DEFAULT; + JNILocal keyOffEvent( + env, + classes::EventKey::make( + env, + _keyboard->_repeatKey, + false, + KeyWayland::getModifiers(_keyboard->_state), + location + ) + ); + JNILocal keyEvent( env, classes::EventKey::make( @@ -200,6 +211,7 @@ void WindowManagerWayland::_processCallbacks() { location ) ); + focus->dispatch(keyOffEvent.get()); focus->dispatch(keyEvent.get()); if (_keyboard->_repeatingText) { jwm::JNILocal jtext = _keyboard->_repeatText.toJString(env); From fd42b2f66db8c6a43ce336f8422a03d553b6b2ee Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Fri, 15 Dec 2023 16:21:23 -0500 Subject: [PATCH 37/93] Acceptable (lags) --- wayland/cc/WindowManagerWayland.cc | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 92e8be9d..145881db 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -134,14 +134,10 @@ void WindowManagerWayland::runLoop() { int timeout = -1; if (_keyboard && _keyboard->_repeating) { if (_keyboard->_repeatRate > 0) { - auto target = _keyboard->_nextRepeat; auto now = std::chrono::steady_clock::now(); - if (now < target) - timeout = std::chrono::duration_cast(now - target).count(); - else { - auto ms = std::chrono::milliseconds(_keyboard->_repeatRate); - _keyboard->_nextRepeat += ms; - timeout = _keyboard->_repeatRate; + auto target = _keyboard->_nextRepeat; + if (now < target) { + timeout = std::chrono::duration_cast(target - now).count(); } } } @@ -184,9 +180,10 @@ void WindowManagerWayland::_processCallbacks() { lock.lock(); } } - if (_keyboard && _keyboard->getFocus() && _keyboard->_repeating) { + if (_keyboard && _keyboard->_repeating && _keyboard->getFocus()) { auto now = std::chrono::steady_clock::now(); if (now > _keyboard->_nextRepeat) { + _keyboard->_nextRepeat = now + std::chrono::milliseconds(_keyboard->_repeatRate); auto focus = _keyboard->getFocus(); auto env = jwm::app.getJniEnv(); jwm::KeyLocation location = jwm::KeyLocation::DEFAULT; From 05cf38bcfe13cb1e269b8e69c145ddfb2963798f Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Fri, 15 Dec 2023 17:23:43 -0500 Subject: [PATCH 38/93] compose --- wayland/cc/Keyboard.cc | 87 +++++++++++++++++++++++++++++++++--------- wayland/cc/Keyboard.hh | 4 ++ 2 files changed, 72 insertions(+), 19 deletions(-) diff --git a/wayland/cc/Keyboard.cc b/wayland/cc/Keyboard.cc index 9b4fb405..6fffc3e6 100644 --- a/wayland/cc/Keyboard.cc +++ b/wayland/cc/Keyboard.cc @@ -12,13 +12,15 @@ #include #include "AppWayland.hh" #include +#include using namespace jwm; // I've noticed that pointers to lambdas are null for some reason. // No idea what's wrong. Going to cry myself to sleep tonight. static void kbKeymap(void* data, wl_keyboard* kb, uint32_t format, int32_t fd, uint32_t size) { auto self = reinterpret_cast(data); - + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { close(fd); fprintf(stderr, "no xkb keymap\n"); @@ -46,6 +48,12 @@ static void kbKeymap(void* data, wl_keyboard* kb, uint32_t format, int32_t fd, u self->_state = xkb_state_new(keymap); self->_keymap = keymap; + + const char* locale = std::setlocale(LC_CTYPE, nullptr); + + self->_composeTable = xkb_compose_table_new_from_locale(self->_context, locale, XKB_COMPOSE_COMPILE_NO_FLAGS); + self->_composeState = xkb_compose_state_new(self->_composeTable, XKB_COMPOSE_STATE_NO_FLAGS); + } static void kbEnter(void* data, wl_keyboard* kb, uint32_t serial, wl_surface* surface, wl_array *keys) { @@ -71,29 +79,70 @@ static void kbKey(void* data, wl_keyboard* kb, uint32_t serial, uint32_t time, const xkb_keysym_t *syms; uint32_t keyCode = key + 8; - if (xkb_state_key_get_syms(self->_state, keyCode, &syms) != 1) + if (xkb_state_key_get_syms(self->_state, keyCode, &syms) != 1) { + xkb_compose_state_feed(self->_composeState, XKB_KEY_NoSymbol); return; - auto lowerSym = xkb_keysym_to_lower(syms[0]); - jwm::Key jwmKey = KeyWayland::fromNative(lowerSym); - if (jwmKey != jwm::Key::UNDEFINED) { - jwm::KeyLocation location = jwm::KeyLocation::DEFAULT; - JNILocal keyEvent( - jwm::app.getJniEnv(), - classes::EventKey::make( - jwm::app.getJniEnv(), - jwmKey, - state == WL_KEYBOARD_KEY_STATE_PRESSED, - KeyWayland::getModifiers(self->_state), - location - ) - ); - self->_focus->dispatch(keyEvent.get()); } + auto sym = syms[0]; + auto lowerSym = xkb_keysym_to_lower(sym); + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) + xkb_compose_state_feed(self->_composeState, sym); + auto status = xkb_compose_state_get_status(self->_composeState); + bool composeRelated = status != XKB_COMPOSE_NOTHING; + jwm::Key jwmKey = KeyWayland::fromNative(lowerSym); self->_repeatingText = false; self->_repeating = false; + if (!composeRelated) { + if (jwmKey != jwm::Key::UNDEFINED) { + jwm::KeyLocation location = jwm::KeyLocation::DEFAULT; + JNILocal keyEvent( + jwm::app.getJniEnv(), + classes::EventKey::make( + jwm::app.getJniEnv(), + jwmKey, + state == WL_KEYBOARD_KEY_STATE_PRESSED, + KeyWayland::getModifiers(self->_state), + location + ) + ); + self->_focus->dispatch(keyEvent.get()); + } + } else { + int dacount; + switch (status) { + case XKB_COMPOSE_COMPOSING: + break; + case XKB_COMPOSE_COMPOSED: + // I am going to wager a guess that no one will ever have a compose key that binds to a + // key we actually parse. + // auto keysym = xkb_compose_state_get_one_sym(self->_composeState); + char textBuf[0x40]; + + dacount = xkb_compose_state_get_utf8(self->_composeState, textBuf, sizeof(textBuf) - 1); + + if (dacount > 0 && (dacount < sizeof(textBuf) - 1)) { + JNIEnv* env = jwm::app.getJniEnv(); + + jwm::StringUTF16 converted = reinterpret_cast(textBuf); + jwm::JNILocal jtext = converted.toJString(env); + + jwm::JNILocal eventTextInput(env, classes::EventTextInput::make(env, jtext.get())); + + + self->_focus->dispatch(eventTextInput.get()); + + } + + + xkb_compose_state_reset(self->_composeState); + break; + case XKB_COMPOSE_CANCELLED: + xkb_compose_state_reset(self->_composeState); + break; + } + return; + } if (state != WL_KEYBOARD_KEY_STATE_PRESSED) { - self->_lastPress = std::chrono::time_point(); - self->_nextRepeat = std::chrono::time_point(); return; } // ??? diff --git a/wayland/cc/Keyboard.hh b/wayland/cc/Keyboard.hh index 7b16522d..464259aa 100644 --- a/wayland/cc/Keyboard.hh +++ b/wayland/cc/Keyboard.hh @@ -2,6 +2,7 @@ #include #include +#include #include #include "KeyWayland.hh" #include "StringUTF16.hh" @@ -21,6 +22,9 @@ namespace jwm { xkb_context* _context = nullptr; xkb_state* _state = nullptr; xkb_keymap* _keymap = nullptr; + xkb_compose_table* _composeTable = nullptr; + xkb_compose_state* _composeState = nullptr; + xkb_state* getState() const { return _state; } From f6f8bd031fe7268a707476a21fff9c5360b76f3c Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Fri, 15 Dec 2023 19:28:23 -0500 Subject: [PATCH 39/93] keycodes, scaling --- wayland/cc/KeyWayland.cc | 254 ++++++++++++++++++----------------- wayland/cc/Keyboard.cc | 36 +++-- wayland/cc/LayerGLWayland.cc | 5 + wayland/cc/WindowWayland.cc | 16 +-- 4 files changed, 156 insertions(+), 155 deletions(-) diff --git a/wayland/cc/KeyWayland.cc b/wayland/cc/KeyWayland.cc index 9c21f662..14d3b95f 100644 --- a/wayland/cc/KeyWayland.cc +++ b/wayland/cc/KeyWayland.cc @@ -2,6 +2,7 @@ #include "KeyModifier.hh" #include #include +#include int jwm::KeyWayland::getModifiers(xkb_state* state) { @@ -29,140 +30,141 @@ int jwm::KeyWayland::getModifiersFromMask(int mask) { }*/ jwm::Key jwm::KeyWayland::fromNative(uint32_t v) { - switch (v) { + switch (v - 8) { // Modifiers - case XKB_KEY_Caps_Lock: return Key::CAPS_LOCK; - case XKB_KEY_Shift_R: - case XKB_KEY_Shift_L: return Key::SHIFT; - case XKB_KEY_Control_R: - case XKB_KEY_Control_L: return Key::CONTROL; - case XKB_KEY_Alt_R: - case XKB_KEY_Alt_L: return Key::ALT; + case KEY_CAPSLOCK: return Key::CAPS_LOCK; + case KEY_RIGHTSHIFT: + case KEY_LEFTSHIFT: return Key::SHIFT; + case KEY_RIGHTCTRL: + case KEY_LEFTCTRL: return Key::CONTROL; + case KEY_RIGHTALT: + case KEY_LEFTALT: return Key::ALT; // Key::WIN_LOGO - case XKB_KEY_Super_L: - case XKB_KEY_Super_R: return Key::LINUX_SUPER; - case XKB_KEY_Meta_L: - case XKB_KEY_Meta_R: return Key::LINUX_META; + case KEY_LEFTMETA: + case KEY_RIGHTMETA: return Key::LINUX_SUPER; + // prefer super over meta + // KEY::LINUX_META // Key::MAC_COMMAND // Key::MAC_OPTION // Key::MAC_FN // Rest of the keys - case XKB_KEY_Return: return Key::ENTER; - case XKB_KEY_BackSpace: return Key::BACKSPACE; - case XKB_KEY_Tab: return Key::TAB; - case XKB_KEY_Cancel: return Key::CANCEL; - case XKB_KEY_Clear: return Key::CLEAR; - case XKB_KEY_Pause: return Key::PAUSE; - case XKB_KEY_Escape: return Key::ESCAPE; - case XKB_KEY_space: return Key::SPACE; - case XKB_KEY_Page_Up: return Key::PAGE_UP; - case XKB_KEY_Page_Down: return Key::PAGE_DOWN; - case XKB_KEY_End: return Key::END; - case XKB_KEY_Home: return Key::HOME; - case XKB_KEY_Left: return Key::LEFT; - case XKB_KEY_Up: return Key::UP; - case XKB_KEY_Right: return Key::RIGHT; - case XKB_KEY_Down: return Key::DOWN; - case XKB_KEY_comma: return Key::COMMA; - case XKB_KEY_minus: return Key::MINUS; - case XKB_KEY_period: return Key::PERIOD; - case XKB_KEY_slash: return Key::SLASH; - case XKB_KEY_0: return Key::DIGIT0; - case XKB_KEY_1: return Key::DIGIT1; - case XKB_KEY_2: return Key::DIGIT2; - case XKB_KEY_3: return Key::DIGIT3; - case XKB_KEY_4: return Key::DIGIT4; - case XKB_KEY_5: return Key::DIGIT5; - case XKB_KEY_6: return Key::DIGIT6; - case XKB_KEY_7: return Key::DIGIT7; - case XKB_KEY_8: return Key::DIGIT8; - case XKB_KEY_9: return Key::DIGIT9; - case XKB_KEY_semicolon: return Key::SEMICOLON; - case XKB_KEY_equal: return Key::EQUALS; - case XKB_KEY_a: return Key::A; - case XKB_KEY_b: return Key::B; - case XKB_KEY_c: return Key::C; - case XKB_KEY_d: return Key::D; - case XKB_KEY_e: return Key::E; - case XKB_KEY_f: return Key::F; - case XKB_KEY_g: return Key::G; - case XKB_KEY_h: return Key::H; - case XKB_KEY_i: return Key::I; - case XKB_KEY_j: return Key::J; - case XKB_KEY_k: return Key::K; - case XKB_KEY_l: return Key::L; - case XKB_KEY_m: return Key::M; - case XKB_KEY_n: return Key::N; - case XKB_KEY_o: return Key::O; - case XKB_KEY_p: return Key::P; - case XKB_KEY_q: return Key::Q; - case XKB_KEY_r: return Key::R; - case XKB_KEY_s: return Key::S; - case XKB_KEY_t: return Key::T; - case XKB_KEY_u: return Key::U; - case XKB_KEY_v: return Key::V; - case XKB_KEY_w: return Key::W; - case XKB_KEY_x: return Key::X; - case XKB_KEY_y: return Key::Y; - case XKB_KEY_z: return Key::Z; - case XKB_KEY_bracketleft: return Key::OPEN_BRACKET; - case XKB_KEY_backslash: return Key::BACK_SLASH; - case XKB_KEY_bracketright: return Key::CLOSE_BRACKET; - case XKB_KEY_KP_0: return Key::DIGIT0; - case XKB_KEY_KP_1: return Key::DIGIT1; - case XKB_KEY_KP_2: return Key::DIGIT2; - case XKB_KEY_KP_3: return Key::DIGIT3; - case XKB_KEY_KP_4: return Key::DIGIT4; - case XKB_KEY_KP_5: return Key::DIGIT5; - case XKB_KEY_KP_6: return Key::DIGIT6; - case XKB_KEY_KP_7: return Key::DIGIT7; - case XKB_KEY_KP_8: return Key::DIGIT8; - case XKB_KEY_KP_9: return Key::DIGIT9; - case XKB_KEY_multiply: return Key::MULTIPLY; - case XKB_KEY_KP_Add: return Key::ADD; - case XKB_KEY_KP_Separator: return Key::SEPARATOR; - case XKB_KEY_KP_Subtract: return Key::MINUS; - case XKB_KEY_KP_Decimal: return Key::PERIOD; - case XKB_KEY_KP_Divide: return Key::SLASH; - case XKB_KEY_KP_Delete: return Key::DEL; - case XKB_KEY_Delete: return Key::DEL; - case XKB_KEY_Num_Lock: return Key::NUM_LOCK; - case XKB_KEY_Scroll_Lock: return Key::SCROLL_LOCK; - case XKB_KEY_F1: return Key::F1; - case XKB_KEY_F2: return Key::F2; - case XKB_KEY_F3: return Key::F3; - case XKB_KEY_F4: return Key::F4; - case XKB_KEY_F5: return Key::F5; - case XKB_KEY_F6: return Key::F6; - case XKB_KEY_F7: return Key::F7; - case XKB_KEY_F8: return Key::F8; - case XKB_KEY_F9: return Key::F9; - case XKB_KEY_F10: return Key::F10; - case XKB_KEY_F11: return Key::F11; - case XKB_KEY_F12: return Key::F12; - case XKB_KEY_F13: return Key::F13; - case XKB_KEY_F14: return Key::F14; - case XKB_KEY_F15: return Key::F15; - case XKB_KEY_F16: return Key::F16; - case XKB_KEY_F17: return Key::F17; - case XKB_KEY_F18: return Key::F18; - case XKB_KEY_F19: return Key::F19; - case XKB_KEY_F20: return Key::F20; - case XKB_KEY_F21: return Key::F21; - case XKB_KEY_F22: return Key::F22; - case XKB_KEY_F23: return Key::F23; - case XKB_KEY_F24: return Key::F24; - case XKB_KEY_Print: return Key::PRINTSCREEN; - case XKB_KEY_Insert: return Key::INSERT; - case XKB_KEY_Help: return Key::HELP; - case XKB_KEY_grave: return Key::BACK_QUOTE; - case XKB_KEY_quoteright: return Key::QUOTE; - case XKB_KEY_Menu: return Key::MENU; + case KEY_ENTER: return Key::ENTER; + case KEY_BACKSPACE: return Key::BACKSPACE; + case KEY_TAB: return Key::TAB; + case KEY_CANCEL: return Key::CANCEL; + case KEY_CLEAR: return Key::CLEAR; + case KEY_PAUSE: return Key::PAUSE; + case KEY_ESC: return Key::ESCAPE; + case KEY_SPACE: return Key::SPACE; + case KEY_PAGEUP: return Key::PAGE_UP; + case KEY_PAGEDOWN: return Key::PAGE_DOWN; + case KEY_END: return Key::END; + case KEY_HOME: return Key::HOME; + case KEY_LEFT: return Key::LEFT; + case KEY_UP: return Key::UP; + case KEY_RIGHT: return Key::RIGHT; + case KEY_DOWN: return Key::DOWN; + case KEY_COMMA: return Key::COMMA; + case KEY_MINUS: return Key::MINUS; + case KEY_DOT: return Key::PERIOD; + case KEY_SLASH: return Key::SLASH; + case KEY_0: return Key::DIGIT0; + case KEY_1: return Key::DIGIT1; + case KEY_2: return Key::DIGIT2; + case KEY_3: return Key::DIGIT3; + case KEY_4: return Key::DIGIT4; + case KEY_5: return Key::DIGIT5; + case KEY_6: return Key::DIGIT6; + case KEY_7: return Key::DIGIT7; + case KEY_8: return Key::DIGIT8; + case KEY_9: return Key::DIGIT9; + case KEY_SEMICOLON: return Key::SEMICOLON; + case KEY_EQUAL: return Key::EQUALS; + case KEY_A: return Key::A; + case KEY_B: return Key::B; + case KEY_C: return Key::C; + case KEY_D: return Key::D; + case KEY_E: return Key::E; + case KEY_F: return Key::F; + case KEY_G: return Key::G; + case KEY_H: return Key::H; + case KEY_I: return Key::I; + case KEY_J: return Key::J; + case KEY_K: return Key::K; + case KEY_L: return Key::L; + case KEY_M: return Key::M; + case KEY_N: return Key::N; + case KEY_O: return Key::O; + case KEY_P: return Key::P; + case KEY_Q: return Key::Q; + case KEY_R: return Key::R; + case KEY_S: return Key::S; + case KEY_T: return Key::T; + case KEY_U: return Key::U; + case KEY_V: return Key::V; + case KEY_W: return Key::W; + case KEY_X: return Key::X; + case KEY_Y: return Key::Y; + case KEY_Z: return Key::Z; + case KEY_LEFTBRACE: return Key::OPEN_BRACKET; + case KEY_BACKSLASH: return Key::BACK_SLASH; + case KEY_RIGHTBRACE: return Key::CLOSE_BRACKET; + case KEY_KP0: return Key::DIGIT0; + case KEY_KP1: return Key::DIGIT1; + case KEY_KP2: return Key::DIGIT2; + case KEY_KP3: return Key::DIGIT3; + case KEY_KP4: return Key::DIGIT4; + case KEY_KP5: return Key::DIGIT5; + case KEY_KP6: return Key::DIGIT6; + case KEY_KP7: return Key::DIGIT7; + case KEY_KP8: return Key::DIGIT8; + case KEY_KP9: return Key::DIGIT9; + case KEY_KPASTERISK: return Key::MULTIPLY; + case KEY_KPPLUS: return Key::ADD; + case KEY_KPCOMMA: return Key::SEPARATOR; + case KEY_KPMINUS: return Key::MINUS; + case KEY_KPDOT: return Key::PERIOD; + case KEY_KPSLASH: return Key::SLASH; + // no kp delete? + // case KEY_: return Key::DEL; + case KEY_DELETE: return Key::DEL; + case KEY_NUMLOCK: return Key::NUM_LOCK; + case KEY_SCROLLLOCK: return Key::SCROLL_LOCK; + case KEY_F1: return Key::F1; + case KEY_F2: return Key::F2; + case KEY_F3: return Key::F3; + case KEY_F4: return Key::F4; + case KEY_F5: return Key::F5; + case KEY_F6: return Key::F6; + case KEY_F7: return Key::F7; + case KEY_F8: return Key::F8; + case KEY_F9: return Key::F9; + case KEY_F10: return Key::F10; + case KEY_F11: return Key::F11; + case KEY_F12: return Key::F12; + case KEY_F13: return Key::F13; + case KEY_F14: return Key::F14; + case KEY_F15: return Key::F15; + case KEY_F16: return Key::F16; + case KEY_F17: return Key::F17; + case KEY_F18: return Key::F18; + case KEY_F19: return Key::F19; + case KEY_F20: return Key::F20; + case KEY_F21: return Key::F21; + case KEY_F22: return Key::F22; + case KEY_F23: return Key::F23; + case KEY_F24: return Key::F24; + case KEY_PRINT: return Key::PRINTSCREEN; + case KEY_INSERT: return Key::INSERT; + case KEY_HELP: return Key::HELP; + case KEY_GRAVE: return Key::BACK_QUOTE; + case KEY_APOSTROPHE: return Key::QUOTE; + case KEY_MENU: return Key::MENU; // Key::KANA - // Key::VOLUME_UP - // Key::VOLUME_DOWN - // Key::MUTE + case KEY_VOLUMEUP: return Key::VOLUME_UP; + case KEY_VOLUMEDOWN: return Key::VOLUME_DOWN; + case KEY_MUTE: return Key::MUTE; default: return Key::UNDEFINED; } } diff --git a/wayland/cc/Keyboard.cc b/wayland/cc/Keyboard.cc index 6fffc3e6..5f7f83a3 100644 --- a/wayland/cc/Keyboard.cc +++ b/wayland/cc/Keyboard.cc @@ -77,37 +77,35 @@ static void kbKey(void* data, wl_keyboard* kb, uint32_t serial, uint32_t time, if (!self->_state || !self->_focus) return; const xkb_keysym_t *syms; - uint32_t keyCode = key + 8; if (xkb_state_key_get_syms(self->_state, keyCode, &syms) != 1) { xkb_compose_state_feed(self->_composeState, XKB_KEY_NoSymbol); return; } auto sym = syms[0]; - auto lowerSym = xkb_keysym_to_lower(sym); if (state == WL_KEYBOARD_KEY_STATE_PRESSED) xkb_compose_state_feed(self->_composeState, sym); auto status = xkb_compose_state_get_status(self->_composeState); bool composeRelated = status != XKB_COMPOSE_NOTHING; - jwm::Key jwmKey = KeyWayland::fromNative(lowerSym); + // use raw key code + jwm::Key jwmKey = KeyWayland::fromNative(keyCode); self->_repeatingText = false; self->_repeating = false; - if (!composeRelated) { - if (jwmKey != jwm::Key::UNDEFINED) { - jwm::KeyLocation location = jwm::KeyLocation::DEFAULT; - JNILocal keyEvent( - jwm::app.getJniEnv(), - classes::EventKey::make( - jwm::app.getJniEnv(), - jwmKey, - state == WL_KEYBOARD_KEY_STATE_PRESSED, - KeyWayland::getModifiers(self->_state), - location - ) - ); - self->_focus->dispatch(keyEvent.get()); - } - } else { + if (jwmKey != jwm::Key::UNDEFINED) { + jwm::KeyLocation location = jwm::KeyLocation::DEFAULT; + JNILocal keyEvent( + jwm::app.getJniEnv(), + classes::EventKey::make( + jwm::app.getJniEnv(), + jwmKey, + state == WL_KEYBOARD_KEY_STATE_PRESSED, + KeyWayland::getModifiers(self->_state), + location + ) + ); + self->_focus->dispatch(keyEvent.get()); + } + if (composeRelated) { int dacount; switch (status) { case XKB_COMPOSE_COMPOSING: diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index db458347..89328c21 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -99,6 +99,11 @@ namespace jwm { // God is dead if _eglWindow is null if (_eglWindow) wl_egl_window_resize(_eglWindow, width, height, 0, 0); + + if (fWindow->_scale != fWindow->_oldScale) { + swapBuffers(); + wl_surface_set_buffer_scale(fWindow->_waylandWindow, fWindow->_scale); + } } void swapBuffers() override { diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index 5e451a70..a067e383 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -284,7 +284,6 @@ void jwm::WindowWayland::surfaceEnter(void* data, wl_surface* surface, wl_output if (o->_output == output) { self->_output = o; self->_scale = o->scale; - wl_surface_set_buffer_scale(surface, o->scale); self->_adaptSize(self->getUnscaledWidth(), self->getUnscaledHeight()); break; } @@ -299,7 +298,6 @@ void jwm::WindowWayland::surfacePreferredBufferScale(void* data, wl_surface* sur self->_scale = factor; // do I pinky promise here? // yes : ) - wl_surface_set_buffer_scale(surface, factor); self->_adaptSize(self->getUnscaledWidth(), self->getUnscaledHeight()); } void jwm::WindowWayland::surfacePreferredBufferTransform(void* data, wl_surface* surface, uint32_t transform) {} @@ -378,12 +376,8 @@ void jwm::WindowWayland::decorFrameConfigure(libdecor_frame* frame, libdecor_con } - self->_newWidth = width; - self->_newHeight = height; + self->_adaptSize(width, height); // This flat out breaks window if it isn't throttled - wl_callback* callback = wl_surface_frame(self->_waylandWindow); - // Throttle frame - wl_callback_add_listener(callback, &_frameCallback, self); } if (!self->_configured && self->_visible) { if (self->_layer) @@ -420,12 +414,14 @@ void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { ) ); dispatch(eventWindowResize.get()); - if (_scale != _oldScale) - _makeCursors(); - _oldScale = _scale; + if (_scale != _oldScale) { + _makeCursors(); + _windowManager._processCallbacks(); + } // In Java Wayland doesn't actually cause a frame: // however decorFrameCommit will cause a redraw anyway. // Not doing it in wayland lets me not cause an exception on hide. + _oldScale = _scale; } // JNI From 22fd80a8ffedda5bbf5fc5f05d28232888a4f2f7 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Sun, 17 Dec 2023 11:39:27 -0500 Subject: [PATCH 40/93] Bump Skija version --- script/common.py | 2 +- script/run.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/script/common.py b/script/common.py index 36a5f31a..5e8bd9fd 100644 --- a/script/common.py +++ b/script/common.py @@ -8,7 +8,7 @@ def deps_compile(): parser = argparse.ArgumentParser() parser.add_argument('--skija-dir', default=None) parser.add_argument('--skija-shared-jar', default=None) - parser.add_argument('--skija-version', default='0.116.1') + parser.add_argument('--skija-version', default='0.116.2') (args, _) = parser.parse_known_args() deps = [ diff --git a/script/run.py b/script/run.py index 4ba67860..64c201c2 100755 --- a/script/run.py +++ b/script/run.py @@ -5,7 +5,7 @@ def main(): parser = argparse.ArgumentParser() parser.add_argument('--example', default='dashboard') parser.add_argument('--jwm-version', default=None) - parser.add_argument('--skija-version', default='0.116.1') + parser.add_argument('--skija-version', default='0.116.2') parser.add_argument('--skija-dir', default=None) parser.add_argument('--skija-shared-jar', default=None) parser.add_argument('--skija-platform-jar', default=None) From 20a7a871bceed8d6333fc55090a82035ffb1fc78 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Sun, 17 Dec 2023 14:06:31 -0500 Subject: [PATCH 41/93] Repeat now not laggy (on GL) --- wayland/cc/Keyboard.cc | 58 +++++++++++++----- wayland/cc/Keyboard.hh | 6 ++ wayland/cc/WindowManagerWayland.cc | 94 +++++++++++++++++------------- wayland/cc/WindowManagerWayland.hh | 1 + 4 files changed, 104 insertions(+), 55 deletions(-) diff --git a/wayland/cc/Keyboard.cc b/wayland/cc/Keyboard.cc index 5f7f83a3..cf7708b2 100644 --- a/wayland/cc/Keyboard.cc +++ b/wayland/cc/Keyboard.cc @@ -13,6 +13,9 @@ #include "AppWayland.hh" #include #include +#include +#include + using namespace jwm; // I've noticed that pointers to lambdas are null for some reason. @@ -63,11 +66,24 @@ static void kbEnter(void* data, wl_keyboard* kb, uint32_t serial, wl_surface* su self->_serial = serial; self->_focus = win; if (self->_state) { - // TODO: keys + uint32_t* key; + // C++ jank + // Normal macro fails to compile bc `void*` can't implicitly convert into `uint32_t*` + for (key = (uint32_t*)keys->data; + (const char*) key < (const char*)keys->data + keys->size; + key++ + ) { + auto jwmKey = jwm::KeyWayland::fromNative(*key + 8); + self->submitKey(jwmKey, WL_KEYBOARD_KEY_STATE_PRESSED); + } } } static void kbLeave(void* data, wl_keyboard* kb, uint32_t serial, wl_surface* surface) { auto self = reinterpret_cast(data); + std::list liftedKeys(self->_depressedKeys); + for (auto key : liftedKeys) { + self->submitKey(key, WL_KEYBOARD_KEY_STATE_RELEASED); + } self->_serial = -1; self->_focus = nullptr; } @@ -91,20 +107,7 @@ static void kbKey(void* data, wl_keyboard* kb, uint32_t serial, uint32_t time, jwm::Key jwmKey = KeyWayland::fromNative(keyCode); self->_repeatingText = false; self->_repeating = false; - if (jwmKey != jwm::Key::UNDEFINED) { - jwm::KeyLocation location = jwm::KeyLocation::DEFAULT; - JNILocal keyEvent( - jwm::app.getJniEnv(), - classes::EventKey::make( - jwm::app.getJniEnv(), - jwmKey, - state == WL_KEYBOARD_KEY_STATE_PRESSED, - KeyWayland::getModifiers(self->_state), - location - ) - ); - self->_focus->dispatch(keyEvent.get()); - } + self->submitKey(jwmKey, state); if (composeRelated) { int dacount; switch (status) { @@ -215,3 +218,28 @@ Keyboard::~Keyboard() if (_keymap) xkb_keymap_unref(_keymap); } + +void Keyboard::submitKey(jwm::Key key, uint32_t state) { + if (key != jwm::Key::UNDEFINED) { + jwm::KeyLocation location = jwm::KeyLocation::DEFAULT; + JNILocal keyEvent( + jwm::app.getJniEnv(), + classes::EventKey::make( + jwm::app.getJniEnv(), + key, + state == WL_KEYBOARD_KEY_STATE_PRESSED, + KeyWayland::getModifiers(_state), + location + ) + ); + _focus->dispatch(keyEvent.get()); + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { + _depressedKeys.push_back(key); + } else { + auto it = std::find(_depressedKeys.begin(), _depressedKeys.end(), key); + if (it != _depressedKeys.end()) { + _depressedKeys.erase(it); + } + } + } +} diff --git a/wayland/cc/Keyboard.hh b/wayland/cc/Keyboard.hh index 464259aa..c4ad891b 100644 --- a/wayland/cc/Keyboard.hh +++ b/wayland/cc/Keyboard.hh @@ -6,6 +6,7 @@ #include #include "KeyWayland.hh" #include "StringUTF16.hh" +#include namespace jwm { class WindowManagerWayland; @@ -41,11 +42,16 @@ namespace jwm { int32_t _repeatRate = 100; int32_t _repeatDelay = 300; + void submitKey(jwm::Key key, uint32_t state); + + jwm::StringUTF16 _repeatText; jwm::Key _repeatKey = jwm::Key::UNDEFINED; bool _repeating = false; bool _repeatingText = false; + std::list _depressedKeys; + jwm::WindowManagerWayland& _wm; static wl_keyboard_listener _keyboardListener; diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 145881db..cf2972b2 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -132,7 +132,7 @@ void WindowManagerWayland::runLoop() { _runLoop = false; // block until event : ) int timeout = -1; - if (_keyboard && _keyboard->_repeating) { + if (_keyboard && _keyboard->_repeating && _keyboard->getFocus()) { if (_keyboard->_repeatRate > 0) { auto now = std::chrono::steady_clock::now(); auto target = _keyboard->_nextRepeat; @@ -145,13 +145,20 @@ void WindowManagerWayland::runLoop() { printf("error with pipe\n"); break; } + if (ps[0].revents & POLLIN) { libdecor_dispatch(decorCtx, -1); } - _processCallbacks(); + if (ps[1].revents & POLLIN) { while (read(pipes[0], buf, sizeof(buf)) == sizeof(buf)) { } } + if (ps[0].revents & POLLIN || ps[1].revents & POLLIN) { + _processCallbacks(); + } else { + // don't test if we already calculated earlier + _processKeyboard(); + } notifyBool.store(false); } @@ -180,44 +187,6 @@ void WindowManagerWayland::_processCallbacks() { lock.lock(); } } - if (_keyboard && _keyboard->_repeating && _keyboard->getFocus()) { - auto now = std::chrono::steady_clock::now(); - if (now > _keyboard->_nextRepeat) { - _keyboard->_nextRepeat = now + std::chrono::milliseconds(_keyboard->_repeatRate); - auto focus = _keyboard->getFocus(); - auto env = jwm::app.getJniEnv(); - jwm::KeyLocation location = jwm::KeyLocation::DEFAULT; - JNILocal keyOffEvent( - env, - classes::EventKey::make( - env, - _keyboard->_repeatKey, - false, - KeyWayland::getModifiers(_keyboard->_state), - location - ) - ); - - JNILocal keyEvent( - env, - classes::EventKey::make( - env, - _keyboard->_repeatKey, - true, - KeyWayland::getModifiers(_keyboard->_state), - location - ) - ); - focus->dispatch(keyOffEvent.get()); - focus->dispatch(keyEvent.get()); - if (_keyboard->_repeatingText) { - jwm::JNILocal jtext = _keyboard->_repeatText.toJString(env); - jwm::JNILocal eventTextInput(env, classes::EventTextInput::make(env, jtext.get())); - - focus->dispatch(eventTextInput.get()); - } - } - } { // copy window list in case one closes any other, invalidating some iterator in _nativeWindowToMy std::vector copy; @@ -237,6 +206,51 @@ void WindowManagerWayland::_processCallbacks() { } } } + if (_keyboard && _keyboard->_repeating) { + auto now = std::chrono::steady_clock::now(); + if (now > _keyboard->_nextRepeat) + _processKeyboard(); + } + +} +void WindowManagerWayland::_processKeyboard() { + if (_keyboard && _keyboard->_repeating && _keyboard->getFocus()) { + auto now = std::chrono::steady_clock::now(); + _keyboard->_nextRepeat = now + std::chrono::milliseconds(_keyboard->_repeatRate); + auto focus = _keyboard->getFocus(); + auto env = jwm::app.getJniEnv(); + jwm::KeyLocation location = jwm::KeyLocation::DEFAULT; + JNILocal keyOffEvent( + env, + classes::EventKey::make( + env, + _keyboard->_repeatKey, + false, + KeyWayland::getModifiers(_keyboard->_state), + location + ) + ); + + JNILocal keyEvent( + env, + classes::EventKey::make( + env, + _keyboard->_repeatKey, + true, + KeyWayland::getModifiers(_keyboard->_state), + location + ) + ); + focus->dispatch(keyOffEvent.get()); + focus->dispatch(keyEvent.get()); + if (_keyboard->_repeatingText) { + jwm::JNILocal jtext = _keyboard->_repeatText.toJString(env); + jwm::JNILocal eventTextInput(env, classes::EventTextInput::make(env, jtext.get())); + + focus->dispatch(eventTextInput.get()); + } + } + } void WindowManagerWayland::registryHandleGlobal(void* data, wl_registry *registry, diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index e6547f85..7138f8c2 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -54,6 +54,7 @@ namespace jwm { } */ void _processCallbacks(); + void _processKeyboard(); void notifyLoop(); void enqueueTask(const std::function& task); From 5a5d611b27655cc6693e60b7517528e22e23a933 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Sun, 17 Dec 2023 14:49:08 -0500 Subject: [PATCH 42/93] nudge keyboard repeat --- wayland/cc/Keyboard.cc | 2 +- wayland/cc/WindowManagerWayland.cc | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/wayland/cc/Keyboard.cc b/wayland/cc/Keyboard.cc index cf7708b2..b2dc1a74 100644 --- a/wayland/cc/Keyboard.cc +++ b/wayland/cc/Keyboard.cc @@ -153,8 +153,8 @@ static void kbKey(void* data, wl_keyboard* kb, uint32_t serial, uint32_t time, if (shouldRepeat && (jwmKey != jwm::Key::UNDEFINED)) { self->_repeating = true; self->_nextRepeat = self->_lastPress + std::chrono::milliseconds(self->_repeatDelay); + self->_wm.notifyLoop(); } - self->_wm.notifyLoop(); char textBuffer[0x40]; int count = xkb_state_key_get_utf8(self->_state, keyCode, textBuffer, sizeof(textBuffer)-1); // ??? diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index cf2972b2..fe8ccfff 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -138,6 +138,8 @@ void WindowManagerWayland::runLoop() { auto target = _keyboard->_nextRepeat; if (now < target) { timeout = std::chrono::duration_cast(target - now).count(); + } else { + _processKeyboard(); } } } @@ -206,11 +208,6 @@ void WindowManagerWayland::_processCallbacks() { } } } - if (_keyboard && _keyboard->_repeating) { - auto now = std::chrono::steady_clock::now(); - if (now > _keyboard->_nextRepeat) - _processKeyboard(); - } } void WindowManagerWayland::_processKeyboard() { @@ -305,8 +302,7 @@ void WindowManagerWayland::pointerHandleEnter(void* data, wl_pointer* pointer, u wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { WindowManagerWayland* self = (WindowManagerWayland*)data; self->mouseSerial = serial; - if (self->getWindowForNative(surface)) { - WindowWayland* window = self->getWindowForNative(surface); + if (auto window = self->getWindowForNative(surface)) { window->setCursor(jwm::MouseCursor::ARROW); self->focusedSurface = surface; } From 9eabca1afcc4c2b779ff0bb50364e677db259a44 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Sun, 17 Dec 2023 15:35:17 -0500 Subject: [PATCH 43/93] don't commit on detach --- wayland/cc/LayerGLWayland.cc | 1 + wayland/cc/LayerRasterWayland.cc | 3 ++- wayland/cc/WindowWayland.cc | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index 89328c21..71a1bc57 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -33,6 +33,7 @@ namespace jwm { _closed = false; fWindow = jwm::ref(window); fWindow->setLayer(this); + // Force a reconfigure; needed to draw title bar correctly if (fWindow->_windowManager._eglDisplay == EGL_NO_DISPLAY) { fWindow->_windowManager._eglDisplay = eglGetDisplay(window->_windowManager.display); diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index 9993b387..cd2aea11 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -83,7 +83,8 @@ namespace jwm { void detach() override { if (_attached && fWindow && fWindow->_waylandWindow) { wl_surface_attach(fWindow->_waylandWindow, nullptr, 0, 0); - wl_surface_commit(fWindow->_waylandWindow); + // commit is not meant to be used in intermediate states + // wl_surface_commit(fWindow->_waylandWindow); } _attached = false; } diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index a067e383..acf80383 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -377,7 +377,6 @@ void jwm::WindowWayland::decorFrameConfigure(libdecor_frame* frame, libdecor_con self->_adaptSize(width, height); - // This flat out breaks window if it isn't throttled } if (!self->_configured && self->_visible) { if (self->_layer) From acc730d0a4a5426d2b4c8d162c2b77794b35a9c1 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Sun, 17 Dec 2023 17:19:58 -0500 Subject: [PATCH 44/93] fix clipboard? --- examples/dashboard/java/PanelTextInput.java | 2 +- shared/java/ClipboardEntry.java | 6 +-- wayland/cc/ClipboardWayland.cc | 6 +-- wayland/cc/WindowManagerWayland.cc | 50 +++++++++++---------- wayland/cc/WindowManagerWayland.hh | 1 + 5 files changed, 33 insertions(+), 32 deletions(-) diff --git a/examples/dashboard/java/PanelTextInput.java b/examples/dashboard/java/PanelTextInput.java index 9d55a522..04eff63b 100644 --- a/examples/dashboard/java/PanelTextInput.java +++ b/examples/dashboard/java/PanelTextInput.java @@ -232,4 +232,4 @@ public String getSubstring(int start, int end) { int end2 = Math.min(end, start2); return text.substring(start2, end2); } -} \ No newline at end of file +} diff --git a/shared/java/ClipboardEntry.java b/shared/java/ClipboardEntry.java index 6b1b0ddb..97b7f2ed 100644 --- a/shared/java/ClipboardEntry.java +++ b/shared/java/ClipboardEntry.java @@ -62,7 +62,7 @@ public static ClipboardEntry makeRTF(String text) { */ @NotNull @SneakyThrows public static ClipboardEntry makeString(ClipboardFormat format, String text) { - if (Platform.CURRENT == Platform.X11 || Platform.CURRENT == Platform.MACOS) { + if (Platform.CURRENT == Platform.X11 || Platform.CURRENT == Platform.MACOS || Platform.CURRENT == Platform.WAYLAND) { return make(format, text.getBytes("UTF-8")); } return make(format, text.getBytes("UTF-16LE")); @@ -76,9 +76,9 @@ public static ClipboardEntry makeString(ClipboardFormat format, String text) { */ @NotNull @SneakyThrows public String getString() { - if (Platform.CURRENT == Platform.X11 || Platform.CURRENT == Platform.MACOS) { + if (Platform.CURRENT == Platform.X11 || Platform.CURRENT == Platform.MACOS || Platform.CURRENT == Platform.WAYLAND) { return new String(_data, "UTF-8"); } return new String(_data, "UTF-16LE"); } -} \ No newline at end of file +} diff --git a/wayland/cc/ClipboardWayland.cc b/wayland/cc/ClipboardWayland.cc index 92ca029f..9b325eea 100644 --- a/wayland/cc/ClipboardWayland.cc +++ b/wayland/cc/ClipboardWayland.cc @@ -44,11 +44,11 @@ namespace jwm { ByteBuf contents; // HACK: prefer UTF8_STRING over text/plain and convert it to utf16 - /* if (formatId == "text/plain") { contents = app.getWindowManager().getClipboardContents("UTF8_STRING"); + } else { + contents = app.getWindowManager().getClipboardContents(formatId.toAscii()); } - */ // TODO add another formats if (contents.empty()) { return nullptr; @@ -70,7 +70,6 @@ namespace jwm { void set(JNIEnv* env, jobjectArray entries) { - /* jsize size = env->GetArrayLength(entries); std::map contents; for (jsize i = 0; i < size; ++i) { @@ -94,7 +93,6 @@ namespace jwm { } } jwm::app.getWindowManager().setClipboardContents(std::move(contents)); - */ // impl me : ) } }; } diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index fe8ccfff..ba3c9ac1 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -460,30 +460,8 @@ static void deviceDataOffer(void* data, wl_data_device* device, wl_data_offer* o static void deviceSelection(void* data, wl_data_device* device, wl_data_offer* offer) { auto self = reinterpret_cast(data); self->_myClipboardContents = {}; - if (offer == nullptr) { - return; - } - for (auto i : self->_currentMimeTypes) { - int fds[2]; - pipe(fds); - wl_data_offer_receive(offer, i.c_str(), fds[1]); - wl_display_flush(self->display); - close(fds[1]); - ByteBuf res; - - - while (true) { - char buf[1024]; - ssize_t n = read(fds[0], buf, sizeof(buf)); - if (n <= 0) - break; - res.insert(res.end(), buf, buf + n); - - } - self->_myClipboardContents[i] = res; - close(fds[0]); - } - wl_data_offer_destroy(offer); + // if null then w/e + self->currentOffer = offer; } wl_data_device_listener WindowManagerWayland::_deviceListener = { .data_offer = deviceDataOffer, @@ -521,6 +499,30 @@ jwm::ByteBuf WindowManagerWayland::getClipboardContents(const std::string& type) auto it = _myClipboardContents.find(type); if (it != _myClipboardContents.end()) { return it->second; + } else if (currentOffer) { + auto it2 = std::find(_currentMimeTypes.begin(), _currentMimeTypes.end(), type); + if (it2 != _currentMimeTypes.end()) { + auto mimeType = *it2; + // pull down offer + int fds[2]; + pipe(fds); + wl_data_offer_receive(currentOffer, mimeType.c_str(), fds[1]); + wl_display_flush(display); + close(fds[1]); + ByteBuf res; + + while (true) { + char buf[1024]; + ssize_t n = read(fds[0], buf, sizeof(buf)); + if (n <= 0) + break; + res.insert(res.end(), buf, buf + n); + } + // cache + _myClipboardContents[mimeType] = res; + close(fds[0]); + return res; + } } return {}; } diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index 7138f8c2..cfac150b 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -108,6 +108,7 @@ namespace jwm { Keyboard* _keyboard = nullptr; wl_data_device* dataDevice = nullptr; wl_data_source* currentSource = nullptr; + wl_data_offer* currentOffer = nullptr; uint32_t mouseSerial = 0; uint32_t getKeyboardSerial() const { if (_keyboard) From 7a6f95b248f89d8aae476f0627d7a622b0928377 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Sun, 17 Dec 2023 20:20:22 -0500 Subject: [PATCH 45/93] clipboard sauce --- wayland/cc/LayerGLWayland.cc | 2 +- wayland/cc/WindowManagerWayland.cc | 27 ++++++++++++++++----------- wayland/cc/WindowManagerWayland.hh | 1 + 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index 71a1bc57..7e577e79 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -76,7 +76,6 @@ namespace jwm { } // Don't block on swap // Blocking here will freeze the app on sway. - eglSwapInterval(_display, 0); } if (fWindow->_configured) attachBuffer(); @@ -129,6 +128,7 @@ namespace jwm { _surface, _surface, _context); + eglSwapInterval(_display, 0); } void attachBuffer() override { if (fWindow && fWindow->_waylandWindow) { diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index ba3c9ac1..789eeca2 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -126,10 +126,12 @@ void WindowManagerWayland::runLoop() { {.fd=libdecor_get_fd(decorCtx), .events=POLLIN}, {.fd=pipes[0], .events=POLLIN}, }; + // who be out here running they loop while (_runLoop) { if (jwm::classes::Throwable::exceptionThrown(app.getJniEnv())) _runLoop = false; + // block until event : ) int timeout = -1; if (_keyboard && _keyboard->_repeating && _keyboard->getFocus()) { @@ -147,9 +149,11 @@ void WindowManagerWayland::runLoop() { printf("error with pipe\n"); break; } - if (ps[0].revents & POLLIN) { - libdecor_dispatch(decorCtx, -1); + if (libdecor_dispatch(decorCtx, -1) < 0) { + fprintf(stderr, "error with dispatch\n"); + break; + } } if (ps[1].revents & POLLIN) { @@ -180,14 +184,13 @@ void WindowManagerWayland::_processCallbacks() { { // process ui thread callbacks std::unique_lock lock(_taskQueueLock); - while (!_taskQueue.empty()) { auto callback = std::move(_taskQueue.front()); _taskQueue.pop(); lock.unlock(); callback(); lock.lock(); - } + } } { // copy window list in case one closes any other, invalidating some iterator in _nativeWindowToMy @@ -459,7 +462,6 @@ static void deviceDataOffer(void* data, wl_data_device* device, wl_data_offer* o } static void deviceSelection(void* data, wl_data_device* device, wl_data_offer* offer) { auto self = reinterpret_cast(data); - self->_myClipboardContents = {}; // if null then w/e self->currentOffer = offer; } @@ -544,8 +546,9 @@ void WindowManagerWayland::terminate() { static void dataSourceSend(void* data, wl_data_source* source, const char* mimeType, int fd) { auto self = reinterpret_cast(data); - auto it = self->_myClipboardContents.find(std::string(mimeType)); - if (it != self->_myClipboardContents.end()) { + auto it = self->_myClipboardSource.find(std::string(mimeType)); + + if (it != self->_myClipboardSource.end()) { write(fd, it->second.data(), it->second.size()); } close(fd); @@ -553,6 +556,8 @@ static void dataSourceSend(void* data, wl_data_source* source, const char* mimeT static void dataSourceCancelled(void* data, wl_data_source* source) { auto self = reinterpret_cast(data); wl_data_source_destroy(source); + self->currentSource = nullptr; + self->_myClipboardSource = {}; } wl_data_source_listener WindowManagerWayland::_sourceListener = { .send = dataSourceSend, @@ -560,10 +565,10 @@ wl_data_source_listener WindowManagerWayland::_sourceListener = { }; void WindowManagerWayland::setClipboardContents(std::map&& c) { assert(("create at least one window in order to use clipboard" && !_nativeWindowToMy.empty())); - _myClipboardContents = c; + _myClipboardSource = c; + + if (!deviceManager) return; - // god is dead if data device manager is null - currentSource = wl_data_device_manager_create_data_source(deviceManager); wl_data_source_add_listener(currentSource, &_sourceListener, this); @@ -573,7 +578,7 @@ void WindowManagerWayland::setClipboardContents(std::map&& _currentMimeTypes.push_back(it.first.c_str()); wl_data_source_offer(currentSource, it.first.c_str()); } - + if (getKeyboardSerial() > 0) wl_data_device_set_selection(dataDevice, currentSource, getKeyboardSerial()); diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index cfac150b..0f8e9e41 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -137,6 +137,7 @@ namespace jwm { std::map _nativeWindowToMy; std::map _myClipboardContents; + std::map _myClipboardSource; std::list _currentMimeTypes; From 291adf3c88e00e0434f2b8217c6a77c28c9d7a04 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Mon, 18 Dec 2023 11:26:11 -0500 Subject: [PATCH 46/93] Self clipboard pasting --- wayland/cc/ClipboardWayland.cc | 11 ++++------- wayland/cc/WindowManagerWayland.cc | 8 +++++++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/wayland/cc/ClipboardWayland.cc b/wayland/cc/ClipboardWayland.cc index 9b325eea..25ff41a1 100644 --- a/wayland/cc/ClipboardWayland.cc +++ b/wayland/cc/ClipboardWayland.cc @@ -43,13 +43,10 @@ namespace jwm { ByteBuf contents; - // HACK: prefer UTF8_STRING over text/plain and convert it to utf16 - if (formatId == "text/plain") { - contents = app.getWindowManager().getClipboardContents("UTF8_STRING"); - } else { - contents = app.getWindowManager().getClipboardContents(formatId.toAscii()); - } - // TODO add another formats + // text will ALWAYS be utf8 if we are getting plain text. + // If you are outputting utf16 into something that other apps read from, + // you are going to hell. + contents = app.getWindowManager().getClipboardContents(formatId.toAscii()); if (contents.empty()) { return nullptr; } diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 789eeca2..66c6f33e 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -501,6 +501,13 @@ jwm::ByteBuf WindowManagerWayland::getClipboardContents(const std::string& type) auto it = _myClipboardContents.find(type); if (it != _myClipboardContents.end()) { return it->second; + } else if (currentSource) { + // Self paste + auto it2 = _myClipboardSource.find(type); + if (it2 != _myClipboardSource.end()) { + _myClipboardContents[type] = it2->second; + return it2->second; + } } else if (currentOffer) { auto it2 = std::find(_currentMimeTypes.begin(), _currentMimeTypes.end(), type); if (it2 != _currentMimeTypes.end()) { @@ -547,7 +554,6 @@ void WindowManagerWayland::terminate() { static void dataSourceSend(void* data, wl_data_source* source, const char* mimeType, int fd) { auto self = reinterpret_cast(data); auto it = self->_myClipboardSource.find(std::string(mimeType)); - if (it != self->_myClipboardSource.end()) { write(fd, it->second.data(), it->second.size()); } From bc0bd2cc3163474ee10d13d6d82e7d010db62826 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Mon, 18 Dec 2023 11:34:47 -0500 Subject: [PATCH 47/93] change focus access to method --- wayland/cc/WindowManagerWayland.cc | 63 +++++++++++++----------------- wayland/cc/WindowManagerWayland.hh | 9 ++++- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 66c6f33e..4922ff1f 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -33,28 +33,26 @@ wl_registry_listener WindowManagerWayland::_registryListener = { }; static void pointerFrame(void* data, wl_pointer* pointer) { auto self = reinterpret_cast(data); - if (!self->focusedSurface) return; + if (!self->getFocusedSurface()) return; if (self->_dX != 0.0f || self->_dY != 0.0f) { auto env = app.getJniEnv(); - auto win = self->getWindowForNative(self->focusedSurface); - if (win) { - jwm::JNILocal eventAxis( - env, - jwm::classes::EventMouseScroll::make( - env, - self->_dX * win->_scale, - self->_dY * win->_scale, - 0.0f, - 0.0f, - 0.0f, - self->lastMousePosX, - self->lastMousePosY, - jwm::KeyWayland::getModifiers(self->getXkbState()) - ) - ); - win->dispatch(eventAxis.get()); + auto win = self->getFocusedSurface(); + jwm::JNILocal eventAxis( + env, + jwm::classes::EventMouseScroll::make( + env, + self->_dX * win->_scale, + self->_dY * win->_scale, + 0.0f, + 0.0f, + 0.0f, + self->lastMousePosX, + self->lastMousePosY, + jwm::KeyWayland::getModifiers(self->getXkbState()) + ) + ); + win->dispatch(eventAxis.get()); - } self->_dX = 0.0f; self->_dY = 0.0f; } @@ -307,13 +305,13 @@ void WindowManagerWayland::pointerHandleEnter(void* data, wl_pointer* pointer, u self->mouseSerial = serial; if (auto window = self->getWindowForNative(surface)) { window->setCursor(jwm::MouseCursor::ARROW); - self->focusedSurface = surface; + self->setFocusedSurface(window); } } void WindowManagerWayland::pointerHandleLeave(void* data, wl_pointer* pointer, uint32_t serial, wl_surface *surface) { WindowManagerWayland* self = (WindowManagerWayland*)data; - self->focusedSurface = nullptr; + self->setFocusedSurface(nullptr); // ??? self->mouseMask = 0; self->mouseSerial = -1; @@ -321,8 +319,8 @@ void WindowManagerWayland::pointerHandleLeave(void* data, wl_pointer* pointer, u void WindowManagerWayland::pointerHandleMotion(void* data, wl_pointer* pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { WindowManagerWayland* self = (WindowManagerWayland*)data; - if (self->focusedSurface) { - ::WindowWayland* window = self->getWindowForNative(self->focusedSurface); + if (self->getFocusedSurface()) { + ::WindowWayland* window = self->getFocusedSurface(); // God is dead if window is null if (window) self->mouseUpdate(window, @@ -335,7 +333,8 @@ void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { using namespace classes; WindowManagerWayland* self = (WindowManagerWayland*)data; - if (!self->focusedSurface) return; + if (!self->getFocusedSurface()) return; + auto window = self->getFocusedSurface(); if (state == 0) { // release switch (button) { @@ -355,7 +354,7 @@ void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, break; } - if (MouseButtonWayland::isButton(button) && self->focusedSurface) { + if (MouseButtonWayland::isButton(button)) { jwm::JNILocal eventButton( app.getJniEnv(), EventMouseButton::make( @@ -367,9 +366,7 @@ void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, jwm::KeyWayland::getModifiers(self->getXkbState()) ) ); - WindowWayland* window = self->getWindowForNative(self->focusedSurface); - if (window) - window->dispatch(eventButton.get()); + window->dispatch(eventButton.get()); } } else { // down @@ -390,7 +387,7 @@ void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, break; } - if (MouseButtonWayland::isButton(button) && self->focusedSurface) { + if (MouseButtonWayland::isButton(button)) { jwm::JNILocal eventButton( app.getJniEnv(), EventMouseButton::make( @@ -402,18 +399,14 @@ void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, jwm::KeyWayland::getModifiers(self->getXkbState()) ) ); - // me when this stuff is NULL : ( - WindowWayland* window = self->getWindowForNative(self->focusedSurface); - if (window) - window->dispatch(eventButton.get()); + window->dispatch(eventButton.get()); } } } void WindowManagerWayland::pointerHandleAxis(void* data, wl_pointer* pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { auto self = reinterpret_cast(data); - if (!self->focusedSurface) return; - + if (!self->getFocusedSurface()) return; switch (axis) { case WL_POINTER_AXIS_VERTICAL_SCROLL: self->_dY += static_cast(wl_fixed_to_double(value)); diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index 0f8e9e41..a594ddd2 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -124,6 +124,7 @@ namespace jwm { EGLDisplay _eglDisplay = EGL_NO_DISPLAY; std::list outputs; + wl_cursor* currentCursor = nullptr; bool _runLoop; int notifyFD = -1; std::atomic_bool notifyBool{false}; @@ -142,7 +143,13 @@ namespace jwm { wl_surface* cursorSurface; - wl_surface* focusedSurface = nullptr; + WindowWayland* _focusedSurface = nullptr; + WindowWayland* getFocusedSurface() const { + return _focusedSurface; + } + void setFocusedSurface(WindowWayland* surface) { + _focusedSurface = surface; + } // Is holding all cursors in memory a good idea? wl_cursor_image* _cursors[static_cast(jwm::MouseCursor::COUNT)]; From 78ab64faf1a9bd8b58ff4d3052fe5c4dd09f24db Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Mon, 18 Dec 2023 12:58:03 -0500 Subject: [PATCH 48/93] yank out pointer into class --- wayland/cc/Pointer.cc | 226 +++++++++++++++++++++++++++++ wayland/cc/Pointer.hh | 49 +++++++ wayland/cc/WindowManagerWayland.cc | 197 +------------------------ wayland/cc/WindowManagerWayland.hh | 50 +++---- wayland/cc/WindowWayland.cc | 13 +- 5 files changed, 304 insertions(+), 231 deletions(-) create mode 100644 wayland/cc/Pointer.cc create mode 100644 wayland/cc/Pointer.hh diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc new file mode 100644 index 00000000..06c242c3 --- /dev/null +++ b/wayland/cc/Pointer.cc @@ -0,0 +1,226 @@ +#include "Pointer.hh" +#include "WindowManagerWayland.hh" +#include "WindowWayland.hh" +#include "MouseButtonWayland.hh" +#include "AppWayland.hh" +#include "KeyWayland.hh" +#include +#include +using namespace jwm; + +static void pointerEnter(void* data, wl_pointer* pointer, uint32_t serial, + wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y + ) +{ + Pointer* self = reinterpret_cast(data); + self->_serial = serial; + if (auto window = self->_wm.getWindowForNative(surface)) { + window->setCursor(jwm::MouseCursor::ARROW); + self->_focusedSurface = window; + } +} + +static void pointerLeave(void* data, wl_pointer* pointer, uint32_t serial, + wl_surface* surface) +{ + auto self = reinterpret_cast(data); + self->_focusedSurface = nullptr; + + self->_mouseMask = 0; + self->_serial = 0; +} +static void pointerMotion(void* data, wl_pointer* pointer, uint32_t time, + wl_fixed_t surface_x, wl_fixed_t surface_y) +{ + auto self = reinterpret_cast(data); + self->mouseUpdateUnscaled(wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y), self->_mouseMask); +} + +static void pointerButton(void* data, wl_pointer* pointer, uint32_t serial, + uint32_t time, uint32_t button, uint32_t state) +{ + using namespace classes; + auto self = reinterpret_cast(data); + auto window = self->_focusedSurface; + if (!window) return; + if (state == 0) { + // release + switch (button) { + // primary + case BTN_LEFT: + self->_mouseMask &= ~0x100; + break; + // secondary + case BTN_RIGHT: + self->_mouseMask &= ~0x400; + break; + // middle + case BTN_MIDDLE: + self->_mouseMask &= ~0x200; + break; + default: + break; + } + + if (MouseButtonWayland::isButton(button)) { + jwm::JNILocal eventButton( + app.getJniEnv(), + jwm::classes::EventMouseButton::make( + app.getJniEnv(), + MouseButtonWayland::fromNative(button), + false, + self->_lastMouseX, + self->_lastMouseY, + jwm::KeyWayland::getModifiers(self->_wm.getXkbState()) + ) + ); + window->dispatch(eventButton.get()); + } + } else { + // down + switch (button) { + // primary + case BTN_LEFT: + self->_mouseMask |= 0x100; + break; + // secondary + case BTN_RIGHT: + self->_mouseMask |= 0x400; + break; + // middle + case BTN_MIDDLE: + self->_mouseMask |= 0x200; + break; + default: + break; + } + + if (MouseButtonWayland::isButton(button)) { + jwm::JNILocal eventButton( + app.getJniEnv(), + jwm::classes::EventMouseButton::make( + app.getJniEnv(), + MouseButtonWayland::fromNative(button), + true, + self->_lastMouseX, + self->_lastMouseY, + jwm::KeyWayland::getModifiers(self->_wm.getXkbState()) + ) + ); + window->dispatch(eventButton.get()); + } + } +} + +static void pointerAxis(void* data, wl_pointer* pointer, uint32_t time, + uint32_t axis, wl_fixed_t value) +{ + auto self = reinterpret_cast(data); + if (!self->_focusedSurface) return; + float fvalue = static_cast(wl_fixed_to_double(value)); + switch (axis) { + case WL_POINTER_AXIS_VERTICAL_SCROLL: + self->_dY += fvalue; + break; + case WL_POINTER_AXIS_HORIZONTAL_SCROLL: + self->_dX += fvalue; + break; + default: + break; + } +} + +static void pointerFrame(void* data, wl_pointer* pointer) +{ + auto self = reinterpret_cast(data); + auto win = self->_focusedSurface; + if (!win) return; + if (self->_dX != 0.0f || self->_dY != 0.0f) { + auto env = app.getJniEnv(); + + jwm::JNILocal eventAxis( + env, + jwm::classes::EventMouseScroll::make( + env, + self->_dX * win->_scale, + self->_dY * win->_scale, + 0.0f, + 0.0f, + 0.0f, + self->_lastMouseX, + self->_lastMouseY, + jwm::KeyWayland::getModifiers(self->_wm.getXkbState()) + ) + ); + win->dispatch(eventAxis.get()); + + self->_dX = 0.0f; + self->_dY = 0.0f; + } +} + +static void pointerAxisSource(void* data, wl_pointer* pointer, uint32_t source) {} +static void pointerAxisStop(void* data, wl_pointer* pointer, uint32_t time, uint32_t axis) {} +static void pointerAxisDiscrete(void* data, wl_pointer* pointer, uint32_t axis, int discrete) {} + +wl_pointer_listener Pointer::_pointerListener = { + .enter = pointerEnter, + .leave = pointerLeave, + .motion = pointerMotion, + .button = pointerButton, + .axis = pointerAxis, + .frame = pointerFrame, + .axis_source = pointerAxisSource, + .axis_stop = pointerAxisStop, + .axis_discrete = pointerAxisDiscrete +}; + +Pointer::Pointer(wl_pointer* pointer, WindowManagerWayland* wm): + _pointer(pointer), + _wm(*wm) +{ + _surface = wl_compositor_create_surface(_wm.compositor); + wl_pointer_add_listener(pointer, &_pointerListener, this); +} + +Pointer::~Pointer() +{ + if (_pointer) + wl_pointer_release(_pointer); +} + +void Pointer::mouseUpdate(uint32_t x, uint32_t y, uint32_t mask) { + auto window = _focusedSurface; + if (!window) + return; + if (_lastMouseX == x && _lastMouseY == y) + return; + _lastMouseX = x; + _lastMouseY = y; + int movementX = 0, movementY = 0; + + jwm::JNILocal eventMove( + app.getJniEnv(), + jwm::classes::EventMouseMove::make(app.getJniEnv(), + x, + y, + movementX, + movementY, + jwm::MouseButtonWayland::fromNativeMask(mask), + // impl me! + jwm::KeyWayland::getModifiers(_wm.getXkbState()) + ) + ); + window->dispatch(eventMove.get()); +} + +void Pointer::mouseUpdateUnscaled(uint32_t x, uint32_t y, uint32_t mask) { + auto window = _focusedSurface; + if (!window) return; + mouseUpdate(x * window->_scale, y * window->_scale, mask); +} + +void Pointer::updateHotspot(int x, int y) { + if (!_focusedSurface) return; + wl_pointer_set_cursor(_pointer, _serial, _surface, x / _focusedSurface->_scale, y / _focusedSurface->_scale); +} diff --git a/wayland/cc/Pointer.hh b/wayland/cc/Pointer.hh new file mode 100644 index 00000000..8fb979eb --- /dev/null +++ b/wayland/cc/Pointer.hh @@ -0,0 +1,49 @@ +#pragma once + +#include + +namespace jwm { + class WindowManagerWayland; + class WindowWayland; + class Pointer { + public: + Pointer(wl_pointer* pointer, jwm::WindowManagerWayland* wm); + ~Pointer(); + + wl_pointer* _pointer; + wl_pointer* getPointer() const { + return _pointer; + } + + uint32_t _serial = 0; + uint32_t getSerial() { + return _serial; + } + + wl_surface* _surface; + wl_surface* getSurface() const { + return _surface; + } + + WindowWayland* _focusedSurface; + WindowWayland* getFocusedSurface() const { + return _focusedSurface; + } + + uint32_t _lastMouseX; + uint32_t _lastMouseY; + float _dX = 0.0; + float _dY = 0.0; + + int _mouseMask = 0; + jwm::WindowManagerWayland& _wm; + + static wl_pointer_listener _pointerListener; + + void mouseUpdate(uint32_t x, uint32_t y, uint32_t mask); + void mouseUpdateUnscaled(uint32_t x, uint32_t y, uint32_t mask); + + void updateHotspot(int x, int y); + + }; +} diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 4922ff1f..e8d3481e 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -31,48 +31,6 @@ wl_registry_listener WindowManagerWayland::_registryListener = { .global = WindowManagerWayland::registryHandleGlobal, .global_remove = WindowManagerWayland::registryHandleGlobalRemove }; -static void pointerFrame(void* data, wl_pointer* pointer) { - auto self = reinterpret_cast(data); - if (!self->getFocusedSurface()) return; - if (self->_dX != 0.0f || self->_dY != 0.0f) { - auto env = app.getJniEnv(); - auto win = self->getFocusedSurface(); - jwm::JNILocal eventAxis( - env, - jwm::classes::EventMouseScroll::make( - env, - self->_dX * win->_scale, - self->_dY * win->_scale, - 0.0f, - 0.0f, - 0.0f, - self->lastMousePosX, - self->lastMousePosY, - jwm::KeyWayland::getModifiers(self->getXkbState()) - ) - ); - win->dispatch(eventAxis.get()); - - self->_dX = 0.0f; - self->_dY = 0.0f; - } -} -static void pointerAxisSource(void* data, wl_pointer* pointer, uint32_t source) {} -static void pointerAxisStop(void* data, wl_pointer* pointer, uint32_t time, uint32_t axis) {} -static void pointerAxisDiscrete(void* data, wl_pointer* pointer, uint32_t axis, int discrete) {} -// Lambdas turn into null pointers at runtime. God knows why. -wl_pointer_listener WindowManagerWayland::_pointerListener = { - .enter = WindowManagerWayland::pointerHandleEnter, - .leave = WindowManagerWayland::pointerHandleLeave, - .motion = WindowManagerWayland::pointerHandleMotion, - .button = WindowManagerWayland::pointerHandleButton, - .axis = WindowManagerWayland::pointerHandleAxis, - .frame = pointerFrame, - .axis_source = pointerAxisSource, - .axis_stop = pointerAxisStop, - .axis_discrete = pointerAxisDiscrete -}; - libdecor_interface WindowManagerWayland::_decorInterface = { .error = WindowManagerWayland::libdecorError }; @@ -102,7 +60,6 @@ WindowManagerWayland::WindowManagerWayland(): wl_display_roundtrip(display); - cursorSurface = wl_compositor_create_surface(compositor); } @@ -299,135 +256,13 @@ WindowWayland* WindowManagerWayland::getWindowForNative(wl_surface* surface) { return myWindow; */ } -void WindowManagerWayland::pointerHandleEnter(void* data, wl_pointer* pointer, uint32_t serial, - wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { - WindowManagerWayland* self = (WindowManagerWayland*)data; - self->mouseSerial = serial; - if (auto window = self->getWindowForNative(surface)) { - window->setCursor(jwm::MouseCursor::ARROW); - self->setFocusedSurface(window); - } -} -void WindowManagerWayland::pointerHandleLeave(void* data, wl_pointer* pointer, uint32_t serial, - wl_surface *surface) { - WindowManagerWayland* self = (WindowManagerWayland*)data; - self->setFocusedSurface(nullptr); - // ??? - self->mouseMask = 0; - self->mouseSerial = -1; -} -void WindowManagerWayland::pointerHandleMotion(void* data, wl_pointer* pointer, - uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { - WindowManagerWayland* self = (WindowManagerWayland*)data; - if (self->getFocusedSurface()) { - ::WindowWayland* window = self->getFocusedSurface(); - // God is dead if window is null - if (window) - self->mouseUpdate(window, - wl_fixed_to_int(surface_x) * window->_scale, - wl_fixed_to_int(surface_y) * window->_scale, self->mouseMask); - } - -} -void WindowManagerWayland::pointerHandleButton(void* data, wl_pointer* pointer, - uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { - using namespace classes; - WindowManagerWayland* self = (WindowManagerWayland*)data; - if (!self->getFocusedSurface()) return; - auto window = self->getFocusedSurface(); - if (state == 0) { - // release - switch (button) { - // primary - case BTN_LEFT: - self->mouseMask &= ~0x100; - break; - // secondary - case BTN_RIGHT: - self->mouseMask &= ~0x400; - break; - // middle - case BTN_MIDDLE: - self->mouseMask &= ~0x200; - break; - default: - break; - } - - if (MouseButtonWayland::isButton(button)) { - jwm::JNILocal eventButton( - app.getJniEnv(), - EventMouseButton::make( - app.getJniEnv(), - MouseButtonWayland::fromNative(button), - false, - self->lastMousePosX, - self->lastMousePosY, - jwm::KeyWayland::getModifiers(self->getXkbState()) - ) - ); - window->dispatch(eventButton.get()); - } - } else { - // down - switch (button) { - // primary - case BTN_LEFT: - self->mouseMask |= 0x100; - break; - // secondary - case BTN_RIGHT: - self->mouseMask |= 0x400; - break; - // middle - case BTN_MIDDLE: - self->mouseMask |= 0x200; - break; - default: - break; - } - - if (MouseButtonWayland::isButton(button)) { - jwm::JNILocal eventButton( - app.getJniEnv(), - EventMouseButton::make( - app.getJniEnv(), - MouseButtonWayland::fromNative(button), - true, - self->lastMousePosX, - self->lastMousePosY, - jwm::KeyWayland::getModifiers(self->getXkbState()) - ) - ); - window->dispatch(eventButton.get()); - } - } -} -void WindowManagerWayland::pointerHandleAxis(void* data, wl_pointer* pointer, - uint32_t time, uint32_t axis, wl_fixed_t value) { - auto self = reinterpret_cast(data); - if (!self->getFocusedSurface()) return; - switch (axis) { - case WL_POINTER_AXIS_VERTICAL_SCROLL: - self->_dY += static_cast(wl_fixed_to_double(value)); - break; - case WL_POINTER_AXIS_HORIZONTAL_SCROLL: - self->_dX += static_cast(wl_fixed_to_double(value)); - break; - default: - break; - } -} - void WindowManagerWayland::seatCapabilities(void* data, wl_seat* seat, uint32_t capabilities) { auto self = reinterpret_cast(data); if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && - !self->pointer) { - self->pointer = wl_seat_get_pointer(seat); - wl_pointer_add_listener(self->pointer, &_pointerListener, self); - } else if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && self->pointer) { - wl_pointer_release(self->pointer); - self->pointer = nullptr; + !self->_pointer) { + self->_pointer = new Pointer(wl_seat_get_pointer(seat), self); + } else if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && self->_pointer) { + self->_pointer = nullptr; } if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && @@ -466,30 +301,6 @@ wl_data_device_listener WindowManagerWayland::_deviceListener = { std::vector WindowManagerWayland::getClipboardFormats() { return { _currentMimeTypes.begin(), _currentMimeTypes.end()}; } -void WindowManagerWayland::mouseUpdate(WindowWayland* myWindow, uint32_t x, uint32_t y, uint32_t mask) { - using namespace classes; - if (!myWindow) - return; - // impl me : ) - if (lastMousePosX == x && lastMousePosY == y) return; - lastMousePosX = x; - lastMousePosY = y; - int movementX = 0, movementY = 0; - jwm::JNILocal eventMove( - app.getJniEnv(), - EventMouseMove::make(app.getJniEnv(), - x, - y, - movementX, - movementY, - jwm::MouseButtonWayland::fromNativeMask(mask), - // impl me! - jwm::KeyWayland::getModifiers(getXkbState()) - ) - ); - auto foo = eventMove.get(); - myWindow->dispatch(foo); -} jwm::ByteBuf WindowManagerWayland::getClipboardContents(const std::string& type) { auto it = _myClipboardContents.find(type); if (it != _myClipboardContents.end()) { diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index a594ddd2..173b9bfc 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -19,6 +19,7 @@ #include #include #include "Keyboard.hh" +#include "Pointer.hh" namespace jwm { class WindowWayland; @@ -67,21 +68,6 @@ namespace jwm { static void registryHandleGlobalRemove(void* data, wl_registry *registry, uint32_t name); - static wl_pointer_listener _pointerListener; - - static void pointerHandleEnter(void* data, wl_pointer *pointer, - uint32_t serial, wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y); - static void pointerHandleLeave(void* data, wl_pointer *pointer, - uint32_t serial, wl_surface* surface); - static void pointerHandleMotion(void* data, wl_pointer *pointer, - uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y); - static void pointerHandleButton(void* data, wl_pointer *pointer, - uint32_t serial, uint32_t time, uint32_t button, - uint32_t state); - static void pointerHandleAxis(void* data, wl_pointer *pointer, - uint32_t time, uint32_t axis, wl_fixed_t value); - - static libdecor_interface _decorInterface; static void libdecorError(libdecor* context, enum libdecor_error error, const char* message); @@ -104,12 +90,19 @@ namespace jwm { wl_data_device_manager* deviceManager = nullptr; // no multiseat? wl_seat* seat = nullptr; - wl_pointer* pointer = nullptr; + Pointer* _pointer = nullptr; + Pointer* getPointer() const { + return _pointer; + } Keyboard* _keyboard = nullptr; wl_data_device* dataDevice = nullptr; wl_data_source* currentSource = nullptr; wl_data_offer* currentOffer = nullptr; - uint32_t mouseSerial = 0; + uint32_t getMouseSerial() const { + if (_pointer) + return _pointer->getSerial(); + return 0; + } uint32_t getKeyboardSerial() const { if (_keyboard) return _keyboard->getSerial(); @@ -124,31 +117,24 @@ namespace jwm { EGLDisplay _eglDisplay = EGL_NO_DISPLAY; std::list outputs; - wl_cursor* currentCursor = nullptr; bool _runLoop; int notifyFD = -1; std::atomic_bool notifyBool{false}; - int lastMousePosX = 0; - int lastMousePosY = 0; - // god forgive me for using float - float _dX = 0.0f; - float _dY = 0.0f; - int mouseMask = 0; - void mouseUpdate(WindowWayland* myWindow, uint32_t x, uint32_t y, uint32_t mask); std::map _nativeWindowToMy; std::map _myClipboardContents; std::map _myClipboardSource; std::list _currentMimeTypes; - - wl_surface* cursorSurface; - WindowWayland* _focusedSurface = nullptr; - WindowWayland* getFocusedSurface() const { - return _focusedSurface; + wl_surface* getCursorSurface() const { + if (_pointer) + return _pointer->getSurface(); + return nullptr; } - void setFocusedSurface(WindowWayland* surface) { - _focusedSurface = surface; + WindowWayland* getFocusedSurface() const { + if (_pointer) + return _pointer->getFocusedSurface(); + return nullptr; } // Is holding all cursors in memory a good idea? wl_cursor_image* _cursors[static_cast(jwm::MouseCursor::COUNT)]; diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index acf80383..a5c1b7f0 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -263,16 +263,17 @@ void WindowWayland::setVisible(bool isVisible) { } void jwm::WindowWayland::setCursor(jwm::MouseCursor cursor) { + if (!_windowManager.getPointer()) return; auto wayCursor = _getCursorFor(cursor)->images[0]; auto buf = wl_cursor_image_get_buffer(wayCursor); - wl_surface_attach(_windowManager.cursorSurface, + auto cursorSurface = _windowManager.getCursorSurface(); + wl_surface_attach(cursorSurface, wl_cursor_image_get_buffer(wayCursor), 0, 0); - wl_surface_set_buffer_scale(_windowManager.cursorSurface, _scale); - wl_surface_damage_buffer(_windowManager.cursorSurface, 0, 0, INT32_MAX, INT32_MAX); - wl_pointer_set_cursor(_windowManager.pointer, _windowManager.mouseSerial, _windowManager.cursorSurface, - wayCursor->hotspot_x / _scale, wayCursor->hotspot_y / _scale); - wl_surface_commit(_windowManager.cursorSurface); + wl_surface_set_buffer_scale(cursorSurface, _scale); + wl_surface_damage_buffer(cursorSurface, 0, 0, INT32_MAX, INT32_MAX); + _windowManager.getPointer()->updateHotspot(wayCursor->hotspot_x, wayCursor->hotspot_y); + wl_surface_commit(cursorSurface); } // what do??? From adc9d353c4c69da8ca7b60f98841f155db657416 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Mon, 18 Dec 2023 22:37:26 -0500 Subject: [PATCH 49/93] check on deref --- wayland/cc/Keyboard.cc | 10 ++++++++-- wayland/cc/Keyboard.hh | 1 - wayland/cc/LayerGLWayland.cc | 4 +++- wayland/cc/Pointer.cc | 4 +++- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/wayland/cc/Keyboard.cc b/wayland/cc/Keyboard.cc index b2dc1a74..4a90c94d 100644 --- a/wayland/cc/Keyboard.cc +++ b/wayland/cc/Keyboard.cc @@ -64,7 +64,7 @@ static void kbEnter(void* data, wl_keyboard* kb, uint32_t serial, wl_surface* su auto win = self->_wm.getWindowForNative(surface); if (!win) return; self->_serial = serial; - self->_focus = win; + self->_focus = jwm::ref(win); if (self->_state) { uint32_t* key; // C++ jank @@ -84,7 +84,11 @@ static void kbLeave(void* data, wl_keyboard* kb, uint32_t serial, wl_surface* su for (auto key : liftedKeys) { self->submitKey(key, WL_KEYBOARD_KEY_STATE_RELEASED); } - self->_serial = -1; + self->_repeating = false; + self->_repeatingText = false; + self->_serial = 0; + if (self->_focus) + jwm::unref(&self->_focus); self->_focus = nullptr; } static void kbKey(void* data, wl_keyboard* kb, uint32_t serial, uint32_t time, @@ -233,6 +237,7 @@ void Keyboard::submitKey(jwm::Key key, uint32_t state) { ) ); _focus->dispatch(keyEvent.get()); + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { _depressedKeys.push_back(key); } else { @@ -243,3 +248,4 @@ void Keyboard::submitKey(jwm::Key key, uint32_t state) { } } } + diff --git a/wayland/cc/Keyboard.hh b/wayland/cc/Keyboard.hh index c4ad891b..2793d66a 100644 --- a/wayland/cc/Keyboard.hh +++ b/wayland/cc/Keyboard.hh @@ -44,7 +44,6 @@ namespace jwm { void submitKey(jwm::Key key, uint32_t state); - jwm::StringUTF16 _repeatText; jwm::Key _repeatKey = jwm::Key::UNDEFINED; bool _repeating = false; diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index 7e577e79..3ad71741 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -95,7 +95,7 @@ namespace jwm { glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); // ??? - glViewport(0, 0, width, height); + // glViewport(0, 0, width, height); // God is dead if _eglWindow is null if (_eglWindow) wl_egl_window_resize(_eglWindow, width, height, 0, 0); @@ -107,6 +107,8 @@ namespace jwm { } void swapBuffers() override { + makeCurrent(); + eglSwapBuffers(_display, _surface); } diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index 06c242c3..5ed89dfb 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -16,7 +16,7 @@ static void pointerEnter(void* data, wl_pointer* pointer, uint32_t serial, self->_serial = serial; if (auto window = self->_wm.getWindowForNative(surface)) { window->setCursor(jwm::MouseCursor::ARROW); - self->_focusedSurface = window; + self->_focusedSurface = jwm::ref(window); } } @@ -24,6 +24,8 @@ static void pointerLeave(void* data, wl_pointer* pointer, uint32_t serial, wl_surface* surface) { auto self = reinterpret_cast(data); + if (self->_focusedSurface) + jwm::unref(&self->_focusedSurface); self->_focusedSurface = nullptr; self->_mouseMask = 0; From 59c30826584b0bcd992b7fac148a3f0bafb54ad3 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Mon, 18 Dec 2023 23:07:46 -0500 Subject: [PATCH 50/93] no copy/move stuff in things w/ destructors --- wayland/cc/Buffer.hh | 6 ++ wayland/cc/Keyboard.cc | 1 - wayland/cc/Keyboard.hh | 7 ++- wayland/cc/Pointer.cc | 1 - wayland/cc/Pointer.hh | 5 ++ wayland/cc/ShmPool.cc | 97 ------------------------------ wayland/cc/ShmPool.hh | 26 -------- wayland/cc/WindowManagerWayland.cc | 3 +- 8 files changed, 19 insertions(+), 127 deletions(-) delete mode 100644 wayland/cc/ShmPool.cc delete mode 100644 wayland/cc/ShmPool.hh diff --git a/wayland/cc/Buffer.hh b/wayland/cc/Buffer.hh index d6bfe08c..a536ba07 100644 --- a/wayland/cc/Buffer.hh +++ b/wayland/cc/Buffer.hh @@ -29,5 +29,11 @@ namespace jwm { static wl_buffer_listener _bufferListener; static Buffer* createShmBuffer(wl_shm* shm, int width, int height, uint32_t format); + private: + Buffer(const Buffer&) = delete; + Buffer(Buffer&&) = delete; + Buffer& operator=(const Buffer&) = delete; + Buffer& operator=(Buffer&&) = delete; + }; } diff --git a/wayland/cc/Keyboard.cc b/wayland/cc/Keyboard.cc index 4a90c94d..57bf50e6 100644 --- a/wayland/cc/Keyboard.cc +++ b/wayland/cc/Keyboard.cc @@ -89,7 +89,6 @@ static void kbLeave(void* data, wl_keyboard* kb, uint32_t serial, wl_surface* su self->_serial = 0; if (self->_focus) jwm::unref(&self->_focus); - self->_focus = nullptr; } static void kbKey(void* data, wl_keyboard* kb, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { diff --git a/wayland/cc/Keyboard.hh b/wayland/cc/Keyboard.hh index 2793d66a..04baf904 100644 --- a/wayland/cc/Keyboard.hh +++ b/wayland/cc/Keyboard.hh @@ -54,6 +54,11 @@ namespace jwm { jwm::WindowManagerWayland& _wm; static wl_keyboard_listener _keyboardListener; - + private: + // no copy or move + Keyboard(const Keyboard&) = delete; + Keyboard(Keyboard&&) = delete; + Keyboard& operator=(const Keyboard&) = delete; + Keyboard& operator=(Keyboard&&) = delete; }; } diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index 5ed89dfb..3674d230 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -26,7 +26,6 @@ static void pointerLeave(void* data, wl_pointer* pointer, uint32_t serial, auto self = reinterpret_cast(data); if (self->_focusedSurface) jwm::unref(&self->_focusedSurface); - self->_focusedSurface = nullptr; self->_mouseMask = 0; self->_serial = 0; diff --git a/wayland/cc/Pointer.hh b/wayland/cc/Pointer.hh index 8fb979eb..4aca0068 100644 --- a/wayland/cc/Pointer.hh +++ b/wayland/cc/Pointer.hh @@ -45,5 +45,10 @@ namespace jwm { void updateHotspot(int x, int y); + private: + Pointer(const Pointer& other) = delete; + Pointer(Pointer&&) = delete; + Pointer& operator=(const Pointer& other) = delete; + Pointer& operator=(Pointer&&) = delete; }; } diff --git a/wayland/cc/ShmPool.cc b/wayland/cc/ShmPool.cc deleted file mode 100644 index 4366b45d..00000000 --- a/wayland/cc/ShmPool.cc +++ /dev/null @@ -1,97 +0,0 @@ -#include "ShmPool.hh" -#include -#include -#include -#include -#include -#include - -using namespace jwm; - -static void randname(char *buf) -{ - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - long r = ts.tv_nsec; - for (int i = 0; i < 6; ++i) { - buf[i] = 'A'+(r&15)+(r&16)*2; - r >>= 5; - } -} -ShmPool::ShmPool(wl_shm* shm, size_t size): - _size(size) { - _fd = _allocateShmFile(size); - if (_fd < 0) { - // why : ( - throw std::system_error(EIO, std::generic_category(), "Couldn't allocate buffer"); - } - _rawData = (uint8_t*)mmap(nullptr, size, - PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0); - _pool = wl_shm_create_pool(shm, _fd, size); - - } -ShmPool::~ShmPool() { - close(); -} -void ShmPool::close() { - wl_shm_pool_destroy(_pool); - ::close(_fd); - munmap(_rawData, _size); -} - -void ShmPool::grow(size_t size) { - if (size <= _size) - return; - int ret; - do { - ret = ftruncate(_fd, size); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - // AAHHHHH! - throw std::system_error(EIO, std::generic_category(), "Couldn't grow buffer"); - } - uint8_t* newData = (uint8_t*)mmap(nullptr, size, - PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0); - // do I need to memcpy??? lets say no :troll: - // TODO: error checking :troll: - munmap(_rawData, _size); - _rawData = newData; - _size = size; - wl_shm_pool_resize(_pool, size); -} - -int ShmPool::_createShmFile() { - int retries = 100; - do { - char name[] = "/wl_shm-XXXXXX"; - randname(name + sizeof(name) - 7); - --retries; - int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); - if (fd >= 0) { - shm_unlink(name); - return fd; - } - } while (retries > 0 && errno == EEXIST); - return -1; -} - -int ShmPool::_allocateShmFile(size_t size) { - int fd = _createShmFile(); - if (fd < 0) - return -1; - int ret; - do { - ret = ftruncate(fd, size); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - ::close(fd); - return -1; - } - return fd; -} - -std::pair ShmPool::createBuffer(int offset, int width, int height, int stride, uint32_t format) { - wl_buffer* buffer = wl_shm_pool_create_buffer(_pool, offset, width, height, stride, format); - uint8_t* data = &_rawData[offset]; - return std::pair(buffer, data); -} diff --git a/wayland/cc/ShmPool.hh b/wayland/cc/ShmPool.hh deleted file mode 100644 index 402660b6..00000000 --- a/wayland/cc/ShmPool.hh +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include -#include - -namespace jwm { - class ShmPool { - public: - ShmPool(wl_shm* shm, size_t size); - ~ShmPool(); - - size_t _size; - int _fd; - wl_shm_pool* _pool; - uint8_t* _rawData; - - // grows current file to at least this size - void grow(size_t size); - - std::pair createBuffer(int offset, int width, int height, int stride, uint32_t format); - - int _createShmFile(); - int _allocateShmFile(size_t size); - void close(); - }; -} diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index e8d3481e..e2673e7a 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -107,7 +107,8 @@ void WindowManagerWayland::runLoop() { if (ps[0].revents & POLLIN) { if (libdecor_dispatch(decorCtx, -1) < 0) { fprintf(stderr, "error with dispatch\n"); - break; + // ??? + // break; } } From aff279051634a01c67c81bb791658eb929fb9c44 Mon Sep 17 00:00:00 2001 From: TheDrawingCoding-Gamer Date: Tue, 19 Dec 2023 13:59:34 -0500 Subject: [PATCH 51/93] clarify what detaching does --- wayland/cc/ILayerWayland.hh | 2 +- wayland/cc/LayerGLWayland.cc | 4 ++-- wayland/cc/LayerRasterWayland.cc | 4 ++-- wayland/cc/WindowWayland.cc | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/wayland/cc/ILayerWayland.hh b/wayland/cc/ILayerWayland.hh index 68d2727f..2e10e226 100644 --- a/wayland/cc/ILayerWayland.hh +++ b/wayland/cc/ILayerWayland.hh @@ -7,6 +7,6 @@ namespace jwm { public: virtual void attachBuffer() = 0; virtual void swapBuffers() = 0; - virtual void detach() = 0; + virtual void detachBuffer() = 0; }; } diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index 3ad71741..e04da171 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -116,7 +116,7 @@ namespace jwm { if (_closed) return; _closed = true; - detach(); + detachBuffer(); eglDestroyContext(_display, _context); _firstAttach = true; @@ -145,7 +145,7 @@ namespace jwm { makeCurrentForced(); } } - void detach() override { + void detachBuffer() override { eglMakeCurrent(_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (_surface) { eglDestroySurface(_display, _surface); diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index cd2aea11..b4bd047e 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -63,7 +63,7 @@ namespace jwm { } void close() override { - detach(); + detachBuffer(); jwm::unref(&fWindow); fWindow = nullptr; } @@ -80,7 +80,7 @@ namespace jwm { swapBuffers(); } - void detach() override { + void detachBuffer() override { if (_attached && fWindow && fWindow->_waylandWindow) { wl_surface_attach(fWindow->_waylandWindow, nullptr, 0, 0); // commit is not meant to be used in intermediate states diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index a5c1b7f0..6f1c05d3 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -77,7 +77,7 @@ void WindowWayland::close() { void WindowWayland::hide() { _visible = false; if (_layer) { - _layer->detach(); + _layer->detachBuffer(); } if (_frame) { libdecor_frame_unref(_frame); From 9748b978f7c82a4f7acbe63edb9971e9652d516b Mon Sep 17 00:00:00 2001 From: TheDrawingCoding-Gamer Date: Tue, 19 Dec 2023 21:56:47 -0500 Subject: [PATCH 52/93] various fixes, nvidia worksish --- wayland/cc/LayerGLWayland.cc | 40 ++++++---------- wayland/cc/MouseButtonWayland.cc | 16 ++++--- wayland/cc/Output.cc | 7 ++- wayland/cc/Output.hh | 7 +++ wayland/cc/Pointer.cc | 4 +- wayland/cc/WindowManagerWayland.cc | 73 ++++++++++++++++-------------- wayland/cc/WindowWayland.cc | 34 +++----------- wayland/cc/WindowWayland.hh | 11 ----- 8 files changed, 82 insertions(+), 110 deletions(-) diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index e04da171..665976ea 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -22,15 +22,11 @@ namespace jwm { EGLDisplay _display = nullptr; EGLSurface _surface = nullptr; EGLConfig _config = nullptr; - bool _firstAttach = true; - bool _closed = false; LayerGL() = default; virtual ~LayerGL() = default; void attach(WindowWayland* window) { - // no idea why you would reopen it??? - _closed = false; fWindow = jwm::ref(window); fWindow->setLayer(this); // Force a reconfigure; needed to draw title bar correctly @@ -40,9 +36,6 @@ namespace jwm { eglInitialize(fWindow->_windowManager._eglDisplay, nullptr, nullptr); } - if (_firstAttach) { - _firstAttach = false; - } _display = fWindow->_windowManager._eglDisplay; if ( eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) { throw new std::runtime_error("Cannot bind EGL Api"); @@ -74,8 +67,6 @@ namespace jwm { if ( _context == EGL_NO_CONTEXT ) { throw std::runtime_error("Couldn't make context"); } - // Don't block on swap - // Blocking here will freeze the app on sway. } if (fWindow->_configured) attachBuffer(); @@ -95,42 +86,37 @@ namespace jwm { glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); // ??? - // glViewport(0, 0, width, height); + glViewport(0, 0, width, height); // God is dead if _eglWindow is null if (_eglWindow) wl_egl_window_resize(_eglWindow, width, height, 0, 0); - if (fWindow->_scale != fWindow->_oldScale) { - swapBuffers(); - wl_surface_set_buffer_scale(fWindow->_waylandWindow, fWindow->_scale); - } + wl_surface_set_buffer_scale(fWindow->_waylandWindow, fWindow->_scale); } void swapBuffers() override { makeCurrent(); - - eglSwapBuffers(_display, _surface); + if (_surface) + eglSwapBuffers(_display, _surface); } void close() override { - if (_closed) - return; - _closed = true; detachBuffer(); eglDestroyContext(_display, _context); - _firstAttach = true; - jwm::unref(&fWindow); - fWindow = nullptr; + if (fWindow) + jwm::unref(&fWindow); } void makeCurrentForced() override { ILayer::makeCurrentForced(); - eglMakeCurrent(_display, - _surface, - _surface, - _context); - eglSwapInterval(_display, 0); + if (_surface) { + eglMakeCurrent(_display, + _surface, + _surface, + _context); + eglSwapInterval(_display, 0); + } } void attachBuffer() override { if (fWindow && fWindow->_waylandWindow) { diff --git a/wayland/cc/MouseButtonWayland.cc b/wayland/cc/MouseButtonWayland.cc index d2fcd79d..b81f1f37 100644 --- a/wayland/cc/MouseButtonWayland.cc +++ b/wayland/cc/MouseButtonWayland.cc @@ -1,13 +1,17 @@ #include "MouseButtonWayland.hh" - +#include jwm::MouseButton jwm::MouseButtonWayland::fromNative(uint32_t v) { switch (v) { - case 0x110: return jwm::MouseButton::PRIMARY; - case 0x112: return jwm::MouseButton::MIDDLE; - case 0x111: return jwm::MouseButton::SECONDARY; - case 0x116: return jwm::MouseButton::BACK; - case 0x115: return jwm::MouseButton::FORWARD; + case BTN_LEFT: return jwm::MouseButton::PRIMARY; + case BTN_MIDDLE: return jwm::MouseButton::MIDDLE; + case BTN_RIGHT: return jwm::MouseButton::SECONDARY; + // TODO: is this mapping consistent? + // I've gotten this from observing my mouse + case BTN_SIDE: + case BTN_BACK: return jwm::MouseButton::BACK; + case BTN_EXTRA: + case BTN_FORWARD: return jwm::MouseButton::FORWARD; } return jwm::MouseButton::PRIMARY; } diff --git a/wayland/cc/Output.cc b/wayland/cc/Output.cc index 91590ce5..753e36de 100644 --- a/wayland/cc/Output.cc +++ b/wayland/cc/Output.cc @@ -16,12 +16,17 @@ Output::Output(wl_output* output, uint32_t name): { wl_output_add_listener(output, &_outputListener, this); } +Output::~Output() +{ + if (_output) + wl_output_release(_output); +} ScreenInfo Output::getScreenInfo() const { return { .id = _name, .bounds = jwm::IRect::makeXYWH(0, 0, width, height), - .isPrimary = false, + .isPrimary = primary, .scale = scale }; } diff --git a/wayland/cc/Output.hh b/wayland/cc/Output.hh index cf8c9381..8af4c421 100644 --- a/wayland/cc/Output.hh +++ b/wayland/cc/Output.hh @@ -8,9 +8,11 @@ namespace jwm { class Output { public: Output(wl_output* output, uint32_t name); + ~Output(); wl_output* _output; uint32_t _name; + bool primary = false; int scale = 1; int width = 0; int height = 0; @@ -25,5 +27,10 @@ namespace jwm { static void outputScale(void* data, wl_output* output, int factor); static void outputName(void* data, wl_output* output, const char* name); static void outputDescription(void* data, wl_output* output, const char* desc); + private: + Output(const Output&) = delete; + Output(Output&&) = delete; + Output& operator=(const Output&) = delete; + Output& operator=(Output&&) = delete; }; } diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index 3674d230..f3871d94 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -12,11 +12,11 @@ static void pointerEnter(void* data, wl_pointer* pointer, uint32_t serial, wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y ) { - Pointer* self = reinterpret_cast(data); + auto self = reinterpret_cast(data); self->_serial = serial; if (auto window = self->_wm.getWindowForNative(surface)) { - window->setCursor(jwm::MouseCursor::ARROW); self->_focusedSurface = jwm::ref(window); + window->setCursor(jwm::MouseCursor::ARROW); } } diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index e2673e7a..89de285d 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -170,41 +170,41 @@ void WindowManagerWayland::_processCallbacks() { } void WindowManagerWayland::_processKeyboard() { - if (_keyboard && _keyboard->_repeating && _keyboard->getFocus()) { - auto now = std::chrono::steady_clock::now(); - _keyboard->_nextRepeat = now + std::chrono::milliseconds(_keyboard->_repeatRate); - auto focus = _keyboard->getFocus(); - auto env = jwm::app.getJniEnv(); - jwm::KeyLocation location = jwm::KeyLocation::DEFAULT; - JNILocal keyOffEvent( - env, - classes::EventKey::make( - env, - _keyboard->_repeatKey, - false, - KeyWayland::getModifiers(_keyboard->_state), - location - ) - ); - - JNILocal keyEvent( - env, - classes::EventKey::make( - env, - _keyboard->_repeatKey, - true, - KeyWayland::getModifiers(_keyboard->_state), - location - ) - ); - focus->dispatch(keyOffEvent.get()); - focus->dispatch(keyEvent.get()); - if (_keyboard->_repeatingText) { - jwm::JNILocal jtext = _keyboard->_repeatText.toJString(env); - jwm::JNILocal eventTextInput(env, classes::EventTextInput::make(env, jtext.get())); - - focus->dispatch(eventTextInput.get()); - } + if (!_keyboard || !_keyboard->_repeating) return; + auto focus = _keyboard->getFocus(); + if (!focus) return; + auto now = std::chrono::steady_clock::now(); + _keyboard->_nextRepeat = now + std::chrono::milliseconds(_keyboard->_repeatRate); + auto env = jwm::app.getJniEnv(); + jwm::KeyLocation location = jwm::KeyLocation::DEFAULT; + JNILocal keyOffEvent( + env, + classes::EventKey::make( + env, + _keyboard->_repeatKey, + false, + KeyWayland::getModifiers(_keyboard->_state), + location + ) + ); + + JNILocal keyEvent( + env, + classes::EventKey::make( + env, + _keyboard->_repeatKey, + true, + KeyWayland::getModifiers(_keyboard->_state), + location + ) + ); + focus->dispatch(keyOffEvent.get()); + focus->dispatch(keyEvent.get()); + if (_keyboard->_repeatingText) { + jwm::JNILocal jtext = _keyboard->_repeatText.toJString(env); + jwm::JNILocal eventTextInput(env, classes::EventTextInput::make(env, jtext.get())); + + focus->dispatch(eventTextInput.get()); } } @@ -229,6 +229,9 @@ void WindowManagerWayland::registryHandleGlobal(void* data, wl_registry *registr wl_output* output = (wl_output*)wl_registry_bind(registry, name, &wl_output_interface, 2); Output* good = new Output(output, name); + if (self->outputs.empty()) + // ??? this is a race condition (probably) but i have to do this to prevent crashes + good->primary = true; self->outputs.push_back(good); } } diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index 6f1c05d3..ef3defae 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -20,15 +20,6 @@ wl_surface_listener WindowWayland::_surfaceListener = { #endif }; - -wl_output_listener WindowWayland::_outputListener = { - .geometry = WindowWayland::outputGeometry, - .mode = WindowWayland::outputMode, - .done = WindowWayland::outputDone, - .scale = WindowWayland::outputScale, - .name = WindowWayland::outputName, - .description = WindowWayland::outputDescription -}; libdecor_frame_interface WindowWayland::_libdecorFrameInterface = { .configure = WindowWayland::decorFrameConfigure, .close = WindowWayland::decorFrameClose, @@ -303,20 +294,6 @@ void jwm::WindowWayland::surfacePreferredBufferScale(void* data, wl_surface* sur } void jwm::WindowWayland::surfacePreferredBufferTransform(void* data, wl_surface* surface, uint32_t transform) {} -void jwm::WindowWayland::outputGeometry(void* data, wl_output* output, int x, int y, int pWidth, int pHeight, - int subpixel, const char* make, const char* model, int transform) {} -void jwm::WindowWayland::outputMode(void* data, wl_output* output, uint32_t flags, int width, int height, - int refresh) {} -void jwm::WindowWayland::outputDone(void* data, wl_output* output) {} -void jwm::WindowWayland::outputScale(void* data, wl_output* output, int factor) { - WindowWayland* self = reinterpret_cast(data); - self->_scale = factor; - if (self->_waylandWindow) - self->dispatch(classes::EventWindowScreenChange::kInstance); -} -void jwm::WindowWayland::outputName(void* data, wl_output* output, const char* name) {} -void jwm::WindowWayland::outputDescription(void* data, wl_output* output, const char* desc) {} - static void frameCallbackDone(void* data, wl_callback* cb, uint32_t cb_data) { auto self = reinterpret_cast(data); self->_adaptSize(self->_newWidth, self->_newHeight); @@ -368,6 +345,11 @@ void jwm::WindowWayland::decorFrameConfigure(libdecor_frame* frame, libdecor_con self->_fullscreen = fullscreen; self->_floating = libdecor_frame_is_floating(frame); } + // before width + if (!self->_configured) { + if (self->_layer) + self->_layer->attachBuffer(); + } if (self->_width != width || self->_height != height) { if (libdecor_frame_is_floating(frame)) { if (width > 0) @@ -379,10 +361,6 @@ void jwm::WindowWayland::decorFrameConfigure(libdecor_frame* frame, libdecor_con self->_adaptSize(width, height); } - if (!self->_configured && self->_visible) { - if (self->_layer) - self->_layer->attachBuffer(); - } self->_configured = true; } void jwm::WindowWayland::decorFrameClose(libdecor_frame* frame, void* userData) { @@ -393,12 +371,12 @@ void jwm::WindowWayland::decorFrameCommit(libdecor_frame* frame, void* userData) WindowWayland* self = reinterpret_cast(userData); if (self->_waylandWindow) { wl_surface_commit(self->_waylandWindow); - wl_display_roundtrip(self->_windowManager.display); } } void jwm::WindowWayland::decorFrameDismissPopup(libdecor_frame* frame, const char* seatName, void* userData) {} void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { using namespace classes; + if (newWidth == _width && newHeight == _height && _scale == _oldScale) return; _width = newWidth; _height = newHeight; int scaledWidth = _width * _scale; diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index b1b09384..2923077e 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -61,16 +61,6 @@ namespace jwm { static void surfacePreferredBufferScale(void* data, wl_surface* surface, int factor); static void surfacePreferredBufferTransform(void* data, wl_surface* surface, uint32_t transform); - static void outputGeometry(void* data, wl_output* output, int x, int y, int physWidth, int physHeight, - int subpixelOrient, const char* make, const char* model, int transform); - static void outputMode(void* data, wl_output* output, uint32_t flags, int width, int height, int refresh); - static void outputDone(void* data, wl_output* output); - // YEAH THAT'S WHAT I'VE BEEN WAITING FOR - static void outputScale(void* data, wl_output* output, int factor); - static void outputName(void* data, wl_output* output, const char* name); - static void outputDescription(void* data, wl_output* output, const char* desc); - - static void decorFrameConfigure(libdecor_frame* frame, libdecor_configuration* config, void* userData); static void decorFrameClose(libdecor_frame* frame, void* userData); static void decorFrameCommit(libdecor_frame* frame, void* userData); @@ -113,7 +103,6 @@ namespace jwm { static wl_surface_listener _surfaceListener; - static wl_output_listener _outputListener; static libdecor_frame_interface _libdecorFrameInterface; static wl_callback_listener _frameCallback; From 1d7fb1af4fed7bbd0f40b23569a7b1d86bd59a9c Mon Sep 17 00:00:00 2001 From: TheDrawingCoding-Gamer Date: Tue, 19 Dec 2023 22:12:52 -0500 Subject: [PATCH 53/93] change how cursors are loaded --- wayland/cc/Pointer.cc | 44 ++++++++++++++++++++++++++++++++++ wayland/cc/Pointer.hh | 9 +++++++ wayland/cc/WindowWayland.cc | 48 ++++--------------------------------- wayland/cc/WindowWayland.hh | 1 - 4 files changed, 58 insertions(+), 44 deletions(-) diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index f3871d94..df1ef231 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -225,3 +225,47 @@ void Pointer::updateHotspot(int x, int y) { if (!_focusedSurface) return; wl_pointer_set_cursor(_pointer, _serial, _surface, x / _focusedSurface->_scale, y / _focusedSurface->_scale); } + +wl_cursor_theme* Pointer::_makeCursors(int scale) { + auto theme = wl_cursor_theme_load(nullptr, 24 * scale, _wm.shm); + _cursorThemes[scale] = theme; + return theme; +} + +wl_cursor_theme* Pointer::getThemeFor(int scale) { + auto it = _cursorThemes.find(scale); + if (it != _cursorThemes.end()) + return it->second; + return _makeCursors(scale); +} +wl_cursor* Pointer::getCursorFor(int scale, jwm::MouseCursor cursor) { + auto theme = getThemeFor(scale); + + switch (cursor) { + case jwm::MouseCursor::ARROW: + return wl_cursor_theme_get_cursor(theme, "default"); + case jwm::MouseCursor::CROSSHAIR: + return wl_cursor_theme_get_cursor(theme, "crosshair"); + case jwm::MouseCursor::HELP: + return wl_cursor_theme_get_cursor(theme, "help"); + case jwm::MouseCursor::POINTING_HAND: + return wl_cursor_theme_get_cursor(theme, "pointer"); + case jwm::MouseCursor::IBEAM: + return wl_cursor_theme_get_cursor(theme, "text"); + case jwm::MouseCursor::NOT_ALLOWED: + return wl_cursor_theme_get_cursor(theme, "not-allowed"); + case jwm::MouseCursor::WAIT: + return wl_cursor_theme_get_cursor(theme, "watch"); + case jwm::MouseCursor::WIN_UPARROW: + return wl_cursor_theme_get_cursor(theme, "up-arrow"); + case jwm::MouseCursor::RESIZE_NS: + return wl_cursor_theme_get_cursor(theme, "ns-resize"); + case jwm::MouseCursor::RESIZE_WE: + return wl_cursor_theme_get_cursor(theme, "ew-resize"); + case jwm::MouseCursor::RESIZE_NESW: + return wl_cursor_theme_get_cursor(theme, "nesw-resize"); + case jwm::MouseCursor::RESIZE_NWSE: + return wl_cursor_theme_get_cursor(theme, "nwse-resize"); + } + return nullptr; +} diff --git a/wayland/cc/Pointer.hh b/wayland/cc/Pointer.hh index 4aca0068..ab5ea0ec 100644 --- a/wayland/cc/Pointer.hh +++ b/wayland/cc/Pointer.hh @@ -1,6 +1,9 @@ #pragma once #include +#include +#include +#include "MouseCursor.hh" namespace jwm { class WindowManagerWayland; @@ -45,6 +48,12 @@ namespace jwm { void updateHotspot(int x, int y); + std::map _cursorThemes; + + wl_cursor_theme* _makeCursors(int scale); + wl_cursor_theme* getThemeFor(int scale); + wl_cursor* getCursorFor(int scale, jwm::MouseCursor cursor); + private: Pointer(const Pointer& other) = delete; Pointer(Pointer&&) = delete; diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index ef3defae..5345b50a 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -35,7 +35,6 @@ WindowWayland::WindowWayland(JNIEnv* env, WindowManagerWayland& windowManager): _title("") { - _makeCursors(); } WindowWayland::~WindowWayland() { @@ -140,47 +139,6 @@ bool WindowWayland::resize(int width, int height) { return true; } -void WindowWayland::_makeCursors() { - - if (theme) - wl_cursor_theme_destroy(theme); - theme = wl_cursor_theme_load(nullptr, 24 * _scale, _windowManager.shm); -} -// cursed -wl_cursor* WindowWayland::_getCursorFor(jwm::MouseCursor cursor) { - switch (cursor) { - case jwm::MouseCursor::ARROW: - // works - return wl_cursor_theme_get_cursor(theme, "default"); - case jwm::MouseCursor::CROSSHAIR: - // works - return wl_cursor_theme_get_cursor(theme, "crosshair"); - case jwm::MouseCursor::HELP: - // sometimes works? - return wl_cursor_theme_get_cursor(theme, "help"); - case jwm::MouseCursor::POINTING_HAND: - // SHOULD work - return wl_cursor_theme_get_cursor(theme, "pointer"); - case jwm::MouseCursor::IBEAM: - // doesn't work at all - return wl_cursor_theme_get_cursor(theme, "text"); - case jwm::MouseCursor::NOT_ALLOWED: - return wl_cursor_theme_get_cursor(theme, "not-allowed"); - case jwm::MouseCursor::WAIT: - return wl_cursor_theme_get_cursor(theme, "watch"); - case jwm::MouseCursor::WIN_UPARROW: - return wl_cursor_theme_get_cursor(theme, "up-arrow"); - case jwm::MouseCursor::RESIZE_NS: - return wl_cursor_theme_get_cursor(theme, "ns-resize"); - case jwm::MouseCursor::RESIZE_WE: - return wl_cursor_theme_get_cursor(theme, "ew-resize"); - case jwm::MouseCursor::RESIZE_NESW: - return wl_cursor_theme_get_cursor(theme, "nesw-resize"); - case jwm::MouseCursor::RESIZE_NWSE: - return wl_cursor_theme_get_cursor(theme, "nwse-resize"); - } - return nullptr; -} int WindowWayland::getLeft() { int x, y; getContentPosition(x, y); @@ -209,6 +167,11 @@ int WindowWayland::getUnscaledHeight() { float WindowWayland::getScale() { return _scale; } +wl_cursor* WindowWayland::_getCursorFor(jwm::MouseCursor cursor) { + if (auto ptr = _windowManager.getPointer()) + return ptr->getCursorFor(_scale, cursor); + return nullptr; +} bool WindowWayland::init() { _waylandWindow = wl_compositor_create_surface(_windowManager.compositor); wl_surface_add_listener(_waylandWindow, &_surfaceListener, this); @@ -393,7 +356,6 @@ void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { ); dispatch(eventWindowResize.get()); if (_scale != _oldScale) { - _makeCursors(); _windowManager._processCallbacks(); } // In Java Wayland doesn't actually cause a frame: diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index 2923077e..97a7012e 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -52,7 +52,6 @@ namespace jwm { void setCursor(jwm::MouseCursor cursor); void setLayer(ILayerWayland* layer); - void _makeCursors(); wl_cursor* _getCursorFor(jwm::MouseCursor cursor); ScreenInfo getScreen(); From 1b040917951e3ca4619bab6356e26aa7a25d8729 Mon Sep 17 00:00:00 2001 From: TheDrawingCoding-Gamer Date: Wed, 20 Dec 2023 18:25:55 -0500 Subject: [PATCH 54/93] More safety? --- wayland/cc/AppWayland.cc | 2 ++ wayland/cc/AppWayland.hh | 2 ++ wayland/cc/LayerGLWayland.cc | 6 ++++- wayland/cc/Output.cc | 12 +++++++++ wayland/cc/Output.hh | 2 ++ wayland/cc/Pointer.cc | 21 +++++++++------ wayland/cc/WindowManagerWayland.cc | 3 ++- wayland/cc/WindowWayland.cc | 43 +++++++++++++++++++++--------- wayland/cc/WindowWayland.hh | 2 +- 9 files changed, 69 insertions(+), 24 deletions(-) diff --git a/wayland/cc/AppWayland.cc b/wayland/cc/AppWayland.cc index 5bdde0a9..598e74d1 100644 --- a/wayland/cc/AppWayland.cc +++ b/wayland/cc/AppWayland.cc @@ -6,6 +6,8 @@ jwm::AppWayland jwm::app; +const char* jwm::AppWayland::proxyTag = "JWM"; + void jwm::AppWayland::init(JNIEnv* jniEnv) { _jniEnv = jniEnv; } diff --git a/wayland/cc/AppWayland.hh b/wayland/cc/AppWayland.hh index 690a26f6..4013b841 100644 --- a/wayland/cc/AppWayland.hh +++ b/wayland/cc/AppWayland.hh @@ -23,5 +23,7 @@ namespace jwm { JNIEnv* _jniEnv; WindowManagerWayland wm; + + static const char* proxyTag; } app; } diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index 665976ea..e6716a66 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -70,7 +70,6 @@ namespace jwm { } if (fWindow->_configured) attachBuffer(); - makeCurrentForced(); } void setVsyncMode(VSync v) override { @@ -116,6 +115,11 @@ namespace jwm { _surface, _context); eglSwapInterval(_display, 0); + } else { + eglMakeCurrent(_display, + EGL_NO_SURFACE, + EGL_NO_SURFACE, + EGL_NO_CONTEXT); } } void attachBuffer() override { diff --git a/wayland/cc/Output.cc b/wayland/cc/Output.cc index 753e36de..58cc2d90 100644 --- a/wayland/cc/Output.cc +++ b/wayland/cc/Output.cc @@ -1,4 +1,6 @@ #include "Output.hh" +#include "AppWayland.hh" + using namespace jwm; @@ -15,6 +17,7 @@ Output::Output(wl_output* output, uint32_t name): _name(name) { wl_output_add_listener(output, &_outputListener, this); + wl_proxy_set_tag((wl_proxy*) output, &AppWayland::proxyTag); } Output::~Output() { @@ -47,3 +50,12 @@ void Output::outputName(void* data, wl_output* output, const char* name) { } void Output::outputDescription(void* data, wl_output* output, const char* desc) {} +Output* Output::getForNative(wl_output* output) { + if (!output) return nullptr; + + if (wl_proxy_get_tag((wl_proxy*) output) == &AppWayland::proxyTag) { + return reinterpret_cast(wl_output_get_user_data(output)); + } + return nullptr; +} + diff --git a/wayland/cc/Output.hh b/wayland/cc/Output.hh index 8af4c421..1c68d4f2 100644 --- a/wayland/cc/Output.hh +++ b/wayland/cc/Output.hh @@ -27,6 +27,8 @@ namespace jwm { static void outputScale(void* data, wl_output* output, int factor); static void outputName(void* data, wl_output* output, const char* name); static void outputDescription(void* data, wl_output* output, const char* desc); + + static Output* getForNative(wl_output* output); private: Output(const Output&) = delete; Output(Output&&) = delete; diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index df1ef231..1a8bae33 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -24,11 +24,13 @@ static void pointerLeave(void* data, wl_pointer* pointer, uint32_t serial, wl_surface* surface) { auto self = reinterpret_cast(data); - if (self->_focusedSurface) - jwm::unref(&self->_focusedSurface); - - self->_mouseMask = 0; - self->_serial = 0; + if (auto window = self->_wm.getWindowForNative(surface)) { + if (window == self->_focusedSurface) { + jwm::unref(&self->_focusedSurface); + self->_mouseMask = 0; + self->_serial = 0; + } + } } static void pointerMotion(void* data, wl_pointer* pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) @@ -188,10 +190,13 @@ Pointer::~Pointer() { if (_pointer) wl_pointer_release(_pointer); + if (_surface) + wl_surface_destroy(_surface); } void Pointer::mouseUpdate(uint32_t x, uint32_t y, uint32_t mask) { auto window = _focusedSurface; + // printf("???\n"); if (!window) return; if (_lastMouseX == x && _lastMouseY == y) @@ -216,9 +221,9 @@ void Pointer::mouseUpdate(uint32_t x, uint32_t y, uint32_t mask) { } void Pointer::mouseUpdateUnscaled(uint32_t x, uint32_t y, uint32_t mask) { - auto window = _focusedSurface; - if (!window) return; - mouseUpdate(x * window->_scale, y * window->_scale, mask); + if (!_focusedSurface) return; + // printf("%i %i\n", x, y); + mouseUpdate(x * _focusedSurface->_scale, y * _focusedSurface->_scale, mask); } void Pointer::updateHotspot(int x, int y) { diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 89de285d..64c5e893 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -108,7 +108,7 @@ void WindowManagerWayland::runLoop() { if (libdecor_dispatch(decorCtx, -1) < 0) { fprintf(stderr, "error with dispatch\n"); // ??? - // break; + break; } } @@ -246,6 +246,7 @@ void WindowManagerWayland::registryHandleGlobalRemove(void* data, wl_registry *r } } WindowWayland* WindowManagerWayland::getWindowForNative(wl_surface* surface) { + if (!surface) return nullptr; // the tag makes it safe. Should:TM: be faster than searching a list every time const char* const* tag = wl_proxy_get_tag((wl_proxy*) surface); if (tag != &WindowWayland::_windowTag) { diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index 5345b50a..569c6a66 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -7,6 +7,7 @@ #include "impl/JNILocal.hh" #include #include +#include using namespace jwm; @@ -136,6 +137,7 @@ bool WindowWayland::resize(int width, int height) { _adaptSize(_width, _height); } */ + _oldScale = _scale; return true; } @@ -194,8 +196,8 @@ void WindowWayland::show() } ScreenInfo WindowWayland::getScreen() { - if (_output) { - return _output->getScreenInfo(); + if (!_outputs.empty()) { + return _outputs.front()->getScreenInfo(); } else { return { .id = -1, @@ -235,16 +237,35 @@ void jwm::WindowWayland::surfaceEnter(void* data, wl_surface* surface, wl_output // doesn't crash : ) WindowWayland* self = reinterpret_cast(data); - for (auto o : self->_windowManager.outputs) { - if (o->_output == output) { - self->_output = o; - self->_scale = o->scale; - self->_adaptSize(self->getUnscaledWidth(), self->getUnscaledHeight()); - break; + if (auto out = Output::getForNative(output)) { + self->_outputs.push_back(out); + int scale = 1; + for (auto i : self->_outputs) { + if (i->scale > scale) + scale = i->scale; + } + self->_scale = scale; + self->_adaptSize(self->getUnscaledWidth(), self->getUnscaledHeight()); + } +} +void jwm::WindowWayland::surfaceLeave(void* data, wl_surface* surface, wl_output* output) { + auto self = reinterpret_cast(data); + + if (auto out = Output::getForNative(output)) { + auto it = std::find(self->_outputs.begin(), self->_outputs.end(), out); + + if (it != self->_outputs.end()) + self->_outputs.erase(it); + + int scale = 1; + for (auto i : self->_outputs) { + if (i->scale > scale) + scale = i->scale; } + self->_scale = scale; + self->_adaptSize(self->getUnscaledWidth(), self->getUnscaledHeight()); } } -void jwm::WindowWayland::surfaceLeave(void* data, wl_surface* surface, wl_output* output) {} void jwm::WindowWayland::surfacePreferredBufferScale(void* data, wl_surface* surface, int factor) { WindowWayland* self = (WindowWayland*) data; if (factor < 1) { @@ -355,13 +376,9 @@ void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { ) ); dispatch(eventWindowResize.get()); - if (_scale != _oldScale) { - _windowManager._processCallbacks(); - } // In Java Wayland doesn't actually cause a frame: // however decorFrameCommit will cause a redraw anyway. // Not doing it in wayland lets me not cause an exception on hide. - _oldScale = _scale; } // JNI diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index 97a7012e..264aaec4 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -97,7 +97,7 @@ namespace jwm { ILayerWayland* _layer = nullptr; wl_surface* _waylandWindow = nullptr; libdecor_frame* _frame = nullptr; - Output* _output = nullptr; + std::list _outputs; wl_cursor_theme* theme = nullptr; static wl_surface_listener _surfaceListener; From 6e7fb7d3c7fbb126195d6da0774577258e2cb1cd Mon Sep 17 00:00:00 2001 From: TheDrawingCoding-Gamer Date: Wed, 20 Dec 2023 22:47:00 -0500 Subject: [PATCH 55/93] rework proxy tags, more checks --- wayland/cc/AppWayland.cc | 6 ++++++ wayland/cc/AppWayland.hh | 3 +++ wayland/cc/Buffer.hh | 2 +- wayland/cc/LayerGLWayland.cc | 6 +++--- wayland/cc/Output.cc | 5 ++++- wayland/cc/Output.hh | 3 ++- wayland/cc/Pointer.cc | 33 +++++++++++++++++++++--------- wayland/cc/Pointer.hh | 9 +++++--- wayland/cc/WindowManagerWayland.cc | 17 +++++++-------- wayland/cc/WindowWayland.cc | 16 +++++++++++---- wayland/cc/WindowWayland.hh | 12 +++++++++-- 11 files changed, 79 insertions(+), 33 deletions(-) diff --git a/wayland/cc/AppWayland.cc b/wayland/cc/AppWayland.cc index 598e74d1..e426fcf7 100644 --- a/wayland/cc/AppWayland.cc +++ b/wayland/cc/AppWayland.cc @@ -23,6 +23,12 @@ void jwm::AppWayland::terminate() { JNIEnv* jwm::AppWayland::getJniEnv() { return _jniEnv; } + +bool jwm::AppWayland::ownProxy(wl_proxy* proxy) { + if (!proxy) + return false; + return wl_proxy_get_tag(proxy) == &proxyTag; +} // JNI extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_App__1nStart(JNIEnv* env, jclass jclass, jobject launcher) { diff --git a/wayland/cc/AppWayland.hh b/wayland/cc/AppWayland.hh index 4013b841..defcc38c 100644 --- a/wayland/cc/AppWayland.hh +++ b/wayland/cc/AppWayland.hh @@ -6,6 +6,7 @@ #include #include "impl/Library.hh" #include "ScreenInfo.hh" +#include namespace jwm { extern class AppWayland { @@ -25,5 +26,7 @@ namespace jwm { WindowManagerWayland wm; static const char* proxyTag; + + static bool ownProxy(wl_proxy* proxy); } app; } diff --git a/wayland/cc/Buffer.hh b/wayland/cc/Buffer.hh index a536ba07..2fd0510e 100644 --- a/wayland/cc/Buffer.hh +++ b/wayland/cc/Buffer.hh @@ -11,7 +11,7 @@ namespace jwm { void *data, size_t dataSize); ~Buffer(); - wl_buffer* _buffer; + wl_buffer* _buffer = nullptr; wl_buffer* getBuffer() const { return _buffer; } diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index e6716a66..9b4c7ada 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -29,7 +29,6 @@ namespace jwm { void attach(WindowWayland* window) { fWindow = jwm::ref(window); fWindow->setLayer(this); - // Force a reconfigure; needed to draw title bar correctly if (fWindow->_windowManager._eglDisplay == EGL_NO_DISPLAY) { fWindow->_windowManager._eglDisplay = eglGetDisplay(window->_windowManager.display); @@ -128,7 +127,7 @@ namespace jwm { _eglWindow = wl_egl_window_create(fWindow->_waylandWindow, fWindow->getWidth(), fWindow->getHeight()); _surface = eglCreateWindowSurface(_display, _config, _eglWindow, nullptr); - if ( _eglWindow == EGL_NO_SURFACE ) { + if ( _surface == EGL_NO_SURFACE ) { throw std::runtime_error("couldn't get surface"); } } @@ -136,11 +135,12 @@ namespace jwm { } } void detachBuffer() override { - eglMakeCurrent(_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (_surface) { eglDestroySurface(_display, _surface); } _surface = nullptr; + // force the current layer to update + makeCurrentForced(); if (_eglWindow) { wl_egl_window_destroy(_eglWindow); } diff --git a/wayland/cc/Output.cc b/wayland/cc/Output.cc index 58cc2d90..4298d459 100644 --- a/wayland/cc/Output.cc +++ b/wayland/cc/Output.cc @@ -53,9 +53,12 @@ void Output::outputDescription(void* data, wl_output* output, const char* desc) Output* Output::getForNative(wl_output* output) { if (!output) return nullptr; - if (wl_proxy_get_tag((wl_proxy*) output) == &AppWayland::proxyTag) { + if (ownOutput(output)) { return reinterpret_cast(wl_output_get_user_data(output)); } return nullptr; } +bool Output::ownOutput(wl_output* output) { + return AppWayland::ownProxy((wl_proxy*) output); +} diff --git a/wayland/cc/Output.hh b/wayland/cc/Output.hh index 1c68d4f2..8ca461b9 100644 --- a/wayland/cc/Output.hh +++ b/wayland/cc/Output.hh @@ -10,7 +10,7 @@ namespace jwm { Output(wl_output* output, uint32_t name); ~Output(); - wl_output* _output; + wl_output* _output = nullptr; uint32_t _name; bool primary = false; int scale = 1; @@ -29,6 +29,7 @@ namespace jwm { static void outputDescription(void* data, wl_output* output, const char* desc); static Output* getForNative(wl_output* output); + static bool ownOutput(wl_output* output); private: Output(const Output&) = delete; Output(Output&&) = delete; diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index 1a8bae33..75564572 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -6,15 +6,19 @@ #include "KeyWayland.hh" #include #include + using namespace jwm; static void pointerEnter(void* data, wl_pointer* pointer, uint32_t serial, wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y ) { + if (!Pointer::ownPointer(pointer)) { + return; + } auto self = reinterpret_cast(data); - self->_serial = serial; if (auto window = self->_wm.getWindowForNative(surface)) { + self->_serial = serial; self->_focusedSurface = jwm::ref(window); window->setCursor(jwm::MouseCursor::ARROW); } @@ -23,18 +27,22 @@ static void pointerEnter(void* data, wl_pointer* pointer, uint32_t serial, static void pointerLeave(void* data, wl_pointer* pointer, uint32_t serial, wl_surface* surface) { + if (!Pointer::ownPointer(pointer)) { + return; + } auto self = reinterpret_cast(data); - if (auto window = self->_wm.getWindowForNative(surface)) { - if (window == self->_focusedSurface) { - jwm::unref(&self->_focusedSurface); - self->_mouseMask = 0; - self->_serial = 0; - } + if (self->_focusedSurface && self->_focusedSurface->isNativeSelf(surface)) { + jwm::unref(&self->_focusedSurface); + self->_mouseMask = 0; + self->_serial = 0; } } static void pointerMotion(void* data, wl_pointer* pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { + if (!Pointer::ownPointer(pointer)) { + return; + } auto self = reinterpret_cast(data); self->mouseUpdateUnscaled(wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y), self->_mouseMask); } @@ -184,6 +192,7 @@ Pointer::Pointer(wl_pointer* pointer, WindowManagerWayland* wm): { _surface = wl_compositor_create_surface(_wm.compositor); wl_pointer_add_listener(pointer, &_pointerListener, this); + wl_proxy_set_tag((wl_proxy*)pointer, &AppWayland::proxyTag); } Pointer::~Pointer() @@ -196,7 +205,6 @@ Pointer::~Pointer() void Pointer::mouseUpdate(uint32_t x, uint32_t y, uint32_t mask) { auto window = _focusedSurface; - // printf("???\n"); if (!window) return; if (_lastMouseX == x && _lastMouseY == y) @@ -222,8 +230,9 @@ void Pointer::mouseUpdate(uint32_t x, uint32_t y, uint32_t mask) { void Pointer::mouseUpdateUnscaled(uint32_t x, uint32_t y, uint32_t mask) { if (!_focusedSurface) return; - // printf("%i %i\n", x, y); - mouseUpdate(x * _focusedSurface->_scale, y * _focusedSurface->_scale, mask); + auto newX = x * _focusedSurface->_scale; + auto newY = y * _focusedSurface->_scale; + mouseUpdate(newX, newY, mask); } void Pointer::updateHotspot(int x, int y) { @@ -274,3 +283,7 @@ wl_cursor* Pointer::getCursorFor(int scale, jwm::MouseCursor cursor) { } return nullptr; } + +bool Pointer::ownPointer(wl_pointer* pointer) { + return AppWayland::ownProxy((wl_proxy*) pointer); +} diff --git a/wayland/cc/Pointer.hh b/wayland/cc/Pointer.hh index ab5ea0ec..41ee7c96 100644 --- a/wayland/cc/Pointer.hh +++ b/wayland/cc/Pointer.hh @@ -13,7 +13,7 @@ namespace jwm { Pointer(wl_pointer* pointer, jwm::WindowManagerWayland* wm); ~Pointer(); - wl_pointer* _pointer; + wl_pointer* _pointer = nullptr; wl_pointer* getPointer() const { return _pointer; } @@ -23,12 +23,12 @@ namespace jwm { return _serial; } - wl_surface* _surface; + wl_surface* _surface = nullptr; wl_surface* getSurface() const { return _surface; } - WindowWayland* _focusedSurface; + WindowWayland* _focusedSurface = nullptr; WindowWayland* getFocusedSurface() const { return _focusedSurface; } @@ -54,6 +54,9 @@ namespace jwm { wl_cursor_theme* getThemeFor(int scale); wl_cursor* getCursorFor(int scale, jwm::MouseCursor cursor); + static bool ownPointer(wl_pointer* pointer); + + private: Pointer(const Pointer& other) = delete; Pointer(Pointer&&) = delete; diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 64c5e893..fe2749b2 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -86,7 +86,11 @@ void WindowManagerWayland::runLoop() { while (_runLoop) { if (jwm::classes::Throwable::exceptionThrown(app.getJniEnv())) _runLoop = false; + while (wl_display_prepare_read(display) != 0) { + wl_display_dispatch_pending(display); + } + wl_display_flush(display); // block until event : ) int timeout = -1; if (_keyboard && _keyboard->_repeating && _keyboard->getFocus()) { @@ -102,14 +106,13 @@ void WindowManagerWayland::runLoop() { } if (poll(&ps[0], 2, timeout) < 0) { printf("error with pipe\n"); + wl_display_cancel_read(display); break; } if (ps[0].revents & POLLIN) { - if (libdecor_dispatch(decorCtx, -1) < 0) { - fprintf(stderr, "error with dispatch\n"); - // ??? - break; - } + wl_display_read_events(display); + } else { + wl_display_cancel_read(display); } if (ps[1].revents & POLLIN) { @@ -248,10 +251,8 @@ void WindowManagerWayland::registryHandleGlobalRemove(void* data, wl_registry *r WindowWayland* WindowManagerWayland::getWindowForNative(wl_surface* surface) { if (!surface) return nullptr; // the tag makes it safe. Should:TM: be faster than searching a list every time - const char* const* tag = wl_proxy_get_tag((wl_proxy*) surface); - if (tag != &WindowWayland::_windowTag) { + if (!WindowWayland::ownSurface(surface)) return nullptr; - } return reinterpret_cast(wl_surface_get_user_data(surface)); /* WindowWayland* myWindow = nullptr; diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index 569c6a66..152c27bf 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -28,8 +28,6 @@ libdecor_frame_interface WindowWayland::_libdecorFrameInterface = { .dismiss_popup = WindowWayland::decorFrameDismissPopup }; -const char* WindowWayland::_windowTag = "WindowWayland"; - WindowWayland::WindowWayland(JNIEnv* env, WindowManagerWayland& windowManager): jwm::Window(env), _windowManager(windowManager), @@ -57,12 +55,13 @@ void WindowWayland::setTitlebarVisible(bool isVisible) { } void WindowWayland::close() { - _windowManager.unregisterWindow(this); + _closed = true; hide(); if (_waylandWindow) { wl_surface_destroy(_waylandWindow); } _waylandWindow = nullptr; + _windowManager.unregisterWindow(this); // TODO: more destruction! } void WindowWayland::hide() { @@ -179,7 +178,7 @@ bool WindowWayland::init() { wl_surface_add_listener(_waylandWindow, &_surfaceListener, this); // unsure if listener data and user data are the same, so i do this for safety : ) wl_surface_set_user_data(_waylandWindow, this); - wl_proxy_set_tag((wl_proxy*) _waylandWindow, &_windowTag); + wl_proxy_set_tag((wl_proxy*) _waylandWindow, &AppWayland::proxyTag); _windowManager.registerWindow(this); _configured = false; @@ -190,6 +189,8 @@ void WindowWayland::show() _frame = libdecor_decorate(_windowManager.decorCtx, _waylandWindow, &_libdecorFrameInterface, this); libdecor_frame_map(_frame); wl_display_roundtrip(_windowManager.display); + + setTitle(_title); setTitlebarVisible(_titlebarVisible); _visible = true; @@ -248,6 +249,13 @@ void jwm::WindowWayland::surfaceEnter(void* data, wl_surface* surface, wl_output self->_adaptSize(self->getUnscaledWidth(), self->getUnscaledHeight()); } } +bool jwm::WindowWayland::isNativeSelf(wl_surface* surface) { + if (!_waylandWindow) return false; + return surface == _waylandWindow; +} +bool jwm::WindowWayland::ownSurface(wl_surface* surface) { + return AppWayland::ownProxy((wl_proxy*) surface); +} void jwm::WindowWayland::surfaceLeave(void* data, wl_surface* surface, wl_output* output) { auto self = reinterpret_cast(data); diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index 264aaec4..f27edc5f 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -12,6 +12,7 @@ namespace jwm { class WindowWayland: public jwm::Window { public: WindowWayland(JNIEnv* env, WindowManagerWayland& windowManager); + WindowWayland() = delete; ~WindowWayland() override; void getDecorations(int& left, int& top, int& right, int& bottom); @@ -67,6 +68,9 @@ namespace jwm { void _adaptSize(int newWidth, int newHeight); + bool isNativeSelf(wl_surface* surface); + static bool ownSurface(wl_surface* surface); + int _posX = -1; int _posY = -1; @@ -93,6 +97,12 @@ namespace jwm { std::string _title; bool _titlebarVisible = true; + bool _closed = false; + + bool isClosed() const { + return _closed; + } + WindowManagerWayland& _windowManager; ILayerWayland* _layer = nullptr; wl_surface* _waylandWindow = nullptr; @@ -106,7 +116,5 @@ namespace jwm { static wl_callback_listener _frameCallback; - static const char* _windowTag; - }; } From 32a841d6b5223db252c92c00b3896edccde1d995 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Fri, 22 Dec 2023 21:09:43 -0500 Subject: [PATCH 56/93] Dont trust EGL size --- wayland/cc/ILayerWayland.cc | 9 +++++ wayland/cc/ILayerWayland.hh | 5 ++- wayland/cc/LayerGLWayland.cc | 48 +++++++++++++++++++------ wayland/cc/LayerRasterWayland.cc | 1 + wayland/cc/WindowManagerWayland.cc | 57 ++++++++++++++++++------------ wayland/cc/WindowManagerWayland.hh | 2 +- wayland/cc/WindowWayland.cc | 47 ++++++++++++------------ wayland/cc/WindowWayland.hh | 1 + 8 files changed, 110 insertions(+), 60 deletions(-) create mode 100644 wayland/cc/ILayerWayland.cc diff --git a/wayland/cc/ILayerWayland.cc b/wayland/cc/ILayerWayland.cc new file mode 100644 index 00000000..d892979c --- /dev/null +++ b/wayland/cc/ILayerWayland.cc @@ -0,0 +1,9 @@ +#include "ILayerWayland.hh" +#include +#include "WindowWayland.hh" + +void jwm::ILayerWayland::detachBuffer() { + if (fWindow && fWindow->_waylandWindow) { + wl_surface_set_buffer_scale(fWindow->_waylandWindow, 1); + } +} diff --git a/wayland/cc/ILayerWayland.hh b/wayland/cc/ILayerWayland.hh index 2e10e226..054abeb5 100644 --- a/wayland/cc/ILayerWayland.hh +++ b/wayland/cc/ILayerWayland.hh @@ -3,10 +3,13 @@ #include namespace jwm { + class WindowWayland; class ILayerWayland: public ILayer { public: + WindowWayland* fWindow = nullptr; + virtual void attachBuffer() = 0; virtual void swapBuffers() = 0; - virtual void detachBuffer() = 0; + virtual void detachBuffer(); }; } diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index 9b4c7ada..d31acc13 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -22,11 +22,16 @@ namespace jwm { EGLDisplay _display = nullptr; EGLSurface _surface = nullptr; EGLConfig _config = nullptr; + bool _closed = false; LayerGL() = default; virtual ~LayerGL() = default; void attach(WindowWayland* window) { + if (_closed) { + fprintf(stderr, "already closed\n"); + throw std::runtime_error("Already closed"); + } fWindow = jwm::ref(window); fWindow->setLayer(this); if (fWindow->_windowManager._eglDisplay == EGL_NO_DISPLAY) { @@ -67,8 +72,11 @@ namespace jwm { throw std::runtime_error("Couldn't make context"); } } + if (fWindow->_waylandWindow) + wl_surface_set_buffer_scale(fWindow->_waylandWindow, 1); if (fWindow->_configured) attachBuffer(); + makeCurrentForced(); } void setVsyncMode(VSync v) override { @@ -76,29 +84,42 @@ namespace jwm { } void resize(int width, int height) override { + if (!_surface || !_eglWindow) return; // Make current to avoid artifacts in other windows - makeCurrent(); + makeCurrentForced(); glClearStencil(0); glClearColor(0, 0, 0, 255); glStencilMask(0xffffffff); glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - - // ??? + glViewport(0, 0, width, height); // God is dead if _eglWindow is null - if (_eglWindow) - wl_egl_window_resize(_eglWindow, width, height, 0, 0); - - wl_surface_set_buffer_scale(fWindow->_waylandWindow, fWindow->_scale); + if (_eglWindow && fWindow && fWindow->_waylandWindow) { + // HACK: make new window with new scale + // https://gitlab.freedesktop.org/mesa/mesa/-/issues/7217 + if (fWindow->_scale != fWindow->_oldScale) { + fprintf(stderr, "HACK: remaking egl window\n"); + detachBuffer(); + attachBuffer(); + } else wl_egl_window_resize(_eglWindow, width, height, 0, 0); + wl_surface_set_buffer_scale(fWindow->_waylandWindow, fWindow->getIntScale()); + fWindow->_oldScale = fWindow->_scale; + } } void swapBuffers() override { - makeCurrent(); - if (_surface) + if (_surface) { + makeCurrent(); eglSwapBuffers(_display, _surface); + } } void close() override { + if (_closed) { + fprintf(stderr, "already closed\n"); + return; + } + _closed = true; detachBuffer(); eglDestroyContext(_display, _context); @@ -125,16 +146,21 @@ namespace jwm { if (fWindow && fWindow->_waylandWindow) { if (!_eglWindow) { _eglWindow = wl_egl_window_create(fWindow->_waylandWindow, fWindow->getWidth(), fWindow->getHeight()); + + if (_eglWindow == nullptr) { + fprintf(stderr, "failed to get window\n"); + } _surface = eglCreateWindowSurface(_display, _config, _eglWindow, nullptr); if ( _surface == EGL_NO_SURFACE ) { - throw std::runtime_error("couldn't get surface"); + fprintf(stderr, "failed to get surface\n"); } + makeCurrentForced(); } - makeCurrentForced(); } } void detachBuffer() override { + ILayerWayland::detachBuffer(); if (_surface) { eglDestroySurface(_display, _surface); } diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index b4bd047e..5502b544 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -81,6 +81,7 @@ namespace jwm { } void detachBuffer() override { + ILayerWayland::detachBuffer(); if (_attached && fWindow && fWindow->_waylandWindow) { wl_surface_attach(fWindow->_waylandWindow, nullptr, 0, 0); // commit is not meant to be used in intermediate states diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index fe2749b2..1d174fce 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -1,5 +1,6 @@ #include "WindowManagerWayland.hh" #include "WindowWayland.hh" +#include #include #include #include @@ -15,7 +16,6 @@ #include #include "Log.hh" #include -#include #include "Output.hh" #include #include @@ -77,8 +77,9 @@ void WindowManagerWayland::runLoop() { } notifyFD = pipes[1]; fcntl(pipes[1], F_SETFL, O_NONBLOCK); // notifyLoop no blockie : ) + struct pollfd wayland_out = {.fd=wl_display_get_fd(display),.events=POLLOUT}; struct pollfd ps[] = { - {.fd=libdecor_get_fd(decorCtx), .events=POLLIN}, + {.fd=wl_display_get_fd(display), .events=POLLIN}, {.fd=pipes[0], .events=POLLIN}, }; @@ -90,7 +91,27 @@ void WindowManagerWayland::runLoop() { wl_display_dispatch_pending(display); } - wl_display_flush(display); + while (true) { + int res = wl_display_flush(display); + if (res >= 0) + break; + + switch (errno) { + case EPIPE: + wl_display_read_events(display); + throw std::system_error(errno, std::generic_category(), "connection to wayland server unexpectedly terminated"); + break; + case EAGAIN: + if (poll(&wayland_out, 1, -1) < 0) { + throw std::system_error(EPIPE, std::generic_category(), "poll failed"); + } + break; + default: + throw std::system_error(errno, std::generic_category(), "failed to flush requests"); + break; + } + + } // block until event : ) int timeout = -1; if (_keyboard && _keyboard->_repeating && _keyboard->getFocus()) { @@ -110,7 +131,10 @@ void WindowManagerWayland::runLoop() { break; } if (ps[0].revents & POLLIN) { - wl_display_read_events(display); + if (wl_display_read_events(display) < 0) { + std::perror("events failed"); + break; + } } else { wl_display_cancel_read(display); } @@ -124,7 +148,8 @@ void WindowManagerWayland::runLoop() { // don't test if we already calculated earlier _processKeyboard(); } - + + wl_display_dispatch_pending(display); notifyBool.store(false); } @@ -152,11 +177,7 @@ void WindowManagerWayland::_processCallbacks() { } } { - // copy window list in case one closes any other, invalidating some iterator in _nativeWindowToMy - std::vector copy; - for (auto& p : _nativeWindowToMy) { - copy.push_back(p.second); - } + std::list copy(_windows); // process redraw requests for (auto p : copy) { if (p->isRedrawRequested()) { @@ -254,13 +275,6 @@ WindowWayland* WindowManagerWayland::getWindowForNative(wl_surface* surface) { if (!WindowWayland::ownSurface(surface)) return nullptr; return reinterpret_cast(wl_surface_get_user_data(surface)); - /* - WindowWayland* myWindow = nullptr; - auto it = _nativeWindowToMy.find(surface); - if (it != _nativeWindowToMy.end()) - myWindow = it->second; - return myWindow; - */ } void WindowManagerWayland::seatCapabilities(void* data, wl_seat* seat, uint32_t capabilities) { auto self = reinterpret_cast(data); @@ -347,13 +361,13 @@ jwm::ByteBuf WindowManagerWayland::getClipboardContents(const std::string& type) } void WindowManagerWayland::registerWindow(WindowWayland* window) { - _nativeWindowToMy[window->_waylandWindow] = window; + _windows.push_back(window); } void WindowManagerWayland::unregisterWindow(WindowWayland* window) { - auto it = _nativeWindowToMy.find(window->_waylandWindow); - if (it != _nativeWindowToMy.end()) { - _nativeWindowToMy.erase(it); + auto it = std::find(_windows.begin(), _windows.end(), window); + if (it != _windows.end()) { + _windows.erase(it); } } @@ -380,7 +394,6 @@ wl_data_source_listener WindowManagerWayland::_sourceListener = { .cancelled = dataSourceCancelled }; void WindowManagerWayland::setClipboardContents(std::map&& c) { - assert(("create at least one window in order to use clipboard" && !_nativeWindowToMy.empty())); _myClipboardSource = c; if (!deviceManager) return; diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index 173b9bfc..b2f395ed 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -121,7 +121,7 @@ namespace jwm { int notifyFD = -1; std::atomic_bool notifyBool{false}; - std::map _nativeWindowToMy; + std::list _windows; std::map _myClipboardContents; std::map _myClipboardSource; std::list _currentMimeTypes; diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index 152c27bf..a2a81ceb 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -57,11 +57,6 @@ void WindowWayland::setTitlebarVisible(bool isVisible) { void WindowWayland::close() { _closed = true; hide(); - if (_waylandWindow) { - wl_surface_destroy(_waylandWindow); - } - _waylandWindow = nullptr; - _windowManager.unregisterWindow(this); // TODO: more destruction! } void WindowWayland::hide() { @@ -69,10 +64,15 @@ void WindowWayland::hide() { if (_layer) { _layer->detachBuffer(); } + if (_waylandWindow) { + wl_surface_destroy(_waylandWindow); + } + _waylandWindow = nullptr; if (_frame) { libdecor_frame_unref(_frame); } _frame = nullptr; + _windowManager.unregisterWindow(this); _configured = false; } void WindowWayland::maximize() { @@ -131,12 +131,6 @@ bool WindowWayland::resize(int width, int height) { return false; _width = width / _scale; _height = height / _scale; - /* - if (_visible) { - _adaptSize(_width, _height); - } - */ - _oldScale = _scale; return true; } @@ -166,6 +160,9 @@ int WindowWayland::getUnscaledHeight() { } float WindowWayland::getScale() { + return getIntScale(); +} +int WindowWayland::getIntScale() { return _scale; } wl_cursor* WindowWayland::_getCursorFor(jwm::MouseCursor cursor) { @@ -174,25 +171,21 @@ wl_cursor* WindowWayland::_getCursorFor(jwm::MouseCursor cursor) { return nullptr; } bool WindowWayland::init() { - _waylandWindow = wl_compositor_create_surface(_windowManager.compositor); - wl_surface_add_listener(_waylandWindow, &_surfaceListener, this); - // unsure if listener data and user data are the same, so i do this for safety : ) - wl_surface_set_user_data(_waylandWindow, this); - wl_proxy_set_tag((wl_proxy*) _waylandWindow, &AppWayland::proxyTag); - - _windowManager.registerWindow(this); - _configured = false; return true; } void WindowWayland::show() { - _frame = libdecor_decorate(_windowManager.decorCtx, _waylandWindow, &_libdecorFrameInterface, this); - libdecor_frame_map(_frame); + _waylandWindow = wl_compositor_create_surface(_windowManager.compositor); + wl_surface_add_listener(_waylandWindow, &_surfaceListener, this); + wl_proxy_set_tag((wl_proxy*) _waylandWindow, &AppWayland::proxyTag); + _windowManager.registerWindow(this); wl_display_roundtrip(_windowManager.display); - - + _frame = libdecor_decorate(_windowManager.decorCtx, _waylandWindow, &_libdecorFrameInterface, this); setTitle(_title); setTitlebarVisible(_titlebarVisible); + libdecor_frame_map(_frame); + + _configured = false; _visible = true; } @@ -202,7 +195,7 @@ ScreenInfo WindowWayland::getScreen() { } else { return { .id = -1, - .bounds = jwm::IRect::makeXYWH(0, 0, _width, _height), + .bounds = jwm::IRect::makeXYWH(0, 0, getWidth(), getHeight()), .isPrimary = false, .scale = _scale }; @@ -342,6 +335,7 @@ void jwm::WindowWayland::decorFrameConfigure(libdecor_frame* frame, libdecor_con if (self->_layer) self->_layer->attachBuffer(); } + self->_configured = true; if (self->_width != width || self->_height != height) { if (libdecor_frame_is_floating(frame)) { if (width > 0) @@ -353,7 +347,6 @@ void jwm::WindowWayland::decorFrameConfigure(libdecor_frame* frame, libdecor_con self->_adaptSize(width, height); } - self->_configured = true; } void jwm::WindowWayland::decorFrameClose(libdecor_frame* frame, void* userData) { WindowWayland* self = reinterpret_cast(userData); @@ -368,6 +361,10 @@ void jwm::WindowWayland::decorFrameCommit(libdecor_frame* frame, void* userData) void jwm::WindowWayland::decorFrameDismissPopup(libdecor_frame* frame, const char* seatName, void* userData) {} void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { using namespace classes; + if (!_configured) { + printf("???\n"); + return; + } if (newWidth == _width && newHeight == _height && _scale == _oldScale) return; _width = newWidth; _height = newHeight; diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index f27edc5f..a881c5c9 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -30,6 +30,7 @@ namespace jwm { int getHeight(); int getUnscaledHeight(); float getScale(); + int getIntScale(); void requestRedraw() { _isRedrawRequested = true; _windowManager.notifyLoop(); From 7c95878d9c15f8a8c0c3259536da9696b33e111b Mon Sep 17 00:00:00 2001 From: TheDrawingCoding-Gamer Date: Fri, 22 Dec 2023 21:47:37 -0500 Subject: [PATCH 57/93] do memleak frame --- wayland/cc/WindowWayland.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index a2a81ceb..a697738f 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -68,9 +68,14 @@ void WindowWayland::hide() { wl_surface_destroy(_waylandWindow); } _waylandWindow = nullptr; + // HACK: memory corruption issue in libdecor: + // https://gitlab.freedesktop.org/libdecor/libdecor/-/issues/59 + // Also causes protocol error that doesn't really make sense + /* if (_frame) { libdecor_frame_unref(_frame); } + */ _frame = nullptr; _windowManager.unregisterWindow(this); _configured = false; From 980ad0df8effbd1e794d1edad6d426db25eec96c Mon Sep 17 00:00:00 2001 From: TheDrawingCoding-Gamer Date: Sat, 23 Dec 2023 13:27:14 -0500 Subject: [PATCH 58/93] grab pointer and keyboard as unique_ptr --- wayland/cc/WindowManagerWayland.cc | 8 ++++---- wayland/cc/WindowManagerWayland.hh | 28 ++++------------------------ 2 files changed, 8 insertions(+), 28 deletions(-) diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 1d174fce..6af927df 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -280,17 +280,17 @@ void WindowManagerWayland::seatCapabilities(void* data, wl_seat* seat, uint32_t auto self = reinterpret_cast(data); if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && !self->_pointer) { - self->_pointer = new Pointer(wl_seat_get_pointer(seat), self); + self->_pointer.reset(new Pointer(wl_seat_get_pointer(seat), self)); } else if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && self->_pointer) { - self->_pointer = nullptr; + self->_pointer.reset(); } if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && !self->_keyboard) { - self->_keyboard = new Keyboard(wl_seat_get_keyboard(seat), self); + self->_keyboard.reset(new Keyboard(wl_seat_get_keyboard(seat), self)); } else if (!(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && self->_keyboard) { - self->_keyboard = nullptr; + self->_keyboard.reset(); } } void WindowManagerWayland::seatName(void* data, wl_seat* seat, const char* name) { diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index b2f395ed..32c1030c 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -20,6 +20,7 @@ #include #include "Keyboard.hh" #include "Pointer.hh" +#include namespace jwm { class WindowWayland; @@ -33,27 +34,6 @@ namespace jwm { void registerWindow(WindowWayland* window); void unregisterWindow(WindowWayland* window); - // XVisualInfo* pickVisual(); - // static int _xerrorhandler(Display* dsp, XErrorEvent* error); - // void _xi2IterateDevices(); - - // XVisualInfo* getVisualInfo() const { return x11VisualInfo; } - // XSetWindowAttributes& getSWA() { return x11SWA; } - // XIM getIM() const { return _im; } - /* - int getX11VisualDepth() const { - if (x11VisualInfo) { - return x11VisualInfo->depth; - } - return DefaultDepth(display, 0); - } - Visual* getX11Visual() const { - if (x11VisualInfo) { - return x11VisualInfo->visual; - } - return DefaultVisual(display, 0); - } - */ void _processCallbacks(); void _processKeyboard(); void notifyLoop(); @@ -90,11 +70,11 @@ namespace jwm { wl_data_device_manager* deviceManager = nullptr; // no multiseat? wl_seat* seat = nullptr; - Pointer* _pointer = nullptr; + std::unique_ptr _pointer = nullptr; Pointer* getPointer() const { - return _pointer; + return _pointer.get(); } - Keyboard* _keyboard = nullptr; + std::unique_ptr _keyboard = nullptr; wl_data_device* dataDevice = nullptr; wl_data_source* currentSource = nullptr; wl_data_offer* currentOffer = nullptr; From ba5192e28d1d9b6c85fb57689fa52ac74153edfb Mon Sep 17 00:00:00 2001 From: TheDrawingCoding-Gamer Date: Sat, 23 Dec 2023 14:09:49 -0500 Subject: [PATCH 59/93] scroll fix --- wayland/cc/Pointer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index 75564572..cfabdd0a 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -131,7 +131,7 @@ static void pointerAxis(void* data, wl_pointer* pointer, uint32_t time, float fvalue = static_cast(wl_fixed_to_double(value)); switch (axis) { case WL_POINTER_AXIS_VERTICAL_SCROLL: - self->_dY += fvalue; + self->_dY += -fvalue; break; case WL_POINTER_AXIS_HORIZONTAL_SCROLL: self->_dX += fvalue; From aae53240c113b41bf1385c821d68e79e10a4d277 Mon Sep 17 00:00:00 2001 From: TheDrawingCoding-Gamer Date: Sat, 23 Dec 2023 21:00:59 -0500 Subject: [PATCH 60/93] lock cursor --- wayland/CMakeLists.txt | 31 ++++++++++++++++++++----- wayland/cc/Pointer.cc | 36 ++++++++++++++++++++++++++++++ wayland/cc/Pointer.hh | 9 ++++++++ wayland/cc/WindowManagerWayland.cc | 3 +++ wayland/cc/WindowManagerWayland.hh | 4 ++++ wayland/cc/WindowWayland.cc | 18 +++++++++++++++ wayland/cc/WindowWayland.hh | 2 ++ wayland/java/WindowWayland.java | 4 +++- 8 files changed, 101 insertions(+), 6 deletions(-) diff --git a/wayland/CMakeLists.txt b/wayland/CMakeLists.txt index 47a98501..8c19fef3 100644 --- a/wayland/CMakeLists.txt +++ b/wayland/CMakeLists.txt @@ -1,9 +1,24 @@ -cmake_minimum_required(VERSION 3.9) - +cmake_minimum_required(VERSION 3.16) # prefer the newer GL library (GLVND) cmake_policy(SET CMP0072 NEW) +find_package(ECM REQUIRED NO_MODULE) +set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) + +include(FindWaylandProtocols) +include(FindWaylandScanner) +find_package(WaylandProtocols 1.32) +set_package_properties(WaylandProtocols PROPERTIES + TYPE REQUIRED +) +if (NOT WaylandProtocols_FOUND) + message(FATAL_ERROR "No protocols installed") +endif() +if (NOT WaylandScanner_FOUND) + message(FATAL_ERROR "No wayland-scanner") +endif() project(jwm LANGUAGES CXX) +project(cursorlock LANGUAGES C) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -20,13 +35,18 @@ file(GLOB SOURCES_CXX ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/*.cc ${CMAKE_CURRENT_LIST_DIR}/cc/*.cc ) file(GLOB SOURCES_CXX_IMPL ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/impl/*.cc) add_library(jwm SHARED ${SOURCES_OBJC} ${SOURCES_CXX} ${SOURCES_CXX_IMPL}) +add_library(cursorlock STATIC) +# set_property(TARGET cursorlock PROPERTY POSITION_INDEPENDENT_CODE ON) +ecm_add_wayland_client_protocol(cursorlock + PROTOCOL "${WaylandProtocols_DATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" + BASENAME pointer-constraints-unstable-v1 +) find_library(WAYLAND_CLIENT_LIB wayland-client) find_library(DECOR_LIB decor-0) find_library(WAYLAND_CURSOR wayland-cursor) find_library(XKBCOMMON xkbcommon) find_library(EGL EGL) find_library(WAYLAND_EGL wayland-egl) -# find_library(OPENGL_ES2 GLESv2) find_package(OpenGL REQUIRED) set(JAVA_HOME $ENV{JAVA_HOME}) if (NOT JAVA_HOME) @@ -39,11 +59,12 @@ if (NOT JAVA_HOME) endif() endif() -target_include_directories(jwm PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../shared/cc ${CMAKE_CURRENT_LIST_DIR}/../linux/cc ${JAVA_HOME}/include ${JAVA_HOME}/include/linux) +target_include_directories(jwm PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../shared/cc ${CMAKE_CURRENT_LIST_DIR}/../linux/cc ${JAVA_HOME}/include ${JAVA_HOME}/include/linux + ${CMAKE_CURRENT_LIST_DIR}/build) set_target_properties(jwm PROPERTIES OUTPUT_NAME "jwm_${JWM_ARCH}_wayland") target_link_libraries(jwm PRIVATE ${WAYLAND_CLIENT_LIB} ${DECOR_LIB} ${WAYLAND_CURSOR} ${XKBCOMMON}) target_link_libraries(jwm PRIVATE ${EGL} ${WAYLAND_EGL}) target_link_libraries(jwm PRIVATE OpenGL::GL) - +target_link_libraries(jwm PRIVATE cursorlock) diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index cfabdd0a..e774b821 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -287,3 +287,39 @@ wl_cursor* Pointer::getCursorFor(int scale, jwm::MouseCursor cursor) { bool Pointer::ownPointer(wl_pointer* pointer) { return AppWayland::ownProxy((wl_proxy*) pointer); } + +static void lockLocked(void* data, zwp_locked_pointer_v1* pointer) { + auto self = reinterpret_cast(data); + + self->_locked = true; +} +static void lockUnlocked(void* data, zwp_locked_pointer_v1* pointer) { + zwp_locked_pointer_v1_destroy(pointer); + + auto self = reinterpret_cast(data); + + self->_locked = false; + self->_lock = nullptr; +} + +static zwp_locked_pointer_v1_listener lockListener = { + .locked = lockLocked, + .unlocked = lockUnlocked +}; +void Pointer::lock() { + if (_wm.pointerConstraints && _focusedSurface && _focusedSurface->_waylandWindow) { + if (_lock) { + zwp_locked_pointer_v1_destroy(_lock); + } + _lock = zwp_pointer_constraints_v1_lock_pointer(_wm.pointerConstraints, _focusedSurface->_waylandWindow, + _pointer, nullptr, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT); + zwp_locked_pointer_v1_add_listener(_lock, &lockListener, this); + } +} +void Pointer::unlock() { + if (_lock) { + zwp_locked_pointer_v1_destroy(_lock); + } + _lock = nullptr; + _locked = false; +} diff --git a/wayland/cc/Pointer.hh b/wayland/cc/Pointer.hh index 41ee7c96..fbaef4f4 100644 --- a/wayland/cc/Pointer.hh +++ b/wayland/cc/Pointer.hh @@ -4,6 +4,7 @@ #include #include #include "MouseCursor.hh" +#include namespace jwm { class WindowManagerWayland; @@ -33,6 +34,14 @@ namespace jwm { return _focusedSurface; } + zwp_locked_pointer_v1* _lock = nullptr; + bool _locked = false; + void lock(); + void unlock(); + bool isLocked() { + return _locked; + } + uint32_t _lastMouseX; uint32_t _lastMouseY; float _dX = 0.0; diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 6af927df..5d6136c7 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -257,6 +257,9 @@ void WindowManagerWayland::registryHandleGlobal(void* data, wl_registry *registr // ??? this is a race condition (probably) but i have to do this to prevent crashes good->primary = true; self->outputs.push_back(good); + } else if (strcmp(interface, zwp_pointer_constraints_v1_interface.name) == 0) { + self->pointerConstraints = (zwp_pointer_constraints_v1*)wl_registry_bind(registry, name, + &zwp_pointer_constraints_v1_interface, 1); } } void WindowManagerWayland::registryHandleGlobalRemove(void* data, wl_registry *registry, uint32_t name) { diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index 32c1030c..235ae912 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -21,6 +21,7 @@ #include "Keyboard.hh" #include "Pointer.hh" #include +#include namespace jwm { class WindowWayland; @@ -70,6 +71,7 @@ namespace jwm { wl_data_device_manager* deviceManager = nullptr; // no multiseat? wl_seat* seat = nullptr; + zwp_pointer_constraints_v1* pointerConstraints = nullptr; std::unique_ptr _pointer = nullptr; Pointer* getPointer() const { return _pointer.get(); @@ -93,6 +95,8 @@ namespace jwm { return _keyboard->getState(); return nullptr; } + + libdecor* decorCtx = nullptr; EGLDisplay _eglDisplay = EGL_NO_DISPLAY; std::list outputs; diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index a697738f..0537694b 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -390,6 +390,17 @@ void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { // however decorFrameCommit will cause a redraw anyway. // Not doing it in wayland lets me not cause an exception on hide. } + +void jwm::WindowWayland::lockCursor(bool locked) { + auto pointer = _windowManager.getPointer(); + if (!pointer) return; + if (pointer->getFocusedSurface() == this) { + if (locked) + pointer->lock(); + else + pointer->unlock(); + } +} // JNI extern "C" JNIEXPORT jlong JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nMake @@ -521,3 +532,10 @@ extern "C" JNIEXPORT jfloat JNICALL Java_io_github_humbleui_jwm_WindowWayland__1 jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); return instance->getScale(); } + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nLockMouseCursor + (JNIEnv* env, jobject obj, jboolean locked) +{ + jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + instance->lockCursor(locked); +} diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index a881c5c9..78b02ddf 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -72,6 +72,8 @@ namespace jwm { bool isNativeSelf(wl_surface* surface); static bool ownSurface(wl_surface* surface); + void lockCursor(bool locked); + int _posX = -1; int _posY = -1; diff --git a/wayland/java/WindowWayland.java b/wayland/java/WindowWayland.java index 74441875..4ac14ac7 100644 --- a/wayland/java/WindowWayland.java +++ b/wayland/java/WindowWayland.java @@ -96,7 +96,8 @@ public Window hideMouseCursorUntilMoved(boolean value) { @Override public Window lockMouseCursor(boolean value) { - // TODO impl me! + assert _onUIThread() : "Should be run on UI thread"; + _nLockMouseCursor(value); return this; } @@ -235,4 +236,5 @@ public float getScale() { @ApiStatus.Internal public native void _nSetFullScreen(boolean isFullScreen); @ApiStatus.Internal public native boolean _nIsFullScreen(); @ApiStatus.Internal public native float _nGetScale(); + @ApiStatus.Internal public native void _nLockMouseCursor(boolean locked); } From b2af1e5a124a77aa950d8b3bfecadac004507e42 Mon Sep 17 00:00:00 2001 From: TheDrawingCoding-Gamer Date: Sun, 24 Dec 2023 13:11:27 -0500 Subject: [PATCH 61/93] Movement, request new lock --- wayland/cc/Pointer.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index e774b821..bef1404a 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -21,6 +21,7 @@ static void pointerEnter(void* data, wl_pointer* pointer, uint32_t serial, self->_serial = serial; self->_focusedSurface = jwm::ref(window); window->setCursor(jwm::MouseCursor::ARROW); + self->mouseUpdateUnscaled(wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y), self->_mouseMask); } } @@ -209,9 +210,9 @@ void Pointer::mouseUpdate(uint32_t x, uint32_t y, uint32_t mask) { return; if (_lastMouseX == x && _lastMouseY == y) return; + int movementX = x - _lastMouseX, movementY = y - _lastMouseY; _lastMouseX = x; _lastMouseY = y; - int movementX = 0, movementY = 0; jwm::JNILocal eventMove( app.getJniEnv(), @@ -298,8 +299,11 @@ static void lockUnlocked(void* data, zwp_locked_pointer_v1* pointer) { auto self = reinterpret_cast(data); - self->_locked = false; self->_lock = nullptr; + if (self->_locked) { + // Request a new lock on surface reenter + self->lock(); + } } static zwp_locked_pointer_v1_listener lockListener = { From f6202e66ea1781401f2b87f985e3e99dae3cb2b9 Mon Sep 17 00:00:00 2001 From: TheDrawingCoding-Gamer Date: Sun, 24 Dec 2023 13:44:56 -0500 Subject: [PATCH 62/93] hide cursor, no primary screen --- shared/java/App.java | 5 ++++- wayland/cc/Output.cc | 2 +- wayland/cc/Output.hh | 1 - wayland/cc/Pointer.cc | 32 ++++++++++++++++++++++++++++++ wayland/cc/Pointer.hh | 12 +++++++++++ wayland/cc/WindowManagerWayland.cc | 5 +---- wayland/cc/WindowWayland.cc | 28 ++++++++++++++++---------- wayland/cc/WindowWayland.hh | 2 ++ wayland/java/WindowWayland.java | 4 +++- 9 files changed, 73 insertions(+), 18 deletions(-) diff --git a/shared/java/App.java b/shared/java/App.java index 7a1c5a76..3275eafd 100644 --- a/shared/java/App.java +++ b/shared/java/App.java @@ -100,12 +100,15 @@ public static Screen[] getScreens() { * * @return primary desktop screen */ + @Nullable public static Screen getPrimaryScreen() { assert _onUIThread() : "Should be run on UI thread"; + if (Platform.CURRENT == Platform.WAYLAND) + return null; for (Screen s: getScreens()) if (s.isPrimary()) return s; - throw new IllegalStateException("Can't find primary screen"); + return null; } public static void openSymbolsPalette() { diff --git a/wayland/cc/Output.cc b/wayland/cc/Output.cc index 4298d459..1cb9d0a2 100644 --- a/wayland/cc/Output.cc +++ b/wayland/cc/Output.cc @@ -29,7 +29,7 @@ ScreenInfo Output::getScreenInfo() const { return { .id = _name, .bounds = jwm::IRect::makeXYWH(0, 0, width, height), - .isPrimary = primary, + .isPrimary = false, .scale = scale }; } diff --git a/wayland/cc/Output.hh b/wayland/cc/Output.hh index 8ca461b9..b137d5a3 100644 --- a/wayland/cc/Output.hh +++ b/wayland/cc/Output.hh @@ -12,7 +12,6 @@ namespace jwm { wl_output* _output = nullptr; uint32_t _name; - bool primary = false; int scale = 1; int width = 0; int height = 0; diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index bef1404a..5b3122c0 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -45,6 +45,7 @@ static void pointerMotion(void* data, wl_pointer* pointer, uint32_t time, return; } auto self = reinterpret_cast(data); + self->unhide(); self->mouseUpdateUnscaled(wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y), self->_mouseMask); } @@ -147,6 +148,8 @@ static void pointerFrame(void* data, wl_pointer* pointer) auto self = reinterpret_cast(data); auto win = self->_focusedSurface; if (!win) return; + // this is always sent so I can safely issue an unhide here + self->unhide(); if (self->_dX != 0.0f || self->_dY != 0.0f) { auto env = app.getJniEnv(); @@ -318,12 +321,41 @@ void Pointer::lock() { _lock = zwp_pointer_constraints_v1_lock_pointer(_wm.pointerConstraints, _focusedSurface->_waylandWindow, _pointer, nullptr, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT); zwp_locked_pointer_v1_add_listener(_lock, &lockListener, this); + hide(); } } void Pointer::unlock() { if (_lock) { zwp_locked_pointer_v1_destroy(_lock); } + unhide(); _lock = nullptr; _locked = false; } + +void Pointer::hide() { + if (_hidden) return; + _hidden = true; + if (_surface) { + wl_surface_attach(_surface, nullptr, 0, 0); + wl_surface_commit(_surface); + } +} + +void Pointer::unhide() { + if (!_hidden) return; + _hidden = false; + setCursor(_scale, _cursor); +} + +void Pointer::setCursor(int scale, jwm::MouseCursor cursor) { + _cursor = cursor; + _scale = scale; + auto wayCursor = getCursorFor(scale, cursor)->images[0]; + auto buf = wl_cursor_image_get_buffer(wayCursor); + wl_surface_attach(_surface, buf, 0, 0); + wl_surface_set_buffer_scale(_surface, scale); + wl_surface_damage_buffer(_surface, 0, 0, INT32_MAX, INT32_MAX); + updateHotspot(wayCursor->hotspot_x, wayCursor->hotspot_y); + wl_surface_commit(_surface); +} diff --git a/wayland/cc/Pointer.hh b/wayland/cc/Pointer.hh index fbaef4f4..35fb2f59 100644 --- a/wayland/cc/Pointer.hh +++ b/wayland/cc/Pointer.hh @@ -42,6 +42,13 @@ namespace jwm { return _locked; } + bool _hidden = false; + void hide(); + void unhide(); + bool isHidden() { + return _hidden; + } + uint32_t _lastMouseX; uint32_t _lastMouseY; float _dX = 0.0; @@ -63,6 +70,11 @@ namespace jwm { wl_cursor_theme* getThemeFor(int scale); wl_cursor* getCursorFor(int scale, jwm::MouseCursor cursor); + jwm::MouseCursor _cursor = jwm::MouseCursor::ARROW; + int _scale = 1; + + void setCursor(int scale, jwm::MouseCursor cursor); + static bool ownPointer(wl_pointer* pointer); diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 5d6136c7..748eb4f5 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -253,10 +253,7 @@ void WindowManagerWayland::registryHandleGlobal(void* data, wl_registry *registr wl_output* output = (wl_output*)wl_registry_bind(registry, name, &wl_output_interface, 2); Output* good = new Output(output, name); - if (self->outputs.empty()) - // ??? this is a race condition (probably) but i have to do this to prevent crashes - good->primary = true; - self->outputs.push_back(good); + self->outputs.push_back(std::move(good)); } else if (strcmp(interface, zwp_pointer_constraints_v1_interface.name) == 0) { self->pointerConstraints = (zwp_pointer_constraints_v1*)wl_registry_bind(registry, name, &zwp_pointer_constraints_v1_interface, 1); diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index 0537694b..6dbe29da 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -219,16 +219,7 @@ void WindowWayland::setVisible(bool isVisible) { void jwm::WindowWayland::setCursor(jwm::MouseCursor cursor) { if (!_windowManager.getPointer()) return; - auto wayCursor = _getCursorFor(cursor)->images[0]; - auto buf = wl_cursor_image_get_buffer(wayCursor); - auto cursorSurface = _windowManager.getCursorSurface(); - wl_surface_attach(cursorSurface, - wl_cursor_image_get_buffer(wayCursor), - 0, 0); - wl_surface_set_buffer_scale(cursorSurface, _scale); - wl_surface_damage_buffer(cursorSurface, 0, 0, INT32_MAX, INT32_MAX); - _windowManager.getPointer()->updateHotspot(wayCursor->hotspot_x, wayCursor->hotspot_y); - wl_surface_commit(cursorSurface); + _windowManager.getPointer()->setCursor(_scale, cursor); } // what do??? @@ -401,6 +392,16 @@ void jwm::WindowWayland::lockCursor(bool locked) { pointer->unlock(); } } +void jwm::WindowWayland::hideCursor(bool hidden) { + auto pointer = _windowManager.getPointer(); + if (!pointer) return; + if (pointer->getFocusedSurface() == this) { + if (hidden) + pointer->hide(); + else + pointer->unhide(); + } +} // JNI extern "C" JNIEXPORT jlong JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nMake @@ -539,3 +540,10 @@ extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nL jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); instance->lockCursor(locked); } + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nHideMouseCursor + (JNIEnv* env, jobject obj, jboolean hidden) +{ + jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + instance->hideCursor(hidden); +} diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index 78b02ddf..ee25b658 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -74,6 +74,8 @@ namespace jwm { void lockCursor(bool locked); + void hideCursor(bool hidden); + int _posX = -1; int _posY = -1; diff --git a/wayland/java/WindowWayland.java b/wayland/java/WindowWayland.java index 4ac14ac7..1ebae6ac 100644 --- a/wayland/java/WindowWayland.java +++ b/wayland/java/WindowWayland.java @@ -90,7 +90,8 @@ public Window setVisible(boolean isVisible) { @Override public Window hideMouseCursorUntilMoved(boolean value) { - // TODO impl me! + assert _onUIThread() : "Should be run on UI thread"; + _nHideMouseCursor(value); return this; } @@ -237,4 +238,5 @@ public float getScale() { @ApiStatus.Internal public native boolean _nIsFullScreen(); @ApiStatus.Internal public native float _nGetScale(); @ApiStatus.Internal public native void _nLockMouseCursor(boolean locked); + @ApiStatus.Internal public native void _nHideMouseCursor(boolean hidden); } From f09192ddd520c8698ed7416ac8a60efc8f12f2be Mon Sep 17 00:00:00 2001 From: TheDrawingCoding-Gamer Date: Sun, 24 Dec 2023 14:38:23 -0500 Subject: [PATCH 63/93] Relative mouse movement --- wayland/CMakeLists.txt | 7 +++- wayland/cc/Pointer.cc | 63 ++++++++++++++++++++---------- wayland/cc/Pointer.hh | 13 ++++-- wayland/cc/WindowManagerWayland.cc | 3 ++ wayland/cc/WindowManagerWayland.hh | 2 + 5 files changed, 63 insertions(+), 25 deletions(-) diff --git a/wayland/CMakeLists.txt b/wayland/CMakeLists.txt index 8c19fef3..ae10dd47 100644 --- a/wayland/CMakeLists.txt +++ b/wayland/CMakeLists.txt @@ -36,11 +36,16 @@ file(GLOB SOURCES_CXX ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/*.cc file(GLOB SOURCES_CXX_IMPL ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/impl/*.cc) add_library(jwm SHARED ${SOURCES_OBJC} ${SOURCES_CXX} ${SOURCES_CXX_IMPL}) add_library(cursorlock STATIC) +add_library(relativepointer STATIC) # set_property(TARGET cursorlock PROPERTY POSITION_INDEPENDENT_CODE ON) ecm_add_wayland_client_protocol(cursorlock PROTOCOL "${WaylandProtocols_DATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" BASENAME pointer-constraints-unstable-v1 ) +ecm_add_wayland_client_protocol(relativepointer + PROTOCOL "${WaylandProtocols_DATADIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml" + BASENAME relative-pointer-unstable-v1 +) find_library(WAYLAND_CLIENT_LIB wayland-client) find_library(DECOR_LIB decor-0) find_library(WAYLAND_CURSOR wayland-cursor) @@ -67,4 +72,4 @@ target_link_libraries(jwm PRIVATE ${WAYLAND_CLIENT_LIB} ${DECOR_LIB} ${WAYLAND_CURSOR} ${XKBCOMMON}) target_link_libraries(jwm PRIVATE ${EGL} ${WAYLAND_EGL}) target_link_libraries(jwm PRIVATE OpenGL::GL) -target_link_libraries(jwm PRIVATE cursorlock) +target_link_libraries(jwm PRIVATE cursorlock relativepointer) diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index 5b3122c0..8ca30911 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -21,7 +21,8 @@ static void pointerEnter(void* data, wl_pointer* pointer, uint32_t serial, self->_serial = serial; self->_focusedSurface = jwm::ref(window); window->setCursor(jwm::MouseCursor::ARROW); - self->mouseUpdateUnscaled(wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y), self->_mouseMask); + // frame probably isn't called so I immediately call + self->mouseUpdateUnscaled(wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y), 0, 0, self->_mouseMask); } } @@ -46,7 +47,12 @@ static void pointerMotion(void* data, wl_pointer* pointer, uint32_t time, } auto self = reinterpret_cast(data); self->unhide(); - self->mouseUpdateUnscaled(wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y), self->_mouseMask); + self->_absX = wl_fixed_to_int(surface_x); + self->_absY = wl_fixed_to_int(surface_y); + self->_movement = true; + // I only unhide here, bc i'm unsure of what exactly is wanted with mouse lock. + // This event isn't sent on mouse lock, only relative events are sent. + self->unhide(); } static void pointerButton(void* data, wl_pointer* pointer, uint32_t serial, @@ -82,8 +88,8 @@ static void pointerButton(void* data, wl_pointer* pointer, uint32_t serial, app.getJniEnv(), MouseButtonWayland::fromNative(button), false, - self->_lastMouseX, - self->_lastMouseY, + self->_absX, + self->_absY, jwm::KeyWayland::getModifiers(self->_wm.getXkbState()) ) ); @@ -115,8 +121,8 @@ static void pointerButton(void* data, wl_pointer* pointer, uint32_t serial, app.getJniEnv(), MouseButtonWayland::fromNative(button), true, - self->_lastMouseX, - self->_lastMouseY, + self->_absX, + self->_absY, jwm::KeyWayland::getModifiers(self->_wm.getXkbState()) ) ); @@ -148,8 +154,6 @@ static void pointerFrame(void* data, wl_pointer* pointer) auto self = reinterpret_cast(data); auto win = self->_focusedSurface; if (!win) return; - // this is always sent so I can safely issue an unhide here - self->unhide(); if (self->_dX != 0.0f || self->_dY != 0.0f) { auto env = app.getJniEnv(); @@ -162,8 +166,8 @@ static void pointerFrame(void* data, wl_pointer* pointer) 0.0f, 0.0f, 0.0f, - self->_lastMouseX, - self->_lastMouseY, + self->_absX * win->_scale, + self->_absY * win->_scale, jwm::KeyWayland::getModifiers(self->_wm.getXkbState()) ) ); @@ -172,6 +176,13 @@ static void pointerFrame(void* data, wl_pointer* pointer) self->_dX = 0.0f; self->_dY = 0.0f; } + if (self->_movement || self->_dXPos != 0.0 || self->_dYPos != 0.0) { + auto scale = win->_scale; + self->mouseUpdateUnscaled(self->_absX * scale, self->_absY * scale, static_cast(self->_dXPos * scale), static_cast(self->_dYPos * scale), self->_mouseMask); + self->_movement = false; + self->_dXPos = 0.0; + self->_dYPos = 0.0; + } } static void pointerAxisSource(void* data, wl_pointer* pointer, uint32_t source) {} @@ -190,6 +201,16 @@ wl_pointer_listener Pointer::_pointerListener = { .axis_discrete = pointerAxisDiscrete }; +static void relativePointerRelativeMotion(void* data, zwp_relative_pointer_v1* relative, uint32_t utime_hi, uint32_t utime_lo, + wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel) { + auto self = reinterpret_cast(data); + + self->_dXPos += static_cast(wl_fixed_to_double(dx)); + self->_dYPos += static_cast(wl_fixed_to_double(dy)); +} +static zwp_relative_pointer_v1_listener relativePointerListener = { + .relative_motion = relativePointerRelativeMotion +}; Pointer::Pointer(wl_pointer* pointer, WindowManagerWayland* wm): _pointer(pointer), _wm(*wm) @@ -197,6 +218,10 @@ Pointer::Pointer(wl_pointer* pointer, WindowManagerWayland* wm): _surface = wl_compositor_create_surface(_wm.compositor); wl_pointer_add_listener(pointer, &_pointerListener, this); wl_proxy_set_tag((wl_proxy*)pointer, &AppWayland::proxyTag); + if (_wm.relativePointerManager) { + _relative = zwp_relative_pointer_manager_v1_get_relative_pointer(_wm.relativePointerManager, pointer); + zwp_relative_pointer_v1_add_listener(_relative, &relativePointerListener, this); + } } Pointer::~Pointer() @@ -207,23 +232,18 @@ Pointer::~Pointer() wl_surface_destroy(_surface); } -void Pointer::mouseUpdate(uint32_t x, uint32_t y, uint32_t mask) { +void Pointer::mouseUpdate(uint32_t x, uint32_t y, int32_t relX, int32_t relY, uint32_t mask) { auto window = _focusedSurface; if (!window) return; - if (_lastMouseX == x && _lastMouseY == y) - return; - int movementX = x - _lastMouseX, movementY = y - _lastMouseY; - _lastMouseX = x; - _lastMouseY = y; jwm::JNILocal eventMove( app.getJniEnv(), jwm::classes::EventMouseMove::make(app.getJniEnv(), x, y, - movementX, - movementY, + relX, + relY, jwm::MouseButtonWayland::fromNativeMask(mask), // impl me! jwm::KeyWayland::getModifiers(_wm.getXkbState()) @@ -232,11 +252,14 @@ void Pointer::mouseUpdate(uint32_t x, uint32_t y, uint32_t mask) { window->dispatch(eventMove.get()); } -void Pointer::mouseUpdateUnscaled(uint32_t x, uint32_t y, uint32_t mask) { +void Pointer::mouseUpdateUnscaled(uint32_t x, uint32_t y, int32_t relX, int32_t relY, uint32_t mask) { if (!_focusedSurface) return; auto newX = x * _focusedSurface->_scale; auto newY = y * _focusedSurface->_scale; - mouseUpdate(newX, newY, mask); + auto newDX = relX * _focusedSurface->_scale; + auto newDY = relY * _focusedSurface->_scale; + + mouseUpdate(newX, newY, newDX, newDY, mask); } void Pointer::updateHotspot(int x, int y) { diff --git a/wayland/cc/Pointer.hh b/wayland/cc/Pointer.hh index 35fb2f59..0f3b1f26 100644 --- a/wayland/cc/Pointer.hh +++ b/wayland/cc/Pointer.hh @@ -5,6 +5,7 @@ #include #include "MouseCursor.hh" #include +#include namespace jwm { class WindowManagerWayland; @@ -49,8 +50,12 @@ namespace jwm { return _hidden; } - uint32_t _lastMouseX; - uint32_t _lastMouseY; + zwp_relative_pointer_v1* _relative = nullptr; + bool _movement = false; + int _absX = 0; + int _absY = 0; + float _dXPos = 0.0; + float _dYPos = 0.0; float _dX = 0.0; float _dY = 0.0; @@ -59,8 +64,8 @@ namespace jwm { static wl_pointer_listener _pointerListener; - void mouseUpdate(uint32_t x, uint32_t y, uint32_t mask); - void mouseUpdateUnscaled(uint32_t x, uint32_t y, uint32_t mask); + void mouseUpdate(uint32_t x, uint32_t y, int32_t relX, int32_t relY, uint32_t mask); + void mouseUpdateUnscaled(uint32_t x, uint32_t y, int32_t relX, int32_t relY, uint32_t mask); void updateHotspot(int x, int y); diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 748eb4f5..287a7130 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -257,6 +257,9 @@ void WindowManagerWayland::registryHandleGlobal(void* data, wl_registry *registr } else if (strcmp(interface, zwp_pointer_constraints_v1_interface.name) == 0) { self->pointerConstraints = (zwp_pointer_constraints_v1*)wl_registry_bind(registry, name, &zwp_pointer_constraints_v1_interface, 1); + } else if (strcmp(interface, zwp_relative_pointer_manager_v1_interface.name) == 0) { + self->relativePointerManager = (zwp_relative_pointer_manager_v1*)wl_registry_bind(registry, name, + &zwp_relative_pointer_manager_v1_interface, 1); } } void WindowManagerWayland::registryHandleGlobalRemove(void* data, wl_registry *registry, uint32_t name) { diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index 235ae912..61d396c6 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -22,6 +22,7 @@ #include "Pointer.hh" #include #include +#include namespace jwm { class WindowWayland; @@ -72,6 +73,7 @@ namespace jwm { // no multiseat? wl_seat* seat = nullptr; zwp_pointer_constraints_v1* pointerConstraints = nullptr; + zwp_relative_pointer_manager_v1* relativePointerManager = nullptr; std::unique_ptr _pointer = nullptr; Pointer* getPointer() const { return _pointer.get(); From 79170545061a933861199d82d458ca3423edb282 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Mon, 25 Dec 2023 16:37:43 -0500 Subject: [PATCH 64/93] fix mouse scaling --- wayland/cc/LayerRasterWayland.cc | 4 ++-- wayland/cc/Pointer.cc | 4 ++-- wayland/cc/WindowWayland.cc | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index 5502b544..a8302eca 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -64,8 +64,8 @@ namespace jwm { void close() override { detachBuffer(); - jwm::unref(&fWindow); - fWindow = nullptr; + if (fWindow) + jwm::unref(&fWindow); } void makeCurrentForced() override { diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index 8ca30911..a96fc4c0 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -46,7 +46,6 @@ static void pointerMotion(void* data, wl_pointer* pointer, uint32_t time, return; } auto self = reinterpret_cast(data); - self->unhide(); self->_absX = wl_fixed_to_int(surface_x); self->_absY = wl_fixed_to_int(surface_y); self->_movement = true; @@ -178,7 +177,8 @@ static void pointerFrame(void* data, wl_pointer* pointer) } if (self->_movement || self->_dXPos != 0.0 || self->_dYPos != 0.0) { auto scale = win->_scale; - self->mouseUpdateUnscaled(self->_absX * scale, self->_absY * scale, static_cast(self->_dXPos * scale), static_cast(self->_dYPos * scale), self->_mouseMask); + // rounding inaccuracy? + self->mouseUpdateUnscaled(self->_absX, self->_absY, static_cast(self->_dXPos), static_cast(self->_dYPos), self->_mouseMask); self->_movement = false; self->_dXPos = 0.0; self->_dYPos = 0.0; diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index 6dbe29da..3e303d10 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -38,7 +38,7 @@ WindowWayland::WindowWayland(JNIEnv* env, WindowManagerWayland& windowManager): WindowWayland::~WindowWayland() { // TODO: close gets called twice? - // close(); + close(); } @@ -56,6 +56,7 @@ void WindowWayland::setTitlebarVisible(bool isVisible) { void WindowWayland::close() { _closed = true; + if (_closed) return; hide(); // TODO: more destruction! } From 26182c772464cd0caaa66d4a93c08addcc202ed8 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Mon, 25 Dec 2023 16:41:33 -0500 Subject: [PATCH 65/93] Really fix mouse --- wayland/cc/Pointer.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index a96fc4c0..8c8af5bb 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -61,6 +61,7 @@ static void pointerButton(void* data, wl_pointer* pointer, uint32_t serial, auto self = reinterpret_cast(data); auto window = self->_focusedSurface; if (!window) return; + int scale = window->getIntScale(); if (state == 0) { // release switch (button) { @@ -87,8 +88,8 @@ static void pointerButton(void* data, wl_pointer* pointer, uint32_t serial, app.getJniEnv(), MouseButtonWayland::fromNative(button), false, - self->_absX, - self->_absY, + self->_absX * scale, + self->_absY * scale, jwm::KeyWayland::getModifiers(self->_wm.getXkbState()) ) ); @@ -120,8 +121,8 @@ static void pointerButton(void* data, wl_pointer* pointer, uint32_t serial, app.getJniEnv(), MouseButtonWayland::fromNative(button), true, - self->_absX, - self->_absY, + self->_absX * scale, + self->_absY * scale, jwm::KeyWayland::getModifiers(self->_wm.getXkbState()) ) ); From c041ebd53bd177dfeef1bdc3dd9eb28c606473db Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Tue, 26 Dec 2023 00:32:08 -0500 Subject: [PATCH 66/93] Fix jank related to resizing --- shared/java/Window.java | 6 ++++-- wayland/cc/WindowWayland.cc | 1 - wayland/java/WindowWayland.java | 4 +++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/shared/java/Window.java b/shared/java/Window.java index 7b5ce0a4..172486ce 100644 --- a/shared/java/Window.java +++ b/shared/java/Window.java @@ -63,7 +63,9 @@ public Window setLayer(@Nullable Layer layer) { if (layer != null) { layer.attach(this); _layer = layer; - accept(EventWindowScreenChange.INSTANCE); + // accepting this immediately causes crashes on wayland + if (Platform.CURRENT != Platform.WAYLAND) + accept(EventWindowScreenChange.INSTANCE); } return this; } @@ -423,7 +425,7 @@ public void accept(Event e) { if (e instanceof EventWindowScreenChange) { accept(new EventWindowResize(this)); - } else if (e instanceof EventWindowResize && Platform.CURRENT != Platform.X11 && Platform.CURRENT != Platform.WAYLAND) { + } else if (e instanceof EventWindowResize && Platform.CURRENT != Platform.X11) { accept(EventFrame.INSTANCE); } } diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index 3e303d10..f466edd0 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -359,7 +359,6 @@ void jwm::WindowWayland::decorFrameDismissPopup(libdecor_frame* frame, const cha void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { using namespace classes; if (!_configured) { - printf("???\n"); return; } if (newWidth == _width && newHeight == _height && _scale == _oldScale) return; diff --git a/wayland/java/WindowWayland.java b/wayland/java/WindowWayland.java index 1ebae6ac..fd99375c 100644 --- a/wayland/java/WindowWayland.java +++ b/wayland/java/WindowWayland.java @@ -85,7 +85,9 @@ public Window setTitlebarVisible(boolean value) { public Window setVisible(boolean isVisible) { assert _onUIThread() : "Should be run on UI thread"; _nSetVisible(isVisible); - return super.setVisible(true); + // this calls a screen change, which will cause a crash because GL context isn't ready yet + // return super.setVisible(true); + return this; } @Override From 6435c2fb33ac44344a729f70dd9e0c946e770be0 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Tue, 26 Dec 2023 00:58:40 -0500 Subject: [PATCH 67/93] Fix closing --- wayland/cc/WindowWayland.cc | 2 +- wayland/java/WindowWayland.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index f466edd0..a6b6d9bc 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -55,8 +55,8 @@ void WindowWayland::setTitlebarVisible(bool isVisible) { } void WindowWayland::close() { - _closed = true; if (_closed) return; + _closed = true; hide(); // TODO: more destruction! } diff --git a/wayland/java/WindowWayland.java b/wayland/java/WindowWayland.java index fd99375c..a8601472 100644 --- a/wayland/java/WindowWayland.java +++ b/wayland/java/WindowWayland.java @@ -77,6 +77,7 @@ public Window setIcon(File icon) { @Override public Window setTitlebarVisible(boolean value) { + assert _onUIThread() : "Should be run on UI thread"; _nSetTitlebarVisible(value); return this; } From ddff041c1fe1352ff2904bbda9416ea63b5781a0 Mon Sep 17 00:00:00 2001 From: TheDrawingCoding-Gamer Date: Sat, 30 Dec 2023 18:59:52 -0500 Subject: [PATCH 68/93] don't constantly set buffer size --- wayland/cc/LayerGLWayland.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index d31acc13..8eb1a52c 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -101,9 +101,10 @@ namespace jwm { fprintf(stderr, "HACK: remaking egl window\n"); detachBuffer(); attachBuffer(); - } else wl_egl_window_resize(_eglWindow, width, height, 0, 0); - wl_surface_set_buffer_scale(fWindow->_waylandWindow, fWindow->getIntScale()); - fWindow->_oldScale = fWindow->_scale; + wl_surface_set_buffer_scale(fWindow->_waylandWindow, fWindow->getIntScale()); + fWindow->_oldScale = fWindow->_scale; + } else + wl_egl_window_resize(_eglWindow, width, height, 0, 0); } } From 96ed37d6873865b36f98f352079872febaec57c1 Mon Sep 17 00:00:00 2001 From: TheDrawingCoding-Gamer Date: Sat, 30 Dec 2023 20:15:42 -0500 Subject: [PATCH 69/93] fix layer swapping --- shared/java/LayerRaster.java | 4 ++-- shared/java/Window.java | 2 +- wayland/cc/LayerGLWayland.cc | 10 +++++++--- wayland/cc/LayerRasterWayland.cc | 16 +++++++--------- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/shared/java/LayerRaster.java b/shared/java/LayerRaster.java index e097bfe0..4f5bd379 100644 --- a/shared/java/LayerRaster.java +++ b/shared/java/LayerRaster.java @@ -15,8 +15,8 @@ public LayerRaster() { @Override public void attach(Window window) { assert _onUIThread() : "Should be run on UI thread"; - _nAttach(window); _window = window; + _nAttach(window); } @Override @@ -81,4 +81,4 @@ public int getRowBytes() { @ApiStatus.Internal public native long _nGetPixelsPtr(); @ApiStatus.Internal public native int _nGetRowBytes(); @ApiStatus.Internal public native void _nClose(); -} \ No newline at end of file +} diff --git a/shared/java/Window.java b/shared/java/Window.java index 172486ce..a77f5060 100644 --- a/shared/java/Window.java +++ b/shared/java/Window.java @@ -61,8 +61,8 @@ public Window setLayer(@Nullable Layer layer) { _layer = null; } if (layer != null) { - layer.attach(this); _layer = layer; + layer.attach(this); // accepting this immediately causes crashes on wayland if (Platform.CURRENT != Platform.WAYLAND) accept(EventWindowScreenChange.INSTANCE); diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index 8eb1a52c..eaea177a 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -74,8 +74,10 @@ namespace jwm { } if (fWindow->_waylandWindow) wl_surface_set_buffer_scale(fWindow->_waylandWindow, 1); - if (fWindow->_configured) + if (fWindow->_configured) { attachBuffer(); + fWindow->dispatch(jwm::classes::EventWindowScreenChange::kInstance); + } makeCurrentForced(); } @@ -124,8 +126,10 @@ namespace jwm { detachBuffer(); eglDestroyContext(_display, _context); - if (fWindow) + if (fWindow) { + fWindow->setLayer(nullptr); jwm::unref(&fWindow); + } } void makeCurrentForced() override { @@ -198,7 +202,7 @@ extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerGL__1nAttach } extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerGL__1nReconfigure - (JNIEnv* env, jobject obj, jint width, jint height) { + (JNIEnv* env, jobject obj) { } extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerGL__1nResize diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index a8302eca..f74e77f2 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -22,9 +22,11 @@ namespace jwm { void attach(WindowWayland* window) { fWindow = jwm::ref(window); fWindow->setLayer(this); - resize(window->getWidth(), window->getHeight()); - if (fWindow->_configured) + if (fWindow->_configured) { attachBuffer(); + // delay this as much as possible + fWindow->dispatch(jwm::classes::EventWindowScreenChange::kInstance); + } } void resize(int width, int height) override { @@ -64,8 +66,10 @@ namespace jwm { void close() override { detachBuffer(); - if (fWindow) + if (fWindow) { + fWindow->setLayer(nullptr); jwm::unref(&fWindow); + } } void makeCurrentForced() override { @@ -77,7 +81,6 @@ namespace jwm { void attachBuffer() override { _attached = true; - swapBuffers(); } void detachBuffer() override { @@ -89,9 +92,6 @@ namespace jwm { } _attached = false; } - void reconfigure() { - swapBuffers(); - } }; } @@ -111,8 +111,6 @@ extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerRaster__1nAtt extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerRaster__1nReconfigure (JNIEnv* env, jobject obj) { - jwm::LayerRaster* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); - instance->reconfigure(); } extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_LayerRaster__1nResize From 38280f60ff85c8b45acdf693316e0da096c25158 Mon Sep 17 00:00:00 2001 From: TheDrawingCoding-Gamer Date: Sat, 30 Dec 2023 20:16:31 -0500 Subject: [PATCH 70/93] don't forget GL too --- shared/java/LayerGL.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/java/LayerGL.java b/shared/java/LayerGL.java index 5162c70a..b31be871 100644 --- a/shared/java/LayerGL.java +++ b/shared/java/LayerGL.java @@ -15,8 +15,8 @@ public LayerGL() { @Override public void attach(Window window) { assert _onUIThread() : "Should be run on UI thread"; - _nAttach(window); _window = window; + _nAttach(window); } @Override From 353d420799432fcf2673d1ed6944ae5e3ec7731b Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Wed, 3 Jan 2024 16:14:58 -0500 Subject: [PATCH 71/93] NO MORE LIBDECOR --- wayland/CMakeLists.txt | 26 +- wayland/cc/Buffer.hh | 2 + wayland/cc/Decoration.cc | 368 +++++++++++++++++++++++++++++ wayland/cc/Decoration.hh | 143 +++++++++++ wayland/cc/LayerGLWayland.cc | 2 +- wayland/cc/LayerRasterWayland.cc | 2 +- wayland/cc/Pointer.cc | 124 +++++++++- wayland/cc/Pointer.hh | 8 +- wayland/cc/WindowManagerWayland.cc | 38 +-- wayland/cc/WindowManagerWayland.hh | 13 +- wayland/cc/WindowWayland.cc | 140 +++-------- wayland/cc/WindowWayland.hh | 19 +- 12 files changed, 722 insertions(+), 163 deletions(-) create mode 100644 wayland/cc/Decoration.cc create mode 100644 wayland/cc/Decoration.hh diff --git a/wayland/CMakeLists.txt b/wayland/CMakeLists.txt index ae10dd47..0b18c608 100644 --- a/wayland/CMakeLists.txt +++ b/wayland/CMakeLists.txt @@ -18,7 +18,7 @@ if (NOT WaylandScanner_FOUND) message(FATAL_ERROR "No wayland-scanner") endif() project(jwm LANGUAGES CXX) -project(cursorlock LANGUAGES C) +project(protocols LANGUAGES C) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -35,19 +35,29 @@ file(GLOB SOURCES_CXX ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/*.cc ${CMAKE_CURRENT_LIST_DIR}/cc/*.cc ) file(GLOB SOURCES_CXX_IMPL ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/impl/*.cc) add_library(jwm SHARED ${SOURCES_OBJC} ${SOURCES_CXX} ${SOURCES_CXX_IMPL}) -add_library(cursorlock STATIC) -add_library(relativepointer STATIC) +add_library(protocols STATIC) # set_property(TARGET cursorlock PROPERTY POSITION_INDEPENDENT_CODE ON) -ecm_add_wayland_client_protocol(cursorlock +ecm_add_wayland_client_protocol(protocols PROTOCOL "${WaylandProtocols_DATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" BASENAME pointer-constraints-unstable-v1 ) -ecm_add_wayland_client_protocol(relativepointer +ecm_add_wayland_client_protocol(protocols PROTOCOL "${WaylandProtocols_DATADIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml" BASENAME relative-pointer-unstable-v1 ) +ecm_add_wayland_client_protocol(protocols + PROTOCOL "${WaylandProtocols_DATADIR}/stable/xdg-shell/xdg-shell.xml" + BASENAME xdg-shell +) +ecm_add_wayland_client_protocol(protocols + PROTOCOL "${WaylandProtocols_DATADIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml" + BASENAME xdg-decoration-unstable-v1 +) +ecm_add_wayland_client_protocol(protocols + PROTOCOL "${WaylandProtocols_DATADIR}/stable/viewporter/viewporter.xml" + BASENAME viewporter +) find_library(WAYLAND_CLIENT_LIB wayland-client) -find_library(DECOR_LIB decor-0) find_library(WAYLAND_CURSOR wayland-cursor) find_library(XKBCOMMON xkbcommon) find_library(EGL EGL) @@ -68,8 +78,8 @@ target_include_directories(jwm PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../shared/cc ${ ${CMAKE_CURRENT_LIST_DIR}/build) set_target_properties(jwm PROPERTIES OUTPUT_NAME "jwm_${JWM_ARCH}_wayland") -target_link_libraries(jwm PRIVATE ${WAYLAND_CLIENT_LIB} ${DECOR_LIB} +target_link_libraries(jwm PRIVATE ${WAYLAND_CLIENT_LIB} ${WAYLAND_CURSOR} ${XKBCOMMON}) target_link_libraries(jwm PRIVATE ${EGL} ${WAYLAND_EGL}) target_link_libraries(jwm PRIVATE OpenGL::GL) -target_link_libraries(jwm PRIVATE cursorlock relativepointer) +target_link_libraries(jwm PRIVATE protocols) diff --git a/wayland/cc/Buffer.hh b/wayland/cc/Buffer.hh index 2fd0510e..2cdfc90c 100644 --- a/wayland/cc/Buffer.hh +++ b/wayland/cc/Buffer.hh @@ -1,3 +1,5 @@ +#pragma once + #include #include #include diff --git a/wayland/cc/Decoration.cc b/wayland/cc/Decoration.cc new file mode 100644 index 00000000..77a01766 --- /dev/null +++ b/wayland/cc/Decoration.cc @@ -0,0 +1,368 @@ +#include "Decoration.hh" +#include "WindowWayland.hh" +#include "WindowManagerWayland.hh" +#include + +using namespace jwm; + +static unsigned int grey_data[] = {0xFF333333}; +// no image editor +// pure unadulterated programming +static unsigned int close_data[] = { + 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, +}; +static unsigned int min_data[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; +static unsigned int max_data[] = { + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, + 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, + 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, + 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, + 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, + 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, + 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +}; + +static void _decorationConfigure(void* data, zxdg_toplevel_decoration_v1* decoration, uint32_t mode) { + auto self = reinterpret_cast(data); + if (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE) { + self->_serverSide = true; + } else { + self->_serverSide = false; + } +} +static zxdg_toplevel_decoration_v1_listener _decorationListener = { + .configure = _decorationConfigure +}; + +static void _xdgSurfaceConfigure(void* data, xdg_surface* surface, uint32_t serial) { + auto self = reinterpret_cast(data); + auto& window = self->_window; + int width = 0, height = 0; + + if (self->_pendingWidth > 0) + width = self->_pendingWidth; + else + width = window._floatingWidth; + + if (self->_pendingHeight > 0) + height = self->_pendingHeight; + else + height = window._floatingHeight; + + self->_pendingWidth = 0; + self->_pendingHeight = 0; + if (self->_oldActive != self->_active) { + if (self->_active) + window.dispatch(classes::EventWindowFocusIn::kInstance); + else + window.dispatch(classes::EventWindowFocusOut::kInstance); + } + self->_oldActive = self->_active; + if (self->_oldMaximized != self->_maximized) { + if (self->_maximized) + window.dispatch(classes::EventWindowMaximize::kInstance); + } + self->_oldMaximized = self->_maximized; + if (self->_oldFullscreen != self->_fullscreen) { + if (self->_fullscreen) + window.dispatch(classes::EventWindowFullScreenEnter::kInstance); + else + window.dispatch(classes::EventWindowFullScreenExit::kInstance); + } + self->_oldFullscreen = self->_fullscreen; + if (!self->_configured) { + if (window._layer) + window._layer->attachBuffer(); + } + if (window.getUnscaledWidth() != width || window.getUnscaledHeight() != height) { + if (self->_floating) { + if (width > 0) { + window._floatingWidth = width; + } + if (height > 0) { + window._floatingHeight = height; + } + } + window._adaptSize(width, height); + self->_adaptSize(); + } + if (self->_serverSide) { + if (self->_top.surface) + self->_destroyDecorations(); + } else if (self->_isVisible) { + if (!self->_top.surface) + self->_showDecorations(); + } + wl_surface_commit(window._waylandWindow); + xdg_surface_ack_configure(self->_xdgSurface, serial); + self->_configured = true; +} + +static xdg_surface_listener _xdgSurfaceListener = { + .configure = _xdgSurfaceConfigure +}; + +static void _xdgToplevelConfigure(void* data, xdg_toplevel* toplevel, int width, int height, wl_array* states) { + auto self = reinterpret_cast(data); + + self->_pendingWidth = width; + self->_pendingHeight = height; + if (!self->_serverSide) { + self->_pendingWidth -= DECORATION_LEFT_WIDTH + DECORATION_RIGHT_WIDTH; + self->_pendingHeight -= DECORATION_TOP_HEIGHT + DECORATION_BOTTOM_HEIGHT; + } + + bool active = false; + bool maximized = false; + bool fullscreen = false; + bool floating = true; + for (uint32_t* pos = (uint32_t*)states->data; + (const char*)pos < ((const char*) states->data + states->size); + pos++) { + switch (*pos) { + case XDG_TOPLEVEL_STATE_MAXIMIZED: + maximized = true; + floating = false; + break; + case XDG_TOPLEVEL_STATE_ACTIVATED: + active = true; + break; + case XDG_TOPLEVEL_STATE_FULLSCREEN: + fullscreen = true; + floating = false; + break; + case XDG_TOPLEVEL_STATE_TILED_LEFT: + case XDG_TOPLEVEL_STATE_TILED_RIGHT: + case XDG_TOPLEVEL_STATE_TILED_TOP: + case XDG_TOPLEVEL_STATE_TILED_BOTTOM: + floating = false; + break; + } + } + self->_active = active; + self->_maximized = maximized; + self->_fullscreen = fullscreen; + self->_floating = floating; +} +static void _xdgToplevelClose(void* data, xdg_toplevel* toplevel) { + auto self = reinterpret_cast(data); + auto& window = self->_window; + + window.dispatch(classes::EventWindowCloseRequest::kInstance); +} + +static void _xdgToplevelConfigureBounds(void* data, xdg_toplevel* toplevel, int width, int height) { + // above version +} +static void _xdgToplevelWmCapabilities(void* data, xdg_toplevel* toplevel, wl_array* capabilities) { + // above version +} +static xdg_toplevel_listener _xdgToplevelListener = { + .configure = _xdgToplevelConfigure, + .close = _xdgToplevelClose, + .configure_bounds = _xdgToplevelConfigureBounds, + .wm_capabilities = _xdgToplevelWmCapabilities +}; + +const char* Decoration::proxyTag = "DecorationJWM"; +Decoration::Decoration(WindowWayland& window): + _window(window), + _wm(window._windowManager) +{ + _xdgSurface = xdg_wm_base_get_xdg_surface(_wm.xdgWm, window._waylandWindow); + xdg_surface_add_listener(_xdgSurface, &_xdgSurfaceListener, this); + _xdgToplevel = xdg_surface_get_toplevel(_xdgSurface); + xdg_toplevel_add_listener(_xdgToplevel, &_xdgToplevelListener, this); + if (_wm.decorationManager) { + _decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(_wm.decorationManager, _xdgToplevel); + zxdg_toplevel_decoration_v1_add_listener(_decoration, &_decorationListener, this); + // for the love of GOD do it for me + zxdg_toplevel_decoration_v1_set_mode(_decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + + } + + _decBuffer = Buffer::createShmBuffer(_wm.shm, 1, 1, WL_SHM_FORMAT_ARGB8888); + memcpy(_decBuffer->getData(), grey_data, 1 * sizeof(uint32_t)); + _closeBuffer = Buffer::createShmBuffer(_wm.shm, 9, 9, WL_SHM_FORMAT_ARGB8888); + memcpy(_closeBuffer->getData(), close_data, 9 * 9 * sizeof(uint32_t)); + _maxBuffer = Buffer::createShmBuffer(_wm.shm, 9, 9, WL_SHM_FORMAT_ARGB8888); + memcpy(_maxBuffer->getData(), max_data, 9 * 9 * sizeof(uint32_t)); + _minBuffer = Buffer::createShmBuffer(_wm.shm, 9, 9, WL_SHM_FORMAT_ARGB8888); + memcpy(_minBuffer->getData(), min_data, 9 * 9 * sizeof(uint32_t)); + + + // delay making parts until configure : ) + +} + +void Decoration::close() { + if (_top.surface) + _destroyDecorations(); + if (_decoration) + zxdg_toplevel_decoration_v1_destroy(_decoration); + xdg_toplevel_destroy(_xdgToplevel); + xdg_surface_destroy(_xdgSurface); +} + +void Decoration::_makePart(DecorationPart* decoration, Buffer* buf, bool opaque, int x, int y, int width, int height) { + decoration->surface = wl_compositor_create_surface(_wm.compositor); + wl_proxy_set_tag((wl_proxy*)decoration->surface, &proxyTag); + wl_proxy_set_user_data((wl_proxy*)decoration->surface, this); + decoration->subsurface = wl_subcompositor_get_subsurface(_wm.subcompositor, decoration->surface, _window._waylandWindow); + wl_subsurface_set_position(decoration->subsurface, x, y); + decoration->viewport = wp_viewporter_get_viewport(_wm.viewporter, decoration->surface); + wp_viewport_set_destination(decoration->viewport, width, height); + if (buf) + wl_surface_attach(decoration->surface, buf->getBuffer(), 0, 0); + + if (opaque) { + wl_region* region = wl_compositor_create_region(_wm.compositor); + wl_region_add(region, 0, 0, width, height); + wl_surface_set_opaque_region(decoration->surface, region); + wl_surface_commit(decoration->surface); + wl_region_destroy(region); + } else + wl_surface_commit(decoration->surface); +} + +void Decoration::_resizeDecoration(DecorationPart* decoration, int x, int y, int width, int height) { + if (decoration->surface) { + wl_subsurface_set_position(decoration->subsurface, x, y); + wp_viewport_set_destination(decoration->viewport, width, height); + wl_surface_commit(decoration->surface); + } +} +void Decoration::_destroyDecoration(DecorationPart* decoration) { + if (decoration->subsurface) { + wl_subsurface_destroy(decoration->subsurface); + } + if (decoration->surface) + wl_surface_destroy(decoration->surface); + if (decoration->viewport) + wp_viewport_destroy(decoration->viewport); + decoration->subsurface = nullptr; + decoration->surface = nullptr; + decoration->viewport = nullptr; +} + +void Decoration::_destroyDecorations() { + _destroyDecoration(&_top); + _destroyDecoration(&_left); + _destroyDecoration(&_right); + _destroyDecoration(&_bottom); + _destroyDecoration(&_close); + _destroyDecoration(&_min); + _destroyDecoration(&_max); +} + +void Decoration::_showDecorations() { + _makePart(&_top, _decBuffer, true, DECORATION_TOP_X, DECORATION_TOP_Y, DECORATION_TOP_WIDTH(_window), DECORATION_TOP_HEIGHT); + _makePart(&_left, _decBuffer, true, DECORATION_LEFT_X, DECORATION_LEFT_Y, DECORATION_LEFT_WIDTH, DECORATION_LEFT_HEIGHT(_window)); + _makePart(&_right, _decBuffer, true, DECORATION_RIGHT_X(_window), DECORATION_RIGHT_Y, DECORATION_RIGHT_WIDTH, DECORATION_RIGHT_HEIGHT(_window)); + _makePart(&_bottom, _decBuffer, true, DECORATION_BOTTOM_X, DECORATION_BOTTOM_Y(_window), DECORATION_BOTTOM_WIDTH(_window), DECORATION_BOTTOM_HEIGHT); + + _makePart(&_close, _closeBuffer, false, DECORATION_CLOSE_X(_window), DECORATION_CLOSE_Y, DECORATION_CLOSE_WIDTH, DECORATION_CLOSE_HEIGHT); + _makePart(&_max, _maxBuffer, false, DECORATION_MAX_X(_window), DECORATION_MAX_Y, DECORATION_MAX_WIDTH, DECORATION_MAX_HEIGHT); + _makePart(&_min, _minBuffer, false, DECORATION_MIN_X(_window), DECORATION_MIN_Y, DECORATION_MIN_WIDTH, DECORATION_MIN_HEIGHT); + +} + +void Decoration::_adaptSize() { + _resizeDecoration(&_top, DECORATION_TOP_X, DECORATION_TOP_Y, DECORATION_TOP_WIDTH(_window), DECORATION_TOP_HEIGHT); + _resizeDecoration(&_left, DECORATION_LEFT_X, DECORATION_LEFT_Y, DECORATION_LEFT_WIDTH, DECORATION_LEFT_HEIGHT(_window)); + _resizeDecoration(&_right, DECORATION_RIGHT_X(_window), DECORATION_RIGHT_Y, DECORATION_RIGHT_WIDTH, DECORATION_RIGHT_HEIGHT(_window)); + _resizeDecoration(&_bottom, DECORATION_BOTTOM_X, DECORATION_BOTTOM_Y(_window), DECORATION_BOTTOM_WIDTH(_window), DECORATION_BOTTOM_HEIGHT); + + + _resizeDecoration(&_close, DECORATION_CLOSE_X(_window), DECORATION_CLOSE_Y, DECORATION_CLOSE_WIDTH, DECORATION_CLOSE_HEIGHT); + _resizeDecoration(&_min, DECORATION_MIN_X(_window), DECORATION_MIN_Y, DECORATION_MIN_WIDTH, DECORATION_MIN_HEIGHT); + _resizeDecoration(&_max, DECORATION_MAX_X(_window), DECORATION_MAX_Y, DECORATION_MAX_WIDTH, DECORATION_MAX_HEIGHT); +} + +bool Decoration::ownDecorationSurface(wl_surface* surface) { + return wl_proxy_get_tag((wl_proxy*)surface) == &proxyTag; +} + +Decoration* Decoration::getDecorationForSurface(wl_surface* surface, DecorationFocus* focus) { + if (ownDecorationSurface(surface)) { + Decoration* decoration = (Decoration*)wl_proxy_get_user_data((wl_proxy*) surface); + if (surface == decoration->_top.surface) { + *focus = DECORATION_FOCUS_TOP; + } else if (surface == decoration->_left.surface) { + *focus = DECORATION_FOCUS_LEFT; + } else if (surface == decoration->_right.surface) { + *focus = DECORATION_FOCUS_RIGHT; + } else if (surface == decoration->_bottom.surface) { + *focus = DECORATION_FOCUS_BOTTOM; + } else if (surface == decoration->_close.surface) { + *focus = DECORATION_FOCUS_CLOSE_BUTTON; + } else if (surface == decoration->_min.surface) { + *focus = DECORATION_FOCUS_MIN_BUTTON; + } else if (surface == decoration->_max.surface) { + *focus = DECORATION_FOCUS_MAX_BUTTON; + } + + return decoration; + } else { + *focus = DECORATION_FOCUS_MAIN; + return nullptr; + } +} + +void Decoration::setVisible(bool isVisible) { + if (isVisible != _isVisible) { + _isVisible = isVisible; + if (isVisible) { + if (_decoration) { + zxdg_toplevel_decoration_v1_set_mode(_decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + } + } else { + if (_decoration) { + zxdg_toplevel_decoration_v1_set_mode(_decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); + } + _destroyDecorations(); + } + + + } +} + +void Decoration::setTitle(const std::string& title) { + xdg_toplevel_set_title(_xdgToplevel, title.c_str()); + // grab a copy - unused for now but maybe a text renderer will eventually be pulled in + _title = title; +} + +void Decoration::getBorders(int& left, int& top, int& right, int& bottom) { + if (_serverSide) { + left = 0; + top = 0; + right = 0; + bottom = 0; + } else { + left = DECORATION_LEFT_WIDTH; + top = DECORATION_TOP_HEIGHT; + right = DECORATION_RIGHT_WIDTH; + bottom = DECORATION_BOTTOM_HEIGHT; + } +} diff --git a/wayland/cc/Decoration.hh b/wayland/cc/Decoration.hh new file mode 100644 index 00000000..082911be --- /dev/null +++ b/wayland/cc/Decoration.hh @@ -0,0 +1,143 @@ +#pragma once + +#include +#include +#include +#include +#include +#include "Buffer.hh" +#include + +#define DECORATION_WIDTH 10 + +#define DECORATION_TOP_X 0 +#define DECORATION_TOP_Y -(DECORATION_TOP_HEIGHT) +#define DECORATION_TOP_WIDTH(window) window.getUnscaledWidth() +#define DECORATION_TOP_HEIGHT DECORATION_WIDTH * 3 + +#define DECORATION_LEFT_X -(DECORATION_WIDTH) +#define DECORATION_LEFT_Y -(DECORATION_TOP_HEIGHT) +#define DECORATION_LEFT_WIDTH DECORATION_WIDTH +#define DECORATION_LEFT_HEIGHT(window) window.getUnscaledHeight() + DECORATION_TOP_HEIGHT + DECORATION_WIDTH + +#define DECORATION_RIGHT_X(window) window.getUnscaledWidth() +#define DECORATION_RIGHT_Y -(DECORATION_TOP_HEIGHT) +#define DECORATION_RIGHT_WIDTH DECORATION_WIDTH +#define DECORATION_RIGHT_HEIGHT(window) window.getUnscaledHeight() + DECORATION_TOP_HEIGHT + DECORATION_WIDTH + +#define DECORATION_BOTTOM_X 0 +#define DECORATION_BOTTOM_Y(window) window.getUnscaledHeight() +#define DECORATION_BOTTOM_WIDTH(window) window.getUnscaledWidth() +#define DECORATION_BOTTOM_HEIGHT DECORATION_WIDTH + +#define DECORATION_CLOSE_X(window) window.getUnscaledWidth() - 10 +#define DECORATION_CLOSE_Y -20 +#define DECORATION_CLOSE_WIDTH 9 +#define DECORATION_CLOSE_HEIGHT 9 + +#define DECORATION_MAX_X(window) (DECORATION_CLOSE_X(window)) - 10 +#define DECORATION_MAX_Y -20 +#define DECORATION_MAX_WIDTH 9 +#define DECORATION_MAX_HEIGHT 9 + +#define DECORATION_MIN_X(window) (DECORATION_MAX_X(window)) - 10 +#define DECORATION_MIN_Y -20 +#define DECORATION_MIN_WIDTH 9 +#define DECORATION_MIN_HEIGHT 9 + +namespace jwm { + class WindowManagerWayland; + class WindowWayland; + struct DecorationPart { + wl_surface* surface = nullptr; + wl_subsurface* subsurface = nullptr; + wp_viewport* viewport = nullptr; + }; + enum DecorationFocus { + DECORATION_FOCUS_MAIN, + DECORATION_FOCUS_TOP, + DECORATION_FOCUS_LEFT, + DECORATION_FOCUS_RIGHT, + DECORATION_FOCUS_BOTTOM, + DECORATION_FOCUS_CLOSE_BUTTON, + DECORATION_FOCUS_MAX_BUTTON, + DECORATION_FOCUS_MIN_BUTTON + }; + // Creation is mapping + // Closing is unmapping + class Decoration { + public: + Decoration() = delete; + Decoration(WindowWayland& window); + ~Decoration(); + + WindowManagerWayland& _wm; + WindowWayland& _window; + + Buffer* _decBuffer; + Buffer* _closeBuffer; + Buffer* _maxBuffer; + Buffer* _minBuffer; + + DecorationPart _top; + DecorationPart _left; + DecorationPart _right; + DecorationPart _bottom; + + DecorationPart _close; + DecorationPart _max; + DecorationPart _min; + // May be null at runtime + zxdg_toplevel_decoration_v1* _decoration = nullptr; + + xdg_surface* _xdgSurface = nullptr; + xdg_toplevel* _xdgToplevel = nullptr; + + bool _serverSide = false; + int _pendingWidth = 0; + int _pendingHeight = 0; + bool _oldActive = false; + // : ) + bool _active = true; + bool _oldMaximized = false; + bool _maximized = false; + bool _oldFullscreen = false; + bool _fullscreen = false; + bool _floating = true; + bool _configured = false; + // unmap and dispose + void close(); + + void _makePart(DecorationPart* part, Buffer* buf, bool opaque, int x, int y, int width, int height); + void _resizeDecoration(DecorationPart* part, int x, int y, int width, int height); + void _destroyDecoration(DecorationPart* part); + + void _adaptSize(); + void _destroyDecorations(); + void _showDecorations(); + + static const char* proxyTag; + static bool ownDecorationSurface(wl_surface* surface); + static Decoration* getDecorationForSurface(wl_surface* surface, DecorationFocus* focus); + + std::string _title; + + void setTitle(const std::string& title); + + bool _isVisible = true; + void setVisible(bool isVisible); + + void getBorders(int& left, int& top, int& right, int& bottom); + + + private: + Decoration(Decoration&& other) = delete; + Decoration& operator=(Decoration&& other) = delete; + + Decoration(Decoration& other) = delete; + Decoration& operator=(Decoration& other) = delete; + + + + }; +} diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index eaea177a..ecdba2f3 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -74,7 +74,7 @@ namespace jwm { } if (fWindow->_waylandWindow) wl_surface_set_buffer_scale(fWindow->_waylandWindow, 1); - if (fWindow->_configured) { + if (fWindow->isConfigured()) { attachBuffer(); fWindow->dispatch(jwm::classes::EventWindowScreenChange::kInstance); } diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index f74e77f2..156d3b91 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -22,7 +22,7 @@ namespace jwm { void attach(WindowWayland* window) { fWindow = jwm::ref(window); fWindow->setLayer(this); - if (fWindow->_configured) { + if (fWindow->isConfigured()) { attachBuffer(); // delay this as much as possible fWindow->dispatch(jwm::classes::EventWindowScreenChange::kInstance); diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index 8c8af5bb..36def276 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -6,6 +6,7 @@ #include "KeyWayland.hh" #include #include +#include using namespace jwm; @@ -17,13 +18,20 @@ static void pointerEnter(void* data, wl_pointer* pointer, uint32_t serial, return; } auto self = reinterpret_cast(data); + DecorationFocus focus = DECORATION_FOCUS_MAIN; if (auto window = self->_wm.getWindowForNative(surface)) { self->_serial = serial; self->_focusedSurface = jwm::ref(window); - window->setCursor(jwm::MouseCursor::ARROW); + window->setCursorMaybe(jwm::MouseCursor::ARROW, true); // frame probably isn't called so I immediately call self->mouseUpdateUnscaled(wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y), 0, 0, self->_mouseMask); + } else if (auto decoration = Decoration::getDecorationForSurface(surface, &focus)) { + self->_serial = serial; + auto window = jwm::ref(&decoration->_window); + self->_focusedSurface = window; + window->setCursorMaybe(jwm::MouseCursor::ARROW, true); } + self->_decorationFocus = focus; } static void pointerLeave(void* data, wl_pointer* pointer, uint32_t serial, @@ -33,10 +41,43 @@ static void pointerLeave(void* data, wl_pointer* pointer, uint32_t serial, return; } auto self = reinterpret_cast(data); - if (self->_focusedSurface && self->_focusedSurface->isNativeSelf(surface)) { + DecorationFocus focus = DECORATION_FOCUS_MAIN; + Decoration* decoration = Decoration::getDecorationForSurface(surface, &focus); + if (self->_focusedSurface && self->_focusedSurface->isNativeSelf(surface) && (!decoration || !decoration->_window.isNativeSelf(surface))) { jwm::unref(&self->_focusedSurface); self->_mouseMask = 0; self->_serial = 0; + self->_decorationFocus = DECORATION_FOCUS_MAIN; + } +} +static xdg_toplevel_resize_edge resizeEdge(DecorationFocus focus, WindowWayland& window, int x, int y) { + switch (focus) { + case DECORATION_FOCUS_MAIN: + // ??? + return XDG_TOPLEVEL_RESIZE_EDGE_NONE; + case DECORATION_FOCUS_TOP: + if (y < DECORATION_TOP_HEIGHT / 2) + return XDG_TOPLEVEL_RESIZE_EDGE_TOP; + else + return XDG_TOPLEVEL_RESIZE_EDGE_NONE; + case DECORATION_FOCUS_LEFT: + if (y < DECORATION_TOP_HEIGHT / 2) + return XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; + else if (y > DECORATION_BOTTOM_Y(window)) + return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT; + else + return XDG_TOPLEVEL_RESIZE_EDGE_LEFT; + case DECORATION_FOCUS_RIGHT: + if (y < DECORATION_TOP_HEIGHT / 2) + return XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; + else if (y > DECORATION_BOTTOM_Y(window)) + return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT; + else + return XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; + case DECORATION_FOCUS_BOTTOM: + return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM; + default: + return XDG_TOPLEVEL_RESIZE_EDGE_NONE; } } static void pointerMotion(void* data, wl_pointer* pointer, uint32_t time, @@ -46,12 +87,46 @@ static void pointerMotion(void* data, wl_pointer* pointer, uint32_t time, return; } auto self = reinterpret_cast(data); - self->_absX = wl_fixed_to_int(surface_x); - self->_absY = wl_fixed_to_int(surface_y); - self->_movement = true; + self->unhide(); + if (self->_decorationFocus != DECORATION_FOCUS_MAIN && !self->_focusedSurface) + return; + int x = wl_fixed_to_int(surface_x); + int y = wl_fixed_to_int(surface_y); + // ??? + self->_absX = x; + self->_absY = y; + switch (self->_decorationFocus) { + case DECORATION_FOCUS_MAIN: + self->_movement = true; + break; + default: + auto edge = resizeEdge(self->_decorationFocus, *self->_focusedSurface, x, y); + switch (edge) { + case XDG_TOPLEVEL_RESIZE_EDGE_TOP: + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM: + self->_focusedSurface->setCursor(jwm::MouseCursor::RESIZE_NS); + break; + case XDG_TOPLEVEL_RESIZE_EDGE_LEFT: + case XDG_TOPLEVEL_RESIZE_EDGE_RIGHT: + self->_focusedSurface->setCursor(jwm::MouseCursor::RESIZE_WE); + break; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT: + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT: + self->_focusedSurface->setCursor(jwm::MouseCursor::RESIZE_NWSE); + break; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT: + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT: + self->_focusedSurface->setCursor(jwm::MouseCursor::RESIZE_NESW); + break; + default: + self->_focusedSurface->setCursor(jwm::MouseCursor::POINTING_HAND); + break; + } + break; + + } // I only unhide here, bc i'm unsure of what exactly is wanted with mouse lock. // This event isn't sent on mouse lock, only relative events are sent. - self->unhide(); } static void pointerButton(void* data, wl_pointer* pointer, uint32_t serial, @@ -62,6 +137,32 @@ static void pointerButton(void* data, wl_pointer* pointer, uint32_t serial, auto window = self->_focusedSurface; if (!window) return; int scale = window->getIntScale(); + if (self->_decorationFocus != DECORATION_FOCUS_MAIN) { + if (button != BTN_LEFT || state == 0) + return; + switch (self->_decorationFocus) { + case DECORATION_FOCUS_CLOSE_BUTTON: + window->dispatch(EventWindowCloseRequest::kInstance); + break; + case DECORATION_FOCUS_MIN_BUTTON: + xdg_toplevel_set_minimized(window->_decoration->_xdgToplevel); + break; + case DECORATION_FOCUS_MAX_BUTTON: + if (window->_decoration->_maximized) + xdg_toplevel_unset_maximized(window->_decoration->_xdgToplevel); + else + xdg_toplevel_set_maximized(window->_decoration->_xdgToplevel); + break; + default: + xdg_toplevel_resize_edge edge = resizeEdge(self->_decorationFocus, *window, self->_absX, self->_absY); + if (edge == XDG_TOPLEVEL_RESIZE_EDGE_NONE) + xdg_toplevel_move(window->_decoration->_xdgToplevel, self->_seat, serial); + else + xdg_toplevel_resize(window->_decoration->_xdgToplevel, self->_seat, serial, static_cast(edge)); + break; + } + return; + } if (state == 0) { // release switch (button) { @@ -212,9 +313,10 @@ static void relativePointerRelativeMotion(void* data, zwp_relative_pointer_v1* r static zwp_relative_pointer_v1_listener relativePointerListener = { .relative_motion = relativePointerRelativeMotion }; -Pointer::Pointer(wl_pointer* pointer, WindowManagerWayland* wm): +Pointer::Pointer(wl_seat* seat, wl_pointer* pointer, WindowManagerWayland* wm): _pointer(pointer), - _wm(*wm) + _wm(*wm), + _seat(seat) { _surface = wl_compositor_create_surface(_wm.compositor); wl_pointer_add_listener(pointer, &_pointerListener, this); @@ -369,10 +471,12 @@ void Pointer::hide() { void Pointer::unhide() { if (!_hidden) return; _hidden = false; - setCursor(_scale, _cursor); + setCursor(_scale, _cursor, true); } -void Pointer::setCursor(int scale, jwm::MouseCursor cursor) { +void Pointer::setCursor(int scale, jwm::MouseCursor cursor, bool force) { + if (!force && _cursor == cursor && _scale == scale) + return; _cursor = cursor; _scale = scale; auto wayCursor = getCursorFor(scale, cursor)->images[0]; diff --git a/wayland/cc/Pointer.hh b/wayland/cc/Pointer.hh index 0f3b1f26..739a3399 100644 --- a/wayland/cc/Pointer.hh +++ b/wayland/cc/Pointer.hh @@ -6,15 +6,18 @@ #include "MouseCursor.hh" #include #include +#include "Decoration.hh" namespace jwm { class WindowManagerWayland; class WindowWayland; class Pointer { public: - Pointer(wl_pointer* pointer, jwm::WindowManagerWayland* wm); + Pointer(wl_seat* seat, wl_pointer* pointer, jwm::WindowManagerWayland* wm); ~Pointer(); + wl_seat* _seat = nullptr; + wl_pointer* _pointer = nullptr; wl_pointer* getPointer() const { return _pointer; @@ -31,6 +34,7 @@ namespace jwm { } WindowWayland* _focusedSurface = nullptr; + DecorationFocus _decorationFocus = DECORATION_FOCUS_MAIN; WindowWayland* getFocusedSurface() const { return _focusedSurface; } @@ -78,7 +82,7 @@ namespace jwm { jwm::MouseCursor _cursor = jwm::MouseCursor::ARROW; int _scale = 1; - void setCursor(int scale, jwm::MouseCursor cursor); + void setCursor(int scale, jwm::MouseCursor cursor, bool force); static bool ownPointer(wl_pointer* pointer); diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 287a7130..4bbd59d9 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -17,7 +17,6 @@ #include "Log.hh" #include #include "Output.hh" -#include #include #include #include @@ -31,13 +30,17 @@ wl_registry_listener WindowManagerWayland::_registryListener = { .global = WindowManagerWayland::registryHandleGlobal, .global_remove = WindowManagerWayland::registryHandleGlobalRemove }; -libdecor_interface WindowManagerWayland::_decorInterface = { - .error = WindowManagerWayland::libdecorError -}; wl_seat_listener WindowManagerWayland::_seatListener = { .capabilities = WindowManagerWayland::seatCapabilities, .name = WindowManagerWayland::seatName }; + +static void xdgWmBasePing(void* data, xdg_wm_base* wm, uint32_t serial) { + xdg_wm_base_pong(wm, serial); +} +static xdg_wm_base_listener _wmListener = { + .ping = xdgWmBasePing +}; WindowManagerWayland::WindowManagerWayland(): display(wl_display_connect(nullptr)) { registry = wl_display_get_registry(display); @@ -46,17 +49,17 @@ WindowManagerWayland::WindowManagerWayland(): - if (!(shm && compositor && deviceManager && seat)) { + if (!(shm && compositor && deviceManager && seat && xdgWm && subcompositor && viewporter)) { // ??? // Bad. Means our compositor no supportie : ( throw std::system_error(ENOTSUP, std::generic_category(), "Unsupported compositor"); } - + + xdg_wm_base_add_listener(xdgWm, &_wmListener, nullptr); // ???: Moving this after libdecor_new causes input to not work wl_seat_add_listener(seat, &_seatListener, this); dataDevice = wl_data_device_manager_get_data_device(deviceManager, seat); wl_data_device_add_listener(dataDevice, &_deviceListener, this); - decorCtx = libdecor_new(display, &_decorInterface); wl_display_roundtrip(display); @@ -159,11 +162,6 @@ void WindowManagerWayland::runLoop() { } -void WindowManagerWayland::libdecorError(libdecor* context, enum libdecor_error error, const char* message) { - // ??? - fprintf(stderr, "Caught error (%d): %s\n", error, message); - throw std::runtime_error("lib decor error > : ("); -} void WindowManagerWayland::_processCallbacks() { { // process ui thread callbacks @@ -182,7 +180,7 @@ void WindowManagerWayland::_processCallbacks() { for (auto p : copy) { if (p->isRedrawRequested()) { p->unsetRedrawRequest(); - if (p->_visible && p->_configured) { + if (p->_visible && p->isConfigured()) { if (p->_layer) { p->_layer->makeCurrent(); } @@ -260,6 +258,18 @@ void WindowManagerWayland::registryHandleGlobal(void* data, wl_registry *registr } else if (strcmp(interface, zwp_relative_pointer_manager_v1_interface.name) == 0) { self->relativePointerManager = (zwp_relative_pointer_manager_v1*)wl_registry_bind(registry, name, &zwp_relative_pointer_manager_v1_interface, 1); + } else if (strcmp(interface, wp_viewporter_interface.name) == 0) { + self->viewporter = (wp_viewporter*)wl_registry_bind(registry, name, + &wp_viewporter_interface, 1); + } else if (strcmp(interface, wl_subcompositor_interface.name) == 0) { + self->subcompositor = (wl_subcompositor*)wl_registry_bind(registry, name, + &wl_subcompositor_interface, 1); + } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { + self->xdgWm = (xdg_wm_base*)wl_registry_bind(registry, name, + &xdg_wm_base_interface, 1); + } else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) { + self->decorationManager = (zxdg_decoration_manager_v1*)wl_registry_bind(registry, name, + &zxdg_decoration_manager_v1_interface, 1); } } void WindowManagerWayland::registryHandleGlobalRemove(void* data, wl_registry *registry, uint32_t name) { @@ -283,7 +293,7 @@ void WindowManagerWayland::seatCapabilities(void* data, wl_seat* seat, uint32_t auto self = reinterpret_cast(data); if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && !self->_pointer) { - self->_pointer.reset(new Pointer(wl_seat_get_pointer(seat), self)); + self->_pointer.reset(new Pointer(seat, wl_seat_get_pointer(seat), self)); } else if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && self->_pointer) { self->_pointer.reset(); } diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index 61d396c6..e0c63917 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -14,7 +14,6 @@ #include #include #include "Output.hh" -#include #include #include #include @@ -23,6 +22,9 @@ #include #include #include +#include +#include +#include namespace jwm { class WindowWayland; @@ -50,9 +52,6 @@ namespace jwm { static void registryHandleGlobalRemove(void* data, wl_registry *registry, uint32_t name); - static libdecor_interface _decorInterface; - static void libdecorError(libdecor* context, enum libdecor_error error, const char* message); - static wl_seat_listener _seatListener; static void seatCapabilities(void* data, wl_seat* seat, uint32_t capabilities); @@ -74,6 +73,11 @@ namespace jwm { wl_seat* seat = nullptr; zwp_pointer_constraints_v1* pointerConstraints = nullptr; zwp_relative_pointer_manager_v1* relativePointerManager = nullptr; + xdg_wm_base* xdgWm = nullptr; + wp_viewporter* viewporter = nullptr; + zxdg_decoration_manager_v1* decorationManager = nullptr; + wl_subcompositor* subcompositor = nullptr; + std::unique_ptr _pointer = nullptr; Pointer* getPointer() const { return _pointer.get(); @@ -99,7 +103,6 @@ namespace jwm { } - libdecor* decorCtx = nullptr; EGLDisplay _eglDisplay = EGL_NO_DISPLAY; std::list outputs; diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index a6b6d9bc..cc063139 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -21,13 +21,6 @@ wl_surface_listener WindowWayland::_surfaceListener = { #endif }; -libdecor_frame_interface WindowWayland::_libdecorFrameInterface = { - .configure = WindowWayland::decorFrameConfigure, - .close = WindowWayland::decorFrameClose, - .commit = WindowWayland::decorFrameCommit, - .dismiss_popup = WindowWayland::decorFrameDismissPopup -}; - WindowWayland::WindowWayland(JNIEnv* env, WindowManagerWayland& windowManager): jwm::Window(env), _windowManager(windowManager), @@ -44,14 +37,14 @@ WindowWayland::~WindowWayland() { void WindowWayland::setTitle(const std::string& title) { _title = title; - if (_frame) - libdecor_frame_set_title(_frame, _title.c_str()); + if (_decoration) + _decoration->setTitle(title); } void WindowWayland::setTitlebarVisible(bool isVisible) { _titlebarVisible = isVisible; - if (_frame) - libdecor_frame_set_visibility(_frame, isVisible); + if (_decoration) + _decoration->setVisible(isVisible); } void WindowWayland::close() { @@ -69,17 +62,11 @@ void WindowWayland::hide() { wl_surface_destroy(_waylandWindow); } _waylandWindow = nullptr; - // HACK: memory corruption issue in libdecor: - // https://gitlab.freedesktop.org/libdecor/libdecor/-/issues/59 - // Also causes protocol error that doesn't really make sense - /* - if (_frame) { - libdecor_frame_unref(_frame); + if (_decoration) { + _decoration->close(); } - */ - _frame = nullptr; + _decoration = nullptr; _windowManager.unregisterWindow(this); - _configured = false; } void WindowWayland::maximize() { // impl me :) @@ -98,7 +85,9 @@ void WindowWayland::setFullScreen(bool isFullScreen) { } bool WindowWayland::isFullScreen() { - return _fullscreen; + if (_decoration) + return _decoration->_fullscreen; + return false; } void WindowWayland::setLayer(ILayerWayland* layer) { @@ -107,10 +96,14 @@ void WindowWayland::setLayer(ILayerWayland* layer) { } void WindowWayland::getDecorations(int& left, int& top, int& right, int& bottom) { // impl me : ) - left = 0; - right = 0; - top = 0; - bottom = 0; + if (_decoration) { + _decoration->getBorders(left, top, right, bottom); + } else { + left = 0; + right = 0; + top = 0; + bottom = 0; + } } @@ -123,9 +116,6 @@ void WindowWayland::getContentPosition(int& posX, int& posY) { bool WindowWayland::resize(int width, int height) { if (width < 0 || height < 0) return false; - // don't allow size to be set if currently tiled - if (!_floating) - return false; // Width and height are in absolute pixel units, and wayland will // complain if you try to set a width/height that isn't a multiple of scale. if ((width % _scale) != 0 || (height % _scale) != 0) @@ -179,6 +169,11 @@ wl_cursor* WindowWayland::_getCursorFor(jwm::MouseCursor cursor) { bool WindowWayland::init() { return true; } +bool WindowWayland::isConfigured() { + if (_decoration) + return _decoration->_configured; + return false; +} void WindowWayland::show() { _waylandWindow = wl_compositor_create_surface(_windowManager.compositor); @@ -186,12 +181,11 @@ void WindowWayland::show() wl_proxy_set_tag((wl_proxy*) _waylandWindow, &AppWayland::proxyTag); _windowManager.registerWindow(this); wl_display_roundtrip(_windowManager.display); - _frame = libdecor_decorate(_windowManager.decorCtx, _waylandWindow, &_libdecorFrameInterface, this); + _decoration = new Decoration(*this); setTitle(_title); setTitlebarVisible(_titlebarVisible); - libdecor_frame_map(_frame); - - _configured = false; + // map + wl_surface_commit(_waylandWindow); _visible = true; } @@ -218,9 +212,12 @@ void WindowWayland::setVisible(bool isVisible) { } } -void jwm::WindowWayland::setCursor(jwm::MouseCursor cursor) { +void jwm::WindowWayland::setCursorMaybe(jwm::MouseCursor cursor, bool force) { if (!_windowManager.getPointer()) return; - _windowManager.getPointer()->setCursor(_scale, cursor); + _windowManager.getPointer()->setCursor(_scale, cursor, force); +} +void jwm::WindowWayland::setCursor(jwm::MouseCursor cursor) { + setCursorMaybe(cursor, false); } // what do??? @@ -283,82 +280,9 @@ static void frameCallbackDone(void* data, wl_callback* cb, uint32_t cb_data) { wl_callback_listener jwm::WindowWayland::_frameCallback = { .done = frameCallbackDone }; - -void jwm::WindowWayland::decorFrameConfigure(libdecor_frame* frame, libdecor_configuration* configuration, - void *userData) { - auto self = reinterpret_cast(userData); - int width = 0, height = 0; - libdecor_window_state winState; - - libdecor_configuration_get_content_size(configuration, frame, &width, &height); - - - width = (width <= 0) ? self->_floatingWidth : width; - height = (height <= 0) ? self->_floatingHeight : height; - - libdecor_state* state = libdecor_state_new(width, height); - libdecor_frame_commit(frame, state, configuration); - libdecor_state_free(state); - - if (libdecor_configuration_get_window_state(configuration, &winState)) { - bool active = (winState & LIBDECOR_WINDOW_STATE_ACTIVE) != 0; - bool maximized = (winState & LIBDECOR_WINDOW_STATE_MAXIMIZED) != 0; - bool fullscreen = (winState & LIBDECOR_WINDOW_STATE_FULLSCREEN) != 0; - // Some compositors (like weston) don't actually tell me on focus in and focus out. - // Libdecor simply sends an active at the beginning and keeps chugging. - if (active != self->_active) - if (active) - self->dispatch(classes::EventWindowFocusIn::kInstance); - else - self->dispatch(classes::EventWindowFocusOut::kInstance); - self->_active = active; - if (maximized != self->_maximized) - if (maximized) - self->dispatch(classes::EventWindowMaximize::kInstance); - self->_maximized = maximized; - // ??? - /* - if (fullscreen != self->_fullscreen) - if (fullscreen) - self->dispatch(classes::EventWindowFullScreenEnter::kInstance); - else - self->dispatch(classes::EventWindowFullScreenLeave::kInstance); - */ - self->_fullscreen = fullscreen; - self->_floating = libdecor_frame_is_floating(frame); - } - // before width - if (!self->_configured) { - if (self->_layer) - self->_layer->attachBuffer(); - } - self->_configured = true; - if (self->_width != width || self->_height != height) { - if (libdecor_frame_is_floating(frame)) { - if (width > 0) - self->_floatingWidth = width; - if (height > 0) - self->_floatingHeight = height; - } - - - self->_adaptSize(width, height); - } -} -void jwm::WindowWayland::decorFrameClose(libdecor_frame* frame, void* userData) { - WindowWayland* self = reinterpret_cast(userData); - self->dispatch(classes::EventWindowCloseRequest::kInstance); -} -void jwm::WindowWayland::decorFrameCommit(libdecor_frame* frame, void* userData) { - WindowWayland* self = reinterpret_cast(userData); - if (self->_waylandWindow) { - wl_surface_commit(self->_waylandWindow); - } -} -void jwm::WindowWayland::decorFrameDismissPopup(libdecor_frame* frame, const char* seatName, void* userData) {} void jwm::WindowWayland::_adaptSize(int newWidth, int newHeight) { using namespace classes; - if (!_configured) { + if (!isConfigured()) { return; } if (newWidth == _width && newHeight == _height && _scale == _oldScale) return; diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index ee25b658..e853acc2 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -6,8 +6,9 @@ #include "WindowManagerWayland.hh" #include "ILayerWayland.hh" #include "ScreenInfo.hh" -#include #include +#include "Decoration.hh" + namespace jwm { class WindowWayland: public jwm::Window { public: @@ -51,6 +52,7 @@ namespace jwm { void setFullScreen(bool isFullScreen); bool isFullScreen(); + void setCursorMaybe(jwm::MouseCursor cursor, bool force); void setCursor(jwm::MouseCursor cursor); void setLayer(ILayerWayland* layer); @@ -62,11 +64,6 @@ namespace jwm { static void surfacePreferredBufferScale(void* data, wl_surface* surface, int factor); static void surfacePreferredBufferTransform(void* data, wl_surface* surface, uint32_t transform); - static void decorFrameConfigure(libdecor_frame* frame, libdecor_configuration* config, void* userData); - static void decorFrameClose(libdecor_frame* frame, void* userData); - static void decorFrameCommit(libdecor_frame* frame, void* userData); - static void decorFrameDismissPopup(libdecor_frame* frame, const char* seatName, void* userData); - void _adaptSize(int newWidth, int newHeight); bool isNativeSelf(wl_surface* surface); @@ -76,6 +73,7 @@ namespace jwm { void hideCursor(bool hidden); + bool isConfigured(); int _posX = -1; int _posY = -1; @@ -93,11 +91,6 @@ namespace jwm { bool _canMaximize = false; bool _canFullscreen = false; bool _visible = false; - bool _configured = false; - bool _active = false; - bool _maximized = false; - bool _fullscreen = false; - bool _floating = false; bool _isRedrawRequested = false; std::string _title; bool _titlebarVisible = true; @@ -111,14 +104,12 @@ namespace jwm { WindowManagerWayland& _windowManager; ILayerWayland* _layer = nullptr; wl_surface* _waylandWindow = nullptr; - libdecor_frame* _frame = nullptr; + Decoration* _decoration = nullptr; std::list _outputs; wl_cursor_theme* theme = nullptr; static wl_surface_listener _surfaceListener; - static libdecor_frame_interface _libdecorFrameInterface; - static wl_callback_listener _frameCallback; }; From b61b050dda81a9051fc4739768de6b95389a6d1c Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Wed, 3 Jan 2024 18:06:59 -0500 Subject: [PATCH 72/93] Don't crash on unmaximize --- proto,log | 63 ++++++++++++++++++++++++++++++++++++++++ wayland/cc/Decoration.cc | 33 ++++++++++++++++----- wayland/cc/Pointer.cc | 3 +- 3 files changed, 91 insertions(+), 8 deletions(-) create mode 100644 proto,log diff --git a/proto,log b/proto,log new file mode 100644 index 00000000..ec2f45dc --- /dev/null +++ b/proto,log @@ -0,0 +1,63 @@ +Date: 2024-01-03 EST +[17:20:09.252] weston 13.0.0 + https://wayland.freedesktop.org + Bug reports to: https://gitlab.freedesktop.org/wayland/weston/issues/ + Build: 13.0.0 +[17:20:09.252] Command line: weston --logging-scopes proto,log +[17:20:09.252] OS: Linux, 5.19.8-arch1-1-surface, #1 SMP PREEMPT_DYNAMIC Wed, 14 Sep 2022 22:06:46 +0000, x86_64 +[17:20:09.252] Flight recorder: enabled +[17:20:09.252] Using config file '/home/bulby/.config/weston.ini' +[17:20:09.252] Output repaint window is 7 ms maximum. +[17:20:09.252] Loading module '/usr/lib/libweston-13/wayland-backend.so' +[17:20:09.289] Loading module '/usr/lib/libweston-13/gl-renderer.so' +[17:20:09.335] Using rendering device: /dev/dri/renderD128 +[17:20:09.335] EGL version: 1.5 +[17:20:09.335] EGL vendor: Mesa Project +[17:20:09.335] EGL client APIs: OpenGL OpenGL_ES +[17:20:09.335] EGL features: + EGL Wayland extension: yes + context priority: yes + buffer age: yes + partial update: no + swap buffers with damage: yes + configless context: yes + surfaceless context: yes + dmabuf support: modifiers +[17:20:09.337] GL version: OpenGL ES 3.2 Mesa 23.3.1-arch1.1 +[17:20:09.337] GLSL version: OpenGL ES GLSL ES 3.20 +[17:20:09.337] GL vendor: Intel +[17:20:09.337] GL renderer: Mesa Intel(R) UHD Graphics 620 (KBL GT2) +[17:20:09.343] GL ES 3.2 - renderer features: + read-back format: ARGB8888 + glReadPixels supports y-flip: yes + wl_shm 10 bpc formats: yes + wl_shm 16 bpc formats: yes + wl_shm half-float formats: yes + internal R and RG formats: yes + OES_EGL_image_external: yes +[17:20:09.343] Using GL renderer +[17:20:09.343] Registered plugin API 'weston_windowed_output_api_v2' of size 16 +[17:20:09.343] Color manager: no-op +[17:20:09.343] Output 'wayland0' attempts EOTF mode: SDR +[17:20:09.343] Output 'wayland0' using color profile: stock sRGB color profile +[17:20:09.343] Creating 1024x640 wayland output at (0, 0) +[17:20:09.346] wayland-backend: Using xdg_wm_base +[17:20:09.347] Chosen EGL config details: id: 41 rgba: 8 8 8 8 buf: 32 dep: 0 stcl: 0 int: 0-1 type: win vis_id: 0 +[17:20:09.355] Output 'wayland0' enabled with head(s) wayland0 +[17:20:09.355] Compositor capabilities: + arbitrary surface rotation: yes + screen capture uses y-flip: yes + cursor planes: no + arbitrary resolutions: no + view mask clipping: yes + explicit sync: yes + color operations: yes + presentation clock: CLOCK_MONOTONIC_RAW, id 4 + presentation clock resolution: 0.000000001 s +[17:20:09.355] libwayland: unable to lock lockfile /run/user/1000/wayland-1.lock, maybe another compositor is running +[17:20:09.355] Loading module '/usr/lib/weston/desktop-shell.so' +[17:20:09.358] launching '/usr/lib/weston/weston-keyboard' +[17:20:09.360] launching '/usr/lib/weston/weston-desktop-shell' +[17:20:09.365] Chosen EGL config details: id: 41 rgba: 8 8 8 8 buf: 32 dep: 0 stcl: 0 int: 0-1 type: win vis_id: 0 +[17:20:20.076] caught signal 12 +[17:20:20.077] BUG: finalizing a layer with views still on it. diff --git a/wayland/cc/Decoration.cc b/wayland/cc/Decoration.cc index 77a01766..f8d8925c 100644 --- a/wayland/cc/Decoration.cc +++ b/wayland/cc/Decoration.cc @@ -94,6 +94,10 @@ static void _xdgSurfaceConfigure(void* data, xdg_surface* surface, uint32_t seri if (window._layer) window._layer->attachBuffer(); } + // ask to configure _before_ commit. jank. + if (self->_floating) { + xdg_surface_ack_configure(self->_xdgSurface, serial); + } if (window.getUnscaledWidth() != width || window.getUnscaledHeight() != height) { if (self->_floating) { if (width > 0) { @@ -113,9 +117,13 @@ static void _xdgSurfaceConfigure(void* data, xdg_surface* surface, uint32_t seri if (!self->_top.surface) self->_showDecorations(); } - wl_surface_commit(window._waylandWindow); - xdg_surface_ack_configure(self->_xdgSurface, serial); + // at the end so that the size isn't adapted on first render self->_configured = true; + wl_surface_commit(window._waylandWindow); + if (!self->_floating) { + + xdg_surface_ack_configure(self->_xdgSurface, serial); + } } static xdg_surface_listener _xdgSurfaceListener = { @@ -127,7 +135,7 @@ static void _xdgToplevelConfigure(void* data, xdg_toplevel* toplevel, int width, self->_pendingWidth = width; self->_pendingHeight = height; - if (!self->_serverSide) { + if (!self->_serverSide && self->_isVisible) { self->_pendingWidth -= DECORATION_LEFT_WIDTH + DECORATION_RIGHT_WIDTH; self->_pendingHeight -= DECORATION_TOP_HEIGHT + DECORATION_BOTTOM_HEIGHT; } @@ -297,9 +305,17 @@ void Decoration::_adaptSize() { _resizeDecoration(&_close, DECORATION_CLOSE_X(_window), DECORATION_CLOSE_Y, DECORATION_CLOSE_WIDTH, DECORATION_CLOSE_HEIGHT); _resizeDecoration(&_min, DECORATION_MIN_X(_window), DECORATION_MIN_Y, DECORATION_MIN_WIDTH, DECORATION_MIN_HEIGHT); _resizeDecoration(&_max, DECORATION_MAX_X(_window), DECORATION_MAX_Y, DECORATION_MAX_WIDTH, DECORATION_MAX_HEIGHT); + + if (!_serverSide && _isVisible) + xdg_surface_set_window_geometry(_xdgSurface, -DECORATION_LEFT_WIDTH, -DECORATION_TOP_HEIGHT, + _window.getUnscaledWidth() + DECORATION_RIGHT_WIDTH + DECORATION_LEFT_WIDTH, + _window.getUnscaledHeight() + DECORATION_BOTTOM_HEIGHT + DECORATION_TOP_HEIGHT); + else + xdg_surface_set_window_geometry(_xdgSurface, 0, 0, _window.getUnscaledWidth(), _window.getUnscaledHeight()); } bool Decoration::ownDecorationSurface(wl_surface* surface) { + if (!surface) return false; return wl_proxy_get_tag((wl_proxy*)surface) == &proxyTag; } @@ -335,15 +351,18 @@ void Decoration::setVisible(bool isVisible) { if (isVisible) { if (_decoration) { zxdg_toplevel_decoration_v1_set_mode(_decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + } else { + _showDecorations(); } } else { + _destroyDecorations(); if (_decoration) { zxdg_toplevel_decoration_v1_set_mode(_decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); + } else { + // TODO: request reconfigure + wl_surface_commit(_window._waylandWindow); } - _destroyDecorations(); } - - } } @@ -354,7 +373,7 @@ void Decoration::setTitle(const std::string& title) { } void Decoration::getBorders(int& left, int& top, int& right, int& bottom) { - if (_serverSide) { + if (_serverSide || !_isVisible) { left = 0; top = 0; right = 0; diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index 36def276..6fee9743 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -255,6 +255,7 @@ static void pointerFrame(void* data, wl_pointer* pointer) auto self = reinterpret_cast(data); auto win = self->_focusedSurface; if (!win) return; + if (self->_decorationFocus != DECORATION_FOCUS_MAIN) return; if (self->_dX != 0.0f || self->_dY != 0.0f) { auto env = app.getJniEnv(); @@ -306,7 +307,7 @@ wl_pointer_listener Pointer::_pointerListener = { static void relativePointerRelativeMotion(void* data, zwp_relative_pointer_v1* relative, uint32_t utime_hi, uint32_t utime_lo, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel) { auto self = reinterpret_cast(data); - + if (self->_decorationFocus != DECORATION_FOCUS_MAIN) return; self->_dXPos += static_cast(wl_fixed_to_double(dx)); self->_dYPos += static_cast(wl_fixed_to_double(dy)); } From 26f1bc79074aabf48a6d474fbe14d9ac11f55809 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Wed, 3 Jan 2024 18:31:57 -0500 Subject: [PATCH 73/93] Implement screen-state related items --- wayland/cc/WindowWayland.cc | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index cc063139..0aa918ba 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -69,19 +69,28 @@ void WindowWayland::hide() { _windowManager.unregisterWindow(this); } void WindowWayland::maximize() { - // impl me :) + if (!_visible || !_decoration) return; + xdg_toplevel_set_maximized(_decoration->_xdgToplevel); } void WindowWayland::minimize() { - // impl me : ) + if (!_visible || !_decoration) return; + xdg_toplevel_set_minimized(_decoration->_xdgToplevel); } void WindowWayland::restore() { - // impl me + // Not possible for minimize + if (!_visible || !_decoration) return; + xdg_toplevel_unset_maximized(_decoration->_xdgToplevel); } void WindowWayland::setFullScreen(bool isFullScreen) { - // impl me : ) + if (!_visible || !_decoration) return; + if (_decoration->_fullscreen == isFullScreen) return; + if (isFullScreen) + xdg_toplevel_set_fullscreen(_decoration->_xdgToplevel, nullptr); + else + xdg_toplevel_unset_fullscreen(_decoration->_xdgToplevel); } bool WindowWayland::isFullScreen() { From a4af84aba5d9ad3cbfb4b6d7afb3c4674e6342c9 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Wed, 3 Jan 2024 18:53:50 -0500 Subject: [PATCH 74/93] try fix build --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 6776c8ac..4646e375 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,7 @@ RUN apt-get update -y && apt-get install -y software-properties-common RUN add-apt-repository -y ppa:ubuntu-toolchain-r/test RUN add-apt-repository -y ppa:openjdk-r/ppa RUN add-apt-repository -y ppa:git-core/ppa -RUN apt-get update -y && apt-get install -y wget zip python git build-essential g++-9 cmake ninja-build libxcomposite-dev libxrandr-dev libgl1-mesa-dev libxi-dev libxcursor-dev openjdk-11-jdk-headless +RUN apt-get update -y && apt-get install -y wget zip python git build-essential g++-9 cmake ninja-build libxcomposite-dev libxrandr-dev libgl1-mesa-dev libxi-dev libxcursor-dev openjdk-11-jdk-headless libegl1-mesa libegl1-mesa-dev extra-cmake-modules wayland-protocols wayland-utils libwayland-dev RUN wget --no-verbose https://downloads.apache.org/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz --output-document - | tar -xz RUN echo 'export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64' > /etc/profile.d/02-jdk.sh RUN echo 'export PATH=$JAVA_HOME/bin:/root/apache-maven-3.6.3/bin:$PATH' >> /etc/profile.d/02-jdk.sh From 25972d86b940f411dce1b1c2005afb9894b52f5b Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Wed, 3 Jan 2024 19:48:00 -0500 Subject: [PATCH 75/93] Hidden actually means just no title bar --- examples/dashboard/java/PanelScreens.java | 12 ++- wayland/cc/Decoration.cc | 100 ++++++++++++++-------- wayland/cc/Decoration.hh | 9 +- wayland/cc/WindowWayland.cc | 2 +- 4 files changed, 81 insertions(+), 42 deletions(-) diff --git a/examples/dashboard/java/PanelScreens.java b/examples/dashboard/java/PanelScreens.java index 378f8ef3..dd287ab7 100644 --- a/examples/dashboard/java/PanelScreens.java +++ b/examples/dashboard/java/PanelScreens.java @@ -18,7 +18,7 @@ public PanelScreens(Window window) { super(window); if (Platform.MACOS == Platform.CURRENT) { titleStyles = new Options("Default", "Hidden", "Transparent", "Unified", "Unified Compact", "Unified Transparent", "Unified Compact Transparent"); - } else if (Platform.X11 == Platform.CURRENT) { + } else if (Platform.X11 == Platform.CURRENT || Platform.WAYLAND == Platform.CURRENT) { titleStyles = new Options("Default", "Hidden"); } } @@ -66,6 +66,14 @@ public void setTitleStyle(String style) { case "Hidden" -> w.setTitlebarVisible(false); } + } else if (Platform.WAYLAND == Platform.CURRENT) { + WindowWayland w = (WindowWayland) window; + switch (style) { + case "Default" -> + w.setTitlebarVisible(true); + case "Hidden" -> + w.setTitlebarVisible(false); + } } } @@ -171,4 +179,4 @@ public void paintImpl(Canvas canvas, int width, int height, float scale) { canvas.translate(0, lineHeight); canvas.restore(); } -} \ No newline at end of file +} diff --git a/wayland/cc/Decoration.cc b/wayland/cc/Decoration.cc index f8d8925c..b0cd4947 100644 --- a/wayland/cc/Decoration.cc +++ b/wayland/cc/Decoration.cc @@ -113,9 +113,9 @@ static void _xdgSurfaceConfigure(void* data, xdg_surface* surface, uint32_t seri if (self->_serverSide) { if (self->_top.surface) self->_destroyDecorations(); - } else if (self->_isVisible) { + } else { if (!self->_top.surface) - self->_showDecorations(); + self->_showDecorations(!self->_isVisible); } // at the end so that the size isn't adapted on first render self->_configured = true; @@ -135,9 +135,13 @@ static void _xdgToplevelConfigure(void* data, xdg_toplevel* toplevel, int width, self->_pendingWidth = width; self->_pendingHeight = height; - if (!self->_serverSide && self->_isVisible) { + if (!self->_serverSide) { self->_pendingWidth -= DECORATION_LEFT_WIDTH + DECORATION_RIGHT_WIDTH; - self->_pendingHeight -= DECORATION_TOP_HEIGHT + DECORATION_BOTTOM_HEIGHT; + self->_pendingHeight -= DECORATION_BOTTOM_HEIGHT; + if (self->_isVisible) + self->_pendingHeight -= DECORATION_TOP_HEIGHT; + else + self->_pendingHeight -= DECORATION_BOTTOM_HEIGHT; } bool active = false; @@ -208,19 +212,7 @@ Decoration::Decoration(WindowWayland& window): zxdg_toplevel_decoration_v1_set_mode(_decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); } - - _decBuffer = Buffer::createShmBuffer(_wm.shm, 1, 1, WL_SHM_FORMAT_ARGB8888); - memcpy(_decBuffer->getData(), grey_data, 1 * sizeof(uint32_t)); - _closeBuffer = Buffer::createShmBuffer(_wm.shm, 9, 9, WL_SHM_FORMAT_ARGB8888); - memcpy(_closeBuffer->getData(), close_data, 9 * 9 * sizeof(uint32_t)); - _maxBuffer = Buffer::createShmBuffer(_wm.shm, 9, 9, WL_SHM_FORMAT_ARGB8888); - memcpy(_maxBuffer->getData(), max_data, 9 * 9 * sizeof(uint32_t)); - _minBuffer = Buffer::createShmBuffer(_wm.shm, 9, 9, WL_SHM_FORMAT_ARGB8888); - memcpy(_minBuffer->getData(), min_data, 9 * 9 * sizeof(uint32_t)); - - // delay making parts until configure : ) - } void Decoration::close() { @@ -283,31 +275,60 @@ void Decoration::_destroyDecorations() { _destroyDecoration(&_max); } -void Decoration::_showDecorations() { - _makePart(&_top, _decBuffer, true, DECORATION_TOP_X, DECORATION_TOP_Y, DECORATION_TOP_WIDTH(_window), DECORATION_TOP_HEIGHT); - _makePart(&_left, _decBuffer, true, DECORATION_LEFT_X, DECORATION_LEFT_Y, DECORATION_LEFT_WIDTH, DECORATION_LEFT_HEIGHT(_window)); - _makePart(&_right, _decBuffer, true, DECORATION_RIGHT_X(_window), DECORATION_RIGHT_Y, DECORATION_RIGHT_WIDTH, DECORATION_RIGHT_HEIGHT(_window)); +void Decoration::_showDecorations(bool hidden) { + // ??? + // When destroyed these get released + _decBuffer = Buffer::createShmBuffer(_wm.shm, 1, 1, WL_SHM_FORMAT_ARGB8888); + memcpy(_decBuffer->getData(), grey_data, 1 * sizeof(uint32_t)); + _closeBuffer = Buffer::createShmBuffer(_wm.shm, 9, 9, WL_SHM_FORMAT_ARGB8888); + memcpy(_closeBuffer->getData(), close_data, 9 * 9 * sizeof(uint32_t)); + _maxBuffer = Buffer::createShmBuffer(_wm.shm, 9, 9, WL_SHM_FORMAT_ARGB8888); + memcpy(_maxBuffer->getData(), max_data, 9 * 9 * sizeof(uint32_t)); + _minBuffer = Buffer::createShmBuffer(_wm.shm, 9, 9, WL_SHM_FORMAT_ARGB8888); + memcpy(_minBuffer->getData(), min_data, 9 * 9 * sizeof(uint32_t)); + if (hidden) { + _makePart(&_top, _decBuffer, true, DECORATION_TOP_X, DECORATION_HIDDEN_TOP_Y, DECORATION_BOTTOM_WIDTH(_window), DECORATION_BOTTOM_HEIGHT); + _makePart(&_left, _decBuffer, true, DECORATION_LEFT_X, DECORATION_HIDDEN_LEFT_Y, DECORATION_LEFT_WIDTH, + DECORATION_HIDDEN_LEFT_HEIGHT(_window)); + _makePart(&_right, _decBuffer, true, DECORATION_RIGHT_X(_window), DECORATION_HIDDEN_RIGHT_Y, + DECORATION_RIGHT_WIDTH, DECORATION_HIDDEN_RIGHT_HEIGHT(_window)); + } else { + _makePart(&_top, _decBuffer, true, DECORATION_TOP_X, DECORATION_TOP_Y, DECORATION_TOP_WIDTH(_window), DECORATION_TOP_HEIGHT); + _makePart(&_left, _decBuffer, true, DECORATION_LEFT_X, DECORATION_LEFT_Y, DECORATION_LEFT_WIDTH, DECORATION_LEFT_HEIGHT(_window)); + _makePart(&_right, _decBuffer, true, DECORATION_RIGHT_X(_window), DECORATION_RIGHT_Y, DECORATION_RIGHT_WIDTH, DECORATION_RIGHT_HEIGHT(_window)); + } _makePart(&_bottom, _decBuffer, true, DECORATION_BOTTOM_X, DECORATION_BOTTOM_Y(_window), DECORATION_BOTTOM_WIDTH(_window), DECORATION_BOTTOM_HEIGHT); - - _makePart(&_close, _closeBuffer, false, DECORATION_CLOSE_X(_window), DECORATION_CLOSE_Y, DECORATION_CLOSE_WIDTH, DECORATION_CLOSE_HEIGHT); - _makePart(&_max, _maxBuffer, false, DECORATION_MAX_X(_window), DECORATION_MAX_Y, DECORATION_MAX_WIDTH, DECORATION_MAX_HEIGHT); - _makePart(&_min, _minBuffer, false, DECORATION_MIN_X(_window), DECORATION_MIN_Y, DECORATION_MIN_WIDTH, DECORATION_MIN_HEIGHT); + + if (!hidden) { + _makePart(&_close, _closeBuffer, false, DECORATION_CLOSE_X(_window), DECORATION_CLOSE_Y, DECORATION_CLOSE_WIDTH, DECORATION_CLOSE_HEIGHT); + _makePart(&_max, _maxBuffer, false, DECORATION_MAX_X(_window), DECORATION_MAX_Y, DECORATION_MAX_WIDTH, DECORATION_MAX_HEIGHT); + _makePart(&_min, _minBuffer, false, DECORATION_MIN_X(_window), DECORATION_MIN_Y, DECORATION_MIN_WIDTH, DECORATION_MIN_HEIGHT); + } } void Decoration::_adaptSize() { - _resizeDecoration(&_top, DECORATION_TOP_X, DECORATION_TOP_Y, DECORATION_TOP_WIDTH(_window), DECORATION_TOP_HEIGHT); - _resizeDecoration(&_left, DECORATION_LEFT_X, DECORATION_LEFT_Y, DECORATION_LEFT_WIDTH, DECORATION_LEFT_HEIGHT(_window)); - _resizeDecoration(&_right, DECORATION_RIGHT_X(_window), DECORATION_RIGHT_Y, DECORATION_RIGHT_WIDTH, DECORATION_RIGHT_HEIGHT(_window)); + if (!_isVisible) { + _resizeDecoration(&_top, DECORATION_TOP_X, DECORATION_HIDDEN_TOP_Y, DECORATION_BOTTOM_WIDTH(_window), DECORATION_BOTTOM_HEIGHT); + _resizeDecoration(&_left, DECORATION_LEFT_X, DECORATION_HIDDEN_LEFT_Y, DECORATION_LEFT_WIDTH, + DECORATION_HIDDEN_LEFT_HEIGHT(_window)); + _resizeDecoration(&_right, DECORATION_RIGHT_X(_window), DECORATION_HIDDEN_RIGHT_Y, DECORATION_RIGHT_WIDTH, + DECORATION_HIDDEN_RIGHT_HEIGHT(_window)); + } else { + _resizeDecoration(&_top, DECORATION_TOP_X, DECORATION_TOP_Y, DECORATION_TOP_WIDTH(_window), DECORATION_TOP_HEIGHT); + _resizeDecoration(&_left, DECORATION_LEFT_X, DECORATION_LEFT_Y, DECORATION_LEFT_WIDTH, DECORATION_LEFT_HEIGHT(_window)); + _resizeDecoration(&_right, DECORATION_RIGHT_X(_window), DECORATION_RIGHT_Y, DECORATION_RIGHT_WIDTH, DECORATION_RIGHT_HEIGHT(_window)); + } _resizeDecoration(&_bottom, DECORATION_BOTTOM_X, DECORATION_BOTTOM_Y(_window), DECORATION_BOTTOM_WIDTH(_window), DECORATION_BOTTOM_HEIGHT); + if (_isVisible) { + _resizeDecoration(&_close, DECORATION_CLOSE_X(_window), DECORATION_CLOSE_Y, DECORATION_CLOSE_WIDTH, DECORATION_CLOSE_HEIGHT); + _resizeDecoration(&_min, DECORATION_MIN_X(_window), DECORATION_MIN_Y, DECORATION_MIN_WIDTH, DECORATION_MIN_HEIGHT); + _resizeDecoration(&_max, DECORATION_MAX_X(_window), DECORATION_MAX_Y, DECORATION_MAX_WIDTH, DECORATION_MAX_HEIGHT); + } - _resizeDecoration(&_close, DECORATION_CLOSE_X(_window), DECORATION_CLOSE_Y, DECORATION_CLOSE_WIDTH, DECORATION_CLOSE_HEIGHT); - _resizeDecoration(&_min, DECORATION_MIN_X(_window), DECORATION_MIN_Y, DECORATION_MIN_WIDTH, DECORATION_MIN_HEIGHT); - _resizeDecoration(&_max, DECORATION_MAX_X(_window), DECORATION_MAX_Y, DECORATION_MAX_WIDTH, DECORATION_MAX_HEIGHT); - - if (!_serverSide && _isVisible) - xdg_surface_set_window_geometry(_xdgSurface, -DECORATION_LEFT_WIDTH, -DECORATION_TOP_HEIGHT, + if (!_serverSide) + xdg_surface_set_window_geometry(_xdgSurface, -DECORATION_LEFT_WIDTH, _isVisible ? -DECORATION_TOP_HEIGHT : -DECORATION_BOTTOM_HEIGHT, _window.getUnscaledWidth() + DECORATION_RIGHT_WIDTH + DECORATION_LEFT_WIDTH, _window.getUnscaledHeight() + DECORATION_BOTTOM_HEIGHT + DECORATION_TOP_HEIGHT); else @@ -345,17 +366,19 @@ Decoration* Decoration::getDecorationForSurface(wl_surface* surface, DecorationF } } -void Decoration::setVisible(bool isVisible) { +void Decoration::setTitlebarVisible(bool isVisible) { if (isVisible != _isVisible) { _isVisible = isVisible; if (isVisible) { + _destroyDecorations(); if (_decoration) { zxdg_toplevel_decoration_v1_set_mode(_decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); } else { - _showDecorations(); + _showDecorations(false); } } else { _destroyDecorations(); + _showDecorations(true); if (_decoration) { zxdg_toplevel_decoration_v1_set_mode(_decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); } else { @@ -373,14 +396,17 @@ void Decoration::setTitle(const std::string& title) { } void Decoration::getBorders(int& left, int& top, int& right, int& bottom) { - if (_serverSide || !_isVisible) { + if (_serverSide) { left = 0; top = 0; right = 0; bottom = 0; } else { left = DECORATION_LEFT_WIDTH; - top = DECORATION_TOP_HEIGHT; + if (_isVisible) + top = DECORATION_TOP_HEIGHT; + else + top = DECORATION_BOTTOM_HEIGHT; right = DECORATION_RIGHT_WIDTH; bottom = DECORATION_BOTTOM_HEIGHT; } diff --git a/wayland/cc/Decoration.hh b/wayland/cc/Decoration.hh index 082911be..a834fe99 100644 --- a/wayland/cc/Decoration.hh +++ b/wayland/cc/Decoration.hh @@ -10,16 +10,21 @@ #define DECORATION_WIDTH 10 +#define DECORATION_HIDDEN_TOP_Y -(DECORATION_BOTTOM_HEIGHT) #define DECORATION_TOP_X 0 #define DECORATION_TOP_Y -(DECORATION_TOP_HEIGHT) #define DECORATION_TOP_WIDTH(window) window.getUnscaledWidth() #define DECORATION_TOP_HEIGHT DECORATION_WIDTH * 3 +#define DECORATION_HIDDEN_LEFT_Y DECORATION_HIDDEN_TOP_Y +#define DECORATION_HIDDEN_LEFT_HEIGHT(window) window.getUnscaledHeight() + DECORATION_WIDTH + DECORATION_WIDTH #define DECORATION_LEFT_X -(DECORATION_WIDTH) #define DECORATION_LEFT_Y -(DECORATION_TOP_HEIGHT) #define DECORATION_LEFT_WIDTH DECORATION_WIDTH #define DECORATION_LEFT_HEIGHT(window) window.getUnscaledHeight() + DECORATION_TOP_HEIGHT + DECORATION_WIDTH +#define DECORATION_HIDDEN_RIGHT_Y DECORATION_HIDDEN_LEFT_Y +#define DECORATION_HIDDEN_RIGHT_HEIGHT(window) DECORATION_HIDDEN_LEFT_HEIGHT(window) #define DECORATION_RIGHT_X(window) window.getUnscaledWidth() #define DECORATION_RIGHT_Y -(DECORATION_TOP_HEIGHT) #define DECORATION_RIGHT_WIDTH DECORATION_WIDTH @@ -114,7 +119,7 @@ namespace jwm { void _adaptSize(); void _destroyDecorations(); - void _showDecorations(); + void _showDecorations(bool hidden); static const char* proxyTag; static bool ownDecorationSurface(wl_surface* surface); @@ -125,7 +130,7 @@ namespace jwm { void setTitle(const std::string& title); bool _isVisible = true; - void setVisible(bool isVisible); + void setTitlebarVisible(bool isVisible); void getBorders(int& left, int& top, int& right, int& bottom); diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index 0aa918ba..954d69c6 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -44,7 +44,7 @@ void WindowWayland::setTitle(const std::string& title) { void WindowWayland::setTitlebarVisible(bool isVisible) { _titlebarVisible = isVisible; if (_decoration) - _decoration->setVisible(isVisible); + _decoration->setTitlebarVisible(isVisible); } void WindowWayland::close() { From 94d4539407b982940a37a0d4203ed7f9e5784116 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Wed, 3 Jan 2024 19:50:06 -0500 Subject: [PATCH 76/93] Thinner = better --- wayland/cc/Decoration.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wayland/cc/Decoration.hh b/wayland/cc/Decoration.hh index a834fe99..afa9a4bf 100644 --- a/wayland/cc/Decoration.hh +++ b/wayland/cc/Decoration.hh @@ -8,13 +8,13 @@ #include "Buffer.hh" #include -#define DECORATION_WIDTH 10 +#define DECORATION_WIDTH 4 #define DECORATION_HIDDEN_TOP_Y -(DECORATION_BOTTOM_HEIGHT) #define DECORATION_TOP_X 0 #define DECORATION_TOP_Y -(DECORATION_TOP_HEIGHT) #define DECORATION_TOP_WIDTH(window) window.getUnscaledWidth() -#define DECORATION_TOP_HEIGHT DECORATION_WIDTH * 3 +#define DECORATION_TOP_HEIGHT 30 #define DECORATION_HIDDEN_LEFT_Y DECORATION_HIDDEN_TOP_Y #define DECORATION_HIDDEN_LEFT_HEIGHT(window) window.getUnscaledHeight() + DECORATION_WIDTH + DECORATION_WIDTH From ebf0c4c6131044c19268eb6791100bae21070a7e Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Thu, 4 Jan 2024 15:43:00 -0500 Subject: [PATCH 77/93] Fix movement when titlebar is hidden --- wayland/cc/Decoration.cc | 14 ++++++++++---- wayland/cc/Decoration.hh | 2 ++ wayland/cc/Pointer.cc | 20 ++++++++++++++++---- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/wayland/cc/Decoration.cc b/wayland/cc/Decoration.cc index b0cd4947..8b8c3712 100644 --- a/wayland/cc/Decoration.cc +++ b/wayland/cc/Decoration.cc @@ -403,11 +403,17 @@ void Decoration::getBorders(int& left, int& top, int& right, int& bottom) { bottom = 0; } else { left = DECORATION_LEFT_WIDTH; - if (_isVisible) - top = DECORATION_TOP_HEIGHT; - else - top = DECORATION_BOTTOM_HEIGHT; + top = getTopSize(); right = DECORATION_RIGHT_WIDTH; bottom = DECORATION_BOTTOM_HEIGHT; } } + +int Decoration::getTopSize() { + if (_serverSide) + return 0; + if (_isVisible) + return DECORATION_TOP_HEIGHT; + else + return DECORATION_BOTTOM_HEIGHT; +} diff --git a/wayland/cc/Decoration.hh b/wayland/cc/Decoration.hh index afa9a4bf..2c36223f 100644 --- a/wayland/cc/Decoration.hh +++ b/wayland/cc/Decoration.hh @@ -134,6 +134,8 @@ namespace jwm { void getBorders(int& left, int& top, int& right, int& bottom); + int getTopSize(); + private: Decoration(Decoration&& other) = delete; diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index 6fee9743..84246051 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -56,19 +56,19 @@ static xdg_toplevel_resize_edge resizeEdge(DecorationFocus focus, WindowWayland& // ??? return XDG_TOPLEVEL_RESIZE_EDGE_NONE; case DECORATION_FOCUS_TOP: - if (y < DECORATION_TOP_HEIGHT / 2) + if (y < window._decoration->getTopSize() / 2) return XDG_TOPLEVEL_RESIZE_EDGE_TOP; else return XDG_TOPLEVEL_RESIZE_EDGE_NONE; case DECORATION_FOCUS_LEFT: - if (y < DECORATION_TOP_HEIGHT / 2) + if (y < window._decoration->getTopSize() / 2) return XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; else if (y > DECORATION_BOTTOM_Y(window)) return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT; else return XDG_TOPLEVEL_RESIZE_EDGE_LEFT; case DECORATION_FOCUS_RIGHT: - if (y < DECORATION_TOP_HEIGHT / 2) + if (y < window._decoration->getTopSize() / 2) return XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; else if (y > DECORATION_BOTTOM_Y(window)) return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT; @@ -138,7 +138,19 @@ static void pointerButton(void* data, wl_pointer* pointer, uint32_t serial, if (!window) return; int scale = window->getIntScale(); if (self->_decorationFocus != DECORATION_FOCUS_MAIN) { - if (button != BTN_LEFT || state == 0) + if (state == 0) + return; + if (button == BTN_RIGHT) { + switch (self->_decorationFocus) { + case DECORATION_FOCUS_TOP: + // not showing but this code is being reached + xdg_toplevel_show_window_menu(window->_decoration->_xdgToplevel, self->_seat, serial, self->_absX, self->_absY); + return; + default: + return; + } + } + if (button != BTN_LEFT) return; switch (self->_decorationFocus) { case DECORATION_FOCUS_CLOSE_BUTTON: From 0a6f4ff6acdf55d922d40f6cf44a497fc654c7ad Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Thu, 4 Jan 2024 16:22:09 -0500 Subject: [PATCH 78/93] remove log --- proto,log | 63 ------------------------------------------------------- 1 file changed, 63 deletions(-) delete mode 100644 proto,log diff --git a/proto,log b/proto,log deleted file mode 100644 index ec2f45dc..00000000 --- a/proto,log +++ /dev/null @@ -1,63 +0,0 @@ -Date: 2024-01-03 EST -[17:20:09.252] weston 13.0.0 - https://wayland.freedesktop.org - Bug reports to: https://gitlab.freedesktop.org/wayland/weston/issues/ - Build: 13.0.0 -[17:20:09.252] Command line: weston --logging-scopes proto,log -[17:20:09.252] OS: Linux, 5.19.8-arch1-1-surface, #1 SMP PREEMPT_DYNAMIC Wed, 14 Sep 2022 22:06:46 +0000, x86_64 -[17:20:09.252] Flight recorder: enabled -[17:20:09.252] Using config file '/home/bulby/.config/weston.ini' -[17:20:09.252] Output repaint window is 7 ms maximum. -[17:20:09.252] Loading module '/usr/lib/libweston-13/wayland-backend.so' -[17:20:09.289] Loading module '/usr/lib/libweston-13/gl-renderer.so' -[17:20:09.335] Using rendering device: /dev/dri/renderD128 -[17:20:09.335] EGL version: 1.5 -[17:20:09.335] EGL vendor: Mesa Project -[17:20:09.335] EGL client APIs: OpenGL OpenGL_ES -[17:20:09.335] EGL features: - EGL Wayland extension: yes - context priority: yes - buffer age: yes - partial update: no - swap buffers with damage: yes - configless context: yes - surfaceless context: yes - dmabuf support: modifiers -[17:20:09.337] GL version: OpenGL ES 3.2 Mesa 23.3.1-arch1.1 -[17:20:09.337] GLSL version: OpenGL ES GLSL ES 3.20 -[17:20:09.337] GL vendor: Intel -[17:20:09.337] GL renderer: Mesa Intel(R) UHD Graphics 620 (KBL GT2) -[17:20:09.343] GL ES 3.2 - renderer features: - read-back format: ARGB8888 - glReadPixels supports y-flip: yes - wl_shm 10 bpc formats: yes - wl_shm 16 bpc formats: yes - wl_shm half-float formats: yes - internal R and RG formats: yes - OES_EGL_image_external: yes -[17:20:09.343] Using GL renderer -[17:20:09.343] Registered plugin API 'weston_windowed_output_api_v2' of size 16 -[17:20:09.343] Color manager: no-op -[17:20:09.343] Output 'wayland0' attempts EOTF mode: SDR -[17:20:09.343] Output 'wayland0' using color profile: stock sRGB color profile -[17:20:09.343] Creating 1024x640 wayland output at (0, 0) -[17:20:09.346] wayland-backend: Using xdg_wm_base -[17:20:09.347] Chosen EGL config details: id: 41 rgba: 8 8 8 8 buf: 32 dep: 0 stcl: 0 int: 0-1 type: win vis_id: 0 -[17:20:09.355] Output 'wayland0' enabled with head(s) wayland0 -[17:20:09.355] Compositor capabilities: - arbitrary surface rotation: yes - screen capture uses y-flip: yes - cursor planes: no - arbitrary resolutions: no - view mask clipping: yes - explicit sync: yes - color operations: yes - presentation clock: CLOCK_MONOTONIC_RAW, id 4 - presentation clock resolution: 0.000000001 s -[17:20:09.355] libwayland: unable to lock lockfile /run/user/1000/wayland-1.lock, maybe another compositor is running -[17:20:09.355] Loading module '/usr/lib/weston/desktop-shell.so' -[17:20:09.358] launching '/usr/lib/weston/weston-keyboard' -[17:20:09.360] launching '/usr/lib/weston/weston-desktop-shell' -[17:20:09.365] Chosen EGL config details: id: 41 rgba: 8 8 8 8 buf: 32 dep: 0 stcl: 0 int: 0-1 type: win vis_id: 0 -[17:20:20.076] caught signal 12 -[17:20:20.077] BUG: finalizing a layer with views still on it. From 67ce6f9de3b664b12a03bedad166a0d86fe6d6c5 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Thu, 4 Jan 2024 16:37:06 -0500 Subject: [PATCH 79/93] Undo some unneeded changes --- linux/cc/ILayer.hh | 1 - wayland/cc/LayerGLWayland.cc | 3 +-- wayland/cc/LayerRasterWayland.cc | 2 +- x11/cc/LayerGLX11.cc | 2 +- x11/cc/LayerRasterX11.cc | 2 +- x11/cc/ScreenInfo.cc | 1 + 6 files changed, 5 insertions(+), 6 deletions(-) diff --git a/linux/cc/ILayer.hh b/linux/cc/ILayer.hh index 5b8ee030..81a32c2b 100644 --- a/linux/cc/ILayer.hh +++ b/linux/cc/ILayer.hh @@ -15,7 +15,6 @@ public: virtual void makeCurrentForced(); virtual void setVsyncMode(VSync v) = 0; virtual void close() = 0; - virtual void resize(int width, int height) = 0; static ILayer* _ourCurrentLayer; diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index ecdba2f3..ebe5a658 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -85,7 +85,7 @@ namespace jwm { // vsync? what vsync? } - void resize(int width, int height) override { + void resize(int width, int height) { if (!_surface || !_eglWindow) return; // Make current to avoid artifacts in other windows makeCurrentForced(); @@ -100,7 +100,6 @@ namespace jwm { // HACK: make new window with new scale // https://gitlab.freedesktop.org/mesa/mesa/-/issues/7217 if (fWindow->_scale != fWindow->_oldScale) { - fprintf(stderr, "HACK: remaking egl window\n"); detachBuffer(); attachBuffer(); wl_surface_set_buffer_scale(fWindow->_waylandWindow, fWindow->getIntScale()); diff --git a/wayland/cc/LayerRasterWayland.cc b/wayland/cc/LayerRasterWayland.cc index 156d3b91..d64ef789 100644 --- a/wayland/cc/LayerRasterWayland.cc +++ b/wayland/cc/LayerRasterWayland.cc @@ -29,7 +29,7 @@ namespace jwm { } } - void resize(int width, int height) override { + void resize(int width, int height) { // god is dead _width = width; _height = height; diff --git a/x11/cc/LayerGLX11.cc b/x11/cc/LayerGLX11.cc index 1b4b8e02..aa78e4ee 100644 --- a/x11/cc/LayerGLX11.cc +++ b/x11/cc/LayerGLX11.cc @@ -49,7 +49,7 @@ namespace jwm { } } - void resize(int width, int height) override { + void resize(int width, int height) { glClearStencil(0); glClearColor(0, 0, 0, 255); glStencilMask(0xffffffff); diff --git a/x11/cc/LayerRasterX11.cc b/x11/cc/LayerRasterX11.cc index cc22ea88..4928aee6 100644 --- a/x11/cc/LayerRasterX11.cc +++ b/x11/cc/LayerRasterX11.cc @@ -30,7 +30,7 @@ namespace jwm { _graphicsContext = DefaultGC(d, DefaultScreen(d)); } - void resize(int width, int height) override { + void resize(int width, int height) { Display* d = fWindow->_windowManager.getDisplay(); _width = width; _height = height; diff --git a/x11/cc/ScreenInfo.cc b/x11/cc/ScreenInfo.cc index f1e56dc2..f3aa1dee 100644 --- a/x11/cc/ScreenInfo.cc +++ b/x11/cc/ScreenInfo.cc @@ -1,6 +1,7 @@ #include "ScreenInfo.hh" #include "AppX11.hh" + jobject jwm::ScreenInfo::asJavaObject(JNIEnv* env) const { return jwm::classes::Screen::make(env, id, isPrimary, bounds, bounds, jwm::app.getScale()); } From ff8827b90556e475ff3acf19986e9adcc1e5991e Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Fri, 5 Jan 2024 14:15:07 -0500 Subject: [PATCH 80/93] Combine border into one part Done to make any future work pulling in drawing libraries easier. --- wayland/cc/Decoration.cc | 71 ++++++++++++++-------------------------- wayland/cc/Decoration.hh | 40 +++++----------------- wayland/cc/Pointer.cc | 70 +++++++++++++++++++++------------------ 3 files changed, 71 insertions(+), 110 deletions(-) diff --git a/wayland/cc/Decoration.cc b/wayland/cc/Decoration.cc index 8b8c3712..58b8efe4 100644 --- a/wayland/cc/Decoration.cc +++ b/wayland/cc/Decoration.cc @@ -111,10 +111,10 @@ static void _xdgSurfaceConfigure(void* data, xdg_surface* surface, uint32_t seri self->_adaptSize(); } if (self->_serverSide) { - if (self->_top.surface) + if (self->_border.surface) self->_destroyDecorations(); } else { - if (!self->_top.surface) + if (!self->_border.surface) self->_showDecorations(!self->_isVisible); } // at the end so that the size isn't adapted on first render @@ -136,12 +136,8 @@ static void _xdgToplevelConfigure(void* data, xdg_toplevel* toplevel, int width, self->_pendingWidth = width; self->_pendingHeight = height; if (!self->_serverSide) { - self->_pendingWidth -= DECORATION_LEFT_WIDTH + DECORATION_RIGHT_WIDTH; - self->_pendingHeight -= DECORATION_BOTTOM_HEIGHT; - if (self->_isVisible) - self->_pendingHeight -= DECORATION_TOP_HEIGHT; - else - self->_pendingHeight -= DECORATION_BOTTOM_HEIGHT; + self->_pendingWidth -= DECORATION_WIDTH + DECORATION_WIDTH; + self->_pendingHeight -= DECORATION_WIDTH + self->getTopSize(); } bool active = false; @@ -216,7 +212,7 @@ Decoration::Decoration(WindowWayland& window): } void Decoration::close() { - if (_top.surface) + if (_border.surface) _destroyDecorations(); if (_decoration) zxdg_toplevel_decoration_v1_destroy(_decoration); @@ -266,10 +262,7 @@ void Decoration::_destroyDecoration(DecorationPart* decoration) { } void Decoration::_destroyDecorations() { - _destroyDecoration(&_top); - _destroyDecoration(&_left); - _destroyDecoration(&_right); - _destroyDecoration(&_bottom); + _destroyDecoration(&_border); _destroyDecoration(&_close); _destroyDecoration(&_min); _destroyDecoration(&_max); @@ -287,18 +280,13 @@ void Decoration::_showDecorations(bool hidden) { _minBuffer = Buffer::createShmBuffer(_wm.shm, 9, 9, WL_SHM_FORMAT_ARGB8888); memcpy(_minBuffer->getData(), min_data, 9 * 9 * sizeof(uint32_t)); if (hidden) { - _makePart(&_top, _decBuffer, true, DECORATION_TOP_X, DECORATION_HIDDEN_TOP_Y, DECORATION_BOTTOM_WIDTH(_window), DECORATION_BOTTOM_HEIGHT); - _makePart(&_left, _decBuffer, true, DECORATION_LEFT_X, DECORATION_HIDDEN_LEFT_Y, DECORATION_LEFT_WIDTH, - DECORATION_HIDDEN_LEFT_HEIGHT(_window)); - _makePart(&_right, _decBuffer, true, DECORATION_RIGHT_X(_window), DECORATION_HIDDEN_RIGHT_Y, - DECORATION_RIGHT_WIDTH, DECORATION_HIDDEN_RIGHT_HEIGHT(_window)); + _makePart(&_border, _decBuffer, true, DECORATION_BORDER_X, DECORATION_HIDDEN_BORDER_Y, + DECORATION_BORDER_WIDTH(_window), DECORATION_HIDDEN_BORDER_HEIGHT(_window)); } else { - _makePart(&_top, _decBuffer, true, DECORATION_TOP_X, DECORATION_TOP_Y, DECORATION_TOP_WIDTH(_window), DECORATION_TOP_HEIGHT); - _makePart(&_left, _decBuffer, true, DECORATION_LEFT_X, DECORATION_LEFT_Y, DECORATION_LEFT_WIDTH, DECORATION_LEFT_HEIGHT(_window)); - _makePart(&_right, _decBuffer, true, DECORATION_RIGHT_X(_window), DECORATION_RIGHT_Y, DECORATION_RIGHT_WIDTH, DECORATION_RIGHT_HEIGHT(_window)); + _makePart(&_border, _decBuffer, true, DECORATION_BORDER_X, DECORATION_BORDER_Y, + DECORATION_BORDER_WIDTH(_window), DECORATION_BORDER_HEIGHT(_window)); } - _makePart(&_bottom, _decBuffer, true, DECORATION_BOTTOM_X, DECORATION_BOTTOM_Y(_window), DECORATION_BOTTOM_WIDTH(_window), DECORATION_BOTTOM_HEIGHT); - + wl_subsurface_place_below(_border.subsurface, _window._waylandWindow); if (!hidden) { _makePart(&_close, _closeBuffer, false, DECORATION_CLOSE_X(_window), DECORATION_CLOSE_Y, DECORATION_CLOSE_WIDTH, DECORATION_CLOSE_HEIGHT); _makePart(&_max, _maxBuffer, false, DECORATION_MAX_X(_window), DECORATION_MAX_Y, DECORATION_MAX_WIDTH, DECORATION_MAX_HEIGHT); @@ -309,17 +297,12 @@ void Decoration::_showDecorations(bool hidden) { void Decoration::_adaptSize() { if (!_isVisible) { - _resizeDecoration(&_top, DECORATION_TOP_X, DECORATION_HIDDEN_TOP_Y, DECORATION_BOTTOM_WIDTH(_window), DECORATION_BOTTOM_HEIGHT); - _resizeDecoration(&_left, DECORATION_LEFT_X, DECORATION_HIDDEN_LEFT_Y, DECORATION_LEFT_WIDTH, - DECORATION_HIDDEN_LEFT_HEIGHT(_window)); - _resizeDecoration(&_right, DECORATION_RIGHT_X(_window), DECORATION_HIDDEN_RIGHT_Y, DECORATION_RIGHT_WIDTH, - DECORATION_HIDDEN_RIGHT_HEIGHT(_window)); + _resizeDecoration(&_border, DECORATION_BORDER_X, DECORATION_HIDDEN_BORDER_Y, DECORATION_BORDER_WIDTH(_window), + DECORATION_HIDDEN_BORDER_HEIGHT(_window)); } else { - _resizeDecoration(&_top, DECORATION_TOP_X, DECORATION_TOP_Y, DECORATION_TOP_WIDTH(_window), DECORATION_TOP_HEIGHT); - _resizeDecoration(&_left, DECORATION_LEFT_X, DECORATION_LEFT_Y, DECORATION_LEFT_WIDTH, DECORATION_LEFT_HEIGHT(_window)); - _resizeDecoration(&_right, DECORATION_RIGHT_X(_window), DECORATION_RIGHT_Y, DECORATION_RIGHT_WIDTH, DECORATION_RIGHT_HEIGHT(_window)); + _resizeDecoration(&_border, DECORATION_BORDER_X, DECORATION_BORDER_Y, + DECORATION_BORDER_WIDTH(_window), DECORATION_BORDER_HEIGHT(_window)); } - _resizeDecoration(&_bottom, DECORATION_BOTTOM_X, DECORATION_BOTTOM_Y(_window), DECORATION_BOTTOM_WIDTH(_window), DECORATION_BOTTOM_HEIGHT); if (_isVisible) { _resizeDecoration(&_close, DECORATION_CLOSE_X(_window), DECORATION_CLOSE_Y, DECORATION_CLOSE_WIDTH, DECORATION_CLOSE_HEIGHT); @@ -328,9 +311,9 @@ void Decoration::_adaptSize() { } if (!_serverSide) - xdg_surface_set_window_geometry(_xdgSurface, -DECORATION_LEFT_WIDTH, _isVisible ? -DECORATION_TOP_HEIGHT : -DECORATION_BOTTOM_HEIGHT, - _window.getUnscaledWidth() + DECORATION_RIGHT_WIDTH + DECORATION_LEFT_WIDTH, - _window.getUnscaledHeight() + DECORATION_BOTTOM_HEIGHT + DECORATION_TOP_HEIGHT); + xdg_surface_set_window_geometry(_xdgSurface, DECORATION_BORDER_X, _isVisible ? DECORATION_BORDER_Y : DECORATION_HIDDEN_BORDER_Y, + DECORATION_BORDER_WIDTH(_window), + _isVisible ? DECORATION_BORDER_HEIGHT(_window) : DECORATION_HIDDEN_BORDER_HEIGHT(_window)); else xdg_surface_set_window_geometry(_xdgSurface, 0, 0, _window.getUnscaledWidth(), _window.getUnscaledHeight()); } @@ -343,14 +326,8 @@ bool Decoration::ownDecorationSurface(wl_surface* surface) { Decoration* Decoration::getDecorationForSurface(wl_surface* surface, DecorationFocus* focus) { if (ownDecorationSurface(surface)) { Decoration* decoration = (Decoration*)wl_proxy_get_user_data((wl_proxy*) surface); - if (surface == decoration->_top.surface) { - *focus = DECORATION_FOCUS_TOP; - } else if (surface == decoration->_left.surface) { - *focus = DECORATION_FOCUS_LEFT; - } else if (surface == decoration->_right.surface) { - *focus = DECORATION_FOCUS_RIGHT; - } else if (surface == decoration->_bottom.surface) { - *focus = DECORATION_FOCUS_BOTTOM; + if (surface == decoration->_border.surface) { + *focus = DECORATION_FOCUS_BORDER; } else if (surface == decoration->_close.surface) { *focus = DECORATION_FOCUS_CLOSE_BUTTON; } else if (surface == decoration->_min.surface) { @@ -402,10 +379,10 @@ void Decoration::getBorders(int& left, int& top, int& right, int& bottom) { right = 0; bottom = 0; } else { - left = DECORATION_LEFT_WIDTH; + left = DECORATION_WIDTH; top = getTopSize(); - right = DECORATION_RIGHT_WIDTH; - bottom = DECORATION_BOTTOM_HEIGHT; + right = DECORATION_WIDTH; + bottom = DECORATION_WIDTH; } } @@ -415,5 +392,5 @@ int Decoration::getTopSize() { if (_isVisible) return DECORATION_TOP_HEIGHT; else - return DECORATION_BOTTOM_HEIGHT; + return DECORATION_WIDTH; } diff --git a/wayland/cc/Decoration.hh b/wayland/cc/Decoration.hh index 2c36223f..1382f7c6 100644 --- a/wayland/cc/Decoration.hh +++ b/wayland/cc/Decoration.hh @@ -9,31 +9,15 @@ #include #define DECORATION_WIDTH 4 - -#define DECORATION_HIDDEN_TOP_Y -(DECORATION_BOTTOM_HEIGHT) -#define DECORATION_TOP_X 0 -#define DECORATION_TOP_Y -(DECORATION_TOP_HEIGHT) -#define DECORATION_TOP_WIDTH(window) window.getUnscaledWidth() #define DECORATION_TOP_HEIGHT 30 -#define DECORATION_HIDDEN_LEFT_Y DECORATION_HIDDEN_TOP_Y -#define DECORATION_HIDDEN_LEFT_HEIGHT(window) window.getUnscaledHeight() + DECORATION_WIDTH + DECORATION_WIDTH -#define DECORATION_LEFT_X -(DECORATION_WIDTH) -#define DECORATION_LEFT_Y -(DECORATION_TOP_HEIGHT) -#define DECORATION_LEFT_WIDTH DECORATION_WIDTH -#define DECORATION_LEFT_HEIGHT(window) window.getUnscaledHeight() + DECORATION_TOP_HEIGHT + DECORATION_WIDTH - -#define DECORATION_HIDDEN_RIGHT_Y DECORATION_HIDDEN_LEFT_Y -#define DECORATION_HIDDEN_RIGHT_HEIGHT(window) DECORATION_HIDDEN_LEFT_HEIGHT(window) -#define DECORATION_RIGHT_X(window) window.getUnscaledWidth() -#define DECORATION_RIGHT_Y -(DECORATION_TOP_HEIGHT) -#define DECORATION_RIGHT_WIDTH DECORATION_WIDTH -#define DECORATION_RIGHT_HEIGHT(window) window.getUnscaledHeight() + DECORATION_TOP_HEIGHT + DECORATION_WIDTH - -#define DECORATION_BOTTOM_X 0 -#define DECORATION_BOTTOM_Y(window) window.getUnscaledHeight() -#define DECORATION_BOTTOM_WIDTH(window) window.getUnscaledWidth() -#define DECORATION_BOTTOM_HEIGHT DECORATION_WIDTH +#define DECORATION_BORDER_X -(DECORATION_WIDTH) +#define DECORATION_BORDER_Y -(DECORATION_TOP_HEIGHT) +#define DECORATION_BORDER_WIDTH(window) window.getUnscaledWidth() + DECORATION_WIDTH + DECORATION_WIDTH +#define DECORATION_BORDER_HEIGHT(window) window.getUnscaledHeight() + DECORATION_TOP_HEIGHT + DECORATION_WIDTH + +#define DECORATION_HIDDEN_BORDER_Y -(DECORATION_WIDTH) +#define DECORATION_HIDDEN_BORDER_HEIGHT(window) window.getUnscaledHeight() + DECORATION_WIDTH + DECORATION_WIDTH #define DECORATION_CLOSE_X(window) window.getUnscaledWidth() - 10 #define DECORATION_CLOSE_Y -20 @@ -60,10 +44,7 @@ namespace jwm { }; enum DecorationFocus { DECORATION_FOCUS_MAIN, - DECORATION_FOCUS_TOP, - DECORATION_FOCUS_LEFT, - DECORATION_FOCUS_RIGHT, - DECORATION_FOCUS_BOTTOM, + DECORATION_FOCUS_BORDER, DECORATION_FOCUS_CLOSE_BUTTON, DECORATION_FOCUS_MAX_BUTTON, DECORATION_FOCUS_MIN_BUTTON @@ -84,10 +65,7 @@ namespace jwm { Buffer* _maxBuffer; Buffer* _minBuffer; - DecorationPart _top; - DecorationPart _left; - DecorationPart _right; - DecorationPart _bottom; + DecorationPart _border; DecorationPart _close; DecorationPart _max; diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index 84246051..44e70f06 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -51,31 +51,37 @@ static void pointerLeave(void* data, wl_pointer* pointer, uint32_t serial, } } static xdg_toplevel_resize_edge resizeEdge(DecorationFocus focus, WindowWayland& window, int x, int y) { + int rightEdge = window.getUnscaledWidth(); + int bottomEdge = window.getUnscaledHeight(); switch (focus) { case DECORATION_FOCUS_MAIN: // ??? return XDG_TOPLEVEL_RESIZE_EDGE_NONE; - case DECORATION_FOCUS_TOP: - if (y < window._decoration->getTopSize() / 2) - return XDG_TOPLEVEL_RESIZE_EDGE_TOP; - else - return XDG_TOPLEVEL_RESIZE_EDGE_NONE; - case DECORATION_FOCUS_LEFT: - if (y < window._decoration->getTopSize() / 2) - return XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; - else if (y > DECORATION_BOTTOM_Y(window)) - return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT; - else - return XDG_TOPLEVEL_RESIZE_EDGE_LEFT; - case DECORATION_FOCUS_RIGHT: - if (y < window._decoration->getTopSize() / 2) - return XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; - else if (y > DECORATION_BOTTOM_Y(window)) - return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT; - else - return XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; - case DECORATION_FOCUS_BOTTOM: - return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM; + case DECORATION_FOCUS_BORDER: + if (y < -window._decoration->getTopSize() / 2) { + if (x < 0) + return XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; + else if (x > rightEdge) + return XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; + else + return XDG_TOPLEVEL_RESIZE_EDGE_TOP; + } + else if (y > bottomEdge) { + if (x < 0) + return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT; + else if (x > rightEdge) + return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT; + else + return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM; + } else { + if (x < 0) + return XDG_TOPLEVEL_RESIZE_EDGE_LEFT; + else if (x > rightEdge) + return XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; + else + return XDG_TOPLEVEL_RESIZE_EDGE_NONE; + } + return XDG_TOPLEVEL_RESIZE_EDGE_NONE; default: return XDG_TOPLEVEL_RESIZE_EDGE_NONE; } @@ -93,14 +99,18 @@ static void pointerMotion(void* data, wl_pointer* pointer, uint32_t time, int x = wl_fixed_to_int(surface_x); int y = wl_fixed_to_int(surface_y); // ??? - self->_absX = x; - self->_absY = y; switch (self->_decorationFocus) { case DECORATION_FOCUS_MAIN: + self->_absX = x; + self->_absY = y; self->_movement = true; break; default: - auto edge = resizeEdge(self->_decorationFocus, *self->_focusedSurface, x, y); + if (self->_decorationFocus == DECORATION_FOCUS_BORDER) { + self->_absX = x - DECORATION_WIDTH; + self->_absY = y - self->_focusedSurface->_decoration->getTopSize(); + } + auto edge = resizeEdge(self->_decorationFocus, *self->_focusedSurface, self->_absX, self->_absY); switch (edge) { case XDG_TOPLEVEL_RESIZE_EDGE_TOP: case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM: @@ -141,14 +151,10 @@ static void pointerButton(void* data, wl_pointer* pointer, uint32_t serial, if (state == 0) return; if (button == BTN_RIGHT) { - switch (self->_decorationFocus) { - case DECORATION_FOCUS_TOP: - // not showing but this code is being reached - xdg_toplevel_show_window_menu(window->_decoration->_xdgToplevel, self->_seat, serial, self->_absX, self->_absY); - return; - default: - return; - } + if (self->_absY < 0) + xdg_toplevel_show_window_menu(window->_decoration->_xdgToplevel, self->_seat, serial, + self->_absX + DECORATION_WIDTH, self->_absY + window->_decoration->getTopSize()); + return; } if (button != BTN_LEFT) return; From 7c921ca23c820de76afcb56af0ea5dce6ab28a60 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Sat, 6 Jan 2024 13:37:25 -0500 Subject: [PATCH 81/93] make title great again --- wayland/cc/Decoration.cc | 35 +++++++++++++++-------------------- wayland/cc/Decoration.hh | 13 +++++++++---- wayland/cc/Pointer.cc | 33 ++++++++++++++++++++++++++------- 3 files changed, 50 insertions(+), 31 deletions(-) diff --git a/wayland/cc/Decoration.cc b/wayland/cc/Decoration.cc index 58b8efe4..fba2bdec 100644 --- a/wayland/cc/Decoration.cc +++ b/wayland/cc/Decoration.cc @@ -206,7 +206,6 @@ Decoration::Decoration(WindowWayland& window): zxdg_toplevel_decoration_v1_add_listener(_decoration, &_decorationListener, this); // for the love of GOD do it for me zxdg_toplevel_decoration_v1_set_mode(_decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); - } // delay making parts until configure : ) } @@ -263,6 +262,7 @@ void Decoration::_destroyDecoration(DecorationPart* decoration) { void Decoration::_destroyDecorations() { _destroyDecoration(&_border); + _destroyDecoration(&_titleComp); _destroyDecoration(&_close); _destroyDecoration(&_min); _destroyDecoration(&_max); @@ -279,15 +279,13 @@ void Decoration::_showDecorations(bool hidden) { memcpy(_maxBuffer->getData(), max_data, 9 * 9 * sizeof(uint32_t)); _minBuffer = Buffer::createShmBuffer(_wm.shm, 9, 9, WL_SHM_FORMAT_ARGB8888); memcpy(_minBuffer->getData(), min_data, 9 * 9 * sizeof(uint32_t)); - if (hidden) { - _makePart(&_border, _decBuffer, true, DECORATION_BORDER_X, DECORATION_HIDDEN_BORDER_Y, - DECORATION_BORDER_WIDTH(_window), DECORATION_HIDDEN_BORDER_HEIGHT(_window)); - } else { - _makePart(&_border, _decBuffer, true, DECORATION_BORDER_X, DECORATION_BORDER_Y, - DECORATION_BORDER_WIDTH(_window), DECORATION_BORDER_HEIGHT(_window)); - } + _makePart(&_border, _decBuffer, true, DECORATION_BORDER_X, DECORATION_BORDER_Y, + DECORATION_BORDER_WIDTH(_window), DECORATION_BORDER_HEIGHT(_window)); wl_subsurface_place_below(_border.subsurface, _window._waylandWindow); if (!hidden) { + _makePart(&_titleComp, _decBuffer, true, DECORATION_TITLE_X, DECORATION_TITLE_Y, + DECORATION_TITLE_WIDTH(_window), DECORATION_TITLE_HEIGHT); + wl_subsurface_place_above(_titleComp.subsurface, _border.surface); _makePart(&_close, _closeBuffer, false, DECORATION_CLOSE_X(_window), DECORATION_CLOSE_Y, DECORATION_CLOSE_WIDTH, DECORATION_CLOSE_HEIGHT); _makePart(&_max, _maxBuffer, false, DECORATION_MAX_X(_window), DECORATION_MAX_Y, DECORATION_MAX_WIDTH, DECORATION_MAX_HEIGHT); _makePart(&_min, _minBuffer, false, DECORATION_MIN_X(_window), DECORATION_MIN_Y, DECORATION_MIN_WIDTH, DECORATION_MIN_HEIGHT); @@ -296,24 +294,20 @@ void Decoration::_showDecorations(bool hidden) { } void Decoration::_adaptSize() { - if (!_isVisible) { - _resizeDecoration(&_border, DECORATION_BORDER_X, DECORATION_HIDDEN_BORDER_Y, DECORATION_BORDER_WIDTH(_window), - DECORATION_HIDDEN_BORDER_HEIGHT(_window)); - } else { - _resizeDecoration(&_border, DECORATION_BORDER_X, DECORATION_BORDER_Y, - DECORATION_BORDER_WIDTH(_window), DECORATION_BORDER_HEIGHT(_window)); - } - + _resizeDecoration(&_border, DECORATION_BORDER_X, DECORATION_BORDER_Y, + DECORATION_BORDER_WIDTH(_window), DECORATION_BORDER_HEIGHT(_window)); if (_isVisible) { + _resizeDecoration(&_titleComp, DECORATION_TITLE_X, DECORATION_TITLE_Y, + DECORATION_TITLE_WIDTH(_window), DECORATION_TITLE_HEIGHT); _resizeDecoration(&_close, DECORATION_CLOSE_X(_window), DECORATION_CLOSE_Y, DECORATION_CLOSE_WIDTH, DECORATION_CLOSE_HEIGHT); _resizeDecoration(&_min, DECORATION_MIN_X(_window), DECORATION_MIN_Y, DECORATION_MIN_WIDTH, DECORATION_MIN_HEIGHT); _resizeDecoration(&_max, DECORATION_MAX_X(_window), DECORATION_MAX_Y, DECORATION_MAX_WIDTH, DECORATION_MAX_HEIGHT); } if (!_serverSide) - xdg_surface_set_window_geometry(_xdgSurface, DECORATION_BORDER_X, _isVisible ? DECORATION_BORDER_Y : DECORATION_HIDDEN_BORDER_Y, + xdg_surface_set_window_geometry(_xdgSurface, DECORATION_BORDER_X, _isVisible ? DECORATION_TITLE_Y : DECORATION_BORDER_Y, DECORATION_BORDER_WIDTH(_window), - _isVisible ? DECORATION_BORDER_HEIGHT(_window) : DECORATION_HIDDEN_BORDER_HEIGHT(_window)); + _isVisible ? DECORATION_BORDER_FULL_HEIGHT(_window) : DECORATION_BORDER_HEIGHT(_window)); else xdg_surface_set_window_geometry(_xdgSurface, 0, 0, _window.getUnscaledWidth(), _window.getUnscaledHeight()); } @@ -328,6 +322,8 @@ Decoration* Decoration::getDecorationForSurface(wl_surface* surface, DecorationF Decoration* decoration = (Decoration*)wl_proxy_get_user_data((wl_proxy*) surface); if (surface == decoration->_border.surface) { *focus = DECORATION_FOCUS_BORDER; + } else if (surface == decoration->_titleComp.surface) { + *focus = DECORATION_FOCUS_TITLE; } else if (surface == decoration->_close.surface) { *focus = DECORATION_FOCUS_CLOSE_BUTTON; } else if (surface == decoration->_min.surface) { @@ -355,11 +351,10 @@ void Decoration::setTitlebarVisible(bool isVisible) { } } else { _destroyDecorations(); - _showDecorations(true); if (_decoration) { zxdg_toplevel_decoration_v1_set_mode(_decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); } else { - // TODO: request reconfigure + _showDecorations(true); wl_surface_commit(_window._waylandWindow); } } diff --git a/wayland/cc/Decoration.hh b/wayland/cc/Decoration.hh index 1382f7c6..7c18708b 100644 --- a/wayland/cc/Decoration.hh +++ b/wayland/cc/Decoration.hh @@ -12,12 +12,15 @@ #define DECORATION_TOP_HEIGHT 30 #define DECORATION_BORDER_X -(DECORATION_WIDTH) -#define DECORATION_BORDER_Y -(DECORATION_TOP_HEIGHT) +#define DECORATION_BORDER_Y -(DECORATION_WIDTH) #define DECORATION_BORDER_WIDTH(window) window.getUnscaledWidth() + DECORATION_WIDTH + DECORATION_WIDTH -#define DECORATION_BORDER_HEIGHT(window) window.getUnscaledHeight() + DECORATION_TOP_HEIGHT + DECORATION_WIDTH +#define DECORATION_BORDER_HEIGHT(window) window.getUnscaledHeight() + DECORATION_WIDTH + DECORATION_WIDTH +#define DECORATION_BORDER_FULL_HEIGHT(window) window.getUnscaledHeight() + DECORATION_TOP_HEIGHT + DECORATION_WIDTH -#define DECORATION_HIDDEN_BORDER_Y -(DECORATION_WIDTH) -#define DECORATION_HIDDEN_BORDER_HEIGHT(window) window.getUnscaledHeight() + DECORATION_WIDTH + DECORATION_WIDTH +#define DECORATION_TITLE_X -(DECORATION_WIDTH) +#define DECORATION_TITLE_Y -(DECORATION_TOP_HEIGHT) +#define DECORATION_TITLE_WIDTH(window) window.getUnscaledWidth() + DECORATION_WIDTH + DECORATION_WIDTH +#define DECORATION_TITLE_HEIGHT DECORATION_TOP_HEIGHT #define DECORATION_CLOSE_X(window) window.getUnscaledWidth() - 10 #define DECORATION_CLOSE_Y -20 @@ -45,6 +48,7 @@ namespace jwm { enum DecorationFocus { DECORATION_FOCUS_MAIN, DECORATION_FOCUS_BORDER, + DECORATION_FOCUS_TITLE, DECORATION_FOCUS_CLOSE_BUTTON, DECORATION_FOCUS_MAX_BUTTON, DECORATION_FOCUS_MIN_BUTTON @@ -66,6 +70,7 @@ namespace jwm { Buffer* _minBuffer; DecorationPart _border; + DecorationPart _titleComp; DecorationPart _close; DecorationPart _max; diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index 44e70f06..a861ff70 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -7,6 +7,8 @@ #include #include #include +#include +#include using namespace jwm; @@ -50,21 +52,33 @@ static void pointerLeave(void* data, wl_pointer* pointer, uint32_t serial, self->_decorationFocus = DECORATION_FOCUS_MAIN; } } -static xdg_toplevel_resize_edge resizeEdge(DecorationFocus focus, WindowWayland& window, int x, int y) { +static xdg_toplevel_resize_edge resizeEdge(DecorationFocus focus, WindowWayland& window, int x, int y, xkb_state* state) { int rightEdge = window.getUnscaledWidth(); int bottomEdge = window.getUnscaledHeight(); switch (focus) { case DECORATION_FOCUS_MAIN: // ??? return XDG_TOPLEVEL_RESIZE_EDGE_NONE; + case DECORATION_FOCUS_TITLE: + if (y < -DECORATION_TOP_HEIGHT / 2) + return XDG_TOPLEVEL_RESIZE_EDGE_TOP; + else + return XDG_TOPLEVEL_RESIZE_EDGE_NONE; case DECORATION_FOCUS_BORDER: - if (y < -window._decoration->getTopSize() / 2) { + + if (y < 0) { if (x < 0) return XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; else if (x > rightEdge) return XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; - else + else { + if (state) { + if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_EFFECTIVE)) + // grab + return XDG_TOPLEVEL_RESIZE_EDGE_NONE; + } return XDG_TOPLEVEL_RESIZE_EDGE_TOP; + } } else if (y > bottomEdge) { if (x < 0) @@ -108,9 +122,13 @@ static void pointerMotion(void* data, wl_pointer* pointer, uint32_t time, default: if (self->_decorationFocus == DECORATION_FOCUS_BORDER) { self->_absX = x - DECORATION_WIDTH; - self->_absY = y - self->_focusedSurface->_decoration->getTopSize(); + self->_absY = y - DECORATION_WIDTH; + } else if (self->_decorationFocus == DECORATION_FOCUS_TITLE) { + self->_absX = x - DECORATION_WIDTH; + self->_absY = y - DECORATION_TOP_HEIGHT; } - auto edge = resizeEdge(self->_decorationFocus, *self->_focusedSurface, self->_absX, self->_absY); + auto edge = resizeEdge(self->_decorationFocus, *self->_focusedSurface, self->_absX, self->_absY, + self->_wm.getXkbState()); switch (edge) { case XDG_TOPLEVEL_RESIZE_EDGE_TOP: case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM: @@ -171,8 +189,9 @@ static void pointerButton(void* data, wl_pointer* pointer, uint32_t serial, else xdg_toplevel_set_maximized(window->_decoration->_xdgToplevel); break; - default: - xdg_toplevel_resize_edge edge = resizeEdge(self->_decorationFocus, *window, self->_absX, self->_absY); + case DECORATION_FOCUS_BORDER: + case DECORATION_FOCUS_TITLE: + xdg_toplevel_resize_edge edge = resizeEdge(self->_decorationFocus, *window, self->_absX, self->_absY, self->_wm.getXkbState()); if (edge == XDG_TOPLEVEL_RESIZE_EDGE_NONE) xdg_toplevel_move(window->_decoration->_xdgToplevel, self->_seat, serial); else From a2c8a479a699525c48cfb612bfc57d9b55cd8856 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Sun, 7 Jan 2024 13:43:49 -0500 Subject: [PATCH 82/93] edit title bar grabbing --- wayland/cc/Pointer.cc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index a861ff70..a095d168 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -60,10 +60,16 @@ static xdg_toplevel_resize_edge resizeEdge(DecorationFocus focus, WindowWayland& // ??? return XDG_TOPLEVEL_RESIZE_EDGE_NONE; case DECORATION_FOCUS_TITLE: - if (y < -DECORATION_TOP_HEIGHT / 2) - return XDG_TOPLEVEL_RESIZE_EDGE_TOP; - else - return XDG_TOPLEVEL_RESIZE_EDGE_NONE; + if (x < 0) { + return XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; + } else if (x > rightEdge) { + return XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; + } else { + if (y < -DECORATION_TOP_HEIGHT / 2) + return XDG_TOPLEVEL_RESIZE_EDGE_TOP; + else + return XDG_TOPLEVEL_RESIZE_EDGE_NONE; + } case DECORATION_FOCUS_BORDER: if (y < 0) { From adef9aef4ef5700bc22fda50ab9b37d5fe2ff488 Mon Sep 17 00:00:00 2001 From: TheDrawingCoding-Gamer Date: Sun, 7 Jan 2024 15:37:49 -0500 Subject: [PATCH 83/93] configure on first resize --- wayland/cc/Decoration.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wayland/cc/Decoration.cc b/wayland/cc/Decoration.cc index fba2bdec..86232824 100644 --- a/wayland/cc/Decoration.cc +++ b/wayland/cc/Decoration.cc @@ -94,6 +94,8 @@ static void _xdgSurfaceConfigure(void* data, xdg_surface* surface, uint32_t seri if (window._layer) window._layer->attachBuffer(); } + // resize on first configure + self->_configured = true; // ask to configure _before_ commit. jank. if (self->_floating) { xdg_surface_ack_configure(self->_xdgSurface, serial); @@ -117,8 +119,6 @@ static void _xdgSurfaceConfigure(void* data, xdg_surface* surface, uint32_t seri if (!self->_border.surface) self->_showDecorations(!self->_isVisible); } - // at the end so that the size isn't adapted on first render - self->_configured = true; wl_surface_commit(window._waylandWindow); if (!self->_floating) { From d34bd628bd991d4638b51e4ce0e334bf5dcb22bb Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Mon, 8 Jan 2024 18:21:40 -0500 Subject: [PATCH 84/93] always allow movement on border with ctrl --- wayland/cc/Pointer.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index a095d168..c428e33f 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -71,18 +71,17 @@ static xdg_toplevel_resize_edge resizeEdge(DecorationFocus focus, WindowWayland& return XDG_TOPLEVEL_RESIZE_EDGE_NONE; } case DECORATION_FOCUS_BORDER: - + if (state) { + if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_EFFECTIVE)) { + return XDG_TOPLEVEL_RESIZE_EDGE_NONE; + } + } if (y < 0) { if (x < 0) return XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; else if (x > rightEdge) return XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; else { - if (state) { - if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_EFFECTIVE)) - // grab - return XDG_TOPLEVEL_RESIZE_EDGE_NONE; - } return XDG_TOPLEVEL_RESIZE_EDGE_TOP; } } From 737857e93e934dd1c2ec6556854c11b783fa2e1b Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Mon, 8 Jan 2024 21:42:25 -0500 Subject: [PATCH 85/93] urgency/focus stealing only tested on sway; weston is known to not support activation, but mutter and kwin do. need to test there. On sway this is seen as a red flash in the swaybar. --- wayland/CMakeLists.txt | 4 ++++ wayland/cc/Decoration.cc | 20 ++++++++++--------- wayland/cc/Token.cc | 31 ++++++++++++++++++++++++++++++ wayland/cc/Token.hh | 14 ++++++++++++++ wayland/cc/WindowManagerWayland.cc | 3 +++ wayland/cc/WindowManagerWayland.hh | 3 ++- wayland/cc/WindowWayland.cc | 14 ++++++++++++++ wayland/cc/WindowWayland.hh | 1 + wayland/java/WindowWayland.java | 3 ++- 9 files changed, 82 insertions(+), 11 deletions(-) create mode 100644 wayland/cc/Token.cc create mode 100644 wayland/cc/Token.hh diff --git a/wayland/CMakeLists.txt b/wayland/CMakeLists.txt index 0b18c608..c3685b6f 100644 --- a/wayland/CMakeLists.txt +++ b/wayland/CMakeLists.txt @@ -57,6 +57,10 @@ ecm_add_wayland_client_protocol(protocols PROTOCOL "${WaylandProtocols_DATADIR}/stable/viewporter/viewporter.xml" BASENAME viewporter ) +ecm_add_wayland_client_protocol(protocols + PROTOCOL "${WaylandProtocols_DATADIR}/staging/xdg-activation/xdg-activation-v1.xml" + BASENAME xdg-activation-v1 + ) find_library(WAYLAND_CLIENT_LIB wayland-client) find_library(WAYLAND_CURSOR wayland-cursor) find_library(XKBCOMMON xkbcommon) diff --git a/wayland/cc/Decoration.cc b/wayland/cc/Decoration.cc index 86232824..ebd7bcca 100644 --- a/wayland/cc/Decoration.cc +++ b/wayland/cc/Decoration.cc @@ -58,14 +58,20 @@ static void _xdgSurfaceConfigure(void* data, xdg_surface* surface, uint32_t seri auto self = reinterpret_cast(data); auto& window = self->_window; int width = 0, height = 0; - - if (self->_pendingWidth > 0) - width = self->_pendingWidth; + int pendingWidth = self->_pendingWidth; + int pendingHeight = self->_pendingHeight; + // do it here bc we don't know configure order + if (!self->_serverSide) { + pendingWidth -= DECORATION_WIDTH + DECORATION_WIDTH; + pendingHeight -= DECORATION_WIDTH + self->getTopSize(); + } + if (pendingWidth > 0) + width = pendingWidth; else width = window._floatingWidth; - if (self->_pendingHeight > 0) - height = self->_pendingHeight; + if (pendingHeight > 0) + height = pendingHeight; else height = window._floatingHeight; @@ -135,10 +141,6 @@ static void _xdgToplevelConfigure(void* data, xdg_toplevel* toplevel, int width, self->_pendingWidth = width; self->_pendingHeight = height; - if (!self->_serverSide) { - self->_pendingWidth -= DECORATION_WIDTH + DECORATION_WIDTH; - self->_pendingHeight -= DECORATION_WIDTH + self->getTopSize(); - } bool active = false; bool maximized = false; diff --git a/wayland/cc/Token.cc b/wayland/cc/Token.cc new file mode 100644 index 00000000..d95034b2 --- /dev/null +++ b/wayland/cc/Token.cc @@ -0,0 +1,31 @@ +#include "Token.hh" +#include "WindowManagerWayland.hh" + + +static void _xdgTokenDone(void* data, xdg_activation_token_v1* token, const char* tokenStr) { + xdg_activation_token_v1_destroy(token); + std::string* str = reinterpret_cast(data); + *str = std::string(tokenStr); +} +static xdg_activation_token_v1_listener _tokenListener = { + .done = _xdgTokenDone +}; +jwm::Token jwm::Token::make(jwm::WindowManagerWayland& wm, wl_surface* surface) { + if (!wm.xdgActivation) + return {}; + auto token = xdg_activation_v1_get_activation_token(wm.xdgActivation); + if (surface) + xdg_activation_token_v1_set_surface(token, surface); + std::string str; + xdg_activation_token_v1_add_listener(token, &_tokenListener, &str); + xdg_activation_token_v1_commit(token); + wl_display_roundtrip(wm.display); + + return {str}; +} + +void jwm::Token::grab(jwm::WindowManagerWayland& wm, wl_surface* surface) { + if (!wm.xdgActivation) + return; + xdg_activation_v1_activate(wm.xdgActivation, token.c_str(), surface); +} diff --git a/wayland/cc/Token.hh b/wayland/cc/Token.hh new file mode 100644 index 00000000..23f781cf --- /dev/null +++ b/wayland/cc/Token.hh @@ -0,0 +1,14 @@ +#include +#include +#include + +namespace jwm { + class WindowManagerWayland; + struct Token { + std::string token; + // blocks + static Token make(WindowManagerWayland& wm, wl_surface* surface); + + void grab(WindowManagerWayland& wm, wl_surface* surface); + }; +} diff --git a/wayland/cc/WindowManagerWayland.cc b/wayland/cc/WindowManagerWayland.cc index 4bbd59d9..14bc4f5a 100644 --- a/wayland/cc/WindowManagerWayland.cc +++ b/wayland/cc/WindowManagerWayland.cc @@ -270,6 +270,9 @@ void WindowManagerWayland::registryHandleGlobal(void* data, wl_registry *registr } else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) { self->decorationManager = (zxdg_decoration_manager_v1*)wl_registry_bind(registry, name, &zxdg_decoration_manager_v1_interface, 1); + } else if (strcmp(interface, xdg_activation_v1_interface.name) == 0) { + self->xdgActivation = (xdg_activation_v1*)wl_registry_bind(registry, name, + &xdg_activation_v1_interface, 1); } } void WindowManagerWayland::registryHandleGlobalRemove(void* data, wl_registry *registry, uint32_t name) { diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index e0c63917..f0c536a7 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -25,6 +25,7 @@ #include #include #include +#include namespace jwm { class WindowWayland; @@ -77,7 +78,7 @@ namespace jwm { wp_viewporter* viewporter = nullptr; zxdg_decoration_manager_v1* decorationManager = nullptr; wl_subcompositor* subcompositor = nullptr; - + xdg_activation_v1* xdgActivation = nullptr; std::unique_ptr _pointer = nullptr; Pointer* getPointer() const { return _pointer.get(); diff --git a/wayland/cc/WindowWayland.cc b/wayland/cc/WindowWayland.cc index 954d69c6..a65eddbe 100644 --- a/wayland/cc/WindowWayland.cc +++ b/wayland/cc/WindowWayland.cc @@ -8,6 +8,7 @@ #include #include #include +#include "Token.hh" using namespace jwm; @@ -335,6 +336,12 @@ void jwm::WindowWayland::hideCursor(bool hidden) { pointer->unhide(); } } + +void jwm::WindowWayland::focus() { + if (!_waylandWindow) return; + auto token = Token::make(_windowManager, _waylandWindow); + token.grab(_windowManager, _waylandWindow); +} // JNI extern "C" JNIEXPORT jlong JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nMake @@ -480,3 +487,10 @@ extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nH jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); instance->hideCursor(hidden); } + +extern "C" JNIEXPORT void JNICALL Java_io_github_humbleui_jwm_WindowWayland__1nFocus + (JNIEnv* env, jobject obj) +{ + jwm::WindowWayland* instance = reinterpret_cast(jwm::classes::Native::fromJava(env, obj)); + instance->focus(); +} diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index e853acc2..753f6d64 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -55,6 +55,7 @@ namespace jwm { void setCursorMaybe(jwm::MouseCursor cursor, bool force); void setCursor(jwm::MouseCursor cursor); void setLayer(ILayerWayland* layer); + void focus(); wl_cursor* _getCursorFor(jwm::MouseCursor cursor); ScreenInfo getScreen(); diff --git a/wayland/java/WindowWayland.java b/wayland/java/WindowWayland.java index a8601472..59d94310 100644 --- a/wayland/java/WindowWayland.java +++ b/wayland/java/WindowWayland.java @@ -155,7 +155,7 @@ public Window minimize() { @Override public Window focus() { assert _onUIThread() : "Should be run on UI thread"; - // TODO implement + _nFocus(); return this; } @@ -242,4 +242,5 @@ public float getScale() { @ApiStatus.Internal public native float _nGetScale(); @ApiStatus.Internal public native void _nLockMouseCursor(boolean locked); @ApiStatus.Internal public native void _nHideMouseCursor(boolean hidden); + @ApiStatus.Internal public native void _nFocus(); } From 8f8842b605a44b829024a4461c487ecce4804570 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Mon, 8 Jan 2024 21:56:39 -0500 Subject: [PATCH 86/93] Add example code for focus Focus stealing isn't possible in most compositors, and sway uses focus stealing attempts as a way to mark urgency. Focus will simply activate itself (stealing focus) and notify on sway. --- examples/dashboard/java/Example.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/examples/dashboard/java/Example.java b/examples/dashboard/java/Example.java index 28150556..27613297 100644 --- a/examples/dashboard/java/Example.java +++ b/examples/dashboard/java/Example.java @@ -200,6 +200,18 @@ public void accept(Event e) { window.minimize(); case B -> setProgressBar(progressBars.next()); + case S -> { + var timer = new Timer(); + // delay to allow workspace/focus switching + timer.schedule(new TimerTask() { + public void run() { + App.runOnUIThread(() -> { + window.focus(); + timer.cancel(); + }); + } + }, 2000); + } } } } else if (e instanceof EventFrame) { From 27ed3079f24a7407ec24694af958a68f13b75413 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Tue, 9 Jan 2024 13:09:46 -0500 Subject: [PATCH 87/93] slim decorations --- wayland/cc/Decoration.cc | 32 +++++++++++++++++++------------- wayland/cc/Decoration.hh | 16 +++++++++------- wayland/cc/Pointer.cc | 16 +++++----------- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/wayland/cc/Decoration.cc b/wayland/cc/Decoration.cc index ebd7bcca..b9ae45a2 100644 --- a/wayland/cc/Decoration.cc +++ b/wayland/cc/Decoration.cc @@ -6,6 +6,7 @@ using namespace jwm; static unsigned int grey_data[] = {0xFF333333}; +static unsigned int zero_data[] = {0x00000000}; // no image editor // pure unadulterated programming static unsigned int close_data[] = { @@ -62,8 +63,7 @@ static void _xdgSurfaceConfigure(void* data, xdg_surface* surface, uint32_t seri int pendingHeight = self->_pendingHeight; // do it here bc we don't know configure order if (!self->_serverSide) { - pendingWidth -= DECORATION_WIDTH + DECORATION_WIDTH; - pendingHeight -= DECORATION_WIDTH + self->getTopSize(); + pendingHeight -= self->getTopSize(); } if (pendingWidth > 0) width = pendingWidth; @@ -275,14 +275,18 @@ void Decoration::_showDecorations(bool hidden) { // When destroyed these get released _decBuffer = Buffer::createShmBuffer(_wm.shm, 1, 1, WL_SHM_FORMAT_ARGB8888); memcpy(_decBuffer->getData(), grey_data, 1 * sizeof(uint32_t)); + _zeroBuffer = Buffer::createShmBuffer(_wm.shm, 1, 1, WL_SHM_FORMAT_ARGB8888); + memcpy(_zeroBuffer->getData(), zero_data, 1 * sizeof(uint32_t)); _closeBuffer = Buffer::createShmBuffer(_wm.shm, 9, 9, WL_SHM_FORMAT_ARGB8888); memcpy(_closeBuffer->getData(), close_data, 9 * 9 * sizeof(uint32_t)); _maxBuffer = Buffer::createShmBuffer(_wm.shm, 9, 9, WL_SHM_FORMAT_ARGB8888); memcpy(_maxBuffer->getData(), max_data, 9 * 9 * sizeof(uint32_t)); _minBuffer = Buffer::createShmBuffer(_wm.shm, 9, 9, WL_SHM_FORMAT_ARGB8888); memcpy(_minBuffer->getData(), min_data, 9 * 9 * sizeof(uint32_t)); - _makePart(&_border, _decBuffer, true, DECORATION_BORDER_X, DECORATION_BORDER_Y, - DECORATION_BORDER_WIDTH(_window), DECORATION_BORDER_HEIGHT(_window)); + int borderY = hidden ? DECORATION_BORDER_HIDDEN_Y : DECORATION_BORDER_Y; + int borderHeight = hidden ? DECORATION_BORDER_HEIGHT(_window) : DECORATION_BORDER_FULL_HEIGHT(_window); + _makePart(&_border, _zeroBuffer, false, DECORATION_BORDER_X, borderY, + DECORATION_BORDER_WIDTH(_window), borderHeight); wl_subsurface_place_below(_border.subsurface, _window._waylandWindow); if (!hidden) { _makePart(&_titleComp, _decBuffer, true, DECORATION_TITLE_X, DECORATION_TITLE_Y, @@ -296,8 +300,10 @@ void Decoration::_showDecorations(bool hidden) { } void Decoration::_adaptSize() { - _resizeDecoration(&_border, DECORATION_BORDER_X, DECORATION_BORDER_Y, - DECORATION_BORDER_WIDTH(_window), DECORATION_BORDER_HEIGHT(_window)); + int borderY = _isVisible ? DECORATION_BORDER_Y : DECORATION_BORDER_HIDDEN_Y; + int borderHeight = _isVisible ? DECORATION_BORDER_FULL_HEIGHT(_window) : DECORATION_BORDER_HEIGHT(_window); + _resizeDecoration(&_border, DECORATION_BORDER_X, borderY, + DECORATION_BORDER_WIDTH(_window), borderHeight); if (_isVisible) { _resizeDecoration(&_titleComp, DECORATION_TITLE_X, DECORATION_TITLE_Y, DECORATION_TITLE_WIDTH(_window), DECORATION_TITLE_HEIGHT); @@ -307,9 +313,9 @@ void Decoration::_adaptSize() { } if (!_serverSide) - xdg_surface_set_window_geometry(_xdgSurface, DECORATION_BORDER_X, _isVisible ? DECORATION_TITLE_Y : DECORATION_BORDER_Y, - DECORATION_BORDER_WIDTH(_window), - _isVisible ? DECORATION_BORDER_FULL_HEIGHT(_window) : DECORATION_BORDER_HEIGHT(_window)); + xdg_surface_set_window_geometry(_xdgSurface, 0, _isVisible ? DECORATION_TITLE_Y : 0, + _window.getUnscaledWidth(), + (_isVisible ? DECORATION_TITLE_HEIGHT : 0) + _window.getUnscaledHeight() ); else xdg_surface_set_window_geometry(_xdgSurface, 0, 0, _window.getUnscaledWidth(), _window.getUnscaledHeight()); } @@ -376,10 +382,10 @@ void Decoration::getBorders(int& left, int& top, int& right, int& bottom) { right = 0; bottom = 0; } else { - left = DECORATION_WIDTH; + left = 0; top = getTopSize(); - right = DECORATION_WIDTH; - bottom = DECORATION_WIDTH; + right = 0; + bottom = 0; } } @@ -389,5 +395,5 @@ int Decoration::getTopSize() { if (_isVisible) return DECORATION_TOP_HEIGHT; else - return DECORATION_WIDTH; + return 0; } diff --git a/wayland/cc/Decoration.hh b/wayland/cc/Decoration.hh index 7c18708b..ceec149d 100644 --- a/wayland/cc/Decoration.hh +++ b/wayland/cc/Decoration.hh @@ -9,17 +9,18 @@ #include #define DECORATION_WIDTH 4 -#define DECORATION_TOP_HEIGHT 30 +#define DECORATION_TOP_HEIGHT 25 #define DECORATION_BORDER_X -(DECORATION_WIDTH) -#define DECORATION_BORDER_Y -(DECORATION_WIDTH) +#define DECORATION_BORDER_HIDDEN_Y -(DECORATION_WIDTH) +#define DECORATION_BORDER_Y -(DECORATION_WIDTH + DECORATION_TOP_HEIGHT) #define DECORATION_BORDER_WIDTH(window) window.getUnscaledWidth() + DECORATION_WIDTH + DECORATION_WIDTH #define DECORATION_BORDER_HEIGHT(window) window.getUnscaledHeight() + DECORATION_WIDTH + DECORATION_WIDTH -#define DECORATION_BORDER_FULL_HEIGHT(window) window.getUnscaledHeight() + DECORATION_TOP_HEIGHT + DECORATION_WIDTH +#define DECORATION_BORDER_FULL_HEIGHT(window) window.getUnscaledHeight() + DECORATION_TOP_HEIGHT + DECORATION_WIDTH + DECORATION_WIDTH -#define DECORATION_TITLE_X -(DECORATION_WIDTH) +#define DECORATION_TITLE_X 0 #define DECORATION_TITLE_Y -(DECORATION_TOP_HEIGHT) -#define DECORATION_TITLE_WIDTH(window) window.getUnscaledWidth() + DECORATION_WIDTH + DECORATION_WIDTH +#define DECORATION_TITLE_WIDTH(window) window.getUnscaledWidth() #define DECORATION_TITLE_HEIGHT DECORATION_TOP_HEIGHT #define DECORATION_CLOSE_X(window) window.getUnscaledWidth() - 10 @@ -28,12 +29,12 @@ #define DECORATION_CLOSE_HEIGHT 9 #define DECORATION_MAX_X(window) (DECORATION_CLOSE_X(window)) - 10 -#define DECORATION_MAX_Y -20 +#define DECORATION_MAX_Y DECORATION_CLOSE_Y #define DECORATION_MAX_WIDTH 9 #define DECORATION_MAX_HEIGHT 9 #define DECORATION_MIN_X(window) (DECORATION_MAX_X(window)) - 10 -#define DECORATION_MIN_Y -20 +#define DECORATION_MIN_Y DECORATION_CLOSE_Y #define DECORATION_MIN_WIDTH 9 #define DECORATION_MIN_HEIGHT 9 @@ -65,6 +66,7 @@ namespace jwm { WindowWayland& _window; Buffer* _decBuffer; + Buffer* _zeroBuffer; Buffer* _closeBuffer; Buffer* _maxBuffer; Buffer* _minBuffer; diff --git a/wayland/cc/Pointer.cc b/wayland/cc/Pointer.cc index c428e33f..b131ef4d 100644 --- a/wayland/cc/Pointer.cc +++ b/wayland/cc/Pointer.cc @@ -53,6 +53,7 @@ static void pointerLeave(void* data, wl_pointer* pointer, uint32_t serial, } } static xdg_toplevel_resize_edge resizeEdge(DecorationFocus focus, WindowWayland& window, int x, int y, xkb_state* state) { + int topEdge = window._decoration->_isVisible ? DECORATION_TITLE_Y : 0; int rightEdge = window.getUnscaledWidth(); int bottomEdge = window.getUnscaledHeight(); switch (focus) { @@ -60,23 +61,14 @@ static xdg_toplevel_resize_edge resizeEdge(DecorationFocus focus, WindowWayland& // ??? return XDG_TOPLEVEL_RESIZE_EDGE_NONE; case DECORATION_FOCUS_TITLE: - if (x < 0) { - return XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; - } else if (x > rightEdge) { - return XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; - } else { - if (y < -DECORATION_TOP_HEIGHT / 2) - return XDG_TOPLEVEL_RESIZE_EDGE_TOP; - else - return XDG_TOPLEVEL_RESIZE_EDGE_NONE; - } + return XDG_TOPLEVEL_RESIZE_EDGE_NONE; case DECORATION_FOCUS_BORDER: if (state) { if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_EFFECTIVE)) { return XDG_TOPLEVEL_RESIZE_EDGE_NONE; } } - if (y < 0) { + if (y < topEdge) { if (x < 0) return XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; else if (x > rightEdge) @@ -128,6 +120,8 @@ static void pointerMotion(void* data, wl_pointer* pointer, uint32_t time, if (self->_decorationFocus == DECORATION_FOCUS_BORDER) { self->_absX = x - DECORATION_WIDTH; self->_absY = y - DECORATION_WIDTH; + if (self->_focusedSurface->_decoration->_isVisible) + self->_absY -= DECORATION_TOP_HEIGHT; } else if (self->_decorationFocus == DECORATION_FOCUS_TITLE) { self->_absX = x - DECORATION_WIDTH; self->_absY = y - DECORATION_TOP_HEIGHT; From ccd584fa76b966a96202c2366f3603c58afcbf01 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Tue, 9 Jan 2024 14:09:01 -0500 Subject: [PATCH 88/93] constrain size of window --- wayland/cc/Decoration.cc | 35 ++++++++++++++++++++++++++--------- wayland/cc/Decoration.hh | 5 +++++ 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/wayland/cc/Decoration.cc b/wayland/cc/Decoration.cc index b9ae45a2..328656e9 100644 --- a/wayland/cc/Decoration.cc +++ b/wayland/cc/Decoration.cc @@ -74,7 +74,8 @@ static void _xdgSurfaceConfigure(void* data, xdg_surface* surface, uint32_t seri height = pendingHeight; else height = window._floatingHeight; - + if (self->_floating) + self->constrainSize(width, height); self->_pendingWidth = 0; self->_pendingHeight = 0; if (self->_oldActive != self->_active) { @@ -100,6 +101,13 @@ static void _xdgSurfaceConfigure(void* data, xdg_surface* surface, uint32_t seri if (window._layer) window._layer->attachBuffer(); } + if (self->_serverSide) { + if (self->_border.surface) + self->_destroyDecorations(); + } else { + if (!self->_border.surface) + self->_showDecorations(!self->_isVisible); + } // resize on first configure self->_configured = true; // ask to configure _before_ commit. jank. @@ -118,13 +126,7 @@ static void _xdgSurfaceConfigure(void* data, xdg_surface* surface, uint32_t seri window._adaptSize(width, height); self->_adaptSize(); } - if (self->_serverSide) { - if (self->_border.surface) - self->_destroyDecorations(); - } else { - if (!self->_border.surface) - self->_showDecorations(!self->_isVisible); - } + wl_surface_commit(window._waylandWindow); if (!self->_floating) { @@ -287,7 +289,7 @@ void Decoration::_showDecorations(bool hidden) { int borderHeight = hidden ? DECORATION_BORDER_HEIGHT(_window) : DECORATION_BORDER_FULL_HEIGHT(_window); _makePart(&_border, _zeroBuffer, false, DECORATION_BORDER_X, borderY, DECORATION_BORDER_WIDTH(_window), borderHeight); - wl_subsurface_place_below(_border.subsurface, _window._waylandWindow); + wl_subsurface_place_below(_border.subsurface, _window._waylandWindow); if (!hidden) { _makePart(&_titleComp, _decBuffer, true, DECORATION_TITLE_X, DECORATION_TITLE_Y, DECORATION_TITLE_WIDTH(_window), DECORATION_TITLE_HEIGHT); @@ -397,3 +399,18 @@ int Decoration::getTopSize() { else return 0; } + +void Decoration::setMinSize(int width, int height) { + _minWidth = width; + _minHeight = height; +} + +void Decoration::constrainSize(int& width, int& height) { + if (width < _minWidth) + width = _minWidth; + // hard coded for buttons + if (width < 40) + width = 40; + if (height < _minHeight) + height = _minHeight; +} diff --git a/wayland/cc/Decoration.hh b/wayland/cc/Decoration.hh index ceec149d..f1d7729e 100644 --- a/wayland/cc/Decoration.hh +++ b/wayland/cc/Decoration.hh @@ -121,6 +121,11 @@ namespace jwm { int getTopSize(); + int _minWidth = 10; + int _minHeight = 10; + void setMinSize(int width, int height); + void constrainSize(int& width, int& height); + private: Decoration(Decoration&& other) = delete; From 1c2f4be5ff97b4d21691b9d95babe39dc6427be4 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Sun, 14 Jan 2024 16:52:27 -0500 Subject: [PATCH 89/93] Use var for protocols --- wayland/CMakeLists.txt | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/wayland/CMakeLists.txt b/wayland/CMakeLists.txt index c3685b6f..eef3c646 100644 --- a/wayland/CMakeLists.txt +++ b/wayland/CMakeLists.txt @@ -7,7 +7,7 @@ set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) include(FindWaylandProtocols) include(FindWaylandScanner) -find_package(WaylandProtocols 1.32) +find_package(WaylandProtocols 1.25) set_package_properties(WaylandProtocols PROPERTIES TYPE REQUIRED ) @@ -35,32 +35,31 @@ file(GLOB SOURCES_CXX ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/*.cc ${CMAKE_CURRENT_LIST_DIR}/cc/*.cc ) file(GLOB SOURCES_CXX_IMPL ${CMAKE_CURRENT_LIST_DIR}/../shared/cc/impl/*.cc) add_library(jwm SHARED ${SOURCES_OBJC} ${SOURCES_CXX} ${SOURCES_CXX_IMPL}) -add_library(protocols STATIC) -# set_property(TARGET cursorlock PROPERTY POSITION_INDEPENDENT_CODE ON) -ecm_add_wayland_client_protocol(protocols +ecm_add_wayland_client_protocol(PROTOCOLS_SOURCE PROTOCOL "${WaylandProtocols_DATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" BASENAME pointer-constraints-unstable-v1 ) -ecm_add_wayland_client_protocol(protocols +ecm_add_wayland_client_protocol(PROTOCOLS_SOURCE PROTOCOL "${WaylandProtocols_DATADIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml" BASENAME relative-pointer-unstable-v1 ) -ecm_add_wayland_client_protocol(protocols +ecm_add_wayland_client_protocol(PROTOCOLS_SOURCE PROTOCOL "${WaylandProtocols_DATADIR}/stable/xdg-shell/xdg-shell.xml" BASENAME xdg-shell ) -ecm_add_wayland_client_protocol(protocols +ecm_add_wayland_client_protocol(PROTOCOLS_SOURCE PROTOCOL "${WaylandProtocols_DATADIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml" BASENAME xdg-decoration-unstable-v1 ) -ecm_add_wayland_client_protocol(protocols +ecm_add_wayland_client_protocol(PROTOCOLS_SOURCE PROTOCOL "${WaylandProtocols_DATADIR}/stable/viewporter/viewporter.xml" BASENAME viewporter ) -ecm_add_wayland_client_protocol(protocols +ecm_add_wayland_client_protocol(PROTOCOLS_SOURCE PROTOCOL "${WaylandProtocols_DATADIR}/staging/xdg-activation/xdg-activation-v1.xml" BASENAME xdg-activation-v1 ) +add_library(protocols STATIC ${PROTOCOLS_SOURCE}) find_library(WAYLAND_CLIENT_LIB wayland-client) find_library(WAYLAND_CURSOR wayland-cursor) find_library(XKBCOMMON xkbcommon) From a7f078f5e372281f8c1d00a9b55d4b7f643cc565 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Sun, 14 Jan 2024 17:13:00 -0500 Subject: [PATCH 90/93] Omit functions that are high version --- wayland/cc/Decoration.cc | 8 -------- 1 file changed, 8 deletions(-) diff --git a/wayland/cc/Decoration.cc b/wayland/cc/Decoration.cc index 328656e9..856690ea 100644 --- a/wayland/cc/Decoration.cc +++ b/wayland/cc/Decoration.cc @@ -183,17 +183,9 @@ static void _xdgToplevelClose(void* data, xdg_toplevel* toplevel) { window.dispatch(classes::EventWindowCloseRequest::kInstance); } -static void _xdgToplevelConfigureBounds(void* data, xdg_toplevel* toplevel, int width, int height) { - // above version -} -static void _xdgToplevelWmCapabilities(void* data, xdg_toplevel* toplevel, wl_array* capabilities) { - // above version -} static xdg_toplevel_listener _xdgToplevelListener = { .configure = _xdgToplevelConfigure, .close = _xdgToplevelClose, - .configure_bounds = _xdgToplevelConfigureBounds, - .wm_capabilities = _xdgToplevelWmCapabilities }; const char* Decoration::proxyTag = "DecorationJWM"; From d407cbaf45e5284433f44582dc281dfc206f6570 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Tue, 16 Jan 2024 14:13:29 -0500 Subject: [PATCH 91/93] remove atoms --- wayland/cc/WindowWayland.hh | 2 -- 1 file changed, 2 deletions(-) diff --git a/wayland/cc/WindowWayland.hh b/wayland/cc/WindowWayland.hh index 753f6d64..6a5e0a5e 100644 --- a/wayland/cc/WindowWayland.hh +++ b/wayland/cc/WindowWayland.hh @@ -84,8 +84,6 @@ namespace jwm { int _oldScale = 1; int _height = -1; int _newHeight = -1; - int _WM_ADD = 1L; - int _WM_REMOVE = 0L; int _floatingWidth = 400; int _floatingHeight = 400; bool _canMinimize = false; From 030cd7d75e332df4526165765872bd7050b509a7 Mon Sep 17 00:00:00 2001 From: BulbyVR <26726264+TheDrawingCoder-Gamer@users.noreply.github.com> Date: Fri, 19 Jan 2024 12:46:33 -0500 Subject: [PATCH 92/93] fix crash on close under sway --- wayland/cc/Decoration.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/wayland/cc/Decoration.cc b/wayland/cc/Decoration.cc index 856690ea..9dd3affa 100644 --- a/wayland/cc/Decoration.cc +++ b/wayland/cc/Decoration.cc @@ -209,10 +209,16 @@ Decoration::Decoration(WindowWayland& window): void Decoration::close() { if (_border.surface) _destroyDecorations(); - if (_decoration) - zxdg_toplevel_decoration_v1_destroy(_decoration); + if (_decoration) { + // ??? + // zxdg_toplevel_decoration_v1_destroy(_decoration); + _decoration = nullptr; + } xdg_toplevel_destroy(_xdgToplevel); + _xdgToplevel = nullptr; xdg_surface_destroy(_xdgSurface); + _xdgSurface = nullptr; + } void Decoration::_makePart(DecorationPart* decoration, Buffer* buf, bool opaque, int x, int y, int width, int height) { From 9baac616a8ce512dbaed21da9424c60697858a5d Mon Sep 17 00:00:00 2001 From: TheDrawingCoding-Gamer Date: Fri, 19 Jan 2024 13:10:15 -0500 Subject: [PATCH 93/93] NVIDIA JUST WORKS:tm: Taken from Sodium's nvidia workaround. Disables optimizations for threading on Nvidia, thus preventing some weird crashes. --- wayland/cc/LayerGLWayland.cc | 12 ++++++++++++ wayland/cc/WindowManagerWayland.hh | 4 +++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/wayland/cc/LayerGLWayland.cc b/wayland/cc/LayerGLWayland.cc index ebe5a658..815fa6fd 100644 --- a/wayland/cc/LayerGLWayland.cc +++ b/wayland/cc/LayerGLWayland.cc @@ -10,6 +10,9 @@ #include #include #include "ILayerWayland.hh" +#include +#include +#include namespace jwm { @@ -32,6 +35,7 @@ namespace jwm { fprintf(stderr, "already closed\n"); throw std::runtime_error("Already closed"); } + fWindow = jwm::ref(window); fWindow->setLayer(this); if (fWindow->_windowManager._eglDisplay == EGL_NO_DISPLAY) { @@ -39,11 +43,19 @@ namespace jwm { eglInitialize(fWindow->_windowManager._eglDisplay, nullptr, nullptr); + fWindow->_windowManager.vendor = eglQueryString(_display, EGL_VENDOR); + + if (fWindow->_windowManager.vendor != nullptr && (strcmp(fWindow->_windowManager.vendor, "NVIDIA") == 0)) { + // Thankfully observed from minecraft's sodium + // https://github.com/CaffeineMC/sodium-fabric/blob/dev/src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaWorkarounds.java#L29 + setenv("__GL_THREADED_OPTIMIZATIONS", "0", true); + } } _display = fWindow->_windowManager._eglDisplay; if ( eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) { throw new std::runtime_error("Cannot bind EGL Api"); } + if (_context == nullptr) { EGLint attrList[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, diff --git a/wayland/cc/WindowManagerWayland.hh b/wayland/cc/WindowManagerWayland.hh index f0c536a7..d9c2bb08 100644 --- a/wayland/cc/WindowManagerWayland.hh +++ b/wayland/cc/WindowManagerWayland.hh @@ -16,7 +16,8 @@ #include "Output.hh" #include #include -#include +#include +#include #include "Keyboard.hh" #include "Pointer.hh" #include @@ -115,6 +116,7 @@ namespace jwm { std::map _myClipboardContents; std::map _myClipboardSource; std::list _currentMimeTypes; + const char* vendor = nullptr; wl_surface* getCursorSurface() const { if (_pointer)