瀏覽代碼

tray notification for windows

Andrii Danylchenko 5 年之前
父節點
當前提交
2fc7cf02b0

+ 18 - 0
client/CMT.cpp

@@ -59,6 +59,7 @@
 #include "gui/CAnimation.h"
 #include "../lib/serializer/Connection.h"
 #include "CServerHandler.h"
+#include "gui/NotificationHandler.h"
 
 #include <boost/asio.hpp>
 
@@ -1225,6 +1226,11 @@ static bool recreateWindow(int w, int h, int bpp, bool fullscreen, int displayIn
 	SDL_RenderClear(mainRenderer);
 	SDL_RenderPresent(mainRenderer);
 
+	if(!settings["session"]["headless"].Bool() && settings["general"]["notifications"].Bool())
+	{
+		NotificationHandler::init(mainWindow);
+	}
+
 	return true;
 }
 
@@ -1355,6 +1361,13 @@ static void handleEvent(SDL_Event & ev)
 		}
 		return;
 	}
+	else if(ev.type == SDL_SYSWMEVENT)
+	{
+		if(!settings["session"]["headless"].Bool() && settings["general"]["notifications"].Bool())
+		{
+			NotificationHandler::handleSdlEvent(ev);
+		}
+	}
 
 	//preprocessing
 	if(ev.type == SDL_MOUSEMOTION)
