gtk2/gdk/win32/gdkdisplay-win32.c
Alexander Larsson 9a7e721181 GdkSurface: Rename various functions and variables
This is an automatic rename of various things related
to the window->surface rename.

Public symbols changed by this is:
 GDK_MODE_WINDOW
 gdk_device_get_window_at_position
 gdk_device_get_window_at_position_double
 gdk_device_get_last_event_window
 gdk_display_get_monitor_at_window
 gdk_drag_context_get_source_window
 gdk_drag_context_get_dest_window
 gdk_drag_context_get_drag_window
 gdk_draw_context_get_window
 gdk_drawing_context_get_window
 gdk_gl_context_get_window
 gdk_synthesize_window_state
 gdk_surface_get_window_type
 gdk_x11_display_set_window_scale
 gsk_renderer_new_for_window
 gsk_renderer_get_window
 gtk_text_view_buffer_to_window_coords
 gtk_tree_view_convert_widget_to_bin_window_coords
 gtk_tree_view_convert_tree_to_bin_window_coords

The commands that generated this are:

git sed -f g "GDK window" "GDK surface"
git sed -f g window_impl surface_impl
(cd gdk; git sed -f g impl_window impl_surface)
git sed -f g WINDOW_IMPL SURFACE_IMPL
git sed -f g GDK_MODE_WINDOW GDK_MODE_SURFACE
git sed -f g gdk_draw_context_get_window gdk_draw_context_get_surface
git sed -f g gdk_drawing_context_get_window gdk_drawing_context_get_surface
git sed -f g gdk_gl_context_get_window gdk_gl_context_get_surface
git sed -f g gsk_renderer_get_window gsk_renderer_get_surface
git sed -f g gsk_renderer_new_for_window gsk_renderer_new_for_surface

(cd gdk; git sed -f g window_type surface_type)
git sed -f g gdk_surface_get_window_type gdk_surface_get_surface_type

git sed -f g window_at_position surface_at_position
git sed -f g event_window event_surface
git sed -f g window_coord surface_coord
git sed -f g window_state surface_state
git sed -f g window_cursor surface_cursor
git sed -f g window_scale surface_scale
git sed -f g window_events surface_events
git sed -f g monitor_at_window monitor_at_surface
git sed -f g window_under_pointer surface_under_pointer
(cd gdk; git sed -f g for_window for_surface)
git sed -f g window_anchor surface_anchor
git sed -f g WINDOW_IS_TOPLEVEL SURFACE_IS_TOPLEVEL
git sed -f g native_window native_surface
git sed -f g source_window source_surface
git sed -f g dest_window dest_surface
git sed -f g drag_window drag_surface
git sed -f g input_window input_surface

git checkout NEWS* po-properties po docs/reference/gtk/migrating-3to4.xml
2018-03-20 12:05:26 +01:00

1189 lines
36 KiB
C

