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 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 91 AwtTrayIcon::~AwtTrayIcon() { 92 } 93 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 111 LPCTSTR AwtTrayIcon::GetClassName() { 112 return TEXT("SunAwtTrayIcon"); 113 } 114 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 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 144 void AwtTrayIcon::UnregisterClass() 145 { 146 ::UnregisterClass(AwtTrayIcon::GetClassName(), AwtToolkit::GetInstance().GetModuleHandle()); 147 } 148 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 159 void AwtTrayIcon::DestroyMessageWindow() 160 { 161 ::DestroyWindow(AwtTrayIcon::sm_msgWindow); 162 AwtTrayIcon::sm_msgWindow = NULL; 163 AwtTrayIcon::UnregisterClass(); 164 } 165 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 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 224 BOOL AwtTrayIcon::SendTrayMessage(DWORD dwMessage) 225 { 226 return Shell_NotifyIcon(dwMessage, (PNOTIFYICONDATA)&m_nid); 227 } 228 229 static UINT lastMessage = WM_NULL; 230 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 */ 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 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 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 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 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 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 759 void AwtTrayIcon::SetIcon(HICON hIcon) 760 { 761 ::DestroyIcon(m_nid.hIcon); 762 m_nid.hIcon = hIcon; 763 } 764 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 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 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 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 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 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 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 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 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 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 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" */