Compare commits

...

27 Commits

Author SHA1 Message Date
Luca Bacci
b017dd54d1 testsuite: Ignore line endings when diff'ing results 2024-11-04 10:43:50 +01:00
Benjamin Otte
1855737aee testsuite: Allow renderers in misc test to fail
When GL or Vulkan is not supported, the test should not fail.

It would be nicer if we could detect GL/Vulkan not being available
otherwise, but I'm not aware of a better solution, in particular because
rendeers might have stricter requirements than GTK itself.

So this is the next best fix.
2024-10-28 09:56:19 +01:00
Benjamin Otte
710f5c088e Revert "testsuite: Fix introspection test on Windows"
This change is no longer necessary now that we properly set the right
directory for the needed DLLs.

This reverts commit 3471c22f52.
2024-10-28 07:48:49 +01:00
Benjamin Otte
06fb03ee50 testsuite: Set $PATH for introspection tests
This is necessary because Windows uses $PATH to search for DLLs and
meson isn't smart enough to figure out that this test needs access
to the DLL.
2024-10-28 05:44:18 +01:00
Benjamin Otte
587a547d64 testsuite: depend on gir and libgtk in introspection test
We also don't need to LD_PRELOAD anymore if we do that.
2024-10-28 05:38:13 +01:00
Benjamin Otte
7b2b538bc8 testsuite: Handle gdk_display_open() returning NULL
It turns out the Windows backend does that.
2024-10-28 01:09:30 +01:00
Benjamin Otte
e7c6e45701 win32: Don't return existing display from gdk_display_open()
Existing code assumes displays are new connections and calls
gdk_display_close() on the display when done with whatever it was
doing.

If we return an existing display, that display gets closed...

It's also what the other backends do, including MacOS.

Fixes gsk/misc test.
2024-10-28 01:09:30 +01:00
Benjamin Otte
2f1c42d095 win32: Stop sending clipboard_hwnd to main thread
With the switch to using the glib main context in the clipboard thread,
the clipboard hwnd is no longer used for sending messages.

This means it's not necessary to know it in the main thread.

And that means there's no small window where the clipboard thread spins
up and the window doesn't exist and any copy operation fails.
The main context can be created before spinning up the thread so
that is avoided.

Fixes the gtk/textbuffer test in the testsuite.
2024-10-28 01:09:05 +01:00
Benjamin Otte
2b36613b40 win32: Do async clipboard thread via main loop
Instead of sending windows messages, use the main loop.
This is closer to the expectations of GTK developers and has better
thread safety handling as no HWND is needed as a messaging queue token.
2024-10-28 01:09:05 +01:00
Benjamin Otte
43a64c93d4 win32: Split out a function 2024-10-28 01:09:05 +01:00
Benjamin Otte
bf342c01e1 win32: Remove useless code
The function is checking and early-exiting in this situation anyway.
2024-10-28 01:09:05 +01:00
Benjamin Otte
2b38e9002c win32: "unpop" items from clipboard queue
We can indeed "unpop" items from the clipboard queue, the function is
called g_async_queue_push_front().

So do that instead of tracking a GList.
2024-10-28 01:09:05 +01:00
Benjamin Otte
581f1d7bb4 gdk: Add GDK_DISABLE_AEROSNAP
Disables the Aerosnap hook for Windows which is particularly useful
when debugging because the aerosnap hook slows down keyboard input.
2024-10-28 01:09:05 +01:00
Benjamin Otte
aa47849d01 win32: Use the builder argument
We can straight build content formats these days, no need for a detour.
2024-10-28 01:09:05 +01:00
Benjamin Otte
557130efa1 win32: Some trivial cleanups
* Make a function static

* Don't lookup function that exists since Windows XP
2024-10-28 01:09:05 +01:00
Benjamin Otte
97254aaa33 win32: Remove unused variable
The variable was last used in GTK3.
2024-10-28 01:09:05 +01:00
Benjamin Otte
958adafa95 clipboard: Run a GMainLoop in the clipboard thread
Use the new message source to do the task of processing messages.
2024-10-28 01:09:05 +01:00
Benjamin Otte
7a0850dc8e win32: Add GdkWin32MessageSource
The source does nothing but run PeekMessage() + DispatchMessage().
But we need it in every thread where we want to use a main loop.

No users yet.
2024-10-28 01:09:05 +01:00
Benjamin Otte
661ef6427d win32: Don't crash if the settings are empty 2024-10-28 01:09:05 +01:00
Benjamin Otte
e405b598ab CI: Install Cantarell into msys build
The testsuite needs it.
2024-10-28 01:09:05 +01:00
Benjamin Otte
7fbccdd136 CI: Turn off gdb wrapper again
Also unset maxfail again.
2024-10-28 01:09:05 +01:00
Benjamin Otte
6823b830aa CI: Limit number of parallel tests for msys runs
This is the result of some consecutive runs with different values.
More would make the runtime of individual tests grow and we don't
want that.
2024-10-28 01:09:05 +01:00
Benjamin Otte
6dfd7a9629 CI: Catch test crashes with gdb wrapper
Add a gdb script to catch segfaults and launch it using meson --wrapper

And try really hard to make that script safe for Windows/msys, because
we want to use it there.
2024-10-28 01:09:05 +01:00
Benjamin Otte
203b1febb1 CI: Set MESON_TEST_MAX_FAIL for msys build 2024-10-28 01:09:05 +01:00
Benjamin Otte
eb60360bc6 CI: Add a meson test run for mingw
So far, we disable all GL and Vulkan testing, because neither of them
works in CI.
2024-10-28 01:09:05 +01:00
Benjamin Otte
fad8475909 CI: Add MESON_TEST_MAX_FAIL variable
Sets the value to be used for meson test --maxfail. This is useful when
bringing up a new testrunner or generally when debugging some changes
that cause many test failures.

