blob: 7cfea3c288589bacf77ae723691b3d5713be1c74 [file] [log] [blame]
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +00001/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19// -=- WinVNC Version 4.0 Tray Icon implementation
20
21#include <winvnc/STrayIcon.h>
22#include <winvnc/resource.h>
23
24#include <rfb/LogWriter.h>
25#include <rfb/Configuration.h>
26#include <rfb_win32/LaunchProcess.h>
27#include <rfb_win32/TrayIcon.h>
28#include <rfb_win32/AboutDialog.h>
29#include <rfb_win32/Win32Util.h>
30#include <rfb_win32/Service.h>
31#include <rfb_win32/CurrentUser.h>
32
33using namespace rfb;
34using namespace win32;
35using namespace winvnc;
36
37static LogWriter vlog("STrayIcon");
38
39BoolParameter STrayIconThread::disableOptions("DisableOptions", "Disable the Options entry in the VNC Server tray menu.", false);
40
41
42//
43// -=- AboutDialog global values
44//
45
46const WORD rfb::win32::AboutDialog::DialogId = IDD_ABOUT;
47const WORD rfb::win32::AboutDialog::Copyright = IDC_COPYRIGHT;
48const WORD rfb::win32::AboutDialog::Version = IDC_VERSION;
49const WORD rfb::win32::AboutDialog::BuildTime = IDC_BUILDTIME;
50const WORD rfb::win32::AboutDialog::Description = IDC_DESCRIPTION;
51
52
53//
54// -=- Internal tray icon class
55//
56
57const UINT WM_SET_TOOLTIP = WM_USER + 1;
58
59
60class winvnc::STrayIcon : public TrayIcon {
61public:
62 STrayIcon(STrayIconThread& t) : thread(t),
63 vncConfig(_T("vncconfig.exe"), isServiceProcess() ? _T("-noconsole -service") : _T("-noconsole")),
64 vncConnect(_T("winvnc4.exe"), _T("-connect")) {
65
66 // ***
67 SetWindowText(getHandle(), _T("winvnc::IPC_Interface"));
68 // ***
69
70 SetTimer(getHandle(), 1, 3000, 0);
71 PostMessage(getHandle(), WM_TIMER, 1, 0);
72 PostMessage(getHandle(), WM_SET_TOOLTIP, 0, 0);
73 }
74
75 virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
76 switch(msg) {
77
78 case WM_USER:
79 {
80 bool userKnown = CurrentUserToken().isValid();
81 bool allowOptions = !STrayIconThread::disableOptions && userKnown;
82
83 switch (lParam) {
84 case WM_LBUTTONDBLCLK:
85 SendMessage(getHandle(), WM_COMMAND, allowOptions ? ID_OPTIONS : ID_ABOUT, 0);
86 break;
87 case WM_RBUTTONUP:
88 HMENU menu = LoadMenu(GetModuleHandle(0), MAKEINTRESOURCE(thread.menu));
89 HMENU trayMenu = GetSubMenu(menu, 0);
90
91
92 // Default item is Options, if available, or About if not
93 SetMenuDefaultItem(trayMenu, allowOptions ? ID_OPTIONS : ID_ABOUT, FALSE);
94
95 // Enable/disable options as required
96 EnableMenuItem(trayMenu, ID_OPTIONS, (!allowOptions ? MF_GRAYED : MF_ENABLED) | MF_BYCOMMAND);
97 EnableMenuItem(trayMenu, ID_CONNECT, (!userKnown ? MF_GRAYED : MF_ENABLED) | MF_BYCOMMAND);
98 EnableMenuItem(trayMenu, ID_CLOSE, (isServiceProcess() ? MF_GRAYED : MF_ENABLED) | MF_BYCOMMAND);
99
100 // SetForegroundWindow is required, otherwise Windows ignores the
101 // TrackPopupMenu because the window isn't the foreground one, on
102 // some older Windows versions...
103 SetForegroundWindow(getHandle());
104
105 // Display the menu
106 POINT pos;
107 GetCursorPos(&pos);
108 TrackPopupMenu(trayMenu, 0, pos.x, pos.y, 0, getHandle(), 0);
109 break;
110 }
111 return 0;
112 }
113
114 // Handle tray icon menu commands
115 case WM_COMMAND:
116 switch (LOWORD(wParam)) {
117 case ID_OPTIONS:
118 {
119 CurrentUserToken token;
120 if (token.isValid())
121 vncConfig.start(isServiceProcess() ? (HANDLE)token : 0);
122 else
123 vlog.error("Options: unknown current user");
124 }
125 break;
126 case ID_CONNECT:
127 {
128 CurrentUserToken token;
129 if (token.isValid())
130 vncConnect.start(isServiceProcess() ? (HANDLE)token : 0);
131 else
132 vlog.error("Options: unknown current user");
133 }
134 break;
135 case ID_DISCONNECT:
136 thread.server.disconnectClients("tray menu disconnect");
137 break;
138 case ID_CLOSE:
139 if (!isServiceProcess())
140 thread.server.stop();
141 break;
142 case ID_ABOUT:
143 AboutDialog::instance.showDialog();
144 break;
145 }
146 return 0;
147
148 // Handle commands send by other processes
149 case WM_COPYDATA:
150 {
151 COPYDATASTRUCT* command = (COPYDATASTRUCT*)lParam;
152 switch (command->dwData) {
153 case 1:
154 {
155 CharArray viewer = new char[command->cbData + 1];
156 memcpy(viewer.buf, command->lpData, command->cbData);
157 viewer.buf[command->cbData] = 0;
158 thread.server.addNewClient(viewer.buf);
159 }
160 break;
161 case 2:
162 thread.server.disconnectClients("IPC disconnect");
163 break;
164 };
165 };
166 break;
167
168 case WM_CLOSE:
169 PostQuitMessage(0);
170 break;
171
172 case WM_TIMER:
173 if (rfb::win32::desktopChangeRequired()) {
174 SendMessage(getHandle(), WM_CLOSE, 0, 0);
175 return 0;
176 }
177 setIcon(thread.server.isServerInUse() ? thread.activeIcon : thread.inactiveIcon);
178 return 0;
179
180 case WM_SET_TOOLTIP:
181 {
182 rfb::Lock l(thread.lock);
183 if (thread.toolTip.buf)
184 setToolTip(thread.toolTip.buf);
185 }
186 return 0;
187
188 }
189
190 return TrayIcon::processMessage(msg, wParam, lParam);
191 }
192
193protected:
194 LaunchProcess vncConfig;
195 LaunchProcess vncConnect;
196 STrayIconThread& thread;
197};
198
199
200STrayIconThread::STrayIconThread(VNCServerWin32& sm, UINT inactiveIcon_, UINT activeIcon_, UINT menu_)
201: server(sm), inactiveIcon(inactiveIcon_), activeIcon(activeIcon_), menu(menu_),
202 windowHandle(0), runTrayIcon(true) {
203 start();
204}
205
206
207void STrayIconThread::run() {
208 while (runTrayIcon) {
209 if (rfb::win32::desktopChangeRequired() &&
210 !rfb::win32::changeDesktop())
211 Sleep(2000);
212
213 STrayIcon icon(*this);
214 windowHandle = icon.getHandle();
215
216 MSG msg;
217 while (runTrayIcon && ::GetMessage(&msg, 0, 0, 0) > 0) {
218 TranslateMessage(&msg);
219 DispatchMessage(&msg);
220 }
221
222 windowHandle = 0;
223 }
224}
225
226void STrayIconThread::setToolTip(const TCHAR* text) {
227 if (!windowHandle) return;
228 Lock l(lock);
229 delete [] toolTip.buf;
230 toolTip.buf = tstrDup(text);
231 PostMessage(windowHandle, WM_SET_TOOLTIP, 0, 0);
232}
233
234