📄 windowstrayicon.cpp
字号:
/**
* WindowsTrayIcon.cpp - a tray icon for Java
* Best viewed with tab size 8
*
* Written by Jan Struyf
*
* jan.struyf@cs.kuleuven.ac.be
* http://jeans.studentenweb.org/java/trayicon/trayicon.html
*
* Changelog
*
* Version pre1.6c (07/16/01)
* * Fixed minor compilation warnings reported by the more strict VC++ 6.0
*
* Version pre1.6b (12/16/00)
* * Fixed memory leak for 'animating icons'
* * ReleaseDC -> DeleteDC
*
* Version pre1.6 (09/02/00)
* * Support for old JDK/JRE 1.1.x
* * TrayIcon 1.6 will support Microsoft Visual J++
*
* Version 1.5 (07/03/00)
* * Tray icon popup menu support
* * Added code for sendWindowsMessage()
*
* Version 1.4 (06/29/00)
* * Added DllMain function to clean init code
* * Removed redundant LoadLibrary/FreeLibrary calls
* * Added code for isRunning()
*
* Version 1.3 (06/09/00)
* * Trail bug fix for NT (no public release)
* (Patch from 'Daniel Hope <danielh@inform.co.nz>')
*
* Version 1.2 (05/03/00)
* * Message handler for first icon fixed
* * WM_RBUTTONDOWN message handler fixed
* * Classes are now unregistered on exit
* (Patch from 'Daniel Rejment <daniel@rejment.com>')
*
* Version 1.0 (06/29/99)
* * Initial release
*
* Please mail me if you
* - 've found bugs
* - like this program
* - don't like a particular feature
* - would like something to be modified
*
* To compile:
* - Use the MDP project file in the VC++ IDE
* - Use Makefile.vc as in:
* VCVARS32
* nmake /f makefile.vc
*
* I always give it my best shot to make a program useful and solid, but
* remeber that there is absolutely no warranty for using this program as
* stated in the following terms:
*
* THERE IS NO WARRANTY FOR THIS PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE
* LAW. THE COPYRIGHT HOLDER AND/OR OTHER PARTIES WHO MAY HAVE MODIFIED THE
* PROGRAM, PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
* TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
* PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
* REPAIR OR CORRECTION.
*
* IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL ANY COPYRIGHT HOLDER,
* OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM,
* BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
* CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
* PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
* INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
* PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER
* PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* May the Force be with you... Just compile it & use it!
*/
#include <windows.h>
#include <windowsx.h>
#include <process.h>
#include <jni.h>
#include "com_jeans_trayicon_WindowsTrayIcon.h"
#if defined(HAS_JVM_LIB) + defined(HAS_OLD_JVM_LIB) == 0
#define NO_JVM_LIB
#endif
// Message ID for sendWindowsMessage() function
#define MYWM_APPTALK (WM_APP+10)
// Message ID for Tray icons
#define MYWM_NOTIFYICON (WM_APP+100)
// Max number of icons supported by this DLL for each application
#define MY_MAX_ICONS 100
// Max length for the name of the hidden window (used for sendWindowsMessage/isRunning)
#define WNDNAME_MAX 20
// Class for the icon bitmap
class IconData {
private:
HBITMAP hBitmapXOR; // Colors
HBITMAP hBitmapAND; // Transparancy info
int wd, hi;
public:
IconData();
~IconData();
int setData(unsigned long *data, int wd, int hi);
HICON makeIcon(HINSTANCE hInst);
};
// Class for a popup submenu
class PopupSubMenu {
private:
HMENU hMenu;
BOOL bSub;
public:
PopupSubMenu();
~PopupSubMenu();
BOOL isSub();
void makeSub();
void reNewMenu();
HMENU getMenu();
void TrackPopupMenu(UINT flags, POINT* pos, HWND hWnd);
};
typedef PopupSubMenu* PtrPopupSubMenu;
// Class for a popup menu (the main popup)
class PopupMenu {
private:
PopupSubMenu **popup;
int nbLevels;
public:
PopupMenu(int levels);
~PopupMenu();
void TrackPopupMenu(UINT flags, POINT* pos, HWND hWnd);
HMENU getMenu(int level);
void initMenu(int level);
PopupSubMenu *getSubMenu(int level);
};
// Growable array for integers
// Used to store the allocated menu id's
class QSIntArray {
protected:
int *m_Array;
long m_Size, m_Grow, m_ArrSize;
public:
QSIntArray();
QSIntArray(long size, long grow);
~QSIntArray();
long getSize();
int getElementAt(long idx);
void addElement(int element);
void setElementAt(long idx, int element);
void removeElementAt(long idx);
void removeAll();
private:
void shrink();
void grow();
};
#define JNIProcPtr(name) int (FAR *name) (JNIEnv*, int, int)
// Information for each tray icon
typedef struct {
BOOL used; // Is this record in use?
BOOL visible; // Icon visible on screen or hidden?
IconData *icon; // Icon bitmap data
char *tooltip; // Icon tooltip
PopupMenu *popup; // Main popup for icon
jobject globalClass; // Pointer to Java class for callbacks
} TrayIconData;
// Information for Java callback
typedef struct {
JNIProcPtr(jni_proc);
int arg1, arg2;
} ThreadJavaCallback;
// Some error codes
#define TRAY_NOERR 0
#define TRAY_NOTIFYPROCERR -1
#define TRAY_TOOMANYICONS -2
#define TRAY_NOTENOUGHMEM -3
#define TRAY_WRONGICONID -4
#define TRAY_DLLNOTFOUND -5
#define TRAY_NOVMS -6
#define TRAY_ERRTHREAD -7
#define TRAY_METHODID -8
#define TRAY_NOLISTENER -9
#define TRAY_JNIERR -10
#define TRAY_CALLBACKDLLERR -11
// Constants for the popup menu system
#define POPUP_TYPE_ITEM 0
#define POPUP_TYPE_SEPARATOR 1
#define POPUP_TYPE_CHECKBOX 2
#define POPUP_TYPE_INIT_LEVEL 3
#define POPUP_TYPE_DONE_LEVEL 4
// Current instance of the TrayIcon DLL
HINSTANCE g_hinst = NULL;
// Handle to the hidden window used to receive the tray icon messages
HWND my_hDlg = NULL;
// App name for the hidden window's registered class
CHAR szAppName[] = "QSJavaTray";
// Title for the hidden window (used for sendWindowsMessage/isRunning)
CHAR szWndName[WNDNAME_MAX+1];
// Number of icons allocated
int nb_tray_icons = 0;
// Record for each icon
TrayIconData tray_icons[MY_MAX_ICONS];
// Contains last error message (see error codes above)
jint last_error = TRAY_NOERR;
// Wait while creating the hidden window
HANDLE wait_event = NULL;
// Wait while destroying hidden window
HANDLE exit_event = NULL;
// Maps menu id's to icon id's
QSIntArray *arrUsedMenuIds = NULL;
// Mouse position
POINT mouse_pos;
#ifdef NO_JVM_LIB
JavaVM *hJavaVM;
#endif
// Get free menu id (for icon id - see arrUsedMenuIds)
long getFreeMenuId(int id_num);
// Free menu id (when removing menu from icon)
void setFreeMenuId(int id_num);
// Map menu id to icon id
int getMenuItemIdNum(int id);
// Add/Remove/Modify tray icon to system tray
BOOL TrayMessage(HWND hDlg, DWORD dwMessage, UINT uID, HICON hIcon, PSTR pszTip);
// Create the hidden window to receive the icon's mouse messages
HWND MakeHWND(HINSTANCE hInst);
// Remove the hidden window (on app closing)
void RemoveHWND();
// The thread proc that creates the hidden window an listens for messages
void DialogThread( void *dummy );
// Free an icon's menu resources
void freeMenu(int id_num);
// Free an icon's other resources
void freeIcon(JNIEnv *env, int id_num);
// Clean up @ exit of app
void cleanUpExit(JNIEnv *env);
// Call TrayMessage for the specified icon id
void updateIcon(jint id_num);
// Make an icon dissapear from the system tray
void makeInvisible(jint id_num);
// Delete global reference to icon's Java class
int DeleteGlobalCallback(JNIEnv *env, int id_num, int dummy);
// Call a Java method in all available VM's (used for mouse/menu callbacks)
int CallJavaVMS(JNIProcPtr(JNIProc), int arg1, int arg2);
// Call a Java method in a given virtual machine
int CallJavaVM(JavaVM* vm, JNIProcPtr(JNIProc), int arg1, int arg2);
/*
* Class: jeans_trayicon_WindowsTrayIcon
* Method: getLastError
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_jeans_trayicon_WindowsTrayIcon_getLastError(JNIEnv *, jclass) {
int err = last_error;
last_error = TRAY_NOERR;
return last_error; // Return the last error
}
/*
* Class: WindowsTrayIcon
* Method: getFreeId
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_jeans_trayicon_WindowsTrayIcon_getFreeId(JNIEnv *env, jclass) {
#ifdef NO_JVM_LIB
env->GetJavaVM(&hJavaVM);
#endif
// Wait for the hidden window to be created (see initTrayIcon())
if (wait_event != NULL) {
WaitForSingleObject(wait_event,10000);
CloseHandle(wait_event);
wait_event = NULL;
}
// Hidden window handle valid?
if (my_hDlg == NULL) {
last_error = TRAY_NOTIFYPROCERR;
return TRAY_NOTIFYPROCERR;
}
// Instance handle valid?
if (g_hinst == NULL) {
last_error = TRAY_DLLNOTFOUND;
return TRAY_DLLNOTFOUND;
}
// Find unused icon record and return icon id
for (int ctr = 0; ctr < MY_MAX_ICONS; ctr++) {
if (tray_icons[ctr].used == FALSE) {
// Unused record, initialize fields and return id
tray_icons[ctr].used = TRUE;
tray_icons[ctr].visible = FALSE;
tray_icons[ctr].icon = NULL;
tray_icons[ctr].tooltip = NULL;
tray_icons[ctr].popup = NULL;
return ctr;
}
}
// No empty record left, return error
last_error = TRAY_NOTIFYPROCERR;
return TRAY_TOOMANYICONS;
}
/*
* Class: WindowsTrayIcon
* Method: setIconData
* Signature: (III[I)V
*/
JNIEXPORT void JNICALL Java_com_jeans_trayicon_WindowsTrayIcon_setIconData(JNIEnv *env, jclass, jint id_num, jint wd, jint hi, jintArray array) {
// Instance handle valid?
if (g_hinst == NULL) {
last_error = TRAY_DLLNOTFOUND;
return;
}
// Icon id valid?
if (tray_icons[id_num].used == FALSE) {
last_error = TRAY_WRONGICONID;
return;
}
// Get array length and elements
jsize len = env->GetArrayLength(array);
jint *body = env->GetIntArrayElements(array, 0);
// Allocate data for icon bitmap and store the given pixel array
IconData *data = new IconData();
if (data != NULL && data->setData((unsigned long *)body, wd, hi) != -1) {
IconData *olddata = tray_icons[id_num].icon;
tray_icons[id_num].icon = data;
updateIcon(id_num);
if (olddata != NULL) delete olddata;
} else {
delete data;
last_error = TRAY_NOTENOUGHMEM;
}
// Release java array
env->ReleaseIntArrayElements(array, body, 0);
}
/*
* Class: WindowsTrayIcon
* Method: showIcon
* Signature: (IZ)V
*/
JNIEXPORT void JNICALL Java_com_jeans_trayicon_WindowsTrayIcon_showIcon(JNIEnv *, jclass, jint id_num, jboolean show) {
// Hidden window handle valid?
if (my_hDlg == NULL) {
last_error = TRAY_NOTIFYPROCERR;
return;
}
// Instance handle valid?
if (g_hinst == NULL) {
last_error = TRAY_DLLNOTFOUND;
return;
}
// Icon id valid?
if (tray_icons[id_num].used == FALSE) {
last_error = TRAY_WRONGICONID;
return;
}
if (show) {
// Show icon in windows system tray
if (tray_icons[id_num].visible == FALSE && tray_icons[id_num].icon != NULL) {
HICON icon = tray_icons[id_num].icon->makeIcon(g_hinst);
if (icon != NULL) {
TrayMessage(my_hDlg, NIM_ADD, id_num, icon, tray_icons[id_num].tooltip);
tray_icons[id_num].visible = TRUE;
} else {
last_error = TRAY_NOTENOUGHMEM;
}
}
} else {
// Hide icon (make invisible)
if (tray_icons[id_num].visible == TRUE) {
TrayMessage(my_hDlg, NIM_DELETE, id_num, NULL, NULL);
tray_icons[id_num].visible = FALSE;
}
}
}
/*
* Class: jeans_trayicon_WindowsTrayIcon
* Method: testVisible
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_com_jeans_trayicon_WindowsTrayIcon_testVisible(JNIEnv *, jclass, jint id_num) {
// Icon id valid?
if (tray_icons[id_num].used == FALSE) {
last_error = TRAY_WRONGICONID;
return TRAY_WRONGICONID;
}
// Is the icon visible now?
if (tray_icons[id_num].visible == TRUE) {
return 1;
} else {
return 0;
}
}
/*
* Class: jeans_trayicon_WindowsTrayIcon
* Method: clickEnable
* Signature: (Ljeans/graph/trayicon/WindowsTrayIcon;IZ)V
*/
JNIEXPORT void JNICALL Java_com_jeans_trayicon_WindowsTrayIcon_clickEnable(JNIEnv *env, jclass, jobject ic_cls, jint id_num, jboolean enable) {
// Icon id valid?
if (tray_icons[id_num].used == FALSE) {
last_error = TRAY_WRONGICONID;
return;
}
if (enable == TRUE) {
// Make icon clickenable by storing a global reference to it's class
jobject globalWinTrayClass = env->NewGlobalRef(ic_cls);
if (globalWinTrayClass != 0) {
if (tray_icons[id_num].globalClass != 0)
env->DeleteGlobalRef(tray_icons[id_num].globalClass);
tray_icons[id_num].globalClass = globalWinTrayClass;
}
} else {
// Remove the icon's global class reference
if (tray_icons[id_num].globalClass != 0)
env->DeleteGlobalRef(tray_icons[id_num].globalClass);
tray_icons[id_num].globalClass = 0;
}
}
/*
* Class: jeans_trayicon_WindowsTrayIcon
* Method: setToolTip
* Signature: (ILjava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_jeans_trayicon_WindowsTrayIcon_setToolTip(JNIEnv *env, jclass, jint id_num, jstring tip) {
// Icon id valid?
if (tray_icons[id_num].used == FALSE) {
last_error = TRAY_WRONGICONID;
return;
}
// Get java string for tooltip
const char *tooltip = env->GetStringUTFChars(tip, 0);
int len = strlen(tooltip);
// If already exists delete first..
if (tray_icons[id_num].tooltip != NULL) delete tray_icons[id_num].tooltip;
tray_icons[id_num].tooltip = new char[len+1];
strcpy(tray_icons[id_num].tooltip, tooltip);
// Release java string
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -