checkpoint. still refactoring. merged common code from primary

screens into CPrimaryScreen and merged common code from secondary
screens into CSecondaryScreen.  changed is-a relationship to a
has-a between the primary and secondary screen classes and the
generic platform dependent screen class to avoid multiple
inheritance of implementation.  also standardized the interface
for those generic screen classes.  adding a platform now involves
implementing simpler interfaces:  IScreen for the generic screen,
IScreenEventHandler and some methods of CPrimaryScreen for the
primary screen, and IScreenEventHandler and some methods of
CSecondaryScreen for the secondary screen.  did X11 platform
but not win32 platform.
This commit is contained in:
crs 2002-07-13 22:00:38 +00:00
parent 52b60d5175
commit f48a5fe387
34 changed files with 1945 additions and 1431 deletions

View File

@ -4,7 +4,7 @@
#include "CInputPacketStream.h"
#include "COutputPacketStream.h"
#include "CProtocolUtil.h"
#include "ISecondaryScreen.h"
#include "CSecondaryScreen.h"
#include "IServer.h"
#include "ProtocolTypes.h"
#include "XScreen.h"
@ -148,9 +148,7 @@ CClient::run()
this, &CClient::runSession));
// handle events
log((CLOG_DEBUG "starting event handling"));
m_screen->run();
log((CLOG_DEBUG "stopped event handling"));
// clean up
deleteSession(thread);
@ -160,7 +158,6 @@ CClient::run()
log((CLOG_ERR "client error: %s", e.what()));
// clean up
log((CLOG_DEBUG "stopped event handling"));
deleteSession(thread);
log((CLOG_NOTE "stopping client \"%s\"", m_name.c_str()));
CLock lock(&m_mutex);
@ -168,7 +165,6 @@ CClient::run()
}
catch (XThread&) {
// clean up
log((CLOG_DEBUG "stopped event handling"));
deleteSession(thread);
log((CLOG_NOTE "stopping client \"%s\"", m_name.c_str()));
throw;
@ -177,7 +173,6 @@ CClient::run()
log((CLOG_DEBUG "unknown client error"));
// clean up
log((CLOG_DEBUG "stopped event handling"));
deleteSession(thread);
log((CLOG_NOTE "stopping client \"%s\"", m_name.c_str()));
throw;
@ -188,6 +183,7 @@ void
CClient::close()
{
closeSecondaryScreen();
log((CLOG_INFO "closed screen"));
}
void
@ -291,9 +287,9 @@ CClient::mouseWheel(SInt32 delta)
}
void
CClient::screenSaver(bool activate)
CClient::screensaver(bool activate)
{
m_screen->screenSaver(activate);
m_screen->screensaver(activate);
}
CString
@ -302,6 +298,12 @@ CClient::getName() const
return m_name;
}
SInt32
CClient::getJumpZoneSize() const
{
return m_screen->getJumpZoneSize();
}
void
CClient::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
{
@ -309,21 +311,15 @@ CClient::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
}
void
CClient::getCenter(SInt32&, SInt32&) const
CClient::getCursorPos(SInt32& x, SInt32& y) const
{
assert(0 && "shouldn't be called");
m_screen->getCursorPos(x, y);
}
void
CClient::getMousePos(SInt32& x, SInt32& y) const
CClient::getCursorCenter(SInt32&, SInt32&) const
{
m_screen->getMousePos(x, y);
}
SInt32
CClient::getJumpZoneSize() const
{
return m_screen->getJumpZoneSize();
assert(0 && "shouldn't be called");
}
// FIXME -- use factory to create screen

View File

@ -7,10 +7,10 @@
#include "CNetworkAddress.h"
#include "CMutex.h"
class CSecondaryScreen;
class CServerProxy;
class CThread;
class IDataSocket;
class ISecondaryScreen;
class IScreenReceiver;
class CClient : public IScreenReceiver, public IClient {
@ -50,7 +50,7 @@ public:
// FIXME -- can we avoid passing everything here?
virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask,
bool screenSaver);
bool forScreensaver);
virtual bool leave();
virtual void setClipboard(ClipboardID, const CString&);
virtual void grabClipboard(ClipboardID);
@ -62,13 +62,13 @@ public:
virtual void mouseUp(ButtonID);
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs);
virtual void mouseWheel(SInt32 delta);
virtual void screenSaver(bool activate);
virtual void screensaver(bool activate);
virtual CString getName() const;
virtual SInt32 getJumpZoneSize() const;
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const;
virtual void getCenter(SInt32& x, SInt32& y) const;
virtual void getMousePos(SInt32& x, SInt32& y) const;
virtual SInt32 getJumpZoneSize() const;
virtual void getCursorPos(SInt32& x, SInt32& y) const;
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
private:
// open/close the secondary screen
@ -87,7 +87,7 @@ private:
private:
CMutex m_mutex;
CString m_name;
ISecondaryScreen* m_screen;
CSecondaryScreen* m_screen;
IScreenReceiver* m_server;
CNetworkAddress m_serverAddress;
bool m_camp;

263
client/CSecondaryScreen.cpp Normal file
View File

@ -0,0 +1,263 @@
#include "CSecondaryScreen.h"
#include "IScreen.h"
#include "CLock.h"
#include "CThread.h"
#include "CLog.h"
//
// CSecondaryScreen
//
CSecondaryScreen::CSecondaryScreen()
{
// do nothing
}
CSecondaryScreen::~CSecondaryScreen()
{
// do nothing
}
bool
CSecondaryScreen::isActive() const
{
CLock lock(&m_mutex);
return m_active;
}
void
CSecondaryScreen::run()
{
// change our priority
CThread::getCurrentThread().setPriority(-7);
// run event loop
try {
log((CLOG_DEBUG "entering event loop"));
onPreRun();
getScreen()->mainLoop();
onPostRun();
log((CLOG_DEBUG "exiting event loop"));
}
catch (...) {
onPostRun();
log((CLOG_DEBUG "exiting event loop"));
throw;
}
}
void
CSecondaryScreen::stop()
{
getScreen()->exitMainLoop();
}
void
CSecondaryScreen::open()
{
try {
// subclass hook
onPreOpen();
// open the screen
getScreen()->open();
// create and prepare our window
createWindow();
// assume primary has all clipboards
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
grabClipboard(id);
}
// update keyboard state
updateKeys();
// disable the screen saver
getScreen()->openScreenSaver(false);
// subclass hook
onPostOpen();
}
catch (...) {
close();
throw;
}
// hide the cursor
m_active = true;
leave();
}
void
CSecondaryScreen::close()
{
onPreClose();
getScreen()->closeScreenSaver();
destroyWindow();
getScreen()->close();
onPostClose();
}
void
CSecondaryScreen::enter(SInt32 x, SInt32 y, KeyModifierMask mask)
{
CLock lock(&m_mutex);
assert(m_active == false);
log((CLOG_INFO "entering screen at %d,%d mask=%04x", x, y, mask));
getScreen()->syncDesktop();
// now active
m_active = true;
// subclass hook
onPreEnter();
// update our keyboard state to reflect the local state
updateKeys();
// toggle modifiers that don't match the desired state
setToggleState(mask);
// warp to requested location
warpCursor(x, y);
// show mouse
hideWindow();
// subclass hook
onPostEnter();
}
void
CSecondaryScreen::leave()
{
log((CLOG_INFO "leaving screen"));
CLock lock(&m_mutex);
assert(m_active == true);
getScreen()->syncDesktop();
// subclass hook
onPreLeave();
// hide mouse
showWindow();
// subclass hook
onPostLeave();
// not active anymore
m_active = false;
// make sure our idea of clipboard ownership is correct
getScreen()->checkClipboards();
}
void
CSecondaryScreen::setClipboard(ClipboardID id,
const IClipboard* clipboard)
{
getScreen()->setClipboard(id, clipboard);
}
void
CSecondaryScreen::grabClipboard(ClipboardID id)
{
getScreen()->setClipboard(id, NULL);
}
void
CSecondaryScreen::screensaver(bool activate)
{
getScreen()->screensaver(activate);
}
void
CSecondaryScreen::getClipboard(ClipboardID id,
IClipboard* clipboard) const
{
getScreen()->getClipboard(id, clipboard);
}
SInt32
CSecondaryScreen::getJumpZoneSize() const
{
return 0;
}
void
CSecondaryScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
{
getScreen()->syncDesktop();
getScreen()->getShape(x, y, w, h);
}
void
CSecondaryScreen::getCursorPos(SInt32& x, SInt32& y) const
{
getScreen()->syncDesktop();
getScreen()->getCursorPos(x, y);
}
void
CSecondaryScreen::onPreRun()
{
// do nothing
}
void
CSecondaryScreen::onPostRun()
{
// do nothing
}
void
CSecondaryScreen::onPreOpen()
{
// do nothing
}
void
CSecondaryScreen::onPostOpen()
{
// do nothing
}
void
CSecondaryScreen::onPreClose()
{
// do nothing
}
void
CSecondaryScreen::onPostClose()
{
// do nothing
}
void
CSecondaryScreen::onPreEnter()
{
// do nothing
}
void
CSecondaryScreen::onPostEnter()
{
// do nothing
}
void
CSecondaryScreen::onPreLeave()
{
// do nothing
}
void
CSecondaryScreen::onPostLeave()
{
// do nothing
}

141
client/CSecondaryScreen.h Normal file
View File

@ -0,0 +1,141 @@
#ifndef CSECONDARYSCREEN_H
#define CSECONDARYSCREEN_H
#include "ClipboardTypes.h"
#include "KeyTypes.h"
#include "MouseTypes.h"
#include "CMutex.h"
class IClipboard;
class IScreen;
// platform independent base class for secondary screen implementations.
// each platform will derive a class from CSecondaryScreen to handle
// platform dependent operations.
class CSecondaryScreen {
public:
CSecondaryScreen();
virtual ~CSecondaryScreen();
// manipulators
// enter the screen's message loop. this returns when it detects
// the application should terminate or when stop() is called.
// run() may only be called between open() and close().
void run();
// cause run() to return
void stop();
// initialize the screen, hide the cursor, and disable the screen
// saver. start reporting events to the IScreenReceiver (which is
// set through some other interface).
void open();
// close the screen. should restore the screen saver. it should
// also simulate key up events for any keys that have simulate key
// down events without a matching key up. without this the client
// will leave its keyboard in the wrong logical state.
void close();
// called when the user navigates to this secondary screen. warps
// the cursor to the given absoltue coordinates and unhide it. prepare to
// simulate input events.
void enter(SInt32 x, SInt32 y, KeyModifierMask mask);
// called when the user navigates off the secondary screen. clean
// up input event simulation and hide the cursor.
void leave();
// set the screen's clipboard contents. this is usually called
// soon after an enter().
void setClipboard(ClipboardID, const IClipboard*);
// synergy should own the clipboard
void grabClipboard(ClipboardID);
// activate or deactivate the screen saver
void screensaver(bool activate);
// keyboard input event synthesis
virtual void keyDown(KeyID, KeyModifierMask) = 0;
virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count) = 0;
virtual void keyUp(KeyID, KeyModifierMask) = 0;
// mouse input event synthesis
virtual void mouseDown(ButtonID) = 0;
virtual void mouseUp(ButtonID) = 0;
virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute) = 0;
virtual void mouseWheel(SInt32 delta) = 0;
// accessors
// returns true iff the screen is active (i.e. the user has entered
// the screen)
bool isActive() const;
// return the contents of the given clipboard
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;
// get the shape (position of upper-left corner and size) of the
// screen
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const;
// get the position of the mouse on the screen
virtual void getCursorPos(SInt32& x, SInt32& y) const;
// get the platform dependent screen object
virtual IScreen* getScreen() const = 0;
protected:
// template method hooks. these are called on entry/exit to the
// named method. override to do platform specific operations.
// defaults do nothing.
virtual void onPreRun();
virtual void onPostRun();
virtual void onPreOpen();
virtual void onPostOpen();
virtual void onPreClose();
virtual void onPostClose();
virtual void onPreEnter();
virtual void onPostEnter();
virtual void onPreLeave();
virtual void onPostLeave();
// create/destroy the window. this window is generally used to
// receive events and hide the cursor.
virtual void createWindow() = 0;
virtual void destroyWindow() = 0;
// called when the user navigates off the secondary screen. hide
// the cursor.
virtual void showWindow() = 0;
// called when the user navigates to this secondary screen. show
// the cursor and prepare to synthesize input events.
virtual void hideWindow() = 0;
// warp the cursor to the given absolute coordinates
virtual void warpCursor(SInt32 x, SInt32 y) = 0;
// check the current keyboard state. normally a screen will save
// the keyboard state in this method and use this shadow state
// when synthesizing events.
virtual void updateKeys() = 0;
// toggle modifiers that don't match the given state
virtual void setToggleState(KeyModifierMask) = 0;
private:
CMutex m_mutex;
// m_active is true if this screen has been entered
bool m_active;
};
#endif

View File

@ -131,7 +131,7 @@ CServerProxy::run()
}
else if (memcmp(code, kMsgCScreenSaver, 4) == 0) {
screenSaver();
screensaver();
}
else if (memcmp(code, kMsgQInfo, 4) == 0) {
@ -484,7 +484,7 @@ CServerProxy::mouseWheel()
}
void
CServerProxy::screenSaver()
CServerProxy::screensaver()
{
// parse
SInt8 on;
@ -492,7 +492,7 @@ CServerProxy::screenSaver()
log((CLOG_DEBUG1 "recv screen saver on=%d", on));
// forward
getClient()->screenSaver(on != 0);
getClient()->screensaver(on != 0);
}
void
@ -501,7 +501,7 @@ CServerProxy::queryInfo()
// get current info
CClientInfo info;
getClient()->getShape(info.m_x, info.m_y, info.m_w, info.m_h);
getClient()->getMousePos(info.m_mx, info.m_my);
getClient()->getCursorPos(info.m_mx, info.m_my);
info.m_zoneSize = getClient()->getJumpZoneSize();
// send it

View File

@ -56,7 +56,7 @@ private:
void mouseUp();
void mouseMove();
void mouseWheel();
void screenSaver();
void screensaver();
void queryInfo();
void infoAcknowledgment();

View File

