checkpoint. refactored win32 code. had to edit and rename some

files so this is only a checkpoint.
This commit is contained in:
crs 2002-07-15 15:01:36 +00:00
parent f48a5fe387
commit 4b46862026
33 changed files with 1210 additions and 1661 deletions

View File

@ -1,12 +1,8 @@
#include "CMSWindowsSecondaryScreen.h" #include "CMSWindowsSecondaryScreen.h"
#include "IScreenReceiver.h" #include "CMSWindowsScreen.h"
#include "CClipboard.h"
#include "CMSWindowsClipboard.h"
#include "CMSWindowsScreenSaver.h"
#include "CPlatform.h" #include "CPlatform.h"
#include "XScreen.h" #include "XScreen.h"
#include "CLock.h" #include "CLock.h"
#include "CThread.h"
#include "CLog.h" #include "CLog.h"
#include <cctype> #include <cctype>
@ -24,155 +20,18 @@
CMSWindowsSecondaryScreen::CMSWindowsSecondaryScreen( CMSWindowsSecondaryScreen::CMSWindowsSecondaryScreen(
IScreenReceiver* receiver) : IScreenReceiver* receiver) :
m_receiver(receiver), m_is95Family(CPlatform::isWindows95Family()),
m_threadID(0),
m_lastThreadID(0),
m_desk(NULL),
m_deskName(),
m_window(NULL), m_window(NULL),
m_active(false), m_mask(0)
m_nextClipboardWindow(NULL)
{ {
assert(m_receiver != NULL); m_screen = new CMSWindowsScreen(receiver, this);
m_is95Family = CPlatform::isWindows95Family();
// make sure this thread has a message queue
MSG dummy;
PeekMessage(&dummy, NULL, WM_USER, WM_USER, PM_NOREMOVE);
} }
CMSWindowsSecondaryScreen::~CMSWindowsSecondaryScreen() CMSWindowsSecondaryScreen::~CMSWindowsSecondaryScreen()
{ {
assert(m_window == NULL); assert(m_window == NULL);
}
void delete m_screen;
CMSWindowsSecondaryScreen::run()
{
assert(m_window != NULL);
// must call run() from same thread as open()
assert(m_threadID == GetCurrentThreadId());
// change our priority
CThread::getCurrentThread().setPriority(-7);
// run event loop
try {
log((CLOG_INFO "entering event loop"));
mainLoop();
log((CLOG_INFO "exiting event loop"));
}
catch (...) {
log((CLOG_INFO "exiting event loop"));
throw;
}
}
void
CMSWindowsSecondaryScreen::stop()
{
exitMainLoop();
}
void
CMSWindowsSecondaryScreen::open()
{
assert(m_window == NULL);
try {
// open the display
openDisplay();
// create and prepare our window
createWindow();
// initialize the clipboards; assume primary has all clipboards
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
grabClipboard(id);
}
// get keyboard state
updateKeys();
updateModifiers();
// disable the screen saver
installScreenSaver();
}
catch (...) {
close();
throw;
}
// hide the cursor
m_active = true;
leave();
}
void
CMSWindowsSecondaryScreen::close()
{
uninstallScreenSaver();
destroyWindow();
closeDisplay();
}
void
CMSWindowsSecondaryScreen::enter(SInt32 x, SInt32 y, KeyModifierMask mask)
{
CLock lock(&m_mutex);
assert(m_window != NULL);
assert(m_active == false);
log((CLOG_INFO "entering screen at %d,%d mask=%04x", x, y, mask));
syncDesktop();
// now active
m_active = true;
// update our keyboard state to reflect the local state
updateKeys();
updateModifiers();
// toggle modifiers that don't match the desired state
if ((mask & KeyModifierCapsLock) != (m_mask & KeyModifierCapsLock)) {
toggleKey(VK_CAPITAL, KeyModifierCapsLock);
}
if ((mask & KeyModifierNumLock) != (m_mask & KeyModifierNumLock)) {
toggleKey(VK_NUMLOCK | 0x100, KeyModifierNumLock);
}
if ((mask & KeyModifierScrollLock) != (m_mask & KeyModifierScrollLock)) {
toggleKey(VK_SCROLL, KeyModifierScrollLock);
}
// warp to requested location
warpCursor(x, y);
// show mouse
hideWindow();
}
void
CMSWindowsSecondaryScreen::leave()
{
CLock lock(&m_mutex);
assert(m_window != NULL);
assert(m_active == true);
log((CLOG_INFO "leaving screen"));
syncDesktop();
// hide mouse
showWindow();
// not active anymore
m_active = false;
// make sure our idea of clipboard ownership is correct
checkClipboard();
} }
void void
@ -182,8 +41,7 @@ CMSWindowsSecondaryScreen::keyDown(KeyID key, KeyModifierMask mask)
UINT virtualKey; UINT virtualKey;
CLock lock(&m_mutex); CLock lock(&m_mutex);
assert(m_window != NULL); m_screen->syncDesktop();
syncDesktop();
// get the sequence of keys to simulate key press and the final // get the sequence of keys to simulate key press and the final
// modifier state. // modifier state.
@ -223,8 +81,7 @@ CMSWindowsSecondaryScreen::keyRepeat(KeyID key,
UINT virtualKey; UINT virtualKey;
CLock lock(&m_mutex); CLock lock(&m_mutex);
assert(m_window != NULL); m_screen->syncDesktop();
syncDesktop();
// get the sequence of keys to simulate key repeat and the final // get the sequence of keys to simulate key repeat and the final
// modifier state. // modifier state.
@ -244,8 +101,7 @@ CMSWindowsSecondaryScreen::keyUp(KeyID key, KeyModifierMask mask)
UINT virtualKey; UINT virtualKey;
CLock lock(&m_mutex); CLock lock(&m_mutex);
assert(m_window != NULL); m_screen->syncDesktop();
syncDesktop();
// get the sequence of keys to simulate key release and the final // get the sequence of keys to simulate key release and the final
// modifier state. // modifier state.
@ -302,8 +158,7 @@ void
CMSWindowsSecondaryScreen::mouseDown(ButtonID button) CMSWindowsSecondaryScreen::mouseDown(ButtonID button)
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
assert(m_window != NULL); m_screen->syncDesktop();
syncDesktop();
// map button id to button flag // map button id to button flag
DWORD flags = mapButton(button, true); DWORD flags = mapButton(button, true);
@ -318,8 +173,7 @@ void
CMSWindowsSecondaryScreen::mouseUp(ButtonID button) CMSWindowsSecondaryScreen::mouseUp(ButtonID button)
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
assert(m_window != NULL); m_screen->syncDesktop();
syncDesktop();
// map button id to button flag // map button id to button flag
DWORD flags = mapButton(button, false); DWORD flags = mapButton(button, false);
@ -334,8 +188,7 @@ void
CMSWindowsSecondaryScreen::mouseMove(SInt32 x, SInt32 y) CMSWindowsSecondaryScreen::mouseMove(SInt32 x, SInt32 y)
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
assert(m_window != NULL); m_screen->syncDesktop();
syncDesktop();
warpCursor(x, y); warpCursor(x, y);
} }
@ -343,61 +196,50 @@ void
CMSWindowsSecondaryScreen::mouseWheel(SInt32 delta) CMSWindowsSecondaryScreen::mouseWheel(SInt32 delta)
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
assert(m_window != NULL); m_screen->syncDesktop();
syncDesktop();
mouse_event(MOUSEEVENTF_WHEEL, 0, 0, delta, 0); mouse_event(MOUSEEVENTF_WHEEL, 0, 0, delta, 0);
} }
void IScreen*
CMSWindowsSecondaryScreen::setClipboard(ClipboardID /*id*/, CMSWindowsSecondaryScreen::getScreen() const
const IClipboard* src)
{ {
CLock lock(&m_mutex); return m_screen;
assert(m_window != NULL);
CMSWindowsClipboard dst(m_window);
CClipboard::copy(&dst, src);
} }
void void
CMSWindowsSecondaryScreen::grabClipboard(ClipboardID /*id*/) CMSWindowsSecondaryScreen::onError()
{ {
CLock lock(&m_mutex); // ignore
assert(m_window != NULL);
CMSWindowsClipboard clipboard(m_window);
if (clipboard.open(0)) {
clipboard.close();
}
} }
void void
CMSWindowsSecondaryScreen::screenSaver(bool activate) CMSWindowsSecondaryScreen::onScreensaver(bool)
{ {
if (activate) { // ignore
getScreenSaver()->activate();
}
else {
getScreenSaver()->deactivate();
}
} }
void bool
CMSWindowsSecondaryScreen::getMousePos(SInt32& x, SInt32& y) const CMSWindowsSecondaryScreen::onPreDispatch(const CEvent*)
{ {
CLock lock(&m_mutex); return false;
assert(m_window != NULL);
syncDesktop();
getCursorPos(x, y);
} }
void bool
CMSWindowsSecondaryScreen::getShape( CMSWindowsSecondaryScreen::onEvent(CEvent* event)
SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
{ {
getScreenShape(x, y, w, h); assert(event != NULL);
const MSG& msg = event->m_msg;
switch (msg.message) {
case WM_ACTIVATEAPP:
if (msg.wParam == FALSE) {
// some other app activated. hide the hider window.
ShowWindow(m_window, SW_HIDE);
}
break;
}
return false;
} }
SInt32 SInt32
@ -407,153 +249,63 @@ CMSWindowsSecondaryScreen::getJumpZoneSize() const
} }
void void
CMSWindowsSecondaryScreen::getClipboard(ClipboardID /*id*/, CMSWindowsSecondaryScreen::postCreateWindow(HWND window)
IClipboard* dst) const {
m_window = window;
if (!isActive()) {
showWindow();
}
}
void
CMSWindowsSecondaryScreen::preDestroyWindow(HWND)
{
// do nothing
}
void
CMSWindowsSecondaryScreen::onPreRun()
{ {
CLock lock(&m_mutex);
assert(m_window != NULL); assert(m_window != NULL);
CMSWindowsClipboard src(m_window);
CClipboard::copy(dst, &src);
} }
bool void
CMSWindowsSecondaryScreen::onPreDispatch(const CEvent* event) CMSWindowsSecondaryScreen::onPreOpen()
{ {
assert(event != NULL); assert(m_window == NULL);
// forward to superclass
if (CMSWindowsScreen::onPreDispatch(event)) {
return true;
} }
// handle event void
const MSG* msg = &event->m_msg; CMSWindowsSecondaryScreen::onPreEnter()
switch (msg->message) {
case WM_TIMER:
// if current desktop is not the input desktop then switch to it
if (!m_is95Family) {
HDESK desk = openInputDesktop();
if (desk != NULL) {
if (isCurrentDesktop(desk)) {
CloseDesktop(desk);
}
else {
switchDesktop(desk);
}
}
}
return true;
}
return false;
}
bool
CMSWindowsSecondaryScreen::onEvent(CEvent* event)
{ {
assert(event != NULL); assert(m_window != NULL);
const MSG& msg = event->msg;
switch (msg.message) {
case WM_QUERYENDSESSION:
if (m_is95Family) {
event->m_result = TRUE;
return true;
}
break;
case WM_ENDSESSION:
if (m_is95Family) {
if (msg.wParam == TRUE && msg.lParam == 0) {
stop();
}
return true;
}
break;
case WM_PAINT:
ValidateRect(msg.hwnd, NULL);
return true;
case WM_ACTIVATEAPP:
if (msg.wParam == FALSE) {
// some other app activated. hide the hider window.
ShowWindow(m_window, SW_HIDE);
}
break;
case WM_DRAWCLIPBOARD:
log((CLOG_DEBUG "clipboard was taken"));
// first pass it on
if (m_nextClipboardWindow != NULL) {
SendMessage(m_nextClipboardWindow,
msg.message, msg.wParam, msg.lParam);
} }
// now notify client that somebody changed the clipboard (unless void
// we're now the owner, in which case it's because we took CMSWindowsSecondaryScreen::onPreLeave()
// ownership, or now it's owned by nobody, which will happen if
// we owned it and switched desktops because we destroy our
// window to do that).
try {
m_clipboardOwner = GetClipboardOwner();
if (m_clipboardOwner != m_window && m_clipboardOwner != NULL) {
m_receiver->onGrabClipboard(kClipboardClipboard);
m_receiver->onGrabClipboard(kClipboardSelection);
}
}
catch (XBadClient&) {
// ignore. this can happen if we receive this event
// before we've fully started up.
}
return true;
case WM_CHANGECBCHAIN:
if (m_nextClipboardWindow == (HWND)msg.wParam) {
m_nextClipboardWindow = (HWND)msg.lParam;
}
else if (m_nextClipboardWindow != NULL) {
SendMessage(m_nextClipboardWindow,
msg.message, msg.wParam, msg.lParam);
}
return true;
case WM_DISPLAYCHANGE:
{ {
// screen resolution may have changed. get old shape. assert(m_window != NULL);
SInt32 xOld, yOld, wOld, hOld;
getScreenShape(xOld, yOld, wOld, hOld);
// update shape
updateScreenShape();
m_multimon = isMultimon();
// collect new screen info
CClientInfo info;
getScreenShape(info.m_x, info.m_y, info.m_w, info.m_h);
getCursorPos(info.m_mx, info.m_my);
info.m_zoneSize = getJumpZoneSize();
// do nothing if resolution hasn't changed
if (info.m_x != xOld || info.m_y != yOld ||
info.m_w != wOld || info.m_h != hOld) {
// send new screen info
m_receiver->onInfoChanged(info);
} }
return true; void
} CMSWindowsSecondaryScreen::createWindow()
}
return false;
}
CString
CMSWindowsSecondaryScreen::getCurrentDesktopName() const
{ {
return m_deskName; // open the desktop and the window
m_window = m_screen->openDesktop();
if (m_window == NULL) {
throw XScreenOpenFailure();
}
}
void
CMSWindowsSecondaryScreen::destroyWindow()
{
// release keys that are logically pressed
releaseKeys();
// close the desktop and the window
m_screen->closeDesktop();
m_window = NULL;
} }
void void
@ -580,9 +332,9 @@ CMSWindowsSecondaryScreen::warpCursor(SInt32 x, SInt32 y)
{ {
// move the mouse directly to target position on NT family or if // move the mouse directly to target position on NT family or if
// not using multiple monitors. // not using multiple monitors.
if (!m_multimon || !m_is95Family) { if (m_screen->isMultimon() || !m_is95Family) {
SInt32 x0, y0, w, h; SInt32 x0, y0, w, h;
getScreenShape(x0, y0, w, h); m_screen->getShape(x0, y0, w, h);
mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,
(DWORD)((65535.99 * (x - x0)) / (w - 1)), (DWORD)((65535.99 * (x - x0)) / (w - 1)),
(DWORD)((65535.99 * (y - y0)) / (h - 1)), (DWORD)((65535.99 * (y - y0)) / (h - 1)),
@ -653,259 +405,70 @@ CMSWindowsSecondaryScreen::warpCursor(SInt32 x, SInt32 y)
} }
void void
CMSWindowsSecondaryScreen::checkClipboard() CMSWindowsSecondaryScreen::updateKeys()
{ {
// if we think we own the clipboard but we don't then somebody // clear key state
// grabbed the clipboard on this screen without us knowing. memset(m_keys, 0, sizeof(m_keys));
// tell the server that this screen grabbed the clipboard.
// // we only care about the modifier key states
// this works around bugs in the clipboard viewer chain. m_keys[VK_LSHIFT] = static_cast<BYTE>(GetKeyState(VK_LSHIFT));
// sometimes NT will simply never send WM_DRAWCLIPBOARD m_keys[VK_RSHIFT] = static_cast<BYTE>(GetKeyState(VK_RSHIFT));
// messages for no apparent reason and rebooting fixes the m_keys[VK_SHIFT] = static_cast<BYTE>(GetKeyState(VK_SHIFT));
// problem. since we don't want a broken clipboard until the m_keys[VK_LCONTROL] = static_cast<BYTE>(GetKeyState(VK_LCONTROL));
// next reboot we do this double check. clipboard ownership m_keys[VK_RCONTROL] = static_cast<BYTE>(GetKeyState(VK_RCONTROL));
// won't be reflected on other screens until we leave but at m_keys[VK_CONTROL] = static_cast<BYTE>(GetKeyState(VK_CONTROL));
// least the clipboard itself will work. m_keys[VK_LMENU] = static_cast<BYTE>(GetKeyState(VK_LMENU));
HWND clipboardOwner = GetClipboardOwner(); m_keys[VK_RMENU] = static_cast<BYTE>(GetKeyState(VK_RMENU));
if (m_clipboardOwner != clipboardOwner) { m_keys[VK_MENU] = static_cast<BYTE>(GetKeyState(VK_MENU));
try { m_keys[VK_LWIN] = static_cast<BYTE>(GetKeyState(VK_LWIN));
m_clipboardOwner = clipboardOwner; m_keys[VK_RWIN] = static_cast<BYTE>(GetKeyState(VK_RWIN));
if (m_clipboardOwner != m_window && m_clipboardOwner != NULL) { m_keys[VK_APPS] = static_cast<BYTE>(GetKeyState(VK_APPS));
m_receiver->onGrabClipboard(kClipboardClipboard); m_keys[VK_CAPITAL] = static_cast<BYTE>(GetKeyState(VK_CAPITAL));
m_receiver->onGrabClipboard(kClipboardSelection); m_keys[VK_NUMLOCK] = static_cast<BYTE>(GetKeyState(VK_NUMLOCK));
m_keys[VK_SCROLL] = static_cast<BYTE>(GetKeyState(VK_SCROLL));
// update active modifier mask
m_mask = 0;
if ((m_keys[VK_LSHIFT] & 0x80) != 0 || (m_keys[VK_RSHIFT] & 0x80) != 0) {
m_mask |= KeyModifierShift;
} }
if ((m_keys[VK_LCONTROL] & 0x80) != 0 ||
(m_keys[VK_RCONTROL] & 0x80) != 0) {
m_mask |= KeyModifierControl;
} }
catch (XBadClient&) { if ((m_keys[VK_LMENU] & 0x80) != 0 || (m_keys[VK_RMENU] & 0x80) != 0) {
// ignore m_mask |= KeyModifierAlt;
} }
if ((m_keys[VK_LWIN] & 0x80) != 0 || (m_keys[VK_RWIN] & 0x80) != 0) {
m_mask |= KeyModifierMeta;
} }
if ((m_keys[VK_CAPITAL] & 0x01) != 0) {
m_mask |= KeyModifierCapsLock;
}
if ((m_keys[VK_NUMLOCK] & 0x01) != 0) {
m_mask |= KeyModifierNumLock;
}
if ((m_keys[VK_SCROLL] & 0x01) != 0) {
m_mask |= KeyModifierScrollLock;
}
log((CLOG_DEBUG2 "modifiers on update: 0x%04x", m_mask));
} }
void void
CMSWindowsPrimaryScreen::createWindow() CMSWindowsSecondaryScreen::setToggleState(KeyModifierMask mask)
{ {
// save thread id // toggle modifiers that don't match the desired state
m_threadID = GetCurrentThreadId(); if ((mask & KeyModifierCapsLock) != (m_mask & KeyModifierCapsLock)) {
toggleKey(VK_CAPITAL, KeyModifierCapsLock);
// note if using multiple monitors
m_multimon = isMultimon();
// get the input desktop and switch to it
if (m_is95Family) {
if (!openDesktop()) {
throw XScreenOpenFailure();
} }
if ((mask & KeyModifierNumLock) != (m_mask & KeyModifierNumLock)) {
toggleKey(VK_NUMLOCK | 0x100, KeyModifierNumLock);
} }
else { if ((mask & KeyModifierScrollLock) != (m_mask & KeyModifierScrollLock)) {
if (!switchDesktop(openInputDesktop())) { toggleKey(VK_SCROLL, KeyModifierScrollLock);
throw XScreenOpenFailure();
} }
} }
// poll input desktop to see if it changes (onPreDispatch()
// handles WM_TIMER)
m_timer = 0;
if (!m_is95Family) {
m_timer = SetTimer(NULL, 0, 200, NULL);
}
}
void
CMSWindowsPrimaryScreen::destroyWindow()
{
// remove timer
if (m_timer != 0) {
KillTimer(NULL, m_timer);
}
// release keys that are logically pressed
releaseKeys();
// disconnect from desktop
if (m_is95Family) {
closeDesktop();
}
else {
switchDesktop(NULL);
}
// clear thread id
m_threadID = 0;
assert(m_window == NULL);
assert(m_desk == NULL);
}
void
CMSWindowsSecondaryScreen::installScreenSaver()
{
getScreenSaver()->disable();
}
void
CMSWindowsSecondaryScreen::uninstallScreenSaver()
{
getScreenSaver()->enable();
}
bool
CMSWindowsSecondaryScreen::openDesktop()
{
CLock lock(&m_mutex);
// initialize clipboard owner to current owner. we don't want
// to take ownership of the clipboard just by starting up.
m_clipboardOwner = GetClipboardOwner();
// create the cursor hiding window. this window is used to hide the
// cursor when it's not on the screen. the window is hidden as soon
// as the cursor enters the screen or the display's real cursor is
// moved.
m_window = CreateWindowEx(WS_EX_TOPMOST |
WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW,
(LPCTSTR)getClass(), "Synergy",
WS_POPUP,
0, 0, 1, 1, NULL, NULL,
getInstance(),
NULL);
// install our clipboard snooper
m_nextClipboardWindow = SetClipboardViewer(m_window);
return true;
}
void
CMSWindowsSecondaryScreen::closeDesktop()
{
CLock lock(&m_mutex);
if (m_window != NULL) {
// remove clipboard snooper
ChangeClipboardChain(m_window, m_nextClipboardWindow);
m_nextClipboardWindow = NULL;
// destroy window
DestroyWindow(m_window);
m_window = NULL;
}
}
bool
CMSWindowsSecondaryScreen::switchDesktop(HDESK desk)
{
CLock lock(&m_mutex);
bool ownClipboard = false;
if (m_window != NULL) {
// note if we own the clipboard
ownClipboard = (m_clipboardOwner == m_window);
// remove clipboard snooper
ChangeClipboardChain(m_window, m_nextClipboardWindow);
m_nextClipboardWindow = NULL;
// destroy window
DestroyWindow(m_window);
m_window = NULL;
}
// done with desktop
if (m_desk != NULL) {
CloseDesktop(m_desk);
m_desk = NULL;
m_deskName = "";
}
// if no new desktop then we're done
if (desk == NULL) {
log((CLOG_INFO "disconnecting desktop"));
return true;
}
// set the desktop. can only do this when there are no windows
// and hooks on the current desktop owned by this thread.
if (SetThreadDesktop(desk) == 0) {
log((CLOG_ERR "failed to set desktop: %d", GetLastError()));
CloseDesktop(desk);
return false;
}
// initialize clipboard owner to current owner. we don't want
// to take ownership of the clipboard just by starting up.
m_clipboardOwner = GetClipboardOwner();
// create the cursor hiding window. this window is used to hide the
// cursor when it's not on the screen. the window is hidden as soon
// as the cursor enters the screen or the display's real cursor is
// moved.
m_window = CreateWindowEx(WS_EX_TOPMOST |
WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW,
(LPCTSTR)getClass(), "Synergy",
WS_POPUP,
0, 0, 1, 1, NULL, NULL,
getInstance(),
NULL);
if (m_window == NULL) {
log((CLOG_ERR "failed to create window: %d", GetLastError()));
CloseDesktop(desk);
return false;
}
// install our clipboard snooper
m_nextClipboardWindow = SetClipboardViewer(m_window);
// if we owned the desktop then set the clipboard owner
if (ownClipboard) {
m_clipboardOwner = GetClipboardOwner();
}
// save new desktop
m_desk = desk;
m_deskName = getDesktopName(m_desk);
log((CLOG_INFO "switched to desktop %s", m_deskName.c_str()));
// get desktop up to date
if (!m_active) {
showWindow();
}
return true;
}
void
CMSWindowsSecondaryScreen::syncDesktop() const
{
// note -- mutex must be locked on entry
// change calling thread's desktop
if (!m_is95Family) {
if (SetThreadDesktop(m_desk) == 0) {
log((CLOG_WARN "failed to set desktop: %d", GetLastError()));
}
}
// attach input queues if not already attached. this has a habit
// of sucking up more and more CPU each time it's called (even if
// the threads are already attached). since we only expect one
// thread to call this more than once we can save just the last
// the attached thread.
DWORD threadID = GetCurrentThreadId();
if (threadID != m_lastThreadID && threadID != m_threadID) {
m_lastThreadID = threadID;
AttachThreadInput(threadID, m_threadID, TRUE);
}
}
bool
CMSWindowsSecondaryScreen::isMultimon() const
{
SInt32 x0, y0, w, h;
getScreenShape(x0, y0, w, h);
return (w != GetSystemMetrics(SM_CXSCREEN) ||
h != GetSystemMetrics(SM_CYSCREEN));
}
// these tables map KeyID (a X windows KeySym) to virtual key codes. // these tables map KeyID (a X windows KeySym) to virtual key codes.
// if the key is an extended key then the entry is the virtual key // if the key is an extended key then the entry is the virtual key
// code | 0x100. keys that map to normal characters have a 0 entry // code | 0x100. keys that map to normal characters have a 0 entry
@ -1768,7 +1331,7 @@ CMSWindowsSecondaryScreen::releaseKeys()
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
syncDesktop(); m_screen->syncDesktop();
// release left/right modifier keys first. if the platform doesn't // release left/right modifier keys first. if the platform doesn't
// support them then they won't be set and the non-side-distinuishing // support them then they won't be set and the non-side-distinuishing
@ -1814,60 +1377,6 @@ CMSWindowsSecondaryScreen::releaseKeys()
} }
} }
void
CMSWindowsSecondaryScreen::updateKeys()
{
// clear key state
memset(m_keys, 0, sizeof(m_keys));
// we only care about the modifier key states
m_keys[VK_LSHIFT] = static_cast<BYTE>(GetKeyState(VK_LSHIFT));
m_keys[VK_RSHIFT] = static_cast<BYTE>(GetKeyState(VK_RSHIFT));
m_keys[VK_SHIFT] = static_cast<BYTE>(GetKeyState(VK_SHIFT));
m_keys[VK_LCONTROL] = static_cast<BYTE>(GetKeyState(VK_LCONTROL));
m_keys[VK_RCONTROL] = static_cast<BYTE>(GetKeyState(VK_RCONTROL));
m_keys[VK_CONTROL] = static_cast<BYTE>(GetKeyState(VK_CONTROL));
m_keys[VK_LMENU] = static_cast<BYTE>(GetKeyState(VK_LMENU));
m_keys[VK_RMENU] = static_cast<BYTE>(GetKeyState(VK_RMENU));
m_keys[VK_MENU] = static_cast<BYTE>(GetKeyState(VK_MENU));
m_keys[VK_LWIN] = static_cast<BYTE>(GetKeyState(VK_LWIN));
m_keys[VK_RWIN] = static_cast<BYTE>(GetKeyState(VK_RWIN));
m_keys[VK_APPS] = static_cast<BYTE>(GetKeyState(VK_APPS));
m_keys[VK_CAPITAL] = static_cast<BYTE>(GetKeyState(VK_CAPITAL));
m_keys[VK_NUMLOCK] = static_cast<BYTE>(GetKeyState(VK_NUMLOCK));
m_keys[VK_SCROLL] = static_cast<BYTE>(GetKeyState(VK_SCROLL));
}
void
CMSWindowsSecondaryScreen::updateModifiers()
{
// update active modifier mask
m_mask = 0;
if ((m_keys[VK_LSHIFT] & 0x80) != 0 || (m_keys[VK_RSHIFT] & 0x80) != 0) {
m_mask |= KeyModifierShift;
}
if ((m_keys[VK_LCONTROL] & 0x80) != 0 ||
(m_keys[VK_RCONTROL] & 0x80) != 0) {
m_mask |= KeyModifierControl;
}
if ((m_keys[VK_LMENU] & 0x80) != 0 || (m_keys[VK_RMENU] & 0x80) != 0) {
m_mask |= KeyModifierAlt;
}
if ((m_keys[VK_LWIN] & 0x80) != 0 || (m_keys[VK_RWIN] & 0x80) != 0) {
m_mask |= KeyModifierMeta;
}
if ((m_keys[VK_CAPITAL] & 0x01) != 0) {
m_mask |= KeyModifierCapsLock;
}
if ((m_keys[VK_NUMLOCK] & 0x01) != 0) {
m_mask |= KeyModifierNumLock;
}
if ((m_keys[VK_SCROLL] & 0x01) != 0) {
m_mask |= KeyModifierScrollLock;
}
log((CLOG_DEBUG2 "modifiers on update: 0x%04x", m_mask));
}
void void
CMSWindowsSecondaryScreen::toggleKey(UINT virtualKey, KeyModifierMask mask) CMSWindowsSecondaryScreen::toggleKey(UINT virtualKey, KeyModifierMask mask)
{ {

View File

@ -7,28 +7,22 @@
#define _WIN32_WINNT 0x401 #define _WIN32_WINNT 0x401
#endif #endif
#include "CMSWindowsScreen.h" #include "CSecondaryScreen.h"
#include "ISecondaryScreen.h" #include "IMSWindowsScreenEventHandler.h"
#include "CMutex.h" #include "CMutex.h"
#include "CString.h" #include "CString.h"
#include "stdvector.h" #include "stdvector.h"
class CMSWindowsScreen;
class IScreenReceiver; class IScreenReceiver;
class CMSWindowsSecondaryScreen : public CMSWindowsScreen, class CMSWindowsSecondaryScreen :
public ISecondaryScreen { public CSecondaryScreen, public IMSWindowsScreenEventHandler {
public: public:
CMSWindowsSecondaryScreen(IScreenReceiver*); CMSWindowsSecondaryScreen(IScreenReceiver*);
virtual ~CMSWindowsSecondaryScreen(); virtual ~CMSWindowsSecondaryScreen();
// ISecondaryScreen overrides // CSecondaryScreen overrides
virtual void run();
virtual void stop();
virtual void open();
virtual void close();
virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute,
KeyModifierMask mask);
virtual void leave();
virtual void keyDown(KeyID, KeyModifierMask); virtual void keyDown(KeyID, KeyModifierMask);
virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count); virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count);
virtual void keyUp(KeyID, KeyModifierMask); virtual void keyUp(KeyID, KeyModifierMask);
@ -36,19 +30,30 @@ public:
virtual void mouseUp(ButtonID); virtual void mouseUp(ButtonID);
virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute); virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute);
virtual void mouseWheel(SInt32 delta); virtual void mouseWheel(SInt32 delta);
virtual void setClipboard(ClipboardID, const IClipboard*); virtual IScreen* getScreen() const;
virtual void grabClipboard(ClipboardID);
virtual void screenSaver(bool activate);
virtual void getMousePos(SInt32& x, SInt32& y) const;
virtual void getShape(SInt32&, SInt32&, SInt32&, SInt32&) const;
virtual SInt32 getJumpZoneSize() const;
virtual void getClipboard(ClipboardID, IClipboard*) const;
protected: // IMSWindowsScreenEventHandler overrides
// CMSWindowsScreen overrides virtual void onError();
virtual void onScreensaver(bool activated);
virtual bool onPreDispatch(const CEvent* event); virtual bool onPreDispatch(const CEvent* event);
virtual bool onEvent(CEvent* event); virtual bool onEvent(CEvent* event);
virtual CString getCurrentDesktopName() const; virtual SInt32 getJumpZoneSize() const;
virtual void postCreateWindow(HWND);
virtual void preDestroyWindow(HWND);
protected:
// CSecondaryScreen overrides
virtual void onPreRun();
virtual void onPreOpen();
virtual void onPreEnter();
virtual void onPreLeave();
virtual void createWindow();
virtual void destroyWindow();
virtual void showWindow();
virtual void hideWindow();
virtual void warpCursor(SInt32 x, SInt32 y);
virtual void updateKeys();
virtual void setToggleState(KeyModifierMask);
private: private:
enum EKeyAction { kPress, kRelease, kRepeat }; enum EKeyAction { kPress, kRelease, kRepeat };
@ -60,26 +65,6 @@ private:
}; };
typedef std::vector<Keystroke> Keystrokes; typedef std::vector<Keystroke> Keystrokes;
void showWindow();
void hideWindow();
// warp the mouse to the specified position
void warpCursor(SInt32 x, SInt32 y);
// check clipboard ownership and, if necessary, tell the receiver
// of a grab.
void checkClipboard();
// create/destroy window
// also attach to desktop; this destroys and recreates the window
// as necessary.
void createWindow();
void destroyWindow();
// start/stop watch for screen saver changes
void installScreenSaver();
void uninstallScreenSaver();
// open/close desktop (for windows 95/98/me) // open/close desktop (for windows 95/98/me)
bool openDesktop(); bool openDesktop();
void closeDesktop(); void closeDesktop();
@ -87,9 +72,6 @@ private:
// make desk the thread desktop (for windows NT/2000/XP) // make desk the thread desktop (for windows NT/2000/XP)
bool switchDesktop(HDESK desk); bool switchDesktop(HDESK desk);
// get calling thread to use the input desktop
void syncDesktop() const;
// returns true iff there appear to be multiple monitors // returns true iff there appear to be multiple monitors
bool isMultimon() const; bool isMultimon() const;
@ -100,8 +82,6 @@ private:
void doKeystrokes(const Keystrokes&, SInt32 count); void doKeystrokes(const Keystrokes&, SInt32 count);
void releaseKeys(); void releaseKeys();
void updateKeys();
void updateModifiers();
void toggleKey(UINT virtualKey, KeyModifierMask mask); void toggleKey(UINT virtualKey, KeyModifierMask mask);
UINT virtualKeyToScanCode(UINT& virtualKey); UINT virtualKeyToScanCode(UINT& virtualKey);
bool isExtendedKey(UINT virtualKey); bool isExtendedKey(UINT virtualKey);
@ -109,37 +89,14 @@ private:
private: private:
CMutex m_mutex; CMutex m_mutex;
IScreenReceiver* m_receiver; CMSWindowsScreen* m_screen;
// true if windows 95/98/me // true if windows 95/98/me
bool m_is95Family; bool m_is95Family;
// true if system appears to have multiple monitors // our window
bool m_multimon;
// the main loop's thread id
DWORD m_threadID;
// the timer used to check for desktop switching
UINT m_timer;
// the thread id of the last attached thread
mutable DWORD m_lastThreadID;
// the current desk and it's name
HDESK m_desk;
CString m_deskName;
// our window (for getting clipboard changes)
HWND m_window; HWND m_window;
// m_active is true if this screen has been entered
bool m_active;
// clipboard stuff
HWND m_nextClipboardWindow;
HWND m_clipboardOwner;
// virtual key states // virtual key states
BYTE m_keys[256]; BYTE m_keys[256];

