barrier/synergy/CMSWindowsScreen.cpp
crs f15c9df85b added platform independent clipboard transfer stuff
clipboard owner support (MS windows done, X windows partial)
added key transfer on ms windows
mutex fixes in CClient (had race conditions)
faster debug output in ms windows
changed temporary screen name to "secondary"
network fixes on ms windows (poll returned wrong result)
fixed transparent cursor on ms windows
2001-11-25 18:32:41 +00:00

256 lines
6.3 KiB
C++

#include "CMSWindowsScreen.h"
#include "CThread.h"
#include "CLock.h"
#include "TMethodJob.h"
#include "CLog.h"
#include "CString.h"
#include <string.h>
#include <assert.h>
//
// CMSWindowsScreen
//
HINSTANCE CMSWindowsScreen::s_instance = NULL;
CMSWindowsScreen* CMSWindowsScreen::s_screen = NULL;
CMSWindowsScreen::CMSWindowsScreen() :
m_class(0),
m_cursor(NULL),
m_w(0), m_h(0),
m_thread(0)
{
assert(s_screen == NULL);
s_screen = this;
}
CMSWindowsScreen::~CMSWindowsScreen()
{
assert(m_class == 0);
s_screen = NULL;
}
void CMSWindowsScreen::init(HINSTANCE instance)
{
s_instance = instance;
}
void CMSWindowsScreen::doRun()
{
m_thread = GetCurrentThreadId();
for (;;) {
// wait for and get the next event
MSG msg;
getEvent(&msg);
// handle quit message
if (msg.message == WM_QUIT) {
break;
}
// dispatch message
if (!onPreTranslate(&msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
void CMSWindowsScreen::doStop()
{
PostThreadMessage(m_thread, WM_QUIT, 0, 0);
}
void CMSWindowsScreen::openDisplay()
{
assert(s_instance != NULL);
assert(m_class == 0);
// create a transparent cursor
int cw = GetSystemMetrics(SM_CXCURSOR);
int ch = GetSystemMetrics(SM_CYCURSOR);
UInt8* cursorAND = new UInt8[ch * ((cw + 31) >> 2)];
UInt8* cursorXOR = new UInt8[ch * ((cw + 31) >> 2)];
memset(cursorAND, 0xff, ch * ((cw + 31) >> 2));
memset(cursorXOR, 0x00, ch * ((cw + 31) >> 2));
m_cursor = CreateCursor(s_instance, 0, 0, cw, ch, cursorAND, cursorXOR);
delete[] cursorXOR;
delete[] cursorAND;
// register a window class
WNDCLASSEX classInfo;
classInfo.cbSize = sizeof(classInfo);
classInfo.style = CS_DBLCLKS | CS_NOCLOSE;
classInfo.lpfnWndProc = &CMSWindowsScreen::wndProc;
classInfo.cbClsExtra = 0;
classInfo.cbWndExtra = 0;
classInfo.hInstance = s_instance;
classInfo.hIcon = NULL;
classInfo.hCursor = m_cursor;
classInfo.hbrBackground = NULL;
classInfo.lpszMenuName = NULL;
classInfo.lpszClassName = "Synergy";
classInfo.hIconSm = NULL;
m_class = RegisterClassEx(&classInfo);
// get screen size
// FIXME -- should handle multiple screens
m_w = GetSystemMetrics(SM_CXSCREEN);
m_h = GetSystemMetrics(SM_CYSCREEN);
log((CLOG_INFO "display size: %dx%d", m_w, m_h));
// let subclass prep display
onOpenDisplay();
}
void CMSWindowsScreen::closeDisplay()
{
assert(s_instance != NULL);
assert(m_class != 0);
// let subclass close down display
onCloseDisplay();
// unregister the window class
UnregisterClass((LPCTSTR)m_class, s_instance);
m_class = 0;
// delete resources
DestroyCursor(m_cursor);
m_cursor = NULL;
log((CLOG_DEBUG "closed display"));
}
HINSTANCE CMSWindowsScreen::getInstance()
{
return s_instance;
}
ATOM CMSWindowsScreen::getClass() const
{
return m_class;
}
void CMSWindowsScreen::getScreenSize(
SInt32* w, SInt32* h) const
{
assert(m_class != 0);
assert(w != NULL && h != NULL);
*w = m_w;
*h = m_h;
}
void CMSWindowsScreen::getEvent(MSG* msg) const
{
// wait for an event in a cancellable way
while (HIWORD(GetQueueStatus(QS_ALLINPUT)) == 0) {
CThread::sleep(0.05);
}
GetMessage(msg, NULL, 0, 0);
}
void CMSWindowsScreen::getDisplayClipboard(
IClipboard* clipboard,
HWND requestor) const
{
/* FIXME
assert(clipboard != NULL);
assert(requestor != None);
// clear the clipboard object
clipboard->open();
// block others from using the display while we get the clipboard.
// in particular, this prevents the event thread from stealing the
// selection notify event we're expecting.
CLock lock(&m_mutex);
// use PRIMARY selection as the "clipboard"
Atom selection = XA_PRIMARY;
// ask the selection for all the formats it has. some owners return
// the TARGETS atom and some the ATOM atom when TARGETS is requested.
Atom format;
CString targets;
if (getDisplayClipboard(selection, m_atomTargets,
requestor, timestamp, &format, &targets) &&
(format == m_atomTargets || format == XA_ATOM)) {
// get each target (that we can interpret). some owners return
// some targets multiple times in the list so don't try to get
// those multiple times.
const Atom* targetAtoms = reinterpret_cast<const Atom*>(targets.data());
const SInt32 numTargets = targets.size() / sizeof(Atom);
std::set<IClipboard::EFormat> clipboardFormats;
std::set<Atom> targets;
log((CLOG_DEBUG "selection has %d targets", numTargets));
for (SInt32 i = 0; i < numTargets; ++i) {
Atom format = targetAtoms[i];
log((CLOG_DEBUG " source target %d", format));
// skip already handled targets
if (targets.count(format) > 0) {
log((CLOG_DEBUG " skipping handled target %d", format));
continue;
}
// mark this target as done
targets.insert(format);
// determine the expected clipboard format
IClipboard::EFormat expectedFormat = getFormat(format);
// if we can use the format and we haven't already retrieved
// it then get it
if (expectedFormat == IClipboard::kNumFormats) {
log((CLOG_DEBUG " no format for target", format));
continue;
}
if (clipboardFormats.count(expectedFormat) > 0) {
log((CLOG_DEBUG " skipping handled format %d", expectedFormat));
continue;
}
CString data;
if (!getDisplayClipboard(selection, format,
requestor, timestamp, &format, &data)) {
log((CLOG_DEBUG " no data for target", format));
continue;
}
// use the actual format, not the expected
IClipboard::EFormat actualFormat = getFormat(format);
if (actualFormat == IClipboard::kNumFormats) {
log((CLOG_DEBUG " no format for target", format));
continue;
}
if (clipboardFormats.count(actualFormat) > 0) {
log((CLOG_DEBUG " skipping handled format %d", actualFormat));
continue;
}
// add to clipboard and note we've done it
clipboard->add(actualFormat, data);
clipboardFormats.insert(actualFormat);
}
}
else {
// non-ICCCM conforming selection owner. try TEXT format.
// FIXME
log((CLOG_DEBUG "selection doesn't support TARGETS, format is %d", format));
}
// done with clipboard
clipboard->close();
*/
}
LRESULT CALLBACK CMSWindowsScreen::wndProc(
HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
assert(s_screen != NULL);
return s_screen->onEvent(hwnd, msg, wParam, lParam);
}