/* GDK - The GIMP Drawing Kit
* Copyright (C) 2002,2005 Hans Breuer
* Copyright (C) 2003 Tor Lillqvist
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#define _WIN32_WINNT 0x0600
#define VK_USE_PLATFORM_WIN32_KHR
#include "gdk.h"
#include "gdkprivate-win32.h"
#include "gdkdisplay-win32.h"
#include "gdkdevicemanager-win32.h"
#include "gdkglcontext-win32.h"
#include "gdkwin32display.h"
#include "gdkwin32screen.h"
#include "gdkwin32surface.h"
#include "gdkmonitor-win32.h"
#include "gdkwin32.h"
#include "gdkvulkancontext-win32.h"
#include <dwmapi.h>
static int debug_indent = 0;
static GdkMonitor *
_gdk_win32_display_find_matching_monitor (GdkWin32Display *win32_display,
GdkMonitor *needle)
{
int i;
for (i = 0; i < win32_display->monitors->len; i++)
{
GdkWin32Monitor *m;
m = GDK_WIN32_MONITOR (g_ptr_array_index (win32_display->monitors, i));
if (_gdk_win32_monitor_compare (m, GDK_WIN32_MONITOR (needle)) == 0)
return GDK_MONITOR (m);
}
return NULL;
}
gboolean
_gdk_win32_display_init_monitors (GdkWin32Display *win32_display)
{
GdkDisplay *display = GDK_DISPLAY (win32_display);
GPtrArray *new_monitors;
gint i;
gboolean changed = FALSE;
GdkWin32Monitor *primary_to_move = NULL;
for (i = 0; i < win32_display->monitors->len; i++)
GDK_WIN32_MONITOR (g_ptr_array_index (win32_display->monitors, i))->remove = TRUE;
new_monitors = _gdk_win32_display_get_monitor_list (win32_display);
for (i = 0; i < new_monitors->len; i++)
{
GdkWin32Monitor *w32_m;
GdkMonitor *m;
GdkWin32Monitor *w32_ex_monitor;
GdkMonitor *ex_monitor;
GdkRectangle geometry, ex_geometry;
GdkRectangle workarea, ex_workarea;
w32_m = GDK_WIN32_MONITOR (g_ptr_array_index (new_monitors, i));
m = GDK_MONITOR (w32_m);
ex_monitor = _gdk_win32_display_find_matching_monitor (win32_display, m);
w32_ex_monitor = GDK_WIN32_MONITOR (ex_monitor);
if (ex_monitor == NULL)
{
w32_m->add = TRUE;
changed = TRUE;
continue;
}
w32_ex_monitor->remove = FALSE;
if (i == 0)
primary_to_move = w32_ex_monitor;
gdk_monitor_get_geometry (m, &geometry);
gdk_monitor_get_geometry (ex_monitor, &ex_geometry);
gdk_monitor_get_workarea (m, &workarea);
gdk_monitor_get_workarea (ex_monitor, &ex_workarea);
if (memcmp (&workarea, &ex_workarea, sizeof (GdkRectangle)) != 0)
{
w32_ex_monitor->work_rect = workarea;
changed = TRUE;
}
if (memcmp (&geometry, &ex_geometry, sizeof (GdkRectangle)) != 0)
{
gdk_monitor_set_size (ex_monitor, geometry.width, geometry.height);
gdk_monitor_set_position (ex_monitor, geometry.x, geometry.y);
changed = TRUE;
}
if (gdk_monitor_get_width_mm (m) != gdk_monitor_get_width_mm (ex_monitor) ||
gdk_monitor_get_height_mm (m) != gdk_monitor_get_height_mm (ex_monitor))
{
gdk_monitor_set_physical_size (ex_monitor,
gdk_monitor_get_width_mm (m),
gdk_monitor_get_height_mm (m));
changed = TRUE;
}
if (g_strcmp0 (gdk_monitor_get_model (m), gdk_monitor_get_model (ex_monitor)) != 0)
{
gdk_monitor_set_model (ex_monitor,
gdk_monitor_get_model (m));
changed = TRUE;
}
if (g_strcmp0 (gdk_monitor_get_manufacturer (m), gdk_monitor_get_manufacturer (ex_monitor)) != 0)
{
gdk_monitor_set_manufacturer (ex_monitor,
gdk_monitor_get_manufacturer (m));
changed = TRUE;
}
if (gdk_monitor_get_refresh_rate (m) != gdk_monitor_get_refresh_rate (ex_monitor))
{
gdk_monitor_set_refresh_rate (ex_monitor, gdk_monitor_get_refresh_rate (m));
changed = TRUE;
}
if (gdk_monitor_get_scale_factor (m) != gdk_monitor_get_scale_factor (ex_monitor))
{
gdk_monitor_set_scale_factor (ex_monitor, gdk_monitor_get_scale_factor (m));
changed = TRUE;
}
if (gdk_monitor_get_subpixel_layout (m) != gdk_monitor_get_subpixel_layout (ex_monitor))
{
gdk_monitor_set_subpixel_layout (ex_monitor, gdk_monitor_get_subpixel_layout (m));
changed = TRUE;
}
}
for (i = win32_display->monitors->len - 1; i >= 0; i--)
{
GdkWin32Monitor *w32_ex_monitor;
GdkMonitor *ex_monitor;
w32_ex_monitor = GDK_WIN32_MONITOR (g_ptr_array_index (win32_display->monitors, i));
ex_monitor = GDK_MONITOR (w32_ex_monitor);
if (!w32_ex_monitor->remove)
continue;
changed = TRUE;
gdk_display_monitor_removed (display, ex_monitor);
g_ptr_array_remove_index (win32_display->monitors, i);
}
for (i = 0; i < new_monitors->len; i++)
{
GdkWin32Monitor *w32_m;
GdkMonitor *m;
w32_m = GDK_WIN32_MONITOR (g_ptr_array_index (new_monitors, i));
m = GDK_MONITOR (w32_m);
if (!w32_m->add)
continue;
gdk_display_monitor_added (display, m);
if (i == 0)
g_ptr_array_insert (win32_display->monitors, 0, g_object_ref (w32_m));
else
g_ptr_array_add (win32_display->monitors, g_object_ref (w32_m));
}
g_ptr_array_free (new_monitors, TRUE);
if (primary_to_move)
{
g_ptr_array_remove (win32_display->monitors, g_object_ref (primary_to_move));
g_ptr_array_insert (win32_display->monitors, 0, primary_to_move);
changed = TRUE;
}
return changed;
}
/**
* gdk_win32_display_set_cursor_theme:
* @display: (type GdkWin32Display): a #GdkDisplay
* @name: (allow-none): the name of the cursor theme to use, or %NULL to unset
* a previously set value
* @size: the cursor size to use, or 0 to keep the previous size
*
* Sets the cursor theme from which the images for cursor
* should be taken.
*
* If the windowing system supports it, existing cursors created
* with gdk_cursor_new(), gdk_cursor_new_for_display() and
* gdk_cursor_new_from_name() are updated to reflect the theme
* change. Custom cursors constructed with
* gdk_cursor_new_from_texture() will have to be handled
* by the application (GTK+ applications can learn about
* cursor theme changes by listening for change notification
* for the corresponding #GtkSetting).
*/
void
gdk_win32_display_set_cursor_theme (GdkDisplay *display,
const gchar *name,
gint size)
{
gint cursor_size;
gint w, h;
Win32CursorTheme *theme;
GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (display);
g_assert (win32_display);
if (name == NULL)
name = "system";
w = GetSystemMetrics (SM_CXCURSOR);
h = GetSystemMetrics (SM_CYCURSOR);
/* We can load cursors of any size, but SetCursor() will scale them back
* to this value. It's possible to break that restrictions with SetSystemCursor(),
* but that will override cursors for the whole desktop session.
*/
cursor_size = (w == h) ? w : size;
if (win32_display->cursor_theme_name != NULL &&
g_strcmp0 (name, win32_display->cursor_theme_name) == 0 &&
win32_display->cursor_theme_size == cursor_size)
return;
theme = win32_cursor_theme_load (name, cursor_size);
if (theme == NULL)
{
g_warning ("Failed to load cursor theme %s", name);
return;
}
if (win32_display->cursor_theme)
{
win32_cursor_theme_destroy (win32_display->cursor_theme);
win32_display->cursor_theme = NULL;
}
win32_display->cursor_theme = theme;
g_free (win32_display->cursor_theme_name);
win32_display->cursor_theme_name = g_strdup (name);
win32_display->cursor_theme_size = cursor_size;
_gdk_win32_display_update_cursors (win32_display);
}
Win32CursorTheme *
_gdk_win32_display_get_cursor_theme (GdkWin32Display *win32_display)
{
Win32CursorTheme *theme;
g_assert (win32_display->cursor_theme_name);
theme = win32_display->cursor_theme;
if (!theme)
{
theme = win32_cursor_theme_load (win32_display->cursor_theme_name,
win32_display->cursor_theme_size);
if (theme == NULL)
{
g_warning ("Failed to load cursor theme %s",
win32_display->cursor_theme_name);
return NULL;
}
win32_display->cursor_theme = theme;
}
return theme;
}
static gulong
gdk_win32_display_get_next_serial (GdkDisplay *display)
{
return 0;
}
static LRESULT CALLBACK
inner_display_change_window_procedure (HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam)
{
switch (message)
{
case WM_DESTROY:
{
PostQuitMessage (0);
return 0;
}
case WM_DISPLAYCHANGE:
{
GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (_gdk_display);
_gdk_win32_screen_on_displaychange_event (GDK_WIN32_SCREEN (win32_display->screen));
return 0;
}
default:
/* Otherwise call DefWindowProcW(). */
GDK_NOTE (EVENTS, g_print (" DefWindowProcW"));
return DefWindowProc (hwnd, message, wparam, lparam);
}
}
static LRESULT CALLBACK
display_change_window_procedure (HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam)
{
LRESULT retval;
GDK_NOTE (EVENTS, g_print ("%s%*s%s %p",
(debug_indent > 0 ? "\n" : ""),
debug_indent, "",
_gdk_win32_message_to_string (message), hwnd));
debug_indent += 2;
retval = inner_display_change_window_procedure (hwnd, message, wparam, lparam);
debug_indent -= 2;
GDK_NOTE (EVENTS, g_print (" => %" G_GINT64_FORMAT "%s", (gint64) retval, (debug_indent == 0 ? "\n" : "")));
return retval;
}
/* Use a hidden window to be notified about display changes */
static void
register_display_change_notification (GdkDisplay *display)
{
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
WNDCLASS wclass = { 0, };
ATOM klass;
wclass.lpszClassName = "GdkDisplayChange";
wclass.lpfnWndProc = display_change_window_procedure;
wclass.hInstance = _gdk_app_hmodule;
klass = RegisterClass (&wclass);
if (klass)
{
display_win32->hwnd = CreateWindow (MAKEINTRESOURCE (klass),
NULL, WS_POPUP,
0, 0, 0, 0, NULL, NULL,
_gdk_app_hmodule, NULL);
if (!display_win32->hwnd)
{
UnregisterClass (MAKEINTRESOURCE (klass), _gdk_app_hmodule);
}
}
}
GdkDisplay *
_gdk_win32_display_open (const gchar *display_name)
{
GdkWin32Display *win32_display;
GDK_NOTE (MISC, g_print ("gdk_display_open: %s\n", (display_name ? display_name : "NULL")));
if (display_name == NULL ||
g_ascii_strcasecmp (display_name,
gdk_display_get_name (_gdk_display)) == 0)
{
if (_gdk_display != NULL)
{
GDK_NOTE (MISC, g_print ("... return _gdk_display\n"));
return _gdk_display;
}
}
else
{
GDK_NOTE (MISC, g_print ("... return NULL\n"));
return NULL;
}
_gdk_display = g_object_new (GDK_TYPE_WIN32_DISPLAY, NULL);
win32_display = GDK_WIN32_DISPLAY (_gdk_display);
win32_display->screen = g_object_new (GDK_TYPE_WIN32_SCREEN, NULL);
_gdk_events_init (_gdk_display);
_gdk_input_ignore_core = 0;
_gdk_device_manager = g_object_new (GDK_TYPE_DEVICE_MANAGER_WIN32,
NULL);
_gdk_device_manager->display = _gdk_display;
_gdk_dnd_init ();
/* Precalculate display name */
(void) gdk_display_get_name (_gdk_display);
register_display_change_notification (_gdk_display);
g_signal_emit_by_name (_gdk_display, "opened");
GDK_NOTE (MISC, g_print ("... _gdk_display now set up\n"));
return _gdk_display;
}
G_DEFINE_TYPE (GdkWin32Display, gdk_win32_display, GDK_TYPE_DISPLAY)
static const gchar *
gdk_win32_display_get_name (GdkDisplay *display)
{
HDESK hdesk = GetThreadDesktop (GetCurrentThreadId ());
char dummy;
char *desktop_name;
HWINSTA hwinsta = GetProcessWindowStation ();
char *window_station_name;
DWORD n;
DWORD session_id;
char *display_name;
static const char *display_name_cache = NULL;
typedef BOOL (WINAPI *PFN_ProcessIdToSessionId) (DWORD, DWORD *);
PFN_ProcessIdToSessionId processIdToSessionId;
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
if (display_name_cache != NULL)
return display_name_cache;
n = 0;
GetUserObjectInformation (hdesk, UOI_NAME, &dummy, 0, &n);
if (n == 0)
desktop_name = "Default";
else
{
n++;
desktop_name = g_alloca (n + 1);
memset (desktop_name, 0, n + 1);
if (!GetUserObjectInformation (hdesk, UOI_NAME, desktop_name, n, &n))
desktop_name = "Default";
}
n = 0;
GetUserObjectInformation (hwinsta, UOI_NAME, &dummy, 0, &n);
if (n == 0)
window_station_name = "WinSta0";
else
{
n++;
window_station_name = g_alloca (n + 1);
memset (window_station_name, 0, n + 1);
if (!GetUserObjectInformation (hwinsta, UOI_NAME, window_station_name, n, &n))
window_station_name = "WinSta0";
}
processIdToSessionId = (PFN_ProcessIdToSessionId) GetProcAddress (GetModuleHandle ("kernel32.dll"), "ProcessIdToSessionId");
if (!processIdToSessionId || !processIdToSessionId (GetCurrentProcessId (), &session_id))
session_id = 0;
display_name = g_strdup_printf ("%ld\\%s\\%s",
session_id,
window_station_name,
desktop_name);
GDK_NOTE (MISC, g_print ("gdk_win32_display_get_name: %s\n", display_name));
display_name_cache = display_name;
return display_name_cache;
}
static GdkSurface *
gdk_win32_display_get_default_group (GdkDisplay *display)
{
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
g_warning ("gdk_display_get_default_group not yet implemented");
return NULL;
}
static HWND _hwnd_next_viewer = NULL;
/*
* maybe this should be integrated with the default message loop - or maybe not ;-)
*/
static LRESULT CALLBACK
inner_clipboard_window_procedure (HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam)
{
switch (message)
{
case WM_DESTROY: /* remove us from chain */
{
ChangeClipboardChain (hwnd, _hwnd_next_viewer);
PostQuitMessage (0);
return 0;
}
case WM_CHANGECBCHAIN:
{
HWND hwndRemove = (HWND) wparam; /* handle of window being removed */
HWND hwndNext = (HWND) lparam; /* handle of next window in chain */
if (hwndRemove == _hwnd_next_viewer)
_hwnd_next_viewer = hwndNext == hwnd ? NULL : hwndNext;
else if (_hwnd_next_viewer != NULL)
return SendMessage (_hwnd_next_viewer, message, wparam, lparam);
return 0;
}
case WM_CLIPBOARDUPDATE:
case WM_DRAWCLIPBOARD:
{
HWND hwnd_owner;
HWND hwnd_opener;
/*
GdkEvent *event;
*/
GdkWin32Selection *win32_sel = _gdk_win32_selection_get ();
hwnd_owner = GetClipboardOwner ();
if ((hwnd_owner == NULL) &&
(GetLastError () != ERROR_SUCCESS))
WIN32_API_FAILED ("GetClipboardOwner");
hwnd_opener = GetOpenClipboardWindow ();
GDK_NOTE (DND, g_print (" drawclipboard owner: %p; opener %p ", hwnd_owner, hwnd_opener));
#ifdef G_ENABLE_DEBUG
if (_gdk_debug_flags & GDK_DEBUG_DND)
{
if (win32_sel->clipboard_opened_for != INVALID_HANDLE_VALUE ||
OpenClipboard (hwnd))
{
UINT nFormat = 0;
while ((nFormat = EnumClipboardFormats (nFormat)) != 0)
g_print ("%s ", _gdk_win32_cf_to_string (nFormat));
if (win32_sel->clipboard_opened_for == INVALID_HANDLE_VALUE)
CloseClipboard ();
}
else
{
WIN32_API_FAILED ("OpenClipboard");
}
}
#endif
GDK_NOTE (DND, g_print (" \n"));
if (win32_sel->stored_hwnd_owner != hwnd_owner)
{
if (win32_sel->clipboard_opened_for != INVALID_HANDLE_VALUE)
{
CloseClipboard ();
GDK_NOTE (DND, g_print ("Closed clipboard @ %s:%d\n", __FILE__, __LINE__));
}
win32_sel->clipboard_opened_for = INVALID_HANDLE_VALUE;
win32_sel->stored_hwnd_owner = hwnd_owner;
_gdk_win32_clear_clipboard_queue ();
}
/* GDK_OWNER_CHANGE does not exist anymore since 437d70f56919916e884a81d3bff0170322ab2906
event = gdk_event_new (GDK_OWNER_CHANGE);
event->owner_change.window = NULL;
event->owner_change.reason = GDK_OWNER_CHANGE_NEW_OWNER;
event->owner_change.selection = GDK_SELECTION_CLIPBOARD;
event->owner_change.time = _gdk_win32_get_next_tick (0);
event->owner_change.selection_time = GDK_CURRENT_TIME;
_gdk_win32_append_event (event);
*/
if (_hwnd_next_viewer != NULL)
return SendMessage (_hwnd_next_viewer, message, wparam, lparam);
/* clear error to avoid confusing SetClipboardViewer() return */
SetLastError (0);
return 0;
}
default:
/* Otherwise call DefWindowProcW(). */
GDK_NOTE (EVENTS, g_print (" DefWindowProcW"));
return DefWindowProc (hwnd, message, wparam, lparam);
}
}
static LRESULT CALLBACK
_clipboard_window_procedure (HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam)
{
LRESULT retval;
GDK_NOTE (EVENTS, g_print ("%s%*s%s %p",
(debug_indent > 0 ? "\n" : ""),
debug_indent, "",
_gdk_win32_message_to_string (message), hwnd));
debug_indent += 2;
retval = inner_clipboard_window_procedure (hwnd, message, wparam, lparam);
debug_indent -= 2;
GDK_NOTE (EVENTS, g_print (" => %" G_GINT64_FORMAT "%s", (gint64) retval, (debug_indent == 0 ? "\n" : "")));
return retval;
}
/*
* Creates a hidden window and adds it to the clipboard chain
*/
static gboolean
register_clipboard_notification (GdkDisplay *display)
{
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
WNDCLASS wclass = { 0, };
ATOM klass;
wclass.lpszClassName = "GdkClipboardNotification";
wclass.lpfnWndProc = _clipboard_window_procedure;
wclass.hInstance = _gdk_app_hmodule;
klass = RegisterClass (&wclass);
if (!klass)
return FALSE;
display_win32->clipboard_hwnd = CreateWindow (MAKEINTRESOURCE (klass),
NULL, WS_POPUP,
0, 0, 0, 0, NULL, NULL,
_gdk_app_hmodule, NULL);
if (display_win32->clipboard_hwnd == NULL)
goto failed;
SetLastError (0);
_hwnd_next_viewer = SetClipboardViewer (display_win32->clipboard_hwnd);
if (_hwnd_next_viewer == NULL && GetLastError() != 0)
goto failed;
/* FIXME: http://msdn.microsoft.com/en-us/library/ms649033(v=VS.85).aspx */
/* This is only supported by Vista, and not yet by mingw64 */
/* if (AddClipboardFormatListener (hwnd) == FALSE) */
/* goto failed; */
return TRUE;
failed:
g_critical ("Failed to install clipboard viewer");
UnregisterClass (MAKEINTRESOURCE (klass), _gdk_app_hmodule);
return FALSE;
}
static gboolean
gdk_win32_display_supports_shapes (GdkDisplay *display)
{
g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
return TRUE;
}
static gboolean
gdk_win32_display_supports_input_shapes (GdkDisplay *display)
{
g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
/* Partially supported, see WM_NCHITTEST handler. */
return TRUE;
}
static void
gdk_win32_display_beep (GdkDisplay *display)
{
g_return_if_fail (display == gdk_display_get_default());
if (!MessageBeep (-1))
Beep(1000, 50);
}
static void
gdk_win32_display_flush (GdkDisplay * display)
{
g_return_if_fail (display == _gdk_display);
GdiFlush ();
}
static void
gdk_win32_display_sync (GdkDisplay * display)
{
g_return_if_fail (display == _gdk_display);
GdiFlush ();
}
static void
gdk_win32_display_dispose (GObject *object)
{
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (object);
if (display_win32->hwnd != NULL)
{
DestroyWindow (display_win32->hwnd);
display_win32->hwnd = NULL;
}
if (display_win32->clipboard_hwnd != NULL)
{
DestroyWindow (display_win32->clipboard_hwnd);
display_win32->clipboard_hwnd = NULL;
_hwnd_next_viewer = NULL;
}
if (display_win32->have_at_least_win81)
{
if (display_win32->shcore_funcs.hshcore != NULL)
{
FreeLibrary (display_win32->shcore_funcs.hshcore);
display_win32->shcore_funcs.hshcore = NULL;
}
}
G_OBJECT_CLASS (gdk_win32_display_parent_class)->dispose (object);
}
static void
gdk_win32_display_finalize (GObject *object)
{
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (object);
_gdk_win32_display_finalize_cursors (display_win32);
_gdk_win32_dnd_exit ();
g_ptr_array_free (display_win32->monitors, TRUE);
G_OBJECT_CLASS (gdk_win32_display_parent_class)->finalize (object);
}
static void
_gdk_win32_enable_hidpi (GdkWin32Display *display)
{
gboolean check_for_dpi_awareness = FALSE;
gboolean have_hpi_disable_envvar = FALSE;
enum dpi_aware_status {
DPI_STATUS_PENDING,
DPI_STATUS_SUCCESS,
DPI_STATUS_DISABLED,
DPI_STATUS_FAILED
} status = DPI_STATUS_PENDING;
if (g_win32_check_windows_version (6, 3, 0, G_WIN32_OS_ANY))
{
/* If we are on Windows 8.1 or later, cache up functions from shcore.dll, by all means */
display->have_at_least_win81 = TRUE;
display->shcore_funcs.hshcore = LoadLibraryW (L"shcore.dll");
if (display->shcore_funcs.hshcore != NULL)
{
display->shcore_funcs.setDpiAwareFunc =
(funcSetProcessDpiAwareness) GetProcAddress (display->shcore_funcs.hshcore,
"SetProcessDpiAwareness");
display->shcore_funcs.getDpiAwareFunc =
(funcGetProcessDpiAwareness) GetProcAddress (display->shcore_funcs.hshcore,
"GetProcessDpiAwareness");
display->shcore_funcs.getDpiForMonitorFunc =
(funcGetDpiForMonitor) GetProcAddress (display->shcore_funcs.hshcore,
"GetDpiForMonitor");
}
}
else
{
/* Windows Vista through 8: use functions from user32.dll directly */
HMODULE user32;
display->have_at_least_win81 = FALSE;
user32 = GetModuleHandleW (L"user32.dll");
if (user32 != NULL)
{
display->user32_dpi_funcs.setDpiAwareFunc =
(funcSetProcessDPIAware) GetProcAddress (user32, "SetProcessDPIAware");
display->user32_dpi_funcs.isDpiAwareFunc =
(funcIsProcessDPIAware) GetProcAddress (user32, "IsProcessDPIAware");
}
}
if (g_getenv ("GDK_WIN32_DISABLE_HIDPI") == NULL)
{
/* For Windows 8.1 and later, use SetProcessDPIAwareness() */
if (display->have_at_least_win81)
{
/* then make the GDK-using app DPI-aware */
if (display->shcore_funcs.setDpiAwareFunc != NULL)
{
GdkWin32ProcessDpiAwareness hidpi_mode;
/* TODO: See how per-monitor DPI awareness is done by the Wayland backend */
if (g_getenv ("GDK_WIN32_PER_MONITOR_HIDPI") != NULL)
hidpi_mode = PROCESS_PER_MONITOR_DPI_AWARE;
else
hidpi_mode = PROCESS_SYSTEM_DPI_AWARE;
switch (display->shcore_funcs.setDpiAwareFunc (hidpi_mode))
{
case S_OK:
display->dpi_aware_type = hidpi_mode;
status = DPI_STATUS_SUCCESS;
break;
case E_ACCESSDENIED:
/* This means the app used a manifest to set DPI awareness, or a
DPI compatibility setting is used.
The manifest is the trump card in this game of bridge here. The
same applies if one uses the control panel or program properties to
force system DPI awareness */
check_for_dpi_awareness = TRUE;
break;
default:
display->dpi_aware_type = PROCESS_DPI_UNAWARE;
status = DPI_STATUS_FAILED;
break;
}
}
else
{
check_for_dpi_awareness = TRUE;
}
}
else
{
/* For Windows Vista through 8, use SetProcessDPIAware() */
display->have_at_least_win81 = FALSE;
if (display->user32_dpi_funcs.setDpiAwareFunc != NULL)
{
if (display->user32_dpi_funcs.setDpiAwareFunc () != 0)
{
display->dpi_aware_type = PROCESS_SYSTEM_DPI_AWARE;
status = DPI_STATUS_SUCCESS;
}
else
{
check_for_dpi_awareness = TRUE;
}
}
else
{
display->dpi_aware_type = PROCESS_DPI_UNAWARE;
status = DPI_STATUS_FAILED;
}
}
}
else
{
/* if GDK_WIN32_DISABLE_HIDPI is set, check for any DPI
* awareness settings done via manifests or user settings
*/
check_for_dpi_awareness = TRUE;
have_hpi_disable_envvar = TRUE;
}
if (check_for_dpi_awareness)
{
if (display->have_at_least_win81)
{
if (display->shcore_funcs.getDpiAwareFunc != NULL)
{
display->shcore_funcs.getDpiAwareFunc (NULL, &display->dpi_aware_type);
if (display->dpi_aware_type != PROCESS_DPI_UNAWARE)
status = DPI_STATUS_SUCCESS;
else
/* This means the DPI awareness setting was forcefully disabled */
status = DPI_STATUS_DISABLED;
}
else
{
display->dpi_aware_type = PROCESS_DPI_UNAWARE;
status = DPI_STATUS_FAILED;
}
}
else
{
if (display->user32_dpi_funcs.isDpiAwareFunc != NULL)
{
/* This most probably means DPI awareness is set through
the manifest, or a DPI compatibility setting is used. */
display->dpi_aware_type = display->user32_dpi_funcs.isDpiAwareFunc () ?
PROCESS_SYSTEM_DPI_AWARE :
PROCESS_DPI_UNAWARE;
if (display->dpi_aware_type == PROCESS_SYSTEM_DPI_AWARE)
status = DPI_STATUS_SUCCESS;
else
status = DPI_STATUS_DISABLED;
}
else
{
display->dpi_aware_type = PROCESS_DPI_UNAWARE;
status = DPI_STATUS_FAILED;
}
}
if (have_hpi_disable_envvar &&
status == DPI_STATUS_SUCCESS)
{
/* The user setting or application manifest trumps over GDK_WIN32_DISABLE_HIDPI */
g_print ("Note: GDK_WIN32_DISABLE_HIDPI is ignored due to preset\n"
" DPI awareness settings in user settings or application\n"
" manifest, DPI awareness is still enabled.");
}
}
switch (status)
{
case DPI_STATUS_SUCCESS:
GDK_NOTE (MISC, g_message ("HiDPI support enabled, type: %s",
display->dpi_aware_type == PROCESS_PER_MONITOR_DPI_AWARE ? "per-monitor" : "system"));
break;
case DPI_STATUS_DISABLED:
GDK_NOTE (MISC, g_message ("HiDPI support disabled via manifest"));
break;
case DPI_STATUS_FAILED:
g_warning ("Failed to enable HiDPI support.");
}
}
static void
gdk_win32_display_init (GdkWin32Display *display)
{
const gchar *scale_str = g_getenv ("GDK_SCALE");
display->monitors = g_ptr_array_new_with_free_func (g_object_unref);
_gdk_win32_enable_hidpi (display);
/* if we have DPI awareness, set up fixed scale if set */
if (display->dpi_aware_type != PROCESS_DPI_UNAWARE &&
scale_str != NULL)
{
display->surface_scale = atol (scale_str);
if (display->surface_scale == 0)
display->surface_scale = 1;
display->has_fixed_scale = TRUE;
}
else
display->surface_scale = 1;
_gdk_win32_display_init_cursors (display);
gdk_win32_display_check_composited (display);
}
void
gdk_win32_display_check_composited (GdkWin32Display *display)
{
gboolean composited;
/* On Windows 8 and later, DWM (composition) is always enabled */
if (g_win32_check_windows_version (6, 2, 0, G_WIN32_OS_ANY))
{
composited = TRUE;
}
else
{
if (DwmIsCompositionEnabled (&composited) != S_OK)
composited = FALSE;
}
gdk_display_set_composited (GDK_DISPLAY (display), composited);
}
static void
gdk_win32_display_notify_startup_complete (GdkDisplay *display,
const gchar *startup_id)
{
/* nothing */
}
static int
gdk_win32_display_get_n_monitors (GdkDisplay *display)
{
GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (display);
return win32_display->monitors->len;
}
static GdkMonitor *
gdk_win32_display_get_monitor (GdkDisplay *display,
int monitor_num)
{
GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (display);
if (monitor_num < 0 || monitor_num >= win32_display->monitors->len)
return NULL;
return (GdkMonitor *) g_ptr_array_index (win32_display->monitors, monitor_num);
}
static GdkMonitor *
gdk_win32_display_get_primary_monitor (GdkDisplay *display)
{
GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (display);
/* We arrange for the first monitor in the array to also be the primiary monitor */
if (win32_display->monitors->len > 0)
return (GdkMonitor *) g_ptr_array_index (win32_display->monitors, 0);
return NULL;
}
guint
_gdk_win32_display_get_monitor_scale_factor (GdkWin32Display *win32_display,
HMONITOR hmonitor,
HWND hwnd,
gint *dpi)
{
gboolean is_scale_acquired = FALSE;
gboolean use_dpi_for_monitor = FALSE;
guint dpix, dpiy;
if (win32_display->have_at_least_win81)
{
if (hmonitor != NULL)
use_dpi_for_monitor = TRUE;
else
{
if (hwnd != NULL)
{
hmonitor = MonitorFromWindow (hwnd, MONITOR_DEFAULTTONEAREST);
use_dpi_for_monitor = TRUE;
}
}
}
if (use_dpi_for_monitor)
{
/* Use GetDpiForMonitor() for Windows 8.1+, when we have a HMONITOR */
if (win32_display->shcore_funcs.hshcore != NULL &&
win32_display->shcore_funcs.getDpiForMonitorFunc != NULL)
{
if (win32_display->shcore_funcs.getDpiForMonitorFunc (hmonitor,
MDT_EFFECTIVE_DPI,
&dpix,
&dpiy) == S_OK)
{
is_scale_acquired = TRUE;
}
}
}
else
{
/* Go back to GetDeviceCaps() for Windows 8 and earler, or when we don't
* have a HMONITOR nor a HWND
*/
HDC hdc = GetDC (hwnd);
/* in case we can't get the DC for the window, return 1 for the scale */
if (hdc == NULL)
{
if (dpi != NULL)
*dpi = USER_DEFAULT_SCREEN_DPI;
return 1;
}
dpix = GetDeviceCaps (hdc, LOGPIXELSX);
dpiy = GetDeviceCaps (hdc, LOGPIXELSY);
ReleaseDC (hwnd, hdc);
is_scale_acquired = TRUE;
}
if (is_scale_acquired)
/* USER_DEFAULT_SCREEN_DPI = 96, in winuser.h */
{
if (dpi != NULL)
*dpi = dpix;
if (win32_display->has_fixed_scale)
return win32_display->surface_scale;
else
return dpix / USER_DEFAULT_SCREEN_DPI > 1 ? dpix / USER_DEFAULT_SCREEN_DPI : 1;
}
else
{
if (dpi != NULL)
*dpi = USER_DEFAULT_SCREEN_DPI;
return 1;
}
}
static gboolean
gdk_win32_display_get_setting (GdkDisplay *display,
const gchar *name,
GValue *value)
{
return _gdk_win32_get_setting (name, value);
}
static guint32
gdk_win32_display_get_last_seen_time (GdkDisplay *display)
{
return GetMessageTime ();
}
static void
gdk_win32_display_class_init (GdkWin32DisplayClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdkDisplayClass *display_class = GDK_DISPLAY_CLASS (klass);
object_class->dispose = gdk_win32_display_dispose;
object_class->finalize = gdk_win32_display_finalize;
display_class->surface_type = GDK_TYPE_WIN32_SURFACE;
display_class->get_name = gdk_win32_display_get_name;
display_class->beep = gdk_win32_display_beep;
display_class->sync = gdk_win32_display_sync;
display_class->flush = gdk_win32_display_flush;
display_class->has_pending = _gdk_win32_display_has_pending;
display_class->queue_events = _gdk_win32_display_queue_events;
display_class->get_default_group = gdk_win32_display_get_default_group;
display_class->supports_shapes = gdk_win32_display_supports_shapes;
display_class->supports_input_shapes = gdk_win32_display_supports_input_shapes;
//? display_class->get_app_launch_context = _gdk_win32_display_get_app_launch_context;
display_class->get_default_cursor_size = _gdk_win32_display_get_default_cursor_size;
display_class->get_maximal_cursor_size = _gdk_win32_display_get_maximal_cursor_size;
display_class->supports_cursor_alpha = _gdk_win32_display_supports_cursor_alpha;
display_class->supports_cursor_color = _gdk_win32_display_supports_cursor_color;
display_class->get_next_serial = gdk_win32_display_get_next_serial;
display_class->notify_startup_complete = gdk_win32_display_notify_startup_complete;
display_class->create_surface_impl = _gdk_win32_display_create_surface_impl;
display_class->get_keymap = _gdk_win32_display_get_keymap;
display_class->text_property_to_utf8_list = _gdk_win32_display_text_property_to_utf8_list;
display_class->utf8_to_string_target = _gdk_win32_display_utf8_to_string_target;
display_class->make_gl_context_current = _gdk_win32_display_make_gl_context_current;
display_class->get_n_monitors = gdk_win32_display_get_n_monitors;
display_class->get_monitor = gdk_win32_display_get_monitor;
display_class->get_primary_monitor = gdk_win32_display_get_primary_monitor;
#ifdef GDK_RENDERING_VULKAN
display_class->vk_context_type = GDK_TYPE_WIN32_VULKAN_CONTEXT;
display_class->vk_extension_name = VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
#endif
display_class->get_setting = gdk_win32_display_get_setting;
display_class->get_last_seen_time = gdk_win32_display_get_last_seen_time;
display_class->set_cursor_theme = gdk_win32_display_set_cursor_theme;
_gdk_win32_surfaceing_init ();
}