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 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, ::JVM_CurrentTimeMillis(NULL, 0), 418 AwtComponent::GetActionModifiers(), &msg); 419 } 420 return mrConsume; 421 } 422 423 MsgRouting AwtTrayIcon::WmKeySelect(UINT flags, int x, int y) 424 { 425 static jlong lastKeySelectTime = 0; 426 jlong now = ::JVM_CurrentTimeMillis(NULL, 0); 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, ::JVM_CurrentTimeMillis(NULL, 0), 434 AwtComponent::GetActionModifiers(), &msg); 435 } 436 lastKeySelectTime = now; 437 438 return mrConsume; 439 } 440 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, ::JVM_CurrentTimeMillis(NULL, 0), 451 AwtComponent::GetActionModifiers(), &msg); 452 } 453 return mrConsume; 454 } 455 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 */ 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 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 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 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 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 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 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 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 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 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 756 void AwtTrayIcon::SetIcon(HICON hIcon) 757 { 758 ::DestroyIcon(m_nid.hIcon); 759 m_nid.hIcon = hIcon; 760 } 761 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 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 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 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 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 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 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 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 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 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 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" */