blob: 229f1ce51ea1476a71eb6db6f593db698b42b326 [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>
Oleg Sheikinf5049ad2005-07-01 12:41:15 +000032#include <winvnc/ControlPanel.h>
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000033
34using namespace rfb;
35using namespace win32;
36using namespace winvnc;
37
38static LogWriter vlog("STrayIcon");
39
40BoolParameter STrayIconThread::disableOptions("DisableOptions", "Disable the Options entry in the VNC Server tray menu.", false);
41
42
43//
44// -=- AboutDialog global values
45//
46
47const WORD rfb::win32::AboutDialog::DialogId = IDD_ABOUT;
48const WORD rfb::win32::AboutDialog::Copyright = IDC_COPYRIGHT;
49const WORD rfb::win32::AboutDialog::Version = IDC_VERSION;
50const WORD rfb::win32::AboutDialog::BuildTime = IDC_BUILDTIME;
51const WORD rfb::win32::AboutDialog::Description = IDC_DESCRIPTION;
52
53
54//
55// -=- Internal tray icon class
56//
57
58const UINT WM_SET_TOOLTIP = WM_USER + 1;
59
60
61class winvnc::STrayIcon : public TrayIcon {
62public:
63 STrayIcon(STrayIconThread& t) : thread(t),
64 vncConfig(_T("vncconfig.exe"), isServiceProcess() ? _T("-noconsole -service") : _T("-noconsole")),
65 vncConnect(_T("winvnc4.exe"), _T("-connect")) {
66
67 // ***
68 SetWindowText(getHandle(), _T("winvnc::IPC_Interface"));
69 // ***
70
71 SetTimer(getHandle(), 1, 3000, 0);
72 PostMessage(getHandle(), WM_TIMER, 1, 0);
73 PostMessage(getHandle(), WM_SET_TOOLTIP, 0, 0);
Oleg Sheikin641f7e52005-11-22 18:04:10 +000074 CPanel = new ControlPanel(getHandle());
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000075 }
76
77 virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
78 switch(msg) {
79
80 case WM_USER:
81 {
82 bool userKnown = CurrentUserToken().isValid();
83 bool allowOptions = !STrayIconThread::disableOptions && userKnown;
84
85 switch (lParam) {
86 case WM_LBUTTONDBLCLK:
Oleg Sheikinf5049ad2005-07-01 12:41:15 +000087 SendMessage(getHandle(), WM_COMMAND, ID_CONTR0L_PANEL, 0);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000088 break;
89 case WM_RBUTTONUP:
90 HMENU menu = LoadMenu(GetModuleHandle(0), MAKEINTRESOURCE(thread.menu));
91 HMENU trayMenu = GetSubMenu(menu, 0);
92
93
94 // Default item is Options, if available, or About if not
Oleg Sheikinf5049ad2005-07-01 12:41:15 +000095 SetMenuDefaultItem(trayMenu, ID_CONTR0L_PANEL, FALSE);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000096
97 // Enable/disable options as required
98 EnableMenuItem(trayMenu, ID_OPTIONS, (!allowOptions ? MF_GRAYED : MF_ENABLED) | MF_BYCOMMAND);
99 EnableMenuItem(trayMenu, ID_CONNECT, (!userKnown ? MF_GRAYED : MF_ENABLED) | MF_BYCOMMAND);
100 EnableMenuItem(trayMenu, ID_CLOSE, (isServiceProcess() ? MF_GRAYED : MF_ENABLED) | MF_BYCOMMAND);
101
Oleg Sheikind87a7a72006-01-12 15:27:04 +0000102 thread.server.getClientsInfo(&LCInfo);
103 CheckMenuItem(trayMenu, ID_DISABLE_NEW_CLIENTS, (LCInfo.getDisable() ? MF_CHECKED : MF_UNCHECKED) | MF_BYCOMMAND);
104
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000105 // SetForegroundWindow is required, otherwise Windows ignores the
106 // TrackPopupMenu because the window isn't the foreground one, on
107 // some older Windows versions...
108 SetForegroundWindow(getHandle());
109
110 // Display the menu
111 POINT pos;
112 GetCursorPos(&pos);
113 TrackPopupMenu(trayMenu, 0, pos.x, pos.y, 0, getHandle(), 0);
Oleg Sheikind87a7a72006-01-12 15:27:04 +0000114
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000115 break;
Oleg Sheikind87a7a72006-01-12 15:27:04 +0000116 }
117 return 0;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000118 }
119
120 // Handle tray icon menu commands
121 case WM_COMMAND:
122 switch (LOWORD(wParam)) {
Oleg Sheikind87a7a72006-01-12 15:27:04 +0000123 case ID_CONTR0L_PANEL:
124 CPanel->showDialog();
125 break;
126 case ID_DISABLE_NEW_CLIENTS:
127 {
128 thread.server.getClientsInfo(&LCInfo);
129 LCInfo.setDisable(!LCInfo.getDisable());
130 thread.server.setClientsStatus(&LCInfo);
131 CPanel->UpdateListView(&LCInfo);
132 }
133 break;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000134 case ID_OPTIONS:
135 {
136 CurrentUserToken token;
137 if (token.isValid())
138 vncConfig.start(isServiceProcess() ? (HANDLE)token : 0);
139 else
140 vlog.error("Options: unknown current user");
141 }
142 break;
143 case ID_CONNECT:
144 {
145 CurrentUserToken token;
146 if (token.isValid())
147 vncConnect.start(isServiceProcess() ? (HANDLE)token : 0);
148 else
149 vlog.error("Options: unknown current user");
150 }
151 break;
152 case ID_DISCONNECT:
153 thread.server.disconnectClients("tray menu disconnect");
154 break;
155 case ID_CLOSE:
156 if (!isServiceProcess())
157 thread.server.stop();
158 break;
159 case ID_ABOUT:
160 AboutDialog::instance.showDialog();
161 break;
162 }
163 return 0;
164
165 // Handle commands send by other processes
166 case WM_COPYDATA:
167 {
168 COPYDATASTRUCT* command = (COPYDATASTRUCT*)lParam;
169 switch (command->dwData) {
170 case 1:
171 {
172 CharArray viewer = new char[command->cbData + 1];
173 memcpy(viewer.buf, command->lpData, command->cbData);
174 viewer.buf[command->cbData] = 0;
175 thread.server.addNewClient(viewer.buf);
176 }
177 break;
178 case 2:
179 thread.server.disconnectClients("IPC disconnect");
180 break;
Oleg Sheikin4b0304f2005-12-09 10:59:12 +0000181 case 3:
182 thread.server.setClientsStatus((rfb::ListConnInfo *)command->cbData);
Oleg Sheikind87a7a72006-01-12 15:27:04 +0000183 case 4:
Constantin Kaplinskyc14a07a2005-12-09 14:54:28 +0000184 thread.server.getClientsInfo(&LCInfo);
185 CPanel->UpdateListView(&LCInfo);
Oleg Sheikin4b0304f2005-12-09 10:59:12 +0000186 break;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000187 };
188 };
189 break;
190
191 case WM_CLOSE:
192 PostQuitMessage(0);
193 break;
194
195 case WM_TIMER:
196 if (rfb::win32::desktopChangeRequired()) {
197 SendMessage(getHandle(), WM_CLOSE, 0, 0);
198 return 0;
199 }
Oleg Sheikin641f7e52005-11-22 18:04:10 +0000200
Oleg Sheikinff43bfd2005-12-07 08:02:52 +0000201 thread.server.getClientsInfo(&LCInfo);
Oleg Sheikin5c642e92005-12-22 20:57:58 +0000202 CPanel->UpdateListView(&LCInfo);
203
204 setIcon(thread.server.isServerInUse() ?
205 (!LCInfo.getDisable() ? thread.activeIcon : thread.dis_activeIcon) :
206 (!LCInfo.getDisable() ? thread.inactiveIcon : thread.dis_inactiveIcon));
Oleg Sheikin641f7e52005-11-22 18:04:10 +0000207
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000208 return 0;
209
210 case WM_SET_TOOLTIP:
211 {
212 rfb::Lock l(thread.lock);
213 if (thread.toolTip.buf)
214 setToolTip(thread.toolTip.buf);
215 }
216 return 0;
217
218 }
219
220 return TrayIcon::processMessage(msg, wParam, lParam);
221 }
222
223protected:
224 LaunchProcess vncConfig;
225 LaunchProcess vncConnect;
226 STrayIconThread& thread;
Oleg Sheikinf5049ad2005-07-01 12:41:15 +0000227 ControlPanel * CPanel;
Oleg Sheikin641f7e52005-11-22 18:04:10 +0000228 rfb::ListConnInfo LCInfo;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000229};
230
231
Oleg Sheikin5c642e92005-12-22 20:57:58 +0000232STrayIconThread::STrayIconThread(VNCServerWin32& sm, UINT inactiveIcon_, UINT activeIcon_,
233 UINT dis_inactiveIcon_, UINT dis_activeIcon_, UINT menu_)
234: server(sm), inactiveIcon(inactiveIcon_), activeIcon(activeIcon_),
235 dis_inactiveIcon(dis_inactiveIcon_), dis_activeIcon(dis_activeIcon_),menu(menu_),
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000236 windowHandle(0), runTrayIcon(true) {
237 start();
238}
239
240
241void STrayIconThread::run() {
242 while (runTrayIcon) {
243 if (rfb::win32::desktopChangeRequired() &&
244 !rfb::win32::changeDesktop())
245 Sleep(2000);
246
247 STrayIcon icon(*this);
248 windowHandle = icon.getHandle();
249
250 MSG msg;
251 while (runTrayIcon && ::GetMessage(&msg, 0, 0, 0) > 0) {
252 TranslateMessage(&msg);
253 DispatchMessage(&msg);
254 }
255
256 windowHandle = 0;
257 }
258}
259
260void STrayIconThread::setToolTip(const TCHAR* text) {
261 if (!windowHandle) return;
262 Lock l(lock);
263 delete [] toolTip.buf;
264 toolTip.buf = tstrDup(text);
265 PostMessage(windowHandle, WM_SET_TOOLTIP, 0, 0);
266}
267
268