|
28 | 28 |
|
29 | 29 | import com.sun.jna.Library; |
30 | 30 | import com.sun.jna.Native; |
| 31 | +import com.sun.jna.Pointer; |
31 | 32 | import com.sun.jna.platform.win32.Shell32Util; |
32 | 33 | import com.sun.jna.platform.win32.ShlObj; |
| 34 | +import com.sun.jna.win32.StdCallLibrary; |
| 35 | +import com.sun.jna.win32.W32APIOptions; |
33 | 36 |
|
34 | 37 | import processing.app.Base; |
35 | 38 | import processing.app.Messages; |
@@ -602,56 +605,57 @@ public int unsetenv(String variable) { |
602 | 605 |
|
603 | 606 | // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
604 | 607 |
|
605 | | - // JNA code for using SHGetFolderPath to fix Issue 410 |
606 | | - // https://code.google.com/p/processing/issues/detail?id=410 |
607 | | - // Based on answer provided by McDowell at |
608 | | - // http://stackoverflow.com/questions/585534/what-is-the-best-way-to-find-the-users-home-directory-in-java/586917#586917 |
609 | 608 |
|
610 | | -// private static Map<String, Object> OPTIONS = new HashMap<String, Object>(); |
611 | | -// |
612 | | -// static { |
613 | | -// OPTIONS.put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE); |
614 | | -// OPTIONS.put(Library.OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE); |
615 | | -// } |
616 | | -// |
617 | | -// |
618 | | -// static class HANDLE extends PointerType implements NativeMapped { |
619 | | -// public HANDLE() { } |
620 | | -// } |
621 | | -// |
622 | | -// static class HWND extends HANDLE { } |
623 | | -// |
624 | | -// |
625 | | -// public interface Shell32 extends Library { |
626 | | -// |
627 | | -// public static final int MAX_PATH = 260; |
628 | | -// public static final int SHGFP_TYPE_CURRENT = 0; |
629 | | -// public static final int SHGFP_TYPE_DEFAULT = 1; |
630 | | -// public static final int S_OK = 0; |
631 | | -// |
632 | | -// // KNOWNFOLDERIDs are preferred to CSDIL values |
633 | | -// // but Windows XP only supports CSDIL so thats what we have to use |
634 | | -// public static final int CSIDL_APPDATA = 0x001a; // "Application Data" |
635 | | -// public static final int CSIDL_PERSONAL = 0x0005; // "My Documents" |
636 | | -// |
637 | | -// static Shell32 INSTANCE = (Shell32) Native.loadLibrary("shell32", Shell32.class, OPTIONS); |
638 | | -// |
639 | | -// /** |
640 | | -// * see http://msdn.microsoft.com/en-us/library/bb762181(VS.85).aspx |
641 | | -// * |
642 | | -// * HRESULT SHGetFolderPath( HWND hwndOwner, int nFolder, HANDLE hToken, |
643 | | -// * DWORD dwFlags, LPTSTR pszPath); |
644 | | -// */ |
645 | | -// public int SHGetFolderPath(HWND hwndOwner, int nFolder, HANDLE hToken, |
646 | | -// int dwFlags, char[] pszPath); |
647 | | -// |
648 | | -// /** |
649 | | -// * This function can be used to copy, move, rename, |
650 | | -// * or delete a file system object. |
651 | | -// * @param fileop Address of an SHFILEOPSTRUCT structure that contains |
652 | | -// * information this function needs to carry out the specified operation. |
653 | | -// * @return Returns zero if successful, or nonzero otherwise. |
654 | | -// */ |
655 | | -// public int SHFileOperation(SHFILEOPSTRUCT fileop); |
656 | | -// } |
| 609 | + // Need to extend com.sun.jna.platform.win32.User32 to access |
| 610 | + // Win32 function GetDpiForSystem() |
| 611 | + interface ExtUser32 extends StdCallLibrary, com.sun.jna.platform.win32.User32 { |
| 612 | + ExtUser32 INSTANCE = (ExtUser32) Native.loadLibrary("user32", ExtUser32.class, W32APIOptions.DEFAULT_OPTIONS); |
| 613 | + |
| 614 | + public int GetDpiForSystem(); |
| 615 | + |
| 616 | + public int SetProcessDpiAwareness(int value); |
| 617 | + |
| 618 | + public final int DPI_AWARENESS_INVALID = -1; |
| 619 | + public final int DPI_AWARENESS_UNAWARE = 0; |
| 620 | + public final int DPI_AWARENESS_SYSTEM_AWARE = 1; |
| 621 | + public final int DPI_AWARENESS_PER_MONITOR_AWARE = 2; |
| 622 | + |
| 623 | + public Pointer SetThreadDpiAwarenessContext(Pointer dpiContext); |
| 624 | + |
| 625 | + public final Pointer DPI_AWARENESS_CONTEXT_UNAWARE = new Pointer(-1); |
| 626 | + public final Pointer DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = new Pointer(-2); |
| 627 | + public final Pointer DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = new Pointer(-3); |
| 628 | + } |
| 629 | + |
| 630 | + |
| 631 | + static private int detected = detectSystemDPI(); |
| 632 | + |
| 633 | + |
| 634 | + public int getSystemDPI() { |
| 635 | + if (detected == -1) { |
| 636 | + return super.getSystemDPI(); |
| 637 | + } |
| 638 | + return detected; |
| 639 | + } |
| 640 | + |
| 641 | + |
| 642 | + public static int detectSystemDPI() { |
| 643 | + try { |
| 644 | + ExtUser32.INSTANCE.SetProcessDpiAwareness(ExtUser32.DPI_AWARENESS_SYSTEM_AWARE); |
| 645 | + } catch (Throwable e) { |
| 646 | + // Ignore error |
| 647 | + } |
| 648 | + try { |
| 649 | + ExtUser32.INSTANCE.SetThreadDpiAwarenessContext(ExtUser32.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE); |
| 650 | + } catch (Throwable e) { |
| 651 | + // Ignore error (call valid only on Windows 10) |
| 652 | + } |
| 653 | + try { |
| 654 | + return ExtUser32.INSTANCE.GetDpiForSystem(); |
| 655 | + } catch (Throwable e) { |
| 656 | + // DPI detection failed, fall back with default |
| 657 | + System.out.println("DPI detection failed, fallback to 96 dpi"); |
| 658 | + return -1; |
| 659 | + } |
| 660 | + } |
657 | 661 | } |
0 commit comments