@ -1,8 +1,9 @@
#include "CXWindowsSecondaryScreen.h"
#include "IScreenReceiver.h"
#include "CXWindowsClipboard.h"
#include "CXWindowsScreen.h"
#include "CXWindowsScreenSaver.h"
#include "CXWindowsUtil.h"
#include "IScreenReceiver.h"
#include "XScreen.h"
#include "CThread.h"
#include "CLog.h"
@ -26,153 +27,16 @@
//
CXWindowsSecondaryScreen::CXWindowsSecondaryScreen(IScreenReceiver* receiver) :
m_receiver(receiver),
m_window(None),
m_active(false)
CSecondaryScreen(),
m_window(None)
{
assert(m_receiver != NULL);
m_screen = new CXWindowsScreen(receiver, this);
}
CXWindowsSecondaryScreen::~CXWindowsSecondaryScreen()
{
assert(m_window == None);
}
void
CXWindowsSecondaryScreen::run()
{
assert(m_window != None);
// 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
CXWindowsSecondaryScreen::stop()
{
exitMainLoop();
}
void
CXWindowsSecondaryScreen::open()
{
assert(m_window == None);
try {
// open the display
openDisplay();
// create and prepare our window
createWindow();
// initialize the clipboards; assume primary has all clipboards
initClipboards(m_window);
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
grabClipboard(id);
}
// check for peculiarities
// FIXME -- may have to get these from some database
m_numLockHalfDuplex = false;
m_capsLockHalfDuplex = false;
// m_numLockHalfDuplex = true;
// m_capsLockHalfDuplex = true;
// get the display
CDisplayLock display(this);
// update key state
updateKeys(display);
updateKeycodeMap(display);
updateModifierMap(display);
updateModifiers(display);
// disable the screen saver
installScreenSaver();
}
catch (...) {
close();
throw;
}
// hide the cursor
m_active = true;
leave();
}
void
CXWindowsSecondaryScreen::close()
{
uninstallScreenSaver();
destroyWindow();
closeDisplay();
}
void
CXWindowsSecondaryScreen::enter(SInt32 x, SInt32 y, KeyModifierMask mask)
{
assert(m_window != None);
assert(m_active == false);
log((CLOG_INFO "entering screen at %d,%d mask=%04x", x, y, mask));
CDisplayLock display(this);
// now active
m_active = true;
// update our keyboard state to reflect the local state
updateKeys(display);
updateModifiers(display);
// toggle modifiers that don't match the desired state
unsigned int xMask = maskToX(mask);
if ((xMask & m_capsLockMask) != (m_mask & m_capsLockMask)) {
toggleKey(display, XK_Caps_Lock, m_capsLockMask);
}
if ((xMask & m_numLockMask) != (m_mask & m_numLockMask)) {
toggleKey(display, XK_Num_Lock, m_numLockMask);
}
if ((xMask & m_scrollLockMask) != (m_mask & m_scrollLockMask)) {
toggleKey(display, XK_Scroll_Lock, m_scrollLockMask);
}
// warp to requested location
warpCursor(x, y);
// show mouse
hideWindow();
}
void
CXWindowsSecondaryScreen::leave()
{
assert(m_window != None);
assert(m_active == true);
log((CLOG_INFO "leaving screen"));
CDisplayLock display(this);
// hide mouse
showWindow();
// not active anymore
m_active = false;
// make sure our idea of clipboard ownership is correct
checkClipboard();
delete m_screen;
}
void
@ -236,7 +100,7 @@ CXWindowsSecondaryScreen::keyUp(KeyID key, KeyModifierMask mask)
void
CXWindowsSecondaryScreen::mouseDown(ButtonID button)
{
CDisplayLock display(this);
CDisplayLock display(m_screen);
XTestFakeButtonEvent(display, mapButton(button), True, CurrentTime);
XSync(display, False);
}
@ -244,7 +108,7 @@ CXWindowsSecondaryScreen::mouseDown(ButtonID button)
void
CXWindowsSecondaryScreen::mouseUp(ButtonID button)
{
CDisplayLock display(this);
CDisplayLock display(m_screen);
XTestFakeButtonEvent(display, mapButton(button), False, CurrentTime);
XSync(display, False);
}
@ -252,7 +116,6 @@ CXWindowsSecondaryScreen::mouseUp(ButtonID button)
void
CXWindowsSecondaryScreen::mouseMove(SInt32 x, SInt32 y)
{
CDisplayLock display(this);
warpCursor(x, y);
}
@ -268,7 +131,7 @@ CXWindowsSecondaryScreen::mouseWheel(SInt32 delta)
}
// send as many clicks as necessary
CDisplayLock display(this);
CDisplayLock display(m_screen);
for (; delta >= 120; delta -= 120) {
XTestFakeButtonEvent(display, button, True, CurrentTime);
XTestFakeButtonEvent(display, button, False, CurrentTime);
@ -276,63 +139,29 @@ CXWindowsSecondaryScreen::mouseWheel(SInt32 delta)
XSync(display, False);
}
void
CXWindowsSecondaryScreen::setClipboard(ClipboardID id,
const IClipboard* clipboard)
IScreen*
CXWindowsSecondaryScreen::getScreen() const
{
setDisplayClipboard(id, clipboard);
return m_screen;
}
void
CXWindowsSecondaryScreen::grabClipboard(ClipboardID id)
CXWindowsSecondaryScreen::onScreensaver(bool)
{
setDisplayClipboard(id, NULL);
// ignore
}
void
CXWindowsSecondaryScreen::screenSaver(bool activate)
CXWindowsSecondaryScreen::onError()
{
CDisplayLock display(this);
if (activate) {
getScreenSaver()->activate();
}
else {
getScreenSaver()->deactivate();
}
}
void
CXWindowsSecondaryScreen::getMousePos(SInt32& x, SInt32& y) const
{
CDisplayLock display(this);
getCursorPos(x, y);
}
void
CXWindowsSecondaryScreen::getShape(
SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
{
getScreenShape(x, y, w, h);
}
SInt32
CXWindowsSecondaryScreen::getJumpZoneSize() const
{
return 0;
}
void
CXWindowsSecondaryScreen::getClipboard(ClipboardID id,
IClipboard* clipboard) const
{
getDisplayClipboard(id, clipboard);
// ignore
// FIXME -- forward this? to whom?
}
bool
CXWindowsSecondaryScreen::onPreDispatch(const CEvent* event)
CXWindowsSecondaryScreen::onPreDispatch(const CEvent*)
{
// forward to superclass
return CXWindowsScreen::onPreDispatch(event);
return false;
}
bool
@ -344,33 +173,117 @@ CXWindowsSecondaryScreen::onEvent(CEvent* event)
// handle event
switch (xevent.type) {
case MappingNotify:
{
// keyboard mapping changed
CDisplayLock display(this);
XRefreshKeyboardMapping(&xevent.xmapping);
updateKeys(display);
updateKeycodeMap(display);
updateModifierMap(display);
updateModifiers(display);
}
// keyboard mapping changed
updateKeys();
return true;
case LeaveNotify:
{
// mouse moved out of hider window somehow. hide the window.
assert(m_window != None);
CDisplayLock display(this);
hideWindow();
}
// mouse moved out of hider window somehow. hide the window.
hideWindow();
return true;
}
}
void
CXWindowsSecondaryScreen::onLostClipboard(ClipboardID id)
CXWindowsSecondaryScreen::onPreRun()
{
// tell client that the clipboard was grabbed locally
m_receiver->onGrabClipboard(id);
assert(m_window != None);
}
void
CXWindowsSecondaryScreen::onPreOpen()
{
assert(m_window == None);
}
void
CXWindowsSecondaryScreen::onPostOpen()
{
// check for peculiarities
// FIXME -- may have to get these from some database
m_numLockHalfDuplex = false;
m_capsLockHalfDuplex = false;
// m_numLockHalfDuplex = true;
// m_capsLockHalfDuplex = true;
}
void
CXWindowsSecondaryScreen::onPreEnter()
{
assert(m_window != None);
}
void
CXWindowsSecondaryScreen::onPreLeave()
{
assert(m_window != None);
}
void
CXWindowsSecondaryScreen::createWindow()
{
{
CDisplayLock display(m_screen);
// verify the availability of the XTest extension
int majorOpcode, firstEvent, firstError;
if (!XQueryExtension(display, XTestExtensionName,
&majorOpcode, &firstEvent, &firstError)) {
// FIXME -- subclass exception for more info?
throw XScreenOpenFailure();
}
// cursor hider window attributes. 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.
XSetWindowAttributes attr;
attr.event_mask = LeaveWindowMask;
attr.do_not_propagate_mask = 0;
attr.override_redirect = True;
attr.cursor = m_screen->getBlankCursor();
// create the cursor hider window
m_window = XCreateWindow(display, m_screen->getRoot(),
0, 0, 1, 1, 0, 0,
InputOnly, CopyFromParent,
CWDontPropagate | CWEventMask |
CWOverrideRedirect | CWCursor,
&attr);
if (m_window == None) {
throw XScreenOpenFailure();
}
log((CLOG_DEBUG "window is 0x%08x", m_window));
// become impervious to server grabs
XTestGrabControl(display, True);
}
// tell our superclass about the window
m_screen->setWindow(m_window);
}
void
CXWindowsSecondaryScreen::destroyWindow()
{
CDisplayLock display(m_screen);
if (display != NULL) {
// release keys that are still pressed
releaseKeys(display);
// 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);
}
}
void
@ -380,106 +293,55 @@ CXWindowsSecondaryScreen::showWindow()
// somewhere else on the screen)
SInt32 x, y;
getCursorPos(x, y);
XMoveWindow(getDisplay(), m_window, x, y);
CDisplayLock display(m_screen);
XMoveWindow(display, m_window, x, y);
// raise and show the hider window. take activation.
// FIXME -- take focus?
XMapRaised(getDisplay(), m_window);
XMapRaised(display, m_window);
/* XXX -- this should have no effect
// hide cursor by moving it into the hider window
XWarpPointer(getDisplay(), None, m_window, 0, 0, 0, 0, 0, 0);
XWarpPointer(display, None, m_window, 0, 0, 0, 0, 0, 0);
*/
}
void
CXWindowsSecondaryScreen::hideWindow()
{
XUnmapWindow(getDisplay(), m_window);
assert(m_window != None);
CDisplayLock display(m_screen);
XUnmapWindow(display, m_window);
}
void
CXWindowsSecondaryScreen::warpCursor(SInt32 x, SInt32 y)
{
XTestFakeMotionEvent(getDisplay(), getScreen(), x, y, CurrentTime);
XSync(getDisplay(), False);
CDisplayLock display(m_screen);
Display* pDisplay = display;
XTestFakeMotionEvent(display, DefaultScreen(pDisplay), x, y, CurrentTime);
XSync(display, False);
}
void
CXWindowsSecondaryScreen::checkClipboard()
CXWindowsSecondaryScreen::setToggleState(KeyModifierMask mask)
{
// do nothing, we're always up to date
}
CDisplayLock display(m_screen);
void
CXWindowsSecondaryScreen::createWindow()
{
CDisplayLock display(this);
// verify the availability of the XTest extension
int majorOpcode, firstEvent, firstError;
if (!XQueryExtension(display, XTestExtensionName,
&majorOpcode, &firstEvent, &firstError)) {
// FIXME -- subclass exception for more info?
throw XScreenOpenFailure();
// toggle modifiers that don't match the desired state
unsigned int xMask = maskToX(mask);
if ((xMask & m_capsLockMask) != (m_mask & m_capsLockMask)) {
toggleKey(display, XK_Caps_Lock, m_capsLockMask);
}
// cursor hider window attributes. 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.
XSetWindowAttributes attr;
attr.event_mask = LeaveWindowMask;
attr.do_not_propagate_mask = 0;
attr.override_redirect = True;
attr.cursor = getBlankCursor();
// create the cursor hider window
m_window = XCreateWindow(display, getRoot(),
0, 0, 1, 1, 0, 0,
InputOnly, CopyFromParent,
CWDontPropagate | CWEventMask |
CWOverrideRedirect | CWCursor,
&attr);
if (m_window == None) {
throw XScreenOpenFailure();
if ((xMask & m_numLockMask) != (m_mask & m_numLockMask)) {
toggleKey(display, XK_Num_Lock, m_numLockMask);
}
log((CLOG_DEBUG "window is 0x%08x", m_window));
// become impervious to server grabs
XTestGrabControl(display, True);
}
void
CXWindowsSecondaryScreen::destroyWindow()
{
releaseKeys();
CDisplayLock display(this);
if (display != NULL) {
// no longer impervious to server grabs
XTestGrabControl(display, False);
// destroy window
if (m_window != None) {
XDestroyWindow(display, m_window);
m_window = None;
}
if ((xMask & m_scrollLockMask) != (m_mask & m_scrollLockMask)) {
toggleKey(display, XK_Scroll_Lock, m_scrollLockMask);
}
}
void
CXWindowsSecondaryScreen::installScreenSaver()
{
getScreenSaver()->disable();
}
void
CXWindowsSecondaryScreen::uninstallScreenSaver()
{
getScreenSaver()->enable();
}
unsigned int
CXWindowsSecondaryScreen::mapButton(ButtonID id) const
{
@ -848,7 +710,7 @@ CXWindowsSecondaryScreen::doKeystrokes(const Keystrokes& keys, SInt32 count)
}
// lock display
CDisplayLock display(this);
CDisplayLock display(m_screen);
// generate key events
for (Keystrokes::const_iterator k = keys.begin(); k != keys.end(); ) {
@ -910,27 +772,24 @@ CXWindowsSecondaryScreen::maskToX(KeyModifierMask inMask) const
}
void
CXWindowsSecondaryScreen::releaseKeys()
CXWindowsSecondaryScreen::releaseKeys(Display* display)
{
CDisplayLock display(this);
assert(display != NULL);
if (display != NULL) {
// key up for each key that's down
for (UInt32 i = 0; i < 256; ++i) {
if (m_keys[i]) {
XTestFakeKeyEvent(display, i, False, CurrentTime);
m_keys[i] = false;
}
// key up for each key that's down
for (UInt32 i = 0; i < 256; ++i) {
if (m_keys[i]) {
XTestFakeKeyEvent(display, i, False, CurrentTime);
m_keys[i] = false;
}
// update
XSync(display, False);
}
}
void
CXWindowsSecondaryScreen::updateKeys(Display* display)
CXWindowsSecondaryScreen::updateKeys()
{
CDisplayLock display(m_screen);
// ask server which keys are pressed
char keys[32];
XQueryKeymap(display, keys);
@ -946,6 +805,11 @@ CXWindowsSecondaryScreen::updateKeys(Display* display)
m_keys[j + 6] = ((keys[i] & 0x40) != 0);
m_keys[j + 7] = ((keys[i] & 0x80) != 0);
}
// update mappings and current modifiers
updateKeycodeMap(display);
updateModifierMap(display);
updateModifiers(display);
}
void

View File

@ -1,47 +1,55 @@
#ifndef CXWINDOWSSECONDARYSCREEN_H
#define CXWINDOWSSECONDARYSCREEN_H
#include "CXWindowsScreen.h"
#include "ISecondaryScreen.h"
#include "CSecondaryScreen.h"
#include "IScreenEventHandler.h"
#include "stdmap.h"
#include "stdvector.h"
#if defined(X_DISPLAY_MISSING)
# error X11 is required to build synergy
#else
# include <X11/Xlib.h>
#endif
class CXWindowsScreen;
class IScreenReceiver;
class CXWindowsSecondaryScreen : public CXWindowsScreen,
public ISecondaryScreen {
class CXWindowsSecondaryScreen :
public CSecondaryScreen, public IScreenEventHandler {
public:
CXWindowsSecondaryScreen(IScreenReceiver*);
virtual ~CXWindowsSecondaryScreen();
// 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);
virtual void mouseDown(ButtonID);
virtual void mouseUp(ButtonID);
virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute);
virtual void mouseMove(SInt32 x, SInt32 y);
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:
// CXWindowsScreen overrides
// IScreenEventHandler overrides
virtual void onError();
virtual void onScreensaver(bool activated);
virtual bool onPreDispatch(const CEvent* event);
virtual bool onEvent(CEvent* event);
virtual void onLostClipboard(ClipboardID);
protected:
// CSecondaryScreen overrides
virtual void onPreRun();
virtual void onPreOpen();
virtual void onPostOpen();
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 };
@ -62,26 +70,6 @@ private:
typedef std::map<KeyID, KeyCodeMask> KeyCodeMap;
typedef std::map<KeyCode, unsigned int> ModifierMap;
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();
unsigned int mapButton(ButtonID button) const;
unsigned int mapKey(Keystrokes&, KeyCode&, KeyID,
@ -91,8 +79,7 @@ private:
void doKeystrokes(const Keystrokes&, SInt32 count);
unsigned int maskToX(KeyModifierMask) const;
void releaseKeys();
void updateKeys(Display* display);
void releaseKeys(Display*);
void updateKeycodeMap(Display* display);
void updateModifiers(Display* display);
void updateModifierMap(Display* display);
@ -100,12 +87,9 @@ private:
static bool isToggleKeysym(KeySym);
private:
IScreenReceiver* m_receiver;
CXWindowsScreen* m_screen;
Window m_window;
// m_active is true if this screen has been entered
bool m_active;
// note toggle keys that toggles on up/down (false) or on
// transition (true)
bool m_numLockHalfDuplex;

View File

@ -1,82 +0,0 @@
#ifndef ISECONDARYSCREEN_H
#define ISECONDARYSCREEN_H
#include "IInterface.h"
#include "ClipboardTypes.h"
#include "KeyTypes.h"
#include "MouseTypes.h"
class IClipboard;
class ISecondaryScreen : public IInterface {
public:
// manipulators
// enter the screen's message loop. this returns when it detects
// the application should terminate or when stop() is called.
// the screen must be open()'d before run() and must not be
// close()'d until run() returns.
virtual void run() = 0;
// cause run() to return
virtual void stop() = 0;
// initialize the screen, hide the cursor, and disable the screen
// saver. start reporting events to the IScreenReceiver (which is
// set through some other interface).
virtual void open() = 0;
// close the screen. should restore the screen saver. it should
// also simulate key up events for any keys that have simulate key
// down events without a matching key up. without this the client
// will leave its keyboard in the wrong logical state.
virtual void close() = 0;
// called when the user navigates to the secondary screen. warp
// the cursor to the given coordinates and unhide it. prepare to
// simulate input events.
virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute,
KeyModifierMask mask) = 0;
// called when the user navigates off the secondary screen. clean
// up input event simulation and hide the cursor.
virtual void leave() = 0;
// keyboard input simulation
virtual void keyDown(KeyID, KeyModifierMask) = 0;
virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count) = 0;
virtual void keyUp(KeyID, KeyModifierMask) = 0;
// mouse input simulation
virtual void mouseDown(ButtonID) = 0;
virtual void mouseUp(ButtonID) = 0;
virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute) = 0;
virtual void mouseWheel(SInt32 delta) = 0;
// set the screen's clipboard contents. this is usually called
// soon after an enter().
virtual void setClipboard(ClipboardID, const IClipboard*) = 0;
// take ownership of clipboard
virtual void grabClipboard(ClipboardID) = 0;
// activate or deactivate the screen saver
virtual void screenSaver(bool activate) = 0;
// accessors
// get the position of the mouse on the screen
virtual void getMousePos(SInt32& x, SInt32& y) const = 0;
// get the size of the screen
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const = 0;
// get the size of jump zone
virtual SInt32 getJumpZoneSize() const = 0;
// get the screen's clipboard contents
virtual void getClipboard(ClipboardID, IClipboard*) const = 0;
};
#endif

View File

@ -5,13 +5,14 @@ DEPTH = ..
bin_PROGRAMS = synergy
synergy_SOURCES = \
CClient.cpp \
CSecondaryScreen.cpp \
CServerProxy.cpp \
CXWindowsSecondaryScreen.cpp \
client.cpp \
CClient.h \
CSecondaryScreen.h \
CServerProxy.h \
CXWindowsSecondaryScreen.h \
ISecondaryScreen.h \
$(NULL)
synergy_LDADD = \
$(DEPTH)/platform/libplatform.a \

View File

@ -116,9 +116,11 @@ realMain(CMutex* mutex)
if (!locked && mutex != NULL) {
mutex->lock();
}
s_client->close();
delete s_client;
s_client = NULL;
if (s_client != NULL) {
s_client->close();
delete s_client;
s_client = NULL;
}
CLog::setLock(NULL);
s_logMutex = NULL;
throw;

View File

@ -3,14 +3,22 @@
#include "CXWindowsScreenSaver.h"
#include "CXWindowsUtil.h"
#include "CClipboard.h"
#include "IScreenEventHandler.h"
#include "IScreenReceiver.h"
#include "XScreen.h"
#include "CLock.h"
#include "CThread.h"
#include "CLog.h"
#include "IJob.h"
#include "CString.h"
#include <cstdlib>
//#include "CString.h"
//#include <cstdlib>
#include <cstring>
#if defined(X_DISPLAY_MISSING)
# error X11 is required to build synergy
#else
# include <X11/X.h>
# include <X11/Xutil.h>
#endif
//
// CXWindowsScreen::CTimer
@ -68,15 +76,24 @@ CXWindowsScreen::CTimer::operator<(const CTimer& t) const
CXWindowsScreen* CXWindowsScreen::s_screen = NULL;
CXWindowsScreen::CXWindowsScreen() :
CXWindowsScreen::CXWindowsScreen(IScreenReceiver* receiver,
IScreenEventHandler* eventHandler) :
m_display(NULL),
m_root(None),
m_stop(false),
m_receiver(receiver),
m_eventHandler(eventHandler),
m_window(None),
m_x(0), m_y(0),
m_w(0), m_h(0),
m_stop(false),
m_screenSaver(NULL)
m_screensaver(NULL),
m_screensaverNotify(false),
m_atomScreensaver(None)
{
assert(s_screen == NULL);
assert(s_screen == NULL);
assert(m_receiver != NULL);
assert(m_eventHandler != NULL);
s_screen = this;
}
@ -120,6 +137,77 @@ CXWindowsScreen::removeTimerNoLock(IJob* job)
m_timers.swap(tmp);
}
void
CXWindowsScreen::setWindow(Window window)
{
CLock lock(&m_mutex);
assert(m_display != NULL);
// destroy the clipboards
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
delete m_clipboard[id];
m_clipboard[id] = NULL;
}
// save the new window
m_window = window;
// initialize the clipboards
if (m_window != None) {
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
m_clipboard[id] = new CXWindowsClipboard(m_display, m_window, id);
}
}
}
Window
CXWindowsScreen::getRoot() const
{
assert(m_display != NULL);
return m_root;
}
Cursor
CXWindowsScreen::getBlankCursor() const
{
return m_cursor;
}
void
CXWindowsScreen::open()
{
assert(m_display == NULL);
// set the X I/O error handler so we catch the display disconnecting
XSetIOErrorHandler(&CXWindowsScreen::ioErrorHandler);
// get the DISPLAY
const char* display = getenv("DISPLAY");
if (display == NULL) {
display = ":0.0";
}
// open the display
log((CLOG_DEBUG "XOpenDisplay(\"%s\")", display));
m_display = XOpenDisplay(display);
if (m_display == NULL) {
throw XScreenOpenFailure();
}
// get root window
m_root = DefaultRootWindow(m_display);
// create the transparent cursor
createBlankCursor();
// get screen shape
updateScreenShape();
// initialize the screen saver
m_atomScreensaver = XInternAtom(m_display, "SCREENSAVER", False);
m_screensaver = new CXWindowsScreenSaver(this, m_display);
}
void
CXWindowsScreen::mainLoop()
{
@ -147,7 +235,7 @@ CXWindowsScreen::mainLoop()
// have a go at it.
m_mutex.unlock();
if (!onPreDispatch(&event)) {
onEvent(&event);
m_eventHandler->onEvent(&event);
}
m_mutex.lock();
}
@ -162,23 +250,210 @@ CXWindowsScreen::exitMainLoop()
m_stop = true;
}
void
CXWindowsScreen::close()
{
CLock lock(&m_mutex);
// done with screen saver
delete m_screensaver;
m_screensaver = NULL;
// destroy clipboards
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
delete m_clipboard[id];
m_clipboard[id] = NULL;
}
// close the display
if (m_display != NULL) {
XCloseDisplay(m_display);
m_display = NULL;
log((CLOG_DEBUG "closed display"));
}
XSetIOErrorHandler(NULL);
}
bool
CXWindowsScreen::onPreDispatch(const CEvent* event)
CXWindowsScreen::setClipboard(ClipboardID id, const IClipboard* clipboard)
{
CLock lock(&m_mutex);
// fail if we don't have the requested clipboard
if (m_clipboard[id] == NULL) {
return false;
}
// get the actual time. ICCCM does not allow CurrentTime.
Time timestamp = CXWindowsUtil::getCurrentTime(
m_display, m_clipboard[id]->getWindow());
if (clipboard != NULL) {
// save clipboard data
return CClipboard::copy(m_clipboard[id], clipboard, timestamp);
}
else {
// assert clipboard ownership
if (!m_clipboard[id]->open(timestamp)) {
return false;
}
m_clipboard[id]->empty();
m_clipboard[id]->close();
return true;
}
}
void
CXWindowsScreen::checkClipboards()
{
// do nothing, we're always up to date
}
void
CXWindowsScreen::openScreenSaver(bool notify)
{
CLock lock(&m_mutex);
assert(m_screensaver != NULL);
m_screensaverNotify = notify;
if (m_screensaverNotify) {
m_screensaver->setNotify(m_window);
}
else {
m_screensaver->disable();
}
}
void
CXWindowsScreen::closeScreenSaver()
{
CLock lock(&m_mutex);
if (m_screensaver != NULL) {
if (m_screensaverNotify) {
m_screensaver->setNotify(None);
}
else {
m_screensaver->enable();
}
}
}
void
CXWindowsScreen::screensaver(bool activate)
{
CLock lock(&m_mutex);
assert(m_screensaver != NULL);
if (activate) {
m_screensaver->activate();
}
else {
m_screensaver->deactivate();
}
}
void
CXWindowsScreen::syncDesktop()
{
// do nothing; X doesn't suffer from this bogosity
}
bool
CXWindowsScreen::getClipboard(ClipboardID id, IClipboard* clipboard) const
{
assert(clipboard != NULL);
// block others from using the display while we get the clipboard
CLock lock(&m_mutex);
// fail if we don't have the requested clipboard
if (m_clipboard[id] == NULL) {
return false;
}
// get the actual time. ICCCM does not allow CurrentTime.
Time timestamp = CXWindowsUtil::getCurrentTime(
m_display, m_clipboard[id]->getWindow());
// copy the clipboard
return CClipboard::copy(clipboard, m_clipboard[id], timestamp);
}
void
CXWindowsScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
{
CLock lock(&m_mutex);
assert(m_display != NULL);
x = m_x;
y = m_y;
w = m_w;
h = m_h;
}
void
CXWindowsScreen::getCursorPos(SInt32& x, SInt32& y) const
{
CLock lock(&m_mutex);
assert(m_display != NULL);
Window root, window;
int mx, my, xWindow, yWindow;
unsigned int mask;
if (XQueryPointer(m_display, getRoot(), &root, &window,
&mx, &my, &xWindow, &yWindow, &mask)) {
x = mx;
y = my;
}
else {
getCursorCenter(x, y);
}
}
void
CXWindowsScreen::getCursorCenter(SInt32& x, SInt32& y) const
{
CLock lock(&m_mutex);
assert(m_display != NULL);
x = m_x + (m_w >> 1);
y = m_y + (m_h >> 1);
}
void
CXWindowsScreen::updateScreenShape()
{
m_x = 0;
m_y = 0;
m_w = WidthOfScreen(DefaultScreenOfDisplay(m_display));
m_h = HeightOfScreen(DefaultScreenOfDisplay(m_display));
log((CLOG_INFO "screen shape: %d,%d %dx%d", m_x, m_y, m_w, m_h));
}
bool
CXWindowsScreen::onPreDispatch(CEvent* event)
{
assert(event != NULL);
const XEvent* xevent = &event->m_event;
XEvent* xevent = &event->m_event;
switch (xevent->type) {
case MappingNotify:
// keyboard mapping changed
XRefreshKeyboardMapping(&xevent->xmapping);
// pass event on
break;
case SelectionClear:
{
// we just lost the selection. that means someone else
// grabbed the selection so this screen is now the
// selection owner. report that to the subclass.
// selection owner. report that to the receiver.
ClipboardID id = getClipboardID(xevent->xselectionclear.selection);
if (id != kClipboardEnd) {
log((CLOG_DEBUG "lost clipboard %d ownership at time %d", id, xevent->xselectionclear.time));
m_clipboard[id]->lost(xevent->xselectionclear.time);
onLostClipboard(id);
m_receiver->onGrabClipboard(id);
return true;
}
}
@ -225,6 +500,15 @@ CXWindowsScreen::onPreDispatch(const CEvent* event)
}
break;
case ClientMessage:
if (xevent->xclient.message_type == m_atomScreensaver ||
xevent->xclient.format == 32) {
// screen saver activation/deactivation event
m_eventHandler->onScreensaver(xevent->xclient.data.l[0] != 0);
return true;
}
break;
case DestroyNotify:
// looks like one of the windows that requested a clipboard
// transfer has gone bye-bye.
@ -237,150 +521,10 @@ CXWindowsScreen::onPreDispatch(const CEvent* event)
// let screen saver have a go
{
CLock lock(&m_mutex);
m_screenSaver->onPreDispatch(xevent);
m_screensaver->onPreDispatch(xevent);
}
return false;
}
void
CXWindowsScreen::openDisplay()
{
assert(m_display == NULL);
// set the X I/O error handler so we catch the display disconnecting
XSetIOErrorHandler(&CXWindowsScreen::ioErrorHandler);
// get the DISPLAY
const char* display = getenv("DISPLAY");
if (display == NULL) {
display = ":0.0";
}
// open the display
log((CLOG_DEBUG "XOpenDisplay(\"%s\")", display));
m_display = XOpenDisplay(display);
if (m_display == NULL) {
throw XScreenOpenFailure();
}
// get default screen and root window
m_screen = DefaultScreen(m_display);
m_root = RootWindow(m_display, m_screen);
// create the transparent cursor
createBlankCursor();
// get screen shape
updateScreenShape();
// initialize the screen saver
m_screenSaver = new CXWindowsScreenSaver(this, m_display);
}
void
CXWindowsScreen::closeDisplay()
{
CLock lock(&m_mutex);
// done with screen saver
delete m_screenSaver;
m_screenSaver = NULL;
// destroy clipboards
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
delete m_clipboard[id];
m_clipboard[id] = NULL;
}
// close the display
if (m_display != NULL) {
XCloseDisplay(m_display);
m_display = NULL;
log((CLOG_DEBUG "closed display"));
}
XSetIOErrorHandler(NULL);
}
Display*
CXWindowsScreen::getDisplay() const
{
return m_display;
}
int
CXWindowsScreen::getScreen() const
{
assert(m_display != NULL);
return m_screen;
}
Window
CXWindowsScreen::getRoot() const
{
assert(m_display != NULL);
return m_root;
}
void
CXWindowsScreen::initClipboards(Window window)
{
assert(m_display != NULL);
assert(window != None);
// initialize clipboards
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
m_clipboard[id] = new CXWindowsClipboard(m_display, window, id);
}
}
void
CXWindowsScreen::updateScreenShape()
{
m_x = 0;
m_y = 0;
m_w = WidthOfScreen(ScreenOfDisplay(m_display, m_screen));
m_h = HeightOfScreen(ScreenOfDisplay(m_display, m_screen));
log((CLOG_INFO "screen shape: %d,%d %dx%d", m_x, m_y, m_w, m_h));
}
void
CXWindowsScreen::getScreenShape(SInt32& x, SInt32& y,
SInt32& w, SInt32& h) const
{
assert(m_display != NULL);
x = m_x;
y = m_y;
w = m_w;
h = m_h;
}
void
CXWindowsScreen::getCursorPos(SInt32& x, SInt32& y) const
{
assert(m_display != NULL);
Window root, window;
int mx, my, xWindow, yWindow;
unsigned int mask;
if (XQueryPointer(m_display, getRoot(), &root, &window,
&mx, &my, &xWindow, &yWindow, &mask)) {
x = mx;
y = my;
}
else {
getCursorCenter(x, y);
}
}
void
CXWindowsScreen::getCursorCenter(SInt32& x, SInt32& y) const
{
assert(m_display != NULL);
x = m_x + (m_w >> 1);
y = m_y + (m_h >> 1);
return m_eventHandler->onPreDispatch(event);
}
void
@ -417,30 +561,6 @@ CXWindowsScreen::createBlankCursor()
XFreePixmap(m_display, bitmap);
}
Cursor
CXWindowsScreen::getBlankCursor() const
{
return m_cursor;
}
ClipboardID
CXWindowsScreen::getClipboardID(Atom selection) const
{
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
if (m_clipboard[id] != NULL &&
m_clipboard[id]->getSelection() == selection) {
return id;
}
}
return kClipboardEnd;
}
void
CXWindowsScreen::onUnexpectedClose()
{
// do nothing
}
bool
CXWindowsScreen::processTimers()
{
@ -486,62 +606,16 @@ CXWindowsScreen::processTimers()
}
}
CXWindowsScreenSaver*
CXWindowsScreen::getScreenSaver() const
ClipboardID
CXWindowsScreen::getClipboardID(Atom selection) const
{
return m_screenSaver;
}
bool
CXWindowsScreen::setDisplayClipboard(ClipboardID id,
const IClipboard* clipboard)
{
CLock lock(&m_mutex);
// fail if we don't have the requested clipboard
if (m_clipboard[id] == NULL) {
return false;
}
// get the actual time. ICCCM does not allow CurrentTime.
Time timestamp = CXWindowsUtil::getCurrentTime(
m_display, m_clipboard[id]->getWindow());
if (clipboard != NULL) {
// save clipboard data
return CClipboard::copy(m_clipboard[id], clipboard, timestamp);
}
else {
// assert clipboard ownership
if (!m_clipboard[id]->open(timestamp)) {
return false;
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
if (m_clipboard[id] != NULL &&
m_clipboard[id]->getSelection() == selection) {
return id;
}
m_clipboard[id]->empty();
m_clipboard[id]->close();
return true;
}
}
bool
CXWindowsScreen::getDisplayClipboard(ClipboardID id,
IClipboard* clipboard) const
{
assert(clipboard != NULL);
// block others from using the display while we get the clipboard
CLock lock(&m_mutex);
// fail if we don't have the requested clipboard
if (m_clipboard[id] == NULL) {
return false;
}
// get the actual time. ICCCM does not allow CurrentTime.
Time timestamp = CXWindowsUtil::getCurrentTime(
m_display, m_clipboard[id]->getWindow());
// copy the clipboard
return CClipboard::copy(clipboard, m_clipboard[id], timestamp);
return kClipboardEnd;
}
void
@ -584,17 +658,17 @@ CXWindowsScreen::ioErrorHandler(Display*)
// so we set it to NULL), and exit.
log((CLOG_WARN "X display has unexpectedly disconnected"));
s_screen->m_display = NULL;
s_screen->onUnexpectedClose();
s_screen->m_eventHandler->onError();
log((CLOG_CRIT "quiting due to X display disconnection"));
exit(17);
}
//
// CXWindowsScreen::CDisplayLock
// CDisplayLock
//
CXWindowsScreen::CDisplayLock::CDisplayLock(const CXWindowsScreen* screen) :
CDisplayLock::CDisplayLock(const CXWindowsScreen* screen) :
m_mutex(&screen->m_mutex),
m_display(screen->m_display)
{
@ -603,12 +677,12 @@ CXWindowsScreen::CDisplayLock::CDisplayLock(const CXWindowsScreen* screen) :
m_mutex->lock();
}
CXWindowsScreen::CDisplayLock::~CDisplayLock()
CDisplayLock::~CDisplayLock()
{
m_mutex->unlock();
}
CXWindowsScreen::CDisplayLock::operator Display*() const
CDisplayLock::operator Display*() const
{
return m_display;
}

