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