Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 127685ef22 |
+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
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -303,10 +303,8 @@
|
||||
<file>listview_applauncher.c</file>
|
||||
<file>listview_colors.c</file>
|
||||
<file>listview_clocks.c</file>
|
||||
<file>listview_emoji.c</file>
|
||||
<file>listview_filebrowser.c</file>
|
||||
<file>listview_minesweeper.c</file>
|
||||
<file>listview_objects.c</file>
|
||||
<file>listview_settings.c</file>
|
||||
<file>listview_ucd.c</file>
|
||||
<file>listview_weather.c</file>
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
/* Lists/Emoji
|
||||
* #Keywords: GtkListItemFactory, GtkGridView
|
||||
*
|
||||
* This demo uses the GtkGridView widget to show Emoji.
|
||||
*
|
||||
* It shows how to use sections in GtkGridView
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static char *
|
||||
get_section (GtkEmojiObject *object)
|
||||
{
|
||||
switch (gtk_emoji_object_get_group (object))
|
||||
{
|
||||
case GTK_EMOJI_GROUP_RECENT: return g_strdup ("Recent");
|
||||
case GTK_EMOJI_GROUP_SMILEYS: return g_strdup ("Smileys");
|
||||
case GTK_EMOJI_GROUP_BODY: return g_strdup ("People");
|
||||
case GTK_EMOJI_GROUP_COMPONENT: return g_strdup ("Components");
|
||||
case GTK_EMOJI_GROUP_NATURE: return g_strdup ("Nature");
|
||||
case GTK_EMOJI_GROUP_FOOD: return g_strdup ("Food");
|
||||
case GTK_EMOJI_GROUP_PLACES: return g_strdup ("Places");
|
||||
case GTK_EMOJI_GROUP_ACTIVITIES: return g_strdup ("Activities");
|
||||
case GTK_EMOJI_GROUP_OBJECTS: return g_strdup ("Objects");
|
||||
case GTK_EMOJI_GROUP_SYMBOLS: return g_strdup ("Symbols");
|
||||
case GTK_EMOJI_GROUP_FLAGS: return g_strdup ("Flags");
|
||||
default: return g_strdup ("Something else");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
setup_section_listitem_cb (GtkListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkWidget *label;
|
||||
|
||||
label = gtk_label_new ("");
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||
gtk_widget_add_css_class (label, "heading");
|
||||
gtk_widget_set_margin_top (label, 4);
|
||||
gtk_widget_set_margin_bottom (label, 4);
|
||||
gtk_list_item_set_child (list_item, label);
|
||||
}
|
||||
|
||||
static void
|
||||
bind_section_listitem_cb (GtkListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkWidget *label;
|
||||
GtkEmojiObject *item;
|
||||
char *text;
|
||||
|
||||
label = gtk_list_item_get_child (list_item);
|
||||
item = gtk_list_item_get_item (list_item);
|
||||
|
||||
text = get_section (item);
|
||||
gtk_label_set_label (GTK_LABEL (label), text);
|
||||
g_free (text);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_listitem_cb (GtkListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkWidget *label;
|
||||
|
||||
label = gtk_label_new ("");
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||
gtk_list_item_set_child (list_item, label);
|
||||
}
|
||||
|
||||
static void
|
||||
bind_listitem_cb (GtkListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkWidget *label;
|
||||
GtkEmojiObject *item;
|
||||
char buffer[64];
|
||||
PangoAttrList *attrs;
|
||||
|
||||
label = gtk_list_item_get_child (list_item);
|
||||
item = gtk_list_item_get_item (list_item);
|
||||
|
||||
gtk_emoji_object_get_text (item, buffer, sizeof (buffer), 0);
|
||||
gtk_label_set_label (GTK_LABEL (label), buffer);
|
||||
attrs = pango_attr_list_new ();
|
||||
pango_attr_list_insert (attrs, pango_attr_scale_new (PANGO_SCALE_X_LARGE));
|
||||
gtk_label_set_attributes (GTK_LABEL (label), attrs);
|
||||
pango_attr_list_unref (attrs);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
match_tokens (const char **term_tokens,
|
||||
const char **hit_tokens)
|
||||
{
|
||||
int i, j;
|
||||
gboolean matched;
|
||||
|
||||
matched = TRUE;
|
||||
|
||||
for (i = 0; term_tokens[i]; i++)
|
||||
{
|
||||
for (j = 0; hit_tokens[j]; j++)
|
||||
if (g_str_has_prefix (hit_tokens[j], term_tokens[i]))
|
||||
goto one_matched;
|
||||
|
||||
matched = FALSE;
|
||||
break;
|
||||
|
||||
one_matched:
|
||||
continue;
|
||||
}
|
||||
|
||||
return matched;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
filter_func (gpointer item,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkEmojiObject *emoji = item;
|
||||
GtkWidget *entry = user_data;
|
||||
const char *text;
|
||||
const char *name;
|
||||
const char **keywords;
|
||||
char **term_tokens;
|
||||
char **name_tokens;
|
||||
gboolean res;
|
||||
|
||||
text = gtk_editable_get_text (GTK_EDITABLE (entry));
|
||||
if (text[0] == 0)
|
||||
return TRUE;
|
||||
|
||||
name = gtk_emoji_object_get_name (emoji);
|
||||
keywords = gtk_emoji_object_get_keywords (emoji);
|
||||
|
||||
term_tokens = g_str_tokenize_and_fold (text, "en", NULL);
|
||||
name_tokens = g_str_tokenize_and_fold (name, "en", NULL);
|
||||
|
||||
res = match_tokens ((const char **)term_tokens, (const char **)name_tokens) ||
|
||||
match_tokens ((const char **)term_tokens, keywords);
|
||||
|
||||
g_strfreev (term_tokens);
|
||||
g_strfreev (name_tokens);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
search_changed (GtkEntry *entry,
|
||||
gpointer data)
|
||||
{
|
||||
GtkFilter *filter = data;
|
||||
|
||||
gtk_filter_changed (filter, GTK_FILTER_CHANGE_DIFFERENT);
|
||||
}
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
GtkWidget *
|
||||
do_listview_emoji (GtkWidget *do_widget)
|
||||
{
|
||||
if (window == NULL)
|
||||
{
|
||||
GtkWidget *list, *sw;
|
||||
GListModel *model;
|
||||
GtkListItemFactory *factory;
|
||||
GtkWidget *box, *entry;
|
||||
GtkFilter *filter;
|
||||
|
||||
/* Create a window and set a few defaults */
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 300, 400);
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
gtk_widget_get_display (do_widget));
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Emoji");
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
|
||||
|
||||
factory = gtk_signal_list_item_factory_new ();
|
||||
g_signal_connect (factory, "setup", G_CALLBACK (setup_listitem_cb), NULL);
|
||||
g_signal_connect (factory, "bind", G_CALLBACK (bind_listitem_cb), NULL);
|
||||
|
||||
entry = gtk_search_entry_new ();
|
||||
|
||||
model = G_LIST_MODEL (gtk_emoji_list_new ());
|
||||
filter = GTK_FILTER (gtk_custom_filter_new (filter_func, entry, NULL));
|
||||
model = G_LIST_MODEL (gtk_filter_list_model_new (model, filter));
|
||||
|
||||
g_signal_connect (entry, "search-changed", G_CALLBACK (search_changed), filter);
|
||||
|
||||
list = gtk_grid_view_new (GTK_SELECTION_MODEL (gtk_no_selection_new (model)), factory);
|
||||
gtk_grid_view_set_max_columns (GTK_GRID_VIEW (list), 20);
|
||||
|
||||
factory = gtk_signal_list_item_factory_new ();
|
||||
g_signal_connect (factory, "setup", G_CALLBACK (setup_section_listitem_cb), NULL);
|
||||
g_signal_connect (factory, "bind", G_CALLBACK (bind_section_listitem_cb), NULL);
|
||||
gtk_grid_view_set_section_factory (GTK_GRID_VIEW (list), factory);
|
||||
g_object_unref (factory);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_box_append (GTK_BOX (box), entry);
|
||||
sw = gtk_scrolled_window_new ();
|
||||
gtk_widget_set_hexpand (sw, TRUE);
|
||||
gtk_widget_set_vexpand (sw, TRUE);
|
||||
gtk_box_append (GTK_BOX (box), sw);
|
||||
gtk_window_set_child (GTK_WINDOW (window), box);
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), list);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -18,8 +18,6 @@ struct _FileBrowserView
|
||||
GObject parent_instance;
|
||||
|
||||
GtkListItemFactory *factory;
|
||||
GtkListItemFactory *section_factory;
|
||||
GtkSorter *section_sorter;
|
||||
char *icon_name;
|
||||
char *title;
|
||||
GtkOrientation orientation;
|
||||
@@ -29,10 +27,8 @@ enum {
|
||||
PROP_0,
|
||||
PROP_FACTORY,
|
||||
PROP_ICON_NAME,
|
||||
PROP_ORIENTATION,
|
||||
PROP_SECTION_FACTORY,
|
||||
PROP_SECTION_SORTER,
|
||||
PROP_TITLE,
|
||||
PROP_ORIENTATION,
|
||||
|
||||
N_PROPS
|
||||
};
|
||||
@@ -62,22 +58,14 @@ file_browser_view_get_property (GObject *object,
|
||||
g_value_set_string (value, self->icon_name);
|
||||
break;
|
||||
|
||||
case PROP_ORIENTATION:
|
||||
g_value_set_enum (value, self->orientation);
|
||||
break;
|
||||
|
||||
case PROP_SECTION_FACTORY:
|
||||
g_value_set_object (value, self->section_factory);
|
||||
break;
|
||||
|
||||
case PROP_SECTION_SORTER:
|
||||
g_value_set_object (value, self->section_sorter);
|
||||
break;
|
||||
|
||||
case PROP_TITLE:
|
||||
g_value_set_string (value, self->title);
|
||||
break;
|
||||
|
||||
case PROP_ORIENTATION:
|
||||
g_value_set_enum (value, self->orientation);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
@@ -103,23 +91,15 @@ file_browser_view_set_property (GObject *object,
|
||||
self->icon_name = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
case PROP_ORIENTATION:
|
||||
self->orientation = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
case PROP_SECTION_FACTORY:
|
||||
g_set_object (&self->section_factory, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_SECTION_SORTER:
|
||||
g_set_object (&self->section_sorter, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_TITLE:
|
||||
g_free (self->title);
|
||||
self->title = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
case PROP_ORIENTATION:
|
||||
self->orientation = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -159,6 +139,12 @@ file_browser_view_class_init (FileBrowserViewClass *klass)
|
||||
"icon to display for selecting this view",
|
||||
NULL,
|
||||
G_PARAM_READWRITE);
|
||||
properties[PROP_TITLE] =
|
||||
g_param_spec_string ("title",
|
||||
"title",
|
||||
"title to display for selecting this view",
|
||||
NULL,
|
||||
G_PARAM_READWRITE);
|
||||
properties[PROP_ORIENTATION] =
|
||||
g_param_spec_enum ("orientation",
|
||||
"orientation",
|
||||
@@ -166,24 +152,6 @@ file_browser_view_class_init (FileBrowserViewClass *klass)
|
||||
GTK_TYPE_ORIENTATION,
|
||||
GTK_ORIENTATION_VERTICAL,
|
||||
G_PARAM_READWRITE);
|
||||
properties[PROP_SECTION_FACTORY] =
|
||||
g_param_spec_object ("section-factory",
|
||||
"section factory",
|
||||
"factory to use for sections or NULL",
|
||||
GTK_TYPE_LIST_ITEM_FACTORY,
|
||||
G_PARAM_READWRITE);
|
||||
properties[PROP_SECTION_SORTER] =
|
||||
g_param_spec_object ("section-sorter",
|
||||
"section sorter",
|
||||
"sorter to split files into sections or NULL",
|
||||
GTK_TYPE_SORTER,
|
||||
G_PARAM_READWRITE);
|
||||
properties[PROP_TITLE] =
|
||||
g_param_spec_string ("title",
|
||||
"title",
|
||||
"title to display for selecting this view",
|
||||
NULL,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
@@ -91,78 +91,6 @@
|
||||
<property name="orientation">vertical</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="FileBrowserView">
|
||||
<property name="factory">
|
||||
<object class="GtkBuilderListItemFactory">
|
||||
<property name="bytes"><![CDATA[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="GtkBox">
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<binding name="gicon">
|
||||
<closure type="GIcon" function="filebrowser_get_icon">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</closure>
|
||||
</binding>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="halign">start</property>
|
||||
<property name="hexpand">true</property>
|
||||
<property name="width-chars">30</property>
|
||||
<property name="ellipsize">middle</property>
|
||||
<binding name="label">
|
||||
<closure type="gchararray" function="filebrowser_get_display_name">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</closure>
|
||||
</binding>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
]]></property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="section-factory">
|
||||
<object class="GtkBuilderListItemFactory">
|
||||
<property name="bytes"><![CDATA[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<property name="xalign">0</property>
|
||||
<binding name="label">
|
||||
<closure type="gchararray" function="filebrowser_get_content_type">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</closure>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
]]></property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="section-sorter">
|
||||
<object class="GtkStringSorter">
|
||||
<property name="expression">
|
||||
<closure type="gchararray" function="filebrowser_get_content_type" swapped="true" />
|
||||
</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="icon-name">view-continuous-symbolic</property>
|
||||
<property name="title" translatable="yes">Sections</property>
|
||||
<property name="orientation">vertical</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="FileBrowserView">
|
||||
<property name="icon-name">view-paged-symbolic</property>
|
||||
@@ -239,17 +167,8 @@
|
||||
</object>
|
||||
<object class="GtkSingleSelection" id="selection_model">
|
||||
<property name="model">
|
||||
<object class="GtkSortListModel">
|
||||
<binding name="section-sorter">
|
||||
<lookup name="section-sorter" type="FileBrowserView">
|
||||
<lookup name="selected-item">selected-view</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
<property name="model">
|
||||
<object class="GtkDirectoryList" id="dirlist">
|
||||
<property name="attributes">standard::name,standard::display-name,standard::icon,standard::size,standard::content-type</property>
|
||||
</object>
|
||||
</property>
|
||||
<object class="GtkDirectoryList" id="dirlist">
|
||||
<property name="attributes">standard::name,standard::display-name,standard::icon,standard::size,standard::content-type</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
@@ -319,11 +238,6 @@
|
||||
<lookup name="selected-item">selected-view</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
<binding name="section-factory">
|
||||
<lookup name="section-factory" type="FileBrowserView">
|
||||
<lookup name="selected-item">selected-view</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
<binding name="orientation">
|
||||
<lookup name="orientation" type="FileBrowserView">
|
||||
<lookup name="selected-item">selected-view</lookup>
|
||||
|
||||
@@ -1,220 +0,0 @@
|
||||
/* Lists/Objects in GTK
|
||||
* #Keywords: GtkListItemFactory, GtkSortListModel, GtkStringList
|
||||
*
|
||||
* This demo uses the GtkListView widget to show all the objects in GTK
|
||||
* grouped by their type.
|
||||
*
|
||||
* It shows how to use sections in GtkListView
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
/* This is the function that creates the GListModel that we need.
|
||||
*/
|
||||
static GListModel *
|
||||
create_object_list (void)
|
||||
{
|
||||
GtkStringList *strings;
|
||||
const GType *types;
|
||||
guint i, n;
|
||||
|
||||
/* We use a GtkStringList here, because it requires the smallest amount of
|
||||
* code, not because it's a great fit.
|
||||
*/
|
||||
strings = gtk_string_list_new (NULL);
|
||||
|
||||
/* This function is meant for testing, but we use it here to get some data
|
||||
* to operate on
|
||||
*/
|
||||
gtk_test_register_all_types ();
|
||||
types = gtk_test_list_all_types (&n);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
/* Add all the names of the object types in GTK */
|
||||
if (g_type_is_a (types[i], G_TYPE_OBJECT))
|
||||
gtk_string_list_append (strings, g_type_name (types[i]));
|
||||
}
|
||||
|
||||
return G_LIST_MODEL (strings);
|
||||
}
|
||||
|
||||
/* Make a function that returns a section name for all our types.
|
||||
* Do this by adding a few type checks and returning a made up
|
||||
* section name for it.
|
||||
*/
|
||||
static char *
|
||||
get_section (GtkStringObject *object)
|
||||
{
|
||||
GType type;
|
||||
|
||||
type = g_type_from_name (gtk_string_object_get_string (object));
|
||||
|
||||
if (g_type_is_a (type, GTK_TYPE_WIDGET))
|
||||
return g_strdup ("Widget");
|
||||
else if (g_type_is_a (type, GTK_TYPE_FILTER))
|
||||
return g_strdup ("Filter");
|
||||
else if (g_type_is_a (type, GTK_TYPE_SORTER))
|
||||
return g_strdup ("Sorter");
|
||||
else if (g_type_is_a (type, G_TYPE_LIST_MODEL))
|
||||
return g_strdup ("ListModel");
|
||||
else
|
||||
return g_strdup ("Zzz..."); /* boring stuff, cleverly sorted at the end */
|
||||
}
|
||||
|
||||
/* These functions set up the object names
|
||||
*/
|
||||
static void
|
||||
setup_section_listitem_cb (GtkListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkWidget *label;
|
||||
|
||||
label = gtk_label_new ("");
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||
gtk_widget_add_css_class (label, "heading");
|
||||
gtk_widget_set_margin_top (label, 4);
|
||||
gtk_widget_set_margin_bottom (label, 4);
|
||||
gtk_list_item_set_child (list_item, label);
|
||||
}
|
||||
|
||||
/* Here we need to prepare the listitem for displaying its item. We get the
|
||||
* listitem already set up from the previous function, so we can reuse the
|
||||
* GtkImage widget we set up above.
|
||||
* We get the item - which we know is a GAppInfo because it comes out of
|
||||
* the model we set up above, grab its icon and display it.
|
||||
*/
|
||||
static void
|
||||
bind_section_listitem_cb (GtkListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkWidget *label;
|
||||
GtkStringObject *item;
|
||||
char *text;
|
||||
|
||||
label = gtk_list_item_get_child (list_item);
|
||||
item = gtk_list_item_get_item (list_item);
|
||||
|
||||
text = get_section (item);
|
||||
gtk_label_set_label (GTK_LABEL (label), text);
|
||||
g_free (text);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_listitem_cb (GtkListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkWidget *label;
|
||||
|
||||
label = gtk_label_new ("");
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||
gtk_list_item_set_child (list_item, label);
|
||||
}
|
||||
|
||||
/* Here we need to prepare the listitem for displaying its item. We get the
|
||||
* listitem already set up from the previous function, so we can reuse the
|
||||
* GtkImage widget we set up above.
|
||||
* We get the item - which we know is a GAppInfo because it comes out of
|
||||
* the model we set up above, grab its icon and display it.
|
||||
*/
|
||||
static void
|
||||
bind_listitem_cb (GtkListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkWidget *label;
|
||||
GtkStringObject *item;
|
||||
|
||||
label = gtk_list_item_get_child (list_item);
|
||||
item = gtk_list_item_get_item (list_item);
|
||||
|
||||
gtk_label_set_label (GTK_LABEL (label), gtk_string_object_get_string (item));
|
||||
}
|
||||
|
||||
/* In more complex code, we would also need functions to unbind and teardown
|
||||
* the listitem, but this is simple code, so the default implementations are
|
||||
* enough. If we had connected signals, this step would have been necessary.
|
||||
*
|
||||
* The GtkSignalListItemFactory documentation contains more information about
|
||||
* this step.
|
||||
*/
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
GtkWidget *
|
||||
do_listview_objects (GtkWidget *do_widget)
|
||||
{
|
||||
if (window == NULL)
|
||||
{
|
||||
GtkWidget *list, *sw;
|
||||
GListModel *model;
|
||||
GtkListItemFactory *factory;
|
||||
GtkSorter *sorter;
|
||||
|
||||
/* Create a window and set a few defaults */
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 300, 400);
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
gtk_widget_get_display (do_widget));
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Objects in GTK");
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
|
||||
|
||||
/* The GtkListitemFactory is what is used to create GtkListItems
|
||||
* to display the data from the model. So it is absolutely necessary
|
||||
* to create one.
|
||||
* We will use a GtkSignalListItemFactory because it is the simplest
|
||||
* one to use. Different ones are available for different use cases.
|
||||
* The most powerful one is GtkBuilderListItemFactory which uses
|
||||
* GtkBuilder .ui files, so it requires little code.
|
||||
*/
|
||||
factory = gtk_signal_list_item_factory_new ();
|
||||
g_signal_connect (factory, "setup", G_CALLBACK (setup_listitem_cb), NULL);
|
||||
g_signal_connect (factory, "bind", G_CALLBACK (bind_listitem_cb), NULL);
|
||||
|
||||
/* And of course we need to set the data model. Here we call the function
|
||||
* we wrote above that gives us the list of applications. Then we set
|
||||
* it on the list widget.
|
||||
* The list will now take items from the model and use the factory
|
||||
* to create as many listitems as it needs to show itself to the user.
|
||||
*/
|
||||
model = create_object_list ();
|
||||
|
||||
/* Wrap the model in a sort model that sorts the objects alphabetically.
|
||||
*/
|
||||
sorter = GTK_SORTER (gtk_string_sorter_new (gtk_property_expression_new (GTK_TYPE_STRING_OBJECT, NULL, "string")));
|
||||
model = G_LIST_MODEL (gtk_sort_list_model_new (model, sorter));
|
||||
|
||||
/* Create a sorter for the sections and tell the sort model about it
|
||||
*/
|
||||
sorter = GTK_SORTER (gtk_string_sorter_new (gtk_cclosure_expression_new (G_TYPE_STRING, NULL, 0, NULL, G_CALLBACK (get_section), NULL, NULL)));
|
||||
gtk_string_sorter_set_ignore_case (GTK_STRING_SORTER (sorter), FALSE);
|
||||
gtk_sort_list_model_set_section_sorter (GTK_SORT_LIST_MODEL (model), sorter);
|
||||
g_object_unref (sorter);
|
||||
|
||||
/* Create the list widget here.
|
||||
*/
|
||||
list = gtk_list_view_new (GTK_SELECTION_MODEL (gtk_single_selection_new (model)), factory);
|
||||
|
||||
/* Set a factory for sections, otherwise the listview won't use sections.
|
||||
*/
|
||||
factory = gtk_signal_list_item_factory_new ();
|
||||
g_signal_connect (factory, "setup", G_CALLBACK (setup_section_listitem_cb), NULL);
|
||||
g_signal_connect (factory, "bind", G_CALLBACK (bind_section_listitem_cb), NULL);
|
||||
gtk_list_view_set_section_factory (GTK_LIST_VIEW (list), factory);
|
||||
g_object_unref (factory);
|
||||
|
||||
/* List widgets should always be contained in a GtkScrolledWindow,
|
||||
* because otherwise they might get too large or they might not
|
||||
* be scrollable.
|
||||
*/
|
||||
sw = gtk_scrolled_window_new ();
|
||||
gtk_window_set_child (GTK_WINDOW (window), sw);
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), list);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -268,31 +268,13 @@ bind_widget (GtkSignalListItemFactory *factory,
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
child = gtk_widget_get_next_sibling (child);
|
||||
s = g_strdup_printf ("%d°", info->temperature);
|
||||
gtk_label_set_text (GTK_LABEL (child), s);
|
||||
g_free (s);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
transform_weather_to_date_string (GBinding *binding,
|
||||
const GValue *from_value,
|
||||
GValue *to_value,
|
||||
gpointer unused)
|
||||
{
|
||||
GtkWeatherInfo *info;
|
||||
GDateTime *timestamp;
|
||||
|
||||
info = g_value_get_object (from_value);
|
||||
if (info == NULL)
|
||||
return TRUE;
|
||||
|
||||
timestamp = g_date_time_new_from_unix_utc (info->timestamp);
|
||||
g_value_take_string (to_value, g_date_time_format (timestamp, "%x"));
|
||||
g_date_time_unref (timestamp);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
GtkWidget *
|
||||
@@ -318,7 +300,7 @@ do_listview_weather (GtkWidget *do_widget)
|
||||
{
|
||||
if (window == NULL)
|
||||
{
|
||||
GtkWidget *listview, *sw, *box, *label;
|
||||
GtkWidget *listview, *sw;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
|
||||
@@ -328,26 +310,10 @@ do_listview_weather (GtkWidget *do_widget)
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Weather");
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
|
||||
gtk_window_set_child (GTK_WINDOW (window), box);
|
||||
|
||||
label = gtk_label_new ("");
|
||||
gtk_widget_set_halign (label, GTK_ALIGN_END);
|
||||
gtk_box_append (GTK_BOX (box), label);
|
||||
|
||||
sw = gtk_scrolled_window_new ();
|
||||
gtk_widget_set_vexpand (sw, TRUE);
|
||||
gtk_box_append (GTK_BOX (box), sw);
|
||||
gtk_window_set_child (GTK_WINDOW (window), sw);
|
||||
listview = create_weather_view ();
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), listview);
|
||||
|
||||
g_object_bind_property_full (listview, "focus-item",
|
||||
label, "label",
|
||||
G_BINDING_SYNC_CREATE,
|
||||
transform_weather_to_date_string,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
|
||||
+10
-12
@@ -18,9 +18,8 @@ demos = files([
|
||||
'css_shadows.c',
|
||||
'cursors.c',
|
||||
'dialog.c',
|
||||
'dnd.c',
|
||||
'drawingarea.c',
|
||||
'dropdown.c',
|
||||
'dnd.c',
|
||||
'editable_cells.c',
|
||||
'entry_completion.c',
|
||||
'entry_undo.c',
|
||||
@@ -29,7 +28,6 @@ demos = files([
|
||||
'filtermodel.c',
|
||||
'fishbowl.c',
|
||||
'fixed.c',
|
||||
'flowbox.c',
|
||||
'fontrendering.c',
|
||||
'frames.c',
|
||||
'gears.c',
|
||||
@@ -48,20 +46,20 @@ demos = files([
|
||||
'links.c',
|
||||
'listbox.c',
|
||||
'listbox_controls.c',
|
||||
'menu.c',
|
||||
'flowbox.c',
|
||||
'list_store.c',
|
||||
'listview_applauncher.c',
|
||||
'listview_clocks.c',
|
||||
'listview_colors.c',
|
||||
'listview_emoji.c',
|
||||
'listview_filebrowser.c',
|
||||
'listview_minesweeper.c',
|
||||
'listview_objects.c',
|
||||
'dropdown.c',
|
||||
'listview_settings.c',
|
||||
'listview_ucd.c',
|
||||
'listview_weather.c',
|
||||
'listview_words.c',
|
||||
'markup.c',
|
||||
'menu.c',
|
||||
'overlay.c',
|
||||
'overlay_decorative.c',
|
||||
'paint.c',
|
||||
@@ -100,7 +98,6 @@ demos = files([
|
||||
'transparent.c',
|
||||
'tree_store.c',
|
||||
'video_player.c',
|
||||
'font_features.c',
|
||||
])
|
||||
|
||||
gtkdemo_deps = [ libgtk_dep, ]
|
||||
@@ -131,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
|
||||
@@ -172,7 +174,6 @@ if build_machine.system() == 'linux' and objcopy.found() and objcopy_supports_ad
|
||||
depfile : 'gtkdemo.gresource.d',
|
||||
command : [glib_compile_resources,
|
||||
'--generate',
|
||||
'--internal',
|
||||
'--target=@OUTPUT@',
|
||||
'--dependency-file=@DEPFILE@',
|
||||
'--sourcedir=' + meson.current_source_dir(),
|
||||
@@ -186,7 +187,6 @@ if build_machine.system() == 'linux' and objcopy.found() and objcopy_supports_ad
|
||||
depfile : 'gtkdemo_resources.c.d',
|
||||
command : [glib_compile_resources,
|
||||
'--generate-source',
|
||||
'--internal',
|
||||
'--target=@OUTPUT@',
|
||||
'--dependency-file=@DEPFILE@',
|
||||
'--sourcedir=' + meson.current_source_dir(),
|
||||
@@ -200,7 +200,6 @@ if build_machine.system() == 'linux' and objcopy.found() and objcopy_supports_ad
|
||||
input : gtkdemo_gresource,
|
||||
output : 'gtkdemo_resources.o',
|
||||
command : [ld,
|
||||
'-z', 'noexecstack',
|
||||
'-r',
|
||||
'-b','binary',
|
||||
'@INPUT@',
|
||||
@@ -211,7 +210,6 @@ if build_machine.system() == 'linux' and objcopy.found() and objcopy_supports_ad
|
||||
input : gtkdemo_resources_binary,
|
||||
output : 'gtkdemo_resources2.o',
|
||||
command : [objcopy,
|
||||
'--strip-all',
|
||||
'--add-symbol','_g_binary_gtkdemo_resource_data=.data:0',
|
||||
'@INPUT@',
|
||||
'@OUTPUT@'])
|
||||
|
||||
@@ -18,7 +18,6 @@ if build_machine.system() == 'linux' and objcopy.found() and objcopy_supports_ad
|
||||
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 build_machine.system() == 'linux' and objcopy.found() and objcopy_supports_ad
|
||||
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 build_machine.system() == 'linux' and objcopy.found() and objcopy_supports_ad
|
||||
input : widgetfactory_gresource,
|
||||
output : 'widgetfactory_resources.o',
|
||||
command : [ld,
|
||||
'-z', 'noexecstack',
|
||||
'-r',
|
||||
'-b','binary',
|
||||
'@INPUT@',
|
||||
@@ -57,7 +54,6 @@ if build_machine.system() == 'linux' and objcopy.found() and objcopy_supports_ad
|
||||
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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -286,7 +286,7 @@ requires that GTK is compiled with support for that backend.
|
||||
The following backends can be selected, provided they are
|
||||
included in the GDK libraries you are using:
|
||||
|
||||
`macos`
|
||||
`quartz`
|
||||
: Selects the native Quartz backend
|
||||
|
||||
`win32`
|
||||
@@ -336,6 +336,9 @@ using and the GDK backend supports them:
|
||||
`gl`
|
||||
: Selects the "gl" OpenGL renderer
|
||||
|
||||
`ngl`
|
||||
: Selects the "ngl" OpenGL renderer
|
||||
|
||||
`vulkan`
|
||||
: Selects the Vulkan renderer
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+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
|
||||
|
||||
@@ -1727,8 +1727,6 @@ gdk_display_init_egl (GdkDisplay *self,
|
||||
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,
|
||||
|
||||
@@ -110,7 +110,6 @@ struct _GdkDisplay
|
||||
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
-20
@@ -185,7 +185,8 @@ gdk_gl_context_dispose (GObject *gobject)
|
||||
|
||||
if (priv->egl_context != NULL)
|
||||
{
|
||||
GdkDisplay *display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
|
||||
GdkSurface *surface = gdk_gl_context_get_surface (context);
|
||||
GdkDisplay *display = gdk_surface_get_display (surface);
|
||||
EGLDisplay *egl_display = gdk_display_get_egl_display (display);
|
||||
|
||||
if (eglGetCurrentContext () == priv->egl_context)
|
||||
@@ -278,11 +279,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) ||
|
||||
@@ -648,12 +645,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)
|
||||
{
|
||||
@@ -665,7 +656,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;
|
||||
@@ -1059,29 +1049,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 {
|
||||
|
||||
+5
-15
@@ -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))
|
||||
@@ -392,8 +383,7 @@ gdk_gl_texture_determine_format (GdkGLTexture *self)
|
||||
* which will happen when the GdkTexture object is finalized, or due to
|
||||
* an explicit call of [method@Gdk.GLTexture.release].
|
||||
*
|
||||
* Return value: (transfer full) (type GdkGLTexture): A newly-created
|
||||
* `GdkTexture`
|
||||
* Return value: (transfer full): A newly-created `GdkTexture`
|
||||
*/
|
||||
GdkTexture *
|
||||
gdk_gl_texture_new (GdkGLContext *context,
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -25,10 +25,6 @@
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
#ifdef __ARM_NEON
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
|
||||
typedef struct _GdkMemoryFormatDescription GdkMemoryFormatDescription;
|
||||
|
||||
#define TYPED_FUNCS(name, T, R, G, B, A, bpp, scale) \
|
||||
@@ -170,75 +166,6 @@ r32g32b32a32_float_from_float (guchar *dest,
|
||||
memcpy (dest, src, sizeof (float) * n * 4);
|
||||
}
|
||||
|
||||
// This one conversion is quite important, it converts from RGBA with straight
|
||||
// alpha (as found in PNG for instance) to BGRA with premultiplied alpha (the
|
||||
// sole cairo format available).
|
||||
static void
|
||||
r8g8b8a8_to_b8g8r8a8_premultiplied (guchar *dest,
|
||||
const guchar *src,
|
||||
gsize n)
|
||||
{
|
||||
#ifdef __ARM_NEON
|
||||
uint16x8_t one = vdupq_n_u16 (1);
|
||||
uint16x8_t half = vdupq_n_u16 (127);
|
||||
|
||||
for (gsize i = n / 8; i > 0; i--)
|
||||
{
|
||||
// Work on “just” 8 pixels at once, since we need the full 16-bytes of
|
||||
// the q registers for the multiplication.
|
||||
uint8x8x4_t rgba = vld4_u8 (src);
|
||||
uint8x8_t r8 = rgba.val[0];
|
||||
uint8x8_t g8 = rgba.val[1];
|
||||
uint8x8_t b8 = rgba.val[2];
|
||||
uint8x8_t a8 = rgba.val[3];
|
||||
|
||||
// This is the same algorithm as premultiply(), but on packed 16-bit
|
||||
// instead of float.
|
||||
uint16x8_t r16 = vmull_u8 (r8, a8);
|
||||
uint16x8_t g16 = vmull_u8 (g8, a8);
|
||||
uint16x8_t b16 = vmull_u8 (b8, a8);
|
||||
|
||||
r16 = vaddq_u16 (r16, half);
|
||||
g16 = vaddq_u16 (g16, half);
|
||||
b16 = vaddq_u16 (b16, half);
|
||||
|
||||
r16 = vsraq_n_u16 (r16, r16, 8);
|
||||
g16 = vsraq_n_u16 (g16, g16, 8);
|
||||
b16 = vsraq_n_u16 (b16, b16, 8);
|
||||
|
||||
r16 = vaddq_u16 (r16, one);
|
||||
g16 = vaddq_u16 (g16, one);
|
||||
b16 = vaddq_u16 (b16, one);
|
||||
|
||||
// Just like the other one, here we use BGRA instead of RGBA!
|
||||
rgba.val[0] = vshrn_n_u16 (b16, 8);
|
||||
rgba.val[1] = vshrn_n_u16 (g16, 8);
|
||||
rgba.val[2] = vshrn_n_u16 (r16, 8);
|
||||
|
||||
vst4_u8 (dest, rgba);
|
||||
src += 32;
|
||||
dest += 32;
|
||||
}
|
||||
|
||||
// We want the fallthrough here for the last (up to) seven bytes of the row.
|
||||
n = n % 8;
|
||||
#endif // __ARM_NEON
|
||||
|
||||
for (; n > 0; n--)
|
||||
{
|
||||
guchar a = src[3];
|
||||
guint16 r = (guint16)src[0] * a + 127;
|
||||
guint16 g = (guint16)src[1] * a + 127;
|
||||
guint16 b = (guint16)src[2] * a + 127;
|
||||
dest[0] = (b + (b >> 8) + 1) >> 8;
|
||||
dest[1] = (g + (g >> 8) + 1) >> 8;
|
||||
dest[2] = (r + (r >> 8) + 1) >> 8;
|
||||
dest[3] = a;
|
||||
dest += 4;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
struct _GdkMemoryFormatDescription
|
||||
{
|
||||
GdkMemoryAlpha alpha;
|
||||
@@ -552,17 +479,6 @@ gdk_memory_convert (guchar *dest_data,
|
||||
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_B8G8R8A8_PREMULTIPLIED)
|
||||
{
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
r8g8b8a8_to_b8g8r8a8_premultiplied (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++)
|
||||
|
||||
@@ -133,10 +133,10 @@ gdk_memory_sanitize (GBytes *bytes,
|
||||
*
|
||||
* Creates a new texture for a blob of image data.
|
||||
*
|
||||
* The `GBytes` must contain @stride × @height pixels
|
||||
* The `GBytes` must contain @stride x @height pixels
|
||||
* in the given format.
|
||||
*
|
||||
* Returns: (type GdkMemoryTexture): A newly-created `GdkTexture`
|
||||
* Returns: A newly-created `GdkTexture`
|
||||
*/
|
||||
GdkTexture *
|
||||
gdk_memory_texture_new (int width,
|
||||
|
||||
+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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+9
-9
@@ -25,14 +25,14 @@
|
||||
* multiple frames, and will be used for a long time.
|
||||
*
|
||||
* There are various ways to create `GdkTexture` objects from a
|
||||
* [class@GdkPixbuf.Pixbuf], or a Cairo surface, or other pixel data.
|
||||
* `GdkPixbuf`, or a Cairo surface, or other pixel data.
|
||||
*
|
||||
* The ownership of the pixel data is transferred to the `GdkTexture`
|
||||
* instance; you can only make a copy of it, via [method@Gdk.Texture.download].
|
||||
*
|
||||
* `GdkTexture` is an immutable object: That means you cannot change
|
||||
* anything about it other than increasing the reference count via
|
||||
* [method@GObject.Object.ref], and consequently, it is a thread-safe object.
|
||||
* g_object_ref().
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
@@ -346,7 +346,7 @@ gdk_texture_init (GdkTexture *self)
|
||||
*
|
||||
* Creates a new texture object representing the surface.
|
||||
*
|
||||
* @surface must be an image surface with format `CAIRO_FORMAT_ARGB32`.
|
||||
* @surface must be an image surface with format CAIRO_FORMAT_ARGB32.
|
||||
*
|
||||
* Returns: a new `GdkTexture`
|
||||
*/
|
||||
@@ -384,7 +384,7 @@ gdk_texture_new_for_surface (cairo_surface_t *surface)
|
||||
* Creates a new texture object representing the `GdkPixbuf`.
|
||||
*
|
||||
* This function is threadsafe, so that you can e.g. use GTask
|
||||
* and [method@Gio.Task.run_in_thread] to avoid blocking the main thread
|
||||
* and g_task_run_in_thread() to avoid blocking the main thread
|
||||
* while loading a big image.
|
||||
*
|
||||
* Returns: a new `GdkTexture`
|
||||
@@ -430,7 +430,7 @@ gdk_texture_new_for_pixbuf (GdkPixbuf *pixbuf)
|
||||
* [ctor@Gdk.Texture.new_from_file] to load it.
|
||||
*
|
||||
* This function is threadsafe, so that you can e.g. use GTask
|
||||
* and [method@Gio.Task.run_in_thread] to avoid blocking the main thread
|
||||
* and g_task_run_in_thread() to avoid blocking the main thread
|
||||
* while loading a big image.
|
||||
*
|
||||
* Return value: A newly-created `GdkTexture`
|
||||
@@ -472,7 +472,7 @@ gdk_texture_new_from_resource (const char *resource_path)
|
||||
* If %NULL is returned, then @error will be set.
|
||||
*
|
||||
* This function is threadsafe, so that you can e.g. use GTask
|
||||
* and [method@Gio.Task.run_in_thread] to avoid blocking the main thread
|
||||
* and g_task_run_in_thread() to avoid blocking the main thread
|
||||
* while loading a big image.
|
||||
*
|
||||
* Return value: A newly-created `GdkTexture`
|
||||
@@ -565,7 +565,7 @@ gdk_texture_new_from_bytes_pixbuf (GBytes *bytes,
|
||||
* If %NULL is returned, then @error will be set.
|
||||
*
|
||||
* This function is threadsafe, so that you can e.g. use GTask
|
||||
* and [method@Gio.Task.run_in_thread] to avoid blocking the main thread
|
||||
* and g_task_run_in_thread() to avoid blocking the main thread
|
||||
* while loading a big image.
|
||||
*
|
||||
* Return value: A newly-created `GdkTexture`
|
||||
@@ -611,7 +611,7 @@ gdk_texture_new_from_bytes (GBytes *bytes,
|
||||
* If %NULL is returned, then @error will be set.
|
||||
*
|
||||
* This function is threadsafe, so that you can e.g. use GTask
|
||||
* and [method@Gio.Task.run_in_thread] to avoid blocking the main thread
|
||||
* and g_task_run_in_thread() to avoid blocking the main thread
|
||||
* while loading a big image.
|
||||
*
|
||||
* Return value: A newly-created `GdkTexture`
|
||||
@@ -796,7 +796,7 @@ gdk_texture_get_render_data (GdkTexture *self,
|
||||
*
|
||||
* This is a utility function intended for debugging and testing.
|
||||
* If you want more control over formats, proper error handling or
|
||||
* want to store to a [iface@Gio.File] or other location, you might want to
|
||||
* want to store to a `GFile` or other location, you might want to
|
||||
* use [method@Gdk.Texture.save_to_png_bytes] or look into the
|
||||
* gdk-pixbuf library.
|
||||
*
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -222,7 +222,11 @@ gdk_load_png (GBytes *bytes,
|
||||
case PNG_COLOR_TYPE_RGB_ALPHA:
|
||||
if (depth == 8)
|
||||
{
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
format = GDK_MEMORY_R8G8B8A8;
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
format = GDK_MEMORY_A8B8G8R8;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -232,7 +236,11 @@ gdk_load_png (GBytes *bytes,
|
||||
case PNG_COLOR_TYPE_RGB:
|
||||
if (depth == 8)
|
||||
{
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
format = GDK_MEMORY_R8G8B8;
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
format = GDK_MEMORY_B8G8R8;
|
||||
#endif
|
||||
}
|
||||
else if (depth == 16)
|
||||
{
|
||||
@@ -317,14 +325,22 @@ gdk_save_png (GdkTexture *texture)
|
||||
case GDK_MEMORY_A8R8G8B8:
|
||||
case GDK_MEMORY_R8G8B8A8:
|
||||
case GDK_MEMORY_A8B8G8R8:
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
format = GDK_MEMORY_R8G8B8A8;
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
format = GDK_MEMORY_A8B8G8R8;
|
||||
#endif
|
||||
png_format = PNG_COLOR_TYPE_RGB_ALPHA;
|
||||
depth = 8;
|
||||
break;
|
||||
|
||||
case GDK_MEMORY_R8G8B8:
|
||||
case GDK_MEMORY_B8G8R8:
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
format = GDK_MEMORY_R8G8B8;
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
format = GDK_MEMORY_B8G8R8;
|
||||
#endif
|
||||
png_format = PNG_COLOR_TYPE_RGB;
|
||||
depth = 8;
|
||||
break;
|
||||
|
||||
@@ -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,86 +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"
|
||||
|
||||
@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)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
|
||||
+117
-90
@@ -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,7 +303,7 @@ typedef NSString *CALayerContentsGravity;
|
||||
|
||||
-(BOOL)canBecomeKeyWindow
|
||||
{
|
||||
return GDK_IS_TOPLEVEL (gdk_surface) || GDK_IS_POPUP (gdk_surface);
|
||||
return GDK_IS_TOPLEVEL (gdk_surface);
|
||||
}
|
||||
|
||||
-(void)showAndMakeKey:(BOOL)makeKey
|
||||
@@ -361,23 +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 ([self gdkSurface]);
|
||||
}
|
||||
|
||||
/* 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.
|
||||
@@ -389,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;
|
||||
@@ -408,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,
|
||||
@@ -506,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;
|
||||
|
||||
@@ -515,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]);
|
||||
}
|
||||
@@ -668,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)
|
||||
{
|
||||
@@ -723,6 +760,7 @@ typedef NSString *CALayerContentsGravity;
|
||||
if (state & GDK_TOPLEVEL_STATE_MAXIMIZED)
|
||||
{
|
||||
lastMaximizedFrame = newFrame;
|
||||
[self windowDidUnmaximize];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -737,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
|
||||
@@ -750,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
|
||||
{
|
||||
}
|
||||
|
||||
@@ -813,9 +845,4 @@ typedef NSString *CALayerContentsGravity;
|
||||
return NO;
|
||||
}
|
||||
|
||||
-(void)swapBuffer:(GdkMacosBuffer *)buffer withDamage:(const cairo_region_t *)damage
|
||||
{
|
||||
[(GdkMacosView *)[self contentView] swapBuffer:buffer withDamage:damage];
|
||||
}
|
||||
|
||||
@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,6 +66,5 @@
|
||||
-(BOOL)trackManualMove;
|
||||
-(BOOL)trackManualResize;
|
||||
-(void)setDecorated:(BOOL)decorated;
|
||||
-(void)swapBuffer:(GdkMacosBuffer *)buffer withDamage:(const cairo_region_t *)damage;
|
||||
|
||||
@end
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include "gdkdisplaylinksource.h"
|
||||
|
||||
#include "gdkmacoseventsource-private.h"
|
||||
#include "gdk-private.h"
|
||||
|
||||
static gint64 host_to_frame_clock_time (gint64 val);
|
||||
|
||||
|
||||
@@ -1,58 +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);
|
||||
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,271 +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);
|
||||
}
|
||||
|
||||
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_reference (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,120 +43,41 @@ struct _GdkMacosCairoContextClass
|
||||
|
||||
G_DEFINE_TYPE (GdkMacosCairoContext, _gdk_macos_cairo_context, GDK_TYPE_CAIRO_CONTEXT)
|
||||
|
||||
static const cairo_user_data_key_t buffer_key;
|
||||
|
||||
static void
|
||||
unlock_buffer (gpointer data)
|
||||
static cairo_surface_t *
|
||||
create_cairo_surface_for_surface (GdkSurface *surface)
|
||||
{
|
||||
GdkMacosBuffer *buffer = data;
|
||||
cairo_surface_t *cairo_surface;
|
||||
int scale;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
g_assert (GDK_IS_MACOS_BUFFER (buffer));
|
||||
g_assert (GDK_IS_MACOS_SURFACE (surface));
|
||||
|
||||
_gdk_macos_buffer_unlock (buffer);
|
||||
g_clear_object (&buffer);
|
||||
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);
|
||||
|
||||
/* Lock the buffer so we can modify it safely */
|
||||
_gdk_macos_buffer_lock (buffer);
|
||||
cairo_surface_set_user_data (image_surface,
|
||||
&buffer_key,
|
||||
g_object_ref (buffer),
|
||||
unlock_buffer);
|
||||
|
||||
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;
|
||||
return cairo_create (self->window_surface);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -164,45 +86,59 @@ _gdk_macos_cairo_context_begin_frame (GdkDrawContext *draw_context,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
GdkMacosCairoContext *self = (GdkMacosCairoContext *)draw_context;
|
||||
GdkMacosBuffer *buffer;
|
||||
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);
|
||||
buffer = _gdk_macos_surface_get_buffer (GDK_MACOS_SURFACE (surface));
|
||||
nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface));
|
||||
|
||||
_gdk_macos_buffer_set_damage (buffer, region);
|
||||
_gdk_macos_buffer_set_flipped (buffer, FALSE);
|
||||
if (self->window_surface == NULL)
|
||||
{
|
||||
self->window_surface = create_cairo_surface_for_surface (surface);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (![nswindow isOpaque])
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_gdk_macos_cairo_context_end_frame (GdkDrawContext *draw_context,
|
||||
cairo_region_t *painted)
|
||||
{
|
||||
GdkMacosBuffer *buffer;
|
||||
GdkMacosCairoContext *self = (GdkMacosCairoContext *)draw_context;
|
||||
GdkSurface *surface;
|
||||
NSView *nsview;
|
||||
|
||||
g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (draw_context));
|
||||
g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (self));
|
||||
g_assert (self->window_surface != NULL);
|
||||
|
||||
surface = gdk_draw_context_get_surface (draw_context);
|
||||
buffer = _gdk_macos_surface_get_buffer (GDK_MACOS_SURFACE (surface));
|
||||
nsview = _gdk_macos_surface_get_view (GDK_MACOS_SURFACE (surface));
|
||||
|
||||
_gdk_macos_surface_swap_buffers (GDK_MACOS_SURFACE (surface), painted);
|
||||
_gdk_macos_buffer_set_damage (buffer, NULL);
|
||||
|
||||
[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
|
||||
|
||||
@@ -174,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
|
||||
|
||||
|
||||
@@ -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,15 +616,6 @@ 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 NULL;
|
||||
|
||||
seat = gdk_display_get_default_seat (GDK_DISPLAY (self));
|
||||
pointer = gdk_seat_get_pointer (seat);
|
||||
state = _gdk_macos_display_get_current_mouse_modifiers (self) |
|
||||
@@ -695,29 +681,17 @@ fill_scroll_event (GdkMacosDisplay *self,
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = gdk_scroll_event_new_discrete (GDK_SURFACE (surface),
|
||||
pointer,
|
||||
NULL,
|
||||
get_time_from_ns_event (nsevent),
|
||||
state,
|
||||
direction,
|
||||
FALSE);
|
||||
}
|
||||
}
|
||||
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);
|
||||
@@ -880,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
|
||||
@@ -932,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);
|
||||
@@ -1040,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])
|
||||
@@ -1064,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;
|
||||
|
||||
@@ -1,178 +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.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;
|
||||
GdkRectangle workarea;
|
||||
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));
|
||||
|
||||
/* If x/y is set, we should place relative to parent */
|
||||
if (GDK_SURFACE (surface)->x != 0 || GDK_SURFACE (surface)->y != 0)
|
||||
{
|
||||
*x = parent->root_x + GDK_SURFACE (surface)->x;
|
||||
*y = parent->root_y + GDK_SURFACE (surface)->y;
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
surface_rect.x = surface->root_x + surface->shadow_left;
|
||||
surface_rect.y = surface->root_y + surface->shadow_top;
|
||||
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;
|
||||
|
||||
parent_rect.x = parent->root_x + surface->shadow_left;
|
||||
parent_rect.y = parent->root_y + surface->shadow_top;
|
||||
parent_rect.width = GDK_SURFACE (parent)->width - surface->shadow_left - surface->shadow_right;
|
||||
parent_rect.height = GDK_SURFACE (parent)->height - surface->shadow_top - surface->shadow_bottom;
|
||||
|
||||
/* Try to place centered atop parent */
|
||||
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);
|
||||
|
||||
/* Now make sure that we don't overlap the top-bar */
|
||||
monitor = _gdk_macos_surface_get_best_monitor (parent);
|
||||
gdk_macos_monitor_get_workarea (monitor, &workarea);
|
||||
|
||||
if (surface_rect.x < workarea.x)
|
||||
surface_rect.x = workarea.x;
|
||||
|
||||
if (surface_rect.y < workarea.y)
|
||||
surface_rect.y = workarea.y;
|
||||
|
||||
*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);
|
||||
|
||||
if (surface_rect.x < workarea.x)
|
||||
surface_rect.x = workarea.x;
|
||||
|
||||
if (surface_rect.y < workarea.y)
|
||||
surface_rect.y = workarea.y;
|
||||
|
||||
*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);
|
||||
}
|
||||
+12
-71
@@ -173,7 +173,8 @@ gdk_macos_display_monitors_changed_cb (CFNotificationCenterRef center,
|
||||
_gdk_macos_display_reload_monitors (self);
|
||||
|
||||
/* Now we need to update all our surface positions since they
|
||||
* probably just changed origins.
|
||||
* 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;
|
||||
@@ -183,7 +184,8 @@ gdk_macos_display_monitors_changed_cb (CFNotificationCenterRef center,
|
||||
|
||||
g_assert (GDK_IS_MACOS_SURFACE (surface));
|
||||
|
||||
_gdk_macos_surface_monitor_changed (surface);
|
||||
if (GDK_IS_TOPLEVEL (surface))
|
||||
_gdk_macos_surface_update_position (surface);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,14 +301,10 @@ gdk_macos_display_frame_cb (gpointer data)
|
||||
|
||||
iter = iter->next;
|
||||
|
||||
_gdk_macos_surface_publish_timings (surface,
|
||||
source->presentation_time,
|
||||
source->refresh_interval);
|
||||
|
||||
_gdk_macos_display_remove_frame_callback (self, surface);
|
||||
|
||||
if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (surface)))
|
||||
gdk_surface_thaw_updates (GDK_SURFACE (surface));
|
||||
_gdk_macos_surface_thaw (surface,
|
||||
source->presentation_time,
|
||||
source->refresh_interval);
|
||||
}
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
@@ -478,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
|
||||
@@ -529,21 +512,6 @@ _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);
|
||||
}
|
||||
|
||||
@@ -758,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
|
||||
@@ -843,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);
|
||||
@@ -853,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 *
|
||||
@@ -996,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);
|
||||
}
|
||||
}
|
||||
@@ -1042,11 +987,7 @@ _gdk_macos_display_add_frame_callback (GdkMacosDisplay *self,
|
||||
|
||||
if (!queue_contains (&self->awaiting_frames, &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.
|
||||
*/
|
||||
g_queue_push_head_link (&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);
|
||||
|
||||
@@ -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
|
||||
@@ -38,17 +38,17 @@ struct _GdkMacosGLContext
|
||||
{
|
||||
GdkGLContext parent_instance;
|
||||
|
||||
cairo_region_t *damage;
|
||||
|
||||
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
|
||||
@@ -56,6 +56,7 @@ struct _GdkMacosGLContextClass
|
||||
GdkGLContextClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_MACOS_GL_CONTEXT_PRIVATE_H__ */
|
||||
|
||||
+261
-384
@@ -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,130 +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);
|
||||
|
||||
/* Create our render target and bind it */
|
||||
gdk_gl_context_make_current (GDK_GL_CONTEXT (self));
|
||||
gdk_macos_gl_context_allocate (self);
|
||||
|
||||
GDK_DRAW_CONTEXT_CLASS (gdk_macos_gl_context_parent_class)->begin_frame (context, prefers_high_depth, region);
|
||||
|
||||
g_clear_pointer (&self->damage, cairo_region_destroy);
|
||||
self->damage = g_steal_pointer (©);
|
||||
self->damage = cairo_region_copy (painted);
|
||||
|
||||
gdk_gl_context_make_current (GDK_GL_CONTEXT (self));
|
||||
CHECK_GL (NULL, glBindFramebuffer (GL_FRAMEBUFFER, self->fbo));
|
||||
/* 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);
|
||||
|
||||
if (self->needs_resize)
|
||||
{
|
||||
CGLContextObj cgl_context = [self->gl_context CGLContextObj];
|
||||
GLint opaque;
|
||||
|
||||
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
|
||||
@@ -488,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
|
||||
@@ -531,23 +401,31 @@ gdk_macos_gl_context_surface_resized (GdkDrawContext *draw_context)
|
||||
|
||||
g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
|
||||
|
||||
g_clear_pointer (&self->damage, cairo_region_destroy);
|
||||
self->needs_resize = TRUE;
|
||||
|
||||
if (self->cgl_context != NULL)
|
||||
CGLUpdateContext (self->cgl_context);
|
||||
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;
|
||||
@@ -558,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;
|
||||
@@ -588,35 +462,40 @@ gdk_macos_gl_context_get_damage (GdkGLContext *context)
|
||||
{
|
||||
GdkMacosGLContext *self = (GdkMacosGLContext *)context;
|
||||
|
||||
if (self->damage)
|
||||
g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
|
||||
|
||||
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);
|
||||
NSView *nsview = g_steal_pointer (&self->dummy_view);
|
||||
[nsview release];
|
||||
}
|
||||
|
||||
if (cgl_context == CGLGetCurrentContext ())
|
||||
CGLSetCurrentContext (NULL);
|
||||
if (self->dummy_window != nil)
|
||||
{
|
||||
NSWindow *nswindow = g_steal_pointer (&self->dummy_window);
|
||||
[nswindow release];
|
||||
}
|
||||
|
||||
CGLClearDrawable (cgl_context);
|
||||
CGLDestroyContext (cgl_context);
|
||||
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);
|
||||
@@ -641,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;
|
||||
}
|
||||
@@ -649,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
|
||||
|
||||
@@ -29,11 +29,10 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
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);
|
||||
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
|
||||
|
||||
|
||||
@@ -56,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;
|
||||
@@ -73,6 +75,8 @@ gdk_macos_monitor_get_workarea (GdkMonitor *monitor,
|
||||
geometry->y = y;
|
||||
geometry->width = self->workarea.size.width;
|
||||
geometry->height = self->workarea.size.height;
|
||||
|
||||
GDK_END_MACOS_ALLOC_POOL;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -294,11 +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);
|
||||
}
|
||||
|
||||
@@ -204,10 +204,6 @@ 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);
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
#include "gdksurfaceprivate.h"
|
||||
|
||||
#include "gdkmacosbuffer-private.h"
|
||||
#include "gdkmacosdisplay.h"
|
||||
#include "gdkmacossurface.h"
|
||||
|
||||
@@ -46,35 +45,23 @@ struct _GdkMacosSurface
|
||||
GList frame;
|
||||
|
||||
GdkMacosWindow *window;
|
||||
GdkMacosBuffer *buffer;
|
||||
GdkMacosBuffer *front;
|
||||
GPtrArray *monitors;
|
||||
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;
|
||||
};
|
||||
|
||||
struct _GdkMacosSurfaceClass
|
||||
@@ -82,69 +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_show (GdkMacosSurface *self);
|
||||
void _gdk_macos_surface_publish_timings (GdkMacosSurface *self,
|
||||
gint64 predicted_presentation_time,
|
||||
gint64 refresh_interval);
|
||||
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
|
||||
|
||||
|
||||
+100
-243
@@ -23,7 +23,7 @@
|
||||
#include <float.h>
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
#import "GdkMacosView.h"
|
||||
#import "GdkMacosCairoView.h"
|
||||
|
||||
#include "gdkmacossurface-private.h"
|
||||
|
||||
@@ -63,16 +63,17 @@ window_is_fullscreen (GdkMacosSurface *self)
|
||||
return ([self->window styleMask] & NSWindowStyleMaskFullScreen) != 0;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
@@ -93,17 +94,6 @@ 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
|
||||
@@ -121,8 +111,9 @@ gdk_macos_surface_set_opaque_region (GdkSurface *surface,
|
||||
self->opaque_region = cairo_region_copy (region);
|
||||
}
|
||||
|
||||
if ((nsview = _gdk_macos_surface_get_view (GDK_MACOS_SURFACE (surface))))
|
||||
[(GdkMacosView *)nsview setOpaqueRegion:region];
|
||||
if ((nsview = _gdk_macos_surface_get_view (GDK_MACOS_SURFACE (surface))) &&
|
||||
GDK_IS_MACOS_CAIRO_VIEW (nsview))
|
||||
[(GdkMacosCairoView *)nsview setOpaqueRegion:region];
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -131,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_display_remove_frame_callback (GDK_MACOS_DISPLAY (surface->display), self);
|
||||
|
||||
was_mapped = GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self));
|
||||
was_key = [self->window isKeyWindow];
|
||||
|
||||
seat = gdk_display_get_default_seat (surface->display);
|
||||
gdk_seat_ungrab (seat);
|
||||
@@ -149,20 +134,6 @@ 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)
|
||||
{
|
||||
/* Return key input to the parent window if necessary */
|
||||
if (surface->parent != NULL && GDK_SURFACE_IS_MAPPED (surface->parent))
|
||||
{
|
||||
GdkMacosWindow *parentWindow = GDK_MACOS_SURFACE (surface->parent)->window;
|
||||
|
||||
[parentWindow showAndMakeKey:YES];
|
||||
}
|
||||
}
|
||||
|
||||
if (was_mapped)
|
||||
gdk_surface_freeze_updates (GDK_SURFACE (self));
|
||||
}
|
||||
@@ -219,20 +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;
|
||||
|
||||
if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self)))
|
||||
{
|
||||
_gdk_macos_display_add_frame_callback (GDK_MACOS_DISPLAY (display), self);
|
||||
gdk_surface_freeze_updates (GDK_SURFACE (self));
|
||||
}
|
||||
_gdk_macos_display_add_frame_callback (GDK_MACOS_DISPLAY (display), self);
|
||||
|
||||
gdk_surface_freeze_updates (GDK_SURFACE (self));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -244,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
|
||||
@@ -260,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
|
||||
@@ -412,7 +376,7 @@ gdk_macos_surface_destroy (GdkSurface *surface,
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -426,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);
|
||||
@@ -449,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,
|
||||
@@ -462,9 +432,6 @@ gdk_macos_surface_constructed (GObject *object)
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
}
|
||||
|
||||
if (self->window != NULL)
|
||||
_gdk_macos_surface_configure (self);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -526,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",
|
||||
@@ -621,27 +583,6 @@ _gdk_macos_surface_get_shadow (GdkMacosSurface *self,
|
||||
*right = self->shadow_right;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gdk_macos_surface_is_opaque (GdkMacosSurface *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), FALSE);
|
||||
|
||||
if (self->opaque_region != NULL &&
|
||||
cairo_region_num_rectangles (self->opaque_region) == 1)
|
||||
{
|
||||
cairo_rectangle_int_t extents;
|
||||
|
||||
cairo_region_get_extents (self->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)
|
||||
{
|
||||
@@ -691,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,
|
||||
@@ -770,21 +690,12 @@ _gdk_macos_surface_update_fullscreen_state (GdkMacosSurface *self)
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_surface_configure (GdkMacosSurface *self)
|
||||
_gdk_macos_surface_update_position (GdkMacosSurface *self)
|
||||
{
|
||||
GdkMacosDisplay *display;
|
||||
GdkSurface *surface = (GdkSurface *)self;
|
||||
NSRect frame_rect;
|
||||
NSRect content_rect;
|
||||
|
||||
g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (self))
|
||||
return;
|
||||
|
||||
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,
|
||||
@@ -801,36 +712,21 @@ _gdk_macos_surface_configure (GdkMacosSurface *self)
|
||||
surface->x = self->root_x;
|
||||
surface->y = self->root_y;
|
||||
}
|
||||
|
||||
if (surface->width != content_rect.size.width ||
|
||||
surface->height != content_rect.size.height)
|
||||
{
|
||||
surface->width = content_rect.size.width;
|
||||
surface->height = content_rect.size.height;
|
||||
|
||||
g_clear_object (&self->buffer);
|
||||
g_clear_object (&self->front);
|
||||
|
||||
_gdk_surface_update_size (surface);
|
||||
gdk_surface_request_layout (surface);
|
||||
gdk_surface_invalidate_rect (surface, NULL);
|
||||
}
|
||||
|
||||
_gdk_macos_surface_reposition_children (self);
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_macos_surface_publish_timings (GdkMacosSurface *self,
|
||||
gint64 presentation_time,
|
||||
gint64 refresh_interval)
|
||||
_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));
|
||||
|
||||
if (!(frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self))))
|
||||
return;
|
||||
gdk_surface_thaw_updates (GDK_SURFACE (self));
|
||||
|
||||
frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self));
|
||||
|
||||
if (self->pending_frame_counter)
|
||||
{
|
||||
@@ -871,16 +767,62 @@ _gdk_macos_surface_show (GdkMacosSurface *self)
|
||||
|
||||
_gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (GDK_SURFACE (self)->display));
|
||||
|
||||
self->show_on_next_swap = TRUE;
|
||||
[self->window showAndMakeKey:YES];
|
||||
|
||||
if (!was_mapped)
|
||||
{
|
||||
if (gdk_surface_get_mapped (GDK_SURFACE (self)))
|
||||
{
|
||||
_gdk_macos_surface_configure (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
|
||||
@@ -932,6 +874,7 @@ _gdk_macos_surface_move_resize (GdkMacosSurface *self,
|
||||
GdkDisplay *display;
|
||||
NSRect content_rect;
|
||||
NSRect frame_rect;
|
||||
gboolean size_changed;
|
||||
|
||||
g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
|
||||
|
||||
@@ -955,43 +898,28 @@ _gdk_macos_surface_move_resize (GdkMacosSurface *self,
|
||||
if (y == -1)
|
||||
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);
|
||||
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: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
|
||||
@@ -1058,14 +986,6 @@ _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);
|
||||
|
||||
_gdk_macos_surface_configure (self);
|
||||
|
||||
gdk_surface_invalidate_rect (GDK_SURFACE (self), NULL);
|
||||
}
|
||||
|
||||
GdkMonitor *
|
||||
@@ -1146,66 +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)
|
||||
{
|
||||
g_assert (GDK_IS_MACOS_SURFACE (self));
|
||||
|
||||
self->show_on_next_swap = FALSE;
|
||||
[self->window showAndMakeKey:YES];
|
||||
gdk_surface_request_motion (GDK_SURFACE (self));
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
@@ -194,15 +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_macos_surface_move (GDK_MACOS_SURFACE (self), x, y);
|
||||
monitor = _gdk_macos_surface_get_best_monitor (GDK_MACOS_SURFACE (self));
|
||||
|
||||
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));
|
||||
@@ -353,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;
|
||||
|
||||
@@ -391,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))
|
||||
{
|
||||
@@ -406,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;
|
||||
}
|
||||
@@ -663,9 +646,6 @@ _gdk_macos_toplevel_surface_new (GdkMacosDisplay *display,
|
||||
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,
|
||||
|
||||
@@ -2,7 +2,6 @@ gdk_macos_sources = files([
|
||||
'edgesnapping.c',
|
||||
|
||||
'gdkdisplaylinksource.c',
|
||||
'gdkmacosbuffer.c',
|
||||
'gdkmacoscairocontext.c',
|
||||
'gdkmacosclipboard.c',
|
||||
'gdkmacoscursor.c',
|
||||
@@ -10,7 +9,6 @@ gdk_macos_sources = files([
|
||||
'gdkmacosdisplay.c',
|
||||
'gdkmacosdisplay-settings.c',
|
||||
'gdkmacosdisplay-translate.c',
|
||||
'gdkmacosdisplay-wm.c',
|
||||
'gdkmacosdrag.c',
|
||||
'gdkmacosdrop.c',
|
||||
'gdkmacosdragsurface.c',
|
||||
@@ -22,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',
|
||||
])
|
||||
|
||||
@@ -47,7 +46,6 @@ gdk_macos_frameworks = [
|
||||
'CoreVideo',
|
||||
'CoreServices',
|
||||
'Foundation',
|
||||
'IOSurface',
|
||||
'OpenGL',
|
||||
'QuartzCore',
|
||||
]
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -118,6 +118,7 @@ struct _GdkWaylandSurface
|
||||
unsigned int mapped : 1;
|
||||
unsigned int awaiting_frame : 1;
|
||||
unsigned int awaiting_frame_frozen : 1;
|
||||
unsigned int is_drag_surface : 1;
|
||||
|
||||
int pending_buffer_offset_x;
|
||||
int pending_buffer_offset_y;
|
||||
@@ -779,22 +780,11 @@ gdk_wayland_surface_update_scale (GdkSurface *surface)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!impl->display_server.outputs)
|
||||
scale = 1;
|
||||
for (l = impl->display_server.outputs; l != NULL; l = l->next)
|
||||
{
|
||||
scale = impl->scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
scale = 1;
|
||||
for (l = impl->display_server.outputs; l != NULL; l = l->next)
|
||||
{
|
||||
struct wl_output *output = l->data;
|
||||
uint32_t output_scale;
|
||||
|
||||
output_scale = gdk_wayland_display_get_output_scale (display_wayland,
|
||||
output);
|
||||
scale = MAX (scale, output_scale);
|
||||
}
|
||||
guint32 output_scale = gdk_wayland_display_get_output_scale (display_wayland, l->data);
|
||||
scale = MAX (scale, output_scale);
|
||||
}
|
||||
|
||||
/* Notify app that scale changed */
|
||||
@@ -935,33 +925,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 +1467,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 +1481,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 +1493,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 +2283,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,
|
||||
@@ -2861,12 +2825,27 @@ find_grab_input_seat (GdkSurface *surface,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
should_be_mapped (GdkSurface *surface)
|
||||
{
|
||||
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
||||
|
||||
/* Don't map crazy temp that GTK uses for internal X11 shenanigans. */
|
||||
if (GDK_IS_DRAG_SURFACE (surface) && surface->x < 0 && surface->y < 0)
|
||||
return FALSE;
|
||||
|
||||
if (impl->is_drag_surface)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_surface_map_toplevel (GdkSurface *surface)
|
||||
{
|
||||
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
||||
|
||||
if (!GDK_IS_WAYLAND_TOPLEVEL (surface))
|
||||
if (!should_be_mapped (surface))
|
||||
return;
|
||||
|
||||
if (impl->mapped)
|
||||
@@ -4724,6 +4703,7 @@ create_dnd_surface (GdkDisplay *display)
|
||||
GDK_SURFACE_TEMP,
|
||||
NULL,
|
||||
0, 0, 100, 100);
|
||||
GDK_WAYLAND_SURFACE (surface)->is_drag_surface = TRUE;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
@@ -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
-720
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