Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions

92
third_party/FreeRDP/uwac/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,92 @@
# UWAC: Using Wayland As Client
# cmake build script
#
# Copyright 2015 David FORT <contact@hardening-consulting.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Soname versioning
set(UWAC_VERSION_MAJOR "0")
set(UWAC_VERSION_MINOR "2")
set(UWAC_VERSION_REVISION "0")
set(UWAC_VERSION "${UWAC_VERSION_MAJOR}.${UWAC_VERSION_MINOR}.${UWAC_VERSION_REVISION}")
set(UWAC_VERSION_FULL "${UWAC_VERSION}")
set(UWAC_API_VERSION "${UWAC_VERSION_MAJOR}")
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/)
if(NOT FREERDP_UNIFIED_BUILD)
cmake_minimum_required(VERSION 3.13)
project(uwac VERSION ${UWAC_VERSION} LANGUAGES C)
include(ProjectCStandard)
include(ExportAllSymbols)
endif()
option(UWAC_FORCE_STATIC_BUILD "Force UWAC to be build as static library (recommended)" OFF)
option(UWAC_HAVE_PIXMAN_REGION "Use PIXMAN or FreeRDP for region calculations" "NOT FREERDP_UNIFIED_BUILD")
# Include our extra modules
include(CommonConfigOptions)
include(CheckFunctionExists)
check_function_exists(strerror_r UWAC_HAVE_STRERROR_R)
# Check for cmake compatibility (enable/disable features)
include(FindFeature)
if(UWAC_FORCE_STATIC_BUILD)
set(BUILD_SHARED_LIBS OFF)
else()
include(SetFreeRDPCMakeInstallDir)
include(CMakePackageConfigHelpers)
endif()
if(NOT IOS)
include(CheckIncludeFiles)
check_include_files(stdbool.h UWAC_HAVE_STDBOOL_H)
if(NOT UWAC_HAVE_STDBOOL_H)
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/../compat/stdbool)
endif()
endif()
# Find required libraries
if(UWAC_HAVE_PIXMAN_REGION)
find_package(PkgConfig REQUIRED)
pkg_check_modules(pixman REQUIRED pixman-1)
include_directories(SYSTEM ${pixman_INCLUDE_DIRS})
elseif(FREERDP_UNIFIED_BUILD)
include_directories(${PROJECT_SOURCE_DIR}/winpr/include)
include_directories(${PROJECT_BINARY_DIR}/winpr/include)
include_directories(${PROJECT_SOURCE_DIR}/include)
include_directories(${PROJECT_BINARY_DIR}/include)
else()
find_package(WinPR 3 REQUIRED)
find_package(FreeRDP 3 REQUIRED)
include_directories(SYSTEM ${WinPR_INCLUDE_DIR})
include_directories(SYSTEM ${FreeRDP_INCLUDE_DIR})
endif()
set(WAYLAND_FEATURE_PURPOSE "Wayland")
set(WAYLAND_FEATURE_DESCRIPTION "Wayland client")
set(WAYLAND_FEATURE_TYPE "REQUIRED")
find_feature(Wayland ${WAYLAND_FEATURE_TYPE} ${WAYLAND_FEATURE_PURPOSE} ${WAYLAND_FEATURE_DESCRIPTION})
set(UWAC_INCLUDE_DIR include/uwac${UWAC_API_VERSION})
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include)
include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/include)
add_subdirectory(libuwac)
add_subdirectory(templates)
add_subdirectory(include)

View File

@@ -0,0 +1,21 @@
# UWAC: Using Wayland As Client
# cmake build script
#
# Copyright 2015 David FORT <contact@hardening-consulting.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
if(NOT UWAC_FORCE_STATIC_BUILD)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ DESTINATION ${UWAC_INCLUDE_DIR} FILES_MATCHING PATTERN "*.h")
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/uwac DESTINATION ${UWAC_INCLUDE_DIR} FILES_MATCHING PATTERN "*.h")
endif()

View File

@@ -0,0 +1,43 @@
/*
* Copyright © 2015 David FORT <contact@hardening-consulting.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef UWAC_TOOLS_H_
#define UWAC_TOOLS_H_
#include <stdbool.h>
#include <uwac/uwac.h>
struct uwac_touch_point
{
uint32_t id;
wl_fixed_t x, y;
};
typedef struct uwac_touch_point UwacTouchPoint;
struct uwac_touch_automata;
typedef struct uwac_touch_automata UwacTouchAutomata;
UWAC_API void UwacTouchAutomataInit(UwacTouchAutomata* automata);
UWAC_API void UwacTouchAutomataReset(UwacTouchAutomata* automata);
UWAC_API bool UwacTouchAutomataInjectEvent(UwacTouchAutomata* automata, UwacEvent* event);
#endif /* UWAC_TOOLS_H_ */

View File

@@ -0,0 +1,674 @@
/*
* Copyright © 2014-2015 David FORT <contact@hardening-consulting.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef UWAC_H_
#define UWAC_H_
#include <wayland-client.h>
#include <stdbool.h>
#if defined(__GNUC__) && (__GNUC__ >= 4)
#if defined(__cplusplus) && (__cplusplus >= 201703L)
#define UWAC_API [[gnu::visibility("default")]]
#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 202311L)
#define UWAC_API [[gnu::visibility("default")]]
#else
#define UWAC_API __attribute__((visibility("default")))
#endif
#else
#define UWAC_API
#endif
typedef struct uwac_position UwacPosition;
typedef struct uwac_size UwacSize;
typedef struct uwac_display UwacDisplay;
typedef struct uwac_output UwacOutput;
typedef struct uwac_window UwacWindow;
typedef struct uwac_seat UwacSeat;
typedef uint32_t UwacSeatId;
/** @brief error codes */
typedef enum
{
UWAC_SUCCESS = 0,
UWAC_ERROR_NOMEMORY,
UWAC_ERROR_UNABLE_TO_CONNECT,
UWAC_ERROR_INVALID_DISPLAY,
UWAC_NOT_ENOUGH_RESOURCES,
UWAC_TIMEDOUT,
UWAC_NOT_FOUND,
UWAC_ERROR_CLOSED,
UWAC_ERROR_INTERNAL,
UWAC_ERROR_LAST,
} UwacReturnCode;
/** @brief input modifiers */
enum
{
UWAC_MOD_SHIFT_MASK = 0x01,
UWAC_MOD_ALT_MASK = 0x02,
UWAC_MOD_CONTROL_MASK = 0x04,
UWAC_MOD_CAPS_MASK = 0x08,
UWAC_MOD_NUM_MASK = 0x10,
};
/** @brief a position */
struct uwac_position
{
int x;
int y;
};
/** @brief a rectangle size measure */
struct uwac_size
{
int width;
int height;
};
/** @brief event types */
enum
{
UWAC_EVENT_NEW_SEAT = 0,
UWAC_EVENT_REMOVED_SEAT,
UWAC_EVENT_NEW_OUTPUT,
UWAC_EVENT_CONFIGURE,
UWAC_EVENT_POINTER_ENTER,
UWAC_EVENT_POINTER_LEAVE,
UWAC_EVENT_POINTER_MOTION,
UWAC_EVENT_POINTER_BUTTONS,
UWAC_EVENT_POINTER_AXIS,
UWAC_EVENT_KEYBOARD_ENTER,
UWAC_EVENT_KEYBOARD_MODIFIERS,
UWAC_EVENT_KEY,
UWAC_EVENT_TOUCH_FRAME_BEGIN,
UWAC_EVENT_TOUCH_UP,
UWAC_EVENT_TOUCH_DOWN,
UWAC_EVENT_TOUCH_MOTION,
UWAC_EVENT_TOUCH_CANCEL,
UWAC_EVENT_TOUCH_FRAME_END,
UWAC_EVENT_FRAME_DONE,
UWAC_EVENT_CLOSE,
UWAC_EVENT_CLIPBOARD_AVAILABLE,
UWAC_EVENT_CLIPBOARD_SELECT,
UWAC_EVENT_CLIPBOARD_OFFER,
UWAC_EVENT_OUTPUT_GEOMETRY,
UWAC_EVENT_POINTER_AXIS_DISCRETE,
UWAC_EVENT_POINTER_FRAME,
UWAC_EVENT_POINTER_SOURCE
};
/** @brief window states */
enum
{
UWAC_WINDOW_MAXIMIZED = 0x1,
UWAC_WINDOW_RESIZING = 0x2,
UWAC_WINDOW_FULLSCREEN = 0x4,
UWAC_WINDOW_ACTIVATED = 0x8,
};
struct uwac_new_output_event
{
int type;
UwacOutput* output;
};
typedef struct uwac_new_output_event UwacOutputNewEvent;
struct uwac_new_seat_event
{
int type;
UwacSeat* seat;
};
typedef struct uwac_new_seat_event UwacSeatNewEvent;
struct uwac_removed_seat_event
{
int type;
UwacSeatId id;
};
typedef struct uwac_removed_seat_event UwacSeatRemovedEvent;
struct uwac_keyboard_enter_event
{
int type;
UwacWindow* window;
UwacSeat* seat;
};
typedef struct uwac_keyboard_enter_event UwacKeyboardEnterLeaveEvent;
struct uwac_keyboard_modifiers_event
{
int type;
uint32_t modifiers;
};
typedef struct uwac_keyboard_modifiers_event UwacKeyboardModifiersEvent;
struct uwac_pointer_enter_event
{
int type;
UwacWindow* window;
UwacSeat* seat;
uint32_t x, y;
};
typedef struct uwac_pointer_enter_event UwacPointerEnterLeaveEvent;
struct uwac_pointer_motion_event
{
int type;
UwacWindow* window;
UwacSeat* seat;
uint32_t x, y;
};
typedef struct uwac_pointer_motion_event UwacPointerMotionEvent;
struct uwac_pointer_button_event
{
int type;
UwacWindow* window;
UwacSeat* seat;
uint32_t x, y;
uint32_t button;
enum wl_pointer_button_state state;
};
typedef struct uwac_pointer_button_event UwacPointerButtonEvent;
struct uwac_pointer_axis_event
{
int type;
UwacWindow* window;
UwacSeat* seat;
uint32_t x, y;
uint32_t axis;
wl_fixed_t value;
};
typedef struct uwac_pointer_axis_event UwacPointerAxisEvent;
struct uwac_pointer_frame_event
{
int type;
UwacWindow* window;
UwacSeat* seat;
};
typedef struct uwac_pointer_frame_event UwacPointerFrameEvent;
struct uwac_pointer_source_event
{
int type;
UwacWindow* window;
UwacSeat* seat;
enum wl_pointer_axis_source axis_source;
};
typedef struct uwac_pointer_source_event UwacPointerSourceEvent;
struct uwac_touch_frame_event
{
int type;
UwacWindow* window;
UwacSeat* seat;
};
typedef struct uwac_touch_frame_event UwacTouchFrameBegin;
typedef struct uwac_touch_frame_event UwacTouchFrameEnd;
typedef struct uwac_touch_frame_event UwacTouchCancel;
struct uwac_touch_data
{
int type;
UwacWindow* window;
UwacSeat* seat;
int32_t id;
wl_fixed_t x;
wl_fixed_t y;
};
typedef struct uwac_touch_data UwacTouchUp;
typedef struct uwac_touch_data UwacTouchDown;
typedef struct uwac_touch_data UwacTouchMotion;
struct uwac_frame_done_event
{
int type;
UwacWindow* window;
};
typedef struct uwac_frame_done_event UwacFrameDoneEvent;
struct uwac_configure_event
{
int type;
UwacWindow* window;
int32_t width;
int32_t height;
int states;
};
typedef struct uwac_configure_event UwacConfigureEvent;
struct uwac_key_event
{
int type;
UwacWindow* window;
uint32_t raw_key;
uint32_t sym;
bool pressed;
bool repeated;
};
typedef struct uwac_key_event UwacKeyEvent;
struct uwac_close_event
{
int type;
UwacWindow* window;
};
typedef struct uwac_close_event UwacCloseEvent;
struct uwac_clipboard_event
{
int type;
UwacSeat* seat;
char mime[64];
};
typedef struct uwac_clipboard_event UwacClipboardEvent;
struct uwac_output_geometry_event
{
int type;
UwacOutput* output;
int x;
int y;
int physical_width;
int physical_height;
int subpixel;
const char* make;
const char* model;
int transform;
};
typedef struct uwac_output_geometry_event UwacOutputGeometryEvent;
union uwac_event
{
int type;
UwacOutputNewEvent output_new;
UwacOutputGeometryEvent output_geometry;
UwacSeatNewEvent seat_new;
UwacSeatRemovedEvent seat_removed;
UwacPointerEnterLeaveEvent mouse_enter_leave;
UwacPointerMotionEvent mouse_motion;
UwacPointerButtonEvent mouse_button;
UwacPointerAxisEvent mouse_axis;
UwacPointerFrameEvent mouse_frame;
UwacPointerSourceEvent mouse_source;
UwacKeyboardEnterLeaveEvent keyboard_enter_leave;
UwacKeyboardModifiersEvent keyboard_modifiers;
UwacClipboardEvent clipboard;
UwacKeyEvent key;
UwacTouchFrameBegin touchFrameBegin;
UwacTouchUp touchUp;
UwacTouchDown touchDown;
UwacTouchMotion touchMotion;
UwacTouchFrameEnd touchFrameEnd;
UwacTouchCancel touchCancel;
UwacFrameDoneEvent frame_done;
UwacConfigureEvent configure;
UwacCloseEvent close;
};
typedef union uwac_event UwacEvent;
typedef bool (*UwacErrorHandler)(UwacDisplay* d, UwacReturnCode code, const char* msg, ...);
typedef void (*UwacDataTransferHandler)(UwacSeat* seat, void* context, const char* mime, int fd);
typedef void (*UwacCancelDataTransferHandler)(UwacSeat* seat, void* context);
#ifdef __cplusplus
extern "C"
{
#endif
/**
* install a handler that will be called when UWAC encounter internal errors. The
* handler is supposed to answer if the execution can continue. I can also be used
* to log things.
*
* @param handler the error handling function to install
*/
UWAC_API void UwacInstallErrorHandler(UwacErrorHandler handler);
/**
* Opens the corresponding wayland display, using nullptr you will open the default
* display.
*
* @param name the name of the display to open
* @return the created UwacDisplay object
*/
UWAC_API UwacDisplay* UwacOpenDisplay(const char* name, UwacReturnCode* err);
/**
* closes the corresponding UwacDisplay
*
* @param pdisplay a pointer on the display to close
* @return UWAC_SUCCESS if the operation was successful, the corresponding error otherwise
*/
UWAC_API UwacReturnCode UwacCloseDisplay(UwacDisplay** pdisplay);
/**
* Returns the file descriptor associated with the UwacDisplay, this is useful when
* you want to poll that file descriptor for activity.
*
* @param display an opened UwacDisplay
* @return the corresponding descriptor
*/
UWAC_API int UwacDisplayGetFd(UwacDisplay* display);
/**
* Returns a human readable form of a Uwac error code
*
* @param error the error number
* @return the associated string
*/
UWAC_API const char* UwacErrorString(UwacReturnCode error);
/**
* returns the last error that occurred on a display
*
* @param display the display
* @return the last error that have been set for this display
*/
UWAC_API UwacReturnCode UwacDisplayGetLastError(const UwacDisplay* display);
/**
* retrieves the version of a given interface
*
* @param display the display connection
* @param name the name of the interface
* @param version the output variable for the version
* @return UWAC_SUCCESS if the interface was found, UWAC_NOT_FOUND otherwise
*/
UWAC_API UwacReturnCode UwacDisplayQueryInterfaceVersion(const UwacDisplay* display,
const char* name, uint32_t* version);
/**
* returns the number SHM formats that have been reported by the compositor
*
* @param display a connected UwacDisplay
* @return the number of SHM formats supported
*/
UWAC_API uint32_t UwacDisplayQueryGetNbShmFormats(UwacDisplay* display);
/**
* returns the supported ShmFormats
*
* @param display a connected UwacDisplay
* @param formats a pointer on an array of wl_shm_format with enough place for formats_size
*items
* @param formats_size the size of the formats array
* @param filled the number of filled entries in the formats array
* @return UWAC_SUCCESS on success, an error otherwise
*/
UWAC_API UwacReturnCode UwacDisplayQueryShmFormats(const UwacDisplay* display,
enum wl_shm_format* formats,
int formats_size, int* filled);
/**
* returns the number of registered outputs
*
* @param display the display to query
* @return the number of outputs
*/
UWAC_API uint32_t UwacDisplayGetNbOutputs(const UwacDisplay* display);
/**
* retrieve a particular UwacOutput object
*
* @param display the display to query
* @param index index of the output
* @return the given UwacOutput, nullptr if something failed (so you should query
*UwacDisplayGetLastError() to have the reason)
*/
UWAC_API const UwacOutput* UwacDisplayGetOutput(UwacDisplay* display, int index);
/**
* retrieve the resolution of a given UwacOutput
*
* @param output the UwacOutput
* @param resolution a pointer on the
* @return UWAC_SUCCESS on success
*/
UWAC_API UwacReturnCode UwacOutputGetResolution(const UwacOutput* output, UwacSize* resolution);
/**
* retrieve the position of a given UwacOutput
*
* @param output the UwacOutput
* @param pos a pointer on the target position
* @return UWAC_SUCCESS on success
*/
UWAC_API UwacReturnCode UwacOutputGetPosition(const UwacOutput* output, UwacPosition* pos);
/**
* creates a window using a SHM surface
*
* @param display the display to attach the window to
* @param width the width of the window
* @param height the height of the window
* @param format format to use for the SHM surface
* @return the created UwacWindow, nullptr if something failed (use UwacDisplayGetLastError() to
*know more about this)
*/
UWAC_API UwacWindow* UwacCreateWindowShm(UwacDisplay* display, uint32_t width, uint32_t height,
enum wl_shm_format format);
/**
* destroys the corresponding UwacWindow
*
* @param window a pointer on the UwacWindow to destroy
* @return if the operation completed successfully
*/
UWAC_API UwacReturnCode UwacDestroyWindow(UwacWindow** window);
/**
* Sets the region that should be considered opaque to the compositor.
*
* @param window the UwacWindow
* @param x The horizontal coordinate in pixels
* @param y The vertical coordinate in pixels
* @param width The width of the region
* @param height The height of the region
* @return UWAC_SUCCESS on success, an error otherwise
*/
UWAC_API UwacReturnCode UwacWindowSetOpaqueRegion(UwacWindow* window, uint32_t x, uint32_t y,
uint32_t width, uint32_t height);
/**
* Sets the region of the window that can trigger input events
*
* @param window the UwacWindow
* @param x The horizontal coordinate in pixels
* @param y The vertical coordinate in pixels
* @param width The width of the region
* @param height The height of the region
* @return UWAC_SUCCESS on success, an error otherwise
*/
UWAC_API UwacReturnCode UwacWindowSetInputRegion(UwacWindow* window, uint32_t x, uint32_t y,
uint32_t width, uint32_t height);
/**
* retrieves a pointer on the current window content to draw a frame
* @param window the UwacWindow
* @return a pointer on the current window content
*/
UWAC_API void* UwacWindowGetDrawingBuffer(UwacWindow* window);
/**
* sets a rectangle as dirty for the next frame of a window
*
* @param window the UwacWindow
* @param x left coordinate
* @param y top coordinate
* @param width the width of the dirty rectangle
* @param height the height of the dirty rectangle
* @return UWAC_SUCCESS on success, an Uwac error otherwise
*/
UWAC_API UwacReturnCode UwacWindowAddDamage(UwacWindow* window, uint32_t x, uint32_t y,
uint32_t width, uint32_t height);
/**
* returns the geometry of the given UwacWindow buffer
*
* @param window the UwacWindow
* @param geometry the geometry to fill
* @param stride the length of a buffer line in bytes
* @return UWAC_SUCCESS on success, an Uwac error otherwise
*/
UWAC_API UwacReturnCode UwacWindowGetDrawingBufferGeometry(UwacWindow* window,
UwacSize* geometry, size_t* stride);
/**
* Sends a frame to the compositor with the content of the drawing buffer
*
* @param window the UwacWindow to refresh
* @param copyContentForNextFrame if true the content to display is copied in the next drawing
*buffer
* @return UWAC_SUCCESS if the operation was successful
*/
UWAC_API UwacReturnCode UwacWindowSubmitBuffer(UwacWindow* window,
bool copyContentForNextFrame);
/**
* returns the geometry of the given UwacWindows
*
* @param window the UwacWindow
* @param geometry the geometry to fill
* @return UWAC_SUCCESS on success, an Uwac error otherwise
*/
UWAC_API UwacReturnCode UwacWindowGetGeometry(UwacWindow* window, UwacSize* geometry);
/**
* Sets or unset the fact that the window is set fullscreen. After this call the
* application should get prepared to receive a configure event. The output is used
* only when going fullscreen, it is optional and not used when exiting fullscreen.
*
* @param window the UwacWindow
* @param output an optional UwacOutput to put the window fullscreen on
* @param isFullscreen set or unset fullscreen
* @return UWAC_SUCCESS if the operation was a success
*/
UWAC_API UwacReturnCode UwacWindowSetFullscreenState(UwacWindow* window, UwacOutput* output,
bool isFullscreen);
/**
* When possible (depending on the shell) sets the title of the UwacWindow
*
* @param window the UwacWindow
* @param name title
*/
UWAC_API void UwacWindowSetTitle(UwacWindow* window, const char* name);
/**
* Sets the app id of the UwacWindow
*
* @param window the UwacWindow
* @param app_id app id
*/
UWAC_API void UwacWindowSetAppId(UwacWindow* window, const char* app_id);
/** Dispatch the display
*
* @param display The display to dispatch
* @param timeout The maximum time to wait in milliseconds (-1 == infinite).
* @return 1 for success, 0 if display not running, -1 on failure
*/
UWAC_API int UwacDisplayDispatch(UwacDisplay* display, int timeout);
/**
* Returns if you have some pending events, and you can UwacNextEvent() without blocking
*
* @param display the UwacDisplay
* @return if there's some pending events
*/
UWAC_API bool UwacHasEvent(UwacDisplay* display);
/** Waits until an event occurs, and when it's there copy the event from the queue to
* event.
*
* @param display the Uwac display
* @param event the event to fill
* @return if the operation completed successfully
*/
UWAC_API UwacReturnCode UwacNextEvent(UwacDisplay* display, UwacEvent* event);
/**
* returns the name of the given UwacSeat
*
* @param seat the UwacSeat
* @return the name of the seat
*/
UWAC_API const char* UwacSeatGetName(const UwacSeat* seat);
/**
* returns the id of the given UwacSeat
*
* @param seat the UwacSeat
* @return the id of the seat
*/
UWAC_API UwacSeatId UwacSeatGetId(const UwacSeat* seat);
/**
*
*/
UWAC_API UwacReturnCode UwacClipboardOfferDestroy(UwacSeat* seat);
UWAC_API UwacReturnCode UwacClipboardOfferCreate(UwacSeat* seat, const char* mime);
UWAC_API UwacReturnCode UwacClipboardOfferAnnounce(UwacSeat* seat, void* context,
UwacDataTransferHandler transfer,
UwacCancelDataTransferHandler cancel);
UWAC_API void* UwacClipboardDataGet(UwacSeat* seat, const char* mime, size_t* size);
/**
* Inhibits or restores keyboard shortcuts.
*
* @param seat The UwacSeat to inhibit the shortcuts for
* @param inhibit Inhibit or restore keyboard shortcuts
*
* @return UWAC_SUCCESS or an appropriate error code.
*/
UWAC_API UwacReturnCode UwacSeatInhibitShortcuts(UwacSeat* seat, bool inhibit);
/**
* @brief UwacSeatSetMouseCursor Sets the specified image as the new mouse cursor.
* Special values: If data == nullptr && length == 0
* the cursor is hidden, if data == nullptr && length != 0
* the default system cursor is used.
*
* @param seat The UwacSeat to apply the cursor image to
* @param data A pointer to the image data
* @param length The size of the image data
* @param width The image width in pixel
* @param height The image height in pixel
* @param hot_x The hotspot horizontal offset in pixel
* @param hot_y The hotspot vertical offset in pixel
*
* @return UWAC_SUCCESS if successful, an appropriate error otherwise.
*/
UWAC_API UwacReturnCode UwacSeatSetMouseCursor(UwacSeat* seat, const void* data, size_t length,
size_t width, size_t height, size_t hot_x,
size_t hot_y);
#ifdef __cplusplus
}
#endif
#endif /* UWAC_H_ */

