Compare commits

..

1 Commits

Author SHA1 Message Date
Matthias Clasen 7fc5a894f9 Don't allow duplicate shortcuts for widget classes
Make gtk_widget_class_add_shortcut() remove an existing
shortcut with the same trigger before adding the new
shortcut. Whenever this happens, this is most likely
the intention.

Fixes: #4130
2021-08-03 15:40:37 -04:00
272 changed files with 64032 additions and 56357 deletions
+1 -1
View File
@@ -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:v33"
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v32"
FLATPAK_IMAGE: "registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master"
.only-default:
-2
View File
@@ -48,9 +48,7 @@ RUN dnf -y install \
libcloudproviders-devel \
libepoxy-devel \
libffi-devel \
libjpeg-turbo-devel \
libmount-devel \
libpng-devel \
librsvg2 \
libselinux-devel \
libubsan \
+2 -2
View File
@@ -40,7 +40,7 @@ export CCACHE_DIR="${CCACHE_BASEDIR}/_ccache"
# https://gitlab.gnome.org/GNOME/gtk/-/issues/2243
# https://gitlab.gnome.org/GNOME/gtk/-/issues/3002
if ! pkg-config --atleast-version=2.66.0 glib-2.0; then
if ! pkg-config --atleast-version=2.65.0 glib-2.0; then
git clone https://gitlab.gnome.org/GNOME/glib.git _glib
meson setup _glib_build _glib
meson compile -C _glib_build
@@ -48,7 +48,7 @@ if ! pkg-config --atleast-version=2.66.0 glib-2.0; then
fi
pkg-config --modversion glib-2.0
if ! pkg-config --atleast-version=1.49.1 pango; then
if ! pkg-config --atleast-version=1.47.0 pango; then
git clone https://gitlab.gnome.org/GNOME/pango.git _pango
meson setup _pango_build _pango
meson compile -C _pango_build
-81
View File
@@ -1,84 +1,3 @@
Overview of Changes
===================
* gsk:
- Drop the GL renderer in favor of NGL
* css:
- Add support for line-height
- Add support for text-transform
* GtkTextView:
- Add support for line height
- Add support for text transforms
* Build:
- Require Pango 1.49
Overview of Changes in 4.4.0
============================
* Input:
- Match IBus for display of Compose sequences
- Match IBus for handling of mismatches
- Handle Escape in Compose sequences
- Allow multiple dead keys
- Support 32bit keysyms
* GtkCheckButton:
- Activate when moving focus
* GtkLabel:
- Propertly ignore double underscores for mnemonics
* GtkPopoverMenu:
- Fix focus cycling
* GtkTextView:
- Improve word selection
- Fix block cursors on empty lines
* GdkToplevel:
- Support the gnome-shell titlebar gesture protocol
* GdkDropTarget:
- Allow creating drop targets in ui files
* gsk:
- Handle partial color fonts correctly
- Use harfbuzz for color font information
- Avoid pango for glyph cache rendering
- Shrink shadow extents
* Settings:
- Change the default for gtk-split-cursor to FALSE
* Demos:
- Small improvements to widget-factory
- gtk-demo: Improve the hypertext demo
- gtk-dem: Improve the clipboard demo
* X11:
- Set WM_CLASS on toplevels
* Wayland:
- Support wl_seat v7
* Windows:
- Drop the local DND protocol
- Avoid WGL if shaders don't work
- Use WinPointer API
* Translation updates:
Belarusian
Friulian
Hebrew
Khmer
Persian
Polish
Overview of Changes in 4.3.2
============================
-1
View File
@@ -321,7 +321,6 @@
<file>paintable_emblem.c</file>
<file>paintable_mediastream.c</file>
<file>paintable_svg.c</file>
<file>paintable_symbolic.c</file>
<file>panes.c</file>
<file>password_entry.c</file>
<file>peg_solitaire.c</file>
+12 -42
View File
@@ -100,11 +100,7 @@ prepare_drag (GtkDragSource *source,
DemoImage *demo = DEMO_IMAGE (widget);
GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (demo->image));
/* Textures can be serialized, paintables can't, so special case the textures */
if (GDK_IS_TEXTURE (paintable))
return gdk_content_provider_new_typed (GDK_TYPE_TEXTURE, paintable);
else
return gdk_content_provider_new_typed (GDK_TYPE_PAINTABLE, paintable);
return gdk_content_provider_new_typed (GDK_TYPE_PAINTABLE, paintable);
}
static gboolean
@@ -133,11 +129,7 @@ copy_image (GtkWidget *widget,
GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (demo->image));
GValue value = G_VALUE_INIT;
/* Textures can be serialized, paintables can't, so special case the textures */
if (GDK_IS_TEXTURE (paintable))
g_value_init (&value, GDK_TYPE_TEXTURE);
else
g_value_init (&value, GDK_TYPE_PAINTABLE);
g_value_init (&value, GDK_TYPE_PAINTABLE);
g_value_set_object (&value, paintable);
gdk_clipboard_set_value (clipboard, &value);
g_value_unset (&value);
@@ -146,46 +138,24 @@ copy_image (GtkWidget *widget,
g_object_unref (paintable);
}
static void
paste_image_cb (GObject *source,
GAsyncResult *result,
gpointer data)
{
GdkClipboard *clipboard = GDK_CLIPBOARD (source);
DemoImage *demo = DEMO_IMAGE (data);
const GValue *value;
value = gdk_clipboard_read_value_finish (clipboard, result, NULL);
if (value == NULL)
{
gtk_widget_error_bell (GTK_WIDGET (demo));
g_object_unref (demo);
return;
}
gtk_image_set_from_paintable (GTK_IMAGE (demo->image), g_value_get_object (value));
g_object_unref (demo);
}
static void
paste_image (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
GdkClipboard *clipboard = gtk_widget_get_clipboard (widget);
GType type;
DemoImage *demo = DEMO_IMAGE (widget);
GdkContentProvider *content = gdk_clipboard_get_content (clipboard);
GValue value = G_VALUE_INIT;
GdkPaintable *paintable;
if (gdk_content_formats_contain_gtype (gdk_clipboard_get_formats (clipboard), GDK_TYPE_TEXTURE))
type = GDK_TYPE_TEXTURE;
else
type = GDK_TYPE_PAINTABLE;
g_value_init (&value, GDK_TYPE_PAINTABLE);
if (!gdk_content_provider_get_value (content, &value, NULL))
return;
gdk_clipboard_read_value_async (clipboard,
type,
G_PRIORITY_DEFAULT,
NULL,
paste_image_cb,
g_object_ref (widget));
paintable = GDK_PAINTABLE (g_value_get_object (&value));
gtk_image_set_from_paintable (GTK_IMAGE (demo->image), paintable);
g_value_unset (&value);
}
static void
-40
View File
@@ -131,19 +131,6 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
gtk_text_buffer_apply_tag (buffer, tag, start, end); \
}
#define VOID_ATTR(attr_name) \
{ \
tag = gtk_text_tag_table_lookup (table, #attr_name); \
if (!tag) \
{ \
tag = gtk_text_tag_new (#attr_name); \
g_object_set (tag, #attr_name, TRUE, NULL); \
gtk_text_tag_table_add (table, tag); \
g_object_unref (tag); \
} \
gtk_text_buffer_apply_tag (buffer, tag, start, end); \
}
fg_alpha = bg_alpha = 1.;
attrs = pango_attr_iterator_get_attrs (iter);
@@ -268,29 +255,6 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
INT_ATTR (insert_hyphens);
break;
case PANGO_ATTR_LINE_HEIGHT:
FLOAT_ATTR (line_height);
break;
case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT:
break;
case PANGO_ATTR_WORD:
VOID_ATTR (word);
break;
case PANGO_ATTR_SENTENCE:
VOID_ATTR (sentence);
break;
case PANGO_ATTR_BASELINE_SHIFT:
INT_ATTR (baseline_shift);
break;
case PANGO_ATTR_FONT_SCALE:
INT_ATTR (font_scale);
break;
case PANGO_ATTR_SHAPE:
case PANGO_ATTR_ABSOLUTE_SIZE:
case PANGO_ATTR_GRAVITY:
@@ -299,10 +263,6 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
case PANGO_ATTR_BACKGROUND_ALPHA:
break;
case PANGO_ATTR_TEXT_TRANSFORM:
INT_ATTR (text_transform);
break;
case PANGO_ATTR_INVALID:
default:
g_assert_not_reached ();
+13 -163
View File
@@ -1,11 +1,6 @@
/* Pango/Font Rendering
*
* Demonstrates various aspects of font rendering,
* such as hinting, antialiasing and grid alignment.
*
* The demo lets you explore font rendering options
* interactively to get a feeling for they affect the
* shape and positioning of the glyphs.
* Demonstrates various aspects of font rendering.
*/
#include <gtk/gtk.h>
@@ -15,21 +10,16 @@ static GtkWidget *font_button = NULL;
static GtkWidget *entry = NULL;
static GtkWidget *image = NULL;
static GtkWidget *hinting = NULL;
static GtkWidget *anti_alias = NULL;
static GtkWidget *hint_metrics = NULL;
static GtkWidget *up_button = NULL;
static GtkWidget *down_button = NULL;
static GtkWidget *text_radio = NULL;
static GtkWidget *show_grid = NULL;
static GtkWidget *show_extents = NULL;
static GtkWidget *show_pixels = NULL;
static GtkWidget *show_outlines = NULL;
static PangoContext *context;
static int scale = 7;
static double pixel_alpha = 1.0;
static double outline_alpha = 0.0;
static int scale = 9;
static void
update_image (void)
@@ -47,8 +37,6 @@ update_image (void)
cairo_font_options_t *fopt;
cairo_hint_style_t hintstyle;
cairo_hint_metrics_t hintmetrics;
cairo_antialias_t antialias;
cairo_path_t *path;
if (!context)
context = gtk_widget_create_pango_context (image);
@@ -77,13 +65,6 @@ update_image (void)
hintmetrics = CAIRO_HINT_METRICS_OFF;
cairo_font_options_set_hint_metrics (fopt, hintmetrics);
if (gtk_check_button_get_active (GTK_CHECK_BUTTON (anti_alias)))
antialias = CAIRO_ANTIALIAS_GRAY;
else
antialias = CAIRO_ANTIALIAS_NONE;
cairo_font_options_set_antialias (fopt, antialias);
pango_context_set_round_glyph_positions (context, hintmetrics == CAIRO_HINT_METRICS_ON);
pango_cairo_context_set_font_options (context, fopt);
cairo_font_options_destroy (fopt);
pango_context_changed (context);
@@ -104,14 +85,10 @@ update_image (void)
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_paint (cr);
cairo_set_source_rgba (cr, 0, 0, 0, pixel_alpha);
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_move_to (cr, 10, 10);
pango_cairo_show_layout (cr, layout);
pango_cairo_layout_path (cr, layout);
path = cairo_copy_path (cr);
cairo_destroy (cr);
g_object_unref (layout);
@@ -150,7 +127,7 @@ update_image (void)
if (gtk_check_button_get_active (GTK_CHECK_BUTTON (show_extents)))
{
cairo_set_source_rgb (cr, 0, 0, 1);
cairo_set_source_rgba (cr, 0, 0, 1, 1);
cairo_rectangle (cr,
scale * (10 + pango_units_to_double (logical.x)) - 0.5,
@@ -163,7 +140,7 @@ update_image (void)
cairo_line_to (cr, scale * (10 + pango_units_to_double (logical.x + logical.width)) + 1,
scale * (10 + pango_units_to_double (baseline)) - 0.5);
cairo_stroke (cr);
cairo_set_source_rgb (cr, 1, 0, 0);
cairo_set_source_rgba (cr, 1, 0, 0, 1);
cairo_rectangle (cr,
scale * (10 + pango_units_to_double (pink.x)) + 0.5,
scale * (10 + pango_units_to_double (pink.y)) + 0.5,
@@ -172,36 +149,8 @@ update_image (void)
cairo_stroke (cr);
}
for (int i = 0; i < path->num_data; i += path->data[i].header.length)
{
cairo_path_data_t *data = &path->data[i];
switch (data->header.type)
{
case CAIRO_PATH_CURVE_TO:
data[3].point.x *= scale; data[3].point.y *= scale;
data[2].point.x *= scale; data[2].point.y *= scale;
data[1].point.x *= scale; data[1].point.y *= scale;
break;
case CAIRO_PATH_LINE_TO:
case CAIRO_PATH_MOVE_TO:
data[1].point.x *= scale; data[1].point.y *= scale;
break;
case CAIRO_PATH_CLOSE_PATH:
break;
default:
g_assert_not_reached ();
}
}
cairo_set_source_rgba (cr, 0, 0, 1, outline_alpha);
cairo_move_to (cr, scale * 20 - 0.5, scale * 20 - 0.5);
cairo_append_path (cr, path);
cairo_stroke (cr);
cairo_surface_destroy (surface);
cairo_destroy (cr);
cairo_path_destroy (path);
}
else
{
@@ -209,26 +158,10 @@ update_image (void)
PangoLayoutRun *run;
PangoGlyphInfo *g;
int i, j;
GString *str;
gunichar ch;
if (*text == '\0')
text = " ";
ch = g_utf8_get_char (text);
str = g_string_new ("");
for (i = 0; i < 4; i++)
{
g_string_append_unichar (str, ch);
g_string_append_unichar (str, 0x200c);
}
layout = pango_layout_new (context);
pango_layout_set_font_description (layout, desc);
pango_layout_set_text (layout, str->str, -1);
g_string_free (str, TRUE);
pango_layout_set_text (layout, "aaaa", -1);
pango_layout_get_extents (layout, &ink, &logical);
pango_extents_to_pixels (&logical, NULL);
@@ -243,7 +176,7 @@ update_image (void)
cairo_set_source_rgb (cr, 0, 0, 0);
for (i = 0; i < 4; i++)
{
g = &(run->glyphs->glyphs[2*i]);
g = &(run->glyphs->glyphs[i]);
g->geometry.width = PANGO_UNITS_ROUND (g->geometry.width * 3 / 2);
}
@@ -251,7 +184,7 @@ update_image (void)
{
for (i = 0; i < 4; i++)
{
g = &(run->glyphs->glyphs[2*i]);
g = &(run->glyphs->glyphs[i]);
g->geometry.x_offset = i * (PANGO_SCALE / 4);
g->geometry.y_offset = j * (PANGO_SCALE / 4);
}
@@ -270,6 +203,7 @@ update_image (void)
cairo_surface_destroy (surface);
}
gtk_picture_set_pixbuf (GTK_PICTURE (image), pixbuf2);
g_object_unref (pixbuf2);
@@ -277,78 +211,6 @@ update_image (void)
pango_font_description_free (desc);
}
static gboolean fading = FALSE;
static double start_pixel_alpha;
static double end_pixel_alpha;
static double start_outline_alpha;
static double end_outline_alpha;
static gint64 start_time;
static gint64 end_time;
static double
ease_out_cubic (double t)
{
double p = t - 1;
return p * p * p + 1;
}
static gboolean
change_alpha (GtkWidget *widget,
GdkFrameClock *clock,
gpointer user_data)
{
gint64 now = g_get_monotonic_time ();
double t;
t = ease_out_cubic ((now - start_time) / (double) (end_time - start_time));
pixel_alpha = start_pixel_alpha + (end_pixel_alpha - start_pixel_alpha) * t;
outline_alpha = start_outline_alpha + (end_outline_alpha - start_outline_alpha) * t;
update_image ();
if (now >= end_time)
{
fading = FALSE;
return G_SOURCE_REMOVE;
}
return G_SOURCE_CONTINUE;
}
static void
start_alpha_fade (void)
{
gboolean pixels;
gboolean outlines;
if (fading)
return;
pixels = gtk_check_button_get_active (GTK_CHECK_BUTTON (show_pixels));
outlines = gtk_check_button_get_active (GTK_CHECK_BUTTON (show_outlines));
start_pixel_alpha = pixel_alpha;
if (pixels && outlines)
end_pixel_alpha = 0.5;
else if (pixels)
end_pixel_alpha = 1;
else
end_pixel_alpha = 0;
start_outline_alpha = outline_alpha;
if (outlines)
end_outline_alpha = 1.0;
else
end_outline_alpha = 0.0;
start_time = g_get_monotonic_time ();
end_time = start_time + G_TIME_SPAN_SECOND / 2;
fading = TRUE;
gtk_widget_add_tick_callback (window, change_alpha, NULL, NULL);
}
static void
update_buttons (void)
{
@@ -356,26 +218,20 @@ update_buttons (void)
gtk_widget_set_sensitive (down_button, scale > 1);
}
static gboolean
scale_up (GtkWidget *widget,
GVariant *args,
gpointer user_data)
static void
scale_up (void)
{
scale += 1;
update_buttons ();
update_image ();
return TRUE;
}
static gboolean
scale_down (GtkWidget *widget,
GVariant *args,
gpointer user_data)
static void
scale_down (void)
{
scale -= 1;
update_buttons ();
update_image ();
return TRUE;
}
GtkWidget *
@@ -396,26 +252,20 @@ do_fontrendering (GtkWidget *do_widget)
entry = GTK_WIDGET (gtk_builder_get_object (builder, "entry"));
image = GTK_WIDGET (gtk_builder_get_object (builder, "image"));
hinting = GTK_WIDGET (gtk_builder_get_object (builder, "hinting"));
anti_alias = GTK_WIDGET (gtk_builder_get_object (builder, "antialias"));
hint_metrics = GTK_WIDGET (gtk_builder_get_object (builder, "hint_metrics"));
text_radio = GTK_WIDGET (gtk_builder_get_object (builder, "text_radio"));
show_grid = GTK_WIDGET (gtk_builder_get_object (builder, "show_grid"));
show_extents = GTK_WIDGET (gtk_builder_get_object (builder, "show_extents"));
show_pixels = GTK_WIDGET (gtk_builder_get_object (builder, "show_pixels"));
show_outlines = GTK_WIDGET (gtk_builder_get_object (builder, "show_outlines"));
g_signal_connect (up_button, "clicked", G_CALLBACK (scale_up), NULL);
g_signal_connect (down_button, "clicked", G_CALLBACK (scale_down), NULL);
g_signal_connect (entry, "notify::text", G_CALLBACK (update_image), NULL);
g_signal_connect (font_button, "notify::font-desc", G_CALLBACK (update_image), NULL);
g_signal_connect (hinting, "notify::active", G_CALLBACK (update_image), NULL);
g_signal_connect (anti_alias, "notify::active", G_CALLBACK (update_image), NULL);
g_signal_connect (hint_metrics, "notify::active", G_CALLBACK (update_image), NULL);
g_signal_connect (text_radio, "notify::active", G_CALLBACK (update_image), NULL);
g_signal_connect (show_grid, "notify::active", G_CALLBACK (update_image), NULL);
g_signal_connect (show_extents, "notify::active", G_CALLBACK (update_image), NULL);
g_signal_connect (show_pixels, "notify::active", G_CALLBACK (start_alpha_fade), NULL);
g_signal_connect (show_outlines, "notify::active", G_CALLBACK (start_alpha_fade), NULL);
update_image ();
+33 -87
View File
@@ -1,8 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkAdjustment" id="scale_adj">
<property name="upper">24</property>
<property name="step-increment">1</property>
<property name="page-increment">4</property>
</object>
<object class="GtkWindow" id="window">
<property name="default-width">1024</property>
<property name="default-height">768</property>
<property name="default-width">1080</property>
<property name="default-height">430</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<child type="title">
@@ -82,94 +87,57 @@
</object>
</child>
<child>
<object class="GtkCheckButton" id="show_pixels">
<property name="label">Show _Pixels</property>
<property name="use-underline">1</property>
<property name="active">1</property>
<object class="GtkLabel">
<property name="label">Hinting</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
<layout>
<property name="column">3</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkCheckButton" id="show_outlines">
<property name="label">Show _Outline</property>
<property name="use-underline">1</property>
<layout>
<property name="column">3</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkBox">
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label">_Hinting</property>
<property name="use-underline">1</property>
<property name="mnemonic-widget">hinting</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="hinting">
<property name="active">0</property>
<property name="valign">center</property>
<items>
<item translatable="yes" id="none">None</item>
<item translatable="yes" id="slight">Slight</item>
<item translatable="yes" id="medium">Medium</item>
<item translatable="yes" id="full">Full</item>
</items>
</object>
</child>
<object class="GtkComboBoxText" id="hinting">
<property name="active">0</property>
<property name="valign">center</property>
<items>
<item translatable="yes" id="none">None</item>
<item translatable="yes" id="slight">Slight</item>
<item translatable="yes" id="medium">Medium</item>
<item translatable="yes" id="full">Full</item>
</items>
<layout>
<property name="column">4</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkCheckButton" id="antialias">
<property name="label">_Antialias</property>
<property name="use-underline">1</property>
<property name="active">1</property>
<layout>
<property name="column">4</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkCheckButton" id="hint_metrics">
<property name="label">Hint _Metrics</property>
<property name="use-underline">1</property>
<property name="label">Hint Metrics</property>
<layout>
<property name="column">5</property>
<property name="column">4</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkCheckButton" id="show_extents">
<property name="label">Show _Extents</property>
<property name="use-underline">1</property>
<property name="label">Show Extents</property>
<property name="active">1</property>
<layout>
<property name="column">6</property>
<property name="column">5</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkCheckButton" id="show_grid">
<property name="label">Show _Grid</property>
<property name="use-underline">1</property>
<property name="active">1</property>
<property name="label">Show Grid</property>
<layout>
<property name="column">6</property>
<property name="column">5</property>
<property name="row">1</property>
</layout>
</object>
@@ -180,19 +148,8 @@
<style>
<class name="circular"/>
</style>
<child>
<object class="GtkShortcutController">
<property name="scope">managed</property>
<child>
<object class="GtkShortcut">
<property name="trigger">&lt;Control&gt;plus</property>
<property name="action">activate</property>
</object>
</child>
</object>
</child>
<layout>
<property name="column">7</property>
<property name="column">6</property>
<property name="row">0</property>
</layout>
</object>
@@ -203,19 +160,8 @@
<style>
<class name="circular"/>
</style>
<child>
<object class="GtkShortcutController">
<property name="scope">managed</property>
<child>
<object class="GtkShortcut">
<property name="trigger">&lt;Control&gt;minus</property>
<property name="action">activate</property>
</object>
</child>
</object>
</child>
<layout>
<property name="column">7</property>
<property name="column">6</property>
<property name="row">1</property>
</layout>
</object>
@@ -224,7 +170,7 @@
<object class="GtkLabel">
<property name="hexpand">1</property>
<layout>
<property name="column">8</property>
<property name="column">7</property>
</layout>
</object>
</child>
+22 -49
View File
@@ -61,26 +61,12 @@ show_page (GtkTextView *text_view,
int page)
{
GtkTextBuffer *buffer;
GtkTextIter iter, start;
GtkTextMark *mark;
GtkTextIter iter;
GtkWidget *child;
GtkTextChildAnchor *anchor;
GtkEventController *controller;
GtkTextTag *bold, *mono, *nobreaks;
buffer = gtk_text_view_get_buffer (text_view);
bold = gtk_text_buffer_create_tag (buffer, NULL,
"weight", PANGO_WEIGHT_BOLD,
"scale", PANGO_SCALE_X_LARGE,
NULL);
mono = gtk_text_buffer_create_tag (buffer, NULL,
"family", "monospace",
NULL);
nobreaks = gtk_text_buffer_create_tag (buffer, NULL,
"allow-breaks", FALSE,
NULL);
gtk_text_buffer_set_text (buffer, "", 0);
gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
gtk_text_buffer_begin_irreversible_action (buffer);
@@ -118,22 +104,17 @@ show_page (GtkTextView *text_view,
}
else if (page == 2)
{
mark = gtk_text_buffer_create_mark (buffer, "mark", &iter, TRUE);
GtkTextTag *tag;
gtk_text_buffer_insert_with_tags (buffer, &iter, "tag", -1, bold, NULL);
gtk_text_buffer_insert (buffer, &iter, " /", -1);
gtk_text_buffer_get_iter_at_mark (buffer, &start, mark);
gtk_text_buffer_apply_tag (buffer, nobreaks, &start, &iter);
gtk_text_buffer_insert (buffer, &iter, " ", -1);
gtk_text_buffer_move_mark (buffer, mark, &iter);
gtk_text_buffer_insert_with_tags (buffer, &iter, "tag", -1, mono, NULL);
gtk_text_buffer_insert (buffer, &iter, " /", -1);
gtk_text_buffer_get_iter_at_mark (buffer, &start, mark);
gtk_text_buffer_apply_tag (buffer, nobreaks, &start, &iter);
gtk_text_buffer_insert (buffer, &iter, " ", -1);
tag = gtk_text_buffer_create_tag (buffer, NULL,
"weight", PANGO_WEIGHT_BOLD,
"scale", PANGO_SCALE_X_LARGE,
NULL);
gtk_text_buffer_insert_with_tags (buffer, &iter, "tag", -1, tag, NULL);
tag = gtk_text_buffer_create_tag (buffer, NULL,
"family", "monospace",
NULL);
gtk_text_buffer_insert_with_tags (buffer, &iter, " /tag/ ", -1, tag, NULL);
anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
child = gtk_image_new_from_icon_name ("audio-volume-high-symbolic");
@@ -151,26 +132,20 @@ show_page (GtkTextView *text_view,
"behavior of mouse and key presses, “lock” a range of text so the "
"user can't edit it, or countless other things.\n", -1);
insert_link (buffer, &iter, "Go back", 1);
gtk_text_buffer_delete_mark (buffer, mark);
}
else if (page == 3)
{
mark = gtk_text_buffer_create_mark (buffer, "mark", &iter, TRUE);
GtkTextTag *tag;
gtk_text_buffer_insert_with_tags (buffer, &iter, "hypertext", -1, bold, NULL);
gtk_text_buffer_insert (buffer, &iter, " /", -1);
gtk_text_buffer_get_iter_at_mark (buffer, &start, mark);
gtk_text_buffer_apply_tag (buffer, nobreaks, &start, &iter);
gtk_text_buffer_insert (buffer, &iter, " ", -1);
gtk_text_buffer_move_mark (buffer, mark, &iter);
gtk_text_buffer_insert_with_tags (buffer, &iter, "ˈhaɪ pərˌtɛkst", -1, mono, NULL);
gtk_text_buffer_insert (buffer, &iter, " /", -1);
gtk_text_buffer_get_iter_at_mark (buffer, &start, mark);
gtk_text_buffer_apply_tag (buffer, nobreaks, &start, &iter);
gtk_text_buffer_insert (buffer, &iter, " ", -1);
tag = gtk_text_buffer_create_tag (buffer, NULL,
"weight", PANGO_WEIGHT_BOLD,
"scale", PANGO_SCALE_X_LARGE,
NULL);
gtk_text_buffer_insert_with_tags (buffer, &iter, "hypertext", -1, tag, NULL);
tag = gtk_text_buffer_create_tag (buffer, NULL,
"family", "monospace",
NULL);
gtk_text_buffer_insert_with_tags (buffer, &iter, " /ˈhaɪ pərˌtɛkst/ ", -1, tag, NULL);
anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
child = gtk_image_new_from_icon_name ("audio-volume-high-symbolic");
@@ -184,8 +159,6 @@ show_page (GtkTextView *text_view,
"Machine-readable text that is not sequential but is organized "
"so that related items of information are connected.\n", -1);
insert_link (buffer, &iter, "Go back", 1);
gtk_text_buffer_delete_mark (buffer, mark);
}
gtk_text_buffer_end_irreversible_action (buffer);
}
@@ -385,7 +358,7 @@ do_hypertext (GtkWidget *do_widget)
sw = gtk_scrolled_window_new ();
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_window_set_child (GTK_WINDOW (window), sw);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), view);
+1 -1
View File
@@ -58,7 +58,7 @@ do_markup (GtkWidget *do_widget)
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 600, 680);
gtk_window_set_default_size (GTK_WINDOW (window), 450, 450);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
stack = gtk_stack_new ();
+2 -12
View File
@@ -1,9 +1,5 @@
Text sizes: <span size="xx-small">tiny </span><span size="x-small">very small </span><span size="small">small </span><span size="medium">normal </span><span size="large">large </span><span size="x-large">very large </span><span size="xx-large">huge</span>
Text styles: <span style="normal">Normal</span> <span style="italic">Italic</span> <span style="oblique">Olique</span>
Text weights: <span weight="thin">thin</span> <span weight="light">light</span> <span weight="normal">normal</span> <span weight="bold">bold</span> <span weight="ultraheavy">ultraheavy</span>
Text sizes: <span size="xx-small">tiny</span> <span size="x-small">very small</span> <span size="small">small</span> <span size="medium">normal</span> <span size="large">large</span> <span size="x-large">very large</span> <span size="xx-large">huge</span>
Text <span color="gray">c<span color="green">o</span>l<span color="tomato">o</span>rs</span> and <span background="pink">backgrounds</span>
@@ -19,12 +15,6 @@ OpenType font features: <span font_desc="sans regular" font_features="dlig=0">fe
Shortcuts: <tt>Monospace</tt> <b>Bold</b> <i>Italic</i> <big>Big</big> <small>Small</small> <u>Underlined</u> <s>Strikethrough</s> Super<sup>script</sup> Sub<sub>script</sub>
hy­phen­ation al­go­rithm is a <span allow_breaks="false" style="italic">set of rules</span>, espe­ci­ally one co­di­fied for im­ple­men­tation in a com­pu­ter pro­gram, that de­ci­des at which points a word can be bro­ken over two lines with a hy­phen. For ex­am­ple, a hy­phen­ation al­go­rithm might de­cide that im­peach­ment can be broken as impeach‧ment or im‧peachment but not impe‧achment.
<span allow_breaks="false">A</span> hy­phen­ation al­go­rithm is a set of rules, espe­ci­ally one co­di­fied for im­ple­men­tation in a com­pu­ter pro­gram, that de­ci­des at which points a word can be bro­ken over two lines with a hy­phen. For ex­am­ple, a hy­phen­ation al­go­rithm might de­cide that im­peach­ment can be broken as <span allow_breaks="false">impeach‧ment</span> or <span allow_breaks="false">im‧peachment</span> but not <span allow_breaks="false">impe‧achment.</span>
<span insert_hyphens="false">one/two three/four five/six seven/eight nine/ten</span>
<span line_height='1.33'>Line height: This is an example of widely spaced text. It was achieved by setting the line-height factor to 1.33. You can set the line-height factor to any value between 0 and 10.
Note that the line height affects the spacing between paragraphs as well as between the wrapped lines inside a paragraph.</span>
Transforms: <span text_transform='uppercase'>straße</span> <span text_transform='capitalize'>up, up and away</span>
-1
View File
@@ -67,7 +67,6 @@ demos = files([
'paintable_animated.c',
'paintable_emblem.c',
'paintable_mediastream.c',
'paintable_symbolic.c',
'panes.c',
'password_entry.c',
'peg_solitaire.c',
+11 -13
View File
@@ -45,27 +45,26 @@ struct _GtkNuclearIconClass
* so that it can be called from all the other demos, too.
*/
void
gtk_nuclear_snapshot (GtkSnapshot *snapshot,
const GdkRGBA *foreground,
const GdkRGBA *background,
double width,
double height,
double rotation)
gtk_nuclear_snapshot (GtkSnapshot *snapshot,
double width,
double height,
double rotation,
gboolean draw_background)
{
#define RADIUS 0.3
cairo_t *cr;
double size;
gtk_snapshot_append_color (snapshot,
background,
&GRAPHENE_RECT_INIT (0, 0, width, height));
if (draw_background)
gtk_snapshot_append_color (snapshot,
&(GdkRGBA) { 0.9, 0.75, 0.15, 1.0 },
&GRAPHENE_RECT_INIT (0, 0, width, height));
size = MIN (width, height);
cr = gtk_snapshot_append_cairo (snapshot,
&GRAPHENE_RECT_INIT ((width - size) / 2.0,
(height - size) / 2.0,
size, size));
gdk_cairo_set_source_rgba (cr, foreground);
cairo_translate (cr, width / 2.0, height / 2.0);
cairo_scale (cr, size, size);
cairo_rotate (cr, rotation);
@@ -95,10 +94,9 @@ gtk_nuclear_icon_snapshot (GdkPaintable *paintable,
*/
gtk_nuclear_snapshot (snapshot,
&(GdkRGBA) { 0, 0, 0, 1 }, /* black */
&(GdkRGBA) { 0.9, 0.75, 0.15, 1.0 }, /* yellow */
width, height,
nuclear->rotation);
nuclear->rotation,
TRUE);
}
static GdkPaintableFlags
+2 -3
View File
@@ -4,11 +4,10 @@
#include <gtk/gtk.h>
void gtk_nuclear_snapshot (GtkSnapshot *snapshot,
const GdkRGBA *foreground,
const GdkRGBA *background,
double width,
double height,
double rotation);
double rotation,
gboolean draw_background);
GdkPaintable * gtk_nuclear_icon_new (double rotation);
GdkPaintable * gtk_nuclear_animation_new (gboolean draw_background);
+2 -5
View File
@@ -65,12 +65,9 @@ gtk_nuclear_animation_snapshot (GdkPaintable *paintable,
/* We call the function from the previous example here. */
gtk_nuclear_snapshot (snapshot,
&(GdkRGBA) { 0, 0, 0, 1 }, /* black */
nuclear->draw_background
? &(GdkRGBA) { 0.9, 0.75, 0.15, 1.0 } /* yellow */
: &(GdkRGBA) { 0, 0, 0, 0 }, /* transparent */
width, height,
2 * G_PI * nuclear->progress / MAX_PROGRESS);
2 * G_PI * nuclear->progress / MAX_PROGRESS,
nuclear->draw_background);
}
static GdkPaintable *
+2 -3
View File
@@ -73,10 +73,9 @@ gtk_nuclear_media_stream_snapshot (GdkPaintable *paintable,
/* We call the function from the previous example here. */
gtk_nuclear_snapshot (snapshot,
&(GdkRGBA) { 0, 0, 0, 1 }, /* black */
&(GdkRGBA) { 0.9, 0.75, 0.15, 1.0 }, /* yellow */
width, height,
2 * G_PI * nuclear->progress / DURATION);
2 * G_PI * nuclear->progress / DURATION,
TRUE);
}
static GdkPaintable *
-208
View File
@@ -1,208 +0,0 @@
/* Paintable/Symbolic Paintable
*
* GdkPaintables can be made to follow the theme's colors. GTK calls
* icons that do this symbolic icons, paintables that want to have
* the same effect can implement the GtkSymbolicPaintable interface.
*
* We will adapt the original paintable example by adding the ability
* to recolor the paintable based on the symbolic colors.
*/
#include <gtk/gtk.h>
#include "paintable.h"
static GtkWidget *window = NULL;
/* First, add the boilerplate for the object itself.
* This part would normally go in the header.
*/
#define GTK_TYPE_NUCLEAR_SYMBOLIC (gtk_nuclear_symbolic_get_type ())
G_DECLARE_FINAL_TYPE (GtkNuclearSymbolic, gtk_nuclear_symbolic, GTK, NUCLEAR_SYMBOLIC, GObject)
/* Declare a few warning levels, so we can pick colors based on them */
typedef enum
{
WARNING_NONE,
WARNING_ALERT,
WARNING_EMERGENCY
} WarningLevel;
/* Declare the struct. */
struct _GtkNuclearSymbolic
{
GObject parent_instance;
WarningLevel warning_level;
};
struct _GtkNuclearSymbolicClass
{
GObjectClass parent_class;
};
/* Add a function to draw the nuclear icon in the given colors */
static void
gtk_nuclear_symbolic_snapshot_symbolic (GtkSymbolicPaintable *paintable,
GdkSnapshot *snapshot,
double width,
double height,
const GdkRGBA *colors,
gsize n_colors)
{
GtkNuclearSymbolic *self = GTK_NUCLEAR_SYMBOLIC (paintable);
static const GdkRGBA transparent = { 0, };
const GdkRGBA *bg_color;
/* select the right background color from the warning level */
switch (self->warning_level)
{
case WARNING_NONE:
bg_color = &transparent;
break;
case WARNING_ALERT:
bg_color = &colors[GTK_SYMBOLIC_COLOR_WARNING];
break;
case WARNING_EMERGENCY:
bg_color = &colors[GTK_SYMBOLIC_COLOR_ERROR];
break;
default:
/* This should never happen, but we better do defensive coding
* with this critical icon */
g_assert_not_reached ();
bg_color = &transparent;
break;
}
/* Draw the icon with the selected warning color */
gtk_nuclear_snapshot (snapshot,
&colors[GTK_SYMBOLIC_COLOR_FOREGROUND],
bg_color,
width, height,
0);
}
static void
gtk_nuclear_symbolic_symbolic_paintable_init (GtkSymbolicPaintableInterface *iface)
{
iface->snapshot_symbolic = gtk_nuclear_symbolic_snapshot_symbolic;
}
/* We need to implement the functionality required by the GdkPaintable interface */
static void
gtk_nuclear_symbolic_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
double width,
double height)
{
/* Calling this function without passing a color is a neat trick
* to make GTK use default colors and otherwise forward the call
* to the snapshotting function above.
*/
gtk_symbolic_paintable_snapshot_symbolic (GTK_SYMBOLIC_PAINTABLE (paintable),
snapshot,
width, height,
NULL, 0);
}
static GdkPaintableFlags
gtk_nuclear_symbolic_get_flags (GdkPaintable *paintable)
{
/* This image has a static size, but the contents may change:
* We draw different things when the warning level changes.
*/
return GDK_PAINTABLE_STATIC_SIZE;
}
static void
gtk_nuclear_symbolic_paintable_init (GdkPaintableInterface *iface)
{
iface->snapshot = gtk_nuclear_symbolic_snapshot;
iface->get_flags = gtk_nuclear_symbolic_get_flags;
}
/* When defining the GType, we need to implement bot the GdkPaintable
* and the GtkSymbolicPaintable interface */
G_DEFINE_TYPE_WITH_CODE (GtkNuclearSymbolic, gtk_nuclear_symbolic, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
gtk_nuclear_symbolic_paintable_init)
G_IMPLEMENT_INTERFACE (GTK_TYPE_SYMBOLIC_PAINTABLE,
gtk_nuclear_symbolic_symbolic_paintable_init))
static void
gtk_nuclear_symbolic_class_init (GtkNuclearSymbolicClass *klass)
{
}
static void
gtk_nuclear_symbolic_init (GtkNuclearSymbolic *nuclear)
{
}
/* And finally, we add the simple constructor we declared in the header. */
GdkPaintable *
gtk_nuclear_symbolic_new (void)
{
return g_object_new (GTK_TYPE_NUCLEAR_SYMBOLIC, NULL);
}
/* Add some fun feature to the button */
static void
nuclear_button_clicked (GtkButton *button,
GtkNuclearSymbolic *nuclear)
{
if (nuclear->warning_level >= WARNING_EMERGENCY)
{
/* On maximum warning level, reset the warning */
nuclear->warning_level = WARNING_NONE;
/* And sometimes (but not always to confuse people)
* close the window.
*/
if (g_random_boolean ())
gtk_window_close (GTK_WINDOW (window));
}
else
{
/* Otherwise just increase the warning level */
nuclear->warning_level++;
}
/* Don't forget to emit the signal causing the paintable to redraw.
* Changing the warning level changes the background color after all.
*/
gdk_paintable_invalidate_contents (GDK_PAINTABLE (nuclear));
}
GtkWidget *
do_paintable_symbolic (GtkWidget *do_widget)
{
GdkPaintable *nuclear;
GtkWidget *image, *button;
if (!window)
{
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Don't click!");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
button = gtk_button_new ();
gtk_window_set_child (GTK_WINDOW (window), button);
nuclear = gtk_nuclear_symbolic_new ();
image = gtk_image_new_from_paintable (nuclear);
gtk_button_set_child (GTK_BUTTON (button), image);
g_signal_connect (button, "clicked", G_CALLBACK (nuclear_button_clicked), nuclear);
g_object_unref (nuclear);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}
+20 -112
View File
@@ -24,6 +24,7 @@
#include "gtkrendererpaintableprivate.h"
#include "gsk/gskrendernodeparserprivate.h"
#include "gsk/gl/gskglrenderer.h"
#include "gsk/ngl/gsknglrenderer.h"
#ifdef GDK_WINDOWING_BROADWAY
#include "gsk/broadway/gskbroadwayrenderer.h"
@@ -60,7 +61,7 @@ struct _NodeEditorWindow
GtkWidget *renderer_listbox;
GListStore *renderers;
GskRenderNode *node;
GdkPaintable *paintable;
GFileMonitor *file_monitor;
@@ -167,6 +168,7 @@ static void
text_changed (GtkTextBuffer *buffer,
NodeEditorWindow *self)
{
GskRenderNode *node;
char *text;
GBytes *bytes;
GtkTextIter iter;
@@ -177,12 +179,10 @@ text_changed (GtkTextBuffer *buffer,
text_buffer_remove_all_tags (self->text_buffer);
bytes = g_bytes_new_take (text, strlen (text));
g_clear_pointer (&self->node, gsk_render_node_unref);
/* If this is too slow, go fix the parser performance */
self->node = gsk_render_node_deserialize (bytes, deserialize_error_func, self);
node = gsk_render_node_deserialize (bytes, deserialize_error_func, self);
g_bytes_unref (bytes);
if (self->node)
if (node)
{
/* XXX: Is this code necessary or can we have API to turn nodes into paintables? */
GtkSnapshot *snapshot;
@@ -191,9 +191,10 @@ text_changed (GtkTextBuffer *buffer,
guint i;
snapshot = gtk_snapshot_new ();
gsk_render_node_get_bounds (self->node, &bounds);
gsk_render_node_get_bounds (node, &bounds);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (- bounds.origin.x, - bounds.origin.y));
gtk_snapshot_append_node (snapshot, self->node);
gtk_snapshot_append_node (snapshot, node);
gsk_render_node_unref (node);
paintable = gtk_snapshot_free_to_paintable (snapshot, &bounds.size);
gtk_picture_set_paintable (GTK_PICTURE (self->picture), paintable);
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (self->renderers)); i++)
@@ -337,9 +338,15 @@ text_view_query_tooltip_cb (GtkWidget *widget,
}
static gboolean
load_bytes (NodeEditorWindow *self,
GBytes *bytes)
load_file_contents (NodeEditorWindow *self,
GFile *file)
{
GBytes *bytes;
bytes = g_file_load_bytes (file, NULL, NULL, NULL);
if (bytes == NULL)
return FALSE;
if (!g_utf8_validate (g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), NULL))
{
g_bytes_unref (bytes);
@@ -355,105 +362,6 @@ load_bytes (NodeEditorWindow *self,
return TRUE;
}
static gboolean
load_file_contents (NodeEditorWindow *self,
GFile *file)
{
GBytes *bytes;
bytes = g_file_load_bytes (file, NULL, NULL, NULL);
if (bytes == NULL)
return FALSE;
return load_bytes (self, bytes);
}
static GdkContentProvider *
on_picture_drag_prepare_cb (GtkDragSource *source,
double x,
double y,
NodeEditorWindow *self)
{
if (self->node == NULL)
return NULL;
return gdk_content_provider_new_typed (GSK_TYPE_RENDER_NODE, self->node);
}
static void
on_picture_drop_read_done_cb (GObject *source,
GAsyncResult *res,
gpointer data)
{
NodeEditorWindow *self = data;
GOutputStream *stream = G_OUTPUT_STREAM (source);
GdkDrop *drop = g_object_get_data (source, "drop");
GdkDragAction action = 0;
GBytes *bytes;
if (g_output_stream_splice_finish (stream, res, NULL) >= 0)
{
bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (stream));
if (load_bytes (self, bytes))
action = GDK_ACTION_COPY;
}
g_object_unref (self);
gdk_drop_finish (drop, action);
g_object_unref (drop);
return;
}
static void
on_picture_drop_read_cb (GObject *source,
GAsyncResult *res,
gpointer data)
{
NodeEditorWindow *self = data;
GdkDrop *drop = GDK_DROP (source);
GInputStream *input;
GOutputStream *output;
input = gdk_drop_read_finish (drop, res, NULL, NULL);
if (input == NULL)
{
g_object_unref (self);
gdk_drop_finish (drop, 0);
return;
}
output = g_memory_output_stream_new_resizable ();
g_object_set_data (G_OBJECT (output), "drop", drop);
g_object_ref (drop);
g_output_stream_splice_async (output,
input,
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
G_PRIORITY_DEFAULT,
NULL,
on_picture_drop_read_done_cb,
self);
g_object_unref (output);
g_object_unref (input);
}
static gboolean
on_picture_drop_cb (GtkDropTargetAsync *dest,
GdkDrop *drop,
double x,
double y,
NodeEditorWindow *self)
{
gdk_drop_read_async (drop,
(const char *[2]) { "application/x-gtk-render-node", NULL },
G_PRIORITY_DEFAULT,
NULL,
on_picture_drop_read_cb,
g_object_ref (self));
return TRUE;
}
static void
file_changed_cb (GFileMonitor *monitor,
GFile *file,
@@ -828,7 +736,6 @@ node_editor_window_finalize (GObject *object)
g_array_free (self->errors, TRUE);
g_clear_pointer (&self->node, gsk_render_node_unref);
g_clear_object (&self->renderers);
G_OBJECT_CLASS (node_editor_window_parent_class)->finalize (object);
@@ -872,8 +779,11 @@ node_editor_window_realize (GtkWidget *widget)
"Default");
#endif
node_editor_window_add_renderer (self,
gsk_ngl_renderer_new (),
gsk_gl_renderer_new (),
"OpenGL");
node_editor_window_add_renderer (self,
gsk_ngl_renderer_new (),
"NGL");
#ifdef GDK_RENDERING_VULKAN
node_editor_window_add_renderer (self,
gsk_vulkan_renderer_new (),
@@ -938,8 +848,6 @@ node_editor_window_class_init (NodeEditorWindowClass *class)
gtk_widget_class_bind_template_callback (widget_class, testcase_save_clicked_cb);
gtk_widget_class_bind_template_callback (widget_class, testcase_name_entry_changed_cb);
gtk_widget_class_bind_template_callback (widget_class, dark_mode_cb);
gtk_widget_class_bind_template_callback (widget_class, on_picture_drag_prepare_cb);
gtk_widget_class_bind_template_callback (widget_class, on_picture_drop_cb);
}
static GtkWidget *
-13
View File
@@ -200,19 +200,6 @@
<property name="can-shrink">0</property>
<property name="halign">center</property>
<property name="valign">center</property>
<child>
<object class="GtkDragSource">
<property name="actions">copy</property>
<signal name="prepare" handler="on_picture_drag_prepare_cb" swapped="no"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkDropTargetAsync">
<property name="actions">copy</property>
<property name="formats">application/x-gtk-render-node</property>
<signal name="drop" handler="on_picture_drop_cb" swapped="no"/>
</object>
</child>
</object>
-2
View File
@@ -162,8 +162,6 @@ done with
|caret-color|[CSS Basic User Interface Level 3](https://www.w3.org/TR/css3-ui/#caret-color) | CSS allows an auto value |
|-gtk-secondary-caret-color|[Color](https://www.w3.org/TR/css-color-3/#valuea-def-color) | used for the secondary caret in bidirectional text |
|letter-spacing| [CSS Text Level 3](https://www.w3.org/TR/css3-text/#letter-spacing) | |
|text-transform| [CSS Text Level 3](https://www.w3.org/TR/css-text-3/#text-transform-property) | CSS allows full-width and full-size-kana. Since 4.6 |
|line-height| [CSS Inline Layout Level 3](https://www.w3.org/TR/css-inline-3/#line-height-property) | Since 4.6 |
|text-decoration-line| [CSS Text Decoration Level 3](https://www.w3.org/TR/css-text-decor-3/#text-decoration-line-property) | |
|text-decoration-color| [CSS Text Decoration Level 3](https://www.w3.org/TR/css-text-decor-3/#text-decoration-color-property) | |
|text-decoration-style| [CSS Text Decoration Level 3](https://www.w3.org/TR/css-text-decor-3/#text-decoration-style-property) | CSS allows dashed and dotted |
-8
View File
@@ -137,14 +137,6 @@ capture phase, and key bindings locally, during the target phase.
Under the hood, all shortcuts are represented as instances of `GtkShortcut`,
and they are managed by `GtkShortcutController`.
## Text input
When actual text input is needed (i.e. not just keyboard shortcuts),
input method support can be added to a widget by connecting an input
method context and listening to its `::commit` signal. To create a new
input method context, use gtk_im_multicontext_new(), to provide it with
input, use gtk_event_controller_key_set_im_context().
## Event controllers and gestures
Event controllers are standalone objects that can perform
+5 -10
View File
@@ -14,19 +14,14 @@ instructions, binary downloads, etc, can be found
The Win32 GDK backend can be influenced with some additional environment
variables.
### GDK_WIN32_TABLET_INPUT_API
### GDK_IGNORE_WINTAB
If this variable is set, it determines the API that GTK uses for tablet support.
The possible values are:
If this variable is set, GTK doesn't use the Wintab API for tablet support.
`none`
: Disables tablet support
### GDK_USE_WINTAB
`wintab`
: Use the Wintab API
`winpointer`
: Use the Windows Pointer Input Stack API. This is the default.
If this variable is set, GTK uses the Wintab API for tablet support.
This is the default.
## Windows-specific handling of cursors
-4
View File
@@ -5,10 +5,6 @@ gidocgen = find_program('gi-docgen', required: get_option('gtk_doc'))
docs_dir = gtk_datadir / 'doc'
if get_option('gtk_doc') and not build_gir
error('API reference requires introspection.')
endif
subdir('gdk')
subdir('gsk')
subdir('gtk')
+29 -4
View File
@@ -7,6 +7,10 @@
struct _ExampleAppPrefs
{
GtkDialog parent;
GSettings *settings;
GtkWidget *font;
GtkWidget *transition;
};
G_DEFINE_TYPE (ExampleAppPrefs, example_app_prefs, GTK_TYPE_DIALOG)
@@ -15,20 +19,41 @@ static void
example_app_prefs_init (ExampleAppPrefs *prefs)
{
gtk_widget_init_template (GTK_WIDGET (prefs));
prefs->settings = g_settings_new ("org.gtk.exampleapp");
g_settings_bind (prefs->settings, "font",
prefs->font, "font",
G_SETTINGS_BIND_DEFAULT);
g_settings_bind (prefs->settings, "transition",
prefs->transition, "active-id",
G_SETTINGS_BIND_DEFAULT);
}
static void
example_app_prefs_dispose (GObject *object)
{
ExampleAppPrefs *prefs;
prefs = EXAMPLE_APP_PREFS (object);
g_clear_object (&prefs->settings);
G_OBJECT_CLASS (example_app_prefs_parent_class)->dispose (object);
}
static void
example_app_prefs_class_init (ExampleAppPrefsClass *class)
{
G_OBJECT_CLASS (class)->dispose = example_app_prefs_dispose;
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/exampleapp/prefs.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppPrefs, font);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppPrefs, transition);
}
ExampleAppPrefs *
example_app_prefs_new (ExampleAppWindow *win)
{
return g_object_new (EXAMPLE_APP_PREFS_TYPE,
"transient-for", win,
"use-header-bar", TRUE,
NULL);
return g_object_new (EXAMPLE_APP_PREFS_TYPE, "transient-for", win, "use-header-bar", TRUE, NULL);
}
-2
View File
@@ -28,7 +28,6 @@
</child>
<child>
<object class="GtkFontButton" id="font">
<property name="font" bind-settings-schema="org.gtk.exampleapp" bind-settings-key="font"/>
<layout>
<property name="column">1</property>
<property name="row">0</property>
@@ -49,7 +48,6 @@
</child>
<child>
<object class="GtkComboBoxText" id="transition">
<property name="active-id" bind-settings-schema="org.gtk.exampleapp" bind-settings-key="transition"/>
<items>
<item translatable="yes" id="none">None</item>
<item translatable="yes" id="crossfade">Fade</item>
+1 -1
View File
@@ -132,7 +132,7 @@ static const GdkDebugKey gdk_debug_keys[] = {
{ "gl-wgl", GDK_DEBUG_GL_WGL, "Use WGL on Windows" },
{ "vulkan-disable", GDK_DEBUG_VULKAN_DISABLE, "Disable Vulkan support" },
{ "vulkan-validate", GDK_DEBUG_VULKAN_VALIDATE, "Load the Vulkan validation layer" },
{ "default-settings",GDK_DEBUG_DEFAULT_SETTINGS, "Force default values for xsettings", TRUE },
{ "default-settings",GDK_DEBUG_DEFAULT_SETTINGS, "Force default values for xsettings" },
};
+2 -8
View File
@@ -635,7 +635,7 @@ gdk_clipboard_read_internal (GdkClipboard *clipboard,
/**
* gdk_clipboard_read_async:
* @clipboard: a `GdkClipboard`
* @mime_types: (array zero-terminated=1): a %NULL-terminated array of mime types to choose from
* @mime_types: a %NULL-terminated array of mime types to choose from
* @io_priority: the I/O priority of the request
* @cancellable: (nullable): optional `GCancellable` object
* @callback: (scope async): callback to call when the request is satisfied
@@ -1253,15 +1253,9 @@ gdk_clipboard_set_content (GdkClipboard *clipboard,
* @...: value contents conforming to @type
*
* Sets the clipboard to contain the value collected from the given varargs.
*
* Values should be passed the same way they are passed to other value
* collecting APIs, such as [`method@GObject.Object.set`] or
* [`id@g_signal_emit`].
*
* ```c
* gdk_clipboard_set (clipboard, GTK_TYPE_STRING, "Hello World");
*
* gdk_clipboard_set (clipboard, GDK_TYPE_TEXTURE, some_texture);
* gdk_clipboard_set (clipboard, GTK_TYPE_TEXT_BUFFER, buffer);
* ```
*/
void
+1 -6
View File
@@ -553,8 +553,6 @@ gdk_content_deserialize_async (GInputStream *stream,
Deserializer *deserializer;
g_return_if_fail (G_IS_INPUT_STREAM (stream));
g_return_if_fail (mime_type != NULL);
g_return_if_fail (G_TYPE_IS_VALUE_TYPE (type));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
g_return_if_fail (callback != NULL);
@@ -593,10 +591,7 @@ gdk_content_deserialize_finish (GAsyncResult *result,
g_return_val_if_fail (GDK_IS_CONTENT_DESERIALIZER (result), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
deserializer = GDK_CONTENT_DESERIALIZER (result);
if (G_VALUE_TYPE (value) == 0)
g_value_init (value, G_VALUE_TYPE (&deserializer->value));
else
g_return_val_if_fail (G_VALUE_HOLDS (value, G_VALUE_TYPE (&deserializer->value)), FALSE);
g_return_val_if_fail (G_VALUE_HOLDS (value, G_VALUE_TYPE (&deserializer->value)), FALSE);
if (deserializer->error)
{
+1 -1
View File
@@ -80,7 +80,7 @@ gdk_content_provider_value_get_value (GdkContentProvider *provider,
{
GdkContentProviderValue *content = GDK_CONTENT_PROVIDER_VALUE (provider);
if (G_VALUE_HOLDS (&content->value, G_VALUE_TYPE (value)))
if (G_VALUE_HOLDS (value, G_VALUE_TYPE (&content->value)))
{
g_value_copy (&content->value, value);
return TRUE;
+5 -5
View File
@@ -70,17 +70,17 @@ typedef enum {
* snapshot at or 0 if none. This is purely a hint. The object must still
* be able to render at any size.
* @get_intrinsic_aspect_ratio: The preferred aspect ratio for this object
* or 0 if none. If both [vfunc@Gdk.Paintable.get_intrinsic_width]
* and [vfunc@Gdk.Paintable.get_intrinsic_height] return non-zero
* or 0 if none. If both [vfunc@Gdk.PaintableInterface.get_intrinsic_width]
* and [vfunc@Gdk.PaintableInterface.get_intrinsic_height] return non-zero
* values, this function should return the aspect ratio computed from those.
*
* The list of functions that can be implemented for the `GdkPaintable`
* interface.
*
* Note that apart from the [vfunc@Gdk.Paintable.snapshot] function,
* Note that apart from the [vfunc@Gdk.PaintableInterface.snapshot] function,
* no virtual function of this interface is mandatory to implement, though it
* is a good idea to implement [vfunc@Gdk.Paintable.get_current_image]
* for non-static paintables and [vfunc@Gdk.Paintable.get_flags] if the
* is a good idea to implement [vfunc@Gdk.PaintableInterface.get_current_image]
* for non-static paintables and [vfunc@Gdk.PaintableInterface.get_flags] if the
* image is not dynamic as the default implementation returns no flags and
* that will make the implementation likely quite slow.
*/
-22
View File
@@ -94,14 +94,6 @@
*/
#define GDK_VERSION_4_4 (G_ENCODE_VERSION (4, 4))
/**
* GDK_VERSION_4_6:
*
* A macro that evaluates to the 4.6 version of GDK, in a format
* that can be used by the C pre-processor.
*/
#define GDK_VERSION_4_6 (G_ENCODE_VERSION (4, 6))
/* evaluates to the current stable version; for development cycles,
* this means the next stable target, with a hard backstop to the
@@ -229,18 +221,4 @@
# define GDK_DEPRECATED_IN_4_4_FOR(f) _GDK_EXTERN
#endif
#if GDK_VERSION_MAX_ALLOWED < GDK_VERSION_4_6
# define GDK_AVAILABLE_IN_4_6 GDK_UNAVAILABLE(4, 6)
#else
# define GDK_AVAILABLE_IN_4_6 _GDK_EXTERN
#endif
#if GDK_VERSION_MIN_REQUIRED >= GDK_VERSION_4_6
# define GDK_DEPRECATED_IN_4_6 GDK_DEPRECATED
# define GDK_DEPRECATED_IN_4_6_FOR(f) GDK_DEPRECATED_FOR(f)
#else
# define GDK_DEPRECATED_IN_4_6 _GDK_EXTERN
# define GDK_DEPRECATED_IN_4_6_FOR(f) _GDK_EXTERN
#endif
#endif /* __GDK_VERSION_MACROS_H__ */
+39 -39
View File
@@ -117,104 +117,104 @@ gdk_vulkan_strerror (VkResult result)
switch (result)
{
case VK_SUCCESS:
return "Command successfully completed. (VK_SUCCESS)";
return "Command successfully completed.";
case VK_NOT_READY:
return "A fence or query has not yet completed. (VK_NOT_READY)";
return "A fence or query has not yet completed.";
case VK_TIMEOUT:
return "A wait operation has not completed in the specified time. (VK_TIMEOUT)";
return "A wait operation has not completed in the specified time.";
case VK_EVENT_SET:
return "An event is signaled. (VK_EVENT_SET)";
return "An event is signaled.";
case VK_EVENT_RESET:
return "An event is unsignaled. (VK_EVENT_RESET)";
return "An event is unsignaled.";
case VK_INCOMPLETE:
return "A return array was too small for the result. (VK_INCOMPLETE)";
return "A return array was too small for the result.";
case VK_SUBOPTIMAL_KHR:
return "A swapchain no longer matches the surface properties exactly, but can still be used to present to the surface successfully. (VK_SUBOPTIMAL_KHR)";
return "A swapchain no longer matches the surface properties exactly, but can still be used to present to the surface successfully.";
case VK_ERROR_OUT_OF_HOST_MEMORY:
return "A host memory allocation has failed. (VK_ERROR_OUT_OF_HOST_MEMORY)";
return "A host memory allocation has failed.";
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
return "A device memory allocation has failed. (VK_ERROR_OUT_OF_DEVICE_MEMORY)";
return "A device memory allocation has failed.";
case VK_ERROR_INITIALIZATION_FAILED:
return "Initialization of an object could not be completed for implementation-specific reasons. (VK_ERROR_INITIALIZATION_FAILED)";
return "Initialization of an object could not be completed for implementation-specific reasons.";
case VK_ERROR_DEVICE_LOST:
return "The logical or physical device has been lost. (VK_ERROR_DEVICE_LOST)";
return "The logical or physical device has been lost.";
case VK_ERROR_MEMORY_MAP_FAILED:
return "Mapping of a memory object has failed. (VK_ERROR_MEMORY_MAP_FAILED)";
return "Mapping of a memory object has failed.";
case VK_ERROR_LAYER_NOT_PRESENT:
return "A requested layer is not present or could not be loaded. (VK_ERROR_LAYER_NOT_PRESENT)";
return "A requested layer is not present or could not be loaded.";
case VK_ERROR_EXTENSION_NOT_PRESENT:
return "A requested extension is not supported. (VK_ERROR_EXTENSION_NOT_PRESENT)";
return "A requested extension is not supported.";
case VK_ERROR_FEATURE_NOT_PRESENT:
return "A requested feature is not supported. (VK_ERROR_FEATURE_NOT_PRESENT)";
return "A requested feature is not supported.";
case VK_ERROR_INCOMPATIBLE_DRIVER:
return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible for implementation-specific reasons. (VK_ERROR_INCOMPATIBLE_DRIVER)";
return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible for implementation-specific reasons.";
case VK_ERROR_TOO_MANY_OBJECTS:
return "Too many objects of the type have already been created. (VK_ERROR_TOO_MANY_OBJECTS)";
return "Too many objects of the type have already been created.";
case VK_ERROR_FORMAT_NOT_SUPPORTED:
return "A requested format is not supported on this device. (VK_ERROR_FORMAT_NOT_SUPPORTED)";
return "A requested format is not supported on this device.";
#if VK_HEADER_VERSION >= 24
case VK_ERROR_FRAGMENTED_POOL:
return "A requested pool allocation has failed due to fragmentation of the pools memory. (VK_ERROR_FRAGMENTED_POOL)";
return "A requested pool allocation has failed due to fragmentation of the pools memory.";
#endif
case VK_ERROR_SURFACE_LOST_KHR:
return "A surface is no longer available. (VK_ERROR_SURFACE_LOST_KHR)";
return "A surface is no longer available.";
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
return "The requested window is already in use by Vulkan or another API in a manner which prevents it from being used again. (VK_ERROR_NATIVE_WINDOW_IN_USE_KHR)";
return "The requested window is already in use by Vulkan or another API in a manner which prevents it from being used again.";
case VK_ERROR_OUT_OF_DATE_KHR:
return "A surface has changed in such a way that it is no longer compatible with the swapchain. (VK_ERROR_OUT_OF_DATE_KHR)";
return "A surface has changed in such a way that it is no longer compatible with the swapchain.";
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
return "The display used by a swapchain does not use the same presentable image layout, or is incompatible in a way that prevents sharing an image. (VK_ERROR_INCOMPATIBLE_DISPLAY_KHR)";
return "The display used by a swapchain does not use the same presentable image layout, or is incompatible in a way that prevents sharing an image.";
case VK_ERROR_VALIDATION_FAILED_EXT:
return "The application caused the validation layer to fail. (VK_ERROR_VALIDATION_FAILED_EXT)";
return "The application caused the validation layer to fail.";
case VK_ERROR_INVALID_SHADER_NV:
return "One or more shaders failed to compile or link. (VK_ERROR_INVALID_SHADER_NV)";
return "One or more shaders failed to compile or link.";
#if VK_HEADER_VERSION >= 39
case VK_ERROR_OUT_OF_POOL_MEMORY_KHR:
return "A pool memory allocation has failed. (VK_ERROR_OUT_OF_POOL_MEMORY_KHR)";
return "A pool memory allocation has failed.";
#endif
#if VK_HEADER_VERSION >= 54
case VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR:
return "An external handle is not a valid handle of the specified type. (VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR)";
return "An external handle is not a valid handle of the specified type.";
#endif
#if VK_HEADER_VERSION >= 64
case VK_ERROR_NOT_PERMITTED_EXT:
return "The caller does not have sufficient privileges. (VK_ERROR_NOT_PERMITTED_EXT)";
return "The caller does not have sufficient privileges.";
#endif
#if VK_HEADER_VERSION >= 72
case VK_ERROR_FRAGMENTATION_EXT:
return "A descriptor pool creation has failed due to fragmentation. (VK_ERROR_FRAGMENTATION_EXT)";
return "A descriptor pool creation has failed due to fragmentation";
#endif
#if VK_HEADER_VERSION >= 89
case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT:
return "Invalid DRM format modifier plane layout (VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT)";
return "Invalid DRM format modifier plane layout";
#endif
#if VK_HEADER_VERSION >= 97
case VK_ERROR_INVALID_DEVICE_ADDRESS_EXT:
return "Invalid device address (VK_ERROR_INVALID_DEVICE_ADDRESS_EXT)";
return "Invalid device address";
#endif
#if VK_HEADER_VERSION >= 105
case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT:
return "An operation on a swapchain created with VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT failed as it did not have exclusive full-screen access. (VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT)";
return "An operation on a swapchain created with VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT failed as it did not have exclusive full-screen access.";
#endif
#if VK_HEADER_VERSION >= 131
case VK_ERROR_UNKNOWN:
return "An unknown error has occurred; either the application has provided invalid input, or an implementation failure has occurred. (VK_ERROR_UNKNOWN)";
return "An unknown error has occurred; either the application has provided invalid input, or an implementation failure has occurred.";
#endif
#if VK_HEADER_VERSION >= 135
#if VK_HEADER_VERSION < 162
case VK_ERROR_INCOMPATIBLE_VERSION_KHR:
return "This error was removed by the Vulkan gods. (VK_ERROR_INCOMPATIBLE_VERSION_KHR)";
return "This error was removed by the Vulkan gods.";
#endif
case VK_THREAD_IDLE_KHR:
return "A deferred operation is not complete but there is currently no work for this thread to do at the time of this call. (VK_THREAD_IDLE_KHR)";
return "A deferred operation is not complete but there is currently no work for this thread to do at the time of this call.";
case VK_THREAD_DONE_KHR:
return "A deferred operation is not complete but there is no work remaining to assign to additional threads. (VK_THREAD_DONE_KHR)";
return "A deferred operation is not complete but there is no work remaining to assign to additional threads.";
case VK_OPERATION_DEFERRED_KHR:
return "A deferred operation was requested and at least some of the work was deferred. (VK_OPERATION_DEFERRED_KHR)";
return "A deferred operation was requested and at least some of the work was deferred.";
case VK_OPERATION_NOT_DEFERRED_KHR:
return "A deferred operation was requested and no operations were deferred. (VK_OPERATION_NOT_DEFERRED_KHR)";
return "A deferred operation was requested and no operations were deferred.";
case VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT:
return "A requested pipeline creation would have required compilation, but the application requested compilation to not be performed. (VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT)";
return "A requested pipeline creation would have required compilation, but the application requested compilation to not be performed.";
#endif
#if VK_HEADER_VERSION < 140
case VK_RESULT_RANGE_SIZE:
-2
View File
@@ -32,8 +32,6 @@
#include "gdkmacoseventsource-private.h"
#include "gdkmacosdisplay-private.h"
#include "gdk-private.h"
/*
* This file implementations integration between the GLib main loop and
* the native system of the Core Foundation run loop and Cocoa event
+1 -20
View File
@@ -2634,23 +2634,6 @@ touch_handle_cancel (void *data,
GDK_SEAT_NOTE (seat, EVENTS, g_message ("touch cancel"));
}
static void
touch_handle_shape (void *data,
struct wl_touch *touch,
int32_t id,
wl_fixed_t major,
wl_fixed_t minor)
{
}
static void
touch_handle_orientation (void *data,
struct wl_touch *touch,
int32_t id,
wl_fixed_t orientation)
{
}
static void
emit_gesture_swipe_event (GdkWaylandSeat *seat,
GdkTouchpadGesturePhase phase,
@@ -3038,9 +3021,7 @@ static const struct wl_touch_listener touch_listener = {
touch_handle_up,
touch_handle_motion,
touch_handle_frame,
touch_handle_cancel,
touch_handle_shape,
touch_handle_orientation,
touch_handle_cancel
};
static const struct zwp_pointer_gesture_swipe_v1_listener gesture_swipe_listener = {
+2 -2
View File
@@ -240,7 +240,7 @@ _gdk_wayland_display_add_seat (GdkWaylandDisplay *display_wayland,
{
struct wl_seat *seat;
display_wayland->seat_version = MIN (version, 7);
display_wayland->seat_version = MIN (version, 5);
seat = wl_registry_bind (display_wayland->wl_registry,
id, &wl_seat_interface,
display_wayland->seat_version);
@@ -2117,7 +2117,7 @@ gdk_wayland_display_get_setting (GdkDisplay *display,
{
TranslationEntry *entry;
if (gdk_display_get_debug_flags (display) & GDK_DEBUG_DEFAULT_SETTINGS)
if (GDK_DISPLAY_DEBUG_CHECK (display, DEFAULT_SETTINGS))
return FALSE;
if (GDK_WAYLAND_DISPLAY (display)->settings != NULL &&
+1 -16
View File
@@ -32,7 +32,6 @@
#include "gdkprivate-wayland.h"
#include "gdkinternals.h"
#include "gdk-private.h"
#include "gdksurfaceprivate.h"
#include "gdkprofilerprivate.h"
@@ -475,28 +474,14 @@ gdk_wayland_display_init_gl (GdkDisplay *display,
G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
G_GNUC_UNUSED gint64 start_time2;
if (!epoxy_has_egl ())
{
gboolean sandboxed = gdk_running_in_sandbox ();
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
sandboxed ? _("libEGL not available in this sandbox")
: _("libEGL not available"));
return NULL;
}
start_time2 = GDK_PROFILER_CURRENT_TIME;
dpy = get_egl_display (display_wayland);
gdk_profiler_end_mark (start_time, "get_egl_display", NULL);
if (dpy == NULL)
{
gboolean sandboxed = gdk_running_in_sandbox ();
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
sandboxed ? _("Sandbox does not provide an OpenGL implementation")
: _("No OpenGL implementation available"));
_("Failed to create EGL display"));
return NULL;
}
+1 -1
View File
@@ -542,7 +542,7 @@ _gdk_wayland_keymap_update_from_fd (GdkKeymap *keymap,
context = xkb_context_new (0);
map_str = mmap (NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
map_str = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0);
if (map_str == MAP_FAILED)
{
close(fd);
+2 -2
View File
@@ -89,7 +89,7 @@ gdk_device_win32_query_state (GdkDevice *device,
hwnd = NULL;
}
_gdk_win32_get_cursor_pos (&point);
GetCursorPos (&point);
if (hwnd)
ScreenToClient (hwnd, &point);
@@ -177,7 +177,7 @@ _gdk_device_win32_surface_at_position (GdkDevice *device,
HWND hwnd;
RECT rect;
if (!_gdk_win32_get_cursor_pos (&screen_pt))
if (!GetCursorPos (&screen_pt))
return NULL;
/* Use WindowFromPoint instead of ChildWindowFromPoint(Ex).
-224
View File
@@ -1,224 +0,0 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2020 the GTK team
*
* 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/>.
*/
#include "config.h"
#include <gdk/gdksurface.h>
#include <windows.h>
#include "gdkwin32.h"
#include "gdkdevice-winpointer.h"
#include "gdkdisplay-win32.h"
G_DEFINE_TYPE (GdkDeviceWinpointer, gdk_device_winpointer, GDK_TYPE_DEVICE)
static GdkModifierType
get_keyboard_mask (void)
{
GdkModifierType mask = 0;
BYTE kbd[256];
GetKeyboardState (kbd);
if (kbd[VK_SHIFT] & 0x80)
mask |= GDK_SHIFT_MASK;
if (kbd[VK_CAPITAL] & 0x80)
mask |= GDK_LOCK_MASK;
if (kbd[VK_CONTROL] & 0x80)
mask |= GDK_CONTROL_MASK;
if (kbd[VK_MENU] & 0x80)
mask |= GDK_ALT_MASK;
return mask;
}
static void
gdk_device_winpointer_set_surface_cursor (GdkDevice *device,
GdkSurface *window,
GdkCursor *cursor)
{
}
void
gdk_device_winpointer_query_state (GdkDevice *device,
GdkSurface *window,
GdkSurface **child_window,
double *win_x,
double *win_y,
GdkModifierType *mask)
{
GdkDeviceWinpointer *device_winpointer;
POINT point;
HWND hwnd, hwndc;
int scale;
device_winpointer = GDK_DEVICE_WINPOINTER (device);
if (window)
{
scale = GDK_WIN32_SURFACE (window)->surface_scale;
hwnd = GDK_SURFACE_HWND (window);
}
else
{
GdkDisplay *display = gdk_device_get_display (device);
scale = GDK_WIN32_DISPLAY (display)->surface_scale;
hwnd = NULL;
}
_gdk_win32_get_cursor_pos (&point);
if (hwnd)
ScreenToClient (hwnd, &point);
if (win_x)
*win_x = point.x / scale;
if (win_y)
*win_y = point.y / scale;
if (!window)
{
if (win_x)
*win_x += _gdk_offset_x;
if (win_y)
*win_y += _gdk_offset_y;
}
if (hwnd && child_window)
{
hwndc = ChildWindowFromPoint (hwnd, point);
if (hwndc && hwndc != hwnd)
*child_window = gdk_win32_handle_table_lookup (hwndc);
else
*child_window = NULL; /* Direct child unknown to gdk */
}
if (mask)
{
*mask = get_keyboard_mask ();
*mask |= device_winpointer->last_button_mask;
}
}
static GdkGrabStatus
gdk_device_winpointer_grab (GdkDevice *device,
GdkSurface *window,
gboolean owner_events,
GdkEventMask event_mask,
GdkSurface *confine_to,
GdkCursor *cursor,
guint32 time_)
{
return GDK_GRAB_SUCCESS;
}
static void
gdk_device_winpointer_ungrab (GdkDevice *device,
guint32 time_)
{
}
static void
screen_to_client (HWND hwnd, POINT screen_pt, POINT *client_pt)
{
*client_pt = screen_pt;
ScreenToClient (hwnd, client_pt);
}
static GdkSurface *
gdk_device_winpointer_surface_at_position (GdkDevice *device,
double *win_x,
double *win_y,
GdkModifierType *mask)
{
GdkSurface *surface = NULL;
GdkWin32Surface *impl = NULL;
POINT screen_pt, client_pt;
HWND hwnd;
RECT rect;
if (!_gdk_win32_get_cursor_pos (&screen_pt))
return NULL;
/* Use WindowFromPoint instead of ChildWindowFromPoint(Ex).
* Only WindowFromPoint is able to look through transparent
* layered windows.
*/
hwnd = GetAncestor (WindowFromPoint (screen_pt), GA_ROOT);
/* Verify that we're really inside the client area of the surface */
GetClientRect (hwnd, &rect);
screen_to_client (hwnd, screen_pt, &client_pt);
if (!PtInRect (&rect, client_pt))
hwnd = NULL;
surface = gdk_win32_handle_table_lookup (hwnd);
if (surface && (win_x || win_y))
{
impl = GDK_WIN32_SURFACE (surface);
if (win_x)
*win_x = client_pt.x / impl->surface_scale;
if (win_y)
*win_y = client_pt.y / impl->surface_scale;
}
return surface;
}
static void
gdk_device_winpointer_init (GdkDeviceWinpointer *device_winpointer)
{
device_winpointer->device_handle = NULL;
device_winpointer->start_cursor_id = 0;
device_winpointer->end_cursor_id = 0;
device_winpointer->origin_x = 0;
device_winpointer->origin_y = 0;
device_winpointer->scale_x = 0.0;
device_winpointer->scale_y = 0.0;
device_winpointer->last_button_mask = 0;
}
static void
gdk_device_winpointer_finalize (GObject *object)
{
GdkDeviceWinpointer *device_winpointer = GDK_DEVICE_WINPOINTER (object);
g_clear_object (&device_winpointer->tool_pen);
g_clear_object (&device_winpointer->tool_eraser);
G_OBJECT_CLASS (gdk_device_winpointer_parent_class)->finalize (object);
}
static void
gdk_device_winpointer_class_init (GdkDeviceWinpointerClass *klass)
{
GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gdk_device_winpointer_finalize;
device_class->set_surface_cursor = gdk_device_winpointer_set_surface_cursor;
device_class->grab = gdk_device_winpointer_grab;
device_class->ungrab = gdk_device_winpointer_ungrab;
device_class->surface_at_position = gdk_device_winpointer_surface_at_position;
}
-67
View File
@@ -1,67 +0,0 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2020 the GTK team
*
* 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/>.
*/
#ifndef __GDK_DEVICE_WINPOINTER_H__
#define __GDK_DEVICE_WINPOINTER_H__
#include <gdk/gdkdeviceprivate.h>
#include <windows.h>
#include "winpointer.h"
G_BEGIN_DECLS
#define GDK_TYPE_DEVICE_WINPOINTER (gdk_device_winpointer_get_type ())
#define GDK_DEVICE_WINPOINTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE_WINPOINTER, GdkDeviceWinpointer))
#define GDK_DEVICE_WINPOINTER_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE_WINPOINTER, GdkDeviceWinpointerClass))
#define GDK_IS_DEVICE_WINPOINTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE_WINPOINTER))
#define GDK_IS_DEVICE_WINPOINTER_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE_WINPOINTER))
#define GDK_DEVICE_WINPOINTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE_WINPOINTER, GdkDeviceWinpointerClass))
typedef struct _GdkDeviceWinpointer GdkDeviceWinpointer;
typedef struct _GdkDeviceWinpointerClass GdkDeviceWinpointerClass;
struct _GdkDeviceWinpointer
{
GdkDevice parent_instance;
HANDLE device_handle;
UINT32 start_cursor_id;
UINT32 end_cursor_id;
int origin_x;
int origin_y;
double scale_x;
double scale_y;
GdkModifierType last_button_mask;
GdkDeviceTool *tool_pen;
GdkDeviceTool *tool_eraser;
};
struct _GdkDeviceWinpointerClass
{
GdkDeviceClass parent_class;
};
GType gdk_device_winpointer_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __GDK_DEVICE_WINPOINTER_H__ */
+1 -1
View File
@@ -88,7 +88,7 @@ gdk_device_wintab_query_state (GdkDevice *device,
hwnd = NULL;
}
_gdk_win32_get_cursor_pos (&point);
GetCursorPos (&point);
if (hwnd)
ScreenToClient (hwnd, &point);
+21 -64
View File
@@ -29,9 +29,7 @@
#include "gdkdevice-win32.h"
#include "gdkdevice-virtual.h"
#include "gdkdevice-wintab.h"
#include "gdkinput-winpointer.h"
#include "gdkdisplayprivate.h"
#include "gdkdisplay-win32.h"
#include "gdkseatdefaultprivate.h"
#define WINTAB32_DLL "Wintab32.dll"
@@ -373,6 +371,9 @@ wintab_init_check (GdkDeviceManagerWin32 *device_manager)
wintab_contexts = NULL;
if (_gdk_input_ignore_wintab)
return;
n = GetSystemDirectory (&dummy, 0);
if (n <= 0)
@@ -683,13 +684,10 @@ wintab_default_display_notify_cb (GdkDisplayManager *display_manager)
static void
gdk_device_manager_win32_constructed (GObject *object)
{
GdkWin32Display *display_win32;
GdkDeviceManagerWin32 *device_manager;
GdkSeat *seat;
const char *api_preference = NULL;
gboolean have_api_preference = TRUE;
display_win32 = GDK_WIN32_DISPLAY (_gdk_display);
GdkDisplayManager *display_manager = NULL;
GdkDisplay *default_display = NULL;
device_manager = GDK_DEVICE_MANAGER_WIN32 (object);
device_manager->core_pointer =
@@ -730,59 +728,18 @@ gdk_device_manager_win32_constructed (GObject *object)
gdk_seat_default_add_physical_device (GDK_SEAT_DEFAULT (seat), device_manager->system_keyboard);
g_object_unref (seat);
_gdk_device_manager = device_manager;
/* Only call Wintab init stuff after the default display
* is globally known and accessible through the display manager
* singleton. Approach lifted from gtkmodules.c.
*/
display_manager = gdk_display_manager_get ();
g_assert (display_manager != NULL);
default_display = gdk_display_manager_get_default_display (display_manager);
g_assert (default_display == NULL);
api_preference = g_getenv ("GDK_WIN32_TABLET_INPUT_API");
if (g_strcmp0 (api_preference, "none") == 0)
{
display_win32->tablet_input_api = GDK_WIN32_TABLET_INPUT_API_NONE;
}
else if (g_strcmp0 (api_preference, "wintab") == 0)
{
display_win32->tablet_input_api = GDK_WIN32_TABLET_INPUT_API_WINTAB;
}
else if (g_strcmp0 (api_preference, "winpointer") == 0)
{
display_win32->tablet_input_api = GDK_WIN32_TABLET_INPUT_API_WINPOINTER;
}
else
{
/* No user preference, default to WinPointer. If unsuccessful,
* try to initialize other API's in sequence until one succeeds.
*/
display_win32->tablet_input_api = GDK_WIN32_TABLET_INPUT_API_WINPOINTER;
have_api_preference = FALSE;
}
if (display_win32->tablet_input_api == GDK_WIN32_TABLET_INPUT_API_WINPOINTER)
{
gboolean init_successful = gdk_winpointer_initialize ();
if (!init_successful && !have_api_preference)
{
/* Try Wintab */
display_win32->tablet_input_api = GDK_WIN32_TABLET_INPUT_API_WINTAB;
}
}
if (display_win32->tablet_input_api == GDK_WIN32_TABLET_INPUT_API_WINTAB)
{
GdkDisplayManager *display_manager = NULL;
GdkDisplay *default_display = NULL;
/* Only call Wintab init stuff after the default display
* is globally known and accessible through the display manager
* singleton. Approach lifted from gtkmodules.c.
*/
display_manager = gdk_display_manager_get ();
g_assert (display_manager != NULL);
default_display = gdk_display_manager_get_default_display (display_manager);
g_assert (default_display == NULL);
g_signal_connect (display_manager, "notify::default-display",
G_CALLBACK (wintab_default_display_notify_cb),
NULL);
}
g_signal_connect (display_manager, "notify::default-display",
G_CALLBACK (wintab_default_display_notify_cb),
NULL);
}
static void
@@ -795,7 +752,7 @@ gdk_device_manager_win32_class_init (GdkDeviceManagerWin32Class *klass)
}
void
_gdk_wintab_set_tablet_active (void)
_gdk_input_set_tablet_active (void)
{
GList *tmp_list;
HCTX *hctx;
@@ -806,7 +763,7 @@ _gdk_wintab_set_tablet_active (void)
if (!wintab_contexts)
return; /* No tablet devices found, or Wintab not initialized yet */
GDK_NOTE (INPUT, g_print ("_gdk_wintab_set_tablet_active: "
GDK_NOTE (INPUT, g_print ("_gdk_input_set_tablet_active: "
"Bringing Wintab contexts to the top of the overlap order\n"));
tmp_list = wintab_contexts;
@@ -909,7 +866,7 @@ gdk_device_manager_find_wintab_device (GdkDeviceManagerWin32 *device_manager,
}
GdkEvent *
gdk_wintab_make_event (GdkDisplay *display,
gdk_input_other_event (GdkDisplay *display,
MSG *msg,
GdkSurface *window)
{
@@ -937,7 +894,7 @@ gdk_wintab_make_event (GdkDisplay *display,
if (window != wintab_window)
{
g_warning ("gdk_wintab_make_event: not wintab_window?");
g_warning ("gdk_input_other_event: not wintab_window?");
return NULL;
}
@@ -948,7 +905,7 @@ gdk_wintab_make_event (GdkDisplay *display,
g_object_ref (window);
GDK_NOTE (EVENTS_OR_INPUT,
g_print ("gdk_wintab_make_event: window=%p %+g%+g\n",
g_print ("gdk_input_other_event: window=%p %+g%+g\n",
window ? GDK_SURFACE_HWND (window) : NULL, x, y));
if (msg->message == WT_PACKET || msg->message == WT_CSRCHANGE)
+2 -4
View File
@@ -40,8 +40,6 @@ struct _GdkDeviceManagerWin32
/* Fake physical devices */
GdkDevice *system_pointer;
GdkDevice *system_keyboard;
GList *winpointer_devices;
GList *wintab_devices;
/* Bumped up every time a wintab device enters the proximity
@@ -58,8 +56,8 @@ struct _GdkDeviceManagerWin32Class
GType gdk_device_manager_win32_get_type (void) G_GNUC_CONST;
void _gdk_wintab_set_tablet_active (void);
GdkEvent * gdk_wintab_make_event (GdkDisplay *display,
void _gdk_input_set_tablet_active (void);
GdkEvent * gdk_input_other_event (GdkDisplay *display,
MSG *msg,
GdkSurface *window);
+2
View File
@@ -18,6 +18,7 @@
#include "config.h"
#define _WIN32_WINNT 0x0600
#define VK_USE_PLATFORM_WIN32_KHR
#include "gdk.h"
@@ -534,6 +535,7 @@ _gdk_win32_display_open (const char *display_name)
_gdk_win32_lang_notification_init ();
_gdk_drag_init ();
_gdk_drop_init ();
_gdk_display->clipboard = gdk_win32_clipboard_new (_gdk_display);
_gdk_display->primary_clipboard = gdk_clipboard_new (_gdk_display);
+1 -9
View File
@@ -99,12 +99,6 @@ typedef struct _GdkWin32User32DPIFuncs
funcADACE areDACEqual;
} GdkWin32User32DPIFuncs;
typedef enum {
GDK_WIN32_TABLET_INPUT_API_NONE,
GDK_WIN32_TABLET_INPUT_API_WINTAB,
GDK_WIN32_TABLET_INPUT_API_WINPOINTER
} GdkWin32TabletInputAPI;
/* Detect running architecture */
typedef BOOL (WINAPI *funcIsWow64Process2) (HANDLE, USHORT *, USHORT *);
typedef struct _GdkWin32KernelCPUFuncs
@@ -165,9 +159,7 @@ struct _GdkWin32Display
GdkWin32ShcoreFuncs shcore_funcs;
GdkWin32User32DPIFuncs user32_dpi_funcs;
GdkWin32TabletInputAPI tablet_input_api;
/* Cursor Items (GdkCursor->GdkWin32HCursor) */
GHashTable *cursors;
/* The cursor that is used by current grab (if any) */
+353 -56
View File
@@ -158,6 +158,9 @@
* drag window) in response to this, as all the functions
* that GDK could perform here are already handled by the
* OS driving the DnD process via DoDragDrop() call.
* The LOCAL protocol, on the other hand, does a lot,
* similar to what X11 backend does with XDND - it sends
* GDK_DRAG_LEAVE and GDK_DRAG_ENTER, emits GDK_DRAG_MOTION.
*
* GDK_BUTTON_RELEASE checks the
* released button - if it's the button that was used to
@@ -178,7 +181,11 @@
* the OS notifies the process about these things happening.
* For X11 backend that is done in Xdnd event filters,
* for W32 backend this is done in IDropSource/IDropTarget
* object methods for the OLE2 protocol.
* object methods for the OLE2 protocol, whereas for the
* LOCAL protocol these events are emitted only by GDK itself
* (with the exception of WM_DROPFILES message, which causes
* GDK to create a drop context and then immediately finish
* the drag, providing the list of files it got from the message).
*
*/
@@ -480,6 +487,17 @@ process_dnd_queue (gboolean timed,
return FALSE;
}
void
_gdk_win32_local_drag_drop_response (GdkDrag *drag,
GdkDragAction action)
{
GDK_NOTE (DND, g_print ("_gdk_win32_local_drag_drop_response: 0x%p\n",
drag));
g_signal_emit_by_name (drag, "dnd-finished");
gdk_drag_drop_done (drag, action != 0);
}
static gboolean
do_drag_drop_response (gpointer user_data)
{
@@ -696,6 +714,16 @@ _gdk_win32_dnd_thread_main (gpointer data)
return NULL;
}
/* For the LOCAL protocol */
typedef enum {
GDK_DRAG_STATUS_DRAG,
GDK_DRAG_STATUS_MOTION_WAIT,
GDK_DRAG_STATUS_ACTION_WAIT,
GDK_DRAG_STATUS_DROP
} GdkDragStatus;
static gboolean use_ole2_dnd = TRUE;
static gboolean drag_context_grab (GdkDrag *drag);
G_DEFINE_TYPE (GdkWin32Drag, gdk_win32_drag, GDK_TYPE_DRAG)
@@ -763,7 +791,8 @@ gdk_drag_new (GdkDisplay *display,
GdkSurface *surface,
GdkContentProvider *content,
GdkDragAction actions,
GdkDevice *device)
GdkDevice *device,
GdkDragProtocol protocol)
{
GdkWin32Drag *drag_win32;
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
@@ -783,6 +812,8 @@ gdk_drag_new (GdkDisplay *display,
else
drag_win32->scale = gdk_win32_display_get_monitor_scale_factor (display_win32, NULL, NULL);
drag_win32->protocol = protocol;
return drag;
}
@@ -1050,6 +1081,21 @@ maybe_emit_action_changed (GdkWin32Drag *drag_win32,
}
}
void
_gdk_win32_local_drag_give_feedback (GdkDrag *drag,
GdkDragAction actions)
{
GdkWin32Drag *drag_win32 = GDK_WIN32_DRAG (drag);
if (drag_win32->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
drag_win32->drag_status = GDK_DRAG_STATUS_DRAG;
GDK_NOTE (DND, g_print ("_gdk_win32_local_drag_give_feedback: 0x%p\n",
drag));
maybe_emit_action_changed (drag_win32, actions);
}
static gboolean
give_feedback (gpointer user_data)
{
@@ -1624,20 +1670,30 @@ enum_formats_new (GArray *formats)
void
_gdk_drag_init (void)
{
HRESULT hr;
CoInitializeEx (NULL, COINIT_APARTMENTTHREADED);
hr = OleInitialize (NULL);
if (g_strcmp0 (getenv ("GDK_WIN32_OLE2_DND"), "0") == 0)
use_ole2_dnd = FALSE;
if (! SUCCEEDED (hr))
g_error ("OleInitialize failed");
if (use_ole2_dnd)
{
HRESULT hr;
hr = OleInitialize (NULL);
if (! SUCCEEDED (hr))
g_error ("OleInitialize failed");
}
}
void
_gdk_win32_dnd_exit (void)
{
OleUninitialize ();
if (use_ole2_dnd)
{
OleUninitialize ();
}
CoUninitialize ();
}
@@ -1667,9 +1723,6 @@ _gdk_win32_surface_drag_begin (GdkSurface *surface,
GdkWin32Clipdrop *clipdrop = _gdk_win32_clipdrop_get ();
double px, py;
int x_root, y_root;
GdkWin32DnDThreadDoDragDrop *ddd;
source_drag_context *source_ctx;
data_object *data_obj;
g_return_val_if_fail (surface != NULL, NULL);
@@ -1677,7 +1730,8 @@ _gdk_win32_surface_drag_begin (GdkSurface *surface,
surface,
content,
actions,
device);
device,
use_ole2_dnd ? GDK_DRAG_PROTO_OLE2 : GDK_DRAG_PROTO_LOCAL);
drag_win32 = GDK_WIN32_DRAG (drag);
GDK_NOTE (DND, g_print ("_gdk_win32_surface_drag_begin\n"));
@@ -1701,35 +1755,121 @@ _gdk_win32_surface_drag_begin (GdkSurface *surface,
return FALSE;
}
ddd = g_new0 (GdkWin32DnDThreadDoDragDrop, 1);
if (drag_win32->protocol == GDK_DRAG_PROTO_OLE2)
{
GdkWin32DnDThreadDoDragDrop *ddd = g_new0 (GdkWin32DnDThreadDoDragDrop, 1);
source_drag_context *source_ctx;
data_object *data_obj;
source_ctx = source_context_new (drag, gdk_drag_get_formats (drag));
data_obj = data_object_new (drag);
source_ctx = source_context_new (drag, gdk_drag_get_formats (drag));
data_obj = data_object_new (drag);
ddd->base.item_type = GDK_WIN32_DND_THREAD_QUEUE_ITEM_DO_DRAG_DROP;
ddd->base.opaque_context = drag_win32;
ddd->src_context = source_ctx;
ddd->src_object = data_obj;
ddd->allowed_drop_effects = 0;
if (actions & GDK_ACTION_COPY)
ddd->allowed_drop_effects |= DROPEFFECT_COPY;
if (actions & GDK_ACTION_MOVE)
ddd->allowed_drop_effects |= DROPEFFECT_MOVE;
if (actions & GDK_ACTION_LINK)
ddd->allowed_drop_effects |= DROPEFFECT_LINK;
ddd->base.item_type = GDK_WIN32_DND_THREAD_QUEUE_ITEM_DO_DRAG_DROP;
ddd->base.opaque_context = drag_win32;
ddd->src_context = source_ctx;
ddd->src_object = data_obj;
ddd->allowed_drop_effects = 0;
if (actions & GDK_ACTION_COPY)
ddd->allowed_drop_effects |= DROPEFFECT_COPY;
if (actions & GDK_ACTION_MOVE)
ddd->allowed_drop_effects |= DROPEFFECT_MOVE;
if (actions & GDK_ACTION_LINK)
ddd->allowed_drop_effects |= DROPEFFECT_LINK;
g_hash_table_replace (clipdrop->active_source_drags, g_object_ref (drag), ddd);
increment_dnd_queue_counter ();
g_async_queue_push (clipdrop->dnd_queue, ddd);
API_CALL (PostThreadMessage, (clipdrop->dnd_thread_id, thread_wakeup_message, 0, 0));
g_hash_table_replace (clipdrop->active_source_drags, g_object_ref (drag), ddd);
increment_dnd_queue_counter ();
g_async_queue_push (clipdrop->dnd_queue, ddd);
API_CALL (PostThreadMessage, (clipdrop->dnd_thread_id, thread_wakeup_message, 0, 0));
drag_win32->util_data.state = GDK_WIN32_DND_PENDING;
drag_win32->util_data.state = GDK_WIN32_DND_PENDING;
}
move_drag_surface (drag, x_root, y_root);
return drag;
}
/* TODO: remove this?
* window finder is only used by our gdk_drag_update() to
* find the window at drag coordinates - which is
* something IDropSourceNotify already gives us.
* Unless, of course, we keep the LOCAL protocol around.
*/
typedef struct {
int x;
int y;
HWND ignore;
HWND result;
} find_window_enum_arg;
static BOOL CALLBACK
find_window_enum_proc (HWND hwnd,
LPARAM lparam)
{
RECT rect;
POINT tl, br;
find_window_enum_arg *a = (find_window_enum_arg *) lparam;
if (hwnd == a->ignore)
return TRUE;
if (!IsWindowVisible (hwnd))
return TRUE;
tl.x = tl.y = 0;
ClientToScreen (hwnd, &tl);
GetClientRect (hwnd, &rect);
br.x = rect.right;
br.y = rect.bottom;
ClientToScreen (hwnd, &br);
if (a->x >= tl.x && a->y >= tl.y && a->x < br.x && a->y < br.y)
{
a->result = hwnd;
return FALSE;
}
else
return TRUE;
}
/* Finds the HWND under cursor. Local DnD protocol
* uses this function, since local protocol is implemented
* entirely in GDK and cannot rely on the OS to notify
* drop targets about drags that move over them.
*/
static HWND
gdk_win32_drag_find_window (GdkDrag *drag,
GdkSurface *drag_surface,
int x_root,
int y_root)
{
GdkWin32Drag *drag_win32 = GDK_WIN32_DRAG (drag);
find_window_enum_arg a;
g_assert (_win32_main_thread == NULL ||
_win32_main_thread == g_thread_self ());
a.x = x_root * drag_win32->scale - _gdk_offset_x;
a.y = y_root * drag_win32->scale - _gdk_offset_y;
a.ignore = drag_surface ? GDK_SURFACE_HWND (drag_surface) : NULL;
a.result = INVALID_HANDLE_VALUE;
GDK_NOTE (DND,
g_print ("gdk_win32_drag_find_window: %p %+d%+d\n",
(drag_surface ? GDK_SURFACE_HWND (drag_surface) : NULL),
a.x, a.y));
EnumWindows (find_window_enum_proc, (LPARAM) &a);
GDK_NOTE (DND,
g_print ("gdk_win32_drag_find_window: %p %+d%+d: %p\n",
(drag_surface ? GDK_SURFACE_HWND (drag_surface) : NULL),
x_root, y_root,
a.result));
return a.result;
}
static DWORD
manufacture_keystate_from_GMT (GdkModifierType state)
{
@@ -1751,6 +1891,100 @@ manufacture_keystate_from_GMT (GdkModifierType state)
return key_state;
}
/* This only works if dest_window our window and the DnD operation
* is currently local to the application.
*/
static GdkDrop *
_gdk_win32_get_drop_for_dest_window (HWND dest_window)
{
GdkSurface *drop_surface = gdk_win32_handle_table_lookup (dest_window);
GdkDrop *result = NULL;
if (drop_surface)
result = _gdk_win32_get_drop_for_dest_surface (drop_surface);
return result;
}
static gboolean
gdk_win32_local_drag_motion (GdkDrag *drag,
HWND dest_window,
int x_root,
int y_root,
GdkDragAction possible_actions,
DWORD key_state,
guint32 time_)
{
GdkWin32Drag *drag_win32;
GdkDrop *drop;
GdkDragAction actions;
g_assert (_win32_main_thread == NULL ||
_win32_main_thread == g_thread_self ());
g_return_val_if_fail (drag != NULL, FALSE);
drag_win32 = GDK_WIN32_DRAG (drag);
drop = _gdk_win32_get_drop_for_dest_window (drag_win32->dest_window);
actions = gdk_drag_get_actions (drag);
GDK_NOTE (DND, g_print ("gdk_win32_local_drag_motion: @ %+d:%+d possible=%s\n"
" dest=%p (current %p) drop=%p drag=%p:{actions=%s,action=%s}\n",
x_root, y_root,
_gdk_win32_drag_action_to_string (possible_actions),
dest_window, drag_win32->dest_window, drop, drag,
_gdk_win32_drag_action_to_string (actions),
_gdk_win32_drag_action_to_string (gdk_drag_get_selected_action (drag))));
if (drag_win32->dest_window != dest_window)
{
/* Send a leave to the last destination */
if (drop)
_gdk_win32_local_drop_target_dragleave (drop, time_);
drag_win32->dest_window = dest_window;
drag_win32->drag_status = GDK_DRAG_STATUS_DRAG;
_gdk_win32_local_drop_target_dragenter (drag,
gdk_win32_handle_table_lookup (dest_window),
x_root,
y_root,
key_state,
time_,
&actions);
drop = _gdk_win32_get_drop_for_dest_window (drag_win32->dest_window);
maybe_emit_action_changed (drag_win32, actions);
}
/* Send a drag-motion event */
drag_win32->util_data.last_x = x_root;
drag_win32->util_data.last_y = y_root;
if (drop != NULL &&
drag_win32->drag_status == GDK_DRAG_STATUS_DRAG &&
_gdk_win32_local_drop_target_will_emit_motion (drop, x_root, y_root, key_state))
{
actions = gdk_drag_get_actions (drag);
drag_win32->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
_gdk_win32_local_drop_target_dragover (drop, drag, x_root, y_root, key_state, time_, &actions);
maybe_emit_action_changed (drag_win32, actions);
}
GDK_NOTE (DND, g_print (" returning %s\n"
" drag=%p:{actions=%s,action=%s}\n",
(drop != NULL && drag_win32->drag_status == GDK_DRAG_STATUS_DRAG) ? "TRUE" : "FALSE",
drag,
_gdk_win32_drag_action_to_string (gdk_drag_get_actions (drag)),
_gdk_win32_drag_action_to_string (gdk_drag_get_selected_action (drag))));
return (drop != NULL && drag_win32->drag_status == GDK_DRAG_STATUS_DRAG);
}
static void
send_source_state_update (GdkWin32Clipdrop *clipdrop,
GdkWin32Drag *drag_win32,
@@ -1771,7 +2005,6 @@ gdk_win32_drag_drop (GdkDrag *drag,
{
GdkWin32Drag *drag_win32 = GDK_WIN32_DRAG (drag);
GdkWin32Clipdrop *clipdrop = _gdk_win32_clipdrop_get ();
gpointer ddd;
g_assert (_win32_main_thread == NULL ||
_win32_main_thread == g_thread_self ());
@@ -1780,12 +2013,29 @@ gdk_win32_drag_drop (GdkDrag *drag,
GDK_NOTE (DND, g_print ("gdk_win32_drag_drop\n"));
ddd = g_hash_table_lookup (clipdrop->active_source_drags, drag);
if (drag_win32->protocol == GDK_DRAG_PROTO_LOCAL)
{
GdkDrop *drop = _gdk_win32_get_drop_for_dest_window (drag_win32->dest_window);
drag_win32->util_data.state = GDK_WIN32_DND_DROPPED;
if (drop)
{
GdkDragAction actions;
if (ddd)
send_source_state_update (clipdrop, drag_win32, ddd);
actions = gdk_drag_get_actions (drag);
_gdk_win32_local_drop_target_drop (drop, drag, time_, &actions);
maybe_emit_action_changed (drag_win32, actions);
_gdk_win32_local_drag_drop_response (drag, actions);
}
}
else if (drag_win32->protocol == GDK_DRAG_PROTO_OLE2)
{
gpointer ddd = g_hash_table_lookup (clipdrop->active_source_drags, drag);
drag_win32->util_data.state = GDK_WIN32_DND_DROPPED;
if (ddd)
send_source_state_update (clipdrop, drag_win32, ddd);
}
}
static void
@@ -1875,8 +2125,6 @@ gdk_win32_drag_drop_done (GdkDrag *drag,
{
GdkWin32Drag *drag_win32 = GDK_WIN32_DRAG (drag);
GdkDragAnim *anim;
GdkWin32Clipdrop *clipdrop;
gpointer ddd;
/*
cairo_surface_t *win_surface;
cairo_surface_t *surface;
@@ -1891,16 +2139,23 @@ gdk_win32_drag_drop_done (GdkDrag *drag,
/* FIXME: This is temporary, until the code is fixed to ensure that
* gdk_drag_finish () is called by GTK.
*/
clipdrop = _gdk_win32_clipdrop_get ();
ddd = g_hash_table_lookup (clipdrop->active_source_drags, drag);
if (drag_win32->protocol == GDK_DRAG_PROTO_OLE2)
{
GdkWin32Clipdrop *clipdrop = _gdk_win32_clipdrop_get ();
gpointer ddd = g_hash_table_lookup (clipdrop->active_source_drags, drag);
if (success)
drag_win32->util_data.state = GDK_WIN32_DND_DROPPED;
else
drag_win32->util_data.state = GDK_WIN32_DND_NONE;
if (success)
drag_win32->util_data.state = GDK_WIN32_DND_DROPPED;
else
drag_win32->util_data.state = GDK_WIN32_DND_NONE;
if (ddd)
send_source_state_update (clipdrop, drag_win32, ddd);
if (ddd)
send_source_state_update (clipdrop, drag_win32, ddd);
}
else if (drag_win32->protocol == GDK_DRAG_PROTO_LOCAL)
{
}
drag_win32->handle_events = FALSE;
@@ -2026,6 +2281,14 @@ gdk_win32_drag_cancel (GdkDrag *drag,
drag,
reason_str));
if (drag_win32->protocol == GDK_DRAG_PROTO_LOCAL)
{
GdkDrop *drop = _gdk_win32_get_drop_for_dest_window (drag_win32->dest_window);
if (drop)
_gdk_win32_local_drop_target_dragleave (drop, GDK_CURRENT_TIME);
drop = NULL;
}
gdk_drag_set_cursor (drag, NULL);
drag_context_ungrab (drag);
gdk_drag_drop_done (drag, FALSE);
@@ -2047,6 +2310,28 @@ gdk_win32_drag_drop_performed (GdkDrag *drag,
#define BIG_STEP 20
#define SMALL_STEP 1
static void
gdk_local_drag_update (GdkDrag *drag,
double x_root,
double y_root,
DWORD grfKeyState,
guint32 evtime)
{
GdkWin32Drag *drag_win32 = GDK_WIN32_DRAG (drag);
HWND dest_window;
g_assert (_win32_main_thread == NULL ||
_win32_main_thread == g_thread_self ());
dest_window = gdk_win32_drag_find_window (drag,
drag_win32->drag_surface,
x_root, y_root);
gdk_win32_local_drag_motion (drag, dest_window, x_root, y_root,
gdk_drag_get_actions (drag),
grfKeyState, evtime);
}
static gboolean
gdk_dnd_handle_motion_event (GdkDrag *drag,
GdkEvent *event)
@@ -2056,7 +2341,6 @@ gdk_dnd_handle_motion_event (GdkDrag *drag,
DWORD key_state;
double x, y;
double x_root, y_root;
GdkWin32Clipdrop *clipdrop;
GDK_NOTE (DND, g_print ("gdk_dnd_handle_motion_event: 0x%p\n", drag));
@@ -2071,18 +2355,26 @@ gdk_dnd_handle_motion_event (GdkDrag *drag,
key_state = manufacture_keystate_from_GMT (state);
clipdrop = _gdk_win32_clipdrop_get ();
if (drag_win32->protocol == GDK_DRAG_PROTO_LOCAL)
{
gdk_local_drag_update (drag, x_root, y_root, key_state,
gdk_event_get_time (event));
}
else if (drag_win32->protocol == GDK_DRAG_PROTO_OLE2)
{
GdkWin32Clipdrop *clipdrop = _gdk_win32_clipdrop_get ();
GDK_NOTE (DND, g_print ("Post WM_MOUSEMOVE keystate=%lu\n", key_state));
GDK_NOTE (DND, g_print ("Post WM_MOUSEMOVE keystate=%lu\n", key_state));
drag_win32->util_data.last_x = x_root;
drag_win32->util_data.last_y = y_root;
drag_win32->util_data.last_x = x_root;
drag_win32->util_data.last_y = y_root;
API_CALL (PostThreadMessage, (clipdrop->dnd_thread_id,
WM_MOUSEMOVE,
key_state,
MAKELPARAM (x * drag_win32->scale,
y * drag_win32->scale)));
API_CALL (PostThreadMessage, (clipdrop->dnd_thread_id,
WM_MOUSEMOVE,
key_state,
MAKELPARAM (x * drag_win32->scale,
y * drag_win32->scale)));
}
return TRUE;
}
@@ -2164,6 +2456,11 @@ gdk_dnd_handle_key_event (GdkDrag *drag,
if (drag_win32->drag_surface)
move_drag_surface (drag, drag_win32->util_data.last_x, drag_win32->util_data.last_y);
if (drag_win32->protocol == GDK_DRAG_PROTO_LOCAL)
gdk_local_drag_update (drag, drag_win32->util_data.last_x, drag_win32->util_data.last_y,
manufacture_keystate_from_GMT (state),
gdk_event_get_time (event));
return TRUE;
}
+211 -21
View File
@@ -140,6 +140,9 @@ struct _drop_target_context
IDataObject *data_object;
};
/* TRUE to use OLE2 protocol, FALSE to use local protocol */
static gboolean use_ole2_dnd = TRUE;
static void
gdk_win32_drop_init (GdkWin32Drop *drop)
{
@@ -193,6 +196,28 @@ gdk_drop_new (GdkDisplay *display,
return GDK_DROP (drop_win32);
}
/* Gets the GdkDrop that corresponds to a particular GdkSurface.
* Will be NULL for surfaces that are not registered as drop targets,
* or for surfaces that are currently not under the drag cursor.
* This function is only used for local DnD, where we do have
* a real GdkSurface that corresponds to the HWND under cursor.
*/
GdkDrop *
_gdk_win32_get_drop_for_dest_surface (GdkSurface *dest)
{
GdkWin32Surface *impl;
if (dest == NULL)
return NULL;
impl = GDK_WIN32_SURFACE (dest);
if (impl->drop_target != NULL)
return impl->drop_target->drop;
return impl->drop;
}
#define PRINT_GUID(guid) \
g_print ("%.08lx-%.04x-%.04x-%.02x%.02x-%.02x%.02x%.02x%.02x%.02x%.02x", \
@@ -426,6 +451,51 @@ set_source_actions_helper (GdkDrop *drop,
return actions;
}
void
_gdk_win32_local_drop_target_dragenter (GdkDrag *drag,
GdkSurface *dest_surface,
int x_root,
int y_root,
DWORD grfKeyState,
guint32 time_,
GdkDragAction *actions)
{
GdkDrop *drop;
GdkWin32Drop *drop_win32;
GdkDisplay *display;
GdkDragAction source_actions;
GdkWin32Surface *impl = GDK_WIN32_SURFACE (dest_surface);
GDK_NOTE (DND, g_print ("_gdk_win32_local_drop_target_dragenter %p @ %d : %d"
" for dest window 0x%p"
". actions = %s\n",
drag, x_root, y_root,
dest_surface,
_gdk_win32_drag_action_to_string (*actions)));
display = gdk_surface_get_display (dest_surface);
drop = gdk_drop_new (display,
gdk_seat_get_pointer (gdk_display_get_default_seat (display)),
drag,
gdk_drag_get_formats (drag),
dest_surface,
GDK_DRAG_PROTO_LOCAL);
drop_win32 = GDK_WIN32_DROP (drop);
impl->drop = drop;
source_actions = set_source_actions_helper (drop, *actions, grfKeyState);
gdk_drop_emit_enter_event (drop, TRUE, x_root, y_root, time_);
drop_win32->last_key_state = grfKeyState;
drop_win32->last_x = x_root;
drop_win32->last_y = y_root;
*actions = filter_actions (drop_win32->actions, source_actions);
GDK_NOTE (DND, g_print ("_gdk_win32_local_drop_target_dragenter returns with actions %s\n",
_gdk_win32_drag_action_to_string (*actions)));
}
/* The pdwEffect here initially points
* to a DWORD that contains the value of dwOKEffects argument in DoDragDrop,
* i.e. the drag action that the drag source deems acceptable.
@@ -505,6 +575,55 @@ idroptarget_dragenter (LPDROPTARGET This,
return S_OK;
}
gboolean
_gdk_win32_local_drop_target_will_emit_motion (GdkDrop *drop,
int x_root,
int y_root,
DWORD grfKeyState)
{
GdkWin32Drop *drop_win32 = GDK_WIN32_DROP (drop);
if (x_root != drop_win32->last_x ||
y_root != drop_win32->last_y ||
grfKeyState != drop_win32->last_key_state)
return TRUE;
return FALSE;
}
void
_gdk_win32_local_drop_target_dragover (GdkDrop *drop,
GdkDrag *drag,
int x_root,
int y_root,
DWORD grfKeyState,
guint32 time_,
GdkDragAction *actions)
{
GdkWin32Drop *drop_win32 = GDK_WIN32_DROP (drop);
GdkDragAction source_actions;
source_actions = set_source_actions_helper (drop, *actions, grfKeyState);
GDK_NOTE (DND, g_print ("_gdk_win32_local_drop_target_dragover %p @ %d : %d"
", actions = %s\n",
drop, x_root, y_root,
_gdk_win32_drag_action_to_string (*actions)));
if (_gdk_win32_local_drop_target_will_emit_motion (drop, x_root, y_root, grfKeyState))
{
gdk_drop_emit_motion_event (drop, TRUE, x_root, y_root, time_);
drop_win32->last_key_state = grfKeyState;
drop_win32->last_x = x_root;
drop_win32->last_y = y_root;
}
*actions = filter_actions (drop_win32->actions, source_actions);
GDK_NOTE (DND, g_print ("_gdk_win32_local_drop_target_dragover returns with actions %s\n",
_gdk_win32_drag_action_to_string (*actions)));
}
/* NOTE: This method is called continuously, even if nothing is
* happening, as long as the drag operation is in progress and
* the cursor is above our window.
@@ -562,6 +681,18 @@ idroptarget_dragover (LPDROPTARGET This,
return S_OK;
}
void
_gdk_win32_local_drop_target_dragleave (GdkDrop *drop,
guint32 time_)
{
GdkWin32Surface *impl = GDK_WIN32_SURFACE (gdk_drop_get_surface (drop));
GDK_NOTE (DND, g_print ("_gdk_win32_local_drop_target_dragleave %p\n", drop));
gdk_drop_emit_leave_event (drop, TRUE, time_);
g_clear_object (&impl->drop);
}
static HRESULT STDMETHODCALLTYPE
idroptarget_dragleave (LPDROPTARGET This)
{
@@ -577,6 +708,35 @@ idroptarget_dragleave (LPDROPTARGET This)
return S_OK;
}
void
_gdk_win32_local_drop_target_drop (GdkDrop *drop,
GdkDrag *drag,
guint32 time_,
GdkDragAction *actions)
{
GdkWin32Drop *drop_win32 = GDK_WIN32_DROP (drop);
GDK_NOTE (DND, g_print ("_gdk_win32_local_drop_target_drop %p ", drop));
set_source_actions_helper (drop,
*actions,
drop_win32->last_key_state);
drop_win32->drop_finished = FALSE;
gdk_drop_emit_drop_event (drop, TRUE, drop_win32->last_x, drop_win32->last_y, time_);
while (!drop_win32->drop_finished)
g_main_context_iteration (NULL, FALSE);
/* Notify local source of the DnD result
* Special case:
* drop_win32->actions is guaranteed to contain 1 action after gdk_drop_finish ()
*/
*actions = drop_win32->actions;
GDK_NOTE (DND, g_print ("drop with action %s\n", _gdk_win32_drag_action_to_string (*actions)));
}
static HRESULT STDMETHODCALLTYPE
idroptarget_drop (LPDROPTARGET This,
LPDATAOBJECT pDataObj,
@@ -918,6 +1078,14 @@ gdk_win32_drop_status (GdkDrop *drop,
_gdk_win32_drag_action_to_string (preferred)));
drop_win32->actions = actions;
if (drop_win32->protocol == GDK_DRAG_PROTO_OLE2)
return;
drag = gdk_drop_get_drag (drop);
if (drag != NULL)
_gdk_win32_local_drag_give_feedback (drag, actions);
}
static void
@@ -933,6 +1101,9 @@ gdk_win32_drop_finish (GdkDrop *drop,
drop_win32->actions = action;
drop_win32->drop_finished = TRUE;
if (drop_win32->protocol == GDK_DRAG_PROTO_OLE2)
return;
}
#if 0
@@ -965,7 +1136,6 @@ _gdk_win32_surface_register_dnd (GdkSurface *window)
{
drop_target_context *ctx;
HRESULT hr;
GdkWin32Surface *impl;
g_return_if_fail (window != NULL);
@@ -976,30 +1146,43 @@ _gdk_win32_surface_register_dnd (GdkSurface *window)
GDK_NOTE (DND, g_print ("gdk_win32_surface_register_dnd: %p\n", GDK_SURFACE_HWND (window)));
impl = GDK_WIN32_SURFACE (window);
/* Return if window is already setup for DND. */
if (impl->drop_target != NULL)
return;
ctx = target_context_new (window);
hr = CoLockObjectExternal ((IUnknown *) &ctx->idt, TRUE, FALSE);
if (!SUCCEEDED (hr))
OTHER_API_FAILED ("CoLockObjectExternal");
if (!use_ole2_dnd)
{
/* We always claim to accept dropped files, but in fact we might not,
* of course. This function is called in such a way that it cannot know
* whether the window (widget) in question actually accepts files
* (in gtk, data of type text/uri-list) or not.
*/
gdk_win32_display_add_filter (GDK_WIN32_DISPLAY (gdk_display_get_default ()), gdk_dropfiles_filter, NULL);
DragAcceptFiles (GDK_SURFACE_HWND (window), TRUE);
}
else
{
hr = RegisterDragDrop (GDK_SURFACE_HWND (window), &ctx->idt);
if (hr == DRAGDROP_E_ALREADYREGISTERED)
{
g_print ("DRAGDROP_E_ALREADYREGISTERED\n");
CoLockObjectExternal ((IUnknown *) &ctx->idt, FALSE, FALSE);
}
else if (!SUCCEEDED (hr))
OTHER_API_FAILED ("RegisterDragDrop");
GdkWin32Surface *impl = GDK_WIN32_SURFACE (window);
/* Return if window is already setup for DND. */
if (impl->drop_target != NULL)
return;
ctx = target_context_new (window);
hr = CoLockObjectExternal ((IUnknown *) &ctx->idt, TRUE, FALSE);
if (!SUCCEEDED (hr))
OTHER_API_FAILED ("CoLockObjectExternal");
else
{
impl->drop_target = ctx;
hr = RegisterDragDrop (GDK_SURFACE_HWND (window), &ctx->idt);
if (hr == DRAGDROP_E_ALREADYREGISTERED)
{
g_print ("DRAGDROP_E_ALREADYREGISTERED\n");
CoLockObjectExternal ((IUnknown *) &ctx->idt, FALSE, FALSE);
}
else if (!SUCCEEDED (hr))
OTHER_API_FAILED ("RegisterDragDrop");
else
{
impl->drop_target = ctx;
}
}
}
}
@@ -1235,3 +1418,10 @@ gdk_win32_drop_class_init (GdkWin32DropClass *klass)
drop_class->read_async = gdk_win32_drop_read_async;
drop_class->read_finish = gdk_win32_drop_read_finish;
}
void
_gdk_drop_init (void)
{
if (g_strcmp0 (getenv ("GDK_WIN32_OLE2_DND"), "0") == 0)
use_ole2_dnd = FALSE;
}
+59 -345
View File
@@ -55,9 +55,7 @@
#include "gdkdevicemanager-win32.h"
#include "gdkdisplay-win32.h"
#include "gdkdeviceprivate.h"
#include "gdkdevice-virtual.h"
#include "gdkdevice-wintab.h"
#include "gdkinput-winpointer.h"
#include "gdkwin32dnd.h"
#include "gdkwin32dnd-private.h"
#include "gdkdisplay-win32.h"
@@ -73,9 +71,8 @@
#endif
#include <objbase.h>
#include <imm.h>
#include <tchar.h>
#include <tpcshrd.h>
#define GDK_MOD2_MASK (1 << 4)
@@ -166,10 +163,6 @@ static int both_shift_pressed[2]; /* to store keycodes for shift keys */
static HHOOK keyboard_hook = NULL;
static UINT aerosnap_message;
static gboolean pen_touch_input;
static POINT pen_touch_cursor_position;
static LONG last_digitizer_time;
static void
track_mouse_event (DWORD dwFlags,
HWND hwnd)
@@ -204,18 +197,6 @@ _gdk_win32_get_next_tick (gulong suggested_tick)
return cur_tick = suggested_tick;
}
BOOL
_gdk_win32_get_cursor_pos (LPPOINT lpPoint)
{
if (pen_touch_input)
{
*lpPoint = pen_touch_cursor_position;
return TRUE;
}
else
return GetCursorPos (lpPoint);
}
static void
generate_focus_event (GdkDeviceManagerWin32 *device_manager,
GdkSurface *window,
@@ -1055,12 +1036,11 @@ do_show_window (GdkSurface *window, gboolean hide_window)
static void
send_crossing_event (GdkDisplay *display,
GdkDevice *physical_device,
GdkSurface *window,
GdkSurface *window,
GdkEventType type,
GdkCrossingMode mode,
GdkNotifyType notify_type,
GdkSurface *subwindow,
GdkSurface *subwindow,
POINT *screen_pt,
GdkModifierType mask,
guint32 time_)
@@ -1087,18 +1067,16 @@ send_crossing_event (GdkDisplay *display,
pt = *screen_pt;
ScreenToClient (GDK_SURFACE_HWND (window), &pt);
_gdk_device_virtual_set_active (_gdk_device_manager->core_pointer, physical_device);
event = gdk_crossing_event_new (type,
window,
device_manager->core_pointer,
time_,
_gdk_win32_get_next_tick (time_),
mask,
pt.x / impl->surface_scale,
pt.y / impl->surface_scale,
mode,
notify_type);
_gdk_win32_append_event (event);
}
@@ -1141,9 +1119,8 @@ find_common_ancestor (GdkSurface *win1,
void
synthesize_crossing_events (GdkDisplay *display,
GdkDevice *physical_device,
GdkSurface *src,
GdkSurface *dest,
GdkSurface *src,
GdkSurface *dest,
GdkCrossingMode mode,
POINT *screen_pt,
GdkModifierType mask,
@@ -1176,7 +1153,6 @@ synthesize_crossing_events (GdkDisplay *display,
else
notify_type = GDK_NOTIFY_ANCESTOR;
send_crossing_event (display,
physical_device,
a, GDK_LEAVE_NOTIFY,
mode,
notify_type,
@@ -1196,7 +1172,6 @@ synthesize_crossing_events (GdkDisplay *display,
while (win != c && win != NULL)
{
send_crossing_event (display,
physical_device,
win, GDK_LEAVE_NOTIFY,
mode,
notify_type,
@@ -1239,7 +1214,6 @@ synthesize_crossing_events (GdkDisplay *display,
next = b;
send_crossing_event (display,
physical_device,
win, GDK_ENTER_NOTIFY,
mode,
notify_type,
@@ -1259,7 +1233,6 @@ synthesize_crossing_events (GdkDisplay *display,
notify_type = GDK_NOTIFY_INFERIOR;
send_crossing_event (display,
physical_device,
b, GDK_ENTER_NOTIFY,
mode,
notify_type,
@@ -1269,26 +1242,6 @@ synthesize_crossing_events (GdkDisplay *display,
}
}
static void
make_crossing_event (GdkDevice *physical_device,
GdkSurface *surface,
POINT *screen_pt,
guint32 time_)
{
GDK_NOTE (EVENTS, g_print (" mouse_window %p -> %p",
mouse_window ? GDK_SURFACE_HWND (mouse_window) : NULL,
surface ? GDK_SURFACE_HWND (surface) : NULL));
synthesize_crossing_events (_gdk_display,
physical_device,
mouse_window, surface,
GDK_CROSSING_NORMAL,
screen_pt,
0, /* TODO: Set right mask */
time_,
FALSE);
g_set_object (&mouse_window, surface);
}
/* Acquires actual client area size of the underlying native window.
* Rectangle is in GDK screen coordinates (_gdk_offset_* is added).
* Returns FALSE if configure events should be inhibited,
@@ -1573,9 +1526,6 @@ generate_button_event (GdkEventType type,
current_x = (gint16) GET_X_LPARAM (msg->lParam) / impl->surface_scale;
current_y = (gint16) GET_Y_LPARAM (msg->lParam) / impl->surface_scale;
_gdk_device_virtual_set_active (_gdk_device_manager->core_pointer,
_gdk_device_manager->system_pointer);
event = gdk_button_event_new (type,
window,
device_manager->core_pointer,
@@ -1807,8 +1757,6 @@ gdk_event_translate (MSG *msg,
GdkDeviceGrabInfo *pointer_grab = NULL;
GdkSurface *grab_window = NULL;
crossing_cb_t crossing_cb = NULL;
int button;
char buf[256];
@@ -2231,8 +2179,6 @@ gdk_event_translate (MSG *msg,
g_print (" (%d,%d)",
GET_X_LPARAM (msg->lParam), GET_Y_LPARAM (msg->lParam)));
pen_touch_input = FALSE;
g_set_object (&window, find_window_for_mouse_event (window, msg));
/* TODO_CSW?: there used to some synthesize and propagate */
if (GDK_SURFACE_DESTROYED (window))
@@ -2275,8 +2221,6 @@ gdk_event_translate (MSG *msg,
g_print (" (%d,%d)",
GET_X_LPARAM (msg->lParam), GET_Y_LPARAM (msg->lParam)));
pen_touch_input = FALSE;
g_set_object (&window, find_window_for_mouse_event (window, msg));
if (pointer_grab == NULL && implicit_grab_surface != NULL)
@@ -2301,12 +2245,11 @@ gdk_event_translate (MSG *msg,
}
synthesize_crossing_events (display,
_gdk_device_manager->system_pointer,
implicit_grab_surface, new_window,
GDK_CROSSING_UNGRAB,
&msg->pt,
0, /* TODO: Set right mask */
_gdk_win32_get_next_tick (msg->time),
msg->time,
FALSE);
g_set_object (&implicit_grab_surface, NULL);
g_set_object (&mouse_window, new_window);
@@ -2335,23 +2278,6 @@ gdk_event_translate (MSG *msg,
(gpointer) msg->wParam,
GET_X_LPARAM (msg->lParam), GET_Y_LPARAM (msg->lParam)));
/* Even if we handle WM_POINTER messages, synthetic WM_MOUSEMOVE messages
* are still sent occasionally by the OS, e.g. when a surface is hidden
* or shown. Discard spurious WM_MOUSEMOVE messages while handling pen or
* touch input
*
* See the article
* "Why do I get spurious WM_MOUSEMOVE messages?" by Raymond Chen:
* https://devblogs.microsoft.com/oldnewthing/20031001-00/?p=42343
*
*/
if (win32_display->tablet_input_api == GDK_WIN32_TABLET_INPUT_API_WINPOINTER &&
( (msg->time - last_digitizer_time) < 200 ||
-(msg->time - last_digitizer_time) < 200 ))
break;
pen_touch_input = FALSE;
new_window = window;
if (pointer_grab != NULL)
@@ -2379,16 +2305,15 @@ gdk_event_translate (MSG *msg,
if (mouse_window != new_window)
{
GDK_NOTE (EVENTS, g_print (" mouse_window %p -> %p",
GDK_NOTE (EVENTS, g_print (" mouse_sinwod %p -> %p",
mouse_window ? GDK_SURFACE_HWND (mouse_window) : NULL,
new_window ? GDK_SURFACE_HWND (new_window) : NULL));
synthesize_crossing_events (display,
_gdk_device_manager->system_pointer,
mouse_window, new_window,
GDK_CROSSING_NORMAL,
&msg->pt,
0, /* TODO: Set right mask */
_gdk_win32_get_next_tick (msg->time),
msg->time,
FALSE);
g_set_object (&mouse_window, new_window);
mouse_window_ignored_leave = NULL;
@@ -2426,9 +2351,6 @@ gdk_event_translate (MSG *msg,
current_x = (gint16) GET_X_LPARAM (msg->lParam) / impl->surface_scale;
current_y = (gint16) GET_Y_LPARAM (msg->lParam) / impl->surface_scale;
_gdk_device_virtual_set_active (_gdk_device_manager->core_pointer,
_gdk_device_manager->system_pointer);
event = gdk_motion_event_new (window,
device_manager_win32->core_pointer,
NULL,
@@ -2454,8 +2376,6 @@ gdk_event_translate (MSG *msg,
GDK_NOTE (EVENTS, g_print (" %d (%ld,%ld)",
HIWORD (msg->wParam), msg->pt.x, msg->pt.y));
pen_touch_input = FALSE;
new_window = NULL;
hwnd = WindowFromPoint (msg->pt);
ignore_leave = FALSE;
@@ -2481,12 +2401,11 @@ gdk_event_translate (MSG *msg,
if (!ignore_leave)
synthesize_crossing_events (display,
_gdk_device_manager->system_pointer,
mouse_window, new_window,
GDK_CROSSING_NORMAL,
&msg->pt,
0, /* TODO: Set right mask */
_gdk_win32_get_next_tick (msg->time),
msg->time,
FALSE);
g_set_object (&mouse_window, new_window);
mouse_window_ignored_leave = ignore_leave ? new_window : NULL;
@@ -2495,213 +2414,6 @@ gdk_event_translate (MSG *msg,
return_val = TRUE;
break;
case WM_POINTERDOWN:
if (win32_display->tablet_input_api != GDK_WIN32_TABLET_INPUT_API_WINPOINTER ||
gdk_winpointer_should_forward_message (msg))
{
return_val = FALSE;
break;
}
if (IS_POINTER_PRIMARY_WPARAM (msg->wParam))
{
current_root_x = pen_touch_cursor_position.x = GET_X_LPARAM (msg->lParam);
current_root_y = pen_touch_cursor_position.y = GET_Y_LPARAM (msg->lParam);
pen_touch_input = TRUE;
last_digitizer_time = msg->time;
}
if (pointer_grab != NULL &&
!pointer_grab->implicit &&
!pointer_grab->owner_events)
g_set_object (&window, pointer_grab->surface);
if (IS_POINTER_PRIMARY_WPARAM (msg->wParam) && mouse_window != window)
crossing_cb = make_crossing_event;
gdk_winpointer_input_events (window, crossing_cb, msg);
*ret_valp = 0;
return_val = TRUE;
break;
case WM_POINTERUP:
if (win32_display->tablet_input_api != GDK_WIN32_TABLET_INPUT_API_WINPOINTER ||
gdk_winpointer_should_forward_message (msg))
{
return_val = FALSE;
break;
}
if (IS_POINTER_PRIMARY_WPARAM (msg->wParam))
{
current_root_x = pen_touch_cursor_position.x = GET_X_LPARAM (msg->lParam);
current_root_y = pen_touch_cursor_position.y = GET_Y_LPARAM (msg->lParam);
pen_touch_input = TRUE;
last_digitizer_time = msg->time;
}
if (pointer_grab != NULL &&
!pointer_grab->implicit &&
!pointer_grab->owner_events)
g_set_object (&window, pointer_grab->surface);
gdk_winpointer_input_events (window, NULL, msg);
impl = GDK_WIN32_SURFACE (window);
if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE)
{
gdk_win32_surface_end_move_resize_drag (window);
}
*ret_valp = 0;
return_val = TRUE;
break;
case WM_POINTERUPDATE:
if (win32_display->tablet_input_api != GDK_WIN32_TABLET_INPUT_API_WINPOINTER ||
gdk_winpointer_should_forward_message (msg))
{
return_val = FALSE;
break;
}
if (IS_POINTER_PRIMARY_WPARAM (msg->wParam))
{
current_root_x = pen_touch_cursor_position.x = GET_X_LPARAM (msg->lParam);
current_root_y = pen_touch_cursor_position.y = GET_Y_LPARAM (msg->lParam);
pen_touch_input = TRUE;
last_digitizer_time = msg->time;
}
if (pointer_grab != NULL &&
!pointer_grab->implicit &&
!pointer_grab->owner_events)
g_set_object (&window, pointer_grab->surface);
if (IS_POINTER_PRIMARY_WPARAM (msg->wParam) && mouse_window != window)
crossing_cb = make_crossing_event;
impl = GDK_WIN32_SURFACE (window);
if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE)
{
gdk_win32_surface_do_move_resize_drag (window, current_root_x, current_root_y);
}
else
{
gdk_winpointer_input_events (window, crossing_cb, msg);
}
*ret_valp = 0;
return_val = TRUE;
break;
case WM_NCPOINTERUPDATE:
if (win32_display->tablet_input_api != GDK_WIN32_TABLET_INPUT_API_WINPOINTER ||
gdk_winpointer_should_forward_message (msg))
{
return_val = FALSE;
break;
}
if (IS_POINTER_PRIMARY_WPARAM (msg->wParam))
{
current_root_x = pen_touch_cursor_position.x = GET_X_LPARAM (msg->lParam);
current_root_y = pen_touch_cursor_position.y = GET_Y_LPARAM (msg->lParam);
pen_touch_input = TRUE;
last_digitizer_time = msg->time;
}
if (IS_POINTER_PRIMARY_WPARAM (msg->wParam) &&
!IS_POINTER_INCONTACT_WPARAM (msg->wParam) &&
mouse_window != NULL)
{
GdkDevice *event_device = NULL;
guint32 event_time = 0;
if (gdk_winpointer_get_message_info (msg, &event_device, &event_time))
{
make_crossing_event(event_device,
NULL,
&pen_touch_cursor_position,
event_time);
}
}
return_val = FALSE; /* forward to DefWindowProc */
break;
case WM_POINTERENTER:
if (win32_display->tablet_input_api != GDK_WIN32_TABLET_INPUT_API_WINPOINTER ||
gdk_winpointer_should_forward_message (msg))
{
return_val = FALSE;
break;
}
if (IS_POINTER_PRIMARY_WPARAM (msg->wParam))
{
current_root_x = pen_touch_cursor_position.x = GET_X_LPARAM (msg->lParam);
current_root_y = pen_touch_cursor_position.y = GET_Y_LPARAM (msg->lParam);
pen_touch_input = TRUE;
last_digitizer_time = msg->time;
}
if (pointer_grab != NULL &&
!pointer_grab->implicit &&
!pointer_grab->owner_events)
g_set_object (&window, pointer_grab->surface);
if (IS_POINTER_NEW_WPARAM (msg->wParam))
{
gdk_winpointer_input_events (window, NULL, msg);
}
*ret_valp = 0;
return_val = TRUE;
break;
case WM_POINTERLEAVE:
if (win32_display->tablet_input_api != GDK_WIN32_TABLET_INPUT_API_WINPOINTER ||
gdk_winpointer_should_forward_message (msg))
{
return_val = FALSE;
break;
}
if (IS_POINTER_PRIMARY_WPARAM (msg->wParam))
{
current_root_x = pen_touch_cursor_position.x = GET_X_LPARAM (msg->lParam);
current_root_y = pen_touch_cursor_position.y = GET_Y_LPARAM (msg->lParam);
pen_touch_input = TRUE;
last_digitizer_time = msg->time;
}
if (!IS_POINTER_INRANGE_WPARAM (msg->wParam))
{
gdk_winpointer_input_events (window, NULL, msg);
}
else if (IS_POINTER_PRIMARY_WPARAM (msg->wParam) && mouse_window != NULL)
{
GdkDevice *event_device = NULL;
guint32 event_time = 0;
if (gdk_winpointer_get_message_info (msg, &event_device, &event_time))
{
make_crossing_event(event_device,
NULL,
&pen_touch_cursor_position,
event_time);
}
}
gdk_winpointer_interaction_ended (msg);
*ret_valp = 0;
return_val = TRUE;
break;
case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL:
GDK_NOTE (EVENTS, g_print (" %d", (short) HIWORD (msg->wParam)));
@@ -2764,9 +2476,6 @@ gdk_event_translate (MSG *msg,
*/
delta_y *= -1.0;
_gdk_device_virtual_set_active (_gdk_device_manager->core_pointer,
_gdk_device_manager->system_pointer);
event = gdk_scroll_event_new (window,
device_manager_win32->core_pointer,
NULL,
@@ -2800,6 +2509,44 @@ gdk_event_translate (MSG *msg,
return_val = TRUE;
break;
case WM_HSCROLL:
/* Just print more debugging information, don't actually handle it. */
GDK_NOTE (EVENTS,
(g_print (" %s",
(LOWORD (msg->wParam) == SB_ENDSCROLL ? "ENDSCROLL" :
(LOWORD (msg->wParam) == SB_LEFT ? "LEFT" :
(LOWORD (msg->wParam) == SB_RIGHT ? "RIGHT" :
(LOWORD (msg->wParam) == SB_LINELEFT ? "LINELEFT" :
(LOWORD (msg->wParam) == SB_LINERIGHT ? "LINERIGHT" :
(LOWORD (msg->wParam) == SB_PAGELEFT ? "PAGELEFT" :
(LOWORD (msg->wParam) == SB_PAGERIGHT ? "PAGERIGHT" :
(LOWORD (msg->wParam) == SB_THUMBPOSITION ? "THUMBPOSITION" :
(LOWORD (msg->wParam) == SB_THUMBTRACK ? "THUMBTRACK" :
"???")))))))))),
(LOWORD (msg->wParam) == SB_THUMBPOSITION ||
LOWORD (msg->wParam) == SB_THUMBTRACK) ?
(g_print (" %d", HIWORD (msg->wParam)), 0) : 0));
break;
case WM_VSCROLL:
/* Just print more debugging information, don't actually handle it. */
GDK_NOTE (EVENTS,
(g_print (" %s",
(LOWORD (msg->wParam) == SB_ENDSCROLL ? "ENDSCROLL" :
(LOWORD (msg->wParam) == SB_BOTTOM ? "BOTTOM" :
(LOWORD (msg->wParam) == SB_TOP ? "TOP" :
(LOWORD (msg->wParam) == SB_LINEDOWN ? "LINDOWN" :
(LOWORD (msg->wParam) == SB_LINEUP ? "LINEUP" :
(LOWORD (msg->wParam) == SB_PAGEDOWN ? "PAGEDOWN" :
(LOWORD (msg->wParam) == SB_PAGEUP ? "PAGEUP" :
(LOWORD (msg->wParam) == SB_THUMBPOSITION ? "THUMBPOSITION" :
(LOWORD (msg->wParam) == SB_THUMBTRACK ? "THUMBTRACK" :
"???")))))))))),
(LOWORD (msg->wParam) == SB_THUMBPOSITION ||
LOWORD (msg->wParam) == SB_THUMBTRACK) ?
(g_print (" %d", HIWORD (msg->wParam)), 0) : 0));
break;
case WM_MOUSEACTIVATE:
{
if (GDK_IS_DRAG_SURFACE (window))
@@ -2817,16 +2564,6 @@ gdk_event_translate (MSG *msg,
break;
case WM_POINTERACTIVATE:
if (GDK_IS_DRAG_SURFACE (window) ||
_gdk_modal_blocked (window))
{
*ret_valp = PA_NOACTIVATE;
return_val = TRUE;
}
break;
case WM_KILLFOCUS:
if (keyboard_grab != NULL &&
!GDK_SURFACE_DESTROYED (keyboard_grab->surface) &&
@@ -3218,13 +2955,6 @@ gdk_event_translate (MSG *msg,
*ret_valp = 0;
break;
case WM_DESTROY:
if (win32_display->tablet_input_api == GDK_WIN32_TABLET_INPUT_API_WINPOINTER)
gdk_winpointer_finalize_surface (window);
return_val = FALSE;
break;
case WM_NCDESTROY:
if ((pointer_grab != NULL && pointer_grab->surface == window) ||
(keyboard_grab && keyboard_grab->surface == window))
@@ -3305,15 +3035,12 @@ gdk_event_translate (MSG *msg,
{
gdk_synthesize_surface_state (window, 0, GDK_TOPLEVEL_STATE_FOCUSED);
if (win32_display->tablet_input_api == GDK_WIN32_TABLET_INPUT_API_WINTAB)
{
/* Bring any tablet contexts to the top of the overlap order when
* one of our windows is activated.
* NOTE: It doesn't seem to work well if it is done in WM_ACTIVATEAPP
* instead
*/
_gdk_wintab_set_tablet_active ();
}
/* Bring any tablet contexts to the top of the overlap order when
* one of our windows is activated.
* NOTE: It doesn't seem to work well if it is done in WM_ACTIVATEAPP
* instead
*/
_gdk_input_set_tablet_active ();
}
break;
@@ -3330,16 +3057,6 @@ gdk_event_translate (MSG *msg,
GET_Y_LPARAM (msg->lParam), ret_valp);
break;
case WM_TABLET_QUERYSYSTEMGESTURESTATUS:
*ret_valp = TABLET_DISABLE_PRESSANDHOLD |
TABLET_DISABLE_PENTAPFEEDBACK |
TABLET_DISABLE_PENBARRELFEEDBACK |
TABLET_DISABLE_FLICKS |
TABLET_DISABLE_FLICKFALLBACKKEYS;
return_val = TRUE;
break;
/* Handle WINTAB events here, as we know that the device manager will
* use the fixed WT_DEFBASE as lcMsgBase, and we thus can use the
* constants as case labels.
@@ -3362,14 +3079,11 @@ gdk_event_translate (MSG *msg,
/* Fall through */
wintab:
if (win32_display->tablet_input_api == GDK_WIN32_TABLET_INPUT_API_WINTAB)
event = gdk_input_other_event (display, msg, window);
if (event)
{
event = gdk_wintab_make_event (display, msg, window);
if (event)
{
_gdk_win32_append_event (event);
gdk_event_unref (event);
}
_gdk_win32_append_event (event);
gdk_event_unref (event);
}
break;
+1 -1
View File
@@ -277,7 +277,7 @@ gdk_win32_display_init_egl (GdkDisplay *display,
display_win32->egl_disp = egl_disp;
display_win32->egl_version = epoxy_egl_version (egl_disp);
eglBindAPI (EGL_OPENGL_ES_API);
eglBindAPI(EGL_OPENGL_ES_API);
display_win32->hasEglSurfacelessContext =
epoxy_has_egl_extension (egl_disp, "EGL_KHR_surfaceless_context");
-19
View File
@@ -278,9 +278,6 @@ gdk_win32_display_init_wgl (GdkDisplay *display,
if (best_idx == 0 ||
!wglMakeCurrent (hdc, display_win32->dummy_context_wgl.hglrc))
{
if (display_win32->dummy_context_wgl.hglrc != NULL)
wglDeleteContext (display_win32->dummy_context_wgl.hglrc);
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
_("No GL implementation is available"));
@@ -291,22 +288,6 @@ gdk_win32_display_init_wgl (GdkDisplay *display,
display_win32->wgl_pixel_format = best_idx;
display_win32->gl_version = epoxy_gl_version ();
/* We must have OpenGL/WGL 2.0 or later, or have the GL_ARB_shader_objects extension */
if (display_win32->gl_version < 20)
{
if (!epoxy_has_gl_extension ("GL_ARB_shader_objects"))
{
wglMakeCurrent (NULL, NULL);
wglDeleteContext (display_win32->dummy_context_wgl.hglrc);
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
_("No GL implementation is available"));
return FALSE;
}
}
display_win32->hasWglARBCreateContext =
epoxy_has_wgl_extension (hdc, "WGL_ARB_create_context");
display_win32->hasWglEXTSwapControl =
+3
View File
@@ -42,6 +42,9 @@ HKL _gdk_input_locale;
gboolean _gdk_input_locale_is_ime = FALSE;
UINT _gdk_input_codepage;
int _gdk_input_ignore_wintab = FALSE;
int _gdk_max_colors = 0;
GdkWin32ModalOpKind _modal_operation_in_progress = GDK_WIN32_MODAL_OP_NONE;
HWND _modal_move_resize_window = NULL;
File diff suppressed because it is too large Load Diff
-43
View File
@@ -1,43 +0,0 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2021 the GTK team
*
* 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/>.
*/
#ifndef __GDK_INPUT_WINPOINTER_H__
#define __GDK_INPUT_WINPOINTER_H__
#include "winpointer.h"
gboolean gdk_winpointer_initialize (void);
void gdk_winpointer_initialize_surface (GdkSurface *surface);
void gdk_winpointer_finalize_surface (GdkSurface *surface);
typedef void
(*crossing_cb_t)(GdkDevice *physical_device,
GdkSurface *surface,
POINT *screen_pt,
guint32 time_);
gboolean gdk_winpointer_should_forward_message (MSG *msg);
void gdk_winpointer_input_events (GdkSurface *surface,
crossing_cb_t crossing_cb,
MSG *msg);
gboolean gdk_winpointer_get_message_info (MSG *msg,
GdkDevice **device,
guint32 *time_);
void gdk_winpointer_interaction_ended (MSG *msg);
#endif /* __GDK_INPUT_WINPOINTER_H__ */
+6
View File
@@ -54,6 +54,11 @@ _gdk_win32_surfaceing_init (void)
{
char buf[10];
if (getenv ("GDK_IGNORE_WINTAB") != NULL)
_gdk_input_ignore_wintab = TRUE;
else if (getenv ("GDK_USE_WINTAB") != NULL)
_gdk_input_ignore_wintab = FALSE;
if (gdk_synchronize)
GdiSetBatchLimit (1);
@@ -248,6 +253,7 @@ _gdk_win32_drag_protocol_to_string (GdkDragProtocol protocol)
CASE (NONE);
CASE (WIN32_DROPFILES);
CASE (OLE2);
CASE (LOCAL);
#undef CASE
default: return static_printf ("illegal_%d", protocol);
}
+16
View File
@@ -15,6 +15,22 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined (_WIN32_WINNT) && WIN32_WINNT < 0x0601
# undef _WIN32_WINNT
# define _WIN32_WINNT 0x0601
# ifdef WINVER
# undef WINVER
# endif
# define WINVER _WIN32_WINNT
#elif !defined (_WIN32_WINNT)
# define _WIN32_WINNT 0x0601
# ifdef WINVER
# undef WINVER
# endif
# define WINVER _WIN32_WINNT
#endif
#include "config.h"
#include "gdkprivate-win32.h"
+16 -4
View File
@@ -25,6 +25,15 @@
#ifndef __GDK_PRIVATE_WIN32_H__
#define __GDK_PRIVATE_WIN32_H__
#ifndef WINVER
/* Vista or newer */
#define WINVER 0x0600
#endif
#ifndef _WIN32_WINNT
#define _WIN32_WINNT WINVER
#endif
#include <gdk/gdkcursorprivate.h>
#include <gdk/win32/gdksurface-win32.h>
#include <gdk/win32/gdkwin32display.h>
@@ -145,14 +154,13 @@ typedef enum
GDK_DRAG_PROTO_NONE = 0,
GDK_DRAG_PROTO_WIN32_DROPFILES,
GDK_DRAG_PROTO_OLE2,
GDK_DRAG_PROTO_LOCAL,
} GdkDragProtocol;
GType _gdk_gc_win32_get_type (void);
gulong _gdk_win32_get_next_tick (gulong suggested_tick);
BOOL _gdk_win32_get_cursor_pos (LPPOINT lpPoint);
void _gdk_surface_init_position (GdkSurface *window);
void _gdk_surface_move_resize_child (GdkSurface *window,
int x,
@@ -242,8 +250,6 @@ void _gdk_other_api_failed (const char *where,
#define WIN32_GDI_FAILED(api) WIN32_API_FAILED (api)
#define OTHER_API_FAILED(api) _gdk_other_api_failed (G_STRLOC, api)
#define WIN32_API_FAILED_LOG_ONCE(api) G_STMT_START { static gboolean logged = 0; if (!logged) { _gdk_win32_api_failed (G_STRLOC , api); logged = 1; }} G_STMT_END
/* These two macros call a GDI or other Win32 API and if the return
* value is zero or NULL, print a warning message. The majority of GDI
* calls return zero or NULL on failure. The value of the macros is nonzero
@@ -307,6 +313,11 @@ extern HWND _modal_move_resize_window;
void _gdk_win32_begin_modal_call (GdkWin32ModalOpKind kind);
void _gdk_win32_end_modal_call (GdkWin32ModalOpKind kind);
/* Options */
extern gboolean _gdk_input_ignore_wintab;
extern int _gdk_max_colors;
/* Convert a pixbuf to an HICON (or HCURSOR). Supports alpha under
* Windows XP, thresholds alpha otherwise.
*/
@@ -431,6 +442,7 @@ BOOL WINAPI GtkShowWindow (GdkSurface *window,
/* Initialization */
void _gdk_win32_surfaceing_init (void);
void _gdk_drag_init (void);
void _gdk_drop_init (void);
void _gdk_events_init (GdkDisplay *display);
#endif /* __GDK_PRIVATE_WIN32_H__ */
+2
View File
@@ -17,6 +17,8 @@
#include "config.h"
#define _WIN32_WINNT 0x0600
#include "gdk.h"
#include "gdkprivate-win32.h"
#include "gdkwin32screen.h"
+1 -4
View File
@@ -43,7 +43,6 @@
#include "gdkmonitorprivate.h"
#include "gdkwin32surface.h"
#include "gdkwin32cursor.h"
#include "gdkinput-winpointer.h"
#include "gdkglcontext-win32.h"
#include "gdkdisplay-win32.h"
#include "gdkdevice-win32.h"
@@ -205,6 +204,7 @@ gdk_surface_win32_finalize (GObject *object)
}
_gdk_win32_surface_unregister_dnd (GDK_SURFACE (surface));
g_clear_object (&surface->drop);
g_assert (surface->transient_owner == NULL);
g_assert (surface->transient_children == NULL);
@@ -646,9 +646,6 @@ _gdk_win32_display_create_surface (GdkDisplay *display,
return NULL;
}
if (display_win32->tablet_input_api == GDK_WIN32_TABLET_INPUT_API_WINPOINTER)
gdk_winpointer_initialize_surface (surface);
_gdk_win32_surface_enable_transparency (surface);
_gdk_win32_surface_register_dnd (surface);
+4
View File
@@ -251,6 +251,10 @@ struct _GdkWin32Surface
* For OLE2 protocol only.
*/
drop_target_context *drop_target;
/* Temporarily holds the GdkDrop currently associated with this window.
* For LOCAL protocol only.
*/
GdkDrop *drop;
GdkSurface *transient_owner;
GSList *transient_children;
+32
View File
@@ -93,6 +93,38 @@ struct _GdkWin32DragClass
gpointer _gdk_win32_dnd_thread_main (gpointer data);
GdkDrag *_gdk_win32_find_drag_for_dest_window (HWND dest_window);
GdkDrop *_gdk_win32_get_drop_for_dest_surface (GdkSurface *dest);
gboolean _gdk_win32_local_drop_target_will_emit_motion (GdkDrop *drop,
int x_root,
int y_root,
DWORD grfKeyState);
void _gdk_win32_local_drop_target_dragenter (GdkDrag *drag,
GdkSurface *dest_surface,
int x_root,
int y_root,
DWORD grfKeyState,
guint32 time_,
GdkDragAction *actions);
void _gdk_win32_local_drop_target_dragover (GdkDrop *drop,
GdkDrag *drag,
int x_root,
int y_root,
DWORD grfKeyState,
guint32 time_,
GdkDragAction *actions);
void _gdk_win32_local_drop_target_dragleave (GdkDrop *drop,
guint32 time_);
void _gdk_win32_local_drop_target_drop (GdkDrop *drop,
GdkDrag *drag,
guint32 time_,
GdkDragAction *actions);
void _gdk_win32_local_drag_give_feedback (GdkDrag *drag,
GdkDragAction actions);
void _gdk_win32_local_drag_drop_response (GdkDrag *drag,
GdkDragAction action);
G_END_DECLS
+2 -7
View File
@@ -6,7 +6,6 @@ gdk_win32_sources = files([
'gdkdevicemanager-win32.c',
'gdkdevice-virtual.c',
'gdkdevice-win32.c',
'gdkdevice-winpointer.c',
'gdkdevice-wintab.c',
'gdkdisplay-win32.c',
'gdkdisplaymanager-win32.c',
@@ -17,7 +16,6 @@ gdk_win32_sources = files([
'gdkglcontext-win32-wgl.c',
'gdkglobals-win32.c',
'gdkhdataoutputstream-win32.c',
'gdkinput-winpointer.c',
'gdkkeys-win32.c',
'gdkwin32langnotification.c',
'gdkmain-win32.c',
@@ -53,9 +51,8 @@ if win32_has_egl
gdk_win32_sources += ['gdkglcontext-win32-egl.c']
endif
gdk_win32_deps = [
pangowin32_dep, # FIXME
cc.find_library('hid'),
gdk_win32_deps = [ # FIXME
pangowin32_dep
]
libgdk_win32 = static_library('gdk-win32',
@@ -65,8 +62,6 @@ libgdk_win32 = static_library('gdk-win32',
'-DGTK_COMPILATION',
'-DG_LOG_DOMAIN="Gdk"',
'-DINSIDE_GDK_WIN32',
'-D_WIN32_WINNT=0x0601',
'-DWINVER=0x0601',
] + GDK_WIN32_EGL_CFLAGS,
dependencies: [ gdk_deps, gdk_win32_deps ],
)
-320
View File
@@ -1,320 +0,0 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2021 the GTK team
*
* 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/>.
*/
/* This code is derived from portions provided by the mingw-w64 project
* (mingw-w64.org), originally licensed under the Zope Public License
* (ZPL) version 2.1, with modifications made on May 12, 2021.
* Legal notice of the Zope Public License version 2.1 follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions in source code must retain the accompanying copyright
* notice, this list of conditions, and the following disclaimer.
* 2. Redistributions in binary form must reproduce the accompanying
* copyright notice, this list of conditions, and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* 3. Names of the copyright holders must not be used to endorse or promote
* products derived from this software without prior written permission
* from the copyright holders.
* 4. The right to distribute this software or to use it for any purpose does
* not give you the right to use Servicemarks (sm) or Trademarks (tm) of
* the copyright holders. Use of them is covered by separate agreement
* with the copyright holders.
* 5. If any files are modified, you must cause the modified files to carry
* prominent notices stating that you changed the files and the date of
* any change.
*/
#ifndef POINTER_FLAG_NONE
#include <windows.h>
#include <tchar.h>
#define WM_POINTERDEVICECHANGE 0x238
#define WM_POINTERDEVICEINRANGE 0x239
#define WM_POINTERDEVICEOUTOFRANGE 0x23a
#define WM_NCPOINTERUPDATE 0x0241
#define WM_NCPOINTERDOWN 0x0242
#define WM_NCPOINTERUP 0x0243
#define WM_POINTERUPDATE 0x0245
#define WM_POINTERDOWN 0x0246
#define WM_POINTERUP 0x0247
#define WM_POINTERENTER 0x0249
#define WM_POINTERLEAVE 0x024a
#define WM_POINTERACTIVATE 0x024b
#define WM_POINTERCAPTURECHANGED 0x024c
#define WM_TOUCHHITTESTING 0x024d
#define WM_POINTERWHEEL 0x024e
#define WM_POINTERHWHEEL 0x024f
#define DM_POINTERHITTEST 0x0250
#define WM_POINTERROUTEDTO 0x0251
#define WM_POINTERROUTEDAWAY 0x0252
#define WM_POINTERROUTEDRELEASED 0x0253
#define POINTER_FLAG_NONE 0x00000000
#define POINTER_FLAG_NEW 0x00000001
#define POINTER_FLAG_INRANGE 0x00000002
#define POINTER_FLAG_INCONTACT 0x00000004
#define POINTER_FLAG_FIRSTBUTTON 0x00000010
#define POINTER_FLAG_SECONDBUTTON 0x00000020
#define POINTER_FLAG_THIRDBUTTON 0x00000040
#define POINTER_FLAG_FOURTHBUTTON 0x00000080
#define POINTER_FLAG_FIFTHBUTTON 0x00000100
#define POINTER_FLAG_PRIMARY 0x00002000
#define POINTER_FLAG_CONFIDENCE 0x00004000
#define POINTER_FLAG_CANCELED 0x00008000
#define POINTER_FLAG_DOWN 0x00010000
#define POINTER_FLAG_UPDATE 0x00020000
#define POINTER_FLAG_UP 0x00040000
#define POINTER_FLAG_WHEEL 0x00080000
#define POINTER_FLAG_HWHEEL 0x00100000
#define POINTER_FLAG_CAPTURECHANGED 0x00200000
#define POINTER_FLAG_HASTRANSFORM 0x00400000
#define POINTER_MOD_SHIFT (0x0004)
#define POINTER_MOD_CTRL (0x0008)
#define TOUCH_FLAG_NONE 0x00000000
#define TOUCH_MASK_NONE 0x00000000
#define TOUCH_MASK_CONTACTAREA 0x00000001
#define TOUCH_MASK_ORIENTATION 0x00000002
#define TOUCH_MASK_PRESSURE 0x00000004
#define PEN_FLAG_NONE 0x00000000
#define PEN_FLAG_BARREL 0x00000001
#define PEN_FLAG_INVERTED 0x00000002
#define PEN_FLAG_ERASER 0x00000004
#define PEN_MASK_NONE 0x00000000
#define PEN_MASK_PRESSURE 0x00000001
#define PEN_MASK_ROTATION 0x00000002
#define PEN_MASK_TILT_X 0x00000004
#define PEN_MASK_TILT_Y 0x00000008
#define POINTER_MESSAGE_FLAG_NEW 0x00000001
#define POINTER_MESSAGE_FLAG_INRANGE 0x00000002
#define POINTER_MESSAGE_FLAG_INCONTACT 0x00000004
#define POINTER_MESSAGE_FLAG_FIRSTBUTTON 0x00000010
#define POINTER_MESSAGE_FLAG_SECONDBUTTON 0x00000020
#define POINTER_MESSAGE_FLAG_THIRDBUTTON 0x00000040
#define POINTER_MESSAGE_FLAG_FOURTHBUTTON 0x00000080
#define POINTER_MESSAGE_FLAG_FIFTHBUTTON 0x00000100
#define POINTER_MESSAGE_FLAG_PRIMARY 0x00002000
#define POINTER_MESSAGE_FLAG_CONFIDENCE 0x00004000
#define POINTER_MESSAGE_FLAG_CANCELED 0x00008000
#define GET_POINTERID_WPARAM(wParam) (LOWORD (wParam))
#define IS_POINTER_FLAG_SET_WPARAM(wParam, flag) (((DWORD)HIWORD (wParam) &(flag)) == (flag))
#define IS_POINTER_NEW_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM (wParam, POINTER_MESSAGE_FLAG_NEW)
#define IS_POINTER_INRANGE_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM (wParam, POINTER_MESSAGE_FLAG_INRANGE)
#define IS_POINTER_INCONTACT_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM (wParam, POINTER_MESSAGE_FLAG_INCONTACT)
#define IS_POINTER_FIRSTBUTTON_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM (wParam, POINTER_MESSAGE_FLAG_FIRSTBUTTON)
#define IS_POINTER_SECONDBUTTON_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM (wParam, POINTER_MESSAGE_FLAG_SECONDBUTTON)
#define IS_POINTER_THIRDBUTTON_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM (wParam, POINTER_MESSAGE_FLAG_THIRDBUTTON)
#define IS_POINTER_FOURTHBUTTON_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM (wParam, POINTER_MESSAGE_FLAG_FOURTHBUTTON)
#define IS_POINTER_FIFTHBUTTON_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM (wParam, POINTER_MESSAGE_FLAG_FIFTHBUTTON)
#define IS_POINTER_PRIMARY_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM (wParam, POINTER_MESSAGE_FLAG_PRIMARY)
#define HAS_POINTER_CONFIDENCE_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM (wParam, POINTER_MESSAGE_FLAG_CONFIDENCE)
#define IS_POINTER_CANCELED_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM (wParam, POINTER_MESSAGE_FLAG_CANCELED)
#define PA_ACTIVATE MA_ACTIVATE
#define PA_NOACTIVATE MA_NOACTIVATE
typedef DWORD POINTER_INPUT_TYPE;
typedef UINT32 POINTER_FLAGS;
typedef UINT32 TOUCH_FLAGS;
typedef UINT32 TOUCH_MASK;
typedef UINT32 PEN_FLAGS;
typedef UINT32 PEN_MASK;
enum tagPOINTER_INPUT_TYPE {
PT_POINTER = 0x00000001,
PT_TOUCH = 0x00000002,
PT_PEN = 0x00000003,
PT_MOUSE = 0x00000004,
PT_TOUCHPAD = 0x00000005
};
typedef enum tagFEEDBACK_TYPE {
FEEDBACK_TOUCH_CONTACTVISUALIZATION = 1,
FEEDBACK_PEN_BARRELVISUALIZATION = 2,
FEEDBACK_PEN_TAP = 3,
FEEDBACK_PEN_DOUBLETAP = 4,
FEEDBACK_PEN_PRESSANDHOLD = 5,
FEEDBACK_PEN_RIGHTTAP = 6,
FEEDBACK_TOUCH_TAP = 7,
FEEDBACK_TOUCH_DOUBLETAP = 8,
FEEDBACK_TOUCH_PRESSANDHOLD = 9,
FEEDBACK_TOUCH_RIGHTTAP = 10,
FEEDBACK_GESTURE_PRESSANDTAP = 11,
FEEDBACK_MAX = 0xffffffff
} FEEDBACK_TYPE;
typedef enum tagPOINTER_BUTTON_CHANGE_TYPE {
POINTER_CHANGE_NONE,
POINTER_CHANGE_FIRSTBUTTON_DOWN,
POINTER_CHANGE_FIRSTBUTTON_UP,
POINTER_CHANGE_SECONDBUTTON_DOWN,
POINTER_CHANGE_SECONDBUTTON_UP,
POINTER_CHANGE_THIRDBUTTON_DOWN,
POINTER_CHANGE_THIRDBUTTON_UP,
POINTER_CHANGE_FOURTHBUTTON_DOWN,
POINTER_CHANGE_FOURTHBUTTON_UP,
POINTER_CHANGE_FIFTHBUTTON_DOWN,
POINTER_CHANGE_FIFTHBUTTON_UP,
} POINTER_BUTTON_CHANGE_TYPE;
typedef struct tagPOINTER_INFO {
POINTER_INPUT_TYPE pointerType;
UINT32 pointerId;
UINT32 frameId;
POINTER_FLAGS pointerFlags;
HANDLE sourceDevice;
HWND hwndTarget;
POINT ptPixelLocation;
POINT ptHimetricLocation;
POINT ptPixelLocationRaw;
POINT ptHimetricLocationRaw;
DWORD dwTime;
UINT32 historyCount;
INT32 InputData;
DWORD dwKeyStates;
UINT64 PerformanceCount;
POINTER_BUTTON_CHANGE_TYPE ButtonChangeType;
} POINTER_INFO;
typedef struct tagPOINTER_TOUCH_INFO {
POINTER_INFO pointerInfo;
TOUCH_FLAGS touchFlags;
TOUCH_MASK touchMask;
RECT rcContact;
RECT rcContactRaw;
UINT32 orientation;
UINT32 pressure;
} POINTER_TOUCH_INFO;
typedef struct tagPOINTER_PEN_INFO {
POINTER_INFO pointerInfo;
PEN_FLAGS penFlags;
PEN_MASK penMask;
UINT32 pressure;
UINT32 rotation;
INT32 tiltX;
INT32 tiltY;
} POINTER_PEN_INFO;
typedef enum {
POINTER_FEEDBACK_DEFAULT = 1,
POINTER_FEEDBACK_INDIRECT = 2,
POINTER_FEEDBACK_NONE = 3
} POINTER_FEEDBACK_MODE;
typedef struct tagUSAGE_PROPERTIES {
USHORT level;
USHORT page;
USHORT usage;
INT32 logicalMinimum;
INT32 logicalMaximum;
USHORT unit;
USHORT exponent;
BYTE count;
INT32 physicalMinimum;
INT32 physicalMaximum;
} USAGE_PROPERTIES, *PUSAGE_PROPERTIES;
typedef struct tagPOINTER_TYPE_INFO {
POINTER_INPUT_TYPE type;
union {
POINTER_TOUCH_INFO touchInfo;
POINTER_PEN_INFO penInfo;
} DUMMYUNIONNAME;
} POINTER_TYPE_INFO, *PPOINTER_TYPE_INFO;
#define POINTER_DEVICE_PRODUCT_STRING_MAX 520
#define PDC_ARRIVAL 0x001
#define PDC_REMOVAL 0x002
#define PDC_ORIENTATION_0 0x004
#define PDC_ORIENTATION_90 0x008
#define PDC_ORIENTATION_180 0x010
#define PDC_ORIENTATION_270 0x020
#define PDC_MODE_DEFAULT 0x040
#define PDC_MODE_CENTERED 0x080
#define PDC_MAPPING_CHANGE 0x100
#define PDC_RESOLUTION 0x200
#define PDC_ORIGIN 0x400
#define PDC_MODE_ASPECTRATIOPRESERVED 0x800
typedef enum tagPOINTER_DEVICE_TYPE {
POINTER_DEVICE_TYPE_INTEGRATED_PEN = 0x00000001,
POINTER_DEVICE_TYPE_EXTERNAL_PEN = 0x00000002,
POINTER_DEVICE_TYPE_TOUCH = 0x00000003,
POINTER_DEVICE_TYPE_TOUCH_PAD = 0x00000004,
POINTER_DEVICE_TYPE_MAX = 0xffffffff
} POINTER_DEVICE_TYPE;
typedef struct tagPOINTER_DEVICE_INFO {
DWORD displayOrientation;
HANDLE device;
POINTER_DEVICE_TYPE pointerDeviceType;
HMONITOR monitor;
ULONG startingCursorId;
USHORT maxActiveContacts;
WCHAR productString[POINTER_DEVICE_PRODUCT_STRING_MAX];
} POINTER_DEVICE_INFO;
typedef struct tagPOINTER_DEVICE_PROPERTY {
INT32 logicalMin;
INT32 logicalMax;
INT32 physicalMin;
INT32 physicalMax;
UINT32 unit;
UINT32 unitExponent;
USHORT usagePageId;
USHORT usageId;
} POINTER_DEVICE_PROPERTY;
typedef enum tagPOINTER_DEVICE_CURSOR_TYPE {
POINTER_DEVICE_CURSOR_TYPE_UNKNOWN = 0x00000000,
POINTER_DEVICE_CURSOR_TYPE_TIP = 0x00000001,
POINTER_DEVICE_CURSOR_TYPE_ERASER = 0x00000002,
POINTER_DEVICE_CURSOR_TYPE_MAX = 0xffffffff
} POINTER_DEVICE_CURSOR_TYPE;
typedef struct tagPOINTER_DEVICE_CURSOR_INFO {
UINT32 cursorId;
POINTER_DEVICE_CURSOR_TYPE cursor;
} POINTER_DEVICE_CURSOR_INFO;
#endif /* POINTER_FLAG_NONE */
#if WINVER < 0x0601
typedef struct tagGESTURECONFIG {
DWORD dwID;
DWORD dwWant;
DWORD dwBlock;
} GESTURECONFIG,*PGESTURECONFIG;
#endif /* WINVER < 0x0601 */
#ifndef MICROSOFT_TABLETPENSERVICE_PROPERTY
#define MICROSOFT_TABLETPENSERVICE_PROPERTY _T("MicrosoftTabletPenServiceProperty")
#endif
+5 -2
View File
@@ -204,6 +204,9 @@ static void
gdk_x11_display_init (GdkX11Display *self)
{
self->monitors = g_list_store_new (GDK_TYPE_MONITOR);
self->program_class = g_strdup (g_get_prgname ());
if (self->program_class && self->program_class[0])
self->program_class[0] = g_ascii_toupper (self->program_class[0]);
}
static void
@@ -1037,8 +1040,8 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
if (xevent->type - display_x11->xrandr_event_base == RRScreenChangeNotify ||
xevent->type - display_x11->xrandr_event_base == RRNotify)
{
if (display_x11->screen)
_gdk_x11_screen_size_changed (display_x11->screen, xevent);
if (x11_screen)
_gdk_x11_screen_size_changed (x11_screen, xevent);
}
else
#endif
+1 -4
View File
@@ -1282,10 +1282,7 @@ _gdk_x11_display_create_surface (GdkDisplay *display,
class_hint = XAllocClassHint ();
class_hint->res_name = (char *) g_get_prgname ();
if (display_x11->program_class)
class_hint->res_class = (char *) display_x11->program_class;
else
class_hint->res_class = class_hint->res_name;
class_hint->res_class = (char *) display_x11->program_class;
XSetClassHint (xdisplay, impl->xid, class_hint);
XFree (class_hint);
+3 -3
View File
@@ -89,7 +89,7 @@ get_boolean_default (GdkX11Screen *x11_screen,
char *v;
int i;
if (gdk_display_get_debug_flags (GDK_SCREEN_DISPLAY (x11_screen)) & GDK_DEBUG_DEFAULT_SETTINGS)
if (GDK_DISPLAY_DEBUG_CHECK (GDK_SCREEN_DISPLAY (x11_screen), DEFAULT_SETTINGS))
return FALSE;
v = XGetDefault (dpy, "Xft", option);
@@ -114,7 +114,7 @@ get_double_default (GdkX11Screen *x11_screen,
Display *dpy = GDK_SCREEN_XDISPLAY (x11_screen);
char *v, *e;
if (gdk_display_get_debug_flags (GDK_SCREEN_DISPLAY (x11_screen)) & GDK_DEBUG_DEFAULT_SETTINGS)
if (GDK_DISPLAY_DEBUG_CHECK (GDK_SCREEN_DISPLAY (x11_screen), DEFAULT_SETTINGS))
return FALSE;
v = XGetDefault (dpy, "Xft", option);
@@ -141,7 +141,7 @@ get_integer_default (GdkX11Screen *x11_screen,
Display *dpy = GDK_SCREEN_XDISPLAY (x11_screen);
char *v, *e;
if (gdk_display_get_debug_flags (GDK_SCREEN_DISPLAY (x11_screen)) & GDK_DEBUG_DEFAULT_SETTINGS)
if (GDK_DISPLAY_DEBUG_CHECK (GDK_SCREEN_DISPLAY (x11_screen), DEFAULT_SETTINGS))
return FALSE;
v = XGetDefault (dpy, "Xft", option);
+317
View File
@@ -0,0 +1,317 @@
#pragma once
#define SANITY_CHECKS 0
#define rounded_rect_top_left(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x, \
r->bounds.origin.y, \
r->corner[0].width, r->corner[0].height))
#define rounded_rect_top_right(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x + r->bounds.size.width - r->corner[1].width, \
r->bounds.origin.y, \
r->corner[1].width, r->corner[1].height))
#define rounded_rect_bottom_right(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x + r->bounds.size.width - r->corner[2].width, \
r->bounds.origin.y + r->bounds.size.height - r->corner[2].height, \
r->corner[2].width, r->corner[2].height))
#define rounded_rect_bottom_left(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x, \
r->bounds.origin.y + r->bounds.size.height - r->corner[2].height, \
r->corner[3].width, r->corner[3].height))
#define rounded_rect_corner0(r) rounded_rect_top_left(r)
#define rounded_rect_corner1(r) rounded_rect_top_right(r)
#define rounded_rect_corner2(r) rounded_rect_bottom_right(r)
#define rounded_rect_corner3(r) rounded_rect_bottom_left(r)
#define rounded_rect_corner(r, i) (rounded_rect_corner ##i(r))
#define graphene_size_non_zero(s) (s->width > 0 && s->height > 0)
#define rounded_rect_has_corner(r, i) (r->corner[i].width > 0 && r->corner[i].height > 0)
#define rect_contains_point(r, _x, _y) (_x >= (r)->origin.x && _x <= (r)->origin.x + (r)->size.width && \
_y >= (r)->origin.y && _y <= (r)->origin.y + (r)->size.height)
enum {
NINE_SLICE_TOP_LEFT = 0,
NINE_SLICE_TOP_CENTER = 1,
NINE_SLICE_TOP_RIGHT = 2,
NINE_SLICE_LEFT_CENTER = 3,
NINE_SLICE_CENTER = 4,
NINE_SLICE_RIGHT_CENTER = 5,
NINE_SLICE_BOTTOM_LEFT = 6,
NINE_SLICE_BOTTOM_CENTER = 7,
NINE_SLICE_BOTTOM_RIGHT = 8,
};
#define NINE_SLICE_SIZE 9 /* Hah. */
typedef struct
{
int texture_id;
float x;
float y;
float x2;
float y2;
} TextureRegion;
static inline bool G_GNUC_PURE
slice_is_visible (const cairo_rectangle_int_t *r)
{
return (r->width > 0 && r->height > 0);
}
static inline void
nine_slice_rounded_rect (const GskRoundedRect *rect,
cairo_rectangle_int_t *out_rects)
{
const graphene_point_t *origin = &rect->bounds.origin;
const graphene_size_t *size = &rect->bounds.size;
const int top_height = ceilf (MAX (rect->corner[GSK_CORNER_TOP_LEFT].height,
rect->corner[GSK_CORNER_TOP_RIGHT].height));
const int bottom_height = ceilf (MAX (rect->corner[GSK_CORNER_BOTTOM_LEFT].height,
rect->corner[GSK_CORNER_BOTTOM_RIGHT].height));
const int right_width = ceilf (MAX (rect->corner[GSK_CORNER_TOP_RIGHT].width,
rect->corner[GSK_CORNER_BOTTOM_RIGHT].width));
const int left_width = ceilf (MAX (rect->corner[GSK_CORNER_TOP_LEFT].width,
rect->corner[GSK_CORNER_BOTTOM_LEFT].width));
/* Top left */
out_rects[0] = (cairo_rectangle_int_t) {
origin->x, origin->y,
left_width, top_height,
};
/* Top center */
out_rects[1] = (cairo_rectangle_int_t) {
origin->x + size->width / 2.0 - 0.5, origin->y,
1, top_height,
};
/* Top right */
out_rects[2] = (cairo_rectangle_int_t) {
origin->x + size->width - right_width, origin->y,
right_width, top_height
};
/* Left center */
out_rects[3] = (cairo_rectangle_int_t) {
origin->x, origin->y + size->height / 2,
left_width, 1,
};
/* center */
out_rects[4] = (cairo_rectangle_int_t) {
origin->x + size->width / 2.0 - 0.5,
origin->y + size->height / 2.0 - 0.5,
1, 1
};
/* Right center */
out_rects[5] = (cairo_rectangle_int_t) {
origin->x + size->width - right_width,
origin->y + (size->height / 2.0) - 0.5,
right_width,
1,
};
/* Bottom Left */
out_rects[6] = (cairo_rectangle_int_t) {
origin->x, origin->y + size->height - bottom_height,
left_width, bottom_height,
};
/* Bottom center */
out_rects[7] = (cairo_rectangle_int_t) {
origin->x + (size->width / 2.0) - 0.5,
origin->y + size->height - bottom_height,
1, bottom_height,
};
/* Bottom right */
out_rects[8] = (cairo_rectangle_int_t) {
origin->x + size->width - right_width,
origin->y + size->height - bottom_height,
right_width, bottom_height,
};
#if SANITY_CHECKS
g_assert_cmpfloat (size->width, >=, left_width + right_width);
g_assert_cmpfloat (size->height, >=, top_height + bottom_height);
#endif
}
static inline void
nine_slice_grow (cairo_rectangle_int_t *slices,
const int amount)
{
/* top left */
slices[0].x -= amount;
slices[0].y -= amount;
if (amount > slices[0].width)
slices[0].width += amount * 2;
else
slices[0].width += amount;
if (amount > slices[0].height)
slices[0].height += amount * 2;
else
slices[0].height += amount;
/* Top center */
slices[1].y -= amount;
if (amount > slices[1].height)
slices[1].height += amount * 2;
else
slices[1].height += amount;
/* top right */
slices[2].y -= amount;
if (amount > slices[2].width)
{
slices[2].x -= amount;
slices[2].width += amount * 2;
}
else
{
slices[2].width += amount;
}
if (amount > slices[2].height)
slices[2].height += amount * 2;
else
slices[2].height += amount;
slices[3].x -= amount;
if (amount > slices[3].width)
slices[3].width += amount * 2;
else
slices[3].width += amount;
/* Leave Britney^Wcenter alone */
if (amount > slices[5].width)
{
slices[5].x -= amount;
slices[5].width += amount * 2;
}
else
{
slices[5].width += amount;
}
/* Bottom left */
slices[6].x -= amount;
if (amount > slices[6].width)
{
slices[6].width += amount * 2;
}
else
{
slices[6].width += amount;
}
if (amount > slices[6].height)
{
slices[6].y -= amount;
slices[6].height += amount * 2;
}
else
{
slices[6].height += amount;
}
/* Bottom center */
if (amount > slices[7].height)
{
slices[7].y -= amount;
slices[7].height += amount * 2;
}
else
{
slices[7].height += amount;
}
if (amount > slices[8].width)
{
slices[8].x -= amount;
slices[8].width += amount * 2;
}
else
{
slices[8].width += amount;
}
if (amount > slices[8].height)
{
slices[8].y -= amount;
slices[8].height += amount * 2;
}
else
{
slices[8].height += amount;
}
#if SANITY_CHECKS
{
for (int i = 0; i < 9; i ++)
{
g_assert_cmpint (slices[i].x, >=, 0);
g_assert_cmpint (slices[i].y, >=, 0);
g_assert_cmpint (slices[i].width, >=, 0);
g_assert_cmpint (slices[i].height, >=, 0);
}
/* Rows don't overlap */
for (int i = 0; i < 3; i++)
{
g_assert_cmpint (slices[i * 3 + 0].x + slices[i * 3 + 0].width, <, slices[i * 3 + 1].x);
}
}
#endif
}
static inline void
nine_slice_to_texture_coords (const cairo_rectangle_int_t *slices,
const int texture_width,
const int texture_height,
TextureRegion *out_regions)
{
const float fw = (float)texture_width;
const float fh = (float)texture_height;
int i;
for (i = 0; i < 9; i++)
{
out_regions[i] = (TextureRegion) {
0, /* Texture id */
slices[i].x / fw,
1.0 - ((slices[i].y + slices[i].height) / fh),
(slices[i].x + slices[i].width) / fw,
1.0 - (slices[i].y / fh),
};
}
#if SANITY_CHECKS
{
for (i = 0; i < 9; i++)
{
const TextureRegion *r = &out_regions[i];
g_assert_cmpfloat (r->x, >=, 0);
g_assert_cmpfloat (r->x, <=, 1);
g_assert_cmpfloat (r->y, >=, 0);
g_assert_cmpfloat (r->y, <=, 1);
g_assert_cmpfloat (r->x, <, r->x2);
g_assert_cmpfloat (r->y, <, r->y2);
}
}
#endif
}
+849
View File
@@ -0,0 +1,849 @@
#include "config.h"
#include "gskgldriverprivate.h"
#include "gskdebugprivate.h"
#include "gskprofilerprivate.h"
#include "gdk/gdkglcontextprivate.h"
#include "gdk/gdktextureprivate.h"
#include "gdk/gdkgltextureprivate.h"
#include "gdkmemorytextureprivate.h"
#include <gdk/gdk.h>
#include <epoxy/gl.h>
typedef struct {
GLuint fbo_id;
GLuint depth_stencil_id;
} Fbo;
typedef struct {
GLuint texture_id;
int width;
int height;
GLuint min_filter;
GLuint mag_filter;
Fbo fbo;
GdkTexture *user;
guint in_use : 1;
guint permanent : 1;
/* TODO: Make this optional and not for every texture... */
TextureSlice *slices;
guint n_slices;
} Texture;
struct _GskGLDriver
{
GObject parent_instance;
GdkGLContext *gl_context;
GskProfiler *profiler;
struct {
GQuark created_textures;
GQuark reused_textures;
GQuark surface_uploads;
} counters;
Fbo default_fbo;
GHashTable *textures; /* texture_id -> Texture */
GHashTable *pointer_textures; /* pointer -> texture_id */
const Texture *bound_source_texture;
int max_texture_size;
gboolean in_frame : 1;
};
G_DEFINE_TYPE (GskGLDriver, gsk_gl_driver, G_TYPE_OBJECT)
static void
upload_gdk_texture (GdkTexture *source_texture,
int target,
int x_offset,
int y_offset,
int width,
int height)
{
cairo_surface_t *surface = NULL;
GdkMemoryFormat data_format;
const guchar *data;
gsize data_stride;
gsize bpp;
g_return_if_fail (source_texture != NULL);
g_return_if_fail (x_offset + width <= gdk_texture_get_width (source_texture));
g_return_if_fail (y_offset + height <= gdk_texture_get_height (source_texture));
/* Note: GdkGLTextures are already handled before we reach this and reused as-is */
if (GDK_IS_MEMORY_TEXTURE (source_texture))
{
GdkMemoryTexture *memory_texture = GDK_MEMORY_TEXTURE (source_texture);
data = gdk_memory_texture_get_data (memory_texture);
data_format = gdk_memory_texture_get_format (memory_texture);
data_stride = gdk_memory_texture_get_stride (memory_texture);
}
else
{
/* Fall back to downloading to a surface */
surface = gdk_texture_download_surface (source_texture);
cairo_surface_flush (surface);
data = cairo_image_surface_get_data (surface);
data_format = GDK_MEMORY_DEFAULT;
data_stride = cairo_image_surface_get_stride (surface);
}
bpp = gdk_memory_format_bytes_per_pixel (data_format);
gdk_gl_context_upload_texture (gdk_gl_context_get_current (),
data + x_offset * bpp + y_offset * data_stride,
width, height, data_stride,
data_format, target);
if (surface)
cairo_surface_destroy (surface);
}
static Texture *
texture_new (void)
{
return g_slice_new0 (Texture);
}
static inline void
fbo_clear (const Fbo *f)
{
if (f->depth_stencil_id != 0)
glDeleteRenderbuffers (1, &f->depth_stencil_id);
glDeleteFramebuffers (1, &f->fbo_id);
}
static void
texture_free (gpointer data)
{
Texture *t = data;
guint i;
if (t->user)
gdk_texture_clear_render_data (t->user);
if (t->fbo.fbo_id != 0)
fbo_clear (&t->fbo);
if (t->texture_id != 0)
{
glDeleteTextures (1, &t->texture_id);
}
else
{
g_assert_cmpint (t->n_slices, >, 0);
for (i = 0; i < t->n_slices; i ++)
glDeleteTextures (1, &t->slices[i].texture_id);
}
g_slice_free (Texture, t);
}
static void
gsk_gl_driver_set_texture_parameters (GskGLDriver *self,
int min_filter,
int mag_filter)
{
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
static void
gsk_gl_driver_finalize (GObject *gobject)
{
GskGLDriver *self = GSK_GL_DRIVER (gobject);
gdk_gl_context_make_current (self->gl_context);
g_clear_pointer (&self->textures, g_hash_table_unref);
g_clear_pointer (&self->pointer_textures, g_hash_table_unref);
g_clear_object (&self->profiler);
if (self->gl_context == gdk_gl_context_get_current ())
gdk_gl_context_clear_current ();
G_OBJECT_CLASS (gsk_gl_driver_parent_class)->finalize (gobject);
}
static void
gsk_gl_driver_class_init (GskGLDriverClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = gsk_gl_driver_finalize;
}
static void
gsk_gl_driver_init (GskGLDriver *self)
{
self->textures = g_hash_table_new_full (NULL, NULL, NULL, texture_free);
self->max_texture_size = -1;
#ifdef G_ENABLE_DEBUG
self->profiler = gsk_profiler_new ();
self->counters.created_textures = gsk_profiler_add_counter (self->profiler,
"created_textures",
"Textures created this frame",
TRUE);
self->counters.reused_textures = gsk_profiler_add_counter (self->profiler,
"reused_textures",
"Textures reused this frame",
TRUE);
self->counters.surface_uploads = gsk_profiler_add_counter (self->profiler,
"surface_uploads",
"Texture uploads from surfaces this frame",
TRUE);
#endif
}
GskGLDriver *
gsk_gl_driver_new (GdkGLContext *context)
{
GskGLDriver *self;
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
self = (GskGLDriver *) g_object_new (GSK_TYPE_GL_DRIVER, NULL);
self->gl_context = context;
return self;
}
void
gsk_gl_driver_begin_frame (GskGLDriver *self)
{
g_return_if_fail (GSK_IS_GL_DRIVER (self));
g_return_if_fail (!self->in_frame);
self->in_frame = TRUE;
if (self->max_texture_size < 0)
{
glGetIntegerv (GL_MAX_TEXTURE_SIZE, (GLint *) &self->max_texture_size);
GSK_NOTE (OPENGL, g_message ("GL max texture size: %d", self->max_texture_size));
}
glBindFramebuffer (GL_FRAMEBUFFER, 0);
glActiveTexture (GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, 0);
glActiveTexture (GL_TEXTURE0 + 1);
glBindTexture (GL_TEXTURE_2D, 0);
glBindVertexArray (0);
glUseProgram (0);
glActiveTexture (GL_TEXTURE0);
#ifdef G_ENABLE_DEBUG
gsk_profiler_reset (self->profiler);
#endif
}
gboolean
gsk_gl_driver_in_frame (GskGLDriver *self)
{
return self->in_frame;
}
void
gsk_gl_driver_end_frame (GskGLDriver *self)
{
g_return_if_fail (GSK_IS_GL_DRIVER (self));
g_return_if_fail (self->in_frame);
self->bound_source_texture = NULL;
self->default_fbo.fbo_id = 0;
#ifdef G_ENABLE_DEBUG
GSK_NOTE (OPENGL,
g_message ("Textures created: %" G_GINT64_FORMAT "\n"
" Textures reused: %" G_GINT64_FORMAT "\n"
" Surface uploads: %" G_GINT64_FORMAT,
gsk_profiler_counter_get (self->profiler, self->counters.created_textures),
gsk_profiler_counter_get (self->profiler, self->counters.reused_textures),
gsk_profiler_counter_get (self->profiler, self->counters.surface_uploads)));
#endif
GSK_NOTE (OPENGL,
g_message ("*** Frame end: textures=%d",
g_hash_table_size (self->textures)));
self->in_frame = FALSE;
}
int
gsk_gl_driver_collect_textures (GskGLDriver *self)
{
GHashTableIter iter;
gpointer value_p = NULL;
int old_size;
g_return_val_if_fail (GSK_IS_GL_DRIVER (self), 0);
g_return_val_if_fail (!self->in_frame, 0);
old_size = g_hash_table_size (self->textures);
g_hash_table_iter_init (&iter, self->textures);
while (g_hash_table_iter_next (&iter, NULL, &value_p))
{
Texture *t = value_p;
if (t->user || t->permanent)
continue;
if (t->in_use)
{
t->in_use = FALSE;
if (t->fbo.fbo_id != 0)
{
fbo_clear (&t->fbo);
t->fbo.fbo_id = 0;
}
}
else
{
/* Remove from self->pointer_textures. */
/* TODO: Is there a better way for this? */
if (self->pointer_textures)
{
GHashTableIter pointer_iter;
gpointer value;
gpointer p;
g_hash_table_iter_init (&pointer_iter, self->pointer_textures);
while (g_hash_table_iter_next (&pointer_iter, &p, &value))
{
if (GPOINTER_TO_INT (value) == t->texture_id)
{
g_hash_table_iter_remove (&pointer_iter);
break;
}
}
}
g_hash_table_iter_remove (&iter);
}
}
return old_size - g_hash_table_size (self->textures);
}
GdkGLContext *
gsk_gl_driver_get_gl_context (GskGLDriver *self)
{
return self->gl_context;
}
int
gsk_gl_driver_get_max_texture_size (GskGLDriver *self)
{
if (self->max_texture_size < 0)
{
if (gdk_gl_context_get_use_es (self->gl_context))
return 2048;
return 1024;
}
return self->max_texture_size;
}
static Texture *
gsk_gl_driver_get_texture (GskGLDriver *self,
int texture_id)
{
Texture *t;
if (g_hash_table_lookup_extended (self->textures, GINT_TO_POINTER (texture_id), NULL, (gpointer *) &t))
return t;
return NULL;
}
static Texture *
create_texture (GskGLDriver *self,
float fwidth,
float fheight)
{
guint texture_id;
Texture *t;
int width = ceilf (fwidth);
int height = ceilf (fheight);
g_assert (width > 0);
g_assert (height > 0);
if (width > self->max_texture_size ||
height > self->max_texture_size)
{
g_critical ("Texture %d x %d is bigger than supported texture limit of %d; clipping...",
width, height,
self->max_texture_size);
width = MIN (width, self->max_texture_size);
height = MIN (height, self->max_texture_size);
}
glGenTextures (1, &texture_id);
t = texture_new ();
t->texture_id = texture_id;
t->width = width;
t->height = height;
t->min_filter = GL_NEAREST;
t->mag_filter = GL_NEAREST;
t->in_use = TRUE;
g_hash_table_insert (self->textures, GINT_TO_POINTER (texture_id), t);
#ifdef G_ENABLE_DEBUG
gsk_profiler_counter_inc (self->profiler, self->counters.created_textures);
#endif
return t;
}
static void
gsk_gl_driver_release_texture (gpointer data)
{
Texture *t = data;
t->user = NULL;
}
void
gsk_gl_driver_slice_texture (GskGLDriver *self,
GdkTexture *texture,
TextureSlice **out_slices,
guint *out_n_slices)
{
const int max_texture_size = gsk_gl_driver_get_max_texture_size (self) / 4; // XXX Too much?
const int cols = (texture->width / max_texture_size) + 1;
const int rows = (texture->height / max_texture_size) + 1;
int col, row;
int x = 0, y = 0; /* Position in the texture */
TextureSlice *slices;
Texture *tex;
g_assert (texture->width > max_texture_size || texture->height > max_texture_size);
tex = gdk_texture_get_render_data (texture, self);
if (tex != NULL)
{
g_assert (tex->n_slices > 0);
*out_slices = tex->slices;
*out_n_slices = tex->n_slices;
return;
}
slices = g_new0 (TextureSlice, cols * rows);
for (col = 0; col < cols; col ++)
{
const int slice_width = MIN (max_texture_size, texture->width - x);
for (row = 0; row < rows; row ++)
{
const int slice_height = MIN (max_texture_size, texture->height - y);
const int slice_index = (col * rows) + row;
guint texture_id;
glGenTextures (1, &texture_id);
#ifdef G_ENABLE_DEBUG
gsk_profiler_counter_inc (self->profiler, self->counters.created_textures);
#endif
glBindTexture (GL_TEXTURE_2D, texture_id);
gsk_gl_driver_set_texture_parameters (self, GL_NEAREST, GL_NEAREST);
upload_gdk_texture (texture, GL_TEXTURE_2D, x, y, slice_width, slice_height);
#ifdef G_ENABLE_DEBUG
gsk_profiler_counter_inc (self->profiler, self->counters.surface_uploads);
#endif
slices[slice_index].rect = (GdkRectangle){x, y, slice_width, slice_height};
slices[slice_index].texture_id = texture_id;
y += slice_height;
}
y = 0;
x += slice_width;
}
/* Allocate one Texture for the entire thing. */
tex = texture_new ();
tex->width = texture->width;
tex->height = texture->height;
tex->min_filter = GL_NEAREST;
tex->mag_filter = GL_NEAREST;
tex->in_use = TRUE;
tex->slices = slices;
tex->n_slices = cols * rows;
/* Use texture_free as destroy notify here since we are not inserting this Texture
* into self->textures! */
gdk_texture_set_render_data (texture, self, tex, texture_free);
*out_slices = slices;
*out_n_slices = cols * rows;
}
int
gsk_gl_driver_get_texture_for_texture (GskGLDriver *self,
GdkTexture *texture,
int min_filter,
int mag_filter)
{
Texture *t;
GdkTexture *downloaded_texture = NULL;
GdkTexture *source_texture;
if (GDK_IS_GL_TEXTURE (texture))
{
GdkGLTexture *gl_texture = (GdkGLTexture *) texture;
GdkGLContext *texture_context = gdk_gl_texture_get_context (gl_texture);
if (gdk_gl_context_is_shared (self->gl_context, texture_context))
{
/* A GL texture from the same GL context is a simple task... */
return gdk_gl_texture_get_id (gl_texture);
}
else
{
cairo_surface_t *surface;
/* In this case, we have to temporarily make the texture's context the current one,
* download its data into our context and then create a texture from it. */
if (texture_context)
gdk_gl_context_make_current (texture_context);
surface = gdk_texture_download_surface (texture);
downloaded_texture = gdk_texture_new_for_surface (surface);
cairo_surface_destroy (surface);
gdk_gl_context_make_current (self->gl_context);
source_texture = downloaded_texture;
}
}
else
{
t = gdk_texture_get_render_data (texture, self);
if (t)
{
if (t->min_filter == min_filter && t->mag_filter == mag_filter)
return t->texture_id;
}
source_texture = texture;
}
t = create_texture (self, gdk_texture_get_width (texture), gdk_texture_get_height (texture));
if (gdk_texture_set_render_data (texture, self, t, gsk_gl_driver_release_texture))
t->user = texture;
gsk_gl_driver_bind_source_texture (self, t->texture_id);
gsk_gl_driver_init_texture (self,
t->texture_id,
source_texture,
min_filter,
mag_filter);
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, t->texture_id,
"GdkTexture<%p> %d", texture, t->texture_id);
if (downloaded_texture)
g_object_unref (downloaded_texture);
return t->texture_id;
}
static guint
texture_key_hash (gconstpointer v)
{
const GskTextureKey *k = (GskTextureKey *)v;
return GPOINTER_TO_UINT (k->pointer)
+ (guint)(k->scale_x * 100)
+ (guint)(k->scale_y * 100)
+ (guint)k->filter * 2 +
+ (guint)k->pointer_is_child;
}
static gboolean
texture_key_equal (gconstpointer v1, gconstpointer v2)
{
const GskTextureKey *k1 = (GskTextureKey *)v1;
const GskTextureKey *k2 = (GskTextureKey *)v2;
return k1->pointer == k2->pointer &&
k1->scale_x == k2->scale_x &&
k1->scale_y == k2->scale_y &&
k1->filter == k2->filter &&
k1->pointer_is_child == k2->pointer_is_child &&
(!k1->pointer_is_child || graphene_rect_equal (&k1->parent_rect, &k2->parent_rect));
}
int
gsk_gl_driver_get_texture_for_key (GskGLDriver *self,
GskTextureKey *key)
{
int id = 0;
if (G_UNLIKELY (self->pointer_textures == NULL))
self->pointer_textures = g_hash_table_new_full (texture_key_hash, texture_key_equal, g_free, NULL);
id = GPOINTER_TO_INT (g_hash_table_lookup (self->pointer_textures, key));
if (id != 0)
{
Texture *t;
t = g_hash_table_lookup (self->textures, GINT_TO_POINTER (id));
if (t != NULL)
t->in_use = TRUE;
}
return id;
}
void
gsk_gl_driver_set_texture_for_key (GskGLDriver *self,
GskTextureKey *key,
int texture_id)
{
GskTextureKey *k;
if (G_UNLIKELY (self->pointer_textures == NULL))
self->pointer_textures = g_hash_table_new_full (texture_key_hash, texture_key_equal, g_free, NULL);
k = g_new (GskTextureKey, 1);
*k = *key;
g_hash_table_insert (self->pointer_textures, k, GINT_TO_POINTER (texture_id));
}
int
gsk_gl_driver_create_texture (GskGLDriver *self,
float width,
float height)
{
Texture *t;
g_return_val_if_fail (GSK_IS_GL_DRIVER (self), -1);
t = create_texture (self, width, height);
return t->texture_id;
}
void
gsk_gl_driver_create_render_target (GskGLDriver *self,
int width,
int height,
int min_filter,
int mag_filter,
int *out_texture_id,
int *out_render_target_id)
{
GLuint fbo_id;
Texture *texture;
g_return_if_fail (self->in_frame);
texture = create_texture (self, width, height);
gsk_gl_driver_bind_source_texture (self, texture->texture_id);
gsk_gl_driver_init_texture_empty (self, texture->texture_id, min_filter, mag_filter);
glGenFramebuffers (1, &fbo_id);
glBindFramebuffer (GL_FRAMEBUFFER, fbo_id);
glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture_id, 0);
#if 0
if (add_depth_buffer || add_stencil_buffer)
{
glGenRenderbuffersEXT (1, &depth_stencil_buffer_id);
gdk_gl_context_label_object_printf (self->gl_context, GL_RENDERBUFFER, depth_stencil_buffer_id,
"%s buffer for %d", add_depth_buffer ? "Depth" : "Stencil", texture_id);
}
else
depth_stencil_buffer_id = 0;
glBindRenderbuffer (GL_RENDERBUFFER, depth_stencil_buffer_id);
if (add_depth_buffer || add_stencil_buffer)
{
if (add_stencil_buffer)
glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, t->width, t->height);
else
glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, t->width, t->height);
if (add_depth_buffer)
glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, depth_stencil_buffer_id);
if (add_stencil_buffer)
glFramebufferRenderbufferEXT (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, depth_stencil_buffer_id);
texture->fbo.depth_stencil_id = depth_stencil_buffer_id;
}
#endif
texture->fbo.fbo_id = fbo_id;
g_assert_cmphex (glCheckFramebufferStatus (GL_FRAMEBUFFER), ==, GL_FRAMEBUFFER_COMPLETE);
glBindFramebuffer (GL_FRAMEBUFFER, self->default_fbo.fbo_id);
*out_texture_id = texture->texture_id;
*out_render_target_id = fbo_id;
}
/* Mark the texture permanent, meaning it won'e be reused by the GLDriver.
* E.g. to store it in some other cache. */
void
gsk_gl_driver_mark_texture_permanent (GskGLDriver *self,
int texture_id)
{
Texture *t = gsk_gl_driver_get_texture (self, texture_id);
g_assert (t != NULL);
t->permanent = TRUE;
}
void
gsk_gl_driver_bind_source_texture (GskGLDriver *self,
int texture_id)
{
Texture *t;
g_return_if_fail (GSK_IS_GL_DRIVER (self));
g_return_if_fail (self->in_frame);
t = gsk_gl_driver_get_texture (self, texture_id);
if (t == NULL)
{
g_critical ("No texture %d found.", texture_id);
return;
}
if (self->bound_source_texture != t)
{
glActiveTexture (GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, t->texture_id);
self->bound_source_texture = t;
}
}
void
gsk_gl_driver_destroy_texture (GskGLDriver *self,
int texture_id)
{
g_return_if_fail (GSK_IS_GL_DRIVER (self));
g_hash_table_remove (self->textures, GINT_TO_POINTER (texture_id));
}
void
gsk_gl_driver_init_texture_empty (GskGLDriver *self,
int texture_id,
int min_filter,
int mag_filter)
{
Texture *t;
g_return_if_fail (GSK_IS_GL_DRIVER (self));
t = gsk_gl_driver_get_texture (self, texture_id);
if (t == NULL)
{
g_critical ("No texture %d found.", texture_id);
return;
}
if (self->bound_source_texture != t)
{
g_critical ("You must bind the texture before initializing it.");
return;
}
t->min_filter = min_filter;
t->mag_filter = mag_filter;
gsk_gl_driver_set_texture_parameters (self, t->min_filter, t->mag_filter);
if (gdk_gl_context_get_use_es (self->gl_context))
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, t->width, t->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
else
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, t->width, t->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
glBindTexture (GL_TEXTURE_2D, 0);
}
static gboolean
filter_uses_mipmaps (int filter)
{
return filter != GL_NEAREST && filter != GL_LINEAR;
}
void
gsk_gl_driver_init_texture (GskGLDriver *self,
int texture_id,
GdkTexture *texture,
int min_filter,
int mag_filter)
{
Texture *t;
g_return_if_fail (GSK_IS_GL_DRIVER (self));
t = gsk_gl_driver_get_texture (self, texture_id);
if (t == NULL)
{
g_critical ("No texture %d found.", texture_id);
return;
}
if (self->bound_source_texture != t)
{
g_critical ("You must bind the texture before initializing it.");
return;
}
gsk_gl_driver_set_texture_parameters (self, min_filter, mag_filter);
upload_gdk_texture (texture, GL_TEXTURE_2D, 0, 0, t->width, t->height);
#ifdef G_ENABLE_DEBUG
gsk_profiler_counter_inc (self->profiler, self->counters.surface_uploads);
#endif
t->min_filter = min_filter;
t->mag_filter = mag_filter;
if (filter_uses_mipmaps (t->min_filter))
glGenerateMipmap (GL_TEXTURE_2D);
}
+86
View File
@@ -0,0 +1,86 @@
#ifndef __GSK_GL_DRIVER_PRIVATE_H__
#define __GSK_GL_DRIVER_PRIVATE_H__
#include <cairo.h>
#include <gdk/gdk.h>
#include <graphene.h>
G_BEGIN_DECLS
#define GSK_TYPE_GL_DRIVER (gsk_gl_driver_get_type ())
G_DECLARE_FINAL_TYPE (GskGLDriver, gsk_gl_driver, GSK, GL_DRIVER, GObject)
typedef struct {
float position[2];
float uv[2];
} GskQuadVertex;
typedef struct {
cairo_rectangle_int_t rect;
guint texture_id;
} TextureSlice;
typedef struct {
gpointer pointer;
float scale_x;
float scale_y;
int filter;
int pointer_is_child;
graphene_rect_t parent_rect; /* Only set if pointer_is_child */
} GskTextureKey;
GskGLDriver * gsk_gl_driver_new (GdkGLContext *context);
GdkGLContext *gsk_gl_driver_get_gl_context (GskGLDriver *driver);
int gsk_gl_driver_get_max_texture_size (GskGLDriver *driver);
void gsk_gl_driver_begin_frame (GskGLDriver *driver);
void gsk_gl_driver_end_frame (GskGLDriver *driver);
gboolean gsk_gl_driver_in_frame (GskGLDriver *driver);
int gsk_gl_driver_get_texture_for_texture (GskGLDriver *driver,
GdkTexture *texture,
int min_filter,
int mag_filter);
int gsk_gl_driver_get_texture_for_key (GskGLDriver *driver,
GskTextureKey *key);
void gsk_gl_driver_set_texture_for_key (GskGLDriver *driver,
GskTextureKey *key,
int texture_id);
int gsk_gl_driver_create_texture (GskGLDriver *driver,
float width,
float height);
void gsk_gl_driver_create_render_target (GskGLDriver *driver,
int width,
int height,
int min_filter,
int mag_filter,
int *out_texture_id,
int *out_render_target_id);
void gsk_gl_driver_mark_texture_permanent (GskGLDriver *self,
int texture_id);
void gsk_gl_driver_bind_source_texture (GskGLDriver *driver,
int texture_id);
void gsk_gl_driver_init_texture_empty (GskGLDriver *driver,
int texture_id,
int min_filter,
int max_filter);
void gsk_gl_driver_init_texture (GskGLDriver *driver,
int texture_id,
GdkTexture *texture,
int min_filter,
int mag_filter);
void gsk_gl_driver_destroy_texture (GskGLDriver *driver,
int texture_id);
int gsk_gl_driver_collect_textures (GskGLDriver *driver);
void gsk_gl_driver_slice_texture (GskGLDriver *self,
GdkTexture *texture,
TextureSlice **out_slices,
guint *out_n_slices);
G_END_DECLS
#endif /* __GSK_GL_DRIVER_PRIVATE_H__ */
+397
View File
@@ -0,0 +1,397 @@
#include "config.h"
#include "gskglglyphcacheprivate.h"
#include "gskgldriverprivate.h"
#include "gskdebugprivate.h"
#include "gskprivate.h"
#include "gskgltextureatlasprivate.h"
#include "gdk/gdkglcontextprivate.h"
#include "gdk/gdkmemorytextureprivate.h"
#include <graphene.h>
#include <cairo.h>
#include <epoxy/gl.h>
#include <string.h>
/* Cache eviction strategy
*
* We mark glyphs as accessed every time we use them.
* Every few frames, we mark glyphs that haven't been
* accessed since the last check as old.
*
* We keep count of the pixels of each atlas that are
* taken up by old data. When the fraction of old pixels
* gets too high, we drop the atlas and all the items it
* contained.
*
* Big glyphs are not stored in the atlas, they get their
* own texture, but they are still cached.
*/
#define MAX_FRAME_AGE (60)
#define MAX_GLYPH_SIZE 128 /* Will get its own texture if bigger */
static guint glyph_cache_hash (gconstpointer v);
static gboolean glyph_cache_equal (gconstpointer v1,
gconstpointer v2);
static void glyph_cache_key_free (gpointer v);
static void glyph_cache_value_free (gpointer v);
GskGLGlyphCache *
gsk_gl_glyph_cache_new (GdkDisplay *display,
GskGLTextureAtlases *atlases)
{
GskGLGlyphCache *glyph_cache;
glyph_cache = g_new0 (GskGLGlyphCache, 1);
glyph_cache->display = display;
glyph_cache->hash_table = g_hash_table_new_full (glyph_cache_hash, glyph_cache_equal,
glyph_cache_key_free, glyph_cache_value_free);
glyph_cache->atlases = gsk_gl_texture_atlases_ref (atlases);
glyph_cache->ref_count = 1;
return glyph_cache;
}
GskGLGlyphCache *
gsk_gl_glyph_cache_ref (GskGLGlyphCache *self)
{
self->ref_count++;
return self;
}
void
gsk_gl_glyph_cache_unref (GskGLGlyphCache *self)
{
g_assert (self->ref_count > 0);
if (self->ref_count == 1)
{
gsk_gl_texture_atlases_unref (self->atlases);
g_hash_table_unref (self->hash_table);
g_free (self);
return;
}
self->ref_count--;
}
static gboolean
glyph_cache_equal (gconstpointer v1, gconstpointer v2)
{
return memcmp (v1, v2, sizeof (CacheKeyData)) == 0;
}
static guint
glyph_cache_hash (gconstpointer v)
{
const GlyphCacheKey *key = v;
return key->hash;
}
static void
glyph_cache_key_free (gpointer v)
{
GlyphCacheKey *f = v;
g_object_unref (f->data.font);
g_free (f);
}
static void
glyph_cache_value_free (gpointer v)
{
g_free (v);
}
static gboolean
render_glyph (GlyphCacheKey *key,
GskGLCachedGlyph *value,
GskImageRegion *region)
{
cairo_surface_t *surface;
cairo_t *cr;
cairo_scaled_font_t *scaled_font;
PangoGlyphString glyph_string;
PangoGlyphInfo glyph_info;
int surface_width, surface_height;
int stride;
unsigned char *data;
scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)key->data.font);
if (G_UNLIKELY (!scaled_font || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS))
{
g_warning ("Failed to get a font");
return FALSE;
}
surface_width = value->draw_width * key->data.scale / 1024;
surface_height = value->draw_height * key->data.scale / 1024;
stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, surface_width);
data = g_malloc0 (stride * surface_height);
surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32,
surface_width, surface_height,
stride);
cairo_surface_set_device_scale (surface, key->data.scale / 1024.0, key->data.scale / 1024.0);
cr = cairo_create (surface);
cairo_set_scaled_font (cr, scaled_font);
cairo_set_source_rgba (cr, 1, 1, 1, 1);
glyph_info.glyph = key->data.glyph;
glyph_info.geometry.width = value->draw_width * 1024;
if (glyph_info.glyph & PANGO_GLYPH_UNKNOWN_FLAG)
glyph_info.geometry.x_offset = 256 * key->data.xshift;
else
glyph_info.geometry.x_offset = 256 * key->data.xshift - value->draw_x * 1024;
glyph_info.geometry.y_offset = 256 * key->data.yshift - value->draw_y * 1024;
glyph_string.num_glyphs = 1;
glyph_string.glyphs = &glyph_info;
pango_cairo_show_glyph_string (cr, key->data.font, &glyph_string);
cairo_destroy (cr);
cairo_surface_flush (surface);
region->width = cairo_image_surface_get_width (surface);
region->height = cairo_image_surface_get_height (surface);
region->stride = cairo_image_surface_get_stride (surface);
region->data = data;
if (value->atlas)
{
region->x = (gsize)(value->tx * value->atlas->width);
region->y = (gsize)(value->ty * value->atlas->height);
}
else
{
region->x = 0;
region->y = 0;
}
cairo_surface_destroy (surface);
return TRUE;
}
static void
upload_glyph (GlyphCacheKey *key,
GskGLCachedGlyph *value)
{
GskImageRegion r;
guchar *pixel_data;
guchar *free_data = NULL;
guint gl_format;
guint gl_type;
gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (),
"Uploading glyph %d",
key->data.glyph);
if (render_glyph (key, value, &r))
{
glPixelStorei (GL_UNPACK_ROW_LENGTH, r.stride / 4);
glBindTexture (GL_TEXTURE_2D, value->texture_id);
if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
{
pixel_data = free_data = g_malloc (r.width * r.height * 4);
gdk_memory_convert (pixel_data, r.width * 4,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
r.data, r.width * 4,
GDK_MEMORY_DEFAULT, r.width, r.height);
gl_format = GL_RGBA;
gl_type = GL_UNSIGNED_BYTE;
}
else
{
pixel_data = r.data;
gl_format = GL_BGRA;
gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
}
glTexSubImage2D (GL_TEXTURE_2D, 0, r.x, r.y, r.width, r.height,
gl_format, gl_type, pixel_data);
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
g_free (r.data);
g_free (free_data);
}
gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ());
}
static void
add_to_cache (GskGLGlyphCache *self,
GlyphCacheKey *key,
GskGLDriver *driver,
GskGLCachedGlyph *value)
{
const int width = value->draw_width * key->data.scale / 1024;
const int height = value->draw_height * key->data.scale / 1024;
if (width < MAX_GLYPH_SIZE && height < MAX_GLYPH_SIZE)
{
GskGLTextureAtlas *atlas = NULL;
int packed_x = 0;
int packed_y = 0;
gsk_gl_texture_atlases_pack (self->atlases, width + 2, height + 2, &atlas, &packed_x, &packed_y);
value->tx = (float)(packed_x + 1) / atlas->width;
value->ty = (float)(packed_y + 1) / atlas->height;
value->tw = (float)width / atlas->width;
value->th = (float)height / atlas->height;
value->used = TRUE;
value->atlas = atlas;
value->texture_id = atlas->texture_id;
}
else
{
value->atlas = NULL;
value->texture_id = gsk_gl_driver_create_texture (driver, width, height);
gsk_gl_driver_mark_texture_permanent (driver, value->texture_id);
gsk_gl_driver_bind_source_texture (driver, value->texture_id);
gsk_gl_driver_init_texture_empty (driver, value->texture_id, GL_LINEAR, GL_LINEAR);
value->tx = 0.0f;
value->ty = 0.0f;
value->tw = 1.0f;
value->th = 1.0f;
}
upload_glyph (key, value);
}
void
gsk_gl_glyph_cache_lookup_or_add (GskGLGlyphCache *cache,
GlyphCacheKey *lookup,
GskGLDriver *driver,
const GskGLCachedGlyph **cached_glyph_out)
{
GskGLCachedGlyph *value;
value = g_hash_table_lookup (cache->hash_table, lookup);
if (value)
{
if (value->atlas && !value->used)
{
gsk_gl_texture_atlas_mark_used (value->atlas, value->draw_width, value->draw_height);
value->used = TRUE;
}
value->accessed = TRUE;
*cached_glyph_out = value;
return;
}
{
GlyphCacheKey *key;
PangoRectangle ink_rect;
pango_font_get_glyph_extents (lookup->data.font, lookup->data.glyph, &ink_rect, NULL);
pango_extents_to_pixels (&ink_rect, NULL);
if (lookup->data.xshift != 0)
ink_rect.width += 1;
if (lookup->data.yshift != 0)
ink_rect.height += 1;
value = g_new0 (GskGLCachedGlyph, 1);
value->draw_x = ink_rect.x;
value->draw_y = ink_rect.y;
value->draw_width = ink_rect.width;
value->draw_height = ink_rect.height;
value->accessed = TRUE;
value->atlas = NULL; /* For now */
key = g_new0 (GlyphCacheKey, 1);
key->data.font = g_object_ref (lookup->data.font);
key->data.glyph = lookup->data.glyph;
key->data.xshift = lookup->data.xshift;
key->data.yshift = lookup->data.yshift;
key->data.scale = lookup->data.scale;
key->hash = lookup->hash;
if (key->data.scale > 0 &&
value->draw_width * key->data.scale / 1024 > 0 &&
value->draw_height * key->data.scale / 1024 > 0)
add_to_cache (cache, key, driver, value);
*cached_glyph_out = value;
g_hash_table_insert (cache->hash_table, key, value);
}
}
void
gsk_gl_glyph_cache_begin_frame (GskGLGlyphCache *self,
GskGLDriver *driver,
GPtrArray *removed_atlases)
{
GHashTableIter iter;
GlyphCacheKey *key;
GskGLCachedGlyph *value;
guint dropped = 0;
self->timestamp++;
if (removed_atlases->len > 0)
{
g_hash_table_iter_init (&iter, self->hash_table);
while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
{
if (g_ptr_array_find (removed_atlases, value->atlas, NULL))
{
g_hash_table_iter_remove (&iter);
dropped++;
}
}
}
if (self->timestamp % MAX_FRAME_AGE == 30)
{
g_hash_table_iter_init (&iter, self->hash_table);
while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
{
if (!value->accessed)
{
if (value->atlas)
{
if (value->used)
{
gsk_gl_texture_atlas_mark_unused (value->atlas, value->draw_width, value->draw_height);
value->used = FALSE;
}
}
else
{
gsk_gl_driver_destroy_texture (driver, value->texture_id);
g_hash_table_iter_remove (&iter);
/* Sadly, if we drop an atlas-less cached glyph, we
* have to treat it like a dropped atlas and purge
* text node render data.
*/
dropped++;
}
}
else
value->accessed = FALSE;
}
GSK_NOTE(GLYPH_CACHE, g_message ("%d glyphs cached", g_hash_table_size (self->hash_table)));
}
GSK_NOTE(GLYPH_CACHE, if (dropped > 0) g_message ("Dropped %d glyphs", dropped));
}
+92
View File
@@ -0,0 +1,92 @@
#ifndef __GSK_GL_GLYPH_CACHE_PRIVATE_H__
#define __GSK_GL_GLYPH_CACHE_PRIVATE_H__
#include "gskgldriverprivate.h"
#include "gskglimageprivate.h"
#include "gskgltextureatlasprivate.h"
#include <pango/pango.h>
#include <gdk/gdk.h>
typedef struct
{
int ref_count;
GdkDisplay *display;
GHashTable *hash_table;
GskGLTextureAtlases *atlases;
int timestamp;
} GskGLGlyphCache;
struct _CacheKeyData
{
PangoFont *font;
PangoGlyph glyph;
guint xshift : 3;
guint yshift : 3;
guint scale : 26; /* times 1024 */
};
typedef struct _CacheKeyData CacheKeyData;
struct _GlyphCacheKey
{
CacheKeyData data;
guint hash;
};
typedef struct _GlyphCacheKey GlyphCacheKey;
#define PHASE(x) ((int)(floor (4 * (x + 0.125)) - 4 * floor (x + 0.125)))
static inline void
glyph_cache_key_set_glyph_and_shift (GlyphCacheKey *key,
PangoGlyph glyph,
float x,
float y)
{
key->data.glyph = glyph;
key->data.xshift = PHASE (x);
key->data.yshift = PHASE (y);
key->hash = GPOINTER_TO_UINT (key->data.font) ^
key->data.glyph ^
(key->data.xshift << 24) ^
(key->data.yshift << 26) ^
key->data.scale;
}
typedef struct _GskGLCachedGlyph GskGLCachedGlyph;
struct _GskGLCachedGlyph
{
GskGLTextureAtlas *atlas;
guint texture_id;
float tx;
float ty;
float tw;
float th;
int draw_x;
int draw_y;
int draw_width;
int draw_height;
guint accessed : 1; /* accessed since last check */
guint used : 1; /* accounted as used in the atlas */
};
GskGLGlyphCache * gsk_gl_glyph_cache_new (GdkDisplay *display,
GskGLTextureAtlases *atlases);
GskGLGlyphCache * gsk_gl_glyph_cache_ref (GskGLGlyphCache *self);
void gsk_gl_glyph_cache_unref (GskGLGlyphCache *self);
void gsk_gl_glyph_cache_begin_frame (GskGLGlyphCache *self,
GskGLDriver *driver,
GPtrArray *removed_atlases);
void gsk_gl_glyph_cache_lookup_or_add (GskGLGlyphCache *self,
GlyphCacheKey *lookup,
GskGLDriver *driver,
const GskGLCachedGlyph **cached_glyph_out);
#endif
+275
View File
@@ -0,0 +1,275 @@
#include "gskgliconcacheprivate.h"
#include "gskgltextureatlasprivate.h"
#include "gdk/gdktextureprivate.h"
#include "gdk/gdkmemorytextureprivate.h"
#include "gdk/gdkglcontextprivate.h"
#include <epoxy/gl.h>
#define MAX_FRAME_AGE 60
static void
icon_data_free (gpointer p)
{
g_object_unref (((IconData *)p)->source_texture);
g_free (p);
}
GskGLIconCache *
gsk_gl_icon_cache_new (GdkDisplay *display,
GskGLTextureAtlases *atlases)
{
GskGLIconCache *self;
self = g_new0 (GskGLIconCache, 1);
self->display = display;
self->icons = g_hash_table_new_full (NULL, NULL, NULL, icon_data_free);
self->atlases = gsk_gl_texture_atlases_ref (atlases);
self->ref_count = 1;
return self;
}
GskGLIconCache *
gsk_gl_icon_cache_ref (GskGLIconCache *self)
{
self->ref_count++;
return self;
}
void
gsk_gl_icon_cache_unref (GskGLIconCache *self)
{
g_assert (self->ref_count > 0);
if (self->ref_count == 1)
{
gsk_gl_texture_atlases_unref (self->atlases);
g_hash_table_unref (self->icons);
g_free (self);
return;
}
self->ref_count--;
}
void
gsk_gl_icon_cache_begin_frame (GskGLIconCache *self,
GPtrArray *removed_atlases)
{
GHashTableIter iter;
GdkTexture *texture;
IconData *icon_data;
self->timestamp++;
/* Drop icons on removed atlases */
if (removed_atlases->len > 0)
{
guint dropped = 0;
g_hash_table_iter_init (&iter, self->icons);
while (g_hash_table_iter_next (&iter, (gpointer *)&texture, (gpointer *)&icon_data))
{
if (g_ptr_array_find (removed_atlases, icon_data->atlas, NULL))
{
g_hash_table_iter_remove (&iter);
dropped++;
}
}
GSK_NOTE(GLYPH_CACHE, if (dropped > 0) g_message ("Dropped %d icons", dropped));
}
if (self->timestamp % MAX_FRAME_AGE == 0)
{
g_hash_table_iter_init (&iter, self->icons);
while (g_hash_table_iter_next (&iter, (gpointer *)&texture, (gpointer *)&icon_data))
{
if (!icon_data->accessed)
{
if (icon_data->used)
{
const int width = icon_data->source_texture->width;
const int height = icon_data->source_texture->height;
gsk_gl_texture_atlas_mark_unused (icon_data->atlas, width + 2, height + 2);
icon_data->used = FALSE;
}
}
icon_data->accessed = FALSE;
}
GSK_NOTE(GLYPH_CACHE, g_message ("%d icons cached", g_hash_table_size (self->icons)));
}
}
void
gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self,
GdkTexture *texture,
const IconData **out_icon_data)
{
IconData *icon_data = g_hash_table_lookup (self->icons, texture);
if (icon_data)
{
if (!icon_data->used)
{
gsk_gl_texture_atlas_mark_used (icon_data->atlas, texture->width + 2, texture->height + 2);
icon_data->used = TRUE;
}
icon_data->accessed = TRUE;
*out_icon_data = icon_data;
return;
}
/* texture not on any atlas yet. Find a suitable one. */
{
const int width = texture->width;
const int height = texture->height;
GskGLTextureAtlas *atlas = NULL;
int packed_x = 0;
int packed_y = 0;
cairo_surface_t *surface;
unsigned char *surface_data;
unsigned char *pixel_data;
guchar *free_data = NULL;
guint gl_format;
guint gl_type;
gsk_gl_texture_atlases_pack (self->atlases, width + 2, height + 2, &atlas, &packed_x, &packed_y);
icon_data = g_new0 (IconData, 1);
icon_data->atlas = atlas;
icon_data->accessed = TRUE;
icon_data->used = TRUE;
icon_data->texture_id = atlas->texture_id;
icon_data->source_texture = g_object_ref (texture);
icon_data->x = (float)(packed_x + 1) / atlas->width;
icon_data->y = (float)(packed_y + 1) / atlas->width;
icon_data->x2 = icon_data->x + (float)width / atlas->width;
icon_data->y2 = icon_data->y + (float)height / atlas->height;
g_hash_table_insert (self->icons, texture, icon_data);
/* actually upload the texture */
surface = gdk_texture_download_surface (texture);
surface_data = cairo_image_surface_get_data (surface);
gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (),
"Uploading texture");
if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
{
pixel_data = free_data = g_malloc (width * height * 4);
gdk_memory_convert (pixel_data, width * 4,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
surface_data, cairo_image_surface_get_stride (surface),
GDK_MEMORY_DEFAULT, width, height);
gl_format = GL_RGBA;
gl_type = GL_UNSIGNED_BYTE;
}
else
{
pixel_data = surface_data;
gl_format = GL_BGRA;
gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
}
glBindTexture (GL_TEXTURE_2D, atlas->texture_id);
glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x + 1, packed_y + 1,
width, height,
gl_format, gl_type,
pixel_data);
/* Padding top */
glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x + 1, packed_y,
width, 1,
gl_format, gl_type,
pixel_data);
/* Padding left */
glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x, packed_y + 1,
1, height,
gl_format, gl_type,
pixel_data);
/* Padding top left */
glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x, packed_y,
1, 1,
gl_format, gl_type,
pixel_data);
/* Padding right */
glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
glPixelStorei (GL_UNPACK_SKIP_PIXELS, width - 1);
glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x + width + 1, packed_y + 1,
1, height,
gl_format, gl_type,
pixel_data);
/* Padding top right */
glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x + width + 1, packed_y,
1, 1,
gl_format, gl_type,
pixel_data);
/* Padding bottom */
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei (GL_UNPACK_SKIP_ROWS, height - 1);
glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x + 1, packed_y + 1 + height,
width, 1,
gl_format, gl_type,
pixel_data);
/* Padding bottom left */
glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x, packed_y + 1 + height,
1, 1,
gl_format, gl_type,
pixel_data);
/* Padding bottom right */
glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
glPixelStorei (GL_UNPACK_SKIP_PIXELS, width - 1);
glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x + 1 + width, packed_y + 1 + height,
1, 1,
gl_format, gl_type,
pixel_data);
/* Reset this */
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ());
*out_icon_data = icon_data;
cairo_surface_destroy (surface);
g_free (free_data);
#if 0
{
static int k;
const int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, atlas->width);
guchar *data = g_malloc (atlas->height * stride);
cairo_surface_t *s;
char *filename = g_strdup_printf ("atlas_%u_%d.png", atlas->texture_id, k++);
glBindTexture (GL_TEXTURE_2D, atlas->texture_id);
glGetTexImage (GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, data);
s = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, atlas->width, atlas->height, stride);
cairo_surface_write_to_png (s, filename);
cairo_surface_destroy (s);
g_free (data);
g_free (filename);
}
#endif
}
}
+44
View File
@@ -0,0 +1,44 @@
#ifndef __GSK_GL_ICON_CACHE_PRIVATE_H__
#define __GSK_GL_ICON_CACHE_PRIVATE_H__
#include "gskgldriverprivate.h"
#include "gskglimageprivate.h"
#include "gskrendererprivate.h"
#include "gskgltextureatlasprivate.h"
#include <pango/pango.h>
#include <gdk/gdk.h>
typedef struct
{
int ref_count;
GdkDisplay *display;
GskGLDriver *gl_driver;
GskGLTextureAtlases *atlases;
GHashTable *icons; /* GdkTexture -> IconData */
int timestamp;
} GskGLIconCache;
typedef struct
{
float x, y, x2, y2;
GskGLTextureAtlas *atlas;
guint used : 1;
guint accessed : 1;
int texture_id;
GdkTexture *source_texture;
} IconData;
GskGLIconCache * gsk_gl_icon_cache_new (GdkDisplay *display,
GskGLTextureAtlases *atlases);
GskGLIconCache * gsk_gl_icon_cache_ref (GskGLIconCache *self);
void gsk_gl_icon_cache_unref (GskGLIconCache *self);
void gsk_gl_icon_cache_begin_frame (GskGLIconCache *self,
GPtrArray *removed_atlases);
void gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self,
GdkTexture *texture,
const IconData **out_icon_data);
#endif
+64
View File
@@ -0,0 +1,64 @@
#include "gskglimageprivate.h"
#include <epoxy/gl.h>
void
gsk_gl_image_create (GskGLImage *self,
GskGLDriver *gl_driver,
int width,
int height,
int min_filter,
int mag_filter)
{
self->texture_id = gsk_gl_driver_create_texture (gl_driver, width, height);
self->width = width;
self->height = height;
gsk_gl_driver_bind_source_texture (gl_driver, self->texture_id);
gsk_gl_driver_init_texture_empty (gl_driver, self->texture_id, min_filter, mag_filter);
gsk_gl_driver_mark_texture_permanent (gl_driver, self->texture_id);
}
void
gsk_gl_image_destroy (GskGLImage *self,
GskGLDriver *gl_driver)
{
gsk_gl_driver_destroy_texture (gl_driver, self->texture_id);
self->texture_id = 0;
}
void
gsk_gl_image_write_to_png (const GskGLImage *self,
GskGLDriver *gl_driver,
const char *filename)
{
int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, self->width);
guchar *data = g_malloc (self->height * stride);
cairo_surface_t *s;
gsk_gl_driver_bind_source_texture (gl_driver, self->texture_id);
glGetTexImage (GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
s = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, self->width, self->height, stride);
cairo_surface_write_to_png (s, filename);
cairo_surface_destroy (s);
g_free (data);
}
void
gsk_gl_image_upload_region (GskGLImage *self,
GskGLDriver *gl_driver,
const GskImageRegion *region)
{
gsk_gl_driver_bind_source_texture (gl_driver, self->texture_id);
glBindTexture (GL_TEXTURE_2D, self->texture_id);
glTexSubImage2D (GL_TEXTURE_2D, 0, region->x, region->y, region->width, region->height,
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, region->data);
#ifdef G_ENABLE_DEBUG
/*gsk_gl_driver_bind_source_texture (gl_driver, self->texture_id);*/
/*gsk_gl_image_dump (self, gl_driver, "/home/baedert/atlases/test_dump.png");*/
#endif
}
+41
View File
@@ -0,0 +1,41 @@
#ifndef __GSK_GL_IMAGE_H__
#define __GSK_GL_IMAGE_H__
#include "gskgldriverprivate.h"
#include <cairo.h>
typedef struct
{
guint texture_id;
int width;
int height;
} GskGLImage;
typedef struct
{
guchar *data;
gsize width;
gsize height;
gsize stride;
gsize x;
gsize y;
} GskImageRegion;
void gsk_gl_image_create (GskGLImage *self,
GskGLDriver *gl_driver,
int width,
int height,
int min_filter,
int mag_filter);
void gsk_gl_image_destroy (GskGLImage *self,
GskGLDriver *gl_driver);
void gsk_gl_image_write_to_png (const GskGLImage *self,
GskGLDriver *gl_driver,
const char *filename);
void gsk_gl_image_upload_region (GskGLImage *self,
GskGLDriver *gl_driver,
const GskImageRegion *region);
#endif
+51
View File
@@ -0,0 +1,51 @@
#include <glib/gprintf.h>
#include "gskglnodesampleprivate.h"
#include "gskrendernodeprivate.h"
void
node_sample_init (NodeSample *self)
{
memset (self->nodes, 0, sizeof (self->nodes));
self->count = 0;
}
void
node_sample_reset (NodeSample *self)
{
node_sample_init (self);
}
void
node_sample_add (NodeSample *self,
GskRenderNode *node)
{
const guint node_type = gsk_render_node_get_node_type (node);
g_assert (node_type <= N_NODE_TYPES);
if (self->nodes[node_type].class_name == NULL)
self->nodes[node_type].class_name = g_type_name_from_instance ((GTypeInstance *) node);
self->nodes[node_type].count ++;
self->count ++;
}
void
node_sample_print (const NodeSample *self,
const char *prefix)
{
guint i;
g_printf ("%s:\n", prefix);
for (i = 0; i < N_NODE_TYPES; i ++)
{
if (self->nodes[i].count > 0)
{
double p = (double)self->nodes[i].count / (double)self->count;
g_printf ("%s: %u (%.2f%%)\n", self->nodes[i].class_name, self->nodes[i].count, p * 100.0);
}
}
}
+28
View File
@@ -0,0 +1,28 @@
#ifndef __GSK_GL_NODE_SAMPLE_PRIVATE_H__
#define __GSK_GL_NODE_SAMPLE_PRIVATE_H__
#include <glib.h>
#include "gskenums.h"
#include "gskrendernode.h"
/* TODO: We have no other way for this...? */
#define N_NODE_TYPES (GSK_DEBUG_NODE + 1)
typedef struct
{
struct {
const char *class_name;
guint count;
} nodes[N_NODE_TYPES];
guint count;
} NodeSample;
void node_sample_init (NodeSample *self);
void node_sample_reset (NodeSample *self);
void node_sample_add (NodeSample *self,
GskRenderNode *node);
void node_sample_print (const NodeSample *self,
const char *prefix);
#endif
File diff suppressed because it is too large Load Diff
+52
View File
@@ -0,0 +1,52 @@
/*
* Copyright © 2016 Endless
* 2018 Timm Bäder <mail@baedert.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.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/>.
*
* Authors: Timm Bäder <mail@baedert.org>
*/
#ifndef __GSK_GL_RENDERER_H__
#define __GSK_GL_RENDERER_H__
#include <gsk/gskrenderer.h>
G_BEGIN_DECLS
#define GSK_TYPE_GL_RENDERER (gsk_gl_renderer_get_type ())
#define GSK_GL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_GL_RENDERER, GskGLRenderer))
#define GSK_IS_GL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_GL_RENDERER))
#define GSK_GL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_GL_RENDERER, GskGLRendererClass))
#define GSK_IS_GL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_GL_RENDERER))
#define GSK_GL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_GL_RENDERER, GskGLRendererClass))
/**
* GskGLRenderer:
*
* A GSK renderer that is using OpenGL.
*/
typedef struct _GskGLRenderer GskGLRenderer;
typedef struct _GskGLRendererClass GskGLRendererClass;
GDK_AVAILABLE_IN_ALL
GType gsk_gl_renderer_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GskRenderer * gsk_gl_renderer_new (void);
G_END_DECLS
#endif /* __GSK_GL_RENDERER_H__ */
+14
View File
@@ -0,0 +1,14 @@
#ifndef __GSK_GL_RENDERER_PRIVATE_H__
#define __GSK_GL_RENDERER_PRIVATE_H__
#include "gskglrenderer.h"
G_BEGIN_DECLS
gboolean gsk_gl_renderer_try_compile_gl_shader (GskGLRenderer *self,
GskGLShader *shader,
GError **error);
G_END_DECLS
#endif /* __GSK_GL_RENDERER_PRIVATE_H__ */
+976
View File
@@ -0,0 +1,976 @@
#include "gskglrenderopsprivate.h"
#include "gsktransform.h"
typedef struct
{
GskRoundedRect rect;
bool is_rectilinear;
} ClipStackEntry;
static inline gboolean
rect_equal (const graphene_rect_t *a,
const graphene_rect_t *b)
{
return memcmp (a, b, sizeof (graphene_rect_t)) == 0;
}
static inline bool G_GNUC_PURE
rounded_rect_equal (const GskRoundedRect *r1,
const GskRoundedRect *r2)
{
if (r1 == r2)
return true;
if (!r1)
return false;
if (r1->bounds.origin.x != r2->bounds.origin.x ||
r1->bounds.origin.y != r2->bounds.origin.y ||
r1->bounds.size.width != r2->bounds.size.width ||
r1->bounds.size.height != r2->bounds.size.height)
return false;
for (int i = 0; i < 4; i ++)
if (r1->corner[i].width != r2->corner[i].width ||
r1->corner[i].height != r2->corner[i].height)
return false;
return true;
}
static inline gboolean G_GNUC_PURE
rounded_rect_corners_equal (const GskRoundedRect *r1,
const GskRoundedRect *r2)
{
int i;
if (!r1)
return FALSE;
for (i = 0; i < 4; i ++)
if (r1->corner[i].width != r2->corner[i].width ||
r1->corner[i].height != r2->corner[i].height)
return FALSE;
return TRUE;
}
static inline ProgramState *
get_current_program_state (RenderOpBuilder *builder)
{
if (!builder->current_program)
return NULL;
return &builder->current_program->state;
}
void
ops_finish (RenderOpBuilder *builder)
{
if (builder->mv_stack)
g_array_free (builder->mv_stack, TRUE);
builder->mv_stack = NULL;
if (builder->clip_stack)
g_array_free (builder->clip_stack, TRUE);
builder->clip_stack = NULL;
builder->dx = 0;
builder->dy = 0;
builder->scale_x = 1;
builder->scale_y = 1;
builder->current_modelview = NULL;
builder->current_clip = NULL;
builder->clip_is_rectilinear = TRUE;
builder->current_render_target = 0;
builder->current_texture = 0;
builder->current_program = NULL;
graphene_matrix_init_identity (&builder->current_projection);
builder->current_viewport = GRAPHENE_RECT_INIT (0, 0, 0, 0);
}
/* Debugging only! */
void
ops_dump_framebuffer (RenderOpBuilder *builder,
const char *filename,
int width,
int height)
{
OpDumpFrameBuffer *op;
op = ops_begin (builder, OP_DUMP_FRAMEBUFFER);
op->filename = g_strdup (filename);
op->width = width;
op->height = height;
}
void
ops_push_debug_group (RenderOpBuilder *builder,
const char *text)
{
OpDebugGroup *op;
op = ops_begin (builder, OP_PUSH_DEBUG_GROUP);
strncpy (op->text, text, sizeof(op->text) - 1);
op->text[sizeof(op->text) - 1] = 0; /* Ensure zero terminated */
}
void
ops_pop_debug_group (RenderOpBuilder *builder)
{
ops_begin (builder, OP_POP_DEBUG_GROUP);
}
static void
extract_matrix_metadata (GskTransform *transform,
OpsMatrixMetadata *md)
{
float dummy;
switch (gsk_transform_get_category (transform))
{
case GSK_TRANSFORM_CATEGORY_IDENTITY:
case GSK_TRANSFORM_CATEGORY_2D_TRANSLATE:
md->scale_x = 1;
md->scale_y = 1;
break;
case GSK_TRANSFORM_CATEGORY_2D_AFFINE:
gsk_transform_to_affine (transform,
&md->scale_x, &md->scale_y,
&dummy, &dummy);
break;
case GSK_TRANSFORM_CATEGORY_UNKNOWN:
case GSK_TRANSFORM_CATEGORY_ANY:
case GSK_TRANSFORM_CATEGORY_3D:
case GSK_TRANSFORM_CATEGORY_2D:
{
graphene_vec3_t col1;
graphene_vec3_t col2;
graphene_matrix_t m;
gsk_transform_to_matrix (transform, &m);
/* TODO: 90% sure this is incorrect. But we should never hit this code
* path anyway. */
graphene_vec3_init (&col1,
graphene_matrix_get_value (&m, 0, 0),
graphene_matrix_get_value (&m, 1, 0),
graphene_matrix_get_value (&m, 2, 0));
graphene_vec3_init (&col2,
graphene_matrix_get_value (&m, 0, 1),
graphene_matrix_get_value (&m, 1, 1),
graphene_matrix_get_value (&m, 2, 1));
md->scale_x = graphene_vec3_length (&col1);
md->scale_y = graphene_vec3_length (&col2);
}
break;
default:
{}
}
}
void
ops_transform_bounds_modelview (const RenderOpBuilder *builder,
const graphene_rect_t *src,
graphene_rect_t *dst)
{
graphene_rect_t r = *src;
g_assert (builder->mv_stack != NULL);
g_assert (builder->mv_stack->len >= 1);
r.origin.x += builder->dx;
r.origin.y += builder->dy;
gsk_transform_transform_bounds (builder->current_modelview, &r, dst);
}
void
ops_init (RenderOpBuilder *builder)
{
memset (builder, 0, sizeof (*builder));
builder->current_opacity = 1.0f;
op_buffer_init (&builder->render_ops);
builder->vertices = g_array_new (FALSE, TRUE, sizeof (GskQuadVertex));
}
void
ops_free (RenderOpBuilder *builder)
{
g_array_unref (builder->vertices);
op_buffer_destroy (&builder->render_ops);
}
void
ops_set_program (RenderOpBuilder *builder,
Program *program)
{
OpProgram *op;
if (builder->current_program == program)
return;
op = ops_begin (builder, OP_CHANGE_PROGRAM);
op->program = program;
builder->current_program = program;
}
void
ops_push_clip (RenderOpBuilder *self,
const GskRoundedRect *clip)
{
ClipStackEntry entry;
if (G_UNLIKELY (self->clip_stack == NULL))
self->clip_stack = g_array_new (FALSE, TRUE, sizeof (ClipStackEntry));
g_assert (self->clip_stack != NULL);
entry.rect = *clip;
entry.is_rectilinear = gsk_rounded_rect_is_rectilinear (clip);
g_array_append_val (self->clip_stack, entry);
self->current_clip = &g_array_index (self->clip_stack, ClipStackEntry, self->clip_stack->len - 1).rect;
self->clip_is_rectilinear = entry.is_rectilinear;
}
void
ops_pop_clip (RenderOpBuilder *self)
{
const ClipStackEntry *head;
g_assert (self->clip_stack);
g_assert (self->clip_stack->len >= 1);
self->clip_stack->len --;
head = &g_array_index (self->clip_stack, ClipStackEntry, self->clip_stack->len - 1);
if (self->clip_stack->len >= 1)
{
self->current_clip = &head->rect;
self->clip_is_rectilinear = head->is_rectilinear;
}
else
{
self->current_clip = NULL;
self->clip_is_rectilinear = TRUE;
}
}
gboolean
ops_has_clip (RenderOpBuilder *self)
{
return self->clip_stack != NULL &&
self->clip_stack->len > 1;
}
/**
* ops_set_modelview:
* @builder
* @transform: (transfer full): The new modelview transform
*
* This sets the modelview to the given one without looking at the
* one that's currently set */
void
ops_set_modelview (RenderOpBuilder *builder,
GskTransform *transform)
{
MatrixStackEntry *entry;
if (G_UNLIKELY (builder->mv_stack == NULL))
builder->mv_stack = g_array_new (FALSE, TRUE, sizeof (MatrixStackEntry));
g_assert (builder->mv_stack != NULL);
g_array_set_size (builder->mv_stack, builder->mv_stack->len + 1);
entry = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
entry->transform = transform;
entry->metadata.dx_before = builder->dx;
entry->metadata.dy_before = builder->dy;
extract_matrix_metadata (entry->transform, &entry->metadata);
builder->dx = 0;
builder->dy = 0;
builder->current_modelview = entry->transform;
builder->scale_x = entry->metadata.scale_x;
builder->scale_y = entry->metadata.scale_y;
}
/* This sets the given modelview to the one we get when multiplying
* the given modelview with the current one. */
void
ops_push_modelview (RenderOpBuilder *builder,
GskTransform *transform)
{
MatrixStackEntry *entry;
if (G_UNLIKELY (builder->mv_stack == NULL))
builder->mv_stack = g_array_new (FALSE, TRUE, sizeof (MatrixStackEntry));
g_assert (builder->mv_stack != NULL);
g_array_set_size (builder->mv_stack, builder->mv_stack->len + 1);
entry = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
if (G_LIKELY (builder->mv_stack->len >= 2))
{
const MatrixStackEntry *cur;
GskTransform *t = NULL;
cur = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 2);
/* Multiply given matrix with current modelview */
t = gsk_transform_translate (gsk_transform_ref (cur->transform),
&(graphene_point_t) { builder->dx, builder->dy});
t = gsk_transform_transform (t, transform);
entry->transform = t;
}
else
{
entry->transform = gsk_transform_ref (transform);
}
entry->metadata.dx_before = builder->dx;
entry->metadata.dy_before = builder->dy;
extract_matrix_metadata (entry->transform, &entry->metadata);
builder->dx = 0;
builder->dy = 0;
builder->scale_x = entry->metadata.scale_x;
builder->scale_y = entry->metadata.scale_y;
builder->current_modelview = entry->transform;
}
void
ops_pop_modelview (RenderOpBuilder *builder)
{
const MatrixStackEntry *head;
g_assert (builder->mv_stack);
g_assert (builder->mv_stack->len >= 1);
head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
builder->dx = head->metadata.dx_before;
builder->dy = head->metadata.dy_before;
gsk_transform_unref (head->transform);
builder->mv_stack->len --;
head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
if (builder->mv_stack->len >= 1)
{
builder->scale_x = head->metadata.scale_x;
builder->scale_y = head->metadata.scale_y;
builder->current_modelview = head->transform;
}
else
{
builder->current_modelview = NULL;
}
}
graphene_matrix_t
ops_set_projection (RenderOpBuilder *builder,
const graphene_matrix_t *projection)
{
graphene_matrix_t prev_mv;
prev_mv = builder->current_projection;
builder->current_projection = *projection;
return prev_mv;
}
graphene_rect_t
ops_set_viewport (RenderOpBuilder *builder,
const graphene_rect_t *viewport)
{
ProgramState *current_program_state = get_current_program_state (builder);
OpViewport *op;
graphene_rect_t prev_viewport;
if (rect_equal (&builder->current_viewport, viewport))
return *viewport;
op = ops_begin (builder, OP_CHANGE_VIEWPORT);
op->viewport = *viewport;
if (current_program_state != NULL)
current_program_state->viewport = *viewport;
prev_viewport = builder->current_viewport;
builder->current_viewport = *viewport;
return prev_viewport;
}
void
ops_set_texture (RenderOpBuilder *builder,
int texture_id)
{
OpTexture *op;
if (builder->current_texture == texture_id)
return;
op = ops_begin (builder, OP_CHANGE_SOURCE_TEXTURE);
op->texture_id = texture_id;
builder->current_texture = texture_id;
}
void
ops_set_extra_texture (RenderOpBuilder *builder,
int texture_id,
int idx)
{
OpExtraTexture *op;
op = ops_begin (builder, OP_CHANGE_EXTRA_SOURCE_TEXTURE);
op->texture_id = texture_id;
op->idx = idx;
}
int
ops_set_render_target (RenderOpBuilder *builder,
int render_target_id)
{
OpRenderTarget *op;
int prev_render_target;
if (builder->current_render_target == render_target_id)
return render_target_id;
prev_render_target = builder->current_render_target;
if (!(op = op_buffer_peek_tail_checked (&builder->render_ops, OP_CHANGE_RENDER_TARGET)))
op = op_buffer_add (&builder->render_ops, OP_CHANGE_RENDER_TARGET);
op->render_target_id = render_target_id;
builder->current_render_target = render_target_id;
return prev_render_target;
}
float
ops_set_opacity (RenderOpBuilder *builder,
float opacity)
{
float prev_opacity;
if (builder->current_opacity == opacity)
return opacity;
prev_opacity = builder->current_opacity;
builder->current_opacity = opacity;
return prev_opacity;
}
void
ops_set_color (RenderOpBuilder *builder,
const GdkRGBA *color)
{
ProgramState *current_program_state = get_current_program_state (builder);
OpColor *op;
if (gdk_rgba_equal (color, &current_program_state->color))
return;
current_program_state->color = *color;
op = ops_begin (builder, OP_CHANGE_COLOR);
op->rgba = color;
}
void
ops_set_gl_shader_args (RenderOpBuilder *builder,
GskGLShader *shader,
float width,
float height,
const guchar *uniform_data)
{
ProgramState *current_program_state = get_current_program_state (builder);
OpGLShader *op;
gsize args_size = gsk_gl_shader_get_args_size (shader);
if (current_program_state)
{
if (current_program_state->gl_shader.width == width &&
current_program_state->gl_shader.height == height &&
current_program_state->gl_shader.uniform_data_len == args_size &&
memcmp (current_program_state->gl_shader.uniform_data, uniform_data, args_size) == 0)
return;
current_program_state->gl_shader.width = width;
current_program_state->gl_shader.height = height;
if (args_size > sizeof (current_program_state->gl_shader.uniform_data))
current_program_state->gl_shader.uniform_data_len = 0;
else
{
current_program_state->gl_shader.uniform_data_len = args_size;
memcpy (current_program_state->gl_shader.uniform_data, uniform_data, args_size);
}
}
op = ops_begin (builder, OP_CHANGE_GL_SHADER_ARGS);
op->shader = shader;
op->size[0] = width;
op->size[1] = height;
op->uniform_data = uniform_data;
}
void
ops_set_color_matrix (RenderOpBuilder *builder,
const graphene_matrix_t *matrix,
const graphene_vec4_t *offset)
{
ProgramState *current_program_state = get_current_program_state (builder);
const bool offset_equal = graphene_vec4_equal (offset, &current_program_state->color_matrix.offset);
const bool matrix_equal = graphene_matrix_equal_fast (matrix,
&current_program_state->color_matrix.matrix);
OpColorMatrix *op;
if (offset_equal && matrix_equal)
return;
op = ops_begin (builder, OP_CHANGE_COLOR_MATRIX);
if (!matrix_equal)
{
current_program_state->color_matrix.matrix = *matrix;
op->matrix.value = matrix;
op->matrix.send = TRUE;
}
else
op->matrix.send = FALSE;
if (!offset_equal)
{
current_program_state->color_matrix.offset = *offset;
op->offset.value = offset;
op->offset.send = TRUE;
}
else
op->offset.send = FALSE;
}
void
ops_set_border (RenderOpBuilder *builder,
const GskRoundedRect *outline)
{
ProgramState *current_program_state = get_current_program_state (builder);
OpBorder *op;
if (memcmp (&current_program_state->border.outline,
outline, sizeof (GskRoundedRect)) == 0)
return;
current_program_state->border.outline = *outline;
op = ops_begin (builder, OP_CHANGE_BORDER);
op->outline = *outline;
}
void
ops_set_border_width (RenderOpBuilder *builder,
const float *widths)
{
ProgramState *current_program_state = get_current_program_state (builder);
OpBorder *op;
g_assert (current_program_state);
if (memcmp (current_program_state->border.widths,
widths, sizeof (float) * 4) == 0)
return;
memcpy (&current_program_state->border.widths,
widths, sizeof (float) * 4);
op = ops_begin (builder, OP_CHANGE_BORDER_WIDTH);
op->widths[0] = widths[0];
op->widths[1] = widths[1];
op->widths[2] = widths[2];
op->widths[3] = widths[3];
}
void
ops_set_border_color (RenderOpBuilder *builder,
const GdkRGBA *color)
{
ProgramState *current_program_state = get_current_program_state (builder);
OpBorder *op;
if (gdk_rgba_equal (color, &current_program_state->border.color))
return;
op = op_buffer_add (&builder->render_ops, OP_CHANGE_BORDER_COLOR);
op->color = color;
current_program_state->border.color = *color;
}
GskQuadVertex *
ops_draw (RenderOpBuilder *builder,
const GskQuadVertex vertex_data[GL_N_VERTICES])
{
ProgramState *program_state = get_current_program_state (builder);
OpDraw *op;
if (memcmp (&builder->current_projection, &program_state->projection, sizeof (graphene_matrix_t)) != 0)
{
OpMatrix *opm;
opm = ops_begin (builder, OP_CHANGE_PROJECTION);
opm->matrix = builder->current_projection;
program_state->projection = builder->current_projection;
}
if (program_state->modelview == NULL ||
!gsk_transform_equal (builder->current_modelview, program_state->modelview))
{
OpMatrix *opm;
opm = ops_begin (builder, OP_CHANGE_MODELVIEW);
gsk_transform_to_matrix (builder->current_modelview, &opm->matrix);
gsk_transform_unref (program_state->modelview);
program_state->modelview = gsk_transform_ref (builder->current_modelview);
}
if (!rect_equal (&builder->current_viewport, &program_state->viewport))
{
OpViewport *opv;
opv = ops_begin (builder, OP_CHANGE_VIEWPORT);
opv->viewport = builder->current_viewport;
program_state->viewport = builder->current_viewport;
}
if (!rounded_rect_equal (builder->current_clip, &program_state->clip))
{
OpClip *opc;
opc = ops_begin (builder, OP_CHANGE_CLIP);
opc->clip = *builder->current_clip;
opc->send_corners = !rounded_rect_corners_equal (builder->current_clip, &program_state->clip);
program_state->clip = *builder->current_clip;
}
if (program_state->opacity != builder->current_opacity)
{
OpOpacity *opo;
opo = ops_begin (builder, OP_CHANGE_OPACITY);
opo->opacity = builder->current_opacity;
program_state->opacity = builder->current_opacity;
}
/* TODO: Did the additions above break the following optimization? */
if ((op = op_buffer_peek_tail_checked (&builder->render_ops, OP_DRAW)))
{
op->vao_size += GL_N_VERTICES;
}
else
{
op = op_buffer_add (&builder->render_ops, OP_DRAW);
op->vao_offset = builder->vertices->len;
op->vao_size = GL_N_VERTICES;
}
if (vertex_data)
{
g_array_append_vals (builder->vertices, vertex_data, GL_N_VERTICES);
return NULL; /* Better not use this on the caller side */
}
g_array_set_size (builder->vertices, builder->vertices->len + GL_N_VERTICES);
return &g_array_index (builder->vertices, GskQuadVertex, builder->vertices->len - GL_N_VERTICES);
}
/* The offset is only valid for the current modelview.
* Setting a new modelview will add the offset to that matrix
* and reset the internal offset to 0. */
void
ops_offset (RenderOpBuilder *builder,
float x,
float y)
{
builder->dx += x;
builder->dy += y;
}
gpointer
ops_begin (RenderOpBuilder *builder,
OpKind kind)
{
return op_buffer_add (&builder->render_ops, kind);
}
void
ops_reset (RenderOpBuilder *builder)
{
op_buffer_clear (&builder->render_ops);
g_array_set_size (builder->vertices, 0);
}
OpBuffer *
ops_get_buffer (RenderOpBuilder *builder)
{
return &builder->render_ops;
}
void
ops_set_inset_shadow (RenderOpBuilder *self,
const GskRoundedRect outline,
float spread,
const GdkRGBA *color,
float dx,
float dy)
{
ProgramState *current_program_state = get_current_program_state (self);
OpShadow *op;
g_assert (current_program_state);
op = ops_begin (self, OP_CHANGE_INSET_SHADOW);
if (!rounded_rect_equal (&outline, &current_program_state->inset_shadow.outline))
{
op->outline.value = outline;
op->outline.send = TRUE;
op->outline.send_corners = !rounded_rect_corners_equal (&current_program_state->inset_shadow.outline,
&outline);
current_program_state->inset_shadow.outline = outline;
}
else
op->outline.send = FALSE;
if (spread != current_program_state->inset_shadow.spread)
{
op->spread.value = spread;
op->spread.send = TRUE;
current_program_state->inset_shadow.spread = spread;
}
else
op->spread.send = FALSE;
if (!gdk_rgba_equal (color, &current_program_state->inset_shadow.color))
{
op->color.value = color;
op->color.send = TRUE;
current_program_state->inset_shadow.color = *color;
}
else
op->color.send = FALSE;
if (dx != current_program_state->inset_shadow.dx ||
dy != current_program_state->inset_shadow.dy)
{
op->offset.value[0] = dx;
op->offset.value[1] = dy;
op->offset.send = TRUE;
current_program_state->inset_shadow.dx = dx;
current_program_state->inset_shadow.dy = dy;
}
else
op->offset.send = FALSE;
if (!op->outline.send &&
!op->spread.send &&
!op->offset.send &&
!op->color.send)
{
op_buffer_pop_tail (&self->render_ops);
}
}
void
ops_set_unblurred_outset_shadow (RenderOpBuilder *self,
const GskRoundedRect outline,
float spread,
const GdkRGBA *color,
float dx,
float dy)
{
ProgramState *current_program_state = get_current_program_state (self);
OpShadow *op;
g_assert (current_program_state);
op = ops_begin (self, OP_CHANGE_UNBLURRED_OUTSET_SHADOW);
if (!rounded_rect_equal (&outline, &current_program_state->unblurred_outset_shadow.outline))
{
op->outline.value = outline;
op->outline.send = TRUE;
op->outline.send_corners = !rounded_rect_corners_equal (&current_program_state->unblurred_outset_shadow.outline,
&outline);
current_program_state->unblurred_outset_shadow.outline = outline;
}
else
op->outline.send = FALSE;
if (spread != current_program_state->unblurred_outset_shadow.spread)
{
op->spread.value = spread;
op->spread.send = TRUE;
current_program_state->unblurred_outset_shadow.spread = spread;
}
else
op->spread.send = FALSE;
if (!gdk_rgba_equal (color, &current_program_state->unblurred_outset_shadow.color))
{
op->color.value = color;
op->color.send = TRUE;
current_program_state->unblurred_outset_shadow.color = *color;
}
else
op->color.send = FALSE;
if (dx != current_program_state->unblurred_outset_shadow.dx ||
dy != current_program_state->unblurred_outset_shadow.dy)
{
op->offset.value[0] = dx;
op->offset.value[1] = dy;
op->offset.send = TRUE;
current_program_state->unblurred_outset_shadow.dx = dx;
current_program_state->unblurred_outset_shadow.dy = dy;
}
else
op->offset.send = FALSE;
}
void
ops_set_linear_gradient (RenderOpBuilder *self,
guint n_color_stops,
const GskColorStop *color_stops,
gboolean repeat,
float start_x,
float start_y,
float end_x,
float end_y)
{
ProgramState *current_program_state = get_current_program_state (self);
OpLinearGradient *op;
const guint real_n_color_stops = MIN (GL_MAX_GRADIENT_STOPS, n_color_stops);
g_assert (current_program_state);
op = ops_begin (self, OP_CHANGE_LINEAR_GRADIENT);
/* We always save the n_color_stops value in the op so the renderer can use it in
* cases where we send the color stops, but not n_color_stops */
op->n_color_stops.value = real_n_color_stops;
if (current_program_state->linear_gradient.n_color_stops != real_n_color_stops)
{
op->n_color_stops.send = TRUE;
current_program_state->linear_gradient.n_color_stops = real_n_color_stops;
}
else
op->n_color_stops.send = FALSE;
op->color_stops.send = FALSE;
if (!op->n_color_stops.send)
{
g_assert (current_program_state->linear_gradient.n_color_stops == real_n_color_stops);
for (guint i = 0; i < real_n_color_stops; i ++)
{
const GskColorStop *s1 = &color_stops[i];
const GskColorStop *s2 = &current_program_state->linear_gradient.color_stops[i];
if (s1->offset != s2->offset ||
!gdk_rgba_equal (&s1->color, &s2->color))
{
op->color_stops.send = TRUE;
break;
}
}
}
else
op->color_stops.send = TRUE;
if (op->color_stops.send)
{
op->color_stops.value = color_stops;
memcpy (&current_program_state->linear_gradient.color_stops,
color_stops,
sizeof (GskColorStop) * real_n_color_stops);
}
op->repeat = repeat;
op->start_point[0] = start_x;
op->start_point[1] = start_y;
op->end_point[0] = end_x;
op->end_point[1] = end_y;
}
void
ops_set_radial_gradient (RenderOpBuilder *self,
guint n_color_stops,
const GskColorStop *color_stops,
gboolean repeat,
float center_x,
float center_y,
float start,
float end,
float hradius,
float vradius)
{
const guint real_n_color_stops = MIN (GL_MAX_GRADIENT_STOPS, n_color_stops);
OpRadialGradient *op;
/* TODO: State tracking? */
op = ops_begin (self, OP_CHANGE_RADIAL_GRADIENT);
op->n_color_stops.value = real_n_color_stops;
op->n_color_stops.send = true;
op->color_stops.value = color_stops;
op->color_stops.send = true;
op->center[0] = center_x;
op->center[1] = center_y;
op->radius[0] = hradius;
op->radius[1] = vradius;
op->start = start;
op->end = end;
op->repeat = repeat;
}
void
ops_set_conic_gradient (RenderOpBuilder *self,
guint n_color_stops,
const GskColorStop *color_stops,
float center_x,
float center_y,
float angle)
{
const guint real_n_color_stops = MIN (GL_MAX_GRADIENT_STOPS, n_color_stops);
OpConicGradient *op;
/* TODO: State tracking? */
op = ops_begin (self, OP_CHANGE_CONIC_GRADIENT);
op->n_color_stops.value = real_n_color_stops;
op->n_color_stops.send = true;
op->color_stops.value = color_stops;
op->color_stops.send = true;
op->center[0] = center_x;
op->center[1] = center_y;
op->angle = angle;
}
+353
View File
@@ -0,0 +1,353 @@
#ifndef __GSK_GL_RENDER_OPS_H__
#define __GSK_GL_RENDER_OPS_H__
#include <glib.h>
#include <graphene.h>
#include <gdk/gdk.h>
#include "gskgldriverprivate.h"
#include "gskroundedrectprivate.h"
#include "gskglrenderer.h"
#include "gskrendernodeprivate.h"
#include "opbuffer.h"
#define GL_N_VERTICES 6
#define GL_N_PROGRAMS 15
#define GL_MAX_GRADIENT_STOPS 6
typedef struct
{
float scale_x;
float scale_y;
float dx_before;
float dy_before;
} OpsMatrixMetadata;
typedef struct
{
GskTransform *transform;
OpsMatrixMetadata metadata;
} MatrixStackEntry;
typedef struct
{
GskTransform *modelview;
GskRoundedRect clip;
graphene_matrix_t projection;
int source_texture;
graphene_rect_t viewport;
float opacity;
/* Per-program state */
union {
GdkRGBA color;
struct {
graphene_matrix_t matrix;
graphene_vec4_t offset;
} color_matrix;
struct {
float widths[4];
GdkRGBA color;
GskRoundedRect outline;
} border;
struct {
GskRoundedRect outline;
float dx;
float dy;
float spread;
GdkRGBA color;
} inset_shadow;
struct {
GskRoundedRect outline;
float dx;
float dy;
float spread;
GdkRGBA color;
} unblurred_outset_shadow;
struct {
int n_color_stops;
GskColorStop color_stops[GL_MAX_GRADIENT_STOPS];
float start_point[2];
float end_point[2];
} linear_gradient;
struct {
int n_color_stops;
GskColorStop color_stops[GL_MAX_GRADIENT_STOPS];
float center[2];
float start;
float end;
float radius[2]; /* h/v */
} radial_gradient;
struct {
float width;
float height;
int uniform_data_len;
guchar uniform_data[32];
} gl_shader;
};
} ProgramState;
struct _Program
{
const char *name;
int index; /* Into the renderer's program array -1 for custom */
int id;
/* Common locations (gl_common)*/
int source_location;
int position_location;
int uv_location;
int alpha_location;
int viewport_location;
int projection_location;
int modelview_location;
int clip_rect_location;
union {
struct {
int color_location;
} color;
struct {
int color_location;
} coloring;
struct {
int color_matrix_location;
int color_offset_location;
} color_matrix;
struct {
int num_color_stops_location;
int color_stops_location;
int points_location;
int repeat_location;
} linear_gradient;
struct {
int num_color_stops_location;
int color_stops_location;
int geometry_location;
int range_location;
int repeat_location;
} radial_gradient;
struct {
int num_color_stops_location;
int color_stops_location;
int geometry_location;
} conic_gradient;
struct {
int blur_radius_location;
int blur_size_location;
int blur_dir_location;
} blur;
struct {
int color_location;
int spread_location;
int offset_location;
int outline_rect_location;
} inset_shadow;
struct {
int color_location;
int outline_rect_location;
} outset_shadow;
struct {
int outline_rect_location;
int color_location;
int spread_location;
int offset_location;
} unblurred_outset_shadow;
struct {
int color_location;
int widths_location;
int outline_rect_location;
} border;
struct {
int source2_location;
int progress_location;
} cross_fade;
struct {
int source2_location;
int mode_location;
} blend;
struct {
int child_bounds_location;
int texture_rect_location;
} repeat;
struct {
int size_location;
int args_locations[8];
int texture_locations[4];
GError *compile_error;
} glshader;
};
ProgramState state;
};
typedef struct {
int ref_count;
union {
Program programs[GL_N_PROGRAMS];
struct {
Program blend_program;
Program blit_program;
Program blur_program;
Program border_program;
Program color_matrix_program;
Program color_program;
Program coloring_program;
Program cross_fade_program;
Program inset_shadow_program;
Program linear_gradient_program;
Program radial_gradient_program;
Program conic_gradient_program;
Program outset_shadow_program;
Program repeat_program;
Program unblurred_outset_shadow_program;
};
};
GHashTable *custom_programs; /* GskGLShader -> Program* */
} GskGLRendererPrograms;
typedef struct
{
GskGLRendererPrograms *programs;
Program *current_program;
int current_render_target;
int current_texture;
graphene_matrix_t current_projection;
graphene_rect_t current_viewport;
float current_opacity;
float dx, dy;
float scale_x, scale_y;
OpBuffer render_ops;
GArray *vertices;
GskGLRenderer *renderer;
/* Stack of modelview matrices */
GArray *mv_stack;
GskTransform *current_modelview;
/* Same thing */
GArray *clip_stack;
/* Pointer into clip_stack */
const GskRoundedRect *current_clip;
bool clip_is_rectilinear;
} RenderOpBuilder;
void ops_dump_framebuffer (RenderOpBuilder *builder,
const char *filename,
int width,
int height);
void ops_init (RenderOpBuilder *builder);
void ops_free (RenderOpBuilder *builder);
void ops_reset (RenderOpBuilder *builder);
void ops_push_debug_group (RenderOpBuilder *builder,
const char *text);
void ops_pop_debug_group (RenderOpBuilder *builder);
void ops_finish (RenderOpBuilder *builder);
void ops_push_modelview (RenderOpBuilder *builder,
GskTransform *transform);
void ops_set_modelview (RenderOpBuilder *builder,
GskTransform *transform);
void ops_pop_modelview (RenderOpBuilder *builder);
void ops_set_program (RenderOpBuilder *builder,
Program *program);
void ops_push_clip (RenderOpBuilder *builder,
const GskRoundedRect *clip);
void ops_pop_clip (RenderOpBuilder *builder);
gboolean ops_has_clip (RenderOpBuilder *builder);
void ops_transform_bounds_modelview (const RenderOpBuilder *builder,
const graphene_rect_t *src,
graphene_rect_t *dst);
graphene_matrix_t ops_set_projection (RenderOpBuilder *builder,
const graphene_matrix_t *projection);
graphene_rect_t ops_set_viewport (RenderOpBuilder *builder,
const graphene_rect_t *viewport);
void ops_set_texture (RenderOpBuilder *builder,
int texture_id);
void ops_set_extra_texture (RenderOpBuilder *builder,
int texture_id,
int idx);
int ops_set_render_target (RenderOpBuilder *builder,
int render_target_id);
float ops_set_opacity (RenderOpBuilder *builder,
float opacity);
void ops_set_color (RenderOpBuilder *builder,
const GdkRGBA *color);
void ops_set_color_matrix (RenderOpBuilder *builder,
const graphene_matrix_t *matrix,
const graphene_vec4_t *offset);
void ops_set_border (RenderOpBuilder *builder,
const GskRoundedRect *outline);
void ops_set_border_width (RenderOpBuilder *builder,
const float *widths);
void ops_set_border_color (RenderOpBuilder *builder,
const GdkRGBA *color);
void ops_set_inset_shadow (RenderOpBuilder *self,
const GskRoundedRect outline,
float spread,
const GdkRGBA *color,
float dx,
float dy);
void ops_set_gl_shader_args (RenderOpBuilder *builder,
GskGLShader *shader,
float width,
float height,
const guchar *uniform_data);
void ops_set_unblurred_outset_shadow (RenderOpBuilder *self,
const GskRoundedRect outline,
float spread,
const GdkRGBA *color,
float dx,
float dy);
void ops_set_linear_gradient (RenderOpBuilder *self,
guint n_color_stops,
const GskColorStop *color_stops,
gboolean repeat,
float start_x,
float start_y,
float end_x,
float end_y);
void ops_set_radial_gradient (RenderOpBuilder *self,
guint n_color_stops,
const GskColorStop *color_stops,
gboolean repeat,
float center_x,
float center_y,
float start,
float end,
float hradius,
float vradius);
void ops_set_conic_gradient (RenderOpBuilder *self,
guint n_color_stops,
const GskColorStop *color_stops,
float center_x,
float center_y,
float angle);
GskQuadVertex * ops_draw (RenderOpBuilder *builder,
const GskQuadVertex vertex_data[GL_N_VERTICES]);
void ops_offset (RenderOpBuilder *builder,
float x,
float y);
gpointer ops_begin (RenderOpBuilder *builder,
OpKind kind);
OpBuffer *ops_get_buffer (RenderOpBuilder *builder);
#endif
+271
View File
@@ -0,0 +1,271 @@
#include "config.h"
#include "gskglshaderbuilderprivate.h"
#include "gskdebugprivate.h"
#include <gdk/gdk.h>
#include <epoxy/gl.h>
void
gsk_gl_shader_builder_init (GskGLShaderBuilder *self,
const char *common_preamble_resource_path,
const char *vs_preamble_resource_path,
const char *fs_preamble_resource_path)
{
memset (self, 0, sizeof (*self));
self->preamble = g_resources_lookup_data (common_preamble_resource_path, 0, NULL);
self->vs_preamble = g_resources_lookup_data (vs_preamble_resource_path, 0, NULL);
self->fs_preamble = g_resources_lookup_data (fs_preamble_resource_path, 0, NULL);
g_assert (self->preamble);
g_assert (self->vs_preamble);
g_assert (self->fs_preamble);
}
void
gsk_gl_shader_builder_finish (GskGLShaderBuilder *self)
{
g_bytes_unref (self->preamble);
g_bytes_unref (self->vs_preamble);
g_bytes_unref (self->fs_preamble);
}
void
gsk_gl_shader_builder_set_glsl_version (GskGLShaderBuilder *self,
int version)
{
self->version = version;
}
static void
prepend_line_numbers (char *code,
GString *s)
{
char *p;
int line;
p = code;
line = 1;
while (*p)
{
char *end = strchr (p, '\n');
if (end)
end = end + 1; /* Include newline */
else
end = p + strlen (p);
g_string_append_printf (s, "%3d| ", line++);
g_string_append_len (s, p, end - p);
p = end;
}
}
static gboolean
check_shader_error (int shader_id,
int shader_type,
const char *resource_path,
GError **error)
{
int status;
int log_len;
char *buffer;
int code_len;
char *code;
GString *s;
glGetShaderiv (shader_id, GL_COMPILE_STATUS, &status);
if (G_LIKELY (status == GL_TRUE))
return TRUE;
glGetShaderiv (shader_id, GL_INFO_LOG_LENGTH, &log_len);
buffer = g_malloc0 (log_len + 1);
glGetShaderInfoLog (shader_id, log_len, NULL, buffer);
glGetShaderiv (shader_id, GL_SHADER_SOURCE_LENGTH, &code_len);
code = g_malloc0 (code_len + 1);
glGetShaderSource (shader_id, code_len, NULL, code);
s = g_string_new ("");
prepend_line_numbers (code, s);
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_COMPILATION_FAILED,
"Compilation failure in %s shader %s.\nSource Code:\n%s\n\nError Message:\n%s\n\n",
(shader_type == GL_FRAGMENT_SHADER ? "fragment" : "vertex"),
resource_path,
s->str,
buffer);
g_string_free (s, TRUE);
g_free (buffer);
g_free (code);
return FALSE;
}
static void
print_shader_info (const char *prefix,
int shader_id,
const char *resource_path)
{
if (GSK_DEBUG_CHECK(SHADERS))
{
int code_len;
char *code;
GString *s;
glGetShaderiv (shader_id, GL_SHADER_SOURCE_LENGTH, &code_len);
code = g_malloc0 (code_len + 1);
glGetShaderSource (shader_id, code_len, NULL, code);
s = g_string_new ("");
prepend_line_numbers (code, s);
g_message ("%s %d, %s:\n%s", prefix, shader_id, resource_path, s->str);
g_string_free (s, TRUE);
g_free (code);
}
}
int
gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self,
const char *resource_path,
const char *extra_fragment_snippet,
gsize extra_fragment_length,
GError **error)
{
GBytes *source_bytes = g_resources_lookup_data (resource_path, 0, NULL);
char version_buffer[64];
const char *source;
const char *vertex_shader_start;
const char *fragment_shader_start;
int vertex_id;
int fragment_id;
int program_id = -1;
int status;
g_assert (source_bytes);
source = g_bytes_get_data (source_bytes, NULL);
vertex_shader_start = strstr (source, "VERTEX_SHADER");
fragment_shader_start = strstr (source, "FRAGMENT_SHADER");
g_assert (vertex_shader_start);
g_assert (fragment_shader_start);
/* They both start at the next newline */
vertex_shader_start = strstr (vertex_shader_start, "\n");
fragment_shader_start = strstr (fragment_shader_start, "\n");
g_snprintf (version_buffer, sizeof (version_buffer),
"#version %d\n", self->version);
vertex_id = glCreateShader (GL_VERTEX_SHADER);
glShaderSource (vertex_id, 8,
(const char *[]) {
version_buffer,
self->debugging ? "#define GSK_DEBUG 1\n" : "",
self->legacy ? "#define GSK_LEGACY 1\n" : "",
self->gl3 ? "#define GSK_GL3 1\n" : "",
self->gles ? "#define GSK_GLES 1\n" : "",
g_bytes_get_data (self->preamble, NULL),
g_bytes_get_data (self->vs_preamble, NULL),
vertex_shader_start
},
(int[]) {
-1,
-1,
-1,
-1,
-1,
-1,
-1,
fragment_shader_start - vertex_shader_start
});
glCompileShader (vertex_id);
if (!check_shader_error (vertex_id, GL_VERTEX_SHADER, resource_path, error))
{
glDeleteShader (vertex_id);
goto out;
}
print_shader_info ("Vertex shader", vertex_id, resource_path);
fragment_id = glCreateShader (GL_FRAGMENT_SHADER);
glShaderSource (fragment_id, 9,
(const char *[]) {
version_buffer,
self->debugging ? "#define GSK_DEBUG 1\n" : "",
self->legacy ? "#define GSK_LEGACY 1\n" : "",
self->gl3 ? "#define GSK_GL3 1\n" : "",
self->gles ? "#define GSK_GLES 1\n" : "",
g_bytes_get_data (self->preamble, NULL),
g_bytes_get_data (self->fs_preamble, NULL),
fragment_shader_start,
extra_fragment_snippet ? extra_fragment_snippet : ""
},
(int[]) {
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
extra_fragment_length,
});
glCompileShader (fragment_id);
if (!check_shader_error (fragment_id, GL_FRAGMENT_SHADER, resource_path, error))
{
glDeleteShader (fragment_id);
goto out;
}
print_shader_info ("Fragment shader", fragment_id, resource_path);
program_id = glCreateProgram ();
glAttachShader (program_id, vertex_id);
glAttachShader (program_id, fragment_id);
glBindAttribLocation (program_id, 0, "aPosition");
glBindAttribLocation (program_id, 1, "aUv");
glLinkProgram (program_id);
glDetachShader (program_id, vertex_id);
glDetachShader (program_id, fragment_id);
glGetProgramiv (program_id, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
{
char *buffer = NULL;
int log_len = 0;
glGetProgramiv (program_id, GL_INFO_LOG_LENGTH, &log_len);
buffer = g_malloc0 (log_len + 1);
glGetProgramInfoLog (program_id, log_len, NULL, buffer);
g_warning ("Linking failure in shader:\n%s", buffer);
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_LINK_FAILED,
"Linking failure in shader: %s", buffer);
g_free (buffer);
glDeleteProgram (program_id);
program_id = -1;
}
glDeleteShader (vertex_id);
glDeleteShader (fragment_id);
out:
g_bytes_unref (source_bytes);
return program_id;
}
+42
View File
@@ -0,0 +1,42 @@
#ifndef __GSK_SHADER_BUILDER_PRIVATE_H__
#define __GSK_SHADER_BUILDER_PRIVATE_H__
#include <gdk/gdk.h>
#include <graphene.h>
G_BEGIN_DECLS
typedef struct
{
GBytes *preamble;
GBytes *vs_preamble;
GBytes *fs_preamble;
int version;
guint debugging: 1;
guint gles: 1;
guint gl3: 1;
guint legacy: 1;
} GskGLShaderBuilder;
void gsk_gl_shader_builder_init (GskGLShaderBuilder *self,
const char *common_preamble_resource_path,
const char *vs_preamble_resource_path,
const char *fs_preamble_resource_path);
void gsk_gl_shader_builder_finish (GskGLShaderBuilder *self);
void gsk_gl_shader_builder_set_glsl_version (GskGLShaderBuilder *self,
int version);
int gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self,
const char *resource_path,
const char *extra_fragment_snippet,
gsize extra_fragment_length,
GError **error);
G_END_DECLS
#endif /* __GSK_SHADER_BUILDER_PRIVATE_H__ */
+141
View File
@@ -0,0 +1,141 @@
#include "gskglshadowcacheprivate.h"
#define MAX_UNUSED_FRAMES (16 * 5)
typedef struct
{
GskRoundedRect outline;
float blur_radius;
} CacheKey;
typedef struct
{
GskRoundedRect outline;
float blur_radius;
int texture_id;
int unused_frames;
} CacheItem;
static gboolean
key_equal (const void *x,
const void *y)
{
const CacheKey *a = x;
const CacheKey *b = y;
return a->blur_radius == b->blur_radius &&
graphene_size_equal (&a->outline.corner[0], &b->outline.corner[0]) &&
graphene_size_equal (&a->outline.corner[1], &b->outline.corner[1]) &&
graphene_size_equal (&a->outline.corner[2], &b->outline.corner[2]) &&
graphene_size_equal (&a->outline.corner[3], &b->outline.corner[3]) &&
graphene_rect_equal (&a->outline.bounds, &b->outline.bounds);
}
void
gsk_gl_shadow_cache_init (GskGLShadowCache *self)
{
self->textures = g_array_new (FALSE, TRUE, sizeof (CacheItem));
}
void
gsk_gl_shadow_cache_free (GskGLShadowCache *self,
GskGLDriver *gl_driver)
{
guint i, p;
for (i = 0, p = self->textures->len; i < p; i ++)
{
const CacheItem *item = &g_array_index (self->textures, CacheItem, i);
gsk_gl_driver_destroy_texture (gl_driver, item->texture_id);
}
g_array_free (self->textures, TRUE);
self->textures = NULL;
}
void
gsk_gl_shadow_cache_begin_frame (GskGLShadowCache *self,
GskGLDriver *gl_driver)
{
guint i, p;
for (i = 0, p = self->textures->len; i < p; i ++)
{
CacheItem *item = &g_array_index (self->textures, CacheItem, i);
if (item->unused_frames > MAX_UNUSED_FRAMES)
{
gsk_gl_driver_destroy_texture (gl_driver, item->texture_id);
g_array_remove_index_fast (self->textures, i);
p --;
i --;
}
else
{
item->unused_frames ++;
}
}
}
/* XXX
* The offset origin should always be at 0/0, or the blur radius should just go
* away since it defines the origin position anyway?
*/
int
gsk_gl_shadow_cache_get_texture_id (GskGLShadowCache *self,
GskGLDriver *gl_driver,
const GskRoundedRect *shadow_rect,
float blur_radius)
{
CacheItem *item= NULL;
guint i;
g_assert (self != NULL);
g_assert (gl_driver != NULL);
g_assert (shadow_rect != NULL);
for (i = 0; i < self->textures->len; i ++)
{
CacheItem *k = &g_array_index (self->textures, CacheItem, i);
if (key_equal (&(CacheKey){*shadow_rect, blur_radius},
&(CacheKey){k->outline, k->blur_radius}))
{
item = k;
break;
}
}
if (item == NULL)
return 0;
item->unused_frames = 0;
g_assert (item->texture_id != 0);
return item->texture_id;
}
void
gsk_gl_shadow_cache_commit (GskGLShadowCache *self,
const GskRoundedRect *shadow_rect,
float blur_radius,
int texture_id)
{
CacheItem *item;
g_assert (self != NULL);
g_assert (shadow_rect != NULL);
g_assert (texture_id > 0);
g_array_set_size (self->textures, self->textures->len + 1);
item = &g_array_index (self->textures, CacheItem, self->textures->len - 1);
item->outline = *shadow_rect;
item->blur_radius = blur_radius;
item->unused_frames = 0;
item->texture_id = texture_id;
}
+31
View File
@@ -0,0 +1,31 @@
#ifndef __GSK_GL_SHADOW_CACHE_H__
#define __GSK_GL_SHADOW_CACHE_H__
#include <glib.h>
#include "gskgldriverprivate.h"
#include "gskroundedrect.h"
typedef struct
{
GArray *textures;
} GskGLShadowCache;
void gsk_gl_shadow_cache_init (GskGLShadowCache *self);
void gsk_gl_shadow_cache_free (GskGLShadowCache *self,
GskGLDriver *gl_driver);
void gsk_gl_shadow_cache_begin_frame (GskGLShadowCache *self,
GskGLDriver *gl_driver);
int gsk_gl_shadow_cache_get_texture_id (GskGLShadowCache *self,
GskGLDriver *gl_driver,
const GskRoundedRect *shadow_rect,
float blur_radius);
void gsk_gl_shadow_cache_commit (GskGLShadowCache *self,
const GskRoundedRect *shadow_rect,
float blur_radius,
int texture_id);
#endif
+309
View File
@@ -0,0 +1,309 @@
#include "config.h"
#include "gskgltextureatlasprivate.h"
#include "gskdebugprivate.h"
#include "gdkglcontextprivate.h"
#include <epoxy/gl.h>
#define ATLAS_SIZE (512)
#define MAX_OLD_RATIO 0.5
static void
free_atlas (gpointer v)
{
GskGLTextureAtlas *atlas = v;
gsk_gl_texture_atlas_free (atlas);
g_free (atlas);
}
GskGLTextureAtlases *
gsk_gl_texture_atlases_new (void)
{
GskGLTextureAtlases *self;
self = g_new (GskGLTextureAtlases, 1);
self->atlases = g_ptr_array_new_with_free_func (free_atlas);
self->ref_count = 1;
return self;
}
GskGLTextureAtlases *
gsk_gl_texture_atlases_ref (GskGLTextureAtlases *self)
{
self->ref_count++;
return self;
}
void
gsk_gl_texture_atlases_unref (GskGLTextureAtlases *self)
{
g_assert (self->ref_count > 0);
if (self->ref_count == 1)
{
g_ptr_array_unref (self->atlases);
g_free (self);
return;
}
self->ref_count--;
}
#if 0
static void
write_atlas_to_png (GskGLTextureAtlas *atlas,
const char *filename)
{
int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, atlas->width);
guchar *data = g_malloc (atlas->height * stride);
cairo_surface_t *s;
glBindTexture (GL_TEXTURE_2D, atlas->texture_id);
glGetTexImage (GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
s = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, atlas->width, atlas->height, stride);
cairo_surface_write_to_png (s, filename);
cairo_surface_destroy (s);
g_free (data);
}
#endif
void
gsk_gl_texture_atlases_begin_frame (GskGLTextureAtlases *self,
GPtrArray *removed)
{
int i;
for (i = self->atlases->len - 1; i >= 0; i--)
{
GskGLTextureAtlas *atlas = g_ptr_array_index (self->atlases, i);
if (gsk_gl_texture_atlas_get_unused_ratio (atlas) > MAX_OLD_RATIO)
{
GSK_NOTE(GLYPH_CACHE,
g_message ("Dropping atlas %d (%g.2%% old)", i,
100.0 * gsk_gl_texture_atlas_get_unused_ratio (atlas)));
if (atlas->texture_id != 0)
{
glDeleteTextures (1, &atlas->texture_id);
atlas->texture_id = 0;
}
g_ptr_array_add (removed, atlas);
g_ptr_array_remove_index (self->atlases, i);
}
}
GSK_NOTE(GLYPH_CACHE, {
static guint timestamp;
if (timestamp++ % 60 == 0)
g_message ("%d atlases", self->atlases->len);
});
#if 0
{
static guint timestamp;
timestamp++;
if (timestamp % 10 == 0)
for (i = 0; i < self->atlases->len; i++)
{
GskGLTextureAtlas *atlas = g_ptr_array_index (self->atlases, i);
if (atlas->texture_id)
{
char *filename;
filename = g_strdup_printf ("textureatlas%d-%u.png", i, timestamp);
write_atlas_to_png (atlas, filename);
g_free (filename);
}
}
}
#endif
}
gboolean
gsk_gl_texture_atlases_pack (GskGLTextureAtlases *self,
int width,
int height,
GskGLTextureAtlas **atlas_out,
int *out_x,
int *out_y)
{
GskGLTextureAtlas *atlas;
int x, y;
int i;
g_assert (width < ATLAS_SIZE);
g_assert (height < ATLAS_SIZE);
atlas = NULL;
for (i = 0; i < self->atlases->len; i++)
{
atlas = g_ptr_array_index (self->atlases, i);
if (gsk_gl_texture_atlas_pack (atlas, width, height, &x, &y))
break;
atlas = NULL;
}
if (atlas == NULL)
{
/* No atlas has enough space, so create a new one... */
atlas = g_malloc (sizeof (GskGLTextureAtlas));
gsk_gl_texture_atlas_init (atlas, ATLAS_SIZE, ATLAS_SIZE);
gsk_gl_texture_atlas_realize (atlas);
g_ptr_array_add (self->atlases, atlas);
/* Pack it onto that one, which surely has enough space... */
if (!gsk_gl_texture_atlas_pack (atlas, width, height, &x, &y))
g_assert_not_reached ();
GSK_NOTE(GLYPH_CACHE, g_message ("adding new atlas"));
}
*atlas_out = atlas;
*out_x = x;
*out_y = y;
return TRUE;
}
void
gsk_gl_texture_atlas_init (GskGLTextureAtlas *self,
int width,
int height)
{
memset (self, 0, sizeof (*self));
self->texture_id = 0;
self->width = width;
self->height = height;
/* TODO: We might want to change the strategy about the amount of
* nodes here? stb_rect_pack.h says with is optimal. */
self->nodes = g_malloc0 (sizeof (struct stbrp_node) * width);
stbrp_init_target (&self->context,
width, height,
self->nodes,
width);
gsk_gl_texture_atlas_realize (self);
}
void
gsk_gl_texture_atlas_free (GskGLTextureAtlas *self)
{
if (self->texture_id != 0)
{
glDeleteTextures (1, &self->texture_id);
self->texture_id = 0;
}
g_clear_pointer (&self->nodes, g_free);
}
void
gsk_gl_texture_atlas_mark_unused (GskGLTextureAtlas *self,
int width,
int height)
{
self->unused_pixels += (width * height);
}
void
gsk_gl_texture_atlas_mark_used (GskGLTextureAtlas *self,
int width,
int height)
{
self->unused_pixels -= (width * height);
g_assert (self->unused_pixels >= 0);
}
gboolean
gsk_gl_texture_atlas_pack (GskGLTextureAtlas *self,
int width,
int height,
int *out_x,
int *out_y)
{
stbrp_rect rect;
g_assert (out_x);
g_assert (out_y);
rect.w = width;
rect.h = height;
stbrp_pack_rects (&self->context, &rect, 1);
if (rect.was_packed)
{
*out_x = rect.x;
*out_y = rect.y;
}
return rect.was_packed;
}
double
gsk_gl_texture_atlas_get_unused_ratio (const GskGLTextureAtlas *self)
{
if (self->unused_pixels > 0)
return (double)(self->unused_pixels) / (double)(self->width * self->height);
return 0.0;
}
/* Not using gdk_gl_driver_create_texture here, since we want
* this texture to survive the driver and stay around until
* the display gets closed.
*/
static guint
create_shared_texture (int width,
int height)
{
guint texture_id;
glGenTextures (1, &texture_id);
glBindTexture (GL_TEXTURE_2D, texture_id);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
else
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
glBindTexture (GL_TEXTURE_2D, 0);
return texture_id;
}
void
gsk_gl_texture_atlas_realize (GskGLTextureAtlas *atlas)
{
if (atlas->texture_id)
return;
atlas->texture_id = create_shared_texture (atlas->width, atlas->height);
gdk_gl_context_label_object_printf (gdk_gl_context_get_current (),
GL_TEXTURE, atlas->texture_id,
"Texture atlas %d", atlas->texture_id);
}
+72
View File
@@ -0,0 +1,72 @@
#ifndef __GSK_GL_TEXTURE_ATLAS_H__
#define __GSK_GL_TEXTURE_ATLAS_H__
#include "stb_rect_pack.h"
#include "gskglimageprivate.h"
#include "gskgldriverprivate.h"
struct _GskGLTextureAtlas
{
struct stbrp_context context;
struct stbrp_node *nodes;
int width;
int height;
guint texture_id;
int unused_pixels; /* Pixels of rects that have been used at some point,
But are now unused. */
void *user_data;
};
typedef struct _GskGLTextureAtlas GskGLTextureAtlas;
struct _GskGLTextureAtlases
{
int ref_count;
GPtrArray *atlases;
};
typedef struct _GskGLTextureAtlases GskGLTextureAtlases;
GskGLTextureAtlases *gsk_gl_texture_atlases_new (void);
GskGLTextureAtlases *gsk_gl_texture_atlases_ref (GskGLTextureAtlases *atlases);
void gsk_gl_texture_atlases_unref (GskGLTextureAtlases *atlases);
void gsk_gl_texture_atlases_begin_frame (GskGLTextureAtlases *atlases,
GPtrArray *removed);
gboolean gsk_gl_texture_atlases_pack (GskGLTextureAtlases *atlases,
int width,
int height,
GskGLTextureAtlas **atlas_out,
int *out_x,
int *out_y);
void gsk_gl_texture_atlas_init (GskGLTextureAtlas *self,
int width,
int height);
void gsk_gl_texture_atlas_free (GskGLTextureAtlas *self);
void gsk_gl_texture_atlas_realize (GskGLTextureAtlas *self);
void gsk_gl_texture_atlas_mark_unused (GskGLTextureAtlas *self,
int width,
int height);
void gsk_gl_texture_atlas_mark_used (GskGLTextureAtlas *self,
int width,
int height);
gboolean gsk_gl_texture_atlas_pack (GskGLTextureAtlas *self,
int width,
int height,
int *out_x,
int *out_y);
double gsk_gl_texture_atlas_get_unused_ratio (const GskGLTextureAtlas *self);
#endif
+137
View File
@@ -0,0 +1,137 @@
#include "opbuffer.h"
#include <string.h>
static guint op_sizes[OP_LAST] = {
0,
sizeof (OpOpacity),
sizeof (OpColor),
sizeof (OpMatrix),
sizeof (OpMatrix),
sizeof (OpProgram),
sizeof (OpRenderTarget),
sizeof (OpClip),
sizeof (OpViewport),
sizeof (OpTexture),
sizeof (OpRepeat),
sizeof (OpLinearGradient),
sizeof (OpRadialGradient),
sizeof (OpColorMatrix),
sizeof (OpBlur),
sizeof (OpShadow),
sizeof (OpOutsetShadow),
sizeof (OpBorder),
sizeof (OpBorder),
sizeof (OpBorder),
sizeof (OpCrossFade),
sizeof (OpShadow),
0,
sizeof (OpDraw),
sizeof (OpDumpFrameBuffer),
sizeof (OpDebugGroup),
0,
sizeof (OpBlend),
sizeof (OpGLShader),
sizeof (OpExtraTexture),
sizeof (OpConicGradient),
};
void
op_buffer_init (OpBuffer *buffer)
{
static gsize initialized = FALSE;
if (g_once_init_enter (&initialized))
{
guint i;
for (i = 0; i < G_N_ELEMENTS (op_sizes); i++)
{
guint size = op_sizes[i];
if (size > 0)
{
/* Round all op entry sizes to the nearest 16 to ensure
* that we guarantee proper alignments for all op entries.
* This is only done once on first use.
*/
#define CHECK_SIZE(s) else if (size < (s)) { size = s; }
if (0) {}
CHECK_SIZE (16)
CHECK_SIZE (32)
CHECK_SIZE (48)
CHECK_SIZE (64)
CHECK_SIZE (80)
CHECK_SIZE (96)
CHECK_SIZE (112)
CHECK_SIZE (128)
CHECK_SIZE (144)
CHECK_SIZE (160)
CHECK_SIZE (176)
CHECK_SIZE (192)
else g_assert_not_reached ();
#undef CHECK_SIZE
op_sizes[i] = size;
}
}
g_once_init_leave (&initialized, TRUE);
}
memset (buffer, 0, sizeof *buffer);
buffer->buflen = 4096;
buffer->bufpos = 0;
buffer->buf = g_malloc (buffer->buflen);
buffer->index = g_array_new (FALSE, FALSE, sizeof (OpBufferEntry));
/* Add dummy entry to guarantee non-empty index */
op_buffer_add (buffer, OP_NONE);
}
void
op_buffer_destroy (OpBuffer *buffer)
{
g_free (buffer->buf);
g_array_unref (buffer->index);
}
void
op_buffer_clear (OpBuffer *buffer)
{
if (buffer->index->len > 1)
g_array_remove_range (buffer->index, 1, buffer->index->len - 1);
buffer->bufpos = 0;
}
static inline void
ensure_buffer_space_for (OpBuffer *buffer,
guint size)
{
if G_UNLIKELY (buffer->bufpos + size >= buffer->buflen)
{
buffer->buflen *= 2;
buffer->buf = g_realloc (buffer->buf, buffer->buflen);
}
}
gpointer
op_buffer_add (OpBuffer *buffer,
OpKind kind)
{
guint size = op_sizes[kind];
OpBufferEntry entry;
entry.pos = buffer->bufpos;
entry.kind = kind;
if (size > 0)
ensure_buffer_space_for (buffer, size);
g_array_append_val (buffer->index, entry);
buffer->bufpos += size;
return &buffer->buf[entry.pos];
}
+306
View File
@@ -0,0 +1,306 @@
#ifndef __OP_BUFFER_H__
#define __OP_BUFFER_H__
#include <gdk/gdk.h>
#include <gsk/gsk.h>
#include <graphene.h>
#include "gskgldriverprivate.h"
typedef struct _Program Program;
typedef enum
{
OP_NONE = 0,
OP_CHANGE_OPACITY = 1,
OP_CHANGE_COLOR = 2,
OP_CHANGE_PROJECTION = 3,
OP_CHANGE_MODELVIEW = 4,
OP_CHANGE_PROGRAM = 5,
OP_CHANGE_RENDER_TARGET = 6,
OP_CHANGE_CLIP = 7,
OP_CHANGE_VIEWPORT = 8,
OP_CHANGE_SOURCE_TEXTURE = 9,
OP_CHANGE_REPEAT = 10,
OP_CHANGE_LINEAR_GRADIENT = 11,
OP_CHANGE_RADIAL_GRADIENT = 12,
OP_CHANGE_COLOR_MATRIX = 13,
OP_CHANGE_BLUR = 14,
OP_CHANGE_INSET_SHADOW = 15,
OP_CHANGE_OUTSET_SHADOW = 16,
OP_CHANGE_BORDER = 17,
OP_CHANGE_BORDER_COLOR = 18,
OP_CHANGE_BORDER_WIDTH = 19,
OP_CHANGE_CROSS_FADE = 20,
OP_CHANGE_UNBLURRED_OUTSET_SHADOW = 21,
OP_CLEAR = 22,
OP_DRAW = 23,
OP_DUMP_FRAMEBUFFER = 24,
OP_PUSH_DEBUG_GROUP = 25,
OP_POP_DEBUG_GROUP = 26,
OP_CHANGE_BLEND = 27,
OP_CHANGE_GL_SHADER_ARGS = 28,
OP_CHANGE_EXTRA_SOURCE_TEXTURE = 29,
OP_CHANGE_CONIC_GRADIENT = 30,
OP_LAST
} OpKind;
typedef struct { int value; guint send: 1; } IntUniformValue;
typedef struct { float value; guint send: 1; } FloatUniformValue;
typedef struct { float value[2]; guint send: 1; } Float2UniformValue;
typedef struct { GskRoundedRect value; guint send: 1; guint send_corners: 1; } RRUniformValue;
typedef struct { const GdkRGBA *value; guint send: 1; } RGBAUniformValue;
typedef struct { const graphene_vec4_t *value; guint send: 1; } Vec4UniformValue;
typedef struct { const GskColorStop *value; guint send: 1; } ColorStopUniformValue;
typedef struct { const graphene_matrix_t *value; guint send: 1; } MatrixUniformValue;
/* OpNode are allocated within OpBuffer.pos, but we keep
* a secondary index into the locations of that buffer
* from OpBuffer.index. This allows peeking at the kind
* and quickly replacing existing entries when necessary.
*/
typedef struct
{
RRUniformValue outline;
FloatUniformValue spread;
Float2UniformValue offset;
RGBAUniformValue color;
} OpShadow;
typedef struct
{
RRUniformValue outline;
} OpOutsetShadow;
typedef struct
{
guint pos;
OpKind kind;
} OpBufferEntry;
typedef struct
{
guint8 *buf;
gsize buflen;
gsize bufpos;
GArray *index;
} OpBuffer;
typedef struct
{
float opacity;
} OpOpacity;
typedef struct
{
graphene_matrix_t matrix;
} OpMatrix;
typedef struct
{
const Program *program;
} OpProgram;
typedef struct
{
const GdkRGBA *rgba;
} OpColor;
typedef struct
{
int render_target_id;
} OpRenderTarget;
typedef struct
{
GskRoundedRect clip;
guint send_corners: 1;
} OpClip;
typedef struct
{
graphene_rect_t viewport;
} OpViewport;
typedef struct
{
int texture_id;
} OpTexture;
typedef struct
{
int texture_id;
int idx;
} OpExtraTexture;
typedef struct
{
gsize vao_offset;
gsize vao_size;
} OpDraw;
typedef struct
{
ColorStopUniformValue color_stops;
IntUniformValue n_color_stops;
float start_point[2];
float end_point[2];
gboolean repeat;
} OpLinearGradient;
typedef struct
{
ColorStopUniformValue color_stops;
IntUniformValue n_color_stops;
float start;
float end;
float radius[2];
float center[2];
gboolean repeat;
} OpRadialGradient;
typedef struct
{
ColorStopUniformValue color_stops;
IntUniformValue n_color_stops;
float center[2];
float angle;
} OpConicGradient;
typedef struct
{
MatrixUniformValue matrix;
Vec4UniformValue offset;
} OpColorMatrix;
typedef struct
{
float radius;
graphene_size_t size;
float dir[2];
} OpBlur;
typedef struct
{
float widths[4];
const GdkRGBA *color;
GskRoundedRect outline;
} OpBorder;
typedef struct
{
float progress;
int source2;
} OpCrossFade;
typedef struct
{
char *filename;
int width;
int height;
} OpDumpFrameBuffer;
typedef struct
{
char text[64];
} OpDebugGroup;
typedef struct
{
int source2;
int mode;
} OpBlend;
typedef struct
{
float child_bounds[4];
float texture_rect[4];
} OpRepeat;
typedef struct
{
float size[2];
GskGLShader *shader;
const guchar *uniform_data;
} OpGLShader;
void op_buffer_init (OpBuffer *buffer);
void op_buffer_destroy (OpBuffer *buffer);
void op_buffer_clear (OpBuffer *buffer);
gpointer op_buffer_add (OpBuffer *buffer,
OpKind kind);
typedef struct
{
GArray *index;
OpBuffer *buffer;
guint pos;
} OpBufferIter;
static inline void
op_buffer_iter_init (OpBufferIter *iter,
OpBuffer *buffer)
{
iter->index = buffer->index;
iter->buffer = buffer;
iter->pos = 1; /* Skip first OP_NONE */
}
static inline gpointer
op_buffer_iter_next (OpBufferIter *iter,
OpKind *kind)
{
const OpBufferEntry *entry;
if (iter->pos == iter->index->len)
return NULL;
entry = &g_array_index (iter->index, OpBufferEntry, iter->pos);
iter->pos++;
*kind = entry->kind;
return &iter->buffer->buf[entry->pos];
}
static inline void
op_buffer_pop_tail (OpBuffer *buffer)
{
/* Never truncate the first OP_NONE */
if G_LIKELY (buffer->index->len > 0)
buffer->index->len--;
}
static inline gpointer
op_buffer_peek_tail (OpBuffer *buffer,
OpKind *kind)
{
const OpBufferEntry *entry;
entry = &g_array_index (buffer->index, OpBufferEntry, buffer->index->len - 1);
*kind = entry->kind;
return &buffer->buf[entry->pos];
}
static inline gpointer
op_buffer_peek_tail_checked (OpBuffer *buffer,
OpKind kind)
{
const OpBufferEntry *entry;
entry = &g_array_index (buffer->index, OpBufferEntry, buffer->index->len - 1);
if (entry->kind == kind)
return &buffer->buf[entry->pos];
return NULL;
}
static inline guint
op_buffer_n_ops (OpBuffer *buffer)
{
return buffer->index->len - 1;
}
#endif /* __OP_BUFFER_H__ */
+310
View File
@@ -0,0 +1,310 @@
// VERTEX_SHADER:
void main() {
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
vUv = vec2(aUv.x, aUv.y);
}
// FRAGMENT_SHADER:
uniform int u_mode;
uniform sampler2D u_source2;
float
combine (float source, float backdrop)
{
return source + backdrop * (1.0 - source);
}
vec4
composite (vec4 Cs, vec4 Cb, vec3 B)
{
float ao = Cs.a + Cb.a * (1.0 - Cs.a);
vec3 Co = (Cs.a*(1.0 - Cb.a)*Cs.rgb + Cs.a*Cb.a*B + (1.0 - Cs.a)*Cb.a*Cb.rgb) / ao;
return vec4(Co, ao);
}
vec4
normal (vec4 Cs, vec4 Cb)
{
return composite (Cs, Cb, Cs.rgb);
}
vec4
multiply (vec4 Cs, vec4 Cb)
{
return composite (Cs, Cb, Cs.rgb * Cb.rgb);
}
vec4
difference (vec4 Cs, vec4 Cb)
{
return composite (Cs, Cb, abs(Cs.rgb - Cb.rgb));
}
vec4
screen (vec4 Cs, vec4 Cb)
{
return composite (Cs, Cb, Cs.rgb + Cb.rgb - Cs.rgb * Cb.rgb);
}
float
hard_light (float source, float backdrop)
{
if (source <= 0.5)
return 2.0 * backdrop * source;
else
return 2.0 * (backdrop + source - backdrop * source) - 1.0;
}
vec4
hard_light (vec4 Cs, vec4 Cb)
{
vec3 B = vec3 (hard_light (Cs.r, Cb.r),
hard_light (Cs.g, Cb.g),
hard_light (Cs.b, Cb.b));
return composite (Cs, Cb, B);
}
float
soft_light (float source, float backdrop)
{
float db;
if (backdrop <= 0.25)
db = ((16.0 * backdrop - 12.0) * backdrop + 4.0) * backdrop;
else
db = sqrt (backdrop);
if (source <= 0.5)
return backdrop - (1.0 - 2.0 * source) * backdrop * (1.0 - backdrop);
else
return backdrop + (2.0 * source - 1.0) * (db - backdrop);
}
vec4
soft_light (vec4 Cs, vec4 Cb)
{
vec3 B = vec3 (soft_light (Cs.r, Cb.r),
soft_light (Cs.g, Cb.g),
soft_light (Cs.b, Cb.b));
return composite (Cs, Cb, B);
}
vec4
overlay (vec4 Cs, vec4 Cb)
{
vec3 B = vec3 (hard_light (Cb.r, Cs.r),
hard_light (Cb.g, Cs.g),
hard_light (Cb.b, Cs.b));
return composite (Cs, Cb, B);
}
vec4
darken (vec4 Cs, vec4 Cb)
{
vec3 B = min (Cs.rgb, Cb.rgb);
return composite (Cs, Cb, B);
}
vec4
lighten (vec4 Cs, vec4 Cb)
{
vec3 B = max (Cs.rgb, Cb.rgb);
return composite (Cs, Cb, B);
}
float
color_dodge (float source, float backdrop)
{
return (source == 1.0) ? source : min (backdrop / (1.0 - source), 1.0);
}
vec4
color_dodge (vec4 Cs, vec4 Cb)
{
vec3 B = vec3 (color_dodge (Cs.r, Cb.r),
color_dodge (Cs.g, Cb.g),
color_dodge (Cs.b, Cb.b));
return composite (Cs, Cb, B);
}
float
color_burn (float source, float backdrop)
{
return (source == 0.0) ? source : max ((1.0 - ((1.0 - backdrop) / source)), 0.0);
}
vec4
color_burn (vec4 Cs, vec4 Cb)
{
vec3 B = vec3 (color_burn (Cs.r, Cb.r),
color_burn (Cs.g, Cb.g),
color_burn (Cs.b, Cb.b));
return composite (Cs, Cb, B);
}
vec4
exclusion (vec4 Cs, vec4 Cb)
{
vec3 B = Cb.rgb + Cs.rgb - 2.0 * Cb.rgb * Cs.rgb;
return composite (Cs, Cb, B);
}
float
lum (vec3 c)
{
return 0.3 * c.r + 0.59 * c.g + 0.11 * c.b;
}
vec3
clip_color (vec3 c)
{
float l = lum (c);
float n = min (c.r, min (c.g, c.b));
float x = max (c.r, max (c.g, c.b));
if (n < 0.0) c = l + (((c - l) * l) / (l - n));
if (x > 1.0) c = l + (((c - l) * (1.0 - l)) / (x - l));
return c;
}
vec3
set_lum (vec3 c, float l)
{
float d = l - lum (c);
return clip_color (vec3 (c.r + d, c.g + d, c.b + d));
}
float
sat (vec3 c)
{
return max (c.r, max (c.g, c.b)) - min (c.r, min (c.g, c.b));
}
vec3
set_sat (vec3 c, float s)
{
float cmin = min (c.r, min (c.g, c.b));
float cmax = max (c.r, max (c.g, c.b));
vec3 res;
if (cmax == cmin)
res = vec3 (0, 0, 0);
else
{
if (c.r == cmax)
{
if (c.g == cmin)
{
res.b = ((c.b - cmin) * s) / (cmax - cmin);
res.g = 0.0;
}
else
{
res.g = ((c.g - cmin) * s) / (cmax - cmin);
res.b = 0.0;
}
res.r = s;
}
else if (c.g == cmax)
{
if (c.r == cmin)
{
res.b = ((c.b - cmin) * s) / (cmax - cmin);
res.r = 0.0;
}
else
{
res.r = ((c.r - cmin) * s) / (cmax - cmin);
res.b = 0.0;
}
res.g = s;
}
else
{
if (c.r == cmin)
{
res.g = ((c.g - cmin) * s) / (cmax - cmin);
res.r = 0.0;
}
else
{
res.r = ((c.r - cmin) * s) / (cmax - cmin);
res.g = 0.0;
}
res.b = s;
}
}
return res;
}
vec4
color (vec4 Cs, vec4 Cb)
{
vec3 B = set_lum (Cs.rgb, lum (Cb.rgb));
return composite (Cs, Cb, B);
}
vec4
hue (vec4 Cs, vec4 Cb)
{
vec3 B = set_lum (set_sat (Cs.rgb, sat (Cb.rgb)), lum (Cb.rgb));
return composite (Cs, Cb, B);
}
vec4
saturation (vec4 Cs, vec4 Cb)
{
vec3 B = set_lum (set_sat (Cb.rgb, sat (Cs.rgb)), lum (Cb.rgb));
return composite (Cs, Cb, B);
}
vec4
luminosity (vec4 Cs, vec4 Cb)
{
vec3 B = set_lum (Cb.rgb, lum (Cs.rgb));
return composite (Cs, Cb, B);
}
void main() {
vec4 bottom_color = GskTexture(u_source, vUv);
vec4 top_color = GskTexture(u_source2, vUv);
vec4 result;
if (u_mode == 0)
result = normal(top_color, bottom_color);
else if (u_mode == 1)
result = multiply(top_color, bottom_color);
else if (u_mode == 2)
result = screen(top_color, bottom_color);
else if (u_mode == 3)
result = overlay(top_color, bottom_color);
else if (u_mode == 4)
result = darken(top_color, bottom_color);
else if (u_mode == 5)
result = lighten(top_color, bottom_color);
else if (u_mode == 6)
result = color_dodge(top_color, bottom_color);
else if (u_mode == 7)
result = color_burn(top_color, bottom_color);
else if (u_mode == 8)
result = hard_light(top_color, bottom_color);
else if (u_mode == 9)
result = soft_light(top_color, bottom_color);
else if (u_mode == 10)
result = difference(top_color, bottom_color);
else if (u_mode == 11)
result = exclusion(top_color, bottom_color);
else if (u_mode == 12)
result = color(top_color, bottom_color);
else if (u_mode == 13)
result = hue(top_color, bottom_color);
else if (u_mode == 14)
result = saturation(top_color, bottom_color);
else if (u_mode == 15)
result = luminosity(top_color, bottom_color);
else
discard;
gskSetOutputColor(result * u_alpha);
}
+13
View File
@@ -0,0 +1,13 @@
// VERTEX_SHADER:
void main() {
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
vUv = vec2(aUv.x, aUv.y);
}
// FRAGMENT_SHADER:
void main() {
vec4 diffuse = GskTexture(u_source, vUv);
gskSetOutputColor(diffuse * u_alpha);
}
+55
View File
@@ -0,0 +1,55 @@
// VERTEX_SHADER:
uniform float u_blur_radius;
uniform vec2 u_blur_size;
uniform vec2 u_blur_dir;
_OUT_ vec2 pixel_step;
_OUT_ float pixels_per_side;
_OUT_ vec3 initial_gaussian;
const float PI = 3.14159265;
const float RADIUS_MULTIPLIER = 2.0;
void main() {
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
vUv = vec2(aUv.x, aUv.y);
pixel_step = (vec2(1.0) / u_blur_size) * u_blur_dir;
pixels_per_side = floor(u_blur_radius * RADIUS_MULTIPLIER / 2.0);
float sigma = u_blur_radius / 2.0; // *shrug*
initial_gaussian.x = 1.0 / (sqrt(2.0 * PI) * sigma);
initial_gaussian.y = exp(-0.5 / (sigma * sigma));
initial_gaussian.z = initial_gaussian.y * initial_gaussian.y;
}
// FRAGMENT_SHADER:
_IN_ vec2 pixel_step;
_IN_ float pixels_per_side;
_IN_ vec3 initial_gaussian;
// blur_radius 0 is NOT supported and MUST be caught before.
// Partially from http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html
void main() {
vec3 incrementalGaussian = initial_gaussian;
float coefficientSum = 0.0;
vec4 sum = GskTexture(u_source, vUv) * incrementalGaussian.x;
coefficientSum += incrementalGaussian.x;
incrementalGaussian.xy *= incrementalGaussian.yz;
vec2 p = pixel_step;
for (int i = 1; i <= int(pixels_per_side); i++) {
sum += GskTexture(u_source, vUv - p) * incrementalGaussian.x;
sum += GskTexture(u_source, vUv + p) * incrementalGaussian.x;
coefficientSum += 2.0 * incrementalGaussian.x;
incrementalGaussian.xy *= incrementalGaussian.yz;
p += pixel_step;
}
gskSetOutputColor(sum / coefficientSum);
}
+40
View File
@@ -0,0 +1,40 @@
// VERTEX_SHADER:
uniform vec4 u_color;
uniform vec4 u_widths;
uniform vec4[3] u_outline_rect;
_OUT_ vec4 final_color;
_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
void main() {
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
final_color = gsk_premultiply(u_color) * u_alpha;
GskRoundedRect outside = gsk_create_rect(u_outline_rect);
GskRoundedRect inside = gsk_rounded_rect_shrink (outside, u_widths);
gsk_rounded_rect_transform(outside, u_modelview);
gsk_rounded_rect_transform(inside, u_modelview);
gsk_rounded_rect_encode(outside, transformed_outside_outline);
gsk_rounded_rect_encode(inside, transformed_inside_outline);
}
// FRAGMENT_SHADER:
uniform vec4[3] u_outline_rect;
_IN_ vec4 final_color;
_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
void main() {
vec2 frag = gsk_get_frag_coord();
float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) -
gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag),
0.0, 1.0);
gskSetOutputColor(final_color * alpha);
}
+18
View File
@@ -0,0 +1,18 @@
// VERTEX_SHADER:
uniform vec4 u_color;
_OUT_ vec4 final_color;
void main() {
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
final_color = gsk_premultiply(u_color) * u_alpha;
}
// FRAGMENT_SHADER:
_IN_ vec4 final_color;
void main() {
gskSetOutputColor(final_color);
}
+25
View File
@@ -0,0 +1,25 @@
// VERTEX_SHADER:
void main() {
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
vUv = vec2(aUv.x, aUv.y);
}
// FRAGMENT_SHADER:
uniform mat4 u_color_matrix;
uniform vec4 u_color_offset;
void main() {
vec4 color = GskTexture(u_source, vUv);
// Un-premultilpy
if (color.a != 0.0)
color.rgb /= color.a;
color = u_color_matrix * color + u_color_offset;
color = clamp(color, 0.0, 1.0);
color.rgb *= color.a;
gskSetOutputColor(color * u_alpha);
}
+22
View File
@@ -0,0 +1,22 @@
// VERTEX_SHADER:
uniform vec4 u_color;
_OUT_ vec4 final_color;
void main() {
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
vUv = vec2(aUv.x, aUv.y);
final_color = gsk_premultiply(u_color) * u_alpha;
}
// FRAGMENT_SHADER:
_IN_ vec4 final_color;
void main() {
vec4 diffuse = GskTexture(u_source, vUv);
gskSetOutputColor(final_color * diffuse.a);
}
+73
View File
@@ -0,0 +1,73 @@
// VERTEX_SHADER
uniform vec4 u_geometry;
_NOPERSPECTIVE_ _OUT_ vec2 coord;
void main() {
gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
vec2 mv0 = u_modelview[0].xy;
vec2 mv1 = u_modelview[1].xy;
vec2 offset = aPosition - u_geometry.xy;
coord = vec2(dot(mv0, offset),
dot(mv1, offset));
}
// FRAGMENT_SHADER:
#ifdef GSK_LEGACY
uniform int u_num_color_stops;
#else
uniform highp int u_num_color_stops; // Why? Because it works like this.
#endif
uniform vec4 u_geometry;
uniform float u_color_stops[6 * 5];
_NOPERSPECTIVE_ _IN_ vec2 coord;
float get_offset(int index) {
return u_color_stops[5 * index];
}
vec4 get_color(int index) {
int base = 5 * index + 1;
return vec4(u_color_stops[base],
u_color_stops[base + 1],
u_color_stops[base + 2],
u_color_stops[base + 3]);
}
void main() {
// direction of point in range [-PI, PI]
vec2 pos = floor(coord);
float angle = atan(pos.y, pos.x);
// fract() does the modulo here, so now we have progress
// into the current conic
float offset = fract(angle * u_geometry.z + u_geometry.w);
if (offset < get_offset(0)) {
gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha));
return;
}
int n = u_num_color_stops - 1;
for (int i = 0; i < n; i++) {
float curr_offset = get_offset(i);
float next_offset = get_offset(i + 1);
if (offset >= curr_offset && offset < next_offset) {
float f = (offset - curr_offset) / (next_offset - curr_offset);
vec4 curr_color = gsk_premultiply(get_color(i));
vec4 next_color = gsk_premultiply(get_color(i + 1));
vec4 color = mix(curr_color, next_color, f);
gskSetOutputColor(color * u_alpha);
return;
}
}
gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha));
}

Some files were not shown because too many files have changed in this diff Show More