From 343f88e3048887e83cc91bb710510b3aa618f779 Mon Sep 17 00:00:00 2001
From: dknn <yoann.blein@free.fr>
Date: Sat, 4 Aug 2012 11:25:47 +0200
Subject: Add basic UI for viewing remote screen


diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index 1e0e9c2..48ea006 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -43,6 +43,8 @@
 #include <Swift/Controllers/SettingConstants.h>
 #include <Swiften/Client/StanzaChannel.h>
 #include <Swift/Controllers/WhiteboardManager.h>
+#include <Swift/Controllers/ScreenSharing/ScreenSharingController.h>
+#include <Swiften/ScreenSharing/IncomingScreenSharing.h>
 
 namespace Swift {
 
@@ -70,6 +72,7 @@ ChatsManager::ChatsManager(
 		MUCSearchWindowFactory* mucSearchWindowFactory,
 		ProfileSettingsProvider* profileSettings,
 		FileTransferOverview* ftOverview,
+		ScreenSharingController* ssController,
 		XMPPRoster* roster,
 		bool eagleMode,
 		SettingsProvider* settings,
@@ -82,6 +85,7 @@ ChatsManager::ChatsManager(
 			entityCapsProvider_(entityCapsProvider), 
 			mucManager(mucManager),
 			ftOverview_(ftOverview),
+			ssController_(ssController),
 			roster_(roster),
 			eagleMode_(eagleMode),
 			settings_(settings),
@@ -112,6 +116,7 @@ ChatsManager::ChatsManager(
 	mucSearchController_ = new MUCSearchController(jid_, mucSearchWindowFactory, iqRouter, profileSettings_);
 	mucSearchController_->onMUCSelected.connect(boost::bind(&ChatsManager::handleMUCSelectedAfterSearch, this, _1));
 	ftOverview_->onNewFileTransferController.connect(boost::bind(&ChatsManager::handleNewFileTransferController, this, _1));
+	ssController->onNewIncomingScreenSharing.connect(boost::bind(&ChatsManager::handleNewIncomingScreenSharing, this, _1));
 	whiteboardManager_->onSessionRequest.connect(boost::bind(&ChatsManager::handleWhiteboardSessionRequest, this, _1, _2));
 	whiteboardManager_->onRequestAccepted.connect(boost::bind(&ChatsManager::handleWhiteboardStateChange, this, _1, ChatWindow::WhiteboardAccepted));
 	whiteboardManager_->onSessionTerminate.connect(boost::bind(&ChatsManager::handleWhiteboardStateChange, this, _1, ChatWindow::WhiteboardTerminated));
@@ -664,6 +669,13 @@ void ChatsManager::handleNewFileTransferController(FileTransferController* ftc)
 	chatController->activateChatWindow();
 }
 
+void ChatsManager::handleNewIncomingScreenSharing(boost::shared_ptr<IncomingScreenSharing> iss)
+{
+	ChatController* chatController = getChatControllerOrCreate(iss->getSender());
+//	chatController->handleNewFileTransferController(ftc);
+	chatController->activateChatWindow();
+}
+
 void ChatsManager::handleWhiteboardSessionRequest(const JID& contact, bool senderIsSelf) {
 	ChatController* chatController = getChatControllerOrCreate(contact);
 	chatController->handleWhiteboardSessionRequest(senderIsSelf);
diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h
index 5b8b785..31006b0 100644
--- a/Swift/Controllers/Chat/ChatsManager.h
+++ b/Swift/Controllers/Chat/ChatsManager.h
@@ -50,10 +50,12 @@ namespace Swift {
 	class SettingsProvider;
 	class WhiteboardManager;
 	class HistoryController;
+	class ScreenSharingController;
+	class IncomingScreenSharing;
 	
 	class ChatsManager {
 		public:
-			ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, JoinMUCWindowFactory* joinMUCWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, ProfileSettingsProvider* profileSettings, FileTransferOverview* ftOverview, XMPPRoster* roster, bool eagleMode, SettingsProvider* settings, HistoryController* historyController_, WhiteboardManager* whiteboardManager);
+			ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, JoinMUCWindowFactory* joinMUCWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, ProfileSettingsProvider* profileSettings, FileTransferOverview* ftOverview, ScreenSharingController* ssController, XMPPRoster* roster, bool eagleMode, SettingsProvider* settings, HistoryController* historyController_, WhiteboardManager* whiteboardManager);
 			virtual ~ChatsManager();
 			void setAvatarManager(AvatarManager* avatarManager);
 			void setOnline(bool enabled);
@@ -75,6 +77,7 @@ namespace Swift {
 			void handleBookmarksReady();
 			void handleChatActivity(const JID& jid, const std::string& activity, bool isMUC);
 			void handleNewFileTransferController(FileTransferController*);
+			void handleNewIncomingScreenSharing(boost::shared_ptr<IncomingScreenSharing> iss);
 			void handleWhiteboardSessionRequest(const JID& contact, bool senderIsSelf);
 			void handleWhiteboardStateChange(const JID& contact, const ChatWindow::WhiteboardSessionState state);
 			void appendRecent(const ChatListWindow::Chat& chat);
@@ -130,6 +133,7 @@ namespace Swift {
 			std::list<ChatListWindow::Chat> recentChats_;
 			ProfileSettingsProvider* profileSettings_;
 			FileTransferOverview* ftOverview_;
+			ScreenSharingController* ssController_;
 			XMPPRoster* roster_;
 			bool eagleMode_;
 			bool userWantsReceipts_;
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index 581ff31..17dab36 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -78,6 +78,7 @@
 #include <Swiften/Client/ClientXMLTracer.h>
 #include <Swift/Controllers/SettingConstants.h>
 #include <Swiften/Client/StanzaChannel.h>
+#include "Swift/Controllers/ScreenSharing/ScreenSharingController.h"
 
 namespace Swift {
 
@@ -109,7 +110,8 @@ MainController::MainController(
 			idleDetector_(idleDetector),
 			loginWindow_(NULL) ,
 			useDelayForLatency_(useDelayForLatency),
-			ftOverview_(NULL) {
+			ftOverview_(NULL),
+			ssController_(NULL) {
 	storages_ = NULL;
 	certificateStorage_ = NULL;
 	statusTracker_ = NULL;
@@ -237,6 +239,8 @@ void MainController::resetClient() {
 #endif
 	delete ftOverview_;
 	ftOverview_ = NULL;
+	delete ssController_;
+	ssController_ = NULL;
 	delete rosterController_;
 	rosterController_ = NULL;
 	delete eventNotifier_;
@@ -302,7 +306,8 @@ void MainController::handleConnected() {
 		client_->getFileTransferManager()->startListeningOnPort(randomPort);
 		ftOverview_ = new FileTransferOverview(client_->getFileTransferManager());
 		fileTransferListController_->setFileTransferOverview(ftOverview_);
-		rosterController_ = new RosterController(jid_, client_->getRoster(), client_->getAvatarManager(), uiFactory_, client_->getNickManager(), client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_, client_->getEntityCapsProvider(), ftOverview_);
+		ssController_ = new ScreenSharingController(client_->getScreenSharingManager(), uiFactory_, networkFactories_->getTimerFactory());
+		rosterController_ = new RosterController(jid_, client_->getRoster(), client_->getAvatarManager(), uiFactory_, client_->getNickManager(), client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_, client_->getEntityCapsProvider(), ftOverview_, ssController_);
 		rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2));
 		rosterController_->onSignOutRequest.connect(boost::bind(&MainController::signOut, this));
 		rosterController_->getWindow()->onShowCertificateRequest.connect(boost::bind(&MainController::handleShowCertificateRequest, this));
@@ -320,7 +325,7 @@ void MainController::handleConnected() {
 		historyViewController_ = new HistoryViewController(jid_, uiEventStream_, historyController_, client_->getNickResolver(), client_->getAvatarManager(), client_->getPresenceOracle(), uiFactory_);
 		chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, historyController_, whiteboardManager_);
 #else
-		chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, NULL, whiteboardManager_);
+		chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, ssController_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, NULL, whiteboardManager_);
 #endif
 		
 		client_->onMessageReceived.connect(boost::bind(&ChatsManager::handleIncomingMessage, chatsManager_, _1));
@@ -340,6 +345,10 @@ void MainController::handleConnected() {
 		discoInfo.addFeature(DiscoInfo::JingleFTFeature);
 		discoInfo.addFeature(DiscoInfo::JingleTransportsIBBFeature);
 		discoInfo.addFeature(DiscoInfo::JingleTransportsS5BFeature);
+		// Screen sharing
+		discoInfo.addFeature(DiscoInfo::JingleRTPFeature);
+		discoInfo.addFeature(DiscoInfo::JingleTransportRawUDPFeature);
+		discoInfo.addFeature(DiscoInfo::JingleScreenSharingFeature);
 #endif
 #ifdef SWIFT_EXPERIMENTAL_WB
 		discoInfo.addFeature(DiscoInfo::WhiteboardFeature);
diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h
index 2e5bd05..ad8fef2 100644
--- a/Swift/Controllers/MainController.h
+++ b/Swift/Controllers/MainController.h
@@ -71,6 +71,7 @@ namespace Swift {
 	class AdHocCommandWindowFactory;
 	class FileTransferOverview;
 	class WhiteboardManager;
+	class ScreenSharingController;
 
 	class MainController {
 		public:
@@ -176,5 +177,6 @@ namespace Swift {
 			static const int SecondsToWaitBeforeForceQuitting;
 			FileTransferOverview* ftOverview_;
 			WhiteboardManager* whiteboardManager_;
+			ScreenSharingController* ssController_;
 	};
 }
diff --git a/Swift/Controllers/Roster/ContactRosterItem.h b/Swift/Controllers/Roster/ContactRosterItem.h
index 8389a44..d156b1f 100644
--- a/Swift/Controllers/Roster/ContactRosterItem.h
+++ b/Swift/Controllers/Roster/ContactRosterItem.h
@@ -26,6 +26,7 @@ class ContactRosterItem : public RosterItem {
 		enum Feature {
 			FileTransferFeature,
 			WhiteboardFeature,
+			ScreenSharingFeature,
 		};
 		
 	public:
diff --git a/Swift/Controllers/Roster/RosterController.cpp b/Swift/Controllers/Roster/RosterController.cpp
index ec52993..40fd957 100644
--- a/Swift/Controllers/Roster/RosterController.cpp
+++ b/Swift/Controllers/Roster/RosterController.cpp
@@ -36,6 +36,7 @@
 #include "Swift/Controllers/UIEvents/RenameRosterItemUIEvent.h"
 #include "Swift/Controllers/UIEvents/RenameGroupUIEvent.h"
 #include "Swift/Controllers/UIEvents/SendFileUIEvent.h"
+#include "Swift/Controllers/UIEvents/ShareScreenUIEvent.h"
 #include <Swiften/FileTransfer/FileTransferManager.h>
 #include <Swiften/Client/NickManager.h>
 #include <Swift/Controllers/Intl.h>
@@ -44,14 +45,15 @@
 #include <Swiften/Disco/EntityCapsManager.h>
 #include <Swiften/Jingle/JingleSessionManager.h>
 #include <Swift/Controllers/SettingConstants.h>
+#include "Swift/Controllers/ScreenSharing/ScreenSharingController.h"
 
 namespace Swift {
 
 /**
  * The controller does not gain ownership of these parameters.
  */
-RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter, SettingsProvider* settings, EntityCapsProvider* entityCapsManager, FileTransferOverview* fileTransferOverview)
- : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), mainWindow_(mainWindowFactory_->createMainWindow(uiEventStream)), roster_(new Roster()), offlineFilter_(new OfflineRosterFilter()), nickManager_(nickManager), nickResolver_(nickResolver), uiEventStream_(uiEventStream), entityCapsManager_(entityCapsManager), ftOverview_(fileTransferOverview) {
+RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter, SettingsProvider* settings, EntityCapsProvider* entityCapsManager, FileTransferOverview* fileTransferOverview, ScreenSharingController *ssController)
+	: myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), mainWindow_(mainWindowFactory_->createMainWindow(uiEventStream)), roster_(new Roster()), offlineFilter_(new OfflineRosterFilter()), nickManager_(nickManager), nickResolver_(nickResolver), uiEventStream_(uiEventStream), entityCapsManager_(entityCapsManager), ftOverview_(fileTransferOverview), ssController_(ssController) {
 	assert(fileTransferOverview);
 	iqRouter_ = iqRouter;
 	presenceOracle_ = presenceOracle;
@@ -238,6 +240,10 @@ void RosterController::handleUIEvent(boost::shared_ptr<UIEvent> event) {
 		//TODO add send file dialog to ChatView of receipient jid
 		ftOverview_->sendFile(sendFileEvent->getJID(), sendFileEvent->getFilename());
 	}
+	else if (boost::shared_ptr<ShareScreenUIEvent> shareScreenEvent = boost::dynamic_pointer_cast<ShareScreenUIEvent>(event)) {
+		std::cout << "Create sharing: " << ssController_->createOugoingScreenSharing(shareScreenEvent->jid);
+		std::cout << std::endl;
+	}
 }
 
 void RosterController::setContactGroups(const JID& jid, const std::vector<std::string>& groups) {
@@ -324,6 +330,12 @@ void RosterController::handleOnCapsChanged(const JID& jid) {
 		if (info->hasFeature(DiscoInfo::WhiteboardFeature)) {
 			features.insert(ContactRosterItem::WhiteboardFeature);
 		}
+		if (info->hasFeature(DiscoInfo::JingleFeature)
+				&& info->hasFeature(DiscoInfo::JingleRTPFeature)
+				&& info->hasFeature(DiscoInfo::JingleTransportRawUDPFeature)
+				&& info->hasFeature(DiscoInfo::JingleScreenSharingFeature)) {
+			features.insert(ContactRosterItem::ScreenSharingFeature);
+		}
 		roster_->setAvailableFeatures(jid, features);
 	}
 }
diff --git a/Swift/Controllers/Roster/RosterController.h b/Swift/Controllers/Roster/RosterController.h
index 5e40124..2fb642d 100644
--- a/Swift/Controllers/Roster/RosterController.h
+++ b/Swift/Controllers/Roster/RosterController.h
@@ -39,10 +39,11 @@ namespace Swift {
 	class NickManager;
 	class EntityCapsProvider;
 	class FileTransferManager;
+	class ScreenSharingController;
 	
 	class RosterController {
 		public:
-			RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter_, SettingsProvider* settings, EntityCapsProvider* entityCapsProvider, FileTransferOverview* fileTransferOverview);
+			RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter_, SettingsProvider* settings, EntityCapsProvider* entityCapsProvider, FileTransferOverview* fileTransferOverview, ScreenSharingController* ssController);
 			~RosterController();
 			void showRosterWindow();
 			MainWindow* getWindow() {return mainWindow_;};
@@ -94,6 +95,7 @@ namespace Swift {
 			UIEventStream* uiEventStream_;
 			EntityCapsProvider* entityCapsManager_;
 			FileTransferOverview* ftOverview_;
+			ScreenSharingController* ssController_;
 			
 			boost::bsignals::scoped_connection changeStatusConnection_;
 			boost::bsignals::scoped_connection signOutConnection_;
diff --git a/Swift/Controllers/SConscript b/Swift/Controllers/SConscript
index 7cd017b..2dba9a9 100644
--- a/Swift/Controllers/SConscript
+++ b/Swift/Controllers/SConscript
@@ -74,7 +74,8 @@ if env["SCONS_STAGE"] == "build" :
 			"XMPPURIController.cpp",
 			"ChatMessageSummarizer.cpp",
 			"SettingConstants.cpp",
-			"WhiteboardManager.cpp"
+			"WhiteboardManager.cpp",
+			"ScreenSharing/ScreenSharingController.cpp",
 		])
 
 	env.Append(UNITTEST_SOURCES = [
diff --git a/Swift/Controllers/ScreenSharing/DesktopScreenGrabber.h b/Swift/Controllers/ScreenSharing/DesktopScreenGrabber.h
new file mode 100644
index 0000000..4fac6fe
--- /dev/null
+++ b/Swift/Controllers/ScreenSharing/DesktopScreenGrabber.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2012 Yoann Blein
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+namespace Swift {
+	class Image;
+
+	class DesktopScreenGrabber {
+		public:
+			virtual ~DesktopScreenGrabber() {}
+
+			virtual Image grab() const = 0;
+	};
+}
diff --git a/Swift/Controllers/ScreenSharing/ScreenSharingController.cpp b/Swift/Controllers/ScreenSharing/ScreenSharingController.cpp
new file mode 100644
index 0000000..fd3357d
--- /dev/null
+++ b/Swift/Controllers/ScreenSharing/ScreenSharingController.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2012 Yoann Blein
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "ScreenSharingController.h"
+
+#include <Swiften/ScreenSharing/ScreenSharingManager.h>
+#include <Swiften/ScreenSharing/IncomingScreenSharing.h>
+#include <Swiften/ScreenSharing/OutgoingScreenSharing.h>
+#include <Swiften/ScreenSharing/Image.h>
+#include <Swiften/Network/TimerFactory.h>
+#include <Swiften/Network/Timer.h>
+#include "Swift/QtUI/ScreenSharing/QtDesktopScreenGrabber.h"
+#include "Swift/Controllers/UIInterfaces/RemoteScreenWindowFactory.h"
+#include "Swift/Controllers/UIInterfaces/RemoteScreenWindow.h"
+
+#include <boost/bind.hpp>
+
+namespace Swift {
+
+ScreenSharingController::ScreenSharingController(ScreenSharingManager *screenSharingManager, RemoteScreenWindowFactory* remoteScreenViewerFactory, TimerFactory* timerFactory)
+	: screenSharingManager(screenSharingManager), remoteScreenWindowFactory(remoteScreenViewerFactory), remoteScreenWindow(0),
+	  grabTimer(timerFactory->createTimer(500)), screenGrabber(new QtDesktopScreenGrabber)
+{
+	screenSharingManager->onIncomingScreenSharing.connect(boost::bind(&ScreenSharingController::handleIncomingScreenSharing, this, _1));
+	grabTimer->onTick.connect(boost::bind(&ScreenSharingController::handleGrabTimerTick, this));
+}
+
+ScreenSharingController::~ScreenSharingController()
+{
+	grabTimer->onTick.disconnect(boost::bind(&ScreenSharingController::handleGrabTimerTick, this));
+	delete remoteScreenWindow;
+}
+
+boost::shared_ptr<OutgoingScreenSharing> ScreenSharingController::createOugoingScreenSharing(const JID& to)
+{
+	if (!oss) {
+		oss = screenSharingManager->createOutgoingScreenSharing(to);
+		if (oss) {
+			oss->onReady.connect(boost::bind(&ScreenSharingController::handleOssReady, this));
+			oss->onFinished.connect(boost::bind(&ScreenSharingController::handleOutgoingFinished, this));
+			const Image& image = screenGrabber->grab();
+			oss->start(image.width, image.height);
+		}
+		return oss;
+	}
+	return boost::shared_ptr<OutgoingScreenSharing>();
+}
+
+void ScreenSharingController::handleIncomingScreenSharing(boost::shared_ptr<IncomingScreenSharing> incomingScreenSharing)
+{
+	if (iss) {
+		incomingScreenSharing->cancel();
+	} else {
+		iss = incomingScreenSharing;
+		iss->accept();
+		iss->onFinished.connect(boost::bind(&ScreenSharingController::handleIncomingFinished, this));
+		remoteScreenWindow = remoteScreenWindowFactory->createRemoteScreenViewer(iss);
+//		onNewIncomingScreenSharing(iss);
+	}
+}
+
+void ScreenSharingController::handleGrabTimerTick()
+{
+	if (oss) {
+		grabTimer->start();
+		oss->addImage(screenGrabber->grab());
+	}
+}
+
+void ScreenSharingController::handleOssReady()
+{
+	handleGrabTimerTick();
+}
+
+void ScreenSharingController::handleIncomingFinished()
+{
+	iss->onFinished.disconnect(boost::bind(&ScreenSharingController::handleIncomingFinished, this));
+	iss.reset();
+	delete remoteScreenWindow;
+	remoteScreenWindow = 0;
+}
+
+void ScreenSharingController::handleOutgoingFinished()
+{
+	oss->onReady.disconnect(boost::bind(&ScreenSharingController::handleOssReady, this));
+	oss->onFinished.disconnect(boost::bind(&ScreenSharingController::handleOutgoingFinished, this));
+	oss.reset();
+}
+
+}
diff --git a/Swift/Controllers/ScreenSharing/ScreenSharingController.h b/Swift/Controllers/ScreenSharing/ScreenSharingController.h
new file mode 100644
index 0000000..6bae132
--- /dev/null
+++ b/Swift/Controllers/ScreenSharing/ScreenSharingController.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012 Yoann Blein
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/boost_bsignals.h>
+
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class ScreenSharingManager;
+	class IncomingScreenSharing;
+	class OutgoingScreenSharing;
+	class Timer;
+	class TimerFactory;
+	class DesktopScreenGrabber;
+	class RemoteScreenWindowFactory;
+	class RemoteScreenWindow;
+	class JID;
+
+	class ScreenSharingController {
+		public:
+			ScreenSharingController(ScreenSharingManager* screenSharingManager, RemoteScreenWindowFactory* remoteScreenWindowFactory, TimerFactory* timerFactory);
+			~ScreenSharingController();
+
+			boost::shared_ptr<OutgoingScreenSharing> createOugoingScreenSharing(const JID& to);
+
+		public:
+			boost::signal<void (boost::shared_ptr<IncomingScreenSharing>)> onNewIncomingScreenSharing;
+
+		private:
+			void handleIncomingScreenSharing(boost::shared_ptr<IncomingScreenSharing> incomingScreenSharing);
+			void handleGrabTimerTick();
+			void handleOssReady();
+			void handleIncomingFinished();
+			void handleOutgoingFinished();
+
+		private:
+			ScreenSharingManager* screenSharingManager;
+			RemoteScreenWindowFactory* remoteScreenWindowFactory;
+
+			RemoteScreenWindow* remoteScreenWindow;
+			boost::shared_ptr<Timer> grabTimer;
+			DesktopScreenGrabber* screenGrabber;
+			boost::shared_ptr<IncomingScreenSharing> iss;
+			boost::shared_ptr<OutgoingScreenSharing> oss;
+	};
+}
diff --git a/Swift/Controllers/UIEvents/ShareScreenUIEvent.h b/Swift/Controllers/UIEvents/ShareScreenUIEvent.h
new file mode 100644
index 0000000..de2b670
--- /dev/null
+++ b/Swift/Controllers/UIEvents/ShareScreenUIEvent.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2012 Yoann Blein
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/JID/JID.h>
+#include <Swift/Controllers/UIEvents/UIEvent.h>
+
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class ShareScreenUIEvent : public UIEvent {
+		public:
+			typedef boost::shared_ptr<SendFileUIEvent> ref;
+
+			ShareScreenUIEvent(const JID& jid) : jid(jid) {}
+
+		public:
+			JID jid;
+	};
+}
diff --git a/Swift/Controllers/UIInterfaces/RemoteScreenWindow.h b/Swift/Controllers/UIInterfaces/RemoteScreenWindow.h
new file mode 100644
index 0000000..c31ca91
--- /dev/null
+++ b/Swift/Controllers/UIInterfaces/RemoteScreenWindow.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2012 Yoann Blein
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class IncomingScreenSharing;
+	class Image;
+
+	class RemoteScreenWindow {
+		public:
+			RemoteScreenWindow(boost::shared_ptr<IncomingScreenSharing> incScreenSharing)
+				: iss(incScreenSharing) {}
+			virtual ~RemoteScreenWindow() {}
+
+		protected:
+			boost::shared_ptr<IncomingScreenSharing> iss;
+	};
+}
diff --git a/Swift/Controllers/UIInterfaces/RemoteScreenWindowFactory.h b/Swift/Controllers/UIInterfaces/RemoteScreenWindowFactory.h
new file mode 100644
index 0000000..7c78777
--- /dev/null
+++ b/Swift/Controllers/UIInterfaces/RemoteScreenWindowFactory.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2012 Yoann Blein
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include "Swift/Controllers/UIInterfaces/RemoteScreenWindow.h"
+
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class IncomingScreenSharing;
+	class RemoteScreenWindowFactory {
+		public:
+			virtual ~RemoteScreenWindowFactory() {}
+
+		virtual RemoteScreenWindow* createRemoteScreenViewer(boost::shared_ptr<IncomingScreenSharing> iss) = 0;
+	};
+}
diff --git a/Swift/Controllers/UIInterfaces/UIFactory.h b/Swift/Controllers/UIInterfaces/UIFactory.h
index 6b4efd8..e0e5425 100644
--- a/Swift/Controllers/UIInterfaces/UIFactory.h
+++ b/Swift/Controllers/UIInterfaces/UIFactory.h
@@ -21,12 +21,12 @@
 #include <Swift/Controllers/UIInterfaces/AdHocCommandWindowFactory.h>
 #include <Swift/Controllers/UIInterfaces/FileTransferListWidgetFactory.h>
 #include <Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h>
+#include <Swift/Controllers/UIInterfaces/RemoteScreenWindowFactory.h>
 
 namespace Swift {
 	class UIFactory : 
 			public ChatListWindowFactory, 
 			public ChatWindowFactory, 
-			public HistoryWindowFactory,
 			public EventWindowFactory, 
 			public LoginWindowFactory, 
 			public MainWindowFactory, 
@@ -38,7 +38,8 @@ namespace Swift {
 			public ContactEditWindowFactory,
 			public AdHocCommandWindowFactory,
 			public FileTransferListWidgetFactory,
-			public WhiteboardWindowFactory {
+			public WhiteboardWindowFactory,
+			public RemoteScreenWindowFactory {
 		public:
 			virtual ~UIFactory() {}
 	};
diff --git a/Swift/QtUI/QtUIFactory.cpp b/Swift/QtUI/QtUIFactory.cpp
index a154fb0..ba9cbc9 100644
--- a/Swift/QtUI/QtUIFactory.cpp
+++ b/Swift/QtUI/QtUIFactory.cpp
@@ -26,6 +26,7 @@
 #include "QtAdHocCommandWindow.h"
 #include "QtFileTransferListWidget.h"
 #include "Whiteboard/QtWhiteboardWindow.h"
+#include <Swift/QtUI/ScreenSharing/QtRemoteScreenWindow.h>
 #include <Swift/Controllers/Settings/SettingsProviderHierachy.h>
 #include <Swift/QtUI/QtUISettingConstants.h>
 #include <QtHistoryWindow.h>
@@ -77,6 +78,13 @@ FileTransferListWidget* QtUIFactory::createFileTransferListWidget() {
 	return widget;
 }
 
+RemoteScreenWindow* QtUIFactory::createRemoteScreenViewer(boost::shared_ptr<IncomingScreenSharing> iss)
+{
+	QtRemoteScreenWindow* rsv = new QtRemoteScreenWindow(iss);
+	rsv->show();
+	return rsv;
+}
+
 MainWindow* QtUIFactory::createMainWindow(UIEventStream* eventStream) {
 	lastMainWindow  = new QtMainWindow(settings, eventStream, loginWindow->getMenus(), emoticonsExist_);
 	return lastMainWindow;
diff --git a/Swift/QtUI/QtUIFactory.h b/Swift/QtUI/QtUIFactory.h
index 30f0101..8d4be81 100644
--- a/Swift/QtUI/QtUIFactory.h
+++ b/Swift/QtUI/QtUIFactory.h
@@ -46,6 +46,7 @@ namespace Swift {
 			virtual ContactEditWindow* createContactEditWindow();
 			virtual FileTransferListWidget* createFileTransferListWidget();
 			virtual WhiteboardWindow* createWhiteboardWindow(boost::shared_ptr<WhiteboardSession> whiteboardSession);
+			virtual RemoteScreenWindow* createRemoteScreenViewer(boost::shared_ptr<IncomingScreenSharing> iss);
 			virtual void createAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command);
 
 		private slots:
diff --git a/Swift/QtUI/Roster/QtRosterWidget.cpp b/Swift/QtUI/Roster/QtRosterWidget.cpp
index 1cf073b..0e75057 100644
--- a/Swift/QtUI/Roster/QtRosterWidget.cpp
+++ b/Swift/QtUI/Roster/QtRosterWidget.cpp
@@ -16,6 +16,7 @@
 #include "Swift/Controllers/UIEvents/RenameGroupUIEvent.h"
 #include "Swift/Controllers/UIEvents/SendFileUIEvent.h"
 #include "Swift/Controllers/UIEvents/RequestWhiteboardUIEvent.h"
+#include "Swift/Controllers/UIEvents/ShareScreenUIEvent.h"
 #include "QtContactEditWindow.h"
 #include "Swift/Controllers/Roster/ContactRosterItem.h"
 #include "Swift/Controllers/Roster/GroupRosterItem.h"
@@ -62,6 +63,10 @@ void QtRosterWidget::contextMenuEvent(QContextMenuEvent* event) {
 		if (contact->supportsFeature(ContactRosterItem::FileTransferFeature)) {
 			sendFile = contextMenu.addAction(tr("Send File"));
 		}
+		QAction* shareScreen = NULL;
+		if (contact->supportsFeature(ContactRosterItem::ScreenSharingFeature)) {
+			shareScreen = contextMenu.addAction(tr("Share my screen"));
+		}
 #endif
 #ifdef SWIFT_EXPERIMENTAL_WB
 		QAction* startWhiteboardChat = NULL;
@@ -85,6 +90,9 @@ void QtRosterWidget::contextMenuEvent(QContextMenuEvent* event) {
 				eventStream_->send(boost::make_shared<SendFileUIEvent>(contact->getJID(), Q2PSTRING(fileName)));
 			}
 		}
+		else if (shareScreen && result == shareScreen) {
+			eventStream_->send(boost::make_shared<ShareScreenUIEvent>(contact->getJID()));
+		}
 #endif
 #ifdef SWIFT_EXPERIMENTAL_WB
 		else if (startWhiteboardChat && result == startWhiteboardChat) {
diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript
index c940d49..9d8f42b 100644
--- a/Swift/QtUI/SConscript
+++ b/Swift/QtUI/SConscript
@@ -161,7 +161,10 @@ sources = [
     "QtChatWindowJSBridge.cpp",
     "QtMUCConfigurationWindow.cpp",
     "QtAffiliationEditor.cpp",
-    "QtUISettingConstants.cpp"
+	"QtUISettingConstants.cpp",
+	"ScreenSharing/RemoteScreenViewerWidget.cpp",
+	"ScreenSharing/QtRemoteScreenWindow.cpp",
+	"ScreenSharing/QtDesktopScreenGrabber.cpp",
   ]
 
 myenv["SWIFT_VERSION"] = Version.getBuildVersion(env.Dir("#").abspath, "swift")
diff --git a/Swift/QtUI/ScreenSharing/QtDesktopScreenGrabber.cpp b/Swift/QtUI/ScreenSharing/QtDesktopScreenGrabber.cpp
new file mode 100644
index 0000000..a5eeafd
--- /dev/null
+++ b/Swift/QtUI/ScreenSharing/QtDesktopScreenGrabber.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2012 Yoann Blein
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtDesktopScreenGrabber.h"
+
+#include <QImage>
+#include <QPixmap>
+#include <QApplication>
+#include <QDesktopWidget>
+
+#include <Swiften/ScreenSharing/Image.h>
+
+/*#include <QImage>
+#include <QLabel>*/
+
+namespace Swift {
+
+QtDesktopScreenGrabber::QtDesktopScreenGrabber()
+{
+	/*Image img = grab();
+	QImage qImg(img.data.data(), img.width, img.height, QImage::Format_RGB888);
+	QLabel *label = new QLabel;
+	label->setPixmap(QPixmap::fromImage(qImg));
+	label->show();*/
+}
+
+QtDesktopScreenGrabber::~QtDesktopScreenGrabber()
+{
+}
+
+Image QtDesktopScreenGrabber::grab() const
+{
+	QImage qImg = QPixmap::grabWindow(QApplication::desktop()->winId()).toImage().convertToFormat(QImage::Format_RGB888);
+	return Image(qImg.width(), qImg.height(), qImg.constBits());
+}
+
+}
diff --git a/Swift/QtUI/ScreenSharing/QtDesktopScreenGrabber.h b/Swift/QtUI/ScreenSharing/QtDesktopScreenGrabber.h
new file mode 100644
index 0000000..55a7842
--- /dev/null
+++ b/Swift/QtUI/ScreenSharing/QtDesktopScreenGrabber.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2012 Yoann Blein
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include "Swift/Controllers/ScreenSharing/DesktopScreenGrabber.h"
+
+namespace Swift {
+	class QtDesktopScreenGrabber : public DesktopScreenGrabber {
+		public:
+			QtDesktopScreenGrabber();
+			virtual ~QtDesktopScreenGrabber();
+
+			virtual Image grab() const;
+	};
+}
diff --git a/Swift/QtUI/ScreenSharing/QtRemoteScreenWindow.cpp b/Swift/QtUI/ScreenSharing/QtRemoteScreenWindow.cpp
new file mode 100644
index 0000000..e6cd291
--- /dev/null
+++ b/Swift/QtUI/ScreenSharing/QtRemoteScreenWindow.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2012 Yoann Blein
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtRemoteScreenWindow.h"
+#include "RemoteScreenViewerWidget.h"
+
+#include <QToolBar>
+
+#include <Swiften/ScreenSharing/IncomingScreenSharing.h>
+
+namespace Swift {
+
+QtRemoteScreenWindow::QtRemoteScreenWindow(boost::shared_ptr<IncomingScreenSharing> incScreenSharing, QWidget *parent)
+	: QMainWindow(parent), RemoteScreenWindow(incScreenSharing)
+{
+	setCentralWidget(new RemoteScreenViewerWidget(iss));
+
+	controlToolBar = addToolBar(tr("Control"));
+	closeAction = controlToolBar->addAction(QIcon::fromTheme("window-close"), tr("&Terminate session"), this, SLOT(handleCloseTriggered()));
+}
+
+QtRemoteScreenWindow::~QtRemoteScreenWindow()
+{
+}
+
+void QtRemoteScreenWindow::handleCloseTriggered()
+{
+	iss->stop();
+}
+
+}
diff --git a/Swift/QtUI/ScreenSharing/QtRemoteScreenWindow.h b/Swift/QtUI/ScreenSharing/QtRemoteScreenWindow.h
new file mode 100644
index 0000000..00ac803
--- /dev/null
+++ b/Swift/QtUI/ScreenSharing/QtRemoteScreenWindow.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2012 Yoann Blein
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include "Swift/Controllers/UIInterfaces/RemoteScreenWindow.h"
+
+#include <QMainWindow>
+
+class QToolBar;
+
+namespace Swift {
+
+	class QtRemoteScreenWindow : public QMainWindow, public RemoteScreenWindow {
+			Q_OBJECT
+
+		public:
+			QtRemoteScreenWindow(boost::shared_ptr<IncomingScreenSharing> incScreenSharing, QWidget *parent = 0);
+			virtual ~QtRemoteScreenWindow();
+
+		private slots:
+			void handleCloseTriggered();
+
+		private:
+			QAction* closeAction;
+			QToolBar* controlToolBar;
+	};
+}
diff --git a/Swift/QtUI/ScreenSharing/RemoteScreenViewerWidget.cpp b/Swift/QtUI/ScreenSharing/RemoteScreenViewerWidget.cpp
new file mode 100644
index 0000000..f601f1b
--- /dev/null
+++ b/Swift/QtUI/ScreenSharing/RemoteScreenViewerWidget.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012 Yoann Blein
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "RemoteScreenViewerWidget.h"
+
+#include <QResizeEvent>
+#include <QPainter>
+
+#include <boost/bind.hpp>
+
+#include <Swiften/ScreenSharing/IncomingScreenSharing.h>
+#include <Swiften/ScreenSharing/Image.h>
+
+
+namespace Swift {
+
+RemoteScreenViewerWidget::RemoteScreenViewerWidget(boost::shared_ptr<IncomingScreenSharing> incScreenSharing, QWidget *parent) :
+	QWidget(parent), iss(incScreenSharing)
+{
+	iss->onNewImageReceived.connect(boost::bind(&RemoteScreenViewerWidget::handleNewImageReceived, this, _1));
+}
+
+RemoteScreenViewerWidget::~RemoteScreenViewerWidget()
+{
+	iss->onNewImageReceived.disconnect(boost::bind(&RemoteScreenViewerWidget::handleNewImageReceived, this, _1));
+}
+
+void RemoteScreenViewerWidget::paintEvent(QPaintEvent *)
+{
+	QPainter painter(this);
+	if (!pixmap.isNull()) {
+		painter.translate(geometry().center());
+		painter.drawPixmap(-pixmap.rect().center(), pixmap);
+	}
+}
+
+void RemoteScreenViewerWidget::resizeEvent(QResizeEvent *event)
+{
+	if (!pixmap.isNull())
+		pixmap = pixmap.scaled(event->size(), Qt::KeepAspectRatio);
+	QWidget::resizeEvent(event);
+}
+
+void RemoteScreenViewerWidget::handleNewImageReceived(const Image& image)
+{
+	QImage qImg(image.data.data(), image.width, image.height, QImage::Format_RGB888);
+	pixmap = QPixmap::fromImage(qImg).scaled(size(), Qt::KeepAspectRatio);
+	update();
+}
+
+}
diff --git a/Swift/QtUI/ScreenSharing/RemoteScreenViewerWidget.h b/Swift/QtUI/ScreenSharing/RemoteScreenViewerWidget.h
new file mode 100644
index 0000000..622bd26
--- /dev/null
+++ b/Swift/QtUI/ScreenSharing/RemoteScreenViewerWidget.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2012 Yoann Blein
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <QWidget>
+
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class IncomingScreenSharing;
+	class Image;
+
+	class RemoteScreenViewerWidget : public QWidget {
+			Q_OBJECT
+		public:
+			RemoteScreenViewerWidget(boost::shared_ptr<IncomingScreenSharing> incScreenSharing, QWidget *parent = 0);
+			~RemoteScreenViewerWidget();
+
+		protected:
+			void paintEvent(QPaintEvent *);
+			void resizeEvent(QResizeEvent *event);
+
+		private:
+			void handleNewImageReceived(const Image& image);
+
+		private:
+			boost::shared_ptr<IncomingScreenSharing> iss;
+			QPixmap pixmap;
+	};
+}
-- 
cgit v0.10.2-6-g49f6