View File

@@ -0,0 +1,108 @@
# UWAC: Using Wayland As Client
#
# Copyright 2015 David FORT <contact@hardening-consulting.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set(MODULE_NAME "uwac")
set(MODULE_PREFIX "UWAC")
set(GENERATED_SOURCES "")
macro(generate_protocol_file PROTO)
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/protocols/${PROTO}-protocol.c" COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_CURRENT_BINARY_DIR}/protocols
COMMAND ${WAYLAND_SCANNER} code < ${CMAKE_CURRENT_SOURCE_DIR}/../protocols/${PROTO}.xml >
${CMAKE_CURRENT_BINARY_DIR}/protocols/${PROTO}-protocol.c
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../protocols/${PROTO}.xml
)
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/protocols/${PROTO}-client-protocol.h"
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/protocols
COMMAND ${WAYLAND_SCANNER} client-header < ${CMAKE_CURRENT_SOURCE_DIR}/../protocols/${PROTO}.xml >
${CMAKE_CURRENT_BINARY_DIR}/protocols/${PROTO}-client-protocol.h
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../protocols/${PROTO}.xml
)
list(APPEND GENERATED_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/protocols/${PROTO}-client-protocol.h)
list(APPEND GENERATED_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/protocols/${PROTO}-protocol.c)
endmacro()
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
generate_protocol_file(xdg-shell)
generate_protocol_file(viewporter)
generate_protocol_file(xdg-decoration-unstable-v1)
generate_protocol_file(server-decoration)
generate_protocol_file(ivi-application)
generate_protocol_file(fullscreen-shell-unstable-v1)
generate_protocol_file(keyboard-shortcuts-inhibit-unstable-v1)
if(FREEBSD)
include_directories(SYSTEM ${EPOLLSHIM_INCLUDE_DIR})
endif()
include_directories(SYSTEM ${WAYLAND_INCLUDE_DIR})
include_directories(SYSTEM ${XKBCOMMON_INCLUDE_DIR})
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../include")
include_directories("${CMAKE_CURRENT_BINARY_DIR}/../include")
include_directories("${CMAKE_CURRENT_BINARY_DIR}/protocols")
add_compile_definitions(BUILD_IVI BUILD_FULLSCREEN_SHELL ENABLE_XKBCOMMON)
set(${MODULE_PREFIX}_SRCS
${GENERATED_SOURCES}
uwac-display.c
uwac-input.c
uwac-clipboard.c
uwac-os.c
uwac-os.h
uwac-output.c
uwac-priv.h
uwac-tools.c
uwac-utils.c
uwac-window.c
)
add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
set_target_properties(${MODULE_NAME} PROPERTIES LINKER_LANGUAGE C)
set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME ${MODULE_NAME}${UWAC_API_VERSION})
if(WITH_LIBRARY_VERSIONING)
set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${UWAC_VERSION} SOVERSION ${UWAC_API_VERSION})
endif()
target_link_libraries(
${MODULE_NAME} ${${MODULE_PREFIX}_LIBS} PRIVATE ${WAYLAND_LIBS} ${XKBCOMMON_LIBS} ${EPOLLSHIM_LIBS}
)
if(UWAC_HAVE_PIXMAN_REGION)
target_link_libraries(${MODULE_NAME} PRIVATE ${pixman_LINK_LIBRARIES})
else()
target_link_libraries(${MODULE_NAME} PRIVATE freerdp)
endif()
target_link_libraries(${MODULE_NAME} PRIVATE m)
if(NOT UWAC_FORCE_STATIC_BUILD)
target_include_directories(${MODULE_NAME} INTERFACE $<INSTALL_INTERFACE:include/uwac${UWAC_API_VERSION}>)
install(TARGETS ${MODULE_NAME} COMPONENT libraries EXPORT uwac ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
endif()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "uwac")
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
# add_subdirectory(test)
endif()

View File

@@ -0,0 +1,282 @@
/*
* Copyright © 2018 Armin Novak <armin.novak@thincast.com>
* Copyright © 2018 Thincast Technologies GmbH
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "uwac-priv.h"
#include "uwac-utils.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/timerfd.h>
#include <sys/epoll.h>
/* paste */
static void data_offer_offer(void* data, struct wl_data_offer* data_offer,
const char* offered_mime_type)
{
UwacSeat* seat = (UwacSeat*)data;
assert(seat);
if (!seat->ignore_announcement)
{
UwacClipboardEvent* event =
(UwacClipboardEvent*)UwacDisplayNewEvent(seat->display, UWAC_EVENT_CLIPBOARD_OFFER);
if (!event)
{
assert(uwacErrorHandler(seat->display, UWAC_ERROR_INTERNAL,
"failed to allocate a clipboard event\n"));
}
else
{
event->seat = seat;
(void)snprintf(event->mime, sizeof(event->mime), "%s", offered_mime_type);
}
}
}
static const struct wl_data_offer_listener data_offer_listener = { .offer = data_offer_offer };
static void data_device_data_offer(void* data, struct wl_data_device* data_device,
struct wl_data_offer* data_offer)
{
UwacSeat* seat = (UwacSeat*)data;
assert(seat);
if (!seat->ignore_announcement)
{
UwacClipboardEvent* event =
(UwacClipboardEvent*)UwacDisplayNewEvent(seat->display, UWAC_EVENT_CLIPBOARD_SELECT);
if (!event)
{
assert(uwacErrorHandler(seat->display, UWAC_ERROR_INTERNAL,
"failed to allocate a close event\n"));
}
else
event->seat = seat;
wl_data_offer_add_listener(data_offer, &data_offer_listener, data);
seat->offer = data_offer;
}
else
seat->offer = nullptr;
}
static void data_device_selection(void* data, struct wl_data_device* data_device,
struct wl_data_offer* data_offer)
{
}
static const struct wl_data_device_listener data_device_listener = {
.data_offer = data_device_data_offer, .selection = data_device_selection
};
/* copy */
static void data_source_target_handler(void* data, struct wl_data_source* data_source,
const char* mime_type)
{
}
static void data_source_send_handler(void* data, struct wl_data_source* data_source,
const char* mime_type, int fd)
{
UwacSeat* seat = (UwacSeat*)data;
seat->transfer_data(seat, seat->data_context, mime_type, fd);
}
static void data_source_cancelled_handler(void* data, struct wl_data_source* data_source)
{
UwacSeat* seat = (UwacSeat*)data;
seat->cancel_data(seat, seat->data_context);
}
static const struct wl_data_source_listener data_source_listener = {
.target = data_source_target_handler,
.send = data_source_send_handler,
.cancelled = data_source_cancelled_handler
};
static void UwacRegisterDeviceListener(UwacSeat* s)
{
wl_data_device_add_listener(s->data_device, &data_device_listener, s);
}
static UwacReturnCode UwacCreateDataSource(UwacSeat* s)
{
if (!s)
return UWAC_ERROR_INTERNAL;
s->data_source = wl_data_device_manager_create_data_source(s->display->data_device_manager);
wl_data_source_add_listener(s->data_source, &data_source_listener, s);
return UWAC_SUCCESS;
}
UwacReturnCode UwacSeatRegisterClipboard(UwacSeat* s)
{
UwacClipboardEvent* event = nullptr;
if (!s)
return UWAC_ERROR_INTERNAL;
if (!s->display->data_device_manager || !s->data_device)
return UWAC_NOT_ENOUGH_RESOURCES;
UwacRegisterDeviceListener(s);
UwacReturnCode rc = UwacCreateDataSource(s);
if (rc != UWAC_SUCCESS)
return rc;
event = (UwacClipboardEvent*)UwacDisplayNewEvent(s->display, UWAC_EVENT_CLIPBOARD_AVAILABLE);
if (!event)
{
assert(uwacErrorHandler(s->display, UWAC_ERROR_INTERNAL,
"failed to allocate a clipboard event\n"));
return UWAC_ERROR_INTERNAL;
}
event->seat = s;
return UWAC_SUCCESS;
}
UwacReturnCode UwacClipboardOfferDestroy(UwacSeat* seat)
{
if (!seat)
return UWAC_ERROR_INTERNAL;
if (seat->data_source)
wl_data_source_destroy(seat->data_source);
return UwacCreateDataSource(seat);
}
UwacReturnCode UwacClipboardOfferCreate(UwacSeat* seat, const char* mime)
{
if (!seat || !mime)
return UWAC_ERROR_INTERNAL;
wl_data_source_offer(seat->data_source, mime);
return UWAC_SUCCESS;
}
static void callback_done(void* data, struct wl_callback* callback, uint32_t serial)
{
*(uint32_t*)data = serial;
}
static const struct wl_callback_listener callback_listener = { .done = callback_done };
static uint32_t get_serial(UwacSeat* s)
{
struct wl_callback* callback = nullptr;
uint32_t serial = 0;
callback = wl_display_sync(s->display->display);
wl_callback_add_listener(callback, &callback_listener, &serial);
while (serial == 0)
{
wl_display_dispatch(s->display->display);
}
return serial;
}
UwacReturnCode UwacClipboardOfferAnnounce(UwacSeat* seat, void* context,
UwacDataTransferHandler transfer,
UwacCancelDataTransferHandler cancel)
{
if (!seat)
return UWAC_ERROR_INTERNAL;
seat->data_context = context;
seat->transfer_data = transfer;
seat->cancel_data = cancel;
seat->ignore_announcement = true;
wl_data_device_set_selection(seat->data_device, seat->data_source, get_serial(seat));
wl_display_roundtrip(seat->display->display);
seat->ignore_announcement = false;
return UWAC_SUCCESS;
}
void* UwacClipboardDataGet(UwacSeat* seat, const char* mime, size_t* size)
{
ssize_t r = 0;
size_t alloc = 0;
size_t pos = 0;
char* data = nullptr;
int pipefd[2] = WINPR_C_ARRAY_INIT;
if (!seat || !mime || !size || !seat->offer)
return nullptr;
*size = 0;
if (pipe(pipefd) != 0)
return nullptr;
wl_data_offer_receive(seat->offer, mime, pipefd[1]);
close(pipefd[1]);
wl_display_roundtrip(seat->display->display);
wl_display_flush(seat->display->display);
do
{
if (alloc >= SIZE_MAX - 1024)
goto fail;
alloc += 1024;
void* tmp = xrealloc(data, alloc);
if (!tmp)
goto fail;
data = tmp;
if (pos >= alloc)
goto fail;
r = read(pipefd[0], &data[pos], alloc - pos);
if (r > 0)
pos += r;
if (r < 0)
goto fail;
} while (r > 0);
close(pipefd[0]);
if (alloc > 0)
{
data[pos] = '\0';
*size = pos + 1;
}
return data;
fail:
free(data);
close(pipefd[0]);
return nullptr;
}