View File

@ -1,6 +1,7 @@
#ifndef CXWINDOWSSCREEN_H
#define CXWINDOWSSCREEN_H
#include "IScreen.h"
#include "ClipboardTypes.h"
#include "CMutex.h"
#include "CStopwatch.h"
@ -13,9 +14,9 @@
#include <algorithm>
#include <functional>
class IClipboard;
class IJob;
class IScreenSaver;
class IScreenEventHandler;
class IScreenReceiver;
class CXWindowsClipboard;
class CXWindowsScreenSaver;
@ -25,9 +26,9 @@ public:
SInt32 m_result;
};
class CXWindowsScreen {
class CXWindowsScreen : public IScreen {
public:
CXWindowsScreen();
CXWindowsScreen(IScreenReceiver*, IScreenEventHandler*);
virtual ~CXWindowsScreen();
// manipulators
@ -39,94 +40,41 @@ public:
void addTimer(IJob*, double timeout);
void removeTimer(IJob*);
protected:
class CDisplayLock {
public:
CDisplayLock(const CXWindowsScreen*);
~CDisplayLock();
// set the window (created by the subclass). this performs some
// initialization and saves the window in case it's needed later.
void setWindow(Window);
operator Display*() const;
// accessors
private:
const CMutex* m_mutex;
Display* m_display;
};
friend class CDisplayLock;
// runs an event loop and returns when exitMainLoop() is called
void mainLoop();
// force mainLoop() to return
void exitMainLoop();
// 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 Display*. only use this when you know the display is
// locked but don't have the CDisplayLock available.
Display* getDisplay() const;
// get the opened screen and its root window. to get the display
// create a CDisplayLock object passing this. while the object
// exists no other threads may access the display. do not save
// the Display* beyond the lifetime of the CDisplayLock.
int getScreen() const;
// get the root window of the screen
Window getRoot() const;
// initialize the clipboards
void initClipboards(Window);
// update screen size cache
void updateScreenShape();
// get the shape of the screen
void getScreenShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const;
// get the current cursor position
void getCursorPos(SInt32& x, SInt32& y) const;
// get the cursor center position
void getCursorCenter(SInt32& x, SInt32& y) const;
// get a cursor that is transparent everywhere
Cursor getBlankCursor() const;
// set the contents of the clipboard (i.e. primary selection)
bool setDisplayClipboard(ClipboardID,
const IClipboard* clipboard);
// copy the clipboard contents to clipboard
bool getDisplayClipboard(ClipboardID,
IClipboard* clipboard) const;
// get the screen saver object
CXWindowsScreenSaver*
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) = 0;
// 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 if the display is unexpectedly closing. default does nothing.
virtual void onUnexpectedClose();
// called when a clipboard is lost
virtual void onLostClipboard(ClipboardID) = 0;
// IScreen overrides
void open();
void mainLoop();
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;
private:
// update screen size cache
void updateScreenShape();
// process events before dispatching to receiver
bool onPreDispatch(CEvent* event);
// create the transparent cursor
void createBlankCursor();
@ -255,14 +203,23 @@ private:
};
private:
friend class CDisplayLock;
typedef CPriorityQueue<CTimer> CTimerPriorityQueue;
// X is not thread safe
CMutex m_mutex;
Display* m_display;
int m_screen;
Window m_root;
bool m_stop;
IScreenReceiver* m_receiver;
IScreenEventHandler* m_eventHandler;
Window m_window;
SInt32 m_x, m_y;
SInt32 m_w, m_h;
bool m_stop;
// clipboards
CXWindowsClipboard* m_clipboard[kClipboardEnd];
@ -270,20 +227,31 @@ private:
// the transparent cursor
Cursor m_cursor;
// screen saver
CXWindowsScreenSaver* m_screenSaver;
// screen saver stuff
CXWindowsScreenSaver* m_screensaver;
bool m_screensaverNotify;
Atom m_atomScreensaver;
// timers, the stopwatch used to time, and a mutex for the timers
CTimerPriorityQueue m_timers;
CStopwatch m_time;
CMutex m_timersMutex;
// X is not thread safe
CMutex m_mutex;
// pointer to (singleton) screen. this is only needed by
// ioErrorHandler().
static CXWindowsScreen* s_screen;
};
class CDisplayLock {
public:
CDisplayLock(const CXWindowsScreen*);
~CDisplayLock();
operator Display*() const;
private:
const CMutex* m_mutex;
Display* m_display;
};
#endif

