GHOST: initial Wayland support
Usable with the CMake option 'WITH_GHOST_WAYLAND' The following functionality is working: - Building with X11 and Wayland at the same time, wayland is used when available. - Keyboard, pointer handling. - Cursor handling. - Dedicated off-screen windows. - Drag & drop. - Copy & paste. - Pointer grabbing. See D6567 for further details.
This commit is contained in:

committed by
Campbell Barton

parent
00e0034b13
commit
66e70fe299
@@ -207,6 +207,10 @@ mark_as_advanced(WITH_GHOST_DEBUG)
|
||||
option(WITH_GHOST_SDL "Enable building Blender against SDL for windowing rather than the native APIs" OFF)
|
||||
mark_as_advanced(WITH_GHOST_SDL)
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
option(WITH_GHOST_WAYLAND "Enable building Blender against Wayland for windowing" OFF)
|
||||
endif()
|
||||
|
||||
if(WITH_X11)
|
||||
option(WITH_GHOST_XDND "Enable drag'n'drop support on X11 using XDND protocol" ON)
|
||||
endif()
|
||||
|
@@ -440,6 +440,14 @@ function(SETUP_LIBDIRS)
|
||||
link_directories(${HDF5_LIBPATH})
|
||||
endif()
|
||||
|
||||
if(WITH_GHOST_WAYLAND)
|
||||
link_directories(
|
||||
${wayland-client_LIBRARY_DIRS}
|
||||
${wayland-egl_LIBRARY_DIRS}
|
||||
${xkbcommon_LIBRARY_DIRS}
|
||||
${wayland-cursor_LIBRARY_DIRS})
|
||||
endif()
|
||||
|
||||
if(WIN32 AND NOT UNIX)
|
||||
link_directories(${PTHREADS_LIBPATH})
|
||||
endif()
|
||||
|
@@ -504,6 +504,26 @@ if(WITH_SYSTEM_AUDASPACE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_GHOST_WAYLAND)
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(wayland-client REQUIRED wayland-client>=1.12)
|
||||
pkg_check_modules(wayland-egl REQUIRED wayland-egl)
|
||||
pkg_check_modules(wayland-scanner REQUIRED wayland-scanner)
|
||||
pkg_check_modules(xkbcommon REQUIRED xkbcommon)
|
||||
pkg_check_modules(wayland-cursor REQUIRED wayland-cursor)
|
||||
|
||||
set(WITH_GL_EGL ON)
|
||||
|
||||
if(WITH_GHOST_WAYLAND)
|
||||
list(APPEND PLATFORM_LINKLIBS
|
||||
${wayland-client_LIBRARIES}
|
||||
${wayland-egl_LIBRARIES}
|
||||
${xkbcommon_LIBRARIES}
|
||||
${wayland-cursor_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_X11)
|
||||
find_package(X11 REQUIRED)
|
||||
|
||||
|
@@ -177,73 +177,141 @@ elseif(APPLE AND NOT WITH_X11)
|
||||
)
|
||||
endif()
|
||||
|
||||
elseif(WITH_X11)
|
||||
list(APPEND INC_SYS
|
||||
${X11_X11_INCLUDE_PATH}
|
||||
)
|
||||
|
||||
list(APPEND SRC
|
||||
intern/GHOST_DisplayManagerX11.cpp
|
||||
intern/GHOST_SystemX11.cpp
|
||||
intern/GHOST_TaskbarX11.cpp
|
||||
intern/GHOST_WindowX11.cpp
|
||||
|
||||
intern/GHOST_DisplayManagerX11.h
|
||||
intern/GHOST_IconX11.h
|
||||
intern/GHOST_SystemX11.h
|
||||
intern/GHOST_TaskbarX11.h
|
||||
intern/GHOST_WindowX11.h
|
||||
)
|
||||
|
||||
if(NOT WITH_GL_EGL)
|
||||
list(APPEND SRC
|
||||
intern/GHOST_ContextGLX.cpp
|
||||
|
||||
intern/GHOST_ContextGLX.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_GHOST_XDND)
|
||||
add_definitions(-DWITH_XDND)
|
||||
|
||||
list(APPEND LIB
|
||||
extern_xdnd
|
||||
)
|
||||
|
||||
list(APPEND INC
|
||||
../../extern/xdnd
|
||||
elseif(WITH_X11 OR WITH_GHOST_WAYLAND)
|
||||
if(WITH_X11)
|
||||
list(APPEND INC_SYS
|
||||
${X11_X11_INCLUDE_PATH}
|
||||
)
|
||||
|
||||
list(APPEND SRC
|
||||
intern/GHOST_DropTargetX11.cpp
|
||||
intern/GHOST_DisplayManagerX11.cpp
|
||||
intern/GHOST_SystemX11.cpp
|
||||
intern/GHOST_TaskbarX11.cpp
|
||||
intern/GHOST_WindowX11.cpp
|
||||
|
||||
intern/GHOST_DropTargetX11.h
|
||||
intern/GHOST_DisplayManagerX11.h
|
||||
intern/GHOST_IconX11.h
|
||||
intern/GHOST_SystemX11.h
|
||||
intern/GHOST_TaskbarX11.h
|
||||
intern/GHOST_WindowX11.h
|
||||
)
|
||||
|
||||
if(NOT WITH_GL_EGL)
|
||||
list(APPEND SRC
|
||||
intern/GHOST_ContextGLX.cpp
|
||||
|
||||
intern/GHOST_ContextGLX.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_GHOST_XDND)
|
||||
add_definitions(-DWITH_XDND)
|
||||
|
||||
list(APPEND LIB
|
||||
extern_xdnd
|
||||
)
|
||||
|
||||
list(APPEND INC
|
||||
../../extern/xdnd
|
||||
)
|
||||
|
||||
list(APPEND SRC
|
||||
intern/GHOST_DropTargetX11.cpp
|
||||
|
||||
intern/GHOST_DropTargetX11.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if(X11_XF86keysym_INCLUDE_PATH)
|
||||
add_definitions(-DWITH_XF86KEYSYM)
|
||||
list(APPEND INC_SYS
|
||||
${X11_XF86keysym_INCLUDE_PATH}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_X11_XF86VMODE)
|
||||
add_definitions(-DWITH_X11_XF86VMODE)
|
||||
list(APPEND INC_SYS
|
||||
${X11_xf86vmode_INCLUDE_PATH}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_X11_XFIXES)
|
||||
add_definitions(-DWITH_X11_XFIXES)
|
||||
list(APPEND INC_SYS
|
||||
${X11_Xfixes_INCLUDE_PATH}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_X11_ALPHA)
|
||||
add_definitions(-DWITH_X11_ALPHA)
|
||||
endif()
|
||||
|
||||
if(WITH_X11_XINPUT)
|
||||
add_definitions(-DWITH_X11_XINPUT)
|
||||
list(APPEND INC_SYS
|
||||
${X11_Xinput_INCLUDE_PATH}
|
||||
)
|
||||
endif()
|
||||
|
||||
add_definitions(-DWITH_X11)
|
||||
endif()
|
||||
|
||||
if(X11_XF86keysym_INCLUDE_PATH)
|
||||
add_definitions(-DWITH_XF86KEYSYM)
|
||||
if(WITH_GHOST_WAYLAND)
|
||||
list(APPEND INC_SYS
|
||||
${X11_XF86keysym_INCLUDE_PATH}
|
||||
${wayland-client_INCLUDE_DIRS}
|
||||
${wayland-egl_INCLUDE_DIRS}
|
||||
${xkbcommon_INCLUDE_DIRS}
|
||||
${wayland-cursor_INCLUDE_DIRS}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_X11_XF86VMODE)
|
||||
add_definitions(-DWITH_X11_XF86VMODE)
|
||||
list(APPEND INC_SYS
|
||||
${X11_xf86vmode_INCLUDE_PATH}
|
||||
list(APPEND SRC
|
||||
intern/GHOST_SystemWayland.cpp
|
||||
intern/GHOST_WindowWayland.cpp
|
||||
|
||||
intern/GHOST_SystemWayland.h
|
||||
intern/GHOST_WindowWayland.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_X11_XFIXES)
|
||||
add_definitions(-DWITH_X11_XFIXES)
|
||||
list(APPEND INC_SYS
|
||||
${X11_Xfixes_INCLUDE_PATH}
|
||||
pkg_get_variable(WAYLAND_SCANNER wayland-scanner wayland_scanner)
|
||||
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
|
||||
|
||||
# Generate protocols bindings.
|
||||
macro(generate_protocol_bindings NAME PROT_DEF)
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${NAME}-client-protocol.h
|
||||
COMMAND ${WAYLAND_SCANNER} client-header ${PROT_DEF} ${NAME}-client-protocol.h
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${NAME}-client-protocol.c
|
||||
COMMAND ${WAYLAND_SCANNER} private-code ${PROT_DEF} ${NAME}-client-protocol.c
|
||||
DEPENDS ${NAME}-client-protocol.h
|
||||
)
|
||||
list(APPEND SRC
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${NAME}-client-protocol.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${NAME}-client-protocol.h
|
||||
)
|
||||
endmacro()
|
||||
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# xdg-shell.
|
||||
generate_protocol_bindings(
|
||||
xdg-shell
|
||||
"${WAYLAND_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml"
|
||||
)
|
||||
# Pointer-constraints.
|
||||
generate_protocol_bindings(
|
||||
pointer-constraints
|
||||
"${WAYLAND_PROTOCOLS_DIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml"
|
||||
)
|
||||
# Relative-pointer.
|
||||
generate_protocol_bindings(
|
||||
relative-pointer
|
||||
"${WAYLAND_PROTOCOLS_DIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_X11_ALPHA)
|
||||
add_definitions(-DWITH_X11_ALPHA)
|
||||
add_definitions(-DWITH_GHOST_WAYLAND)
|
||||
endif()
|
||||
|
||||
if(WITH_INPUT_NDOF)
|
||||
|
@@ -27,8 +27,13 @@
|
||||
|
||||
#include "GHOST_ISystem.h"
|
||||
|
||||
#ifdef WITH_X11
|
||||
# include "GHOST_SystemX11.h"
|
||||
#if defined(WITH_X11) || defined(WITH_GHOST_WAYLAND)
|
||||
# ifdef WITH_X11
|
||||
# include "GHOST_SystemX11.h"
|
||||
# endif
|
||||
# ifdef WITH_GHOST_WAYLAND
|
||||
# include "GHOST_SystemWayland.h"
|
||||
# endif
|
||||
#else
|
||||
# ifdef WITH_HEADLESS
|
||||
# include "GHOST_SystemNULL.h"
|
||||
@@ -49,8 +54,19 @@ GHOST_TSuccess GHOST_ISystem::createSystem()
|
||||
{
|
||||
GHOST_TSuccess success;
|
||||
if (!m_system) {
|
||||
#ifdef WITH_X11
|
||||
m_system = new GHOST_SystemX11();
|
||||
#if defined(WITH_X11) || defined(WITH_GHOST_WAYLAND)
|
||||
# ifdef WITH_GHOST_WAYLAND
|
||||
try {
|
||||
m_system = new GHOST_SystemWayland();
|
||||
}
|
||||
catch (const std::exception &) {
|
||||
}
|
||||
# endif
|
||||
# ifdef WITH_X11
|
||||
if (!m_system) {
|
||||
m_system = new GHOST_SystemX11();
|
||||
}
|
||||
# endif
|
||||
#else
|
||||
# ifdef WITH_HEADLESS
|
||||
m_system = new GHOST_SystemNULL();
|
||||
|
1648
intern/ghost/intern/GHOST_SystemWayland.cpp
Normal file
1648
intern/ghost/intern/GHOST_SystemWayland.cpp
Normal file
File diff suppressed because it is too large
Load Diff
111
intern/ghost/intern/GHOST_SystemWayland.h
Normal file
111
intern/ghost/intern/GHOST_SystemWayland.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
* Declaration of GHOST_SystemWayland class.
|
||||
*/
|
||||
|
||||
#ifndef __GHOST_SYSTEMWAYLAND_H__
|
||||
#define __GHOST_SYSTEMWAYLAND_H__
|
||||
|
||||
#include "../GHOST_Types.h"
|
||||
#include "GHOST_System.h"
|
||||
#include "GHOST_WindowWayland.h"
|
||||
|
||||
#include <wayland-client.h>
|
||||
#include <xdg-shell-client-protocol.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
class GHOST_WindowWayland;
|
||||
|
||||
struct display_t;
|
||||
|
||||
class GHOST_SystemWayland : public GHOST_System {
|
||||
public:
|
||||
GHOST_SystemWayland();
|
||||
|
||||
~GHOST_SystemWayland() override;
|
||||
|
||||
bool processEvents(bool waitForEvent) override;
|
||||
|
||||
int toggleConsole(int action) override;
|
||||
|
||||
GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const override;
|
||||
|
||||
GHOST_TSuccess getButtons(GHOST_Buttons &buttons) const override;
|
||||
|
||||
GHOST_TUns8 *getClipboard(bool selection) const override;
|
||||
|
||||
void putClipboard(GHOST_TInt8 *buffer, bool selection) const override;
|
||||
|
||||
GHOST_TUns8 getNumDisplays() const override;
|
||||
|
||||
GHOST_TSuccess getCursorPosition(GHOST_TInt32 &x, GHOST_TInt32 &y) const override;
|
||||
|
||||
GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) override;
|
||||
|
||||
void getMainDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const override;
|
||||
|
||||
void getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const override;
|
||||
|
||||
GHOST_IContext *createOffscreenContext() override;
|
||||
|
||||
GHOST_TSuccess disposeContext(GHOST_IContext *context) override;
|
||||
|
||||
GHOST_IWindow *createWindow(const char *title,
|
||||
GHOST_TInt32 left,
|
||||
GHOST_TInt32 top,
|
||||
GHOST_TUns32 width,
|
||||
GHOST_TUns32 height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_TDrawingContextType type,
|
||||
GHOST_GLSettings glSettings,
|
||||
const bool exclusive,
|
||||
const bool is_dialog,
|
||||
const GHOST_IWindow *parentWindow) override;
|
||||
|
||||
wl_display *display();
|
||||
|
||||
wl_compositor *compositor();
|
||||
|
||||
xdg_wm_base *shell();
|
||||
|
||||
void setSelection(const std::string &selection);
|
||||
|
||||
GHOST_TSuccess setCursorShape(GHOST_TStandardCursor shape);
|
||||
|
||||
GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor cursorShape);
|
||||
|
||||
GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 *bitmap,
|
||||
GHOST_TUns8 *mask,
|
||||
int sizex,
|
||||
int sizey,
|
||||
int hotX,
|
||||
int hotY,
|
||||
bool canInvertColor);
|
||||
|
||||
GHOST_TSuccess setCursorVisibility(bool visible);
|
||||
|
||||
GHOST_TSuccess setCursorGrab(const GHOST_TGrabCursorMode mode, wl_surface *surface);
|
||||
|
||||
private:
|
||||
struct display_t *d;
|
||||
std::string selection;
|
||||
};
|
||||
|
||||
#endif /* __GHOST_SYSTEMWAYLAND_H__ */
|
404
intern/ghost/intern/GHOST_WindowWayland.cpp
Normal file
404
intern/ghost/intern/GHOST_WindowWayland.cpp
Normal file
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
#include "GHOST_WindowWayland.h"
|
||||
#include "GHOST_SystemWayland.h"
|
||||
#include "GHOST_WindowManager.h"
|
||||
|
||||
#include "GHOST_Event.h"
|
||||
|
||||
#include "GHOST_ContextEGL.h"
|
||||
#include "GHOST_ContextNone.h"
|
||||
|
||||
#include <wayland-egl.h>
|
||||
|
||||
struct window_t {
|
||||
GHOST_WindowWayland *w;
|
||||
wl_surface *surface;
|
||||
struct xdg_surface *xdg_surface;
|
||||
struct xdg_toplevel *xdg_toplevel;
|
||||
wl_egl_window *egl_window;
|
||||
int32_t pending_width, pending_height;
|
||||
bool is_maximised;
|
||||
bool is_fullscreen;
|
||||
bool is_active;
|
||||
int32_t width, height;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Wayland Interface Callbacks
|
||||
*
|
||||
* These callbacks are registered for Wayland interfaces and called when
|
||||
* an event is received from the compositor.
|
||||
* \{ */
|
||||
|
||||
static void toplevel_configure(
|
||||
void *data, xdg_toplevel * /*xdg_toplevel*/, int32_t width, int32_t height, wl_array *states)
|
||||
{
|
||||
window_t *win = static_cast<window_t *>(data);
|
||||
win->pending_width = width;
|
||||
win->pending_height = height;
|
||||
|
||||
win->is_maximised = false;
|
||||
win->is_fullscreen = false;
|
||||
win->is_active = false;
|
||||
|
||||
/* Note that the macro 'wl_array_for_each' would typically be used to simplify this logic,
|
||||
* however it's not compatible with C++, so perform casts instead.
|
||||
* If this needs to be done more often we could define our own C++ compatible macro. */
|
||||
for (enum xdg_toplevel_state *state = static_cast<xdg_toplevel_state *>(states->data);
|
||||
reinterpret_cast<uint8_t *>(state) < (static_cast<uint8_t *>(states->data) + states->size);
|
||||
state++) {
|
||||
switch (*state) {
|
||||
case XDG_TOPLEVEL_STATE_MAXIMIZED:
|
||||
win->is_maximised = true;
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_FULLSCREEN:
|
||||
win->is_fullscreen = true;
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_ACTIVATED:
|
||||
win->is_active = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void toplevel_close(void *data, xdg_toplevel * /*xdg_toplevel*/)
|
||||
{
|
||||
static_cast<window_t *>(data)->w->close();
|
||||
}
|
||||
|
||||
static const xdg_toplevel_listener toplevel_listener = {
|
||||
toplevel_configure,
|
||||
toplevel_close,
|
||||
};
|
||||
|
||||
static void surface_configure(void *data, xdg_surface *xdg_surface, uint32_t serial)
|
||||
{
|
||||
window_t *win = static_cast<window_t *>(data);
|
||||
|
||||
int w, h;
|
||||
wl_egl_window_get_attached_size(win->egl_window, &w, &h);
|
||||
if (win->pending_width != 0 && win->pending_height != 0 && win->pending_width != w &&
|
||||
win->pending_height != h) {
|
||||
win->width = win->pending_width;
|
||||
win->height = win->pending_height;
|
||||
wl_egl_window_resize(win->egl_window, win->pending_width, win->pending_height, 0, 0);
|
||||
win->pending_width = 0;
|
||||
win->pending_height = 0;
|
||||
win->w->notify_size();
|
||||
}
|
||||
|
||||
if (win->is_active) {
|
||||
win->w->activate();
|
||||
}
|
||||
else {
|
||||
win->w->deactivate();
|
||||
}
|
||||
|
||||
xdg_surface_ack_configure(xdg_surface, serial);
|
||||
}
|
||||
|
||||
static const xdg_surface_listener surface_listener = {
|
||||
surface_configure,
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Ghost Implementation
|
||||
*
|
||||
* Wayland specific implementation of the GHOST_Window interface.
|
||||
* \{ */
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWayland::hasCursorShape(GHOST_TStandardCursor cursorShape)
|
||||
{
|
||||
return m_system->hasCursorShape(cursorShape);
|
||||
}
|
||||
|
||||
GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
|
||||
const char *title,
|
||||
GHOST_TInt32 /*left*/,
|
||||
GHOST_TInt32 /*top*/,
|
||||
GHOST_TUns32 width,
|
||||
GHOST_TUns32 height,
|
||||
GHOST_TWindowState state,
|
||||
const GHOST_IWindow *parentWindow,
|
||||
GHOST_TDrawingContextType type,
|
||||
const bool stereoVisual,
|
||||
const bool exclusive)
|
||||
: GHOST_Window(width, height, state, stereoVisual, exclusive),
|
||||
m_system(system),
|
||||
w(new window_t)
|
||||
{
|
||||
w->w = this;
|
||||
|
||||
w->width = int32_t(width);
|
||||
w->height = int32_t(height);
|
||||
|
||||
/* Window surfaces. */
|
||||
w->surface = wl_compositor_create_surface(m_system->compositor());
|
||||
w->egl_window = wl_egl_window_create(w->surface, int(width), int(height));
|
||||
|
||||
w->xdg_surface = xdg_wm_base_get_xdg_surface(m_system->shell(), w->surface);
|
||||
w->xdg_toplevel = xdg_surface_get_toplevel(w->xdg_surface);
|
||||
|
||||
wl_surface_set_user_data(w->surface, this);
|
||||
|
||||
xdg_surface_add_listener(w->xdg_surface, &surface_listener, w);
|
||||
xdg_toplevel_add_listener(w->xdg_toplevel, &toplevel_listener, w);
|
||||
|
||||
if (parentWindow) {
|
||||
xdg_toplevel_set_parent(
|
||||
w->xdg_toplevel, dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->xdg_toplevel);
|
||||
}
|
||||
|
||||
/* Call top-level callbacks. */
|
||||
wl_surface_commit(w->surface);
|
||||
wl_display_roundtrip(m_system->display());
|
||||
|
||||
setTitle(title);
|
||||
|
||||
/* EGL context. */
|
||||
if (setDrawingContextType(type) == GHOST_kFailure) {
|
||||
GHOST_PRINT("Failed to create EGL context" << std::endl);
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWayland::close()
|
||||
{
|
||||
return m_system->pushEvent(
|
||||
new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowClose, this));
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWayland::activate()
|
||||
{
|
||||
if (m_system->getWindowManager()->setActiveWindow(this) == GHOST_kFailure) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
return m_system->pushEvent(
|
||||
new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowActivate, this));
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWayland::deactivate()
|
||||
{
|
||||
m_system->getWindowManager()->setWindowInactive(this);
|
||||
return m_system->pushEvent(
|
||||
new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowDeactivate, this));
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWayland::notify_size()
|
||||
{
|
||||
return m_system->pushEvent(
|
||||
new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowSize, this));
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWayland::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
|
||||
{
|
||||
return m_system->setCursorGrab(mode, w->surface);
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWayland::setWindowCursorShape(GHOST_TStandardCursor shape)
|
||||
{
|
||||
const GHOST_TSuccess ok = m_system->setCursorShape(shape);
|
||||
m_cursorShape = (ok == GHOST_kSuccess) ? shape : GHOST_kStandardCursorDefault;
|
||||
return ok;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWayland::setWindowCustomCursorShape(GHOST_TUns8 *bitmap,
|
||||
GHOST_TUns8 *mask,
|
||||
int sizex,
|
||||
int sizey,
|
||||
int hotX,
|
||||
int hotY,
|
||||
bool canInvertColor)
|
||||
{
|
||||
return m_system->setCustomCursorShape(bitmap, mask, sizex, sizey, hotX, hotY, canInvertColor);
|
||||
}
|
||||
|
||||
void GHOST_WindowWayland::setTitle(const char *title)
|
||||
{
|
||||
xdg_toplevel_set_title(w->xdg_toplevel, title);
|
||||
xdg_toplevel_set_app_id(w->xdg_toplevel, title);
|
||||
this->title = title;
|
||||
}
|
||||
|
||||
std::string GHOST_WindowWayland::getTitle() const
|
||||
{
|
||||
return this->title.empty() ? "untitled" : this->title;
|
||||
}
|
||||
|
||||
void GHOST_WindowWayland::getWindowBounds(GHOST_Rect &bounds) const
|
||||
{
|
||||
getClientBounds(bounds);
|
||||
}
|
||||
|
||||
void GHOST_WindowWayland::getClientBounds(GHOST_Rect &bounds) const
|
||||
{
|
||||
bounds.set(0, 0, w->width, w->height);
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWayland::setClientWidth(GHOST_TUns32 width)
|
||||
{
|
||||
return setClientSize(width, GHOST_TUns32(w->height));
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWayland::setClientHeight(GHOST_TUns32 height)
|
||||
{
|
||||
return setClientSize(GHOST_TUns32(w->width), height);
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWayland::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height)
|
||||
{
|
||||
wl_egl_window_resize(w->egl_window, int(width), int(height), 0, 0);
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
void GHOST_WindowWayland::screenToClient(GHOST_TInt32 inX,
|
||||
GHOST_TInt32 inY,
|
||||
GHOST_TInt32 &outX,
|
||||
GHOST_TInt32 &outY) const
|
||||
{
|
||||
outX = inX;
|
||||
outY = inY;
|
||||
}
|
||||
|
||||
void GHOST_WindowWayland::clientToScreen(GHOST_TInt32 inX,
|
||||
GHOST_TInt32 inY,
|
||||
GHOST_TInt32 &outX,
|
||||
GHOST_TInt32 &outY) const
|
||||
{
|
||||
outX = inX;
|
||||
outY = inY;
|
||||
}
|
||||
|
||||
GHOST_WindowWayland::~GHOST_WindowWayland()
|
||||
{
|
||||
releaseNativeHandles();
|
||||
|
||||
wl_egl_window_destroy(w->egl_window);
|
||||
xdg_toplevel_destroy(w->xdg_toplevel);
|
||||
xdg_surface_destroy(w->xdg_surface);
|
||||
wl_surface_destroy(w->surface);
|
||||
|
||||
delete w;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWayland::setWindowCursorVisibility(bool visible)
|
||||
{
|
||||
return m_system->setCursorVisibility(visible);
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWayland::setState(GHOST_TWindowState state)
|
||||
{
|
||||
switch (state) {
|
||||
case GHOST_kWindowStateNormal:
|
||||
/* Unset states. */
|
||||
switch (getState()) {
|
||||
case GHOST_kWindowStateMaximized:
|
||||
xdg_toplevel_unset_maximized(w->xdg_toplevel);
|
||||
break;
|
||||
case GHOST_kWindowStateFullScreen:
|
||||
xdg_toplevel_unset_fullscreen(w->xdg_toplevel);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GHOST_kWindowStateMaximized:
|
||||
xdg_toplevel_set_maximized(w->xdg_toplevel);
|
||||
break;
|
||||
case GHOST_kWindowStateMinimized:
|
||||
xdg_toplevel_set_minimized(w->xdg_toplevel);
|
||||
break;
|
||||
case GHOST_kWindowStateFullScreen:
|
||||
xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr);
|
||||
break;
|
||||
case GHOST_kWindowStateEmbedded:
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TWindowState GHOST_WindowWayland::getState() const
|
||||
{
|
||||
if (w->is_fullscreen) {
|
||||
return GHOST_kWindowStateFullScreen;
|
||||
}
|
||||
else if (w->is_maximised) {
|
||||
return GHOST_kWindowStateMaximized;
|
||||
}
|
||||
else {
|
||||
return GHOST_kWindowStateNormal;
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWayland::invalidate()
|
||||
{
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWayland::setOrder(GHOST_TWindowOrder /*order*/)
|
||||
{
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWayland::beginFullScreen() const
|
||||
{
|
||||
xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr);
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWayland::endFullScreen() const
|
||||
{
|
||||
xdg_toplevel_unset_fullscreen(w->xdg_toplevel);
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param type The type of rendering context create.
|
||||
* \return Indication of success.
|
||||
*/
|
||||
GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType type)
|
||||
{
|
||||
GHOST_Context *context;
|
||||
switch (type) {
|
||||
case GHOST_kDrawingContextTypeNone:
|
||||
context = new GHOST_ContextNone(m_wantStereoVisual);
|
||||
break;
|
||||
case GHOST_kDrawingContextTypeOpenGL:
|
||||
context = new GHOST_ContextEGL(m_wantStereoVisual,
|
||||
EGLNativeWindowType(w->egl_window),
|
||||
EGLNativeDisplayType(m_system->display()),
|
||||
EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
|
||||
3,
|
||||
3,
|
||||
GHOST_OPENGL_EGL_CONTEXT_FLAGS,
|
||||
GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
|
||||
EGL_OPENGL_API);
|
||||
break;
|
||||
}
|
||||
|
||||
return (context->initializeDrawingContext() == GHOST_kSuccess) ? context : nullptr;
|
||||
}
|
||||
|
||||
/** \} */
|
121
intern/ghost/intern/GHOST_WindowWayland.h
Normal file
121
intern/ghost/intern/GHOST_WindowWayland.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*
|
||||
* Declaration of GHOST_WindowWayland class.
|
||||
*/
|
||||
|
||||
#ifndef __GHOST_WINDOWWAYLAND_H__
|
||||
#define __GHOST_WINDOWWAYLAND_H__
|
||||
|
||||
#include "GHOST_Window.h"
|
||||
|
||||
class GHOST_SystemWayland;
|
||||
|
||||
struct window_t;
|
||||
|
||||
class GHOST_WindowWayland : public GHOST_Window {
|
||||
public:
|
||||
GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor cursorShape) override;
|
||||
|
||||
GHOST_WindowWayland(GHOST_SystemWayland *system,
|
||||
const char *title,
|
||||
GHOST_TInt32 left,
|
||||
GHOST_TInt32 top,
|
||||
GHOST_TUns32 width,
|
||||
GHOST_TUns32 height,
|
||||
GHOST_TWindowState state,
|
||||
const GHOST_IWindow *parentWindow,
|
||||
GHOST_TDrawingContextType type,
|
||||
const bool stereoVisual,
|
||||
const bool exclusive);
|
||||
|
||||
~GHOST_WindowWayland() override;
|
||||
|
||||
GHOST_TSuccess close();
|
||||
|
||||
GHOST_TSuccess activate();
|
||||
|
||||
GHOST_TSuccess deactivate();
|
||||
|
||||
GHOST_TSuccess notify_size();
|
||||
|
||||
protected:
|
||||
GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode) override;
|
||||
|
||||
GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape) override;
|
||||
|
||||
GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap,
|
||||
GHOST_TUns8 *mask,
|
||||
int sizex,
|
||||
int sizey,
|
||||
int hotX,
|
||||
int hotY,
|
||||
bool canInvertColor) override;
|
||||
|
||||
void setTitle(const char *title) override;
|
||||
|
||||
std::string getTitle() const override;
|
||||
|
||||
void getWindowBounds(GHOST_Rect &bounds) const override;
|
||||
|
||||
void getClientBounds(GHOST_Rect &bounds) const override;
|
||||
|
||||
GHOST_TSuccess setClientWidth(GHOST_TUns32 width) override;
|
||||
|
||||
GHOST_TSuccess setClientHeight(GHOST_TUns32 height) override;
|
||||
|
||||
GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) override;
|
||||
|
||||
void screenToClient(GHOST_TInt32 inX,
|
||||
GHOST_TInt32 inY,
|
||||
GHOST_TInt32 &outX,
|
||||
GHOST_TInt32 &outY) const override;
|
||||
|
||||
void clientToScreen(GHOST_TInt32 inX,
|
||||
GHOST_TInt32 inY,
|
||||
GHOST_TInt32 &outX,
|
||||
GHOST_TInt32 &outY) const override;
|
||||
|
||||
GHOST_TSuccess setWindowCursorVisibility(bool visible) override;
|
||||
|
||||
GHOST_TSuccess setState(GHOST_TWindowState state) override;
|
||||
|
||||
GHOST_TWindowState getState() const override;
|
||||
|
||||
GHOST_TSuccess invalidate() override;
|
||||
|
||||
GHOST_TSuccess setOrder(GHOST_TWindowOrder order) override;
|
||||
|
||||
GHOST_TSuccess beginFullScreen() const override;
|
||||
|
||||
GHOST_TSuccess endFullScreen() const override;
|
||||
|
||||
private:
|
||||
GHOST_SystemWayland *m_system;
|
||||
struct window_t *w;
|
||||
std::string title;
|
||||
|
||||
/**
|
||||
* \param type The type of rendering context create.
|
||||
* \return Indication of success.
|
||||
*/
|
||||
GHOST_Context *newDrawingContext(GHOST_TDrawingContextType type) override;
|
||||
};
|
||||
|
||||
#endif // __GHOST_WINDOWWAYLAND_H__
|
Reference in New Issue
Block a user