Commits (138)
Overview of Changes in GTK+ 3.24.27
===================================
* Input: Ensure preedit-start and preedit-end
are emitted properly
* GtkScrolledWindow:
- Revert a change that broke touch scrolling
* Theme:
- Fix a problem with size changes in SSD decorations
that caused mutter crashes
- Use transparent black for window border in the dark theme
* Windows:
- Memory leak fixes
- Fix unresponsive windows after tablet input
- Add support for wheel and rotation axes
* Translation updates:
Belarusian
German
Kazakh
Korean
Latvian
Turkish
Overview of Changes in GTK+ 3.24.26
===================================
* Input:
- Fix a few oversights in Compose file parsing
- Fine-tune Compose preedit display
* Theme:
- Fine-tune scrollbar size and transitions
- Reinstate invisible borders for tiled windows
* Wayland:
- Fix a problem with font settings not being found
* Translation updates
French
Hungarian
Turkish
Overview of Changes in GTK+ 3.24.25
===================================
* Settings:
- Make cursor aspect ratio setting work
* Broadway:
- Fix touchscreen event handling
- Support Android / Chrome on-screen keyboard
* Windows:
- Fix issues with Intel graphics drivers
- Avoid UAC for gtk-update-icon-cache
* Wayland:
- Avoid crashes with tablet input
- Add api to support clients with subsurfaces better
* Inspector:
- Make the inspector available in non-debug builds
* Theme:
- Make scrollbars larger
- Disable shadows on maximized, fullscreen and tiled windows
* Printing:
- Support Avahi-discovered printers better
* Input:
- Show preedit for compose sequences
- Support long compose sequences
- Support compose sequences producing multiple characters
* Translation updates
Belarusian
British English
Catalan
Friulian
Galician
Japanese
Persian
Serbian
Overview of Changes in GTK+ 3.24.24
===================================
 