View File

@ -32,7 +32,7 @@ public:
virtual void close() = 0;
virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask,
bool screenSaver) = 0;
bool forScreensaver) = 0;
virtual bool leave() = 0;
virtual void setClipboard(ClipboardID, const CString&) = 0;
virtual void grabClipboard(ClipboardID) = 0;
@ -44,13 +44,13 @@ public:
virtual void mouseUp(ButtonID) = 0;
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs) = 0;
virtual void mouseWheel(SInt32 delta) = 0;
virtual void screenSaver(bool activate) = 0;
virtual void screensaver(bool activate) = 0;
virtual CString getName() const;
virtual SInt32 getJumpZoneSize() const = 0;
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const = 0;
virtual void getCenter(SInt32& x, SInt32& y) const = 0;
virtual void getMousePos(SInt32& x, SInt32& y) const = 0;
virtual SInt32 getJumpZoneSize() const = 0;
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0;
private:
IServer* m_server;

View File

@ -236,12 +236,19 @@ CClientProxy1_0::mouseWheel(SInt32 delta)
}
void
CClientProxy1_0::screenSaver(bool on)
CClientProxy1_0::screensaver(bool on)
{
log((CLOG_DEBUG1 "send screen saver to \"%s\" on=%d", getName().c_str(), on ? 1 : 0));
CProtocolUtil::writef(getOutputStream(), kMsgCScreenSaver, on ? 1 : 0);
}
SInt32
CClientProxy1_0::getJumpZoneSize() const
{
CLock lock(&m_mutex);
return m_info.m_zoneSize;
}
void
CClientProxy1_0::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
{
@ -253,24 +260,17 @@ CClientProxy1_0::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
}
void
CClientProxy1_0::getCenter(SInt32& x, SInt32& y) const
{
CLock lock(&m_mutex);
x = m_info.m_mx;
y = m_info.m_my;
}
void
CClientProxy1_0::getMousePos(SInt32&, SInt32&) const
CClientProxy1_0::getCursorPos(SInt32&, SInt32&) const
{
assert(0 && "shouldn't be called");
}
SInt32
CClientProxy1_0::getJumpZoneSize() const
void
CClientProxy1_0::getCursorCenter(SInt32& x, SInt32& y) const
{
CLock lock(&m_mutex);
return m_info.m_zoneSize;
x = m_info.m_mx;
y = m_info.m_my;
}
void

View File

@ -18,7 +18,7 @@ public:
virtual void close();
virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask,
bool screenSaver);
bool forScreensaver);
virtual bool leave();
virtual void setClipboard(ClipboardID, const CString&);
virtual void grabClipboard(ClipboardID);
@ -30,12 +30,12 @@ public:
virtual void mouseUp(ButtonID);
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs);
virtual void mouseWheel(SInt32 delta);
virtual void screenSaver(bool activate);
virtual void screensaver(bool activate);
virtual SInt32 getJumpZoneSize() const;
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const;
virtual void getCenter(SInt32& x, SInt32& y) const;
virtual void getMousePos(SInt32& x, SInt32& y) const;
virtual SInt32 getJumpZoneSize() const;
virtual void getCursorPos(SInt32& x, SInt32& y) const;
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
private:
void recvInfo(bool notify);

View File

@ -1,6 +1,6 @@
#include "CPrimaryClient.h"
#include "IServer.h"
#include "IPrimaryScreen.h"
#include "CPrimaryScreen.h"
#include "CClipboard.h"
#include "CLog.h"
@ -15,7 +15,8 @@
// CPrimaryClient
//
CPrimaryClient::CPrimaryClient(IServer* server, const CString& name) :
CPrimaryClient::CPrimaryClient(IServer* server,
IPrimaryScreenReceiver* receiver, const CString& name) :
m_server(server),
m_name(name),
m_seqNum(0)
@ -25,9 +26,9 @@ CPrimaryClient::CPrimaryClient(IServer* server, const CString& name) :
// create screen
log((CLOG_DEBUG1 "creating primary screen"));
#if WINDOWS_LIKE
m_screen = new CMSWindowsPrimaryScreen(this, m_server);
m_screen = new CMSWindowsPrimaryScreen(this, receiver);
#elif UNIX_LIKE
m_screen = new CXWindowsPrimaryScreen(this, m_server);
m_screen = new CXWindowsPrimaryScreen(this, receiver);
#endif
}
@ -211,7 +212,7 @@ CPrimaryClient::mouseWheel(SInt32)
}
void
CPrimaryClient::screenSaver(bool)
CPrimaryClient::screensaver(bool)
{
// ignore
}
@ -222,6 +223,12 @@ CPrimaryClient::getName() const
return m_name;
}
SInt32
CPrimaryClient::getJumpZoneSize() const
{
return m_info.m_zoneSize;
}
void
CPrimaryClient::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
{
@ -232,20 +239,14 @@ CPrimaryClient::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
}
void
CPrimaryClient::getCenter(SInt32& x, SInt32& y) const
{
x = m_info.m_mx;
y = m_info.m_my;
}
void
CPrimaryClient::getMousePos(SInt32&, SInt32&) const
CPrimaryClient::getCursorPos(SInt32&, SInt32&) const
{
assert(0 && "shouldn't be called");
}
SInt32
CPrimaryClient::getJumpZoneSize() const
void
CPrimaryClient::getCursorCenter(SInt32& x, SInt32& y) const
{
return m_info.m_zoneSize;
x = m_info.m_mx;
y = m_info.m_my;
}

View File

@ -6,12 +6,13 @@
#include "ProtocolTypes.h"
class IClipboard;
class IPrimaryScreen;
class CPrimaryScreen;
class IPrimaryScreenReceiver;
class IServer;
class CPrimaryClient : public IScreenReceiver, public IClient {
public:
CPrimaryClient(IServer*, const CString& name);
CPrimaryClient(IServer*, IPrimaryScreenReceiver*, const CString& name);
~CPrimaryClient();
// manipulators
@ -44,7 +45,7 @@ public:
virtual void close();
virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask,
bool screenSaver);
bool forScreensaver);
virtual bool leave();
virtual void setClipboard(ClipboardID, const CString&);
virtual void grabClipboard(ClipboardID);
@ -56,17 +57,17 @@ public:
virtual void mouseUp(ButtonID);
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs);
virtual void mouseWheel(SInt32 delta);
virtual void screenSaver(bool activate);
virtual void screensaver(bool activate);
virtual CString getName() const;
virtual SInt32 getJumpZoneSize() const;
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const;
virtual void getCenter(SInt32& x, SInt32& y) const;
virtual void getMousePos(SInt32& x, SInt32& y) const;
virtual SInt32 getJumpZoneSize() const;
virtual void getCursorPos(SInt32& x, SInt32& y) const;
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
private:
IServer* m_server;
IPrimaryScreen* m_screen;
CPrimaryScreen* m_screen;
CString m_name;
UInt32 m_seqNum;
CClientInfo m_info;

270
server/CPrimaryScreen.cpp Normal file
View File

@ -0,0 +1,270 @@
#include "CPrimaryScreen.h"
#include "IScreen.h"
#include "IScreenReceiver.h"
#include "ProtocolTypes.h"
#include "CThread.h"
#include "CLog.h"
// FIXME -- should be locking
//
// CPrimaryScreen
//
CPrimaryScreen::CPrimaryScreen(IScreenReceiver* receiver) :
m_receiver(receiver),
m_active(false)
{
// do nothing
}
CPrimaryScreen::~CPrimaryScreen()
{
// do nothing
}
void
CPrimaryScreen::run()
{
// change our priority
CThread::getCurrentThread().setPriority(-3);
// run event loop
try {
log((CLOG_DEBUG "entering event loop"));
onPreRun();
getScreen()->mainLoop();
onPostRun();
log((CLOG_DEBUG "exiting event loop"));
}
catch (...) {
onPostRun();
log((CLOG_DEBUG "exiting event loop"));
throw;
}
}
void
CPrimaryScreen::stop()
{
getScreen()->exitMainLoop();
}
void
CPrimaryScreen::open()
{
CClientInfo info;
try {
// subclass hook
onPreOpen();
// open the screen
getScreen()->open();
// create and prepare our window
createWindow();
// collect screen info
getScreen()->getShape(info.m_x, info.m_y, info.m_w, info.m_h);
getScreen()->getCursorPos(info.m_mx, info.m_my);
info.m_zoneSize = getJumpZoneSize();
// update keyboard state
updateKeys();
// get notified of screen saver activation/deactivation
getScreen()->openScreenSaver(true);
// subclass hook
onPostOpen();
}
catch (...) {
close();
throw;
}
// enter the screen
enterNoWarp();
// send screen info
m_receiver->onInfoChanged(info);
}
void
CPrimaryScreen::close()
{
onPreClose();
getScreen()->closeScreenSaver();
destroyWindow();
getScreen()->close();
onPostClose();
}
void
CPrimaryScreen::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);
enterNoWarp();
if (!forScreensaver) {
warpCursor(x, y);
}
else {
onEnterScreensaver();
}
}
void
CPrimaryScreen::enterNoWarp()
{
// not active anymore
m_active = false;
// subclass hook
onPreEnter();
// restore active window and hide our window
hideWindow();
// subclass hook
onPostEnter();
}
bool
CPrimaryScreen::leave()
{
log((CLOG_INFO "leaving primary"));
assert(m_active == false);
// subclass hook
onPreLeave();
// show our window
if (!showWindow()) {
onPostLeave(false);
return false;
}
// get keyboard state as we leave
updateKeys();
// warp mouse to center
warpCursorToCenter();
// FIXME -- this doesn't match the win32 version. that just does
// the warp while we flush the input queue until we find the warp
// and we discard that too. would prefer to at least match our
// own warping when we receive MotionNotify; that just does the
// warp. however, the win32 version sometimes stutters when
// leaving and perhaps this is why. hmm, win32 does ignore the
// events until after the warp (via the mark).
// subclass hook
onPostLeave(true);
// local client now active
m_active = true;
// make sure our idea of clipboard ownership is correct
getScreen()->checkClipboards();
return true;
}
void
CPrimaryScreen::setClipboard(ClipboardID id,
const IClipboard* clipboard)
{
getScreen()->setClipboard(id, clipboard);
}
void
CPrimaryScreen::grabClipboard(ClipboardID id)
{
getScreen()->setClipboard(id, NULL);
}
bool
CPrimaryScreen::isActive() const
{
return m_active;
}
void
CPrimaryScreen::getClipboard(ClipboardID id,
IClipboard* clipboard) const
{
getScreen()->getClipboard(id, clipboard);
}
SInt32
CPrimaryScreen::getJumpZoneSize() const
{
return 1;
}
void
CPrimaryScreen::onPreRun()
{
// do nothing
}
void
CPrimaryScreen::onPostRun()
{
// do nothing
}
void
CPrimaryScreen::onPreOpen()
{
// do nothing
}
void
CPrimaryScreen::onPostOpen()
{
// do nothing
}
void
CPrimaryScreen::onPreClose()
{
// do nothing
}
void
CPrimaryScreen::onPostClose()
{
// do nothing
}
void
CPrimaryScreen::onPreEnter()
{
// do nothing
}
void
CPrimaryScreen::onPostEnter()
{
// do nothing
}
void
CPrimaryScreen::onEnterScreensaver()
{
// do nothing
}
void
CPrimaryScreen::onPreLeave()
{
// do nothing
}
void
CPrimaryScreen::onPostLeave(bool)
{
// do nothing
}

157
server/CPrimaryScreen.h Normal file
View File

@ -0,0 +1,157 @@
#ifndef CPRIMARYSCREEN_H
#define CPRIMARYSCREEN_H
#include "ClipboardTypes.h"
#include "KeyTypes.h"
class IClipboard;
class IScreen;
class IScreenReceiver;
// platform independent base class for primary screen implementations.
// each platform will derive a class from CPrimaryScreen to handle
// platform dependent operations.
class CPrimaryScreen {
public:
CPrimaryScreen(IScreenReceiver*);
virtual ~CPrimaryScreen();
// manipulators
// enter the screen's message loop. this returns when it detects
// the application should terminate or when stop() is called.
// run() may only be called between open() and close().
void run();
// cause run() to return
void stop();
// initializes the screen and starts reporting events
void open();
// close the screen
void close();
// called when the user navigates to the primary screen.
// forScreensaver == true means that we're entering the primary
// screen because the screensaver has activated.
void enter(SInt32 x, SInt32 y, bool forScreensaver);
// called when the user navigates off the primary screen. returns
// true iff successful.
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.
virtual void reconfigure(UInt32 activeSides) = 0;
// warp the cursor to the given absolute coordinates
virtual void warpCursor(SInt32 x, SInt32 y) = 0;
// set the screen's clipboard contents. this is usually called
// soon after an enter().
void setClipboard(ClipboardID, const IClipboard*);
// synergy should own the clipboard
void grabClipboard(ClipboardID);
// accessors
// returns true iff the screen is active (i.e. the user has left
// the screen)
bool isActive() const;
// return the contents of the given clipboard
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;
// get the primary screen's current toggle modifier key state.
// the returned mask should have the corresponding bit set for
// each toggle key that is active.
virtual KeyModifierMask getToggleMask() const = 0;
// return true if any key or button is being pressed or if there's
// any other reason that the user should not be allowed to switch
// screens.
virtual bool isLockedToScreen() const = 0;
// get the platform dependent screen object
virtual IScreen* getScreen() const = 0;
protected:
// template method hooks. these are called on entry/exit to the
// named method. onEnterScreensaver() is called by enter() iff
// forScreensaver is true. onPostLeave() is passed the result of
// showWindow(). override to do platform specific operations.
// defaults do nothing.
virtual void onPreRun();
virtual void onPostRun();
virtual void onPreOpen();
virtual void onPostOpen();
virtual void onPreClose();
virtual void onPostClose();
virtual void onPreEnter();
virtual void onPostEnter();
virtual void onEnterScreensaver();
virtual void onPreLeave();
virtual void onPostLeave(bool success);
// create/destroy the window. this window is generally used to
// receive events and, when the user navigates to another screen,
// to capture keyboard and mouse input.
virtual void createWindow() = 0;
virtual void destroyWindow() = 0;
// called when the user navigates off the primary screen. hide the
// cursor and grab exclusive access to the input devices. returns
// true iff successful. every call to showWindow() has a matching
// call to hideWindow() which preceeds it. return true iff
// successful (in particular, iff the input devices were grabbed).
//
// after a successful showWindow(), user input events and
// screensaver activation/deactivation should be reported to an
// IPrimaryScreenReceiver until hideWindow() is called. report
// mouse motion to IPrimaryScreenReceiver::onMouseMoveSecondary().
// user input should not be delivered to any application except
// synergy.
virtual bool showWindow() = 0;
// called when the user navigates back to the primary screen. show
// the cursor and ungab the input devices.
//
// after hideWindow(), user input events should be delivered normally.
// mouse motion over (at least) the jump zones must be reported to
// an IPrimaryScreenReceiver::onMouseMovePrimary().
virtual void hideWindow() = 0;
// prepare the cursor to report relative motion. when the user has
// navigated to another screen, synergy requires the cursor motion
// deltas, not the absolute coordinates. typically this is done by
// warping the cursor to the center of the primary screen and then
// every time it moves compute the motion and warp back to the
// center (but without reporting that warp as motion). this is
// only called after a successful showWindow().
virtual void warpCursorToCenter() = 0;
// check the current keyboard state. normally a screen will save
// the keyboard state in this method and use this shadow state
// when handling user input and in methods like isLockedToScreen().
virtual void updateKeys() = 0;
private:
void enterNoWarp();
private:
// FIXME -- should have a mutex
IScreenReceiver* m_receiver;
// m_active is true if this screen has been left
bool m_active;
};
#endif

View File

