Compare commits
303 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 79835c7e57 | |||
| 1740aeab40 | |||
| 589a662052 | |||
| 349e0156b3 | |||
| a9fb224b8d | |||
| e2162c13ee | |||
| 17103d765f | |||
| c1bf9e3320 | |||
| 6f913eac15 | |||
| f9b0b55361 | |||
| 6e0ac83d99 | |||
| 12ad6b3157 | |||
| fda9fd5ced | |||
| 029ce83a69 | |||
| 5ced6be416 | |||
| bbda833b01 | |||
| c86bc00330 | |||
| 68755c0fd2 | |||
| 9090c28125 | |||
| 3a3244891e | |||
| b55117334c | |||
| 02e5c7b9ad | |||
| 7268167f4c | |||
| 93c7502cf7 | |||
| 789705cfe4 | |||
| 741471a1f8 | |||
| f8da751cc2 | |||
| 8174842d9f | |||
| e872952f36 | |||
| b010e46d13 | |||
| eb646a8e8b | |||
| 1e2975147d | |||
| 653c10e8b6 | |||
| dfbafdf047 | |||
| d8c821a851 | |||
| 83376648d7 | |||
| 089c34fa03 | |||
| c846f8d745 | |||
| 79ebd76ac8 | |||
| 6eb9836eb0 | |||
| 4a8f8a6eea | |||
| 3ea723730b | |||
| 90be2baf8b | |||
| 0b64fa88a1 | |||
| c6cc446e63 | |||
| 0cad37760e | |||
| e720008dca | |||
| 9c636a6136 | |||
| 1e24aa425e | |||
| a8c597005a | |||
| 97a781b380 | |||
| 313cadefe6 | |||
| 9f078bd5c9 | |||
| 8ff4e27103 | |||
| 8389ca633d | |||
| 18fbec0fe1 | |||
| eb0a00067d | |||
| 91216408e5 | |||
| 6da5b8cb25 | |||
| 7bee7bf5fc | |||
| fac66ade01 | |||
| 96eae5f62e | |||
| 1cc99847f4 | |||
| d8b14cd3e3 | |||
| 0c80eb5afb | |||
| fdcb1d92c5 | |||
| d65dc6c730 | |||
| c721c4d6ef | |||
| 1a7ba3c512 | |||
| 25ee1a7784 | |||
| 0b2cebe3d8 | |||
| 5dd0d39a6b | |||
| 9f3ff427c1 | |||
| 14e60d21ac | |||
| 65c3796135 | |||
| 25acc26531 | |||
| 859bf8b15d | |||
| e0bf96f329 | |||
| 11c5ea1fec | |||
| bc063350ef | |||
| 347b0317e5 | |||
| 72d832a4f3 | |||
| 76df3ade18 | |||
| d849a53b98 | |||
| ef6d3af6b9 | |||
| f513914306 | |||
| 7135f80094 | |||
| ef82e0ce4e | |||
| 1910834f8f | |||
| f94a0624fa | |||
| 17c59d6da6 | |||
| 56c0aa596e | |||
| a1c73a9b2e | |||
| cac0cb7f02 | |||
| 7eb999720a | |||
| 05e15241b4 | |||
| a730867778 | |||
| 8513621709 | |||
| 14d99bacbc | |||
| cbbd3e8fc3 | |||
| 8fa45d5fef | |||
| 3e1706679c | |||
| 7f359e31c6 | |||
| e4af2c4d80 | |||
| 2d121c07c9 | |||
| cc904698a6 | |||
| a5fdd1228f | |||
| 271d7632cb | |||
| a8613377a5 | |||
| d7cf5c2b1b | |||
| 95865cb1bf | |||
| 0b813de72a | |||
| 9c159cf129 | |||
| 957d494090 | |||
| 968b4237a9 | |||
| f67c57b1f8 | |||
| 84f8c2d91d | |||
| 8f1d8d7cb5 | |||
| e98d9d62eb | |||
| 5a0b65c611 | |||
| 5777587e7a | |||
| ecfc661054 | |||
| e00722dee6 | |||
| 5af21e70ec | |||
| 7e13cfea91 | |||
| 68b4d9c35e | |||
| 1f3b69e7db | |||
| ca63552cf8 | |||
| a6d2d983b8 | |||
| 7cd97192e5 | |||
| 8ac8bca52a | |||
| cf8f6d254e | |||
| a267dfac5d | |||
| 745b28ef38 | |||
| 5c27899efa | |||
| fd006592b5 | |||
| 201f27fe19 | |||
| 36c4dc8aea | |||
| f0bd0c3e50 | |||
| 4d71ff6da1 | |||
| 6d16776e27 | |||
| 7cdff6bbb3 | |||
| bf43859bdc | |||
| 4b45f8415f | |||
| 86e0d5c13e | |||
| d21ee115d0 | |||
| 2dd8e3b0eb | |||
| 6d001f79f9 | |||
| eb6ca8f39a | |||
| abebd92b19 | |||
| 014ca76334 | |||
| a520f9fcf7 | |||
| de724b2a57 | |||
| 061637f4eb | |||
| dab1897d4e | |||
| 9ebb030c78 | |||
| 93477ec019 | |||
| f2a71898b1 | |||
| 24048dce43 | |||
| 41af8ee2e2 | |||
| 60c20fa6ed | |||
| 5152c13081 | |||
| e9089f65e3 | |||
| 9aaec91f95 | |||
| 1c971c595f | |||
| f8627755b5 | |||
| 55ae8dc39e | |||
| dd7d145249 | |||
| 0b2c249de3 | |||
| ea6b95f60d | |||
| ed44f37de4 | |||
| 3780a5ed6a | |||
| fec3f0191a | |||
| 359fa99945 | |||
| 5441ed2227 | |||
| ec1a1d0e34 | |||
| 8f4fb45715 | |||
| 9db2288064 | |||
| 1502c21e97 | |||
| 408dd4b34d | |||
| 609e1f54ef | |||
| f49d0fbbf6 | |||
| dde47b7966 | |||
| f84da62740 | |||
| cbfbe6dc23 | |||
| 2c63a34791 | |||
| 9ab07553a3 | |||
| c29fb838e9 | |||
| aecc76d916 | |||
| 713a5188cf | |||
| 911f3bf555 | |||
| c752598a3d | |||
| 9dfdb1b65b | |||
| a05a021fd1 | |||
| 9ffd7840ba | |||
| dd64084b44 | |||
| 21277a37d6 | |||
| ddc7e36543 | |||
| f429dff03e | |||
| 6f07c6a3f1 | |||
| 4cb4aa1029 | |||
| cecab7801e | |||
| ea7fd1ff5a | |||
| ad474a60c0 | |||
| 1e8e7e0c00 | |||
| 1e9e8d24c3 | |||
| 9bd9b6f2ca | |||
| 913a6ddcc9 | |||
| 31da6f60d0 | |||
| c4c118e425 | |||
| 02599acf4d | |||
| 6a653e4675 | |||
| 29e92d6a0e | |||
| b4fcc8b5f0 | |||
| b00333c603 | |||
| 63614727a3 | |||
| 061a56d213 | |||
| 3f63ba36ce | |||
| d9b96c34be | |||
| 39a8c64624 | |||
| 360b77cc50 | |||
| 1186eff1b7 | |||
| 0b8582ccba | |||
| dc2914e1f9 | |||
| a0d8678a9c | |||
| c8a43da526 | |||
| 90ee05ae64 | |||
| 67a7602080 | |||
| 37db270d19 | |||
| f3312f677b | |||
| 05547d98d6 | |||
| 11b219bc61 | |||
| 5721c3cb8f | |||
| f90ca697af | |||
| 7a0e27b6e8 | |||
| e81aa18c82 | |||
| 827bbc0cc1 | |||
| 7095a67910 | |||
| dcbca3f0d7 | |||
| 702d7c238a | |||
| 5a3ed65ad8 | |||
| 2e24a9ece4 | |||
| 2a17320314 | |||
| 0dbff14555 | |||
| c5d89d00f1 | |||
| 6f3be310f4 | |||
| 0ea6b70d55 | |||
| 2ca9982b91 | |||
| a40282b2fb | |||
| ad9fb1e101 | |||
| 02a9652af4 | |||
| 6f823d2d0d | |||
| a5c9cd5657 | |||
| 21ab5b6fa3 | |||
| 2582fd45e4 | |||
| 0a28a5d53a | |||
| ddd4855bbc | |||
| 204216e3d5 | |||
| 1e6a124665 | |||
| 78c5aff956 | |||
| 8d1844135b | |||
| b5dd9dae0d | |||
| ebcb518e4f | |||
| b7ea22f168 | |||
| f0b3381660 | |||
| 0796c72049 | |||
| 822e988efe | |||
| cee043f977 | |||
| b420540b15 | |||
| 031c0ec3e5 | |||
| 43b6822eb0 | |||
| ba3a657c48 | |||
| 5f2f116c28 | |||
| 1db75e521d | |||
| 2297a353b8 | |||
| 80903e5f44 | |||
| 7342ce5bca | |||
| 167b38dfa1 | |||
| ead88c36ec | |||
| b8a3d7fa00 | |||
| 0fce24674a | |||
| 739084e9bc | |||
| 99ad585252 | |||
| 949b6692ac | |||
| eb0479d8ed | |||
| 6defdb4e8a | |||
| 9fdad6d4ee | |||
| b6e285844f | |||
| c989a06718 | |||
| 1c8bd8658d | |||
| ab50cba4e9 | |||
| 57918813e2 | |||
| a4df8d8818 | |||
| 4b00cfc1ce | |||
| 889688c978 | |||
| 0bf1ae033d | |||
| 994afcaeed | |||
| b69cc832ef | |||
| 81c8d1dd28 | |||
| 32d00ca9ed | |||
| 2782daadb4 | |||
| afbcbb8404 | |||
| 5c00dc7ef4 |
@@ -207,9 +207,7 @@ msys2-mingw64:
|
||||
|
||||
macos-x86_64:
|
||||
rules:
|
||||
# run merge request pipelines
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
# do not run in forks
|
||||
# Do not run in forks as the runner is not available there.
|
||||
- if: $CI_PROJECT_NAMESPACE == "GNOME"
|
||||
stage: build
|
||||
tags:
|
||||
|
||||
@@ -23,6 +23,7 @@ case "${backend}" in
|
||||
--suite=gtk \
|
||||
--no-suite=failing \
|
||||
--no-suite=flaky \
|
||||
--no-suite=headless \
|
||||
--no-suite=gsk-compare-broadway
|
||||
|
||||
# Store the exit code for the CI run, but always
|
||||
@@ -45,6 +46,7 @@ case "${backend}" in
|
||||
--suite=gtk \
|
||||
--no-suite=failing \
|
||||
--no-suite=flaky \
|
||||
--no-suite=headless \
|
||||
--no-suite=${backend}_failing \
|
||||
--no-suite=gsk-compare-broadway
|
||||
exit_code=$?
|
||||
@@ -67,6 +69,7 @@ case "${backend}" in
|
||||
--suite=gtk \
|
||||
--no-suite=failing \
|
||||
--no-suite=flaky \
|
||||
--no-suite=headless \
|
||||
--no-suite=gsk-compare-opengl
|
||||
|
||||
kill ${server}
|
||||
|
||||
@@ -35,8 +35,7 @@ The issue tracker is meant to be used for actionable issues only.
|
||||
|
||||
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.
|
||||
When in doubt, follow [security](https://security.gnome.org/).
|
||||
|
||||
### Bug reports
|
||||
|
||||
@@ -244,13 +243,11 @@ people committing to GTK to follow a few rules:
|
||||
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.
|
||||
better way to do things.
|
||||
The `gtk` [room on matrix](https://matrix.to/#/#gtk: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, the [gtk tag on the GNOME Discourse instance](https://discourse.gnome.org/tag/gtk)
|
||||
is the most certain and preferred method.
|
||||
|
||||
0. Ask _first_.
|
||||
|
||||
|
||||
@@ -1,6 +1,95 @@
|
||||
Overview of Changes in 4.13.1, xx-xx-xxxx
|
||||
Overview of Changes in 4.13.2, xx-xx-xxxx
|
||||
=========================================
|
||||
|
||||
Overview of Changes in 4.13.1, 28-09-2023
|
||||
=========================================
|
||||
|
||||
* GtkTooltip:
|
||||
- Don't cross native boundaries when looking for tooltips
|
||||
|
||||
* GtkCenterLayout, GtkEntry, GtkSearchEntry:
|
||||
- Fix some issues with baseline handling
|
||||
|
||||
* GtkColorButton, GtkFontButton:
|
||||
- Propagate focus-on-click
|
||||
|
||||
* GtkFileChooser:
|
||||
- Make "Visit file" scroll to the file
|
||||
|
||||
* GtkSwitch:
|
||||
- Respect text direction
|
||||
|
||||
* GtkWindow:
|
||||
- Don't assume titlebars are GtkHeaderBars
|
||||
|
||||
* Printing:
|
||||
- Fix some problems with the portal implementation
|
||||
- Add a new simple print API: GtkPrintDialog
|
||||
|
||||
* Paths:
|
||||
- GskPathMeasure performance has been improved
|
||||
- Add custom contours for circles, rounded rectangles and rectangles
|
||||
- Simplify GskPathPoint handling
|
||||
- gsk_path_point_get_closest_point now returns the distance as well
|
||||
- Make GskPathBuilder simplify curves
|
||||
|
||||
* Input:
|
||||
- Handle (some) single-key compose sequences
|
||||
- Fix active state tracking with sensitivity changes and grabs
|
||||
|
||||
* GSK:
|
||||
- Make the repeated gradients match between GL and cairo
|
||||
- Make rounded rect shrinking match between Vulkan, GL and cairo
|
||||
- Fix parsing of text nodes with color glyphs
|
||||
- Restrict an optimization to the cases where it is crrect
|
||||
- Fix rendering of shadows with opacity
|
||||
- The Vulkan renderer now requires Vulkan 1.2
|
||||
- GL: Transition gradients unpremultiplied
|
||||
- GL: Fix clipping of shadows
|
||||
- GL: Some optimizations
|
||||
- Broadway: Fix memory leaks in the renderer
|
||||
|
||||
* Wayland:
|
||||
- Make activation more reliable
|
||||
|
||||
* macOS:
|
||||
- Clamp damage regions to the surface size
|
||||
|
||||
* Tools:
|
||||
- gtk4-path-tool gained restrict and reverse commands
|
||||
- gtk4-path-tool show and render can show control points
|
||||
|
||||
* Demos:
|
||||
- Add a demo for hit testing with paths
|
||||
|
||||
* Build:
|
||||
- Fix build problems with C++ compilers
|
||||
|
||||
* Deprecations:
|
||||
- gtk_window_present_with_time
|
||||
|
||||
* Translation updates
|
||||
Brazilian Portuguese
|
||||
British English
|
||||
Catalan
|
||||
Chinese (China)
|
||||
Czech
|
||||
Danish
|
||||
Dutch
|
||||
Esperanto
|
||||
Galician
|
||||
Georgian
|
||||
Italian
|
||||
Korean
|
||||
Latvian
|
||||
Lithuanian
|
||||
Persian
|
||||
Polish
|
||||
Punjabi
|
||||
Slovenian
|
||||
Turkish
|
||||
|
||||
|
||||
Overview of Changes in 4.13.0, 25-08-2023
|
||||
=========================================
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
@@ -223,7 +223,7 @@ delete_messages (gpointer data)
|
||||
static void
|
||||
pop_message (GtkWidget *status)
|
||||
{
|
||||
GList *messages = (GList *) g_object_get_data (G_OBJECT (status), "messages");
|
||||
GList *messages = (GList *) g_object_steal_data (G_OBJECT (status), "messages");
|
||||
|
||||
if (messages)
|
||||
{
|
||||
@@ -241,7 +241,7 @@ static void
|
||||
push_message (GtkWidget *status,
|
||||
const char *message)
|
||||
{
|
||||
GList *messages = (GList *) g_object_get_data (G_OBJECT (status), "messages");
|
||||
GList *messages = (GList *) g_object_steal_data (G_OBJECT (status), "messages");
|
||||
|
||||
gtk_label_set_label (GTK_LABEL (status), message);
|
||||
messages = g_list_prepend (messages, g_strdup (message));
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 985 B After Width: | Height: | Size: 1019 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
@@ -127,6 +127,7 @@
|
||||
<file>fishbowl.ui</file>
|
||||
<file>gtkfishbowl.c</file>
|
||||
<file>gtkfishbowl.h</file>
|
||||
<file>tiger.node</file>
|
||||
</gresource>
|
||||
<gresource prefix="/frames">
|
||||
<file>frames.ui</file>
|
||||
@@ -336,6 +337,7 @@
|
||||
<file>panes.c</file>
|
||||
<file>password_entry.c</file>
|
||||
<file>path_fill.c</file>
|
||||
<file>path_maze.c</file>
|
||||
<file>path_spinner.c</file>
|
||||
<file>path_walk.c</file>
|
||||
<file>path_text.c</file>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -11,6 +11,9 @@
|
||||
#include "gtkgears.h"
|
||||
#include "gskshaderpaintable.h"
|
||||
|
||||
#include "nodewidget.h"
|
||||
#include "graphwidget.h"
|
||||
|
||||
const char *const css =
|
||||
".blurred-button {"
|
||||
" box-shadow: 0px 0px 5px 10px rgba(0, 0, 0, 0.5);"
|
||||
@@ -71,14 +74,7 @@ create_blurred_button (void)
|
||||
static GtkWidget *
|
||||
create_font_button (void)
|
||||
{
|
||||
GtkFontDialog *dialog;
|
||||
GtkWidget *button;
|
||||
|
||||
dialog = gtk_font_dialog_new ();
|
||||
button = gtk_font_dialog_button_new (dialog);
|
||||
g_object_unref (dialog);
|
||||
|
||||
return button;
|
||||
return gtk_font_dialog_button_new (gtk_font_dialog_new ());
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
@@ -208,6 +204,18 @@ create_menu_button (void)
|
||||
return w;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_tiger (void)
|
||||
{
|
||||
return node_widget_new ("/fishbowl/tiger.node");
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_graph (void)
|
||||
{
|
||||
return graph_widget_new ();
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
GtkWidget * (*create_func) (void);
|
||||
@@ -225,6 +233,8 @@ static const struct {
|
||||
{ "Switch", create_switch },
|
||||
{ "Menubutton", create_menu_button },
|
||||
{ "Shader", create_cogs },
|
||||
{ "Tiger", create_tiger },
|
||||
{ "Graph", create_graph },
|
||||
};
|
||||
|
||||
static int selected_widget_type = -1;
|
||||
|
||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,153 @@
|
||||
#include "graphwidget.h"
|
||||
|
||||
struct _GraphWidget
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GskPath *path;
|
||||
GskStroke *stroke;
|
||||
GdkRGBA color;
|
||||
|
||||
guint tick_cb;
|
||||
guint64 start_time;
|
||||
|
||||
double period;
|
||||
double amplitude;
|
||||
};
|
||||
|
||||
struct _GraphWidgetClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GraphWidget, graph_widget, GTK_TYPE_WIDGET)
|
||||
|
||||
static void
|
||||
update_path (GraphWidget *self,
|
||||
float amplitude)
|
||||
{
|
||||
graphene_point_t p[20];
|
||||
GskPathBuilder *builder;
|
||||
|
||||
g_clear_pointer (&self->path, gsk_path_unref);
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
p[i].x = 10 * i;
|
||||
p[i].y = 50;
|
||||
|
||||
if (i % 4 == 1 || i % 4 == 2)
|
||||
{
|
||||
if (i % 8 < 4)
|
||||
p[i].y += amplitude;
|
||||
else
|
||||
p[i].y -= amplitude;
|
||||
}
|
||||
}
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_builder_move_to (builder, p[0].x, p[0].y);
|
||||
|
||||
for (int i = 0; i < 20; i += 4)
|
||||
gsk_path_builder_cubic_to (builder,
|
||||
p[i+1].x, p[i+1].y,
|
||||
p[i+2].x, p[i+2].y,
|
||||
p[i+3].x, p[i+3].y);
|
||||
|
||||
self->path = gsk_path_builder_free_to_path (builder);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
tick_cb (GtkWidget *widget,
|
||||
GdkFrameClock *frame_clock,
|
||||
gpointer user_data)
|
||||
{
|
||||
GraphWidget *self = GRAPH_WIDGET (widget);
|
||||
guint64 now;
|
||||
double angle;
|
||||
|
||||
now = gdk_frame_clock_get_frame_time (frame_clock);
|
||||
|
||||
if (self->start_time == 0)
|
||||
self->start_time = now;
|
||||
|
||||
angle = 360 * (now - self->start_time) / (double)(self->period * G_TIME_SPAN_MINUTE);
|
||||
update_path (self, sin (angle) * self->amplitude);
|
||||
|
||||
gtk_widget_queue_draw (widget);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
graph_widget_init (GraphWidget *self)
|
||||
{
|
||||
self->color.red = g_random_double_range (0, 1);
|
||||
self->color.green = g_random_double_range (0, 1);
|
||||
self->color.blue = g_random_double_range (0, 1);
|
||||
self->color.alpha = 1;
|
||||
|
||||
self->period = g_random_double_range (0.5, 1);
|
||||
self->amplitude = g_random_double_range (10, 25);
|
||||
|
||||
self->stroke = gsk_stroke_new (2);
|
||||
|
||||
update_path (self, 0);
|
||||
|
||||
self->start_time = 0;
|
||||
self->tick_cb = gtk_widget_add_tick_callback (GTK_WIDGET (self), tick_cb, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
graph_widget_dispose (GObject *object)
|
||||
{
|
||||
GraphWidget *self = GRAPH_WIDGET (object);
|
||||
|
||||
g_clear_pointer (&self->path, gsk_path_unref);
|
||||
gsk_stroke_free (self->stroke);
|
||||
|
||||
G_OBJECT_CLASS (graph_widget_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
graph_widget_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
GraphWidget *self = GRAPH_WIDGET (widget);
|
||||
|
||||
gtk_snapshot_append_stroke (snapshot, self->path, self->stroke, &self->color);
|
||||
}
|
||||
|
||||
static void
|
||||
graph_widget_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
*minimum = *natural = 200;
|
||||
else
|
||||
*minimum = *natural = 100;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
graph_widget_class_init (GraphWidgetClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
object_class->dispose = graph_widget_dispose;
|
||||
|
||||
widget_class->snapshot = graph_widget_snapshot;
|
||||
widget_class->measure = graph_widget_measure;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
graph_widget_new (void)
|
||||
{
|
||||
return g_object_new (GRAPH_TYPE_WIDGET, NULL);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define GRAPH_TYPE_WIDGET (graph_widget_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GraphWidget, graph_widget, GRAPH, WIDGET, GtkWidget)
|
||||
|
||||
GtkWidget * graph_widget_new (void);
|
||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.8 KiB |
@@ -73,6 +73,7 @@ demos = files([
|
||||
'panes.c',
|
||||
'password_entry.c',
|
||||
'path_fill.c',
|
||||
'path_maze.c',
|
||||
'path_spinner.c',
|
||||
'path_walk.c',
|
||||
'path_text.c',
|
||||
@@ -140,6 +141,8 @@ extra_demo_sources = files([
|
||||
'unicode-names.c',
|
||||
'suggestionentry.c',
|
||||
'language-names.c',
|
||||
'nodewidget.c',
|
||||
'graphwidget.c',
|
||||
])
|
||||
|
||||
if os_unix
|
||||
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,76 @@
|
||||
#include "nodewidget.h"
|
||||
|
||||
struct _NodeWidget
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GskRenderNode *node;
|
||||
};
|
||||
|
||||
struct _NodeWidgetClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (NodeWidget, node_widget, GTK_TYPE_WIDGET)
|
||||
|
||||
static void
|
||||
node_widget_init (NodeWidget *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
node_widget_dispose (GObject *object)
|
||||
{
|
||||
NodeWidget *self = NODE_WIDGET (object);
|
||||
|
||||
gsk_render_node_unref (self->node);
|
||||
|
||||
G_OBJECT_CLASS (node_widget_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
node_widget_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
NodeWidget *self = NODE_WIDGET (widget);
|
||||
|
||||
gtk_snapshot_append_node (snapshot, self->node);
|
||||
}
|
||||
|
||||
static void
|
||||
node_widget_class_init (NodeWidgetClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
object_class->dispose = node_widget_dispose;
|
||||
|
||||
widget_class->snapshot = node_widget_snapshot;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
node_widget_new (const char *resource)
|
||||
{
|
||||
NodeWidget *self;
|
||||
GBytes *bytes;
|
||||
GskRenderNode *node;
|
||||
graphene_rect_t bounds;
|
||||
float scale;
|
||||
GskTransform *transform;
|
||||
|
||||
self = g_object_new (NODE_TYPE_WIDGET, NULL);
|
||||
|
||||
bytes = g_resources_lookup_data (resource, 0, NULL);
|
||||
node = gsk_render_node_deserialize (bytes, NULL, NULL);
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
gsk_render_node_get_bounds (node, &bounds);
|
||||
scale = MIN (100.0/bounds.size.width, 100.0/bounds.size.height);
|
||||
transform = gsk_transform_scale (NULL, scale, scale);
|
||||
self->node = gsk_transform_node_new (node, transform);
|
||||
gsk_transform_unref (transform);
|
||||
gsk_render_node_unref (node);
|
||||
|
||||
return GTK_WIDGET (self);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define NODE_TYPE_WIDGET (node_widget_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (NodeWidget, node_widget, NODE, WIDGET, GtkWidget)
|
||||
|
||||
GtkWidget * node_widget_new (const char *file);
|
||||
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB |
@@ -2,10 +2,13 @@
|
||||
*
|
||||
* This demo shows how to use GskPath to draw shapes that are (a bit)
|
||||
* more complex than a rounded rectangle.
|
||||
*
|
||||
* It also demonstrates printing to a stream with GtkPrintDialog.
|
||||
*/
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <cairo-pdf.h>
|
||||
|
||||
#include "paintable.h"
|
||||
|
||||
@@ -165,6 +168,89 @@ gtk_logo_paintable_new (void)
|
||||
return GDK_PAINTABLE (self);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
write_cairo (void *closure,
|
||||
const unsigned char *data,
|
||||
unsigned int length)
|
||||
{
|
||||
GOutputStream *stream = closure;
|
||||
gsize written;
|
||||
GError *error = NULL;
|
||||
|
||||
if (!g_output_stream_write_all (stream, data, length, &written, NULL, &error))
|
||||
{
|
||||
g_print ("Error writing pdf stream: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
return CAIRO_STATUS_WRITE_ERROR;
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
print_ready (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GtkPrintDialog *dialog = GTK_PRINT_DIALOG (source);
|
||||
GError *error = NULL;
|
||||
GOutputStream *stream;
|
||||
GtkSnapshot *snapshot;
|
||||
GdkPaintable *paintable;
|
||||
GskRenderNode *node;
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
|
||||
stream = gtk_print_dialog_print_finish (dialog, result, &error);
|
||||
if (stream == NULL)
|
||||
{
|
||||
g_print ("Failed to get output stream: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
snapshot = gtk_snapshot_new ();
|
||||
paintable = gtk_picture_get_paintable (GTK_PICTURE (data));
|
||||
gdk_paintable_snapshot (paintable, snapshot, 100, 100);
|
||||
node = gtk_snapshot_free_to_node (snapshot);
|
||||
|
||||
surface = cairo_pdf_surface_create_for_stream (write_cairo, stream, 100, 100);
|
||||
cr = cairo_create (surface);
|
||||
|
||||
gsk_render_node_draw (node, cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
cairo_surface_destroy (surface);
|
||||
gsk_render_node_unref (node);
|
||||
|
||||
if (!g_output_stream_close (stream, NULL, &error))
|
||||
{
|
||||
g_print ("Error from close: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_object_unref (stream);
|
||||
}
|
||||
|
||||
static void
|
||||
print (GtkButton *button,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *picture = data;
|
||||
GtkPrintDialog *dialog;
|
||||
|
||||
dialog = gtk_print_dialog_new ();
|
||||
|
||||
gtk_print_dialog_print (dialog,
|
||||
GTK_WINDOW (gtk_widget_get_root (picture)),
|
||||
NULL,
|
||||
NULL,
|
||||
print_ready,
|
||||
picture);
|
||||
|
||||
g_object_unref (dialog);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_path_fill (GtkWidget *do_widget)
|
||||
{
|
||||
@@ -172,12 +258,21 @@ do_path_fill (GtkWidget *do_widget)
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkWidget *header, *button, *label;
|
||||
GtkWidget *picture;
|
||||
GdkPaintable *paintable;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
|
||||
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 100, 100);
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Fill and Stroke");
|
||||
header = gtk_header_bar_new ();
|
||||
button = gtk_button_new_from_icon_name ("printer-symbolic");
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), button);
|
||||
label = gtk_label_new ("Fill and Stroke");
|
||||
gtk_widget_add_css_class (label, "title");
|
||||
gtk_header_bar_set_title_widget (GTK_HEADER_BAR (header), label);
|
||||
gtk_window_set_titlebar (GTK_WINDOW (window), header);
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
paintable = gtk_logo_paintable_new ();
|
||||
@@ -186,6 +281,8 @@ do_path_fill (GtkWidget *do_widget)
|
||||
gtk_picture_set_can_shrink (GTK_PICTURE (picture), FALSE);
|
||||
g_object_unref (paintable);
|
||||
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (print), picture);
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), picture);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,369 @@
|
||||
/* Path/Maze
|
||||
*
|
||||
* This demo shows how to use a GskPath to create a maze and use
|
||||
* gsk_path_get_closest_point() to check the mouse stays
|
||||
* on the path.
|
||||
*
|
||||
* It also shows off the performance of GskPath (or not) as this
|
||||
* is a rather complex path.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "paintable.h"
|
||||
|
||||
#define MAZE_GRID_SIZE 20
|
||||
#define MAZE_STROKE_SIZE_ACTIVE (MAZE_GRID_SIZE - 4)
|
||||
#define MAZE_STROKE_SIZE_INACTIVE (MAZE_GRID_SIZE - 12)
|
||||
#define MAZE_WIDTH 31
|
||||
#define MAZE_HEIGHT 21
|
||||
|
||||
#define GTK_TYPE_MAZE (gtk_maze_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GtkMaze, gtk_maze, GTK, MAZE, GtkWidget)
|
||||
|
||||
struct _GtkMaze
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
GskPath *path;
|
||||
GskPathMeasure *measure;
|
||||
GdkPaintable *background;
|
||||
|
||||
gboolean active;
|
||||
};
|
||||
|
||||
struct _GtkMazeClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkMaze, gtk_maze, GTK_TYPE_WIDGET)
|
||||
|
||||
static void
|
||||
gtk_maze_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
GtkMaze *self = GTK_MAZE (widget);
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
*minimum = *natural = self->width;
|
||||
else
|
||||
*minimum = *natural = self->height;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_maze_snapshot (GtkWidget *widget,
|
||||
GdkSnapshot *snapshot)
|
||||
{
|
||||
GtkMaze *self = GTK_MAZE (widget);
|
||||
double width = gtk_widget_get_width (widget);
|
||||
double height = gtk_widget_get_height (widget);
|
||||
GskStroke *stroke;
|
||||
|
||||
stroke = gsk_stroke_new (MAZE_STROKE_SIZE_INACTIVE);
|
||||
if (self->active)
|
||||
gsk_stroke_set_line_width (stroke, MAZE_STROKE_SIZE_ACTIVE);
|
||||
gsk_stroke_set_line_join (stroke, GSK_LINE_JOIN_ROUND);
|
||||
gsk_stroke_set_line_cap (stroke, GSK_LINE_CAP_ROUND);
|
||||
gtk_snapshot_push_stroke (snapshot, self->path, stroke);
|
||||
gsk_stroke_free (stroke);
|
||||
|
||||
if (self->background)
|
||||
{
|
||||
gdk_paintable_snapshot (self->background, snapshot, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_snapshot_append_linear_gradient (snapshot,
|
||||
&GRAPHENE_RECT_INIT (0, 0, width, height),
|
||||
&GRAPHENE_POINT_INIT (0, 0),
|
||||
&GRAPHENE_POINT_INIT (width, height),
|
||||
(GskColorStop[8]) {
|
||||
{ 0.0, { 1.0, 0.0, 0.0, 1.0 } },
|
||||
{ 0.2, { 1.0, 0.0, 0.0, 1.0 } },
|
||||
{ 0.3, { 1.0, 1.0, 0.0, 1.0 } },
|
||||
{ 0.4, { 0.0, 1.0, 0.0, 1.0 } },
|
||||
{ 0.6, { 0.0, 1.0, 1.0, 1.0 } },
|
||||
{ 0.7, { 0.0, 0.0, 1.0, 1.0 } },
|
||||
{ 0.8, { 1.0, 0.0, 1.0, 1.0 } },
|
||||
{ 1.0, { 1.0, 0.0, 1.0, 1.0 } }
|
||||
},
|
||||
8);
|
||||
}
|
||||
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_maze_dispose (GObject *object)
|
||||
{
|
||||
GtkMaze *self = GTK_MAZE (object);
|
||||
|
||||
g_clear_pointer (&self->path, gsk_path_unref);
|
||||
g_clear_pointer (&self->measure, gsk_path_measure_unref);
|
||||
if (self->background)
|
||||
{
|
||||
g_signal_handlers_disconnect_matched (self->background, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
|
||||
g_clear_object (&self->background);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (gtk_maze_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_maze_class_init (GtkMazeClass *klass)
|
||||
{
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = gtk_maze_dispose;
|
||||
|
||||
widget_class->measure = gtk_maze_measure;
|
||||
widget_class->snapshot = gtk_maze_snapshot;
|
||||
}
|
||||
|
||||
static void
|
||||
celebrate (gboolean win)
|
||||
{
|
||||
char *path;
|
||||
GtkMediaStream *stream;
|
||||
|
||||
if (win)
|
||||
path = g_build_filename (GTK_DATADIR, "sounds", "freedesktop", "stereo", "complete.oga", NULL);
|
||||
else
|
||||
path = g_build_filename (GTK_DATADIR, "sounds", "freedesktop", "stereo", "suspend-error.oga", NULL);
|
||||
stream = gtk_media_file_new_for_filename (path);
|
||||
gtk_media_stream_set_volume (stream, 1.0);
|
||||
gtk_media_stream_play (stream);
|
||||
|
||||
g_signal_connect (stream, "notify::ended", G_CALLBACK (g_object_unref), NULL);
|
||||
g_free (path);
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_motion (GtkEventControllerMotion *controller,
|
||||
double x,
|
||||
double y,
|
||||
GtkMaze *self)
|
||||
{
|
||||
GskPathPoint point;
|
||||
float distance;
|
||||
|
||||
if (!self->active)
|
||||
return;
|
||||
|
||||
if (gsk_path_get_closest_point (self->path,
|
||||
&GRAPHENE_POINT_INIT (x, y),
|
||||
INFINITY,
|
||||
&point,
|
||||
&distance))
|
||||
{
|
||||
if (distance < MAZE_STROKE_SIZE_ACTIVE / 2.f)
|
||||
return;
|
||||
}
|
||||
|
||||
celebrate (FALSE);
|
||||
|
||||
self->active = FALSE;
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_leave (GtkEventControllerMotion *controller,
|
||||
GtkMaze *self)
|
||||
{
|
||||
if (!self->active)
|
||||
{
|
||||
self->active = TRUE;
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_maze_init (GtkMaze *self)
|
||||
{
|
||||
GtkEventController *controller;
|
||||
|
||||
controller = GTK_EVENT_CONTROLLER (gtk_event_controller_motion_new ());
|
||||
g_signal_connect (controller, "motion", G_CALLBACK (pointer_motion), self);
|
||||
g_signal_connect (controller, "leave", G_CALLBACK (pointer_leave), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), controller);
|
||||
|
||||
self->active = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_maze_set_path (GtkMaze *self,
|
||||
GskPath *path)
|
||||
{
|
||||
g_clear_pointer (&self->path, gsk_path_unref);
|
||||
g_clear_pointer (&self->measure, gsk_path_measure_unref);
|
||||
self->path = gsk_path_ref (path);
|
||||
self->measure = gsk_path_measure_new (path);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gtk_maze_new (GskPath *path,
|
||||
GdkPaintable *background,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
GtkMaze *self;
|
||||
|
||||
self = g_object_new (GTK_TYPE_MAZE, NULL);
|
||||
|
||||
gtk_maze_set_path (self, path);
|
||||
gsk_path_unref (path);
|
||||
self->background = background;
|
||||
if (self->background)
|
||||
{
|
||||
g_signal_connect_swapped (self->background, "invalidate-contents", G_CALLBACK (gtk_widget_queue_draw), self);
|
||||
g_signal_connect_swapped (self->background, "invalidate-size", G_CALLBACK (gtk_widget_queue_resize), self);
|
||||
}
|
||||
self->width = width;
|
||||
self->height = height;
|
||||
|
||||
return GTK_WIDGET (self);
|
||||
}
|
||||
|
||||
static void
|
||||
add_point_to_maze (GtkBitset *maze,
|
||||
GskPathBuilder *builder,
|
||||
guint x,
|
||||
guint y)
|
||||
{
|
||||
gboolean set[4] = { FALSE, FALSE, FALSE, FALSE };
|
||||
guint dir;
|
||||
|
||||
gtk_bitset_add (maze, y * MAZE_WIDTH + x);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
set[0] = set[0] || x == 0 || gtk_bitset_contains (maze, y * MAZE_WIDTH + x - 1);
|
||||
set[1] = set[1] || y == 0 || gtk_bitset_contains (maze, (y - 1) * MAZE_WIDTH + x);
|
||||
set[2] = set[2] || x + 1 == MAZE_WIDTH || gtk_bitset_contains (maze, y * MAZE_WIDTH + x + 1);
|
||||
set[3] = set[3] || y + 1 == MAZE_HEIGHT || gtk_bitset_contains (maze, (y + 1) * MAZE_WIDTH + x);
|
||||
|
||||
if (set[0] && set[1] && set[2] && set[3])
|
||||
return;
|
||||
|
||||
do
|
||||
{
|
||||
dir = g_random_int_range (0, 4);
|
||||
}
|
||||
while (set[dir]);
|
||||
|
||||
switch (dir)
|
||||
{
|
||||
case 0:
|
||||
gsk_path_builder_move_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_line_to (builder, (x - 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
|
||||
add_point_to_maze (maze, builder, x - 1, y);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
gsk_path_builder_move_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_line_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y - 0.5) * MAZE_GRID_SIZE);
|
||||
add_point_to_maze (maze, builder, x, y - 1);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
gsk_path_builder_move_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_line_to (builder, (x + 1.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
|
||||
add_point_to_maze (maze, builder, x + 1, y);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
gsk_path_builder_move_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_line_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 1.5) * MAZE_GRID_SIZE);
|
||||
add_point_to_maze (maze, builder, x, y + 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static GskPath *
|
||||
create_path_for_maze (GtkWidget *widget)
|
||||
{
|
||||
GskPathBuilder *builder;
|
||||
GtkBitset *maze;
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
maze = gtk_bitset_new_empty ();
|
||||
/* make sure the outer lines are unreachable:
|
||||
* Set the full range, then remove the center again. */
|
||||
gtk_bitset_add_range (maze, 0, MAZE_WIDTH * MAZE_HEIGHT);
|
||||
gtk_bitset_remove_rectangle (maze, MAZE_WIDTH + 1, MAZE_WIDTH - 2, MAZE_HEIGHT - 2, MAZE_WIDTH);
|
||||
|
||||
/* Fill the maze */
|
||||
add_point_to_maze (maze, builder, MAZE_WIDTH / 2, MAZE_HEIGHT / 2);
|
||||
|
||||
/* Add start and stop lines */
|
||||
gsk_path_builder_move_to (builder, 1.5 * MAZE_GRID_SIZE, -0.5 * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_line_to (builder, 1.5 * MAZE_GRID_SIZE, 1.5 * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_move_to (builder, (MAZE_WIDTH - 1.5) * MAZE_GRID_SIZE, (MAZE_HEIGHT - 1.5) * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_line_to (builder, (MAZE_WIDTH - 1.5) * MAZE_GRID_SIZE, (MAZE_HEIGHT + 0.5) * MAZE_GRID_SIZE);
|
||||
|
||||
|
||||
gtk_bitset_unref (maze);
|
||||
|
||||
return gsk_path_builder_free_to_path (builder);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_path_maze (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkWidget *maze;
|
||||
GtkMediaStream *stream;
|
||||
GskPath *path;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Follow the maze with the mouse");
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
#if 0
|
||||
stream = gtk_media_file_new_for_resource ("/images/gtk-logo.webm");
|
||||
#else
|
||||
stream = gtk_nuclear_media_stream_new ();
|
||||
#endif
|
||||
gtk_media_stream_play (stream);
|
||||
gtk_media_stream_set_loop (stream, TRUE);
|
||||
|
||||
path = create_path_for_maze (window);
|
||||
|
||||
maze = gtk_maze_new (path,
|
||||
GDK_PAINTABLE (stream),
|
||||
MAZE_WIDTH * MAZE_GRID_SIZE,
|
||||
MAZE_HEIGHT * MAZE_GRID_SIZE);
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), maze);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#include "paintable.h"
|
||||
|
||||
#undef SHOW_CONTROLS
|
||||
|
||||
#define GTK_TYPE_SPINNER_PAINTABLE (gtk_spinner_paintable_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GtkSpinnerPaintable, gtk_spinner_paintable, GTK, SPINNER_PAINTABLE, GObject)
|
||||
|
||||
@@ -56,9 +58,9 @@ gtk_spinner_paintable_get_intrinsic_height (GdkPaintable *paintable)
|
||||
|
||||
static void
|
||||
gtk_spinner_paintable_snapshot (GdkPaintable *paintable,
|
||||
GdkSnapshot *snapshot,
|
||||
double width,
|
||||
double height)
|
||||
GdkSnapshot *snapshot,
|
||||
double width,
|
||||
double height)
|
||||
{
|
||||
GtkSpinnerPaintable *self = GTK_SPINNER_PAINTABLE (paintable);
|
||||
|
||||
@@ -150,6 +152,7 @@ static gboolean
|
||||
add_controls (GskPathOperation op,
|
||||
const graphene_point_t *pts,
|
||||
gsize n_pts,
|
||||
float weight,
|
||||
gpointer data)
|
||||
{
|
||||
GskPathBuilder *builder = data;
|
||||
@@ -166,7 +169,7 @@ add_controls (GskPathOperation op,
|
||||
break;
|
||||
|
||||
case GSK_PATH_QUAD:
|
||||
case GSK_PATH_ARC:
|
||||
case GSK_PATH_CONIC:
|
||||
gsk_path_builder_line_to (builder, pts[1].x, pts[1].y);
|
||||
gsk_path_builder_line_to (builder, pts[2].x, pts[2].y);
|
||||
break;
|
||||
@@ -190,32 +193,21 @@ update_path (GtkSpinnerPaintable *self)
|
||||
{
|
||||
GskPathBuilder *builder;
|
||||
GskPathPoint start, end;
|
||||
GskTransform *t;
|
||||
graphene_point_t p, p0, p1;
|
||||
graphene_point_t p0, p1;
|
||||
float start_angle, end_angle;
|
||||
|
||||
p = GRAPHENE_POINT_INIT (40, 0);
|
||||
start_angle = self->angle;
|
||||
end_angle = fmod (self->angle + 360 * self->completion / 100, 360);
|
||||
|
||||
t = gsk_transform_translate (
|
||||
gsk_transform_rotate (
|
||||
gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (50, 50)),
|
||||
start_angle),
|
||||
&GRAPHENE_POINT_INIT (-50, -50));
|
||||
gsk_transform_transform_point (t, &p, &p0);
|
||||
|
||||
t = gsk_transform_translate (
|
||||
gsk_transform_rotate (
|
||||
gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (50, 50)),
|
||||
end_angle),
|
||||
&GRAPHENE_POINT_INIT (-50, -50));
|
||||
gsk_transform_transform_point (t, &p, &p1);
|
||||
p0 = GRAPHENE_POINT_INIT (50 + 40 * cos (M_PI * start_angle / 180),
|
||||
50 + 40 * sin (M_PI * start_angle / 180));
|
||||
p1 = GRAPHENE_POINT_INIT (50 + 40 * cos (M_PI * end_angle / 180),
|
||||
50 + 40 * sin (M_PI * end_angle / 180));
|
||||
|
||||
g_clear_pointer (&self->path, gsk_path_unref);
|
||||
|
||||
gsk_path_get_closest_point (self->circle, &p0, INFINITY, &start);
|
||||
gsk_path_get_closest_point (self->circle, &p1, INFINITY, &end);
|
||||
gsk_path_get_closest_point (self->circle, &p0, INFINITY, &start, NULL);
|
||||
gsk_path_get_closest_point (self->circle, &p1, INFINITY, &end, NULL);
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_builder_add_segment (builder, self->circle, &start, &end);
|
||||
|
||||
@@ -501,15 +501,13 @@ pointer_motion (GtkEventControllerMotion *controller,
|
||||
GtkPathWidget *self)
|
||||
{
|
||||
GskPathPoint point;
|
||||
graphene_point_t pos;
|
||||
|
||||
if (gsk_path_get_closest_point (self->line_path,
|
||||
&GRAPHENE_POINT_INIT (x, y),
|
||||
INFINITY,
|
||||
&point))
|
||||
&point,
|
||||
NULL))
|
||||
{
|
||||
gsk_path_point_get_position (&point, self->line_path, &pos);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
<property name="lower">0</property>
|
||||
<property name="upper">5000</property>
|
||||
<property name="value">500</property>
|
||||
<property name="step-increment">1</property>
|
||||
<property name="page-increment">10</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/* Pickers and Launchers
|
||||
* #Keywords: GtkColorDialog, GtkFontDialog, GtkFileDialog, GtkFileLauncher, GtkUriLauncher
|
||||
* #Keywords: GtkColorDialog, GtkFontDialog, GtkFileDialog, GtkPrintDialog, GtkFileLauncher, GtkUriLauncher
|
||||
*
|
||||
* The dialogs are mainly intended for use in preference dialogs.
|
||||
* They allow to select colors, fonts and applications.
|
||||
* They allow to select colors, fonts and files. There is also a
|
||||
* print dialog.
|
||||
*
|
||||
* The launchers let you open files or URIs in applications that
|
||||
* can handle them.
|
||||
@@ -11,11 +12,13 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static GtkWidget *app_picker;
|
||||
static GtkWidget *print_button;
|
||||
|
||||
static void
|
||||
set_file (GFile *file,
|
||||
gpointer data)
|
||||
{
|
||||
GFileInfo *info;
|
||||
char *name;
|
||||
|
||||
if (!file)
|
||||
@@ -31,6 +34,13 @@ set_file (GFile *file,
|
||||
|
||||
gtk_widget_set_sensitive (app_picker, TRUE);
|
||||
g_object_set_data_full (G_OBJECT (app_picker), "file", g_object_ref (file), g_object_unref);
|
||||
|
||||
info = g_file_query_info (file, "standard::content-type", 0, NULL, NULL);
|
||||
if (strcmp (g_file_info_get_content_type (info), "application/pdf") == 0)
|
||||
{
|
||||
gtk_widget_set_sensitive (print_button, TRUE);
|
||||
g_object_set_data_full (G_OBJECT (print_button), "file", g_object_ref (file), g_object_unref);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -47,6 +57,10 @@ file_opened (GObject *source,
|
||||
{
|
||||
g_print ("%s\n", error->message);
|
||||
g_error_free (error);
|
||||
gtk_widget_set_sensitive (app_picker, FALSE);
|
||||
g_object_set_data (G_OBJECT (app_picker), "file", NULL);
|
||||
gtk_widget_set_sensitive (print_button, FALSE);
|
||||
g_object_set_data (G_OBJECT (print_button), "file", NULL);
|
||||
}
|
||||
|
||||
set_file (file, data);
|
||||
@@ -114,6 +128,53 @@ open_app (GtkButton *picker)
|
||||
g_object_unref (launcher);
|
||||
}
|
||||
|
||||
static void
|
||||
print_file_done (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GtkPrintDialog *dialog = GTK_PRINT_DIALOG (source);
|
||||
GError *error = NULL;
|
||||
GCancellable *cancellable;
|
||||
unsigned int id;
|
||||
|
||||
cancellable = g_task_get_cancellable (G_TASK (result));
|
||||
id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (cancellable), "timeout"));
|
||||
if (id)
|
||||
g_source_remove (id);
|
||||
|
||||
if (!gtk_print_dialog_print_file_finish (dialog, result, &error))
|
||||
{
|
||||
g_print ("%s\n", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_file (GtkButton *picker)
|
||||
{
|
||||
GtkWindow *parent = GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (picker)));
|
||||
GtkPrintDialog *dialog;
|
||||
GCancellable *cancellable;
|
||||
GFile *file;
|
||||
unsigned int id;
|
||||
|
||||
file = G_FILE (g_object_get_data (G_OBJECT (picker), "file"));
|
||||
dialog = gtk_print_dialog_new ();
|
||||
|
||||
cancellable = g_cancellable_new ();
|
||||
|
||||
id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
|
||||
20,
|
||||
abort_mission, g_object_ref (cancellable), g_object_unref);
|
||||
g_object_set_data (G_OBJECT (cancellable), "timeout", GUINT_TO_POINTER (id));
|
||||
|
||||
gtk_print_dialog_print_file (dialog, parent, NULL, file, cancellable, print_file_done, NULL);
|
||||
|
||||
g_object_unref (cancellable);
|
||||
g_object_unref (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
open_uri_done (GObject *source,
|
||||
GAsyncResult *result,
|
||||
@@ -234,8 +295,14 @@ do_pickers (GtkWidget *do_widget)
|
||||
gtk_widget_set_sensitive (app_picker, FALSE);
|
||||
g_signal_connect (app_picker, "clicked", G_CALLBACK (open_app), NULL);
|
||||
gtk_box_append (GTK_BOX (picker), app_picker);
|
||||
gtk_grid_attach (GTK_GRID (table), picker, 1, 2, 1, 1);
|
||||
|
||||
print_button = gtk_button_new_from_icon_name ("printer-symbolic");
|
||||
gtk_widget_set_tooltip_text (print_button, "Print file");
|
||||
gtk_widget_set_sensitive (print_button, FALSE);
|
||||
g_signal_connect (print_button, "clicked", G_CALLBACK (print_file), NULL);
|
||||
gtk_box_append (GTK_BOX (picker), print_button);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (table), picker, 1, 2, 1, 1);
|
||||
|
||||
label = gtk_label_new ("URI:");
|
||||
gtk_widget_set_halign (label, GTK_ALIGN_START);
|
||||
|
||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 844 B After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 823 B After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
@@ -147,6 +147,19 @@ Creates a node like `gsk_cross_fade_node_new()` with the given properties.
|
||||
|
||||
Creates a node like `gsk_debug_node_new()` with the given properties.
|
||||
|
||||
### fill
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| --------- | --------------- | ---------------------- | ----------- |
|
||||
| child | `<node>` | *see below* | always |
|
||||
| path | `<string>` | "" | always |
|
||||
| fill-rule | `<fill-rule>` | winding | always |
|
||||
|
||||
Creates a node like `gsk_fill_node_new()` with the given properties.
|
||||
|
||||
The default child node is the default color node, but created with the
|
||||
bounds of the path.
|
||||
|
||||
### glshader
|
||||
|
||||
| property | syntax | default | printed |
|
||||
@@ -289,6 +302,24 @@ Creates a node like `gsk_rounded_clip_node_new()` with the given properties.
|
||||
|
||||
Creates a node like `gsk_shadow_node_new()` with the given properties.
|
||||
|
||||
### stroke
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| ----------- | ------------------ | ----------------- | ----------- |
|
||||
| child | `<node>` | *see below* | always |
|
||||
| path | `<string>` | "" | always |
|
||||
| line-width | `<number>` | 0 | non-default |
|
||||
| line-cap | `<line-cap>` | butt | always |
|
||||
| line-join | `<line-join>` | miter | always |
|
||||
| miter-limit | `<number>` | 4 | non-default |
|
||||
| dash | `<number>{+}|none` | none | non-default |
|
||||
| dash-offset | `<number>` | 0 | non-default |
|
||||
|
||||
Creates a node like `gsk_stroke_node_new()` with the given properties.
|
||||
|
||||
The default child node is the default color node, but created with the
|
||||
stroke bounds of the path.
|
||||
|
||||
### text
|
||||
|
||||
| property | syntax | default | printed |
|
||||
|
||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 985 B After Width: | Height: | Size: 1019 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 844 B After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 823 B After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
@@ -15,6 +15,7 @@ SYNOPSIS
|
||||
| **gtk4-path-tool** decompose [OPTIONS...] <PATH>
|
||||
| **gtk4-path-tool** show [OPTIONS...] <PATH>
|
||||
| **gtk4-path-tool** render [OPTIONS...] <PATH>
|
||||
| **gtk4-path-tool** reverse [OPTIONS...] <PATH>
|
||||
| **gtk4-path-tool** info [OPTIONS...] <PATH>
|
||||
|
||||
DESCRIPTION
|
||||
@@ -54,6 +55,22 @@ Showing
|
||||
The ``show`` command displays the given path in a window. The interior
|
||||
of the path is filled.
|
||||
|
||||
``--fill``
|
||||
|
||||
Fill the path (this is the default).
|
||||
|
||||
``--stroke``
|
||||
|
||||
Stroke the path instead of filling it.
|
||||
|
||||
``--points``
|
||||
|
||||
Show points on the path.
|
||||
|
||||
``--controls``
|
||||
|
||||
Show control points.
|
||||
|
||||
``--fill-rule=VALUE``
|
||||
|
||||
The fill rule that is used to determine what areas are inside the path.
|
||||
@@ -69,13 +86,10 @@ of the path is filled.
|
||||
The color that is used to render the background behind the path.
|
||||
If not specified, white is used.
|
||||
|
||||
``--fill``
|
||||
``--point-color=COLOR``
|
||||
|
||||
Fill the path (this is the default).
|
||||
|
||||
``--stroke``
|
||||
|
||||
Stroke the path instead of filling it.
|
||||
The color that is used to render the points.
|
||||
If not specified, red is used.
|
||||
|
||||
``--line-width=VALUE``
|
||||
|
||||
@@ -118,6 +132,22 @@ Rendering
|
||||
The ``render`` command renders the given path as a PNG image.
|
||||
The interior of the path is filled.
|
||||
|
||||
``--fill``
|
||||
|
||||
Fill the path (this is the default).
|
||||
|
||||
``--stroke``
|
||||
|
||||
Stroke the path instead of filling it.
|
||||
|
||||
``--points``
|
||||
|
||||
Show points on the path.
|
||||
|
||||
``--controls``
|
||||
|
||||
Show control points.
|
||||
|
||||
``--fill-rule=VALUE``
|
||||
|
||||
The fill rule that is used to determine what areas are inside the path.
|
||||
@@ -133,19 +163,16 @@ The interior of the path is filled.
|
||||
The color that is used to render the background behind the path.
|
||||
If not specified, white is used.
|
||||
|
||||
``--point-color=COLOR``
|
||||
|
||||
The color that is used to render the points.
|
||||
If not specified, red is used.
|
||||
|
||||
``--output-file=FILE``
|
||||
|
||||
The file to save the PNG image to.
|
||||
If not specified, "path.png" is used.
|
||||
|
||||
``--fill``
|
||||
|
||||
Fill the path (this is the default).
|
||||
|
||||
``--stroke``
|
||||
|
||||
Stroke the path instead of filling it.
|
||||
|
||||
``--line-width=VALUE``
|
||||
|
||||
The line width to use for the stroke. ``VALUE`` must be a positive number.
|
||||
@@ -181,6 +208,12 @@ The interior of the path is filled.
|
||||
The offset into the dash pattern where dashing should begin.
|
||||
The default value is 0.
|
||||
|
||||
Reversing
|
||||
^^^^^^^^^
|
||||
|
||||
The ``reverse`` command changes the direction of the path. The resulting
|
||||
paths starts where the original path ends.
|
||||
|
||||
Info
|
||||
^^^^
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
@@ -263,7 +263,7 @@ gdk_parse_debug_var (const char *variable,
|
||||
if (debug_enabled || keys[i].always_enabled)
|
||||
fprintf (stderr, " %s%*s%s\n", keys[i].key, (int)(max_width - strlen (keys[i].key)), " ", keys[i].help);
|
||||
}
|
||||
fprintf (stderr, " %s%*s%s\n", "all", max_width - 3, " ", "Enable all values");
|
||||
fprintf (stderr, " %s%*s%s\n", "all", max_width - 3, " ", "Enable all values. Other given values are subtracted");
|
||||
fprintf (stderr, " %s%*s%s\n", "help", max_width - 4, " ", "Print this help");
|
||||
fprintf (stderr, "\nMultiple values can be given, separated by : or space.\n");
|
||||
}
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
#include <gdk/gdkdevicetool.h>
|
||||
#include <gdk/gdkdisplay.h>
|
||||
#include <gdk/gdkdisplaymanager.h>
|
||||
#include <gdk/gdkdmabuftexture.h>
|
||||
#include <gdk/gdkdmabuftexturebuilder.h>
|
||||
#include <gdk/gdkdrag.h>
|
||||
#include <gdk/gdkdragsurface.h>
|
||||
#include <gdk/gdkdragsurfacesize.h>
|
||||
|
||||
@@ -82,6 +82,18 @@ gdk_array(init) (GdkArray *self)
|
||||
#endif
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline gsize
|
||||
gdk_array(get_capacity) (const GdkArray *self)
|
||||
{
|
||||
return self->end_allocation - self->start;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline gsize
|
||||
gdk_array(get_size) (const GdkArray *self)
|
||||
{
|
||||
return self->end - self->start;
|
||||
}
|
||||
|
||||
static inline void
|
||||
gdk_array(free_elements) (_T_ *start,
|
||||
_T_ *end)
|
||||
@@ -110,6 +122,38 @@ gdk_array(clear) (GdkArray *self)
|
||||
gdk_array(init) (self);
|
||||
}
|
||||
|
||||
/*
|
||||
* gdk_array_steal:
|
||||
* @self: the array
|
||||
*
|
||||
* Steals all data in the array and clears the array.
|
||||
*
|
||||
* If you need to know the size of the data, you should query it
|
||||
* beforehand.
|
||||
*
|
||||
* Returns: The array's data
|
||||
**/
|
||||
G_GNUC_UNUSED static inline _T_ *
|
||||
gdk_array(steal) (GdkArray *self)
|
||||
{
|
||||
_T_ *result;
|
||||
|
||||
#ifdef GDK_ARRAY_PREALLOC
|
||||
if (self->start == self->preallocated)
|
||||
{
|
||||
gsize size = GDK_ARRAY_REAL_SIZE (gdk_array(get_size) (self));
|
||||
result = g_new (_T_, size);
|
||||
memcpy (result, self->preallocated, sizeof (_T_) * size);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
result = self->start;
|
||||
|
||||
gdk_array(init) (self);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline _T_ *
|
||||
gdk_array(get_data) (const GdkArray *self)
|
||||
{
|
||||
@@ -123,18 +167,6 @@ gdk_array(index) (const GdkArray *self,
|
||||
return self->start + pos;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline gsize
|
||||
gdk_array(get_capacity) (const GdkArray *self)
|
||||
{
|
||||
return self->end_allocation - self->start;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline gsize
|
||||
gdk_array(get_size) (const GdkArray *self)
|
||||
{
|
||||
return self->end - self->start;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline gboolean
|
||||
gdk_array(is_empty) (const GdkArray *self)
|
||||
{
|
||||
@@ -151,7 +183,7 @@ gdk_array(reserve) (GdkArray *self,
|
||||
return;
|
||||
|
||||
size = gdk_array(get_size) (self);
|
||||
new_size = 1 << g_bit_storage (MAX (GDK_ARRAY_REAL_SIZE (n), 16) - 1);
|
||||
new_size = ((gsize) 1) << g_bit_storage (MAX (GDK_ARRAY_REAL_SIZE (n), 16) - 1);
|
||||
|
||||
#ifdef GDK_ARRAY_PREALLOC
|
||||
if (self->start == self->preallocated)
|
||||
@@ -286,3 +318,5 @@ gdk_array(get) (const GdkArray *self,
|
||||
#undef GDK_ARRAY_TYPE_NAME
|
||||
#undef GDK_ARRAY_NO_MEMSET
|
||||
#endif
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "gdkmonitorprivate.h"
|
||||
#include "gdkrectangle.h"
|
||||
#include "gdkvulkancontext.h"
|
||||
#include "gdkdmabuftextureprivate.h"
|
||||
|
||||
#ifdef HAVE_EGL
|
||||
#include <epoxy/egl.h>
|
||||
@@ -404,6 +405,8 @@ gdk_display_finalize (GObject *object)
|
||||
|
||||
g_list_free_full (display->seats, g_object_unref);
|
||||
|
||||
g_free (display->egl_dmabuf_formats);
|
||||
|
||||
G_OBJECT_CLASS (gdk_display_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@@ -473,8 +476,7 @@ gdk_display_get_event (GdkDisplay *display)
|
||||
* @display: a `GdkDisplay`
|
||||
* @event: (transfer none): a `GdkEvent`
|
||||
*
|
||||
* Appends the given event onto the front of the event
|
||||
* queue for @display.
|
||||
* Adds the given event to the event queue for @display.
|
||||
*
|
||||
* Deprecated: 4.10: This function is only useful in very
|
||||
* special situations and should not be used by applications.
|
||||
@@ -1260,6 +1262,68 @@ gdk_display_create_vulkan_context (GdkDisplay *self,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* To support a drm format, we must be able to import it into GL
|
||||
* using the relevant EGL extensions, and download it into a memory
|
||||
* texture, possibly doing format conversion with shaders (in GSK).
|
||||
*/
|
||||
static void
|
||||
init_dmabuf_formats (GdkDisplay *self)
|
||||
{
|
||||
GdkDisplayPrivate *priv = gdk_display_get_instance_private (self);
|
||||
|
||||
if (priv->egl_display != EGL_NO_DISPLAY)
|
||||
{
|
||||
int num_formats;
|
||||
int *formats;
|
||||
GArray *array;
|
||||
|
||||
eglQueryDmaBufFormatsEXT (priv->egl_display, 0, NULL, &num_formats);
|
||||
formats = g_new (int, num_formats);
|
||||
eglQueryDmaBufFormatsEXT (priv->egl_display, num_formats, formats, &num_formats);
|
||||
|
||||
array = g_array_new (FALSE, FALSE, sizeof (GdkDmabufFormat));
|
||||
|
||||
for (int i = 0; i < num_formats; i++)
|
||||
{
|
||||
int num_modifiers;
|
||||
uint64_t *modifiers;
|
||||
unsigned int *external_only;
|
||||
|
||||
if (!gdk_dmabuf_texture_may_support ((unsigned int)formats[i]))
|
||||
continue;
|
||||
|
||||
eglQueryDmaBufModifiersEXT (priv->egl_display, formats[i], 0, NULL, NULL, &num_modifiers);
|
||||
modifiers = g_new (uint64_t, num_modifiers);
|
||||
external_only = g_new (unsigned int, num_modifiers);
|
||||
eglQueryDmaBufModifiersEXT (priv->egl_display, formats[i], num_modifiers, modifiers, external_only, &num_modifiers);
|
||||
|
||||
if (num_modifiers == 0)
|
||||
g_array_append_val (array, ((GdkDmabufFormat){ formats[i], 0 }));
|
||||
else
|
||||
{
|
||||
for (int j = 0; j < num_modifiers; j++)
|
||||
g_array_append_val (array, ((GdkDmabufFormat){ formats[i], modifiers[j] }));
|
||||
}
|
||||
|
||||
g_free (modifiers);
|
||||
}
|
||||
|
||||
g_free (formats);
|
||||
|
||||
self->egl_dmabuf_n_formats = array->len;
|
||||
self->egl_dmabuf_formats = (GdkDmabufFormat *) g_array_free (array, FALSE);
|
||||
}
|
||||
|
||||
GDK_DEBUG (MISC, "Supported EGL dmabuf formats: (%lu)", self->egl_dmabuf_n_formats);
|
||||
for (gsize i = 0; i < self->egl_dmabuf_n_formats; i++)
|
||||
{
|
||||
uint32_t f = self->egl_dmabuf_formats[i].fourcc;
|
||||
uint64_t m = self->egl_dmabuf_formats[i].modifier;
|
||||
|
||||
GDK_DEBUG (MISC, " %c%c%c%c:%#lx", f & 0xff, (f >> 8) & 0xff, (f >> 16) & 0xff, (f >> 24) & 0xff, m);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_display_init_gl (GdkDisplay *self)
|
||||
{
|
||||
@@ -1301,6 +1365,10 @@ gdk_display_init_gl (GdkDisplay *self)
|
||||
gdk_gl_backend_use (GDK_GL_CONTEXT_GET_CLASS (context)->backend_type);
|
||||
|
||||
gdk_profiler_end_mark (before, "initialize OpenGL", NULL);
|
||||
|
||||
gdk_gl_context_make_current (context);
|
||||
|
||||
init_dmabuf_formats (self);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1825,6 +1893,43 @@ gdk_display_get_egl_display (GdkDisplay *self)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* GdkDmabufFormat:
|
||||
* @fourcc: the format code
|
||||
* @modifiers: the format modifier
|
||||
*
|
||||
* The `GdkDmabufFormat` struct represents a dma-buf format
|
||||
* as defined in the `drm_fourcc.h` header.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
|
||||
/**
|
||||
* gdk_display_get_dmabuf_formats:
|
||||
* @display: a `GdkDisplay`
|
||||
* @n_formats: return location for the number of formats
|
||||
*
|
||||
* Returns the dma-buf formats that are supported on this display.
|
||||
*
|
||||
* Note that GTK uses EGL to convert some formats, so the list
|
||||
* of supported formats depends on the GL API that is used on
|
||||
* the display.
|
||||
*
|
||||
* Returns: (transfer none): an array of `GdkDmabufFormat` structs.
|
||||
* The length of the array is returned in @n_formats
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
const GdkDmabufFormat *
|
||||
gdk_display_get_dmabuf_formats (GdkDisplay *display,
|
||||
gsize *n_formats)
|
||||
{
|
||||
gdk_display_prepare_gl (display, NULL);
|
||||
|
||||
*n_formats = display->egl_dmabuf_n_formats;
|
||||
return display->egl_dmabuf_formats;
|
||||
}
|
||||
|
||||
GdkDebugFlags
|
||||
gdk_display_get_debug_flags (GdkDisplay *display)
|
||||
{
|
||||
|
||||
@@ -134,6 +134,17 @@ gboolean gdk_display_get_setting (GdkDisplay *display,
|
||||
const char *name,
|
||||
GValue *value);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t fourcc;
|
||||
uint64_t modifier;
|
||||
} GdkDmabufFormat;
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
const GdkDmabufFormat *
|
||||
gdk_display_get_dmabuf_formats (GdkDisplay *display,
|
||||
gsize *n_formats);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkDisplay, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -113,6 +113,9 @@ struct _GdkDisplay
|
||||
guint have_egl_buffer_age : 1;
|
||||
guint have_egl_no_config_context : 1;
|
||||
guint have_egl_pixel_format_float : 1;
|
||||
|
||||
GdkDmabufFormat *egl_dmabuf_formats;
|
||||
gsize egl_dmabuf_n_formats;
|
||||
};
|
||||
|
||||
struct _GdkDisplayClass
|
||||
|
||||
@@ -0,0 +1,397 @@
|
||||
/* gdkdmabuftexture.c
|
||||
*
|
||||
* Copyright 2023 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gdkdmabuftextureprivate.h"
|
||||
|
||||
#ifndef __linux__
|
||||
|
||||
GType
|
||||
gdk_dmabuf_texture_get_type (void)
|
||||
{
|
||||
return G_TYPE_INVALID;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include "gdkdisplayprivate.h"
|
||||
#include "gdkmemoryformatprivate.h"
|
||||
#include "gdkmemorytextureprivate.h"
|
||||
#include <gdk/gdkglcontext.h>
|
||||
#include <gdk/gdkgltexturebuilder.h>
|
||||
#include <gdk/gdktexturedownloader.h>
|
||||
#include <gsk/gsk.h>
|
||||
#include <gsk/gl/gskglrenderer.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <epoxy/egl.h>
|
||||
|
||||
/**
|
||||
* GdkDmabufTexture:
|
||||
*
|
||||
* A `GdkTexture` representing a dma-buf object.
|
||||
*
|
||||
* To create a `GdkDmabufTexture`, use the auxiliary
|
||||
* [class@Gdk.DmabufTextureBuilder] object.
|
||||
*
|
||||
* Dma-buf textures can only be created on Linux.
|
||||
*/
|
||||
|
||||
struct _GdkDmabufTexture
|
||||
{
|
||||
GdkTexture parent_instance;
|
||||
|
||||
GdkDisplay *display;
|
||||
|
||||
unsigned int fourcc;
|
||||
guint64 modifier;
|
||||
|
||||
unsigned int n_planes;
|
||||
|
||||
/* Per-plane properties */
|
||||
int fds[4];
|
||||
unsigned int strides[4];
|
||||
unsigned int offsets[4];
|
||||
|
||||
GDestroyNotify destroy;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
struct _GdkDmabufTextureClass
|
||||
{
|
||||
GdkTextureClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GdkDmabufTexture, gdk_dmabuf_texture, GDK_TYPE_TEXTURE)
|
||||
|
||||
static void
|
||||
gdk_dmabuf_texture_dispose (GObject *object)
|
||||
{
|
||||
GdkDmabufTexture *self = GDK_DMABUF_TEXTURE (object);
|
||||
|
||||
if (self->destroy)
|
||||
self->destroy (self->data);
|
||||
|
||||
G_OBJECT_CLASS (gdk_dmabuf_texture_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
typedef struct _GdkDrmFormatInfo GdkDrmFormatInfo;
|
||||
struct _GdkDrmFormatInfo
|
||||
{
|
||||
unsigned int fourcc;
|
||||
GdkMemoryFormat memory_format;
|
||||
gboolean requires_gl;
|
||||
};
|
||||
|
||||
static GdkDrmFormatInfo supported_formats[] = {
|
||||
{ DRM_FORMAT_RGB888, GDK_MEMORY_R8G8B8, FALSE },
|
||||
{ DRM_FORMAT_BGR888, GDK_MEMORY_B8G8R8, FALSE },
|
||||
{ DRM_FORMAT_ARGB8888, GDK_MEMORY_A8R8G8B8_PREMULTIPLIED, FALSE },
|
||||
{ DRM_FORMAT_RGBA8888, GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, FALSE },
|
||||
{ DRM_FORMAT_BGRA8888, GDK_MEMORY_B8G8R8A8_PREMULTIPLIED, FALSE },
|
||||
{ DRM_FORMAT_ABGR16161616F, GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, FALSE },
|
||||
{ DRM_FORMAT_YUYV, GDK_MEMORY_DEFAULT, TRUE },
|
||||
{ DRM_FORMAT_NV12, GDK_MEMORY_DEFAULT, TRUE },
|
||||
{ DRM_FORMAT_P010, GDK_MEMORY_R16G16B16A16_PREMULTIPLIED, TRUE },
|
||||
{ DRM_FORMAT_YUV420, GDK_MEMORY_DEFAULT, TRUE },
|
||||
};
|
||||
|
||||
static GdkDrmFormatInfo *
|
||||
get_drm_format_info (unsigned int fourcc)
|
||||
{
|
||||
for (int i = 0; i < G_N_ELEMENTS (supported_formats); i++)
|
||||
{
|
||||
if (supported_formats[i].fourcc == fourcc)
|
||||
return &supported_formats[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_dmabuf_texture_may_support (unsigned int fourcc)
|
||||
{
|
||||
return get_drm_format_info (fourcc) != NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
do_indirect_download (GdkDmabufTexture *self,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
GskRenderer *renderer;
|
||||
int width, height;
|
||||
GskRenderNode *node;
|
||||
GdkTexture *gl_texture;
|
||||
GdkTextureDownloader *downloader;
|
||||
GError *error = NULL;
|
||||
|
||||
GDK_DEBUG (MISC, "Using gsk_renderer_render_texture import for downloading a dmabuf");
|
||||
|
||||
g_assert (GDK_IS_DISPLAY (self->display));
|
||||
g_assert (GDK_IS_GL_CONTEXT (gdk_display_get_gl_context (self->display)));
|
||||
|
||||
renderer = gsk_gl_renderer_new ();
|
||||
if (!gsk_renderer_realize (renderer, NULL, &error))
|
||||
{
|
||||
g_warning ("Failed to realize GL renderer: %s", error->message);
|
||||
g_error_free (error);
|
||||
g_object_unref (renderer);
|
||||
return;
|
||||
}
|
||||
|
||||
width = gdk_texture_get_width (GDK_TEXTURE (self));
|
||||
height = gdk_texture_get_height (GDK_TEXTURE (self));
|
||||
|
||||
node = gsk_texture_node_new (GDK_TEXTURE (self), &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gl_texture = gsk_renderer_render_texture (renderer, node, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gsk_render_node_unref (node);
|
||||
|
||||
gsk_renderer_unrealize (renderer);
|
||||
g_object_unref (renderer);
|
||||
|
||||
downloader = gdk_texture_downloader_new (gl_texture);
|
||||
|
||||
gdk_texture_downloader_set_format (downloader, format);
|
||||
|
||||
gdk_texture_downloader_download_into (downloader, data, stride);
|
||||
|
||||
gdk_texture_downloader_free (downloader);
|
||||
g_object_unref (gl_texture);
|
||||
}
|
||||
|
||||
static void
|
||||
do_direct_download (GdkDmabufTexture *self,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
gsize size;
|
||||
unsigned int height;
|
||||
gsize src_stride;
|
||||
guchar *src_data;
|
||||
int bpp;
|
||||
|
||||
GDK_DEBUG (MISC, "Using mmap() and memcpy() for downloading a dmabuf");
|
||||
|
||||
height = gdk_texture_get_height (GDK_TEXTURE (self));
|
||||
bpp = gdk_memory_format_bytes_per_pixel (gdk_texture_get_format (GDK_TEXTURE (self)));
|
||||
|
||||
src_stride = self->strides[0];
|
||||
size = self->strides[0] * height;
|
||||
|
||||
if (ioctl (self->fds[0], DMA_BUF_IOCTL_SYNC, &(struct dma_buf_sync) { DMA_BUF_SYNC_START|DMA_BUF_SYNC_READ }) < 0)
|
||||
g_warning ("Failed to sync dma-buf: %s", g_strerror (errno));
|
||||
|
||||
src_data = mmap (NULL, size, PROT_READ, MAP_SHARED, self->fds[0], self->offsets[0]);
|
||||
|
||||
if (stride == src_stride)
|
||||
memcpy (data, src_data, size);
|
||||
else
|
||||
{
|
||||
for (unsigned int i = 0; i < height; i++)
|
||||
memcpy (data + i * stride, src_data + i * src_stride, height * bpp);
|
||||
}
|
||||
|
||||
if (ioctl (self->fds[0], DMA_BUF_IOCTL_SYNC, &(struct dma_buf_sync) { DMA_BUF_SYNC_END|DMA_BUF_SYNC_READ }) < 0)
|
||||
g_warning ("Failed to sync dma-buf: %s", g_strerror (errno));
|
||||
|
||||
munmap (src_data, size);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_dmabuf_texture_download (GdkTexture *texture,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
GdkDmabufTexture *self = GDK_DMABUF_TEXTURE (texture);
|
||||
GdkMemoryFormat src_format = gdk_texture_get_format (texture);
|
||||
GdkDrmFormatInfo *info;
|
||||
|
||||
info = get_drm_format_info (self->fourcc);
|
||||
|
||||
if (info->requires_gl || self->n_planes > 1)
|
||||
do_indirect_download (self, format, data, stride);
|
||||
else if (format == src_format)
|
||||
do_direct_download (self, data, stride);
|
||||
else
|
||||
{
|
||||
unsigned int width, height;
|
||||
guchar *src_data;
|
||||
gsize src_stride;
|
||||
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
|
||||
src_stride = self->strides[0];
|
||||
src_data = g_new (guchar, src_stride * height);
|
||||
|
||||
do_direct_download (self, src_data, src_stride);
|
||||
|
||||
gdk_memory_convert (data, stride, format,
|
||||
src_data, src_stride, src_format,
|
||||
width, height);
|
||||
|
||||
g_free (src_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_dmabuf_texture_class_init (GdkDmabufTextureClass *klass)
|
||||
{
|
||||
GdkTextureClass *texture_class = GDK_TEXTURE_CLASS (klass);
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
texture_class->download = gdk_dmabuf_texture_download;
|
||||
|
||||
gobject_class->dispose = gdk_dmabuf_texture_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_dmabuf_texture_init (GdkDmabufTexture *self)
|
||||
{
|
||||
self->fds[0] = self->fds[1] = self->fds[2] = self->fds[3] = -1;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
display_supports_format (GdkDisplay *display,
|
||||
unsigned int fourcc,
|
||||
guint64 modifier)
|
||||
{
|
||||
const GdkDmabufFormat *formats;
|
||||
gsize n_formats;
|
||||
|
||||
if (!display)
|
||||
return FALSE;
|
||||
|
||||
formats = gdk_display_get_dmabuf_formats (display, &n_formats);
|
||||
|
||||
for (gsize i = 0; i < n_formats; i++)
|
||||
{
|
||||
if (formats[i].fourcc == fourcc &&
|
||||
formats[i].modifier == modifier)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GdkTexture *
|
||||
gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
|
||||
GDestroyNotify destroy,
|
||||
gpointer data)
|
||||
{
|
||||
GdkDmabufTexture *self;
|
||||
GdkTexture *update_texture;
|
||||
GdkDisplay *display = gdk_dmabuf_texture_builder_get_display (builder);
|
||||
uint32_t fourcc = gdk_dmabuf_texture_builder_get_fourcc (builder);
|
||||
uint64_t modifier = gdk_dmabuf_texture_builder_get_modifier (builder);
|
||||
unsigned int n_planes = gdk_dmabuf_texture_builder_get_n_planes (builder);
|
||||
GdkDrmFormatInfo *info;
|
||||
|
||||
info = get_drm_format_info (fourcc);
|
||||
|
||||
if (!info ||
|
||||
((info->requires_gl || n_planes > 1) && !display_supports_format (display, fourcc, modifier)))
|
||||
{
|
||||
g_warning ("Unsupported dmabuf format %c%c%c%c:%#lx",
|
||||
fourcc & 0xff, (fourcc >> 8) & 0xff, (fourcc >> 16) & 0xff, (fourcc >> 24) & 0xff, modifier);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GDK_DEBUG (MISC, "Dmabuf texture in format %c%c%c%c:%#lx",
|
||||
fourcc & 0xff, (fourcc >> 8) & 0xff, (fourcc >> 16) & 0xff, (fourcc >> 24) & 0xff, modifier);
|
||||
|
||||
self = g_object_new (GDK_TYPE_DMABUF_TEXTURE,
|
||||
"width", gdk_dmabuf_texture_builder_get_width (builder),
|
||||
"height", gdk_dmabuf_texture_builder_get_height (builder),
|
||||
NULL);
|
||||
|
||||
GDK_TEXTURE (self)->format = info->memory_format;
|
||||
|
||||
g_set_object (&self->display, display);
|
||||
|
||||
self->fourcc = fourcc;
|
||||
self->modifier = modifier;
|
||||
self->n_planes = n_planes;
|
||||
|
||||
memcpy (self->fds, gdk_dmabuf_texture_builder_get_fds (builder), sizeof (int) * 4);
|
||||
memcpy (self->strides, gdk_dmabuf_texture_builder_get_strides (builder), sizeof (unsigned int) * 4);
|
||||
memcpy (self->offsets, gdk_dmabuf_texture_builder_get_offsets (builder), sizeof (unsigned int) * 4);
|
||||
|
||||
update_texture = gdk_dmabuf_texture_builder_get_update_texture (builder);
|
||||
if (update_texture)
|
||||
{
|
||||
cairo_region_t *update_region = gdk_dmabuf_texture_builder_get_update_region (builder);
|
||||
if (update_region)
|
||||
{
|
||||
update_region = cairo_region_copy (update_region);
|
||||
cairo_region_intersect_rectangle (update_region,
|
||||
&(cairo_rectangle_int_t) {
|
||||
0, 0,
|
||||
update_texture->width, update_texture->height
|
||||
});
|
||||
gdk_texture_set_diff (GDK_TEXTURE (self), update_texture, update_region);
|
||||
}
|
||||
}
|
||||
|
||||
return GDK_TEXTURE (self);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
gdk_dmabuf_texture_get_fourcc (GdkDmabufTexture *texture)
|
||||
{
|
||||
return texture->fourcc;
|
||||
}
|
||||
|
||||
guint64
|
||||
gdk_dmabuf_texture_get_modifier (GdkDmabufTexture *texture)
|
||||
{
|
||||
return texture->modifier;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
gdk_dmabuf_texture_get_n_planes (GdkDmabufTexture *texture)
|
||||
{
|
||||
return texture->n_planes;
|
||||
}
|
||||
|
||||
int *
|
||||
gdk_dmabuf_texture_get_fds (GdkDmabufTexture *texture)
|
||||
{
|
||||
return texture->fds;
|
||||
}
|
||||
|
||||
unsigned int *
|
||||
gdk_dmabuf_texture_get_strides (GdkDmabufTexture *texture)
|
||||
{
|
||||
return texture->strides;
|
||||
}
|
||||
|
||||
unsigned int *
|
||||
gdk_dmabuf_texture_get_offsets (GdkDmabufTexture *texture)
|
||||
{
|
||||
return texture->offsets;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
@@ -0,0 +1,43 @@
|
||||
/* gdkdmabuftexture.h
|
||||
*
|
||||
* Copyright 2023 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gdk/gdk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdktypes.h>
|
||||
#include <gdk/gdktexture.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDK_TYPE_DMABUF_TEXTURE (gdk_dmabuf_texture_get_type ())
|
||||
|
||||
#define GDK_DMABUF_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_DMABUF_TEXTURE, GdkDmabufTexture))
|
||||
#define GDK_IS_DMABUF_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_DMABUF_TEXTURE))
|
||||
|
||||
typedef struct _GdkDmabufTexture GdkDmabufTexture;
|
||||
typedef struct _GdkDmabufTextureClass GdkDmabufTextureClass;
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GType gdk_dmabuf_texture_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkDmabufTexture, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||