If not set, we set it to 0, meaning disabled.
2024-10-28 01:09:05 +01:00
Benjamin Otte
808ff04c52 CI: Split Fedora runs from test runs
That way, we can inherit from either separately.
2024-10-28 01:09:05 +01:00
22 changed files with 338 additions and 252 deletions

View File

@@ -59,8 +59,7 @@ style-check-diff:
script:
- .gitlab-ci/run-style-check-diff.sh
.build-fedora-default:
image: $FEDORA_IMAGE
.test-runner:
artifacts:
when: always
reports:
@@ -68,6 +67,7 @@ style-check-diff:
- "${CI_PROJECT_DIR}/_build/report-x11.xml"
- "${CI_PROJECT_DIR}/_build/report-wayland.xml"
- "${CI_PROJECT_DIR}/_build/report-wayland_gl.xml"
- "${CI_PROJECT_DIR}/_build/report-win32.xml"
- "${CI_PROJECT_DIR}/_build/report-broadway.xml"
name: "gtk-${CI_COMMIT_REF_NAME}"
paths:
@@ -82,13 +82,20 @@ style-check-diff:
- "${CI_PROJECT_DIR}/_build/testsuite/css/output/*/*.syscap"
- "${CI_PROJECT_DIR}/_build/testsuite/headless/*/*.log"
- "${CI_PROJECT_DIR}/_build_hello/meson-logs"
# somewhat hacky to add this here, but avoids yaml madness
- "${CI_PROJECT_DIR}/_build/gtkdll.tar.gz"
.build-fedora-default:
image: $FEDORA_IMAGE
cache:
key: "$CI_JOB_NAME"
paths:
- _ccache/
fedora-x86_64:
extends: .build-fedora-default
extends:
- .test-runner
- .build-fedora-default
stage: build
needs: []
variables:
@@ -110,7 +117,9 @@ fedora-x86_64:
- .gitlab-ci/run-tests.sh _build wayland_gl gtk:gdk,gtk:gsk-gl
release-build:
extends: .build-fedora-default
extends:
- .test-runner
- .build-fedora-default
stage: build
needs: []
variables:
@@ -188,6 +197,7 @@ fedora-mingw64:
script:
- C:\msys64\usr\bin\pacman --noconfirm -Syyuu
- C:\msys64\usr\bin\bash -lc "bash -x ./.gitlab-ci/test-msys2.sh"
- C:\msys64\usr\bin\bash -lc "bash -x ./.gitlab-ci/run-tests.sh _build win32 gtk"
cache:
key: "$CI_JOB_NAME"
paths:
@@ -199,17 +209,15 @@ fedora-mingw64:
- subprojects/pango/
msys2-ucrt64:
extends: .mingw-defaults
extends:
- .test-runner
- .mingw-defaults
needs: []
variables:
MSYSTEM: "UCRT64"
CHERE_INVOKING: "yes"
artifacts:
when: always
expose_as: 'Windows_DLL_MSYS2_64_bit_toolchain'
paths:
- "${CI_PROJECT_DIR}/_build/gtkdll.tar.gz"
MESON_TEST_MAX_PROCESSES: 2
macos:
rules:
# Do not run in forks as the runner is not available there.
@@ -391,7 +399,9 @@ static-scan:
# Run tests with the address sanitizer. We need to turn off introspection
# and f16c, since they are incompatible with asan
asan-build:
extends: .build-fedora-default
extends:
- .test-runner
- .build-fedora-default
tags: [ asan ]
stage: analysis
needs: []

View File

@@ -0,0 +1,28 @@
set charset UTF-8
set logging redirect on
set logging debugredirect on
set logging enabled on
set schedule-multiple on
set detach-on-fork off
catch signal
commands
set logging enabled off
py print ("# " + gdb.execute ("thread apply all bt full", True, True).replace ("\n", "\n# "))
set logging enabled on
c
end
catch signal SIGTRAP
commands
set logging enabled off
py print ("# " + gdb.execute ("thread apply all bt full", True, True).replace ("\n", "\n# "))
set logging enabled on
q 1
end
r
if $_isvoid($_exitcode)
q $_exitsignal
else
q $_exitcode

View File

