blob: 1196367536dda9120e8712f036247799e5db9599 [file] [log] [blame] [edit]
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2012-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- Clipboard.cxx
#include <rfb_win32/Clipboard.h>
#include <rfb_win32/WMShatter.h>
#include <rfb/util.h>
#include <rfb/LogWriter.h>
using namespace rfb;
using namespace rfb::win32;
static LogWriter vlog("Clipboard");
//
// -=- Clipboard object
//
Clipboard::Clipboard()
: MsgWindow(_T("Clipboard")), notifier(0), next_window(0) {
next_window = SetClipboardViewer(getHandle());
vlog.debug("registered clipboard handler");
}
Clipboard::~Clipboard() {
vlog.debug("removing %p from chain (next is %p)", getHandle(), next_window);
ChangeClipboardChain(getHandle(), next_window);
}
LRESULT
Clipboard::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CHANGECBCHAIN:
vlog.debug("change clipboard chain (%I64x, %I64x)",
(long long)wParam, (long long)lParam);
if ((HWND) wParam == next_window)
next_window = (HWND) lParam;
else if (next_window != 0)
SendMessage(next_window, msg, wParam, lParam);
else
vlog.error("bad clipboard chain change!");
break;
case WM_DRAWCLIPBOARD:
{
HWND owner = GetClipboardOwner();
if (owner == getHandle()) {
vlog.debug("local clipboard changed by me");
} else {
vlog.debug("local clipboard changed by %p", owner);
if (notifier == NULL)
vlog.debug("no clipboard notifier registered");
else
notifier->notifyClipboardChanged(IsClipboardFormatAvailable(CF_UNICODETEXT));
}
}
if (next_window)
SendMessage(next_window, msg, wParam, lParam);
return 0;
};
return MsgWindow::processMessage(msg, wParam, lParam);
};
char*
Clipboard::getClipText() {
HGLOBAL cliphandle;
wchar_t* clipdata;
CharArray utf8;
// Open the clipboard
if (!OpenClipboard(getHandle()))
return NULL;
// Get the clipboard data
cliphandle = GetClipboardData(CF_UNICODETEXT);
if (!cliphandle) {
CloseClipboard();
return NULL;
}
clipdata = (wchar_t*) GlobalLock(cliphandle);
if (!clipdata) {
CloseClipboard();
return NULL;
}
// Convert it to UTF-8
utf8.replaceBuf(utf16ToUTF8(clipdata));
// Release the buffer and close the clipboard
GlobalUnlock(cliphandle);
CloseClipboard();
return convertLF(utf8.buf);
}
void
Clipboard::setClipText(const char* text) {
HANDLE clip_handle = 0;
try {
// - Firstly, we must open the clipboard
if (!OpenClipboard(getHandle()))
throw rdr::SystemException("unable to open Win32 clipboard", GetLastError());
// - Convert the supplied clipboard text into UTF-16 format with CRLF
CharArray filtered(convertCRLF(text));
wchar_t* utf16;
utf16 = utf8ToUTF16(filtered.buf);
// - Allocate global memory for the data
clip_handle = ::GlobalAlloc(GMEM_MOVEABLE, (wcslen(utf16) + 1) * 2);
wchar_t* data = (wchar_t*) GlobalLock(clip_handle);
wcscpy(data, utf16);
GlobalUnlock(clip_handle);
strFree(utf16);
// - Next, we must clear out any existing data
if (!EmptyClipboard())
throw rdr::SystemException("unable to empty Win32 clipboard", GetLastError());
// - Set the new clipboard data
if (!SetClipboardData(CF_UNICODETEXT, clip_handle))
throw rdr::SystemException("unable to set Win32 clipboard", GetLastError());
clip_handle = 0;
vlog.debug("set clipboard");
} catch (rdr::Exception& e) {
vlog.debug("%s", e.str());
}
// - Close the clipboard
if (!CloseClipboard())
vlog.debug("unable to close Win32 clipboard: %lu", GetLastError());
else
vlog.debug("closed clipboard");
if (clip_handle) {
vlog.debug("freeing clipboard handle");
GlobalFree(clip_handle);
}
}