View File

@ -74,7 +74,7 @@ CSecondaryScreen::open()
updateKeys(); updateKeys();
// disable the screen saver // disable the screen saver
getScreen()->openScreenSaver(false); getScreen()->openScreensaver(false);
// subclass hook // subclass hook
onPostOpen(); onPostOpen();
@ -93,7 +93,7 @@ void
CSecondaryScreen::close() CSecondaryScreen::close()
{ {
onPreClose(); onPreClose();
getScreen()->closeScreenSaver(); getScreen()->closeScreensaver();
destroyWindow(); destroyWindow();
getScreen()->close(); getScreen()->close();
onPostClose(); onPostClose();
@ -182,12 +182,6 @@ CSecondaryScreen::getClipboard(ClipboardID id,
getScreen()->getClipboard(id, clipboard); getScreen()->getClipboard(id, clipboard);
} }
SInt32
CSecondaryScreen::getJumpZoneSize() const
{
return 0;
}
void void
CSecondaryScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const CSecondaryScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
{ {

View File

@ -78,8 +78,8 @@ public:
void getClipboard(ClipboardID, IClipboard*) const; void getClipboard(ClipboardID, IClipboard*) const;
// returns the size of the zone on the edges of the screen that // returns the size of the zone on the edges of the screen that
// causes the cursor to jump to another screen. default returns 0. // causes the cursor to jump to another screen.
virtual SInt32 getJumpZoneSize() const; virtual SInt32 getJumpZoneSize() const = 0;
// get the shape (position of upper-left corner and size) of the // get the shape (position of upper-left corner and size) of the
// screen // screen

View File

@ -145,12 +145,6 @@ CXWindowsSecondaryScreen::getScreen() const
return m_screen; return m_screen;
} }
void
CXWindowsSecondaryScreen::onScreensaver(bool)
{
// ignore
}
void void
CXWindowsSecondaryScreen::onError() CXWindowsSecondaryScreen::onError()
{ {
@ -158,6 +152,12 @@ CXWindowsSecondaryScreen::onError()
// FIXME -- forward this? to whom? // FIXME -- forward this? to whom?
} }
void
CXWindowsSecondaryScreen::onScreensaver(bool)
{
// ignore
}
bool bool
CXWindowsSecondaryScreen::onPreDispatch(const CEvent*) CXWindowsSecondaryScreen::onPreDispatch(const CEvent*)
{ {
@ -184,6 +184,12 @@ CXWindowsSecondaryScreen::onEvent(CEvent* event)
} }
} }
SInt32
CXWindowsSecondaryScreen::getJumpZoneSize() const
{
return 0;
}
void void
CXWindowsSecondaryScreen::onPreRun() CXWindowsSecondaryScreen::onPreRun()
{ {
@ -260,7 +266,7 @@ CXWindowsSecondaryScreen::createWindow()
XTestGrabControl(display, True); XTestGrabControl(display, True);
} }
// tell our superclass about the window // tell generic screen about the window
m_screen->setWindow(m_window); m_screen->setWindow(m_window);
} }
@ -275,15 +281,19 @@ CXWindowsSecondaryScreen::destroyWindow()
// no longer impervious to server grabs // no longer impervious to server grabs
XTestGrabControl(display, False); XTestGrabControl(display, False);
// destroy window
if (m_window != None) {
XDestroyWindow(display, m_window);
m_window = None;
}
// update // update
XSync(display, False); XSync(display, False);
} }
// destroy window
if (m_window != None) {
m_screen->setWindow(None);
CDisplayLock display(m_screen);
if (display != NULL) {
XDestroyWindow(display, m_window);
}
m_window = None;
}
} }
void void

