2010-05-25 22:38:44 +00:00
|
|
|
/* GDK - The GIMP Drawing Kit
|
|
|
|
* Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
|
|
|
|
*
|
|
|
|
* 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
|
2012-02-27 13:01:10 +00:00
|
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
2010-05-25 22:38:44 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2018-03-20 10:46:11 +00:00
|
|
|
#include <gdk/gdksurface.h>
|
2010-05-25 22:38:44 +00:00
|
|
|
|
|
|
|
#include <windowsx.h>
|
|
|
|
#include <objbase.h>
|
2019-03-27 22:47:56 +00:00
|
|
|
#include <math.h>
|
2010-05-25 22:38:44 +00:00
|
|
|
|
|
|
|
#include "gdkdevice-win32.h"
|
|
|
|
#include "gdkwin32.h"
|
2017-11-17 07:27:10 +00:00
|
|
|
#include "gdkdisplay-win32.h"
|
2020-08-26 19:31:45 +00:00
|
|
|
#include "gdkdevice-virtual.h"
|
|
|
|
#include "gdkdevice-wintab.h"
|
2010-05-25 22:38:44 +00:00
|
|
|
|
|
|
|
G_DEFINE_TYPE (GdkDeviceWin32, gdk_device_win32, GDK_TYPE_DEVICE)
|
|
|
|
|
|
|
|
static void
|
2018-03-20 11:05:26 +00:00
|
|
|
gdk_device_win32_set_surface_cursor (GdkDevice *device,
|
2018-03-20 10:40:08 +00:00
|
|
|
GdkSurface *window,
|
2010-05-25 22:38:44 +00:00
|
|
|
GdkCursor *cursor)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static GdkModifierType
|
|
|
|
get_current_mask (void)
|
|
|
|
{
|
|
|
|
GdkModifierType mask;
|
|
|
|
BYTE kbd[256];
|
|
|
|
|
|
|
|
GetKeyboardState (kbd);
|
|
|
|
mask = 0;
|
|
|
|
if (kbd[VK_SHIFT] & 0x80)
|
|
|
|
mask |= GDK_SHIFT_MASK;
|
|
|
|
if (kbd[VK_CAPITAL] & 0x80)
|
|
|
|
mask |= GDK_LOCK_MASK;
|
|
|
|
if (kbd[VK_CONTROL] & 0x80)
|
|
|
|
mask |= GDK_CONTROL_MASK;
|
|
|
|
if (kbd[VK_MENU] & 0x80)
|
2020-04-05 13:39:03 +00:00
|
|
|
mask |= GDK_ALT_MASK;
|
2010-05-25 22:38:44 +00:00
|
|
|
if (kbd[VK_LBUTTON] & 0x80)
|
|
|
|
mask |= GDK_BUTTON1_MASK;
|
|
|
|
if (kbd[VK_MBUTTON] & 0x80)
|
|
|
|
mask |= GDK_BUTTON2_MASK;
|
|
|
|
if (kbd[VK_RBUTTON] & 0x80)
|
|
|
|
mask |= GDK_BUTTON3_MASK;
|
|
|
|
|
|
|
|
return mask;
|
|
|
|
}
|
|
|
|
|
2012-03-09 12:20:41 +00:00
|
|
|
static void
|
2010-05-25 22:38:44 +00:00
|
|
|
gdk_device_win32_query_state (GdkDevice *device,
|
2020-03-12 11:01:30 +00:00
|
|
|
GdkSurface *window,
|
|
|
|
GdkSurface **child_window,
|
|
|
|
double *win_x,
|
|
|
|
double *win_y,
|
2010-05-25 22:38:44 +00:00
|
|
|
GdkModifierType *mask)
|
|
|
|
{
|
|
|
|
POINT point;
|
|
|
|
HWND hwnd, hwndc;
|
2020-07-24 13:54:49 +00:00
|
|
|
int scale;
|
2010-05-25 22:38:44 +00:00
|
|
|
|
2017-11-14 23:05:41 +00:00
|
|
|
if (window)
|
|
|
|
{
|
2019-05-19 03:09:05 +00:00
|
|
|
scale = GDK_WIN32_SURFACE (window)->surface_scale;
|
2018-03-20 10:40:08 +00:00
|
|
|
hwnd = GDK_SURFACE_HWND (window);
|
2017-11-14 23:05:41 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GdkDisplay *display = gdk_device_get_display (device);
|
|
|
|
|
2018-03-20 11:05:26 +00:00
|
|
|
scale = GDK_WIN32_DISPLAY (display)->surface_scale;
|
2017-11-14 23:05:41 +00:00
|
|
|
hwnd = NULL;
|
|
|
|
}
|
2015-12-17 23:36:57 +00:00
|
|
|
|
2021-08-16 12:39:25 +00:00
|
|
|
_gdk_win32_get_cursor_pos (&point);
|
2010-05-25 22:38:44 +00:00
|
|
|
|
2017-11-14 23:05:41 +00:00
|
|
|
if (hwnd)
|
|
|
|
ScreenToClient (hwnd, &point);
|
2010-05-25 22:38:44 +00:00
|
|
|
|
|
|
|
if (win_x)
|
2017-11-14 23:05:41 +00:00
|
|
|
*win_x = point.x / scale;
|
2010-05-25 22:38:44 +00:00
|
|
|
|
|
|
|
if (win_y)
|
2017-11-14 23:05:41 +00:00
|
|
|
*win_y = point.y / scale;
|
2010-05-25 22:38:44 +00:00
|
|
|
|
2017-11-14 23:05:41 +00:00
|
|
|
if (hwnd && child_window)
|
2010-05-25 22:38:44 +00:00
|
|
|
{
|
|
|
|
hwndc = ChildWindowFromPoint (hwnd, point);
|
|
|
|
|
|
|
|
if (hwndc && hwndc != hwnd)
|
2022-08-24 17:01:45 +00:00
|
|
|
*child_window = gdk_win32_handle_table_lookup_ (hwndc);
|
2010-05-25 22:38:44 +00:00
|
|
|
else
|
|
|
|
*child_window = NULL; /* Direct child unknown to gdk */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mask)
|
|
|
|
*mask = get_current_mask ();
|
|
|
|
}
|
|
|
|
|
2020-08-26 19:31:45 +00:00
|
|
|
void
|
|
|
|
_gdk_device_win32_query_state (GdkDevice *device,
|
|
|
|
GdkSurface *window,
|
|
|
|
GdkSurface **child_window,
|
|
|
|
double *win_x,
|
|
|
|
double *win_y,
|
|
|
|
GdkModifierType *mask)
|
|
|
|
{
|
|
|
|
if (GDK_IS_DEVICE_VIRTUAL (device))
|
|
|
|
gdk_device_virtual_query_state (device, window, child_window, win_x, win_y, mask);
|
|
|
|
else if (GDK_IS_DEVICE_WINTAB (device))
|
|
|
|
gdk_device_wintab_query_state (device, window, child_window, win_x, win_y, mask);
|
|
|
|
else
|
|
|
|
gdk_device_win32_query_state (device, window, child_window, win_x, win_y, mask);
|
|
|
|
}
|
|
|
|
|
2010-05-25 22:38:44 +00:00
|
|
|
static GdkGrabStatus
|
|
|
|
gdk_device_win32_grab (GdkDevice *device,
|
2018-03-20 10:40:08 +00:00
|
|
|
GdkSurface *window,
|
2010-05-25 22:38:44 +00:00
|
|
|
gboolean owner_events,
|
|
|
|
GdkEventMask event_mask,
|
2018-03-20 10:40:08 +00:00
|
|
|
GdkSurface *confine_to,
|
2010-05-25 22:38:44 +00:00
|
|
|
GdkCursor *cursor,
|
|
|
|
guint32 time_)
|
|
|
|
{
|
2020-06-18 18:22:20 +00:00
|
|
|
/* No support for grabbing physical devices atm */
|
2012-03-30 12:59:17 +00:00
|
|
|
return GDK_GRAB_NOT_VIEWABLE;
|
2010-05-25 22:38:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_device_win32_ungrab (GdkDevice *device,
|
|
|
|
guint32 time_)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
Win32: Fix _gdk_windowing_window_at_pointer to correctly return a toplevel
Commit 5ebb32d1ffa23241d562fb4d5be02bc6f156b515 didn't add the correct
code to find the toplevel window. The WindowFromPoint() function does
not return the toplevel window in the hierarchy, it returns the deepest
non-disabled, non-invisible child. As we don't use invisible or disabled
windows, we don't actually need to use the ChildWindowFromPoint walk for
the non get_toplevel case, so we can remove that code path.
To find a toplevel, we need to start from the desktop and work up, using
ChildWindowFromPointEx (to ignore invisible and disabled windows). If we
don't ignore invisible and disabled windows (as is the case with the
ChildWindowFromPoint call, we are liable to get returns of hidden or
disabled children of the desktop which don't belong to us, but notionally
occupy the same area under the pointer.
An alternative might be to start our walk with one of the children of the
desktop owned by our process and thread - which we can enumerate using,
the EnumThreadWindows call, or (presumably) determine internally. This
would not work when we are inside a GtkSocket though, as the children of
the desktop would belong to the process owning the GtkPlug - we would
have to rely on our own list of windows.
For correctness, this commit adds tests to ensure that we don't try to
return either x or y window coordinates if that corresponding pointer is
NULL.
https://bugzilla.gnome.org/show_bug.cgi?id=658842
2011-09-10 15:30:56 +00:00
|
|
|
static void
|
|
|
|
screen_to_client (HWND hwnd, POINT screen_pt, POINT *client_pt)
|
|
|
|
{
|
|
|
|
*client_pt = screen_pt;
|
|
|
|
ScreenToClient (hwnd, client_pt);
|
|
|
|
}
|
|
|
|
|
2018-03-20 10:40:08 +00:00
|
|
|
GdkSurface *
|
|
|
|
_gdk_device_win32_surface_at_position (GdkDevice *device,
|
2020-07-24 20:32:16 +00:00
|
|
|
double *win_x,
|
|
|
|
double *win_y,
|
2020-05-19 19:00:32 +00:00
|
|
|
GdkModifierType *mask)
|
2010-05-25 22:38:44 +00:00
|
|
|
{
|
2018-03-20 10:40:08 +00:00
|
|
|
GdkSurface *window = NULL;
|
2019-05-19 03:09:05 +00:00
|
|
|
GdkWin32Surface *impl = NULL;
|
Win32: Fix _gdk_windowing_window_at_pointer to correctly return a toplevel
Commit 5ebb32d1ffa23241d562fb4d5be02bc6f156b515 didn't add the correct
code to find the toplevel window. The WindowFromPoint() function does
not return the toplevel window in the hierarchy, it returns the deepest
non-disabled, non-invisible child. As we don't use invisible or disabled
windows, we don't actually need to use the ChildWindowFromPoint walk for
the non get_toplevel case, so we can remove that code path.
To find a toplevel, we need to start from the desktop and work up, using
ChildWindowFromPointEx (to ignore invisible and disabled windows). If we
don't ignore invisible and disabled windows (as is the case with the
ChildWindowFromPoint call, we are liable to get returns of hidden or
disabled children of the desktop which don't belong to us, but notionally
occupy the same area under the pointer.
An alternative might be to start our walk with one of the children of the
desktop owned by our process and thread - which we can enumerate using,
the EnumThreadWindows call, or (presumably) determine internally. This
would not work when we are inside a GtkSocket though, as the children of
the desktop would belong to the process owning the GtkPlug - we would
have to rely on our own list of windows.
For correctness, this commit adds tests to ensure that we don't try to
return either x or y window coordinates if that corresponding pointer is
NULL.
https://bugzilla.gnome.org/show_bug.cgi?id=658842
2011-09-10 15:30:56 +00:00
|
|
|
POINT screen_pt, client_pt;
|
2020-11-06 21:43:45 +00:00
|
|
|
HWND hwnd;
|
2010-05-25 22:38:44 +00:00
|
|
|
RECT rect;
|
|
|
|
|
2021-08-16 12:39:25 +00:00
|
|
|
if (!_gdk_win32_get_cursor_pos (&screen_pt))
|
2020-11-06 21:43:45 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Use WindowFromPoint instead of ChildWindowFromPoint(Ex).
|
|
|
|
* Only WindowFromPoint is able to look through transparent
|
|
|
|
* layered windows.
|
|
|
|
*/
|
|
|
|
hwnd = GetAncestor (WindowFromPoint (screen_pt), GA_ROOT);
|
|
|
|
|
|
|
|
/* Verify that we're really inside the client area of the window */
|
|
|
|
GetClientRect (hwnd, &rect);
|
|
|
|
screen_to_client (hwnd, screen_pt, &client_pt);
|
|
|
|
if (!PtInRect (&rect, client_pt))
|
|
|
|
hwnd = NULL;
|
|
|
|
|
2022-08-24 17:01:45 +00:00
|
|
|
window = gdk_win32_handle_table_lookup_ (hwnd);
|
2010-05-25 22:38:44 +00:00
|
|
|
|
|
|
|
if (window && (win_x || win_y))
|
|
|
|
{
|
2019-05-19 03:09:05 +00:00
|
|
|
impl = GDK_WIN32_SURFACE (window);
|
GDK-Win32/4.0: Enable HiDPI support for Windows
This enables HiDPI support for GTK+ on Windows, so that the
fonts and window look better on HiDPI displays. Notes for the current
work:
-The DPI awareness enabling can be disabled if and only if an application
manifest is not embedded in the app to enable DPI awareness AND a user
compatibility setting is not set to limit DPI awareness for the app, via
the envvar GDK_WIN32_DISABLE_HIDPI. The app manifest/user setting for
DPI awareness will always win against the envvar, and so the HiDPI items
will be always setup in such scenarios, unless DPI awareness is disabled.
-Both automatic detection for the scaling factor and setting the scale
factor using the GDK_SCALE envvar are supported, where the envvar takes
precedence, which will therefore disable automatic scaling when
resolution changes.
-We now default to a per-system DPI awareness model, which means that we
do not handle WM_DPICHANGED, unless one sets the
GDK_WIN32_PER_MONITOR_HIDPI envvar, where notes for it are in the
following point.
-Automatic scaling during WM_DISPLAYCHANGE is handled (DPI setting change of
current monitor) is now supported. WM_DPICHANGED is handled as well,
except that the window positioning during the change of scaling still
needs to be refined, a change in GDK itself may be required for this.
-I am unable to test the wintab items because I don't have such devices
around.
https://bugzilla.gnome.org/show_bug.cgi?id=768081
2016-06-27 05:16:43 +00:00
|
|
|
|
Win32: Fix _gdk_windowing_window_at_pointer to correctly return a toplevel
Commit 5ebb32d1ffa23241d562fb4d5be02bc6f156b515 didn't add the correct
code to find the toplevel window. The WindowFromPoint() function does
not return the toplevel window in the hierarchy, it returns the deepest
non-disabled, non-invisible child. As we don't use invisible or disabled
windows, we don't actually need to use the ChildWindowFromPoint walk for
the non get_toplevel case, so we can remove that code path.
To find a toplevel, we need to start from the desktop and work up, using
ChildWindowFromPointEx (to ignore invisible and disabled windows). If we
don't ignore invisible and disabled windows (as is the case with the
ChildWindowFromPoint call, we are liable to get returns of hidden or
disabled children of the desktop which don't belong to us, but notionally
occupy the same area under the pointer.
An alternative might be to start our walk with one of the children of the
desktop owned by our process and thread - which we can enumerate using,
the EnumThreadWindows call, or (presumably) determine internally. This
would not work when we are inside a GtkSocket though, as the children of
the desktop would belong to the process owning the GtkPlug - we would
have to rely on our own list of windows.
For correctness, this commit adds tests to ensure that we don't try to
return either x or y window coordinates if that corresponding pointer is
NULL.
https://bugzilla.gnome.org/show_bug.cgi?id=658842
2011-09-10 15:30:56 +00:00
|
|
|
if (win_x)
|
2018-03-20 11:05:26 +00:00
|
|
|
*win_x = client_pt.x / impl->surface_scale;
|
Win32: Fix _gdk_windowing_window_at_pointer to correctly return a toplevel
Commit 5ebb32d1ffa23241d562fb4d5be02bc6f156b515 didn't add the correct
code to find the toplevel window. The WindowFromPoint() function does
not return the toplevel window in the hierarchy, it returns the deepest
non-disabled, non-invisible child. As we don't use invisible or disabled
windows, we don't actually need to use the ChildWindowFromPoint walk for
the non get_toplevel case, so we can remove that code path.
To find a toplevel, we need to start from the desktop and work up, using
ChildWindowFromPointEx (to ignore invisible and disabled windows). If we
don't ignore invisible and disabled windows (as is the case with the
ChildWindowFromPoint call, we are liable to get returns of hidden or
disabled children of the desktop which don't belong to us, but notionally
occupy the same area under the pointer.
An alternative might be to start our walk with one of the children of the
desktop owned by our process and thread - which we can enumerate using,
the EnumThreadWindows call, or (presumably) determine internally. This
would not work when we are inside a GtkSocket though, as the children of
the desktop would belong to the process owning the GtkPlug - we would
have to rely on our own list of windows.
For correctness, this commit adds tests to ensure that we don't try to
return either x or y window coordinates if that corresponding pointer is
NULL.
https://bugzilla.gnome.org/show_bug.cgi?id=658842
2011-09-10 15:30:56 +00:00
|
|
|
if (win_y)
|
2018-03-20 11:05:26 +00:00
|
|
|
*win_y = client_pt.y / impl->surface_scale;
|
2010-05-25 22:38:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return window;
|
|
|
|
}
|
|
|
|
|
2016-01-23 22:26:04 +00:00
|
|
|
static void
|
|
|
|
gdk_device_win32_class_init (GdkDeviceWin32Class *klass)
|
|
|
|
{
|
|
|
|
GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
|
|
|
|
|
2018-03-20 11:05:26 +00:00
|
|
|
device_class->set_surface_cursor = gdk_device_win32_set_surface_cursor;
|
2016-01-23 22:26:04 +00:00
|
|
|
device_class->grab = gdk_device_win32_grab;
|
|
|
|
device_class->ungrab = gdk_device_win32_ungrab;
|
2018-03-20 11:05:26 +00:00
|
|
|
device_class->surface_at_position = _gdk_device_win32_surface_at_position;
|
2016-01-23 22:26:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_device_win32_init (GdkDeviceWin32 *device_win32)
|
|
|
|
{
|
|
|
|
GdkDevice *device;
|
|
|
|
|
|
|
|
device = GDK_DEVICE (device_win32);
|
|
|
|
|
2020-06-09 19:26:04 +00:00
|
|
|
_gdk_device_add_axis (device, GDK_AXIS_X, 0, 0, 1);
|
|
|
|
_gdk_device_add_axis (device, GDK_AXIS_Y, 0, 0, 1);
|
2016-01-23 22:26:04 +00:00
|
|
|
}
|