@ -92,7 +92,6 @@ CServer::run()
}
// handle events
log((CLOG_DEBUG "starting event handling"));
m_primaryClient->run();
// clean up
@ -108,9 +107,6 @@ CServer::run()
stopThreads(); \
delete m_httpServer; \
m_httpServer = NULL; \
if (m_primaryClient != NULL) { \
closePrimaryScreen(); \
} \
} while (false)
FINALLY;
}
@ -144,6 +140,15 @@ CServer::quit()
m_primaryClient->stop();
}
void
CServer::close()
{
if (m_primaryClient != NULL) {
closePrimaryScreen();
}
log((CLOG_INFO "closed screen"));
}
bool
CServer::setConfig(const CConfig& config)
{
@ -211,20 +216,6 @@ CServer::getActivePrimarySides() const
return sides;
}
void
CServer::onError()
{
// stop all running threads but don't wait too long since some
// threads may be unable to proceed until this thread returns.
stopThreads(3.0);
// done with the HTTP server
delete m_httpServer;
m_httpServer = NULL;
// note -- we do not attempt to close down the primary screen
}
void
CServer::onInfoChanged(const CString& name, const CClientInfo& info)
{
@ -347,10 +338,74 @@ CServer::onClipboardChangedNoLock(ClipboardID id,
m_active->setClipboard(id, m_clipboards[id].m_clipboardData);
}
bool
CServer::onCommandKey(KeyID /*id*/, KeyModifierMask /*mask*/, bool /*down*/)
void
CServer::onError()
{
return false;
// stop all running threads but don't wait too long since some
// threads may be unable to proceed until this thread returns.
stopThreads(3.0);
// done with the HTTP server
delete m_httpServer;
m_httpServer = NULL;
// note -- we do not attempt to close down the primary screen
}
void
CServer::onScreensaver(bool activated)
{
log((CLOG_DEBUG "onScreenSaver %s", activated ? "activated" : "deactivated"));
CLock lock(&m_mutex);
if (activated) {
// save current screen and position
m_activeSaver = m_active;
m_xSaver = m_x;
m_ySaver = m_y;
// jump to primary screen
if (m_active != m_primaryClient) {
switchScreen(m_primaryClient, 0, 0, true);
}
}
else {
// jump back to previous screen and position. we must check
// that the position is still valid since the screen may have
// changed resolutions while the screen saver was running.
if (m_activeSaver != NULL && m_activeSaver != m_primaryClient) {
// check position
IClient* screen = m_activeSaver;
SInt32 x, y, w, h;
screen->getShape(x, y, w, h);
SInt32 zoneSize = screen->getJumpZoneSize();
if (m_xSaver < x + zoneSize) {
m_xSaver = x + zoneSize;
}
else if (m_xSaver >= x + w - zoneSize) {
m_xSaver = x + w - zoneSize - 1;
}
if (m_ySaver < y + zoneSize) {
m_ySaver = y + zoneSize;
}
else if (m_ySaver >= y + h - zoneSize) {
m_ySaver = y + h - zoneSize - 1;
}
// jump
switchScreen(screen, m_xSaver, m_ySaver, false);
}
// reset state
m_activeSaver = NULL;
}
// send message to all clients
for (CClientList::const_iterator index = m_clients.begin();
index != m_clients.end(); ++index) {
IClient* client = index->second;
client->screensaver(activated);
}
}
void
@ -615,60 +670,10 @@ CServer::onMouseWheel(SInt32 delta)
m_active->mouseWheel(delta);
}
void
CServer::onScreenSaver(bool activated)
bool
CServer::onCommandKey(KeyID /*id*/, KeyModifierMask /*mask*/, bool /*down*/)
{
log((CLOG_DEBUG "onScreenSaver %s", activated ? "activated" : "deactivated"));
CLock lock(&m_mutex);
if (activated) {
// save current screen and position
m_activeSaver = m_active;
m_xSaver = m_x;
m_ySaver = m_y;
// jump to primary screen
if (m_active != m_primaryClient) {
switchScreen(m_primaryClient, 0, 0, true);
}
}
else {
// jump back to previous screen and position. we must check
// that the position is still valid since the screen may have
// changed resolutions while the screen saver was running.
if (m_activeSaver != NULL && m_activeSaver != m_primaryClient) {
// check position
IClient* screen = m_activeSaver;
SInt32 x, y, w, h;
screen->getShape(x, y, w, h);
SInt32 zoneSize = screen->getJumpZoneSize();
if (m_xSaver < x + zoneSize) {
m_xSaver = x + zoneSize;
}
else if (m_xSaver >= x + w - zoneSize) {
m_xSaver = x + w - zoneSize - 1;
}
if (m_ySaver < y + zoneSize) {
m_ySaver = y + zoneSize;
}
else if (m_ySaver >= y + h - zoneSize) {
m_ySaver = y + h - zoneSize - 1;
}
// jump
switchScreen(screen, m_xSaver, m_ySaver, false);
}
// reset state
m_activeSaver = NULL;
}
// send message to all clients
for (CClientList::const_iterator index = m_clients.begin();
index != m_clients.end(); ++index) {
IClient* client = index->second;
client->screenSaver(activated);
}
return false;
}
bool
@ -689,7 +694,7 @@ CServer::isLockedToScreenNoLock() const
}
void
CServer::switchScreen(IClient* dst, SInt32 x, SInt32 y, bool screenSaver)
CServer::switchScreen(IClient* dst, SInt32 x, SInt32 y, bool forScreensaver)
{
assert(dst != NULL);
#ifndef NDEBUG
@ -741,7 +746,8 @@ CServer::switchScreen(IClient* dst, SInt32 x, SInt32 y, bool screenSaver)
// enter new screen
m_active->enter(x, y, m_seqNum,
m_primaryClient->getToggleMask(), screenSaver);
m_primaryClient->getToggleMask(),
forScreensaver);
// send the clipboard data to new active screen
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
@ -1209,7 +1215,7 @@ CServer::runClient(void* vsocket)
{
CLock lock(&m_mutex);
if (m_activeSaver != NULL) {
proxy->screenSaver(true);
proxy->screensaver(true);
}
}
@ -1510,7 +1516,7 @@ CServer::openPrimaryScreen()
// create the primary client and open it
try {
m_primaryClient = new CPrimaryClient(this, primary);
m_primaryClient = new CPrimaryClient(this, this, primary);
// add connection
addConnection(m_primaryClient);
@ -1593,7 +1599,7 @@ CServer::removeConnection(const CString& name)
IClient* active = (m_activeSaver != NULL) ? m_activeSaver : m_active;
if (active == index->second && active != m_primaryClient) {
// record new position (center of primary screen)
m_primaryClient->getCenter(m_x, m_y);
m_primaryClient->getCursorCenter(m_x, m_y);
// don't notify active screen since it probably already disconnected
log((CLOG_INFO "jump from \"%s\" to \"%s\" at %d,%d", active->getName().c_str(), m_primaryClient->getName().c_str(), m_x, m_y));

View File

@ -2,6 +2,7 @@
#define CSERVER_H
#include "IServer.h"
#include "IPrimaryScreenReceiver.h"
#include "CConfig.h"
#include "CClipboard.h"
#include "CCondVar.h"
@ -20,7 +21,7 @@ class IServerProtocol;
class ISocketFactory;
class ISecurityFactory;
class CServer : public IServer {
class CServer : public IServer, public IPrimaryScreenReceiver {
public:
CServer(const CString& serverName);
~CServer();
@ -38,6 +39,9 @@ public:
// after a successful open().
void quit();
// close the server's screen
void close();
// update screen map. returns true iff the new configuration was
// accepted.
bool setConfig(const CConfig&);
@ -50,8 +54,14 @@ public:
// get the primary screen's name
CString getPrimaryScreenName() const;
// IServer overrides
virtual void onInfoChanged(const CString&, const CClientInfo&);
virtual bool onGrabClipboard(const CString&, ClipboardID, UInt32);
virtual void onClipboardChanged(ClipboardID, UInt32, const CString&);
// IPrimaryScreenReceiver overrides
virtual void onError();
virtual void onScreensaver(bool activated);
virtual void onKeyDown(KeyID, KeyModifierMask);
virtual void onKeyUp(KeyID, KeyModifierMask);
virtual void onKeyRepeat(KeyID, KeyModifierMask, SInt32 count);
@ -60,12 +70,6 @@ public:
virtual bool onMouseMovePrimary(SInt32 x, SInt32 y);
virtual void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
virtual void onMouseWheel(SInt32 delta);
virtual void onScreenSaver(bool activated);
// IServer overrides
virtual void onInfoChanged(const CString&, const CClientInfo&);
virtual bool onGrabClipboard(const CString&, ClipboardID, UInt32);
virtual void onClipboardChanged(ClipboardID, UInt32, const CString&);
protected:
bool onCommandKey(KeyID, KeyModifierMask, bool down);

View File

@ -1,11 +1,7 @@
#include "CXWindowsPrimaryScreen.h"
#include "IScreenReceiver.h"
#include "IPrimaryScreenReceiver.h"
#include "CXWindowsClipboard.h"
#include "CXWindowsScreenSaver.h"
#include "CXWindowsScreen.h"
#include "CXWindowsUtil.h"
#include "CClipboard.h"
#include "ProtocolTypes.h"
#include "IPrimaryScreenReceiver.h"
#include "XScreen.h"
#include "CThread.h"
#include "CLog.h"
@ -26,162 +22,17 @@
CXWindowsPrimaryScreen::CXWindowsPrimaryScreen(
IScreenReceiver* receiver,
IPrimaryScreenReceiver* primaryReceiver) :
m_receiver(receiver),
m_primaryReceiver(primaryReceiver),
m_active(false),
CPrimaryScreen(receiver),
m_receiver(primaryReceiver),
m_window(None)
{
// do nothing
m_screen = new CXWindowsScreen(receiver, this);
}
CXWindowsPrimaryScreen::~CXWindowsPrimaryScreen()
{
assert(m_window == None);
}
void
CXWindowsPrimaryScreen::run()
{
// 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
CXWindowsPrimaryScreen::stop()
{
exitMainLoop();
}
void
CXWindowsPrimaryScreen::open()
{
assert(m_window == None);
CClientInfo info;
try {
// open the display
openDisplay();
// create and prepare our window
createWindow();
// get the display
CDisplayLock display(this);
// initialize the clipboards
initClipboards(m_window);
// miscellaneous initialization
m_atomScreenSaver = XInternAtom(display, "SCREENSAVER", False);
// check for peculiarities
// FIXME -- may have to get these from some database
m_numLockHalfDuplex = false;
m_capsLockHalfDuplex = false;
// m_numLockHalfDuplex = true;
// m_capsLockHalfDuplex = true;
// 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);
// update key state
updateModifierMap(display);
// get notified of screen saver activation/deactivation
installScreenSaver();
}
catch (...) {
close();
throw;
}
// enter the screen
enterNoWarp();
// send screen info
m_receiver->onInfoChanged(info);
}
void
CXWindowsPrimaryScreen::close()
{
uninstallScreenSaver();
destroyWindow();
closeDisplay();
}
void
CXWindowsPrimaryScreen::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 != None);
// enter the screen
enterNoWarp();
// warp to requested location
if (!forScreenSaver) {
warpCursor(x, y);
}
// redirect input to root window. do not warp the mouse because
// that will deactivate the screen saver.
else {
CDisplayLock display(this);
XSetInputFocus(display, PointerRoot, PointerRoot, CurrentTime);
}
}
bool
CXWindowsPrimaryScreen::leave()
{
log((CLOG_INFO "leaving primary"));
assert(m_active == false);
assert(m_window != None);
// show our window
if (!showWindow()) {
return false;
}
// warp mouse to center
warpCursorToCenter();
// FIXME -- this doesn't match the win32 version. that just does
// the warp while we flush the input queue until we find the warp
// and we discard that too. would prefer to at least match our
// own warping when we receive MotionNotify; that just does the
// warp. however, the win32 version sometimes stutters when
// leaving and perhaps this is why. hmm, win32 does ignore the
// events until after the warp (via the mark).
// local client now active
m_active = true;
// make sure our idea of clipboard ownership is correct
checkClipboard();
return true;
delete m_screen;
}
void
@ -193,7 +44,7 @@ CXWindowsPrimaryScreen::reconfigure(UInt32)
void
CXWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y)
{
CDisplayLock display(this);
CDisplayLock display(m_screen);
// warp mouse
warpCursorNoFlush(display, x, y);
@ -213,30 +64,10 @@ CXWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y)
m_y = y;
}
void
CXWindowsPrimaryScreen::setClipboard(ClipboardID id,
const IClipboard* clipboard)
{
setDisplayClipboard(id, clipboard);
}
void
CXWindowsPrimaryScreen::grabClipboard(ClipboardID id)
{
setDisplayClipboard(id, NULL);
}
void
CXWindowsPrimaryScreen::getClipboard(ClipboardID id,
IClipboard* clipboard) const
{
getDisplayClipboard(id, clipboard);
}
KeyModifierMask
CXWindowsPrimaryScreen::getToggleMask() const
{
CDisplayLock display(this);
CDisplayLock display(m_screen);
// query the pointer to get the keyboard state
Window root, window;
@ -265,7 +96,7 @@ CXWindowsPrimaryScreen::getToggleMask() const
bool
CXWindowsPrimaryScreen::isLockedToScreen() const
{
CDisplayLock display(this);
CDisplayLock display(m_screen);
// query the pointer to get the button state
Window root, window;
@ -295,11 +126,29 @@ CXWindowsPrimaryScreen::isLockedToScreen() const
return false;
}
bool
CXWindowsPrimaryScreen::onPreDispatch(const CEvent* event)
IScreen*
CXWindowsPrimaryScreen::getScreen() const
{
// forward to superclass
return CXWindowsScreen::onPreDispatch(event);
return m_screen;
}
void
CXWindowsPrimaryScreen::onError()
{
// tell server to shutdown
m_receiver->onError();
}
void
CXWindowsPrimaryScreen::onScreensaver(bool activated)
{
m_receiver->onScreensaver(activated);
}
bool
CXWindowsPrimaryScreen::onPreDispatch(const CEvent*)
{
return false;
}
bool
@ -313,41 +162,28 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event)
case CreateNotify:
{
// select events on new window
CDisplayLock display(this);
CDisplayLock display(m_screen);
selectEvents(display, xevent.xcreatewindow.window);
}
return true;
case MappingNotify:
{
// keyboard mapping changed
CDisplayLock display(this);
XRefreshKeyboardMapping(&xevent.xmapping);
updateModifierMap(display);
}
// keyboard mapping changed
updateKeys();
return true;
case ClientMessage:
if (xevent.xclient.message_type == m_atomScreenSaver ||
xevent.xclient.format == 32) {
// screen saver activation/deactivation event
m_primaryReceiver->onScreenSaver(xevent.xclient.data.l[0] != 0);
return true;
}
break;
case KeyPress:
{
log((CLOG_DEBUG1 "event: KeyPress code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state));
const KeyModifierMask mask = mapModifier(xevent.xkey.state);
const KeyID key = mapKey(&xevent.xkey);
if (key != kKeyNone) {
m_primaryReceiver->onKeyDown(key, mask);
m_receiver->onKeyDown(key, mask);
if (key == XK_Caps_Lock && m_capsLockHalfDuplex) {
m_primaryReceiver->onKeyUp(key, mask | KeyModifierCapsLock);
m_receiver->onKeyUp(key, mask | KeyModifierCapsLock);
}
else if (key == XK_Num_Lock && m_numLockHalfDuplex) {
m_primaryReceiver->onKeyUp(key, mask | KeyModifierNumLock);
m_receiver->onKeyUp(key, mask | KeyModifierNumLock);
}
}
}
@ -369,20 +205,24 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event)
filter.m_keycode = xevent.xkey.keycode;
// now check for event
XEvent xevent2;
CDisplayLock display(this);
if (XCheckIfEvent(display, &xevent2,
&CXWindowsPrimaryScreen::findKeyEvent,
(XPointer)&filter) != True) {
bool hasPress;
{
XEvent xevent2;
CDisplayLock display(m_screen);
hasPress = (XCheckIfEvent(display, &xevent2,
&CXWindowsPrimaryScreen::findKeyEvent,
(XPointer)&filter) == True);
}
if (!hasPress) {
// no press event follows so it's a plain release
log((CLOG_DEBUG1 "event: KeyRelease code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state));
if (key == XK_Caps_Lock && m_capsLockHalfDuplex) {
m_primaryReceiver->onKeyDown(key, mask);
m_receiver->onKeyDown(key, mask);
}
else if (key == XK_Num_Lock && m_numLockHalfDuplex) {
m_primaryReceiver->onKeyDown(key, mask);
m_receiver->onKeyDown(key, mask);
}
m_primaryReceiver->onKeyUp(key, mask);
m_receiver->onKeyUp(key, mask);
}
else {
// found a press event following so it's a repeat.
@ -390,7 +230,7 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event)
// repeats but we'll just send a repeat of 1.
// note that we discard the press event.
log((CLOG_DEBUG1 "event: repeat code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state));
m_primaryReceiver->onKeyRepeat(key, mask, 1);
m_receiver->onKeyRepeat(key, mask, 1);
}
}
}
@ -401,7 +241,7 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event)
log((CLOG_DEBUG1 "event: ButtonPress button=%d", xevent.xbutton.button));
const ButtonID button = mapButton(xevent.xbutton.button);
if (button != kButtonNone) {
m_primaryReceiver->onMouseDown(button);
m_receiver->onMouseDown(button);
}
}
return true;
@ -411,15 +251,15 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event)
log((CLOG_DEBUG1 "event: ButtonRelease button=%d", xevent.xbutton.button));
const ButtonID button = mapButton(xevent.xbutton.button);
if (button != kButtonNone) {
m_primaryReceiver->onMouseUp(button);
m_receiver->onMouseUp(button);
}
else if (xevent.xbutton.button == 4) {
// wheel forward (away from user)
m_primaryReceiver->onMouseWheel(120);
m_receiver->onMouseWheel(120);
}
else if (xevent.xbutton.button == 5) {
// wheel backward (toward user)
m_primaryReceiver->onMouseWheel(-120);
m_receiver->onMouseWheel(-120);
}
}
return true;
@ -443,14 +283,14 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event)
// warpCursorNoFlush() for where the events are
// sent. we discard the matching sent event and
// can be sure we've skipped the warp event.
CDisplayLock display(this);
CDisplayLock display(m_screen);
do {
XMaskEvent(display, PointerMotionMask, &xevent);
} while (!xevent.xmotion.send_event);
}
else if (!m_active) {
else if (!isActive()) {
// motion on primary screen
m_primaryReceiver->onMouseMovePrimary(m_x, m_y);
m_receiver->onMouseMovePrimary(m_x, m_y);
}
else {
// motion on secondary screen. warp mouse back to
@ -470,7 +310,7 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event)
xevent.xmotion.x_root - m_xCenter > s_size ||
xevent.xmotion.y_root - m_yCenter < -s_size ||
xevent.xmotion.y_root - m_yCenter > s_size) {
CDisplayLock display(this);
CDisplayLock display(m_screen);
warpCursorNoFlush(display, m_xCenter, m_yCenter);
}
@ -481,7 +321,7 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event)
// warping to the primary screen's enter position,
// effectively overriding it.
if (x != 0 || y != 0) {
m_primaryReceiver->onMouseMoveSecondary(x, y);
m_receiver->onMouseMoveSecondary(x, y);
}
}
}
@ -492,77 +332,117 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event)
}
void
CXWindowsPrimaryScreen::onUnexpectedClose()
CXWindowsPrimaryScreen::onPreRun()
{
// tell server to shutdown
m_primaryReceiver->onError();
}
void
CXWindowsPrimaryScreen::onLostClipboard(ClipboardID id)
{
// tell server that the clipboard was grabbed locally
m_receiver->onGrabClipboard(id);
}
SInt32
CXWindowsPrimaryScreen::getJumpZoneSize() const
{
return 1;
}
void
CXWindowsPrimaryScreen::warpCursorToCenter()
{
warpCursor(m_xCenter, m_yCenter);
}
void
CXWindowsPrimaryScreen::warpCursorNoFlush(
Display* display, SInt32 x, SInt32 y)
{
assert(display != NULL);
assert(m_window != None);
// send an event that we can recognize before the mouse warp
XEvent eventBefore;
eventBefore.type = MotionNotify;
eventBefore.xmotion.display = display;
eventBefore.xmotion.window = m_window;
eventBefore.xmotion.root = getRoot();
eventBefore.xmotion.subwindow = m_window;
eventBefore.xmotion.time = CurrentTime;
eventBefore.xmotion.x = x;
eventBefore.xmotion.y = y;
eventBefore.xmotion.x_root = x;
eventBefore.xmotion.y_root = y;
eventBefore.xmotion.state = 0;
eventBefore.xmotion.is_hint = False;
eventBefore.xmotion.same_screen = True;
XEvent eventAfter = eventBefore;
XSendEvent(display, m_window, False, 0, &eventBefore);
// warp mouse
XWarpPointer(display, None, getRoot(), 0, 0, 0, 0, x, y);
// send an event that we can recognize after the mouse warp
XSendEvent(display, m_window, False, 0, &eventAfter);
XSync(display, False);
log((CLOG_DEBUG2 "warped to %d,%d", x, y));
}
void
CXWindowsPrimaryScreen::enterNoWarp()
CXWindowsPrimaryScreen::onPreOpen()
{
m_active = false;
hideWindow();
assert(m_window == None);
}
void
CXWindowsPrimaryScreen::onPostOpen()
{
// get cursor info
m_screen->getCursorPos(m_x, m_y);
m_screen->getCursorCenter(m_xCenter, m_yCenter);
// check for peculiarities
// FIXME -- may have to get these from some database
m_numLockHalfDuplex = false;
m_capsLockHalfDuplex = false;
// m_numLockHalfDuplex = true;
// m_capsLockHalfDuplex = true;
}
void
CXWindowsPrimaryScreen::onPreEnter()
{
assert(m_window != None);
}
void
CXWindowsPrimaryScreen::onPreLeave()
{
assert(m_window != None);
}
void
CXWindowsPrimaryScreen::onEnterScreenSaver()
{
CDisplayLock display(m_screen);
// set keyboard focus to root window. the screensaver should then
// pick up key events for when the user enters a password to unlock.
XSetInputFocus(display, PointerRoot, PointerRoot, CurrentTime);
}
void
CXWindowsPrimaryScreen::createWindow()
{
assert(m_window == None);
// get size of screen
SInt32 x, y, w, h;
m_screen->getShape(x, y, w, h);
// grab window attributes. this window is used to capture user
// input when the user is focused on another client. don't let
// the window manager mess with it.
XSetWindowAttributes attr;
attr.event_mask = PointerMotionMask |
ButtonPressMask | ButtonReleaseMask |
KeyPressMask | KeyReleaseMask |
KeymapStateMask | PropertyChangeMask;
attr.do_not_propagate_mask = 0;
attr.override_redirect = True;
attr.cursor = m_screen->getBlankCursor();
{
// create the grab window
CDisplayLock display(m_screen);
m_window = XCreateWindow(display, m_screen->getRoot(),
x, y, w, h, 0, 0,
InputOnly, CopyFromParent,
CWDontPropagate | CWEventMask |
CWOverrideRedirect | CWCursor,
&attr);
if (m_window == None) {
throw XScreenOpenFailure();
}
log((CLOG_DEBUG "window is 0x%08x", m_window));
// start watching for events on other windows
selectEvents(display, m_screen->getRoot());
}
// tell our superclass about the window
m_screen->setWindow(m_window);
}
void
CXWindowsPrimaryScreen::destroyWindow()
{
// display can be NULL if the server unexpectedly disconnected
if (m_window != None) {
m_screen->setWindow(None);
CDisplayLock display(m_screen);
if (display != NULL) {
XDestroyWindow(display, m_window);
}
m_window = None;
}
}
bool
CXWindowsPrimaryScreen::showWindow()
{
CDisplayLock display(this);
assert(m_window != None);
CDisplayLock display(m_screen);
// raise and show the input window
XMapRaised(display, m_window);
@ -616,83 +496,51 @@ CXWindowsPrimaryScreen::showWindow()
void
CXWindowsPrimaryScreen::hideWindow()
{
CDisplayLock display(this);
CDisplayLock display(m_screen);
// unmap the grab window. this also ungrabs the mouse and keyboard.
XUnmapWindow(display, m_window);
}
void
CXWindowsPrimaryScreen::checkClipboard()
CXWindowsPrimaryScreen::warpCursorToCenter()
{
// do nothing, we're always up to date
warpCursor(m_xCenter, m_yCenter);
}
void
CXWindowsPrimaryScreen::createWindow()
CXWindowsPrimaryScreen::warpCursorNoFlush(
Display* display, SInt32 x, SInt32 y)
{
assert(m_window == None);
assert(display != NULL);
assert(m_window != None);
// get size of screen
SInt32 x, y, w, h;
getScreenShape(x, y, w, h);
// send an event that we can recognize before the mouse warp
XEvent eventBefore;
eventBefore.type = MotionNotify;
eventBefore.xmotion.display = display;
eventBefore.xmotion.window = m_window;
eventBefore.xmotion.root = m_screen->getRoot();
eventBefore.xmotion.subwindow = m_window;
eventBefore.xmotion.time = CurrentTime;
eventBefore.xmotion.x = x;
eventBefore.xmotion.y = y;
eventBefore.xmotion.x_root = x;
eventBefore.xmotion.y_root = y;
eventBefore.xmotion.state = 0;
eventBefore.xmotion.is_hint = False;
eventBefore.xmotion.same_screen = True;
XEvent eventAfter = eventBefore;
XSendEvent(display, m_window, False, 0, &eventBefore);
// grab window attributes. this window is used to capture user
// input when the user is focused on another client. don't let
// the window manager mess with it.
XSetWindowAttributes attr;
attr.event_mask = PointerMotionMask |
ButtonPressMask | ButtonReleaseMask |
KeyPressMask | KeyReleaseMask |
KeymapStateMask | PropertyChangeMask;
attr.do_not_propagate_mask = 0;
attr.override_redirect = True;
attr.cursor = getBlankCursor();
// warp mouse
XWarpPointer(display, None, m_screen->getRoot(), 0, 0, 0, 0, x, y);
// create the grab window
CDisplayLock display(this);
m_window = XCreateWindow(display, getRoot(),
x, y, w, h, 0, 0,
InputOnly, CopyFromParent,
CWDontPropagate | CWEventMask |
CWOverrideRedirect | CWCursor,
&attr);
if (m_window == None) {
throw XScreenOpenFailure();
}
log((CLOG_DEBUG "window is 0x%08x", m_window));
// send an event that we can recognize after the mouse warp
XSendEvent(display, m_window, False, 0, &eventAfter);
XSync(display, False);
// start watching for events on other windows
selectEvents(display, getRoot());
}
void
CXWindowsPrimaryScreen::destroyWindow()
{
// display can be NULL if the server unexpectedly disconnected
CDisplayLock display(this);
if (display != NULL && m_window != None) {
XDestroyWindow(display, m_window);
}
m_window = None;
}
void
CXWindowsPrimaryScreen::installScreenSaver()
{
assert(getScreenSaver() != NULL);
getScreenSaver()->setNotify(m_window);
}
void
CXWindowsPrimaryScreen::uninstallScreenSaver()
{
// stop being notified of screen saver activation/deactivation
if (getScreenSaver() != NULL) {
getScreenSaver()->setNotify(None);
}
m_atomScreenSaver = None;
log((CLOG_DEBUG2 "warped to %d,%d", x, y));
}
void
@ -777,7 +625,7 @@ CXWindowsPrimaryScreen::mapKey(XKeyEvent* event) const
KeySym keysym;
char dummy[1];
CDisplayLock display(this);
CDisplayLock display(m_screen);
XLookupString(event, dummy, 0, &keysym, NULL);
return static_cast<KeyID>(keysym);
}
@ -795,8 +643,10 @@ CXWindowsPrimaryScreen::mapButton(unsigned int button) const
}
void
CXWindowsPrimaryScreen::updateModifierMap(Display* display)
CXWindowsPrimaryScreen::updateKeys()
{
CDisplayLock display(m_screen);
// get modifier map from server
XModifierKeymap* keymap = XGetModifierMapping(display);

View File

@ -1,63 +1,59 @@
#ifndef CXWINDOWSPRIMARYSCREEN_H
#define CXWINDOWSPRIMARYSCREEN_H
#include "CXWindowsScreen.h"
#include "IPrimaryScreen.h"
#include "CPrimaryScreen.h"
#include "IScreenEventHandler.h"
#include "MouseTypes.h"
#if defined(X_DISPLAY_MISSING)
# error X11 is required to build synergy
#else
# include <X11/Xlib.h>
#endif
class CXWindowsScreen;
class IScreenReceiver;
class IPrimaryScreenReceiver;
class CXWindowsPrimaryScreen : public CXWindowsScreen, public IPrimaryScreen {
class CXWindowsPrimaryScreen :
public CPrimaryScreen, public IScreenEventHandler {
public:
CXWindowsPrimaryScreen(IScreenReceiver*, IPrimaryScreenReceiver*);
virtual ~CXWindowsPrimaryScreen();
// 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;
protected:
// CXWindowsScreen overrides
// IScreenEventHandler overrides
virtual void onError();
virtual void onScreensaver(bool activated);
virtual bool onPreDispatch(const CEvent* event);
virtual bool onEvent(CEvent* event);
virtual void onUnexpectedClose();
virtual void onLostClipboard(ClipboardID);
protected:
// CPrimaryScreen overrides
virtual void onPreRun();
virtual void onPreOpen();
virtual void onPostOpen();
virtual void onPreEnter();
virtual void onPreLeave();
virtual void onEnterScreenSaver();
virtual void createWindow();
virtual void destroyWindow();
virtual bool showWindow();
virtual void hideWindow();
virtual void warpCursorToCenter();
virtual void updateKeys();
private:
SInt32 getJumpZoneSize() const;
void warpCursorToCenter();
void warpCursorNoFlush(Display*,
SInt32 xAbsolute, SInt32 yAbsolute);
void enterNoWarp();
bool showWindow();
void hideWindow();
// check clipboard ownership and, if necessary, tell the receiver
// of a grab.
void checkClipboard();
// create/destroy window
void createWindow();
void destroyWindow();
// start/stop watch for screen saver changes
void installScreenSaver();
void uninstallScreenSaver();
void selectEvents(Display*, Window) const;
void doSelectEvents(Display*, Window) const;
@ -65,8 +61,6 @@ private:
KeyID mapKey(XKeyEvent*) const;
ButtonID mapButton(unsigned int button) const;
void updateModifierMap(Display* display);
class CKeyEventInfo {
public:
int m_event;
@ -77,15 +71,12 @@ private:
static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg);
private:
IScreenReceiver* m_receiver;
IPrimaryScreenReceiver* m_primaryReceiver;
CXWindowsScreen* m_screen;
IPrimaryScreenReceiver* m_receiver;
bool m_active;
// our window
Window m_window;
// atom for screen saver messages
Atom m_atomScreenSaver;
// note toggle keys that toggle on up/down (false) or on
// transition (true)
bool m_numLockHalfDuplex;

View File

@ -1,95 +0,0 @@
#ifndef IPRIMARYSCREEN_H
#define IPRIMARYSCREEN_H
#include "IInterface.h"
#include "KeyTypes.h"
#include "ClipboardTypes.h"
class IClipboard;
class IPrimaryScreen : public IInterface {
public:
// manipulators
// enter the screen's message loop. this returns when it detects
// the application should terminate or when stop() is called.
// the screen must be open()'d before run() and must not be
// close()'d until run() returns.
virtual void run() = 0;
// cause run() to return
virtual void stop() = 0;
// initialize the screen and start reporting events to the receiver
// (which is set through some interface of the derived class).
// events should be reported no matter where on the screen they
// occur but do not interfere with normal event dispatch. the
// screen saver engaging should be reported as an event. if that
// can't be detected then this object should disable the system's
// screen saver timer and should start the screen saver after
// idling for an appropriate time.
//
// open() must call receiver->onInfoChanged() to notify of the
// primary screen's initial resolution and jump zone size. it
// must also call receiver->onClipboardChanged() for each
// clipboard that the primary screen has.
virtual void open() = 0;
// close the screen. should restore the screen saver timer if it
// was disabled.
virtual void close() = 0;
// called when the user navigates back to the primary screen.
// warp the cursor to the given coordinates, unhide it, and
// ungrab the input devices. every call to enter has a matching
// call to leave() which preceeds it, however the screen should
// assume an implicit call to enter() in the call to open().
// if warpCursor is false then do not warp the mouse.
//
// enter() must not call any receiver methods except onError().
virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute,
bool forScreenSaver) = 0;
// called when the user navigates off the primary screen. hide the
// cursor and grab exclusive access to the input devices. return
// true iff successful.
//
// leave() must not call any receiver methods except onError().
virtual bool leave() = 0;
// called when the configuration has changed. activeSides is a
// bitmask of CConfig::EDirectionMask indicating which sides of
// the primary screen are linked to clients.
virtual void reconfigure(UInt32 activeSides) = 0;
// warp the cursor to the given position
virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute) = 0;
// set the screen's clipboard contents. this is usually called
// soon after an enter().
//
// setClipboard() must not call any receiver methods except onError().
virtual void setClipboard(ClipboardID, const IClipboard*) = 0;
// synergy should own the clipboard
virtual void grabClipboard(ClipboardID) = 0;
// accessors
// return the contents of the given clipboard.
//
// getClipboard() must not call any receiver methods except onError().
virtual void getClipboard(ClipboardID, IClipboard*) const = 0;
// get the primary screen's current toggle modifier key state.
// the returned mask should have the corresponding bit set for
// each toggle key that is active.
virtual KeyModifierMask getToggleMask() const = 0;
// return true if any key or button is being pressed or if there's
// any other reason that the user should not be allowed to switch
// screens.
virtual bool isLockedToScreen() const = 0;
};
#endif

View File

@ -9,6 +9,7 @@ synergyd_SOURCES = \
CConfig.cpp \
CHTTPServer.cpp \
CPrimaryClient.cpp \
CPrimaryScreen.cpp \
CServer.cpp \
CXWindowsPrimaryScreen.cpp \
server.cpp \
@ -17,9 +18,9 @@ synergyd_SOURCES = \
CConfig.h \
CHTTPServer.h \
CPrimaryClient.h \
CPrimaryScreen.h \
CServer.h \
CXWindowsPrimaryScreen.h \
IPrimaryScreen.h \
$(NULL)
synergyd_LDADD = \
$(DEPTH)/platform/libplatform.a \

View File

@ -132,6 +132,7 @@ realMain(CMutex* mutex)
}
// clean up
s_server->close();
delete s_server;
s_server = NULL;
CLog::setLock(NULL);
@ -142,8 +143,11 @@ realMain(CMutex* mutex)
if (!locked && mutex != NULL) {
mutex->lock();
}
delete s_server;
s_server = NULL;
if (s_server != NULL) {
s_server->close();
delete s_server;
s_server = NULL;
}
CLog::setLock(NULL);
s_logMutex = NULL;
throw;