View File

@@ -0,0 +1,796 @@
/*
* Copyright © 2014 David FORT <contact@hardening-consulting.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "uwac-priv.h"
#include "uwac-utils.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <assert.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
#include <sys/epoll.h>
#include "uwac-os.h"
#include "wayland-cursor.h"
#define TARGET_COMPOSITOR_INTERFACE 3U
#define TARGET_SHM_INTERFACE 1U
#define TARGET_SHELL_INTERFACE 1U
#define TARGET_DDM_INTERFACE 1U
#define TARGET_SEAT_INTERFACE 5U
#define TARGET_XDG_VERSION 5U /* The version of xdg-shell that we implement */
#if !defined(NDEBUG)
static const char* event_names[] = {
"new seat", "removed seat", "new output", "configure", "pointer enter",
"pointer leave", "pointer motion", "pointer buttons", "pointer axis", "keyboard enter",
"key", "touch frame begin", "touch up", "touch down", "touch motion",
"touch cancel", "touch frame end", "frame done", "close", nullptr
};
#endif
static bool uwac_default_error_handler(UwacDisplay* display, UwacReturnCode code, const char* msg,
...)
{
va_list args = WINPR_C_ARRAY_INIT;
va_start(args, msg);
(void)vfprintf(stderr, "%s", args);
va_end(args);
return false;
}
UwacErrorHandler uwacErrorHandler = uwac_default_error_handler;
void UwacInstallErrorHandler(UwacErrorHandler handler)
{
if (handler)
uwacErrorHandler = handler;
else
uwacErrorHandler = uwac_default_error_handler;
}
static void cb_shm_format(void* data, struct wl_shm* wl_shm, uint32_t format)
{
UwacDisplay* d = data;
if (format == WL_SHM_FORMAT_RGB565)
d->has_rgb565 = true;
d->shm_formats_nb++;
d->shm_formats =
xrealloc((void*)d->shm_formats, sizeof(enum wl_shm_format) * d->shm_formats_nb);
d->shm_formats[d->shm_formats_nb - 1] = format;
}
static struct wl_shm_listener shm_listener = { cb_shm_format };
static void xdg_shell_ping(void* data, struct xdg_wm_base* xdg_wm_base, uint32_t serial)
{
xdg_wm_base_pong(xdg_wm_base, serial);
}
static const struct xdg_wm_base_listener xdg_wm_base_listener = {
xdg_shell_ping,
};
#ifdef BUILD_FULLSCREEN_SHELL
static void fullscreen_capability(void* data,
struct zwp_fullscreen_shell_v1* zwp_fullscreen_shell_v1,
uint32_t capability)
{
}
static const struct zwp_fullscreen_shell_v1_listener fullscreen_shell_listener = {
fullscreen_capability,
};
#endif
static void display_destroy_seat(UwacDisplay* d, uint32_t name)
{
UwacSeat* seat = nullptr;
UwacSeat* tmp = nullptr;
wl_list_for_each_safe(seat, tmp, &d->seats, link)
{
if (seat->seat_id == name)
{
UwacSeatDestroy(seat);
}
}
}
static void UwacSeatRegisterDDM(UwacSeat* seat)
{
UwacDisplay* d = seat->display;
if (!d->data_device_manager)
return;
if (!seat->data_device)
seat->data_device =
wl_data_device_manager_get_data_device(d->data_device_manager, seat->seat);
}
static void UwacRegisterCursor(UwacSeat* seat)
{
if (!seat || !seat->display || !seat->display->compositor)
return;
seat->pointer_surface = wl_compositor_create_surface(seat->display->compositor);
}
static void registry_handle_global(void* data, struct wl_registry* registry, uint32_t id,
const char* interface, uint32_t version)
{
UwacDisplay* d = data;
UwacGlobal* global = nullptr;
global = xzalloc(sizeof *global);
global->name = id;
global->interface = xstrdup(interface);
global->version = version;
wl_list_insert(d->globals.prev, &global->link);
if (strcmp(interface, "wl_compositor") == 0)
{
d->compositor = wl_registry_bind(registry, id, &wl_compositor_interface,
min(TARGET_COMPOSITOR_INTERFACE, version));
}
else if (strcmp(interface, "wl_shm") == 0)
{
d->shm =
wl_registry_bind(registry, id, &wl_shm_interface, min(TARGET_SHM_INTERFACE, version));
wl_shm_add_listener(d->shm, &shm_listener, d);
}
else if (strcmp(interface, "wl_output") == 0)
{
UwacOutput* output = nullptr;
UwacOutputNewEvent* ev = nullptr;
output = UwacCreateOutput(d, id, version);
if (!output)
{
assert(uwacErrorHandler(d, UWAC_ERROR_NOMEMORY, "unable to create output\n"));
return;
}
ev = (UwacOutputNewEvent*)UwacDisplayNewEvent(d, UWAC_EVENT_NEW_OUTPUT);
if (ev)
ev->output = output;
}
else if (strcmp(interface, "wl_seat") == 0)
{
UwacSeatNewEvent* ev = nullptr;
UwacSeat* seat = nullptr;
seat = UwacSeatNew(d, id, min(version, TARGET_SEAT_INTERFACE));
if (!seat)
{
assert(uwacErrorHandler(d, UWAC_ERROR_NOMEMORY, "unable to create new seat\n"));
return;
}
UwacSeatRegisterDDM(seat);
UwacSeatRegisterClipboard(seat);
UwacRegisterCursor(seat);
ev = (UwacSeatNewEvent*)UwacDisplayNewEvent(d, UWAC_EVENT_NEW_SEAT);
if (!ev)
{
assert(uwacErrorHandler(d, UWAC_ERROR_NOMEMORY, "unable to create new seat event\n"));
return;
}
ev->seat = seat;
}
else if (strcmp(interface, "wl_data_device_manager") == 0)
{
UwacSeat* seat = nullptr;
UwacSeat* tmp = nullptr;
d->data_device_manager = wl_registry_bind(registry, id, &wl_data_device_manager_interface,
min(TARGET_DDM_INTERFACE, version));
wl_list_for_each_safe(seat, tmp, &d->seats, link)
{
UwacSeatRegisterDDM(seat);
UwacSeatRegisterClipboard(seat);
UwacRegisterCursor(seat);
}
}
else if (strcmp(interface, "wl_shell") == 0)
{
d->shell = wl_registry_bind(registry, id, &wl_shell_interface,
min(TARGET_SHELL_INTERFACE, version));
}
else if (strcmp(interface, "xdg_wm_base") == 0)
{
d->xdg_base = wl_registry_bind(registry, id, &xdg_wm_base_interface, 1);
xdg_wm_base_add_listener(d->xdg_base, &xdg_wm_base_listener, d);
}
else if (strcmp(interface, "wp_viewporter") == 0)
{
d->viewporter = wl_registry_bind(registry, id, &wp_viewporter_interface, 1);
}
else if (strcmp(interface, "zwp_keyboard_shortcuts_inhibit_manager_v1") == 0)
{
d->keyboard_inhibit_manager =
wl_registry_bind(registry, id, &zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1);
}
else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0)
{
d->deco_manager = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1);
}
else if (strcmp(interface, "org_kde_kwin_server_decoration_manager") == 0)
{
d->kde_deco_manager =
wl_registry_bind(registry, id, &org_kde_kwin_server_decoration_manager_interface, 1);
}
#if BUILD_IVI
else if (strcmp(interface, "ivi_application") == 0)
{
d->ivi_application = wl_registry_bind(registry, id, &ivi_application_interface, 1);
}
#endif
#if BUILD_FULLSCREEN_SHELL
else if (strcmp(interface, "zwp_fullscreen_shell_v1") == 0)
{
d->fullscreen_shell = wl_registry_bind(registry, id, &zwp_fullscreen_shell_v1_interface, 1);
zwp_fullscreen_shell_v1_add_listener(d->fullscreen_shell, &fullscreen_shell_listener, d);
}
#endif
#if 0
else if (strcmp(interface, "text_cursor_position") == 0)
{
d->text_cursor_position = wl_registry_bind(registry, id, &text_cursor_position_interface, 1);
}
else if (strcmp(interface, "workspace_manager") == 0)
{
//init_workspace_manager(d, id);
}
else if (strcmp(interface, "wl_subcompositor") == 0)
{
d->subcompositor = wl_registry_bind(registry, id, &wl_subcompositor_interface, 1);
#endif
}
static void registry_handle_global_remove(void* data, struct wl_registry* registry, uint32_t name)
{
UwacDisplay* d = data;
UwacGlobal* global = nullptr;
UwacGlobal* tmp = nullptr;
wl_list_for_each_safe(global, tmp, &d->globals, link)
{
if (global->name != name)
continue;
#if 0
if (strcmp(global->interface, "wl_output") == 0)
display_destroy_output(d, name);
#endif
if (strcmp(global->interface, "wl_seat") == 0)
{
UwacSeatRemovedEvent* ev = nullptr;
display_destroy_seat(d, name);
ev = (UwacSeatRemovedEvent*)UwacDisplayNewEvent(d, UWAC_EVENT_REMOVED_SEAT);
if (ev)
ev->id = name;
}
wl_list_remove(&global->link);
free(global->interface);
free(global);
}
}
static void UwacDestroyGlobal(UwacGlobal* global)
{
free(global->interface);
wl_list_remove(&global->link);
free(global);
}
static void* display_bind(UwacDisplay* display, uint32_t name, const struct wl_interface* interface,
uint32_t version)
{
return wl_registry_bind(display->registry, name, interface, version);
}
static const struct wl_registry_listener registry_listener = { registry_handle_global,
registry_handle_global_remove };
int UwacDisplayWatchFd(UwacDisplay* display, int fd, uint32_t events, UwacTask* task)
{
struct epoll_event ep;
ep.events = events;
ep.data.ptr = task;
return epoll_ctl(display->epoll_fd, EPOLL_CTL_ADD, fd, &ep);
}
static void UwacDisplayUnwatchFd(UwacDisplay* display, int fd)
{
epoll_ctl(display->epoll_fd, EPOLL_CTL_DEL, fd, nullptr);
}
static void display_exit(UwacDisplay* display)
{
display->running = false;
}
static void display_dispatch_events(UwacTask* task, uint32_t events)
{
UwacDisplay* display = container_of(task, UwacDisplay, dispatch_fd_task);
struct epoll_event ep;
int ret = 0;
display->display_fd_events = events;
if ((events & EPOLLERR) || (events & EPOLLHUP))
{
display_exit(display);
return;
}
if (events & EPOLLIN)
{
ret = wl_display_dispatch(display->display);
if (ret == -1)
{
display_exit(display);
return;
}
}
if (events & EPOLLOUT)
{
ret = wl_display_flush(display->display);
if (ret == 0)
{
ep.events = EPOLLIN | EPOLLERR | EPOLLHUP;
ep.data.ptr = &display->dispatch_fd_task;
epoll_ctl(display->epoll_fd, EPOLL_CTL_MOD, display->display_fd, &ep);
}
else if (ret == -1 && errno != EAGAIN)
{
display_exit(display);
return;
}
}
}
UwacDisplay* UwacOpenDisplay(const char* name, UwacReturnCode* err)
{
UwacDisplay* ret = nullptr;
ret = (UwacDisplay*)xzalloc(sizeof(*ret));
if (!ret)
{
*err = UWAC_ERROR_NOMEMORY;
return nullptr;
}
wl_list_init(&ret->globals);
wl_list_init(&ret->seats);
wl_list_init(&ret->outputs);
wl_list_init(&ret->windows);
ret->display = wl_display_connect(name);
if (ret->display == nullptr)
{
char buffer[256] = WINPR_C_ARRAY_INIT;
(void)fprintf(stderr, "failed to connect to Wayland display %s: %s\n", name,
uwac_strerror(errno, buffer, sizeof(buffer)));
*err = UWAC_ERROR_UNABLE_TO_CONNECT;
goto out_free;
}
ret->epoll_fd = uwac_os_epoll_create_cloexec();
if (ret->epoll_fd < 0)
{
*err = UWAC_NOT_ENOUGH_RESOURCES;
goto out_disconnect;
}
ret->display_fd = wl_display_get_fd(ret->display);
ret->registry = wl_display_get_registry(ret->display);
if (!ret->registry)
{
*err = UWAC_ERROR_NOMEMORY;
goto out_close_epoll;
}
wl_registry_add_listener(ret->registry, &registry_listener, ret);
if ((wl_display_roundtrip(ret->display) < 0) || (wl_display_roundtrip(ret->display) < 0))
{
uwacErrorHandler(ret, UWAC_ERROR_UNABLE_TO_CONNECT,
"Failed to process Wayland connection: %m\n");
*err = UWAC_ERROR_UNABLE_TO_CONNECT;
goto out_free_registry;
}
ret->dispatch_fd_task.run = display_dispatch_events;
if (UwacDisplayWatchFd(ret, ret->display_fd, EPOLLIN | EPOLLERR | EPOLLHUP,
&ret->dispatch_fd_task) < 0)
{
uwacErrorHandler(ret, UWAC_ERROR_INTERNAL, "unable to watch display fd: %m\n");
*err = UWAC_ERROR_INTERNAL;
goto out_free_registry;
}
ret->running = true;
ret->last_error = *err = UWAC_SUCCESS;
return ret;
out_free_registry:
wl_registry_destroy(ret->registry);
out_close_epoll:
close(ret->epoll_fd);
out_disconnect:
wl_display_disconnect(ret->display);
out_free:
free(ret);
return nullptr;
}
int UwacDisplayDispatch(UwacDisplay* display, int timeout)
{
int ret = 0;
int count = 0;
UwacTask* task = nullptr;
struct epoll_event ep[16];
wl_display_dispatch_pending(display->display);
if (!display->running)
return 0;
ret = wl_display_flush(display->display);
if (ret < 0 && errno == EAGAIN)
{
ep[0].events = (EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP);
ep[0].data.ptr = &display->dispatch_fd_task;
epoll_ctl(display->epoll_fd, EPOLL_CTL_MOD, display->display_fd, &ep[0]);
}
else if (ret < 0)
{
return -1;
}
count = epoll_wait(display->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
for (int i = 0; i < count; i++)
{
task = ep[i].data.ptr;
task->run(task, ep[i].events);
}
return 1;
}
UwacReturnCode UwacDisplayGetLastError(const UwacDisplay* display)
{
return display->last_error;
}
UwacReturnCode UwacCloseDisplay(UwacDisplay** pdisplay)
{
UwacDisplay* display = nullptr;
UwacSeat* seat = nullptr;
UwacSeat* tmpSeat = nullptr;
UwacWindow* window = nullptr;
UwacWindow* tmpWindow = nullptr;
UwacOutput* output = nullptr;
UwacOutput* tmpOutput = nullptr;
UwacGlobal* global = nullptr;
UwacGlobal* tmpGlobal = nullptr;
assert(pdisplay);
display = *pdisplay;
if (!display)
return UWAC_ERROR_INVALID_DISPLAY;
/* destroy windows */
wl_list_for_each_safe(window, tmpWindow, &display->windows, link)
{
UwacDestroyWindow(&window);
}
/* destroy seats */
wl_list_for_each_safe(seat, tmpSeat, &display->seats, link)
{
UwacSeatDestroy(seat);
}
/* destroy output */
wl_list_for_each_safe(output, tmpOutput, &display->outputs, link)
{
UwacDestroyOutput(output);
}
/* destroy globals */
wl_list_for_each_safe(global, tmpGlobal, &display->globals, link)
{
UwacDestroyGlobal(global);
}
if (display->compositor)
wl_compositor_destroy(display->compositor);
if (display->keyboard_inhibit_manager)
zwp_keyboard_shortcuts_inhibit_manager_v1_destroy(display->keyboard_inhibit_manager);
if (display->deco_manager)
zxdg_decoration_manager_v1_destroy(display->deco_manager);
if (display->kde_deco_manager)
org_kde_kwin_server_decoration_manager_destroy(display->kde_deco_manager);
#ifdef BUILD_FULLSCREEN_SHELL
if (display->fullscreen_shell)
zwp_fullscreen_shell_v1_destroy(display->fullscreen_shell);
#endif
#ifdef BUILD_IVI
if (display->ivi_application)
ivi_application_destroy(display->ivi_application);
#endif
if (display->xdg_toplevel)
xdg_toplevel_destroy(display->xdg_toplevel);
if (display->xdg_base)
xdg_wm_base_destroy(display->xdg_base);
if (display->shell)
wl_shell_destroy(display->shell);
if (display->shm)
wl_shm_destroy(display->shm);
if (display->viewporter)
wp_viewporter_destroy(display->viewporter);
if (display->subcompositor)
wl_subcompositor_destroy(display->subcompositor);
if (display->data_device_manager)
wl_data_device_manager_destroy(display->data_device_manager);
free(display->shm_formats);
wl_registry_destroy(display->registry);
close(display->epoll_fd);
wl_display_disconnect(display->display);
/* cleanup the event queue */
while (display->push_queue)
{
UwacEventListItem* item = display->push_queue;
display->push_queue = item->tail;
free(item);
}
free(display);
*pdisplay = nullptr;
return UWAC_SUCCESS;
}
int UwacDisplayGetFd(UwacDisplay* display)
{
return display->epoll_fd;
}
static const char* errorStrings[] = {
"success",
"out of memory error",
"unable to connect to wayland display",
"invalid UWAC display",
"not enough resources",
"timed out",
"not found",
"closed connection",
"internal error",
};
const char* UwacErrorString(UwacReturnCode error)
{
if (error < UWAC_SUCCESS || error >= UWAC_ERROR_LAST)
return "invalid error code";
return errorStrings[error];
}
UwacReturnCode UwacDisplayQueryInterfaceVersion(const UwacDisplay* display, const char* name,
uint32_t* version)
{
const UwacGlobal* global = nullptr;
const UwacGlobal* tmp = nullptr;
if (!display)
return UWAC_ERROR_INVALID_DISPLAY;
wl_list_for_each_safe(global, tmp, &display->globals, link)
{
if (strcmp(global->interface, name) == 0)
{
if (version)
*version = global->version;
return UWAC_SUCCESS;
}
}
return UWAC_NOT_FOUND;
}
uint32_t UwacDisplayQueryGetNbShmFormats(UwacDisplay* display)
{
if (!display)
{
return 0;
}
if (!display->shm)
{
display->last_error = UWAC_NOT_FOUND;
return 0;
}
display->last_error = UWAC_SUCCESS;
return display->shm_formats_nb;
}
UwacReturnCode UwacDisplayQueryShmFormats(const UwacDisplay* display, enum wl_shm_format* formats,
int formats_size, int* filled)
{
if (!display)
return UWAC_ERROR_INVALID_DISPLAY;
*filled = min((int64_t)display->shm_formats_nb, formats_size);
memcpy(formats, (const void*)display->shm_formats, *filled * sizeof(enum wl_shm_format));
return UWAC_SUCCESS;
}
uint32_t UwacDisplayGetNbOutputs(const UwacDisplay* display)
{
return wl_list_length(&display->outputs);
}
const UwacOutput* UwacDisplayGetOutput(UwacDisplay* display, int index)
{
int i = 0;
int display_count = 0;
UwacOutput* ret = nullptr;
if (!display)
return nullptr;
display_count = wl_list_length(&display->outputs);
if (display_count <= index)
return nullptr;
wl_list_for_each(ret, &display->outputs, link)
{
if (i == index)
break;
i++;
}
if (!ret)
{
display->last_error = UWAC_NOT_FOUND;
return nullptr;
}
display->last_error = UWAC_SUCCESS;
return ret;
}
UwacReturnCode UwacOutputGetResolution(const UwacOutput* output, UwacSize* resolution)
{
if ((output->resolution.height <= 0) || (output->resolution.width <= 0))
return UWAC_ERROR_INTERNAL;
*resolution = output->resolution;
return UWAC_SUCCESS;
}
UwacReturnCode UwacOutputGetPosition(const UwacOutput* output, UwacPosition* pos)
{
*pos = output->position;
return UWAC_SUCCESS;
}
UwacEvent* UwacDisplayNewEvent(UwacDisplay* display, int type)
{
UwacEventListItem* ret = nullptr;
if (!display)
{
return nullptr;
}
ret = xzalloc(sizeof(UwacEventListItem));
if (!ret)
{
assert(uwacErrorHandler(display, UWAC_ERROR_NOMEMORY, "unable to allocate a '%s' event",
event_names[type]));
display->last_error = UWAC_ERROR_NOMEMORY;
return nullptr;
}
ret->event.type = type;
ret->tail = display->push_queue;
if (ret->tail)
ret->tail->head = ret;
else
display->pop_queue = ret;
display->push_queue = ret;
return &ret->event;
}
bool UwacHasEvent(UwacDisplay* display)
{
return display->pop_queue != nullptr;
}
UwacReturnCode UwacNextEvent(UwacDisplay* display, UwacEvent* event)
{
UwacEventListItem* prevItem = nullptr;
int ret = 0;
if (!display)
return UWAC_ERROR_INVALID_DISPLAY;
while (!display->pop_queue)
{
ret = UwacDisplayDispatch(display, 1 * 1000);
if (ret < 0)
return UWAC_ERROR_INTERNAL;
else if (ret == 0)
return UWAC_ERROR_CLOSED;
}
prevItem = display->pop_queue->head;
*event = display->pop_queue->event;
free(display->pop_queue);
display->pop_queue = prevItem;
if (prevItem)
prevItem->tail = nullptr;
else
display->push_queue = nullptr;
return UWAC_SUCCESS;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,300 @@
/*
* Copyright © 2012 Collabora, Ltd.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
/*
* This file is an adaptation of src/wayland-os.h from the wayland project and
* shared/os-compatiblity.h from the weston project.
*
* Functions have been renamed just to prevent name clashes.
*/
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreserved-id-macro"
#endif
#define _GNU_SOURCE // NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
#if defined(__FreeBSD__) || defined(__DragonFly__)
#define USE_SHM
#endif
/* uClibc and uClibc-ng don't provide O_TMPFILE */
#if !defined(O_TMPFILE) && !defined(__FreeBSD__)
#define O_TMPFILE (020000000 | O_DIRECTORY)
#endif
#include <sys/types.h>
#include <sys/socket.h>
#ifdef USE_SHM
#include <sys/mman.h>
#endif
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/stat.h>
#include <winpr/wtypes.h>
#include <uwac/config.h>
#include "uwac-os.h"
#include "uwac-utils.h"
static int set_cloexec_or_close(int fd)
{
long flags = 0;
if (fd == -1)
return -1;
flags = fcntl(fd, F_GETFD);
if (flags == -1)
goto err;
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
goto err;
return fd;
err:
close(fd);
return -1;
}
int uwac_os_socket_cloexec(int domain, int type, int protocol)
{
int fd = 0;
fd = socket(domain, type | SOCK_CLOEXEC, protocol);
if (fd >= 0)
return fd;
if (errno != EINVAL)
return -1;
fd = socket(domain, type, protocol);
return set_cloexec_or_close(fd);
}
int uwac_os_dupfd_cloexec(int fd, long minfd)
{
int newfd = 0;
newfd = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
if (newfd >= 0)
return newfd;
if (errno != EINVAL)
return -1;
newfd = fcntl(fd, F_DUPFD, minfd);
return set_cloexec_or_close(newfd);
}
static ssize_t recvmsg_cloexec_fallback(int sockfd, struct msghdr* msg, int flags)
{
ssize_t len = 0;
struct cmsghdr* cmsg = nullptr;
unsigned char* data = nullptr;
int* end = nullptr;
len = recvmsg(sockfd, msg, flags);
if (len == -1)
return -1;
if (!msg->msg_control || msg->msg_controllen == 0)
return len;
cmsg = CMSG_FIRSTHDR(msg);
for (; cmsg != nullptr; cmsg = CMSG_NXTHDR(msg, cmsg))
{
if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
continue;
data = CMSG_DATA(cmsg);
end = (int*)(data + cmsg->cmsg_len - CMSG_LEN(0));
for (int* fd = (int*)data; fd < end; ++fd)
*fd = set_cloexec_or_close(*fd);
}
return len;
}
ssize_t uwac_os_recvmsg_cloexec(int sockfd, struct msghdr* msg, int flags)
{
ssize_t len = 0;
len = recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC);
if (len >= 0)
return len;
if (errno != EINVAL)
return -1;
return recvmsg_cloexec_fallback(sockfd, msg, flags);
}
int uwac_os_epoll_create_cloexec(void)
{
int fd = 0;
#ifdef EPOLL_CLOEXEC
fd = epoll_create1(EPOLL_CLOEXEC);
if (fd >= 0)
return fd;
if (errno != EINVAL)
return -1;
#endif
fd = epoll_create(1);
return set_cloexec_or_close(fd);
}
static int secure_mkstemp(char* tmpname)
{
const mode_t mask = umask(S_IRWXU);
int fd = mkstemp(tmpname);
(void)umask(mask);
return fd;
}
static int create_tmpfile_cloexec(char* tmpname)
{
int fd = 0;
#ifdef USE_SHM
fd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0600);
#elif defined(UWAC_HAVE_MKOSTEMP)
fd = mkostemp(tmpname, O_CLOEXEC);
if (fd >= 0)
unlink(tmpname);
#else
fd = secure_mkstemp(tmpname);
if (fd >= 0)
{
fd = set_cloexec_or_close(fd);
unlink(tmpname);
}
#endif
return fd;
}
/*
* Create a new, unique, anonymous file of the given size, and
* return the file descriptor for it. The file descriptor is set
* CLOEXEC. The file is immediately suitable for mmap()'ing
* the given size at offset zero.
*
* The file should not have a permanent backing store like a disk,
* but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
*
* The file name is deleted from the file system.
*
* The file is suitable for buffer sharing between processes by
* transmitting the file descriptor over Unix sockets using the
* SCM_RIGHTS methods.
*
* If the C library implements posix_fallocate(), it is used to
* guarantee that disk space is available for the file at the
* given size. If disk space is insufficient, errno is set to ENOSPC.
* If posix_fallocate() is not supported, program may receive
* SIGBUS on accessing mmap()'ed file contents instead.
*/
int uwac_create_anonymous_file(off_t size)
{
static const char template[] = "/weston-shared-XXXXXX";
size_t length = 0;
char* name = nullptr;
int fd = 0;
int ret = 0;
// NOLINTNEXTLINE(concurrency-mt-unsafe)
const char* path = getenv("XDG_RUNTIME_DIR");
if (!path)
{
errno = ENOENT;
return -1;
}
#ifdef O_TMPFILE
fd = open(path, O_TMPFILE | O_RDWR | O_EXCL, 0600);
#else
/*
* Some platforms (e.g. FreeBSD) won't support O_TMPFILE and can't
* reasonably emulate it at first blush. Opt to make them rely on
* the create_tmpfile_cloexec() path instead.
*/
fd = -1;
#endif
if (fd < 0)
{
length = strlen(path) + sizeof(template);
name = xmalloc(length);
if (!name)
return -1;
(void)snprintf(name, length, "%s%s", path, template);
fd = create_tmpfile_cloexec(name);
free(name);
}
if (fd < 0)
return -1;
#ifdef UWAC_HAVE_POSIX_FALLOCATE
ret = posix_fallocate(fd, 0, size);
if (ret != 0)
{
close(fd);
errno = ret;
return -1;
}
#else
ret = ftruncate(fd, size);
if (ret < 0)
{
close(fd);
return -1;
}
#endif
return fd;
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright © 2012 Collabora, Ltd.
* Copyright © 2014 David FORT <contact@hardening-consulting.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
/*
* This file is an adaptation of src/wayland-os.h from the wayland project and
* shared/os-compatiblity.h from the weston project.
*
* Functions have been renamed just to prevent name clashes.
*/
#ifndef UWAC_OS_H
#define UWAC_OS_H
#include <sys/socket.h>
int uwac_os_socket_cloexec(int domain, int type, int protocol);
int uwac_os_dupfd_cloexec(int fd, long minfd);
ssize_t uwac_os_recvmsg_cloexec(int sockfd, struct msghdr* msg, int flags);
int uwac_os_epoll_create_cloexec(void);
int uwac_create_anonymous_file(off_t size);
#endif /* UWAC_OS_H */

View File

@@ -0,0 +1,183 @@
/*
* Copyright © 2014 David FORT <contact@hardening-consulting.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "uwac-priv.h"
#include "uwac-utils.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define TARGET_OUTPUT_INTERFACE 2U
static bool dupstr(char** dst, const char* src)
{
assert(dst);
free(*dst);
*dst = nullptr;
if (!src)
return true;
*dst = strdup(src);
return *dst != nullptr;
}
static void output_handle_geometry(void* data, struct wl_output* wl_output, int x, int y,
int physical_width, int physical_height, int subpixel,
const char* make, const char* model, int transform)
{
UwacOutput* output = data;
assert(output);
output->position.x = x;
output->position.y = y;
output->transform = transform;
if (!dupstr(&output->make, make))
{
assert(uwacErrorHandler(output->display, UWAC_ERROR_NOMEMORY, "%s: unable to strdup make\n",
__func__));
}
if (!dupstr(&output->model, model))
{
assert(uwacErrorHandler(output->display, UWAC_ERROR_NOMEMORY,
"%s: unable to strdup model\n", __func__));
}
UwacEvent* event = UwacDisplayNewEvent(output->display, UWAC_EVENT_OUTPUT_GEOMETRY);
event->output_geometry.output = output;
event->output_geometry.x = x;
event->output_geometry.y = y;
event->output_geometry.physical_width = physical_width;
event->output_geometry.physical_height = physical_height;
event->output_geometry.subpixel = subpixel;
event->output_geometry.make = output->make;
event->output_geometry.model = output->model;
event->output_geometry.transform = transform;
}
static void output_handle_done(void* data, struct wl_output* wl_output)
{
UwacOutput* output = data;
assert(output);
output->doneReceived = true;
}
static void output_handle_scale(void* data, struct wl_output* wl_output, int32_t scale)
{
UwacOutput* output = data;
assert(output);
output->scale = scale;
if (scale > output->display->actual_scale)
output->display->actual_scale = scale;
}
static void output_handle_name(void* data, struct wl_output* wl_output, const char* name)
{
UwacOutput* output = data;
assert(output);
if (!dupstr(&output->name, name))
{
assert(uwacErrorHandler(output->display, UWAC_ERROR_NOMEMORY, "%s: unable to strdup make\n",
__func__));
}
}
static void output_handle_description(void* data, struct wl_output* wl_output,
const char* description)
{
UwacOutput* output = data;
assert(output);
if (!dupstr(&output->description, description))
{
assert(uwacErrorHandler(output->display, UWAC_ERROR_NOMEMORY, "%s: unable to strdup make\n",
__func__));
}
}
static void output_handle_mode(void* data, struct wl_output* wl_output, uint32_t flags, int width,
int height, int refresh)
{
UwacOutput* output = data;
assert(output);
// UwacDisplay *display = output->display;
if (output->doneNeeded && output->doneReceived)
{
/* TODO: we should clear the mode list */
}
if (flags & WL_OUTPUT_MODE_CURRENT)
{
output->resolution.width = width;
output->resolution.height = height;
/* output->allocation.width = width;
output->allocation.height = height;
if (display->output_configure_handler)
(*display->output_configure_handler)(
output, display->user_data);*/
}
}
static const struct wl_output_listener output_listener = {
output_handle_geometry, output_handle_mode, output_handle_done,
output_handle_scale, output_handle_name, output_handle_description
};
UwacOutput* UwacCreateOutput(UwacDisplay* d, uint32_t id, uint32_t version)
{
UwacOutput* o = xzalloc(sizeof *o);
if (!o)
return nullptr;
o->display = d;
o->server_output_id = id;
o->doneNeeded = (version > 1);
o->doneReceived = false;
o->output = wl_registry_bind(d->registry, id, &wl_output_interface,
min(TARGET_OUTPUT_INTERFACE, version));
wl_output_add_listener(o->output, &output_listener, o);
wl_list_insert(d->outputs.prev, &o->link);
return o;
}
int UwacDestroyOutput(UwacOutput* output)
{
if (!output)
return UWAC_SUCCESS;
free(output->make);
free(output->model);
free(output->name);
free(output->description);
wl_output_destroy(output->output);
wl_list_remove(&output->link);
free(output);
return UWAC_SUCCESS;
}

View File

@@ -0,0 +1,291 @@
/*
* Copyright © 2014 David FORT <contact@hardening-consulting.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef UWAC_PRIV_H_
#define UWAC_PRIV_H_
#include <uwac/config.h>
#include <stdbool.h>
#include <wayland-client.h>
#include "xdg-shell-client-protocol.h"
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
#include "xdg-decoration-unstable-v1-client-protocol.h"
#include "server-decoration-client-protocol.h"
#include "viewporter-client-protocol.h"
#ifdef BUILD_IVI
#include "ivi-application-client-protocol.h"
#endif
#ifdef BUILD_FULLSCREEN_SHELL
#include "fullscreen-shell-unstable-v1-client-protocol.h"
#endif
#ifdef UWAC_HAVE_PIXMAN_REGION
#include <pixman-1/pixman.h>
#else
#include <freerdp/codec/region.h>
#endif
#include <xkbcommon/xkbcommon.h>
#include <uwac/uwac.h>
extern UwacErrorHandler uwacErrorHandler;
typedef struct uwac_task UwacTask;
/** @brief task struct
*/
struct uwac_task
{
void (*run)(UwacTask* task, uint32_t events);
struct wl_list link;
};
/** @brief a global registry object
*/
struct uwac_global
{
uint32_t name;
char* interface;
uint32_t version;
struct wl_list link;
};
typedef struct uwac_global UwacGlobal;
struct uwac_event_list_item;
typedef struct uwac_event_list_item UwacEventListItem;
/** @brief double linked list element
*/
struct uwac_event_list_item
{
UwacEvent event;
UwacEventListItem *tail, *head;
};
/** @brief main connection object to a wayland display
*/
struct uwac_display
{
struct wl_list globals;
struct wl_display* display;
struct wl_registry* registry;
struct wl_compositor* compositor;
struct wp_viewporter* viewporter;
struct wl_subcompositor* subcompositor;
struct wl_shell* shell;
struct xdg_toplevel* xdg_toplevel;
struct xdg_wm_base* xdg_base;
struct wl_data_device_manager* devicemanager;
struct zwp_keyboard_shortcuts_inhibit_manager_v1* keyboard_inhibit_manager;
struct zxdg_decoration_manager_v1* deco_manager;
struct org_kde_kwin_server_decoration_manager* kde_deco_manager;
#ifdef BUILD_IVI
struct ivi_application* ivi_application;
#endif
#ifdef BUILD_FULLSCREEN_SHELL
struct zwp_fullscreen_shell_v1* fullscreen_shell;
#endif
struct wl_shm* shm;
enum wl_shm_format* shm_formats;
uint32_t shm_formats_nb;
bool has_rgb565;
struct wl_data_device_manager* data_device_manager;
struct text_cursor_position* text_cursor_position;
struct workspace_manager* workspace_manager;
struct wl_list seats;
int display_fd;
UwacReturnCode last_error;
uint32_t display_fd_events;
int epoll_fd;
bool running;
UwacTask dispatch_fd_task;
uint32_t serial;
uint32_t pointer_focus_serial;
int actual_scale;
struct wl_list windows;
struct wl_list outputs;
UwacEventListItem *push_queue, *pop_queue;
};
/** @brief an output on a wayland display */
struct uwac_output
{
UwacDisplay* display;
bool doneNeeded;
bool doneReceived;
UwacPosition position;
UwacSize resolution;
int transform;
int scale;
char* make;
char* model;
uint32_t server_output_id;
struct wl_output* output;
struct wl_list link;
char* name;
char* description;
};
/** @brief a seat attached to a wayland display */
struct uwac_seat
{
UwacDisplay* display;
char* name;
struct wl_seat* seat;
uint32_t seat_id;
uint32_t seat_version;
struct wl_data_device* data_device;
struct wl_data_source* data_source;
struct wl_pointer* pointer;
struct wl_surface* pointer_surface;
struct wl_cursor_image* pointer_image;
struct wl_cursor_theme* cursor_theme;
struct wl_cursor* default_cursor;
void* pointer_data;
size_t pointer_size;
int pointer_type;
struct wl_keyboard* keyboard;
struct wl_touch* touch;
struct wl_data_offer* offer;
struct xkb_context* xkb_context;
struct zwp_keyboard_shortcuts_inhibitor_v1* keyboard_inhibitor;
struct
{
struct xkb_keymap* keymap;
struct xkb_state* state;
xkb_mod_mask_t control_mask;
xkb_mod_mask_t alt_mask;
xkb_mod_mask_t shift_mask;
xkb_mod_mask_t caps_mask;
xkb_mod_mask_t num_mask;
} xkb;
uint32_t modifiers;
int32_t repeat_rate_sec, repeat_rate_nsec;
int32_t repeat_delay_sec, repeat_delay_nsec;
uint32_t repeat_sym, repeat_key, repeat_time;
struct wl_array pressed_keys;
UwacWindow* pointer_focus;
UwacWindow* keyboard_focus;
UwacWindow* touch_focus;
bool touch_frame_started;
int repeat_timer_fd;
UwacTask repeat_task;
double sx, sy;
struct wl_list link;
void* data_context;
UwacDataTransferHandler transfer_data;
UwacCancelDataTransferHandler cancel_data;
bool ignore_announcement;
};
/** @brief a buffer used for drawing a surface frame */
struct uwac_buffer
{
bool used;
bool dirty;
#ifdef UWAC_HAVE_PIXMAN_REGION
pixman_region32_t damage;
#else
REGION16 damage;
#endif
struct wl_buffer* wayland_buffer;
void* data;
size_t size;
};
typedef struct uwac_buffer UwacBuffer;
/** @brief a window */
struct uwac_window
{
UwacDisplay* display;
int width, height, stride;
int surfaceStates;
enum wl_shm_format format;
size_t nbuffers;
UwacBuffer* buffers;
struct wl_region* opaque_region;
struct wl_region* input_region;
ssize_t drawingBufferIdx;
ssize_t pendingBufferIdx;
struct wl_surface* surface;
struct wp_viewport* viewport;
struct wl_shell_surface* shell_surface;
struct xdg_surface* xdg_surface;
struct xdg_toplevel* xdg_toplevel;
struct zxdg_toplevel_decoration_v1* deco;
struct org_kde_kwin_server_decoration* kde_deco;
#ifdef BUILD_IVI
struct ivi_surface* ivi_surface;
#endif
struct wl_list link;
uint32_t pointer_enter_serial;
uint32_t pointer_cursor_serial;
int pointer_current_cursor;
};
/**@brief data to pass to wl_buffer release listener */
struct uwac_buffer_release_data
{
UwacWindow* window;
size_t bufferIdx;
};
typedef struct uwac_buffer_release_data UwacBufferReleaseData;
/* in uwa-display.c */
UwacEvent* UwacDisplayNewEvent(UwacDisplay* d, int type);
int UwacDisplayWatchFd(UwacDisplay* display, int fd, uint32_t events, UwacTask* task);
/* in uwac-input.c */
UwacSeat* UwacSeatNew(UwacDisplay* d, uint32_t id, uint32_t version);
void UwacSeatDestroy(UwacSeat* s);
/* in uwac-output.c */
UwacOutput* UwacCreateOutput(UwacDisplay* d, uint32_t id, uint32_t version);
int UwacDestroyOutput(UwacOutput* output);
UwacReturnCode UwacSeatRegisterClipboard(UwacSeat* s);
#endif /* UWAC_PRIV_H_ */

View File

@@ -0,0 +1,107 @@
/*
* Copyright © 2015 David FORT <contact@hardening-consulting.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include <wayland-util.h>
#include <string.h>
#include <uwac/uwac-tools.h>
#include <winpr/wtypes.h>
struct uwac_touch_automata
{
struct wl_array tp;
};
void UwacTouchAutomataInit(UwacTouchAutomata* automata)
{
wl_array_init(&automata->tp);
}
void UwacTouchAutomataReset(UwacTouchAutomata* automata)
{
automata->tp.size = 0;
}
bool UwacTouchAutomataInjectEvent(UwacTouchAutomata* automata, UwacEvent* event)
{
UwacTouchPoint* tp = nullptr;
switch (event->type)
{
case UWAC_EVENT_TOUCH_FRAME_BEGIN:
break;
case UWAC_EVENT_TOUCH_UP:
{
UwacTouchUp* touchUp = &event->touchUp;
size_t toMove = automata->tp.size - sizeof(UwacTouchPoint);
wl_array_for_each(tp, &automata->tp)
{
if ((int64_t)tp->id == touchUp->id)
{
if (toMove)
memmove(tp, tp + 1, toMove);
return true;
}
toMove -= sizeof(UwacTouchPoint);
}
break;
}
case UWAC_EVENT_TOUCH_DOWN:
{
UwacTouchDown* touchDown = &event->touchDown;
wl_array_for_each(tp, &automata->tp)
{
if ((int64_t)tp->id == touchDown->id)
{
tp->x = touchDown->x;
tp->y = touchDown->y;
return true;
}
}
tp = wl_array_add(&automata->tp, sizeof(UwacTouchPoint));
if (!tp)
return false;
if (touchDown->id < 0)
return false;
tp->id = (uint32_t)touchDown->id;
tp->x = touchDown->x;
tp->y = touchDown->y;
break;
}
case UWAC_EVENT_TOUCH_FRAME_END:
break;
default:
break;
}
return true;
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright © 2012 Collabora, Ltd.
* Copyright © 2008 Kristian Høgsberg
* Copyright © 2014 David FORT <contact@hardening-consulting.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include <uwac/config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <winpr/wtypes.h>
#include "uwac-utils.h"
/*
* This part is an adaptation of client/window.c from the weston project.
*/
static void* fail_on_null(void* p)
{
if (p == nullptr)
{
(void)fprintf(stderr, "out of memory\n");
// NOLINTNEXTLINE(concurrency-mt-unsafe)
exit(EXIT_FAILURE);
}
return p;
}
void* xmalloc(size_t s)
{
return fail_on_null(malloc(s));
}
void* xzalloc(size_t s)
{
return fail_on_null(zalloc(s));
}
char* xstrdup(const char* s)
{
return fail_on_null(strdup(s));
}
void* xrealloc(void* p, size_t s)
{
return fail_on_null(realloc(p, s));
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright © 2014 David FORT <contact@hardening-consulting.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef UWAC_UTILS_H_
#define UWAC_UTILS_H_
#include <stdlib.h>
#include <string.h>
#include <uwac/config.h>
#define min(a, b) (a) < (b) ? (a) : (b)
#define container_of(ptr, type, member) (type*)((char*)(ptr)-offsetof(type, member))
#define ARRAY_LENGTH(a) (sizeof(a) / sizeof(a)[0])
void* xmalloc(size_t s);
static inline void* zalloc(size_t size)
{
return calloc(1, size);
}
void* xzalloc(size_t s);
char* xstrdup(const char* s);
void* xrealloc(void* p, size_t s);
static inline char* uwac_strerror(int dw, char* dmsg, size_t size)
{
#ifdef __STDC_LIB_EXT1__
(void)strerror_s(dw, dmsg, size);
#elif defined(UWAC_HAVE_STRERROR_R)
(void)strerror_r(dw, dmsg, size);
#else
(void)_snprintf(dmsg, size, "%s", strerror(dw));
#endif
return dmsg;
}
#endif /* UWAC_UTILS_H_ */

View File

@@ -0,0 +1,921 @@
/*
* Copyright © 2014 David FORT <contact@hardening-consulting.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <sys/mman.h>
#include <errno.h>
#include "uwac-priv.h"
#include "uwac-utils.h"
#include "uwac-os.h"
#include <uwac/config.h>
#include <winpr/cast.h>
#define UWAC_INITIAL_BUFFERS 3ull
static int bppFromShmFormat(enum wl_shm_format format)
{
switch (format)
{
case WL_SHM_FORMAT_ARGB8888:
case WL_SHM_FORMAT_XRGB8888:
default:
return 4;
}
}
static void buffer_release(void* data, struct wl_buffer* buffer)
{
UwacBufferReleaseData* releaseData = data;
UwacBuffer* uwacBuffer = &releaseData->window->buffers[releaseData->bufferIdx];
uwacBuffer->used = false;
}
static const struct wl_buffer_listener buffer_listener = { buffer_release };
static void UwacWindowDestroyBuffers(UwacWindow* w)
{
for (size_t i = 0; i < w->nbuffers; i++)
{
UwacBuffer* buffer = &w->buffers[i];
#ifdef UWAC_HAVE_PIXMAN_REGION
pixman_region32_fini(&buffer->damage);
#else
region16_uninit(&buffer->damage);
#endif
UwacBufferReleaseData* releaseData =
(UwacBufferReleaseData*)wl_buffer_get_user_data(buffer->wayland_buffer);
wl_buffer_destroy(buffer->wayland_buffer);
free(releaseData);
munmap(buffer->data, buffer->size);
}
w->nbuffers = 0;
free(w->buffers);
w->buffers = nullptr;
}
static int UwacWindowShmAllocBuffers(UwacWindow* w, uint64_t nbuffers, uint64_t allocSize,
uint32_t width, uint32_t height, enum wl_shm_format format);
static void xdg_handle_toplevel_configure(void* data, struct xdg_toplevel* xdg_toplevel,
int32_t width, int32_t height, struct wl_array* states)
{
UwacWindow* window = (UwacWindow*)data;
int scale = window->display->actual_scale;
int32_t actual_width = width;
int32_t actual_height = height;
width *= scale;
height *= scale;
UwacConfigureEvent* event = nullptr;
int ret = 0;
int surfaceState = 0;
enum xdg_toplevel_state* state = nullptr;
surfaceState = 0;
wl_array_for_each(state, states)
{
switch (*state)
{
case XDG_TOPLEVEL_STATE_MAXIMIZED:
surfaceState |= UWAC_WINDOW_MAXIMIZED;
break;
case XDG_TOPLEVEL_STATE_FULLSCREEN:
surfaceState |= UWAC_WINDOW_FULLSCREEN;
break;
case XDG_TOPLEVEL_STATE_ACTIVATED:
surfaceState |= UWAC_WINDOW_ACTIVATED;
break;
case XDG_TOPLEVEL_STATE_RESIZING:
surfaceState |= UWAC_WINDOW_RESIZING;
break;
default:
break;
}
}
window->surfaceStates = surfaceState;
event = (UwacConfigureEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE);
if (!event)
{
assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY,
"failed to allocate a configure event\n"));
return;
}
event->window = window;
event->states = surfaceState;
if ((width > 0 && height > 0) && (width != window->width || height != window->height))
{
event->width = width;
event->height = height;
UwacWindowDestroyBuffers(window);
window->width = width;
window->stride = width * bppFromShmFormat(window->format);
window->height = height;
ret =
UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, 1ull * window->stride * height,
width, height, window->format);
if (ret != UWAC_SUCCESS)
{
assert(
uwacErrorHandler(window->display, ret, "failed to reallocate a wayland buffers\n"));
window->drawingBufferIdx = window->pendingBufferIdx = -1;
return;
}
window->drawingBufferIdx = 0;
if (window->pendingBufferIdx != -1)
window->pendingBufferIdx = window->drawingBufferIdx;
if (window->viewport)
{
wp_viewport_set_source(window->viewport, wl_fixed_from_int(0), wl_fixed_from_int(0),
wl_fixed_from_int(actual_width),
wl_fixed_from_int(actual_height));
wp_viewport_set_destination(window->viewport, actual_width, actual_height);
}
}
else
{
event->width = window->width;
event->height = window->height;
}
}
static void xdg_handle_toplevel_close(void* data, struct xdg_toplevel* xdg_toplevel)
{
UwacCloseEvent* event = nullptr;
UwacWindow* window = (UwacWindow*)data;
event = (UwacCloseEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_CLOSE);
if (!event)
{
assert(uwacErrorHandler(window->display, UWAC_ERROR_INTERNAL,
"failed to allocate a close event\n"));
return;
}
event->window = window;
}
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
xdg_handle_toplevel_configure,
xdg_handle_toplevel_close,
};
static void xdg_handle_surface_configure(void* data, struct xdg_surface* xdg_surface,
uint32_t serial)
{
xdg_surface_ack_configure(xdg_surface, serial);
}
static const struct xdg_surface_listener xdg_surface_listener = {
.configure = xdg_handle_surface_configure,
};
#if BUILD_IVI
static void ivi_handle_configure(void* data, struct ivi_surface* surface, int32_t width,
int32_t height)
{
UwacWindow* window = (UwacWindow*)data;
UwacConfigureEvent* event = nullptr;
int ret = 0;
event = (UwacConfigureEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE);
if (!event)
{
assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY,
"failed to allocate a configure event\n"));
return;
}
event->window = window;
event->states = 0;
if (width && height)
{
event->width = width;
event->height = height;
UwacWindowDestroyBuffers(window);
window->width = width;
window->stride = width * bppFromShmFormat(window->format);
window->height = height;
ret =
UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, 1ull * window->stride * height,
width, height, window->format);
if (ret != UWAC_SUCCESS)
{
assert(
uwacErrorHandler(window->display, ret, "failed to reallocate a wayland buffers\n"));
window->drawingBufferIdx = window->pendingBufferIdx = -1;
return;
}
window->drawingBufferIdx = 0;
if (window->pendingBufferIdx != -1)
window->pendingBufferIdx = window->drawingBufferIdx;
}
else
{
event->width = window->width;
event->height = window->height;
}
}
static const struct ivi_surface_listener ivi_surface_listener = {
ivi_handle_configure,
};
#endif
static void shell_ping(void* data, struct wl_shell_surface* surface, uint32_t serial)
{
wl_shell_surface_pong(surface, serial);
}
static void shell_configure(void* data, struct wl_shell_surface* surface, uint32_t edges,
int32_t width, int32_t height)
{
UwacWindow* window = (UwacWindow*)data;
UwacConfigureEvent* event = nullptr;
int ret = 0;
event = (UwacConfigureEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE);
if (!event)
{
assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY,
"failed to allocate a configure event\n"));
return;
}
event->window = window;
event->states = 0;
if (width && height)
{
event->width = width;
event->height = height;
UwacWindowDestroyBuffers(window);
window->width = width;
window->stride = width * bppFromShmFormat(window->format);
window->height = height;
ret =
UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, 1ull * window->stride * height,
width, height, window->format);
if (ret != UWAC_SUCCESS)
{
assert(
uwacErrorHandler(window->display, ret, "failed to reallocate a wayland buffers\n"));
window->drawingBufferIdx = window->pendingBufferIdx = -1;
return;
}
window->drawingBufferIdx = 0;
if (window->pendingBufferIdx != -1)
window->pendingBufferIdx = window->drawingBufferIdx;
}
else
{
event->width = window->width;
event->height = window->height;
}
}
static void shell_popup_done(void* data, struct wl_shell_surface* surface)
{
}
static const struct wl_shell_surface_listener shell_listener = { shell_ping, shell_configure,
shell_popup_done };
int UwacWindowShmAllocBuffers(UwacWindow* w, uint64_t nbuffers, uint64_t allocSize, uint32_t width,
uint32_t height, enum wl_shm_format format)
{
int ret = UWAC_SUCCESS;
int fd = 0;
void* data = nullptr;
struct wl_shm_pool* pool = nullptr;
if ((width > INT32_MAX) || (height > INT32_MAX))
return UWAC_ERROR_NOMEMORY;
const int64_t pagesize = sysconf(_SC_PAGESIZE);
if (pagesize <= 0)
return UWAC_ERROR_NOMEMORY;
/* round up to a multiple of PAGESIZE to page align data for each buffer */
const uint64_t test = (1ull * allocSize + (size_t)pagesize - 1ull) & ~((size_t)pagesize - 1);
if (test > INT64_MAX)
return UWAC_ERROR_NOMEMORY;
allocSize = test;
UwacBuffer* newBuffers =
xrealloc(w->buffers, (0ull + w->nbuffers + nbuffers) * sizeof(UwacBuffer));
if (!newBuffers)
return UWAC_ERROR_NOMEMORY;
w->buffers = newBuffers;
memset(w->buffers + w->nbuffers, 0, sizeof(UwacBuffer) * nbuffers);
const size_t allocbuffersize = 1ull * allocSize * nbuffers;
if (allocbuffersize > INT32_MAX)
return UWAC_ERROR_NOMEMORY;
fd = uwac_create_anonymous_file(WINPR_ASSERTING_INT_CAST(off_t, allocbuffersize));
if (fd < 0)
{
return UWAC_ERROR_INTERNAL;
}
data = mmap(nullptr, allocbuffersize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED)
{
ret = UWAC_ERROR_NOMEMORY;
goto error_mmap;
}
pool = wl_shm_create_pool(w->display->shm, fd, (int32_t)allocbuffersize);
if (!pool)
{
munmap(data, allocbuffersize);
ret = UWAC_ERROR_NOMEMORY;
goto error_mmap;
}
for (uint64_t i = 0; i < nbuffers; i++)
{
const size_t idx = (size_t)i;
const size_t bufferIdx = w->nbuffers + idx;
UwacBuffer* buffer = &w->buffers[bufferIdx];
#ifdef UWAC_HAVE_PIXMAN_REGION
pixman_region32_init(&buffer->damage);
#else
region16_init(&buffer->damage);
#endif
const size_t offset = allocSize * idx;
if (offset > INT32_MAX)
goto error_mmap;
buffer->data = &((char*)data)[allocSize * idx];
buffer->size = allocSize;
buffer->wayland_buffer = wl_shm_pool_create_buffer(pool, (int32_t)offset, (int32_t)width,
(int32_t)height, w->stride, format);
UwacBufferReleaseData* listener_data = xmalloc(sizeof(UwacBufferReleaseData));
listener_data->window = w;
listener_data->bufferIdx = bufferIdx;
wl_buffer_add_listener(buffer->wayland_buffer, &buffer_listener, listener_data);
}
wl_shm_pool_destroy(pool);
w->nbuffers += nbuffers;
error_mmap:
close(fd);
return ret;
}
static UwacBuffer* UwacWindowFindFreeBuffer(UwacWindow* w, ssize_t* index)
{
int ret = 0;
if (index)
*index = -1;
size_t i = 0;
for (; i < w->nbuffers; i++)
{
if (!w->buffers[i].used)
{
w->buffers[i].used = true;
if (index)
*index = WINPR_ASSERTING_INT_CAST(ssize_t, i);
return &w->buffers[i];
}
}
ret = UwacWindowShmAllocBuffers(w, 2, 1ull * w->stride * w->height, w->width, w->height,
w->format);
if (ret != UWAC_SUCCESS)
{
w->display->last_error = ret;
return nullptr;
}
w->buffers[i].used = true;
if (index)
*index = WINPR_ASSERTING_INT_CAST(ssize_t, i);
return &w->buffers[i];
}
static UwacReturnCode UwacWindowSetDecorations(UwacWindow* w)
{
if (!w || !w->display)
return UWAC_ERROR_INTERNAL;
if (w->display->deco_manager)
{
w->deco = zxdg_decoration_manager_v1_get_toplevel_decoration(w->display->deco_manager,
w->xdg_toplevel);
if (!w->deco)
{
uwacErrorHandler(w->display, UWAC_NOT_FOUND,
"Current window manager does not allow decorating with SSD");
}
else
zxdg_toplevel_decoration_v1_set_mode(w->deco,
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
}
else if (w->display->kde_deco_manager)
{
w->kde_deco =
org_kde_kwin_server_decoration_manager_create(w->display->kde_deco_manager, w->surface);
if (!w->kde_deco)
{
uwacErrorHandler(w->display, UWAC_NOT_FOUND,
"Current window manager does not allow decorating with SSD");
}
else
org_kde_kwin_server_decoration_request_mode(w->kde_deco,
ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER);
}
return UWAC_SUCCESS;
}
UwacWindow* UwacCreateWindowShm(UwacDisplay* display, uint32_t width, uint32_t height,
enum wl_shm_format format)
{
UwacWindow* w = nullptr;
int ret = 0;
if (!display)
{
return nullptr;
}
w = xzalloc(sizeof(*w));
if (!w)
{
display->last_error = UWAC_ERROR_NOMEMORY;
return nullptr;
}
w->display = display;
w->format = format;
w->width = WINPR_ASSERTING_INT_CAST(int32_t, width);
w->height = WINPR_ASSERTING_INT_CAST(int32_t, height);
w->stride = WINPR_ASSERTING_INT_CAST(int32_t, width* bppFromShmFormat(format));
const size_t allocSize = 1ULL * w->stride * height;
ret = UwacWindowShmAllocBuffers(w, UWAC_INITIAL_BUFFERS, allocSize, width, height, format);
if (ret != UWAC_SUCCESS)
{
display->last_error = ret;
goto out_error_free;
}
w->buffers[0].used = true;
w->drawingBufferIdx = 0;
w->pendingBufferIdx = -1;
w->surface = wl_compositor_create_surface(display->compositor);
if (!w->surface)
{
display->last_error = UWAC_ERROR_NOMEMORY;
goto out_error_surface;
}
wl_surface_set_user_data(w->surface, w);
#if BUILD_IVI
uint32_t ivi_surface_id = 1;
// NOLINTNEXTLINE(concurrency-mt-unsafe)
char* env = getenv("IVI_SURFACE_ID");
if (env)
{
unsigned long val = 0;
char* endp = nullptr;
errno = 0;
val = strtoul(env, &endp, 10);
if (!errno && val != 0 && val != UINT32_MAX)
ivi_surface_id = val;
}
if (display->ivi_application)
{
w->ivi_surface =
ivi_application_surface_create(display->ivi_application, ivi_surface_id, w->surface);
assert(w->ivi_surface);
ivi_surface_add_listener(w->ivi_surface, &ivi_surface_listener, w);
}
else
#endif
#if BUILD_FULLSCREEN_SHELL
if (display->fullscreen_shell)
{
zwp_fullscreen_shell_v1_present_surface(display->fullscreen_shell, w->surface,
ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER,
nullptr);
}
else
#endif
if (display->xdg_base)
{
w->xdg_surface = xdg_wm_base_get_xdg_surface(display->xdg_base, w->surface);
if (!w->xdg_surface)
{
display->last_error = UWAC_ERROR_NOMEMORY;
goto out_error_shell;
}
xdg_surface_add_listener(w->xdg_surface, &xdg_surface_listener, w);
w->xdg_toplevel = xdg_surface_get_toplevel(w->xdg_surface);
if (!w->xdg_toplevel)
{
display->last_error = UWAC_ERROR_NOMEMORY;
goto out_error_shell;
}
assert(w->xdg_surface);
xdg_toplevel_add_listener(w->xdg_toplevel, &xdg_toplevel_listener, w);
wl_surface_commit(w->surface);
wl_display_roundtrip(w->display->display);
}
else
{
w->shell_surface = wl_shell_get_shell_surface(display->shell, w->surface);
assert(w->shell_surface);
wl_shell_surface_add_listener(w->shell_surface, &shell_listener, w);
wl_shell_surface_set_toplevel(w->shell_surface);
}
if (display->viewporter)
{
w->viewport = wp_viewporter_get_viewport(display->viewporter, w->surface);
if (display->actual_scale != 1)
wl_surface_set_buffer_scale(w->surface, display->actual_scale);
}
wl_list_insert(display->windows.prev, &w->link);
display->last_error = UWAC_SUCCESS;
UwacWindowSetDecorations(w);
return w;
out_error_shell:
wl_surface_destroy(w->surface);
out_error_surface:
UwacWindowDestroyBuffers(w);
out_error_free:
free(w);
return nullptr;
}
UwacReturnCode UwacDestroyWindow(UwacWindow** pwindow)
{
UwacWindow* w = nullptr;
assert(pwindow);
w = *pwindow;
UwacWindowDestroyBuffers(w);
if (w->deco)
zxdg_toplevel_decoration_v1_destroy(w->deco);
if (w->kde_deco)
org_kde_kwin_server_decoration_destroy(w->kde_deco);
if (w->xdg_surface)
xdg_surface_destroy(w->xdg_surface);
#if BUILD_IVI
if (w->ivi_surface)
ivi_surface_destroy(w->ivi_surface);
#endif
if (w->opaque_region)
wl_region_destroy(w->opaque_region);
if (w->input_region)
wl_region_destroy(w->input_region);
if (w->viewport)
wp_viewport_destroy(w->viewport);
wl_surface_destroy(w->surface);
wl_list_remove(&w->link);
free(w);
*pwindow = nullptr;
return UWAC_SUCCESS;
}
UwacReturnCode UwacWindowSetOpaqueRegion(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
uint32_t height)
{
assert(window);
if (window->opaque_region)
wl_region_destroy(window->opaque_region);
window->opaque_region = wl_compositor_create_region(window->display->compositor);
if (!window->opaque_region)
return UWAC_ERROR_NOMEMORY;
wl_region_add(window->opaque_region, WINPR_ASSERTING_INT_CAST(int32_t, x),
WINPR_ASSERTING_INT_CAST(int32_t, y), WINPR_ASSERTING_INT_CAST(int32_t, width),
WINPR_ASSERTING_INT_CAST(int32_t, height));
wl_surface_set_opaque_region(window->surface, window->opaque_region);
return UWAC_SUCCESS;
}
UwacReturnCode UwacWindowSetInputRegion(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
uint32_t height)
{
assert(window);
if (window->input_region)
wl_region_destroy(window->input_region);
window->input_region = wl_compositor_create_region(window->display->compositor);
if (!window->input_region)
return UWAC_ERROR_NOMEMORY;
wl_region_add(window->input_region, WINPR_ASSERTING_INT_CAST(int32_t, x),
WINPR_ASSERTING_INT_CAST(int32_t, y), WINPR_ASSERTING_INT_CAST(int32_t, width),
WINPR_ASSERTING_INT_CAST(int32_t, height));
wl_surface_set_input_region(window->surface, window->input_region);
return UWAC_SUCCESS;
}
void* UwacWindowGetDrawingBuffer(UwacWindow* window)
{
UwacBuffer* buffer = nullptr;
if (window->drawingBufferIdx < 0)
return nullptr;
buffer = &window->buffers[window->drawingBufferIdx];
if (!buffer)
return nullptr;
return buffer->data;
}
static void frame_done_cb(void* data, struct wl_callback* callback, uint32_t time);
static const struct wl_callback_listener frame_listener = { frame_done_cb };
#ifdef UWAC_HAVE_PIXMAN_REGION
static void damage_surface(UwacWindow* window, UwacBuffer* buffer, int scale)
{
int nrects = 0;
const pixman_box32_t* box = pixman_region32_rectangles(&buffer->damage, &nrects);
for (int i = 0; i < nrects; i++, box++)
{
const int x = ((int)floor(box->x1 / scale)) - 1;
const int y = ((int)floor(box->y1 / scale)) - 1;
const int w = ((int)ceil((box->x2 - box->x1) / scale)) + 2;
const int h = ((int)ceil((box->y2 - box->y1) / scale)) + 2;
wl_surface_damage(window->surface, x, y, w, h);
}
pixman_region32_clear(&buffer->damage);
}
#else
static void damage_surface(UwacWindow* window, UwacBuffer* buffer, int scale)
{
uint32_t nrects = 0;
const RECTANGLE_16* boxes = region16_rects(&buffer->damage, &nrects);
for (UINT32 i = 0; i < nrects; i++)
{
const RECTANGLE_16* box = &boxes[i];
const double dx = floor(1.0 * box->left / scale);
const double dy = floor(1.0 * box->top / scale);
const double dw = ceil(1.0 * (box->right - box->left) / scale);
const double dh = ceil(1.0 * (box->bottom - box->top) / scale);
const int x = ((int)dx) - 1;
const int y = ((int)dy) - 1;
const int w = ((int)dw) + 2;
const int h = ((int)dh) + 2;
wl_surface_damage(window->surface, x, y, w, h);
}
region16_clear(&buffer->damage);
}
#endif
static void UwacSubmitBufferPtr(UwacWindow* window, UwacBuffer* buffer)
{
wl_surface_attach(window->surface, buffer->wayland_buffer, 0, 0);
int scale = window->display->actual_scale;
damage_surface(window, buffer, scale);
struct wl_callback* frame_callback = wl_surface_frame(window->surface);
wl_callback_add_listener(frame_callback, &frame_listener, window);
wl_surface_commit(window->surface);
buffer->dirty = false;
}
static void frame_done_cb(void* data, struct wl_callback* callback, uint32_t time)
{
UwacWindow* window = (UwacWindow*)data;
UwacFrameDoneEvent* event = nullptr;
wl_callback_destroy(callback);
window->pendingBufferIdx = -1;
event = (UwacFrameDoneEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_FRAME_DONE);
if (event)
event->window = window;
}
#ifdef UWAC_HAVE_PIXMAN_REGION
UwacReturnCode UwacWindowAddDamage(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
uint32_t height)
{
UwacBuffer* buf = nullptr;
if (window->drawingBufferIdx < 0)
return UWAC_ERROR_INTERNAL;
buf = &window->buffers[window->drawingBufferIdx];
if (!pixman_region32_union_rect(&buf->damage, &buf->damage, x, y, width, height))
return UWAC_ERROR_INTERNAL;
buf->dirty = true;
return UWAC_SUCCESS;
}
#else
UwacReturnCode UwacWindowAddDamage(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
uint32_t height)
{
RECTANGLE_16 box;
UwacBuffer* buf = nullptr;
box.left = x;
box.top = y;
box.right = x + width;
box.bottom = y + height;
if (window->drawingBufferIdx < 0)
return UWAC_ERROR_INTERNAL;
buf = &window->buffers[window->drawingBufferIdx];
if (!buf)
return UWAC_ERROR_INTERNAL;
if (!region16_union_rect(&buf->damage, &buf->damage, &box))
return UWAC_ERROR_INTERNAL;
buf->dirty = true;
return UWAC_SUCCESS;
}
#endif
UwacReturnCode UwacWindowGetDrawingBufferGeometry(UwacWindow* window, UwacSize* geometry,
size_t* stride)
{
if (!window || (window->drawingBufferIdx < 0))
return UWAC_ERROR_INTERNAL;
if (geometry)
{
geometry->width = window->width;
geometry->height = window->height;
}
if (stride)
*stride = window->stride;
return UWAC_SUCCESS;
}
UwacReturnCode UwacWindowSubmitBuffer(UwacWindow* window, bool copyContentForNextFrame)
{
UwacBuffer* currentDrawingBuffer = nullptr;
UwacBuffer* nextDrawingBuffer = nullptr;
UwacBuffer* pendingBuffer = nullptr;
if (window->drawingBufferIdx < 0)
return UWAC_ERROR_INTERNAL;
currentDrawingBuffer = &window->buffers[window->drawingBufferIdx];
if ((window->pendingBufferIdx >= 0) || !currentDrawingBuffer->dirty)
return UWAC_SUCCESS;
window->pendingBufferIdx = window->drawingBufferIdx;
nextDrawingBuffer = UwacWindowFindFreeBuffer(window, &window->drawingBufferIdx);
pendingBuffer = &window->buffers[window->pendingBufferIdx];
if ((!nextDrawingBuffer) || (window->drawingBufferIdx < 0))
return UWAC_ERROR_NOMEMORY;
if (copyContentForNextFrame)
memcpy(nextDrawingBuffer->data, pendingBuffer->data,
1ull * window->stride * window->height);
UwacSubmitBufferPtr(window, pendingBuffer);
return UWAC_SUCCESS;
}
UwacReturnCode UwacWindowGetGeometry(UwacWindow* window, UwacSize* geometry)
{
assert(window);
assert(geometry);
geometry->width = window->width;
geometry->height = window->height;
return UWAC_SUCCESS;
}
UwacReturnCode UwacWindowSetFullscreenState(UwacWindow* window, UwacOutput* output,
bool isFullscreen)
{
if (window->xdg_toplevel)
{
if (isFullscreen)
{
xdg_toplevel_set_fullscreen(window->xdg_toplevel, output ? output->output : nullptr);
}
else
{
xdg_toplevel_unset_fullscreen(window->xdg_toplevel);
}
}
else if (window->shell_surface)
{
if (isFullscreen)
{
wl_shell_surface_set_fullscreen(window->shell_surface,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0,
output ? output->output : nullptr);
}
else
{
wl_shell_surface_set_toplevel(window->shell_surface);
}
}
return UWAC_SUCCESS;
}
void UwacWindowSetTitle(UwacWindow* window, const char* name)
{
if (window->xdg_toplevel)
xdg_toplevel_set_title(window->xdg_toplevel, name);
else if (window->shell_surface)
wl_shell_surface_set_title(window->shell_surface, name);
}
void UwacWindowSetAppId(UwacWindow* window, const char* app_id)
{
if (window->xdg_toplevel)
xdg_toplevel_set_app_id(window->xdg_toplevel, app_id);
}

View File

@@ -0,0 +1,220 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="fullscreen_shell_unstable_v1">
<interface name="zwp_fullscreen_shell_v1" version="1">
<description summary="displays a single surface per output">
Displays a single surface per output.
This interface provides a mechanism for a single client to display
simple full-screen surfaces. While there technically may be multiple
clients bound to this interface, only one of those clients should be
shown at a time.
To present a surface, the client uses either the present_surface or
present_surface_for_mode requests. Presenting a surface takes effect
on the next wl_surface.commit. See the individual requests for
details about scaling and mode switches.
The client can have at most one surface per output at any time.
Requesting a surface to be presented on an output that already has a
surface replaces the previously presented surface. Presenting a null
surface removes its content and effectively disables the output.
Exactly what happens when an output is "disabled" is
compositor-specific. The same surface may be presented on multiple
outputs simultaneously.
Once a surface is presented on an output, it stays on that output
until either the client removes it or the compositor destroys the
output. This way, the client can update the output's contents by
simply attaching a new buffer.
Warning! The protocol described in this file is experimental and
backward incompatible changes may be made. Backward compatible changes
may be added together with the corresponding interface version bump.
Backward incompatible changes are done by bumping the version number in
the protocol and interface names and resetting the interface version.
Once the protocol is to be declared stable, the 'z' prefix and the
version number in the protocol and interface names are removed and the
interface version number is reset.
</description>
<request name="release" type="destructor">
<description summary="release the wl_fullscreen_shell interface">
Release the binding from the wl_fullscreen_shell interface.
This destroys the server-side object and frees this binding. If
the client binds to wl_fullscreen_shell multiple times, it may wish
to free some of those bindings.
</description>
</request>
<enum name="capability">
<description summary="capabilities advertised by the compositor">
Various capabilities that can be advertised by the compositor. They
are advertised one-at-a-time when the wl_fullscreen_shell interface is
bound. See the wl_fullscreen_shell.capability event for more details.
ARBITRARY_MODES:
This is a hint to the client that indicates that the compositor is
capable of setting practically any mode on its outputs. If this
capability is provided, wl_fullscreen_shell.present_surface_for_mode
will almost never fail and clients should feel free to set whatever
mode they like. If the compositor does not advertise this, it may
still support some modes that are not advertised through wl_global.mode
but it is less likely.
CURSOR_PLANE:
This is a hint to the client that indicates that the compositor can
handle a cursor surface from the client without actually compositing.
This may be because of a hardware cursor plane or some other mechanism.
If the compositor does not advertise this capability then setting
wl_pointer.cursor may degrade performance or be ignored entirely. If
CURSOR_PLANE is not advertised, it is recommended that the client draw
its own cursor and set wl_pointer.cursor(NULL).
</description>
<entry name="arbitrary_modes" value="1" summary="compositor is capable of almost any output mode"/>
<entry name="cursor_plane" value="2" summary="compositor has a separate cursor plane"/>
</enum>
<event name="capability">
<description summary="advertises a capability of the compositor">
Advertises a single capability of the compositor.
When the wl_fullscreen_shell interface is bound, this event is emitted
once for each capability advertised. Valid capabilities are given by
the wl_fullscreen_shell.capability enum. If clients want to take
advantage of any of these capabilities, they should use a
wl_display.sync request immediately after binding to ensure that they
receive all the capability events.
</description>
<arg name="capability" type="uint"/>
</event>
<enum name="present_method">
<description summary="different method to set the surface fullscreen">
Hints to indicate to the compositor how to deal with a conflict
between the dimensions of the surface and the dimensions of the
output. The compositor is free to ignore this parameter.
</description>
<entry name="default" value="0" summary="no preference, apply default policy"/>
<entry name="center" value="1" summary="center the surface on the output"/>
<entry name="zoom" value="2" summary="scale the surface, preserving aspect ratio, to the largest size that will fit on the output" />
<entry name="zoom_crop" value="3" summary="scale the surface, preserving aspect ratio, to fully fill the output cropping if needed" />
<entry name="stretch" value="4" summary="scale the surface to the size of the output ignoring aspect ratio" />
</enum>
<request name="present_surface">
<description summary="present surface for display">
Present a surface on the given output.
If the output is null, the compositor will present the surface on
whatever display (or displays) it thinks best. In particular, this
may replace any or all surfaces currently presented so it should
not be used in combination with placing surfaces on specific
outputs.
The method parameter is a hint to the compositor for how the surface
is to be presented. In particular, it tells the compositor how to
handle a size mismatch between the presented surface and the
output. The compositor is free to ignore this parameter.
The "zoom", "zoom_crop", and "stretch" methods imply a scaling
operation on the surface. This will override any kind of output
scaling, so the buffer_scale property of the surface is effectively
ignored.
</description>
<arg name="surface" type="object" interface="wl_surface" allow-null="true"/>
<arg name="method" type="uint"/>
<arg name="output" type="object" interface="wl_output" allow-null="true"/>
</request>
<request name="present_surface_for_mode">
<description summary="present surface for display at a particular mode">
Presents a surface on the given output for a particular mode.
If the current size of the output differs from that of the surface,
the compositor will attempt to change the size of the output to
match the surface. The result of the mode-switch operation will be
returned via the provided wl_fullscreen_shell_mode_feedback object.
If the current output mode matches the one requested or if the
compositor successfully switches the mode to match the surface,
then the mode_successful event will be sent and the output will
contain the contents of the given surface. If the compositor
cannot match the output size to the surface size, the mode_failed
will be sent and the output will contain the contents of the
previously presented surface (if any). If another surface is
presented on the given output before either of these has a chance
to happen, the present_cancelled event will be sent.
Due to race conditions and other issues unknown to the client, no
mode-switch operation is guaranteed to succeed. However, if the
mode is one advertised by wl_output.mode or if the compositor
advertises the ARBITRARY_MODES capability, then the client should
expect that the mode-switch operation will usually succeed.
If the size of the presented surface changes, the resulting output
is undefined. The compositor may attempt to change the output mode
to compensate. However, there is no guarantee that a suitable mode
will be found and the client has no way to be notified of success
or failure.
The framerate parameter specifies the desired framerate for the
output in mHz. The compositor is free to ignore this parameter. A
value of 0 indicates that the client has no preference.
If the value of wl_output.scale differs from wl_surface.buffer_scale,
then the compositor may choose a mode that matches either the buffer
size or the surface size. In either case, the surface will fill the
output.
</description>
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="output" type="object" interface="wl_output"/>
<arg name="framerate" type="int"/>
<arg name="feedback" type="new_id" interface="zwp_fullscreen_shell_mode_feedback_v1"/>
</request>
<enum name="error">
<description summary="wl_fullscreen_shell error values">
These errors can be emitted in response to wl_fullscreen_shell requests.
</description>
<entry name="invalid_method" value="0" summary="present_method is not known"/>
</enum>
</interface>
<interface name="zwp_fullscreen_shell_mode_feedback_v1" version="1">
<event name="mode_successful">
<description summary="mode switch succeeded">
This event indicates that the attempted mode switch operation was
successful. A surface of the size requested in the mode switch
will fill the output without scaling.
Upon receiving this event, the client should destroy the
wl_fullscreen_shell_mode_feedback object.
</description>
</event>
<event name="mode_failed">
<description summary="mode switch failed">
This event indicates that the attempted mode switch operation
failed. This may be because the requested output mode is not
possible or it may mean that the compositor does not want to allow it.
Upon receiving this event, the client should destroy the
wl_fullscreen_shell_mode_feedback object.
</description>
</event>
<event name="present_cancelled">
<description summary="mode switch cancelled">
This event indicates that the attempted mode switch operation was
cancelled. Most likely this is because the client requested a
second mode switch before the first one completed.
Upon receiving this event, the client should destroy the
wl_fullscreen_shell_mode_feedback object.
</description>
</event>
</interface>
</protocol>

View File

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="ivi_application">
<copyright>
Copyright (C) 2013 DENSO CORPORATION
Copyright (c) 2013 BMW Car IT GmbH
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.
</copyright>
<interface name="ivi_surface" version="1">
<description summary="application interface to surface in ivi compositor"/>
<request name="destroy" type="destructor">
<description summary="destroy ivi_surface">
This removes link from ivi_id to wl_surface and destroys ivi_surface.
The ID, ivi_id, is free and can be used for surface_create again.
</description>
</request>
<event name="configure">
<description summary="suggest resize">
The configure event asks the client to resize its surface.
The size is a hint, in the sense that the client is free to
ignore it if it doesn't resize, pick a smaller size (to
satisfy aspect ratio or resize in steps of NxM pixels).
The client is free to dismiss all but the last configure
event it received.
The width and height arguments specify the size of the window
in surface local coordinates.
</description>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
</event>
</interface>
<interface name="ivi_application" version="1">
<description summary="create ivi-style surfaces">
This interface is exposed as a global singleton.
This interface is implemented by servers that provide IVI-style user interfaces.
It allows clients to associate a ivi_surface with wl_surface.
</description>
<enum name="error">
<entry name="role" value="0" summary="given wl_surface has another role"/>
<entry name="ivi_id" value="1" summary="given ivi_id is assigned to another wl_surface"/>
</enum>
<request name="surface_create">
<description summary="create ivi_surface with numeric ID in ivi compositor">
This request gives the wl_surface the role of an IVI Surface. Creating more than
one ivi_surface for a wl_surface is not allowed. Note, that this still allows the
following example:
1. create a wl_surface
2. create ivi_surface for the wl_surface
3. destroy the ivi_surface
4. create ivi_surface for the wl_surface (with the same or another ivi_id as before)
surface_create will create a interface:ivi_surface with numeric ID; ivi_id in
ivi compositor. These ivi_ids are defined as unique in the system to identify
it inside of ivi compositor. The ivi compositor implements business logic how to
set properties of the surface with ivi_id according to status of the system.
E.g. a unique ID for Car Navigation application is used for implementing special
logic of the application about where it shall be located.
The server regards following cases as protocol errors and disconnects the client.
- wl_surface already has an nother role.
- ivi_id is already assigned to an another wl_surface.
If client destroys ivi_surface or wl_surface which is assigned to the ivi_surface,
ivi_id which is assigned to the ivi_surface is free for reuse.
</description>
<arg name="ivi_id" type="uint"/>
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="id" type="new_id" interface="ivi_surface"/>
</request>
</interface>
</protocol>

View File

@@ -0,0 +1,143 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="keyboard_shortcuts_inhibit_unstable_v1">
<copyright>
Copyright © 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.
</copyright>
<description summary="Protocol for inhibiting the compositor keyboard shortcuts">
This protocol specifies a way for a client to request the compositor
to ignore its own keyboard shortcuts for a given seat, so that all
key events from that seat get forwarded to a surface.
Warning! The protocol described in this file is experimental and
backward incompatible changes may be made. Backward compatible
changes may be added together with the corresponding interface
version bump.
Backward incompatible changes are done by bumping the version
number in the protocol and interface names and resetting the
interface version. Once the protocol is to be declared stable,
the 'z' prefix and the version number in the protocol and
interface names are removed and the interface version number is
reset.
</description>
<interface name="zwp_keyboard_shortcuts_inhibit_manager_v1" version="1">
<description summary="context object for keyboard grab_manager">
A global interface used for inhibiting the compositor keyboard shortcuts.
</description>
<request name="destroy" type="destructor">
<description summary="destroy the keyboard shortcuts inhibitor object">
Destroy the keyboard shortcuts inhibitor manager.
</description>
</request>
<request name="inhibit_shortcuts">
<description summary="create a new keyboard shortcuts inhibitor object">
Create a new keyboard shortcuts inhibitor object associated with
the given surface for the given seat.
If shortcuts are already inhibited for the specified seat and surface,
a protocol error "already_inhibited" is raised by the compositor.
</description>
<arg name="id" type="new_id" interface="zwp_keyboard_shortcuts_inhibitor_v1"/>
<arg name="surface" type="object" interface="wl_surface"
summary="the surface that inhibits the keyboard shortcuts behavior"/>
<arg name="seat" type="object" interface="wl_seat"
summary="the wl_seat for which keyboard shortcuts should be disabled"/>
</request>
<enum name="error">
<entry name="already_inhibited"
value="0"
summary="the shortcuts are already inhibited for this surface"/>
</enum>
</interface>
<interface name="zwp_keyboard_shortcuts_inhibitor_v1" version="1">
<description summary="context object for keyboard shortcuts inhibitor">
A keyboard shortcuts inhibitor instructs the compositor to ignore
its own keyboard shortcuts when the associated surface has keyboard
focus. As a result, when the surface has keyboard focus on the given
seat, it will receive all key events originating from the specified
seat, even those which would normally be caught by the compositor for
its own shortcuts.
The Wayland compositor is however under no obligation to disable
all of its shortcuts, and may keep some special key combo for its own
use, including but not limited to one allowing the user to forcibly
restore normal keyboard events routing in the case of an unwilling
client. The compositor may also use the same key combo to reactivate
an existing shortcut inhibitor that was previously deactivated on
user request.
When the compositor restores its own keyboard shortcuts, an
"inactive" event is emitted to notify the client that the keyboard
shortcuts inhibitor is not effectively active for the surface and
seat any more, and the client should not expect to receive all
keyboard events.
When the keyboard shortcuts inhibitor is inactive, the client has
no way to forcibly reactivate the keyboard shortcuts inhibitor.
The user can chose to re-enable a previously deactivated keyboard
shortcuts inhibitor using any mechanism the compositor may offer,
in which case the compositor will send an "active" event to notify
the client.
If the surface is destroyed, unmapped, or loses the seat's keyboard
focus, the keyboard shortcuts inhibitor becomes irrelevant and the
compositor will restore its own keyboard shortcuts but no "inactive"
event is emitted in this case.
</description>
<request name="destroy" type="destructor">
<description summary="destroy the keyboard shortcuts inhibitor object">
Remove the keyboard shortcuts inhibitor from the associated wl_surface.
</description>
</request>
<event name="active">
<description summary="shortcuts are inhibited">
This event indicates that the shortcut inhibitor is active.
The compositor sends this event every time compositor shortcuts
are inhibited on behalf of the surface. When active, the client
may receive input events normally reserved by the compositor
(see zwp_keyboard_shortcuts_inhibitor_v1).
This occurs typically when the initial request "inhibit_shortcuts"
first becomes active or when the user instructs the compositor to
re-enable and existing shortcuts inhibitor using any mechanism
offered by the compositor.
</description>
</event>
<event name="inactive">
<description summary="shortcuts are restored">
This event indicates that the shortcuts inhibitor is inactive,
normal shortcuts processing is restored by the compositor.
</description>
</event>
</interface>
</protocol>

View File

@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="server_decoration">
<copyright><![CDATA[
Copyright (C) 2015 Martin Gräßlin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
]]></copyright>
<interface name="org_kde_kwin_server_decoration_manager" version="1">
<description summary="Server side window decoration manager">
This interface allows to coordinate whether the server should create
a server-side window decoration around a wl_surface representing a
shell surface (wl_shell_surface or similar). By announcing support
for this interface the server indicates that it supports server
side decorations.
Use in conjunction with zxdg_decoration_manager_v1 is undefined.
</description>
<request name="create">
<description summary="Create a server-side decoration object for a given surface">
When a client creates a server-side decoration object it indicates
that it supports the protocol. The client is supposed to tell the
server whether it wants server-side decorations or will provide
client-side decorations.
If the client does not create a server-side decoration object for
a surface the server interprets this as lack of support for this
protocol and considers it as client-side decorated. Nevertheless a
client-side decorated surface should use this protocol to indicate
to the server that it does not want a server-side deco.
</description>
<arg name="id" type="new_id" interface="org_kde_kwin_server_decoration"/>
<arg name="surface" type="object" interface="wl_surface"/>
</request>
<enum name="mode">
<description summary="Possible values to use in request_mode and the event mode."/>
<entry name="None" value="0" summary="Undecorated: The surface is not decorated at all, neither server nor client-side. An example is a popup surface which should not be decorated."/>
<entry name="Client" value="1" summary="Client-side decoration: The decoration is part of the surface and the client."/>
<entry name="Server" value="2" summary="Server-side decoration: The server embeds the surface into a decoration frame."/>
</enum>
<event name="default_mode">
<description summary="The default mode used on the server">
This event is emitted directly after binding the interface. It contains
the default mode for the decoration. When a new server decoration object
is created this new object will be in the default mode until the first
request_mode is requested.
The server may change the default mode at any time.
</description>
<arg name="mode" type="uint" summary="The default decoration mode applied to newly created server decorations."/>
</event>
</interface>
<interface name="org_kde_kwin_server_decoration" version="1">
<request name="release" type="destructor">
<description summary="release the server decoration object"/>
</request>
<enum name="mode">
<description summary="Possible values to use in request_mode and the event mode."/>
<entry name="None" value="0" summary="Undecorated: The surface is not decorated at all, neither server nor client-side. An example is a popup surface which should not be decorated."/>
<entry name="Client" value="1" summary="Client-side decoration: The decoration is part of the surface and the client."/>
<entry name="Server" value="2" summary="Server-side decoration: The server embeds the surface into a decoration frame."/>
</enum>
<request name="request_mode">
<description summary="The decoration mode the surface wants to use."/>
<arg name="mode" type="uint" summary="The mode this surface wants to use."/>
</request>
<event name="mode">
<description summary="The new decoration mode applied by the server">
This event is emitted directly after the decoration is created and
represents the base decoration policy by the server. E.g. a server
which wants all surfaces to be client-side decorated will send Client,
a server which wants server-side decoration will send Server.
The client can request a different mode through the decoration request.
The server will acknowledge this by another event with the same mode. So
even if a server prefers server-side decoration it's possible to force a
client-side decoration.
The server may emit this event at any time. In this case the client can
again request a different mode. It's the responsibility of the server to
prevent a feedback loop.
</description>
<arg name="mode" type="uint" summary="The decoration mode applied to the surface by the server."/>
</event>
</interface>
</protocol>

