Compare commits

..

1 Commits

Author SHA1 Message Date
Matthias Clasen 2a3f1acb3f treeview: Get rid of child surfaces
Drop the drag-highlight and drag surfaces. The highlighting
is broken anyway, so just drop it. And for dragging the header
button, we can just position it properly, that works just as
well as this surface approach.
2018-07-29 09:43:00 -04:00
442 changed files with 50156 additions and 71985 deletions
-1
View File
@@ -1 +0,0 @@
/subprojects/*/
+2 -2
View File
@@ -13,7 +13,7 @@ stages:
- subprojects/pango/
fedora-x86_64:
image: registry.gitlab.gnome.org/gnome/gtk/master:v2
image: registry.gitlab.gnome.org/gnome/gtk/master:v1
stage: build
script:
- bash -x ./.gitlab-ci/test-docker.sh
@@ -64,7 +64,7 @@ flatpak:widget-factory:
<<: *flatpak-defaults
pages:
image: registry.gitlab.gnome.org/gnome/gtk/master:v2
image: registry.gitlab.gnome.org/gnome/gtk/master:v1
stage: deploy
script:
- meson -Ddocumentation=true _build .
+2 -3
View File
@@ -1,4 +1,4 @@
FROM fedora:29
FROM fedora:28
RUN dnf -y install \
hicolor-icon-theme \
@@ -33,7 +33,6 @@ RUN dnf -y install \
iso-codes \
itstool \
json-glib-devel \
lcov \
libattr-devel \
libepoxy-devel \
libffi-devel \
@@ -70,7 +69,7 @@ RUN dnf -y install \
xorg-x11-server-Xvfb \
&& dnf clean all
RUN pip3 install meson==0.49.0
RUN pip3 install meson
ARG HOST_USER_ID=5555
ENV HOST_USER_ID ${HOST_USER_ID}
+1 -1
View File
@@ -2,7 +2,7 @@
set -e
TAG="registry.gitlab.gnome.org/gnome/gtk/master:v2"
TAG="registry.gitlab.gnome.org/gnome/gtk/master:v1"
sudo docker build --build-arg HOST_USER_ID="$UID" --tag "${TAG}" \
--file "Dockerfile" .
+22 -223
View File
@@ -1,144 +1,31 @@
# Contribution guidelines
Thank you for considering contributing to the GTK project!
These guidelines are meant for new contributors, regardless of their level
of proficiency; following them allows the maintainers of the GTK project to
more effectively evaluate your contribution, and provide prompt feedback to
you. Additionally, by following these guidelines you clearly communicate
that you respect the time and effort that the people developing GTK put into
managing the project.
GTK is a complex free software GUI toolkit, and it would not exist without
contributions from the free and open source software community. There are
many things that we value:
- bug reporting and fixing
- documentation and examples
- tests
- new features
Please, do not use the issue tracker for support questions. If you have
questions on how to use GTK effectively, you can use:
- the `#gtk+` IRC channel on irc.gnome.org
- the [gtk](https://mail.gnome.org/mailman/listinfo/gtk-list) mailing list,
for general questions on GTK
- the [gtk-app-devel](https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list)
mailing list, for questions on application development with GTK
- the [gtk-devel](https://mail.gnome.org/mailman/listinfo/gtk-devel-list)
mailing list, for questions on developing GTK itself
You can also look at the GTK tag on [Stack
Overflow](https://stackoverflow.com/questions/tagged/gtk).
The issue tracker is meant to be used for actionable issues only.
## How to report bugs
### Security issues
You should not open a new issue for security related questions.
When in doubt, send an email to the [security](mailto:security@gnome.org)
mailing list.
### Bug reports
If you're reporting a bug make sure to list:
0. which version of GTK are you using?
0. which operating system are you using?
0. the necessary steps to reproduce the issue
0. the expected outcome
0. a description of the behavior; screenshots are also welcome
0. a small, self-contained example exhibiting the behavior; if this
is not available, try reproducing the issue using the GTK examples
or interactive tests
If the issue includes a crash, you should also include:
0. the eventual warnings printed on the terminal
0. a backtrace, obtained with tools such as GDB or LLDB
For small issues, such as:
- spelling/grammar fixes in the documentation
- typo correction
- comment clean ups
- changes to metadata files (CI, `.gitignore`)
- build system changes
- source tree clean ups and reorganizations
You should directly open a merge request instead of filing a new issue.
### Features and enhancements
Feature discussion can be open ended and require high bandwidth channels; if
you are proposing a new feature on the issue tracker, make sure to make
an actionable proposal, and list:
0. what you're trying to achieve
0. prior art, in other toolkits or applications
0. design and theming changes
If you're proposing the integration of new features it helps to have
multiple applications using shared or similar code, especially if they have
iterated over it various times.
Each feature should also come fully documented, and with tests.
## Your first contribution
### Prerequisites
If you want to contribute to the GTK project, you will need to have the
development tools appropriate for your operating system, including:
If you want to hack on the GTK+ project, you'll need to have the development
tools appropriate for your operating system, including:
- Python 3.x
- Meson
- Ninja
- Gettext (19.7 or newer)
- a [C99 compatible compiler](https://wiki.gnome.org/Projects/GLib/CompilerRequirements)
- a C99 compatible compiler
Up-to-date instructions about developing GNOME applications and libraries
can be found on [the GNOME Developer Center](https://developer.gnome.org).
can be found here:
The GTK project uses GitLab for code hosting and for tracking issues. More
information about using GitLab can be found [on the GNOME
wiki](https://wiki.gnome.org/GitLab).
* https://developer.gnome.org
### Dependencies
Information about using GitLab with GNOME can be found here:
In order to get GTK from Git installed on your system, you need to have the
required versions of all the software dependencies required by GTK; typically,
this means a recent version of GLib, Cairo, Pango, and ATK, as well as the
platform-specific dependencies for the windowing system you are using (Wayland,
X11, Windows, or macOS).
* https://wiki.gnome.org/GitLab
The core dependencies for GTK are:
- [GLib, GObject, and GIO](https://gitlab.gnome.org/GNOME/glib)
- [Cairo](http://cairographics.org)
- [Pango](https://gitlab.gnome.org/GNOME/pango)
- [GdkPixbuf](https://gitlab.gnome.org/GNOME/gdk-pixbuf)
- [Epoxy](https://github.com/anholt/libepoxy)
- [ATK](https://gitlab.gnome.org/GNOME/atk)
- [Graphene](https://github.com/ebassi/graphene)
GTK will attempt to download and build some of these dependencies if it
cannot find them on your system.
Additionally, you may want to look at projects that create a development
environment for you, like [jhbuild](https://wiki.gnome.org/HowDoI/Jhbuild)
and [gvsbuild](https://github.com/wingtk/gvsbuild).
### Getting started
In order to get Git GTK+ installed on your system, you need to have the
required versions of all the GTK+ dependencies; typically, this means a
recent version of GLib, Cairo, Pango, and ATK, as well as the platform
specific dependencies for the windowing system you are using (Wayland, X11,
Windows, or macOS).
You should start by forking the GTK repository from the GitLab web UI, and
cloning from your fork:
```sh
```ssh
$ git clone https://gitlab.gnome.org/yourusername/gtk.git
$ cd gtk
```
@@ -151,7 +38,7 @@ $ git clone git@gitlab.gnome.org:GNOME/gtk.git
$ cd gtk
```
To compile the Git version of GTK on your system, you will need to
To compile the Git version of GTK+ on your system, you will need to
configure your build using Meson:
```sh
@@ -160,6 +47,11 @@ $ cd _builddir
$ ninja
```
**Note**: For information about submitting patches and pushing changes
to Git, see the `README.md` and `README.commits` files. In particular,
don't, under any circumstances, push anything to Git before reading and
understanding `README.commmits`.
Typically, you should work on your own branch:
```sh
@@ -168,99 +60,6 @@ $ git checkout -b your-branch
Once you've finished working on the bug fix or feature, push the branch
to the Git repository and open a new merge request, to let the GTK
maintainers review your contribution.
### Code reviews
Each contribution is reviewed by the core developers of the GTK project.
The [CODE-OWNERS](./docs/CODE-OWNERS) document contains the list of core
contributors to GTK and the areas for which they are responsible; you
should ensure to receive their review and signoff on your changes.
### Commit messages
The expected format for git commit messages is as follows:
```plain
Short explanation of the commit
Longer explanation explaining exactly what's changed, whether any
external or private interfaces changed, what bugs were fixed (with bug
tracker reference if applicable) and so forth. Be concise but not too
brief.
Closes #1234
```
- Always add a brief description of the commit to the _first_ line of
the commit and terminate by two newlines (it will work without the
second newline, but that is not nice for the interfaces).
- First line (the brief description) must only be one sentence and
should start with a capital letter unless it starts with a lowercase
symbol or identifier. Don't use a trailing period either. Don't exceed
72 characters.
- The main description (the body) is normal prose and should use normal
punctuation and capital letters where appropriate. Consider the commit
message as an email sent to the developers (or yourself, six months
down the line) detailing **why** you changed something. There's no need
to specify the **how**: the changes can be inlined.
- When committing code on behalf of others use the `--author` option, e.g.
`git commit -a --author "Joe Coder <joe@coder.org>"` and `--signoff`.
- If your commit is addressing an issue, use the
[GitLab syntax](https://docs.gitlab.com/ce/user/project/issues/automatic_issue_closing.html)
to automatically close the issue when merging the commit with the upstream
repository:
```plain
Closes #1234
Fixes #1234
Closes: https://gitlab.gnome.org/GNOME/gtk/issues/1234
```
- If you have a merge request with multiple commits and none of them
completely fixes an issue, you should add a reference to the issue in
the commit message, e.g. `Bug: #1234`, and use the automatic issue
closing syntax in the description of the merge request.
### Commit access to the GTK repository
GTK is part of the GNOME infrastructure. At the current time, any
person with write access to the GNOME repository can merge changes to
GTK. This is a good thing, in that it encourages many people to work
on GTK, and progress can be made quickly. However, GTK is a fairly
large and complicated project on which many other things depend, so to
avoid unnecessary breakage, and to take advantage of the knowledge
about GTK that has been built up over the years, we'd like to ask
people committing to GTK to follow a few rules:
0. Ask first. If your changes are major, or could possibly break existing
code, you should always ask. If your change is minor and you've been
working on GTK for a while it probably isn't necessary to ask. But when
in doubt, ask. Even if your change is correct, somebody may know a
better way to do things. If you are making changes to GTK, you should
be subscribed to the [gtk-devel](https://mail.gnome.org/mailman/listinfo/gtk-devel-list)
mailing list; this is a good place to ask about intended changes.
The `#gtk+` IRC channel on irc.gnome.org is also a good place to find GTK
developers to discuss changes, but if you live outside of the EU/US time
zones, an email to the gtk-devel mailing list is the most certain and
preferred method.
0. Ask _first_.
0. Always write a meaningful commit message. Changes without a sufficient
commit message will be reverted.
0. Never push to the `master` branch, or any stable branches, directly; you
should always go through a merge request, to ensure that the code is
tested on the CI infrastructure at the very least. A merge request is
also the proper place to get a comprehensive code review from the core
developers of GTK.
If you have been contributing to GTK for a while and you don't have commit
access to the repository, you may ask to obtain it following the [GNOME account
process](https://wiki.gnome.org/AccountsTeam/NewAccounts).
maintainers review your contribution. The [CODE-OWNERS](./docs-CODE-OWNERS)
document contains the list of core contributors to GTK and the areas for
which they are responsible.
+72
View File
@@ -0,0 +1,72 @@
GTK+ is part of the GNOME git repository. At the current time, any
person with write access to the GNOME repository, can make changes to
GTK+. This is a good thing, in that it encourages many people to work
on GTK+, and progress can be made quickly. However, GTK+ is a fairly
large and complicated package that many other things depend on, so to
avoid unnecessary breakage, and to take advantage of the knowledge
about GTK+ that has been built up over the years, we'd like to ask
people committing to GTK+ to follow a few rules:
0) Ask first. If your changes are major, or could possibly break existing
code, you should always ask. If your change is minor and you've
been working on GTK+ for a while it probably isn't necessary
to ask. But when in doubt, ask. Even if your change is correct,
somebody may know a better way to do things.
If you are making changes to GTK+, you should be subscribed
to gtk-devel-list@gnome.org. (Subscription address:
gtk-devel-list-request@gnome.org.) This is a good place to ask
about intended changes.
#gtk+ on GIMPNet (irc.gimp.org, irc.us.gimp.org, irc.eu.gimp.org, ...)
is also a good place to find GTK+ developers to discuss changes with,
however, email to gtk-devel-list is the most certain and preferred
method.
1) Ask _first_.
2) With git, we no longer maintain a ChangeLog file, but you are expected
to produce a meaningful commit message. Changes without a sufficient
commit message will be reverted. See below for the expected format
of commit messages.
Notes:
* When developing larger features or complicated bug fixes, it is
advisable to work in a branch in your own cloned GTK+ repository.
You may even consider making your repository publically available
so that others can easily test and review your changes.
* The expected format for git commit messages is as follows:
=== begin example commit ===
Short explanation of the commit
Longer explanation explaining exactly what's changed, whether any
external or private interfaces changed, what bugs were fixed (with bug
tracker reference if applicable) and so forth. Be concise but not too brief.
=== end example commit ===
- Always add a brief description of the commit to the _first_ line of
the commit and terminate by two newlines (it will work without the
second newline, but that is not nice for the interfaces).
- First line (the brief description) must only be one sentence and
should start with a capital letter unless it starts with a lowercase
symbol or identifier. Don't use a trailing period either. Don't exceed
72 characters.
- The main description (the body) is normal prose and should use normal
punctuation and capital letters where appropriate. Normally, for patches
sent to a mailing list it's copied from there.
- When committing code on behalf of others use the --author option, e.g.
git commit -a --author "Joe Coder <joe@coder.org>" and --signoff.
Owen Taylor
13 Aug 1998
17 Apr 2001
Matthias Clasen
31 Mar 2009
-5
View File
@@ -31,11 +31,6 @@ Information about mailing lists can be found at
- http://www.gtk.org/mailing-lists.php
Nightly documentation can be found at
- Gtk: https://gnome.pages.gitlab.gnome.org/gtk/gtk/
- Gdk: https://gnome.pages.gitlab.gnome.org/gtk/gdk/
- Gsk: https://gnome.pages.gitlab.gnome.org/gtk/gsk/
Building and installing
-----------------------
+1
View File
@@ -5,6 +5,7 @@
"sdk": "org.gnome.Sdk",
"command": "gtk4-demo",
"tags": ["devel", "development", "nightly"],
"rename-desktop-file": "gtk4-demo.desktop",
"rename-icon": "gtk4-demo",
"desktop-file-name-prefix": "(Development) ",
"finish-args": [
@@ -5,6 +5,7 @@
"sdk": "org.gnome.Sdk",
"command": "gtk4-widget-factory",
"tags": ["devel", "development", "nightly"],
"rename-desktop-file": "gtk4-widget-factory.desktop",
"rename-icon": "gtk4-widget-factory",
"desktop-file-name-prefix": "(Development) ",
"finish-args": [
+4 -7
View File
@@ -455,16 +455,13 @@ demo_application_window_constructed (GObject *object)
}
static void
demo_application_window_size_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
demo_application_window_size_allocate (GtkWidget *widget,
const GtkAllocation *allocation,
int baseline)
{
DemoApplicationWindow *window = (DemoApplicationWindow *)widget;
GTK_WIDGET_CLASS (demo_application_window_parent_class)->size_allocate (widget,
width,
height,
GTK_WIDGET_CLASS (demo_application_window_parent_class)->size_allocate (widget, allocation,
baseline);
if (!window->maximized && !window->fullscreen)
+9 -13
View File
@@ -87,14 +87,14 @@ find_toplevel_at_pointer (GdkDisplay *display)
return widget ? gtk_widget_get_toplevel (widget) : NULL;
}
static void
released_cb (GtkGestureMultiPress *gesture,
guint n_press,
gdouble x,
gdouble y,
gboolean *clicked)
static gboolean
release_event_cb (GtkWidget *widget,
GdkEvent *event,
gboolean *clicked)
{
*clicked = TRUE;
if (gdk_event_get_event_type (event) == GDK_BUTTON_RELEASE)
*clicked = TRUE;
return TRUE;
}
/* Asks the user to click on a window, then waits for them click
@@ -132,12 +132,10 @@ query_for_toplevel (GdkDisplay *display,
GDK_SEAT_CAPABILITY_ALL_POINTING,
FALSE, cursor, NULL, NULL, NULL) == GDK_GRAB_SUCCESS)
{
GtkGesture *gesture = gtk_gesture_multi_press_new ();
gboolean clicked = FALSE;
g_signal_connect (gesture, "released",
G_CALLBACK (released_cb), &clicked);
gtk_widget_add_controller (popup, GTK_EVENT_CONTROLLER (gesture));
g_signal_connect (popup, "event",
G_CALLBACK (release_event_cb), &clicked);
/* Process events until clicked is set by our button release event handler.
* We pass in may_block=TRUE since we want to wait if there
@@ -146,8 +144,6 @@ query_for_toplevel (GdkDisplay *display,
while (!clicked)
g_main_context_iteration (NULL, TRUE);
gdk_seat_ungrab (gdk_device_get_seat (device));
toplevel = find_toplevel_at_pointer (display);
if (toplevel == popup)
toplevel = NULL;
+2 -2
View File
@@ -144,7 +144,7 @@ create_capital_store (void)
{ NULL, "Jackson" },
{ NULL, "Jefferson City" },
{ NULL, "Juneau" },
{ "K - O", NULL },
{ "K - O" },
{ NULL, "Lansing" },
{ NULL, "Lincoln" },
{ NULL, "Little Rock" },
@@ -154,7 +154,7 @@ create_capital_store (void)
{ NULL, "Nashville" },
{ NULL, "Oklahoma City" },
{ NULL, "Olympia" },
{ "P - S", NULL },
{ NULL, "P - S" },
{ NULL, "Phoenix" },
{ NULL, "Pierre" },
{ NULL, "Providence" },
+1
View File
@@ -161,6 +161,7 @@
<file>editable_cells.c</file>
<file>entry_buffer.c</file>
<file>entry_completion.c</file>
<file>event_axes.c</file>
<file>expander.c</file>
<file>filtermodel.c</file>
<file>fishbowl.c</file>
+666
View File
@@ -0,0 +1,666 @@
/* Touch and Drawing Tablets
*
* Demonstrates advanced handling of event information from exotic
* input devices.
*
* On one hand, this snippet demonstrates management of drawing tablets,
* those contain additional information for the pointer other than
* X/Y coordinates. Tablet pads events are mapped to actions, which
* are both defined and interpreted by the application.
*
* Input axes are dependent on hardware devices, on linux/unix you
* can see the device axes through xinput list <device>. Each time
* a different hardware device is used to move the pointer, the
* master device will be updated to match the axes it provides,
* these changes can be tracked through GdkDevice::changed, or
* checking gdk_event_get_source_device().
*
* On the other hand, this demo handles basic multitouch events,
* each event coming from an specific touchpoint will contain a
* GdkEventSequence that's unique for its lifetime, so multiple
* touchpoints can be tracked.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
typedef struct {
GdkDevice *last_source;
GdkDeviceTool *last_tool;
gdouble *axes;
GdkRGBA color;
gdouble x;
gdouble y;
} AxesInfo;
typedef struct {
GHashTable *pointer_info; /* GdkDevice -> AxesInfo */
GHashTable *touch_info; /* GdkEventSequence -> AxesInfo */
} EventData;
const gchar *colors[] = {
"black",
"orchid",
"fuchsia",
"indigo",
"thistle",
"sienna",
"azure",
"plum",
"lime",
"navy",
"maroon",
"burlywood"
};
static GtkPadActionEntry pad_actions[] = {
{ GTK_PAD_ACTION_BUTTON, 1, -1, N_("Nuclear strike"), "pad.nuke" },
{ GTK_PAD_ACTION_BUTTON, 2, -1, N_("Release siberian methane reserves"), "pad.heat" },
{ GTK_PAD_ACTION_BUTTON, 3, -1, N_("Release solar flare"), "pad.fry" },
{ GTK_PAD_ACTION_BUTTON, 4, -1, N_("De-stabilize Oort cloud"), "pad.fall" },
{ GTK_PAD_ACTION_BUTTON, 5, -1, N_("Ignite WR-104"), "pad.burst" },
{ GTK_PAD_ACTION_BUTTON, 6, -1, N_("Lart whoever asks about this button"), "pad.lart" },
{ GTK_PAD_ACTION_RING, -1, -1, N_("Earth axial tilt"), "pad.tilt" },
{ GTK_PAD_ACTION_STRIP, -1, -1, N_("Extent of weak nuclear force"), "pad.dissolve" },
};
static const gchar *pad_action_results[] = {
"",
"",
"",
"",
"",
"💫",
"",
""
};
static guint cur_color = 0;
static guint pad_action_timeout_id = 0;
static AxesInfo *
axes_info_new (void)
{
AxesInfo *info;
info = g_new0 (AxesInfo, 1);
gdk_rgba_parse (&info->color, colors[cur_color]);
cur_color = (cur_color + 1) % G_N_ELEMENTS (colors);
return info;
}
static EventData *
event_data_new (void)
{
EventData *data;
data = g_new0 (EventData, 1);
data->pointer_info = g_hash_table_new_full (NULL, NULL, NULL,
(GDestroyNotify) g_free);
data->touch_info = g_hash_table_new_full (NULL, NULL, NULL,
(GDestroyNotify) g_free);
return data;
}
static void
event_data_free (EventData *data)
{
g_hash_table_destroy (data->pointer_info);
g_hash_table_destroy (data->touch_info);
g_free (data);
}
static void
update_axes_from_event (GdkEvent *event,
EventData *data)
{
GdkDevice *device, *source_device;
GdkEventSequence *sequence;
GdkDeviceTool *tool;
GdkEventType type;
gdouble x, y;
AxesInfo *info;
device = gdk_event_get_device (event);
source_device = gdk_event_get_source_device (event);
sequence = gdk_event_get_event_sequence (event);
tool = gdk_event_get_device_tool (event);
type = gdk_event_get_event_type (event);
if (type == GDK_TOUCH_END ||
type == GDK_TOUCH_CANCEL)
{
g_hash_table_remove (data->touch_info, sequence);
return;
}
else if (type == GDK_LEAVE_NOTIFY)
{
g_hash_table_remove (data->pointer_info, device);
return;
}
if (!source_device)
return;
if (!sequence)
{
info = g_hash_table_lookup (data->pointer_info, device);
if (!info)
{
info = axes_info_new ();
g_hash_table_insert (data->pointer_info, device, info);
}
}
else
{
info = g_hash_table_lookup (data->touch_info, sequence);
if (!info)
{
info = axes_info_new ();
g_hash_table_insert (data->touch_info, sequence, info);
}
}
if (info->last_source != source_device)
info->last_source = source_device;
if (info->last_tool != tool)
info->last_tool = tool;
g_clear_pointer (&info->axes, g_free);
if (type == GDK_TOUCH_BEGIN ||
type == GDK_TOUCH_UPDATE)
{
gboolean emulating_pointer;
gdk_event_get_touch_emulating_pointer (event, &emulating_pointer);
if (sequence && emulating_pointer)
g_hash_table_remove (data->pointer_info, device);
}
if (type == GDK_MOTION_NOTIFY ||
type == GDK_BUTTON_PRESS ||
type == GDK_BUTTON_RELEASE)
{
gdouble *axes;
guint n_axes;
gdk_event_get_axes (event, &axes, &n_axes);
info->axes = g_memdup (axes, sizeof (double) * n_axes);
}
if (gdk_event_get_coords (event, &x, &y))
{
info->x = x;
info->y = y;
}
}
static gboolean
event_cb (GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
{
update_axes_from_event (event, user_data);
gtk_widget_queue_draw (widget);
return FALSE;
}
static void
render_arrow (cairo_t *cr,
gdouble x_diff,
gdouble y_diff,
const gchar *label)
{
cairo_save (cr);
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_new_path (cr);
cairo_move_to (cr, 0, 0);
cairo_line_to (cr, x_diff, y_diff);
cairo_stroke (cr);
cairo_move_to (cr, x_diff, y_diff);
cairo_show_text (cr, label);
cairo_restore (cr);
}
static void
draw_axes_info (cairo_t *cr,
AxesInfo *info,
int width,
int height)
{
gdouble pressure, tilt_x, tilt_y, distance, wheel, rotation, slider;
GdkAxisFlags axes = gdk_device_get_axes (info->last_source);
cairo_save (cr);
cairo_set_line_width (cr, 1);
gdk_cairo_set_source_rgba (cr, &info->color);
cairo_move_to (cr, 0, info->y);
cairo_line_to (cr, width, info->y);
cairo_move_to (cr, info->x, 0);
cairo_line_to (cr, info->x, height);
cairo_stroke (cr);
cairo_translate (cr, info->x, info->y);
if (!info->axes)
{
cairo_restore (cr);
return;
}
if (axes & GDK_AXIS_FLAG_PRESSURE)
{
cairo_pattern_t *pattern;
gdk_device_get_axis (info->last_source, info->axes, GDK_AXIS_PRESSURE,
&pressure);
pattern = cairo_pattern_create_radial (0, 0, 0, 0, 0, 100);
cairo_pattern_add_color_stop_rgba (pattern, pressure, 1, 0, 0, pressure);
cairo_pattern_add_color_stop_rgba (pattern, 1, 0, 0, 1, 0);
cairo_set_source (cr, pattern);
cairo_arc (cr, 0, 0, 100, 0, 2 * G_PI);
cairo_fill (cr);
cairo_pattern_destroy (pattern);
}
if (axes & GDK_AXIS_FLAG_XTILT &&
axes & GDK_AXIS_FLAG_YTILT)
{
gdk_device_get_axis (info->last_source, info->axes, GDK_AXIS_XTILT,
&tilt_x);
gdk_device_get_axis (info->last_source, info->axes, GDK_AXIS_YTILT,
&tilt_y);
render_arrow (cr, tilt_x * 100, tilt_y * 100, "Tilt");
}
if (axes & GDK_AXIS_FLAG_DISTANCE)
{
double dashes[] = { 5.0, 5.0 };
cairo_text_extents_t extents;
gdk_device_get_axis (info->last_source, info->axes, GDK_AXIS_DISTANCE,
&distance);
cairo_save (cr);
cairo_move_to (cr, distance * 100, 0);
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
cairo_set_dash (cr, dashes, 2, 0.0);
cairo_arc (cr, 0, 0, distance * 100, 0, 2 * G_PI);
cairo_stroke (cr);
cairo_move_to (cr, 0, -distance * 100);
cairo_text_extents (cr, "Distance", &extents);
cairo_rel_move_to (cr, -extents.width / 2, 0);
cairo_show_text (cr, "Distance");
cairo_move_to (cr, 0, 0);
cairo_restore (cr);
}
if (axes & GDK_AXIS_FLAG_WHEEL)
{
gdk_device_get_axis (info->last_source, info->axes, GDK_AXIS_WHEEL,
&wheel);
cairo_save (cr);
cairo_set_line_width (cr, 10);
cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
cairo_new_sub_path (cr);
cairo_arc (cr, 0, 0, 100, 0, wheel * 2 * G_PI);
cairo_stroke (cr);
cairo_restore (cr);
}
if (axes & GDK_AXIS_FLAG_ROTATION)
{
gdk_device_get_axis (info->last_source, info->axes, GDK_AXIS_ROTATION,
&rotation);
rotation *= 2 * G_PI;
cairo_save (cr);
cairo_rotate (cr, - G_PI / 2);
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
cairo_set_line_width (cr, 5);
cairo_new_sub_path (cr);
cairo_arc (cr, 0, 0, 100, 0, rotation);
cairo_stroke (cr);
cairo_restore (cr);
}
if (axes & GDK_AXIS_FLAG_SLIDER)
{
cairo_pattern_t *pattern, *mask;
gdk_device_get_axis (info->last_source, info->axes, GDK_AXIS_SLIDER,
&slider);
cairo_save (cr);
cairo_move_to (cr, 0, -10);
cairo_rel_line_to (cr, 0, -50);
cairo_rel_line_to (cr, 10, 0);
cairo_rel_line_to (cr, -5, 50);
cairo_close_path (cr);
cairo_clip_preserve (cr);
pattern = cairo_pattern_create_linear (0, -10, 0, -60);
cairo_pattern_add_color_stop_rgb (pattern, 0, 0, 1, 0);
cairo_pattern_add_color_stop_rgb (pattern, 1, 1, 0, 0);
cairo_set_source (cr, pattern);
cairo_pattern_destroy (pattern);
mask = cairo_pattern_create_linear (0, -10, 0, -60);
cairo_pattern_add_color_stop_rgba (mask, 0, 0, 0, 0, 1);
cairo_pattern_add_color_stop_rgba (mask, slider, 0, 0, 0, 1);
cairo_pattern_add_color_stop_rgba (mask, slider, 0, 0, 0, 0);
cairo_pattern_add_color_stop_rgba (mask, 1, 0, 0, 0, 0);
cairo_mask (cr, mask);
cairo_pattern_destroy (mask);
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_stroke (cr);
cairo_restore (cr);
}
cairo_restore (cr);
}
static const gchar *
tool_type_to_string (GdkDeviceToolType tool_type)
{
switch (tool_type)
{
case GDK_DEVICE_TOOL_TYPE_PEN:
return "Pen";
case GDK_DEVICE_TOOL_TYPE_ERASER:
return "Eraser";
case GDK_DEVICE_TOOL_TYPE_BRUSH:
return "Brush";
case GDK_DEVICE_TOOL_TYPE_PENCIL:
return "Pencil";
case GDK_DEVICE_TOOL_TYPE_AIRBRUSH:
return "Airbrush";
case GDK_DEVICE_TOOL_TYPE_MOUSE:
return "Mouse";
case GDK_DEVICE_TOOL_TYPE_LENS:
return "Lens cursor";
case GDK_DEVICE_TOOL_TYPE_UNKNOWN:
default:
return "Unknown";
}
}
static void
draw_device_info (GtkWidget *widget,
cairo_t *cr,
GdkEventSequence *sequence,
gint *y,
AxesInfo *info)
{
PangoLayout *layout;
GString *string;
gint height;
cairo_save (cr);
string = g_string_new (NULL);
g_string_append_printf (string, "Source: %s",
gdk_device_get_name (info->last_source));
if (sequence)
g_string_append_printf (string, "\nSequence: %d",
GPOINTER_TO_UINT (sequence));
if (info->last_tool)
{
const gchar *tool_type;
guint64 serial;
tool_type = tool_type_to_string (gdk_device_tool_get_tool_type (info->last_tool));
serial = gdk_device_tool_get_serial (info->last_tool);
g_string_append_printf (string, "\nTool: %s", tool_type);
if (serial != 0)
g_string_append_printf (string, ", Serial: %" G_GINT64_MODIFIER "x", serial);
}
cairo_move_to (cr, 10, *y);
layout = gtk_widget_create_pango_layout (widget, string->str);
pango_cairo_show_layout (cr, layout);
cairo_stroke (cr);
pango_layout_get_pixel_size (layout, NULL, &height);
gdk_cairo_set_source_rgba (cr, &info->color);
cairo_set_line_width (cr, 10);
cairo_move_to (cr, 0, *y);
*y = *y + height;
cairo_line_to (cr, 0, *y);
cairo_stroke (cr);
cairo_restore (cr);
g_object_unref (layout);
g_string_free (string, TRUE);
}
static void
draw_cb (GtkDrawingArea *da,
cairo_t *cr,
int width,
int height,
gpointer user_data)
{
GtkWidget *widget = GTK_WIDGET (da);
EventData *data = user_data;
AxesInfo *info;
GHashTableIter iter;
gpointer key, value;
gint y = 0;
/* Draw Abs info */
g_hash_table_iter_init (&iter, data->pointer_info);
while (g_hash_table_iter_next (&iter, NULL, &value))
{
info = value;
draw_axes_info (cr, info, width, height);
}
g_hash_table_iter_init (&iter, data->touch_info);
while (g_hash_table_iter_next (&iter, NULL, &value))
{
info = value;
draw_axes_info (cr, info, width, height);
}
/* Draw name, color legend and misc data */
g_hash_table_iter_init (&iter, data->pointer_info);
while (g_hash_table_iter_next (&iter, NULL, &value))
{
info = value;
draw_device_info (widget, cr, NULL, &y, info);
}
g_hash_table_iter_init (&iter, data->touch_info);
while (g_hash_table_iter_next (&iter, &key, &value))
{
info = value;
draw_device_info (widget, cr, key, &y, info);
}
}
static void
update_label_text (GtkWidget *label,
const gchar *text)
{
gchar *markup = NULL;
if (text)
markup = g_strdup_printf ("<span font='48.0'>%s</span>", text);
gtk_label_set_markup (GTK_LABEL (label), markup);
g_free (markup);
}
static gboolean
reset_label_text_timeout_cb (gpointer user_data)
{
GtkWidget *label = user_data;
update_label_text (label, NULL);
pad_action_timeout_id = 0;
return G_SOURCE_REMOVE;
}
static void
update_label_and_timeout (GtkWidget *label,
const gchar *text)
{
if (pad_action_timeout_id)
g_source_remove (pad_action_timeout_id);
update_label_text (label, text);
pad_action_timeout_id = g_timeout_add (200, reset_label_text_timeout_cb, label);
}
static void
on_action_activate (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GtkWidget *label = user_data;
const gchar *result;
gchar *str;
result = g_object_get_data (G_OBJECT (action), "action-result");
if (!parameter)
update_label_and_timeout (label, result);
else
{
str = g_strdup_printf ("%s %.2f", result, g_variant_get_double (parameter));
update_label_and_timeout (label, str);
g_free (str);
}
}
static void
init_pad_controller (GtkWidget *window,
GtkWidget *label)
{
GtkPadController *pad_controller;
GSimpleActionGroup *action_group;
GSimpleAction *action;
gint i;
action_group = g_simple_action_group_new ();
pad_controller = gtk_pad_controller_new (G_ACTION_GROUP (action_group),
NULL);
for (i = 0; i < G_N_ELEMENTS (pad_actions); i++)
{
if (pad_actions[i].type == GTK_PAD_ACTION_BUTTON)
{
action = g_simple_action_new (pad_actions[i].action_name, NULL);
}
else
{
action = g_simple_action_new_stateful (pad_actions[i].action_name,
G_VARIANT_TYPE_DOUBLE, NULL);
}
g_signal_connect (action, "activate",
G_CALLBACK (on_action_activate), label);
g_object_set_data (G_OBJECT (action), "action-result",
(gpointer) pad_action_results[i]);
g_action_map_add_action (G_ACTION_MAP (action_group), G_ACTION (action));
g_object_unref (action);
}
gtk_pad_controller_set_action_entries (pad_controller, pad_actions,
G_N_ELEMENTS (pad_actions));
gtk_widget_add_controller (window, GTK_EVENT_CONTROLLER (pad_controller));
g_object_unref (action_group);
}
GtkWidget *
do_event_axes (GtkWidget *toplevel)
{
static GtkWidget *window = NULL;
EventData *event_data;
GtkWidget *label;
GtkWidget *overlay;
GtkWidget *da;
if (!window)
{
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Touch and Drawing Tablets");
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
gtk_widget_set_support_multidevice (window, TRUE);
event_data = event_data_new ();
g_object_set_data_full (G_OBJECT (window), "gtk-demo-event-data",
event_data, (GDestroyNotify) event_data_free);
da = gtk_drawing_area_new ();
gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (da), 400);
gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (da), 400);
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_cb, event_data, NULL);
gtk_widget_set_can_focus (da, TRUE);
gtk_widget_grab_focus (da);
g_signal_connect (da, "event",
G_CALLBACK (event_cb), event_data);
label = gtk_label_new ("");
gtk_widget_set_halign (label, GTK_ALIGN_START);
gtk_widget_set_valign (label, GTK_ALIGN_START);
gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
overlay = gtk_overlay_new ();
gtk_container_add (GTK_CONTAINER (window), overlay);
gtk_container_add (GTK_CONTAINER (overlay), da);
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), label);
init_pad_controller (da, label);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}
+1 -3
View File
@@ -134,9 +134,7 @@ static GtkWidget *
create_video (void)
{
GtkMediaStream *stream = gtk_media_file_new_for_resource ("/images/gtk-logo.webm");
GtkWidget *w = gtk_picture_new_for_paintable (GDK_PAINTABLE (stream));
gtk_widget_set_size_request (w, 64, 64);
GtkWidget *w = gtk_image_new_from_paintable (GDK_PAINTABLE (stream));
gtk_media_stream_set_loop (stream, TRUE);
gtk_media_stream_play (stream);
g_object_unref (stream);
+5 -6
View File
@@ -128,10 +128,9 @@ gtk_fishbowl_measure (GtkWidget *widget,
}
static void
gtk_fishbowl_size_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
gtk_fishbowl_size_allocate (GtkWidget *widget,
const GtkAllocation *allocation,
int baseline)
{
GtkFishbowl *fishbowl = GTK_FISHBOWL (widget);
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
@@ -148,8 +147,8 @@ gtk_fishbowl_size_allocate (GtkWidget *widget,
continue;
gtk_widget_get_preferred_size (child->widget, &child_requisition, NULL);
child_allocation.x = round (child->x * (width - child_requisition.width));
child_allocation.y = round (child->y * (height - child_requisition.height));
child_allocation.x = allocation->x + round (child->x * (allocation->width - child_requisition.width));
child_allocation.y = allocation->y + round (child->y * (allocation->height - child_requisition.height));
child_allocation.width = child_requisition.width;
child_allocation.height = child_requisition.height;
+34 -29
View File
@@ -135,42 +135,55 @@ static void set_cursor_if_appropriate (GtkTextView *text_view,
gint x,
gint y);
static void
released_cb (GtkGestureMultiPress *gesture,
guint n_press,
gdouble x,
gdouble y,
GtkWidget *text_view)
/* Links can also be activated by clicking or tapping.
*/
static gboolean
event_cb (GtkWidget *text_view,
GdkEvent *ev)
{
GtkTextIter start, end, iter;
GtkTextBuffer *buffer;
int tx, ty;
gdouble ex, ey;
int x, y;
GdkEventType type;
if (gtk_gesture_single_get_button (GTK_GESTURE_SINGLE (gesture)) > 1)
return;
type = gdk_event_get_event_type (ev);
gdk_event_get_coords (ev, &ex, &ey);
gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view),
GTK_TEXT_WINDOW_WIDGET,
x, y, &tx, &ty);
ex, ey, &x, &y);
if (type == GDK_BUTTON_RELEASE)
{
guint button;
gdk_event_get_button (ev, &button);
if (button != GDK_BUTTON_PRIMARY)
return FALSE;
}
else if (type == GDK_MOTION_NOTIFY)
{
set_cursor_if_appropriate (GTK_TEXT_VIEW (text_view), x, y);
return FALSE;
}
else if (type == GDK_TOUCH_END)
{
}
else
return FALSE;
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
/* we shouldn't follow a link if the user has selected something */
gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
if (gtk_text_iter_get_offset (&start) != gtk_text_iter_get_offset (&end))
return;
return FALSE;
if (gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (text_view), &iter, x, y))
follow_if_link (text_view, &iter);
}
static void
motion_cb (GtkEventControllerMotion *controller,
gdouble x,
gdouble y,
GtkTextView *text_view)
{
set_cursor_if_appropriate (text_view, x, y);
return TRUE;
}
static gboolean hovering_over_link = FALSE;
@@ -246,16 +259,8 @@ do_hypertext (GtkWidget *do_widget)
controller = gtk_event_controller_key_new ();
g_signal_connect (controller, "key-pressed", G_CALLBACK (key_pressed), view);
gtk_widget_add_controller (view, controller);
controller = GTK_EVENT_CONTROLLER (gtk_gesture_multi_press_new ());
g_signal_connect (controller, "released",
G_CALLBACK (released_cb), view);
gtk_widget_add_controller (view, controller);
controller = gtk_event_controller_motion_new ();
g_signal_connect (controller, "motion",
G_CALLBACK (motion_cb), view);
gtk_widget_add_controller (view, controller);
g_signal_connect (view, "event",
G_CALLBACK (event_cb), NULL);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+7 -6
View File
@@ -831,14 +831,15 @@ load_file (const gchar *demoname,
/* Skipping blank lines */
while (g_ascii_isspace (*p))
p++;
if (!*p)
if (*p)
{
p = lines[i];
state++;
/* Fall through */
}
else
break;
p = lines[i];
state++;
/* Fall through */
case 3:
/* Reading program body */
gtk_text_buffer_insert (source_buffer, &start, p, -1);
-1
View File
@@ -16,7 +16,6 @@
</columns>
</object>
<object class="GtkApplicationWindow" id="window">
<style><class name="devel"/></style>
<property name="default-width">800</property>
<property name="default-height">600</property>
<property name="title">GTK+ Demo</property>
+2 -1
View File
@@ -22,6 +22,7 @@ demos = files([
'editable_cells.c',
'entry_buffer.c',
'entry_completion.c',
'event_axes.c',
'expander.c',
'filtermodel.c',
'fishbowl.c',
@@ -129,7 +130,7 @@ foreach icon_size: [ '16x16', '22x22', '24x24', '32x32', '48x48', '256x256', ]
endforeach
# desktop file
install_data('org.gtk.Demo.desktop', install_dir: gtk_applicationsdir)
install_data('gtk4-demo.desktop', install_dir: gtk_applicationsdir)
# GSettings
install_data('org.gtk.Demo.gschema.xml', install_dir: gtk_schemasdir)
+10 -139
View File
@@ -3,24 +3,14 @@
* Demonstrates practical handling of drawing tablets in a real world
* usecase.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
enum {
COLOR_SET,
N_SIGNALS
};
static guint area_signals[N_SIGNALS] = { 0, };
typedef struct
{
GtkWidget parent_instance;
cairo_surface_t *surface;
cairo_t *cr;
GdkRGBA draw_color;
GtkPadController *pad_controller;
gdouble brush_size;
} DrawingArea;
typedef struct
@@ -28,30 +18,8 @@ typedef struct
GtkWidgetClass parent_class;
} DrawingAreaClass;
static GtkPadActionEntry pad_actions[] = {
{ GTK_PAD_ACTION_BUTTON, 1, -1, N_("Black"), "pad.black" },
{ GTK_PAD_ACTION_BUTTON, 2, -1, N_("Pink"), "pad.pink" },
{ GTK_PAD_ACTION_BUTTON, 3, -1, N_("Green"), "pad.green" },
{ GTK_PAD_ACTION_BUTTON, 4, -1, N_("Red"), "pad.red" },
{ GTK_PAD_ACTION_BUTTON, 5, -1, N_("Purple"), "pad.purple" },
{ GTK_PAD_ACTION_BUTTON, 6, -1, N_("Orange"), "pad.orange" },
{ GTK_PAD_ACTION_STRIP, -1, -1, N_("Brush size"), "pad.brush_size" },
};
static const gchar *pad_colors[] = {
"black",
"pink",
"green",
"red",
"purple",
"orange"
};
G_DEFINE_TYPE (DrawingArea, drawing_area, GTK_TYPE_WIDGET)
static void drawing_area_set_color (DrawingArea *area,
GdkRGBA *color);
static void
drawing_area_ensure_surface (DrawingArea *area,
gint width,
@@ -84,16 +52,15 @@ drawing_area_ensure_surface (DrawingArea *area,
}
static void
drawing_area_size_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
drawing_area_size_allocate (GtkWidget *widget,
const GtkAllocation *allocation,
int baseline)
{
DrawingArea *area = (DrawingArea *) widget;
drawing_area_ensure_surface (area, width, height);
drawing_area_ensure_surface (area, allocation->width, allocation->height);
GTK_WIDGET_CLASS (drawing_area_parent_class)->size_allocate (widget, width, height, baseline);
GTK_WIDGET_CLASS (drawing_area_parent_class)->size_allocate (widget, allocation, baseline);
}
static void
@@ -148,82 +115,6 @@ drawing_area_snapshot (GtkWidget *widget,
cairo_destroy (cr);
}
static void
on_pad_button_activate (GSimpleAction *action,
GVariant *parameter,
DrawingArea *area)
{
const gchar *color = g_object_get_data (G_OBJECT (action), "color");
GdkRGBA rgba;
gdk_rgba_parse (&rgba, color);
drawing_area_set_color (area, &rgba);
}
static void
on_pad_knob_change (GSimpleAction *action,
GVariant *parameter,
DrawingArea *area)
{
gdouble value = g_variant_get_double (parameter);
area->brush_size = value;
}
static void
drawing_area_hierarchy_changed (GtkWidget *widget,
GtkWidget *previous_toplevel)
{
DrawingArea *area = (DrawingArea *) widget;
GSimpleActionGroup *action_group;
GSimpleAction *action;
GtkWidget *toplevel;
gint i;
if (previous_toplevel && area->pad_controller)
{
gtk_widget_remove_controller (previous_toplevel,
GTK_EVENT_CONTROLLER (area->pad_controller));
area->pad_controller = NULL;
}
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (area));
if (!GTK_IS_WINDOW (toplevel))
return;
action_group = g_simple_action_group_new ();
area->pad_controller = gtk_pad_controller_new (G_ACTION_GROUP (action_group),
NULL);
for (i = 0; i < G_N_ELEMENTS (pad_actions); i++)
{
if (pad_actions[i].type == GTK_PAD_ACTION_BUTTON)
{
action = g_simple_action_new (pad_actions[i].action_name, NULL);
g_object_set_data (G_OBJECT (action), "color",
(gpointer) pad_colors[i]);
g_signal_connect (action, "activate",
G_CALLBACK (on_pad_button_activate), area);
}
else
{
action = g_simple_action_new_stateful (pad_actions[i].action_name,
G_VARIANT_TYPE_DOUBLE, NULL);
g_signal_connect (action, "activate",
G_CALLBACK (on_pad_knob_change), area);
}
g_action_map_add_action (G_ACTION_MAP (action_group), G_ACTION (action));
g_object_unref (action);
}
gtk_pad_controller_set_action_entries (area->pad_controller, pad_actions,
G_N_ELEMENTS (pad_actions));
gtk_widget_add_controller (toplevel,
GTK_EVENT_CONTROLLER (area->pad_controller));
}
static void
drawing_area_class_init (DrawingAreaClass *klass)
{
@@ -233,14 +124,6 @@ drawing_area_class_init (DrawingAreaClass *klass)
widget_class->snapshot = drawing_area_snapshot;
widget_class->map = drawing_area_map;
widget_class->unmap = drawing_area_unmap;
widget_class->hierarchy_changed = drawing_area_hierarchy_changed;
area_signals[COLOR_SET] =
g_signal_new ("color-set",
G_TYPE_FROM_CLASS (widget_class),
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 1, GDK_TYPE_RGBA);
}
static void
@@ -252,12 +135,12 @@ drawing_area_apply_stroke (DrawingArea *area,
{
if (gdk_device_tool_get_tool_type (tool) == GDK_DEVICE_TOOL_TYPE_ERASER)
{
cairo_set_line_width (area->cr, 10 * pressure * area->brush_size);
cairo_set_line_width (area->cr, 10 * pressure);
cairo_set_operator (area->cr, CAIRO_OPERATOR_DEST_OUT);
}
else
{
cairo_set_line_width (area->cr, 4 * pressure * area->brush_size);
cairo_set_line_width (area->cr, 4 * pressure);
cairo_set_operator (area->cr, CAIRO_OPERATOR_SATURATE);
}
@@ -265,6 +148,8 @@ drawing_area_apply_stroke (DrawingArea *area,
area->draw_color.green, area->draw_color.blue,
area->draw_color.alpha * pressure);
//cairo_set_source_rgba (area->cr, 0, 0, 0, pressure);
cairo_line_to (area->cr, x, y);
cairo_stroke (area->cr);
cairo_move_to (area->cr, x, y);
@@ -340,15 +225,11 @@ drawing_area_new (void)
return g_object_new (drawing_area_get_type (), NULL);
}
static void
void
drawing_area_set_color (DrawingArea *area,
GdkRGBA *color)
{
if (gdk_rgba_equal (&area->draw_color, color))
return;
area->draw_color = *color;
g_signal_emit (area, area_signals[COLOR_SET], 0, &area->draw_color);
}
static void
@@ -361,14 +242,6 @@ color_button_color_set (GtkColorButton *button,
drawing_area_set_color (draw_area, &color);
}
static void
drawing_area_color_set (DrawingArea *area,
GdkRGBA *color,
GtkColorButton *button)
{
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (button), color);
}
GtkWidget *
do_paint (GtkWidget *toplevel)
{
@@ -390,8 +263,6 @@ do_paint (GtkWidget *toplevel)
colorbutton = gtk_color_button_new ();
g_signal_connect (colorbutton, "color-set",
G_CALLBACK (color_button_color_set), draw_area);
g_signal_connect (draw_area, "color-set",
G_CALLBACK (drawing_area_color_set), colorbutton);
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (colorbutton),
&(GdkRGBA) { 0, 0, 0, 1 });
+4 -5
View File
@@ -55,11 +55,10 @@ create_complex_popover (GtkWidget *parent,
}
static void
entry_size_allocate_cb (GtkEntry *entry,
int width,
int height,
int baseline,
gpointer user_data)
entry_size_allocate_cb (GtkEntry *entry,
const GtkAllocation *allocation,
int baseline,
gpointer user_data)
{
GtkEntryIconPosition popover_pos;
GtkPopover *popover = user_data;
+12 -1
View File
@@ -26,6 +26,17 @@ changed_cb (GtkEditable *editable)
g_message ("changed: %s", text);
}
static gboolean
window_event_cb (GtkWidget *widget,
GdkEvent *event,
GtkSearchBar *bar)
{
if (gdk_event_get_event_type (event) == GDK_KEY_PRESS)
return gtk_search_bar_handle_event (bar, event);
return GDK_EVENT_PROPAGATE;
}
static void
search_changed (GtkSearchEntry *entry,
GtkLabel *label)
@@ -91,7 +102,7 @@ do_search_entry2 (GtkWidget *do_widget)
gtk_box_pack_start (GTK_BOX (vbox), searchbar);
/* Hook the search bar to key presses */
gtk_search_bar_set_key_capture_widget (GTK_SEARCH_BAR (searchbar), window);
g_signal_connect (window, "event", G_CALLBACK (window_event_cb), searchbar);
/* Help */
label = gtk_label_new ("Start Typing to search");
+14 -3
View File
@@ -12,10 +12,12 @@ do_transparent (GtkWidget *do_widget)
if (!window)
{
GtkWidget *sw;
GtkWidget *overlay;
GtkWidget *button;
GtkWidget *label;
GtkWidget *picture;
GtkWidget *box;
GtkWidget *image;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_display (GTK_WINDOW (window),
@@ -52,8 +54,17 @@ do_transparent (GtkWidget *do_widget)
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), button);
gtk_container_child_set (GTK_CONTAINER (overlay), button, "blur", 5.0, NULL);
picture = gtk_picture_new_for_resource ("/transparent/portland-rose.jpg");
gtk_container_add (GTK_CONTAINER (overlay), picture);
sw = gtk_scrolled_window_new (NULL, NULL);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (overlay), sw);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (sw), box);
image = gtk_image_new_from_resource ("/transparent/portland-rose.jpg");
gtk_container_add (GTK_CONTAINER (box), image);
}
if (!gtk_widget_get_visible (window))
+1 -1
View File
@@ -17,4 +17,4 @@ executable('gtk4-icon-browser',
link_args: extra_demo_ldflags,
install: true)
install_data('org.gtk.IconBrowser.desktop', install_dir: gtk_applicationsdir)
install_data('gtk4-icon-browser.desktop', install_dir: gtk_applicationsdir)
-1
View File
@@ -6,7 +6,6 @@
<property name="child-model">store</property>
</object>
<template class="IconBrowserWindow" parent="GtkApplicationWindow">
<style><class name="devel"/></style>
<property name="title" translatable="yes">Icon Browser</property>
<property name="default-width">1024</property>
<property name="default-height">768</property>
+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<menu id="app-menu">
<section>
<item>
<attribute name="label" translatable="yes">About</attribute>
<attribute name="action">app.about</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">_Quit</attribute>
<attribute name="action">app.quit</attribute>
<attribute name="accel">&lt;Primary&gt;q</attribute>
</item>
</section>
</menu>
</interface>
+1 -1
View File
@@ -13,7 +13,7 @@ executable('gtk4-widget-factory',
install: true)
# desktop file
install_data('org.gtk.WidgetFactory.desktop', install_dir: gtk_applicationsdir)
install_data('gtk4-widget-factory.desktop', install_dir: gtk_applicationsdir)
# icons
icontheme_dir = join_paths(gtk_datadir, 'icons/hicolor')
@@ -6,6 +6,9 @@
<gresource prefix="/org/gtk/WidgetFactory">
<file>widget-factory.css</file>
</gresource>
<gresource prefix="/org/gtk/WidgetFactory/gtk">
<file preprocess="xml-stripblanks">menus.ui</file>
</gresource>
<gresource prefix="/org/gtk/WidgetFactory/gtk">
<file preprocess="xml-stripblanks">help-overlay.ui</file>
</gresource>
+1 -12
View File
@@ -16,16 +16,6 @@
<attribute name="action">win.transition</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">_Keyboard Shortcuts</attribute>
<attribute name="action">win.show-help-overlay</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_About Widget Factory</attribute>
<attribute name="action">app.about</attribute>
</item>
</section>
</menu>
<menu id="dinner_menu">
<section>
@@ -406,7 +396,6 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
</columns>
</object>
<object class="GtkApplicationWindow" id="window">
<style><class name="devel"/></style>
<property name="title">GTK+ Widget Factory</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="headerbar1">
@@ -3594,4 +3583,4 @@ bad things might happen.</property>
</object>
</child>
</object>
</interface>
</interface>
+1
View File
@@ -655,6 +655,7 @@ gdk_event_get_key_is_modifier
gdk_event_get_pad_axis_value
gdk_event_get_pad_button
gdk_event_get_pad_group_mode
gdk_event_get_string
gdk_event_get_touch_emulating_pointer
gdk_event_get_touchpad_angle_delta
gdk_event_get_touchpad_deltas
@@ -44,7 +44,7 @@
<informalexample>
<para>Create a new file with the following content named <filename>example-0.c.</filename></para>
<programlisting><xi:include href="@SRC_DIR@/examples/window-default.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<programlisting><xi:include href="../../../../examples/window-default.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</informalexample>
<para>
@@ -153,7 +153,7 @@
<example id="gtk-getting-started-hello-world">
<title>Hello World in GTK+</title>
<para>Create a new file with the following content named example-1.c.</para>
<programlisting><xi:include href="@SRC_DIR@/examples/hello-world.c" parse="text">
<programlisting><xi:include href="../../../../examples/hello-world.c" parse="text">
<xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</example>
@@ -233,7 +233,7 @@
<example id="gtk-getting-started-grid-packing">
<title>Packing buttons</title>
<para>Create a new file with the following content named example-2.c.</para>
<programlisting><xi:include href="@SRC_DIR@/examples/grid-packing.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<programlisting><xi:include href="../../../../examples/grid-packing.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</example>
<para>
You can compile the program above with GCC using:
@@ -257,9 +257,9 @@
<example>
<title>Packing buttons with GtkBuilder</title>
<para>Create a new file with the following content named example-3.c.</para>
<programlisting><xi:include href="@SRC_DIR@/examples/builder.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<programlisting><xi:include href="../../../../examples/builder.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<para>Create a new file with the following content named builder.ui.</para>
<programlisting><xi:include href="@SRC_DIR@/examples/builder.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<programlisting><xi:include href="../../../../examples/builder.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</example>
<para>
You can compile the program above with GCC using:
@@ -346,7 +346,7 @@
of our application class.</para>
<informalexample>
<programlisting><xi:include href="@SRC_DIR@/examples/application1/main.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<programlisting><xi:include href="../../../../examples/application1/main.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</informalexample>
<para>All the application logic is in the application class, which
@@ -364,7 +364,7 @@
GIO <ulink url="https://developer.gnome.org/gio/2.36/GApplication.html#GApplication.description">documentation</ulink>.</para>
<informalexample>
<programlisting><xi:include href="@SRC_DIR@/examples/application1/exampleapp.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<programlisting><xi:include href="../../../../examples/application1/exampleapp.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</informalexample>
<para>Another important class that is part of the application support
@@ -373,7 +373,7 @@
window.</para>
<informalexample>
<programlisting><xi:include href="@SRC_DIR@/examples/application1/exampleappwin.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<programlisting><xi:include href="../../../../examples/application1/exampleappwin.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</informalexample>
<para>As part of the initial setup of our application, we also
@@ -388,7 +388,7 @@
</informalfigure>
<informalexample>
<programlisting><xi:include href="@SRC_DIR@/examples/application1/org.gtk.exampleapp.desktop" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<programlisting><xi:include href="../../../../examples/application1/exampleapp.desktop" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</informalexample>
<para>Note that <replaceable>@<!-- -->bindir@</replaceable> needs to be replaced
@@ -420,7 +420,7 @@
</para>
<informalexample>
<programlisting><xi:include href="@SRC_DIR@/examples/application2/window.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<programlisting><xi:include href="../../../../examples/application2/window.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</informalexample>
<para>To make use of this file in our application, we revisit
@@ -460,7 +460,7 @@ example_app_window_class_init (ExampleAppWindowClass *class)
</para>
<informalexample>
<programlisting><xi:include href="@SRC_DIR@/examples/application2/exampleapp.gresource.xml" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<programlisting><xi:include href="../../../../examples/application2/exampleapp.gresource.xml" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</informalexample>
<para>This file has to be converted into a C source file that will be
@@ -599,7 +599,7 @@ example_app_window_open (ExampleAppWindow *win,
in a ui file, and add it as a resource to our binary.</para>
<informalexample>
<programlisting><xi:include href="@SRC_DIR@/examples/application4/app-menu.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<programlisting><xi:include href="../../../../examples/application4/app-menu.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</informalexample>
<para>To associate the app menu with the application, we have to call
@@ -698,7 +698,7 @@ example_app_class_init (ExampleAppClass *class)
GSettings requires a schema that describes our settings:</para>
<informalexample>
<programlisting><xi:include href="@SRC_DIR@/examples/application5/org.gtk.exampleapp.gschema.xml" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<programlisting><xi:include href="../../../../examples/application5/org.gtk.exampleapp.gschema.xml" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</informalexample>
<para>Before we can make use of this schema in our application,
@@ -747,13 +747,13 @@ example_app_window_init (ExampleAppWindow *win)
<para>Lets start with the template.</para>
<informalexample>
<programlisting><xi:include href="@SRC_DIR@/examples/application6/prefs.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<programlisting><xi:include href="../../../../examples/application6/prefs.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</informalexample>
<para>Next comes the dialog subclass.</para>
<informalexample>
<programlisting><xi:include href="@SRC_DIR@/examples/application6/exampleappprefs.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<programlisting><xi:include href="../../../../examples/application6/exampleappprefs.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</informalexample>
<para>Now we revisit the <literal>preferences_activated(<!-- -->)</literal> function in our
@@ -805,7 +805,7 @@ preferences_activated (GSimpleAction *action,
to slide out the search bar below the header bar.</para>
<informalexample>
<programlisting><xi:include href="@SRC_DIR@/examples/application7/window.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<programlisting><xi:include href="../../../../examples/application7/window.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</informalexample>
<para>Implementing the search needs quite a few code changes that
@@ -882,7 +882,7 @@ example_app_window_init (ExampleAppWindow *win)
which demonstrates #GtkMenuButton, #GtkRevealer and #GtkListBox.</para>
<informalexample>
<programlisting><xi:include href="@SRC_DIR@/examples/application8/window.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<programlisting><xi:include href="../../../../examples/application8/window.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</informalexample>
<para>The code to populate the sidebar with buttons for the words
@@ -893,7 +893,7 @@ example_app_window_init (ExampleAppWindow *win)
ui file.</para>
<informalexample>
<programlisting><xi:include href="@SRC_DIR@/examples/application8/gears-menu.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<programlisting><xi:include href="../../../../examples/application8/gears-menu.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</informalexample>
<para>To connect the menuitem to the show-words setting, we use
@@ -952,7 +952,7 @@ example_app_window_init (ExampleAppWindow *win)
triggers the show-lines action:</para>
<informalexample>
<programlisting><xi:include href="@SRC_DIR@/examples/application9/gears-menu.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<programlisting><xi:include href="../../../../examples/application9/gears-menu.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</informalexample>
<para>To make this menu item do something, we create a property
@@ -1012,7 +1012,7 @@ example_app_window_init (ExampleAppWindow *win)
be a direct child of the window, and set its type to be titlebar.</para>
<informalexample>
<programlisting><xi:include href="@SRC_DIR@/examples/application10/window.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<programlisting><xi:include href="../../../../examples/application10/window.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</informalexample>
<para>A small extra bonus of using a header bar is that we get
@@ -1068,7 +1068,7 @@ example_app_window_init (ExampleAppWindow *win)
<example id="gtk-getting-started-drawing">
<title>Drawing in response to input</title>
<para>Create a new file with the following content named example-4.c.</para>
<programlisting><xi:include href="@SRC_DIR@/examples/drawing.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
<programlisting><xi:include href="../../../../examples/drawing.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</example>
<para>
You can compile the program above with GCC using:
-12
View File
@@ -41,16 +41,6 @@
<xi:include href="visual_index.xml" />
</chapter>
<chapter id="Lists">
<title>GListModel support</title>
<xi:include href="xml/gtkfilterlistmodel.xml" />
<xi:include href="xml/gtkflattenlistmodel.xml" />
<xi:include href="xml/gtkmaplistmodel.xml" />
<xi:include href="xml/gtkslicelistmodel.xml" />
<xi:include href="xml/gtksortlistmodel.xml" />
<xi:include href="xml/gtktreelistmodel.xml" />
</chapter>
<chapter id="Application">
<title>Application support</title>
<xi:include href="xml/gtkapplication.xml" />
@@ -162,7 +152,6 @@
<chapter id="TreeWidgetObjects">
<title>Tree, List and Icon Grid Widgets</title>
<xi:include href="xml/tree_widget.sgml" />
<xi:include href="xml/treeview_tutorial.xml" />
<xi:include href="xml/gtktreemodel.xml" />
<xi:include href="xml/gtktreeselection.xml" />
<xi:include href="xml/gtktreeviewcolumn.xml" />
@@ -312,7 +301,6 @@
<title>Gestures and event handling</title>
<xi:include href="xml/gtkeventcontroller.xml" />
<xi:include href="xml/gtkeventcontrollerkey.xml" />
<xi:include href="xml/gtkeventcontrollerlegacy.xml" />
<xi:include href="xml/gtkeventcontrollerscroll.xml" />
<xi:include href="xml/gtkeventcontrollermotion.xml" />
<xi:include href="xml/gtkgesture.xml" />
+4 -170
View File
@@ -758,6 +758,9 @@ gtk_container_child_set_valist
gtk_container_child_notify
gtk_container_child_notify_by_pspec
gtk_container_forall
gtk_container_get_focus_chain
gtk_container_set_focus_chain
gtk_container_unset_focus_chain
gtk_container_class_find_child_property
gtk_container_class_install_child_property
gtk_container_class_install_child_properties
@@ -1239,26 +1242,6 @@ GTK_TYPE_FILE_FILTER
gtk_file_filter_get_type
</SECTION>
<SECTION>
<FILE>gtkfilterlistmodel</FILE>
<TITLE>GtkFilterListModel</TITLE>
GtkFilterListModel
gtk_filter_list_model_new
gtk_filter_list_model_get_model
gtk_filter_list_model_set_filter_func
gtk_filter_list_model_has_filter
gtk_filter_list_model_refilter
<SUBSECTION Standard>
GTK_FILTER_LIST_MODEL
GTK_IS_FILTER_LIST_MODEL
GTK_TYPE_FILTER_LIST_MODEL
GTK_FILTER_LIST_MODEL_CLASS
GTK_IS_FILTER_LIST_MODEL_CLASS
GTK_FILTER_LIST_MODEL_GET_CLASS
<SUBSECTION Private>
gtk_filter_list_model_get_type
</SECTION>
<SECTION>
<FILE>gtkfixed</FILE>
<TITLE>GtkFixed</TITLE>
@@ -1279,24 +1262,6 @@ GtkFixedChild
gtk_fixed_get_type
</SECTION>
<SECTION>
<FILE>gtkflattenlistmodel</FILE>
<TITLE>GtkFlattenListModel</TITLE>
GtkFlattenListModel
gtk_flatten_list_model_new
gtk_flatten_list_model_set_model
gtk_flatten_list_model_get_model
<SUBSECTION Standard>
GTK_FLATTEN_LIST_MODEL
GTK_IS_FLATTEN_LIST_MODEL
GTK_TYPE_FLATTEN_LIST_MODEL
GTK_FLATTEN_LIST_MODEL_CLASS
GTK_IS_FLATTEN_LIST_MODEL_CLASS
GTK_FLATTEN_LIST_MODEL_GET_CLASS
<SUBSECTION Private>
gtk_flatten_list_model_get_type
</SECTION>
<SECTION>
<FILE>gtkfontbutton</FILE>
<TITLE>GtkFontButton</TITLE>
@@ -1744,27 +1709,6 @@ GtkLinkButtonPrivate
gtk_link_button_get_type
</SECTION>
<SECTION>
<FILE>gtkmaplistmodel</FILE>
<TITLE>GtkMapListModel</TITLE>
GtkMapListModel
GtkMapListModelMapFunc
gtk_map_list_model_new
gtk_map_list_model_set_map_func
gtk_map_list_model_set_model
gtk_map_list_model_get_model
gtk_map_list_model_has_map
<SUBSECTION Standard>
GTK_MAP_LIST_MODEL
GTK_IS_MAP_LIST_MODEL
GTK_TYPE_MAP_LIST_MODEL
GTK_MAP_LIST_MODEL_CLASS
GTK_IS_MAP_LIST_MODEL_CLASS
GTK_MAP_LIST_MODEL_GET_CLASS
<SUBSECTION Private>
gtk_map_list_model_get_type
</SECTION>
<SECTION>
<FILE>gtkmenu</FILE>
<TITLE>GtkMenu</TITLE>
@@ -2593,51 +2537,6 @@ GtkSizeGroupPrivate
gtk_size_group_get_type
</SECTION>
<SECTION>
<FILE>gtkslicelistmodel</FILE>
<TITLE>GtkSliceListModel</TITLE>
GtkSliceListModel
gtk_slice_list_model_new
gtk_slice_list_model_new_for_type
gtk_slice_list_model_set_model
gtk_slice_list_model_get_model
gtk_slice_list_model_set_offset
gtk_slice_list_model_get_offset
gtk_slice_list_model_set_size
gtk_slice_list_model_get_size
<SUBSECTION Standard>
GTK_SLICE_LIST_MODEL
GTK_IS_SLICE_LIST_MODEL
GTK_TYPE_SLICE_LIST_MODEL
GTK_SLICE_LIST_MODEL_CLASS
GTK_IS_SLICE_LIST_MODEL_CLASS
GTK_SLICE_LIST_MODEL_GET_CLASS
<SUBSECTION Private>
gtk_slice_list_model_get_type
</SECTION>
<SECTION>
<FILE>gtksortlistmodel</FILE>
<TITLE>GtkSortListModel</TITLE>
GtkSortListModel
gtk_sort_list_model_new
gtk_sort_list_model_new_for_type
gtk_sort_list_model_set_sort_func
gtk_sort_list_model_has_sort
gtk_sort_list_model_set_model
gtk_sort_list_model_get_model
gtk_sort_list_model_resort
<SUBSECTION Standard>
GTK_SORT_LIST_MODEL
GTK_IS_SORT_LIST_MODEL
GTK_TYPE_SORT_LIST_MODEL
GTK_SORT_LIST_MODEL_CLASS
GTK_IS_SORT_LIST_MODEL_CLASS
GTK_SORT_LIST_MODEL_GET_CLASS
<SUBSECTION Private>
gtk_sort_list_model_get_type
</SECTION>
<SECTION>
<FILE>gtkspinbutton</FILE>
<TITLE>GtkSpinButton</TITLE>
@@ -3372,49 +3271,6 @@ GTK_TOOLTIP
gtk_tooltip_get_type
</SECTION>
<SECTION>
<FILE>gtktreelistmodel</FILE>
<TITLE>GtkTreeListModel</TITLE>
GtkTreeListModel
GtkTreeListRow
GtkTreeListModelCreateModelFunc
gtk_tree_list_model_new
gtk_tree_list_model_get_model
gtk_tree_list_model_get_passthrough
gtk_tree_list_model_set_autoexpand
gtk_tree_list_model_get_autoexpand
gtk_tree_list_model_get_child_row
gtk_tree_list_model_get_row
<SUBSECTION>
gtk_tree_list_row_get_item
gtk_tree_list_row_set_expanded
gtk_tree_list_row_get_expanded
gtk_tree_list_row_is_expandable
gtk_tree_list_row_get_position
gtk_tree_list_row_get_depth
gtk_tree_list_row_get_children
gtk_tree_list_row_get_parent
gtk_tree_list_row_get_child_row
<SUBSECTION Standard>
GTK_TREE_LIST_MODEL
GTK_IS_TREE_LIST_MODEL
GTK_TYPE_TREE_LIST_MODEL
GTK_TREE_LIST_MODEL_CLASS
GTK_IS_TREE_LIST_MODEL_CLASS
GTK_TREE_LIST_MODEL_GET_CLASS
GTK_TREE_LIST_ROW
GTK_IS_TREE_LIST_ROW
GTK_TYPE_TREE_LIST_ROW
GTK_TREE_LIST_ROW_CLASS
GTK_IS_TREE_LIST_ROW_CLASS
GTK_TREE_LIST_ROW_GET_CLASS
<SUBSECTION Private>
gtk_tree_list_model_get_type
gtk_tree_list_row_get_type
</SECTION>
<SECTION>
<FILE>gtktreemodel</FILE>
<TITLE>GtkTreeModel</TITLE>
@@ -4421,6 +4277,7 @@ gtk_widget_list_accel_closures
gtk_widget_can_activate_accel
gtk_widget_event
gtk_widget_activate
gtk_widget_intersect
gtk_widget_is_focus
gtk_widget_grab_focus
gtk_widget_grab_default
@@ -4603,10 +4460,6 @@ gtk_widget_class_bind_template_callback
gtk_widget_class_bind_template_callback_full
gtk_widget_class_set_connect_func
<SUBSECTION>
gtk_widget_observe_children
gtk_widget_observe_controllers
<SUBSECTION Standard>
GTK_WIDGET
GTK_IS_WIDGET
@@ -4650,7 +4503,6 @@ gtk_window_set_destroy_with_parent
gtk_window_set_display
gtk_window_is_active
gtk_window_is_maximized
gtk_window_get_toplevels
gtk_window_list_toplevels
gtk_window_add_mnemonic
gtk_window_remove_mnemonic
@@ -6604,24 +6456,6 @@ GTK_GESTURE_SINGLE_GET_CLASS
gtk_gesture_single_get_type
</SECTION>
<SECTION>
<FILE>gtkeventcontrollerlegacy</FILE>
<TITLE>GtkEventControllerlegacy</TITLE>
GtkEventControllerlegacy
gtk_event_controller_legacy_new
<SUBSECTION Standard>
GTK_TYPE_EVENT_CONTROLLER_LEGACY
GTK_EVENT_CONTROLLER_LEGACY
GTK_EVENT_CONTROLLER_LEGACY_CLASS
GTK_IS_EVENT_CONTROLLER_LEGACY
GTK_IS_EVENT_CONTROLLER_LEGACY_CLASS
GTK_EVENT_CONTROLLER_LEGACY_GET_CLASS
<SUBSECTION Private>
gtk_event_controller_legacy_get_type
</SECTION>
<SECTION>
<FILE>gtkeventcontrollerscroll</FILE>
<TITLE>GtkEventControllerScroll</TITLE>
-1
View File
@@ -54,7 +54,6 @@ gtk_entry_completion_get_type
gtk_entry_get_type
gtk_event_controller_get_type
gtk_event_controller_key_get_type
gtk_event_controller_legacy_get_type
gtk_event_controller_motion_get_type
gtk_event_controller_scroll_get_type
gtk_expander_get_type
+2 -3
View File
@@ -340,6 +340,7 @@ content_files = [
'css-overview.xml',
'css-properties.xml',
'drawing-model.xml',
'getting_started.xml',
'glossary.xml',
'gtk4-broadwayd.xml',
'gtk4-builder-tool.xml',
@@ -362,7 +363,6 @@ content_files = [
'running.sgml',
'text_widget.sgml',
'tree_widget.sgml',
'treeview_tutorial.xml',
'visual_index.xml',
'wayland.xml',
'windows.sgml',
@@ -372,6 +372,7 @@ content_files = [
expand_content_files = [
'compiling.sgml',
'drawing-model.xml',
'getting_started.xml',
'glossary.xml',
'input-handling.xml',
'migrating-2to4.xml',
@@ -379,11 +380,9 @@ expand_content_files = [
'question_index.sgml',
'text_widget.sgml',
'tree_widget.sgml',
'treeview_tutorial.xml',
]
configure_file(input: 'version.xml.in', output: 'version.xml', configuration: version_conf)
configure_file(input: 'getting_started.xml.in', output: 'getting_started.xml', configuration: src_dir_conf)
types_conf = configuration_data()
if os_win32
-28
View File
@@ -177,22 +177,6 @@
</para>
</section>
<section>
<title>Set a proper app_id</title>
<para>
In GTK+4 we want the application's #GApplication
'application-id' (and therefore the D-Bus name), the desktop
file basename and Wayland's xdg-shell app_id to match. In
order to achieve this with GTK+3 call g_set_prgname() with the same
application id you passed to #GtkApplication. Rename your
desktop files to match the application id if needed.
</para>
<para>
The call to g_set_prgname() can be removed once you fully migrated
to GTK+4.
</para>
</section>
</section>
<section>
@@ -286,14 +270,6 @@
</para>
</section>
<section>
<title>Stop using GtkEventBox</title>
<para>
GtkEventBox is no longer needed and has been removed.
All widgets receive all events.
</para>
</section>
<section>
<title>Adapt to GtkHeaderBar API changes</title>
<para>
@@ -432,10 +408,6 @@
from ui files it run the command <command>gtk4-builder-tool simplify --replace</command>
on them.
</para>
<para>
The function gtk_widget_show_all(), the #GtkWidget::no-show-all property
and its getter and setter have been removed in GTK+ 4, so you should stop using them.
</para>
</section>
<section>
-143
View File
@@ -1,143 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
]>
<refentry id="TreeView-tutorial">
<refmeta>
<refentrytitle>TreeView Tutorial</refentrytitle>
<manvolnum>3</manvolnum>
<refmiscinfo>GTK Library</refmiscinfo>
</refmeta>
<refnamediv>
<refname>TreeView Tutorial</refname>
<refpurpose>A tutorial on the use of GtkTreeModel, GtkTreeView, and friends</refpurpose>
</refnamediv>
<refsect1>
<title>Overview</title>
<para>GtkTreeView is a widget that displays single- or multi-columned
lists and trees.</para>
<para>The purpose of this tutorial is not to provide an exhaustive
documentation of #GtkTreeView - that is what the API documentation is
for, which should be read alongside with this tutorial. The goal is
rather to present an introduction to the most commonly-used aspects
of #GtkTreeView, and to demonstrate how the various #GtkTreeView
components and concepts work together. Furthermore, an attempt has
been made to shed some light on custom tree models and custom cell
renderers, which seem to be often-mentioned, but rarely
explained.</para>
<para>Developers looking for a quick and dirty introduction that
teaches them everything they need to know in less than five paragraphs
will not find it here. In the author's experience, developers who do
not understand how the tree view and the models work together will run
into problems once they try to modify the given examples, whereas
developers who have worked with other toolkits that employ the
Model/View/Controller-design will find that the API reference provides
all the information they need to know in more condensed form anyway.
Those who disagree may jump straight to the working example code of
course.</para>
<para>Please note that the code examples in the following sections do
not necessarily demonstrate how GtkTreeView is used best in a particular
situation. There are different ways to achieve the same result, and the
examples merely show those different ways, so that developers are able
to decide which one is most suitable for the task at hand.</para>
<refsect2>
<title>Components</title>
<para>The most important concept underlying #GtkTreeView is that of
complete separation between data and how that data is displayed on
the screen. This is commonly known as Model/View/Controller-design,
or MVC. Data of various type (strings, numbers, images, etc.) is
stored in a "model". The "view" is then told which data to display,
where to display it, and how to display it. One of the advantages
of this approach is that you can have multiple views that display
the same data (a directory tree for example) in different ways, or
in the same way multiple times, with only one copy of the underlying
data. This avoids duplication of data and programming effort if the
same data is re-used in different contexts. Also, when the data in
the model is updated, all views automatically get updated as
well.</para>
<para>So, while #GtkTreeModel is used to store data, there are other
components that determine which data is displayed in the #GtkTreeView
and how it is displayed. These components are #GtkTreeViewColumn and
#GtkCellRenderer. A #GtkTreeView is made up of tree view columns.
These are the columns that users perceive as columns. They have a
clickable column header with a column title that can be hidden, and
can be resized and sorted. Tree view columns do not display any data,
they are only used as a device to represent the user-side of the tree
view (sorting etc.) and serve as packing widgets for the components
that do the actual rendering of data onto the screen, namely the
#GtkCellRenderer family of objects. There are a number of different
cell renderers that specialise in rendering certain data like
strings, pixbufs, or toggle buttons. More on this later.</para>
<para>Cell renderers are packed into tree view columns to display data.
A tree view column needs to contain at least one cell renderer, but can
contain multiple cell renderers. For example, if one wanted to display
a 'Filename' column where each filename has a little icon on the left
indicating the file type, one would pack a GtkCellRendererPixbuf and a
GtkCellRendererText into one tree view column. Packing renderers into a
tree view column is similar to packing widgets into a #GtkBox.</para>
</refsect2>
<refsect2>
<title>GtkTreeModels for Data Storage: GtkListStore and GtkTreeStore</title>
<para>It is important to realise what #GtkTreeModel is and what it is
not. #GtkTreeModel is basically just an 'interface' to the data store,
meaning that it is a standardised set of functions that allows a
#GtkTreeView widget (and the application programmer) to query certain
characteristics of a data store, for example how many rows there are,
which rows have children, and how many children a particular row has.
It also provides functions to retrieve data from the data store, and
tell the tree view what type of data is stored in the model. Every
data store must implement the #GtkTreeModel interface and provide these
functions. #GtkTreeModel itself only provides a way to query a data
store's characteristics and to retrieve existing data, it does not
provide a way to remove or add rows to the store or put data into the
store. This is done using the specific store's functions.</para>
<para>GTK comes with two built-in data stores (models): #GtkListStore
and #GtkTreeStore. As the names imply, #GtkListStore is used for simple
lists of data items where items have no hierarchical parent-child
relationships, and #GtkTreeStore is used for tree-like data structures,
where items can have parent-child relationships. A list of files in a
directory would be an example of a simple list structure, whereas a
directory tree is an example for a tree structure. A list is basically
just a special case of a tree with none of the items having any
children, so one could use a tree store to maintain a simple list of
items as well. The only reason #GtkListStore exists is in order to
provide an easier interface that does not need to cater for
child-parent relationships, and because a simple list model can be
optimised for the special case where no children exist, which makes it
faster and more efficient.</para>
<para>#GtkListStore and #GtkTreeStore should cater for most types of
data an application developer might want to display in a #GtkTreeView.
However, it should be noted that #GtkListStore and #GtkTreeStore have
been designed to cater to a large number of potential use cases, and
so are not overly optimized. If you already have your specialized data
store; if you plan to store a lot of data; or if have a large number
of rows, you should consider implementing your own custom model that
stores and manipulates data your own way and implements the
#GtkTreeModel interface. This will not only be more efficient, but
probably also lead to saner code in the long run, and give you more
control over your data. See below for more details on how to implement
custom models.</para>
<para>Tree model implementations like #GtkListStore and #GtkTreeStore
will take care of the view side for you once you have configured the
#GtkTreeView to display what you want. If you change data in the store,
the model will notify the tree view and your data display will be
updated. If you add or remove rows, the model will also notify the
store, and your row will appear in or disappear from the view as
well.</para>
</refsect2>
</refsect1>
-3
View File
@@ -12,9 +12,6 @@ docpath = join_paths(gtk_datadir, 'gtk-doc', 'html')
version_conf = configuration_data()
version_conf.set('GTK_VERSION', meson.project_version())
src_dir_conf = configuration_data()
src_dir_conf.set('SRC_DIR', meson.source_root())
subdir('gdk')
subdir('gsk')
subdir('gtk')
+2 -2
View File
@@ -2,8 +2,8 @@ To make gnome-shell use the desktop file and icon for this example
while running it uninstalled, do the following:
mkdir -p ~/.local/share/applications
sed -e "s#@bindir@#$PWD#" org.gtk.exampleapp.desktop \
> ~/.local/share/applications/org.gtk.exampleapp.desktop
sed -e "s#@bindir@#$PWD#" exampleapp.desktop \
> ~/.local/share/applications/lt-exampleapp.desktop
mkdir -p ~/.local/share/icons/hicolor/48x48/apps
cp exampleapp.png ~/.local/share/icons/hicolor/48x48/apps
+1
View File
@@ -285,6 +285,7 @@ _gdk_broadway_events_got_input (BroadwayInputMsg *message)
event->key.state = message->key.state;
event->key.hardware_keycode = message->key.key;
gdk_event_set_scancode (event, message->key.key);
event->key.length = 0;
gdk_event_set_device (event, gdk_seat_get_keyboard (seat));
node = _gdk_event_queue_append (display, event);
-1
View File
@@ -32,7 +32,6 @@ void gdk_display_set_cursor_theme (GdkDisplay *display,
const char *theme,
int size);
gboolean gdk_running_in_sandbox (void);
gboolean gdk_should_use_portal (void);
const gchar * gdk_get_startup_notification_id (void);
+6 -19
View File
@@ -269,27 +269,14 @@ gdk_get_startup_notification_id (void)
gboolean
gdk_running_in_sandbox (void)
{
return g_file_test ("/.flatpak-info", G_FILE_TEST_EXISTS);
}
char *path;
gboolean ret;
gboolean
gdk_should_use_portal (void)
{
static const char *use_portal = NULL;
path = g_build_filename (g_get_user_runtime_dir (), "flatpak-info", NULL);
ret = g_file_test (path, G_FILE_TEST_EXISTS);
g_free (path);
if (G_UNLIKELY (use_portal == NULL))
{
if (gdk_running_in_sandbox ())
use_portal = "1";
else
{
use_portal = g_getenv ("GTK_USE_PORTAL");
if (!use_portal)
use_portal = "";
}
}
return use_portal[0] == '1';
return ret;
}
/**
+1 -1
View File
@@ -107,7 +107,7 @@ gdk_drop_read_local_async (GdkDrop *self,
if (priv->drag == NULL)
{
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
_("Dragndrop from other applications is not supported."));
_("Drag'n'drop from other applications is not supported."));
g_object_unref (task);
return;
}
+41
View File
@@ -631,6 +631,11 @@ gdk_event_copy (const GdkEvent *event)
switch ((guint) event->any.type)
{
case GDK_KEY_PRESS:
case GDK_KEY_RELEASE:
new_event->key.string = g_strdup (event->key.string);
break;
case GDK_ENTER_NOTIFY:
case GDK_LEAVE_NOTIFY:
if (event->crossing.child_surface != NULL)
@@ -693,6 +698,11 @@ gdk_event_finalize (GObject *object)
switch ((guint) event->any.type)
{
case GDK_KEY_PRESS:
case GDK_KEY_RELEASE:
g_free (event->key.string);
break;
case GDK_ENTER_NOTIFY:
case GDK_LEAVE_NOTIFY:
g_clear_object (&event->crossing.child_surface);
@@ -1283,6 +1293,37 @@ gdk_event_get_key_group (const GdkEvent *event,
return fetched;
}
/**
* gdk_event_get_string:
* @event: a #GdkEvent
* @string: (out) (transfer none): return location for the string
*
* Extracts a string from an event. The string is an
* approximation of the keyval in a key event.
*
* Returns: %TRUE on success, otherwise %FALSE
**/
gboolean
gdk_event_get_string (const GdkEvent *event,
const char **string)
{
gboolean fetched = TRUE;
switch ((guint) event->any.type)
{
case GDK_KEY_PRESS:
case GDK_KEY_RELEASE:
*string = event->key.string;
break;
default:
*string = NULL;
fetched = FALSE;
break;
}
return fetched;
}
/**
* gdk_event_get_key_is_modifier:
* @event: a #GdkEvent
+4 -1
View File
@@ -54,7 +54,7 @@ G_BEGIN_DECLS
#define GDK_PRIORITY_EVENTS (G_PRIORITY_DEFAULT)
/**
* GDK_PRIORITY_REDRAW: (value 120)
* GDK_PRIORITY_REDRAW:
*
* This is the priority that the idle handler processing surface updates
* is given in the
@@ -403,6 +403,9 @@ gboolean gdk_event_get_key_is_modifier (const GdkEvent *event,
GDK_AVAILABLE_IN_ALL
gboolean gdk_event_get_key_group (const GdkEvent *event,
guint *group);
GDK_AVAILABLE_IN_ALL
gboolean gdk_event_get_string (const GdkEvent *event,
const char **string);
GDK_AVAILABLE_IN_ALL
gboolean gdk_event_get_scroll_direction (const GdkEvent *event,
+14
View File
@@ -244,6 +244,18 @@ struct _GdkEventScroll
* @keyval: the key that was pressed or released. See the
* `gdk/gdkkeysyms.h` header file for a
* complete list of GDK key codes.
* @length: the length of @string.
* @string: a string containing an approximation of the text that
* would result from this keypress. The only correct way to handle text
* input of text is using input methods (see #GtkIMContext), so this
* field is deprecated and should never be used.
* (gdk_unicode_to_keyval() provides a non-deprecated way of getting
* an approximate translation for a key.) The string is encoded in the
* encoding of the current locale (Note: this for backwards compatibility:
* strings in GTK+ and GDK are typically in UTF-8.) and NUL-terminated.
* In some cases, the translation of the key code will be a single
* NUL byte, in which case looking at @length is necessary to distinguish
* it from the an empty translation.
* @hardware_keycode: the raw code of the key that was pressed or released.
* @group: the keyboard group.
* @is_modifier: a flag that indicates if @hardware_keycode is mapped to a
@@ -257,6 +269,8 @@ struct _GdkEventKey
guint32 time;
guint state;
guint keyval;
gint length;
gchar *string;
guint16 hardware_keycode;
guint16 key_scancode;
guint8 group;
+8 -8
View File
@@ -175,7 +175,7 @@ parse_rgb_value (const gchar *str,
* - A RGBA color in the form “rgba(r,g,b,a)”
*
* Where “r”, “g”, “b” and “a” are respectively the red, green, blue and
* alpha color values. In the last two cases, “r”, “g”, and “b” are either integers
* alpha color values. In the last two cases, r g and b are either integers
* in the range 0 to 255 or percentage values in the range 0% to 100%, and
* a is a floating point value in the range 0 to 1.
*
@@ -353,18 +353,18 @@ gdk_rgba_equal (gconstpointer p1,
* @rgba: a #GdkRGBA
*
* Returns a textual specification of @rgba in the form
* `rgb(r,g,b)` or
* `rgba(r g,b,a)`,
* `rgb (r, g, b)` or
* `rgba (r, g, b, a)`,
* where “r”, “g”, “b” and “a” represent the red, green,
* blue and alpha values respectively. “r”, “g”, and “b” are
* represented as integers in the range 0 to 255, and “a”
* is represented as a floating point value in the range 0 to 1.
* blue and alpha values respectively. r, g, and b are
* represented as integers in the range 0 to 255, and a
* is represented as floating point value in the range 0 to 1.
*
* These string forms are string forms that are supported by
* These string forms are string forms those supported by
* the CSS3 colors module, and can be parsed by gdk_rgba_parse().
*
* Note that this string representation may lose some
* precision, since “r”, “g” and “b” are represented as 8-bit
* precision, since r, g and b are represented as 8-bit
* integers. If this is a concern, you should use a
* different representation.
*
+2 -3
View File
@@ -434,15 +434,14 @@ gdk_seat_tool_removed (GdkSeat *seat,
GdkDeviceTool *
gdk_seat_get_tool (GdkSeat *seat,
guint64 serial,
guint64 hw_id)
guint64 serial)
{
GdkSeatClass *seat_class;
g_return_val_if_fail (GDK_IS_SEAT (seat), NULL);
seat_class = GDK_SEAT_GET_CLASS (seat);
return seat_class->get_tool (seat, serial, hw_id);
return seat_class->get_tool (seat, serial);
}
/**
+4 -4
View File
@@ -282,8 +282,7 @@ gdk_seat_default_get_slaves (GdkSeat *seat,
static GdkDeviceTool *
gdk_seat_default_get_tool (GdkSeat *seat,
guint64 serial,
guint64 hw_id)
guint64 serial)
{
GdkSeatDefaultPrivate *priv;
GdkDeviceTool *tool;
@@ -298,7 +297,7 @@ gdk_seat_default_get_tool (GdkSeat *seat,
{
tool = g_ptr_array_index (priv->tools, i);
if (tool->serial == serial && tool->hw_id == hw_id)
if (tool->serial == serial)
return tool;
}
@@ -458,7 +457,8 @@ gdk_seat_default_remove_tool (GdkSeatDefault *seat,
priv = gdk_seat_default_get_instance_private (seat);
if (tool != gdk_seat_get_tool (GDK_SEAT (seat), tool->serial, tool->hw_id))
if (tool != gdk_seat_get_tool (GDK_SEAT (seat),
gdk_device_tool_get_serial (tool)))
return;
g_signal_emit_by_name (seat, "tool-removed", tool);
+2 -4
View File
@@ -57,8 +57,7 @@ struct _GdkSeatClass
GdkSeatCapabilities capabilities);
GdkDeviceTool * (* get_tool) (GdkSeat *seat,
guint64 serial,
guint64 tool_id);
guint64 serial);
GList * (* get_master_pointers) (GdkSeat *seat,
GdkSeatCapabilities capabilities);
};
@@ -75,7 +74,6 @@ void gdk_seat_tool_removed (GdkSeat *seat,
GdkDeviceTool *
gdk_seat_get_tool (GdkSeat *seat,
guint64 serial,
guint64 hw_id);
guint64 serial);
#endif /* __GDK_SEAT_PRIVATE_H__ */
+31 -3
View File
@@ -461,6 +461,12 @@ gdk_surface_get_property (GObject *object,
}
}
static gboolean
gdk_surface_is_subsurface (GdkSurface *surface)
{
return surface->surface_type == GDK_SURFACE_SUBSURFACE;
}
static GdkSurface *
gdk_surface_get_impl_surface (GdkSurface *surface)
{
@@ -549,7 +555,10 @@ recompute_visible_regions_internal (GdkSurface *private,
old_abs_y = private->abs_y;
/* Update absolute position */
if (gdk_surface_has_impl (private))
if ((gdk_surface_has_impl (private) &&
private->surface_type != GDK_SURFACE_SUBSURFACE) ||
(gdk_surface_is_toplevel (private) &&
private->surface_type == GDK_SURFACE_SUBSURFACE))
{
/* Native surfaces and toplevel subsurfaces start here */
private->abs_x = 0;
@@ -668,6 +677,15 @@ gdk_surface_new (GdkDisplay *display,
if (parent != NULL)
g_warning (G_STRLOC "Toplevel surfaces must be created without a parent");
break;
case GDK_SURFACE_SUBSURFACE:
#ifdef GDK_WINDOWING_WAYLAND
if (!GDK_IS_WAYLAND_DISPLAY (display))
{
g_warning (G_STRLOC "Subsurface surfaces can only be used on Wayland");
return NULL;
}
#endif
break;
case GDK_SURFACE_CHILD:
break;
default:
@@ -697,6 +715,11 @@ gdk_surface_new (GdkDisplay *display,
native = TRUE; /* Always use native surfaces for toplevels */
}
#ifdef GDK_WINDOWING_WAYLAND
if (surface->surface_type == GDK_SURFACE_SUBSURFACE)
native = TRUE; /* Always use native windows for subsurfaces as well */
#endif
if (native)
{
/* Create the impl */
@@ -899,6 +922,7 @@ _gdk_surface_destroy_hierarchy (GdkSurface *surface,
case GDK_SURFACE_TOPLEVEL:
case GDK_SURFACE_CHILD:
case GDK_SURFACE_TEMP:
case GDK_SURFACE_SUBSURFACE:
if (surface->parent)
{
if (surface->parent->children)
@@ -1149,7 +1173,10 @@ gdk_surface_get_parent (GdkSurface *surface)
{
g_return_val_if_fail (GDK_IS_SURFACE (surface), NULL);
return surface->parent;
if (gdk_surface_is_subsurface (surface))
return surface->transient_for;
else
return surface->parent;
}
/**
@@ -1169,7 +1196,8 @@ gdk_surface_get_toplevel (GdkSurface *surface)
{
g_return_val_if_fail (GDK_IS_SURFACE (surface), NULL);
while (surface->surface_type == GDK_SURFACE_CHILD)
while (surface->surface_type == GDK_SURFACE_CHILD ||
surface->surface_type == GDK_SURFACE_SUBSURFACE)
{
if (gdk_surface_is_toplevel (surface))
break;
+7 -2
View File
@@ -43,7 +43,11 @@ typedef struct _GdkGeometry GdkGeometry;
* GdkSurfaceType:
* @GDK_SURFACE_TOPLEVEL: toplevel window (used to implement #GtkWindow)
* @GDK_SURFACE_CHILD: child surface (used to implement e.g. #GtkEntry)
* @GDK_SURFACE_TEMP: override redirect temporary surface (used to implement #GtkMenu)
* @GDK_SURFACE_TEMP: override redirect temporary surface (used to implement
* #GtkMenu)
* @GDK_SURFACE_SUBSURFACE: subsurface; This surface is visually
* tied to a toplevel, and is moved/stacked with it. Currently this window
* type is only implemented in Wayland
*
* Describes the kind of surface.
*/
@@ -51,7 +55,8 @@ typedef enum
{
GDK_SURFACE_TOPLEVEL,
GDK_SURFACE_CHILD,
GDK_SURFACE_TEMP
GDK_SURFACE_TEMP,
GDK_SURFACE_SUBSURFACE
} GdkSurfaceType;
/* Size restriction enumeration.
+2 -7
View File
@@ -190,11 +190,6 @@ gdk_vulkan_strerror (VkResult result)
case 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";
#endif
case VK_RESULT_RANGE_SIZE:
case VK_RESULT_MAX_ENUM:
default:
@@ -711,7 +706,7 @@ gdk_vulkan_context_get_image (GdkVulkanContext *context,
*
* Gets the index of the image that is currently being drawn.
*
* This function can only be used between gdk_draw_context_begin_frame() and
* This function can only be used between gdk_cairo_context_begin_frame() and
* gdk_draw_context_end_frame() calls.
*
* Returns: the index of the images that is being drawn
@@ -734,7 +729,7 @@ gdk_vulkan_context_get_draw_index (GdkVulkanContext *context)
* Gets the Vulkan semaphore that protects access to the image that is
* currently being drawn.
*
* This function can only be used between gdk_draw_context_begin_frame() and
* This function can only be used between gdk_cairo_context_begin_frame() and
* gdk_draw_context_end_frame() calls.
*
* Returns: (transfer none): the VkSemaphore
+40
View File
@@ -1113,6 +1113,8 @@ fill_key_event (GdkSurface *window,
{
GdkEventPrivate *priv;
GdkQuartzDeviceManagerCore *device_manager;
gchar buf[7];
gunichar c = 0;
priv = (GdkEventPrivate *) event;
priv->windowing_data = [nsevent retain];
@@ -1187,6 +1189,44 @@ fill_key_event (GdkSurface *window,
gdk_keymap_add_virtual_modifiers (gdk_display_get_keymap (_gdk_display),
&event->key.state);
event->key.string = NULL;
/* Fill in ->string since apps depend on it, taken from the x11 backend. */
if (event->key.keyval != GDK_KEY_VoidSymbol)
c = gdk_keyval_to_unicode (event->key.keyval);
if (c)
{
gsize bytes_written;
gint len;
len = g_unichar_to_utf8 (c, buf);
buf[len] = '\0';
event->key.string = g_locale_from_utf8 (buf, len,
NULL, &bytes_written,
NULL);
if (event->key.string)
event->key.length = bytes_written;
}
else if (event->key.keyval == GDK_KEY_Escape)
{
event->key.length = 1;
event->key.string = g_strdup ("\033");
}
else if (event->key.keyval == GDK_KEY_Return ||
event->key.keyval == GDK_KEY_KP_Enter)
{
event->key.length = 1;
event->key.string = g_strdup ("\r");
}
if (!event->key.string)
{
event->key.length = 0;
event->key.string = g_strdup ("");
}
GDK_NOTE(EVENTS,
g_message ("key %s:\t\twindow: %p key: %12s %d",
type == GDK_KEY_PRESS ? "press" : "release",
+5 -12
View File
@@ -35,19 +35,12 @@ gdk_quartz_monitor_get_workarea (GdkMonitor *monitor,
GDK_QUARTZ_ALLOC_POOL;
NSArray *array = [NSScreen screens];
if (quartz_monitor->monitor_num < [array count])
{
NSScreen *screen = [array objectAtIndex:quartz_monitor->monitor_num];
NSRect rect = [screen visibleFrame];
NSRect rect = [quartz_monitor->nsscreen visibleFrame];
dest->x = rect.origin.x - quartz_screen->min_x;
dest->y = quartz_screen->height - (rect.origin.y + rect.size.height) + quartz_screen->min_y;
dest->width = rect.size.width;
dest->height = rect.size.height;
}
else
*dest = monitor->geometry;
dest->x = rect.origin.x - quartz_screen->min_x;
dest->y = quartz_screen->height - (rect.origin.y + rect.size.height) + quartz_screen->min_y;
dest->width = rect.size.width;
dest->height = rect.size.height;
GDK_QUARTZ_RELEASE_POOL;
}
+1 -1
View File
@@ -30,7 +30,7 @@ struct _GdkQuartzMonitor
{
GdkMonitor parent;
gint monitor_num;
NSScreen *nsscreen;
};
struct _GdkQuartzMonitorClass {
+1 -3
View File
@@ -52,9 +52,7 @@ typedef enum
GDK_OSX_YOSEMITE = 10,
GDK_OSX_EL_CAPITAN = 11,
GDK_OSX_SIERRA = 12,
GDK_OSX_HIGH_SIERRA = 13,
GDK_OSX_MOJAVE = 14,
GDK_OSX_CURRENT = 14,
GDK_OSX_CURRENT = 12,
GDK_OSX_NEW = 99
} GdkOSXVersion;
+1 -1
View File
@@ -144,7 +144,7 @@ gdk_quartz_screen_calculate_layout (GdkQuartzScreen *screen)
"display", display,
NULL);
g_ptr_array_add (display_quartz->monitors, monitor);
monitor->monitor_num = i;
monitor->nsscreen = [array objectAtIndex:i];
NSRect rect = [[array objectAtIndex:i] frame];
+7 -11
View File
@@ -134,12 +134,8 @@ gdk_surface_impl_quartz_get_context (GdkSurfaceImplQuartz *surface_impl,
if (![surface_impl->view lockFocusIfCanDraw])
return NULL;
}
if (gdk_quartz_osx_version () < GDK_OSX_YOSEMITE)
cg_context = [[NSGraphicsContext currentContext] graphicsPort];
else
cg_context = [[NSGraphicsContext currentContext] CGContext];
if (!cg_context)
return NULL;
cg_context = [[NSGraphicsContext currentContext] graphicsPort];
CGContextSaveGState (cg_context);
CGContextSetAllowsAntialiasing (cg_context, antialias);
@@ -280,15 +276,15 @@ gdk_quartz_create_cairo_surface (GdkSurfaceImplQuartz *impl,
cg_context = gdk_quartz_surface_get_context (impl, TRUE);
if (!cg_context)
return NULL;
surface_data = g_new (GdkQuartzCairoSurfaceData, 1);
surface_data->surface_impl = impl;
surface_data->cg_context = cg_context;
if (cg_context)
surface = cairo_quartz_surface_create_for_cg_context (cg_context,
width, height);
else
surface = cairo_quartz_surface_create(CAIRO_FORMAT_ARGB32, width, height);
surface = cairo_quartz_surface_create_for_cg_context (cg_context,
width, height);
cairo_surface_set_user_data (surface, &gdk_quartz_cairo_key,
surface_data,
+71 -2
View File
@@ -2009,6 +2009,73 @@ keyboard_handle_leave (void *data,
static gboolean keyboard_repeat (gpointer data);
static void
translate_keyboard_string (GdkEventKey *event)
{
gunichar c = 0;
gchar buf[7];
/* Fill in event->string crudely, since various programs
* depend on it.
*/
event->string = NULL;
if (event->keyval != GDK_KEY_VoidSymbol)
c = gdk_keyval_to_unicode (event->keyval);
if (c)
{
gsize bytes_written;
gint len;
/* Apply the control key - Taken from Xlib */
if (event->state & GDK_CONTROL_MASK)
{
if ((c >= '@' && c < '\177') || c == ' ')
c &= 0x1F;
else if (c == '2')
{
event->string = g_memdup ("\0\0", 2);
event->length = 1;
buf[0] = '\0';
return;
}
else if (c >= '3' && c <= '7')
c -= ('3' - '\033');
else if (c == '8')
c = '\177';
else if (c == '/')
c = '_' & 0x1F;
}
len = g_unichar_to_utf8 (c, buf);
buf[len] = '\0';
event->string = g_locale_from_utf8 (buf, len,
NULL, &bytes_written,
NULL);
if (event->string)
event->length = bytes_written;
}
else if (event->keyval == GDK_KEY_Escape)
{
event->length = 1;
event->string = g_strdup ("\033");
}
else if (event->keyval == GDK_KEY_Return ||
event->keyval == GDK_KEY_KP_Enter)
{
event->length = 1;
event->string = g_strdup ("\r");
}
if (!event->string)
{
event->length = 0;
event->string = g_strdup ("");
}
}
static GSettings *
get_keyboard_settings (GdkWaylandSeat *seat)
{
@@ -2124,15 +2191,17 @@ deliver_key_event (GdkWaylandSeat *seat,
event->key.keyval = sym;
event->key.is_modifier = _gdk_wayland_keymap_key_is_modifier (keymap, key);
translate_keyboard_string (&event->key);
_gdk_wayland_display_deliver_event (seat->display, event);
GDK_DISPLAY_NOTE (seat->display, EVENTS,
g_message ("keyboard %s event%s, code %d, sym %d, "
"mods 0x%x",
"string %s, mods 0x%x",
(state ? "press" : "release"),
(from_key_repeat ? " (repeat)" : ""),
event->key.hardware_keycode, event->key.keyval,
event->key.state));
event->key.string, event->key.state));
if (!xkb_keymap_key_repeats (xkb_keymap, key))
return;
+59 -330
View File
@@ -730,10 +730,7 @@ gdk_wayland_display_finalize (GObject *object)
g_ptr_array_free (display_wayland->monitors, TRUE);
if (display_wayland->settings)
g_hash_table_destroy (display_wayland->settings);
g_clear_object (&display_wayland->settings_portal);
g_hash_table_destroy (display_wayland->settings);
G_OBJECT_CLASS (gdk_wayland_display_parent_class)->finalize (object);
}
@@ -1210,21 +1207,13 @@ open_shared_memory (void)
#if defined (__NR_memfd_create)
if (!force_shm_open)
{
int options = MFD_CLOEXEC;
#if defined (MFD_ALLOW_SEALING)
options |= MFD_ALLOW_SEALING;
#endif
ret = syscall (__NR_memfd_create, "gdk-wayland", options);
ret = syscall (__NR_memfd_create, "gdk-wayland", MFD_CLOEXEC);
/* fall back to shm_open until debian stops shipping 3.16 kernel
* See bug 766341
*/
if (ret < 0 && errno == ENOSYS)
force_shm_open = TRUE;
#if defined (F_ADD_SEALS) && defined (F_SEAL_SHRINK)
if (ret >= 0)
fcntl (ret, F_ADD_SEALS, F_SEAL_SHRINK);
#endif
}
#endif
@@ -1379,19 +1368,6 @@ typedef enum
GSD_FONT_ANTIALIASING_MODE_RGBA
} GsdFontAntialiasingMode;
static int
get_antialiasing (const char *s)
{
const char *names[] = { "none", "grayscale", "rgba" };
int i;
for (i = 0; i < G_N_ELEMENTS (names); i++)
if (strcmp (s, names[i]) == 0)
return i;
return 0;
}
typedef enum
{
GSD_FONT_HINTING_NONE,
@@ -1400,19 +1376,6 @@ typedef enum
GSD_FONT_HINTING_FULL
} GsdFontHinting;
static int
get_hinting (const char *s)
{
const char *names[] = { "none", "slight", "medium", "full" };
int i;
for (i = 0; i < G_N_ELEMENTS (names); i++)
if (strcmp (s, names[i]) == 0)
return i;
return 0;
}
typedef enum
{
GSD_FONT_RGBA_ORDER_RGBA,
@@ -1422,19 +1385,6 @@ typedef enum
GSD_FONT_RGBA_ORDER_VBGR
} GsdFontRgbaOrder;
static int
get_order (const char *s)
{
const char *names[] = { "rgba", "rgb", "bgr", "vrgb", "vbgr" };
int i;
for (i = 0; i < G_N_ELEMENTS (names); i++)
if (strcmp (s, names[i]) == 0)
return i;
return 0;
}
static gdouble
get_dpi_from_gsettings (GdkWaylandDisplay *display_wayland)
{
@@ -1451,26 +1401,6 @@ get_dpi_from_gsettings (GdkWaylandDisplay *display_wayland)
return 96.0 * factor;
}
/* When using the Settings portal, we cache the value in
* the fallback member, and we ignore the valid field
*/
typedef struct _TranslationEntry TranslationEntry;
struct _TranslationEntry {
gboolean valid;
const gchar *schema;
const gchar *key;
const gchar *setting;
GType type;
union {
const char *s;
gint i;
gboolean b;
} fallback;
};
static TranslationEntry * find_translation_entry_by_schema (const char *schema,
const char *key);
static void
update_xft_settings (GdkDisplay *display)
{
@@ -1481,47 +1411,25 @@ update_xft_settings (GdkDisplay *display)
GsdFontRgbaOrder order;
gboolean use_rgba = FALSE;
GsdXftSettings xft_settings;
double dpi;
if (display_wayland->settings_portal)
settings = g_hash_table_lookup (display_wayland->settings,
"org.gnome.settings-daemon.plugins.xsettings");
if (settings)
{
TranslationEntry *entry;
entry = find_translation_entry_by_schema ("org.gnome.settings-daemon.plugins.xsettings", "antialiasing");
antialiasing = entry->fallback.i;
entry = find_translation_entry_by_schema ("org.gnome.settings-daemon.plugins.xsettings", "hinting");
hinting = entry->fallback.i;
entry = find_translation_entry_by_schema ("org.gnome.settings-daemon.plugins.xsettings", "rgba-order");
order = entry->fallback.i;
entry = find_translation_entry_by_schema ("org.gnome.desktop.interface", "text-scaling-factor");
dpi = 96.0 * entry->fallback.i / 65536.0 * 1024; /* Xft wants 1/1024th of an inch */
antialiasing = g_settings_get_enum (settings, "antialiasing");
hinting = g_settings_get_enum (settings, "hinting");
order = g_settings_get_enum (settings, "rgba-order");
}
else
{
settings = g_hash_table_lookup (display_wayland->settings,
"org.gnome.settings-daemon.plugins.xsettings");
if (settings)
{
antialiasing = g_settings_get_enum (settings, "antialiasing");
hinting = g_settings_get_enum (settings, "hinting");
order = g_settings_get_enum (settings, "rgba-order");
}
else
{
antialiasing = GSD_FONT_ANTIALIASING_MODE_GRAYSCALE;
hinting = GSD_FONT_HINTING_MEDIUM;
order = GSD_FONT_RGBA_ORDER_RGB;
}
dpi = get_dpi_from_gsettings (display_wayland) * 1024;
antialiasing = GSD_FONT_ANTIALIASING_MODE_GRAYSCALE;
hinting = GSD_FONT_HINTING_MEDIUM;
order = GSD_FONT_RGBA_ORDER_RGB;
}
xft_settings.hinting = (hinting != GSD_FONT_HINTING_NONE);
xft_settings.dpi = dpi;
xft_settings.dpi = get_dpi_from_gsettings (display_wayland) * 1024; /* Xft wants 1/1024ths of an inch */
switch (hinting)
{
@@ -1608,6 +1516,23 @@ update_xft_settings (GdkDisplay *display)
}
}
#define WM_SETTINGS_SCHEMA "org.gnome.desktop.wm.preferences"
#define CLASSIC_WM_SETTINGS_SCHEMA "org.gnome.shell.extensions.classic-overrides"
typedef struct _TranslationEntry TranslationEntry;
struct _TranslationEntry {
gboolean valid;
const gchar *schema;
const gchar *key;
const gchar *setting;
GType type;
union {
const gchar *s;
gint i;
gboolean b;
} fallback;
};
static TranslationEntry translations[] = {
{ FALSE, "org.gnome.desktop.interface", "gtk-theme", "gtk-theme-name" , G_TYPE_STRING, { .s = "Adwaita" } },
{ FALSE, "org.gnome.desktop.interface", "icon-theme", "gtk-icon-theme-name", G_TYPE_STRING, { .s = "gnome" } },
@@ -1627,48 +1552,41 @@ static TranslationEntry translations[] = {
{ FALSE, "org.gnome.desktop.sound", "input-feedback-sounds", "gtk-enable-input-feedback-sounds", G_TYPE_BOOLEAN, { . b = FALSE } },
{ FALSE, "org.gnome.desktop.privacy", "recent-files-max-age", "gtk-recent-files-max-age", G_TYPE_INT, { .i = 30 } },
{ FALSE, "org.gnome.desktop.privacy", "remember-recent-files", "gtk-recent-files-enabled", G_TYPE_BOOLEAN, { .b = TRUE } },
{ FALSE, "org.gnome.desktop.wm.preferences", "button-layout", "gtk-decoration-layout", G_TYPE_STRING, { .s = "menu:close" } },
{ FALSE, WM_SETTINGS_SCHEMA, "button-layout", "gtk-decoration-layout", G_TYPE_STRING, { .s = "menu:close" } },
{ FALSE, CLASSIC_WM_SETTINGS_SCHEMA, "button-layout", "gtk-decoration-layout", G_TYPE_STRING, { .s = "menu:close" } },
{ FALSE, "org.gnome.settings-daemon.plugins.xsettings", "antialiasing", "gtk-xft-antialias", G_TYPE_NONE, { .i = 0 } },
{ FALSE, "org.gnome.settings-daemon.plugins.xsettings", "hinting", "gtk-xft-hinting", G_TYPE_NONE, { .i = 0 } },
{ FALSE, "org.gnome.settings-daemon.plugins.xsettings", "hinting", "gtk-xft-hintstyle", G_TYPE_NONE, { .i = 0 } },
{ FALSE, "org.gnome.settings-daemon.plugins.xsettings", "rgba-order", "gtk-xft-rgba", G_TYPE_NONE, { .i = 0 } },
{ FALSE, "org.gnome.desktop.interface", "text-scaling-factor", "gtk-xft-dpi" , G_TYPE_NONE, { .i = 0 } }, /* We store the factor as 16.16 */
{ FALSE, "org.gnome.desktop.interface", "text-scaling-factor", "gtk-xft-dpi" , G_TYPE_NONE, { .i = 0 } },
{ FALSE, "org.gnome.desktop.wm.preferences", "action-double-click-titlebar", "gtk-titlebar-double-click", G_TYPE_STRING, { .s = "toggle-maximize" } },
{ FALSE, "org.gnome.desktop.wm.preferences", "action-middle-click-titlebar", "gtk-titlebar-middle-click", G_TYPE_STRING, { .s = "none" } },
{ FALSE, "org.gnome.desktop.wm.preferences", "action-right-click-titlebar", "gtk-titlebar-right-click", G_TYPE_STRING, { .s = "menu" } },
{ FALSE, "org.gnome.desktop.a11y", "always-show-text-caret", "gtk-keynav-use-caret", G_TYPE_BOOLEAN, { .b = FALSE } },
{ FALSE, "org.gnome.fontconfig", "serial", "gtk-fontconfig-timestamp", G_TYPE_NONE, { .i = 0 } }
{ FALSE, "org.gnome.desktop.a11y", "always-show-text-caret", "gtk-keynav-use-caret", G_TYPE_BOOLEAN, { .b = FALSE } }
};
static TranslationEntry *
find_translation_entry_by_schema (const char *schema,
const char *key)
{
guint i;
for (i = 0; i < G_N_ELEMENTS (translations); i++)
{
if (g_str_equal (schema, translations[i].schema) &&
g_str_equal (key, translations[i].key))
return &translations[i];
}
return NULL;
}
static TranslationEntry *
find_translation_entry_by_key (GSettings *settings,
const char *key)
{
guint i;
char *schema;
TranslationEntry *entry;
g_object_get (settings, "schema", &schema, NULL);
entry = find_translation_entry_by_schema (schema, key);
for (i = 0; i < G_N_ELEMENTS (translations); i++)
{
if (g_str_equal (schema, translations[i].schema) &&
g_str_equal (key, translations[i].key))
{
g_free (schema);
return &translations[i];
}
}
g_free (schema);
return entry;
return NULL;
}
static TranslationEntry *
@@ -1703,79 +1621,6 @@ settings_changed (GSettings *settings,
}
}
static void
apply_portal_setting (TranslationEntry *entry,
GVariant *value,
GdkDisplay *display)
{
switch (entry->type)
{
case G_TYPE_STRING:
entry->fallback.s = g_intern_string (g_variant_get_string (value, NULL));
break;
case G_TYPE_INT:
entry->fallback.i = g_variant_get_int32 (value);
break;
case G_TYPE_BOOLEAN:
entry->fallback.b = g_variant_get_boolean (value);
break;
case G_TYPE_NONE:
if (strcmp (entry->key, "serial") == 0)
{
entry->fallback.i = g_variant_get_int32 (value);
break;
}
if (strcmp (entry->key, "antialiasing") == 0)
entry->fallback.i = get_antialiasing (g_variant_get_string (value, NULL));
else if (strcmp (entry->key, "hinting") == 0)
entry->fallback.i = get_hinting (g_variant_get_string (value, NULL));
else if (strcmp (entry->key, "rgba-order") == 0)
entry->fallback.i = get_order (g_variant_get_string (value, NULL));
else if (strcmp (entry->key, "text-scaling-factor") == 0)
entry->fallback.i = (int) (g_variant_get_double (value) * 65536.0);
update_xft_settings (display);
break;
default:
break;
}
}
static void
settings_portal_changed (GDBusProxy *proxy,
const char *sender_name,
const char *signal_name,
GVariant *parameters,
GdkDisplay *display)
{
if (strcmp (signal_name, "SettingChanged") == 0)
{
const char *namespace;
const char *name;
GVariant *value;
TranslationEntry *entry;
g_variant_get (parameters, "(&s&sv)", &namespace, &name, &value);
entry = find_translation_entry_by_schema (namespace, name);
if (entry != NULL)
{
char *a = g_variant_print (value, FALSE);
g_debug ("Using changed portal setting %s %s: %s", namespace, name, a);
g_free (a);
apply_portal_setting (entry, value, display);
gdk_display_setting_changed (display, entry->setting);
}
else
g_debug ("Ignoring portal setting %s %s", namespace, name);
g_variant_unref (value);
}
}
#define PORTAL_BUS_NAME "org.freedesktop.portal.Desktop"
#define PORTAL_OBJECT_PATH "/org/freedesktop/portal/desktop"
#define PORTAL_SETTINGS_INTERFACE "org.freedesktop.portal.Settings"
static void
init_settings (GdkDisplay *display)
{
@@ -1785,86 +1630,6 @@ init_settings (GdkDisplay *display)
GSettings *settings;
gint i;
if (gdk_should_use_portal ())
{
GVariant *ret;
GError *error = NULL;
const char *schema;
GVariant *val;
GVariantIter *iter;
const char *patterns[] = { "org.gnome.*", NULL };
display_wayland->settings_portal = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
PORTAL_BUS_NAME,
PORTAL_OBJECT_PATH,
PORTAL_SETTINGS_INTERFACE,
NULL,
&error);
if (error)
{
g_warning ("Settings portal not found: %s", error->message);
g_error_free (error);
goto fallback;
}
ret = g_dbus_proxy_call_sync (display_wayland->settings_portal,
"ReadAll",
g_variant_new ("(^as)", patterns),
G_DBUS_CALL_FLAGS_NONE,
G_MAXINT,
NULL,
&error);
if (error)
{
g_warning ("Failed to read portal settings: %s", error->message);
g_error_free (error);
g_clear_object (&display_wayland->settings_portal);
goto fallback;
}
g_variant_get (ret, "(a{sa{sv}})", &iter);
while (g_variant_iter_loop (iter, "{s@a{sv}}", &schema, &val))
{
GVariantIter *iter2 = g_variant_iter_new (val);
const char *key;
GVariant *v;
while (g_variant_iter_loop (iter2, "{sv}", &key, &v))
{
TranslationEntry *entry = find_translation_entry_by_schema (schema, key);
if (entry)
{
char *a = g_variant_print (v, FALSE);
g_debug ("Using portal setting for %s %s: %s\n", schema, key, a);
g_free (a);
apply_portal_setting (entry, v, display);
}
else
{
g_debug ("Ignoring portal setting for %s %s", schema, key);
}
}
g_variant_iter_free (iter2);
}
g_variant_iter_free (iter);
g_variant_unref (ret);
g_signal_connect (display_wayland->settings_portal, "g-signal",
G_CALLBACK (settings_portal_changed), display_wayland);
return;
fallback:
g_debug ("Failed to use Settings portal; falling back to gsettings");
}
g_intern_static_string ("antialiasing");
g_intern_static_string ("hinting");
g_intern_static_string ("rgba-order");
@@ -1936,43 +1701,6 @@ set_value_from_entry (GdkDisplay *display,
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
GSettings *settings;
if (display_wayland->settings_portal)
{
switch (entry->type)
{
case G_TYPE_STRING:
g_value_set_string (value, entry->fallback.s);
break;
case G_TYPE_INT:
g_value_set_int (value, entry->fallback.i);
break;
case G_TYPE_BOOLEAN:
g_value_set_boolean (value, entry->fallback.b);
break;
case G_TYPE_NONE:
if (g_str_equal (entry->setting, "gtk-fontconfig-timestamp"))
g_value_set_uint (value, (guint)entry->fallback.i);
else if (g_str_equal (entry->setting, "gtk-xft-antialias"))
g_value_set_int (value, display_wayland->xft_settings.antialias);
else if (g_str_equal (entry->setting, "gtk-xft-hinting"))
g_value_set_int (value, display_wayland->xft_settings.hinting);
else if (g_str_equal (entry->setting, "gtk-xft-hintstyle"))
g_value_set_static_string (value, display_wayland->xft_settings.hintstyle);
else if (g_str_equal (entry->setting, "gtk-xft-rgba"))
g_value_set_static_string (value, display_wayland->xft_settings.rgba);
else if (g_str_equal (entry->setting, "gtk-xft-dpi"))
g_value_set_int (value, display_wayland->xft_settings.dpi);
else
g_assert_not_reached ();
break;
default:
g_assert_not_reached ();
break;
}
return;
}
settings = (GSettings *)g_hash_table_lookup (display_wayland->settings, entry->schema);
switch (entry->type)
{
@@ -2000,9 +1728,7 @@ set_value_from_entry (GdkDisplay *display,
: entry->fallback.b);
break;
case G_TYPE_NONE:
if (g_str_equal (entry->setting, "gtk-fontconfig-timestamp"))
g_value_set_uint (value, (guint)entry->fallback.i);
else if (g_str_equal (entry->setting, "gtk-xft-antialias"))
if (g_str_equal (entry->setting, "gtk-xft-antialias"))
g_value_set_int (value, display_wayland->xft_settings.antialias);
else if (g_str_equal (entry->setting, "gtk-xft-hinting"))
g_value_set_int (value, display_wayland->xft_settings.hinting);
@@ -2027,14 +1753,18 @@ set_decoration_layout_from_entry (GdkDisplay *display,
{
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
GSettings *settings = NULL;
const char *session;
if (display_wayland->settings_portal)
{
g_value_set_string (value, entry->fallback.s);
return;
}
/* Hack: until we get session-dependent defaults in GSettings,
* swap out the usual schema for the "classic" one when
* running in classic mode
*/
session = g_getenv ("XDG_CURRENT_DESKTOP");
if (session && strstr (session, "GNOME-Classic"))
settings = (GSettings *)g_hash_table_lookup (display_wayland->settings, CLASSIC_WM_SETTINGS_SCHEMA);
settings = (GSettings *)g_hash_table_lookup (display_wayland->settings, entry->schema);
if (settings == NULL)
settings = (GSettings *)g_hash_table_lookup (display_wayland->settings, WM_SETTINGS_SCHEMA);
if (settings)
{
@@ -2070,8 +1800,7 @@ gdk_wayland_display_get_setting (GdkDisplay *display,
{
TranslationEntry *entry;
if (GDK_WAYLAND_DISPLAY (display)->settings != NULL &&
g_hash_table_size (GDK_WAYLAND_DISPLAY (display)->settings) == 0)
if (g_hash_table_size (GDK_WAYLAND_DISPLAY (display)->settings) == 0)
return FALSE;
entry = find_translation_entry_by_setting (name);
-1
View File
@@ -77,7 +77,6 @@ struct _GdkWaylandDisplay
GHashTable *settings;
GsdXftSettings xft_settings;
GDBusProxy *settings_portal;
guint32 shell_capabilities;
+14 -23
View File
@@ -170,7 +170,7 @@ gdk_wayland_gl_context_get_damage (GdkGLContext *context)
{
GdkGLContext *shared;
GdkWaylandGLContext *shared_wayland;
shared = gdk_gl_context_get_shared_context (context);
if (shared == NULL)
shared = context;
@@ -182,29 +182,20 @@ gdk_wayland_gl_context_get_damage (GdkGLContext *context)
eglQuerySurface (display_wayland->egl_display, egl_surface,
EGL_BUFFER_AGE_EXT, &buffer_age);
switch (buffer_age)
if (buffer_age == 2)
{
case 1:
return cairo_region_create ();
break;
case 2:
if (context->old_updated_area[0])
return cairo_region_copy (context->old_updated_area[0]);
break;
case 3:
if (context->old_updated_area[0] &&
context->old_updated_area[1])
{
cairo_region_t *damage = cairo_region_copy (context->old_updated_area[0]);
cairo_region_union (damage, context->old_updated_area[1]);
return damage;
}
break;
default:
;
if (context->old_updated_area[0])
return cairo_region_copy (context->old_updated_area[0]);
}
else if (buffer_age == 3)
{
if (context->old_updated_area[0] &&
context->old_updated_area[1])
{
cairo_region_t *damage = cairo_region_copy (context->old_updated_area[0]);
cairo_region_union (damage, context->old_updated_area[1]);
return damage;
}
}
}
+226 -10
View File
@@ -117,6 +117,7 @@ struct _GdkSurfaceImplWayland
struct zxdg_popup_v6 *zxdg_popup_v6;
struct gtk_surface1 *gtk_surface;
struct wl_subsurface *wl_subsurface;
struct wl_egl_window *egl_window;
struct wl_egl_window *dummy_egl_window;
struct zxdg_exported_v1 *xdg_exported;
@@ -217,6 +218,8 @@ static void gdk_wayland_surface_maybe_configure (GdkSurface *surface,
static void maybe_set_gtk_surface_dbus_properties (GdkSurface *surface);
static void maybe_set_gtk_surface_modal (GdkSurface *surface);
static void gdk_surface_request_transient_parent_commit (GdkSurface *surface);
static void gdk_wayland_surface_sync_margin (GdkSurface *surface);
static void gdk_wayland_surface_sync_input_region (GdkSurface *surface);
static void gdk_wayland_surface_sync_opaque_region (GdkSurface *surface);
@@ -1027,6 +1030,31 @@ gdk_wayland_surface_sync_input_region (GdkSurface *surface)
impl->input_region_dirty = FALSE;
}
static void
gdk_wayland_set_input_region_if_empty (GdkSurface *surface)
{
GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (surface->impl);
GdkWaylandDisplay *display;
struct wl_region *empty;
if (!impl->input_region_dirty)
return;
if (impl->input_region == NULL)
return;
if (!cairo_region_is_empty (impl->input_region))
return;
display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
empty = wl_compositor_create_region (display->compositor);
wl_surface_set_input_region (impl->display_server.wl_surface, empty);
wl_region_destroy (empty);
impl->input_region_dirty = FALSE;
}
static void
surface_enter (void *data,
struct wl_surface *wl_surface,
@@ -1065,6 +1093,61 @@ static const struct wl_surface_listener surface_listener = {
surface_leave
};
static void
on_parent_surface_committed (GdkSurfaceImplWayland *parent_impl,
GdkSurface *surface)
{
GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (surface->impl);
g_signal_handler_disconnect (parent_impl,
impl->parent_surface_committed_handler);
impl->parent_surface_committed_handler = 0;
wl_subsurface_set_desync (impl->display_server.wl_subsurface);
/* Special case if the input region is empty, it won't change on resize */
gdk_wayland_set_input_region_if_empty (surface);
}
static void
gdk_wayland_surface_create_subsurface (GdkSurface *surface)
{
GdkSurfaceImplWayland *impl, *parent_impl = NULL;
GdkWaylandDisplay *display_wayland;
impl = GDK_SURFACE_IMPL_WAYLAND (surface->impl);
if (!impl->display_server.wl_surface)
return; /* Bail out, surface and subsurface will be created later when shown */
if (impl->display_server.wl_subsurface)
return;
if (impl->transient_for)
parent_impl = GDK_SURFACE_IMPL_WAYLAND (impl->transient_for->impl);
if (parent_impl && parent_impl->display_server.wl_surface)
{
display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
impl->display_server.wl_subsurface =
wl_subcompositor_get_subsurface (display_wayland->subcompositor,
impl->display_server.wl_surface, parent_impl->display_server.wl_surface);
wl_subsurface_set_position (impl->display_server.wl_subsurface,
surface->x + surface->abs_x,
surface->y + surface->abs_y);
/* In order to synchronize the initial position with the initial frame
* content, wait with making the subsurface desynchronized until after
* the parent was committed.
*/
impl->parent_surface_committed_handler =
g_signal_connect_object (parent_impl, "committed",
G_CALLBACK (on_parent_surface_committed),
surface, 0);
gdk_surface_request_transient_parent_commit (surface);
}
}
static void
gdk_wayland_surface_create_surface (GdkSurface *surface)
{
@@ -1432,9 +1515,7 @@ gdk_wayland_surface_create_xdg_toplevel (GdkSurface *surface)
impl->initial_fullscreen_output = NULL;
app_id = impl->application.application_id;
if (app_id == NULL)
app_id = g_get_prgname ();
app_id = g_get_prgname ();
if (app_id == NULL)
app_id = "GTK+ Application";
@@ -1486,8 +1567,6 @@ gdk_wayland_surface_handle_configure_popup (GdkSurface *surface,
&flipped_x,
&flipped_y);
impl->position_method = POSITION_METHOD_MOVE_TO_RECT;
g_signal_emit_by_name (surface,
"moved-to-rect",
&flipped_rect,
@@ -1710,15 +1789,23 @@ get_real_parent_and_translate (GdkSurface *surface,
while (parent)
{
GdkSurfaceImplWayland *parent_impl =
GDK_SURFACE_IMPL_WAYLAND (parent->impl);
GdkSurface *effective_parent = gdk_surface_get_parent (parent);
if (gdk_surface_has_native (parent) && !effective_parent)
if ((gdk_surface_has_native (parent) &&
!parent_impl->display_server.wl_subsurface) ||
!effective_parent)
break;
*x += parent->x;
*y += parent->y;
parent = effective_parent;
if (gdk_surface_has_native (parent) &&
parent_impl->display_server.wl_subsurface)
parent = parent->transient_for;
else
parent = effective_parent;
}
return parent;
@@ -2378,9 +2465,38 @@ should_map_as_popup (GdkSurface *surface)
break;
}
if (impl->position_method == POSITION_METHOD_MOVE_TO_RECT)
return FALSE;
}
static gboolean
should_map_as_subsurface (GdkSurface *surface)
{
GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (surface->impl);
if (GDK_SURFACE_TYPE (surface) == GDK_SURFACE_SUBSURFACE)
return TRUE;
if (GDK_SURFACE_TYPE (surface) != GDK_SURFACE_TEMP)
return FALSE;
/* if we want a popup, we do not want a subsurface */
if (should_map_as_popup (surface))
return FALSE;
if (impl->transient_for)
{
GdkSurfaceImplWayland *impl_parent;
impl_parent = GDK_SURFACE_IMPL_WAYLAND (impl->transient_for->impl);
/* subsurface require that the parent is mapped */
if (impl_parent->mapped)
return TRUE;
else
g_warning ("Couldn't map surface %p as subsurface because its parent is not mapped.",
surface);
}
return FALSE;
}
@@ -2416,7 +2532,15 @@ gdk_wayland_surface_map (GdkSurface *surface)
if (impl->mapped || impl->use_custom_surface)
return;
if (should_map_as_popup (surface))
if (should_map_as_subsurface (surface))
{
if (impl->transient_for)
gdk_wayland_surface_create_subsurface (surface);
else
g_warning ("Couldn't map surface %p as susburface yet because it doesn't have a parent",
surface);
}
else if (should_map_as_popup (surface))
{
gboolean create_fallback = FALSE;
struct wl_seat *grab_input_seat;
@@ -2517,6 +2641,26 @@ gdk_wayland_surface_show (GdkSurface *surface,
gdk_wayland_surface_map (surface);
}
static void
unmap_subsurface (GdkSurface *surface)
{
GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (surface->impl);
GdkSurfaceImplWayland *parent_impl;
g_return_if_fail (impl->display_server.wl_subsurface);
g_return_if_fail (impl->transient_for);
parent_impl = GDK_SURFACE_IMPL_WAYLAND (impl->transient_for->impl);
wl_subsurface_destroy (impl->display_server.wl_subsurface);
if (impl->parent_surface_committed_handler)
{
g_signal_handler_disconnect (parent_impl,
impl->parent_surface_committed_handler);
impl->parent_surface_committed_handler = 0;
}
impl->display_server.wl_subsurface = NULL;
}
static void
unmap_popups_for_surface (GdkSurface *surface)
{
@@ -2617,6 +2761,9 @@ gdk_wayland_surface_hide_surface (GdkSurface *surface)
impl->initial_configure_received = FALSE;
}
if (impl->display_server.wl_subsurface)
unmap_subsurface (surface);
if (impl->awaiting_frame)
{
GdkFrameClock *frame_clock;
@@ -2690,6 +2837,32 @@ gdk_surface_wayland_restack_toplevel (GdkSurface *surface,
{
}
static void
gdk_surface_request_transient_parent_commit (GdkSurface *surface)
{
GdkSurfaceImplWayland *surface_impl, *impl;
GdkFrameClock *frame_clock;
surface_impl = GDK_SURFACE_IMPL_WAYLAND (surface->impl);
if (!surface_impl->transient_for)
return;
impl = GDK_SURFACE_IMPL_WAYLAND (surface_impl->transient_for->impl);
if (!impl->display_server.wl_surface || impl->pending_commit)
return;
frame_clock = gdk_surface_get_frame_clock (surface_impl->transient_for);
if (!frame_clock)
return;
impl->pending_commit = TRUE;
gdk_frame_clock_request_phase (frame_clock,
GDK_FRAME_CLOCK_PHASE_AFTER_PAINT);
}
static void
gdk_surface_wayland_move_resize (GdkSurface *surface,
gboolean with_move,
@@ -2708,6 +2881,14 @@ gdk_surface_wayland_move_resize (GdkSurface *surface,
surface->x = x;
surface->y = y;
impl->position_method = POSITION_METHOD_MOVE_RESIZE;
if (impl->display_server.wl_subsurface)
{
wl_subsurface_set_position (impl->display_server.wl_subsurface,
surface->x + surface->abs_x,
surface->y + surface->abs_y);
gdk_surface_request_transient_parent_commit (surface);
}
}
}
@@ -3233,6 +3414,9 @@ gdk_wayland_surface_set_transient_for (GdkSurface *surface,
unset_transient_for_exported (surface);
if (impl->display_server.wl_subsurface)
unmap_subsurface (surface);
previous_parent = impl->transient_for;
impl->transient_for = parent;
@@ -3245,6 +3429,9 @@ gdk_wayland_surface_set_transient_for (GdkSurface *surface,
g_list_remove (display_wayland->orphan_dialogs, surface);
}
gdk_wayland_surface_sync_parent (surface, NULL);
if (should_map_as_subsurface (surface) &&
parent && gdk_surface_is_visible (surface))
gdk_wayland_surface_create_subsurface (surface);
}
static void
@@ -3911,6 +4098,34 @@ _gdk_wayland_surface_set_grab_seat (GdkSurface *surface,
impl->grab_input_seat = seat;
}
/**
* gdk_wayland_surface_new_subsurface: (constructor)
* @display: the display to create the surface on
* @position: position relative to the transient surface
*
* Creates a new subsurface surface.
*
* Returns: (transfer full): the new #GdkSurface
**/
GdkSurface *
gdk_wayland_surface_new_subsurface (GdkDisplay *display,
const GdkRectangle *position)
{
GdkSurfaceAttr attr;
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
g_return_val_if_fail (position != NULL, NULL);
attr.wclass = GDK_INPUT_OUTPUT;
attr.x = position->x;
attr.y = position->y;
attr.width = position->width;
attr.height = position->height;
attr.surface_type = GDK_SURFACE_SUBSURFACE;
return gdk_surface_new (display, NULL, &attr);
}
/**
* gdk_wayland_surface_get_wl_surface:
* @surface: (type GdkWaylandSurface): a #GdkSurface
@@ -4318,7 +4533,8 @@ gdk_wayland_surface_set_transient_for_exported (GdkSurface *surface,
g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), FALSE);
g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), FALSE);
g_return_val_if_fail (!should_map_as_popup (surface), FALSE);
g_return_val_if_fail (!should_map_as_subsurface (surface) &&
!should_map_as_popup (surface), FALSE);
impl = GDK_SURFACE_IMPL_WAYLAND (surface->impl);
display_wayland = GDK_WAYLAND_DISPLAY (display);
+44 -8
View File
@@ -1655,7 +1655,7 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop)
g_hash_table_replace (win32_clipdrop->compatibility_w32formats, (gpointer) fmt.contentformat, comp);
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 2);
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 3);
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_PNG);
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_IMAGE_PNG);
@@ -1665,10 +1665,14 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop)
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_PNG);
g_array_append_val (comp, fmt);
fmt.w32format = CF_DIB;
fmt.transmute = TRUE;
g_array_append_val (comp, fmt);
g_hash_table_replace (win32_clipdrop->compatibility_w32formats, (gpointer) fmt.contentformat, comp);
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 2);
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 4);
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_JPEG);
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_IMAGE_JPEG);
@@ -1678,10 +1682,17 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop)
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_JFIF);
g_array_append_val (comp, fmt);
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_PNG);
fmt.transmute = TRUE;
g_array_append_val (comp, fmt);
fmt.w32format = CF_DIB;
g_array_append_val (comp, fmt);
g_hash_table_replace (win32_clipdrop->compatibility_w32formats, (gpointer) fmt.contentformat, comp);
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 2);
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 4);
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_GIF);
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_IMAGE_GIF);
@@ -1691,6 +1702,13 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop)
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_GIF);
g_array_append_val (comp, fmt);
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_PNG);
fmt.transmute = TRUE;
g_array_append_val (comp, fmt);
fmt.w32format = CF_DIB;
g_array_append_val (comp, fmt);
g_hash_table_replace (win32_clipdrop->compatibility_w32formats, (gpointer) fmt.contentformat, comp);
@@ -1753,7 +1771,7 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop)
g_hash_table_replace (win32_clipdrop->compatibility_contentformats, GINT_TO_POINTER (CF_UNICODETEXT), comp);
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 2);
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 3);
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_PNG);
fmt.transmute = FALSE;
@@ -1763,10 +1781,14 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop)
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_PNG);
g_array_append_val (comp, fmt);
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_BMP);
fmt.transmute = TRUE;
g_array_append_val (comp, fmt);
g_hash_table_replace (win32_clipdrop->compatibility_contentformats, GINT_TO_POINTER (_gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_PNG)), comp);
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 2);
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 4);
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_JFIF);
fmt.transmute = FALSE;
@@ -1776,10 +1798,17 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop)
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_JPEG);
g_array_append_val (comp, fmt);
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_PNG);
fmt.transmute = TRUE;
g_array_append_val (comp, fmt);
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_BMP);
g_array_append_val (comp, fmt);
g_hash_table_replace (win32_clipdrop->compatibility_contentformats, GINT_TO_POINTER (_gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_JFIF)), comp);
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 2);
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 4);
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_GIF);
fmt.transmute = FALSE;
@@ -1789,10 +1818,17 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop)
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_GIF);
g_array_append_val (comp, fmt);
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_PNG);
fmt.transmute = TRUE;
g_array_append_val (comp, fmt);
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_BMP);
g_array_append_val (comp, fmt);
g_hash_table_replace (win32_clipdrop->compatibility_contentformats, GINT_TO_POINTER (_gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_GIF)), comp);
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 2);
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 3);
fmt.w32format = CF_DIB;
fmt.transmute = FALSE;
@@ -1806,7 +1842,7 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop)
g_hash_table_replace (win32_clipdrop->compatibility_contentformats, GINT_TO_POINTER (CF_DIB), comp);
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 2);
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 3);
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_CFSTR_SHELLIDLIST);
fmt.transmute = FALSE;
+90 -32
View File
@@ -738,6 +738,8 @@ build_wm_ime_composition_event (GdkEvent *event,
build_key_event_state (event, key_state);
event->key.hardware_keycode = 0; /* FIXME: What should it be? */
event->key.string = NULL;
event->key.length = 0;
event->key.keyval = gdk_unicode_to_keyval (wc);
}
@@ -766,7 +768,7 @@ print_event_state (guint state)
void
_gdk_win32_print_event (const GdkEvent *event)
{
gchar *kvname;
gchar *escaped, *kvname;
g_print ("%s%*s===> ", (debug_indent > 0 ? "\n" : ""), debug_indent, "");
switch (event->any.type)
@@ -817,10 +819,17 @@ _gdk_win32_print_event (const GdkEvent *event)
break;
case GDK_KEY_PRESS:
case GDK_KEY_RELEASE:
if (event->key.length == 0)
escaped = g_strdup ("");
else
escaped = g_strescape (event->key.string, NULL);
kvname = gdk_keyval_name (event->key.keyval);
g_print ("%#.02x group:%d %s",
g_print ("%#.02x group:%d %s %d:\"%s\" ",
event->key.hardware_keycode, event->key.group,
(kvname ? kvname : "??"));
(kvname ? kvname : "??"),
event->key.length,
escaped);
g_free (escaped);
print_event_state (event->key.state);
break;
case GDK_ENTER_NOTIFY:
@@ -931,6 +940,73 @@ _gdk_win32_append_event (GdkEvent *event)
#endif
}
static void
fill_key_event_string (GdkEvent *event)
{
gunichar c;
gchar buf[256];
/* Fill in event->string crudely, since various programs
* depend on it.
*/
c = 0;
if (event->key.keyval != GDK_KEY_VoidSymbol)
c = gdk_keyval_to_unicode (event->key.keyval);
if (c)
{
gsize bytes_written;
gint len;
/* Apply the control key - Taken from Xlib
*/
if (event->key.state & GDK_CONTROL_MASK)
{
if ((c >= '@' && c < '\177') || c == ' ')
c &= 0x1F;
else if (c == '2')
{
event->key.string = g_memdup ("\0\0", 2);
event->key.length = 1;
return;
}
else if (c >= '3' && c <= '7')
c -= ('3' - '\033');
else if (c == '8')
c = '\177';
else if (c == '/')
c = '_' & 0x1F;
}
len = g_unichar_to_utf8 (c, buf);
buf[len] = '\0';
event->key.string = g_locale_from_utf8 (buf, len,
NULL, &bytes_written,
NULL);
if (event->key.string)
event->key.length = bytes_written;
}
else if (event->key.keyval == GDK_KEY_Escape)
{
event->key.length = 1;
event->key.string = g_strdup ("\033");
}
else if (event->key.keyval == GDK_KEY_Return ||
event->key.keyval == GDK_KEY_KP_Enter)
{
event->key.length = 1;
event->key.string = g_strdup ("\r");
}
if (!event->key.string)
{
event->key.length = 0;
event->key.string = g_strdup ("");
}
}
static GdkWin32MessageFilterReturn
apply_message_filters (GdkDisplay *display,
MSG *msg,
@@ -1701,7 +1777,7 @@ ensure_stacking_on_unminimize (MSG *msg)
g_print (" restacking %p above %p",
msg->hwnd, lowest_transient));
SetWindowPos (msg->hwnd, lowest_transient, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER);
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
}
}
@@ -1782,7 +1858,7 @@ ensure_stacking_on_activate_app (MSG *msg,
impl->transient_owner != NULL)
{
SetWindowPos (msg->hwnd, HWND_TOP, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER);
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
return;
}
@@ -1824,7 +1900,7 @@ ensure_stacking_on_activate_app (MSG *msg,
g_print (" restacking %p above %p",
msg->hwnd, rover));
SetWindowPos (msg->hwnd, rover, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER);
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
break;
}
}
@@ -2124,7 +2200,6 @@ gdk_event_translate (MSG *msg,
(gulong) msg->wParam,
(gpointer) msg->lParam, _gdk_input_locale_is_ime ? " (IME)" : "",
_gdk_input_codepage));
gdk_display_setting_changed (display, "gtk-im-module");
break;
case WM_SYSKEYUP:
@@ -2213,6 +2288,8 @@ gdk_event_translate (MSG *msg,
event->any.surface = window;
event->key.time = _gdk_win32_get_next_tick (msg->time);
event->key.keyval = GDK_KEY_VoidSymbol;
event->key.string = NULL;
event->key.length = 0;
event->key.hardware_keycode = msg->wParam;
/* save original scancode */
gdk_event_set_scancode (event, msg->lParam >> 16);
@@ -2283,6 +2360,8 @@ gdk_event_translate (MSG *msg,
else
impl->leading_surrogate_keyup = 0;
fill_key_event_string (event);
/* Only one release key event is fired when both shift keys are pressed together
and then released. In order to send the missing event, press events for shift
keys are recorded and sent together when the release event occurs.
@@ -2713,20 +2792,13 @@ gdk_event_translate (MSG *msg,
event = gdk_event_new (GDK_SCROLL);
event->any.surface = window;
event->scroll.direction = GDK_SCROLL_SMOOTH;
if (msg->message == WM_MOUSEWHEEL)
{
event->scroll.delta_y = (gdouble) GET_WHEEL_DELTA_WPARAM (msg->wParam) / (gdouble) WHEEL_DELTA;
}
event->scroll.direction = (((short) HIWORD (msg->wParam)) > 0) ?
GDK_SCROLL_UP : GDK_SCROLL_DOWN;
else if (msg->message == WM_MOUSEHWHEEL)
{
event->scroll.delta_x = (gdouble) GET_WHEEL_DELTA_WPARAM (msg->wParam) / (gdouble) WHEEL_DELTA;
}
/* Positive delta scrolls up, not down,
see API documentation for WM_MOUSEWHEEL message.
*/
event->scroll.delta_y *= -1.0;
event->scroll.direction = (((short) HIWORD (msg->wParam)) > 0) ?
GDK_SCROLL_RIGHT : GDK_SCROLL_LEFT;
event->scroll.time = _gdk_win32_get_next_tick (msg->time);
event->scroll.x = (gint16) point.x / impl->surface_scale;
event->scroll.y = (gint16) point.y / impl->surface_scale;
@@ -2735,20 +2807,6 @@ gdk_event_translate (MSG *msg,
event->scroll.state = build_pointer_event_state (msg);
gdk_event_set_device (event, device_manager_win32->core_pointer);
gdk_event_set_source_device (event, device_manager_win32->system_pointer);
gdk_event_set_pointer_emulated (event, FALSE);
_gdk_win32_append_event (gdk_event_copy (event));
/* Append the discrete version too */
if (msg->message == WM_MOUSEWHEEL)
event->scroll.direction = (((short) HIWORD (msg->wParam)) > 0) ?
GDK_SCROLL_UP : GDK_SCROLL_DOWN;
else if (msg->message == WM_MOUSEHWHEEL)
event->scroll.direction = (((short) HIWORD (msg->wParam)) > 0) ?
GDK_SCROLL_RIGHT : GDK_SCROLL_LEFT;
event->scroll.delta_x = 0;
event->scroll.delta_y = 0;
gdk_event_set_pointer_emulated (event, TRUE);
_gdk_win32_append_event (event);
+1 -1
View File
@@ -201,7 +201,7 @@ gdk_win32_hdata_output_stream_close (GOutputStream *output_stream,
if (priv->handle_is_buffer)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
_("Cant transmute a single handle"));
_("Can't transmute a single handle"));
return FALSE;
}
+48 -89
View File
@@ -27,39 +27,12 @@
#include <string.h>
#include <stdlib.h>
#include <glib/gprintf.h>
#include <pango/pangowin32.h>
#include "gdkproperty.h"
#include "gdkdisplayprivate.h"
#include "gdkprivate-win32.h"
#include "gdkwin32.h"
static gchar*
_get_system_font_name (HDC hdc)
{
NONCLIENTMETRICSW ncm;
PangoFontDescription *font_desc;
gchar *result, *font_desc_string;
int logpixelsy;
gint font_size;
ncm.cbSize = sizeof(NONCLIENTMETRICSW);
if (!SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0))
return NULL;
logpixelsy = GetDeviceCaps (hdc, LOGPIXELSY);
font_desc = pango_win32_font_description_from_logfontw (&ncm.lfMessageFont);
font_desc_string = pango_font_description_to_string (font_desc);
pango_font_description_free (font_desc);
/* https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/ns-wingdi-taglogfonta */
font_size = -MulDiv (ncm.lfMessageFont.lfHeight, 72, logpixelsy);
result = g_strdup_printf ("%s %d", font_desc_string, font_size);
g_free (font_desc_string);
return result;
}
/*
For reference, from gdk/x11/gdksettings.c:
@@ -151,75 +124,61 @@ _gdk_win32_get_setting (const gchar *name,
g_value_set_boolean (value, TRUE);
return TRUE;
}
else if (strcmp ("gtk-xft-hinting", name) == 0)
{
GDK_NOTE(MISC, g_print ("gdk_screen_get_setting(\"%s\") : 1\n", name));
g_value_set_int (value, 1);
return TRUE;
}
else if (strcmp ("gtk-xft-antialias", name) == 0)
{
GDK_NOTE(MISC, g_print ("gdk_screen_get_setting(\"%s\") : 1\n", name));
g_value_set_int (value, 1);
return TRUE;
}
else if (strcmp ("gtk-xft-hintstyle", name) == 0)
{
g_value_set_static_string (value, "hintfull");
GDK_NOTE(MISC, g_print ("gdk_screen_get_setting(\"%s\") : %s\n", name, g_value_get_string (value)));
return TRUE;
}
else if (strcmp ("gtk-xft-rgba", name) == 0)
{
unsigned int orientation = 0;
if (SystemParametersInfoW (SPI_GETFONTSMOOTHINGORIENTATION, 0, &orientation, 0))
{
if (orientation == FE_FONTSMOOTHINGORIENTATIONRGB)
g_value_set_static_string (value, "rgb");
else if (orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
g_value_set_static_string (value, "bgr");
else
g_value_set_static_string (value, "none");
}
else
g_value_set_static_string (value, "none");
GDK_NOTE(MISC, g_print ("gdk_screen_get_setting(\"%s\") : %s\n", name, g_value_get_string (value)));
return TRUE;
}
else if (strcmp ("gtk-font-name", name) == 0)
{
gchar *font_name = _get_system_font_name (_gdk_display_hdc);
NONCLIENTMETRICS ncm;
CPINFOEX cpinfoex_default, cpinfoex_curr_thread;
OSVERSIONINFO info;
BOOL result_default, result_curr_thread;
if (font_name)
info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
/* TODO: Fallback to using Pango on Windows 8 and later,
* as this method of handling gtk-font-name does not work
* well there, where garbled text will be displayed for texts
* that are not supported by the default menu font. Look for
* whether there is a better solution for this on Windows 8 and
* later
*/
if (!GetVersionEx (&info) ||
info.dwMajorVersion > 6 ||
(info.dwMajorVersion == 6 && info.dwMinorVersion >= 2))
return FALSE;
/* check whether the system default ANSI codepage matches the
* ANSI code page of the running thread. If so, continue, otherwise
* fall back to using Pango to handle gtk-font-name
*/
result_default = GetCPInfoEx (CP_ACP, 0, &cpinfoex_default);
result_curr_thread = GetCPInfoEx (CP_THREAD_ACP, 0, &cpinfoex_curr_thread);
if (!result_default ||
!result_curr_thread ||
cpinfoex_default.CodePage != cpinfoex_curr_thread.CodePage)
return FALSE;
ncm.cbSize = sizeof(NONCLIENTMETRICS);
if (SystemParametersInfo (SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, FALSE))
{
/* The pango font fallback list got fixed during 1.43, before that
* using anything but "Segoe UI" would lead to a poor glyph coverage */
if (pango_version_check (1, 43, 0) != NULL &&
g_ascii_strncasecmp (font_name, "Segoe UI", strlen ("Segoe UI")) != 0)
/* Pango finally uses GetDeviceCaps to scale, we use simple
* approximation here.
*/
int nHeight = (0 > ncm.lfMenuFont.lfHeight ? - 3 * ncm.lfMenuFont.lfHeight / 4 : 10);
if (OUT_STRING_PRECIS == ncm.lfMenuFont.lfOutPrecision)
GDK_NOTE(MISC, g_print("gdk_display_get_setting(%s) : ignoring bitmap font '%s'\n",
name, ncm.lfMenuFont.lfFaceName));
else if (ncm.lfMenuFont.lfFaceName && strlen(ncm.lfMenuFont.lfFaceName) > 0 &&
/* Avoid issues like those described in bug #135098 */
g_utf8_validate (ncm.lfMenuFont.lfFaceName, -1, NULL))
{
g_free (font_name);
return FALSE;
char *s = g_strdup_printf ("%s %d", ncm.lfMenuFont.lfFaceName, nHeight);
GDK_NOTE(MISC, g_print("gdk_display_get_setting(%s) : %s\n", name, s));
g_value_set_string (value, s);
g_free(s);
return TRUE;
}
GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : %s\n", name, font_name));
g_value_take_string (value, font_name);
return TRUE;
}
else
{
g_warning ("gdk_screen_get_setting: Detecting the system font failed");
return FALSE;
}
}
else if (strcmp ("gtk-im-module", name) == 0)
{
if (_gdk_input_locale_is_ime)
g_value_set_string (value, "ime");
else
g_value_set_string (value, "");
return TRUE;
}
return FALSE;
+30 -26
View File
@@ -760,11 +760,17 @@ gdk_win32_surface_destroy (GdkSurface *window,
_gdk_remove_modal_window (window);
/* Remove all our transient children */
while (surface_impl->transient_children != NULL)
tmp = surface_impl->transient_children;
while (tmp != NULL)
{
GdkSurface *child = surface_impl->transient_children->data;
gdk_surface_set_transient_for (child, NULL);
GdkSurface *child = tmp->data;
GdkSurfaceImplWin32 *child_impl = GDK_SURFACE_IMPL_WIN32 (GDK_SURFACE (child)->impl);
child_impl->transient_owner = NULL;
tmp = tmp->next;
}
g_slist_free (surface_impl->transient_children);
surface_impl->transient_children = NULL;
/* Remove ourself from our transient owner */
if (surface_impl->transient_owner != NULL)
@@ -1118,7 +1124,7 @@ show_window_internal (GdkSurface *window,
API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
(window->state & GDK_SURFACE_STATE_ABOVE)?HWND_TOPMOST:HWND_NOTOPMOST,
0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOOWNERZORDER));
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE));
}
}
@@ -1376,7 +1382,7 @@ gdk_win32_surface_raise (GdkSurface *window)
if (GDK_SURFACE_TYPE (window) == GDK_SURFACE_TEMP)
API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_TOPMOST,
0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER));
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE));
else if (window->accept_focus)
/* Do not wrap this in an API_CALL macro as SetForegroundWindow might
* fail when for example dragging a window belonging to a different
@@ -1386,7 +1392,7 @@ gdk_win32_surface_raise (GdkSurface *window)
else
API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_TOP,
0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER));
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE));
}
}
@@ -1403,7 +1409,7 @@ gdk_win32_surface_lower (GdkSurface *window)
API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_BOTTOM,
0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER));
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE));
}
}
@@ -1666,29 +1672,27 @@ gdk_win32_surface_set_transient_for (GdkSurface *window,
return;
}
if (surface_impl->transient_owner == parent)
return;
if (GDK_IS_SURFACE (surface_impl->transient_owner))
if (parent == NULL)
{
GdkSurfaceImplWin32 *trans_impl = GDK_SURFACE_IMPL_WIN32 (surface_impl->transient_owner->impl);
item = g_slist_find (trans_impl->transient_children, window);
item->data = NULL;
trans_impl->transient_children = g_slist_delete_link (trans_impl->transient_children, item);
trans_impl->num_transients--;
if (!trans_impl->num_transients)
if (trans_impl->transient_children != NULL)
{
trans_impl->transient_children = NULL;
}
item = g_slist_find (trans_impl->transient_children, window);
item->data = NULL;
trans_impl->transient_children = g_slist_delete_link (trans_impl->transient_children, item);
trans_impl->num_transients--;
if (!trans_impl->num_transients)
{
trans_impl->transient_children = NULL;
}
}
g_object_unref (G_OBJECT (surface_impl->transient_owner));
g_object_unref (G_OBJECT (window));
surface_impl->transient_owner = NULL;
}
if (parent)
else
{
parent_impl = GDK_SURFACE_IMPL_WIN32 (parent->impl);
@@ -2313,7 +2317,7 @@ _gdk_win32_surface_update_style_bits (GdkSurface *window)
rect.right += after.right - before.right;
rect.bottom += after.bottom - before.bottom;
flags = SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOREPOSITION | SWP_NOOWNERZORDER;
flags = SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOREPOSITION;
if (will_be_topmost && !was_topmost)
{
@@ -4767,7 +4771,7 @@ gdk_win32_surface_fullscreen (GdkSurface *window)
API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_TOP,
x, y, width, height,
SWP_NOCOPYBITS | SWP_SHOWWINDOW | SWP_NOOWNERZORDER));
SWP_NOCOPYBITS | SWP_SHOWWINDOW));
}
}
@@ -4790,7 +4794,7 @@ gdk_win32_surface_unfullscreen (GdkSurface *window)
API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_NOTOPMOST,
fi->r.left, fi->r.top,
fi->r.right - fi->r.left, fi->r.bottom - fi->r.top,
SWP_NOCOPYBITS | SWP_SHOWWINDOW | SWP_NOOWNERZORDER));
SWP_NOCOPYBITS | SWP_SHOWWINDOW));
g_object_set_data (G_OBJECT (window), "fullscreen-info", NULL);
g_free (fi);
@@ -4816,7 +4820,7 @@ gdk_win32_surface_set_keep_above (GdkSurface *window,
API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
setting ? HWND_TOPMOST : HWND_NOTOPMOST,
0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOOWNERZORDER));
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE));
}
gdk_synthesize_surface_state (window,
@@ -4842,7 +4846,7 @@ gdk_win32_surface_set_keep_below (GdkSurface *window,
API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
setting ? HWND_BOTTOM : HWND_NOTOPMOST,
0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOOWNERZORDER));
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE));
}
gdk_synthesize_surface_state (window,
-1
View File
@@ -45,7 +45,6 @@ install_headers(gdk_win32_public_headers, subdir: 'gtk-4.0/gdk/win32/')
install_headers('gdkwin32.h', subdir: 'gtk-4.0/gdk/')
gdk_win32_deps = [ # FIXME
pangowin32_dep
]
libgdk_win32 = static_library('gdk-win32',
+1 -1
View File
@@ -261,7 +261,7 @@ gdk_x11_cursor_create_for_name (GdkDisplay *display,
/**
* gdk_x11_display_set_cursor_theme:
* @display: (type GdkX11Display): a #GdkDisplay
* @theme: (nullable): the name of the cursor theme to use, or %NULL to unset
* @theme: the name of the cursor theme to use, or %NULL to unset
* a previously set value
* @size: the cursor size to use, or 0 to keep the previous size
*
+70
View File
@@ -221,6 +221,8 @@ translate_key_event (GdkDisplay *display,
event->key.is_modifier = gdk_x11_keymap_key_is_modifier (keymap, event->key.hardware_keycode);
_gdk_x11_event_translate_keyboard_string (&event->key);
#ifdef G_ENABLE_DEBUG
if (GDK_DISPLAY_DEBUG_CHECK (display, EVENTS))
{
@@ -229,6 +231,10 @@ translate_key_event (GdkDisplay *display,
xevent->xkey.window,
event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)",
event->key.keyval);
if (event->key.length > 0)
g_message ("\t\tlength: %4d string: \"%s\"",
event->key.length, event->key.string);
}
#endif /* G_ENABLE_DEBUG */
return;
@@ -718,6 +724,70 @@ gdk_x11_device_manager_core_translate_event (GdkEventTranslator *translator,
return return_val;
}
void
_gdk_x11_event_translate_keyboard_string (GdkEventKey *event)
{
gunichar c = 0;
gchar buf[7];
/* Fill in event->string crudely, since various programs
* depend on it.
*/
event->string = NULL;
if (event->keyval != GDK_KEY_VoidSymbol)
c = gdk_keyval_to_unicode (event->keyval);
if (c)
{
gsize bytes_written;
gint len;
/* Apply the control key - Taken from Xlib
*/
if (event->state & GDK_CONTROL_MASK)
{
if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F;
else if (c == '2')
{
event->string = g_memdup ("\0\0", 2);
event->length = 1;
buf[0] = '\0';
return;
}
else if (c >= '3' && c <= '7') c -= ('3' - '\033');
else if (c == '8') c = '\177';
else if (c == '/') c = '_' & 0x1F;
}
len = g_unichar_to_utf8 (c, buf);
buf[len] = '\0';
event->string = g_locale_from_utf8 (buf, len,
NULL, &bytes_written,
NULL);
if (event->string)
event->length = bytes_written;
}
else if (event->keyval == GDK_KEY_Escape)
{
event->length = 1;
event->string = g_strdup ("\033");
}
else if (event->keyval == GDK_KEY_Return ||
event->keyval == GDK_KEY_KP_Enter)
{
event->length = 1;
event->string = g_strdup ("\r");
}
if (!event->string)
{
event->length = 0;
event->string = g_strdup ("");
}
}
/* We only care about focus events that indicate that _this_
* surface (not a ancestor or child) got or lost the focus
*/
+6 -86
View File
@@ -40,23 +40,6 @@
#include <string.h>
static const char *wacom_type_atoms[] = {
"STYLUS",
"CURSOR",
"ERASER",
"PAD",
"TOUCH"
};
#define N_WACOM_TYPE_ATOMS G_N_ELEMENTS (wacom_type_atoms)
enum {
WACOM_TYPE_STYLUS,
WACOM_TYPE_CURSOR,
WACOM_TYPE_ERASER,
WACOM_TYPE_PAD,
WACOM_TYPE_TOUCH,
};
struct _GdkX11DeviceManagerXI2
{
GdkX11DeviceManagerCore parent_object;
@@ -1016,66 +999,6 @@ device_get_tool_serial_and_id (GdkDevice *device,
return TRUE;
}
static GdkDeviceToolType
device_get_tool_type (GdkDevice *device)
{
GdkDisplay *display;
gulong nitems, bytes_after;
guint32 *data;
int rc, format;
Atom type;
Atom device_type;
Atom types[N_WACOM_TYPE_ATOMS];
GdkDeviceToolType tool_type = GDK_DEVICE_TOOL_TYPE_UNKNOWN;
display = gdk_device_get_display (device);
gdk_x11_display_error_trap_push (display);
rc = XIGetProperty (GDK_DISPLAY_XDISPLAY (display),
gdk_x11_device_get_id (device),
gdk_x11_get_xatom_by_name_for_display (display, "Wacom Tool Type"),
0, 1, False, XA_ATOM, &type, &format, &nitems, &bytes_after,
(guchar **) &data);
gdk_x11_display_error_trap_pop_ignored (display);
if (rc != Success)
return GDK_DEVICE_TOOL_TYPE_UNKNOWN;
if (type != XA_ATOM || format != 32 || nitems != 1)
{
XFree (data);
return GDK_DEVICE_TOOL_TYPE_UNKNOWN;
}
device_type = *data;
XFree (data);
if (device_type == 0)
return GDK_DEVICE_TOOL_TYPE_UNKNOWN;
gdk_x11_display_error_trap_push (display);
rc = XInternAtoms (GDK_DISPLAY_XDISPLAY (display),
(char **) wacom_type_atoms,
N_WACOM_TYPE_ATOMS,
False,
types);
gdk_x11_display_error_trap_pop_ignored (display);
if (rc == 0)
return GDK_DEVICE_TOOL_TYPE_UNKNOWN;
if (device_type == types[WACOM_TYPE_STYLUS])
tool_type = GDK_DEVICE_TOOL_TYPE_PEN;
else if (device_type == types[WACOM_TYPE_CURSOR])
tool_type = GDK_DEVICE_TOOL_TYPE_MOUSE;
else if (device_type == types[WACOM_TYPE_ERASER])
tool_type = GDK_DEVICE_TOOL_TYPE_ERASER;
else if (device_type == types[WACOM_TYPE_TOUCH])
tool_type = GDK_DEVICE_TOOL_TYPE_UNKNOWN;
return tool_type;
}
static void
handle_property_change (GdkX11DeviceManagerXI2 *device_manager,
XIPropertyEvent *ev)
@@ -1096,18 +1019,13 @@ handle_property_change (GdkX11DeviceManagerXI2 *device_manager,
device_get_tool_serial_and_id (device, &serial_id, &tool_id))
{
seat = gdk_device_get_seat (device);
tool = gdk_seat_get_tool (seat, serial_id, tool_id);
tool = gdk_seat_get_tool (seat, serial_id);
if (!tool && serial_id > 0)
{
GdkDeviceToolType tool_type;
tool_type = device_get_tool_type (device);
if (tool_type != GDK_DEVICE_TOOL_TYPE_UNKNOWN)
{
tool = gdk_device_tool_new (serial_id, tool_id, tool_type, 0);
gdk_seat_default_add_tool (GDK_SEAT_DEFAULT (seat), tool);
}
tool = gdk_device_tool_new (serial_id, tool_id,
GDK_DEVICE_TOOL_TYPE_UNKNOWN, 0);
gdk_seat_default_add_tool (GDK_SEAT_DEFAULT (seat), tool);
}
}
@@ -1553,6 +1471,8 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
_gdk_x11_keymap_add_virt_mods (keymap, &state);
event->key.state |= state;
_gdk_x11_event_translate_keyboard_string (&event->key);
if (ev->evtype == XI_KeyPress)
set_user_time (event);
+3 -3
View File
@@ -1600,7 +1600,7 @@ gdk_x11_display_open (const gchar *display_name)
if (!gdk_running_in_sandbox ())
{
/* if sandboxed, we're likely in a pid namespace and would only confuse the wm with this */
long pid = getpid ();
pid_t pid = getpid ();
XChangeProperty (display_x11->xdisplay,
display_x11->leader_window,
gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PID"),
@@ -2822,8 +2822,8 @@ gdk_x11_display_error_trap_pop_ignored (GdkDisplay *display)
/**
* gdk_x11_set_sm_client_id:
* @sm_client_id: (nullable): the client id assigned by the session manager
* when the connection was opened, or %NULL to remove the property.
* @sm_client_id: the client id assigned by the session manager when the
* connection was opened, or %NULL to remove the property.
*
* Sets the `SM_CLIENT_ID` property on the applications leader window so that
* the window manager can save the applications state using the X11R6 ICCCM
+16 -26
View File
@@ -201,41 +201,31 @@ gdk_x11_gl_context_get_damage (GdkGLContext *context)
{
GdkGLContext *shared;
GdkX11GLContext *shared_x11;
shared = gdk_gl_context_get_shared_context (context);
if (shared == NULL)
shared = context;
shared_x11 = GDK_X11_GL_CONTEXT (shared);
gdk_gl_context_make_current (shared);
glXQueryDrawable (dpy, shared_x11->attached_drawable,
GLX_BACK_BUFFER_AGE_EXT, &buffer_age);
glXQueryDrawable(dpy, shared_x11->attached_drawable,
GLX_BACK_BUFFER_AGE_EXT, &buffer_age);
switch (buffer_age)
if (buffer_age == 2)
{
case 1:
return cairo_region_create ();
break;
case 2:
if (context->old_updated_area[0])
return cairo_region_copy (context->old_updated_area[0]);
break;
case 3:
if (context->old_updated_area[0] &&
context->old_updated_area[1])
{
cairo_region_t *damage = cairo_region_copy (context->old_updated_area[0]);
cairo_region_union (damage, context->old_updated_area[1]);
return damage;
}
break;
default:
;
if (context->old_updated_area[0])
return cairo_region_copy (context->old_updated_area[0]);
}
else if (buffer_age == 3)
{
if (context->old_updated_area[0] &&
context->old_updated_area[1])
{
cairo_region_t *damage = cairo_region_copy (context->old_updated_area[0]);
cairo_region_union (damage, context->old_updated_area[1]);
return damage;
}
}
}
return GDK_GL_CONTEXT_CLASS (gdk_x11_gl_context_parent_class)->get_damage (context);
+2
View File
@@ -166,6 +166,8 @@ void gdk_x11_device_xi2_store_axes (GdkX11DeviceXI2 *device,
gint n_axes);
#endif
void _gdk_x11_event_translate_keyboard_string (GdkEventKey *event);
GdkAtom _gdk_x11_display_manager_atom_intern (GdkDisplayManager *manager,
const gchar *atom_name,
gboolean copy_name);
+1 -1
View File
@@ -140,7 +140,7 @@ gdk_x11_selection_input_stream_flush (GdkX11SelectionInputStream *stream)
written, priv->pending_size));
g_task_return_int (priv->pending_task, written);
g_clear_object (&priv->pending_task);
priv->pending_task = NULL;
priv->pending_data = NULL;
priv->pending_size = 0;
}
+1 -1
View File
@@ -746,7 +746,7 @@ setup_toplevel_window (GdkSurface *surface,
if (!gdk_running_in_sandbox ())
{
/* if sandboxed, we're likely in a pid namespace and would only confuse the wm with this */
long pid = getpid ();
pid_t pid = getpid ();
XChangeProperty (xdisplay, xid,
gdk_x11_get_xatom_by_name_for_display (x11_screen->display, "_NET_WM_PID"),
XA_CARDINAL, 32,
+35 -49
View File
@@ -46,7 +46,6 @@ struct _GskGLDriver
Fbo default_fbo;
GHashTable *textures;
GHashTable *pointer_textures;
const Texture *bound_source_texture;
const Fbo *bound_fbo;
@@ -120,7 +119,6 @@ gsk_gl_driver_finalize (GObject *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 ())
@@ -265,28 +263,7 @@ gsk_gl_driver_collect_textures (GskGLDriver *self)
}
}
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);
}
g_hash_table_iter_remove (&iter);
}
return old_size - g_hash_table_size (self->textures);
@@ -330,6 +307,26 @@ gsk_gl_driver_get_fbo (GskGLDriver *self,
return &t->fbo;
}
static Texture *
find_texture_by_size (GHashTable *textures,
int width,
int height)
{
GHashTableIter iter;
gpointer value_p = NULL;
g_hash_table_iter_init (&iter, textures);
while (g_hash_table_iter_next (&iter, NULL, &value_p))
{
Texture *t = value_p;
if (t->width == width && t->height == height)
return t;
}
return NULL;
}
static Texture *
create_texture (GskGLDriver *self,
float fwidth,
@@ -354,7 +351,21 @@ create_texture (GskGLDriver *self,
height = MIN (height, self->max_texture_size);
}
t = find_texture_by_size (self->textures, width, height);
if (t != NULL && !t->in_use && t->user == NULL)
{
GSK_NOTE (OPENGL, g_message ("Reusing Texture(%d) for size %dx%d",
t->texture_id, t->width, t->height));
t->in_use = TRUE;
#ifdef G_ENABLE_DEBUG
gsk_profiler_counter_inc (self->profiler, self->counters.reused_textures);
#endif
return t;
}
glGenTextures (1, &texture_id);
t = texture_new ();
t->texture_id = texture_id;
t->width = width;
@@ -536,31 +547,6 @@ gsk_gl_driver_get_texture_for_texture (GskGLDriver *self,
return t->texture_id;
}
int
gsk_gl_driver_get_texture_for_pointer (GskGLDriver *self,
gpointer pointer)
{
int id = 0;
if (G_UNLIKELY (self->pointer_textures == NULL))
self->pointer_textures = g_hash_table_new (NULL, NULL);
id = GPOINTER_TO_INT (g_hash_table_lookup (self->pointer_textures, pointer));
return id;
}
void
gsk_gl_driver_set_texture_for_pointer (GskGLDriver *self,
gpointer pointer,
int texture_id)
{
if (G_UNLIKELY (self->pointer_textures == NULL))
self->pointer_textures = g_hash_table_new (NULL, NULL);
g_hash_table_insert (self->pointer_textures, pointer, GINT_TO_POINTER (texture_id));
}
int
gsk_gl_driver_create_permanent_texture (GskGLDriver *self,
float width,
-5
View File
@@ -33,11 +33,6 @@ 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_pointer (GskGLDriver *driver,
gpointer pointer);
void gsk_gl_driver_set_texture_for_pointer (GskGLDriver *driver,
gpointer pointer,
int texture_id);
int gsk_gl_driver_create_permanent_texture (GskGLDriver *driver,
float width,
float height);
+51 -19
View File
@@ -24,6 +24,21 @@
#define ATLAS_SIZE 512
typedef struct
{
PangoFont *font;
PangoGlyph glyph;
guint scale; /* times 1024 */
} GlyphCacheKey;
typedef struct
{
GlyphCacheKey *key;
GskGLCachedGlyph *value;
cairo_surface_t *surface;
} DirtyGlyph;
static guint glyph_cache_hash (gconstpointer v);
static gboolean glyph_cache_equal (gconstpointer v1,
gconstpointer v2);
@@ -43,6 +58,8 @@ create_atlas (GskGLGlyphCache *cache)
atlas->y = 1;
atlas->x = 1;
atlas->image = NULL;
atlas->num_glyphs = 0;
atlas->dirty_glyphs = NULL;
return atlas;
}
@@ -57,7 +74,7 @@ free_atlas (gpointer v)
g_assert (atlas->image->texture_id == 0);
g_free (atlas->image);
}
g_list_free_full (atlas->dirty_glyphs, dirty_glyph_free);
g_free (atlas);
}
@@ -136,15 +153,17 @@ dirty_glyph_free (gpointer v)
if (glyph->surface)
cairo_surface_destroy (glyph->surface);
g_free (glyph);
}
static void
add_to_cache (GskGLGlyphCache *cache,
GlyphCacheKey *key,
GlyphCacheKey *key,
GskGLCachedGlyph *value)
{
GskGLGlyphAtlas *atlas;
int i;
DirtyGlyph *dirty;
int width = value->draw_width * key->scale / 1024;
int height = value->draw_height * key->scale / 1024;
@@ -186,12 +205,16 @@ add_to_cache (GskGLGlyphCache *cache,
value->atlas = atlas;
atlas->pending_glyph.key = key;
atlas->pending_glyph.value = value;
dirty = g_new0 (DirtyGlyph, 1);
dirty->key = key;
dirty->value = value;
atlas->dirty_glyphs = g_list_prepend (atlas->dirty_glyphs, dirty);
atlas->x = atlas->x + width + 1;
atlas->y = MAX (atlas->y, atlas->y0 + height + 1);
atlas->num_glyphs++;
#ifdef G_ENABLE_DEBUG
if (GSK_RENDERER_DEBUG_CHECK (cache->renderer, GLYPH_CACHE))
{
@@ -199,8 +222,9 @@ add_to_cache (GskGLGlyphCache *cache,
for (i = 0; i < cache->atlases->len; i++)
{
atlas = g_ptr_array_index (cache->atlases, i);
g_print ("\tGskGLGlyphAtlas %d (%dx%d): %.2g%% old pixels, filled to %d, %d / %d\n",
g_print ("\tGskGLGlyphAtlas %d (%dx%d): %d glyphs (%d dirty), %.2g%% old pixels, filled to %d, %d / %d\n",
i, atlas->width, atlas->height,
atlas->num_glyphs, g_list_length (atlas->dirty_glyphs),
100.0 * (double)atlas->old_pixels / (double)(atlas->width * atlas->height),
atlas->x, atlas->y0, atlas->y);
}
@@ -260,20 +284,28 @@ render_glyph (const GskGLGlyphAtlas *atlas,
}
static void
upload_dirty_glyph (GskGLGlyphCache *self,
GskGLGlyphAtlas *atlas)
upload_dirty_glyphs (GskGLGlyphCache *self,
GskGLGlyphAtlas *atlas)
{
GskImageRegion region;
GList *l;
guint num_regions;
GskImageRegion *regions;
int i;
g_assert (atlas->pending_glyph.key != NULL);
num_regions = g_list_length (atlas->dirty_glyphs);
regions = alloca (sizeof (GskImageRegion) * num_regions);
render_glyph (atlas, &atlas->pending_glyph, &region);
for (l = atlas->dirty_glyphs, i = 0; l; l = l->next, i++)
render_glyph (atlas, (DirtyGlyph *)l->data, &regions[i]);
gsk_gl_image_upload_regions (atlas->image, self->gl_driver, 1, &region);
GSK_RENDERER_NOTE (self->renderer, GLYPH_CACHE,
g_message ("uploading %d glyphs to cache", num_regions));
dirty_glyph_free (&atlas->pending_glyph);
atlas->pending_glyph.key = NULL;
atlas->pending_glyph.value = NULL;
gsk_gl_image_upload_regions (atlas->image, self->gl_driver, num_regions, regions);
g_list_free_full (atlas->dirty_glyphs, dirty_glyph_free);
atlas->dirty_glyphs = NULL;
}
const GskGLCachedGlyph *
@@ -322,13 +354,12 @@ gsk_gl_glyph_cache_lookup (GskGLGlyphCache *cache,
value->draw_height = ink_rect.height;
value->timestamp = cache->timestamp;
value->atlas = NULL; /* For now */
value->scale = (guint)(scale * 1024);
key->font = g_object_ref (font);
key->glyph = glyph;
key->scale = (guint)(scale * 1024);
if (ink_rect.width > 0 && ink_rect.height > 0 && key->scale > 0)
if (ink_rect.width > 0 && ink_rect.height > 0)
add_to_cache (cache, key, value);
g_hash_table_insert (cache->hash_table, key, value);
@@ -338,21 +369,22 @@ gsk_gl_glyph_cache_lookup (GskGLGlyphCache *cache,
}
GskGLImage *
gsk_gl_glyph_cache_get_glyph_image (GskGLGlyphCache *self,
gsk_gl_glyph_cache_get_glyph_image (GskGLGlyphCache *self,
const GskGLCachedGlyph *glyph)
{
GskGLGlyphAtlas *atlas = glyph->atlas;
g_assert (atlas != NULL);
if (atlas->image == NULL)
{
atlas->image = g_new0 (GskGLImage, 1);
gsk_gl_image_create (atlas->image, self->gl_driver, atlas->width, atlas->height);
}
if (atlas->pending_glyph.key != NULL)
upload_dirty_glyph (self, atlas);
if (atlas->dirty_glyphs)
upload_dirty_glyphs (self, atlas);
return atlas->image;
}
+4 -23
View File
@@ -18,34 +18,18 @@ typedef struct
guint64 timestamp;
} GskGLGlyphCache;
typedef struct
{
PangoFont *font;
PangoGlyph glyph;
guint scale; /* times 1024 */
} GlyphCacheKey;
typedef struct _DirtyGlyph DirtyGlyph;
typedef struct _GskGLCachedGlyph GskGLCachedGlyph;
struct _DirtyGlyph
{
GlyphCacheKey *key;
GskGLCachedGlyph *value;
cairo_surface_t *surface;
};
typedef struct
{
GskGLImage *image;
int width, height;
int x, y, y0;
int num_glyphs;
GList *dirty_glyphs;
guint old_pixels;
DirtyGlyph pending_glyph;
} GskGLGlyphAtlas;
struct _GskGLCachedGlyph
typedef struct
{
GskGLGlyphAtlas *atlas;
@@ -59,11 +43,8 @@ struct _GskGLCachedGlyph
int draw_width;
int draw_height;
float scale;
guint64 timestamp;
};
} GskGLCachedGlyph;
void gsk_gl_glyph_cache_init (GskGLGlyphCache *self,
GskRenderer *renderer,
-51
View File
@@ -1,51 +0,0 @@
#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 = node->node_class->type_name;
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
@@ -1,28 +0,0 @@
#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
+163 -379
View File
@@ -14,7 +14,6 @@
#include "gskglrenderopsprivate.h"
#include "gskcairoblurprivate.h"
#include "gskglshadowcacheprivate.h"
#include "gskglnodesampleprivate.h"
#include "gskprivate.h"
@@ -105,19 +104,8 @@ print_render_node_tree (GskRenderNode *root, int level)
g_print ("%*s Texture %p\n", level * INDENT, " ", gsk_texture_node_get_texture (root));
break;
case GSK_DEBUG_NODE:
g_print ("%*s Debug: %s\n", level * INDENT, " ", gsk_debug_node_get_message (root));
print_render_node_tree (gsk_debug_node_get_child (root), level + 1);
break;
case GSK_CLIP_NODE:
g_print ("%*s Clip (%f, %f, %f, %f):\n", level * INDENT, " ",
root->bounds.origin.x, root->bounds.origin.y, root->bounds.size.width, root->bounds.size.height);
print_render_node_tree (gsk_clip_node_get_child (root), level + 1);
break;
default:
g_print ("%*s %s\n", level * INDENT, " ", root->node_class->type_name);
g_print ("UNKNOWN: %u\n", type);
}
#undef INDENT
@@ -231,40 +219,18 @@ gsk_rounded_rect_shrink_to_minimum (GskRoundedRect *self)
MAX (self->corner[2].height, self->corner[3].height)) * 2);
}
static inline gboolean
node_supports_transform (GskRenderNode *node)
{
/* Some nodes can't handle non-trivial transforms without being
* rendered to a texture (e.g. rotated clips, etc.). Some however
* work just fine, mostly because they already draw their child
* to a texture and just render the texture manipulated in some
* way, think opacity or color matrix. */
const guint node_type = gsk_render_node_get_node_type (node);
switch (node_type)
{
case GSK_COLOR_NODE:
case GSK_OPACITY_NODE:
case GSK_COLOR_MATRIX_NODE:
case GSK_TEXTURE_NODE:
return TRUE;
default:
return FALSE;
}
return FALSE;
}
static void gsk_gl_renderer_setup_render_mode (GskGLRenderer *self);
static void add_offscreen_ops (GskGLRenderer *self,
RenderOpBuilder *builder,
const graphene_rect_t *bounds,
GskRenderNode *child_node,
int *texture_id,
gboolean *is_offscreen,
gboolean force_offscreen,
gboolean reset_clip);
RenderOpBuilder *builder,
float min_x,
float max_x,
float min_y,
float max_y,
GskRenderNode *child_node,
int *texture_id,
gboolean *is_offscreen,
gboolean force_offscreen,
gboolean reset_clip);
static void gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
GskRenderNode *node,
RenderOpBuilder *builder);
@@ -282,6 +248,7 @@ struct _GskGLRenderer
union {
Program programs[GL_N_PROGRAMS];
struct {
Program blend_program;
Program blit_program;
Program color_program;
Program coloring_program;
@@ -322,49 +289,6 @@ struct _GskGLRendererClass
G_DEFINE_TYPE (GskGLRenderer, gsk_gl_renderer, GSK_TYPE_RENDERER)
static void G_GNUC_UNUSED
add_rect_ops (RenderOpBuilder *builder,
const graphene_rect_t *r)
{
const float min_x = r->origin.x;
const float min_y = r->origin.y;
const float max_x = min_x + r->size.width;
const float max_y = min_y + r->size.height;
ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
{ { min_x, min_y }, { 0, 1 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
{ { max_x, max_y }, { 1, 0 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
});
}
static void G_GNUC_UNUSED
add_rect_outline_ops (GskGLRenderer *self,
RenderOpBuilder *builder,
const graphene_rect_t *rect)
{
ops_set_program (builder, &self->color_program);
ops_set_color (builder, &(GdkRGBA) { 1, 0, 0, 1 });
add_rect_ops (builder,
&GRAPHENE_RECT_INIT (rect->origin.x, rect->origin.y,
1, rect->size.height));
add_rect_ops (builder,
&GRAPHENE_RECT_INIT (rect->origin.x, rect->origin.y,
rect->size.width, 1));
add_rect_ops (builder,
&GRAPHENE_RECT_INIT (rect->origin.x + rect->size.width - 1, rect->origin.y,
1, rect->size.height));
add_rect_ops (builder,
&GRAPHENE_RECT_INIT (rect->origin.x, rect->origin.y + rect->size.height - 1,
rect->size.width, 1));
}
static inline void
rounded_rect_to_floats (GskGLRenderer *self,
RenderOpBuilder *builder,
@@ -377,7 +301,7 @@ rounded_rect_to_floats (GskGLRenderer *self,
int i;
graphene_rect_t transformed_bounds;
ops_transform_bounds_modelview (builder, &rect->bounds, &transformed_bounds);
graphene_matrix_transform_bounds (&builder->current_modelview, &rect->bounds, &transformed_bounds);
outline[0] = transformed_bounds.origin.x;
outline[1] = transformed_bounds.origin.y;
@@ -496,7 +420,7 @@ render_text_node (GskGLRenderer *self,
text_scale);
/* e.g. whitespace */
if (glyph->draw_width <= 0 || glyph->draw_height <= 0 || glyph->scale <= 0)
if (glyph->draw_width <= 0 || glyph->draw_height <= 0)
goto next;
cx = (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
@@ -536,8 +460,8 @@ render_border_node (GskGLRenderer *self,
RenderOpBuilder *builder)
{
const float scale = ops_get_scale (builder);
const float min_x = builder->dx + node->bounds.origin.x;
const float min_y = builder->dy + node->bounds.origin.y;
const float min_x = node->bounds.origin.x;
const float min_y = node->bounds.origin.y;
const float max_x = min_x + node->bounds.size.width;
const float max_y = min_y + node->bounds.size.height;
const GdkRGBA *colors = gsk_border_node_peek_colors (node);
@@ -654,8 +578,8 @@ render_border_node (GskGLRenderer *self,
/* Prepare outline */
outline = *rounded_outline;
ops_transform_bounds_modelview (builder, &outline.bounds, &outline.bounds);
graphene_matrix_transform_bounds (&builder->current_modelview,
&outline.bounds, &outline.bounds);
for (i = 0; i < 4; i ++)
{
outline.corner[i].width *= scale;
@@ -663,8 +587,7 @@ render_border_node (GskGLRenderer *self,
}
ops_set_program (builder, &self->border_program);
ops_set_border_width (builder, widths);
ops_set_border (builder, &outline);
ops_set_border (builder, widths, &outline);
for (i = 0; i < 4; i ++)
{
@@ -766,12 +689,41 @@ render_offset_node (GskGLRenderer *self,
RenderOpBuilder *builder)
{
GskRenderNode *child = gsk_offset_node_get_child (node);
const guint child_type = gsk_render_node_get_node_type (child);
const float dx = gsk_offset_node_get_x_offset (node);
const float dy = gsk_offset_node_get_y_offset (node);
ops_offset (builder, dx, dy);
gsk_gl_renderer_add_render_ops (self, child, builder);
ops_offset (builder, - dx, - dy);
/* TODO: We do this only for selected node type we know handle
* builder->dx/dy correctly. That should be "all nodes" eventually.
*/
switch (child_type)
{
case GSK_TEXT_NODE:
case GSK_TEXTURE_NODE:
case GSK_COLOR_NODE:
case GSK_COLOR_MATRIX_NODE:
{
ops_offset (builder, dx, dy);
gsk_gl_renderer_add_render_ops (self, child, builder);
ops_offset (builder, - dx, - dy);
}
break;
default:
{
graphene_matrix_t prev_mv;
graphene_matrix_t transform, transformed_mv;
graphene_matrix_init_translate (&transform,
&GRAPHENE_POINT3D_INIT(dx, dy, 1.0));
graphene_matrix_multiply (&transform, &builder->current_modelview, &transformed_mv);
prev_mv = ops_set_modelview (builder, &transformed_mv);
gsk_gl_renderer_add_render_ops (self, child, builder);
ops_set_modelview (builder, &prev_mv);
}
}
}
static inline void
@@ -779,64 +731,17 @@ render_transform_node (GskGLRenderer *self,
GskRenderNode *node,
RenderOpBuilder *builder)
{
const float scale = ops_get_scale (builder);
GskRenderNode *child = gsk_transform_node_get_child (node);
graphene_matrix_t prev_mv;
graphene_matrix_t transform, transformed_mv;
graphene_matrix_init_from_matrix (&transform, gsk_transform_node_peek_transform (node));
graphene_matrix_multiply (&transform, builder->current_modelview, &transformed_mv);
graphene_matrix_translate (&transformed_mv,
&(graphene_point3d_t) { builder->dx * scale, builder->dy * scale, 0});
graphene_matrix_multiply (&transform, &builder->current_modelview, &transformed_mv);
prev_mv = ops_set_modelview (builder, &transformed_mv);
/* We just added the offset to the new modelview matrix, so the following
* cases dont' have to care about builder->dx/dy! */
gsk_gl_renderer_add_render_ops (self, child, builder);
ops_push_modelview (builder, &transformed_mv);
if (ops_modelview_is_simple (builder) ||
node_supports_transform (child))
{
const float dx = builder->dx;
const float dy = builder->dy;
builder->dx = 0;
builder->dy = 0;
gsk_gl_renderer_add_render_ops (self, child, builder);
builder->dx = dx;
builder->dy = dy;
}
else
{
const float min_x = node->bounds.origin.x;
const float min_y = node->bounds.origin.y;
const float max_x = min_x + node->bounds.size.width;
const float max_y = min_y + node->bounds.size.height;
const GskQuadVertex vertex_data[GL_N_VERTICES] = {
{ { min_x, min_y }, { 0, 1 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
{ { max_x, max_y }, { 1, 0 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
};
int texture_id;
gboolean is_offscreen;
/* For non-trivial transforms, we draw everything on a texture and then
* draw the texture transformed. */
/* TODO: We should compute a modelview containing only the "non-trivial"
* part (e.g. the rotation) and use that. We want to keep the scale
* for the texture.
*/
add_offscreen_ops (self, builder,
&node->bounds,
child,
&texture_id, &is_offscreen,
FALSE, TRUE);
ops_set_texture (builder, texture_id);
ops_set_program (builder, &self->blit_program);
ops_draw (builder, vertex_data);
}
ops_pop_modelview (builder);
ops_set_modelview (builder, &prev_mv);
}
static inline void
@@ -882,11 +787,7 @@ render_linear_gradient_node (GskGLRenderer *self,
op.op = OP_CHANGE_LINEAR_GRADIENT;
op.linear_gradient.n_color_stops = n_color_stops;
op.linear_gradient.start_point = *start;
op.linear_gradient.start_point.x += builder->dx;
op.linear_gradient.start_point.y += builder->dy;
op.linear_gradient.end_point = *end;
op.linear_gradient.end_point.x += builder->dx;
op.linear_gradient.end_point.y += builder->dy;
ops_add (builder, &op);
ops_draw (builder, vertex_data);
@@ -897,98 +798,64 @@ render_clip_node (GskGLRenderer *self,
GskRenderNode *node,
RenderOpBuilder *builder)
{
GskRoundedRect prev_clip;
GskRenderNode *child = gsk_clip_node_get_child (node);
graphene_rect_t transformed_clip;
graphene_rect_t intersection;
GskRoundedRect child_clip;
transformed_clip = *gsk_clip_node_peek_clip (node);
ops_transform_bounds_modelview (builder, &transformed_clip, &transformed_clip);
graphene_matrix_transform_bounds (&builder->current_modelview, &transformed_clip, &transformed_clip);
graphene_rect_intersection (&transformed_clip,
&builder->current_clip->bounds,
&builder->current_clip.bounds,
&intersection);
gsk_rounded_rect_init_from_rect (&child_clip, &intersection, 0.0f);
ops_push_clip (builder, &child_clip);
prev_clip = ops_set_clip (builder, &child_clip);
gsk_gl_renderer_add_render_ops (self, child, builder);
ops_pop_clip (builder);
ops_set_clip (builder, &prev_clip);
}
static gboolean
gsk_rounded_rect_intersection (const GskRoundedRect *self,
const GskRoundedRect *other,
GskRoundedRect *out_intersection)
{
const graphene_rect_t *self_bounds = &self->bounds;
const graphene_rect_t *other_bounds = &other->bounds;
if (graphene_rect_contains_rect (self_bounds, other_bounds))
{
*out_intersection = *other;
return TRUE;
}
/* TODO: There are a few cases here that we can express using a single
* rounded rectangle, which are even interesting in every day usage.
* For example, a partially scrolled-away rounded rectangle
* might just work.
*/
return FALSE;
}
static inline void
render_rounded_clip_node (GskGLRenderer *self,
GskRenderNode *node,
RenderOpBuilder *builder)
{
const float scale = ops_get_scale (builder);
const float min_x = node->bounds.origin.x;
const float min_y = node->bounds.origin.y;
const float max_x = min_x + node->bounds.size.width;
const float max_y = min_y + node->bounds.size.height;
GskRoundedRect child_clip = *gsk_rounded_clip_node_peek_clip (node);
GskRoundedRect transformed_clip;
GskRoundedRect prev_clip;
GskRenderNode *child = gsk_rounded_clip_node_get_child (node);
GskRoundedRect intersection;
gboolean need_offscreen;
int i;
transformed_clip = child_clip;
ops_transform_bounds_modelview (builder, &child_clip.bounds, &transformed_clip.bounds);
graphene_matrix_transform_bounds (&builder->current_modelview, &child_clip.bounds, &transformed_clip.bounds);
if (!ops_has_clip (builder))
{
intersection = transformed_clip;
need_offscreen = FALSE;
}
else
{
need_offscreen = !gsk_rounded_rect_intersection (builder->current_clip,
&transformed_clip,
&intersection);
}
if (!need_offscreen)
if (graphene_rect_contains_rect (&builder->current_clip.bounds,
&transformed_clip.bounds))
{
/* If they don't intersect at all, we can simply set
* the new clip and add the render ops */
for (i = 0; i < 4; i ++)
{
intersection.corner[i].width *= scale;
intersection.corner[i].height *= scale;
transformed_clip.corner[i].width *= scale;
transformed_clip.corner[i].height *= scale;
}
ops_push_clip (builder, &intersection);
prev_clip = ops_set_clip (builder, &transformed_clip);
gsk_gl_renderer_add_render_ops (self, child, builder);
ops_pop_clip (builder);
ops_set_clip (builder, &prev_clip);
}
else
else if (graphene_rect_intersection (&builder->current_clip.bounds,
&transformed_clip.bounds, NULL))
{
const float min_x = builder->dx + node->bounds.origin.x;
const float min_y = builder->dy + node->bounds.origin.y;
const float max_x = min_x + node->bounds.size.width;
const float max_y = min_y + node->bounds.size.height;
graphene_matrix_t scale_matrix;
gboolean is_offscreen;
int texture_id;
@@ -1009,12 +876,12 @@ render_rounded_clip_node (GskGLRenderer *self,
child_clip.corner[i].height *= scale;
}
ops_push_clip (builder, &child_clip);
add_offscreen_ops (self, builder, &node->bounds,
prev_clip = ops_set_clip (builder, &child_clip);
add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y,
child,
&texture_id, &is_offscreen, TRUE, FALSE);
ops_pop_clip (builder);
ops_set_clip (builder, &prev_clip);
ops_set_program (builder, &self->blit_program);
ops_set_texture (builder, texture_id);
@@ -1044,9 +911,7 @@ render_color_matrix_node (GskGLRenderer *self,
int texture_id;
gboolean is_offscreen;
/* Pass min_x/max_x/min_y/max_y without builder->dx/dy! */
add_offscreen_ops (self, builder,
&node->bounds,
add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y,
gsk_color_matrix_node_get_child (node),
&texture_id, &is_offscreen, FALSE, TRUE);
@@ -1083,23 +948,16 @@ render_blur_node (GskGLRenderer *self,
RenderOpBuilder *builder,
const GskQuadVertex *vertex_data)
{
const float min_x = builder->dx + node->bounds.origin.x;
const float min_y = builder->dy + node->bounds.origin.y;
const float min_x = node->bounds.origin.x;
const float min_y = node->bounds.origin.y;
const float max_x = min_x + node->bounds.size.width;
const float max_y = min_y + node->bounds.size.height;
int texture_id;
gboolean is_offscreen;
RenderOp op;
/* TODO(perf): We're forcing the child offscreen even if it's a texture
* so the resulting offscreen texture is bigger by the gaussian blur factor
* (see gsk_blur_node_new), but we didn't have to do that if the blur
* shader could handle that situation. */
add_offscreen_ops (self, builder,
&node->bounds,
add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y,
gsk_blur_node_get_child (node),
&texture_id, &is_offscreen, TRUE, TRUE);
&texture_id, &is_offscreen, FALSE, TRUE);
ops_set_program (builder, &self->blur_program);
op.op = OP_CHANGE_BLUR;
@@ -1205,14 +1063,15 @@ render_outset_shadow_node (GskGLRenderer *self,
const float spread = gsk_outset_shadow_node_get_spread (node);
const float dx = gsk_outset_shadow_node_get_dx (node);
const float dy = gsk_outset_shadow_node_get_dy (node);
const float min_x = builder->dx + outline->bounds.origin.x - spread - blur_extra / 2.0;
const float min_y = builder->dy + outline->bounds.origin.y - spread - blur_extra / 2.0;
const float min_x = outline->bounds.origin.x - spread - blur_extra / 2.0;
const float min_y = outline->bounds.origin.y - spread - blur_extra / 2.0;
const float max_x = min_x + outline->bounds.size.width + (spread + blur_extra/2.0) * 2;
const float max_y = min_y + outline->bounds.size.height + (spread + blur_extra/2.0) * 2;
float texture_width, texture_height;
RenderOp op;
graphene_matrix_t identity;
graphene_matrix_t prev_projection;
graphene_matrix_t prev_modelview;
graphene_rect_t prev_viewport;
graphene_matrix_t item_proj;
int blurred_texture_id;
@@ -1247,7 +1106,7 @@ render_outset_shadow_node (GskGLRenderer *self,
int texture_id, render_target;
int blurred_render_target;
int prev_render_target;
GskRoundedRect blit_clip;
GskRoundedRect prev_clip, blit_clip;
texture_id = gsk_gl_driver_create_texture (self->gl_driver, texture_width, texture_height);
gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id);
@@ -1265,12 +1124,12 @@ render_outset_shadow_node (GskGLRenderer *self,
op.op = OP_CLEAR;
ops_add (builder, &op);
prev_projection = ops_set_projection (builder, &item_proj);
ops_push_modelview (builder, &identity);
prev_modelview = ops_set_modelview (builder, &identity);
prev_viewport = ops_set_viewport (builder, &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height));
/* Draw outline */
ops_set_program (builder, &self->color_program);
ops_push_clip (builder, &offset_outline);
prev_clip = ops_set_clip (builder, &offset_outline);
ops_set_color (builder, gsk_outset_shadow_node_peek_color (node));
ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
{ { 0, }, { 0, 1 }, },
@@ -1288,7 +1147,6 @@ render_outset_shadow_node (GskGLRenderer *self,
blurred_render_target = gsk_gl_driver_create_render_target (self->gl_driver, blurred_texture_id, TRUE, TRUE);
ops_set_render_target (builder, blurred_render_target);
ops_pop_clip (builder);
op.op = OP_CLEAR;
ops_add (builder, &op);
@@ -1302,7 +1160,7 @@ render_outset_shadow_node (GskGLRenderer *self,
op.blur.radius = blur_radius;
ops_add (builder, &op);
ops_push_clip (builder, &blit_clip);
ops_set_clip (builder, &blit_clip);
ops_set_texture (builder, texture_id);
ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
{ { 0, 0 }, { 0, 1 }, },
@@ -1315,9 +1173,9 @@ render_outset_shadow_node (GskGLRenderer *self,
});
ops_pop_clip (builder);
ops_set_clip (builder, &prev_clip);
ops_set_viewport (builder, &prev_viewport);
ops_pop_modelview (builder);
ops_set_modelview (builder, &prev_modelview);
ops_set_projection (builder, &prev_projection);
ops_set_render_target (builder, prev_render_target);
@@ -1601,6 +1459,11 @@ render_shadow_node (GskGLRenderer *self,
g_assert (shadow->radius <= 0);
min_x = shadow_child->bounds.origin.x;
min_y = shadow_child->bounds.origin.y;
max_x = min_x + shadow_child->bounds.size.width;
max_y = min_y + shadow_child->bounds.size.height;
if (gsk_render_node_get_node_type (shadow_child) == GSK_TEXT_NODE)
{
ops_offset (builder, dx, dy);
@@ -1609,14 +1472,9 @@ render_shadow_node (GskGLRenderer *self,
continue;
}
min_x = builder->dx + shadow_child->bounds.origin.x;
min_y = builder->dy + shadow_child->bounds.origin.y;
max_x = min_x + shadow_child->bounds.size.width;
max_y = min_y + shadow_child->bounds.size.height;
/* Draw the child offscreen, without the offset. */
add_offscreen_ops (self, builder,
&shadow_child->bounds,
min_x, max_x, min_y, max_y,
shadow_child, &texture_id, &is_offscreen, FALSE, TRUE);
ops_offset (builder, dx, dy);
@@ -1664,8 +1522,8 @@ render_cross_fade_node (GskGLRenderer *self,
GskRenderNode *node,
RenderOpBuilder *builder)
{
const float min_x = builder->dx + node->bounds.origin.x;
const float min_y = builder->dy + node->bounds.origin.y;
const float min_x = node->bounds.origin.x;
const float min_y = node->bounds.origin.y;
const float max_x = min_x + node->bounds.size.width;
const float max_y = min_y + node->bounds.size.height;
GskRenderNode *start_node = gsk_cross_fade_node_get_start_child (node);
@@ -1688,14 +1546,10 @@ render_cross_fade_node (GskGLRenderer *self,
/* TODO: We create 2 textures here as big as the cross-fade node, but both the
* start and the end node might be a lot smaller than that. */
add_offscreen_ops (self, builder,
&node->bounds,
start_node,
add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y, start_node,
&start_texture_id, &is_offscreen1, TRUE, TRUE);
add_offscreen_ops (self, builder,
&node->bounds,
end_node,
add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y, end_node,
&end_texture_id, &is_offscreen2, TRUE, TRUE);
ops_set_program (builder, &self->cross_fade_program);
@@ -1923,7 +1777,8 @@ apply_border_op (const Program *program,
float widths[4];
float heights[4];
int i;
OP_PRINT (" -> Border Outline");
OP_PRINT (" -> Border (%f, %f, %f, %f)",
op->border.widths[0], op->border.widths[1], op->border.widths[2], op->border.widths[3]);
outline[0] = o->bounds.origin.x;
outline[1] = o->bounds.origin.y;
@@ -1936,21 +1791,12 @@ apply_border_op (const Program *program,
heights[i] = o->corner[i].height;
}
glUniform4fv (program->border.widths_location, 1, op->border.widths);
glUniform4fv (program->border.outline_location, 1, outline);
glUniform4fv (program->border.corner_widths_location, 1, widths);
glUniform4fv (program->border.corner_heights_location, 1, heights);
}
static inline void
apply_border_width_op (const Program *program,
const RenderOp *op)
{
OP_PRINT (" -> Border width (%f, %f, %f, %f)",
op->border.widths[0], op->border.widths[1], op->border.widths[2], op->border.widths[3]);
glUniform4fv (program->border.widths_location, 1, op->border.widths);
}
static inline void
apply_border_color_op (const Program *program,
const RenderOp *op)
@@ -2001,19 +1847,21 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
int i;
static const struct {
const char *name;
const char *vs;
const char *fs;
} program_definitions[] = {
{ "blit", "blit.fs.glsl" },
{ "color", "color.fs.glsl" },
{ "coloring", "coloring.fs.glsl" },
{ "color matrix", "color_matrix.fs.glsl" },
{ "linear gradient", "linear_gradient.fs.glsl" },
{ "blur", "blur.fs.glsl" },
{ "inset shadow", "inset_shadow.fs.glsl" },
{ "outset shadow", "outset_shadow.fs.glsl" },
{ "unblurred outset shadow", "unblurred_outset_shadow.fs.glsl" },
{ "border", "border.fs.glsl" },
{ "cross fade", "cross_fade.fs.glsl" },
{ "blend", "blend.vs.glsl", "blend.fs.glsl" },
{ "blit", "blit.vs.glsl", "blit.fs.glsl" },
{ "color", "blit.vs.glsl", "color.fs.glsl" },
{ "coloring", "blit.vs.glsl", "coloring.fs.glsl" },
{ "color matrix", "blit.vs.glsl", "color_matrix.fs.glsl" },
{ "linear gradient", "blit.vs.glsl", "linear_gradient.fs.glsl" },
{ "blur", "blit.vs.glsl", "blur.fs.glsl" },
{ "inset shadow", "blit.vs.glsl", "inset_shadow.fs.glsl" },
{ "outset shadow", "blit.vs.glsl", "outset_shadow.fs.glsl" },
{ "unblurred outset shadow", "blit.vs.glsl", "unblurred_outset_shadow.fs.glsl" },
{ "border", "blit.vs.glsl", "border.fs.glsl" },
{ "cross fade", "blit.vs.glsl", "cross_fade.fs.glsl" },
};
builder = gsk_shader_builder_new ();
@@ -2054,17 +1902,13 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
gsk_shader_builder_add_define (builder, "GSK_DEBUG", "1");
#endif
gsk_shader_builder_set_common_vertex_shader (builder, "blit.vs.glsl",
&shader_error);
g_assert_no_error (shader_error);
for (i = 0; i < GL_N_PROGRAMS; i ++)
{
Program *prog = &self->programs[i];
prog->index = i;
prog->id = gsk_shader_builder_create_program (builder,
program_definitions[i].vs,
program_definitions[i].fs,
&shader_error);
@@ -2073,7 +1917,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
g_propagate_prefixed_error (error, shader_error,
"Unable to create '%s' program (from %s and %s):\n",
program_definitions[i].name,
"blit.vs.glsl",
program_definitions[i].vs,
program_definitions[i].fs);
g_object_unref (builder);
@@ -2296,11 +2140,12 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
{
graphene_rect_t transformed_node_bounds;
ops_transform_bounds_modelview (builder,
&node->bounds,
&transformed_node_bounds);
graphene_matrix_transform_bounds (&builder->current_modelview,
&node->bounds,
&transformed_node_bounds);
graphene_rect_offset (&transformed_node_bounds, builder->dx, builder->dy);
if (!graphene_rect_intersection (&builder->current_clip->bounds,
if (!graphene_rect_intersection (&builder->current_clip.bounds,
&transformed_node_bounds, NULL))
return;
}
@@ -2409,29 +2254,30 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
}
static void
add_offscreen_ops (GskGLRenderer *self,
RenderOpBuilder *builder,
const graphene_rect_t *bounds,
GskRenderNode *child_node,
int *texture_id_out,
gboolean *is_offscreen,
gboolean force_offscreen,
gboolean reset_clip)
add_offscreen_ops (GskGLRenderer *self,
RenderOpBuilder *builder,
float min_x,
float max_x,
float min_y,
float max_y,
GskRenderNode *child_node,
int *texture_id,
gboolean *is_offscreen,
gboolean force_offscreen,
gboolean reset_clip)
{
const float scale = ops_get_scale (builder);
const float width = bounds->size.width * scale;
const float height = bounds->size.height * scale;
const float dx = builder->dx;
const float dy = builder->dy;
const float width = (max_x - min_x) * scale;
const float height = (max_y - min_y) * scale;
int render_target;
int prev_render_target;
RenderOp op;
graphene_matrix_t identity;
graphene_matrix_t prev_projection;
graphene_matrix_t prev_modelview;
graphene_rect_t prev_viewport;
graphene_matrix_t item_proj;
float prev_opacity;
int texture_id = 0;
GskRoundedRect prev_clip;
/* We need the child node as a texture. If it already is one, we don't need to draw
* it on a framebuffer of course. */
@@ -2442,37 +2288,22 @@ add_offscreen_ops (GskGLRenderer *self,
get_gl_scaling_filters (child_node, &gl_min_filter, &gl_mag_filter);
*texture_id_out = gsk_gl_driver_get_texture_for_texture (self->gl_driver,
texture,
gl_min_filter,
gl_mag_filter);
*texture_id = gsk_gl_driver_get_texture_for_texture (self->gl_driver,
texture,
gl_min_filter,
gl_mag_filter);
*is_offscreen = FALSE;
return;
}
/* Check if we've already cached the drawn texture. */
{
const int cached_id = gsk_gl_driver_get_texture_for_pointer (self->gl_driver, child_node);
if (cached_id != 0)
{
*texture_id_out = cached_id;
/* We didn't render it offscreen, but hand out an offscreen texture id */
*is_offscreen = TRUE;
return;
}
}
texture_id = gsk_gl_driver_create_texture (self->gl_driver, width, height);
gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id);
gsk_gl_driver_init_texture_empty (self->gl_driver, texture_id);
render_target = gsk_gl_driver_create_render_target (self->gl_driver, texture_id, TRUE, TRUE);
*texture_id = gsk_gl_driver_create_texture (self->gl_driver, width, height);
gsk_gl_driver_bind_source_texture (self->gl_driver, *texture_id);
gsk_gl_driver_init_texture_empty (self->gl_driver, *texture_id);
render_target = gsk_gl_driver_create_render_target (self->gl_driver, *texture_id, TRUE, TRUE);
graphene_matrix_init_ortho (&item_proj,
bounds->origin.x * scale,
(bounds->origin.x + bounds->size.width) * scale,
bounds->origin.y * scale,
(bounds->origin.y + bounds->size.height) * scale,
min_x * scale, max_x * scale,
min_y * scale, max_y * scale,
ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE);
graphene_matrix_scale (&item_proj, 1, -1, 1);
graphene_matrix_init_identity (&identity);
@@ -2483,39 +2314,27 @@ add_offscreen_ops (GskGLRenderer *self,
op.op = OP_CLEAR;
ops_add (builder, &op);
prev_projection = ops_set_projection (builder, &item_proj);
ops_push_modelview (builder, &identity);
prev_viewport = ops_set_viewport (builder,
&GRAPHENE_RECT_INIT (bounds->origin.x * scale,
bounds->origin.y * scale,
width, height));
prev_modelview = ops_set_modelview (builder, &identity);
prev_viewport = ops_set_viewport (builder, &GRAPHENE_RECT_INIT (min_x * scale,
min_y * scale,
width, height));
if (reset_clip)
ops_push_clip (builder,
&GSK_ROUNDED_RECT_INIT (bounds->origin.x * scale,
bounds->origin.y * scale,
width, height));
builder->dx = 0;
builder->dy = 0;
prev_opacity = ops_set_opacity (builder, 1.0);
prev_clip = ops_set_clip (builder,
&GSK_ROUNDED_RECT_INIT (min_x * scale,
min_y * scale,
width, height));
gsk_gl_renderer_add_render_ops (self, child_node, builder);
ops_set_opacity (builder, prev_opacity);
builder->dx = dx;
builder->dy = dy;
if (reset_clip)
ops_pop_clip (builder);
ops_set_clip (builder, &prev_clip);
ops_set_viewport (builder, &prev_viewport);
ops_pop_modelview (builder);
ops_set_modelview (builder, &prev_modelview);
ops_set_projection (builder, &prev_projection);
ops_set_render_target (builder, prev_render_target);
*is_offscreen = TRUE;
*texture_id_out = texture_id;
gsk_gl_driver_set_texture_for_pointer (self->gl_driver, child_node, texture_id);
}
static void
@@ -2662,10 +2481,6 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
apply_border_op (program, op);
break;
case OP_CHANGE_BORDER_WIDTH:
apply_border_width_op (program, op);
break;
case OP_CHANGE_UNBLURRED_OUTSET_SHADOW:
apply_unblurred_outset_shadow_op (program, op);
break;
@@ -2676,10 +2491,6 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
glDrawArrays (GL_TRIANGLES, op->draw.vao_offset, op->draw.vao_size);
break;
case OP_DUMP_FRAMEBUFFER:
dump_framebuffer (op->dump.filename, op->dump.width, op->dump.height);
break;
default:
g_warn_if_reached ();
}
@@ -2737,35 +2548,11 @@ gsk_gl_renderer_do_render (GskRenderer *renderer,
memset (&render_op_builder, 0, sizeof (render_op_builder));
render_op_builder.renderer = self;
render_op_builder.current_projection = projection;
render_op_builder.current_modelview = modelview;
render_op_builder.current_viewport = *viewport;
render_op_builder.current_opacity = 1.0f;
render_op_builder.render_ops = self->render_ops;
ops_push_modelview (&render_op_builder, &modelview);
/* Initial clip is self->render_region! */
if (self->render_region != NULL)
{
GskRoundedRect transformed_render_region = { 0, };
cairo_rectangle_int_t render_extents;
cairo_region_get_extents (self->render_region, &render_extents);
ops_transform_bounds_modelview (&render_op_builder,
&GRAPHENE_RECT_INIT (render_extents.x,
render_extents.y,
render_extents.width,
render_extents.height),
&transformed_render_region.bounds);
ops_push_clip (&render_op_builder, &transformed_render_region);
}
else
{
ops_push_clip (&render_op_builder,
&GSK_ROUNDED_RECT_INIT (viewport->origin.x,
viewport->origin.y,
viewport->size.width,
viewport->size.height));
}
gsk_rounded_rect_init_from_rect (&render_op_builder.current_clip, viewport, 0.0f);
if (fbo_id != 0)
ops_set_render_target (&render_op_builder, fbo_id);
@@ -2774,9 +2561,6 @@ gsk_gl_renderer_do_render (GskRenderer *renderer,
/* We correctly reset the state everywhere */
g_assert_cmpint (render_op_builder.current_render_target, ==, fbo_id);
ops_pop_modelview (&render_op_builder);
ops_pop_clip (&render_op_builder);
ops_finish (&render_op_builder);
/*g_message ("Ops: %u", self->render_ops->len);*/
+60 -312
View File
@@ -1,22 +1,5 @@
#include "gskglrenderopsprivate.h"
static inline gboolean
rect_equal (const graphene_rect_t *a,
const graphene_rect_t *b)
{
return memcmp (a, b, sizeof (graphene_rect_t)) == 0;
}
void
ops_finish (RenderOpBuilder *builder)
{
if (builder->mv_stack)
g_array_free (builder->mv_stack, TRUE);
if (builder->clip_stack)
g_array_free (builder->clip_stack, TRUE);
}
static inline void
rgba_to_float (const GdkRGBA *c,
float *f)
@@ -27,134 +10,13 @@ rgba_to_float (const GdkRGBA *c,
f[3] = c->alpha;
}
/* Debugging only! */
void
ops_dump_framebuffer (RenderOpBuilder *builder,
const char *filename,
int width,
int height)
{
RenderOp op;
op.op = OP_DUMP_FRAMEBUFFER;
op.dump.filename = g_strdup (filename);
op.dump.width = width;
op.dump.height = height;
g_array_append_val (builder->render_ops, op);
}
float
ops_get_scale (const RenderOpBuilder *builder)
{
const MatrixStackEntry *head;
const graphene_matrix_t *mv = &builder->current_modelview;
g_assert (builder->mv_stack != NULL);
g_assert (builder->mv_stack->len >= 1);
head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
/* TODO: Use two separate values */
return MAX (head->metadata.scale_x,
head->metadata.scale_y);
}
static void
extract_matrix_metadata (const graphene_matrix_t *m,
OpsMatrixMetadata *md)
{
graphene_vec3_t col1;
graphene_vec3_t col2;
/* Translate */
md->translate_x = graphene_matrix_get_value (m, 3, 0);
md->translate_y = graphene_matrix_get_value (m, 3, 1);
/* Scale */
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);
/* A simple matrix (in our case) is one that doesn't do anything but scale
* and/or translate.
*
* For orher matrices, we fall back to offscreen drawing.
*/
md->simple = TRUE;
{
static const guchar check_zero[4][4] = {
{ 0, 1, 0, 1 }, /* If any of the values marked as '1' here is non-zero, */
{ 1, 0, 0, 1 }, /* We have to resort to offscreen drawing later on. */
{ 1, 1, 0, 1 },
{ 0, 0, 0, 0 },
};
int x, y;
for (x = 0; x < 4; x ++)
for (y = 0; y < 4; y ++)
if (check_zero[y][x] &&
graphene_matrix_get_value (m, y, x) != 0.0f)
{
md->simple = FALSE;
goto out;
}
}
out:
md->only_translation = (md->simple && md->scale_x == 1 && md->scale_y == 1);
}
void
ops_transform_bounds_modelview (const RenderOpBuilder *builder,
const graphene_rect_t *src,
graphene_rect_t *dst)
{
const float scale = ops_get_scale (builder);
const MatrixStackEntry *head;
g_assert (builder->mv_stack != NULL);
g_assert (builder->mv_stack->len >= 1);
head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
if (head->metadata.only_translation)
{
*dst = *src;
graphene_rect_offset (dst,
head->metadata.translate_x,
head->metadata.translate_y);
}
else
{
graphene_matrix_transform_bounds (builder->current_modelview,
src,
dst);
}
graphene_rect_offset (dst, builder->dx * scale, builder->dy * scale);
}
gboolean
ops_modelview_is_simple (const RenderOpBuilder *builder)
{
const MatrixStackEntry *head;
g_assert (builder->mv_stack != NULL);
g_assert (builder->mv_stack->len >= 1);
head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
return head->metadata.simple;
return MAX (graphene_matrix_get_x_scale (mv),
graphene_matrix_get_y_scale (mv));
}
void
@@ -167,7 +29,6 @@ ops_set_program (RenderOpBuilder *builder,
static const graphene_matrix_t empty_matrix;
static const graphene_rect_t empty_rect;
RenderOp op;
ProgramState *program_state;
if (builder->current_program == program)
return;
@@ -177,61 +38,58 @@ ops_set_program (RenderOpBuilder *builder,
g_array_append_val (builder->render_ops, op);
builder->current_program = program;
program_state = &builder->program_state[program->index];
/* If the projection is not yet set for this program, we use the current one. */
if (memcmp (&empty_matrix, &program_state->projection, sizeof (graphene_matrix_t)) == 0 ||
memcmp (&builder->current_projection, &program_state->projection, sizeof (graphene_matrix_t)) != 0)
if (memcmp (&empty_matrix, &builder->program_state[program->index].projection, sizeof (graphene_matrix_t)) == 0 ||
memcmp (&builder->current_projection, &builder->program_state[program->index].projection, sizeof (graphene_matrix_t)) != 0)
{
op.op = OP_CHANGE_PROJECTION;
op.projection = builder->current_projection;
g_array_append_val (builder->render_ops, op);
program_state->projection = builder->current_projection;
builder->program_state[program->index].projection = builder->current_projection;
}
if (memcmp (&empty_matrix, &program_state->modelview, sizeof (graphene_matrix_t)) == 0 ||
memcmp (builder->current_modelview, &program_state->modelview, sizeof (graphene_matrix_t)) != 0)
if (memcmp (&empty_matrix, &builder->program_state[program->index].modelview, sizeof (graphene_matrix_t)) == 0 ||
memcmp (&builder->current_modelview, &builder->program_state[program->index].modelview, sizeof (graphene_matrix_t)) != 0)
{
op.op = OP_CHANGE_MODELVIEW;
op.modelview = *builder->current_modelview;
op.modelview = builder->current_modelview;
g_array_append_val (builder->render_ops, op);
program_state->modelview = *builder->current_modelview;
builder->program_state[program->index].modelview = builder->current_modelview;
}
if (rect_equal (&empty_rect, &program_state->viewport) ||
!rect_equal (&builder->current_viewport, &program_state->viewport))
if (memcmp (&empty_rect, &builder->program_state[program->index].viewport, sizeof (graphene_rect_t)) == 0 ||
memcmp (&builder->current_viewport, &builder->program_state[program->index].viewport, sizeof (graphene_rect_t)) != 0)
{
op.op = OP_CHANGE_VIEWPORT;
op.viewport = builder->current_viewport;
g_array_append_val (builder->render_ops, op);
program_state->viewport = builder->current_viewport;
builder->program_state[program->index].viewport = builder->current_viewport;
}
if (memcmp (&empty_clip, &program_state->clip, sizeof (GskRoundedRect)) == 0 ||
memcmp (&builder->current_clip, &program_state->clip, sizeof (GskRoundedRect)) != 0)
if (memcmp (&empty_clip, &builder->program_state[program->index].clip, sizeof (GskRoundedRect)) == 0 ||
memcmp (&builder->current_clip, &builder->program_state[program->index].clip, sizeof (GskRoundedRect)) != 0)
{
op.op = OP_CHANGE_CLIP;
op.clip = *builder->current_clip;
op.clip = builder->current_clip;
g_array_append_val (builder->render_ops, op);
program_state->clip = *builder->current_clip;
builder->program_state[program->index].clip = builder->current_clip;
}
if (program_state->opacity != builder->current_opacity)
if (builder->program_state[program->index].opacity != builder->current_opacity)
{
op.op = OP_CHANGE_OPACITY;
op.opacity = builder->current_opacity;
g_array_append_val (builder->render_ops, op);
program_state->opacity = builder->current_opacity;
builder->program_state[program->index].opacity = builder->current_opacity;
}
builder->current_program_state = &builder->program_state[program->index];
}
static void
GskRoundedRect
ops_set_clip (RenderOpBuilder *builder,
const GskRoundedRect *clip)
{
RenderOp *last_op;
GskRoundedRect prev_clip;
if (builder->render_ops->len > 0)
{
@@ -252,62 +110,25 @@ ops_set_clip (RenderOpBuilder *builder,
}
if (builder->current_program != NULL)
builder->current_program_state->clip = *clip;
builder->program_state[builder->current_program->index].clip = *clip;
prev_clip = builder->current_clip;
builder->current_clip = *clip;
return prev_clip;
}
void
ops_push_clip (RenderOpBuilder *self,
const GskRoundedRect *clip)
{
if (G_UNLIKELY (self->clip_stack == NULL))
self->clip_stack = g_array_new (FALSE, TRUE, sizeof (GskRoundedRect));
g_assert (self->clip_stack != NULL);
g_array_append_val (self->clip_stack, *clip);
self->current_clip = &g_array_index (self->clip_stack, GskRoundedRect, self->clip_stack->len - 1);
ops_set_clip (self, clip);
}
void
ops_pop_clip (RenderOpBuilder *self)
{
const GskRoundedRect *head;
g_assert (self->clip_stack);
g_assert (self->clip_stack->len >= 1);
self->clip_stack->len --;
head = &g_array_index (self->clip_stack, GskRoundedRect, self->clip_stack->len - 1);
if (self->clip_stack->len >= 1)
{
self->current_clip = head;
ops_set_clip (self, head);
}
else
{
self->current_clip = NULL;
}
}
gboolean
ops_has_clip (RenderOpBuilder *self)
{
return self->clip_stack != NULL &&
self->clip_stack->len > 1;
}
static void
graphene_matrix_t
ops_set_modelview (RenderOpBuilder *builder,
const graphene_matrix_t *modelview)
{
RenderOp op;
graphene_matrix_t prev_mv;
if (builder->current_program &&
memcmp (&builder->current_program_state->modelview, modelview,
memcmp (&builder->program_state[builder->current_program->index].modelview, modelview,
sizeof (graphene_matrix_t)) == 0)
return;
return *modelview;
if (builder->render_ops->len > 0)
{
@@ -331,52 +152,12 @@ ops_set_modelview (RenderOpBuilder *builder,
}
if (builder->current_program != NULL)
builder->current_program_state->modelview = *modelview;
}
builder->program_state[builder->current_program->index].modelview = *modelview;
void
ops_push_modelview (RenderOpBuilder *builder,
const graphene_matrix_t *mv)
{
MatrixStackEntry *entry;
prev_mv = builder->current_modelview;
builder->current_modelview = *modelview;
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->matrix = *mv;
extract_matrix_metadata (mv, &entry->metadata);
builder->current_modelview = &entry->matrix;
ops_set_modelview (builder, mv);
}
void
ops_pop_modelview (RenderOpBuilder *builder)
{
const graphene_matrix_t *m;
const MatrixStackEntry *head;
g_assert (builder->mv_stack);
g_assert (builder->mv_stack->len >= 1);
builder->mv_stack->len --;
head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
m = &head->matrix;
if (builder->mv_stack->len >= 1)
{
builder->current_modelview = m;
ops_set_modelview (builder, m);
}
else
{
builder->current_modelview = NULL;
}
return prev_mv;
}
graphene_matrix_t
@@ -408,7 +189,7 @@ ops_set_projection (RenderOpBuilder *builder,
}
if (builder->current_program != NULL)
builder->current_program_state->projection = *projection;
builder->program_state[builder->current_program->index].projection = *projection;
prev_mv = builder->current_projection;
builder->current_projection = *projection;
@@ -423,16 +204,12 @@ ops_set_viewport (RenderOpBuilder *builder,
RenderOp op;
graphene_rect_t prev_viewport;
if (builder->current_program_state != NULL &&
rect_equal (&builder->current_program_state->viewport, viewport))
return builder->current_program_state->viewport;
op.op = OP_CHANGE_VIEWPORT;
op.viewport = *viewport;
g_array_append_val (builder->render_ops, op);
if (builder->current_program != NULL)
builder->current_program_state->viewport = *viewport;
builder->program_state[builder->current_program->index].viewport = *viewport;
prev_viewport = builder->current_viewport;
builder->current_viewport = *viewport;
@@ -466,28 +243,9 @@ ops_set_render_target (RenderOpBuilder *builder,
return render_target_id;
prev_render_target = builder->current_render_target;
if (builder->render_ops->len > 0)
{
RenderOp *last_op = &g_array_index (builder->render_ops, RenderOp, builder->render_ops->len - 1);
if (last_op->op == OP_CHANGE_RENDER_TARGET)
{
last_op->render_target_id = render_target_id;
}
else
{
op.op = OP_CHANGE_RENDER_TARGET;
op.render_target_id = render_target_id;
g_array_append_val (builder->render_ops, op);
}
}
else
{
op.op = OP_CHANGE_RENDER_TARGET;
op.render_target_id = render_target_id;
g_array_append_val (builder->render_ops, op);
}
op.op = OP_CHANGE_RENDER_TARGET;
op.render_target_id = render_target_id;
g_array_append_val (builder->render_ops, op);
builder->current_render_target = render_target_id;
return prev_render_target;
@@ -530,7 +288,7 @@ ops_set_opacity (RenderOpBuilder *builder,
builder->current_opacity = opacity;
if (builder->current_program != NULL)
builder->current_program_state->opacity = opacity;
builder->program_state[builder->current_program->index].opacity = opacity;
return prev_opacity;
}
@@ -541,10 +299,10 @@ ops_set_color (RenderOpBuilder *builder,
{
RenderOp op;
if (gdk_rgba_equal (color, &builder->current_program_state->color))
if (gdk_rgba_equal (color, &builder->program_state[builder->current_program->index].color))
return;
builder->current_program_state->color = *color;
builder->program_state[builder->current_program->index].color = *color;
op.op = OP_CHANGE_COLOR;
op.color = *color;
@@ -559,15 +317,15 @@ ops_set_color_matrix (RenderOpBuilder *builder,
RenderOp op;
if (memcmp (matrix,
&builder->current_program_state->color_matrix.matrix,
&builder->program_state[builder->current_program->index].color_matrix.matrix,
sizeof (graphene_matrix_t)) == 0 &&
memcmp (offset,
&builder->current_program_state->color_matrix.offset,
&builder->program_state[builder->current_program->index].color_matrix.offset,
sizeof (graphene_vec4_t)) == 0)
return;
builder->current_program_state->color_matrix.matrix = *matrix;
builder->current_program_state->color_matrix.offset = *offset;
builder->program_state[builder->current_program->index].color_matrix.matrix = *matrix;
builder->program_state[builder->current_program->index].color_matrix.offset = *offset;
op.op = OP_CHANGE_COLOR_MATRIX;
op.color_matrix.matrix = *matrix;
@@ -577,40 +335,30 @@ ops_set_color_matrix (RenderOpBuilder *builder,
void
ops_set_border (RenderOpBuilder *builder,
const float *widths,
const GskRoundedRect *outline)
{
RenderOp op;
if (memcmp (&builder->current_program_state->border.outline,
/* TODO: Assert that current_program == border program? */
if (memcmp (&builder->program_state[builder->current_program->index].border.widths,
widths, sizeof (float) * 4) == 0 &&
memcmp (&builder->program_state[builder->current_program->index].border.outline,
outline, sizeof (GskRoundedRect)) == 0)
return;
builder->current_program_state->border.outline = *outline;
op.op = OP_CHANGE_BORDER;
op.border.outline = *outline;
g_array_append_val (builder->render_ops, op);
}
void
ops_set_border_width (RenderOpBuilder *builder,
const float *widths)
{
RenderOp op;
if (memcmp (builder->current_program_state->border.widths,
widths, sizeof (float) * 4) == 0)
return;
memcpy (&builder->current_program_state->border.widths,
memcpy (&builder->program_state[builder->current_program->index].border.widths,
widths, sizeof (float) * 4);
op.op = OP_CHANGE_BORDER_WIDTH;
builder->program_state[builder->current_program->index].border.outline = *outline;
op.op = OP_CHANGE_BORDER;
op.border.widths[0] = widths[0];
op.border.widths[1] = widths[1];
op.border.widths[2] = widths[2];
op.border.widths[3] = widths[3];
op.border.outline = *outline;
g_array_append_val (builder->render_ops, op);
}
@@ -622,11 +370,11 @@ ops_set_border_color (RenderOpBuilder *builder,
op.op = OP_CHANGE_BORDER_COLOR;
rgba_to_float (color, op.border.color);
if (memcmp (&op.border.color, &builder->current_program_state->border.color,
if (memcmp (&op.border.color, &builder->program_state[builder->current_program->index].border.color,
sizeof (float) * 4) == 0)
return;
rgba_to_float (color, builder->current_program_state->border.color);
rgba_to_float (color, builder->program_state[builder->current_program->index].border.color);
g_array_append_val (builder->render_ops, op);
}
+33 -82
View File
@@ -10,26 +10,7 @@
#include "gskglrendererprivate.h"
#define GL_N_VERTICES 6
#define GL_N_PROGRAMS 11
typedef struct
{
float translate_x;
float translate_y;
float scale_x;
float scale_y;
guint simple : 1;
guint only_translation : 1;
} OpsMatrixMetadata;
typedef struct
{
graphene_matrix_t matrix;
OpsMatrixMetadata metadata;
} MatrixStackEntry;
#define GL_N_PROGRAMS 12
enum {
OP_NONE,
@@ -50,12 +31,10 @@ enum {
OP_CHANGE_OUTSET_SHADOW = 15,
OP_CHANGE_BORDER = 16,
OP_CHANGE_BORDER_COLOR = 17,
OP_CHANGE_BORDER_WIDTH = 18,
OP_CHANGE_CROSS_FADE = 19,
OP_CHANGE_UNBLURRED_OUTSET_SHADOW = 20,
OP_CLEAR = 21,
OP_DRAW = 22,
OP_DUMP_FRAMEBUFFER = 23,
OP_CHANGE_CROSS_FADE = 18,
OP_CHANGE_UNBLURRED_OUTSET_SHADOW = 19,
OP_CLEAR = 20,
OP_DRAW = 21,
};
typedef struct
@@ -209,46 +188,40 @@ typedef struct
float progress;
int source2;
} cross_fade;
struct {
char *filename;
int width;
int height;
} dump;
};
} RenderOp;
typedef struct
{
GskRoundedRect clip;
graphene_matrix_t modelview;
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];
float color[4];
GskRoundedRect outline;
} border;
};
} ProgramState;
/* Per-Program State */
struct {
GskRoundedRect clip;
graphene_matrix_t modelview;
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];
float color[4];
GskRoundedRect outline;
} border;
};
} program_state[GL_N_PROGRAMS];
typedef struct
{
ProgramState program_state[GL_N_PROGRAMS];
/* Current global state */
ProgramState *current_program_state;
const Program *current_program;
int current_render_target;
int current_texture;
GskRoundedRect current_clip;
graphene_matrix_t current_modelview;
graphene_matrix_t current_projection;
graphene_rect_t current_viewport;
float current_opacity;
@@ -258,41 +231,20 @@ typedef struct
GArray *render_ops;
GskGLRenderer *renderer;
/* Stack of modelview matrices */
GArray *mv_stack;
/* Pointer into mv_stack */
const graphene_matrix_t *current_modelview;
/* Same thing */
GArray *clip_stack;
const GskRoundedRect *current_clip;
} RenderOpBuilder;
void ops_dump_framebuffer (RenderOpBuilder *builder,
const char *filename,
int width,
int height);
void ops_finish (RenderOpBuilder *builder);
void ops_push_modelview (RenderOpBuilder *builder,
const graphene_matrix_t *mv);
void ops_pop_modelview (RenderOpBuilder *builder);
gboolean ops_modelview_is_simple (const RenderOpBuilder *builder);
float ops_get_scale (const RenderOpBuilder *builder);
void ops_set_program (RenderOpBuilder *builder,
const Program *program);
void ops_push_clip (RenderOpBuilder *builder,
GskRoundedRect ops_set_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_modelview (RenderOpBuilder *builder,
const graphene_matrix_t *modelview);
graphene_matrix_t ops_set_projection (RenderOpBuilder *builder,
const graphene_matrix_t *projection);
@@ -316,9 +268,8 @@ void ops_set_color_matrix (RenderOpBuilder *builder,
const graphene_vec4_t *offset);
void ops_set_border (RenderOpBuilder *builder,
const float *widths,
const GskRoundedRect *outline);
void ops_set_border_width (RenderOpBuilder *builder,
const float *widths);
void ops_set_border_color (RenderOpBuilder *builder,
const GdkRGBA *color);
+11 -29
View File
@@ -15,9 +15,6 @@ struct _GskShaderBuilder
char *vertex_preamble;
char *fragment_preamble;
int common_vertex_shader_id;
int version;
GPtrArray *defines;
@@ -40,9 +37,6 @@ gsk_shader_builder_finalize (GObject *gobject)
g_clear_pointer (&self->defines, g_ptr_array_unref);
if (self->common_vertex_shader_id > 0)
glDeleteShader (self->common_vertex_shader_id);
G_OBJECT_CLASS (gsk_shader_builder_parent_class)->finalize (gobject);
}
@@ -236,39 +230,27 @@ gsk_shader_builder_compile_shader (GskShaderBuilder *builder,
return shader_id;
}
void
gsk_shader_builder_set_common_vertex_shader (GskShaderBuilder *self,
const char *vertex_shader,
GError **error)
{
int shader_id;
shader_id = gsk_shader_builder_compile_shader (self,
GL_VERTEX_SHADER,
self->vertex_preamble,
vertex_shader,
error);
g_assert (shader_id > 0);
self->common_vertex_shader_id = shader_id;
}
int
gsk_shader_builder_create_program (GskShaderBuilder *builder,
const char *vertex_shader,
const char *fragment_shader,
GError **error)
{
int vertex_id;
int fragment_id;
int vertex_id, fragment_id;
int program_id;
int status;
g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
g_return_val_if_fail (vertex_shader != NULL, -1);
g_return_val_if_fail (fragment_shader != NULL, -1);
g_return_val_if_fail (builder->common_vertex_shader_id != 0, -1);
vertex_id = builder->common_vertex_shader_id;
vertex_id = gsk_shader_builder_compile_shader (builder, GL_VERTEX_SHADER,
builder->vertex_preamble,
vertex_shader,
error);
if (vertex_id < 0)
return -1;
fragment_id = gsk_shader_builder_compile_shader (builder, GL_FRAGMENT_SHADER,
builder->fragment_preamble,
fragment_shader,
@@ -308,8 +290,8 @@ gsk_shader_builder_create_program (GskShaderBuilder *builder,
out:
if (vertex_id > 0)
{
/* We delete the common vertex shader when destroying the shader builder */
glDetachShader (program_id, vertex_id);
glDeleteShader (vertex_id);
}
if (fragment_id > 0)
+1 -4
View File
@@ -25,11 +25,8 @@ void gsk_shader_builder_add_define (GskShad
const char *define_name,
const char *define_value);
void gsk_shader_builder_set_common_vertex_shader (GskShaderBuilder *self,
const char *vertex_shader,
GError **error);
int gsk_shader_builder_create_program (GskShaderBuilder *builder,
const char *vertex_shader,
const char *fragment_shader,
GError **error);
+2 -1
View File
@@ -1,4 +1,6 @@
gsk_private_gl_shaders = [
'resources/glsl/blend.fs.glsl',
'resources/glsl/blend.vs.glsl',
'resources/glsl/blit.fs.glsl',
'resources/glsl/blit.vs.glsl',
'resources/glsl/color.fs.glsl',
@@ -41,7 +43,6 @@ gsk_private_sources = files([
'gl/gskgldriver.c',
'gl/gskglrenderops.c',
'gl/gskglshadowcache.c',
'gl/gskglnodesample.c',
])
gsk_public_headers = files([
+61
View File
@@ -0,0 +1,61 @@
vec3 BlendMultiply(vec3 Cb, vec3 Cs) {
return Cb * Cs;
}
vec3 BlendScreen(vec3 Cb, vec3 Cs) {
return Cb + Cs - (Cb * Cs);
}
vec3 BlendHardLight(vec3 Cb, vec3 Cs) {
vec3 m = BlendMultiply(Cb, 2.0 * Cs);
vec3 s = BlendScreen(Cb, 2.0 * Cs - 1.0);
vec3 edge = vec3(0.5, 0.5, 0.5);
/* Use mix() and step() to avoid a branch */
return mix(m, s, step(edge, Cs));
}
vec3 BlendOverlay(vec3 Cb, vec3 Cs) {
return BlendHardLight(Cs, Cb);
}
vec3 BlendDarken(vec3 Cb, vec3 Cs) {
return min(Cb, Cs);
}
vec3 BlendLighten(vec3 Cb, vec3 Cs) {
return max(Cb, Cs);
}
void main() {
vec4 Cs = Texture(u_source, vUv);
vec4 Cb = Texture(u_mask, vUv);
vec3 res;
if (uBlendMode == 0) {
res = Cs.xyz;
}
else if (uBlendMode == 1) {
res = BlendMultiply(Cb.xyz, Cs.xyz);
}
else if (uBlendMode == 2) {
res = BlendScreen(Cb.xyz, Cs.xyz);
}
else if (uBlendMode == 3) {
res = BlendOverlay(Cb.xyz, Cs.xyz);
}
else if (uBlendMode == 4) {
res = BlendDarken(Cb.xyz, Cs.xyz);
}
else if (uBlendMode == 5) {
res = BlendLighten(Cb.xyz, Cs.xyz);
}
else if (uBlendMode == 8) {
res = BlendHardLight(Cb.xyz, Cs.xyz);
}
else {
// Use red for debugging missing blend modes
res = vec3(1.0, 0.0, 0.0);
}
setOutputColor(vec4(res, Cs.a) * u_alpha);
}
+5
View File
@@ -0,0 +1,5 @@
void main() {
gl_Position = u_modelview * u_projection * vec4(aPosition, 0.0, 1.0);
vUv = vec2(aUv.x, aUv.y);
}
+3 -3
View File
@@ -24,7 +24,7 @@ developers, including those developing proprietary software, without
any license fees or royalties.</description>
<homepage rdf:resource="http://www.gtk.org/" />
<license rdf:resource="http://usefulinc.com/doap/licenses/lgpl" />
<bug-database rdf:resource="https://gitlab.gnome.org/GNOME/gtk/issues/" />
<bug-database rdf:resource="http://bugzilla.gnome.org/enter_bug.cgi?product=gtk%2B" />
<download-page rdf:resource="http://download.gnome.org/sources/gtk+/" />
<mailing-list rdf:resource="http://mail.gnome.org/mailman/listinfo/gtk-list" />
<mailing-list rdf:resource="http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list" />
@@ -39,8 +39,8 @@ any license fees or royalties.</description>
<repository>
<GitRepository>
<browse rdf:resource="https://gitlab.gnome.org/GNOME/gtk/"/>
<location rdf:resource="https://gitlab.gnome.org/GNOME/gtk.git"/>
<browse rdf:resource="http://git.gnome.org/browse/gtk+/"/>
<location rdf:resource="git://git.gnome.org/gtk+"/>
</GitRepository>
</repository>
+10 -2
View File
@@ -116,11 +116,13 @@ atk_key_event_from_gdk_event_key (GdkEventKey *key,
GdkModifierType state;
guint keyval;
guint16 keycode;
const char *string;
type = gdk_event_get_event_type ((GdkEvent *)key);
gdk_event_get_state ((GdkEvent *)key, &state);
gdk_event_get_keyval ((GdkEvent *)key, &keyval);
gdk_event_get_keycode ((GdkEvent *)key, &keycode);
gdk_event_get_string ((GdkEvent *)key, &string);
if (type == GDK_KEY_PRESS)
event->type = ATK_KEY_EVENT_PRESS;
@@ -131,8 +133,14 @@ atk_key_event_from_gdk_event_key (GdkEventKey *key,
event->state = state;
event->keyval = keyval;
event->string = gdk_keyval_name (keyval);
event->length = strlen (event->string);
if (string && string[0] &&
(state & GDK_CONTROL_MASK ||
g_unichar_isgraph (g_utf8_get_char (string))))
event->string = (char *) string;
else
event->string = gdk_keyval_name (keyval);
event->length = strlen (string);
event->keycode = keycode;
event->timestamp = gdk_event_get_time ((GdkEvent *)key);
}
+1 -87
View File
@@ -46,13 +46,11 @@ static const struct {
static GtkCellRendererState gtk_cell_accessible_get_state (GtkCellAccessible *cell);
static void atk_action_interface_init (AtkActionIface *iface);
static void atk_component_interface_init (AtkComponentIface *iface);
static void atk_table_cell_interface_init (AtkTableCellIface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkCellAccessible, gtk_cell_accessible, GTK_TYPE_ACCESSIBLE,
G_ADD_PRIVATE (GtkCellAccessible)
G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init)
G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, atk_component_interface_init)
G_IMPLEMENT_INTERFACE (ATK_TYPE_TABLE_CELL, atk_table_cell_interface_init))
G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, atk_component_interface_init))
static gint
gtk_cell_accessible_get_index_in_parent (AtkObject *obj)
@@ -368,90 +366,6 @@ atk_component_interface_init (AtkComponentIface *iface)
iface->grab_focus = gtk_cell_accessible_grab_focus;
}
static int
gtk_cell_accessible_get_column_span (AtkTableCell *table_cell)
{
return 1;
}
static GPtrArray *
gtk_cell_accessible_get_column_header_cells (AtkTableCell *table_cell)
{
GtkCellAccessible *cell;
AtkObject *parent;
cell = GTK_CELL_ACCESSIBLE (table_cell);
parent = gtk_widget_get_accessible (gtk_accessible_get_widget (GTK_ACCESSIBLE (cell)));
return gtk_cell_accessible_parent_get_column_header_cells (GTK_CELL_ACCESSIBLE_PARENT (parent),
cell);
}
static gboolean
gtk_cell_accessible_get_position (AtkTableCell *table_cell,
gint *row,
gint *column)
{
GtkCellAccessible *cell;
AtkObject *parent;
cell = GTK_CELL_ACCESSIBLE (table_cell);
parent = gtk_widget_get_accessible (gtk_accessible_get_widget (GTK_ACCESSIBLE (cell)));
gtk_cell_accessible_parent_get_cell_position (GTK_CELL_ACCESSIBLE_PARENT (parent),
cell,
row, column);
return ((row && *row > 0) || (column && *column > 0));
}
static int
gtk_cell_accessible_get_row_span (AtkTableCell *table_cell)
{
return 1;
}
static GPtrArray *
gtk_cell_accessible_get_row_header_cells (AtkTableCell *table_cell)
{
GtkCellAccessible *cell;
AtkObject *parent;
cell = GTK_CELL_ACCESSIBLE (table_cell);
parent = gtk_widget_get_accessible (gtk_accessible_get_widget (GTK_ACCESSIBLE (cell)));
return gtk_cell_accessible_parent_get_row_header_cells (GTK_CELL_ACCESSIBLE_PARENT (parent),
cell);
}
static AtkObject *
gtk_cell_accessible_get_table (AtkTableCell *table_cell)
{
AtkObject *obj;
obj = ATK_OBJECT (table_cell);
do
{
AtkRole role;
obj = atk_object_get_parent (obj);
role = atk_object_get_role (obj);
if (role == ATK_ROLE_TABLE || role == ATK_ROLE_TREE_TABLE)
break;
}
while (obj);
return obj;
}
static void
atk_table_cell_interface_init (AtkTableCellIface *iface)
{
iface->get_column_span = gtk_cell_accessible_get_column_span;
iface->get_column_header_cells = gtk_cell_accessible_get_column_header_cells;
iface->get_position = gtk_cell_accessible_get_position;
iface->get_row_span = gtk_cell_accessible_get_row_span;
iface->get_row_header_cells = gtk_cell_accessible_get_row_header_cells;
iface->get_table = gtk_cell_accessible_get_table;
}
static GtkCellRendererState
gtk_cell_accessible_get_state (GtkCellAccessible *cell)
{

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