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