From 4b1eb956012629e12fe8bd00cbfc829beee7f067 Mon Sep 17 00:00:00 2001 From: nathan Date: Sun, 8 Apr 2018 21:58:56 +0200 Subject: [PATCH] Removed Windows Native Tray +menu WIP --- .../nativeUI/WindowsBaseMenuItem.java | 167 ---- .../systemTray/nativeUI/WindowsMenu.java | 741 ------------------ .../systemTray/nativeUI/WindowsMenuItem.java | 94 --- .../nativeUI/WindowsMenuItemCheckbox.java | 153 ---- .../nativeUI/WindowsMenuItemSeparator.java | 45 -- .../nativeUI/WindowsMenuItemStatus.java | 71 -- .../nativeUI/_WindowsNativeTray.java | 271 ------- 7 files changed, 1542 deletions(-) delete mode 100644 src/dorkbox/systemTray/nativeUI/WindowsBaseMenuItem.java delete mode 100644 src/dorkbox/systemTray/nativeUI/WindowsMenu.java delete mode 100644 src/dorkbox/systemTray/nativeUI/WindowsMenuItem.java delete mode 100644 src/dorkbox/systemTray/nativeUI/WindowsMenuItemCheckbox.java delete mode 100644 src/dorkbox/systemTray/nativeUI/WindowsMenuItemSeparator.java delete mode 100644 src/dorkbox/systemTray/nativeUI/WindowsMenuItemStatus.java delete mode 100644 src/dorkbox/systemTray/nativeUI/_WindowsNativeTray.java diff --git a/src/dorkbox/systemTray/nativeUI/WindowsBaseMenuItem.java b/src/dorkbox/systemTray/nativeUI/WindowsBaseMenuItem.java deleted file mode 100644 index 416f5ea..0000000 --- a/src/dorkbox/systemTray/nativeUI/WindowsBaseMenuItem.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2017 dorkbox, llc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package dorkbox.systemTray.nativeUI; - -import static com.sun.jna.platform.win32.WinDef.HMENU; -import static dorkbox.systemTray.nativeUI.WindowsMenu.MFT_OWNERDRAW; -import static dorkbox.util.jna.windows.User32.MF_BYPOSITION; - -import java.awt.AlphaComposite; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.image.BufferedImage; -import java.io.File; - -import javax.swing.Icon; -import javax.swing.ImageIcon; - -import com.sun.jna.platform.win32.BaseTSD; - -import dorkbox.systemTray.SystemTray; -import dorkbox.util.SwingUtil; -import dorkbox.util.jna.windows.GDI32; -import dorkbox.util.jna.windows.GetLastErrorException; -import dorkbox.util.jna.windows.HBITMAPWrap; -import dorkbox.util.jna.windows.User32; -import dorkbox.util.jna.windows.structs.MENUITEMINFO; - -public class WindowsBaseMenuItem { - - private final int position; - - volatile HBITMAPWrap hbitmapWrapImage; - volatile String text = ""; - volatile boolean enabled = true; // default is enabled - - // these have to be volatile, because they can be changed from any thread - private volatile ActionListener callback; - private volatile ActionEvent actionEvent; - - public - WindowsBaseMenuItem(int position) { - this.position = position; - } - - void setText(final String text) { - if (text != null) { - this.text = text; - } else { - this.text = ""; - } - } - - void setEnabled(final boolean enabled) { - this.enabled = enabled; - } - - void setImage(final File imageFile) { - if (imageFile != null) { - SwingUtil.invokeAndWaitQuietly(new Runnable() { - @Override - public - void run() { - // has to run on swing EDT. - ImageIcon imageIcon = new ImageIcon(imageFile.getAbsolutePath()); - // fully loads the image and returns when it's done loading the image - imageIcon = new ImageIcon(imageIcon.getImage()); - - hbitmapWrapImage = convertMenuImage(imageIcon); - } - }); - } - else { - hbitmapWrapImage = null; - } - } - - void setCallback(final ActionListener callback, final ActionEvent actionEvent) { - this.callback = callback; - this.actionEvent = actionEvent; - } - - void fireCallback() { - ActionEvent actionEvent = this.actionEvent; - ActionListener callback = this.callback; - - if (callback != null) { - try { - callback.actionPerformed(actionEvent); - } catch (Throwable throwable) { - SystemTray.logger.error("Error calling menu entry {} click event.", this.text, throwable); - } - } - } - - private static HBITMAPWrap convertMenuImage(Icon icon) { -// BufferedImage img = createBitmap(icon); - - int menubarHeight = WindowsMenu.getSystemMenuImageSize(); - - BufferedImage scaledImage = new BufferedImage(menubarHeight, menubarHeight, BufferedImage.TYPE_INT_ARGB); - Graphics2D g = scaledImage.createGraphics(); - g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); - g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); - g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); - - icon.paintIcon(null, g, 0, 0); -// g.drawImage(img, 0, 0, menubarHeight, menubarHeight, null); - g.dispose(); - - return new HBITMAPWrap(scaledImage); - } - - void remove() { - if (hbitmapWrapImage != null) { - GDI32.DeleteObject(hbitmapWrapImage); - hbitmapWrapImage = null; - } - } - - boolean hasImage() { - return false; - } - - void onCreateMenu(final HMENU parentNative, final boolean hasImages) { -// setSpacerImage(hasImagesInMenu); - - if (!User32.IMPL.AppendMenu(parentNative, MFT_OWNERDRAW, position, null)) { - throw new GetLastErrorException(); - } - - MENUITEMINFO mmi = new MENUITEMINFO(); - if (!User32.IMPL.GetMenuItemInfo(parentNative, position, false, mmi)) { - throw new GetLastErrorException(); - } - - mmi.dwItemData = new BaseTSD.ULONG_PTR(position); - mmi.fMask |= MENUITEMINFO.MIIM_DATA; - - if (!User32.IMPL.SetMenuItemInfo(parentNative, position, false, mmi)) { - throw new GetLastErrorException(); - } - } - - void onDeleteMenu(final HMENU parentNative) { - remove(); - - if (!User32.IMPL.DeleteMenu(parentNative, position, MF_BYPOSITION)) { - throw new GetLastErrorException(); - } - } -} diff --git a/src/dorkbox/systemTray/nativeUI/WindowsMenu.java b/src/dorkbox/systemTray/nativeUI/WindowsMenu.java deleted file mode 100644 index 1896d1a..0000000 --- a/src/dorkbox/systemTray/nativeUI/WindowsMenu.java +++ /dev/null @@ -1,741 +0,0 @@ -/* - * Copyright 2017 dorkbox, llc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package dorkbox.systemTray.nativeUI; - -import static com.sun.jna.platform.win32.WinDef.HBITMAP; -import static com.sun.jna.platform.win32.WinDef.HDC; -import static com.sun.jna.platform.win32.WinDef.HFONT; -import static com.sun.jna.platform.win32.WinDef.HMENU; -import static com.sun.jna.platform.win32.WinDef.HWND; -import static com.sun.jna.platform.win32.WinDef.LPARAM; -import static com.sun.jna.platform.win32.WinDef.POINT; -import static com.sun.jna.platform.win32.WinDef.RECT; -import static com.sun.jna.platform.win32.WinDef.WPARAM; -import static com.sun.jna.platform.win32.WinNT.HANDLE; -import static com.sun.jna.platform.win32.WinUser.AC_SRC_ALPHA; -import static com.sun.jna.platform.win32.WinUser.AC_SRC_OVER; -import static com.sun.jna.platform.win32.WinUser.SIZE; -import static com.sun.jna.platform.win32.WinUser.SM_CYMENUCHECK; -import static dorkbox.util.jna.windows.WindowsEventDispatch.MF_POPUP; -import static dorkbox.util.jna.windows.WindowsEventDispatch.WM_COMMAND; -import static dorkbox.util.jna.windows.WindowsEventDispatch.WM_DRAWITEM; -import static dorkbox.util.jna.windows.WindowsEventDispatch.WM_MEASUREITEM; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; - -import com.sun.jna.Pointer; - -import dorkbox.systemTray.Checkbox; -import dorkbox.systemTray.Entry; -import dorkbox.systemTray.Menu; -import dorkbox.systemTray.MenuItem; -import dorkbox.systemTray.Separator; -import dorkbox.systemTray.Status; -import dorkbox.systemTray.peer.MenuPeer; -import dorkbox.util.jna.windows.GDI32; -import dorkbox.util.jna.windows.GetLastErrorException; -import dorkbox.util.jna.windows.Listener; -import dorkbox.util.jna.windows.MsImg32; -import dorkbox.util.jna.windows.User32; -import dorkbox.util.jna.windows.WindowsEventDispatch; -import dorkbox.util.jna.windows.structs.BLENDFUNCTION; -import dorkbox.util.jna.windows.structs.DRAWITEMSTRUCT; -import dorkbox.util.jna.windows.structs.MEASUREITEMSTRUCT; -import dorkbox.util.jna.windows.structs.NONCLIENTMETRICS; - -// this is a weird composite class, because it must be a Menu, but ALSO a Entry -- so it has both -@SuppressWarnings("ForLoopReplaceableByForEach") -class WindowsMenu extends WindowsBaseMenuItem implements MenuPeer { - - volatile HMENU _nativeMenu; // must ONLY be created at the end of delete! - private final WindowsMenu parent; - - private final Listener menuItemListener; - private final Listener menuItemMeasureListener; - private final Listener menuItemDrawListener; - - public static final int WM_NULL = 0x0000; - - public static final int VK_ESCAPE = 0x1B; - public static final int WM_KEYDOWN = 0x0100; - - public static final int TPM_RECURSE = 0x0001; - public static final int TPM_RIGHTBUTTON = 0x0002; - - public static final int MFT_OWNERDRAW = 256; - - - private static final int SPACE_ICONS = 2; - - // have to make sure no other methods can call obliterate, delete, or create menu once it's already started - private AtomicBoolean obliterateInProgress = new AtomicBoolean(false); - - // this is a list (that mirrors the actual list) BECAUSE we have to create/delete the entire menu in Windows every time something is changed - private final List menuEntries = new ArrayList(); - - - // called by the system tray constructors - // This is NOT a copy constructor! - @SuppressWarnings("IncompleteCopyConstructor") - WindowsMenu() { - super(0); - this.parent = null; - - // Register drawing menu items, etc - menuItemListener = new Listener() { - @Override - public - void run(final HWND hWnd, final WPARAM wParam, final LPARAM lParam) { - int position = wParam.intValue() & 0xff; - WindowsBaseMenuItem item = menuEntries.get(position); - item.fireCallback(); - } - }; - - menuItemMeasureListener = new Listener() { - @Override - public - void run(final HWND hWnd, final WPARAM wParam, final LPARAM lParam) { - MEASUREITEMSTRUCT ms = new MEASUREITEMSTRUCT(new Pointer(lParam.longValue())); - - int position = ms.itemData.intValue(); - WindowsBaseMenuItem item = menuEntries.get(position); - - SIZE size = measureItem(hWnd, item); - ms.itemWidth = size.cx; - ms.itemHeight = size.cy; - ms.write(); - } - }; - - - menuItemDrawListener = new Listener() { - @Override - public - void run(final HWND hWnd, final WPARAM wParam, final LPARAM lParam) { - DRAWITEMSTRUCT di = new DRAWITEMSTRUCT(new Pointer(lParam.longValue())); - - int position = di.itemData.intValue(); - WindowsBaseMenuItem item = menuEntries.get(position); - - drawItem(item, di.hDC, di.rcItem, di.itemState); - } - }; - - WindowsEventDispatch.addListener(WM_COMMAND, menuItemListener); - WindowsEventDispatch.addListener(WM_MEASUREITEM, menuItemMeasureListener); - WindowsEventDispatch.addListener(WM_DRAWITEM, menuItemDrawListener); - } - - // This is NOT a copy constructor! - @SuppressWarnings("IncompleteCopyConstructor") - private - WindowsMenu(final WindowsMenu parent, final int index) { - super(index); // is what is added to the parent menu (so images work) - this.parent = parent; - - // Register drawing menu items, etc - menuItemListener = new Listener() { - @Override - public - void run(final HWND hWnd, final WPARAM wParam, final LPARAM lParam) { - int position = wParam.intValue() & 0xff; - WindowsBaseMenuItem item = menuEntries.get(position); - item.fireCallback(); - } - }; - - menuItemMeasureListener = new Listener() { - @Override - public - void run(final HWND hWnd, final WPARAM wParam, final LPARAM lParam) { - MEASUREITEMSTRUCT ms = new MEASUREITEMSTRUCT(new Pointer(lParam.longValue())); - - int position = ms.itemData.intValue(); - WindowsBaseMenuItem item = menuEntries.get(position); - - SIZE size = measureItem(hWnd, item); - ms.itemWidth = size.cx; - ms.itemHeight = size.cy; - ms.write(); - } - }; - - menuItemDrawListener = new Listener() { - @Override - public - void run(final HWND hWnd, final WPARAM wParam, final LPARAM lParam) { - DRAWITEMSTRUCT di = new DRAWITEMSTRUCT(new Pointer(lParam.longValue())); - - int position = di.itemData.intValue(); - WindowsBaseMenuItem item = menuEntries.get(position); - - drawItem(item, di.hDC, di.rcItem, di.itemState); - } - }; - - WindowsEventDispatch.addListener(WM_COMMAND, menuItemListener); - WindowsEventDispatch.addListener(WM_MEASUREITEM, menuItemMeasureListener); - WindowsEventDispatch.addListener(WM_DRAWITEM, menuItemDrawListener); - } - - - WindowsMenu getParent() { - return parent; - } - - /** - * Deletes the menu, and unreferences everything in it. ALSO recreates ONLY the menu object. - */ - @SuppressWarnings("ForLoopReplaceableByForEach") - private - void deleteMenu() { - if (obliterateInProgress.get()) { - return; - } - - if (_nativeMenu != null) { - // have to work in reverse so the index is preserved - for (int i = menuEntries.size()-1; i >= 0; i--) { - final WindowsBaseMenuItem menuEntry__ = menuEntries.get(i); - menuEntry__.onDeleteMenu(_nativeMenu); - } - - if (!User32.IMPL.DestroyMenu(_nativeMenu)) { - throw new GetLastErrorException(); - } - } - - if (parent != null) { - parent.deleteMenu(); - } - - // makes a new one - this._nativeMenu = User32.IMPL.CreatePopupMenu(); - - // binds sub-menu to entry (if it exists! it does not for the root menu) - if (parent != null) { - // get around windows crap (transfer handle to decimal) - int handle = (int) Pointer.nativeValue(_nativeMenu.getPointer()); - - if (!User32.IMPL.AppendMenu(getParent()._nativeMenu, MF_POPUP | MFT_OWNERDRAW, handle, null)) { - throw new GetLastErrorException(); - } - } - } - - /** - * some GTK libraries DO NOT let us add items AFTER the menu has been attached to the indicator. - * - * To work around this issue, we destroy then recreate the menu every time something is changed. - * - * ALWAYS CALLED ON THE EDT - */ - @SuppressWarnings("ForLoopReplaceableByForEach") - private - void createMenu() { - if (obliterateInProgress.get()) { - return; - } - - if (parent != null) { - parent.createMenu(); - } - - // now add back other menu entries - boolean hasImages = false; - - for (int i = 0, menuEntriesSize = menuEntries.size(); i < menuEntriesSize; i++) { - final WindowsBaseMenuItem menuEntry__ = menuEntries.get(i); - hasImages |= menuEntry__.hasImage(); - } - - for (int i = 0, menuEntriesSize = menuEntries.size(); i < menuEntriesSize; i++) { - // the menu entry looks FUNKY when there are a mis-match of entries WITH and WITHOUT images - final WindowsBaseMenuItem menuEntry__ = menuEntries.get(i); - menuEntry__.onCreateMenu(_nativeMenu, hasImages); - - if (menuEntry__ instanceof WindowsMenu) { - WindowsMenu subMenu = (WindowsMenu) menuEntry__; - if (subMenu.getParent() != WindowsMenu.this) { - // we don't want to "createMenu" on our sub-menu that is assigned to us directly, as they are already doing it - subMenu.createMenu(); - } - } - } - -// Gtk.gtk_widget_show_all(_nativeMenu); // necessary to guarantee widget is visible (doesn't always show_all for all children) -// onMenuAdded(_nativeMenu); // not needed for windows - } - - /** - * Completely obliterates the menu, no possible way to reconstruct it. - * - * ALWAYS CALLED ON THE EDT - */ - @SuppressWarnings("ForLoopReplaceableByForEach") - private - void obliterateMenu() { - if (_nativeMenu != null && !obliterateInProgress.get()) { - obliterateInProgress.set(true); - - // have to remove all other menu entries - - // a copy is made because sub-menus remove themselves from parents when .remove() is called. If we don't - // do this, errors will be had because indices don't line up anymore. - ArrayList menuEntriesCopy = new ArrayList(menuEntries); - menuEntries.clear(); - - // have to work in reverse so the index is preserved - for (int i = menuEntriesCopy.size()-1; i >= 0; i--) { - final WindowsBaseMenuItem menuEntry__ = menuEntriesCopy.get(i); - menuEntry__.onDeleteMenu(_nativeMenu); - } - menuEntriesCopy.clear(); - - if (!User32.IMPL.DestroyMenu(_nativeMenu)) { - throw new GetLastErrorException(); - } - - _nativeMenu = null; - - obliterateInProgress.set(false); - } - } - - - @Override - public - void add(final Menu parentMenu, final Entry entry, int index) { - deleteMenu(); - - if (entry instanceof Menu) { -// WindowsMenu item = new WindowsMenu(WindowsMenu.this, index); -// menuEntries.add(index, item); -// ((Menu) entry).bind(item, parentMenu, parentMenu.getSystemTray()); - } - else if (entry instanceof Separator) { -// WindowsMenuItemSeparator item = new WindowsMenuItemSeparator(WindowsMenu.this); -// menuEntries.add(index, item); -// entry.bind(item, parentMenu, parentMenu.getSystemTray()); - } - else if (entry instanceof Checkbox) { -// WindowsMenuItemCheckbox item = new WindowsMenuItemCheckbox(WindowsMenu.this); -// menuEntries.add(index, item); -// ((Checkbox) entry).bind(item, parentMenu, parentMenu.getSystemTray()); - } - else if (entry instanceof Status) { -// WindowsMenuItemStatus item = new WindowsMenuItemStatus(WindowsMenu.this); -// menuEntries.add(index, item); -// ((Status) entry).bind(item, parentMenu, parentMenu.getSystemTray()); - } - else if (entry instanceof MenuItem) { - WindowsMenuItem item = new WindowsMenuItem(WindowsMenu.this, index); - menuEntries.add(index, item); - ((MenuItem) entry).bind(item, parentMenu, parentMenu.getSystemTray()); - } - - createMenu(); - } - - // is overridden in tray impl - @Override - public - void setImage(final MenuItem menuItem) { - super.setImage(menuItem.getImage()); - } - - // is overridden in tray impl - @Override - public - void setEnabled(final MenuItem menuItem) { - super.setEnabled(menuItem.getEnabled()); - } - - // is overridden in tray impl - @Override - public - void setText(final MenuItem menuItem) { - super.setText(menuItem.getText()); - } - - @Override - public - void setCallback(final MenuItem menuItem) { - // can't have a callback for menus! - } - - // is overridden in tray impl - @Override - public - void setShortcut(final MenuItem menuItem) { -// // yikes... -// final int vKey = SwingUtil.getVirtualKey(menuItem.getShortcut()); -// -// SwingUtil.invokeLater(new Runnable() { -// @Override -// public -// void run() { -// _native.setShortcut(new MenuShortcut(vKey)); -// } -// }); - } - - /** - * called when a child removes itself from the parent menu. Does not work for sub-menus - * - * ALWAYS CALLED ON THE EDT - */ - public - void remove(final WindowsBaseMenuItem item) { - menuEntries.remove(item); - - // have to rebuild the menu now... - deleteMenu(); // must be on EDT - createMenu(); // must be on EDT - } - - // a child will always remove itself from the parent. - @Override - public - void remove() { - WindowsMenu parent = getParent(); - - if (parent != null) { - // have to remove from the parent.menuEntries first - parent.menuEntries.remove(WindowsMenu.this); - } - - // delete all of the children of this submenu (must happen before the menuEntry is removed) - obliterateMenu(); - - if (parent != null) { - // have to rebuild the menu now... - parent.deleteMenu(); // must be on EDT - parent.createMenu(); // must be on EDT - } - } - - - void showContextMenu(final POINT position) { - HWND mainHwnd = WindowsEventDispatch.get(); - User32.IMPL.SetForegroundWindow(mainHwnd); - - // TrackPopupMenu blocks until popup menu is closed - if (!User32.IMPL.TrackPopupMenu(_nativeMenu, TPM_RIGHTBUTTON, position.x, position.y, 0, mainHwnd, null)) { - // Popup menu already active - if (com.sun.jna.platform.win32.Kernel32.INSTANCE.GetLastError() == 0x000005a6) { - HWND hWnd = null; - while (true) { - // "#32768" - Name of the popup menu class - hWnd = User32.IMPL.FindWindowEx(null, hWnd, "#32768", null); - - if (hWnd == null) { - break; - } - - // close the previous popup menu - User32.IMPL.SendMessage(hWnd, WM_KEYDOWN, new WPARAM(VK_ESCAPE), new LPARAM(0)); - } - - return; - } else { - throw new GetLastErrorException(); - } - } - - User32.IMPL.PostMessage(mainHwnd, WM_NULL, new WPARAM(0), new LPARAM(0)); - } - - -// // menus have to be cleared before each render. -// void clearMenus() { -// if (_native != null) { -// if (!User32.DestroyMenu(_native)) { -// System.err.println("PROBLEM"); -//// throw new GetLastErrorException(); -// } -// _native = null; -// } -// for (WindowsBaseMenuItem m : menuEntries) { -// m.close(); -// } -// -// hMenusIDs.clear(); -// } - -// void updateMenus() { -// clearMenus(); -// -// HMENU hmenu = User32.CreatePopupMenu(); -// this._native = hmenu; -// -// for (int i = 0; i < menu.getComponentCount(); i++) { -// Component e = menu.getComponent(i); -// -// if (e instanceof JMenu) { -// JMenu sub = (JMenu) e; -// HMENU hsub = createSubmenu(sub); -// -// int nID = menuEntries.size(); -// menuEntries.add(new WindowsBaseMenuItem(sub)); -// -// // you know, the usual windows tricks (transfer handle to -// // decimal) -// int handle = (int) Pointer.nativeValue(hsub.getPointer()); -// -// if (!User32.AppendMenu(hmenu, MF_POPUP | MFT_OWNERDRAW, handle, null)) -// throw new GetLastErrorException(); -// -// MENUITEMINFO mi = new MENUITEMINFO(); -// if (!User32.GetMenuItemInfo(hmenu, handle, false, mi)) -// throw new GetLastErrorException(); -// -// mi.dwItemData = new ULONG_PTR(nID); -// mi.fMask |= MENUITEMINFO.MIIM_DATA; -// if (!User32.SetMenuItemInfo(hmenu, handle, false, mi)) -// throw new GetLastErrorException(); -// -// -// } else if (e instanceof JCheckBoxMenuItem) { -// JCheckBoxMenuItem ch = (JCheckBoxMenuItem) e; -// -// int nID = menuEntries.size(); -// menuEntries.add(new WindowsBaseMenuItem(ch)); -// -// if (!User32.AppendMenu(hmenu, MFT_OWNERDRAW, nID, null)) -// throw new GetLastErrorException(); -// -// MENUITEMINFO mmi = new MENUITEMINFO(); -// if (!User32.GetMenuItemInfo(hmenu, nID, false, mmi)) -// throw new GetLastErrorException(); -// mmi.dwItemData = new ULONG_PTR(nID); -// mmi.fMask |= MENUITEMINFO.MIIM_DATA; -// if (!User32.SetMenuItemInfo(hmenu, nID, false, mmi)) -// throw new GetLastErrorException(); -// } else if (e instanceof JMenuItem) { -// JMenuItem mi = (JMenuItem) e; -// -// int nID = menuEntries.size(); -// menuEntries.add(new WindowsBaseMenuItem(mi)); -// -// if (!User32.AppendMenu(hmenu, MFT_OWNERDRAW, nID, null)) -// throw new GetLastErrorException(); -// -// MENUITEMINFO mmi = new MENUITEMINFO(); -// if (!User32.GetMenuItemInfo(hmenu, nID, false, mmi)) -// throw new GetLastErrorException(); -// mmi.dwItemData = new ULONG_PTR(nID); -// mmi.fMask |= MENUITEMINFO.MIIM_DATA; -// if (!User32.SetMenuItemInfo(hmenu, nID, false, mmi)) -// throw new GetLastErrorException(); -// } -// -// if (e instanceof JPopupMenu.Separator) { -// if (!User32.AppendMenu(hmenu, MF_SEPARATOR, 0, null)) -// throw new GetLastErrorException(); -// } -// } -// } - -// HMENU createSubmenu(JMenu menu) { -// HMENU hmenu = User32.CreatePopupMenu(); -// // seems like you dont have to free this menu, since it already attached -// // to main HMENU handler -// -// for (int i = 0; i < menu.getMenuComponentCount(); i++) { -// Component e = menu.getMenuComponent(i); -// -// if (e instanceof JMenu) { -// JMenu sub = (JMenu) e; -// HMENU hsub = createSubmenu(sub); -// -// // you know, the usual windows tricks (transfer handle to -// // decimal) -// int handle = (int) Pointer.nativeValue(hsub.getPointer()); -// -// int nID = menuEntries.size(); -// menuEntries.add(new WindowsBaseMenuItem(sub)); -// -// if (!User32.AppendMenu(hmenu, MF_POPUP | MFT_OWNERDRAW, handle, null)) -// throw new GetLastErrorException(); -// -// MENUITEMINFO mi = new MENUITEMINFO(); -// if (!User32.GetMenuItemInfo(hmenu, handle, false, mi)) -// throw new GetLastErrorException(); -// mi.dwItemData = new ULONG_PTR(nID); -// mi.fMask |= MENUITEMINFO.MIIM_DATA; -// if (!User32.SetMenuItemInfo(hmenu, handle, false, mi)) -// throw new GetLastErrorException(); -// } else if (e instanceof JCheckBoxMenuItem) { -// JCheckBoxMenuItem ch = (JCheckBoxMenuItem) e; -// -// int nID = menuEntries.size(); -// menuEntries.add(new WindowsBaseMenuItem(ch)); -// -// if (!User32.AppendMenu(hmenu, MFT_OWNERDRAW, nID, null)) -// throw new GetLastErrorException(); -// -// MENUITEMINFO mi = new MENUITEMINFO(); -// if (!User32.GetMenuItemInfo(hmenu, nID, false, mi)) -// throw new GetLastErrorException(); -// mi.dwItemData = new ULONG_PTR(nID); -// mi.fMask |= MENUITEMINFO.MIIM_DATA; -// if (!User32.SetMenuItemInfo(hmenu, nID, false, mi)) -// throw new GetLastErrorException(); -// } else if (e instanceof JMenuItem) { -// JMenuItem mi = (JMenuItem) e; -// -// int nID = menuEntries.size(); -// menuEntries.add(new WindowsBaseMenuItem(mi)); -// -// if (!User32.AppendMenu(hmenu, MFT_OWNERDRAW, nID, null)) -// throw new GetLastErrorException(); -// -// MENUITEMINFO mmi = new MENUITEMINFO(); -// if (!User32.GetMenuItemInfo(hmenu, nID, false, mmi)) -// throw new GetLastErrorException(); -// mmi.dwItemData = new ULONG_PTR(nID); -// mmi.fMask |= MENUITEMINFO.MIIM_DATA; -// if (!User32.SetMenuItemInfo(hmenu, nID, false, mmi)) -// throw new GetLastErrorException(); -// } -// -// if (e instanceof JPopupMenu.Separator) { -// if (!User32.AppendMenu(hmenu, MF_SEPARATOR, 0, null)) -// throw new GetLastErrorException(); -// } -// } -// -// return hmenu; -// } - - - private static - void drawItem(WindowsBaseMenuItem item, HDC hDC, RECT rcItem, int itemState) { - if (!item.enabled) { - GDI32.SetTextColor(hDC, User32.IMPL.GetSysColor(User32.COLOR_GRAYTEXT)); - GDI32.SetBkColor(hDC, User32.IMPL.GetSysColor(User32.COLOR_MENU)); - } - else if ((itemState & DRAWITEMSTRUCT.ODS_SELECTED) == DRAWITEMSTRUCT.ODS_SELECTED) { - GDI32.SetTextColor(hDC, User32.IMPL.GetSysColor(User32.COLOR_HIGHLIGHTTEXT)); - GDI32.SetBkColor(hDC, User32.IMPL.GetSysColor(User32.COLOR_HIGHLIGHT)); - } - else { - GDI32.SetTextColor(hDC, User32.IMPL.GetSysColor(User32.COLOR_MENUTEXT)); - GDI32.SetBkColor(hDC, User32.IMPL.GetSysColor(User32.COLOR_MENU)); - } - - int x = rcItem.left; - int y = rcItem.top; - - x += (getSystemMenuImageSize() + SPACE_ICONS) * 2; - - GDI32.SelectObject(hDC, createSystemMenuFont()); - GDI32.ExtTextOut(hDC, - x, - y, - GDI32.ETO_OPAQUE, - rcItem, - item.text, - item.text.length(), - null); - - x = rcItem.left; - -// if (item.item instanceof JCheckBoxMenuItem) { -// JCheckBoxMenuItem cc = (JCheckBoxMenuItem) item.item; -// if (cc.getState()) { -// // draw checkmark image -//// drawHBITMAP(hbitmapChecked, x, y, hbitmapChecked.getImage().getWidth(), -//// hbitmapChecked.getImage().getHeight(), hDC); -// } -// else { -// // draw blank checkmark image -//// drawHBITMAP(hbitmapUnchecked, x, y, hbitmapUnchecked.getImage().getWidth(), -//// hbitmapUnchecked.getImage().getHeight(), hDC); -// } -// } - - x += getSystemMenuImageSize() + SPACE_ICONS; - - if (item.hbitmapWrapImage != null) { - drawHBITMAP(item.hbitmapWrapImage, - x, - y, - item.hbitmapWrapImage.getImage().getWidth(), - item.hbitmapWrapImage.getImage().getHeight(), - hDC); - } - } - - public static - int getSystemMenuImageSize() { - // get's the height of the default (small) checkmark - return User32.IMPL.GetSystemMetrics(SM_CYMENUCHECK); - } - - static - HFONT createSystemMenuFont() { - NONCLIENTMETRICS nm = new NONCLIENTMETRICS(); - - User32.IMPL.SystemParametersInfo(User32.SPI_GETNONCLIENTMETRICS, 0, nm, 0); - return GDI32.CreateFontIndirect(nm.lfMenuFont); - } - - private static - void drawHBITMAP(HBITMAP hbm, int x, int y, int cx, int cy, HDC hdcDst) { - HDC hdcSrc = GDI32.CreateCompatibleDC(hdcDst); - HANDLE old = GDI32.SelectObject(hdcSrc, hbm); - - BLENDFUNCTION.ByValue bld = new BLENDFUNCTION.ByValue(); - bld.BlendOp = AC_SRC_OVER; - bld.BlendFlags = 0; - bld.SourceConstantAlpha = (byte) 255; - bld.AlphaFormat = AC_SRC_ALPHA; - - if (!MsImg32.AlphaBlend(hdcDst, x, y, cx, cy, hdcSrc, 0, 0, cx, cy, bld)) { - throw new GetLastErrorException(); - } - - GDI32.SelectObject(hdcSrc, old); - - if (!GDI32.DeleteDC(hdcSrc)) { - throw new GetLastErrorException(); - } - } - - private static - SIZE measureItem(HWND hWnd, WindowsBaseMenuItem item) { - HDC hdc = User32.IMPL.GetDC(hWnd); - HANDLE hfntOld = GDI32.SelectObject(hdc, createSystemMenuFont()); - SIZE size = new SIZE(); - if (!GDI32.GetTextExtentPoint32(hdc, - item.text, - item.text.length(), - size)) { - throw new GetLastErrorException(); - } - GDI32.SelectObject(hdc, hfntOld); - User32.IMPL.ReleaseDC(hWnd, hdc); - - size.cx += (getSystemMenuImageSize() + SPACE_ICONS) * 2; - - return size; - } -} diff --git a/src/dorkbox/systemTray/nativeUI/WindowsMenuItem.java b/src/dorkbox/systemTray/nativeUI/WindowsMenuItem.java deleted file mode 100644 index 5cb3be1..0000000 --- a/src/dorkbox/systemTray/nativeUI/WindowsMenuItem.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2017 dorkbox, llc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package dorkbox.systemTray.nativeUI; - -import java.awt.event.ActionEvent; - -import dorkbox.systemTray.peer.MenuItemPeer; - -class WindowsMenuItem extends WindowsBaseMenuItem implements MenuItemPeer { - - private final WindowsMenu parent; - - // this is ALWAYS called on the EDT. - WindowsMenuItem(final WindowsMenu parent, final int index) { - super(index); - this.parent = parent; - } - - @Override - public - void setImage(final dorkbox.systemTray.MenuItem menuItem) { - super.setImage(menuItem.getImage()); - } - - @Override - public - void setEnabled(final dorkbox.systemTray.MenuItem menuItem) { - super.setEnabled(menuItem.getEnabled()); - } - - @Override - public - void setText(final dorkbox.systemTray.MenuItem menuItem) { - super.setText(menuItem.getText()); - } - - @SuppressWarnings("Duplicates") - @Override - public - void setCallback(final dorkbox.systemTray.MenuItem menuItem) { - super.setCallback(menuItem.getCallback(), new ActionEvent(menuItem, ActionEvent.ACTION_PERFORMED, "")); - } - - @Override - public - void setShortcut(final dorkbox.systemTray.MenuItem menuItem) { -// char shortcut = menuItem.getShortcut(); -// // yikes... -// final int vKey = SwingUtil.getVirtualKey(shortcut); -// -// SwingUtil.invokeLater(new Runnable() { -// @Override -// public -// void run() { -// _native.setShortcut(new MenuShortcut(vKey)); -// } -// }); - } - - @SuppressWarnings("Duplicates") - @Override - public - void remove() { -// SwingUtil.invokeLater(new Runnable() { -// @Override -// public -// void run() { -// _native.deleteShortcut(); -// _native.setEnabled(false); -// -// if (swingCallback != null) { -// _native.removeActionListener(swingCallback); -// swingCallback = null; -// } -// parent._native.remove(_native); -// -// _native.removeNotify(); -// } -// }); - } -} diff --git a/src/dorkbox/systemTray/nativeUI/WindowsMenuItemCheckbox.java b/src/dorkbox/systemTray/nativeUI/WindowsMenuItemCheckbox.java deleted file mode 100644 index 811d957..0000000 --- a/src/dorkbox/systemTray/nativeUI/WindowsMenuItemCheckbox.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2017 dorkbox, llc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package dorkbox.systemTray.nativeUI; - -import java.awt.event.ActionListener; - -import dorkbox.systemTray.Checkbox; -import dorkbox.systemTray.peer.CheckboxPeer; - -class WindowsMenuItemCheckbox extends WindowsBaseMenuItem implements CheckboxPeer { - - private final WindowsMenu parent; - private final java.awt.CheckboxMenuItem _native = new java.awt.CheckboxMenuItem(); - - // these have to be volatile, because they can be changed from any thread - private volatile ActionListener callback; - private volatile boolean isChecked = false; - - // this is ALWAYS called on the EDT. - WindowsMenuItemCheckbox(final WindowsMenu parent) { - super(0); - this.parent = parent; -// parent._native.add(_native); - } - - @Override - public - void setEnabled(final Checkbox menuItem) { -// SwingUtil.invokeLater(new Runnable() { -// @Override -// public -// void run() { -// _native.setEnabled(menuItem.getEnabled()); -// } -// }); - } - - @Override - public - void setText(final Checkbox menuItem) { -// SwingUtil.invokeLater(new Runnable() { -// @Override -// public -// void run() { -// _native.setLabel(menuItem.getText()); -// } -// }); - } - - @SuppressWarnings("Duplicates") - @Override - public - void setCallback(final Checkbox menuItem) { -// if (callback != null) { -// _native.removeActionListener(callback); -// } -// -// callback = menuItem.getCallback(); // can be set to null -// -// if (callback != null) { -// callback = new ActionListener() { -// @Override -// public -// void actionPerformed(ActionEvent e) { -// // this will run on the EDT, since we are calling it from the EDT -// menuItem.setChecked(!isChecked); -// -// // we want it to run on the EDT, but with our own action event info (so it is consistent across all platforms) -// ActionListener cb = menuItem.getCallback(); -// if (cb != null) { -// try { -// cb.actionPerformed(new ActionEvent(menuItem, ActionEvent.ACTION_PERFORMED, "")); -// } catch (Throwable throwable) { -// SystemTray.logger.error("Error calling menu entry {} click event.", menuItem.getText(), throwable); -// } -// } -// } -// }; -// -// _native.addActionListener(callback); -// } - } - - @Override - public - void setShortcut(final Checkbox menuItem) { -// char shortcut = menuItem.getShortcut(); -// // yikes... -// final int vKey = SwingUtil.getVirtualKey(shortcut); -// -// SwingUtil.invokeLater(new Runnable() { -// @Override -// public -// void run() { -// _native.setShortcut(new MenuShortcut(vKey)); -// } -// }); - } - - @Override - public - void setChecked(final Checkbox menuItem) { -// boolean checked = menuItem.getChecked(); -// -// // only dispatch if it's actually different -// if (checked != this.isChecked) { -// this.isChecked = checked; -// -// SwingUtil.invokeLater(new Runnable() { -// @Override -// public -// void run() { -// _native.setState(isChecked); -// } -// }); -// } - } - - @SuppressWarnings("Duplicates") - @Override - public - void remove() { -// SwingUtil.invokeLater(new Runnable() { -// @Override -// public -// void run() { -// _native.deleteShortcut(); -// _native.setEnabled(false); -// -// if (callback != null) { -// _native.removeActionListener(callback); -// callback = null; -// } -// parent._native.remove(_native); -// -// _native.removeNotify(); -// } -// }); - } -} diff --git a/src/dorkbox/systemTray/nativeUI/WindowsMenuItemSeparator.java b/src/dorkbox/systemTray/nativeUI/WindowsMenuItemSeparator.java deleted file mode 100644 index 375c002..0000000 --- a/src/dorkbox/systemTray/nativeUI/WindowsMenuItemSeparator.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2017 dorkbox, llc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package dorkbox.systemTray.nativeUI; - - -import dorkbox.systemTray.peer.EntryPeer; - -class WindowsMenuItemSeparator extends WindowsBaseMenuItem implements EntryPeer { - - private final WindowsMenu parent; - private final java.awt.MenuItem _native = new java.awt.MenuItem("-"); - - - // this is ALWAYS called on the EDT. - WindowsMenuItemSeparator(final WindowsMenu parent) { - super(0); - this.parent = parent; -// parent._native.add(_native); - } - - @Override - public - void remove() { -// SwingUtil.invokeLater(new Runnable() { -// @Override -// public -// void run() { -// parent._native.remove(_native); -// } -// }); - } -} diff --git a/src/dorkbox/systemTray/nativeUI/WindowsMenuItemStatus.java b/src/dorkbox/systemTray/nativeUI/WindowsMenuItemStatus.java deleted file mode 100644 index c852605..0000000 --- a/src/dorkbox/systemTray/nativeUI/WindowsMenuItemStatus.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2017 dorkbox, llc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package dorkbox.systemTray.nativeUI; - -import java.awt.MenuItem; - -import dorkbox.systemTray.Status; -import dorkbox.systemTray.peer.StatusPeer; - -class WindowsMenuItemStatus extends WindowsBaseMenuItem implements StatusPeer { - - private final WindowsMenu parent; - private final MenuItem _native = new MenuItem(); - - WindowsMenuItemStatus(final WindowsMenu parent) { - super(0); - this.parent = parent; - - // status is ALWAYS at 0 index... -// parent._native.insert(_native, 0); - } - - @Override - public - void setText(final Status menuItem) { -// SwingUtil.invokeLater(new Runnable() { -// @Override -// public -// void run() { -// Font font = _native.getFont(); -// if (font == null) { -// font = new Font(DIALOG, Font.BOLD, 12); // the default font used for dialogs. -// } -// else { -// font = font.deriveFont(Font.BOLD); -// } -// -// _native.setFont(font); -// _native.setLabel(menuItem.getText()); -// -// // this makes sure it can't be selected -// _native.setEnabled(false); -// } -// }); - } - - @Override - public - void remove() { -// SwingUtil.invokeLater(new Runnable() { -// @Override -// public -// void run() { -// parent._native.remove(_native); -// } -// }); - } -} diff --git a/src/dorkbox/systemTray/nativeUI/_WindowsNativeTray.java b/src/dorkbox/systemTray/nativeUI/_WindowsNativeTray.java deleted file mode 100644 index c111cb9..0000000 --- a/src/dorkbox/systemTray/nativeUI/_WindowsNativeTray.java +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright 2017 dorkbox, llc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package dorkbox.systemTray.nativeUI; - -import static com.sun.jna.platform.win32.WinDef.HWND; -import static com.sun.jna.platform.win32.WinDef.LPARAM; -import static com.sun.jna.platform.win32.WinDef.POINT; -import static com.sun.jna.platform.win32.WinDef.WPARAM; -import static com.sun.jna.platform.win32.WinUser.WM_QUIT; -import static dorkbox.util.jna.windows.Shell32.NIM_ADD; -import static dorkbox.util.jna.windows.Shell32.NIM_DELETE; -import static dorkbox.util.jna.windows.Shell32.NIM_MODIFY; -import static dorkbox.util.jna.windows.Shell32.Shell_NotifyIcon; -import static dorkbox.util.jna.windows.User32.WM_LBUTTONUP; -import static dorkbox.util.jna.windows.User32.WM_RBUTTONUP; -import static dorkbox.util.jna.windows.WindowsEventDispatch.WM_SHELLNOTIFY; -import static dorkbox.util.jna.windows.WindowsEventDispatch.WM_TASKBARCREATED; - -import java.io.File; - -import javax.swing.ImageIcon; - -import dorkbox.systemTray.MenuItem; -import dorkbox.systemTray.SystemTray; -import dorkbox.systemTray.Tray; -import dorkbox.util.ImageUtil; -import dorkbox.util.jna.windows.HBITMAPWrap; -import dorkbox.util.jna.windows.HICONWrap; -import dorkbox.util.jna.windows.Kernel32; -import dorkbox.util.jna.windows.Listener; -import dorkbox.util.jna.windows.Shell32; -import dorkbox.util.jna.windows.User32; -import dorkbox.util.jna.windows.WindowsEventDispatch; -import dorkbox.util.jna.windows.structs.NOTIFYICONDATA; - - -/** - * Native implementation of a System tray on Windows, derivative of the original implementation by Nathan Sweet (BSD License). - */ -public -class _WindowsNativeTray extends Tray implements NativeUI { - private final Listener quitListener; - private final Listener menuListener; - - // is the system tray visible or not. - private volatile boolean visible = true; - - private volatile File imageFile; - private volatile HICONWrap imageIcon; - - private volatile String tooltipText = ""; - private final Listener showListener; - - public _WindowsNativeTray (final dorkbox.systemTray.SystemTray systemTray) { - super(); - - // we override various methods, because each tray implementation is SLIGHTLY different. This allows us customization. - final WindowsMenu windowsMenu = new WindowsMenu() { - @Override - public - void setEnabled(final MenuItem menuItem) { - boolean enabled = menuItem.getEnabled(); - - if (visible && !enabled) { - // hide - hide(); - } - else if (!visible && enabled) { - // show - show(); - } - } - - @Override - public - void setImage(final MenuItem menuItem) { - imageFile = menuItem.getImage(); - - if (imageIcon != null) { - imageIcon.close(); - } - imageIcon = convertImage(imageFile); - - NOTIFYICONDATA nid = new NOTIFYICONDATA(); - nid.hWnd = WindowsEventDispatch.get(); - nid.setIcon(imageIcon); - - if (!Shell32.Shell_NotifyIcon(NIM_MODIFY, nid)) { - SystemTray.logger.error("Error setting the image for the tray. {}", Kernel32.getLastErrorMessage()); - } - } - - @Override - public - void setText(final MenuItem menuItem) { - // no op. - } - - @Override - public - void setShortcut(final MenuItem menuItem) { - // no op - } - - @Override - public - void remove() { - hide(); - - super.remove(); - - User32.IMPL.PostMessage(WindowsEventDispatch.get(), WM_QUIT, new WPARAM(0), new LPARAM(0)); - } - }; - - // will wait until it's started up. - WindowsEventDispatch.start(); - - HWND hWnd = WindowsEventDispatch.get(); - if (hWnd == null) { - throw new RuntimeException("The Windows System Tray is not supported! Please write an issue and include your OS type and " + - "configuration"); - } - - showListener = new Listener() { - @Override - public - void run(final HWND hWnd, final WPARAM wParam, final LPARAM lParam) { - show(); - } - }; - quitListener = new Listener() { - @Override - public - void run(final HWND hWnd, final WPARAM wParam, final LPARAM lParam) { - System.err.println("quit listener"); - WindowsEventDispatch.stop(); - WindowsEventDispatch.removeListener(showListener); - WindowsEventDispatch.removeListener(quitListener); - WindowsEventDispatch.removeListener(menuListener); - } - }; - - - menuListener = new Listener() { - final POINT mousePosition = new POINT(); - - @Override - public - void run(final HWND hWnd, final WPARAM wParam, final LPARAM lParam) { - int lp = lParam.intValue(); - switch (lp) { - case WM_LBUTTONUP: - if (User32.IMPL.GetCursorPos(mousePosition)) { - windowsMenu.showContextMenu(mousePosition); - } - break; - case WM_RBUTTONUP: - if (User32.IMPL.GetCursorPos(mousePosition)) { - windowsMenu.showContextMenu(mousePosition); - } - break; - } - } - }; - - WindowsEventDispatch.addListener(WM_TASKBARCREATED, showListener); - WindowsEventDispatch.addListener(WM_QUIT, quitListener); - WindowsEventDispatch.addListener(WM_SHELLNOTIFY, menuListener); - - show(); - -// Runtime.getRuntime().addShutdownHook(new Thread() { -// @Override -// public void run () { -// Shell_NotifyIcon(NIM_DELETE, windowNotifyIconData); -// } -// }); - - bind(windowsMenu, null, systemTray); - } - -// public synchronized void balloon (String title, String message, int millis) { -// balloonNotifyIconData.hWnd = this.windowNotifyIconData.hWnd; -// balloonNotifyIconData.uID = this.windowNotifyIconData.uID; -// balloonNotifyIconData.setBalloon(title, message, millis, NIIF_NONE); -// Shell_NotifyIcon(NIM_MODIFY, balloonNotifyIconData); -// } - - - private void hide() { - if (imageIcon != null) { - imageIcon.close(); - imageIcon = null; - } - - NOTIFYICONDATA nid = new NOTIFYICONDATA(); - nid.hWnd = WindowsEventDispatch.get(); - - if (!Shell32.Shell_NotifyIcon(NIM_DELETE, nid)) { - SystemTray.logger.error("Error hiding tray. {}", Kernel32.getLastErrorMessage()); - } - visible = false; - } - - private void show() { - if (imageIcon != null) { - imageIcon.close(); - } - imageIcon = convertImage(imageFile); - - NOTIFYICONDATA nid = new NOTIFYICONDATA(); - nid.hWnd = WindowsEventDispatch.get(); - nid.setTooltip(tooltipText); - nid.setIcon(imageIcon); - nid.setCallback(WM_SHELLNOTIFY); - - if (!Shell_NotifyIcon(NIM_ADD, nid)) { - SystemTray.logger.error("Error showing tray. {}", Kernel32.getLastErrorMessage()); - } - visible = true; - } - - @Override - protected - void setTooltip_(final String tooltipText) { - if (this.tooltipText.equals(tooltipText)){ - return; - } - this.tooltipText = tooltipText; - - NOTIFYICONDATA nid = new NOTIFYICONDATA(); - nid.hWnd = WindowsEventDispatch.get(); - nid.setTooltip(tooltipText); - - Shell_NotifyIcon(NIM_MODIFY, nid); - } - - @Override - public - boolean hasImage() { - return imageFile != null; - } - - private static - HICONWrap convertImage(final File imageFile) { - if (imageFile != null) { - ImageIcon imageIcon = new ImageIcon(imageFile.getAbsolutePath()); - // fully loads the image and returns when it's done loading the image - imageIcon = new ImageIcon(imageIcon.getImage()); - - HBITMAPWrap hbitmapTrayIcon = new HBITMAPWrap(ImageUtil.getBufferedImage(imageIcon)); - return new HICONWrap(hbitmapTrayIcon); - } - - return null; - } -}