@@ -1430,6 +1443,11 @@ void handleQuit(bool ask)
 		boost::this_thread::sleep(boost::posix_time::milliseconds(750));//???
 		if(!settings["session"]["headless"].Bool())
 		{
+			if(settings["general"]["notifications"].Bool())
+			{
+				NotificationHandler::destroy();
+			}
+
 			cleanupRenderer();
 
 			if(nullptr != mainRenderer)

+ 2 - 0
client/CMakeLists.txt

@@ -14,6 +14,7 @@ set(client_SRCS
 		gui/Fonts.cpp
 		gui/Geometries.cpp
 		gui/SDL_Extensions.cpp
+		gui/NotificationHandler.cpp
 
 		widgets/AdventureMapClasses.cpp
 		widgets/Buttons.cpp
@@ -88,6 +89,7 @@ set(client_HEADERS
 		gui/SDL_Compat.h
 		gui/SDL_Extensions.h
 		gui/SDL_Pixels.h
+		gui/NotificationHandler.h
 
 		widgets/AdventureMapClasses.h
 		widgets/Buttons.h

+ 3 - 0
client/CPlayerInterface.cpp

@@ -62,6 +62,7 @@
 #include "CServerHandler.h"
 // FIXME: only needed for CGameState::mutex
 #include "../lib/CGameState.h"
+#include "gui/NotificationHandler.h"
 
 
 // The macro below is used to mark functions that are called by client when game state changes.
@@ -166,6 +167,8 @@ void CPlayerInterface::yourTurn()
 		GH.curInt = this;
 		adventureInt->selection = nullptr;
 
+		NotificationHandler::notify("Your turn");
+
 		std::string prefix = settings["session"]["saveprefix"].String();
 		int frequency = static_cast<int>(settings["general"]["saveFrequency"].Integer());
 		if (firstCall)

+ 159 - 0
client/gui/NotificationHandler.cpp

@@ -0,0 +1,159 @@
+/*
+* NotificationHandler.cpp, part of VCMI engine
+*
+* Authors: listed in file AUTHORS in main folder
+*
+* License: GNU General Public License v2.0 or later
+* Full text of license available in license.txt file, in main folder
+*
+*/
+
+#include "StdInc.h"
+#include "NotificationHandler.h"
+#include <SDL_video.h>
+#include <SDL_syswm.h>
+
+#if defined(VCMI_WINDOWS) && defined(_WIN64)
+
+#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
+// Windows Header Files:
+#include <windows.h>
+#include <shellapi.h>
+// C RunTime Header Files
+
+#define	WM_USER_SHELLICON WM_USER + 1
+
+// Global Variables:
+
+struct NotificationState
+{
+	HINSTANCE		hInst;	// current instance
+	NOTIFYICONDATA	niData;	// notify icon data
+	bool initialized = false;
+	SDL_Window * window;
+};
+
+NotificationState state;
+
+void NotificationHandler::notify(std::string msg)
+{
+	NOTIFYICONDATA niData;
+	SDL_SysWMinfo info;
+	SDL_VERSION(&info.version);
+
+	if(!SDL_GetWindowWMInfo(state.window, &info))
+		return;
+
+	if(info.info.win.window == GetForegroundWindow())
+		return;
+
+	ZeroMemory(&niData, sizeof(NOTIFYICONDATA));
+
+	niData.cbSize = sizeof(NOTIFYICONDATA);
+	niData.hWnd = info.info.win.window;
+	niData.uID = 1;
+	niData.uFlags = NIF_INFO | NIF_MESSAGE;
+	niData.uCallbackMessage = WM_USER_SHELLICON;
+
+	niData.dwInfoFlags = NIIF_INFO;
+	msg.copy(niData.szInfo, msg.length());
+
+	Shell_NotifyIcon(NIM_MODIFY, &niData);
+}
+
+void NotificationHandler::init(SDL_Window * window)
+{
+	state.window = window;
+
+	if(state.initialized)
+		return;
+
+	SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
+
+	NOTIFYICONDATA niData;
+	SDL_SysWMinfo info;
+	SDL_VERSION(&info.version);
+
+	if(!SDL_GetWindowWMInfo(state.window, &info))
+		return;
+
+	ZeroMemory(&niData, sizeof(NOTIFYICONDATA));
+
+	state.hInst = (HINSTANCE)GetModuleHandle("VCMI_client.exe");
+
+	niData.cbSize = sizeof(NOTIFYICONDATA);
+	niData.hWnd = info.info.win.window;
+	niData.uID = 1;
+	niData.uFlags = NIF_ICON | NIF_MESSAGE;
+	niData.uCallbackMessage = WM_USER_SHELLICON;
+
+	niData.hIcon = (HICON)LoadImage(
+		state.hInst,
+		"IDI_ICON1",
+		IMAGE_ICON,
+		GetSystemMetrics(SM_CXSMICON),
+		GetSystemMetrics(SM_CYSMICON),
+		LR_DEFAULTSIZE);
+
+	Shell_NotifyIcon(NIM_ADD, &niData);
+
+	state.initialized = true;
+}
+
+void NotificationHandler::destroy()
+{
+	NOTIFYICONDATA niData;
+	SDL_SysWMinfo info;
+	SDL_VERSION(&info.version);
+
+	if(!SDL_GetWindowWMInfo(state.window, &info))
+		return;
+
+	ZeroMemory(&niData, sizeof(NOTIFYICONDATA));
+
+	niData.cbSize = sizeof(NOTIFYICONDATA);
+	niData.hWnd = info.info.win.window;
+	niData.uID = 1;
+
+	Shell_NotifyIcon(NIM_DELETE, &niData);
+}
+
+bool NotificationHandler::handleSdlEvent(const SDL_Event & ev)
+{
+	if(ev.syswm.msg->msg.win.msg == WM_USER_SHELLICON)
+	{
+		auto winMsg = LOWORD(ev.syswm.msg->msg.win.lParam);
+
+		if(winMsg == WM_LBUTTONUP || winMsg == NIN_BALLOONUSERCLICK)
+		{
+			SDL_MinimizeWindow(state.window);
+			SDL_RestoreWindow(state.window);
+			SDL_RaiseWindow(state.window);
+
+			return true;
+		}
+	}
+
+	return false;
+}
+
+#else
+
+void NotificationHandler::notify(std::string msg)
+{
+}
+
+void NotificationHandler::init(SDL_Window * window)
+{
+}
+
+void NotificationHandler::destroy()
+{
+}
+
+bool NotificationHandler::handleSdlEvent(const SDL_Event & ev)
+{
+	return false;
+}
+
+#endif

+ 22 - 0
client/gui/NotificationHandler.h

@@ -0,0 +1,22 @@
+/*
+* NotificationHandler.cpp, part of VCMI engine
+*
+* Authors: listed in file AUTHORS in main folder
+*
+* License: GNU General Public License v2.0 or later
+* Full text of license available in license.txt file, in main folder
+*
+*/
+
+#pragma once
+
+#include <SDL_events.h>
+
+class NotificationHandler
+{
+public:
+	static void notify(std::string msg);
+	static void init(SDL_Window * window);
+	static bool handleSdlEvent(const SDL_Event & ev);
+	static void destroy();
+};

+ 5 - 1
config/schemas/settings.json

@@ -17,7 +17,7 @@
 			"type" : "object",
 			"default": {},
 			"additionalProperties" : false,
-			"required" : [ "playerName", "showfps", "music", "sound", "encoding", "swipe", "saveRandomMaps", "saveFrequency" ],
+			"required" : [ "playerName", "showfps", "music", "sound", "encoding", "swipe", "saveRandomMaps", "saveFrequency", "notifications" ],
 			"properties" : {
 				"playerName" : {
 					"type":"string",
@@ -62,6 +62,10 @@
 				"saveFrequency" : {
 					"type" : "number",
 					"default" : 1
+				},
+				"notifications" : {
+					"type" : "boolean",
+					"default" : false
 				}
 			}
 		},