View File

@ -35,6 +35,7 @@ public:
virtual void onScreensaver(bool activated); virtual void onScreensaver(bool activated);
virtual bool onPreDispatch(const CEvent* event); virtual bool onPreDispatch(const CEvent* event);
virtual bool onEvent(CEvent* event); virtual bool onEvent(CEvent* event);
virtual SInt32 getJumpZoneSize() const;
protected: protected:
// CSecondaryScreen overrides // CSecondaryScreen overrides

View File

@ -110,6 +110,10 @@ SOURCE=.\CMSWindowsSecondaryScreen.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\CSecondaryScreen.cpp
# End Source File
# Begin Source File
SOURCE=.\CServerProxy.cpp SOURCE=.\CServerProxy.cpp
# End Source File # End Source File
# End Group # End Group
@ -126,11 +130,11 @@ SOURCE=.\CMSWindowsSecondaryScreen.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\CServerProxy.h SOURCE=.\CSecondaryScreen.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\ISecondaryScreen.h SOURCE=.\CServerProxy.h
# End Source File # End Source File
# Begin Source File # Begin Source File

View File

@ -1,5 +1,10 @@
#include "CMSWindowsScreen.h" #include "CMSWindowsScreen.h"
#include "CMSWindowsClipboard.h"
#include "CMSWindowsScreenSaver.h" #include "CMSWindowsScreenSaver.h"
#include "CClipboard.h"
#include "IMSWindowsScreenEventHandler.h"
#include "IScreenReceiver.h"
#include "XSynergy.h"
#include "CThread.h" #include "CThread.h"
#include "CLock.h" #include "CLock.h"
#include "TMethodJob.h" #include "TMethodJob.h"
@ -8,7 +13,7 @@
#include <cstring> #include <cstring>
// //
// add backwards compatible multihead support (suppress bogus warning) // add backwards compatible multihead support (and suppress bogus warning)
// //
#pragma warning(push) #pragma warning(push)
#pragma warning(disable: 4706) // assignment within conditional #pragma warning(disable: 4706) // assignment within conditional
@ -23,21 +28,46 @@
HINSTANCE CMSWindowsScreen::s_instance = NULL; HINSTANCE CMSWindowsScreen::s_instance = NULL;
CMSWindowsScreen* CMSWindowsScreen::s_screen = NULL; CMSWindowsScreen* CMSWindowsScreen::s_screen = NULL;
CMSWindowsScreen::CMSWindowsScreen() : CMSWindowsScreen::CMSWindowsScreen(IScreenReceiver* receiver,
m_class(0), IMSWindowsScreenEventHandler* eventHandler) :
m_receiver(receiver),
m_eventHandler(eventHandler),
m_class(NULL),
m_icon(NULL),
m_cursor(NULL), m_cursor(NULL),
m_window(NULL),
m_x(0), m_y(0), m_x(0), m_y(0),
m_w(0), m_h(0), m_w(0), m_h(0),
m_thread(0), m_multimon(false),
m_screenSaver(NULL) m_threadID(0),
m_lastThreadID(0),
m_nextClipboardWindow(NULL),
m_clipboardOwner(NULL),
m_timer(0),
m_desk(NULL),
m_deskName(),
m_hookLibrary(NULL),
m_installScreensaver(NULL),
m_uninstallScreensaver(NULL),
m_screensaver(NULL),
m_screensaverNotify(false)
{ {
assert(s_screen == NULL); assert(s_screen == NULL);
assert(m_receiver != NULL);
assert(m_eventHandler != NULL);
s_screen = this; s_screen = this;
// make sure this thread has a message queue
MSG dummy;
PeekMessage(&dummy, NULL, WM_USER, WM_USER, PM_NOREMOVE);
} }
CMSWindowsScreen::~CMSWindowsScreen() CMSWindowsScreen::~CMSWindowsScreen()
{ {
assert(s_screen != NULL);
assert(m_class == 0); assert(m_class == 0);
s_screen = NULL; s_screen = NULL;
} }
@ -47,11 +77,110 @@ CMSWindowsScreen::init(HINSTANCE instance)
s_instance = instance; s_instance = instance;
} }
HWND
CMSWindowsScreen::openDesktop()
{
// save thread id
m_threadID = GetCurrentThreadId();
// get the input desktop and switch to it
if (!switchDesktop(openInputDesktop())) {
return NULL;
}
// poll input desktop to see if it changes (onPreDispatch()
// handles WM_TIMER)
m_timer = 0;
if (!m_is95Family) {
m_timer = SetTimer(NULL, 0, 200, NULL);
}
return m_window;
}
void
CMSWindowsScreen::closeDesktop()
{
// remove timer
if (m_timer != 0) {
KillTimer(NULL, m_timer);
}
// disconnect from desktop
switchDesktop(NULL);
// clear thread id
m_threadID = 0;
assert(m_window == NULL);
assert(m_desk == NULL);
}
bool
CMSWindowsScreen::isMultimon() const
{
return m_multimon;
}
HINSTANCE
CMSWindowsScreen::getInstance()
{
return s_instance;
}
void
CMSWindowsScreen::open()
{
assert(s_instance != NULL);
assert(m_class == 0);
log((CLOG_DEBUG "opening display"));
// create the transparent cursor
createBlankCursor();
// 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 shape
updateScreenShape();
// initialize the screen saver
m_screensaver = new CMSWindowsScreenSaver();
// load the hook library and get the screen saver functions
m_hookLibrary = LoadLibrary("synrgyhk");
if (m_hookLibrary != NULL) {
m_installScreensaver = (InstallScreenSaverFunc)GetProcAddress(
m_hookLibrary, "installScreenSaver");
m_uninstallScreensaver = (UninstallScreenSaverFunc)GetProcAddress(
m_hookLibrary, "uninstallScreenSaver");
if (m_installScreensaver == NULL || m_uninstallScreensaver == NULL) {
// disable if either install or uninstall is unavailable
m_installScreensaver = NULL;
m_uninstallScreensaver = NULL;
}
}
}
void void
CMSWindowsScreen::mainLoop() CMSWindowsScreen::mainLoop()
{ {
// save thread id for posting quit message // must call mainLoop() from same thread as openDesktop()
m_thread = GetCurrentThreadId(); assert(m_threadID == GetCurrentThreadId());
// event loop // event loop
CEvent event; CEvent event;
@ -77,55 +206,25 @@ CMSWindowsScreen::mainLoop()
void void
CMSWindowsScreen::exitMainLoop() CMSWindowsScreen::exitMainLoop()
{ {
PostThreadMessage(m_thread, WM_QUIT, 0, 0); PostThreadMessage(m_threadID, WM_QUIT, 0, 0);
}
bool
CMSWindowsScreen::onPreDispatch(const CEvent*)
{
return false;
} }
void void
CMSWindowsScreen::openDisplay() CMSWindowsScreen::close()
{ {
assert(s_instance != NULL); assert(s_instance != NULL);
assert(m_class == 0);
// create the transparent cursor // done with hook library
createBlankCursor(); if (m_hookLibrary != NULL) {
FreeLibrary(m_hookLibrary);
// register a window class m_installScreensaver = NULL;
WNDCLASSEX classInfo; m_uninstallScreensaver = NULL;
classInfo.cbSize = sizeof(classInfo); m_hookLibrary = NULL;
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 shape
updateScreenShape();
// initialize the screen saver
m_screenSaver = new CMSWindowsScreenSaver();
} }
void
CMSWindowsScreen::closeDisplay()
{
assert(s_instance != NULL);
// done with screen saver // done with screen saver
delete m_screenSaver; delete m_screensaver;
m_screenSaver = NULL; m_screensaver = NULL;
// unregister the window class // unregister the window class
if (m_class != 0) { if (m_class != 0) {
@ -142,30 +241,130 @@ CMSWindowsScreen::closeDisplay()
log((CLOG_DEBUG "closed display")); log((CLOG_DEBUG "closed display"));
} }
HINSTANCE bool
CMSWindowsScreen::getInstance() CMSWindowsScreen::setClipboard(ClipboardID, const IClipboard* src)
{ {
return s_instance; CMSWindowsClipboard dst(m_window);
if (src != NULL) {
// save clipboard data
return CClipboard::copy(&dst, src);
}
else {
// assert clipboard ownership
if (!dst.open(0)) {
return false;
}
dst.empty();
dst.close();
return true;
} }
ATOM
CMSWindowsScreen::getClass() const
{
return m_class;
} }
void void
CMSWindowsScreen::updateScreenShape() CMSWindowsScreen::checkClipboards()
{ {
m_x = GetSystemMetrics(SM_XVIRTUALSCREEN); // if we think we own the clipboard but we don't then somebody
m_y = GetSystemMetrics(SM_YVIRTUALSCREEN); // grabbed the clipboard on this screen without us knowing.
m_w = GetSystemMetrics(SM_CXVIRTUALSCREEN); // tell the server that this screen grabbed the clipboard.
m_h = GetSystemMetrics(SM_CYVIRTUALSCREEN); //
log((CLOG_INFO "screen shape: %d,%d %dx%d", m_x, m_y, m_w, m_h)); // this works around bugs in the clipboard viewer chain.
// sometimes NT will simply never send WM_DRAWCLIPBOARD
// messages for no apparent reason and rebooting fixes the
// problem. since we don't want a broken clipboard until the
// next reboot we do this double check. clipboard ownership
// won't be reflected on other screens until we leave but at
// least the clipboard itself will work.
HWND clipboardOwner = GetClipboardOwner();
if (m_clipboardOwner != clipboardOwner) {
try {
m_clipboardOwner = clipboardOwner;
if (m_clipboardOwner != m_window && m_clipboardOwner != NULL) {
m_receiver->onGrabClipboard(kClipboardClipboard);
m_receiver->onGrabClipboard(kClipboardSelection);
}
}
catch (XBadClient&) {
// ignore
}
}
} }
void void
CMSWindowsScreen::getScreenShape(SInt32& x, SInt32& y, CMSWindowsScreen::openScreensaver(bool notify)
{
assert(m_screensaver != NULL);
m_screensaverNotify = notify;
if (m_screensaverNotify) {
if (m_installScreensaver != NULL) {
m_installScreensaver();
}
}
else {
m_screensaver->disable();
}
}
void
CMSWindowsScreen::closeScreensaver()
{
if (m_screensaver != NULL) {
if (m_screensaverNotify) {
if (m_uninstallScreensaver != NULL) {
m_uninstallScreensaver();
}
}
else {
m_screensaver->enable();
}
}
m_screensaverNotify = false;
}
void
CMSWindowsScreen::screensaver(bool activate)
{
assert(m_screensaver != NULL);
if (activate) {
m_screensaver->activate();
}
else {
m_screensaver->deactivate();
}
}
void
CMSWindowsScreen::syncDesktop()
{
// change calling thread's desktop
if (!m_is95Family) {
if (SetThreadDesktop(m_desk) == 0) {
log((CLOG_WARN "failed to set desktop: %d", GetLastError()));
}
}
// attach input queues if not already attached. this has a habit
// of sucking up more and more CPU each time it's called (even if
// the threads are already attached). since we only expect one
// thread to call this more than once we can save just the last
// the attached thread.
DWORD threadID = GetCurrentThreadId();
if (threadID != m_lastThreadID && threadID != m_threadID) {
m_lastThreadID = threadID;
AttachThreadInput(threadID, m_threadID, TRUE);
}
}
bool
CMSWindowsScreen::getClipboard(ClipboardID, IClipboard* dst) const
{
CMSWindowsClipboard src(m_window);
CClipboard::copy(dst, &src);
return true;
}
void
CMSWindowsScreen::getShape(SInt32& x, SInt32& y,
SInt32& w, SInt32& h) const SInt32& w, SInt32& h) const
{ {
assert(m_class != 0); assert(m_class != 0);
@ -196,10 +395,153 @@ CMSWindowsScreen::getCursorCenter(SInt32& x, SInt32& y) const
y = GetSystemMetrics(SM_CYSCREEN) >> 1; y = GetSystemMetrics(SM_CYSCREEN) >> 1;
} }
HCURSOR void
CMSWindowsScreen::getBlankCursor() const CMSWindowsScreen::updateScreenShape()
{ {
return m_cursor; // get shape
m_x = GetSystemMetrics(SM_XVIRTUALSCREEN);
m_y = GetSystemMetrics(SM_YVIRTUALSCREEN);
m_w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
m_h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
log((CLOG_INFO "screen shape: %d,%d %dx%d", m_x, m_y, m_w, m_h));
// check for multiple monitors
m_multimon = (m_w != GetSystemMetrics(SM_CXSCREEN) ||
m_h != GetSystemMetrics(SM_CYSCREEN));
}
bool
CMSWindowsScreen::onPreDispatch(const CEvent* event)
{
// handle event
const MSG* msg = &event->m_msg;
switch (msg->message) {
case SYNERGY_MSG_SCREEN_SAVER:
if (msg->wParam != 0) {
if (m_screensaver->checkStarted(msg->message, FALSE, 0)) {
m_eventHandler->onScreensaver(true);
}
}
else {
m_eventHandler->onScreensaver(false);
}
return true;
case WM_TIMER:
// if current desktop is not the input desktop then switch to it.
// windows 95 doesn't support multiple desktops so don't bother
// to check under it.
if (!m_is95Family) {
HDESK desk = openInputDesktop();
if (desk != NULL) {
if (isCurrentDesktop(desk)) {
CloseDesktop(desk);
}
else {
switchDesktop(desk);
}
}
}
return true;
}
return m_eventHandler->onPreDispatch(event);
}
bool
CMSWindowsScreen::onEvent(CEvent* event)
{
assert(event != NULL);
const MSG& msg = event->m_msg;
switch (msg.message) {
case WM_QUERYENDSESSION:
if (m_is95Family) {
event->m_result = TRUE;
return true;
}
break;
case WM_ENDSESSION:
if (m_is95Family) {
if (msg.wParam == TRUE && msg.lParam == 0) {
exitMainLoop();
}
return true;
}
break;
case WM_PAINT:
ValidateRect(msg.hwnd, NULL);
return true;
case WM_DRAWCLIPBOARD:
log((CLOG_DEBUG "clipboard was taken"));
// first pass it on
if (m_nextClipboardWindow != NULL) {
SendMessage(m_nextClipboardWindow,
msg.message, msg.wParam, msg.lParam);
}
// now notify client that somebody changed the clipboard (unless
// we're now the owner, in which case it's because we took
// ownership, or now it's owned by nobody, which will happen if
// we owned it and switched desktops because we destroy our
// window to do that).
try {
m_clipboardOwner = GetClipboardOwner();
if (m_clipboardOwner != m_window && m_clipboardOwner != NULL) {
m_receiver->onGrabClipboard(kClipboardClipboard);
m_receiver->onGrabClipboard(kClipboardSelection);
}
}
catch (XBadClient&) {
// ignore. this can happen if we receive this event
// before we've fully started up.
}
return true;
case WM_CHANGECBCHAIN:
if (m_nextClipboardWindow == (HWND)msg.wParam) {
m_nextClipboardWindow = (HWND)msg.lParam;
}
else if (m_nextClipboardWindow != NULL) {
SendMessage(m_nextClipboardWindow,
msg.message, msg.wParam, msg.lParam);
}
return true;
case WM_DISPLAYCHANGE:
{
// screen resolution may have changed. get old shape.
SInt32 xOld, yOld, wOld, hOld;
getShape(xOld, yOld, wOld, hOld);
// update shape
updateScreenShape();
// collect new screen info
CClientInfo info;
getShape(info.m_x, info.m_y, info.m_w, info.m_h);
getCursorPos(info.m_mx, info.m_my);
info.m_zoneSize = m_eventHandler->getJumpZoneSize();
// do nothing if resolution hasn't changed
if (info.m_x != xOld || info.m_y != yOld ||
info.m_w != wOld || info.m_h != hOld) {
// forward event
m_eventHandler->onEvent(event);
// send new screen info
m_receiver->onInfoChanged(info);
}
return true;
}
}
return m_eventHandler->onEvent(event);
} }
void void
@ -217,14 +559,122 @@ CMSWindowsScreen::createBlankCursor()
delete[] cursorAND; delete[] cursorAND;
} }
bool
CMSWindowsScreen::switchDesktop(HDESK desk)
{
// did we own the clipboard?
bool ownClipboard = (m_clipboardOwner == m_window && m_window != NULL);
// destroy old window
if (m_window != NULL) {
// first remove clipboard snooper
ChangeClipboardChain(m_window, m_nextClipboardWindow);
m_nextClipboardWindow = NULL;
// we no longer own the clipboard
if (ownClipboard) {
m_clipboardOwner = NULL;
}
// let client clean up before we destroy the window
m_eventHandler->preDestroyWindow(m_window);
// now destroy window
DestroyWindow(m_window);
m_window = NULL;
// done with desk
if (!m_is95Family) {
CloseDesktop(m_desk);
}
m_desk = NULL;
m_deskName = "";
}
// if no new desktop then we're done
if (desk == NULL) {
log((CLOG_INFO "disconnecting desktop"));
return true;
}
// uninstall screen saver hooks
if (m_screensaverNotify) {
if (m_uninstallScreensaver != NULL) {
m_uninstallScreensaver();
}
}
// set the desktop. can only do this when there are no windows
// and hooks on the current desktop owned by this thread.
if (SetThreadDesktop(desk) == 0) {
log((CLOG_ERR "failed to set desktop: %d", GetLastError()));
if (!m_is95Family) {
CloseDesktop(desk);
}
return false;
}
// create the window
m_window = CreateWindowEx(WS_EX_TOPMOST |
WS_EX_TRANSPARENT |
WS_EX_TOOLWINDOW,
(LPCTSTR)m_class,
"Synergy",
WS_POPUP,
0, 0, 1, 1,
NULL, NULL,
getInstance(),
NULL);
if (m_window == NULL) {
log((CLOG_ERR "failed to create window: %d", GetLastError()));
if (!m_is95Family) {
CloseDesktop(desk);
}
return false;
}
// reinstall screen saver hooks
if (m_screensaverNotify) {
if (m_installScreensaver != NULL) {
m_installScreensaver();
}
}
// install our clipboard snooper
m_nextClipboardWindow = SetClipboardViewer(m_window);
// reassert clipboard ownership
if (ownClipboard) {
// FIXME -- take clipboard ownership, but we should also set
// the clipboard data.
}
m_clipboardOwner = GetClipboardOwner();
// save new desktop
m_desk = desk;
m_deskName = getDesktopName(m_desk);
log((CLOG_INFO "switched to desktop \"%s\"", m_deskName.c_str()));
// let client prepare the window
m_eventHandler->postCreateWindow(m_window);
return true;
}
HDESK HDESK
CMSWindowsScreen::openInputDesktop() const CMSWindowsScreen::openInputDesktop() const
{ {
if (m_is95Family) {
// there's only one desktop on windows 95 et al.
return GetThreadDesktop(GetCurrentThreadId());
}
else {
return OpenInputDesktop(DF_ALLOWOTHERACCOUNTHOOK, TRUE, return OpenInputDesktop(DF_ALLOWOTHERACCOUNTHOOK, TRUE,
DESKTOP_CREATEWINDOW | DESKTOP_CREATEWINDOW |
DESKTOP_HOOKCONTROL | DESKTOP_HOOKCONTROL |
GENERIC_WRITE); GENERIC_WRITE);
} }
}
CString CString
CMSWindowsScreen::getDesktopName(HDESK desk) const CMSWindowsScreen::getDesktopName(HDESK desk) const
@ -232,6 +682,9 @@ CMSWindowsScreen::getDesktopName(HDESK desk) const
if (desk == NULL) { if (desk == NULL) {
return CString(); return CString();
} }
else if (m_is95Family) {
return "desktop";
}
else { else {
DWORD size; DWORD size;
GetUserObjectInformation(desk, UOI_NAME, NULL, 0, &size); GetUserObjectInformation(desk, UOI_NAME, NULL, 0, &size);
@ -246,14 +699,7 @@ CMSWindowsScreen::getDesktopName(HDESK desk) const
bool bool
CMSWindowsScreen::isCurrentDesktop(HDESK desk) const CMSWindowsScreen::isCurrentDesktop(HDESK desk) const
{ {
return CStringUtil::CaselessCmp::equal(getDesktopName(desk), return CStringUtil::CaselessCmp::equal(getDesktopName(desk), m_deskName);
getCurrentDesktopName());
}
CMSWindowsScreenSaver*
CMSWindowsScreen::getScreenSaver() const
{
return m_screenSaver;
} }
LRESULT CALLBACK LRESULT CALLBACK

View File

@ -1,7 +1,8 @@
#ifndef CMSWINDOWSSCREEN_H #ifndef CMSWINDOWSSCREEN_H
#define CMSWINDOWSSCREEN_H #define CMSWINDOWSSCREEN_H
#include "IClipboard.h" #include "IScreen.h"
#include "CSynergyHook.h"
#include "CMutex.h" #include "CMutex.h"
#include "CString.h" #include "CString.h"
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
@ -16,52 +17,69 @@ public:
LRESULT m_result; LRESULT m_result;
}; };
class CMSWindowsScreen { class IScreenReceiver;
class IMSWindowsScreenEventHandler;
class CMSWindowsScreen : public IScreen {
public: public:
CMSWindowsScreen(); CMSWindowsScreen(IScreenReceiver*, IMSWindowsScreenEventHandler*);
virtual ~CMSWindowsScreen(); virtual ~CMSWindowsScreen();
// manipulators // manipulators
static void init(HINSTANCE); static void init(HINSTANCE);
// open the desktop and create and return the window. returns NULL
// on failure.
HWND openDesktop();
// close the window and desktop
void closeDesktop();
// accessors // accessors
// returns true iff the system appears to have multiple monitors
bool isMultimon() const;
// get the application instance handle // get the application instance handle
static HINSTANCE getInstance(); static HINSTANCE getInstance();
protected: // IScreen overrides
// runs an event loop and returns when exitMainLoop() is called // note -- this class expects the hook DLL to have been loaded
// and initialized before open() is called.
void open();
void mainLoop(); void mainLoop();
// force mainLoop() to return
void exitMainLoop(); void exitMainLoop();
void close();
bool setClipboard(ClipboardID, const IClipboard*);
void checkClipboards();
void openScreensaver(bool notify);
void closeScreensaver();
void screensaver(bool activate);
void syncDesktop();
bool getClipboard(ClipboardID, IClipboard*) const;
void getShape(SInt32&, SInt32&, SInt32&, SInt32&) const;
void getCursorPos(SInt32&, SInt32&) const;
void getCursorCenter(SInt32&, SInt32&) const;
// open the X display. calls onOpenDisplay() after opening the display, private:
// getting the screen, its size, and root window. then it starts the
// event thread.
void openDisplay();
// destroy the window and close the display. calls onCloseDisplay()
// after the event thread has been shut down but before the display
// is closed.
void closeDisplay();
// get the registered window class atom
ATOM getClass() const;
// update screen size cache // update screen size cache
void updateScreenShape(); void updateScreenShape();
// get the size of the screen // internal pre-dispatch event processing
void getScreenShape(SInt32& x, SInt32& y, bool onPreDispatch(const CEvent* event);
SInt32& width, SInt32& height) const;
// get the current cursor position // internal (post-dispatch) event processing
void getCursorPos(SInt32& x, SInt32& y) const; bool onEvent(CEvent* event);
// get the cursor center position // create the transparent cursor
void getCursorCenter(SInt32& x, SInt32& y) const; void createBlankCursor();
// switch to the given desktop. this destroys the window and unhooks
// all hooks, switches the desktop, then creates the window and rehooks
// all hooks (because you can't switch the thread's desktop if it has
// any windows or hooks).
bool switchDesktop(HDESK desk);
// get the input desktop. caller must CloseDesktop() the result. // get the input desktop. caller must CloseDesktop() the result.
// do not call under windows 95/98/me. // do not call under windows 95/98/me.
@ -74,38 +92,56 @@ protected:
// windows 95/98/me. // windows 95/98/me.
bool isCurrentDesktop(HDESK desk) const; bool isCurrentDesktop(HDESK desk) const;
// get the screen saver object
CMSWindowsScreenSaver*
getScreenSaver() const;
// called for each event before event translation and dispatch. return
// true to skip translation and dispatch. subclasses should call the
// superclass's version first and return true if it returns true.
virtual bool onPreDispatch(const CEvent* event);
// called by mainLoop(). iff the event was handled return true and
// store the result, if any, in m_result, which defaults to zero.
virtual bool onEvent(CEvent* event) = 0;
// called by isCurrentDesktop() to get the current desktop name
virtual CString getCurrentDesktopName() const = 0;
private:
// create the transparent cursor
void createBlankCursor();
// our window proc // our window proc
static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM); static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM);
private: private:
static HINSTANCE s_instance; static HINSTANCE s_instance;
IScreenReceiver* m_receiver;
IMSWindowsScreenEventHandler* m_eventHandler;
ATOM m_class; ATOM m_class;
HICON m_icon; HICON m_icon;
HCURSOR m_cursor; HCURSOR m_cursor;
// true if windows 95/98/me
bool m_is95Family;
// our window
HWND m_window;
// screen shape
SInt32 m_x, m_y; SInt32 m_x, m_y;
SInt32 m_w, m_h; SInt32 m_w, m_h;
DWORD m_thread;
CMSWindowsScreenSaver* m_screenSaver; // true if system appears to have multiple monitors
bool m_multimon;
// the main loop's thread id
DWORD m_threadID;
// the thread id of the last attached thread
DWORD m_lastThreadID;
// clipboard stuff
HWND m_nextClipboardWindow;
HWND m_clipboardOwner;
// the timer used to check for desktop switching
UINT m_timer;
// the current desk and it's name
HDESK m_desk;
CString m_deskName;
// screen saver stuff
HINSTANCE m_hookLibrary;
InstallScreenSaverFunc m_installScreensaver;
UninstallScreenSaverFunc m_uninstallScreensaver;
CMSWindowsScreenSaver* m_screensaver;
bool m_screensaverNotify;
static CMSWindowsScreen* s_screen; static CMSWindowsScreen* s_screen;
}; };

