forked from dorkbox/SystemTray
WIP Windows Native implementation
This commit is contained in:
parent
8d97b90162
commit
787e16b4e0
29
src/dorkbox/systemTray/jna/windows/COLORREF.java
Normal file
29
src/dorkbox/systemTray/jna/windows/COLORREF.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows;
|
||||||
|
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.platform.win32.WinNT;
|
||||||
|
|
||||||
|
public class COLORREF extends WinNT.HANDLE {
|
||||||
|
public COLORREF() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public COLORREF(Pointer p) {
|
||||||
|
super(p);
|
||||||
|
}
|
||||||
|
}
|
148
src/dorkbox/systemTray/jna/windows/GDI32.java
Normal file
148
src/dorkbox/systemTray/jna/windows/GDI32.java
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows;
|
||||||
|
|
||||||
|
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.RECT;
|
||||||
|
import static com.sun.jna.platform.win32.WinGDI.BITMAPINFO;
|
||||||
|
import static com.sun.jna.platform.win32.WinNT.HANDLE;
|
||||||
|
|
||||||
|
import com.sun.jna.Native;
|
||||||
|
import com.sun.jna.NativeLibrary;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.platform.win32.WinUser;
|
||||||
|
import com.sun.jna.ptr.PointerByReference;
|
||||||
|
import com.sun.jna.win32.W32APIOptions;
|
||||||
|
|
||||||
|
import dorkbox.systemTray.jna.windows.structs.LOGFONT;
|
||||||
|
|
||||||
|
public
|
||||||
|
class GDI32 {
|
||||||
|
static {
|
||||||
|
Native.register(NativeLibrary.getInstance("GDI32", W32APIOptions.DEFAULT_OPTIONS));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final int ETO_OPAQUE = 2;
|
||||||
|
public static final int SRCCOPY = 0xCC0020;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/dd144938(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
public static native
|
||||||
|
boolean GetTextExtentPoint32(HDC hdc, String lpString, int c, WinUser.SIZE lpSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/dd145093(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
public static native
|
||||||
|
COLORREF SetTextColor(HDC hdc, COLORREF crColor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/dd162964(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
public static native
|
||||||
|
COLORREF SetBkColor(HDC hdc, COLORREF crColor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/dd162713(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
public static native
|
||||||
|
boolean ExtTextOut(HDC hdc, int X, int Y, int fuOptions, RECT lprc, String lpString, int cbCount, int[] lpDx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://msdn.microsoft.com/ru-ru/library/windows/desktop/dd183500(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
public static native
|
||||||
|
HFONT CreateFontIndirect(LOGFONT l);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SelectObject function selects an object into the specified device context (DC).
|
||||||
|
* The new object replaces the previous object of the same type.
|
||||||
|
*
|
||||||
|
* @param hDC Handle to the DC.
|
||||||
|
* @param hGDIObj Handle to the object to be selected.
|
||||||
|
*
|
||||||
|
* @return If the selected object is not a region and the function succeeds, the return value
|
||||||
|
* is a handle to the object being replaced. If the selected object is a region and the
|
||||||
|
* function succeeds, the return value is one of the REGION values.
|
||||||
|
*/
|
||||||
|
public static native
|
||||||
|
HANDLE SelectObject(HDC hDC, HANDLE hGDIObj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The CreateCompatibleDC function creates a memory device context (DC) compatible with the specified device.
|
||||||
|
*
|
||||||
|
* @param hDC Handle to an existing DC. If this handle is NULL, the function creates a memory DC compatible with the
|
||||||
|
* application's current screen.
|
||||||
|
*
|
||||||
|
* @return If the function succeeds, the return value is the handle to a memory DC.
|
||||||
|
* If the function fails, the return value is NULL.
|
||||||
|
* To get extended error information, call GetLastError.
|
||||||
|
*/
|
||||||
|
public static native
|
||||||
|
HDC CreateCompatibleDC(HDC hDC);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DeleteDC function deletes the specified device context (DC).
|
||||||
|
*
|
||||||
|
* @param hDC Handle to the device context.
|
||||||
|
*
|
||||||
|
* @return If the function succeeds, the return value is nonzero.
|
||||||
|
* If the function fails, the return value is zero.
|
||||||
|
* To get extended error information, call GetLastError.
|
||||||
|
*/
|
||||||
|
public static native
|
||||||
|
boolean DeleteDC(HDC hDC);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DeleteObject function deletes a logical pen, brush, font, bitmap, region, or palette,
|
||||||
|
* freeing all system resources associated with the object. After the object is deleted, the
|
||||||
|
* specified handle is no longer valid.
|
||||||
|
*
|
||||||
|
* @param hObject Handle to a logical pen, brush, font, bitmap, region, or palette.
|
||||||
|
*
|
||||||
|
* @return If the function succeeds, the return value is nonzero.
|
||||||
|
* If the specified handle is not valid or is currently selected into a DC, the return value is zero.
|
||||||
|
* To get extended error information, call GetLastError.
|
||||||
|
*/
|
||||||
|
public static native
|
||||||
|
boolean DeleteObject(HANDLE hObject);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The CreateDIBSection function creates a DIB that applications can write to directly.
|
||||||
|
* The function gives you a pointer to the location of the bitmap bit values. You can supply
|
||||||
|
* a handle to a file-mapping object that the function will use to create the bitmap, or you
|
||||||
|
* can let the system allocate the memory for the bitmap.
|
||||||
|
*
|
||||||
|
* @param hDC Handle to a device context. If the value of iUsage is DIB_PAL_COLORS, the function uses this
|
||||||
|
* device context's logical palette to initialize the DIB colors.
|
||||||
|
* @param pbmi Pointer to a BITMAPINFO structure that specifies various attributes of the DIB, including
|
||||||
|
* the bitmap dimensions and colors.
|
||||||
|
* @param iUsage Specifies the type of data contained in the bmiColors array member of the BITMAPINFO structure
|
||||||
|
* pointed to by pbmi (either logical palette indexes or literal RGB values).
|
||||||
|
* @param ppvBits Pointer to a variable that receives a pointer to the location of the DIB bit values.
|
||||||
|
* @param hSection Handle to a file-mapping object that the function will use to create the DIB. This parameter can be NULL.
|
||||||
|
* @param dwOffset Specifies the offset from the beginning of the file-mapping object referenced by hSection where storage
|
||||||
|
* for the bitmap bit values is to begin.
|
||||||
|
*
|
||||||
|
* @return Specifies the offset from the beginning of the file-mapping object referenced by hSection where storage
|
||||||
|
* for the bitmap bit values is to begin.
|
||||||
|
*/
|
||||||
|
public static native
|
||||||
|
HBITMAP CreateDIBSection(HDC hDC, BITMAPINFO pbmi, int iUsage, PointerByReference ppvBits, Pointer hSection, int dwOffset);
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows;
|
||||||
|
|
||||||
|
public
|
||||||
|
class GetLastErrorException extends RuntimeException {
|
||||||
|
private static final long serialVersionUID = 3980497906900380359L;
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public
|
||||||
|
GetLastErrorException() {
|
||||||
|
message = Kernel32.getLastErrorMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public
|
||||||
|
String toString() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
104
src/dorkbox/systemTray/jna/windows/HBITMAPWrap.java
Normal file
104
src/dorkbox/systemTray/jna/windows/HBITMAPWrap.java
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows;
|
||||||
|
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.HBITMAP;
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.HDC;
|
||||||
|
|
||||||
|
import java.awt.AlphaComposite;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.Raster;
|
||||||
|
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.platform.win32.WinGDI;
|
||||||
|
import com.sun.jna.ptr.PointerByReference;
|
||||||
|
|
||||||
|
public class HBITMAPWrap extends HBITMAP {
|
||||||
|
|
||||||
|
// https://github.com/twall/jna/blob/master/contrib/alphamaskdemo/com/sun/jna/contrib/demo/AlphaMaskDemo.java
|
||||||
|
private static
|
||||||
|
HBITMAP createBitmap(BufferedImage image) {
|
||||||
|
int w = image.getWidth(null);
|
||||||
|
int h = image.getHeight(null);
|
||||||
|
HDC screenDC = User32.IMPL.GetDC(null);
|
||||||
|
HDC memDC = GDI32.CreateCompatibleDC(screenDC);
|
||||||
|
HBITMAP hBitmap = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
BufferedImage buf = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE);
|
||||||
|
Graphics2D g = (Graphics2D) buf.getGraphics();
|
||||||
|
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
|
||||||
|
g.drawImage(image, 0, 0, w, h, null);
|
||||||
|
|
||||||
|
WinGDI.BITMAPINFO bmi = new WinGDI.BITMAPINFO();
|
||||||
|
bmi.bmiHeader.biWidth = w;
|
||||||
|
bmi.bmiHeader.biHeight = h;
|
||||||
|
bmi.bmiHeader.biPlanes = 1;
|
||||||
|
bmi.bmiHeader.biBitCount = 32;
|
||||||
|
bmi.bmiHeader.biCompression = WinGDI.BI_RGB;
|
||||||
|
bmi.bmiHeader.biSizeImage = w * h * 4;
|
||||||
|
|
||||||
|
PointerByReference ppbits = new PointerByReference();
|
||||||
|
hBitmap = GDI32.CreateDIBSection(memDC, bmi, WinGDI.DIB_RGB_COLORS, ppbits, null, 0);
|
||||||
|
Pointer pbits = ppbits.getValue();
|
||||||
|
|
||||||
|
Raster raster = buf.getData();
|
||||||
|
int[] pixel = new int[4];
|
||||||
|
int[] bits = new int[w * h];
|
||||||
|
for (int y = 0; y < h; y++) {
|
||||||
|
for (int x = 0; x < w; x++) {
|
||||||
|
raster.getPixel(x, h - y - 1, pixel);
|
||||||
|
int red = (pixel[2] & 0xFF) << 0;
|
||||||
|
int green = (pixel[1] & 0xFF) << 8;
|
||||||
|
int blue = (pixel[0] & 0xFF) << 16;
|
||||||
|
int alpha = (pixel[3] & 0xFF) << 24;
|
||||||
|
bits[x + y * w] = alpha | red | green | blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pbits.write(0, bits, 0, bits.length);
|
||||||
|
return hBitmap;
|
||||||
|
} finally {
|
||||||
|
User32.IMPL.ReleaseDC(null, screenDC);
|
||||||
|
GDI32.DeleteDC(memDC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferedImage img;
|
||||||
|
|
||||||
|
public HBITMAPWrap(BufferedImage img) {
|
||||||
|
setPointer(createBitmap(img).getPointer());
|
||||||
|
|
||||||
|
this.img = img;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finalize() throws Throwable {
|
||||||
|
close();
|
||||||
|
super.finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
if (Pointer.nativeValue(getPointer()) != 0) {
|
||||||
|
GDI32.DeleteObject(this);
|
||||||
|
setPointer(new Pointer(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferedImage getImage() {
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
}
|
72
src/dorkbox/systemTray/jna/windows/HICONWrap.java
Normal file
72
src/dorkbox/systemTray/jna/windows/HICONWrap.java
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows;
|
||||||
|
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.HBITMAP;
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.HICON;
|
||||||
|
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
|
import dorkbox.systemTray.jna.windows.structs.ICONINFO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://www.pinvoke.net/default.aspx/user32.createiconindirect
|
||||||
|
*/
|
||||||
|
public class HICONWrap extends HICON {
|
||||||
|
|
||||||
|
static HICON createIconIndirect(HBITMAP bm) {
|
||||||
|
ICONINFO info = new ICONINFO();
|
||||||
|
info.IsIcon = true;
|
||||||
|
info.MaskBitmap = bm;
|
||||||
|
info.ColorBitmap = bm;
|
||||||
|
|
||||||
|
HICON hicon = User32.IMPL.CreateIconIndirect(info);
|
||||||
|
if (hicon == null) {
|
||||||
|
throw new GetLastErrorException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return hicon;
|
||||||
|
}
|
||||||
|
|
||||||
|
private HBITMAPWrap bm;
|
||||||
|
|
||||||
|
public HICONWrap() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public HICONWrap(Pointer p) {
|
||||||
|
super(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HICONWrap(HBITMAPWrap bm) {
|
||||||
|
this.bm = bm;
|
||||||
|
setPointer(createIconIndirect(bm).getPointer());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
bm.close();
|
||||||
|
|
||||||
|
if (Pointer.nativeValue(getPointer()) != 0) {
|
||||||
|
GDI32.DeleteObject(this);
|
||||||
|
setPointer(new Pointer(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finalize() throws Throwable {
|
||||||
|
close();
|
||||||
|
super.finalize();
|
||||||
|
}
|
||||||
|
}
|
43
src/dorkbox/systemTray/jna/windows/Kernel32.java
Normal file
43
src/dorkbox/systemTray/jna/windows/Kernel32.java
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows;
|
||||||
|
|
||||||
|
import com.sun.jna.Memory;
|
||||||
|
import com.sun.jna.ptr.PointerByReference;
|
||||||
|
|
||||||
|
public
|
||||||
|
class Kernel32 {
|
||||||
|
public static
|
||||||
|
String getLastErrorMessage() {
|
||||||
|
// has to be Kernel32.INSTANCE, otherwise it will crash the JVM
|
||||||
|
int hresult = com.sun.jna.platform.win32.Kernel32.INSTANCE.GetLastError();
|
||||||
|
if (hresult == 0) {
|
||||||
|
return "HRESULT: 0x0 [No Error]";
|
||||||
|
} else {
|
||||||
|
Memory memory = new Memory(1024);
|
||||||
|
PointerByReference reference = new PointerByReference(memory);
|
||||||
|
|
||||||
|
// Must be Kernel32.INSTANCE because of how it pulls in variety arguments.
|
||||||
|
com.sun.jna.platform.win32.Kernel32.INSTANCE.FormatMessage(com.sun.jna.platform.win32.Kernel32.FORMAT_MESSAGE_FROM_SYSTEM, null, hresult, 0, reference, (int) memory.size(), null);
|
||||||
|
|
||||||
|
String memoryMessage = reference.getPointer()
|
||||||
|
.getString(0, true);
|
||||||
|
memoryMessage = memoryMessage.trim();
|
||||||
|
|
||||||
|
return String.format("HRESULT: 0x%08x [%s]", hresult, memoryMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
src/dorkbox/systemTray/jna/windows/Listener.java
Normal file
28
src/dorkbox/systemTray/jna/windows/Listener.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows;
|
||||||
|
|
||||||
|
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.WPARAM;
|
||||||
|
|
||||||
|
public
|
||||||
|
class Listener {
|
||||||
|
public
|
||||||
|
void run(HWND hWnd, WPARAM wParam, LPARAM lParam) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
39
src/dorkbox/systemTray/jna/windows/MSG.java
Normal file
39
src/dorkbox/systemTray/jna/windows/MSG.java
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
|
||||||
|
public
|
||||||
|
class MSG extends Structure {
|
||||||
|
public Pointer hWnd;
|
||||||
|
public int message;
|
||||||
|
public Parameter wParam;
|
||||||
|
public Parameter lParam;
|
||||||
|
public int time;
|
||||||
|
public int x;
|
||||||
|
public int y;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
List getFieldOrder() {
|
||||||
|
return Arrays.asList("hWnd", "message", "wParam", "lParam", "time", "x", "y");
|
||||||
|
}
|
||||||
|
}
|
40
src/dorkbox/systemTray/jna/windows/MsImg32.java
Normal file
40
src/dorkbox/systemTray/jna/windows/MsImg32.java
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows;
|
||||||
|
|
||||||
|
import com.sun.jna.Native;
|
||||||
|
import com.sun.jna.NativeLibrary;
|
||||||
|
import com.sun.jna.platform.win32.WinDef;
|
||||||
|
import com.sun.jna.win32.W32APIOptions;
|
||||||
|
|
||||||
|
import dorkbox.systemTray.jna.windows.structs.BLENDFUNCTION;
|
||||||
|
|
||||||
|
public
|
||||||
|
class MsImg32 {
|
||||||
|
static {
|
||||||
|
Native.register(NativeLibrary.getInstance("Msimg32", W32APIOptions.DEFAULT_OPTIONS));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final int ETO_OPAQUE = 2;
|
||||||
|
public static final int SRCCOPY = 0xCC0020;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/dd183351(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
public static native
|
||||||
|
boolean AlphaBlend(WinDef.HDC hdcDest, int xoriginDest, int yoriginDest, int wDest, int hDest, WinDef.HDC hdcSrc, int xoriginSrc,
|
||||||
|
int yoriginSrc, int wSrc, int hSrc, BLENDFUNCTION.ByValue ftn);
|
||||||
|
}
|
17
src/dorkbox/systemTray/jna/windows/Parameter.java
Normal file
17
src/dorkbox/systemTray/jna/windows/Parameter.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package dorkbox.systemTray.jna.windows;
|
||||||
|
|
||||||
|
import com.sun.jna.IntegerType;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
|
public
|
||||||
|
class Parameter extends IntegerType {
|
||||||
|
public
|
||||||
|
Parameter() {
|
||||||
|
this(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public
|
||||||
|
Parameter(long value) {
|
||||||
|
super(Pointer.SIZE, value);
|
||||||
|
}
|
||||||
|
}
|
36
src/dorkbox/systemTray/jna/windows/Shell32.java
Normal file
36
src/dorkbox/systemTray/jna/windows/Shell32.java
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows;
|
||||||
|
|
||||||
|
import com.sun.jna.Native;
|
||||||
|
import com.sun.jna.NativeLibrary;
|
||||||
|
import com.sun.jna.win32.W32APIOptions;
|
||||||
|
|
||||||
|
import dorkbox.systemTray.jna.windows.structs.NOTIFYICONDATA;
|
||||||
|
|
||||||
|
public
|
||||||
|
class Shell32 {
|
||||||
|
static {
|
||||||
|
Native.register(NativeLibrary.getInstance("shell32", W32APIOptions.DEFAULT_OPTIONS));
|
||||||
|
}
|
||||||
|
|
||||||
|
static public final int NIM_ADD = 0x0;
|
||||||
|
static public final int NIM_MODIFY = 0x1;
|
||||||
|
static public final int NIM_DELETE = 0x2;
|
||||||
|
|
||||||
|
public static native
|
||||||
|
boolean Shell_NotifyIcon(int dwMessage, NOTIFYICONDATA lpdata);
|
||||||
|
}
|
239
src/dorkbox/systemTray/jna/windows/User32.java
Normal file
239
src/dorkbox/systemTray/jna/windows/User32.java
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows;
|
||||||
|
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.HDC;
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.HICON;
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.HINSTANCE;
|
||||||
|
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.LRESULT;
|
||||||
|
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 com.sun.jna.Callback;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.WString;
|
||||||
|
import com.sun.jna.platform.win32.WinNT;
|
||||||
|
|
||||||
|
import dorkbox.systemTray.jna.windows.structs.ICONINFO;
|
||||||
|
import dorkbox.systemTray.jna.windows.structs.MENUITEMINFO;
|
||||||
|
import dorkbox.systemTray.jna.windows.structs.NONCLIENTMETRICS;
|
||||||
|
import dorkbox.util.OS;
|
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
public
|
||||||
|
interface User32 {
|
||||||
|
User32 IMPL = OS.is64bit() ? new User32_64() : new User32_32();
|
||||||
|
|
||||||
|
int WM_QUIT = 18;
|
||||||
|
|
||||||
|
int SPI_GETNONCLIENTMETRICS = 0x0029;
|
||||||
|
int COLOR_MENU = 4;
|
||||||
|
int COLOR_MENUTEXT = 7;
|
||||||
|
int COLOR_HIGHLIGHTTEXT = 14;
|
||||||
|
int COLOR_HIGHLIGHT = 13;
|
||||||
|
int COLOR_GRAYTEXT = 17;
|
||||||
|
|
||||||
|
int GWL_WNDPROC = -4;
|
||||||
|
|
||||||
|
int WM_LBUTTONUP = 0x202;
|
||||||
|
int WM_RBUTTONUP = 0x205;
|
||||||
|
|
||||||
|
int MF_BYPOSITION = 0x400;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is overridden by the 64-bit version to be SetWindowLongPtr instead.
|
||||||
|
*/
|
||||||
|
int SetWindowLong(HWND hWnd, int nIndex, Callback procedure);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms647626(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
HMENU CreatePopupMenu();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms647616(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
boolean AppendMenu(HMENU hMenu, int uFlags, int uIDNewItem, String lpNewItem);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://msdn.microsoft.com/en-us/library/windows/desktop/ms647629(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
boolean DeleteMenu(HMENU hMenu, int uPosition, int uFlags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms647631(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
boolean DestroyMenu(HMENU hMenu);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms648002(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
boolean TrackPopupMenu(HMENU hMenu, int uFlags, int x, int y, int nReserved, HWND hWnd, RECT prcRect);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms648001(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
boolean SetMenuItemInfo(HMENU hMenu, int uItem, boolean fByPosition, MENUITEMINFO lpmii);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms647980(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
boolean GetMenuItemInfo(HMENU hMenu, int uItem, boolean fByPosition, MENUITEMINFO lpmii);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Brings the thread that created the specified window into the foreground
|
||||||
|
* and activates the window. Keyboard input is directed to the window, and
|
||||||
|
* various visual cues are changed for the user. The system assigns a
|
||||||
|
* slightly higher priority to the thread that created the foreground window
|
||||||
|
* than it does to other threads.
|
||||||
|
*
|
||||||
|
* @param hWnd A handle to the window that should be activated and brought to
|
||||||
|
* the foreground.
|
||||||
|
*
|
||||||
|
* @return If the window was brought to the foreground, the return value is
|
||||||
|
* nonzero.
|
||||||
|
*/
|
||||||
|
boolean SetForegroundWindow(HWND hWnd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The GetSystemMetrics function retrieves various system metrics (widths
|
||||||
|
* and heights of display elements) and system configuration settings. All
|
||||||
|
* dimensions retrieved by GetSystemMetrics are in pixels.
|
||||||
|
*
|
||||||
|
* @param nIndex System metric or configuration setting to retrieve. This
|
||||||
|
* parameter can be one of the following values. Note that all
|
||||||
|
* SM_CX* values are widths and all SM_CY* values are heights.
|
||||||
|
* Also note that all settings designed to return Boolean data
|
||||||
|
* represent TRUE as any nonzero value, and FALSE as a zero
|
||||||
|
* value.
|
||||||
|
*
|
||||||
|
* @return If the function succeeds, the return value is the requested
|
||||||
|
* system metric or configuration setting. If the function fails,
|
||||||
|
* the return value is zero. GetLastError does not provide extended
|
||||||
|
* error information.
|
||||||
|
*/
|
||||||
|
int GetSystemMetrics(int nIndex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms633500(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
HWND FindWindowEx(HWND hwndParent, HWND hwndChildAfter, String lpszClass, String lpszWindow);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms644950(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
LRESULT SendMessage(HWND hWnd, int Msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms648062(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
HICON CreateIconIndirect(ICONINFO piconinfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms632682(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
boolean DestroyWindow(HWND hWnd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms724947(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
boolean SystemParametersInfo(int uiAction, int uiParam, NONCLIENTMETRICS pvParam, int fWinIni);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms724371(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
COLORREF GetSysColor(int nIndex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function places a message in the message queue associated with the
|
||||||
|
* thread that created the specified window and then returns without waiting
|
||||||
|
* for the thread to process the message. Messages in a message queue are
|
||||||
|
* retrieved by calls to the GetMessage or PeekMessage function.
|
||||||
|
*
|
||||||
|
* @param hWnd Handle to the window whose window procedure is to receive the
|
||||||
|
* message.
|
||||||
|
* @param msg Specifies the message to be posted.
|
||||||
|
* @param wParam Specifies additional message-specific information.
|
||||||
|
* @param lParam Specifies additional message-specific information.
|
||||||
|
*/
|
||||||
|
void PostMessage(HWND hWnd, int msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms632680(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
HWND CreateWindowEx(int dwExStyle,
|
||||||
|
String lpClassName,
|
||||||
|
String lpWindowName,
|
||||||
|
int dwStyle,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
int nWidth,
|
||||||
|
int nHeight,
|
||||||
|
HWND hWndParent,
|
||||||
|
HMENU hMenu,
|
||||||
|
HINSTANCE hInstance,
|
||||||
|
WinNT.HANDLE lpParam);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms644947(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
LRESULT DefWindowProc(HWND hWnd, int Msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
|
||||||
|
boolean GetMessage(MSG lpMsg, Pointer hWnd, int wMsgFilterMin, int wMsgFilterMax);
|
||||||
|
|
||||||
|
boolean TranslateMessage(MSG lpMsg);
|
||||||
|
|
||||||
|
boolean DispatchMessage(MSG lpMsg);
|
||||||
|
|
||||||
|
int RegisterWindowMessage(WString lpString);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function retrieves a handle to a display device context (DC) for the
|
||||||
|
* client area of the specified window. The display device context can be
|
||||||
|
* used in subsequent graphics display interface (GDI) functions to draw in
|
||||||
|
* the client area of the window.
|
||||||
|
*
|
||||||
|
* @param hWnd Handle to the window whose device context is to be retrieved.
|
||||||
|
* If this value is NULL, GetDC retrieves the device context for
|
||||||
|
* the entire screen.
|
||||||
|
*
|
||||||
|
* @return The handle the device context for the specified window's client
|
||||||
|
* area indicates success. NULL indicates failure. To get extended
|
||||||
|
* error information, call GetLastError.
|
||||||
|
*/
|
||||||
|
HDC GetDC(HWND hWnd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function releases a device context (DC), freeing it for use by other
|
||||||
|
* applications. The effect of ReleaseDC depends on the type of device
|
||||||
|
* context.
|
||||||
|
*
|
||||||
|
* @param hWnd Handle to the window whose device context is to be released.
|
||||||
|
* @param hDC Handle to the device context to be released.
|
||||||
|
*
|
||||||
|
* @return The return value specifies whether the device context is
|
||||||
|
* released. 1 indicates that the device context is released. Zero
|
||||||
|
* indicates that the device context is not released.
|
||||||
|
*/
|
||||||
|
int ReleaseDC(HWND hWnd, HDC hDC);
|
||||||
|
|
||||||
|
boolean GetCursorPos(POINT point);
|
||||||
|
}
|
175
src/dorkbox/systemTray/jna/windows/User32_32.java
Normal file
175
src/dorkbox/systemTray/jna/windows/User32_32.java
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows;
|
||||||
|
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.HDC;
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.HICON;
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.HINSTANCE;
|
||||||
|
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.LRESULT;
|
||||||
|
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 com.sun.jna.Callback;
|
||||||
|
import com.sun.jna.Native;
|
||||||
|
import com.sun.jna.NativeLibrary;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.WString;
|
||||||
|
import com.sun.jna.platform.win32.WinNT;
|
||||||
|
import com.sun.jna.win32.W32APIOptions;
|
||||||
|
|
||||||
|
import dorkbox.systemTray.jna.windows.structs.ICONINFO;
|
||||||
|
import dorkbox.systemTray.jna.windows.structs.MENUITEMINFO;
|
||||||
|
import dorkbox.systemTray.jna.windows.structs.NONCLIENTMETRICS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On first glance, this appears to be unnecessary to have a DirectMapping class implement an interface - however this is so different
|
||||||
|
* methods can be overridden by the correct 64bit versions, otherwise multiple copies of this library would have to be loaded (one for
|
||||||
|
* "normal", and another for the "special case").
|
||||||
|
*
|
||||||
|
* Doing it this way greatly simplifies the API while maintaining Direct Mapping, at the cost of a slightly more complex code hierarchy.
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
class User32_32 implements User32 {
|
||||||
|
static {
|
||||||
|
Native.register(NativeLibrary.getInstance("user32", W32APIOptions.DEFAULT_OPTIONS));
|
||||||
|
}
|
||||||
|
|
||||||
|
// is replaced by the 64bit version
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
int SetWindowLong(HWND hWnd, int nIndex, Callback procedure);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
HMENU CreatePopupMenu();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean AppendMenu(final HMENU hMenu, final int uFlags, final int uIDNewItem, final String lpNewItem);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean DeleteMenu(final HMENU hMenu, final int uPosition, final int uFlags);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean DestroyMenu(final HMENU hMenu);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean TrackPopupMenu(final HMENU hMenu,
|
||||||
|
final int uFlags,
|
||||||
|
final int x,
|
||||||
|
final int y,
|
||||||
|
final int nReserved,
|
||||||
|
final HWND hWnd,
|
||||||
|
final RECT prcRect);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean SetMenuItemInfo(final HMENU hMenu, final int uItem, final boolean fByPosition, final MENUITEMINFO lpmii);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean GetMenuItemInfo(final HMENU hMenu, final int uItem, final boolean fByPosition, final MENUITEMINFO lpmii);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean SetForegroundWindow(final HWND hWnd);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
int GetSystemMetrics(final int nIndex);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
HWND FindWindowEx(final HWND hwndParent, final HWND hwndChildAfter, final String lpszClass, final String lpszWindow);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
LRESULT SendMessage(final HWND hWnd, final int Msg, final WPARAM wParam, final LPARAM lParam);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
HICON CreateIconIndirect(final ICONINFO piconinfo);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean DestroyWindow(final HWND hWnd);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean SystemParametersInfo(final int uiAction, final int uiParam, final NONCLIENTMETRICS pvParam, final int fWinIni);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
COLORREF GetSysColor(final int nIndex);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void PostMessage(final HWND hWnd, final int msg, final WPARAM wParam, final LPARAM lParam);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
HWND CreateWindowEx(final int dwExStyle,
|
||||||
|
final String lpClassName,
|
||||||
|
final String lpWindowName,
|
||||||
|
final int dwStyle,
|
||||||
|
final int x,
|
||||||
|
final int y,
|
||||||
|
final int nWidth,
|
||||||
|
final int nHeight,
|
||||||
|
final HWND hWndParent,
|
||||||
|
final HMENU hMenu,
|
||||||
|
final HINSTANCE hInstance,
|
||||||
|
final WinNT.HANDLE lpParam);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
LRESULT DefWindowProc(final HWND hWnd, final int Msg, final WPARAM wParam, final LPARAM lParam);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean GetMessage(final MSG lpMsg, final Pointer hWnd, final int wMsgFilterMin, final int wMsgFilterMax);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean TranslateMessage(final MSG lpMsg);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean DispatchMessage(final MSG lpMsg);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
int RegisterWindowMessage(final WString lpString);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
HDC GetDC(final HWND hWnd);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
int ReleaseDC(final HWND hWnd, final HDC hDC);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean GetCursorPos(final POINT point);
|
||||||
|
}
|
173
src/dorkbox/systemTray/jna/windows/User32_64.java
Normal file
173
src/dorkbox/systemTray/jna/windows/User32_64.java
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows;
|
||||||
|
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.HMENU;
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.HWND;
|
||||||
|
|
||||||
|
import com.sun.jna.Callback;
|
||||||
|
import com.sun.jna.Native;
|
||||||
|
import com.sun.jna.NativeLibrary;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.WString;
|
||||||
|
import com.sun.jna.platform.win32.WinDef;
|
||||||
|
import com.sun.jna.platform.win32.WinNT;
|
||||||
|
import com.sun.jna.win32.W32APIOptions;
|
||||||
|
|
||||||
|
import dorkbox.systemTray.jna.windows.structs.ICONINFO;
|
||||||
|
import dorkbox.systemTray.jna.windows.structs.MENUITEMINFO;
|
||||||
|
import dorkbox.systemTray.jna.windows.structs.NONCLIENTMETRICS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On first glance, this appears to be unnecessary to have a DirectMapping class implement an interface - however this is so different
|
||||||
|
* methods can be overridden by the correct 64bit versions, otherwise multiple copies of this library would have to be loaded (one for
|
||||||
|
* "normal", and another for the "special case").
|
||||||
|
*
|
||||||
|
* Doing it this way greatly simplifies the API while maintaining Direct Mapping, at the cost of a slightly more complex code hierarchy.
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
class User32_64 implements User32 {
|
||||||
|
static {
|
||||||
|
Native.register(NativeLibrary.getInstance("user32", W32APIOptions.DEFAULT_OPTIONS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
int SetWindowLong(HWND hWnd, int nIndex, Callback procedure) {
|
||||||
|
return SetWindowLongPtr(hWnd, nIndex, procedure);
|
||||||
|
}
|
||||||
|
|
||||||
|
// should be used instead of SetWindowLong for 64 versions
|
||||||
|
public native
|
||||||
|
int SetWindowLongPtr(HWND hWnd, int nIndex, Callback procedure);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
HMENU CreatePopupMenu();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean AppendMenu(final HMENU hMenu, final int uFlags, final int uIDNewItem, final String lpNewItem);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean DeleteMenu(final HMENU hMenu, final int uPosition, final int uFlags);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean DestroyMenu(final HMENU hMenu);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean TrackPopupMenu(final HMENU hMenu,
|
||||||
|
final int uFlags,
|
||||||
|
final int x,
|
||||||
|
final int y,
|
||||||
|
final int nReserved,
|
||||||
|
final HWND hWnd,
|
||||||
|
final WinDef.RECT prcRect);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean SetMenuItemInfo(final HMENU hMenu, final int uItem, final boolean fByPosition, final MENUITEMINFO lpmii);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean GetMenuItemInfo(final HMENU hMenu, final int uItem, final boolean fByPosition, final MENUITEMINFO lpmii);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean SetForegroundWindow(final HWND hWnd);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
int GetSystemMetrics(final int nIndex);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
HWND FindWindowEx(final HWND hwndParent, final HWND hwndChildAfter, final String lpszClass, final String lpszWindow);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
WinDef.LRESULT SendMessage(final HWND hWnd, final int Msg, final WinDef.WPARAM wParam, final WinDef.LPARAM lParam);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
WinDef.HICON CreateIconIndirect(final ICONINFO piconinfo);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean DestroyWindow(final HWND hWnd);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean SystemParametersInfo(final int uiAction, final int uiParam, final NONCLIENTMETRICS pvParam, final int fWinIni);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
COLORREF GetSysColor(final int nIndex);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void PostMessage(final HWND hWnd, final int msg, final WinDef.WPARAM wParam, final WinDef.LPARAM lParam);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
HWND CreateWindowEx(final int dwExStyle,
|
||||||
|
final String lpClassName,
|
||||||
|
final String lpWindowName,
|
||||||
|
final int dwStyle,
|
||||||
|
final int x,
|
||||||
|
final int y,
|
||||||
|
final int nWidth,
|
||||||
|
final int nHeight,
|
||||||
|
final HWND hWndParent,
|
||||||
|
final HMENU hMenu,
|
||||||
|
final WinDef.HINSTANCE hInstance,
|
||||||
|
final WinNT.HANDLE lpParam);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
WinDef.LRESULT DefWindowProc(final HWND hWnd, final int Msg, final WinDef.WPARAM wParam, final WinDef.LPARAM lParam);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean GetMessage(final MSG lpMsg, final Pointer hWnd, final int wMsgFilterMin, final int wMsgFilterMax);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean TranslateMessage(final MSG lpMsg);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean DispatchMessage(final MSG lpMsg);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
int RegisterWindowMessage(final WString lpString);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
WinDef.HDC GetDC(final HWND hWnd);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
int ReleaseDC(final HWND hWnd, final WinDef.HDC hDC);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean GetCursorPos(final WinDef.POINT point);
|
||||||
|
}
|
28
src/dorkbox/systemTray/jna/windows/WNDPROC.java
Normal file
28
src/dorkbox/systemTray/jna/windows/WNDPROC.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows;
|
||||||
|
|
||||||
|
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.LRESULT;
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.WPARAM;
|
||||||
|
|
||||||
|
import com.sun.jna.win32.StdCallLibrary;
|
||||||
|
|
||||||
|
public
|
||||||
|
interface WNDPROC extends StdCallLibrary.StdCallCallback {
|
||||||
|
LRESULT callback(HWND hWnd, int uMsg, WPARAM uParam, LPARAM lParam);
|
||||||
|
}
|
207
src/dorkbox/systemTray/jna/windows/WindowsEventDispatch.java
Normal file
207
src/dorkbox/systemTray/jna/windows/WindowsEventDispatch.java
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows;
|
||||||
|
|
||||||
|
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.LRESULT;
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.WPARAM;
|
||||||
|
import static com.sun.jna.platform.win32.WinUser.WM_USER;
|
||||||
|
import static dorkbox.systemTray.jna.windows.User32.GWL_WNDPROC;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.sun.jna.WString;
|
||||||
|
|
||||||
|
import dorkbox.systemTray.SystemTray;
|
||||||
|
|
||||||
|
@SuppressWarnings({"Convert2Lambda", "UnusedAssignment", "Convert2Diamond", "FieldCanBeLocal"})
|
||||||
|
public
|
||||||
|
class WindowsEventDispatch implements Runnable {
|
||||||
|
private static final String NAME = "WindowsEventDispatch";
|
||||||
|
|
||||||
|
|
||||||
|
public static final int WM_TASKBARCREATED = User32.IMPL.RegisterWindowMessage(new WString("TaskbarCreated"));
|
||||||
|
public static final int WM_COMMAND = 0x0111;
|
||||||
|
public static final int WM_SHELLNOTIFY = WM_USER + 1;
|
||||||
|
public static final int WM_MEASUREITEM = 44;
|
||||||
|
public static final int WM_DRAWITEM = 43;
|
||||||
|
|
||||||
|
public static final int MF_POPUP = 0x00000010;
|
||||||
|
|
||||||
|
|
||||||
|
private static final WindowsEventDispatch edt = new WindowsEventDispatch();
|
||||||
|
private final static Map<Integer, List<Listener>> messageIDs = new HashMap<Integer, List<Listener>>();
|
||||||
|
|
||||||
|
private static final Object lock = new Object();
|
||||||
|
private static int referenceCount = 0;
|
||||||
|
|
||||||
|
|
||||||
|
private Thread dispatchThread;
|
||||||
|
|
||||||
|
// keep these around to prevent GC
|
||||||
|
private WNDPROC WndProc;
|
||||||
|
|
||||||
|
// used to dispatch messages
|
||||||
|
private volatile HWND hWnd;
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
WindowsEventDispatch() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static
|
||||||
|
void start() {
|
||||||
|
synchronized (lock) {
|
||||||
|
int ref = referenceCount++;
|
||||||
|
|
||||||
|
if (ref == 0) {
|
||||||
|
edt.start_();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// wait for the dispatch thread to start
|
||||||
|
lock.wait();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static
|
||||||
|
void stop() {
|
||||||
|
synchronized (lock) {
|
||||||
|
if (--referenceCount == 0) {
|
||||||
|
edt.stop_();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static
|
||||||
|
HWND get() {
|
||||||
|
return edt.hWnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// always from inside lock!
|
||||||
|
private
|
||||||
|
void start_() {
|
||||||
|
dispatchThread = new Thread(this, NAME);
|
||||||
|
dispatchThread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// always from inside lock!
|
||||||
|
private void
|
||||||
|
stop_() {
|
||||||
|
WPARAM wparam = new WPARAM(0);
|
||||||
|
LPARAM lparam = new LPARAM(0);
|
||||||
|
User32.IMPL.SendMessage(hWnd, User32.WM_QUIT, wparam, lparam);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// wait for the dispatch thread to quit (but only if we are not on the dispatch thread)
|
||||||
|
if (!Thread.currentThread().equals(dispatchThread)) {
|
||||||
|
dispatchThread.join();
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("Java8MapApi")
|
||||||
|
public static
|
||||||
|
void addListener(final int messageId, final Listener listener) {
|
||||||
|
synchronized (messageIDs) {
|
||||||
|
List<Listener> listeners = messageIDs.get(messageId);
|
||||||
|
if (listeners == null) {
|
||||||
|
listeners = new ArrayList<Listener>();
|
||||||
|
messageIDs.put(messageId, listeners);
|
||||||
|
}
|
||||||
|
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static
|
||||||
|
void removeListener(final Listener listener) {
|
||||||
|
synchronized (messageIDs) {
|
||||||
|
for (Map.Entry<Integer, List<Listener>> entry : messageIDs.entrySet()) {
|
||||||
|
List<Listener> value = entry.getValue();
|
||||||
|
if (value.remove(listener)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void run() {
|
||||||
|
WndProc = new WNDPROC() {
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
LRESULT callback(HWND hWnd, int msg, WPARAM wParam, LPARAM lParam) {
|
||||||
|
List<Listener> listeners = null;
|
||||||
|
synchronized (messageIDs) {
|
||||||
|
listeners = messageIDs.get(msg);
|
||||||
|
if (listeners != null) {
|
||||||
|
// make a copy, in case a listener action modifies the message listener
|
||||||
|
listeners = new ArrayList<Listener>(listeners);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listeners != null) {
|
||||||
|
for (final Listener listener : listeners) {
|
||||||
|
if (listener != null) {
|
||||||
|
try {
|
||||||
|
listener.run(hWnd, wParam, lParam);
|
||||||
|
} catch (Exception e) {
|
||||||
|
SystemTray.logger.error("Error executing listener.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return User32.IMPL.DefWindowProc(hWnd, msg, wParam, lParam);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
hWnd = User32.IMPL.CreateWindowEx(0, "STATIC", NAME, 0, 0, 0, 0, 0, null, null, null,
|
||||||
|
null);
|
||||||
|
if (hWnd == null) {
|
||||||
|
throw new GetLastErrorException();
|
||||||
|
}
|
||||||
|
|
||||||
|
User32.IMPL.SetWindowLong(hWnd, GWL_WNDPROC, WndProc);
|
||||||
|
|
||||||
|
synchronized (lock) {
|
||||||
|
lock.notifyAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
MSG msg = new MSG();
|
||||||
|
while (User32.IMPL.GetMessage(msg, null, 0, 0)) {
|
||||||
|
User32.IMPL.TranslateMessage(msg);
|
||||||
|
User32.IMPL.DispatchMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hWnd != null) {
|
||||||
|
if (!User32.IMPL.DestroyWindow(hWnd)) {
|
||||||
|
throw new GetLastErrorException();
|
||||||
|
}
|
||||||
|
hWnd = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows.structs;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
import com.sun.jna.platform.win32.WinUser;
|
||||||
|
|
||||||
|
public class BLENDFUNCTION extends Structure {
|
||||||
|
public static class ByValue extends BLENDFUNCTION implements Structure.ByValue {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ByReference extends BLENDFUNCTION implements Structure.ByReference {
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte BlendOp = WinUser.AC_SRC_OVER; // only valid value
|
||||||
|
public byte BlendFlags = 0; // only valid value
|
||||||
|
public byte SourceConstantAlpha;
|
||||||
|
public byte AlphaFormat;
|
||||||
|
|
||||||
|
public
|
||||||
|
BLENDFUNCTION() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList("BlendOp", "BlendFlags", "SourceConstantAlpha", "AlphaFormat");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows.structs;
|
||||||
|
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.HDC;
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.HWND;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
import com.sun.jna.platform.win32.BaseTSD;
|
||||||
|
import com.sun.jna.platform.win32.WinDef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/bb775802(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
public class DRAWITEMSTRUCT extends Structure {
|
||||||
|
|
||||||
|
public static class ByValue extends DRAWITEMSTRUCT implements Structure.ByValue {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ByReference extends DRAWITEMSTRUCT implements Structure.ByReference {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final int ODT_BUTTON = 4;
|
||||||
|
public static final int ODT_COMBOBOX = 3;
|
||||||
|
public static final int ODT_LISTBOX = 2;
|
||||||
|
public static final int ODT_LISTVIEW = 102;
|
||||||
|
public static final int ODT_MENU = 1;
|
||||||
|
public static final int ODT_STATIC = 5;
|
||||||
|
public static final int ODT_TAB = 101;
|
||||||
|
|
||||||
|
public static final int ODS_SELECTED = 1;
|
||||||
|
|
||||||
|
public int CtlType;
|
||||||
|
public int CtlID;
|
||||||
|
public int itemID;
|
||||||
|
public int itemAction;
|
||||||
|
public int itemState;
|
||||||
|
public HWND hwndItem;
|
||||||
|
public HDC hDC;
|
||||||
|
public WinDef.RECT rcItem;
|
||||||
|
public BaseTSD.ULONG_PTR itemData;
|
||||||
|
|
||||||
|
public DRAWITEMSTRUCT() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public DRAWITEMSTRUCT(Pointer p) {
|
||||||
|
super(p);
|
||||||
|
|
||||||
|
read();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList("CtlType", "CtlID", "itemID", "itemAction", "itemState", "hwndItem", "hDC", "rcItem", "itemData");
|
||||||
|
}
|
||||||
|
}
|
50
src/dorkbox/systemTray/jna/windows/structs/ICONINFO.java
Normal file
50
src/dorkbox/systemTray/jna/windows/structs/ICONINFO.java
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows.structs;
|
||||||
|
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.DWORD;
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.HBITMAP;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms648052(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
class ICONINFO extends Structure {
|
||||||
|
public boolean IsIcon;
|
||||||
|
public DWORD xHotspot;
|
||||||
|
public DWORD yHotspot;
|
||||||
|
public HBITMAP MaskBitmap;
|
||||||
|
public HBITMAP ColorBitmap;
|
||||||
|
|
||||||
|
|
||||||
|
public
|
||||||
|
ICONINFO() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList("IsIcon", "xHotspot", "yHotspot", "MaskBitmap", "ColorBitmap");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static
|
||||||
|
class ByValue extends ICONINFO implements Structure.ByValue {}
|
||||||
|
}
|
77
src/dorkbox/systemTray/jna/windows/structs/LOGFONT.java
Normal file
77
src/dorkbox/systemTray/jna/windows/structs/LOGFONT.java
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows.structs;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
import com.sun.jna.platform.win32.WinDef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://msdn.microsoft.com/en-us/library/windows/desktop/dd145037(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
public class LOGFONT extends Structure {
|
||||||
|
|
||||||
|
public static final int LF_FACESIZE = 32;
|
||||||
|
|
||||||
|
public static class ByValue extends LOGFONT implements Structure.ByValue {
|
||||||
|
}
|
||||||
|
|
||||||
|
public WinDef.LONG lfHeight;
|
||||||
|
public WinDef.LONG lfWidth;
|
||||||
|
public WinDef.LONG lfEscapement;
|
||||||
|
public WinDef.LONG lfOrientation;
|
||||||
|
public WinDef.LONG lfWeight;
|
||||||
|
public byte lfItalic;
|
||||||
|
public byte lfUnderline;
|
||||||
|
public byte lfStrikeOut;
|
||||||
|
public byte lfCharSet;
|
||||||
|
public byte lfOutPrecision;
|
||||||
|
public byte lfClipPrecision;
|
||||||
|
public byte lfQuality;
|
||||||
|
public byte lfPitchAndFamily;
|
||||||
|
public char[] lfFaceName = new char[LF_FACESIZE];
|
||||||
|
|
||||||
|
public LOGFONT() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public LOGFONT(Pointer p) {
|
||||||
|
super(p);
|
||||||
|
|
||||||
|
read();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList("lfHeight",
|
||||||
|
"lfWidth",
|
||||||
|
"lfEscapement",
|
||||||
|
"lfOrientation",
|
||||||
|
"lfWeight",
|
||||||
|
"lfItalic",
|
||||||
|
"lfUnderline",
|
||||||
|
"lfStrikeOut",
|
||||||
|
"lfCharSet",
|
||||||
|
"lfOutPrecision",
|
||||||
|
"lfClipPrecision",
|
||||||
|
"lfQuality",
|
||||||
|
"lfPitchAndFamily",
|
||||||
|
"lfFaceName");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows.structs;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
import com.sun.jna.platform.win32.BaseTSD;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/bb775804(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
public class MEASUREITEMSTRUCT extends Structure {
|
||||||
|
public static class ByValue extends MEASUREITEMSTRUCT implements Structure.ByValue {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ByReference extends MEASUREITEMSTRUCT implements Structure.ByReference {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final int ODT_MENU = 1;
|
||||||
|
public static final int ODT_LISTBOX = 2;
|
||||||
|
public static final int ODT_COMBOBOX = 3;
|
||||||
|
public static final int ODT_BUTTON = 4;
|
||||||
|
public static final int ODT_STATIC = 5;
|
||||||
|
|
||||||
|
public int CtlType;
|
||||||
|
public int CtlID;
|
||||||
|
public int itemID;
|
||||||
|
public int itemWidth;
|
||||||
|
public int itemHeight;
|
||||||
|
public BaseTSD.ULONG_PTR itemData;
|
||||||
|
|
||||||
|
public MEASUREITEMSTRUCT() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public MEASUREITEMSTRUCT(Pointer p) {
|
||||||
|
super(p);
|
||||||
|
|
||||||
|
read();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList("CtlType", "CtlID", "itemID", "itemWidth", "itemHeight", "itemData");
|
||||||
|
}
|
||||||
|
}
|
89
src/dorkbox/systemTray/jna/windows/structs/MENUITEMINFO.java
Normal file
89
src/dorkbox/systemTray/jna/windows/structs/MENUITEMINFO.java
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows.structs;
|
||||||
|
|
||||||
|
import static com.sun.jna.platform.win32.BaseTSD.ULONG_PTR;
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.HBITMAP;
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.HMENU;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms647578(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
class MENUITEMINFO extends Structure {
|
||||||
|
|
||||||
|
public static final int MFS_ENABLED = 0x00000000;
|
||||||
|
public static final int MFS_DISABLED = 0x00000003;
|
||||||
|
|
||||||
|
public static final int MFS_GRAYED = 0x00000003;
|
||||||
|
public static final int MFS_DEFAULT = 0x00001000;
|
||||||
|
|
||||||
|
public static final int MFS_CHECKED = 0x00000008;
|
||||||
|
public static final int MFS_UNCHECKED= 0x00000000;
|
||||||
|
|
||||||
|
public static final int MFS_HILITE = 0x00000080;
|
||||||
|
public static final int MFS_UNHILITE = 0x00000000;
|
||||||
|
|
||||||
|
public static final int MIIM_DATA = 0x00000020;
|
||||||
|
|
||||||
|
|
||||||
|
public int cbSize;
|
||||||
|
public int fMask;
|
||||||
|
public int fType;
|
||||||
|
public int fState;
|
||||||
|
public int wID;
|
||||||
|
|
||||||
|
public HMENU hSubMenu;
|
||||||
|
public HBITMAP hbmpChecked;
|
||||||
|
public HBITMAP hbmpUnchecked;
|
||||||
|
public ULONG_PTR dwItemData;
|
||||||
|
public String dwTypeData;
|
||||||
|
public int cch;
|
||||||
|
public HBITMAP hbmpItem;
|
||||||
|
|
||||||
|
public
|
||||||
|
MENUITEMINFO() {
|
||||||
|
cbSize = size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public
|
||||||
|
MENUITEMINFO(Pointer p) {
|
||||||
|
super(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList("cbSize",
|
||||||
|
"fMask",
|
||||||
|
"fType",
|
||||||
|
"fState",
|
||||||
|
"wID",
|
||||||
|
"hSubMenu",
|
||||||
|
"hbmpChecked",
|
||||||
|
"hbmpUnchecked",
|
||||||
|
"dwItemData",
|
||||||
|
"dwTypeData",
|
||||||
|
"cch",
|
||||||
|
"hbmpItem");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows.structs;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/ff729175(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
public class NONCLIENTMETRICS extends Structure {
|
||||||
|
public static class ByValue extends NONCLIENTMETRICS implements Structure.ByValue {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ByReference extends NONCLIENTMETRICS implements Structure.ByReference {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final int ODT_MENU = 1;
|
||||||
|
public static final int ODT_LISTBOX = 2;
|
||||||
|
public static final int ODT_COMBOBOX = 3;
|
||||||
|
public static final int ODT_BUTTON = 4;
|
||||||
|
public static final int ODT_STATIC = 5;
|
||||||
|
|
||||||
|
public int cbSize;
|
||||||
|
public int iBorderWidth;
|
||||||
|
public int iScrollWidth;
|
||||||
|
public int iScrollHeight;
|
||||||
|
public int iCaptionWidth;
|
||||||
|
public int iCaptionHeight;
|
||||||
|
public LOGFONT.ByValue lfCaptionFont;
|
||||||
|
public int iSmCaptionWidth;
|
||||||
|
public int iSmCaptionHeight;
|
||||||
|
public LOGFONT.ByValue lfSmCaptionFont;
|
||||||
|
public int iMenuWidth;
|
||||||
|
public int iMenuHeight;
|
||||||
|
public LOGFONT.ByValue lfMenuFont;
|
||||||
|
public LOGFONT.ByValue lfStatusFont;
|
||||||
|
public LOGFONT.ByValue lfMessageFont;
|
||||||
|
//public int iPaddedBorderWidth;
|
||||||
|
|
||||||
|
public NONCLIENTMETRICS() {
|
||||||
|
cbSize = size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NONCLIENTMETRICS(Pointer p) {
|
||||||
|
super(p);
|
||||||
|
|
||||||
|
read();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList("cbSize",
|
||||||
|
"iBorderWidth",
|
||||||
|
"iScrollWidth",
|
||||||
|
"iScrollHeight",
|
||||||
|
"iCaptionWidth",
|
||||||
|
"iCaptionHeight",
|
||||||
|
"lfCaptionFont",
|
||||||
|
"iSmCaptionWidth",
|
||||||
|
"iSmCaptionHeight",
|
||||||
|
"lfSmCaptionFont",
|
||||||
|
"iMenuWidth",
|
||||||
|
"iMenuHeight",
|
||||||
|
"lfMenuFont",
|
||||||
|
"lfStatusFont",
|
||||||
|
"lfMessageFont"
|
||||||
|
//"iPaddedBorderWidth"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
116
src/dorkbox/systemTray/jna/windows/structs/NOTIFYICONDATA.java
Normal file
116
src/dorkbox/systemTray/jna/windows/structs/NOTIFYICONDATA.java
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows.structs;
|
||||||
|
|
||||||
|
import static com.sun.jna.platform.win32.WinDef.HWND;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
import com.sun.jna.platform.win32.WinDef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/bb773352(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
public class NOTIFYICONDATA extends Structure {
|
||||||
|
static public final int NIF_MESSAGE = 0x1;
|
||||||
|
static public final int NIF_ICON = 0x2;
|
||||||
|
static public final int NIF_TIP = 0x4;
|
||||||
|
static public final int NIF_STATE = 0x8;
|
||||||
|
|
||||||
|
static public final int NIF_INFO = 0x10;
|
||||||
|
|
||||||
|
static public final int NIIF_NONE = 0x0;
|
||||||
|
static public final int NIIF_INFO = 0x1;
|
||||||
|
static public final int NIIF_WARNING = 0x2;
|
||||||
|
static public final int NIIF_ERROR = 0x3;
|
||||||
|
static public final int NIIF_USER = 0x4;
|
||||||
|
|
||||||
|
public int cbSize;
|
||||||
|
public HWND hWnd;
|
||||||
|
public int uID;
|
||||||
|
public int uFlags;
|
||||||
|
public int uCallbackMessage;
|
||||||
|
public WinDef.HICON hIcon;
|
||||||
|
|
||||||
|
public char[] szTip = new char[128];
|
||||||
|
|
||||||
|
public int dwState;
|
||||||
|
public int dwStateMask;
|
||||||
|
|
||||||
|
public char[] szInfo = new char[256];
|
||||||
|
public int uTimeoutOrVersion; // {UINT uTimeout; UINT uVersion;};
|
||||||
|
|
||||||
|
public char[] szInfoTitle = new char[64];
|
||||||
|
public int dwInfoFlags;
|
||||||
|
|
||||||
|
public
|
||||||
|
NOTIFYICONDATA() {
|
||||||
|
cbSize = size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public
|
||||||
|
void setTooltip(String s) {
|
||||||
|
uFlags |= NIF_TIP;
|
||||||
|
|
||||||
|
System.arraycopy(s.toCharArray(), 0, szTip, 0, Math.min(s.length(), szTip.length));
|
||||||
|
szTip[s.length()] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
public
|
||||||
|
void setBalloon(String title, String message, int millis, int niif) {
|
||||||
|
uFlags |= NIF_INFO;
|
||||||
|
|
||||||
|
System.arraycopy(message.toCharArray(), 0, szInfo, 0, Math.min(message.length(), szInfo.length));
|
||||||
|
szInfo[message.length()] = '\0';
|
||||||
|
|
||||||
|
uTimeoutOrVersion = millis;
|
||||||
|
|
||||||
|
System.arraycopy(title.toCharArray(), 0, szInfoTitle, 0, Math.min(title.length(), szInfoTitle.length));
|
||||||
|
szInfoTitle[title.length()] = '\0';
|
||||||
|
|
||||||
|
dwInfoFlags = niif;
|
||||||
|
}
|
||||||
|
|
||||||
|
public
|
||||||
|
void setIcon(WinDef.HICON hIcon) {
|
||||||
|
uFlags |= NIF_ICON;
|
||||||
|
this.hIcon = hIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCallback(int callback) {
|
||||||
|
uFlags |= NIF_MESSAGE;
|
||||||
|
uCallbackMessage = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> getFieldOrder () {
|
||||||
|
return Arrays.asList("cbSize",
|
||||||
|
"hWnd",
|
||||||
|
"uID",
|
||||||
|
"uFlags",
|
||||||
|
"uCallbackMessage",
|
||||||
|
"hIcon",
|
||||||
|
"szTip",
|
||||||
|
"dwState",
|
||||||
|
"dwStateMask",
|
||||||
|
"szInfo",
|
||||||
|
"uTimeoutOrVersion",
|
||||||
|
"szInfoTitle",
|
||||||
|
"dwInfoFlags");
|
||||||
|
}
|
||||||
|
}
|
177
src/dorkbox/systemTray/nativeUI/WindowsBaseMenuItem.java
Normal file
177
src/dorkbox/systemTray/nativeUI/WindowsBaseMenuItem.java
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
/*
|
||||||
|
* 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.jna.windows.User32.MF_BYPOSITION;
|
||||||
|
import static dorkbox.systemTray.nativeUI.WindowsMenu.MFT_OWNERDRAW;
|
||||||
|
|
||||||
|
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.systemTray.jna.windows.GDI32;
|
||||||
|
import dorkbox.systemTray.jna.windows.GetLastErrorException;
|
||||||
|
import dorkbox.systemTray.jna.windows.HBITMAPWrap;
|
||||||
|
import dorkbox.systemTray.jna.windows.User32;
|
||||||
|
import dorkbox.systemTray.jna.windows.structs.MENUITEMINFO;
|
||||||
|
import dorkbox.util.SwingUtil;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
BufferedImage createBitmap(Icon icon) {
|
||||||
|
BufferedImage bi = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||||
|
Graphics2D g = bi.createGraphics();
|
||||||
|
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
|
||||||
|
icon.paintIcon(null, g, 0, 0);
|
||||||
|
g.dispose();
|
||||||
|
return bi;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
744
src/dorkbox/systemTray/nativeUI/WindowsMenu.java
Normal file
744
src/dorkbox/systemTray/nativeUI/WindowsMenu.java
Normal file
@ -0,0 +1,744 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemTray.jna.windows.WindowsEventDispatch.MF_POPUP;
|
||||||
|
import static dorkbox.systemTray.jna.windows.WindowsEventDispatch.WM_COMMAND;
|
||||||
|
import static dorkbox.systemTray.jna.windows.WindowsEventDispatch.WM_DRAWITEM;
|
||||||
|
import static dorkbox.systemTray.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.jna.windows.GDI32;
|
||||||
|
import dorkbox.systemTray.jna.windows.GetLastErrorException;
|
||||||
|
import dorkbox.systemTray.jna.windows.Listener;
|
||||||
|
import dorkbox.systemTray.jna.windows.MsImg32;
|
||||||
|
import dorkbox.systemTray.jna.windows.User32;
|
||||||
|
import dorkbox.systemTray.jna.windows.WindowsEventDispatch;
|
||||||
|
import dorkbox.systemTray.jna.windows.structs.BLENDFUNCTION;
|
||||||
|
import dorkbox.systemTray.jna.windows.structs.DRAWITEMSTRUCT;
|
||||||
|
import dorkbox.systemTray.jna.windows.structs.MEASUREITEMSTRUCT;
|
||||||
|
import dorkbox.systemTray.jna.windows.structs.NONCLIENTMETRICS;
|
||||||
|
import dorkbox.systemTray.peer.MenuPeer;
|
||||||
|
|
||||||
|
// 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<WindowsBaseMenuItem> menuEntries = new ArrayList<WindowsBaseMenuItem>();
|
||||||
|
|
||||||
|
|
||||||
|
// 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<WindowsBaseMenuItem> menuEntriesCopy = new ArrayList<WindowsBaseMenuItem>(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), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
throw new GetLastErrorException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WPARAM wparam = new WPARAM(0);
|
||||||
|
LPARAM lparam = new LPARAM(0);
|
||||||
|
User32.IMPL.PostMessage(mainHwnd, WM_NULL, wparam, lparam);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// // 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;
|
||||||
|
}
|
||||||
|
}
|
94
src/dorkbox/systemTray/nativeUI/WindowsMenuItem.java
Normal file
94
src/dorkbox/systemTray/nativeUI/WindowsMenuItem.java
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* 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();
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
}
|
153
src/dorkbox/systemTray/nativeUI/WindowsMenuItemCheckbox.java
Normal file
153
src/dorkbox/systemTray/nativeUI/WindowsMenuItemCheckbox.java
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* 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();
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
}
|
71
src/dorkbox/systemTray/nativeUI/WindowsMenuItemStatus.java
Normal file
71
src/dorkbox/systemTray/nativeUI/WindowsMenuItemStatus.java
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
}
|
272
src/dorkbox/systemTray/nativeUI/_WindowsNativeTray.java
Normal file
272
src/dorkbox/systemTray/nativeUI/_WindowsNativeTray.java
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
/*
|
||||||
|
* 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 dorkbox.systemTray.jna.windows.Shell32.NIM_ADD;
|
||||||
|
import static dorkbox.systemTray.jna.windows.Shell32.NIM_DELETE;
|
||||||
|
import static dorkbox.systemTray.jna.windows.Shell32.NIM_MODIFY;
|
||||||
|
import static dorkbox.systemTray.jna.windows.Shell32.Shell_NotifyIcon;
|
||||||
|
import static dorkbox.systemTray.jna.windows.User32.WM_LBUTTONUP;
|
||||||
|
import static dorkbox.systemTray.jna.windows.User32.WM_QUIT;
|
||||||
|
import static dorkbox.systemTray.jna.windows.User32.WM_RBUTTONUP;
|
||||||
|
import static dorkbox.systemTray.jna.windows.WindowsEventDispatch.WM_SHELLNOTIFY;
|
||||||
|
import static dorkbox.systemTray.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.systemTray.jna.windows.HBITMAPWrap;
|
||||||
|
import dorkbox.systemTray.jna.windows.HICONWrap;
|
||||||
|
import dorkbox.systemTray.jna.windows.Kernel32;
|
||||||
|
import dorkbox.systemTray.jna.windows.Listener;
|
||||||
|
import dorkbox.systemTray.jna.windows.Shell32;
|
||||||
|
import dorkbox.systemTray.jna.windows.User32;
|
||||||
|
import dorkbox.systemTray.jna.windows.WindowsEventDispatch;
|
||||||
|
import dorkbox.systemTray.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();
|
||||||
|
|
||||||
|
WPARAM wparam = new WPARAM(0);
|
||||||
|
LPARAM lparam = new LPARAM(0);
|
||||||
|
User32.IMPL.PostMessage(WindowsEventDispatch.get(), WM_QUIT, wparam, lparam);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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(WindowsBaseMenuItem.createBitmap(imageIcon));
|
||||||
|
return new HICONWrap(hbitmapTrayIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user