Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2a3f1acb3f |
@@ -1 +0,0 @@
|
||||
/subprojects/*/
|
||||
+2
-2
@@ -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 .
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
-----------------------
|
||||
|
||||
|
||||
@@ -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": [
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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" },
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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));
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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 });
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"><Primary>q</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</menu>
|
||||
</interface>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
||||
+21
-21
@@ -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:
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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,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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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,
|
||||
_("Drag’n’drop from other applications is not supported."));
|
||||
_("Drag'n'drop from other applications is not supported."));
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ struct _GdkQuartzMonitor
|
||||
{
|
||||
GdkMonitor parent;
|
||||
|
||||
gint monitor_num;
|
||||
NSScreen *nsscreen;
|
||||
};
|
||||
|
||||
struct _GdkQuartzMonitorClass {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -77,7 +77,6 @@ struct _GdkWaylandDisplay
|
||||
|
||||
GHashTable *settings;
|
||||
GsdXftSettings xft_settings;
|
||||
GDBusProxy *settings_portal;
|
||||
|
||||
guint32 shell_capabilities;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
_("Can’t transmute a single handle"));
|
||||
_("Can't transmute a single handle"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 application’s leader window so that
|
||||
* the window manager can save the application’s state using the X11R6 ICCCM
|
||||
|
||||
+16
-26
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
@@ -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, ®ion);
|
||||
for (l = atlas->dirty_glyphs, i = 0; l; l = l->next, i++)
|
||||
render_glyph (atlas, (DirtyGlyph *)l->data, ®ions[i]);
|
||||
|
||||
gsk_gl_image_upload_regions (atlas->image, self->gl_driver, 1, ®ion);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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([
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
void main() {
|
||||
gl_Position = u_modelview * u_projection * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user