@@ -9,6 +9,7 @@ setup=$2
suite=$3
multiplier=${MESON_TEST_TIMEOUT_MULTIPLIER:-1}
n_processes=${MESON_TEST_MAX_PROCESSES:-1}
max_fail=${MESON_TEST_MAX_FAIL:-0}
# Ignore memory leaks lower in dependencies
export LSAN_OPTIONS=suppressions=$srcdir/lsan.supp:print_suppressions=0:detect_leaks=0:allocator_may_return_null=1
@@ -21,6 +22,7 @@ case "${setup}" in
--quiet \
--timeout-multiplier "${multiplier}" \
--num-processes "${n_processes}" \
--maxfail "${max_fail}" \
--print-errorlogs \
--setup=${setup} \
--suite=${suite//,/ --suite=} \
@@ -47,6 +49,7 @@ case "${setup}" in
--quiet \
--timeout-multiplier "${multiplier}" \
--num-processes "${n_processes}" \
--maxfail "${max_fail}" \
--print-errorlogs \
--setup=${setup} \
--suite=${suite//,/ --suite=} \
@@ -72,6 +75,7 @@ case "${setup}" in
--quiet \
--timeout-multiplier "${multiplier}" \
--num-processes "${n_processes}" \
--maxfail "${max_fail}" \
--print-errorlogs \
--setup=${setup} \
--suite=${suite//,/ --suite=} \
@@ -84,6 +88,26 @@ case "${setup}" in
kill ${server}
;;
win32*)
meson test -C ${builddir} \
--quiet \
--timeout-multiplier "${multiplier}" \
--num-processes "${n_processes}" \
--maxfail "${max_fail}" \
--print-errorlogs \
--setup=${setup} \
--suite=${suite//,/ --suite=} \
--no-suite=failing \
--no-suite=${setup}_failing \
--no-suite=flaky \
--no-suite=headless \
--no-suite=gsk-compare-gl \
--no-suite=gsk-compare-ngl \
--no-suite=gsk-compare-vulkan \
--no-suite=gsk-compare-broadway
exit_code=$?
;;
*)
echo "Failed to add ${setup} to .gitlab-ci/run-tests.sh"
exit 1

View File

@@ -17,6 +17,8 @@ pacman --noconfirm -S --needed \
${MINGW_PACKAGE_PREFIX}-adwaita-icon-theme \
${MINGW_PACKAGE_PREFIX}-atk \
${MINGW_PACKAGE_PREFIX}-cairo \
${MINGW_PACKAGE_PREFIX}-cantarell-fonts \
${MINGW_PACKAGE_PREFIX}-gdb \
${MINGW_PACKAGE_PREFIX}-gdk-pixbuf2 \
${MINGW_PACKAGE_PREFIX}-glib2 \
${MINGW_PACKAGE_PREFIX}-graphene \

View File

@@ -158,6 +158,7 @@ static const GdkDebugKey gdk_feature_keys[] = {
{ "dmabuf", GDK_FEATURE_DMABUF, "Disable dmabuf support" },
{ "offload", GDK_FEATURE_OFFLOAD, "Disable graphics offload" },
{ "color-mgmt", GDK_FEATURE_COLOR_MANAGEMENT, "Disable color management" },
{ "aerosnap", GDK_FEATURE_AEROSNAP, "Disable Aerosnap support on Windows" },
};

View File

@@ -64,6 +64,7 @@ typedef enum {
GDK_FEATURE_DMABUF = 1 << 7,
GDK_FEATURE_OFFLOAD = 1 << 8,
GDK_FEATURE_COLOR_MANAGEMENT = 1 << 9,
GDK_FEATURE_AEROSNAP = 1 << 10,
} GdkFeatures;
#define GDK_ALL_FEATURES ((1 << 10) - 1)

View File

@@ -62,12 +62,13 @@ gdk_win32_clipboard_request_contentformats (GdkWin32Clipboard *cb)
UINT w32_formats_len = 0;
UINT w32_formats_allocated;
gsize i;
GArray *formatpairs;
GdkContentFormatsBuilder *builder;
GdkContentFormats *formats;
GdkWin32Clipdrop *clipdrop = gdk_win32_clipboard_get_clipdrop (GDK_CLIPBOARD (cb));
DWORD error_code;
SetLastError (0);
success = clipdrop->GetUpdatedClipboardFormats (NULL, 0, &w32_formats_allocated);
success = GetUpdatedClipboardFormats (NULL, 0, &w32_formats_allocated);
error_code = GetLastError ();
if (!success && error_code != ERROR_INSUFFICIENT_BUFFER)
@@ -79,7 +80,7 @@ gdk_win32_clipboard_request_contentformats (GdkWin32Clipboard *cb)
w32_formats = g_new0 (UINT, w32_formats_allocated);
SetLastError (0);
success = clipdrop->GetUpdatedClipboardFormats (w32_formats, w32_formats_allocated, &w32_formats_len);
success = GetUpdatedClipboardFormats (w32_formats, w32_formats_allocated, &w32_formats_len);
error_code = GetLastError ();
if (!success)
@@ -89,46 +90,21 @@ gdk_win32_clipboard_request_contentformats (GdkWin32Clipboard *cb)
return NULL;
}
formatpairs = g_array_sized_new (FALSE,
FALSE,
sizeof (GdkWin32ContentFormatPair),
MIN (w32_formats_len, w32_formats_allocated));
builder = gdk_content_formats_builder_new ();
for (i = 0; i < MIN (w32_formats_len, w32_formats_allocated); i++)
gdk_win32_clipdrop_add_win32_format_to_pairs (clipdrop, w32_formats[i], formatpairs, NULL);
gdk_win32_clipdrop_add_win32_format_to_pairs (clipdrop, w32_formats[i], NULL, builder);
g_free (w32_formats);
formats = gdk_content_formats_builder_free_to_formats (builder);
GDK_NOTE (DND, {
g_print ("... ");
for (i = 0; i < formatpairs->len; i++)
{
const char *mime_type = (const char *) g_array_index (formatpairs, GdkWin32ContentFormatPair, i).contentformat;
g_print ("%s", mime_type);
if (i < formatpairs->len - 1)
g_print (", ");
}
g_print ("\n");
char *s = gdk_content_formats_to_string (formats);
g_print ("... %s\n", s);
g_free (s);
});
if (formatpairs->len > 0)
{
GdkContentFormatsBuilder *builder = gdk_content_formats_builder_new ();
for (i = 0; i < formatpairs->len; i++)
gdk_content_formats_builder_add_mime_type (builder, g_array_index (formatpairs, GdkWin32ContentFormatPair, i).contentformat);
g_array_free (formatpairs, TRUE);
return gdk_content_formats_builder_free_to_formats (builder);
}
else
{
g_array_free (formatpairs, TRUE);
return NULL;
}
return formats;
}
void

View File

@@ -283,6 +283,7 @@ Otherwise it's similar to how the clipboard works. Only the DnD server
#include "gdkhdataoutputstream-win32.h"
#include "gdkwin32dnd.h"
#include "gdkwin32dnd-private.h"
#include "gdkwin32messagesourceprivate.h"
#include "gdkwin32.h"
#include "gdk/gdkdebugprivate.h"
@@ -408,15 +409,6 @@ struct _GdkWin32ClipboardThread
*/
HWND clipboard_opened_for;
/* We can't peek the queue or "unpop" queue items,
* so the items that we can't act upon (yet) got
* to be stored *somewhere*.
*/
GList *dequeued_items;
/* Wakeup timer id (1 if timer is set, 0 otherwise) */
UINT wakeup_timer;
/* The formats that the main thread claims to provide */
GArray *cached_advertisement; /* of GdkWin32ContentFormatPair */
@@ -424,9 +416,6 @@ struct _GdkWin32ClipboardThread
* Contains GdkWin32ClipboardThreadRender structs.
*/
GAsyncQueue *render_queue;
/* Set to TRUE when we're calling EmptyClipboard () */
gboolean ignore_destroy_clipboard;
};
typedef struct _GdkWin32ClipboardThreadResponse GdkWin32ClipboardThreadResponse;
@@ -467,18 +456,6 @@ _gdk_win32_format_uses_hdata (UINT w32format)
}
}
/* This function is called in the main thread */
static gboolean
clipboard_hwnd_created (gpointer user_data)
{
GdkWin32Clipdrop *clipdrop = gdk_win32_display_get_clipdrop (gdk_display_get_default ());
clipdrop->clipboard_hwnd = (HWND) user_data;
return G_SOURCE_REMOVE;
}
/* This function is called in the main thread */
static gboolean
clipboard_owner_changed (gpointer user_data)
@@ -735,10 +712,8 @@ process_advertise (GdkWin32Clipdrop *clipdrop,
return FALSE;
}
CLIPDROP_CB_THREAD_MEMBER (clipdrop, ignore_destroy_clipboard) = TRUE;
if (!EmptyClipboard ())
{
CLIPDROP_CB_THREAD_MEMBER (clipdrop, ignore_destroy_clipboard) = FALSE;
error_code = GetLastError ();
send_response (adv->parent.item_type,
adv->parent.opaque_task,
@@ -747,8 +722,6 @@ process_advertise (GdkWin32Clipdrop *clipdrop,
return FALSE;
}
CLIPDROP_CB_THREAD_MEMBER (clipdrop, ignore_destroy_clipboard) = FALSE;
if (adv->unset)
return FALSE;
@@ -946,8 +919,6 @@ process_retrieve (GdkWin32Clipdrop *clipdrop,
if (CLIPDROP_CB_THREAD_MEMBER (clipdrop, clipboard_opened_for) == INVALID_HANDLE_VALUE)
error_code = try_open_clipboard (clipdrop, CLIPDROP_CB_THREAD_MEMBER (clipdrop, clipboard_hwnd));
else
error_code = try_open_clipboard (clipdrop, CLIPDROP_CB_THREAD_MEMBER (clipdrop, clipboard_opened_for));
if (error_code == ERROR_ACCESS_DENIED)
return TRUE;
@@ -1033,38 +1004,14 @@ process_retrieve (GdkWin32Clipdrop *clipdrop,
}
static gboolean
process_clipboard_queue (GdkWin32Clipdrop *clipdrop)
process_clipboard_queue (gpointer data)
{
GdkWin32Clipdrop *clipdrop = data;
GdkWin32ClipboardThreadQueueItem *placeholder;
GList *p;
gboolean try_again;
GList *p_next;
for (p = CLIPDROP_CB_THREAD_MEMBER (clipdrop, dequeued_items), p_next = NULL; p; p = p_next)
{
placeholder = (GdkWin32ClipboardThreadQueueItem *) p->data;
p_next = p->next;
switch (placeholder->item_type)
{
case GDK_WIN32_CLIPBOARD_THREAD_QUEUE_ITEM_ADVERTISE:
try_again = process_advertise (clipdrop, (GdkWin32ClipboardThreadAdvertise *) placeholder);
break;
case GDK_WIN32_CLIPBOARD_THREAD_QUEUE_ITEM_RETRIEVE:
try_again = process_retrieve (clipdrop, (GdkWin32ClipboardThreadRetrieve *) placeholder);
break;
case GDK_WIN32_CLIPBOARD_THREAD_QUEUE_ITEM_STORE:
try_again = process_store (clipdrop, (GdkWin32ClipboardThreadStore *) placeholder);
break;
}
if (try_again)
return FALSE;
CLIPDROP_CB_THREAD_MEMBER (clipdrop, dequeued_items) = g_list_delete_link (CLIPDROP_CB_THREAD_MEMBER (clipdrop, dequeued_items), p);
free_queue_item (placeholder);
}
while ((placeholder = g_async_queue_try_pop (CLIPDROP_CB_THREAD_MEMBER (clipdrop, input_queue))) != NULL)
{
switch (placeholder->item_type)
@@ -1080,18 +1027,30 @@ process_clipboard_queue (GdkWin32Clipdrop *clipdrop)
break;
}
if (!try_again)
if (try_again)
{
free_queue_item (placeholder);
continue;
GSource *source;
g_async_queue_push_front (CLIPDROP_CB_THREAD_MEMBER (clipdrop, input_queue), placeholder);
source = g_timeout_source_new (1000);
g_source_set_priority (source, G_PRIORITY_DEFAULT);
g_source_set_callback (source, process_clipboard_queue, clipdrop, NULL);
g_source_attach (source, clipdrop->clipboard_main_context);
g_source_unref (source);
break;
}
CLIPDROP_CB_THREAD_MEMBER (clipdrop, dequeued_items) = g_list_append (CLIPDROP_CB_THREAD_MEMBER (clipdrop, dequeued_items), placeholder);
return FALSE;
free_queue_item (placeholder);
}
return TRUE;
if (CLIPDROP_CB_THREAD_MEMBER (clipdrop, clipboard_opened_for) != INVALID_HANDLE_VALUE)
{
API_CALL (CloseClipboard, ());
CLIPDROP_CB_THREAD_MEMBER (clipdrop, clipboard_opened_for) = INVALID_HANDLE_VALUE;
}
return G_SOURCE_REMOVE;
}
static void
@@ -1113,9 +1072,9 @@ discard_render (GdkWin32ClipboardThreadRender *render,
static LRESULT
inner_clipboard_hwnd_procedure (HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam)
UINT message,
WPARAM wparam,
LPARAM lparam)
{
GdkWin32Clipdrop *clipdrop = NULL;
@@ -1131,49 +1090,6 @@ inner_clipboard_hwnd_procedure (HWND hwnd,
else
clipdrop = (GdkWin32Clipdrop *) GetWindowLongPtr (hwnd, GWLP_USERDATA);
if (message == clipdrop->thread_wakeup_message ||
message == WM_TIMER)
{
gboolean queue_is_empty = FALSE;
if (clipdrop->clipboard_thread_items == NULL)
{
g_warning ("Clipboard thread got an actionable message with no thread data");
return DefWindowProcW (hwnd, message, wparam, lparam);
}
queue_is_empty = process_clipboard_queue (clipdrop);
if (queue_is_empty && CLIPDROP_CB_THREAD_MEMBER (clipdrop, wakeup_timer))
{
API_CALL (KillTimer, (CLIPDROP_CB_THREAD_MEMBER (clipdrop, clipboard_hwnd), CLIPDROP_CB_THREAD_MEMBER (clipdrop, wakeup_timer)));
CLIPDROP_CB_THREAD_MEMBER (clipdrop, wakeup_timer) = 0;
}
/* Close the clipboard after each queue run, if it's open.
* It would be wrong to keep it open, even if we would
* need it again a second later.
* queue_is_empty == FALSE implies that the clipboard
* is closed already, but it's better to be sure.
*/
if (CLIPDROP_CB_THREAD_MEMBER (clipdrop, clipboard_opened_for) != INVALID_HANDLE_VALUE)
{
API_CALL (CloseClipboard, ());
CLIPDROP_CB_THREAD_MEMBER (clipdrop, clipboard_opened_for) = INVALID_HANDLE_VALUE;
}
if (queue_is_empty ||
CLIPDROP_CB_THREAD_MEMBER (clipdrop, wakeup_timer) != 0)
return 0;
if (SetTimer (CLIPDROP_CB_THREAD_MEMBER (clipdrop, clipboard_hwnd), 1, 1000, NULL))
CLIPDROP_CB_THREAD_MEMBER (clipdrop, wakeup_timer) = 1;
else
g_critical ("Failed to set a timer for the clipboard HWND 0x%p: %lu",
CLIPDROP_CB_THREAD_MEMBER (clipdrop, clipboard_hwnd),
GetLastError ());
}
switch (message)
{
case WM_DESTROY: /* unregister the clipboard listener */
@@ -1250,7 +1166,7 @@ inner_clipboard_hwnd_procedure (HWND hwnd,
CLIPDROP_CB_THREAD_MEMBER (clipdrop, cached_advertisement) = NULL;
}
API_CALL (PostMessage, (CLIPDROP_CB_THREAD_MEMBER (clipdrop, clipboard_hwnd), clipdrop->thread_wakeup_message, 0, 0));
process_clipboard_queue (clipdrop);
if (hwnd_owner != CLIPDROP_CB_THREAD_MEMBER (clipdrop, clipboard_hwnd))
g_idle_add_full (G_PRIORITY_DEFAULT, clipboard_owner_changed, NULL, NULL);
@@ -1389,11 +1305,11 @@ inner_clipboard_hwnd_procedure (HWND hwnd,
}
}
LRESULT CALLBACK
_clipboard_hwnd_procedure (HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam)
static LRESULT CALLBACK
clipboard_hwnd_procedure (HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam)
{
LRESULT retval;
@@ -1416,7 +1332,7 @@ register_clipboard_notification (GdkWin32Clipdrop *clipdrop)
ATOM klass;
wclass.lpszClassName = L"GdkClipboardNotification";
wclass.lpfnWndProc = _clipboard_hwnd_procedure;
wclass.lpfnWndProc = clipboard_hwnd_procedure;
wclass.hInstance = this_module ();
wclass.cbWndExtra = sizeof (GdkWin32ClipboardThread *);
@@ -1441,8 +1357,6 @@ register_clipboard_notification (GdkWin32Clipdrop *clipdrop)
goto failed;
}
g_idle_add_full (G_PRIORITY_DEFAULT, clipboard_hwnd_created, (gpointer) CLIPDROP_CB_THREAD_MEMBER (clipdrop, clipboard_hwnd), NULL);
return TRUE;
failed:
@@ -1458,8 +1372,14 @@ _gdk_win32_clipboard_thread_main (gpointer data)
MSG msg;
GAsyncQueue *queue = self->clipboard_open_thread_queue;
GAsyncQueue *render_queue = self->clipboard_render_queue;
guint message_source_id;
GMainLoop *loop;
g_assert (self->clipboard_thread_items == NULL);
g_assert (self->clipboard_main_context != NULL);
g_main_context_push_thread_default (self->clipboard_main_context);
message_source_id = gdk_win32_message_source_add (self->clipboard_main_context);
self->clipboard_thread_items = g_new0 (GdkWin32ClipboardThread, 1);
CLIPDROP_CB_THREAD_MEMBER (self, input_queue) = queue;
@@ -1474,17 +1394,18 @@ _gdk_win32_clipboard_thread_main (gpointer data)
return NULL;
}
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
loop = g_main_loop_new (self->clipboard_main_context, TRUE);
g_main_loop_run (loop);
g_main_loop_unref (loop);
/* Just in case, as this should only happen when we shut down */
DestroyWindow (CLIPDROP_CB_THREAD_MEMBER (self, clipboard_hwnd));
CloseHandle (CLIPDROP_CB_THREAD_MEMBER (self, clipboard_hwnd));
g_clear_pointer (&self->clipboard_thread_items, g_free);
g_source_remove (message_source_id);
g_main_context_pop_thread_default (self->clipboard_main_context);
return NULL;
}
@@ -1519,14 +1440,9 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop)
int i;
GArray *comp;
GdkWin32ContentFormatPair fmt;
HMODULE user32;
win32_clipdrop->thread_wakeup_message = RegisterWindowMessage (L"GDK_WORKER_THREAD_WEAKEUP");
user32 = LoadLibrary (L"user32.dll");
win32_clipdrop->GetUpdatedClipboardFormats = (GetUpdatedClipboardFormatsFunc) GetProcAddress (user32, "GetUpdatedClipboardFormats");
FreeLibrary (user32);
atoms = g_array_sized_new (FALSE, TRUE, sizeof (const char *), GDK_WIN32_ATOM_INDEX_LAST);
g_array_set_size (atoms, GDK_WIN32_ATOM_INDEX_LAST);
cfs = g_array_sized_new (FALSE, TRUE, sizeof (UINT), GDK_WIN32_CF_INDEX_LAST);
@@ -1808,6 +1724,7 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop)
win32_clipdrop->clipboard_open_thread_queue = g_async_queue_new ();
win32_clipdrop->clipboard_render_queue = g_async_queue_new ();
win32_clipdrop->clipboard_main_context = g_main_context_new ();
win32_clipdrop->clipboard_open_thread = g_thread_new ("GDK Win32 Clipboard Thread",
_gdk_win32_clipboard_thread_main,
win32_clipdrop);
@@ -2760,6 +2677,29 @@ _gdk_win32_add_contentformat_to_pairs (GdkWin32Clipdrop *clip_drop,
return added_count;
}
static void
gdk_win32_clipdrop_run_in_clipboard_thread (GdkWin32Clipdrop *self,
GdkWin32ClipboardThreadQueueItem *item)
{
gboolean was_empty;
g_async_queue_lock (self->clipboard_open_thread_queue);
was_empty = g_async_queue_length_unlocked (self->clipboard_open_thread_queue) == 0;
g_async_queue_push_unlocked (self->clipboard_open_thread_queue, item);
g_async_queue_unlock (self->clipboard_open_thread_queue);
if (was_empty)
{
GSource *source;
source = g_idle_source_new ();
g_source_set_priority (source, G_PRIORITY_DEFAULT);
g_source_set_callback (source, process_clipboard_queue, self, NULL);
g_source_attach (source, self->clipboard_main_context);
g_source_unref (source);
}
}
void
_gdk_win32_advertise_clipboard_contentformats (GdkClipboard *cb,
GTask *task,
@@ -2771,8 +2711,6 @@ _gdk_win32_advertise_clipboard_contentformats (GdkClipboard *cb,
gsize mime_types_len;
gsize i;
g_assert (clipdrop->clipboard_hwnd != NULL);
adv->parent.item_type = GDK_WIN32_CLIPBOARD_THREAD_QUEUE_ITEM_ADVERTISE;
adv->parent.start_time = g_get_monotonic_time ();
adv->parent.end_time = adv->parent.start_time + CLIPBOARD_OPERATION_TIMEOUT;
@@ -2793,10 +2731,7 @@ _gdk_win32_advertise_clipboard_contentformats (GdkClipboard *cb,
_gdk_win32_add_contentformat_to_pairs (clipdrop, mime_types[i], adv->pairs);
}
g_async_queue_push (clipdrop->clipboard_open_thread_queue, adv);
API_CALL (PostMessage, (clipdrop->clipboard_hwnd, clipdrop->thread_wakeup_message, 0, 0));
return;
gdk_win32_clipdrop_run_in_clipboard_thread (clipdrop, &adv->parent);
}
void
@@ -2810,8 +2745,6 @@ _gdk_win32_retrieve_clipboard_contentformats (GdkClipboard *cb,
gsize mime_types_len;
gsize i;
g_assert (clipdrop->clipboard_hwnd != NULL);
retr->parent.item_type = GDK_WIN32_CLIPBOARD_THREAD_QUEUE_ITEM_RETRIEVE;
retr->parent.start_time = g_get_monotonic_time ();
retr->parent.end_time = retr->parent.start_time + CLIPBOARD_OPERATION_TIMEOUT;
@@ -2824,10 +2757,7 @@ _gdk_win32_retrieve_clipboard_contentformats (GdkClipboard *cb,
for (i = 0; i < mime_types_len; i++)
_gdk_win32_add_contentformat_to_pairs (clipdrop, mime_types[i], retr->pairs);
g_async_queue_push (clipdrop->clipboard_open_thread_queue, retr);
API_CALL (PostMessage, (clipdrop->clipboard_hwnd, clipdrop->thread_wakeup_message, 0, 0));
return;
gdk_win32_clipdrop_run_in_clipboard_thread (clipdrop, &retr->parent);
}
typedef struct _GdkWin32ClipboardHDataPrepAndStream GdkWin32ClipboardHDataPrepAndStream;
@@ -2905,8 +2835,7 @@ clipboard_store_hdata_ready (GObject *clipboard,
store->parent.opaque_task = prep->store_task;
store->elements = prep->elements;
g_async_queue_push (clipdrop->clipboard_open_thread_queue, store);
API_CALL (PostMessage, (clipdrop->clipboard_hwnd, clipdrop->thread_wakeup_message, 0, 0));
gdk_win32_clipdrop_run_in_clipboard_thread (clipdrop, &store->parent);
g_free (prep);
}
@@ -2923,8 +2852,6 @@ _gdk_win32_store_clipboard_contentformats (GdkClipboard *cb,
GdkWin32Clipdrop *clipdrop = gdk_win32_display_get_clipdrop (gdk_clipboard_get_display (cb));
GdkWin32ClipboardStorePrep *prep;
g_assert (clipdrop->clipboard_hwnd != NULL);
mime_types = gdk_content_formats_get_mime_types (contentformats, &n_mime_types);
pairs = g_array_sized_new (FALSE,

View File

@@ -113,12 +113,6 @@ typedef enum _GdkWin32CFIndex GdkWin32CFIndex;
typedef struct _GdkWin32Clipdrop GdkWin32Clipdrop;
typedef struct _GdkWin32ClipdropClass GdkWin32ClipdropClass;
typedef BOOL (WINAPI * GetUpdatedClipboardFormatsFunc)(
_Out_ PUINT lpuiFormats,
_In_ UINT cFormats,
_Out_ PUINT pcFormatsOut
);
/* This object is just a sink to hold all the clipboard- and dnd-related data
* that otherwise would be in global variables.
*/
@@ -147,14 +141,6 @@ struct _GdkWin32Clipdrop
/* A format-keyed hash table of GArrays of GdkAtoms describing compatibility contentformats for a w32format */
GHashTable *compatibility_contentformats;
/* By all rights we should be able to just use this function
* normally, as our target platform is Vista-or-later.
* This pointer is manually retrieved only to allow
* GTK to be compiled with old MinGW versions, which
* don't have GetUpdatedClipboardFormats in the import libs.
*/
GetUpdatedClipboardFormatsFunc GetUpdatedClipboardFormats;
/* The thread that tries to open the clipboard and then
* do stuff with it. Since clipboard opening can
* fail, we split the code into a thread, and let
@@ -163,6 +149,12 @@ struct _GdkWin32Clipdrop
*/
GThread *clipboard_open_thread;
/* The main loop run in the clipboard thread.
* When we want to communicate with the thread, we just add
* tasks to it via this context.
*/
GMainContext *clipboard_main_context;
/* Our primary means of communicating with the thread.
* The communication is one-way only - the thread replies
* by just queueing functions to be called in the main
@@ -177,13 +169,6 @@ struct _GdkWin32Clipdrop
*/
GAsyncQueue *clipboard_render_queue;
/* Window handle for the clipboard surface that we
* receive from the clipboard thread. We use that
* to wake up the clipboard surface main loop by
* posting a message to it.
*/
HWND clipboard_hwnd;
/* The thread that calls DoDragDrop (), which would
* normally block our main thread, as it runs its own
* Windows message loop.

View File

@@ -527,18 +527,16 @@ _gdk_win32_display_open (const char *display_name)
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 (display)) == 0)
if (display != NULL)
{
if (display != NULL)
{
GDK_NOTE (MISC, g_print ("... return existing gdkdisplay\n"));
return display;
}
GDK_NOTE (MISC, g_print ("... Display is already open\n"));
return NULL;
}
else
if (display_name != NULL)
{
/* we don't really support multiple GdkDisplay's on Windows at this point */
GDK_NOTE (MISC, g_print ("... return NULL\n"));
GDK_NOTE (MISC, g_print ("... win32 does not support named displays, but given name was \"%s\"\n", display_name));
return NULL;
}

View File

@@ -391,6 +391,9 @@ set_up_low_level_keyboard_hook (GdkDisplay *display)
{
HHOOK hook_handle;
if (!gdk_has_feature (GDK_FEATURE_AEROSNAP))
return;
if (GDK_WIN32_DISPLAY (display)->event_record->aerosnap_keyboard_hook != NULL)
return;

View File

@@ -0,0 +1,123 @@
#include "config.h"
#include "gdkwin32messagesourceprivate.h"
#include "gdkevents.h"
#include <windows.h>
typedef struct _GdkWin32MessageSource GdkWin32MessageSource;
struct _GdkWin32MessageSource
{
GSource source;
GPollFD poll_fd;
} ;
static gboolean
gdk_win32_message_source_prepare (GSource *source,
int *timeout)
{
GdkWin32MessageSource *self = (GdkWin32MessageSource *) source;
gboolean retval;
*timeout = -1;
return GetQueueStatus (QS_ALLINPUT) != 0;
}
static gboolean
gdk_win32_message_source_check (GSource *source)
{
GdkWin32MessageSource *self = (GdkWin32MessageSource *) source;
self->poll_fd.revents = 0;
return GetQueueStatus (QS_ALLINPUT) != 0;
}
static gboolean
gdk_win32_message_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
MSG msg;
while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return G_SOURCE_CONTINUE;
}
static void
gdk_win32_message_source_finalize (GSource *source)
{
#ifdef G_WITH_CYGWIN
close (self->poll_fd.fd);
#endif
}
static GSourceFuncs gdk_win32_message_source_funcs = {
gdk_win32_message_source_prepare,
gdk_win32_message_source_check,
gdk_win32_message_source_dispatch,
gdk_win32_message_source_finalize,
};
/*
* gdk_win32_message_source_new:
*
* Creates a new source for processing events of the Windows main loop.
*
* Returns: The new source
*/
GSource *
gdk_win32_message_source_new (void)
{
GdkWin32MessageSource *self;
GSource *source;
source = g_source_new (&gdk_win32_message_source_funcs, sizeof (GdkWin32MessageSource));
g_source_set_static_name (source, "GDK Win32 message source");
g_source_set_priority (source, GDK_PRIORITY_EVENTS);
self = (GdkWin32MessageSource *) source;
#ifdef G_WITH_CYGWIN
self->poll_fd.fd = open ("/dev/windows", O_RDONLY);
if (self->poll_fd.fd == -1)
g_error ("can't open \"/dev/windows\": %s", g_strerror (errno));
#else
self->poll_fd.fd = G_WIN32_MSG_HANDLE;
#endif
self->poll_fd.events = G_IO_IN;
g_source_add_poll (source, &self->poll_fd);
g_source_set_can_recurse (source, TRUE);
return source;
}
/*
* gdk_win32_message_source_add:
* @context: (nullable): The context to add the source to
*
* Adds a message source to the default main context.
*
* Returns: the ID (greater than 0) of the event source.
*/
guint
gdk_win32_message_source_add (GMainContext *context)
{
GSource *source;
guint id;
source = gdk_win32_message_source_new ();
id = g_source_attach (source, context);
g_source_unref (source);
return id;
}

View File

@@ -0,0 +1,7 @@
#pragma once
#include <glib.h>
GSource * gdk_win32_message_source_new (void);
guint gdk_win32_message_source_add (GMainContext *context);

View File

@@ -33,6 +33,7 @@ gdk_win32_sources = gdk_win32_public_sources + files([
'gdkvulkancontext-win32.c',
'gdkwin32cursor.h',
'gdkwin32display.h',
'gdkwin32messagesource.c',
'gdkwin32keys.h',
])

View File

@@ -962,6 +962,8 @@ devmode_from_settings (GtkPrintSettings *settings,
const char *extras_base64;
gsize extras_len;
const char *val;
gunichar2 *device_name;
glong device_name_len;
/* If we already provided a valid hDevMode, don't initialize a new one; just lock the one we have */
if (hDevMode)
@@ -986,8 +988,9 @@ devmode_from_settings (GtkPrintSettings *settings,
devmode->dmSpecVersion = DM_SPECVERSION;
devmode->dmSize = sizeof (DEVMODEW);
gunichar2 *device_name = g_utf8_to_utf16 (gtk_print_settings_get (settings, "win32-devmode-name"), -1, NULL, NULL, NULL);
memcpy (devmode->dmDeviceName, device_name, CCHDEVICENAME);
device_name = g_utf8_to_utf16 (gtk_print_settings_get (settings, "win32-devmode-name"), -1, NULL, &device_name_len, NULL);
if (device_name && device_name_len)
memcpy (devmode->dmDeviceName, device_name, MIN (device_name_len, CCHDEVICENAME) * sizeof (gunichar2));
g_free (device_name);

View File

@@ -155,7 +155,6 @@ test_renderer (GskRenderer *renderer)
GdkDisplay *display;
gboolean realized;
GdkSurface *surface;
gboolean res;
GError *error = NULL;
g_assert (GSK_IS_RENDERER (renderer));
@@ -172,24 +171,30 @@ test_renderer (GskRenderer *renderer)
g_assert_null (gsk_renderer_get_surface (renderer));
surface = gdk_surface_new_toplevel (display);
surface = gdk_surface_new_toplevel (display ? display : gdk_display_get_default ());
res = gsk_renderer_realize (renderer, surface, &error);
if (!gsk_renderer_realize (renderer, surface, &error))
{
g_test_skip_printf ("%s not available: %s", G_OBJECT_TYPE_NAME (renderer), error->message);
}
else
{
g_assert_no_error (error);
g_assert_no_error (error);
g_assert_true (res);
g_assert_true (gsk_renderer_is_realized (renderer));
g_assert_true (gsk_renderer_get_surface (renderer) == surface);
g_assert_true (gsk_renderer_is_realized (renderer));
g_assert_true (gsk_renderer_get_surface (renderer) == surface);
gsk_renderer_unrealize (renderer);
gsk_renderer_unrealize (renderer);
}
g_assert_false (gsk_renderer_is_realized (renderer));
g_assert_null (gsk_renderer_get_surface (renderer));
gdk_surface_destroy (surface);
gdk_display_close (display);
if (display)
gdk_display_close (display);
}
static void

View File

@@ -1,19 +1,7 @@
#! /usr/bin/env python3
import os
import sys
# Python 3.8.x or later on Windows require os.add_dll_directory()
# to be called on every directory that contains the required
# non-bundled, non-system DLLs of a module so that the module can
# be loaded successfully by Python. Make things easiler for people
# by calling os.add_dll_directory() on the valid paths in %PATH%.
if hasattr(os, 'add_dll_directory'):
paths = reversed(os.environ['PATH'].split(os.pathsep))
for path in paths:
if path != '' and os.path.isdir(path):
os.add_dll_directory(path)
try:
import gi
except ImportError:

View File

@@ -2,10 +2,14 @@ env = environment()
env.prepend('GI_TYPELIB_PATH',
project_build_root / 'gtk',
)
env.prepend('LD_PRELOAD', project_build_root / 'gtk' / 'libgtk-4.so')
if host_machine.system() == 'windows'
env.prepend('PATH', project_build_root / 'gtk')
endif
test('api',
find_program('api.py', dirs: meson.current_source_dir()),
suite: ['introspection'],
depends: [ gtk_gir, libgtk ],
env: env,
)

View File

@@ -25,7 +25,7 @@ for t in ${TESTS[*]}; do
cd $OLDPWD
if diff -u "$expected" "$result" > "$diff"; then
if diff --strip-trailing-cr -u "$expected" "$result" > "$diff"; then
echo "ok $I $name"
rm "$diff"
else

View File

@@ -22,7 +22,7 @@ for t in ${TESTS[*]}; do
$GTK_BUILDER_TOOL simplify $t 2>/dev/null >$result
if diff -u "$expected" "$result" > "$diff"; then
if diff --strip-trailing-cr -u "$expected" "$result" > "$diff"; then
echo "ok $I $name"
rm "$diff"
else
@@ -35,7 +35,7 @@ for t in ${TESTS[*]}; do
cp $t $result2
$GTK_BUILDER_TOOL simplify --replace $result2 2>/dev/null
if diff -u "$expected" "$result2" > "$diff"; then
if diff --strip-trailing-cr -u "$expected" "$result2" > "$diff"; then
echo "ok $I $name (--replace)"
rm "$diff"
else

View File

@@ -22,7 +22,7 @@ for t in ${TESTS[*]}; do
$GTK_BUILDER_TOOL simplify --3to4 $t 2>/dev/null >$result
if diff -u "$expected" "$result" > "$diff"; then
if diff --strip-trailing-cr -u "$expected" "$result" > "$diff"; then
echo "ok $I $name"
rm "$diff"
else
@@ -35,7 +35,7 @@ for t in ${TESTS[*]}; do
cp $t $result2
$GTK_BUILDER_TOOL simplify --3to4 --replace $result2 2>/dev/null
if diff -u "$expected" "$result2" > "$diff"; then
if diff --strip-trailing-cr -u "$expected" "$result2" > "$diff"; then
echo "ok $I $name (--replace)"
rm "$diff"
else

View File

@@ -28,7 +28,7 @@ for t in ${TESTS[*]}; do
cd $OLDPWD
if diff -u "$expected" "$result" > "$diff"; then
if diff --strip-trailing-cr -u "$expected" "$result" > "$diff"; then
echo "ok $I $name"
rm "$diff"
else