Feature to drag a file from Windows to Mac:

- On Mac client main thread is used for cocoa application in order to simulate drag.
- Send dragging file dir from Windows server to Mac client while dragging after switching screen.
- Dragging information sending is immature now (need to support multi files dragging in the future).
- Used Cocoa function to monitor dragg pasteboard.
- Changed Mac client to use another thread for event queue instead of the main thread.
- Change fileRecieveComplete to fileRecieveCompleted.
This commit is contained in:
jerry 2013-08-30 14:38:43 +00:00
parent 031a84ca84
commit ce1b62db14
52 changed files with 875 additions and 184 deletions

View File

@ -594,3 +594,9 @@ CEventQueue::CTimer::operator<(const CTimer& t) const
{ {
return m_time < t.m_time; return m_time < t.m_time;
} }
void
CEventQueue::cacheCurrentEventQueueRef()
{
m_buffer->cacheCurrentEventQueueRef();
}

View File

@ -60,6 +60,8 @@ public:
virtual CEvent::Type virtual CEvent::Type
getRegisteredType(const CString& name) const; getRegisteredType(const CString& name) const;
void* getSystemTarget(); void* getSystemTarget();
void cacheCurrentEventQueueRef();
private: private:
UInt32 saveEvent(const CEvent& event); UInt32 saveEvent(const CEvent& event);

View File

@ -177,7 +177,7 @@ REGISTER_EVENT(IScreen, clipboardGrabbed)
REGISTER_EVENT(IScreen, suspend) REGISTER_EVENT(IScreen, suspend)
REGISTER_EVENT(IScreen, resume) REGISTER_EVENT(IScreen, resume)
REGISTER_EVENT(IScreen, fileChunkSending) REGISTER_EVENT(IScreen, fileChunkSending)
REGISTER_EVENT(IScreen, fileRecieveComplete) REGISTER_EVENT(IScreen, fileRecieveCompleted)
// //
// CIpcServer // CIpcServer

View File

@ -629,7 +629,7 @@ public:
m_suspend(CEvent::kUnknown), m_suspend(CEvent::kUnknown),
m_resume(CEvent::kUnknown), m_resume(CEvent::kUnknown),
m_fileChunkSending(CEvent::kUnknown), m_fileChunkSending(CEvent::kUnknown),
m_fileRecieveComplete(CEvent::kUnknown) { } m_fileRecieveCompleted(CEvent::kUnknown) { }
//! @name accessors //! @name accessors
//@{ //@{
@ -674,7 +674,7 @@ public:
CEvent::Type fileChunkSending(); CEvent::Type fileChunkSending();
//! Completed receiving a file //! Completed receiving a file
CEvent::Type fileRecieveComplete(); CEvent::Type fileRecieveCompleted();
//@} //@}
@ -685,5 +685,5 @@ private:
CEvent::Type m_suspend; CEvent::Type m_suspend;
CEvent::Type m_resume; CEvent::Type m_resume;
CEvent::Type m_fileChunkSending; CEvent::Type m_fileChunkSending;
CEvent::Type m_fileRecieveComplete; CEvent::Type m_fileRecieveCompleted;
}; };

View File

@ -40,6 +40,7 @@ public:
virtual CEventQueueTimer* virtual CEventQueueTimer*
newTimer(double duration, bool oneShot) const; newTimer(double duration, bool oneShot) const;
virtual void deleteTimer(CEventQueueTimer*) const; virtual void deleteTimer(CEventQueueTimer*) const;
void cacheCurrentEventQueueRef() { }
private: private:
typedef std::deque<UInt32> CEventDeque; typedef std::deque<UInt32> CEventDeque;

View File

@ -176,6 +176,8 @@ public:
virtual CEvent::Type virtual CEvent::Type
registerTypeOnce(CEvent::Type& type, registerTypeOnce(CEvent::Type& type,
const char* name) = 0; const char* name) = 0;
virtual void cacheCurrentEventQueueRef() = 0;
//@} //@}
//! @name accessors //! @name accessors

View File

@ -66,6 +66,8 @@ public:
return at some future time if it's blocked waiting on an event. return at some future time if it's blocked waiting on an event.
*/ */
virtual bool addEvent(UInt32 dataID) = 0; virtual bool addEvent(UInt32 dataID) = 0;
virtual void cacheCurrentEventQueueRef() = 0;
//@} //@}
//! @name accessors //! @name accessors

View File

@ -85,10 +85,10 @@ CClient::CClient(IEventQueue* events,
this, this,
new TMethodEventJob<CClient>(this, new TMethodEventJob<CClient>(this,
&CClient::handleFileChunkSending)); &CClient::handleFileChunkSending));
m_events->adoptHandler(m_events->forIScreen().fileRecieveComplete(), m_events->adoptHandler(m_events->forIScreen().fileRecieveCompleted(),
this, this,
new TMethodEventJob<CClient>(this, new TMethodEventJob<CClient>(this,
&CClient::handleFileRecieveComplete)); &CClient::handleFileRecieveCompleted));
} }
CClient::~CClient() CClient::~CClient()
@ -711,17 +711,19 @@ CClient::handleFileChunkSending(const CEvent& event, void*)
} }
void void
CClient::handleFileRecieveComplete(const CEvent& event, void*) CClient::handleFileRecieveCompleted(const CEvent& event, void*)
{ {
onFileRecieveComplete(); onFileRecieveCompleted();
} }
void void
CClient::onFileRecieveComplete() CClient::onFileRecieveCompleted()
{ {
if (isReceivedFileSizeValid()) { if (isReceivedFileSizeValid()) {
m_fileTransferDes = m_screen->getDropTarget();
if (!m_fileTransferDes.empty()) { if (!m_fileTransferDes.empty()) {
std::fstream file; std::fstream file;
m_fileTransferDes.append("/").append(m_dragFileList.at(0));
file.open(m_fileTransferDes.c_str(), std::ios::out | std::ios::binary); file.open(m_fileTransferDes.c_str(), std::ios::out | std::ios::binary);
if (!file.is_open()) { if (!file.is_open()) {
// TODO: file open failed // TODO: file open failed
@ -730,6 +732,9 @@ CClient::onFileRecieveComplete()
file.write(m_receivedFileData.c_str(), m_receivedFileData.size()); file.write(m_receivedFileData.c_str(), m_receivedFileData.size());
file.close(); file.close();
} }
else {
LOG((CLOG_ERR "drop file failed: drop target is empty"));
}
} }
} }
@ -752,6 +757,30 @@ CClient::fileChunkReceived(CString data)
m_receivedFileData += data; m_receivedFileData += data;
} }
void
CClient::dragInfoReceived(UInt32 fileNum, CString data)
{
CDragInformation::parseDragInfo(m_dragFileList, fileNum, data);
LOG((CLOG_DEBUG "drag information received"));
LOG((CLOG_DEBUG "total drag file number: %i", m_dragFileList.size()));
for(int i = 0; i < m_dragFileList.size(); ++i) {
LOG((CLOG_DEBUG2 "dragging file %i name: %s", i + 1, m_dragFileList.at(i).c_str()));
}
if (m_dragFileList.size() == 1) {
m_dragFileExt = CDragInformation::getDragFileExtension(m_dragFileList.at(0));
}
else if (m_dragFileList.size() > 1) {
m_dragFileExt.clear();
}
else {
return;
}
m_screen->startDraggingFiles(m_dragFileExt);
}
bool bool
CClient::isReceivedFileSizeValid() CClient::isReceivedFileSizeValid()
{ {

View File

@ -25,6 +25,7 @@
#include "INode.h" #include "INode.h"
#include "CCryptoOptions.h" #include "CCryptoOptions.h"
#include "CEventTypes.h" #include "CEventTypes.h"
#include "CDragInformation.h"
class CEventQueueTimer; class CEventQueueTimer;
class CScreen; class CScreen;
@ -100,7 +101,10 @@ public:
//! Received a chunk of file data //! Received a chunk of file data
void fileChunkReceived(CString data); void fileChunkReceived(CString data);
//! Received drag information
void dragInfoReceived(UInt32 fileNum, CString data);
//! Create a new thread and use it to send file to Server //! Create a new thread and use it to send file to Server
void sendFileToServer(const char* filename); void sendFileToServer(const char* filename);
@ -193,8 +197,8 @@ private:
void handleSuspend(const CEvent& event, void*); void handleSuspend(const CEvent& event, void*);
void handleResume(const CEvent& event, void*); void handleResume(const CEvent& event, void*);
void handleFileChunkSending(const CEvent&, void*); void handleFileChunkSending(const CEvent&, void*);
void handleFileRecieveComplete(const CEvent&, void*); void handleFileRecieveCompleted(const CEvent&, void*);
void onFileRecieveComplete(); void onFileRecieveCompleted();
public: public:
bool m_mock; bool m_mock;
@ -223,6 +227,8 @@ private:
CString m_receivedFileData; CString m_receivedFileData;
CString m_fileTransferSrc; CString m_fileTransferSrc;
CString m_fileTransferDes; CString m_fileTransferDes;
CDragFileList m_dragFileList;
CString m_dragFileExt;
}; };
#endif #endif

View File

@ -301,6 +301,9 @@ CServerProxy::parseMessage(const UInt8* code)
else if (memcmp(code, kMsgDFileTransfer, 4) == 0) { else if (memcmp(code, kMsgDFileTransfer, 4) == 0) {
fileChunkReceived(); fileChunkReceived();
} }
else if (memcmp(code, kMsgDDragInfo, 4) == 0) {
dragInfoReceived();
}
else if (memcmp(code, kMsgCClose, 4) == 0) { else if (memcmp(code, kMsgCClose, 4) == 0) {
// server wants us to hangup // server wants us to hangup
@ -865,7 +868,7 @@ void
CServerProxy::fileChunkReceived() CServerProxy::fileChunkReceived()
{ {
// parse // parse
UInt8 mark; UInt8 mark = 0;
CString content; CString content;
CProtocolUtil::readf(m_stream, kMsgDFileTransfer + 4, &mark, &content); CProtocolUtil::readf(m_stream, kMsgDFileTransfer + 4, &mark, &content);
@ -898,7 +901,7 @@ CServerProxy::fileChunkReceived()
break; break;
case kFileEnd: case kFileEnd:
m_events->addEvent(CEvent(m_events->forIScreen().fileRecieveComplete(), m_client)); m_events->addEvent(CEvent(m_events->forIScreen().fileRecieveCompleted(), m_client));
if (CLOG->getFilter() >= kDEBUG2) { if (CLOG->getFilter() >= kDEBUG2) {
LOG((CLOG_DEBUG2 "file data transfer finished")); LOG((CLOG_DEBUG2 "file data transfer finished"));
m_elapsedTime += m_stopwatch.getTime(); m_elapsedTime += m_stopwatch.getTime();
@ -911,6 +914,17 @@ CServerProxy::fileChunkReceived()
} }
} }
void
CServerProxy::dragInfoReceived()
{
// parse
UInt32 fileNum = 0;
CString content;
CProtocolUtil::readf(m_stream, kMsgDDragInfo + 4, &fileNum, &content);
m_client->dragInfoReceived(fileNum, content);
}
void void
CServerProxy::fileChunkSending(UInt8 mark, char* data, size_t dataSize) CServerProxy::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
{ {

View File

@ -103,6 +103,7 @@ private:
void queryInfo(); void queryInfo();
void infoAcknowledgment(); void infoAcknowledgment();
void fileChunkReceived(); void fileChunkReceived();
void dragInfoReceived();
private: private:
typedef EResult (CServerProxy::*MessageParser)(const UInt8*); typedef EResult (CServerProxy::*MessageParser)(const UInt8*);

View File

@ -40,6 +40,8 @@ public:
newTimer(double duration, bool oneShot) const; newTimer(double duration, bool oneShot) const;
virtual void deleteTimer(CEventQueueTimer*) const; virtual void deleteTimer(CEventQueueTimer*) const;
virtual void cacheCurrentEventQueueRef() {}
private: private:
DWORD m_thread; DWORD m_thread;
UINT m_userEvent; UINT m_userEvent;

View File

@ -699,7 +699,7 @@ CMSWindowsScreen::fakeMouseButton(ButtonID id, bool press)
} }
void void
CMSWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y) const CMSWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y)
{ {
m_desks->fakeMouseMove(x, y); m_desks->fakeMouseMove(x, y);
} }

View File

@ -88,7 +88,7 @@ public:
// ISecondaryScreen overrides // ISecondaryScreen overrides
virtual void fakeMouseButton(ButtonID id, bool press); virtual void fakeMouseButton(ButtonID id, bool press);
virtual void fakeMouseMove(SInt32 x, SInt32 y) const; virtual void fakeMouseMove(SInt32 x, SInt32 y);
virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const; virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const;
virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const; virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const;

View File

@ -70,6 +70,9 @@ elseif (APPLE)
COSXScreen.cpp COSXScreen.cpp
COSXScreenSaver.cpp COSXScreenSaver.cpp
COSXScreenSaverUtil.m COSXScreenSaverUtil.m
COSXPasteboardPeeker.m
COSXDragSimulator.m
COSXDragView.m
) )
elseif (UNIX) elseif (UNIX)
@ -110,9 +113,20 @@ if (UNIX)
) )
endif() endif()
if (APPLE)
list(APPEND inc
/System/Library/Frameworks
)
endif()
include_directories(${inc}) include_directories(${inc})
add_library(platform STATIC ${src}) add_library(platform STATIC ${src})
if (UNIX) if (UNIX)
target_link_libraries(platform io net ipc synergy ${libs}) target_link_libraries(platform io net ipc synergy ${libs})
endif() endif()
if (APPLE)
FIND_LIBRARY(COCOA_LIBRARY Cocoa)
target_link_libraries(platform ${COCOA_LIBRARY})
endif()

View File

@ -0,0 +1,32 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software 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 COPYING 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 "common.h"
#import <CoreFoundation/CoreFoundation.h>
#if defined(__cplusplus)
extern "C" {
#endif
void runCocoaApp();
void fakeDragging(const char* str, int length, int cursorX, int cursorY);
CFStringRef getCocoaDropTarget();
#if defined(__cplusplus)
}
#endif

View File

@ -0,0 +1,64 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software 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 COPYING 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.
*/
#import "COSXDragSimulator.h"
#import "COSXDragView.h"
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import <Cocoa/Cocoa.h>
NSWindow* g_dragWindow = NULL;
COSXDragView* g_dragView = NULL;
void
runCocoaApp()
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSApplication* app = [[NSApplication alloc] init];
NSWindow* window = [[NSWindow alloc]
initWithContentRect: NSMakeRect(-100, -100, 100, 100)
styleMask: NSTitledWindowMask | NSMiniaturizableWindowMask
backing: NSBackingStoreBuffered
defer: NO];
[window setTitle: @""];
[window makeKeyAndOrderFront:nil];
COSXDragView* dragView = [[COSXDragView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
g_dragWindow = window;
g_dragView = dragView;
[window setContentView: dragView];
[app run];
[pool release];
}
void
fakeDragging(const char* str, int length, int cursorX, int cursorY)
{
dispatch_async(dispatch_get_main_queue(), ^{
NSRect screen = [[NSScreen mainScreen] frame];
NSLog ( @"mouseLocation: %d %d", cursorX, cursorY);
NSRect rect = NSMakeRect(cursorX - 50, screen.size.height - cursorY - 50, 100, 100);
[g_dragWindow setFrame:rect display:YES];
[g_dragWindow makeKeyWindow];
});
}
CFStringRef
getCocoaDropTarget()
{
return [g_dragView getDropTarget];
}

View File

@ -0,0 +1,28 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software 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 COPYING 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/>.
*/
#import <Cocoa/Cocoa.h>
@interface COSXDragView : NSView<NSDraggingSource,NSDraggingInfo>
{
NSMutableString* m_dropTarget;
}
-(CFStringRef)getDropTarget;
-(void)clearDropTarget;
@end

View File

@ -0,0 +1,90 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software 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 COPYING 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/>.
*/
#import "COSXDragView.h"
@implementation COSXDragView
- (id)
initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
m_dropTarget = [[NSMutableString alloc] initWithCapacity:0];
return self;
}
- (void)
drawRect:(NSRect)dirtyRect
{
}
- (BOOL)
acceptsFirstMouse:(NSEvent *)theEvent
{
return YES;
}
- (void)
mouseDown:(NSEvent *)theEvent
{
NSPoint dragPosition;
NSRect imageLocation;
dragPosition = [self convertPoint:[theEvent locationInWindow]
fromView:nil];
dragPosition.x -= 16;
dragPosition.y -= 16;
imageLocation.origin = dragPosition;
imageLocation.size = NSMakeSize(32,32);
[self dragPromisedFilesOfTypes:[NSArray arrayWithObject:@"zip"]
fromRect:imageLocation
source:self
slideBack:NO
event:theEvent];
}
- (NSArray*)
namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination
{
[m_dropTarget setString:@""];
[m_dropTarget appendString:dropDestination.path];
NSLog ( @"cocoa drop target: %@", m_dropTarget);
return nil;
}
-(NSDragOperation)
draggingSourceOperationMaskForLocal:(BOOL)flag
{
return NSDragOperationCopy;
}
-(CFStringRef)
getDropTarget
{
NSMutableString* string;
string = [[NSMutableString alloc] initWithCapacity:0];
[string appendString:m_dropTarget];
return (CFStringRef)string;
}
-(void)
clearDropTarget
{
[m_dropTarget setString:@""];
}
@end

View File

@ -90,7 +90,7 @@ bool
COSXEventQueueBuffer::addEvent(UInt32 dataID) COSXEventQueueBuffer::addEvent(UInt32 dataID)
{ {
EventRef event; EventRef event;
OSStatus error = CreateEvent( OSStatus error = CreateEvent(
kCFAllocatorDefault, kCFAllocatorDefault,
'Syne', 'Syne',
dataID, dataID,
@ -99,7 +99,7 @@ COSXEventQueueBuffer::addEvent(UInt32 dataID)
&event); &event);
if (error == noErr) { if (error == noErr) {
error = PostEventToQueue(GetMainEventQueue(), event, error = PostEventToQueue(m_threadEventQueueRef, event,
kEventPriorityStandard); kEventPriorityStandard);
ReleaseEvent(event); ReleaseEvent(event);
} }
@ -126,3 +126,9 @@ COSXEventQueueBuffer::deleteTimer(CEventQueueTimer* timer) const
{ {
delete timer; delete timer;
} }
void
COSXEventQueueBuffer::cacheCurrentEventQueueRef()
{
m_threadEventQueueRef = GetCurrentEventQueue();
}

View File

@ -38,10 +38,12 @@ public:
virtual CEventQueueTimer* virtual CEventQueueTimer*
newTimer(double duration, bool oneShot) const; newTimer(double duration, bool oneShot) const;
virtual void deleteTimer(CEventQueueTimer*) const; virtual void deleteTimer(CEventQueueTimer*) const;
virtual void cacheCurrentEventQueueRef();
private: private:
EventRef m_event; EventRef m_event;
IEventQueue* m_eventQueue; IEventQueue* m_eventQueue;
EventQueueRef m_threadEventQueueRef;
}; };
#endif #endif

View File

@ -0,0 +1,31 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software 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 COPYING 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 "common.h"
#import <CoreFoundation/CoreFoundation.h>
#if defined(__cplusplus)
extern "C" {
#endif
CFStringRef getDraggedFileURL();
#if defined(__cplusplus)
}
#endif

View File

@ -0,0 +1,35 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software 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 COPYING 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.
*/
#import "COSXPasteboardPeeker.h"
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import <Cocoa/Cocoa.h>
CFStringRef
getDraggedFileURL()
{
NSString* pbName = NSDragPboard;
NSPasteboard* pboard = [NSPasteboard pasteboardWithName:pbName];
NSMutableString* string;
string = [[NSMutableString alloc] initWithCapacity:0];
NSArray* files = [pboard propertyListForType:NSFilenamesPboardType];
for (id file in files) {
[string appendString: (NSString*)file];
}
return (CFStringRef)string;
}

View File

@ -32,6 +32,8 @@
#include "TMethodEventJob.h" #include "TMethodEventJob.h"
#include "TMethodJob.h" #include "TMethodJob.h"
#include "XArch.h" #include "XArch.h"
#include "COSXDragSimulator.h"
#include "COSXPasteboardPeeker.h"
#include <math.h> #include <math.h>
@ -95,7 +97,9 @@ COSXScreen::COSXScreen(IEventQueue* events, bool isPrimary, bool autoShowHideCur
m_autoShowHideCursor(autoShowHideCursor), m_autoShowHideCursor(autoShowHideCursor),
m_eventTapRLSR(nullptr), m_eventTapRLSR(nullptr),
m_eventTapPort(nullptr), m_eventTapPort(nullptr),
m_pmRootPort(0) m_pmRootPort(0),
m_fakeDraggingStarted(false),
m_getDropTargetThread(NULL)
{ {
try { try {
m_displayID = CGMainDisplayID(); m_displayID = CGMainDisplayID();
@ -564,7 +568,7 @@ COSXScreen::fakeMouseButton(ButtonID id, bool press)
MouseButtonState state = press ? kMouseButtonDown : kMouseButtonUp; MouseButtonState state = press ? kMouseButtonDown : kMouseButtonUp;
LOG((CLOG_DEBUG1 "faking mouse button %s", press ? "press" : "release")); LOG((CLOG_DEBUG1 "faking mouse button id: %d press: %s", id, press ? "pressed" : "released"));
MouseButtonEventMapType thisButtonMap = MouseButtonEventMap[index]; MouseButtonEventMapType thisButtonMap = MouseButtonEventMap[index];
CGEventType type = thisButtonMap[state]; CGEventType type = thisButtonMap[state];
@ -580,11 +584,60 @@ COSXScreen::fakeMouseButton(ButtonID id, bool press)
m_lastSingleClickXCursor = m_xCursor; m_lastSingleClickXCursor = m_xCursor;
m_lastSingleClickYCursor = m_yCursor; m_lastSingleClickYCursor = m_yCursor;
} }
if (!press && (id == kButtonLeft)) {
fakeKeyUp(29);
if (m_fakeDraggingStarted) {
m_getDropTargetThread = new CThread(new TMethodJob<COSXScreen>(
this, &COSXScreen::getDropTargetThread));
}
m_fakeDraggingStarted = false;
}
} }
void void
COSXScreen::fakeMouseMove(SInt32 x, SInt32 y) const COSXScreen::getDropTargetThread(void*)
{ {
char* cstr = NULL;
// wait for 5 secs for the drop destinaiton string to be filled.
UInt32 timeout = ARCH->time() + 5;
while (ARCH->time() < timeout) {
CFStringRef cfstr = getCocoaDropTarget();
cstr = CFStringRefToUTF8String(cfstr);
CFRelease(cfstr);
if (cstr != NULL) {
break;
}
ARCH->sleep(.1f);
}
if (cstr != NULL) {
LOG((CLOG_DEBUG "drop target: %s", cstr));
m_dropTarget = cstr;
}
else {
LOG((CLOG_ERR "failed to get drop target"));
m_dropTarget.clear();
}
delete m_getDropTargetThread;
}
void
COSXScreen::fakeMouseMove(SInt32 x, SInt32 y)
{
if (m_fakeDraggingStarted) {
// HACK: for some reason the drag icon
// does not follow the cursor unless a key
// is pressed (except esc key)
// TODO: fake this key down properly
fakeKeyDown(kKeyControl_L, 8194, 29);
}
// synthesize event // synthesize event
CGPoint pos; CGPoint pos;
pos.x = x; pos.x = x;
@ -671,6 +724,12 @@ COSXScreen::showCursor()
} }
m_cursorHidden = false; m_cursorHidden = false;
if (m_fakeDraggingStarted) {
// TODO: use real file extension
fakeDragging("txt", 3, m_xCursor, m_yCursor);
fakeMouseButton(kButtonLeft, true);
}
} }
void void
@ -1409,8 +1468,8 @@ COSXScreen::getScrollSpeedFactor() const
void void
COSXScreen::enableDragTimer(bool enable) COSXScreen::enableDragTimer(bool enable)
{ {
UInt32 modifiers; UInt32 modifiers;
MouseTrackingResult res; MouseTrackingResult res;
if (enable && m_dragTimer == NULL) { if (enable && m_dragTimer == NULL) {
m_dragTimer = m_events->newTimer(0.01, NULL); m_dragTimer = m_events->newTimer(0.01, NULL);
@ -1430,8 +1489,8 @@ void
COSXScreen::handleDrag(const CEvent&, void*) COSXScreen::handleDrag(const CEvent&, void*)
{ {
Point p; Point p;
UInt32 modifiers; UInt32 modifiers;
MouseTrackingResult res; MouseTrackingResult res;
TrackMouseLocationWithOptions(NULL, 0, 0, &p, &modifiers, &res); TrackMouseLocationWithOptions(NULL, 0, 0, &p, &modifiers, &res);
@ -1848,10 +1907,16 @@ COSXScreen::handleCGInputEvent(CGEventTapProxy proxy,
case kCGEventOtherMouseUp: case kCGEventOtherMouseUp:
screen->onMouseButton(false, CGEventGetIntegerValueField(event, kCGMouseEventButtonNumber) + 1); screen->onMouseButton(false, CGEventGetIntegerValueField(event, kCGMouseEventButtonNumber) + 1);
break; break;
case kCGEventMouseMoved: case kCGEventLeftMouseDragged: {
case kCGEventLeftMouseDragged: CFStringRef dragInfo = getDraggedFileURL();
char* info = CFStringRefToUTF8String(dragInfo);
LOG((CLOG_DEBUG "drag info: %s", info));
CFRelease(dragInfo);
break;
}
case kCGEventRightMouseDragged: case kCGEventRightMouseDragged:
case kCGEventOtherMouseDragged: case kCGEventOtherMouseDragged:
case kCGEventMouseMoved:
pos = CGEventGetLocation(event); pos = CGEventGetLocation(event);
screen->onMouseMove(pos.x, pos.y); screen->onMouseMove(pos.x, pos.y);
@ -1942,3 +2007,27 @@ COSXScreen::CMouseButtonState::getFirstButtonDown() const
} }
return -1; return -1;
} }
char*
COSXScreen::CFStringRefToUTF8String(CFStringRef aString)
{
if (aString == NULL) {
return NULL;
}
CFIndex length = CFStringGetLength(aString);
CFIndex maxSize = CFStringGetMaximumSizeForEncoding(
length,
kCFStringEncodingUTF8);
char* buffer = (char*)malloc(maxSize);
if (CFStringGetCString(aString, buffer, maxSize, kCFStringEncodingUTF8)) {
return buffer;
}
return NULL;
}
void
COSXScreen::fakeDraggingFiles(CString str)
{
m_fakeDraggingStarted = true;
}

View File

@ -79,7 +79,7 @@ public:
// ISecondaryScreen overrides // ISecondaryScreen overrides
virtual void fakeMouseButton(ButtonID id, bool press); virtual void fakeMouseButton(ButtonID id, bool press);
virtual void fakeMouseMove(SInt32 x, SInt32 y) const; virtual void fakeMouseMove(SInt32 x, SInt32 y);
virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const; virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const;
virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const; virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const;
@ -98,6 +98,10 @@ public:
virtual void setSequenceNumber(UInt32); virtual void setSequenceNumber(UInt32);
virtual bool isPrimary() const; virtual bool isPrimary() const;
virtual void fakeDraggingFiles(CString str);
const CString& getDropTarget() const { return m_dropTarget; }
protected: protected:
// IPlatformScreen overrides // IPlatformScreen overrides
virtual void handleSystemEvent(const CEvent&, void*); virtual void handleSystemEvent(const CEvent&, void*);
@ -191,10 +195,16 @@ private:
CGEventType type, CGEventType type,
CGEventRef event, CGEventRef event,
void* refcon); void* refcon);
static CGEventRef handleCGInputEventSecondary(CGEventTapProxy proxy, static CGEventRef handleCGInputEventSecondary(CGEventTapProxy proxy,
CGEventType type, CGEventType type,
CGEventRef event, CGEventRef event,
void* refcon); void* refcon);
// convert CFString to char*
static char* CFStringRefToUTF8String(CFStringRef aString);
void getDropTargetThread(void*);
private: private:
struct CHotKeyItem { struct CHotKeyItem {
public: public:
@ -334,6 +344,10 @@ private:
bool m_autoShowHideCursor; bool m_autoShowHideCursor;
IEventQueue* m_events; IEventQueue* m_events;
bool m_fakeDraggingStarted;
CThread* m_getDropTargetThread;
CString m_dropTarget;
}; };
#endif #endif

View File

@ -45,6 +45,8 @@ public:
newTimer(double duration, bool oneShot) const; newTimer(double duration, bool oneShot) const;
virtual void deleteTimer(CEventQueueTimer*) const; virtual void deleteTimer(CEventQueueTimer*) const;
virtual void cacheCurrentEventQueueRef() {}
private: private:
void flush(); void flush();

View File

@ -832,7 +832,7 @@ CXWindowsScreen::fakeMouseButton(ButtonID button, bool press)
} }
void void
CXWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y) const CXWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y)
{ {
if (m_xinerama && m_xtestIsXineramaUnaware) { if (m_xinerama && m_xtestIsXineramaUnaware) {
XWarpPointer(m_display, None, m_root, 0, 0, 0, 0, x, y); XWarpPointer(m_display, None, m_root, 0, 0, 0, 0, x, y);

View File

@ -66,7 +66,7 @@ public:
// ISecondaryScreen overrides // ISecondaryScreen overrides
virtual void fakeMouseButton(ButtonID id, bool press); virtual void fakeMouseButton(ButtonID id, bool press);
virtual void fakeMouseMove(SInt32 x, SInt32 y) const; virtual void fakeMouseMove(SInt32 x, SInt32 y);
virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const; virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const;
virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const; virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const;

View File

@ -79,6 +79,7 @@ public:
virtual void screensaver(bool activate) = 0; virtual void screensaver(bool activate) = 0;
virtual void resetOptions() = 0; virtual void resetOptions() = 0;
virtual void setOptions(const COptionsList& options) = 0; virtual void setOptions(const COptionsList& options) = 0;
virtual void draggingInfoSending(UInt32 fileCount, const char* data, size_t dataSize) = 0;
virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize) = 0; virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize) = 0;
virtual CString getName() const; virtual CString getName() const;

View File

@ -85,6 +85,7 @@ public:
virtual void resetOptions() = 0; virtual void resetOptions() = 0;
virtual void setOptions(const COptionsList& options) = 0; virtual void setOptions(const COptionsList& options) = 0;
virtual void cryptoIv(const UInt8* iv) = 0; virtual void cryptoIv(const UInt8* iv) = 0;
virtual void draggingInfoSending(UInt32 fileCount, const char* data, size_t dataSize) = 0;
virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize) = 0; virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize) = 0;
private: private:

View File

@ -365,6 +365,13 @@ CClientProxy1_0::cryptoIv(const UInt8* iv)
LOG((CLOG_DEBUG "cryptoIv not supported")); LOG((CLOG_DEBUG "cryptoIv not supported"));
} }
void
CClientProxy1_0::draggingInfoSending(UInt32 fileCount, const char* data, size_t dataSize)
{
// ignore -- not supported in protocol 1.0
LOG((CLOG_DEBUG "draggingInfoSending not supported"));
}
void void
CClientProxy1_0::fileChunkSending(UInt8 mark, char* data, size_t dataSize) CClientProxy1_0::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
{ {

View File

@ -60,6 +60,7 @@ public:
virtual void resetOptions(); virtual void resetOptions();
virtual void setOptions(const COptionsList& options); virtual void setOptions(const COptionsList& options);
virtual void cryptoIv(const UInt8* iv); virtual void cryptoIv(const UInt8* iv);
virtual void draggingInfoSending(UInt32 fileCount, const char* data, size_t dataSize);
virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize); virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize);
protected: protected:

View File

@ -40,6 +40,14 @@ CClientProxy1_5::~CClientProxy1_5()
{ {
} }
void
CClientProxy1_5::draggingInfoSending(UInt32 fileCount, const char* data, size_t dataSize)
{
CString info(data, dataSize);
CProtocolUtil::writef(getStream(), kMsgDDragInfo, fileCount, &info);
}
void void
CClientProxy1_5::fileChunkSending(UInt8 mark, char* data, size_t dataSize) CClientProxy1_5::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
{ {
@ -79,7 +87,7 @@ void
CClientProxy1_5::fileChunkReceived() CClientProxy1_5::fileChunkReceived()
{ {
// parse // parse
UInt8 mark; UInt8 mark = 0;
CString content; CString content;
CProtocolUtil::readf(getStream(), kMsgDFileTransfer + 4, &mark, &content); CProtocolUtil::readf(getStream(), kMsgDFileTransfer + 4, &mark, &content);
@ -113,7 +121,7 @@ CClientProxy1_5::fileChunkReceived()
break; break;
case kFileEnd: case kFileEnd:
m_events->addEvent(CEvent(m_events->forIScreen().fileRecieveComplete(), server)); m_events->addEvent(CEvent(m_events->forIScreen().fileRecieveCompleted(), server));
if (CLOG->getFilter() >= kDEBUG2) { if (CLOG->getFilter() >= kDEBUG2) {
LOG((CLOG_DEBUG2 "file data transfer finished")); LOG((CLOG_DEBUG2 "file data transfer finished"));
m_elapsedTime += m_stopwatch.getTime(); m_elapsedTime += m_stopwatch.getTime();

View File

@ -29,6 +29,7 @@ public:
CClientProxy1_5(const CString& name, synergy::IStream* adoptedStream, CServer* server, IEventQueue* events); CClientProxy1_5(const CString& name, synergy::IStream* adoptedStream, CServer* server, IEventQueue* events);
~CClientProxy1_5(); ~CClientProxy1_5();
virtual void draggingInfoSending(UInt32 fileCount, const char* data, size_t dataSize);
virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize); virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize);
virtual bool parseMessage(const UInt8* code); virtual bool parseMessage(const UInt8* code);
void fileChunkReceived(); void fileChunkReceived();

View File

@ -249,6 +249,12 @@ CPrimaryClient::screensaver(bool)
// ignore // ignore
} }
void
CPrimaryClient::draggingInfoSending(UInt32 fileCount, const char* data, size_t dataSize)
{
// ignore
}
void void
CPrimaryClient::fileChunkSending(UInt8 mark, char* data, size_t dataSize) CPrimaryClient::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
{ {

View File

@ -144,6 +144,7 @@ public:
virtual void screensaver(bool activate); virtual void screensaver(bool activate);
virtual void resetOptions(); virtual void resetOptions();
virtual void setOptions(const COptionsList& options); virtual void setOptions(const COptionsList& options);
virtual void draggingInfoSending(UInt32 fileCount, const char* data, size_t dataSize);
virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize); virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize);
private: private:

View File

@ -37,6 +37,7 @@
#include "CThread.h" #include "CThread.h"
#include "TMethodJob.h" #include "TMethodJob.h"
#include "CFileChunker.h" #include "CFileChunker.h"
#include "CDragInformation.h"
#include <cstring> #include <cstring>
#include <cstdlib> #include <cstdlib>
#include <sstream> #include <sstream>
@ -167,10 +168,10 @@ CServer::CServer(CConfig& config, CPrimaryClient* primaryClient, CScreen* screen
this, this,
new TMethodEventJob<CServer>(this, new TMethodEventJob<CServer>(this,
&CServer::handleFileChunkSendingEvent)); &CServer::handleFileChunkSendingEvent));
m_events->adoptHandler(m_events->forIScreen().fileRecieveComplete(), m_events->adoptHandler(m_events->forIScreen().fileRecieveCompleted(),
this, this,
new TMethodEventJob<CServer>(this, new TMethodEventJob<CServer>(this,
&CServer::handleFileRecieveCompleteEvent)); &CServer::handleFileRecieveCompletedEvent));
// add connection // add connection
addClient(m_primaryClient); addClient(m_primaryClient);
@ -1472,9 +1473,9 @@ CServer::handleFileChunkSendingEvent(const CEvent& event, void*)
} }
void void
CServer::handleFileRecieveCompleteEvent(const CEvent& event, void*) CServer::handleFileRecieveCompletedEvent(const CEvent& event, void*)
{ {
onFileRecieveComplete(); onFileRecieveCompleted();
} }
void void
@ -1737,8 +1738,24 @@ CServer::onMouseMovePrimary(SInt32 x, SInt32 y)
// should we switch or not? // should we switch or not?
if (isSwitchOkay(newScreen, dir, x, y, xc, yc)) { if (isSwitchOkay(newScreen, dir, x, y, xc, yc)) {
if (m_screen->getDraggingStarted() && m_active != newScreen) {
CString& dragFileList = m_screen->getDraggingFileDir();
size_t size = dragFileList.size() + 1;
char* fileList = new char[size];
memcpy(fileList, dragFileList.c_str(), size);
fileList[size - 1] = '\0';
UInt32 fileCount = 1;
LOG((CLOG_DEBUG2 "sending drag information to client"));
LOG((CLOG_DEBUG3 "dragging file list: %s", fileList));
LOG((CLOG_DEBUG3 "dragging file list string size: %i", size));
newScreen->draggingInfoSending(fileCount, fileList, size);
m_screen->setDraggingStarted(false);
}
// switch screen // switch screen
switchScreen(newScreen, x, y, false); switchScreen(newScreen, x, y, false);
return true; return true;
} }
else { else {
@ -1930,7 +1947,7 @@ CServer::onFileChunkSending(const void* data)
} }
void void
CServer::onFileRecieveComplete() CServer::onFileRecieveCompleted()
{ {
if (isReceivedFileSizeValid()) { if (isReceivedFileSizeValid()) {
if (!m_fileTransferDes.empty()) { if (!m_fileTransferDes.empty()) {

View File

@ -310,7 +310,7 @@ private:
void handleFakeInputBeginEvent(const CEvent&, void*); void handleFakeInputBeginEvent(const CEvent&, void*);
void handleFakeInputEndEvent(const CEvent&, void*); void handleFakeInputEndEvent(const CEvent&, void*);
void handleFileChunkSendingEvent(const CEvent&, void*); void handleFileChunkSendingEvent(const CEvent&, void*);
void handleFileRecieveCompleteEvent(const CEvent&, void*); void handleFileRecieveCompletedEvent(const CEvent&, void*);
// event processing // event processing
void onClipboardChanged(CBaseClientProxy* sender, void onClipboardChanged(CBaseClientProxy* sender,
@ -327,7 +327,7 @@ private:
void onMouseMoveSecondary(SInt32 dx, SInt32 dy); void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
void onMouseWheel(SInt32 xDelta, SInt32 yDelta); void onMouseWheel(SInt32 xDelta, SInt32 yDelta);
void onFileChunkSending(const void* data); void onFileChunkSending(const void* data);
void onFileRecieveComplete(); void onFileRecieveCompleted();
// add client to list and attach event handlers for client // add client to list and attach event handlers for client
bool addClient(CBaseClientProxy*); bool addClient(CBaseClientProxy*);

View File

@ -50,6 +50,10 @@
#include "COSXScreen.h" #include "COSXScreen.h"
#endif #endif
#if defined(__APPLE__)
#include "COSXDragSimulator.h"
#endif
#include <iostream> #include <iostream>
#include <stdio.h> #include <stdio.h>
@ -531,7 +535,17 @@ CClientApp::mainLoop()
// later. the timer installed by startClient() will take care of // later. the timer installed by startClient() will take care of
// that. // that.
DAEMON_RUNNING(true); DAEMON_RUNNING(true);
#if defined(__APPLE__)
CThread thread(
new TMethodJob<CClientApp>(
this, &CClientApp::runEventsLoop,
NULL));
runCocoaApp();
#else
m_events->loop(); m_events->loop();
#endif
DAEMON_RUNNING(false); DAEMON_RUNNING(false);
// close down // close down
@ -612,3 +626,10 @@ CClientApp::startNode()
m_bye(kExitFailed); m_bye(kExitFailed);
} }
} }
void
CClientApp::runEventsLoop(void*)
{
m_events->cacheCurrentEventQueueRef();
m_events->loop();
}

View File

@ -85,6 +85,7 @@ public:
private: private:
virtual bool parseArg(const int& argc, const char* const* argv, int& i); virtual bool parseArg(const int& argc, const char* const* argv, int& i);
void runEventsLoop(void*);
private: private:
CClient* s_client; CClient* s_client;

View File

@ -0,0 +1,57 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software 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 COPYING 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 "CDragInformation.h"
#include "CLog.h"
using namespace std;
void
CDragInformation::parseDragInfo(CDragFileList& dragFileList, UInt32 fileNum, CString data)
{
size_t startPos = 0;
size_t findResult1 = 0;
size_t findResult2 = 0;
dragFileList.clear();
while (fileNum) {
findResult1 = data.find('\0', startPos);
findResult2 = data.find_last_of("\\", findResult1);
if (findResult1 == startPos) {
//TODO: file number does not match, something goes wrong
break;
}
if (findResult1 - findResult2 > 1) {
dragFileList.push_back(data.substr(findResult2 + 1, findResult1 - findResult2));
}
startPos = findResult1 + 1;
--fileNum;
}
}
CString
CDragInformation::getDragFileExtension(CString fileName)
{
size_t findResult = -1;
findResult = fileName.find_last_of(".", fileName.size());
if (findResult != -1) {
return fileName.substr(findResult + 1, fileName.size() - findResult - 1);
}
else {
return "";
}
}

View File

@ -0,0 +1,34 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software 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 COPYING 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 "stdvector.h"
#include "CString.h"
#include "BasicTypes.h"
typedef std::vector<CString> CDragFileList;
class CDragInformation {
public:
CDragInformation() { }
~CDragInformation() { }
static void parseDragInfo(CDragFileList& dragFileList, UInt32 fileNum, CString data);
static CString getDragFileExtension(CString fileName);
};

View File

@ -48,6 +48,7 @@ set(inc
CArgsBase.h CArgsBase.h
IAppUtil.h IAppUtil.h
CFileChunker.h CFileChunker.h
CDragInformation.h
) )
set(src set(src
@ -75,6 +76,7 @@ set(src
CAppUtil.cpp CAppUtil.cpp
CArgsBase.cpp CArgsBase.cpp
CFileChunker.cpp CFileChunker.cpp
CDragInformation.cpp
) )
if (WIN32) if (WIN32)

View File

@ -1,119 +1,126 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Bolton Software Ltd. * Copyright (C) 2012 Bolton Software Ltd.
* Copyright (C) 2004 Chris Schoeneman * Copyright (C) 2004 Chris Schoeneman
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef CPLATFORMSCREEN_H #ifndef CPLATFORMSCREEN_H
#define CPLATFORMSCREEN_H #define CPLATFORMSCREEN_H
#include "IPlatformScreen.h" #include "IPlatformScreen.h"
#include <stdexcept>
//! Base screen implementation
/*! //! Base screen implementation
This screen implementation is the superclass of all other screen /*!
implementations. It implements a handful of methods and requires This screen implementation is the superclass of all other screen
subclasses to implement the rest. implementations. It implements a handful of methods and requires
*/ subclasses to implement the rest.
class CPlatformScreen : public IPlatformScreen { */
public: class CPlatformScreen : public IPlatformScreen {
CPlatformScreen(IEventQueue* events); public:
virtual ~CPlatformScreen(); CPlatformScreen(IEventQueue* events);
virtual ~CPlatformScreen();
// IScreen overrides
virtual void* getEventTarget() const = 0; // IScreen overrides
virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0; virtual void* getEventTarget() const = 0;
virtual void getShape(SInt32& x, SInt32& y, virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0;
SInt32& width, SInt32& height) const = 0; virtual void getShape(SInt32& x, SInt32& y,
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0; SInt32& width, SInt32& height) const = 0;
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
// IPrimaryScreen overrides
virtual void reconfigure(UInt32 activeSides) = 0; // IPrimaryScreen overrides
virtual void warpCursor(SInt32 x, SInt32 y) = 0; virtual void reconfigure(UInt32 activeSides) = 0;
virtual UInt32 registerHotKey(KeyID key, virtual void warpCursor(SInt32 x, SInt32 y) = 0;
KeyModifierMask mask) = 0; virtual UInt32 registerHotKey(KeyID key,
virtual void unregisterHotKey(UInt32 id) = 0; KeyModifierMask mask) = 0;
virtual void fakeInputBegin() = 0; virtual void unregisterHotKey(UInt32 id) = 0;
virtual void fakeInputEnd() = 0; virtual void fakeInputBegin() = 0;
virtual SInt32 getJumpZoneSize() const = 0; virtual void fakeInputEnd() = 0;
virtual bool isAnyMouseButtonDown(UInt32& buttonID) const = 0; virtual SInt32 getJumpZoneSize() const = 0;
virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0; virtual bool isAnyMouseButtonDown(UInt32& buttonID) const = 0;
virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0;
// ISecondaryScreen overrides
virtual void fakeMouseButton(ButtonID id, bool press) = 0; // ISecondaryScreen overrides
virtual void fakeMouseMove(SInt32 x, SInt32 y) const = 0; virtual void fakeMouseButton(ButtonID id, bool press) = 0;
virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const = 0; virtual void fakeMouseMove(SInt32 x, SInt32 y) = 0;
virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const = 0; virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const = 0;
virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const = 0;
// IKeyState overrides
virtual void updateKeyMap(); // IKeyState overrides
virtual void updateKeyState(); virtual void updateKeyMap();
virtual void setHalfDuplexMask(KeyModifierMask); virtual void updateKeyState();
virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, virtual void setHalfDuplexMask(KeyModifierMask);
KeyButton button); virtual void fakeKeyDown(KeyID id, KeyModifierMask mask,
virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask, KeyButton button);
SInt32 count, KeyButton button); virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask,
virtual bool fakeKeyUp(KeyButton button); SInt32 count, KeyButton button);
virtual void fakeAllKeysUp(); virtual bool fakeKeyUp(KeyButton button);
virtual bool fakeCtrlAltDel(); virtual void fakeAllKeysUp();
virtual bool isKeyDown(KeyButton) const; virtual bool fakeCtrlAltDel();
virtual KeyModifierMask virtual bool isKeyDown(KeyButton) const;
getActiveModifiers() const; virtual KeyModifierMask
virtual KeyModifierMask getActiveModifiers() const;
pollActiveModifiers() const; virtual KeyModifierMask
virtual SInt32 pollActiveGroup() const; pollActiveModifiers() const;
virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const; virtual SInt32 pollActiveGroup() const;
virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const;
virtual CString& getDraggingFileDir() { return m_draggingFileDir; }
virtual void setDraggingStarted(bool started) { m_draggingStarted = started; }
// IPlatformScreen overrides virtual bool getDraggingStarted() { return m_draggingStarted; }
virtual void enable() = 0; virtual CString& getDraggingFileDir() { return m_draggingFileDir; }
virtual void disable() = 0;
virtual void enter() = 0; // IPlatformScreen overrides
virtual bool leave() = 0; virtual void enable() = 0;
virtual bool setClipboard(ClipboardID, const IClipboard*) = 0; virtual void disable() = 0;
virtual void checkClipboards() = 0; virtual void enter() = 0;
virtual void openScreensaver(bool notify) = 0; virtual bool leave() = 0;
virtual void closeScreensaver() = 0; virtual bool setClipboard(ClipboardID, const IClipboard*) = 0;
virtual void screensaver(bool activate) = 0; virtual void checkClipboards() = 0;
virtual void resetOptions() = 0; virtual void openScreensaver(bool notify) = 0;
virtual void setOptions(const COptionsList& options) = 0; virtual void closeScreensaver() = 0;
virtual void setSequenceNumber(UInt32) = 0; virtual void screensaver(bool activate) = 0;
virtual bool isPrimary() const = 0; virtual void resetOptions() = 0;
virtual void setOptions(const COptionsList& options) = 0;
protected: virtual void setSequenceNumber(UInt32) = 0;
//! Update mouse buttons virtual bool isPrimary() const = 0;
/*!
Subclasses must implement this method to update their internal mouse virtual void fakeDraggingFiles(CString str) { throw std::runtime_error("fakeDraggingFiles not implemented"); }
button mapping and, if desired, state tracking. virtual const CString&
*/ getDropTarget() const { throw std::runtime_error("getDropTarget not implemented"); }
virtual void updateButtons() = 0;
protected:
//! Get the key state //! Update mouse buttons
/*! /*!
Subclasses must implement this method to return the platform specific Subclasses must implement this method to update their internal mouse
key state object that each subclass must have. button mapping and, if desired, state tracking.
*/ */
virtual IKeyState* getKeyState() const = 0; virtual void updateButtons() = 0;
// IPlatformScreen overrides //! Get the key state
virtual void handleSystemEvent(const CEvent& event, void*) = 0; /*!
Subclasses must implement this method to return the platform specific
protected: key state object that each subclass must have.
CString m_draggingFileDir; */
bool m_draggingStarted; virtual IKeyState* getKeyState() const = 0;
};
// IPlatformScreen overrides
#endif virtual void handleSystemEvent(const CEvent& event, void*) = 0;
protected:
CString m_draggingFileDir;
bool m_draggingStarted;
};
#endif

View File

@ -415,12 +415,36 @@ CScreen::pollActiveModifiers() const
return m_screen->pollActiveModifiers(); return m_screen->pollActiveModifiers();
} }
bool
CScreen::getDraggingStarted() const
{
return m_screen->getDraggingStarted();
}
void
CScreen::setDraggingStarted(bool started)
{
m_screen->setDraggingStarted(started);
}
void
CScreen::startDraggingFiles(CString str)
{
m_screen->fakeDraggingFiles(str);
}
CString& CString&
CScreen::getDraggingFileDir() const CScreen::getDraggingFileDir() const
{ {
return m_screen->getDraggingFileDir(); return m_screen->getDraggingFileDir();
} }
const CString&
CScreen::getDropTarget() const
{
return m_screen->getDropTarget();
}
void* void*
CScreen::getEventTarget() const CScreen::getEventTarget() const
{ {

View File

@ -219,6 +219,12 @@ public:
*/ */
void fakeInputEnd(); void fakeInputEnd();
//! Change dragging status
void setDraggingStarted(bool started);
//! Fake a files dragging operation
void startDraggingFiles(CString str);
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{
@ -267,10 +273,18 @@ public:
*/ */
KeyModifierMask pollActiveModifiers() const; KeyModifierMask pollActiveModifiers() const;
//! Check if dragging has started.
bool getDraggingStarted() const;
//! Get dragging file's directory. //! Get dragging file's directory.
CString& getDraggingFileDir() const; CString& getDraggingFileDir() const;
//! Get drop target directory.
const CString& getDropTarget() const;
//@} //@}
// IScreen overrides // IScreen overrides

View File

@ -130,6 +130,9 @@ public:
*/ */
virtual void setSequenceNumber(UInt32) = 0; virtual void setSequenceNumber(UInt32) = 0;
//! Change dragging status
virtual void setDraggingStarted(bool started) = 0;
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{
@ -162,7 +165,7 @@ public:
// ISecondaryScreen overrides // ISecondaryScreen overrides
virtual void fakeMouseButton(ButtonID id, bool press) = 0; virtual void fakeMouseButton(ButtonID id, bool press) = 0;
virtual void fakeMouseMove(SInt32 x, SInt32 y) const = 0; virtual void fakeMouseMove(SInt32 x, SInt32 y) = 0;
virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const = 0; virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const = 0;
virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const = 0; virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const = 0;
@ -186,7 +189,12 @@ public:
virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const = 0; virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const = 0;
virtual CString& getDraggingFileDir() = 0; virtual CString& getDraggingFileDir() = 0;
virtual bool getDraggingStarted() = 0;
virtual void fakeDraggingFiles(CString str) = 0;
virtual const CString&
getDropTarget() const = 0;
protected: protected:
//! Handle system event //! Handle system event
/*! /*!

View File

@ -44,7 +44,7 @@ public:
/*! /*!
Synthesize a mouse move to the absolute coordinates \c x,y. Synthesize a mouse move to the absolute coordinates \c x,y.
*/ */
virtual void fakeMouseMove(SInt32 x, SInt32 y) const = 0; virtual void fakeMouseMove(SInt32 x, SInt32 y) = 0;
//! Fake mouse move //! Fake mouse move
/*! /*!

View File

@ -46,6 +46,7 @@ const char* kMsgDInfo = "DINF%2i%2i%2i%2i%2i%2i%2i";
const char* kMsgDSetOptions = "DSOP%4I"; const char* kMsgDSetOptions = "DSOP%4I";
const char* kMsgDCryptoIv = "DCIV%s"; const char* kMsgDCryptoIv = "DCIV%s";
const char* kMsgDFileTransfer = "DFTR%1i%s"; const char* kMsgDFileTransfer = "DFTR%1i%s";
const char* kMsgDDragInfo = "DDRG%2i%s";
const char* kMsgQInfo = "QINF"; const char* kMsgQInfo = "QINF";
const char* kMsgEIncompatible = "EICV%2i%2i"; const char* kMsgEIncompatible = "EICV%2i%2i";
const char* kMsgEBusy = "EBSY"; const char* kMsgEBusy = "EBSY";

View File

@ -263,6 +263,12 @@ extern const char* kMsgDCryptoIv;
// 2 means the file transfer is finished. // 2 means the file transfer is finished.
extern const char* kMsgDFileTransfer; extern const char* kMsgDFileTransfer;
// drag infomation: primary <-> secondary
// transfer drag infomation. The first 2 bytes are used for storing
// the number of dragging objects. Then the following string consists
// of each object's directory.
extern const char* kMsgDDragInfo;
// //
// query codes // query codes
// //

View File

@ -92,16 +92,16 @@ public:
void sendMockData(void* eventTarget); void sendMockData(void* eventTarget);
void sendToClient_mockData_handleClientConnected(const CEvent&, void* vlistener); void sendToClient_mockData_handleClientConnected(const CEvent&, void* vlistener);
void sendToClient_mockData_fileRecieveComplete(const CEvent&, void*); void sendToClient_mockData_fileRecieveCompleted(const CEvent&, void*);
void sendToClient_mockFile_handleClientConnected(const CEvent&, void* vlistener); void sendToClient_mockFile_handleClientConnected(const CEvent&, void* vlistener);
void sendToClient_mockFile_fileRecieveComplete(const CEvent& event, void*); void sendToClient_mockFile_fileRecieveCompleted(const CEvent& event, void*);
void sendToServer_mockData_handleClientConnected(const CEvent&, void* vlistener); void sendToServer_mockData_handleClientConnected(const CEvent&, void* vlistener);
void sendToServer_mockData_fileRecieveComplete(const CEvent& event, void*); void sendToServer_mockData_fileRecieveCompleted(const CEvent& event, void*);
void sendToServer_mockFile_handleClientConnected(const CEvent&, void* vlistener); void sendToServer_mockFile_handleClientConnected(const CEvent&, void* vlistener);
void sendToServer_mockFile_fileRecieveComplete(const CEvent& event, void*); void sendToServer_mockFile_fileRecieveCompleted(const CEvent& event, void*);
public: public:
CTestEventQueue m_events; CTestEventQueue m_events;
@ -159,16 +159,16 @@ TEST_F(NetworkTests, sendToClient_mockData)
CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions); CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions);
m_events.adoptHandler( m_events.adoptHandler(
m_events.forIScreen().fileRecieveComplete(), &client, m_events.forIScreen().fileRecieveCompleted(), &client,
new TMethodEventJob<NetworkTests>( new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendToClient_mockData_fileRecieveComplete)); this, &NetworkTests::sendToClient_mockData_fileRecieveCompleted));
client.connect(); client.connect();
m_events.initQuitTimeout(10); m_events.initQuitTimeout(10);
m_events.loop(); m_events.loop();
m_events.removeHandler(m_events.forCClientListener().connected(), &listener); m_events.removeHandler(m_events.forCClientListener().connected(), &listener);
m_events.removeHandler(m_events.forIScreen().fileRecieveComplete(), &client); m_events.removeHandler(m_events.forIScreen().fileRecieveCompleted(), &client);
m_events.cleanupQuitTimeout(); m_events.cleanupQuitTimeout();
} }
@ -220,16 +220,16 @@ TEST_F(NetworkTests, sendToClient_mockFile)
CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions); CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions);
m_events.adoptHandler( m_events.adoptHandler(
m_events.forIScreen().fileRecieveComplete(), &client, m_events.forIScreen().fileRecieveCompleted(), &client,
new TMethodEventJob<NetworkTests>( new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendToClient_mockFile_fileRecieveComplete)); this, &NetworkTests::sendToClient_mockFile_fileRecieveCompleted));
client.connect(); client.connect();
m_events.initQuitTimeout(10); m_events.initQuitTimeout(10);
m_events.loop(); m_events.loop();
m_events.removeHandler(m_events.forCClientListener().connected(), &listener); m_events.removeHandler(m_events.forCClientListener().connected(), &listener);
m_events.removeHandler(m_events.forIScreen().fileRecieveComplete(), &client); m_events.removeHandler(m_events.forIScreen().fileRecieveCompleted(), &client);
m_events.cleanupQuitTimeout(); m_events.cleanupQuitTimeout();
} }
@ -281,16 +281,16 @@ TEST_F(NetworkTests, sendToServer_mockData)
this, &NetworkTests::sendToServer_mockData_handleClientConnected, &client)); this, &NetworkTests::sendToServer_mockData_handleClientConnected, &client));
m_events.adoptHandler( m_events.adoptHandler(
m_events.forIScreen().fileRecieveComplete(), &server, m_events.forIScreen().fileRecieveCompleted(), &server,
new TMethodEventJob<NetworkTests>( new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendToServer_mockData_fileRecieveComplete)); this, &NetworkTests::sendToServer_mockData_fileRecieveCompleted));
client.connect(); client.connect();
m_events.initQuitTimeout(10); m_events.initQuitTimeout(10);
m_events.loop(); m_events.loop();
m_events.removeHandler(m_events.forCClientListener().connected(), &listener); m_events.removeHandler(m_events.forCClientListener().connected(), &listener);
m_events.removeHandler(m_events.forIScreen().fileRecieveComplete(), &server); m_events.removeHandler(m_events.forIScreen().fileRecieveCompleted(), &server);
m_events.cleanupQuitTimeout(); m_events.cleanupQuitTimeout();
} }
@ -342,16 +342,16 @@ TEST_F(NetworkTests, sendToServer_mockFile)
this, &NetworkTests::sendToServer_mockFile_handleClientConnected, &client)); this, &NetworkTests::sendToServer_mockFile_handleClientConnected, &client));
m_events.adoptHandler( m_events.adoptHandler(
m_events.forIScreen().fileRecieveComplete(), &server, m_events.forIScreen().fileRecieveCompleted(), &server,
new TMethodEventJob<NetworkTests>( new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendToServer_mockFile_fileRecieveComplete)); this, &NetworkTests::sendToServer_mockFile_fileRecieveCompleted));
client.connect(); client.connect();
m_events.initQuitTimeout(10); m_events.initQuitTimeout(10);
m_events.loop(); m_events.loop();
m_events.removeHandler(m_events.forCClientListener().connected(), &listener); m_events.removeHandler(m_events.forCClientListener().connected(), &listener);
m_events.removeHandler(m_events.forIScreen().fileRecieveComplete(), &server); m_events.removeHandler(m_events.forIScreen().fileRecieveCompleted(), &server);
m_events.cleanupQuitTimeout(); m_events.cleanupQuitTimeout();
} }
@ -374,7 +374,7 @@ NetworkTests::sendToClient_mockData_handleClientConnected(const CEvent&, void* v
} }
void void
NetworkTests::sendToClient_mockData_fileRecieveComplete(const CEvent& event, void*) NetworkTests::sendToClient_mockData_fileRecieveCompleted(const CEvent& event, void*)
{ {
CClient* client = reinterpret_cast<CClient*>(event.getTarget()); CClient* client = reinterpret_cast<CClient*>(event.getTarget());
EXPECT_TRUE(client->isReceivedFileSizeValid()); EXPECT_TRUE(client->isReceivedFileSizeValid());
@ -401,7 +401,7 @@ NetworkTests::sendToClient_mockFile_handleClientConnected(const CEvent&, void* v
} }
void void
NetworkTests::sendToClient_mockFile_fileRecieveComplete(const CEvent& event, void*) NetworkTests::sendToClient_mockFile_fileRecieveCompleted(const CEvent& event, void*)
{ {
CClient* client = reinterpret_cast<CClient*>(event.getTarget()); CClient* client = reinterpret_cast<CClient*>(event.getTarget());
EXPECT_TRUE(client->isReceivedFileSizeValid()); EXPECT_TRUE(client->isReceivedFileSizeValid());
@ -417,7 +417,7 @@ NetworkTests::sendToServer_mockData_handleClientConnected(const CEvent&, void* v
} }
void void
NetworkTests::sendToServer_mockData_fileRecieveComplete(const CEvent& event, void*) NetworkTests::sendToServer_mockData_fileRecieveCompleted(const CEvent& event, void*)
{ {
CServer* server = reinterpret_cast<CServer*>(event.getTarget()); CServer* server = reinterpret_cast<CServer*>(event.getTarget());
EXPECT_TRUE(server->isReceivedFileSizeValid()); EXPECT_TRUE(server->isReceivedFileSizeValid());
@ -433,7 +433,7 @@ NetworkTests::sendToServer_mockFile_handleClientConnected(const CEvent&, void* v
} }
void void
NetworkTests::sendToServer_mockFile_fileRecieveComplete(const CEvent& event, void*) NetworkTests::sendToServer_mockFile_fileRecieveCompleted(const CEvent& event, void*)
{ {
CServer* server = reinterpret_cast<CServer*>(event.getTarget()); CServer* server = reinterpret_cast<CServer*>(event.getTarget());
EXPECT_TRUE(server->isReceivedFileSizeValid()); EXPECT_TRUE(server->isReceivedFileSizeValid());

View File

@ -61,6 +61,7 @@ public:
MOCK_METHOD0(forIKeyState, IKeyStateEvents&()); MOCK_METHOD0(forIKeyState, IKeyStateEvents&());
MOCK_METHOD0(forIPrimaryScreen, IPrimaryScreenEvents&()); MOCK_METHOD0(forIPrimaryScreen, IPrimaryScreenEvents&());
MOCK_METHOD0(forIScreen, IScreenEvents&()); MOCK_METHOD0(forIScreen, IScreenEvents&());
MOCK_METHOD0(cacheCurrentEventQueueRef, void());
}; };
#endif #endif