This commit is contained in:
Florian Hofhammer 2020-11-24 02:09:21 +00:00 committed by GitHub
commit 2876f35e48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 445 additions and 117 deletions

View File

@ -178,13 +178,11 @@ Screen::grabClipboard(ClipboardID id)
void void
Screen::screensaver(bool activate) Screen::screensaver(bool activate)
{ {
if (!m_isPrimary) {
// activate/deactivation screen saver iff synchronization enabled // activate/deactivation screen saver iff synchronization enabled
if (m_screenSaverSync) { if (m_screenSaverSync) {
m_screen->screensaver(activate); m_screen->screensaver(activate);
} }
} }
}
void void
Screen::keyDown(KeyID id, KeyModifierMask mask, KeyButton button) Screen::keyDown(KeyID id, KeyModifierMask mask, KeyButton button)

View File

@ -29,6 +29,7 @@ const char* kMsgCScreenSaver = "CSEC%1i";
const char* kMsgCResetOptions = "CROP"; const char* kMsgCResetOptions = "CROP";
const char* kMsgCInfoAck = "CIAK"; const char* kMsgCInfoAck = "CIAK";
const char* kMsgCKeepAlive = "CALV"; const char* kMsgCKeepAlive = "CALV";
const char* kMsgCLocalInput = "CLIN%2i%2i";
const char* kMsgDKeyDown = "DKDN%2i%2i%2i"; const char* kMsgDKeyDown = "DKDN%2i%2i%2i";
const char* kMsgDKeyDown1_0 = "DKDN%2i%2i"; const char* kMsgDKeyDown1_0 = "DKDN%2i%2i";
const char* kMsgDKeyRepeat = "DKRP%2i%2i%2i%2i"; const char* kMsgDKeyRepeat = "DKRP%2i%2i%2i%2i";

View File

@ -29,9 +29,11 @@
// 1.4: adds crypto support // 1.4: adds crypto support
// 1.5: adds file transfer and removes home brew crypto // 1.5: adds file transfer and removes home brew crypto
// 1.6: adds clipboard streaming // 1.6: adds clipboard streaming
// 1.7: adds focus/screen switch on local input
// adds screensaver sync on client local input
// NOTE: with new version, barrier minor version should increment // NOTE: with new version, barrier minor version should increment
static const SInt16 kProtocolMajorVersion = 1; static const SInt16 kProtocolMajorVersion = 1;
static const SInt16 kProtocolMinorVersion = 6; static const SInt16 kProtocolMinorVersion = 7;
// default contact port number // default contact port number
static const UInt16 kDefaultPort = 24800; static const UInt16 kDefaultPort = 24800;
@ -129,9 +131,16 @@ extern const char* kMsgCClose;
// must return this number with some messages. $4 = modifier key // must return this number with some messages. $4 = modifier key
// mask. this will have bits set for each toggle modifier key // mask. this will have bits set for each toggle modifier key
// that is activated on entry to the screen. the secondary screen // that is activated on entry to the screen. the secondary screen
// should adjust its toggle modifiers to reflect that state. // should adjust its toggle modifiers to reflect that state. $5 =
// forScreensaver flag which denotes whether the screen is only
// entered for screensaver management purposes or not and thus
// whether the client can change its screensaver state or should
// not change the screensaver state
extern const char* kMsgCEnter; extern const char* kMsgCEnter;
// enter screen 1.0: same as above but without respecting the screensaver state
extern const char* kMsgCEnter1_0;
// leave screen: primary -> secondary // leave screen: primary -> secondary
// leaving screen. the secondary screen should send clipboard // leaving screen. the secondary screen should send clipboard
// data in response to this message for those clipboards that // data in response to this message for those clipboards that
@ -148,8 +157,10 @@ extern const char* kMsgCLeave;
// most recent kMsgCEnter. the primary always sends 0. // most recent kMsgCEnter. the primary always sends 0.
extern const char* kMsgCClipboard; extern const char* kMsgCClipboard;
// screensaver change: primary -> secondary // screensaver change: primary <-> secondary
// screensaver on primary has started ($1 == 1) or closed ($1 == 0) // screensaver has started ($1 == 1) or closed ($1 == 0).
// sync screensavers by dispatching information to all clients via
// the server
extern const char* kMsgCScreenSaver; extern const char* kMsgCScreenSaver;
// reset options: primary -> secondary // reset options: primary -> secondary
@ -172,6 +183,10 @@ extern const char* kMsgCInfoAck;
// defined by an option. // defined by an option.
extern const char* kMsgCKeepAlive; extern const char* kMsgCKeepAlive;
// Local input: secondary -> primary
// Inform primary about local input to request focus
extern const char* kMsgCLocalInput;
// //
// data codes // data codes
// //

View File

@ -177,6 +177,7 @@ REGISTER_EVENT(IPrimaryScreen, fakeInputEnd)
REGISTER_EVENT(IScreen, error) REGISTER_EVENT(IScreen, error)
REGISTER_EVENT(IScreen, shapeChanged) REGISTER_EVENT(IScreen, shapeChanged)
REGISTER_EVENT(IScreen, localInput)
REGISTER_EVENT(IScreen, suspend) REGISTER_EVENT(IScreen, suspend)
REGISTER_EVENT(IScreen, resume) REGISTER_EVENT(IScreen, resume)

View File

@ -651,6 +651,7 @@ public:
IScreenEvents() : IScreenEvents() :
m_error(Event::kUnknown), m_error(Event::kUnknown),
m_shapeChanged(Event::kUnknown), m_shapeChanged(Event::kUnknown),
m_localInput(Event::kUnknown),
m_suspend(Event::kUnknown), m_suspend(Event::kUnknown),
m_resume(Event::kUnknown) { } m_resume(Event::kUnknown) { }
@ -671,6 +672,14 @@ public:
*/ */
Event::Type shapeChanged(); Event::Type shapeChanged();
//! Get local input event type
/*!
Returns the local input event type. This is sent when the cursor
is not on the current screen but a local input is detected (e.g.
via touchscreen inputs or mouse movements).
*/
Event::Type localInput();
//! Get suspend event type //! Get suspend event type
/*! /*!
Returns the suspend event type. This is sent whenever the system goes Returns the suspend event type. This is sent whenever the system goes
@ -690,6 +699,7 @@ public:
private: private:
Event::Type m_error; Event::Type m_error;
Event::Type m_shapeChanged; Event::Type m_shapeChanged;
Event::Type m_localInput;
Event::Type m_suspend; Event::Type m_suspend;
Event::Type m_resume; Event::Type m_resume;
}; };

View File

@ -237,10 +237,13 @@ Client::getCursorPos(SInt32& x, SInt32& y) const
} }
void void
Client::enter(SInt32 xAbs, SInt32 yAbs, UInt32, KeyModifierMask mask, bool) Client::enter(SInt32 xAbs, SInt32 yAbs, UInt32, KeyModifierMask mask, bool forScreensaver)
{ {
m_active = true; m_active = true;
m_screen->mouseMove(xAbs, yAbs); m_screen->mouseMove(xAbs, yAbs);
if (!forScreensaver) {
m_screen->screensaver(false);
}
m_screen->enter(mask); m_screen->enter(mask);
if (m_sendFileThread != NULL) { if (m_sendFileThread != NULL) {
@ -508,6 +511,18 @@ Client::setupScreen()
getEventTarget(), getEventTarget(),
new TMethodEventJob<Client>(this, new TMethodEventJob<Client>(this,
&Client::handleClipboardGrabbed)); &Client::handleClipboardGrabbed));
m_events->adoptHandler(m_events->forIScreen().localInput(),
getEventTarget(),
new TMethodEventJob<Client>(this,
&Client::handleLocalInputEvent));
m_events->adoptHandler(m_events->forIPrimaryScreen().screensaverActivated(),
getEventTarget(),
new TMethodEventJob<Client>(this,
&Client::handleScreensaverActivatedEvent));
m_events->adoptHandler(m_events->forIPrimaryScreen().screensaverDeactivated(),
getEventTarget(),
new TMethodEventJob<Client>(this,
&Client::handleScreensaverDeactivatedEvent));
} }
void void
@ -564,6 +579,13 @@ Client::cleanupScreen()
getEventTarget()); getEventTarget());
m_events->removeHandler(m_events->forClipboard().clipboardGrabbed(), m_events->removeHandler(m_events->forClipboard().clipboardGrabbed(),
getEventTarget()); getEventTarget());
m_events->removeHandler(m_events->forIScreen().localInput(),
getEventTarget());
m_events->removeHandler(m_events->forIPrimaryScreen().screensaverActivated(),
getEventTarget());
m_events->removeHandler(m_events->forIPrimaryScreen().screensaverDeactivated(),
getEventTarget());
delete m_server; delete m_server;
m_server = NULL; m_server = NULL;
} }
@ -739,6 +761,18 @@ Client::handleResume(const Event&, void*)
} }
} }
void
Client::handleScreensaverActivatedEvent(const Event&, void*) {
LOG((CLOG_DEBUG "Client received screensaver activate"));
m_server->sendScreensaver(true);
}
void
Client::handleScreensaverDeactivatedEvent(const Event&, void*) {
LOG((CLOG_DEBUG "Client received screensaver deactivate"));
m_server->sendScreensaver(false);
}
void void
Client::handleFileChunkSending(const Event& event, void*) Client::handleFileChunkSending(const Event& event, void*)
{ {
@ -767,6 +801,14 @@ Client::handleStopRetry(const Event&, void*)
m_args.m_restartable = false; m_args.m_restartable = false;
} }
void
Client::handleLocalInputEvent(const Event& event, void*)
{
IPlatformScreen::MotionInfo* info = static_cast<IPlatformScreen::MotionInfo*>(event.getData());
LOG((CLOG_DEBUG "Trigger screen switching caused by local input, screen coordinates (%d, %d)", info->m_x, info->m_y));
m_server->onLocalInput(info->m_x, info->m_y);
}
void void
Client::writeToDropDirThread(void*) Client::writeToDropDirThread(void*)
{ {

View File

@ -188,9 +188,12 @@ private:
void handleHello(const Event&, void*); void handleHello(const Event&, void*);
void handleSuspend(const Event& event, void*); void handleSuspend(const Event& event, void*);
void handleResume(const Event& event, void*); void handleResume(const Event& event, void*);
void handleScreensaverActivatedEvent(const Event&, void*);
void handleScreensaverDeactivatedEvent(const Event&, void*);
void handleFileChunkSending(const Event&, void*); void handleFileChunkSending(const Event&, void*);
void handleFileRecieveCompleted(const Event&, void*); void handleFileRecieveCompleted(const Event&, void*);
void handleStopRetry(const Event&, void*); void handleStopRetry(const Event&, void*);
void handleLocalInputEvent(const Event&, void*);
void onFileRecieveCompleted(); void onFileRecieveCompleted();
void sendClipboardThread(void*); void sendClipboardThread(void*);

View File

@ -275,7 +275,7 @@ ServerProxy::parseMessage(const UInt8* code)
} }
else if (memcmp(code, kMsgCScreenSaver, 4) == 0) { else if (memcmp(code, kMsgCScreenSaver, 4) == 0) {
screensaver(); rcvScreensaver();
} }
else if (memcmp(code, kMsgQInfo, 4) == 0) { else if (memcmp(code, kMsgQInfo, 4) == 0) {
@ -367,6 +367,14 @@ ServerProxy::onClipboardChanged(ClipboardID id, const IClipboard* clipboard)
StreamChunker::sendClipboard(data, data.size(), id, m_seqNum, m_events, this); StreamChunker::sendClipboard(data, data.size(), id, m_seqNum, m_events, this);
} }
void
ServerProxy::onLocalInput(SInt32 x, SInt32 y)
{
// Coordinates as signed 32 bit integers don't make a lot of sense
// but are used for compatibility with e.g. IPlatformScreen::MotionInfo
ProtocolUtil::writef(m_stream, kMsgCLocalInput, x, y);
}
void void
ServerProxy::flushCompressedMouse() ServerProxy::flushCompressedMouse()
{ {
@ -516,11 +524,12 @@ void
ServerProxy::enter() ServerProxy::enter()
{ {
// parse // parse
SInt8 forScreensaver;
SInt16 x, y; SInt16 x, y;
UInt16 mask; UInt16 mask;
UInt32 seqNum; UInt32 seqNum;
ProtocolUtil::readf(m_stream, kMsgCEnter + 4, &x, &y, &seqNum, &mask); ProtocolUtil::readf(m_stream, kMsgCEnter + 4, &x, &y, &seqNum, &mask, &forScreensaver);
LOG((CLOG_DEBUG1 "recv enter, %d,%d %d %04x", x, y, seqNum, mask)); LOG((CLOG_DEBUG1 "recv enter, %d,%d %d %04x, forScreensaver=%d", x, y, seqNum, mask, forScreensaver));
// discard old compressed mouse motion, if any // discard old compressed mouse motion, if any
m_compressMouse = false; m_compressMouse = false;
@ -530,7 +539,7 @@ ServerProxy::enter()
m_seqNum = seqNum; m_seqNum = seqNum;
// forward // forward
m_client->enter(x, y, seqNum, static_cast<KeyModifierMask>(mask), false); m_client->enter(x, y, seqNum, static_cast<KeyModifierMask>(mask), forScreensaver != 0);
} }
void void
@ -769,7 +778,7 @@ ServerProxy::mouseWheel()
} }
void void
ServerProxy::screensaver() ServerProxy::rcvScreensaver()
{ {
// parse // parse
SInt8 on; SInt8 on;
@ -780,6 +789,12 @@ ServerProxy::screensaver()
m_client->screensaver(on != 0); m_client->screensaver(on != 0);
} }
void
ServerProxy::sendScreensaver(bool activate) {
// Notify server about screensaver state of client
ProtocolUtil::writef(m_stream, kMsgCScreenSaver, activate ? 1 : 0);
}
void void
ServerProxy::resetOptions() ServerProxy::resetOptions()
{ {

View File

@ -50,6 +50,7 @@ public:
void onInfoChanged(); void onInfoChanged();
bool onGrabClipboard(ClipboardID); bool onGrabClipboard(ClipboardID);
void onClipboardChanged(ClipboardID, const IClipboard*); void onClipboardChanged(ClipboardID, const IClipboard*);
void onLocalInput(SInt32 x, SInt32 y);
//@} //@}
@ -59,6 +60,9 @@ public:
// sending dragging information to server // sending dragging information to server
void sendDragInfo(UInt32 fileCount, const char* info, size_t size); void sendDragInfo(UInt32 fileCount, const char* info, size_t size);
// Send screensaver information to server
void sendScreensaver(bool activate);
#ifdef BARRIER_TEST_ENV #ifdef BARRIER_TEST_ENV
void handleDataForTest() { handleData(Event(), NULL); } void handleDataForTest() { handleData(Event(), NULL); }
#endif #endif
@ -98,7 +102,7 @@ private:
void mouseMove(); void mouseMove();
void mouseRelativeMove(); void mouseRelativeMove();
void mouseWheel(); void mouseWheel();
void screensaver(); void rcvScreensaver();
void resetOptions(); void resetOptions();
void setOptions(); void setOptions();
void queryInfo(); void queryInfo();

View File

@ -133,7 +133,7 @@ XWindowsScreen::XWindowsScreen(
#ifdef HAVE_XI2 #ifdef HAVE_XI2
m_xi2detected = detectXI2(); m_xi2detected = detectXI2();
if (m_xi2detected) { if (m_xi2detected) {
selectXIRawMotion(); selectXIRawEventsPrimary();
} else } else
#endif #endif
{ {
@ -145,6 +145,12 @@ XWindowsScreen::XWindowsScreen(
openIM(); openIM();
} }
else { else {
#ifdef HAVE_XI2
m_xi2detected = detectXI2();
if (m_xi2detected) {
selectXIRawEventsSecondary();
}
#endif
// become impervious to server grabs // become impervious to server grabs
m_impl->XTestGrabControl(m_display, True); m_impl->XTestGrabControl(m_display, True);
} }
@ -238,8 +244,6 @@ XWindowsScreen::disable()
void void
XWindowsScreen::enter() XWindowsScreen::enter()
{ {
screensaver(false);
// release input context focus // release input context focus
if (m_ic != NULL) { if (m_ic != NULL) {
m_impl->XUnsetICFocus(m_ic); m_impl->XUnsetICFocus(m_ic);
@ -405,9 +409,11 @@ void
XWindowsScreen::screensaver(bool activate) XWindowsScreen::screensaver(bool activate)
{ {
if (activate) { if (activate) {
m_screensaverNotificationTimer.reset();
m_screensaver->activate(); m_screensaver->activate();
} }
else { else {
m_screensaverNotificationTimer.reset();
m_screensaver->deactivate(); m_screensaver->deactivate();
} }
} }
@ -1218,14 +1224,33 @@ XWindowsScreen::handleSystemEvent(const Event& event, void*)
#ifdef HAVE_XI2 #ifdef HAVE_XI2
if (m_xi2detected) { if (m_xi2detected) {
// Process RawMotion // Process RawEvents
XGenericEventCookie *cookie = (XGenericEventCookie*)&xevent->xcookie; XGenericEventCookie *cookie = (XGenericEventCookie*)&xevent->xcookie;
if (m_impl->XGetEventData(m_display, cookie) && if (m_impl->XGetEventData(m_display, cookie) &&
cookie->type == GenericEvent && cookie->type == GenericEvent &&
cookie->extension == xi_opcode) { cookie->extension == xi_opcode) {
LOGC(cookie->evtype == XI_RawTouchBegin, (CLOG_DEBUG1 "Touch begin on %s, onScreen = %s",
m_isPrimary ? "server" : "client",
m_isOnScreen ? "true" : "false"));
if (!m_isOnScreen && (cookie->evtype == XI_RawTouchBegin || cookie->evtype == XI_RawButtonPress )) {
// Touch or button press detected on local screen but cursor is not on screen => request focus from server
// Note: focus switching works on touch from client to server and vice versa, on mouse button press due
// to the nature of the shared server mouse only from server to client
SInt32 x, y;
// On touch event, getCursorPos sets x and y to the actual event coordinates. On mouse button press, x and
// y are set to the coordinates of the center of the screen.
// In the latter case, reusing m_x, m_y or m_xCursor, m_yCursor failed as they are not set on the client
// and thus trigger unexpected behavior (unexpected jumps to (0, 0) on button press)
getCursorPos(x, y);
sendEvent(m_events->forIScreen().localInput(), MotionInfo::alloc(x, y));
m_impl->XFreeEventData(m_display, cookie);
return;
}
if (cookie->evtype == XI_RawMotion) { if (cookie->evtype == XI_RawMotion) {
// Mouse motion detected on server => handle mouse motion
// Get current pointer's position // Get current pointer's position
Window root, child;
XMotionEvent xmotion; XMotionEvent xmotion;
xmotion.type = MotionNotify; xmotion.type = MotionNotify;
xmotion.send_event = False; // Raw motion xmotion.send_event = False; // Raw motion
@ -2062,17 +2087,46 @@ XWindowsScreen::detectXI2()
#ifdef HAVE_XI2 #ifdef HAVE_XI2
void void
XWindowsScreen::selectXIRawMotion() XWindowsScreen::selectXIRawEventsPrimary()
{ {
XIEventMask mask; XIEventMask mask;
mask.deviceid = XIAllDevices;
mask.mask_len = XIMaskLen(XI_RawMotion);
mask.mask = (unsigned char*)calloc(mask.mask_len, sizeof(char));
mask.deviceid = XIAllMasterDevices; mask.deviceid = XIAllMasterDevices;
memset(mask.mask, 0, 2); mask.mask_len = XIMaskLen(XI_LASTEVENT);
mask.mask = (unsigned char*) calloc(mask.mask_len, sizeof(char));
LOGC((mask.mask == nullptr), (CLOG_ERR "Cannot listen on XI2 events due to memory error"));
XISetMask(mask.mask, XI_RawKeyRelease); XISetMask(mask.mask, XI_RawKeyRelease);
XISetMask(mask.mask, XI_RawMotion); XISetMask(mask.mask, XI_RawMotion);
// Detect touchscreen events on primary screen (= server)
XISetMask(mask.mask, XI_RawTouchBegin);
XISetMask(mask.mask, XI_RawTouchUpdate);
XISetMask(mask.mask, XI_RawTouchEnd);
m_impl->XISelectEvents(m_display, DefaultRootWindow(m_display), &mask, 1);
free(mask.mask);
}
void
XWindowsScreen::selectXIRawEventsSecondary()
{
XIEventMask mask;
mask.deviceid = XIAllMasterDevices;
mask.mask_len = XIMaskLen(XI_LASTEVENT);
mask.mask = (unsigned char*) calloc(mask.mask_len, sizeof(char));
LOGC((mask.mask == nullptr), (CLOG_ERR "Cannot listen on XI2 events due to memory error"));
// Detect mouse events (movement, button press) on secondary screens (= clients)
XISetMask(mask.mask, XI_RawMotion);
XISetMask(mask.mask, XI_RawButtonPress);
// Detect key press events on secondary screens (= clients)
XISetMask(mask.mask, XI_RawKeyPress);
// Detect touchscreen events on secondary screens (= clients)
XISetMask(mask.mask, XI_RawTouchBegin);
XISetMask(mask.mask, XI_RawTouchUpdate);
XISetMask(mask.mask, XI_RawTouchEnd);
m_impl->XISelectEvents(m_display, DefaultRootWindow(m_display), &mask, 1); m_impl->XISelectEvents(m_display, DefaultRootWindow(m_display), &mask, 1);
free(mask.mask); free(mask.mask);
} }

View File

@ -20,6 +20,7 @@
#include "barrier/PlatformScreen.h" #include "barrier/PlatformScreen.h"
#include "barrier/KeyMap.h" #include "barrier/KeyMap.h"
#include "base/Stopwatch.h"
#include "common/stdset.h" #include "common/stdset.h"
#include "common/stdvector.h" #include "common/stdvector.h"
#include "XWindowsImpl.h" #include "XWindowsImpl.h"
@ -144,7 +145,8 @@ private:
bool detectXI2(); bool detectXI2();
#ifdef HAVE_XI2 #ifdef HAVE_XI2
void selectXIRawMotion(); void selectXIRawEventsPrimary();
void selectXIRawEventsSecondary();
#endif #endif
void selectEvents(Window) const; void selectEvents(Window) const;
void doSelectEvents(Window) const; void doSelectEvents(Window) const;
@ -230,6 +232,9 @@ private:
// screen saver stuff // screen saver stuff
XWindowsScreenSaver* m_screensaver; XWindowsScreenSaver* m_screensaver;
bool m_screensaverNotify; bool m_screensaverNotify;
// Timer for server notification to suppress screensaver if necessary
Stopwatch m_screensaverNotificationTimer;
const double NOTIFICATION_TIMEOUT = 10.0;
// logical to physical button mapping. m_buttons[i] gives the // logical to physical button mapping. m_buttons[i] gives the
// physical button for logical button i+1. // physical button for logical button i+1.

View File

@ -0,0 +1,83 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "server/ClientProxy1_7.h"
#include "server/Server.h"
#include "barrier/ProtocolUtil.h"
#include "barrier/StreamChunker.h"
#include "barrier/ClipboardChunk.h"
#include "io/IStream.h"
#include "base/TMethodEventJob.h"
#include "base/Log.h"
//
// ClientProxy1_7
//
ClientProxy1_7::ClientProxy1_7(const String& name, barrier::IStream* stream, Server* server, IEventQueue* events) :
ClientProxy1_6(name, stream, server, events),
m_events(events)
{
}
ClientProxy1_7::~ClientProxy1_7()
{
}
void
ClientProxy1_7::enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask, bool forScreensaver)
{
LOG((CLOG_DEBUG1 "send enter to \"%s\", %d,%d %d %04x, forScreensaver=%d", getName().c_str(), xAbs, yAbs, seqNum, mask, forScreensaver ? 1 : 0));
ProtocolUtil::writef(getStream(), kMsgCEnter,
xAbs, yAbs, seqNum, mask, forScreensaver ? 1 : 0);
}
bool
ClientProxy1_7::parseMessage(const UInt8* code)
{
if (memcmp(code, kMsgCLocalInput, 4) == 0) {
SInt16 x, y;
ProtocolUtil::readf(getStream(), kMsgCLocalInput + 4, &x, &y);
// Set up container for x and y coordinates
IPlatformScreen::MotionInfo* info = IPlatformScreen::MotionInfo::alloc(x, y);
m_events->addEvent(Event(m_events->forIScreen().localInput(), getEventTarget(), info));
}
else if (memcmp(code, kMsgCScreenSaver, 4) == 0) {
rcvScreensaver();
}
else {
return ClientProxy1_6::parseMessage(code);
}
return true;
}
void
ClientProxy1_7::rcvScreensaver()
{
SInt8 activate;
ProtocolUtil::readf(getStream(), kMsgCScreenSaver + 4, &activate);
if (activate != 0) {
m_events->addEvent(Event(m_events->forIPrimaryScreen().screensaverActivated(), getEventTarget()));
} else {
m_events->addEvent(Event(m_events->forIPrimaryScreen().screensaverDeactivated(), getEventTarget()));
}
}

View File

@ -0,0 +1,42 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "server/ClientProxy1_6.h"
class Server;
class IEventQueue;
//! Proxy for client implementing protocol version 1.7
class ClientProxy1_7 : public ClientProxy1_6 {
public:
ClientProxy1_7(const String& name, barrier::IStream* adoptedStream, Server* server, IEventQueue* events);
~ClientProxy1_7();
virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask,
bool forScreensaver);
protected:
virtual bool parseMessage(const UInt8* code);
virtual void rcvScreensaver();
private:
IEventQueue* m_events;
};

View File

@ -26,6 +26,7 @@
#include "server/ClientProxy1_4.h" #include "server/ClientProxy1_4.h"
#include "server/ClientProxy1_5.h" #include "server/ClientProxy1_5.h"
#include "server/ClientProxy1_6.h" #include "server/ClientProxy1_6.h"
#include "server/ClientProxy1_7.h"
#include "barrier/protocol_types.h" #include "barrier/protocol_types.h"
#include "barrier/ProtocolUtil.h" #include "barrier/ProtocolUtil.h"
#include "barrier/XBarrier.h" #include "barrier/XBarrier.h"
@ -231,6 +232,10 @@ ClientProxyUnknown::handleData(const Event&, void*)
case 6: case 6:
m_proxy = new ClientProxy1_6(name, m_stream, m_server, m_events); m_proxy = new ClientProxy1_6(name, m_stream, m_server, m_events);
break; break;
case 7:
m_proxy = new ClientProxy1_7(name, m_stream, m_server, m_events);
break;
} }
} }

View File

@ -139,10 +139,10 @@ PrimaryClient::disable()
void void
PrimaryClient::enter(SInt32 xAbs, SInt32 yAbs, PrimaryClient::enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask, bool screensaver) UInt32 seqNum, KeyModifierMask mask, bool forScreensaver)
{ {
m_screen->setSequenceNumber(seqNum); m_screen->setSequenceNumber(seqNum);
if (!screensaver) { if (!forScreensaver) {
m_screen->warpCursor(xAbs, yAbs); m_screen->warpCursor(xAbs, yAbs);
} }
m_screen->enter(mask); m_screen->enter(mask);
@ -244,9 +244,9 @@ PrimaryClient::mouseWheel(SInt32, SInt32)
} }
void void
PrimaryClient::screensaver(bool) PrimaryClient::screensaver(bool activate)
{ {
// ignore m_screen->screensaver(activate);
} }
void void

View File

@ -243,6 +243,14 @@ Server::~Server()
m_primaryClient->getEventTarget()); m_primaryClient->getEventTarget());
m_events->removeHandler(m_events->forIPrimaryScreen().screensaverDeactivated(), m_events->removeHandler(m_events->forIPrimaryScreen().screensaverDeactivated(),
m_primaryClient->getEventTarget()); m_primaryClient->getEventTarget());
m_events->removeHandler(m_events->forServer().switchToScreen(),
m_inputFilter);
m_events->removeHandler(m_events->forServer().switchInDirection(),
m_inputFilter);
m_events->removeHandler(m_events->forServer().keyboardBroadcast(),
m_inputFilter);
m_events->removeHandler(m_events->forServer().lockCursorToScreen(),
m_inputFilter);
m_events->removeHandler(m_events->forIPrimaryScreen().fakeInputBegin(), m_events->removeHandler(m_events->forIPrimaryScreen().fakeInputBegin(),
m_inputFilter); m_inputFilter);
m_events->removeHandler(m_events->forIPrimaryScreen().fakeInputEnd(), m_events->removeHandler(m_events->forIPrimaryScreen().fakeInputEnd(),
@ -1426,6 +1434,20 @@ Server::handleToggleScreenEvent(const Event& event, void*)
} }
} }
void
Server::handleLocalInputEvent(const Event& event, void* vclient)
{
BaseClientProxy* client = static_cast<BaseClientProxy*>(vclient);
IPlatformScreen::MotionInfo* info = static_cast<IPlatformScreen::MotionInfo*>(event.getData());
info = (info == nullptr) ? IPlatformScreen::MotionInfo::alloc(0, 0) : info;
LOG((CLOG_DEBUG "Trigger screen switching caused by local input on screen \"%s\", screen coordinates (%d, %d)", client->getName().c_str(), info->m_x, info->m_y));
// Record current cursor position on active screen
m_active->setJumpCursorPos(m_x, m_y);
// Do actual screen switching
switchScreen(client, info->m_x, info->m_y, false);
}
void void
Server::handleSwitchInDirectionEvent(const Event& event, void*) Server::handleSwitchInDirectionEvent(const Event& event, void*)
@ -1579,6 +1601,12 @@ Server::onScreensaver(bool activated)
{ {
LOG((CLOG_DEBUG "onScreenSaver %s", activated ? "activated" : "deactivated")); LOG((CLOG_DEBUG "onScreenSaver %s", activated ? "activated" : "deactivated"));
if (m_screensaverDelayTimer.getTime() > SCREENSAVER_DELAY_THRESHOLD) {
// The timer prevents flickering and erronous screensavers caused by a bad combination
// of internal events and XEvents => drop events in the range of a certain delay to
// prevent duplicate screensaver invocations
m_screensaverDelayTimer.reset();
if (activated) { if (activated) {
// save current screen and position // save current screen and position
m_activeSaver = m_active; m_activeSaver = m_active;
@ -1594,28 +1622,28 @@ Server::onScreensaver(bool activated)
// jump back to previous screen and position. we must check // jump back to previous screen and position. we must check
// that the position is still valid since the screen may have // that the position is still valid since the screen may have
// changed resolutions while the screen saver was running. // changed resolutions while the screen saver was running.
if (m_activeSaver != NULL && m_activeSaver != m_primaryClient) { // if (m_activeSaver != NULL && m_activeSaver != m_primaryClient) {
// check position // // check position
BaseClientProxy* screen = m_activeSaver; // BaseClientProxy* screen = m_activeSaver;
SInt32 x, y, w, h; // SInt32 x, y, w, h;
screen->getShape(x, y, w, h); // screen->getShape(x, y, w, h);
SInt32 zoneSize = getJumpZoneSize(screen); // SInt32 zoneSize = getJumpZoneSize(screen);
if (m_xSaver < x + zoneSize) { // if (m_xSaver < x + zoneSize) {
m_xSaver = x + zoneSize; // m_xSaver = x + zoneSize;
} // }
else if (m_xSaver >= x + w - zoneSize) { // else if (m_xSaver >= x + w - zoneSize) {
m_xSaver = x + w - zoneSize - 1; // m_xSaver = x + w - zoneSize - 1;
} // }
if (m_ySaver < y + zoneSize) { // if (m_ySaver < y + zoneSize) {
m_ySaver = y + zoneSize; // m_ySaver = y + zoneSize;
} // }
else if (m_ySaver >= y + h - zoneSize) { // else if (m_ySaver >= y + h - zoneSize) {
m_ySaver = y + h - zoneSize - 1; // m_ySaver = y + h - zoneSize - 1;
} // }
// jump // // jump
switchScreen(screen, m_xSaver, m_ySaver, false); // switchScreen(screen, m_xSaver, m_ySaver, false);
} // }
// reset state // reset state
m_activeSaver = NULL; m_activeSaver = NULL;
@ -1626,6 +1654,13 @@ Server::onScreensaver(bool activated)
index != m_clients.end(); ++index) { index != m_clients.end(); ++index) {
BaseClientProxy* client = index->second; BaseClientProxy* client = index->second;
client->screensaver(activated); client->screensaver(activated);
if (!activated && client != m_active) {
// Leave all screens that are not the active screen. This ensures that the
// cursor does not appear on multiple screens again after deactivating the
// screensaver
client->leave();
}
}
} }
} }
@ -2127,6 +2162,14 @@ Server::addClient(BaseClientProxy* client)
client->getEventTarget(), client->getEventTarget(),
new TMethodEventJob<Server>(this, new TMethodEventJob<Server>(this,
&Server::handleClipboardChanged, client)); &Server::handleClipboardChanged, client));
m_events->adoptHandler(m_events->forIScreen().localInput(),
client->getEventTarget(),
new TMethodEventJob<Server>(this,
&Server::handleLocalInputEvent, client));
m_events->adoptHandler(m_events->forIPrimaryScreen().screensaverDeactivated(),
client->getEventTarget(),
new TMethodEventJob<Server>(this,
&Server::handleScreensaverDeactivatedEvent));
// add to list // add to list
m_clientSet.insert(client); m_clientSet.insert(client);
@ -2159,6 +2202,10 @@ Server::removeClient(BaseClientProxy* client)
client->getEventTarget()); client->getEventTarget());
m_events->removeHandler(m_events->forClipboard().clipboardChanged(), m_events->removeHandler(m_events->forClipboard().clipboardChanged(),
client->getEventTarget()); client->getEventTarget());
m_events->removeHandler(m_events->forIScreen().localInput(),
client->getEventTarget());
m_events->removeHandler(m_events->forIPrimaryScreen().screensaverDeactivated(),
client->getEventTarget());
// remove from list // remove from list
m_clients.erase(getName(client)); m_clients.erase(getName(client));

View File

@ -309,6 +309,7 @@ private:
void handleClientCloseTimeout(const Event&, void*); void handleClientCloseTimeout(const Event&, void*);
void handleSwitchToScreenEvent(const Event&, void*); void handleSwitchToScreenEvent(const Event&, void*);
void handleToggleScreenEvent(const Event&, void*); void handleToggleScreenEvent(const Event&, void*);
void handleLocalInputEvent(const Event&, void*);
void handleSwitchInDirectionEvent(const Event&, void*); void handleSwitchInDirectionEvent(const Event&, void*);
void handleKeyboardBroadcastEvent(const Event&,void*); void handleKeyboardBroadcastEvent(const Event&,void*);
void handleLockCursorToScreenEvent(const Event&, void*); void handleLockCursorToScreenEvent(const Event&, void*);
@ -426,6 +427,8 @@ private:
// state saved when screen saver activates // state saved when screen saver activates
BaseClientProxy* m_activeSaver; BaseClientProxy* m_activeSaver;
SInt32 m_xSaver, m_ySaver; SInt32 m_xSaver, m_ySaver;
Stopwatch m_screensaverDelayTimer; // Used for preventing duplicate messages to clients
const double SCREENSAVER_DELAY_THRESHOLD = 0.5;
// common state for screen switch tests. all tests are always // common state for screen switch tests. all tests are always
// trying to reach the same screen in the same direction. // trying to reach the same screen in the same direction.