summaryrefslogtreecommitdiffstats
blob: 944045129745a464686d14e691121f6cc273d321 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#ifndef SNARL_INTERFACE_V41
#define SNARL_INTERFACE_V41

#include <tchar.h>
#include <windows.h>
#include <cstdio>

#ifndef SMTO_NOTIMEOUTIFNOTHUNG
	#define SMTO_NOTIMEOUTIFNOTHUNG 8
#endif


namespace Snarl {
	namespace V41 {

	static const LPCTSTR SnarlWindowClass = _T("w>Snarl");
	static const LPCTSTR SnarlWindowTitle = _T("Snarl");

	static const LPCTSTR SnarlGlobalMsg = _T("SnarlGlobalEvent");
	static const LPCTSTR SnarlAppMsg = _T("SnarlAppMessage");

	static const int SnarlPacketDataSize = 4096;

	// Enums put in own namespace, because ANSI C++ doesn't decorate enums with tagname :(
	namespace SnarlEnums {

		/// <summary>
		/// Global event identifiers.
		/// Identifiers marked with a '*' are sent by Snarl in two ways:
		///   1. As a broadcast message (uMsg = 'SNARL_GLOBAL_MSG')
		///   2. To the window registered in snRegisterConfig() or snRegisterConfig2()
		///      (uMsg = reply message specified at the time of registering)
		/// In both cases these values appear in wParam.
		///   
		/// Identifiers not marked are not broadcast; they are simply sent to the application's registered window.
		/// </summary>
		enum GlobalEvent
		{
			SnarlLaunched = 1,      // Snarl has just started running*
			SnarlQuit = 2,          // Snarl is about to stop running*
			SnarlAskAppletVer = 3,  // (R1.5) Reserved for future use
			SnarlShowAppUi = 4      // (R1.6) Application should show its UI
		};

		/// <summary>
		/// Message event identifiers.
		/// These are sent by Snarl to the window specified in RegisterApp() when the
		/// Snarl Notification raised times out or the user clicks on it.
		/// </summary>
		enum MessageEvent
		{
			NotificationClicked = 32,      // Notification was right-clicked by user
			NotificationCancelled = 32,    // Added in V37 (R1.6) -- same value, just improved the meaning of it
			NotificationTimedOut = 33,     // 
			NotificationAck = 34,          // Notification was left-clicked by user
			NotificationMenu = 35,         // Menu item selected (V39)
			NotificationMiddleButton = 36, // Notification middle-clicked by user (V39)
			NotificationClosed = 37        // User clicked the close gadget (V39)
		};

		/// <summary>
		/// Error values returned by calls to GetLastError().
		/// </summary>
		enum SnarlStatus
		{
			Success = 0,

			ErrorFailed = 101,        // miscellaneous failure
			ErrorUnknownCommand,      // specified command not recognised
			ErrorTimedOut,            // Snarl took too long to respond

			ErrorArgMissing = 109,    // required argument missing
			ErrorSystem,              // internal system error

			ErrorNotRunning = 201,    // Snarl handling window not found
			ErrorNotRegistered,       // 
			ErrorAlreadyRegistered,   // not used yet; RegisterApp() returns existing token
			ErrorClassAlreadyExists,  // not used yet; AddClass() returns existing token
			ErrorClassBlocked,
			ErrorClassNotFound,
			ErrorNotificationNotFound
		};

		/// <summary>
		/// Application flags - features this app supports.
		/// </summary>
		enum AppFlags
		{
			AppDefault = 0,
			AppHasPrefs = 1,
			AppHasAbout = 2,
			AppIsWindowless = 0x8000
		};

		enum SnarlCommand
		{
			RegisterApp = 1,
			UnregisterApp,
			UpdateApp,
			SetCallback,
			AddClass,
			RemoveClass,
			Notify,
			UpdateNotification,
			HideNotification,
			IsNotificationVisible,
			LastError                  // deprecated but retained for backwards compatability
		};
	}

	struct SnarlMessage
	{
		SnarlEnums::SnarlCommand Command;
		LONG32 Token;
		BYTE PacketData[SnarlPacketDataSize];
	};