View File

@ -7,6 +7,8 @@
#include "MouseTypes.h"
#include "CString.h"
// the client interface. this provides all the methods necessary for
// the server to communicate with a client.
class IClient : public IInterface {
public:
// manipulators
@ -23,11 +25,11 @@ public:
// enter the screen. the cursor should be warped to xAbs,yAbs.
// the client should record seqNum for future reporting of
// clipboard changes. mask is the expected toggle button state.
// screenSaver is true if the screen is being entered because
// forScreensaver is true if the screen is being entered because
// the screen saver is starting.
virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask,
bool screenSaver) = 0;
bool forScreensaver) = 0;
// leave the screen. returns false if the user may not leave the
// client's screen.
@ -54,25 +56,25 @@ public:
virtual void mouseUp(ButtonID) = 0;
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs) = 0;
virtual void mouseWheel(SInt32 delta) = 0;
virtual void screenSaver(bool activate) = 0;
virtual void screensaver(bool activate) = 0;
// accessors
// get the client's identifier
virtual CString getName() const = 0;
// get the size of jump zone
virtual SInt32 getJumpZoneSize() const = 0;
// get the screen's shape
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const = 0;
// get the center pixel
virtual void getCenter(SInt32& x, SInt32& y) const = 0;
// get the mouse position
virtual void getMousePos(SInt32& x, SInt32& y) const = 0;
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
// get the size of jump zone
virtual SInt32 getJumpZoneSize() const = 0;
// get the center pixel
virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0;
};
#endif

