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 = TimeHelper::getMessageTimeUTC();
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, TimeHelper::getMessageTimeUTC(),
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                        TimeHelper::getMessageTimeUTC(), 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, TimeHelper::getMessageTimeUTC(), 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     if (AwtComponent::GetJavaModifiers() & java_awt_event_InputEvent_BUTTON1_DOWN_MASK) {
415         MSG msg;
416         AwtComponent::InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y);
417         SendActionEvent(java_awt_event_ActionEvent_ACTION_PERFORMED, TimeHelper::getMessageTimeUTC(),
418                         AwtComponent::GetJavaModifiers(), &msg);
419     }
420     return mrConsume;
421 }
422 
WmKeySelect(UINT flags,int x,int y)423 MsgRouting AwtTrayIcon::WmKeySelect(UINT flags, int x, int y)
424 {
425     static jlong lastKeySelectTime = 0;
426     jlong now = TimeHelper::getMessageTimeUTC();
427 
428     // If a user selects a notify icon with the ENTER key,
429     // Shell 5.0 sends double NIN_KEYSELECT notification.
430     if (lastKeySelectTime != now) {
431         MSG msg;
432         AwtComponent::InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y);
433         SendActionEvent(java_awt_event_ActionEvent_ACTION_PERFORMED, TimeHelper::getMessageTimeUTC(),
434                         AwtComponent::GetJavaModifiers(), &msg);
435     }
436     lastKeySelectTime = now;
437 
438     return mrConsume;
439 }
440 
WmSelect(UINT flags,int x,int y)441 MsgRouting AwtTrayIcon::WmSelect(UINT flags, int x, int y)
442 {
443 
444     // If a user click on a notify icon with the mouse,
445     // Shell 5.0 sends NIN_SELECT notification on every click.
446     // To be compatible with JDK6.0 only second click is important.
447     if (clickCount == 2) {
448         MSG msg;
449         AwtComponent::InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y);
450         SendActionEvent(java_awt_event_ActionEvent_ACTION_PERFORMED, TimeHelper::getMessageTimeUTC(),
451                         AwtComponent::GetJavaModifiers(), &msg);
452     }
453     return mrConsume;
454 }
455 
WmContextMenu(UINT flags,int x,int y)456 MsgRouting AwtTrayIcon::WmContextMenu(UINT flags, int x, int y)
457 {
458     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
459     jobject peer = GetPeer(env);
460     if (peer != NULL) {
461         JNU_CallMethodByName(env, NULL, peer, "showPopupMenu",
462                              "(II)V", x, y);
463     }
464     return mrConsume;
465 }
466 
467 /*
468  * Adds all icons we already have to taskbar.
469  * We use this method on taskbar recreation (see 6369062).
470  */
WmTaskbarCreated()471 MsgRouting AwtTrayIcon::WmTaskbarCreated() {
472     TrayIconListItem* item;
473     for (item = sm_trayIconList; item != NULL; item = item->m_next) {
474         BOOL result = item->m_trayIcon->SendTrayMessage(NIM_ADD);
475         // 6270114: Instructs the taskbar to behave according to the Shell version 5.0
476         if (result) {
477             item->m_trayIcon->SendTrayMessage(NIM_SETVERSION);
478         }
479     }
480     return mrDoDefault;
481 }
482 
SendMouseEvent(jint id,jlong when,jint x,jint y,jint modifiers,jint clickCount,jboolean popupTrigger,jint button,MSG * pMsg)483 void AwtTrayIcon::SendMouseEvent(jint id, jlong when, jint x, jint y,
484                                  jint modifiers, jint clickCount,
485                                  jboolean popupTrigger, jint button,
486                                  MSG *pMsg)
487 {
488     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
489     if (GetPeer(env) == NULL) {
490         /* event received during termination. */
491         return;
492     }
493 
494     static jclass mouseEventCls;
495     if (mouseEventCls == NULL) {
496         jclass mouseEventClsLocal =
497             env->FindClass("java/awt/event/MouseEvent");
498         if (!mouseEventClsLocal) {
499             /* exception already thrown */
500             return;
501         }
502         mouseEventCls = (jclass)env->NewGlobalRef(mouseEventClsLocal);
503         env->DeleteLocalRef(mouseEventClsLocal);
504     }
505 
506     static jmethodID mouseEventConst;
507     if (mouseEventConst == NULL) {
508         mouseEventConst =
509             env->GetMethodID(mouseEventCls, "<init>",
510                              "(Ljava/awt/Component;IJIIIIIIZI)V");
511         DASSERT(mouseEventConst);
512         CHECK_NULL(mouseEventConst);
513     }
514     if (env->EnsureLocalCapacity(2) < 0) {
515         return;
516     }
517     jobject target = GetTarget(env);
518     jobject mouseEvent = env->NewObject(mouseEventCls, mouseEventConst,
519                                         target,
520                                         id, when, modifiers,
521                                         x, y, // no client area coordinates
522                                         x, y,
523                                         clickCount, popupTrigger, button);
524 
525     if (safe_ExceptionOccurred(env)) {
526         env->ExceptionDescribe();
527         env->ExceptionClear();
528     }
529 
530     DASSERT(mouseEvent != NULL);
531     if (pMsg != 0) {
532         AwtAWTEvent::saveMSG(env, pMsg, mouseEvent);
533     }
534     SendEvent(mouseEvent);
535 
536     env->DeleteLocalRef(mouseEvent);
537     env->DeleteLocalRef(target);
538 }
539 
SendActionEvent(jint id,jlong when,jint modifiers,MSG * pMsg)540 void AwtTrayIcon::SendActionEvent(jint id, jlong when, jint modifiers, MSG *pMsg)
541 {
542     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
543     if (GetPeer(env) == NULL) {
544         /* event received during termination. */
545         return;
546     }
547 
548     static jclass actionEventCls;
549     if (actionEventCls == NULL) {
550         jclass actionEventClsLocal =
551             env->FindClass("java/awt/event/ActionEvent");
552         if (!actionEventClsLocal) {
553             /* exception already thrown */
554             return;
555         }
556         actionEventCls = (jclass)env->NewGlobalRef(actionEventClsLocal);
557         env->DeleteLocalRef(actionEventClsLocal);
558     }
559 
560     static jmethodID actionEventConst;
561     if (actionEventConst == NULL) {
562         actionEventConst =
563             env->GetMethodID(actionEventCls, "<init>",
564                              "(Ljava/lang/Object;ILjava/lang/String;JI)V");
565         DASSERT(actionEventConst);
566         CHECK_NULL(actionEventConst);
567     }
568     if (env->EnsureLocalCapacity(2) < 0) {
569         return;
570     }
571     jobject target = GetTarget(env);
572     jstring actionCommand = (jstring)env->GetObjectField(target, AwtTrayIcon::actionCommandID);
573     jobject actionEvent = env->NewObject(actionEventCls, actionEventConst,
574                                          target, id, actionCommand, when, modifiers);
575 
576     if (safe_ExceptionOccurred(env)) {
577         env->ExceptionDescribe();
578         env->ExceptionClear();
579     }
580 
581     DASSERT(actionEvent != NULL);
582     if (pMsg != 0) {
583         AwtAWTEvent::saveMSG(env, pMsg, actionEvent);
584     }
585     SendEvent(actionEvent);
586 
587     env->DeleteLocalRef(actionEvent);
588     env->DeleteLocalRef(target);
589     env->DeleteLocalRef(actionCommand);
590 }
591 
SearchTrayIconItem(UINT id)592 AwtTrayIcon* AwtTrayIcon::SearchTrayIconItem(UINT id) {
593     TrayIconListItem* item;
594     for (item = sm_trayIconList; item != NULL; item = item->m_next) {
595         if (item->m_ID == id) {
596             return item->m_trayIcon;
597         }
598     }
599     /*
600      * DASSERT(FALSE);
601      * This should not be happend if all tray icons are recorded
602      */
603     return NULL;
604 }
605 
RemoveTrayIconItem(UINT id)606 void AwtTrayIcon::RemoveTrayIconItem(UINT id) {
607     TrayIconListItem* item = sm_trayIconList;
608     TrayIconListItem* lastItem = NULL;
609     while (item != NULL) {
610         if (item->m_ID == id) {
611             if (lastItem == NULL) {
612                 sm_trayIconList = item->m_next;
613             } else {
614                 lastItem->m_next = item->m_next;
615             }
616             item->m_next = NULL;
617             DASSERT(item != NULL);
618             delete item;
619             return;
620         }
621         lastItem = item;
622         item = item->m_next;
623     }
624 }
625 
LinkObjects(JNIEnv * env,jobject peer)626 void AwtTrayIcon::LinkObjects(JNIEnv *env, jobject peer)
627 {
628     if (m_peerObject == NULL) {
629         m_peerObject = env->NewGlobalRef(peer);
630     }
631 
632     /* Bind JavaPeer -> C++*/
633     JNI_SET_PDATA(peer, this);
634 }
635 
UnlinkObjects()636 void AwtTrayIcon::UnlinkObjects()
637 {
638     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
639     if (m_peerObject) {
640         JNI_SET_PDATA(m_peerObject, static_cast<PDATA>(NULL));
641         env->DeleteGlobalRef(m_peerObject);
642         m_peerObject = NULL;
643     }
644 }
645 
CreateBMP(HWND hW,int * imageData,int nSS,int nW,int nH)646 HBITMAP AwtTrayIcon::CreateBMP(HWND hW,int* imageData,int nSS, int nW, int nH)
647 {
648     Bitmapheader    bmhHeader = {0};
649     HDC             hDC;
650     char            *ptrImageData;
651     HBITMAP         hbmpBitmap;
652     HBITMAP         hBitmap;
653     int             nNumChannels    = 4;
654 
655     if (!hW) {
656         hW = ::GetDesktopWindow();
657     }
658     hDC = ::GetDC(hW);
659     if (!hDC) {
660         return NULL;
661     }
662 
663     bmhHeader.bmiHeader.bV5Size              = sizeof(BITMAPV5HEADER);
664     bmhHeader.bmiHeader.bV5Width             = nW;
665     bmhHeader.bmiHeader.bV5Height            = -nH;
666     bmhHeader.bmiHeader.bV5Planes            = 1;
667 
668     bmhHeader.bmiHeader.bV5BitCount          = 32;
669     bmhHeader.bmiHeader.bV5Compression       = BI_BITFIELDS;
670 
671     // The following mask specification specifies a supported 32 BPP
672     // alpha format for Windows XP.
673     bmhHeader.bmiHeader.bV5RedMask   =  0x00FF0000;
674     bmhHeader.bmiHeader.bV5GreenMask =  0x0000FF00;
675     bmhHeader.bmiHeader.bV5BlueMask  =  0x000000FF;
676     bmhHeader.bmiHeader.bV5AlphaMask =  0xFF000000;
677 
678     hbmpBitmap = ::CreateDIBSection(hDC, (BITMAPINFO*)&(bmhHeader),
679                                     DIB_RGB_COLORS,
680                                     (void**)&(ptrImageData),
681                                     NULL, 0);
682     int  *srcPtr = imageData;
683     char *dstPtr = ptrImageData;
684     if (!dstPtr) {
685         ReleaseDC(hW, hDC);
686         return NULL;
687     }
688     for (int nOutern = 0; nOutern < nH; nOutern++) {
689         for (int nInner = 0; nInner < nSS; nInner++) {
690             dstPtr[3] = (*srcPtr >> 0x18) & 0xFF;
691             dstPtr[2] = (*srcPtr >> 0x10) & 0xFF;
692             dstPtr[1] = (*srcPtr >> 0x08) & 0xFF;
693             dstPtr[0] = *srcPtr & 0xFF;
694 
695             srcPtr++;
696             dstPtr += nNumChannels;
697         }
698     }
699 
700     // convert it into DDB to make CustomCursor work on WIN95
701     hBitmap = CreateDIBitmap(hDC,
702                              (BITMAPINFOHEADER*)&bmhHeader,
703                              CBM_INIT,
704                              (void *)ptrImageData,
705                              (BITMAPINFO*)&bmhHeader,
706                              DIB_RGB_COLORS);
707 
708     ::DeleteObject(hbmpBitmap);
709     ::ReleaseDC(hW, hDC);
710 //  ::GdiFlush();
711     return hBitmap;
712 }
713 
SetToolTip(LPCTSTR tooltip)714 void AwtTrayIcon::SetToolTip(LPCTSTR tooltip)
715 {
716     if (tooltip == NULL) {
717         m_nid.szTip[0] = '\0';
718     } else if (lstrlen(tooltip) >= TRAY_ICON_TOOLTIP_MAX_SIZE) {
719         _tcsncpy(m_nid.szTip, tooltip, TRAY_ICON_TOOLTIP_MAX_SIZE);
720         m_nid.szTip[TRAY_ICON_TOOLTIP_MAX_SIZE - 1] = '\0';
721     } else {
722         _tcscpy_s(m_nid.szTip, TRAY_ICON_TOOLTIP_MAX_SIZE, tooltip);
723     }
724 
725     SendTrayMessage(NIM_MODIFY);
726 }
727 
_SetToolTip(void * param)728 void AwtTrayIcon::_SetToolTip(void *param)
729 {
730     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
731     SetToolTipStruct *sts = (SetToolTipStruct *)param;
732     jobject self = sts->trayIcon;
733     jstring jtooltip = sts->tooltip;
734     AwtTrayIcon *trayIcon = NULL;
735     LPCTSTR tooltipStr = NULL;
736 
737     PDATA pData;
738     JNI_CHECK_PEER_GOTO(self, ret);
739     trayIcon = (AwtTrayIcon *)pData;
740 
741     if (jtooltip == NULL) {
742         trayIcon->SetToolTip(NULL);
743         goto ret;
744     }
745 
746     tooltipStr = JNU_GetStringPlatformChars(env, jtooltip, (jboolean *)NULL);
747     if (env->ExceptionCheck()) goto ret;
748     trayIcon->SetToolTip(tooltipStr);
749     JNU_ReleaseStringPlatformChars(env, jtooltip, tooltipStr);
750 ret:
751     env->DeleteGlobalRef(self);
752     env->DeleteGlobalRef(jtooltip);
753     delete sts;
754 }
755 
SetIcon(HICON hIcon)756 void AwtTrayIcon::SetIcon(HICON hIcon)
757 {
758     ::DestroyIcon(m_nid.hIcon);
759     m_nid.hIcon = hIcon;
760 }
761 
_SetIcon(void * param)762 void AwtTrayIcon::_SetIcon(void *param)
763 {
764     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
765     SetIconStruct *sis = (SetIconStruct *)param;
766     jobject self = sis->trayIcon;
767     HICON hIcon = sis->hIcon;
768     AwtTrayIcon *trayIcon = NULL;
769 
770     PDATA pData;
771     JNI_CHECK_PEER_GOTO(self, ret);
772     trayIcon = (AwtTrayIcon *)pData;
773 
774     trayIcon->SetIcon(hIcon);
775 
776 ret:
777     env->DeleteGlobalRef(self);
778     delete sis;
779 }
780 
_UpdateIcon(void * param)781 void AwtTrayIcon::_UpdateIcon(void *param)
782 {
783     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
784     UpdateIconStruct *uis = (UpdateIconStruct *)param;
785     jobject self = uis->trayIcon;
786     jboolean jupdate = uis->update;
787     AwtTrayIcon *trayIcon = NULL;
788 
789     PDATA pData;
790     JNI_CHECK_PEER_GOTO(self, ret);
791     trayIcon = (AwtTrayIcon *)pData;
792 
793     BOOL result = trayIcon->SendTrayMessage(jupdate == JNI_TRUE ? NIM_MODIFY : NIM_ADD);
794     // 6270114: Instructs the taskbar to behave according to the Shell version 5.0
795     if (result && jupdate == JNI_FALSE) {
796         trayIcon->SendTrayMessage(NIM_SETVERSION);
797     }
798 ret:
799     env->DeleteGlobalRef(self);
800     delete uis;
801 }
802 
DisplayMessage(LPCTSTR caption,LPCTSTR text,LPCTSTR msgType)803 void AwtTrayIcon::DisplayMessage(LPCTSTR caption, LPCTSTR text, LPCTSTR msgType)
804 {
805     m_nid.uFlags |= NIF_INFO;
806     m_nid.uTimeout = 10000;
807 
808     if (lstrcmp(msgType, TEXT("ERROR")) == 0) {
809         m_nid.dwInfoFlags = NIIF_ERROR;
810     } else if (lstrcmp(msgType, TEXT("WARNING")) == 0) {
811         m_nid.dwInfoFlags = NIIF_WARNING;
812     } else if (lstrcmp(msgType, TEXT("INFO")) == 0) {
813         m_nid.dwInfoFlags = NIIF_INFO;
814     } else if (lstrcmp(msgType, TEXT("NONE")) == 0) {
815         m_nid.dwInfoFlags = NIIF_NONE;
816     } else {
817         m_nid.dwInfoFlags = NIIF_NONE;
818     }
819 
820     if (caption[0] == '\0') {
821         m_nid.szInfoTitle[0] = '\0';
822 
823     } else if (lstrlen(caption) >= TRAY_ICON_BALLOON_TITLE_MAX_SIZE) {
824 
825         _tcsncpy(m_nid.szInfoTitle, caption, TRAY_ICON_BALLOON_TITLE_MAX_SIZE);
826         m_nid.szInfoTitle[TRAY_ICON_BALLOON_TITLE_MAX_SIZE - 1] = '\0';
827 
828     } else {
829         _tcscpy_s(m_nid.szInfoTitle, TRAY_ICON_BALLOON_TITLE_MAX_SIZE, caption);
830     }
831 
832     if (text[0] == '\0') {
833         m_nid.szInfo[0] = ' ';
834         m_nid.szInfo[1] = '\0';
835 
836     } else if (lstrlen(text) >= TRAY_ICON_BALLOON_INFO_MAX_SIZE) {
837 
838         _tcsncpy(m_nid.szInfo, text, TRAY_ICON_BALLOON_INFO_MAX_SIZE);
839         m_nid.szInfo[TRAY_ICON_BALLOON_INFO_MAX_SIZE - 1] = '\0';
840 
841     } else {
842         _tcscpy_s(m_nid.szInfo, TRAY_ICON_BALLOON_INFO_MAX_SIZE, text);
843     }
844 
845     SendTrayMessage(NIM_MODIFY);
846     m_nid.uFlags &= ~NIF_INFO;
847 }
848 
_DisplayMessage(void * param)849 void AwtTrayIcon::_DisplayMessage(void *param)
850 {
851     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
852     DisplayMessageStruct *dms = (DisplayMessageStruct *)param;
853     jobject self = dms->trayIcon;
854     jstring jcaption = dms->caption;
855     jstring jtext = dms-> text;
856     jstring jmsgType = dms->msgType;
857     AwtTrayIcon *trayIcon = NULL;
858     LPCTSTR captionStr = NULL;
859     LPCTSTR textStr = NULL;
860     LPCTSTR msgTypeStr = NULL;
861 
862     PDATA pData;
863     JNI_CHECK_PEER_GOTO(self, ret);
864     trayIcon = (AwtTrayIcon *)pData;
865 
866     captionStr = JNU_GetStringPlatformChars(env, jcaption, (jboolean *)NULL);
867     if (env->ExceptionCheck()) goto ret;
868     textStr = JNU_GetStringPlatformChars(env, jtext, (jboolean *)NULL);
869     if (env->ExceptionCheck()) {
870         JNU_ReleaseStringPlatformChars(env, jcaption, captionStr);
871         goto ret;
872     }
873     msgTypeStr = JNU_GetStringPlatformChars(env, jmsgType, (jboolean *)NULL);
874     if (env->ExceptionCheck()) {
875         JNU_ReleaseStringPlatformChars(env, jcaption, captionStr);
876         JNU_ReleaseStringPlatformChars(env, jtext, textStr);
877         goto ret;
878     }
879     trayIcon->DisplayMessage(captionStr, textStr, msgTypeStr);
880 
881     JNU_ReleaseStringPlatformChars(env, jcaption, captionStr);
882     JNU_ReleaseStringPlatformChars(env, jtext, textStr);
883     JNU_ReleaseStringPlatformChars(env, jmsgType, msgTypeStr);
884 ret:
885     env->DeleteGlobalRef(self);
886     env->DeleteGlobalRef(jcaption);
887     env->DeleteGlobalRef(jtext);
888     env->DeleteGlobalRef(jmsgType);
889     delete dms;
890 }
891 
892 /************************************************************************
893  * TrayIcon native methods
894  */
895 
896 extern "C" {
897 
898 /*
899  * Class:     java_awt_TrayIcon
900  * Method:    initIDs
901  * Signature: ()V
902  */
903 JNIEXPORT void JNICALL
Java_java_awt_TrayIcon_initIDs(JNIEnv * env,jclass cls)904 Java_java_awt_TrayIcon_initIDs(JNIEnv *env, jclass cls)
905 {
906     TRY;
907 
908     /* init field ids */
909     AwtTrayIcon::idID = env->GetFieldID(cls, "id", "I");
910     DASSERT(AwtTrayIcon::idID != NULL);
911     CHECK_NULL(AwtTrayIcon::idID);
912 
913     AwtTrayIcon::actionCommandID = env->GetFieldID(cls, "actionCommand", "Ljava/lang/String;");
914     DASSERT(AwtTrayIcon::actionCommandID != NULL);
915     CHECK_NULL( AwtTrayIcon::actionCommandID);
916 
917     CATCH_BAD_ALLOC;
918 }
919 
920 /*
921  * Class:     sun_awt_windows_WTrayIconPeer
922  * Method:    create
923  * Signature: ()V
924  */
925 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTrayIconPeer_create(JNIEnv * env,jobject self)926 Java_sun_awt_windows_WTrayIconPeer_create(JNIEnv *env, jobject self)
927 {
928     TRY;
929 
930     AwtToolkit::CreateComponent(self, NULL,
931                                 (AwtToolkit::ComponentFactory)
932                                 AwtTrayIcon::Create);
933     PDATA pData;
934     JNI_CHECK_PEER_CREATION_RETURN(self);
935 
936     CATCH_BAD_ALLOC;
937 }
938 
939 /*
940  * Class:     sun_awt_windows_WTrayIconPeer
941  * Method:    _dispose
942  * Signature: ()V
943  */
944 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTrayIconPeer__1dispose(JNIEnv * env,jobject self)945 Java_sun_awt_windows_WTrayIconPeer__1dispose(JNIEnv *env, jobject self)
946 {
947     TRY;
948 
949     AwtObject::_Dispose(self);
950 
951     CATCH_BAD_ALLOC;
952 }
953 
954 /*
955  * Class:     sun_awt_windows_WTrayIconPeer
956  * Method:    _setToolTip
957  * Signature: ()V
958  */
959 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTrayIconPeer_setToolTip(JNIEnv * env,jobject self,jstring tooltip)960 Java_sun_awt_windows_WTrayIconPeer_setToolTip(JNIEnv *env, jobject self,
961                                               jstring tooltip)
962 {
963     TRY;
964 
965     SetToolTipStruct *sts = new SetToolTipStruct;
966     sts->trayIcon = env->NewGlobalRef(self);
967     if (tooltip != NULL) {
968         sts->tooltip = (jstring)env->NewGlobalRef(tooltip);
969     } else {
970         sts->tooltip = NULL;
971     }
972 
973     AwtToolkit::GetInstance().SyncCall(AwtTrayIcon::_SetToolTip, sts);
974     // global ref and sts are deleted in _SetToolTip
975 
976     CATCH_BAD_ALLOC;
977 }
978 
979 /*
980  * Class:     sun_awt_windows_WTrayIconPeer
981  * Method:    setNativeIcon
982  * Signature: (I[B[IIIII)V
983  */
984 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTrayIconPeer_setNativeIcon(JNIEnv * env,jobject self,jintArray intRasterData,jbyteArray andMask,jint nSS,jint nW,jint nH)985 Java_sun_awt_windows_WTrayIconPeer_setNativeIcon(JNIEnv *env, jobject self,
986                                                  jintArray intRasterData, jbyteArray andMask,
987                                                  jint nSS, jint nW, jint nH)
988 {
989     TRY;
990 
991     int length = env->GetArrayLength(andMask);
992     jbyte *andMaskPtr = new jbyte[length];
993 
994     env->GetByteArrayRegion(andMask, 0, length, andMaskPtr);
995 
996     HBITMAP hMask = ::CreateBitmap(nW, nH, 1, 1, (BYTE *)andMaskPtr);
997 //    ::GdiFlush();
998 
999     delete[] andMaskPtr;
1000 
1001     jint *intRasterDataPtr = NULL;
1002     HBITMAP hColor = NULL;
1003     try {
1004         intRasterDataPtr = (jint *)env->GetPrimitiveArrayCritical(intRasterData, 0);
1005         if (intRasterDataPtr == NULL) {
1006             ::DeleteObject(hMask);
1007             return;
1008         }
1009         hColor = AwtTrayIcon::CreateBMP(NULL, (int *)intRasterDataPtr, nSS, nW, nH);
1010     } catch (...) {
1011         if (intRasterDataPtr != NULL) {
1012             env->ReleasePrimitiveArrayCritical(intRasterData, intRasterDataPtr, 0);
1013         }
1014         ::DeleteObject(hMask);
1015         throw;
1016     }
1017 
1018     env->ReleasePrimitiveArrayCritical(intRasterData, intRasterDataPtr, 0);
1019     intRasterDataPtr = NULL;
1020 
1021     HICON hIcon = NULL;
1022 
1023     if (hMask && hColor) {
1024         ICONINFO icnInfo;
1025         memset(&icnInfo, 0, sizeof(ICONINFO));
1026         icnInfo.hbmMask = hMask;
1027         icnInfo.hbmColor = hColor;
1028         icnInfo.fIcon = TRUE;
1029         icnInfo.xHotspot = TRAY_ICON_X_HOTSPOT;
1030         icnInfo.yHotspot = TRAY_ICON_Y_HOTSPOT;
1031 
1032         hIcon = ::CreateIconIndirect(&icnInfo);
1033     }
1034     ::DeleteObject(hColor);
1035     ::DeleteObject(hMask);
1036 
1037     //////////////////////////////////////////
1038 
1039     SetIconStruct *sis = new SetIconStruct;
1040     sis->trayIcon = env->NewGlobalRef(self);
1041     sis->hIcon = hIcon;
1042 
1043     AwtToolkit::GetInstance().SyncCall(AwtTrayIcon::_SetIcon, sis);
1044     // global ref is deleted in _SetIcon
1045 
1046     CATCH_BAD_ALLOC;
1047 }
1048 
1049 /*
1050  * Class:     sun_awt_windows_WTrayIconPeer
1051  * Method:    updateNativeIcon
1052  * Signature: (Z)V
1053  */
1054 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTrayIconPeer_updateNativeIcon(JNIEnv * env,jobject self,jboolean doUpdate)1055 Java_sun_awt_windows_WTrayIconPeer_updateNativeIcon(JNIEnv *env, jobject self,
1056                                                     jboolean doUpdate)
1057 {
1058     TRY;
1059 
1060     UpdateIconStruct *uis = new UpdateIconStruct;
1061     uis->trayIcon = env->NewGlobalRef(self);
1062     uis->update = doUpdate;
1063 
1064     AwtToolkit::GetInstance().SyncCall(AwtTrayIcon::_UpdateIcon, uis);
1065     // global ref is deleted in _UpdateIcon
1066 
1067     CATCH_BAD_ALLOC;
1068 }
1069 
1070 /*
1071  * Class:     sun_awt_windows_WTrayIconPeer
1072  * Method:    displayMessage
1073  * Signature: ()V;
1074  */
1075 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTrayIconPeer__1displayMessage(JNIEnv * env,jobject self,jstring caption,jstring text,jstring msgType)1076 Java_sun_awt_windows_WTrayIconPeer__1displayMessage(JNIEnv *env, jobject self,
1077     jstring caption, jstring text, jstring msgType)
1078 {
1079     TRY;
1080 
1081     DisplayMessageStruct *dms = new DisplayMessageStruct;
1082     dms->trayIcon = env->NewGlobalRef(self);
1083     dms->caption = (jstring)env->NewGlobalRef(caption);
1084     dms->text = (jstring)env->NewGlobalRef(text);
1085     dms->msgType = (jstring)env->NewGlobalRef(msgType);
1086 
1087     AwtToolkit::GetInstance().SyncCall(AwtTrayIcon::_DisplayMessage, dms);
1088     // global ref is deleted in _DisplayMessage
1089 
1090     CATCH_BAD_ALLOC(NULL);
1091 }
1092 
1093 } /* extern "C" */
1094