📄 windowstrayicon.cpp
字号:
if (tray_icons[m_IDNum].used == FALSE) return TRAY_WRONGICONID;
jobject obj = tray_icons[m_IDNum].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, "notifyMouseListeners", "(IIII)V");
if (mid == 0) return TRAY_METHODID;
// Call method "notifyMouseListeners"
env->CallVoidMethod(obj, mid, m_Button, m_Mask, m_Pos.x, m_Pos.y);
return TRAY_NOERR;
}
BalloonJavaCallback::BalloonJavaCallback(int idnum, int mask) {
m_Mask = mask;
m_IDNum = idnum;
}
int BalloonJavaCallback::execute(JNIEnv* env) {
// Valid icon id and valid global reference to icon's Java class?
if (tray_icons[m_IDNum].used == FALSE) return TRAY_WRONGICONID;
jobject obj = tray_icons[m_IDNum].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, "notifyBalloonListeners", "(I)V");
if (mid == 0) return TRAY_METHODID;
// Call method "notifyMouseListeners"
env->CallVoidMethod(obj, mid, m_Mask);
return TRAY_NOERR;
}
// Call a Java method in a given virtual machine
int CallJavaVM(JavaVM* vm, ThreadJavaCallback* call) {
int result = TRAY_NOERR;
JNIEnv* env;
// Attach current thread to given Java VM
if (vm->AttachCurrentThread((void**) &env, NULL) < 0) return TRAY_ERRTHREAD;
// Call method (MousePressedCallback/MenuItemCallback/WindowsMessageCallback/..)
result = call->execute(env);
// Check for exception detach thread and exit
if (env->ExceptionOccurred()) env->ExceptionDescribe();
vm->DetachCurrentThread();
return result;
}
// Thread proc to call Java method (calls CallJavaVMS but with wrapped params)
void CallJavaThread(void *arg) {
ThreadJavaCallback *tjc = (ThreadJavaCallback*)arg;
int result = CallJavaVM(hJavaVM, tjc);
if (result != TRAY_NOERR) last_error = result;
delete tjc;
}
// Call a Java method in a new thread
void CallJavaVMSThread(ThreadJavaCallback* tjc) {
if (_beginthread(CallJavaThread, 0, tjc) == -1) delete tjc;
}
SimpleJavaCallback::SimpleJavaCallback(JNIProcPtr(jniproc), int arg1, int arg2) {
m_JNIProc = jniproc;
m_Arg1 = arg1;
m_Arg2 = arg2;
}
int SimpleJavaCallback::execute(JNIEnv* env) {
return m_JNIProc(env, m_Arg1, m_Arg2);
}
// Handle popup menu command
void HandleMenuCommand(WPARAM menuId) {
// Get icon id given menu id
int id_num = getMenuItemIdNum(menuId);
// Callback to Java class in new thread, using method "MenuItemCallback()"
SimpleJavaCallback* call = new SimpleJavaCallback(MenuItemCallback, id_num, menuId);
CallJavaVMSThread(call);
}
// Handle icon mouse event (left/right button)
void HandleNotifyIcon(WPARAM id_num, LPARAM lParam) {
if (lParam == WM_RBUTTONDOWN || lParam == NIN_KEYSELECT || lParam == NIN_SELECT || lParam == WM_CONTEXTMENU) {
if (id_num >= 0) {
POINT mouse_pos;
GetCursorPos(&mouse_pos);
// If menu defined, then show it
if (tray_icons[id_num].popup != NULL) {
// Display and track the popup menu
PopupMenu *menu = tray_icons[id_num].popup;
menu->TrackPopupMenu(TPM_RIGHTALIGN | TPM_RIGHTBUTTON,&mouse_pos,my_hDlg);
} else {
// Callback Java class in new thread using "MousePressedCallback()"
MouseJavaCallback* call = new MouseJavaCallback(id_num, 1, 0, &mouse_pos);
CallJavaVMSThread(call);
}
}
} else {
int button = -1;
int mask = 0;
switch (lParam) {
case WM_LBUTTONDOWN:
button = 0; break;
case WM_MBUTTONDOWN:
button = 2; break;
case WM_LBUTTONUP:
button = 0; mask |= MOUSE_BTN_UP; break;
case WM_MBUTTONUP:
button = 2; mask |= MOUSE_BTN_UP; break;
case NIN_KEYSELECT:
case NIN_SELECT:
case WM_CONTEXTMENU:
case WM_RBUTTONUP:
button = 1; mask |= MOUSE_BTN_UP; break;
case WM_LBUTTONDBLCLK:
button = 0; mask |= MOUSE_BTN_DOUBLE; break;
case WM_RBUTTONDBLCLK:
button = 1; mask |= MOUSE_BTN_DOUBLE; break;
case WM_MBUTTONDBLCLK:
button = 2; mask |= MOUSE_BTN_DOUBLE; break;
case NIN_BALLOONSHOW:
button = 3; mask |= BALLOON_MSG_SHOW; break;
case NIN_BALLOONHIDE:
button = 3; mask |= BALLOON_MSG_HIDE; break;
case NIN_BALLOONTIMEOUT:
button = 3; mask |= BALLOON_MSG_TIMEOUT; break;
case NIN_BALLOONUSERCLICK:
button = 3; mask |= BALLOON_MSG_CLICK; break;
}
if (id_num >= 0 && button != -1) {
if (button == 3) {
BalloonJavaCallback* call = new BalloonJavaCallback(id_num, mask);
CallJavaVMSThread(call);
} else {
MouseJavaCallback* call = new MouseJavaCallback(id_num, button, mask);
GetCursorPos(call->getPos());
CallJavaVMSThread(call);
}
}
}
}
void ReAddAllIcons() {
for (int id_num = 0; id_num < MY_MAX_ICONS; id_num++) {
if (tray_icons[id_num].visible == TRUE) {
showIcon(id_num);
}
}
}
int HandleAppTalk(int value) {
SimpleJavaCallback call(WindowsMessageCallback, 0, value);
return CallJavaVM(hJavaVM, &call);
}
int HandleAppMouse(int xp, int yp) {
SimpleJavaCallback call(MouseHookCallback, xp, yp);
return CallJavaVM(hJavaVM, &call);
}
// Windows message proc for hidden window
// Receives mouse/menu events for the apps tray icons
LONG APIENTRY WndProc(HWND hWnd, UINT iMessage, UINT wParam, LONG lParam) {
switch (iMessage) {
case WM_DESTROY:
// Exit message thread
PostQuitMessage(0) ;
break;
case MYWM_NOTIFYICON:
// Mouse event for icon (left/right button)
HandleNotifyIcon(wParam, lParam);
break;
case MYWM_APPTALK:
// ID used for sendWindowsMessage()
// Callback Java class using "WindowsMessageCallback()"
return HandleAppTalk((int)lParam);
case MYWM_APPMOUSE:
// Handle mouse message (from global hook)
return HandleAppMouse((int)wParam, (int)lParam);
case WM_COMMAND:
// Menu command for icon
HandleMenuCommand(LOWORD(wParam));
break;
// Get notified if task bar restarts
case WM_CREATE:
g_TaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
break;
// Do nothing for other messages
case WM_GETMINMAXINFO:
case WM_PAINT:
case WM_MOUSEMOVE:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_MOVE:
case WM_SIZE:
case WM_LBUTTONDOWN:
case WM_KEYDOWN:
break;
// Or use default handler
default:
if (iMessage == g_TaskbarRestart) ReAddAllIcons();
else return DefWindowProc (hWnd, iMessage, wParam, lParam) ;
}
return 0L ;
}
// Create the hidden window to receive the icon's mouse messages
HWND MakeHWND(HINSTANCE hInst) {
HWND hWnd;
// Create window class
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = (WNDPROC) WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInst;
wndclass.hIcon = LoadIcon(hInst, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass)) return NULL;
// Create window
hWnd = CreateWindow(szAppName, szWndName, WS_OVERLAPPEDWINDOW,
0,0,100,100,
NULL, NULL, hInst, NULL);
return hWnd;
}
// Remove the hidden window (on app closing)
void RemoveHWND() {
// Close dial
if (my_hDlg != NULL) {
// Create wait event
exit_event = CreateEvent(NULL,FALSE,FALSE,NULL);
// Send destroy messages
PostMessage(my_hDlg, WM_NCDESTROY, 0, 0);
PostMessage(my_hDlg, WM_DESTROY, 0, 0);
// Wait for window to destroy
WaitForSingleObject(exit_event,10000);
CloseHandle(exit_event);
exit_event = NULL;
}
// Free handle
if (wait_event != NULL) {
CloseHandle(wait_event);
wait_event = NULL;
}
}
// The thread proc that creates the hidden window an listens for messages
void DialogThread(void *dummy) {
MSG msg;
// Create window
my_hDlg = MakeHWND(g_hinst);
// Signal wait event
if (wait_event != NULL) SetEvent(wait_event);
// Hide window
ShowWindow(my_hDlg, SW_HIDE);
UpdateWindow(my_hDlg);
// Process messages
while (GetMessage(&msg, NULL, 0, 0)){
TranslateMessage(&msg) ;
DispatchMessage(&msg) ;
}
// Unregister window class
UnregisterClass(szAppName, g_hinst);
// Signal exit event (so app knows hidden window is destroyed)
if (exit_event != NULL) SetEvent(exit_event);
}
JNIEXPORT void JNICALL Java_com_jeans_trayicon_WindowsTrayIcon_setAlwaysOnTop(JNIEnv *env, jclass cls, jobject win, jboolean onTop) {
DoAlwaysOnTop top;
doWithHWND(&top, env, win);
}
int DoAlwaysOnTop::execute(HWND hwnd) {
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
return 0;
}
void doWithHWND(DoWithHWND* hwndProc, JNIEnv* env, jobject window) {
if (hJAWT == NULL) {
last_error = TRAY_NO_JAWT;
return;
}
PJAWT_GETAWT JAWT_GetAWT = (PJAWT_GETAWT)GetProcAddress(hJAWT, "_JAWT_GetAWT@8");
if (JAWT_GetAWT == NULL) {
last_error = TRAY_NO_GET_JAWT;
return;
}
JAWT awt;
awt.version = JAWT_VERSION_1_3;
jboolean result = JAWT_GetAWT(env, &awt);
if (result == JNI_FALSE) {
last_error = TRAY_GET_JAWT_FAILS;
return;
}
JAWT_DrawingSurface* ds = awt.GetDrawingSurface(env, window);
if (ds == NULL) {
last_error = TRAY_JAWT_DS_FAILS;
return;
}
jint lock = ds->Lock(ds);
if ((lock & JAWT_LOCK_ERROR) == 0) {
JAWT_DrawingSurfaceInfo* dsi = ds->GetDrawingSurfaceInfo(ds);
JAWT_Win32DrawingSurfaceInfo* dsi_win = (JAWT_Win32DrawingSurfaceInfo*)dsi->platformInfo;
hwndProc->execute(dsi_win->hwnd);
ds->FreeDrawingSurfaceInfo(dsi);
ds->Unlock(ds);
} else {
last_error = TRAY_JAWT_LOCK_FAILS;
}
awt.FreeDrawingSurface(ds);
}
void RemoveJAWT() {
if (hJAWT != NULL) {
FreeLibrary(hJAWT);
hJAWT = NULL;
}
}
void RemoveHook() {
if (hMouseClickHook != NULL) {
UnhookWindowsHookEx(hMouseClickHook);
hMouseClickHook = NULL;
}
}
void GetJAWTHandle() {
if (hJAWTTried == 0 && hJAWT == NULL) {
hJAWTTried = 1;
hJAWT = LoadLibrary("jawt.dll");
if (hJAWT == NULL) {
char* jawt_path = find_in_path("../jre/bin/jawt.dll");
if (jawt_path != NULL) hJAWT = LoadLibrary(jawt_path);
}
if (hJAWT == NULL) {
last_error = TRAY_NO_JAWT;
}
}
}
// New icon resource with no bitmap and zero size
IconData::IconData() {
wd = hi = 0;
hBitmapAND = hBitmapXOR = NULL;
}
// Destroy icon resources (and and xor bitmap)
IconData::~IconData() {
if (hBitmapAND != NULL) DeleteObject(hBitmapAND);
if (hBitmapXOR != NULL) DeleteObject(hBitmapXOR);
}
// Make icon using and and xor bitmaps (returns handle to new icon)
HICON IconData::makeIcon(HINSTANCE hInst) {
ICONINFO ii;
ii.fIcon = TRUE;
ii.xHotspot = 0;
ii.yHotspot = 0;
ii.hbmMask = hBitmapAND;
ii.hbmColor = hBitmapXOR;
return CreateIconIndirect(&ii);
}
// Set icon's image data (pixel array, width, height)
int IconData::setData(unsigned long *data, int wd, int hi) {
int res = -1;
// Set size
this->wd = wd;
this->hi = hi;
// Clean up if setData was called before
if (hBitmapAND != NULL) DeleteObject(hBitmapAND);
if (hBitmapXOR != NULL) DeleteObject(hBitmapXOR);
// To protect against java sending a dud image
if (wd > 0 && hi > 0) {
// Set up the header for creating our 24 bit colour bitmap
BITMAPINFOHEADER bih;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = wd;
bih.biHeight = hi;
bih.biPlanes = 1;
bih.biBitCount = 24;
bih.biCompression = BI_RGB;
bih.biSizeImage = 0;
bih.biXPelsPerMeter = 0;
bih.biYPelsPerMeter = 0;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
// Create memory DC
HDC hdc = CreateCompatibleDC(NULL);
// Make the 24-bit DIB
hBitmapXOR = CreateDIBSection(hdc, (LPBITMAPINFO)&bih, DIB_RGB_COLORS, (LPVOID *)NULL, NULL, 0);
// Select it into the DC so we can draw onto it
SelectObject(hdc, hBitmapXOR);
// Calloc memory to be used to create a monochrome bitmask
long size = (wd*hi/8)+1;
unsigned char *andMask = new unsigned char[size];
if (andMask != NULL) {
for (int i = 0; i < size; i++) andMask[i] = 0;
// Loop through the given pixels and draw onto the colour and mono bitmaps
unsigned long pixel;
unsigned char red, green, blue, alpha;
for (int row = 0; row < hi; row++) {
for (int col = 0; col < wd; col++) {
pixel = data[(row*wd)+col];
alpha = (unsigned char)((pixel >> 24) & 0x000000ff);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -