From 0cba9edc994bb869d9d5761a0f96c2d166bdbec4 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 19 Dec 2018 16:17:59 +0100 Subject: [PATCH] Implemented UWAC clipboard handling. --- uwac/include/uwac/uwac.h | 190 +++++++++++++--------- uwac/libuwac/CMakeLists.txt | 1 + uwac/libuwac/uwac-clipboard.c | 288 ++++++++++++++++++++++++++++++++++ uwac/libuwac/uwac-display.c | 3 +- uwac/libuwac/uwac-input.c | 7 + uwac/libuwac/uwac-priv.h | 11 ++ 6 files changed, 428 insertions(+), 72 deletions(-) create mode 100644 uwac/libuwac/uwac-clipboard.c diff --git a/uwac/include/uwac/uwac.h b/uwac/include/uwac/uwac.h index 710392ac9..6b54dbb57 100644 --- a/uwac/include/uwac/uwac.h +++ b/uwac/include/uwac/uwac.h @@ -27,9 +27,9 @@ #include #if __GNUC__ >= 4 - #define UWAC_API __attribute__ ((visibility("default"))) +#define UWAC_API __attribute__ ((visibility("default"))) #else - #define UWAC_API +#define UWAC_API #endif typedef struct uwac_size UwacSize; @@ -41,7 +41,8 @@ typedef uint32_t UwacSeatId; /** @brief error codes */ -typedef enum { +typedef enum +{ UWAC_SUCCESS = 0, UWAC_ERROR_NOMEMORY, UWAC_ERROR_UNABLE_TO_CONNECT, @@ -56,21 +57,24 @@ typedef enum { } UwacReturnCode; /** @brief input modifiers */ -enum { +enum +{ UWAC_MOD_SHIFT_MASK = 0x01, UWAC_MOD_ALT_MASK = 0x02, UWAC_MOD_CONTROL_MASK = 0x04, }; /** @brief a rectangle size measure */ -struct uwac_size { +struct uwac_size +{ int width; int height; }; /** @brief event types */ -enum { +enum +{ UWAC_EVENT_NEW_SEAT = 0, UWAC_EVENT_REMOVED_SEAT, UWAC_EVENT_NEW_OUTPUT, @@ -90,91 +94,105 @@ enum { UWAC_EVENT_TOUCH_FRAME_END, UWAC_EVENT_FRAME_DONE, UWAC_EVENT_CLOSE, + UWAC_EVENT_CLIPBOARD_AVAILABLE, + UWAC_EVENT_CLIPBOARD_SELECT, + UWAC_EVENT_CLIPBOARD_OFFER, }; /** @brief window states */ -enum { +enum +{ UWAC_WINDOW_MAXIMIZED = 0x1, UWAC_WINDOW_RESIZING = 0x2, UWAC_WINDOW_FULLSCREEN = 0x4, UWAC_WINDOW_ACTIVATED = 0x8, }; -struct uwac_new_output_event { +struct uwac_new_output_event +{ int type; - UwacOutput *output; + UwacOutput* output; }; typedef struct uwac_new_output_event UwacOutputNewEvent; -struct uwac_new_seat_event { +struct uwac_new_seat_event +{ int type; - UwacSeat *seat; + UwacSeat* seat; }; typedef struct uwac_new_seat_event UwacSeatNewEvent; -struct uwac_removed_seat_event { +struct uwac_removed_seat_event +{ int type; UwacSeatId id; }; typedef struct uwac_removed_seat_event UwacSeatRemovedEvent; -struct uwac_keyboard_enter_event { +struct uwac_keyboard_enter_event +{ int type; - UwacWindow *window; - UwacSeat *seat; + UwacWindow* window; + UwacSeat* seat; }; typedef struct uwac_keyboard_enter_event UwacKeyboardEnterLeaveEvent; -struct uwac_pointer_enter_event { +struct uwac_pointer_enter_event +{ int type; - UwacWindow *window; - UwacSeat *seat; + UwacWindow* window; + UwacSeat* seat; uint32_t x, y; }; typedef struct uwac_pointer_enter_event UwacPointerEnterLeaveEvent; -struct uwac_pointer_motion_event { +struct uwac_pointer_motion_event +{ int type; - UwacWindow *window; - UwacSeat *seat; + UwacWindow* window; + UwacSeat* seat; uint32_t x, y; }; typedef struct uwac_pointer_motion_event UwacPointerMotionEvent; -struct uwac_pointer_button_event { +struct uwac_pointer_button_event +{ int type; - UwacWindow *window; - UwacSeat *seat; + 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 { +struct uwac_pointer_axis_event +{ int type; - UwacWindow *window; - UwacSeat *seat; + UwacWindow* window; + UwacSeat* seat; uint32_t x, y; uint32_t axis; wl_fixed_t value; }; typedef struct uwac_pointer_axis_event UwacPointerAxisEvent; -struct uwac_touch_frame_event { +struct uwac_touch_frame_event +{ int type; - UwacWindow *window; - UwacSeat *seat; + 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 { +struct uwac_touch_data +{ int type; - UwacWindow *window; - UwacSeat *seat; + UwacWindow* window; + UwacSeat* seat; int32_t id; wl_fixed_t x; wl_fixed_t y; @@ -183,39 +201,51 @@ typedef struct uwac_touch_data UwacTouchUp; typedef struct uwac_touch_data UwacTouchDown; typedef struct uwac_touch_data UwacTouchMotion; -struct uwac_frame_done_event { +struct uwac_frame_done_event +{ int type; - UwacWindow *window; + UwacWindow* window; }; typedef struct uwac_frame_done_event UwacFrameDoneEvent; -struct uwac_configure_event { +struct uwac_configure_event +{ int type; - UwacWindow *window; + UwacWindow* window; int32_t width; int32_t height; int states; }; typedef struct uwac_configure_event UwacConfigureEvent; -struct uwac_key_event { +struct uwac_key_event +{ int type; - UwacWindow *window; + UwacWindow* window; uint32_t raw_key; uint32_t sym; bool pressed; }; typedef struct uwac_key_event UwacKeyEvent; -struct uwac_close_event { +struct uwac_close_event +{ int type; - UwacWindow *window; + 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; /** @brief */ -union uwac_event { +union uwac_event +{ int type; UwacOutputNewEvent output_new; UwacSeatNewEvent seat_new; @@ -225,6 +255,7 @@ union uwac_event { UwacPointerButtonEvent mouse_button; UwacPointerAxisEvent mouse_axis; UwacKeyboardEnterLeaveEvent keyboard_enter_leave; + UwacClipboardEvent clipboard; UwacKeyEvent key; UwacTouchFrameBegin touchFrameBegin; UwacTouchUp touchUp; @@ -238,7 +269,9 @@ union uwac_event { }; typedef union uwac_event UwacEvent; -typedef bool (*UwacErrorHandler)(UwacDisplay *d, UwacReturnCode code, const char *msg, ...); +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" { @@ -261,7 +294,7 @@ UWAC_API void UwacInstallErrorHandler(UwacErrorHandler handler); * @param name the name of the display to open * @return the created UwacDisplay object */ -UWAC_API UwacDisplay *UwacOpenDisplay(const char *name, UwacReturnCode *err); +UWAC_API UwacDisplay* UwacOpenDisplay(const char* name, UwacReturnCode* err); /** * closes the corresponding UwacDisplay @@ -269,7 +302,7 @@ UWAC_API UwacDisplay *UwacOpenDisplay(const char *name, UwacReturnCode *err); * @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); +UWAC_API UwacReturnCode UwacCloseDisplay(UwacDisplay** pdisplay); /** * Returns the file descriptor associated with the UwacDisplay, this is useful when @@ -278,7 +311,7 @@ UWAC_API UwacReturnCode UwacCloseDisplay(UwacDisplay **pdisplay); * @param display an opened UwacDisplay * @return the corresponding descriptor */ -UWAC_API int UwacDisplayGetFd(UwacDisplay *display); +UWAC_API int UwacDisplayGetFd(UwacDisplay* display); /** * Returns a human readable form of a Uwac error code @@ -286,7 +319,7 @@ UWAC_API int UwacDisplayGetFd(UwacDisplay *display); * @param error the error number * @return the associated string */ -UWAC_API const char *UwacErrorString(UwacReturnCode error); +UWAC_API const char* UwacErrorString(UwacReturnCode error); /** * returns the last error that occurred on a display @@ -294,7 +327,7 @@ UWAC_API const char *UwacErrorString(UwacReturnCode error); * @param display the display * @return the last error that have been set for this display */ -UWAC_API UwacReturnCode UwacDisplayGetLastError(const UwacDisplay *display); +UWAC_API UwacReturnCode UwacDisplayGetLastError(const UwacDisplay* display); /** * retrieves the version of a given interface @@ -304,7 +337,8 @@ UWAC_API UwacReturnCode UwacDisplayGetLastError(const UwacDisplay *display); * @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); +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 @@ -312,7 +346,7 @@ UWAC_API UwacReturnCode UwacDisplayQueryInterfaceVersion(const UwacDisplay *disp * @param display a connected UwacDisplay * @return the number of SHM formats supported */ -UWAC_API uint32_t UwacDisplayQueryGetNbShmFormats(UwacDisplay *display); +UWAC_API uint32_t UwacDisplayQueryGetNbShmFormats(UwacDisplay* display); /** * returns the supported ShmFormats @@ -323,7 +357,8 @@ UWAC_API uint32_t UwacDisplayQueryGetNbShmFormats(UwacDisplay *display); * @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); +UWAC_API UwacReturnCode UwacDisplayQueryShmFormats(const UwacDisplay* display, + enum wl_shm_format* formats, int formats_size, int* filled); /** * returns the number of registered outputs @@ -331,7 +366,7 @@ UWAC_API UwacReturnCode UwacDisplayQueryShmFormats(const UwacDisplay *display, e * @param display the display to query * @return the number of outputs */ -UWAC_API uint32_t UwacDisplayGetNbOutputs(UwacDisplay *display); +UWAC_API uint32_t UwacDisplayGetNbOutputs(UwacDisplay* display); /** * retrieve a particular UwacOutput object @@ -340,7 +375,7 @@ UWAC_API uint32_t UwacDisplayGetNbOutputs(UwacDisplay *display); * @param index index of the output * @return the given UwacOutput, NULL if something failed (so you should query UwacDisplayGetLastError() to have the reason) */ -UWAC_API UwacOutput *UwacDisplayGetOutput(UwacDisplay *display, int index); +UWAC_API UwacOutput* UwacDisplayGetOutput(UwacDisplay* display, int index); /** * retrieve the resolution of a given UwacOutput @@ -349,7 +384,7 @@ UWAC_API UwacOutput *UwacDisplayGetOutput(UwacDisplay *display, int index); * @param resolution a pointer on the * @return UWAC_SUCCESS on success */ -UWAC_API UwacReturnCode UwacOutputGetResolution(UwacOutput *output, UwacSize *resolution); +UWAC_API UwacReturnCode UwacOutputGetResolution(UwacOutput* output, UwacSize* resolution); /** @@ -361,7 +396,8 @@ UWAC_API UwacReturnCode UwacOutputGetResolution(UwacOutput *output, UwacSize *re * @param format format to use for the SHM surface * @return the created UwacWindow, NULL 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); +UWAC_API UwacWindow* UwacCreateWindowShm(UwacDisplay* display, uint32_t width, uint32_t height, + enum wl_shm_format format); /** * destroys the corresponding UwacWindow @@ -369,7 +405,7 @@ UWAC_API UwacWindow *UwacCreateWindowShm(UwacDisplay *display, uint32_t width, u * @param window a pointer on the UwacWindow to destroy * @return if the operation completed successfully */ -UWAC_API UwacReturnCode UwacDestroyWindow(UwacWindow **window); +UWAC_API UwacReturnCode UwacDestroyWindow(UwacWindow** window); /** * Sets the region that should be considered opaque to the compositor. @@ -381,7 +417,8 @@ UWAC_API UwacReturnCode UwacDestroyWindow(UwacWindow **window); * @param height * @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); +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 @@ -393,14 +430,15 @@ UWAC_API UwacReturnCode UwacWindowSetOpaqueRegion(UwacWindow *window, uint32_t x * @param height * @return */ -UWAC_API UwacReturnCode UwacWindowSetInputRegion(UwacWindow *window, uint32_t x, uint32_t y, uint32_t width, uint32_t height); +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); +UWAC_API void* UwacWindowGetDrawingBuffer(UwacWindow* window); /** * sets a rectangle as dirty for the next frame of a window @@ -412,7 +450,8 @@ UWAC_API void *UwacWindowGetDrawingBuffer(UwacWindow *window); * @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); +UWAC_API UwacReturnCode UwacWindowAddDamage(UwacWindow* window, uint32_t x, uint32_t y, + uint32_t width, uint32_t height); /** * Sends a frame to the compositor with the content of the drawing buffer @@ -421,7 +460,7 @@ UWAC_API UwacReturnCode UwacWindowAddDamage(UwacWindow *window, uint32_t x, uint * @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); +UWAC_API UwacReturnCode UwacWindowSubmitBuffer(UwacWindow* window, bool copyContentForNextFrame); /** * returns the geometry of the given UwacWindows @@ -430,7 +469,7 @@ UWAC_API UwacReturnCode UwacWindowSubmitBuffer(UwacWindow *window, bool copyCont * @param geometry the geometry to fill * @return UWAC_SUCCESS on success, an Uwac error otherwise */ -UWAC_API UwacReturnCode UwacWindowGetGeometry(UwacWindow *window, UwacSize *geometry); +UWAC_API UwacReturnCode UwacWindowGetGeometry(UwacWindow* window, UwacSize* geometry); /** * Sets or unset the fact that the window is set fullscreen. After this call the @@ -442,7 +481,8 @@ UWAC_API UwacReturnCode UwacWindowGetGeometry(UwacWindow *window, UwacSize *geom * @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); +UWAC_API UwacReturnCode UwacWindowSetFullscreenState(UwacWindow* window, UwacOutput* output, + bool isFullscreen); /** * When possible (depending on the shell) sets the title of the UwacWindow @@ -450,7 +490,7 @@ UWAC_API UwacReturnCode UwacWindowSetFullscreenState(UwacWindow *window, UwacOut * @param window the UwacWindow * @param name title */ -UWAC_API void UwacWindowSetTitle(UwacWindow *window, const char *name); +UWAC_API void UwacWindowSetTitle(UwacWindow* window, const char* name); /** * @@ -458,7 +498,7 @@ UWAC_API void UwacWindowSetTitle(UwacWindow *window, const char *name); * @param timeout * @return */ -UWAC_API int UwacDisplayDispatch(UwacDisplay *display, int timeout); +UWAC_API int UwacDisplayDispatch(UwacDisplay* display, int timeout); /** * Returns if you have some pending events, and you can UwacNextEvent() without blocking @@ -466,7 +506,7 @@ UWAC_API int UwacDisplayDispatch(UwacDisplay *display, int timeout); * @param display the UwacDisplay * @return if there's some pending events */ -UWAC_API bool UwacHasEvent(UwacDisplay *display); +UWAC_API bool UwacHasEvent(UwacDisplay* display); /** Waits until an event occurs, and when it's there copy the event from the queue to * event. @@ -475,8 +515,7 @@ UWAC_API bool UwacHasEvent(UwacDisplay *display); * @param event the event to fill * @return if the operation completed successfully */ -UWAC_API UwacReturnCode UwacNextEvent(UwacDisplay *display, UwacEvent *event); - +UWAC_API UwacReturnCode UwacNextEvent(UwacDisplay* display, UwacEvent* event); /** * returns the name of the given UwacSeat @@ -484,7 +523,7 @@ UWAC_API UwacReturnCode UwacNextEvent(UwacDisplay *display, UwacEvent *event); * @param seat the UwacSeat * @return the name of the seat */ -UWAC_API const char *UwacSeatGetName(const UwacSeat *seat); +UWAC_API const char* UwacSeatGetName(const UwacSeat* seat); /** * returns the id of the given UwacSeat @@ -492,7 +531,18 @@ UWAC_API const char *UwacSeatGetName(const UwacSeat *seat); * @param seat the UwacSeat * @return the id of the seat */ -UWAC_API UwacSeatId UwacSeatGetId(const UwacSeat *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. diff --git a/uwac/libuwac/CMakeLists.txt b/uwac/libuwac/CMakeLists.txt index 82cea7c89..cfadba8ae 100644 --- a/uwac/libuwac/CMakeLists.txt +++ b/uwac/libuwac/CMakeLists.txt @@ -58,6 +58,7 @@ set(${MODULE_PREFIX}_SRCS ${GENERATED_SOURCES} uwac-display.c uwac-input.c + uwac-clipboard.c uwac-os.c uwac-os.h uwac-output.c diff --git a/uwac/libuwac/uwac-clipboard.c b/uwac/libuwac/uwac-clipboard.c new file mode 100644 index 000000000..6ae892e94 --- /dev/null +++ b/uwac/libuwac/uwac-clipboard.c @@ -0,0 +1,288 @@ +/* + * Copyright © 2018 Armin Novak + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* paste */ +static void data_offer_offer(void* data, struct wl_data_offer* data_offer, + const char* offered_mime_type) +{ + UwacSeat* seat = (UwacSeat*)data; + + if (seat && !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 close event\n")); + } + else + { + event->seat = seat; + sprintf_s(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; + + if (seat && !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 if (seat) + seat->offer = NULL; +} + +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 UwacReturnCode UwacRegisterDeviceListener(UwacSeat* s) +{ + if (!s) + return UWAC_ERROR_INTERNAL; + + wl_data_device_add_listener(s->data_device, &data_device_listener, s); + return UWAC_SUCCESS; +} + +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) +{ + UwacReturnCode rc; + UwacClipboardEvent* event; + + if (!s) + return UWAC_ERROR_INTERNAL; + + rc = UwacRegisterDeviceListener(s); + + if (rc != UWAC_SUCCESS) + return rc; + + 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 close event\n")); + return UWAC_ERROR_INTERNAL; + } + + event->seat = s; +} + +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 +}; + +uint32_t get_serial(UwacSeat* s) +{ + struct wl_callback* callback; + 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 = NULL; + int pipefd[2]; + + if (!seat || !mime || !size || !seat->offer) + return NULL; + + if (pipe(pipefd) != 0) + return NULL; + + 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 + { + void* tmp; + alloc += 1024; + tmp = realloc(data, alloc); + if (!tmp) + { + free(data); + close(pipefd[0]); + return NULL; + } + + data = tmp; + r = read(pipefd[0], &data[pos], alloc - pos); + if (r > 0) + pos += r; + if (r < 0) + { + free(data); + close(pipefd[0]); + return NULL; + } + } while(r > 0); + + close(pipefd[0]); + close(pipefd[1]); + + *size = pos + 1; + return data; +} diff --git a/uwac/libuwac/uwac-display.c b/uwac/libuwac/uwac-display.c index 27014e547..518d430ba 100644 --- a/uwac/libuwac/uwac-display.c +++ b/uwac/libuwac/uwac-display.c @@ -191,6 +191,7 @@ static void registry_handle_global(void* data, struct wl_registry* registry, uin return; } + UwacSeatRegisterClipboard(seat); ev = (UwacSeatNewEvent*)UwacDisplayNewEvent(d, UWAC_EVENT_NEW_SEAT); if (!ev) @@ -276,7 +277,6 @@ static void registry_handle_global_remove(void* data, struct wl_registry* regist if (strcmp(global->interface, "wl_seat") == 0) { UwacSeatRemovedEvent* ev; - display_destroy_seat(d, name); ev = (UwacSeatRemovedEvent*)UwacDisplayNewEvent(d, UWAC_EVENT_REMOVED_SEAT); @@ -727,7 +727,6 @@ bool UwacHasEvent(UwacDisplay* display) return display->pop_queue != NULL; } - UwacReturnCode UwacNextEvent(UwacDisplay* display, UwacEvent* event) { UwacEventListItem* prevItem; diff --git a/uwac/libuwac/uwac-input.c b/uwac/libuwac/uwac-input.c index 5adb62dc1..f5602d41d 100644 --- a/uwac/libuwac/uwac-input.c +++ b/uwac/libuwac/uwac-input.c @@ -807,6 +807,7 @@ UwacSeat *UwacSeatNew(UwacDisplay *d, uint32_t id, uint32_t version) { goto error_watch_timerfd; } + ret->data_device = wl_data_device_manager_get_data_device(d->data_device_manager, ret->seat); wl_list_insert(d->seats.prev, &ret->link); return ret; @@ -864,6 +865,12 @@ void UwacSeatDestroy(UwacSeat *s) { wl_keyboard_destroy(s->keyboard); } + if (s->data_device) + wl_data_device_destroy(s->data_device); + + if (s->data_source) + wl_data_source_destroy(s->data_source); + wl_list_remove(&s->link); free(s); } diff --git a/uwac/libuwac/uwac-priv.h b/uwac/libuwac/uwac-priv.h index 8a27b158f..2046fee66 100644 --- a/uwac/libuwac/uwac-priv.h +++ b/uwac/libuwac/uwac-priv.h @@ -90,6 +90,7 @@ struct uwac_display { 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; @@ -154,9 +155,12 @@ struct uwac_seat { 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_keyboard *keyboard; struct wl_touch *touch; + struct wl_data_offer* offer; struct xkb_context *xkb_context; struct zwp_keyboard_shortcuts_inhibitor_v1 *keyboard_inhibitor; @@ -185,6 +189,11 @@ struct uwac_seat { UwacTask repeat_task; float sx, sy; struct wl_list link; + + void* data_context; + UwacDataTransferHandler transfer_data; + UwacCancelDataTransferHandler cancel_data; + bool ignore_announcement; }; @@ -246,4 +255,6 @@ void UwacSeatDestroy(UwacSeat *s); UwacOutput *UwacCreateOutput(UwacDisplay *d, uint32_t id, uint32_t version); int UwacDestroyOutput(UwacOutput *output); +UwacReturnCode UwacSeatRegisterClipboard(UwacSeat* s); + #endif /* UWAC_PRIV_H_ */