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

View File

@ -7,10 +7,10 @@
#include "CNetworkAddress.h" #include "CNetworkAddress.h"
#include "CMutex.h" #include "CMutex.h"
class CSecondaryScreen;
class CServerProxy; class CServerProxy;
class CThread; class CThread;
class IDataSocket; class IDataSocket;
class ISecondaryScreen;
class IScreenReceiver; class IScreenReceiver;
class CClient : public IScreenReceiver, public IClient { class CClient : public IScreenReceiver, public IClient {
@ -50,7 +50,7 @@ public:
// FIXME -- can we avoid passing everything here? // FIXME -- can we avoid passing everything here?
virtual void enter(SInt32 xAbs, SInt32 yAbs, virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask, UInt32 seqNum, KeyModifierMask mask,
bool screenSaver); bool forScreensaver);
virtual bool leave(); virtual bool leave();
virtual void setClipboard(ClipboardID, const CString&); virtual void setClipboard(ClipboardID, const CString&);
virtual void grabClipboard(ClipboardID); virtual void grabClipboard(ClipboardID);
@ -62,13 +62,13 @@ public:
virtual void mouseUp(ButtonID); virtual void mouseUp(ButtonID);
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs); virtual void mouseMove(SInt32 xAbs, SInt32 yAbs);
virtual void mouseWheel(SInt32 delta); virtual void mouseWheel(SInt32 delta);
virtual void screenSaver(bool activate); virtual void screensaver(bool activate);
virtual CString getName() const; virtual CString getName() const;
virtual SInt32 getJumpZoneSize() const;
virtual void getShape(SInt32& x, SInt32& y, virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const; SInt32& width, SInt32& height) const;
virtual void getCenter(SInt32& x, SInt32& y) const; virtual void getCursorPos(SInt32& x, SInt32& y) const;
virtual void getMousePos(SInt32& x, SInt32& y) const; virtual void getCursorCenter(SInt32& x, SInt32& y) const;
virtual SInt32 getJumpZoneSize() const;
private: private:
// open/close the secondary screen // open/close the secondary screen
@ -87,7 +87,7 @@ private:
private: private:
CMutex m_mutex; CMutex m_mutex;
CString m_name; CString m_name;
ISecondaryScreen* m_screen; CSecondaryScreen* m_screen;
IScreenReceiver* m_server; IScreenReceiver* m_server;
CNetworkAddress m_serverAddress; CNetworkAddress m_serverAddress;
bool m_camp; 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) { else if (memcmp(code, kMsgCScreenSaver, 4) == 0) {
screenSaver(); screensaver();
} }
else if (memcmp(code, kMsgQInfo, 4) == 0) { else if (memcmp(code, kMsgQInfo, 4) == 0) {
@ -484,7 +484,7 @@ CServerProxy::mouseWheel()
} }
void void
CServerProxy::screenSaver() CServerProxy::screensaver()
{ {
// parse // parse
SInt8 on; SInt8 on;
@ -492,7 +492,7 @@ CServerProxy::screenSaver()
log((CLOG_DEBUG1 "recv screen saver on=%d", on)); log((CLOG_DEBUG1 "recv screen saver on=%d", on));
// forward // forward
getClient()->screenSaver(on != 0); getClient()->screensaver(on != 0);
} }
void void
@ -501,7 +501,7 @@ CServerProxy::queryInfo()
// get current info // get current info
CClientInfo info; CClientInfo info;
getClient()->getShape(info.m_x, info.m_y, info.m_w, info.m_h); 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(); info.m_zoneSize = getClient()->getJumpZoneSize();
// send it // send it

View File

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

View File

@ -1,8 +1,9 @@
#include "CXWindowsSecondaryScreen.h" #include "CXWindowsSecondaryScreen.h"
#include "IScreenReceiver.h"
#include "CXWindowsClipboard.h" #include "CXWindowsClipboard.h"
#include "CXWindowsScreen.h"
#include "CXWindowsScreenSaver.h" #include "CXWindowsScreenSaver.h"
#include "CXWindowsUtil.h" #include "CXWindowsUtil.h"
#include "IScreenReceiver.h"
#include "XScreen.h" #include "XScreen.h"
#include "CThread.h" #include "CThread.h"
#include "CLog.h" #include "CLog.h"
@ -26,153 +27,16 @@
// //
CXWindowsSecondaryScreen::CXWindowsSecondaryScreen(IScreenReceiver* receiver) : CXWindowsSecondaryScreen::CXWindowsSecondaryScreen(IScreenReceiver* receiver) :
m_receiver(receiver), CSecondaryScreen(),
m_window(None), m_window(None)
m_active(false)
{ {
assert(m_receiver != NULL); m_screen = new CXWindowsScreen(receiver, this);
} }
CXWindowsSecondaryScreen::~CXWindowsSecondaryScreen() CXWindowsSecondaryScreen::~CXWindowsSecondaryScreen()
{ {
assert(m_window == None); assert(m_window == None);
} delete m_screen;
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();
} }
void void
@ -236,7 +100,7 @@ CXWindowsSecondaryScreen::keyUp(KeyID key, KeyModifierMask mask)
void void
CXWindowsSecondaryScreen::mouseDown(ButtonID button) CXWindowsSecondaryScreen::mouseDown(ButtonID button)
{ {
CDisplayLock display(this); CDisplayLock display(m_screen);
XTestFakeButtonEvent(display, mapButton(button), True, CurrentTime); XTestFakeButtonEvent(display, mapButton(button), True, CurrentTime);
XSync(display, False); XSync(display, False);
} }
@ -244,7 +108,7 @@ CXWindowsSecondaryScreen::mouseDown(ButtonID button)
void void
CXWindowsSecondaryScreen::mouseUp(ButtonID button) CXWindowsSecondaryScreen::mouseUp(ButtonID button)
{ {
CDisplayLock display(this); CDisplayLock display(m_screen);
XTestFakeButtonEvent(display, mapButton(button), False, CurrentTime); XTestFakeButtonEvent(display, mapButton(button), False, CurrentTime);
XSync(display, False); XSync(display, False);
} }
@ -252,7 +116,6 @@ CXWindowsSecondaryScreen::mouseUp(ButtonID button)
void void
CXWindowsSecondaryScreen::mouseMove(SInt32 x, SInt32 y) CXWindowsSecondaryScreen::mouseMove(SInt32 x, SInt32 y)
{ {
CDisplayLock display(this);
warpCursor(x, y); warpCursor(x, y);
} }
@ -268,7 +131,7 @@ CXWindowsSecondaryScreen::mouseWheel(SInt32 delta)
} }
// send as many clicks as necessary // send as many clicks as necessary
CDisplayLock display(this); CDisplayLock display(m_screen);
for (; delta >= 120; delta -= 120) { for (; delta >= 120; delta -= 120) {
XTestFakeButtonEvent(display, button, True, CurrentTime); XTestFakeButtonEvent(display, button, True, CurrentTime);
XTestFakeButtonEvent(display, button, False, CurrentTime); XTestFakeButtonEvent(display, button, False, CurrentTime);
@ -276,63 +139,29 @@ CXWindowsSecondaryScreen::mouseWheel(SInt32 delta)
XSync(display, False); XSync(display, False);
} }
void IScreen*
CXWindowsSecondaryScreen::setClipboard(ClipboardID id, CXWindowsSecondaryScreen::getScreen() const
const IClipboard* clipboard)
{ {
setDisplayClipboard(id, clipboard); return m_screen;
} }
void void
CXWindowsSecondaryScreen::grabClipboard(ClipboardID id) CXWindowsSecondaryScreen::onScreensaver(bool)
{ {
setDisplayClipboard(id, NULL); // ignore
} }
void void
CXWindowsSecondaryScreen::screenSaver(bool activate) CXWindowsSecondaryScreen::onError()
{ {
CDisplayLock display(this); // ignore
if (activate) { // FIXME -- forward this? to whom?
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);
} }
bool bool
CXWindowsSecondaryScreen::onPreDispatch(const CEvent* event) CXWindowsSecondaryScreen::onPreDispatch(const CEvent*)
{ {
// forward to superclass return false;
return CXWindowsScreen::onPreDispatch(event);
} }
bool bool
@ -344,33 +173,117 @@ CXWindowsSecondaryScreen::onEvent(CEvent* event)
// handle event // handle event
switch (xevent.type) { switch (xevent.type) {
case MappingNotify: case MappingNotify:
{ // keyboard mapping changed
// keyboard mapping changed updateKeys();
CDisplayLock display(this);
XRefreshKeyboardMapping(&xevent.xmapping);
updateKeys(display);
updateKeycodeMap(display);
updateModifierMap(display);
updateModifiers(display);
}
return true; return true;
case LeaveNotify: case LeaveNotify:
{ // mouse moved out of hider window somehow. hide the window.
// mouse moved out of hider window somehow. hide the window. hideWindow();
assert(m_window != None);
CDisplayLock display(this);
hideWindow();
}
return true; return true;
} }
} }
void void
CXWindowsSecondaryScreen::onLostClipboard(ClipboardID id) CXWindowsSecondaryScreen::onPreRun()
{ {
// tell client that the clipboard was grabbed locally assert(m_window != None);
m_receiver->onGrabClipboard(id); }
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 void
@ -380,106 +293,55 @@ CXWindowsSecondaryScreen::showWindow()
// somewhere else on the screen) // somewhere else on the screen)
SInt32 x, y; SInt32 x, y;
getCursorPos(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. // raise and show the hider window. take activation.
// FIXME -- take focus? // FIXME -- take focus?
XMapRaised(getDisplay(), m_window); XMapRaised(display, m_window);
/* XXX -- this should have no effect /* XXX -- this should have no effect
// hide cursor by moving it into the hider window // 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 void
CXWindowsSecondaryScreen::hideWindow() CXWindowsSecondaryScreen::hideWindow()
{ {
XUnmapWindow(getDisplay(), m_window); assert(m_window != None);
CDisplayLock display(m_screen);
XUnmapWindow(display, m_window);
} }
void void
CXWindowsSecondaryScreen::warpCursor(SInt32 x, SInt32 y) CXWindowsSecondaryScreen::warpCursor(SInt32 x, SInt32 y)
{ {
XTestFakeMotionEvent(getDisplay(), getScreen(), x, y, CurrentTime); CDisplayLock display(m_screen);
XSync(getDisplay(), False); Display* pDisplay = display;
XTestFakeMotionEvent(display, DefaultScreen(pDisplay), x, y, CurrentTime);
XSync(display, False);
} }
void void
CXWindowsSecondaryScreen::checkClipboard() CXWindowsSecondaryScreen::setToggleState(KeyModifierMask mask)
{ {
// do nothing, we're always up to date CDisplayLock display(m_screen);
}
void // toggle modifiers that don't match the desired state
CXWindowsSecondaryScreen::createWindow() unsigned int xMask = maskToX(mask);
{ if ((xMask & m_capsLockMask) != (m_mask & m_capsLockMask)) {
CDisplayLock display(this); toggleKey(display, XK_Caps_Lock, m_capsLockMask);
// 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();
} }
if ((xMask & m_numLockMask) != (m_mask & m_numLockMask)) {
// cursor hider window attributes. this window is used to hide the toggleKey(display, XK_Num_Lock, m_numLockMask);
// 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();
} }
log((CLOG_DEBUG "window is 0x%08x", m_window)); if ((xMask & m_scrollLockMask) != (m_mask & m_scrollLockMask)) {
toggleKey(display, XK_Scroll_Lock, m_scrollLockMask);
// 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;
}
} }
} }
void
CXWindowsSecondaryScreen::installScreenSaver()
{
getScreenSaver()->disable();
}
void
CXWindowsSecondaryScreen::uninstallScreenSaver()
{
getScreenSaver()->enable();
}
unsigned int unsigned int
CXWindowsSecondaryScreen::mapButton(ButtonID id) const CXWindowsSecondaryScreen::mapButton(ButtonID id) const
{ {
@ -848,7 +710,7 @@ CXWindowsSecondaryScreen::doKeystrokes(const Keystrokes& keys, SInt32 count)
} }
// lock display // lock display
CDisplayLock display(this); CDisplayLock display(m_screen);
// generate key events // generate key events
for (Keystrokes::const_iterator k = keys.begin(); k != keys.end(); ) { for (Keystrokes::const_iterator k = keys.begin(); k != keys.end(); ) {
@ -910,27 +772,24 @@ CXWindowsSecondaryScreen::maskToX(KeyModifierMask inMask) const
} }
void void
CXWindowsSecondaryScreen::releaseKeys() CXWindowsSecondaryScreen::releaseKeys(Display* display)
{ {
CDisplayLock display(this); assert(display != NULL);
if (display != NULL) { // key up for each key that's down
// key up for each key that's down for (UInt32 i = 0; i < 256; ++i) {
for (UInt32 i = 0; i < 256; ++i) { if (m_keys[i]) {
if (m_keys[i]) { XTestFakeKeyEvent(display, i, False, CurrentTime);
XTestFakeKeyEvent(display, i, False, CurrentTime); m_keys[i] = false;
m_keys[i] = false;
}
} }
// update
XSync(display, False);
} }
} }
void void
CXWindowsSecondaryScreen::updateKeys(Display* display) CXWindowsSecondaryScreen::updateKeys()
{ {
CDisplayLock display(m_screen);
// ask server which keys are pressed // ask server which keys are pressed
char keys[32]; char keys[32];
XQueryKeymap(display, keys); XQueryKeymap(display, keys);
@ -946,6 +805,11 @@ CXWindowsSecondaryScreen::updateKeys(Display* display)
m_keys[j + 6] = ((keys[i] & 0x40) != 0); m_keys[j + 6] = ((keys[i] & 0x40) != 0);
m_keys[j + 7] = ((keys[i] & 0x80) != 0); m_keys[j + 7] = ((keys[i] & 0x80) != 0);
} }
// update mappings and current modifiers
updateKeycodeMap(display);
updateModifierMap(display);
updateModifiers(display);
} }
void void

View File

@ -1,47 +1,55 @@
#ifndef CXWINDOWSSECONDARYSCREEN_H #ifndef CXWINDOWSSECONDARYSCREEN_H
#define CXWINDOWSSECONDARYSCREEN_H #define CXWINDOWSSECONDARYSCREEN_H
#include "CXWindowsScreen.h" #include "CSecondaryScreen.h"
#include "ISecondaryScreen.h" #include "IScreenEventHandler.h"
#include "stdmap.h" #include "stdmap.h"
#include "stdvector.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 IScreenReceiver;
class CXWindowsSecondaryScreen : public CXWindowsScreen, class CXWindowsSecondaryScreen :
public ISecondaryScreen { public CSecondaryScreen, public IScreenEventHandler {
public: public:
CXWindowsSecondaryScreen(IScreenReceiver*); CXWindowsSecondaryScreen(IScreenReceiver*);
virtual ~CXWindowsSecondaryScreen(); virtual ~CXWindowsSecondaryScreen();
// ISecondaryScreen overrides // CSecondaryScreen overrides
virtual void run();
virtual void stop();
virtual void open();
virtual void close();
virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute,
KeyModifierMask mask);
virtual void leave();
virtual void keyDown(KeyID, KeyModifierMask); virtual void keyDown(KeyID, KeyModifierMask);
virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count); virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count);
virtual void keyUp(KeyID, KeyModifierMask); virtual void keyUp(KeyID, KeyModifierMask);
virtual void mouseDown(ButtonID); virtual void mouseDown(ButtonID);
virtual void mouseUp(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 mouseWheel(SInt32 delta);
virtual void setClipboard(ClipboardID, const IClipboard*); virtual IScreen* getScreen() const;
virtual void grabClipboard(ClipboardID);
virtual void screenSaver(bool activate);
virtual void getMousePos(SInt32& x, SInt32& y) const;
virtual void getShape(SInt32&, SInt32&, SInt32&, SInt32&) const;
virtual SInt32 getJumpZoneSize() const;
virtual void getClipboard(ClipboardID, IClipboard*) const;
protected: // IScreenEventHandler overrides
// CXWindowsScreen overrides virtual void onError();
virtual void onScreensaver(bool activated);
virtual bool onPreDispatch(const CEvent* event); virtual bool onPreDispatch(const CEvent* event);
virtual bool onEvent(CEvent* event); virtual bool onEvent(CEvent* event);
virtual 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: private:
enum EKeyAction { kPress, kRelease, kRepeat }; enum EKeyAction { kPress, kRelease, kRepeat };
@ -62,26 +70,6 @@ private:
typedef std::map<KeyID, KeyCodeMask> KeyCodeMap; typedef std::map<KeyID, KeyCodeMask> KeyCodeMap;
typedef std::map<KeyCode, unsigned int> ModifierMap; 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 mapButton(ButtonID button) const;
unsigned int mapKey(Keystrokes&, KeyCode&, KeyID, unsigned int mapKey(Keystrokes&, KeyCode&, KeyID,
@ -91,8 +79,7 @@ private:
void doKeystrokes(const Keystrokes&, SInt32 count); void doKeystrokes(const Keystrokes&, SInt32 count);
unsigned int maskToX(KeyModifierMask) const; unsigned int maskToX(KeyModifierMask) const;
void releaseKeys(); void releaseKeys(Display*);
void updateKeys(Display* display);
void updateKeycodeMap(Display* display); void updateKeycodeMap(Display* display);
void updateModifiers(Display* display); void updateModifiers(Display* display);
void updateModifierMap(Display* display); void updateModifierMap(Display* display);
@ -100,12 +87,9 @@ private:
static bool isToggleKeysym(KeySym); static bool isToggleKeysym(KeySym);
private: private:
IScreenReceiver* m_receiver; CXWindowsScreen* m_screen;
Window m_window; 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 // note toggle keys that toggles on up/down (false) or on
// transition (true) // transition (true)
bool m_numLockHalfDuplex; 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 bin_PROGRAMS = synergy
synergy_SOURCES = \ synergy_SOURCES = \
CClient.cpp \ CClient.cpp \
CSecondaryScreen.cpp \
CServerProxy.cpp \ CServerProxy.cpp \
CXWindowsSecondaryScreen.cpp \ CXWindowsSecondaryScreen.cpp \
client.cpp \ client.cpp \
CClient.h \ CClient.h \
CSecondaryScreen.h \
CServerProxy.h \ CServerProxy.h \
CXWindowsSecondaryScreen.h \ CXWindowsSecondaryScreen.h \
ISecondaryScreen.h \
$(NULL) $(NULL)
synergy_LDADD = \ synergy_LDADD = \
$(DEPTH)/platform/libplatform.a \ $(DEPTH)/platform/libplatform.a \

View File

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

View File

@ -3,14 +3,22 @@
#include "CXWindowsScreenSaver.h" #include "CXWindowsScreenSaver.h"
#include "CXWindowsUtil.h" #include "CXWindowsUtil.h"
#include "CClipboard.h" #include "CClipboard.h"
#include "IScreenEventHandler.h"
#include "IScreenReceiver.h"
#include "XScreen.h" #include "XScreen.h"
#include "CLock.h" #include "CLock.h"
#include "CThread.h" #include "CThread.h"
#include "CLog.h" #include "CLog.h"
#include "IJob.h" #include "IJob.h"
#include "CString.h" //#include "CString.h"
#include <cstdlib> //#include <cstdlib>
#include <cstring> #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 // CXWindowsScreen::CTimer
@ -68,15 +76,24 @@ CXWindowsScreen::CTimer::operator<(const CTimer& t) const
CXWindowsScreen* CXWindowsScreen::s_screen = NULL; CXWindowsScreen* CXWindowsScreen::s_screen = NULL;
CXWindowsScreen::CXWindowsScreen() : CXWindowsScreen::CXWindowsScreen(IScreenReceiver* receiver,
IScreenEventHandler* eventHandler) :
m_display(NULL), m_display(NULL),
m_root(None), m_root(None),
m_stop(false),
m_receiver(receiver),
m_eventHandler(eventHandler),
m_window(None),
m_x(0), m_y(0), m_x(0), m_y(0),
m_w(0), m_h(0), m_w(0), m_h(0),
m_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; s_screen = this;
} }
@ -120,6 +137,77 @@ CXWindowsScreen::removeTimerNoLock(IJob* job)
m_timers.swap(tmp); 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 void
CXWindowsScreen::mainLoop() CXWindowsScreen::mainLoop()
{ {
@ -147,7 +235,7 @@ CXWindowsScreen::mainLoop()
// have a go at it. // have a go at it.
m_mutex.unlock(); m_mutex.unlock();
if (!onPreDispatch(&event)) { if (!onPreDispatch(&event)) {
onEvent(&event); m_eventHandler->onEvent(&event);
} }
m_mutex.lock(); m_mutex.lock();
} }
@ -162,23 +250,210 @@ CXWindowsScreen::exitMainLoop()
m_stop = true; 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 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); assert(event != NULL);
const XEvent* xevent = &event->m_event; XEvent* xevent = &event->m_event;
switch (xevent->type) { switch (xevent->type) {
case MappingNotify:
// keyboard mapping changed
XRefreshKeyboardMapping(&xevent->xmapping);
// pass event on
break;
case SelectionClear: case SelectionClear:
{ {
// we just lost the selection. that means someone else // we just lost the selection. that means someone else
// grabbed the selection so this screen is now the // 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); ClipboardID id = getClipboardID(xevent->xselectionclear.selection);
if (id != kClipboardEnd) { if (id != kClipboardEnd) {
log((CLOG_DEBUG "lost clipboard %d ownership at time %d", id, xevent->xselectionclear.time)); log((CLOG_DEBUG "lost clipboard %d ownership at time %d", id, xevent->xselectionclear.time));
m_clipboard[id]->lost(xevent->xselectionclear.time); m_clipboard[id]->lost(xevent->xselectionclear.time);
onLostClipboard(id); m_receiver->onGrabClipboard(id);
return true; return true;
} }
} }
@ -225,6 +500,15 @@ CXWindowsScreen::onPreDispatch(const CEvent* event)
} }
break; 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: case DestroyNotify:
// looks like one of the windows that requested a clipboard // looks like one of the windows that requested a clipboard
// transfer has gone bye-bye. // transfer has gone bye-bye.
@ -237,150 +521,10 @@ CXWindowsScreen::onPreDispatch(const CEvent* event)
// let screen saver have a go // let screen saver have a go
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
m_screenSaver->onPreDispatch(xevent); m_screensaver->onPreDispatch(xevent);
} }
return false; return m_eventHandler->onPreDispatch(event);
}
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);
} }
void void
@ -417,30 +561,6 @@ CXWindowsScreen::createBlankCursor()
XFreePixmap(m_display, bitmap); 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 bool
CXWindowsScreen::processTimers() CXWindowsScreen::processTimers()
{ {
@ -486,62 +606,16 @@ CXWindowsScreen::processTimers()
} }
} }
CXWindowsScreenSaver* ClipboardID
CXWindowsScreen::getScreenSaver() const CXWindowsScreen::getClipboardID(Atom selection) const
{ {
return m_screenSaver; for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
} if (m_clipboard[id] != NULL &&
m_clipboard[id]->getSelection() == selection) {
bool return id;
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;
} }
m_clipboard[id]->empty();
m_clipboard[id]->close();
return true;
} }
} return kClipboardEnd;
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);
} }
void void
@ -584,17 +658,17 @@ CXWindowsScreen::ioErrorHandler(Display*)
// so we set it to NULL), and exit. // so we set it to NULL), and exit.
log((CLOG_WARN "X display has unexpectedly disconnected")); log((CLOG_WARN "X display has unexpectedly disconnected"));
s_screen->m_display = NULL; s_screen->m_display = NULL;
s_screen->onUnexpectedClose(); s_screen->m_eventHandler->onError();
log((CLOG_CRIT "quiting due to X display disconnection")); log((CLOG_CRIT "quiting due to X display disconnection"));
exit(17); exit(17);
} }
// //
// CXWindowsScreen::CDisplayLock // CDisplayLock
// //
CXWindowsScreen::CDisplayLock::CDisplayLock(const CXWindowsScreen* screen) : CDisplayLock::CDisplayLock(const CXWindowsScreen* screen) :
m_mutex(&screen->m_mutex), m_mutex(&screen->m_mutex),
m_display(screen->m_display) m_display(screen->m_display)
{ {
@ -603,12 +677,12 @@ CXWindowsScreen::CDisplayLock::CDisplayLock(const CXWindowsScreen* screen) :
m_mutex->lock(); m_mutex->lock();
} }
CXWindowsScreen::CDisplayLock::~CDisplayLock() CDisplayLock::~CDisplayLock()
{ {
m_mutex->unlock(); m_mutex->unlock();
} }
CXWindowsScreen::CDisplayLock::operator Display*() const CDisplayLock::operator Display*() const
{ {
return m_display; return m_display;
} }

View File

@ -1,6 +1,7 @@
#ifndef CXWINDOWSSCREEN_H #ifndef CXWINDOWSSCREEN_H
#define CXWINDOWSSCREEN_H #define CXWINDOWSSCREEN_H
#include "IScreen.h"
#include "ClipboardTypes.h" #include "ClipboardTypes.h"
#include "CMutex.h" #include "CMutex.h"
#include "CStopwatch.h" #include "CStopwatch.h"
@ -13,9 +14,9 @@
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
class IClipboard;
class IJob; class IJob;
class IScreenSaver; class IScreenEventHandler;
class IScreenReceiver;
class CXWindowsClipboard; class CXWindowsClipboard;
class CXWindowsScreenSaver; class CXWindowsScreenSaver;
@ -25,9 +26,9 @@ public:
SInt32 m_result; SInt32 m_result;
}; };
class CXWindowsScreen { class CXWindowsScreen : public IScreen {
public: public:
CXWindowsScreen(); CXWindowsScreen(IScreenReceiver*, IScreenEventHandler*);
virtual ~CXWindowsScreen(); virtual ~CXWindowsScreen();
// manipulators // manipulators
@ -39,94 +40,41 @@ public:
void addTimer(IJob*, double timeout); void addTimer(IJob*, double timeout);
void removeTimer(IJob*); void removeTimer(IJob*);
protected: // set the window (created by the subclass). this performs some
class CDisplayLock { // initialization and saves the window in case it's needed later.
public: void setWindow(Window);
CDisplayLock(const CXWindowsScreen*);
~CDisplayLock();
operator Display*() const; // accessors
private: // get the root window of the screen
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;
Window getRoot() const; 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 // get a cursor that is transparent everywhere
Cursor getBlankCursor() const; Cursor getBlankCursor() const;
// set the contents of the clipboard (i.e. primary selection) // IScreen overrides
bool setDisplayClipboard(ClipboardID, void open();
const IClipboard* clipboard); void mainLoop();
void exitMainLoop();
// copy the clipboard contents to clipboard void close();
bool getDisplayClipboard(ClipboardID, bool setClipboard(ClipboardID, const IClipboard*);
IClipboard* clipboard) const; void checkClipboards();
void openScreenSaver(bool notify);
// get the screen saver object void closeScreenSaver();
CXWindowsScreenSaver* void screensaver(bool activate);
getScreenSaver() const; void syncDesktop();
bool getClipboard(ClipboardID, IClipboard*) const;
// called for each event before event translation and dispatch. return void getShape(SInt32&, SInt32&, SInt32&, SInt32&) const;
// true to skip translation and dispatch. subclasses should call the void getCursorPos(SInt32&, SInt32&) const;
// superclass's version first and return true if it returns true. void getCursorCenter(SInt32&, SInt32&) const;
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;
private: private:
// update screen size cache
void updateScreenShape();
// process events before dispatching to receiver
bool onPreDispatch(CEvent* event);
// create the transparent cursor // create the transparent cursor
void createBlankCursor(); void createBlankCursor();
@ -255,14 +203,23 @@ private:
}; };
private: private:
friend class CDisplayLock;
typedef CPriorityQueue<CTimer> CTimerPriorityQueue; typedef CPriorityQueue<CTimer> CTimerPriorityQueue;
// X is not thread safe
CMutex m_mutex;
Display* m_display; Display* m_display;
int m_screen;
Window m_root; Window m_root;
bool m_stop;
IScreenReceiver* m_receiver;
IScreenEventHandler* m_eventHandler;
Window m_window;
SInt32 m_x, m_y; SInt32 m_x, m_y;
SInt32 m_w, m_h; SInt32 m_w, m_h;
bool m_stop;
// clipboards // clipboards
CXWindowsClipboard* m_clipboard[kClipboardEnd]; CXWindowsClipboard* m_clipboard[kClipboardEnd];
@ -270,20 +227,31 @@ private:
// the transparent cursor // the transparent cursor
Cursor m_cursor; Cursor m_cursor;
// screen saver // screen saver stuff
CXWindowsScreenSaver* m_screenSaver; CXWindowsScreenSaver* m_screensaver;
bool m_screensaverNotify;
Atom m_atomScreensaver;
// timers, the stopwatch used to time, and a mutex for the timers // timers, the stopwatch used to time, and a mutex for the timers
CTimerPriorityQueue m_timers; CTimerPriorityQueue m_timers;
CStopwatch m_time; CStopwatch m_time;
CMutex m_timersMutex; CMutex m_timersMutex;
// X is not thread safe
CMutex m_mutex;
// pointer to (singleton) screen. this is only needed by // pointer to (singleton) screen. this is only needed by
// ioErrorHandler(). // ioErrorHandler().
static CXWindowsScreen* s_screen; static CXWindowsScreen* s_screen;
}; };
class CDisplayLock {
public:
CDisplayLock(const CXWindowsScreen*);
~CDisplayLock();
operator Display*() const;
private:
const CMutex* m_mutex;
Display* m_display;
};
#endif #endif

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
#include "CPrimaryClient.h" #include "CPrimaryClient.h"
#include "IServer.h" #include "IServer.h"
#include "IPrimaryScreen.h" #include "CPrimaryScreen.h"
#include "CClipboard.h" #include "CClipboard.h"
#include "CLog.h" #include "CLog.h"
@ -15,7 +15,8 @@
// CPrimaryClient // CPrimaryClient
// //
CPrimaryClient::CPrimaryClient(IServer* server, const CString& name) : CPrimaryClient::CPrimaryClient(IServer* server,
IPrimaryScreenReceiver* receiver, const CString& name) :
m_server(server), m_server(server),
m_name(name), m_name(name),
m_seqNum(0) m_seqNum(0)
@ -25,9 +26,9 @@ CPrimaryClient::CPrimaryClient(IServer* server, const CString& name) :
// create screen // create screen
log((CLOG_DEBUG1 "creating primary screen")); log((CLOG_DEBUG1 "creating primary screen"));
#if WINDOWS_LIKE #if WINDOWS_LIKE
m_screen = new CMSWindowsPrimaryScreen(this, m_server); m_screen = new CMSWindowsPrimaryScreen(this, receiver);
#elif UNIX_LIKE #elif UNIX_LIKE
m_screen = new CXWindowsPrimaryScreen(this, m_server); m_screen = new CXWindowsPrimaryScreen(this, receiver);
#endif #endif
} }
@ -211,7 +212,7 @@ CPrimaryClient::mouseWheel(SInt32)
} }
void void
CPrimaryClient::screenSaver(bool) CPrimaryClient::screensaver(bool)
{ {
// ignore // ignore
} }
@ -222,6 +223,12 @@ CPrimaryClient::getName() const
return m_name; return m_name;
} }
SInt32
CPrimaryClient::getJumpZoneSize() const
{
return m_info.m_zoneSize;
}
void void
CPrimaryClient::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const 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 void
CPrimaryClient::getCenter(SInt32& x, SInt32& y) const CPrimaryClient::getCursorPos(SInt32&, SInt32&) const
{
x = m_info.m_mx;
y = m_info.m_my;
}
void
CPrimaryClient::getMousePos(SInt32&, SInt32&) const
{ {
assert(0 && "shouldn't be called"); assert(0 && "shouldn't be called");
} }
SInt32 void
CPrimaryClient::getJumpZoneSize() const 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" #include "ProtocolTypes.h"
class IClipboard; class IClipboard;
class IPrimaryScreen; class CPrimaryScreen;
class IPrimaryScreenReceiver;
class IServer; class IServer;
class CPrimaryClient : public IScreenReceiver, public IClient { class CPrimaryClient : public IScreenReceiver, public IClient {
public: public:
CPrimaryClient(IServer*, const CString& name); CPrimaryClient(IServer*, IPrimaryScreenReceiver*, const CString& name);
~CPrimaryClient(); ~CPrimaryClient();
// manipulators // manipulators
@ -44,7 +45,7 @@ public:
virtual void close(); virtual void close();
virtual void enter(SInt32 xAbs, SInt32 yAbs, virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask, UInt32 seqNum, KeyModifierMask mask,
bool screenSaver); bool forScreensaver);
virtual bool leave(); virtual bool leave();
virtual void setClipboard(ClipboardID, const CString&); virtual void setClipboard(ClipboardID, const CString&);
virtual void grabClipboard(ClipboardID); virtual void grabClipboard(ClipboardID);
@ -56,17 +57,17 @@ public:
virtual void mouseUp(ButtonID); virtual void mouseUp(ButtonID);
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs); virtual void mouseMove(SInt32 xAbs, SInt32 yAbs);
virtual void mouseWheel(SInt32 delta); virtual void mouseWheel(SInt32 delta);
virtual void screenSaver(bool activate); virtual void screensaver(bool activate);
virtual CString getName() const; virtual CString getName() const;
virtual SInt32 getJumpZoneSize() const;
virtual void getShape(SInt32& x, SInt32& y, virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const; SInt32& width, SInt32& height) const;
virtual void getCenter(SInt32& x, SInt32& y) const; virtual void getCursorPos(SInt32& x, SInt32& y) const;
virtual void getMousePos(SInt32& x, SInt32& y) const; virtual void getCursorCenter(SInt32& x, SInt32& y) const;
virtual SInt32 getJumpZoneSize() const;
private: private:
IServer* m_server; IServer* m_server;
IPrimaryScreen* m_screen; CPrimaryScreen* m_screen;
CString m_name; CString m_name;
UInt32 m_seqNum; UInt32 m_seqNum;
CClientInfo m_info; 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 // handle events
log((CLOG_DEBUG "starting event handling"));
m_primaryClient->run(); m_primaryClient->run();
// clean up // clean up
@ -108,9 +107,6 @@ CServer::run()
stopThreads(); \ stopThreads(); \
delete m_httpServer; \ delete m_httpServer; \
m_httpServer = NULL; \ m_httpServer = NULL; \
if (m_primaryClient != NULL) { \
closePrimaryScreen(); \
} \
} while (false) } while (false)
FINALLY; FINALLY;
} }
@ -144,6 +140,15 @@ CServer::quit()
m_primaryClient->stop(); m_primaryClient->stop();
} }
void
CServer::close()
{
if (m_primaryClient != NULL) {
closePrimaryScreen();
}
log((CLOG_INFO "closed screen"));
}
bool bool
CServer::setConfig(const CConfig& config) CServer::setConfig(const CConfig& config)
{ {
@ -211,20 +216,6 @@ CServer::getActivePrimarySides() const
return sides; 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 void
CServer::onInfoChanged(const CString& name, const CClientInfo& info) 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); m_active->setClipboard(id, m_clipboards[id].m_clipboardData);
} }
bool void
CServer::onCommandKey(KeyID /*id*/, KeyModifierMask /*mask*/, bool /*down*/) 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 void
@ -615,60 +670,10 @@ CServer::onMouseWheel(SInt32 delta)
m_active->mouseWheel(delta); m_active->mouseWheel(delta);
} }
void bool
CServer::onScreenSaver(bool activated) CServer::onCommandKey(KeyID /*id*/, KeyModifierMask /*mask*/, bool /*down*/)
{ {
log((CLOG_DEBUG "onScreenSaver %s", activated ? "activated" : "deactivated")); return false;
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);
}
} }
bool bool
@ -689,7 +694,7 @@ CServer::isLockedToScreenNoLock() const
} }
void void
CServer::switchScreen(IClient* dst, SInt32 x, SInt32 y, bool screenSaver) CServer::switchScreen(IClient* dst, SInt32 x, SInt32 y, bool forScreensaver)
{ {
assert(dst != NULL); assert(dst != NULL);
#ifndef NDEBUG #ifndef NDEBUG
@ -741,7 +746,8 @@ CServer::switchScreen(IClient* dst, SInt32 x, SInt32 y, bool screenSaver)
// enter new screen // enter new screen
m_active->enter(x, y, m_seqNum, m_active->enter(x, y, m_seqNum,
m_primaryClient->getToggleMask(), screenSaver); m_primaryClient->getToggleMask(),
forScreensaver);
// send the clipboard data to new active screen // send the clipboard data to new active screen
for (ClipboardID id = 0; id < kClipboardEnd; ++id) { for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
@ -1209,7 +1215,7 @@ CServer::runClient(void* vsocket)
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
if (m_activeSaver != NULL) { if (m_activeSaver != NULL) {
proxy->screenSaver(true); proxy->screensaver(true);
} }
} }
@ -1510,7 +1516,7 @@ CServer::openPrimaryScreen()
// create the primary client and open it // create the primary client and open it
try { try {
m_primaryClient = new CPrimaryClient(this, primary); m_primaryClient = new CPrimaryClient(this, this, primary);
// add connection // add connection
addConnection(m_primaryClient); addConnection(m_primaryClient);
@ -1593,7 +1599,7 @@ CServer::removeConnection(const CString& name)
IClient* active = (m_activeSaver != NULL) ? m_activeSaver : m_active; IClient* active = (m_activeSaver != NULL) ? m_activeSaver : m_active;
if (active == index->second && active != m_primaryClient) { if (active == index->second && active != m_primaryClient) {
// record new position (center of primary screen) // 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 // 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)); 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 #define CSERVER_H
#include "IServer.h" #include "IServer.h"
#include "IPrimaryScreenReceiver.h"
#include "CConfig.h" #include "CConfig.h"
#include "CClipboard.h" #include "CClipboard.h"
#include "CCondVar.h" #include "CCondVar.h"
@ -20,7 +21,7 @@ class IServerProtocol;
class ISocketFactory; class ISocketFactory;
class ISecurityFactory; class ISecurityFactory;
class CServer : public IServer { class CServer : public IServer, public IPrimaryScreenReceiver {
public: public:
CServer(const CString& serverName); CServer(const CString& serverName);
~CServer(); ~CServer();
@ -38,6 +39,9 @@ public:
// after a successful open(). // after a successful open().
void quit(); void quit();
// close the server's screen
void close();
// update screen map. returns true iff the new configuration was // update screen map. returns true iff the new configuration was
// accepted. // accepted.
bool setConfig(const CConfig&); bool setConfig(const CConfig&);
@ -50,8 +54,14 @@ public:
// get the primary screen's name // get the primary screen's name
CString getPrimaryScreenName() const; 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 // IPrimaryScreenReceiver overrides
virtual void onError(); virtual void onError();
virtual void onScreensaver(bool activated);
virtual void onKeyDown(KeyID, KeyModifierMask); virtual void onKeyDown(KeyID, KeyModifierMask);
virtual void onKeyUp(KeyID, KeyModifierMask); virtual void onKeyUp(KeyID, KeyModifierMask);
virtual void onKeyRepeat(KeyID, KeyModifierMask, SInt32 count); virtual void onKeyRepeat(KeyID, KeyModifierMask, SInt32 count);
@ -60,12 +70,6 @@ public:
virtual bool onMouseMovePrimary(SInt32 x, SInt32 y); virtual bool onMouseMovePrimary(SInt32 x, SInt32 y);
virtual void onMouseMoveSecondary(SInt32 dx, SInt32 dy); virtual void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
virtual void onMouseWheel(SInt32 delta); 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: protected:
bool onCommandKey(KeyID, KeyModifierMask, bool down); bool onCommandKey(KeyID, KeyModifierMask, bool down);

View File

@ -1,11 +1,7 @@
#include "CXWindowsPrimaryScreen.h" #include "CXWindowsPrimaryScreen.h"
#include "IScreenReceiver.h" #include "CXWindowsScreen.h"
#include "IPrimaryScreenReceiver.h"
#include "CXWindowsClipboard.h"
#include "CXWindowsScreenSaver.h"
#include "CXWindowsUtil.h" #include "CXWindowsUtil.h"
#include "CClipboard.h" #include "IPrimaryScreenReceiver.h"
#include "ProtocolTypes.h"
#include "XScreen.h" #include "XScreen.h"
#include "CThread.h" #include "CThread.h"
#include "CLog.h" #include "CLog.h"
@ -26,162 +22,17 @@
CXWindowsPrimaryScreen::CXWindowsPrimaryScreen( CXWindowsPrimaryScreen::CXWindowsPrimaryScreen(
IScreenReceiver* receiver, IScreenReceiver* receiver,
IPrimaryScreenReceiver* primaryReceiver) : IPrimaryScreenReceiver* primaryReceiver) :
m_receiver(receiver), CPrimaryScreen(receiver),
m_primaryReceiver(primaryReceiver), m_receiver(primaryReceiver),
m_active(false),
m_window(None) m_window(None)
{ {
// do nothing m_screen = new CXWindowsScreen(receiver, this);
} }
CXWindowsPrimaryScreen::~CXWindowsPrimaryScreen() CXWindowsPrimaryScreen::~CXWindowsPrimaryScreen()
{ {
assert(m_window == None); assert(m_window == None);
} delete m_screen;
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;
} }
void void
@ -193,7 +44,7 @@ CXWindowsPrimaryScreen::reconfigure(UInt32)
void void
CXWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y) CXWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y)
{ {
CDisplayLock display(this); CDisplayLock display(m_screen);
// warp mouse // warp mouse
warpCursorNoFlush(display, x, y); warpCursorNoFlush(display, x, y);
@ -213,30 +64,10 @@ CXWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y)
m_y = 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 KeyModifierMask
CXWindowsPrimaryScreen::getToggleMask() const CXWindowsPrimaryScreen::getToggleMask() const
{ {
CDisplayLock display(this); CDisplayLock display(m_screen);
// query the pointer to get the keyboard state // query the pointer to get the keyboard state
Window root, window; Window root, window;
@ -265,7 +96,7 @@ CXWindowsPrimaryScreen::getToggleMask() const
bool bool
CXWindowsPrimaryScreen::isLockedToScreen() const CXWindowsPrimaryScreen::isLockedToScreen() const
{ {
CDisplayLock display(this); CDisplayLock display(m_screen);
// query the pointer to get the button state // query the pointer to get the button state
Window root, window; Window root, window;
@ -295,11 +126,29 @@ CXWindowsPrimaryScreen::isLockedToScreen() const
return false; return false;
} }
bool IScreen*
CXWindowsPrimaryScreen::onPreDispatch(const CEvent* event) CXWindowsPrimaryScreen::getScreen() const
{ {
// forward to superclass return m_screen;
return CXWindowsScreen::onPreDispatch(event); }
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 bool
@ -313,41 +162,28 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event)
case CreateNotify: case CreateNotify:
{ {
// select events on new window // select events on new window
CDisplayLock display(this); CDisplayLock display(m_screen);
selectEvents(display, xevent.xcreatewindow.window); selectEvents(display, xevent.xcreatewindow.window);
} }
return true; return true;
case MappingNotify: case MappingNotify:
{ // keyboard mapping changed
// keyboard mapping changed updateKeys();
CDisplayLock display(this);
XRefreshKeyboardMapping(&xevent.xmapping);
updateModifierMap(display);
}
return true; 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: case KeyPress:
{ {
log((CLOG_DEBUG1 "event: KeyPress code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state)); log((CLOG_DEBUG1 "event: KeyPress code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state));
const KeyModifierMask mask = mapModifier(xevent.xkey.state); const KeyModifierMask mask = mapModifier(xevent.xkey.state);
const KeyID key = mapKey(&xevent.xkey); const KeyID key = mapKey(&xevent.xkey);
if (key != kKeyNone) { if (key != kKeyNone) {
m_primaryReceiver->onKeyDown(key, mask); m_receiver->onKeyDown(key, mask);
if (key == XK_Caps_Lock && m_capsLockHalfDuplex) { 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) { 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; filter.m_keycode = xevent.xkey.keycode;
// now check for event // now check for event
XEvent xevent2; bool hasPress;
CDisplayLock display(this); {
if (XCheckIfEvent(display, &xevent2, XEvent xevent2;
&CXWindowsPrimaryScreen::findKeyEvent, CDisplayLock display(m_screen);
(XPointer)&filter) != True) { hasPress = (XCheckIfEvent(display, &xevent2,
&CXWindowsPrimaryScreen::findKeyEvent,
(XPointer)&filter) == True);
}
if (!hasPress) {
// no press event follows so it's a plain release // 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)); log((CLOG_DEBUG1 "event: KeyRelease code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state));
if (key == XK_Caps_Lock && m_capsLockHalfDuplex) { 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) { 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 { else {
// found a press event following so it's a repeat. // 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. // repeats but we'll just send a repeat of 1.
// note that we discard the press event. // note that we discard the press event.
log((CLOG_DEBUG1 "event: repeat code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state)); 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)); log((CLOG_DEBUG1 "event: ButtonPress button=%d", xevent.xbutton.button));
const ButtonID button = mapButton(xevent.xbutton.button); const ButtonID button = mapButton(xevent.xbutton.button);
if (button != kButtonNone) { if (button != kButtonNone) {
m_primaryReceiver->onMouseDown(button); m_receiver->onMouseDown(button);
} }
} }
return true; return true;
@ -411,15 +251,15 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event)
log((CLOG_DEBUG1 "event: ButtonRelease button=%d", xevent.xbutton.button)); log((CLOG_DEBUG1 "event: ButtonRelease button=%d", xevent.xbutton.button));
const ButtonID button = mapButton(xevent.xbutton.button); const ButtonID button = mapButton(xevent.xbutton.button);
if (button != kButtonNone) { if (button != kButtonNone) {
m_primaryReceiver->onMouseUp(button); m_receiver->onMouseUp(button);
} }
else if (xevent.xbutton.button == 4) { else if (xevent.xbutton.button == 4) {
// wheel forward (away from user) // wheel forward (away from user)
m_primaryReceiver->onMouseWheel(120); m_receiver->onMouseWheel(120);
} }
else if (xevent.xbutton.button == 5) { else if (xevent.xbutton.button == 5) {
// wheel backward (toward user) // wheel backward (toward user)
m_primaryReceiver->onMouseWheel(-120); m_receiver->onMouseWheel(-120);
} }
} }
return true; return true;
@ -443,14 +283,14 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event)
// warpCursorNoFlush() for where the events are // warpCursorNoFlush() for where the events are
// sent. we discard the matching sent event and // sent. we discard the matching sent event and
// can be sure we've skipped the warp event. // can be sure we've skipped the warp event.
CDisplayLock display(this); CDisplayLock display(m_screen);
do { do {
XMaskEvent(display, PointerMotionMask, &xevent); XMaskEvent(display, PointerMotionMask, &xevent);
} while (!xevent.xmotion.send_event); } while (!xevent.xmotion.send_event);
} }
else if (!m_active) { else if (!isActive()) {
// motion on primary screen // motion on primary screen
m_primaryReceiver->onMouseMovePrimary(m_x, m_y); m_receiver->onMouseMovePrimary(m_x, m_y);
} }
else { else {
// motion on secondary screen. warp mouse back to // 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.x_root - m_xCenter > s_size ||
xevent.xmotion.y_root - m_yCenter < -s_size || xevent.xmotion.y_root - m_yCenter < -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); warpCursorNoFlush(display, m_xCenter, m_yCenter);
} }
@ -481,7 +321,7 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event)
// warping to the primary screen's enter position, // warping to the primary screen's enter position,
// effectively overriding it. // effectively overriding it.
if (x != 0 || y != 0) { if (x != 0 || y != 0) {
m_primaryReceiver->onMouseMoveSecondary(x, y); m_receiver->onMouseMoveSecondary(x, y);
} }
} }
} }
@ -492,77 +332,117 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event)
} }
void 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); 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 void
CXWindowsPrimaryScreen::enterNoWarp() CXWindowsPrimaryScreen::onPreOpen()
{ {
m_active = false; assert(m_window == None);
hideWindow(); }
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 bool
CXWindowsPrimaryScreen::showWindow() CXWindowsPrimaryScreen::showWindow()
{ {
CDisplayLock display(this); assert(m_window != None);
CDisplayLock display(m_screen);
// raise and show the input window // raise and show the input window
XMapRaised(display, m_window); XMapRaised(display, m_window);
@ -616,83 +496,51 @@ CXWindowsPrimaryScreen::showWindow()
void void
CXWindowsPrimaryScreen::hideWindow() CXWindowsPrimaryScreen::hideWindow()
{ {
CDisplayLock display(this); CDisplayLock display(m_screen);
// unmap the grab window. this also ungrabs the mouse and keyboard. // unmap the grab window. this also ungrabs the mouse and keyboard.
XUnmapWindow(display, m_window); XUnmapWindow(display, m_window);
} }
void void
CXWindowsPrimaryScreen::checkClipboard() CXWindowsPrimaryScreen::warpCursorToCenter()
{ {
// do nothing, we're always up to date warpCursor(m_xCenter, m_yCenter);
} }
void 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 // send an event that we can recognize before the mouse warp
SInt32 x, y, w, h; XEvent eventBefore;
getScreenShape(x, y, w, h); 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 // warp mouse
// input when the user is focused on another client. don't let XWarpPointer(display, None, m_screen->getRoot(), 0, 0, 0, 0, x, y);
// 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();
// create the grab window // send an event that we can recognize after the mouse warp
CDisplayLock display(this); XSendEvent(display, m_window, False, 0, &eventAfter);
m_window = XCreateWindow(display, getRoot(), XSync(display, False);
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 log((CLOG_DEBUG2 "warped to %d,%d", x, y));
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;
} }
void void
@ -777,7 +625,7 @@ CXWindowsPrimaryScreen::mapKey(XKeyEvent* event) const
KeySym keysym; KeySym keysym;
char dummy[1]; char dummy[1];
CDisplayLock display(this); CDisplayLock display(m_screen);
XLookupString(event, dummy, 0, &keysym, NULL); XLookupString(event, dummy, 0, &keysym, NULL);
return static_cast<KeyID>(keysym); return static_cast<KeyID>(keysym);
} }
@ -795,8 +643,10 @@ CXWindowsPrimaryScreen::mapButton(unsigned int button) const
} }
void void
CXWindowsPrimaryScreen::updateModifierMap(Display* display) CXWindowsPrimaryScreen::updateKeys()
{ {
CDisplayLock display(m_screen);
// get modifier map from server // get modifier map from server
XModifierKeymap* keymap = XGetModifierMapping(display); XModifierKeymap* keymap = XGetModifierMapping(display);

View File

@ -1,63 +1,59 @@
#ifndef CXWINDOWSPRIMARYSCREEN_H #ifndef CXWINDOWSPRIMARYSCREEN_H
#define CXWINDOWSPRIMARYSCREEN_H #define CXWINDOWSPRIMARYSCREEN_H
#include "CXWindowsScreen.h" #include "CPrimaryScreen.h"
#include "IPrimaryScreen.h" #include "IScreenEventHandler.h"
#include "MouseTypes.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 IScreenReceiver;
class IPrimaryScreenReceiver; class IPrimaryScreenReceiver;
class CXWindowsPrimaryScreen : public CXWindowsScreen, public IPrimaryScreen { class CXWindowsPrimaryScreen :
public CPrimaryScreen, public IScreenEventHandler {
public: public:
CXWindowsPrimaryScreen(IScreenReceiver*, IPrimaryScreenReceiver*); CXWindowsPrimaryScreen(IScreenReceiver*, IPrimaryScreenReceiver*);
virtual ~CXWindowsPrimaryScreen(); virtual ~CXWindowsPrimaryScreen();
// IPrimaryScreen overrides // CPrimaryScreen overrides
virtual void run();
virtual void stop();
virtual void open();
virtual void close();
virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute, bool);
virtual bool leave();
virtual void reconfigure(UInt32 activeSides); virtual void reconfigure(UInt32 activeSides);
virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute); virtual void warpCursor(SInt32 x, SInt32 y);
virtual void setClipboard(ClipboardID, const IClipboard*);
virtual void grabClipboard(ClipboardID);
virtual void getClipboard(ClipboardID, IClipboard*) const;
virtual KeyModifierMask getToggleMask() const; virtual KeyModifierMask getToggleMask() const;
virtual bool isLockedToScreen() const; virtual bool isLockedToScreen() const;
virtual IScreen* getScreen() const;
protected: // IScreenEventHandler overrides
// CXWindowsScreen overrides virtual void onError();
virtual void onScreensaver(bool activated);
virtual bool onPreDispatch(const CEvent* event); virtual bool onPreDispatch(const CEvent* event);
virtual bool onEvent(CEvent* event); virtual bool onEvent(CEvent* event);
virtual 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: private:
SInt32 getJumpZoneSize() const;
void warpCursorToCenter();
void warpCursorNoFlush(Display*, void warpCursorNoFlush(Display*,
SInt32 xAbsolute, SInt32 yAbsolute); 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 selectEvents(Display*, Window) const;
void doSelectEvents(Display*, Window) const; void doSelectEvents(Display*, Window) const;
@ -65,8 +61,6 @@ private:
KeyID mapKey(XKeyEvent*) const; KeyID mapKey(XKeyEvent*) const;
ButtonID mapButton(unsigned int button) const; ButtonID mapButton(unsigned int button) const;
void updateModifierMap(Display* display);
class CKeyEventInfo { class CKeyEventInfo {
public: public:
int m_event; int m_event;
@ -77,15 +71,12 @@ private:
static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg); static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg);
private: private:
IScreenReceiver* m_receiver; CXWindowsScreen* m_screen;
IPrimaryScreenReceiver* m_primaryReceiver; IPrimaryScreenReceiver* m_receiver;
bool m_active; // our window
Window m_window; Window m_window;
// atom for screen saver messages
Atom m_atomScreenSaver;
// note toggle keys that toggle on up/down (false) or on // note toggle keys that toggle on up/down (false) or on
// transition (true) // transition (true)
bool m_numLockHalfDuplex; 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 \ CConfig.cpp \
CHTTPServer.cpp \ CHTTPServer.cpp \
CPrimaryClient.cpp \ CPrimaryClient.cpp \
CPrimaryScreen.cpp \
CServer.cpp \ CServer.cpp \
CXWindowsPrimaryScreen.cpp \ CXWindowsPrimaryScreen.cpp \
server.cpp \ server.cpp \
@ -17,9 +18,9 @@ synergyd_SOURCES = \
CConfig.h \ CConfig.h \
CHTTPServer.h \ CHTTPServer.h \
CPrimaryClient.h \ CPrimaryClient.h \
CPrimaryScreen.h \
CServer.h \ CServer.h \
CXWindowsPrimaryScreen.h \ CXWindowsPrimaryScreen.h \
IPrimaryScreen.h \
$(NULL) $(NULL)
synergyd_LDADD = \ synergyd_LDADD = \
$(DEPTH)/platform/libplatform.a \ $(DEPTH)/platform/libplatform.a \

View File

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

View File

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

View File

@ -5,12 +5,22 @@
#include "KeyTypes.h" #include "KeyTypes.h"
#include "MouseTypes.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 { class IPrimaryScreenReceiver : public IInterface {
public: public:
// notify of serious error. this implies that the server should // called if the display is unexpectedly closing.
// shutdown.
// 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; 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 // call to notify of events. onMouseMovePrimary() returns
// true iff the mouse enters a jump zone and jumps. // true iff the mouse enters a jump zone and jumps.
virtual void onKeyDown(KeyID, KeyModifierMask) = 0; virtual void onKeyDown(KeyID, KeyModifierMask) = 0;
@ -21,8 +31,6 @@ public:
virtual bool onMouseMovePrimary(SInt32 x, SInt32 y) = 0; virtual bool onMouseMovePrimary(SInt32 x, SInt32 y) = 0;
virtual void onMouseMoveSecondary(SInt32 dx, SInt32 dy) = 0; virtual void onMouseMoveSecondary(SInt32 dx, SInt32 dy) = 0;
virtual void onMouseWheel(SInt32 delta) = 0; virtual void onMouseWheel(SInt32 delta) = 0;
virtual void onScreenSaver(bool activated) = 0;
}; };
#endif #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 "ProtocolTypes.h"
#include "CString.h" #include "CString.h"
// the interface for types that receive screen resize and clipboard
// notifications (indirectly) from the system.
class IScreenReceiver : public IInterface { class IScreenReceiver : public IInterface {
public: public:
// notify of client info change // notify of client info change

View File

@ -1,13 +1,19 @@
#ifndef ISERVER_H #ifndef ISERVER_H
#define ISERVER_H #define ISERVER_H
#include "IPrimaryScreenReceiver.h" #include "IInterface.h"
#include "ClipboardTypes.h" #include "ClipboardTypes.h"
#include "CString.h" #include "CString.h"
class CClientInfo; 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: public:
// manipulators // manipulators
@ -23,18 +29,6 @@ public:
// notify of new clipboard data // notify of new clipboard data
virtual void onClipboardChanged(ClipboardID, virtual void onClipboardChanged(ClipboardID,
UInt32 seqNum, const CString& data) = 0; 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 #endif

View File

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