📄 windowstrayicon.cpp
字号:
PopupSubMenu *menu = popup->getSubMenu(level);
HMENU hMenu = popup->getMenu(level-1);
HMENU sMenu = menu->getMenu();
TrayAppendMenu(env, hMenu, MF_POPUP | MF_ENABLED | MF_UNCHECKED, (UINT)sMenu, menuName);
// Sub menus must not be destroyed, only parents must: mark as sub
menu->makeSub();
}
break;
}
} else {
MENUITEMINFO info;
info.cbSize = sizeof(MENUITEMINFO);
info.fMask = MIIM_STATE;
info.fState = 0;
// Add a regular item to a (sub)menu
HMENU hMenu = popup->getMenu(level);
if (hMenu == NULL) return -1;
switch (type) {
case POPUP_TYPE_CHECKBOX:
case POPUP_TYPE_ITEM:
if ((extra & POPUP_MODE_CHECK) != 0) info.fState |= MFS_CHECKED;
else info.fState |= MFS_UNCHECKED;
if ((extra & POPUP_MODE_ENABLE) != 0) info.fState |= MFS_ENABLED;
else info.fState |= MFS_GRAYED;
if ((extra & POPUP_MODE_DEFAULT) != 0) info.fState |= MFS_DEFAULT;
// Get free id for the new menu item
id = getFreeMenuId(id_num);
// Append the new item to the existing menu
TrayAppendMenu(env, hMenu, MF_STRING, (UINT)id, menuName);
SetMenuItemInfo(hMenu, id, FALSE, &info);
break;
case POPUP_TYPE_SEPARATOR:
// Append a separator to the menu
AppendMenu(hMenu,MF_SEPARATOR, 0, NULL);
break;
}
}
}
// Return the id of the new menu item (used for callback messages)
return id;
}
extern "C" {
// Main proc of DLL, called on initialisation, termination
BOOL WINAPI DllMain(HANDLE hInst, ULONG fdwReason, LPVOID lpReserved) {
switch(fdwReason) {
case DLL_PROCESS_ATTACH:
// Store the instance handle
g_hinst = (HINSTANCE)hInst;
// Make new map for menu ids
if (arrUsedMenuIds == NULL) arrUsedMenuIds = new QSIntArray();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
// Delete the map for menu ids
if (arrUsedMenuIds != NULL) {
delete arrUsedMenuIds;
arrUsedMenuIds = NULL;
}
break;
}
// Initialisation OK
return TRUE;
}
}
// This proc is called on exit (before Java's System.exit())
// Free all icon resources and remove the hidden window
void cleanUpExit(JNIEnv *env) {
for (int id_num = 0; id_num < MY_MAX_ICONS; id_num++) {
freeIcon(env, id_num);
}
RemoveHWND();
RemoveJAWT();
RemoveHook();
if (hGlobalWinTrayClass != 0) {
env->DeleteGlobalRef(hGlobalWinTrayClass);
hGlobalWinTrayClass = 0;
}
}
// Free menu resources for icon with given id
void freeMenu(int id_num) {
// Free allocated menu id's
setFreeMenuId(id_num);
// Free popup class
if (tray_icons[id_num].popup != NULL) {
delete tray_icons[id_num].popup;
tray_icons[id_num].popup = NULL;
}
}
// Free all icon resources for given id
// Make invisible, destroy icon, destroy tooltip, destroy global reference, free menu,..
void freeIcon(JNIEnv *env, int id_num) {
// Icon handle valid?
if (tray_icons[id_num].used == TRUE) {
// Make invisible
if (tray_icons[id_num].visible == TRUE) {
makeInvisible(id_num);
}
// Make invalid
tray_icons[id_num].used = FALSE;
// Free icon
if (tray_icons[id_num].icon != NULL) {
delete tray_icons[id_num].icon;
tray_icons[id_num].icon = NULL;
}
// Free tooltip
if (tray_icons[id_num].tooltip != NULL) {
delete tray_icons[id_num].tooltip;
tray_icons[id_num].tooltip = NULL;
}
// Free global ref to callback class for mouse/menu events
if (tray_icons[id_num].globalClass != 0) {
if (env != NULL) {
env->DeleteGlobalRef(tray_icons[id_num].globalClass);
} else {
SimpleJavaCallback call(DeleteGlobalCallback, id_num, 0);
CallJavaVM(hJavaVM, &call);
}
tray_icons[id_num].globalClass = 0;
}
// Free menu ids and resources
freeMenu(id_num);
}
}
// Update icon with given id in system tray
// Show or Hide and add tooltip,..
void updateIcon(jint id_num) {
// Valid hidden window handle, icon id an visible?
if (my_hDlg != NULL && tray_icons[id_num].used == TRUE && tray_icons[id_num].visible == TRUE) {
// Valid instance handle and icon resources?
if (g_hinst != NULL && tray_icons[id_num].icon != NULL) {
// Get icon handle
HICON icon = tray_icons[id_num].icon->makeIcon(g_hinst);
if (icon != NULL) {
// Modify icon status
if (bUseUnicode == 0) {
TrayMessage(my_hDlg, NIM_MODIFY, id_num, icon, tray_icons[id_num].tooltip);
} else {
TrayMessageW(my_hDlg, NIM_MODIFY, id_num, icon, (jchar*)tray_icons[id_num].tooltip);
}
} else {
last_error = TRAY_NOTENOUGHMEM;
}
} else {
// Make icon invisible if no valid resources
makeInvisible(id_num);
}
}
}
// Hide icon
void makeInvisible(jint id_num) {
// Valid icon id and currently visible?
if (tray_icons[id_num].used == TRUE && tray_icons[id_num].visible == TRUE) {
// Make invisible
if (my_hDlg != NULL) TrayMessage(my_hDlg, NIM_DELETE, id_num, NULL, NULL);
tray_icons[id_num].visible = FALSE;
}
}
// Add/Remove/Modify tray icon to system tray
BOOL TrayMessage(HWND hDlg, DWORD dwMessage, UINT uID, HICON hIcon, PSTR pszTip) {
BOOL res;
// Fill data struct for tray icon
MY_NOTIFYICONDATA tnd;
if (hShell32Version >= 5) {
tnd.cbSize = sizeof(MY_NOTIFYICONDATA);
} else {
tnd.cbSize = sizeof(NOTIFYICONDATA);
// NOTIFYICONDATA_V2_SIZE;
}
tnd.hWnd = hDlg;
tnd.uID = uID;
tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
tnd.uCallbackMessage = MYWM_NOTIFYICON;
tnd.hIcon = hIcon;
// Include tooltip?
if (pszTip) {
lstrcpyn(tnd.szTip, pszTip, sizeof(tnd.szTip));
tnd.szTip[sizeof(tnd.szTip)-1] = 0;
} else {
tnd.szTip[0] = '\0';
}
tnd.dwState = 0;
tnd.dwStateMask = 0;
tnd.szInfo[0] = '\0';
tnd.uTimeOrVersion = 10000;
tnd.szInfoTitle[0] = '\0';
tnd.dwInfoFlags = 0;
// tnd.guidItem = 0;
// Call tray icon windows API function
res = Shell_NotifyIcon(dwMessage, (NOTIFYICONDATA*)&tnd);
// Destroy the icon's handle (icon data is copied by Windows function)
if (hIcon) DestroyIcon(hIcon);
return res;
}
// Add/Remove/Modify tray icon to system tray
BOOL TrayMessageW(HWND hDlg, DWORD dwMessage, UINT uID, HICON hIcon, const jchar* pszTip) {
BOOL res;
// Fill data struct for tray icon
MY_NOTIFYICONDATAW tnd;
if (hShell32Version >= 5) {
tnd.cbSize = sizeof(MY_NOTIFYICONDATAW);
} else {
tnd.cbSize = sizeof(NOTIFYICONDATAW);
// NOTIFYICONDATA_V2_SIZEW;
}
tnd.hWnd = hDlg;
tnd.uID = uID;
tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
tnd.uCallbackMessage = MYWM_NOTIFYICON;
tnd.hIcon = hIcon;
// Include tooltip?
if (pszTip) {
copyJCharMax(pszTip, tnd.szTip, sizeof(tnd.szTip)/sizeof(jchar));
} else {
tnd.szTip[0] = 0;
}
tnd.dwState = 0;
tnd.dwStateMask = 0;
tnd.szInfo[0] = 0;
tnd.uTimeOrVersion = 10000;
tnd.szInfoTitle[0] = 0;
tnd.dwInfoFlags = 0;
// tnd.guidItem = 0;
// Call tray icon windows API function
res = Shell_NotifyIconW(dwMessage, (NOTIFYICONDATAW*)&tnd);
// Destroy the icon's handle (icon data is copied by Windows function)
if (hIcon) DestroyIcon(hIcon);
return res;
}
bool TraySetVersion(HWND hDlg, UINT uID) {
if (hShell32Version < 5) {
// No balloon messages supported :-(
return FALSE;
}
// Fill data struct for tray icon
MY_NOTIFYICONDATA tnd;
tnd.cbSize = sizeof(MY_NOTIFYICONDATA);
tnd.hWnd = hDlg;
tnd.uID = uID;
tnd.uFlags = 0;
tnd.uCallbackMessage = 0;
tnd.hIcon = NULL;
tnd.szTip[0] = '\0';
tnd.dwState = 0;
tnd.dwStateMask = 0;
tnd.szInfo[0] = '\0';
tnd.uTimeOrVersion = NOTIFYICON_VERSION;
tnd.szInfoTitle[0] = '\0';
tnd.dwInfoFlags = 0;
// tnd.guidItem = NULL;
// Call tray icon windows API function
return Shell_NotifyIcon(NIM_SETVERSION, (NOTIFYICONDATA*)&tnd);
}
bool TrayBalloon(HWND hDlg, UINT uID, const char* msg, const char* title, UINT time, DWORD flags) {
if (hShell32Version < 5) {
// No balloon messages supported :-(
return FALSE;
}
// Fill data struct for tray icon
MY_NOTIFYICONDATA tnd;
tnd.cbSize = 488; // sizeof(MY_NOTIFYICONDATA);
tnd.hWnd = hDlg;
tnd.uID = uID;
tnd.uFlags = NIF_INFO;
tnd.uCallbackMessage = 0;
tnd.hIcon = NULL;
tnd.szTip[0] = '\0';
tnd.dwState = 0;
tnd.dwStateMask = 0;
if (msg) {
lstrcpyn(tnd.szInfo, msg, sizeof(tnd.szInfo));
tnd.szInfo[sizeof(tnd.szInfo)-1] = 0;
} else {
tnd.szInfo[0] = '\0';
}
tnd.uTimeOrVersion = time;
if (title) {
lstrcpyn(tnd.szInfoTitle, title, sizeof(tnd.szInfoTitle));
tnd.szInfoTitle[sizeof(tnd.szInfoTitle)-1] = 0;
} else {
tnd.szInfoTitle[0] = '\0';
}
tnd.dwInfoFlags = flags;
// tnd.guidItem = NULL;
// Call tray icon windows API function
return Shell_NotifyIcon(NIM_MODIFY, (NOTIFYICONDATA*)&tnd);
}
// Unicode version of TrayBalloon
bool TrayBalloonW(HWND hDlg, UINT uID, const jchar* msg, const jchar* title, UINT time, DWORD flags) {
if (hShell32Version < 5) {
// No balloon messages supported :-(
return FALSE;
}
// Fill data struct for tray icon
MY_NOTIFYICONDATAW tnd;
tnd.cbSize = sizeof(MY_NOTIFYICONDATAW);
tnd.hWnd = hDlg;
tnd.uID = uID;
tnd.uFlags = NIF_INFO;
tnd.uCallbackMessage = 0;
tnd.hIcon = NULL;
tnd.szTip[0] = '\0';
tnd.dwState = 0;
tnd.dwStateMask = 0;
if (msg) {
copyJCharMax(msg, tnd.szInfo, sizeof(tnd.szInfo)/sizeof(jchar));
} else {
tnd.szInfo[0] = 0;
}
tnd.uTimeOrVersion = time;
if (title) {
copyJCharMax(title, tnd.szInfoTitle, sizeof(tnd.szInfoTitle)/sizeof(jchar));
} else {
tnd.szInfoTitle[0] = 0;
}
tnd.dwInfoFlags = flags;
// tnd.guidItem = NULL;
// Call tray icon windows API function
return Shell_NotifyIconW(NIM_MODIFY, (NOTIFYICONDATAW*)&tnd);
}
// Java VM callback function to delete a global reference to a given Java class
// Used to delete the global reference to the icon's class to receive mouse/menu events
int DeleteGlobalCallback(JNIEnv *env, int id_num, int dummy) {
env->DeleteGlobalRef(tray_icons[id_num].globalClass);
tray_icons[id_num].globalClass = 0;
return 0;
}
jclass GetTrayIconClass(JNIEnv* env) {
if (hGlobalWinTrayClass != 0) {
jclass winTrayClass = env->GetObjectClass(hGlobalWinTrayClass);
if (winTrayClass != 0) return winTrayClass;
}
MessageBox(NULL, "Error", "using FindClass", MB_OK);
return env->FindClass("com/jeans/trayicon/WindowsTrayIcon");
}
// Java VM callback function used to notify icon class after incomming sendWindowsMessage()
int WindowsMessageCallback(JNIEnv *env, int dummy, int wParam) {
// Get reference to WindowsTrayIcon Java class
jclass cls = GetTrayIconClass(env);
if (cls == 0) return -1;
// Get static callback method id
jmethodID mid = env->GetStaticMethodID(cls, "callWindowsMessage", "(I)I");
if (mid == 0) return -1;
// Make call to "callWindowsMessage" with parameter wParam
return env->CallStaticIntMethod(cls, mid, (jint)wParam);
}
int MouseHookCallback(JNIEnv *env, int xp, int yp) {
// Get reference to WindowsTrayIcon Java class
jclass cls = GetTrayIconClass(env);
if (cls == 0) return -1;
// Get static callback method id
jmethodID mid = env->GetStaticMethodID(cls, "callMouseHook", "(II)V");
if (mid == 0) return -1;
// Make call to "callMouseHook" with given coordinates
env->CallStaticVoidMethod(cls, mid, (jint)xp, (jint)yp);
return 0;
}
// Java VM callback function used for menu item callbacks
int MenuItemCallback(JNIEnv *env, int id_num, int menu_id) {
// Valid icon id and valid global reference to icon's Java class?
if (tray_icons[id_num].used == FALSE) return TRAY_WRONGICONID;
jobject obj = tray_icons[id_num].globalClass;
if (obj == 0) return TRAY_NOLISTENER;
jclass winTrayClass = env->GetObjectClass(obj);
if (winTrayClass == 0) return TRAY_NOTENOUGHMEM;
// Get callback method id
jmethodID mid = env->GetMethodID(winTrayClass, "notifyMenuListeners", "(I)V");
if (mid == 0) return TRAY_METHODID;
// Call method "notifyMenuListeners"
env->CallVoidMethod(obj, mid, menu_id);
return TRAY_NOERR;
}
MouseJavaCallback::MouseJavaCallback(int idnum, int button, int mask, POINT* pos) {
m_Button = button;
m_Mask = mask;
m_IDNum = idnum;
m_Pos.x = pos->x;
m_Pos.y = pos->y;
}
MouseJavaCallback::MouseJavaCallback(int idnum, int button, int mask) {
m_Button = button;
m_Mask = mask;
m_IDNum = idnum;
}
POINT* MouseJavaCallback::getPos() {
return &m_Pos;
}
int MouseJavaCallback::execute(JNIEnv* env) {
// Valid icon id and valid global reference to icon's Java class?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -