checkpoint. refactored win32 code. had to edit and rename some
files so this is only a checkpoint.
This commit is contained in:
parent
f48a5fe387
commit
4b46862026
|
@ -1,12 +1,8 @@
|
|||
#include "CMSWindowsSecondaryScreen.h"
|
||||
#include "IScreenReceiver.h"
|
||||
#include "CClipboard.h"
|
||||
#include "CMSWindowsClipboard.h"
|
||||
#include "CMSWindowsScreenSaver.h"
|
||||
#include "CMSWindowsScreen.h"
|
||||
#include "CPlatform.h"
|
||||
#include "XScreen.h"
|
||||
#include "CLock.h"
|
||||
#include "CThread.h"
|
||||
#include "CLog.h"
|
||||
#include <cctype>
|
||||
|
||||
|
@ -24,155 +20,18 @@
|
|||
|
||||
CMSWindowsSecondaryScreen::CMSWindowsSecondaryScreen(
|
||||
IScreenReceiver* receiver) :
|
||||
m_receiver(receiver),
|
||||
m_threadID(0),
|
||||
m_lastThreadID(0),
|
||||
m_desk(NULL),
|
||||
m_deskName(),
|
||||
m_is95Family(CPlatform::isWindows95Family()),
|
||||
m_window(NULL),
|
||||
m_active(false),
|
||||
m_nextClipboardWindow(NULL)
|
||||
m_mask(0)
|
||||
{
|
||||
assert(m_receiver != NULL);
|
||||
|
||||
m_is95Family = CPlatform::isWindows95Family();
|
||||
|
||||
// make sure this thread has a message queue
|
||||
MSG dummy;
|
||||
PeekMessage(&dummy, NULL, WM_USER, WM_USER, PM_NOREMOVE);
|
||||
m_screen = new CMSWindowsScreen(receiver, this);
|
||||
}
|
||||
|
||||
CMSWindowsSecondaryScreen::~CMSWindowsSecondaryScreen()
|
||||
{
|
||||
assert(m_window == NULL);
|
||||
}
|
||||
|
||||
void
|
||||
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();
|
||||
delete m_screen;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -182,8 +41,7 @@ CMSWindowsSecondaryScreen::keyDown(KeyID key, KeyModifierMask mask)
|
|||
UINT virtualKey;
|
||||
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_window != NULL);
|
||||
syncDesktop();
|
||||
m_screen->syncDesktop();
|
||||
|
||||
// get the sequence of keys to simulate key press and the final
|
||||
// modifier state.
|
||||
|
@ -223,8 +81,7 @@ CMSWindowsSecondaryScreen::keyRepeat(KeyID key,
|
|||
UINT virtualKey;
|
||||
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_window != NULL);
|
||||
syncDesktop();
|
||||
m_screen->syncDesktop();
|
||||
|
||||
// get the sequence of keys to simulate key repeat and the final
|
||||
// modifier state.
|
||||
|
@ -244,8 +101,7 @@ CMSWindowsSecondaryScreen::keyUp(KeyID key, KeyModifierMask mask)
|
|||
UINT virtualKey;
|
||||
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_window != NULL);
|
||||
syncDesktop();
|
||||
m_screen->syncDesktop();
|
||||
|
||||
// get the sequence of keys to simulate key release and the final
|
||||
// modifier state.
|
||||
|
@ -302,8 +158,7 @@ void
|
|||
CMSWindowsSecondaryScreen::mouseDown(ButtonID button)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_window != NULL);
|
||||
syncDesktop();
|
||||
m_screen->syncDesktop();
|
||||
|
||||
// map button id to button flag
|
||||
DWORD flags = mapButton(button, true);
|
||||
|
@ -318,8 +173,7 @@ void
|
|||
CMSWindowsSecondaryScreen::mouseUp(ButtonID button)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_window != NULL);
|
||||
syncDesktop();
|
||||
m_screen->syncDesktop();
|
||||
|
||||
// map button id to button flag
|
||||
DWORD flags = mapButton(button, false);
|
||||
|
@ -334,8 +188,7 @@ void
|
|||
CMSWindowsSecondaryScreen::mouseMove(SInt32 x, SInt32 y)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_window != NULL);
|
||||
syncDesktop();
|
||||
m_screen->syncDesktop();
|
||||
warpCursor(x, y);
|
||||
}
|
||||
|
||||
|
@ -343,61 +196,50 @@ void
|
|||
CMSWindowsSecondaryScreen::mouseWheel(SInt32 delta)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_window != NULL);
|
||||
syncDesktop();
|
||||
|
||||
m_screen->syncDesktop();
|
||||
mouse_event(MOUSEEVENTF_WHEEL, 0, 0, delta, 0);
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsSecondaryScreen::setClipboard(ClipboardID /*id*/,
|
||||
const IClipboard* src)
|
||||
IScreen*
|
||||
CMSWindowsSecondaryScreen::getScreen() const
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_window != NULL);
|
||||
|
||||
CMSWindowsClipboard dst(m_window);
|
||||
CClipboard::copy(&dst, src);
|
||||
return m_screen;
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsSecondaryScreen::grabClipboard(ClipboardID /*id*/)
|
||||
CMSWindowsSecondaryScreen::onError()
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_window != NULL);
|
||||
|
||||
CMSWindowsClipboard clipboard(m_window);
|
||||
if (clipboard.open(0)) {
|
||||
clipboard.close();
|
||||
}
|
||||
// ignore
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsSecondaryScreen::screenSaver(bool activate)
|
||||
CMSWindowsSecondaryScreen::onScreensaver(bool)
|
||||
{
|
||||
if (activate) {
|
||||
getScreenSaver()->activate();
|
||||
}
|
||||
else {
|
||||
getScreenSaver()->deactivate();
|
||||
}
|
||||
// ignore
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsSecondaryScreen::getMousePos(SInt32& x, SInt32& y) const
|
||||
bool
|
||||
CMSWindowsSecondaryScreen::onPreDispatch(const CEvent*)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_window != NULL);
|
||||
syncDesktop();
|
||||
|
||||
getCursorPos(x, y);
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsSecondaryScreen::getShape(
|
||||
SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
|
||||
bool
|
||||
CMSWindowsSecondaryScreen::onEvent(CEvent* event)
|
||||
{
|
||||
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
|
||||
|
@ -407,153 +249,63 @@ CMSWindowsSecondaryScreen::getJumpZoneSize() const
|
|||
}
|
||||
|
||||
void
|
||||
CMSWindowsSecondaryScreen::getClipboard(ClipboardID /*id*/,
|
||||
IClipboard* dst) const
|
||||
CMSWindowsSecondaryScreen::postCreateWindow(HWND window)
|
||||
{
|
||||
m_window = window;
|
||||
if (!isActive()) {
|
||||
showWindow();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsSecondaryScreen::preDestroyWindow(HWND)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsSecondaryScreen::onPreRun()
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_window != NULL);
|
||||
|
||||
CMSWindowsClipboard src(m_window);
|
||||
CClipboard::copy(dst, &src);
|
||||
}
|
||||
|
||||
bool
|
||||
CMSWindowsSecondaryScreen::onPreDispatch(const CEvent* event)
|
||||
void
|
||||
CMSWindowsSecondaryScreen::onPreOpen()
|
||||
{
|
||||
assert(event != NULL);
|
||||
|
||||
// forward to superclass
|
||||
if (CMSWindowsScreen::onPreDispatch(event)) {
|
||||
return true;
|
||||
assert(m_window == NULL);
|
||||
}
|
||||
|
||||
// handle event
|
||||
const MSG* msg = &event->m_msg;
|
||||
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)
|
||||
void
|
||||
CMSWindowsSecondaryScreen::onPreEnter()
|
||||
{
|
||||
assert(event != 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);
|
||||
assert(m_window != NULL);
|
||||
}
|
||||
|
||||
// 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:
|
||||
void
|
||||
CMSWindowsSecondaryScreen::onPreLeave()
|
||||
{
|
||||
// screen resolution may have changed. get old shape.
|
||||
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);
|
||||
assert(m_window != NULL);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
CString
|
||||
CMSWindowsSecondaryScreen::getCurrentDesktopName() const
|
||||
void
|
||||
CMSWindowsSecondaryScreen::createWindow()
|
||||
{
|
||||
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
|
||||
|
@ -580,9 +332,9 @@ CMSWindowsSecondaryScreen::warpCursor(SInt32 x, SInt32 y)
|
|||
{
|
||||
// move the mouse directly to target position on NT family or if
|
||||
// not using multiple monitors.
|
||||
if (!m_multimon || !m_is95Family) {
|
||||
if (m_screen->isMultimon() || !m_is95Family) {
|
||||
SInt32 x0, y0, w, h;
|
||||
getScreenShape(x0, y0, w, h);
|
||||
m_screen->getShape(x0, y0, w, h);
|
||||
mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,
|
||||
(DWORD)((65535.99 * (x - x0)) / (w - 1)),
|
||||
(DWORD)((65535.99 * (y - y0)) / (h - 1)),
|
||||
|
@ -653,259 +405,70 @@ CMSWindowsSecondaryScreen::warpCursor(SInt32 x, SInt32 y)
|
|||
}
|
||||
|
||||
void
|
||||
CMSWindowsSecondaryScreen::checkClipboard()
|
||||
CMSWindowsSecondaryScreen::updateKeys()
|
||||
{
|
||||
// if we think we own the clipboard but we don't then somebody
|
||||
// grabbed the clipboard on this screen without us knowing.
|
||||
// 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);
|
||||
// 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));
|
||||
|
||||
// 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&) {
|
||||
// ignore
|
||||
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
|
||||
CMSWindowsPrimaryScreen::createWindow()
|
||||
CMSWindowsSecondaryScreen::setToggleState(KeyModifierMask mask)
|
||||
{
|
||||
// save thread id
|
||||
m_threadID = GetCurrentThreadId();
|
||||
|
||||
// note if using multiple monitors
|
||||
m_multimon = isMultimon();
|
||||
|
||||
// get the input desktop and switch to it
|
||||
if (m_is95Family) {
|
||||
if (!openDesktop()) {
|
||||
throw XScreenOpenFailure();
|
||||
// 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);
|
||||
}
|
||||
else {
|
||||
if (!switchDesktop(openInputDesktop())) {
|
||||
throw XScreenOpenFailure();
|
||||
if ((mask & KeyModifierScrollLock) != (m_mask & KeyModifierScrollLock)) {
|
||||
toggleKey(VK_SCROLL, KeyModifierScrollLock);
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
// 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
|
||||
|
@ -1768,7 +1331,7 @@ CMSWindowsSecondaryScreen::releaseKeys()
|
|||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
syncDesktop();
|
||||
m_screen->syncDesktop();
|
||||
|
||||
// release left/right modifier keys first. if the platform doesn't
|
||||
// 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
|
||||
CMSWindowsSecondaryScreen::toggleKey(UINT virtualKey, KeyModifierMask mask)
|
||||
{
|
||||
|
|
|
@ -7,28 +7,22 @@
|
|||
#define _WIN32_WINNT 0x401
|
||||
#endif
|
||||
|
||||
#include "CMSWindowsScreen.h"
|
||||
#include "ISecondaryScreen.h"
|
||||
#include "CSecondaryScreen.h"
|
||||
#include "IMSWindowsScreenEventHandler.h"
|
||||
#include "CMutex.h"
|
||||
#include "CString.h"
|
||||
#include "stdvector.h"
|
||||
|
||||
class CMSWindowsScreen;
|
||||
class IScreenReceiver;
|
||||
|
||||
class CMSWindowsSecondaryScreen : public CMSWindowsScreen,
|
||||
public ISecondaryScreen {
|
||||
class CMSWindowsSecondaryScreen :
|
||||
public CSecondaryScreen, public IMSWindowsScreenEventHandler {
|
||||
public:
|
||||
CMSWindowsSecondaryScreen(IScreenReceiver*);
|
||||
virtual ~CMSWindowsSecondaryScreen();
|
||||
|
||||
// ISecondaryScreen 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();
|
||||
// CSecondaryScreen overrides
|
||||
virtual void keyDown(KeyID, KeyModifierMask);
|
||||
virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count);
|
||||
virtual void keyUp(KeyID, KeyModifierMask);
|
||||
|
@ -36,19 +30,30 @@ public:
|
|||
virtual void mouseUp(ButtonID);
|
||||
virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute);
|
||||
virtual void mouseWheel(SInt32 delta);
|
||||
virtual void setClipboard(ClipboardID, const IClipboard*);
|
||||
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;
|
||||
virtual IScreen* getScreen() const;
|
||||
|
||||
protected:
|
||||
// CMSWindowsScreen overrides
|
||||
// IMSWindowsScreenEventHandler overrides
|
||||
virtual void onError();
|
||||
virtual void onScreensaver(bool activated);
|
||||
virtual bool onPreDispatch(const 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:
|
||||
enum EKeyAction { kPress, kRelease, kRepeat };
|
||||
|
@ -60,26 +65,6 @@ private:
|
|||
};
|
||||
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)
|
||||
bool openDesktop();
|
||||
void closeDesktop();
|
||||
|
@ -87,9 +72,6 @@ private:
|
|||
// make desk the thread desktop (for windows NT/2000/XP)
|
||||
bool switchDesktop(HDESK desk);
|
||||
|
||||
// get calling thread to use the input desktop
|
||||
void syncDesktop() const;
|
||||
|
||||
// returns true iff there appear to be multiple monitors
|
||||
bool isMultimon() const;
|
||||
|
||||
|
@ -100,8 +82,6 @@ private:
|
|||
void doKeystrokes(const Keystrokes&, SInt32 count);
|
||||
|
||||
void releaseKeys();
|
||||
void updateKeys();
|
||||
void updateModifiers();
|
||||
void toggleKey(UINT virtualKey, KeyModifierMask mask);
|
||||
UINT virtualKeyToScanCode(UINT& virtualKey);
|
||||
bool isExtendedKey(UINT virtualKey);
|
||||
|
@ -109,37 +89,14 @@ private:
|
|||
|
||||
private:
|
||||
CMutex m_mutex;
|
||||
IScreenReceiver* m_receiver;
|
||||
CMSWindowsScreen* m_screen;
|
||||
|
||||
// true if windows 95/98/me
|
||||
bool m_is95Family;
|
||||
|
||||
// true if system appears to have multiple monitors
|
||||
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)
|
||||
// our 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
|
||||
BYTE m_keys[256];
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ CSecondaryScreen::open()
|
|||
updateKeys();
|
||||
|
||||
// disable the screen saver
|
||||
getScreen()->openScreenSaver(false);
|
||||
getScreen()->openScreensaver(false);
|
||||
|
||||
// subclass hook
|
||||
onPostOpen();
|
||||
|
@ -93,7 +93,7 @@ void
|
|||
CSecondaryScreen::close()
|
||||
{
|
||||
onPreClose();
|
||||
getScreen()->closeScreenSaver();
|
||||
getScreen()->closeScreensaver();
|
||||
destroyWindow();
|
||||
getScreen()->close();
|
||||
onPostClose();
|
||||
|
@ -182,12 +182,6 @@ CSecondaryScreen::getClipboard(ClipboardID id,
|
|||
getScreen()->getClipboard(id, clipboard);
|
||||
}
|
||||
|
||||
SInt32
|
||||
CSecondaryScreen::getJumpZoneSize() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
|
||||
{
|
||||
|
|
|
@ -78,8 +78,8 @@ public:
|
|||
void getClipboard(ClipboardID, IClipboard*) const;
|
||||
|
||||
// returns the size of the zone on the edges of the screen that
|
||||
// causes the cursor to jump to another screen. default returns 0.
|
||||
virtual SInt32 getJumpZoneSize() const;
|
||||
// causes the cursor to jump to another screen.
|
||||
virtual SInt32 getJumpZoneSize() const = 0;
|
||||
|
||||
// get the shape (position of upper-left corner and size) of the
|
||||
// screen
|
||||
|
|
|
@ -145,12 +145,6 @@ CXWindowsSecondaryScreen::getScreen() const
|
|||
return m_screen;
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsSecondaryScreen::onScreensaver(bool)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsSecondaryScreen::onError()
|
||||
{
|
||||
|
@ -158,6 +152,12 @@ CXWindowsSecondaryScreen::onError()
|
|||
// FIXME -- forward this? to whom?
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsSecondaryScreen::onScreensaver(bool)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
bool
|
||||
CXWindowsSecondaryScreen::onPreDispatch(const CEvent*)
|
||||
{
|
||||
|
@ -184,6 +184,12 @@ CXWindowsSecondaryScreen::onEvent(CEvent* event)
|
|||
}
|
||||
}
|
||||
|
||||
SInt32
|
||||
CXWindowsSecondaryScreen::getJumpZoneSize() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsSecondaryScreen::onPreRun()
|
||||
{
|
||||
|
@ -260,7 +266,7 @@ CXWindowsSecondaryScreen::createWindow()
|
|||
XTestGrabControl(display, True);
|
||||
}
|
||||
|
||||
// tell our superclass about the window
|
||||
// tell generic screen about the window
|
||||
m_screen->setWindow(m_window);
|
||||
}
|
||||
|
||||
|
@ -275,15 +281,19 @@ CXWindowsSecondaryScreen::destroyWindow()
|
|||
// no longer impervious to server grabs
|
||||
XTestGrabControl(display, False);
|
||||
|
||||
// destroy window
|
||||
if (m_window != None) {
|
||||
XDestroyWindow(display, m_window);
|
||||
m_window = None;
|
||||
}
|
||||
|
||||
// update
|
||||
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
|
||||
|
|
|
@ -35,6 +35,7 @@ public:
|
|||
virtual void onScreensaver(bool activated);
|
||||
virtual bool onPreDispatch(const CEvent* event);
|
||||
virtual bool onEvent(CEvent* event);
|
||||
virtual SInt32 getJumpZoneSize() const;
|
||||
|
||||
protected:
|
||||
// CSecondaryScreen overrides
|
||||
|
|
|
@ -110,6 +110,10 @@ SOURCE=.\CMSWindowsSecondaryScreen.cpp
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CSecondaryScreen.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CServerProxy.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
|
@ -126,11 +130,11 @@ SOURCE=.\CMSWindowsSecondaryScreen.h
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CServerProxy.h
|
||||
SOURCE=.\CSecondaryScreen.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ISecondaryScreen.h
|
||||
SOURCE=.\CServerProxy.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
#include "CMSWindowsScreen.h"
|
||||
#include "CMSWindowsClipboard.h"
|
||||
#include "CMSWindowsScreenSaver.h"
|
||||
#include "CClipboard.h"
|
||||
#include "IMSWindowsScreenEventHandler.h"
|
||||
#include "IScreenReceiver.h"
|
||||
#include "XSynergy.h"
|
||||
#include "CThread.h"
|
||||
#include "CLock.h"
|
||||
#include "TMethodJob.h"
|
||||
|
@ -8,7 +13,7 @@
|
|||
#include <cstring>
|
||||
|
||||
//
|
||||
// add backwards compatible multihead support (suppress bogus warning)
|
||||
// add backwards compatible multihead support (and suppress bogus warning)
|
||||
//
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4706) // assignment within conditional
|
||||
|
@ -23,21 +28,46 @@
|
|||
HINSTANCE CMSWindowsScreen::s_instance = NULL;
|
||||
CMSWindowsScreen* CMSWindowsScreen::s_screen = NULL;
|
||||
|
||||
CMSWindowsScreen::CMSWindowsScreen() :
|
||||
m_class(0),
|
||||
CMSWindowsScreen::CMSWindowsScreen(IScreenReceiver* receiver,
|
||||
IMSWindowsScreenEventHandler* eventHandler) :
|
||||
m_receiver(receiver),
|
||||
m_eventHandler(eventHandler),
|
||||
m_class(NULL),
|
||||
m_icon(NULL),
|
||||
m_cursor(NULL),
|
||||
m_window(NULL),
|
||||
m_x(0), m_y(0),
|
||||
m_w(0), m_h(0),
|
||||
m_thread(0),
|
||||
m_screenSaver(NULL)
|
||||
m_multimon(false),
|
||||
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(m_receiver != NULL);
|
||||
assert(m_eventHandler != NULL);
|
||||
|
||||
s_screen = this;
|
||||
|
||||
// make sure this thread has a message queue
|
||||
MSG dummy;
|
||||
PeekMessage(&dummy, NULL, WM_USER, WM_USER, PM_NOREMOVE);
|
||||
}
|
||||
|
||||
CMSWindowsScreen::~CMSWindowsScreen()
|
||||
{
|
||||
assert(s_screen != NULL);
|
||||
assert(m_class == 0);
|
||||
|
||||
s_screen = NULL;
|
||||
}
|
||||
|
||||
|
@ -47,11 +77,110 @@ CMSWindowsScreen::init(HINSTANCE 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
|
||||
CMSWindowsScreen::mainLoop()
|
||||
{
|
||||
// save thread id for posting quit message
|
||||
m_thread = GetCurrentThreadId();
|
||||
// must call mainLoop() from same thread as openDesktop()
|
||||
assert(m_threadID == GetCurrentThreadId());
|
||||
|
||||
// event loop
|
||||
CEvent event;
|
||||
|
@ -77,55 +206,25 @@ CMSWindowsScreen::mainLoop()
|
|||
void
|
||||
CMSWindowsScreen::exitMainLoop()
|
||||
{
|
||||
PostThreadMessage(m_thread, WM_QUIT, 0, 0);
|
||||
}
|
||||
|
||||
bool
|
||||
CMSWindowsScreen::onPreDispatch(const CEvent*)
|
||||
{
|
||||
return false;
|
||||
PostThreadMessage(m_threadID, WM_QUIT, 0, 0);
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsScreen::openDisplay()
|
||||
CMSWindowsScreen::close()
|
||||
{
|
||||
assert(s_instance != NULL);
|
||||
assert(m_class == 0);
|
||||
|
||||
// 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();
|
||||
// done with hook library
|
||||
if (m_hookLibrary != NULL) {
|
||||
FreeLibrary(m_hookLibrary);
|
||||
m_installScreensaver = NULL;
|
||||
m_uninstallScreensaver = NULL;
|
||||
m_hookLibrary = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsScreen::closeDisplay()
|
||||
{
|
||||
assert(s_instance != NULL);
|
||||
|
||||
// done with screen saver
|
||||
delete m_screenSaver;
|
||||
m_screenSaver = NULL;
|
||||
delete m_screensaver;
|
||||
m_screensaver = NULL;
|
||||
|
||||
// unregister the window class
|
||||
if (m_class != 0) {
|
||||
|
@ -142,30 +241,130 @@ CMSWindowsScreen::closeDisplay()
|
|||
log((CLOG_DEBUG "closed display"));
|
||||
}
|
||||
|
||||
HINSTANCE
|
||||
CMSWindowsScreen::getInstance()
|
||||
bool
|
||||
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
|
||||
CMSWindowsScreen::updateScreenShape()
|
||||
CMSWindowsScreen::checkClipboards()
|
||||
{
|
||||
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));
|
||||
// if we think we own the clipboard but we don't then somebody
|
||||
// grabbed the clipboard on this screen without us knowing.
|
||||
// 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
|
||||
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
|
||||
{
|
||||
assert(m_class != 0);
|
||||
|
@ -196,10 +395,153 @@ CMSWindowsScreen::getCursorCenter(SInt32& x, SInt32& y) const
|
|||
y = GetSystemMetrics(SM_CYSCREEN) >> 1;
|
||||
}
|
||||
|
||||
HCURSOR
|
||||
CMSWindowsScreen::getBlankCursor() const
|
||||
void
|
||||
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
|
||||
|
@ -217,14 +559,122 @@ CMSWindowsScreen::createBlankCursor()
|
|||
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
|
||||
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,
|
||||
DESKTOP_CREATEWINDOW |
|
||||
DESKTOP_HOOKCONTROL |
|
||||
GENERIC_WRITE);
|
||||
}
|
||||
}
|
||||
|
||||
CString
|
||||
CMSWindowsScreen::getDesktopName(HDESK desk) const
|
||||
|
@ -232,6 +682,9 @@ CMSWindowsScreen::getDesktopName(HDESK desk) const
|
|||
if (desk == NULL) {
|
||||
return CString();
|
||||
}
|
||||
else if (m_is95Family) {
|
||||
return "desktop";
|
||||
}
|
||||
else {
|
||||
DWORD size;
|
||||
GetUserObjectInformation(desk, UOI_NAME, NULL, 0, &size);
|
||||
|
@ -246,14 +699,7 @@ CMSWindowsScreen::getDesktopName(HDESK desk) const
|
|||
bool
|
||||
CMSWindowsScreen::isCurrentDesktop(HDESK desk) const
|
||||
{
|
||||
return CStringUtil::CaselessCmp::equal(getDesktopName(desk),
|
||||
getCurrentDesktopName());
|
||||
}
|
||||
|
||||
CMSWindowsScreenSaver*
|
||||
CMSWindowsScreen::getScreenSaver() const
|
||||
{
|
||||
return m_screenSaver;
|
||||
return CStringUtil::CaselessCmp::equal(getDesktopName(desk), m_deskName);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#ifndef CMSWINDOWSSCREEN_H
|
||||
#define CMSWINDOWSSCREEN_H
|
||||
|
||||
#include "IClipboard.h"
|
||||
#include "IScreen.h"
|
||||
#include "CSynergyHook.h"
|
||||
#include "CMutex.h"
|
||||
#include "CString.h"
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
@ -16,52 +17,69 @@ public:
|
|||
LRESULT m_result;
|
||||
};
|
||||
|
||||
class CMSWindowsScreen {
|
||||
class IScreenReceiver;
|
||||
class IMSWindowsScreenEventHandler;
|
||||
|
||||
class CMSWindowsScreen : public IScreen {
|
||||
public:
|
||||
CMSWindowsScreen();
|
||||
CMSWindowsScreen(IScreenReceiver*, IMSWindowsScreenEventHandler*);
|
||||
virtual ~CMSWindowsScreen();
|
||||
|
||||
// manipulators
|
||||
|
||||
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
|
||||
|
||||
// returns true iff the system appears to have multiple monitors
|
||||
bool isMultimon() const;
|
||||
|
||||
// get the application instance handle
|
||||
static HINSTANCE getInstance();
|
||||
|
||||
protected:
|
||||
// runs an event loop and returns when exitMainLoop() is called
|
||||
// IScreen overrides
|
||||
// note -- this class expects the hook DLL to have been loaded
|
||||
// and initialized before open() is called.
|
||||
void open();
|
||||
void mainLoop();
|
||||
|
||||
// force mainLoop() to return
|
||||
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,
|
||||
// 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;
|
||||
|
||||
private:
|
||||
// update screen size cache
|
||||
void updateScreenShape();
|
||||
|
||||
// get the size of the screen
|
||||
void getScreenShape(SInt32& x, SInt32& y,
|
||||
SInt32& width, SInt32& height) const;
|
||||
// internal pre-dispatch event processing
|
||||
bool onPreDispatch(const CEvent* event);
|
||||
|
||||
// get the current cursor position
|
||||
void getCursorPos(SInt32& x, SInt32& y) const;
|
||||
// internal (post-dispatch) event processing
|
||||
bool onEvent(CEvent* event);
|
||||
|
||||
// get the cursor center position
|
||||
void getCursorCenter(SInt32& x, SInt32& y) const;
|
||||
// create the transparent cursor
|
||||
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.
|
||||
// do not call under windows 95/98/me.
|
||||
|
@ -74,38 +92,56 @@ protected:
|
|||
// windows 95/98/me.
|
||||
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
|
||||
static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
private:
|
||||
static HINSTANCE s_instance;
|
||||
|
||||
IScreenReceiver* m_receiver;
|
||||
IMSWindowsScreenEventHandler* m_eventHandler;
|
||||
|
||||
ATOM m_class;
|
||||
HICON m_icon;
|
||||
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_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;
|
||||
};
|
||||
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
#include "CThread.h"
|
||||
#include "CLog.h"
|
||||
#include "IJob.h"
|
||||
//#include "CString.h"
|
||||
//#include <cstdlib>
|
||||
#include <cstring>
|
||||
#if defined(X_DISPLAY_MISSING)
|
||||
# error X11 is required to build synergy
|
||||
|
@ -310,7 +308,7 @@ CXWindowsScreen::checkClipboards()
|
|||
}
|
||||
|
||||
void
|
||||
CXWindowsScreen::openScreenSaver(bool notify)
|
||||
CXWindowsScreen::openScreensaver(bool notify)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_screensaver != NULL);
|
||||
|
@ -325,7 +323,7 @@ CXWindowsScreen::openScreenSaver(bool notify)
|
|||
}
|
||||
|
||||
void
|
||||
CXWindowsScreen::closeScreenSaver()
|
||||
CXWindowsScreen::closeScreensaver()
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
if (m_screensaver != NULL) {
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define CXWINDOWSSCREEN_H
|
||||
|
||||
#include "IScreen.h"
|
||||
#include "ClipboardTypes.h"
|
||||
#include "CMutex.h"
|
||||
#include "CStopwatch.h"
|
||||
#include "stdvector.h"
|
||||
|
@ -59,8 +58,8 @@ public:
|
|||
void close();
|
||||
bool setClipboard(ClipboardID, const IClipboard*);
|
||||
void checkClipboards();
|
||||
void openScreenSaver(bool notify);
|
||||
void closeScreenSaver();
|
||||
void openScreensaver(bool notify);
|
||||
void closeScreensaver();
|
||||
void screensaver(bool activate);
|
||||
void syncDesktop();
|
||||
bool getClipboard(ClipboardID, IClipboard*) const;
|
||||
|
|
|
@ -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
|
|
@ -127,6 +127,10 @@ SOURCE=.\CWin32Platform.h
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\IMSWindowsScreenEventHandler.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\IPlatform.h
|
||||
# End Source File
|
||||
# End Group
|
||||
|
|
|
@ -624,22 +624,22 @@ operator<<(std::ostream& s, const CConfig& config)
|
|||
screen != config.end(); ++screen) {
|
||||
s << "\t" << screen->c_str() << ":" << std::endl;
|
||||
|
||||
neighbor = config.getNeighbor(*screen, CConfig::kLeft);
|
||||
neighbor = config.getNeighbor(*screen, kLeft);
|
||||
if (!neighbor.empty()) {
|
||||
s << "\t\tleft=" << neighbor.c_str() << std::endl;
|
||||
}
|
||||
|
||||
neighbor = config.getNeighbor(*screen, CConfig::kRight);
|
||||
neighbor = config.getNeighbor(*screen, kRight);
|
||||
if (!neighbor.empty()) {
|
||||
s << "\t\tright=" << neighbor.c_str() << std::endl;
|
||||
}
|
||||
|
||||
neighbor = config.getNeighbor(*screen, CConfig::kTop);
|
||||
neighbor = config.getNeighbor(*screen, kTop);
|
||||
if (!neighbor.empty()) {
|
||||
s << "\t\tup=" << neighbor.c_str() << std::endl;
|
||||
}
|
||||
|
||||
neighbor = config.getNeighbor(*screen, CConfig::kBottom);
|
||||
neighbor = config.getNeighbor(*screen, kBottom);
|
||||
if (!neighbor.empty()) {
|
||||
s << "\t\tdown=" << neighbor.c_str() << std::endl;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef CCONFIG_H
|
||||
#define CCONFIG_H
|
||||
|
||||
#include "ProtocolTypes.h"
|
||||
#include "CNetworkAddress.h"
|
||||
#include "XBase.h"
|
||||
#include "stdmap.h"
|
||||
|
@ -20,11 +21,6 @@ struct iterator_traits<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:
|
||||
class CCell {
|
||||
public:
|
||||
|
|
|
@ -649,7 +649,7 @@ CHTTPServer::CScreenArray::convertFrom(const CConfig& config)
|
|||
// insert the screen's neighbors
|
||||
// FIXME -- handle edge wrapping
|
||||
CString neighbor;
|
||||
neighbor = config.getNeighbor(name, CConfig::kLeft);
|
||||
neighbor = config.getNeighbor(name, kLeft);
|
||||
if (!neighbor.empty() && doneSet.count(neighbor) == 0) {
|
||||
// insert left neighbor, adding a column if necessary
|
||||
if (x == 0 || get(x - 1, y) != neighbor) {
|
||||
|
@ -659,7 +659,7 @@ CHTTPServer::CScreenArray::convertFrom(const CConfig& config)
|
|||
}
|
||||
screenStack.push_back(neighbor);
|
||||
}
|
||||
neighbor = config.getNeighbor(name, CConfig::kRight);
|
||||
neighbor = config.getNeighbor(name, kRight);
|
||||
if (!neighbor.empty() && doneSet.count(neighbor) == 0) {
|
||||
// insert right neighbor, adding a column if necessary
|
||||
if (x == m_w - 1 || get(x + 1, y) != neighbor) {
|
||||
|
@ -668,7 +668,7 @@ CHTTPServer::CScreenArray::convertFrom(const CConfig& config)
|
|||
}
|
||||
screenStack.push_back(neighbor);
|
||||
}
|
||||
neighbor = config.getNeighbor(name, CConfig::kTop);
|
||||
neighbor = config.getNeighbor(name, kTop);
|
||||
if (!neighbor.empty() && doneSet.count(neighbor) == 0) {
|
||||
// insert top neighbor, adding a row if necessary
|
||||
if (y == 0 || get(x, y - 1) != neighbor) {
|
||||
|
@ -678,7 +678,7 @@ CHTTPServer::CScreenArray::convertFrom(const CConfig& config)
|
|||
}
|
||||
screenStack.push_back(neighbor);
|
||||
}
|
||||
neighbor = config.getNeighbor(name, CConfig::kBottom);
|
||||
neighbor = config.getNeighbor(name, kBottom);
|
||||
if (!neighbor.empty() && doneSet.count(neighbor) == 0) {
|
||||
// insert bottom neighbor, adding a row if necessary
|
||||
if (y == m_h - 1 || get(x, y + 1) != neighbor) {
|
||||
|
@ -699,25 +699,25 @@ CHTTPServer::CScreenArray::convertFrom(const CConfig& config)
|
|||
}
|
||||
|
||||
CString neighbor;
|
||||
neighbor = config.getNeighbor(name, CConfig::kLeft);
|
||||
neighbor = config.getNeighbor(name, kLeft);
|
||||
if ((x == 0 && !neighbor.empty()) ||
|
||||
(x > 0 && get(x - 1, y) != neighbor)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
neighbor = config.getNeighbor(name, CConfig::kRight);
|
||||
neighbor = config.getNeighbor(name, kRight);
|
||||
if ((x == m_w - 1 && !neighbor.empty()) ||
|
||||
(x < m_w - 1 && get(x + 1, y) != neighbor)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
neighbor = config.getNeighbor(name, CConfig::kTop);
|
||||
neighbor = config.getNeighbor(name, kTop);
|
||||
if ((y == 0 && !neighbor.empty()) ||
|
||||
(y > 0 && get(x, y - 1) != neighbor)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
neighbor = config.getNeighbor(name, CConfig::kBottom);
|
||||
neighbor = config.getNeighbor(name, kBottom);
|
||||
if ((y == m_h - 1 && !neighbor.empty()) ||
|
||||
(y < m_h - 1 && get(x, y + 1) != neighbor)) {
|
||||
return false;
|
||||
|
@ -764,24 +764,16 @@ CHTTPServer::CScreenArray::convertTo(CConfig& config) const
|
|||
continue;
|
||||
}
|
||||
if (x > x0 && isSet(x - 1, y)) {
|
||||
config.connect(get(x, y),
|
||||
CConfig::kLeft,
|
||||
get(x - 1, y));
|
||||
config.connect(get(x, y), kLeft, get(x - 1, y));
|
||||
}
|
||||
if (x < x1 && isSet(x + 1, y)) {
|
||||
config.connect(get(x, y),
|
||||
CConfig::kRight,
|
||||
get(x + 1, y));
|
||||
config.connect(get(x, y), kRight, get(x + 1, y));
|
||||
}
|
||||
if (y > y0 && isSet(x, y - 1)) {
|
||||
config.connect(get(x, y),
|
||||
CConfig::kTop,
|
||||
get(x, y - 1));
|
||||
config.connect(get(x, y), kTop, get(x, y - 1));
|
||||
}
|
||||
if (y < y1 && isSet(x, y + 1)) {
|
||||
config.connect(get(x, y),
|
||||
CConfig::kBottom,
|
||||
get(x, y + 1));
|
||||
config.connect(get(x, y), kBottom, get(x, y + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,8 @@
|
|||
#include "CMSWindowsPrimaryScreen.h"
|
||||
#include "IScreenReceiver.h"
|
||||
#include "CMSWindowsScreen.h"
|
||||
#include "IPrimaryScreenReceiver.h"
|
||||
#include "CMSWindowsClipboard.h"
|
||||
#include "CMSWindowsScreenSaver.h"
|
||||
#include "CPlatform.h"
|
||||
#include "CClipboard.h"
|
||||
#include "ProtocolTypes.h"
|
||||
#include "XScreen.h"
|
||||
#include "XSynergy.h"
|
||||
#include "CThread.h"
|
||||
#include "CLog.h"
|
||||
#include <cstring>
|
||||
|
||||
|
@ -19,21 +13,16 @@
|
|||
CMSWindowsPrimaryScreen::CMSWindowsPrimaryScreen(
|
||||
IScreenReceiver* receiver,
|
||||
IPrimaryScreenReceiver* primaryReceiver) :
|
||||
m_receiver(receiver),
|
||||
m_primaryReceiver(primaryReceiver),
|
||||
CPrimaryScreen(receiver),
|
||||
m_receiver(primaryReceiver),
|
||||
m_is95Family(CPlatform::isWindows95Family()),
|
||||
m_threadID(0),
|
||||
m_timer(0),
|
||||
m_desk(NULL),
|
||||
m_deskName(),
|
||||
m_window(NULL),
|
||||
m_active(false),
|
||||
m_mark(0),
|
||||
m_markReceived(0),
|
||||
m_nextClipboardWindow(NULL),
|
||||
m_clipboardOwner(NULL)
|
||||
m_mouseMoveIgnore(0)
|
||||
{
|
||||
assert(m_receiver != NULL);
|
||||
assert(m_primaryReceiver != NULL);
|
||||
|
||||
// load the hook library
|
||||
m_hookLibrary = LoadLibrary("synrgyhk");
|
||||
|
@ -60,22 +49,8 @@ CMSWindowsPrimaryScreen::CMSWindowsPrimaryScreen(
|
|||
throw XScreenOpenFailure();
|
||||
}
|
||||
|
||||
// get the screen saver functions
|
||||
m_installScreenSaver = (InstallScreenSaverFunc)GetProcAddress(
|
||||
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);
|
||||
// create screen
|
||||
m_screen = new CMSWindowsScreen(receiver, this);
|
||||
}
|
||||
|
||||
CMSWindowsPrimaryScreen::~CMSWindowsPrimaryScreen()
|
||||
|
@ -83,169 +58,10 @@ CMSWindowsPrimaryScreen::~CMSWindowsPrimaryScreen()
|
|||
assert(m_hookLibrary != NULL);
|
||||
assert(m_window == NULL);
|
||||
|
||||
// done with hook library
|
||||
delete m_screen;
|
||||
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
|
||||
CMSWindowsPrimaryScreen::reconfigure(UInt32 activeSides)
|
||||
{
|
||||
|
@ -264,41 +80,6 @@ CMSWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 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
|
||||
CMSWindowsPrimaryScreen::getToggleMask() const
|
||||
{
|
||||
|
@ -334,7 +115,7 @@ CMSWindowsPrimaryScreen::isLockedToScreen() const
|
|||
// 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
|
||||
// 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
|
||||
for (UInt32 i = 0; i < 256; ++i) {
|
||||
if ((m_keys[i] & 0x80) != 0) {
|
||||
|
@ -358,16 +139,29 @@ CMSWindowsPrimaryScreen::isLockedToScreen() const
|
|||
return false;
|
||||
}
|
||||
|
||||
IScreen*
|
||||
CMSWindowsPrimaryScreen::getScreen() const
|
||||
{
|
||||
return m_screen;
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsPrimaryScreen::onError()
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsPrimaryScreen::onScreensaver(bool activated)
|
||||
{
|
||||
m_receiver->onScreensaver(activated);
|
||||
}
|
||||
|
||||
bool
|
||||
CMSWindowsPrimaryScreen::onPreTranslate(const CEvent* event)
|
||||
CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event)
|
||||
{
|
||||
assert(event != NULL);
|
||||
|
||||
// forward to superclass
|
||||
if (CMSWindowsScreen::onPreTranslate(event)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// handle event
|
||||
const MSG* msg = &event->m_msg;
|
||||
switch (msg->message) {
|
||||
|
@ -386,11 +180,11 @@ CMSWindowsPrimaryScreen::onPreTranslate(const CEvent* event)
|
|||
const SInt32 repeat = (SInt32)(msg->lParam & 0xffff);
|
||||
if (repeat >= 2) {
|
||||
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 {
|
||||
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
|
||||
|
@ -399,7 +193,7 @@ CMSWindowsPrimaryScreen::onPreTranslate(const CEvent* event)
|
|||
else {
|
||||
// key release
|
||||
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
|
||||
updateKey(msg->wParam, false);
|
||||
|
@ -428,7 +222,7 @@ CMSWindowsPrimaryScreen::onPreTranslate(const CEvent* event)
|
|||
case WM_RBUTTONDOWN:
|
||||
log((CLOG_DEBUG1 "event: button press button=%d", button));
|
||||
if (button != kButtonNone) {
|
||||
m_primaryReceiver->onMouseDown(button);
|
||||
m_receiver->onMouseDown(button);
|
||||
m_keys[s_vkButton[button]] |= 0x80;
|
||||
}
|
||||
break;
|
||||
|
@ -438,7 +232,7 @@ CMSWindowsPrimaryScreen::onPreTranslate(const CEvent* event)
|
|||
case WM_RBUTTONUP:
|
||||
log((CLOG_DEBUG1 "event: button release button=%d", button));
|
||||
if (button != kButtonNone) {
|
||||
m_primaryReceiver->onMouseUp(button);
|
||||
m_receiver->onMouseUp(button);
|
||||
m_keys[s_vkButton[button]] &= ~0x80;
|
||||
}
|
||||
break;
|
||||
|
@ -450,7 +244,7 @@ CMSWindowsPrimaryScreen::onPreTranslate(const CEvent* event)
|
|||
// ignore message if posted prior to last mark change
|
||||
if (m_markReceived == m_mark) {
|
||||
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;
|
||||
|
||||
|
@ -459,8 +253,8 @@ CMSWindowsPrimaryScreen::onPreTranslate(const CEvent* event)
|
|||
if (m_markReceived == m_mark) {
|
||||
SInt32 x = static_cast<SInt32>(msg->wParam);
|
||||
SInt32 y = static_cast<SInt32>(msg->lParam);
|
||||
if (!m_active) {
|
||||
m_primaryReceiver->onMouseMovePrimary(x, y);
|
||||
if (!isActive()) {
|
||||
m_receiver->onMouseMovePrimary(x, y);
|
||||
}
|
||||
else {
|
||||
// compute motion delta. this is relative to the
|
||||
|
@ -480,7 +274,7 @@ CMSWindowsPrimaryScreen::onPreTranslate(const CEvent* event)
|
|||
warpCursorToCenter();
|
||||
|
||||
// send motion
|
||||
m_primaryReceiver->onMouseMoveSecondary(x, y);
|
||||
m_receiver->onMouseMoveSecondary(x, y);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -495,32 +289,6 @@ CMSWindowsPrimaryScreen::onPreTranslate(const CEvent* event)
|
|||
m_x = static_cast<SInt32>(msg->wParam);
|
||||
m_y = static_cast<SInt32>(msg->lParam);
|
||||
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;
|
||||
|
@ -531,111 +299,29 @@ CMSWindowsPrimaryScreen::onEvent(CEvent* event)
|
|||
{
|
||||
assert(event != NULL);
|
||||
|
||||
const MSG& msg = event->msg;
|
||||
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) {
|
||||
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:
|
||||
{
|
||||
// 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
|
||||
getCursorCenter(m_xCenter, m_yCenter);
|
||||
m_screen->getCursorCenter(m_xCenter, m_yCenter);
|
||||
|
||||
// warp mouse to center if active
|
||||
if (m_active) {
|
||||
if (isActive()) {
|
||||
warpCursorToCenter();
|
||||
}
|
||||
|
||||
// tell hook about resize if not active
|
||||
else {
|
||||
m_setZone(info.m_x, info.m_y,
|
||||
info.m_w, info.m_h, info.m_zoneSize);
|
||||
SInt32 x, y, w, h;
|
||||
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 false;
|
||||
}
|
||||
|
||||
CString
|
||||
CMSWindowsPrimaryScreen::getCurrentDesktopName() const
|
||||
{
|
||||
return m_deskName;
|
||||
}
|
||||
|
||||
SInt32
|
||||
CMSWindowsPrimaryScreen::getJumpZoneSize() const
|
||||
{
|
||||
|
@ -643,25 +329,96 @@ CMSWindowsPrimaryScreen::getJumpZoneSize() const
|
|||
}
|
||||
|
||||
void
|
||||
CMSWindowsPrimaryScreen::warpCursorToCenter()
|
||||
CMSWindowsPrimaryScreen::postCreateWindow(HWND window)
|
||||
{
|
||||
// warp to center. the extra info tells the hook DLL to send
|
||||
// SYNERGY_MSG_POST_WARP instead of SYNERGY_MSG_MOUSE_MOVE.
|
||||
// save window
|
||||
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;
|
||||
getScreenShape(x, y, w, h);
|
||||
mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
|
||||
(DWORD)((65535.99 * (m_xCenter - x)) / (w - 1)),
|
||||
(DWORD)((65535.99 * (m_yCenter - y)) / (h - 1)),
|
||||
0,
|
||||
0x12345678);
|
||||
// FIXME -- ignore mouse until we get warp notification?
|
||||
m_screen->getShape(x, y, w, h);
|
||||
MoveWindow(m_window, x, y, w, h, FALSE);
|
||||
|
||||
if (isActive()) {
|
||||
// hide the cursor
|
||||
showWindow();
|
||||
}
|
||||
else {
|
||||
// watch jump zones
|
||||
m_setRelay(false);
|
||||
|
||||
// all messages prior to now are invalid
|
||||
nextMark();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsPrimaryScreen::enterNoWarp()
|
||||
CMSWindowsPrimaryScreen::preDestroyWindow(HWND)
|
||||
{
|
||||
// not active anymore
|
||||
m_active = false;
|
||||
// hide the window if it's visible
|
||||
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
|
||||
m_mouseMoveIgnore = 0;
|
||||
|
@ -674,14 +431,78 @@ CMSWindowsPrimaryScreen::enterNoWarp()
|
|||
|
||||
// watch jump zones
|
||||
m_setRelay(false);
|
||||
}
|
||||
|
||||
// restore active window and hide our window
|
||||
hideWindow();
|
||||
void
|
||||
CMSWindowsPrimaryScreen::onPostEnter()
|
||||
{
|
||||
// all messages prior to now are invalid
|
||||
nextMark();
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsPrimaryScreen::onPreLeave()
|
||||
{
|
||||
assert(m_window != NULL);
|
||||
|
||||
// all messages prior to now are invalid
|
||||
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
|
||||
CMSWindowsPrimaryScreen::showWindow()
|
||||
{
|
||||
|
@ -733,262 +554,18 @@ CMSWindowsPrimaryScreen::hideWindow()
|
|||
}
|
||||
|
||||
void
|
||||
CMSWindowsPrimaryScreen::checkClipboard()
|
||||
CMSWindowsPrimaryScreen::warpCursorToCenter()
|
||||
{
|
||||
// if we think we own the clipboard but we don't then somebody
|
||||
// grabbed the clipboard on this screen without us knowing.
|
||||
// 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).
|
||||
// warp to center. the extra info tells the hook DLL to send
|
||||
// SYNERGY_MSG_POST_WARP instead of SYNERGY_MSG_MOUSE_MOVE.
|
||||
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();
|
||||
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;
|
||||
m_screen->getShape(x, y, w, h);
|
||||
mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
|
||||
(DWORD)((65535.99 * (m_xCenter - x)) / (w - 1)),
|
||||
(DWORD)((65535.99 * (m_yCenter - y)) / (h - 1)),
|
||||
0,
|
||||
0x12345678);
|
||||
// FIXME -- ignore mouse until we get warp notification?
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -1,74 +1,61 @@
|
|||
#ifndef CMSWINDOWSPRIMARYSCREEN_H
|
||||
#define CMSWINDOWSPRIMARYSCREEN_H
|
||||
|
||||
#include "CMSWindowsScreen.h"
|
||||
#include "IPrimaryScreen.h"
|
||||
#include "CPrimaryScreen.h"
|
||||
#include "IMSWindowsScreenEventHandler.h"
|
||||
#include "CSynergyHook.h"
|
||||
#include "MouseTypes.h"
|
||||
#include "CString.h"
|
||||
|
||||
class CMSWindowsScreen;
|
||||
class IScreenReceiver;
|
||||
class IPrimaryScreenReceiver;
|
||||
|
||||
class CMSWindowsPrimaryScreen : public CMSWindowsScreen, public IPrimaryScreen {
|
||||
class CMSWindowsPrimaryScreen :
|
||||
public CPrimaryScreen, public IMSWindowsScreenEventHandler {
|
||||
public:
|
||||
typedef bool (CMSWindowsPrimaryScreen::*HookMethod)(int, WPARAM, LPARAM);
|
||||
|
||||
CMSWindowsPrimaryScreen(IScreenReceiver*, IPrimaryScreenReceiver*);
|
||||
virtual ~CMSWindowsPrimaryScreen();
|
||||
|
||||
// IPrimaryScreen overrides
|
||||
virtual void run();
|
||||
virtual void stop();
|
||||
virtual void open();
|
||||
virtual void close();
|
||||
virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute, bool);
|
||||
virtual bool leave();
|
||||
// CPrimaryScreen overrides
|
||||
virtual void reconfigure(UInt32 activeSides);
|
||||
virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute);
|
||||
virtual void setClipboard(ClipboardID, const IClipboard*);
|
||||
virtual void grabClipboard(ClipboardID);
|
||||
virtual void getClipboard(ClipboardID, IClipboard*) const;
|
||||
virtual void warpCursor(SInt32 x, SInt32 y);
|
||||
virtual KeyModifierMask getToggleMask() 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:
|
||||
// CMSWindowsScreen overrides
|
||||
virtual bool onPreTranslate(const CEvent* event);
|
||||
virtual bool onEvent(CEvent* event);
|
||||
virtual CString getCurrentDesktopName() const;
|
||||
// CPrimaryScreen overrides
|
||||
virtual void onPreRun();
|
||||
virtual void onPreOpen();
|
||||
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:
|
||||
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();
|
||||
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
|
||||
void nextMark();
|
||||
|
@ -77,12 +64,11 @@ private:
|
|||
KeyID mapKey(WPARAM keycode, LPARAM info,
|
||||
KeyModifierMask* maskOut);
|
||||
ButtonID mapButton(WPARAM button) const;
|
||||
void updateKeys();
|
||||
void updateKey(UINT vkCode, bool press);
|
||||
|
||||
private:
|
||||
IScreenReceiver* m_receiver;
|
||||
IPrimaryScreenReceiver* m_primaryReceiver;
|
||||
IPrimaryScreenReceiver* m_receiver;
|
||||
CMSWindowsScreen* m_screen;
|
||||
|
||||
// true if windows 95/98/me
|
||||
bool m_is95Family;
|
||||
|
@ -90,27 +76,13 @@ private:
|
|||
// the main loop's thread id
|
||||
DWORD m_threadID;
|
||||
|
||||
// the timer used to check for desktop switching
|
||||
UINT m_timer;
|
||||
|
||||
// the current desk and it's name
|
||||
HDESK m_desk;
|
||||
CString m_deskName;
|
||||
|
||||
// our window (for getting clipboard changes)
|
||||
// our 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
|
||||
UInt32 m_mark;
|
||||
UInt32 m_markReceived;
|
||||
|
||||
// clipboard stuff
|
||||
HWND m_nextClipboardWindow;
|
||||
HWND m_clipboardOwner;
|
||||
|
||||
// map of key state
|
||||
BYTE m_keys[256];
|
||||
|
||||
|
@ -132,8 +104,6 @@ private:
|
|||
SetSidesFunc m_setSides;
|
||||
SetZoneFunc m_setZone;
|
||||
SetRelayFunc m_setRelay;
|
||||
InstallScreenSaverFunc m_installScreenSaver;
|
||||
UninstallScreenSaverFunc m_uninstallScreenSaver;
|
||||
|
||||
// stuff for restoring active window
|
||||
HWND m_lastForegroundWindow;
|
||||
|
|
|
@ -73,7 +73,7 @@ CPrimaryScreen::open()
|
|||
updateKeys();
|
||||
|
||||
// get notified of screen saver activation/deactivation
|
||||
getScreen()->openScreenSaver(true);
|
||||
getScreen()->openScreensaver(true);
|
||||
|
||||
// subclass hook
|
||||
onPostOpen();
|
||||
|
@ -94,7 +94,7 @@ void
|
|||
CPrimaryScreen::close()
|
||||
{
|
||||
onPreClose();
|
||||
getScreen()->closeScreenSaver();
|
||||
getScreen()->closeScreensaver();
|
||||
destroyWindow();
|
||||
getScreen()->close();
|
||||
onPostClose();
|
||||
|
@ -197,12 +197,6 @@ CPrimaryScreen::getClipboard(ClipboardID id,
|
|||
getScreen()->getClipboard(id, clipboard);
|
||||
}
|
||||
|
||||
SInt32
|
||||
CPrimaryScreen::getJumpZoneSize() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
CPrimaryScreen::onPreRun()
|
||||
{
|
||||
|
|
|
@ -42,8 +42,8 @@ public:
|
|||
bool leave();
|
||||
|
||||
// called when the configuration has changed. activeSides is a
|
||||
// bitmask of CConfig::EDirectionMask indicating which sides of
|
||||
// the primary screen are linked to clients.
|
||||
// bitmask of EDirectionMask indicating which sides of the
|
||||
// primary screen are linked to clients.
|
||||
virtual void reconfigure(UInt32 activeSides) = 0;
|
||||
|
||||
// warp the cursor to the given absolute coordinates
|
||||
|
@ -66,8 +66,8 @@ public:
|
|||
void getClipboard(ClipboardID, IClipboard*) const;
|
||||
|
||||
// returns the size of the zone on the edges of the screen that
|
||||
// causes the cursor to jump to another screen. default returns 1.
|
||||
virtual SInt32 getJumpZoneSize() const;
|
||||
// causes the cursor to jump to another screen.
|
||||
virtual SInt32 getJumpZoneSize() const = 0;
|
||||
|
||||
// get the primary screen's current toggle modifier key state.
|
||||
// the returned mask should have the corresponding bit set for
|
||||
|
|
|
@ -197,21 +197,17 @@ CServer::getActivePrimarySides() const
|
|||
{
|
||||
// note -- m_mutex must be locked on entry
|
||||
UInt32 sides = 0;
|
||||
if (!m_config.getNeighbor(getPrimaryScreenName(),
|
||||
CConfig::kLeft).empty()) {
|
||||
sides |= CConfig::kLeftMask;
|
||||
if (!m_config.getNeighbor(getPrimaryScreenName(), kLeft).empty()) {
|
||||
sides |= kLeftMask;
|
||||
}
|
||||
if (!m_config.getNeighbor(getPrimaryScreenName(),
|
||||
CConfig::kRight).empty()) {
|
||||
sides |= CConfig::kRightMask;
|
||||
if (!m_config.getNeighbor(getPrimaryScreenName(), kRight).empty()) {
|
||||
sides |= kRightMask;
|
||||
}
|
||||
if (!m_config.getNeighbor(getPrimaryScreenName(),
|
||||
CConfig::kTop).empty()) {
|
||||
sides |= CConfig::kTopMask;
|
||||
if (!m_config.getNeighbor(getPrimaryScreenName(), kTop).empty()) {
|
||||
sides |= kTopMask;
|
||||
}
|
||||
if (!m_config.getNeighbor(getPrimaryScreenName(),
|
||||
CConfig::kBottom).empty()) {
|
||||
sides |= CConfig::kBottomMask;
|
||||
if (!m_config.getNeighbor(getPrimaryScreenName(), kBottom).empty()) {
|
||||
sides |= kBottomMask;
|
||||
}
|
||||
return sides;
|
||||
}
|
||||
|
@ -505,25 +501,25 @@ CServer::onMouseMovePrimaryNoLock(SInt32 x, SInt32 y)
|
|||
SInt32 zoneSize = m_active->getJumpZoneSize();
|
||||
|
||||
// see if we should change screens
|
||||
CConfig::EDirection dir;
|
||||
EDirection dir;
|
||||
if (x < ax + zoneSize) {
|
||||
x -= zoneSize;
|
||||
dir = CConfig::kLeft;
|
||||
dir = kLeft;
|
||||
log((CLOG_DEBUG1 "switch to left"));
|
||||
}
|
||||
else if (x >= ax + aw - zoneSize) {
|
||||
x += zoneSize;
|
||||
dir = CConfig::kRight;
|
||||
dir = kRight;
|
||||
log((CLOG_DEBUG1 "switch to right"));
|
||||
}
|
||||
else if (y < ay + zoneSize) {
|
||||
y -= zoneSize;
|
||||
dir = CConfig::kTop;
|
||||
dir = kTop;
|
||||
log((CLOG_DEBUG1 "switch to top"));
|
||||
}
|
||||
else if (y >= ay + ah - zoneSize) {
|
||||
y += zoneSize;
|
||||
dir = CConfig::kBottom;
|
||||
dir = kBottom;
|
||||
log((CLOG_DEBUG1 "switch to bottom"));
|
||||
}
|
||||
else {
|
||||
|
@ -584,24 +580,24 @@ CServer::onMouseMoveSecondaryNoLock(SInt32 dx, SInt32 dy)
|
|||
IClient* newScreen = NULL;
|
||||
if (!isLockedToScreenNoLock()) {
|
||||
// find direction of neighbor
|
||||
CConfig::EDirection dir;
|
||||
EDirection dir;
|
||||
if (m_x < ax) {
|
||||
dir = CConfig::kLeft;
|
||||
dir = kLeft;
|
||||
}
|
||||
else if (m_x > ax + aw - 1) {
|
||||
dir = CConfig::kRight;
|
||||
dir = kRight;
|
||||
}
|
||||
else if (m_y < ay) {
|
||||
dir = CConfig::kTop;
|
||||
dir = kTop;
|
||||
}
|
||||
else if (m_y > ay + ah - 1) {
|
||||
dir = CConfig::kBottom;
|
||||
dir = kBottom;
|
||||
}
|
||||
else {
|
||||
newScreen = m_active;
|
||||
|
||||
// keep compiler quiet about unset variable
|
||||
dir = CConfig::kLeft;
|
||||
dir = kLeft;
|
||||
}
|
||||
|
||||
// get neighbor if we should switch
|
||||
|
@ -760,7 +756,7 @@ CServer::switchScreen(IClient* dst, SInt32 x, SInt32 y, bool forScreensaver)
|
|||
}
|
||||
|
||||
IClient*
|
||||
CServer::getNeighbor(IClient* src, CConfig::EDirection dir) const
|
||||
CServer::getNeighbor(IClient* src, EDirection dir) const
|
||||
{
|
||||
assert(src != NULL);
|
||||
|
||||
|
@ -793,7 +789,7 @@ CServer::getNeighbor(IClient* src, CConfig::EDirection dir) const
|
|||
|
||||
IClient*
|
||||
CServer::getNeighbor(IClient* src,
|
||||
CConfig::EDirection srcSide, SInt32& x, SInt32& y) const
|
||||
EDirection srcSide, SInt32& x, SInt32& y) const
|
||||
{
|
||||
assert(src != NULL);
|
||||
|
||||
|
@ -816,7 +812,7 @@ CServer::getNeighbor(IClient* src,
|
|||
// actual to canonical position on entry to and from canonical to
|
||||
// actual on exit from the search.
|
||||
switch (srcSide) {
|
||||
case CConfig::kLeft:
|
||||
case kLeft:
|
||||
x -= dx;
|
||||
while (dst != NULL && dst != lastGoodScreen) {
|
||||
lastGoodScreen = dst;
|
||||
|
@ -832,7 +828,7 @@ CServer::getNeighbor(IClient* src,
|
|||
x += dx;
|
||||
break;
|
||||
|
||||
case CConfig::kRight:
|
||||
case kRight:
|
||||
x -= dx;
|
||||
while (dst != NULL) {
|
||||
x -= dw;
|
||||
|
@ -848,7 +844,7 @@ CServer::getNeighbor(IClient* src,
|
|||
x += dx;
|
||||
break;
|
||||
|
||||
case CConfig::kTop:
|
||||
case kTop:
|
||||
y -= dy;
|
||||
while (dst != NULL) {
|
||||
lastGoodScreen = dst;
|
||||
|
@ -864,7 +860,7 @@ CServer::getNeighbor(IClient* src,
|
|||
y += dy;
|
||||
break;
|
||||
|
||||
case CConfig::kBottom:
|
||||
case kBottom:
|
||||
y -= dy;
|
||||
while (dst != NULL) {
|
||||
y -= dh;
|
||||
|
@ -892,26 +888,26 @@ CServer::getNeighbor(IClient* src,
|
|||
if (dst == m_primaryClient) {
|
||||
const CString dstName(dst->getName());
|
||||
switch (srcSide) {
|
||||
case CConfig::kLeft:
|
||||
if (!m_config.getNeighbor(dstName, CConfig::kRight).empty() &&
|
||||
case kLeft:
|
||||
if (!m_config.getNeighbor(dstName, kRight).empty() &&
|
||||
x > dx + dw - 1 - dst->getJumpZoneSize())
|
||||
x = dx + dw - 1 - dst->getJumpZoneSize();
|
||||
break;
|
||||
|
||||
case CConfig::kRight:
|
||||
if (!m_config.getNeighbor(dstName, CConfig::kLeft).empty() &&
|
||||
case kRight:
|
||||
if (!m_config.getNeighbor(dstName, kLeft).empty() &&
|
||||
x < dx + dst->getJumpZoneSize())
|
||||
x = dx + dst->getJumpZoneSize();
|
||||
break;
|
||||
|
||||
case CConfig::kTop:
|
||||
if (!m_config.getNeighbor(dstName, CConfig::kBottom).empty() &&
|
||||
case kTop:
|
||||
if (!m_config.getNeighbor(dstName, kBottom).empty() &&
|
||||
y > dy + dh - 1 - dst->getJumpZoneSize())
|
||||
y = dy + dh - 1 - dst->getJumpZoneSize();
|
||||
break;
|
||||
|
||||
case CConfig::kBottom:
|
||||
if (!m_config.getNeighbor(dstName, CConfig::kTop).empty() &&
|
||||
case kBottom:
|
||||
if (!m_config.getNeighbor(dstName, kTop).empty() &&
|
||||
y < dy + dst->getJumpZoneSize())
|
||||
y = dy + dst->getJumpZoneSize();
|
||||
break;
|
||||
|
@ -925,8 +921,8 @@ CServer::getNeighbor(IClient* src,
|
|||
// should be set 120 pixels from the top (again 20% from the
|
||||
// top).
|
||||
switch (srcSide) {
|
||||
case CConfig::kLeft:
|
||||
case CConfig::kRight:
|
||||
case kLeft:
|
||||
case kRight:
|
||||
y -= sy;
|
||||
if (y < 0) {
|
||||
y = 0;
|
||||
|
@ -941,8 +937,8 @@ CServer::getNeighbor(IClient* src,
|
|||
y += dy;
|
||||
break;
|
||||
|
||||
case CConfig::kTop:
|
||||
case CConfig::kBottom:
|
||||
case kTop:
|
||||
case kBottom:
|
||||
x -= sx;
|
||||
if (x < 0) {
|
||||
x = 0;
|
||||
|
|
|
@ -96,15 +96,14 @@ private:
|
|||
SInt32 x, SInt32 y, bool forScreenSaver);
|
||||
|
||||
// lookup neighboring screen
|
||||
IClient* getNeighbor(IClient*, CConfig::EDirection) const;
|
||||
IClient* getNeighbor(IClient*, EDirection) const;
|
||||
|
||||
// lookup neighboring screen. given a position relative to the
|
||||
// source screen, find the screen we should move onto and where.
|
||||
// if the position is sufficiently far from the source then we
|
||||
// cross multiple screens. if there is no suitable screen then
|
||||
// return NULL and x,y are not modified.
|
||||
IClient* getNeighbor(IClient*,
|
||||
CConfig::EDirection,
|
||||
IClient* getNeighbor(IClient*, EDirection,
|
||||
SInt32& x, SInt32& y) const;
|
||||
|
||||
// open/close the primary screen
|
||||
|
|
|
@ -331,6 +331,12 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event)
|
|||
return false;
|
||||
}
|
||||
|
||||
SInt32
|
||||
CXWindowsPrimaryScreen::getJumpZoneSize() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsPrimaryScreen::onPreRun()
|
||||
{
|
||||
|
@ -419,7 +425,7 @@ CXWindowsPrimaryScreen::createWindow()
|
|||
selectEvents(display, m_screen->getRoot());
|
||||
}
|
||||
|
||||
// tell our superclass about the window
|
||||
// tell generic screen about the window
|
||||
m_screen->setWindow(m_window);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ public:
|
|||
virtual void onScreensaver(bool activated);
|
||||
virtual bool onPreDispatch(const CEvent* event);
|
||||
virtual bool onEvent(CEvent* event);
|
||||
virtual SInt32 getJumpZoneSize() const;
|
||||
|
||||
protected:
|
||||
// CPrimaryScreen overrides
|
||||
|
|
|
@ -118,6 +118,10 @@ SOURCE=.\CPrimaryClient.cpp
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CPrimaryScreen.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CServer.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -158,11 +162,11 @@ SOURCE=.\CPrimaryClient.h
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CServer.h
|
||||
SOURCE=.\CPrimaryScreen.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\IPrimaryScreen.h
|
||||
SOURCE=.\CServer.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
|
|
|
@ -37,8 +37,8 @@ public:
|
|||
// will call IScreenEventHandler's onScreenSaver() when the screensaver
|
||||
// activates or deactivates until close. if notify is false then
|
||||
// the screen saver is disabled on open and restored on close.
|
||||
virtual void openScreenSaver(bool notify) = 0;
|
||||
virtual void closeScreenSaver() = 0;
|
||||
virtual void openScreensaver(bool notify) = 0;
|
||||
virtual void closeScreensaver() = 0;
|
||||
|
||||
// activate or deactivate the screen saver
|
||||
virtual void screensaver(bool activate) = 0;
|
||||
|
|
|
@ -34,6 +34,11 @@ public:
|
|||
// 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;
|
||||
|
||||
// accessors
|
||||
|
||||
// called to get the jump zone size
|
||||
virtual SInt32 getJumpZoneSize() const = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,6 +16,23 @@ static const double kHeartRate = 2.0;
|
|||
// time without a heartbeat that we call death
|
||||
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
|
||||
// refers to the n'th argument (counting from one). message codes are
|
||||
|
|
|
@ -155,6 +155,14 @@ SOURCE=.\IPrimaryScreenReceiver.h
|
|||
# End 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
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
Loading…
Reference in New Issue