	static const DWORD WM_SNARLTEST = WM_USER + 237;

	
	// ------------------------------------------------------------------------
	/// SnarlInterface class definition
	// ------------------------------------------------------------------------
	class SnarlInterface {
		public:
			SnarlInterface();
			~SnarlInterface();
			
			LPTSTR AllocateString(size_t n) { return new TCHAR[n]; }
			void FreeString(LPTSTR str)     { delete [] str; str = NULL; }
			void FreeString(LPCTSTR str)    { delete [] str; }

			/// <summary>Register application with Snarl.</summary>
			/// <returns>The application token or 0 on failure.</returns>
			/// <remarks>The application token is saved in SnarlInterface member variable, so just use return value to check for error.</remarks>
			LONG32 RegisterApp(LPCSTR signature, LPCSTR title, LPCSTR icon, HWND hWndReply = NULL, LONG32 msgReply = 0, SnarlEnums::AppFlags flags = SnarlEnums::AppDefault);
			LONG32 RegisterApp(LPCWSTR  signature, LPCWSTR title, LPCWSTR icon, HWND hWndReply = NULL, LONG32 msgReply = 0, SnarlEnums::AppFlags flags = SnarlEnums::AppDefault);

			/// <summary>Unregister application with Snarl when application is closing.</summary>
			/// <returns>0 on failure.</returns>
			LONG32 UnregisterApp();

			/// <summary>Update information provided when calling RegisterApp.</summary>
			/// <returns>0 on failure.</returns>
			LONG32 UpdateApp(LPCSTR title = NULL, LPCSTR icon = NULL);
			LONG32 UpdateApp(LPCWSTR title = NULL, LPCWSTR icon = NULL);

			/// <summary>Add a notification class to Snarl.</summary>
			/// <returns>0 on failure.</returns>
			LONG32 AddClass(LPCSTR className, LPCSTR description, bool enabled = true);
			LONG32 AddClass(LPCWSTR className, LPCWSTR description, bool enabled = true);
			
			/// <summary>Remove a notification class added with AddClass().</summary>
			/// <returns>0 on failure.</returns>
			LONG32 RemoveClass(LPCSTR className, bool forgetSettings = false);
			LONG32 RemoveClass(LPCWSTR className, bool forgetSettings = false);

			/// <summary>Remove all notification classes in one call.</summary>
			/// <returns>0 on failure.</returns>
			LONG32 RemoveAllClasses(bool forgetSettings = false);
			
			/// <summary>Show a Snarl notification.</summary>
			/// <returns>Returns the notification token or 0 on failure.</returns>
			/// <remarks>You can use <see cref="GetLastMsgToken()" /> to get the last token.</remarks>
			LONG32 EZNotify(LPCSTR className, LPCSTR title, LPCSTR text, LONG32 timeout = -1, LPCSTR icon = NULL, LONG32 priority = 0, LPCSTR acknowledge = NULL, LPCSTR value = NULL);
			LONG32 EZNotify(LPCWSTR className, LPCWSTR title, LPCWSTR text, LONG32 timeout = -1, LPCWSTR icon = NULL, LONG32 priority = 0, LPCWSTR acknowledge = NULL, LPCWSTR value = NULL);

			/// <summary>
			///     Show a Snarl notification.
			///     This function requires that you write your own packet data.
			/// </summary>
			/// <returns>Returns the notification token or 0 on failure.</returns>
			/// <remarks>You can use <see cref="GetLastMsgToken()" /> to get the last token.</remarks>
			LONG32 Notify(LPCSTR className, LPCSTR packetData);
			LONG32 Notify(LPCWSTR className, LPCWSTR packetData);

			/// <summary>Update the text or other parameters of a visible Snarl notification.</summary>
			/// <returns>0 on failure.</returns>
			LONG32 EZUpdate(LONG32 msgToken, LPCSTR title = NULL, LPCSTR text = NULL, LONG32 timeout = -1, LPCSTR icon = NULL);
			LONG32 EZUpdate(LONG32 msgToken, LPCWSTR title = NULL, LPCWSTR text = NULL, LONG32 timeout = -1, LPCWSTR icon = NULL);
			
			/// <summary>
			///     Update the text or other parameters of a visible Snarl notification.
			///     This function requires that you write your own packet data.
			/// </summary>
			/// <returns>0 on failure.</returns>
			LONG32 Update(LONG32 msgToken, LPCSTR packetData);
			LONG32 Update(LONG32 msgToken, LPCWSTR packetData);

			/// <summary>Hide a Snarl notification.</summary>
			/// <returns>0 on failure.</returns>
			LONG32 Hide(LONG32 msgToken);

			/// <summary>Test if a Snarl notification is visible.</summary>
			/// <returns>Returns -1 if message is visible. 0 if not visible or if an error occured.</returns>
			LONG32 IsVisible(LONG32 msgToken);

			/// <summary>Get the last error from Snarl. Call after other functions return 0 to know why it failed.</summary>
			/// <returns>Returns one of the SnarlEnums::SnarlStatus values.</returns>
			SnarlEnums::SnarlStatus GetLastError();

			/// <summary>Get Snarl version, if it is running.</summary>
			/// <returns>Returns a number indicating Snarl version.</returns>
			LONG32 GetVersion();

			/// <summary>
			///     Get the path to where Snarl is installed.
			///     ** Remember to call <see cref="FreeString(LPCTSTR)" /> on the returned string !!!
			/// </summary>
			/// <returns>Returns the path to where Snarl is installed.</returns>
			/// <remarks>This is a V39 API method.</remarks>
			LPCTSTR  GetAppPath();

			/// <summary>
			///     Get the path to where the default Snarl icons are located.
			///     <para>** Remember to call <see cref="FreeString(LPCTSTR)" /> on the returned string !!!</para>
			/// </summary>
			/// <returns>Returns the path to where the default Snarl icons are located.</returns>
			/// <remarks>This is a V39 API method.</remarks>
			LPCTSTR  GetIconsPath();

			/// <summary>GetLastMsgToken() returns token of the last message sent to Snarl.</summary>
			/// <returns>Returns message token of last message.</returns>
			/// <remarks>This function is not in the official API!</remarks>
			LONG32 GetLastMsgToken() const;
			
			/// <summary>Check whether Snarl is running</summary>
			/// <returns>Returns true if Snarl system was found running.</returns>
			static BOOL IsSnarlRunning();

			/// <summary>
			///     Returns the value of Snarl's global registered message.
			///     Notes:
			///       Snarl registers SNARL_GLOBAL_MSG during startup which it then uses to communicate
			///       with all running applications through a Windows broadcast message. This function can
			///       only fail if for some reason the Windows RegisterWindowMessage() function fails
			///       - given this, this function *cannnot* be used to test for the presence of Snarl.
			/// </summary>
			/// <returns>A 16-bit value (translated to 32-bit) which is the registered Windows message for Snarl.</returns>
			static UINT Broadcast();

			/// <summary>Returns the global Snarl Application message  (V39)</summary>
			/// <returns>Returns Snarl application registered message.</returns>
			static UINT AppMsg();

			/// <summary>Returns a handle to the Snarl Dispatcher window  (V37)</summary>
			/// <returns>Returns handle to Snarl Dispatcher window, or zero if it's not found.</returns>
			/// <remarks>This is now the preferred way to test if Snarl is actually running.</remarks>
			static HWND GetSnarlWindow();
		
		private:
			/// <summary>Send message to Snarl.</summary>
			/// <returns>Return zero on failure.</returns>
			LONG32 Send(SnarlMessage msg);

			/// <summary>Convert a unicode string to UTF8</summary>
			/// <returns>Returns pointer to the new string - Remember to delete [] returned string !</returns>
			/// <remarks>Remember to delete [] returned string !!!</remarks>
			LPSTR  WideToUTF8(LPCWSTR szWideStr);

			/// <summary>Pack data into the PackedData member field.</summary>
			/// <param name="data">Should always be a pointer to the PackedData field</param>
			/// <param name="format">The format string. Can be NULL or "" to just zero PackedData!</param>
			/// <param name="...">Variable number of objects to convert</param>
			void   PackData(BYTE* data, LPCSTR format, ...);

			LONG32 appToken;
			LONG32 lastMsgToken;
			SnarlEnums::SnarlStatus localError;

	}; // class

	} // namespace V41
} // namespace Snarl

#endif // SNARL_INTERFACE_V41