Compare commits
280 Commits
wip/baeder
...
theme-load
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
979e3cd685 | ||
|
|
4cfde0bdc8 | ||
|
|
872dd9856b | ||
|
|
df0648bd74 | ||
|
|
dbd20a6ba6 | ||
|
|
bc64f7d815 | ||
|
|
b3ff4154ec | ||
|
|
879a0c118d | ||
|
|
cb51699098 | ||
|
|
d91f04eefd | ||
|
|
a86160265a | ||
|
|
8aaa8958c4 | ||
|
|
97b450dfd7 | ||
|
|
46c1e154f1 | ||
|
|
fcb1408e1e | ||
|
|
4cc27285b1 | ||
|
|
705bf48eed | ||
|
|
b651a355ab | ||
|
|
dd299c50bf | ||
|
|
bc7972dfa7 | ||
|
|
24d6ce7e51 | ||
|
|
e1c1c46e34 | ||
|
|
60a18229ee | ||
|
|
725e7c7470 | ||
|
|
2bd6661cd3 | ||
|
|
31cd43a245 | ||
|
|
ef446de92d | ||
|
|
18127be3bd | ||
|
|
64454a7e47 | ||
|
|
b09a0958a0 | ||
|
|
c541fa9555 | ||
|
|
1660bac6bd | ||
|
|
9e40642335 | ||
|
|
032bb45ce3 | ||
|
|
5a578669c2 | ||
|
|
3377133d19 | ||
|
|
ed31ea3773 | ||
|
|
feddf5a694 | ||
|
|
e847c030bd | ||
|
|
b3c4320bc2 | ||
|
|
730b52b084 | ||
|
|
4ff578db10 | ||
|
|
248c07c65e | ||
|
|
b01cf6be65 | ||
|
|
a0c6d88858 | ||
|
|
68560a941a | ||
|
|
77b7817266 | ||
|
|
c6a42e92bb | ||
|
|
73ff7baa1b | ||
|
|
e29cf84ac4 | ||
|
|
7ae675b469 | ||
|
|
b87b281df1 | ||
|
|
4869013a8d | ||
|
|
3e2107846d | ||
|
|
c8865459fc | ||
|
|
8559593a18 | ||
|
|
759a97403c | ||
|
|
a8aa7afa13 | ||
|
|
ecc8f9cf72 | ||
|
|
fe473dbef8 | ||
|
|
59c6862a03 | ||
|
|
e98973e2c0 | ||
|
|
c6b2184aa0 | ||
|
|
562e492056 | ||
|
|
15b8ee4564 | ||
|
|
d61e77dab4 | ||
|
|
d8e92d4859 | ||
|
|
4eb00a3e41 | ||
|
|
82eee65334 | ||
|
|
4f6cc46278 | ||
|
|
84d3848c01 | ||
|
|
b4093e59ee | ||
|
|
c4013eeb26 | ||
|
|
96cce3ae23 | ||
|
|
09b6dbb7ef | ||
|
|
cfea8de6b5 | ||
|
|
d5d48af7f7 | ||
|
|
43a5ff8e01 | ||
|
|
00b947124f | ||
|
|
3f24ad741a | ||
|
|
cc5f2f8995 | ||
|
|
6594ccf716 | ||
|
|
559ae8b326 | ||
|
|
da5b99f807 | ||
|
|
008b7bc94f | ||
|
|
b4f5baf4fa | ||
|
|
8c04129b94 | ||
|
|
5010461066 | ||
|
|
dde69802cd | ||
|
|
5530331b35 | ||
|
|
a55ebf2350 | ||
|
|
fb63364f30 | ||
|
|
58666c6210 | ||
|
|
3a9fa035ee | ||
|
|
1000d971f9 | ||
|
|
349e6af2c8 | ||
|
|
44b3b8937a | ||
|
|
9598e16753 | ||
|
|
61a963d78d | ||
|
|
e31856fe1b | ||
|
|
1d6134f87d | ||
|
|
08e9725797 | ||
|
|
4d98e96124 | ||
|
|
50e10cd771 | ||
|
|
b6838cb9f4 | ||
|
|
01a7c7a8b2 | ||
|
|
3c6aa84e44 | ||
|
|
bf2ae5aa81 | ||
|
|
44b0a893fc | ||
|
|
32fd55a66d | ||
|
|
9af01bea5e | ||
|
|
40fe3d94ac | ||
|
|
6fe203d0e2 | ||
|
|
7b6f652630 | ||
|
|
1a4c988a22 | ||
|
|
d936a9ae89 | ||
|
|
67e6d1087e | ||
|
|
29bafd1e15 | ||
|
|
65697e3324 | ||
|
|
bceca277ea | ||
|
|
16c8fb52df | ||
|
|
d702bfe7b7 | ||
|
|
596c9a3c0b | ||
|
|
c675d1c9e1 | ||
|
|
bd490ed511 | ||
|
|
bcf180642d | ||
|
|
5882e22f89 | ||
|
|
6f25168db3 | ||
|
|
2a4b5862ae | ||
|
|
7037ff8f3d | ||
|
|
1c9a486d60 | ||
|
|
eb9284e9ca | ||
|
|
77e3b72b15 | ||
|
|
05cb7e7412 | ||
|
|
299422994a | ||
|
|
b1d90cc171 | ||
|
|
af2207bc0b | ||
|
|
522bbc182d | ||
|
|
65233726f8 | ||
|
|
19227d9789 | ||
|
|
8915d60900 | ||
|
|
ed52c029a0 | ||
|
|
7b1201cd4d | ||
|
|
3f940715e4 | ||
|
|
f6225901e8 | ||
|
|
eff4b6377d | ||
|
|
a18647af0e | ||
|
|
c7df0c907a | ||
|
|
b74407a343 | ||
|
|
cd5c39834d | ||
|
|
574a25b09c | ||
|
|
6e0b13b81f | ||
|
|
bea8025fb5 | ||
|
|
965d0e04d1 | ||
|
|
d7c54920ee | ||
|
|
33a8108f19 | ||
|
|
78d254370c | ||
|
|
377ec33069 | ||
|
|
2952ba07e1 | ||
|
|
62b7ea7611 | ||
|
|
c9eca55c5e | ||
|
|
435bc269e9 | ||
|
|
0d2a7f876b | ||
|
|
737400ddbc | ||
|
|
134e159bc9 | ||
|
|
6f0b47681b | ||
|
|
d53981fdbb | ||
|
|
e09beee62a | ||
|
|
724ec3ca92 | ||
|
|
3ce6a710a3 | ||
|
|
e41596d6a1 | ||
|
|
0fa4d54316 | ||
|
|
e7cbb7a76c | ||
|
|
b2a23a9a90 | ||
|
|
6878c2bae0 | ||
|
|
5b8f1aa2ee | ||
|
|
6b4a82224c | ||
|
|
1f30b7742b | ||
|
|
54e7a94d70 | ||
|
|
f1919c706f | ||
|
|
26b17473aa | ||
|
|
99eee5cea9 | ||
|
|
074a0014c1 | ||
|
|
091cac00b2 | ||
|
|
175e3d751d | ||
|
|
83e9361005 | ||
|
|
17bb1248b5 | ||
|
|
8211e79be9 | ||
|
|
d5282862e5 | ||
|
|
26b6d18563 | ||
|
|
31fb5cc2d4 | ||
|
|
90301c6813 | ||
|
|
ccdf50aafd | ||
|
|
af5c80248d | ||
|
|
1d81a58cf1 | ||
|
|
09cec2e6a1 | ||
|
|
efed2641f4 | ||
|
|
97a5ca74d2 | ||
|
|
5b5b215dea | ||
|
|
7a06859f38 | ||
|
|
24fa104b61 | ||
|
|
89861faa04 | ||
|
|
5fd94e2027 | ||
|
|
1f4d02740e | ||
|
|
0023b9036b | ||
|
|
89d1f8c3ca | ||
|
|
7d9364655d | ||
|
|
86d2fcef16 | ||
|
|
5f8543fe81 | ||
|
|
aae7816557 | ||
|
|
6fbf13965c | ||
|
|
484e330e4a | ||
|
|
f27ecde1e2 | ||
|
|
c06d1a69ae | ||
|
|
cf9deb7cf5 | ||
|
|
40beb69487 | ||
|
|
f1cadee196 | ||
|
|
f6594ff073 | ||
|
|
478fdaa632 | ||
|
|
6c472ed2b8 | ||
|
|
30942c4e3d | ||
|
|
bf7d1e7b5a | ||
|
|
92e21c3f1c | ||
|
|
8880d27460 | ||
|
|
59d50be737 | ||
|
|
6d73443131 | ||
|
|
fe3796ed5b | ||
|
|
89f7b974f2 | ||
|
|
0ae958d45b | ||
|
|
3d1fdf77dc | ||
|
|
0ae71cacb4 | ||
|
|
218d635ca2 | ||
|
|
7553d0c471 | ||
|
|
f4880f5df5 | ||
|
|
3ccdad76de | ||
|
|
e464c08545 | ||
|
|
56e95ddfc8 | ||
|
|
65052a5d6c | ||
|
|
1364eb2f62 | ||
|
|
aa8ada3fed | ||
|
|
3643a9fe86 | ||
|
|
25f4bb2e17 | ||
|
|
3b62d9c027 | ||
|
|
c92938b378 | ||
|
|
c98313016e | ||
|
|
e43839114d | ||
|
|
b6c1786165 | ||
|
|
3a40555202 | ||
|
|
ff604e1906 | ||
|
|
34974a8a66 | ||
|
|
7c15daf99e | ||
|
|
b9467a4dc7 | ||
|
|
5a1c37a8c8 | ||
|
|
b75bc8aa64 | ||
|
|
ed4c08d9b3 | ||
|
|
929cdd9259 | ||
|
|
78049f452a | ||
|
|
cf2ef4863b | ||
|
|
2bd348558e | ||
|
|
0f6d83bb5f | ||
|
|
7e20232607 | ||
|
|
dcc55e3a73 | ||
|
|
59fd48cee0 | ||
|
|
c848b9014b | ||
|
|
1e16cb088a | ||
|
|
f4cf43359d | ||
|
|
6c8a5f5e2f | ||
|
|
da64d687d1 | ||
|
|
aab803b7ae | ||
|
|
936aba884a | ||
|
|
e1200230c4 | ||
|
|
d3ad816d63 | ||
|
|
eea1388cf4 | ||
|
|
f3747d1776 | ||
|
|
6277f2fccc | ||
|
|
931b0b3752 | ||
|
|
6f3e608331 | ||
|
|
1f58e0ed6b | ||
|
|
7a45768efe | ||
|
|
3a56da60dd |
@@ -32,7 +32,6 @@ xvfb-run -a -s "-screen 0 1024x768x24" \
|
||||
--timeout-multiplier 2 \
|
||||
--print-errorlogs \
|
||||
--suite=gtk \
|
||||
--no-suite=gtk:gsk \
|
||||
--no-suite=gtk:a11y
|
||||
|
||||
# Save the exit code
|
||||
|
||||
39
NEWS
39
NEWS
@@ -12,13 +12,13 @@ Overview of Changes in GTK+ 3.96.0
|
||||
* The use of global coordinates in GDK apis has been reduced. This
|
||||
work is still incomplete
|
||||
|
||||
* Events have been simplified and are just used for input
|
||||
- expose events have been replaced by a GdkSurface::render signal
|
||||
- configure events have been replaced by a GdkSurface::size-changed signal
|
||||
- map events have been replaced by a GdkSurface::mapped property
|
||||
- gdk_event_handler_set has been replaced by a GdkSurface::event signal
|
||||
- key events no longer contain a string
|
||||
- events on unmapped widgets are ignored
|
||||
* Events have been simplified and are used just for input
|
||||
- expose events have been replaced by a GdkSurface::render signal
|
||||
- configure events have been replaced by a GdkSurface::size-changed signal
|
||||
- map events have been replaced by a GdkSurface::mapped property
|
||||
- gdk_event_handler_set has been replaced by a GdkSurface::event signal
|
||||
- key events no longer contain a string
|
||||
- events on unmapped widgets are ignored
|
||||
|
||||
* Warping the pointer is no longer supported
|
||||
|
||||
@@ -36,11 +36,11 @@ Overview of Changes in GTK+ 3.96.0
|
||||
|
||||
* A number of list models have been introduced, for internal use
|
||||
and as public api:
|
||||
- GtkMapListModel
|
||||
- GtkSliceListModel
|
||||
- GtkSortListModel
|
||||
- GtkSelectionModel
|
||||
- GtkSingleSelection
|
||||
- GtkMapListModel
|
||||
- GtkSliceListModel
|
||||
- GtkSortListModel
|
||||
- GtkSelectionModel
|
||||
- GtkSingleSelection
|
||||
|
||||
* Support for tabular menus and combo boxes has been dropped
|
||||
|
||||
@@ -70,9 +70,13 @@ Overview of Changes in GTK+ 3.96.0
|
||||
|
||||
* GtkWidget can now use a GtkLayoutManager for size allocation.
|
||||
Layout managers can optionally use layout children holding layout
|
||||
properties. GtkBinLayout, GtkBoxLayout, GtkGridLayout, GtkFixedLayout
|
||||
and GtkCustomLayout are currently available, more layout manager
|
||||
implementations will appear in the future.
|
||||
properties. A number of layout managers are available:
|
||||
- GtkBinLayout
|
||||
- GtkBoxLayout
|
||||
- GtkGridLayout
|
||||
- GtkFixedLayout
|
||||
- GtkCustomLayout
|
||||
More layout manager implementations will appear in the future.
|
||||
|
||||
* GtkAssistant, GtkStack and GtkNotebook now have publicly
|
||||
accessible page objects for their children. The page objects
|
||||
@@ -82,8 +86,11 @@ Overview of Changes in GTK+ 3.96.0
|
||||
child properties have been removed, converted to regular properties,
|
||||
moved to layout properties or moved to child meta objects.
|
||||
|
||||
* GtkListBox has gained a ::show-separators property that gets
|
||||
translated into a CSS style class.
|
||||
|
||||
* A number of X11-specific GtkWindow and GdkSurface apis have been
|
||||
removed
|
||||
removed or changed to backend APIs.
|
||||
|
||||
* GtkBuilder can specify object-valued properties inline.
|
||||
|
||||
|
||||
@@ -24,9 +24,6 @@
|
||||
/* Define to 1 if you have the <crt_externs.h> header file. */
|
||||
#mesondefine HAVE_CRT_EXTERNS_H
|
||||
|
||||
/* Define to 1 if CUPS 1.6 API is available */
|
||||
#mesondefine HAVE_CUPS_API_1_6
|
||||
|
||||
/* Define to 1 if you have the `dcgettext' function. */
|
||||
#mesondefine HAVE_DCGETTEXT
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ do_expander (GtkWidget *do_widget)
|
||||
GtkWidget *toplevel;
|
||||
GtkWidget *area;
|
||||
GtkWidget *expander;
|
||||
GtkWidget *label;
|
||||
GtkWidget *sw;
|
||||
GtkWidget *tv;
|
||||
GtkTextBuffer *buffer;
|
||||
@@ -50,13 +51,19 @@ do_expander (GtkWidget *do_widget)
|
||||
|
||||
area = gtk_message_dialog_get_message_area (GTK_MESSAGE_DIALOG (window));
|
||||
|
||||
label = gtk_widget_get_last_child (area);
|
||||
gtk_label_set_line_wrap (GTK_LABEL (label), FALSE);
|
||||
gtk_widget_set_vexpand (label, FALSE);
|
||||
|
||||
expander = gtk_expander_new ("Details:");
|
||||
gtk_widget_set_vexpand (expander, TRUE);
|
||||
sw = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (sw), 100);
|
||||
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
||||
GTK_POLICY_NEVER,
|
||||
GTK_POLICY_AUTOMATIC);
|
||||
gtk_scrolled_window_set_propagate_natural_height (GTK_SCROLLED_WINDOW (sw), TRUE);
|
||||
|
||||
tv = gtk_text_view_new ();
|
||||
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
|
||||
@@ -101,51 +101,41 @@ do_menus (GtkWidget *do_widget)
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_container_add (GTK_CONTAINER (window), box);
|
||||
gtk_widget_show (box);
|
||||
|
||||
box1 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_container_add (GTK_CONTAINER (box), box1);
|
||||
gtk_widget_show (box1);
|
||||
|
||||
menubar = gtk_menu_bar_new ();
|
||||
gtk_widget_set_hexpand (menubar, TRUE);
|
||||
gtk_container_add (GTK_CONTAINER (box1), menubar);
|
||||
gtk_widget_show (menubar);
|
||||
|
||||
menu = create_menu (2);
|
||||
|
||||
menuitem = gtk_menu_item_new_with_label ("test\nline2");
|
||||
gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menubar), menuitem);
|
||||
gtk_widget_show (menuitem);
|
||||
|
||||
menuitem = gtk_menu_item_new_with_label ("foo");
|
||||
gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), create_menu (3));
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menubar), menuitem);
|
||||
gtk_widget_show (menuitem);
|
||||
|
||||
menuitem = gtk_menu_item_new_with_label ("bar");
|
||||
gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), create_menu (4));
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menubar), menuitem);
|
||||
gtk_widget_show (menuitem);
|
||||
|
||||
box2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
|
||||
gtk_container_add (GTK_CONTAINER (box1), box2);
|
||||
gtk_widget_show (box2);
|
||||
|
||||
button = gtk_button_new_with_label ("Flip");
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (change_orientation), menubar);
|
||||
gtk_container_add (GTK_CONTAINER (box2), button);
|
||||
gtk_widget_show (button);
|
||||
|
||||
button = gtk_button_new_with_label ("Close");
|
||||
g_signal_connect_swapped (button, "clicked",
|
||||
G_CALLBACK(gtk_widget_destroy), window);
|
||||
gtk_container_add (GTK_CONTAINER (box2), button);
|
||||
gtk_widget_set_can_default (button, TRUE);
|
||||
gtk_widget_grab_default (button);
|
||||
gtk_widget_show (button);
|
||||
gtk_window_set_default_widget (GTK_WINDOW (window), button);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
|
||||
@@ -76,8 +76,7 @@ do_password_entry (GtkWidget *do_widget)
|
||||
gtk_widget_set_sensitive (button, FALSE);
|
||||
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), button);
|
||||
|
||||
gtk_widget_set_can_default (button, TRUE);
|
||||
gtk_window_set_default (GTK_WINDOW (window), button);
|
||||
gtk_window_set_default_widget (GTK_WINDOW (window), button);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
|
||||
@@ -99,8 +99,7 @@ do_tagged_entry (GtkWidget *do_widget)
|
||||
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
|
||||
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), button);
|
||||
|
||||
gtk_widget_set_can_default (button, TRUE);
|
||||
gtk_window_set_default (GTK_WINDOW (window), button);
|
||||
gtk_window_set_default_widget (GTK_WINDOW (window), button);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
subdir('gtk-demo')
|
||||
subdir('icon-browser')
|
||||
subdir('node-editor')
|
||||
subdir('widget-factory')
|
||||
|
||||
323
demos/node-editor/gtkrendererpaintable.c
Normal file
323
demos/node-editor/gtkrendererpaintable.c
Normal file
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Copyright © 2019 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkrendererpaintableprivate.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
struct _GtkRendererPaintable
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GskRenderer *renderer;
|
||||
GdkPaintable *paintable;
|
||||
};
|
||||
|
||||
struct _GtkRendererPaintableClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_PAINTABLE,
|
||||
PROP_RENDERER,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties[N_PROPS] = { NULL, };
|
||||
|
||||
static void
|
||||
gtk_renderer_paintable_paintable_snapshot (GdkPaintable *paintable,
|
||||
GdkSnapshot *snapshot,
|
||||
double width,
|
||||
double height)
|
||||
{
|
||||
GtkRendererPaintable *self = GTK_RENDERER_PAINTABLE (paintable);
|
||||
GtkSnapshot *node_snapshot;
|
||||
GskRenderNode *node;
|
||||
GdkTexture *texture;
|
||||
|
||||
if (self->paintable == NULL)
|
||||
return;
|
||||
|
||||
if (self->renderer == NULL ||
|
||||
!gsk_renderer_is_realized (self->renderer))
|
||||
{
|
||||
gdk_paintable_snapshot (self->paintable, snapshot, width, height);
|
||||
return;
|
||||
}
|
||||
|
||||
node_snapshot = gtk_snapshot_new ();
|
||||
gdk_paintable_snapshot (self->paintable, node_snapshot, width, height);
|
||||
node = gtk_snapshot_free_to_node (node_snapshot);
|
||||
if (node == NULL)
|
||||
return;
|
||||
|
||||
texture = gsk_renderer_render_texture (self->renderer,
|
||||
node,
|
||||
&GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
|
||||
gdk_paintable_snapshot (GDK_PAINTABLE (texture), snapshot, width, height);
|
||||
g_object_unref (texture);
|
||||
}
|
||||
|
||||
static int
|
||||
gtk_renderer_paintable_paintable_get_intrinsic_width (GdkPaintable *paintable)
|
||||
{
|
||||
GtkRendererPaintable *self = GTK_RENDERER_PAINTABLE (paintable);
|
||||
|
||||
if (self->paintable == NULL)
|
||||
return 0;
|
||||
|
||||
return gdk_paintable_get_intrinsic_width (self->paintable);
|
||||
}
|
||||
|
||||
static int
|
||||
gtk_renderer_paintable_paintable_get_intrinsic_height (GdkPaintable *paintable)
|
||||
{
|
||||
GtkRendererPaintable *self = GTK_RENDERER_PAINTABLE (paintable);
|
||||
|
||||
if (self->paintable == NULL)
|
||||
return 0;
|
||||
|
||||
return gdk_paintable_get_intrinsic_height (self->paintable);
|
||||
}
|
||||
|
||||
static double
|
||||
gtk_renderer_paintable_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
|
||||
{
|
||||
GtkRendererPaintable *self = GTK_RENDERER_PAINTABLE (paintable);
|
||||
|
||||
if (self->paintable == NULL)
|
||||
return 0.0;
|
||||
|
||||
return gdk_paintable_get_intrinsic_aspect_ratio (self->paintable);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_renderer_paintable_paintable_init (GdkPaintableInterface *iface)
|
||||
{
|
||||
iface->snapshot = gtk_renderer_paintable_paintable_snapshot;
|
||||
iface->get_intrinsic_width = gtk_renderer_paintable_paintable_get_intrinsic_width;
|
||||
iface->get_intrinsic_height = gtk_renderer_paintable_paintable_get_intrinsic_height;
|
||||
iface->get_intrinsic_aspect_ratio = gtk_renderer_paintable_paintable_get_intrinsic_aspect_ratio;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (GtkRendererPaintable, gtk_renderer_paintable, G_TYPE_OBJECT, 0,
|
||||
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
|
||||
gtk_renderer_paintable_paintable_init))
|
||||
|
||||
static void
|
||||
gtk_renderer_paintable_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
|
||||
{
|
||||
GtkRendererPaintable *self = GTK_RENDERER_PAINTABLE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PAINTABLE:
|
||||
gtk_renderer_paintable_set_paintable (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_RENDERER:
|
||||
gtk_renderer_paintable_set_renderer (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_renderer_paintable_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkRendererPaintable *self = GTK_RENDERER_PAINTABLE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PAINTABLE:
|
||||
g_value_set_object (value, self->paintable);
|
||||
break;
|
||||
|
||||
case PROP_RENDERER:
|
||||
g_value_set_object (value, self->renderer);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_renderer_paintable_unset_paintable (GtkRendererPaintable *self)
|
||||
{
|
||||
guint flags;
|
||||
|
||||
if (self->paintable == NULL)
|
||||
return;
|
||||
|
||||
flags = gdk_paintable_get_flags (self->paintable);
|
||||
|
||||
if ((flags & GDK_PAINTABLE_STATIC_CONTENTS) == 0)
|
||||
g_signal_handlers_disconnect_by_func (self->paintable,
|
||||
gdk_paintable_invalidate_contents,
|
||||
self);
|
||||
|
||||
if ((flags & GDK_PAINTABLE_STATIC_SIZE) == 0)
|
||||
g_signal_handlers_disconnect_by_func (self->paintable,
|
||||
gdk_paintable_invalidate_size,
|
||||
self);
|
||||
|
||||
g_clear_object (&self->paintable);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_renderer_paintable_dispose (GObject *object)
|
||||
{
|
||||
GtkRendererPaintable *self = GTK_RENDERER_PAINTABLE (object);
|
||||
|
||||
g_clear_object (&self->renderer);
|
||||
gtk_renderer_paintable_unset_paintable (self);
|
||||
|
||||
G_OBJECT_CLASS (gtk_renderer_paintable_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_renderer_paintable_class_init (GtkRendererPaintableClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->get_property = gtk_renderer_paintable_get_property;
|
||||
gobject_class->set_property = gtk_renderer_paintable_set_property;
|
||||
gobject_class->dispose = gtk_renderer_paintable_dispose;
|
||||
|
||||
properties[PROP_PAINTABLE] =
|
||||
g_param_spec_object ("paintable",
|
||||
"Paintable",
|
||||
"The paintable to be shown",
|
||||
GDK_TYPE_PAINTABLE,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
properties[PROP_RENDERER] =
|
||||
g_param_spec_object ("renderer",
|
||||
"Renderer",
|
||||
"Renderer used to render the paintable",
|
||||
GSK_TYPE_RENDERER,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_renderer_paintable_init (GtkRendererPaintable *self)
|
||||
{
|
||||
}
|
||||
|
||||
GdkPaintable *
|
||||
gtk_renderer_paintable_new (GskRenderer *renderer,
|
||||
GdkPaintable *paintable)
|
||||
{
|
||||
g_return_val_if_fail (renderer == NULL || GSK_IS_RENDERER (renderer), NULL);
|
||||
g_return_val_if_fail (paintable == NULL || GDK_IS_PAINTABLE (paintable), NULL);
|
||||
|
||||
return g_object_new (GTK_TYPE_RENDERER_PAINTABLE,
|
||||
"renderer", renderer,
|
||||
"paintable", paintable,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_renderer_paintable_set_renderer (GtkRendererPaintable *self,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_RENDERER_PAINTABLE (self));
|
||||
g_return_if_fail (renderer == NULL || GSK_IS_RENDERER (renderer));
|
||||
|
||||
if (!g_set_object (&self->renderer, renderer))
|
||||
return;
|
||||
|
||||
if (self->paintable)
|
||||
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_RENDERER]);
|
||||
}
|
||||
|
||||
GskRenderer *
|
||||
gtk_renderer_paintable_get_renderer (GtkRendererPaintable *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_RENDERER_PAINTABLE (self), NULL);
|
||||
|
||||
return self->renderer;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_renderer_paintable_set_paintable (GtkRendererPaintable *self,
|
||||
GdkPaintable *paintable)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_RENDERER_PAINTABLE (self));
|
||||
g_return_if_fail (paintable == NULL || GDK_IS_PAINTABLE (paintable));
|
||||
|
||||
if (self->paintable == paintable)
|
||||
return;
|
||||
|
||||
gtk_renderer_paintable_unset_paintable (self);
|
||||
|
||||
if (paintable)
|
||||
{
|
||||
const guint flags = gdk_paintable_get_flags (paintable);
|
||||
|
||||
self->paintable = g_object_ref (paintable);
|
||||
|
||||
if ((flags & GDK_PAINTABLE_STATIC_CONTENTS) == 0)
|
||||
g_signal_connect_swapped (paintable,
|
||||
"invalidate-contents",
|
||||
G_CALLBACK (gdk_paintable_invalidate_contents),
|
||||
self);
|
||||
if ((flags & GDK_PAINTABLE_STATIC_SIZE) == 0)
|
||||
g_signal_connect_swapped (paintable,
|
||||
"invalidate-size",
|
||||
G_CALLBACK (gdk_paintable_invalidate_size),
|
||||
self);
|
||||
}
|
||||
|
||||
gdk_paintable_invalidate_size (GDK_PAINTABLE (self));
|
||||
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PAINTABLE]);
|
||||
}
|
||||
|
||||
GdkPaintable *
|
||||
gtk_renderer_paintable_get_paintable (GtkRendererPaintable *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_RENDERER_PAINTABLE (self), NULL);
|
||||
|
||||
return self->paintable;
|
||||
}
|
||||
|
||||
43
demos/node-editor/gtkrendererpaintableprivate.h
Normal file
43
demos/node-editor/gtkrendererpaintableprivate.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright © 2019 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_RENDERER_PAINTABLE_H__
|
||||
#define __GTK_RENDERER_PAINTABLE_H__
|
||||
|
||||
#include <gsk/gsk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_RENDERER_PAINTABLE (gtk_renderer_paintable_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (GtkRendererPaintable, gtk_renderer_paintable, GTK, RENDERER_PAINTABLE, GObject)
|
||||
|
||||
GdkPaintable * gtk_renderer_paintable_new (GskRenderer *renderer,
|
||||
GdkPaintable *paintable);
|
||||
|
||||
void gtk_renderer_paintable_set_renderer (GtkRendererPaintable *self,
|
||||
GskRenderer *renderer);
|
||||
GskRenderer * gtk_renderer_paintable_get_renderer (GtkRendererPaintable *self) G_GNUC_PURE;
|
||||
void gtk_renderer_paintable_set_paintable (GtkRendererPaintable *self,
|
||||
GdkPaintable *paintable);
|
||||
GdkPaintable * gtk_renderer_paintable_get_paintable (GtkRendererPaintable *self) G_GNUC_PURE;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_RENDERER_PAINTABLE_H__ */
|
||||
28
demos/node-editor/main.c
Normal file
28
demos/node-editor/main.c
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright © 2019 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <node-editor-application.h>
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
return g_application_run (G_APPLICATION (node_editor_application_new ()), argc, argv);
|
||||
}
|
||||
18
demos/node-editor/meson.build
Normal file
18
demos/node-editor/meson.build
Normal file
@@ -0,0 +1,18 @@
|
||||
node_editor_sources = [
|
||||
'gtkrendererpaintable.c',
|
||||
'main.c',
|
||||
'node-editor-application.c',
|
||||
'node-editor-window.c',
|
||||
]
|
||||
|
||||
node_editor_resources = gnome.compile_resources('node_editor_resources',
|
||||
'node-editor.gresource.xml',
|
||||
source_dir: '.')
|
||||
|
||||
executable('gtk4-node-editor',
|
||||
node_editor_sources, node_editor_resources,
|
||||
dependencies: libgtk_dep,
|
||||
include_directories: confinc,
|
||||
gui_app: true,
|
||||
link_args: extra_demo_ldflags,
|
||||
install: false)
|
||||
132
demos/node-editor/node-editor-application.c
Normal file
132
demos/node-editor/node-editor-application.c
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright © 2019 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "node-editor-application.h"
|
||||
|
||||
#include "node-editor-window.h"
|
||||
|
||||
static const char *css =
|
||||
"textview.editor {"
|
||||
" color: rgb(192, 197, 206);"
|
||||
" caret-color: white;"
|
||||
"}"
|
||||
"textview.editor text {"
|
||||
" background-color: rgb(43, 48, 59);"
|
||||
"}"
|
||||
;
|
||||
|
||||
struct _NodeEditorApplication
|
||||
{
|
||||
GtkApplication parent;
|
||||
};
|
||||
|
||||
struct _NodeEditorApplicationClass
|
||||
{
|
||||
GtkApplicationClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(NodeEditorApplication, node_editor_application, GTK_TYPE_APPLICATION);
|
||||
|
||||
static void
|
||||
node_editor_application_init (NodeEditorApplication *app)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
quit_activated (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer data)
|
||||
{
|
||||
g_application_quit (G_APPLICATION (data));
|
||||
}
|
||||
|
||||
static GActionEntry app_entries[] =
|
||||
{
|
||||
{ "quit", quit_activated, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
node_editor_application_startup (GApplication *app)
|
||||
{
|
||||
const char *quit_accels[2] = { "<Ctrl>Q", NULL };
|
||||
const char *open_accels[2] = { "<Ctrl>O", NULL };
|
||||
GtkCssProvider *provider;
|
||||
|
||||
G_APPLICATION_CLASS (node_editor_application_parent_class)->startup (app);
|
||||
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (app),
|
||||
app_entries, G_N_ELEMENTS (app_entries),
|
||||
app);
|
||||
gtk_application_set_accels_for_action (GTK_APPLICATION (app), "app.quit", quit_accels);
|
||||
gtk_application_set_accels_for_action (GTK_APPLICATION (app), "win.open", open_accels);
|
||||
|
||||
|
||||
provider = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_data (provider, css, -1);
|
||||
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
|
||||
GTK_STYLE_PROVIDER (provider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
}
|
||||
|
||||
static void
|
||||
node_editor_application_activate (GApplication *app)
|
||||
{
|
||||
NodeEditorWindow *win;
|
||||
|
||||
win = node_editor_window_new (NODE_EDITOR_APPLICATION (app));
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
static void
|
||||
node_editor_application_open (GApplication *app,
|
||||
GFile **files,
|
||||
gint n_files,
|
||||
const gchar *hint)
|
||||
{
|
||||
NodeEditorWindow *win;
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < n_files; i++)
|
||||
{
|
||||
win = node_editor_window_new (NODE_EDITOR_APPLICATION (app));
|
||||
node_editor_window_load (win, files[i]);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
node_editor_application_class_init (NodeEditorApplicationClass *class)
|
||||
{
|
||||
GApplicationClass *application_class = G_APPLICATION_CLASS (class);
|
||||
|
||||
application_class->startup = node_editor_application_startup;
|
||||
application_class->activate = node_editor_application_activate;
|
||||
application_class->open = node_editor_application_open;
|
||||
}
|
||||
|
||||
NodeEditorApplication *
|
||||
node_editor_application_new (void)
|
||||
{
|
||||
return g_object_new (NODE_EDITOR_APPLICATION_TYPE,
|
||||
"application-id", "org.gtk.gtk4.NodeEditor",
|
||||
"flags", G_APPLICATION_HANDLES_OPEN,
|
||||
NULL);
|
||||
}
|
||||
38
demos/node-editor/node-editor-application.h
Normal file
38
demos/node-editor/node-editor-application.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright © 2019 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __NODE_EDITOR_APPLICATION_H__
|
||||
#define __NODE_EDITOR_APPLICATION_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
#define NODE_EDITOR_APPLICATION_TYPE (node_editor_application_get_type ())
|
||||
#define NODE_EDITOR_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NODE_EDITOR_APPLICATION_TYPE, NodeEditorApplication))
|
||||
|
||||
|
||||
typedef struct _NodeEditorApplication NodeEditorApplication;
|
||||
typedef struct _NodeEditorApplicationClass NodeEditorApplicationClass;
|
||||
|
||||
|
||||
GType node_editor_application_get_type (void);
|
||||
NodeEditorApplication *node_editor_application_new (void);
|
||||
|
||||
|
||||
#endif /* __NODE_EDITOR_APPLICATION_H__ */
|
||||
701
demos/node-editor/node-editor-window.c
Normal file
701
demos/node-editor/node-editor-window.c
Normal file
@@ -0,0 +1,701 @@
|
||||
/*
|
||||
* Copyright © 2019 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "node-editor-window.h"
|
||||
|
||||
#include "gtkrendererpaintableprivate.h"
|
||||
|
||||
#include "gsk/gskrendernodeparserprivate.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gsize start_chars;
|
||||
gsize end_chars;
|
||||
char *message;
|
||||
} TextViewError;
|
||||
|
||||
struct _NodeEditorWindow
|
||||
{
|
||||
GtkApplicationWindow parent;
|
||||
|
||||
GtkWidget *picture;
|
||||
GtkWidget *text_view;
|
||||
GtkTextBuffer *text_buffer;
|
||||
GtkTextTagTable *tag_table;
|
||||
|
||||
GtkWidget *renderer_listbox;
|
||||
GListStore *renderers;
|
||||
GdkPaintable *paintable;
|
||||
|
||||
GArray *errors;
|
||||
};
|
||||
|
||||
struct _NodeEditorWindowClass
|
||||
{
|
||||
GtkApplicationWindowClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(NodeEditorWindow, node_editor_window, GTK_TYPE_APPLICATION_WINDOW);
|
||||
|
||||
static void
|
||||
text_view_error_free (TextViewError *e)
|
||||
{
|
||||
g_free (e->message);
|
||||
}
|
||||
|
||||
static gchar *
|
||||
get_current_text (GtkTextBuffer *buffer)
|
||||
{
|
||||
GtkTextIter start, end;
|
||||
|
||||
gtk_text_buffer_get_start_iter (buffer, &start);
|
||||
gtk_text_buffer_get_end_iter (buffer, &end);
|
||||
gtk_text_buffer_remove_all_tags (buffer, &start, &end);
|
||||
|
||||
return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
deserialize_error_func (const GtkCssSection *section,
|
||||
const GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
const GtkCssLocation *start_location = gtk_css_section_get_start_location (section);
|
||||
const GtkCssLocation *end_location = gtk_css_section_get_end_location (section);
|
||||
NodeEditorWindow *self = user_data;
|
||||
GtkTextIter start_iter, end_iter;
|
||||
TextViewError text_view_error;
|
||||
|
||||
gtk_text_buffer_get_iter_at_line_offset (self->text_buffer, &start_iter,
|
||||
start_location->lines,
|
||||
start_location->line_chars);
|
||||
gtk_text_buffer_get_iter_at_line_offset (self->text_buffer, &end_iter,
|
||||
end_location->lines,
|
||||
end_location->line_chars);
|
||||
|
||||
gtk_text_buffer_apply_tag_by_name (self->text_buffer, "error",
|
||||
&start_iter, &end_iter);
|
||||
|
||||
text_view_error.start_chars = start_location->chars;
|
||||
text_view_error.end_chars = end_location->chars;
|
||||
text_view_error.message = g_strdup (error->message);
|
||||
g_array_append_val (self->errors, text_view_error);
|
||||
}
|
||||
|
||||
static void
|
||||
text_iter_skip_alpha_backward (GtkTextIter *iter)
|
||||
{
|
||||
/* Just skip to the previous non-whitespace char */
|
||||
|
||||
while (!gtk_text_iter_is_start (iter))
|
||||
{
|
||||
gunichar c = gtk_text_iter_get_char (iter);
|
||||
|
||||
if (g_unichar_isspace (c))
|
||||
{
|
||||
gtk_text_iter_forward_char (iter);
|
||||
break;
|
||||
}
|
||||
|
||||
gtk_text_iter_backward_char (iter);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
text_iter_skip_whitespace_backward (GtkTextIter *iter)
|
||||
{
|
||||
while (!gtk_text_iter_is_start (iter))
|
||||
{
|
||||
gunichar c = gtk_text_iter_get_char (iter);
|
||||
|
||||
if (g_unichar_isalpha (c))
|
||||
{
|
||||
gtk_text_iter_forward_char (iter);
|
||||
break;
|
||||
}
|
||||
|
||||
gtk_text_iter_backward_char (iter);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
text_changed (GtkTextBuffer *buffer,
|
||||
NodeEditorWindow *self)
|
||||
{
|
||||
GskRenderNode *node;
|
||||
char *text;
|
||||
GBytes *bytes;
|
||||
|
||||
g_array_remove_range (self->errors, 0, self->errors->len);
|
||||
text = get_current_text (self->text_buffer);
|
||||
bytes = g_bytes_new_take (text, strlen (text));
|
||||
|
||||
/* If this is too slow, go fix the parser performance */
|
||||
node = gsk_render_node_deserialize (bytes, deserialize_error_func, self);
|
||||
g_bytes_unref (bytes);
|
||||
if (node)
|
||||
{
|
||||
/* XXX: Is this code necessary or can we have API to turn nodes into paintables? */
|
||||
GtkSnapshot *snapshot;
|
||||
GdkPaintable *paintable;
|
||||
graphene_rect_t bounds;
|
||||
guint i;
|
||||
|
||||
snapshot = gtk_snapshot_new ();
|
||||
gsk_render_node_get_bounds (node, &bounds);
|
||||
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (- bounds.origin.x, - bounds.origin.y));
|
||||
gtk_snapshot_append_node (snapshot, node);
|
||||
gsk_render_node_unref (node);
|
||||
paintable = gtk_snapshot_free_to_paintable (snapshot, &bounds.size);
|
||||
gtk_picture_set_paintable (GTK_PICTURE (self->picture), paintable);
|
||||
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (self->renderers)); i++)
|
||||
{
|
||||
gpointer item = g_list_model_get_item (G_LIST_MODEL (self->renderers), i);
|
||||
gtk_renderer_paintable_set_paintable (item, paintable);
|
||||
g_object_unref (item);
|
||||
}
|
||||
g_clear_object (&paintable);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_picture_set_paintable (GTK_PICTURE (self->picture), NULL);
|
||||
}
|
||||
|
||||
GtkTextIter iter;
|
||||
|
||||
gtk_text_buffer_get_start_iter (self->text_buffer, &iter);
|
||||
|
||||
while (!gtk_text_iter_is_end (&iter))
|
||||
{
|
||||
gunichar c = gtk_text_iter_get_char (&iter);
|
||||
|
||||
if (c == '{')
|
||||
{
|
||||
GtkTextIter word_end = iter;
|
||||
GtkTextIter word_start;
|
||||
|
||||
gtk_text_iter_backward_char (&word_end);
|
||||
text_iter_skip_whitespace_backward (&word_end);
|
||||
|
||||
word_start = word_end;
|
||||
gtk_text_iter_backward_word_start (&word_start);
|
||||
text_iter_skip_alpha_backward (&word_start);
|
||||
|
||||
gtk_text_buffer_apply_tag_by_name (self->text_buffer, "nodename",
|
||||
&word_start, &word_end);
|
||||
}
|
||||
else if (c == ':')
|
||||
{
|
||||
GtkTextIter word_end = iter;
|
||||
GtkTextIter word_start;
|
||||
|
||||
gtk_text_iter_backward_char (&word_end);
|
||||
text_iter_skip_whitespace_backward (&word_end);
|
||||
|
||||
word_start = word_end;
|
||||
gtk_text_iter_backward_word_start (&word_start);
|
||||
text_iter_skip_alpha_backward (&word_start);
|
||||
|
||||
gtk_text_buffer_apply_tag_by_name (self->text_buffer, "propname",
|
||||
&word_start, &word_end);
|
||||
}
|
||||
else if (c == '"')
|
||||
{
|
||||
GtkTextIter string_start = iter;
|
||||
GtkTextIter string_end = iter;
|
||||
|
||||
gtk_text_iter_forward_char (&iter);
|
||||
while (!gtk_text_iter_is_end (&iter))
|
||||
{
|
||||
c = gtk_text_iter_get_char (&iter);
|
||||
|
||||
if (c == '"')
|
||||
{
|
||||
gtk_text_iter_forward_char (&iter);
|
||||
string_end = iter;
|
||||
break;
|
||||
}
|
||||
|
||||
gtk_text_iter_forward_char (&iter);
|
||||
}
|
||||
|
||||
gtk_text_buffer_apply_tag_by_name (self->text_buffer, "string",
|
||||
&string_start, &string_end);
|
||||
}
|
||||
|
||||
gtk_text_iter_forward_char (&iter);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
text_view_query_tooltip_cb (GtkWidget *widget,
|
||||
int x,
|
||||
int y,
|
||||
gboolean keyboard_tip,
|
||||
GtkTooltip *tooltip,
|
||||
NodeEditorWindow *self)
|
||||
{
|
||||
GtkTextIter iter;
|
||||
guint i;
|
||||
|
||||
if (keyboard_tip)
|
||||
{
|
||||
gint offset;
|
||||
|
||||
g_object_get (self->text_buffer, "cursor-position", &offset, NULL);
|
||||
gtk_text_buffer_get_iter_at_offset (self->text_buffer, &iter, offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
gint bx, by, trailing;
|
||||
|
||||
gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (self->text_view), GTK_TEXT_WINDOW_TEXT,
|
||||
x, y, &bx, &by);
|
||||
gtk_text_view_get_iter_at_position (GTK_TEXT_VIEW (self->text_view), &iter, &trailing, bx, by);
|
||||
}
|
||||
|
||||
for (i = 0; i < self->errors->len; i ++)
|
||||
{
|
||||
const TextViewError *e = &g_array_index (self->errors, TextViewError, i);
|
||||
GtkTextIter start_iter, end_iter;
|
||||
|
||||
gtk_text_buffer_get_iter_at_offset (self->text_buffer, &start_iter, e->start_chars);
|
||||
gtk_text_buffer_get_iter_at_offset (self->text_buffer, &end_iter, e->end_chars);
|
||||
|
||||
if (gtk_text_iter_in_range (&iter, &start_iter, &end_iter))
|
||||
{
|
||||
gtk_tooltip_set_text (tooltip, e->message);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
node_editor_window_load (NodeEditorWindow *self,
|
||||
GFile *file)
|
||||
{
|
||||
GtkTextIter end;
|
||||
GBytes *bytes;
|
||||
|
||||
bytes = g_file_load_bytes (file, NULL, NULL, NULL);
|
||||
if (bytes == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (!g_utf8_validate (g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), NULL))
|
||||
{
|
||||
g_bytes_unref (bytes);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gtk_text_buffer_get_end_iter (self->text_buffer, &end);
|
||||
gtk_text_buffer_insert (self->text_buffer,
|
||||
&end,
|
||||
g_bytes_get_data (bytes, NULL),
|
||||
g_bytes_get_size (bytes));
|
||||
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
open_response_cb (GtkWidget *dialog,
|
||||
gint response,
|
||||
NodeEditorWindow *self)
|
||||
{
|
||||
gtk_widget_hide (dialog);
|
||||
|
||||
if (response == GTK_RESPONSE_ACCEPT)
|
||||
{
|
||||
GFile *file;
|
||||
|
||||
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
|
||||
node_editor_window_load (self, file);
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
gtk_widget_destroy (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
show_open_filechooser (NodeEditorWindow *self)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
|
||||
dialog = gtk_file_chooser_dialog_new ("Open node file",
|
||||
GTK_WINDOW (self),
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
"_Cancel", GTK_RESPONSE_CANCEL,
|
||||
"_Load", GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
|
||||
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
|
||||
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
|
||||
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), ".");
|
||||
g_signal_connect (dialog, "response", G_CALLBACK (open_response_cb), self);
|
||||
gtk_widget_show (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
open_cb (GtkWidget *button,
|
||||
NodeEditorWindow *self)
|
||||
{
|
||||
show_open_filechooser (self);
|
||||
}
|
||||
|
||||
static void
|
||||
save_response_cb (GtkWidget *dialog,
|
||||
gint response,
|
||||
NodeEditorWindow *self)
|
||||
{
|
||||
gtk_widget_hide (dialog);
|
||||
|
||||
if (response == GTK_RESPONSE_ACCEPT)
|
||||
{
|
||||
char *text, *filename;
|
||||
GError *error = NULL;
|
||||
|
||||
text = get_current_text (self->text_buffer);
|
||||
|
||||
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
|
||||
if (!g_file_set_contents (filename, text, -1, &error))
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
|
||||
dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self))),
|
||||
GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_INFO,
|
||||
GTK_BUTTONS_OK,
|
||||
"Saving failed");
|
||||
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
|
||||
"%s", error->message);
|
||||
g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
|
||||
gtk_widget_show (dialog);
|
||||
g_error_free (error);
|
||||
}
|
||||
g_free (filename);
|
||||
}
|
||||
|
||||
gtk_widget_destroy (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
save_cb (GtkWidget *button,
|
||||
NodeEditorWindow *self)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
|
||||
dialog = gtk_file_chooser_dialog_new ("Save node",
|
||||
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (button))),
|
||||
GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
"_Cancel", GTK_RESPONSE_CANCEL,
|
||||
"_Save", GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
|
||||
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
|
||||
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
|
||||
gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
|
||||
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), ".");
|
||||
g_signal_connect (dialog, "response", G_CALLBACK (save_response_cb), self);
|
||||
gtk_widget_show (dialog);
|
||||
}
|
||||
|
||||
static GdkTexture *
|
||||
create_texture (NodeEditorWindow *self)
|
||||
{
|
||||
GdkPaintable *paintable;
|
||||
GtkSnapshot *snapshot;
|
||||
GskRenderer *renderer;
|
||||
GskRenderNode *node;
|
||||
GdkTexture *texture;
|
||||
|
||||
paintable = gtk_picture_get_paintable (GTK_PICTURE (self->picture));
|
||||
if (paintable == NULL ||
|
||||
gdk_paintable_get_intrinsic_width (paintable) <= 0 ||
|
||||
gdk_paintable_get_intrinsic_height (paintable) <= 0)
|
||||
return NULL;
|
||||
snapshot = gtk_snapshot_new ();
|
||||
gdk_paintable_snapshot (paintable, snapshot, gdk_paintable_get_intrinsic_width (paintable), gdk_paintable_get_intrinsic_height (paintable));
|
||||
node = gtk_snapshot_free_to_node (snapshot);
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
|
||||
/* ahem */
|
||||
renderer = GTK_ROOT_GET_IFACE (gtk_widget_get_root (GTK_WIDGET (self)))->get_renderer (gtk_widget_get_root (GTK_WIDGET (self)));
|
||||
texture = gsk_renderer_render_texture (renderer, node, NULL);
|
||||
gsk_render_node_unref (node);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
static void
|
||||
export_image_response_cb (GtkWidget *dialog,
|
||||
gint response,
|
||||
GdkTexture *texture)
|
||||
{
|
||||
gtk_widget_hide (dialog);
|
||||
|
||||
if (response == GTK_RESPONSE_ACCEPT)
|
||||
{
|
||||
char *filename;
|
||||
|
||||
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
|
||||
if (!gdk_texture_save_to_png (texture, filename))
|
||||
{
|
||||
GtkWidget *message_dialog;
|
||||
|
||||
message_dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_window_get_transient_for (GTK_WINDOW (dialog))),
|
||||
GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_INFO,
|
||||
GTK_BUTTONS_OK,
|
||||
"Exporting to image failed");
|
||||
g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
|
||||
gtk_widget_show (message_dialog);
|
||||
}
|
||||
g_free (filename);
|
||||
}
|
||||
|
||||
gtk_widget_destroy (dialog);
|
||||
g_object_unref (texture);
|
||||
}
|
||||
|
||||
static void
|
||||
export_image_cb (GtkWidget *button,
|
||||
NodeEditorWindow *self)
|
||||
{
|
||||
GdkTexture *texture;
|
||||
GtkWidget *dialog;
|
||||
|
||||
texture = create_texture (self);
|
||||
if (texture == NULL)
|
||||
return;
|
||||
|
||||
dialog = gtk_file_chooser_dialog_new ("",
|
||||
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (button))),
|
||||
GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
"_Cancel", GTK_RESPONSE_CANCEL,
|
||||
"_Save", GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
|
||||
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
|
||||
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
|
||||
gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
|
||||
g_signal_connect (dialog, "response", G_CALLBACK (export_image_response_cb), texture);
|
||||
gtk_widget_show (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
node_editor_window_finalize (GObject *object)
|
||||
{
|
||||
NodeEditorWindow *self = (NodeEditorWindow *)object;
|
||||
|
||||
g_array_free (self->errors, TRUE);
|
||||
|
||||
g_clear_object (&self->renderers);
|
||||
|
||||
G_OBJECT_CLASS (node_editor_window_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
node_editor_window_add_renderer (NodeEditorWindow *self,
|
||||
GskRenderer *renderer,
|
||||
const char *description)
|
||||
{
|
||||
GdkSurface *surface;
|
||||
GdkPaintable *paintable;
|
||||
|
||||
surface = gtk_widget_get_surface (GTK_WIDGET (self));
|
||||
g_assert (surface != NULL);
|
||||
|
||||
if (renderer != NULL && !gsk_renderer_realize (renderer, surface, NULL))
|
||||
{
|
||||
g_object_unref (renderer);
|
||||
return;
|
||||
}
|
||||
|
||||
paintable = gtk_renderer_paintable_new (renderer, gtk_picture_get_paintable (GTK_PICTURE (self->picture)));
|
||||
g_object_set_data_full (G_OBJECT (paintable), "description", g_strdup (description), g_free);
|
||||
g_clear_object (&renderer);
|
||||
|
||||
g_list_store_append (self->renderers, paintable);
|
||||
g_object_unref (paintable);
|
||||
}
|
||||
|
||||
static void
|
||||
node_editor_window_realize (GtkWidget *widget)
|
||||
{
|
||||
NodeEditorWindow *self = NODE_EDITOR_WINDOW (widget);
|
||||
|
||||
GTK_WIDGET_CLASS (node_editor_window_parent_class)->realize (widget);
|
||||
|
||||
#if 0
|
||||
node_editor_window_add_renderer (self,
|
||||
NULL,
|
||||
"Default");
|
||||
#endif
|
||||
node_editor_window_add_renderer (self,
|
||||
gsk_gl_renderer_new (),
|
||||
"OpenGL");
|
||||
#ifdef GDK_RENDERING_VULKAN
|
||||
node_editor_window_add_renderer (self,
|
||||
gsk_vulkan_renderer_new (),
|
||||
"Vulkan");
|
||||
#endif
|
||||
#ifdef GDK_WINDOWING_BROADWAY
|
||||
node_editor_window_add_renderer (self,
|
||||
gsk_broadway_renderer_new (),
|
||||
"Broadway");
|
||||
#endif
|
||||
node_editor_window_add_renderer (self,
|
||||
gsk_cairo_renderer_new (),
|
||||
"Cairo");
|
||||
}
|
||||
|
||||
static void
|
||||
node_editor_window_unrealize (GtkWidget *widget)
|
||||
{
|
||||
NodeEditorWindow *self = NODE_EDITOR_WINDOW (widget);
|
||||
|
||||
g_list_store_remove_all (self->renderers);
|
||||
|
||||
GTK_WIDGET_CLASS (node_editor_window_parent_class)->unrealize (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
node_editor_window_class_init (NodeEditorWindowClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
object_class->finalize = node_editor_window_finalize;
|
||||
|
||||
gtk_widget_class_set_template_from_resource (widget_class,
|
||||
"/org/gtk/gtk4/node-editor/node-editor-window.ui");
|
||||
|
||||
widget_class->realize = node_editor_window_realize;
|
||||
widget_class->unrealize = node_editor_window_unrealize;
|
||||
|
||||
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, text_view);
|
||||
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, picture);
|
||||
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, renderer_listbox);
|
||||
|
||||
gtk_widget_class_bind_template_callback (widget_class, text_view_query_tooltip_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, open_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, save_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, export_image_cb);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
node_editor_window_create_renderer_widget (gpointer item,
|
||||
gpointer user_data)
|
||||
{
|
||||
GdkPaintable *paintable = item;
|
||||
GtkWidget *box, *label, *picture;
|
||||
GtkWidget *row;
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_widget_set_size_request (box, 120, 90);
|
||||
|
||||
label = gtk_label_new (g_object_get_data (G_OBJECT (paintable), "description"));
|
||||
gtk_container_add (GTK_CONTAINER (box), label);
|
||||
|
||||
picture = gtk_picture_new_for_paintable (paintable);
|
||||
gtk_container_add (GTK_CONTAINER (box), picture);
|
||||
|
||||
row = gtk_list_box_row_new ();
|
||||
gtk_container_add (GTK_CONTAINER (row), box);
|
||||
gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
static void
|
||||
window_open (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
NodeEditorWindow *self = user_data;
|
||||
|
||||
show_open_filechooser (self);
|
||||
}
|
||||
|
||||
static GActionEntry win_entries[] = {
|
||||
{ "open", window_open, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
static void
|
||||
node_editor_window_init (NodeEditorWindow *self)
|
||||
{
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
|
||||
self->renderers = g_list_store_new (GDK_TYPE_PAINTABLE);
|
||||
gtk_list_box_bind_model (GTK_LIST_BOX (self->renderer_listbox),
|
||||
G_LIST_MODEL (self->renderers),
|
||||
node_editor_window_create_renderer_widget,
|
||||
self,
|
||||
NULL);
|
||||
|
||||
self->errors = g_array_new (FALSE, TRUE, sizeof (TextViewError));
|
||||
g_array_set_clear_func (self->errors, (GDestroyNotify)text_view_error_free);
|
||||
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (self), win_entries, G_N_ELEMENTS (win_entries), self);
|
||||
|
||||
self->tag_table = gtk_text_tag_table_new ();
|
||||
gtk_text_tag_table_add (self->tag_table,
|
||||
g_object_new (GTK_TYPE_TEXT_TAG,
|
||||
"name", "error",
|
||||
"underline", PANGO_UNDERLINE_ERROR,
|
||||
NULL));
|
||||
gtk_text_tag_table_add (self->tag_table,
|
||||
g_object_new (GTK_TYPE_TEXT_TAG,
|
||||
"name", "nodename",
|
||||
"foreground-rgba", &(GdkRGBA) { 0.9, 0.78, 0.53, 1},
|
||||
NULL));
|
||||
gtk_text_tag_table_add (self->tag_table,
|
||||
g_object_new (GTK_TYPE_TEXT_TAG,
|
||||
"name", "propname",
|
||||
"foreground-rgba", &(GdkRGBA) { 0.7, 0.55, 0.67, 1},
|
||||
NULL));
|
||||
gtk_text_tag_table_add (self->tag_table,
|
||||
g_object_new (GTK_TYPE_TEXT_TAG,
|
||||
"name", "string",
|
||||
"foreground-rgba", &(GdkRGBA) { 0.63, 0.73, 0.54, 1},
|
||||
NULL));
|
||||
gtk_text_tag_table_add (self->tag_table,
|
||||
g_object_new (GTK_TYPE_TEXT_TAG,
|
||||
"name", "number",
|
||||
"foreground-rgba", &(GdkRGBA) { 0.8, 0.52, 0.43, 1},
|
||||
NULL));
|
||||
|
||||
self->text_buffer = gtk_text_buffer_new (self->tag_table);
|
||||
g_signal_connect (self->text_buffer, "changed", G_CALLBACK (text_changed), self);
|
||||
gtk_text_view_set_buffer (GTK_TEXT_VIEW (self->text_view), self->text_buffer);
|
||||
}
|
||||
|
||||
NodeEditorWindow *
|
||||
node_editor_window_new (NodeEditorApplication *application)
|
||||
{
|
||||
return g_object_new (NODE_EDITOR_WINDOW_TYPE,
|
||||
"application", application,
|
||||
NULL);
|
||||
}
|
||||
42
demos/node-editor/node-editor-window.h
Normal file
42
demos/node-editor/node-editor-window.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright © 2019 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __NODE_EDITOR_WINDOW_H__
|
||||
#define __NODE_EDITOR_WINDOW_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "node-editor-application.h"
|
||||
|
||||
#define NODE_EDITOR_WINDOW_TYPE (node_editor_window_get_type ())
|
||||
#define NODE_EDITOR_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NODE_EDITOR_WINDOW_TYPE, NodeEditorWindow))
|
||||
|
||||
|
||||
typedef struct _NodeEditorWindow NodeEditorWindow;
|
||||
typedef struct _NodeEditorWindowClass NodeEditorWindowClass;
|
||||
|
||||
|
||||
GType node_editor_window_get_type (void);
|
||||
|
||||
NodeEditorWindow * node_editor_window_new (NodeEditorApplication *application);
|
||||
|
||||
gboolean node_editor_window_load (NodeEditorWindow *self,
|
||||
GFile *file);
|
||||
|
||||
#endif /* __NODE_EDITOR_WINDOW_H__ */
|
||||
103
demos/node-editor/node-editor-window.ui
Normal file
103
demos/node-editor/node-editor-window.ui
Normal file
@@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="NodeEditorWindow" parent="GtkApplicationWindow">
|
||||
<style>
|
||||
<class name="devel"/>
|
||||
</style>
|
||||
<property name="title" translatable="yes">GTK Node Editor</property>
|
||||
<property name="default-width">1024</property>
|
||||
<property name="default-height">768</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header">
|
||||
<property name="title" translatable="yes">GTK Node Editor</property>
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child type="start">
|
||||
<object class="GtkButton">
|
||||
<property name="icon-name">document-open-symbolic</property>
|
||||
<property name="tooltip-text">Open node file</property>
|
||||
<signal name="clicked" handler="open_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
<child type="start">
|
||||
<object class="GtkButton">
|
||||
<property name="icon-name">document-save-symbolic</property>
|
||||
<property name="tooltip-text">Save to node file</property>
|
||||
<signal name="clicked" handler="save_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
<child type="start">
|
||||
<object class="GtkButton">
|
||||
<property name="icon-name">insert-image-symbolic</property>
|
||||
<property name="tooltip-text">Export to image</property>
|
||||
<signal name="clicked" handler="export_image_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
<child type="title">
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">GTK Node Editor</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkPaned">
|
||||
<property name="shrink-child2">false</property>
|
||||
<property name="position">400</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<property name="expand">1</property>
|
||||
<child>
|
||||
<object class="GtkTextView" id="text_view">
|
||||
<property name="wrap-mode">word</property>
|
||||
<property name="monospace">1</property>
|
||||
<property name="has-focus">1</property>
|
||||
<property name="top-margin">6</property>
|
||||
<property name="left-margin">6</property>
|
||||
<property name="right-margin">6</property>
|
||||
<property name="bottom-margin">6</property>
|
||||
<property name="has-tooltip">1</property>
|
||||
<signal name="query-tooltip" handler="text_view_query_tooltip_cb"/>
|
||||
<style>
|
||||
<class name="editor" />
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="expand">1</property>
|
||||
<property name="min-content-height">100</property>
|
||||
<property name="min-content-width">100</property>
|
||||
<child>
|
||||
<object class="GtkViewport">
|
||||
<child>
|
||||
<object class="GtkPicture" id="picture">
|
||||
<property name="can-shrink">0</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<child>
|
||||
<object class="GtkListBox" id="renderer_listbox">
|
||||
<property name="selection-mode">none</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
6
demos/node-editor/node-editor.gresource.xml
Normal file
6
demos/node-editor/node-editor.gresource.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/org/gtk/gtk4/node-editor">
|
||||
<file preprocess="xml-stripblanks">node-editor-window.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
@@ -2880,6 +2880,17 @@ microphone-sensitivity-medium-symbolic</property>
|
||||
<child>
|
||||
<object class="GtkNotebook">
|
||||
<property name="show-border">0</property>
|
||||
<child type="action-end">
|
||||
<object class="GtkMenuButton">
|
||||
<property name="valign">center</property>
|
||||
<property name="popover">notebook_info_popover2</property>
|
||||
<property name="icon-name">emblem-important-symbolic</property>
|
||||
<property name="relief">none</property>
|
||||
<style>
|
||||
<class name="circular"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkNotebookPage">
|
||||
<property name="tab-expand">1</property>
|
||||
@@ -3143,6 +3154,7 @@ bad things might happen.</property>
|
||||
<property name="use-header-bar">1</property>
|
||||
<property name="title" translatable="yes">Zelda</property>
|
||||
<property name="hide-on-close">1</property>
|
||||
<property name="default-widget">act_action_dialog</property>
|
||||
<child internal-child="content_area">
|
||||
<object class="GtkBox">
|
||||
<child>
|
||||
@@ -3164,8 +3176,6 @@ bad things might happen.</property>
|
||||
</child>
|
||||
<child type="action">
|
||||
<object class="GtkButton" id="act_action_dialog">
|
||||
<property name="can-default">1</property>
|
||||
<property name="has-default">1</property>
|
||||
<property name="label" translatable="yes">_Act</property>
|
||||
<property name="use-underline">1</property>
|
||||
</object>
|
||||
@@ -3303,6 +3313,7 @@ bad things might happen.</property>
|
||||
<property name="use-header-bar">1</property>
|
||||
<property name="title" translatable="yes">Choose one</property>
|
||||
<property name="hide-on-close">1</property>
|
||||
<property name="default-widget">select_selection_dialog</property>
|
||||
<child internal-child="content_area">
|
||||
<object class="GtkBox">
|
||||
<child>
|
||||
@@ -3324,8 +3335,6 @@ bad things might happen.</property>
|
||||
</child>
|
||||
<child type="action">
|
||||
<object class="GtkButton" id="select_selection_dialog">
|
||||
<property name="can-default">1</property>
|
||||
<property name="has-default">1</property>
|
||||
<property name="label" translatable="yes">_Select</property>
|
||||
<property name="use-underline">1</property>
|
||||
</object>
|
||||
@@ -3386,6 +3395,7 @@ bad things might happen.</property>
|
||||
<layout>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
<property name="column-span">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
@@ -3398,22 +3408,52 @@ bad things might happen.</property>
|
||||
<layout>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
<property name="column-span">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkExpander">
|
||||
<child type="label">
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Extra Info</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry">
|
||||
<property name="placeholder-text">Tell me anything…</property>
|
||||
</object>
|
||||
</child>
|
||||
<layout>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">2</property>
|
||||
<property name="column-span">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuButton">
|
||||
<property name="halign">end</property>
|
||||
<property name="icon-name">emblem-system-symbolic</property>
|
||||
<property name="menu-model">gear_menu</property>
|
||||
<layout>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">3</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="open_popover_button">
|
||||
<property name="halign">end</property>
|
||||
<property name="halign">fill</property>
|
||||
<property name="label">_Open</property>
|
||||
<property name="use-underline">1</property>
|
||||
<property name="sensitive">0</property>
|
||||
<property name="can-default">1</property>
|
||||
<style>
|
||||
<class name="suggested-action"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">2</property>
|
||||
<property name="left-attach">2</property>
|
||||
<property name="top-attach">3</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
@@ -3439,8 +3479,9 @@ bad things might happen.</property>
|
||||
</widgets>
|
||||
</object>
|
||||
<object class="GtkPopover" id="notebook_info_popover">
|
||||
<property name="modal">0</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="notebook_info_label">
|
||||
<object class="GtkLabel">
|
||||
<property name="label">No updates at this time</property>
|
||||
<accessibility>
|
||||
<role type="static"/>
|
||||
@@ -3448,4 +3489,39 @@ bad things might happen.</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkPopover" id="notebook_info_popover3">
|
||||
<property name="modal">0</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">You're in too deep!</property>
|
||||
<accessibility>
|
||||
<role type="static"/>
|
||||
</accessibility>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkPopover" id="notebook_info_popover2">
|
||||
<property name="modal">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">horizontal</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Hidden gems:</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuButton">
|
||||
<property name="valign">center</property>
|
||||
<property name="popover">notebook_info_popover3</property>
|
||||
<property name="icon-name">emblem-important-symbolic</property>
|
||||
<property name="relief">none</property>
|
||||
<style>
|
||||
<class name="circular"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
|
||||
@@ -231,6 +231,7 @@ gdk_surface_get_scale_factor
|
||||
gdk_surface_set_opaque_region
|
||||
gdk_surface_create_gl_context
|
||||
gdk_surface_create_vulkan_context
|
||||
gdk_surface_create_cairo_context
|
||||
|
||||
<SUBSECTION>
|
||||
gdk_surface_queue_expose
|
||||
@@ -988,7 +989,6 @@ gdk_wayland_device_get_wl_seat
|
||||
gdk_wayland_display_get_wl_compositor
|
||||
gdk_wayland_display_get_wl_display
|
||||
gdk_wayland_display_query_registry
|
||||
gdk_wayland_surface_new_subsurface
|
||||
gdk_wayland_surface_get_wl_surface
|
||||
GdkWaylandSurfaceExported
|
||||
gdk_wayland_surface_export_handle
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
<SECTION>
|
||||
<FILE>GskRenderer</FILE>
|
||||
gsk_renderer_new_for_surface
|
||||
gsk_renderer_get_surface
|
||||
gsk_renderer_realize
|
||||
gsk_renderer_unrealize
|
||||
gsk_renderer_is_realized
|
||||
gsk_renderer_render
|
||||
gsk_renderer_render_texture
|
||||
<SUBSECTION>
|
||||
gsk_renderer_new_for_surface
|
||||
gsk_gl_renderer_new
|
||||
gsk_cairo_renderer_new
|
||||
gsk_vulkan_renderer_new
|
||||
gsk_broadway_renderer_new
|
||||
<SUBSECTION Standard>
|
||||
GSK_IS_RENDERER
|
||||
GSK_RENDERER
|
||||
@@ -62,6 +67,7 @@ gsk_outset_shadow_node_get_spread
|
||||
gsk_outset_shadow_node_get_blur_radius
|
||||
gsk_cairo_node_new
|
||||
gsk_cairo_node_get_draw_context
|
||||
gsk_cairo_node_peek_surface
|
||||
gsk_container_node_new
|
||||
gsk_container_node_get_n_children
|
||||
gsk_container_node_get_child
|
||||
@@ -88,6 +94,7 @@ GskShadow
|
||||
gsk_shadow_node_new
|
||||
gsk_shadow_node_peek_shadow
|
||||
gsk_shadow_node_get_n_shadows
|
||||
gsk_shadow_node_get_child
|
||||
GskBlendMode
|
||||
gsk_blend_node_new
|
||||
gsk_blend_node_get_bottom_child
|
||||
@@ -103,6 +110,7 @@ gsk_text_node_peek_glyphs
|
||||
gsk_text_node_peek_color
|
||||
gsk_text_node_get_x
|
||||
gsk_text_node_get_y
|
||||
gsk_text_node_get_num_glyphs
|
||||
gsk_blur_node_new
|
||||
gsk_blur_node_get_child
|
||||
gsk_blur_node_get_radius
|
||||
@@ -162,6 +170,7 @@ gsk_transform_to_translate
|
||||
gsk_transform_transform
|
||||
gsk_transform_invert
|
||||
gsk_transform_matrix
|
||||
gsk_transform_matrix_with_category
|
||||
gsk_transform_translate
|
||||
gsk_transform_translate_3d
|
||||
gsk_transform_rotate
|
||||
|
||||
373
docs/reference/gtk/actions.xml
Normal file
373
docs/reference/gtk/actions.xml
Normal file
@@ -0,0 +1,373 @@
|
||||
<?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="chap-actions">
|
||||
<refmeta>
|
||||
<refentrytitle>The GTK Action Model</refentrytitle>
|
||||
<manvolnum>3</manvolnum>
|
||||
<refmiscinfo>GTK Library</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>The GTK Action Model</refname>
|
||||
<refpurpose>
|
||||
How actions are used in GTK
|
||||
</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
|
||||
<refsect1 id="actions-overview">
|
||||
<title>Overview of actions in GTK</title>
|
||||
|
||||
<para>
|
||||
This chapter describes in detail how GTK uses actions to connect
|
||||
activatable UI elements to callbacks. GTK inherits the underlying
|
||||
architecture of GAction and GMenu for describing abstract actions
|
||||
and menus from the GIO library.
|
||||
</para>
|
||||
|
||||
<refsect2>
|
||||
<title>Basics about actions</title>
|
||||
|
||||
<para>
|
||||
A GAction is essentially a way to tell the toolkit about a
|
||||
piece of functionality in your program, and to give it a name.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Actions are purely functional. They do not contain any
|
||||
presentational information.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
An action has four pieces of information associated with it:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
a name as an identifier (usually all-lowercase, untranslated
|
||||
English string)
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
an enabled flag indicating if the action can be activated or
|
||||
not (like the "sensitive" property on widgets)
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
an optional state value, for stateful actions (like a boolean
|
||||
for toggles)
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
an optional parameter type, used when activating the action
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
An action supports two operations. You can activate it, which
|
||||
requires passing a parameter of the correct type
|
||||
And you can request to change the actions state (for stateful
|
||||
actions) to a new state value of the correct type.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Here are some rules about an action:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
the name is immutable (in the sense that it will never
|
||||
change) and it is never %NULL
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
the enabled flag can change
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
the parameter type is immutable
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
the parameter type is optional: it can be %NULL
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
if the parameter type is %NULL then action activation must
|
||||
be done without a parameter (ie: a %NULL GVariant pointer)
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
if the parameter type is non-%NULL then the parameter must
|
||||
have this type
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
the state can change, but it cannot change type
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
if the action was stateful when it was created, it will
|
||||
always have a state and it will always have exactly the same
|
||||
type (such as boolean or string)
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
if the action was stateless when it was created, it can never
|
||||
have a state
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
you can only request state changes on stateful actions and it
|
||||
is only possible to request that the state change to a value
|
||||
of the same type as the existing state
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
An action does not have any sort of presentational information
|
||||
such as a label, an icon or a way of creating a widget from it.
|
||||
</para>
|
||||
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>Action state and parameters</title>
|
||||
|
||||
<para>
|
||||
Most actions in your application will be stateless actions with
|
||||
no parameters. These typically appear as menu items with no
|
||||
special decoration. An example is "quit".
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Stateful actions are used to represent an action which has a
|
||||
closely-associated state of some kind. A good example is a
|
||||
"fullscreen" action. For this case, you'd expect to see a
|
||||
checkmark next to the menu item when the fullscreen option
|
||||
is active. This is usually called a toggle action, and it has
|
||||
a boolean state. By convention, toggle actions have no parameter
|
||||
type for activation: activating the action always toggles the
|
||||
state.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Another common case is to have an action representing a
|
||||
enumeration of possible values of a given type (typically
|
||||
string). This is often called a radio action and is usually
|
||||
represented in the user interface with radio buttons or radio
|
||||
menu items, or sometimes a combobox. A good example is
|
||||
"text-justify" with possible values "left", "center", and
|
||||
"right". By convention, these types of actions have a parameter
|
||||
type equal to their state type, and activating them with a
|
||||
particular parameter value is equivalent to changing their
|
||||
state to that value.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This approach to handling radio buttons is different than many
|
||||
other action systems such as GtkAction. With GAction, there is
|
||||
only one action for "text-justify" and "left", "center" and
|
||||
"right" are possible states on that action. There are not three
|
||||
separate "justify-left", "justify-center" and "justify-right"
|
||||
actions.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The final common type of action is a stateless action with a
|
||||
parameter. This is typically used for actions like
|
||||
"open-bookmark" where the parameter to the action would be
|
||||
the identifier of the bookmark to open.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Because some types of actions cannot be invoked without a
|
||||
parameter, it is often important to specify a parameter when
|
||||
referring to the action from a place where it will be invoked
|
||||
(such as from a radio button that sets the state to a particular
|
||||
value or from a menu item that opens a specific bookmark). In
|
||||
these contexts, the value used for the action parameter is
|
||||
typically called the target of the action.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Even though toggle actions have a state, they do not have a
|
||||
parameter. Therefore, a target value is not needed when
|
||||
referring to them — they will always be toggled on activation.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Most APIs that allow using a GAction (such as GMenuModel and
|
||||
GtkActionable) allow use of detailed action names. This is a
|
||||
convenient way of specifying an action name and an action target
|
||||
with a single string.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In the case that the action target is a string with no unusual
|
||||
characters (ie: only alpha-numeric, plus '-' and '.') then you
|
||||
can use a detailed action name of the form "justify::left" to
|
||||
specify the justify action with a target of left.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In the case that the action target is not a string, or contains
|
||||
unusual characters, you can use the more general format
|
||||
"action-name(5)", where the "5" here is any valid text-format
|
||||
GVariant (ie: a string that can be parsed by g_variant_parse()).
|
||||
Another example is "open-bookmark('http://gnome.org/')".
|
||||
</para>
|
||||
|
||||
<para>
|
||||
You can convert between detailed action names and split-out
|
||||
action names and target values using g_action_parse_detailed_action_name()
|
||||
and g_action_print_detailed_action_name() but usually you will
|
||||
not need to. Most APIs will provide both ways of specifying
|
||||
actions with targets.
|
||||
</para>
|
||||
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>Action scopes</title>
|
||||
|
||||
<para>
|
||||
Actions are always scoped to a particular object on which they
|
||||
operate.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In GTK, actions are typically scoped to either an application
|
||||
or a window, but any widget can have actions associated with it.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Actions scoped to windows should be the actions that
|
||||
specifically impact that window. These are actions like
|
||||
"fullscreen" and "close", or in the case that a window contains
|
||||
a document, "save" and "print".
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Actions that impact the application as a whole rather than one
|
||||
specific window are scoped to the application. These are actions
|
||||
like "about" and "preferences".
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If a particular action is scoped to a window then it is scoped
|
||||
to a specific window. Another way of saying this: if your
|
||||
application has a "fullscreen" action that applies to windows
|
||||
and it has three windows, then it will have three fullscreen
|
||||
actions: one for each window.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Having a separate action per-window allows for each window to
|
||||
have a separate state for each instance of the action as well
|
||||
as being able to control the enabled state of the action on a
|
||||
per-window basis.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Actions are added to their relevant scope (application or
|
||||
window) either using the GActionMap interface, or by using
|
||||
gtk_widget_insert_action_group().
|
||||
</para>
|
||||
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>Action groups and action maps</title>
|
||||
|
||||
<para>
|
||||
Actions rarely occurs in isolation. It is common to have groups
|
||||
of related actions, which are represented by instances of the
|
||||
GActionGroup interface.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Action maps are a variant of action groups that allow to change
|
||||
the name of the action as it is looked up. In GTK, the convention
|
||||
is to add a prefix to the action name to indicate the scope of
|
||||
the actions, such as "app." for the actions with application scope
|
||||
or "win." for those with window scope.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
When referring to actions on a GActionMap only the name of the
|
||||
action itself is used (ie: "quit", not "app.quit"). The
|
||||
"app.quit" form is only used when referring to actions from
|
||||
places like a GMenu or GtkActionable widget where the scope
|
||||
of the action is not already known.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
GtkApplication and GtkApplicationWindow implement the GActionMap
|
||||
interface, so you can just add actions directly to them. For
|
||||
other widgets, use gtk_widget_insert_action_group() to add
|
||||
actions to it.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If you want to insert several actions at the same time, it is
|
||||
typically faster and easier to use GActionEntry.
|
||||
</para>
|
||||
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>Connecting actions to widgets</title>
|
||||
|
||||
<para>
|
||||
Any widget that implements the GtkActionable interface can
|
||||
be connected to an action just by setting the ::action-name
|
||||
property. If the action has a parameter, you will also need
|
||||
to set the ::action-target property.
|
||||
Widgets that implement GtkAction include GtkSwitch, GtkButton,
|
||||
GtkMenuItem and their respective subclasses.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Another of obtaining widgets that are connected to actions is
|
||||
to create a menu using a GMenu menu model. GMenu provides an
|
||||
abstract way to describe typical menus: nested groups of items
|
||||
where each item can have a label, and icon, and an action.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Typical uses of GMenu inside GTK are to set up an application
|
||||
menu or menubar with gtk_application_set_app_menu() or
|
||||
gtk_application_set_menubar(). Another, maybe more common use
|
||||
is to create a popover for a menubutton, using
|
||||
gtk_menu_button_set_menu_model().
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Unlike traditional menus, those created from menu models don't
|
||||
have keyboard accelerators associated with menu items. Instead,
|
||||
GtkApplication offers the gtk_application_set_accels_for_action()
|
||||
API to associate keyboard shortcuts with actions.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>Activation</title>
|
||||
|
||||
<para>
|
||||
When a widget with a connected action is activated, GTK finds
|
||||
the action to activate by walking up the widget hierarchy,
|
||||
looking for a matching action, ending up at the GtkApplication.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>Built-in Actions</title>
|
||||
|
||||
<para>
|
||||
GTK uses actions for its own purposes in a number places. These
|
||||
built-in actions can sometimes be activated by applications, and
|
||||
you should avoid naming conflicts with them when creating your
|
||||
own actions.
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>default.activate</term>
|
||||
<listitem><para>Activates the default widget in a context
|
||||
(typically a GtkWindow, GtkDialog or GtkPopover)
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</para>
|
||||
|
||||
</refsect2>
|
||||
|
||||
</refsect1>
|
||||
</refentry>
|
||||
@@ -12,7 +12,7 @@
|
||||
<refnamediv>
|
||||
<refname>The GTK Drawing Model</refname>
|
||||
<refpurpose>
|
||||
The GTK drawing model in detail
|
||||
How widgets draw
|
||||
</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
|
||||
@@ -24,8 +24,9 @@
|
||||
<xi:include href="xml/getting_started.xml"/>
|
||||
<xi:include href="resources.sgml" />
|
||||
<xi:include href="xml/question_index.sgml" />
|
||||
<xi:include href="drawing-model.xml" />
|
||||
<xi:include href="xml/drawing-model.xml" />
|
||||
<xi:include href="xml/input-handling.xml" />
|
||||
<xi:include href="xml/actions.xml" />
|
||||
</part>
|
||||
|
||||
<part id="gtkobjects">
|
||||
|
||||
@@ -1779,7 +1779,6 @@ GtkMenu
|
||||
GtkArrowPlacement
|
||||
gtk_menu_new
|
||||
gtk_menu_new_from_model
|
||||
gtk_menu_set_display
|
||||
gtk_menu_reorder_child
|
||||
gtk_menu_popup_at_rect
|
||||
gtk_menu_popup_at_widget
|
||||
@@ -4433,7 +4432,6 @@ gtk_widget_event
|
||||
gtk_widget_activate
|
||||
gtk_widget_is_focus
|
||||
gtk_widget_grab_focus
|
||||
gtk_widget_grab_default
|
||||
gtk_widget_set_name
|
||||
gtk_widget_get_name
|
||||
gtk_widget_set_sensitive
|
||||
@@ -4504,8 +4502,6 @@ gtk_widget_compute_point
|
||||
gtk_widget_contains
|
||||
GtkPickFlags
|
||||
gtk_widget_pick
|
||||
gtk_widget_get_can_default
|
||||
gtk_widget_set_can_default
|
||||
gtk_widget_get_can_focus
|
||||
gtk_widget_set_can_focus
|
||||
gtk_widget_get_focus_on_click
|
||||
@@ -4538,13 +4534,15 @@ gtk_widget_get_realized
|
||||
gtk_widget_get_mapped
|
||||
gtk_widget_device_is_shadowed
|
||||
gtk_widget_get_modifier_mask
|
||||
gtk_widget_insert_action_group
|
||||
gtk_widget_get_opacity
|
||||
gtk_widget_set_opacity
|
||||
gtk_widget_get_overflow
|
||||
gtk_widget_set_overflow
|
||||
gtk_widget_insert_action_group
|
||||
gtk_widget_list_action_prefixes
|
||||
gtk_widget_get_action_group
|
||||
gtk_widget_activate_action
|
||||
gtk_widget_activate_default
|
||||
gtk_widget_measure
|
||||
gtk_widget_snapshot_child
|
||||
gtk_widget_get_next_sibling
|
||||
@@ -4647,8 +4645,6 @@ gtk_window_set_resizable
|
||||
gtk_window_get_resizable
|
||||
gtk_window_add_accel_group
|
||||
gtk_window_remove_accel_group
|
||||
gtk_window_activate_focus
|
||||
gtk_window_activate_default
|
||||
gtk_window_set_modal
|
||||
gtk_window_set_default_size
|
||||
gtk_window_set_hide_on_close
|
||||
@@ -4671,7 +4667,7 @@ gtk_window_propagate_key_event
|
||||
gtk_window_get_focus
|
||||
gtk_window_set_focus
|
||||
gtk_window_get_default_widget
|
||||
gtk_window_set_default
|
||||
gtk_window_set_default_widget
|
||||
gtk_window_present
|
||||
gtk_window_present_with_time
|
||||
gtk_window_close
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
]>
|
||||
<refentry id="chap-input-handling">
|
||||
<refmeta>
|
||||
<refentrytitle>The GTK Input and Event Handling Model</refentrytitle>
|
||||
<refentrytitle>The GTK Input Model</refentrytitle>
|
||||
<manvolnum>3</manvolnum>
|
||||
<refmiscinfo>GTK Library</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>The GTK Input and Event Handling Model</refname>
|
||||
<refname>The GTK Input Model</refname>
|
||||
<refpurpose>
|
||||
GTK input and event handling in detail
|
||||
input and event handling in detail
|
||||
</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
@@ -52,13 +52,12 @@
|
||||
with any pointing device or keyboard.
|
||||
</para>
|
||||
|
||||
<!-- input events: button, touch, key, motion, etc -->
|
||||
<para>
|
||||
When a user interacts with an input device (e.g. moves a mouse or presses
|
||||
a key on the keyboard), GTK receives events from the windowing system.
|
||||
These are typically directed at a specific window - for pointer events,
|
||||
the window under the pointer (grabs complicate this), for keyboard events,
|
||||
the window with the keyboard focus.
|
||||
These are typically directed at a specific surface - for pointer events,
|
||||
the surface under the pointer (grabs complicate this), for keyboard events,
|
||||
the surface with the keyboard focus.
|
||||
</para>
|
||||
<para>
|
||||
GDK translates these raw windowing system events into #GdkEvents.
|
||||
@@ -81,9 +80,10 @@
|
||||
</simplelist>
|
||||
</para>
|
||||
<para>
|
||||
When GTK is initialized, it sets up an event handler function with
|
||||
gdk_event_handler_set(), which receives all of these input events
|
||||
(as well as others, for instance window management related events).
|
||||
When GTK creates a GdkSurface, it connects to the ::event signal
|
||||
on it, which receives all of these input events. Surfaces have
|
||||
have signals and properties, e.g. to deal with window management
|
||||
related events.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
@@ -91,8 +91,8 @@
|
||||
<title>Event propagation</title>
|
||||
|
||||
<para>
|
||||
For widgets which have a #GdkSurface set, events are received from the
|
||||
windowing system and passed to gtk_main_do_event(). See its documentation
|
||||
The function which initially receives input events on the GTK
|
||||
side is gtk_main_do_event(). See its documentation
|
||||
for details of what it does: compression of enter/leave events,
|
||||
identification of the widget receiving the event, pushing the event onto a
|
||||
stack for gtk_get_current_event(), and propagating the event to the
|
||||
@@ -120,62 +120,55 @@
|
||||
|
||||
<para>
|
||||
An event is propagated to a widget using gtk_propagate_event().
|
||||
Propagation differs between event types: key events (%GDK_KEY_PRESS,
|
||||
%GDK_KEY_RELEASE) are delivered to the top-level #GtkWindow; other events
|
||||
are propagated down and up the widget hierarchy in three phases (see
|
||||
#GtkPropagationPhase).
|
||||
Propagation goes down and up the widget hierarchy in three phases
|
||||
(see #GtkPropagationPhase) towards a target widget.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For key events, the top-level window’s default #GtkWindow::key-press-event
|
||||
and #GtkWindow::key-release-event signal handlers handle mnemonics and
|
||||
accelerators first. Other key presses are then passed to
|
||||
gtk_window_propagate_key_event() which propagates the event upwards from
|
||||
the window’s current focus widget (gtk_window_get_focus()) to the
|
||||
top-level.
|
||||
For key events, the top-level window gets a first shot at activating
|
||||
mnemonics and accelerators. If that does not consume the events,
|
||||
the target widget for event propagation is window's current focus
|
||||
widget (see gtk_window_get_focus()).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For other events, in the first phase (the “capture” phase) the event is
|
||||
delivered to each widget from the top-most (for example, the top-level
|
||||
For pointer events, the target widget is determined by picking
|
||||
the widget at the events coordinates (see gtk_window_pick()).
|
||||
</para>
|
||||
|
||||
<para>In the first phase (the “capture” phase) the event is
|
||||
delivered to each widget from the top-most (the top-level
|
||||
#GtkWindow or grab widget) down to the target #GtkWidget.
|
||||
<link linkend="event-controllers-and-gestures">Gestures</link> that are
|
||||
attached with %GTK_PHASE_CAPTURE get a chance to react to the event.
|
||||
<link linkend="event-controllers-and-gestures">Event
|
||||
controllers</link> that are attached with %GTK_PHASE_CAPTURE
|
||||
get a chance to react to the event.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
After the “capture” phase, the widget that was intended to be the
|
||||
destination of the event will run gestures attached to it with
|
||||
%GTK_PHASE_TARGET. This is known as the “target” phase, and only
|
||||
happens on that widget.
|
||||
destination of the event will run event controllers attached to
|
||||
it with %GTK_PHASE_TARGET. This is known as the “target” phase,
|
||||
and only happens on that widget.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Next, the #GtkWidget::event signal is emitted.
|
||||
Handling these signals was the primary way to handle input in GTK widgets
|
||||
before gestures were introduced. The signal is emitted from
|
||||
the target widget up to the top-level, as part of the “bubble” phase.
|
||||
In the last phase (the “bubble” phase), the event is delivered
|
||||
to each widget from the target to the top-most, and event
|
||||
controllers attached with %GTK_PHASE_BUBBLE are run.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The default handlers for the event signals send the event
|
||||
to gestures that are attached with %GTK_PHASE_BUBBLE. Therefore,
|
||||
gestures in the “bubble” phase are only used if the widget does
|
||||
not have its own event handlers, or takes care to chain up to the
|
||||
default #GtkWidget handlers.
|
||||
Events are not delivered to a widget which is insensitive or
|
||||
unmapped.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Events are not delivered to a widget which is insensitive or unmapped.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Any time during the propagation phase, a widget may indicate that a
|
||||
received event was consumed and propagation should therefore be stopped.
|
||||
In traditional event handlers, this is hinted by returning %GDK_EVENT_STOP.
|
||||
If gestures are used, this may happen when the widget tells the gesture
|
||||
to claim the event touch sequence (or the pointer events) for its own. See the
|
||||
"gesture states" section below to know more of the latter.
|
||||
Any time during the propagation phase, a controller may indicate
|
||||
that a received event was consumed and propagation should
|
||||
therefore be stopped. If gestures are used, this may happen
|
||||
when the gesture claims the event touch sequence (or the
|
||||
pointer events) for its own. See the “gesture states” section
|
||||
below to learn more about gestures and sequences.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
@@ -183,27 +176,10 @@
|
||||
<title>Touch events</title>
|
||||
|
||||
<para>
|
||||
Touch events are emitted as events of type %GDK_TOUCH_BEGIN, %GDK_TOUCH_UPDATE or
|
||||
%GDK_TOUCH_END, those events contain an “event sequence” that univocally identifies
|
||||
the physical touch until it is lifted from the device.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
On some windowing platforms, multitouch devices perform pointer emulation, this works
|
||||
by granting a “pointer emulating” hint to one of the currently interacting touch
|
||||
sequences, which will be reported on every #GdkEventTouch event from that sequence. By
|
||||
default, if a widget didn't request touch events by setting %GDK_TOUCH_MASK on its
|
||||
event mask and didn't override #GtkWidget::touch-event, GTK will transform these
|
||||
“pointer emulating” events into semantically similar #GdkEventButton and #GdkEventMotion
|
||||
events. Depending on %GDK_TOUCH_MASK being in the event mask or not, non-pointer-emulating
|
||||
sequences could still trigger gestures or just get filtered out, regardless of the widget
|
||||
not handling those directly.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If the widget sets %GDK_TOUCH_MASK on its event mask and doesn't chain up on
|
||||
#GtkWidget::touch-event, only touch events will be received, and no pointer emulation
|
||||
will be performed.
|
||||
Touch events are emitted as events of type %GDK_TOUCH_BEGIN,
|
||||
%GDK_TOUCH_UPDATE or %GDK_TOUCH_END, those events contain an
|
||||
“event sequence” that univocally identifies the physical touch
|
||||
until it is lifted from the device.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
@@ -211,43 +187,66 @@
|
||||
<title>Grabs</title>
|
||||
|
||||
<para>
|
||||
Grabs are a method to claim all input events from a device, they happen
|
||||
either implicitly on pointer and touch devices, or explicitly. Implicit grabs
|
||||
happen on user interaction, when a #GdkEventButtonPress happens, all events from
|
||||
then on, until after the corresponding #GdkEventButtonRelease, will be reported
|
||||
to the widget that got the first event. Likewise, on touch events, every
|
||||
#GdkEventSequence will deliver only events to the widget that received its
|
||||
%GDK_TOUCH_BEGIN event.
|
||||
Grabs are a method to claim all input events from a device,
|
||||
they happen either implicitly on pointer and touch devices,
|
||||
or explicitly. Implicit grabs happen on user interaction, when
|
||||
a #GdkEventButtonPress happens, all events from then on, until
|
||||
after the corresponding #GdkEventButtonRelease, will be reported
|
||||
to the widget that got the first event. Likewise, on touch events,
|
||||
every #GdkEventSequence will deliver only events to the widget
|
||||
that received its %GDK_TOUCH_BEGIN event.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Explicit grabs happen programatically (both activation and deactivation),
|
||||
and can be either system-wide (GDK grabs) or application-wide (GTK grabs).
|
||||
On the windowing platforms that support it, GDK grabs will prevent any
|
||||
interaction with any other application/window/widget than the grabbing one,
|
||||
whereas GTK grabs will be effective only within the application (across all
|
||||
its windows), still allowing for interaction with other applications.
|
||||
Explicit grabs happen programatically (both activation and
|
||||
deactivation), and can be either system-wide (GDK grabs) or
|
||||
application-wide (GTK grabs). On the windowing platforms that
|
||||
support it, GDK grabs will prevent any interaction with any other
|
||||
application/window/widget than the grabbing one, whereas GTK grabs
|
||||
will be effective only within the application (across all its
|
||||
windows), still allowing for interaction with other applications.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
But one important aspect of grabs is that they may potentially happen at any
|
||||
point somewhere else, even while the pointer/touch device is already grabbed.
|
||||
This makes it necessary for widgets to handle the cancellation of any ongoing
|
||||
interaction. Depending on whether a GTK or GDK grab is causing this, the
|
||||
widget will respectively receive a #GtkWidget::grab-notify signal, or a
|
||||
But one important aspect of grabs is that they may potentially
|
||||
happen at any point somewhere else, even while the pointer/touch
|
||||
device is already grabbed. This makes it necessary for widgets to
|
||||
handle the cancellation of any ongoing interaction. Depending on
|
||||
whether a GTK or GDK grab is causing this, the widget will
|
||||
respectively receive a #GtkWidget::grab-notify signal, or a
|
||||
#GdkEventGrabBroken event.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
On gestures, these signals are handled automatically, causing the gesture
|
||||
to cancel all tracked pointer/touch events, and signal the end of recognition.
|
||||
On gestures, these signals are handled automatically, causing the
|
||||
gesture to cancel all tracked pointer/touch events, and signal
|
||||
the end of recognition.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>Keyboard input</title>
|
||||
|
||||
<!-- focus, tab, directional navigation -->
|
||||
<para>
|
||||
Every #GtkWindow maintains a single focus location (in
|
||||
the ::focus-widget property). The focus widget is the
|
||||
target widget for key events sent to the window. Only
|
||||
widgets which have ::can-focus set to %TRUE can become
|
||||
the focus. Typically these are input controls such as
|
||||
entries or text fields, but e.g. buttons can take the
|
||||
focus too.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Input widgets can be given the focus by clicking on them,
|
||||
but focus can also be moved around with certain key
|
||||
events (this is known as “keyboard navigation”). GTK
|
||||
reserves the Tab key to move the focus to the next location,
|
||||
and Shift-Tab to move it back to the previous one. In addition
|
||||
many containers allow “directional navigation” with the
|
||||
arrow keys.
|
||||
</para>
|
||||
|
||||
<!-- mnemonics, accelerators, bindings -->
|
||||
</refsect2>
|
||||
|
||||
@@ -255,37 +254,43 @@
|
||||
<title>Event controllers and gestures</title>
|
||||
|
||||
<para>
|
||||
Event controllers are standalone objects that can perform specific actions
|
||||
upon received #GdkEvents. These are tied to a #GtkWidget, and can be told of
|
||||
the event propagation phase at which they will manage the events.
|
||||
Event controllers are standalone objects that can perform
|
||||
specific actions upon received #GdkEvents. These are tied
|
||||
to a #GtkWidget, and can be told of the event propagation
|
||||
phase at which they will manage the events.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Gestures are a set of specific controllers that are prepared to handle pointer
|
||||
and/or touch events, each gestures implementation attempts to recognize specific
|
||||
actions out the received events, notifying of the state/progress accordingly to
|
||||
let the widget react to those. On multi-touch gestures, every interacting touch
|
||||
sequence will be tracked independently.
|
||||
Gestures are a set of specific controllers that are prepared
|
||||
to handle pointer and/or touch events, each gesture
|
||||
implementation attempts to recognize specific actions out the
|
||||
received events, notifying of the state/progress accordingly to
|
||||
let the widget react to those. On multi-touch gestures, every
|
||||
interacting touch sequence will be tracked independently.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Being gestures “simple” units, it is not uncommon to tie several together to
|
||||
perform higher level actions, grouped gestures handle the same event sequences
|
||||
simultaneously, and those sequences share a same state across all grouped
|
||||
Since gestures are “simple” units, it is not uncommon to tie
|
||||
several together to perform higher level actions, grouped
|
||||
gestures handle the same event sequences simultaneously, and
|
||||
those sequences share a same state across all grouped
|
||||
gestures. Some examples of grouping may be:
|
||||
|
||||
<simplelist>
|
||||
<member>
|
||||
A “drag” and a “swipe” gestures may want grouping. The former will report
|
||||
events as the dragging happens, the latter will tell the swipe X/Y velocities
|
||||
only after gesture has finished.
|
||||
A “drag” and a “swipe” gestures may want grouping.
|
||||
The former will report events as the dragging happens,
|
||||
the latter will tell the swipe X/Y velocities only after
|
||||
recognition has finished.
|
||||
</member>
|
||||
<member>
|
||||
Grouping a “drag” gesture with a “pan” gesture will only effectively allow
|
||||
dragging in the panning orientation, as both gestures share state.
|
||||
Grouping a “drag” gesture with a “pan” gesture will only
|
||||
effectively allow dragging in the panning orientation, as
|
||||
both gestures share state.
|
||||
</member>
|
||||
<member>
|
||||
If “press” and “long press” are wanted simultaneously, those would need grouping.
|
||||
If “press” and “long press” are wanted simultaneously,
|
||||
those would need grouping.
|
||||
</member>
|
||||
</simplelist>
|
||||
</para>
|
||||
@@ -294,34 +299,39 @@
|
||||
<refsect2>
|
||||
<title>Gesture states</title>
|
||||
<para>
|
||||
Gestures have a notion of “state” for each individual touch sequence. When events
|
||||
from a touch sequence are first received, the touch sequence will have “none” state,
|
||||
this means the touch sequence is being handled by the gesture to possibly trigger
|
||||
Gestures have a notion of “state” for each individual touch
|
||||
sequence. When events from a touch sequence are first received,
|
||||
the touch sequence will have “none” state, this means the touch
|
||||
sequence is being handled by the gesture to possibly trigger
|
||||
actions, but the event propagation will not be stopped.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
When the gesture enters recognition, or at a later point in time, the widget may
|
||||
choose to claim the touch sequences (individually or as a group), hence stopping
|
||||
event propagation after the event is run through every gesture in that widget and
|
||||
propagation phase. Anytime this happens, the touch sequences are cancelled downwards
|
||||
the propagation chain, to let these know that no further events will be sent.
|
||||
When the gesture enters recognition, or at a later point in time,
|
||||
the widget may choose to claim the touch sequences (individually
|
||||
or as a group), hence stopping event propagation after the event
|
||||
is run through every gesture in that widget and propagation phase.
|
||||
Anytime this happens, the touch sequences are cancelled downwards
|
||||
the propagation chain, to let these know that no further events
|
||||
will be sent.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Alternatively, or at a later point in time, the widget may choose to deny the touch
|
||||
sequences, thus letting those go through again in event propagation. When this happens
|
||||
in the capture phase, and if there are no other claiming gestures in the widget,
|
||||
Alternatively, or at a later point in time, the widget may choose
|
||||
to deny the touch sequences, thus letting those go through again
|
||||
in event propagation. When this happens in the capture phase, and
|
||||
if there are no other claiming gestures in the widget,
|
||||
a %GDK_TOUCH_BEGIN/%GDK_BUTTON_PRESS event will be emulated and
|
||||
propagated downwards, in order to preserve consistency.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Grouped gestures always share the same state for a given touch sequence, so setting
|
||||
the state on one does transfer the state to the others. They also are mutually exclusive,
|
||||
within a widget there may be only one gesture group claiming a given sequence. If
|
||||
another gesture group claims later that same sequence, the first group will deny the
|
||||
sequence.
|
||||
Grouped gestures always share the same state for a given touch
|
||||
sequence, so setting the state on one does transfer the state to
|
||||
the others. They also are mutually exclusive, within a widget
|
||||
there may be only one gesture group claiming a given sequence.
|
||||
If another gesture group claims later that same sequence, the
|
||||
first group will deny the sequence.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
|
||||
@@ -333,6 +333,7 @@ images = [
|
||||
]
|
||||
|
||||
content_files = [
|
||||
'actions.xml',
|
||||
'broadway.xml',
|
||||
'building.sgml',
|
||||
'compiling.sgml',
|
||||
@@ -368,6 +369,7 @@ content_files = [
|
||||
]
|
||||
|
||||
expand_content_files = [
|
||||
'actions.xml',
|
||||
'compiling.sgml',
|
||||
'drawing-model.xml',
|
||||
'glossary.xml',
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
compared to GTK 3.x. Thankfully, most of the changes are not hard
|
||||
to adapt to and there are a number of steps that you can take to
|
||||
prepare your GTK 3.x application for the switch to GTK 4. After
|
||||
that, there's a small number of adjustments that you may have to do
|
||||
that, there's a number of adjustments that you may have to do
|
||||
when you actually switch your application to build against GTK 4.
|
||||
</para>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
The steps outlined in the following sections assume that your
|
||||
application is working with GTK 3.24, which is the final stable
|
||||
release of GTK 3.x. It includes all the necessary APIs and tools
|
||||
to help you port your application to GTK 4. If you are still using
|
||||
to help you port your application to GTK 4. If you are using
|
||||
an older version of GTK 3.x, you should first get your application
|
||||
to build and work with the latest minor release in the 3.24 series.
|
||||
</para>
|
||||
@@ -84,9 +84,9 @@
|
||||
</para>
|
||||
<para>
|
||||
GTK 4 also removes the GDK_WA_VISUAL flag, and always uses
|
||||
an RGBA visual for windows. To prepare your code for this,
|
||||
use gdk_window_set_visual (gdk_screen_get_rgba_visual ()) after
|
||||
creating your window.
|
||||
an RGBA visual for windows. To prepare your code for this, use
|
||||
<literal>gdk_window_set_visual (gdk_screen_get_rgba_visual ())</literal>
|
||||
after creating your window.
|
||||
</para>
|
||||
<para>
|
||||
GTK 4 also removes the GDK_WA_WMCLASS flag. If you need this
|
||||
@@ -110,7 +110,7 @@
|
||||
<section>
|
||||
<title>Stop using GtkBox:padding, GtkBox:fill and GtkBox:expand</title>
|
||||
<para>
|
||||
GTK4 removes these #GtkBox child properties, so you should not use them.
|
||||
GTK 4 removes these #GtkBox child properties, so you should not use them.
|
||||
You can replace GtkBox:padding using the #GtkWidget:margin properties
|
||||
on your #GtkBox child widgets.
|
||||
</para>
|
||||
@@ -172,35 +172,30 @@
|
||||
<section>
|
||||
<title>Stop using GtkWidget event signals</title>
|
||||
<para>
|
||||
Event controllers and #GtkGestures replace event signals in GTK 4. They
|
||||
have been backported to GTK 3.x so you can prepare for this change.
|
||||
Event controllers and #GtkGestures replace event signals in GTK 4.
|
||||
They have been backported to GTK 3.x so you can prepare for this change.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Set a proper app_id</title>
|
||||
<title>Set a proper application ID</title>
|
||||
<para>
|
||||
In GTK4 we want the application's #GApplication
|
||||
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 GTK3 call g_set_prgname() with the same
|
||||
application id you passed to #GtkApplication. Rename your
|
||||
desktop files to match the application id if needed.
|
||||
order to achieve this with GTK 3.x 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 GTK4.
|
||||
to GTK 4.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Stop using GtkBox's pack-type child property</title>
|
||||
<para>
|
||||
In order to improve performance and simplify the widget, GtkBox lost its
|
||||
'pack-type' child property. In GTK4, every GtkBox instance has a simple
|
||||
list of child widgets that it allocates from start to end.
|
||||
The old behavior of pack-type=END can be emulated by simply making the
|
||||
box child in the center hexpand and right-align the ones at the end.
|
||||
You should be aware that changing the application ID makes your
|
||||
application appear as a new, different app to application installers.
|
||||
You should consult the appstream documentation for best practices
|
||||
around renaming applications.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
@@ -216,6 +211,17 @@
|
||||
have been either impossible or impractical.
|
||||
</para>
|
||||
|
||||
<section>
|
||||
<title>Convert your ui files</title>
|
||||
|
||||
<para>
|
||||
A number of the changes outlined below affect .ui files. The
|
||||
gtk4-builder-tool simplify command can perform many of the
|
||||
necessary changes automatically, when called with the --3to4
|
||||
option. You should always review the resulting changes.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Stop using GdkScreen</title>
|
||||
<para>
|
||||
@@ -301,9 +307,9 @@
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Adapt to coordinate api changes</title>
|
||||
<title>Adapt to coordinate API changes</title>
|
||||
<para>
|
||||
A number of coordinate apis in GTK 3 had _double variants:
|
||||
A number of coordinate APIs in GTK 3 had _double variants:
|
||||
gdk_device_get_position(), gdk_device_get_surface_at_position(),
|
||||
gdk_surface_get_device_position(). These have been changed to use
|
||||
doubles, and the _double variants have been removed. Update your
|
||||
@@ -395,6 +401,10 @@
|
||||
their #GError argument. If you want to handle CSS loading errors,
|
||||
use the #GtkCssProvider::parsing-error signal instead.
|
||||
</para>
|
||||
<para>
|
||||
gtk_css_provider_get_named() has been replaced by
|
||||
gtk_css_provider_load_named().
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -411,7 +421,7 @@
|
||||
<para>
|
||||
GTK 3 used five different virtual functions in GtkWidget to
|
||||
implement size requisition, namely the gtk_widget_get_preferred_width()
|
||||
family of functions. To simplify widget implementations, GTK4 uses
|
||||
family of functions. To simplify widget implementations, GTK 4 uses
|
||||
only one virtual function, GtkWidgetClass::measure() that widgets
|
||||
have to implement.
|
||||
</para>
|
||||
@@ -640,7 +650,7 @@
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Adapt to changes in the API of GtkEntry, GtkSearchEntry adn GtkSpinButton</title>
|
||||
<title>Adapt to changes in the API of GtkEntry, GtkSearchEntry and GtkSpinButton</title>
|
||||
<para>
|
||||
The GtkEditable has been made more useful, and the core functionality of
|
||||
GtkEntry has been broken out as a GtkText widget. GtkEntry, GtkSearchEntry,
|
||||
@@ -675,6 +685,77 @@
|
||||
of the existing GtkFixed container widget.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Adapt to search entry changes</title>
|
||||
<para>
|
||||
The way search entries are connected to global events has changed;
|
||||
gtk_search_entry_handle_event() has been dropped and replaced by
|
||||
gtk_search_entry_set_key_capture_widget() and
|
||||
gtk_event_controller_key_forward().
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Stop using child properties</title>
|
||||
<para>
|
||||
GtkContainer no longer provides facilities for defining and using
|
||||
child properties. If you have custom widgets using child properties,
|
||||
they will have to be converted either to layout properties provided
|
||||
by a layout manager (if they are layout-related), or handled in
|
||||
some other way. One possibility is to use child meta objects,
|
||||
as seen with GtkAssistantPage, GtkStackPage and the like.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Stop using tabular menus</title>
|
||||
<para>
|
||||
Tabular menus were rarely used and complicated the menu code,
|
||||
so they have been removed. If you need complex layout in menu-like
|
||||
popups, consider using a #GtkPopover instead.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Stop using gtk_menu_set_display()</title>
|
||||
<para>
|
||||
This function has been removed. Menus should always be
|
||||
attached to a widget and get their display that way.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Stop using gtk_window_activate_default()</title>
|
||||
<para>
|
||||
The handling of default widgets has been changed, and activating
|
||||
the default now works by calling gtk_widget_activate_default()
|
||||
on the widget that caused the activation.
|
||||
</para>
|
||||
<para>
|
||||
If you have a custom widget that wants to override the default
|
||||
handling, you can provide an implementation of the default.activate
|
||||
action in your widgets' action groups.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Stop setting ::has-default and ::has-focus in .ui files</title>
|
||||
<para>
|
||||
The special handling for the ::has-default and ::has-focus properties
|
||||
has been removed. If you want to define the initial focus or the
|
||||
the default widget in a .ui file, set the ::default-widget or
|
||||
::focus-widget properties of the toplevel window.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Stop using the GtkWidget::display-changed signal</title>
|
||||
<para>
|
||||
To track the current display, use the GtkWidget::root property
|
||||
instead.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
||||
@@ -79,12 +79,30 @@ Use a GdkPixbuf in combination with GtkImage to display images.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>graphene</term>
|
||||
<listitem><para>
|
||||
This is a small library which provides vector and matrix datatypes
|
||||
and operations. graphene provides optimized implementations using
|
||||
various SIMD instruction sets such as SSE.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>GDK</term>
|
||||
<listitem><para>
|
||||
GDK is the abstraction layer that allows GTK to support multiple
|
||||
windowing systems. GDK provides window system facilities on X11, Windows,
|
||||
and OS X.
|
||||
windowing systems. GDK provides window system facilities on Wayland,
|
||||
X11, Windows, and OS X.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>GSK</term>
|
||||
<listitem><para>
|
||||
GSK is a library for creating a scene graph from render nodes,
|
||||
and rendering it using different rendering APIs. GSK provides renderers
|
||||
for OpenGL, Vulkan and cairo.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
@@ -574,6 +574,32 @@ nevertheless.
|
||||
|
||||
</refsect2>
|
||||
|
||||
<refsect2 id="profiling">
|
||||
<title>Profiling</title>
|
||||
|
||||
<para>
|
||||
GTK supports profiling with sysprof. It exports timing information
|
||||
about frameclock phases and various characteristics of GskRenders
|
||||
in a format that can be displayed by sysprof or GNOME Builder.
|
||||
</para>
|
||||
<para>
|
||||
A simple way to capture data is to set the <envar>GTK_TRACE</envar>
|
||||
environment variable. When it is set, GTK will write profiling
|
||||
data to a file called
|
||||
<filename>gtk.<replaceable>PID</replaceable>.syscap</filename>.
|
||||
</para>
|
||||
<para>
|
||||
When launching the application from sysprof, it will set the
|
||||
<envar>SYSPROF_TRACE_FD</envar> environment variable to point
|
||||
GTK at a file descriptor to write profiling data to.
|
||||
</para>
|
||||
<para>
|
||||
When GtkApplication registers with D-Bus, it exports the
|
||||
<literal>org.gnome.Sysprof2.Profiler</literal> interface
|
||||
that lets sysprof request profiling data at runtime.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
|
||||
@@ -24,9 +24,7 @@ gdk_broadway_public_headers = [
|
||||
'gdkbroadwaymonitor.h',
|
||||
]
|
||||
|
||||
# Broadway backend headers aren't installed it seems
|
||||
#install_headers(gdk_broadway_public_headers, subdir: 'gtk-4.0/gdk/broadway/')
|
||||
#install_headers('gdkbroadway.h', subdir: 'gtk-4.0/gdk/')
|
||||
install_headers(gdk_broadway_public_headers, 'gdkbroadway.h', subdir: 'gtk-4.0/gdk/broadway/')
|
||||
|
||||
gdk_broadway_deps = [shmlib]
|
||||
|
||||
|
||||
224
gdk/capture/sp-capture-types.h
Normal file
224
gdk/capture/sp-capture-types.h
Normal file
@@ -0,0 +1,224 @@
|
||||
/* sp-capture-types.h
|
||||
*
|
||||
* Copyright © 2016 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This file 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 file 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 General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SP_CAPTURE_FORMAT_H
|
||||
#define SP_CAPTURE_FORMAT_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#ifndef SP_DISABLE_GOBJECT
|
||||
# include <glib-object.h>
|
||||
#endif
|
||||
|
||||
#include "sp-clock.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SP_CAPTURE_MAGIC (GUINT32_TO_LE(0xFDCA975E))
|
||||
#define SP_CAPTURE_ALIGN (sizeof(SpCaptureAddress))
|
||||
|
||||
#if __WORDSIZE == 64
|
||||
# define SP_CAPTURE_JITMAP_MARK G_GUINT64_CONSTANT(0xE000000000000000)
|
||||
# define SP_CAPTURE_ADDRESS_FORMAT "0x%016lx"
|
||||
#else
|
||||
# define SP_CAPTURE_JITMAP_MARK G_GUINT64_CONSTANT(0xE0000000)
|
||||
# define SP_CAPTURE_ADDRESS_FORMAT "0x%016llx"
|
||||
#endif
|
||||
|
||||
#define SP_CAPTURE_CURRENT_TIME (sp_clock_get_current_time())
|
||||
#define SP_CAPTURE_COUNTER_INT64 0
|
||||
#define SP_CAPTURE_COUNTER_DOUBLE 1
|
||||
|
||||
typedef struct _SpCaptureReader SpCaptureReader;
|
||||
typedef struct _SpCaptureWriter SpCaptureWriter;
|
||||
typedef struct _SpCaptureCursor SpCaptureCursor;
|
||||
typedef struct _SpCaptureCondition SpCaptureCondition;
|
||||
|
||||
typedef guint64 SpCaptureAddress;
|
||||
|
||||
typedef union
|
||||
{
|
||||
gint64 v64;
|
||||
gdouble vdbl;
|
||||
} SpCaptureCounterValue;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SP_CAPTURE_FRAME_TIMESTAMP = 1,
|
||||
SP_CAPTURE_FRAME_SAMPLE = 2,
|
||||
SP_CAPTURE_FRAME_MAP = 3,
|
||||
SP_CAPTURE_FRAME_PROCESS = 4,
|
||||
SP_CAPTURE_FRAME_FORK = 5,
|
||||
SP_CAPTURE_FRAME_EXIT = 6,
|
||||
SP_CAPTURE_FRAME_JITMAP = 7,
|
||||
SP_CAPTURE_FRAME_CTRDEF = 8,
|
||||
SP_CAPTURE_FRAME_CTRSET = 9,
|
||||
SP_CAPTURE_FRAME_MARK = 10,
|
||||
} SpCaptureFrameType;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
guint32 magic;
|
||||
guint8 version;
|
||||
guint32 little_endian : 1;
|
||||
guint32 padding : 23;
|
||||
gchar capture_time[64];
|
||||
gint64 time;
|
||||
gint64 end_time;
|
||||
gchar suffix[168];
|
||||
} SpCaptureFileHeader;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
guint16 len;
|
||||
gint16 cpu;
|
||||
gint32 pid;
|
||||
gint64 time;
|
||||
guint8 type;
|
||||
guint64 padding : 56;
|
||||
guint8 data[0];
|
||||
} SpCaptureFrame;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SpCaptureFrame frame;
|
||||
guint64 start;
|
||||
guint64 end;
|
||||
guint64 offset;
|
||||
guint64 inode;
|
||||
gchar filename[0];
|
||||
} SpCaptureMap;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SpCaptureFrame frame;
|
||||
guint32 n_jitmaps;
|
||||
guint8 data[0];
|
||||
} SpCaptureJitmap;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SpCaptureFrame frame;
|
||||
gchar cmdline[0];
|
||||
} SpCaptureProcess;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SpCaptureFrame frame;
|
||||
guint16 n_addrs;
|
||||
guint64 padding : 48;
|
||||
SpCaptureAddress addrs[0];
|
||||
} SpCaptureSample;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SpCaptureFrame frame;
|
||||
GPid child_pid;
|
||||
} SpCaptureFork;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SpCaptureFrame frame;
|
||||
} SpCaptureExit;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SpCaptureFrame frame;
|
||||
} SpCaptureTimestamp;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gchar category[32];
|
||||
gchar name[32];
|
||||
gchar description[52];
|
||||
guint32 id : 24;
|
||||
guint8 type;
|
||||
SpCaptureCounterValue value;
|
||||
} SpCaptureCounter;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SpCaptureFrame frame;
|
||||
guint16 n_counters;
|
||||
guint64 padding : 48;
|
||||
SpCaptureCounter counters[0];
|
||||
} SpCaptureFrameCounterDefine;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/*
|
||||
* 96 bytes might seem a bit odd, but the counter frame header is 32
|
||||
* bytes. So this makes a nice 2-cacheline aligned size which is
|
||||
* useful when the number of counters is rather small.
|
||||
*/
|
||||
guint32 ids[8];
|
||||
SpCaptureCounterValue values[8];
|
||||
} SpCaptureCounterValues;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SpCaptureFrame frame;
|
||||
guint16 n_values;
|
||||
guint64 padding : 48;
|
||||
SpCaptureCounterValues values[0];
|
||||
} SpCaptureFrameCounterSet;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SpCaptureFrame frame;
|
||||
gint64 duration;
|
||||
gchar group[24];
|
||||
gchar name[40];
|
||||
gchar message[0];
|
||||
} SpCaptureMark;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
G_STATIC_ASSERT (sizeof (SpCaptureFileHeader) == 256);
|
||||
G_STATIC_ASSERT (sizeof (SpCaptureFrame) == 24);
|
||||
G_STATIC_ASSERT (sizeof (SpCaptureMap) == 56);
|
||||
G_STATIC_ASSERT (sizeof (SpCaptureJitmap) == 28);
|
||||
G_STATIC_ASSERT (sizeof (SpCaptureProcess) == 24);
|
||||
G_STATIC_ASSERT (sizeof (SpCaptureSample) == 32);
|
||||
G_STATIC_ASSERT (sizeof (SpCaptureFork) == 28);
|
||||
G_STATIC_ASSERT (sizeof (SpCaptureExit) == 24);
|
||||
G_STATIC_ASSERT (sizeof (SpCaptureTimestamp) == 24);
|
||||
G_STATIC_ASSERT (sizeof (SpCaptureCounter) == 128);
|
||||
G_STATIC_ASSERT (sizeof (SpCaptureCounterValues) == 96);
|
||||
G_STATIC_ASSERT (sizeof (SpCaptureFrameCounterDefine) == 32);
|
||||
G_STATIC_ASSERT (sizeof (SpCaptureFrameCounterSet) == 32);
|
||||
G_STATIC_ASSERT (sizeof (SpCaptureMark) == 96);
|
||||
|
||||
static inline gint
|
||||
sp_capture_address_compare (SpCaptureAddress a,
|
||||
SpCaptureAddress b)
|
||||
{
|
||||
if (a < b)
|
||||
return -1;
|
||||
if (a > b)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* SP_CAPTURE_FORMAT_H */
|
||||
|
||||
1123
gdk/capture/sp-capture-writer.c
Normal file
1123
gdk/capture/sp-capture-writer.c
Normal file
File diff suppressed because it is too large
Load Diff
132
gdk/capture/sp-capture-writer.h
Normal file
132
gdk/capture/sp-capture-writer.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/* sp-capture-writer.h
|
||||
*
|
||||
* Copyright © 2016 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This file 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 file 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 General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SP_CAPTURE_WRITER_H
|
||||
#define SP_CAPTURE_WRITER_H
|
||||
|
||||
#include "capture/sp-capture-types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _SpCaptureWriter SpCaptureWriter;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/*
|
||||
* The number of frames indexed by SpCaptureFrameType
|
||||
*/
|
||||
gsize frame_count[16];
|
||||
|
||||
/*
|
||||
* Padding for future expansion.
|
||||
*/
|
||||
gsize padding[48];
|
||||
} SpCaptureStat;
|
||||
|
||||
SpCaptureWriter *sp_capture_writer_new (const gchar *filename,
|
||||
gsize buffer_size);
|
||||
SpCaptureWriter *sp_capture_writer_new_from_fd (int fd,
|
||||
gsize buffer_size);
|
||||
SpCaptureWriter *sp_capture_writer_ref (SpCaptureWriter *self);
|
||||
void sp_capture_writer_unref (SpCaptureWriter *self);
|
||||
void sp_capture_writer_stat (SpCaptureWriter *self,
|
||||
SpCaptureStat *stat);
|
||||
gboolean sp_capture_writer_add_map (SpCaptureWriter *self,
|
||||
gint64 time,
|
||||
gint cpu,
|
||||
GPid pid,
|
||||
guint64 start,
|
||||
guint64 end,
|
||||
guint64 offset,
|
||||
guint64 inode,
|
||||
const gchar *filename);
|
||||
gboolean sp_capture_writer_add_mark (SpCaptureWriter *self,
|
||||
gint64 time,
|
||||
gint cpu,
|
||||
GPid pid,
|
||||
guint64 duration,
|
||||
const gchar *group,
|
||||
const gchar *name,
|
||||
const gchar *message);
|
||||
guint64 sp_capture_writer_add_jitmap (SpCaptureWriter *self,
|
||||
const gchar *name);
|
||||
gboolean sp_capture_writer_add_process (SpCaptureWriter *self,
|
||||
gint64 time,
|
||||
gint cpu,
|
||||
GPid pid,
|
||||
const gchar *cmdline);
|
||||
gboolean sp_capture_writer_add_sample (SpCaptureWriter *self,
|
||||
gint64 time,
|
||||
gint cpu,
|
||||
GPid pid,
|
||||
const SpCaptureAddress *addrs,
|
||||
guint n_addrs);
|
||||
gboolean sp_capture_writer_add_fork (SpCaptureWriter *self,
|
||||
gint64 time,
|
||||
gint cpu,
|
||||
GPid pid,
|
||||
GPid child_pid);
|
||||
gboolean sp_capture_writer_add_exit (SpCaptureWriter *self,
|
||||
gint64 time,
|
||||
gint cpu,
|
||||
GPid pid);
|
||||
gboolean sp_capture_writer_add_timestamp (SpCaptureWriter *self,
|
||||
gint64 time,
|
||||
gint cpu,
|
||||
GPid pid);
|
||||
gboolean sp_capture_writer_define_counters (SpCaptureWriter *self,
|
||||
gint64 time,
|
||||
gint cpu,
|
||||
GPid pid,
|
||||
const SpCaptureCounter *counters,
|
||||
guint n_counters);
|
||||
gboolean sp_capture_writer_set_counters (SpCaptureWriter *self,
|
||||
gint64 time,
|
||||
gint cpu,
|
||||
GPid pid,
|
||||
const guint *counters_ids,
|
||||
const SpCaptureCounterValue *values,
|
||||
guint n_counters);
|
||||
gboolean sp_capture_writer_flush (SpCaptureWriter *self);
|
||||
gboolean sp_capture_writer_save_as (SpCaptureWriter *self,
|
||||
const gchar *filename,
|
||||
GError **error);
|
||||
gint sp_capture_writer_request_counter (SpCaptureWriter *self,
|
||||
guint n_counters);
|
||||
SpCaptureReader *sp_capture_writer_create_reader (SpCaptureWriter *self,
|
||||
GError **error);
|
||||
gboolean sp_capture_writer_splice (SpCaptureWriter *self,
|
||||
SpCaptureWriter *dest,
|
||||
GError **error);
|
||||
gboolean _sp_capture_writer_splice_from_fd (SpCaptureWriter *self,
|
||||
int fd,
|
||||
GError **error) G_GNUC_INTERNAL;
|
||||
|
||||
#ifndef SP_DISABLE_GOBJECT
|
||||
# define SP_TYPE_CAPTURE_WRITER (sp_capture_writer_get_type())
|
||||
GType sp_capture_writer_get_type (void);
|
||||
#endif
|
||||
|
||||
#if GLIB_CHECK_VERSION(2, 44, 0)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SpCaptureWriter, sp_capture_writer_unref)
|
||||
#endif
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* SP_CAPTURE_WRITER_H */
|
||||
|
||||
52
gdk/capture/sp-clock.c
Normal file
52
gdk/capture/sp-clock.c
Normal file
@@ -0,0 +1,52 @@
|
||||
/* sp-clock.c
|
||||
*
|
||||
* Copyright © 2016 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This file 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 file 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 General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "sp-clock.h"
|
||||
|
||||
gint sp_clock = -1;
|
||||
|
||||
void
|
||||
sp_clock_init (void)
|
||||
{
|
||||
static const gint clock_ids[] = {
|
||||
CLOCK_MONOTONIC_RAW,
|
||||
CLOCK_MONOTONIC_COARSE,
|
||||
CLOCK_MONOTONIC,
|
||||
CLOCK_REALTIME_COARSE,
|
||||
CLOCK_REALTIME,
|
||||
};
|
||||
guint i;
|
||||
|
||||
if (sp_clock != -1)
|
||||
return;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (clock_ids); i++)
|
||||
{
|
||||
struct timespec ts;
|
||||
int clock_id = clock_ids [i];
|
||||
|
||||
if (0 == clock_gettime (clock_id, &ts))
|
||||
{
|
||||
sp_clock = clock_id;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
55
gdk/capture/sp-clock.h
Normal file
55
gdk/capture/sp-clock.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/* sp-clock.h
|
||||
*
|
||||
* Copyright © 2016 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This file 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 file 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 General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SP_CLOCK_H
|
||||
#define SP_CLOCK_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <time.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef gint SpClock;
|
||||
typedef gint64 SpTimeStamp;
|
||||
typedef gint32 SpTimeSpan;
|
||||
|
||||
extern SpClock sp_clock;
|
||||
|
||||
static inline SpTimeStamp
|
||||
sp_clock_get_current_time (void)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
clock_gettime (sp_clock, &ts);
|
||||
|
||||
return (ts.tv_sec * G_GINT64_CONSTANT (1000000000)) + ts.tv_nsec;
|
||||
}
|
||||
|
||||
static inline SpTimeSpan
|
||||
sp_clock_get_relative_time (SpTimeStamp epoch)
|
||||
{
|
||||
return sp_clock_get_current_time () - epoch;
|
||||
}
|
||||
|
||||
void sp_clock_init (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* SP_CLOCK_H */
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include "gdkversionmacros.h"
|
||||
|
||||
#include "gdkprofilerprivate.h"
|
||||
#include "gdkinternals.h"
|
||||
#include "gdkintl.h"
|
||||
|
||||
@@ -211,6 +212,11 @@ gdk_pre_parse (void)
|
||||
_gdk_debug_flags = g_parse_debug_string (debug_string,
|
||||
(GDebugKey *) gdk_debug_keys,
|
||||
G_N_ELEMENTS (gdk_debug_keys));
|
||||
|
||||
if (g_getenv ("SYSPROF_TRACE_FD"))
|
||||
gdk_profiler_start (atoi (g_getenv ("SYSPROF_TRACE_FD")));
|
||||
else if (g_getenv ("GTK_TRACE"))
|
||||
gdk_profiler_start (-1);
|
||||
}
|
||||
#endif /* G_ENABLE_DEBUG */
|
||||
|
||||
|
||||
@@ -146,15 +146,48 @@ gdk_event_class_init (GdkEventClass *klass)
|
||||
g_object_class_install_properties (object_class, N_PROPS, event_props);
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_event_emit (GdkEvent *event)
|
||||
gboolean
|
||||
check_event_sanity (GdkEvent *event)
|
||||
{
|
||||
GdkDisplay *display;
|
||||
GdkSurface *surface;
|
||||
GdkDevice *device;
|
||||
|
||||
display = gdk_event_get_display (event);
|
||||
surface = gdk_event_get_surface (event);
|
||||
device = gdk_event_get_device (event);
|
||||
|
||||
if (gdk_event_get_event_type (event) == GDK_NOTHING)
|
||||
{
|
||||
g_warning ("Ignoring GDK_NOTHING events; they're good for nothing");
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (surface && display != gdk_surface_get_display (surface))
|
||||
{
|
||||
char *type = g_enum_to_string (GDK_TYPE_EVENT_TYPE, event->any.type);
|
||||
g_warning ("Event of type %s with mismatched surface display", type);
|
||||
g_free (type);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (device && display != gdk_device_get_display (device))
|
||||
{
|
||||
char *type = g_enum_to_string (GDK_TYPE_EVENT_TYPE, event->any.type);
|
||||
g_warning ("Event of type %s with mismatched device display", type);
|
||||
g_free (type);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_event_emit (GdkEvent *event)
|
||||
{
|
||||
if (!check_event_sanity (event))
|
||||
return;
|
||||
|
||||
if (gdk_drag_handle_source_event (event))
|
||||
return;
|
||||
|
||||
|
||||
@@ -645,5 +645,7 @@ void gdk_event_set_related_target (GdkEvent *event,
|
||||
GObject *user_data);
|
||||
GObject * gdk_event_get_related_target (const GdkEvent *event);
|
||||
|
||||
gboolean check_event_sanity (GdkEvent *event);
|
||||
|
||||
|
||||
#endif /* __GDK_EVENTS_PRIVATE_H__ */
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "gdkinternals.h"
|
||||
#include "gdkframeclockprivate.h"
|
||||
#include "gdk.h"
|
||||
#include "gdkprofilerprivate.h"
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
#include <windows.h>
|
||||
@@ -113,6 +114,96 @@ get_sleep_serial (void)
|
||||
return sleep_serial;
|
||||
}
|
||||
|
||||
static guint fps_counter = 0;
|
||||
|
||||
static void
|
||||
add_timings_to_profiler (GdkFrameTimings *timings)
|
||||
{
|
||||
gdk_profiler_add_mark (timings->frame_time * 1000,
|
||||
(timings->frame_end_time - timings->frame_time) * 1000,
|
||||
"frame", "");
|
||||
if (timings->layout_start_time != 0)
|
||||
gdk_profiler_add_mark (timings->layout_start_time * 1000,
|
||||
(timings->paint_start_time - timings->layout_start_time) * 1000,
|
||||
"layout", "");
|
||||
|
||||
if (timings->paint_start_time != 0)
|
||||
gdk_profiler_add_mark (timings->paint_start_time * 1000,
|
||||
(timings->frame_end_time - timings->paint_start_time) * 1000,
|
||||
"paint", "");
|
||||
}
|
||||
|
||||
static gint64
|
||||
guess_refresh_interval (GdkFrameClock *frame_clock)
|
||||
{
|
||||
gint64 interval;
|
||||
gint64 i;
|
||||
|
||||
interval = G_MAXINT64;
|
||||
|
||||
for (i = gdk_frame_clock_get_history_start (frame_clock);
|
||||
i < gdk_frame_clock_get_frame_counter (frame_clock);
|
||||
i++)
|
||||
{
|
||||
GdkFrameTimings *t, *before;
|
||||
gint64 ts, before_ts;
|
||||
|
||||
t = gdk_frame_clock_get_timings (frame_clock, i);
|
||||
before = gdk_frame_clock_get_timings (frame_clock, i - 1);
|
||||
if (t == NULL || before == NULL)
|
||||
continue;
|
||||
|
||||
ts = gdk_frame_timings_get_frame_time (t);
|
||||
before_ts = gdk_frame_timings_get_frame_time (before);
|
||||
if (ts == 0 || before_ts == 0)
|
||||
continue;
|
||||
|
||||
interval = MIN (interval, ts - before_ts);
|
||||
}
|
||||
|
||||
if (interval == G_MAXINT64)
|
||||
return 0;
|
||||
|
||||
return interval;
|
||||
}
|
||||
|
||||
static double
|
||||
frame_clock_get_fps (GdkFrameClock *frame_clock)
|
||||
{
|
||||
GdkFrameTimings *start, *end;
|
||||
gint64 start_counter, end_counter;
|
||||
gint64 start_timestamp, end_timestamp;
|
||||
gint64 interval;
|
||||
|
||||
start_counter = gdk_frame_clock_get_history_start (frame_clock);
|
||||
end_counter = gdk_frame_clock_get_frame_counter (frame_clock);
|
||||
start = gdk_frame_clock_get_timings (frame_clock, start_counter);
|
||||
for (end = gdk_frame_clock_get_timings (frame_clock, end_counter);
|
||||
end_counter > start_counter && end != NULL && !gdk_frame_timings_get_complete (end);
|
||||
end = gdk_frame_clock_get_timings (frame_clock, end_counter))
|
||||
end_counter--;
|
||||
if (end_counter - start_counter < 4)
|
||||
return 0.0;
|
||||
|
||||
start_timestamp = gdk_frame_timings_get_presentation_time (start);
|
||||
end_timestamp = gdk_frame_timings_get_presentation_time (end);
|
||||
if (start_timestamp == 0 || end_timestamp == 0)
|
||||
{
|
||||
start_timestamp = gdk_frame_timings_get_frame_time (start);
|
||||
end_timestamp = gdk_frame_timings_get_frame_time (end);
|
||||
}
|
||||
|
||||
interval = gdk_frame_timings_get_refresh_interval (end);
|
||||
if (interval == 0)
|
||||
{
|
||||
interval = guess_refresh_interval (frame_clock);
|
||||
if (interval == 0)
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return ((double) end_counter - start_counter) * G_USEC_PER_SEC / (end_timestamp - start_timestamp);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_frame_clock_idle_init (GdkFrameClockIdle *frame_clock_idle)
|
||||
{
|
||||
@@ -123,6 +214,11 @@ gdk_frame_clock_idle_init (GdkFrameClockIdle *frame_clock_idle)
|
||||
|
||||
priv->frame_time = g_get_monotonic_time (); /* more sane than zero */
|
||||
priv->freeze_count = 0;
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (fps_counter == 0)
|
||||
fps_counter = gdk_profiler_define_counter ("fps", "Frames per Second");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -405,7 +501,7 @@ gdk_frame_clock_paint_idle (void *data)
|
||||
{
|
||||
int iter;
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (GDK_DEBUG_CHECK (FRAMES))
|
||||
if (GDK_DEBUG_CHECK (FRAMES) || gdk_profiler_is_running ())
|
||||
{
|
||||
if (priv->phase != GDK_FRAME_CLOCK_PHASE_LAYOUT &&
|
||||
(priv->requested & GDK_FRAME_CLOCK_PHASE_LAYOUT))
|
||||
@@ -435,7 +531,7 @@ gdk_frame_clock_paint_idle (void *data)
|
||||
if (priv->freeze_count == 0)
|
||||
{
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (GDK_DEBUG_CHECK (FRAMES))
|
||||
if (GDK_DEBUG_CHECK (FRAMES) || gdk_profiler_is_running ())
|
||||
{
|
||||
if (priv->phase != GDK_FRAME_CLOCK_PHASE_PAINT &&
|
||||
(priv->requested & GDK_FRAME_CLOCK_PHASE_PAINT))
|
||||
@@ -462,7 +558,7 @@ gdk_frame_clock_paint_idle (void *data)
|
||||
priv->phase = GDK_FRAME_CLOCK_PHASE_NONE;
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (GDK_DEBUG_CHECK (FRAMES))
|
||||
if (GDK_DEBUG_CHECK (FRAMES) || gdk_profiler_is_running ())
|
||||
timings->frame_end_time = g_get_monotonic_time ();
|
||||
#endif /* G_ENABLE_DEBUG */
|
||||
}
|
||||
@@ -475,6 +571,12 @@ gdk_frame_clock_paint_idle (void *data)
|
||||
}
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (gdk_profiler_is_running ())
|
||||
{
|
||||
add_timings_to_profiler (timings);
|
||||
gdk_profiler_set_counter (fps_counter, timings->frame_end_time * 1000, frame_clock_get_fps (clock));
|
||||
}
|
||||
|
||||
if (GDK_DEBUG_CHECK (FRAMES))
|
||||
{
|
||||
if (timings && timings->complete)
|
||||
|
||||
@@ -116,6 +116,8 @@ typedef struct {
|
||||
|
||||
int use_es;
|
||||
|
||||
int max_debug_label_length;
|
||||
|
||||
GdkGLContextPaintData *paint_data;
|
||||
} GdkGLContextPrivate;
|
||||
|
||||
@@ -457,11 +459,14 @@ gdk_gl_context_push_debug_group_printf (GdkGLContext *context,
|
||||
|
||||
if (priv->use_khr_debug)
|
||||
{
|
||||
int msg_len;
|
||||
|
||||
va_start (args, format);
|
||||
message = g_strdup_vprintf (format, args);
|
||||
va_end (args);
|
||||
|
||||
glPushDebugGroupKHR (GL_DEBUG_SOURCE_APPLICATION, 0, -1, message);
|
||||
msg_len = MIN (priv->max_debug_label_length, strlen (message) - 1);
|
||||
glPushDebugGroupKHR (GL_DEBUG_SOURCE_APPLICATION, 0, msg_len, message);
|
||||
g_free (message);
|
||||
}
|
||||
}
|
||||
@@ -500,11 +505,15 @@ gdk_gl_context_label_object_printf (GdkGLContext *context,
|
||||
|
||||
if (priv->use_khr_debug)
|
||||
{
|
||||
int msg_len;
|
||||
|
||||
va_start (args, format);
|
||||
message = g_strdup_vprintf (format, args);
|
||||
va_end (args);
|
||||
|
||||
glObjectLabel (identifier, name, -1, message);
|
||||
msg_len = MIN (priv->max_debug_label_length, strlen (message) - 1);
|
||||
|
||||
glObjectLabel (identifier, name, msg_len, message);
|
||||
g_free (message);
|
||||
}
|
||||
}
|
||||
@@ -992,7 +1001,10 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
|
||||
display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
|
||||
|
||||
if (priv->has_khr_debug && GDK_DISPLAY_DEBUG_CHECK (display, GL_DEBUG))
|
||||
priv->use_khr_debug = TRUE;
|
||||
{
|
||||
priv->use_khr_debug = TRUE;
|
||||
glGetIntegerv (GL_MAX_LABEL_LENGTH, &priv->max_debug_label_length);
|
||||
}
|
||||
if (!priv->use_es && GDK_DISPLAY_DEBUG_CHECK (display, GL_TEXTURE_RECT))
|
||||
priv->use_texture_rectangle = TRUE;
|
||||
else if (has_npot)
|
||||
|
||||
230
gdk/gdkprofiler.c
Normal file
230
gdk/gdkprofiler.c
Normal file
@@ -0,0 +1,230 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
*
|
||||
* gdkprofiler.c: A simple profiler
|
||||
*
|
||||
* Copyright © 2018 Matthias Clasen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "gdkversionmacros.h"
|
||||
#include "gdkprofilerprivate.h"
|
||||
#include "gdkframeclockprivate.h"
|
||||
|
||||
#ifndef G_OS_WIN32
|
||||
|
||||
#include "capture/sp-capture-writer.h"
|
||||
|
||||
static SpCaptureWriter *writer = NULL;
|
||||
static gboolean running = FALSE;
|
||||
|
||||
static void
|
||||
profiler_stop (void)
|
||||
{
|
||||
if (writer)
|
||||
sp_capture_writer_unref (writer);
|
||||
}
|
||||
|
||||
void
|
||||
gdk_profiler_start (int fd)
|
||||
{
|
||||
if (writer)
|
||||
return;
|
||||
|
||||
sp_clock_init ();
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
gchar *filename;
|
||||
|
||||
filename = g_strdup_printf ("gtk.%d.syscap", getpid ());
|
||||
g_print ("Writing profiling data to %s\n", filename);
|
||||
writer = sp_capture_writer_new (filename, 16*1024);
|
||||
g_free (filename);
|
||||
}
|
||||
else if (fd > 2)
|
||||
writer = sp_capture_writer_new_from_fd (fd, 16*1024);
|
||||
|
||||
if (writer)
|
||||
running = TRUE;
|
||||
|
||||
atexit (profiler_stop);
|
||||
}
|
||||
|
||||
void
|
||||
gdk_profiler_stop (void)
|
||||
{
|
||||
running = FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_profiler_is_running (void)
|
||||
{
|
||||
return running;
|
||||
}
|
||||
|
||||
void
|
||||
gdk_profiler_add_mark (gint64 start,
|
||||
guint64 duration,
|
||||
const char *name,
|
||||
const char *message)
|
||||
{
|
||||
if (!running)
|
||||
return;
|
||||
|
||||
sp_capture_writer_add_mark (writer,
|
||||
start,
|
||||
-1, getpid (),
|
||||
duration,
|
||||
"gtk", name, message);
|
||||
}
|
||||
|
||||
static guint
|
||||
define_counter (const char *name,
|
||||
const char *description,
|
||||
int type)
|
||||
{
|
||||
SpCaptureCounter counter;
|
||||
|
||||
if (!writer)
|
||||
return 0;
|
||||
|
||||
counter.id = (guint) sp_capture_writer_request_counter (writer, 1);
|
||||
counter.type = type;
|
||||
counter.value.vdbl = 0;
|
||||
g_strlcpy (counter.category, "gtk", sizeof counter.category);
|
||||
g_strlcpy (counter.name, name, sizeof counter.name);
|
||||
g_strlcpy (counter.description, description, sizeof counter.name);
|
||||
|
||||
sp_capture_writer_define_counters (writer,
|
||||
SP_CAPTURE_CURRENT_TIME,
|
||||
-1,
|
||||
getpid (),
|
||||
&counter,
|
||||
1);
|
||||
|
||||
return counter.id;
|
||||
}
|
||||
|
||||
guint
|
||||
gdk_profiler_define_counter (const char *name,
|
||||
const char *description)
|
||||
{
|
||||
return define_counter (name, description, SP_CAPTURE_COUNTER_DOUBLE);
|
||||
}
|
||||
|
||||
guint
|
||||
gdk_profiler_define_int_counter (const char *name,
|
||||
const char *description)
|
||||
{
|
||||
return define_counter (name, description, SP_CAPTURE_COUNTER_INT64);
|
||||
}
|
||||
|
||||
void
|
||||
gdk_profiler_set_counter (guint id,
|
||||
gint64 time,
|
||||
double val)
|
||||
{
|
||||
SpCaptureCounterValue value;
|
||||
|
||||
if (!running)
|
||||
return;
|
||||
|
||||
value.vdbl = val;
|
||||
sp_capture_writer_set_counters (writer,
|
||||
time,
|
||||
-1, getpid (),
|
||||
&id, &value, 1);
|
||||
}
|
||||
|
||||
void
|
||||
gdk_profiler_set_int_counter (guint id,
|
||||
gint64 time,
|
||||
gint64 val)
|
||||
{
|
||||
SpCaptureCounterValue value;
|
||||
|
||||
if (!running)
|
||||
return;
|
||||
|
||||
value.v64 = val;
|
||||
sp_capture_writer_set_counters (writer,
|
||||
time,
|
||||
-1, getpid (),
|
||||
&id, &value, 1);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void
|
||||
gdk_profiler_start (int fd)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
gdk_profiler_stop (void)
|
||||
{
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_profiler_is_running (void)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gdk_profiler_add_mark (gint64 start,
|
||||
guint64 duration,
|
||||
const char *name,
|
||||
const char *message)
|
||||
{
|
||||
}
|
||||
|
||||
guint
|
||||
gdk_profiler_define_counter (const char *name,
|
||||
const char *description)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
gdk_profiler_set_counter (guint id,
|
||||
gint64 time,
|
||||
double value)
|
||||
{
|
||||
}
|
||||
|
||||
guint
|
||||
gdk_profiler_define_int_counter (const char *name,
|
||||
const char *description)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
gdk_profiler_set_int_counter (guint id,
|
||||
gint64 time,
|
||||
gint64 value)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* G_OS_WIN32 */
|
||||
46
gdk/gdkprofilerprivate.h
Normal file
46
gdk/gdkprofilerprivate.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
* Copyright (C) 2018 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GDK_PROFILER_PRIVATE_H__
|
||||
#define __GDK_PROFILER_PRIVATE_H__
|
||||
|
||||
#include "gdk/gdkframeclock.h"
|
||||
#include "gdk/gdkdisplay.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void gdk_profiler_start (int fd);
|
||||
void gdk_profiler_stop (void);
|
||||
gboolean gdk_profiler_is_running (void);
|
||||
void gdk_profiler_add_mark (gint64 start,
|
||||
guint64 duration,
|
||||
const char *name,
|
||||
const char *message);
|
||||
guint gdk_profiler_define_counter (const char *name,
|
||||
const char *description);
|
||||
void gdk_profiler_set_counter (guint id,
|
||||
gint64 time,
|
||||
double value);
|
||||
guint gdk_profiler_define_int_counter (const char *name,
|
||||
const char *description);
|
||||
void gdk_profiler_set_int_counter (guint id,
|
||||
gint64 time,
|
||||
gint64 value);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_PROFILER_PRIVATE_H__ */
|
||||
@@ -293,6 +293,7 @@ gdk_seat_grab (GdkSeat *seat,
|
||||
|
||||
g_return_val_if_fail (GDK_IS_SEAT (seat), GDK_GRAB_FAILED);
|
||||
g_return_val_if_fail (GDK_IS_SURFACE (surface), GDK_GRAB_FAILED);
|
||||
g_return_val_if_fail (gdk_surface_get_display (surface) == gdk_seat_get_display (seat), GDK_GRAB_FAILED);
|
||||
|
||||
capabilities &= GDK_SEAT_CAPABILITY_ALL;
|
||||
g_return_val_if_fail (capabilities != GDK_SEAT_CAPABILITY_NONE, GDK_GRAB_FAILED);
|
||||
|
||||
@@ -107,6 +107,7 @@ enum {
|
||||
PROP_0,
|
||||
PROP_CURSOR,
|
||||
PROP_DISPLAY,
|
||||
PROP_FRAME_CLOCK,
|
||||
PROP_STATE,
|
||||
PROP_MAPPED,
|
||||
LAST_PROP
|
||||
@@ -268,6 +269,13 @@ gdk_surface_class_init (GdkSurfaceClass *klass)
|
||||
GDK_TYPE_DISPLAY,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
properties[PROP_FRAME_CLOCK] =
|
||||
g_param_spec_object ("frame-clock",
|
||||
P_("Frame Clock"),
|
||||
P_("Frame Clock"),
|
||||
GDK_TYPE_FRAME_CLOCK,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
properties[PROP_STATE] =
|
||||
g_param_spec_flags ("state",
|
||||
P_("State"),
|
||||
@@ -462,6 +470,10 @@ gdk_surface_set_property (GObject *object,
|
||||
g_assert (surface->display != NULL);
|
||||
break;
|
||||
|
||||
case PROP_FRAME_CLOCK:
|
||||
gdk_surface_set_frame_clock (surface, GDK_FRAME_CLOCK (g_value_get_object (value)));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -486,6 +498,10 @@ gdk_surface_get_property (GObject *object,
|
||||
g_value_set_object (value, surface->display);
|
||||
break;
|
||||
|
||||
case PROP_FRAME_CLOCK:
|
||||
g_value_set_object (value, surface->frame_clock);
|
||||
break;
|
||||
|
||||
case PROP_STATE:
|
||||
g_value_set_flags (value, surface->state);
|
||||
break;
|
||||
@@ -4186,7 +4202,10 @@ void
|
||||
gdk_surface_set_startup_id (GdkSurface *surface,
|
||||
const gchar *startup_id)
|
||||
{
|
||||
GDK_SURFACE_IMPL_GET_CLASS (surface->impl)->set_startup_id (surface, startup_id);
|
||||
GdkSurfaceImplClass *klass = GDK_SURFACE_IMPL_GET_CLASS (surface->impl);
|
||||
|
||||
if (klass->set_startup_id)
|
||||
klass->set_startup_id (surface, startup_id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -45,8 +45,16 @@ gdk_public_sources = files([
|
||||
'gdkvulkancontext.c',
|
||||
'gdksurface.c',
|
||||
'gdksurfaceimpl.c',
|
||||
'gdkprofiler.c'
|
||||
])
|
||||
|
||||
if not win32_enabled
|
||||
gdk_public_sources += files([
|
||||
'capture/sp-capture-writer.c',
|
||||
'capture/sp-clock.c'
|
||||
])
|
||||
endif
|
||||
|
||||
gdk_public_headers = files([
|
||||
'gdk-autocleanup.h',
|
||||
'gdk.h',
|
||||
|
||||
@@ -33,8 +33,7 @@ gdk_quartz_public_headers = files([
|
||||
'gdkquartzsurface.h',
|
||||
])
|
||||
|
||||
install_headers(gdk_quartz_public_headers, subdir: 'gtk-4.0/gdk/quartz/')
|
||||
install_headers('gdkquartz.h', subdir: 'gtk-4.0/gdk/')
|
||||
install_headers(gdk_quartz_public_headers, 'gdkquartz.h', subdir: 'gtk-4.0/gdk/quartz/')
|
||||
|
||||
gdk_quartz_deps = [ # FIXME
|
||||
]
|
||||
|
||||
@@ -5028,31 +5028,29 @@ _gdk_wayland_device_get_implicit_grab_serial (GdkWaylandDevice *device,
|
||||
}
|
||||
}
|
||||
|
||||
return GDK_WAYLAND_SEAT (seat)->pointer_info.press_serial;
|
||||
return GDK_WAYLAND_SEAT (seat)->pointer_info.press_serial;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
_gdk_wayland_seat_get_last_implicit_grab_serial (GdkSeat *seat,
|
||||
_gdk_wayland_seat_get_last_implicit_grab_serial (GdkWaylandSeat *seat,
|
||||
GdkEventSequence **sequence)
|
||||
{
|
||||
GdkWaylandSeat *wayland_seat;
|
||||
GdkWaylandTouchData *touch;
|
||||
GHashTableIter iter;
|
||||
GList *l;
|
||||
uint32_t serial;
|
||||
|
||||
wayland_seat = GDK_WAYLAND_SEAT (seat);
|
||||
g_hash_table_iter_init (&iter, wayland_seat->touches);
|
||||
g_hash_table_iter_init (&iter, seat->touches);
|
||||
|
||||
if (sequence)
|
||||
*sequence = NULL;
|
||||
|
||||
serial = wayland_seat->keyboard_key_serial;
|
||||
serial = seat->keyboard_key_serial;
|
||||
|
||||
if (wayland_seat->pointer_info.press_serial > serial)
|
||||
serial = wayland_seat->pointer_info.press_serial;
|
||||
if (seat->pointer_info.press_serial > serial)
|
||||
serial = seat->pointer_info.press_serial;
|
||||
|
||||
for (l = wayland_seat->tablets; l; l = l->next)
|
||||
for (l = seat->tablets; l; l = l->next)
|
||||
{
|
||||
GdkWaylandTabletData *tablet = l->data;
|
||||
|
||||
|
||||
@@ -396,6 +396,8 @@ static void gdk_wayland_display_add_output (GdkWaylandDisplay *display_wa
|
||||
guint32 version);
|
||||
static void gdk_wayland_display_remove_output (GdkWaylandDisplay *display_wayland,
|
||||
guint32 id);
|
||||
static void gdk_wayland_display_init_xdg_output (GdkWaylandDisplay *display_wayland);
|
||||
static void gdk_wayland_display_get_xdg_output (GdkWaylandMonitor *monitor);
|
||||
|
||||
static void
|
||||
gdk_registry_handle_global (void *data,
|
||||
@@ -527,6 +529,13 @@ gdk_registry_handle_global (void *data,
|
||||
&server_decoration_listener,
|
||||
display_wayland);
|
||||
}
|
||||
else if (strcmp(interface, "zxdg_output_manager_v1") == 0)
|
||||
{
|
||||
display_wayland->xdg_output_manager =
|
||||
wl_registry_bind (registry, id, &zxdg_output_manager_v1_interface, 1);
|
||||
gdk_wayland_display_init_xdg_output (display_wayland);
|
||||
_gdk_wayland_display_async_roundtrip (display_wayland);
|
||||
}
|
||||
|
||||
g_hash_table_insert (display_wayland->known_globals,
|
||||
GUINT_TO_POINTER (id), g_strdup (interface));
|
||||
@@ -2170,6 +2179,123 @@ update_scale (GdkDisplay *display)
|
||||
g_list_free (seats);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_display_init_xdg_output (GdkWaylandDisplay *display_wayland)
|
||||
{
|
||||
int i;
|
||||
|
||||
GDK_NOTE (MISC,
|
||||
g_message ("init xdg-output support, %d monitor(s) already present",
|
||||
display_wayland->monitors->len));
|
||||
|
||||
for (i = 0; i < display_wayland->monitors->len; i++)
|
||||
gdk_wayland_display_get_xdg_output (display_wayland->monitors->pdata[i]);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
display_has_xdg_output_support (GdkWaylandDisplay *display_wayland)
|
||||
{
|
||||
return (display_wayland->xdg_output_manager != NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
monitor_has_xdg_output (GdkWaylandMonitor *monitor)
|
||||
{
|
||||
return (monitor->xdg_output != NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
should_update_monitor (GdkWaylandMonitor *monitor)
|
||||
{
|
||||
return (GDK_MONITOR (monitor)->geometry.width != 0 &&
|
||||
monitor->version < OUTPUT_VERSION_WITH_DONE);
|
||||
}
|
||||
|
||||
static void
|
||||
apply_monitor_change (GdkWaylandMonitor *monitor)
|
||||
{
|
||||
GDK_NOTE (MISC,
|
||||
g_message ("monitor %d changed position %d %d, size %d %d",
|
||||
monitor->id,
|
||||
monitor->x, monitor->y,
|
||||
monitor->width, monitor->height));
|
||||
|
||||
gdk_monitor_set_position (GDK_MONITOR (monitor), monitor->x, monitor->y);
|
||||
gdk_monitor_set_size (GDK_MONITOR (monitor), monitor->width, monitor->height);
|
||||
monitor->wl_output_done = FALSE;
|
||||
monitor->xdg_output_done = FALSE;
|
||||
|
||||
update_scale (GDK_MONITOR (monitor)->display);
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_output_handle_logical_position (void *data,
|
||||
struct zxdg_output_v1 *xdg_output,
|
||||
int32_t x,
|
||||
int32_t y)
|
||||
{
|
||||
GdkWaylandMonitor *monitor = (GdkWaylandMonitor *) data;
|
||||
|
||||
GDK_NOTE (MISC,
|
||||
g_message ("handle logical position xdg-output %d, position %d %d",
|
||||
monitor->id, x, y));
|
||||
monitor->x = x;
|
||||
monitor->y = y;
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_output_handle_logical_size (void *data,
|
||||
struct zxdg_output_v1 *xdg_output,
|
||||
int32_t width,
|
||||
int32_t height)
|
||||
{
|
||||
GdkWaylandMonitor *monitor = (GdkWaylandMonitor *) data;
|
||||
|
||||
GDK_NOTE (MISC,
|
||||
g_message ("handle logical size xdg-output %d, size %d %d",
|
||||
monitor->id, width, height));
|
||||
monitor->width = width;
|
||||
monitor->height = height;
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_output_handle_done (void *data,
|
||||
struct zxdg_output_v1 *xdg_output)
|
||||
{
|
||||
GdkWaylandMonitor *monitor = (GdkWaylandMonitor *) data;
|
||||
|
||||
GDK_NOTE (MISC,
|
||||
g_message ("handle done xdg-output %d", monitor->id));
|
||||
|
||||
monitor->xdg_output_done = TRUE;
|
||||
if (monitor->wl_output_done)
|
||||
apply_monitor_change (monitor);
|
||||
}
|
||||
|
||||
static const struct zxdg_output_v1_listener xdg_output_listener = {
|
||||
xdg_output_handle_logical_position,
|
||||
xdg_output_handle_logical_size,
|
||||
xdg_output_handle_done,
|
||||
};
|
||||
|
||||
static void
|
||||
gdk_wayland_display_get_xdg_output (GdkWaylandMonitor *monitor)
|
||||
{
|
||||
GdkDisplay *display = GDK_MONITOR (monitor)->display;
|
||||
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
|
||||
|
||||
GDK_NOTE (MISC,
|
||||
g_message ("get xdg-output for monitor %d", monitor->id));
|
||||
|
||||
monitor->xdg_output =
|
||||
zxdg_output_manager_v1_get_xdg_output (display_wayland->xdg_output_manager,
|
||||
monitor->output);
|
||||
|
||||
zxdg_output_v1_add_listener (monitor->xdg_output,
|
||||
&xdg_output_listener,
|
||||
monitor);
|
||||
}
|
||||
|
||||
static void
|
||||
output_handle_geometry (void *data,
|
||||
struct wl_output *wl_output,
|
||||
@@ -2188,13 +2314,17 @@ output_handle_geometry (void *data,
|
||||
g_message ("handle geometry output %d, position %d %d, phys. size %d %d, subpixel layout %s, manufacturer %s, model %s, transform %s",
|
||||
monitor->id, x, y, physical_width, physical_height, subpixel_to_string (subpixel), make, model, transform_to_string (transform)));
|
||||
|
||||
gdk_monitor_set_position (GDK_MONITOR (monitor), x, y);
|
||||
monitor->x = x;
|
||||
monitor->y = y;
|
||||
gdk_monitor_set_physical_size (GDK_MONITOR (monitor), physical_width, physical_height);
|
||||
gdk_monitor_set_subpixel_layout (GDK_MONITOR (monitor), subpixel);
|
||||
gdk_monitor_set_manufacturer (GDK_MONITOR (monitor), make);
|
||||
gdk_monitor_set_model (GDK_MONITOR (monitor), model);
|
||||
|
||||
if (GDK_MONITOR (monitor)->geometry.width != 0 && monitor->version < OUTPUT_VERSION_WITH_DONE)
|
||||
if (should_update_monitor (monitor) || !monitor_has_xdg_output (monitor))
|
||||
apply_monitor_change (monitor);
|
||||
|
||||
if (should_update_monitor (monitor))
|
||||
update_scale (GDK_MONITOR (monitor)->display);
|
||||
}
|
||||
|
||||
@@ -2203,19 +2333,14 @@ output_handle_done (void *data,
|
||||
struct wl_output *wl_output)
|
||||
{
|
||||
GdkWaylandMonitor *monitor = (GdkWaylandMonitor *)data;
|
||||
GdkDisplay *display = gdk_monitor_get_display (GDK_MONITOR (monitor));
|
||||
|
||||
GDK_NOTE (MISC,
|
||||
g_message ("handle done output %d", monitor->id));
|
||||
|
||||
if (!monitor->added)
|
||||
{
|
||||
monitor->added = TRUE;
|
||||
g_ptr_array_add (GDK_WAYLAND_DISPLAY (display)->monitors, monitor);
|
||||
gdk_display_monitor_added (display, GDK_MONITOR (monitor));
|
||||
}
|
||||
monitor->wl_output_done = TRUE;
|
||||
|
||||
update_scale (display);
|
||||
if (!monitor_has_xdg_output (monitor) || monitor->xdg_output_done)
|
||||
apply_monitor_change (monitor);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2232,6 +2357,9 @@ output_handle_scale (void *data,
|
||||
GDK_NOTE (MISC,
|
||||
g_message ("handle scale output %d, scale %d", monitor->id, scale));
|
||||
|
||||
if (monitor_has_xdg_output (monitor))
|
||||
return;
|
||||
|
||||
gdk_monitor_get_geometry (GDK_MONITOR (monitor), &previous_geometry);
|
||||
previous_scale = gdk_monitor_get_scale_factor (GDK_MONITOR (monitor));
|
||||
|
||||
@@ -2239,10 +2367,11 @@ output_handle_scale (void *data,
|
||||
height = previous_geometry.height * previous_scale;
|
||||
|
||||
gdk_monitor_set_scale_factor (GDK_MONITOR (monitor), scale);
|
||||
gdk_monitor_set_size (GDK_MONITOR (monitor), width / scale, height / scale);
|
||||
monitor->width = width / scale;
|
||||
monitor->height = height / scale;
|
||||
|
||||
if (GDK_MONITOR (monitor)->geometry.width != 0 && monitor->version < OUTPUT_VERSION_WITH_DONE)
|
||||
update_scale (GDK_MONITOR (monitor)->display);
|
||||
if (should_update_monitor (monitor))
|
||||
apply_monitor_change (monitor);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2264,11 +2393,12 @@ output_handle_mode (void *data,
|
||||
return;
|
||||
|
||||
scale = gdk_monitor_get_scale_factor (GDK_MONITOR (monitor));
|
||||
gdk_monitor_set_size (GDK_MONITOR (monitor), width / scale, height / scale);
|
||||
monitor->width = width / scale;
|
||||
monitor->height = height / scale;
|
||||
gdk_monitor_set_refresh_rate (GDK_MONITOR (monitor), refresh);
|
||||
|
||||
if (width != 0 && monitor->version < OUTPUT_VERSION_WITH_DONE)
|
||||
update_scale (GDK_MONITOR (monitor)->display);
|
||||
if (should_update_monitor (monitor) || !monitor_has_xdg_output (monitor))
|
||||
apply_monitor_change (monitor);
|
||||
}
|
||||
|
||||
static const struct wl_output_listener output_listener =
|
||||
@@ -2295,13 +2425,17 @@ gdk_wayland_display_add_output (GdkWaylandDisplay *display_wayland,
|
||||
monitor->output = output;
|
||||
monitor->version = version;
|
||||
|
||||
if (monitor->version < OUTPUT_VERSION_WITH_DONE)
|
||||
{
|
||||
g_ptr_array_add (display_wayland->monitors, monitor);
|
||||
gdk_display_monitor_added (GDK_DISPLAY (display_wayland), GDK_MONITOR (monitor));
|
||||
}
|
||||
g_ptr_array_add (display_wayland->monitors, monitor);
|
||||
gdk_display_monitor_added (GDK_DISPLAY (display_wayland), GDK_MONITOR (monitor));
|
||||
|
||||
wl_output_add_listener (output, &output_listener, monitor);
|
||||
|
||||
GDK_NOTE (MISC,
|
||||
g_message ("xdg_output_manager %p",
|
||||
display_wayland->xdg_output_manager));
|
||||
|
||||
if (display_has_xdg_output_support (display_wayland))
|
||||
gdk_wayland_display_get_xdg_output (monitor);
|
||||
}
|
||||
|
||||
struct wl_output *
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <gdk/wayland/xdg-foreign-unstable-v1-client-protocol.h>
|
||||
#include <gdk/wayland/keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h>
|
||||
#include <gdk/wayland/server-decoration-client-protocol.h>
|
||||
#include <gdk/wayland/xdg-output-unstable-v1-client-protocol.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <gdk/gdkkeys.h>
|
||||
@@ -109,6 +110,7 @@ struct _GdkWaylandDisplay
|
||||
struct zxdg_importer_v1 *xdg_importer;
|
||||
struct zwp_keyboard_shortcuts_inhibit_manager_v1 *keyboard_shortcuts_inhibit;
|
||||
struct org_kde_kwin_server_decoration_manager *server_decoration_manager;
|
||||
struct zxdg_output_manager_v1 *xdg_output_manager;
|
||||
|
||||
GList *async_roundtrips;
|
||||
|
||||
|
||||
@@ -151,6 +151,9 @@ _gdk_wayland_display_deliver_event (GdkDisplay *display,
|
||||
{
|
||||
GList *node;
|
||||
|
||||
if (!check_event_sanity (event))
|
||||
g_warning ("Snap! delivering insane events\n");
|
||||
|
||||
node = _gdk_event_queue_append (display, event);
|
||||
_gdk_windowing_got_event (display, node, event,
|
||||
_gdk_display_get_next_serial (display));
|
||||
|
||||
@@ -30,6 +30,15 @@ struct _GdkWaylandMonitor {
|
||||
guint32 version;
|
||||
struct wl_output *output;
|
||||
gboolean added;
|
||||
|
||||
struct zxdg_output_v1 *xdg_output;
|
||||
/* Size and position, can be either from wl_output or xdg_output */
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
gboolean wl_output_done;
|
||||
gboolean xdg_output_done;
|
||||
};
|
||||
|
||||
struct _GdkWaylandMonitorClass {
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <gdk/gdkcursor.h>
|
||||
#include <gdk/wayland/gdkwayland.h>
|
||||
#include <gdk/wayland/gdkdisplay-wayland.h>
|
||||
#include <gdk/wayland/gdkseat-wayland.h>
|
||||
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
@@ -138,7 +139,7 @@ void _gdk_wayland_display_remove_seat (GdkWaylandDisplay *displa
|
||||
GdkKeymap *_gdk_wayland_device_get_keymap (GdkDevice *device);
|
||||
uint32_t _gdk_wayland_device_get_implicit_grab_serial(GdkWaylandDevice *device,
|
||||
const GdkEvent *event);
|
||||
uint32_t _gdk_wayland_seat_get_last_implicit_grab_serial (GdkSeat *seat,
|
||||
uint32_t _gdk_wayland_seat_get_last_implicit_grab_serial (GdkWaylandSeat *seat,
|
||||
GdkEventSequence **seqence);
|
||||
struct wl_data_device * gdk_wayland_device_get_data_device (GdkDevice *gdk_device);
|
||||
void gdk_wayland_device_set_selection (GdkDevice *gdk_device,
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "gdkdeviceprivate.h"
|
||||
#include "gdkprivate-wayland.h"
|
||||
#include "gdkmonitor-wayland.h"
|
||||
#include "gdkseat-wayland.h"
|
||||
#include <wayland/xdg-shell-unstable-v6-client-protocol.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
@@ -861,7 +862,7 @@ gdk_wayland_surface_update_dialogs (GdkSurface *surface)
|
||||
GdkSurface *w = l->data;
|
||||
GdkSurfaceImplWayland *impl;
|
||||
|
||||
if (!GDK_IS_SURFACE_IMPL_WAYLAND(w->impl))
|
||||
if (!GDK_IS_SURFACE_IMPL_WAYLAND (w->impl))
|
||||
continue;
|
||||
|
||||
impl = GDK_SURFACE_IMPL_WAYLAND (w->impl);
|
||||
@@ -2185,14 +2186,12 @@ create_simple_positioner (GdkSurface *surface,
|
||||
static void
|
||||
gdk_wayland_surface_create_xdg_popup (GdkSurface *surface,
|
||||
GdkSurface *parent,
|
||||
struct wl_seat *seat)
|
||||
GdkWaylandSeat *grab_input_seat)
|
||||
{
|
||||
GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
|
||||
GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (surface->impl);
|
||||
GdkSurfaceImplWayland *parent_impl = GDK_SURFACE_IMPL_WAYLAND (parent->impl);
|
||||
gpointer positioner;
|
||||
GdkSeat *gdk_seat;
|
||||
guint32 serial;
|
||||
|
||||
if (!impl->display_server.wl_surface)
|
||||
return;
|
||||
@@ -2210,10 +2209,11 @@ gdk_wayland_surface_create_xdg_popup (GdkSurface *surface,
|
||||
g_warning ("Can't map popup, already mapped");
|
||||
return;
|
||||
}
|
||||
if ((display->current_popups &&
|
||||
g_list_last (display->current_popups)->data != parent) ||
|
||||
(!display->current_popups &&
|
||||
!is_realized_toplevel (parent)))
|
||||
if (grab_input_seat &&
|
||||
((display->current_popups &&
|
||||
g_list_last (display->current_popups)->data != parent) ||
|
||||
(!display->current_popups &&
|
||||
!is_realized_toplevel (parent))))
|
||||
{
|
||||
g_warning ("Tried to map a popup with a non-top most parent");
|
||||
return;
|
||||
@@ -2264,10 +2264,13 @@ gdk_wayland_surface_create_xdg_popup (GdkSurface *surface,
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
if (seat)
|
||||
if (grab_input_seat)
|
||||
{
|
||||
gdk_seat = gdk_display_get_default_seat (GDK_DISPLAY (display));
|
||||
serial = _gdk_wayland_seat_get_last_implicit_grab_serial (gdk_seat, NULL);
|
||||
struct wl_seat *seat;
|
||||
guint32 serial;
|
||||
|
||||
seat = gdk_wayland_seat_get_wl_seat (GDK_SEAT (grab_input_seat));
|
||||
serial = _gdk_wayland_seat_get_last_implicit_grab_serial (grab_input_seat, NULL);
|
||||
|
||||
switch (display->shell_variant)
|
||||
{
|
||||
@@ -2288,7 +2291,7 @@ gdk_wayland_surface_create_xdg_popup (GdkSurface *surface,
|
||||
display->current_popups = g_list_append (display->current_popups, surface);
|
||||
}
|
||||
|
||||
static struct wl_seat *
|
||||
static GdkWaylandSeat *
|
||||
find_grab_input_seat (GdkSurface *surface,
|
||||
GdkSurface *transient_for)
|
||||
{
|
||||
@@ -2301,7 +2304,7 @@ find_grab_input_seat (GdkSurface *surface,
|
||||
* grab before showing the popup surface.
|
||||
*/
|
||||
if (impl->grab_input_seat)
|
||||
return gdk_wayland_seat_get_wl_seat (impl->grab_input_seat);
|
||||
return GDK_WAYLAND_SEAT (impl->grab_input_seat);
|
||||
|
||||
/* HACK: GtkMenu grabs a special surface known as the "grab transfer surface"
|
||||
* and then transfers the grab over to the correct surface later. Look for
|
||||
@@ -2314,7 +2317,7 @@ find_grab_input_seat (GdkSurface *surface,
|
||||
{
|
||||
tmp_impl = GDK_SURFACE_IMPL_WAYLAND (attached_grab_surface->impl);
|
||||
if (tmp_impl->grab_input_seat)
|
||||
return gdk_wayland_seat_get_wl_seat (tmp_impl->grab_input_seat);
|
||||
return GDK_WAYLAND_SEAT (tmp_impl->grab_input_seat);
|
||||
}
|
||||
|
||||
while (transient_for)
|
||||
@@ -2322,7 +2325,7 @@ find_grab_input_seat (GdkSurface *surface,
|
||||
tmp_impl = GDK_SURFACE_IMPL_WAYLAND (transient_for->impl);
|
||||
|
||||
if (tmp_impl->grab_input_seat)
|
||||
return gdk_wayland_seat_get_wl_seat (tmp_impl->grab_input_seat);
|
||||
return GDK_WAYLAND_SEAT (tmp_impl->grab_input_seat);
|
||||
|
||||
transient_for = tmp_impl->transient_for;
|
||||
}
|
||||
@@ -2418,7 +2421,7 @@ gdk_wayland_surface_map (GdkSurface *surface)
|
||||
if (should_map_as_popup (surface))
|
||||
{
|
||||
gboolean create_fallback = FALSE;
|
||||
struct wl_seat *grab_input_seat;
|
||||
GdkWaylandSeat *grab_input_seat;
|
||||
|
||||
/* Popup menus can appear without a transient parent, which means they
|
||||
* cannot be positioned properly on Wayland. This attempts to guess the
|
||||
@@ -2492,8 +2495,8 @@ gdk_wayland_surface_map (GdkSurface *surface)
|
||||
if (!create_fallback)
|
||||
{
|
||||
gdk_wayland_surface_create_xdg_popup (surface,
|
||||
transient_for,
|
||||
grab_input_seat);
|
||||
transient_for,
|
||||
grab_input_seat);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3581,7 +3584,7 @@ gdk_wayland_surface_begin_resize_drag (GdkSurface *surface,
|
||||
if (!is_realized_toplevel (surface))
|
||||
return;
|
||||
|
||||
serial = _gdk_wayland_seat_get_last_implicit_grab_serial (gdk_device_get_seat (device),
|
||||
serial = _gdk_wayland_seat_get_last_implicit_grab_serial (GDK_WAYLAND_SEAT (gdk_device_get_seat (device)),
|
||||
&sequence);
|
||||
|
||||
switch (display_wayland->shell_variant)
|
||||
@@ -3632,7 +3635,7 @@ gdk_wayland_surface_begin_move_drag (GdkSurface *surface,
|
||||
if (!is_realized_toplevel (surface))
|
||||
return;
|
||||
|
||||
serial = _gdk_wayland_seat_get_last_implicit_grab_serial (gdk_device_get_seat (device),
|
||||
serial = _gdk_wayland_seat_get_last_implicit_grab_serial (GDK_WAYLAND_SEAT (gdk_device_get_seat (device)),
|
||||
&sequence);
|
||||
switch (display_wayland->shell_variant)
|
||||
{
|
||||
|
||||
@@ -26,8 +26,7 @@ gdk_wayland_public_headers = files([
|
||||
'gdkwaylandsurface.h'
|
||||
])
|
||||
|
||||
install_headers(gdk_wayland_public_headers, subdir: 'gtk-4.0/gdk/wayland/')
|
||||
install_headers('gdkwayland.h', subdir: 'gtk-4.0/gdk/')
|
||||
install_headers(gdk_wayland_public_headers, 'gdkwayland.h', subdir: 'gtk-4.0/gdk/wayland/')
|
||||
|
||||
gdk_wayland_deps = [
|
||||
shmlib,
|
||||
@@ -58,6 +57,7 @@ proto_sources = [
|
||||
['tablet', 'unstable', 'v2', ],
|
||||
['keyboard-shortcuts-inhibit', 'unstable', 'v1', ],
|
||||
['server-decoration', 'private' ],
|
||||
['xdg-output', 'unstable', 'v1', ],
|
||||
]
|
||||
|
||||
gdk_wayland_gen_headers = []
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
G_DEFINE_TYPE (GdkWin32CairoContext, gdk_win32_cairo_context, GDK_TYPE_CAIRO_CONTEXT)
|
||||
|
||||
static void
|
||||
void
|
||||
gdk_win32_surface_get_queued_window_rect (GdkSurface *surface,
|
||||
gint scale,
|
||||
RECT *return_window_rect)
|
||||
@@ -53,7 +53,7 @@ gdk_win32_surface_get_queued_window_rect (GdkSurface *surface,
|
||||
*return_window_rect = window_rect;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
gdk_win32_surface_apply_queued_move_resize (GdkSurface *surface,
|
||||
RECT window_rect)
|
||||
{
|
||||
|
||||
@@ -166,6 +166,27 @@ gdk_win32_gl_context_begin_frame (GdkDrawContext *draw_context,
|
||||
{
|
||||
GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
|
||||
GdkSurface *surface;
|
||||
GdkSurfaceImplWin32 *impl;
|
||||
RECT queued_window_rect;
|
||||
|
||||
surface = gdk_gl_context_get_surface (context);
|
||||
impl = GDK_SURFACE_IMPL_WIN32 (surface->impl);
|
||||
|
||||
gdk_win32_surface_get_queued_window_rect (surface,
|
||||
gdk_surface_get_scale_factor (surface),
|
||||
&queued_window_rect);
|
||||
|
||||
/* Apply queued resizes GL windows before painting them
|
||||
* (we paint on the window DC directly, it must have the right size).
|
||||
* Due to some poorly-understood issue delayed
|
||||
* resizing of double-buffered windows can produce weird
|
||||
* artefacts, so these are also resized before we paint.
|
||||
*/
|
||||
if (impl->drag_move_resize_context.native_move_resize_pending)
|
||||
{
|
||||
impl->drag_move_resize_context.native_move_resize_pending = FALSE;
|
||||
gdk_win32_surface_apply_queued_move_resize (surface, queued_window_rect);
|
||||
}
|
||||
|
||||
GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_parent_class)->begin_frame (draw_context, update_area);
|
||||
if (gdk_gl_context_get_shared_context (context))
|
||||
@@ -176,7 +197,6 @@ gdk_win32_gl_context_begin_frame (GdkDrawContext *draw_context,
|
||||
|
||||
/* If nothing else is known, repaint everything so that the back
|
||||
buffer is fully up-to-date for the swapbuffer */
|
||||
surface = gdk_gl_context_get_surface (context);
|
||||
cairo_region_union_rectangle (update_area, &(GdkRectangle) {
|
||||
0, 0,
|
||||
gdk_surface_get_width (surface),
|
||||
|
||||
@@ -384,6 +384,15 @@ void _gdk_win32_update_layered_window_from_cache (GdkSurface *window,
|
||||
gboolean do_paint);
|
||||
|
||||
|
||||
void
|
||||
gdk_win32_surface_get_queued_window_rect (GdkSurface *surface,
|
||||
gint scale,
|
||||
RECT *return_window_rect);
|
||||
|
||||
void
|
||||
gdk_win32_surface_apply_queued_move_resize (GdkSurface *surface,
|
||||
RECT window_rect);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_SURFACE_WIN32_H__ */
|
||||
|
||||
@@ -42,8 +42,7 @@ gdk_win32_public_headers = files([
|
||||
'gdkwin32surface.h',
|
||||
])
|
||||
|
||||
install_headers(gdk_win32_public_headers, subdir: 'gtk-4.0/gdk/win32/')
|
||||
install_headers('gdkwin32.h', subdir: 'gtk-4.0/gdk/')
|
||||
install_headers(gdk_win32_public_headers, 'gdkwin32.h', subdir: 'gtk-4.0/gdk/win32/')
|
||||
|
||||
gdk_win32_deps = [ # FIXME
|
||||
pangowin32_dep
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
|
||||
|
||||
|
||||
#define APPEARS_FOCUSED(toplevel) \
|
||||
((toplevel)->has_focus || (toplevel)->has_focus_window || (toplevel)->has_pointer_focus)
|
||||
#define HAS_FOCUS(toplevel) \
|
||||
((toplevel)->has_focus || (toplevel)->has_pointer_focus)
|
||||
|
||||
static void gdk_x11_device_manager_core_finalize (GObject *object);
|
||||
static void gdk_x11_device_manager_core_constructed (GObject *object);
|
||||
@@ -752,7 +752,7 @@ _gdk_device_manager_core_handle_focus (GdkSurface *surface,
|
||||
if (toplevel->focus_window == original)
|
||||
return;
|
||||
|
||||
had_focus = APPEARS_FOCUSED (toplevel);
|
||||
had_focus = HAS_FOCUS (toplevel);
|
||||
x11_screen = GDK_X11_SCREEN (GDK_SURFACE_SCREEN (surface));
|
||||
|
||||
switch (detail)
|
||||
@@ -814,7 +814,7 @@ _gdk_device_manager_core_handle_focus (GdkSurface *surface,
|
||||
break;
|
||||
}
|
||||
|
||||
if (APPEARS_FOCUSED (toplevel) != had_focus)
|
||||
if (HAS_FOCUS (toplevel) != had_focus)
|
||||
{
|
||||
GdkEvent *event;
|
||||
|
||||
|
||||
@@ -36,8 +36,8 @@ static void gdk_event_source_finalize (GSource *source);
|
||||
|
||||
static GQuark quark_needs_enter = 0;
|
||||
|
||||
#define APPEARS_FOCUSED(toplevel) \
|
||||
((toplevel)->has_focus || (toplevel)->has_focus_window || (toplevel)->has_pointer_focus)
|
||||
#define HAS_FOCUS(toplevel) \
|
||||
((toplevel)->has_focus || (toplevel)->has_pointer_focus)
|
||||
|
||||
struct _GdkEventSource
|
||||
{
|
||||
@@ -108,10 +108,10 @@ handle_focus_change (GdkEventCrossing *event)
|
||||
if (!event->focus || toplevel->has_focus_window)
|
||||
return;
|
||||
|
||||
had_focus = APPEARS_FOCUSED (toplevel);
|
||||
had_focus = HAS_FOCUS (toplevel);
|
||||
toplevel->has_pointer_focus = focus_in;
|
||||
|
||||
if (APPEARS_FOCUSED (toplevel) != had_focus)
|
||||
if (HAS_FOCUS (toplevel) != had_focus)
|
||||
{
|
||||
GdkEvent *focus_event;
|
||||
|
||||
|
||||
@@ -1867,6 +1867,14 @@ gdk_x11_surface_set_modal_hint (GdkSurface *surface,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_x11_surface_set_skip_taskbar_hint:
|
||||
* @surface: (type GdkX11Surface): a native #GdkSurface
|
||||
* @skips_taskbar: %TRUE to skip taskbars
|
||||
*
|
||||
* Sets a hint on @surface that taskbars should not
|
||||
* display it. See the EWMH for details.
|
||||
*/
|
||||
void
|
||||
gdk_x11_surface_set_skip_taskbar_hint (GdkSurface *surface,
|
||||
gboolean skips_taskbar)
|
||||
@@ -1888,6 +1896,14 @@ gdk_x11_surface_set_skip_taskbar_hint (GdkSurface *surface,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_x11_surface_set_skip_pager_hint:
|
||||
* @surface: (type GdkX11Surface): a #GdkSurface
|
||||
* @skips_pager: %TRUE to skip pagers
|
||||
*
|
||||
* Sets a hint on @surface that pagers should not
|
||||
* display it. See the EWMH for details.
|
||||
*/
|
||||
void
|
||||
gdk_x11_surface_set_skip_pager_hint (GdkSurface *surface,
|
||||
gboolean skips_pager)
|
||||
@@ -1909,6 +1925,14 @@ gdk_x11_surface_set_skip_pager_hint (GdkSurface *surface,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_x11_surface_set_urgency_hint:
|
||||
* @surface: (type GdkX11Surface): a native #GdkSurface
|
||||
* @urgent: %TRUE to indicate urgenct attention needed
|
||||
*
|
||||
* Sets a hint on @surface that it needs user attention.
|
||||
* See the ICCCM for details.
|
||||
*/
|
||||
void
|
||||
gdk_x11_surface_set_urgency_hint (GdkSurface *surface,
|
||||
gboolean urgent)
|
||||
@@ -3377,6 +3401,14 @@ gdk_x11_surface_get_group (GdkSurface *surface)
|
||||
return toplevel->group_leader;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_x11_surface_set_group:
|
||||
* @surface: (type GdkX11Surface): a native #GdkSurface
|
||||
* @leader: a #GdkSurface
|
||||
*
|
||||
* Sets the group leader of @surface to be @leader.
|
||||
* See the ICCCM for details.
|
||||
*/
|
||||
void
|
||||
gdk_x11_surface_set_group (GdkSurface *surface,
|
||||
GdkSurface *leader)
|
||||
|
||||
@@ -54,8 +54,7 @@ gdk_x11_public_headers = files([
|
||||
'gdkx11surface.h',
|
||||
])
|
||||
|
||||
install_headers(gdk_x11_public_headers, subdir: 'gtk-4.0/gdk/x11/')
|
||||
install_headers('gdkx.h', subdir: 'gtk-4.0/gdk/')
|
||||
install_headers(gdk_x11_public_headers, 'gdkx.h', subdir: 'gtk-4.0/gdk/x11/')
|
||||
|
||||
gdk_x11_deps = [
|
||||
xrender_dep,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskbroadwayrendererprivate.h"
|
||||
#include "gskbroadwayrenderer.h"
|
||||
|
||||
#include "broadway/gdkprivate-broadway.h"
|
||||
|
||||
#include "gskdebugprivate.h"
|
||||
@@ -827,3 +828,23 @@ static void
|
||||
gsk_broadway_renderer_init (GskBroadwayRenderer *self)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_broadway_renderer_new:
|
||||
*
|
||||
* Creates a new Broadway renderer.
|
||||
*
|
||||
* The Broadway renderer is the default renderer for the broadway backend.
|
||||
* It will only work with broadway surfaces, otherwise it will fail the
|
||||
* call to gdk_renderer_realize().
|
||||
*
|
||||
* This function is only available when GTK was compiled with Broadway
|
||||
* support.
|
||||
*
|
||||
* Returns: a new Broadway renderer.
|
||||
**/
|
||||
GskRenderer *
|
||||
gsk_broadway_renderer_new (void)
|
||||
{
|
||||
return g_object_new (GSK_TYPE_BROADWAY_RENDERER, NULL);
|
||||
}
|
||||
|
||||
52
gsk/broadway/gskbroadwayrenderer.h
Normal file
52
gsk/broadway/gskbroadwayrenderer.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright © 2019 Alexander Larsson
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __GSK_BROADWAY_RENDERER_H__
|
||||
#define __GSK_BROADWAY_RENDERER_H__
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gsk/gskrenderer.h>
|
||||
|
||||
#ifdef GDK_WINDOWING_BROADWAY
|
||||
|
||||
#include <gdk/broadway/gdkbroadway.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_BROADWAY_RENDERER (gsk_broadway_renderer_get_type ())
|
||||
|
||||
#define GSK_BROADWAY_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_BROADWAY_RENDERER, GskBroadwayRenderer))
|
||||
#define GSK_IS_BROADWAY_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_BROADWAY_RENDERER))
|
||||
#define GSK_BROADWAY_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_BROADWAY_RENDERER, GskBroadwayRendererClass))
|
||||
#define GSK_IS_BROADWAY_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_BROADWAY_RENDERER))
|
||||
#define GSK_BROADWAY_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_BROADWAY_RENDERER, GskBroadwayRendererClass))
|
||||
|
||||
typedef struct _GskBroadwayRenderer GskBroadwayRenderer;
|
||||
typedef struct _GskBroadwayRendererClass GskBroadwayRendererClass;
|
||||
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gsk_broadway_renderer_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskRenderer * gsk_broadway_renderer_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* GDK_WINDOWING_BROADWAY */
|
||||
|
||||
#endif /* __GSK_BROADWAY_RENDERER_H__ */
|
||||
@@ -1,24 +0,0 @@
|
||||
#ifndef __GSK_BROADWAY_RENDERER_PRIVATE_H__
|
||||
#define __GSK_BROADWAY_RENDERER_PRIVATE_H__
|
||||
|
||||
#include "broadway/gdkbroadway.h"
|
||||
#include <gsk/gskrenderer.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_BROADWAY_RENDERER (gsk_broadway_renderer_get_type ())
|
||||
|
||||
#define GSK_BROADWAY_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_BROADWAY_RENDERER, GskBroadwayRenderer))
|
||||
#define GSK_IS_BROADWAY_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_BROADWAY_RENDERER))
|
||||
#define GSK_BROADWAY_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_BROADWAY_RENDERER, GskBroadwayRendererClass))
|
||||
#define GSK_IS_BROADWAY_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_BROADWAY_RENDERER))
|
||||
#define GSK_BROADWAY_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_BROADWAY_RENDERER, GskBroadwayRendererClass))
|
||||
|
||||
typedef struct _GskBroadwayRenderer GskBroadwayRenderer;
|
||||
typedef struct _GskBroadwayRendererClass GskBroadwayRendererClass;
|
||||
|
||||
GType gsk_broadway_renderer_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_BROADWAY_RENDERER_PRIVATE_H__ */
|
||||
@@ -535,8 +535,6 @@ gsk_gl_driver_get_texture_for_texture (GskGLDriver *self,
|
||||
}
|
||||
|
||||
t = create_texture (self, gdk_texture_get_width (texture), gdk_texture_get_height (texture));
|
||||
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, t->texture_id,
|
||||
"GdkTexture<%p> %d", texture, t->texture_id);
|
||||
|
||||
if (gdk_texture_set_render_data (texture, self, t, gsk_gl_driver_release_texture))
|
||||
t->user = texture;
|
||||
@@ -547,6 +545,9 @@ gsk_gl_driver_get_texture_for_texture (GskGLDriver *self,
|
||||
surface,
|
||||
min_filter,
|
||||
mag_filter);
|
||||
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, t->texture_id,
|
||||
"GdkTexture<%p> %d", texture, t->texture_id);
|
||||
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
return t->texture_id;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskglrendererprivate.h"
|
||||
#include "gskglrenderer.h"
|
||||
|
||||
#include "gskdebugprivate.h"
|
||||
#include "gskenums.h"
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "gdk/gdkgltextureprivate.h"
|
||||
#include "gdk/gdkglcontextprivate.h"
|
||||
#include "gdk/gdkprofilerprivate.h"
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
#include <cairo-ft.h>
|
||||
@@ -326,6 +327,7 @@ struct _GskGLRenderer
|
||||
Program unblurred_outset_shadow_program;
|
||||
Program border_program;
|
||||
Program cross_fade_program;
|
||||
Program blend_program;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -479,14 +481,14 @@ render_fallback_node (GskGLRenderer *self,
|
||||
texture_id = gsk_gl_driver_create_texture (self->gl_driver,
|
||||
surface_width,
|
||||
surface_height);
|
||||
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, texture_id,
|
||||
"Fallback %s %d", node->node_class->type_name, texture_id);
|
||||
|
||||
gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id);
|
||||
gsk_gl_driver_init_texture_with_surface (self->gl_driver,
|
||||
texture_id,
|
||||
surface,
|
||||
GL_NEAREST, GL_NEAREST);
|
||||
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, texture_id,
|
||||
"Fallback %s %d", node->node_class->type_name, texture_id);
|
||||
|
||||
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
@@ -1267,10 +1269,17 @@ render_blur_node (GskGLRenderer *self,
|
||||
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;
|
||||
const float blur_radius = gsk_blur_node_get_radius (node);
|
||||
int texture_id;
|
||||
gboolean is_offscreen;
|
||||
RenderOp op;
|
||||
|
||||
if (blur_radius <= 0)
|
||||
{
|
||||
gsk_gl_renderer_add_render_ops (self, gsk_blur_node_get_child (node), builder);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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
|
||||
@@ -1431,10 +1440,10 @@ render_outset_shadow_node (GskGLRenderer *self,
|
||||
GskRoundedRect blit_clip;
|
||||
|
||||
texture_id = gsk_gl_driver_create_texture (self->gl_driver, texture_width, texture_height);
|
||||
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, texture_id,
|
||||
"Outset Shadow Temp %d", texture_id);
|
||||
gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id);
|
||||
gsk_gl_driver_init_texture_empty (self->gl_driver, texture_id);
|
||||
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, texture_id,
|
||||
"Outset Shadow Temp %d", texture_id);
|
||||
render_target = gsk_gl_driver_create_render_target (self->gl_driver, texture_id, FALSE, FALSE);
|
||||
gdk_gl_context_label_object_printf (self->gl_context, GL_FRAMEBUFFER, render_target,
|
||||
"Outset Shadow FB Temp %d", render_target);
|
||||
@@ -1468,10 +1477,10 @@ render_outset_shadow_node (GskGLRenderer *self,
|
||||
});
|
||||
|
||||
blurred_texture_id = gsk_gl_driver_create_permanent_texture (self->gl_driver, texture_width, texture_height);
|
||||
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, blurred_texture_id,
|
||||
"Outset Shadow Cache %d", blurred_texture_id);
|
||||
gsk_gl_driver_bind_source_texture (self->gl_driver, blurred_texture_id);
|
||||
gsk_gl_driver_init_texture_empty (self->gl_driver, blurred_texture_id);
|
||||
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, blurred_texture_id,
|
||||
"Outset Shadow Cache %d", blurred_texture_id);
|
||||
blurred_render_target = gsk_gl_driver_create_render_target (self->gl_driver, blurred_texture_id, TRUE, TRUE);
|
||||
gdk_gl_context_label_object_printf (self->gl_context, GL_FRAMEBUFFER, render_target,
|
||||
"Outset Shadow Cache FB %d", render_target);
|
||||
@@ -1882,13 +1891,13 @@ render_cross_fade_node (GskGLRenderer *self,
|
||||
&node->bounds,
|
||||
start_node,
|
||||
&start_texture_id, &is_offscreen1,
|
||||
FORCE_OFFSCREEN | RESET_CLIP);
|
||||
FORCE_OFFSCREEN | RESET_CLIP | RESET_OPACITY);
|
||||
|
||||
add_offscreen_ops (self, builder,
|
||||
&node->bounds,
|
||||
end_node,
|
||||
&end_texture_id, &is_offscreen2,
|
||||
FORCE_OFFSCREEN | RESET_CLIP);
|
||||
FORCE_OFFSCREEN | RESET_CLIP | RESET_OPACITY);
|
||||
|
||||
ops_set_program (builder, &self->cross_fade_program);
|
||||
op.op = OP_CHANGE_CROSS_FADE;
|
||||
@@ -1900,6 +1909,54 @@ render_cross_fade_node (GskGLRenderer *self,
|
||||
ops_draw (builder, vertex_data);
|
||||
}
|
||||
|
||||
static inline void
|
||||
render_blend_node (GskGLRenderer *self,
|
||||
GskRenderNode *node,
|
||||
RenderOpBuilder *builder)
|
||||
{
|
||||
GskRenderNode *top_child = gsk_blend_node_get_top_child (node);
|
||||
GskRenderNode *bottom_child = gsk_blend_node_get_bottom_child (node);
|
||||
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;
|
||||
int top_texture_id;
|
||||
int bottom_texture_id;
|
||||
gboolean is_offscreen1, is_offscreen2;
|
||||
RenderOp op;
|
||||
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 }, },
|
||||
};
|
||||
|
||||
/* TODO: We create 2 textures here as big as the blend node, but both the
|
||||
* start and the end node might be a lot smaller than that. */
|
||||
add_offscreen_ops (self, builder,
|
||||
&node->bounds,
|
||||
bottom_child,
|
||||
&bottom_texture_id, &is_offscreen1,
|
||||
FORCE_OFFSCREEN | RESET_CLIP);
|
||||
|
||||
add_offscreen_ops (self, builder,
|
||||
&node->bounds,
|
||||
top_child,
|
||||
&top_texture_id, &is_offscreen2,
|
||||
FORCE_OFFSCREEN | RESET_CLIP);
|
||||
|
||||
ops_set_program (builder, &self->blend_program);
|
||||
ops_set_texture (builder, bottom_texture_id);
|
||||
op.op = OP_CHANGE_BLEND;
|
||||
op.blend.source2 = top_texture_id;
|
||||
op.blend.mode = gsk_blend_node_get_blend_mode (node);
|
||||
ops_add (builder, &op);
|
||||
ops_draw (builder, vertex_data);
|
||||
}
|
||||
|
||||
static inline void
|
||||
apply_viewport_op (const Program *program,
|
||||
const RenderOp *op)
|
||||
@@ -2174,6 +2231,18 @@ apply_cross_fade_op (const Program *program,
|
||||
glUniform1f (program->cross_fade.progress_location, op->cross_fade.progress);
|
||||
}
|
||||
|
||||
static inline void
|
||||
apply_blend_op (const Program *program,
|
||||
const RenderOp *op)
|
||||
{
|
||||
/* End texture id */
|
||||
glUniform1i (program->blend.source2_location, 1);
|
||||
glActiveTexture (GL_TEXTURE0 + 1);
|
||||
glBindTexture (GL_TEXTURE_2D, op->blend.source2);
|
||||
/* progress */
|
||||
glUniform1i (program->blend.mode_location, op->blend.mode);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_renderer_dispose (GObject *gobject)
|
||||
{
|
||||
@@ -2206,6 +2275,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
|
||||
{ "unblurred outset shadow", "unblurred_outset_shadow.fs.glsl" },
|
||||
{ "border", "border.fs.glsl" },
|
||||
{ "cross fade", "cross_fade.fs.glsl" },
|
||||
{ "blend", "blend.fs.glsl" },
|
||||
};
|
||||
|
||||
builder = gsk_shader_builder_new ();
|
||||
@@ -2336,6 +2406,10 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
|
||||
INIT_PROGRAM_UNIFORM_LOCATION (cross_fade, progress);
|
||||
INIT_PROGRAM_UNIFORM_LOCATION (cross_fade, source2);
|
||||
|
||||
/* blend */
|
||||
INIT_PROGRAM_UNIFORM_LOCATION (blend, source2);
|
||||
INIT_PROGRAM_UNIFORM_LOCATION (blend, mode);
|
||||
|
||||
g_object_unref (builder);
|
||||
return TRUE;
|
||||
}
|
||||
@@ -2588,8 +2662,11 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
|
||||
render_cross_fade_node (self, node, builder);
|
||||
break;
|
||||
|
||||
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
||||
case GSK_BLEND_NODE:
|
||||
render_blend_node (self, node, builder);
|
||||
break;
|
||||
|
||||
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
||||
case GSK_REPEAT_NODE:
|
||||
case GSK_CAIRO_NODE:
|
||||
default:
|
||||
@@ -2855,6 +2932,11 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
|
||||
apply_cross_fade_op (program, op);
|
||||
break;
|
||||
|
||||
case OP_CHANGE_BLEND:
|
||||
g_assert (program == &self->blend_program);
|
||||
apply_blend_op (program, op);
|
||||
break;
|
||||
|
||||
case OP_CHANGE_LINEAR_GRADIENT:
|
||||
apply_linear_gradient_op (program, op);
|
||||
break;
|
||||
@@ -2927,7 +3009,7 @@ gsk_gl_renderer_do_render (GskRenderer *renderer,
|
||||
gsize buffer_size;
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
GskProfiler *profiler;
|
||||
gint64 gpu_time, cpu_time;
|
||||
gint64 gpu_time, cpu_time, start_time;
|
||||
#endif
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
@@ -3035,6 +3117,7 @@ gsk_gl_renderer_do_render (GskRenderer *renderer,
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
gsk_profiler_counter_inc (profiler, self->profile_counters.frames);
|
||||
|
||||
start_time = gsk_profiler_timer_get_start (profiler, self->profile_timers.cpu_time);
|
||||
cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
|
||||
gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
|
||||
|
||||
@@ -3042,6 +3125,10 @@ gsk_gl_renderer_do_render (GskRenderer *renderer,
|
||||
gsk_profiler_timer_set (profiler, self->profile_timers.gpu_time, gpu_time);
|
||||
|
||||
gsk_profiler_push_samples (profiler);
|
||||
|
||||
if (gdk_profiler_is_running ())
|
||||
gdk_profiler_add_mark (start_time, cpu_time, "render", "");
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -3207,3 +3294,17 @@ gsk_gl_renderer_init (GskGLRenderer *self)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_gl_renderer_new:
|
||||
*
|
||||
* Creates a new #GskRenderer using OpenGL. This is the default renderer
|
||||
* used by GTK.
|
||||
*
|
||||
* Returns: a new GL renderer
|
||||
**/
|
||||
GskRenderer *
|
||||
gsk_gl_renderer_new (void)
|
||||
{
|
||||
return g_object_new (GSK_TYPE_GL_RENDERER, NULL);
|
||||
}
|
||||
|
||||
47
gsk/gl/gskglrenderer.h
Normal file
47
gsk/gl/gskglrenderer.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright © 2016 Endless
|
||||
* 2018 Timm Bäder <mail@baedert.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Timm Bäder <mail@baedert.org>
|
||||
*/
|
||||
|
||||
#ifndef __GSK_GL_RENDERER_H__
|
||||
#define __GSK_GL_RENDERER_H__
|
||||
|
||||
#include <gsk/gskrenderer.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_GL_RENDERER (gsk_gl_renderer_get_type ())
|
||||
|
||||
#define GSK_GL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_GL_RENDERER, GskGLRenderer))
|
||||
#define GSK_IS_GL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_GL_RENDERER))
|
||||
#define GSK_GL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_GL_RENDERER, GskGLRendererClass))
|
||||
#define GSK_IS_GL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_GL_RENDERER))
|
||||
#define GSK_GL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_GL_RENDERER, GskGLRendererClass))
|
||||
|
||||
typedef struct _GskGLRenderer GskGLRenderer;
|
||||
typedef struct _GskGLRendererClass GskGLRendererClass;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gsk_gl_renderer_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskRenderer * gsk_gl_renderer_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_GL_RENDERER_H__ */
|
||||
@@ -1,23 +0,0 @@
|
||||
#ifndef __GSK_GL_RENDERER_PRIVATE_H__
|
||||
#define __GSK_GL_RENDERER_PRIVATE_H__
|
||||
|
||||
#include <gsk/gskrenderer.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_GL_RENDERER (gsk_gl_renderer_get_type ())
|
||||
|
||||
#define GSK_GL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_GL_RENDERER, GskGLRenderer))
|
||||
#define GSK_IS_GL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_GL_RENDERER))
|
||||
#define GSK_GL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_GL_RENDERER, GskGLRendererClass))
|
||||
#define GSK_IS_GL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_GL_RENDERER))
|
||||
#define GSK_GL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_GL_RENDERER, GskGLRendererClass))
|
||||
|
||||
typedef struct _GskGLRenderer GskGLRenderer;
|
||||
typedef struct _GskGLRendererClass GskGLRendererClass;
|
||||
|
||||
GType gsk_gl_renderer_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_GL_RENDERER_PRIVATE_H__ */
|
||||
@@ -7,11 +7,11 @@
|
||||
|
||||
#include "gskgldriverprivate.h"
|
||||
#include "gskroundedrectprivate.h"
|
||||
#include "gskglrendererprivate.h"
|
||||
#include "gskglrenderer.h"
|
||||
#include "gskrendernodeprivate.h"
|
||||
|
||||
#define GL_N_VERTICES 6
|
||||
#define GL_N_PROGRAMS 11
|
||||
#define GL_N_PROGRAMS 12
|
||||
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ enum {
|
||||
OP_DUMP_FRAMEBUFFER = 23,
|
||||
OP_PUSH_DEBUG_GROUP = 24,
|
||||
OP_POP_DEBUG_GROUP = 25,
|
||||
OP_CHANGE_BLEND = 26,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
@@ -136,6 +137,10 @@ typedef struct
|
||||
int source2_location;
|
||||
int progress_location;
|
||||
} cross_fade;
|
||||
struct {
|
||||
int source2_location;
|
||||
int mode_location;
|
||||
} blend;
|
||||
};
|
||||
|
||||
} Program;
|
||||
@@ -214,6 +219,10 @@ typedef struct
|
||||
float progress;
|
||||
int source2;
|
||||
} cross_fade;
|
||||
struct {
|
||||
int source2;
|
||||
int mode;
|
||||
} blend;
|
||||
struct {
|
||||
char *filename;
|
||||
int width;
|
||||
|
||||
@@ -26,6 +26,11 @@
|
||||
#include <gsk/gskroundedrect.h>
|
||||
#include <gsk/gsktransform.h>
|
||||
|
||||
#include <gsk/gskcairorenderer.h>
|
||||
#include <gsk/gl/gskglrenderer.h>
|
||||
#include <gsk/broadway/gskbroadwayrenderer.h>
|
||||
#include <gsk/vulkan/gskvulkanrenderer.h>
|
||||
|
||||
#include <gsk/gsktypes.h>
|
||||
#include <gsk/gskenumtypes.h>
|
||||
|
||||
|
||||
@@ -1,6 +1,26 @@
|
||||
/*
|
||||
* Copyright © 2016 Endless
|
||||
* 2018 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gskcairorendererprivate.h"
|
||||
#include "gskcairorenderer.h"
|
||||
|
||||
#include "gskdebugprivate.h"
|
||||
#include "gskrendererprivate.h"
|
||||
@@ -159,3 +179,23 @@ gsk_cairo_renderer_init (GskCairoRenderer *self)
|
||||
self->profile_timers.cpu_time = gsk_profiler_add_timer (profiler, "cpu-time", "CPU time", FALSE, TRUE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_cairo_renderer_new:
|
||||
*
|
||||
* Creates a new Cairo renderer.
|
||||
*
|
||||
* The Cairo renderer is the fallback renderer drawing in ways similar
|
||||
* to how GTK 3 drew its content. Its primary use is as comparison tool.
|
||||
*
|
||||
* The Cairo renderer is incomplete. It cannot render 3D transformed
|
||||
* content and will instead render an error marker. Its usage should be
|
||||
* avoided.
|
||||
*
|
||||
* Returns: a new Cairo renderer.
|
||||
**/
|
||||
GskRenderer *
|
||||
gsk_cairo_renderer_new (void)
|
||||
{
|
||||
return g_object_new (GSK_TYPE_CAIRO_RENDERER, NULL);
|
||||
}
|
||||
|
||||
48
gsk/gskcairorenderer.h
Normal file
48
gsk/gskcairorenderer.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright © 2016 Endless
|
||||
* 2018 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GSK_CAIRO_RENDERER_H__
|
||||
#define __GSK_CAIRO_RENDERER_H__
|
||||
|
||||
#include <cairo.h>
|
||||
#include <gsk/gskrenderer.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_CAIRO_RENDERER (gsk_cairo_renderer_get_type ())
|
||||
|
||||
#define GSK_CAIRO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_CAIRO_RENDERER, GskCairoRenderer))
|
||||
#define GSK_IS_CAIRO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_CAIRO_RENDERER))
|
||||
#define GSK_CAIRO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_CAIRO_RENDERER, GskCairoRendererClass))
|
||||
#define GSK_IS_CAIRO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_CAIRO_RENDERER))
|
||||
#define GSK_CAIRO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_CAIRO_RENDERER, GskCairoRendererClass))
|
||||
|
||||
typedef struct _GskCairoRenderer GskCairoRenderer;
|
||||
typedef struct _GskCairoRendererClass GskCairoRendererClass;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gsk_cairo_renderer_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskRenderer * gsk_cairo_renderer_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_CAIRO_RENDERER_H__ */
|
||||
@@ -1,24 +0,0 @@
|
||||
#ifndef __GSK_CAIRO_RENDERER_PRIVATE_H__
|
||||
#define __GSK_CAIRO_RENDERER_PRIVATE_H__
|
||||
|
||||
#include <cairo.h>
|
||||
#include <gsk/gskrenderer.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_CAIRO_RENDERER (gsk_cairo_renderer_get_type ())
|
||||
|
||||
#define GSK_CAIRO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_CAIRO_RENDERER, GskCairoRenderer))
|
||||
#define GSK_IS_CAIRO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_CAIRO_RENDERER))
|
||||
#define GSK_CAIRO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_CAIRO_RENDERER, GskCairoRendererClass))
|
||||
#define GSK_IS_CAIRO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_CAIRO_RENDERER))
|
||||
#define GSK_CAIRO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_CAIRO_RENDERER, GskCairoRendererClass))
|
||||
|
||||
typedef struct _GskCairoRenderer GskCairoRenderer;
|
||||
typedef struct _GskCairoRendererClass GskCairoRendererClass;
|
||||
|
||||
GType gsk_cairo_renderer_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_CAIRO_RENDERER_PRIVATE_H__ */
|
||||
@@ -365,6 +365,19 @@ gsk_profiler_timer_get (GskProfiler *profiler,
|
||||
return timer->value;
|
||||
}
|
||||
|
||||
gint64
|
||||
gsk_profiler_timer_get_start (GskProfiler *profiler,
|
||||
GQuark timer_id)
|
||||
{
|
||||
NamedTimer *timer;
|
||||
|
||||
timer = gsk_profiler_get_timer (profiler, timer_id);
|
||||
if (timer == NULL)
|
||||
return 0;
|
||||
|
||||
return timer->start_time;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_profiler_reset (GskProfiler *profiler)
|
||||
{
|
||||
|
||||
@@ -40,6 +40,8 @@ gint64 gsk_profiler_counter_get (GskProfiler *profiler,
|
||||
GQuark counter_id);
|
||||
gint64 gsk_profiler_timer_get (GskProfiler *profiler,
|
||||
GQuark timer_id);
|
||||
gint64 gsk_profiler_timer_get_start (GskProfiler *profiler,
|
||||
GQuark timer_id);
|
||||
|
||||
void gsk_profiler_reset (GskProfiler *profiler);
|
||||
|
||||
|
||||
@@ -36,9 +36,9 @@
|
||||
|
||||
#include "gskrendererprivate.h"
|
||||
|
||||
#include "gskcairorendererprivate.h"
|
||||
#include "gskcairorenderer.h"
|
||||
#include "gskdebugprivate.h"
|
||||
#include "gl/gskglrendererprivate.h"
|
||||
#include "gl/gskglrenderer.h"
|
||||
#include "gskprofilerprivate.h"
|
||||
#include "gskrendernodeprivate.h"
|
||||
|
||||
@@ -55,10 +55,10 @@
|
||||
#include <gdk/wayland/gdkwayland.h>
|
||||
#endif
|
||||
#ifdef GDK_WINDOWING_BROADWAY
|
||||
#include "broadway/gskbroadwayrendererprivate.h"
|
||||
#include "broadway/gskbroadwayrenderer.h"
|
||||
#endif
|
||||
#ifdef GDK_RENDERING_VULKAN
|
||||
#include "vulkan/gskvulkanrendererprivate.h"
|
||||
#include "vulkan/gskvulkanrenderer.h"
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
|
||||
#include "gskdebugprivate.h"
|
||||
#include "gskrendererprivate.h"
|
||||
#include "gskrendernodeparserprivate.h"
|
||||
|
||||
#include <graphene-gobject.h>
|
||||
|
||||
@@ -328,19 +329,11 @@ gsk_render_node_diff (GskRenderNode *node1,
|
||||
GBytes *
|
||||
gsk_render_node_serialize (GskRenderNode *node)
|
||||
{
|
||||
GVariant *node_variant, *variant;
|
||||
GBytes *result;
|
||||
char *str;
|
||||
|
||||
node_variant = gsk_render_node_serialize_node (node);
|
||||
|
||||
variant = g_variant_new ("(suuv)",
|
||||
GSK_RENDER_NODE_SERIALIZATION_ID,
|
||||
(guint32) GSK_RENDER_NODE_SERIALIZATION_VERSION,
|
||||
(guint32) gsk_render_node_get_node_type (node),
|
||||
node_variant);
|
||||
|
||||
result = g_variant_get_data_as_bytes (variant);
|
||||
g_variant_unref (variant);
|
||||
str = gsk_render_node_serialize_to_string (node);
|
||||
result = g_bytes_new_take (str, strlen (str));
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -394,39 +387,13 @@ gsk_render_node_write_to_file (GskRenderNode *node,
|
||||
* error.
|
||||
**/
|
||||
GskRenderNode *
|
||||
gsk_render_node_deserialize (GBytes *bytes,
|
||||
GError **error)
|
||||
gsk_render_node_deserialize (GBytes *bytes,
|
||||
GskParseErrorFunc error_func,
|
||||
gpointer user_data)
|
||||
{
|
||||
char *id_string;
|
||||
guint32 version, node_type;
|
||||
GVariant *variant, *node_variant;
|
||||
GskRenderNode *node = NULL;
|
||||
|
||||
variant = g_variant_new_from_bytes (G_VARIANT_TYPE ("(suuv)"), bytes, FALSE);
|
||||
|
||||
g_variant_get (variant, "(suuv)", &id_string, &version, &node_type, &node_variant);
|
||||
|
||||
if (!g_str_equal (id_string, GSK_RENDER_NODE_SERIALIZATION_ID))
|
||||
{
|
||||
g_set_error (error, GSK_SERIALIZATION_ERROR, GSK_SERIALIZATION_UNSUPPORTED_FORMAT,
|
||||
"Data not in GskRenderNode serialization format.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (version != GSK_RENDER_NODE_SERIALIZATION_VERSION)
|
||||
{
|
||||
g_set_error (error, GSK_SERIALIZATION_ERROR, GSK_SERIALIZATION_UNSUPPORTED_VERSION,
|
||||
"Format version %u not supported.", version);
|
||||
goto out;
|
||||
}
|
||||
|
||||
node = gsk_render_node_deserialize_node (node_type, node_variant, error);
|
||||
|
||||
out:
|
||||
g_free (id_string);
|
||||
g_variant_unref (node_variant);
|
||||
g_variant_unref (variant);
|
||||
node = gsk_render_node_deserialize_from_bytes (bytes, error_func, user_data);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include <gsk/gskroundedrect.h>
|
||||
#include <gsk/gsktypes.h>
|
||||
#include <gtk/css/gtkcss.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -52,6 +53,10 @@ struct _GskShadow
|
||||
float radius;
|
||||
};
|
||||
|
||||
typedef void (* GskParseErrorFunc) (const GtkCssSection *section,
|
||||
const GError *error,
|
||||
gpointer user_data);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gsk_render_node_get_type (void) G_GNUC_CONST;
|
||||
|
||||
@@ -81,8 +86,9 @@ gboolean gsk_render_node_write_to_file (GskRenderNode *
|
||||
const char *filename,
|
||||
GError **error);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskRenderNode * gsk_render_node_deserialize (GBytes *bytes,
|
||||
GError **error);
|
||||
GskRenderNode * gsk_render_node_deserialize (GBytes *bytes,
|
||||
GskParseErrorFunc error_func,
|
||||
gpointer user_data);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskRenderNode * gsk_debug_node_new (GskRenderNode *child,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1858
gsk/gskrendernodeparser.c
Normal file
1858
gsk/gskrendernodeparser.c
Normal file
File diff suppressed because it is too large
Load Diff
12
gsk/gskrendernodeparserprivate.h
Normal file
12
gsk/gskrendernodeparserprivate.h
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
#ifndef __GSK_RENDER_NODE_PARSER_PRIVATE_H__
|
||||
#define __GSK_RENDER_NODE_PARSER_PRIVATE_H__
|
||||
|
||||
#include "gskrendernode.h"
|
||||
|
||||
GskRenderNode * gsk_render_node_deserialize_from_bytes (GBytes *bytes,
|
||||
GskParseErrorFunc error_func,
|
||||
gpointer user_data);
|
||||
char * gsk_render_node_serialize_to_string (GskRenderNode *root);
|
||||
|
||||
#endif
|
||||
@@ -33,9 +33,6 @@ struct _GskRenderNodeClass
|
||||
void (* diff) (GskRenderNode *node1,
|
||||
GskRenderNode *node2,
|
||||
cairo_region_t *region);
|
||||
GVariant * (* serialize) (GskRenderNode *node);
|
||||
GskRenderNode * (* deserialize) (GVariant *variant,
|
||||
GError **error);
|
||||
};
|
||||
|
||||
GskRenderNode * gsk_render_node_new (const GskRenderNodeClass *node_class,
|
||||
@@ -50,11 +47,6 @@ void gsk_render_node_diff_impossible (GskRenderNode *nod
|
||||
GskRenderNode *node2,
|
||||
cairo_region_t *region);
|
||||
|
||||
GVariant * gsk_render_node_serialize_node (GskRenderNode *node);
|
||||
GskRenderNode * gsk_render_node_deserialize_node (GskRenderNodeType type,
|
||||
GVariant *variant,
|
||||
GError **error);
|
||||
|
||||
GskRenderNode * gsk_cairo_node_new_for_surface (const graphene_rect_t *bounds,
|
||||
cairo_surface_t *surface);
|
||||
|
||||
|
||||
@@ -197,9 +197,10 @@ gsk_rounded_rect_offset (GskRoundedRect *self,
|
||||
}
|
||||
|
||||
static void
|
||||
border_radius_shrink (graphene_size_t *corner,
|
||||
double width,
|
||||
double height)
|
||||
border_radius_shrink (graphene_size_t *corner,
|
||||
double width,
|
||||
double height,
|
||||
const graphene_size_t *max)
|
||||
{
|
||||
if (corner->width > 0)
|
||||
corner->width -= width;
|
||||
@@ -211,6 +212,11 @@ border_radius_shrink (graphene_size_t *corner,
|
||||
corner->width = 0;
|
||||
corner->height = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
corner->width = MIN (corner->width, max->width);
|
||||
corner->height = MIN (corner->height, max->height);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -260,10 +266,10 @@ gsk_rounded_rect_shrink (GskRoundedRect *self,
|
||||
self->bounds.size.height -= top + bottom;
|
||||
}
|
||||
|
||||
border_radius_shrink (&self->corner[GSK_CORNER_TOP_LEFT], left, top);
|
||||
border_radius_shrink (&self->corner[GSK_CORNER_TOP_RIGHT], right, top);
|
||||
border_radius_shrink (&self->corner[GSK_CORNER_BOTTOM_RIGHT], right, bottom);
|
||||
border_radius_shrink (&self->corner[GSK_CORNER_BOTTOM_LEFT], left, bottom);
|
||||
border_radius_shrink (&self->corner[GSK_CORNER_TOP_LEFT], left, top, &self->bounds.size);
|
||||
border_radius_shrink (&self->corner[GSK_CORNER_TOP_RIGHT], right, top, &self->bounds.size);
|
||||
border_radius_shrink (&self->corner[GSK_CORNER_BOTTOM_RIGHT], right, bottom, &self->bounds.size);
|
||||
border_radius_shrink (&self->corner[GSK_CORNER_BOTTOM_LEFT], left, bottom, &self->bounds.size);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:gsktransform
|
||||
* SECTION:GskTransform
|
||||
* @Title: GskTransform
|
||||
* @Short_description: A description for transform operations
|
||||
*
|
||||
@@ -42,8 +42,7 @@ typedef struct _GskTransformClass GskTransformClass;
|
||||
struct _GskTransform
|
||||
{
|
||||
const GskTransformClass *transform_class;
|
||||
|
||||
volatile int ref_count;
|
||||
|
||||
GskTransformCategory category;
|
||||
GskTransform *next;
|
||||
};
|
||||
@@ -113,10 +112,9 @@ gsk_transform_alloc (const GskTransformClass *transform_class,
|
||||
|
||||
g_return_val_if_fail (transform_class != NULL, NULL);
|
||||
|
||||
self = g_malloc0 (transform_class->struct_size);
|
||||
self = g_atomic_rc_box_alloc0 (transform_class->struct_size);
|
||||
|
||||
self->transform_class = transform_class;
|
||||
self->ref_count = 1;
|
||||
self->category = next ? MIN (category, next->category) : category;
|
||||
self->next = gsk_transform_is_identity (next) ? NULL : next;
|
||||
|
||||
@@ -312,15 +310,15 @@ gsk_matrix_transform_apply_affine (GskTransform *transform,
|
||||
break;
|
||||
|
||||
case GSK_TRANSFORM_CATEGORY_2D_AFFINE:
|
||||
*out_dx += *out_scale_x * graphene_matrix_get_value (&self->matrix, 3, 0);
|
||||
*out_dy += *out_scale_y * graphene_matrix_get_value (&self->matrix, 3, 1);
|
||||
*out_scale_x *= graphene_matrix_get_value (&self->matrix, 0, 0);
|
||||
*out_scale_y *= graphene_matrix_get_value (&self->matrix, 1, 1);
|
||||
*out_dx += *out_scale_x * graphene_matrix_get_x_translation (&self->matrix);
|
||||
*out_dy += *out_scale_y * graphene_matrix_get_y_translation (&self->matrix);
|
||||
*out_scale_x *= graphene_matrix_get_x_scale (&self->matrix);
|
||||
*out_scale_y *= graphene_matrix_get_y_scale (&self->matrix);
|
||||
break;
|
||||
|
||||
case GSK_TRANSFORM_CATEGORY_2D_TRANSLATE:
|
||||
*out_dx += *out_scale_x * graphene_matrix_get_value (&self->matrix, 3, 0);
|
||||
*out_dy += *out_scale_y * graphene_matrix_get_value (&self->matrix, 3, 1);
|
||||
*out_dx += *out_scale_x * graphene_matrix_get_x_translation (&self->matrix);
|
||||
*out_dy += *out_scale_y * graphene_matrix_get_y_translation (&self->matrix);
|
||||
break;
|
||||
|
||||
case GSK_TRANSFORM_CATEGORY_IDENTITY:
|
||||
@@ -347,8 +345,8 @@ gsk_matrix_transform_apply_translate (GskTransform *transform,
|
||||
break;
|
||||
|
||||
case GSK_TRANSFORM_CATEGORY_2D_TRANSLATE:
|
||||
*out_dx += graphene_matrix_get_value (&self->matrix, 3, 0);
|
||||
*out_dy += graphene_matrix_get_value (&self->matrix, 3, 1);
|
||||
*out_dx += graphene_matrix_get_x_translation (&self->matrix);
|
||||
*out_dy += graphene_matrix_get_y_translation (&self->matrix);
|
||||
break;
|
||||
|
||||
case GSK_TRANSFORM_CATEGORY_IDENTITY:
|
||||
@@ -421,8 +419,10 @@ gsk_matrix_transform_equal (GskTransform *first_transform,
|
||||
GskMatrixTransform *first = (GskMatrixTransform *) first_transform;
|
||||
GskMatrixTransform *second = (GskMatrixTransform *) second_transform;
|
||||
|
||||
/* Crude, but better than just returning FALSE */
|
||||
return memcmp (&first->matrix, &second->matrix, sizeof (graphene_matrix_t)) == 0;
|
||||
if (graphene_matrix_equal_fast (&first->matrix, &second->matrix))
|
||||
return TRUE;
|
||||
|
||||
return graphene_matrix_equal (&first->matrix, &second->matrix);
|
||||
}
|
||||
|
||||
static const GskTransformClass GSK_TRANSFORM_TRANSFORM_CLASS =
|
||||
@@ -735,7 +735,7 @@ gsk_rotate_transform_equal (GskTransform *first_transform,
|
||||
GskRotateTransform *first = (GskRotateTransform *) first_transform;
|
||||
GskRotateTransform *second = (GskRotateTransform *) second_transform;
|
||||
|
||||
return first->angle == second->angle;
|
||||
return G_APPROX_VALUE (first->angle, second->angle, 0.01f);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -837,8 +837,8 @@ gsk_rotate3d_transform_equal (GskTransform *first_transform,
|
||||
GskRotate3dTransform *first = (GskRotate3dTransform *) first_transform;
|
||||
GskRotate3dTransform *second = (GskRotate3dTransform *) second_transform;
|
||||
|
||||
return first->angle == second->angle
|
||||
&& graphene_vec3_equal (&first->axis, &second->axis);
|
||||
return G_APPROX_VALUE (first->angle, second->angle, 0.01f) &&
|
||||
graphene_vec3_equal (&first->axis, &second->axis);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -996,9 +996,9 @@ gsk_scale_transform_equal (GskTransform *first_transform,
|
||||
GskScaleTransform *first = (GskScaleTransform *) first_transform;
|
||||
GskScaleTransform *second = (GskScaleTransform *) second_transform;
|
||||
|
||||
return first->factor_x == second->factor_x
|
||||
&& first->factor_y == second->factor_y
|
||||
&& first->factor_z == second->factor_z;
|
||||
return G_APPROX_VALUE (first->factor_x, second->factor_x, 0.01f) &&
|
||||
G_APPROX_VALUE (first->factor_y, second->factor_y, 0.01f) &&
|
||||
G_APPROX_VALUE (first->factor_z, second->factor_z, 0.01f);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1150,7 +1150,7 @@ gsk_perspective_transform_equal (GskTransform *first_transform,
|
||||
GskPerspectiveTransform *first = (GskPerspectiveTransform *) first_transform;
|
||||
GskPerspectiveTransform *second = (GskPerspectiveTransform *) second_transform;
|
||||
|
||||
return first->depth == second->depth;
|
||||
return G_APPROX_VALUE (first->depth, second->depth, 0.001f);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1217,8 +1217,6 @@ gsk_transform_finalize (GskTransform *self)
|
||||
self->transform_class->finalize (self);
|
||||
|
||||
gsk_transform_unref (self->next);
|
||||
|
||||
g_free (self);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1235,9 +1233,7 @@ gsk_transform_ref (GskTransform *self)
|
||||
if (self == NULL)
|
||||
return NULL;
|
||||
|
||||
g_atomic_int_inc (&self->ref_count);
|
||||
|
||||
return self;
|
||||
return g_atomic_rc_box_acquire (self);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1255,8 +1251,7 @@ gsk_transform_unref (GskTransform *self)
|
||||
if (self == NULL)
|
||||
return;
|
||||
|
||||
if (g_atomic_int_dec_and_test (&self->ref_count))
|
||||
gsk_transform_finalize (self);
|
||||
g_atomic_rc_box_release_full (self, (GDestroyNotify) gsk_transform_finalize);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,6 +11,7 @@ gsk_private_gl_shaders = [
|
||||
'resources/glsl/unblurred_outset_shadow.fs.glsl',
|
||||
'resources/glsl/border.fs.glsl',
|
||||
'resources/glsl/cross_fade.fs.glsl',
|
||||
'resources/glsl/blend.fs.glsl',
|
||||
'resources/glsl/es2_common.fs.glsl',
|
||||
'resources/glsl/es2_common.vs.glsl',
|
||||
'resources/glsl/gl3_common.fs.glsl',
|
||||
@@ -21,22 +22,23 @@ gsk_private_gl_shaders = [
|
||||
|
||||
gsk_public_sources = files([
|
||||
'gskdiff.c',
|
||||
'gskcairorenderer.c',
|
||||
'gskrenderer.c',
|
||||
'gskrendernode.c',
|
||||
'gskrendernodeimpl.c',
|
||||
'gskroundedrect.c',
|
||||
'gsktransform.c',
|
||||
'gl/gskglrenderer.c',
|
||||
])
|
||||
|
||||
gsk_private_sources = files([
|
||||
'gskcairoblur.c',
|
||||
'gskcairorenderer.c',
|
||||
'gskdebug.c',
|
||||
'gskprivate.c',
|
||||
'gskprofiler.c',
|
||||
'gskrendernodeparser.c',
|
||||
'gl/gskshaderbuilder.c',
|
||||
'gl/gskglprofiler.c',
|
||||
'gl/gskglrenderer.c',
|
||||
'gl/gskglglyphcache.c',
|
||||
'gl/gskglimage.c',
|
||||
'gl/gskgldriver.c',
|
||||
@@ -46,17 +48,35 @@ gsk_private_sources = files([
|
||||
])
|
||||
|
||||
gsk_public_headers = files([
|
||||
'gskcairorenderer.h',
|
||||
'gskenums.h',
|
||||
'gskrenderer.h',
|
||||
'gskrendernode.h',
|
||||
'gskroundedrect.h',
|
||||
'gsktransform.h',
|
||||
'gsktypes.h',
|
||||
'gsk-autocleanup.h'
|
||||
'gsk-autocleanup.h',
|
||||
])
|
||||
|
||||
install_headers(gsk_public_headers, 'gsk.h', subdir: 'gtk-4.0/gsk')
|
||||
|
||||
gsk_public_gl_headers = files([
|
||||
'gl/gskglrenderer.h'
|
||||
])
|
||||
install_headers(gsk_public_gl_headers, subdir: 'gtk-4.0/gsk/gl')
|
||||
gsk_public_headers += gsk_public_gl_headers
|
||||
|
||||
gsk_public_broadway_headers = files([
|
||||
'broadway/gskbroadwayrenderer.h'
|
||||
])
|
||||
install_headers(gsk_public_broadway_headers, subdir: 'gtk-4.0/gsk/broadway')
|
||||
gsk_public_headers += gsk_public_broadway_headers
|
||||
|
||||
gsk_public_vulkan_headers = files([
|
||||
'vulkan/gskvulkanrenderer.h'
|
||||
])
|
||||
install_headers(gsk_public_vulkan_headers, subdir: 'gtk-4.0/gsk/vulkan')
|
||||
gsk_public_headers += gsk_public_vulkan_headers
|
||||
|
||||
gsk_private_vulkan_shaders = []
|
||||
# This is an odd split because we use configure_file() below to workaround
|
||||
# a limitation in meson preventing using custom_target() with gnome.compile_resources()
|
||||
@@ -96,7 +116,7 @@ if have_vulkan
|
||||
endif # have_vulkan
|
||||
|
||||
if get_variable('broadway_enabled')
|
||||
gsk_private_sources += files([
|
||||
gsk_public_sources += files([
|
||||
'broadway/gskbroadwayrenderer.c',
|
||||
])
|
||||
endif
|
||||
|
||||
287
gsk/resources/glsl/blend.fs.glsl
Normal file
287
gsk/resources/glsl/blend.fs.glsl
Normal file
@@ -0,0 +1,287 @@
|
||||
uniform int u_mode;
|
||||
uniform sampler2D u_source2;
|
||||
|
||||
float
|
||||
combine (float source, float backdrop)
|
||||
{
|
||||
return source + backdrop * (1 - source);
|
||||
}
|
||||
|
||||
vec4
|
||||
composite (vec4 Cs, vec4 Cb, vec3 B)
|
||||
{
|
||||
float ao = Cs.a + Cb.a * (1 - Cs.a);
|
||||
vec3 Co = (Cs.a*(1 - Cb.a)*Cs.rgb + Cs.a*Cb.a*B + (1 - Cs.a)*Cb.a*Cb.rgb) / ao;
|
||||
return vec4(Co, ao);
|
||||
}
|
||||
|
||||
vec4
|
||||
normal (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
return composite (Cs, Cb, Cs.rgb);
|
||||
}
|
||||
|
||||
vec4
|
||||
multiply (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
return composite (Cs, Cb, Cs.rgb * Cb.rgb);
|
||||
}
|
||||
|
||||
vec4
|
||||
difference (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
return composite (Cs, Cb, abs(Cs.rgb - Cb.rgb));
|
||||
}
|
||||
|
||||
vec4
|
||||
screen (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
return composite (Cs, Cb, Cs.rgb + Cb.rgb - Cs.rgb * Cb.rgb);
|
||||
}
|
||||
|
||||
float
|
||||
hard_light (float source, float backdrop)
|
||||
{
|
||||
if (source <= 0.5)
|
||||
return 2 * backdrop * source;
|
||||
else
|
||||
return 2 * (backdrop + source - backdrop * source) - 1;
|
||||
}
|
||||
|
||||
vec4
|
||||
hard_light (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = vec3 (hard_light (Cs.r, Cb.r),
|
||||
hard_light (Cs.g, Cb.g),
|
||||
hard_light (Cs.b, Cb.b));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
float
|
||||
soft_light (float source, float backdrop)
|
||||
{
|
||||
float db;
|
||||
|
||||
if (backdrop <= 0.25)
|
||||
db = ((16 * backdrop - 12) * backdrop + 4) * backdrop;
|
||||
else
|
||||
db = sqrt (backdrop);
|
||||
|
||||
if (source <= 0.5)
|
||||
return backdrop - (1 - 2 * source) * backdrop * (1 - backdrop);
|
||||
else
|
||||
return backdrop + (2 * source - 1) * (db - backdrop);
|
||||
}
|
||||
|
||||
vec4
|
||||
soft_light (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = vec3 (soft_light (Cs.r, Cb.r),
|
||||
soft_light (Cs.g, Cb.g),
|
||||
soft_light (Cs.b, Cb.b));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
overlay (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = vec3 (hard_light (Cb.r, Cs.r),
|
||||
hard_light (Cb.g, Cs.g),
|
||||
hard_light (Cb.b, Cs.b));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
darken (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = min (Cs.rgb, Cb.rgb);
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
lighten (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = max (Cs.rgb, Cb.rgb);
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
float
|
||||
color_dodge (float source, float backdrop)
|
||||
{
|
||||
return (source == 1.0) ? source : min (backdrop / (1.0 - source), 1.0);
|
||||
}
|
||||
|
||||
vec4
|
||||
color_dodge (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = vec3 (color_dodge (Cs.r, Cb.r),
|
||||
color_dodge (Cs.g, Cb.g),
|
||||
color_dodge (Cs.b, Cb.b));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
color_burn (float source, float backdrop)
|
||||
{
|
||||
return (source == 0.0) ? source : max ((1.0 - ((1.0 - backdrop) / source)), 0.0);
|
||||
}
|
||||
|
||||
vec4
|
||||
color_burn (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = vec3 (color_burn (Cs.r, Cb.r),
|
||||
color_burn (Cs.g, Cb.g),
|
||||
color_burn (Cs.b, Cb.b));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
exclusion (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = Cb.rgb + Cs.rgb - 2.0 * Cb.rgb * Cs.rgb;
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
float
|
||||
lum (vec3 c)
|
||||
{
|
||||
return 0.3 * c.r + 0.59 * c.g + 0.11 * c.b;
|
||||
}
|
||||
|
||||
vec3
|
||||
clip_color (vec3 c)
|
||||
{
|
||||
float l = lum (c);
|
||||
float n = min (c.r, min (c.g, c.b));
|
||||
float x = max (c.r, max (c.g, c.b));
|
||||
if (n < 0) c = l + (((c - l) * l) / (l - n));
|
||||
if (x > 1) c = l + (((c - l) * (1 - l)) / (x - l));
|
||||
return c;
|
||||
}
|
||||
|
||||
vec3
|
||||
set_lum (vec3 c, float l)
|
||||
{
|
||||
float d = l - lum (c);
|
||||
return clip_color (vec3 (c.r + d, c.g + d, c.b + d));
|
||||
}
|
||||
|
||||
float
|
||||
sat (vec3 c)
|
||||
{
|
||||
return max (c.r, max (c.g, c.b)) - min (c.r, min (c.g, c.b));
|
||||
}
|
||||
|
||||
vec3
|
||||
set_sat (vec3 c, float s)
|
||||
{
|
||||
float cmin = min (c.r, min (c.g, c.b));
|
||||
float cmax = max (c.r, max (c.g, c.b));
|
||||
vec3 res;
|
||||
|
||||
if (cmax == cmin)
|
||||
res = vec3 (0, 0, 0);
|
||||
else
|
||||
{
|
||||
if (c.r == cmax)
|
||||
{
|
||||
if (c.g == cmin)
|
||||
{
|
||||
res.b = ((c.b - cmin) * s) / (cmax - cmin);
|
||||
res.g = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res.g = ((c.g - cmin) * s) / (cmax - cmin);
|
||||
res.b = 0;
|
||||
}
|
||||
res.r = s;
|
||||
}
|
||||
else if (c.g == cmax)
|
||||
{
|
||||
if (c.r == cmin)
|
||||
{
|
||||
res.b = ((c.b - cmin) * s) / (cmax - cmin);
|
||||
res.r = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res.r = ((c.r - cmin) * s) / (cmax - cmin);
|
||||
res.b = 0;
|
||||
}
|
||||
res.g = s;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c.r == cmin)
|
||||
{
|
||||
res.g = ((c.g - cmin) * s) / (cmax - cmin);
|
||||
res.r = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res.r = ((c.r - cmin) * s) / (cmax - cmin);
|
||||
res.g = 0;
|
||||
}
|
||||
res.b = s;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
vec4
|
||||
color (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = set_lum (Cs.rgb, lum (Cb.rgb));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
hue (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = set_lum (set_sat (Cs.rgb, sat (Cb.rgb)), lum (Cb.rgb));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
saturation (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = set_lum (set_sat (Cb.rgb, sat (Cs.rgb)), lum (Cb.rgb));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
luminosity (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = set_lum (Cb.rgb, lum (Cs.rgb));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 bottom_color = Texture(u_source, vUv);
|
||||
vec4 top_color = Texture(u_source2, vUv);
|
||||
|
||||
vec4 result;
|
||||
switch(u_mode) {
|
||||
case 0: result = normal(top_color, bottom_color); break;
|
||||
case 1: result = multiply(top_color, bottom_color); break;
|
||||
case 2: result = screen(top_color, bottom_color); break;
|
||||
case 3: result = overlay(top_color, bottom_color); break;
|
||||
case 4: result = darken(top_color, bottom_color); break;
|
||||
case 5: result = lighten(top_color, bottom_color); break;
|
||||
case 6: result = color_dodge(top_color, bottom_color); break;
|
||||
case 7: result = color_burn(top_color, bottom_color); break;
|
||||
case 8: result = hard_light(top_color, bottom_color); break;
|
||||
case 9: result = soft_light(top_color, bottom_color); break;
|
||||
case 10: result = difference(top_color, bottom_color); break;
|
||||
case 11: result = exclusion(top_color, bottom_color); break;
|
||||
case 12: result = color(top_color, bottom_color); break;
|
||||
case 13: result = hue(top_color, bottom_color); break;
|
||||
case 14: result = saturation(top_color, bottom_color); break;
|
||||
case 15: result = luminosity(top_color, bottom_color); break;
|
||||
default: discard;
|
||||
}
|
||||
|
||||
setOutputColor(result * u_alpha);
|
||||
}
|
||||
@@ -8,7 +8,8 @@ void main() {
|
||||
color.rgb *= color.a;
|
||||
|
||||
// u_source is drawn using cairo, so already pre-multiplied.
|
||||
color = vec4(u_color.rgb * diffuse.a * u_alpha, diffuse.a * color.a * u_alpha);
|
||||
color = vec4(color.rgb * diffuse.a * u_alpha,
|
||||
color.a * diffuse.a * u_alpha);
|
||||
|
||||
setOutputColor(color);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "gskvulkanglyphcacheprivate.h"
|
||||
|
||||
#include "gdk/gdktextureprivate.h"
|
||||
#include "gdk/gdkprofilerprivate.h"
|
||||
|
||||
#include <graphene.h>
|
||||
|
||||
@@ -38,6 +39,9 @@ typedef struct {
|
||||
} ProfileTimers;
|
||||
#endif
|
||||
|
||||
static guint texture_pixels_counter;
|
||||
static guint fallback_pixels_counter;
|
||||
|
||||
struct _GskVulkanRenderer
|
||||
{
|
||||
GskRenderer parent_instance;
|
||||
@@ -170,7 +174,7 @@ gsk_vulkan_renderer_render_texture (GskRenderer *renderer,
|
||||
GdkTexture *texture;
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
GskProfiler *profiler;
|
||||
gint64 cpu_time;
|
||||
gint64 cpu_time, start_time;
|
||||
#endif
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
@@ -201,10 +205,22 @@ gsk_vulkan_renderer_render_texture (GskRenderer *renderer,
|
||||
gsk_vulkan_render_free (render);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
start_time = gsk_profiler_timer_get_start (profiler, self->profile_timers.cpu_time);
|
||||
cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
|
||||
gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
|
||||
|
||||
gsk_profiler_push_samples (profiler);
|
||||
|
||||
if (gdk_profiler_is_running ())
|
||||
{
|
||||
gdk_profiler_add_mark (start_time, cpu_time, "render", "");
|
||||
gdk_profiler_set_int_counter (texture_pixels_counter,
|
||||
start_time + cpu_time,
|
||||
gsk_profiler_counter_get (profiler, self->profile_counters.texture_pixels));
|
||||
gdk_profiler_set_int_counter (fallback_pixels_counter,
|
||||
start_time + cpu_time,
|
||||
gsk_profiler_counter_get (profiler, self->profile_counters.fallback_pixels));
|
||||
}
|
||||
#endif
|
||||
|
||||
return texture;
|
||||
@@ -284,6 +300,13 @@ gsk_vulkan_renderer_init (GskVulkanRenderer *self)
|
||||
self->profile_timers.cpu_time = gsk_profiler_add_timer (profiler, "cpu-time", "CPU time", FALSE, TRUE);
|
||||
if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), SYNC))
|
||||
self->profile_timers.gpu_time = gsk_profiler_add_timer (profiler, "gpu-time", "GPU time", FALSE, TRUE);
|
||||
|
||||
if (texture_pixels_counter == 0)
|
||||
{
|
||||
texture_pixels_counter = gdk_profiler_define_int_counter ("texture-pixels", "Texture Pixels");
|
||||
fallback_pixels_counter = gdk_profiler_define_int_counter ("fallback-pixels", "Fallback Pixels");
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -364,3 +387,22 @@ gsk_vulkan_renderer_get_cached_glyph (GskVulkanRenderer *self,
|
||||
{
|
||||
return gsk_vulkan_glyph_cache_lookup (self->glyph_cache, FALSE, font, glyph, scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_vulkan_renderer_new:
|
||||
*
|
||||
* Creates a new Vulkan renderer.
|
||||
*
|
||||
* The Vulkan renderer is a renderer that uses the Vulkan library for
|
||||
* rendering.
|
||||
*
|
||||
* This function is only available when GTK was compiled with Vulkan
|
||||
* support.
|
||||
*
|
||||
* Returns: a new Vulkan renderer
|
||||
**/
|
||||
GskRenderer *
|
||||
gsk_vulkan_renderer_new (void)
|
||||
{
|
||||
return g_object_new (GSK_TYPE_VULKAN_RENDERER, NULL);
|
||||
}
|
||||
|
||||
51
gsk/vulkan/gskvulkanrenderer.h
Normal file
51
gsk/vulkan/gskvulkanrenderer.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright © 2016 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __GSK_VULKAN_RENDERER_H__
|
||||
#define __GSK_VULKAN_RENDERER_H__
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gsk/gskrenderer.h>
|
||||
|
||||
#ifdef GDK_RENDERING_VULKAN
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_VULKAN_RENDERER (gsk_vulkan_renderer_get_type ())
|
||||
|
||||
#define GSK_VULKAN_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_VULKAN_RENDERER, GskVulkanRenderer))
|
||||
#define GSK_IS_VULKAN_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_VULKAN_RENDERER))
|
||||
#define GSK_VULKAN_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_VULKAN_RENDERER, GskVulkanRendererClass))
|
||||
#define GSK_IS_VULKAN_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_VULKAN_RENDERER))
|
||||
#define GSK_VULKAN_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_VULKAN_RENDERER, GskVulkanRendererClass))
|
||||
|
||||
typedef struct _GskVulkanRenderer GskVulkanRenderer;
|
||||
typedef struct _GskVulkanRendererClass GskVulkanRendererClass;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gsk_vulkan_renderer_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskRenderer * gsk_vulkan_renderer_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* GDK_WINDOWING_VULKAN */
|
||||
|
||||
#endif /* __GSK_VULKAN_RENDERER_H__ */
|
||||
@@ -1,26 +1,11 @@
|
||||
#ifndef __GSK_VULKAN_RENDERER_PRIVATE_H__
|
||||
#define __GSK_VULKAN_RENDERER_PRIVATE_H__
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <gsk/gskrenderer.h>
|
||||
|
||||
#include "gskvulkanrenderer.h"
|
||||
#include "gskvulkanimageprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_VULKAN_RENDERER (gsk_vulkan_renderer_get_type ())
|
||||
|
||||
#define GSK_VULKAN_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_VULKAN_RENDERER, GskVulkanRenderer))
|
||||
#define GSK_IS_VULKAN_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_VULKAN_RENDERER))
|
||||
#define GSK_VULKAN_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_VULKAN_RENDERER, GskVulkanRendererClass))
|
||||
#define GSK_IS_VULKAN_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_VULKAN_RENDERER))
|
||||
#define GSK_VULKAN_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_VULKAN_RENDERER, GskVulkanRendererClass))
|
||||
|
||||
typedef struct _GskVulkanRenderer GskVulkanRenderer;
|
||||
typedef struct _GskVulkanRendererClass GskVulkanRendererClass;
|
||||
|
||||
GType gsk_vulkan_renderer_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GskVulkanImage * gsk_vulkan_renderer_ref_texture_image (GskVulkanRenderer *self,
|
||||
GdkTexture *texture,
|
||||
GskVulkanUploader *uploader);
|
||||
|
||||
@@ -42,6 +42,13 @@ gtk_cell_accessible_parent_get_type (void)
|
||||
return g_define_type_id__volatile;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_cell_accessible_parent_get_cell_extents:
|
||||
* @x: (out):
|
||||
* @y: (out):
|
||||
* @width: (out):
|
||||
* @height: (out):
|
||||
*/
|
||||
void
|
||||
gtk_cell_accessible_parent_get_cell_extents (GtkCellAccessibleParent *parent,
|
||||
GtkCellAccessible *cell,
|
||||
@@ -61,6 +68,10 @@ gtk_cell_accessible_parent_get_cell_extents (GtkCellAccessibleParent *parent,
|
||||
(iface->get_cell_extents) (parent, cell, x, y, width, height, coord_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_cell_accessible_parent_get_cell_area:
|
||||
* @cell_rect: (out):
|
||||
*/
|
||||
void
|
||||
gtk_cell_accessible_parent_get_cell_area (GtkCellAccessibleParent *parent,
|
||||
GtkCellAccessible *cell,
|
||||
@@ -188,6 +199,11 @@ gtk_cell_accessible_parent_update_relationset (GtkCellAccessibleParent *parent,
|
||||
(iface->update_relationset) (parent, cell, relationset);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_cell_accessible_parent_get_cell_position:
|
||||
* @row: (out):
|
||||
* @column: (out):
|
||||
*/
|
||||
void
|
||||
gtk_cell_accessible_parent_get_cell_position (GtkCellAccessibleParent *parent,
|
||||
GtkCellAccessible *cell,
|
||||
|
||||
@@ -614,7 +614,6 @@ static gboolean
|
||||
gtk_icon_view_item_accessible_grab_focus (AtkComponent *component)
|
||||
{
|
||||
GtkIconViewItemAccessible *item;
|
||||
GtkWidget *toplevel;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component), FALSE);
|
||||
|
||||
@@ -624,13 +623,6 @@ gtk_icon_view_item_accessible_grab_focus (AtkComponent *component)
|
||||
|
||||
gtk_widget_grab_focus (item->widget);
|
||||
_gtk_icon_view_set_cursor_item (GTK_ICON_VIEW (item->widget), item->item, NULL);
|
||||
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (item->widget));
|
||||
if (gtk_widget_is_toplevel (toplevel))
|
||||
{
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
gtk_window_present (GTK_WINDOW (toplevel));
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -243,6 +243,7 @@ gtk_notebook_page_accessible_new (GtkNotebookAccessible *notebook,
|
||||
GObject *object;
|
||||
AtkObject *atk_object;
|
||||
GtkNotebookPageAccessible *page;
|
||||
GtkNotebook *nb;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_NOTEBOOK_ACCESSIBLE (notebook), NULL);
|
||||
g_return_val_if_fail (GTK_WIDGET (child), NULL);
|
||||
@@ -258,9 +259,10 @@ gtk_notebook_page_accessible_new (GtkNotebookAccessible *notebook,
|
||||
atk_object->layer = ATK_LAYER_WIDGET;
|
||||
|
||||
atk_object_set_parent (gtk_widget_get_accessible (child), atk_object);
|
||||
nb = GTK_NOTEBOOK (gtk_accessible_get_widget (page->priv->notebook));
|
||||
|
||||
g_signal_connect (gtk_accessible_get_widget (page->priv->notebook),
|
||||
"child-notify::tab-label",
|
||||
g_signal_connect (gtk_notebook_get_page (nb, child),
|
||||
"notify::tab-label",
|
||||
G_CALLBACK (notify_tab_label), page);
|
||||
|
||||
return atk_object;
|
||||
|
||||
@@ -1000,6 +1000,15 @@ gtk_css_parser_consume_url (GtkCssParser *self)
|
||||
return result;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_css_parser_has_number (GtkCssParser *self)
|
||||
{
|
||||
return gtk_css_parser_has_token (self, GTK_CSS_TOKEN_SIGNED_NUMBER)
|
||||
|| gtk_css_parser_has_token (self, GTK_CSS_TOKEN_SIGNLESS_NUMBER)
|
||||
|| gtk_css_parser_has_token (self, GTK_CSS_TOKEN_SIGNED_INTEGER)
|
||||
|| gtk_css_parser_has_token (self, GTK_CSS_TOKEN_SIGNLESS_INTEGER);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_css_parser_consume_number (GtkCssParser *self,
|
||||
double *number)
|
||||
|
||||
@@ -118,6 +118,7 @@ gboolean gtk_css_parser_has_token (GtkCssParser
|
||||
GtkCssTokenType token_type);
|
||||
gboolean gtk_css_parser_has_ident (GtkCssParser *self,
|
||||
const char *ident);
|
||||
gboolean gtk_css_parser_has_number (GtkCssParser *self);
|
||||
gboolean gtk_css_parser_has_integer (GtkCssParser *self);
|
||||
gboolean gtk_css_parser_has_function (GtkCssParser *self,
|
||||
const char *name);
|
||||
|
||||
@@ -633,13 +633,6 @@ is_name (char c)
|
||||
|| c == '-';
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_valid_escape (char c1, char c2)
|
||||
{
|
||||
return c1 == '\\'
|
||||
&& !is_newline (c2);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_non_printable (char c)
|
||||
{
|
||||
@@ -650,6 +643,25 @@ is_non_printable (char c)
|
||||
|| c == 0x7F;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_valid_escape (const char *data,
|
||||
const char *end)
|
||||
{
|
||||
switch (end - data)
|
||||
{
|
||||
default:
|
||||
if (is_newline (data[1]))
|
||||
return FALSE;
|
||||
G_GNUC_FALLTHROUGH;
|
||||
|
||||
case 1:
|
||||
return data[0] == '\\';
|
||||
|
||||
case 0:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static inline gsize
|
||||
gtk_css_tokenizer_remaining (GtkCssTokenizer *tokenizer)
|
||||
{
|
||||
@@ -659,15 +671,7 @@ gtk_css_tokenizer_remaining (GtkCssTokenizer *tokenizer)
|
||||
static gboolean
|
||||
gtk_css_tokenizer_has_valid_escape (GtkCssTokenizer *tokenizer)
|
||||
{
|
||||
switch (gtk_css_tokenizer_remaining (tokenizer))
|
||||
{
|
||||
case 0:
|
||||
return FALSE;
|
||||
case 1:
|
||||
return *tokenizer->data == '\\';
|
||||
default:
|
||||
return is_valid_escape (tokenizer->data[0], tokenizer->data[1]);
|
||||
}
|
||||
return is_valid_escape (tokenizer->data, tokenizer->end);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -814,7 +818,11 @@ gtk_css_tokenizer_read_escape (GtkCssTokenizer *tokenizer)
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
value = g_utf8_get_char_validated (tokenizer->data, gtk_css_tokenizer_remaining (tokenizer));
|
||||
gsize remaining = gtk_css_tokenizer_remaining (tokenizer);
|
||||
if (remaining == 0)
|
||||
return 0xFFFD;
|
||||
|
||||
value = g_utf8_get_char_validated (tokenizer->data, remaining);
|
||||
if (value == (gunichar) -1 || value == (gunichar) -2)
|
||||
value = 0;
|
||||
|
||||
@@ -1376,6 +1384,7 @@ gtk_css_tokenizer_read_token (GtkCssTokenizer *tokenizer,
|
||||
else
|
||||
{
|
||||
gtk_css_token_init (token, GTK_CSS_TOKEN_DELIM, '\\');
|
||||
gtk_css_tokenizer_consume_ascii (tokenizer);
|
||||
gtk_css_tokenizer_parse_error (error, "Newline may not follow '\' escape character");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ def get_files(subdir,extension):
|
||||
|
||||
xml += '''
|
||||
<file>theme/Adwaita/gtk.css</file>
|
||||
<file>theme/Adwaita/gtk-dark.css</file>
|
||||
<file alias='theme/Adwaita-dark/gtk.css'>theme/Adwaita/gtk-dark.css</file>
|
||||
<file>theme/Adwaita/gtk-contained.css</file>
|
||||
<file>theme/Adwaita/gtk-contained-dark.css</file>
|
||||
'''
|
||||
@@ -70,6 +70,7 @@ for f in get_files('inspector', '.ui'):
|
||||
|
||||
xml += '''
|
||||
<file>inspector/logo.png</file>
|
||||
<file>inspector/inspector.css</file>
|
||||
<file>emoji/emoji.data</file>
|
||||
</gresource>
|
||||
</gresources>'''
|
||||
|
||||
@@ -21,6 +21,11 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkapplication.h"
|
||||
#include "gdkprofilerprivate.h"
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
#include <gio/gunixfdlist.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -603,6 +608,148 @@ gtk_application_finalize (GObject *object)
|
||||
G_OBJECT_CLASS (gtk_application_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
|
||||
static const gchar org_gnome_Sysprof3_Profiler_xml[] =
|
||||
"<node>"
|
||||
"<interface name='org.gnome.Sysprof3.Profiler'>"
|
||||
"<method name='Start'>"
|
||||
"<arg type='h' name='fd' direction='in'/>"
|
||||
"</method>"
|
||||
"<method name='Stop'>"
|
||||
"</method>"
|
||||
"</interface>"
|
||||
"</node>";
|
||||
|
||||
static GDBusInterfaceInfo *org_gnome_Sysprof3_Profiler;
|
||||
|
||||
static void
|
||||
sysprof_profiler_method_call (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (strcmp (method_name, "Start") == 0)
|
||||
{
|
||||
GDBusMessage *message;
|
||||
GUnixFDList *fd_list;
|
||||
int fd = -1;
|
||||
int idx;
|
||||
|
||||
if (gdk_profiler_is_running ())
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_FAILED,
|
||||
"Profiler already running");
|
||||
return;
|
||||
}
|
||||
|
||||
g_variant_get (parameters, "(h)", &idx);
|
||||
|
||||
message = g_dbus_method_invocation_get_message (invocation);
|
||||
fd_list = g_dbus_message_get_unix_fd_list (message);
|
||||
if (fd_list)
|
||||
fd = g_unix_fd_list_get (fd_list, idx, NULL);
|
||||
|
||||
gdk_profiler_start (fd);
|
||||
}
|
||||
else if (strcmp (method_name, "Stop") == 0)
|
||||
{
|
||||
if (!gdk_profiler_is_running ())
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_FAILED,
|
||||
"Profiler not running");
|
||||
return;
|
||||
}
|
||||
|
||||
gdk_profiler_stop ();
|
||||
}
|
||||
else
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_UNKNOWN_METHOD,
|
||||
"Unknown method");
|
||||
return;
|
||||
}
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_application_dbus_register (GApplication *application,
|
||||
GDBusConnection *connection,
|
||||
const char *obect_path,
|
||||
GError **error)
|
||||
{
|
||||
GtkApplicationImplDBus *dbus = (GtkApplicationImplDBus *) application;
|
||||
GDBusInterfaceVTable vtable = {
|
||||
sysprof_profiler_method_call,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
if (org_gnome_Sysprof3_Profiler == NULL)
|
||||
{
|
||||
GDBusNodeInfo *info;
|
||||
|
||||
info = g_dbus_node_info_new_for_xml (org_gnome_Sysprof3_Profiler_xml, error);
|
||||
if (info == NULL)
|
||||
return FALSE;
|
||||
|
||||
org_gnome_Sysprof3_Profiler = g_dbus_node_info_lookup_interface (info, "org.gnome.Sysprof3.Profiler");
|
||||
g_dbus_interface_info_ref (org_gnome_Sysprof3_Profiler);
|
||||
g_dbus_node_info_unref (info);
|
||||
}
|
||||
|
||||
dbus->profiler_id = g_dbus_connection_register_object (connection,
|
||||
"/org/gtk/Profiler",
|
||||
org_gnome_Sysprof3_Profiler,
|
||||
&vtable,
|
||||
NULL,
|
||||
NULL,
|
||||
error);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_application_dbus_unregister (GApplication *application,
|
||||
GDBusConnection *connection,
|
||||
const char *obect_path)
|
||||
{
|
||||
GtkApplicationImplDBus *dbus = (GtkApplicationImplDBus *) application;
|
||||
|
||||
g_dbus_connection_unregister_object (connection, dbus->profiler_id);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static gboolean
|
||||
gtk_application_dbus_register (GApplication *application,
|
||||
GDBusConnection *connection,
|
||||
const char *obect_path,
|
||||
GError **error)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_application_dbus_unregister (GApplication *application,
|
||||
GDBusConnection *connection,
|
||||
const char *obect_path)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
gtk_application_class_init (GtkApplicationClass *class)
|
||||
{
|
||||
@@ -619,6 +766,8 @@ gtk_application_class_init (GtkApplicationClass *class)
|
||||
application_class->after_emit = gtk_application_after_emit;
|
||||
application_class->startup = gtk_application_startup;
|
||||
application_class->shutdown = gtk_application_shutdown;
|
||||
application_class->dbus_register = gtk_application_dbus_register;
|
||||
application_class->dbus_unregister = gtk_application_dbus_unregister;
|
||||
|
||||
class->window_added = gtk_application_window_added;
|
||||
class->window_removed = gtk_application_window_removed;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user