View File

@ -10,8 +10,6 @@
#include "CThread.h" #include "CThread.h"
#include "CLog.h" #include "CLog.h"
#include "IJob.h" #include "IJob.h"
//#include "CString.h"
//#include <cstdlib>
#include <cstring> #include <cstring>
#if defined(X_DISPLAY_MISSING) #if defined(X_DISPLAY_MISSING)
# error X11 is required to build synergy # error X11 is required to build synergy
@ -310,7 +308,7 @@ CXWindowsScreen::checkClipboards()
} }
void void
CXWindowsScreen::openScreenSaver(bool notify) CXWindowsScreen::openScreensaver(bool notify)
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
assert(m_screensaver != NULL); assert(m_screensaver != NULL);
@ -325,7 +323,7 @@ CXWindowsScreen::openScreenSaver(bool notify)
} }
void void
CXWindowsScreen::closeScreenSaver() CXWindowsScreen::closeScreensaver()
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
if (m_screensaver != NULL) { if (m_screensaver != NULL) {

View File

@ -2,7 +2,6 @@
#define CXWINDOWSSCREEN_H #define CXWINDOWSSCREEN_H
#include "IScreen.h" #include "IScreen.h"
#include "ClipboardTypes.h"
#include "CMutex.h" #include "CMutex.h"
#include "CStopwatch.h" #include "CStopwatch.h"
#include "stdvector.h" #include "stdvector.h"
@ -59,8 +58,8 @@ public:
void close(); void close();
bool setClipboard(ClipboardID, const IClipboard*); bool setClipboard(ClipboardID, const IClipboard*);
void checkClipboards(); void checkClipboards();
void openScreenSaver(bool notify); void openScreensaver(bool notify);
void closeScreenSaver(); void closeScreensaver();
void screensaver(bool activate); void screensaver(bool activate);
void syncDesktop(); void syncDesktop();
bool getClipboard(ClipboardID, IClipboard*) const; bool getClipboard(ClipboardID, IClipboard*) const;

View File

@ -0,0 +1,26 @@
#ifndef IMSWINDOWSSCREENEVENTHANDLER_H
#define IMSWINDOWSSCREENEVENTHANDLER_H
#include "IScreenEventHandler.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
class IMSWindowsScreenEventHandler : public IScreenEventHandler {
public:
// manipulators
// called after the window is created
virtual void postCreateWindow(HWND) = 0;
// called before the window is destroyed
virtual void preDestroyWindow(HWND) = 0;
// IScreenEventHandler overrides
virtual void onError() = 0;
virtual void onScreensaver(bool activated) = 0;
virtual bool onPreDispatch(const CEvent* event) = 0;
virtual bool onEvent(CEvent* event) = 0;
virtual SInt32 getJumpZoneSize() const = 0;
};
#endif

View File

@ -127,6 +127,10 @@ SOURCE=.\CWin32Platform.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\IMSWindowsScreenEventHandler.h
# End Source File
# Begin Source File
SOURCE=.\IPlatform.h SOURCE=.\IPlatform.h
# End Source File # End Source File
# End Group # End Group

View File

@ -624,22 +624,22 @@ operator<<(std::ostream& s, const CConfig& config)
screen != config.end(); ++screen) { screen != config.end(); ++screen) {
s << "\t" << screen->c_str() << ":" << std::endl; s << "\t" << screen->c_str() << ":" << std::endl;
neighbor = config.getNeighbor(*screen, CConfig::kLeft); neighbor = config.getNeighbor(*screen, kLeft);
if (!neighbor.empty()) { if (!neighbor.empty()) {
s << "\t\tleft=" << neighbor.c_str() << std::endl; s << "\t\tleft=" << neighbor.c_str() << std::endl;
} }
neighbor = config.getNeighbor(*screen, CConfig::kRight); neighbor = config.getNeighbor(*screen, kRight);
if (!neighbor.empty()) { if (!neighbor.empty()) {
s << "\t\tright=" << neighbor.c_str() << std::endl; s << "\t\tright=" << neighbor.c_str() << std::endl;
} }
neighbor = config.getNeighbor(*screen, CConfig::kTop); neighbor = config.getNeighbor(*screen, kTop);
if (!neighbor.empty()) { if (!neighbor.empty()) {
s << "\t\tup=" << neighbor.c_str() << std::endl; s << "\t\tup=" << neighbor.c_str() << std::endl;
} }
neighbor = config.getNeighbor(*screen, CConfig::kBottom); neighbor = config.getNeighbor(*screen, kBottom);
if (!neighbor.empty()) { if (!neighbor.empty()) {
s << "\t\tdown=" << neighbor.c_str() << std::endl; s << "\t\tdown=" << neighbor.c_str() << std::endl;
} }

View File

@ -1,6 +1,7 @@
#ifndef CCONFIG_H #ifndef CCONFIG_H
#define CCONFIG_H #define CCONFIG_H
#include "ProtocolTypes.h"
#include "CNetworkAddress.h" #include "CNetworkAddress.h"
#include "XBase.h" #include "XBase.h"
#include "stdmap.h" #include "stdmap.h"
@ -20,11 +21,6 @@ struct iterator_traits<CConfig> {
}; };
class CConfig { class CConfig {
public:
enum EDirection { kLeft, kRight, kTop, kBottom,
kFirstDirection = kLeft, kLastDirection = kBottom };
enum EDirectionMask { kLeftMask = 1, kRightMask = 2,
kTopMask = 4, kBottomMask = 8 };
private: private:
class CCell { class CCell {
public: public:

View File

@ -649,7 +649,7 @@ CHTTPServer::CScreenArray::convertFrom(const CConfig& config)
// insert the screen's neighbors // insert the screen's neighbors
// FIXME -- handle edge wrapping // FIXME -- handle edge wrapping
CString neighbor; CString neighbor;
neighbor = config.getNeighbor(name, CConfig::kLeft); neighbor = config.getNeighbor(name, kLeft);
if (!neighbor.empty() && doneSet.count(neighbor) == 0) { if (!neighbor.empty() && doneSet.count(neighbor) == 0) {
// insert left neighbor, adding a column if necessary // insert left neighbor, adding a column if necessary
if (x == 0 || get(x - 1, y) != neighbor) { if (x == 0 || get(x - 1, y) != neighbor) {
@ -659,7 +659,7 @@ CHTTPServer::CScreenArray::convertFrom(const CConfig& config)
} }
screenStack.push_back(neighbor); screenStack.push_back(neighbor);
} }
neighbor = config.getNeighbor(name, CConfig::kRight); neighbor = config.getNeighbor(name, kRight);
if (!neighbor.empty() && doneSet.count(neighbor) == 0) { if (!neighbor.empty() && doneSet.count(neighbor) == 0) {
// insert right neighbor, adding a column if necessary // insert right neighbor, adding a column if necessary
if (x == m_w - 1 || get(x + 1, y) != neighbor) { if (x == m_w - 1 || get(x + 1, y) != neighbor) {
@ -668,7 +668,7 @@ CHTTPServer::CScreenArray::convertFrom(const CConfig& config)
} }
screenStack.push_back(neighbor); screenStack.push_back(neighbor);
} }
neighbor = config.getNeighbor(name, CConfig::kTop); neighbor = config.getNeighbor(name, kTop);
if (!neighbor.empty() && doneSet.count(neighbor) == 0) { if (!neighbor.empty() && doneSet.count(neighbor) == 0) {
// insert top neighbor, adding a row if necessary // insert top neighbor, adding a row if necessary
if (y == 0 || get(x, y - 1) != neighbor) { if (y == 0 || get(x, y - 1) != neighbor) {
@ -678,7 +678,7 @@ CHTTPServer::CScreenArray::convertFrom(const CConfig& config)
} }
screenStack.push_back(neighbor); screenStack.push_back(neighbor);
} }
neighbor = config.getNeighbor(name, CConfig::kBottom); neighbor = config.getNeighbor(name, kBottom);
if (!neighbor.empty() && doneSet.count(neighbor) == 0) { if (!neighbor.empty() && doneSet.count(neighbor) == 0) {
// insert bottom neighbor, adding a row if necessary // insert bottom neighbor, adding a row if necessary
if (y == m_h - 1 || get(x, y + 1) != neighbor) { if (y == m_h - 1 || get(x, y + 1) != neighbor) {
@ -699,25 +699,25 @@ CHTTPServer::CScreenArray::convertFrom(const CConfig& config)
} }
CString neighbor; CString neighbor;
neighbor = config.getNeighbor(name, CConfig::kLeft); neighbor = config.getNeighbor(name, kLeft);
if ((x == 0 && !neighbor.empty()) || if ((x == 0 && !neighbor.empty()) ||
(x > 0 && get(x - 1, y) != neighbor)) { (x > 0 && get(x - 1, y) != neighbor)) {
return false; return false;
} }
neighbor = config.getNeighbor(name, CConfig::kRight); neighbor = config.getNeighbor(name, kRight);
if ((x == m_w - 1 && !neighbor.empty()) || if ((x == m_w - 1 && !neighbor.empty()) ||
(x < m_w - 1 && get(x + 1, y) != neighbor)) { (x < m_w - 1 && get(x + 1, y) != neighbor)) {
return false; return false;
} }
neighbor = config.getNeighbor(name, CConfig::kTop); neighbor = config.getNeighbor(name, kTop);
if ((y == 0 && !neighbor.empty()) || if ((y == 0 && !neighbor.empty()) ||
(y > 0 && get(x, y - 1) != neighbor)) { (y > 0 && get(x, y - 1) != neighbor)) {
return false; return false;
} }
neighbor = config.getNeighbor(name, CConfig::kBottom); neighbor = config.getNeighbor(name, kBottom);
if ((y == m_h - 1 && !neighbor.empty()) || if ((y == m_h - 1 && !neighbor.empty()) ||
(y < m_h - 1 && get(x, y + 1) != neighbor)) { (y < m_h - 1 && get(x, y + 1) != neighbor)) {
return false; return false;
@ -764,24 +764,16 @@ CHTTPServer::CScreenArray::convertTo(CConfig& config) const
continue; continue;
} }
if (x > x0 && isSet(x - 1, y)) { if (x > x0 && isSet(x - 1, y)) {
config.connect(get(x, y), config.connect(get(x, y), kLeft, get(x - 1, y));
CConfig::kLeft,
get(x - 1, y));
} }
if (x < x1 && isSet(x + 1, y)) { if (x < x1 && isSet(x + 1, y)) {
config.connect(get(x, y), config.connect(get(x, y), kRight, get(x + 1, y));
CConfig::kRight,
get(x + 1, y));
} }
if (y > y0 && isSet(x, y - 1)) { if (y > y0 && isSet(x, y - 1)) {
config.connect(get(x, y), config.connect(get(x, y), kTop, get(x, y - 1));
CConfig::kTop,
get(x, y - 1));
} }
if (y < y1 && isSet(x, y + 1)) { if (y < y1 && isSet(x, y + 1)) {
config.connect(get(x, y), config.connect(get(x, y), kBottom, get(x, y + 1));
CConfig::kBottom,
get(x, y + 1));
} }
} }
} }

View File

@ -1,14 +1,8 @@
#include "CMSWindowsPrimaryScreen.h" #include "CMSWindowsPrimaryScreen.h"
#include "IScreenReceiver.h" #include "CMSWindowsScreen.h"
#include "IPrimaryScreenReceiver.h" #include "IPrimaryScreenReceiver.h"
#include "CMSWindowsClipboard.h"
#include "CMSWindowsScreenSaver.h"
#include "CPlatform.h" #include "CPlatform.h"
#include "CClipboard.h"
#include "ProtocolTypes.h"
#include "XScreen.h" #include "XScreen.h"
#include "XSynergy.h"
#include "CThread.h"
#include "CLog.h" #include "CLog.h"
#include <cstring> #include <cstring>
@ -19,21 +13,16 @@
CMSWindowsPrimaryScreen::CMSWindowsPrimaryScreen( CMSWindowsPrimaryScreen::CMSWindowsPrimaryScreen(
IScreenReceiver* receiver, IScreenReceiver* receiver,
IPrimaryScreenReceiver* primaryReceiver) : IPrimaryScreenReceiver* primaryReceiver) :
m_receiver(receiver), CPrimaryScreen(receiver),
m_primaryReceiver(primaryReceiver), m_receiver(primaryReceiver),
m_is95Family(CPlatform::isWindows95Family()),
m_threadID(0), m_threadID(0),
m_timer(0),
m_desk(NULL),
m_deskName(),
m_window(NULL), m_window(NULL),
m_active(false),
m_mark(0), m_mark(0),
m_markReceived(0), m_markReceived(0),
m_nextClipboardWindow(NULL), m_mouseMoveIgnore(0)
m_clipboardOwner(NULL)
{ {
assert(m_receiver != NULL); assert(m_receiver != NULL);
assert(m_primaryReceiver != NULL);
// load the hook library // load the hook library
m_hookLibrary = LoadLibrary("synrgyhk"); m_hookLibrary = LoadLibrary("synrgyhk");
@ -60,22 +49,8 @@ CMSWindowsPrimaryScreen::CMSWindowsPrimaryScreen(
throw XScreenOpenFailure(); throw XScreenOpenFailure();
} }
// get the screen saver functions // create screen
m_installScreenSaver = (InstallScreenSaverFunc)GetProcAddress( m_screen = new CMSWindowsScreen(receiver, this);
m_hookLibrary, "installScreenSaver");
m_uninstallScreenSaver = (UninstallScreenSaverFunc)GetProcAddress(
m_hookLibrary, "uninstallScreenSaver");
if (m_installScreenSaver == NULL || m_uninstallScreenSaver == NULL) {
// disable uninstall if install is unavailable
m_uninstallScreenSaver = NULL;
}
// detect operating system
m_is95Family = CPlatform::isWindows95Family();
// make sure this thread has a message queue
MSG dummy;
PeekMessage(&dummy, NULL, WM_USER, WM_USER, PM_NOREMOVE);
} }
CMSWindowsPrimaryScreen::~CMSWindowsPrimaryScreen() CMSWindowsPrimaryScreen::~CMSWindowsPrimaryScreen()
@ -83,169 +58,10 @@ CMSWindowsPrimaryScreen::~CMSWindowsPrimaryScreen()
assert(m_hookLibrary != NULL); assert(m_hookLibrary != NULL);
assert(m_window == NULL); assert(m_window == NULL);
// done with hook library delete m_screen;
FreeLibrary(m_hookLibrary); FreeLibrary(m_hookLibrary);
} }
void
CMSWindowsPrimaryScreen::run()
{
// must call run() from same thread as open()
assert(m_threadID == GetCurrentThreadId());
// change our priority
CThread::getCurrentThread().setPriority(-3);
// run event loop
try {
log((CLOG_INFO "entering event loop"));
mainLoop();
log((CLOG_INFO "exiting event loop"));
}
catch (...) {
log((CLOG_INFO "exiting event loop"));
throw;
}
}
void
CMSWindowsPrimaryScreen::stop()
{
exitMainLoop();
}
void
CMSWindowsPrimaryScreen::open()
{
assert(m_window == NULL);
CClientInfo info;
try {
// initialize hook library
m_threadID = GetCurrentThreadId();
m_init(m_threadID);
// open the display
openDisplay();
// create and prepare our window
createWindow();
// set jump zones
m_setZone(info.m_x, info.m_y, info.m_w, info.m_h, info.m_zoneSize);
// initialize marks
m_mark = 0;
m_markReceived = 0;
nextMark();
// collect screen info
getScreenShape(info.m_x, info.m_y, info.m_w, info.m_h);
getCursorPos(info.m_mx, info.m_my);
info.m_zoneSize = getJumpZoneSize();
// save mouse position
m_x = info.m_mx;
m_y = info.m_my;
// compute center pixel of primary screen
getCursorCenter(m_xCenter, m_yCenter);
// get keyboard state
updateKeys();
// get notified of screen saver activation/deactivation
installScreenSaver();
}
catch (...) {
close();
throw;
}
// enter the screen
enterNoWarp();
// send screen info
m_receiver->onInfoChanged(info);
}
void
CMSWindowsPrimaryScreen::close()
{
uninstallScreenSaver();
destroyWindow();
closeDisplay();
m_cleanup();
m_threadID = 0;
}
void
CMSWindowsPrimaryScreen::enter(SInt32 x, SInt32 y, bool forScreenSaver)
{
log((CLOG_INFO "entering primary at %d,%d%s", x, y, forScreenSaver ? " for screen saver" : ""));
assert(m_active == true);
assert(m_window != NULL);
// enter the screen
enterNoWarp();
// warp to requested location
if (!forScreenSaver) {
warpCursor(x, y);
}
}
bool
CMSWindowsPrimaryScreen::leave()
{
log((CLOG_INFO "leaving primary"));
assert(m_active == false);
assert(m_window != NULL);
// all messages prior to now are invalid
nextMark();
// show our window
if (!showWindow()) {
return false;
}
// relay all mouse and keyboard events
m_setRelay(true);
// get state of keys as we leave
updateKeys();
// warp mouse to center of screen
warpCursorToCenter();
// ignore this many mouse motion events (not including the already
// queued events). on (at least) the win2k login desktop, one
// motion event is reported using a position from before the above
// warpCursor(). i don't know why it does that and other desktops
// don't have the same problem. anyway, simply ignoring that event
// works around it.
// FIXME -- is this true now that we're using mouse_event?
m_mouseMoveIgnore = 1;
// disable ctrl+alt+del, alt+tab, etc
if (m_is95Family) {
DWORD dummy = 0;
SystemParametersInfo(SPI_SETSCREENSAVERRUNNING, TRUE, &dummy, 0);
}
// discard messages until after the warp
nextMark();
// local client now active
m_active = true;
// make sure our idea of clipboard ownership is correct
checkClipboard();
return true;
}
void void
CMSWindowsPrimaryScreen::reconfigure(UInt32 activeSides) CMSWindowsPrimaryScreen::reconfigure(UInt32 activeSides)
{ {
@ -264,41 +80,6 @@ CMSWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y)
m_y = y; m_y = y;
} }
void
CMSWindowsPrimaryScreen::setClipboard(ClipboardID /*id*/,
const IClipboard* src)
{
// FIXME -- this is identical to CMSWindowsSecondaryScreen's code
assert(m_window != NULL);
CMSWindowsClipboard dst(m_window);
CClipboard::copy(&dst, src);
}
void
CMSWindowsPrimaryScreen::grabClipboard(ClipboardID /*id*/)
{
// FIXME -- this is identical to CMSWindowsSecondaryScreen's code
assert(m_window != NULL);
CMSWindowsClipboard clipboard(m_window);
if (clipboard.open(0)) {
// FIXME -- don't we need to empty it?
clipboard.close();
}
}
void
CMSWindowsPrimaryScreen::getClipboard(ClipboardID /*id*/,
IClipboard* dst) const
{
// FIXME -- this is identical to CMSWindowsSecondaryScreen's code
assert(m_window != NULL);
CMSWindowsClipboard src(m_window);
CClipboard::copy(dst, &src);
}
KeyModifierMask KeyModifierMask
CMSWindowsPrimaryScreen::getToggleMask() const CMSWindowsPrimaryScreen::getToggleMask() const
{ {
@ -334,7 +115,7 @@ CMSWindowsPrimaryScreen::isLockedToScreen() const
// that have been pulled off the queue. in general, we won't get // that have been pulled off the queue. in general, we won't get
// these key messages because they're not for our window. if any // these key messages because they're not for our window. if any
// key (or mouse button) is down then we're locked to the screen. // key (or mouse button) is down then we're locked to the screen.
if (m_active) { if (isActive()) {
// use shadow keyboard state in m_keys // use shadow keyboard state in m_keys
for (UInt32 i = 0; i < 256; ++i) { for (UInt32 i = 0; i < 256; ++i) {
if ((m_keys[i] & 0x80) != 0) { if ((m_keys[i] & 0x80) != 0) {
@ -358,16 +139,29 @@ CMSWindowsPrimaryScreen::isLockedToScreen() const
return false; return false;
} }
IScreen*
CMSWindowsPrimaryScreen::getScreen() const
{
return m_screen;
}
void
CMSWindowsPrimaryScreen::onError()
{
// ignore
}
void
CMSWindowsPrimaryScreen::onScreensaver(bool activated)
{
m_receiver->onScreensaver(activated);
}
bool bool
CMSWindowsPrimaryScreen::onPreTranslate(const CEvent* event) CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event)
{ {
assert(event != NULL); assert(event != NULL);
// forward to superclass
if (CMSWindowsScreen::onPreTranslate(event)) {
return true;
}
// handle event // handle event
const MSG* msg = &event->m_msg; const MSG* msg = &event->m_msg;
switch (msg->message) { switch (msg->message) {
@ -386,11 +180,11 @@ CMSWindowsPrimaryScreen::onPreTranslate(const CEvent* event)
const SInt32 repeat = (SInt32)(msg->lParam & 0xffff); const SInt32 repeat = (SInt32)(msg->lParam & 0xffff);
if (repeat >= 2) { if (repeat >= 2) {
log((CLOG_DEBUG1 "event: key repeat key=%d mask=0x%04x count=%d", key, mask, repeat)); log((CLOG_DEBUG1 "event: key repeat key=%d mask=0x%04x count=%d", key, mask, repeat));
m_primaryReceiver->onKeyRepeat(key, mask, repeat); m_receiver->onKeyRepeat(key, mask, repeat);
} }
else { else {
log((CLOG_DEBUG1 "event: key press key=%d mask=0x%04x", key, mask)); log((CLOG_DEBUG1 "event: key press key=%d mask=0x%04x", key, mask));
m_primaryReceiver->onKeyDown(key, mask); m_receiver->onKeyDown(key, mask);
} }
// update key state // update key state
@ -399,7 +193,7 @@ CMSWindowsPrimaryScreen::onPreTranslate(const CEvent* event)
else { else {
// key release // key release
log((CLOG_DEBUG1 "event: key release key=%d mask=0x%04x", key, mask)); log((CLOG_DEBUG1 "event: key release key=%d mask=0x%04x", key, mask));
m_primaryReceiver->onKeyUp(key, mask); m_receiver->onKeyUp(key, mask);
// update key state // update key state
updateKey(msg->wParam, false); updateKey(msg->wParam, false);
@ -428,7 +222,7 @@ CMSWindowsPrimaryScreen::onPreTranslate(const CEvent* event)
case WM_RBUTTONDOWN: case WM_RBUTTONDOWN:
log((CLOG_DEBUG1 "event: button press button=%d", button)); log((CLOG_DEBUG1 "event: button press button=%d", button));
if (button != kButtonNone) { if (button != kButtonNone) {
m_primaryReceiver->onMouseDown(button); m_receiver->onMouseDown(button);
m_keys[s_vkButton[button]] |= 0x80; m_keys[s_vkButton[button]] |= 0x80;
} }
break; break;
@ -438,7 +232,7 @@ CMSWindowsPrimaryScreen::onPreTranslate(const CEvent* event)
case WM_RBUTTONUP: case WM_RBUTTONUP:
log((CLOG_DEBUG1 "event: button release button=%d", button)); log((CLOG_DEBUG1 "event: button release button=%d", button));
if (button != kButtonNone) { if (button != kButtonNone) {
m_primaryReceiver->onMouseUp(button); m_receiver->onMouseUp(button);
m_keys[s_vkButton[button]] &= ~0x80; m_keys[s_vkButton[button]] &= ~0x80;
} }
break; break;
@ -450,7 +244,7 @@ CMSWindowsPrimaryScreen::onPreTranslate(const CEvent* event)
// ignore message if posted prior to last mark change // ignore message if posted prior to last mark change
if (m_markReceived == m_mark) { if (m_markReceived == m_mark) {
log((CLOG_ERR "event: button wheel delta=%d %d", msg->wParam, msg->lParam)); log((CLOG_ERR "event: button wheel delta=%d %d", msg->wParam, msg->lParam));
m_primaryReceiver->onMouseWheel(msg->wParam); m_receiver->onMouseWheel(msg->wParam);
} }
return true; return true;
@ -459,8 +253,8 @@ CMSWindowsPrimaryScreen::onPreTranslate(const CEvent* event)
if (m_markReceived == m_mark) { if (m_markReceived == m_mark) {
SInt32 x = static_cast<SInt32>(msg->wParam); SInt32 x = static_cast<SInt32>(msg->wParam);
SInt32 y = static_cast<SInt32>(msg->lParam); SInt32 y = static_cast<SInt32>(msg->lParam);
if (!m_active) { if (!isActive()) {
m_primaryReceiver->onMouseMovePrimary(x, y); m_receiver->onMouseMovePrimary(x, y);
} }
else { else {
// compute motion delta. this is relative to the // compute motion delta. this is relative to the
@ -480,7 +274,7 @@ CMSWindowsPrimaryScreen::onPreTranslate(const CEvent* event)
warpCursorToCenter(); warpCursorToCenter();
// send motion // send motion
m_primaryReceiver->onMouseMoveSecondary(x, y); m_receiver->onMouseMoveSecondary(x, y);
} }
} }
else { else {
@ -495,32 +289,6 @@ CMSWindowsPrimaryScreen::onPreTranslate(const CEvent* event)
m_x = static_cast<SInt32>(msg->wParam); m_x = static_cast<SInt32>(msg->wParam);
m_y = static_cast<SInt32>(msg->lParam); m_y = static_cast<SInt32>(msg->lParam);
return true; return true;
case SYNERGY_MSG_SCREEN_SAVER:
if (msg->wParam != 0) {
if (getScreenSaver()->checkStarted(msg->message, FALSE, 0)) {
m_primaryReceiver->onScreenSaver(true);
}
}
else {
m_primaryReceiver->onScreenSaver(false);
}
return true;
case WM_TIMER:
// if current desktop is not the input desktop then switch to it
if (!m_is95Family) {
HDESK desk = openInputDesktop();
if (desk != NULL) {
if (isCurrentDesktop(desk)) {
CloseDesktop(desk);
}
else {
switchDesktop(desk);
}
}
}
return true;
} }
return false; return false;
@ -531,111 +299,29 @@ CMSWindowsPrimaryScreen::onEvent(CEvent* event)
{ {
assert(event != NULL); assert(event != NULL);
const MSG& msg = event->msg; const MSG& msg = event->m_msg;
switch (msg.message) { switch (msg.message) {
case WM_QUERYENDSESSION:
if (m_is95Family) {
event->m_result = TRUE;
return true;
}
break;
case WM_ENDSESSION:
if (m_is95Family) {
if (msg.wParam == TRUE && msg.lParam == 0) {
stop();
}
return true;
}
break;
case WM_PAINT:
ValidateRect(msg.hwnd, NULL);
return true;
case WM_DRAWCLIPBOARD:
log((CLOG_DEBUG "clipboard was taken"));
// first pass it on
if (m_nextClipboardWindow != NULL) {
SendMessage(m_nextClipboardWindow,
msg.message, msg.wParam, msg.lParam);
}
// now notify server that somebody changed the clipboard.
// skip that if we're the new owner.
try {
m_clipboardOwner = GetClipboardOwner();
if (m_clipboardOwner != m_window && m_clipboardOwner != NULL) {
m_receiver->onGrabClipboard(kClipboardClipboard);
m_receiver->onGrabClipboard(kClipboardSelection);
}
}
catch (XBadClient&) {
// ignore. this can happen if we receive this event
// before we've fully started up.
}
return true;
case WM_CHANGECBCHAIN:
if (m_nextClipboardWindow == (HWND)msg.wParam) {
m_nextClipboardWindow = (HWND)msg.lParam;
}
else if (m_nextClipboardWindow != NULL) {
SendMessage(m_nextClipboardWindow,
msg.message, msg.wParam, msg.lParam);
}
return true;
case WM_DISPLAYCHANGE: case WM_DISPLAYCHANGE:
{
// screen resolution may have changed. get old shape.
SInt32 xOld, yOld, wOld, hOld;
getScreenShape(xOld, yOld, wOld, hOld);
// update shape
updateScreenShape();
// collect new screen info
CClientInfo info;
getScreenShape(info.m_x, info.m_y, info.m_w, info.m_h);
getCursorPos(info.m_mx, info.m_my);
info.m_zoneSize = getJumpZoneSize();
// do nothing if resolution hasn't changed
if (info.m_x != xOld || info.m_y != yOld ||
info.m_w != wOld || info.m_h != hOld) {
// recompute center pixel of primary screen // recompute center pixel of primary screen
getCursorCenter(m_xCenter, m_yCenter); m_screen->getCursorCenter(m_xCenter, m_yCenter);
// warp mouse to center if active // warp mouse to center if active
if (m_active) { if (isActive()) {
warpCursorToCenter(); warpCursorToCenter();
} }
// tell hook about resize if not active // tell hook about resize if not active
else { else {
m_setZone(info.m_x, info.m_y, SInt32 x, y, w, h;
info.m_w, info.m_h, info.m_zoneSize); m_screen->getShape(x, y, w, h);
m_setZone(x, y, w, h, getJumpZoneSize());
} }
// send new screen info
m_receiver->onInfoChanged(info);
}
return true; return true;
} }
}
return false; return false;
} }
CString
CMSWindowsPrimaryScreen::getCurrentDesktopName() const
{
return m_deskName;
}
SInt32 SInt32
CMSWindowsPrimaryScreen::getJumpZoneSize() const CMSWindowsPrimaryScreen::getJumpZoneSize() const
{ {
@ -643,25 +329,96 @@ CMSWindowsPrimaryScreen::getJumpZoneSize() const
} }
void void
CMSWindowsPrimaryScreen::warpCursorToCenter() CMSWindowsPrimaryScreen::postCreateWindow(HWND window)
{ {
// warp to center. the extra info tells the hook DLL to send // save window
// SYNERGY_MSG_POST_WARP instead of SYNERGY_MSG_MOUSE_MOVE. m_window = window;
// install hooks
m_install();
// resize window
// note -- we use a fullscreen window to grab input. it should
// be possible to use a 1x1 window but i've run into problems
// with losing keyboard input (focus?) in that case.
// unfortunately, hiding the full screen window (when entering
// the screen) causes all other windows to redraw.
SInt32 x, y, w, h; SInt32 x, y, w, h;
getScreenShape(x, y, w, h); m_screen->getShape(x, y, w, h);
mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, MoveWindow(m_window, x, y, w, h, FALSE);
(DWORD)((65535.99 * (m_xCenter - x)) / (w - 1)),
(DWORD)((65535.99 * (m_yCenter - y)) / (h - 1)), if (isActive()) {
0, // hide the cursor
0x12345678); showWindow();
// FIXME -- ignore mouse until we get warp notification? }
else {
// watch jump zones
m_setRelay(false);
// all messages prior to now are invalid
nextMark();
}
} }
void void
CMSWindowsPrimaryScreen::enterNoWarp() CMSWindowsPrimaryScreen::preDestroyWindow(HWND)
{ {
// not active anymore // hide the window if it's visible
m_active = false; if (isActive()) {
hideWindow();
}
// uninstall hooks
m_uninstall();
}
void
CMSWindowsPrimaryScreen::onPreRun()
{
// must call run() from same thread as open()
assert(m_threadID == GetCurrentThreadId());
assert(m_window != NULL);
}
void
CMSWindowsPrimaryScreen::onPreOpen()
{
assert(m_window == NULL);
// initialize hook library
m_threadID = GetCurrentThreadId();
m_init(m_threadID);
}
void
CMSWindowsPrimaryScreen::onPostOpen()
{
// get cursor info
m_screen->getCursorPos(m_x, m_y);
m_screen->getCursorCenter(m_xCenter, m_yCenter);
// set jump zones
SInt32 x, y, w, h;
m_screen->getShape(x, y, w, h);
m_setZone(x, y, w, h, getJumpZoneSize());
// initialize marks
m_mark = 0;
m_markReceived = 0;
nextMark();
}
void
CMSWindowsPrimaryScreen::onPostClose()
{
m_cleanup();
m_threadID = 0;
}
void
CMSWindowsPrimaryScreen::onPreEnter()
{
assert(m_window != NULL);
// reset motion ignore count // reset motion ignore count
m_mouseMoveIgnore = 0; m_mouseMoveIgnore = 0;
@ -674,14 +431,78 @@ CMSWindowsPrimaryScreen::enterNoWarp()
// watch jump zones // watch jump zones
m_setRelay(false); m_setRelay(false);
}
// restore active window and hide our window void
hideWindow(); CMSWindowsPrimaryScreen::onPostEnter()
{
// all messages prior to now are invalid
nextMark();
}
void
CMSWindowsPrimaryScreen::onPreLeave()
{
assert(m_window != NULL);
// all messages prior to now are invalid // all messages prior to now are invalid
nextMark(); nextMark();
} }
void
CMSWindowsPrimaryScreen::onPostLeave(bool success)
{
if (success) {
// relay all mouse and keyboard events
m_setRelay(true);
// ignore this many mouse motion events (not including the already
// queued events). on (at least) the win2k login desktop, one
// motion event is reported using a position from before the above
// warpCursor(). i don't know why it does that and other desktops
// don't have the same problem. anyway, simply ignoring that event
// works around it.
// FIXME -- is this true now that we're using mouse_event?
m_mouseMoveIgnore = 1;
// disable ctrl+alt+del, alt+tab, etc
if (m_is95Family) {
DWORD dummy = 0;
SystemParametersInfo(SPI_SETSCREENSAVERRUNNING, TRUE, &dummy, 0);
}
// discard messages until after the warp
nextMark();
}
}
void
CMSWindowsPrimaryScreen::createWindow()
{
// open the desktop and the window
m_window = m_screen->openDesktop();
if (m_window == NULL) {
throw XScreenOpenFailure();
}
// note -- we use a fullscreen window to grab input. it should
// be possible to use a 1x1 window but i've run into problems
// with losing keyboard input (focus?) in that case.
// unfortunately, hiding the full screen window (when entering
// the scren causes all other windows to redraw).
SInt32 x, y, w, h;
m_screen->getShape(x, y, w, h);
MoveWindow(m_window, x, y, w, h, FALSE);
}
void
CMSWindowsPrimaryScreen::destroyWindow()
{
// close the desktop and the window
m_screen->closeDesktop();
m_window = NULL;
}
bool bool
CMSWindowsPrimaryScreen::showWindow() CMSWindowsPrimaryScreen::showWindow()
{ {
@ -733,262 +554,18 @@ CMSWindowsPrimaryScreen::hideWindow()
} }
void void
CMSWindowsPrimaryScreen::checkClipboard() CMSWindowsPrimaryScreen::warpCursorToCenter()
{ {
// if we think we own the clipboard but we don't then somebody // warp to center. the extra info tells the hook DLL to send
// grabbed the clipboard on this screen without us knowing. // SYNERGY_MSG_POST_WARP instead of SYNERGY_MSG_MOUSE_MOVE.
// tell the server that this screen grabbed the clipboard.
//
// this works around bugs in the clipboard viewer chain.
// sometimes NT will simply never send WM_DRAWCLIPBOARD
// messages for no apparent reason and rebooting fixes the
// problem. since we don't want a broken clipboard until the
// next reboot we do this double check. clipboard ownership
// won't be reflected on other screens until we leave but at
// least the clipboard itself will work.
HWND clipboardOwner = GetClipboardOwner();
if (m_clipboardOwner != clipboardOwner) {
try {
m_clipboardOwner = clipboardOwner;
if (m_clipboardOwner != m_window && m_clipboardOwner != NULL) {
m_receiver->onGrabClipboard(kClipboardClipboard);
m_receiver->onGrabClipboard(kClipboardSelection);
}
}
catch (XBadClient&) {
// ignore
}
}
}
void
CMSWindowsPrimaryScreen::createWindow()
{
// get the input desktop and switch to it
if (m_is95Family) {
if (!openDesktop()) {
throw XScreenOpenFailure();
}
}
else {
if (!switchDesktop(openInputDesktop())) {
throw XScreenOpenFailure();
}
}
// poll input desktop to see if it changes (preTranslateMessage()
// handles WM_TIMER)
m_timer = 0;
if (!m_is95Family) {
m_timer = SetTimer(NULL, 0, 200, NULL);
}
}
void
CMSWindowsPrimaryScreen::destroyWindow()
{
// remove timer
if (m_timer != 0) {
KillTimer(NULL, m_timer);
}
// disconnect from desktop
if (m_is95Family) {
closeDesktop();
}
else {
switchDesktop(NULL);
}
assert(m_window == NULL);
assert(m_desk == NULL);
}
void
CMSWindowsPrimaryScreen::installScreenSaver()
{
// install the screen saver hook
if (m_installScreenSaver != NULL) {
m_installScreenSaver();
}
}
void
CMSWindowsPrimaryScreen::uninstallScreenSaver()
{
// uninstall the screen saver hook
if (m_uninstallScreenSaver != NULL) {
m_uninstallScreenSaver();
}
}
bool
CMSWindowsPrimaryScreen::openDesktop()
{
// install hooks
m_install();
// note -- we use a fullscreen window to grab input. it should
// be possible to use a 1x1 window but i've run into problems
// with losing keyboard input (focus?) in that case.
// unfortunately, hiding the full screen window (when entering
// the scren causes all other windows to redraw).
SInt32 x, y, w, h; SInt32 x, y, w, h;
getScreenShape(x, y, w, h); m_screen->getShape(x, y, w, h);
mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
// create the window (DWORD)((65535.99 * (m_xCenter - x)) / (w - 1)),
m_window = CreateWindowEx(WS_EX_TOPMOST | (DWORD)((65535.99 * (m_yCenter - y)) / (h - 1)),
WS_EX_TRANSPARENT | 0,
WS_EX_TOOLWINDOW, 0x12345678);
(LPCTSTR)getClass(), // FIXME -- ignore mouse until we get warp notification?
"Synergy",
WS_POPUP,
x, y, w, h, NULL, NULL,
getInstance(),
NULL);
if (m_window == NULL) {
log((CLOG_ERR "failed to create window: %d", GetLastError()));
m_uninstall();
return false;
}
// install our clipboard snooper
m_nextClipboardWindow = SetClipboardViewer(m_window);
return true;
}
void
CMSWindowsPrimaryScreen::closeDesktop()
{
// destroy old window
if (m_window != NULL) {
// restore active window and hide ours
if (m_active) {
hideWindow();
}
// first remove clipboard snooper
ChangeClipboardChain(m_window, m_nextClipboardWindow);
m_nextClipboardWindow = NULL;
// we no longer own the clipboard
if (m_clipboardOwner == m_window) {
m_clipboardOwner = NULL;
}
// now destroy window
DestroyWindow(m_window);
m_window = NULL;
}
// unhook
m_uninstall();
}
bool
CMSWindowsPrimaryScreen::switchDesktop(HDESK desk)
{
// did we own the clipboard?
bool ownClipboard = (m_clipboardOwner == m_window);
// destroy old window
if (m_window != NULL) {
// restore active window and hide ours
if (m_active) {
hideWindow();
}
// first remove clipboard snooper
ChangeClipboardChain(m_window, m_nextClipboardWindow);
m_nextClipboardWindow = NULL;
// we no longer own the clipboard
if (ownClipboard) {
m_clipboardOwner = NULL;
}
// now destroy window
DestroyWindow(m_window);
m_window = NULL;
}
// unhook
if (m_desk != NULL) {
m_uninstall();
CloseDesktop(m_desk);
m_desk = NULL;
m_deskName = "";
}
// if no new desktop then we're done
if (desk == NULL) {
log((CLOG_INFO "disconnecting desktop"));
return true;
}
// set the desktop. can only do this when there are no windows
// and hooks on the current desktop owned by this thread.
if (SetThreadDesktop(desk) == 0) {
log((CLOG_ERR "failed to set desktop: %d", GetLastError()));
CloseDesktop(desk);
return false;
}
// install hooks
m_install();
// note -- we use a fullscreen window to grab input. it should
// be possible to use a 1x1 window but i've run into problems
// with losing keyboard input (focus?) in that case.
// unfortunately, hiding the full screen window (when entering
// the scren causes all other windows to redraw).
SInt32 x, y, w, h;
getScreenShape(x, y, w, h);
// create the window
m_window = CreateWindowEx(WS_EX_TOPMOST |
WS_EX_TRANSPARENT |
WS_EX_TOOLWINDOW,
(LPCTSTR)getClass(),
"Synergy",
WS_POPUP,
x, y, w, h, NULL, NULL,
getInstance(),
NULL);
if (m_window == NULL) {
log((CLOG_ERR "failed to create window: %d", GetLastError()));
m_uninstall();
CloseDesktop(desk);
return false;
}
// install our clipboard snooper
m_nextClipboardWindow = SetClipboardViewer(m_window);
// reassert clipboard ownership
if (ownClipboard) {
// FIXME
}
// save new desktop
m_desk = desk;
m_deskName = getDesktopName(m_desk);
log((CLOG_INFO "switched to desktop %s", m_deskName.c_str()));
// get active window and show ours
if (m_active) {
showWindow();
}
else {
// watch jump zones
m_setRelay(false);
// all messages prior to now are invalid
nextMark();
}
return true;
} }
void void

View File

@ -1,74 +1,61 @@
#ifndef CMSWINDOWSPRIMARYSCREEN_H #ifndef CMSWINDOWSPRIMARYSCREEN_H
#define CMSWINDOWSPRIMARYSCREEN_H #define CMSWINDOWSPRIMARYSCREEN_H
#include "CMSWindowsScreen.h" #include "CPrimaryScreen.h"
#include "IPrimaryScreen.h" #include "IMSWindowsScreenEventHandler.h"
#include "CSynergyHook.h" #include "CSynergyHook.h"
#include "MouseTypes.h" #include "MouseTypes.h"
#include "CString.h" #include "CString.h"
class CMSWindowsScreen;
class IScreenReceiver; class IScreenReceiver;
class IPrimaryScreenReceiver; class IPrimaryScreenReceiver;
class CMSWindowsPrimaryScreen : public CMSWindowsScreen, public IPrimaryScreen { class CMSWindowsPrimaryScreen :
public CPrimaryScreen, public IMSWindowsScreenEventHandler {
public: public:
typedef bool (CMSWindowsPrimaryScreen::*HookMethod)(int, WPARAM, LPARAM); typedef bool (CMSWindowsPrimaryScreen::*HookMethod)(int, WPARAM, LPARAM);
CMSWindowsPrimaryScreen(IScreenReceiver*, IPrimaryScreenReceiver*); CMSWindowsPrimaryScreen(IScreenReceiver*, IPrimaryScreenReceiver*);
virtual ~CMSWindowsPrimaryScreen(); virtual ~CMSWindowsPrimaryScreen();
// IPrimaryScreen overrides // CPrimaryScreen overrides
virtual void run();
virtual void stop();
virtual void open();
virtual void close();
virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute, bool);
virtual bool leave();
virtual void reconfigure(UInt32 activeSides); virtual void reconfigure(UInt32 activeSides);
virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute); virtual void warpCursor(SInt32 x, SInt32 y);
virtual void setClipboard(ClipboardID, const IClipboard*);
virtual void grabClipboard(ClipboardID);
virtual void getClipboard(ClipboardID, IClipboard*) const;
virtual KeyModifierMask getToggleMask() const; virtual KeyModifierMask getToggleMask() const;
virtual bool isLockedToScreen() const; virtual bool isLockedToScreen() const;
virtual IScreen* getScreen() const;
// IMSWindowsScreenEventHandler overrides
virtual void onError();
virtual void onScreensaver(bool activated);
virtual bool onPreDispatch(const CEvent* event);
virtual bool onEvent(CEvent* event);
virtual SInt32 getJumpZoneSize() const;
virtual void postCreateWindow(HWND);
virtual void preDestroyWindow(HWND);
protected: protected:
// CMSWindowsScreen overrides // CPrimaryScreen overrides
virtual bool onPreTranslate(const CEvent* event); virtual void onPreRun();
virtual bool onEvent(CEvent* event); virtual void onPreOpen();
virtual CString getCurrentDesktopName() const; virtual void onPostOpen();
virtual void onPostClose();
virtual void onPreEnter();
virtual void onPostEnter();
virtual void onPreLeave();
virtual void onPostLeave(bool);
virtual void createWindow();
virtual void destroyWindow();
virtual bool showWindow();
virtual void hideWindow();
virtual void warpCursorToCenter();
virtual void updateKeys();
private: private:
SInt32 getJumpZoneSize() const;
// warp mouse to center of primary display (used when computing
// motion deltas while mouse is on secondary screen).
void warpCursorToCenter();
void enterNoWarp(); void enterNoWarp();
bool showWindow();
void hideWindow();
// check clipboard ownership and, if necessary, tell the receiver
// of a grab.
void checkClipboard();
// create/destroy window
// also attach to desktop; this destroys and recreates the window
// as necessary.
void createWindow();
void destroyWindow();
// start/stop watch for screen saver changes
void installScreenSaver();
void uninstallScreenSaver();
// open/close desktop (for windows 95/98/me)
bool openDesktop();
void closeDesktop();
// make desk the thread desktop (for windows NT/2000/XP)
bool switchDesktop(HDESK desk);
// discard posted messages // discard posted messages
void nextMark(); void nextMark();
@ -77,12 +64,11 @@ private:
KeyID mapKey(WPARAM keycode, LPARAM info, KeyID mapKey(WPARAM keycode, LPARAM info,
KeyModifierMask* maskOut); KeyModifierMask* maskOut);
ButtonID mapButton(WPARAM button) const; ButtonID mapButton(WPARAM button) const;
void updateKeys();
void updateKey(UINT vkCode, bool press); void updateKey(UINT vkCode, bool press);
private: private:
IScreenReceiver* m_receiver; IPrimaryScreenReceiver* m_receiver;
IPrimaryScreenReceiver* m_primaryReceiver; CMSWindowsScreen* m_screen;
// true if windows 95/98/me // true if windows 95/98/me
bool m_is95Family; bool m_is95Family;
@ -90,27 +76,13 @@ private:
// the main loop's thread id // the main loop's thread id
DWORD m_threadID; DWORD m_threadID;
// the timer used to check for desktop switching // our window
UINT m_timer;
// the current desk and it's name
HDESK m_desk;
CString m_deskName;
// our window (for getting clipboard changes)
HWND m_window; HWND m_window;
// m_active is true the hooks are relaying events
bool m_active;
// used to discard queued messages that are no longer needed // used to discard queued messages that are no longer needed
UInt32 m_mark; UInt32 m_mark;
UInt32 m_markReceived; UInt32 m_markReceived;
// clipboard stuff
HWND m_nextClipboardWindow;
HWND m_clipboardOwner;
// map of key state // map of key state
BYTE m_keys[256]; BYTE m_keys[256];
@ -132,8 +104,6 @@ private:
SetSidesFunc m_setSides; SetSidesFunc m_setSides;
SetZoneFunc m_setZone; SetZoneFunc m_setZone;
SetRelayFunc m_setRelay; SetRelayFunc m_setRelay;
InstallScreenSaverFunc m_installScreenSaver;
UninstallScreenSaverFunc m_uninstallScreenSaver;
// stuff for restoring active window // stuff for restoring active window
HWND m_lastForegroundWindow; HWND m_lastForegroundWindow;

View File

@ -73,7 +73,7 @@ CPrimaryScreen::open()
updateKeys(); updateKeys();
// get notified of screen saver activation/deactivation // get notified of screen saver activation/deactivation
getScreen()->openScreenSaver(true); getScreen()->openScreensaver(true);
// subclass hook // subclass hook
onPostOpen(); onPostOpen();
@ -94,7 +94,7 @@ void
CPrimaryScreen::close() CPrimaryScreen::close()
{ {
onPreClose(); onPreClose();
getScreen()->closeScreenSaver(); getScreen()->closeScreensaver();
destroyWindow(); destroyWindow();
getScreen()->close(); getScreen()->close();
onPostClose(); onPostClose();
@ -197,12 +197,6 @@ CPrimaryScreen::getClipboard(ClipboardID id,
getScreen()->getClipboard(id, clipboard); getScreen()->getClipboard(id, clipboard);
} }
SInt32
CPrimaryScreen::getJumpZoneSize() const
{
return 1;
}
void void
CPrimaryScreen::onPreRun() CPrimaryScreen::onPreRun()
{ {

View File

@ -42,8 +42,8 @@ public:
bool leave(); bool leave();
// called when the configuration has changed. activeSides is a // called when the configuration has changed. activeSides is a
// bitmask of CConfig::EDirectionMask indicating which sides of // bitmask of EDirectionMask indicating which sides of the
// the primary screen are linked to clients. // primary screen are linked to clients.
virtual void reconfigure(UInt32 activeSides) = 0; virtual void reconfigure(UInt32 activeSides) = 0;
// warp the cursor to the given absolute coordinates // warp the cursor to the given absolute coordinates
@ -66,8 +66,8 @@ public:
void getClipboard(ClipboardID, IClipboard*) const; void getClipboard(ClipboardID, IClipboard*) const;
// returns the size of the zone on the edges of the screen that // returns the size of the zone on the edges of the screen that
// causes the cursor to jump to another screen. default returns 1. // causes the cursor to jump to another screen.
virtual SInt32 getJumpZoneSize() const; virtual SInt32 getJumpZoneSize() const = 0;
// get the primary screen's current toggle modifier key state. // get the primary screen's current toggle modifier key state.
// the returned mask should have the corresponding bit set for // the returned mask should have the corresponding bit set for

View File

@ -197,21 +197,17 @@ CServer::getActivePrimarySides() const
{ {
// note -- m_mutex must be locked on entry // note -- m_mutex must be locked on entry
UInt32 sides = 0; UInt32 sides = 0;
if (!m_config.getNeighbor(getPrimaryScreenName(), if (!m_config.getNeighbor(getPrimaryScreenName(), kLeft).empty()) {
CConfig::kLeft).empty()) { sides |= kLeftMask;
sides |= CConfig::kLeftMask;
} }
if (!m_config.getNeighbor(getPrimaryScreenName(), if (!m_config.getNeighbor(getPrimaryScreenName(), kRight).empty()) {
CConfig::kRight).empty()) { sides |= kRightMask;
sides |= CConfig::kRightMask;
} }
if (!m_config.getNeighbor(getPrimaryScreenName(), if (!m_config.getNeighbor(getPrimaryScreenName(), kTop).empty()) {
CConfig::kTop).empty()) { sides |= kTopMask;
sides |= CConfig::kTopMask;
} }
if (!m_config.getNeighbor(getPrimaryScreenName(), if (!m_config.getNeighbor(getPrimaryScreenName(), kBottom).empty()) {
CConfig::kBottom).empty()) { sides |= kBottomMask;
sides |= CConfig::kBottomMask;
} }
return sides; return sides;
} }
@ -505,25 +501,25 @@ CServer::onMouseMovePrimaryNoLock(SInt32 x, SInt32 y)
SInt32 zoneSize = m_active->getJumpZoneSize(); SInt32 zoneSize = m_active->getJumpZoneSize();
// see if we should change screens // see if we should change screens
CConfig::EDirection dir; EDirection dir;
if (x < ax + zoneSize) { if (x < ax + zoneSize) {
x -= zoneSize; x -= zoneSize;
dir = CConfig::kLeft; dir = kLeft;
log((CLOG_DEBUG1 "switch to left")); log((CLOG_DEBUG1 "switch to left"));
} }
else if (x >= ax + aw - zoneSize) { else if (x >= ax + aw - zoneSize) {
x += zoneSize; x += zoneSize;
dir = CConfig::kRight; dir = kRight;
log((CLOG_DEBUG1 "switch to right")); log((CLOG_DEBUG1 "switch to right"));
} }
else if (y < ay + zoneSize) { else if (y < ay + zoneSize) {
y -= zoneSize; y -= zoneSize;
dir = CConfig::kTop; dir = kTop;
log((CLOG_DEBUG1 "switch to top")); log((CLOG_DEBUG1 "switch to top"));
} }
else if (y >= ay + ah - zoneSize) { else if (y >= ay + ah - zoneSize) {
y += zoneSize; y += zoneSize;
dir = CConfig::kBottom; dir = kBottom;
log((CLOG_DEBUG1 "switch to bottom")); log((CLOG_DEBUG1 "switch to bottom"));
} }
else { else {
@ -584,24 +580,24 @@ CServer::onMouseMoveSecondaryNoLock(SInt32 dx, SInt32 dy)
IClient* newScreen = NULL; IClient* newScreen = NULL;
if (!isLockedToScreenNoLock()) { if (!isLockedToScreenNoLock()) {
// find direction of neighbor // find direction of neighbor
CConfig::EDirection dir; EDirection dir;
if (m_x < ax) { if (m_x < ax) {
dir = CConfig::kLeft; dir = kLeft;
} }
else if (m_x > ax + aw - 1) { else if (m_x > ax + aw - 1) {
dir = CConfig::kRight; dir = kRight;
} }
else if (m_y < ay) { else if (m_y < ay) {
dir = CConfig::kTop; dir = kTop;
} }
else if (m_y > ay + ah - 1) { else if (m_y > ay + ah - 1) {
dir = CConfig::kBottom; dir = kBottom;
} }
else { else {
newScreen = m_active; newScreen = m_active;
// keep compiler quiet about unset variable // keep compiler quiet about unset variable
dir = CConfig::kLeft; dir = kLeft;
} }
// get neighbor if we should switch // get neighbor if we should switch
@ -760,7 +756,7 @@ CServer::switchScreen(IClient* dst, SInt32 x, SInt32 y, bool forScreensaver)
} }
IClient* IClient*
CServer::getNeighbor(IClient* src, CConfig::EDirection dir) const CServer::getNeighbor(IClient* src, EDirection dir) const
{ {
assert(src != NULL); assert(src != NULL);
@ -793,7 +789,7 @@ CServer::getNeighbor(IClient* src, CConfig::EDirection dir) const
IClient* IClient*
CServer::getNeighbor(IClient* src, CServer::getNeighbor(IClient* src,
CConfig::EDirection srcSide, SInt32& x, SInt32& y) const EDirection srcSide, SInt32& x, SInt32& y) const
{ {
assert(src != NULL); assert(src != NULL);
@ -816,7 +812,7 @@ CServer::getNeighbor(IClient* src,
// actual to canonical position on entry to and from canonical to // actual to canonical position on entry to and from canonical to
// actual on exit from the search. // actual on exit from the search.
switch (srcSide) { switch (srcSide) {
case CConfig::kLeft: case kLeft:
x -= dx; x -= dx;
while (dst != NULL && dst != lastGoodScreen) { while (dst != NULL && dst != lastGoodScreen) {
lastGoodScreen = dst; lastGoodScreen = dst;
@ -832,7 +828,7 @@ CServer::getNeighbor(IClient* src,
x += dx; x += dx;
break; break;
case CConfig::kRight: case kRight:
x -= dx; x -= dx;
while (dst != NULL) { while (dst != NULL) {
x -= dw; x -= dw;
@ -848,7 +844,7 @@ CServer::getNeighbor(IClient* src,
x += dx; x += dx;
break; break;
case CConfig::kTop: case kTop:
y -= dy; y -= dy;
while (dst != NULL) { while (dst != NULL) {
lastGoodScreen = dst; lastGoodScreen = dst;
@ -864,7 +860,7 @@ CServer::getNeighbor(IClient* src,
y += dy; y += dy;
break; break;
case CConfig::kBottom: case kBottom:
y -= dy; y -= dy;
while (dst != NULL) { while (dst != NULL) {
y -= dh; y -= dh;
@ -892,26 +888,26 @@ CServer::getNeighbor(IClient* src,
if (dst == m_primaryClient) { if (dst == m_primaryClient) {
const CString dstName(dst->getName()); const CString dstName(dst->getName());
switch (srcSide) { switch (srcSide) {
case CConfig::kLeft: case kLeft:
if (!m_config.getNeighbor(dstName, CConfig::kRight).empty() && if (!m_config.getNeighbor(dstName, kRight).empty() &&
x > dx + dw - 1 - dst->getJumpZoneSize()) x > dx + dw - 1 - dst->getJumpZoneSize())
x = dx + dw - 1 - dst->getJumpZoneSize(); x = dx + dw - 1 - dst->getJumpZoneSize();
break; break;
case CConfig::kRight: case kRight:
if (!m_config.getNeighbor(dstName, CConfig::kLeft).empty() && if (!m_config.getNeighbor(dstName, kLeft).empty() &&
x < dx + dst->getJumpZoneSize()) x < dx + dst->getJumpZoneSize())
x = dx + dst->getJumpZoneSize(); x = dx + dst->getJumpZoneSize();
break; break;
case CConfig::kTop: case kTop:
if (!m_config.getNeighbor(dstName, CConfig::kBottom).empty() && if (!m_config.getNeighbor(dstName, kBottom).empty() &&
y > dy + dh - 1 - dst->getJumpZoneSize()) y > dy + dh - 1 - dst->getJumpZoneSize())
y = dy + dh - 1 - dst->getJumpZoneSize(); y = dy + dh - 1 - dst->getJumpZoneSize();
break; break;
case CConfig::kBottom: case kBottom:
if (!m_config.getNeighbor(dstName, CConfig::kTop).empty() && if (!m_config.getNeighbor(dstName, kTop).empty() &&
y < dy + dst->getJumpZoneSize()) y < dy + dst->getJumpZoneSize())
y = dy + dst->getJumpZoneSize(); y = dy + dst->getJumpZoneSize();
break; break;
@ -925,8 +921,8 @@ CServer::getNeighbor(IClient* src,
// should be set 120 pixels from the top (again 20% from the // should be set 120 pixels from the top (again 20% from the
// top). // top).
switch (srcSide) { switch (srcSide) {
case CConfig::kLeft: case kLeft:
case CConfig::kRight: case kRight:
y -= sy; y -= sy;
if (y < 0) { if (y < 0) {
y = 0; y = 0;
@ -941,8 +937,8 @@ CServer::getNeighbor(IClient* src,
y += dy; y += dy;
break; break;
case CConfig::kTop: case kTop:
case CConfig::kBottom: case kBottom:
x -= sx; x -= sx;
if (x < 0) { if (x < 0) {
x = 0; x = 0;

View File

@ -96,15 +96,14 @@ private:
SInt32 x, SInt32 y, bool forScreenSaver); SInt32 x, SInt32 y, bool forScreenSaver);
// lookup neighboring screen // lookup neighboring screen
IClient* getNeighbor(IClient*, CConfig::EDirection) const; IClient* getNeighbor(IClient*, EDirection) const;
// lookup neighboring screen. given a position relative to the // lookup neighboring screen. given a position relative to the
// source screen, find the screen we should move onto and where. // source screen, find the screen we should move onto and where.
// if the position is sufficiently far from the source then we // if the position is sufficiently far from the source then we
// cross multiple screens. if there is no suitable screen then // cross multiple screens. if there is no suitable screen then
// return NULL and x,y are not modified. // return NULL and x,y are not modified.
IClient* getNeighbor(IClient*, IClient* getNeighbor(IClient*, EDirection,
CConfig::EDirection,
SInt32& x, SInt32& y) const; SInt32& x, SInt32& y) const;
// open/close the primary screen // open/close the primary screen

View File

@ -331,6 +331,12 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event)
return false; return false;
} }
SInt32
CXWindowsPrimaryScreen::getJumpZoneSize() const
{
return 1;
}
void void
CXWindowsPrimaryScreen::onPreRun() CXWindowsPrimaryScreen::onPreRun()
{ {
@ -419,7 +425,7 @@ CXWindowsPrimaryScreen::createWindow()
selectEvents(display, m_screen->getRoot()); selectEvents(display, m_screen->getRoot());
} }
// tell our superclass about the window // tell generic screen about the window
m_screen->setWindow(m_window); m_screen->setWindow(m_window);
} }

View File

@ -32,6 +32,7 @@ public:
virtual void onScreensaver(bool activated); virtual void onScreensaver(bool activated);
virtual bool onPreDispatch(const CEvent* event); virtual bool onPreDispatch(const CEvent* event);
virtual bool onEvent(CEvent* event); virtual bool onEvent(CEvent* event);
virtual SInt32 getJumpZoneSize() const;
protected: protected:
// CPrimaryScreen overrides // CPrimaryScreen overrides

View File

@ -118,6 +118,10 @@ SOURCE=.\CPrimaryClient.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\CPrimaryScreen.cpp
# End Source File
# Begin Source File
SOURCE=.\CServer.cpp SOURCE=.\CServer.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -158,11 +162,11 @@ SOURCE=.\CPrimaryClient.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\CServer.h SOURCE=.\CPrimaryScreen.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\IPrimaryScreen.h SOURCE=.\CServer.h
# End Source File # End Source File
# Begin Source File # Begin Source File

View File

@ -37,8 +37,8 @@ public:
// will call IScreenEventHandler's onScreenSaver() when the screensaver // will call IScreenEventHandler's onScreenSaver() when the screensaver
// activates or deactivates until close. if notify is false then // activates or deactivates until close. if notify is false then
// the screen saver is disabled on open and restored on close. // the screen saver is disabled on open and restored on close.
virtual void openScreenSaver(bool notify) = 0; virtual void openScreensaver(bool notify) = 0;
virtual void closeScreenSaver() = 0; virtual void closeScreensaver() = 0;
// activate or deactivate the screen saver // activate or deactivate the screen saver
virtual void screensaver(bool activate) = 0; virtual void screensaver(bool activate) = 0;

View File

@ -34,6 +34,11 @@ public:
// called by mainLoop(). iff the event was handled return true and // called by mainLoop(). iff the event was handled return true and
// store the result, if any, in m_result, which defaults to zero. // store the result, if any, in m_result, which defaults to zero.
virtual bool onEvent(CEvent* event) = 0; virtual bool onEvent(CEvent* event) = 0;
// accessors
// called to get the jump zone size
virtual SInt32 getJumpZoneSize() const = 0;
}; };
#endif #endif

View File

@ -16,6 +16,23 @@ static const double kHeartRate = 2.0;
// time without a heartbeat that we call death // time without a heartbeat that we call death
static const double kHeartDeath = 3.0 * kHeartRate; static const double kHeartDeath = 3.0 * kHeartRate;
// direction constants
enum EDirection {
kLeft,
kRight,
kTop,
kBottom,
kFirstDirection = kLeft,
kLastDirection = kBottom
};
enum EDirectionMask {
kLeftMask = 1 << kLeft,
kRightMask = 1 << kRight,
kTopMask = 1 << kTop,
kBottomMask = 1 << kBottom
};
// //
// message codes (trailing NUL is not part of code). in comments, $n // message codes (trailing NUL is not part of code). in comments, $n
// refers to the n'th argument (counting from one). message codes are // refers to the n'th argument (counting from one). message codes are

View File

@ -155,6 +155,14 @@ SOURCE=.\IPrimaryScreenReceiver.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\IScreen.h
# End Source File
# Begin Source File
SOURCE=.\IScreenEventHandler.h
# End Source File
# Begin Source File
SOURCE=.\IScreenReceiver.h SOURCE=.\IScreenReceiver.h
# End Source File # End Source File
# Begin Source File # Begin Source File