View File

@@ -0,0 +1,180 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="viewporter">
<copyright>
Copyright © 2013-2016 Collabora, Ltd.
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.
</copyright>
<interface name="wp_viewporter" version="1">
<description summary="surface cropping and scaling">
The global interface exposing surface cropping and scaling
capabilities is used to instantiate an interface extension for a
wl_surface object. This extended interface will then allow
cropping and scaling the surface contents, effectively
disconnecting the direct relationship between the buffer and the
surface size.
</description>
<request name="destroy" type="destructor">
<description summary="unbind from the cropping and scaling interface">
Informs the server that the client will not be using this
protocol object anymore. This does not affect any other objects,
wp_viewport objects included.
</description>
</request>
<enum name="error">
<entry name="viewport_exists" value="0"
summary="the surface already has a viewport object associated"/>
</enum>
<request name="get_viewport">
<description summary="extend surface interface for crop and scale">
Instantiate an interface extension for the given wl_surface to
crop and scale its content. If the given wl_surface already has
a wp_viewport object associated, the viewport_exists
protocol error is raised.
</description>
<arg name="id" type="new_id" interface="wp_viewport"
summary="the new viewport interface id"/>
<arg name="surface" type="object" interface="wl_surface"
summary="the surface"/>
</request>
</interface>
<interface name="wp_viewport" version="1">
<description summary="crop and scale interface to a wl_surface">
An additional interface to a wl_surface object, which allows the
client to specify the cropping and scaling of the surface
contents.
This interface works with two concepts: the source rectangle (src_x,
src_y, src_width, src_height), and the destination size (dst_width,
dst_height). The contents of the source rectangle are scaled to the
destination size, and content outside the source rectangle is ignored.
This state is double-buffered, and is applied on the next
wl_surface.commit.
The two parts of crop and scale state are independent: the source
rectangle, and the destination size. Initially both are unset, that
is, no scaling is applied. The whole of the current wl_buffer is
used as the source, and the surface size is as defined in
wl_surface.attach.
If the destination size is set, it causes the surface size to become
dst_width, dst_height. The source (rectangle) is scaled to exactly
this size. This overrides whatever the attached wl_buffer size is,
unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface
has no content and therefore no size. Otherwise, the size is always
at least 1x1 in surface local coordinates.
If the source rectangle is set, it defines what area of the wl_buffer is
taken as the source. If the source rectangle is set and the destination
size is not set, then src_width and src_height must be integers, and the
surface size becomes the source rectangle size. This results in cropping
without scaling. If src_width or src_height are not integers and
destination size is not set, the bad_size protocol error is raised when
the surface state is applied.
The coordinate transformations from buffer pixel coordinates up to
the surface-local coordinates happen in the following order:
1. buffer_transform (wl_surface.set_buffer_transform)
2. buffer_scale (wl_surface.set_buffer_scale)
3. crop and scale (wp_viewport.set*)
This means, that the source rectangle coordinates of crop and scale
are given in the coordinates after the buffer transform and scale,
i.e. in the coordinates that would be the surface-local coordinates
if the crop and scale was not applied.
If src_x or src_y are negative, the bad_value protocol error is raised.
Otherwise, if the source rectangle is partially or completely outside of
the non-NULL wl_buffer, then the out_of_buffer protocol error is raised
when the surface state is applied. A NULL wl_buffer does not raise the
out_of_buffer error.
If the wl_surface associated with the wp_viewport is destroyed,
all wp_viewport requests except 'destroy' raise the protocol error
no_surface.
If the wp_viewport object is destroyed, the crop and scale
state is removed from the wl_surface. The change will be applied
on the next wl_surface.commit.
</description>
<request name="destroy" type="destructor">
<description summary="remove scaling and cropping from the surface">
The associated wl_surface's crop and scale state is removed.
The change is applied on the next wl_surface.commit.
</description>
</request>
<enum name="error">
<entry name="bad_value" value="0"
summary="negative or zero values in width or height"/>
<entry name="bad_size" value="1"
summary="destination size is not integer"/>
<entry name="out_of_buffer" value="2"
summary="source rectangle extends outside of the content area"/>
<entry name="no_surface" value="3"
summary="the wl_surface was destroyed"/>
</enum>
<request name="set_source">
<description summary="set the source rectangle for cropping">
Set the source rectangle of the associated wl_surface. See
wp_viewport for the description, and relation to the wl_buffer
size.
If all of x, y, width and height are -1.0, the source rectangle is
unset instead. Any other set of values where width or height are zero
or negative, or x or y are negative, raise the bad_value protocol
error.
The crop and scale state is double-buffered state, and will be
applied on the next wl_surface.commit.
</description>
<arg name="x" type="fixed" summary="source rectangle x"/>
<arg name="y" type="fixed" summary="source rectangle y"/>
<arg name="width" type="fixed" summary="source rectangle width"/>
<arg name="height" type="fixed" summary="source rectangle height"/>
</request>
<request name="set_destination">
<description summary="set the surface size for scaling">
Set the destination size of the associated wl_surface. See
wp_viewport for the description, and relation to the wl_buffer
size.
If width is -1 and height is -1, the destination size is unset
instead. Any other pair of values for width and height that
contains zero or negative values raises the bad_value protocol
error.
The crop and scale state is double-buffered state, and will be
applied on the next wl_surface.commit.
</description>
<arg name="width" type="int" summary="surface width"/>
<arg name="height" type="int" summary="surface height"/>
</request>
</interface>
</protocol>

View File

@@ -0,0 +1,156 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="xdg_decoration_unstable_v1">
<copyright>
Copyright © 2018 Simon Ser
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.
</copyright>
<interface name="zxdg_decoration_manager_v1" version="1">
<description summary="window decoration manager">
This interface allows a compositor to announce support for server-side
decorations.
A window decoration is a set of window controls as deemed appropriate by
the party managing them, such as user interface components used to move,
resize and change a window's state.
A client can use this protocol to request being decorated by a supporting
compositor.
If compositor and client do not negotiate the use of a server-side
decoration using this protocol, clients continue to self-decorate as they
see fit.
Warning! The protocol described in this file is experimental and
backward incompatible changes may be made. Backward compatible changes
may be added together with the corresponding interface version bump.
Backward incompatible changes are done by bumping the version number in
the protocol and interface names and resetting the interface version.
Once the protocol is to be declared stable, the 'z' prefix and the
version number in the protocol and interface names are removed and the
interface version number is reset.
</description>
<request name="destroy" type="destructor">
<description summary="destroy the decoration manager object">
Destroy the decoration manager. This doesn't destroy objects created
with the manager.
</description>
</request>
<request name="get_toplevel_decoration">
<description summary="create a new toplevel decoration object">
Create a new decoration object associated with the given toplevel.
Creating an xdg_toplevel_decoration from an xdg_toplevel 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_toplevel_decoration.configure event must also be treated as
errors.
</description>
<arg name="id" type="new_id" interface="zxdg_toplevel_decoration_v1"/>
<arg name="toplevel" type="object" interface="xdg_toplevel"/>
</request>
</interface>
<interface name="zxdg_toplevel_decoration_v1" version="1">
<description summary="decoration object for a toplevel surface">
The decoration object allows the compositor to toggle server-side window
decorations for a toplevel surface. The client can request to switch to
another mode.
The xdg_toplevel_decoration object must be destroyed before its
xdg_toplevel.
</description>
<enum name="error">
<entry name="unconfigured_buffer" value="0"
summary="xdg_toplevel has a buffer attached before configure"/>
<entry name="already_constructed" value="1"
summary="xdg_toplevel already has a decoration object"/>
<entry name="orphaned" value="2"
summary="xdg_toplevel destroyed before the decoration object"/>
</enum>
<request name="destroy" type="destructor">
<description summary="destroy the decoration object">
Switch back to a mode without any server-side decorations at the next
commit.
</description>
</request>
<enum name="mode">
<description summary="window decoration modes">
These values describe window decoration modes.
</description>
<entry name="client_side" value="1"
summary="no server-side window decoration"/>
<entry name="server_side" value="2"
summary="server-side window decoration"/>
</enum>
<request name="set_mode">
<description summary="set the decoration mode">
Set the toplevel surface decoration mode. This informs the compositor
that the client prefers the provided decoration mode.
After requesting a decoration mode, the compositor will respond by
emitting a xdg_surface.configure event. The client should then update
its content, drawing it without decorations if the received mode is
server-side decorations. The client must also acknowledge the configure
when committing the new content (see xdg_surface.ack_configure).
The compositor can decide not to use the client's mode and enforce a
different mode instead.
Clients whose decoration mode depend on the xdg_toplevel state may send
a set_mode request in response to a xdg_surface.configure event and wait
for the next xdg_surface.configure event to prevent unwanted state.
Such clients are responsible for preventing configure loops and must
make sure not to send multiple successive set_mode requests with the
same decoration mode.
</description>
<arg name="mode" type="uint" enum="mode" summary="the decoration mode"/>
</request>
<request name="unset_mode">
<description summary="unset the decoration mode">
Unset the toplevel surface decoration mode. This informs the compositor
that the client doesn't prefer a particular decoration mode.
This request has the same semantics as set_mode.
</description>
</request>
<event name="configure">
<description summary="suggest a surface change">
The configure event asks the client to change its decoration mode. The
configured state should not be applied immediately. Clients must send an
ack_configure in response to this event. See xdg_surface.configure and
xdg_surface.ack_configure for details.
A configure event can be sent at any time. The specified mode must be
obeyed by the client.
</description>
<arg name="mode" type="uint" enum="mode" summary="the decoration mode"/>
</event>
</interface>
</protocol>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,51 @@
set(UWAC_INCLUDE_DIR "include/uwac${UWAC_VERSION_MAJOR}")
if(NOT UWAC_FORCE_STATIC_BUILD)
# cmake package
export(PACKAGE uwac)
setfreerdpcmakeinstalldir(UWAC_CMAKE_INSTALL_DIR "uwac${UWAC_VERSION_MAJOR}")
configure_package_config_file(
${CMAKE_CURRENT_SOURCE_DIR}/uwacConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/uwacConfig.cmake
INSTALL_DESTINATION ${UWAC_CMAKE_INSTALL_DIR} PATH_VARS UWAC_INCLUDE_DIR
)
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/uwacConfigVersion.cmake VERSION ${UWAC_VERSION} COMPATIBILITY SameMajorVersion
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/uwacConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/uwacConfigVersion.cmake
DESTINATION ${UWAC_CMAKE_INSTALL_DIR}
)
install(EXPORT uwac DESTINATION ${UWAC_CMAKE_INSTALL_DIR})
endif()
set(UWAC_BUILD_CONFIG_LIST "")
get_cmake_property(res VARIABLES)
foreach(var ${res})
if(var MATCHES "^WITH_*|^BUILD_TESTING*|^UWAC_HAVE_*")
list(APPEND UWAC_BUILD_CONFIG_LIST "${var}=${${var}}")
endif()
endforeach()
string(REPLACE ";" " " UWAC_BUILD_CONFIG "${UWAC_BUILD_CONFIG_LIST}")
cleaning_configure_file(version.h.in ${CMAKE_CURRENT_BINARY_DIR}/../include/uwac/version.h)
cleaning_configure_file(buildflags.h.in ${CMAKE_CURRENT_BINARY_DIR}/../include/uwac/buildflags.h)
cleaning_configure_file(build-config.h.in ${CMAKE_CURRENT_BINARY_DIR}/../include/uwac/build-config.h)
cleaning_configure_file(config.h.in ${CMAKE_CURRENT_BINARY_DIR}/../include/uwac/config.h)
if(NOT UWAC_FORCE_STATIC_BUILD)
# Do not set Requires.Private if not a static build
if(NOT BUILD_SHARED_LIBS)
set(UWAC_PC_REQUIRES_PRIVATE "wayland-client xkbcommon freerdp${FREERDP_VERSION_MAJOR}")
set(UWAC_PC_LIBRARY_PRIVATE "")
endif()
include(pkg-config-install-prefix)
cleaning_configure_file(uwac.pc.in ${CMAKE_CURRENT_BINARY_DIR}/uwac${UWAC_VERSION_MAJOR}.pc @ONLY)
set(UWAC_INSTALL_INCLUDE_DIR ${UWAC_INCLUDE_DIR}/uwac)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/uwac${UWAC_VERSION_MAJOR}.pc DESTINATION ${PKG_CONFIG_PC_INSTALL_DIR})
endif()

View File

@@ -0,0 +1,22 @@
#ifndef UWAC_BUILD_CONFIG_H
#define UWAC_BUILD_CONFIG_H
#define UWAC_DATA_PATH "${WINPR_DATA_PATH}"
#define UWAC_KEYMAP_PATH "${WINPR_KEYMAP_PATH}"
#define UWAC_PLUGIN_PATH "${WINPR_PLUGIN_PATH}"
#define UWAC_INSTALL_PREFIX "${WINPR_INSTALL_PREFIX}"
#define UWAC_LIBRARY_PATH "${WINPR_LIBRARY_PATH}"
#define UWAC_ADDIN_PATH "${WINPR_ADDIN_PATH}"
#define UWAC_SHARED_LIBRARY_SUFFIX "${CMAKE_SHARED_LIBRARY_SUFFIX}"
#define UWAC_SHARED_LIBRARY_PREFIX "${CMAKE_SHARED_LIBRARY_PREFIX}"
#define UWAC_VENDOR_STRING "${VENDOR}"
#define UWAC_PRODUCT_STRING "${PRODUCT}"
#define UWAC_PROXY_PLUGINDIR "${WINPR_PROXY_PLUGINDIR}"
#endif /* UWAC_BUILD_CONFIG_H */

View File

@@ -0,0 +1,11 @@
#ifndef UWAC_BUILD_FLAGS_H
#define UWAC_BUILD_FLAGS_H
#define UWAC_CFLAGS "${CURRENT_C_FLAGS}"
#define UWAC_COMPILER_ID "${CMAKE_C_COMPILER_ID}"
#define UWAC_COMPILER_VERSION "${CMAKE_C_COMPILER_VERSION}"
#define UWAC_TARGET_ARCH "${TARGET_ARCH}"
#define UWAC_BUILD_CONFIG "${UWAC_BUILD_CONFIG}"
#define UWAC_BUILD_TYPE "${CURRENT_BUILD_CONFIG}"
#endif /* UWAC_BUILD_FLAGS_H */

View File

@@ -0,0 +1,12 @@
#ifndef UWAC_CONFIG_H
#define UWAC_CONFIG_H
/* Include files */
#cmakedefine UWAC_HAVE_TM_GMTOFF
#cmakedefine UWAC_HAVE_POLL_H
#cmakedefine UWAC_HAVE_SYSLOG_H
#cmakedefine UWAC_HAVE_JOURNALD_H
#cmakedefine UWAC_HAVE_PIXMAN_REGION
#cmakedefine UWAC_HAVE_STRERROR_R
#endif /* UWAC_CONFIG_H */

View File

@@ -0,0 +1,15 @@
prefix=@PKG_CONFIG_INSTALL_PREFIX@
exec_prefix=${prefix}
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
includedir=${prefix}/@UWAC_INCLUDE_DIR@
libs=-luwac@UWAC_VERSION_MAJOR@
Name: uwac@UWAC_API_VERSION@
Description: uwac: using wayland as a client
URL: http://www.freerdp.com/
Version: @UWAC_VERSION@
Requires:
Requires.private: @UWAC_PC_REQUIRES_PRIVATE@
Libs: -L${libdir} ${libs}
Libs.private: @UWAC_PC_LIBRARY_PRIVATE@
Cflags: -I${includedir}

View File

@@ -0,0 +1,9 @@
@PACKAGE_INIT@
set(UWAC_VERSION_MAJOR "@UWAC_VERSION_MAJOR@")
set(UWAC_VERSION_MINOR "@UWAC_VERSION_MINOR@")
set(UWAC_VERSION_REVISION "@UWAC_VERSION_REVISION@")
set_and_check(UWAC_INCLUDE_DIR "@PACKAGE_UWAC_INCLUDE_DIR@")
include("${CMAKE_CURRENT_LIST_DIR}/uwac.cmake")

View File

@@ -0,0 +1,32 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Version includes
*
* Copyright 2021 Thincast Technologies GmbH
* Copyright 2021 Armin Novak <armin.novak@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef UWAC_VERSION_H
#define UWAC_VERSION_H
#define UWAC_VERSION_MAJOR ${UWAC_VERSION_MAJOR}
#define UWAC_VERSION_MINOR ${UWAC_VERSION_MINOR}
#define UWAC_VERSION_REVISION ${UWAC_VERSION_REVISION}
#define UWAC_VERSION_SUFFIX "${UWAC_VERSION_SUFFIX}"
#define UWAC_API_VERSION "${UWAC_API_VERSION}"
#define UWAC_VERSION "${UWAC_VERSION}"
#define UWAC_VERSION_FULL "${UWAC_VERSION_FULL}"
#define UWAC_GIT_REVISION "${GIT_REVISION}"
#endif /* UWAC_VERSION_H */