Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 61f7ac09bc | |||
| 688085cfaf |
+2
-7
@@ -25,7 +25,7 @@ variables:
|
||||
BACKEND_FLAGS: "-Dx11-backend=true -Dwayland-backend=true -Dbroadway-backend=true"
|
||||
FEATURE_FLAGS: "-Dvulkan=enabled -Dcloudproviders=enabled"
|
||||
MESON_TEST_TIMEOUT_MULTIPLIER: 3
|
||||
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v36"
|
||||
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v35"
|
||||
FLATPAK_IMAGE: "registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master"
|
||||
|
||||
.only-default:
|
||||
@@ -88,7 +88,7 @@ fedora-x86_64:
|
||||
- meson compile -C _build
|
||||
- meson install -C _build
|
||||
- PKG_CONFIG_PATH=${CI_PROJECT_DIR}/_install/lib64/pkgconfig:${CI_PROJECT_DIR}/_install/share/pkgconfig meson setup _build_hello examples/hello
|
||||
- LD_LIBRARY_PATH=${CI_PROJECT_DIR}/_install/lib64 meson compile -C _build_hello
|
||||
- meson compile -C _build_hello
|
||||
- .gitlab-ci/run-tests.sh _build x11
|
||||
- .gitlab-ci/run-tests.sh _build wayland
|
||||
- .gitlab-ci/run-tests.sh _build waylandgles
|
||||
@@ -156,11 +156,6 @@ msys2-mingw64:
|
||||
variables:
|
||||
MSYSTEM: "MINGW64"
|
||||
CHERE_INVOKING: "yes"
|
||||
artifacts:
|
||||
when: always
|
||||
expose_as: 'Windows_DLL_MSYS2_64_bit_toolchain'
|
||||
paths:
|
||||
- "${CI_PROJECT_DIR}/_build/gtkdll.tar.gz"
|
||||
|
||||
macos:
|
||||
extends: .only-default
|
||||
|
||||
@@ -95,8 +95,6 @@ RUN dnf -y install \
|
||||
weston-libs \
|
||||
which \
|
||||
xorg-x11-server-Xvfb \
|
||||
&& dnf install -y 'dnf-command(builddep)' \
|
||||
&& dnf builddep -y wayland \
|
||||
&& dnf clean all
|
||||
|
||||
# Enable sudo for wheel users
|
||||
|
||||
@@ -6,7 +6,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliar
|
||||
|
||||
:: FIXME: make warnings fatal
|
||||
pip3 install --upgrade --user meson==0.59 || goto :error
|
||||
meson -Ddebug=false -Dmedia-gstreamer=disabled _build || goto :error
|
||||
meson -Dmedia-gstreamer=disabled _build || goto :error
|
||||
ninja -C _build || goto :error
|
||||
|
||||
goto :EOF
|
||||
|
||||
@@ -73,5 +73,3 @@ unset CCACHE_DISABLE
|
||||
|
||||
ninja -C _build
|
||||
ccache --show-stats
|
||||
|
||||
tar zcf _build/gtkdll.tar.gz _build/gtk/libgtk*.dll
|
||||
|
||||
@@ -1,72 +1,5 @@
|
||||
Overview of Changes in 4.6.1, 11-02-2022
|
||||
========================================
|
||||
|
||||
* GtkFontChooser:
|
||||
- Stop using PangoFc api
|
||||
- Fix a crash
|
||||
- Use new HarfBuzz api
|
||||
|
||||
* GtkMenuButton:
|
||||
- Update accessible description
|
||||
|
||||
* GtkTextView:
|
||||
- Fix intra-widget dnd
|
||||
|
||||
* Printing:
|
||||
- Fix an fd leak
|
||||
|
||||
* Input:
|
||||
- Make sure input methods get focus-in events
|
||||
- Always flush events to avoid scroll event pileup
|
||||
- Support hold events
|
||||
- Update keysyms from libxkbcommon
|
||||
|
||||
* Theme:
|
||||
- Improve text selection legibility
|
||||
|
||||
* Introspection:
|
||||
- Add missing nullable annotations everywhere
|
||||
|
||||
* Build:
|
||||
- Make stack noexec again
|
||||
- Avoid symbol leaks
|
||||
- Drop unneeded script data
|
||||
|
||||
* Windows:
|
||||
- Stop using WM_SYNCPAINT
|
||||
- Relax check for GL 3.x legacy contexts
|
||||
- Use native apis for language names
|
||||
- Rewrite the keymap code
|
||||
- Use the GL renderer by default
|
||||
|
||||
* Wayland:
|
||||
- Fix support for the new high-contrast setting
|
||||
- Avoid redundant scale changes
|
||||
- Fix DND hotspot handling
|
||||
- Don't always restore the saved size when floating
|
||||
|
||||
* MacOS:
|
||||
- Various performance improvements
|
||||
|
||||
* Translation updates:
|
||||
Brazilian Portuguese
|
||||
Catalan
|
||||
Chinese (China)
|
||||
Galician
|
||||
Hebrew
|
||||
Japanese
|
||||
Lithuanian
|
||||
Persian
|
||||
Polish
|
||||
Portuguese
|
||||
Russian
|
||||
Slovenian
|
||||
Spanish
|
||||
Ukrainian
|
||||
|
||||
|
||||
Overview of Changes in 4.6.0, 30-12-2021
|
||||
========================================
|
||||
Overview of Changes
|
||||
===================
|
||||
|
||||
* GtkProgressBar:
|
||||
- Fix handling of "inverted"
|
||||
|
||||
@@ -43,8 +43,7 @@
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://gitlab.freedesktop.org/wayland/wayland.git",
|
||||
"branch" : "main"
|
||||
"url" : "https://gitlab.freedesktop.org/wayland/wayland.git"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -43,8 +43,7 @@
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://gitlab.freedesktop.org/wayland/wayland.git",
|
||||
"branch" : "main"
|
||||
"url" : "https://gitlab.freedesktop.org/wayland/wayland.git"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -43,8 +43,7 @@
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://gitlab.freedesktop.org/wayland/wayland.git",
|
||||
"branch" : "main"
|
||||
"url" : "https://gitlab.freedesktop.org/wayland/wayland.git"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -13,7 +13,7 @@ if 'DESTDIR' not in os.environ:
|
||||
|
||||
gtk_moduledir = os.path.join(gtk_libdir, 'gtk-' + gtk_api_version, gtk_abi_version)
|
||||
gtk_printmodule_dir = os.path.join(gtk_moduledir, 'printbackends')
|
||||
gtk_mediamodule_dir = os.path.join(gtk_moduledir, 'media')
|
||||
gtk_immodule_dir = os.path.join(gtk_moduledir, 'immodules')
|
||||
|
||||
print('Compiling GSettings schemas...')
|
||||
glib_compile_schemas = subprocess.check_output(['pkg-config',
|
||||
@@ -40,6 +40,6 @@ if 'DESTDIR' not in os.environ:
|
||||
gio_querymodules = 'gio-querymodules'
|
||||
subprocess.call([gio_querymodules, gtk_printmodule_dir])
|
||||
|
||||
print('Updating module cache for media backends...')
|
||||
os.makedirs(gtk_mediamodule_dir, exist_ok=True)
|
||||
subprocess.call([gio_querymodules, gtk_mediamodule_dir])
|
||||
print('Updating module cache for input methods...')
|
||||
os.makedirs(gtk_immodule_dir, exist_ok=True)
|
||||
subprocess.call([gio_querymodules, gtk_immodule_dir])
|
||||
|
||||
@@ -45,9 +45,7 @@
|
||||
<object class="GtkLabel">
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Font Features</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"></attribute>
|
||||
</attributes>
|
||||
<property name="attributes" translatable="yes">0 -1 weight bold</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
@@ -75,9 +73,7 @@
|
||||
<object class="GtkLabel" id="variations_heading">
|
||||
<property name="label" translatable="yes">Font Variations</property>
|
||||
<property name="xalign">0</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"></attribute>
|
||||
</attributes>
|
||||
<property name="attributes" translatable="yes">0 -1 weight bold</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <pango/pangofc-font.h>
|
||||
#include <hb.h>
|
||||
#include <hb-ot.h>
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
@@ -18,81 +18,15 @@
|
||||
|
||||
#include "language-names.h"
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#else
|
||||
|
||||
#ifndef ISO_CODES_PREFIX
|
||||
#define ISO_CODES_PREFIX "/usr"
|
||||
#endif
|
||||
|
||||
#define ISO_CODES_DATADIR ISO_CODES_PREFIX "/share/xml/iso-codes"
|
||||
#define ISO_CODES_LOCALESDIR ISO_CODES_PREFIX "/share/locale"
|
||||
#endif
|
||||
|
||||
static GHashTable *language_map;
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
/* if we are using native Windows use native Windows API for language names */
|
||||
static BOOL CALLBACK
|
||||
get_win32_all_locales_scripts (LPWSTR locale_w, DWORD flags, LPARAM param)
|
||||
{
|
||||
wchar_t *langname_w = NULL;
|
||||
wchar_t locale_abbrev_w[9];
|
||||
gchar *langname, *locale_abbrev, *locale, *p;
|
||||
gint i;
|
||||
const LCTYPE iso639_lctypes[] = { LOCALE_SISO639LANGNAME, LOCALE_SISO639LANGNAME2 };
|
||||
GHashTable *ht_scripts_langs = (GHashTable *) param;
|
||||
PangoLanguage *lang;
|
||||
|
||||
gint langname_size, locale_abbrev_size;
|
||||
langname_size = GetLocaleInfoEx (locale_w, LOCALE_SLOCALIZEDDISPLAYNAME, langname_w, 0);
|
||||
if (langname_size == 0)
|
||||
return FALSE;
|
||||
|
||||
langname_w = g_new0 (wchar_t, langname_size);
|
||||
|
||||
if (langname_size == 0)
|
||||
return FALSE;
|
||||
|
||||
GetLocaleInfoEx (locale_w, LOCALE_SLOCALIZEDDISPLAYNAME, langname_w, langname_size);
|
||||
langname = g_utf16_to_utf8 (langname_w, -1, NULL, NULL, NULL);
|
||||
locale = g_utf16_to_utf8 (locale_w, -1, NULL, NULL, NULL);
|
||||
p = strchr (locale, '-');
|
||||
lang = pango_language_from_string (locale);
|
||||
if (g_hash_table_lookup (ht_scripts_langs, lang) == NULL)
|
||||
g_hash_table_insert (ht_scripts_langs, lang, langname);
|
||||
|
||||
/*
|
||||
* Track 3+-letter ISO639-2/3 language codes as well (these have a max length of 9 including terminating NUL)
|
||||
* ISO639-2: iso639_lctypes[0] = LOCALE_SISO639LANGNAME
|
||||
* ISO639-3: iso639_lctypes[1] = LOCALE_SISO639LANGNAME2
|
||||
*/
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
locale_abbrev_size = GetLocaleInfoEx (locale_w, iso639_lctypes[i], locale_abbrev_w, 0);
|
||||
if (locale_abbrev_size > 0)
|
||||
{
|
||||
GetLocaleInfoEx (locale_w, iso639_lctypes[i], locale_abbrev_w, locale_abbrev_size);
|
||||
|
||||
locale_abbrev = g_utf16_to_utf8 (locale_abbrev_w, -1, NULL, NULL, NULL);
|
||||
lang = pango_language_from_string (locale_abbrev);
|
||||
if (g_hash_table_lookup (ht_scripts_langs, lang) == NULL)
|
||||
g_hash_table_insert (ht_scripts_langs, lang, langname);
|
||||
|
||||
g_free (locale_abbrev);
|
||||
}
|
||||
}
|
||||
|
||||
g_free (locale);
|
||||
g_free (langname_w);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#else /* non-Windows */
|
||||
|
||||
static char *
|
||||
get_first_item_in_semicolon_list (const char *list)
|
||||
{
|
||||
@@ -276,7 +210,6 @@ languages_variant_init (const char *variant)
|
||||
g_free (filename);
|
||||
g_free (buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
languages_init (void)
|
||||
@@ -285,13 +218,8 @@ languages_init (void)
|
||||
return;
|
||||
|
||||
language_map = g_hash_table_new_full (NULL, NULL, NULL, g_free);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
g_return_if_fail (EnumSystemLocalesEx (&get_win32_all_locales_scripts, LOCALE_ALL, (LPARAM) language_map, NULL));
|
||||
#else
|
||||
languages_variant_init ("iso_639");
|
||||
languages_variant_init ("iso_639_3");
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
|
||||
@@ -1040,7 +1040,7 @@ out:
|
||||
g_signal_connect_swapped (G_OBJECT (demo), "destroy", G_CALLBACK (g_application_quit), app);
|
||||
}
|
||||
else
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
gtk_widget_show (GTK_WIDGET (window));
|
||||
|
||||
if (autoquit)
|
||||
g_timeout_add_seconds (1, auto_quit, app);
|
||||
|
||||
@@ -98,7 +98,6 @@ demos = files([
|
||||
'transparent.c',
|
||||
'tree_store.c',
|
||||
'video_player.c',
|
||||
'font_features.c',
|
||||
])
|
||||
|
||||
gtkdemo_deps = [ libgtk_dep, ]
|
||||
@@ -129,9 +128,14 @@ extra_demo_sources = files([
|
||||
'script-names.c',
|
||||
'unicode-names.c',
|
||||
'suggestionentry.c',
|
||||
'language-names.c',
|
||||
])
|
||||
|
||||
if harfbuzz_dep.found() and pangoft_dep.found()
|
||||
demos += files(['font_features.c'])
|
||||
extra_demo_sources += files(['language-names.c'])
|
||||
gtkdemo_deps += [ harfbuzz_dep, epoxy_dep ]
|
||||
endif
|
||||
|
||||
if os_unix
|
||||
demos += files('pagesetup.c')
|
||||
endif
|
||||
@@ -160,7 +164,7 @@ endif
|
||||
|
||||
ld = find_program('ld', required : false)
|
||||
|
||||
if not meson.is_cross_build() and build_machine.cpu_family() != 'arm' and build_machine.system() == 'linux' and objcopy.found() and objcopy_supports_add_symbol and ld.found()
|
||||
if build_machine.system() == 'linux' and objcopy.found() and objcopy_supports_add_symbol and ld.found()
|
||||
glib_compile_resources = find_program('glib-compile-resources')
|
||||
|
||||
# Create the resource blob
|
||||
@@ -170,7 +174,6 @@ if not meson.is_cross_build() and build_machine.cpu_family() != 'arm' and build_
|
||||
depfile : 'gtkdemo.gresource.d',
|
||||
command : [glib_compile_resources,
|
||||
'--generate',
|
||||
'--internal',
|
||||
'--target=@OUTPUT@',
|
||||
'--dependency-file=@DEPFILE@',
|
||||
'--sourcedir=' + meson.current_source_dir(),
|
||||
@@ -184,7 +187,6 @@ if not meson.is_cross_build() and build_machine.cpu_family() != 'arm' and build_
|
||||
depfile : 'gtkdemo_resources.c.d',
|
||||
command : [glib_compile_resources,
|
||||
'--generate-source',
|
||||
'--internal',
|
||||
'--target=@OUTPUT@',
|
||||
'--dependency-file=@DEPFILE@',
|
||||
'--sourcedir=' + meson.current_source_dir(),
|
||||
@@ -198,7 +200,6 @@ if not meson.is_cross_build() and build_machine.cpu_family() != 'arm' and build_
|
||||
input : gtkdemo_gresource,
|
||||
output : 'gtkdemo_resources.o',
|
||||
command : [ld,
|
||||
'-z', 'noexecstack',
|
||||
'-r',
|
||||
'-b','binary',
|
||||
'@INPUT@',
|
||||
@@ -209,7 +210,6 @@ if not meson.is_cross_build() and build_machine.cpu_family() != 'arm' and build_
|
||||
input : gtkdemo_resources_binary,
|
||||
output : 'gtkdemo_resources2.o',
|
||||
command : [objcopy,
|
||||
'--strip-all',
|
||||
'--add-symbol','_g_binary_gtkdemo_resource_data=.data:0',
|
||||
'@INPUT@',
|
||||
'@OUTPUT@'])
|
||||
|
||||
@@ -871,7 +871,7 @@ activate (GApplication *app)
|
||||
|
||||
update_ui ();
|
||||
|
||||
gtk_window_present (GTK_WINDOW (main_window));
|
||||
gtk_widget_show (main_window);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -8,7 +8,7 @@ endif
|
||||
|
||||
ld = find_program('ld', required : false)
|
||||
|
||||
if not meson.is_cross_build() and build_machine.cpu_family() != 'arm' and build_machine.system() == 'linux' and objcopy.found() and objcopy_supports_add_symbol and ld.found()
|
||||
if build_machine.system() == 'linux' and objcopy.found() and objcopy_supports_add_symbol and ld.found()
|
||||
glib_compile_resources = find_program('glib-compile-resources')
|
||||
|
||||
# Create the resource blob
|
||||
@@ -18,7 +18,6 @@ if not meson.is_cross_build() and build_machine.cpu_family() != 'arm' and build_
|
||||
depfile: 'widgetfactory.gresource.d',
|
||||
command : [glib_compile_resources,
|
||||
'--generate',
|
||||
'--internal',
|
||||
'--target=@OUTPUT@',
|
||||
'--dependency-file=@DEPFILE@',
|
||||
'--sourcedir=' + meson.current_source_dir(),
|
||||
@@ -32,7 +31,6 @@ if not meson.is_cross_build() and build_machine.cpu_family() != 'arm' and build_
|
||||
depfile: 'widgetfactory_resources.c.d',
|
||||
command : [glib_compile_resources,
|
||||
'--generate-source',
|
||||
'--internal',
|
||||
'--target=@OUTPUT@',
|
||||
'--dependency-file=@DEPFILE@',
|
||||
'--sourcedir=' + meson.current_source_dir(),
|
||||
@@ -46,7 +44,6 @@ if not meson.is_cross_build() and build_machine.cpu_family() != 'arm' and build_
|
||||
input : widgetfactory_gresource,
|
||||
output : 'widgetfactory_resources.o',
|
||||
command : [ld,
|
||||
'-z', 'noexecstack',
|
||||
'-r',
|
||||
'-b','binary',
|
||||
'@INPUT@',
|
||||
@@ -57,7 +54,6 @@ if not meson.is_cross_build() and build_machine.cpu_family() != 'arm' and build_
|
||||
input : widgetfactory_resources_binary,
|
||||
output : 'widgetfactory_resources2.o',
|
||||
command : [objcopy,
|
||||
'--strip-all',
|
||||
'--add-symbol','_g_binary_widgetfactory_resource_data=.data:0',
|
||||
'@INPUT@',
|
||||
'@OUTPUT@'])
|
||||
|
||||
@@ -2053,7 +2053,6 @@ activate (GApplication *app)
|
||||
{ "win.open", { "<Control>o", NULL } },
|
||||
{ "win.record", { "<Control>r", NULL } },
|
||||
{ "win.lock", { "<Control>l", NULL } },
|
||||
{ "win.fullscreen", { "F11", NULL } },
|
||||
};
|
||||
struct {
|
||||
const char *action_and_target;
|
||||
@@ -2360,7 +2359,7 @@ activate (GApplication *app)
|
||||
model = (GMenuModel *)gtk_builder_get_object (builder, "new_style_context_menu_model");
|
||||
set_up_context_popover (widget, model);
|
||||
|
||||
gtk_window_present (window);
|
||||
gtk_widget_show (GTK_WIDGET (window));
|
||||
|
||||
g_object_unref (builder);
|
||||
}
|
||||
|
||||
@@ -7,21 +7,20 @@ authors = "GTK Development Team"
|
||||
logo_url = "gtk-logo.svg"
|
||||
license = "GPL-2.1-or-later"
|
||||
description = "The GTK toolkit"
|
||||
dependencies = [ "GObject-2.0" ]
|
||||
devhelp = true
|
||||
|
||||
dependencies = ["Gdk-4.0"]
|
||||
|
||||
[dependencies."Gdk-4.0"]
|
||||
name = "GDK"
|
||||
description = "The GTK drawing kit"
|
||||
docs_url = "https://docs.gtk.org/gdk/"
|
||||
[dependencies."GObject-2.0"]
|
||||
name = "GObject"
|
||||
description = "The base type system library"
|
||||
docs_url = "https://docs.gtk.org/gobject/"
|
||||
|
||||
[theme]
|
||||
name = "basic"
|
||||
show_index_summary = true
|
||||
|
||||
[source-location]
|
||||
base_url = "https://gitlab.gnome.org/GNOME/gtk/-/blob/main/"
|
||||
base_url = "https://gitlab.gnome.org/GNOME/gtk/-/blob/master/"
|
||||
|
||||
[extra]
|
||||
content_images = [
|
||||
|
||||
@@ -7,20 +7,20 @@ authors = "GTK Development Team"
|
||||
logo_url = "gtk-logo.svg"
|
||||
license = "GPL-2.1-or-later"
|
||||
description = "The GTK toolkit"
|
||||
dependencies = ["Gdk-4.0"]
|
||||
dependencies = [ "GObject-2.0" ]
|
||||
devhelp = true
|
||||
|
||||
[dependencies."Gdk-4.0"]
|
||||
name = "GDK"
|
||||
description = "The GTK drawing kit"
|
||||
docs_url = "https://docs.gtk.org/gdk4/"
|
||||
[dependencies."GObject-2.0"]
|
||||
name = "GObject"
|
||||
description = "The base type system library"
|
||||
docs_url = "https://docs.gtk.org/gobject/"
|
||||
|
||||
[theme]
|
||||
name = "basic"
|
||||
show_index_summary = true
|
||||
|
||||
[source-location]
|
||||
base_url = "https://gitlab.gnome.org/GNOME/gtk/-/blob/main/"
|
||||
base_url = "https://gitlab.gnome.org/GNOME/gtk/-/blob/master/"
|
||||
|
||||
[extra]
|
||||
content_images = [
|
||||
|
||||
@@ -8,7 +8,7 @@ authors = "GTK Development Team"
|
||||
logo_url = "gtk-logo.svg"
|
||||
license = "LGPL-2.1-or-later"
|
||||
description = "The GTK toolkit"
|
||||
dependencies = ["GObject-2.0", "Gio-2.0", "cairo-1.0", "Pango-1.0", "GdkPixbuf-2.0"]
|
||||
dependencies = [ "GObject-2.0", "cairo-1.0", "Pango-1.0", "GdkWayland-4.0", "GdkX11-4.0" ]
|
||||
devhelp = true
|
||||
search_index = true
|
||||
|
||||
@@ -17,11 +17,6 @@ search_index = true
|
||||
description = "The base type system library"
|
||||
docs_url = "https://docs.gtk.org/gobject/"
|
||||
|
||||
[dependencies."Gio-2.0"]
|
||||
name = "GIO"
|
||||
description = "GObject Interfaces and Objects, Networking, IPC, and I/O"
|
||||
docs_url = "https://docs.gtk.org/gio/"
|
||||
|
||||
[dependencies."cairo-1.0"]
|
||||
name = "Cairo"
|
||||
description = "A 2D graphics library with support for multiple output devices"
|
||||
@@ -32,19 +27,12 @@ search_index = true
|
||||
description = "Text shaping and rendering"
|
||||
docs_url = "https://docs.gtk.org/Pango/"
|
||||
|
||||
[dependencies."GdkPixbuf-2.0"]
|
||||
name = "GdkPixbuf"
|
||||
description = "Image data loading"
|
||||
docs_url = "https://docs.gtk.org/gdk-pixbuf/"
|
||||
|
||||
related = ["GdkWayland-4.0", "GdkX11-4.0"]
|
||||
|
||||
[related."GdkWayland-4.0"]
|
||||
[dependencies."GdkWayland-4.0"]
|
||||
name = "GdkWayland"
|
||||
description = "GDK Wayland Backend"
|
||||
docs_url = "https://docs.gtk.org/gdk4-wayland/"
|
||||
|
||||
[related."GdkX11-4.0"]
|
||||
[dependencies."GdkX11-4.0"]
|
||||
name = "GdkX11"
|
||||
description = "GDK X11 Backend"
|
||||
docs_url = "https://docs.gtk.org/gdk4-x11/"
|
||||
@@ -55,7 +43,7 @@ show_index_summary = true
|
||||
show_class_hierarchy = true
|
||||
|
||||
[source-location]
|
||||
base_url = "https://gitlab.gnome.org/GNOME/gtk/-/blob/main/"
|
||||
base_url = "https://gitlab.gnome.org/GNOME/gtk/-/blob/master/"
|
||||
|
||||
[extra]
|
||||
content_files = [
|
||||
|
||||
@@ -8,16 +8,25 @@ authors = "GTK Development Team"
|
||||
logo_url = "gtk-logo.svg"
|
||||
license = "LGPL-2.1-or-later"
|
||||
description = "The GTK toolkit"
|
||||
dependencies = [ "GObject-2.0", "Graphene-1.0", "Pango-1.0", "Gdk-4.0" ]
|
||||
devhelp = true
|
||||
search_index = true
|
||||
|
||||
dependencies = ["Graphene-1.0", "Gdk-4.0"]
|
||||
[dependencies."GObject-2.0"]
|
||||
name = "GObject"
|
||||
description = "The base type system library"
|
||||
docs_url = "https://docs.gtk.org/gobject/"
|
||||
|
||||
[dependencies."Graphene-1.0"]
|
||||
name = "Graphene"
|
||||
description = "A thin layer of mathematical types for 3D libraries"
|
||||
docs_url = "https://ebassi.github.io/graphene/docs/"
|
||||
|
||||
[dependencies."Pango-1.0"]
|
||||
name = "Pango"
|
||||
description = "Text shaping and rendering"
|
||||
docs_url = "https://docs.gtk.org/Pango/"
|
||||
|
||||
[dependencies."Gdk-4.0"]
|
||||
name = "GDK"
|
||||
description = "The GTK windowing system abstraction"
|
||||
@@ -29,7 +38,7 @@ show_index_summary = true
|
||||
show_class_hierarchy = true
|
||||
|
||||
[source-location]
|
||||
base_url = "https://gitlab.gnome.org/GNOME/gtk/-/blob/main/"
|
||||
base_url = "https://gitlab.gnome.org/GNOME/gtk/-/blob/master/"
|
||||
|
||||
[extra]
|
||||
content_images = [
|
||||
|
||||
@@ -170,7 +170,7 @@ activate (GtkApplication *app,
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_widget_set_halign (box, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_valign (box, GTK_ALIGN_CENTER);
|
||||
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), box);
|
||||
|
||||
button = gtk_button_new_with_label ("Hello World");
|
||||
@@ -752,7 +752,7 @@ templates, resources, application menus, settings, [class@Gtk.HeaderBar], [class
|
||||
|
||||
The full, buildable sources for these examples can be found in the
|
||||
`examples` directory of the GTK source distribution, or
|
||||
[online](https://gitlab.gnome.org/GNOME/gtk/blob/main/examples) in the GTK
|
||||
[online](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples) in the GTK
|
||||
source code repository. You can build each example separately by using make
|
||||
with the `Makefile.example` file. For more information, see the `README`
|
||||
included in the examples directory.
|
||||
@@ -972,7 +972,7 @@ example_app_window_class_init (ExampleAppWindowClass *class)
|
||||
...
|
||||
```
|
||||
|
||||
([full source](https://gitlab.gnome.org/GNOME/gtk/blob/main/examples/application2/exampleappwin.c))
|
||||
([full source](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application2/exampleappwin.c))
|
||||
|
||||
You may have noticed that we used the `_from_resource()` variant of the function
|
||||
that sets a template. Now we need to use
|
||||
@@ -1043,7 +1043,7 @@ example_app_window_class_init (ExampleAppWindowClass *class)
|
||||
...
|
||||
```
|
||||
|
||||
([full source](https://gitlab.gnome.org/GNOME/gtk/blob/main/examples/application3/exampleappwin.c))
|
||||
([full source](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application3/exampleappwin.c))
|
||||
|
||||
Now we revisit the `example_app_window_open()` function that is called for each
|
||||
commandline argument, and construct a GtkTextView that we then add as a page
|
||||
@@ -1087,7 +1087,7 @@ example_app_window_open (ExampleAppWindow *win,
|
||||
...
|
||||
```
|
||||
|
||||
([full source](https://gitlab.gnome.org/GNOME/gtk/blob/main/examples/application3/exampleappwin.c))
|
||||
([full source](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application3/exampleappwin.c))
|
||||
|
||||
Lastly, we add a [class@Gtk.StackSwitcher] to the titlebar area in the UI file, and we
|
||||
tell it to display information about our stack.
|
||||
@@ -1188,7 +1188,7 @@ example_app_class_init (ExampleAppClass *class)
|
||||
...
|
||||
```
|
||||
|
||||
([full source](https://gitlab.gnome.org/GNOME/gtk/blob/main/examples/application4/exampleapp.c))
|
||||
([full source](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application4/exampleapp.c))
|
||||
|
||||
Our preferences menu item does not do anything yet, but the Quit menu item
|
||||
is fully functional. Note that it can also be activated by the usual Ctrl-Q
|
||||
@@ -1258,7 +1258,7 @@ example_app_window_init (ExampleAppWindow *win)
|
||||
...
|
||||
```
|
||||
|
||||
([full source](https://gitlab.gnome.org/GNOME/gtk/blob/main/examples/application5/exampleappwin.c))
|
||||
([full source](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application5/exampleappwin.c))
|
||||
|
||||
The code to connect the font setting is a little more involved, since there
|
||||
is no simple object property that it corresponds to, so we are not going to
|
||||
@@ -1429,7 +1429,7 @@ preferences_activated (GSimpleAction *action,
|
||||
...
|
||||
```
|
||||
|
||||
([full source](https://gitlab.gnome.org/GNOME/gtk/blob/main/examples/application6/exampleapp.c))
|
||||
([full source](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application6/exampleapp.c))
|
||||
|
||||
After all this work, our application can now show a preference dialog
|
||||
like this:
|
||||
@@ -1549,7 +1549,7 @@ example_app_window_init (ExampleAppWindow *win)
|
||||
...
|
||||
```
|
||||
|
||||
([full source](https://gitlab.gnome.org/GNOME/gtk/blob/main/examples/application7/exampleappwin.c))
|
||||
([full source](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application7/exampleappwin.c))
|
||||
|
||||
With the search bar, our application now looks like this:
|
||||
|
||||
@@ -1682,7 +1682,7 @@ example_app_window_init (ExampleAppWindow *win)
|
||||
...
|
||||
```
|
||||
|
||||
([full source](https://gitlab.gnome.org/GNOME/gtk/blob/main/examples/application8/exampleappwin.c))
|
||||
([full source](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application8/exampleappwin.c))
|
||||
|
||||
What our application looks like now:
|
||||
|
||||
@@ -1760,10 +1760,10 @@ example_app_window_init (ExampleAppWindow *win)
|
||||
...
|
||||
```
|
||||
|
||||
([full source](https://gitlab.gnome.org/GNOME/gtk/blob/main/examples/application9/exampleappwin.c))
|
||||
([full source](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application9/exampleappwin.c))
|
||||
|
||||
We also need a function that counts the lines of the currently active tab,
|
||||
and updates the `lines` label. See the [full source](https://gitlab.gnome.org/GNOME/gtk/blob/main/examples/application9/exampleappwin.c)
|
||||
and updates the `lines` label. See the [full source](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application9/exampleappwin.c)
|
||||
if you are interested in the details.
|
||||
|
||||
This brings our example application to this appearance:
|
||||
|
||||
@@ -8,10 +8,24 @@ authors = "GTK Development Team"
|
||||
logo_url = "gtk-logo.svg"
|
||||
license = "LGPL-2.1-or-later"
|
||||
description = "The GTK toolkit"
|
||||
dependencies = [ "GObject-2.0", "Graphene-1.0", "Pango-1.0", "Gdk-4.0", "Gsk-4.0" ]
|
||||
devhelp = true
|
||||
search_index = true
|
||||
|
||||
dependencies = ["Gdk-4.0", "Gsk-4.0"]
|
||||
[dependencies."GObject-2.0"]
|
||||
name = "GObject"
|
||||
description = "The base type system library"
|
||||
docs_url = "https://docs.gtk.org/gobject/"
|
||||
|
||||
[dependencies."Graphene-1.0"]
|
||||
name = "Graphene"
|
||||
description = "A thin layer of mathematical types for 3D libraries"
|
||||
docs_url = "https://ebassi.github.io/graphene/docs"
|
||||
|
||||
[dependencies."Pango-1.0"]
|
||||
name = "Pango"
|
||||
description = "Text shaping and rendering"
|
||||
docs_url = "https://docs.gtk.org/Pango/"
|
||||
|
||||
[dependencies."Gdk-4.0"]
|
||||
name = "GDK"
|
||||
@@ -23,35 +37,13 @@ dependencies = ["Gdk-4.0", "Gsk-4.0"]
|
||||
description = "The GTK rendering abstraction"
|
||||
docs_url = "https://docs.gtk.org/gsk4/"
|
||||
|
||||
related = ["Pango-1.0", "Graphene-1.0", "GObject-2.0", "Gio-2.0"]
|
||||
|
||||
[related."GObject-2.0"]
|
||||
name = "GObject"
|
||||
description = "The base type system library"
|
||||
docs_url = "https://docs.gtk.org/gobject/"
|
||||
|
||||
[related."Gio-2.0"]
|
||||
name = "GIO"
|
||||
description = "GObject Interfaces and Objects, Networking, IPC, and I/O"
|
||||
docs_url = "https://docs.gtk.org/gio/"
|
||||
|
||||
[related."Graphene-1.0"]
|
||||
name = "Graphene"
|
||||
description = "A thin layer of mathematical types for 3D libraries"
|
||||
docs_url = "https://ebassi.github.io/graphene/docs"
|
||||
|
||||
[related."Pango-1.0"]
|
||||
name = "Pango"
|
||||
description = "Text shaping and rendering"
|
||||
docs_url = "https://docs.gtk.org/Pango/"
|
||||
|
||||
[theme]
|
||||
name = "basic"
|
||||
show_index_summary = true
|
||||
show_class_hierarchy = true
|
||||
|
||||
[source-location]
|
||||
base_url = "https://gitlab.gnome.org/GNOME/gtk/-/blob/main/"
|
||||
base_url = "https://gitlab.gnome.org/GNOME/gtk/-/blob/master/"
|
||||
|
||||
[extra]
|
||||
# The same order will be used when generating the index
|
||||
|
||||
@@ -42,7 +42,7 @@ univocally identifies events that are related to the same
|
||||
interaction.
|
||||
|
||||
When GTK creates a `GdkSurface`, it connects to the ::event
|
||||
signal on it, which receives all of these input events. Surfaces
|
||||
signal on it, which receives all of these input events. Surfaces have
|
||||
have signals and properties, e.g. to deal with window management
|
||||
related events.
|
||||
|
||||
|
||||
@@ -1382,5 +1382,5 @@ a new family of widgets for this purpose that uses list models instead
|
||||
of tree models, and widgets instead of cell renderers.
|
||||
|
||||
To learn more about the new list widgets, you can read the [List Widget
|
||||
Overview](https://docs.gtk.org/gtk4/section-list-widget.html).
|
||||
Overview](#ListWidget).
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ GTK with your code applied, and run the test suite, on multiple platforms
|
||||
and architectures, and verify that nothing breaks. They also allow us to
|
||||
do proper code reviews, so we can iterate over the changes.
|
||||
|
||||
You should follow the [contribution guide](https://gitlab.gnome.org/GNOME/gtk/blob/main/CONTRIBUTING.md)
|
||||
You should follow the [contribution guide](https://gitlab.gnome.org/GNOME/gtk/blob/master/CONTRIBUTING.md)
|
||||
for GTK, available on GitLab.
|
||||
|
||||
If you want to discuss your approach before or after working on it,
|
||||
|
||||
@@ -372,7 +372,7 @@ library you are using:
|
||||
The `test` accessibility backend is recommended for test suites and remote
|
||||
continuous integration pipelines.
|
||||
|
||||
### `XDG_DATA_HOME`, `XDG_DATA_DIRS`
|
||||
### `XDG_DTA_HOME`, `XDG_DATA_DIRS`
|
||||
|
||||
GTK uses these environment variables to locate icon themes
|
||||
and MIME information. For more information, see the
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
* `GdkAppLaunchContext` handles launching an application in a graphical context.
|
||||
*
|
||||
* It is an implementation of `GAppLaunchContext` that provides startup
|
||||
* notification and allows to launch applications on a specific workspace.
|
||||
* notification and allows to launch applications on a specific screen
|
||||
* or workspace.
|
||||
*
|
||||
* ## Launching an application
|
||||
*
|
||||
@@ -40,6 +41,7 @@
|
||||
*
|
||||
* context = gdk_display_get_app_launch_context (display);
|
||||
*
|
||||
* gdk_app_launch_context_set_display (display);
|
||||
* gdk_app_launch_context_set_timestamp (gdk_event_get_time (event));
|
||||
*
|
||||
* if (!g_app_info_launch_default_for_uri ("http://www.gtk.org", context, &error))
|
||||
@@ -194,10 +196,6 @@ gdk_app_launch_context_get_display (GdkAppLaunchContext *context)
|
||||
* This only works when running under a window manager that
|
||||
* supports multiple workspaces, as described in the
|
||||
* [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec).
|
||||
* Specifically this sets the `_NET_WM_DESKTOP` property described
|
||||
* in that spec.
|
||||
*
|
||||
* This only works when using the X11 backend.
|
||||
*
|
||||
* When the workspace is not specified or @desktop is set to -1,
|
||||
* it is up to the window manager to pick one, typically it will
|
||||
|
||||
@@ -576,7 +576,7 @@ gdk_content_deserialize_async (GInputStream *stream,
|
||||
/**
|
||||
* gdk_content_deserialize_finish:
|
||||
* @result: the `GAsyncResult`
|
||||
* @value: (out): return location for the result of the operation
|
||||
* @value: return location for the result of the operation
|
||||
* @error: return location for an error
|
||||
*
|
||||
* Finishes a content deserialization operation.
|
||||
|
||||
+5
-1
@@ -132,6 +132,8 @@ gdk_device_class_init (GdkDeviceClass *klass)
|
||||
* GdkDevice:source: (attributes org.gtk.Property.get=gdk_device_get_source)
|
||||
*
|
||||
* Source type for the device.
|
||||
*
|
||||
* Deprecated: 4.6: Use GdkDeviceTool:tool-type instead
|
||||
*/
|
||||
device_props[PROP_SOURCE] =
|
||||
g_param_spec_enum ("source",
|
||||
@@ -596,6 +598,8 @@ gdk_device_get_has_cursor (GdkDevice *device)
|
||||
* Determines the type of the device.
|
||||
*
|
||||
* Returns: a `GdkInputSource`
|
||||
*
|
||||
* Deprecated: 4.6: Use gdk_device_tool_get_tool_type() instead
|
||||
*/
|
||||
GdkInputSource
|
||||
gdk_device_get_source (GdkDevice *device)
|
||||
@@ -1238,7 +1242,7 @@ gdk_device_get_num_touches (GdkDevice *device)
|
||||
*
|
||||
* Retrieves the current tool for @device.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): the `GdkDeviceTool`
|
||||
* Returns: (transfer none): the `GdkDeviceTool`
|
||||
*/
|
||||
GdkDeviceTool *
|
||||
gdk_device_get_device_tool (GdkDevice *device)
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ GDK_AVAILABLE_IN_ALL
|
||||
GdkDisplay * gdk_device_get_display (GdkDevice *device);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkSeat * gdk_device_get_seat (GdkDevice *device);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GDK_DEPRECATED_IN_4_6_FOR(gdk_device_tool_get_tool_type)
|
||||
GdkDeviceTool * gdk_device_get_device_tool (GdkDevice *device);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
|
||||
+2
-2
@@ -1721,12 +1721,12 @@ gdk_display_init_egl (GdkDisplay *self,
|
||||
|
||||
self->have_egl_buffer_age =
|
||||
epoxy_has_egl_extension (priv->egl_display, "EGL_EXT_buffer_age");
|
||||
self->have_egl_swap_buffers_with_damage =
|
||||
epoxy_has_egl_extension (priv->egl_display, "EGL_EXT_swap_buffers_with_damage");
|
||||
self->have_egl_no_config_context =
|
||||
epoxy_has_egl_extension (priv->egl_display, "EGL_KHR_no_config_context");
|
||||
self->have_egl_pixel_format_float =
|
||||
epoxy_has_egl_extension (priv->egl_display, "EGL_EXT_pixel_format_float");
|
||||
self->have_egl_win32_libangle =
|
||||
epoxy_has_egl_extension (priv->egl_display, "EGL_ANGLE_d3d_share_handle_client_buffer");
|
||||
|
||||
if (self->have_egl_no_config_context)
|
||||
priv->egl_config_high_depth = gdk_display_create_egl_config (self,
|
||||
|
||||
@@ -107,9 +107,9 @@ struct _GdkDisplay
|
||||
|
||||
/* egl info */
|
||||
guint have_egl_buffer_age : 1;
|
||||
guint have_egl_swap_buffers_with_damage : 1;
|
||||
guint have_egl_no_config_context : 1;
|
||||
guint have_egl_pixel_format_float : 1;
|
||||
guint have_egl_win32_libangle : 1;
|
||||
};
|
||||
|
||||
struct _GdkDisplayClass
|
||||
|
||||
+19
-27
@@ -719,6 +719,14 @@ gdk_event_queue_handle_scroll_compression (GdkDisplay *display)
|
||||
|
||||
gdk_event_unref (old_event);
|
||||
}
|
||||
|
||||
if (g_queue_get_length (&display->queued_events) == 1 &&
|
||||
g_queue_peek_head_link (&display->queued_events) == scrolls)
|
||||
{
|
||||
GdkFrameClock *clock = gdk_surface_get_frame_clock (surface);
|
||||
if (clock) /* might be NULL if surface was destroyed */
|
||||
gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -824,6 +832,14 @@ _gdk_event_queue_handle_motion_compression (GdkDisplay *display)
|
||||
g_queue_delete_link (&display->queued_events, pending_motions);
|
||||
pending_motions = next;
|
||||
}
|
||||
|
||||
if (g_queue_get_length (&display->queued_events) == 1 &&
|
||||
g_queue_peek_head_link (&display->queued_events) == pending_motions)
|
||||
{
|
||||
GdkFrameClock *clock = gdk_surface_get_frame_clock (pending_motion_surface);
|
||||
if (clock) /* might be NULL if surface was destroyed */
|
||||
gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2496,8 +2512,7 @@ static const GdkEventTypeInfo gdk_touchpad_event_info = {
|
||||
GDK_DEFINE_EVENT_TYPE (GdkTouchpadEvent, gdk_touchpad_event,
|
||||
&gdk_touchpad_event_info,
|
||||
GDK_EVENT_TYPE_SLOT (GDK_TOUCHPAD_SWIPE)
|
||||
GDK_EVENT_TYPE_SLOT (GDK_TOUCHPAD_PINCH)
|
||||
GDK_EVENT_TYPE_SLOT (GDK_TOUCHPAD_HOLD))
|
||||
GDK_EVENT_TYPE_SLOT (GDK_TOUCHPAD_PINCH))
|
||||
|
||||
GdkEvent *
|
||||
gdk_touchpad_event_new_swipe (GdkSurface *surface,
|
||||
@@ -2571,27 +2586,6 @@ gdk_touchpad_event_new_pinch (GdkSurface *surface,
|
||||
return (GdkEvent *) self;
|
||||
}
|
||||
|
||||
GdkEvent *
|
||||
gdk_touchpad_event_new_hold (GdkSurface *surface,
|
||||
GdkDevice *device,
|
||||
guint32 time,
|
||||
GdkModifierType state,
|
||||
GdkTouchpadGesturePhase phase,
|
||||
double x,
|
||||
double y,
|
||||
int n_fingers)
|
||||
{
|
||||
GdkTouchpadEvent *self = gdk_event_alloc (GDK_TOUCHPAD_HOLD, surface, device, time);
|
||||
|
||||
self->state = state;
|
||||
self->phase = phase;
|
||||
self->x = x;
|
||||
self->y = y;
|
||||
self->n_fingers = n_fingers;
|
||||
|
||||
return (GdkEvent *) self;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_touchpad_event_get_gesture_phase:
|
||||
* @event: (type GdkTouchpadEvent): a touchpad event
|
||||
@@ -2607,8 +2601,7 @@ gdk_touchpad_event_get_gesture_phase (GdkEvent *event)
|
||||
|
||||
g_return_val_if_fail (GDK_IS_EVENT (event), 0);
|
||||
g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_PINCH) ||
|
||||
GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_SWIPE) ||
|
||||
GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_HOLD), 0);
|
||||
GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_SWIPE), 0);
|
||||
|
||||
return self->phase;
|
||||
}
|
||||
@@ -2628,8 +2621,7 @@ gdk_touchpad_event_get_n_fingers (GdkEvent *event)
|
||||
|
||||
g_return_val_if_fail (GDK_IS_EVENT (event), 0);
|
||||
g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_PINCH) ||
|
||||
GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_SWIPE) ||
|
||||
GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_HOLD), 0);
|
||||
GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_SWIPE), 0);
|
||||
|
||||
return self->n_fingers;
|
||||
}
|
||||
|
||||
@@ -169,8 +169,6 @@ typedef struct _GdkTouchpadEvent GdkTouchpadEvent;
|
||||
* @GDK_PAD_RING: A tablet pad axis event from a "ring".
|
||||
* @GDK_PAD_STRIP: A tablet pad axis event from a "strip".
|
||||
* @GDK_PAD_GROUP_MODE: A tablet pad group mode change.
|
||||
* @GDK_TOUCHPAD_HOLD: A touchpad hold gesture event, the current state
|
||||
* is determined by its phase field. Since: 4.6
|
||||
* @GDK_EVENT_LAST: marks the end of the GdkEventType enumeration.
|
||||
*
|
||||
* Specifies the type of the event.
|
||||
@@ -205,7 +203,6 @@ typedef enum
|
||||
GDK_PAD_RING,
|
||||
GDK_PAD_STRIP,
|
||||
GDK_PAD_GROUP_MODE,
|
||||
GDK_TOUCHPAD_HOLD,
|
||||
GDK_EVENT_LAST /* helper variable for decls */
|
||||
} GdkEventType;
|
||||
|
||||
|
||||
@@ -533,15 +533,6 @@ GdkEvent * gdk_touchpad_event_new_pinch (GdkSurface *surface,
|
||||
double scale,
|
||||
double angle_delta);
|
||||
|
||||
GdkEvent * gdk_touchpad_event_new_hold (GdkSurface *surface,
|
||||
GdkDevice *device,
|
||||
guint32 time,
|
||||
GdkModifierType state,
|
||||
GdkTouchpadGesturePhase phase,
|
||||
double x,
|
||||
double y,
|
||||
int n_fingers);
|
||||
|
||||
GdkEvent * gdk_pad_event_new_ring (GdkSurface *surface,
|
||||
GdkDevice *device,
|
||||
guint32 time,
|
||||
|
||||
+7
-27
@@ -117,7 +117,6 @@ typedef struct {
|
||||
|
||||
#ifdef HAVE_EGL
|
||||
EGLContext egl_context;
|
||||
EGLBoolean (*eglSwapBuffersWithDamage) (EGLDisplay, EGLSurface, const EGLint *, EGLint);
|
||||
#endif
|
||||
} GdkGLContextPrivate;
|
||||
|
||||
@@ -279,11 +278,7 @@ gdk_gl_context_real_realize (GdkGLContext *context,
|
||||
int i = 0;
|
||||
G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
|
||||
|
||||
if (share != NULL)
|
||||
gdk_gl_context_get_required_version (share, &major, &minor);
|
||||
else
|
||||
gdk_gl_context_get_required_version (context, &major, &minor);
|
||||
|
||||
gdk_gl_context_get_required_version (context, &major, &minor);
|
||||
debug_bit = gdk_gl_context_get_debug_enabled (context);
|
||||
forward_bit = gdk_gl_context_get_forward_compatible (context);
|
||||
legacy_bit = GDK_DISPLAY_DEBUG_CHECK (display, GL_LEGACY) ||
|
||||
@@ -421,11 +416,6 @@ gdk_gl_context_real_realize (GdkGLContext *context,
|
||||
|
||||
gdk_gl_context_set_is_legacy (context, legacy_bit);
|
||||
|
||||
if (epoxy_has_egl_extension (egl_display, "EGL_KHR_swap_buffers_with_damage"))
|
||||
priv->eglSwapBuffersWithDamage = (gpointer)epoxy_eglGetProcAddress ("eglSwapBuffersWithDamageKHR");
|
||||
else if (epoxy_has_egl_extension (egl_display, "EGL_EXT_swap_buffers_with_damage"))
|
||||
priv->eglSwapBuffersWithDamage = (gpointer)epoxy_eglGetProcAddress ("eglSwapBuffersWithDamageEXT");
|
||||
|
||||
gdk_profiler_end_mark (start_time, "realize GdkWaylandGLContext", NULL);
|
||||
|
||||
return api;
|
||||
@@ -614,7 +604,7 @@ gdk_gl_context_real_end_frame (GdkDrawContext *draw_context,
|
||||
|
||||
gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "EGL", "swap buffers");
|
||||
|
||||
if (priv->eglSwapBuffersWithDamage)
|
||||
if (display->have_egl_swap_buffers_with_damage)
|
||||
{
|
||||
EGLint stack_rects[4 * 4]; /* 4 rects */
|
||||
EGLint *heap_rects = NULL;
|
||||
@@ -638,7 +628,7 @@ gdk_gl_context_real_end_frame (GdkDrawContext *draw_context,
|
||||
rects[j++] = rect.width * scale;
|
||||
rects[j++] = rect.height * scale;
|
||||
}
|
||||
priv->eglSwapBuffersWithDamage (gdk_display_get_egl_display (display), egl_surface, rects, n_rects);
|
||||
eglSwapBuffersWithDamageEXT (gdk_display_get_egl_display (display), egl_surface, rects, n_rects);
|
||||
g_free (heap_rects);
|
||||
}
|
||||
else
|
||||
@@ -654,12 +644,6 @@ gdk_gl_context_surface_resized (GdkDrawContext *draw_context)
|
||||
gdk_gl_context_clear_old_updated_area (context);
|
||||
}
|
||||
|
||||
static guint
|
||||
gdk_gl_context_real_get_default_framebuffer (GdkGLContext *self)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_gl_context_class_init (GdkGLContextClass *klass)
|
||||
{
|
||||
@@ -671,7 +655,6 @@ gdk_gl_context_class_init (GdkGLContextClass *klass)
|
||||
klass->is_shared = gdk_gl_context_real_is_shared;
|
||||
klass->make_current = gdk_gl_context_real_make_current;
|
||||
klass->clear_current = gdk_gl_context_real_clear_current;
|
||||
klass->get_default_framebuffer = gdk_gl_context_real_get_default_framebuffer;
|
||||
|
||||
draw_context_class->begin_frame = gdk_gl_context_real_begin_frame;
|
||||
draw_context_class->end_frame = gdk_gl_context_real_end_frame;
|
||||
@@ -1065,29 +1048,26 @@ gdk_gl_context_get_required_version (GdkGLContext *context,
|
||||
{
|
||||
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
||||
gboolean force_gles = FALSE;
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
GdkDisplay *display;
|
||||
#endif
|
||||
int default_major, default_minor;
|
||||
int maj, min;
|
||||
|
||||
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
|
||||
|
||||
display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
|
||||
force_gles = GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES);
|
||||
#endif
|
||||
|
||||
/* libANGLE on Windows at least requires GLES 3.0+ */
|
||||
if (display->have_egl_win32_libangle)
|
||||
force_gles = TRUE;
|
||||
|
||||
/* Default fallback values for uninitialised contexts; we
|
||||
* enforce a context version number of 3.2 for desktop GL,
|
||||
* and 2.0 for GLES
|
||||
*/
|
||||
if (gdk_gl_context_get_use_es (context) || force_gles)
|
||||
{
|
||||
default_major = display->have_egl_win32_libangle ? 3 : 2;
|
||||
default_major = 2;
|
||||
default_minor = 0;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -71,8 +71,6 @@ struct _GdkGLContextClass
|
||||
|
||||
gboolean (* is_shared) (GdkGLContext *self,
|
||||
GdkGLContext *other);
|
||||
|
||||
guint (* get_default_framebuffer) (GdkGLContext *self);
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
||||
+4
-13
@@ -175,19 +175,10 @@ gdk_gl_texture_do_download (gpointer texture_,
|
||||
glGenFramebuffers (1, &fbo);
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, fbo);
|
||||
glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->id, 0);
|
||||
if (gdk_gl_context_check_version (self->context, 4, 3, 3, 1))
|
||||
{
|
||||
glGetFramebufferParameteriv (GL_FRAMEBUFFER, GL_IMPLEMENTATION_COLOR_READ_FORMAT, &gl_read_format);
|
||||
glGetFramebufferParameteriv (GL_FRAMEBUFFER, GL_IMPLEMENTATION_COLOR_READ_TYPE, &gl_read_type);
|
||||
if (!gdk_gl_texture_find_format (gdk_gl_context_get_use_es (self->context), gl_read_format, gl_read_type, &actual_format))
|
||||
actual_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; /* pray */
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_read_format = GL_RGBA;
|
||||
gl_read_type = GL_UNSIGNED_BYTE;
|
||||
actual_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
|
||||
}
|
||||
glGetFramebufferParameteriv (GL_FRAMEBUFFER, GL_IMPLEMENTATION_COLOR_READ_FORMAT, &gl_read_format);
|
||||
glGetFramebufferParameteriv (GL_FRAMEBUFFER, GL_IMPLEMENTATION_COLOR_READ_TYPE, &gl_read_type);
|
||||
if (!gdk_gl_texture_find_format (gdk_gl_context_get_use_es (self->context), gl_read_format, gl_read_type, &actual_format))
|
||||
actual_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; /* pray */
|
||||
|
||||
if (download->format == actual_format &&
|
||||
(download->stride == expected_stride))
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# Updates https://gitlab.gnome.org/GNOME/gtk/tree/main/gdk/gdkkeysyms.h from upstream (X.org 7.x),
|
||||
# Updates https://gitlab.gnome.org/GNOME/gtk/tree/master/gdk/gdkkeysyms.h from upstream (X.org 7.x),
|
||||
# from https://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
|
||||
#
|
||||
#
|
||||
# Author : Simos Xenitellis <simos at gnome dot org>.
|
||||
# Author : Bastien Nocera <hadess@hadess.net>
|
||||
# Version : 1.2
|
||||
#
|
||||
# Input : https://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
|
||||
# Input : https://cgit.freedesktop.org/xorg/proto/x11proto/plain/XF86keysym.h
|
||||
# Output : https://gitlab.gnome.org/GNOME/gtk/tree/main/gdk/gdkkeysyms.h
|
||||
#
|
||||
# Output : https://gitlab.gnome.org/GNOME/gtk/tree/master/gdk/gdkkeysyms.h
|
||||
#
|
||||
# Notes : It downloads keysymdef.h from the Internet, if not found locally,
|
||||
# Notes : and creates an updated gdkkeysyms.h
|
||||
# Notes : This version updates the source of gdkkeysyms.h from CVS to the GIT server.
|
||||
@@ -24,7 +24,7 @@ if ( ! -f "keysymdef.h" )
|
||||
{
|
||||
print "Trying to download keysymdef.h from\n";
|
||||
print "http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h\n";
|
||||
die "Unable to download keysymdef.h from http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h\n"
|
||||
die "Unable to download keysymdef.h from http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h\n"
|
||||
unless system("wget -c -O keysymdef.h \"http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h\"") == 0;
|
||||
print " done.\n\n";
|
||||
}
|
||||
@@ -39,7 +39,7 @@ if ( ! -f "XF86keysym.h" )
|
||||
{
|
||||
print "Trying to download XF86keysym.h from\n";
|
||||
print "http://cgit.freedesktop.org/xorg/proto/x11proto/plain/XF86keysym.h\n";
|
||||
die "Unable to download keysymdef.h from http://cgit.freedesktop.org/xorg/proto/x11proto/plain/XF86keysym.h\n"
|
||||
die "Unable to download keysymdef.h from http://cgit.freedesktop.org/xorg/proto/x11proto/plain/XF86keysym.h\n"
|
||||
unless system("wget -c -O XF86keysym.h \"http://cgit.freedesktop.org/xorg/proto/x11proto/plain/XF86keysym.h\"") == 0;
|
||||
print " done.\n\n";
|
||||
}
|
||||
@@ -82,7 +82,7 @@ print OUT_GDKKEYSYMS $LICENSE_HEADER;
|
||||
print OUT_GDKKEYSYMS<<EOF;
|
||||
|
||||
/*
|
||||
* File auto-generated from script https://gitlab.gnome.org/GNOME/gtk/tree/main/gdk/gdkkeysyms-update.pl
|
||||
* File auto-generated from script https://gitlab.gnome.org/GNOME/gtk/tree/master/gdk/gdkkeysyms-update.pl
|
||||
* using the input file
|
||||
* http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
|
||||
* and
|
||||
@@ -111,7 +111,7 @@ while (<IN_KEYSYMDEF>)
|
||||
|
||||
$_ = $keysymelements[1];
|
||||
die "Internal error, was expecting \"XC_*\", found: $_\n" if ( ! /^XK_/ );
|
||||
|
||||
|
||||
$_ = $keysymelements[2];
|
||||
die "Internal error, was expecting \"0x*\", found: $_\n" if ( ! /^0x/ );
|
||||
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
|
||||
|
||||
/*
|
||||
* File auto-generated from script https://gitlab.gnome.org/GNOME/gtk/tree/main/gdk/gdkkeysyms-update.pl
|
||||
* File auto-generated from script https://gitlab.gnome.org/GNOME/gtk/tree/master/gdk/gdkkeysyms-update.pl
|
||||
* using the input file
|
||||
* http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
|
||||
* and
|
||||
|
||||
+43
-58
@@ -369,7 +369,7 @@ static const struct {
|
||||
{ 0x07a2, 0x0388 }, /* Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */
|
||||
{ 0x07a3, 0x0389 }, /* Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */
|
||||
{ 0x07a4, 0x038a }, /* Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */
|
||||
{ 0x07a5, 0x03aa }, /* Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */
|
||||
{ 0x07a5, 0x03aa }, /* Greek_IOTAdieresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */
|
||||
{ 0x07a7, 0x038c }, /* Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */
|
||||
{ 0x07a8, 0x038e }, /* Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */
|
||||
{ 0x07a9, 0x03ab }, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */
|
||||
@@ -436,22 +436,22 @@ static const struct {
|
||||
{ 0x07f7, 0x03c7 }, /* Greek_chi χ GREEK SMALL LETTER CHI */
|
||||
{ 0x07f8, 0x03c8 }, /* Greek_psi ψ GREEK SMALL LETTER PSI */
|
||||
{ 0x07f9, 0x03c9 }, /* Greek_omega ω GREEK SMALL LETTER OMEGA */
|
||||
{ 0x08a1, 0x23b7 }, /* leftradical ⎷ ??? */
|
||||
{ 0x08a2, 0x250c }, /* topleftradical ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */
|
||||
{ 0x08a3, 0x2500 }, /* horizconnector ─ BOX DRAWINGS LIGHT HORIZONTAL */
|
||||
/* 0x08a1 leftradical ? ??? */
|
||||
/* 0x08a2 topleftradical ? ??? */
|
||||
/* 0x08a3 horizconnector ? ??? */
|
||||
{ 0x08a4, 0x2320 }, /* topintegral ⌠ TOP HALF INTEGRAL */
|
||||
{ 0x08a5, 0x2321 }, /* botintegral ⌡ BOTTOM HALF INTEGRAL */
|
||||
{ 0x08a6, 0x2502 }, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */
|
||||
{ 0x08a7, 0x23a1 }, /* topleftsqbracket ⎡ ??? */
|
||||
{ 0x08a8, 0x23a3 }, /* botleftsqbracket ⎣ ??? */
|
||||
{ 0x08a9, 0x23a4 }, /* toprightsqbracket ⎤ ??? */
|
||||
{ 0x08aa, 0x23a6 }, /* botrightsqbracket ⎦ ??? */
|
||||
{ 0x08ab, 0x239b }, /* topleftparens ⎛ ??? */
|
||||
{ 0x08ac, 0x239d }, /* botleftparens ⎝ ??? */
|
||||
{ 0x08ad, 0x239e }, /* toprightparens ⎞ ??? */
|
||||
{ 0x08ae, 0x23a0 }, /* botrightparens ⎠ ??? */
|
||||
{ 0x08af, 0x23a8 }, /* leftmiddlecurlybrace ⎨ ??? */
|
||||
{ 0x08b0, 0x23ac }, /* rightmiddlecurlybrace ⎬ ??? */
|
||||
/* 0x08a7 topleftsqbracket ? ??? */
|
||||
/* 0x08a8 botleftsqbracket ? ??? */
|
||||
/* 0x08a9 toprightsqbracket ? ??? */
|
||||
/* 0x08aa botrightsqbracket ? ??? */
|
||||
/* 0x08ab topleftparens ? ??? */
|
||||
/* 0x08ac botleftparens ? ??? */
|
||||
/* 0x08ad toprightparens ? ??? */
|
||||
/* 0x08ae botrightparens ? ??? */
|
||||
/* 0x08af leftmiddlecurlybrace ? ??? */
|
||||
/* 0x08b0 rightmiddlecurlybrace ? ??? */
|
||||
/* 0x08b1 topleftsummation ? ??? */
|
||||
/* 0x08b2 botleftsummation ? ??? */
|
||||
/* 0x08b3 topvertsummationconnector ? ??? */
|
||||
@@ -467,8 +467,8 @@ static const struct {
|
||||
{ 0x08c1, 0x221d }, /* variation ∝ PROPORTIONAL TO */
|
||||
{ 0x08c2, 0x221e }, /* infinity ∞ INFINITY */
|
||||
{ 0x08c5, 0x2207 }, /* nabla ∇ NABLA */
|
||||
{ 0x08c8, 0x223c }, /* approximate ∼ TILDE OPERATOR */
|
||||
{ 0x08c9, 0x2243 }, /* similarequal ≃ ASYMPTOTICALLY EQUAL TO */
|
||||
{ 0x08c8, 0x2245 }, /* approximate ≅ APPROXIMATELY EQUAL TO */
|
||||
/* 0x08c9 similarequal ? ??? */
|
||||
{ 0x08cd, 0x21d4 }, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */
|
||||
{ 0x08ce, 0x21d2 }, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */
|
||||
{ 0x08cf, 0x2261 }, /* identical ≡ IDENTICAL TO */
|
||||
@@ -485,7 +485,7 @@ static const struct {
|
||||
{ 0x08fc, 0x2191 }, /* uparrow ↑ UPWARDS ARROW */
|
||||
{ 0x08fd, 0x2192 }, /* rightarrow → RIGHTWARDS ARROW */
|
||||
{ 0x08fe, 0x2193 }, /* downarrow ↓ DOWNWARDS ARROW */
|
||||
/* 0x09df blank ? ??? */
|
||||
{ 0x09df, 0x2422 }, /* blank ␢ BLANK SYMBOL */
|
||||
{ 0x09e0, 0x25c6 }, /* soliddiamond ◆ BLACK DIAMOND */
|
||||
{ 0x09e1, 0x2592 }, /* checkerboard ▒ MEDIUM SHADE */
|
||||
{ 0x09e2, 0x2409 }, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */
|
||||
@@ -499,11 +499,11 @@ static const struct {
|
||||
{ 0x09ec, 0x250c }, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */
|
||||
{ 0x09ed, 0x2514 }, /* lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */
|
||||
{ 0x09ee, 0x253c }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
|
||||
{ 0x09ef, 0x23ba }, /* horizlinescan1 ⎺ HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */
|
||||
{ 0x09f0, 0x23bb }, /* horizlinescan3 ⎻ HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */
|
||||
/* 0x09ef horizlinescan1 ? ??? */
|
||||
/* 0x09f0 horizlinescan3 ? ??? */
|
||||
{ 0x09f1, 0x2500 }, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */
|
||||
{ 0x09f2, 0x23bc }, /* horizlinescan7 ⎼ HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */
|
||||
{ 0x09f3, 0x23bd }, /* horizlinescan9 ⎽ HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */
|
||||
/* 0x09f2 horizlinescan7 ? ??? */
|
||||
/* 0x09f3 horizlinescan9 ? ??? */
|
||||
{ 0x09f4, 0x251c }, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
|
||||
{ 0x09f5, 0x2524 }, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */
|
||||
{ 0x09f6, 0x2534 }, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */
|
||||
@@ -519,9 +519,9 @@ static const struct {
|
||||
{ 0x0aa8, 0x200a }, /* hairspace HAIR SPACE */
|
||||
{ 0x0aa9, 0x2014 }, /* emdash — EM DASH */
|
||||
{ 0x0aaa, 0x2013 }, /* endash – EN DASH */
|
||||
{ 0x0aac, 0x2423 }, /* signifblank ␣ OPEN BOX */
|
||||
/* 0x0aac signifblank ? ??? */
|
||||
{ 0x0aae, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */
|
||||
{ 0x0aaf, 0x2025 }, /* doubbaselinedot ‥ TWO DOT LEADER */
|
||||
/* 0x0aaf doubbaselinedot ? ??? */
|
||||
{ 0x0ab0, 0x2153 }, /* onethird ⅓ VULGAR FRACTION ONE THIRD */
|
||||
{ 0x0ab1, 0x2154 }, /* twothirds ⅔ VULGAR FRACTION TWO THIRDS */
|
||||
{ 0x0ab2, 0x2155 }, /* onefifth ⅕ VULGAR FRACTION ONE FIFTH */
|
||||
@@ -532,9 +532,9 @@ static const struct {
|
||||
{ 0x0ab7, 0x215a }, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */
|
||||
{ 0x0ab8, 0x2105 }, /* careof ℅ CARE OF */
|
||||
{ 0x0abb, 0x2012 }, /* figdash ‒ FIGURE DASH */
|
||||
{ 0x0abc, 0x27e8 }, /* leftanglebracket ⟨ MATHEMATICAL LEFT ANGLE BRACKET */
|
||||
{ 0x0abc, 0x2329 }, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET */
|
||||
{ 0x0abd, 0x002e }, /* decimalpoint . FULL STOP */
|
||||
{ 0x0abe, 0x27e9 }, /* rightanglebracket ⟩ MATHEMATICAL RIGHT ANGLE BRACKET */
|
||||
{ 0x0abe, 0x232a }, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET */
|
||||
/* 0x0abf marker ? ??? */
|
||||
{ 0x0ac3, 0x215b }, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */
|
||||
{ 0x0ac4, 0x215c }, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */
|
||||
@@ -546,13 +546,12 @@ static const struct {
|
||||
{ 0x0acc, 0x25c1 }, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */
|
||||
{ 0x0acd, 0x25b7 }, /* rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */
|
||||
{ 0x0ace, 0x25cb }, /* emopencircle ○ WHITE CIRCLE */
|
||||
{ 0x0acf, 0x25af }, /* emopenrectangle ▯ WHITE VERTICAL RECTANGLE */
|
||||
{ 0x0acf, 0x25a1 }, /* emopenrectangle □ WHITE SQUARE */
|
||||
{ 0x0ad0, 0x2018 }, /* leftsinglequotemark ‘ LEFT SINGLE QUOTATION MARK */
|
||||
{ 0x0ad1, 0x2019 }, /* rightsinglequotemark ’ RIGHT SINGLE QUOTATION MARK */
|
||||
{ 0x0ad2, 0x201c }, /* leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */
|
||||
{ 0x0ad3, 0x201d }, /* rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */
|
||||
{ 0x0ad4, 0x211e }, /* prescription ℞ PRESCRIPTION TAKE */
|
||||
{ 0x0ad5, 0x2030 }, /* permille ‰ PER MILLE SIGN */
|
||||
{ 0x0ad6, 0x2032 }, /* minutes ′ PRIME */
|
||||
{ 0x0ad7, 0x2033 }, /* seconds ″ DOUBLE PRIME */
|
||||
{ 0x0ad9, 0x271d }, /* latincross ✝ LATIN CROSS */
|
||||
@@ -561,7 +560,7 @@ static const struct {
|
||||
{ 0x0adc, 0x25c0 }, /* filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */
|
||||
{ 0x0add, 0x25b6 }, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */
|
||||
{ 0x0ade, 0x25cf }, /* emfilledcircle ● BLACK CIRCLE */
|
||||
{ 0x0adf, 0x25ae }, /* emfilledrect ▮ BLACK VERTICAL RECTANGLE */
|
||||
{ 0x0adf, 0x25a0 }, /* emfilledrect ■ BLACK SQUARE */
|
||||
{ 0x0ae0, 0x25e6 }, /* enopencircbullet ◦ WHITE BULLET */
|
||||
{ 0x0ae1, 0x25ab }, /* enopensquarebullet ▫ WHITE SMALL SQUARE */
|
||||
{ 0x0ae2, 0x25ad }, /* openrectbullet ▭ WHITE RECTANGLE */
|
||||
@@ -806,16 +805,15 @@ static const struct {
|
||||
{ 0x0ef0, 0x3171 }, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */
|
||||
{ 0x0ef1, 0x3178 }, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */
|
||||
{ 0x0ef2, 0x317f }, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */
|
||||
{ 0x0ef3, 0x3181 }, /* Hangul_KkogjiDalrinIeung ㆁ HANGUL LETTER YESIEUNG */
|
||||
/* 0x0ef3 Hangul_KkogjiDalrinIeung ? ??? */
|
||||
{ 0x0ef4, 0x3184 }, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */
|
||||
{ 0x0ef5, 0x3186 }, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */
|
||||
{ 0x0ef6, 0x318d }, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */
|
||||
{ 0x0ef7, 0x318e }, /* Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */
|
||||
{ 0x0ef8, 0x11eb }, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */
|
||||
{ 0x0ef9, 0x11f0 }, /* Hangul_J_KkogjiDalrinIeung ᇰ HANGUL JONGSEONG YESIEUNG */
|
||||
/* 0x0ef9 Hangul_J_KkogjiDalrinIeung ? ??? */
|
||||
{ 0x0efa, 0x11f9 }, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */
|
||||
{ 0x0eff, 0x20a9 }, /* Korean_Won ₩ WON SIGN */
|
||||
{ 0x13a4, 0x20ac }, /* Euro € EURO SIGN */
|
||||
{ 0x13bc, 0x0152 }, /* OE Œ LATIN CAPITAL LIGATURE OE */
|
||||
{ 0x13bd, 0x0153 }, /* oe œ LATIN SMALL LIGATURE OE */
|
||||
{ 0x13be, 0x0178 }, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */
|
||||
@@ -837,13 +835,18 @@ static const struct {
|
||||
/* Following items added to GTK, not in the xterm table */
|
||||
|
||||
/* A few ASCII control characters */
|
||||
|
||||
#ifndef GDK_WINDOWING_WIN32
|
||||
{ 0xFF08 /* Backspace */, '\b' },
|
||||
{ 0xFF09 /* Tab */, '\t' },
|
||||
#endif
|
||||
|
||||
{ 0xFF0A /* Linefeed */, '\n' },
|
||||
{ 0xFF0B /* Vert. Tab */, '\v' },
|
||||
|
||||
#ifndef GDK_WINDOWING_WIN32
|
||||
{ 0xFF0D /* Return */, '\r' },
|
||||
{ 0xFF1B /* Escape */, '\033' },
|
||||
#endif
|
||||
|
||||
/* Numeric keypad */
|
||||
|
||||
@@ -868,7 +871,9 @@ static const struct {
|
||||
|
||||
/* End numeric keypad */
|
||||
|
||||
#ifndef GDK_WINDOWING_WIN32
|
||||
{ 0xFFFF /* Delete */, '\177' }
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1079,7 +1084,7 @@ static const struct {
|
||||
{ 0x07d7, 0x03a7 }, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */
|
||||
{ 0x07d8, 0x03a8 }, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */
|
||||
{ 0x07d9, 0x03a9 }, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */
|
||||
{ 0x07a5, 0x03aa }, /* Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */
|
||||
{ 0x07a5, 0x03aa }, /* Greek_IOTAdieresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */
|
||||
{ 0x07a9, 0x03ab }, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */
|
||||
{ 0x07b1, 0x03ac }, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */
|
||||
{ 0x07b2, 0x03ad }, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */
|
||||
@@ -1394,7 +1399,6 @@ static const struct {
|
||||
{ 0x0eed, 0x11c1 }, /* Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */
|
||||
{ 0x0eee, 0x11c2 }, /* Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */
|
||||
{ 0x0ef8, 0x11eb }, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */
|
||||
{ 0x0ef9, 0x11f0 }, /* Hangul_J_KkogjiDalrinIeung ᇰ HANGUL JONGSEONG YESIEUNG */
|
||||
{ 0x0efa, 0x11f9 }, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */
|
||||
{ 0x0aa2, 0x2002 }, /* enspace EN SPACE */
|
||||
{ 0x0aa1, 0x2003 }, /* emspace EM SPACE */
|
||||
@@ -1418,9 +1422,7 @@ static const struct {
|
||||
{ 0x0af1, 0x2020 }, /* dagger † DAGGER */
|
||||
{ 0x0af2, 0x2021 }, /* doubledagger ‡ DOUBLE DAGGER */
|
||||
{ 0x0ae6, 0x2022 }, /* enfilledcircbullet • BULLET */
|
||||
{ 0x0aaf, 0x2025 }, /* doubbaselinedot ‥ TWO DOT LEADER */
|
||||
{ 0x0aae, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */
|
||||
{ 0x0ad5, 0x2030 }, /* permille ‰ PER MILLE SIGN */
|
||||
{ 0x0ad6, 0x2032 }, /* minutes ′ PRIME */
|
||||
{ 0x0ad7, 0x2033 }, /* seconds ″ DOUBLE PRIME */
|
||||
{ 0x0afc, 0x2038 }, /* caret ‸ CARET */
|
||||
@@ -1478,8 +1480,7 @@ static const struct {
|
||||
{ 0x0bd6, 0x222a }, /* downshoe ∪ UNION */
|
||||
{ 0x08bf, 0x222b }, /* integral ∫ INTEGRAL */
|
||||
{ 0x08c0, 0x2234 }, /* therefore ∴ THEREFORE */
|
||||
{ 0x08c8, 0x223c }, /* approximate ∼ TILDE OPERATOR */
|
||||
{ 0x08c9, 0x2243 }, /* similarequal ≃ ASYMPTOTICALLY EQUAL TO */
|
||||
{ 0x08c8, 0x2245 }, /* approximate ≅ APPROXIMATELY EQUAL TO */
|
||||
{ 0x08bd, 0x2260 }, /* notequal ≠ NOT EQUAL TO */
|
||||
{ 0x08cf, 0x2261 }, /* identical ≡ IDENTICAL TO */
|
||||
{ 0x08bc, 0x2264 }, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */
|
||||
@@ -1497,28 +1498,15 @@ static const struct {
|
||||
{ 0x0afa, 0x2315 }, /* telephonerecorder ⌕ TELEPHONE RECORDER */
|
||||
{ 0x08a4, 0x2320 }, /* topintegral ⌠ TOP HALF INTEGRAL */
|
||||
{ 0x08a5, 0x2321 }, /* botintegral ⌡ BOTTOM HALF INTEGRAL */
|
||||
{ 0x0abc, 0x2329 }, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET */
|
||||
{ 0x0abe, 0x232a }, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET */
|
||||
{ 0x0bcc, 0x2395 }, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD (Unicode 3.0) */
|
||||
{ 0x08a7, 0x23a1 }, /* topleftsqbracket ⎡ ??? */
|
||||
{ 0x08a8, 0x23a3 }, /* botleftsqbracket ⎣ ??? */
|
||||
{ 0x08a9, 0x23a4 }, /* toprightsqbracket ⎤ ??? */
|
||||
{ 0x08aa, 0x23a6 }, /* botrightsqbracket ⎦ ??? */
|
||||
{ 0x08ab, 0x239b }, /* topleftparens ⎛ ??? */
|
||||
{ 0x08ac, 0x239d }, /* botleftparens ⎝ ??? */
|
||||
{ 0x08ad, 0x239e }, /* toprightparens ⎞ ??? */
|
||||
{ 0x08ae, 0x23a0 }, /* botrightparens ⎠ ??? */
|
||||
{ 0x08af, 0x23a8 }, /* leftmiddlecurlybrace ⎨ ??? */
|
||||
{ 0x08b0, 0x23ac }, /* rightmiddlecurlybrace ⎬ ??? */
|
||||
{ 0x08a1, 0x23b7 }, /* leftradical ⎷ ??? */
|
||||
{ 0x09ef, 0x23ba }, /* horizlinescan1 ⎺ HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */
|
||||
{ 0x09f0, 0x23bb }, /* horizlinescan3 ⎻ HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */
|
||||
{ 0x09f2, 0x23bc }, /* horizlinescan7 ⎼ HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */
|
||||
{ 0x09f3, 0x23bd }, /* horizlinescan9 ⎽ HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */
|
||||
{ 0x09e2, 0x2409 }, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */
|
||||
{ 0x09e5, 0x240a }, /* lf ␊ SYMBOL FOR LINE FEED */
|
||||
{ 0x09e9, 0x240b }, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */
|
||||
{ 0x09e3, 0x240c }, /* ff ␌ SYMBOL FOR FORM FEED */
|
||||
{ 0x09e4, 0x240d }, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */
|
||||
{ 0x0aac, 0x2423 }, /* signifblank ␣ OPEN BOX */
|
||||
{ 0x09df, 0x2422 }, /* blank ␢ BLANK SYMBOL */
|
||||
{ 0x09e8, 0x2424 }, /* nl  SYMBOL FOR NEWLINE */
|
||||
{ 0x09f1, 0x2500 }, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */
|
||||
{ 0x08a6, 0x2502 }, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */
|
||||
@@ -1534,11 +1522,11 @@ static const struct {
|
||||
{ 0x09ee, 0x253c }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
|
||||
{ 0x09e1, 0x2592 }, /* checkerboard ▒ MEDIUM SHADE */
|
||||
{ 0x0adf, 0x25a0 }, /* emfilledrect ■ BLACK SQUARE */
|
||||
{ 0x0acf, 0x25a1 }, /* emopenrectangle □ WHITE SQUARE */
|
||||
{ 0x0ae7, 0x25aa }, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */
|
||||
{ 0x0ae1, 0x25ab }, /* enopensquarebullet ▫ WHITE SMALL SQUARE */
|
||||
{ 0x0adb, 0x25ac }, /* filledrectbullet ▬ BLACK RECTANGLE */
|
||||
{ 0x0ae2, 0x25ad }, /* openrectbullet ▭ WHITE RECTANGLE */
|
||||
{ 0x0acf, 0x25af }, /* emopenrectangle ▯ WHITE VERTICAL RECTANGLE */
|
||||
{ 0x0ae8, 0x25b2 }, /* filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */
|
||||
{ 0x0ae3, 0x25b3 }, /* opentribulletup △ WHITE UP-POINTING TRIANGLE */
|
||||
{ 0x0add, 0x25b6 }, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */
|
||||
@@ -1568,8 +1556,6 @@ static const struct {
|
||||
{ 0x0af4, 0x2717 }, /* ballotcross ✗ BALLOT X */
|
||||
{ 0x0ad9, 0x271d }, /* latincross ✝ LATIN CROSS */
|
||||
{ 0x0af0, 0x2720 }, /* maltesecross ✠ MALTESE CROSS */
|
||||
{ 0x0abc, 0x27e8 }, /* leftanglebracket ⟨ MATHEMATICAL LEFT ANGLE BRACKET */
|
||||
{ 0x0abe, 0x27e9 }, /* rightanglebracket ⟩ MATHEMATICAL RIGHT ANGLE BRACKET */
|
||||
{ 0x04a4, 0x3001 }, /* kana_comma 、 IDEOGRAPHIC COMMA */
|
||||
{ 0x04a1, 0x3002 }, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */
|
||||
{ 0x04a2, 0x300c }, /* kana_openingbracket 「 LEFT CORNER BRACKET */
|
||||
@@ -1688,7 +1674,6 @@ static const struct {
|
||||
{ 0x0ef0, 0x3171 }, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */
|
||||
{ 0x0ef1, 0x3178 }, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */
|
||||
{ 0x0ef2, 0x317f }, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */
|
||||
{ 0x0ef3, 0x3181 }, /* Hangul_KkogjiDalrinIeung ㆁ HANGUL LETTER YESIEUNG */
|
||||
{ 0x0ef4, 0x3184 }, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */
|
||||
{ 0x0ef5, 0x3186 }, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */
|
||||
{ 0x0ef6, 0x318d }, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */
|
||||
|
||||
@@ -166,54 +166,6 @@ r32g32b32a32_float_from_float (guchar *dest,
|
||||
memcpy (dest, src, sizeof (float) * n * 4);
|
||||
}
|
||||
|
||||
#define PREMULTIPLY_FUNC(name, R1, G1, B1, A1, R2, G2, B2, A2) \
|
||||
static void \
|
||||
name (guchar *dest, \
|
||||
const guchar *src, \
|
||||
gsize n) \
|
||||
{ \
|
||||
for (; n > 0; n--) \
|
||||
{ \
|
||||
guchar a = src[A1]; \
|
||||
guint16 r = (guint16)src[R1] * a + 127; \
|
||||
guint16 g = (guint16)src[G1] * a + 127; \
|
||||
guint16 b = (guint16)src[B1] * a + 127; \
|
||||
dest[R2] = (r + (r >> 8) + 1) >> 8; \
|
||||
dest[G2] = (g + (g >> 8) + 1) >> 8; \
|
||||
dest[B2] = (b + (b >> 8) + 1) >> 8; \
|
||||
dest[A2] = a; \
|
||||
dest += 4; \
|
||||
src += 4; \
|
||||
} \
|
||||
}
|
||||
|
||||
PREMULTIPLY_FUNC(r8g8b8a8_to_r8g8b8a8_premultiplied, 0, 1, 2, 3, 0, 1, 2, 3)
|
||||
PREMULTIPLY_FUNC(r8g8b8a8_to_b8g8r8a8_premultiplied, 0, 1, 2, 3, 2, 1, 0, 3)
|
||||
PREMULTIPLY_FUNC(r8g8b8a8_to_a8r8g8b8_premultiplied, 0, 1, 2, 3, 1, 2, 3, 0)
|
||||
PREMULTIPLY_FUNC(r8g8b8a8_to_a8b8g8r8_premultiplied, 0, 1, 2, 3, 3, 2, 1, 0)
|
||||
|
||||
#define ADD_ALPHA_FUNC(name, R1, G1, B1, R2, G2, B2, A2) \
|
||||
static void \
|
||||
name (guchar *dest, \
|
||||
const guchar *src, \
|
||||
gsize n) \
|
||||
{ \
|
||||
for (; n > 0; n--) \
|
||||
{ \
|
||||
dest[R2] = src[R1]; \
|
||||
dest[G2] = src[G1]; \
|
||||
dest[B2] = src[B1]; \
|
||||
dest[A2] = 255; \
|
||||
dest += 4; \
|
||||
src += 3; \
|
||||
} \
|
||||
}
|
||||
|
||||
ADD_ALPHA_FUNC(r8g8b8_to_r8g8b8a8, 0, 1, 2, 0, 1, 2, 3)
|
||||
ADD_ALPHA_FUNC(r8g8b8_to_b8g8r8a8, 0, 1, 2, 2, 1, 0, 3)
|
||||
ADD_ALPHA_FUNC(r8g8b8_to_a8r8g8b8, 0, 1, 2, 1, 2, 3, 0)
|
||||
ADD_ALPHA_FUNC(r8g8b8_to_a8b8g8r8, 0, 1, 2, 3, 2, 1, 0)
|
||||
|
||||
struct _GdkMemoryFormatDescription
|
||||
{
|
||||
GdkMemoryAlpha alpha;
|
||||
@@ -523,59 +475,10 @@ gdk_memory_convert (guchar *dest_data,
|
||||
const GdkMemoryFormatDescription *src_desc = &memory_formats[src_format];
|
||||
float *tmp;
|
||||
gsize y;
|
||||
void (*func) (guchar *, const guchar *, gsize) = NULL;
|
||||
|
||||
g_assert (dest_format < GDK_MEMORY_N_FORMATS);
|
||||
g_assert (src_format < GDK_MEMORY_N_FORMATS);
|
||||
|
||||
if (src_format == GDK_MEMORY_R8G8B8A8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
|
||||
func = r8g8b8a8_to_r8g8b8a8_premultiplied;
|
||||
else if (src_format == GDK_MEMORY_B8G8R8A8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
|
||||
func = r8g8b8a8_to_b8g8r8a8_premultiplied;
|
||||
else if (src_format == GDK_MEMORY_R8G8B8A8 && dest_format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED)
|
||||
func = r8g8b8a8_to_b8g8r8a8_premultiplied;
|
||||
else if (src_format == GDK_MEMORY_B8G8R8A8 && dest_format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED)
|
||||
func = r8g8b8a8_to_r8g8b8a8_premultiplied;
|
||||
else if (src_format == GDK_MEMORY_R8G8B8A8 && dest_format == GDK_MEMORY_A8R8G8B8_PREMULTIPLIED)
|
||||
func = r8g8b8a8_to_a8r8g8b8_premultiplied;
|
||||
else if (src_format == GDK_MEMORY_B8G8R8A8 && dest_format == GDK_MEMORY_A8R8G8B8_PREMULTIPLIED)
|
||||
func = r8g8b8a8_to_a8b8g8r8_premultiplied;
|
||||
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
|
||||
func = r8g8b8_to_r8g8b8a8;
|
||||
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
|
||||
func = r8g8b8_to_b8g8r8a8;
|
||||
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED)
|
||||
func = r8g8b8_to_b8g8r8a8;
|
||||
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED)
|
||||
func = r8g8b8_to_r8g8b8a8;
|
||||
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_A8R8G8B8_PREMULTIPLIED)
|
||||
func = r8g8b8_to_a8r8g8b8;
|
||||
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_A8R8G8B8_PREMULTIPLIED)
|
||||
func = r8g8b8_to_a8b8g8r8;
|
||||
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_R8G8B8A8)
|
||||
func = r8g8b8_to_r8g8b8a8;
|
||||
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_R8G8B8A8)
|
||||
func = r8g8b8_to_b8g8r8a8;
|
||||
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_B8G8R8A8)
|
||||
func = r8g8b8_to_b8g8r8a8;
|
||||
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_B8G8R8A8)
|
||||
func = r8g8b8_to_r8g8b8a8;
|
||||
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_A8R8G8B8)
|
||||
func = r8g8b8_to_a8r8g8b8;
|
||||
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_A8R8G8B8)
|
||||
func = r8g8b8_to_a8b8g8r8;
|
||||
|
||||
if (func != NULL)
|
||||
{
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
func (dest_data, src_data, width);
|
||||
src_data += src_stride;
|
||||
dest_data += dest_stride;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
tmp = g_new (float, width * 4);
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
|
||||
+17
-17
@@ -1,5 +1,5 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
* Copyright (C) 2000 Red Hat, Inc.
|
||||
* Copyright (C) 2000 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -52,25 +52,25 @@ layout_iter_get_line_clip_region (PangoLayoutIter *iter,
|
||||
|
||||
i = 0;
|
||||
while (i < n_ranges)
|
||||
{
|
||||
{
|
||||
int *pixel_ranges = NULL;
|
||||
int n_pixel_ranges = 0;
|
||||
int j;
|
||||
|
||||
/* Note that get_x_ranges returns layout coordinates
|
||||
*/
|
||||
if (index_ranges[i*2+1] >= pango_layout_line_get_start_index (line) &&
|
||||
index_ranges[i*2] < pango_layout_line_get_start_index (line) + pango_layout_line_get_length (line))
|
||||
if (index_ranges[i*2+1] >= line->start_index &&
|
||||
index_ranges[i*2] < line->start_index + line->length)
|
||||
pango_layout_line_get_x_ranges (line,
|
||||
index_ranges[i*2],
|
||||
index_ranges[i*2+1],
|
||||
&pixel_ranges, &n_pixel_ranges);
|
||||
|
||||
|
||||
for (j = 0; j < n_pixel_ranges; j++)
|
||||
{
|
||||
GdkRectangle rect;
|
||||
int x_off, y_off;
|
||||
|
||||
|
||||
x_off = PANGO_PIXELS (pixel_ranges[2*j] - logical_rect.x);
|
||||
y_off = PANGO_PIXELS (baseline - logical_rect.y);
|
||||
|
||||
@@ -124,14 +124,14 @@ gdk_pango_layout_line_get_clip_region (PangoLayoutLine *line,
|
||||
{
|
||||
cairo_region_t *clip_region;
|
||||
PangoLayoutIter *iter;
|
||||
|
||||
|
||||
g_return_val_if_fail (line != NULL, NULL);
|
||||
g_return_val_if_fail (index_ranges != NULL, NULL);
|
||||
|
||||
|
||||
iter = pango_layout_get_iter (line->layout);
|
||||
while (pango_layout_iter_get_line_readonly (iter) != line)
|
||||
pango_layout_iter_next_line (iter);
|
||||
|
||||
|
||||
clip_region = layout_iter_get_line_clip_region(iter, x_origin, y_origin, index_ranges, n_ranges);
|
||||
|
||||
pango_layout_iter_free (iter);
|
||||
@@ -167,26 +167,26 @@ gdk_pango_layout_get_clip_region (PangoLayout *layout,
|
||||
const int *index_ranges,
|
||||
int n_ranges)
|
||||
{
|
||||
PangoLayoutIter *iter;
|
||||
PangoLayoutIter *iter;
|
||||
cairo_region_t *clip_region;
|
||||
|
||||
|
||||
g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL);
|
||||
g_return_val_if_fail (index_ranges != NULL, NULL);
|
||||
|
||||
|
||||
clip_region = cairo_region_create ();
|
||||
|
||||
|
||||
iter = pango_layout_get_iter (layout);
|
||||
|
||||
|
||||
do
|
||||
{
|
||||
PangoRectangle logical_rect;
|
||||
cairo_region_t *line_region;
|
||||
int baseline;
|
||||
|
||||
|
||||
pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
|
||||
baseline = pango_layout_iter_get_baseline (iter);
|
||||
baseline = pango_layout_iter_get_baseline (iter);
|
||||
|
||||
line_region = layout_iter_get_line_clip_region(iter,
|
||||
line_region = layout_iter_get_line_clip_region(iter,
|
||||
x_origin + PANGO_PIXELS (logical_rect.x),
|
||||
y_origin + PANGO_PIXELS (baseline),
|
||||
index_ranges,
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
((_GDK_RGBA_SELECT_COLOR(str, 0, 0) << 4) | _GDK_RGBA_SELECT_COLOR(str, 0, 1)) / 255., \
|
||||
((_GDK_RGBA_SELECT_COLOR(str, 1, 2) << 4) | _GDK_RGBA_SELECT_COLOR(str, 1, 3)) / 255., \
|
||||
((_GDK_RGBA_SELECT_COLOR(str, 2, 4) << 4) | _GDK_RGBA_SELECT_COLOR(str, 2, 5)) / 255., \
|
||||
((sizeof(str) % 4 == 1) ? ((_GDK_RGBA_SELECT_COLOR(str, 3, 6) << 4) | _GDK_RGBA_SELECT_COLOR(str, 3, 7)) : 0xFF) / 255. })
|
||||
((sizeof(str) % 4 == 1) ? ((_GDK_RGBA_SELECT_COLOR(str, 3, 6) << 4) | _GDK_RGBA_SELECT_COLOR(str, 3, 7)) : 0xFF) / 255 })
|
||||
|
||||
|
||||
gboolean gdk_rgba_parser_parse (GtkCssParser *parser,
|
||||
|
||||
+1
-9
@@ -2244,7 +2244,7 @@ _gdk_windowing_got_event (GdkDisplay *display,
|
||||
GdkEvent *event,
|
||||
gulong serial)
|
||||
{
|
||||
GdkSurface *event_surface = NULL;
|
||||
GdkSurface *event_surface;
|
||||
gboolean unlink_event = FALSE;
|
||||
GdkDeviceGrabInfo *button_release_grab;
|
||||
GdkPointerSurfaceInfo *pointer_info = NULL;
|
||||
@@ -2336,14 +2336,6 @@ _gdk_windowing_got_event (GdkDisplay *display,
|
||||
*/
|
||||
_gdk_event_queue_handle_motion_compression (display);
|
||||
gdk_event_queue_handle_scroll_compression (display);
|
||||
|
||||
if (event_surface)
|
||||
{
|
||||
GdkFrameClock *clock = gdk_surface_get_frame_clock (event_surface);
|
||||
|
||||
if (clock) /* might be NULL if surface was destroyed */
|
||||
gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -83,8 +83,6 @@
|
||||
*
|
||||
* A macro that evaluates to the 4.2 version of GDK, in a format
|
||||
* that can be used by the C pre-processor.
|
||||
*
|
||||
* Since: 4.2
|
||||
*/
|
||||
#define GDK_VERSION_4_2 (G_ENCODE_VERSION (4, 2))
|
||||
|
||||
@@ -93,8 +91,6 @@
|
||||
*
|
||||
* A macro that evaluates to the 4.4 version of GDK, in a format
|
||||
* that can be used by the C pre-processor.
|
||||
*
|
||||
* Since: 4.4
|
||||
*/
|
||||
#define GDK_VERSION_4_4 (G_ENCODE_VERSION (4, 4))
|
||||
|
||||
@@ -103,21 +99,9 @@
|
||||
*
|
||||
* A macro that evaluates to the 4.6 version of GDK, in a format
|
||||
* that can be used by the C pre-processor.
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
#define GDK_VERSION_4_6 (G_ENCODE_VERSION (4, 6))
|
||||
|
||||
/**
|
||||
* GDK_VERSION_4_8:
|
||||
*
|
||||
* A macro that evaluates to the 4.8 version of GDK, in a format
|
||||
* that can be used by the C pre-processor.
|
||||
*
|
||||
* Since: 4.8
|
||||
*/
|
||||
#define GDK_VERSION_4_8 (G_ENCODE_VERSION (4, 8))
|
||||
|
||||
|
||||
/* evaluates to the current stable version; for development cycles,
|
||||
* this means the next stable target, with a hard backstop to the
|
||||
@@ -259,18 +243,4 @@
|
||||
# define GDK_DEPRECATED_IN_4_6_FOR(f) _GDK_EXTERN
|
||||
#endif
|
||||
|
||||
#if GDK_VERSION_MAX_ALLOWED < GDK_VERSION_4_8
|
||||
# define GDK_AVAILABLE_IN_4_8 GDK_UNAVAILABLE(4, 8)
|
||||
#else
|
||||
# define GDK_AVAILABLE_IN_4_8 _GDK_EXTERN
|
||||
#endif
|
||||
|
||||
#if GDK_VERSION_MIN_REQUIRED >= GDK_VERSION_4_8
|
||||
# define GDK_DEPRECATED_IN_4_8 GDK_DEPRECATED
|
||||
# define GDK_DEPRECATED_IN_4_8_FOR(f) GDK_DEPRECATED_FOR(f)
|
||||
#else
|
||||
# define GDK_DEPRECATED_IN_4_8 _GDK_EXTERN
|
||||
# define GDK_DEPRECATED_IN_4_8_FOR(f) _GDK_EXTERN
|
||||
#endif
|
||||
|
||||
#endif /* __GDK_VERSION_MACROS_H__ */
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gdkjpegprivate.h"
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
|
||||
options = (NSTrackingMouseEnteredAndExited |
|
||||
NSTrackingMouseMoved |
|
||||
NSTrackingInVisibleRect |
|
||||
NSTrackingActiveAlways);
|
||||
trackingArea = [[NSTrackingArea alloc] initWithRect:rect
|
||||
options:options
|
||||
@@ -56,26 +57,9 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)setInputArea:(const cairo_rectangle_int_t *)area
|
||||
{
|
||||
NSRect rect = NSMakeRect (area->x, area->y, area->width, area->height);
|
||||
NSTrackingAreaOptions options;
|
||||
|
||||
[self removeTrackingArea:trackingArea];
|
||||
|
||||
options = (NSTrackingMouseEnteredAndExited |
|
||||
NSTrackingMouseMoved |
|
||||
NSTrackingActiveAlways);
|
||||
trackingArea = [[NSTrackingArea alloc] initWithRect:rect
|
||||
options:options
|
||||
owner:(id)self
|
||||
userInfo:nil];
|
||||
[self addTrackingArea:trackingArea];
|
||||
}
|
||||
|
||||
-(void)setOpaqueRegion:(cairo_region_t *)region
|
||||
{
|
||||
/* Handled in Subclass */
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
-(BOOL)acceptsFirstMouse
|
||||
|
||||
@@ -42,6 +42,5 @@
|
||||
-(void)setNeedsInvalidateShadow: (BOOL)invalidate;
|
||||
-(NSTrackingArea *)trackingArea;
|
||||
-(void)setOpaqueRegion:(cairo_region_t *)region;
|
||||
-(void)setInputArea:(const cairo_rectangle_int_t *)area;
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
/* GdkMacosCairoSubview.c
|
||||
*
|
||||
* Copyright © 2020 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
#include <cairo-quartz.h>
|
||||
|
||||
|
||||
#import "GdkMacosCairoSubview.h"
|
||||
#import "GdkMacosCairoView.h"
|
||||
|
||||
#include "gdkmacossurface-private.h"
|
||||
|
||||
@implementation GdkMacosCairoSubview
|
||||
|
||||
-(void)dealloc
|
||||
{
|
||||
g_clear_pointer (&self->clip, cairo_region_destroy);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
-(BOOL)isOpaque
|
||||
{
|
||||
return _isOpaque;
|
||||
}
|
||||
|
||||
-(BOOL)isFlipped
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(GdkSurface *)gdkSurface
|
||||
{
|
||||
return GDK_SURFACE ([(GdkMacosBaseView *)[self superview] gdkSurface]);
|
||||
}
|
||||
|
||||
-(void)drawRect:(NSRect)rect
|
||||
{
|
||||
CGContextRef cgContext;
|
||||
GdkSurface *gdk_surface;
|
||||
cairo_surface_t *dest;
|
||||
const NSRect *rects = NULL;
|
||||
NSView *root_view;
|
||||
NSInteger n_rects = 0;
|
||||
NSRect abs_bounds;
|
||||
cairo_t *cr;
|
||||
CGSize scale;
|
||||
int scale_factor;
|
||||
|
||||
if (self->cairoSurface == NULL)
|
||||
return;
|
||||
|
||||
/* Acquire everything we need to do translations, drawing, etc */
|
||||
gdk_surface = [self gdkSurface];
|
||||
scale_factor = gdk_surface_get_scale_factor (gdk_surface);
|
||||
root_view = [[self window] contentView];
|
||||
cgContext = [[NSGraphicsContext currentContext] CGContext];
|
||||
abs_bounds = [self convertRect:[self bounds] toView:root_view];
|
||||
|
||||
CGContextSaveGState (cgContext);
|
||||
|
||||
/* Translate scaling to remove HiDPI scaling from CGContext as
|
||||
* cairo will be doing that for us already.
|
||||
*/
|
||||
scale = CGSizeMake (1.0, 1.0);
|
||||
scale = CGContextConvertSizeToDeviceSpace (cgContext, scale);
|
||||
CGContextScaleCTM (cgContext, 1.0 / scale.width, 1.0 / scale.height);
|
||||
|
||||
/* Create the cairo surface to draw to the CGContext and translate
|
||||
* coordinates so we can pretend we are in the same coordinate system
|
||||
* as the GDK surface.
|
||||
*/
|
||||
dest = cairo_quartz_surface_create_for_cg_context (cgContext,
|
||||
gdk_surface->width * scale_factor,
|
||||
gdk_surface->height * scale_factor);
|
||||
cairo_surface_set_device_scale (dest, scale_factor, scale_factor);
|
||||
|
||||
/* Create cairo context and translate things into the origin of
|
||||
* the topmost contentView so that we just draw at 0,0 with a
|
||||
* clip region to paint the surface.
|
||||
*/
|
||||
cr = cairo_create (dest);
|
||||
cairo_translate (cr, -abs_bounds.origin.x, -abs_bounds.origin.y);
|
||||
|
||||
/* Apply the clip if provided one */
|
||||
if (self->clip != NULL)
|
||||
{
|
||||
cairo_rectangle_int_t area;
|
||||
|
||||
n_rects = cairo_region_num_rectangles (self->clip);
|
||||
for (guint i = 0; i < n_rects; i++)
|
||||
{
|
||||
cairo_region_get_rectangle (self->clip, i, &area);
|
||||
cairo_rectangle (cr, area.x, area.y, area.width, area.height);
|
||||
}
|
||||
|
||||
cairo_clip (cr);
|
||||
}
|
||||
|
||||
/* Clip the cairo context based on the rectangles to be drawn
|
||||
* within the bounding box :rect.
|
||||
*/
|
||||
[self getRectsBeingDrawn:&rects count:&n_rects];
|
||||
for (NSInteger i = 0; i < n_rects; i++)
|
||||
{
|
||||
NSRect area = [self convertRect:rects[i] toView:root_view];
|
||||
cairo_rectangle (cr,
|
||||
area.origin.x, area.origin.y,
|
||||
area.size.width, area.size.height);
|
||||
}
|
||||
cairo_clip (cr);
|
||||
|
||||
/* Now paint the surface (without blending) as we do not need
|
||||
* any compositing here. The transparent regions (like shadows)
|
||||
* are already on non-opaque layers.
|
||||
*/
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_set_source_surface (cr, self->cairoSurface, 0, 0);
|
||||
cairo_paint (cr);
|
||||
|
||||
/* Cleanup state, flush the surface to the backing layer, and
|
||||
* restore GState for future use.
|
||||
*/
|
||||
cairo_destroy (cr);
|
||||
cairo_surface_flush (dest);
|
||||
cairo_surface_destroy (dest);
|
||||
CGContextRestoreGState (cgContext);
|
||||
}
|
||||
|
||||
-(void)setCairoSurface:(cairo_surface_t *)surface
|
||||
withDamage:(cairo_region_t *)region
|
||||
{
|
||||
if (surface != self->cairoSurface)
|
||||
{
|
||||
g_clear_pointer (&self->cairoSurface, cairo_surface_destroy);
|
||||
if (surface != NULL)
|
||||
self->cairoSurface = cairo_surface_reference (surface);
|
||||
}
|
||||
|
||||
if (region != NULL)
|
||||
{
|
||||
NSView *root_view = [[self window] contentView];
|
||||
NSRect abs_bounds = [self convertRect:[self bounds] toView:root_view];
|
||||
guint n_rects = cairo_region_num_rectangles (region);
|
||||
|
||||
for (guint i = 0; i < n_rects; i++)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
NSRect nsrect;
|
||||
|
||||
cairo_region_get_rectangle (region, i, &rect);
|
||||
nsrect = NSMakeRect (rect.x, rect.y, rect.width, rect.height);
|
||||
|
||||
if (NSIntersectsRect (abs_bounds, nsrect))
|
||||
{
|
||||
nsrect.origin.x -= abs_bounds.origin.x;
|
||||
nsrect.origin.y -= abs_bounds.origin.y;
|
||||
[self setNeedsDisplayInRect:nsrect];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (id view in [self subviews])
|
||||
[(GdkMacosCairoSubview *)view setCairoSurface:surface
|
||||
withDamage:region];
|
||||
}
|
||||
|
||||
-(void)setOpaque:(BOOL)opaque
|
||||
{
|
||||
self->_isOpaque = opaque;
|
||||
}
|
||||
|
||||
-(void)setClip:(cairo_region_t*)region
|
||||
{
|
||||
if (region != self->clip)
|
||||
{
|
||||
g_clear_pointer (&self->clip, cairo_region_destroy);
|
||||
if (region != NULL)
|
||||
self->clip = cairo_region_reference (region);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,6 +1,6 @@
|
||||
/* GdkMacosTile.h
|
||||
/* GdkMacosCairoSubview.h
|
||||
*
|
||||
* Copyright © 2022 Red Hat, Inc.
|
||||
* Copyright © 2020 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -18,20 +18,20 @@
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include <QuartzCore/QuartzCore.h>
|
||||
#include <AppKit/AppKit.h>
|
||||
|
||||
#include "gdkmacosbuffer-private.h"
|
||||
#define GDK_IS_MACOS_CAIRO_SUBVIEW(obj) ((obj) && [obj isKindOfClass:[GdkMacosCairoSubview class]])
|
||||
|
||||
#define GDK_IS_MACOS_TILE(obj) ((obj) && [obj isKindOfClass:[GdkMacosTile class]])
|
||||
|
||||
@protocol CanSetContentsChanged
|
||||
-(void)setContentsChanged;
|
||||
@end
|
||||
|
||||
@interface GdkMacosTile : CALayer
|
||||
@interface GdkMacosCairoSubview : NSView
|
||||
{
|
||||
};
|
||||
BOOL _isOpaque;
|
||||
cairo_surface_t *cairoSurface;
|
||||
cairo_region_t *clip;
|
||||
}
|
||||
|
||||
-(void)swapBuffer:(IOSurfaceRef)buffer withRect:(CGRect)rect;
|
||||
-(void)setOpaque:(BOOL)opaque;
|
||||
-(void)setCairoSurface:(cairo_surface_t *)cairoSurface
|
||||
withDamage:(cairo_region_t *)region;
|
||||
-(void)setClip:(cairo_region_t*)region;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,187 @@
|
||||
/* GdkMacosCairoView.c
|
||||
*
|
||||
* Copyright © 2020 Red Hat, Inc.
|
||||
* Copyright © 2005-2007 Imendio AB
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
#include <cairo-quartz.h>
|
||||
|
||||
|
||||
#import "GdkMacosCairoView.h"
|
||||
#import "GdkMacosCairoSubview.h"
|
||||
|
||||
#include "gdkmacossurface-private.h"
|
||||
|
||||
@implementation GdkMacosCairoView
|
||||
|
||||
-(void)dealloc
|
||||
{
|
||||
g_clear_pointer (&self->opaque, g_ptr_array_unref);
|
||||
self->transparent = NULL;
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
-(BOOL)isOpaque
|
||||
{
|
||||
if ([self window])
|
||||
return [[self window] isOpaque];
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(BOOL)isFlipped
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(void)setNeedsDisplay:(BOOL)needsDisplay
|
||||
{
|
||||
for (id child in [self subviews])
|
||||
[child setNeedsDisplay:needsDisplay];
|
||||
}
|
||||
|
||||
-(void)setCairoSurface:(cairo_surface_t *)cairoSurface
|
||||
withDamage:(cairo_region_t *)cairoRegion
|
||||
{
|
||||
for (id view in [self subviews])
|
||||
[(GdkMacosCairoSubview *)view setCairoSurface:cairoSurface
|
||||
withDamage:cairoRegion];
|
||||
}
|
||||
|
||||
-(void)removeOpaqueChildren
|
||||
{
|
||||
[[self->transparent subviews]
|
||||
makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||
|
||||
if (self->opaque->len)
|
||||
g_ptr_array_remove_range (self->opaque, 0, self->opaque->len);
|
||||
}
|
||||
|
||||
-(void)setOpaqueRegion:(cairo_region_t *)region
|
||||
{
|
||||
cairo_region_t *transparent_clip;
|
||||
NSRect abs_bounds;
|
||||
guint n_rects;
|
||||
|
||||
if (region == NULL)
|
||||
return;
|
||||
|
||||
abs_bounds = [self convertRect:[self bounds] toView:nil];
|
||||
n_rects = cairo_region_num_rectangles (region);
|
||||
|
||||
/* First, we create a clip region for the transparent region to use so that
|
||||
* we dont end up exposing too much other than the corners on CSD.
|
||||
*/
|
||||
transparent_clip = cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
|
||||
abs_bounds.origin.x, abs_bounds.origin.y,
|
||||
abs_bounds.size.width, abs_bounds.size.height
|
||||
});
|
||||
cairo_region_subtract (transparent_clip, region);
|
||||
[(GdkMacosCairoSubview *)self->transparent setClip:transparent_clip];
|
||||
cairo_region_destroy (transparent_clip);
|
||||
|
||||
/* The common case (at least for opaque windows and CSD) is that we will
|
||||
* have either one or two opaque rectangles. If we detect that the same
|
||||
* number of them are available as the previous, we can just resize the
|
||||
* previous ones to avoid adding/removing views at a fast rate while
|
||||
* resizing.
|
||||
*/
|
||||
if (n_rects == self->opaque->len)
|
||||
{
|
||||
for (guint i = 0; i < n_rects; i++)
|
||||
{
|
||||
GdkMacosCairoSubview *child;
|
||||
cairo_rectangle_int_t rect;
|
||||
|
||||
child = g_ptr_array_index (self->opaque, i);
|
||||
cairo_region_get_rectangle (region, i, &rect);
|
||||
|
||||
[child setFrame:NSMakeRect (rect.x - abs_bounds.origin.x,
|
||||
rect.y - abs_bounds.origin.y,
|
||||
rect.width,
|
||||
rect.height)];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
[self removeOpaqueChildren];
|
||||
for (guint i = 0; i < n_rects; i++)
|
||||
{
|
||||
GdkMacosCairoSubview *child;
|
||||
cairo_rectangle_int_t rect;
|
||||
NSRect nsrect;
|
||||
|
||||
cairo_region_get_rectangle (region, i, &rect);
|
||||
nsrect = NSMakeRect (rect.x - abs_bounds.origin.x,
|
||||
rect.y - abs_bounds.origin.y,
|
||||
rect.width,
|
||||
rect.height);
|
||||
|
||||
child = [[GdkMacosCairoSubview alloc] initWithFrame:nsrect];
|
||||
[child setOpaque:YES];
|
||||
[child setWantsLayer:YES];
|
||||
[self->transparent addSubview:child];
|
||||
g_ptr_array_add (self->opaque, child);
|
||||
}
|
||||
}
|
||||
|
||||
-(NSView *)initWithFrame:(NSRect)frame
|
||||
{
|
||||
if ((self = [super initWithFrame:frame]))
|
||||
{
|
||||
/* An array to track all the opaque children placed into
|
||||
* the child self->transparent. This allows us to reuse them
|
||||
* when we receive a new opaque area instead of discarding
|
||||
* them on each draw.
|
||||
*/
|
||||
self->opaque = g_ptr_array_new ();
|
||||
|
||||
/* Setup our primary subview which will render all content that is not
|
||||
* within an opaque region (such as shadows for CSD windows). For opaque
|
||||
* windows, this will all be obscurred by other views, so it doesn't
|
||||
* matter much to have it here.
|
||||
*/
|
||||
self->transparent = [[GdkMacosCairoSubview alloc] initWithFrame:frame];
|
||||
[self addSubview:self->transparent];
|
||||
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)setFrame:(NSRect)rect
|
||||
{
|
||||
[super setFrame:rect];
|
||||
[self->transparent setFrame:NSMakeRect (0, 0, rect.size.width, rect.size.height)];
|
||||
}
|
||||
|
||||
-(BOOL)acceptsFirstMouse
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(BOOL)mouseDownCanMoveWindow
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,6 +1,7 @@
|
||||
/* GdkMacosView.h
|
||||
/* GdkMacosCairoView.h
|
||||
*
|
||||
* Copyright 2022 Christian Hergert <chergert@redhat.com>
|
||||
* Copyright © 2020 Red Hat, Inc.
|
||||
* Copyright © 2005-2007 Imendio AB
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -22,17 +23,15 @@
|
||||
|
||||
#import "GdkMacosBaseView.h"
|
||||
|
||||
#include "gdkmacosbuffer-private.h"
|
||||
#define GDK_IS_MACOS_CAIRO_VIEW(obj) ((obj) && [obj isKindOfClass:[GdkMacosCairoView class]])
|
||||
|
||||
#define GDK_IS_MACOS_VIEW(obj) ((obj) && [obj isKindOfClass:[GdkMacosView class]])
|
||||
|
||||
@interface GdkMacosView : GdkMacosBaseView
|
||||
@interface GdkMacosCairoView : GdkMacosBaseView
|
||||
{
|
||||
NSRect _nextFrame;
|
||||
guint _nextFrameDirty : 1;
|
||||
NSView *transparent;
|
||||
GPtrArray *opaque;
|
||||
}
|
||||
|
||||
-(void)setOpaqueRegion:(const cairo_region_t *)opaqueRegion;
|
||||
-(void)swapBuffer:(GdkMacosBuffer *)buffer withDamage:(const cairo_region_t *)damage;
|
||||
-(void)setCairoSurface:(cairo_surface_t *)cairoSurface
|
||||
withDamage:(cairo_region_t *)region;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,125 @@
|
||||
/* GdkMacosGLView.c
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
#include <OpenGL/gl.h>
|
||||
|
||||
#include "gdkmacossurface-private.h"
|
||||
|
||||
#import "GdkMacosGLView.h"
|
||||
|
||||
@implementation GdkMacosGLView
|
||||
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
|
||||
-(void)lockFocus
|
||||
{
|
||||
NSOpenGLContext *context;
|
||||
|
||||
[super lockFocus];
|
||||
|
||||
context = [self openGLContext];
|
||||
|
||||
if ([context view] != self)
|
||||
[context setView: self];
|
||||
}
|
||||
|
||||
-(void)drawRect:(NSRect)rect
|
||||
{
|
||||
}
|
||||
|
||||
-(void)clearGLContext
|
||||
{
|
||||
if (_openGLContext != nil)
|
||||
[_openGLContext clearDrawable];
|
||||
|
||||
_openGLContext = nil;
|
||||
}
|
||||
|
||||
-(void)setOpenGLContext:(NSOpenGLContext*)context
|
||||
{
|
||||
if (_openGLContext != context)
|
||||
{
|
||||
if (_openGLContext != nil)
|
||||
[_openGLContext clearDrawable];
|
||||
|
||||
_openGLContext = context;
|
||||
|
||||
if (_openGLContext != nil)
|
||||
{
|
||||
[_openGLContext setView:self];
|
||||
[self setWantsLayer:YES];
|
||||
[self.layer setContentsGravity:kCAGravityBottomLeft];
|
||||
[_openGLContext update];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-(NSOpenGLContext *)openGLContext
|
||||
{
|
||||
return _openGLContext;
|
||||
}
|
||||
|
||||
-(BOOL)isOpaque
|
||||
{
|
||||
if ([self window])
|
||||
return [[self window] isOpaque];
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(BOOL)isFlipped
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(BOOL)acceptsFirstMouse
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(BOOL)mouseDownCanMoveWindow
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
-(void)invalidateRegion:(const cairo_region_t *)region
|
||||
{
|
||||
if (region != NULL)
|
||||
{
|
||||
guint n_rects = cairo_region_num_rectangles (region);
|
||||
|
||||
for (guint i = 0; i < n_rects; i++)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
NSRect nsrect;
|
||||
|
||||
cairo_region_get_rectangle (region, i, &rect);
|
||||
nsrect = NSMakeRect (rect.x, rect.y, rect.width, rect.height);
|
||||
|
||||
[self setNeedsDisplayInRect:nsrect];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
|
||||
@end
|
||||
@@ -1,6 +1,7 @@
|
||||
/* GdkMacosTile.c
|
||||
/* GdkMacosGLView.h
|
||||
*
|
||||
* Copyright © 2022 Red Hat, Inc.
|
||||
* Copyright © 2020 Red Hat, Inc.
|
||||
* Copyright © 2005-2007 Imendio AB
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -18,34 +19,23 @@
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <cairo.h>
|
||||
|
||||
#include <AppKit/AppKit.h>
|
||||
#import "GdkMacosBaseView.h"
|
||||
|
||||
#import "GdkMacosTile.h"
|
||||
#define GDK_IS_MACOS_GL_VIEW(obj) ((obj) && [obj isKindOfClass:[GdkMacosGLView class]])
|
||||
|
||||
@implementation GdkMacosTile
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
|
||||
-(id)init
|
||||
@interface GdkMacosGLView : GdkMacosBaseView
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
[self setContentsScale:1.0];
|
||||
[self setEdgeAntialiasingMask:0];
|
||||
[self setDrawsAsynchronously:YES];
|
||||
|
||||
return self;
|
||||
NSOpenGLContext *_openGLContext;
|
||||
}
|
||||
|
||||
-(void)swapBuffer:(IOSurfaceRef)buffer withRect:(CGRect)rect
|
||||
{
|
||||
if G_LIKELY ([self contents] == (id)buffer)
|
||||
[(id<CanSetContentsChanged>)self setContentsChanged];
|
||||
else
|
||||
[self setContents:(id)buffer];
|
||||
-(void)setOpenGLContext:(NSOpenGLContext*)context;
|
||||
-(NSOpenGLContext *)openGLContext;
|
||||
-(void)invalidateRegion:(const cairo_region_t *)region;
|
||||
|
||||
if G_UNLIKELY (!CGRectEqualToRect ([self contentsRect], rect))
|
||||
self.contentsRect = rect;
|
||||
}
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
|
||||
@end
|
||||
@@ -1,386 +0,0 @@
|
||||
/* GdkMacosLayer.c
|
||||
*
|
||||
* Copyright © 2022 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#import "GdkMacosLayer.h"
|
||||
#import "GdkMacosTile.h"
|
||||
|
||||
@protocol CanSetContentsOpaque
|
||||
- (void)setContentsOpaque:(BOOL)mask;
|
||||
@end
|
||||
|
||||
@implementation GdkMacosLayer
|
||||
|
||||
#define TILE_MAX_SIZE 128
|
||||
#define TILE_EDGE_MAX_SIZE 512
|
||||
|
||||
static CGAffineTransform flipTransform;
|
||||
static gboolean hasFlipTransform;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GdkMacosTile *tile;
|
||||
cairo_rectangle_int_t cr_area;
|
||||
CGRect area;
|
||||
guint opaque : 1;
|
||||
} TileInfo;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const cairo_region_t *region;
|
||||
guint n_rects;
|
||||
guint iter;
|
||||
cairo_rectangle_int_t rect;
|
||||
cairo_rectangle_int_t stash;
|
||||
guint finished : 1;
|
||||
} Tiler;
|
||||
|
||||
static void
|
||||
tiler_init (Tiler *tiler,
|
||||
const cairo_region_t *region)
|
||||
{
|
||||
memset (tiler, 0, sizeof *tiler);
|
||||
|
||||
if (region == NULL)
|
||||
{
|
||||
tiler->finished = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
tiler->region = region;
|
||||
tiler->n_rects = cairo_region_num_rectangles (region);
|
||||
|
||||
if (tiler->n_rects > 0)
|
||||
cairo_region_get_rectangle (region, 0, &tiler->rect);
|
||||
else
|
||||
tiler->finished = TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
tiler_next (Tiler *tiler,
|
||||
cairo_rectangle_int_t *tile,
|
||||
int max_size)
|
||||
{
|
||||
if (tiler->finished)
|
||||
return FALSE;
|
||||
|
||||
if (tiler->rect.width == 0 || tiler->rect.height == 0)
|
||||
{
|
||||
tiler->iter++;
|
||||
|
||||
if (tiler->iter >= tiler->n_rects)
|
||||
{
|
||||
tiler->finished = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
cairo_region_get_rectangle (tiler->region, tiler->iter, &tiler->rect);
|
||||
}
|
||||
|
||||
/* If the next rectangle is too tall, slice the bottom off to
|
||||
* leave just the height we want into tiler->stash.
|
||||
*/
|
||||
if (tiler->rect.height > max_size)
|
||||
{
|
||||
tiler->stash = tiler->rect;
|
||||
tiler->stash.y += max_size;
|
||||
tiler->stash.height -= max_size;
|
||||
tiler->rect.height = max_size;
|
||||
}
|
||||
|
||||
/* Now we can take the next horizontal slice */
|
||||
tile->x = tiler->rect.x;
|
||||
tile->y = tiler->rect.y;
|
||||
tile->height = tiler->rect.height;
|
||||
tile->width = MIN (max_size, tiler->rect.width);
|
||||
|
||||
tiler->rect.x += tile->width;
|
||||
tiler->rect.width -= tile->width;
|
||||
|
||||
if (tiler->rect.width == 0)
|
||||
{
|
||||
tiler->rect = tiler->stash;
|
||||
tiler->stash.width = tiler->stash.height = 0;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline CGRect
|
||||
toCGRect (const cairo_rectangle_int_t *rect)
|
||||
{
|
||||
return CGRectMake (rect->x, rect->y, rect->width, rect->height);
|
||||
}
|
||||
|
||||
static inline cairo_rectangle_int_t
|
||||
fromCGRect (const CGRect rect)
|
||||
{
|
||||
return (cairo_rectangle_int_t) {
|
||||
rect.origin.x,
|
||||
rect.origin.y,
|
||||
rect.size.width,
|
||||
rect.size.height
|
||||
};
|
||||
}
|
||||
|
||||
-(id)init
|
||||
{
|
||||
if (!hasFlipTransform)
|
||||
{
|
||||
hasFlipTransform = TRUE;
|
||||
flipTransform = CGAffineTransformMakeScale (1, -1);
|
||||
}
|
||||
|
||||
self = [super init];
|
||||
|
||||
if (self == NULL)
|
||||
return NULL;
|
||||
|
||||
self->_layoutInvalid = TRUE;
|
||||
|
||||
[self setContentsGravity:kCAGravityCenter];
|
||||
[self setContentsScale:1.0f];
|
||||
[self setGeometryFlipped:YES];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
-(BOOL)isOpaque
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
-(void)_applyLayout:(GArray *)tiles
|
||||
{
|
||||
CGAffineTransform transform;
|
||||
GArray *prev;
|
||||
gboolean exhausted;
|
||||
guint j = 0;
|
||||
|
||||
if (self->_isFlipped)
|
||||
transform = flipTransform;
|
||||
else
|
||||
transform = CGAffineTransformIdentity;
|
||||
|
||||
prev = g_steal_pointer (&self->_tiles);
|
||||
self->_tiles = tiles;
|
||||
exhausted = prev == NULL;
|
||||
|
||||
/* Try to use existing CALayer to avoid creating new layers
|
||||
* as that can be rather expensive.
|
||||
*/
|
||||
for (guint i = 0; i < tiles->len; i++)
|
||||
{
|
||||
TileInfo *info = &g_array_index (tiles, TileInfo, i);
|
||||
|
||||
if (!exhausted)
|
||||
{
|
||||
TileInfo *other = NULL;
|
||||
|
||||
for (; j < prev->len; j++)
|
||||
{
|
||||
other = &g_array_index (prev, TileInfo, j);
|
||||
|
||||
if (other->opaque == info->opaque)
|
||||
{
|
||||
j++;
|
||||
break;
|
||||
}
|
||||
|
||||
other = NULL;
|
||||
}
|
||||
|
||||
if (other != NULL)
|
||||
{
|
||||
info->tile = g_steal_pointer (&other->tile);
|
||||
[info->tile setFrame:info->area];
|
||||
[info->tile setAffineTransform:transform];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
info->tile = [GdkMacosTile layer];
|
||||
|
||||
[info->tile setAffineTransform:transform];
|
||||
[info->tile setContentsScale:1.0f];
|
||||
[info->tile setOpaque:info->opaque];
|
||||
[(id<CanSetContentsOpaque>)info->tile setContentsOpaque:info->opaque];
|
||||
[info->tile setFrame:info->area];
|
||||
|
||||
[self addSublayer:info->tile];
|
||||
}
|
||||
|
||||
/* Release all of our old layers */
|
||||
if (prev != NULL)
|
||||
{
|
||||
for (guint i = 0; i < prev->len; i++)
|
||||
{
|
||||
TileInfo *info = &g_array_index (prev, TileInfo, i);
|
||||
|
||||
if (info->tile != NULL)
|
||||
[info->tile removeFromSuperlayer];
|
||||
}
|
||||
|
||||
g_array_unref (prev);
|
||||
}
|
||||
}
|
||||
|
||||
-(void)layoutSublayers
|
||||
{
|
||||
Tiler tiler;
|
||||
GArray *ar;
|
||||
cairo_region_t *transparent;
|
||||
cairo_rectangle_int_t rect;
|
||||
int max_size;
|
||||
|
||||
if (!self->_inSwapBuffer)
|
||||
return;
|
||||
|
||||
self->_layoutInvalid = FALSE;
|
||||
|
||||
ar = g_array_sized_new (FALSE, FALSE, sizeof (TileInfo), 32);
|
||||
|
||||
rect = fromCGRect ([self bounds]);
|
||||
rect.x = rect.y = 0;
|
||||
|
||||
/* Calculate the transparent region (edges usually) */
|
||||
transparent = cairo_region_create_rectangle (&rect);
|
||||
if (self->_opaqueRegion)
|
||||
cairo_region_subtract (transparent, self->_opaqueRegion);
|
||||
|
||||
self->_opaque = cairo_region_is_empty (transparent);
|
||||
|
||||
/* If we have transparent borders around the opaque region, then
|
||||
* we are okay with a bit larger tiles since they don't change
|
||||
* all that much and are generally small in width.
|
||||
*/
|
||||
if (!self->_opaque &&
|
||||
self->_opaqueRegion &&
|
||||
!cairo_region_is_empty (self->_opaqueRegion))
|
||||
max_size = TILE_EDGE_MAX_SIZE;
|
||||
else
|
||||
max_size = TILE_MAX_SIZE;
|
||||
|
||||
/* Track transparent children */
|
||||
tiler_init (&tiler, transparent);
|
||||
while (tiler_next (&tiler, &rect, max_size))
|
||||
{
|
||||
TileInfo *info;
|
||||
|
||||
g_array_set_size (ar, ar->len+1);
|
||||
|
||||
info = &g_array_index (ar, TileInfo, ar->len-1);
|
||||
info->tile = NULL;
|
||||
info->opaque = FALSE;
|
||||
info->cr_area = rect;
|
||||
info->area = toCGRect (&info->cr_area);
|
||||
}
|
||||
|
||||
/* Track opaque children */
|
||||
tiler_init (&tiler, self->_opaqueRegion);
|
||||
while (tiler_next (&tiler, &rect, TILE_MAX_SIZE))
|
||||
{
|
||||
TileInfo *info;
|
||||
|
||||
g_array_set_size (ar, ar->len+1);
|
||||
|
||||
info = &g_array_index (ar, TileInfo, ar->len-1);
|
||||
info->tile = NULL;
|
||||
info->opaque = TRUE;
|
||||
info->cr_area = rect;
|
||||
info->area = toCGRect (&info->cr_area);
|
||||
}
|
||||
|
||||
cairo_region_destroy (transparent);
|
||||
|
||||
[self _applyLayout:g_steal_pointer (&ar)];
|
||||
[super layoutSublayers];
|
||||
}
|
||||
|
||||
-(void)setFrame:(NSRect)frame
|
||||
{
|
||||
if (frame.size.width != self.bounds.size.width ||
|
||||
frame.size.height != self.bounds.size.height)
|
||||
{
|
||||
self->_layoutInvalid = TRUE;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
[super setFrame:frame];
|
||||
}
|
||||
|
||||
-(void)setOpaqueRegion:(const cairo_region_t *)opaqueRegion
|
||||
{
|
||||
g_clear_pointer (&self->_opaqueRegion, cairo_region_destroy);
|
||||
self->_opaqueRegion = cairo_region_copy (opaqueRegion);
|
||||
self->_layoutInvalid = TRUE;
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
-(void)swapBuffer:(GdkMacosBuffer *)buffer withDamage:(const cairo_region_t *)damage
|
||||
{
|
||||
IOSurfaceRef ioSurface = _gdk_macos_buffer_get_native (buffer);
|
||||
gboolean flipped = _gdk_macos_buffer_get_flipped (buffer);
|
||||
double scale = _gdk_macos_buffer_get_device_scale (buffer);
|
||||
double width = _gdk_macos_buffer_get_width (buffer) / scale;
|
||||
double height = _gdk_macos_buffer_get_height (buffer) / scale;
|
||||
|
||||
if (flipped != self->_isFlipped)
|
||||
{
|
||||
self->_isFlipped = flipped;
|
||||
self->_layoutInvalid = TRUE;
|
||||
}
|
||||
|
||||
if (self->_layoutInvalid)
|
||||
{
|
||||
self->_inSwapBuffer = TRUE;
|
||||
[self layoutSublayers];
|
||||
self->_inSwapBuffer = FALSE;
|
||||
}
|
||||
|
||||
if (self->_tiles == NULL)
|
||||
return;
|
||||
|
||||
for (guint i = 0; i < self->_tiles->len; i++)
|
||||
{
|
||||
const TileInfo *info = &g_array_index (self->_tiles, TileInfo, i);
|
||||
cairo_region_overlap_t overlap;
|
||||
CGRect area;
|
||||
|
||||
overlap = cairo_region_contains_rectangle (damage, &info->cr_area);
|
||||
if (overlap == CAIRO_REGION_OVERLAP_OUT)
|
||||
continue;
|
||||
|
||||
area.origin.x = info->area.origin.x / width;
|
||||
area.size.width = info->area.size.width / width;
|
||||
area.size.height = info->area.size.height / height;
|
||||
|
||||
if (flipped)
|
||||
area.origin.y = (height - info->area.origin.y - info->area.size.height) / height;
|
||||
else
|
||||
area.origin.y = info->area.origin.y / height;
|
||||
|
||||
[info->tile swapBuffer:ioSurface withRect:area];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,44 +0,0 @@
|
||||
/* GdkMacosLayer.h
|
||||
*
|
||||
* Copyright © 2022 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include <QuartzCore/QuartzCore.h>
|
||||
#include <IOSurface/IOSurface.h>
|
||||
|
||||
#include <cairo.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "gdkmacosbuffer-private.h"
|
||||
|
||||
#define GDK_IS_MACOS_LAYER(obj) ((obj) && [obj isKindOfClass:[GdkMacosLayer class]])
|
||||
|
||||
@interface GdkMacosLayer : CALayer
|
||||
{
|
||||
cairo_region_t *_opaqueRegion;
|
||||
GArray *_tiles;
|
||||
guint _opaque : 1;
|
||||
guint _layoutInvalid : 1;
|
||||
guint _inSwapBuffer : 1;
|
||||
guint _isFlipped : 1;
|
||||
};
|
||||
|
||||
-(void)setOpaqueRegion:(const cairo_region_t *)opaqueRegion;
|
||||
-(void)swapBuffer:(GdkMacosBuffer *)buffer withDamage:(const cairo_region_t *)damage;
|
||||
|
||||
@end
|
||||
@@ -1,100 +0,0 @@
|
||||
/* GdkMacosView.c
|
||||
*
|
||||
* Copyright 2022 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
|
||||
#import "GdkMacosLayer.h"
|
||||
#import "GdkMacosView.h"
|
||||
#import "GdkMacosWindow.h"
|
||||
|
||||
@implementation GdkMacosView
|
||||
|
||||
-(id)initWithFrame:(NSRect)frame
|
||||
{
|
||||
if ((self = [super initWithFrame:frame]))
|
||||
{
|
||||
GdkMacosLayer *layer = [GdkMacosLayer layer];
|
||||
|
||||
[self setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawNever];
|
||||
[self setLayer:layer];
|
||||
[self setWantsLayer:YES];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
-(BOOL)isFlipped
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(BOOL)acceptsFirstMouse
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(BOOL)mouseDownCanMoveWindow
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
-(void)mouseDown:(NSEvent *)nsevent
|
||||
{
|
||||
if ([(GdkMacosWindow *)[self window] needsMouseDownQuirk])
|
||||
/* We should only hit this when we are trying to click through
|
||||
* the shadow of a window into another window. Just request
|
||||
* that the application not activate this window on mouseUp.
|
||||
* See gdkmacosdisplay-translate.c for the other half of this.
|
||||
*/
|
||||
[NSApp preventWindowOrdering];
|
||||
else
|
||||
[super mouseDown:nsevent];
|
||||
}
|
||||
|
||||
-(void)setFrame:(NSRect)rect
|
||||
{
|
||||
[super setFrame:rect];
|
||||
self->_nextFrameDirty = TRUE;
|
||||
}
|
||||
|
||||
-(void)setOpaqueRegion:(const cairo_region_t *)opaqueRegion
|
||||
{
|
||||
[(GdkMacosLayer *)[self layer] setOpaqueRegion:opaqueRegion];
|
||||
}
|
||||
|
||||
-(BOOL)wantsUpdateLayer
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(void)swapBuffer:(GdkMacosBuffer *)buffer withDamage:(const cairo_region_t *)damage
|
||||
{
|
||||
if (self->_nextFrameDirty)
|
||||
{
|
||||
self->_nextFrameDirty = FALSE;
|
||||
[[self layer] setFrame:[self frame]];
|
||||
}
|
||||
|
||||
[(GdkMacosLayer *)[self layer] swapBuffer:buffer withDamage:damage];
|
||||
}
|
||||
|
||||
@end
|
||||
+119
-110
@@ -24,7 +24,8 @@
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
#import "GdkMacosBaseView.h"
|
||||
#import "GdkMacosView.h"
|
||||
#import "GdkMacosCairoView.h"
|
||||
#import "GdkMacosGLView.h"
|
||||
#import "GdkMacosWindow.h"
|
||||
|
||||
#include "gdkmacosclipboard-private.h"
|
||||
@@ -149,7 +150,8 @@ typedef NSString *CALayerContentsGravity;
|
||||
_gdk_macos_display_break_all_grabs (GDK_MACOS_DISPLAY (display), time);
|
||||
|
||||
/* Reset gravity */
|
||||
[[[self contentView] layer] setContentsGravity:kCAGravityBottomLeft];
|
||||
if (GDK_IS_MACOS_GL_VIEW ([self contentView]))
|
||||
[[[self contentView] layer] setContentsGravity:kCAGravityBottomLeft];
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -201,20 +203,69 @@ typedef NSString *CALayerContentsGravity;
|
||||
}
|
||||
}
|
||||
|
||||
-(void)setFrame:(NSRect)frame display:(BOOL)display
|
||||
-(void)windowDidUnmaximize
|
||||
{
|
||||
NSWindowStyleMask style_mask = [self styleMask];
|
||||
|
||||
gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface), GDK_TOPLEVEL_STATE_MAXIMIZED, 0);
|
||||
|
||||
/* If we are using CSD, then we transitioned to an opaque
|
||||
* window while we were maximized. Now we need to drop that
|
||||
* as we are leaving maximized state.
|
||||
*/
|
||||
if ((style_mask & NSWindowStyleMaskTitled) == 0 && [self isOpaque])
|
||||
[self setOpaque:NO];
|
||||
}
|
||||
|
||||
-(void)windowDidMove:(NSNotification *)aNotification
|
||||
{
|
||||
NSRect contentRect = [self contentRectForFrameRect:frame];
|
||||
GdkSurface *surface = GDK_SURFACE (gdk_surface);
|
||||
gboolean maximized = (surface->state & GDK_TOPLEVEL_STATE_MAXIMIZED) != 0;
|
||||
|
||||
if (maximized && !inMaximizeTransition && !NSEqualRects (lastMaximizedFrame, frame))
|
||||
{
|
||||
gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_MAXIMIZED, 0);
|
||||
_gdk_surface_update_size (surface);
|
||||
}
|
||||
/* In case the window is changed when maximized remove the maximized state */
|
||||
if (maximized && !inMaximizeTransition && !NSEqualRects (lastMaximizedFrame, [self frame]))
|
||||
[self windowDidUnmaximize];
|
||||
|
||||
[super setFrame:frame display:display];
|
||||
[[self contentView] setFrame:NSMakeRect (0, 0, contentRect.size.width, contentRect.size.height)];
|
||||
_gdk_macos_surface_update_position (gdk_surface);
|
||||
_gdk_macos_surface_reposition_children (gdk_surface);
|
||||
|
||||
[self checkSendEnterNotify];
|
||||
}
|
||||
|
||||
-(void)windowDidResize:(NSNotification *)aNotification
|
||||
{
|
||||
NSRect content_rect;
|
||||
GdkSurface *surface;
|
||||
GdkDisplay *display;
|
||||
gboolean maximized;
|
||||
|
||||
surface = GDK_SURFACE (gdk_surface);
|
||||
display = gdk_surface_get_display (surface);
|
||||
|
||||
content_rect = [self contentRectForFrameRect:[self frame]];
|
||||
maximized = (surface->state & GDK_TOPLEVEL_STATE_MAXIMIZED) != 0;
|
||||
|
||||
/* see same in windowDidMove */
|
||||
if (maximized && !inMaximizeTransition && !NSEqualRects (lastMaximizedFrame, [self frame]))
|
||||
[self windowDidUnmaximize];
|
||||
|
||||
surface->width = content_rect.size.width;
|
||||
surface->height = content_rect.size.height;
|
||||
|
||||
/* Certain resize operations (e.g. going fullscreen), also move the
|
||||
* origin of the window.
|
||||
*/
|
||||
_gdk_macos_surface_update_position (GDK_MACOS_SURFACE (surface));
|
||||
|
||||
[[self contentView] setFrame:NSMakeRect (0, 0, surface->width, surface->height)];
|
||||
|
||||
_gdk_surface_update_size (surface);
|
||||
|
||||
gdk_surface_request_layout (surface);
|
||||
|
||||
_gdk_macos_surface_reposition_children (gdk_surface);
|
||||
|
||||
[self checkSendEnterNotify];
|
||||
}
|
||||
|
||||
-(id)initWithContentRect:(NSRect)contentRect
|
||||
@@ -223,7 +274,7 @@ typedef NSString *CALayerContentsGravity;
|
||||
defer:(BOOL)flag
|
||||
screen:(NSScreen *)screen
|
||||
{
|
||||
GdkMacosView *view;
|
||||
GdkMacosCairoView *view;
|
||||
|
||||
self = [super initWithContentRect:contentRect
|
||||
styleMask:styleMask
|
||||
@@ -234,9 +285,8 @@ typedef NSString *CALayerContentsGravity;
|
||||
[self setAcceptsMouseMovedEvents:YES];
|
||||
[self setDelegate:(id<NSWindowDelegate>)self];
|
||||
[self setReleasedWhenClosed:YES];
|
||||
[self setPreservesContentDuringLiveResize:NO];
|
||||
|
||||
view = [[GdkMacosView alloc] initWithFrame:contentRect];
|
||||
view = [[GdkMacosCairoView alloc] initWithFrame:contentRect];
|
||||
[self setContentView:view];
|
||||
[view release];
|
||||
|
||||
@@ -253,8 +303,7 @@ typedef NSString *CALayerContentsGravity;
|
||||
|
||||
-(BOOL)canBecomeKeyWindow
|
||||
{
|
||||
return GDK_IS_TOPLEVEL (gdk_surface) ||
|
||||
(GDK_IS_POPUP (gdk_surface) && GDK_SURFACE (gdk_surface)->input_region != NULL);
|
||||
return GDK_IS_TOPLEVEL (gdk_surface);
|
||||
}
|
||||
|
||||
-(void)showAndMakeKey:(BOOL)makeKey
|
||||
@@ -262,12 +311,9 @@ typedef NSString *CALayerContentsGravity;
|
||||
inShowOrHide = YES;
|
||||
|
||||
if (makeKey && [self canBecomeKeyWindow])
|
||||
[self makeKeyAndOrderFront:self];
|
||||
[self makeKeyAndOrderFront:nil];
|
||||
else
|
||||
[self orderFront:self];
|
||||
|
||||
if (makeKey && [self canBecomeMainWindow])
|
||||
[self makeMainWindow];
|
||||
[self orderFront:nil];
|
||||
|
||||
inShowOrHide = NO;
|
||||
|
||||
@@ -365,31 +411,12 @@ typedef NSString *CALayerContentsGravity;
|
||||
windowFrame.origin.x = new_origin.x;
|
||||
windowFrame.origin.y = new_origin.y;
|
||||
|
||||
[self setFrame:NSMakeRect (new_origin.x, new_origin.y,
|
||||
window_gdk.width, window_gdk.height)
|
||||
display:YES];
|
||||
/* And now apply the frame to the window */
|
||||
[self setFrameOrigin:NSMakePoint(new_origin.x, new_origin.y)];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(void)windowDidMove:(NSNotification *)notification
|
||||
{
|
||||
_gdk_macos_surface_configure ([self gdkSurface]);
|
||||
}
|
||||
|
||||
-(void)windowDidResize:(NSNotification *)notification
|
||||
{
|
||||
_gdk_macos_surface_configure (gdk_surface);
|
||||
|
||||
/* If we're using server-side decorations, this notification is coming
|
||||
* in from a display-side change. We need to request a layout in
|
||||
* addition to the configure event.
|
||||
*/
|
||||
if (GDK_IS_MACOS_TOPLEVEL_SURFACE (gdk_surface) &&
|
||||
GDK_MACOS_TOPLEVEL_SURFACE (gdk_surface)->decorated)
|
||||
gdk_surface_request_layout (GDK_SURFACE (gdk_surface));
|
||||
}
|
||||
|
||||
/* Used by gdkmacosdisplay-translate.c to decide if our sendEvent() handler
|
||||
* above will see the event or if it will be subjected to standard processing
|
||||
* by GDK.
|
||||
@@ -401,7 +428,6 @@ typedef NSString *CALayerContentsGravity;
|
||||
|
||||
-(void)beginManualMove
|
||||
{
|
||||
gboolean maximized = GDK_SURFACE (gdk_surface)->state & GDK_TOPLEVEL_STATE_MAXIMIZED;
|
||||
NSPoint initialMoveLocation;
|
||||
GdkPoint point;
|
||||
GdkMonitor *monitor;
|
||||
@@ -420,13 +446,6 @@ typedef NSString *CALayerContentsGravity;
|
||||
|
||||
initialMoveLocation = [NSEvent mouseLocation];
|
||||
|
||||
if (maximized)
|
||||
[self setFrame:NSMakeRect (initialMoveLocation.x - (int)lastUnmaximizedFrame.size.width/2,
|
||||
initialMoveLocation.y,
|
||||
lastUnmaximizedFrame.size.width,
|
||||
lastUnmaximizedFrame.size.height)
|
||||
display:YES];
|
||||
|
||||
_gdk_macos_display_from_display_coords ([self gdkDisplay],
|
||||
initialMoveLocation.x,
|
||||
initialMoveLocation.y,
|
||||
@@ -518,7 +537,15 @@ typedef NSString *CALayerContentsGravity;
|
||||
new_frame.size.height = min_size.height;
|
||||
}
|
||||
|
||||
_gdk_macos_surface_user_resize ([self gdkSurface], new_frame);
|
||||
/* We could also apply aspect ratio:
|
||||
new_frame.size.height = new_frame.size.width / [self aspectRatio].width * [self aspectRatio].height;
|
||||
*/
|
||||
|
||||
[self setFrame:new_frame display:YES];
|
||||
|
||||
/* Let the resizing be handled by GTK. */
|
||||
if (g_main_context_pending (NULL))
|
||||
g_main_context_iteration (NULL, FALSE);
|
||||
|
||||
inTrackManualResize = NO;
|
||||
|
||||
@@ -527,46 +554,49 @@ typedef NSString *CALayerContentsGravity;
|
||||
|
||||
-(void)beginManualResize:(GdkSurfaceEdge)edge
|
||||
{
|
||||
CALayerContentsGravity gravity = kCAGravityBottomLeft;
|
||||
|
||||
if (inMove || inManualMove || inManualResize)
|
||||
return;
|
||||
|
||||
inManualResize = YES;
|
||||
resizeEdge = edge;
|
||||
|
||||
switch (edge)
|
||||
if (GDK_IS_MACOS_GL_VIEW ([self contentView]))
|
||||
{
|
||||
default:
|
||||
case GDK_SURFACE_EDGE_NORTH:
|
||||
gravity = kCAGravityTopLeft;
|
||||
break;
|
||||
CALayerContentsGravity gravity = kCAGravityBottomLeft;
|
||||
|
||||
case GDK_SURFACE_EDGE_NORTH_WEST:
|
||||
gravity = kCAGravityTopRight;
|
||||
break;
|
||||
switch (edge)
|
||||
{
|
||||
default:
|
||||
case GDK_SURFACE_EDGE_NORTH:
|
||||
gravity = kCAGravityTopLeft;
|
||||
break;
|
||||
|
||||
case GDK_SURFACE_EDGE_SOUTH_WEST:
|
||||
case GDK_SURFACE_EDGE_WEST:
|
||||
gravity = kCAGravityBottomRight;
|
||||
break;
|
||||
case GDK_SURFACE_EDGE_NORTH_WEST:
|
||||
gravity = kCAGravityTopRight;
|
||||
break;
|
||||
|
||||
case GDK_SURFACE_EDGE_SOUTH:
|
||||
case GDK_SURFACE_EDGE_SOUTH_EAST:
|
||||
gravity = kCAGravityBottomLeft;
|
||||
break;
|
||||
case GDK_SURFACE_EDGE_SOUTH_WEST:
|
||||
case GDK_SURFACE_EDGE_WEST:
|
||||
gravity = kCAGravityBottomRight;
|
||||
break;
|
||||
|
||||
case GDK_SURFACE_EDGE_EAST:
|
||||
gravity = kCAGravityBottomLeft;
|
||||
break;
|
||||
case GDK_SURFACE_EDGE_SOUTH:
|
||||
case GDK_SURFACE_EDGE_SOUTH_EAST:
|
||||
gravity = kCAGravityBottomLeft;
|
||||
break;
|
||||
|
||||
case GDK_SURFACE_EDGE_NORTH_EAST:
|
||||
gravity = kCAGravityTopLeft;
|
||||
break;
|
||||
case GDK_SURFACE_EDGE_EAST:
|
||||
gravity = kCAGravityBottomLeft;
|
||||
break;
|
||||
|
||||
case GDK_SURFACE_EDGE_NORTH_EAST:
|
||||
gravity = kCAGravityTopLeft;
|
||||
break;
|
||||
}
|
||||
|
||||
[[[self contentView] layer] setContentsGravity:gravity];
|
||||
}
|
||||
|
||||
[[[self contentView] layer] setContentsGravity:gravity];
|
||||
|
||||
initialResizeFrame = [self frame];
|
||||
initialResizeLocation = convert_nspoint_to_screen (self, [self mouseLocationOutsideOfEventStream]);
|
||||
}
|
||||
@@ -680,12 +710,7 @@ typedef NSString *CALayerContentsGravity;
|
||||
is_opaque = (([self styleMask] & NSWindowStyleMaskTitled) != 0);
|
||||
|
||||
if (was_fullscreen != is_fullscreen)
|
||||
{
|
||||
if (was_fullscreen)
|
||||
[self setFrame:lastUnfullscreenFrame display:NO];
|
||||
|
||||
_gdk_macos_surface_update_fullscreen_state (gdk_surface);
|
||||
}
|
||||
_gdk_macos_surface_update_fullscreen_state (gdk_surface);
|
||||
|
||||
if (was_opaque != is_opaque)
|
||||
{
|
||||
@@ -735,6 +760,7 @@ typedef NSString *CALayerContentsGravity;
|
||||
if (state & GDK_TOPLEVEL_STATE_MAXIMIZED)
|
||||
{
|
||||
lastMaximizedFrame = newFrame;
|
||||
[self windowDidUnmaximize];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -749,7 +775,16 @@ typedef NSString *CALayerContentsGravity;
|
||||
|
||||
-(void)windowDidEndLiveResize:(NSNotification *)aNotification
|
||||
{
|
||||
gboolean maximized = GDK_SURFACE (gdk_surface)->state & GDK_TOPLEVEL_STATE_MAXIMIZED;
|
||||
|
||||
inMaximizeTransition = NO;
|
||||
|
||||
/* Even if this is CSD, we want to be opaque while maximized
|
||||
* to speed up compositing by allowing the display server to
|
||||
* avoid costly blends.
|
||||
*/
|
||||
if (maximized)
|
||||
[self setOpaque:YES];
|
||||
}
|
||||
|
||||
-(NSSize)window:(NSWindow *)window willUseFullScreenContentSize:(NSSize)proposedSize
|
||||
@@ -762,27 +797,12 @@ typedef NSString *CALayerContentsGravity;
|
||||
lastUnfullscreenFrame = [self frame];
|
||||
}
|
||||
|
||||
-(void)windowDidEnterFullScreen:(NSNotification *)aNotification
|
||||
{
|
||||
initialPositionKnown = NO;
|
||||
[self checkSendEnterNotify];
|
||||
}
|
||||
|
||||
-(void)windowWillExitFullScreen:(NSNotification *)aNotification
|
||||
{
|
||||
[self setFrame:lastUnfullscreenFrame display:YES];
|
||||
}
|
||||
|
||||
-(void)windowDidExitFullScreen:(NSNotification *)aNotification
|
||||
{
|
||||
initialPositionKnown = NO;
|
||||
[self checkSendEnterNotify];
|
||||
}
|
||||
|
||||
-(void)windowDidFailToEnterFullScreen:(NSNotification *)aNotification
|
||||
{
|
||||
}
|
||||
|
||||
-(void)windowDidFailToExitFullScreen:(NSNotification *)aNotification
|
||||
{
|
||||
}
|
||||
|
||||
@@ -825,15 +845,4 @@ typedef NSString *CALayerContentsGravity;
|
||||
return NO;
|
||||
}
|
||||
|
||||
-(void)swapBuffer:(GdkMacosBuffer *)buffer withDamage:(const cairo_region_t *)damage
|
||||
{
|
||||
[(GdkMacosView *)[self contentView] swapBuffer:buffer withDamage:damage];
|
||||
}
|
||||
|
||||
-(BOOL)needsMouseDownQuirk
|
||||
{
|
||||
return GDK_IS_MACOS_TOPLEVEL_SURFACE (gdk_surface) &&
|
||||
!GDK_MACOS_TOPLEVEL_SURFACE (gdk_surface)->decorated;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -21,11 +21,9 @@
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <IOSurface/IOSurface.h>
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
#include "gdkmacosbuffer-private.h"
|
||||
#include "gdkmacosdisplay.h"
|
||||
#include "gdkmacossurface.h"
|
||||
#include "edgesnapping.h"
|
||||
@@ -68,7 +66,5 @@
|
||||
-(BOOL)trackManualMove;
|
||||
-(BOOL)trackManualResize;
|
||||
-(void)setDecorated:(BOOL)decorated;
|
||||
-(void)swapBuffer:(GdkMacosBuffer *)buffer withDamage:(const cairo_region_t *)damage;
|
||||
-(BOOL)needsMouseDownQuirk;
|
||||
|
||||
@end
|
||||
|
||||
@@ -26,10 +26,7 @@
|
||||
|
||||
#include "gdkdisplaylinksource.h"
|
||||
|
||||
#include "gdkdebug.h"
|
||||
#include "gdkmacoseventsource-private.h"
|
||||
#include "gdkmacosmonitor-private.h"
|
||||
#include "gdk-private.h"
|
||||
|
||||
static gint64 host_to_frame_clock_time (gint64 val);
|
||||
|
||||
@@ -67,7 +64,7 @@ gdk_display_link_source_dispatch (GSource *source,
|
||||
|
||||
impl->needs_dispatch = FALSE;
|
||||
|
||||
if (!impl->paused && callback != NULL)
|
||||
if (callback != NULL)
|
||||
ret = callback (user_data);
|
||||
|
||||
return ret;
|
||||
@@ -78,9 +75,7 @@ gdk_display_link_source_finalize (GSource *source)
|
||||
{
|
||||
GdkDisplayLinkSource *impl = (GdkDisplayLinkSource *)source;
|
||||
|
||||
if (!impl->paused)
|
||||
CVDisplayLinkStop (impl->display_link);
|
||||
|
||||
CVDisplayLinkStop (impl->display_link);
|
||||
CVDisplayLinkRelease (impl->display_link);
|
||||
}
|
||||
|
||||
@@ -94,18 +89,12 @@ static GSourceFuncs gdk_display_link_source_funcs = {
|
||||
void
|
||||
gdk_display_link_source_pause (GdkDisplayLinkSource *source)
|
||||
{
|
||||
g_return_if_fail (source->paused == FALSE);
|
||||
|
||||
source->paused = TRUE;
|
||||
CVDisplayLinkStop (source->display_link);
|
||||
}
|
||||
|
||||
void
|
||||
gdk_display_link_source_unpause (GdkDisplayLinkSource *source)
|
||||
{
|
||||
g_return_if_fail (source->paused == TRUE);
|
||||
|
||||
source->paused = FALSE;
|
||||
CVDisplayLinkStart (source->display_link);
|
||||
}
|
||||
|
||||
@@ -157,7 +146,6 @@ gdk_display_link_source_frame_cb (CVDisplayLinkRef display_link,
|
||||
|
||||
/**
|
||||
* gdk_display_link_source_new:
|
||||
* @display_id: the identifier of the monitor
|
||||
*
|
||||
* Creates a new `GSource` that will activate the dispatch function upon
|
||||
* notification from a CVDisplayLink that a new frame should be drawn.
|
||||
@@ -170,61 +158,41 @@ gdk_display_link_source_frame_cb (CVDisplayLinkRef display_link,
|
||||
* Returns: (transfer full): A newly created `GSource`
|
||||
*/
|
||||
GSource *
|
||||
gdk_display_link_source_new (CGDirectDisplayID display_id,
|
||||
CGDisplayModeRef mode)
|
||||
gdk_display_link_source_new (void)
|
||||
{
|
||||
GdkDisplayLinkSource *impl;
|
||||
GSource *source;
|
||||
char *name;
|
||||
CVReturn ret;
|
||||
double period;
|
||||
|
||||
source = g_source_new (&gdk_display_link_source_funcs, sizeof *impl);
|
||||
impl = (GdkDisplayLinkSource *)source;
|
||||
impl->display_id = display_id;
|
||||
impl->paused = TRUE;
|
||||
|
||||
/* Create DisplayLink for timing information for the display in
|
||||
* question so that we can produce graphics for that display at whatever
|
||||
* rate it can provide.
|
||||
/*
|
||||
* Create our link based on currently connected displays.
|
||||
* If there are multiple displays, this will be something that tries
|
||||
* to work for all of them. In the future, we may want to explore multiple
|
||||
* links based on the connected displays.
|
||||
*/
|
||||
if (CVDisplayLinkCreateWithCGDisplay (display_id, &impl->display_link) != kCVReturnSuccess)
|
||||
ret = CVDisplayLinkCreateWithActiveCGDisplays (&impl->display_link);
|
||||
if (ret != kCVReturnSuccess)
|
||||
{
|
||||
g_warning ("Failed to initialize CVDisplayLink!");
|
||||
goto failure;
|
||||
return source;
|
||||
}
|
||||
|
||||
impl->refresh_rate = CGDisplayModeGetRefreshRate (mode) * 1000.0;
|
||||
/*
|
||||
* Determine our nominal period between frames.
|
||||
*/
|
||||
period = CVDisplayLinkGetActualOutputVideoRefreshPeriod (impl->display_link);
|
||||
if (period == 0.0)
|
||||
period = 1.0 / 60.0;
|
||||
impl->refresh_interval = period * 1000000L;
|
||||
impl->refresh_rate = 1.0 / period * 1000L;
|
||||
|
||||
if (impl->refresh_rate == 0)
|
||||
{
|
||||
const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod (impl->display_link);
|
||||
if (!(time.flags & kCVTimeIsIndefinite))
|
||||
impl->refresh_rate = (double)time.timeScale / (double)time.timeValue * 1000.0;
|
||||
}
|
||||
|
||||
if (impl->refresh_rate != 0)
|
||||
{
|
||||
impl->refresh_interval = 1000000.0 / (double)impl->refresh_rate * 1000.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
double period = CVDisplayLinkGetActualOutputVideoRefreshPeriod (impl->display_link);
|
||||
|
||||
if (period == 0.0)
|
||||
period = 1.0 / 60.0;
|
||||
|
||||
impl->refresh_rate = 1.0 / period * 1000L;
|
||||
impl->refresh_interval = period * 1000000L;
|
||||
}
|
||||
|
||||
name = _gdk_macos_monitor_get_connector_name (display_id);
|
||||
GDK_NOTE (MISC,
|
||||
g_message ("Monitor \"%s\" discovered with Refresh Rate %d and Interval %"G_GINT64_FORMAT,
|
||||
name ? name : "unknown",
|
||||
impl->refresh_rate,
|
||||
impl->refresh_interval));
|
||||
g_free (name);
|
||||
|
||||
/* Wire up our callback to be executed within the high-priority thread. */
|
||||
/*
|
||||
* Wire up our callback to be executed within the high-priority thread.
|
||||
*/
|
||||
CVDisplayLinkSetOutputCallback (impl->display_link,
|
||||
gdk_display_link_source_frame_cb,
|
||||
source);
|
||||
@@ -232,10 +200,6 @@ gdk_display_link_source_new (CGDirectDisplayID display_id,
|
||||
g_source_set_static_name (source, "[gdk] quartz frame clock");
|
||||
|
||||
return source;
|
||||
|
||||
failure:
|
||||
g_source_unref (source);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gint64
|
||||
|
||||
@@ -30,20 +30,17 @@ G_BEGIN_DECLS
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GSource source;
|
||||
GSource source;
|
||||
|
||||
CGDirectDisplayID display_id;
|
||||
CVDisplayLinkRef display_link;
|
||||
gint64 refresh_interval;
|
||||
guint refresh_rate;
|
||||
guint paused : 1;
|
||||
CVDisplayLinkRef display_link;
|
||||
gint64 refresh_interval;
|
||||
guint refresh_rate;
|
||||
|
||||
volatile gint64 presentation_time;
|
||||
volatile guint needs_dispatch;
|
||||
volatile gint64 presentation_time;
|
||||
volatile guint needs_dispatch;
|
||||
} GdkDisplayLinkSource;
|
||||
|
||||
GSource *gdk_display_link_source_new (CGDirectDisplayID display_id,
|
||||
CGDisplayModeRef mode);
|
||||
GSource *gdk_display_link_source_new (void);
|
||||
void gdk_display_link_source_pause (GdkDisplayLinkSource *source);
|
||||
void gdk_display_link_source_unpause (GdkDisplayLinkSource *source);
|
||||
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2021 Red Hat, Inc.
|
||||
*
|
||||
* 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.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#ifndef __GDK_MACOS_BUFFER_PRIVATE_H__
|
||||
#define __GDK_MACOS_BUFFER_PRIVATE_H__
|
||||
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <IOSurface/IOSurface.h>
|
||||
|
||||
#include <cairo.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDK_TYPE_MACOS_BUFFER (gdk_macos_buffer_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (GdkMacosBuffer, gdk_macos_buffer, GDK, MACOS_BUFFER, GObject)
|
||||
|
||||
GdkMacosBuffer *_gdk_macos_buffer_new (int width,
|
||||
int height,
|
||||
double device_scale,
|
||||
int bytes_per_element,
|
||||
int bits_per_pixel);
|
||||
IOSurfaceRef _gdk_macos_buffer_get_native (GdkMacosBuffer *self);
|
||||
void _gdk_macos_buffer_lock (GdkMacosBuffer *self);
|
||||
void _gdk_macos_buffer_unlock (GdkMacosBuffer *self);
|
||||
void _gdk_macos_buffer_read_lock (GdkMacosBuffer *self);
|
||||
void _gdk_macos_buffer_read_unlock (GdkMacosBuffer *self);
|
||||
guint _gdk_macos_buffer_get_width (GdkMacosBuffer *self);
|
||||
guint _gdk_macos_buffer_get_height (GdkMacosBuffer *self);
|
||||
guint _gdk_macos_buffer_get_stride (GdkMacosBuffer *self);
|
||||
double _gdk_macos_buffer_get_device_scale (GdkMacosBuffer *self);
|
||||
const cairo_region_t *_gdk_macos_buffer_get_damage (GdkMacosBuffer *self);
|
||||
void _gdk_macos_buffer_set_damage (GdkMacosBuffer *self,
|
||||
cairo_region_t *damage);
|
||||
gpointer _gdk_macos_buffer_get_data (GdkMacosBuffer *self);
|
||||
gboolean _gdk_macos_buffer_get_flipped (GdkMacosBuffer *self);
|
||||
void _gdk_macos_buffer_set_flipped (GdkMacosBuffer *self,
|
||||
gboolean flipped);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_MACOS_BUFFER_PRIVATE_H__ */
|
||||
@@ -1,310 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2021 Red Hat, Inc.
|
||||
*
|
||||
* 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.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <IOSurface/IOSurface.h>
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <OpenGL/CGLIOSurface.h>
|
||||
#include <QuartzCore/QuartzCore.h>
|
||||
|
||||
#include "gdkmacosbuffer-private.h"
|
||||
|
||||
struct _GdkMacosBuffer
|
||||
{
|
||||
GObject parent_instance;
|
||||
cairo_region_t *damage;
|
||||
IOSurfaceRef surface;
|
||||
int lock_count;
|
||||
guint bytes_per_element;
|
||||
guint bits_per_pixel;
|
||||
guint width;
|
||||
guint height;
|
||||
guint stride;
|
||||
double device_scale;
|
||||
guint flipped : 1;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GdkMacosBuffer, gdk_macos_buffer, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
gdk_macos_buffer_dispose (GObject *object)
|
||||
{
|
||||
GdkMacosBuffer *self = (GdkMacosBuffer *)object;
|
||||
|
||||
if (self->lock_count != 0)
|
||||
g_critical ("Attempt to dispose %s while lock is held",
|
||||
G_OBJECT_TYPE_NAME (self));
|
||||
|
||||
/* We could potentially force the unload of our surface here with
|
||||
* IOSurfaceSetPurgeable (self->surface, kIOSurfacePurgeableEmpty, NULL)
|
||||
* but that would cause it to empty when the layers may still be attached
|
||||
* to it. Better to just let it get GC'd by the system after they have
|
||||
* moved on to a new buffer.
|
||||
*/
|
||||
g_clear_pointer (&self->surface, CFRelease);
|
||||
g_clear_pointer (&self->damage, cairo_region_destroy);
|
||||
|
||||
G_OBJECT_CLASS (gdk_macos_buffer_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_macos_buffer_class_init (GdkMacosBufferClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = gdk_macos_buffer_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_macos_buffer_init (GdkMacosBuffer *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
add_int (CFMutableDictionaryRef dict,
|
||||
const CFStringRef key,
|
||||
int value)
|
||||
{
|
||||
CFNumberRef number = CFNumberCreate (NULL, kCFNumberIntType, &value);
|
||||
CFDictionaryAddValue (dict, key, number);
|
||||
CFRelease (number);
|
||||
}
|
||||
|
||||
static IOSurfaceRef
|
||||
create_surface (int width,
|
||||
int height,
|
||||
int bytes_per_element,
|
||||
guint *stride)
|
||||
{
|
||||
CFMutableDictionaryRef props;
|
||||
IOSurfaceRef ret;
|
||||
size_t bytes_per_row;
|
||||
size_t total_bytes;
|
||||
|
||||
props = CFDictionaryCreateMutable (kCFAllocatorDefault,
|
||||
16,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
if (props == NULL)
|
||||
return NULL;
|
||||
|
||||
bytes_per_row = IOSurfaceAlignProperty (kIOSurfaceBytesPerRow, width * bytes_per_element);
|
||||
total_bytes = IOSurfaceAlignProperty (kIOSurfaceAllocSize, height * bytes_per_row);
|
||||
|
||||
add_int (props, kIOSurfaceAllocSize, total_bytes);
|
||||
add_int (props, kIOSurfaceBytesPerElement, bytes_per_element);
|
||||
add_int (props, kIOSurfaceBytesPerRow, bytes_per_row);
|
||||
add_int (props, kIOSurfaceHeight, height);
|
||||
add_int (props, kIOSurfacePixelFormat, (int)'BGRA');
|
||||
add_int (props, kIOSurfaceWidth, width);
|
||||
|
||||
ret = IOSurfaceCreate (props);
|
||||
|
||||
CFRelease (props);
|
||||
|
||||
*stride = bytes_per_row;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
GdkMacosBuffer *
|
||||
_gdk_macos_buffer_new (int width,
|
||||
int height,
|
||||
double device_scale,
|
||||
int bytes_per_element,
|
||||
int bits_per_pixel)
|
||||
{
|
||||
GdkMacosBuffer *self;
|
||||
|
||||
g_return_val_if_fail (width > 0, NULL);
|
||||
g_return_val_if_fail (height > 0, NULL);
|
||||
|
||||
self = g_object_new (GDK_TYPE_MACOS_BUFFER, NULL);
|
||||
self->bytes_per_element = bytes_per_element;
|
||||
self->bits_per_pixel = bits_per_pixel;
|
||||
self->surface = create_surface (width, height, bytes_per_element, &self->stride);
|
||||
self->width = width;
|
||||
self->height = height;
|
||||
self->device_scale = device_scale;
|
||||
self->lock_count = 0;
|
||||
|
||||
if (self->surface == NULL)
|
||||
g_clear_object (&self);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
IOSurfaceRef
|
||||
_gdk_macos_buffer_get_native (GdkMacosBuffer *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_MACOS_BUFFER (self), NULL);
|
||||
|
||||
return self->surface;
|
||||
}
|
||||
|
||||
/**
|
||||
* _gdk_macos_buffer_lock:
|
||||
*
|
||||
* This function matches the IOSurfaceLock() name but what it really
|
||||
* does is page the buffer back for the CPU to access from VRAM.
|
||||
*
|
||||
* Generally we don't want to do that, but we do need to in some
|
||||
* cases such as when we are rendering with Cairo. There might
|
||||
* be an opportunity later to avoid that, but since we are using
|
||||
* GL pretty much everywhere already, we don't try.
|
||||
*/
|
||||
void
|
||||
_gdk_macos_buffer_lock (GdkMacosBuffer *self)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_MACOS_BUFFER (self));
|
||||
g_return_if_fail (self->lock_count == 0);
|
||||
|
||||
self->lock_count++;
|
||||
|
||||
IOSurfaceLock (self->surface, 0, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_buffer_unlock (GdkMacosBuffer *self)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_MACOS_BUFFER (self));
|
||||
g_return_if_fail (self->lock_count == 1);
|
||||
|
||||
self->lock_count--;
|
||||
|
||||
IOSurfaceUnlock (self->surface, 0, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* _gdk_macos_buffer_lock_readonly:
|
||||
*
|
||||
* Like _gdk_macos_buffer_lock() but uses the read-only flag to
|
||||
* indicate we are not interested in retrieving the updates from
|
||||
* the GPU before modifying the CPU-side cache.
|
||||
*
|
||||
* Must be used with _gdk_macos_buffer_unlock_readonly().
|
||||
*/
|
||||
void
|
||||
_gdk_macos_buffer_read_lock (GdkMacosBuffer *self)
|
||||
{
|
||||
kern_return_t ret;
|
||||
|
||||
g_return_if_fail (GDK_IS_MACOS_BUFFER (self));
|
||||
g_return_if_fail (self->lock_count == 0);
|
||||
|
||||
self->lock_count++;
|
||||
|
||||
ret = IOSurfaceLock (self->surface, kIOSurfaceLockReadOnly, NULL);
|
||||
|
||||
g_return_if_fail (ret == KERN_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_buffer_read_unlock (GdkMacosBuffer *self)
|
||||
{
|
||||
kern_return_t ret;
|
||||
|
||||
g_return_if_fail (GDK_IS_MACOS_BUFFER (self));
|
||||
g_return_if_fail (self->lock_count == 1);
|
||||
|
||||
self->lock_count--;
|
||||
|
||||
ret = IOSurfaceUnlock (self->surface, kIOSurfaceLockReadOnly, NULL);
|
||||
|
||||
g_return_if_fail (ret == KERN_SUCCESS);
|
||||
}
|
||||
|
||||
guint
|
||||
_gdk_macos_buffer_get_width (GdkMacosBuffer *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_MACOS_BUFFER (self), 0);
|
||||
|
||||
return self->width;
|
||||
}
|
||||
|
||||
guint
|
||||
_gdk_macos_buffer_get_height (GdkMacosBuffer *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_MACOS_BUFFER (self), 0);
|
||||
|
||||
return self->height;
|
||||
}
|
||||
|
||||
guint
|
||||
_gdk_macos_buffer_get_stride (GdkMacosBuffer *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_MACOS_BUFFER (self), 0);
|
||||
|
||||
return self->stride;
|
||||
}
|
||||
|
||||
double
|
||||
_gdk_macos_buffer_get_device_scale (GdkMacosBuffer *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_MACOS_BUFFER (self), 1.0);
|
||||
|
||||
return self->device_scale;
|
||||
}
|
||||
|
||||
const cairo_region_t *
|
||||
_gdk_macos_buffer_get_damage (GdkMacosBuffer *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_MACOS_BUFFER (self), NULL);
|
||||
|
||||
return self->damage;
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_buffer_set_damage (GdkMacosBuffer *self,
|
||||
cairo_region_t *damage)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_MACOS_BUFFER (self));
|
||||
|
||||
if (damage == self->damage)
|
||||
return;
|
||||
|
||||
g_clear_pointer (&self->damage, cairo_region_destroy);
|
||||
self->damage = cairo_region_copy (damage);
|
||||
}
|
||||
|
||||
gpointer
|
||||
_gdk_macos_buffer_get_data (GdkMacosBuffer *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_MACOS_BUFFER (self), NULL);
|
||||
|
||||
return IOSurfaceGetBaseAddress (self->surface);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gdk_macos_buffer_get_flipped (GdkMacosBuffer *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_MACOS_BUFFER (self), FALSE);
|
||||
|
||||
return self->flipped;
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_buffer_set_flipped (GdkMacosBuffer *self,
|
||||
gboolean flipped)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_MACOS_BUFFER (self));
|
||||
|
||||
self->flipped = !!flipped;
|
||||
}
|
||||
@@ -22,17 +22,18 @@
|
||||
|
||||
#include "gdkconfig.h"
|
||||
|
||||
#include <cairo.h>
|
||||
#include <QuartzCore/QuartzCore.h>
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
|
||||
#include "gdkmacosbuffer-private.h"
|
||||
#import "GdkMacosCairoView.h"
|
||||
|
||||
#include "gdkmacoscairocontext-private.h"
|
||||
#include "gdkmacossurface-private.h"
|
||||
|
||||
struct _GdkMacosCairoContext
|
||||
{
|
||||
GdkCairoContext parent_instance;
|
||||
GdkCairoContext parent_instance;
|
||||
|
||||
cairo_surface_t *window_surface;
|
||||
};
|
||||
|
||||
struct _GdkMacosCairoContextClass
|
||||
@@ -42,150 +43,41 @@ struct _GdkMacosCairoContextClass
|
||||
|
||||
G_DEFINE_TYPE (GdkMacosCairoContext, _gdk_macos_cairo_context, GDK_TYPE_CAIRO_CONTEXT)
|
||||
|
||||
static cairo_surface_t *
|
||||
create_cairo_surface_for_surface (GdkSurface *surface)
|
||||
{
|
||||
cairo_surface_t *cairo_surface;
|
||||
int scale;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
g_assert (GDK_IS_MACOS_SURFACE (surface));
|
||||
|
||||
scale = gdk_surface_get_scale_factor (surface);
|
||||
width = scale * gdk_surface_get_width (surface);
|
||||
height = scale * gdk_surface_get_height (surface);
|
||||
|
||||
/* We use a cairo image surface here instead of a quartz surface because we
|
||||
* get strange artifacts with the quartz surface such as empty cross-fades
|
||||
* when hovering buttons. For performance, we want to be using GL rendering
|
||||
* so there isn't much point here as correctness is better.
|
||||
*/
|
||||
cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
|
||||
if (cairo_surface != NULL)
|
||||
cairo_surface_set_device_scale (cairo_surface, scale, scale);
|
||||
|
||||
return cairo_surface;
|
||||
}
|
||||
|
||||
static cairo_t *
|
||||
_gdk_macos_cairo_context_cairo_create (GdkCairoContext *cairo_context)
|
||||
{
|
||||
GdkMacosCairoContext *self = (GdkMacosCairoContext *)cairo_context;
|
||||
const cairo_region_t *damage;
|
||||
cairo_surface_t *image_surface;
|
||||
GdkMacosBuffer *buffer;
|
||||
GdkSurface *surface;
|
||||
NSWindow *nswindow;
|
||||
cairo_t *cr;
|
||||
gpointer data;
|
||||
double scale;
|
||||
guint width;
|
||||
guint height;
|
||||
guint stride;
|
||||
gboolean opaque;
|
||||
|
||||
g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (self));
|
||||
|
||||
surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (self));
|
||||
nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface));
|
||||
opaque = [nswindow isOpaque];
|
||||
|
||||
buffer = _gdk_macos_surface_get_buffer (GDK_MACOS_SURFACE (surface));
|
||||
damage = _gdk_macos_buffer_get_damage (buffer);
|
||||
width = _gdk_macos_buffer_get_width (buffer);
|
||||
height = _gdk_macos_buffer_get_height (buffer);
|
||||
scale = _gdk_macos_buffer_get_device_scale (buffer);
|
||||
stride = _gdk_macos_buffer_get_stride (buffer);
|
||||
data = _gdk_macos_buffer_get_data (buffer);
|
||||
|
||||
/* Instead of forcing cairo to do everything through a CGContext,
|
||||
* we just use an image surface backed by an IOSurfaceRef mapped
|
||||
* into user-space. We can then use pixman which is quite fast as
|
||||
* far as software rendering goes.
|
||||
*
|
||||
* Additionally, cairo_quartz_surface_t can't handle a number of
|
||||
* tricks that the GSK cairo renderer does with border nodes and
|
||||
* shadows, so an image surface is necessary for that.
|
||||
*
|
||||
* Since our IOSurfaceRef is width*scale-by-height*scale, we undo
|
||||
* the scaling using cairo_surface_set_device_scale() so the renderer
|
||||
* just thinks it's on a 2x scale surface for HiDPI.
|
||||
*/
|
||||
image_surface = cairo_image_surface_create_for_data (data,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
width,
|
||||
height,
|
||||
stride);
|
||||
cairo_surface_set_device_scale (image_surface, scale, scale);
|
||||
|
||||
/* The buffer should already be locked at this point, and will
|
||||
* be unlocked as part of end_frame.
|
||||
*/
|
||||
|
||||
if (!(cr = cairo_create (image_surface)))
|
||||
goto failure;
|
||||
|
||||
/* Clip to the current damage region */
|
||||
if (damage != NULL)
|
||||
{
|
||||
gdk_cairo_region (cr, damage);
|
||||
cairo_clip (cr);
|
||||
}
|
||||
|
||||
/* If we have some exposed transparent area in the damage region,
|
||||
* we need to clear the existing content first to leave an transparent
|
||||
* area for cairo. We use (surface_bounds or damage)-(opaque) to get
|
||||
* the smallest set of rectangles we need to clear as it's expensive.
|
||||
*/
|
||||
if (!opaque)
|
||||
{
|
||||
cairo_region_t *transparent;
|
||||
cairo_rectangle_int_t r = { 0, 0, width/scale, height/scale };
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
if (damage != NULL)
|
||||
cairo_region_get_extents (damage, &r);
|
||||
transparent = cairo_region_create_rectangle (&r);
|
||||
if (surface->opaque_region)
|
||||
cairo_region_subtract (transparent, surface->opaque_region);
|
||||
|
||||
if (!cairo_region_is_empty (transparent))
|
||||
{
|
||||
gdk_cairo_region (cr, transparent);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
cairo_region_destroy (transparent);
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
failure:
|
||||
cairo_surface_destroy (image_surface);
|
||||
|
||||
return cr;
|
||||
}
|
||||
|
||||
static void
|
||||
copy_surface_data (GdkMacosBuffer *from,
|
||||
GdkMacosBuffer *to,
|
||||
const cairo_region_t *region,
|
||||
int scale)
|
||||
{
|
||||
const guint8 *from_base;
|
||||
guint8 *to_base;
|
||||
guint from_stride;
|
||||
guint to_stride;
|
||||
guint n_rects;
|
||||
|
||||
g_assert (GDK_IS_MACOS_BUFFER (from));
|
||||
g_assert (GDK_IS_MACOS_BUFFER (to));
|
||||
g_assert (region != NULL);
|
||||
g_assert (!cairo_region_is_empty (region));
|
||||
|
||||
from_base = _gdk_macos_buffer_get_data (from);
|
||||
from_stride = _gdk_macos_buffer_get_stride (from);
|
||||
|
||||
to_base = _gdk_macos_buffer_get_data (to);
|
||||
to_stride = _gdk_macos_buffer_get_stride (to);
|
||||
|
||||
n_rects = cairo_region_num_rectangles (region);
|
||||
|
||||
for (guint i = 0; i < n_rects; i++)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
int y2;
|
||||
|
||||
cairo_region_get_rectangle (region, i, &rect);
|
||||
|
||||
rect.y *= scale;
|
||||
rect.height *= scale;
|
||||
rect.x *= scale;
|
||||
rect.width *= scale;
|
||||
|
||||
y2 = rect.y + rect.height;
|
||||
|
||||
for (int y = rect.y; y < y2; y++)
|
||||
memcpy (&to_base[y * to_stride + rect.x * 4],
|
||||
&from_base[y * from_stride + rect.x * 4],
|
||||
rect.width * 4);
|
||||
}
|
||||
return cairo_create (self->window_surface);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -194,49 +86,28 @@ _gdk_macos_cairo_context_begin_frame (GdkDrawContext *draw_context,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
GdkMacosCairoContext *self = (GdkMacosCairoContext *)draw_context;
|
||||
GdkMacosBuffer *buffer;
|
||||
GdkMacosSurface *surface;
|
||||
GdkSurface *surface;
|
||||
NSWindow *nswindow;
|
||||
|
||||
g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (self));
|
||||
|
||||
[CATransaction begin];
|
||||
[CATransaction setDisableActions:YES];
|
||||
surface = gdk_draw_context_get_surface (draw_context);
|
||||
nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface));
|
||||
|
||||
surface = GDK_MACOS_SURFACE (gdk_draw_context_get_surface (draw_context));
|
||||
buffer = _gdk_macos_surface_get_buffer (surface);
|
||||
|
||||
_gdk_macos_buffer_set_damage (buffer, region);
|
||||
_gdk_macos_buffer_set_flipped (buffer, FALSE);
|
||||
|
||||
_gdk_macos_buffer_lock (buffer);
|
||||
|
||||
/* If there is damage that was on the previous frame that is not on
|
||||
* this frame, we need to copy that rendered region over to the back
|
||||
* buffer so that when swapping buffers, we still have that content.
|
||||
* This is done with a read-only lock on the IOSurface to avoid
|
||||
* invalidating the buffer contents.
|
||||
*/
|
||||
if (surface->front != NULL)
|
||||
if (self->window_surface == NULL)
|
||||
{
|
||||
const cairo_region_t *previous = _gdk_macos_buffer_get_damage (surface->front);
|
||||
|
||||
if (previous != NULL)
|
||||
self->window_surface = create_cairo_surface_for_surface (surface);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (![nswindow isOpaque])
|
||||
{
|
||||
cairo_region_t *copy;
|
||||
|
||||
copy = cairo_region_copy (previous);
|
||||
cairo_region_subtract (copy, region);
|
||||
|
||||
if (!cairo_region_is_empty (copy))
|
||||
{
|
||||
int scale = gdk_surface_get_scale_factor (GDK_SURFACE (surface));
|
||||
|
||||
_gdk_macos_buffer_read_lock (surface->front);
|
||||
copy_surface_data (surface->front, buffer, copy, scale);
|
||||
_gdk_macos_buffer_read_unlock (surface->front);
|
||||
}
|
||||
|
||||
cairo_region_destroy (copy);
|
||||
cairo_t *cr = cairo_create (self->window_surface);
|
||||
gdk_cairo_region (cr, region);
|
||||
cairo_set_source_rgba (cr, 0, 0, 0, 0);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_fill (cr);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -246,27 +117,28 @@ _gdk_macos_cairo_context_end_frame (GdkDrawContext *draw_context,
|
||||
cairo_region_t *painted)
|
||||
{
|
||||
GdkMacosCairoContext *self = (GdkMacosCairoContext *)draw_context;
|
||||
GdkMacosSurface *surface;
|
||||
GdkMacosBuffer *buffer;
|
||||
GdkSurface *surface;
|
||||
NSView *nsview;
|
||||
|
||||
g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (self));
|
||||
g_assert (self->window_surface != NULL);
|
||||
|
||||
surface = GDK_MACOS_SURFACE (gdk_draw_context_get_surface (draw_context));
|
||||
buffer = _gdk_macos_surface_get_buffer (surface);
|
||||
surface = gdk_draw_context_get_surface (draw_context);
|
||||
nsview = _gdk_macos_surface_get_view (GDK_MACOS_SURFACE (surface));
|
||||
|
||||
_gdk_macos_buffer_unlock (buffer);
|
||||
|
||||
_gdk_macos_surface_swap_buffers (surface, painted);
|
||||
|
||||
[CATransaction commit];
|
||||
if (GDK_IS_MACOS_CAIRO_VIEW (nsview))
|
||||
[(GdkMacosCairoView *)nsview setCairoSurface:self->window_surface
|
||||
withDamage:painted];
|
||||
}
|
||||
|
||||
static void
|
||||
_gdk_macos_cairo_context_surface_resized (GdkDrawContext *draw_context)
|
||||
{
|
||||
g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (draw_context));
|
||||
GdkMacosCairoContext *self = (GdkMacosCairoContext *)draw_context;
|
||||
|
||||
/* Do nothing, next begin_frame will get new buffer */
|
||||
g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (self));
|
||||
|
||||
g_clear_pointer (&self->window_surface, cairo_surface_destroy);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2022 Red Hat, Inc.
|
||||
*
|
||||
* 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.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <AppKit/AppKit.h>
|
||||
|
||||
#include "gdkmacosdisplay-private.h"
|
||||
#include "gdkmacossurface-private.h"
|
||||
|
||||
static void
|
||||
gdk_macos_display_user_defaults_changed_cb (CFNotificationCenterRef center,
|
||||
void *observer,
|
||||
CFStringRef name,
|
||||
const void *object,
|
||||
CFDictionaryRef userInfo)
|
||||
{
|
||||
GdkMacosDisplay *self = observer;
|
||||
|
||||
g_assert (GDK_IS_MACOS_DISPLAY (self));
|
||||
|
||||
_gdk_macos_display_reload_settings (self);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_macos_display_monitors_changed_cb (CFNotificationCenterRef center,
|
||||
void *observer,
|
||||
CFStringRef name,
|
||||
const void *object,
|
||||
CFDictionaryRef userInfo)
|
||||
{
|
||||
GdkMacosDisplay *self = observer;
|
||||
|
||||
g_assert (GDK_IS_MACOS_DISPLAY (self));
|
||||
|
||||
_gdk_macos_display_reload_monitors (self);
|
||||
|
||||
/* Now we need to update all our surface positions since they
|
||||
* probably just changed origins.
|
||||
*/
|
||||
for (const GList *iter = _gdk_macos_display_get_surfaces (self);
|
||||
iter != NULL;
|
||||
iter = iter->next)
|
||||
{
|
||||
GdkMacosSurface *surface = iter->data;
|
||||
|
||||
g_assert (GDK_IS_MACOS_SURFACE (surface));
|
||||
|
||||
_gdk_macos_surface_monitor_changed (surface);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_gdk_macos_display_feedback_init (GdkMacosDisplay *self)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
|
||||
|
||||
CFNotificationCenterAddObserver (CFNotificationCenterGetLocalCenter (),
|
||||
self,
|
||||
gdk_macos_display_monitors_changed_cb,
|
||||
CFSTR ("NSApplicationDidChangeScreenParametersNotification"),
|
||||
NULL,
|
||||
CFNotificationSuspensionBehaviorDeliverImmediately);
|
||||
|
||||
CFNotificationCenterAddObserver (CFNotificationCenterGetDistributedCenter (),
|
||||
self,
|
||||
gdk_macos_display_user_defaults_changed_cb,
|
||||
CFSTR ("NSUserDefaultsDidChangeNotification"),
|
||||
NULL,
|
||||
CFNotificationSuspensionBehaviorDeliverImmediately);
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_display_feedback_destroy (GdkMacosDisplay *self)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
|
||||
|
||||
CFNotificationCenterRemoveObserver (CFNotificationCenterGetDistributedCenter (),
|
||||
self,
|
||||
CFSTR ("NSApplicationDidChangeScreenParametersNotification"),
|
||||
NULL);
|
||||
|
||||
CFNotificationCenterRemoveObserver (CFNotificationCenterGetDistributedCenter (),
|
||||
self,
|
||||
CFSTR ("NSUserDefaultsDidChangeNotification"),
|
||||
NULL);
|
||||
|
||||
}
|
||||
@@ -43,8 +43,6 @@ G_BEGIN_DECLS
|
||||
#define GIC_FILTER_PASSTHRU 0
|
||||
#define GIC_FILTER_FILTERED 1
|
||||
|
||||
#define GDK_MACOS_EVENT_DROP (GdkEvent *)GSIZE_TO_POINTER(1)
|
||||
|
||||
struct _GdkMacosDisplay
|
||||
{
|
||||
GdkDisplay parent_instance;
|
||||
@@ -70,6 +68,16 @@ struct _GdkMacosDisplay
|
||||
*/
|
||||
GQueue sorted_surfaces;
|
||||
|
||||
/* Our CVDisplayLink based GSource which we use to freeze/thaw the
|
||||
* GdkFrameClock for the surface.
|
||||
*/
|
||||
GSource *frame_source;
|
||||
|
||||
/* A queue of surfaces which we know are awaiting frames to be drawn. This
|
||||
* uses the GdkMacosSurface.frame link.
|
||||
*/
|
||||
GQueue awaiting_frames;
|
||||
|
||||
/* The surface that is receiving keyboard events */
|
||||
GdkMacosSurface *keyboard_surface;
|
||||
|
||||
@@ -84,14 +92,6 @@ struct _GdkMacosDisplay
|
||||
int min_y;
|
||||
int max_x;
|
||||
int max_y;
|
||||
|
||||
/* A GSource to select a new main/key window */
|
||||
guint select_key_in_idle;
|
||||
|
||||
/* Note if we have a key window that is not a GdkMacosWindow
|
||||
* such as a NSPanel used for native dialogs.
|
||||
*/
|
||||
guint key_window_is_foregin : 1;
|
||||
};
|
||||
|
||||
struct _GdkMacosDisplayClass
|
||||
@@ -124,8 +124,6 @@ GdkMonitor *_gdk_macos_display_get_monitor_at_display_coords (GdkMacosDisp
|
||||
int y);
|
||||
GdkEvent *_gdk_macos_display_translate (GdkMacosDisplay *self,
|
||||
NSEvent *event);
|
||||
void _gdk_macos_display_feedback_init (GdkMacosDisplay *self);
|
||||
void _gdk_macos_display_feedback_destroy (GdkMacosDisplay *self);
|
||||
void _gdk_macos_display_break_all_grabs (GdkMacosDisplay *self,
|
||||
guint32 time);
|
||||
GdkModifierType _gdk_macos_display_get_current_keyboard_modifiers (GdkMacosDisplay *self);
|
||||
@@ -138,6 +136,10 @@ GdkMacosSurface *_gdk_macos_display_get_surface_at_display_coords (GdkMacosDisp
|
||||
void _gdk_macos_display_reload_monitors (GdkMacosDisplay *self);
|
||||
void _gdk_macos_display_surface_removed (GdkMacosDisplay *self,
|
||||
GdkMacosSurface *surface);
|
||||
void _gdk_macos_display_add_frame_callback (GdkMacosDisplay *self,
|
||||
GdkMacosSurface *surface);
|
||||
void _gdk_macos_display_remove_frame_callback (GdkMacosDisplay *self,
|
||||
GdkMacosSurface *surface);
|
||||
NSWindow *_gdk_macos_display_find_native_under_pointer (GdkMacosDisplay *self,
|
||||
int *x,
|
||||
int *y);
|
||||
@@ -153,6 +155,7 @@ void _gdk_macos_display_surface_resigned_key (GdkMacosDisp
|
||||
GdkMacosSurface *surface);
|
||||
void _gdk_macos_display_surface_became_key (GdkMacosDisplay *self,
|
||||
GdkMacosSurface *surface);
|
||||
int _gdk_macos_display_get_nominal_refresh_rate (GdkMacosDisplay *self);
|
||||
void _gdk_macos_display_clear_sorting (GdkMacosDisplay *self);
|
||||
const GList *_gdk_macos_display_get_surfaces (GdkMacosDisplay *self);
|
||||
void _gdk_macos_display_send_button_event (GdkMacosDisplay *self,
|
||||
@@ -171,10 +174,6 @@ void _gdk_macos_display_set_drag (GdkMacosDisp
|
||||
void _gdk_macos_display_set_drop (GdkMacosDisplay *self,
|
||||
NSInteger sequence_number,
|
||||
GdkDrop *drop);
|
||||
void _gdk_macos_display_position_surface (GdkMacosDisplay *self,
|
||||
GdkMacosSurface *surface,
|
||||
int *x,
|
||||
int *y);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ typedef struct
|
||||
const char *font_name;
|
||||
int xft_dpi;
|
||||
int double_click_time;
|
||||
int cursor_blink_time;
|
||||
int cursor_blink_timeout;
|
||||
guint enable_animations : 1;
|
||||
guint shell_shows_desktop : 1;
|
||||
guint shell_shows_menubar : 1;
|
||||
@@ -65,9 +65,9 @@ _gdk_macos_settings_load (GdkMacosSettings *settings)
|
||||
|
||||
ival = [defaults integerForKey:@"NSTextInsertionPointBlinkPeriod"];
|
||||
if (ival > 0)
|
||||
settings->cursor_blink_time = ival;
|
||||
settings->cursor_blink_timeout = ival;
|
||||
else
|
||||
settings->cursor_blink_time = 1000;
|
||||
settings->cursor_blink_timeout = 1000;
|
||||
|
||||
settings->primary_button_warps_slider =
|
||||
[[NSUserDefaults standardUserDefaults] boolForKey:@"AppleScrollerPagingBehavior"] == YES;
|
||||
@@ -124,9 +124,9 @@ _gdk_macos_display_get_setting (GdkMacosDisplay *self,
|
||||
g_value_set_int (value, current_settings.xft_dpi);
|
||||
ret = TRUE;
|
||||
}
|
||||
else if (strcmp (setting, "gtk-cursor-blink-time") == 0)
|
||||
else if (strcmp (setting, "gtk-cursor-blink-timeout") == 0)
|
||||
{
|
||||
g_value_set_int (value, current_settings.cursor_blink_time);
|
||||
g_value_set_int (value, current_settings.cursor_blink_timeout);
|
||||
ret = TRUE;
|
||||
}
|
||||
else if (strcmp (setting, "gtk-double-click-time") == 0)
|
||||
|
||||
@@ -211,7 +211,6 @@ fill_button_event (GdkMacosDisplay *display,
|
||||
GdkDevice *pointer = NULL;
|
||||
GdkDeviceTool *tool = NULL;
|
||||
double *axes = NULL;
|
||||
cairo_region_t *input_region;
|
||||
|
||||
g_assert (GDK_IS_MACOS_DISPLAY (display));
|
||||
g_assert (GDK_IS_MACOS_SURFACE (surface));
|
||||
@@ -219,7 +218,6 @@ fill_button_event (GdkMacosDisplay *display,
|
||||
seat = gdk_display_get_default_seat (GDK_DISPLAY (display));
|
||||
state = get_keyboard_modifiers_from_ns_event (nsevent) |
|
||||
_gdk_macos_display_get_current_mouse_modifiers (display);
|
||||
input_region = GDK_SURFACE (surface)->input_region;
|
||||
|
||||
switch ((int)[nsevent type])
|
||||
{
|
||||
@@ -246,8 +244,7 @@ fill_button_event (GdkMacosDisplay *display,
|
||||
*/
|
||||
if (type == GDK_BUTTON_PRESS &&
|
||||
(x < 0 || x > GDK_SURFACE (surface)->width ||
|
||||
y < 0 || y > GDK_SURFACE (surface)->height ||
|
||||
(input_region && !cairo_region_contains_point (input_region, x, y))))
|
||||
y < 0 || y > GDK_SURFACE (surface)->height))
|
||||
return NULL;
|
||||
|
||||
if (([nsevent subtype] == NSEventSubtypeTabletPoint) &&
|
||||
@@ -612,8 +609,6 @@ fill_scroll_event (GdkMacosDisplay *self,
|
||||
GdkModifierType state;
|
||||
GdkDevice *pointer;
|
||||
GdkEvent *ret = NULL;
|
||||
NSEventPhase phase;
|
||||
NSEventPhase momentumPhase;
|
||||
GdkSeat *seat;
|
||||
double dx;
|
||||
double dy;
|
||||
@@ -621,31 +616,11 @@ fill_scroll_event (GdkMacosDisplay *self,
|
||||
g_assert (GDK_IS_MACOS_SURFACE (surface));
|
||||
g_assert (nsevent != NULL);
|
||||
|
||||
phase = [nsevent phase];
|
||||
momentumPhase = [nsevent momentumPhase];
|
||||
|
||||
/* Ignore kinetic scroll events from the display server as we already
|
||||
* handle those internally.
|
||||
*/
|
||||
if (phase == 0 && momentumPhase != 0)
|
||||
return GDK_MACOS_EVENT_DROP;
|
||||
|
||||
seat = gdk_display_get_default_seat (GDK_DISPLAY (self));
|
||||
pointer = gdk_seat_get_pointer (seat);
|
||||
state = _gdk_macos_display_get_current_mouse_modifiers (self) |
|
||||
_gdk_macos_display_get_current_keyboard_modifiers (self);
|
||||
|
||||
/* If we are starting a new phase, send a stop so any previous
|
||||
* scrolling immediately stops.
|
||||
*/
|
||||
if (phase == NSEventPhaseMayBegin)
|
||||
return gdk_scroll_event_new (GDK_SURFACE (surface),
|
||||
pointer,
|
||||
NULL,
|
||||
get_time_from_ns_event (nsevent),
|
||||
state,
|
||||
0.0, 0.0, TRUE);
|
||||
|
||||
dx = [nsevent deltaX];
|
||||
dy = [nsevent deltaY];
|
||||
|
||||
@@ -689,32 +664,34 @@ fill_scroll_event (GdkMacosDisplay *self,
|
||||
dy = 0.0;
|
||||
}
|
||||
|
||||
if ((dx != 0.0 || dy != 0.0) && ![nsevent hasPreciseScrollingDeltas])
|
||||
if (dx != 0.0 || dy != 0.0)
|
||||
{
|
||||
g_assert (ret == NULL);
|
||||
if ([nsevent hasPreciseScrollingDeltas])
|
||||
{
|
||||
GdkEvent *emulated;
|
||||
|
||||
ret = gdk_scroll_event_new_discrete (GDK_SURFACE (surface),
|
||||
pointer,
|
||||
NULL,
|
||||
get_time_from_ns_event (nsevent),
|
||||
state,
|
||||
direction,
|
||||
FALSE);
|
||||
}
|
||||
emulated = gdk_scroll_event_new_discrete (GDK_SURFACE (surface),
|
||||
pointer,
|
||||
NULL,
|
||||
get_time_from_ns_event (nsevent),
|
||||
state,
|
||||
direction,
|
||||
TRUE);
|
||||
_gdk_event_queue_append (GDK_DISPLAY (self), emulated);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert (ret == NULL);
|
||||
|
||||
if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled)
|
||||
{
|
||||
/* The user must have released their fingers in a touchpad
|
||||
* scroll, so try to send a scroll is_stop event.
|
||||
*/
|
||||
if (ret != NULL)
|
||||
_gdk_event_queue_append (GDK_DISPLAY (self), g_steal_pointer (&ret));
|
||||
ret = gdk_scroll_event_new (GDK_SURFACE (surface),
|
||||
pointer,
|
||||
NULL,
|
||||
get_time_from_ns_event (nsevent),
|
||||
state,
|
||||
0.0, 0.0, TRUE);
|
||||
ret = gdk_scroll_event_new (GDK_SURFACE (surface),
|
||||
pointer,
|
||||
NULL,
|
||||
get_time_from_ns_event (nsevent),
|
||||
state,
|
||||
dx,
|
||||
dy,
|
||||
FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
return g_steal_pointer (&ret);
|
||||
@@ -877,9 +854,9 @@ get_surface_from_ns_event (GdkMacosDisplay *self,
|
||||
|
||||
find_under_pointer:
|
||||
|
||||
if (surface == NULL && nswindow == NULL)
|
||||
if (!surface)
|
||||
{
|
||||
/* Fallback used when no NSWindow set. This happens e.g. when
|
||||
/* Fallback used when no NSSurface set. This happens e.g. when
|
||||
* we allow motion events without a window set in gdk_event_translate()
|
||||
* that occur immediately after the main menu bar was clicked/used.
|
||||
* This fallback will not return coordinates contained in a window's
|
||||
@@ -929,13 +906,7 @@ find_surface_for_mouse_event (GdkMacosDisplay *self,
|
||||
GdkDeviceGrabInfo *grab;
|
||||
GdkSeat *seat;
|
||||
|
||||
/* Even if we had a surface window, it might be for something outside
|
||||
* the input region (shadow) which we might want to ignore. This is
|
||||
* handled for us deeper in the event unwrapping.
|
||||
*/
|
||||
if (!(surface = get_surface_from_ns_event (self, nsevent, &point, x, y)))
|
||||
return NULL;
|
||||
|
||||
surface = get_surface_from_ns_event (self, nsevent, &point, x, y);
|
||||
display = gdk_surface_get_display (surface);
|
||||
seat = gdk_display_get_default_seat (GDK_DISPLAY (self));
|
||||
pointer = gdk_seat_get_pointer (seat);
|
||||
@@ -1037,6 +1008,11 @@ find_surface_for_ns_event (GdkMacosDisplay *self,
|
||||
g_assert (x != NULL);
|
||||
g_assert (y != NULL);
|
||||
|
||||
if (!(surface = get_surface_from_ns_event (self, nsevent, &point, x, y)))
|
||||
return NULL;
|
||||
|
||||
view = (GdkMacosBaseView *)[GDK_MACOS_SURFACE (surface)->window contentView];
|
||||
|
||||
_gdk_macos_display_from_display_coords (self, point.x, point.y, &x_tmp, &y_tmp);
|
||||
|
||||
switch ((int)[nsevent type])
|
||||
@@ -1061,9 +1037,7 @@ find_surface_for_ns_event (GdkMacosDisplay *self,
|
||||
/* Only handle our own entered/exited events, not the ones for the
|
||||
* titlebar buttons.
|
||||
*/
|
||||
if ((surface = get_surface_from_ns_event (self, nsevent, &point, x, y)) &&
|
||||
(view = (GdkMacosBaseView *)[GDK_MACOS_SURFACE (surface)->window contentView]) &&
|
||||
([nsevent trackingArea] == [view trackingArea]))
|
||||
if ([nsevent trackingArea] == [view trackingArea])
|
||||
return GDK_MACOS_SURFACE (surface);
|
||||
else
|
||||
return NULL;
|
||||
@@ -1086,7 +1060,6 @@ _gdk_macos_display_translate (GdkMacosDisplay *self,
|
||||
GdkMacosSurface *surface;
|
||||
GdkMacosWindow *window;
|
||||
NSEventType event_type;
|
||||
NSWindow *event_window;
|
||||
GdkEvent *ret = NULL;
|
||||
int x;
|
||||
int y;
|
||||
@@ -1129,15 +1102,6 @@ _gdk_macos_display_translate (GdkMacosDisplay *self,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If the event was delivered to NSWindow that is foreign (or rather,
|
||||
* Cocoa native), then we should pass the event along to that window.
|
||||
*/
|
||||
if ((event_window = [nsevent window]) && !GDK_IS_MACOS_WINDOW (event_window))
|
||||
return NULL;
|
||||
|
||||
/* If we can't find a GdkSurface to deliver the event to, then we
|
||||
* should pass it along to the NSApp.
|
||||
*/
|
||||
if (!(surface = find_surface_for_ns_event (self, nsevent, &x, &y)))
|
||||
return NULL;
|
||||
|
||||
@@ -1169,31 +1133,15 @@ _gdk_macos_display_translate (GdkMacosDisplay *self,
|
||||
if (test_resize (nsevent, surface, x, y))
|
||||
return NULL;
|
||||
|
||||
if (event_type == NSEventTypeRightMouseDown ||
|
||||
event_type == NSEventTypeOtherMouseDown ||
|
||||
event_type == NSEventTypeLeftMouseDown)
|
||||
if ((event_type == NSEventTypeRightMouseDown ||
|
||||
event_type == NSEventTypeOtherMouseDown ||
|
||||
event_type == NSEventTypeLeftMouseDown))
|
||||
{
|
||||
if (![NSApp isActive])
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
|
||||
if (![window isKeyWindow])
|
||||
{
|
||||
NSWindow *orig_window = [nsevent window];
|
||||
|
||||
/* To get NSApp to supress activating the window we might
|
||||
* have clicked through the shadow of, we need to dispatch
|
||||
* the event and handle it in GdkMacosView:mouseDown to call
|
||||
* [NSApp preventWindowOrdering]. Calling it here will not
|
||||
* do anything as the event is not registered.
|
||||
*/
|
||||
if (orig_window &&
|
||||
GDK_IS_MACOS_WINDOW (orig_window) &&
|
||||
[(GdkMacosWindow *)orig_window needsMouseDownQuirk])
|
||||
[NSApp sendEvent:nsevent];
|
||||
|
||||
[window showAndMakeKey:YES];
|
||||
_gdk_macos_display_clear_sorting (self);
|
||||
}
|
||||
[window makeKeyWindow];
|
||||
}
|
||||
|
||||
switch ((int)event_type)
|
||||
@@ -1226,11 +1174,7 @@ _gdk_macos_display_translate (GdkMacosDisplay *self,
|
||||
GdkDevice *pointer = gdk_seat_get_pointer (seat);
|
||||
GdkDeviceGrabInfo *grab = _gdk_display_get_last_device_grab (GDK_DISPLAY (self), pointer);
|
||||
|
||||
if ([(GdkMacosWindow *)window isInManualResizeOrMove])
|
||||
{
|
||||
ret = GDK_MACOS_EVENT_DROP;
|
||||
}
|
||||
else if (grab == NULL)
|
||||
if (grab == NULL)
|
||||
{
|
||||
if (event_type == NSEventTypeMouseExited)
|
||||
[[NSCursor arrowCursor] set];
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2022 Red Hat, Inc.
|
||||
*
|
||||
* 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.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gdkmacosdisplay-private.h"
|
||||
#include "gdkmacosmonitor-private.h"
|
||||
#include "gdkmacossurface-private.h"
|
||||
#include "gdkmacostoplevelsurface-private.h"
|
||||
|
||||
#define WARP_OFFSET_X 15
|
||||
#define WARP_OFFSET_Y 15
|
||||
|
||||
static void
|
||||
_gdk_macos_display_position_toplevel_with_parent (GdkMacosDisplay *self,
|
||||
GdkMacosSurface *surface,
|
||||
GdkMacosSurface *parent,
|
||||
int *x,
|
||||
int *y)
|
||||
{
|
||||
GdkRectangle surface_rect;
|
||||
GdkRectangle parent_rect;
|
||||
GdkMonitor *monitor;
|
||||
|
||||
g_assert (GDK_IS_MACOS_DISPLAY (self));
|
||||
g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (surface));
|
||||
g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (parent));
|
||||
|
||||
monitor = _gdk_macos_surface_get_best_monitor (parent);
|
||||
|
||||
/* Try to center on top of the parent but also try to make the whole thing
|
||||
* visible in case that lands us under the topbar/panel/etc.
|
||||
*/
|
||||
parent_rect.x = parent->root_x + parent->shadow_left;
|
||||
parent_rect.y = parent->root_y + parent->shadow_top;
|
||||
parent_rect.width = GDK_SURFACE (parent)->width - parent->shadow_left - parent->shadow_right;
|
||||
parent_rect.height = GDK_SURFACE (parent)->height - parent->shadow_top - parent->shadow_bottom;
|
||||
|
||||
surface_rect.width = GDK_SURFACE (surface)->width - surface->shadow_left - surface->shadow_right;
|
||||
surface_rect.height = GDK_SURFACE (surface)->height - surface->shadow_top - surface->shadow_bottom;
|
||||
surface_rect.x = parent_rect.x + ((parent_rect.width - surface_rect.width) / 2);
|
||||
surface_rect.y = parent_rect.y + ((parent_rect.height - surface_rect.height) / 2);
|
||||
|
||||
_gdk_macos_monitor_clamp (GDK_MACOS_MONITOR (monitor), &surface_rect);
|
||||
|
||||
*x = surface_rect.x - surface->shadow_left;
|
||||
*y = surface_rect.y - surface->shadow_top;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
has_surface_at_origin (const GList *surfaces,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
for (const GList *iter = surfaces; iter; iter = iter->next)
|
||||
{
|
||||
GdkMacosSurface *surface = iter->data;
|
||||
|
||||
if (surface->root_x == x && surface->root_y == y)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_gdk_macos_display_position_toplevel (GdkMacosDisplay *self,
|
||||
GdkMacosSurface *surface,
|
||||
int *x,
|
||||
int *y)
|
||||
{
|
||||
cairo_rectangle_int_t surface_rect;
|
||||
GdkRectangle workarea;
|
||||
const GList *surfaces;
|
||||
GdkMonitor *monitor;
|
||||
CGPoint mouse;
|
||||
|
||||
g_assert (GDK_IS_MACOS_DISPLAY (self));
|
||||
g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (surface));
|
||||
|
||||
mouse = [NSEvent mouseLocation];
|
||||
monitor = _gdk_macos_display_get_monitor_at_display_coords (self, mouse.x, mouse.y);
|
||||
gdk_macos_monitor_get_workarea (monitor, &workarea);
|
||||
|
||||
/* First place at top-left of current monitor */
|
||||
surface_rect.width = GDK_SURFACE (surface)->width - surface->shadow_left - surface->shadow_right;
|
||||
surface_rect.height = GDK_SURFACE (surface)->height - surface->shadow_top - surface->shadow_bottom;
|
||||
surface_rect.x = workarea.x + ((workarea.width - surface_rect.width) / 2);
|
||||
surface_rect.y = workarea.y + ((workarea.height - surface_rect.height) / 2);
|
||||
|
||||
_gdk_macos_monitor_clamp (GDK_MACOS_MONITOR (surface->best_monitor), &surface_rect);
|
||||
|
||||
*x = surface_rect.x - surface->shadow_left;
|
||||
*y = surface_rect.y - surface->shadow_top;
|
||||
|
||||
/* Try to see if there are any other surfaces at this origin and if so,
|
||||
* adjust until we get something better.
|
||||
*/
|
||||
surfaces = _gdk_macos_display_get_surfaces (self);
|
||||
while (has_surface_at_origin (surfaces, *x, *y))
|
||||
{
|
||||
*x += WARP_OFFSET_X;
|
||||
*y += WARP_OFFSET_Y;
|
||||
|
||||
/* If we reached the bottom right, just bail and try the workspace origin */
|
||||
if (*x + surface->shadow_left + WARP_OFFSET_X > workarea.x + workarea.width ||
|
||||
*y + surface->shadow_top + WARP_OFFSET_Y > workarea.y + workarea.height)
|
||||
{
|
||||
*x = workarea.x - surface->shadow_left;
|
||||
*y = workarea.y - surface->shadow_top;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*<private>
|
||||
* _gdk_macos_display_position_surface:
|
||||
*
|
||||
* Tries to position a window on a screen without landing in edges
|
||||
* and other weird areas the user can't use.
|
||||
*/
|
||||
void
|
||||
_gdk_macos_display_position_surface (GdkMacosDisplay *self,
|
||||
GdkMacosSurface *surface,
|
||||
int *x,
|
||||
int *y)
|
||||
{
|
||||
GdkSurface *transient_for;
|
||||
|
||||
g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
|
||||
g_return_if_fail (GDK_IS_MACOS_TOPLEVEL_SURFACE (surface));
|
||||
|
||||
transient_for = GDK_SURFACE (surface)->transient_for;
|
||||
|
||||
if (transient_for != NULL)
|
||||
_gdk_macos_display_position_toplevel_with_parent (self, surface, GDK_MACOS_SURFACE (transient_for), x, y);
|
||||
else
|
||||
_gdk_macos_display_position_toplevel (self, surface, x, y);
|
||||
}
|
||||
+205
-113
@@ -156,13 +156,53 @@ gdk_macos_display_update_bounds (GdkMacosDisplay *self)
|
||||
self->width = self->max_x - self->min_x;
|
||||
self->height = self->max_y - self->min_y;
|
||||
|
||||
GDK_NOTE (MISC,
|
||||
g_message ("Displays reconfigured to bounds %d,%d %dx%d",
|
||||
self->min_x, self->min_y, self->width, self->height));
|
||||
|
||||
GDK_END_MACOS_ALLOC_POOL;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_macos_display_monitors_changed_cb (CFNotificationCenterRef center,
|
||||
void *observer,
|
||||
CFStringRef name,
|
||||
const void *object,
|
||||
CFDictionaryRef userInfo)
|
||||
{
|
||||
GdkMacosDisplay *self = observer;
|
||||
|
||||
g_assert (GDK_IS_MACOS_DISPLAY (self));
|
||||
|
||||
_gdk_macos_display_reload_monitors (self);
|
||||
|
||||
/* Now we need to update all our surface positions since they
|
||||
* probably just changed origins. We ignore the popup surfaces
|
||||
* since we can rely on the toplevel surfaces to handle that.
|
||||
*/
|
||||
for (const GList *iter = _gdk_macos_display_get_surfaces (self);
|
||||
iter != NULL;
|
||||
iter = iter->next)
|
||||
{
|
||||
GdkMacosSurface *surface = iter->data;
|
||||
|
||||
g_assert (GDK_IS_MACOS_SURFACE (surface));
|
||||
|
||||
if (GDK_IS_TOPLEVEL (surface))
|
||||
_gdk_macos_surface_update_position (surface);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_macos_display_user_defaults_changed_cb (CFNotificationCenterRef center,
|
||||
void *observer,
|
||||
CFStringRef name,
|
||||
const void *object,
|
||||
CFDictionaryRef userInfo)
|
||||
{
|
||||
GdkMacosDisplay *self = observer;
|
||||
|
||||
g_assert (GDK_IS_MACOS_DISPLAY (self));
|
||||
|
||||
_gdk_macos_display_reload_settings (self);
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_display_reload_monitors (GdkMacosDisplay *self)
|
||||
{
|
||||
@@ -235,6 +275,52 @@ gdk_macos_display_load_seat (GdkMacosDisplay *self)
|
||||
g_object_unref (seat);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_macos_display_frame_cb (gpointer data)
|
||||
{
|
||||
GdkMacosDisplay *self = data;
|
||||
GdkDisplayLinkSource *source;
|
||||
gint64 presentation_time;
|
||||
gint64 now;
|
||||
GList *iter;
|
||||
|
||||
g_assert (GDK_IS_MACOS_DISPLAY (self));
|
||||
|
||||
source = (GdkDisplayLinkSource *)self->frame_source;
|
||||
|
||||
presentation_time = source->presentation_time;
|
||||
now = g_source_get_time ((GSource *)source);
|
||||
|
||||
iter = self->awaiting_frames.head;
|
||||
|
||||
while (iter != NULL)
|
||||
{
|
||||
GdkMacosSurface *surface = iter->data;
|
||||
|
||||
g_assert (GDK_IS_MACOS_SURFACE (surface));
|
||||
|
||||
iter = iter->next;
|
||||
|
||||
_gdk_macos_display_remove_frame_callback (self, surface);
|
||||
_gdk_macos_surface_thaw (surface,
|
||||
source->presentation_time,
|
||||
source->refresh_interval);
|
||||
}
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_macos_display_load_display_link (GdkMacosDisplay *self)
|
||||
{
|
||||
self->frame_source = gdk_display_link_source_new ();
|
||||
g_source_set_callback (self->frame_source,
|
||||
gdk_macos_display_frame_cb,
|
||||
self,
|
||||
NULL);
|
||||
g_source_attach (self->frame_source, NULL);
|
||||
}
|
||||
|
||||
static const char *
|
||||
gdk_macos_display_get_name (GdkDisplay *display)
|
||||
{
|
||||
@@ -310,15 +396,11 @@ gdk_macos_display_queue_events (GdkDisplay *display)
|
||||
|
||||
g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
|
||||
|
||||
while ((nsevent = _gdk_macos_event_source_get_pending ()))
|
||||
if ((nsevent = _gdk_macos_event_source_get_pending ()))
|
||||
{
|
||||
GdkEvent *event = _gdk_macos_display_translate (self, nsevent);
|
||||
|
||||
if (event == GDK_MACOS_EVENT_DROP)
|
||||
{
|
||||
[nsevent release];
|
||||
}
|
||||
else if (event != NULL)
|
||||
if (event != NULL)
|
||||
{
|
||||
push_nsevent (event, nsevent);
|
||||
_gdk_windowing_got_event (GDK_DISPLAY (self),
|
||||
@@ -342,6 +424,7 @@ _gdk_macos_display_surface_added (GdkMacosDisplay *self,
|
||||
g_assert (GDK_IS_MACOS_SURFACE (surface));
|
||||
g_assert (!queue_contains (&self->sorted_surfaces, &surface->sorted));
|
||||
g_assert (!queue_contains (&self->main_surfaces, &surface->main));
|
||||
g_assert (!queue_contains (&self->awaiting_frames, &surface->frame));
|
||||
g_assert (surface->sorted.data == surface);
|
||||
g_assert (surface->main.data == surface);
|
||||
g_assert (surface->frame.data == surface);
|
||||
@@ -368,6 +451,9 @@ _gdk_macos_display_surface_removed (GdkMacosDisplay *self,
|
||||
if (queue_contains (&self->main_surfaces, &surface->main))
|
||||
_gdk_macos_display_surface_resigned_main (self, surface);
|
||||
|
||||
if (queue_contains (&self->awaiting_frames, &surface->frame))
|
||||
g_queue_unlink (&self->awaiting_frames, &surface->frame);
|
||||
|
||||
g_return_if_fail (self->keyboard_surface != surface);
|
||||
}
|
||||
|
||||
@@ -390,21 +476,6 @@ _gdk_macos_display_surface_became_key (GdkMacosDisplay *self,
|
||||
event = gdk_focus_event_new (GDK_SURFACE (surface), keyboard, TRUE);
|
||||
_gdk_event_queue_append (GDK_DISPLAY (self), event);
|
||||
|
||||
/* For each parent surface, we want them to look like they
|
||||
* are also still focused, so ensure they have that same
|
||||
* state associated with them.
|
||||
*/
|
||||
if (GDK_IS_POPUP (surface))
|
||||
{
|
||||
for (GdkSurface *parent = GDK_SURFACE (surface)->parent;
|
||||
parent != NULL;
|
||||
parent = parent->parent)
|
||||
{
|
||||
if (GDK_IS_TOPLEVEL (parent))
|
||||
gdk_synthesize_surface_state (parent, 0, GDK_TOPLEVEL_STATE_FOCUSED);
|
||||
}
|
||||
}
|
||||
|
||||
/* We just became the active window. Unlike X11, Mac OS X does
|
||||
* not send us motion events while the window does not have focus
|
||||
* ("is not key"). We send a dummy motion notify event now, so that
|
||||
@@ -413,38 +484,6 @@ _gdk_macos_display_surface_became_key (GdkMacosDisplay *self,
|
||||
gdk_surface_request_motion (GDK_SURFACE (surface));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
select_key_in_idle_cb (gpointer data)
|
||||
{
|
||||
GdkMacosDisplay *self = data;
|
||||
|
||||
g_assert (GDK_IS_MACOS_DISPLAY (self));
|
||||
|
||||
self->select_key_in_idle = 0;
|
||||
|
||||
/* Don't steal focus from NSPanel, etc */
|
||||
if (self->key_window_is_foregin)
|
||||
return G_SOURCE_REMOVE;
|
||||
|
||||
if (self->keyboard_surface == NULL)
|
||||
{
|
||||
const GList *surfaces = _gdk_macos_display_get_surfaces (self);
|
||||
|
||||
for (const GList *iter = surfaces; iter; iter = iter->next)
|
||||
{
|
||||
GdkMacosSurface *surface = iter->data;
|
||||
|
||||
if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (surface)))
|
||||
{
|
||||
[surface->window showAndMakeKey:YES];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_display_surface_resigned_key (GdkMacosDisplay *self,
|
||||
GdkMacosSurface *surface)
|
||||
@@ -473,25 +512,7 @@ _gdk_macos_display_surface_resigned_key (GdkMacosDisplay *self,
|
||||
_gdk_display_get_next_serial (GDK_DISPLAY (self)));
|
||||
}
|
||||
|
||||
/* For each parent surface, we want them to look like they
|
||||
* are also still focused, so ensure they have that same
|
||||
* state associated with them.
|
||||
*/
|
||||
if (GDK_IS_POPUP (surface))
|
||||
{
|
||||
for (GdkSurface *parent = GDK_SURFACE (surface)->parent;
|
||||
parent != NULL;
|
||||
parent = parent->parent)
|
||||
{
|
||||
if (GDK_IS_TOPLEVEL (parent))
|
||||
gdk_synthesize_surface_state (parent, GDK_TOPLEVEL_STATE_FOCUSED, 0);
|
||||
}
|
||||
}
|
||||
|
||||
_gdk_macos_display_clear_sorting (self);
|
||||
|
||||
if (self->select_key_in_idle == 0)
|
||||
self->select_key_in_idle = g_idle_add (select_key_in_idle_cb, self);
|
||||
}
|
||||
|
||||
/* Raises a transient window.
|
||||
@@ -530,6 +551,8 @@ void
|
||||
_gdk_macos_display_surface_resigned_main (GdkMacosDisplay *self,
|
||||
GdkMacosSurface *surface)
|
||||
{
|
||||
GdkMacosSurface *new_surface = NULL;
|
||||
|
||||
g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
|
||||
g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
|
||||
|
||||
@@ -537,6 +560,40 @@ _gdk_macos_display_surface_resigned_main (GdkMacosDisplay *self,
|
||||
g_queue_unlink (&self->main_surfaces, &surface->main);
|
||||
|
||||
_gdk_macos_display_clear_sorting (self);
|
||||
|
||||
if (GDK_SURFACE (surface)->transient_for &&
|
||||
gdk_surface_get_mapped (GDK_SURFACE (surface)->transient_for))
|
||||
{
|
||||
new_surface = GDK_MACOS_SURFACE (GDK_SURFACE (surface)->transient_for);
|
||||
}
|
||||
else
|
||||
{
|
||||
const GList *surfaces = _gdk_macos_display_get_surfaces (self);
|
||||
|
||||
for (const GList *iter = surfaces; iter; iter = iter->next)
|
||||
{
|
||||
GdkMacosSurface *item = iter->data;
|
||||
|
||||
g_assert (GDK_IS_MACOS_SURFACE (item));
|
||||
|
||||
if (item == surface)
|
||||
continue;
|
||||
|
||||
if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (item)))
|
||||
{
|
||||
new_surface = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (new_surface != NULL)
|
||||
{
|
||||
NSWindow *nswindow = _gdk_macos_surface_get_native (new_surface);
|
||||
[nswindow makeKeyAndOrderFront:nswindow];
|
||||
}
|
||||
|
||||
_gdk_macos_display_clear_sorting (self);
|
||||
}
|
||||
|
||||
static GdkSurface *
|
||||
@@ -597,12 +654,20 @@ gdk_macos_display_finalize (GObject *object)
|
||||
{
|
||||
GdkMacosDisplay *self = (GdkMacosDisplay *)object;
|
||||
|
||||
_gdk_macos_display_feedback_destroy (self);
|
||||
CFNotificationCenterRemoveObserver (CFNotificationCenterGetDistributedCenter (),
|
||||
self,
|
||||
CFSTR ("NSApplicationDidChangeScreenParametersNotification"),
|
||||
NULL);
|
||||
|
||||
CFNotificationCenterRemoveObserver (CFNotificationCenterGetDistributedCenter (),
|
||||
self,
|
||||
CFSTR ("NSUserDefaultsDidChangeNotification"),
|
||||
NULL);
|
||||
|
||||
g_clear_handle_id (&self->select_key_in_idle, g_source_remove);
|
||||
g_clear_pointer (&self->active_drags, g_hash_table_unref);
|
||||
g_clear_pointer (&self->active_drops, g_hash_table_unref);
|
||||
g_clear_object (&GDK_DISPLAY (self)->clipboard);
|
||||
g_clear_pointer (&self->frame_source, g_source_unref);
|
||||
g_clear_object (&self->monitors);
|
||||
g_clear_pointer (&self->name, g_free);
|
||||
|
||||
@@ -661,8 +726,7 @@ _gdk_macos_display_open (const char *display_name)
|
||||
if (self != NULL)
|
||||
return NULL;
|
||||
|
||||
display_name = display_name ? display_name : "";
|
||||
GDK_NOTE (MISC, g_message ("opening display %s", display_name));
|
||||
GDK_NOTE (MISC, g_message ("opening display %s", display_name ? display_name : ""));
|
||||
|
||||
/* Make the current process a foreground application, i.e. an app
|
||||
* with a user interface, in case we're not running from a .app bundle
|
||||
@@ -677,10 +741,24 @@ _gdk_macos_display_open (const char *display_name)
|
||||
|
||||
gdk_macos_display_load_seat (self);
|
||||
gdk_macos_display_load_clipboard (self);
|
||||
|
||||
/* Load CVDisplayLink before monitors to access refresh rates */
|
||||
gdk_macos_display_load_display_link (self);
|
||||
_gdk_macos_display_reload_monitors (self);
|
||||
|
||||
/* Initialize feedback from display server */
|
||||
_gdk_macos_display_feedback_init (self);
|
||||
CFNotificationCenterAddObserver (CFNotificationCenterGetLocalCenter (),
|
||||
self,
|
||||
gdk_macos_display_monitors_changed_cb,
|
||||
CFSTR ("NSApplicationDidChangeScreenParametersNotification"),
|
||||
NULL,
|
||||
CFNotificationSuspensionBehaviorDeliverImmediately);
|
||||
|
||||
CFNotificationCenterAddObserver (CFNotificationCenterGetDistributedCenter (),
|
||||
self,
|
||||
gdk_macos_display_user_defaults_changed_cb,
|
||||
CFSTR ("NSUserDefaultsDidChangeNotification"),
|
||||
NULL,
|
||||
CFNotificationSuspensionBehaviorDeliverImmediately);
|
||||
|
||||
if (event_source == NULL)
|
||||
{
|
||||
@@ -692,8 +770,6 @@ _gdk_macos_display_open (const char *display_name)
|
||||
|
||||
gdk_display_emit_opened (GDK_DISPLAY (self));
|
||||
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
|
||||
return GDK_DISPLAY (self);
|
||||
}
|
||||
|
||||
@@ -734,7 +810,6 @@ _gdk_macos_display_get_monitor_at_coords (GdkMacosDisplay *self,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
GdkMacosMonitor *best_match = NULL;
|
||||
guint n_monitors;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (self), NULL);
|
||||
@@ -744,25 +819,12 @@ _gdk_macos_display_get_monitor_at_coords (GdkMacosDisplay *self,
|
||||
for (guint i = 0; i < n_monitors; i++)
|
||||
{
|
||||
GdkMacosMonitor *monitor = get_monitor (self, i);
|
||||
const GdkRectangle *geom = &GDK_MONITOR (monitor)->geometry;
|
||||
|
||||
if (x >= geom->x &&
|
||||
y >= geom->y &&
|
||||
x <= (geom->x + geom->width) &&
|
||||
y <= (geom->y + geom->height))
|
||||
{
|
||||
if (x <= geom->x + geom->width && y < geom->y + geom->height)
|
||||
return GDK_MONITOR (monitor);
|
||||
|
||||
/* Not an exact match as we're on a boundary, but there is
|
||||
* a good chance another monitor doesn't exist there so we
|
||||
* would want to still treat this as the best monitor.
|
||||
*/
|
||||
best_match = monitor;
|
||||
}
|
||||
if (gdk_rectangle_contains_point (&GDK_MONITOR (monitor)->geometry, x, y))
|
||||
return GDK_MONITOR (monitor);
|
||||
}
|
||||
|
||||
return GDK_MONITOR (best_match);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GdkMonitor *
|
||||
@@ -887,14 +949,6 @@ _gdk_macos_display_get_surface_at_coords (GdkMacosDisplay *self,
|
||||
*surface_x = x - GDK_MACOS_SURFACE (surface)->root_x;
|
||||
*surface_y = y - GDK_MACOS_SURFACE (surface)->root_y;
|
||||
|
||||
/* One last check to make sure that the x,y is within the input
|
||||
* region of the window. Otherwise we might send the event to the
|
||||
* wrong window because of window shadow.
|
||||
*/
|
||||
if (surface->input_region != NULL &&
|
||||
!cairo_region_contains_point (surface->input_region, *surface_x, *surface_y))
|
||||
continue;
|
||||
|
||||
return GDK_MACOS_SURFACE (surface);
|
||||
}
|
||||
}
|
||||
@@ -924,6 +978,38 @@ _gdk_macos_display_get_surface_at_display_coords (GdkMacosDisplay *self,
|
||||
return _gdk_macos_display_get_surface_at_coords (self, x_gdk, y_gdk, surface_x, surface_y);
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_display_add_frame_callback (GdkMacosDisplay *self,
|
||||
GdkMacosSurface *surface)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
|
||||
g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
|
||||
|
||||
if (!queue_contains (&self->awaiting_frames, &surface->frame))
|
||||
{
|
||||
g_queue_push_tail_link (&self->awaiting_frames, &surface->frame);
|
||||
|
||||
if (self->awaiting_frames.length == 1)
|
||||
gdk_display_link_source_unpause ((GdkDisplayLinkSource *)self->frame_source);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_display_remove_frame_callback (GdkMacosDisplay *self,
|
||||
GdkMacosSurface *surface)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
|
||||
g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
|
||||
|
||||
if (queue_contains (&self->awaiting_frames, &surface->frame))
|
||||
{
|
||||
g_queue_unlink (&self->awaiting_frames, &surface->frame);
|
||||
|
||||
if (self->awaiting_frames.length == 0)
|
||||
gdk_display_link_source_pause ((GdkDisplayLinkSource *)self->frame_source);
|
||||
}
|
||||
}
|
||||
|
||||
NSWindow *
|
||||
_gdk_macos_display_find_native_under_pointer (GdkMacosDisplay *self,
|
||||
int *x,
|
||||
@@ -943,6 +1029,17 @@ _gdk_macos_display_find_native_under_pointer (GdkMacosDisplay *self,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
_gdk_macos_display_get_nominal_refresh_rate (GdkMacosDisplay *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (self), 60 * 1000);
|
||||
|
||||
if (self->frame_source == NULL)
|
||||
return 60 * 1000;
|
||||
|
||||
return ((GdkDisplayLinkSource *)self->frame_source)->refresh_rate;
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_display_clear_sorting (GdkMacosDisplay *self)
|
||||
{
|
||||
@@ -964,16 +1061,11 @@ _gdk_macos_display_get_surfaces (GdkMacosDisplay *self)
|
||||
NSArray *array = [NSApp orderedWindows];
|
||||
GQueue sorted = G_QUEUE_INIT;
|
||||
|
||||
self->key_window_is_foregin = FALSE;
|
||||
|
||||
for (id obj in array)
|
||||
{
|
||||
NSWindow *nswindow = (NSWindow *)obj;
|
||||
GdkMacosSurface *surface;
|
||||
|
||||
if ([nswindow isKeyWindow])
|
||||
self->key_window_is_foregin = !GDK_IS_MACOS_WINDOW (nswindow);
|
||||
|
||||
if (!GDK_IS_MACOS_WINDOW (nswindow))
|
||||
continue;
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "gdkmacossurface.h"
|
||||
|
||||
#import <OpenGL/OpenGL.h>
|
||||
#import <OpenGL/gl3.h>
|
||||
#import <OpenGL/gl.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
@@ -39,14 +39,16 @@ struct _GdkMacosGLContext
|
||||
GdkGLContext parent_instance;
|
||||
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
CGLContextObj cgl_context;
|
||||
NSOpenGLContext *gl_context;
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
|
||||
GLuint texture;
|
||||
GLuint target;
|
||||
GLuint fbo;
|
||||
NSWindow *dummy_window;
|
||||
NSView *dummy_view;
|
||||
|
||||
guint last_opaque : 1;
|
||||
cairo_region_t *damage;
|
||||
|
||||
guint is_attached : 1;
|
||||
guint needs_resize : 1;
|
||||
};
|
||||
|
||||
struct _GdkMacosGLContextClass
|
||||
@@ -54,6 +56,7 @@ struct _GdkMacosGLContextClass
|
||||
GdkGLContextClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_MACOS_GL_CONTEXT_PRIVATE_H__ */
|
||||
|
||||
+264
-388
@@ -19,139 +19,20 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gdkconfig.h"
|
||||
|
||||
#include <OpenGL/gl3.h>
|
||||
#include <OpenGL/CGLIOSurface.h>
|
||||
#include <QuartzCore/QuartzCore.h>
|
||||
|
||||
#include "gdkmacosbuffer-private.h"
|
||||
#include "gdkmacosglcontext-private.h"
|
||||
#include "gdkmacossurface-private.h"
|
||||
#include "gdkmacostoplevelsurface-private.h"
|
||||
|
||||
#include "gdkintl.h"
|
||||
|
||||
#include <OpenGL/gl.h>
|
||||
|
||||
#import "GdkMacosGLView.h"
|
||||
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
|
||||
G_DEFINE_TYPE (GdkMacosGLContext, gdk_macos_gl_context, GDK_TYPE_GL_CONTEXT)
|
||||
|
||||
#define CHECK(error,cgl_error) _CHECK_CGL(error, G_STRLOC, cgl_error)
|
||||
static inline gboolean
|
||||
_CHECK_CGL (GError **error,
|
||||
const char *location,
|
||||
CGLError cgl_error)
|
||||
{
|
||||
if (cgl_error != kCGLNoError)
|
||||
{
|
||||
g_log ("Core OpenGL",
|
||||
G_LOG_LEVEL_CRITICAL,
|
||||
"%s: %s",
|
||||
location, CGLErrorString (cgl_error));
|
||||
g_set_error (error,
|
||||
GDK_GL_ERROR,
|
||||
GDK_GL_ERROR_NOT_AVAILABLE,
|
||||
"%s",
|
||||
CGLErrorString (cgl_error));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Apple's OpenGL implementation does not contain the extension to
|
||||
* perform log handler callbacks when errors occur. Therefore, to aid in
|
||||
* tracking down issues we have a CHECK_GL() macro that can wrap GL
|
||||
* calls and check for an error afterwards.
|
||||
*
|
||||
* To make this easier, we use a statement expression, as this will
|
||||
* always be using something GCC-compatible on macOS.
|
||||
*/
|
||||
#define CHECK_GL(error,func) _CHECK_GL(error, G_STRLOC, ({ func; glGetError(); }))
|
||||
static inline gboolean
|
||||
_CHECK_GL (GError **error,
|
||||
const char *location,
|
||||
GLenum gl_error)
|
||||
{
|
||||
const char *msg;
|
||||
|
||||
switch (gl_error)
|
||||
{
|
||||
case GL_INVALID_ENUM:
|
||||
msg = "invalid enum";
|
||||
break;
|
||||
case GL_INVALID_VALUE:
|
||||
msg = "invalid value";
|
||||
break;
|
||||
case GL_INVALID_OPERATION:
|
||||
msg = "invalid operation";
|
||||
break;
|
||||
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
||||
msg = "invalid framebuffer operation";
|
||||
break;
|
||||
case GL_OUT_OF_MEMORY:
|
||||
msg = "out of memory";
|
||||
break;
|
||||
default:
|
||||
msg = "unknown error";
|
||||
break;
|
||||
}
|
||||
|
||||
if (gl_error != GL_NO_ERROR)
|
||||
{
|
||||
g_log ("OpenGL",
|
||||
G_LOG_LEVEL_CRITICAL,
|
||||
"%s: %s", location, msg);
|
||||
if (error != NULL)
|
||||
g_set_error (error,
|
||||
GDK_GL_ERROR,
|
||||
GDK_GL_ERROR_NOT_AVAILABLE,
|
||||
"%s", msg);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
check_framebuffer_status (GLenum target)
|
||||
{
|
||||
switch (glCheckFramebufferStatus (target))
|
||||
{
|
||||
case GL_FRAMEBUFFER_COMPLETE:
|
||||
return TRUE;
|
||||
|
||||
case GL_FRAMEBUFFER_UNDEFINED:
|
||||
g_critical ("Framebuffer is undefined");
|
||||
return FALSE;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||
g_critical ("Framebuffer has incomplete attachment");
|
||||
return FALSE;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||
g_critical ("Framebuffer has missing attachment");
|
||||
return FALSE;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
|
||||
g_critical ("Framebuffer has incomplete draw buffer");
|
||||
return FALSE;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
|
||||
g_critical ("Framebuffer has incomplete read buffer");
|
||||
return FALSE;
|
||||
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
g_critical ("Framebuffer is unsupported");
|
||||
return FALSE;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
|
||||
g_critical ("Framebuffer has incomplete multisample");
|
||||
return FALSE;
|
||||
|
||||
default:
|
||||
g_critical ("Framebuffer has unknown error");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_renderer_name (GLint id)
|
||||
{
|
||||
@@ -191,165 +72,97 @@ get_renderer_name (GLint id)
|
||||
}
|
||||
}
|
||||
|
||||
static GLuint
|
||||
create_texture (CGLContextObj cgl_context,
|
||||
GLuint target,
|
||||
IOSurfaceRef io_surface,
|
||||
guint width,
|
||||
guint height)
|
||||
{
|
||||
GLuint texture = 0;
|
||||
|
||||
if (!CHECK_GL (NULL, glActiveTexture (GL_TEXTURE0)) ||
|
||||
!CHECK_GL (NULL, glGenTextures (1, &texture)) ||
|
||||
!CHECK_GL (NULL, glBindTexture (target, texture)) ||
|
||||
!CHECK (NULL, CGLTexImageIOSurface2D (cgl_context,
|
||||
target,
|
||||
GL_RGBA,
|
||||
width,
|
||||
height,
|
||||
GL_BGRA,
|
||||
GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
io_surface,
|
||||
0)) ||
|
||||
!CHECK_GL (NULL, glTexParameteri (target, GL_TEXTURE_BASE_LEVEL, 0)) ||
|
||||
!CHECK_GL (NULL, glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST)) ||
|
||||
!CHECK_GL (NULL, glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST)) ||
|
||||
!CHECK_GL (NULL, glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)) ||
|
||||
!CHECK_GL (NULL, glTexParameteri (target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE)) ||
|
||||
!CHECK_GL (NULL, glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)) ||
|
||||
!CHECK_GL (NULL, glBindTexture (target, 0)))
|
||||
{
|
||||
glDeleteTextures (1, &texture);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_macos_gl_context_allocate (GdkMacosGLContext *self)
|
||||
{
|
||||
GdkSurface *surface;
|
||||
GLint opaque;
|
||||
|
||||
g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
|
||||
g_assert (self->cgl_context != NULL);
|
||||
g_assert (self->target != 0);
|
||||
g_assert (self->texture != 0 || self->fbo == 0);
|
||||
g_assert (self->fbo != 0 || self->texture == 0);
|
||||
|
||||
if (!(surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (self))))
|
||||
return;
|
||||
|
||||
/* Alter to an opaque surface if necessary */
|
||||
opaque = _gdk_macos_surface_is_opaque (GDK_MACOS_SURFACE (surface));
|
||||
if (opaque != self->last_opaque)
|
||||
{
|
||||
self->last_opaque = !!opaque;
|
||||
if (!CHECK (NULL, CGLSetParameter (self->cgl_context, kCGLCPSurfaceOpacity, &opaque)))
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->texture == 0)
|
||||
{
|
||||
GdkMacosBuffer *buffer;
|
||||
IOSurfaceRef io_surface;
|
||||
guint width;
|
||||
guint height;
|
||||
GLuint texture = 0;
|
||||
GLuint fbo = 0;
|
||||
|
||||
buffer = _gdk_macos_surface_get_buffer (GDK_MACOS_SURFACE (surface));
|
||||
io_surface = _gdk_macos_buffer_get_native (buffer);
|
||||
width = _gdk_macos_buffer_get_width (buffer);
|
||||
height = _gdk_macos_buffer_get_height (buffer);
|
||||
|
||||
/* We might need to re-enforce our CGL context here to keep
|
||||
* video playing correctly. Something, somewhere, might have
|
||||
* changed the context without touching GdkGLContext.
|
||||
*
|
||||
* Without this, video_player often breaks in gtk-demo when using
|
||||
* the GStreamer backend.
|
||||
*/
|
||||
CGLSetCurrentContext (self->cgl_context);
|
||||
|
||||
if (!(texture = create_texture (self->cgl_context, self->target, io_surface, width, height)) ||
|
||||
!CHECK_GL (NULL, glGenFramebuffers (1, &fbo)) ||
|
||||
!CHECK_GL (NULL, glBindFramebuffer (GL_FRAMEBUFFER, fbo)) ||
|
||||
!CHECK_GL (NULL, glBindTexture (self->target, texture)) ||
|
||||
!CHECK_GL (NULL, glFramebufferTexture2D (GL_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0,
|
||||
self->target,
|
||||
texture,
|
||||
0)) ||
|
||||
!check_framebuffer_status (GL_FRAMEBUFFER))
|
||||
{
|
||||
glDeleteFramebuffers (1, &fbo);
|
||||
glDeleteTextures (1, &texture);
|
||||
return;
|
||||
}
|
||||
|
||||
glBindTexture (self->target, 0);
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, 0);
|
||||
|
||||
self->texture = texture;
|
||||
self->fbo = fbo;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_macos_gl_context_release (GdkMacosGLContext *self)
|
||||
static NSOpenGLContext *
|
||||
get_ns_open_gl_context (GdkMacosGLContext *self,
|
||||
GError **error)
|
||||
{
|
||||
g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
|
||||
g_assert (self->texture != 0 || self->fbo == 0);
|
||||
g_assert (self->fbo != 0 || self->texture == 0);
|
||||
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, 0);
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glBindTexture (self->target, 0);
|
||||
|
||||
if (self->fbo != 0)
|
||||
if (self->gl_context == nil)
|
||||
{
|
||||
glDeleteFramebuffers (1, &self->fbo);
|
||||
self->fbo = 0;
|
||||
g_set_error_literal (error,
|
||||
GDK_GL_ERROR,
|
||||
GDK_GL_ERROR_NOT_AVAILABLE,
|
||||
"Cannot access NSOpenGLContext for surface");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (self->texture != 0)
|
||||
{
|
||||
glDeleteTextures (1, &self->texture);
|
||||
self->texture = 0;
|
||||
}
|
||||
return self->gl_context;
|
||||
}
|
||||
|
||||
static CGLPixelFormatObj
|
||||
static NSOpenGLPixelFormat *
|
||||
create_pixel_format (int major,
|
||||
int minor,
|
||||
GError **error)
|
||||
{
|
||||
CGLPixelFormatAttribute attrs[] = {
|
||||
kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute)kCGLOGLPVersion_Legacy,
|
||||
kCGLPFAAllowOfflineRenderers, /* allow sharing across GPUs */
|
||||
kCGLPFADepthSize, 0,
|
||||
kCGLPFAStencilSize, 0,
|
||||
kCGLPFAColorSize, 24,
|
||||
kCGLPFAAlphaSize, 8,
|
||||
NSOpenGLPixelFormatAttribute attrs[] = {
|
||||
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersionLegacy,
|
||||
NSOpenGLPFAAccelerated,
|
||||
NSOpenGLPFADoubleBuffer,
|
||||
NSOpenGLPFABackingStore,
|
||||
NSOpenGLPFAColorSize, 24,
|
||||
NSOpenGLPFAAlphaSize, 8,
|
||||
0
|
||||
};
|
||||
CGLPixelFormatObj format = NULL;
|
||||
GLint n_format = 1;
|
||||
|
||||
if (major == 3 && minor == 2)
|
||||
attrs[1] = (CGLPixelFormatAttribute)kCGLOGLPVersion_GL3_Core;
|
||||
attrs[1] = NSOpenGLProfileVersion3_2Core;
|
||||
else if (major == 4 && minor == 1)
|
||||
attrs[1] = (CGLPixelFormatAttribute)kCGLOGLPVersion_GL4_Core;
|
||||
attrs[1] = NSOpenGLProfileVersion4_1Core;
|
||||
|
||||
if (!CHECK (error, CGLChoosePixelFormat (attrs, &format, &n_format)))
|
||||
return NULL;
|
||||
NSOpenGLPixelFormat *format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
|
||||
|
||||
if (format == NULL)
|
||||
g_set_error (error,
|
||||
GDK_GL_ERROR,
|
||||
GDK_GL_ERROR_NOT_AVAILABLE,
|
||||
"Failed to create pixel format");
|
||||
|
||||
return g_steal_pointer (&format);
|
||||
}
|
||||
|
||||
static NSView *
|
||||
ensure_gl_view (GdkMacosGLContext *self)
|
||||
{
|
||||
GdkMacosSurface *surface;
|
||||
NSWindow *nswindow;
|
||||
NSView *nsview;
|
||||
|
||||
g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
|
||||
|
||||
surface = GDK_MACOS_SURFACE (gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (self)));
|
||||
nsview = _gdk_macos_surface_get_view (surface);
|
||||
nswindow = _gdk_macos_surface_get_native (surface);
|
||||
|
||||
if G_UNLIKELY (!GDK_IS_MACOS_GL_VIEW (nsview))
|
||||
{
|
||||
NSRect frame;
|
||||
|
||||
frame = [[nswindow contentView] bounds];
|
||||
nsview = [[GdkMacosGLView alloc] initWithFrame:frame];
|
||||
[nsview setWantsBestResolutionOpenGLSurface:YES];
|
||||
[nsview setPostsFrameChangedNotifications: YES];
|
||||
[nsview setNeedsDisplay:YES];
|
||||
[nswindow setContentView:nsview];
|
||||
[nswindow makeFirstResponder:nsview];
|
||||
[nsview release];
|
||||
|
||||
if (self->dummy_view != NULL)
|
||||
{
|
||||
NSView *dummy_view = g_steal_pointer (&self->dummy_view);
|
||||
[dummy_view release];
|
||||
}
|
||||
|
||||
if (self->dummy_window != NULL)
|
||||
{
|
||||
NSWindow *dummy_window = g_steal_pointer (&self->dummy_window);
|
||||
[dummy_window release];
|
||||
}
|
||||
}
|
||||
|
||||
return [nswindow contentView];
|
||||
}
|
||||
|
||||
static GdkGLAPI
|
||||
gdk_macos_gl_context_real_realize (GdkGLContext *context,
|
||||
GError **error)
|
||||
@@ -357,128 +170,195 @@ gdk_macos_gl_context_real_realize (GdkGLContext *context,
|
||||
GdkMacosGLContext *self = (GdkMacosGLContext *)context;
|
||||
GdkSurface *surface;
|
||||
GdkDisplay *display;
|
||||
CGLPixelFormatObj pixelFormat;
|
||||
CGLContextObj shared_gl_context = nil;
|
||||
NSOpenGLContext *shared_gl_context = nil;
|
||||
NSOpenGLContext *gl_context;
|
||||
NSOpenGLPixelFormat *pixelFormat;
|
||||
CGLContextObj cgl_context;
|
||||
CGLContextObj existing;
|
||||
GdkGLContext *shared;
|
||||
NSOpenGLContext *existing;
|
||||
GLint sync_to_framerate = 1;
|
||||
GLint validate = 0;
|
||||
GLint renderer_id = 0;
|
||||
GLint swapRect[4];
|
||||
int major, minor;
|
||||
|
||||
g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
|
||||
|
||||
if (self->cgl_context != nil)
|
||||
if (self->gl_context != nil)
|
||||
return GDK_GL_API_GL;
|
||||
|
||||
if (!gdk_gl_context_is_api_allowed (context, GDK_GL_API_GL, error))
|
||||
return 0;
|
||||
|
||||
existing = CGLGetCurrentContext ();
|
||||
existing = [NSOpenGLContext currentContext];
|
||||
|
||||
gdk_gl_context_get_required_version (context, &major, &minor);
|
||||
|
||||
surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (context));
|
||||
display = gdk_gl_context_get_display (context);
|
||||
shared = gdk_display_get_gl_context (display);
|
||||
|
||||
if (shared != NULL)
|
||||
{
|
||||
if (!(shared_gl_context = GDK_MACOS_GL_CONTEXT (shared)->cgl_context))
|
||||
{
|
||||
g_set_error_literal (error,
|
||||
GDK_GL_ERROR,
|
||||
GDK_GL_ERROR_NOT_AVAILABLE,
|
||||
"Cannot access shared CGLContextObj");
|
||||
return 0;
|
||||
}
|
||||
if (!(shared_gl_context = get_ns_open_gl_context (GDK_MACOS_GL_CONTEXT (shared), error)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
GDK_DISPLAY_NOTE (display,
|
||||
OPENGL,
|
||||
g_message ("Creating CGLContextObj (version %d.%d)",
|
||||
g_message ("Creating NSOpenGLContext (version %d.%d)",
|
||||
major, minor));
|
||||
|
||||
if (!(pixelFormat = create_pixel_format (major, minor, error)))
|
||||
return 0;
|
||||
|
||||
if (!CHECK (error, CGLCreateContext (pixelFormat, shared_gl_context, &cgl_context)))
|
||||
gl_context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
|
||||
shareContext:shared_gl_context];
|
||||
|
||||
[pixelFormat release];
|
||||
|
||||
if (gl_context == nil)
|
||||
{
|
||||
CGLReleasePixelFormat (pixelFormat);
|
||||
g_set_error_literal (error,
|
||||
GDK_GL_ERROR,
|
||||
GDK_GL_ERROR_NOT_AVAILABLE,
|
||||
"Failed to create NSOpenGLContext");
|
||||
return 0;
|
||||
}
|
||||
|
||||
CGLSetCurrentContext (cgl_context);
|
||||
CGLReleasePixelFormat (pixelFormat);
|
||||
cgl_context = [gl_context CGLContextObj];
|
||||
|
||||
swapRect[0] = 0;
|
||||
swapRect[1] = 0;
|
||||
swapRect[2] = surface ? surface->width : 0;
|
||||
swapRect[3] = surface ? surface->height : 0;
|
||||
|
||||
CGLSetParameter (cgl_context, kCGLCPSwapRectangle, swapRect);
|
||||
CGLSetParameter (cgl_context, kCGLCPSwapInterval, &sync_to_framerate);
|
||||
|
||||
CGLEnable (cgl_context, kCGLCESwapRectangle);
|
||||
if (validate)
|
||||
CHECK (NULL, CGLEnable (cgl_context, kCGLCEStateValidation));
|
||||
CGLEnable (cgl_context, kCGLCEStateValidation);
|
||||
|
||||
if (!CHECK (error, CGLSetParameter (cgl_context, kCGLCPSwapInterval, &sync_to_framerate)) ||
|
||||
!CHECK (error, CGLGetParameter (cgl_context, kCGLCPCurrentRendererID, &renderer_id)))
|
||||
{
|
||||
CGLReleaseContext (cgl_context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (context));
|
||||
|
||||
if (surface != NULL)
|
||||
{
|
||||
/* Setup initial swap rectangle. We might not actually need this
|
||||
* anymore though as we are rendering to an IOSurface and we have
|
||||
* a scissor clip when rendering to it.
|
||||
*/
|
||||
swapRect[0] = 0;
|
||||
swapRect[1] = 0;
|
||||
swapRect[2] = surface->width;
|
||||
swapRect[3] = surface->height;
|
||||
CGLSetParameter (cgl_context, kCGLCPSwapRectangle, swapRect);
|
||||
CGLEnable (cgl_context, kCGLCESwapRectangle);
|
||||
}
|
||||
self->dummy_window = [[NSWindow alloc] initWithContentRect:NSZeroRect
|
||||
styleMask:0
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO
|
||||
screen:nil];
|
||||
self->dummy_view = [[NSView alloc] initWithFrame:NSZeroRect];
|
||||
[self->dummy_window setContentView:self->dummy_view];
|
||||
[gl_context setView:self->dummy_view];
|
||||
|
||||
GLint renderer_id = 0;
|
||||
[gl_context getValues:&renderer_id forParameter:NSOpenGLContextParameterCurrentRendererID];
|
||||
GDK_DISPLAY_NOTE (display,
|
||||
OPENGL,
|
||||
g_message ("Created CGLContextObj@%p using %s",
|
||||
cgl_context,
|
||||
g_message ("Created NSOpenGLContext[%p] using %s",
|
||||
gl_context,
|
||||
get_renderer_name (renderer_id)));
|
||||
|
||||
self->cgl_context = g_steal_pointer (&cgl_context);
|
||||
self->gl_context = g_steal_pointer (&gl_context);
|
||||
|
||||
if (existing != NULL)
|
||||
CGLSetCurrentContext (existing);
|
||||
[existing makeCurrentContext];
|
||||
|
||||
return GDK_GL_API_GL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
opaque_region_covers_surface (GdkMacosGLContext *self)
|
||||
{
|
||||
GdkSurface *surface;
|
||||
cairo_region_t *region;
|
||||
|
||||
g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
|
||||
|
||||
surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (self));
|
||||
region = GDK_MACOS_SURFACE (surface)->opaque_region;
|
||||
|
||||
if (region != NULL &&
|
||||
cairo_region_num_rectangles (region) == 1)
|
||||
{
|
||||
cairo_rectangle_int_t extents;
|
||||
|
||||
cairo_region_get_extents (region, &extents);
|
||||
|
||||
if (extents.x == 0 &&
|
||||
extents.y == 0 &&
|
||||
extents.width == surface->width &&
|
||||
extents.height == surface->height)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_macos_gl_context_begin_frame (GdkDrawContext *context,
|
||||
gboolean prefers_high_depth,
|
||||
cairo_region_t *region)
|
||||
cairo_region_t *painted)
|
||||
{
|
||||
GdkMacosGLContext *self = (GdkMacosGLContext *)context;
|
||||
GdkMacosBuffer *buffer;
|
||||
cairo_region_t *copy;
|
||||
GdkSurface *surface;
|
||||
|
||||
g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
|
||||
|
||||
copy = cairo_region_copy (region);
|
||||
surface = gdk_draw_context_get_surface (context);
|
||||
buffer = _gdk_macos_surface_get_buffer (GDK_MACOS_SURFACE (surface));
|
||||
|
||||
_gdk_macos_buffer_set_flipped (buffer, TRUE);
|
||||
_gdk_macos_buffer_set_damage (buffer, region);
|
||||
g_clear_pointer (&self->damage, cairo_region_destroy);
|
||||
self->damage = cairo_region_copy (painted);
|
||||
|
||||
/* Create our render target and bind it */
|
||||
gdk_gl_context_make_current (GDK_GL_CONTEXT (self));
|
||||
gdk_macos_gl_context_allocate (self);
|
||||
/* If begin frame is called, that means we are trying to draw to
|
||||
* the NSWindow using our view. That might be a GdkMacosCairoView
|
||||
* but we need it to be a GL view. Also, only in this case do we
|
||||
* want to replace our damage region for the next frame (to avoid
|
||||
* doing it multiple times).
|
||||
*/
|
||||
ensure_gl_view (self);
|
||||
|
||||
GDK_DRAW_CONTEXT_CLASS (gdk_macos_gl_context_parent_class)->begin_frame (context, prefers_high_depth, region);
|
||||
if (self->needs_resize)
|
||||
{
|
||||
CGLContextObj cgl_context = [self->gl_context CGLContextObj];
|
||||
GLint opaque;
|
||||
|
||||
gdk_gl_context_make_current (GDK_GL_CONTEXT (self));
|
||||
CHECK_GL (NULL, glBindFramebuffer (GL_FRAMEBUFFER, self->fbo));
|
||||
self->needs_resize = FALSE;
|
||||
|
||||
if (self->dummy_view != NULL)
|
||||
{
|
||||
NSRect frame = NSMakeRect (0, 0, surface->width, surface->height);
|
||||
|
||||
[self->dummy_window setFrame:frame display:NO];
|
||||
[self->dummy_view setFrame:frame];
|
||||
}
|
||||
|
||||
/* Possibly update our opaque setting depending on a resize. We can
|
||||
* rely on getting a resize if decoarated is changed, so this reduces
|
||||
* how much we adjust the parameter.
|
||||
*/
|
||||
if (GDK_IS_MACOS_TOPLEVEL_SURFACE (surface))
|
||||
opaque = GDK_MACOS_TOPLEVEL_SURFACE (surface)->decorated;
|
||||
else
|
||||
opaque = FALSE;
|
||||
|
||||
/* If we are maximized, we might be able to make it opaque */
|
||||
if (opaque == FALSE)
|
||||
opaque = opaque_region_covers_surface (self);
|
||||
|
||||
CGLSetParameter (cgl_context, kCGLCPSurfaceOpacity, &opaque);
|
||||
|
||||
[self->gl_context update];
|
||||
}
|
||||
|
||||
GDK_DRAW_CONTEXT_CLASS (gdk_macos_gl_context_parent_class)->begin_frame (context, prefers_high_depth, painted);
|
||||
|
||||
if (!self->is_attached)
|
||||
{
|
||||
NSView *nsview = _gdk_macos_surface_get_view (GDK_MACOS_SURFACE (surface));
|
||||
|
||||
g_assert (self->gl_context != NULL);
|
||||
g_assert (GDK_IS_MACOS_GL_VIEW (nsview));
|
||||
|
||||
[(GdkMacosGLView *)nsview setOpenGLContext:self->gl_context];
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -486,40 +366,32 @@ gdk_macos_gl_context_end_frame (GdkDrawContext *context,
|
||||
cairo_region_t *painted)
|
||||
{
|
||||
GdkMacosGLContext *self = GDK_MACOS_GL_CONTEXT (context);
|
||||
GdkSurface *surface;
|
||||
cairo_rectangle_int_t flush_rect;
|
||||
GLint swapRect[4];
|
||||
|
||||
g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
|
||||
g_assert (self->cgl_context != nil);
|
||||
g_assert (self->gl_context != nil);
|
||||
|
||||
GDK_DRAW_CONTEXT_CLASS (gdk_macos_gl_context_parent_class)->end_frame (context, painted);
|
||||
|
||||
surface = gdk_draw_context_get_surface (context);
|
||||
gdk_gl_context_make_current (GDK_GL_CONTEXT (self));
|
||||
if (!self->is_attached)
|
||||
{
|
||||
GdkSurface *surface = gdk_draw_context_get_surface (context);
|
||||
CGLContextObj glctx = [self->gl_context CGLContextObj];
|
||||
cairo_rectangle_int_t flush_rect;
|
||||
GLint swapRect[4];
|
||||
|
||||
/* Coordinates are in display coordinates, where as flush_rect is
|
||||
* in GDK coordinates. Must flip Y to match display coordinates where
|
||||
* 0,0 is the bottom-left corner.
|
||||
*/
|
||||
cairo_region_get_extents (painted, &flush_rect);
|
||||
swapRect[0] = flush_rect.x; /* left */
|
||||
swapRect[1] = surface->height - flush_rect.y; /* bottom */
|
||||
swapRect[2] = flush_rect.width; /* width */
|
||||
swapRect[3] = flush_rect.height; /* height */
|
||||
CGLSetParameter (self->cgl_context, kCGLCPSwapRectangle, swapRect);
|
||||
/* Coordinates are in display coordinates, where as flush_rect is
|
||||
* in GDK coordinates. Must flip Y to match display coordinates where
|
||||
* 0,0 is the bottom-left corner.
|
||||
*/
|
||||
cairo_region_get_extents (painted, &flush_rect);
|
||||
swapRect[0] = flush_rect.x; /* left */
|
||||
swapRect[1] = surface->height - flush_rect.y; /* bottom */
|
||||
swapRect[2] = flush_rect.width; /* width */
|
||||
swapRect[3] = flush_rect.height; /* height */
|
||||
CGLSetParameter (glctx, kCGLCPSwapRectangle, swapRect);
|
||||
|
||||
gdk_macos_gl_context_release (self);
|
||||
|
||||
glFlush ();
|
||||
|
||||
/* Begin a Core Animation transaction so that all changes we
|
||||
* make within the window are seen atomically.
|
||||
*/
|
||||
[CATransaction begin];
|
||||
[CATransaction setDisableActions:YES];
|
||||
_gdk_macos_surface_swap_buffers (GDK_MACOS_SURFACE (surface), painted);
|
||||
[CATransaction commit];
|
||||
[self->gl_context flushBuffer];
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -529,21 +401,31 @@ gdk_macos_gl_context_surface_resized (GdkDrawContext *draw_context)
|
||||
|
||||
g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
|
||||
|
||||
if (self->cgl_context != NULL)
|
||||
CGLUpdateContext (self->cgl_context);
|
||||
self->needs_resize = TRUE;
|
||||
|
||||
g_clear_pointer (&self->damage, cairo_region_destroy);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_macos_gl_context_clear_current (GdkGLContext *context)
|
||||
{
|
||||
GdkMacosGLContext *self = GDK_MACOS_GL_CONTEXT (context);
|
||||
NSOpenGLContext *current;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_MACOS_GL_CONTEXT (self), FALSE);
|
||||
|
||||
if (self->cgl_context == CGLGetCurrentContext ())
|
||||
current = [NSOpenGLContext currentContext];
|
||||
|
||||
if (self->gl_context == current)
|
||||
{
|
||||
glFlush ();
|
||||
CGLSetCurrentContext (NULL);
|
||||
/* The OpenGL mac programming guide suggests that glFlush() is called
|
||||
* before switching current contexts to ensure that the drawing commands
|
||||
* are submitted.
|
||||
*/
|
||||
if (current != NULL)
|
||||
glFlush ();
|
||||
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@@ -554,26 +436,22 @@ gdk_macos_gl_context_make_current (GdkGLContext *context,
|
||||
gboolean surfaceless)
|
||||
{
|
||||
GdkMacosGLContext *self = GDK_MACOS_GL_CONTEXT (context);
|
||||
CGLContextObj current;
|
||||
NSOpenGLContext *current;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_MACOS_GL_CONTEXT (self), FALSE);
|
||||
|
||||
current = CGLGetCurrentContext ();
|
||||
current = [NSOpenGLContext currentContext];
|
||||
|
||||
if (self->cgl_context != current)
|
||||
if (self->gl_context != current)
|
||||
{
|
||||
/* The OpenGL mac programming guide suggests that glFlush() is called
|
||||
* before switching current contexts to ensure that the drawing commands
|
||||
* are submitted.
|
||||
*
|
||||
* TODO: investigate if we need this because we may switch contexts
|
||||
* durring composition and only need it when returning to a
|
||||
* previous context that uses the other context.
|
||||
*/
|
||||
if (current != NULL)
|
||||
glFlush ();
|
||||
|
||||
CGLSetCurrentContext (self->cgl_context);
|
||||
[self->gl_context makeCurrentContext];
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@@ -583,45 +461,45 @@ static cairo_region_t *
|
||||
gdk_macos_gl_context_get_damage (GdkGLContext *context)
|
||||
{
|
||||
GdkMacosGLContext *self = (GdkMacosGLContext *)context;
|
||||
const cairo_region_t *damage;
|
||||
GdkMacosBuffer *buffer;
|
||||
GdkSurface *surface;
|
||||
|
||||
g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
|
||||
|
||||
if ((surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (context))) &&
|
||||
(buffer = GDK_MACOS_SURFACE (surface)->front) &&
|
||||
(damage = _gdk_macos_buffer_get_damage (buffer)))
|
||||
return cairo_region_copy (damage);
|
||||
if (self->damage != NULL)
|
||||
return cairo_region_copy (self->damage);
|
||||
|
||||
return GDK_GL_CONTEXT_CLASS (gdk_macos_gl_context_parent_class)->get_damage (context);
|
||||
}
|
||||
|
||||
static guint
|
||||
gdk_macos_gl_context_get_default_framebuffer (GdkGLContext *context)
|
||||
{
|
||||
return GDK_MACOS_GL_CONTEXT (context)->fbo;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_macos_gl_context_dispose (GObject *gobject)
|
||||
{
|
||||
GdkMacosGLContext *self = GDK_MACOS_GL_CONTEXT (gobject);
|
||||
|
||||
self->texture = 0;
|
||||
self->fbo = 0;
|
||||
|
||||
if (self->cgl_context != nil)
|
||||
if (self->dummy_view != nil)
|
||||
{
|
||||
CGLContextObj cgl_context = g_steal_pointer (&self->cgl_context);
|
||||
|
||||
if (cgl_context == CGLGetCurrentContext ())
|
||||
CGLSetCurrentContext (NULL);
|
||||
|
||||
CGLClearDrawable (cgl_context);
|
||||
CGLDestroyContext (cgl_context);
|
||||
NSView *nsview = g_steal_pointer (&self->dummy_view);
|
||||
[nsview release];
|
||||
}
|
||||
|
||||
if (self->dummy_window != nil)
|
||||
{
|
||||
NSWindow *nswindow = g_steal_pointer (&self->dummy_window);
|
||||
[nswindow release];
|
||||
}
|
||||
|
||||
if (self->gl_context != nil)
|
||||
{
|
||||
NSOpenGLContext *gl_context = g_steal_pointer (&self->gl_context);
|
||||
|
||||
if (gl_context == [NSOpenGLContext currentContext])
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
|
||||
[gl_context clearDrawable];
|
||||
[gl_context release];
|
||||
}
|
||||
|
||||
g_clear_pointer (&self->damage, cairo_region_destroy);
|
||||
|
||||
G_OBJECT_CLASS (gdk_macos_gl_context_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
@@ -642,7 +520,6 @@ gdk_macos_gl_context_class_init (GdkMacosGLContextClass *klass)
|
||||
gl_class->clear_current = gdk_macos_gl_context_clear_current;
|
||||
gl_class->make_current = gdk_macos_gl_context_make_current;
|
||||
gl_class->realize = gdk_macos_gl_context_real_realize;
|
||||
gl_class->get_default_framebuffer = gdk_macos_gl_context_get_default_framebuffer;
|
||||
|
||||
gl_class->backend_type = GDK_GL_CGL;
|
||||
}
|
||||
@@ -650,7 +527,6 @@ gdk_macos_gl_context_class_init (GdkMacosGLContextClass *klass)
|
||||
static void
|
||||
gdk_macos_gl_context_init (GdkMacosGLContext *self)
|
||||
{
|
||||
self->target = GL_TEXTURE_RECTANGLE;
|
||||
}
|
||||
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
|
||||
@@ -24,25 +24,15 @@
|
||||
|
||||
#include "gdkmacosdisplay.h"
|
||||
#include "gdkmacosmonitor.h"
|
||||
#include "gdkmacossurface.h"
|
||||
|
||||
#include "gdkmonitorprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
char *_gdk_macos_monitor_get_localized_name (NSScreen *screen);
|
||||
char *_gdk_macos_monitor_get_connector_name (CGDirectDisplayID screen_id);
|
||||
GdkMacosMonitor *_gdk_macos_monitor_new (GdkMacosDisplay *display,
|
||||
CGDirectDisplayID screen_id);
|
||||
CGDirectDisplayID _gdk_macos_monitor_get_screen_id (GdkMacosMonitor *self);
|
||||
gboolean _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self);
|
||||
CGColorSpaceRef _gdk_macos_monitor_copy_colorspace (GdkMacosMonitor *self);
|
||||
void _gdk_macos_monitor_add_frame_callback (GdkMacosMonitor *self,
|
||||
GdkMacosSurface *surface);
|
||||
void _gdk_macos_monitor_remove_frame_callback (GdkMacosMonitor *self,
|
||||
GdkMacosSurface *surface);
|
||||
void _gdk_macos_monitor_clamp (GdkMacosMonitor *self,
|
||||
GdkRectangle *area);
|
||||
GdkMacosMonitor *_gdk_macos_monitor_new (GdkMacosDisplay *display,
|
||||
CGDirectDisplayID screen_id);
|
||||
CGDirectDisplayID _gdk_macos_monitor_get_screen_id (GdkMacosMonitor *self);
|
||||
gboolean _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
+16
-175
@@ -22,21 +22,16 @@
|
||||
#include <gdk/gdk.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "gdkdisplaylinksource.h"
|
||||
#include "gdkmacosdisplay-private.h"
|
||||
#include "gdkmacosmonitor-private.h"
|
||||
#include "gdkmacossurface-private.h"
|
||||
#include "gdkmacosutils-private.h"
|
||||
|
||||
struct _GdkMacosMonitor
|
||||
{
|
||||
GdkMonitor parent_instance;
|
||||
CGDirectDisplayID screen_id;
|
||||
GdkDisplayLinkSource *display_link;
|
||||
NSRect workarea;
|
||||
GQueue awaiting_frames;
|
||||
guint has_opengl : 1;
|
||||
guint in_frame : 1;
|
||||
GdkMonitor parent_instance;
|
||||
CGDirectDisplayID screen_id;
|
||||
NSRect workarea;
|
||||
guint has_opengl : 1;
|
||||
};
|
||||
|
||||
struct _GdkMacosMonitorClass
|
||||
@@ -61,11 +56,13 @@ void
|
||||
gdk_macos_monitor_get_workarea (GdkMonitor *monitor,
|
||||
GdkRectangle *geometry)
|
||||
{
|
||||
GDK_BEGIN_MACOS_ALLOC_POOL;
|
||||
|
||||
GdkMacosMonitor *self = (GdkMacosMonitor *)monitor;
|
||||
int x, y;
|
||||
|
||||
g_return_if_fail (GDK_IS_MACOS_MONITOR (self));
|
||||
g_return_if_fail (geometry != NULL);
|
||||
g_assert (GDK_IS_MACOS_MONITOR (self));
|
||||
g_assert (geometry != NULL);
|
||||
|
||||
x = self->workarea.origin.x;
|
||||
y = self->workarea.origin.y + self->workarea.size.height;
|
||||
@@ -78,28 +75,13 @@ gdk_macos_monitor_get_workarea (GdkMonitor *monitor,
|
||||
geometry->y = y;
|
||||
geometry->width = self->workarea.size.width;
|
||||
geometry->height = self->workarea.size.height;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_macos_monitor_dispose (GObject *object)
|
||||
{
|
||||
GdkMacosMonitor *self = (GdkMacosMonitor *)object;
|
||||
|
||||
if (self->display_link)
|
||||
{
|
||||
g_source_destroy ((GSource *)self->display_link);
|
||||
g_clear_pointer ((GSource **)&self->display_link, g_source_unref);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (gdk_macos_monitor_parent_class)->dispose (object);
|
||||
GDK_END_MACOS_ALLOC_POOL;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_macos_monitor_class_init (GdkMacosMonitorClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = gdk_macos_monitor_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -160,8 +142,8 @@ GetSubpixelLayout (CGDirectDisplayID screen_id)
|
||||
return GDK_SUBPIXEL_LAYOUT_UNKNOWN;
|
||||
}
|
||||
|
||||
char *
|
||||
_gdk_macos_monitor_get_localized_name (NSScreen *screen)
|
||||
static char *
|
||||
GetLocalizedName (NSScreen *screen)
|
||||
{
|
||||
#ifdef AVAILABLE_MAC_OS_X_VERSION_10_15_AND_LATER
|
||||
GDK_BEGIN_MACOS_ALLOC_POOL;
|
||||
@@ -182,8 +164,8 @@ _gdk_macos_monitor_get_localized_name (NSScreen *screen)
|
||||
#endif
|
||||
}
|
||||
|
||||
char *
|
||||
_gdk_macos_monitor_get_connector_name (CGDirectDisplayID screen_id)
|
||||
static char *
|
||||
GetConnectorName (CGDirectDisplayID screen_id)
|
||||
{
|
||||
guint unit = CGDisplayUnitNumber (screen_id);
|
||||
return g_strdup_printf ("unit-%u", unit);
|
||||
@@ -210,68 +192,6 @@ find_screen (CGDirectDisplayID screen_id)
|
||||
return screen;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_macos_monitor_display_link_cb (GdkMacosMonitor *self)
|
||||
{
|
||||
gint64 presentation_time;
|
||||
gint64 refresh_interval;
|
||||
gint64 now;
|
||||
GList *iter;
|
||||
|
||||
g_assert (GDK_IS_MACOS_MONITOR (self));
|
||||
g_assert (!self->display_link->paused);
|
||||
|
||||
self->in_frame = TRUE;
|
||||
|
||||
presentation_time = self->display_link->presentation_time;
|
||||
refresh_interval = self->display_link->refresh_interval;
|
||||
now = g_source_get_time ((GSource *)self->display_link);
|
||||
|
||||
iter = self->awaiting_frames.head;
|
||||
|
||||
while (iter != NULL)
|
||||
{
|
||||
GdkMacosSurface *surface = iter->data;
|
||||
|
||||
g_assert (GDK_IS_MACOS_SURFACE (surface));
|
||||
|
||||
iter = iter->next;
|
||||
|
||||
g_queue_unlink (&self->awaiting_frames, &surface->frame);
|
||||
_gdk_macos_surface_frame_presented (surface, presentation_time, refresh_interval);
|
||||
}
|
||||
|
||||
if (self->awaiting_frames.length == 0 && !self->display_link->paused)
|
||||
gdk_display_link_source_pause (self->display_link);
|
||||
|
||||
self->in_frame = FALSE;
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_gdk_macos_monitor_reset_display_link (GdkMacosMonitor *self,
|
||||
CGDisplayModeRef mode)
|
||||
{
|
||||
GSource *source;
|
||||
|
||||
g_assert (GDK_IS_MACOS_MONITOR (self));
|
||||
|
||||
if (self->display_link)
|
||||
{
|
||||
g_source_destroy ((GSource *)self->display_link);
|
||||
g_clear_pointer ((GSource **)&self->display_link, g_source_unref);
|
||||
}
|
||||
|
||||
source = gdk_display_link_source_new (self->screen_id, mode);
|
||||
self->display_link = (GdkDisplayLinkSource *)source;
|
||||
g_source_set_callback (source,
|
||||
(GSourceFunc) gdk_macos_monitor_display_link_cb,
|
||||
self,
|
||||
NULL);
|
||||
g_source_attach (source, NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gdk_macos_monitor_reconfigure (GdkMacosMonitor *self)
|
||||
{
|
||||
@@ -306,8 +226,8 @@ _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self)
|
||||
pixel_width = CGDisplayModeGetPixelWidth (mode);
|
||||
has_opengl = CGDisplayUsesOpenGLAcceleration (self->screen_id);
|
||||
subpixel_layout = GetSubpixelLayout (self->screen_id);
|
||||
name = _gdk_macos_monitor_get_localized_name (screen);
|
||||
connector = _gdk_macos_monitor_get_connector_name (self->screen_id);
|
||||
name = GetLocalizedName (screen);
|
||||
connector = GetConnectorName (self->screen_id);
|
||||
|
||||
if (width != 0 && pixel_width != 0)
|
||||
scale_factor = MAX (1, pixel_width / width);
|
||||
@@ -325,7 +245,7 @@ _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self)
|
||||
* setting (which is also used by the frame clock).
|
||||
*/
|
||||
if (!(refresh_rate = CGDisplayModeGetRefreshRate (mode)))
|
||||
refresh_rate = 60 * 1000;
|
||||
refresh_rate = _gdk_macos_display_get_nominal_refresh_rate (display);
|
||||
|
||||
gdk_monitor_set_connector (GDK_MONITOR (self), connector);
|
||||
gdk_monitor_set_model (GDK_MONITOR (self), name);
|
||||
@@ -345,9 +265,6 @@ _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self)
|
||||
*/
|
||||
self->has_opengl = !!has_opengl;
|
||||
|
||||
/* Create a new display link to receive feedback about when to render */
|
||||
_gdk_macos_monitor_reset_display_link (self, mode);
|
||||
|
||||
CGDisplayModeRelease (mode);
|
||||
g_free (name);
|
||||
g_free (connector);
|
||||
@@ -381,79 +298,3 @@ _gdk_macos_monitor_get_screen_id (GdkMacosMonitor *self)
|
||||
|
||||
return self->screen_id;
|
||||
}
|
||||
|
||||
CGColorSpaceRef
|
||||
_gdk_macos_monitor_copy_colorspace (GdkMacosMonitor *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_MACOS_MONITOR (self), NULL);
|
||||
|
||||
return CGDisplayCopyColorSpace (self->screen_id);
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_monitor_add_frame_callback (GdkMacosMonitor *self,
|
||||
GdkMacosSurface *surface)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_MACOS_MONITOR (self));
|
||||
g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
|
||||
g_return_if_fail (surface->frame.data == (gpointer)surface);
|
||||
g_return_if_fail (surface->frame.prev == NULL);
|
||||
g_return_if_fail (surface->frame.next == NULL);
|
||||
g_return_if_fail (self->awaiting_frames.head != &surface->frame);
|
||||
g_return_if_fail (self->awaiting_frames.tail != &surface->frame);
|
||||
|
||||
/* Processing frames is always head to tail, so push to the
|
||||
* head so that we don't possibly re-enter this right after
|
||||
* adding to the queue.
|
||||
*/
|
||||
if (!queue_contains (&self->awaiting_frames, &surface->frame))
|
||||
{
|
||||
g_queue_push_head_link (&self->awaiting_frames, &surface->frame);
|
||||
|
||||
if (!self->in_frame && self->awaiting_frames.length == 1)
|
||||
gdk_display_link_source_unpause (self->display_link);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_monitor_remove_frame_callback (GdkMacosMonitor *self,
|
||||
GdkMacosSurface *surface)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_MACOS_MONITOR (self));
|
||||
g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
|
||||
g_return_if_fail (surface->frame.data == (gpointer)surface);
|
||||
|
||||
if (queue_contains (&self->awaiting_frames, &surface->frame))
|
||||
{
|
||||
g_queue_unlink (&self->awaiting_frames, &surface->frame);
|
||||
|
||||
if (!self->in_frame && self->awaiting_frames.length == 0)
|
||||
gdk_display_link_source_pause (self->display_link);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_monitor_clamp (GdkMacosMonitor *self,
|
||||
GdkRectangle *area)
|
||||
{
|
||||
GdkRectangle workarea;
|
||||
GdkRectangle geom;
|
||||
|
||||
g_return_if_fail (GDK_IS_MACOS_MONITOR (self));
|
||||
g_return_if_fail (area != NULL);
|
||||
|
||||
gdk_macos_monitor_get_workarea (GDK_MONITOR (self), &workarea);
|
||||
gdk_monitor_get_geometry (GDK_MONITOR (self), &geom);
|
||||
|
||||
if (area->x + area->width > workarea.x + workarea.width)
|
||||
area->x = workarea.x + workarea.width - area->width;
|
||||
|
||||
if (area->x < workarea.x)
|
||||
area->x = workarea.x;
|
||||
|
||||
if (area->y + area->height > workarea.y + workarea.height)
|
||||
area->y = workarea.y + workarea.height - area->height;
|
||||
|
||||
if (area->y < workarea.y)
|
||||
area->y = workarea.y;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ struct _GdkMacosPopupSurface
|
||||
{
|
||||
GdkMacosSurface parent_instance;
|
||||
GdkPopupLayout *layout;
|
||||
guint attached : 1;
|
||||
};
|
||||
|
||||
struct _GdkMacosPopupSurfaceClass
|
||||
@@ -88,9 +87,6 @@ gdk_macos_popup_surface_layout (GdkMacosPopupSurface *self,
|
||||
|
||||
gdk_surface_get_origin (GDK_SURFACE (self)->parent, &x, &y);
|
||||
|
||||
GDK_SURFACE (self)->x = final_rect.x;
|
||||
GDK_SURFACE (self)->y = final_rect.y;
|
||||
|
||||
x += final_rect.x;
|
||||
y += final_rect.y;
|
||||
|
||||
@@ -139,9 +135,6 @@ gdk_macos_popup_surface_present (GdkPopup *popup,
|
||||
if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self)))
|
||||
return TRUE;
|
||||
|
||||
if (!self->attached && GDK_SURFACE (self)->parent != NULL)
|
||||
_gdk_macos_popup_surface_attach_to_parent (self);
|
||||
|
||||
if (GDK_SURFACE (self)->autohide)
|
||||
{
|
||||
GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (popup));
|
||||
@@ -207,27 +200,10 @@ enum {
|
||||
LAST_PROP,
|
||||
};
|
||||
|
||||
static void
|
||||
_gdk_macos_popup_surface_hide (GdkSurface *surface)
|
||||
{
|
||||
GdkMacosPopupSurface *self = (GdkMacosPopupSurface *)surface;
|
||||
|
||||
g_assert (GDK_IS_MACOS_POPUP_SURFACE (self));
|
||||
|
||||
if (self->attached)
|
||||
_gdk_macos_popup_surface_detach_from_parent (self);
|
||||
|
||||
GDK_SURFACE_CLASS (_gdk_macos_popup_surface_parent_class)->hide (surface);
|
||||
}
|
||||
|
||||
static void
|
||||
_gdk_macos_popup_surface_finalize (GObject *object)
|
||||
{
|
||||
GdkMacosPopupSurface *self = (GdkMacosPopupSurface *)object;
|
||||
GdkSurface *parent = GDK_SURFACE (self)->parent;
|
||||
|
||||
if (parent != NULL)
|
||||
parent->children = g_list_remove (parent->children, self);
|
||||
|
||||
g_clear_object (&GDK_SURFACE (self)->parent);
|
||||
g_clear_pointer (&self->layout, gdk_popup_layout_unref);
|
||||
@@ -287,15 +263,12 @@ static void
|
||||
_gdk_macos_popup_surface_class_init (GdkMacosPopupSurfaceClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GdkSurfaceClass *surface_class = GDK_SURFACE_CLASS (klass);
|
||||
|
||||
object_class->finalize = _gdk_macos_popup_surface_finalize;
|
||||
object_class->get_property = _gdk_macos_popup_surface_get_property;
|
||||
object_class->set_property = _gdk_macos_popup_surface_set_property;
|
||||
|
||||
surface_class->hide = _gdk_macos_popup_surface_hide;
|
||||
|
||||
gdk_popup_install_properties (object_class, LAST_PROP);
|
||||
gdk_popup_install_properties (object_class, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -346,8 +319,14 @@ _gdk_macos_popup_surface_new (GdkMacosDisplay *display,
|
||||
[window setOpaque:NO];
|
||||
[window setBackgroundColor:[NSColor clearColor]];
|
||||
[window setDecorated:NO];
|
||||
[window setExcludedFromWindowsMenu:YES];
|
||||
|
||||
#if 0
|
||||
/* NOTE: We could set these to be popup level, but then
|
||||
* [NSApp orderedWindows] would not give us the windows
|
||||
* back with the stacking order applied.
|
||||
*/
|
||||
[window setLevel:NSPopUpMenuWindowLevel];
|
||||
#endif
|
||||
|
||||
self = g_object_new (GDK_TYPE_MACOS_POPUP_SURFACE,
|
||||
"display", display,
|
||||
@@ -378,8 +357,6 @@ _gdk_macos_popup_surface_attach_to_parent (GdkMacosPopupSurface *self)
|
||||
|
||||
[parent addChildWindow:window ordered:NSWindowAbove];
|
||||
|
||||
self->attached = TRUE;
|
||||
|
||||
_gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (surface->display));
|
||||
}
|
||||
}
|
||||
@@ -401,8 +378,6 @@ _gdk_macos_popup_surface_detach_from_parent (GdkMacosPopupSurface *self)
|
||||
|
||||
[parent removeChildWindow:window];
|
||||
|
||||
self->attached = FALSE;
|
||||
|
||||
_gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (surface->display));
|
||||
}
|
||||
}
|
||||
@@ -412,7 +387,9 @@ _gdk_macos_popup_surface_reposition (GdkMacosPopupSurface *self)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_MACOS_POPUP_SURFACE (self));
|
||||
|
||||
if (self->layout == NULL || GDK_SURFACE (self)->parent == NULL)
|
||||
if (self->layout == NULL ||
|
||||
!gdk_surface_get_mapped (GDK_SURFACE (self)) ||
|
||||
GDK_SURFACE (self)->parent == NULL)
|
||||
return;
|
||||
|
||||
gdk_macos_popup_surface_layout (self,
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
#include "gdksurfaceprivate.h"
|
||||
|
||||
#include "gdkmacosbuffer-private.h"
|
||||
#include "gdkmacosdisplay.h"
|
||||
#include "gdkmacossurface.h"
|
||||
|
||||
@@ -46,38 +45,23 @@ struct _GdkMacosSurface
|
||||
GList frame;
|
||||
|
||||
GdkMacosWindow *window;
|
||||
GdkMacosBuffer *buffer;
|
||||
GdkMacosBuffer *front;
|
||||
GPtrArray *monitors;
|
||||
GdkMonitor *best_monitor;
|
||||
cairo_region_t *input_region;
|
||||
cairo_region_t *opaque_region;
|
||||
char *title;
|
||||
|
||||
int root_x;
|
||||
int root_y;
|
||||
|
||||
struct {
|
||||
int root_x;
|
||||
int root_y;
|
||||
int width;
|
||||
int height;
|
||||
} next_layout;
|
||||
|
||||
int shadow_top;
|
||||
int shadow_right;
|
||||
int shadow_bottom;
|
||||
int shadow_left;
|
||||
|
||||
cairo_rectangle_int_t next_frame;
|
||||
|
||||
gint64 pending_frame_counter;
|
||||
|
||||
guint did_initial_present : 1;
|
||||
guint geometry_dirty : 1;
|
||||
guint next_frame_set : 1;
|
||||
guint show_on_next_swap : 1;
|
||||
guint in_change_monitor : 1;
|
||||
guint in_frame : 1;
|
||||
guint awaiting_frame : 1;
|
||||
};
|
||||
|
||||
struct _GdkMacosSurfaceClass
|
||||
@@ -85,70 +69,68 @@ struct _GdkMacosSurfaceClass
|
||||
GdkSurfaceClass parent_class;
|
||||
};
|
||||
|
||||
GdkMacosSurface *_gdk_macos_surface_new (GdkMacosDisplay *display,
|
||||
GdkSurfaceType surface_type,
|
||||
GdkSurface *parent,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height);
|
||||
NSWindow *_gdk_macos_surface_get_native (GdkMacosSurface *self);
|
||||
CGDirectDisplayID _gdk_macos_surface_get_screen_id (GdkMacosSurface *self);
|
||||
const char *_gdk_macos_surface_get_title (GdkMacosSurface *self);
|
||||
void _gdk_macos_surface_set_title (GdkMacosSurface *self,
|
||||
const char *title);
|
||||
void _gdk_macos_surface_get_shadow (GdkMacosSurface *self,
|
||||
int *top,
|
||||
int *right,
|
||||
int *bottom,
|
||||
int *left);
|
||||
void _gdk_macos_surface_set_shadow (GdkMacosSurface *self,
|
||||
int top,
|
||||
int right,
|
||||
int bottom,
|
||||
int left);
|
||||
gboolean _gdk_macos_surface_is_opaque (GdkMacosSurface *self);
|
||||
NSView *_gdk_macos_surface_get_view (GdkMacosSurface *self);
|
||||
gboolean _gdk_macos_surface_get_modal_hint (GdkMacosSurface *self);
|
||||
void _gdk_macos_surface_set_modal_hint (GdkMacosSurface *self,
|
||||
gboolean modal_hint);
|
||||
void _gdk_macos_surface_set_geometry_hints (GdkMacosSurface *self,
|
||||
const GdkGeometry *geometry,
|
||||
GdkSurfaceHints geom_mask);
|
||||
void _gdk_macos_surface_resize (GdkMacosSurface *self,
|
||||
int width,
|
||||
int height);
|
||||
void _gdk_macos_surface_update_fullscreen_state (GdkMacosSurface *self);
|
||||
void _gdk_macos_surface_request_frame (GdkMacosSurface *self);
|
||||
void _gdk_macos_surface_frame_presented (GdkMacosSurface *self,
|
||||
gint64 predicted_presentation_time,
|
||||
gint64 refresh_interval);
|
||||
void _gdk_macos_surface_show (GdkMacosSurface *self);
|
||||
void _gdk_macos_surface_synthesize_null_key (GdkMacosSurface *self);
|
||||
void _gdk_macos_surface_move (GdkMacosSurface *self,
|
||||
int x,
|
||||
int y);
|
||||
void _gdk_macos_surface_move_resize (GdkMacosSurface *self,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height);
|
||||
void _gdk_macos_surface_configure (GdkMacosSurface *self);
|
||||
void _gdk_macos_surface_user_resize (GdkMacosSurface *self,
|
||||
CGRect new_frame);
|
||||
gboolean _gdk_macos_surface_is_tracking (GdkMacosSurface *self,
|
||||
NSTrackingArea *area);
|
||||
void _gdk_macos_surface_monitor_changed (GdkMacosSurface *self);
|
||||
GdkMonitor *_gdk_macos_surface_get_best_monitor (GdkMacosSurface *self);
|
||||
void _gdk_macos_surface_reposition_children (GdkMacosSurface *self);
|
||||
void _gdk_macos_surface_set_opacity (GdkMacosSurface *self,
|
||||
double opacity);
|
||||
void _gdk_macos_surface_get_root_coords (GdkMacosSurface *self,
|
||||
int *x,
|
||||
int *y);
|
||||
GdkMacosBuffer *_gdk_macos_surface_get_buffer (GdkMacosSurface *self);
|
||||
void _gdk_macos_surface_swap_buffers (GdkMacosSurface *self,
|
||||
const cairo_region_t *damage);
|
||||
GdkMacosSurface *_gdk_macos_surface_new (GdkMacosDisplay *display,
|
||||
GdkSurfaceType surface_type,
|
||||
GdkSurface *parent,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height);
|
||||
NSWindow *_gdk_macos_surface_get_native (GdkMacosSurface *self);
|
||||
CGDirectDisplayID _gdk_macos_surface_get_screen_id (GdkMacosSurface *self);
|
||||
const char *_gdk_macos_surface_get_title (GdkMacosSurface *self);
|
||||
void _gdk_macos_surface_set_title (GdkMacosSurface *self,
|
||||
const char *title);
|
||||
void _gdk_macos_surface_get_shadow (GdkMacosSurface *self,
|
||||
int *top,
|
||||
int *right,
|
||||
int *bottom,
|
||||
int *left);
|
||||
void _gdk_macos_surface_set_shadow (GdkMacosSurface *self,
|
||||
int top,
|
||||
int right,
|
||||
int bottom,
|
||||
int left);
|
||||
NSView *_gdk_macos_surface_get_view (GdkMacosSurface *self);
|
||||
gboolean _gdk_macos_surface_get_modal_hint (GdkMacosSurface *self);
|
||||
void _gdk_macos_surface_set_modal_hint (GdkMacosSurface *self,
|
||||
gboolean modal_hint);
|
||||
void _gdk_macos_surface_set_geometry_hints (GdkMacosSurface *self,
|
||||
const GdkGeometry *geometry,
|
||||
GdkSurfaceHints geom_mask);
|
||||
void _gdk_macos_surface_resize (GdkMacosSurface *self,
|
||||
int width,
|
||||
int height);
|
||||
void _gdk_macos_surface_update_fullscreen_state (GdkMacosSurface *self);
|
||||
void _gdk_macos_surface_update_position (GdkMacosSurface *self);
|
||||
void _gdk_macos_surface_show (GdkMacosSurface *self);
|
||||
void _gdk_macos_surface_thaw (GdkMacosSurface *self,
|
||||
gint64 predicted_presentation_time,
|
||||
gint64 refresh_interval);
|
||||
CGContextRef _gdk_macos_surface_acquire_context (GdkMacosSurface *self,
|
||||
gboolean clear_scale,
|
||||
gboolean antialias);
|
||||
void _gdk_macos_surface_release_context (GdkMacosSurface *self,
|
||||
CGContextRef cg_context);
|
||||
void _gdk_macos_surface_synthesize_null_key (GdkMacosSurface *self);
|
||||
void _gdk_macos_surface_move (GdkMacosSurface *self,
|
||||
int x,
|
||||
int y);
|
||||
void _gdk_macos_surface_move_resize (GdkMacosSurface *self,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height);
|
||||
gboolean _gdk_macos_surface_is_tracking (GdkMacosSurface *self,
|
||||
NSTrackingArea *area);
|
||||
void _gdk_macos_surface_monitor_changed (GdkMacosSurface *self);
|
||||
GdkMonitor *_gdk_macos_surface_get_best_monitor (GdkMacosSurface *self);
|
||||
void _gdk_macos_surface_reposition_children (GdkMacosSurface *self);
|
||||
void _gdk_macos_surface_set_opacity (GdkMacosSurface *self,
|
||||
double opacity);
|
||||
void _gdk_macos_surface_get_root_coords (GdkMacosSurface *self,
|
||||
int *x,
|
||||
int *y);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
+178
-427
@@ -23,11 +23,10 @@
|
||||
#include <float.h>
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
#import "GdkMacosView.h"
|
||||
#import "GdkMacosCairoView.h"
|
||||
|
||||
#include "gdkmacossurface-private.h"
|
||||
|
||||
#include "gdkdebug.h"
|
||||
#include "gdkdeviceprivate.h"
|
||||
#include "gdkdisplay.h"
|
||||
#include "gdkeventsprivate.h"
|
||||
@@ -64,89 +63,17 @@ window_is_fullscreen (GdkMacosSurface *self)
|
||||
return ([self->window styleMask] & NSWindowStyleMaskFullScreen) != 0;
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_surface_request_frame (GdkMacosSurface *self)
|
||||
{
|
||||
g_assert (GDK_IS_MACOS_SURFACE (self));
|
||||
|
||||
if (self->awaiting_frame)
|
||||
return;
|
||||
|
||||
if (self->best_monitor != NULL)
|
||||
{
|
||||
self->awaiting_frame = TRUE;
|
||||
_gdk_macos_monitor_add_frame_callback (GDK_MACOS_MONITOR (self->best_monitor), self);
|
||||
gdk_surface_freeze_updates (GDK_SURFACE (self));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_gdk_macos_surface_cancel_frame (GdkMacosSurface *self)
|
||||
{
|
||||
g_assert (GDK_IS_MACOS_SURFACE (self));
|
||||
|
||||
if (!self->awaiting_frame)
|
||||
return;
|
||||
|
||||
if (self->best_monitor != NULL)
|
||||
{
|
||||
self->awaiting_frame = FALSE;
|
||||
_gdk_macos_monitor_remove_frame_callback (GDK_MACOS_MONITOR (self->best_monitor), self);
|
||||
gdk_surface_thaw_updates (GDK_SURFACE (self));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_surface_frame_presented (GdkMacosSurface *self,
|
||||
gint64 presentation_time,
|
||||
gint64 refresh_interval)
|
||||
{
|
||||
GdkFrameTimings *timings;
|
||||
GdkFrameClock *frame_clock;
|
||||
|
||||
g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
|
||||
|
||||
self->awaiting_frame = FALSE;
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (self))
|
||||
return;
|
||||
|
||||
frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self));
|
||||
|
||||
if (self->pending_frame_counter)
|
||||
{
|
||||
timings = gdk_frame_clock_get_timings (frame_clock, self->pending_frame_counter);
|
||||
|
||||
if (timings != NULL)
|
||||
{
|
||||
timings->presentation_time = presentation_time - refresh_interval;
|
||||
timings->complete = TRUE;
|
||||
}
|
||||
|
||||
self->pending_frame_counter = 0;
|
||||
}
|
||||
|
||||
timings = gdk_frame_clock_get_current_timings (frame_clock);
|
||||
|
||||
if (timings != NULL)
|
||||
{
|
||||
timings->refresh_interval = refresh_interval;
|
||||
timings->predicted_presentation_time = presentation_time;
|
||||
}
|
||||
|
||||
if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self)))
|
||||
gdk_surface_thaw_updates (GDK_SURFACE (self));
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_surface_reposition_children (GdkMacosSurface *self)
|
||||
{
|
||||
g_assert (GDK_IS_MACOS_SURFACE (self));
|
||||
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (self))
|
||||
return;
|
||||
|
||||
if (!gdk_surface_get_mapped (GDK_SURFACE (self)))
|
||||
return;
|
||||
|
||||
for (const GList *iter = GDK_SURFACE (self)->children;
|
||||
iter != NULL;
|
||||
iter = iter->next)
|
||||
@@ -158,23 +85,15 @@ _gdk_macos_surface_reposition_children (GdkMacosSurface *self)
|
||||
if (GDK_IS_MACOS_POPUP_SURFACE (child))
|
||||
_gdk_macos_popup_surface_reposition (GDK_MACOS_POPUP_SURFACE (child));
|
||||
}
|
||||
|
||||
if (GDK_IS_POPUP (self) && self->did_initial_present)
|
||||
gdk_surface_request_layout (GDK_SURFACE (self));
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_macos_surface_set_input_region (GdkSurface *surface,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
GdkMacosSurface *self = (GdkMacosSurface *)surface;
|
||||
cairo_rectangle_int_t rect;
|
||||
|
||||
g_assert (GDK_IS_MACOS_SURFACE (self));
|
||||
|
||||
if (self->window == NULL)
|
||||
return;
|
||||
|
||||
cairo_region_get_extents (region, &rect);
|
||||
|
||||
[(GdkMacosBaseView *)[self->window contentView] setInputArea:&rect];
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -186,8 +105,15 @@ gdk_macos_surface_set_opaque_region (GdkSurface *surface,
|
||||
|
||||
g_assert (GDK_IS_MACOS_SURFACE (self));
|
||||
|
||||
if ((nsview = _gdk_macos_surface_get_view (GDK_MACOS_SURFACE (surface))))
|
||||
[(GdkMacosView *)nsview setOpaqueRegion:region];
|
||||
if (region != self->opaque_region)
|
||||
{
|
||||
g_clear_pointer (&self->opaque_region, cairo_region_destroy);
|
||||
self->opaque_region = cairo_region_copy (region);
|
||||
}
|
||||
|
||||
if ((nsview = _gdk_macos_surface_get_view (GDK_MACOS_SURFACE (surface))) &&
|
||||
GDK_IS_MACOS_CAIRO_VIEW (nsview))
|
||||
[(GdkMacosCairoView *)nsview setOpaqueRegion:region];
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -196,16 +122,10 @@ gdk_macos_surface_hide (GdkSurface *surface)
|
||||
GdkMacosSurface *self = (GdkMacosSurface *)surface;
|
||||
GdkSeat *seat;
|
||||
gboolean was_mapped;
|
||||
gboolean was_key;
|
||||
|
||||
g_assert (GDK_IS_MACOS_SURFACE (self));
|
||||
|
||||
self->show_on_next_swap = FALSE;
|
||||
|
||||
_gdk_macos_surface_cancel_frame (self);
|
||||
|
||||
was_mapped = GDK_SURFACE_IS_MAPPED (surface);
|
||||
was_key = [self->window isKeyWindow];
|
||||
was_mapped = GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self));
|
||||
|
||||
seat = gdk_display_get_default_seat (surface->display);
|
||||
gdk_seat_ungrab (seat);
|
||||
@@ -214,26 +134,8 @@ gdk_macos_surface_hide (GdkSurface *surface)
|
||||
|
||||
_gdk_surface_clear_update_area (surface);
|
||||
|
||||
g_clear_object (&self->buffer);
|
||||
g_clear_object (&self->front);
|
||||
|
||||
if (was_key)
|
||||
{
|
||||
GdkSurface *parent;
|
||||
|
||||
if (GDK_IS_TOPLEVEL (surface))
|
||||
parent = surface->transient_for;
|
||||
else
|
||||
parent = surface->parent;
|
||||
|
||||
/* Return key input to the parent window if necessary */
|
||||
if (parent != NULL && GDK_SURFACE_IS_MAPPED (parent))
|
||||
{
|
||||
GdkMacosWindow *parentWindow = GDK_MACOS_SURFACE (parent)->window;
|
||||
|
||||
[parentWindow showAndMakeKey:YES];
|
||||
}
|
||||
}
|
||||
if (was_mapped)
|
||||
gdk_surface_freeze_updates (GDK_SURFACE (self));
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -277,7 +179,6 @@ gdk_macos_surface_begin_frame (GdkMacosSurface *self)
|
||||
{
|
||||
g_assert (GDK_IS_MACOS_SURFACE (self));
|
||||
|
||||
self->in_frame = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -289,18 +190,15 @@ gdk_macos_surface_end_frame (GdkMacosSurface *self)
|
||||
|
||||
g_assert (GDK_IS_MACOS_SURFACE (self));
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (self))
|
||||
return;
|
||||
|
||||
display = gdk_surface_get_display (GDK_SURFACE (self));
|
||||
frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self));
|
||||
|
||||
if ((timings = gdk_frame_clock_get_current_timings (frame_clock)))
|
||||
self->pending_frame_counter = timings->frame_counter;
|
||||
|
||||
self->in_frame = FALSE;
|
||||
_gdk_macos_display_add_frame_callback (GDK_MACOS_DISPLAY (display), self);
|
||||
|
||||
_gdk_macos_surface_request_frame (self);
|
||||
gdk_surface_freeze_updates (GDK_SURFACE (self));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -312,11 +210,10 @@ gdk_macos_surface_before_paint (GdkMacosSurface *self,
|
||||
g_assert (GDK_IS_MACOS_SURFACE (self));
|
||||
g_assert (GDK_IS_FRAME_CLOCK (frame_clock));
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (self))
|
||||
if (surface->update_freeze_count > 0)
|
||||
return;
|
||||
|
||||
if (surface->update_freeze_count == 0)
|
||||
gdk_macos_surface_begin_frame (self);
|
||||
gdk_macos_surface_begin_frame (self);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -328,11 +225,10 @@ gdk_macos_surface_after_paint (GdkMacosSurface *self,
|
||||
g_assert (GDK_IS_MACOS_SURFACE (self));
|
||||
g_assert (GDK_IS_FRAME_CLOCK (frame_clock));
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (self))
|
||||
if (surface->update_freeze_count > 0)
|
||||
return;
|
||||
|
||||
if (surface->update_freeze_count == 0)
|
||||
gdk_macos_surface_end_frame (self);
|
||||
gdk_macos_surface_end_frame (self);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -474,20 +370,18 @@ gdk_macos_surface_destroy (GdkSurface *surface,
|
||||
GdkMacosWindow *window = g_steal_pointer (&self->window);
|
||||
GdkFrameClock *frame_clock;
|
||||
|
||||
_gdk_macos_surface_cancel_frame (self);
|
||||
g_clear_object (&self->best_monitor);
|
||||
|
||||
if ((frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self))))
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (frame_clock,
|
||||
G_CALLBACK (gdk_macos_surface_before_paint),
|
||||
self);
|
||||
g_signal_handlers_disconnect_by_func (frame_clock,
|
||||
G_CALLBACK (gdk_macos_surface_after_paint),
|
||||
G_CALLBACK (gdk_macos_surface_before_paint),
|
||||
self);
|
||||
}
|
||||
|
||||
g_clear_pointer (&self->title, g_free);
|
||||
g_clear_pointer (&self->opaque_region, cairo_region_destroy);
|
||||
|
||||
if (window != NULL)
|
||||
[window close];
|
||||
@@ -496,9 +390,6 @@ gdk_macos_surface_destroy (GdkSurface *surface,
|
||||
|
||||
g_clear_pointer (&self->monitors, g_ptr_array_unref);
|
||||
|
||||
g_clear_object (&self->buffer);
|
||||
g_clear_object (&self->front);
|
||||
|
||||
g_assert (self->sorted.prev == NULL);
|
||||
g_assert (self->sorted.next == NULL);
|
||||
g_assert (self->frame.prev == NULL);
|
||||
@@ -519,6 +410,15 @@ gdk_macos_surface_constructed (GObject *object)
|
||||
|
||||
G_OBJECT_CLASS (gdk_macos_surface_parent_class)->constructed (object);
|
||||
|
||||
if (self->window != NULL)
|
||||
{
|
||||
NSRect bounds = [[self->window contentView] bounds];
|
||||
|
||||
GDK_SURFACE (self)->width = bounds.size.width;
|
||||
GDK_SURFACE (self)->height = bounds.size.height;
|
||||
_gdk_macos_surface_update_position (self);
|
||||
}
|
||||
|
||||
if ((frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self))))
|
||||
{
|
||||
g_signal_connect_object (frame_clock,
|
||||
@@ -532,9 +432,6 @@ gdk_macos_surface_constructed (GObject *object)
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
}
|
||||
|
||||
if (self->window != NULL)
|
||||
_gdk_macos_surface_configure (self);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -596,11 +493,6 @@ gdk_macos_surface_class_init (GdkMacosSurfaceClass *klass)
|
||||
surface_class->set_input_region = gdk_macos_surface_set_input_region;
|
||||
surface_class->set_opaque_region = gdk_macos_surface_set_opaque_region;
|
||||
|
||||
/**
|
||||
* GdkMacosSurface:native: (attributes org.gtk.Property.get=gdk_macos_surface_get_native_window)
|
||||
*
|
||||
* The "native" property contains the underlying NSWindow.
|
||||
*/
|
||||
properties [PROP_NATIVE] =
|
||||
g_param_spec_pointer ("native",
|
||||
"Native",
|
||||
@@ -634,7 +526,7 @@ _gdk_macos_surface_new (GdkMacosDisplay *display,
|
||||
g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
|
||||
|
||||
if (parent != NULL)
|
||||
frame_clock = g_object_ref (parent->frame_clock);
|
||||
frame_clock = g_object_ref (gdk_surface_get_frame_clock (parent));
|
||||
else
|
||||
frame_clock = _gdk_frame_clock_idle_new ();
|
||||
|
||||
@@ -691,29 +583,6 @@ _gdk_macos_surface_get_shadow (GdkMacosSurface *self,
|
||||
*right = self->shadow_right;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gdk_macos_surface_is_opaque (GdkMacosSurface *self)
|
||||
{
|
||||
GdkSurface *surface = (GdkSurface *)self;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), FALSE);
|
||||
|
||||
if (surface->opaque_region != NULL &&
|
||||
cairo_region_num_rectangles (surface->opaque_region) == 1)
|
||||
{
|
||||
cairo_rectangle_int_t extents;
|
||||
|
||||
cairo_region_get_extents (surface->opaque_region, &extents);
|
||||
|
||||
return (extents.x == 0 &&
|
||||
extents.y == 0 &&
|
||||
extents.width == GDK_SURFACE (self)->width &&
|
||||
extents.height == GDK_SURFACE (self)->height);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const char *
|
||||
_gdk_macos_surface_get_title (GdkMacosSurface *self)
|
||||
{
|
||||
@@ -763,27 +632,6 @@ _gdk_macos_surface_get_native (GdkMacosSurface *self)
|
||||
return (NSWindow *)self->window;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_macos_surface_get_native_window: (attributes org.gtk.Method.get_property=native)
|
||||
* @self: a #GdkMacosSurface
|
||||
*
|
||||
* Gets the underlying NSWindow used by the surface.
|
||||
*
|
||||
* The NSWindow's contentView is an implementation detail and may change
|
||||
* between releases of GTK.
|
||||
*
|
||||
* Returns: (nullable): a #NSWindow or %NULL
|
||||
*
|
||||
* Since: 4.8
|
||||
*/
|
||||
gpointer
|
||||
gdk_macos_surface_get_native_window (GdkMacosSurface *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL);
|
||||
|
||||
return _gdk_macos_surface_get_native (self);
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_surface_set_geometry_hints (GdkMacosSurface *self,
|
||||
const GdkGeometry *geometry,
|
||||
@@ -842,60 +690,64 @@ _gdk_macos_surface_update_fullscreen_state (GdkMacosSurface *self)
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_surface_configure (GdkMacosSurface *self)
|
||||
_gdk_macos_surface_update_position (GdkMacosSurface *self)
|
||||
{
|
||||
GdkSurface *surface = (GdkSurface *)self;
|
||||
GdkMacosDisplay *display;
|
||||
GdkMacosSurface *parent;
|
||||
NSRect frame_rect;
|
||||
NSRect content_rect;
|
||||
|
||||
g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (self))
|
||||
return;
|
||||
|
||||
if (surface->parent != NULL)
|
||||
parent = GDK_MACOS_SURFACE (surface->parent);
|
||||
else if (surface->transient_for != NULL)
|
||||
parent = GDK_MACOS_SURFACE (surface->transient_for);
|
||||
else
|
||||
parent = NULL;
|
||||
|
||||
display = GDK_MACOS_DISPLAY (GDK_SURFACE (self)->display);
|
||||
frame_rect = [self->window frame];
|
||||
content_rect = [self->window contentRectForFrameRect:frame_rect];
|
||||
GdkSurface *surface = GDK_SURFACE (self);
|
||||
GdkDisplay *display = gdk_surface_get_display (surface);
|
||||
NSRect frame_rect = [self->window frame];
|
||||
NSRect content_rect = [self->window contentRectForFrameRect:frame_rect];
|
||||
|
||||
_gdk_macos_display_from_display_coords (GDK_MACOS_DISPLAY (display),
|
||||
content_rect.origin.x,
|
||||
content_rect.origin.y + content_rect.size.height,
|
||||
&self->root_x, &self->root_y);
|
||||
|
||||
if (parent != NULL)
|
||||
if (surface->parent != NULL)
|
||||
{
|
||||
surface->x = self->root_x - parent->root_x;
|
||||
surface->y = self->root_y - parent->root_y;
|
||||
surface->x = self->root_x - GDK_MACOS_SURFACE (surface->parent)->root_x;
|
||||
surface->y = self->root_y - GDK_MACOS_SURFACE (surface->parent)->root_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
surface->x = self->root_x;
|
||||
surface->y = self->root_y;
|
||||
}
|
||||
}
|
||||
|
||||
if (surface->width != content_rect.size.width ||
|
||||
surface->height != content_rect.size.height)
|
||||
void
|
||||
_gdk_macos_surface_thaw (GdkMacosSurface *self,
|
||||
gint64 presentation_time,
|
||||
gint64 refresh_interval)
|
||||
{
|
||||
GdkFrameTimings *timings;
|
||||
GdkFrameClock *frame_clock;
|
||||
|
||||
g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
|
||||
|
||||
gdk_surface_thaw_updates (GDK_SURFACE (self));
|
||||
|
||||
frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self));
|
||||
|
||||
if (self->pending_frame_counter)
|
||||
{
|
||||
surface->width = content_rect.size.width;
|
||||
surface->height = content_rect.size.height;
|
||||
timings = gdk_frame_clock_get_timings (frame_clock, self->pending_frame_counter);
|
||||
|
||||
g_clear_object (&self->buffer);
|
||||
g_clear_object (&self->front);
|
||||
if (timings != NULL)
|
||||
{
|
||||
timings->presentation_time = presentation_time - refresh_interval;
|
||||
timings->complete = TRUE;
|
||||
}
|
||||
|
||||
_gdk_surface_update_size (surface);
|
||||
gdk_surface_invalidate_rect (surface, NULL);
|
||||
self->pending_frame_counter = 0;
|
||||
}
|
||||
|
||||
_gdk_macos_surface_reposition_children (self);
|
||||
timings = gdk_frame_clock_get_current_timings (frame_clock);
|
||||
|
||||
if (timings != NULL)
|
||||
{
|
||||
timings->refresh_interval = refresh_interval;
|
||||
timings->predicted_presentation_time = presentation_time;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -908,18 +760,69 @@ _gdk_macos_surface_show (GdkMacosSurface *self)
|
||||
if (GDK_SURFACE_DESTROYED (self))
|
||||
return;
|
||||
|
||||
_gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (GDK_SURFACE (self)->display));
|
||||
self->show_on_next_swap = TRUE;
|
||||
|
||||
was_mapped = GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self));
|
||||
|
||||
if (!was_mapped)
|
||||
gdk_surface_set_is_mapped (GDK_SURFACE (self), TRUE);
|
||||
|
||||
_gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (GDK_SURFACE (self)->display));
|
||||
|
||||
[self->window showAndMakeKey:YES];
|
||||
|
||||
if (!was_mapped)
|
||||
{
|
||||
gdk_surface_set_is_mapped (GDK_SURFACE (self), TRUE);
|
||||
gdk_surface_request_layout (GDK_SURFACE (self));
|
||||
gdk_surface_invalidate_rect (GDK_SURFACE (self), NULL);
|
||||
gdk_surface_thaw_updates (GDK_SURFACE (self));
|
||||
if (gdk_surface_get_mapped (GDK_SURFACE (self)))
|
||||
{
|
||||
_gdk_macos_surface_update_position (self);
|
||||
gdk_surface_invalidate_rect (GDK_SURFACE (self), NULL);
|
||||
gdk_surface_thaw_updates (GDK_SURFACE (self));
|
||||
}
|
||||
}
|
||||
|
||||
[[self->window contentView] setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
CGContextRef
|
||||
_gdk_macos_surface_acquire_context (GdkMacosSurface *self,
|
||||
gboolean clear_scale,
|
||||
gboolean antialias)
|
||||
{
|
||||
CGContextRef cg_context;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL);
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (self))
|
||||
return NULL;
|
||||
|
||||
if (!(cg_context = [[NSGraphicsContext currentContext] CGContext]))
|
||||
return NULL;
|
||||
|
||||
CGContextSaveGState (cg_context);
|
||||
|
||||
if (!antialias)
|
||||
CGContextSetAllowsAntialiasing (cg_context, antialias);
|
||||
|
||||
if (clear_scale)
|
||||
{
|
||||
CGSize scale;
|
||||
|
||||
scale = CGSizeMake (1.0, 1.0);
|
||||
scale = CGContextConvertSizeToDeviceSpace (cg_context, scale);
|
||||
|
||||
CGContextScaleCTM (cg_context, 1.0 / fabs (scale.width), 1.0 / fabs (scale.height));
|
||||
}
|
||||
|
||||
return cg_context;
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_surface_release_context (GdkMacosSurface *self,
|
||||
CGContextRef cg_context)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
|
||||
|
||||
CGContextRestoreGState (cg_context);
|
||||
CGContextSetAllowsAntialiasing (cg_context, TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -971,89 +874,52 @@ _gdk_macos_surface_move_resize (GdkMacosSurface *self,
|
||||
GdkDisplay *display;
|
||||
NSRect content_rect;
|
||||
NSRect frame_rect;
|
||||
gboolean ignore_move;
|
||||
gboolean ignore_size;
|
||||
GdkRectangle current;
|
||||
gboolean size_changed;
|
||||
|
||||
g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
|
||||
|
||||
/* Query for up-to-date values in case we're racing against
|
||||
* an incoming frame notify which could be queued behind whatever
|
||||
* we're processing right now.
|
||||
*/
|
||||
frame_rect = [self->window frame];
|
||||
content_rect = [self->window contentRectForFrameRect:frame_rect];
|
||||
_gdk_macos_display_from_display_coords (GDK_MACOS_DISPLAY (GDK_SURFACE (self)->display),
|
||||
content_rect.origin.x, content_rect.origin.y,
|
||||
¤t.x, ¤t.y);
|
||||
current.width = content_rect.size.width;
|
||||
current.height = content_rect.size.height;
|
||||
|
||||
/* Check if we can ignore the operation all together */
|
||||
ignore_move = (x == -1 || (x == current.x)) &&
|
||||
(y == -1 || (y == current.y));
|
||||
ignore_size = (width == -1 || (width == current.width)) &&
|
||||
(height == -1 || (height == current.height));
|
||||
|
||||
if (ignore_move && ignore_size)
|
||||
if ((x == -1 || (x == self->root_x)) &&
|
||||
(y == -1 || (y == self->root_y)) &&
|
||||
(width == -1 || (width == surface->width)) &&
|
||||
(height == -1 || (height == surface->height)))
|
||||
return;
|
||||
|
||||
display = gdk_surface_get_display (surface);
|
||||
|
||||
if (width == -1)
|
||||
width = current.width;
|
||||
width = surface->width;
|
||||
|
||||
if (height == -1)
|
||||
height = current.height;
|
||||
height = surface->height;
|
||||
|
||||
if (x == -1)
|
||||
x = current.x;
|
||||
x = self->root_x;
|
||||
|
||||
if (y == -1)
|
||||
y = current.y;
|
||||
y = self->root_y;
|
||||
|
||||
size_changed = height != surface->height || width != surface->width;
|
||||
|
||||
if (GDK_IS_MACOS_SURFACE (surface->parent))
|
||||
{
|
||||
surface->x = x - GDK_MACOS_SURFACE (surface->parent)->root_x;
|
||||
surface->y = y - GDK_MACOS_SURFACE (surface->parent)->root_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
surface->x = x;
|
||||
surface->y = y;
|
||||
}
|
||||
|
||||
_gdk_macos_display_to_display_coords (GDK_MACOS_DISPLAY (display),
|
||||
x, y + height,
|
||||
&x, &y);
|
||||
|
||||
if (!ignore_move)
|
||||
content_rect.origin = NSMakePoint (x, y);
|
||||
|
||||
if (!ignore_size)
|
||||
content_rect.size = NSMakeSize (width, height);
|
||||
x, y + height, &x, &y);
|
||||
|
||||
content_rect = NSMakeRect (x, y, width, height);
|
||||
frame_rect = [self->window frameRectForContentRect:content_rect];
|
||||
[self->window setFrame:frame_rect display:NO];
|
||||
}
|
||||
[self->window setFrame:frame_rect display:YES];
|
||||
|
||||
void
|
||||
_gdk_macos_surface_user_resize (GdkMacosSurface *self,
|
||||
CGRect new_frame)
|
||||
{
|
||||
GdkMacosDisplay *display;
|
||||
CGRect content_rect;
|
||||
int root_x, root_y;
|
||||
|
||||
g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
|
||||
g_return_if_fail (GDK_IS_TOPLEVEL (self));
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (self))
|
||||
return;
|
||||
|
||||
display = GDK_MACOS_DISPLAY (GDK_SURFACE (self)->display);
|
||||
content_rect = [self->window contentRectForFrameRect:new_frame];
|
||||
|
||||
_gdk_macos_display_from_display_coords (display,
|
||||
new_frame.origin.x,
|
||||
new_frame.origin.y + new_frame.size.height,
|
||||
&root_x, &root_y);
|
||||
|
||||
self->next_layout.root_x = root_x;
|
||||
self->next_layout.root_y = root_y;
|
||||
self->next_layout.width = content_rect.size.width;
|
||||
self->next_layout.height = content_rect.size.height;
|
||||
|
||||
gdk_surface_request_layout (GDK_SURFACE (self));
|
||||
if (size_changed)
|
||||
gdk_surface_invalidate_rect (surface, NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -1078,24 +944,14 @@ void
|
||||
_gdk_macos_surface_monitor_changed (GdkMacosSurface *self)
|
||||
{
|
||||
GListModel *monitors;
|
||||
GdkMonitor *best = NULL;
|
||||
GdkRectangle rect;
|
||||
GdkRectangle intersect;
|
||||
GdkDisplay *display;
|
||||
GdkMonitor *monitor;
|
||||
guint n_monitors;
|
||||
int best_area = 0;
|
||||
|
||||
g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
|
||||
|
||||
if (self->in_change_monitor)
|
||||
return;
|
||||
|
||||
self->in_change_monitor = TRUE;
|
||||
|
||||
_gdk_macos_surface_cancel_frame (self);
|
||||
_gdk_macos_surface_configure (self);
|
||||
|
||||
rect.x = self->root_x;
|
||||
rect.y = self->root_y;
|
||||
rect.width = GDK_SURFACE (self)->width;
|
||||
@@ -1130,15 +986,26 @@ _gdk_macos_surface_monitor_changed (GdkMacosSurface *self)
|
||||
|
||||
g_object_unref (monitor);
|
||||
}
|
||||
}
|
||||
|
||||
/* We need to create a new IOSurface for this monitor */
|
||||
g_clear_object (&self->buffer);
|
||||
g_clear_object (&self->front);
|
||||
GdkMonitor *
|
||||
_gdk_macos_surface_get_best_monitor (GdkMacosSurface *self)
|
||||
{
|
||||
GdkMonitor *best = NULL;
|
||||
GdkRectangle rect;
|
||||
int best_area = 0;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL);
|
||||
|
||||
rect.x = self->root_x;
|
||||
rect.y = self->root_y;
|
||||
rect.width = GDK_SURFACE (self)->width;
|
||||
rect.height = GDK_SURFACE (self)->height;
|
||||
|
||||
/* Determine the best-fit monitor */
|
||||
for (guint i = 0; i < self->monitors->len; i++)
|
||||
{
|
||||
monitor = g_ptr_array_index (self->monitors, i);
|
||||
GdkMonitor *monitor = g_ptr_array_index (self->monitors, i);
|
||||
GdkRectangle intersect;
|
||||
|
||||
if (gdk_rectangle_intersect (&monitor->geometry, &rect, &intersect))
|
||||
{
|
||||
@@ -1146,62 +1013,13 @@ _gdk_macos_surface_monitor_changed (GdkMacosSurface *self)
|
||||
|
||||
if (area > best_area)
|
||||
{
|
||||
best_area = area;
|
||||
best = monitor;
|
||||
best_area = area;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (g_set_object (&self->best_monitor, best))
|
||||
{
|
||||
GDK_NOTE (MISC,
|
||||
g_message ("Surface \"%s\" moved to monitor \"%s\"",
|
||||
self->title ? self->title : "unknown",
|
||||
gdk_monitor_get_connector (best)));
|
||||
|
||||
_gdk_macos_surface_configure (self);
|
||||
|
||||
if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self)))
|
||||
{
|
||||
_gdk_macos_surface_request_frame (self);
|
||||
gdk_surface_request_layout (GDK_SURFACE (self));
|
||||
}
|
||||
|
||||
for (const GList *iter = GDK_SURFACE (self)->children;
|
||||
iter != NULL;
|
||||
iter = iter->next)
|
||||
{
|
||||
GdkMacosSurface *child = iter->data;
|
||||
GdkRectangle area;
|
||||
|
||||
g_set_object (&child->best_monitor, best);
|
||||
|
||||
area.x = self->root_x + GDK_SURFACE (child)->x + child->shadow_left;
|
||||
area.y = self->root_y + GDK_SURFACE (child)->y + child->shadow_top;
|
||||
area.width = GDK_SURFACE (child)->width - child->shadow_left - child->shadow_right;
|
||||
area.height = GDK_SURFACE (child)->height - child->shadow_top - child->shadow_bottom;
|
||||
|
||||
_gdk_macos_monitor_clamp (GDK_MACOS_MONITOR (best), &area);
|
||||
|
||||
area.x -= child->shadow_left;
|
||||
area.y -= child->shadow_top;
|
||||
|
||||
_gdk_macos_surface_move (child, area.x, area.y);
|
||||
gdk_surface_invalidate_rect (GDK_SURFACE (child), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
gdk_surface_invalidate_rect (GDK_SURFACE (self), NULL);
|
||||
|
||||
self->in_change_monitor = FALSE;
|
||||
}
|
||||
|
||||
GdkMonitor *
|
||||
_gdk_macos_surface_get_best_monitor (GdkMacosSurface *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL);
|
||||
|
||||
return self->best_monitor;
|
||||
return best;
|
||||
}
|
||||
|
||||
NSView *
|
||||
@@ -1248,70 +1066,3 @@ _gdk_macos_surface_get_root_coords (GdkMacosSurface *self,
|
||||
if (y)
|
||||
*y = out_y;
|
||||
}
|
||||
|
||||
GdkMacosBuffer *
|
||||
_gdk_macos_surface_get_buffer (GdkMacosSurface *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL);
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (self))
|
||||
return NULL;
|
||||
|
||||
if (self->buffer == NULL)
|
||||
{
|
||||
/* Create replacement buffer. We always use 4-byte and 32-bit BGRA for
|
||||
* our surface as that can work with both Cairo and GL. The GdkMacosTile
|
||||
* handles opaque regions for the compositor, so using 3-byte/24-bit is
|
||||
* not a necessary optimization.
|
||||
*/
|
||||
double scale = gdk_surface_get_scale_factor (GDK_SURFACE (self));
|
||||
guint width = GDK_SURFACE (self)->width * scale;
|
||||
guint height = GDK_SURFACE (self)->height * scale;
|
||||
|
||||
self->buffer = _gdk_macos_buffer_new (width, height, scale, 4, 32);
|
||||
}
|
||||
|
||||
return self->buffer;
|
||||
}
|
||||
|
||||
static void
|
||||
_gdk_macos_surface_do_delayed_show (GdkMacosSurface *self)
|
||||
{
|
||||
GdkSurface *surface = (GdkSurface *)self;
|
||||
|
||||
g_assert (GDK_IS_MACOS_SURFACE (self));
|
||||
|
||||
self->show_on_next_swap = FALSE;
|
||||
[self->window showAndMakeKey:YES];
|
||||
|
||||
_gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (surface->display));
|
||||
gdk_surface_request_motion (surface);
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_surface_swap_buffers (GdkMacosSurface *self,
|
||||
const cairo_region_t *damage)
|
||||
{
|
||||
GdkMacosBuffer *swap;
|
||||
|
||||
g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
|
||||
g_return_if_fail (damage != NULL);
|
||||
|
||||
swap = self->buffer;
|
||||
self->buffer = self->front;
|
||||
self->front = swap;
|
||||
|
||||
/* This code looks like it swaps buffers, but since the IOSurfaceRef
|
||||
* appears to be retained on the other side, we really just ask all
|
||||
* of the GdkMacosTile CALayer's to update their contents.
|
||||
*/
|
||||
[self->window swapBuffer:swap withDamage:damage];
|
||||
|
||||
/* We might have delayed actually showing the window until the buffer
|
||||
* contents are ready to be displayed. Doing so ensures that we don't
|
||||
* get a point where we might have invalid buffer contents before we
|
||||
* have content to display to the user.
|
||||
*/
|
||||
if G_UNLIKELY (self->show_on_next_swap)
|
||||
_gdk_macos_surface_do_delayed_show (self);
|
||||
}
|
||||
|
||||
@@ -36,9 +36,7 @@ typedef struct _GdkMacosSurfaceClass GdkMacosSurfaceClass;
|
||||
#define GDK_IS_MACOS_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_SURFACE))
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gdk_macos_surface_get_type (void);
|
||||
GDK_AVAILABLE_IN_4_8
|
||||
gpointer gdk_macos_surface_get_native_window (GdkMacosSurface *self);
|
||||
GType gdk_macos_surface_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -35,8 +35,6 @@ struct _GdkMacosToplevelSurface
|
||||
{
|
||||
GdkMacosSurface parent_instance;
|
||||
GdkToplevelLayout *layout;
|
||||
int last_computed_width;
|
||||
int last_computed_height;
|
||||
guint decorated : 1;
|
||||
};
|
||||
|
||||
|
||||
@@ -174,14 +174,6 @@ _gdk_macos_toplevel_surface_present (GdkToplevel *toplevel,
|
||||
|
||||
_gdk_macos_surface_set_geometry_hints (GDK_MACOS_SURFACE (self), &geometry, mask);
|
||||
gdk_surface_constrain_size (&geometry, mask, width, height, &width, &height);
|
||||
|
||||
GDK_NOTE (MISC,
|
||||
g_message ("Resizing \"%s\" to %dx%d",
|
||||
GDK_MACOS_SURFACE (self)->title ?
|
||||
GDK_MACOS_SURFACE (self)->title :
|
||||
"untitled",
|
||||
width, height));
|
||||
|
||||
_gdk_macos_surface_resize (GDK_MACOS_SURFACE (self), width, height);
|
||||
|
||||
/* Maximized state */
|
||||
@@ -202,22 +194,43 @@ _gdk_macos_toplevel_surface_present (GdkToplevel *toplevel,
|
||||
_gdk_macos_toplevel_surface_unfullscreen (self);
|
||||
}
|
||||
|
||||
if (!GDK_MACOS_SURFACE (self)->did_initial_present)
|
||||
if (GDK_SURFACE (self)->transient_for != NULL)
|
||||
{
|
||||
int x = 0, y = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
[nswindow setAnimationBehavior:NSWindowAnimationBehaviorDocumentWindow];
|
||||
|
||||
_gdk_macos_display_position_surface (GDK_MACOS_DISPLAY (display),
|
||||
GDK_MACOS_SURFACE (self),
|
||||
&x, &y);
|
||||
if (!self->decorated &&
|
||||
!GDK_MACOS_SURFACE (self)->did_initial_present &&
|
||||
GDK_SURFACE (self)->x == 0 &&
|
||||
GDK_SURFACE (self)->y == 0 &&
|
||||
(GDK_MACOS_SURFACE (self)->shadow_left ||
|
||||
GDK_MACOS_SURFACE (self)->shadow_top))
|
||||
{
|
||||
int x = GDK_SURFACE (self)->x;
|
||||
int y = GDK_SURFACE (self)->y;
|
||||
|
||||
GDK_NOTE (MISC,
|
||||
g_message ("Placing new toplevel \"%s\" at %d,%d",
|
||||
GDK_MACOS_SURFACE (self)->title ?
|
||||
GDK_MACOS_SURFACE (self)->title :
|
||||
"untitled",
|
||||
x, y));
|
||||
monitor = _gdk_macos_surface_get_best_monitor (GDK_MACOS_SURFACE (self));
|
||||
|
||||
_gdk_macos_surface_move (GDK_MACOS_SURFACE (self), x, y);
|
||||
if (monitor != NULL)
|
||||
{
|
||||
GdkRectangle visible;
|
||||
|
||||
gdk_macos_monitor_get_workarea (monitor, &visible);
|
||||
|
||||
if (x < visible.x)
|
||||
x = visible.x;
|
||||
|
||||
if (y < visible.y)
|
||||
y = visible.y;
|
||||
}
|
||||
|
||||
x -= GDK_MACOS_SURFACE (self)->shadow_left;
|
||||
y -= GDK_MACOS_SURFACE (self)->shadow_top;
|
||||
|
||||
_gdk_macos_surface_move (GDK_MACOS_SURFACE (self), x, y);
|
||||
}
|
||||
}
|
||||
|
||||
_gdk_macos_surface_show (GDK_MACOS_SURFACE (self));
|
||||
@@ -368,11 +381,11 @@ static gboolean
|
||||
_gdk_macos_toplevel_surface_compute_size (GdkSurface *surface)
|
||||
{
|
||||
GdkMacosToplevelSurface *self = (GdkMacosToplevelSurface *)surface;
|
||||
GdkMacosSurface *macos_surface = (GdkMacosSurface *)surface;
|
||||
GdkToplevelSize size;
|
||||
GdkDisplay *display;
|
||||
GdkMonitor *monitor;
|
||||
int bounds_width, bounds_height;
|
||||
int width, height;
|
||||
GdkGeometry geometry;
|
||||
GdkSurfaceHints mask;
|
||||
|
||||
@@ -406,6 +419,9 @@ _gdk_macos_toplevel_surface_compute_size (GdkSurface *surface)
|
||||
g_warn_if_fail (size.width > 0);
|
||||
g_warn_if_fail (size.height > 0);
|
||||
|
||||
width = surface->width;
|
||||
height = surface->height;
|
||||
|
||||
if (self->layout != NULL &&
|
||||
gdk_toplevel_layout_get_resizable (self->layout))
|
||||
{
|
||||
@@ -421,64 +437,16 @@ _gdk_macos_toplevel_surface_compute_size (GdkSurface *surface)
|
||||
}
|
||||
|
||||
if (size.shadow.is_valid)
|
||||
_gdk_macos_surface_set_shadow (macos_surface,
|
||||
_gdk_macos_surface_set_shadow (GDK_MACOS_SURFACE (surface),
|
||||
size.shadow.top,
|
||||
size.shadow.right,
|
||||
size.shadow.bottom,
|
||||
size.shadow.left);
|
||||
|
||||
_gdk_macos_surface_set_geometry_hints (macos_surface, &geometry, mask);
|
||||
gdk_surface_constrain_size (&geometry, mask, width, height, &width, &height);
|
||||
|
||||
if (surface->state & (GDK_TOPLEVEL_STATE_FULLSCREEN |
|
||||
GDK_TOPLEVEL_STATE_MAXIMIZED |
|
||||
GDK_TOPLEVEL_STATE_TILED |
|
||||
GDK_TOPLEVEL_STATE_TOP_TILED |
|
||||
GDK_TOPLEVEL_STATE_RIGHT_TILED |
|
||||
GDK_TOPLEVEL_STATE_BOTTOM_TILED |
|
||||
GDK_TOPLEVEL_STATE_LEFT_TILED |
|
||||
GDK_TOPLEVEL_STATE_MINIMIZED) ||
|
||||
[macos_surface->window inLiveResize])
|
||||
return FALSE;
|
||||
|
||||
/* If we delayed a user resize until the beginning of the frame,
|
||||
* apply it now so we can start processing updates for it.
|
||||
*/
|
||||
if (macos_surface->next_layout.width > 0 &&
|
||||
macos_surface->next_layout.height > 0)
|
||||
{
|
||||
int root_x = macos_surface->next_layout.root_x;
|
||||
int root_y = macos_surface->next_layout.root_y;
|
||||
int width = macos_surface->next_layout.width;
|
||||
int height = macos_surface->next_layout.height;
|
||||
|
||||
gdk_surface_constrain_size (&geometry, mask,
|
||||
width, height,
|
||||
&width, &height);
|
||||
|
||||
macos_surface->next_layout.width = 0;
|
||||
macos_surface->next_layout.height = 0;
|
||||
|
||||
_gdk_macos_surface_move_resize (macos_surface,
|
||||
root_x, root_y,
|
||||
width, height);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gdk_surface_constrain_size (&geometry, mask,
|
||||
size.width, size.height,
|
||||
&size.width, &size.height);
|
||||
|
||||
if ((size.width != self->last_computed_width ||
|
||||
size.height != self->last_computed_height) &&
|
||||
(size.width != surface->width ||
|
||||
size.height != surface->height))
|
||||
{
|
||||
self->last_computed_width = size.width;
|
||||
self->last_computed_height = size.height;
|
||||
|
||||
_gdk_macos_surface_resize (macos_surface, size.width, size.height);
|
||||
}
|
||||
_gdk_macos_surface_set_geometry_hints (GDK_MACOS_SURFACE (self), &geometry, mask);
|
||||
_gdk_macos_surface_resize (GDK_MACOS_SURFACE (self), width, height);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -648,10 +616,10 @@ _gdk_macos_toplevel_surface_new (GdkMacosDisplay *display,
|
||||
|
||||
GdkMacosWindow *window;
|
||||
GdkMacosSurface *self;
|
||||
NSScreen *screen;
|
||||
NSUInteger style_mask;
|
||||
NSRect content_rect;
|
||||
NSRect visible_frame;
|
||||
NSScreen *screen;
|
||||
NSRect screen_rect;
|
||||
int nx;
|
||||
int ny;
|
||||
|
||||
@@ -664,26 +632,20 @@ _gdk_macos_toplevel_surface_new (GdkMacosDisplay *display,
|
||||
NSWindowStyleMaskMiniaturizable |
|
||||
NSWindowStyleMaskResizable);
|
||||
|
||||
if (parent != NULL)
|
||||
{
|
||||
x += GDK_MACOS_SURFACE (parent)->root_x;
|
||||
y += GDK_MACOS_SURFACE (parent)->root_y;
|
||||
}
|
||||
|
||||
_gdk_macos_display_to_display_coords (display, x, y + height, &nx, &ny);
|
||||
_gdk_macos_display_to_display_coords (display, x, y, &nx, &ny);
|
||||
|
||||
screen = _gdk_macos_display_get_screen_at_display_coords (display, nx, ny);
|
||||
visible_frame = [screen visibleFrame];
|
||||
content_rect = NSMakeRect (nx - visible_frame.origin.x, ny - visible_frame.origin.y, width, height);
|
||||
screen_rect = [screen visibleFrame];
|
||||
nx -= screen_rect.origin.x;
|
||||
ny -= screen_rect.origin.y;
|
||||
content_rect = NSMakeRect (nx, ny - height, width, height);
|
||||
|
||||
window = [[GdkMacosWindow alloc] initWithContentRect:content_rect
|
||||
styleMask:style_mask
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO
|
||||
screen:screen];
|
||||
|
||||
/* Allow NSWindow to go fullscreen */
|
||||
[window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
|
||||
|
||||
self = g_object_new (GDK_TYPE_MACOS_TOPLEVEL_SURFACE,
|
||||
"display", display,
|
||||
"frame-clock", frame_clock,
|
||||
@@ -710,21 +672,13 @@ _gdk_macos_toplevel_surface_attach_to_parent (GdkMacosToplevelSurface *self)
|
||||
{
|
||||
NSWindow *parent = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface->transient_for));
|
||||
NSWindow *window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
|
||||
int x, y;
|
||||
|
||||
[parent addChildWindow:window ordered:NSWindowAbove];
|
||||
|
||||
if (GDK_SURFACE (self)->modal_hint)
|
||||
[window setLevel:NSModalPanelWindowLevel];
|
||||
|
||||
surface->x = 0;
|
||||
surface->y = 0;
|
||||
|
||||
_gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (surface->display));
|
||||
_gdk_macos_display_position_surface (GDK_MACOS_DISPLAY (surface->display),
|
||||
GDK_MACOS_SURFACE (surface),
|
||||
&x, &y);
|
||||
_gdk_macos_surface_move (GDK_MACOS_SURFACE (surface), x, y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,16 +2,13 @@ gdk_macos_sources = files([
|
||||
'edgesnapping.c',
|
||||
|
||||
'gdkdisplaylinksource.c',
|
||||
'gdkmacosbuffer.c',
|
||||
'gdkmacoscairocontext.c',
|
||||
'gdkmacosclipboard.c',
|
||||
'gdkmacoscursor.c',
|
||||
'gdkmacosdevice.c',
|
||||
'gdkmacosdisplay.c',
|
||||
'gdkmacosdisplay-feedback.c',
|
||||
'gdkmacosdisplay-settings.c',
|
||||
'gdkmacosdisplay-translate.c',
|
||||
'gdkmacosdisplay-wm.c',
|
||||
'gdkmacosdrag.c',
|
||||
'gdkmacosdrop.c',
|
||||
'gdkmacosdragsurface.c',
|
||||
@@ -23,10 +20,11 @@ gdk_macos_sources = files([
|
||||
'gdkmacosseat.c',
|
||||
'gdkmacossurface.c',
|
||||
'gdkmacostoplevelsurface.c',
|
||||
|
||||
'GdkMacosBaseView.c',
|
||||
'GdkMacosLayer.c',
|
||||
'GdkMacosTile.c',
|
||||
'GdkMacosView.c',
|
||||
'GdkMacosCairoView.c',
|
||||
'GdkMacosCairoSubview.c',
|
||||
'GdkMacosGLView.c',
|
||||
'GdkMacosWindow.c',
|
||||
])
|
||||
|
||||
@@ -48,7 +46,6 @@ gdk_macos_frameworks = [
|
||||
'CoreVideo',
|
||||
'CoreServices',
|
||||
'Foundation',
|
||||
'IOSurface',
|
||||
'OpenGL',
|
||||
'QuartzCore',
|
||||
]
|
||||
|
||||
@@ -73,9 +73,8 @@ gdk_wayland_app_launch_context_get_startup_notify_id (GAppLaunchContext *context
|
||||
xdg_activation_token_v1_set_serial (token,
|
||||
_gdk_wayland_seat_get_last_implicit_grab_serial (seat, NULL),
|
||||
gdk_wayland_seat_get_wl_seat (GDK_SEAT (seat)));
|
||||
if (focus_surface)
|
||||
xdg_activation_token_v1_set_surface (token,
|
||||
gdk_wayland_surface_get_wl_surface (focus_surface));
|
||||
xdg_activation_token_v1_set_surface (token,
|
||||
gdk_wayland_surface_get_wl_surface (focus_surface));
|
||||
xdg_activation_token_v1_commit (token);
|
||||
|
||||
while (app_launch_data.token == NULL)
|
||||
|
||||
@@ -181,8 +181,8 @@ gdk_wayland_cairo_context_end_frame (GdkDrawContext *draw_context,
|
||||
GdkWaylandCairoContext *self = GDK_WAYLAND_CAIRO_CONTEXT (draw_context);
|
||||
GdkSurface *surface = gdk_draw_context_get_surface (draw_context);
|
||||
|
||||
gdk_wayland_surface_sync (surface);
|
||||
gdk_wayland_surface_attach_image (surface, self->paint_surface, painted);
|
||||
gdk_wayland_surface_sync (surface);
|
||||
gdk_wayland_surface_request_frame (surface);
|
||||
|
||||
gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "wayland", "surface commit");
|
||||
|
||||
@@ -227,7 +227,6 @@ struct _GdkWaylandSeat
|
||||
struct wl_touch *wl_touch;
|
||||
struct zwp_pointer_gesture_swipe_v1 *wp_pointer_gesture_swipe;
|
||||
struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch;
|
||||
struct zwp_pointer_gesture_hold_v1 *wp_pointer_gesture_hold;
|
||||
struct zwp_tablet_seat_v2 *wp_tablet_seat;
|
||||
|
||||
GdkDisplay *display;
|
||||
@@ -2857,81 +2856,6 @@ gesture_pinch_end (void *data,
|
||||
0, 0, 1, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
emit_gesture_hold_event (GdkWaylandSeat *seat,
|
||||
GdkTouchpadGesturePhase phase,
|
||||
guint32 _time,
|
||||
guint32 n_fingers)
|
||||
{
|
||||
GdkEvent *event;
|
||||
|
||||
if (!seat->pointer_info.focus)
|
||||
return;
|
||||
|
||||
seat->pointer_info.time = _time;
|
||||
|
||||
event = gdk_touchpad_event_new_hold (seat->pointer_info.focus,
|
||||
seat->logical_pointer,
|
||||
_time,
|
||||
device_get_modifiers (seat->logical_pointer),
|
||||
phase,
|
||||
seat->pointer_info.surface_x,
|
||||
seat->pointer_info.surface_y,
|
||||
n_fingers);
|
||||
|
||||
if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS))
|
||||
{
|
||||
double x, y;
|
||||
gdk_event_get_position (event, &x, &y);
|
||||
g_message ("hold event %d, coords: %f %f, seat %p state %d",
|
||||
gdk_event_get_event_type (event),
|
||||
x, y, seat,
|
||||
gdk_event_get_modifier_state (event));
|
||||
}
|
||||
|
||||
_gdk_wayland_display_deliver_event (seat->display, event);
|
||||
}
|
||||
|
||||
static void
|
||||
gesture_hold_begin (void *data,
|
||||
struct zwp_pointer_gesture_hold_v1 *hold,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
struct wl_surface *surface,
|
||||
uint32_t fingers)
|
||||
{
|
||||
GdkWaylandSeat *seat = data;
|
||||
GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display);
|
||||
|
||||
_gdk_wayland_display_update_serial (display, serial);
|
||||
|
||||
emit_gesture_hold_event (seat,
|
||||
GDK_TOUCHPAD_GESTURE_PHASE_BEGIN,
|
||||
time, fingers);
|
||||
seat->gesture_n_fingers = fingers;
|
||||
}
|
||||
|
||||
static void
|
||||
gesture_hold_end (void *data,
|
||||
struct zwp_pointer_gesture_hold_v1 *hold,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
int32_t cancelled)
|
||||
{
|
||||
GdkWaylandSeat *seat = data;
|
||||
GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display);
|
||||
GdkTouchpadGesturePhase phase;
|
||||
|
||||
_gdk_wayland_display_update_serial (display, serial);
|
||||
|
||||
phase = (cancelled) ?
|
||||
GDK_TOUCHPAD_GESTURE_PHASE_CANCEL :
|
||||
GDK_TOUCHPAD_GESTURE_PHASE_END;
|
||||
|
||||
emit_gesture_hold_event (seat, phase, time,
|
||||
seat->gesture_n_fingers);
|
||||
}
|
||||
|
||||
static void
|
||||
_gdk_wayland_seat_remove_tool (GdkWaylandSeat *seat,
|
||||
GdkWaylandTabletToolData *tool)
|
||||
@@ -3141,11 +3065,6 @@ static const struct zwp_pointer_gesture_pinch_v1_listener gesture_pinch_listener
|
||||
gesture_pinch_end
|
||||
};
|
||||
|
||||
static const struct zwp_pointer_gesture_hold_v1_listener gesture_hold_listener = {
|
||||
gesture_hold_begin,
|
||||
gesture_hold_end
|
||||
};
|
||||
|
||||
static const struct zwp_tablet_v2_listener tablet_listener = {
|
||||
tablet_handle_name,
|
||||
tablet_handle_id,
|
||||
@@ -3201,17 +3120,6 @@ seat_handle_capabilities (void *data,
|
||||
seat);
|
||||
zwp_pointer_gesture_pinch_v1_add_listener (seat->wp_pointer_gesture_pinch,
|
||||
&gesture_pinch_listener, seat);
|
||||
|
||||
if (display_wayland->pointer_gestures_version >= ZWP_POINTER_GESTURES_V1_GET_HOLD_GESTURE_SINCE_VERSION)
|
||||
{
|
||||
seat->wp_pointer_gesture_hold =
|
||||
zwp_pointer_gestures_v1_get_hold_gesture (display_wayland->pointer_gestures,
|
||||
seat->wl_pointer);
|
||||
zwp_pointer_gesture_hold_v1_set_user_data (seat->wp_pointer_gesture_hold,
|
||||
seat);
|
||||
zwp_pointer_gesture_hold_v1_add_listener (seat->wp_pointer_gesture_hold,
|
||||
&gesture_hold_listener, seat);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && seat->wl_pointer)
|
||||
|
||||
@@ -366,8 +366,7 @@ gdk_registry_handle_global (void *data,
|
||||
if (strcmp (interface, "wl_compositor") == 0)
|
||||
{
|
||||
display_wayland->compositor =
|
||||
wl_registry_bind (display_wayland->wl_registry, id,
|
||||
&wl_compositor_interface, MIN (version, 5));
|
||||
wl_registry_bind (display_wayland->wl_registry, id, &wl_compositor_interface, MIN (version, 4));
|
||||
display_wayland->compositor_version = MIN (version, 4);
|
||||
}
|
||||
else if (strcmp (interface, "wl_shm") == 0)
|
||||
@@ -431,9 +430,6 @@ gdk_registry_handle_global (void *data,
|
||||
}
|
||||
else if (strcmp (interface, "zwp_pointer_gestures_v1") == 0)
|
||||
{
|
||||
display_wayland->pointer_gestures_version =
|
||||
MIN (version, GDK_ZWP_POINTER_GESTURES_V1_VERSION);
|
||||
|
||||
display_wayland->pointer_gestures =
|
||||
wl_registry_bind (display_wayland->wl_registry,
|
||||
id, &zwp_pointer_gestures_v1_interface,
|
||||
@@ -854,10 +850,6 @@ gdk_wayland_display_notify_startup_complete (GdkDisplay *display,
|
||||
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
|
||||
char *free_this = NULL;
|
||||
|
||||
/* Will be signaled with focus activation */
|
||||
if (display_wayland->xdg_activation)
|
||||
return;
|
||||
|
||||
if (startup_id == NULL)
|
||||
{
|
||||
startup_id = free_this = display_wayland->startup_notification_id;
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDK_ZWP_POINTER_GESTURES_V1_VERSION 3
|
||||
#define GDK_ZWP_POINTER_GESTURES_V1_VERSION 1
|
||||
|
||||
typedef struct _GdkWaylandSelection GdkWaylandSelection;
|
||||
|
||||
@@ -140,7 +140,6 @@ struct _GdkWaylandDisplay
|
||||
int data_device_manager_version;
|
||||
int gtk_shell_version;
|
||||
int xdg_output_manager_version;
|
||||
int pointer_gestures_version;
|
||||
int xdg_activation_version;
|
||||
|
||||
uint32_t server_decoration_mode;
|
||||
|
||||
@@ -101,7 +101,6 @@ gdk_wayland_primary_claim_remote (GdkWaylandPrimary *cb,
|
||||
{
|
||||
GDK_DISPLAY_NOTE (gdk_clipboard_get_display (GDK_CLIPBOARD (cb)), CLIPBOARD, g_message ("%p: Ignoring clipboard offer for self", cb));
|
||||
gdk_content_formats_unref (formats);
|
||||
g_clear_pointer (&offer, zwp_primary_selection_offer_v1_destroy);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -935,33 +935,12 @@ gdk_wayland_surface_attach_image (GdkSurface *surface,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_surface_sync_offset (GdkSurface *surface)
|
||||
{
|
||||
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
||||
|
||||
if (wl_surface_get_version (impl->display_server.wl_surface) <
|
||||
WL_SURFACE_OFFSET_SINCE_VERSION)
|
||||
return;
|
||||
|
||||
if (impl->pending_buffer_offset_x == 0 &&
|
||||
impl->pending_buffer_offset_y == 0)
|
||||
return;
|
||||
|
||||
wl_surface_offset (impl->display_server.wl_surface,
|
||||
impl->pending_buffer_offset_x,
|
||||
impl->pending_buffer_offset_y);
|
||||
impl->pending_buffer_offset_x = 0;
|
||||
impl->pending_buffer_offset_y = 0;
|
||||
}
|
||||
|
||||
void
|
||||
gdk_wayland_surface_sync (GdkSurface *surface)
|
||||
{
|
||||
gdk_wayland_surface_sync_shadow (surface);
|
||||
gdk_wayland_surface_sync_opaque_region (surface);
|
||||
gdk_wayland_surface_sync_input_region (surface);
|
||||
gdk_wayland_surface_sync_offset (surface);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -1498,7 +1477,6 @@ gdk_wayland_surface_configure_toplevel (GdkSurface *surface)
|
||||
int width, height;
|
||||
gboolean is_resizing;
|
||||
gboolean fixed_size;
|
||||
gboolean was_fixed_size;
|
||||
gboolean saved_size;
|
||||
|
||||
new_state = impl->pending.toplevel.state;
|
||||
@@ -1513,11 +1491,6 @@ gdk_wayland_surface_configure_toplevel (GdkSurface *surface)
|
||||
GDK_TOPLEVEL_STATE_TILED) ||
|
||||
is_resizing;
|
||||
|
||||
was_fixed_size =
|
||||
surface->state & (GDK_TOPLEVEL_STATE_MAXIMIZED |
|
||||
GDK_TOPLEVEL_STATE_FULLSCREEN |
|
||||
GDK_TOPLEVEL_STATE_TILED);
|
||||
|
||||
width = impl->pending.toplevel.width;
|
||||
height = impl->pending.toplevel.height;
|
||||
|
||||
@@ -1530,7 +1503,7 @@ gdk_wayland_surface_configure_toplevel (GdkSurface *surface)
|
||||
* the client should configure its size back to what it was before
|
||||
* being maximize or fullscreen.
|
||||
*/
|
||||
if (saved_size && !fixed_size && was_fixed_size)
|
||||
if (saved_size && !fixed_size)
|
||||
{
|
||||
width = impl->saved_width;
|
||||
height = impl->saved_height;
|
||||
@@ -2320,7 +2293,8 @@ gdk_wayland_toplevel_inhibit_idle (GdkToplevel *toplevel)
|
||||
|
||||
if (!wayland_toplevel->idle_inhibitor)
|
||||
{
|
||||
g_assert (wayland_toplevel->idle_inhibitor_refcount == 0);
|
||||
g_assert (wayland_toplevel->idle_inhibitor &&
|
||||
wayland_toplevel->idle_inhibitor_refcount > 0);
|
||||
|
||||
wayland_toplevel->idle_inhibitor =
|
||||
zwp_idle_inhibit_manager_v1_create_inhibitor (display_wayland->idle_inhibit_manager,
|
||||
@@ -3453,80 +3427,39 @@ gdk_wayland_surface_destroy (GdkSurface *surface,
|
||||
display->toplevels = g_list_remove (display->toplevels, surface);
|
||||
}
|
||||
|
||||
static void
|
||||
token_done (gpointer data,
|
||||
struct xdg_activation_token_v1 *provider,
|
||||
const char *token)
|
||||
{
|
||||
char **token_out = data;
|
||||
|
||||
*token_out = g_strdup (token);
|
||||
}
|
||||
|
||||
static const struct xdg_activation_token_v1_listener token_listener = {
|
||||
token_done,
|
||||
};
|
||||
|
||||
static void
|
||||
gdk_wayland_surface_focus (GdkSurface *surface,
|
||||
guint32 timestamp)
|
||||
{
|
||||
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
||||
GdkDisplay *display = gdk_surface_get_display (surface);
|
||||
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
|
||||
gchar *startup_id = NULL;
|
||||
|
||||
startup_id = g_steal_pointer (&display_wayland->startup_notification_id);
|
||||
if (!impl->display_server.gtk_surface)
|
||||
return;
|
||||
|
||||
if (display_wayland->xdg_activation)
|
||||
if (timestamp == GDK_CURRENT_TIME)
|
||||
{
|
||||
GdkWaylandSeat *seat =
|
||||
GDK_WAYLAND_SEAT (gdk_display_get_default_seat (display));
|
||||
GdkWaylandDisplay *display_wayland =
|
||||
GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
|
||||
|
||||
/* If the focus request does not have a startup ID associated, get a
|
||||
* new token to activate the window.
|
||||
*/
|
||||
if (!startup_id)
|
||||
if (display_wayland->startup_notification_id)
|
||||
{
|
||||
struct xdg_activation_token_v1 *token;
|
||||
struct wl_event_queue *event_queue;
|
||||
if (display_wayland->xdg_activation)
|
||||
{
|
||||
xdg_activation_v1_activate (display_wayland->xdg_activation,
|
||||
display_wayland->startup_notification_id,
|
||||
impl->display_server.wl_surface);
|
||||
}
|
||||
else if (display_wayland->gtk_shell_version >= 3)
|
||||
{
|
||||
gtk_surface1_request_focus (impl->display_server.gtk_surface,
|
||||
display_wayland->startup_notification_id);
|
||||
}
|
||||
|
||||
event_queue = wl_display_create_queue (display_wayland->wl_display);
|
||||
|
||||
token = xdg_activation_v1_get_activation_token (display_wayland->xdg_activation);
|
||||
wl_proxy_set_queue ((struct wl_proxy *) token, event_queue);
|
||||
|
||||
xdg_activation_token_v1_add_listener (token,
|
||||
&token_listener,
|
||||
&startup_id);
|
||||
xdg_activation_token_v1_set_serial (token,
|
||||
_gdk_wayland_seat_get_last_implicit_grab_serial (seat, NULL),
|
||||
gdk_wayland_seat_get_wl_seat (GDK_SEAT (seat)));
|
||||
xdg_activation_token_v1_set_surface (token,
|
||||
gdk_wayland_surface_get_wl_surface (surface));
|
||||
xdg_activation_token_v1_commit (token);
|
||||
|
||||
while (startup_id == NULL)
|
||||
wl_display_dispatch_queue (display_wayland->wl_display, event_queue);
|
||||
|
||||
xdg_activation_token_v1_destroy (token);
|
||||
wl_event_queue_destroy (event_queue);
|
||||
g_clear_pointer (&display_wayland->startup_notification_id, g_free);
|
||||
}
|
||||
|
||||
xdg_activation_v1_activate (display_wayland->xdg_activation,
|
||||
startup_id,
|
||||
impl->display_server.wl_surface);
|
||||
}
|
||||
else if (impl->display_server.gtk_surface)
|
||||
{
|
||||
if (timestamp != GDK_CURRENT_TIME)
|
||||
gtk_surface1_present (impl->display_server.gtk_surface, timestamp);
|
||||
else if (startup_id && display_wayland->gtk_shell_version >= 3)
|
||||
gtk_surface1_request_focus (impl->display_server.gtk_surface,
|
||||
startup_id);
|
||||
}
|
||||
|
||||
g_free (startup_id);
|
||||
else
|
||||
gtk_surface1_present (impl->display_server.gtk_surface, timestamp);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -71,7 +71,7 @@ foreach p: proto_sources
|
||||
elif proto_stability == 'staging'
|
||||
proto_version = p.get(2)
|
||||
output_base = '@0@-@1@'.format(proto_name, proto_version)
|
||||
input = files(join_paths(wlproto_dir, '@0@/@1@/@2@.xml'.format(proto_stability, proto_name, output_base)))
|
||||
input = join_paths(wlproto_dir, '@0@/@1@/@2@.xml'.format(proto_stability, proto_name, output_base))
|
||||
elif proto_stability == 'private'
|
||||
output_base = proto_name
|
||||
input = files('protocol/@0@.xml'.format(proto_name))
|
||||
|
||||
@@ -1219,10 +1219,11 @@ inner_clipboard_window_procedure (HWND hwnd,
|
||||
return DefWindowProcW (hwnd, message, wparam, lparam);
|
||||
}
|
||||
|
||||
SetLastError (0);
|
||||
hwnd_owner = GetClipboardOwner ();
|
||||
if (hwnd_owner == NULL && GetLastError () != 0)
|
||||
WIN32_API_FAILED ("GetClipboardOwner");
|
||||
|
||||
if ((hwnd_owner == NULL) &&
|
||||
(GetLastError () != ERROR_SUCCESS))
|
||||
WIN32_API_FAILED ("GetClipboardOwner");
|
||||
|
||||
hwnd_opener = GetOpenClipboardWindow ();
|
||||
|
||||
|
||||
@@ -945,71 +945,38 @@ _gdk_win32_enable_hidpi (GdkWin32Display *display)
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gdk_win32_check_processor (GdkWin32ProcessorCheckType check_type)
|
||||
static void
|
||||
_gdk_win32_check_on_arm64 (GdkWin32Display *display)
|
||||
{
|
||||
static gsize checked = 0;
|
||||
static gboolean is_arm64 = FALSE;
|
||||
static gboolean is_wow64 = FALSE;
|
||||
|
||||
if (g_once_init_enter (&checked))
|
||||
{
|
||||
gboolean fallback_wow64_check = FALSE;
|
||||
HMODULE kernel32 = LoadLibraryW (L"kernel32.dll");
|
||||
|
||||
if (kernel32 != NULL)
|
||||
{
|
||||
typedef BOOL (WINAPI *funcIsWow64Process2) (HANDLE, USHORT *, USHORT *);
|
||||
|
||||
funcIsWow64Process2 isWow64Process2 =
|
||||
display->cpu_funcs.isWow64Process2 =
|
||||
(funcIsWow64Process2) GetProcAddress (kernel32, "IsWow64Process2");
|
||||
|
||||
if (isWow64Process2 != NULL)
|
||||
if (display->cpu_funcs.isWow64Process2 != NULL)
|
||||
{
|
||||
USHORT proc_cpu = 0;
|
||||
USHORT native_cpu = 0;
|
||||
|
||||
isWow64Process2 (GetCurrentProcess (), &proc_cpu, &native_cpu);
|
||||
display->cpu_funcs.isWow64Process2 (GetCurrentProcess (),
|
||||
&proc_cpu,
|
||||
&native_cpu);
|
||||
|
||||
if (native_cpu == IMAGE_FILE_MACHINE_ARM64)
|
||||
is_arm64 = TRUE;
|
||||
|
||||
if (proc_cpu != IMAGE_FILE_MACHINE_UNKNOWN)
|
||||
is_wow64 = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
fallback_wow64_check = TRUE;
|
||||
display->running_on_arm64 = TRUE;
|
||||
}
|
||||
|
||||
FreeLibrary (kernel32);
|
||||
}
|
||||
else
|
||||
{
|
||||
fallback_wow64_check = TRUE;
|
||||
}
|
||||
|
||||
if (fallback_wow64_check)
|
||||
IsWow64Process (GetCurrentProcess (), &is_wow64);
|
||||
|
||||
g_once_init_leave (&checked, 1);
|
||||
}
|
||||
|
||||
switch (check_type)
|
||||
{
|
||||
case GDK_WIN32_ARM64:
|
||||
return is_arm64;
|
||||
break;
|
||||
|
||||
case GDK_WIN32_WOW64:
|
||||
return is_wow64;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_warning ("unknown CPU check type");
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1020,7 +987,7 @@ gdk_win32_display_init (GdkWin32Display *display_win32)
|
||||
display_win32->monitors = G_LIST_MODEL (g_list_store_new (GDK_TYPE_MONITOR));
|
||||
|
||||
_gdk_win32_enable_hidpi (display_win32);
|
||||
display_win32->running_on_arm64 = _gdk_win32_check_processor (GDK_WIN32_ARM64);
|
||||
_gdk_win32_check_on_arm64 (display_win32);
|
||||
|
||||
/* if we have DPI awareness, set up fixed scale if set */
|
||||
if (display_win32->dpi_aware_type != PROCESS_DPI_UNAWARE &&
|
||||
@@ -1175,18 +1142,16 @@ gdk_win32_display_get_setting (GdkDisplay *display,
|
||||
#define EGL_PLATFORM_ANGLE_ANGLE 0x3202
|
||||
#endif
|
||||
|
||||
static GdkGLContext *
|
||||
gdk_win32_display_init_gl (GdkDisplay *display,
|
||||
GError **error)
|
||||
static gboolean
|
||||
gdk_win32_display_init_gl_backend (GdkDisplay *display,
|
||||
GError **error)
|
||||
{
|
||||
gboolean result = FALSE;
|
||||
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
|
||||
HDC init_gl_hdc = NULL;
|
||||
|
||||
if (display_win32->dummy_context_wgl.hdc == NULL)
|
||||
display_win32->dummy_context_wgl.hdc = GetDC (display_win32->hwnd);
|
||||
|
||||
init_gl_hdc = display_win32->dummy_context_wgl.hdc;
|
||||
|
||||
/*
|
||||
* No env vars set, do the regular GL initialization, first WGL and then EGL,
|
||||
* as WGL is the more tried-and-tested configuration.
|
||||
@@ -1194,50 +1159,59 @@ gdk_win32_display_init_gl (GdkDisplay *display,
|
||||
|
||||
#ifdef HAVE_EGL
|
||||
/*
|
||||
* Disable defaulting to EGL as EGL is used more as a compatibility layer
|
||||
* Disable defaulting to EGL for now, since shaders need to be fixed for
|
||||
* usage against libANGLE EGL. EGL is used more as a compatibility layer
|
||||
* on Windows rather than being a native citizen on Windows
|
||||
*/
|
||||
if (GDK_DEBUG_CHECK (GL_EGL) || GDK_DEBUG_CHECK (GL_GLES))
|
||||
{
|
||||
if (gdk_display_init_egl (display,
|
||||
EGL_PLATFORM_ANGLE_ANGLE,
|
||||
init_gl_hdc,
|
||||
FALSE,
|
||||
error))
|
||||
{
|
||||
return g_object_new (GDK_TYPE_WIN32_GL_CONTEXT_EGL,
|
||||
"display", display,
|
||||
NULL);
|
||||
}
|
||||
else
|
||||
g_clear_error (error);
|
||||
}
|
||||
if (_gdk_debug_flags & GDK_DEBUG_GL_EGL)
|
||||
result = gdk_display_init_egl (display,
|
||||
EGL_PLATFORM_ANGLE_ANGLE,
|
||||
display_win32->dummy_context_wgl.hdc,
|
||||
FALSE,
|
||||
error);
|
||||
#endif
|
||||
|
||||
if (gdk_win32_display_init_wgl (display, error))
|
||||
if (!result)
|
||||
{
|
||||
return g_object_new (GDK_TYPE_WIN32_GL_CONTEXT_WGL,
|
||||
"display", display,
|
||||
NULL);
|
||||
g_clear_error (error);
|
||||
result = gdk_win32_display_init_wgl (display, error);
|
||||
}
|
||||
|
||||
#ifdef HAVE_EGL
|
||||
g_clear_error (error);
|
||||
|
||||
if (gdk_display_init_egl (display,
|
||||
EGL_PLATFORM_ANGLE_ANGLE,
|
||||
init_gl_hdc,
|
||||
TRUE,
|
||||
error))
|
||||
if (!result)
|
||||
{
|
||||
return g_object_new (GDK_TYPE_WIN32_GL_CONTEXT_EGL,
|
||||
"display", display,
|
||||
NULL);
|
||||
|
||||
g_clear_error (error);
|
||||
result = gdk_display_init_egl (display,
|
||||
EGL_PLATFORM_ANGLE_ANGLE,
|
||||
display_win32->dummy_context_wgl.hdc,
|
||||
TRUE,
|
||||
error);
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
static GdkGLContext *
|
||||
gdk_win32_display_init_gl (GdkDisplay *display,
|
||||
GError **error)
|
||||
{
|
||||
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
|
||||
GdkGLContext *gl_context = NULL;
|
||||
|
||||
if (!gdk_win32_display_init_gl_backend (display, error))
|
||||
return NULL;
|
||||
|
||||
if (display_win32->wgl_pixel_format != 0)
|
||||
gl_context = g_object_new (GDK_TYPE_WIN32_GL_CONTEXT_WGL, "display", display, NULL);
|
||||
#ifdef HAVE_EGL
|
||||
else if (gdk_display_get_egl_display (display))
|
||||
gl_context = g_object_new (GDK_TYPE_WIN32_GL_CONTEXT_EGL, "display", display, NULL);
|
||||
#endif
|
||||
|
||||
g_return_val_if_fail (gl_context != NULL, NULL);
|
||||
|
||||
return gl_context;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -105,6 +105,13 @@ typedef enum {
|
||||
GDK_WIN32_TABLET_INPUT_API_WINPOINTER
|
||||
} GdkWin32TabletInputAPI;
|
||||
|
||||
/* Detect running architecture */
|
||||
typedef BOOL (WINAPI *funcIsWow64Process2) (HANDLE, USHORT *, USHORT *);
|
||||
typedef struct _GdkWin32KernelCPUFuncs
|
||||
{
|
||||
funcIsWow64Process2 isWow64Process2;
|
||||
} GdkWin32KernelCPUFuncs;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HDC hdc;
|
||||
@@ -125,6 +132,7 @@ struct _GdkWin32Display
|
||||
|
||||
/* WGL/OpenGL Items */
|
||||
GdkWin32GLDummyContextWGL dummy_context_wgl;
|
||||
int wgl_pixel_format;
|
||||
guint gl_version;
|
||||
|
||||
GListModel *monitors;
|
||||
@@ -169,6 +177,7 @@ struct _GdkWin32Display
|
||||
|
||||
/* Running CPU items */
|
||||
guint running_on_arm64 : 1;
|
||||
GdkWin32KernelCPUFuncs cpu_funcs;
|
||||
};
|
||||
|
||||
struct _GdkWin32DisplayClass
|
||||
|
||||
+307
-308
@@ -19,7 +19,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the GTK+ Team and others 1997-2020. See the AUTHORS
|
||||
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
|
||||
* file for a list of people on the GTK+ Team. See the ChangeLog
|
||||
* files for a list of changes. These files are distributed with
|
||||
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
||||
@@ -134,6 +134,15 @@ static GSourceFuncs event_funcs = {
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Whenever we do an implicit grab (call SetCapture() after
|
||||
* a mouse button is held down), we ref the capturing surface
|
||||
* and keep that ref here. When mouse buttons are released,
|
||||
* we remove the implicit grab and synthesize a crossing
|
||||
* event from the grab surface to whatever surface is now
|
||||
* under cursor.
|
||||
*/
|
||||
static GdkSurface *implicit_grab_surface = NULL;
|
||||
|
||||
static GdkSurface *mouse_window = NULL;
|
||||
static GdkSurface *mouse_window_ignored_leave = NULL;
|
||||
static int current_x, current_y;
|
||||
@@ -635,9 +644,11 @@ build_key_event_state (BYTE *key_state)
|
||||
{
|
||||
GdkModifierType state;
|
||||
GdkWin32Keymap *keymap;
|
||||
keymap = GDK_WIN32_KEYMAP (_gdk_win32_display_get_keymap (_gdk_display));
|
||||
|
||||
state = _gdk_win32_keymap_get_mod_mask (keymap);
|
||||
state = 0;
|
||||
|
||||
if (key_state[VK_SHIFT] & 0x80)
|
||||
state |= GDK_SHIFT_MASK;
|
||||
|
||||
if (key_state[VK_CAPITAL] & 0x01)
|
||||
state |= GDK_LOCK_MASK;
|
||||
@@ -653,6 +664,26 @@ build_key_event_state (BYTE *key_state)
|
||||
if (key_state[VK_XBUTTON2] & 0x80)
|
||||
state |= GDK_BUTTON5_MASK;
|
||||
|
||||
keymap = GDK_WIN32_KEYMAP (_gdk_win32_display_get_keymap (_gdk_display));
|
||||
|
||||
if (_gdk_win32_keymap_has_altgr (keymap) &&
|
||||
(key_state[VK_LCONTROL] & 0x80) &&
|
||||
(key_state[VK_RMENU] & 0x80))
|
||||
{
|
||||
state |= GDK_MOD2_MASK;
|
||||
if (key_state[VK_RCONTROL] & 0x80)
|
||||
state |= GDK_CONTROL_MASK;
|
||||
if (key_state[VK_LMENU] & 0x80)
|
||||
state |= GDK_ALT_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (key_state[VK_CONTROL] & 0x80)
|
||||
state |= GDK_CONTROL_MASK;
|
||||
if (key_state[VK_MENU] & 0x80)
|
||||
state |= GDK_ALT_MASK;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -1731,12 +1762,16 @@ gdk_event_translate (MSG *msg,
|
||||
POINT point;
|
||||
MINMAXINFO *mmi;
|
||||
HWND hwnd;
|
||||
BYTE key_state[256];
|
||||
HIMC himc;
|
||||
WINDOWPOS *windowpos;
|
||||
gboolean ignore_leave;
|
||||
|
||||
GdkEvent *event;
|
||||
|
||||
wchar_t wbuf[100];
|
||||
int ccount;
|
||||
|
||||
GdkDisplay *display;
|
||||
GdkSurface *window = NULL;
|
||||
GdkWin32Surface *impl;
|
||||
@@ -1754,12 +1789,20 @@ gdk_event_translate (MSG *msg,
|
||||
|
||||
int button;
|
||||
|
||||
char buf[256];
|
||||
gboolean return_val = FALSE;
|
||||
|
||||
int i;
|
||||
|
||||
GdkModifierType state;
|
||||
guint keyval;
|
||||
guint16 keycode;
|
||||
guint8 group;
|
||||
gboolean is_modifier;
|
||||
|
||||
double delta_x, delta_y;
|
||||
GdkScrollDirection direction;
|
||||
GdkTranslatedKey translated;
|
||||
|
||||
display = gdk_display_get_default ();
|
||||
win32_display = GDK_WIN32_DISPLAY (display);
|
||||
@@ -1818,39 +1861,35 @@ gdk_event_translate (MSG *msg,
|
||||
switch (msg->message)
|
||||
{
|
||||
case WM_INPUTLANGCHANGE:
|
||||
{
|
||||
GdkWin32Keymap *win32_keymap;
|
||||
GdkTranslatedKey translated;
|
||||
_gdk_input_locale = (HKL) msg->lParam;
|
||||
_gdk_win32_keymap_set_active_layout (GDK_WIN32_KEYMAP (_gdk_win32_display_get_keymap (_gdk_display)), _gdk_input_locale);
|
||||
GetLocaleInfo (MAKELCID (LOWORD (_gdk_input_locale), SORT_DEFAULT),
|
||||
LOCALE_IDEFAULTANSICODEPAGE,
|
||||
buf, sizeof (buf));
|
||||
_gdk_input_codepage = atoi (buf);
|
||||
_gdk_keymap_serial++;
|
||||
GDK_NOTE (EVENTS,
|
||||
g_print (" cs:%lu hkl:%p%s cp:%d",
|
||||
(gulong) msg->wParam,
|
||||
(gpointer) msg->lParam, _gdk_input_locale_is_ime ? " (IME)" : "",
|
||||
_gdk_input_codepage));
|
||||
gdk_display_setting_changed (display, "gtk-im-module");
|
||||
|
||||
win32_keymap = GDK_WIN32_KEYMAP (_gdk_win32_display_get_keymap (_gdk_display));
|
||||
|
||||
_gdk_input_locale = (HKL) msg->lParam;
|
||||
_gdk_win32_keymap_set_active_layout (win32_keymap, _gdk_input_locale);
|
||||
_gdk_keymap_serial++;
|
||||
|
||||
GDK_NOTE (EVENTS,
|
||||
g_print (" cs:%lu hkl:%p%s",
|
||||
(gulong) msg->wParam,
|
||||
(gpointer) msg->lParam,
|
||||
_gdk_input_locale_is_ime ? " (IME)" : ""));
|
||||
gdk_display_setting_changed (display, "gtk-im-module");
|
||||
|
||||
/* Generate a dummy key event to "nudge" IMContext */
|
||||
translated.keyval = GDK_KEY_VoidSymbol;
|
||||
translated.consumed = 0;
|
||||
translated.layout = 0;
|
||||
translated.level = 0;
|
||||
event = gdk_key_event_new (GDK_KEY_PRESS,
|
||||
window,
|
||||
device_manager_win32->core_keyboard,
|
||||
_gdk_win32_get_next_tick (msg->time),
|
||||
0,
|
||||
0,
|
||||
FALSE,
|
||||
&translated,
|
||||
&translated);
|
||||
_gdk_win32_append_event (event);
|
||||
}
|
||||
/* Generate a dummy key event to "nudge" IMContext */
|
||||
translated.keyval = GDK_KEY_VoidSymbol;
|
||||
translated.consumed = 0;
|
||||
translated.layout = 0;
|
||||
translated.level = 0;
|
||||
event = gdk_key_event_new (GDK_KEY_PRESS,
|
||||
window,
|
||||
device_manager_win32->core_keyboard,
|
||||
_gdk_win32_get_next_tick (msg->time),
|
||||
0,
|
||||
0,
|
||||
FALSE,
|
||||
&translated,
|
||||
&translated);
|
||||
_gdk_win32_append_event (event);
|
||||
break;
|
||||
|
||||
case WM_SYSKEYUP:
|
||||
@@ -1887,203 +1926,177 @@ gdk_event_translate (MSG *msg,
|
||||
decode_key_lparam (msg->lParam)));
|
||||
|
||||
keyup_or_down:
|
||||
{
|
||||
GdkWin32Keymap *win32_keymap;
|
||||
GdkModifierType state;
|
||||
guint keyval;
|
||||
guint16 keycode;
|
||||
guint8 group;
|
||||
gboolean is_modifier;
|
||||
GdkTranslatedKey translated;
|
||||
GdkTranslatedKey no_lock;
|
||||
BYTE key_state[256];
|
||||
wchar_t wbuf[100];
|
||||
int ccount = 0;
|
||||
|
||||
/* Ignore key messages intended for the IME */
|
||||
if (msg->wParam == VK_PROCESSKEY || in_ime_composition)
|
||||
break;
|
||||
/* Ignore key messages intended for the IME */
|
||||
if (msg->wParam == VK_PROCESSKEY ||
|
||||
in_ime_composition)
|
||||
break;
|
||||
|
||||
/* Ignore autorepeats on modifiers */
|
||||
if (msg->message == WM_KEYDOWN &&
|
||||
(msg->wParam == VK_MENU ||
|
||||
msg->wParam == VK_CONTROL ||
|
||||
msg->wParam == VK_SHIFT) &&
|
||||
((HIWORD(msg->lParam) & KF_REPEAT) >= 1))
|
||||
break;
|
||||
/* Ignore autorepeats on modifiers */
|
||||
if (msg->message == WM_KEYDOWN &&
|
||||
(msg->wParam == VK_MENU ||
|
||||
msg->wParam == VK_CONTROL ||
|
||||
msg->wParam == VK_SHIFT) &&
|
||||
((HIWORD(msg->lParam) & KF_REPEAT) >= 1))
|
||||
break;
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (window))
|
||||
break;
|
||||
if (GDK_SURFACE_DESTROYED (window))
|
||||
break;
|
||||
|
||||
win32_keymap = GDK_WIN32_KEYMAP (_gdk_win32_display_get_keymap (display));
|
||||
impl = GDK_WIN32_SURFACE (window);
|
||||
impl = GDK_WIN32_SURFACE (window);
|
||||
|
||||
API_CALL (GetKeyboardState, (key_state));
|
||||
API_CALL (GetKeyboardState, (key_state));
|
||||
|
||||
ccount = 0;
|
||||
ccount = 0;
|
||||
|
||||
if (msg->wParam == VK_PACKET)
|
||||
{
|
||||
ccount = ToUnicode (VK_PACKET, HIWORD (msg->lParam), key_state, wbuf, 1, 0);
|
||||
if (ccount == 1)
|
||||
{
|
||||
if (wbuf[0] >= 0xD800 && wbuf[0] < 0xDC00)
|
||||
{
|
||||
if (msg->message == WM_KEYDOWN)
|
||||
impl->leading_surrogate_keydown = wbuf[0];
|
||||
else
|
||||
impl->leading_surrogate_keyup = wbuf[0];
|
||||
if (msg->wParam == VK_PACKET)
|
||||
{
|
||||
ccount = ToUnicode (VK_PACKET, HIWORD (msg->lParam), key_state, wbuf, 1, 0);
|
||||
if (ccount == 1)
|
||||
{
|
||||
if (wbuf[0] >= 0xD800 && wbuf[0] < 0xDC00)
|
||||
{
|
||||
if (msg->message == WM_KEYDOWN)
|
||||
impl->leading_surrogate_keydown = wbuf[0];
|
||||
else
|
||||
impl->leading_surrogate_keyup = wbuf[0];
|
||||
|
||||
/* don't emit an event */
|
||||
return_val = TRUE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* wait until an event is created */;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* don't emit an event */
|
||||
return_val = TRUE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* wait until an event is created */;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
keyval = GDK_KEY_VoidSymbol;
|
||||
keycode = msg->wParam;
|
||||
keyval = GDK_KEY_VoidSymbol;
|
||||
keycode = msg->wParam;
|
||||
|
||||
if (HIWORD (msg->lParam) & KF_EXTENDED)
|
||||
{
|
||||
switch (msg->wParam)
|
||||
{
|
||||
case VK_CONTROL:
|
||||
keycode = VK_RCONTROL;
|
||||
break;
|
||||
case VK_SHIFT: /* Actually, KF_EXTENDED is not set
|
||||
* for the right shift key.
|
||||
*/
|
||||
keycode = VK_RSHIFT;
|
||||
break;
|
||||
case VK_MENU:
|
||||
keycode = VK_RMENU;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (msg->wParam == VK_SHIFT &&
|
||||
LOBYTE (HIWORD (msg->lParam)) == _gdk_win32_keymap_get_rshift_scancode (win32_keymap))
|
||||
keycode = VK_RSHIFT;
|
||||
if (HIWORD (msg->lParam) & KF_EXTENDED)
|
||||
{
|
||||
switch (msg->wParam)
|
||||
{
|
||||
case VK_CONTROL:
|
||||
keycode = VK_RCONTROL;
|
||||
break;
|
||||
case VK_SHIFT: /* Actually, KF_EXTENDED is not set
|
||||
* for the right shift key.
|
||||
*/
|
||||
keycode = VK_RSHIFT;
|
||||
break;
|
||||
case VK_MENU:
|
||||
keycode = VK_RMENU;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (msg->wParam == VK_SHIFT &&
|
||||
LOBYTE (HIWORD (msg->lParam)) == _gdk_win32_keymap_get_rshift_scancode (GDK_WIN32_KEYMAP (_gdk_win32_display_get_keymap (_gdk_display))))
|
||||
keycode = VK_RSHIFT;
|
||||
|
||||
is_modifier = (msg->wParam == VK_CONTROL ||
|
||||
msg->wParam == VK_SHIFT ||
|
||||
msg->wParam == VK_MENU);
|
||||
is_modifier = (msg->wParam == VK_CONTROL ||
|
||||
msg->wParam == VK_SHIFT ||
|
||||
msg->wParam == VK_MENU);
|
||||
/* g_print ("ctrl:%02x lctrl:%02x rctrl:%02x alt:%02x lalt:%02x ralt:%02x\n", key_state[VK_CONTROL], key_state[VK_LCONTROL], key_state[VK_RCONTROL], key_state[VK_MENU], key_state[VK_LMENU], key_state[VK_RMENU]); */
|
||||
|
||||
state = build_key_event_state (key_state);
|
||||
group = get_active_group ();
|
||||
state = build_key_event_state (key_state);
|
||||
group = get_active_group ();
|
||||
|
||||
if (msg->wParam == VK_PACKET && ccount == 1)
|
||||
{
|
||||
if (wbuf[0] >= 0xD800 && wbuf[0] < 0xDC00)
|
||||
{
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
else if (wbuf[0] >= 0xDC00 && wbuf[0] < 0xE000)
|
||||
{
|
||||
wchar_t leading;
|
||||
if (msg->wParam == VK_PACKET && ccount == 1)
|
||||
{
|
||||
if (wbuf[0] >= 0xD800 && wbuf[0] < 0xDC00)
|
||||
{
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
else if (wbuf[0] >= 0xDC00 && wbuf[0] < 0xE000)
|
||||
{
|
||||
wchar_t leading;
|
||||
|
||||
if (msg->message == WM_KEYDOWN)
|
||||
leading = impl->leading_surrogate_keydown;
|
||||
else
|
||||
leading = impl->leading_surrogate_keyup;
|
||||
if (msg->message == WM_KEYDOWN)
|
||||
leading = impl->leading_surrogate_keydown;
|
||||
else
|
||||
leading = impl->leading_surrogate_keyup;
|
||||
|
||||
keyval = gdk_unicode_to_keyval ((leading - 0xD800) * 0x400 + wbuf[0] - 0xDC00 + 0x10000);
|
||||
}
|
||||
else
|
||||
{
|
||||
keyval = gdk_unicode_to_keyval (wbuf[0]);
|
||||
}
|
||||
keyval = gdk_unicode_to_keyval ((leading - 0xD800) * 0x400 + wbuf[0] - 0xDC00 + 0x10000);
|
||||
}
|
||||
else
|
||||
{
|
||||
keyval = gdk_unicode_to_keyval (wbuf[0]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gdk_keymap_translate_keyboard_state (_gdk_win32_display_get_keymap (display),
|
||||
keycode,
|
||||
state,
|
||||
group,
|
||||
&keyval,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
translated.keyval = keyval;
|
||||
translated.consumed = 0;
|
||||
translated.layout = 0;
|
||||
translated.level = 0;
|
||||
if (msg->message == WM_KEYDOWN)
|
||||
impl->leading_surrogate_keydown = 0;
|
||||
else
|
||||
impl->leading_surrogate_keyup = 0;
|
||||
|
||||
no_lock = translated;
|
||||
}
|
||||
else
|
||||
{
|
||||
int level = 0;
|
||||
int effective_group = 0;
|
||||
GdkModifierType consumed = 0;
|
||||
/* Only one release key event is fired when both shift keys are pressed together
|
||||
and then released. In order to send the missing event, press events for shift
|
||||
keys are recorded and sent together when the release event occurs.
|
||||
Other modifiers (e.g. ctrl, alt) don't have this problem. */
|
||||
if (msg->message == WM_KEYDOWN && msg->wParam == VK_SHIFT)
|
||||
{
|
||||
int pressed_shift = msg->lParam & 0xffffff; /* mask shift modifier */
|
||||
if (both_shift_pressed[0] == 0)
|
||||
both_shift_pressed[0] = pressed_shift;
|
||||
else if (both_shift_pressed[0] != pressed_shift)
|
||||
both_shift_pressed[1] = pressed_shift;
|
||||
}
|
||||
|
||||
gdk_keymap_translate_keyboard_state ((GdkKeymap*) win32_keymap, keycode, state, group,
|
||||
&keyval, &effective_group, &level, &consumed);
|
||||
translated.keyval = keyval;
|
||||
translated.consumed = consumed;
|
||||
translated.layout = effective_group;
|
||||
translated.level = level;
|
||||
if (msg->message == WM_KEYUP && msg->wParam == VK_SHIFT)
|
||||
{
|
||||
if (both_shift_pressed[0] != 0 && both_shift_pressed[1] != 0)
|
||||
{
|
||||
int tmp_retval;
|
||||
MSG fake_release = *msg;
|
||||
int pressed_shift = msg->lParam & 0xffffff;
|
||||
|
||||
gdk_keymap_translate_keyboard_state ((GdkKeymap*) win32_keymap, keycode,
|
||||
state & ~GDK_LOCK_MASK, group, &keyval,
|
||||
&effective_group, &level, &consumed);
|
||||
no_lock.keyval = keyval;
|
||||
no_lock.consumed = consumed;
|
||||
no_lock.layout = effective_group;
|
||||
no_lock.level = level;
|
||||
}
|
||||
if (both_shift_pressed[0] == pressed_shift)
|
||||
fake_release.lParam = both_shift_pressed[1];
|
||||
else
|
||||
fake_release.lParam = both_shift_pressed[0];
|
||||
|
||||
if (msg->message == WM_KEYDOWN)
|
||||
impl->leading_surrogate_keydown = 0;
|
||||
else
|
||||
impl->leading_surrogate_keyup = 0;
|
||||
both_shift_pressed[0] = both_shift_pressed[1] = 0;
|
||||
gdk_event_translate (&fake_release, &tmp_retval);
|
||||
}
|
||||
both_shift_pressed[0] = both_shift_pressed[1] = 0;
|
||||
}
|
||||
|
||||
/* Only one release key event is fired when both shift keys are pressed together
|
||||
and then released. In order to send the missing event, press events for shift
|
||||
keys are recorded and sent together when the release event occurs.
|
||||
Other modifiers (e.g. ctrl, alt) don't have this problem. */
|
||||
if (msg->message == WM_KEYDOWN && msg->wParam == VK_SHIFT)
|
||||
{
|
||||
int pressed_shift = msg->lParam & 0xffffff; /* mask shift modifier */
|
||||
if (both_shift_pressed[0] == 0)
|
||||
both_shift_pressed[0] = pressed_shift;
|
||||
else if (both_shift_pressed[0] != pressed_shift)
|
||||
both_shift_pressed[1] = pressed_shift;
|
||||
}
|
||||
/* Reset ALT_MASK if it is the Alt key itself */
|
||||
if (msg->wParam == VK_MENU)
|
||||
state &= ~GDK_ALT_MASK;
|
||||
|
||||
if (msg->message == WM_KEYUP && msg->wParam == VK_SHIFT)
|
||||
{
|
||||
if (both_shift_pressed[0] != 0 && both_shift_pressed[1] != 0)
|
||||
{
|
||||
int tmp_retval;
|
||||
MSG fake_release = *msg;
|
||||
int pressed_shift = msg->lParam & 0xffffff;
|
||||
/* FIXME do proper translation */
|
||||
translated.keyval = keyval;
|
||||
translated.consumed = 0;
|
||||
translated.layout = group;
|
||||
translated.level = 0;
|
||||
event = gdk_key_event_new ((msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN)
|
||||
? GDK_KEY_PRESS
|
||||
: GDK_KEY_RELEASE,
|
||||
window,
|
||||
device_manager_win32->core_keyboard,
|
||||
_gdk_win32_get_next_tick (msg->time),
|
||||
keycode,
|
||||
state,
|
||||
is_modifier,
|
||||
&translated,
|
||||
&translated);
|
||||
|
||||
if (both_shift_pressed[0] == pressed_shift)
|
||||
fake_release.lParam = both_shift_pressed[1];
|
||||
else
|
||||
fake_release.lParam = both_shift_pressed[0];
|
||||
_gdk_win32_append_event (event);
|
||||
|
||||
both_shift_pressed[0] = both_shift_pressed[1] = 0;
|
||||
gdk_event_translate (&fake_release, &tmp_retval);
|
||||
}
|
||||
both_shift_pressed[0] = both_shift_pressed[1] = 0;
|
||||
}
|
||||
|
||||
/* Reset ALT_MASK if it is the Alt key itself */
|
||||
if (msg->wParam == VK_MENU)
|
||||
state &= ~GDK_ALT_MASK;
|
||||
|
||||
event = gdk_key_event_new ((msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN)
|
||||
? GDK_KEY_PRESS
|
||||
: GDK_KEY_RELEASE,
|
||||
window,
|
||||
device_manager_win32->core_keyboard,
|
||||
_gdk_win32_get_next_tick (msg->time),
|
||||
keycode,
|
||||
state,
|
||||
is_modifier,
|
||||
&translated,
|
||||
&no_lock);
|
||||
|
||||
_gdk_win32_append_event (event);
|
||||
|
||||
return_val = TRUE;
|
||||
}
|
||||
return_val = TRUE;
|
||||
break;
|
||||
|
||||
case WM_SYSCHAR:
|
||||
@@ -2104,82 +2117,73 @@ gdk_event_translate (MSG *msg,
|
||||
break;
|
||||
|
||||
case WM_IME_COMPOSITION:
|
||||
{
|
||||
BYTE key_state[256];
|
||||
wchar_t wbuf[100];
|
||||
int ccount = 0;
|
||||
/* On Win2k WM_IME_CHAR doesn't work correctly for non-Unicode
|
||||
* applications. Thus, handle WM_IME_COMPOSITION with
|
||||
* GCS_RESULTSTR instead, fetch the Unicode chars from the IME
|
||||
* with ImmGetCompositionStringW().
|
||||
*
|
||||
* See for instance
|
||||
* http://groups.google.com/groups?selm=natX5.57%24g77.19788%40nntp2.onemain.com
|
||||
* and
|
||||
* http://groups.google.com/groups?selm=u2XfrXw5BHA.1628%40tkmsftngp02
|
||||
* for comments by other people that seems to have the same
|
||||
* experience. WM_IME_CHAR just gives question marks, apparently
|
||||
* because of going through some conversion to the current code
|
||||
* page.
|
||||
*
|
||||
* WM_IME_CHAR might work on NT4 or Win9x with ActiveIMM, but
|
||||
* use WM_IME_COMPOSITION there, too, to simplify the code.
|
||||
*/
|
||||
GDK_NOTE (EVENTS, g_print (" %#lx", (long) msg->lParam));
|
||||
|
||||
/* On Win2k WM_IME_CHAR doesn't work correctly for non-Unicode
|
||||
* applications. Thus, handle WM_IME_COMPOSITION with
|
||||
* GCS_RESULTSTR instead, fetch the Unicode chars from the IME
|
||||
* with ImmGetCompositionStringW().
|
||||
*
|
||||
* See for instance
|
||||
* http://groups.google.com/groups?selm=natX5.57%24g77.19788%40nntp2.onemain.com
|
||||
* and
|
||||
* http://groups.google.com/groups?selm=u2XfrXw5BHA.1628%40tkmsftngp02
|
||||
* for comments by other people that seems to have the same
|
||||
* experience. WM_IME_CHAR just gives question marks, apparently
|
||||
* because of going through some conversion to the current code
|
||||
* page.
|
||||
*
|
||||
* WM_IME_CHAR might work on NT4 or Win9x with ActiveIMM, but
|
||||
* use WM_IME_COMPOSITION there, too, to simplify the code.
|
||||
*/
|
||||
GDK_NOTE (EVENTS, g_print (" %#lx", (long) msg->lParam));
|
||||
if (!(msg->lParam & GCS_RESULTSTR))
|
||||
break;
|
||||
|
||||
if (!(msg->lParam & GCS_RESULTSTR))
|
||||
break;
|
||||
if (GDK_SURFACE_DESTROYED (window))
|
||||
break;
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (window))
|
||||
break;
|
||||
himc = ImmGetContext (msg->hwnd);
|
||||
ccount = ImmGetCompositionStringW (himc, GCS_RESULTSTR,
|
||||
wbuf, sizeof (wbuf));
|
||||
ImmReleaseContext (msg->hwnd, himc);
|
||||
|
||||
himc = ImmGetContext (msg->hwnd);
|
||||
ccount = ImmGetCompositionStringW (himc, GCS_RESULTSTR,
|
||||
wbuf, sizeof (wbuf));
|
||||
ImmReleaseContext (msg->hwnd, himc);
|
||||
ccount /= 2;
|
||||
|
||||
ccount /= 2;
|
||||
API_CALL (GetKeyboardState, (key_state));
|
||||
|
||||
API_CALL (GetKeyboardState, (key_state));
|
||||
for (i = 0; i < ccount; i++)
|
||||
{
|
||||
/* Build a key press event */
|
||||
translated.keyval = gdk_unicode_to_keyval (wbuf[i]);
|
||||
translated.consumed = 0;
|
||||
translated.layout = get_active_group ();
|
||||
translated.level = 0;
|
||||
event = gdk_key_event_new (GDK_KEY_PRESS,
|
||||
window,
|
||||
device_manager_win32->core_keyboard,
|
||||
_gdk_win32_get_next_tick (msg->time),
|
||||
0,
|
||||
build_key_event_state (key_state),
|
||||
FALSE,
|
||||
&translated,
|
||||
&translated);
|
||||
|
||||
for (i = 0; i < ccount; i++)
|
||||
{
|
||||
GdkTranslatedKey translated;
|
||||
_gdk_win32_append_event (event);
|
||||
|
||||
/* Build a key press event */
|
||||
translated.keyval = gdk_unicode_to_keyval (wbuf[i]);
|
||||
translated.consumed = 0;
|
||||
translated.layout = get_active_group ();
|
||||
translated.level = 0;
|
||||
event = gdk_key_event_new (GDK_KEY_PRESS,
|
||||
window,
|
||||
device_manager_win32->core_keyboard,
|
||||
_gdk_win32_get_next_tick (msg->time),
|
||||
0,
|
||||
build_key_event_state (key_state),
|
||||
FALSE,
|
||||
&translated,
|
||||
&translated);
|
||||
/* Build a key release event. */
|
||||
event = gdk_key_event_new (GDK_KEY_RELEASE,
|
||||
window,
|
||||
device_manager_win32->core_keyboard,
|
||||
_gdk_win32_get_next_tick (msg->time),
|
||||
0,
|
||||
build_key_event_state (key_state),
|
||||
FALSE,
|
||||
&translated,
|
||||
&translated);
|
||||
|
||||
_gdk_win32_append_event (event);
|
||||
|
||||
/* Build a key release event. */
|
||||
event = gdk_key_event_new (GDK_KEY_RELEASE,
|
||||
window,
|
||||
device_manager_win32->core_keyboard,
|
||||
_gdk_win32_get_next_tick (msg->time),
|
||||
0,
|
||||
build_key_event_state (key_state),
|
||||
FALSE,
|
||||
&translated,
|
||||
&translated);
|
||||
|
||||
_gdk_win32_append_event (event);
|
||||
}
|
||||
|
||||
return_val = TRUE;
|
||||
}
|
||||
_gdk_win32_append_event (event);
|
||||
}
|
||||
return_val = TRUE;
|
||||
break;
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
@@ -2215,7 +2219,10 @@ gdk_event_translate (MSG *msg,
|
||||
if (pointer_grab == NULL)
|
||||
{
|
||||
SetCapture (GDK_SURFACE_HWND (window));
|
||||
g_set_object (&implicit_grab_surface, g_object_ref (window));
|
||||
}
|
||||
else
|
||||
g_set_object (&implicit_grab_surface, NULL);
|
||||
|
||||
generate_button_event (GDK_BUTTON_PRESS, button,
|
||||
window, msg);
|
||||
@@ -2250,7 +2257,7 @@ gdk_event_translate (MSG *msg,
|
||||
|
||||
g_set_object (&window, find_window_for_mouse_event (window, msg));
|
||||
|
||||
if (pointer_grab != NULL && pointer_grab->implicit)
|
||||
if (pointer_grab == NULL && implicit_grab_surface != NULL)
|
||||
{
|
||||
int state = build_pointer_event_state (msg);
|
||||
|
||||
@@ -2273,16 +2280,19 @@ gdk_event_translate (MSG *msg,
|
||||
|
||||
synthesize_crossing_events (display,
|
||||
_gdk_device_manager->system_pointer,
|
||||
pointer_grab->surface, new_window,
|
||||
implicit_grab_surface, new_window,
|
||||
GDK_CROSSING_UNGRAB,
|
||||
&msg->pt,
|
||||
0, /* TODO: Set right mask */
|
||||
_gdk_win32_get_next_tick (msg->time),
|
||||
FALSE);
|
||||
g_set_object (&implicit_grab_surface, NULL);
|
||||
g_set_object (&mouse_window, new_window);
|
||||
mouse_window_ignored_leave = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
g_set_object (&implicit_grab_surface, NULL);
|
||||
|
||||
generate_button_event (GDK_BUTTON_RELEASE, button,
|
||||
window, msg);
|
||||
@@ -2970,22 +2980,17 @@ gdk_event_translate (MSG *msg,
|
||||
break;
|
||||
|
||||
case WM_WINDOWPOSCHANGING:
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
{
|
||||
char buf[256];
|
||||
GDK_NOTE (EVENTS, (windowpos = (WINDOWPOS *) msg->lParam,
|
||||
g_print (" %s %s %dx%d@%+d%+d now below %p",
|
||||
_gdk_win32_surface_pos_bits_to_string (windowpos->flags),
|
||||
(windowpos->hwndInsertAfter == HWND_BOTTOM ? "BOTTOM" :
|
||||
(windowpos->hwndInsertAfter == HWND_NOTOPMOST ? "NOTOPMOST" :
|
||||
(windowpos->hwndInsertAfter == HWND_TOP ? "TOP" :
|
||||
(windowpos->hwndInsertAfter == HWND_TOPMOST ? "TOPMOST" :
|
||||
(sprintf (buf, "%p", windowpos->hwndInsertAfter),
|
||||
buf))))),
|
||||
windowpos->cx, windowpos->cy, windowpos->x, windowpos->y,
|
||||
GetNextWindow (msg->hwnd, GW_HWNDPREV))));
|
||||
}
|
||||
#endif
|
||||
GDK_NOTE (EVENTS, (windowpos = (WINDOWPOS *) msg->lParam,
|
||||
g_print (" %s %s %dx%d@%+d%+d now below %p",
|
||||
_gdk_win32_surface_pos_bits_to_string (windowpos->flags),
|
||||
(windowpos->hwndInsertAfter == HWND_BOTTOM ? "BOTTOM" :
|
||||
(windowpos->hwndInsertAfter == HWND_NOTOPMOST ? "NOTOPMOST" :
|
||||
(windowpos->hwndInsertAfter == HWND_TOP ? "TOP" :
|
||||
(windowpos->hwndInsertAfter == HWND_TOPMOST ? "TOPMOST" :
|
||||
(sprintf (buf, "%p", windowpos->hwndInsertAfter),
|
||||
buf))))),
|
||||
windowpos->cx, windowpos->cy, windowpos->x, windowpos->y,
|
||||
GetNextWindow (msg->hwnd, GW_HWNDPREV))));
|
||||
|
||||
if (GDK_SURFACE_IS_MAPPED (window))
|
||||
{
|
||||
@@ -3011,21 +3016,15 @@ gdk_event_translate (MSG *msg,
|
||||
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
windowpos = (WINDOWPOS *) msg->lParam;
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
{
|
||||
char buf[256];
|
||||
GDK_NOTE (EVENTS, g_print (" %s %s %dx%d@%+d%+d",
|
||||
_gdk_win32_surface_pos_bits_to_string (windowpos->flags),
|
||||
(windowpos->hwndInsertAfter == HWND_BOTTOM ? "BOTTOM" :
|
||||
(windowpos->hwndInsertAfter == HWND_NOTOPMOST ? "NOTOPMOST" :
|
||||
(windowpos->hwndInsertAfter == HWND_TOP ? "TOP" :
|
||||
(windowpos->hwndInsertAfter == HWND_TOPMOST ? "TOPMOST" :
|
||||
(sprintf (buf, "%p", windowpos->hwndInsertAfter),
|
||||
buf))))),
|
||||
windowpos->cx, windowpos->cy, windowpos->x, windowpos->y));
|
||||
}
|
||||
#endif
|
||||
GDK_NOTE (EVENTS, g_print (" %s %s %dx%d@%+d%+d",
|
||||
_gdk_win32_surface_pos_bits_to_string (windowpos->flags),
|
||||
(windowpos->hwndInsertAfter == HWND_BOTTOM ? "BOTTOM" :
|
||||
(windowpos->hwndInsertAfter == HWND_NOTOPMOST ? "NOTOPMOST" :
|
||||
(windowpos->hwndInsertAfter == HWND_TOP ? "TOP" :
|
||||
(windowpos->hwndInsertAfter == HWND_TOPMOST ? "TOPMOST" :
|
||||
(sprintf (buf, "%p", windowpos->hwndInsertAfter),
|
||||
buf))))),
|
||||
windowpos->cx, windowpos->cy, windowpos->x, windowpos->y));
|
||||
|
||||
/* Break grabs on unmap or minimize */
|
||||
if (windowpos->flags & SWP_HIDEWINDOW ||
|
||||
|
||||
@@ -258,6 +258,9 @@ gdk_win32_display_init_wgl (GdkDisplay *display,
|
||||
if (!gdk_gl_backend_can_be_used (GDK_GL_WGL, error))
|
||||
return FALSE;
|
||||
|
||||
if (display_win32->wgl_pixel_format != 0)
|
||||
return TRUE;
|
||||
|
||||
/* acquire and cache dummy Window (HWND & HDC) and
|
||||
* dummy GL Context, it is used to query functions
|
||||
* and used for other stuff as well
|
||||
@@ -296,6 +299,8 @@ gdk_win32_display_init_wgl (GdkDisplay *display,
|
||||
}
|
||||
}
|
||||
|
||||
display_win32->wgl_pixel_format = best_idx;
|
||||
|
||||
display_win32->hasWglARBCreateContext =
|
||||
epoxy_has_wgl_extension (hdc, "WGL_ARB_create_context");
|
||||
display_win32->hasWglEXTSwapControl =
|
||||
@@ -427,13 +432,33 @@ create_wgl_context (HDC hdc,
|
||||
goto gl_fail;
|
||||
}
|
||||
|
||||
hglrc = create_wgl_context_with_attribs (hdc,
|
||||
hglrc_base,
|
||||
share,
|
||||
flags,
|
||||
major,
|
||||
minor,
|
||||
is_legacy);
|
||||
/*
|
||||
* We need a Core GL 4.1 context in order to use the GL support in
|
||||
* the GStreamer media widget backend, but wglCreateContextAttribsARB()
|
||||
* may only give us the GL context version that we ask for here, and
|
||||
* nothing more. So, if we are asking for a pre-GL 4.1 context,
|
||||
* try to ask for a 4.1 context explicitly first. If that is not supported,
|
||||
* then we fall back to whatever version that we were asking for (or, even a
|
||||
* legacy context if that fails), at a price of not able to have GL support
|
||||
* for the media GStreamer backend.
|
||||
*/
|
||||
if (major < 4 || (major == 4 && minor < 1))
|
||||
hglrc = create_wgl_context_with_attribs (hdc,
|
||||
hglrc_base,
|
||||
share,
|
||||
flags,
|
||||
4,
|
||||
1,
|
||||
is_legacy);
|
||||
|
||||
if (hglrc == NULL)
|
||||
hglrc = create_wgl_context_with_attribs (hdc,
|
||||
hglrc_base,
|
||||
share,
|
||||
flags,
|
||||
major,
|
||||
minor,
|
||||
is_legacy);
|
||||
|
||||
/* return the legacy context we have if it could be setup properly, in case the 3.0+ context creation failed */
|
||||
if (hglrc == NULL)
|
||||
@@ -539,27 +564,10 @@ gdk_win32_gl_context_wgl_realize (GdkGLContext *context,
|
||||
if (!gdk_gl_context_is_api_allowed (context, GDK_GL_API_GL, error))
|
||||
return 0;
|
||||
|
||||
gdk_gl_context_get_required_version (context, &major, &minor);
|
||||
debug_bit = gdk_gl_context_get_debug_enabled (context);
|
||||
compat_bit = gdk_gl_context_get_forward_compatible (context);
|
||||
|
||||
/*
|
||||
* We may need a Core GL 4.1+ context in order to use the GL support in
|
||||
* the GStreamer media widget backend (such as on Intel drivers), but
|
||||
* wglCreateContextAttribsARB() may only give us the GL context version
|
||||
* that we ask for here, and nothing more. So, improve things here by
|
||||
* asking for the GL version that is reported to us via epoxy_gl_version(),
|
||||
* rather than the default GL core 3.2 context. Save this up in our
|
||||
* GdkGLContext so that subsequent contexts that are shared with this
|
||||
* context are created likewise too.
|
||||
*/
|
||||
if (share != NULL)
|
||||
gdk_gl_context_get_required_version (share, &major, &minor);
|
||||
else
|
||||
{
|
||||
major = display_win32->gl_version / 10;
|
||||
minor = display_win32->gl_version % 10;
|
||||
}
|
||||
|
||||
if (surface != NULL)
|
||||
hdc = GDK_WIN32_SURFACE (surface)->hdc;
|
||||
else
|
||||
@@ -626,7 +634,6 @@ gdk_win32_gl_context_wgl_realize (GdkGLContext *context,
|
||||
|
||||
/* Ensure that any other context is created with a legacy bit set */
|
||||
gdk_gl_context_set_is_legacy (context, legacy_bit);
|
||||
gdk_gl_context_set_required_version (context, major, minor);
|
||||
|
||||
return GDK_GL_API_GL;
|
||||
}
|
||||
@@ -721,10 +728,9 @@ gdk_win32_display_get_wgl_version (GdkDisplay *display,
|
||||
if (!GDK_IS_WIN32_DISPLAY (display))
|
||||
return FALSE;
|
||||
|
||||
if (!gdk_gl_backend_can_be_used (GDK_GL_WGL, NULL))
|
||||
return FALSE;
|
||||
|
||||
display_win32 = GDK_WIN32_DISPLAY (display);
|
||||
if (display_win32->wgl_pixel_format == 0)
|
||||
return FALSE;
|
||||
|
||||
if (major != NULL)
|
||||
*major = display_win32->gl_version / 10;
|
||||
|
||||
@@ -38,6 +38,7 @@ int _gdk_input_ignore_core;
|
||||
|
||||
HKL _gdk_input_locale;
|
||||
gboolean _gdk_input_locale_is_ime = FALSE;
|
||||
UINT _gdk_input_codepage;
|
||||
|
||||
GdkWin32ModalOpKind _modal_operation_in_progress = GDK_WIN32_MODAL_OP_NONE;
|
||||
HWND _modal_move_resize_window = NULL;
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Philip Zander
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _WIN64
|
||||
#define GDK_WIN32_COMPILE_FOR_WOW64 1
|
||||
#include "gdkkeys-win32-impl.c"
|
||||
#endif
|
||||
@@ -1,566 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Philip Zander
|
||||
* Copyright (c) 2018 Microsoft
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* NOTE: When compiling the 32-bit version of the library, in addition to being
|
||||
* compiled as a regular source file, this file is also included by
|
||||
* gdkkeys-win32-impl-wow64.c to generate an alternate version of the code
|
||||
* intended for running on a 64-bit kernel. Because of the way keyboard layout
|
||||
* DLLs work on Windows, we have to generate two versions and decide at runtime
|
||||
* which code path to execute. You can read more about the specifics below, in
|
||||
* the section about KBD_LONG_POINTER. */
|
||||
|
||||
#include "gdkkeys-win32.h"
|
||||
|
||||
#ifndef GDK_WIN32_COMPILE_FOR_WOW64
|
||||
#define GDK_WIN32_COMPILE_FOR_WOW64 0
|
||||
#endif
|
||||
|
||||
/* This is our equivalent of the KBD_LONG_POINTER macro in Microsoft's kbd.h.
|
||||
*
|
||||
* A KBD_LONG_POINTER represents a pointer native to the *host*.
|
||||
* I.e. 32 bits on 32-bit Windows and 64 bits on 64-bit Windows.
|
||||
*
|
||||
* This is *not* the same as the the bitness of the application, since it is
|
||||
* possible to execute 32-bit binaries on either a 32-bit *or* a 64-bit host.
|
||||
* On a 64-bit host, KBD_LONG_PTR will be 64-bits, even if the application
|
||||
* itself is 32-bit. (Whereas on a 32-bit host, it will be 32-bit.)
|
||||
*
|
||||
* For clarity, here is an overview of the bit-size of KBD_LONG_POINTER on all
|
||||
* possible host & app combinations:
|
||||
*
|
||||
* Host 32 64
|
||||
* App +-----------
|
||||
* 32 | 32 64
|
||||
* 64 | - 64
|
||||
*
|
||||
* In the official MS headers, KBD_LONG_POINTER is implemented via a macro
|
||||
* which expands to the attribute `__ptr64` if the keyboard driver is
|
||||
* compiled for a 64 bit host. Unfortunately, `__ptr64` is only
|
||||
* supported by MSVC. We use a union here as a workaround.
|
||||
*
|
||||
* For all KBD_LONG_POINTERs, we define an alias starting with "KLP".
|
||||
* Our naming schema (inspired by the Windows headers) is thus the following:
|
||||
* - FOO: The type FOO itself
|
||||
* - PFOO: Regular pointer to the type FOO
|
||||
* - KLPFOO: Keyboard Long Pointer to the type FOO
|
||||
*/
|
||||
|
||||
#if GDK_WIN32_COMPILE_FOR_WOW64
|
||||
#define DEFINE_KBD_LONG_POINTER(type) \
|
||||
typedef union { \
|
||||
P##type ptr; \
|
||||
UINT64 _align; \
|
||||
} KLP##type
|
||||
#else
|
||||
#define DEFINE_KBD_LONG_POINTER(type) \
|
||||
typedef union { \
|
||||
P##type ptr; \
|
||||
} KLP##type
|
||||
#endif
|
||||
|
||||
DEFINE_KBD_LONG_POINTER (USHORT);
|
||||
DEFINE_KBD_LONG_POINTER (VOID);
|
||||
|
||||
/* Driver definitions
|
||||
* See
|
||||
* https://github.com/microsoft/windows-rs/blob/0.28.0/crates/deps/sys/src/Windows/Win32/UI/Input/KeyboardAndMouse/mod.rs
|
||||
*
|
||||
* For more information on how these structures work, see also:
|
||||
* https://github.com/microsoft/Windows-driver-samples/tree/f0adcda012820b1cd44a8b3a1953baf478029738/input/layout
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BYTE Vk;
|
||||
BYTE ModBits;
|
||||
} VK_TO_BIT, *PVK_TO_BIT;
|
||||
|
||||
DEFINE_KBD_LONG_POINTER (VK_TO_BIT);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
KLPVK_TO_BIT pVkToBit;
|
||||
WORD wMaxModBits;
|
||||
BYTE ModNumber[1];
|
||||
} MODIFIERS, *PMODIFIERS;
|
||||
|
||||
DEFINE_KBD_LONG_POINTER (MODIFIERS);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BYTE Vsc;
|
||||
USHORT Vk;
|
||||
} VSC_VK, *PVSC_VK;
|
||||
|
||||
DEFINE_KBD_LONG_POINTER (VSC_VK);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BYTE Vk;
|
||||
BYTE Vsc;
|
||||
} VK_VSC, *PVK_VSC;
|
||||
|
||||
DEFINE_KBD_LONG_POINTER (VK_VSC);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BYTE VirtualKey;
|
||||
BYTE Attributes;
|
||||
WCHAR wch[1];
|
||||
} VK_TO_WCHARS, *PVK_TO_WCHARS;
|
||||
|
||||
DEFINE_KBD_LONG_POINTER (VK_TO_WCHARS);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
KLPVK_TO_WCHARS pVkToWchars;
|
||||
BYTE nModifications;
|
||||
BYTE cbSize;
|
||||
} VK_TO_WCHAR_TABLE, *PVK_TO_WCHAR_TABLE;
|
||||
|
||||
DEFINE_KBD_LONG_POINTER (VK_TO_WCHAR_TABLE);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD dwBoth;
|
||||
WCHAR wchComposed;
|
||||
USHORT uFlags;
|
||||
} DEADKEY, *PDEADKEY;
|
||||
|
||||
DEFINE_KBD_LONG_POINTER (DEADKEY);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
KLPMODIFIERS pCharModifiers;
|
||||
KLPVK_TO_WCHAR_TABLE pVkToWcharTable;
|
||||
KLPDEADKEY pDeadKey;
|
||||
KLPVOID pKeyNames;
|
||||
KLPVOID pKeyNamesExt;
|
||||
KLPVOID pKeyNamesDead;
|
||||
KLPUSHORT pusVSCtoVK;
|
||||
BYTE bMaxVSCtoVK;
|
||||
KLPVSC_VK pVSCtoVK_E0;
|
||||
KLPVSC_VK pVSCtoVK_E1;
|
||||
DWORD fLocaleFlags;
|
||||
BYTE nLgMaxd;
|
||||
BYTE cbLgEntry;
|
||||
KLPVOID pLigature;
|
||||
} KBDTABLES, *PKBDTABLES;
|
||||
|
||||
DEFINE_KBD_LONG_POINTER (KBDTABLES);
|
||||
|
||||
/* End of declarations */
|
||||
|
||||
static BYTE
|
||||
keystate_to_modbits (GdkWin32KeymapLayoutInfo *info,
|
||||
const BYTE keystate[256])
|
||||
{
|
||||
PKBDTABLES tables = (PKBDTABLES) info->tables;
|
||||
PVK_TO_BIT vk_to_bit;
|
||||
BYTE result = 0;
|
||||
int i;
|
||||
|
||||
if (tables == NULL)
|
||||
return 0;
|
||||
|
||||
vk_to_bit = tables->pCharModifiers.ptr->pVkToBit.ptr;
|
||||
|
||||
for (i = 0; vk_to_bit[i].Vk != 0; ++i)
|
||||
if (keystate[vk_to_bit[i].Vk] & 0x80)
|
||||
result |= vk_to_bit[i].ModBits;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static BYTE
|
||||
modbits_to_level (GdkWin32KeymapLayoutInfo *info,
|
||||
BYTE modbits)
|
||||
{
|
||||
PKBDTABLES tables = (PKBDTABLES) info->tables;
|
||||
PMODIFIERS modifiers;
|
||||
|
||||
if (tables == NULL)
|
||||
return 0;
|
||||
|
||||
modifiers = tables->pCharModifiers.ptr;
|
||||
if (modbits > modifiers->wMaxModBits)
|
||||
return 0;
|
||||
|
||||
return modifiers->ModNumber[modbits];
|
||||
}
|
||||
|
||||
#define POPCOUNT(b) (!!(b & 0x01) + !!(b & 0x02) + !!(b & 0x04) + !!(b & 0x08) + \
|
||||
!!(b & 0x10) + !!(b & 0x20) + !!(b & 0x40) + !!(b & 0x80))
|
||||
|
||||
/*
|
||||
* vk_to_char_fuzzy:
|
||||
*
|
||||
* For a given key and modifier state, return the best-fit character and the
|
||||
* modifiers used to produce it. Note that not all modifiers need to be used,
|
||||
* because some modifier combination aren't actually mapped in the keyboard
|
||||
* layout (for example the Ctrl key typically has no effect, unless used in
|
||||
* combination with Alt). Such modifiers will not be consumed.
|
||||
*
|
||||
* 'Best-fit' means 'consume as many modifiers as possibe'.
|
||||
*
|
||||
* For example (assuming a neutral lock state):
|
||||
*
|
||||
* - a -> 'a', consumed_mod_bits: []
|
||||
* - Shift + a -> 'A', consumed_mod_bits: [Shift]
|
||||
* - Ctrl + a -> 'a', consumed_mod_bits: []
|
||||
* - Ctrl + Shift + a -> 'A', consumed_mod_bits: [Shift]
|
||||
*
|
||||
* If capslock is active, the result could be:
|
||||
*
|
||||
* - a -> 'A', consumed_mod_bits: [Shift]
|
||||
* - Shift + a -> 'a', consumed_mod_bits: []
|
||||
* - Ctrl + a -> 'a', consumed_mod_bits: []
|
||||
* - Ctrl + Shift + a -> 'A', consumed_mod_bits: [Shift]
|
||||
*
|
||||
* The held down modifiers are supplied in `mod_bits` as a bitmask of KBDSHIFT,
|
||||
* KBDCTRL, KBDALT etc.
|
||||
*
|
||||
* The toggled modifiers are supplied in `lock_state` as a bitmask of CAPLOK and KANALOK.
|
||||
*
|
||||
* If the key combination results in a dead key, `is_dead` will be set to TRUE,
|
||||
* otherwise it will be set to FALSE.
|
||||
*/
|
||||
static WCHAR
|
||||
vk_to_char_fuzzy (GdkWin32KeymapLayoutInfo *info,
|
||||
BYTE mod_bits,
|
||||
BYTE lock_bits,
|
||||
BYTE *consumed_mod_bits,
|
||||
gboolean *is_dead,
|
||||
BYTE vk)
|
||||
{
|
||||
PKBDTABLES tables = (PKBDTABLES) info->tables;
|
||||
|
||||
PVK_TO_WCHAR_TABLE wch_tables;
|
||||
PVK_TO_WCHAR_TABLE wch_table;
|
||||
PVK_TO_WCHARS entry;
|
||||
|
||||
int table_index;
|
||||
int entry_index;
|
||||
int n_levels;
|
||||
int entry_size;
|
||||
|
||||
/* Initialize with defaults */
|
||||
if (consumed_mod_bits)
|
||||
*consumed_mod_bits = 0;
|
||||
if (is_dead)
|
||||
*is_dead = FALSE;
|
||||
|
||||
if (tables == NULL)
|
||||
return WCH_NONE;
|
||||
|
||||
wch_tables = tables->pVkToWcharTable.ptr;
|
||||
|
||||
table_index = info->vk_lookup_table[vk].table;
|
||||
entry_index = info->vk_lookup_table[vk].index;
|
||||
|
||||
if (table_index == -1 || entry_index == -1)
|
||||
return WCH_NONE;
|
||||
|
||||
wch_table = &wch_tables[table_index];
|
||||
|
||||
n_levels = wch_table->nModifications;
|
||||
entry_size = wch_table->cbSize;
|
||||
|
||||
entry = (PVK_TO_WCHARS) ((PBYTE) wch_table->pVkToWchars.ptr
|
||||
+ entry_size*entry_index);
|
||||
|
||||
if (entry->VirtualKey == vk)
|
||||
{
|
||||
gboolean have_sgcaps = FALSE;
|
||||
WCHAR best_char = WCH_NONE;
|
||||
BYTE best_modifiers = 0;
|
||||
int best_score = -1;
|
||||
gboolean best_is_dead = FALSE;
|
||||
int level;
|
||||
|
||||
/* Take toggled keys into account. For example, capslock normally inverts the
|
||||
* state of KBDSHIFT (with some exceptions). */
|
||||
|
||||
/* Key supporting capslock */
|
||||
if ((entry->Attributes & CAPLOK) &&
|
||||
/* Ignore capslock if any modifiers other than shift are pressed.
|
||||
* E.g. on the German layout, CapsLock + AltGr + q is the same as
|
||||
* AltGr + q ('@'), but NOT the same as Shift + AltGr + q (not mapped). */
|
||||
!(mod_bits & ~KBDSHIFT) &&
|
||||
(lock_bits & CAPLOK))
|
||||
mod_bits ^= KBDSHIFT;
|
||||
|
||||
/* Key supporting combination of capslock + altgr */
|
||||
if ((entry->Attributes & CAPLOKALTGR) &&
|
||||
(mod_bits & KBDALTGR) &&
|
||||
(lock_bits & CAPLOK))
|
||||
mod_bits ^= KBDSHIFT;
|
||||
|
||||
/* In the Swiss German layout, CapsLock + key is different from Shift + key
|
||||
* for some keys. For such keys, the characters for active capslock are
|
||||
* in the next entry. */
|
||||
if ((entry->Attributes & SGCAPS) &&
|
||||
(lock_bits & CAPLOK))
|
||||
have_sgcaps = TRUE;
|
||||
|
||||
/* I'm not totally sure how kanalok behaves, for now I assume that there
|
||||
* aren't any special cases. */
|
||||
if ((entry->Attributes & KANALOK) &&
|
||||
(lock_bits & KANALOK))
|
||||
mod_bits ^= KBDKANA;
|
||||
|
||||
/* We try to find the entry with the most matching modifiers */
|
||||
for (level = 0; level < n_levels; ++level)
|
||||
{
|
||||
BYTE candidate_modbits = info->level_to_modbits[level];
|
||||
gboolean candidate_is_dead = FALSE;
|
||||
WCHAR c;
|
||||
int score;
|
||||
|
||||
if (candidate_modbits & ~mod_bits)
|
||||
continue;
|
||||
|
||||
/* Some keys have bogus mappings for the control key, e.g. Ctrl +
|
||||
* Backspace = Delete, Ctrl + [ = 0x1B or even Ctrl + Shift + 6 =
|
||||
* 0x1E on a US keyboard. So we have to ignore all cases of
|
||||
* Ctrl that aren't part of AltGr.
|
||||
*/
|
||||
if ((candidate_modbits & KBDCTRL) && !(candidate_modbits & KBDALT))
|
||||
continue;
|
||||
|
||||
c = entry->wch[level];
|
||||
if (c == WCH_DEAD || have_sgcaps)
|
||||
{
|
||||
/* Next entry contains the undead/capslocked keys */
|
||||
PVK_TO_WCHARS next_entry;
|
||||
next_entry = (PVK_TO_WCHARS) ((PBYTE) wch_table->pVkToWchars.ptr
|
||||
+ entry_size * (entry_index + 1));
|
||||
c = next_entry->wch[level];
|
||||
candidate_is_dead = TRUE;
|
||||
}
|
||||
|
||||
if (c == WCH_DEAD || c == WCH_LGTR || c == WCH_NONE)
|
||||
continue;
|
||||
|
||||
score = POPCOUNT (candidate_modbits & mod_bits);
|
||||
if (score > best_score)
|
||||
{
|
||||
best_score = score;
|
||||
best_char = c;
|
||||
best_modifiers = candidate_modbits;
|
||||
best_is_dead = candidate_is_dead;
|
||||
}
|
||||
}
|
||||
|
||||
if (consumed_mod_bits)
|
||||
*consumed_mod_bits = best_modifiers;
|
||||
|
||||
if (is_dead)
|
||||
*is_dead = best_is_dead;
|
||||
|
||||
return best_char;
|
||||
}
|
||||
|
||||
return WCH_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
init_vk_lookup_table (GdkWin32KeymapLayoutInfo *info)
|
||||
{
|
||||
PKBDTABLES tables = (PKBDTABLES) info->tables;
|
||||
PVK_TO_WCHAR_TABLE wch_tables;
|
||||
PMODIFIERS modifiers;
|
||||
int i, vk, table_idx;
|
||||
|
||||
g_return_if_fail (tables != NULL);
|
||||
|
||||
wch_tables = tables->pVkToWcharTable.ptr;
|
||||
|
||||
/* Initialize empty table */
|
||||
memset (info->vk_lookup_table, -1, sizeof (info->vk_lookup_table));
|
||||
|
||||
/* Initialize level -> modbits lookup table */
|
||||
memset (info->level_to_modbits, 0, sizeof(info->level_to_modbits));
|
||||
info->max_level = 0;
|
||||
|
||||
modifiers = tables->pCharModifiers.ptr;
|
||||
for (i = 0; i <= modifiers->wMaxModBits; ++i)
|
||||
{
|
||||
if (modifiers->ModNumber[i] != SHFT_INVALID &&
|
||||
modifiers->ModNumber[i] != 0 /* Workaround for buggy layouts*/)
|
||||
{
|
||||
if (modifiers->ModNumber[i] > info->max_level)
|
||||
info->max_level = modifiers->ModNumber[i];
|
||||
info->level_to_modbits[modifiers->ModNumber[i]] = i;
|
||||
}
|
||||
}
|
||||
|
||||
info->max_modbit_value = modifiers->wMaxModBits;
|
||||
|
||||
/* For convenience, we add 256 identity-mapped entries corresponding to the VKs.
|
||||
* This allows us to return a pointer to them from the `gdk_keysym_to_key_entry`
|
||||
* function.
|
||||
*/
|
||||
|
||||
for (vk = 0; vk < 256; ++vk)
|
||||
{
|
||||
GdkWin32KeymapKeyEntry key_entry = {0};
|
||||
key_entry.vk = vk;
|
||||
key_entry.mod_bits = 0;
|
||||
key_entry.next = -1;
|
||||
g_array_append_val (info->key_entries, key_entry);
|
||||
}
|
||||
|
||||
/* Special entry for ISO_Left_Tab */
|
||||
{
|
||||
GdkWin32KeymapKeyEntry key_entry = {0};
|
||||
key_entry.vk = VK_TAB;
|
||||
key_entry.mod_bits = KBDSHIFT;
|
||||
key_entry.next = -1;
|
||||
g_array_append_val (info->key_entries, key_entry);
|
||||
}
|
||||
|
||||
/* Initialize generic vk <-> char tables */
|
||||
|
||||
for (table_idx = 0; ; ++table_idx)
|
||||
{
|
||||
PVK_TO_WCHAR_TABLE wch_table = &wch_tables[table_idx];
|
||||
int entry_size;
|
||||
int n_levels;
|
||||
int entry_idx;
|
||||
|
||||
if (wch_table->pVkToWchars.ptr == NULL)
|
||||
break;
|
||||
|
||||
entry_size = wch_table->cbSize;
|
||||
n_levels = wch_table->nModifications;
|
||||
|
||||
for (entry_idx = 0; ; ++entry_idx)
|
||||
{
|
||||
PVK_TO_WCHARS entry;
|
||||
int level;
|
||||
|
||||
entry = (PVK_TO_WCHARS) ((PBYTE) wch_table->pVkToWchars.ptr
|
||||
+ entry_size * entry_idx);
|
||||
|
||||
if (entry->VirtualKey == 0)
|
||||
break;
|
||||
|
||||
/* Lookup table to find entry for a VK in O(1). */
|
||||
|
||||
/* Only add the first entry, as some layouts (Swiss German) contain
|
||||
* multiple successive entries for the same VK (SGCAPS). */
|
||||
if (info->vk_lookup_table[entry->VirtualKey].table < 0)
|
||||
{
|
||||
info->vk_lookup_table[entry->VirtualKey].table = table_idx;
|
||||
info->vk_lookup_table[entry->VirtualKey].index = entry_idx;
|
||||
}
|
||||
|
||||
/* Create reverse lookup entries to find a VK+modifier combinations
|
||||
* that results in a given character. */
|
||||
for (level = 0; level < n_levels; ++level)
|
||||
{
|
||||
GdkWin32KeymapKeyEntry key_entry = {0};
|
||||
WCHAR c = entry->wch[level];
|
||||
int inserted_idx;
|
||||
gintptr next_idx;
|
||||
|
||||
key_entry.vk = entry->VirtualKey;
|
||||
key_entry.mod_bits = info->level_to_modbits[level];
|
||||
|
||||
/* There can be multiple combinations that produce the same character.
|
||||
* We store all of them in a linked list.
|
||||
* Check if we already have an entry for the character, so we can chain
|
||||
* them together. */
|
||||
if (g_hash_table_lookup_extended (info->reverse_lookup_table,
|
||||
GINT_TO_POINTER (c),
|
||||
NULL, (gpointer*)&next_idx))
|
||||
{
|
||||
key_entry.next = next_idx;
|
||||
}
|
||||
else
|
||||
{
|
||||
key_entry.next = -1;
|
||||
}
|
||||
|
||||
/* We store the KeyEntry in an array. In the hash table we only store
|
||||
* the index. */
|
||||
|
||||
g_array_append_val (info->key_entries, key_entry);
|
||||
inserted_idx = info->key_entries->len - 1;
|
||||
|
||||
g_hash_table_insert (info->reverse_lookup_table,
|
||||
GINT_TO_POINTER (c),
|
||||
GINT_TO_POINTER (inserted_idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
load_layout_dll (const char *dll,
|
||||
GdkWin32KeymapLayoutInfo *info)
|
||||
{
|
||||
typedef KLPKBDTABLES (*KbdLayerDescriptor)(VOID);
|
||||
|
||||
HMODULE lib;
|
||||
KbdLayerDescriptor func;
|
||||
KLPKBDTABLES tables;
|
||||
|
||||
g_return_val_if_fail (dll != NULL, FALSE);
|
||||
|
||||
lib = LoadLibraryA (dll);
|
||||
if (lib == NULL)
|
||||
goto fail1;
|
||||
|
||||
func = (KbdLayerDescriptor) GetProcAddress (lib, "KbdLayerDescriptor");
|
||||
if (func == NULL)
|
||||
goto fail2;
|
||||
|
||||
tables = func();
|
||||
|
||||
info->lib = lib;
|
||||
info->tables = (PKBDTABLES) tables.ptr;
|
||||
|
||||
return TRUE;
|
||||
|
||||
fail2:
|
||||
FreeLibrary (lib);
|
||||
fail1:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#if GDK_WIN32_COMPILE_FOR_WOW64
|
||||
#define GDK_WIN32_KEYMAP_IMPL_NAME gdkwin32_keymap_impl_wow64
|
||||
#else
|
||||
#define GDK_WIN32_KEYMAP_IMPL_NAME gdkwin32_keymap_impl
|
||||
#endif
|
||||
|
||||
const GdkWin32KeymapImpl GDK_WIN32_KEYMAP_IMPL_NAME =
|
||||
{
|
||||
load_layout_dll,
|
||||
init_vk_lookup_table,
|
||||
keystate_to_modbits,
|
||||
modbits_to_level,
|
||||
vk_to_char_fuzzy
|
||||
};
|
||||
+1301
-721
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user