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