Chandra
view release on metacpan or search on metacpan
include/webview-tray-win32.c view on Meta::CPAN
/*
* webview-tray-win32.c â Windows system tray (Shell_NotifyIcon) backend
*
* Uses the Win32 Shell notification API with popup menus.
*/
#define WM_TRAYICON (WM_USER + 1)
struct webview_tray_win32 {
NOTIFYICONDATAA nid;
HMENU menu;
HWND msg_hwnd;
};
/* Forward */
static LRESULT CALLBACK tray_wndproc(HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam);
static HMENU tray_win32_build_menu(struct webview_tray *t,
struct webview_tray_item *items,
int count) {
HMENU menu = CreatePopupMenu();
for (int i = 0; i < count; i++) {
struct webview_tray_item *it = &items[i];
if (it->is_separator) {
AppendMenuA(menu, MF_SEPARATOR, 0, NULL);
continue;
}
UINT flags = MF_STRING;
if (it->is_disabled) flags |= MF_GRAYED;
if (it->is_checked) flags |= MF_CHECKED;
if (it->submenu_count > 0 && it->submenu) {
HMENU sub = tray_win32_build_menu(t, it->submenu, it->submenu_count);
AppendMenuA(menu, flags | MF_POPUP, (UINT_PTR)sub,
it->label ? it->label : "");
} else {
AppendMenuA(menu, flags, (UINT_PTR)it->id,
it->label ? it->label : "");
}
}
return menu;
}
static LRESULT CALLBACK tray_wndproc(HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam) {
struct webview_tray *t = (struct webview_tray *)
GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (msg == WM_TRAYICON) {
if (LOWORD(lParam) == WM_RBUTTONUP || LOWORD(lParam) == WM_LBUTTONUP) {
struct webview_tray_win32 *priv = (struct webview_tray_win32 *)t->_priv;
POINT pt;
GetCursorPos(&pt);
SetForegroundWindow(hwnd);
int cmd = TrackPopupMenu(priv->menu,
TPM_RETURNCMD | TPM_NONOTIFY,
pt.x, pt.y, 0, hwnd, NULL);
SendMessage(hwnd, WM_NULL, 0, 0);
if (cmd > 0 && t->menu_cb) {
t->menu_cb(t->w, cmd);
}
}
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
WEBVIEW_API int webview_tray_create(struct webview_tray *t) {
struct webview_tray_win32 *priv = (struct webview_tray_win32 *)
calloc(1, sizeof(*priv));
if (!priv) return -1;
t->_priv = priv;
/* Register a hidden message-only window class for tray messages */
static int tray_class_registered = 0;
HINSTANCE hInst = GetModuleHandle(NULL);
if (!tray_class_registered) {
WNDCLASSEXA wc;
ZeroMemory(&wc, sizeof(wc));
wc.cbSize = sizeof(wc);
wc.lpfnWndProc = tray_wndproc;
wc.hInstance = hInst;
wc.lpszClassName = "Chandra_TrayMsg";
RegisterClassExA(&wc);
tray_class_registered = 1;
}
priv->msg_hwnd = CreateWindowExA(0, "Chandra_TrayMsg", "", 0,
0, 0, 0, 0,
HWND_MESSAGE, NULL, hInst, NULL);
SetWindowLongPtr(priv->msg_hwnd, GWLP_USERDATA, (LONG_PTR)t);
/* Set up NOTIFYICONDATA */
ZeroMemory(&priv->nid, sizeof(priv->nid));
priv->nid.cbSize = sizeof(priv->nid);
priv->nid.hWnd = priv->msg_hwnd;
priv->nid.uID = 1;
priv->nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
priv->nid.uCallbackMessage = WM_TRAYICON;
/* Load icon */
if (t->icon_path && strlen(t->icon_path) > 0) {
priv->nid.hIcon = (HICON)LoadImageA(NULL, t->icon_path,
IMAGE_ICON, 0, 0,
LR_LOADFROMFILE | LR_DEFAULTSIZE);
}
if (!priv->nid.hIcon) {
priv->nid.hIcon = LoadIcon(NULL, IDI_APPLICATION);
}
/* Tooltip */
if (t->tooltip) {
strncpy(priv->nid.szTip, t->tooltip, sizeof(priv->nid.szTip) - 1);
}
Shell_NotifyIconA(NIM_ADD, &priv->nid);
/* Build menu */
priv->menu = tray_win32_build_menu(t, t->items, t->item_count);
return 0;
}
WEBVIEW_API void webview_tray_update(struct webview_tray *t) {
if (!t || !t->_priv) return;
struct webview_tray_win32 *priv = (struct webview_tray_win32 *)t->_priv;
/* Update tooltip */
if (t->tooltip) {
strncpy(priv->nid.szTip, t->tooltip, sizeof(priv->nid.szTip) - 1);
}
/* Update icon */
if (t->icon_path && strlen(t->icon_path) > 0) {
HICON newicon = (HICON)LoadImageA(NULL, t->icon_path,
IMAGE_ICON, 0, 0,
LR_LOADFROMFILE | LR_DEFAULTSIZE);
if (newicon) {
priv->nid.hIcon = newicon;
}
}
Shell_NotifyIconA(NIM_MODIFY, &priv->nid);
/* Rebuild menu */
if (priv->menu) {
DestroyMenu(priv->menu);
}
priv->menu = tray_win32_build_menu(t, t->items, t->item_count);
}
WEBVIEW_API void webview_tray_destroy(struct webview_tray *t) {
if (!t || !t->_priv) return;
struct webview_tray_win32 *priv = (struct webview_tray_win32 *)t->_priv;
Shell_NotifyIconA(NIM_DELETE, &priv->nid);
if (priv->menu) {
DestroyMenu(priv->menu);
}
if (priv->msg_hwnd) {
DestroyWindow(priv->msg_hwnd);
}
free(priv);
t->_priv = NULL;
}
( run in 0.560 second using v1.01-cache-2.11-cpan-39bf76dae61 )