Add clipboard support on Linux

This commit is contained in:
Wojtek Figat
2021-02-24 21:19:14 +01:00
parent d4b2171c19
commit 3da6f9186c
5 changed files with 170 additions and 7 deletions

View File

@@ -7,7 +7,7 @@
#elif PLATFORM_UWP
#include "Base/ClipboardBase.h"
#elif PLATFORM_LINUX
#include "Base/ClipboardBase.h"
#include "Linux/LinuxClipboard.h"
#elif PLATFORM_PS4
#include "Base/ClipboardBase.h"
#elif PLATFORM_XBOX_SCARLETT

View File

@@ -0,0 +1,26 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
#if PLATFORM_LINUX
#include "Engine/Platform/Base/ClipboardBase.h"
/// <summary>
/// Linux platform implementation of the clipboard service.
/// </summary>
class FLAXENGINE_API LinuxClipboard : public ClipboardBase
{
public:
// [ClipboardBase]
static void Clear();
static void SetText(const StringView& text);
static void SetRawData(const Span<byte>& data);
static void SetFiles(const Array<String>& files);
static String GetText();
static Array<byte> GetRawData();
static Array<String> GetFiles();
};
#endif

View File

@@ -19,8 +19,10 @@
#include "Engine/Platform/StringUtils.h"
#include "Engine/Platform/MessageBox.h"
#include "Engine/Platform/WindowsManager.h"
#include "Engine/Platform/Clipboard.h"
#include "Engine/Utilities/StringConverter.h"
#include "Engine/Threading/Threading.h"
#include "Engine/Engine/Engine.h"
#include "Engine/Engine/CommandLine.h"
#include "Engine/Input/Input.h"
#include "Engine/Input/Mouse.h"
@@ -62,6 +64,7 @@ X11::Atom xAtomWmStateMaxVert;
X11::Atom xAtomWmStateMaxHorz;
X11::Atom xAtomWmWindowOpacity;
X11::Atom xAtomWmName;
X11::Atom xAtomClipboard;
int32 SystemDpi = 96;
X11::Cursor Cursors[(int32)CursorType::MAX];
X11::XcursorImage* CursorsImg[(int32)CursorType::MAX];
@@ -357,9 +360,7 @@ static int X11_MessageBoxCreateWindow(MessageBoxData* data)
data->screen = X11_DefaultScreen(display);
}
data->event_mask = ExposureMask |
ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask |
StructureNotifyMask | FocusChangeMask | PointerMotionMask;
data->event_mask = ExposureMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask | FocusChangeMask | PointerMotionMask;
wnd_attr.event_mask = data->event_mask;
data->window = X11::XCreateWindow(
@@ -1172,6 +1173,110 @@ namespace Impl
{
LinuxKeyboard Keyboard;
LinuxMouse Mouse;
StringAnsi ClipboardText;
void ClipboardGetText(String& result, X11::Atom source, X11::Atom atom, X11::Window window)
{
X11::Window selectionOwner = X11::XGetSelectionOwner(xDisplay, source);
if (selectionOwner == 0)
{
// No copy owner
return;
}
if (selectionOwner == window)
{
// Copy/paste from self
result.Set(ClipboardText.Get(), ClipboardText.Length());
return;
}
// Send event to get data from the owner
int format;
unsigned long N, size;
char* data;
X11::Atom target;
X11::Atom CLIPBOARD = X11::XInternAtom(xDisplay, "CLIPBOARD", 0);
X11::Atom XSEL_DATA = X11::XInternAtom(xDisplay, "XSEL_DATA", 0);
X11::Atom UTF8 = X11::XInternAtom(xDisplay, "UTF8_STRING", 1);
X11::XEvent event;
X11::XConvertSelection(xDisplay, CLIPBOARD, atom, XSEL_DATA, window, CurrentTime);
X11::XSync(xDisplay, 0);
X11::XNextEvent(xDisplay, &event);
switch(event.type)
{
case SelectionNotify:
if (event.xselection.selection != CLIPBOARD)
break;
if (event.xselection.property)
{
X11::XGetWindowProperty(event.xselection.display, event.xselection.requestor, event.xselection.property, 0L,(~0L), 0, AnyPropertyType, &target, &format, &size, &N,(unsigned char**)&data);
if (target == UTF8 || target == (X11::Atom)31)
{
// Got text to paste
result.Set(data , size);
X11::XFree(data);
}
X11::XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property);
}
}
}
}
void LinuxClipboard::Clear()
{
SetText(StringView::Empty);
}
void LinuxClipboard::SetText(const StringView& text)
{
auto mainWindow = (LinuxWindow*)Engine::MainWindow;
if (!mainWindow)
return;
X11::Window window = (X11::Window)mainWindow->GetNativePtr();
Impl::ClipboardText.Set(text.GetText(), text.Length());
X11::XSetSelectionOwner(xDisplay, xAtomClipboard, window, CurrentTime); // CLIPBOARD
X11::XSetSelectionOwner(xDisplay, (X11::Atom)1, window, CurrentTime); // XA_PRIMARY
}
void LinuxClipboard::SetRawData(const Span<byte>& data)
{
}
void LinuxClipboard::SetFiles(const Array<String>& files)
{
}
String LinuxClipboard::GetText()
{
String result;
auto mainWindow = (LinuxWindow*)Engine::MainWindow;
if (!mainWindow)
return result;
X11::Window window = (X11::Window)mainWindow->GetNativePtr();
X11::Atom UTF8 = X11::XInternAtom(xDisplay, "UTF8_STRING", 1);
Impl::ClipboardGetText(result, xAtomClipboard, UTF8, window);
if (result.HasChars())
return result;
Impl::ClipboardGetText(result, xAtomClipboard, (X11::Atom)31, window);
if (result.HasChars())
return result;
Impl::ClipboardGetText(result, (X11::Atom)1, UTF8, window);
if (result.HasChars())
return result;
Impl::ClipboardGetText(result, (X11::Atom)1, (X11::Atom)31, window);
return result;
}
Array<byte> LinuxClipboard::GetRawData()
{
return Array<byte>();
}
Array<String> LinuxClipboard::GetFiles()
{
return Array<String>();
}
void* LinuxPlatform::GetXDisplay()
@@ -1550,6 +1655,7 @@ bool LinuxPlatform::Init()
xAtomWmStateMaxVert = X11::XInternAtom(xDisplay, "_NET_WM_STATE_MAXIMIZED_VERT", 0);
xAtomWmWindowOpacity = X11::XInternAtom(xDisplay, "_NET_WM_WINDOW_OPACITY", 0);
xAtomWmName = X11::XInternAtom(xDisplay, "_NET_WM_NAME", 0);
xAtomClipboard = X11::XInternAtom(xDisplay, "CLIPBOARD", 0);
SystemDpi = CalculateDpi();
@@ -1841,6 +1947,37 @@ void LinuxPlatform::Tick()
if (window)
window->OnLeaveNotify(&event.xcrossing);
break;
case SelectionRequest:
{
if (event.xselectionrequest.selection != xAtomClipboard)
break;
X11::Atom targets_atom = X11::XInternAtom(xDisplay, "TARGETS", 0);
X11::Atom text_atom = X11::XInternAtom(xDisplay, "TEXT", 0);
X11::Atom UTF8 = X11::XInternAtom(xDisplay, "UTF8_STRING", 1);
if (UTF8 == 0)
UTF8 = (X11::Atom)31;
X11::XSelectionRequestEvent* xsr = &event.xselectionrequest;
int result = 0;
X11::XSelectionEvent ev = { 0 };
ev.type = SelectionNotify;
ev.display = xsr->display;
ev.requestor = xsr->requestor;
ev.selection = xsr->selection;
ev.time = xsr->time;
ev.target = xsr->target;
ev.property = xsr->property;
if (ev.target == targets_atom)
result = X11::XChangeProperty(ev.display, ev.requestor, ev.property, (X11::Atom)4, 32, PropModeReplace, (unsigned char*)&UTF8, 1);
else if (ev.target == (X11::Atom)31 || ev.target == text_atom)
result = X11::XChangeProperty(ev.display, ev.requestor, ev.property, (X11::Atom)31, 8, PropModeReplace, (unsigned char*)Impl::ClipboardText.Get(), Impl::ClipboardText.Length());
else if (ev.target == UTF8)
result = X11::XChangeProperty(ev.display, ev.requestor, ev.property, UTF8, 8, PropModeReplace, (unsigned char*)Impl::ClipboardText.Get(), Impl::ClipboardText.Length());
else
ev.property = 0;
if ((result & 2) == 0)
X11::XSendEvent(xDisplay, ev.requestor, 0, 0, (X11::XEvent*)&ev);
break;
}
default:
break;
}

View File

@@ -50,8 +50,8 @@ typedef NetworkBase Network;
#elif PLATFORM_LINUX
class ClipboardBase;
typedef ClipboardBase Clipboard;
class LinuxClipboard;
typedef LinuxClipboard Clipboard;
class UnixCriticalSection;
typedef UnixCriticalSection CriticalSection;
class UnixConditionVariable;

View File

@@ -7,7 +7,7 @@
#include "Engine/Platform/Base/ClipboardBase.h"
/// <summary>
/// Windows platform implementation of the clipboards service
/// Windows platform implementation of the clipboard service.
/// </summary>
class FLAXENGINE_API WindowsClipboard : public ClipboardBase
{