View File

@ -5,12 +5,22 @@
#include "KeyTypes.h"
#include "MouseTypes.h"
// the interface for receiving notification of events on the primary
// screen. the server implements this interface to handle user input.
// platform dependent primary screen implementation will need to take
// an IPrimaryScreenReceiver* and notify it of events.
class IPrimaryScreenReceiver : public IInterface {
public:
// notify of serious error. this implies that the server should
// shutdown.
// called if the display is unexpectedly closing.
// called if the screen is unexpectedly closing. this implies that
// the screen is no longer usable and that the program should
// close the screen and possibly terminate.
virtual void onError() = 0;
// called when the screensaver is activated or deactivated
virtual void onScreensaver(bool activated) = 0;
// call to notify of events. onMouseMovePrimary() returns
// true iff the mouse enters a jump zone and jumps.
virtual void onKeyDown(KeyID, KeyModifierMask) = 0;
@ -21,8 +31,6 @@ public:
virtual bool onMouseMovePrimary(SInt32 x, SInt32 y) = 0;
virtual void onMouseMoveSecondary(SInt32 dx, SInt32 dy) = 0;
virtual void onMouseWheel(SInt32 delta) = 0;
virtual void onScreenSaver(bool activated) = 0;
};
#endif

66
synergy/IScreen.h Normal file
View File

@ -0,0 +1,66 @@
#ifndef ISCREEN_H
#define ISCREEN_H
#include "IInterface.h"
#include "ClipboardTypes.h"
class IClipboard;
// the interface for platform dependent screen implementations. each
// platform will derive a type from IScreen for interaction with the
// platform's screen that's common to primary and secondary screens.
class IScreen : public IInterface {
public:
// manipulators
// open the screen
virtual void open() = 0;
// runs an event loop and returns when exitMainLoop() is called.
// must be called between open() and close().
virtual void mainLoop() = 0;
// force mainLoop() to return
virtual void exitMainLoop() = 0;
// close the screen
virtual void close() = 0;
// set the contents of the clipboard
virtual bool setClipboard(ClipboardID, const IClipboard*) = 0;
// check clipboard ownership and notify IScreenReceiver (set through
// some other interface) if any changed
virtual void checkClipboards() = 0;
// open/close the screen saver. if notify is true then this object
// 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;
// activate or deactivate the screen saver
virtual void screensaver(bool activate) = 0;
// FIXME -- need explanation
virtual void syncDesktop() = 0;
// accessors
// get the contents of the clipboard
virtual bool getClipboard(ClipboardID, IClipboard*) const = 0;
// get the shape of the screen
virtual void getShape(SInt32& x, SInt32& y,
SInt32& w, SInt32& h) const = 0;
// get the current cursor coordinates
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
// get the cursor center position
// FIXME -- need better explanation
virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0;
};
#endif

View File

@ -0,0 +1,39 @@
#ifndef ISCREENEVENTHANDLER_H
#define ISCREENEVENTHANDLER_H
#include "IInterface.h"
// the platform screen should define this
class CEvent;
class IScreen;
// the interface through which IScreen sends notification of events.
// each platform will derive two types from IScreenEventHandler, one
// for handling events on the primary screen and one for the
// secondary screen. the header file with the IScreen subclass for
// each platform should define the CEvent type, which depends on the
// type of native events for that platform.
class IScreenEventHandler : public IInterface {
public:
// manipulators
// called if the screen is unexpectedly closing. this implies that
// the screen is no longer usable and that the program should
// close the screen and possibly terminate.
virtual void onError() = 0;
// called when the screensaver is activated or deactivated
virtual void onScreensaver(bool activated) = 0;
// 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) = 0;
// 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;
};
#endif

View File

@ -6,6 +6,8 @@
#include "ProtocolTypes.h"
#include "CString.h"
// the interface for types that receive screen resize and clipboard
// notifications (indirectly) from the system.
class IScreenReceiver : public IInterface {
public:
// notify of client info change

View File

@ -1,13 +1,19 @@
#ifndef ISERVER_H
#define ISERVER_H
#include "IPrimaryScreenReceiver.h"
#include "IInterface.h"
#include "ClipboardTypes.h"
#include "CString.h"
class CClientInfo;
class IServer : public IPrimaryScreenReceiver {
// the server interface. this provides all the methods necessary for
// clients to communicate with the server. note that the methods
// in this interface are similar to the methods in IScreenReceiver but
// include extra parameters. this interface is suitable for server-side
// client proxies. client-side objects should use the IScreenReceiver
// interface since the extra parameters are meaningless on the client-side.
class IServer : public IInterface {
public:
// manipulators
@ -23,18 +29,6 @@ public:
// notify of new clipboard data
virtual void onClipboardChanged(ClipboardID,
UInt32 seqNum, const CString& data) = 0;
// IPrimaryScreenReceiver overrides
virtual void onError() = 0;
virtual void onKeyDown(KeyID, KeyModifierMask) = 0;
virtual void onKeyUp(KeyID, KeyModifierMask) = 0;
virtual void onKeyRepeat(KeyID, KeyModifierMask, SInt32 count) = 0;
virtual void onMouseDown(ButtonID) = 0;
virtual void onMouseUp(ButtonID) = 0;
virtual bool onMouseMovePrimary(SInt32 x, SInt32 y) = 0;
virtual void onMouseMoveSecondary(SInt32 dx, SInt32 dy) = 0;
virtual void onMouseWheel(SInt32 delta) = 0;
virtual void onScreenSaver(bool activated) = 0;
};
#endif

View File

@ -20,6 +20,8 @@ libsynergy_a_SOURCES = \
IClient.h \
IClipboard.h \
IPrimaryScreenReceiver.h\
IScreen.h \
IScreenEventHandler.h \
IScreenReceiver.h \
IScreenSaver.h \
IServer.h \