......
......@@ -175,6 +175,27 @@ instance the makefile.msc files might not produce identically named
DLLs and import libraries as the "autoconfiscated" makefiles and
libtool do. If this bothers you, you will have to fix the makefiles.
If desiring to build binaries for ARM64 (aarch64), one needs to use the
Visual Studio 2017 or 2019 solution files, or use Meson with a
cross-compilation file, with a Windows 10 SDK that supports ARM64
builds. At this point, building the introspection files is not supported
for ARM64 builds, and you will need a Python interpreter and
glib-compile-resources binaries that run on the build machine. For Visual Studio
2017 ARM64 builds, do also check the Directory.Build.props file in $(srcroot)/win32/vs15
indicates a Windows 10 SDK version that supports ARM64 builds exists on the build machine.
For building ARM64 binaries with the Visual Studio projects, prior to the build,
you may need to update gtk3-gen-srcs.props to pass in the variables GLIB_MKENUMS,
GLIB_GENMARSHAL, GDBUS_CODEGEN and/or GLIB_COMPILE_RESOURCES in the nmake command line
indicated by <GenerateRequiredSourcesBase> so that they point to the glib-mkenums,
glib-genmarshal, gdbus-codegen and glib-compile-resources that will run on the build
machine. You may also need to update gtk3-version-paths.props to update PythonDir to
the installation of the Python interpreter that will run on the build machine. To carry
out the actual build using the solution files, use the "Configuration Manager" to add the
ARM64 build configs by copying the settings from the x64 configs, and then build the solution.
The build instructions for such builds otherwise follow the standard Win32 (x86) and
x64 builds, but you need to ensure that you have ARM64 builds of the various dependencies.
3) Using Meson (for Visual Studio and MinGW builds)
---
......
......@@ -44,6 +44,9 @@
/* Define to 1 if you have the `flockfile' function. */
#mesondefine HAVE_FLOCKFILE
/* Define to 1 if you have the `fmin' function. */
#mesondefine HAVE_FMIN
/* Define to 1 if you have the <ftw.h> header file. */
#mesondefine HAVE_FTW_H
......
......@@ -52,6 +52,11 @@
/* Define to 1 if you have the `flockfile' function. */
#undef HAVE_FLOCKFILE
/* Define to 1 if you have the `fmin' function. */
#if !defined (_MSC_VER) || (_MSC_VER >= 1800)
# define HAVE_FMIN 1
#endif
/* Define to 1 if you have the <ftw.h> header file. */
/* #undef HAVE_FTW_H */
......
......@@ -10,8 +10,8 @@
m4_define([gtk_major_version], [3])
m4_define([gtk_minor_version], [24])
m4_define([gtk_micro_version], [24])
m4_define([gtk_interface_age], [20])
m4_define([gtk_micro_version], [27])
m4_define([gtk_interface_age], [23])
m4_define([gtk_binary_age],
[m4_eval(100 * gtk_minor_version + gtk_micro_version)])
m4_define([gtk_version],
......@@ -843,7 +843,7 @@ AC_TYPE_UID_T
# Check for round(), rint(), isnan() and isinf()
# Check for log2(), exp2(), nearbyint() and trunc()
AC_CHECK_LIB(m,round,,)
AC_CHECK_FUNCS(round rint nearbyint sincos exp2 log2 trunc)
AC_CHECK_FUNCS(round rint nearbyint sincos exp2 log2 trunc fmin)
AC_CHECK_DECLS([isnan, isinf], [], [], [[#include <math.h>]])
AC_MSG_CHECKING(whether to build dynamic modules)
......
......@@ -1279,6 +1279,8 @@ GdkWaylandWindowExported
gdk_wayland_window_export_handle
gdk_wayland_window_unexport_handle
gdk_wayland_window_set_transient_for_exported
gdk_wayland_window_add_frame_callback_surface
gdk_wayland_window_remove_frame_callback_surface
<SUBSECTION Standard>
GDK_TYPE_WAYLAND_DEVICE
......
......@@ -20,12 +20,8 @@ Getting help with GTK+
<title>Filing a bug report or feature request</title>
<para>
If you encounter a bug, misfeature, or missing feature in GTK+, please
file a bug report on
<ulink url="https://bugzilla.gnome.org">https://bugzilla.gnome.org</ulink>.
We'd also appreciate reports of incomplete or misleading information in
the GTK+ documentation; file those against the "docs" component of the "gtk+"
product in Bugzilla.
If you encounter a bug, misfeature, or missing feature in GTK, please
file a bug report on <ulink url="https://gitlab.gnome.org/GNOME/gtk/issues">GitLab</ulink>.
</para>
<para>
......@@ -37,103 +33,38 @@ discussed, we'll add a note to that effect in the report.
<para>
The bug tracker should definitely be used for feature requests, it's
not only for bugs. We track all GTK+ development in Bugzilla, so it's
the way to be sure the GTK+ developers won't forget about an issue.
not only for bugs. We track all GTK development in GitLab, so it's
the way to be sure the GTK developers won't forget about an issue.
</para>
</refsect1>
<refsect1>
<title>Submitting Patches</title>
<para>
If you develop a bugfix or enhancement for GTK+, please file that in
Bugzilla as well. Bugzilla allows you to attach files; please attach a
patch generated by the <command>diff</command> utility, using the
<option>-u</option> option to make the patch more readable. All patches
must be offered under the terms of the GNU LGPL license, so be sure you
are authorized to give us the patch under those terms.
</para>
<para>
If you want to discuss your patch before or after developing it, mail
<ulink url="mailto:gtk-devel-list@gnome.org">gtk-devel-list@gnome.org</ulink>.
But be sure to file the Bugzilla report as well; if the patch is only on the
list and not in Bugzilla, it's likely to slip through the cracks.
Just make sure that any issue filed is actionable, and contains clear
instructions on how to reproduce an issue, and the conditions to close
the bug report or feature request. Non-actionable, or user support
questions will be directed to Discourse.
</para>
</refsect1>
<refsect1>
<title>Mailing lists</title>
<title>Contributing</title>
<para>
There are several mailing lists dedicated to GTK+ and related
libraries. Discussion of GLib, Pango, and ATK in addition to GTK+
proper is welcome on these lists. You can subscribe or view the
archives of these lists on
<ulink url="https://mail.gnome.org">http://mail.gnome.org</ulink>.
If you aren't subscribed to the list, any message you post to
the list will be held for manual moderation, which might take
some days to happen.
Please, follow the instructions outlined in the
<ulink url="https://gitlab.gnome.org/GNOME/gtk/-/blob/master/CONTRIBUTING.md">Contribution Guide</ulink> available in the GTK
source code repository.
</para>
<para>
<variablelist>
<varlistentry>
<term><ulink url="mailto:gtk-list@gnome.org">gtk-list@gnome.org</ulink></term>
<listitem><para>
gtk-list covers general GTK+ topics; questions about using GTK+ in programs,
GTK+ from a user standpoint, announcements of GTK+-related projects
such as themes or GTK+ modules would all be on-topic. The bulk of the
traffic consists of GTK+ programming questions.
</para></listitem>
</varlistentry>
<varlistentry>
<term><ulink url="mailto:gtk-app-devel-list@gnome.org">gtk-app-devel-list@gnome.org</ulink></term>
<listitem><para>
gtk-app-devel-list covers writing applications in GTK+. It's narrower
in scope than gtk-list, but the two lists overlap quite a
bit. gtk-app-devel-list is a good place to ask questions about GTK+
programming. </para></listitem>
</varlistentry>
<varlistentry>
<term><ulink url="mailto:gtk-devel-list@gnome.org">gtk-devel-list@gnome.org</ulink></term>
<listitem><para>
gtk-devel-list is for discussion of work on GTK+ itself, it is
<emphasis>not</emphasis> for
asking questions about how to use GTK+ in applications. gtk-devel-list
is appropriate for discussion of patches, bugs, proposed features,
and so on.
</para></listitem>
</varlistentry>
<varlistentry>
<term><ulink url="mailto:gtk-i18n-list@gnome.org">gtk-i18n-list@gnome.org</ulink></term>
<listitem><para>
gtk-i18n-list is for discussion of internationalization in GTK+;
Pango is the main focus of the list. Questions about the details of
using Pango, and discussion of proposed Pango patches or features, are
all on topic.
</para></listitem>
</varlistentry>
</refsect1>
<varlistentry>
<term><ulink url="mailto:gtk-doc-list@gnome.org">gtk-doc-list@gnome.org</ulink></term>
<listitem><para>
gtk-doc-list is for discussion of the <application>gtk-doc</application>
documentation system (used to document GTK+), and for work on the GTK+
documentation.
</para></listitem>
</varlistentry>
<refsect1>
<title>User support</title>
</variablelist>
<para>
If you have questions about building, using, or contributing to GTK, please
open a topic on <ulink url="https://discourse.gnome.org/tag/gtk">Discourse</ulink>.
</para>
</refsect1>
</refentry>
......@@ -134,9 +134,9 @@ additional environment variables.
<title><envar>GTK_DEBUG</envar></title>
<para>
Unless GTK+ has been configured with <option>--enable-debug=no</option>,
this variable can be set to a list of debug options, which cause GTK+
to print out different types of debugging information.
This variable can be set to a list of debug options, which cause GTK to
print out different types of debugging information. Some of these options
are only available when GTK has been configured with <option>--enable-debug=yes</option>.
<variablelist>
<varlistentry>
<term>actions</term>
......
/* check if we are on Android and using Chrome */
var isAndroidChrome = false;
{
var ua = navigator.userAgent.toLowerCase();
if (ua.indexOf("android") > -1 && ua.indexOf("chrom") > -1) {
isAndroidChrome = true;
}
}
/* check for the passive option for Event listener */
let passiveSupported = false;
try {
const options = {
get passive() { // This function will be called when the browser
// attempts to access the passive property.
passiveSupported = true;
return false;
}
};
window.addEventListener("test", null, options);
window.removeEventListener("test", null, options);
} catch(err) {
passiveSupported = false;
}
/* Helper functions for debugging */
var logDiv = null;
function log(str) {
......@@ -10,6 +34,25 @@ function log(str) {
logDiv.appendChild(document.createTextNode(str));
logDiv.appendChild(document.createElement('br'));
}
/* Helper functions for touch identifier to make it unique on Android */
var globalTouchIdentifier = Math.round(Date.now() / 1000);
function touchIdentifierStart(tId)
{
if (isAndroidChrome) {
if (tId == 0) {
return ++globalTouchIdentifier;
}
return globalTouchIdentifier + tId;
}
return tId;
}
function touchIdentifier(tId)
{
if (isAndroidChrome) {
return globalTouchIdentifier + tId;
}
return tId;
}
function getStackTrace()
{
......@@ -91,6 +134,7 @@ grab.window = null;
grab.ownerEvents = false;
grab.implicit = false;
var keyDownList = [];
var inputList = [];
var lastSerial = 0;
var lastX = 0;
var lastY = 0;
......@@ -223,6 +267,7 @@ function cmdSetTransientFor(id, parentId)
{
var surface = surfaces[id];
if (surface === undefined) return;
if (surface.transientParent == parentId)
return;
......@@ -253,8 +298,9 @@ function moveToHelper(surface, position) {
for (var cid in surfaces) {
var child = surfaces[cid];
if (child.transientParent == surface.id)
if (child.transientParent == surface.id) {
moveToHelper(child, stackingOrder.indexOf(surface) + 1);
}
}
}
......@@ -269,6 +315,13 @@ function cmdDeleteSurface(id)
stackingOrder.splice(i, 1);
var canvas = surface.canvas;
canvas.parentNode.removeChild(canvas);
if (id == windowWithMouse) {
windowWithMouse = 0;
}
if (id == realWindowWithMouse) {
realWindowWithMouse = 0;
firstTouchDownId = null;
}
delete surfaces[id];
}
......@@ -307,6 +360,7 @@ function cmdRaiseSurface(id)
{
var surface = surfaces[id];
if (surface === undefined) return;
moveToHelper(surface);
restackWindows();
}
......@@ -315,6 +369,7 @@ function cmdLowerSurface(id)
{
var surface = surfaces[id];
if (surface === undefined) return;
moveToHelper(surface, 0);
restackWindows();
}
......@@ -520,6 +575,7 @@ function cmdPutBuffer(id, w, h, compressed)
var data = inflate.decompress();
var imageData = decodeBuffer (context, surface.imageData, w, h, data, debugDecoding);
context.imageSmoothingEnabled = false;
context.putImageData(imageData, 0, 0);
if (debugDecoding)
......@@ -776,8 +832,15 @@ function getEffectiveEventTarget (id) {
function updateKeyboardStatus() {
if (fakeInput != null && showKeyboardChanged) {
showKeyboardChanged = false;
if (showKeyboard)
if (showKeyboard) {
if (isAndroidChrome) {
fakeInput.blur();
fakeInput.value = ' '.repeat(80); // TODO: Should be exchange with broadway server
// to bring real value here.
}
fakeInput.focus();
//if (isAndroidChrome) fakeInput.click();
}
else
fakeInput.blur();
}
......@@ -2329,6 +2392,19 @@ function pushKeyEvent(fev) {
keyDownList.push(fev);
}
function copyInputEvent(ev) {
var members = ['inputType', 'data'], i, obj = {};
for (i = 0; i < members.length; i++) {
if (typeof ev[members[i]] !== "undefined")
obj[members[i]] = ev[members[i]];
}
return obj;
}
function pushInputEvent(fev) {
inputList.push(fev);
}
function getKeyEvent(keyCode, pop) {
var i, fev = null;
for (i = keyDownList.length-1; i >= 0; i--) {
......@@ -2366,8 +2442,9 @@ function handleKeyDown(e) {
// If it is a key or key combination that might trigger
// browser behaviors or it has no corresponding keyPress
// event, then send it immediately
if (!ignoreKeyEvent(ev))
if (!ignoreKeyEvent(ev)) {
sendInput("k", [keysym, lastState]);
}
suppress = true;
}
......@@ -2411,8 +2488,9 @@ function handleKeyPress(e) {
}
// Send the translated keysym
if (keysym > 0)
if (keysym > 0) {
sendInput ("k", [keysym, lastState]);
}
// Stop keypress events just in case
return cancelEvent(ev);
......@@ -2427,11 +2505,45 @@ function handleKeyUp(e) {
keysym = fev.keysym;
else {
//log("Key event (keyCode = " + ev.keyCode + ") not found on keyDownList");
if (isAndroidChrome && (ev.keyCode == 229)) {
var i, fev = null, len = inputList.length, str;
for (i = 0; i < len; i++) {
fev = inputList[i];
switch(fev.inputType) {
case "deleteContentBackward":
sendInput ("k", [65288, lastState]);
sendInput ("K", [65288, lastState]);
break;
case "insertText":
if (fev.data !== undefined) {
for (let sym of fev.data) {
sendInput ("k", [sym.codePointAt(0), lastState]);
sendInput ("K", [sym.codePointAt(0), lastState]);
}
}
break;
default:
break;
}
}
inputList.splice(0, len);
}
keysym = 0;
}
if (keysym > 0)
if (keysym > 0) {
sendInput ("K", [keysym, lastState]);
}
return cancelEvent(ev);
}
function handleInput (e) {
var fev = null, ev = (e ? e : window.event), keysym = null, suppress = false;
fev = copyInputEvent(ev);
pushInputEvent(fev);
// Stop keypress events just in case
return cancelEvent(ev);
}
......@@ -2450,6 +2562,11 @@ function onKeyUp (ev) {
return handleKeyUp(ev);
}
function onInput (ev) {
updateForEvent(ev);
return handleInput(ev);
}
function cancelEvent(ev)
{
ev = ev ? ev : window.event;
......@@ -2481,13 +2598,14 @@ function onMouseWheel(ev)
}
function onTouchStart(ev) {
event.preventDefault();
ev.preventDefault();
updateKeyboardStatus();
updateForEvent(ev);
for (var i = 0; i < ev.changedTouches.length; i++) {
var touch = ev.changedTouches.item(i);
var touchId = touchIdentifierStart(touch.identifier);
var origId = getSurfaceId(touch);
var id = getEffectiveEventTarget (origId);
......@@ -2495,7 +2613,7 @@ function onTouchStart(ev) {
var isEmulated = 0;
if (firstTouchDownId == null) {
firstTouchDownId = touch.identifier;
firstTouchDownId = touchId;
isEmulated = 1;
if (realWindowWithMouse != origId || id != windowWithMouse) {
......@@ -2510,52 +2628,54 @@ function onTouchStart(ev) {
}
}
sendInput ("t", [0, id, touch.identifier, isEmulated, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState]);
sendInput ("t", [0, id, touchId, isEmulated, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState]);
}
}
function onTouchMove(ev) {
event.preventDefault();
ev.preventDefault();
updateKeyboardStatus();
updateForEvent(ev);
for (var i = 0; i < ev.changedTouches.length; i++) {
var touch = ev.changedTouches.item(i);
var touchId = touchIdentifier(touch.identifier);
var origId = getSurfaceId(touch);
var id = getEffectiveEventTarget (origId);
var pos = getPositionsFromEvent(touch, id);
var isEmulated = 0;
if (firstTouchDownId == touch.identifier) {
if (firstTouchDownId == touchId) {
isEmulated = 1;
}
sendInput ("t", [1, id, touch.identifier, isEmulated, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState]);
sendInput ("t", [1, id, touchId, isEmulated, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState]);
}
}
function onTouchEnd(ev) {
event.preventDefault();
ev.preventDefault();
updateKeyboardStatus();
updateForEvent(ev);
for (var i = 0; i < ev.changedTouches.length; i++) {
var touch = ev.changedTouches.item(i);
var touchId = touchIdentifier(touch.identifier);
var origId = getSurfaceId(touch);
var id = getEffectiveEventTarget (origId);
var pos = getPositionsFromEvent(touch, id);
var isEmulated = 0;
if (firstTouchDownId == touch.identifier) {
if (firstTouchDownId == touchId) {
isEmulated = 1;
firstTouchDownId = null;
}
sendInput ("t", [2, id, touch.identifier, isEmulated, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState]);
sendInput ("t", [2, id, touchId, isEmulated, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState]);
}
}
......@@ -2572,11 +2692,11 @@ function setupDocument(document)
document.onkeyup = onKeyUp;
if (document.addEventListener) {
document.addEventListener('DOMMouseScroll', onMouseWheel, false);
document.addEventListener('mousewheel', onMouseWheel, false);
document.addEventListener('touchstart', onTouchStart, false);
document.addEventListener('touchmove', onTouchMove, false);
document.addEventListener('touchend', onTouchEnd, false);
document.addEventListener('DOMMouseScroll', onMouseWheel, passiveSupported ? { passive: false, capture: false } : false);
document.addEventListener('mousewheel', onMouseWheel, passiveSupported ? { passive: false, capture: false } : false);
document.addEventListener('touchstart', onTouchStart, passiveSupported ? { passive: false, capture: false } : false);
document.addEventListener('touchmove', onTouchMove, passiveSupported ? { passive: false, capture: false } : false);
document.addEventListener('touchend', onTouchEnd, passiveSupported ? { passive: false, capture: false } : false);
} else if (document.attachEvent) {
element.attachEvent("onmousewheel", onMouseWheel);
}
......@@ -2630,12 +2750,14 @@ function connect()
};
var iOS = /(iPad|iPhone|iPod)/g.test( navigator.userAgent );
if (iOS) {
if (iOS || isAndroidChrome) {
fakeInput = document.createElement("input");
fakeInput.type = "text";
fakeInput.style.position = "absolute";
fakeInput.style.left = "-1000px";
fakeInput.style.top = "-1000px";
document.body.appendChild(fakeInput);
if (isAndroidChrome)
fakeInput.addEventListener('input', onInput, passiveSupported ? { passive: false, capture: false } : false);
}
}
......@@ -288,6 +288,7 @@ gdk_pixbuf_get_from_surface (cairo_surface_t *surface,
if (cairo_surface_status (surface) || dest == NULL)
{
cairo_surface_destroy (surface);
g_clear_object (&dest);
return NULL;
}
......
......@@ -10200,7 +10200,7 @@ gdk_window_create_similar_surface (GdkWindow * window,
* gdk_window_create_similar_image_surface:
* @window: (nullable): window to make new surface similar to, or
* %NULL if none
* @format: (type int): the format for the new surface
* @format: the format for the new surface
* @width: width of the new surface
* @height: height of the new surface
* @scale: the scale of the new surface, or 0 to use same as @window
......
......@@ -2506,6 +2506,9 @@ touch_handle_down (void *data,
_gdk_wayland_display_update_serial (display, serial);
if (!wl_surface)
return;
touch = gdk_wayland_seat_add_touch (seat, id, wl_surface);
touch->x = wl_fixed_to_double (x);
touch->y = wl_fixed_to_double (y);
......@@ -2541,6 +2544,9 @@ touch_handle_up (void *data,
_gdk_wayland_display_update_serial (display, serial);
touch = gdk_wayland_seat_get_touch (seat, id);
if (!touch)
return;
event = _create_touch_event (seat, touch, GDK_TOUCH_END, time);
GDK_NOTE (EVENTS,
......@@ -2567,6 +2573,9 @@ touch_handle_motion (void *data,
GdkEvent *event;
touch = gdk_wayland_seat_get_touch (seat, id);
if (!touch)
return;
touch->x = wl_fixed_to_double (x);
touch->y = wl_fixed_to_double (y);
......@@ -3680,19 +3689,21 @@ tablet_tool_handle_proximity_in (void *data,
struct zwp_tablet_tool_v2 *wp_tablet_tool,
uint32_t serial,
struct zwp_tablet_v2 *wp_tablet,
struct wl_surface *surface)
struct wl_surface *wl_surface)
{
GdkWaylandTabletToolData *tool = data;
GdkWaylandTabletData *tablet = zwp_tablet_v2_get_user_data (wp_tablet);
GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (tablet->seat);
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display);
GdkWindow *window = wl_surface_get_user_data (surface);
GdkWindow *window;
GdkEvent *event;
if (!surface)
return;
if (!wl_surface)
return;
window = wl_surface_get_user_data (wl_surface);
if (!GDK_IS_WINDOW (window))
return;
return;
tool->current_tablet = tablet;
tablet->current_tool = tool;
......@@ -3731,6 +3742,9 @@ tablet_tool_handle_proximity_out (void *data,
GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (tool->seat);
#endif
if (!tablet)
return;
GDK_NOTE (EVENTS,
g_message ("proximity out, seat %p, tool %d", seat,
gdk_device_tool_get_tool_type (tool->tool)));
......@@ -3787,7 +3801,7 @@ tablet_tool_handle_down (void *data,
GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (tool->seat);
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display);
if (!tablet->pointer_info.focus)
if (!tablet || !tablet->pointer_info.focus)
return;
_gdk_wayland_display_update_serial (display_wayland, serial);
......@@ -3804,7 +3818,7 @@ tablet_tool_handle_up (void *data,
GdkWaylandTabletToolData *tool = data;
GdkWaylandTabletData *tablet = tool->current_tablet;
if (!tablet->pointer_info.focus)
if (!tablet || !tablet->pointer_info.focus)
return;
tablet_create_button_event_frame (tablet, GDK_BUTTON_RELEASE, GDK_BUTTON_PRIMARY);
......@@ -3823,6 +3837,9 @@ tablet_tool_handle_motion (void *data,
GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display);
GdkEvent *event;
if (!tablet)
return;
tablet->pointer_info.surface_x = wl_fixed_to_double (sx);
tablet->pointer_info.surface_y = wl_fixed_to_double (sy);
......@@ -3855,7 +3872,12 @@ tablet_tool_handle_pressure (void *data,
{
GdkWaylandTabletToolData *tool = data;
GdkWaylandTabletData *tablet = tool->current_tablet;
gint axis_index = tablet->axis_indices[GDK_AXIS_PRESSURE];
gint axis_index;
if (!tablet)
return;
axis_index = tablet->axis_indices[GDK_AXIS_PRESSURE];
_gdk_device_translate_axis (tablet->current_device, axis_index,
pressure, &tablet->axes[axis_index]);
......@@ -3872,7 +3894,12 @@ tablet_tool_handle_distance (void *data,
{
GdkWaylandTabletToolData *tool = data;
GdkWaylandTabletData *tablet = tool->current_tablet;
gint axis_index = tablet->axis_indices[GDK_AXIS_DISTANCE];
gint axis_index;
if (!tablet)
return;
axis_index = tablet->axis_indices[GDK_AXIS_DISTANCE];
_gdk_device_translate_axis (tablet->current_device, axis_index,
distance, &tablet->axes[axis_index]);
......@@ -3890,8 +3917,14 @@ tablet_tool_handle_tilt (void *data,
{
GdkWaylandTabletToolData *tool = data;
GdkWaylandTabletData *tablet = tool->current_tablet;
gint xtilt_axis_index = tablet->axis_indices[GDK_AXIS_XTILT];
gint ytilt_axis_index = tablet->axis_indices[GDK_AXIS_YTILT];
gint xtilt_axis_index;
gint ytilt_axis_index;
if (!tablet)
return;
xtilt_axis_index = tablet->axis_indices[GDK_AXIS_XTILT];
ytilt_axis_index = tablet->axis_indices[GDK_AXIS_YTILT];
_gdk_device_translate_axis (tablet->current_device, xtilt_axis_index,
wl_fixed_to_double (xtilt),
......@@ -3918,7 +3951,7 @@ tablet_tool_handle_button (void *data,
GdkEventType evtype;
guint n_button;
if (!tablet->pointer_info.focus)
if (!tablet || !tablet->pointer_info.focus)
return;
tablet->pointer_info.press_serial = serial;
......@@ -3949,7 +3982,12 @@ tablet_tool_handle_rotation (void *data,
{
GdkWaylandTabletToolData *tool = data;
GdkWaylandTabletData *tablet = tool->current_tablet;
gint axis_index = tablet->axis_indices[GDK_AXIS_ROTATION];
gint axis_index;
if (!tablet)
return;
axis_index = tablet->axis_indices[GDK_AXIS_ROTATION];
_gdk_device_translate_axis (tablet->current_device, axis_index,
wl_fixed_to_double (degrees),
......@@ -3968,7 +4006,12 @@ tablet_tool_handle_slider (void *data,
{
GdkWaylandTabletToolData *tool = data;
GdkWaylandTabletData *tablet = tool->current_tablet;
gint axis_index = tablet->axis_indices[GDK_AXIS_SLIDER];
gint axis_index;
if (!tablet)
return;
axis_index = tablet->axis_indices[GDK_AXIS_SLIDER];
_gdk_device_translate_axis (tablet->current_device, axis_index,
position, &tablet->axes[axis_index]);
......@@ -3986,9 +4029,12 @@ tablet_tool_handle_wheel (void *data,
{
GdkWaylandTabletToolData *tool = data;
GdkWaylandTabletData *tablet = tool->current_tablet;
GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (tablet->seat);
GdkWaylandSeat *seat;
GdkEvent *event;
if (!tablet)
return;
GDK_NOTE (EVENTS,
g_message ("tablet tool %d wheel %d/%d",
gdk_device_tool_get_tool_type (tool->tool), degrees, clicks));
......@@ -3996,6 +4042,8 @@ tablet_tool_handle_wheel (void *data,
if (clicks == 0)
return;
seat = GDK_WAYLAND_SEAT (tablet->seat);
/* Send smooth event */
event = create_scroll_event (seat, &tablet->pointer_info,
tablet->master, tablet->current_device, FALSE);
......@@ -4021,6 +4069,9 @@ tablet_tool_handle_frame (void *data,
GdkWaylandTabletData *tablet = tool->current_tablet;
GdkEvent *frame_event;
if (!tablet)
return;
GDK_NOTE (EVENTS,
g_message ("tablet frame, time %d", time));
......@@ -4644,6 +4695,9 @@ pointer_surface_update_scale (GdkDevice *device)
return;
}
if (!pointer->pointer_surface_outputs)
return;
scale = 1;
for (l = pointer->pointer_surface_outputs; l != NULL; l = l->next)
{
......@@ -4653,6 +4707,8 @@ pointer_surface_update_scale (GdkDevice *device)
scale = MAX (scale, output_scale);
}
if (pointer->current_output_scale == scale)
return;
pointer->current_output_scale = scale;
if (pointer->cursor)
......
......@@ -84,7 +84,7 @@
#define MIN_SYSTEM_BELL_DELAY_MS 20
#define GTK_SHELL1_VERSION 3
#define GTK_SHELL1_VERSION 4
static void _gdk_wayland_display_load_cursor_theme (GdkWaylandDisplay *display_wayland);
......
......@@ -380,15 +380,11 @@ update_xft_settings (GdkScreen *screen)
}
else
{
GSettingsSchemaSource *source;
GSettingsSchema *schema;
TranslationEntry *entry;
source = g_settings_schema_source_get_default ();
schema = g_settings_schema_source_lookup (source,
"org.gnome.desktop.interface",
FALSE);
entry = find_translation_entry_by_schema ("org.gnome.desktop.interface", "font-antialiasing");
if (schema && g_settings_schema_has_key (schema, "font-antialiasing"))
if (entry && entry->valid)
{
settings = g_hash_table_lookup (screen_wayland->settings,
"org.gnome.desktop.interface");
......@@ -765,6 +761,7 @@ init_settings (GdkScreen *screen)
char *a = g_variant_print (v, FALSE);
g_debug ("Using portal setting for %s %s: %s\n", schema, key, a);
g_free (a);
entry->valid = TRUE;
apply_portal_setting (entry, v, screen);
}
else
......
......@@ -87,6 +87,14 @@ void gdk_wayland_window_announce_csd (GdkWindow *window);
GDK_AVAILABLE_IN_3_24
void gdk_wayland_window_announce_ssd (GdkWindow *window);
GDK_AVAILABLE_IN_3_24
void gdk_wayland_window_add_frame_callback_surface (GdkWindow *window,
struct wl_surface *surface);
GDK_AVAILABLE_IN_3_24
void gdk_wayland_window_remove_frame_callback_surface (GdkWindow *window,
struct wl_surface *surface);
G_END_DECLS
#endif /* __GDK_WAYLAND_WINDOW_H__ */
......@@ -236,6 +236,9 @@ struct _GdkWindowImplWayland
struct zxdg_imported_v1 *imported_transient_for;
GHashTable *shortcuts_inhibitors;
struct wl_callback *surface_callback;
GHashTable *frame_callback_surfaces;
};
struct _GdkWindowImplWaylandClass
......@@ -572,9 +575,25 @@ frame_callback (void *data,
GdkFrameClock *clock = gdk_window_get_frame_clock (window);
GdkFrameTimings *timings;
GDK_NOTE (EVENTS,
g_message ("frame %p", window));
if (callback == impl->surface_callback)
{
impl->surface_callback = NULL;
}
else
{
GHashTableIter iter;
gpointer surface_callback;
g_hash_table_iter_init (&iter, impl->frame_callback_surfaces);
while (g_hash_table_iter_next (&iter, NULL, &surface_callback))
{
if (callback == surface_callback)
{
g_hash_table_iter_replace (&iter, NULL);
break;
}
}
}
wl_callback_destroy (callback);
if (GDK_WINDOW_DESTROYED (window))
......@@ -583,6 +602,9 @@ frame_callback (void *data,
if (!impl->awaiting_frame)
return;
GDK_NOTE (EVENTS,
g_message ("frame %p", window));
impl->awaiting_frame = FALSE;
_gdk_frame_clock_thaw (clock);
......@@ -660,6 +682,8 @@ on_frame_clock_after_paint (GdkFrameClock *clock,
{
GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
struct wl_callback *callback;
GHashTableIter iter;
gpointer surface, surface_callback;
if (!impl->pending_commit)
return;
......@@ -667,8 +691,6 @@ on_frame_clock_after_paint (GdkFrameClock *clock,
if (window->update_freeze_count > 0)
return;
callback = wl_surface_frame (impl->display_server.wl_surface);
wl_callback_add_listener (callback, &frame_listener, window);
_gdk_frame_clock_freeze (clock);
/* Before we commit a new buffer, make sure we've backfilled
......@@ -677,6 +699,24 @@ on_frame_clock_after_paint (GdkFrameClock *clock,
if (impl->pending_buffer_attached)
read_back_cairo_surface (window);
if (impl->surface_callback == NULL)
{
callback = wl_surface_frame (impl->display_server.wl_surface);
wl_callback_add_listener (callback, &frame_listener, window);
impl->surface_callback = callback;
}
g_hash_table_iter_init (&iter, impl->frame_callback_surfaces);
while (g_hash_table_iter_next (&iter, &surface, &surface_callback))
{
if (surface_callback)
continue;
callback = wl_surface_frame (surface);
wl_callback_add_listener (callback, &frame_listener, window);
g_hash_table_iter_replace (&iter, callback);
}
/* From this commit forward, we can't write to the buffer,
* it's "live". In the future, if we need to stage more changes
* we have to allocate a new staging buffer and draw to it instead.
......@@ -756,6 +796,8 @@ _gdk_wayland_display_create_window_impl (GdkDisplay *display,
impl->wrapper = GDK_WINDOW (window);
impl->shortcuts_inhibitors = g_hash_table_new (NULL, NULL);
impl->using_csd = TRUE;
impl->surface_callback = NULL;
impl->frame_callback_surfaces = g_hash_table_new (NULL, NULL);
if (window->width > 65535)
{
......@@ -1067,6 +1109,7 @@ gdk_window_impl_wayland_finalize (GObject *object)
g_clear_pointer (&impl->staged_updates_region, cairo_region_destroy);
g_clear_pointer (&impl->shortcuts_inhibitors, g_hash_table_unref);
g_clear_pointer (&impl->frame_callback_surfaces, g_hash_table_unref);
G_OBJECT_CLASS (_gdk_window_impl_wayland_parent_class)->finalize (object);
}
......@@ -3335,7 +3378,11 @@ gdk_wayland_window_hide_surface (GdkWindow *window)
if (impl->display_server.gtk_surface)
{
gtk_surface1_destroy (impl->display_server.gtk_surface);
if (display_wayland->gtk_shell_version >=
GTK_SURFACE1_RELEASE_SINCE_VERSION)
gtk_surface1_release (impl->display_server.gtk_surface);
else
gtk_surface1_destroy (impl->display_server.gtk_surface);
impl->display_server.gtk_surface = NULL;
impl->application.was_set = FALSE;
}
......@@ -3348,6 +3395,7 @@ gdk_wayland_window_hide_surface (GdkWindow *window)
wl_surface_destroy (impl->display_server.wl_surface);
impl->display_server.wl_surface = NULL;
impl->surface_callback = NULL;
g_slist_free (impl->display_server.outputs);
impl->display_server.outputs = NULL;
......@@ -5393,3 +5441,71 @@ gdk_wayland_window_restore_shortcuts (GdkWindow *window,
g_hash_table_remove (impl->shortcuts_inhibitors, seat);
}
/**
* gdk_wayland_window_add_frame_callback_surface:
* @window: the #GdkWindow requesting callbacks
* @surface: the wl_surface to add
*
* Add @surface to a list of surfaces for which frame callback
* listeners will get set up, additionally to the one of @window.
*
* This is useful when clients use subsurfaces independently of GDK.
* For example if a client creates a subsurface that covers @window
* entirely. If this subsurface is opaque, Wayland compositors may not
* emit callbacks for the surface of @window any more.
* Adding the covering subsurface via this function ensures the
* @window will continue to update.
*
* A single callback is sufficient to trigger the next update. If more
* than one are triggered, the later ones will get ignored.
*
* Before @surface gets destroyed it must get removed again using
* gdk_wayland_window_remove_frame_callback_surface().
*
* Note that the client is responsible to commit the @surface.
* One way to archive this is to always commit after the
* #GdkSurface::after-paint signal was triggered.
*
* Since: 3.24.25
*/
void
gdk_wayland_window_add_frame_callback_surface (GdkWindow *window,
struct wl_surface *surface)
{
GdkWindowImplWayland *impl;
g_return_if_fail (GDK_IS_WAYLAND_WINDOW (window));
g_return_if_fail (GDK_IS_WINDOW_IMPL_WAYLAND (window->impl));
g_return_if_fail (surface != NULL);
impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
g_hash_table_insert (impl->frame_callback_surfaces, surface, NULL);
}
/**
* gdk_wayland_window_remove_frame_callback_surface:
* @window: the #GdkWindow requesting callbacks
* @surface: the surface to remove
*
* Remove @surface from the list of surfaces again that got added via
* gdk_wayland_window_add_frame_callback_surface().
*
* This function must be called before @surface gets destroyed.
*
* Since: 3.24.25
*/
void
gdk_wayland_window_remove_frame_callback_surface (GdkWindow *window,
struct wl_surface *surface)
{
GdkWindowImplWayland *impl;
g_return_if_fail (GDK_IS_WAYLAND_WINDOW (window));
g_return_if_fail (GDK_IS_WINDOW_IMPL_WAYLAND (window->impl));
g_return_if_fail (surface != NULL);
impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
g_hash_table_remove (impl->frame_callback_surfaces, surface);
}
<protocol name="gtk">
<interface name="gtk_shell1" version="3">
<interface name="gtk_shell1" version="4">
<description summary="gtk specific extensions">
gtk_shell is a protocol extension providing additional features for
clients implementing it.
......@@ -35,7 +35,7 @@
</request>
</interface>
<interface name="gtk_surface1" version="3">
<interface name="gtk_surface1" version="4">
<request name="set_dbus_properties">
<arg name="application_id" type="string" allow-null="true"/>
<arg name="app_menu_path" type="string" allow-null="true"/>
......@@ -82,6 +82,9 @@
<request name="request_focus" since="3">
<arg name="startup_id" type="string" allow-null="true"/>
</request>
<!-- Version 4 additions -->
<request name="release" type="destructor" since="4"/>
</interface>
</protocol>
......@@ -150,7 +150,18 @@ gdk_device_win32_query_state (GdkDevice *device,
if (child_window)
{
hwndc = ChildWindowFromPoint (hwnd, point);
if (window == gdk_screen_get_root_window (screen))
{
/* Always use WindowFromPoint when searching from the root window.
* Only WindowFromPoint is able to look through transparent
* layered windows.
*/
hwndc = GetAncestor (WindowFromPoint (point), GA_ROOT);
}
else
{
hwndc = ChildWindowFromPoint (hwnd, point);
}
if (hwndc && hwndc != hwnd)
*child_window = gdk_win32_handle_table_lookup (hwndc);
......@@ -201,71 +212,46 @@ _gdk_device_win32_window_at_position (GdkDevice *device,
GdkWindow *window = NULL;
GdkWindowImplWin32 *impl = NULL;
POINT screen_pt, client_pt;
HWND hwnd, hwndc;
HWND hwnd;
RECT rect;
GetCursorPos (&screen_pt);
if (!GetCursorPos (&screen_pt))
return NULL;
hwnd = WindowFromPoint (screen_pt);
if (get_toplevel)
{
/* Only consider visible children of the desktop to avoid the various
* non-visible windows you often find on a running Windows box. These
* might overlap our windows and cause our walk to fail. As we assume
* WindowFromPoint() can find our windows, we follow similar logic
* here, and ignore invisible and disabled windows.
*/
hwnd = GetDesktopWindow ();
do {
window = gdk_win32_handle_table_lookup (hwnd);
if (window != NULL &&
GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT &&
GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
break;
screen_to_client (hwnd, screen_pt, &client_pt);
hwndc = ChildWindowFromPointEx (hwnd, client_pt, CWP_SKIPDISABLED |
CWP_SKIPINVISIBLE);
/* Verify that we're really inside the client area of the window */
if (hwndc != hwnd)
{
GetClientRect (hwndc, &rect);
screen_to_client (hwndc, screen_pt, &client_pt);
if (!PtInRect (&rect, client_pt))
hwndc = hwnd;
}
} while (hwndc != hwnd && (hwnd = hwndc, 1));
/* Use WindowFromPoint instead of ChildWindowFromPoint(Ex).
* Only WindowFromPoint is able to look through transparent
* layered windows.
*/
hwnd = GetAncestor (hwnd, GA_ROOT);
}
else
{
hwnd = WindowFromPoint (screen_pt);
/* 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;
/* 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;
/* If we didn't hit any window at that point, return the desktop */
if (hwnd == NULL)
{
window = gdk_get_default_root_window ();
impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
if (win_x)
*win_x = (screen_pt.x + _gdk_offset_x) / impl->window_scale;
if (win_y)
*win_y = (screen_pt.y + _gdk_offset_y) / impl->window_scale;
if (!get_toplevel && hwnd == NULL)
{
/* If we didn't hit any window, return the root window */
/* note that the root window ain't a toplevel window */
window = gdk_get_default_root_window ();
impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
return window;
}
if (win_x)
*win_x = (screen_pt.x + _gdk_offset_x) / impl->window_scale;
if (win_y)
*win_y = (screen_pt.y + _gdk_offset_y) / impl->window_scale;
window = gdk_win32_handle_table_lookup (hwnd);
return window;
}
window = gdk_win32_handle_table_lookup (hwnd);
if (window && (win_x || win_y))
{
impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
......
......@@ -49,8 +49,8 @@ struct _GdkDeviceWintab
UINT cursor;
/* The cursor's CSR_PKTDATA */
WTPKT pktdata;
/* Azimuth and altitude axis */
AXIS orientation_axes[2];
/* Azimuth, altitude and twist axis */
AXIS orientation_axes[3];
};
struct _GdkDeviceWintabClass
......
This diff is collapsed.