1 /*
2 * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 #include "awt.h"
27 #include <windowsx.h>
28 #include <shellapi.h>
29 #include <shlwapi.h>
30
31 #include "awt_Toolkit.h"
32 #include "awt_TrayIcon.h"
33 #include "awt_AWTEvent.h"
34
35 #include <java_awt_event_InputEvent.h>
36
37 /***********************************************************************/
38 // Struct for _SetToolTip() method
39 struct SetToolTipStruct {
40 jobject trayIcon;
41 jstring tooltip;
42 };
43 // Struct for _SetIcon() method
44 struct SetIconStruct {
45 jobject trayIcon;
46 HICON hIcon;
47 };
48 // Struct for _UpdateIcon() method
49 struct UpdateIconStruct {
50 jobject trayIcon;
51 jboolean update;
52 };
53 // Struct for _DisplayMessage() method
54 struct DisplayMessageStruct {
55 jobject trayIcon;
56 jstring caption;
57 jstring text;
58 jstring msgType;
59 };
60
61 typedef struct tagBitmapheader {
62 BITMAPV5HEADER bmiHeader;
63 DWORD dwMasks[256];
64 } Bitmapheader, *LPBITMAPHEADER;
65
66
67 /************************************************************************
68 * AwtTrayIcon fields
69 */
70
71 jfieldID AwtTrayIcon::idID;
72 jfieldID AwtTrayIcon::actionCommandID;
73
74 HWND AwtTrayIcon::sm_msgWindow = NULL;
75 AwtTrayIcon::TrayIconListItem* AwtTrayIcon::sm_trayIconList = NULL;
76 int AwtTrayIcon::sm_instCount = 0;
77
78 /************************************************************************
79 * AwtTrayIcon methods
80 */
81
AwtTrayIcon()82 AwtTrayIcon::AwtTrayIcon() {
83 ::ZeroMemory(&m_nid, sizeof(m_nid));
84
85 if (sm_instCount++ == 0 && AwtTrayIcon::sm_msgWindow == NULL) {
86 sm_msgWindow = AwtTrayIcon::CreateMessageWindow();
87 }
88 m_mouseButtonClickAllowed = 0;
89 }
90
~AwtTrayIcon()91 AwtTrayIcon::~AwtTrayIcon() {
92 }
93
Dispose()94 void AwtTrayIcon::Dispose() {
95 SendTrayMessage(NIM_DELETE);
96
97 // Destroy the icon to avoid leak of GDI objects
98 if (m_nid.hIcon != NULL) {
99 ::DestroyIcon(m_nid.hIcon);
100 }
101
102 UnlinkObjects();
103
104 if (--sm_instCount == 0) {
105 AwtTrayIcon::DestroyMessageWindow();
106 }
107
108 AwtObject::Dispose();
109 }
110
GetClassName()111 LPCTSTR AwtTrayIcon::GetClassName() {
112 return TEXT("SunAwtTrayIcon");
113 }
114
FillClassInfo(WNDCLASS * lpwc)115 void AwtTrayIcon::FillClassInfo(WNDCLASS *lpwc)
116 {
117 lpwc->style = 0L;
118 lpwc->lpfnWndProc = (WNDPROC)TrayWindowProc;
119 lpwc->cbClsExtra = 0;
120 lpwc->cbWndExtra = 0;
121 lpwc->hInstance = AwtToolkit::GetInstance().GetModuleHandle(),
122 lpwc->hIcon = AwtToolkit::GetInstance().GetAwtIcon();
123 lpwc->hCursor = NULL;
124 lpwc->hbrBackground = NULL;
125 lpwc->lpszMenuName = NULL;
126 lpwc->lpszClassName = AwtTrayIcon::GetClassName();
127 }
128
RegisterClass()129 void AwtTrayIcon::RegisterClass()
130 {
131 WNDCLASS wc;
132
133 ::ZeroMemory(&wc, sizeof(wc));
134
135 if (!::GetClassInfo(AwtToolkit::GetInstance().GetModuleHandle(),
136 AwtTrayIcon::GetClassName(), &wc))
137 {
138 AwtTrayIcon::FillClassInfo(&wc);
139 ATOM atom = ::RegisterClass(&wc);
140 DASSERT(atom != 0);
141 }
142 }
143
UnregisterClass()144 void AwtTrayIcon::UnregisterClass()
145 {
146 ::UnregisterClass(AwtTrayIcon::GetClassName(), AwtToolkit::GetInstance().GetModuleHandle());
147 }
148
CreateMessageWindow()149 HWND AwtTrayIcon::CreateMessageWindow()
150 {
151 AwtTrayIcon::RegisterClass();
152
153 HWND hWnd = ::CreateWindow(AwtTrayIcon::GetClassName(), TEXT("TrayMessageWindow"),
154 0, 0, 0, 0, 0, NULL, NULL,
155 AwtToolkit::GetInstance().GetModuleHandle(), NULL);
156 return hWnd;
157 }
158
DestroyMessageWindow()159 void AwtTrayIcon::DestroyMessageWindow()
160 {
161 ::DestroyWindow(AwtTrayIcon::sm_msgWindow);
162 AwtTrayIcon::sm_msgWindow = NULL;
163 AwtTrayIcon::UnregisterClass();
164 }
165
Create(jobject self,jobject parent)166 AwtTrayIcon* AwtTrayIcon::Create(jobject self, jobject parent)
167 {
168 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
169 jobject target = NULL;
170 AwtTrayIcon* awtTrayIcon = NULL;
171
172 target = env->GetObjectField(self, AwtObject::targetID);
173 DASSERT(target);
174
175 awtTrayIcon = new AwtTrayIcon();
176 awtTrayIcon->LinkObjects(env, self);
177 awtTrayIcon->InitNID(env->GetIntField(target, AwtTrayIcon::idID));
178 awtTrayIcon->AddTrayIconItem(awtTrayIcon->GetID());
179
180 env->DeleteLocalRef(target);
181 return awtTrayIcon;
182 }
183
InitNID(UINT uID)184 void AwtTrayIcon::InitNID(UINT uID)
185 {
186 // fix for 6271589: we MUST set the size of the structure to match
187 // the shell version, otherwise some errors may occur (like missing
188 // balloon messages on win2k)
189 DLLVERSIONINFO dllVersionInfo;
190 dllVersionInfo.cbSize = sizeof(DLLVERSIONINFO);
191 int shellVersion = 5; // WIN_2000
192 // MSDN: DllGetVersion should not be implicitly called, but rather
193 // loaded using GetProcAddress
194 HMODULE hShell = JDK_LoadSystemLibrary("Shell32.dll");
195 if (hShell != NULL) {
196 DLLGETVERSIONPROC proc = (DLLGETVERSIONPROC)GetProcAddress(hShell, "DllGetVersion");
197 if (proc != NULL) {
198 if (proc(&dllVersionInfo) == NOERROR) {
199 shellVersion = dllVersionInfo.dwMajorVersion;
200 }
201 }
202 }
203 FreeLibrary(hShell);
204 switch (shellVersion) {
205 case 5: // WIN_2000
206 m_nid.cbSize = (BYTE *)(&m_nid.guidItem) - (BYTE *)(&m_nid.cbSize);
207 break;
208 case 6: // WIN_XP
209 m_nid.cbSize = (BYTE *)(&m_nid.hBalloonIcon) - (BYTE *)(&m_nid.cbSize);
210 break;
211 default: // WIN_VISTA
212 m_nid.cbSize = sizeof(m_nid);
213 break;
214 }
215 m_nid.hWnd = AwtTrayIcon::sm_msgWindow;
216 m_nid.uID = uID;
217 m_nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
218 m_nid.uCallbackMessage = WM_AWT_TRAY_NOTIFY;
219 m_nid.hIcon = AwtToolkit::GetInstance().GetAwtIcon();
220 m_nid.szTip[0] = '\0';
221 m_nid.uVersion = NOTIFYICON_VERSION;
222 }
223
SendTrayMessage(DWORD dwMessage)224 BOOL AwtTrayIcon::SendTrayMessage(DWORD dwMessage)
225 {
226 return Shell_NotifyIcon(dwMessage, (PNOTIFYICONDATA)&m_nid);
227 }
228
229 static UINT lastMessage = WM_NULL;
230
TrayWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)231 LRESULT CALLBACK AwtTrayIcon::TrayWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
232 {
233 LRESULT retValue = 0;
234 MsgRouting mr = mrDoDefault;
235 static UINT s_msgTaskbarCreated;
236
237 switch(uMsg)
238 {
239 case WM_CREATE:
240 // Fix for CR#6369062
241 s_msgTaskbarCreated = ::RegisterWindowMessage(TEXT("TaskbarCreated"));
242 break;
243 case WM_AWT_TRAY_NOTIFY:
244 if (hwnd == AwtTrayIcon::sm_msgWindow) {
245 AwtTrayIcon* trayIcon = AwtTrayIcon::SearchTrayIconItem((UINT)wParam);
246 if (trayIcon != NULL) {
247 mr = trayIcon->WmAwtTrayNotify(wParam, lParam);
248 }
249 }
250 break;
251 default:
252 if(uMsg == s_msgTaskbarCreated) {
253 if (hwnd == AwtTrayIcon::sm_msgWindow) {
254 mr = WmTaskbarCreated();
255 }
256 }
257 break;
258 }
259
260 if (mr != mrConsume) {
261 retValue = ::DefWindowProc(hwnd, uMsg, wParam, lParam);
262 }
263 return retValue;
264 }
265
266 /*
267 * This function processes callback messages for taskbar icons.
268 */
WmAwtTrayNotify(WPARAM wParam,LPARAM lParam)269 MsgRouting AwtTrayIcon::WmAwtTrayNotify(WPARAM wParam, LPARAM lParam)
270 {
271 MsgRouting mr = mrDoDefault;
272
273 POINT pos = {0, 0};
274 ::GetCursorPos(&pos);
275
276 lastMessage = (UINT)lParam;
277 UINT flags = AwtToolkit::GetInstance().GetMouseKeyState();
278
279 switch((UINT)lParam)
280 {
281 case WM_MOUSEMOVE:
282 mr = WmMouseMove(flags, pos.x, pos.y);
283 break;
284 case WM_LBUTTONDBLCLK:
285 case WM_LBUTTONDOWN:
286 mr = WmMouseDown(flags, pos.x, pos.y, LEFT_BUTTON);
287 break;
288 case WM_LBUTTONUP:
289 mr = WmMouseUp(flags, pos.x, pos.y, LEFT_BUTTON);
290 break;
291 case WM_RBUTTONDBLCLK:
292 case WM_RBUTTONDOWN:
293 mr = WmMouseDown(flags, pos.x, pos.y, RIGHT_BUTTON);
294 break;
295 case WM_RBUTTONUP:
296 mr = WmMouseUp(flags, pos.x, pos.y, RIGHT_BUTTON);
297 break;
298 case WM_MBUTTONDBLCLK:
299 case WM_MBUTTONDOWN:
300 mr = WmMouseDown(flags, pos.x, pos.y, MIDDLE_BUTTON);
301 break;
302 case WM_MBUTTONUP:
303 mr = WmMouseUp(flags, pos.x, pos.y, MIDDLE_BUTTON);
304 break;
305 case WM_CONTEXTMENU:
306 mr = WmContextMenu(0, pos.x, pos.y);
307 break;
308 case NIN_KEYSELECT:
309 mr = WmKeySelect(0, pos.x, pos.y);
310 break;
311 case NIN_SELECT:
312 mr = WmSelect(0, pos.x, pos.y);
313 break;
314 case NIN_BALLOONUSERCLICK:
315 mr = WmBalloonUserClick(0, pos.x, pos.y);
316 break;
317 }
318 return mr;
319 }
320
321 /* Double-click variables. */
322 static jlong multiClickTime = ::GetDoubleClickTime();
323 static int multiClickMaxX = ::GetSystemMetrics(SM_CXDOUBLECLK);
324 static int multiClickMaxY = ::GetSystemMetrics(SM_CYDOUBLECLK);
325 static AwtTrayIcon* lastClickTrIc = NULL;
326 static jlong lastTime = 0;
327 static int lastClickX = 0;
328 static int lastClickY = 0;
329 static int lastButton = 0;
330 static int clickCount = 0;
331
WmMouseDown(UINT flags,int x,int y,int button)332 MsgRouting AwtTrayIcon::WmMouseDown(UINT flags, int x, int y, int button)
333 {
334 jlong now = ::JVM_CurrentTimeMillis(NULL, 0);
335 jint javaModif = AwtComponent::GetJavaModifiers();
336
337 if (lastClickTrIc == this &&
338 lastButton == button &&
339 (now - lastTime) <= multiClickTime &&
340 abs(x - lastClickX) <= multiClickMaxX &&
341 abs(y - lastClickY) <= multiClickMaxY)
342 {
343 clickCount++;
344 } else {
345 clickCount = 1;
346 lastClickTrIc = this;
347 lastButton = button;
348 lastClickX = x;
349 lastClickY = y;
350 }
351 lastTime = now;
352 // it's needed only if WM_LBUTTONUP doesn't come for some reason
353 m_mouseButtonClickAllowed |= AwtComponent::GetButtonMK(button);
354
355 MSG msg;
356 AwtComponent::InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y);
357
358 SendMouseEvent(java_awt_event_MouseEvent_MOUSE_PRESSED, now, x, y,
359 javaModif, clickCount, JNI_FALSE,
360 AwtComponent::GetButton(button), &msg);
361
362 return mrConsume;
363 }
364
WmMouseUp(UINT flags,int x,int y,int button)365 MsgRouting AwtTrayIcon::WmMouseUp(UINT flags, int x, int y, int button)
366 {
367 MSG msg;
368 AwtComponent::InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y);
369
370 SendMouseEvent(java_awt_event_MouseEvent_MOUSE_RELEASED, ::JVM_CurrentTimeMillis(NULL, 0),
371 x, y, AwtComponent::GetJavaModifiers(), clickCount,
372 (AwtComponent::GetButton(button) == java_awt_event_MouseEvent_BUTTON3 ?
373 TRUE : FALSE), AwtComponent::GetButton(button), &msg);
374
375 if ((m_mouseButtonClickAllowed & AwtComponent::GetButtonMK(button)) != 0) { // No up-button in the drag-state
376 SendMouseEvent(java_awt_event_MouseEvent_MOUSE_CLICKED,
377 ::JVM_CurrentTimeMillis(NULL, 0), x, y, AwtComponent::GetJavaModifiers(),
378 clickCount, JNI_FALSE, AwtComponent::GetButton(button));
379 }
380 m_mouseButtonClickAllowed &= ~AwtComponent::GetButtonMK(button); // Exclude the up-button from the drag-state
381
382 return mrConsume;
383 }
384
WmMouseMove(UINT flags,int x,int y)385 MsgRouting AwtTrayIcon::WmMouseMove(UINT flags, int x, int y)
386 {
387 MSG msg;
388 static AwtTrayIcon* lastComp = NULL;
389 static int lastX = 0;
390 static int lastY = 0;
391
392 /*
393 * Workaround for CR#6267980
394 * Windows sends WM_MOUSEMOVE if mouse is motionless
395 */
396 if (lastComp != this || x != lastX || y != lastY) {
397 lastComp = this;
398 lastX = x;
399 lastY = y;
400 AwtComponent::InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y);
401 if ((flags & ALL_MK_BUTTONS) != 0) {
402 m_mouseButtonClickAllowed = 0;
403 } else {
404 SendMouseEvent(java_awt_event_MouseEvent_MOUSE_MOVED, ::JVM_CurrentTimeMillis(NULL, 0), x, y,
405 AwtComponent::GetJavaModifiers(), 0, JNI_FALSE,
406 java_awt_event_MouseEvent_NOBUTTON, &msg);
407 }
408 }
409 return mrConsume;
410 }
411
WmBalloonUserClick(UINT flags,int x,int y)412 MsgRouting AwtTrayIcon::WmBalloonUserClick(UINT flags, int x, int y)
413 {
414 // The windows api GetKeyState() when read would provide the key state of the requrested key
415 // but it is not guaranteed to receive the same as it is stored in the thread message queue and
416 // unless the thread runs faster.
417 // Event NIN_BALLOONUSERCLICK is received only upon left mouse click. Hence the additional check
418 // is not required.
419 MSG msg;
420 AwtComponent::InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y);
421 SendActionEvent(java_awt_event_ActionEvent_ACTION_PERFORMED, ::JVM_CurrentTimeMillis(NULL, 0),
422 AwtComponent::GetActionModifiers(), &msg);
423 return mrConsume;
424 }
425
WmKeySelect(UINT flags,int x,int y)426 MsgRouting AwtTrayIcon::WmKeySelect(UINT flags, int x, int y)
427 {
428 static jlong lastKeySelectTime = 0;
429 jlong now = ::JVM_CurrentTimeMillis(NULL, 0);
430
431 // If a user selects a notify icon with the ENTER key,
432 // Shell 5.0 sends double NIN_KEYSELECT notification.
433 if (lastKeySelectTime != now) {
434 MSG msg;
435 AwtComponent::InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y);
436 SendActionEvent(java_awt_event_ActionEvent_ACTION_PERFORMED, ::JVM_CurrentTimeMillis(NULL, 0),
437 AwtComponent::GetActionModifiers(), &msg);
438 }
439 lastKeySelectTime = now;
440
441 return mrConsume;
442 }
443
WmSelect(UINT flags,int x,int y)444 MsgRouting AwtTrayIcon::WmSelect(UINT flags, int x, int y)
445 {
446
447 // If a user click on a notify icon with the mouse,
448 // Shell 5.0 sends NIN_SELECT notification on every click.
449 // To be compatible with JDK6.0 only second click is important.
450 if (clickCount == 2) {
451 MSG msg;
452 AwtComponent::InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y);
453 SendActionEvent(java_awt_event_ActionEvent_ACTION_PERFORMED, ::JVM_CurrentTimeMillis(NULL, 0),
454 AwtComponent::GetActionModifiers(), &msg);
455 }
456 return mrConsume;
457 }
458
WmContextMenu(UINT flags,int x,int y)459 MsgRouting AwtTrayIcon::WmContextMenu(UINT flags, int x, int y)
460 {
461 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
462 jobject peer = GetPeer(env);
463 if (peer != NULL) {
464 JNU_CallMethodByName(env, NULL, peer, "showPopupMenu",
465 "(II)V", x, y);
466 }
467 return mrConsume;
468 }
469
470 /*
471 * Adds all icons we already have to taskbar.
472 * We use this method on taskbar recreation (see 6369062).
473 */
WmTaskbarCreated()474 MsgRouting AwtTrayIcon::WmTaskbarCreated() {
475 TrayIconListItem* item;
476 for (item = sm_trayIconList; item != NULL; item = item->m_next) {
477 BOOL result = item->m_trayIcon->SendTrayMessage(NIM_ADD);
478 // 6270114: Instructs the taskbar to behave according to the Shell version 5.0
479 if (result) {
480 item->m_trayIcon->SendTrayMessage(NIM_SETVERSION);
481 }
482 }
483 return mrDoDefault;
484 }
485
SendMouseEvent(jint id,jlong when,jint x,jint y,jint modifiers,jint clickCount,jboolean popupTrigger,jint button,MSG * pMsg)486 void AwtTrayIcon::SendMouseEvent(jint id, jlong when, jint x, jint y,
487 jint modifiers, jint clickCount,
488 jboolean popupTrigger, jint button,
489 MSG *pMsg)
490 {
491 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
492 if (GetPeer(env) == NULL) {
493 /* event received during termination. */
494 return;
495 }
496
497 static jclass mouseEventCls;
498 if (mouseEventCls == NULL) {
499 jclass mouseEventClsLocal =
500 env->FindClass("java/awt/event/MouseEvent");
501 if (!mouseEventClsLocal) {
502 /* exception already thrown */
503 return;
504 }
505 mouseEventCls = (jclass)env->NewGlobalRef(mouseEventClsLocal);
506 env->DeleteLocalRef(mouseEventClsLocal);
507 }
508
509 static jmethodID mouseEventConst;
510 if (mouseEventConst == NULL) {
511 mouseEventConst =
512 env->GetMethodID(mouseEventCls, "<init>",
513 "(Ljava/awt/Component;IJIIIIIIZI)V");
514 DASSERT(mouseEventConst);
515 CHECK_NULL(mouseEventConst);
516 }
517 if (env->EnsureLocalCapacity(2) < 0) {
518 return;
519 }
520 jobject target = GetTarget(env);
521 jobject mouseEvent = env->NewObject(mouseEventCls, mouseEventConst,
522 target,
523 id, when, modifiers,
524 x, y, // no client area coordinates
525 x, y,
526 clickCount, popupTrigger, button);
527
528 if (safe_ExceptionOccurred(env)) {
529 env->ExceptionDescribe();
530 env->ExceptionClear();
531 }
532
533 DASSERT(mouseEvent != NULL);
534 if (pMsg != 0) {
535 AwtAWTEvent::saveMSG(env, pMsg, mouseEvent);
536 }
537 SendEvent(mouseEvent);
538
539 env->DeleteLocalRef(mouseEvent);
540 env->DeleteLocalRef(target);
541 }
542
SendActionEvent(jint id,jlong when,jint modifiers,MSG * pMsg)543 void AwtTrayIcon::SendActionEvent(jint id, jlong when, jint modifiers, MSG *pMsg)
544 {
545 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
546 if (GetPeer(env) == NULL) {
547 /* event received during termination. */
548 return;
549 }
550
551 static jclass actionEventCls;
552 if (actionEventCls == NULL) {
553 jclass actionEventClsLocal =
554 env->FindClass("java/awt/event/ActionEvent");
555 if (!actionEventClsLocal) {
556 /* exception already thrown */
557 return;
558 }
559 actionEventCls = (jclass)env->NewGlobalRef(actionEventClsLocal);
560 env->DeleteLocalRef(actionEventClsLocal);
561 }
562
563 static jmethodID actionEventConst;
564 if (actionEventConst == NULL) {
565 actionEventConst =
566 env->GetMethodID(actionEventCls, "<init>",
567 "(Ljava/lang/Object;ILjava/lang/String;JI)V");
568 DASSERT(actionEventConst);
569 CHECK_NULL(actionEventConst);
570 }
571 if (env->EnsureLocalCapacity(2) < 0) {
572 return;
573 }
574 jobject target = GetTarget(env);
575 jstring actionCommand = (jstring)env->GetObjectField(target, AwtTrayIcon::actionCommandID);
576 jobject actionEvent = env->NewObject(actionEventCls, actionEventConst,
577 target, id, actionCommand, when, modifiers);
578
579 if (safe_ExceptionOccurred(env)) {
580 env->ExceptionDescribe();
581 env->ExceptionClear();
582 }
583
584 DASSERT(actionEvent != NULL);
585 if (pMsg != 0) {
586 AwtAWTEvent::saveMSG(env, pMsg, actionEvent);
587 }
588 SendEvent(actionEvent);
589
590 env->DeleteLocalRef(actionEvent);
591 env->DeleteLocalRef(target);
592 env->DeleteLocalRef(actionCommand);
593 }
594
SearchTrayIconItem(UINT id)595 AwtTrayIcon* AwtTrayIcon::SearchTrayIconItem(UINT id) {
596 TrayIconListItem* item;
597 for (item = sm_trayIconList; item != NULL; item = item->m_next) {
598 if (item->m_ID == id) {
599 return item->m_trayIcon;
600 }
601 }
602 /*
603 * DASSERT(FALSE);
604 * This should not be happend if all tray icons are recorded
605 */
606 return NULL;
607 }
608
RemoveTrayIconItem(UINT id)609 void AwtTrayIcon::RemoveTrayIconItem(UINT id) {
610 TrayIconListItem* item = sm_trayIconList;
611 TrayIconListItem* lastItem = NULL;
612 while (item != NULL) {
613 if (item->m_ID == id) {
614 if (lastItem == NULL) {
615 sm_trayIconList = item->m_next;
616 } else {
617 lastItem->m_next = item->m_next;
618 }
619 item->m_next = NULL;
620 DASSERT(item != NULL);
621 delete item;
622 return;
623 }
624 lastItem = item;
625 item = item->m_next;
626 }
627 }
628
LinkObjects(JNIEnv * env,jobject peer)629 void AwtTrayIcon::LinkObjects(JNIEnv *env, jobject peer)
630 {
631 if (m_peerObject == NULL) {
632 m_peerObject = env->NewGlobalRef(peer);
633 }
634
635 /* Bind JavaPeer -> C++*/
636 JNI_SET_PDATA(peer, this);
637 }
638
UnlinkObjects()639 void AwtTrayIcon::UnlinkObjects()
640 {
641 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
642 if (m_peerObject) {
643 JNI_SET_PDATA(m_peerObject, static_cast<PDATA>(NULL));
644 env->DeleteGlobalRef(m_peerObject);
645 m_peerObject = NULL;
646 }
647 }
648
CreateBMP(HWND hW,int * imageData,int nSS,int nW,int nH)649 HBITMAP AwtTrayIcon::CreateBMP(HWND hW,int* imageData,int nSS, int nW, int nH)
650 {
651 Bitmapheader bmhHeader = {0};
652 HDC hDC;
653 char *ptrImageData;
654 HBITMAP hbmpBitmap;
655 HBITMAP hBitmap;
656 int nNumChannels = 4;
657
658 if (!hW) {
659 hW = ::GetDesktopWindow();
660 }
661 hDC = ::GetDC(hW);
662 if (!hDC) {
663 return NULL;
664 }
665
666 bmhHeader.bmiHeader.bV5Size = sizeof(BITMAPV5HEADER);
667 bmhHeader.bmiHeader.bV5Width = nW;
668 bmhHeader.bmiHeader.bV5Height = -nH;
669 bmhHeader.bmiHeader.bV5Planes = 1;
670
671 bmhHeader.bmiHeader.bV5BitCount = 32;
672 bmhHeader.bmiHeader.bV5Compression = BI_BITFIELDS;
673
674 // The following mask specification specifies a supported 32 BPP
675 // alpha format for Windows XP.
676 bmhHeader.bmiHeader.bV5RedMask = 0x00FF0000;
677 bmhHeader.bmiHeader.bV5GreenMask = 0x0000FF00;
678 bmhHeader.bmiHeader.bV5BlueMask = 0x000000FF;
679 bmhHeader.bmiHeader.bV5AlphaMask = 0xFF000000;
680
681 hbmpBitmap = ::CreateDIBSection(hDC, (BITMAPINFO*)&(bmhHeader),
682 DIB_RGB_COLORS,
683 (void**)&(ptrImageData),
684 NULL, 0);
685 int *srcPtr = imageData;
686 char *dstPtr = ptrImageData;
687 if (!dstPtr) {
688 ReleaseDC(hW, hDC);
689 return NULL;
690 }
691 for (int nOutern = 0; nOutern < nH; nOutern++) {
692 for (int nInner = 0; nInner < nSS; nInner++) {
693 dstPtr[3] = (*srcPtr >> 0x18) & 0xFF;
694 dstPtr[2] = (*srcPtr >> 0x10) & 0xFF;
695 dstPtr[1] = (*srcPtr >> 0x08) & 0xFF;
696 dstPtr[0] = *srcPtr & 0xFF;
697
698 srcPtr++;
699 dstPtr += nNumChannels;
700 }
701 }
702
703 // convert it into DDB to make CustomCursor work on WIN95
704 hBitmap = CreateDIBitmap(hDC,
705 (BITMAPINFOHEADER*)&bmhHeader,
706 CBM_INIT,
707 (void *)ptrImageData,
708 (BITMAPINFO*)&bmhHeader,
709 DIB_RGB_COLORS);
710
711 ::DeleteObject(hbmpBitmap);
712 ::ReleaseDC(hW, hDC);
713 // ::GdiFlush();
714 return hBitmap;
715 }
716
SetToolTip(LPCTSTR tooltip)717 void AwtTrayIcon::SetToolTip(LPCTSTR tooltip)
718 {
719 if (tooltip == NULL) {
720 m_nid.szTip[0] = '\0';
721 } else if (lstrlen(tooltip) >= TRAY_ICON_TOOLTIP_MAX_SIZE) {
722 _tcsncpy(m_nid.szTip, tooltip, TRAY_ICON_TOOLTIP_MAX_SIZE);
723 m_nid.szTip[TRAY_ICON_TOOLTIP_MAX_SIZE - 1] = '\0';
724 } else {
725 _tcscpy_s(m_nid.szTip, TRAY_ICON_TOOLTIP_MAX_SIZE, tooltip);
726 }
727
728 SendTrayMessage(NIM_MODIFY);
729 }
730
_SetToolTip(void * param)731 void AwtTrayIcon::_SetToolTip(void *param)
732 {
733 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
734 SetToolTipStruct *sts = (SetToolTipStruct *)param;
735 jobject self = sts->trayIcon;
736 jstring jtooltip = sts->tooltip;
737 AwtTrayIcon *trayIcon = NULL;
738 LPCTSTR tooltipStr = NULL;
739
740 PDATA pData;
741 JNI_CHECK_PEER_GOTO(self, ret);
742 trayIcon = (AwtTrayIcon *)pData;
743
744 if (jtooltip == NULL) {
745 trayIcon->SetToolTip(NULL);
746 goto ret;
747 }
748
749 tooltipStr = JNU_GetStringPlatformChars(env, jtooltip, (jboolean *)NULL);
750 if (env->ExceptionCheck()) goto ret;
751 trayIcon->SetToolTip(tooltipStr);
752 JNU_ReleaseStringPlatformChars(env, jtooltip, tooltipStr);
753 ret:
754 env->DeleteGlobalRef(self);
755 env->DeleteGlobalRef(jtooltip);
756 delete sts;
757 }
758
SetIcon(HICON hIcon)759 void AwtTrayIcon::SetIcon(HICON hIcon)
760 {
761 ::DestroyIcon(m_nid.hIcon);
762 m_nid.hIcon = hIcon;
763 }
764
_SetIcon(void * param)765 void AwtTrayIcon::_SetIcon(void *param)
766 {
767 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
768 SetIconStruct *sis = (SetIconStruct *)param;
769 jobject self = sis->trayIcon;
770 HICON hIcon = sis->hIcon;
771 AwtTrayIcon *trayIcon = NULL;
772
773 PDATA pData;
774 JNI_CHECK_PEER_GOTO(self, ret);
775 trayIcon = (AwtTrayIcon *)pData;
776
777 trayIcon->SetIcon(hIcon);
778
779 ret:
780 env->DeleteGlobalRef(self);
781 delete sis;
782 }
783
_UpdateIcon(void * param)784 void AwtTrayIcon::_UpdateIcon(void *param)
785 {
786 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
787 UpdateIconStruct *uis = (UpdateIconStruct *)param;
788 jobject self = uis->trayIcon;
789 jboolean jupdate = uis->update;
790 AwtTrayIcon *trayIcon = NULL;
791
792 PDATA pData;
793 JNI_CHECK_PEER_GOTO(self, ret);
794 trayIcon = (AwtTrayIcon *)pData;
795
796 BOOL result = trayIcon->SendTrayMessage(jupdate == JNI_TRUE ? NIM_MODIFY : NIM_ADD);
797 // 6270114: Instructs the taskbar to behave according to the Shell version 5.0
798 if (result && jupdate == JNI_FALSE) {
799 trayIcon->SendTrayMessage(NIM_SETVERSION);
800 }
801 ret:
802 env->DeleteGlobalRef(self);
803 delete uis;
804 }
805
DisplayMessage(LPCTSTR caption,LPCTSTR text,LPCTSTR msgType)806 void AwtTrayIcon::DisplayMessage(LPCTSTR caption, LPCTSTR text, LPCTSTR msgType)
807 {
808 m_nid.uFlags |= NIF_INFO;
809 m_nid.uTimeout = 10000;
810
811 if (lstrcmp(msgType, TEXT("ERROR")) == 0) {
812 m_nid.dwInfoFlags = NIIF_ERROR;
813 } else if (lstrcmp(msgType, TEXT("WARNING")) == 0) {
814 m_nid.dwInfoFlags = NIIF_WARNING;
815 } else if (lstrcmp(msgType, TEXT("INFO")) == 0) {
816 m_nid.dwInfoFlags = NIIF_INFO;
817 } else if (lstrcmp(msgType, TEXT("NONE")) == 0) {
818 m_nid.dwInfoFlags = NIIF_NONE;
819 } else {
820 m_nid.dwInfoFlags = NIIF_NONE;
821 }
822
823 if (caption[0] == '\0') {
824 m_nid.szInfoTitle[0] = '\0';
825
826 } else if (lstrlen(caption) >= TRAY_ICON_BALLOON_TITLE_MAX_SIZE) {
827
828 _tcsncpy(m_nid.szInfoTitle, caption, TRAY_ICON_BALLOON_TITLE_MAX_SIZE);
829 m_nid.szInfoTitle[TRAY_ICON_BALLOON_TITLE_MAX_SIZE - 1] = '\0';
830
831 } else {
832 _tcscpy_s(m_nid.szInfoTitle, TRAY_ICON_BALLOON_TITLE_MAX_SIZE, caption);
833 }
834
835 if (text[0] == '\0') {
836 m_nid.szInfo[0] = ' ';
837 m_nid.szInfo[1] = '\0';
838
839 } else if (lstrlen(text) >= TRAY_ICON_BALLOON_INFO_MAX_SIZE) {
840
841 _tcsncpy(m_nid.szInfo, text, TRAY_ICON_BALLOON_INFO_MAX_SIZE);
842 m_nid.szInfo[TRAY_ICON_BALLOON_INFO_MAX_SIZE - 1] = '\0';
843
844 } else {
845 _tcscpy_s(m_nid.szInfo, TRAY_ICON_BALLOON_INFO_MAX_SIZE, text);
846 }
847
848 SendTrayMessage(NIM_MODIFY);
849 m_nid.uFlags &= ~NIF_INFO;
850 }
851
_DisplayMessage(void * param)852 void AwtTrayIcon::_DisplayMessage(void *param)
853 {
854 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
855 DisplayMessageStruct *dms = (DisplayMessageStruct *)param;
856 jobject self = dms->trayIcon;
857 jstring jcaption = dms->caption;
858 jstring jtext = dms-> text;
859 jstring jmsgType = dms->msgType;
860 AwtTrayIcon *trayIcon = NULL;
861 LPCTSTR captionStr = NULL;
862 LPCTSTR textStr = NULL;
863 LPCTSTR msgTypeStr = NULL;
864
865 PDATA pData;
866 JNI_CHECK_PEER_GOTO(self, ret);
867 trayIcon = (AwtTrayIcon *)pData;
868
869 captionStr = JNU_GetStringPlatformChars(env, jcaption, (jboolean *)NULL);
870 if (env->ExceptionCheck()) goto ret;
871 textStr = JNU_GetStringPlatformChars(env, jtext, (jboolean *)NULL);
872 if (env->ExceptionCheck()) {
873 JNU_ReleaseStringPlatformChars(env, jcaption, captionStr);
874 goto ret;
875 }
876 msgTypeStr = JNU_GetStringPlatformChars(env, jmsgType, (jboolean *)NULL);
877 if (env->ExceptionCheck()) {
878 JNU_ReleaseStringPlatformChars(env, jcaption, captionStr);
879 JNU_ReleaseStringPlatformChars(env, jtext, textStr);
880 goto ret;
881 }
882 trayIcon->DisplayMessage(captionStr, textStr, msgTypeStr);
883
884 JNU_ReleaseStringPlatformChars(env, jcaption, captionStr);
885 JNU_ReleaseStringPlatformChars(env, jtext, textStr);
886 JNU_ReleaseStringPlatformChars(env, jmsgType, msgTypeStr);
887 ret:
888 env->DeleteGlobalRef(self);
889 env->DeleteGlobalRef(jcaption);
890 env->DeleteGlobalRef(jtext);
891 env->DeleteGlobalRef(jmsgType);
892 delete dms;
893 }
894
895 /************************************************************************
896 * TrayIcon native methods
897 */
898
899 extern "C" {
900
901 /*
902 * Class: java_awt_TrayIcon
903 * Method: initIDs
904 * Signature: ()V
905 */
906 JNIEXPORT void JNICALL
Java_java_awt_TrayIcon_initIDs(JNIEnv * env,jclass cls)907 Java_java_awt_TrayIcon_initIDs(JNIEnv *env, jclass cls)
908 {
909 TRY;
910
911 /* init field ids */
912 AwtTrayIcon::idID = env->GetFieldID(cls, "id", "I");
913 DASSERT(AwtTrayIcon::idID != NULL);
914 CHECK_NULL(AwtTrayIcon::idID);
915
916 AwtTrayIcon::actionCommandID = env->GetFieldID(cls, "actionCommand", "Ljava/lang/String;");
917 DASSERT(AwtTrayIcon::actionCommandID != NULL);
918 CHECK_NULL( AwtTrayIcon::actionCommandID);
919
920 CATCH_BAD_ALLOC;
921 }
922
923 /*
924 * Class: sun_awt_windows_WTrayIconPeer
925 * Method: create
926 * Signature: ()V
927 */
928 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTrayIconPeer_create(JNIEnv * env,jobject self)929 Java_sun_awt_windows_WTrayIconPeer_create(JNIEnv *env, jobject self)
930 {
931 TRY;
932
933 AwtToolkit::CreateComponent(self, NULL,
934 (AwtToolkit::ComponentFactory)
935 AwtTrayIcon::Create);
936 PDATA pData;
937 JNI_CHECK_PEER_CREATION_RETURN(self);
938
939 CATCH_BAD_ALLOC;
940 }
941
942 /*
943 * Class: sun_awt_windows_WTrayIconPeer
944 * Method: _dispose
945 * Signature: ()V
946 */
947 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTrayIconPeer__1dispose(JNIEnv * env,jobject self)948 Java_sun_awt_windows_WTrayIconPeer__1dispose(JNIEnv *env, jobject self)
949 {
950 TRY;
951
952 AwtObject::_Dispose(self);
953
954 CATCH_BAD_ALLOC;
955 }
956
957 /*
958 * Class: sun_awt_windows_WTrayIconPeer
959 * Method: _setToolTip
960 * Signature: ()V
961 */
962 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTrayIconPeer_setToolTip(JNIEnv * env,jobject self,jstring tooltip)963 Java_sun_awt_windows_WTrayIconPeer_setToolTip(JNIEnv *env, jobject self,
964 jstring tooltip)
965 {
966 TRY;
967
968 SetToolTipStruct *sts = new SetToolTipStruct;
969 sts->trayIcon = env->NewGlobalRef(self);
970 if (tooltip != NULL) {
971 sts->tooltip = (jstring)env->NewGlobalRef(tooltip);
972 } else {
973 sts->tooltip = NULL;
974 }
975
976 AwtToolkit::GetInstance().SyncCall(AwtTrayIcon::_SetToolTip, sts);
977 // global ref and sts are deleted in _SetToolTip
978
979 CATCH_BAD_ALLOC;
980 }
981
982 /*
983 * Class: sun_awt_windows_WTrayIconPeer
984 * Method: setNativeIcon
985 * Signature: (I[B[IIIII)V
986 */
987 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTrayIconPeer_setNativeIcon(JNIEnv * env,jobject self,jintArray intRasterData,jbyteArray andMask,jint nSS,jint nW,jint nH)988 Java_sun_awt_windows_WTrayIconPeer_setNativeIcon(JNIEnv *env, jobject self,
989 jintArray intRasterData, jbyteArray andMask,
990 jint nSS, jint nW, jint nH)
991 {
992 TRY;
993
994 int length = env->GetArrayLength(andMask);
995 jbyte *andMaskPtr = new jbyte[length];
996
997 env->GetByteArrayRegion(andMask, 0, length, andMaskPtr);
998
999 HBITMAP hMask = ::CreateBitmap(nW, nH, 1, 1, (BYTE *)andMaskPtr);
1000 // ::GdiFlush();
1001
1002 delete[] andMaskPtr;
1003
1004 jint *intRasterDataPtr = NULL;
1005 HBITMAP hColor = NULL;
1006 try {
1007 intRasterDataPtr = (jint *)env->GetPrimitiveArrayCritical(intRasterData, 0);
1008 if (intRasterDataPtr == NULL) {
1009 ::DeleteObject(hMask);
1010 return;
1011 }
1012 hColor = AwtTrayIcon::CreateBMP(NULL, (int *)intRasterDataPtr, nSS, nW, nH);
1013 } catch (...) {
1014 if (intRasterDataPtr != NULL) {
1015 env->ReleasePrimitiveArrayCritical(intRasterData, intRasterDataPtr, 0);
1016 }
1017 ::DeleteObject(hMask);
1018 throw;
1019 }
1020
1021 env->ReleasePrimitiveArrayCritical(intRasterData, intRasterDataPtr, 0);
1022 intRasterDataPtr = NULL;
1023
1024 HICON hIcon = NULL;
1025
1026 if (hMask && hColor) {
1027 ICONINFO icnInfo;
1028 memset(&icnInfo, 0, sizeof(ICONINFO));
1029 icnInfo.hbmMask = hMask;
1030 icnInfo.hbmColor = hColor;
1031 icnInfo.fIcon = TRUE;
1032 icnInfo.xHotspot = TRAY_ICON_X_HOTSPOT;
1033 icnInfo.yHotspot = TRAY_ICON_Y_HOTSPOT;
1034
1035 hIcon = ::CreateIconIndirect(&icnInfo);
1036 }
1037 ::DeleteObject(hColor);
1038 ::DeleteObject(hMask);
1039
1040 //////////////////////////////////////////
1041
1042 SetIconStruct *sis = new SetIconStruct;
1043 sis->trayIcon = env->NewGlobalRef(self);
1044 sis->hIcon = hIcon;
1045
1046 AwtToolkit::GetInstance().SyncCall(AwtTrayIcon::_SetIcon, sis);
1047 // global ref is deleted in _SetIcon
1048
1049 CATCH_BAD_ALLOC;
1050 }
1051
1052 /*
1053 * Class: sun_awt_windows_WTrayIconPeer
1054 * Method: updateNativeIcon
1055 * Signature: (Z)V
1056 */
1057 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTrayIconPeer_updateNativeIcon(JNIEnv * env,jobject self,jboolean doUpdate)1058 Java_sun_awt_windows_WTrayIconPeer_updateNativeIcon(JNIEnv *env, jobject self,
1059 jboolean doUpdate)
1060 {
1061 TRY;
1062
1063 UpdateIconStruct *uis = new UpdateIconStruct;
1064 uis->trayIcon = env->NewGlobalRef(self);
1065 uis->update = doUpdate;
1066
1067 AwtToolkit::GetInstance().SyncCall(AwtTrayIcon::_UpdateIcon, uis);
1068 // global ref is deleted in _UpdateIcon
1069
1070 CATCH_BAD_ALLOC;
1071 }
1072
1073 /*
1074 * Class: sun_awt_windows_WTrayIconPeer
1075 * Method: displayMessage
1076 * Signature: ()V;
1077 */
1078 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTrayIconPeer__1displayMessage(JNIEnv * env,jobject self,jstring caption,jstring text,jstring msgType)1079 Java_sun_awt_windows_WTrayIconPeer__1displayMessage(JNIEnv *env, jobject self,
1080 jstring caption, jstring text, jstring msgType)
1081 {
1082 TRY;
1083
1084 DisplayMessageStruct *dms = new DisplayMessageStruct;
1085 dms->trayIcon = env->NewGlobalRef(self);
1086 dms->caption = (jstring)env->NewGlobalRef(caption);
1087 dms->text = (jstring)env->NewGlobalRef(text);
1088 dms->msgType = (jstring)env->NewGlobalRef(msgType);
1089
1090 AwtToolkit::GetInstance().SyncCall(AwtTrayIcon::_DisplayMessage, dms);
1091 // global ref is deleted in _DisplayMessage
1092
1093 CATCH_BAD_ALLOC(NULL);
1094 }
1095
1096 } /* extern "C" */
1097