From 449b2a4bf3b072d039bcebfb7f811b75cb9644bc Mon Sep 17 00:00:00 2001 From: Vincent Torri Date: Fri, 5 May 2017 07:52:12 +0200 Subject: [PATCH] Ecore_Win32: add API to retrieve the geometry and dpi of plugged displays @feature Signed-off-by: Cedric BAIL --- src/Makefile_Ecore_Win32.am | 1 + src/lib/ecore_win32/Ecore_Win32.h | 29 +++ src/lib/ecore_win32/ecore_win32.c | 20 ++ src/lib/ecore_win32/ecore_win32_monitor.c | 224 ++++++++++++++++++++++ src/lib/ecore_win32/ecore_win32_private.h | 11 +- 5 files changed, 282 insertions(+), 3 deletions(-) create mode 100644 src/lib/ecore_win32/ecore_win32_monitor.c diff --git a/src/Makefile_Ecore_Win32.am b/src/Makefile_Ecore_Win32.am index 8a407e95f0..c230a8b8f1 100644 --- a/src/Makefile_Ecore_Win32.am +++ b/src/Makefile_Ecore_Win32.am @@ -18,6 +18,7 @@ lib/ecore_win32/ecore_win32_dnd_data_object.cpp \ lib/ecore_win32/ecore_win32_dnd_drop_source.cpp \ lib/ecore_win32/ecore_win32_dnd_drop_target.cpp \ lib/ecore_win32/ecore_win32_event.c \ +lib/ecore_win32/ecore_win32_monitor.c \ lib/ecore_win32/ecore_win32_window.c \ lib/ecore_win32/ecore_win32_private.h \ lib/ecore_win32/ecore_win32_cursor_x11.h \ diff --git a/src/lib/ecore_win32/Ecore_Win32.h b/src/lib/ecore_win32/Ecore_Win32.h index 19a8b2ccb1..34e8596fdb 100644 --- a/src/lib/ecore_win32/Ecore_Win32.h +++ b/src/lib/ecore_win32/Ecore_Win32.h @@ -740,6 +740,35 @@ EAPI Eina_Bool ecore_win32_clipboard_get(const Ecore_Win32_Window *window, */ EAPI Eina_Bool ecore_win32_clipboard_clear(const Ecore_Win32_Window *window); +/** + * @typedef Ecore_Win32_Monitor + * Desktop geometry and dpi of a monitor. + * + * @since 1.20 + */ +typedef struct +{ + Eina_Rectangle desktop; /**< Coordinates and size of the desktop */ + struct + { + unsigned int x; /**< DPI along the X axis */ + unsigned int y; /**< DPI along the Y axis */ + } dpi; +} Ecore_Win32_Monitor; + +/** + * @brief Return the coordinates, sizes DPI's of the monitors. + * + * @return An iterator of an Eina list, with #Ecore_Win32_Monitor + * as data. + * + * This function returns the coordinates, sizes and DPI's of the + * monitors as an iterator of a list of #Ecore_Win32_Monitor. + * + * @since 1.20 + */ +EAPI Eina_Iterator *ecore_win32_monitors_get(void); + /** * @} */ diff --git a/src/lib/ecore_win32/ecore_win32.c b/src/lib/ecore_win32/ecore_win32.c index cd75bee28f..7b170c954d 100644 --- a/src/lib/ecore_win32/ecore_win32.c +++ b/src/lib/ecore_win32/ecore_win32.c @@ -8,6 +8,7 @@ #include #undef WIN32_LEAN_AND_MEAN #include +#include #include #include @@ -209,6 +210,7 @@ _ecore_win32_window_procedure(HWND window, efl_AddClipboardFormatListener acfl; INF("create window message"); + acfl = (efl_AddClipboardFormatListener)GetProcAddress(GetModuleHandle("user32.dll"), "AddClipboardFormatListener"); if (acfl) @@ -386,6 +388,20 @@ _ecore_win32_window_procedure(HWND window, case WM_SYNCPAINT: INF("sync paint message"); return 0; + /* Desktop notifications */ + case WM_DEVICECHANGE: + if (window == ecore_win32_monitor_window) + { + PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)data_param; + + if ((window_param == DBT_DEVICEARRIVAL) && + (pHdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)) + ecore_win32_monitor_update(1); + + if ((window_param == DBT_DEVICEREMOVECOMPLETE) && + (pHdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)) + ecore_win32_monitor_update(2); + } default: return DefWindowProc(window, message, window_param, data_param); } @@ -578,6 +594,8 @@ ecore_win32_init() for (i = 0; i < 77; i++) _ecore_win32_cursor_x[i] = _ecore_win32_cursor_x11_shaped_new(i); + ecore_win32_monitor_init(); + return _ecore_win32_init_count; unregister_class: @@ -612,6 +630,8 @@ ecore_win32_shutdown() if (--_ecore_win32_init_count != 0) return _ecore_win32_init_count; + ecore_win32_monitor_shutdown(); + for (i = 0; i < 77; i++) ecore_win32_cursor_free(_ecore_win32_cursor_x[i]); diff --git a/src/lib/ecore_win32/ecore_win32_monitor.c b/src/lib/ecore_win32/ecore_win32_monitor.c new file mode 100644 index 0000000000..36d136908e --- /dev/null +++ b/src/lib/ecore_win32/ecore_win32_monitor.c @@ -0,0 +1,224 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN +#include + +#include + +#include "Ecore_Win32.h" +#include "ecore_win32_private.h" + +/*============================================================================* + * Local * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +typedef struct +{ + Ecore_Win32_Monitor monitor; + char *name; + Eina_Bool delete_me : 1; +} Ecore_Win32_Monitor_Priv; + +typedef HRESULT (WINAPI *GetDpiForMonitor_t)(HMONITOR, int, UINT *, UINT *); + +static HMODULE _ecore_win32_mod = NULL; +static GetDpiForMonitor_t GetDpiForMonitor_ = NULL; +static Eina_List *ecore_win32_monitors = NULL; + +#ifndef GUID_DEVINTERFACE_MONITOR +static GUID GUID_DEVINTERFACE_MONITOR = {0xe6f07b5f, 0xee97, 0x4a90, { 0xb0, 0x76, 0x33, 0xf5, 0x7b, 0xf4, 0xea, 0xa7} }; +#endif + +static void +_ecore_win32_monitor_free(void *p) +{ + Ecore_Win32_Monitor_Priv *ewm = p; + + if (ewm) + { + free(ewm->name); + free(ewm); + } +} + +static BOOL CALLBACK +_ecore_win32_monitor_update_cb(HMONITOR m, HDC monitor EINA_UNUSED, LPRECT r EINA_UNUSED, LPARAM data) +{ + MONITORINFOEX mi; + Ecore_Win32_Monitor_Priv *ewm; + Eina_Bool is_added; + + mi.cbSize = sizeof(MONITORINFOEX); + GetMonitorInfo(m, (MONITORINFO *)&mi); + + if (data == 1) + { + Eina_List *l; + + is_added = EINA_FALSE; + EINA_LIST_FOREACH(ecore_win32_monitors, l, ewm) + { + if (strcmp(mi.szDevice, ewm->name) != 0) + { + is_added = EINA_TRUE; + break; + } + } + } + else if (data == 2) + { + Eina_List *l; + + EINA_LIST_FOREACH(ecore_win32_monitors, l, ewm) + { + if (strcmp(mi.szDevice, ewm->name) == 0) + { + ewm->delete_me = EINA_FALSE; + return FALSE; + } + } + } + else + is_added = EINA_TRUE; + + if (!is_added) + return TRUE; + + ewm = (Ecore_Win32_Monitor_Priv *)malloc(sizeof(Ecore_Win32_Monitor_Priv)); + if (ewm) + { + ewm->monitor.desktop.x = mi.rcMonitor.left; + ewm->monitor.desktop.y = mi.rcMonitor.top; + ewm->monitor.desktop.w = mi.rcMonitor.right - mi.rcMonitor.left; + ewm->monitor.desktop.h = mi.rcMonitor.bottom - mi.rcMonitor.top; + if (!GetDpiForMonitor_ || + (GetDpiForMonitor_(m, 0, + &ewm->monitor.dpi.x, + &ewm->monitor.dpi.y) != S_OK)) + { + HDC dc; + + dc = GetDC(NULL); + ewm->monitor.dpi.x = GetDeviceCaps(dc, LOGPIXELSX); + ewm->monitor.dpi.y = GetDeviceCaps(dc, LOGPIXELSY); + ReleaseDC(NULL, dc); + } + ewm->name = strdup(mi.szDevice); + if (ewm->name) + ecore_win32_monitors = eina_list_append(ecore_win32_monitors, ewm); + else + free(ewm); + } + + return TRUE; +} + +/** + * @endcond + */ + + +/*============================================================================* + * Global * + *============================================================================*/ + +HWND ecore_win32_monitor_window = NULL; + +void +ecore_win32_monitor_init(void) +{ + DEV_BROADCAST_DEVICEINTERFACE notification; + DWORD style; + + style = WS_POPUP & ~(WS_CAPTION | WS_THICKFRAME); + ecore_win32_monitor_window = CreateWindow(ECORE_WIN32_WINDOW_CLASS, "", + style, + 10, 10, + 100, 100, + NULL, NULL, + _ecore_win32_instance, NULL); + + if (ecore_win32_monitor_window) + { + ZeroMemory(¬ification, sizeof(notification)); + notification.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); + notification.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + notification.dbcc_classguid = GUID_DEVINTERFACE_MONITOR; + RegisterDeviceNotification(ecore_win32_monitor_window, + ¬ification, + DEVICE_NOTIFY_WINDOW_HANDLE); + } + + /* + * Even if RegisterDeviceNotification() fails, the next call will + * fill one item of the monitor lists, except if there is no more + * memory + */ + ecore_win32_monitor_update(0); + + _ecore_win32_mod = LoadLibrary("shcore.dll"); + if (_ecore_win32_mod) + GetDpiForMonitor_ = (GetDpiForMonitor_t)GetProcAddress(_ecore_win32_mod, + "GetDpiForMonitor"); +} + +void +ecore_win32_monitor_shutdown(void) +{ + Ecore_Win32_Monitor_Priv *ewm; + + if (_ecore_win32_mod) + FreeLibrary(_ecore_win32_mod); + EINA_LIST_FREE(ecore_win32_monitors, ewm) + _ecore_win32_monitor_free(ewm); + if (ecore_win32_monitor_window) + DestroyWindow(ecore_win32_monitor_window); +} + +void +ecore_win32_monitor_update(int d) +{ + Ecore_Win32_Monitor_Priv *ewm; + Eina_List *l; + + if (d == 2) + { + EINA_LIST_FOREACH(ecore_win32_monitors, l, ewm) + ewm->delete_me = EINA_TRUE; + } + + EnumDisplayMonitors(NULL, NULL, _ecore_win32_monitor_update_cb, d); + + if (d == 2) + { + EINA_LIST_FOREACH(ecore_win32_monitors, l, ewm) + { + if (ewm->delete_me == EINA_TRUE) + { + ecore_win32_monitors = eina_list_remove(ecore_win32_monitors, ewm); + _ecore_win32_monitor_free(ewm); + break; + } + } + } +} + +/*============================================================================* + * API * + *============================================================================*/ + +EAPI Eina_Iterator * +ecore_win32_monitors_get(void) +{ + return eina_list_iterator_new(ecore_win32_monitors); +} diff --git a/src/lib/ecore_win32/ecore_win32_private.h b/src/lib/ecore_win32/ecore_win32_private.h index bb22b466f5..1956f8bf6b 100644 --- a/src/lib/ecore_win32/ecore_win32_private.h +++ b/src/lib/ecore_win32/ecore_win32_private.h @@ -6,9 +6,6 @@ extern "C" { #endif -/* logging messages macros */ -extern int _ecore_win32_log_dom_global; - #ifdef ECORE_WIN32_DEFAULT_LOG_COLOR # undef ECORE_WIN32_DEFAULT_LOG_COLOR #endif @@ -134,12 +131,16 @@ struct _Ecore_Win32_Window }; +/* logging messages macros */ +extern int _ecore_win32_log_dom_global; + extern HINSTANCE _ecore_win32_instance; extern double _ecore_win32_double_click_time; extern unsigned long _ecore_win32_event_last_time; extern Ecore_Win32_Window *_ecore_win32_event_last_window; extern Ecore_Win32_Cursor *_ecore_win32_cursor_x[77]; +extern HWND ecore_win32_monitor_window; void _ecore_win32_event_handle_key_press(Ecore_Win32_Callback_Data *msg); void _ecore_win32_event_handle_key_release(Ecore_Win32_Callback_Data *msg); @@ -173,6 +174,10 @@ Eina_Bool ecore_win32_window_drag(Ecore_Win32_Window *w, int ptx, int pty); Ecore_Win32_Cursor *_ecore_win32_cursor_x11_shaped_new(Ecore_Win32_Cursor_X11_Shape shape); +void ecore_win32_monitor_init(void); +void ecore_win32_monitor_shutdown(void); +void ecore_win32_monitor_update(int d); + #ifdef __cplusplus }