Allow XScreensaver syncing from client to server
Allows to deactivate the screensaver and postpone screensaver activation if local input is detected on a client. This fixes the screensavers getting out of sync if a client has a local input device such as a touchscreen
This commit is contained in:
parent
b891b1e630
commit
b3fd2335b3
|
@ -178,11 +178,9 @@ Screen::grabClipboard(ClipboardID id)
|
|||
void
|
||||
Screen::screensaver(bool activate)
|
||||
{
|
||||
if (!m_isPrimary) {
|
||||
// activate/deactivation screen saver iff synchronization enabled
|
||||
if (m_screenSaverSync) {
|
||||
m_screen->screensaver(activate);
|
||||
}
|
||||
// activate/deactivation screen saver iff synchronization enabled
|
||||
if (m_screenSaverSync) {
|
||||
m_screen->screensaver(activate);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
* barrier -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012-2016 Symless Ltd.
|
||||
* Copyright (C) 2002 Chris Schoeneman
|
||||
*
|
||||
*
|
||||
* 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
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
// 1.5: adds file transfer and removes home brew crypto
|
||||
// 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
|
||||
static const SInt16 kProtocolMajorVersion = 1;
|
||||
static const SInt16 kProtocolMinorVersion = 7;
|
||||
|
@ -130,9 +131,16 @@ extern const char* kMsgCClose;
|
|||
// must return this number with some messages. $4 = modifier key
|
||||
// mask. this will have bits set for each toggle modifier key
|
||||
// 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;
|
||||
|
||||
// enter screen 1.0: same as above but without respecting the screensaver state
|
||||
extern const char* kMsgCEnter1_0;
|
||||
|
||||
// leave screen: primary -> secondary
|
||||
// leaving screen. the secondary screen should send clipboard
|
||||
// data in response to this message for those clipboards that
|
||||
|
@ -149,8 +157,10 @@ extern const char* kMsgCLeave;
|
|||
// most recent kMsgCEnter. the primary always sends 0.
|
||||
extern const char* kMsgCClipboard;
|
||||
|
||||
// screensaver change: primary -> secondary
|
||||
// screensaver on primary has started ($1 == 1) or closed ($1 == 0)
|
||||
// screensaver change: primary <-> secondary
|
||||
// screensaver has started ($1 == 1) or closed ($1 == 0).
|
||||
// sync screensavers by dispatching information to all clients via
|
||||
// the server
|
||||
extern const char* kMsgCScreenSaver;
|
||||
|
||||
// reset options: primary -> secondary
|
||||
|
|
|
@ -237,10 +237,13 @@ Client::getCursorPos(SInt32& x, SInt32& y) const
|
|||
}
|
||||
|
||||
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_screen->mouseMove(xAbs, yAbs);
|
||||
if (!forScreensaver) {
|
||||
m_screen->screensaver(false);
|
||||
}
|
||||
m_screen->enter(mask);
|
||||
|
||||
if (m_sendFileThread != NULL) {
|
||||
|
@ -509,9 +512,17 @@ Client::setupScreen()
|
|||
new TMethodEventJob<Client>(this,
|
||||
&Client::handleClipboardGrabbed));
|
||||
m_events->adoptHandler(m_events->forIScreen().localInput(),
|
||||
getEventTarget(),
|
||||
new TMethodEventJob<Client>(this,
|
||||
&Client::handleLocalInputEvent));
|
||||
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
|
||||
|
@ -570,6 +581,11 @@ Client::cleanupScreen()
|
|||
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;
|
||||
m_server = NULL;
|
||||
}
|
||||
|
@ -745,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
|
||||
Client::handleFileChunkSending(const Event& event, void*)
|
||||
{
|
||||
|
|
|
@ -188,6 +188,8 @@ private:
|
|||
void handleHello(const Event&, void*);
|
||||
void handleSuspend(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 handleFileRecieveCompleted(const Event&, void*);
|
||||
void handleStopRetry(const Event&, void*);
|
||||
|
|
|
@ -275,7 +275,7 @@ ServerProxy::parseMessage(const UInt8* code)
|
|||
}
|
||||
|
||||
else if (memcmp(code, kMsgCScreenSaver, 4) == 0) {
|
||||
screensaver();
|
||||
rcvScreensaver();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgQInfo, 4) == 0) {
|
||||
|
@ -524,11 +524,12 @@ void
|
|||
ServerProxy::enter()
|
||||
{
|
||||
// parse
|
||||
SInt8 forScreensaver;
|
||||
SInt16 x, y;
|
||||
UInt16 mask;
|
||||
UInt32 seqNum;
|
||||
ProtocolUtil::readf(m_stream, kMsgCEnter + 4, &x, &y, &seqNum, &mask);
|
||||
LOG((CLOG_DEBUG1 "recv enter, %d,%d %d %04x", x, y, seqNum, mask));
|
||||
ProtocolUtil::readf(m_stream, kMsgCEnter + 4, &x, &y, &seqNum, &mask, &forScreensaver);
|
||||
LOG((CLOG_DEBUG1 "recv enter, %d,%d %d %04x, forScreensaver=%d", x, y, seqNum, mask, forScreensaver));
|
||||
|
||||
// discard old compressed mouse motion, if any
|
||||
m_compressMouse = false;
|
||||
|
@ -538,7 +539,7 @@ ServerProxy::enter()
|
|||
m_seqNum = seqNum;
|
||||
|
||||
// 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
|
||||
|
@ -777,7 +778,7 @@ ServerProxy::mouseWheel()
|
|||
}
|
||||
|
||||
void
|
||||
ServerProxy::screensaver()
|
||||
ServerProxy::rcvScreensaver()
|
||||
{
|
||||
// parse
|
||||
SInt8 on;
|
||||
|
@ -788,6 +789,12 @@ ServerProxy::screensaver()
|
|||
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
|
||||
ServerProxy::resetOptions()
|
||||
{
|
||||
|
|
|
@ -60,6 +60,9 @@ public:
|
|||
// sending dragging information to server
|
||||
void sendDragInfo(UInt32 fileCount, const char* info, size_t size);
|
||||
|
||||
// Send screensaver information to server
|
||||
void sendScreensaver(bool activate);
|
||||
|
||||
#ifdef BARRIER_TEST_ENV
|
||||
void handleDataForTest() { handleData(Event(), NULL); }
|
||||
#endif
|
||||
|
@ -99,7 +102,7 @@ private:
|
|||
void mouseMove();
|
||||
void mouseRelativeMove();
|
||||
void mouseWheel();
|
||||
void screensaver();
|
||||
void rcvScreensaver();
|
||||
void resetOptions();
|
||||
void setOptions();
|
||||
void queryInfo();
|
||||
|
|
|
@ -244,8 +244,6 @@ XWindowsScreen::disable()
|
|||
void
|
||||
XWindowsScreen::enter()
|
||||
{
|
||||
screensaver(false);
|
||||
|
||||
// release input context focus
|
||||
if (m_ic != NULL) {
|
||||
m_impl->XUnsetICFocus(m_ic);
|
||||
|
@ -411,9 +409,11 @@ void
|
|||
XWindowsScreen::screensaver(bool activate)
|
||||
{
|
||||
if (activate) {
|
||||
m_screensaverNotificationTimer.reset();
|
||||
m_screensaver->activate();
|
||||
}
|
||||
else {
|
||||
m_screensaverNotificationTimer.reset();
|
||||
m_screensaver->deactivate();
|
||||
}
|
||||
}
|
||||
|
@ -2117,8 +2117,11 @@ XWindowsScreen::selectXIRawEventsSecondary()
|
|||
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 button press events on secondary screens (= clients)
|
||||
// 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);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "barrier/PlatformScreen.h"
|
||||
#include "barrier/KeyMap.h"
|
||||
#include "base/Stopwatch.h"
|
||||
#include "common/stdset.h"
|
||||
#include "common/stdvector.h"
|
||||
#include "XWindowsImpl.h"
|
||||
|
@ -231,6 +232,9 @@ private:
|
|||
// screen saver stuff
|
||||
XWindowsScreenSaver* m_screensaver;
|
||||
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
|
||||
// physical button for logical button i+1.
|
||||
|
|
|
@ -39,6 +39,15 @@ 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)
|
||||
{
|
||||
|
@ -51,9 +60,24 @@ ClientProxy1_7::parseMessage(const UInt8* code)
|
|||
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,10 +28,14 @@ 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);
|
||||
|
||||
private:
|
||||
void handleClipboardSendingEvent(const Event&, void*);
|
||||
virtual void rcvScreensaver();
|
||||
|
||||
private:
|
||||
IEventQueue* m_events;
|
||||
|
|
|
@ -139,10 +139,10 @@ PrimaryClient::disable()
|
|||
|
||||
void
|
||||
PrimaryClient::enter(SInt32 xAbs, SInt32 yAbs,
|
||||
UInt32 seqNum, KeyModifierMask mask, bool screensaver)
|
||||
UInt32 seqNum, KeyModifierMask mask, bool forScreensaver)
|
||||
{
|
||||
m_screen->setSequenceNumber(seqNum);
|
||||
if (!screensaver) {
|
||||
if (!forScreensaver) {
|
||||
m_screen->warpCursor(xAbs, yAbs);
|
||||
}
|
||||
m_screen->enter(mask);
|
||||
|
@ -244,9 +244,9 @@ PrimaryClient::mouseWheel(SInt32, SInt32)
|
|||
}
|
||||
|
||||
void
|
||||
PrimaryClient::screensaver(bool)
|
||||
PrimaryClient::screensaver(bool activate)
|
||||
{
|
||||
// ignore
|
||||
m_screen->screensaver(activate);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -1599,56 +1599,69 @@ Server::onClipboardChanged(BaseClientProxy* sender,
|
|||
void
|
||||
Server::onScreensaver(bool activated)
|
||||
{
|
||||
LOG((CLOG_DEBUG "onScreenSaver %s", activated ? "activated" : "deactivated"));
|
||||
LOG((CLOG_DEBUG "onScreenSaver %s", activated ? "activated" : "deactivated"));
|
||||
|
||||
if (activated) {
|
||||
// save current screen and position
|
||||
m_activeSaver = m_active;
|
||||
m_xSaver = m_x;
|
||||
m_ySaver = m_y;
|
||||
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();
|
||||
|
||||
// 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
|
||||
BaseClientProxy* screen = m_activeSaver;
|
||||
SInt32 x, y, w, h;
|
||||
screen->getShape(x, y, w, h);
|
||||
SInt32 zoneSize = getJumpZoneSize(screen);
|
||||
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;
|
||||
}
|
||||
if (activated) {
|
||||
// save current screen and position
|
||||
m_activeSaver = m_active;
|
||||
m_xSaver = m_x;
|
||||
m_ySaver = m_y;
|
||||
|
||||
// jump
|
||||
switchScreen(screen, m_xSaver, m_ySaver, false);
|
||||
}
|
||||
// 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
|
||||
// BaseClientProxy* screen = m_activeSaver;
|
||||
// SInt32 x, y, w, h;
|
||||
// screen->getShape(x, y, w, h);
|
||||
// SInt32 zoneSize = getJumpZoneSize(screen);
|
||||
// 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;
|
||||
// }
|
||||
|
||||
// reset state
|
||||
m_activeSaver = NULL;
|
||||
}
|
||||
// // jump
|
||||
// switchScreen(screen, m_xSaver, m_ySaver, false);
|
||||
// }
|
||||
|
||||
// send message to all clients
|
||||
for (ClientList::const_iterator index = m_clients.begin();
|
||||
index != m_clients.end(); ++index) {
|
||||
BaseClientProxy* client = index->second;
|
||||
client->screensaver(activated);
|
||||
}
|
||||
// reset state
|
||||
m_activeSaver = NULL;
|
||||
}
|
||||
|
||||
// send message to all clients
|
||||
for (ClientList::const_iterator index = m_clients.begin();
|
||||
index != m_clients.end(); ++index) {
|
||||
BaseClientProxy* client = index->second;
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2153,6 +2166,10 @@ Server::addClient(BaseClientProxy* client)
|
|||
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
|
||||
m_clientSet.insert(client);
|
||||
|
@ -2187,6 +2204,8 @@ Server::removeClient(BaseClientProxy* client)
|
|||
client->getEventTarget());
|
||||
m_events->removeHandler(m_events->forIScreen().localInput(),
|
||||
client->getEventTarget());
|
||||
m_events->removeHandler(m_events->forIPrimaryScreen().screensaverDeactivated(),
|
||||
client->getEventTarget());
|
||||
|
||||
// remove from list
|
||||
m_clients.erase(getName(client));
|
||||
|
|
|
@ -426,7 +426,9 @@ private:
|
|||
|
||||
// state saved when screen saver activates
|
||||
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
|
||||
// trying to reach the same screen in the same direction.
|
||||
|
|
Loading…
Reference in New Issue