Compare commits
2 Commits
editor-exp
...
filter-sel
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f2bce941a | ||
|
|
0a7fb26909 |
@@ -222,7 +222,7 @@ macos:
|
||||
-Dcpp_std=c++11
|
||||
-Dpixman:tests=disabled
|
||||
-Dlibjpeg-turbo:simd=disabled
|
||||
-Dbuild-demos=false
|
||||
-Ddemos=false
|
||||
-Dbuild-tests=false
|
||||
-Dbuild-examples=false
|
||||
-Dbuild-testsuite=false
|
||||
@@ -385,27 +385,17 @@ asan-build:
|
||||
tags: [ asan ]
|
||||
stage: analysis
|
||||
needs: []
|
||||
when: manual
|
||||
variables:
|
||||
script:
|
||||
- export PATH="$HOME/.local/bin:$PATH"
|
||||
- CC=clang meson setup
|
||||
--buildtype=debugoptimized
|
||||
-Db_sanitize=address
|
||||
-Db_lundef=false
|
||||
-Dbuild-demos=false
|
||||
-Dbuild-tests=false
|
||||
-Dbuild-examples=false
|
||||
-Dintrospection=disabled
|
||||
-Df16c=disabled
|
||||
_build
|
||||
- CC=clang meson setup --buildtype=debugoptimized -Db_sanitize=address -Db_lundef=false -Dintrospection=disabled -Df16c=disabled _build
|
||||
- ninja -C _build
|
||||
- .gitlab-ci/run-tests.sh _build wayland
|
||||
- .gitlab-ci/run-tests.sh _build wayland_gles
|
||||
- .gitlab-ci/run-tests.sh _build x11
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- "${CI_PROJECT_DIR}/_build/meson-logs"
|
||||
- _build/meson-logs
|
||||
allow_failure: true
|
||||
|
||||
reference:
|
||||
image: $FEDORA_IMAGE
|
||||
|
||||
@@ -9,7 +9,7 @@ backend=$2
|
||||
multiplier=${MESON_TEST_TIMEOUT_MULTIPLIER:-1}
|
||||
|
||||
# Ignore memory leaks lower in dependencies
|
||||
export LSAN_OPTIONS=suppressions=$srcdir/lsan.supp:print_suppressions=0:detect_leaks=0:allocator_may_return_null=1
|
||||
export LSAN_OPTIONS=suppressions=$srcdir/lsan.supp:print_suppressions=0:verbosity=1:log_threads=1
|
||||
export G_SLICE=always-malloc
|
||||
|
||||
case "${backend}" in
|
||||
|
||||
39
NEWS
39
NEWS
@@ -1,7 +1,4 @@
|
||||
Overview of Changes in 4.11.4, xx-xx-xxxx
|
||||
=========================================
|
||||
|
||||
Overview of Changes in 4.11.3, 05-06-2023
|
||||
Overview of Changes in 4.11.3, xx-xx-xxxx
|
||||
=========================================
|
||||
|
||||
* GtkGridView:
|
||||
@@ -23,41 +20,22 @@ Overview of Changes in 4.11.3, 05-06-2023
|
||||
* GtkPopoverMenu:
|
||||
- Avoid unnecessary left padding
|
||||
|
||||
* GtkSearchEntry:
|
||||
- Improve size allocation for the clear icon
|
||||
|
||||
* GtkBoxLayout:
|
||||
- Fix a regression from recent baseline work
|
||||
|
||||
* CSS:
|
||||
* Css:
|
||||
- Add new binding-friendly css provider apis
|
||||
|
||||
* GDK:
|
||||
- Support grayscale texture and alpha texture formats
|
||||
for loading and saving to png and tiff, and in GL
|
||||
|
||||
* Theme:
|
||||
- Show focus in the shortcuts window
|
||||
|
||||
* GDK:
|
||||
- Support grayscale and alpha texture formats for loading
|
||||
and saving to png and tiff, and in GL
|
||||
- Fix some regressions in GL context initialization
|
||||
|
||||
* GSK:
|
||||
- Support grayscale and alpha texture formats in the GL renderer
|
||||
- Support straight alpha textures in the GL renderer
|
||||
- Many improvements to the experimental Vulkan renderer
|
||||
* Tests:
|
||||
- Improve test coverage
|
||||
|
||||
* Wayland:
|
||||
- Make exporting surface handles more flexible
|
||||
|
||||
* X11:
|
||||
- Trap XRandr errors
|
||||
- Stop using passive grabs during DND
|
||||
|
||||
* Windows:
|
||||
- Many cleanups and simplifications
|
||||
|
||||
* Tests:
|
||||
- Improve test coverage
|
||||
|
||||
* Build:
|
||||
- Some build options have been renamed:
|
||||
demos -> build-demos
|
||||
@@ -77,7 +55,6 @@ Overview of Changes in 4.11.3, 05-06-2023
|
||||
* Translation updates:
|
||||
Basque
|
||||
Catalan
|
||||
Georgian
|
||||
Russian
|
||||
Turkish
|
||||
|
||||
|
||||
@@ -162,10 +162,6 @@ create_page4 (GtkWidget *assistant)
|
||||
gtk_assistant_set_page_type (GTK_ASSISTANT (assistant), progress_bar, GTK_ASSISTANT_PAGE_PROGRESS);
|
||||
gtk_assistant_set_page_title (GTK_ASSISTANT (assistant), progress_bar, "Applying changes");
|
||||
|
||||
gtk_accessible_update_property (GTK_ACCESSIBLE (progress_bar),
|
||||
GTK_ACCESSIBLE_PROPERTY_LABEL, "Applying changes",
|
||||
-1);
|
||||
|
||||
/* This prevents the assistant window from being
|
||||
* closed while we're "busy" applying changes.
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,90 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CE_TYPE_PATH (ce_path_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (CEPath, ce_path, CE, PATH, GObject)
|
||||
|
||||
typedef struct _CEPathCurve CEPathCurve;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CE_PATH_CUSP,
|
||||
CE_PATH_SMOOTH,
|
||||
CE_PATH_SYMMETRIC,
|
||||
CE_PATH_AUTOMATIC
|
||||
} CEPathConstraint;
|
||||
|
||||
CEPath * ce_path_new (void);
|
||||
|
||||
int ce_path_get_n_curves (CEPath *self);
|
||||
|
||||
CEPathCurve * ce_path_get_curve (CEPath *self,
|
||||
int idx);
|
||||
|
||||
CEPathCurve * ce_path_previous_curve (CEPath *self,
|
||||
CEPathCurve *seg);
|
||||
|
||||
CEPathCurve * ce_path_next_curve (CEPath *self,
|
||||
CEPathCurve *seg);
|
||||
|
||||
void ce_path_set_gsk_path (CEPath *self,
|
||||
GskPath *path);
|
||||
|
||||
GskPath * ce_path_get_gsk_path (CEPath *self);
|
||||
|
||||
void ce_path_split_curve (CEPath *self,
|
||||
CEPathCurve *seg,
|
||||
float pos);
|
||||
|
||||
void ce_path_remove_curve (CEPath *self,
|
||||
CEPathCurve *seg);
|
||||
|
||||
void ce_path_drag_curve (CEPath *self,
|
||||
CEPathCurve *seg,
|
||||
const graphene_point_t *pos);
|
||||
|
||||
CEPathCurve * ce_path_find_closest_curve (CEPath *self,
|
||||
graphene_point_t *point,
|
||||
float threshold,
|
||||
graphene_point_t *p,
|
||||
float *pos);
|
||||
|
||||
void ce_path_get_point (CEPath *self,
|
||||
CEPathCurve *seg,
|
||||
int c,
|
||||
graphene_point_t *point);
|
||||
|
||||
void ce_path_set_point (CEPath *self,
|
||||
CEPathCurve *seg,
|
||||
int point,
|
||||
const graphene_point_t *pos);
|
||||
|
||||
GskPathOperation
|
||||
ce_path_get_operation (CEPath *self,
|
||||
CEPathCurve *seg);
|
||||
|
||||
void ce_path_set_operation (CEPath *self,
|
||||
CEPathCurve *seg,
|
||||
GskPathOperation op);
|
||||
|
||||
float ce_path_get_weight (CEPath *self,
|
||||
CEPathCurve *seg);
|
||||
|
||||
void ce_path_set_weight (CEPath *self,
|
||||
CEPathCurve *seg,
|
||||
float weight);
|
||||
|
||||
CEPathConstraint
|
||||
ce_path_get_constraint (CEPath *self,
|
||||
CEPathCurve *seg);
|
||||
|
||||
void ce_path_set_constraint (CEPath *self,
|
||||
CEPathCurve *seg,
|
||||
CEPathConstraint constraint);
|
||||
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
@@ -4,9 +4,6 @@
|
||||
<object class="GtkWindow" id="window">
|
||||
<property name="resizable">1</property>
|
||||
<property name="title">Clipboard</property>
|
||||
<accessibility>
|
||||
<relation name="described-by">label</relation>
|
||||
</accessibility>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
@@ -16,7 +13,7 @@
|
||||
<property name="margin-bottom">12</property>
|
||||
<property name="spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label">
|
||||
<object class="GtkLabel">
|
||||
<property name="label">“Copy” will copy the selected data the clipboard, “Paste” will show the current clipboard contents. You can also drag the data to the bottom.</property>
|
||||
<property name="wrap">1</property>
|
||||
<property name="max-width-chars">40</property>
|
||||
@@ -27,9 +24,6 @@
|
||||
<property name="spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkDropDown" id="source_chooser">
|
||||
<accessibility>
|
||||
<property name="label">Source Type</property>
|
||||
</accessibility>
|
||||
<property name="valign">center</property>
|
||||
<property name="model">
|
||||
<object class="GtkStringList">
|
||||
@@ -60,9 +54,6 @@
|
||||
<property name="name">Text</property>
|
||||
<property name="child">
|
||||
<object class="GtkEntry" id="source_text">
|
||||
<accessibility>
|
||||
<property name="label">Text Drag Source</property>
|
||||
</accessibility>
|
||||
<property name="valign">center</property>
|
||||
<signal name="notify::text" handler="text_changed_cb" object="copy_button"/>
|
||||
<property name="text">Copy this!</property>
|
||||
@@ -75,9 +66,6 @@
|
||||
<property name="name">Color</property>
|
||||
<property name="child">
|
||||
<object class="GtkColorDialogButton" id="source_color">
|
||||
<accessibility>
|
||||
<property name="label">Color Drag Source</property>
|
||||
</accessibility>
|
||||
<property name="dialog">
|
||||
<object class="GtkColorDialog">
|
||||
</object>
|
||||
@@ -99,17 +87,14 @@
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="image_rose">
|
||||
<accessibility>
|
||||
<property name="label">Photo Drag Source</property>
|
||||
</accessibility>
|
||||
<property name="active">1</property>
|
||||
<child>
|
||||
<object class="GtkDragSource">
|
||||
<signal name="prepare" handler="drag_prepare"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<accessibility>
|
||||
<property name="label">Portland Rose Photo</property>
|
||||
</accessibility>
|
||||
<style>
|
||||
<class name="large-icons"/>
|
||||
</style>
|
||||
@@ -120,9 +105,6 @@
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="image_floppy">
|
||||
<accessibility>
|
||||
<property name="label">Icon Drag Source</property>
|
||||
</accessibility>
|
||||
<property name="group">image_rose</property>
|
||||
<child>
|
||||
<object class="GtkDragSource">
|
||||
@@ -131,9 +113,6 @@
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<accessibility>
|
||||
<property name="label">Floppy Buddy Icon</property>
|
||||
</accessibility>
|
||||
<style>
|
||||
<class name="large-icons"/>
|
||||
</style>
|
||||
@@ -144,9 +123,6 @@
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="image_logo">
|
||||
<accessibility>
|
||||
<property name="label">SVG Drag Source</property>
|
||||
</accessibility>
|
||||
<property name="group">image_floppy</property>
|
||||
<child>
|
||||
<object class="GtkDragSource">
|
||||
@@ -155,9 +131,6 @@
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<accessibility>
|
||||
<property name="label">gtk-demo logo</property>
|
||||
</accessibility>
|
||||
<style>
|
||||
<class name="large-icons"/>
|
||||
</style>
|
||||
@@ -175,9 +148,6 @@
|
||||
<property name="name">File</property>
|
||||
<property name="child">
|
||||
<object class="GtkButton" id="source_file">
|
||||
<accessibility>
|
||||
<property name="label">File Drag Source</property>
|
||||
</accessibility>
|
||||
<child>
|
||||
<object class="GtkDragSource">
|
||||
<property name="propagation-phase">capture</property>
|
||||
@@ -202,9 +172,6 @@
|
||||
<property name="name">Folder</property>
|
||||
<property name="child">
|
||||
<object class="GtkButton" id="source_folder">
|
||||
<accessibility>
|
||||
<property name="label">Folder Drag Source</property>
|
||||
</accessibility>
|
||||
<child>
|
||||
<object class="GtkDragSource">
|
||||
<property name="propagation-phase">capture</property>
|
||||
@@ -258,7 +225,7 @@
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="paste_label">
|
||||
<object class="GtkLabel">
|
||||
<property name="xalign">0</property>
|
||||
<binding name="label">
|
||||
<lookup name="visible-child-name" type="GtkStack">
|
||||
@@ -285,9 +252,6 @@
|
||||
<property name="name">Text</property>
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<accessibility>
|
||||
<relation name="labelled-by">paste_label</relation>
|
||||
</accessibility>
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="xalign">0</property>
|
||||
@@ -301,9 +265,6 @@
|
||||
<property name="name">Image</property>
|
||||
<property name="child">
|
||||
<object class="GtkImage">
|
||||
<accessibility>
|
||||
<relation name="labelled-by">paste_label</relation>
|
||||
</accessibility>
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<style>
|
||||
@@ -322,9 +283,6 @@
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkColorSwatch">
|
||||
<accessibility>
|
||||
<relation name="labelled-by">paste_label</relation>
|
||||
</accessibility>
|
||||
<property name="accessible-role">img</property>
|
||||
<property name="can-focus">0</property>
|
||||
<property name="selectable">0</property>
|
||||
@@ -340,9 +298,6 @@
|
||||
<property name="name">File</property>
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<accessibility>
|
||||
<relation name="labelled-by">paste_label</relation>
|
||||
</accessibility>
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="xalign">0</property>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CURVE_TYPE_EDITOR (curve_editor_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (CurveEditor, curve_editor, CURVE, EDITOR, GtkWidget)
|
||||
|
||||
GtkWidget * curve_editor_new (void);
|
||||
|
||||
void curve_editor_set_edit (CurveEditor *self,
|
||||
gboolean edit);
|
||||
|
||||
void curve_editor_set_path (CurveEditor *self,
|
||||
GskPath *path);
|
||||
|
||||
GskPath * curve_editor_get_path (CurveEditor *self);
|
||||
|
||||
void curve_editor_set_stroke (CurveEditor *self,
|
||||
GskStroke *stroke);
|
||||
|
||||
const GskStroke * curve_editor_get_stroke (CurveEditor *self);
|
||||
|
||||
|
||||
void curve_editor_set_color (CurveEditor *self,
|
||||
const GdkRGBA *color);
|
||||
|
||||
const GdkRGBA * curve_editor_get_color (CurveEditor *self);
|
||||
|
||||
gboolean curve_editor_get_show_outline (CurveEditor *self);
|
||||
|
||||
void curve_editor_set_show_outline (CurveEditor *self,
|
||||
gboolean show_outline);
|
||||
|
||||
G_END_DECLS
|
||||
@@ -1,271 +0,0 @@
|
||||
/* Path/Curve Editor
|
||||
*
|
||||
* This demo shows an elaborate curve editor that you would expect to find
|
||||
* in a vector graphics editor. It is built on top of GTK's path APIs.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "curve-editor.h"
|
||||
|
||||
|
||||
static GskPath *
|
||||
make_circle_path (void)
|
||||
{
|
||||
float w = 310;
|
||||
float h = 310;
|
||||
float cx = w / 2;
|
||||
float cy = h / 2;
|
||||
float pad = 20;
|
||||
float r = (w - 2 * pad) / 2;
|
||||
float k = 0.55228;
|
||||
float kr = k * r;
|
||||
GskPathBuilder *builder;
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
|
||||
gsk_path_builder_move_to (builder, cx, pad);
|
||||
gsk_path_builder_cubic_to (builder, cx + kr, pad,
|
||||
w - pad, cy - kr,
|
||||
w - pad, cy);
|
||||
gsk_path_builder_cubic_to (builder, w - pad, cy + kr,
|
||||
cx + kr, h - pad,
|
||||
cx, h - pad);
|
||||
gsk_path_builder_cubic_to (builder, cx - kr, h - pad,
|
||||
pad, cy + kr,
|
||||
pad, cy);
|
||||
#if 0
|
||||
gsk_path_builder_cubic_to (builder, pad, cy - kr,
|
||||
cx - kr, pad,
|
||||
cx, pad);
|
||||
gsk_path_builder_close (builder);
|
||||
#endif
|
||||
|
||||
return gsk_path_builder_free_to_path (builder);
|
||||
}
|
||||
|
||||
static void
|
||||
edit_changed (GtkToggleButton *button,
|
||||
GParamSpec *pspec,
|
||||
CurveEditor *editor)
|
||||
{
|
||||
curve_editor_set_edit (editor, gtk_toggle_button_get_active (button));
|
||||
}
|
||||
|
||||
static void
|
||||
reset (GtkButton *button,
|
||||
CurveEditor *editor)
|
||||
{
|
||||
GskPath *path;
|
||||
|
||||
path = make_circle_path ();
|
||||
curve_editor_set_path (editor, path);
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
|
||||
static void
|
||||
line_width_changed (GtkSpinButton *spin,
|
||||
CurveEditor *editor)
|
||||
{
|
||||
GskStroke *stroke;
|
||||
|
||||
stroke = gsk_stroke_copy (curve_editor_get_stroke (editor));
|
||||
gsk_stroke_set_line_width (stroke, gtk_spin_button_get_value (spin));
|
||||
curve_editor_set_stroke (editor, stroke);
|
||||
gsk_stroke_free (stroke);
|
||||
}
|
||||
|
||||
static void
|
||||
cap_changed (GtkDropDown *combo,
|
||||
GParamSpec *pspec,
|
||||
CurveEditor *editor)
|
||||
{
|
||||
GskStroke *stroke;
|
||||
|
||||
stroke = gsk_stroke_copy (curve_editor_get_stroke (editor));
|
||||
gsk_stroke_set_line_cap (stroke, (GskLineCap)gtk_drop_down_get_selected (combo));
|
||||
curve_editor_set_stroke (editor, stroke);
|
||||
gsk_stroke_free (stroke);
|
||||
}
|
||||
|
||||
static void
|
||||
join_changed (GtkDropDown *combo,
|
||||
GParamSpec *pspec,
|
||||
CurveEditor *editor)
|
||||
{
|
||||
GskStroke *stroke;
|
||||
|
||||
stroke = gsk_stroke_copy (curve_editor_get_stroke (editor));
|
||||
gsk_stroke_set_line_join (stroke, (GskLineJoin)gtk_drop_down_get_selected (combo));
|
||||
curve_editor_set_stroke (editor, stroke);
|
||||
gsk_stroke_free (stroke);
|
||||
}
|
||||
|
||||
static void
|
||||
color_changed (GtkColorDialogButton *button,
|
||||
GParamSpec *pspec,
|
||||
CurveEditor *editor)
|
||||
{
|
||||
curve_editor_set_color (editor, gtk_color_dialog_button_get_rgba (button));
|
||||
}
|
||||
|
||||
static void
|
||||
stroke_toggled (GtkCheckButton *button,
|
||||
CurveEditor *editor)
|
||||
{
|
||||
curve_editor_set_show_outline (editor, gtk_check_button_get_active (button));
|
||||
gtk_widget_queue_draw (GTK_WIDGET (editor));
|
||||
}
|
||||
|
||||
static void
|
||||
limit_changed (GtkSpinButton *spin,
|
||||
CurveEditor *editor)
|
||||
{
|
||||
GskStroke *stroke;
|
||||
|
||||
stroke = gsk_stroke_copy (curve_editor_get_stroke (editor));
|
||||
gsk_stroke_set_miter_limit (stroke, gtk_spin_button_get_value (spin));
|
||||
curve_editor_set_stroke (editor, stroke);
|
||||
gsk_stroke_free (stroke);
|
||||
}
|
||||
|
||||
static void
|
||||
dashes_changed (GtkEntry *entry,
|
||||
GParamSpec *spec,
|
||||
CurveEditor *editor)
|
||||
{
|
||||
const char *text;
|
||||
char **split;
|
||||
GArray *dash;
|
||||
GskStroke *stroke;
|
||||
|
||||
text = gtk_editable_get_text (GTK_EDITABLE (entry));
|
||||
split = g_strsplit (text, " ", 0);
|
||||
|
||||
dash = g_array_new (FALSE, FALSE, sizeof (float));
|
||||
for (int i = 0; split[i] != NULL; i++)
|
||||
{
|
||||
double d;
|
||||
char *endp = 0;
|
||||
|
||||
d = g_strtod (split[i], &endp);
|
||||
if (*endp == '\0')
|
||||
g_array_append_vals (dash, (float[1]) { d }, 1);
|
||||
}
|
||||
|
||||
g_strfreev (split);
|
||||
|
||||
stroke = gsk_stroke_copy (curve_editor_get_stroke (editor));
|
||||
gsk_stroke_set_dash (stroke, (const float *)dash->data, dash->len);
|
||||
curve_editor_set_stroke (editor, stroke);
|
||||
gsk_stroke_free (stroke);
|
||||
|
||||
g_array_free (dash, TRUE);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_curve (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window = NULL;
|
||||
GtkWidget *demo;
|
||||
GtkWidget *edit_toggle;
|
||||
GtkWidget *reset_button;
|
||||
GtkWidget *titlebar;
|
||||
GtkWidget *stroke_toggle;
|
||||
GtkWidget *line_width_spin;
|
||||
GtkWidget *stroke_button;
|
||||
GtkWidget *popover;
|
||||
GtkWidget *grid;
|
||||
GtkWidget *cap_combo;
|
||||
GtkWidget *join_combo;
|
||||
GtkWidget *color_button;
|
||||
GtkWidget *limit_spin;
|
||||
GtkWidget *dash_entry;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Curve Editor");
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 315, 350);
|
||||
|
||||
edit_toggle = gtk_toggle_button_new ();
|
||||
gtk_button_set_icon_name (GTK_BUTTON (edit_toggle), "document-edit-symbolic");
|
||||
|
||||
reset_button = gtk_button_new_from_icon_name ("edit-undo-symbolic");
|
||||
|
||||
stroke_button = gtk_menu_button_new ();
|
||||
gtk_menu_button_set_icon_name (GTK_MENU_BUTTON (stroke_button), "open-menu-symbolic");
|
||||
popover = gtk_popover_new ();
|
||||
gtk_menu_button_set_popover (GTK_MENU_BUTTON (stroke_button), popover);
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
|
||||
gtk_popover_set_child (GTK_POPOVER (popover), grid);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Color:"), 0, 0, 1, 1);
|
||||
color_button = gtk_color_dialog_button_new (gtk_color_dialog_new ());
|
||||
gtk_grid_attach (GTK_GRID (grid), color_button, 1, 0, 1, 1);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Line width:"), 0, 1, 1, 1);
|
||||
line_width_spin = gtk_spin_button_new_with_range (1, 20, 1);
|
||||
gtk_spin_button_set_value (GTK_SPIN_BUTTON (line_width_spin), 1);
|
||||
gtk_grid_attach (GTK_GRID (grid), line_width_spin, 1, 1, 1, 1);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Line cap:"), 0, 2, 1, 1);
|
||||
cap_combo = gtk_drop_down_new_from_strings ((const char *[]){"Butt", "Round", "Square", NULL});
|
||||
gtk_grid_attach (GTK_GRID (grid), cap_combo, 1, 2, 1, 1);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Line join:"), 0, 3, 1, 1);
|
||||
join_combo = gtk_drop_down_new_from_strings ((const char *[]){"Miter", "Miter-clip", "Round", "Bevel", "Arcs", NULL});
|
||||
gtk_grid_attach (GTK_GRID (grid), join_combo, 1, 3, 1, 1);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Miter limit:"), 0, 4, 1, 1);
|
||||
limit_spin = gtk_spin_button_new_with_range (0, 10, 1);
|
||||
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (limit_spin), 1);
|
||||
gtk_spin_button_set_value (GTK_SPIN_BUTTON (limit_spin), 4);
|
||||
gtk_grid_attach (GTK_GRID (grid), limit_spin, 1, 4, 1, 1);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Dashes:"), 0, 5, 1, 1);
|
||||
dash_entry = gtk_entry_new ();
|
||||
gtk_grid_attach (GTK_GRID (grid), dash_entry, 1, 5, 1, 1);
|
||||
|
||||
stroke_toggle = gtk_check_button_new_with_label ("Show outline");
|
||||
gtk_grid_attach (GTK_GRID (grid), stroke_toggle, 1, 6, 1, 1);
|
||||
|
||||
titlebar = gtk_header_bar_new ();
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (titlebar), edit_toggle);
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (titlebar), reset_button);
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (titlebar), stroke_button);
|
||||
|
||||
gtk_window_set_titlebar (GTK_WINDOW (window), titlebar);
|
||||
|
||||
demo = curve_editor_new ();
|
||||
|
||||
g_signal_connect (stroke_toggle, "toggled", G_CALLBACK (stroke_toggled), demo);
|
||||
g_signal_connect (edit_toggle, "notify::active", G_CALLBACK (edit_changed), demo);
|
||||
g_signal_connect (reset_button, "clicked", G_CALLBACK (reset), demo);
|
||||
g_signal_connect (cap_combo, "notify::selected", G_CALLBACK (cap_changed), demo);
|
||||
g_signal_connect (join_combo, "notify::selected", G_CALLBACK (join_changed), demo);
|
||||
g_signal_connect (color_button, "notify::rgba", G_CALLBACK (color_changed), demo);
|
||||
g_signal_connect (line_width_spin, "value-changed", G_CALLBACK (line_width_changed), demo);
|
||||
g_signal_connect (limit_spin, "value-changed", G_CALLBACK (limit_changed), demo);
|
||||
g_signal_connect (dash_entry, "notify::text", G_CALLBACK (dashes_changed), demo);
|
||||
|
||||
reset (NULL, CURVE_EDITOR (demo));
|
||||
|
||||
gtk_spin_button_set_value (GTK_SPIN_BUTTON (line_width_spin), 6);
|
||||
gtk_color_dialog_button_set_rgba (GTK_COLOR_DIALOG_BUTTON (color_button), &(GdkRGBA) { 1, 0, 0, 1 });
|
||||
gtk_drop_down_set_selected (GTK_DROP_DOWN (cap_combo), GSK_LINE_CAP_ROUND);
|
||||
gtk_editable_set_text (GTK_EDITABLE (dash_entry), "0 8");
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), demo);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -127,7 +127,6 @@
|
||||
<file>fishbowl.ui</file>
|
||||
<file>gtkfishbowl.c</file>
|
||||
<file>gtkfishbowl.h</file>
|
||||
<file>tiger.node</file>
|
||||
</gresource>
|
||||
<gresource prefix="/frames">
|
||||
<file>frames.ui</file>
|
||||
@@ -259,10 +258,6 @@
|
||||
<gresource prefix="/video-player">
|
||||
<file>bbb.png</file>
|
||||
</gresource>
|
||||
<gresource prefix="/curve">
|
||||
<file>curve-editor.c</file>
|
||||
<file>curve-editor.h</file>
|
||||
</gresource>
|
||||
<gresource prefix="/sources">
|
||||
<file>application_demo.c</file>
|
||||
<file>assistant.c</file>
|
||||
@@ -280,7 +275,6 @@
|
||||
<file>css_pixbufs.c</file>
|
||||
<file>css_shadows.c</file>
|
||||
<file>cursors.c</file>
|
||||
<file>curve.c</file>
|
||||
<file>dialog.c</file>
|
||||
<file>drawingarea.c</file>
|
||||
<file>dnd.c</file>
|
||||
@@ -300,7 +294,6 @@
|
||||
<file>gears.c</file>
|
||||
<file>gestures.c</file>
|
||||
<file>glarea.c</file>
|
||||
<file>glyphs.c</file>
|
||||
<file>gltransition.c</file>
|
||||
<file>headerbar.c</file>
|
||||
<file>hypertext.c</file>
|
||||
@@ -342,9 +335,6 @@
|
||||
<file>paintable_symbolic.c</file>
|
||||
<file>panes.c</file>
|
||||
<file>password_entry.c</file>
|
||||
<file>path_fill.c</file>
|
||||
<file>path_maze.c</file>
|
||||
<file>path_text.c</file>
|
||||
<file>peg_solitaire.c</file>
|
||||
<file>pickers.c</file>
|
||||
<file>printing.c</file>
|
||||
@@ -430,9 +420,6 @@
|
||||
<gresource prefix="/fontrendering">
|
||||
<file>fontrendering.ui</file>
|
||||
</gresource>
|
||||
<gresource prefix="/path_text">
|
||||
<file>path_text.ui</file>
|
||||
</gresource>
|
||||
<gresource prefix="/org/gtk/Demo4">
|
||||
<file>icons/16x16/actions/application-exit.png</file>
|
||||
<file>icons/16x16/actions/document-new.png</file>
|
||||
|
||||
@@ -387,8 +387,6 @@ demo3_widget_class_init (Demo3WidgetClass *class)
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/menu/demo3widget.ui");
|
||||
gtk_widget_class_bind_template_child (widget_class, Demo3Widget, menu);
|
||||
gtk_widget_class_bind_template_callback (widget_class, pressed_cb);
|
||||
|
||||
gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_IMG);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
|
||||
@@ -19,14 +19,8 @@
|
||||
</item>
|
||||
</menu>
|
||||
<template class="Demo3Widget">
|
||||
<accessibility>
|
||||
<property name="label">Demo image</property>
|
||||
</accessibility>
|
||||
<child>
|
||||
<object class="GtkPopoverMenu" id="menu">
|
||||
<accessibility>
|
||||
<property name="label">Context menu</property>
|
||||
</accessibility>
|
||||
<property name="has-arrow">0</property>
|
||||
<property name="menu-model">model</property>
|
||||
</object>
|
||||
|
||||
@@ -334,17 +334,11 @@ do_drawingarea (GtkWidget *do_widget)
|
||||
gtk_widget_set_vexpand (frame, TRUE);
|
||||
gtk_box_append (GTK_BOX (vbox), frame);
|
||||
|
||||
da = g_object_new (GTK_TYPE_DRAWING_AREA,
|
||||
"accessible-role", GTK_ACCESSIBLE_ROLE_IMG,
|
||||
NULL);
|
||||
gtk_frame_set_child (GTK_FRAME (frame), da);
|
||||
gtk_accessible_update_relation (GTK_ACCESSIBLE (da),
|
||||
GTK_ACCESSIBLE_RELATION_LABELLED_BY, label, NULL,
|
||||
-1);
|
||||
|
||||
da = gtk_drawing_area_new ();
|
||||
gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (da), 100);
|
||||
gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (da), 100);
|
||||
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), groups_draw, NULL, NULL);
|
||||
gtk_frame_set_child (GTK_FRAME (frame), da);
|
||||
|
||||
/*
|
||||
* Create the scribble area
|
||||
@@ -358,17 +352,11 @@ do_drawingarea (GtkWidget *do_widget)
|
||||
gtk_widget_set_vexpand (frame, TRUE);
|
||||
gtk_box_append (GTK_BOX (vbox), frame);
|
||||
|
||||
da = g_object_new (GTK_TYPE_DRAWING_AREA,
|
||||
"accessible-role", GTK_ACCESSIBLE_ROLE_IMG,
|
||||
NULL);
|
||||
gtk_frame_set_child (GTK_FRAME (frame), da);
|
||||
gtk_accessible_update_relation (GTK_ACCESSIBLE (da),
|
||||
GTK_ACCESSIBLE_RELATION_LABELLED_BY, label, NULL,
|
||||
-1);
|
||||
|
||||
da = gtk_drawing_area_new ();
|
||||
gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (da), 100);
|
||||
gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (da), 100);
|
||||
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), scribble_draw, NULL, NULL);
|
||||
gtk_frame_set_child (GTK_FRAME (frame), da);
|
||||
|
||||
g_signal_connect (da, "resize",
|
||||
G_CALLBACK (scribble_resize), NULL);
|
||||
@@ -384,7 +372,7 @@ do_drawingarea (GtkWidget *do_widget)
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
gtk_widget_set_visible (window, TRUE);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
|
||||
@@ -95,13 +95,6 @@ do_entry_completion (GtkWidget *do_widget)
|
||||
entry = gtk_entry_new ();
|
||||
gtk_box_append (GTK_BOX (vbox), entry);
|
||||
|
||||
gtk_accessible_update_relation (GTK_ACCESSIBLE (entry),
|
||||
GTK_ACCESSIBLE_RELATION_LABELLED_BY, label, NULL,
|
||||
-1);
|
||||
gtk_accessible_update_property (GTK_ACCESSIBLE (entry),
|
||||
GTK_ACCESSIBLE_PROPERTY_AUTOCOMPLETE, GTK_ACCESSIBLE_AUTOCOMPLETE_LIST,
|
||||
-1);
|
||||
|
||||
/* Create the completion object */
|
||||
completion = gtk_entry_completion_new ();
|
||||
|
||||
|
||||
@@ -43,10 +43,6 @@ do_entry_undo (GtkWidget *do_widget)
|
||||
entry = gtk_entry_new ();
|
||||
gtk_editable_set_enable_undo (GTK_EDITABLE (entry), TRUE);
|
||||
gtk_box_append (GTK_BOX (vbox), entry);
|
||||
|
||||
gtk_accessible_update_relation (GTK_ACCESSIBLE (entry),
|
||||
GTK_ACCESSIBLE_RELATION_LABELLED_BY, label, NULL,
|
||||
-1);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
|
||||
@@ -22,15 +22,11 @@ validate_more_details (GtkEntry *entry,
|
||||
{
|
||||
gtk_widget_set_tooltip_text (GTK_WIDGET (entry), "Must have details first");
|
||||
gtk_widget_add_css_class (GTK_WIDGET (entry), "error");
|
||||
gtk_accessible_update_state (GTK_ACCESSIBLE (entry),
|
||||
GTK_ACCESSIBLE_STATE_INVALID, GTK_ACCESSIBLE_INVALID_TRUE,
|
||||
-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_set_tooltip_text (GTK_WIDGET (entry), "");
|
||||
gtk_widget_remove_css_class (GTK_WIDGET (entry), "error");
|
||||
gtk_accessible_reset_state (GTK_ACCESSIBLE (entry), GTK_ACCESSIBLE_STATE_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,18 +44,10 @@ mode_switch_state_set (GtkSwitch *sw,
|
||||
{
|
||||
gtk_widget_set_visible (label, FALSE);
|
||||
gtk_switch_set_state (sw, state);
|
||||
gtk_accessible_reset_relation (GTK_ACCESSIBLE (sw), GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE);
|
||||
gtk_accessible_reset_state (GTK_ACCESSIBLE (sw), GTK_ACCESSIBLE_STATE_INVALID);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_set_visible (label, TRUE);
|
||||
gtk_accessible_update_relation (GTK_ACCESSIBLE (sw),
|
||||
GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE, label,
|
||||
-1);
|
||||
gtk_accessible_update_state (GTK_ACCESSIBLE (sw),
|
||||
GTK_ACCESSIBLE_STATE_INVALID, GTK_ACCESSIBLE_INVALID_TRUE,
|
||||
-1);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@@ -85,9 +73,6 @@ level_scale_value_changed (GtkRange *range,
|
||||
{
|
||||
gtk_switch_set_state (GTK_SWITCH (sw), FALSE);
|
||||
}
|
||||
|
||||
gtk_accessible_reset_relation (GTK_ACCESSIBLE (sw), GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE);
|
||||
gtk_accessible_reset_state (GTK_ACCESSIBLE (sw), GTK_ACCESSIBLE_STATE_INVALID);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
|
||||
@@ -11,9 +11,6 @@
|
||||
#include "gtkgears.h"
|
||||
#include "gskshaderpaintable.h"
|
||||
|
||||
#include "nodewidget.h"
|
||||
#include "graphwidget.h"
|
||||
|
||||
const char *const css =
|
||||
".blurred-button {"
|
||||
" box-shadow: 0px 0px 5px 10px rgba(0, 0, 0, 0.5);"
|
||||
@@ -206,18 +203,6 @@ create_menu_button (void)
|
||||
return w;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_tiger (void)
|
||||
{
|
||||
return node_widget_new ("/fishbowl/tiger.node");
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_graph (void)
|
||||
{
|
||||
return graph_widget_new ();
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
GtkWidget * (*create_func) (void);
|
||||
@@ -235,8 +220,6 @@ static const struct {
|
||||
{ "Switch", create_switch },
|
||||
{ "Menubutton", create_menu_button },
|
||||
{ "Shader", create_cogs },
|
||||
{ "Tiger", create_tiger },
|
||||
{ "Graph", create_graph },
|
||||
};
|
||||
|
||||
static int selected_widget_type = -1;
|
||||
|
||||
@@ -59,9 +59,6 @@
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkFontDialogButton" id="font">
|
||||
<accessibility>
|
||||
<property name="label">Font</property>
|
||||
</accessibility>
|
||||
<property name="dialog">
|
||||
<object class="GtkFontDialog">
|
||||
</object>
|
||||
@@ -76,7 +73,7 @@
|
||||
<property name="column-spacing">10</property>
|
||||
<property name="row-spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="size_label">
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Size</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="valign">baseline</property>
|
||||
@@ -92,9 +89,6 @@
|
||||
<property name="width-request">100</property>
|
||||
<property name="valign">baseline</property>
|
||||
<property name="adjustment">size_adjustment</property>
|
||||
<accessibility>
|
||||
<relation name="labelled-by">size_label</relation>
|
||||
</accessibility>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">0</property>
|
||||
@@ -107,9 +101,6 @@
|
||||
<property name="max-width-chars">4</property>
|
||||
<property name="hexpand">0</property>
|
||||
<property name="valign">baseline</property>
|
||||
<accessibility>
|
||||
<relation name="labelled-by">size_label</relation>
|
||||
</accessibility>
|
||||
<signal name="activate" handler="basic_entry_activated"
|
||||
object="size_adjustment" swapped="false"/>
|
||||
<layout>
|
||||
@@ -119,7 +110,7 @@
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="letterspacing_label">
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Letterspacing</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="valign">baseline</property>
|
||||
@@ -135,9 +126,6 @@
|
||||
<property name="width-request">100</property>
|
||||
<property name="valign">baseline</property>
|
||||
<property name="adjustment">letterspacing_adjustment</property>
|
||||
<accessibility>
|
||||
<relation name="labelled-by">letterspacing_label</relation>
|
||||
</accessibility>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">1</property>
|
||||
@@ -150,9 +138,6 @@
|
||||
<property name="max-width-chars">4</property>
|
||||
<property name="hexpand">0</property>
|
||||
<property name="valign">baseline</property>
|
||||
<accessibility>
|
||||
<relation name="labelled-by">letterspacing_label</relation>
|
||||
</accessibility>
|
||||
<signal name="activate" handler="basic_entry_activated"
|
||||
object="letterspacing_adjustment" swapped="false"/>
|
||||
<layout>
|
||||
@@ -162,7 +147,7 @@
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="line_height_label">
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Line Height</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="valign">baseline</property>
|
||||
@@ -178,9 +163,6 @@
|
||||
<property name="width-request">100</property>
|
||||
<property name="valign">baseline</property>
|
||||
<property name="adjustment">line_height_adjustment</property>
|
||||
<accessibility>
|
||||
<relation name="labelled-by">line_height_label</relation>
|
||||
</accessibility>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">2</property>
|
||||
@@ -193,9 +175,6 @@
|
||||
<property name="max-width-chars">4</property>
|
||||
<property name="hexpand">0</property>
|
||||
<property name="valign">baseline</property>
|
||||
<accessibility>
|
||||
<relation name="labelled-by">line_height_label</relation>
|
||||
</accessibility>
|
||||
<signal name="activate" handler="basic_entry_activated"
|
||||
object="line_height_adjustment" swapped="false"/>
|
||||
<layout>
|
||||
@@ -205,7 +184,7 @@
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="foreground_label">
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Foreground</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="valign">baseline</property>
|
||||
@@ -223,9 +202,6 @@
|
||||
</property>
|
||||
<property name="valign">baseline</property>
|
||||
<property name="rgba">black</property>
|
||||
<accessibility>
|
||||
<relation name="labelled-by">foreground_label</relation>
|
||||
</accessibility>
|
||||
<signal name="notify::rgba" handler="color_set_cb"/>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
@@ -234,7 +210,7 @@
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="background_label">
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Background</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="valign">baseline</property>
|
||||
@@ -252,9 +228,6 @@
|
||||
</property>
|
||||
<property name="valign">baseline</property>
|
||||
<property name="rgba">white</property>
|
||||
<accessibility>
|
||||
<relation name="labelled-by">background_label</relation>
|
||||
</accessibility>
|
||||
<signal name="notify::rgba" handler="color_set_cb"/>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
@@ -267,9 +240,6 @@
|
||||
<property name="icon-name">object-flip-vertical-symbolic</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">center</property>
|
||||
<accessibility>
|
||||
<property name="label">Swap colors</property>
|
||||
</accessibility>
|
||||
<style>
|
||||
<class name="circular"/>
|
||||
</style>
|
||||
@@ -371,9 +341,6 @@
|
||||
<property name="yalign">0</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="selectable">1</property>
|
||||
<accessibility>
|
||||
<property name="label">Font example</property>
|
||||
</accessibility>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
@@ -383,9 +350,6 @@
|
||||
<property name="name">entry</property>
|
||||
<property name="child">
|
||||
<object class="GtkTextView" id="entry">
|
||||
<accessibility>
|
||||
<property name="label">Example text</property>
|
||||
</accessibility>
|
||||
<property name="buffer">
|
||||
<object class="GtkTextBuffer">
|
||||
<property name="text">Grumpy wizards make toxic brew for the evil Queen and Jack. A quick movement of the enemy will jeopardize six gunboats. The job of waxing linoleum frequently peeves chintzy kids. My girl wove six dozen plaid jackets before she quit. Twelve ziggurats quickly jumped a finch box.
|
||||
@@ -482,9 +446,6 @@
|
||||
<property name="icon-name">document-edit-symbolic</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">end</property>
|
||||
<accessibility>
|
||||
<property name="label">Edit text</property>
|
||||
</accessibility>
|
||||
<signal name="clicked" handler="font_features_toggle_edit"/>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
@@ -306,7 +306,7 @@ retry:
|
||||
texture = gdk_texture_new_for_pixbuf (pixbuf2);
|
||||
gtk_picture_set_paintable (GTK_PICTURE (image), GDK_PAINTABLE (texture));
|
||||
g_object_unref (pixbuf2);
|
||||
g_object_unref (texture);
|
||||
g_object_unref (pixbuf2);
|
||||
}
|
||||
|
||||
static gboolean fading = FALSE;
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<property name="row-spacing">10</property>
|
||||
<property name="column-spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="text_label">
|
||||
<object class="GtkLabel">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="label">Text</property>
|
||||
<property name="xalign">1</property>
|
||||
@@ -57,13 +57,10 @@
|
||||
<layout>
|
||||
<property name="column">2</property>
|
||||
</layout>
|
||||
<accessibility>
|
||||
<relation name="labelled-by">text_label</relation>
|
||||
</accessibility>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="font_label">
|
||||
<object class="GtkLabel">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="label">Font</property>
|
||||
<property name="xalign">1</property>
|
||||
@@ -78,9 +75,6 @@
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFontDialogButton" id="font_button">
|
||||
<accessibility>
|
||||
<relation name="labelled-by">font_label</relation>
|
||||
</accessibility>
|
||||
<property name="dialog">
|
||||
<object class="GtkFontDialog">
|
||||
</object>
|
||||
@@ -192,9 +186,6 @@
|
||||
<property name="icon-name">list-add-symbolic</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<accessibility>
|
||||
<property name="label">Zoom in</property>
|
||||
</accessibility>
|
||||
<style>
|
||||
<class name="circular"/>
|
||||
</style>
|
||||
@@ -220,9 +211,6 @@
|
||||
<property name="icon-name">list-remove-symbolic</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<accessibility>
|
||||
<property name="label">Zoom out</property>
|
||||
</accessibility>
|
||||
<style>
|
||||
<class name="circular"/>
|
||||
</style>
|
||||
@@ -263,9 +251,6 @@
|
||||
<property name="vexpand">1</property>
|
||||
<child>
|
||||
<object class="GtkPicture" id="image">
|
||||
<accessibility>
|
||||
<property name="label">Font rendering example</property>
|
||||
</accessibility>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="can-shrink">0</property>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,164 +0,0 @@
|
||||
#include "graphwidget.h"
|
||||
|
||||
struct _GraphWidget
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GskPath *path;
|
||||
GskStroke *stroke;
|
||||
GdkRGBA color;
|
||||
GskPath *stroke_path;
|
||||
|
||||
guint tick_cb;
|
||||
guint64 start_time;
|
||||
|
||||
double period;
|
||||
double amplitude;
|
||||
};
|
||||
|
||||
struct _GraphWidgetClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GraphWidget, graph_widget, GTK_TYPE_WIDGET)
|
||||
|
||||
static void
|
||||
update_path (GraphWidget *self,
|
||||
float amplitude)
|
||||
{
|
||||
graphene_point_t p[20];
|
||||
GskPathBuilder *builder;
|
||||
|
||||
g_clear_pointer (&self->path, gsk_path_unref);
|
||||
g_clear_pointer (&self->stroke_path, gsk_path_unref);
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
p[i].x = 10 * i;
|
||||
p[i].y = 50;
|
||||
|
||||
if (i % 4 == 1 || i % 4 == 2)
|
||||
{
|
||||
if (i % 8 < 4)
|
||||
p[i].y += amplitude;
|
||||
else
|
||||
p[i].y -= amplitude;
|
||||
}
|
||||
}
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_builder_move_to (builder, p[0].x, p[0].y);
|
||||
|
||||
for (int i = 0; i < 20; i += 4)
|
||||
gsk_path_builder_cubic_to (builder,
|
||||
p[i+1].x, p[i+1].y,
|
||||
p[i+2].x, p[i+2].y,
|
||||
p[i+3].x, p[i+3].y);
|
||||
|
||||
self->path = gsk_path_builder_free_to_path (builder);
|
||||
self->stroke_path = gsk_path_stroke (self->path, self->stroke);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
tick_cb (GtkWidget *widget,
|
||||
GdkFrameClock *frame_clock,
|
||||
gpointer user_data)
|
||||
{
|
||||
GraphWidget *self = GRAPH_WIDGET (widget);
|
||||
guint64 now;
|
||||
double angle;
|
||||
|
||||
now = gdk_frame_clock_get_frame_time (frame_clock);
|
||||
|
||||
if (self->start_time == 0)
|
||||
self->start_time = now;
|
||||
|
||||
angle = 360 * (now - self->start_time) / (double)(self->period * G_TIME_SPAN_MINUTE);
|
||||
update_path (self, sin (angle) * self->amplitude);
|
||||
|
||||
gtk_widget_queue_draw (widget);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
graph_widget_init (GraphWidget *self)
|
||||
{
|
||||
self->color.red = g_random_double_range (0, 1);
|
||||
self->color.green = g_random_double_range (0, 1);
|
||||
self->color.blue = g_random_double_range (0, 1);
|
||||
self->color.alpha = 1;
|
||||
|
||||
self->period = g_random_double_range (0.5, 1);
|
||||
self->amplitude = g_random_double_range (10, 25);
|
||||
|
||||
self->stroke = gsk_stroke_new (2);
|
||||
|
||||
update_path (self, 0);
|
||||
|
||||
self->start_time = 0;
|
||||
self->tick_cb = gtk_widget_add_tick_callback (GTK_WIDGET (self), tick_cb, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
graph_widget_dispose (GObject *object)
|
||||
{
|
||||
GraphWidget *self = GRAPH_WIDGET (object);
|
||||
|
||||
gsk_path_unref (self->path);
|
||||
gsk_stroke_free (self->stroke);
|
||||
|
||||
G_OBJECT_CLASS (graph_widget_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
graph_widget_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
GraphWidget *self = GRAPH_WIDGET (widget);
|
||||
int width, height;
|
||||
|
||||
width = gtk_widget_get_width (widget);
|
||||
height = gtk_widget_get_height (widget);
|
||||
|
||||
gtk_snapshot_push_fill (snapshot, self->stroke_path, GSK_FILL_RULE_WINDING);
|
||||
gtk_snapshot_append_color (snapshot,
|
||||
&self->color,
|
||||
&GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gtk_snapshot_pop (snapshot);
|
||||
}
|
||||
|
||||
static void
|
||||
graph_widget_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
*minimum = *natural = 200;
|
||||
else
|
||||
*minimum = *natural = 100;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
graph_widget_class_init (GraphWidgetClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
object_class->dispose = graph_widget_dispose;
|
||||
|
||||
widget_class->snapshot = graph_widget_snapshot;
|
||||
widget_class->measure = graph_widget_measure;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
graph_widget_new (void)
|
||||
{
|
||||
return g_object_new (GRAPH_TYPE_WIDGET, NULL);
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define GRAPH_TYPE_WIDGET (graph_widget_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GraphWidget, graph_widget, GRAPH, WIDGET, GtkWidget)
|
||||
|
||||
GtkWidget * graph_widget_new (void);
|
||||
@@ -18,7 +18,6 @@ do_headerbar (GtkWidget *do_widget)
|
||||
GtkWidget *header;
|
||||
GtkWidget *button;
|
||||
GtkWidget *box;
|
||||
GtkWidget *content;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
@@ -38,26 +37,16 @@ do_headerbar (GtkWidget *do_widget)
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_widget_add_css_class (box, "linked");
|
||||
button = gtk_button_new_from_icon_name ("go-previous-symbolic");
|
||||
gtk_widget_set_tooltip_text (button, "Back");
|
||||
gtk_box_append (GTK_BOX (box), button);
|
||||
button = gtk_button_new_from_icon_name ("go-next-symbolic");
|
||||
gtk_widget_set_tooltip_text (button, "Forward");
|
||||
gtk_box_append (GTK_BOX (box), button);
|
||||
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), box);
|
||||
button = gtk_switch_new ();
|
||||
gtk_accessible_update_property (GTK_ACCESSIBLE (button),
|
||||
GTK_ACCESSIBLE_PROPERTY_LABEL, "Change something",
|
||||
-1);
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), button);
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), gtk_switch_new ());
|
||||
|
||||
gtk_window_set_titlebar (GTK_WINDOW (window), header);
|
||||
|
||||
content = gtk_text_view_new ();
|
||||
gtk_accessible_update_property (GTK_ACCESSIBLE (content),
|
||||
GTK_ACCESSIBLE_PROPERTY_LABEL, "Content",
|
||||
-1);
|
||||
gtk_window_set_child (GTK_WINDOW (window), content);
|
||||
gtk_window_set_child (GTK_WINDOW (window), gtk_text_view_new ());
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
|
||||
@@ -164,18 +164,12 @@ do_image_scaling (GtkWidget *do_widget)
|
||||
scale = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, -10., 10., 0.1);
|
||||
gtk_scale_add_mark (GTK_SCALE (scale), 0., GTK_POS_TOP, NULL);
|
||||
gtk_widget_set_tooltip_text (scale, "Zoom");
|
||||
gtk_accessible_update_property (GTK_ACCESSIBLE (scale),
|
||||
GTK_ACCESSIBLE_PROPERTY_LABEL, "Zoom",
|
||||
-1);
|
||||
gtk_range_set_value (GTK_RANGE (scale), 0.);
|
||||
gtk_widget_set_hexpand (scale, TRUE);
|
||||
gtk_box_append (GTK_BOX (box2), scale);
|
||||
|
||||
dropdown = gtk_drop_down_new (G_LIST_MODEL (gtk_string_list_new ((const char *[]){ "Linear", "Nearest", "Trilinear", NULL })), NULL);
|
||||
gtk_widget_set_tooltip_text (dropdown, "Filter");
|
||||
gtk_accessible_update_property (GTK_ACCESSIBLE (dropdown),
|
||||
GTK_ACCESSIBLE_PROPERTY_LABEL, "Filter",
|
||||
-1);
|
||||
gtk_box_append (GTK_BOX (box2), dropdown);
|
||||
|
||||
g_object_bind_property (dropdown, "selected", widget, "filter", G_BINDING_DEFAULT);
|
||||
|
||||
@@ -49,7 +49,6 @@
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">1</property>
|
||||
<property name="mnemonic-widget">switch</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
@@ -74,7 +73,6 @@
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">1</property>
|
||||
<property name="mnemonic-widget">check</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
@@ -112,7 +110,6 @@
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="opacity">0</property>
|
||||
<property name="accessible-role">status</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
@@ -153,11 +150,10 @@
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">1</property>
|
||||
<property name="mnemonic-widget">scale</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScale" id="scale">
|
||||
<object class="GtkScale">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="draw-value">0</property>
|
||||
@@ -189,11 +185,10 @@
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">1</property>
|
||||
<property name="mnemonic-widget">spin</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="spin">
|
||||
<object class="GtkSpinButton">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="adjustment">
|
||||
@@ -222,11 +217,10 @@
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">1</property>
|
||||
<property name="mnemonic-widget">dropdown</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkDropDown" id="dropdown">
|
||||
<object class="GtkDropDown">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="model">
|
||||
@@ -258,11 +252,10 @@
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">1</property>
|
||||
<property name="mnemonic-widget">entry</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="entry">
|
||||
<object class="GtkEntry">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="placeholder-text">Type here…</property>
|
||||
|
||||
@@ -368,38 +368,6 @@ match_func (MatchObject *obj,
|
||||
g_free (tmp2);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_header (GtkSignalListItemFactory *factory,
|
||||
GObject *list_item,
|
||||
gpointer data)
|
||||
{
|
||||
GtkListHeader *self = GTK_LIST_HEADER (list_item);
|
||||
GtkWidget *child;
|
||||
|
||||
child = gtk_label_new ("");
|
||||
gtk_label_set_xalign (GTK_LABEL (child), 0);
|
||||
gtk_label_set_use_markup (GTK_LABEL (child), TRUE);
|
||||
gtk_widget_set_margin_top (child, 10);
|
||||
gtk_widget_set_margin_bottom (child, 10);
|
||||
|
||||
gtk_list_header_set_child (self, child);
|
||||
}
|
||||
|
||||
static void
|
||||
bind_header (GtkSignalListItemFactory *factory,
|
||||
GObject *list_item,
|
||||
gpointer data)
|
||||
{
|
||||
GtkListHeader *self = GTK_LIST_HEADER (list_item);
|
||||
GtkWidget *child = gtk_list_header_get_child (self);
|
||||
GObject *item = gtk_list_header_get_item (self);
|
||||
|
||||
if (strstr (gtk_string_object_get_string (GTK_STRING_OBJECT (item)), "hour"))
|
||||
gtk_label_set_label (GTK_LABEL (child), "<big><b>Hours</b></big>");
|
||||
else
|
||||
gtk_label_set_label (GTK_LABEL (child), "<big><b>Minutes</b></big>");
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_listview_selections (GtkWidget *do_widget)
|
||||
{
|
||||
@@ -409,12 +377,10 @@ do_listview_selections (GtkWidget *do_widget)
|
||||
GtkExpression *expression;
|
||||
GtkListItemFactory *factory;
|
||||
const char * const times[] = { "1 minute", "2 minutes", "5 minutes", "20 minutes", NULL };
|
||||
const char * const minutes[] = {
|
||||
const char * const many_times[] = {
|
||||
"1 minute", "2 minutes", "5 minutes", "10 minutes", "15 minutes", "20 minutes",
|
||||
"25 minutes", "30 minutes", "35 minutes", "40 minutes", "45 minutes", "50 minutes",
|
||||
"55 minutes", NULL
|
||||
};
|
||||
const char * const hours[] = { "1 hour", "2 hours", "3 hours", "5 hours", "6 hours", "7 hours",
|
||||
"55 minutes", "1 hour", "2 hours", "3 hours", "5 hours", "6 hours", "7 hours",
|
||||
"8 hours", "9 hours", "10 hours", "11 hours", "12 hours", NULL
|
||||
};
|
||||
const char * const device_titles[] = { "Digital Output", "Headphones", "Digital Output", "Analog Output", NULL };
|
||||
@@ -429,10 +395,6 @@ do_listview_selections (GtkWidget *do_widget)
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkStringList *minutes_model, *hours_model;
|
||||
GListStore *store;
|
||||
GtkFlattenListModel *flat;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
gtk_widget_get_display (do_widget));
|
||||
@@ -460,25 +422,14 @@ do_listview_selections (GtkWidget *do_widget)
|
||||
gtk_box_append (GTK_BOX (box), button);
|
||||
|
||||
/* A dropdown using an expression to obtain strings */
|
||||
minutes_model = gtk_string_list_new (minutes);
|
||||
hours_model = gtk_string_list_new (hours);
|
||||
store = g_list_store_new (G_TYPE_LIST_MODEL);
|
||||
g_list_store_append (store, minutes_model);
|
||||
g_list_store_append (store, hours_model);
|
||||
g_object_unref (minutes_model);
|
||||
g_object_unref (hours_model);
|
||||
flat = gtk_flatten_list_model_new (G_LIST_MODEL (store));
|
||||
button = drop_down_new_from_strings (many_times, NULL, NULL);
|
||||
gtk_drop_down_set_enable_search (GTK_DROP_DOWN (button), TRUE);
|
||||
expression = gtk_cclosure_expression_new (G_TYPE_STRING, NULL,
|
||||
0, NULL,
|
||||
(GCallback)get_title,
|
||||
NULL, NULL);
|
||||
button = gtk_drop_down_new (G_LIST_MODEL (flat), expression);
|
||||
gtk_drop_down_set_enable_search (GTK_DROP_DOWN (button), TRUE);
|
||||
factory = gtk_signal_list_item_factory_new ();
|
||||
g_signal_connect (factory, "setup", G_CALLBACK (setup_header), NULL);
|
||||
g_signal_connect (factory, "bind", G_CALLBACK (bind_header), NULL);
|
||||
gtk_drop_down_set_header_factory (GTK_DROP_DOWN (button), factory);
|
||||
g_object_unref (factory);
|
||||
gtk_drop_down_set_expression (GTK_DROP_DOWN (button), expression);
|
||||
gtk_expression_unref (expression);
|
||||
gtk_box_append (GTK_BOX (box), button);
|
||||
|
||||
button = gtk_drop_down_new (NULL, NULL);
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
<property name="child">
|
||||
<object class="GtkInscription">
|
||||
<property name="hexpand">1</property>
|
||||
<property name="nat-chars">25</property>
|
||||
<property name="text-overflow">ellipsize-end</property>
|
||||
<binding name="text">
|
||||
<lookup name="title" type="GtkDemo">
|
||||
<lookup name="item">expander</lookup>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
@@ -267,9 +268,9 @@ activate_run (GSimpleAction *action,
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
display_image (const char *format,
|
||||
const char *resource,
|
||||
GtkWidget *label)
|
||||
display_image (const char *format,
|
||||
const char *resource,
|
||||
char **label)
|
||||
{
|
||||
GtkWidget *sw, *image;
|
||||
|
||||
@@ -279,17 +280,13 @@ display_image (const char *format,
|
||||
sw = gtk_scrolled_window_new ();
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), image);
|
||||
|
||||
gtk_accessible_update_relation (GTK_ACCESSIBLE (image),
|
||||
GTK_ACCESSIBLE_RELATION_LABELLED_BY, label, NULL,
|
||||
-1);
|
||||
|
||||
return sw;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
display_images (const char *format,
|
||||
const char *resource_dir,
|
||||
GtkWidget *label)
|
||||
display_images (const char *format,
|
||||
const char *resource_dir,
|
||||
char **label)
|
||||
{
|
||||
char **resources;
|
||||
GtkWidget *grid;
|
||||
@@ -314,15 +311,13 @@ display_images (const char *format,
|
||||
{
|
||||
char *resource_name;
|
||||
GtkWidget *box;
|
||||
GtkWidget *image_label;
|
||||
|
||||
resource_name = g_strconcat (resource_dir, "/", resources[i], NULL);
|
||||
|
||||
image_label = gtk_label_new (resources[i]);
|
||||
widget = display_image (NULL, resource_name, image_label);
|
||||
widget = display_image (NULL, resource_name, NULL);
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_box_append (GTK_BOX (box), widget);
|
||||
gtk_box_append (GTK_BOX (box), image_label);
|
||||
gtk_box_append (GTK_BOX (box), gtk_label_new (resources[i]));
|
||||
gtk_flow_box_insert (GTK_FLOW_BOX (grid), box, -1);
|
||||
|
||||
g_free (resource_name);
|
||||
@@ -330,19 +325,15 @@ display_images (const char *format,
|
||||
|
||||
g_strfreev (resources);
|
||||
|
||||
gtk_label_set_label (GTK_LABEL (label), "Images");
|
||||
|
||||
gtk_accessible_update_relation (GTK_ACCESSIBLE (grid),
|
||||
GTK_ACCESSIBLE_RELATION_LABELLED_BY, label, NULL,
|
||||
-1);
|
||||
*label = g_strdup ("Images");
|
||||
|
||||
return sw;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
display_text (const char *format,
|
||||
const char *resource,
|
||||
GtkWidget *label)
|
||||
display_text (const char *format,
|
||||
const char *resource,
|
||||
char **label)
|
||||
{
|
||||
GtkTextBuffer *buffer;
|
||||
GtkWidget *textview, *sw;
|
||||
@@ -377,10 +368,6 @@ display_text (const char *format,
|
||||
|
||||
gtk_text_view_set_buffer (GTK_TEXT_VIEW (textview), buffer);
|
||||
|
||||
gtk_accessible_update_relation (GTK_ACCESSIBLE (textview),
|
||||
GTK_ACCESSIBLE_RELATION_LABELLED_BY, label, NULL,
|
||||
-1);
|
||||
|
||||
sw = gtk_scrolled_window_new ();
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
||||
GTK_POLICY_AUTOMATIC,
|
||||
@@ -391,19 +378,15 @@ display_text (const char *format,
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
display_video (const char *format,
|
||||
const char *resource,
|
||||
GtkWidget *label)
|
||||
display_video (const char *format,
|
||||
const char *resource,
|
||||
char **label)
|
||||
{
|
||||
GtkWidget *video;
|
||||
|
||||
video = gtk_video_new_for_resource (resource);
|
||||
gtk_video_set_loop (GTK_VIDEO (video), TRUE);
|
||||
|
||||
gtk_accessible_update_relation (GTK_ACCESSIBLE (video),
|
||||
GTK_ACCESSIBLE_RELATION_LABELLED_BY, label, NULL,
|
||||
-1);
|
||||
|
||||
return video;
|
||||
}
|
||||
|
||||
@@ -425,9 +408,9 @@ display_nothing (const char *resource)
|
||||
static struct {
|
||||
const char *extension;
|
||||
const char *format;
|
||||
GtkWidget * (* display_func) (const char *format,
|
||||
const char *resource,
|
||||
GtkWidget *label);
|
||||
GtkWidget * (* display_func) (const char *format,
|
||||
const char *resource,
|
||||
char **label);
|
||||
} display_funcs[] = {
|
||||
{ ".gif", NULL, display_image },
|
||||
{ ".jpg", NULL, display_image },
|
||||
@@ -450,6 +433,7 @@ add_data_tab (const char *demoname)
|
||||
char **resources;
|
||||
GtkWidget *widget, *label;
|
||||
guint i, j;
|
||||
char *label_string;
|
||||
|
||||
resource_dir = g_strconcat ("/", demoname, NULL);
|
||||
resources = g_resources_enumerate_children (resource_dir, 0, NULL);
|
||||
@@ -469,21 +453,23 @@ add_data_tab (const char *demoname)
|
||||
break;
|
||||
}
|
||||
|
||||
label = gtk_label_new (resources[i]);
|
||||
label_string = NULL;
|
||||
|
||||
if (j < G_N_ELEMENTS (display_funcs))
|
||||
widget = display_funcs[j].display_func (display_funcs[j].format,
|
||||
resource_name,
|
||||
label);
|
||||
&label_string);
|
||||
else
|
||||
widget = display_nothing (resource_name);
|
||||
|
||||
label = gtk_label_new (label_string ? label_string : resources[i]);
|
||||
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), widget, label);
|
||||
g_object_set (gtk_notebook_get_page (GTK_NOTEBOOK (notebook), widget),
|
||||
"tab-expand", FALSE,
|
||||
NULL);
|
||||
|
||||
g_free (resource_name);
|
||||
g_free (label_string);
|
||||
}
|
||||
|
||||
g_strfreev (resources);
|
||||
|
||||
@@ -57,17 +57,14 @@
|
||||
<object class="GtkBox">
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="width-request">220</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkSearchBar" id="searchbar">
|
||||
<accessibility>
|
||||
<relation name="labelled-by">search-entry</relation>
|
||||
</accessibility>
|
||||
<property name="key-capture-widget">window</property>
|
||||
<child>
|
||||
<object class="GtkSearchEntry" id="search-entry">
|
||||
<accessibility>
|
||||
<property name="label" translatable="yes">Search</property>
|
||||
<relation name="controls">listview</relation>
|
||||
</accessibility>
|
||||
</object>
|
||||
@@ -79,15 +76,15 @@
|
||||
<style>
|
||||
<class name="sidebar"/>
|
||||
</style>
|
||||
<property name="width-request">120</property>
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<property name="propagate-natural-width">1</property>
|
||||
<property name="min-content-width">150</property>
|
||||
<property name="vexpand">1</property>
|
||||
<child>
|
||||
<object class="GtkListView" id="listview">
|
||||
<style>
|
||||
<class name="navigation-sidebar"/>
|
||||
</style>
|
||||
<property name="tab-behavior">item</property>
|
||||
<property name="factory">
|
||||
<object class="GtkBuilderListItemFactory">
|
||||
<property name="resource">/ui/main-listitem.ui</property>
|
||||
|
||||
@@ -17,7 +17,6 @@ demos = files([
|
||||
'css_pixbufs.c',
|
||||
'css_shadows.c',
|
||||
'cursors.c',
|
||||
'curve.c',
|
||||
'dialog.c',
|
||||
'drawingarea.c',
|
||||
'dnd.c',
|
||||
@@ -35,7 +34,6 @@ demos = files([
|
||||
'gestures.c',
|
||||
'glarea.c',
|
||||
'gltransition.c',
|
||||
'glyphs.c',
|
||||
'headerbar.c',
|
||||
'hypertext.c',
|
||||
'iconscroll.c',
|
||||
@@ -74,9 +72,6 @@ demos = files([
|
||||
'paintable_symbolic.c',
|
||||
'panes.c',
|
||||
'password_entry.c',
|
||||
'path_fill.c',
|
||||
'path_maze.c',
|
||||
'path_text.c',
|
||||
'peg_solitaire.c',
|
||||
'pickers.c',
|
||||
'printing.c',
|
||||
@@ -141,10 +136,6 @@ extra_demo_sources = files([
|
||||
'unicode-names.c',
|
||||
'suggestionentry.c',
|
||||
'language-names.c',
|
||||
'nodewidget.c',
|
||||
'graphwidget.c',
|
||||
'curve-editor.c',
|
||||
'cepath.c',
|
||||
])
|
||||
|
||||
if os_unix
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
#include "nodewidget.h"
|
||||
|
||||
struct _NodeWidget
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GskRenderNode *node;
|
||||
};
|
||||
|
||||
struct _NodeWidgetClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (NodeWidget, node_widget, GTK_TYPE_WIDGET)
|
||||
|
||||
static void
|
||||
node_widget_init (NodeWidget *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
node_widget_dispose (GObject *object)
|
||||
{
|
||||
NodeWidget *self = NODE_WIDGET (object);
|
||||
|
||||
gsk_render_node_unref (self->node);
|
||||
|
||||
G_OBJECT_CLASS (node_widget_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
node_widget_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
NodeWidget *self = NODE_WIDGET (widget);
|
||||
|
||||
gtk_snapshot_append_node (snapshot, self->node);
|
||||
}
|
||||
|
||||
static void
|
||||
node_widget_class_init (NodeWidgetClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
object_class->dispose = node_widget_dispose;
|
||||
|
||||
widget_class->snapshot = node_widget_snapshot;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
node_widget_new (const char *resource)
|
||||
{
|
||||
NodeWidget *self;
|
||||
GBytes *bytes;
|
||||
GskRenderNode *node;
|
||||
graphene_rect_t bounds;
|
||||
float scale;
|
||||
GskTransform *transform;
|
||||
|
||||
self = g_object_new (NODE_TYPE_WIDGET, NULL);
|
||||
|
||||
bytes = g_resources_lookup_data (resource, 0, NULL);
|
||||
node = gsk_render_node_deserialize (bytes, NULL, NULL);
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
gsk_render_node_get_bounds (node, &bounds);
|
||||
scale = MIN (100.0/bounds.size.width, 100.0/bounds.size.height);
|
||||
transform = gsk_transform_scale (NULL, scale, scale);
|
||||
self->node = gsk_transform_node_new (node, transform);
|
||||
gsk_transform_unref (transform);
|
||||
gsk_render_node_unref (node);
|
||||
|
||||
return GTK_WIDGET (self);
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define NODE_TYPE_WIDGET (node_widget_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (NodeWidget, node_widget, NODE, WIDGET, GtkWidget)
|
||||
|
||||
GtkWidget * node_widget_new (const char *file);
|
||||
@@ -68,9 +68,6 @@ do_password_entry (GtkWidget *do_widget)
|
||||
"placeholder-text", "Password",
|
||||
"activates-default", TRUE,
|
||||
NULL);
|
||||
gtk_accessible_update_property (GTK_ACCESSIBLE (entry),
|
||||
GTK_ACCESSIBLE_PROPERTY_LABEL, "Password",
|
||||
-1);
|
||||
g_signal_connect (entry, "notify::text", G_CALLBACK (update_button), NULL);
|
||||
gtk_box_append (GTK_BOX (box), entry);
|
||||
|
||||
@@ -80,9 +77,6 @@ do_password_entry (GtkWidget *do_widget)
|
||||
"placeholder-text", "Confirm",
|
||||
"activates-default", TRUE,
|
||||
NULL);
|
||||
gtk_accessible_update_property (GTK_ACCESSIBLE (entry2),
|
||||
GTK_ACCESSIBLE_PROPERTY_LABEL, "Confirm",
|
||||
-1);
|
||||
g_signal_connect (entry2, "notify::text", G_CALLBACK (update_button), NULL);
|
||||
gtk_box_append (GTK_BOX (box), entry2);
|
||||
|
||||
|
||||
@@ -1,361 +0,0 @@
|
||||
/* Path/Fill
|
||||
*
|
||||
* This demo shows how to use PangoCairo to draw text with more than
|
||||
* just a single color.
|
||||
*/
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "paintable.h"
|
||||
|
||||
#define GTK_TYPE_PATH_PAINTABLE (gtk_path_paintable_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GtkPathPaintable, gtk_path_paintable, GTK, PATH_PAINTABLE, GObject)
|
||||
|
||||
struct _GtkPathPaintable
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
GskPath *path;
|
||||
GdkPaintable *background;
|
||||
};
|
||||
|
||||
struct _GtkPathPaintableClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
static int
|
||||
gtk_path_paintable_get_intrinsic_width (GdkPaintable *paintable)
|
||||
{
|
||||
GtkPathPaintable *self = GTK_PATH_PAINTABLE (paintable);
|
||||
|
||||
if (self->background)
|
||||
return MAX (gdk_paintable_get_intrinsic_width (self->background), self->width);
|
||||
else
|
||||
return self->width;
|
||||
}
|
||||
|
||||
static int
|
||||
gtk_path_paintable_get_intrinsic_height (GdkPaintable *paintable)
|
||||
{
|
||||
GtkPathPaintable *self = GTK_PATH_PAINTABLE (paintable);
|
||||
|
||||
if (self->background)
|
||||
return MAX (gdk_paintable_get_intrinsic_height (self->background), self->height);
|
||||
else
|
||||
return self->height;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_paintable_snapshot (GdkPaintable *paintable,
|
||||
GdkSnapshot *snapshot,
|
||||
double width,
|
||||
double height)
|
||||
{
|
||||
GtkPathPaintable *self = GTK_PATH_PAINTABLE (paintable);
|
||||
|
||||
#if 0
|
||||
gtk_snapshot_push_fill (snapshot, self->path, GSK_FILL_RULE_WINDING);
|
||||
#else
|
||||
GskStroke *stroke = gsk_stroke_new (2.0);
|
||||
gtk_snapshot_push_stroke (snapshot, self->path, stroke);
|
||||
gsk_stroke_free (stroke);
|
||||
#endif
|
||||
|
||||
if (self->background)
|
||||
{
|
||||
gdk_paintable_snapshot (self->background, snapshot, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_snapshot_append_linear_gradient (snapshot,
|
||||
&GRAPHENE_RECT_INIT (0, 0, width, height),
|
||||
&GRAPHENE_POINT_INIT (0, 0),
|
||||
&GRAPHENE_POINT_INIT (width, height),
|
||||
(GskColorStop[8]) {
|
||||
{ 0.0, { 1.0, 0.0, 0.0, 1.0 } },
|
||||
{ 0.2, { 1.0, 0.0, 0.0, 1.0 } },
|
||||
{ 0.3, { 1.0, 1.0, 0.0, 1.0 } },
|
||||
{ 0.4, { 0.0, 1.0, 0.0, 1.0 } },
|
||||
{ 0.6, { 0.0, 1.0, 1.0, 1.0 } },
|
||||
{ 0.7, { 0.0, 0.0, 1.0, 1.0 } },
|
||||
{ 0.8, { 1.0, 0.0, 1.0, 1.0 } },
|
||||
{ 1.0, { 1.0, 0.0, 1.0, 1.0 } }
|
||||
},
|
||||
8);
|
||||
}
|
||||
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
}
|
||||
|
||||
static GdkPaintableFlags
|
||||
gtk_path_paintable_get_flags (GdkPaintable *paintable)
|
||||
{
|
||||
GtkPathPaintable *self = GTK_PATH_PAINTABLE (paintable);
|
||||
|
||||
if (self->background)
|
||||
return gdk_paintable_get_flags (self->background);
|
||||
else
|
||||
return GDK_PAINTABLE_STATIC_CONTENTS | GDK_PAINTABLE_STATIC_SIZE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_paintable_paintable_init (GdkPaintableInterface *iface)
|
||||
{
|
||||
iface->get_intrinsic_width = gtk_path_paintable_get_intrinsic_width;
|
||||
iface->get_intrinsic_height = gtk_path_paintable_get_intrinsic_height;
|
||||
iface->snapshot = gtk_path_paintable_snapshot;
|
||||
iface->get_flags = gtk_path_paintable_get_flags;
|
||||
}
|
||||
|
||||
/* When defining the GType, we need to implement the GdkPaintable interface */
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkPathPaintable, gtk_path_paintable, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
|
||||
gtk_path_paintable_paintable_init))
|
||||
|
||||
/* Here's the boilerplate for the GObject declaration.
|
||||
* We need to disconnect the signals here that we set up elsewhere
|
||||
*/
|
||||
static void
|
||||
gtk_path_paintable_dispose (GObject *object)
|
||||
{
|
||||
GtkPathPaintable *self = GTK_PATH_PAINTABLE (object);
|
||||
|
||||
if (self->background)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (self->background, gdk_paintable_invalidate_contents, self);
|
||||
g_signal_handlers_disconnect_by_func (self->background, gdk_paintable_invalidate_size, self);
|
||||
g_clear_object (&self->background);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (gtk_path_paintable_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_paintable_class_init (GtkPathPaintableClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = gtk_path_paintable_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_paintable_init (GtkPathPaintable *self)
|
||||
{
|
||||
}
|
||||
|
||||
/* And finally, we add a simple constructor.
|
||||
* It is declared in the header so that the other examples
|
||||
* can use it.
|
||||
*/
|
||||
GdkPaintable *
|
||||
gtk_path_paintable_new (GskPath *path,
|
||||
GdkPaintable *background,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
GtkPathPaintable *self;
|
||||
|
||||
self = g_object_new (GTK_TYPE_PATH_PAINTABLE, NULL);
|
||||
self->path = path;
|
||||
self->background = background;
|
||||
if (self->background)
|
||||
{
|
||||
g_object_ref (self->background);
|
||||
g_signal_connect_swapped (self->background, "invalidate-contents", G_CALLBACK (gdk_paintable_invalidate_contents), self);
|
||||
g_signal_connect_swapped (self->background, "invalidate-size", G_CALLBACK (gdk_paintable_invalidate_size), self);
|
||||
}
|
||||
self->width = width;
|
||||
self->height = height;
|
||||
|
||||
return GDK_PAINTABLE (self);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_path_paintable_set_path (GtkPathPaintable *self,
|
||||
GskPath *path)
|
||||
{
|
||||
g_clear_pointer (&self->path, gsk_path_unref);
|
||||
self->path = gsk_path_ref (path);
|
||||
|
||||
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
|
||||
}
|
||||
|
||||
static GskPath *
|
||||
create_hexagon (GtkWidget *widget)
|
||||
{
|
||||
GskPathBuilder *builder;
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
|
||||
gsk_path_builder_move_to (builder, 120, 0);
|
||||
gsk_path_builder_line_to (builder, 360, 0);
|
||||
gsk_path_builder_line_to (builder, 480, 208);
|
||||
gsk_path_builder_line_to (builder, 360, 416);
|
||||
gsk_path_builder_line_to (builder, 120, 416);
|
||||
gsk_path_builder_line_to (builder, 0, 208);
|
||||
gsk_path_builder_close (builder);
|
||||
|
||||
return gsk_path_builder_free_to_path (builder);
|
||||
}
|
||||
|
||||
static GskPath *
|
||||
create_path_from_text (GtkWidget *widget)
|
||||
{
|
||||
PangoLayout *layout;
|
||||
PangoFontDescription *desc;
|
||||
GskPathBuilder *builder;
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, "Pango power!\nPango power!\nPango power!");
|
||||
desc = pango_font_description_from_string ("sans bold 36");
|
||||
pango_layout_set_font_description (layout, desc);
|
||||
pango_font_description_free (desc);
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
|
||||
gsk_path_builder_add_layout (builder, layout);
|
||||
|
||||
return gsk_path_builder_free_to_path (builder);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
build_path (GskPathOperation op,
|
||||
const graphene_point_t *pts,
|
||||
gsize n_pts,
|
||||
float weight,
|
||||
gpointer user_data)
|
||||
{
|
||||
GskPathBuilder *builder = user_data;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case GSK_PATH_MOVE:
|
||||
gsk_path_builder_move_to (builder, pts[0].x, pts[0].y);
|
||||
break;
|
||||
|
||||
case GSK_PATH_CLOSE:
|
||||
gsk_path_builder_close (builder);
|
||||
break;
|
||||
|
||||
case GSK_PATH_LINE:
|
||||
gsk_path_builder_line_to (builder, pts[1].x, pts[1].y);
|
||||
break;
|
||||
|
||||
case GSK_PATH_QUAD:
|
||||
gsk_path_builder_quad_to (builder, pts[1].x, pts[1].y, pts[2].x, pts[2].y);
|
||||
break;
|
||||
|
||||
case GSK_PATH_CUBIC:
|
||||
gsk_path_builder_cubic_to (builder, pts[1].x, pts[1].y, pts[2].x, pts[2].y, pts[3].x, pts[3].y);
|
||||
break;
|
||||
|
||||
case GSK_PATH_CONIC:
|
||||
gsk_path_builder_conic_to (builder, pts[1].x, pts[1].y, pts[2].x, pts[2].y, weight);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
update_path (GtkWidget *widget,
|
||||
GdkFrameClock *frame_clock,
|
||||
gpointer measure)
|
||||
{
|
||||
float progress = gdk_frame_clock_get_frame_time (frame_clock) % (60 * G_USEC_PER_SEC) / (float) (30 * G_USEC_PER_SEC);
|
||||
GskPathBuilder *builder;
|
||||
GskPath *path;
|
||||
GskPathPoint *point;
|
||||
graphene_point_t pos;
|
||||
graphene_vec2_t tangent;
|
||||
GskStroke *stroke;
|
||||
|
||||
path = gsk_path_measure_get_path (measure);
|
||||
|
||||
stroke = gsk_stroke_new (1);
|
||||
gsk_stroke_set_dash (stroke, (float[2]) { 10, 5 }, 2);
|
||||
gsk_stroke_set_dash_offset (stroke, - (gdk_frame_clock_get_frame_time (frame_clock) % G_USEC_PER_SEC) * 15. / G_USEC_PER_SEC);
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_dash (path, stroke, 0.2, build_path, builder);
|
||||
|
||||
point = gsk_path_measure_get_point (measure,
|
||||
(progress > 1 ? (progress - 1) : progress) * gsk_path_measure_get_length (measure));
|
||||
gsk_path_point_get_position (point, &pos);
|
||||
gsk_path_point_get_tangent (point, GSK_PATH_END, &tangent);
|
||||
gsk_path_point_unref (point);
|
||||
|
||||
gsk_path_builder_move_to (builder, pos.x + 5 * graphene_vec2_get_x (&tangent), pos.y + 5 * graphene_vec2_get_y (&tangent));
|
||||
gsk_path_builder_line_to (builder, pos.x + 3 * graphene_vec2_get_y (&tangent), pos.y + 3 * graphene_vec2_get_x (&tangent));
|
||||
gsk_path_builder_line_to (builder, pos.x - 3 * graphene_vec2_get_y (&tangent), pos.y - 3 * graphene_vec2_get_x (&tangent));
|
||||
gsk_path_builder_close (builder);
|
||||
|
||||
path = gsk_path_builder_free_to_path (builder);
|
||||
|
||||
gtk_path_paintable_set_path (GTK_PATH_PAINTABLE (gtk_picture_get_paintable (GTK_PICTURE (widget))),
|
||||
path);
|
||||
gsk_path_unref (path);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_path_fill (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkWidget *picture;
|
||||
GdkPaintable *paintable;
|
||||
GtkMediaStream *stream;
|
||||
GskPath *path;
|
||||
graphene_rect_t bounds;
|
||||
GskPathMeasure *measure;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Path Fill");
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
#if 0
|
||||
stream = gtk_media_file_new_for_resource ("/images/gtk-logo.webm");
|
||||
#else
|
||||
stream = gtk_nuclear_media_stream_new ();
|
||||
#endif
|
||||
gtk_media_stream_play (stream);
|
||||
gtk_media_stream_set_loop (stream, TRUE);
|
||||
|
||||
path = create_hexagon (window);
|
||||
path = create_path_from_text (window);
|
||||
gsk_path_get_bounds (path, &bounds);
|
||||
|
||||
paintable = gtk_path_paintable_new (path,
|
||||
GDK_PAINTABLE (stream),
|
||||
bounds.origin.x + bounds.size.width,
|
||||
bounds.origin.y + bounds.size.height);
|
||||
picture = gtk_picture_new_for_paintable (paintable);
|
||||
measure = gsk_path_measure_new (path);
|
||||
gtk_widget_add_tick_callback (picture, update_path, measure, (GDestroyNotify) gsk_path_measure_unref);
|
||||
gtk_picture_set_content_fit (GTK_PICTURE (picture), GTK_CONTENT_FIT_CONTAIN);
|
||||
gtk_picture_set_can_shrink (GTK_PICTURE (picture), FALSE);
|
||||
g_object_unref (paintable);
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), picture);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -1,345 +0,0 @@
|
||||
/* Path/Maze
|
||||
*
|
||||
* This demo shows how to use a GskPath to create a maze and use
|
||||
* gsk_path_measure_get_closest_point() to check the mouse stays
|
||||
* on the path.
|
||||
*
|
||||
* It also shows off the performance of GskPath (or not) as this
|
||||
* is a rather complex path.
|
||||
*/
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "paintable.h"
|
||||
|
||||
#define MAZE_GRID_SIZE 20
|
||||
#define MAZE_STROKE_SIZE_ACTIVE (MAZE_GRID_SIZE - 4)
|
||||
#define MAZE_STROKE_SIZE_INACTIVE (MAZE_GRID_SIZE - 12)
|
||||
#define MAZE_WIDTH 31
|
||||
#define MAZE_HEIGHT 21
|
||||
|
||||
#define GTK_TYPE_MAZE (gtk_maze_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GtkMaze, gtk_maze, GTK, MAZE, GtkWidget)
|
||||
|
||||
struct _GtkMaze
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
GskPath *path;
|
||||
GskPathMeasure *measure;
|
||||
GdkPaintable *background;
|
||||
|
||||
gboolean active;
|
||||
};
|
||||
|
||||
struct _GtkMazeClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkMaze, gtk_maze, GTK_TYPE_WIDGET)
|
||||
|
||||
static void
|
||||
gtk_maze_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
GtkMaze *self = GTK_MAZE (widget);
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
*minimum = *natural = self->width;
|
||||
else
|
||||
*minimum = *natural = self->height;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_maze_snapshot (GtkWidget *widget,
|
||||
GdkSnapshot *snapshot)
|
||||
{
|
||||
GtkMaze *self = GTK_MAZE (widget);
|
||||
double width = gtk_widget_get_width (widget);
|
||||
double height = gtk_widget_get_height (widget);
|
||||
GskStroke *stroke;
|
||||
|
||||
stroke = gsk_stroke_new (MAZE_STROKE_SIZE_INACTIVE);
|
||||
if (self->active)
|
||||
gsk_stroke_set_line_width (stroke, MAZE_STROKE_SIZE_ACTIVE);
|
||||
gsk_stroke_set_line_join (stroke, GSK_LINE_JOIN_ROUND);
|
||||
gsk_stroke_set_line_cap (stroke, GSK_LINE_CAP_ROUND);
|
||||
gtk_snapshot_push_stroke (snapshot, self->path, stroke);
|
||||
gsk_stroke_free (stroke);
|
||||
|
||||
if (self->background)
|
||||
{
|
||||
gdk_paintable_snapshot (self->background, snapshot, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_snapshot_append_linear_gradient (snapshot,
|
||||
&GRAPHENE_RECT_INIT (0, 0, width, height),
|
||||
&GRAPHENE_POINT_INIT (0, 0),
|
||||
&GRAPHENE_POINT_INIT (width, height),
|
||||
(GskColorStop[8]) {
|
||||
{ 0.0, { 1.0, 0.0, 0.0, 1.0 } },
|
||||
{ 0.2, { 1.0, 0.0, 0.0, 1.0 } },
|
||||
{ 0.3, { 1.0, 1.0, 0.0, 1.0 } },
|
||||
{ 0.4, { 0.0, 1.0, 0.0, 1.0 } },
|
||||
{ 0.6, { 0.0, 1.0, 1.0, 1.0 } },
|
||||
{ 0.7, { 0.0, 0.0, 1.0, 1.0 } },
|
||||
{ 0.8, { 1.0, 0.0, 1.0, 1.0 } },
|
||||
{ 1.0, { 1.0, 0.0, 1.0, 1.0 } }
|
||||
},
|
||||
8);
|
||||
}
|
||||
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_maze_dispose (GObject *object)
|
||||
{
|
||||
GtkMaze *self = GTK_MAZE (object);
|
||||
|
||||
g_clear_pointer (&self->path, gsk_path_unref);
|
||||
g_clear_pointer (&self->measure, gsk_path_measure_unref);
|
||||
if (self->background)
|
||||
{
|
||||
g_signal_handlers_disconnect_matched (self->background, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
|
||||
g_clear_object (&self->background);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (gtk_maze_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_maze_class_init (GtkMazeClass *klass)
|
||||
{
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = gtk_maze_dispose;
|
||||
|
||||
widget_class->measure = gtk_maze_measure;
|
||||
widget_class->snapshot = gtk_maze_snapshot;
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_motion (GtkEventControllerMotion *controller,
|
||||
double x,
|
||||
double y,
|
||||
GtkMaze *self)
|
||||
{
|
||||
GskPathPoint *point;
|
||||
graphene_point_t pos;
|
||||
|
||||
if (!self->active)
|
||||
return;
|
||||
|
||||
point = gsk_path_measure_get_closest_point (self->measure, &GRAPHENE_POINT_INIT (x, y), INFINITY);
|
||||
gsk_path_point_get_position (point, &pos);
|
||||
gsk_path_point_unref (point);
|
||||
|
||||
if (graphene_point_distance (&pos, &GRAPHENE_POINT_INIT (x, y), NULL, NULL) <= MAZE_STROKE_SIZE_ACTIVE / 2.0f)
|
||||
return;
|
||||
|
||||
self->active = FALSE;
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_leave (GtkEventControllerMotion *controller,
|
||||
GtkMaze *self)
|
||||
{
|
||||
if (!self->active)
|
||||
{
|
||||
self->active = TRUE;
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_maze_init (GtkMaze *self)
|
||||
{
|
||||
GtkEventController *controller;
|
||||
|
||||
controller = GTK_EVENT_CONTROLLER (gtk_event_controller_motion_new ());
|
||||
g_signal_connect (controller, "motion", G_CALLBACK (pointer_motion), self);
|
||||
g_signal_connect (controller, "leave", G_CALLBACK (pointer_leave), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), controller);
|
||||
|
||||
self->active = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_maze_set_path (GtkMaze *self,
|
||||
GskPath *path)
|
||||
{
|
||||
g_clear_pointer (&self->path, gsk_path_unref);
|
||||
g_clear_pointer (&self->measure, gsk_path_measure_unref);
|
||||
self->path = gsk_path_ref (path);
|
||||
self->measure = gsk_path_measure_new (path);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gtk_maze_new (GskPath *path,
|
||||
GdkPaintable *background,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
GtkMaze *self;
|
||||
|
||||
self = g_object_new (GTK_TYPE_MAZE, NULL);
|
||||
|
||||
gtk_maze_set_path (self, path);
|
||||
gsk_path_unref (path);
|
||||
self->background = background;
|
||||
if (self->background)
|
||||
{
|
||||
g_signal_connect_swapped (self->background, "invalidate-contents", G_CALLBACK (gtk_widget_queue_draw), self);
|
||||
g_signal_connect_swapped (self->background, "invalidate-size", G_CALLBACK (gtk_widget_queue_resize), self);
|
||||
}
|
||||
self->width = width;
|
||||
self->height = height;
|
||||
|
||||
return GTK_WIDGET (self);
|
||||
}
|
||||
|
||||
static void
|
||||
add_point_to_maze (GtkBitset *maze,
|
||||
GskPathBuilder *builder,
|
||||
guint x,
|
||||
guint y)
|
||||
{
|
||||
gboolean set[4] = { FALSE, FALSE, FALSE, FALSE };
|
||||
guint dir;
|
||||
|
||||
gtk_bitset_add (maze, y * MAZE_WIDTH + x);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
set[0] = set[0] || x == 0 || gtk_bitset_contains (maze, y * MAZE_WIDTH + x - 1);
|
||||
set[1] = set[1] || y == 0 || gtk_bitset_contains (maze, (y - 1) * MAZE_WIDTH + x);
|
||||
set[2] = set[2] || x + 1 == MAZE_WIDTH || gtk_bitset_contains (maze, y * MAZE_WIDTH + x + 1);
|
||||
set[3] = set[3] || y + 1 == MAZE_HEIGHT || gtk_bitset_contains (maze, (y + 1) * MAZE_WIDTH + x);
|
||||
|
||||
if (set[0] && set[1] && set[2] && set[3])
|
||||
return;
|
||||
|
||||
do
|
||||
{
|
||||
dir = g_random_int_range (0, 4);
|
||||
}
|
||||
while (set[dir]);
|
||||
|
||||
switch (dir)
|
||||
{
|
||||
case 0:
|
||||
gsk_path_builder_move_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_line_to (builder, (x - 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
|
||||
add_point_to_maze (maze, builder, x - 1, y);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
gsk_path_builder_move_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_line_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y - 0.5) * MAZE_GRID_SIZE);
|
||||
add_point_to_maze (maze, builder, x, y - 1);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
gsk_path_builder_move_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_line_to (builder, (x + 1.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
|
||||
add_point_to_maze (maze, builder, x + 1, y);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
gsk_path_builder_move_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_line_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 1.5) * MAZE_GRID_SIZE);
|
||||
add_point_to_maze (maze, builder, x, y + 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static GskPath *
|
||||
create_path_for_maze (GtkWidget *widget)
|
||||
{
|
||||
GskPathBuilder *builder;
|
||||
GtkBitset *maze;
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
maze = gtk_bitset_new_empty ();
|
||||
/* make sure the outer lines are unreachable:
|
||||
* Set the full range, then remove the center again. */
|
||||
gtk_bitset_add_range (maze, 0, MAZE_WIDTH * MAZE_HEIGHT);
|
||||
gtk_bitset_remove_rectangle (maze, MAZE_WIDTH + 1, MAZE_WIDTH - 2, MAZE_HEIGHT - 2, MAZE_WIDTH);
|
||||
|
||||
/* Fill the maze */
|
||||
add_point_to_maze (maze, builder, MAZE_WIDTH / 2, MAZE_HEIGHT / 2);
|
||||
|
||||
/* Add start and stop lines */
|
||||
gsk_path_builder_move_to (builder, 1.5 * MAZE_GRID_SIZE, -0.5 * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_line_to (builder, 1.5 * MAZE_GRID_SIZE, 1.5 * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_move_to (builder, (MAZE_WIDTH - 1.5) * MAZE_GRID_SIZE, (MAZE_HEIGHT - 1.5) * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_line_to (builder, (MAZE_WIDTH - 1.5) * MAZE_GRID_SIZE, (MAZE_HEIGHT + 0.5) * MAZE_GRID_SIZE);
|
||||
|
||||
|
||||
gtk_bitset_unref (maze);
|
||||
|
||||
return gsk_path_builder_free_to_path (builder);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_path_maze (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkWidget *maze;
|
||||
GtkMediaStream *stream;
|
||||
GskPath *path;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Follow the maze with the mouse");
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
#if 0
|
||||
stream = gtk_media_file_new_for_resource ("/images/gtk-logo.webm");
|
||||
#else
|
||||
stream = gtk_nuclear_media_stream_new ();
|
||||
#endif
|
||||
gtk_media_stream_play (stream);
|
||||
gtk_media_stream_set_loop (stream, TRUE);
|
||||
|
||||
path = create_path_for_maze (window);
|
||||
|
||||
maze = gtk_maze_new (path,
|
||||
GDK_PAINTABLE (stream),
|
||||
MAZE_WIDTH * MAZE_GRID_SIZE,
|
||||
MAZE_HEIGHT * MAZE_GRID_SIZE);
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), maze);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -1,608 +0,0 @@
|
||||
/* Path/Text
|
||||
*
|
||||
* This demo shows how to use GskPath to animate a path along another path.
|
||||
*/
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define GTK_TYPE_PATH_WIDGET (gtk_path_widget_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GtkPathWidget, gtk_path_widget, GTK, PATH_WIDGET, GtkWidget)
|
||||
|
||||
#define POINT_SIZE 8
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_TEXT,
|
||||
PROP_EDITABLE,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
struct _GtkPathWidget
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
char *text;
|
||||
gboolean editable;
|
||||
|
||||
graphene_point_t points[4];
|
||||
|
||||
guint active_point;
|
||||
float line_closest;
|
||||
|
||||
GskPath *line_path;
|
||||
GskPathMeasure *line_measure;
|
||||
GskPath *text_path;
|
||||
|
||||
GdkPaintable *background;
|
||||
};
|
||||
|
||||
struct _GtkPathWidgetClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
static GParamSpec *properties[N_PROPS] = { NULL, };
|
||||
|
||||
G_DEFINE_TYPE (GtkPathWidget, gtk_path_widget, GTK_TYPE_WIDGET)
|
||||
|
||||
static GskPath *
|
||||
create_path_from_text (GtkWidget *widget,
|
||||
const char *text,
|
||||
graphene_point_t *out_offset)
|
||||
{
|
||||
PangoLayout *layout;
|
||||
PangoFontDescription *desc;
|
||||
GskPathBuilder *builder;
|
||||
GskPath *result;
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, text);
|
||||
desc = pango_font_description_from_string ("sans bold 36");
|
||||
pango_layout_set_font_description (layout, desc);
|
||||
pango_font_description_free (desc);
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_builder_add_layout (builder, layout);
|
||||
result = gsk_path_builder_free_to_path (builder);
|
||||
|
||||
if (out_offset)
|
||||
graphene_point_init (out_offset, 0, - pango_layout_get_baseline (layout) / (double) PANGO_SCALE);
|
||||
g_object_unref (layout);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GskPathMeasure *measure;
|
||||
GskPathBuilder *builder;
|
||||
graphene_point_t offset;
|
||||
double scale;
|
||||
} GtkPathTransform;
|
||||
|
||||
static void
|
||||
gtk_path_transform_point (GskPathMeasure *measure,
|
||||
const graphene_point_t *pt,
|
||||
const graphene_point_t *offset,
|
||||
float scale,
|
||||
graphene_point_t *res)
|
||||
{
|
||||
graphene_vec2_t tangent;
|
||||
GskPathPoint *point;
|
||||
|
||||
point = gsk_path_measure_get_point (measure, (pt->x + offset->x) * scale);
|
||||
gsk_path_point_get_position (point, res);
|
||||
gsk_path_point_get_tangent (point, GSK_PATH_END, &tangent);
|
||||
gsk_path_point_unref (point);
|
||||
|
||||
res->x -= (pt->y + offset->y) * scale * graphene_vec2_get_y (&tangent);
|
||||
res->y += (pt->y + offset->y) * scale * graphene_vec2_get_x (&tangent);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_path_transform_op (GskPathOperation op,
|
||||
const graphene_point_t *pts,
|
||||
gsize n_pts,
|
||||
float weight,
|
||||
gpointer data)
|
||||
{
|
||||
GtkPathTransform *transform = data;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case GSK_PATH_MOVE:
|
||||
{
|
||||
graphene_point_t res;
|
||||
gtk_path_transform_point (transform->measure, &pts[0], &transform->offset, transform->scale, &res);
|
||||
gsk_path_builder_move_to (transform->builder, res.x, res.y);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_PATH_LINE:
|
||||
{
|
||||
graphene_point_t res;
|
||||
gtk_path_transform_point (transform->measure, &pts[1], &transform->offset, transform->scale, &res);
|
||||
gsk_path_builder_line_to (transform->builder, res.x, res.y);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_PATH_QUAD:
|
||||
{
|
||||
graphene_point_t res[2];
|
||||
gtk_path_transform_point (transform->measure, &pts[1], &transform->offset, transform->scale, &res[0]);
|
||||
gtk_path_transform_point (transform->measure, &pts[2], &transform->offset, transform->scale, &res[1]);
|
||||
gsk_path_builder_quad_to (transform->builder, res[0].x, res[0].y, res[1].x, res[1].y);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_PATH_CUBIC:
|
||||
{
|
||||
graphene_point_t res[3];
|
||||
gtk_path_transform_point (transform->measure, &pts[1], &transform->offset, transform->scale, &res[0]);
|
||||
gtk_path_transform_point (transform->measure, &pts[2], &transform->offset, transform->scale, &res[1]);
|
||||
gtk_path_transform_point (transform->measure, &pts[3], &transform->offset, transform->scale, &res[2]);
|
||||
gsk_path_builder_cubic_to (transform->builder, res[0].x, res[0].y, res[1].x, res[1].y, res[2].x, res[2].y);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_PATH_CONIC:
|
||||
{
|
||||
graphene_point_t res[2];
|
||||
gtk_path_transform_point (transform->measure, &pts[1], &transform->offset, transform->scale, &res[0]);
|
||||
gtk_path_transform_point (transform->measure, &pts[2], &transform->offset, transform->scale, &res[1]);
|
||||
gsk_path_builder_conic_to (transform->builder, res[0].x, res[0].y, res[1].x, res[1].y, weight);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_PATH_CLOSE:
|
||||
gsk_path_builder_close (transform->builder);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GskPath *
|
||||
gtk_path_transform (GskPathMeasure *measure,
|
||||
GskPath *path,
|
||||
const graphene_point_t *offset)
|
||||
{
|
||||
GtkPathTransform transform = { measure, gsk_path_builder_new (), *offset };
|
||||
graphene_rect_t bounds;
|
||||
|
||||
gsk_path_get_bounds (path, &bounds);
|
||||
if (bounds.origin.x + bounds.size.width > 0)
|
||||
transform.scale = gsk_path_measure_get_length (measure) / (bounds.origin.x + bounds.size.width);
|
||||
else
|
||||
transform.scale = 1.0f;
|
||||
|
||||
gsk_path_foreach (path, -1, gtk_path_transform_op, &transform);
|
||||
|
||||
return gsk_path_builder_free_to_path (transform.builder);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_clear_text_path (GtkPathWidget *self)
|
||||
{
|
||||
g_clear_pointer (&self->text_path, gsk_path_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_clear_paths (GtkPathWidget *self)
|
||||
{
|
||||
gtk_path_widget_clear_text_path (self);
|
||||
|
||||
g_clear_pointer (&self->line_path, gsk_path_unref);
|
||||
g_clear_pointer (&self->line_measure, gsk_path_measure_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_create_text_path (GtkPathWidget *self)
|
||||
{
|
||||
GskPath *path;
|
||||
graphene_point_t offset;
|
||||
|
||||
gtk_path_widget_clear_text_path (self);
|
||||
|
||||
if (self->line_measure == NULL)
|
||||
return;
|
||||
|
||||
path = create_path_from_text (GTK_WIDGET (self), self->text, &offset);
|
||||
self->text_path = gtk_path_transform (self->line_measure, path, &offset);
|
||||
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_create_paths (GtkPathWidget *self)
|
||||
{
|
||||
double width = gtk_widget_get_width (GTK_WIDGET (self));
|
||||
double height = gtk_widget_get_height (GTK_WIDGET (self));
|
||||
GskPathBuilder *builder;
|
||||
|
||||
gtk_path_widget_clear_paths (self);
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
return;
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_builder_move_to (builder,
|
||||
self->points[0].x * width, self->points[0].y * height);
|
||||
gsk_path_builder_cubic_to (builder,
|
||||
self->points[1].x * width, self->points[1].y * height,
|
||||
self->points[2].x * width, self->points[2].y * height,
|
||||
self->points[3].x * width, self->points[3].y * height);
|
||||
self->line_path = gsk_path_builder_free_to_path (builder);
|
||||
|
||||
self->line_measure = gsk_path_measure_new (self->line_path);
|
||||
|
||||
gtk_path_widget_create_text_path (self);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
GtkPathWidget *self = GTK_PATH_WIDGET (widget);
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_path_widget_parent_class)->size_allocate (widget, width, height, baseline);
|
||||
|
||||
gtk_path_widget_create_paths (self);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
GtkPathWidget *self = GTK_PATH_WIDGET (widget);
|
||||
double width = gtk_widget_get_width (widget);
|
||||
double height = gtk_widget_get_height (widget);
|
||||
GskPath *path;
|
||||
GskStroke *stroke;
|
||||
gsize i;
|
||||
|
||||
/* frosted glass the background */
|
||||
gtk_snapshot_push_blur (snapshot, 100);
|
||||
gdk_paintable_snapshot (self->background, snapshot, width, height);
|
||||
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 1, 1, 1, 0.6 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
/* draw the text */
|
||||
if (self->text_path)
|
||||
{
|
||||
gtk_snapshot_push_fill (snapshot, self->text_path, GSK_FILL_RULE_WINDING);
|
||||
gdk_paintable_snapshot (self->background, snapshot, width, height);
|
||||
|
||||
/* ... with an emboss effect */
|
||||
stroke = gsk_stroke_new (2.0);
|
||||
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT(1, 1));
|
||||
gtk_snapshot_push_stroke (snapshot, self->text_path, stroke);
|
||||
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 0, 0.2 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gsk_stroke_free (stroke);
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
gtk_snapshot_pop (snapshot);
|
||||
}
|
||||
|
||||
if (self->editable && self->line_path)
|
||||
{
|
||||
GskPathBuilder *builder;
|
||||
|
||||
/* draw the control line */
|
||||
stroke = gsk_stroke_new (1.0);
|
||||
gtk_snapshot_push_stroke (snapshot, self->line_path, stroke);
|
||||
gsk_stroke_free (stroke);
|
||||
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 0, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
/* draw the points */
|
||||
builder = gsk_path_builder_new ();
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (self->points[i].x * width, self->points[i].y * height), POINT_SIZE);
|
||||
}
|
||||
path = gsk_path_builder_free_to_path (builder);
|
||||
|
||||
gtk_snapshot_push_fill (snapshot, path, GSK_FILL_RULE_WINDING);
|
||||
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 1, 1, 1, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
stroke = gsk_stroke_new (1.0);
|
||||
gtk_snapshot_push_stroke (snapshot, path, stroke);
|
||||
gsk_stroke_free (stroke);
|
||||
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 0, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
|
||||
if (self->line_closest >= 0)
|
||||
{
|
||||
GskPathBuilder *builder;
|
||||
GskPathPoint *point;
|
||||
graphene_point_t closest;
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
point = gsk_path_measure_get_point (self->line_measure, self->line_closest);
|
||||
gsk_path_point_get_position (point, &closest);
|
||||
gsk_path_point_unref (point);
|
||||
gsk_path_builder_add_circle (builder, &closest, POINT_SIZE);
|
||||
path = gsk_path_builder_free_to_path (builder);
|
||||
|
||||
gtk_snapshot_push_fill (snapshot, path, GSK_FILL_RULE_WINDING);
|
||||
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 1, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_set_text (GtkPathWidget *self,
|
||||
const char *text)
|
||||
{
|
||||
if (g_strcmp0 (self->text, text) == 0)
|
||||
return;
|
||||
|
||||
g_free (self->text);
|
||||
self->text = g_strdup (text);
|
||||
|
||||
gtk_path_widget_create_paths (self);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TEXT]);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_set_editable (GtkPathWidget *self,
|
||||
gboolean editable)
|
||||
{
|
||||
if (self->editable == editable)
|
||||
return;
|
||||
|
||||
self->editable = editable;
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_EDITABLE]);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
|
||||
{
|
||||
GtkPathWidget *self = GTK_PATH_WIDGET (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_TEXT:
|
||||
gtk_path_widget_set_text (self, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_EDITABLE:
|
||||
gtk_path_widget_set_editable (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkPathWidget *self = GTK_PATH_WIDGET (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_TEXT:
|
||||
g_value_set_string (value, self->text);
|
||||
break;
|
||||
|
||||
case PROP_EDITABLE:
|
||||
g_value_set_boolean (value, self->editable);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_dispose (GObject *object)
|
||||
{
|
||||
GtkPathWidget *self = GTK_PATH_WIDGET (object);
|
||||
|
||||
gtk_path_widget_clear_paths (self);
|
||||
|
||||
G_OBJECT_CLASS (gtk_path_widget_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_class_init (GtkPathWidgetClass *klass)
|
||||
{
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = gtk_path_widget_dispose;
|
||||
object_class->set_property = gtk_path_widget_set_property;
|
||||
object_class->get_property = gtk_path_widget_get_property;
|
||||
|
||||
widget_class->size_allocate = gtk_path_widget_allocate;
|
||||
widget_class->snapshot = gtk_path_widget_snapshot;
|
||||
|
||||
properties[PROP_TEXT] =
|
||||
g_param_spec_string ("text",
|
||||
"text",
|
||||
"Text transformed along a path",
|
||||
NULL,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
properties[PROP_EDITABLE] =
|
||||
g_param_spec_boolean ("editable",
|
||||
"editable",
|
||||
"If the path can be edited by the user",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_begin (GtkGestureDrag *gesture,
|
||||
double x,
|
||||
double y,
|
||||
GtkPathWidget *self)
|
||||
{
|
||||
graphene_point_t mouse = GRAPHENE_POINT_INIT (x, y);
|
||||
double width = gtk_widget_get_width (GTK_WIDGET (self));
|
||||
double height = gtk_widget_get_height (GTK_WIDGET (self));
|
||||
gsize i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (graphene_point_distance (&GRAPHENE_POINT_INIT (self->points[i].x * width, self->points[i].y * height), &mouse, NULL, NULL) <= POINT_SIZE)
|
||||
{
|
||||
self->active_point = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == 4)
|
||||
{
|
||||
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
drag_update (GtkGestureDrag *drag,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
GtkPathWidget *self)
|
||||
{
|
||||
double width = gtk_widget_get_width (GTK_WIDGET (self));
|
||||
double height = gtk_widget_get_height (GTK_WIDGET (self));
|
||||
double start_x, start_y;
|
||||
|
||||
gtk_gesture_drag_get_start_point (drag, &start_x, &start_y);
|
||||
|
||||
self->points[self->active_point] = GRAPHENE_POINT_INIT ((start_x + offset_x) / width,
|
||||
(start_y + offset_y) / height);
|
||||
self->points[self->active_point].x = CLAMP (self->points[self->active_point].x, 0, 1);
|
||||
self->points[self->active_point].y = CLAMP (self->points[self->active_point].y, 0, 1);
|
||||
|
||||
gtk_path_widget_create_paths (self);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_motion (GtkEventControllerMotion *controller,
|
||||
double x,
|
||||
double y,
|
||||
GtkPathWidget *self)
|
||||
{
|
||||
GskPathPoint *point;
|
||||
graphene_point_t pos;
|
||||
|
||||
point = gsk_path_measure_get_closest_point (self->line_measure,
|
||||
&GRAPHENE_POINT_INIT (x, y),
|
||||
INFINITY);
|
||||
gsk_path_point_get_position (point, &pos);
|
||||
self->line_closest = graphene_point_distance (&pos, &GRAPHENE_POINT_INIT (x, y), NULL, NULL);
|
||||
gsk_path_point_unref (point);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_leave (GtkEventControllerMotion *controller,
|
||||
GtkPathWidget *self)
|
||||
{
|
||||
self->line_closest = -1;
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_init (GtkPathWidget *self)
|
||||
{
|
||||
GtkEventController *controller;
|
||||
|
||||
controller = GTK_EVENT_CONTROLLER (gtk_gesture_drag_new ());
|
||||
g_signal_connect (controller, "drag-begin", G_CALLBACK (drag_begin), self);
|
||||
g_signal_connect (controller, "drag-update", G_CALLBACK (drag_update), self);
|
||||
g_signal_connect (controller, "drag-end", G_CALLBACK (drag_update), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), controller);
|
||||
|
||||
controller = GTK_EVENT_CONTROLLER (gtk_event_controller_motion_new ());
|
||||
g_signal_connect (controller, "enter", G_CALLBACK (pointer_motion), self);
|
||||
g_signal_connect (controller, "motion", G_CALLBACK (pointer_motion), self);
|
||||
g_signal_connect (controller, "leave", G_CALLBACK (pointer_leave), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), controller);
|
||||
|
||||
self->line_closest = -1;
|
||||
|
||||
self->points[0] = GRAPHENE_POINT_INIT (0.1, 0.9);
|
||||
self->points[1] = GRAPHENE_POINT_INIT (0.3, 0.1);
|
||||
self->points[2] = GRAPHENE_POINT_INIT (0.7, 0.1);
|
||||
self->points[3] = GRAPHENE_POINT_INIT (0.9, 0.9);
|
||||
|
||||
self->background = GDK_PAINTABLE (gdk_texture_new_from_resource ("/sliding_puzzle/portland-rose.jpg"));
|
||||
|
||||
gtk_path_widget_set_text (self, "It's almost working");
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gtk_path_widget_new (void)
|
||||
{
|
||||
GtkPathWidget *self;
|
||||
|
||||
self = g_object_new (GTK_TYPE_PATH_WIDGET, NULL);
|
||||
|
||||
return GTK_WIDGET (self);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_path_text (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkBuilder *builder;
|
||||
|
||||
g_type_ensure (GTK_TYPE_PATH_WIDGET);
|
||||
|
||||
builder = gtk_builder_new_from_resource ("/path_text/path_text.ui");
|
||||
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
gtk_widget_get_display (do_widget));
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
|
||||
g_object_unref (builder);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<object class="GtkWindow" id="window">
|
||||
<property name="title" translatable="yes">Text along a Path</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar">
|
||||
<child type="end">
|
||||
<object class="GtkToggleButton" id="edit-toggle">
|
||||
<property name="icon-name">document-edit-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkRevealer">
|
||||
<property name="reveal-child" bind-source="edit-toggle" bind-property="active" bind-flags="sync-create"></property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="text">
|
||||
<property name="text">Through the looking glass</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkPathWidget" id="view">
|
||||
<property name="editable" bind-source="edit-toggle" bind-property="active" bind-flags="sync-create"></property>
|
||||
<property name="text" bind-source="text" bind-property="text" bind-flags="sync-create"></property>
|
||||
<property name="hexpand">true</property>
|
||||
<property name="vexpand">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -189,7 +189,6 @@ do_pickers (GtkWidget *do_widget)
|
||||
gtk_grid_attach (GTK_GRID (table), label, 0, 0, 1, 1);
|
||||
|
||||
picker = gtk_color_dialog_button_new (gtk_color_dialog_new ());
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), picker);
|
||||
gtk_grid_attach (GTK_GRID (table), picker, 1, 0, 1, 1);
|
||||
|
||||
label = gtk_label_new ("Font:");
|
||||
@@ -199,7 +198,6 @@ do_pickers (GtkWidget *do_widget)
|
||||
gtk_grid_attach (GTK_GRID (table), label, 0, 1, 1, 1);
|
||||
|
||||
picker = gtk_font_dialog_button_new (gtk_font_dialog_new ());
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), picker);
|
||||
gtk_grid_attach (GTK_GRID (table), picker, 1, 1, 1, 1);
|
||||
|
||||
label = gtk_label_new ("File:");
|
||||
@@ -210,9 +208,6 @@ do_pickers (GtkWidget *do_widget)
|
||||
|
||||
picker = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
|
||||
button = gtk_button_new_from_icon_name ("document-open-symbolic");
|
||||
gtk_accessible_update_property (GTK_ACCESSIBLE (button),
|
||||
GTK_ACCESSIBLE_PROPERTY_LABEL, "Select File",
|
||||
-1);
|
||||
|
||||
label = gtk_label_new ("None");
|
||||
|
||||
@@ -228,9 +223,6 @@ do_pickers (GtkWidget *do_widget)
|
||||
gtk_box_append (GTK_BOX (picker), button);
|
||||
app_picker = gtk_button_new_from_icon_name ("emblem-system-symbolic");
|
||||
gtk_widget_set_halign (app_picker, GTK_ALIGN_END);
|
||||
gtk_accessible_update_property (GTK_ACCESSIBLE (app_picker),
|
||||
GTK_ACCESSIBLE_PROPERTY_LABEL, "Open File",
|
||||
-1);
|
||||
gtk_widget_set_sensitive (app_picker, FALSE);
|
||||
g_signal_connect (app_picker, "clicked", G_CALLBACK (open_app), NULL);
|
||||
gtk_box_append (GTK_BOX (picker), app_picker);
|
||||
@@ -249,7 +241,7 @@ do_pickers (GtkWidget *do_widget)
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
gtk_widget_set_visible (window, TRUE);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -150,36 +150,20 @@ do_video_player (GtkWidget *do_widget)
|
||||
|
||||
button = gtk_button_new ();
|
||||
image = gtk_image_new_from_resource ("/cursors/images/gtk_logo_cursor.png");
|
||||
gtk_accessible_update_relation (GTK_ACCESSIBLE (image),
|
||||
GTK_ACCESSIBLE_RELATION_LABELLED_BY, button, NULL,
|
||||
-1);
|
||||
gtk_image_set_pixel_size (GTK_IMAGE (image), 24);
|
||||
gtk_button_set_child (GTK_BUTTON (button), image);
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (logo_clicked_cb), video);
|
||||
gtk_accessible_update_property (GTK_ACCESSIBLE (button),
|
||||
GTK_ACCESSIBLE_PROPERTY_LABEL, "GTK Logo",
|
||||
-1);
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (title), button);
|
||||
|
||||
button = gtk_button_new ();
|
||||
image = gtk_image_new_from_resource ("/video-player/bbb.png");
|
||||
gtk_accessible_update_relation (GTK_ACCESSIBLE (image),
|
||||
GTK_ACCESSIBLE_RELATION_LABELLED_BY, button, NULL,
|
||||
-1);
|
||||
gtk_image_set_pixel_size (GTK_IMAGE (image), 24);
|
||||
gtk_button_set_child (GTK_BUTTON (button), image);
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (bbb_clicked_cb), video);
|
||||
gtk_accessible_update_property (GTK_ACCESSIBLE (button),
|
||||
GTK_ACCESSIBLE_PROPERTY_LABEL, "Big Buck Bunny",
|
||||
-1);
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (title), button);
|
||||
|
||||
fullscreen_button = gtk_button_new_from_icon_name ("view-fullscreen-symbolic");
|
||||
g_signal_connect (fullscreen_button, "clicked", G_CALLBACK (fullscreen_clicked_cb), NULL);
|
||||
gtk_accessible_update_property (GTK_ACCESSIBLE (fullscreen_button),
|
||||
GTK_ACCESSIBLE_PROPERTY_LABEL, "Fullscreen",
|
||||
-1);
|
||||
|
||||
gtk_header_bar_pack_end (GTK_HEADER_BAR (title), fullscreen_button);
|
||||
|
||||
controller = gtk_shortcut_controller_new ();
|
||||
|
||||
@@ -23,7 +23,7 @@ When it comes to rendering, GTK follows the CSS box model as far as practical.
|
||||
|
||||
The CSS stylesheet that is in use determines the sizes (and appearance) of the
|
||||
margin, border and padding areas for each widget. The size of the content area
|
||||
is determined by GTKs layout algorithm using each widget’s [vfunc@Gtk.Widget.measure]
|
||||
is determined by GTKs layout algorithm using each widgets [vfunc@Gtk.Widget.measure]
|
||||
and [vfunc@Gtk.Widget.size_allocate] vfuncs.
|
||||
|
||||
You can learn more about the CSS box model by reading the
|
||||
@@ -37,11 +37,11 @@ To learn more about where GTK CSS differs from CSS on the web, see the
|
||||
|
||||
The content area in the CSS box model is the region that the widget considers its own.
|
||||
|
||||
The origin of the widget’s coordinate system is the top left corner of the content area,
|
||||
and its size is the widget’s size. The size can be queried with [method@Gtk.Widget.get_width]
|
||||
The origin of the widgets coordinate system is the top left corner of the content area,
|
||||
and its size is the widgets size. The size can be queried with [method@Gtk.Widget.get_width]
|
||||
and [method@Gtk.Widget.get_height]. GTK allows general 3D transformations to position
|
||||
widgets (although most of the time, the transformation will be a simple 2D translation).
|
||||
The transform to go from one widget’s coordinate system to another one can be obtained
|
||||
The transform to go from one widgets coordinate system to another one can be obtained
|
||||
with [method@Gtk.Widget.compute_transform].
|
||||
|
||||
In addition to a size, widgets can optionally have a **_baseline_** to position text on.
|
||||
@@ -55,8 +55,8 @@ or [method@Gtk.Widget.compute_bounds]. These methods can fail (either because th
|
||||
don't share a common ancestor, or because of a singular transformation), and callers need
|
||||
to handle this eventuality.
|
||||
|
||||
Another area that is occasionally relevant are the widget’s **_bounds_**, which is the area
|
||||
that a widget’s rendering is typically confined to (technically, widgets can draw outside
|
||||
Another area that is occasionally relevant are the widgets **_bounds_**, which is the area
|
||||
that a widgets rendering is typically confined to (technically, widgets can draw outside
|
||||
of this area, unless clipping is enforced via the [property@Gtk.Widget:overflow] property).
|
||||
In CSS terms, the bounds of a widget correspond to the border area.
|
||||
|
||||
|
||||
@@ -1,207 +0,0 @@
|
||||
.. _gtk4-path-tool(1):
|
||||
|
||||
=================
|
||||
gtk4-path-tool
|
||||
=================
|
||||
|
||||
-----------------------
|
||||
GskPath Utility
|
||||
-----------------------
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
| **gtk4-path-tool** <COMMAND> [OPTIONS...] <PATH>
|
||||
|
|
||||
| **gtk4-path-tool** stroke [OPTIONS...] <PATH>
|
||||
| **gtk4-path-tool** offset [OPTIONS...] <PATH>
|
||||
| **gtk4-path-tool** simplify [OPTIONS...] <PATH>
|
||||
| **gtk4-path-tool** intersection [OPTIONS...] <PATH> <PATH>
|
||||
| **gtk4-path-tool** union [OPTIONS...] <PATH> <PATH>
|
||||
| **gtk4-path-tool** difference [OPTIONS...] <PATH> <PATH>
|
||||
| **gtk4-path-tool** symmetric-difference [OPTIONS...] <PATH> <PATH>
|
||||
| **gtk4-path-tool** decompose [OPTIONS...] <PATH>
|
||||
| **gtk4-path-tool** restrict [OPTIONS...] <PATH>
|
||||
| **gtk4-path-tool** show [OPTIONS...] <PATH>
|
||||
| **gtk4-path-tool** render [OPTIONS...] <PATH>
|
||||
| **gtk4-path-tool** info [OPTIONS...] <PATH>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
``gtk4-path-tool`` can perform various tasks on paths. Paths are specified
|
||||
in SVG syntax, as strings like "M 100 100 C 100 200 200 200 200 100 Z".
|
||||
|
||||
To read a path from a file, use a filename that starts with a '.' or a '/'.
|
||||
To read a path from stdin, use '-'.
|
||||
|
||||
COMMANDS
|
||||
--------
|
||||
|
||||
Stroking
|
||||
^^^^^^^^
|
||||
|
||||
The ``stroke`` command performs a stroke operation along the path according to
|
||||
the parameters specified via options.
|
||||
|
||||
``--line-width=VALUE``
|
||||
|
||||
The line width to use for the stroke. ``VALUE`` must be a positive number.
|
||||
The default line width is 1.
|
||||
|
||||
``--line-cap=VALUE``
|
||||
|
||||
The cap style to use at line ends. The possible values are ``butt``, ``round``
|
||||
or ``square``. See the SVG specification for details on these styles.
|
||||
The default cap style is ``butt``.
|
||||
|
||||
``--line-join=VALUE``
|
||||
|
||||
The join style to use at line joins. The possible values are ``miter``,
|
||||
``miter-clip``, ``round``, ``bevel`` or ``arcs``. See the SVG specification
|
||||
for details on these styles.
|
||||
The default join style is ``miter``.
|
||||
|
||||
``--miter-limit=VALUE``
|
||||
|
||||
The limit at which to clip miters at line joins. The default value is 4.
|
||||
|
||||
``--dashes=VALUE``
|
||||
|
||||
The dash pattern to use for this stroke. A dash pattern is specified by
|
||||
a comma-separated list of alternating non-negative numbers. Each number
|
||||
provides the length of alternate "on" and "off" portions of the stroke.
|
||||
If the dash pattern is empty, dashing is disabled, which is the default.
|
||||
See the SVG specification for details on dashing.
|
||||
|
||||
``--dash-offset=VALUE``
|
||||
|
||||
The offset into the dash pattern where dashing should begin.
|
||||
The default value is 0.
|
||||
|
||||
Offsetting
|
||||
^^^^^^^^^^
|
||||
|
||||
The ``offset`` command applies a lateral offset to the path. Note that this
|
||||
is different from applying a translation transformation.
|
||||
|
||||
``--distance=VALUE``
|
||||
|
||||
The distance by which to offset the path. Positive values offset to the right,
|
||||
negative values to the left (wrt to the direction of the path). The default
|
||||
value is 0.
|
||||
|
||||
``--line-join=VALUE``
|
||||
|
||||
The join style to use at line joins. The possible values are ``miter``,
|
||||
``miter-clip``, ``round``, ``bevel`` or ``arcs``. See the SVG specification
|
||||
for details on these styles.
|
||||
The default join style is ``miter``.
|
||||
|
||||
``--miter-limit=VALUE``
|
||||
|
||||
The limit at which to clip miters at line joins. The default value is 4.
|
||||
|
||||
Boolean Operations
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The ``intersection``, ``union``, ``difference`` and ``symmetric-difference`` commands
|
||||
perform boolean operations on paths. Given two paths, they create a new path which
|
||||
encircles the area that is the intersection, union, difference or symmetric difference
|
||||
of the areas encircled by the paths.
|
||||
|
||||
Simplification
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
The ``simplify`` command removes areas of overlap from a path such that the resulting
|
||||
path encircles the same area, but every edge in the resulting path is a boundary between
|
||||
the inside and the outside.
|
||||
|
||||
Decomposing
|
||||
^^^^^^^^^^^
|
||||
|
||||
The ``decompose`` command approximates the path by one with simpler elements.
|
||||
When used without options, the curves of the path are approximated by line
|
||||
segments.
|
||||
|
||||
``--allow-curves``
|
||||
|
||||
Allow cubic Bézier curves to be used in the generated path.
|
||||
|
||||
``--allow-conics``
|
||||
|
||||
Allow rational quadratic Bézier curves to be used in the generated path.
|
||||
|
||||
Restricting
|
||||
^^^^^^^^^^^
|
||||
|
||||
The ``restrict`` command creates a path that traces a segment of the original
|
||||
path. Note that the start and the end of the segment are specified as
|
||||
path length from the beginning of the path.
|
||||
|
||||
``--start=LENGTH``
|
||||
|
||||
The distance from the beginning of the path where the segment begins. The
|
||||
default values is 0.
|
||||
|
||||
``--end=LENGTH``
|
||||
|
||||
The distance from the beginning of the path where the segment ends. The
|
||||
default value is the length of path.
|
||||
|
||||
Showing
|
||||
^^^^^^^
|
||||
|
||||
The ``show`` command displays the given path in a window. The interior
|
||||
of the path is filled.
|
||||
|
||||
``--fill-rule=VALUE``
|
||||
|
||||
The fill rule that is used to determine what areas are inside the path.
|
||||
The possible values are ``winding`` or ``even-odd``. The default is ``winding``.
|
||||
|
||||
``--fg-color=COLOR``
|
||||
|
||||
The color that is used to fill the interior of the path.
|
||||
If not specified, black is used.
|
||||
|
||||
``--bg-color=COLOR``
|
||||
|
||||
The color that is used to render the background behind the path.
|
||||
If not specified, white is used.
|
||||
|
||||
Rendering
|
||||
^^^^^^^^^
|
||||
|
||||
The ``render`` command renders the given path as a PNG image.
|
||||
The interior of the path is filled.
|
||||
|
||||
``--fill-rule=VALUE``
|
||||
|
||||
The fill rule that is used to determine what areas are inside the path.
|
||||
The possible values are ``winding`` or ``even-odd``. The default is ``winding``.
|
||||
|
||||
``--fg-color=COLOR``
|
||||
|
||||
The color that is used to fill the interior of the path.
|
||||
If not specified, black is used.
|
||||
|
||||
``--bg-color=COLOR``
|
||||
|
||||
The color that is used to render the background behind the path.
|
||||
If not specified, white is used.
|
||||
|
||||
``--output-file=FILE``
|
||||
|
||||
The file to save the PNG image to.
|
||||
If not specified, "path.png" is used.
|
||||
|
||||
Info
|
||||
^^^^
|
||||
|
||||
The ``info`` command shows various information about the given path,
|
||||
such as the number of contours, its bounding box and and its length.
|
||||
|
||||
REFERENCES
|
||||
----------
|
||||
|
||||
- SVG Path Specification, https://www.w3.org/TR/SVG2/paths.html
|
||||
@@ -76,7 +76,6 @@ if get_option('man-pages') and rst2man.found()
|
||||
[ 'gtk4-launch', '1', ],
|
||||
[ 'gtk4-query-settings', '1', ],
|
||||
[ 'gtk4-update-icon-cache', '1', ],
|
||||
[ 'gtk4-path-tool', '1', ],
|
||||
]
|
||||
|
||||
if get_option('demos')
|
||||
|
||||
@@ -208,9 +208,6 @@ A number of options affect behavior instead of logging:
|
||||
`nograbs`
|
||||
: Turn off all pointer and keyboard grabs
|
||||
|
||||
`portals`
|
||||
: Force the use of [portals](https://docs.flatpak.org/en/latest/portals.html)
|
||||
|
||||
`gl-disable`
|
||||
: Disable OpenGL support
|
||||
|
||||
|
||||
@@ -204,17 +204,19 @@ you should ensure that:
|
||||
readable and localised action performed when pressed; for instance "Copy",
|
||||
"Paste", "Add layer", or "Remove"
|
||||
|
||||
GTK will try to fill in some information by using ancillary UI control properties,
|
||||
for instance the accessible name will be taken from the label used by the UI control,
|
||||
or from its tooltip, if the `GTK_ACCESSIBLE_PROPERTY_LABEL` property or the
|
||||
`GTK_ACCESSIBLE_RELATION_LABELLED_BY` relation are unset. Similary for the accessible
|
||||
description. Nevertheless, it is good practice and project hygiene to explicitly specify
|
||||
the accessible properties, just like it's good practice to specify tooltips and style classes.
|
||||
GTK will try to fill in some information by using ancillary UI control
|
||||
properties, for instance the accessible label will be taken from the label or
|
||||
placeholder text used by the UI control, or from its tooltip, if the
|
||||
`GTK_ACCESSIBLE_PROPERTY_LABEL` property or the `GTK_ACCESSIBLE_RELATION_LABELLED_BY`
|
||||
relation are unset. Nevertheless, it is good practice and project hygiene
|
||||
to explicitly specify the accessible properties, just like it's good practice
|
||||
to specify tooltips and style classes.
|
||||
|
||||
Application developers using GTK **should** ensure that their UI controls
|
||||
are accessible as part of the development process. The GTK Inspector shows
|
||||
the accessible attributes of each widget, and also provides an overlay that
|
||||
can highlight accessibility issues.
|
||||
are accessible as part of the development process. When using `GtkBuilder`
|
||||
templates and UI definition files, GTK provides a validation tool that
|
||||
verifies that each UI element has a valid role and properties; this tool can
|
||||
be used as part of the application's test suite to avoid regressions.
|
||||
|
||||
## Implementations
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ gdk_broadway_cairo_context_dispose (GObject *object)
|
||||
|
||||
static void
|
||||
gdk_broadway_cairo_context_begin_frame (GdkDrawContext *draw_context,
|
||||
GdkMemoryDepth depth,
|
||||
gboolean prefers_high_depth,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
GdkBroadwayCairoContext *self = GDK_BROADWAY_CAIRO_CONTEXT (draw_context);
|
||||
|
||||
@@ -34,7 +34,7 @@ gdk_broadway_draw_context_dispose (GObject *object)
|
||||
|
||||
static void
|
||||
gdk_broadway_draw_context_begin_frame (GdkDrawContext *draw_context,
|
||||
GdkMemoryDepth depth,
|
||||
gboolean prefers_high_depth,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
GdkBroadwayDrawContext *self = GDK_BROADWAY_DRAW_CONTEXT (draw_context);
|
||||
|
||||
@@ -645,9 +645,6 @@ gdk_content_formats_builder_clear (GdkContentFormatsBuilder *builder)
|
||||
{
|
||||
g_clear_pointer (&builder->gtypes, g_slist_free);
|
||||
g_clear_pointer (&builder->mime_types, g_slist_free);
|
||||
|
||||
builder->n_gtypes = 0;
|
||||
builder->n_mime_types = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
#include "gdkglcontextprivate.h"
|
||||
#include "gdkmonitorprivate.h"
|
||||
#include "gdkrectangle.h"
|
||||
#include "gdkvulkancontext.h"
|
||||
|
||||
#ifdef HAVE_EGL
|
||||
#include <epoxy/egl.h>
|
||||
@@ -384,9 +383,6 @@ gdk_display_dispose (GObject *object)
|
||||
#endif
|
||||
g_clear_error (&priv->gl_error);
|
||||
|
||||
for (GList *l = display->seats; l; l = l->next)
|
||||
g_object_run_dispose (G_OBJECT (l->data));
|
||||
|
||||
G_OBJECT_CLASS (gdk_display_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
@@ -1217,49 +1213,6 @@ gdk_display_get_keymap (GdkDisplay *display)
|
||||
return GDK_DISPLAY_GET_CLASS (display)->get_keymap (display);
|
||||
}
|
||||
|
||||
/*<private>
|
||||
* gdk_display_create_vulkan_context:
|
||||
* @self: a `GdkDisplay`
|
||||
* @error: return location for an error
|
||||
*
|
||||
* Creates a new `GdkVulkanContext` for use with @display.
|
||||
*
|
||||
* The context can not be used to draw to surfaces, it can only be
|
||||
* used for custom rendering or compute.
|
||||
*
|
||||
* If the creation of the `GdkVulkanContext` failed, @error will be set.
|
||||
*
|
||||
* Returns: (transfer full): the newly created `GdkVulkanContext`, or
|
||||
* %NULL on error
|
||||
*/
|
||||
GdkVulkanContext *
|
||||
gdk_display_create_vulkan_context (GdkDisplay *self,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DISPLAY (self), NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
if (gdk_display_get_debug_flags (self) & GDK_DEBUG_VULKAN_DISABLE)
|
||||
{
|
||||
g_set_error_literal (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_NOT_AVAILABLE,
|
||||
_("Vulkan support disabled via GDK_DEBUG"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (GDK_DISPLAY_GET_CLASS (self)->vk_extension_name == NULL)
|
||||
{
|
||||
g_set_error (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_UNSUPPORTED,
|
||||
"The %s backend has no Vulkan support.", G_OBJECT_TYPE_NAME (self));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return g_initable_new (GDK_DISPLAY_GET_CLASS (self)->vk_context_type,
|
||||
NULL,
|
||||
error,
|
||||
"display", self,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_display_init_gl (GdkDisplay *self)
|
||||
{
|
||||
|
||||
@@ -202,9 +202,6 @@ gulong _gdk_display_get_next_serial (GdkDisplay *display
|
||||
void _gdk_display_pause_events (GdkDisplay *display);
|
||||
void _gdk_display_unpause_events (GdkDisplay *display);
|
||||
|
||||
GdkVulkanContext * gdk_display_create_vulkan_context (GdkDisplay *self,
|
||||
GError **error);
|
||||
|
||||
GdkGLContext * gdk_display_get_gl_context (GdkDisplay *display);
|
||||
|
||||
gboolean gdk_display_init_egl (GdkDisplay *display,
|
||||
|
||||
@@ -311,20 +311,19 @@ gdk_draw_context_begin_frame (GdkDrawContext *context,
|
||||
g_return_if_fail (priv->surface != NULL);
|
||||
g_return_if_fail (region != NULL);
|
||||
|
||||
gdk_draw_context_begin_frame_full (context, GDK_MEMORY_U8, region);
|
||||
gdk_draw_context_begin_frame_full (context, FALSE, region);
|
||||
}
|
||||
|
||||
/*
|
||||
* @depth: best depth to render in
|
||||
* @prefers_high_depth: %TRUE to request a higher bit depth
|
||||
*
|
||||
* If the given depth is not `GDK_MEMORY_U8`, GDK will see about providing a
|
||||
* rendering target that supports a higher bit depth than 8 bits per channel.
|
||||
* Typically this means a target supporting 16bit floating point pixels, but
|
||||
* that is not guaranteed.
|
||||
* If high depth is preferred, GDK will see about providing a rendering target
|
||||
* that supports higher bit depth than 8 bits per channel. Typically this means
|
||||
* a target supporting 16bit floating point pixels, but that is not guaranteed.
|
||||
*
|
||||
* This is only a request and if the GDK backend does not support HDR rendering
|
||||
* or does not consider it worthwhile, it may choose to not honor the request.
|
||||
* It may also choose to provide a differnet depth even if it was not requested.
|
||||
* It may also choose to provide high depth even if it was not requested.
|
||||
* Typically the steps undertaken by a backend are:
|
||||
* 1. Check if high depth is supported by this drawing backend.
|
||||
* 2. Check if the compositor supports high depth.
|
||||
@@ -334,12 +333,12 @@ gdk_draw_context_begin_frame (GdkDrawContext *context,
|
||||
* In either of those cases, the context will usually choose to not honor the request.
|
||||
*
|
||||
* The rendering code must be able to deal with content in any bit depth, no matter
|
||||
* the preference. The depth argument is only a hint and GDK is free
|
||||
* the preference. The prefers_high_depth argument is only a hint and GDK is free
|
||||
* to choose.
|
||||
*/
|
||||
void
|
||||
gdk_draw_context_begin_frame_full (GdkDrawContext *context,
|
||||
GdkMemoryDepth depth,
|
||||
gboolean prefers_high_depth,
|
||||
const cairo_region_t *region)
|
||||
{
|
||||
GdkDrawContextPrivate *priv = gdk_draw_context_get_instance_private (context);
|
||||
@@ -366,12 +365,12 @@ gdk_draw_context_begin_frame_full (GdkDrawContext *context,
|
||||
}
|
||||
|
||||
if (gdk_display_get_debug_flags (priv->display) & GDK_DEBUG_HIGH_DEPTH)
|
||||
depth = GDK_MEMORY_FLOAT32;
|
||||
prefers_high_depth = TRUE;
|
||||
|
||||
priv->frame_region = cairo_region_copy (region);
|
||||
priv->surface->paint_context = g_object_ref (context);
|
||||
|
||||
GDK_DRAW_CONTEXT_GET_CLASS (context)->begin_frame (context, depth, priv->frame_region);
|
||||
GDK_DRAW_CONTEXT_GET_CLASS (context)->begin_frame (context, prefers_high_depth, priv->frame_region);
|
||||
|
||||
cairo_region_intersect_rectangle (priv->frame_region,
|
||||
&(cairo_rectangle_int_t) {
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
|
||||
#include "gdkdrawcontext.h"
|
||||
|
||||
#include "gdkmemoryformatprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDK_DRAW_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_DRAW_CONTEXT, GdkDrawContextClass))
|
||||
@@ -42,7 +40,7 @@ struct _GdkDrawContextClass
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (* begin_frame) (GdkDrawContext *context,
|
||||
GdkMemoryDepth depth,
|
||||
gboolean prefers_high_depth,
|
||||
cairo_region_t *update_area);
|
||||
void (* end_frame) (GdkDrawContext *context,
|
||||
cairo_region_t *painted);
|
||||
@@ -52,7 +50,7 @@ struct _GdkDrawContextClass
|
||||
void gdk_draw_context_surface_resized (GdkDrawContext *context);
|
||||
|
||||
void gdk_draw_context_begin_frame_full (GdkDrawContext *context,
|
||||
GdkMemoryDepth depth,
|
||||
gboolean prefers_high_depth,
|
||||
const cairo_region_t *region);
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -173,8 +173,12 @@ static GPrivate thread_current_context = G_PRIVATE_INIT (unref_unmasked);
|
||||
static void
|
||||
gdk_gl_context_clear_old_updated_area (GdkGLContext *context)
|
||||
{
|
||||
for (unsigned int i = 0; i < GDK_GL_MAX_TRACKED_BUFFERS; i++)
|
||||
g_clear_pointer (&context->old_updated_area[i], cairo_region_destroy);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
g_clear_pointer (&context->old_updated_area[i], cairo_region_destroy);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -581,7 +585,7 @@ gdk_gl_context_get_scale (GdkGLContext *self)
|
||||
|
||||
static void
|
||||
gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context,
|
||||
GdkMemoryDepth depth,
|
||||
gboolean prefers_high_depth,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
|
||||
@@ -597,7 +601,7 @@ gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context,
|
||||
|
||||
#ifdef HAVE_EGL
|
||||
if (priv->egl_context)
|
||||
gdk_surface_ensure_egl_surface (surface, depth != GDK_MEMORY_U8);
|
||||
gdk_surface_ensure_egl_surface (surface, prefers_high_depth);
|
||||
#endif
|
||||
|
||||
damage = GDK_GL_CONTEXT_GET_CLASS (context)->get_damage (context);
|
||||
|
||||
@@ -258,7 +258,7 @@ struct _GdkMemoryFormatDescription
|
||||
GdkMemoryAlpha alpha;
|
||||
gsize bytes_per_pixel;
|
||||
gsize alignment;
|
||||
GdkMemoryDepth depth;
|
||||
gboolean prefers_high_depth;
|
||||
struct {
|
||||
guint gl_major;
|
||||
guint gl_minor;
|
||||
@@ -289,7 +289,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
||||
4,
|
||||
G_ALIGNOF (guchar),
|
||||
GDK_MEMORY_U8,
|
||||
FALSE,
|
||||
{ 0, 0, G_MAXUINT, G_MAXUINT },
|
||||
{ GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
||||
b8g8r8a8_premultiplied_to_float,
|
||||
@@ -299,7 +299,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
||||
4,
|
||||
G_ALIGNOF (guchar),
|
||||
GDK_MEMORY_U8,
|
||||
FALSE,
|
||||
{ 0, 0, G_MAXUINT, G_MAXUINT },
|
||||
{ GL_RGBA8, GL_BGRA, GDK_GL_UNSIGNED_BYTE_FLIPPED, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
||||
a8r8g8b8_premultiplied_to_float,
|
||||
@@ -309,7 +309,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
||||
4,
|
||||
G_ALIGNOF (guchar),
|
||||
GDK_MEMORY_U8,
|
||||
FALSE,
|
||||
{ 0, 0, 0, 0 },
|
||||
{ GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
||||
r8g8b8a8_premultiplied_to_float,
|
||||
@@ -319,7 +319,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
4,
|
||||
G_ALIGNOF (guchar),
|
||||
GDK_MEMORY_U8,
|
||||
FALSE,
|
||||
{ 0, 0, G_MAXUINT, G_MAXUINT },
|
||||
{ GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
||||
b8g8r8a8_to_float,
|
||||
@@ -329,7 +329,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
4,
|
||||
G_ALIGNOF (guchar),
|
||||
GDK_MEMORY_U8,
|
||||
FALSE,
|
||||
{ 0, 0, G_MAXUINT, G_MAXUINT },
|
||||
{ GL_RGBA8, GL_RGBA, GDK_GL_UNSIGNED_BYTE_FLIPPED, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
||||
a8r8g8b8_to_float,
|
||||
@@ -339,7 +339,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
4,
|
||||
G_ALIGNOF (guchar),
|
||||
GDK_MEMORY_U8,
|
||||
FALSE,
|
||||
{ 0, 0, 0, 0 },
|
||||
{ GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
||||
r8g8b8a8_to_float,
|
||||
@@ -349,7 +349,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
4,
|
||||
G_ALIGNOF (guchar),
|
||||
GDK_MEMORY_U8,
|
||||
FALSE,
|
||||
{ 0, 0, G_MAXUINT, G_MAXUINT },
|
||||
{ GL_RGBA8, GL_BGRA, GDK_GL_UNSIGNED_BYTE_FLIPPED, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
||||
a8b8g8r8_to_float,
|
||||
@@ -359,7 +359,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_OPAQUE,
|
||||
3,
|
||||
G_ALIGNOF (guchar),
|
||||
GDK_MEMORY_U8,
|
||||
FALSE,
|
||||
{ 0, 0, 0, 0 },
|
||||
{ GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, { GL_RED, GL_GREEN, GL_BLUE, GL_ONE } },
|
||||
r8g8b8_to_float,
|
||||
@@ -369,7 +369,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_OPAQUE,
|
||||
3,
|
||||
G_ALIGNOF (guchar),
|
||||
GDK_MEMORY_U8,
|
||||
FALSE,
|
||||
{ 0, 0, G_MAXUINT, G_MAXUINT },
|
||||
{ GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE, { GL_RED, GL_GREEN, GL_BLUE, GL_ONE } },
|
||||
b8g8r8_to_float,
|
||||
@@ -379,7 +379,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_OPAQUE,
|
||||
6,
|
||||
G_ALIGNOF (guint16),
|
||||
GDK_MEMORY_U16,
|
||||
TRUE,
|
||||
{ 0, 0, 3, 0 },
|
||||
{ GL_RGB16, GL_RGB, GL_UNSIGNED_SHORT, { GL_RED, GL_GREEN, GL_BLUE, GL_ONE } },
|
||||
r16g16b16_to_float,
|
||||
@@ -389,7 +389,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
||||
8,
|
||||
G_ALIGNOF (guint16),
|
||||
GDK_MEMORY_U16,
|
||||
TRUE,
|
||||
{ 0, 0, 3, 0 },
|
||||
{ GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
||||
r16g16b16a16_to_float,
|
||||
@@ -399,7 +399,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
8,
|
||||
G_ALIGNOF (guint16),
|
||||
GDK_MEMORY_U16,
|
||||
TRUE,
|
||||
{ 0, 0, 3, 0 },
|
||||
{ GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
||||
r16g16b16a16_to_float,
|
||||
@@ -409,7 +409,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_OPAQUE,
|
||||
6,
|
||||
G_ALIGNOF (guint16),
|
||||
GDK_MEMORY_FLOAT16,
|
||||
TRUE,
|
||||
{ 0, 0, 3, 0 },
|
||||
{ GL_RGB16F, GL_RGB, GL_HALF_FLOAT, { GL_RED, GL_GREEN, GL_BLUE, GL_ONE } },
|
||||
r16g16b16_float_to_float,
|
||||
@@ -419,7 +419,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
||||
8,
|
||||
G_ALIGNOF (guint16),
|
||||
GDK_MEMORY_FLOAT16,
|
||||
TRUE,
|
||||
{ 0, 0, 3, 0 },
|
||||
{ GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
||||
r16g16b16a16_float_to_float,
|
||||
@@ -429,7 +429,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
8,
|
||||
G_ALIGNOF (guint16),
|
||||
GDK_MEMORY_FLOAT16,
|
||||
TRUE,
|
||||
{ 0, 0, 3, 0 },
|
||||
{ GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
||||
r16g16b16a16_float_to_float,
|
||||
@@ -439,7 +439,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_OPAQUE,
|
||||
12,
|
||||
G_ALIGNOF (float),
|
||||
GDK_MEMORY_FLOAT32,
|
||||
TRUE,
|
||||
{ 0, 0, 3, 0 },
|
||||
{ GL_RGB32F, GL_RGB, GL_FLOAT, { GL_RED, GL_GREEN, GL_BLUE, GL_ONE } },
|
||||
r32g32b32_float_to_float,
|
||||
@@ -459,7 +459,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
16,
|
||||
G_ALIGNOF (float),
|
||||
GDK_MEMORY_FLOAT32,
|
||||
TRUE,
|
||||
{ 0, 0, 3, 0 },
|
||||
{ GL_RGBA32F, GL_RGBA, GL_FLOAT, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
||||
r32g32b32a32_float_to_float,
|
||||
@@ -469,7 +469,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
||||
2,
|
||||
G_ALIGNOF (guchar),
|
||||
GDK_MEMORY_U8,
|
||||
FALSE,
|
||||
{ 0, 0, 3, 0 },
|
||||
{ GL_RG8, GL_RG, GL_UNSIGNED_BYTE, { GL_RED, GL_RED, GL_RED, GL_GREEN } },
|
||||
g8a8_premultiplied_to_float,
|
||||
@@ -479,7 +479,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
2,
|
||||
G_ALIGNOF (guchar),
|
||||
GDK_MEMORY_U8,
|
||||
FALSE,
|
||||
{ 0, 0, 3, 0 },
|
||||
{ GL_RG8, GL_RG, GL_UNSIGNED_BYTE, { GL_RED, GL_RED, GL_RED, GL_GREEN } },
|
||||
g8a8_to_float,
|
||||
@@ -489,7 +489,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_OPAQUE,
|
||||
1,
|
||||
G_ALIGNOF (guchar),
|
||||
GDK_MEMORY_U8,
|
||||
FALSE,
|
||||
{ 0, 0, 3, 0 },
|
||||
{ GL_R8, GL_RED, GL_UNSIGNED_BYTE, { GL_RED, GL_RED, GL_RED, GL_ONE } },
|
||||
g8_to_float,
|
||||
@@ -499,7 +499,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
||||
4,
|
||||
G_ALIGNOF (guint16),
|
||||
GDK_MEMORY_U16,
|
||||
TRUE,
|
||||
{ 0, 0, 3, 0 },
|
||||
{ GL_RG16, GL_RG, GL_UNSIGNED_SHORT, { GL_RED, GL_RED, GL_RED, GL_GREEN } },
|
||||
g16a16_premultiplied_to_float,
|
||||
@@ -509,7 +509,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
4,
|
||||
G_ALIGNOF (guint16),
|
||||
GDK_MEMORY_U16,
|
||||
TRUE,
|
||||
{ 0, 0, 3, 0 },
|
||||
{ GL_RG16, GL_RG, GL_UNSIGNED_SHORT, { GL_RED, GL_RED, GL_RED, GL_GREEN } },
|
||||
g16a16_to_float,
|
||||
@@ -519,7 +519,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_OPAQUE,
|
||||
2,
|
||||
G_ALIGNOF (guint16),
|
||||
GDK_MEMORY_U16,
|
||||
TRUE,
|
||||
{ 0, 0, 3, 0 },
|
||||
{ GL_R16, GL_RED, GL_UNSIGNED_SHORT, { GL_RED, GL_RED, GL_RED, GL_ONE } },
|
||||
g16_to_float,
|
||||
@@ -529,7 +529,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
1,
|
||||
G_ALIGNOF (guchar),
|
||||
GDK_MEMORY_U8,
|
||||
FALSE,
|
||||
{ 0, 0, 3, 0 },
|
||||
{ GL_R8, GL_RED, GL_UNSIGNED_BYTE, { GL_ONE, GL_ONE, GL_ONE, GL_RED } },
|
||||
a8_to_float,
|
||||
@@ -539,7 +539,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
2,
|
||||
G_ALIGNOF (guint16),
|
||||
GDK_MEMORY_U16,
|
||||
TRUE,
|
||||
{ 0, 0, 3, 0 },
|
||||
{ GL_R16, GL_RED, GL_UNSIGNED_SHORT, { GL_ONE, GL_ONE, GL_ONE, GL_RED } },
|
||||
a16_to_float,
|
||||
@@ -566,57 +566,23 @@ gdk_memory_format_alignment (GdkMemoryFormat format)
|
||||
}
|
||||
|
||||
/*<private>
|
||||
* gdk_memory_format_get_depth:
|
||||
* gdk_memory_format_prefers_high_depth:
|
||||
* @format: a memory format
|
||||
*
|
||||
* Gets the depth of the individual channels of the format.
|
||||
* See gsk_render_node_prefers_high_depth() for more
|
||||
* information on this.
|
||||
* Checks if the given format benefits from being rendered
|
||||
* in bit depths higher than 8bits per pixel. See
|
||||
* gsk_render_node_prefers_high_depth() for more information
|
||||
* on this.
|
||||
* Usually this is the case when
|
||||
* gdk_memory_format_bytes_per_pixel() is larger than 4.
|
||||
*
|
||||
* Usually renderers want to use higher depth for render
|
||||
* targets to match these formats.
|
||||
*
|
||||
* Returns: The depth of this format
|
||||
* Returns: %TRUE if the format benefits from being
|
||||
* composited in hgiher bit depths.
|
||||
**/
|
||||
GdkMemoryDepth
|
||||
gdk_memory_format_get_depth (GdkMemoryFormat format)
|
||||
gboolean
|
||||
gdk_memory_format_prefers_high_depth (GdkMemoryFormat format)
|
||||
{
|
||||
return memory_formats[format].depth;
|
||||
}
|
||||
|
||||
/*<private>
|
||||
* gdk_memory_depth_merge:
|
||||
* @depth1: the first depth
|
||||
* @depth2: the second depth
|
||||
*
|
||||
* Returns a depth that can accomodate both given depths
|
||||
* without any loss of precision.
|
||||
*
|
||||
* Returns: The merged depth
|
||||
**/
|
||||
GdkMemoryDepth
|
||||
gdk_memory_depth_merge (GdkMemoryDepth depth1,
|
||||
GdkMemoryDepth depth2)
|
||||
{
|
||||
switch (depth1)
|
||||
{
|
||||
case GDK_MEMORY_U8:
|
||||
return depth2;
|
||||
|
||||
case GDK_MEMORY_FLOAT32:
|
||||
return GDK_MEMORY_FLOAT32;
|
||||
|
||||
case GDK_MEMORY_U16:
|
||||
case GDK_MEMORY_FLOAT16:
|
||||
if (depth2 == depth1 || depth2 == GDK_MEMORY_U8)
|
||||
return depth1;
|
||||
else
|
||||
return GDK_MEMORY_FLOAT32;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return GDK_MEMORY_U8;
|
||||
}
|
||||
return memory_formats[format].prefers_high_depth;
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
||||
@@ -31,19 +31,10 @@ typedef enum {
|
||||
GDK_MEMORY_ALPHA_OPAQUE
|
||||
} GdkMemoryAlpha;
|
||||
|
||||
typedef enum {
|
||||
GDK_MEMORY_U8,
|
||||
GDK_MEMORY_U16,
|
||||
GDK_MEMORY_FLOAT16,
|
||||
GDK_MEMORY_FLOAT32
|
||||
} GdkMemoryDepth;
|
||||
|
||||
gsize gdk_memory_format_alignment (GdkMemoryFormat format) G_GNUC_CONST;
|
||||
GdkMemoryAlpha gdk_memory_format_alpha (GdkMemoryFormat format) G_GNUC_CONST;
|
||||
gsize gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) G_GNUC_CONST;
|
||||
GdkMemoryDepth gdk_memory_format_get_depth (GdkMemoryFormat format) G_GNUC_CONST;
|
||||
GdkMemoryDepth gdk_memory_depth_merge (GdkMemoryDepth depth1,
|
||||
GdkMemoryDepth depth2) G_GNUC_CONST;
|
||||
gboolean gdk_memory_format_prefers_high_depth(GdkMemoryFormat format) G_GNUC_CONST;
|
||||
gboolean gdk_memory_format_gl_format (GdkMemoryFormat format,
|
||||
gboolean gles,
|
||||
guint gl_major,
|
||||
|
||||
@@ -55,7 +55,7 @@ typedef enum {
|
||||
GDK_SEAT_CAPABILITY_KEYBOARD = 1 << 3,
|
||||
GDK_SEAT_CAPABILITY_TABLET_PAD = 1 << 4,
|
||||
GDK_SEAT_CAPABILITY_ALL_POINTING = (GDK_SEAT_CAPABILITY_POINTER | GDK_SEAT_CAPABILITY_TOUCH | GDK_SEAT_CAPABILITY_TABLET_STYLUS),
|
||||
GDK_SEAT_CAPABILITY_ALL = (GDK_SEAT_CAPABILITY_ALL_POINTING | GDK_SEAT_CAPABILITY_KEYBOARD | GDK_SEAT_CAPABILITY_TABLET_PAD)
|
||||
GDK_SEAT_CAPABILITY_ALL = (GDK_SEAT_CAPABILITY_ALL_POINTING | GDK_SEAT_CAPABILITY_KEYBOARD)
|
||||
} GdkSeatCapabilities;
|
||||
|
||||
struct _GdkSeat
|
||||
|
||||
@@ -47,11 +47,7 @@ typedef struct _GdkVulkanContextPrivate GdkVulkanContextPrivate;
|
||||
struct _GdkVulkanContextPrivate {
|
||||
#ifdef GDK_RENDERING_VULKAN
|
||||
VkSurfaceKHR surface;
|
||||
struct {
|
||||
VkSurfaceFormatKHR vk_format;
|
||||
GdkMemoryFormat gdk_format;
|
||||
} formats[4];
|
||||
GdkMemoryDepth current_format;
|
||||
VkSurfaceFormatKHR image_format;
|
||||
|
||||
VkSwapchainKHR swapchain;
|
||||
VkSemaphore draw_semaphore;
|
||||
@@ -433,8 +429,8 @@ gdk_vulkan_context_check_swapchain (GdkVulkanContext *context,
|
||||
.minImageCount = CLAMP (4,
|
||||
capabilities.minImageCount,
|
||||
capabilities.maxImageCount ? capabilities.maxImageCount : G_MAXUINT32),
|
||||
.imageFormat = priv->formats[priv->current_format].vk_format.format,
|
||||
.imageColorSpace = priv->formats[priv->current_format].vk_format.colorSpace,
|
||||
.imageFormat = priv->image_format.format,
|
||||
.imageColorSpace = priv->image_format.colorSpace,
|
||||
.imageExtent = capabilities.currentExtent,
|
||||
.imageArrayLayers = 1,
|
||||
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
||||
@@ -503,20 +499,19 @@ gdk_vulkan_context_check_swapchain (GdkVulkanContext *context,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
physical_device_supports_extension (VkPhysicalDevice device,
|
||||
const char *extension_name)
|
||||
device_supports_incremental_present (VkPhysicalDevice device)
|
||||
{
|
||||
VkExtensionProperties *extensions;
|
||||
uint32_t n_device_extensions;
|
||||
|
||||
GDK_VK_CHECK (vkEnumerateDeviceExtensionProperties, device, NULL, &n_device_extensions, NULL);
|
||||
vkEnumerateDeviceExtensionProperties (device, NULL, &n_device_extensions, NULL);
|
||||
|
||||
extensions = g_newa (VkExtensionProperties, n_device_extensions);
|
||||
GDK_VK_CHECK (vkEnumerateDeviceExtensionProperties, device, NULL, &n_device_extensions, extensions);
|
||||
vkEnumerateDeviceExtensionProperties (device, NULL, &n_device_extensions, extensions);
|
||||
|
||||
for (uint32_t i = 0; i < n_device_extensions; i++)
|
||||
{
|
||||
if (g_str_equal (extensions[i].extensionName, extension_name))
|
||||
if (g_str_equal (extensions[i].extensionName, VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -525,27 +520,13 @@ physical_device_supports_extension (VkPhysicalDevice device,
|
||||
|
||||
static void
|
||||
gdk_vulkan_context_begin_frame (GdkDrawContext *draw_context,
|
||||
GdkMemoryDepth depth,
|
||||
gboolean prefers_high_depth,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
GdkVulkanContext *context = GDK_VULKAN_CONTEXT (draw_context);
|
||||
GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context);
|
||||
guint i;
|
||||
|
||||
if (depth != priv->current_format)
|
||||
{
|
||||
if (priv->formats[depth].gdk_format != priv->formats[priv->current_format].gdk_format)
|
||||
{
|
||||
GError *error = NULL;
|
||||
if (!gdk_vulkan_context_check_swapchain (context, &error))
|
||||
{
|
||||
g_warning ("%s", error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
priv->current_format = depth;
|
||||
}
|
||||
for (i = 0; i < priv->n_images; i++)
|
||||
{
|
||||
cairo_region_union (priv->regions[i], region);
|
||||
@@ -684,7 +665,6 @@ gdk_vulkan_context_real_init (GInitable *initable,
|
||||
GdkVulkanContext *context = GDK_VULKAN_CONTEXT (initable);
|
||||
GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context);
|
||||
GdkDisplay *display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
|
||||
GdkSurface *surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (context));
|
||||
VkResult res;
|
||||
VkBool32 supported;
|
||||
uint32_t i;
|
||||
@@ -693,17 +673,6 @@ gdk_vulkan_context_real_init (GInitable *initable,
|
||||
if (!priv->vulkan_ref)
|
||||
return FALSE;
|
||||
|
||||
if (surface == NULL)
|
||||
{
|
||||
for (i = 0; i < G_N_ELEMENTS (priv->formats); i++)
|
||||
{
|
||||
priv->formats[i].vk_format.format = VK_FORMAT_B8G8R8A8_UNORM;
|
||||
priv->formats[i].vk_format.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||
priv->formats[i].gdk_format = GDK_MEMORY_B8G8R8A8_PREMULTIPLIED;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
res = GDK_VULKAN_CONTEXT_GET_CLASS (context)->create_surface (context, &priv->surface);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
@@ -738,73 +707,17 @@ gdk_vulkan_context_real_init (GInitable *initable,
|
||||
&n_formats, formats);
|
||||
for (i = 0; i < n_formats; i++)
|
||||
{
|
||||
if (formats[i].colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||
continue;
|
||||
|
||||
switch ((int) formats[i].format)
|
||||
{
|
||||
case VK_FORMAT_B8G8R8A8_UNORM:
|
||||
if (priv->formats[GDK_MEMORY_U8].vk_format.format == VK_FORMAT_UNDEFINED)
|
||||
{
|
||||
priv->formats[GDK_MEMORY_U8].vk_format = formats[i];
|
||||
priv->formats[GDK_MEMORY_U8].gdk_format = GDK_MEMORY_B8G8R8A8_PREMULTIPLIED;
|
||||
};
|
||||
break;
|
||||
|
||||
case VK_FORMAT_R8G8B8A8_UNORM:
|
||||
if (priv->formats[GDK_MEMORY_U8].vk_format.format == VK_FORMAT_UNDEFINED)
|
||||
{
|
||||
priv->formats[GDK_MEMORY_U8].vk_format = formats[i];
|
||||
priv->formats[GDK_MEMORY_U8].gdk_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
|
||||
}
|
||||
break;
|
||||
|
||||
case VK_FORMAT_R16G16B16A16_UNORM:
|
||||
priv->formats[GDK_MEMORY_U16].vk_format = formats[i];
|
||||
priv->formats[GDK_MEMORY_U16].gdk_format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED;
|
||||
break;
|
||||
|
||||
case VK_FORMAT_R16G16B16A16_SFLOAT:
|
||||
priv->formats[GDK_MEMORY_FLOAT16].vk_format = formats[i];
|
||||
priv->formats[GDK_MEMORY_FLOAT16].gdk_format = GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED;
|
||||
break;
|
||||
|
||||
case VK_FORMAT_R32G32B32A32_SFLOAT:
|
||||
priv->formats[GDK_MEMORY_FLOAT32].vk_format = formats[i];
|
||||
priv->formats[GDK_MEMORY_FLOAT32].gdk_format = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (formats[i].format == VK_FORMAT_B8G8R8A8_UNORM)
|
||||
break;
|
||||
}
|
||||
if (priv->formats[GDK_MEMORY_U8].vk_format.format == VK_FORMAT_UNDEFINED)
|
||||
if (i == n_formats)
|
||||
{
|
||||
g_set_error_literal (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_NOT_AVAILABLE,
|
||||
"No supported image format found.");
|
||||
goto out_surface;
|
||||
}
|
||||
/* Ensure all the formats exist:
|
||||
* - If a format was found, keep that one.
|
||||
* - FLOAT32 chooses the best format we have.
|
||||
* - FLOAT16 and U16 pick the format FLOAT32 uses
|
||||
*/
|
||||
if (priv->formats[GDK_MEMORY_FLOAT32].vk_format.format == VK_FORMAT_UNDEFINED)
|
||||
{
|
||||
if (priv->formats[GDK_MEMORY_FLOAT16].vk_format.format != VK_FORMAT_UNDEFINED)
|
||||
priv->formats[GDK_MEMORY_FLOAT32] = priv->formats[GDK_MEMORY_FLOAT16];
|
||||
else if (priv->formats[GDK_MEMORY_U16].vk_format.format != VK_FORMAT_UNDEFINED)
|
||||
priv->formats[GDK_MEMORY_FLOAT32] = priv->formats[GDK_MEMORY_U16];
|
||||
else
|
||||
priv->formats[GDK_MEMORY_FLOAT32] = priv->formats[GDK_MEMORY_U8];
|
||||
}
|
||||
if (priv->formats[GDK_MEMORY_FLOAT16].vk_format.format == VK_FORMAT_UNDEFINED)
|
||||
priv->formats[GDK_MEMORY_FLOAT16] = priv->formats[GDK_MEMORY_FLOAT32];
|
||||
if (priv->formats[GDK_MEMORY_U16].vk_format.format == VK_FORMAT_UNDEFINED)
|
||||
priv->formats[GDK_MEMORY_U16] = priv->formats[GDK_MEMORY_FLOAT32];
|
||||
|
||||
priv->has_present_region = physical_device_supports_extension (display->vk_physical_device,
|
||||
VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME);
|
||||
priv->image_format = formats[i];
|
||||
priv->has_present_region = device_supports_incremental_present (display->vk_physical_device);
|
||||
|
||||
if (!gdk_vulkan_context_check_swapchain (context, error))
|
||||
goto out_surface;
|
||||
@@ -930,7 +843,7 @@ gdk_vulkan_context_get_image_format (GdkVulkanContext *context)
|
||||
|
||||
g_return_val_if_fail (GDK_IS_VULKAN_CONTEXT (context), VK_FORMAT_UNDEFINED);
|
||||
|
||||
return priv->formats[priv->current_format].vk_format.format;
|
||||
return priv->image_format.format;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1126,10 +1039,6 @@ gdk_display_create_vulkan_device (GdkDisplay *display,
|
||||
for (i = first; i < last; i++)
|
||||
{
|
||||
uint32_t n_queue_props;
|
||||
|
||||
if (!physical_device_supports_extension (devices[i], VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME))
|
||||
continue;
|
||||
|
||||
vkGetPhysicalDeviceQueueFamilyProperties (devices[i], &n_queue_props, NULL);
|
||||
VkQueueFamilyProperties *queue_props = g_newa (VkQueueFamilyProperties, n_queue_props);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties (devices[i], &n_queue_props, queue_props);
|
||||
@@ -1140,35 +1049,30 @@ gdk_display_create_vulkan_device (GdkDisplay *display,
|
||||
GPtrArray *device_extensions;
|
||||
gboolean has_incremental_present;
|
||||
|
||||
has_incremental_present = physical_device_supports_extension (devices[i],
|
||||
VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME);
|
||||
has_incremental_present = device_supports_incremental_present (devices[i]);
|
||||
|
||||
device_extensions = g_ptr_array_new ();
|
||||
g_ptr_array_add (device_extensions, (gpointer) VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||
g_ptr_array_add (device_extensions, (gpointer) VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
|
||||
g_ptr_array_add (device_extensions, (gpointer) VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||
if (has_incremental_present)
|
||||
g_ptr_array_add (device_extensions, (gpointer) VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME);
|
||||
|
||||
GDK_DISPLAY_DEBUG (display, VULKAN, "Using Vulkan device %u, queue %u", i, j);
|
||||
if (GDK_VK_CHECK (vkCreateDevice, devices[i],
|
||||
&(VkDeviceCreateInfo) {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
.queueCreateInfoCount = 1,
|
||||
.pQueueCreateInfos = &(VkDeviceQueueCreateInfo) {
|
||||
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
NULL,
|
||||
0,
|
||||
1,
|
||||
&(VkDeviceQueueCreateInfo) {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
||||
.queueFamilyIndex = j,
|
||||
.queueCount = 1,
|
||||
.pQueuePriorities = (float []) { 1.0f },
|
||||
},
|
||||
.enabledExtensionCount = device_extensions->len,
|
||||
.ppEnabledExtensionNames = (const char * const *) device_extensions->pdata,
|
||||
.pNext = &(VkPhysicalDeviceDescriptorIndexingFeatures) {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES,
|
||||
.descriptorBindingPartiallyBound = VK_TRUE,
|
||||
.descriptorBindingVariableDescriptorCount = VK_TRUE,
|
||||
.descriptorBindingSampledImageUpdateAfterBind = VK_TRUE,
|
||||
}
|
||||
0,
|
||||
NULL,
|
||||
device_extensions->len,
|
||||
(const char * const *) device_extensions->pdata
|
||||
},
|
||||
NULL,
|
||||
&display->vk_device) != VK_SUCCESS)
|
||||
@@ -1240,7 +1144,6 @@ gdk_display_create_vulkan_instance (GdkDisplay *display,
|
||||
|
||||
used_extensions = g_ptr_array_new ();
|
||||
g_ptr_array_add (used_extensions, (gpointer) VK_KHR_SURFACE_EXTENSION_NAME);
|
||||
g_ptr_array_add (used_extensions, (gpointer) VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
|
||||
g_ptr_array_add (used_extensions, (gpointer) GDK_DISPLAY_GET_CLASS (display)->vk_extension_name);
|
||||
|
||||
for (i = 0; i < n_extensions; i++)
|
||||
@@ -1312,7 +1215,7 @@ gdk_display_create_vulkan_instance (GdkDisplay *display,
|
||||
.enabledLayerCount = used_layers->len,
|
||||
.ppEnabledLayerNames = (const char * const *) used_layers->pdata,
|
||||
.enabledExtensionCount = used_extensions->len,
|
||||
.ppEnabledExtensionNames = (const char * const *) used_extensions->pdata,
|
||||
.ppEnabledExtensionNames = (const char * const *) used_extensions->pdata
|
||||
},
|
||||
NULL,
|
||||
&display->vk_instance);
|
||||
|
||||
@@ -190,7 +190,7 @@ copy_surface_data (GdkMacosBuffer *from,
|
||||
|
||||
static void
|
||||
_gdk_macos_cairo_context_begin_frame (GdkDrawContext *draw_context,
|
||||
GdkMemoryDepth depth,
|
||||
gboolean prefers_high_depth,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
GdkMacosCairoContext *self = (GdkMacosCairoContext *)draw_context;
|
||||
|
||||
@@ -480,7 +480,7 @@ gdk_macos_gl_context_real_realize (GdkGLContext *context,
|
||||
|
||||
static void
|
||||
gdk_macos_gl_context_begin_frame (GdkDrawContext *context,
|
||||
GdkMemoryDepth depth,
|
||||
gboolean prefers_high_depth,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
GdkMacosGLContext *self = (GdkMacosGLContext *)context;
|
||||
|
||||
@@ -207,7 +207,7 @@ wl_cursor_create_from_xcursor_images(struct wl_cursor_theme *theme,
|
||||
{
|
||||
char *path;
|
||||
XcursorImages *images;
|
||||
struct wl_cursor *cursor;
|
||||
struct cursor *cursor;
|
||||
struct cursor_image *image;
|
||||
int i, nbytes;
|
||||
unsigned int load_size;
|
||||
@@ -240,16 +240,17 @@ wl_cursor_create_from_xcursor_images(struct wl_cursor_theme *theme,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cursor->images =
|
||||
malloc(images->nimage * sizeof cursor->images[0]);
|
||||
if (!cursor->images) {
|
||||
cursor->cursor.images =
|
||||
malloc(images->nimage * sizeof cursor->cursor.images[0]);
|
||||
if (!cursor->cursor.images) {
|
||||
free(cursor);
|
||||
xcursor_images_destroy (images);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cursor->name = strdup(name);
|
||||
cursor->size = load_size;
|
||||
cursor->cursor.name = strdup(name);
|
||||
cursor->cursor.size = load_size;
|
||||
cursor->total_delay = 0;
|
||||
|
||||
for (i = 0; i < images->nimage; i++) {
|
||||
image = malloc(sizeof *image);
|
||||
@@ -290,13 +291,14 @@ wl_cursor_create_from_xcursor_images(struct wl_cursor_theme *theme,
|
||||
}
|
||||
}
|
||||
}
|
||||
cursor->images[i] = (struct wl_cursor_image *) image;
|
||||
cursor->total_delay += image->image.delay;
|
||||
cursor->cursor.images[i] = (struct wl_cursor_image *) image;
|
||||
}
|
||||
cursor->image_count = i;
|
||||
cursor->cursor.image_count = i;
|
||||
|
||||
if (cursor->image_count == 0) {
|
||||
free(cursor->name);
|
||||
free(cursor->images);
|
||||
if (cursor->cursor.image_count == 0) {
|
||||
free(cursor->cursor.name);
|
||||
free(cursor->cursor.images);
|
||||
free(cursor);
|
||||
xcursor_images_destroy (images);
|
||||
return NULL;
|
||||
@@ -304,7 +306,7 @@ wl_cursor_create_from_xcursor_images(struct wl_cursor_theme *theme,
|
||||
|
||||
xcursor_images_destroy (images);
|
||||
|
||||
return cursor;
|
||||
return &cursor->cursor;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -145,7 +145,7 @@ gdk_wayland_cairo_context_create_surface (GdkWaylandCairoContext *self)
|
||||
|
||||
static void
|
||||
gdk_wayland_cairo_context_begin_frame (GdkDrawContext *draw_context,
|
||||
GdkMemoryDepth depth,
|
||||
gboolean prefers_high_depth,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
GdkWaylandCairoContext *self = GDK_WAYLAND_CAIRO_CONTEXT (draw_context);
|
||||
|
||||
@@ -698,36 +698,7 @@ gdk_wayland_display_dispose (GObject *object)
|
||||
|
||||
g_list_free_full (display_wayland->on_has_globals_closures, g_free);
|
||||
|
||||
g_clear_pointer (&display_wayland->cursor_theme, wl_cursor_theme_destroy);
|
||||
g_clear_pointer (&display_wayland->compositor, wl_compositor_destroy);
|
||||
g_clear_pointer (&display_wayland->xdg_wm_base, xdg_wm_base_destroy);
|
||||
g_clear_pointer (&display_wayland->zxdg_shell_v6, zxdg_shell_v6_destroy);
|
||||
g_clear_pointer (&display_wayland->gtk_shell, gtk_shell1_destroy);
|
||||
g_clear_pointer (&display_wayland->data_device_manager, wl_data_device_manager_destroy);
|
||||
g_clear_pointer (&display_wayland->subcompositor, wl_subcompositor_destroy);
|
||||
g_clear_pointer (&display_wayland->pointer_gestures, zwp_pointer_gestures_v1_destroy);
|
||||
g_clear_pointer (&display_wayland->primary_selection_manager, zwp_primary_selection_device_manager_v1_destroy);
|
||||
g_clear_pointer (&display_wayland->tablet_manager, zwp_tablet_manager_v2_destroy);
|
||||
g_clear_pointer (&display_wayland->xdg_exporter, zxdg_exporter_v1_destroy);
|
||||
g_clear_pointer (&display_wayland->xdg_exporter_v2, zxdg_exporter_v2_destroy);
|
||||
g_clear_pointer (&display_wayland->xdg_importer, zxdg_importer_v1_destroy);
|
||||
g_clear_pointer (&display_wayland->xdg_importer_v2, zxdg_importer_v2_destroy);
|
||||
g_clear_pointer (&display_wayland->keyboard_shortcuts_inhibit, zwp_keyboard_shortcuts_inhibit_manager_v1_destroy);
|
||||
g_clear_pointer (&display_wayland->server_decoration_manager, org_kde_kwin_server_decoration_manager_destroy);
|
||||
g_clear_pointer (&display_wayland->xdg_output_manager, zxdg_output_manager_v1_destroy);
|
||||
g_clear_pointer (&display_wayland->idle_inhibit_manager, zwp_idle_inhibit_manager_v1_destroy);
|
||||
g_clear_pointer (&display_wayland->xdg_activation, xdg_activation_v1_destroy);
|
||||
g_clear_pointer (&display_wayland->fractional_scale, wp_fractional_scale_manager_v1_destroy);
|
||||
g_clear_pointer (&display_wayland->viewporter, wp_viewporter_destroy);
|
||||
|
||||
g_clear_pointer (&display_wayland->shm, wl_shm_destroy);
|
||||
g_clear_pointer (&display_wayland->wl_registry, wl_registry_destroy);
|
||||
|
||||
g_list_store_remove_all (display_wayland->monitors);
|
||||
|
||||
G_OBJECT_CLASS (gdk_wayland_display_parent_class)->dispose (object);
|
||||
|
||||
g_clear_pointer (&display_wayland->wl_display, wl_display_disconnect);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -737,17 +708,22 @@ gdk_wayland_display_finalize (GObject *object)
|
||||
|
||||
_gdk_wayland_display_finalize_cursors (display_wayland);
|
||||
|
||||
g_object_unref (display_wayland->monitors);
|
||||
|
||||
g_free (display_wayland->startup_notification_id);
|
||||
g_free (display_wayland->cursor_theme_name);
|
||||
xkb_context_unref (display_wayland->xkb_context);
|
||||
|
||||
g_clear_pointer (&display_wayland->cursor_theme, wl_cursor_theme_destroy);
|
||||
|
||||
g_list_store_remove_all (display_wayland->monitors);
|
||||
g_object_unref (display_wayland->monitors);
|
||||
|
||||
if (display_wayland->settings)
|
||||
g_hash_table_destroy (display_wayland->settings);
|
||||
|
||||
g_clear_object (&display_wayland->settings_portal);
|
||||
|
||||
wl_display_disconnect (display_wayland->wl_display);
|
||||
|
||||
G_OBJECT_CLASS (gdk_wayland_display_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
||||
@@ -98,6 +98,7 @@ struct _GdkWaylandDisplay
|
||||
struct xdg_wm_base *xdg_wm_base;
|
||||
struct zxdg_shell_v6 *zxdg_shell_v6;
|
||||
struct gtk_shell1 *gtk_shell;
|
||||
struct wl_input_device *input_device;
|
||||
struct wl_data_device_manager *data_device_manager;
|
||||
struct wl_subcompositor *subcompositor;
|
||||
struct zwp_pointer_gestures_v1 *pointer_gestures;
|
||||
|
||||
@@ -48,12 +48,12 @@ G_DEFINE_TYPE (GdkWaylandGLContext, gdk_wayland_gl_context, GDK_TYPE_GL_CONTEXT)
|
||||
|
||||
static void
|
||||
gdk_wayland_gl_context_begin_frame (GdkDrawContext *draw_context,
|
||||
GdkMemoryDepth depth,
|
||||
gboolean prefers_high_depth,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
gdk_wayland_surface_ensure_wl_egl_window (gdk_draw_context_get_surface (draw_context));
|
||||
|
||||
GDK_DRAW_CONTEXT_CLASS (gdk_wayland_gl_context_parent_class)->begin_frame (draw_context, depth, region);
|
||||
GDK_DRAW_CONTEXT_CLASS (gdk_wayland_gl_context_parent_class)->begin_frame (draw_context, prefers_high_depth, region);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -2143,13 +2143,10 @@ _gdk_wayland_seat_remove_tablet_pad (GdkWaylandSeat *seat,
|
||||
{
|
||||
seat->tablet_pads = g_list_remove (seat->tablet_pads, pad);
|
||||
|
||||
if (pad->device)
|
||||
{
|
||||
gdk_seat_device_removed (GDK_SEAT (seat), pad->device);
|
||||
_gdk_device_set_associated_device (pad->device, NULL);
|
||||
g_object_unref (pad->device);
|
||||
}
|
||||
gdk_seat_device_removed (GDK_SEAT (seat), pad->device);
|
||||
_gdk_device_set_associated_device (pad->device, NULL);
|
||||
|
||||
g_object_unref (pad->device);
|
||||
g_free (pad);
|
||||
}
|
||||
|
||||
@@ -3538,10 +3535,21 @@ static void
|
||||
tablet_pad_handle_done (void *data,
|
||||
struct zwp_tablet_pad_v2 *wp_tablet_pad)
|
||||
{
|
||||
G_GNUC_UNUSED GdkWaylandTabletPadData *pad = data;
|
||||
GdkWaylandTabletPadData *pad = data;
|
||||
|
||||
GDK_SEAT_DEBUG (pad->seat, EVENTS,
|
||||
"tablet pad handle done, pad = %p", wp_tablet_pad);
|
||||
|
||||
pad->device =
|
||||
g_object_new (GDK_TYPE_WAYLAND_DEVICE_PAD,
|
||||
"name", "Pad device",
|
||||
"source", GDK_SOURCE_TABLET_PAD,
|
||||
"display", gdk_seat_get_display (pad->seat),
|
||||
"seat", pad->seat,
|
||||
NULL);
|
||||
|
||||
_gdk_device_set_associated_device (pad->device, GDK_WAYLAND_SEAT (pad->seat)->logical_keyboard);
|
||||
gdk_seat_device_added (GDK_SEAT (pad->seat), pad->device);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -3598,44 +3606,9 @@ tablet_pad_handle_enter (void *data,
|
||||
"tablet pad handle enter, pad = %p, tablet = %p surface = %p",
|
||||
wp_tablet_pad, wp_tablet, surface);
|
||||
|
||||
if (pad->device && pad->current_tablet != tablet)
|
||||
{
|
||||
gdk_seat_device_removed (GDK_SEAT (pad->seat), pad->device);
|
||||
_gdk_device_set_associated_device (pad->device, NULL);
|
||||
g_clear_object (&pad->device);
|
||||
}
|
||||
|
||||
/* Relate pad and tablet */
|
||||
tablet->pads = g_list_prepend (tablet->pads, pad);
|
||||
pad->current_tablet = tablet;
|
||||
|
||||
if (!pad->device)
|
||||
{
|
||||
gchar *name, *vid, *pid;
|
||||
|
||||
name = g_strdup_printf ("%s Pad %d",
|
||||
tablet->name,
|
||||
g_list_index (tablet->pads, pad) + 1);
|
||||
vid = g_strdup_printf ("%.4x", tablet->vid);
|
||||
pid = g_strdup_printf ("%.4x", tablet->pid);
|
||||
|
||||
pad->device =
|
||||
g_object_new (GDK_TYPE_WAYLAND_DEVICE_PAD,
|
||||
"name", name,
|
||||
"vendor-id", vid,
|
||||
"product-id", pid,
|
||||
"source", GDK_SOURCE_TABLET_PAD,
|
||||
"display", gdk_seat_get_display (pad->seat),
|
||||
"seat", pad->seat,
|
||||
NULL);
|
||||
|
||||
_gdk_device_set_associated_device (pad->device, GDK_WAYLAND_SEAT (pad->seat)->logical_keyboard);
|
||||
gdk_seat_device_added (GDK_SEAT (pad->seat), pad->device);
|
||||
|
||||
g_free (name);
|
||||
g_free (vid);
|
||||
g_free (pid);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -3651,7 +3624,10 @@ tablet_pad_handle_leave (void *data,
|
||||
wp_tablet_pad, surface);
|
||||
|
||||
if (pad->current_tablet)
|
||||
pad->current_tablet->pads = g_list_remove (pad->current_tablet->pads, pad);
|
||||
{
|
||||
pad->current_tablet->pads = g_list_remove (pad->current_tablet->pads, pad);
|
||||
pad->current_tablet = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -3899,23 +3875,6 @@ gdk_wayland_pointer_data_finalize (GdkWaylandPointerData *pointer)
|
||||
g_slist_free (pointer->pointer_surface_outputs);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_seat_dispose (GObject *object)
|
||||
{
|
||||
GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (object);
|
||||
|
||||
g_clear_pointer (&seat->wl_seat, wl_seat_destroy);
|
||||
g_clear_pointer (&seat->wl_pointer, wl_pointer_destroy);
|
||||
g_clear_pointer (&seat->wl_keyboard, wl_keyboard_destroy);
|
||||
g_clear_pointer (&seat->wl_touch, wl_touch_destroy);
|
||||
g_clear_pointer (&seat->wp_pointer_gesture_swipe, zwp_pointer_gesture_swipe_v1_destroy);
|
||||
g_clear_pointer (&seat->wp_pointer_gesture_pinch, zwp_pointer_gesture_pinch_v1_destroy);
|
||||
g_clear_pointer (&seat->wp_pointer_gesture_hold, zwp_pointer_gesture_hold_v1_destroy);
|
||||
g_clear_pointer (&seat->wp_tablet_seat, zwp_tablet_seat_v2_destroy);
|
||||
|
||||
G_OBJECT_CLASS (gdk_wayland_seat_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_seat_finalize (GObject *object)
|
||||
{
|
||||
@@ -4230,7 +4189,6 @@ gdk_wayland_seat_class_init (GdkWaylandSeatClass *klass)
|
||||
GdkSeatClass *seat_class = GDK_SEAT_CLASS (klass);
|
||||
|
||||
object_class->finalize = gdk_wayland_seat_finalize;
|
||||
object_class->dispose = gdk_wayland_seat_dispose;
|
||||
|
||||
seat_class->get_capabilities = gdk_wayland_seat_get_capabilities;
|
||||
seat_class->grab = gdk_wayland_seat_grab;
|
||||
|
||||
@@ -53,7 +53,7 @@ create_cairo_surface_for_surface (GdkSurface *surface,
|
||||
|
||||
static void
|
||||
gdk_win32_cairo_context_begin_frame (GdkDrawContext *draw_context,
|
||||
GdkMemoryDepth depth,
|
||||
gboolean prefers_high_depth,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
GdkWin32CairoContext *self = GDK_WIN32_CAIRO_CONTEXT (draw_context);
|
||||
|
||||
@@ -2734,10 +2734,6 @@ gdk_event_translate (MSG *msg,
|
||||
if (GDK_IS_DRAG_SURFACE (window) ||
|
||||
_gdk_modal_blocked (window))
|
||||
{
|
||||
/* Focus the modal window */
|
||||
GdkSurface *modal_window = _gdk_modal_current ();
|
||||
if (modal_window != NULL)
|
||||
SetFocus (GDK_SURFACE_HWND (modal_window));
|
||||
*ret_valp = MA_NOACTIVATE;
|
||||
return_val = TRUE;
|
||||
}
|
||||
@@ -2748,10 +2744,6 @@ gdk_event_translate (MSG *msg,
|
||||
if (GDK_IS_DRAG_SURFACE (window) ||
|
||||
_gdk_modal_blocked (window))
|
||||
{
|
||||
/* Focus the modal window */
|
||||
GdkSurface *modal_window = _gdk_modal_current ();
|
||||
if (modal_window != NULL)
|
||||
SetFocus (GDK_SURFACE_HWND (modal_window));
|
||||
*ret_valp = PA_NOACTIVATE;
|
||||
return_val = TRUE;
|
||||
}
|
||||
|
||||
@@ -109,12 +109,12 @@ gdk_win32_gl_context_egl_end_frame (GdkDrawContext *draw_context,
|
||||
|
||||
static void
|
||||
gdk_win32_gl_context_egl_begin_frame (GdkDrawContext *draw_context,
|
||||
GdkMemoryDepth depth,
|
||||
gboolean prefers_high_depth,
|
||||
cairo_region_t *update_area)
|
||||
{
|
||||
gdk_win32_surface_handle_queued_move_resize (draw_context);
|
||||
|
||||
GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_egl_parent_class)->begin_frame (draw_context, depth, update_area);
|
||||
GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_egl_parent_class)->begin_frame (draw_context, prefers_high_depth, update_area);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -118,12 +118,12 @@ gdk_win32_gl_context_wgl_end_frame (GdkDrawContext *draw_context,
|
||||
|
||||
static void
|
||||
gdk_win32_gl_context_wgl_begin_frame (GdkDrawContext *draw_context,
|
||||
GdkMemoryDepth depth,
|
||||
gboolean prefers_high_depth,
|
||||
cairo_region_t *update_area)
|
||||
{
|
||||
gdk_win32_surface_handle_queued_move_resize (draw_context);
|
||||
|
||||
GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_wgl_parent_class)->begin_frame (draw_context, depth, update_area);
|
||||
GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_wgl_parent_class)->begin_frame (draw_context, prefers_high_depth, update_area);
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
@@ -725,7 +725,11 @@ show_window_internal (GdkSurface *window,
|
||||
|
||||
if (center)
|
||||
{
|
||||
GetWindowRect (GDK_SURFACE_HWND (window), &window_rect);
|
||||
window_rect.left = 0;
|
||||
window_rect.top = 0;
|
||||
window_rect.right = window->width * surface->surface_scale;
|
||||
window_rect.bottom = window->height * surface->surface_scale;
|
||||
_gdk_win32_adjust_client_rect (window, &window_rect);
|
||||
|
||||
x = center_on_rect.left + ((center_on_rect.right - center_on_rect.left) - (window_rect.right - window_rect.left)) / 2;
|
||||
y = center_on_rect.top + ((center_on_rect.bottom - center_on_rect.top) - (window_rect.bottom - window_rect.top)) / 2;
|
||||
|
||||
@@ -66,12 +66,12 @@ gdk_win32_vulkan_context_create_surface (GdkVulkanContext *context,
|
||||
|
||||
static void
|
||||
gdk_win32_vulkan_context_begin_frame (GdkDrawContext *draw_context,
|
||||
GdkMemoryDepth depth,
|
||||
gboolean prefers_high_depth,
|
||||
cairo_region_t *update_area)
|
||||
{
|
||||
gdk_win32_surface_handle_queued_move_resize (draw_context);
|
||||
|
||||
GDK_DRAW_CONTEXT_CLASS (gdk_win32_vulkan_context_parent_class)->begin_frame (draw_context, depth, update_area);
|
||||
GDK_DRAW_CONTEXT_CLASS (gdk_win32_vulkan_context_parent_class)->begin_frame (draw_context, prefers_high_depth, update_area);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -55,7 +55,7 @@ create_cairo_surface_for_surface (GdkSurface *surface)
|
||||
|
||||
static void
|
||||
gdk_x11_cairo_context_begin_frame (GdkDrawContext *draw_context,
|
||||
GdkMemoryDepth depth,
|
||||
gboolean prefers_high_depth,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
GdkX11CairoContext *self = GDK_X11_CAIRO_CONTEXT (draw_context);
|
||||
|
||||
@@ -549,6 +549,8 @@ gdk_x11_context_create_glx_context (GdkGLContext *context,
|
||||
context_attribs [major_idx] = gdk_gl_version_get_major (&supported_versions[j]);
|
||||
context_attribs [minor_idx] = gdk_gl_version_get_minor (&supported_versions[j]);
|
||||
|
||||
gdk_x11_display_error_trap_push (display);
|
||||
|
||||
/* If we don't have access to GLX_ARB_create_context_profile, then
|
||||
* we have to fall back to the old GLX 1.3 API.
|
||||
*/
|
||||
@@ -566,16 +568,19 @@ gdk_x11_context_create_glx_context (GdkGLContext *context,
|
||||
True,
|
||||
context_attribs);
|
||||
|
||||
if (ctx != NULL)
|
||||
if (ctx == NULL)
|
||||
{
|
||||
gdk_x11_display_error_trap_pop_ignored (display);
|
||||
}
|
||||
else if (gdk_x11_display_error_trap_pop (display))
|
||||
{
|
||||
glXDestroyContext (dpy, ctx);
|
||||
ctx = NULL;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (ctx == NULL)
|
||||
{
|
||||
GDK_DISPLAY_DEBUG (display, OPENGL, "Failed to create a GLX context");
|
||||
return 0;
|
||||
}
|
||||
|
||||
GDK_DISPLAY_DEBUG (display, OPENGL,
|
||||
"Realized GLX context[%p], %s, version: %d.%d",
|
||||
context_glx->glx_context,
|
||||
@@ -656,42 +661,25 @@ gdk_x11_gl_context_glx_realize (GdkGLContext *context,
|
||||
if (share != NULL && gdk_gl_context_is_legacy (share))
|
||||
legacy = TRUE;
|
||||
|
||||
gdk_x11_display_error_trap_push (display);
|
||||
|
||||
/* Increase XNextRequest because GLX may fake errors with the last request
|
||||
* and we want the error trap to catch them */
|
||||
XChangeWindowAttributes (GDK_DISPLAY_XDISPLAY (display),
|
||||
GDK_X11_DISPLAY (display)->leader_window,
|
||||
0,
|
||||
(XSetWindowAttributes[1]) { 0, });
|
||||
|
||||
if (preferred_api == GDK_GL_API_GL)
|
||||
{
|
||||
api = gdk_x11_context_create_glx_context (context, GDK_GL_API_GL, legacy);
|
||||
if (api == 0)
|
||||
api = gdk_x11_context_create_glx_context (context, GDK_GL_API_GLES, legacy);
|
||||
if (api == 0)
|
||||
api = gdk_x11_context_create_glx_context (context, GDK_GL_API_GL, TRUE);
|
||||
if ((api = gdk_x11_context_create_glx_context (context, GDK_GL_API_GL, legacy)) ||
|
||||
(api = gdk_x11_context_create_glx_context (context, GDK_GL_API_GLES, legacy)) ||
|
||||
(api = gdk_x11_context_create_glx_context (context, GDK_GL_API_GL, TRUE)))
|
||||
return api;
|
||||
}
|
||||
else
|
||||
{
|
||||
api = gdk_x11_context_create_glx_context (context, GDK_GL_API_GLES, FALSE);
|
||||
if (api == 0)
|
||||
api = gdk_x11_context_create_glx_context (context, GDK_GL_API_GL, legacy);
|
||||
if (api == 0)
|
||||
api = gdk_x11_context_create_glx_context (context, GDK_GL_API_GL, TRUE);
|
||||
if ((api = gdk_x11_context_create_glx_context (context, GDK_GL_API_GLES, FALSE)) ||
|
||||
(api = gdk_x11_context_create_glx_context (context, GDK_GL_API_GL, legacy)) ||
|
||||
(api = gdk_x11_context_create_glx_context (context, GDK_GL_API_GL, TRUE)))
|
||||
return api;
|
||||
}
|
||||
|
||||
gdk_x11_display_error_trap_pop_ignored (display);
|
||||
|
||||
if (api == 0)
|
||||
{
|
||||
g_set_error_literal (error, GDK_GL_ERROR,
|
||||
GDK_GL_ERROR_NOT_AVAILABLE,
|
||||
_("Unable to create a GL context"));
|
||||
}
|
||||
|
||||
return api;
|
||||
g_set_error_literal (error, GDK_GL_ERROR,
|
||||
GDK_GL_ERROR_NOT_AVAILABLE,
|
||||
_("Unable to create a GL context"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef N_GLX_ATTRS
|
||||
|
||||
@@ -271,8 +271,6 @@ collect_reused_child_nodes (GskRenderer *renderer,
|
||||
case GSK_CROSS_FADE_NODE:
|
||||
case GSK_BLUR_NODE:
|
||||
case GSK_MASK_NODE:
|
||||
case GSK_FILL_NODE:
|
||||
case GSK_STROKE_NODE:
|
||||
|
||||
default:
|
||||
|
||||
@@ -861,8 +859,6 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
case GSK_CROSS_FADE_NODE:
|
||||
case GSK_BLUR_NODE:
|
||||
case GSK_GL_SHADER_NODE:
|
||||
case GSK_FILL_NODE:
|
||||
case GSK_STROKE_NODE:
|
||||
default:
|
||||
break; /* Fallback */
|
||||
}
|
||||
|
||||
@@ -1458,9 +1458,6 @@ memory_format_gl_format (GdkMemoryFormat data_format,
|
||||
guint *gl_type,
|
||||
GLint (*gl_swizzle)[4])
|
||||
{
|
||||
GdkMemoryDepth depth;
|
||||
|
||||
/* First, try the format itself */
|
||||
if (gdk_memory_format_gl_format (data_format,
|
||||
use_es,
|
||||
major,
|
||||
@@ -1472,48 +1469,7 @@ memory_format_gl_format (GdkMemoryFormat data_format,
|
||||
gdk_memory_format_alpha (data_format) != GDK_MEMORY_ALPHA_STRAIGHT)
|
||||
return data_format;
|
||||
|
||||
depth = gdk_memory_format_get_depth (data_format);
|
||||
|
||||
/* Next, try the generic format for the given bit depth */
|
||||
switch (depth)
|
||||
{
|
||||
case GDK_MEMORY_FLOAT16:
|
||||
data_format = GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED;
|
||||
if (gdk_memory_format_gl_format (data_format,
|
||||
use_es,
|
||||
major,
|
||||
minor,
|
||||
gl_internalformat,
|
||||
gl_format,
|
||||
gl_type,
|
||||
gl_swizzle))
|
||||
return data_format;
|
||||
break;
|
||||
|
||||
case GDK_MEMORY_U16:
|
||||
data_format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED;
|
||||
if (gdk_memory_format_gl_format (data_format,
|
||||
use_es,
|
||||
major,
|
||||
minor,
|
||||
gl_internalformat,
|
||||
gl_format,
|
||||
gl_type,
|
||||
gl_swizzle))
|
||||
return data_format;
|
||||
break;
|
||||
|
||||
case GDK_MEMORY_FLOAT32:
|
||||
case GDK_MEMORY_U8:
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
/* If the format is high depth, also try float32 */
|
||||
if (depth != GDK_MEMORY_U8)
|
||||
if (gdk_memory_format_prefers_high_depth (data_format))
|
||||
{
|
||||
data_format = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED;
|
||||
if (gdk_memory_format_gl_format (data_format,
|
||||
@@ -1527,7 +1483,6 @@ memory_format_gl_format (GdkMemoryFormat data_format,
|
||||
return data_format;
|
||||
}
|
||||
|
||||
/* If all else fails, pick the one format that's always supported */
|
||||
data_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
|
||||
if (!gdk_memory_format_gl_format (data_format,
|
||||
use_es,
|
||||
|
||||
@@ -296,7 +296,7 @@ gsk_gl_renderer_render (GskRenderer *renderer,
|
||||
viewport.size.height = gdk_surface_get_height (surface) * scale;
|
||||
|
||||
gdk_draw_context_begin_frame_full (GDK_DRAW_CONTEXT (self->context),
|
||||
gsk_render_node_get_preferred_depth (root),
|
||||
gsk_render_node_prefers_high_depth (root),
|
||||
update_area);
|
||||
|
||||
gdk_gl_context_make_current (self->context);
|
||||
@@ -373,7 +373,7 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer,
|
||||
return texture;
|
||||
}
|
||||
|
||||
if (gsk_render_node_get_preferred_depth (root) != GDK_MEMORY_U8 &&
|
||||
if (gsk_render_node_prefers_high_depth (root) &&
|
||||
gdk_gl_context_check_version (self->context, "3.0", "3.0"))
|
||||
format = GL_RGBA32F;
|
||||
else
|
||||
|
||||
@@ -194,7 +194,7 @@ static inline int
|
||||
get_target_format (GskGLRenderJob *job,
|
||||
const GskRenderNode *node)
|
||||
{
|
||||
if (gsk_render_node_get_preferred_depth (node) != GDK_MEMORY_U8)
|
||||
if (gsk_render_node_prefers_high_depth (node))
|
||||
return job->target_format;
|
||||
|
||||
return GL_RGBA8;
|
||||
@@ -254,8 +254,6 @@ node_supports_2d_transform (const GskRenderNode *node)
|
||||
case GSK_BLEND_NODE:
|
||||
case GSK_BLUR_NODE:
|
||||
case GSK_MASK_NODE:
|
||||
case GSK_FILL_NODE:
|
||||
case GSK_STROKE_NODE:
|
||||
return TRUE;
|
||||
|
||||
case GSK_SHADOW_NODE:
|
||||
@@ -310,8 +308,6 @@ node_supports_transform (const GskRenderNode *node)
|
||||
case GSK_BLEND_NODE:
|
||||
case GSK_BLUR_NODE:
|
||||
case GSK_MASK_NODE:
|
||||
case GSK_FILL_NODE:
|
||||
case GSK_STROKE_NODE:
|
||||
return TRUE;
|
||||
|
||||
case GSK_SHADOW_NODE:
|
||||
@@ -4115,14 +4111,6 @@ gsk_gl_render_job_visit_node (GskGLRenderJob *job,
|
||||
gsk_gl_render_job_visit_as_fallback (job, node);
|
||||
break;
|
||||
|
||||
case GSK_FILL_NODE:
|
||||
gsk_gl_render_job_visit_as_fallback (job, node);
|
||||
break;
|
||||
|
||||
case GSK_STROKE_NODE:
|
||||
gsk_gl_render_job_visit_as_fallback (job, node);
|
||||
break;
|
||||
|
||||
case GSK_NOT_A_RENDER_NODE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
|
||||
@@ -204,7 +204,6 @@ gsk_gl_texture_library_dispose (GObject *object)
|
||||
|
||||
g_clear_pointer (&self->atlases, g_ptr_array_unref);
|
||||
g_clear_object (&self->driver);
|
||||
g_clear_pointer (&self->hash_table, g_hash_table_unref);
|
||||
|
||||
G_OBJECT_CLASS (gsk_gl_texture_library_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
@@ -20,14 +20,9 @@
|
||||
#define __GSK_H_INSIDE__
|
||||
|
||||
#include <gsk/gskenums.h>
|
||||
#include <gsk/gskpath.h>
|
||||
#include <gsk/gskpathbuilder.h>
|
||||
#include <gsk/gskpathmeasure.h>
|
||||
#include <gsk/gskpathpoint.h>
|
||||
#include <gsk/gskrenderer.h>
|
||||
#include <gsk/gskrendernode.h>
|
||||
#include <gsk/gskroundedrect.h>
|
||||
#include <gsk/gskstroke.h>
|
||||
#include <gsk/gsktransform.h>
|
||||
#include <gsk/gskglshader.h>
|
||||
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gsk/gsktypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GskBoundingBox GskBoundingBox;
|
||||
|
||||
struct _GskBoundingBox {
|
||||
graphene_point_t min;
|
||||
graphene_point_t max;
|
||||
};
|
||||
|
||||
static inline GskBoundingBox *
|
||||
gsk_bounding_box_init (GskBoundingBox *self,
|
||||
const graphene_point_t *a,
|
||||
const graphene_point_t *b)
|
||||
{
|
||||
self->min.x = MIN (a->x, b->x);
|
||||
self->min.y = MIN (a->y, b->y);
|
||||
self->max.x = MAX (a->x, b->x);
|
||||
self->max.y = MAX (a->y, b->y);
|
||||
return self;
|
||||
}
|
||||
|
||||
static inline GskBoundingBox *
|
||||
gsk_bounding_box_init_copy (GskBoundingBox *self,
|
||||
const GskBoundingBox *src)
|
||||
{
|
||||
self->min = src->min;
|
||||
self->max = src->max;
|
||||
return self;
|
||||
}
|
||||
|
||||
static inline GskBoundingBox *
|
||||
gsk_bounding_box_init_from_rect (GskBoundingBox *self,
|
||||
const graphene_rect_t *bounds)
|
||||
{
|
||||
self->min = bounds->origin;
|
||||
self->max.x = bounds->origin.x + bounds->size.width;
|
||||
self->max.y = bounds->origin.y + bounds->size.height;
|
||||
return self;
|
||||
}
|
||||
|
||||
static inline void
|
||||
gsk_bounding_box_expand (GskBoundingBox *self,
|
||||
const graphene_point_t *p)
|
||||
{
|
||||
self->min.x = MIN (self->min.x, p->x);
|
||||
self->min.y = MIN (self->min.y, p->y);
|
||||
self->max.x = MAX (self->max.x, p->x);
|
||||
self->max.y = MAX (self->max.y, p->y);
|
||||
}
|
||||
|
||||
static inline graphene_rect_t *
|
||||
gsk_bounding_box_to_rect (const GskBoundingBox *self,
|
||||
graphene_rect_t *rect)
|
||||
{
|
||||
rect->origin = self->min;
|
||||
rect->size.width = self->max.x - self->min.x;
|
||||
rect->size.height = self->max.y - self->min.y;
|
||||
return rect;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
gsk_bounding_box_contains_point (const GskBoundingBox *self,
|
||||
const graphene_point_t *p)
|
||||
{
|
||||
return self->min.x <= p->x && p->x <= self->max.x &&
|
||||
self->min.y <= p->y && p->y <= self->max.y;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
gsk_bounding_box_contains_point_with_epsilon (const GskBoundingBox *self,
|
||||
const graphene_point_t *p,
|
||||
float epsilon)
|
||||
{
|
||||
return self->min.x - epsilon <= p->x && p->x <= self->max.x + epsilon &&
|
||||
self->min.y - epsilon <= p->y && p->y <= self->max.y + epsilon;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
gsk_bounding_box_intersection (const GskBoundingBox *a,
|
||||
const GskBoundingBox *b,
|
||||
GskBoundingBox *res)
|
||||
{
|
||||
graphene_point_t min, max;
|
||||
|
||||
min.x = MAX (a->min.x, b->min.x);
|
||||
min.y = MAX (a->min.y, b->min.y);
|
||||
max.x = MIN (a->max.x, b->max.x);
|
||||
max.y = MIN (a->max.y, b->max.y);
|
||||
|
||||
if (res)
|
||||
gsk_bounding_box_init (res, &min, &max);
|
||||
|
||||
return min.x <= max.x && min.y <= max.y;
|
||||
}
|
||||
|
||||
G_END_DECLS
|
||||
2718
gsk/gskcontour.c
2718
gsk/gskcontour.c
File diff suppressed because it is too large
Load Diff
@@ -1,128 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020 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>
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gskpath.h"
|
||||
|
||||
#include "gskpathopprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GSK_PATH_FLAT,
|
||||
GSK_PATH_CLOSED
|
||||
} GskPathFlags;
|
||||
|
||||
typedef struct _GskContour GskContour;
|
||||
|
||||
GskContour * gsk_rect_contour_new (const graphene_rect_t *rect);
|
||||
GskContour * gsk_rounded_rect_contour_new (const GskRoundedRect *rounded_rect);
|
||||
GskContour * gsk_circle_contour_new (const graphene_point_t *center,
|
||||
float radius,
|
||||
float start_angle,
|
||||
float end_angle);
|
||||
GskContour * gsk_standard_contour_new (GskPathFlags flags,
|
||||
const graphene_point_t *points,
|
||||
gsize n_points,
|
||||
const gskpathop *ops,
|
||||
gsize n_ops,
|
||||
gssize offset);
|
||||
|
||||
void gsk_contour_copy (GskContour * dest,
|
||||
const GskContour *src);
|
||||
GskContour * gsk_contour_dup (const GskContour *src);
|
||||
GskContour * gsk_contour_reverse (const GskContour *src);
|
||||
|
||||
gsize gsk_contour_get_size (const GskContour *self);
|
||||
GskPathFlags gsk_contour_get_flags (const GskContour *self);
|
||||
void gsk_contour_print (const GskContour *self,
|
||||
GString *string);
|
||||
gboolean gsk_contour_get_bounds (const GskContour *self,
|
||||
graphene_rect_t *bounds);
|
||||
gboolean gsk_contour_get_stroke_bounds (const GskContour *self,
|
||||
const GskStroke *stroke,
|
||||
graphene_rect_t *bounds);
|
||||
gpointer gsk_contour_init_measure (const GskContour *self,
|
||||
float tolerance,
|
||||
float *out_length);
|
||||
void gsk_contour_free_measure (const GskContour *self,
|
||||
gpointer data);
|
||||
gboolean gsk_contour_foreach (const GskContour *self,
|
||||
float tolerance,
|
||||
GskPathForeachFunc func,
|
||||
gpointer user_data);
|
||||
void gsk_contour_get_start_end (const GskContour *self,
|
||||
graphene_point_t *start,
|
||||
graphene_point_t *end);
|
||||
void gsk_contour_get_point (const GskContour *self,
|
||||
gpointer measure_data,
|
||||
float distance,
|
||||
GskPathDirection direction,
|
||||
graphene_point_t *pos,
|
||||
graphene_vec2_t *tangent);
|
||||
gboolean gsk_contour_get_closest_point (const GskContour *self,
|
||||
gpointer measure_data,
|
||||
float tolerance,
|
||||
const graphene_point_t *point,
|
||||
float threshold,
|
||||
float *out_distance,
|
||||
graphene_point_t *out_pos,
|
||||
float *out_offset,
|
||||
graphene_vec2_t *out_tangent);
|
||||
int gsk_contour_get_winding (const GskContour *self,
|
||||
gpointer measure_data,
|
||||
const graphene_point_t *point);
|
||||
void gsk_contour_add_segment (const GskContour *self,
|
||||
GskPathBuilder *builder,
|
||||
gpointer measure_data,
|
||||
gboolean emit_move_to,
|
||||
float start,
|
||||
float end);
|
||||
float gsk_contour_get_curvature (const GskContour *self,
|
||||
gpointer measure_data,
|
||||
float distance,
|
||||
graphene_point_t *center);
|
||||
gboolean gsk_contour_dash (const GskContour *contour,
|
||||
GskStroke *stroke,
|
||||
float tolerance,
|
||||
GskPathForeachFunc func,
|
||||
gpointer user_data);
|
||||
|
||||
void gsk_contour_add_stroke (const GskContour *contour,
|
||||
GskPathBuilder *builder,
|
||||
GskStroke *stroke);
|
||||
|
||||
void gsk_contour_default_add_stroke (const GskContour *contour,
|
||||
GskPathBuilder *builder,
|
||||
GskStroke *stroke);
|
||||
|
||||
void gsk_contour_offset (const GskContour *contour,
|
||||
GskPathBuilder *builder,
|
||||
float distance,
|
||||
GskStroke *stroke);
|
||||
|
||||
void gsk_contour_default_offset (const GskContour *contour,
|
||||
GskPathBuilder *builder,
|
||||
float distance,
|
||||
GskStroke *stroke);
|
||||
|
||||
G_END_DECLS
|
||||
2207
gsk/gskcurve.c
2207
gsk/gskcurve.c
File diff suppressed because it is too large
Load Diff
@@ -1,879 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020 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.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: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "gskcurveprivate.h"
|
||||
|
||||
/* {{{ Utilities */
|
||||
|
||||
static void
|
||||
get_tangent (const graphene_point_t *p0,
|
||||
const graphene_point_t *p1,
|
||||
graphene_vec2_t *t)
|
||||
{
|
||||
graphene_vec2_init (t, p1->x - p0->x, p1->y - p0->y);
|
||||
graphene_vec2_normalize (t, t);
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
acceptable (float t)
|
||||
{
|
||||
return 0 - FLT_EPSILON <= t && t <= 1 + FLT_EPSILON;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_sincosf (float angle,
|
||||
float *out_s,
|
||||
float *out_c)
|
||||
{
|
||||
#ifdef HAVE_SINCOSF
|
||||
sincosf (angle, out_s, out_c);
|
||||
#else
|
||||
*out_s = sinf (angle);
|
||||
*out_c = cosf (angle);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
align_points (const graphene_point_t *p,
|
||||
const graphene_point_t *a,
|
||||
const graphene_point_t *b,
|
||||
graphene_point_t *q,
|
||||
int n)
|
||||
{
|
||||
graphene_vec2_t n1;
|
||||
float angle;
|
||||
float s, c;
|
||||
|
||||
get_tangent (a, b, &n1);
|
||||
angle = - atan2 (graphene_vec2_get_y (&n1), graphene_vec2_get_x (&n1));
|
||||
_sincosf (angle, &s, &c);
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
q[i].x = (p[i].x - a->x) * c - (p[i].y - a->y) * s;
|
||||
q[i].y = (p[i].x - a->x) * s + (p[i].y - a->y) * c;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
find_point_on_line (const graphene_point_t *p1,
|
||||
const graphene_point_t *p2,
|
||||
const graphene_point_t *q,
|
||||
float *t)
|
||||
{
|
||||
if (p2->x != p1->x)
|
||||
*t = (q->x - p1->x) / (p2->x - p1->x);
|
||||
else
|
||||
*t = (q->y - p1->y) / (p2->y - p1->y);
|
||||
}
|
||||
|
||||
/* find solutions for at^2 + bt + c = 0 */
|
||||
static int
|
||||
solve_quadratic (float a, float b, float c, float t[2])
|
||||
{
|
||||
float d;
|
||||
int n = 0;
|
||||
|
||||
if (fabs (a) > 0.0001)
|
||||
{
|
||||
if (b*b > 4*a*c)
|
||||
{
|
||||
d = sqrt (b*b - 4*a*c);
|
||||
t[n++] = (-b + d)/(2*a);
|
||||
t[n++] = (-b - d)/(2*a);
|
||||
}
|
||||
else
|
||||
{
|
||||
t[n++] = -b / (2*a);
|
||||
}
|
||||
}
|
||||
else if (fabs (b) > 0.0001)
|
||||
{
|
||||
t[n++] = -c / b;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
filter_allowable (float t[3],
|
||||
int n)
|
||||
{
|
||||
float g[3];
|
||||
int j = 0;
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
if (0 < t[i] && t[i] < 1)
|
||||
g[j++] = t[i];
|
||||
for (int i = 0; i < j; i++)
|
||||
t[i] = g[i];
|
||||
return j;
|
||||
}
|
||||
|
||||
/* Solve P = 0 where P is
|
||||
* P = (1-t)^2*pa + 2*t*(1-t)*pb + t^2*pc
|
||||
*/
|
||||
static int
|
||||
get_quadratic_roots (float pa, float pb, float pc, float roots[2])
|
||||
{
|
||||
float a, b, c, d;
|
||||
int n_roots = 0;
|
||||
|
||||
a = pa - 2 * pb + pc;
|
||||
b = 2 * (pb - pa);
|
||||
c = pa;
|
||||
|
||||
d = b*b - 4*a*c;
|
||||
|
||||
if (d > 0.0001)
|
||||
{
|
||||
float q = sqrt (d);
|
||||
roots[n_roots] = (-b + q) / (2 * a);
|
||||
if (acceptable (roots[n_roots]))
|
||||
n_roots++;
|
||||
roots[n_roots] = (-b - q) / (2 * a);
|
||||
if (acceptable (roots[n_roots]))
|
||||
n_roots++;
|
||||
}
|
||||
else if (fabs (d) < 0.0001)
|
||||
{
|
||||
roots[n_roots] = -b / (2 * a);
|
||||
if (acceptable (roots[n_roots]))
|
||||
n_roots++;
|
||||
}
|
||||
|
||||
return n_roots;
|
||||
}
|
||||
|
||||
static float
|
||||
cuberoot (float v)
|
||||
{
|
||||
if (v < 0)
|
||||
return -pow (-v, 1.f / 3);
|
||||
return pow (v, 1.f / 3);
|
||||
}
|
||||
|
||||
/* Solve P = 0 where P is
|
||||
* P = (1-t)^3*pa + 3*t*(1-t)^2*pb + 3*t^2*(1-t)*pc + t^3*pd
|
||||
*/
|
||||
static int
|
||||
get_cubic_roots (float pa, float pb, float pc, float pd, float roots[3])
|
||||
{
|
||||
float a, b, c, d;
|
||||
float q, q2;
|
||||
float p, p3;
|
||||
float discriminant;
|
||||
float u1, v1, sd;
|
||||
int n_roots = 0;
|
||||
|
||||
d = -pa + 3*pb - 3*pc + pd;
|
||||
a = 3*pa - 6*pb + 3*pc;
|
||||
b = -3*pa + 3*pb;
|
||||
c = pa;
|
||||
|
||||
if (fabs (d) < 0.0001)
|
||||
{
|
||||
if (fabs (a) < 0.0001)
|
||||
{
|
||||
if (fabs (b) < 0.0001)
|
||||
return 0;
|
||||
|
||||
if (acceptable (-c / b))
|
||||
{
|
||||
roots[0] = -c / b;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
q = sqrt (b*b - 4*a*c);
|
||||
roots[n_roots] = (-b + q) / (2 * a);
|
||||
if (acceptable (roots[n_roots]))
|
||||
n_roots++;
|
||||
|
||||
roots[n_roots] = (-b - q) / (2 * a);
|
||||
if (acceptable (roots[n_roots]))
|
||||
n_roots++;
|
||||
|
||||
return n_roots;
|
||||
}
|
||||
|
||||
a /= d;
|
||||
b /= d;
|
||||
c /= d;
|
||||
|
||||
p = (3*b - a*a)/3;
|
||||
p3 = p/3;
|
||||
q = (2*a*a*a - 9*a*b + 27*c)/27;
|
||||
q2 = q/2;
|
||||
discriminant = q2*q2 + p3*p3*p3;
|
||||
|
||||
if (discriminant < 0)
|
||||
{
|
||||
float mp3 = -p/3;
|
||||
float mp33 = mp3*mp3*mp3;
|
||||
float r = sqrt (mp33);
|
||||
float t = -q / (2*r);
|
||||
float cosphi = t < -1 ? -1 : (t > 1 ? 1 : t);
|
||||
float phi = acos (cosphi);
|
||||
float crtr = cuberoot (r);
|
||||
float t1 = 2*crtr;
|
||||
|
||||
roots[n_roots] = t1 * cos (phi/3) - a/3;
|
||||
if (acceptable (roots[n_roots]))
|
||||
n_roots++;
|
||||
roots[n_roots] = t1 * cos ((phi + 2*M_PI) / 3) - a/3;
|
||||
if (acceptable (roots[n_roots]))
|
||||
n_roots++;
|
||||
roots[n_roots] = t1 * cos ((phi + 4*M_PI) / 3) - a/3;
|
||||
if (acceptable (roots[n_roots]))
|
||||
n_roots++;
|
||||
|
||||
return n_roots;
|
||||
}
|
||||
|
||||
if (discriminant == 0)
|
||||
{
|
||||
u1 = q2 < 0 ? cuberoot (-q2) : -cuberoot (q2);
|
||||
roots[n_roots] = 2*u1 - a/3;
|
||||
if (acceptable (roots[n_roots]))
|
||||
n_roots++;
|
||||
roots[n_roots] = -u1 - a/3;
|
||||
if (acceptable (roots[n_roots]))
|
||||
n_roots++;
|
||||
|
||||
return n_roots;
|
||||
}
|
||||
|
||||
sd = sqrt (discriminant);
|
||||
u1 = cuberoot (sd - q2);
|
||||
v1 = cuberoot (sd + q2);
|
||||
roots[n_roots] = u1 - v1 - a/3;
|
||||
if (acceptable (roots[n_roots]))
|
||||
n_roots++;
|
||||
|
||||
return n_roots;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* {{{ Cusps and inflections */
|
||||
|
||||
/* Get the points where the curvature of curve is
|
||||
* zero, or a maximum or minimum, inside the open
|
||||
* interval from 0 to 1.
|
||||
*/
|
||||
int
|
||||
gsk_curve_get_curvature_points (const GskCurve *curve,
|
||||
float t[3])
|
||||
{
|
||||
const graphene_point_t *pts = curve->cubic.points;
|
||||
graphene_point_t p[4];
|
||||
float a, b, c, d;
|
||||
float x, y, z;
|
||||
int n;
|
||||
|
||||
if (curve->op != GSK_PATH_CUBIC)
|
||||
return 0;
|
||||
|
||||
align_points (pts, &pts[0], &pts[3], p, 4);
|
||||
|
||||
a = p[2].x * p[1].y;
|
||||
b = p[3].x * p[1].y;
|
||||
c = p[1].x * p[2].y;
|
||||
d = p[3].x * p[2].y;
|
||||
|
||||
x = - 3*a + 2*b + 3*c - d;
|
||||
y = 3*a - b - 3*c;
|
||||
z = c - a;
|
||||
|
||||
n = solve_quadratic (x, y, z, t);
|
||||
return filter_allowable (t, n);
|
||||
}
|
||||
|
||||
/* Find cusps inside the open interval from 0 to 1.
|
||||
*
|
||||
* According to Stone & deRose, A Geometric Characterization
|
||||
* of Parametric Cubic curves, a necessary and sufficient
|
||||
* condition is that the first derivative vanishes.
|
||||
*/
|
||||
int
|
||||
gsk_curve_get_cusps (const GskCurve *curve,
|
||||
float t[2])
|
||||
{
|
||||
const graphene_point_t *pts = curve->cubic.points;
|
||||
graphene_point_t p[3];
|
||||
float ax, bx, cx;
|
||||
float ay, by, cy;
|
||||
float tx[3];
|
||||
int nx;
|
||||
int n = 0;
|
||||
|
||||
if (curve->op != GSK_PATH_CUBIC)
|
||||
return 0;
|
||||
|
||||
p[0].x = 3 * (pts[1].x - pts[0].x);
|
||||
p[0].y = 3 * (pts[1].y - pts[0].y);
|
||||
p[1].x = 3 * (pts[2].x - pts[1].x);
|
||||
p[1].y = 3 * (pts[2].y - pts[1].y);
|
||||
p[2].x = 3 * (pts[3].x - pts[2].x);
|
||||
p[2].y = 3 * (pts[3].y - pts[2].y);
|
||||
|
||||
ax = p[0].x - 2 * p[1].x + p[2].x;
|
||||
bx = - 2 * p[0].x + 2 * p[1].x;
|
||||
cx = p[0].x;
|
||||
|
||||
nx = solve_quadratic (ax, bx, cx, tx);
|
||||
nx = filter_allowable (tx, nx);
|
||||
|
||||
ay = p[0].y - 2 * p[1].y + p[2].y;
|
||||
by = - 2 * p[0].y + 2 * p[1].y;
|
||||
cy = p[0].y;
|
||||
|
||||
for (int i = 0; i < nx; i++)
|
||||
{
|
||||
float ti = tx[i];
|
||||
|
||||
if (0 < ti && ti < 1 &&
|
||||
fabs (ay * ti * ti + by * ti + cy) < 0.001)
|
||||
t[n++] = ti;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* {{{ Intersection */
|
||||
|
||||
static int
|
||||
line_intersect (const GskCurve *curve1,
|
||||
const GskCurve *curve2,
|
||||
float *t1,
|
||||
float *t2,
|
||||
graphene_point_t *p,
|
||||
int n)
|
||||
{
|
||||
const graphene_point_t *pts1 = curve1->line.points;
|
||||
const graphene_point_t *pts2 = curve2->line.points;
|
||||
float a1 = pts1[0].x - pts1[1].x;
|
||||
float b1 = pts1[0].y - pts1[1].y;
|
||||
float a2 = pts2[0].x - pts2[1].x;
|
||||
float b2 = pts2[0].y - pts2[1].y;
|
||||
float det = a1 * b2 - b1 * a2;
|
||||
|
||||
if (fabs(det) > 0.01)
|
||||
{
|
||||
float tt = ((pts1[0].x - pts2[0].x) * b2 - (pts1[0].y - pts2[0].y) * a2) / det;
|
||||
float ss = - ((pts1[0].y - pts2[0].y) * a1 - (pts1[0].x - pts2[0].x) * b1) / det;
|
||||
|
||||
if (acceptable (tt) && acceptable (ss))
|
||||
{
|
||||
p[0].x = pts1[0].x + tt * (pts1[1].x - pts1[0].x);
|
||||
p[0].y = pts1[0].y + tt * (pts1[1].y - pts1[0].y);
|
||||
|
||||
t1[0] = tt;
|
||||
t2[0] = ss;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else /* parallel lines */
|
||||
{
|
||||
float r = a1 * (pts1[1].y - pts2[0].y) - (pts1[1].x - pts2[0].x) * b1;
|
||||
float dist = (r * r) / (a1 * a1 + b1 * b1);
|
||||
float t, s, tt, ss;
|
||||
|
||||
if (dist > 0.01)
|
||||
return 0;
|
||||
|
||||
if (pts1[1].x != pts1[0].x)
|
||||
{
|
||||
t = (pts2[0].x - pts1[0].x) / (pts1[1].x - pts1[0].x);
|
||||
s = (pts2[1].x - pts1[0].x) / (pts1[1].x - pts1[0].x);
|
||||
}
|
||||
else
|
||||
{
|
||||
t = (pts2[0].y - pts1[0].y) / (pts1[1].y - pts1[0].y);
|
||||
s = (pts2[1].y - pts1[0].y) / (pts1[1].y - pts1[0].y);
|
||||
}
|
||||
|
||||
if ((t < 0 && s < 0) || (t > 1 && s > 1))
|
||||
return 0;
|
||||
|
||||
if (acceptable (t))
|
||||
{
|
||||
t1[0] = t;
|
||||
t2[0] = 0;
|
||||
p[0] = pts2[0];
|
||||
}
|
||||
else if (t < 0)
|
||||
{
|
||||
if (pts2[1].x != pts2[0].x)
|
||||
tt = (pts1[0].x - pts2[0].x) / (pts2[1].x - pts2[0].x);
|
||||
else
|
||||
tt = (pts1[0].y - pts2[0].y) / (pts2[1].y - pts2[0].y);
|
||||
|
||||
t1[0] = 0;
|
||||
t2[0] = tt;
|
||||
p[0] = pts1[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pts2[1].x != pts2[0].x)
|
||||
tt = (pts1[1].x - pts2[0].x) / (pts2[1].x - pts2[0].x);
|
||||
else
|
||||
tt = (pts1[1].y - pts2[0].y) / (pts2[1].y - pts2[0].y);
|
||||
|
||||
t1[0] = 1;
|
||||
t2[0] = tt;
|
||||
p[0] = pts1[1];
|
||||
}
|
||||
|
||||
if (acceptable (s))
|
||||
{
|
||||
if (t2[0] == 1)
|
||||
return 1;
|
||||
|
||||
t1[1] = s;
|
||||
t2[1] = 1;
|
||||
p[1] = pts2[1];
|
||||
}
|
||||
else if (s < 0)
|
||||
{
|
||||
if (t1[0] == 0)
|
||||
return 1;
|
||||
|
||||
if (pts2[1].x != pts2[0].x)
|
||||
ss = (pts1[0].x - pts2[0].x) / (pts2[1].x - pts2[0].x);
|
||||
else
|
||||
ss = (pts1[0].y - pts2[0].y) / (pts2[1].y - pts2[0].y);
|
||||
|
||||
t1[1] = 0;
|
||||
t2[1] = ss;
|
||||
p[1] = pts1[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (t1[0] == 1)
|
||||
return 1;
|
||||
|
||||
if (pts2[1].x != pts2[0].x)
|
||||
ss = (pts1[1].x - pts2[0].x) / (pts2[1].x - pts2[0].x);
|
||||
else
|
||||
ss = (pts1[1].y - pts2[0].y) / (pts2[1].y - pts2[0].y);
|
||||
|
||||
t1[1] = 1;
|
||||
t2[1] = ss;
|
||||
p[1] = pts1[1];
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
line_quad_intersect (const GskCurve *curve1,
|
||||
const GskCurve *curve2,
|
||||
float *t1,
|
||||
float *t2,
|
||||
graphene_point_t *p,
|
||||
int n)
|
||||
{
|
||||
const graphene_point_t *a = &curve1->line.points[0];
|
||||
const graphene_point_t *b = &curve1->line.points[1];
|
||||
graphene_point_t pts[4];
|
||||
float t[2];
|
||||
int m, i, j;
|
||||
|
||||
/* Rotate things to place curve1 on the x axis,
|
||||
* then solve curve2 for y == 0.
|
||||
*/
|
||||
align_points (curve2->quad.points, a, b, pts, 3);
|
||||
|
||||
m = get_quadratic_roots (pts[0].y, pts[1].y, pts[2].y, t);
|
||||
|
||||
j = 0;
|
||||
for (i = 0; i < m; i++)
|
||||
{
|
||||
t2[j] = t[i];
|
||||
gsk_curve_get_point (curve2, t2[j], &p[j]);
|
||||
find_point_on_line (a, b, &p[j], &t1[j]);
|
||||
if (acceptable (t1[j]))
|
||||
j++;
|
||||
if (j == n)
|
||||
break;
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
static int
|
||||
line_cubic_intersect (const GskCurve *curve1,
|
||||
const GskCurve *curve2,
|
||||
float *t1,
|
||||
float *t2,
|
||||
graphene_point_t *p,
|
||||
int n)
|
||||
{
|
||||
const graphene_point_t *a = &curve1->line.points[0];
|
||||
const graphene_point_t *b = &curve1->line.points[1];
|
||||
graphene_point_t pts[4];
|
||||
float t[3];
|
||||
int m, i, j;
|
||||
|
||||
/* Rotate things to place curve1 on the x axis,
|
||||
* then solve curve2 for y == 0.
|
||||
*/
|
||||
align_points (curve2->cubic.points, a, b, pts, 4);
|
||||
|
||||
m = get_cubic_roots (pts[0].y, pts[1].y, pts[2].y, pts[3].y, t);
|
||||
|
||||
j = 0;
|
||||
for (i = 0; i < m; i++)
|
||||
{
|
||||
t2[j] = t[i];
|
||||
gsk_curve_get_point (curve2, t2[j], &p[j]);
|
||||
find_point_on_line (a, b, &p[j], &t1[j]);
|
||||
if (acceptable (t1[j]))
|
||||
j++;
|
||||
if (j == n)
|
||||
break;
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
#define MAX_LEVEL 25
|
||||
#define TOLERANCE 0.001
|
||||
|
||||
static void
|
||||
cubic_intersect_recurse (const GskCurve *curve1,
|
||||
const GskCurve *curve2,
|
||||
float t1l,
|
||||
float t1r,
|
||||
float t2l,
|
||||
float t2r,
|
||||
float *t1,
|
||||
float *t2,
|
||||
graphene_point_t *p,
|
||||
int n,
|
||||
int *pos,
|
||||
int level)
|
||||
{
|
||||
GskCurve p11, p12, p21, p22;
|
||||
GskBoundingBox b1, b2;
|
||||
float d1, d2;
|
||||
|
||||
if (*pos == n)
|
||||
return;
|
||||
|
||||
if (level == MAX_LEVEL)
|
||||
return;
|
||||
|
||||
gsk_curve_get_bounds (curve1, &b1);
|
||||
gsk_curve_get_bounds (curve2, &b2);
|
||||
if (!gsk_bounding_box_intersection (&b1, &b2, NULL))
|
||||
return;
|
||||
|
||||
gsk_curve_get_tight_bounds (curve1, &b1);
|
||||
if (!gsk_bounding_box_intersection (&b1, &b2, NULL))
|
||||
return;
|
||||
|
||||
gsk_curve_get_tight_bounds (curve2, &b2);
|
||||
if (!gsk_bounding_box_intersection (&b1, &b2, NULL))
|
||||
return;
|
||||
|
||||
d1 = (t1r - t1l) / 2;
|
||||
d2 = (t2r - t2l) / 2;
|
||||
|
||||
if (b1.max.x - b1.min.x < TOLERANCE && b1.max.y - b1.min.y < TOLERANCE &&
|
||||
b2.max.x - b2.min.x < TOLERANCE && b2.max.y - b2.min.y < TOLERANCE)
|
||||
{
|
||||
graphene_point_t c;
|
||||
t1[*pos] = t1l + d1;
|
||||
t2[*pos] = t2l + d2;
|
||||
gsk_curve_get_point (curve1, 0.5, &c);
|
||||
|
||||
for (int i = 0; i < *pos; i++)
|
||||
{
|
||||
if (graphene_point_near (&c, &p[i], 0.1))
|
||||
return;
|
||||
}
|
||||
|
||||
p[*pos] = c;
|
||||
(*pos)++;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
gsk_curve_split (curve1, 0.5, &p11, &p12);
|
||||
gsk_curve_split (curve2, 0.5, &p21, &p22);
|
||||
|
||||
cubic_intersect_recurse (&p11, &p21, t1l, t1l + d1, t2l, t2l + d2, t1, t2, p, n, pos, level + 1);
|
||||
cubic_intersect_recurse (&p11, &p22, t1l, t1l + d1, t2l + d2, t2r, t1, t2, p, n, pos, level + 1);
|
||||
cubic_intersect_recurse (&p12, &p21, t1l + d1, t1r, t2l, t2l + d2, t1, t2, p, n, pos, level + 1);
|
||||
cubic_intersect_recurse (&p12, &p22, t1l + d1, t1r, t2l + d2, t2r, t1, t2, p, n, pos, level + 1);
|
||||
}
|
||||
|
||||
static int
|
||||
cubic_intersect (const GskCurve *curve1,
|
||||
const GskCurve *curve2,
|
||||
float *t1,
|
||||
float *t2,
|
||||
graphene_point_t *p,
|
||||
int n)
|
||||
{
|
||||
int pos = 0;
|
||||
|
||||
cubic_intersect_recurse (curve1, curve2, 0, 1, 0, 1, t1, t2, p, n, &pos, 0);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static void
|
||||
get_bounds (const GskCurve *curve,
|
||||
float tl,
|
||||
float tr,
|
||||
GskBoundingBox *bounds)
|
||||
{
|
||||
GskCurve c;
|
||||
|
||||
gsk_curve_segment (curve, tl, tr, &c);
|
||||
gsk_curve_get_tight_bounds (&c, bounds);
|
||||
}
|
||||
|
||||
static void
|
||||
general_intersect_recurse (const GskCurve *curve1,
|
||||
const GskCurve *curve2,
|
||||
float t1l,
|
||||
float t1r,
|
||||
float t2l,
|
||||
float t2r,
|
||||
float *t1,
|
||||
float *t2,
|
||||
graphene_point_t *p,
|
||||
int n,
|
||||
int *pos,
|
||||
int level)
|
||||
{
|
||||
GskBoundingBox b1, b2;
|
||||
float d1, d2;
|
||||
|
||||
if (*pos == n)
|
||||
return;
|
||||
|
||||
if (level == MAX_LEVEL)
|
||||
return;
|
||||
|
||||
get_bounds (curve1, t1l, t1r, &b1);
|
||||
get_bounds (curve2, t2l, t2r, &b2);
|
||||
|
||||
if (!gsk_bounding_box_intersection (&b1, &b2, NULL))
|
||||
return;
|
||||
|
||||
d1 = (t1r - t1l) / 2;
|
||||
d2 = (t2r - t2l) / 2;
|
||||
|
||||
if (b1.max.x - b1.min.x < TOLERANCE && b1.max.y - b1.min.y < TOLERANCE &&
|
||||
b2.max.x - b2.min.x < TOLERANCE && b2.max.y - b2.min.y < TOLERANCE)
|
||||
{
|
||||
graphene_point_t c;
|
||||
t1[*pos] = t1l + d1;
|
||||
t2[*pos] = t2l + d2;
|
||||
gsk_curve_get_point (curve1, t1[*pos], &c);
|
||||
|
||||
for (int i = 0; i < *pos; i++)
|
||||
{
|
||||
if (graphene_point_near (&c, &p[i], 0.1))
|
||||
return;
|
||||
}
|
||||
|
||||
p[*pos] = c;
|
||||
(*pos)++;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Note that in the conic case, we cannot just split the curves and
|
||||
* pass the two halves down, since splitting changes the parametrization,
|
||||
* and we need the t's to be valid parameters wrt to the original curve.
|
||||
*
|
||||
* So, instead, we determine the bounding boxes above by always starting
|
||||
* from the original curve. That is a bit less efficient, but also works
|
||||
* for conics.
|
||||
*/
|
||||
general_intersect_recurse (curve1, curve2, t1l, t1l + d1, t2l, t2l + d2, t1, t2, p, n, pos, level + 1);
|
||||
general_intersect_recurse (curve1, curve2, t1l, t1l + d1, t2l + d2, t2r, t1, t2, p, n, pos, level + 1);
|
||||
general_intersect_recurse (curve1, curve2, t1l + d1, t1r, t2l, t2l + d2, t1, t2, p, n, pos, level + 1);
|
||||
general_intersect_recurse (curve1, curve2, t1l + d1, t1r, t2l + d2, t2r, t1, t2, p, n, pos, level + 1);
|
||||
}
|
||||
|
||||
static int
|
||||
general_intersect (const GskCurve *curve1,
|
||||
const GskCurve *curve2,
|
||||
float *t1,
|
||||
float *t2,
|
||||
graphene_point_t *p,
|
||||
int n)
|
||||
{
|
||||
int pos = 0;
|
||||
|
||||
general_intersect_recurse (curve1, curve2, 0, 1, 0, 1, t1, t2, p, n, &pos, 0);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static int
|
||||
curve_self_intersect (const GskCurve *curve,
|
||||
float *t1,
|
||||
float *t2,
|
||||
graphene_point_t *p,
|
||||
int n)
|
||||
{
|
||||
float tt[3], ss[3], s;
|
||||
graphene_point_t pp[3];
|
||||
int m;
|
||||
GskCurve cs, ce;
|
||||
|
||||
if (curve->op != GSK_PATH_CUBIC)
|
||||
return 0;
|
||||
|
||||
s = 0.5;
|
||||
m = gsk_curve_get_curvature_points (curve, tt);
|
||||
for (int i = 0; i < m; i++)
|
||||
{
|
||||
if (gsk_curve_get_curvature (curve, tt[i], NULL) == 0)
|
||||
{
|
||||
s = tt[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gsk_curve_split (curve, s, &cs, &ce);
|
||||
|
||||
m = cubic_intersect (&cs, &ce, tt, ss, pp, 3);
|
||||
|
||||
if (m > 1)
|
||||
{
|
||||
/* One of the (at most 2) intersections we found
|
||||
* must be the common point where we split the curve.
|
||||
* It will have a t value of 1 and an s value of 0.
|
||||
*/
|
||||
if (fabs (tt[0] - 1) > 1e-3)
|
||||
{
|
||||
t1[0] = t2[0] = tt[0] * s;
|
||||
p[0] = pp[0];
|
||||
}
|
||||
else if (fabs (tt[1] - 1) > 1e-3)
|
||||
{
|
||||
t1[0] = t2[0] = tt[1] * s;
|
||||
p[0] = pp[1];
|
||||
}
|
||||
|
||||
if (n == 1)
|
||||
return 1;
|
||||
|
||||
if (fabs (ss[0]) > 1e-3)
|
||||
{
|
||||
t1[1] = t2[1] = s + ss[0] * (1 - s);
|
||||
p[1] = pp[0];
|
||||
}
|
||||
else if (fabs (ss[1]) > 1e-3)
|
||||
{
|
||||
t1[1] = t2[1] = s + ss[1] * (1 - s);
|
||||
p[1] = pp[1];
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
curve_equal (const GskCurve *c1,
|
||||
const GskCurve *c2)
|
||||
{
|
||||
gsize curve_size[] = {
|
||||
sizeof (GskLineCurve),
|
||||
sizeof (GskLineCurve),
|
||||
sizeof (GskLineCurve),
|
||||
sizeof (GskQuadCurve),
|
||||
sizeof (GskCubicCurve),
|
||||
sizeof (GskConicCurve)
|
||||
};
|
||||
|
||||
return c1->op == c2->op && memcmp (c1, c2, curve_size[c1->op]) == 0;
|
||||
}
|
||||
|
||||
/* Place intersections between the curves in p, and their Bezier positions
|
||||
* in t1 and t2, up to n. Return the number of intersections found.
|
||||
*
|
||||
* Note that two cubic Beziers can have up to 9 intersections.
|
||||
*/
|
||||
int
|
||||
gsk_curve_intersect (const GskCurve *curve1,
|
||||
const GskCurve *curve2,
|
||||
float *t1,
|
||||
float *t2,
|
||||
graphene_point_t *p,
|
||||
int n)
|
||||
{
|
||||
GskPathOperation op1 = curve1->op;
|
||||
GskPathOperation op2 = curve2->op;
|
||||
|
||||
if (op1 == GSK_PATH_CLOSE)
|
||||
op1 = GSK_PATH_LINE;
|
||||
|
||||
if (op2 == GSK_PATH_CLOSE)
|
||||
op2 = GSK_PATH_LINE;
|
||||
|
||||
if (curve_equal (curve1, curve2))
|
||||
return curve_self_intersect (curve1, t1, t2, p, n);
|
||||
|
||||
/* We special-case line-line and line-cubic intersections,
|
||||
* since we can solve them directly.
|
||||
* Everything else is done via bisection.
|
||||
*/
|
||||
if (op1 == GSK_PATH_LINE && op2 == GSK_PATH_LINE)
|
||||
return line_intersect (curve1, curve2, t1, t2, p, n);
|
||||
else if (op1 == GSK_PATH_LINE && op2 == GSK_PATH_QUAD)
|
||||
return line_quad_intersect (curve1, curve2, t1, t2, p, n);
|
||||
else if (op1 == GSK_PATH_QUAD && op2 == GSK_PATH_LINE)
|
||||
return line_quad_intersect (curve2, curve1, t2, t1, p, n);
|
||||
else if (op1 == GSK_PATH_LINE && op2 == GSK_PATH_CUBIC)
|
||||
return line_cubic_intersect (curve1, curve2, t1, t2, p, n);
|
||||
else if (op1 == GSK_PATH_CUBIC && op2 == GSK_PATH_LINE)
|
||||
return line_cubic_intersect (curve2, curve1, t2, t1, p, n);
|
||||
else if ((op1 == GSK_PATH_QUAD || op1 == GSK_PATH_CUBIC) &&
|
||||
(op2 == GSK_PATH_QUAD || op2 == GSK_PATH_CUBIC))
|
||||
return cubic_intersect (curve1, curve2, t1, t2, p, n);
|
||||
else
|
||||
return general_intersect (curve1, curve2, t1, t2, p, n);
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* vim:set foldmethod=marker expandtab: */
|
||||
@@ -1,184 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020 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>
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gskpathopprivate.h"
|
||||
#include "gskpath.h"
|
||||
#include "gskboundingboxprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef gpointer gskpathop;
|
||||
|
||||
typedef union _GskCurve GskCurve;
|
||||
|
||||
typedef struct _GskLineCurve GskLineCurve;
|
||||
typedef struct _GskQuadCurve GskQuadCurve;
|
||||
typedef struct _GskCubicCurve GskCubicCurve;
|
||||
typedef struct _GskConicCurve GskConicCurve;
|
||||
|
||||
struct _GskLineCurve
|
||||
{
|
||||
GskPathOperation op;
|
||||
|
||||
gboolean padding;
|
||||
|
||||
graphene_point_t points[2];
|
||||
};
|
||||
|
||||
struct _GskQuadCurve
|
||||
{
|
||||
GskPathOperation op;
|
||||
|
||||
gboolean has_coefficients;
|
||||
|
||||
graphene_point_t points[3];
|
||||
|
||||
graphene_point_t coeffs[3];
|
||||
};
|
||||
|
||||
struct _GskCubicCurve
|
||||
{
|
||||
GskPathOperation op;
|
||||
|
||||
gboolean has_coefficients;
|
||||
|
||||
graphene_point_t points[4];
|
||||
|
||||
graphene_point_t coeffs[4];
|
||||
};
|
||||
|
||||
struct _GskConicCurve
|
||||
{
|
||||
GskPathOperation op;
|
||||
|
||||
gboolean has_coefficients;
|
||||
|
||||
/* points[0], points[1], points[3] are the control points,
|
||||
* points[2].x is the weight
|
||||
*/
|
||||
graphene_point_t points[4];
|
||||
|
||||
graphene_point_t num[3];
|
||||
graphene_point_t denom[3];
|
||||
};
|
||||
|
||||
union _GskCurve
|
||||
{
|
||||
GskPathOperation op;
|
||||
GskLineCurve line;
|
||||
GskQuadCurve quad;
|
||||
GskCubicCurve cubic;
|
||||
GskConicCurve conic;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
GSK_CURVE_LINE_REASON_STRAIGHT,
|
||||
GSK_CURVE_LINE_REASON_SHORT
|
||||
} GskCurveLineReason;
|
||||
|
||||
typedef gboolean (* GskCurveAddLineFunc) (const graphene_point_t *from,
|
||||
const graphene_point_t *to,
|
||||
float from_progress,
|
||||
float to_progress,
|
||||
GskCurveLineReason reason,
|
||||
gpointer user_data);
|
||||
|
||||
typedef gboolean (* GskCurveAddCurveFunc) (GskPathOperation op,
|
||||
const graphene_point_t *pts,
|
||||
gsize n_pts,
|
||||
float weight,
|
||||
gpointer user_data);
|
||||
|
||||
void gsk_curve_init (GskCurve *curve,
|
||||
gskpathop op);
|
||||
void gsk_curve_init_foreach (GskCurve *curve,
|
||||
GskPathOperation op,
|
||||
const graphene_point_t *pts,
|
||||
gsize n_pts,
|
||||
float weight);
|
||||
|
||||
void gsk_curve_print (const GskCurve *curve,
|
||||
GString *string);
|
||||
|
||||
char * gsk_curve_to_string (const GskCurve *curve);
|
||||
|
||||
gskpathop gsk_curve_pathop (const GskCurve *curve);
|
||||
const graphene_point_t *gsk_curve_get_start_point (const GskCurve *curve);
|
||||
const graphene_point_t *gsk_curve_get_end_point (const GskCurve *curve);
|
||||
void gsk_curve_get_start_tangent (const GskCurve *curve,
|
||||
graphene_vec2_t *tangent);
|
||||
void gsk_curve_get_end_tangent (const GskCurve *curve,
|
||||
graphene_vec2_t *tangent);
|
||||
void gsk_curve_get_point (const GskCurve *curve,
|
||||
float progress,
|
||||
graphene_point_t *pos);
|
||||
void gsk_curve_get_tangent (const GskCurve *curve,
|
||||
float progress,
|
||||
graphene_vec2_t *tangent);
|
||||
void gsk_curve_reverse (const GskCurve *curve,
|
||||
GskCurve *reverse);
|
||||
void gsk_curve_split (const GskCurve *curve,
|
||||
float progress,
|
||||
GskCurve *start,
|
||||
GskCurve *end);
|
||||
void gsk_curve_segment (const GskCurve *curve,
|
||||
float start,
|
||||
float end,
|
||||
GskCurve *segment);
|
||||
gboolean gsk_curve_decompose (const GskCurve *curve,
|
||||
float tolerance,
|
||||
GskCurveAddLineFunc add_line_func,
|
||||
gpointer user_data);
|
||||
gboolean gsk_curve_decompose_curve (const GskCurve *curve,
|
||||
GskPathForeachFlags flags,
|
||||
float tolerance,
|
||||
GskCurveAddCurveFunc add_curve_func,
|
||||
gpointer user_data);
|
||||
|
||||
#define gsk_curve_builder_to(curve, builder) gsk_path_builder_pathop_to ((builder), gsk_curve_pathop (curve))
|
||||
|
||||
float gsk_curve_get_curvature (const GskCurve *curve,
|
||||
float t,
|
||||
graphene_point_t *center);
|
||||
void gsk_curve_get_bounds (const GskCurve *curve,
|
||||
GskBoundingBox *bounds);
|
||||
void gsk_curve_get_tight_bounds (const GskCurve *curve,
|
||||
GskBoundingBox *bounds);
|
||||
void gsk_curve_offset (const GskCurve *curve,
|
||||
float distance,
|
||||
GskCurve *offset_curve);
|
||||
|
||||
int gsk_curve_get_curvature_points (const GskCurve *curve,
|
||||
float t[3]);
|
||||
|
||||
int gsk_curve_get_cusps (const GskCurve *curve,
|
||||
float t[2]);
|
||||
|
||||
int gsk_curve_intersect (const GskCurve *curve1,
|
||||
const GskCurve *curve2,
|
||||
float *t1,
|
||||
float *t2,
|
||||
graphene_point_t *p,
|
||||
int n);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -15,7 +15,8 @@ static const GdkDebugKey gsk_debug_keys[] = {
|
||||
{ "geometry", GSK_DEBUG_GEOMETRY, "Show borders (when using cairo)" },
|
||||
{ "full-redraw", GSK_DEBUG_FULL_REDRAW, "Force full redraws" },
|
||||
{ "sync", GSK_DEBUG_SYNC, "Sync after each frame" },
|
||||
{ "staging", GSK_DEBUG_STAGING, "Use a staging image for texture upload (Vulkan only)" },
|
||||
{ "vulkan-staging-image", GSK_DEBUG_VULKAN_STAGING_IMAGE, "Use a staging image for Vulkan texture upload" },
|
||||
{ "vulkan-staging-buffer", GSK_DEBUG_VULKAN_STAGING_BUFFER, "Use a staging buffer for Vulkan texture upload" }
|
||||
};
|
||||
|
||||
static guint gsk_debug_flags;
|
||||
|
||||
@@ -18,7 +18,8 @@ typedef enum {
|
||||
GSK_DEBUG_GEOMETRY = 1 << 9,
|
||||
GSK_DEBUG_FULL_REDRAW = 1 << 10,
|
||||
GSK_DEBUG_SYNC = 1 << 11,
|
||||
GSK_DEBUG_STAGING = 1 << 12
|
||||
GSK_DEBUG_VULKAN_STAGING_IMAGE = 1 << 12,
|
||||
GSK_DEBUG_VULKAN_STAGING_BUFFER = 1 << 13
|
||||
} GskDebugFlags;
|
||||
|
||||
#define GSK_DEBUG_ANY ((1 << 13) - 1)
|
||||
|
||||
123
gsk/gskenums.h
123
gsk/gskenums.h
@@ -42,8 +42,6 @@
|
||||
* @GSK_REPEAT_NODE: A node that repeats the child's contents
|
||||
* @GSK_CLIP_NODE: A node that clips its child to a rectangular area
|
||||
* @GSK_ROUNDED_CLIP_NODE: A node that clips its child to a rounded rectangle
|
||||
* @GSK_FILL_NODE: A node that fills a path
|
||||
* @GSK_STROKE_NODE: A node that strokes a path
|
||||
* @GSK_SHADOW_NODE: A node that draws a shadow below its child
|
||||
* @GSK_BLEND_NODE: A node that blends two children together
|
||||
* @GSK_CROSS_FADE_NODE: A node that cross-fades between two children
|
||||
@@ -76,8 +74,6 @@ typedef enum {
|
||||
GSK_REPEAT_NODE,
|
||||
GSK_CLIP_NODE,
|
||||
GSK_ROUNDED_CLIP_NODE,
|
||||
GSK_FILL_NODE,
|
||||
GSK_STROKE_NODE,
|
||||
GSK_SHADOW_NODE,
|
||||
GSK_BLEND_NODE,
|
||||
GSK_CROSS_FADE_NODE,
|
||||
@@ -174,124 +170,6 @@ typedef enum {
|
||||
GSK_CORNER_BOTTOM_LEFT
|
||||
} GskCorner;
|
||||
|
||||
/**
|
||||
* GskFillRule:
|
||||
* @GSK_FILL_RULE_WINDING: If the path crosses the ray from
|
||||
* left-to-right, counts +1. If the path crosses the ray
|
||||
* from right to left, counts -1. (Left and right are determined
|
||||
* from the perspective of looking along the ray from the starting
|
||||
* point.) If the total count is non-zero, the point will be filled.
|
||||
* @GSK_FILL_RULE_EVEN_ODD: Counts the total number of
|
||||
* intersections, without regard to the orientation of the contour. If
|
||||
* the total number of intersections is odd, the point will be
|
||||
* filled.
|
||||
*
|
||||
* `GskFillRule` is used to select how paths are filled.
|
||||
*
|
||||
* Whether or not a point is included in the fill is determined by taking
|
||||
* a ray from that point to infinity and looking at intersections with the
|
||||
* path. The ray can be in any direction, as long as it doesn't pass through
|
||||
* the end point of a segment or have a tricky intersection such as
|
||||
* intersecting tangent to the path.
|
||||
*
|
||||
* (Note that filling is not actually implemented in this way. This
|
||||
* is just a description of the rule that is applied.)
|
||||
*
|
||||
* New entries may be added in future versions.
|
||||
*/
|
||||
typedef enum {
|
||||
GSK_FILL_RULE_WINDING,
|
||||
GSK_FILL_RULE_EVEN_ODD
|
||||
} GskFillRule;
|
||||
|
||||
/**
|
||||
* GskLineCap:
|
||||
* @GSK_LINE_CAP_BUTT: Start and stop the line exactly at the start
|
||||
* and end point
|
||||
* @GSK_LINE_CAP_ROUND: Use a round ending, the center of the circle
|
||||
* is the start or end point
|
||||
* @GSK_LINE_CAP_SQUARE: use squared ending, the center of the square
|
||||
* is the start or end point
|
||||
*
|
||||
* Specifies how to render the start and end points of contours or
|
||||
* dashes when stroking.
|
||||
*
|
||||
* The default line cap style is `GSK_LINE_CAP_BUTT`.
|
||||
*/
|
||||
typedef enum {
|
||||
GSK_LINE_CAP_BUTT,
|
||||
GSK_LINE_CAP_ROUND,
|
||||
GSK_LINE_CAP_SQUARE
|
||||
} GskLineCap;
|
||||
|
||||
/**
|
||||
* GskLineJoin:
|
||||
* @GSK_LINE_JOIN_MITER: Use a sharp angled corner
|
||||
* @GSK_LINE_JOIN_MITER_CLIP: Use a sharp, angled corner, at a distance
|
||||
* @GSK_LINE_JOIN_ROUND: Use a round join, the center of the circle is
|
||||
* the join point
|
||||
* @GSK_LINE_JOIN_BEVEL: use a cut-off join, the join is cut off at half
|
||||
* the line width from the joint point
|
||||
* @GSK_LINE_JOIN_ARCS: Use a sharp angled corner made from circles
|
||||
*
|
||||
* Specifies how to render the junction of two lines when stroking.
|
||||
*
|
||||
* See [method@Gsk.Stroke.set_miter_limit] for details on the difference
|
||||
* between `GSK_LINE_JOIN_MITER` and `GSK_LINE_JOIN_MITER_CLIP`.
|
||||
*
|
||||
* The default line join style is `GSK_LINE_JOIN_MITER`.
|
||||
**/
|
||||
typedef enum {
|
||||
GSK_LINE_JOIN_MITER,
|
||||
GSK_LINE_JOIN_MITER_CLIP,
|
||||
GSK_LINE_JOIN_ROUND,
|
||||
GSK_LINE_JOIN_BEVEL,
|
||||
GSK_LINE_JOIN_ARCS
|
||||
} GskLineJoin;
|
||||
|
||||
/**
|
||||
* GskPathOperation:
|
||||
* @GSK_PATH_MOVE: A move-to operation, with 1 point describing the target point.
|
||||
* @GSK_PATH_CLOSE: A close operation ending the current contour with a line back
|
||||
* to the starting point. Two points describe the start and end of the line.
|
||||
* @GSK_PATH_LINE: A line-to operation, with 2 points describing the start and
|
||||
* end point of a straight line.
|
||||
* @GSK_PATH_QUAD: A curve-to operation describing a quadratic Bézier curve
|
||||
* with 3 points describing the start point, the control point and the end
|
||||
* point of the curve.
|
||||
* @GSK_PATH_CUBIC: A curve-to operation describing a cubic Bézier curve with 4
|
||||
* points describing the start point, the two control points and the end point
|
||||
* of the curve.
|
||||
* @GSK_PATH_CONIC: A weighted quadratic Bézier curve with 3 points describing
|
||||
* the start point, control point and end point of the curve. A weight for the
|
||||
* curve will be passed, too.
|
||||
*
|
||||
* Path operations can be used to approximate a `GskPath`.
|
||||
*
|
||||
* More values may be added in the future.
|
||||
**/
|
||||
typedef enum {
|
||||
GSK_PATH_MOVE,
|
||||
GSK_PATH_CLOSE,
|
||||
GSK_PATH_LINE,
|
||||
GSK_PATH_QUAD,
|
||||
GSK_PATH_CUBIC,
|
||||
GSK_PATH_CONIC,
|
||||
} GskPathOperation;
|
||||
|
||||
/**
|
||||
* GskPathDirection:
|
||||
* @GSK_PATH_START: The side that leads to the start of the path
|
||||
* @GSK_PATH_END: The side that leads to the end of the path
|
||||
*
|
||||
* The values of the `GskPathDirection` enum are used to pick one
|
||||
* of the two sides of the path that at a given point on the path.
|
||||
*/
|
||||
typedef enum {
|
||||
GSK_PATH_START,
|
||||
GSK_PATH_END
|
||||
} GskPathDirection;
|
||||
|
||||
/**
|
||||
* GskSerializationError:
|
||||
* @GSK_SERIALIZATION_UNSUPPORTED_FORMAT: The format can not be identified
|
||||
@@ -396,3 +274,4 @@ typedef enum
|
||||
GSK_MASK_MODE_LUMINANCE,
|
||||
GSK_MASK_MODE_INVERTED_LUMINANCE
|
||||
} GskMaskMode;
|
||||
|
||||
|
||||
1386
gsk/gskpath.c
1386
gsk/gskpath.c
File diff suppressed because it is too large
Load Diff
149
gsk/gskpath.h
149
gsk/gskpath.h
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020 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>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined (__GSK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gsk/gsk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#include <gsk/gsktypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* GskPathForeachFlags:
|
||||
* @GSK_PATH_FOREACH_ALLOW_QUAD: Allow emission of `GSK_PATH_QUAD` operations
|
||||
* @GSK_PATH_FOREACH_ALLOW_CUBIC: Allow emission of `GSK_PATH_CUBIC` operations.
|
||||
* @GSK_PATH_FOREACH_ALLOW_CONIC: Allow emission of `GSK_PATH_CONIC` operations.
|
||||
*
|
||||
* Flags that can be passed to gsk_path_foreach() to enable additional
|
||||
* features.
|
||||
*
|
||||
* By default, [method@Gsk.Path.foreach] will only emit a path with all operations
|
||||
* flattened to straight lines to allow for maximum compatibility. The only
|
||||
* operations emitted will be `GSK_PATH_MOVE`, `GSK_PATH_LINE` and `GSK_PATH_CLOSE`.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GSK_PATH_FOREACH_ALLOW_QUAD = (1 << 0),
|
||||
GSK_PATH_FOREACH_ALLOW_CUBIC = (1 << 1),
|
||||
GSK_PATH_FOREACH_ALLOW_CONIC = (1 << 2),
|
||||
} GskPathForeachFlags;
|
||||
|
||||
/**
|
||||
* GskPathForeachFunc:
|
||||
* @op: The operation to perform
|
||||
* @pts: The points of the operation
|
||||
* @n_pts: The number of points
|
||||
* @weight: The weight for conic curves, or unused if not a conic curve.
|
||||
* @user_data: The user data provided with the function
|
||||
*
|
||||
* Prototype of the callback to iterate throught the operations of
|
||||
* a path.
|
||||
*
|
||||
* Returns: %TRUE to continue evaluating the path, %FALSE to
|
||||
* immediately abort and not call the function again.
|
||||
*/
|
||||
typedef gboolean (* GskPathForeachFunc) (GskPathOperation op,
|
||||
const graphene_point_t *pts,
|
||||
gsize n_pts,
|
||||
float weight,
|
||||
gpointer user_data);
|
||||
|
||||
#define GSK_TYPE_PATH (gsk_path_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gsk_path_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPath * gsk_path_ref (GskPath *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_unref (GskPath *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_print (GskPath *self,
|
||||
GString *string);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
char * gsk_path_to_string (GskPath *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPath * gsk_path_parse (const char *string);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_to_cairo (GskPath *self,
|
||||
cairo_t *cr);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gsk_path_is_empty (GskPath *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gsk_path_get_bounds (GskPath *self,
|
||||
graphene_rect_t *bounds);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gsk_path_foreach (GskPath *self,
|
||||
GskPathForeachFlags flags,
|
||||
GskPathForeachFunc func,
|
||||
gpointer user_data);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gsk_path_dash (GskPath *path,
|
||||
GskStroke *stroke,
|
||||
float tolerance,
|
||||
GskPathForeachFunc func,
|
||||
gpointer user_data);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPath * gsk_path_stroke (GskPath *self,
|
||||
GskStroke *stroke);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPath * gsk_path_offset (GskPath *self,
|
||||
float distance,
|
||||
GskStroke *stroke);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPath * gsk_path_union (GskPath *first,
|
||||
GskPath *second,
|
||||
GskFillRule fill_rule);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPath * gsk_path_intersection (GskPath *first,
|
||||
GskPath *second,
|
||||
GskFillRule fill_rule);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPath * gsk_path_difference (GskPath *first,
|
||||
GskPath *second,
|
||||
GskFillRule fill_rule);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPath * gsk_path_symmetric_difference (GskPath *first,
|
||||
GskPath *second,
|
||||
GskFillRule fill_rule);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPath * gsk_path_simplify (GskPath *self,
|
||||
GskFillRule fill_rule);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskPath, gsk_path_unref)
|
||||
|
||||
G_END_DECLS
|
||||
1062
gsk/gskpathbuilder.c
1062
gsk/gskpathbuilder.c
File diff suppressed because it is too large
Load Diff
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020 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>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined (__GSK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gsk/gsk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#include <gsk/gskroundedrect.h>
|
||||
#include <gsk/gsktypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_PATH_BUILDER (gsk_path_builder_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gsk_path_builder_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPathBuilder * gsk_path_builder_new (void);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPathBuilder * gsk_path_builder_ref (GskPathBuilder *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_unref (GskPathBuilder *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPath * gsk_path_builder_free_to_path (GskPathBuilder *self) G_GNUC_WARN_UNUSED_RESULT;
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPath * gsk_path_builder_to_path (GskPathBuilder *self) G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
const graphene_point_t *gsk_path_builder_get_current_point (GskPathBuilder *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_add_path (GskPathBuilder *self,
|
||||
GskPath *path);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_add_reverse_path (GskPathBuilder *self,
|
||||
GskPath *path);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_add_cairo_path (GskPathBuilder *self,
|
||||
const cairo_path_t *path);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_add_layout (GskPathBuilder *self,
|
||||
PangoLayout *layout);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_add_rect (GskPathBuilder *self,
|
||||
const graphene_rect_t *rect);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_add_rounded_rect (GskPathBuilder *self,
|
||||
const GskRoundedRect *rect);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_add_circle (GskPathBuilder *self,
|
||||
const graphene_point_t *center,
|
||||
float radius);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_add_ellipse (GskPathBuilder *self,
|
||||
const graphene_point_t *center,
|
||||
const graphene_size_t *radius);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_add_segment (GskPathBuilder *self,
|
||||
GskPathMeasure *measure,
|
||||
float start,
|
||||
float end);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_move_to (GskPathBuilder *self,
|
||||
float x,
|
||||
float y);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_rel_move_to (GskPathBuilder *self,
|
||||
float x,
|
||||
float y);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_line_to (GskPathBuilder *self,
|
||||
float x,
|
||||
float y);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_rel_line_to (GskPathBuilder *self,
|
||||
float x,
|
||||
float y);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_quad_to (GskPathBuilder *self,
|
||||
float x1,
|
||||
float y1,
|
||||
float x2,
|
||||
float y2);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_rel_quad_to (GskPathBuilder *self,
|
||||
float x1,
|
||||
float y1,
|
||||
float x2,
|
||||
float y2);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_cubic_to (GskPathBuilder *self,
|
||||
float x1,
|
||||
float y1,
|
||||
float x2,
|
||||
float y2,
|
||||
float x3,
|
||||
float y3);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_rel_cubic_to (GskPathBuilder *self,
|
||||
float x1,
|
||||
float y1,
|
||||
float x2,
|
||||
float y2,
|
||||
float x3,
|
||||
float y3);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_conic_to (GskPathBuilder *self,
|
||||
float x1,
|
||||
float y1,
|
||||
float x2,
|
||||
float y2,
|
||||
float weight);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_rel_conic_to (GskPathBuilder *self,
|
||||
float x1,
|
||||
float y1,
|
||||
float x2,
|
||||
float y2,
|
||||
float weight);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_close (GskPathBuilder *self);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskPathBuilder, gsk_path_builder_unref)
|
||||
|
||||
G_END_DECLS
|
||||
@@ -1,304 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020 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 "gskcontourprivate.h"
|
||||
#include "gskcurveprivate.h"
|
||||
#include "gskpathprivate.h"
|
||||
#include "gskstrokeprivate.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float offset; /* how much of the current dash we've spent */
|
||||
gsize dash_index; /* goes from 0 to n_dash * 2, so we don't have to care about on/off
|
||||
for uneven dashes */
|
||||
gboolean on; /* If we're currently dashing or not */
|
||||
gboolean may_close; /* TRUE if we haven't turned the dash off in this contour */
|
||||
gboolean needs_move_to; /* If we have emitted the initial move_to() yet */
|
||||
enum {
|
||||
NORMAL, /* no special behavior required */
|
||||
SKIP, /* skip the next dash */
|
||||
ONLY, /* only do the first dash */
|
||||
DONE /* done with the first dash */
|
||||
} first_dash_behavior; /* How to handle the first dash in the loop. We loop closed contours
|
||||
twice to make sure the first dash and the last dash can get joined */
|
||||
|
||||
GskCurve curve; /* Curve we are currently processing */
|
||||
|
||||
float collect_start; /* We're collecting multiple line segments when decomposing. */
|
||||
float collect_length; /* No need to emit a curve for every line segment when the dash is long enough. */
|
||||
|
||||
/* from the stroke */
|
||||
float *dash;
|
||||
gsize n_dash;
|
||||
float dash_length;
|
||||
float dash_offset;
|
||||
|
||||
float tolerance;
|
||||
GskPathForeachFunc func;
|
||||
gpointer user_data;
|
||||
} GskPathDash;
|
||||
|
||||
static void
|
||||
gsk_path_dash_setup (GskPathDash *self)
|
||||
{
|
||||
self->offset = fmodf (self->dash_offset, 2 * self->dash_length);
|
||||
|
||||
self->dash_index = 0;
|
||||
self->on = TRUE;
|
||||
self->may_close = TRUE;
|
||||
while (self->offset > self->dash[self->dash_index % self->n_dash])
|
||||
{
|
||||
self->offset -= self->dash[self->dash_index % self->n_dash];
|
||||
self->dash_index++;
|
||||
self->on = !self->on;
|
||||
}
|
||||
if (self->first_dash_behavior != ONLY)
|
||||
self->needs_move_to = TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_path_dash_ensure_move_to (GskPathDash *self,
|
||||
const graphene_point_t *pt)
|
||||
{
|
||||
if (!self->needs_move_to)
|
||||
return TRUE;
|
||||
|
||||
if (!self->func (GSK_PATH_MOVE, pt, 1, 0, self->user_data))
|
||||
return FALSE;
|
||||
|
||||
self->needs_move_to = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_path_dash_add_line_segment (const graphene_point_t *start,
|
||||
const graphene_point_t *end,
|
||||
float t_start,
|
||||
float t_end,
|
||||
GskCurveLineReason reason,
|
||||
gpointer user_data)
|
||||
{
|
||||
GskPathDash *self = user_data;
|
||||
float remaining, length, t_step;
|
||||
|
||||
length = graphene_point_distance (start, end, NULL, NULL);
|
||||
if (self->collect_length)
|
||||
{
|
||||
t_start = self->collect_start;
|
||||
length += self->collect_length;
|
||||
self->collect_length = 0;
|
||||
}
|
||||
|
||||
t_step = t_end - t_start;
|
||||
remaining = length;
|
||||
|
||||
while (remaining)
|
||||
{
|
||||
float piece;
|
||||
|
||||
if (self->offset + remaining <= self->dash[self->dash_index % self->n_dash])
|
||||
{
|
||||
/* try collecting multiple line segments */
|
||||
if (t_end < 1.0)
|
||||
{
|
||||
self->collect_start = t_start + t_step * (length - remaining) / length;
|
||||
self->collect_length = remaining;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
piece = remaining;
|
||||
}
|
||||
else
|
||||
piece = self->dash[self->dash_index % self->n_dash] - self->offset;
|
||||
|
||||
if (self->on)
|
||||
{
|
||||
if (self->first_dash_behavior != SKIP)
|
||||
{
|
||||
GskCurve segment;
|
||||
|
||||
if (piece)
|
||||
{
|
||||
gsk_curve_segment (&self->curve,
|
||||
t_start + t_step * (length - remaining) / length,
|
||||
t_start + t_step * (length - (remaining - piece)) / length,
|
||||
&segment);
|
||||
if (!gsk_path_dash_ensure_move_to (self, gsk_curve_get_start_point (&segment)))
|
||||
return FALSE;
|
||||
|
||||
if (!gsk_pathop_foreach (gsk_curve_pathop (&segment), self->func, self->user_data))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
graphene_point_t p;
|
||||
|
||||
gsk_curve_get_point (&self->curve, t_start + t_step * (length - remaining) / length, &p);
|
||||
if (!gsk_path_dash_ensure_move_to (self, &p))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self->may_close = FALSE;
|
||||
if (self->first_dash_behavior == ONLY)
|
||||
{
|
||||
self->first_dash_behavior = DONE;
|
||||
return FALSE;
|
||||
}
|
||||
self->first_dash_behavior = NORMAL;
|
||||
}
|
||||
|
||||
if (self->offset + remaining <= self->dash[self->dash_index % self->n_dash])
|
||||
{
|
||||
self->offset += remaining;
|
||||
remaining = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
remaining -= piece;
|
||||
self->offset = 0;
|
||||
self->dash_index++;
|
||||
self->dash_index %= 2 * self->n_dash;
|
||||
self->on = !self->on;
|
||||
self->needs_move_to = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_path_dash_foreach (GskPathOperation op,
|
||||
const graphene_point_t *pts,
|
||||
gsize n_pts,
|
||||
float weight,
|
||||
gpointer user_data)
|
||||
{
|
||||
GskPathDash *self = user_data;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case GSK_PATH_MOVE:
|
||||
gsk_path_dash_setup (self);
|
||||
break;
|
||||
|
||||
case GSK_PATH_CLOSE:
|
||||
if (self->may_close)
|
||||
{
|
||||
if (graphene_point_equal (&pts[0], &pts[1]))
|
||||
return self->func (GSK_PATH_CLOSE, pts, 2, 0, self->user_data);
|
||||
}
|
||||
else
|
||||
op = GSK_PATH_LINE;
|
||||
G_GNUC_FALLTHROUGH;
|
||||
|
||||
case GSK_PATH_LINE:
|
||||
case GSK_PATH_QUAD:
|
||||
case GSK_PATH_CUBIC:
|
||||
case GSK_PATH_CONIC:
|
||||
gsk_curve_init_foreach (&self->curve, op, pts, n_pts, weight);
|
||||
if (!gsk_curve_decompose (&self->curve, self->tolerance, gsk_path_dash_add_line_segment, self))
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gsk_contour_dash (const GskContour *contour,
|
||||
GskStroke *stroke,
|
||||
float tolerance,
|
||||
GskPathForeachFunc func,
|
||||
gpointer user_data)
|
||||
{
|
||||
GskPathDash self = {
|
||||
.offset = 0,
|
||||
.dash = stroke->dash,
|
||||
.n_dash = stroke->n_dash,
|
||||
.dash_length = stroke->dash_length,
|
||||
.dash_offset = stroke->dash_offset,
|
||||
.tolerance = tolerance,
|
||||
.func = func,
|
||||
.user_data = user_data
|
||||
};
|
||||
gboolean is_closed = gsk_contour_get_flags (contour) & GSK_PATH_CLOSED ? TRUE : FALSE;
|
||||
|
||||
self.first_dash_behavior = is_closed ? SKIP : NORMAL;
|
||||
if (!gsk_contour_foreach (contour, tolerance, gsk_path_dash_foreach, &self))
|
||||
return FALSE;
|
||||
|
||||
if (is_closed)
|
||||
{
|
||||
if (self.first_dash_behavior == NORMAL)
|
||||
self.first_dash_behavior = ONLY;
|
||||
else
|
||||
self.first_dash_behavior = NORMAL;
|
||||
self.needs_move_to = !self.on;
|
||||
if (!gsk_contour_foreach (contour, tolerance, gsk_path_dash_foreach, &self) &&
|
||||
self.first_dash_behavior != DONE)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_dash:
|
||||
* @path: the `GskPath` to dash
|
||||
* @stroke: the stroke containing the dash parameters
|
||||
* @tolerance: tolerance to use while dashing
|
||||
* @func: (scope call) (closure user_data): the function to call for operations
|
||||
* @user_data: (nullable): user data passed to @func
|
||||
*
|
||||
* Calls @func for every operation of the path that is the result
|
||||
* of dashing @path with the dash pattern from @stroke.
|
||||
*
|
||||
* Returns: `FALSE` if @func returned FALSE`, `TRUE` otherwise.
|
||||
*/
|
||||
gboolean
|
||||
gsk_path_dash (GskPath *path,
|
||||
GskStroke *stroke,
|
||||
float tolerance,
|
||||
GskPathForeachFunc func,
|
||||
gpointer user_data)
|
||||
{
|
||||
gsize i;
|
||||
|
||||
/* Dashing disabled, no need to do any work */
|
||||
if (stroke->dash_length <= 0)
|
||||
return gsk_path_foreach (path, -1, func, user_data);
|
||||
|
||||
for (i = 0; i < gsk_path_get_n_contours (path); i++)
|
||||
{
|
||||
if (!gsk_contour_dash (gsk_path_get_contour (path, i), stroke, tolerance, func, user_data))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -1,490 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020 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 "gskpathmeasure.h"
|
||||
#include "gskpathbuilder.h"
|
||||
|
||||
#include "gskpathbuilder.h"
|
||||
#include "gskpathpointprivate.h"
|
||||
#include "gskpathprivate.h"
|
||||
|
||||
/**
|
||||
* `GskPathMeasure` is an object that allows measurements
|
||||
* on `GskPath`s such as determining the length of the path.
|
||||
*
|
||||
* Many measuring operations require approximating the path
|
||||
* with simpler shapes. Therefore, a `GskPathMeasure` has
|
||||
* a tolerance that determines what amount is required
|
||||
* for such approximations.
|
||||
*
|
||||
* A `GskPathMeasure` struct is a reference counted struct
|
||||
* and should be treated as opaque.
|
||||
*/
|
||||
|
||||
typedef struct _GskContourMeasure GskContourMeasure;
|
||||
|
||||
struct _GskContourMeasure
|
||||
{
|
||||
float length;
|
||||
gpointer contour_data;
|
||||
};
|
||||
|
||||
struct _GskPathMeasure
|
||||
{
|
||||
/*< private >*/
|
||||
guint ref_count;
|
||||
|
||||
GskPath *path;
|
||||
float tolerance;
|
||||
|
||||
float length;
|
||||
gsize n_contours;
|
||||
GskContourMeasure measures[];
|
||||
};
|
||||
|
||||
G_DEFINE_BOXED_TYPE (GskPathMeasure, gsk_path_measure,
|
||||
gsk_path_measure_ref,
|
||||
gsk_path_measure_unref)
|
||||
|
||||
/**
|
||||
* gsk_path_measure_new:
|
||||
* @path: the path to measure
|
||||
*
|
||||
* Creates a measure object for the given @path.
|
||||
*
|
||||
* Returns: a new `GskPathMeasure` representing @path
|
||||
*/
|
||||
GskPathMeasure *
|
||||
gsk_path_measure_new (GskPath *path)
|
||||
{
|
||||
return gsk_path_measure_new_with_tolerance (path, GSK_PATH_TOLERANCE_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_measure_new_with_tolerance:
|
||||
* @path: the path to measure
|
||||
* @tolerance: the tolerance for measuring operations
|
||||
*
|
||||
* Creates a measure object for the given @path and @tolerance.
|
||||
*
|
||||
* Returns: a new `GskPathMeasure` representing @path
|
||||
*/
|
||||
GskPathMeasure *
|
||||
gsk_path_measure_new_with_tolerance (GskPath *path,
|
||||
float tolerance)
|
||||
{
|
||||
GskPathMeasure *self;
|
||||
gsize i, n_contours;
|
||||
|
||||
g_return_val_if_fail (path != NULL, NULL);
|
||||
g_return_val_if_fail (tolerance > 0, NULL);
|
||||
|
||||
n_contours = gsk_path_get_n_contours (path);
|
||||
|
||||
self = g_malloc0 (sizeof (GskPathMeasure) + n_contours * sizeof (GskContourMeasure));
|
||||
|
||||
self->ref_count = 1;
|
||||
self->path = gsk_path_ref (path);
|
||||
self->tolerance = tolerance;
|
||||
self->n_contours = n_contours;
|
||||
|
||||
for (i = 0; i < n_contours; i++)
|
||||
{
|
||||
self->measures[i].contour_data = gsk_contour_init_measure (gsk_path_get_contour (path, i),
|
||||
self->tolerance,
|
||||
&self->measures[i].length);
|
||||
self->length += self->measures[i].length;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_measure_ref:
|
||||
* @self: a `GskPathMeasure`
|
||||
*
|
||||
* Increases the reference count of a `GskPathMeasure` by one.
|
||||
*
|
||||
* Returns: the passed in `GskPathMeasure`.
|
||||
*/
|
||||
GskPathMeasure *
|
||||
gsk_path_measure_ref (GskPathMeasure *self)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, NULL);
|
||||
|
||||
self->ref_count++;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_measure_unref:
|
||||
* @self: a `GskPathMeasure`
|
||||
*
|
||||
* Decreases the reference count of a `GskPathMeasure` by one.
|
||||
*
|
||||
* If the resulting reference count is zero, frees the object.
|
||||
*/
|
||||
void
|
||||
gsk_path_measure_unref (GskPathMeasure *self)
|
||||
{
|
||||
gsize i;
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (self->ref_count > 0);
|
||||
|
||||
self->ref_count--;
|
||||
if (self->ref_count > 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < self->n_contours; i++)
|
||||
{
|
||||
gsk_contour_free_measure (gsk_path_get_contour (self->path, i),
|
||||
self->measures[i].contour_data);
|
||||
}
|
||||
|
||||
gsk_path_unref (self->path);
|
||||
g_free (self);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_measure_get_path:
|
||||
* @self: a `GskPathMeasure`
|
||||
*
|
||||
* Returns the path that the measure was created for.
|
||||
*
|
||||
* Returns: (transfer none): the path of @self
|
||||
*/
|
||||
GskPath *
|
||||
gsk_path_measure_get_path (GskPathMeasure *self)
|
||||
{
|
||||
return self->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_measure_get_tolerance:
|
||||
* @self: a `GskPathMeasure`
|
||||
*
|
||||
* Returns the tolerance that the measure was created with.
|
||||
*
|
||||
* Returns: the tolerance of @self
|
||||
*/
|
||||
float
|
||||
gsk_path_measure_get_tolerance (GskPathMeasure *self)
|
||||
{
|
||||
return self->tolerance;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_measure_get_length:
|
||||
* @self: a `GskPathMeasure`
|
||||
*
|
||||
* Gets the length of the path being measured.
|
||||
*
|
||||
* The length is cached, so this function does not do any work.
|
||||
*
|
||||
* Returns: The length of the path measured by @self
|
||||
*/
|
||||
float
|
||||
gsk_path_measure_get_length (GskPathMeasure *self)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, 0);
|
||||
|
||||
return self->length;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_measure_is_closed:
|
||||
* @self: a `GskPathMeasure`
|
||||
*
|
||||
* Returns if the path being measured represents a single closed
|
||||
* contour.
|
||||
*
|
||||
* Returns: `TRUE` if the current path is closed
|
||||
*/
|
||||
gboolean
|
||||
gsk_path_measure_is_closed (GskPathMeasure *self)
|
||||
{
|
||||
const GskContour *contour;
|
||||
|
||||
g_return_val_if_fail (self != NULL, FALSE);
|
||||
|
||||
/* XXX: is the empty path closed? Currently it's not */
|
||||
if (self->n_contours != 1)
|
||||
return FALSE;
|
||||
|
||||
contour = gsk_path_get_contour (self->path, 0);
|
||||
return gsk_contour_get_flags (contour) & GSK_PATH_CLOSED ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static float
|
||||
gsk_path_measure_clamp_distance (GskPathMeasure *self,
|
||||
float distance)
|
||||
{
|
||||
if (isnan (distance))
|
||||
return 0;
|
||||
|
||||
return CLAMP (distance, 0, self->length);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_measure_in_fill:
|
||||
* @self: a `GskPathMeasure`
|
||||
* @point: the point to test
|
||||
* @fill_rule: the fill rule to follow
|
||||
*
|
||||
* Returns whether the given point is inside the area
|
||||
* that would be affected if the path was filled according
|
||||
* to @fill_rule.
|
||||
*
|
||||
* Returns: `TRUE` if @point is inside
|
||||
*/
|
||||
gboolean
|
||||
gsk_path_measure_in_fill (GskPathMeasure *self,
|
||||
const graphene_point_t *point,
|
||||
GskFillRule fill_rule)
|
||||
{
|
||||
int winding = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < self->n_contours; i++)
|
||||
winding += gsk_contour_get_winding (gsk_path_get_contour (self->path, i),
|
||||
self->measures[i].contour_data,
|
||||
point);
|
||||
|
||||
switch (fill_rule)
|
||||
{
|
||||
case GSK_FILL_RULE_EVEN_ODD:
|
||||
return winding & 1;
|
||||
case GSK_FILL_RULE_WINDING:
|
||||
return winding != 0;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_path_builder_add_segment_chunk (GskPathBuilder *self,
|
||||
GskPathMeasure *measure,
|
||||
gboolean emit_move_to,
|
||||
float start,
|
||||
float end)
|
||||
{
|
||||
g_assert (start < end);
|
||||
|
||||
for (gsize i = 0; i < measure->n_contours; i++)
|
||||
{
|
||||
if (measure->measures[i].length < start)
|
||||
{
|
||||
start -= measure->measures[i].length;
|
||||
end -= measure->measures[i].length;
|
||||
}
|
||||
else if (start > 0 || end < measure->measures[i].length)
|
||||
{
|
||||
float len = MIN (end, measure->measures[i].length);
|
||||
gsk_contour_add_segment (gsk_path_get_contour (measure->path, i),
|
||||
self,
|
||||
measure->measures[i].contour_data,
|
||||
emit_move_to,
|
||||
start,
|
||||
len);
|
||||
end -= len;
|
||||
start = 0;
|
||||
if (end <= 0)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
end -= measure->measures[i].length;
|
||||
gsk_path_builder_add_contour (self, gsk_contour_dup (gsk_path_get_contour (measure->path, i)));
|
||||
}
|
||||
emit_move_to = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_add_segment:
|
||||
* @self: a `GskPathBuilder`
|
||||
* @measure: the `GskPathMeasure` to take the segment to
|
||||
* @start: start distance into the path
|
||||
* @end: end distance into the path
|
||||
*
|
||||
* Adds to @self the segment of @measure from @start to @end.
|
||||
*
|
||||
* The distances are given relative to the length of @measure's path,
|
||||
* from 0 for the beginning of the path to its length for the end
|
||||
* of the path. The values will be clamped to that range. The length
|
||||
* can be obtained with [method@Gsk.PathMeasure.get_length].
|
||||
*
|
||||
* If @start >= @end after clamping, the path will first add the segment
|
||||
* from @start to the end of the path, and then add the segment from
|
||||
* the beginning to @end. If the path is closed, these segments will
|
||||
* be connected.
|
||||
*/
|
||||
void
|
||||
gsk_path_builder_add_segment (GskPathBuilder *self,
|
||||
GskPathMeasure *measure,
|
||||
float start,
|
||||
float end)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (measure != NULL);
|
||||
|
||||
start = gsk_path_measure_clamp_distance (measure, start);
|
||||
end = gsk_path_measure_clamp_distance (measure, end);
|
||||
|
||||
if (start < end)
|
||||
{
|
||||
gsk_path_builder_add_segment_chunk (self, measure, TRUE, start, end);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the path is closed, we can connect the 2 subpaths. */
|
||||
gboolean closed = gsk_path_measure_is_closed (measure);
|
||||
gboolean need_move_to = !closed;
|
||||
|
||||
if (start < measure->length)
|
||||
gsk_path_builder_add_segment_chunk (self, measure,
|
||||
TRUE,
|
||||
start, measure->length);
|
||||
else
|
||||
need_move_to = TRUE;
|
||||
|
||||
if (end > 0)
|
||||
gsk_path_builder_add_segment_chunk (self, measure,
|
||||
need_move_to,
|
||||
0, end);
|
||||
if (start == end && closed)
|
||||
gsk_path_builder_close (self);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_measure_get_point:
|
||||
* @self: a `GskPathMeasure`
|
||||
* @distance: the distance
|
||||
*
|
||||
* Returns a `GskPathPoint` representing the point at the given
|
||||
* distance into the path.
|
||||
*
|
||||
* An empty path has no points, so `NULL` is returned in that case.
|
||||
*
|
||||
* Returns: (transfer full) (nullable): a newly allocated `GskPathPoint`
|
||||
*/
|
||||
GskPathPoint *
|
||||
gsk_path_measure_get_point (GskPathMeasure *self,
|
||||
float distance)
|
||||
{
|
||||
gsize i;
|
||||
float contour_offset;
|
||||
float offset;
|
||||
const GskContour *contour;
|
||||
|
||||
g_return_val_if_fail (self != NULL, NULL);
|
||||
|
||||
if (self->n_contours == 0)
|
||||
return NULL;
|
||||
|
||||
contour_offset = 0;
|
||||
offset = gsk_path_measure_clamp_distance (self, distance);
|
||||
|
||||
for (i = 0; i < self->n_contours - 1; i++)
|
||||
{
|
||||
if (offset < self->measures[i].length)
|
||||
break;
|
||||
|
||||
contour_offset += self->measures[i].length;
|
||||
offset -= self->measures[i].length;
|
||||
}
|
||||
|
||||
g_assert (0 <= i && i < self->n_contours);
|
||||
|
||||
offset = CLAMP (offset, 0, self->measures[i].length);
|
||||
|
||||
contour = gsk_path_get_contour (self->path, i);
|
||||
|
||||
return gsk_path_point_new (self,
|
||||
contour, self->measures[i].contour_data,
|
||||
contour_offset, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_measure_get_closest_point:
|
||||
* @self: a `GskPathMeasure`
|
||||
* @point: the point to fond the closest point to
|
||||
* @threshold: The maximum allowed distance between the path and @point.
|
||||
* Use `INFINITY` to look for any point.
|
||||
*
|
||||
* Returns a `GskPathPoint` representing the point on the path
|
||||
* that is closest to the given point.
|
||||
*
|
||||
* If no point on the path is closer than @threshold, `NULL` is returned.
|
||||
*
|
||||
* Returns: (transfer full) (nullable): a newly allocated `GskPathPoint`
|
||||
*/
|
||||
GskPathPoint *
|
||||
gsk_path_measure_get_closest_point (GskPathMeasure *self,
|
||||
const graphene_point_t *point,
|
||||
float threshold)
|
||||
{
|
||||
gssize best_idx;
|
||||
float best_offset;
|
||||
float best_contour_offset;
|
||||
float contour_offset;
|
||||
|
||||
contour_offset = 0;
|
||||
best_idx = -1;
|
||||
|
||||
for (gsize i = 0; i < self->n_contours; i++)
|
||||
{
|
||||
float distance, offset;
|
||||
|
||||
if (gsk_contour_get_closest_point (gsk_path_get_contour (self->path, i),
|
||||
self->measures[i].contour_data,
|
||||
self->tolerance,
|
||||
point,
|
||||
threshold,
|
||||
&distance,
|
||||
NULL,
|
||||
&offset,
|
||||
NULL))
|
||||
{
|
||||
best_idx = i;
|
||||
best_offset = offset;
|
||||
best_contour_offset = contour_offset;
|
||||
|
||||
if (distance < self->tolerance)
|
||||
break;
|
||||
|
||||
threshold = distance - self->tolerance;
|
||||
}
|
||||
|
||||
contour_offset += self->measures[i].length;
|
||||
}
|
||||
|
||||
if (best_idx != -1)
|
||||
return gsk_path_point_new (self,
|
||||
gsk_path_get_contour (self->path, best_idx),
|
||||
self->measures[best_idx].contour_data,
|
||||
best_contour_offset, best_offset);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020 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>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined (__GSK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gsk/gsk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#include <gsk/gskpath.h>
|
||||
#include <gsk/gskpathpoint.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_PATH_MEASURE (gsk_path_measure_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gsk_path_measure_get_type (void) G_GNUC_CONST;
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPathMeasure * gsk_path_measure_new (GskPath *path);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPathMeasure * gsk_path_measure_new_with_tolerance (GskPath *path,
|
||||
float tolerance);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPathMeasure * gsk_path_measure_ref (GskPathMeasure *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_measure_unref (GskPathMeasure *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPath * gsk_path_measure_get_path (GskPathMeasure *self) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
float gsk_path_measure_get_tolerance (GskPathMeasure *self) G_GNUC_PURE;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
float gsk_path_measure_get_length (GskPathMeasure *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gsk_path_measure_is_closed (GskPathMeasure *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gsk_path_measure_in_fill (GskPathMeasure *self,
|
||||
const graphene_point_t *point,
|
||||
GskFillRule fill_rule);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPathPoint * gsk_path_measure_get_point (GskPathMeasure *self,
|
||||
float distance);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPathPoint * gsk_path_measure_get_closest_point (GskPathMeasure *self,
|
||||
const graphene_point_t *point,
|
||||
float threshold);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskPathMeasure, gsk_path_measure_unref)
|
||||
|
||||
G_END_DECLS
|
||||
@@ -1,186 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020 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>
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gskpath.h"
|
||||
#include "gskpathbuilder.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef gpointer gskpathop;
|
||||
|
||||
static inline
|
||||
gskpathop gsk_pathop_encode (GskPathOperation op,
|
||||
const graphene_point_t *pts);
|
||||
static inline
|
||||
const graphene_point_t *gsk_pathop_points (gskpathop pop);
|
||||
static inline
|
||||
GskPathOperation gsk_pathop_op (gskpathop pop);
|
||||
|
||||
static inline
|
||||
gboolean gsk_pathop_foreach (gskpathop pop,
|
||||
GskPathForeachFunc func,
|
||||
gpointer user_data);
|
||||
|
||||
/* included inline so tests can use them */
|
||||
static inline
|
||||
void gsk_path_builder_pathop_to (GskPathBuilder *builder,
|
||||
gskpathop op);
|
||||
static inline
|
||||
void gsk_path_builder_pathop_reverse_to (GskPathBuilder *builder,
|
||||
gskpathop op);
|
||||
|
||||
/* IMPLEMENTATION */
|
||||
|
||||
#define GSK_PATHOP_OPERATION_MASK (0x7)
|
||||
|
||||
static inline gskpathop
|
||||
gsk_pathop_encode (GskPathOperation op,
|
||||
const graphene_point_t *pts)
|
||||
{
|
||||
/* g_assert (op & GSK_PATHOP_OPERATION_MASK == op); */
|
||||
g_assert ((GPOINTER_TO_SIZE (pts) & GSK_PATHOP_OPERATION_MASK) == 0);
|
||||
|
||||
return GSIZE_TO_POINTER (GPOINTER_TO_SIZE (pts) | op);
|
||||
}
|
||||
|
||||
static inline const graphene_point_t *
|
||||
gsk_pathop_points (gskpathop pop)
|
||||
{
|
||||
return GSIZE_TO_POINTER (GPOINTER_TO_SIZE (pop) & ~GSK_PATHOP_OPERATION_MASK);
|
||||
}
|
||||
|
||||
static inline
|
||||
GskPathOperation gsk_pathop_op (gskpathop pop)
|
||||
{
|
||||
return GPOINTER_TO_SIZE (pop) & GSK_PATHOP_OPERATION_MASK;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
gsk_pathop_foreach (gskpathop pop,
|
||||
GskPathForeachFunc func,
|
||||
gpointer user_data)
|
||||
{
|
||||
switch (gsk_pathop_op (pop))
|
||||
{
|
||||
case GSK_PATH_MOVE:
|
||||
return func (gsk_pathop_op (pop), gsk_pathop_points (pop), 1, 0, user_data);
|
||||
|
||||
case GSK_PATH_CLOSE:
|
||||
case GSK_PATH_LINE:
|
||||
return func (gsk_pathop_op (pop), gsk_pathop_points (pop), 2, 0, user_data);
|
||||
|
||||
case GSK_PATH_QUAD:
|
||||
return func (gsk_pathop_op (pop), gsk_pathop_points (pop), 3, 0, user_data);
|
||||
|
||||
case GSK_PATH_CUBIC:
|
||||
return func (gsk_pathop_op (pop), gsk_pathop_points (pop), 4, 0, user_data);
|
||||
|
||||
case GSK_PATH_CONIC:
|
||||
{
|
||||
const graphene_point_t *pts = gsk_pathop_points (pop);
|
||||
return func (gsk_pathop_op (pop), (graphene_point_t[3]) { pts[0], pts[1], pts[3] }, 3, pts[2].x, user_data);
|
||||
}
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
gsk_path_builder_pathop_to (GskPathBuilder *builder,
|
||||
gskpathop op)
|
||||
{
|
||||
const graphene_point_t *pts = gsk_pathop_points (op);
|
||||
|
||||
switch (gsk_pathop_op (op))
|
||||
{
|
||||
case GSK_PATH_MOVE:
|
||||
gsk_path_builder_move_to (builder, pts[0].x, pts[0].y);
|
||||
break;
|
||||
|
||||
case GSK_PATH_CLOSE:
|
||||
gsk_path_builder_close (builder);
|
||||
break;
|
||||
|
||||
case GSK_PATH_LINE:
|
||||
gsk_path_builder_line_to (builder, pts[1].x, pts[1].y);
|
||||
break;
|
||||
|
||||
case GSK_PATH_QUAD:
|
||||
gsk_path_builder_quad_to (builder, pts[1].x, pts[1].y, pts[2].x, pts[2].y);
|
||||
break;
|
||||
|
||||
case GSK_PATH_CUBIC:
|
||||
gsk_path_builder_cubic_to (builder, pts[1].x, pts[1].y, pts[2].x, pts[2].y, pts[3].x, pts[3].y);
|
||||
break;
|
||||
|
||||
case GSK_PATH_CONIC:
|
||||
gsk_path_builder_conic_to (builder, pts[1].x, pts[1].y, pts[3].x, pts[3].y, pts[2].x);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
gsk_path_builder_pathop_reverse_to (GskPathBuilder *builder,
|
||||
gskpathop op)
|
||||
{
|
||||
const graphene_point_t *pts = gsk_pathop_points (op);
|
||||
|
||||
switch (gsk_pathop_op (op))
|
||||
{
|
||||
case GSK_PATH_MOVE:
|
||||
gsk_path_builder_move_to (builder, pts[0].x, pts[0].y);
|
||||
break;
|
||||
|
||||
case GSK_PATH_CLOSE:
|
||||
gsk_path_builder_line_to (builder, pts[0].x, pts[0].y);
|
||||
break;
|
||||
|
||||
case GSK_PATH_LINE:
|
||||
gsk_path_builder_line_to (builder, pts[1].x, pts[1].y);
|
||||
break;
|
||||
|
||||
case GSK_PATH_QUAD:
|
||||
gsk_path_builder_quad_to (builder, pts[1].x, pts[1].y, pts[0].x, pts[0].y);
|
||||
break;
|
||||
|
||||
case GSK_PATH_CUBIC:
|
||||
gsk_path_builder_cubic_to (builder, pts[2].x, pts[2].y, pts[1].x, pts[1].y, pts[0].x, pts[0].y);
|
||||
break;
|
||||
|
||||
case GSK_PATH_CONIC:
|
||||
gsk_path_builder_conic_to (builder, pts[1].x, pts[1].y, pts[0].x, pts[0].y, pts[2].x);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
1727
gsk/gskpathops.c
1727
gsk/gskpathops.c
File diff suppressed because it is too large
Load Diff
@@ -1,195 +0,0 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskpathpointprivate.h"
|
||||
|
||||
#include "gskcontourprivate.h"
|
||||
#include "gskpathmeasure.h"
|
||||
|
||||
#include "gdk/gdkprivate.h"
|
||||
|
||||
|
||||
/**
|
||||
* GskPathPoint:
|
||||
*
|
||||
* `GskPathPoint` is an opaque, immutable type representing a point on a path.
|
||||
*
|
||||
* It can be queried for properties of the path at that point, such as its
|
||||
* tangent or its curvature.
|
||||
*
|
||||
* To obtain a `GskPathPoint`, use [method@Gsk.PathMeasure.get_path_point]
|
||||
* or [method@Gsk.PathMeasure.get_closest_point].
|
||||
*/
|
||||
|
||||
struct _GskPathPoint
|
||||
{
|
||||
guint ref_count;
|
||||
|
||||
GskPathMeasure *measure;
|
||||
const GskContour *contour;
|
||||
gpointer measure_data;
|
||||
float contour_offset; /* distance from beginning of path to contour */
|
||||
float offset; /* offset of point inside contour */
|
||||
};
|
||||
|
||||
G_DEFINE_BOXED_TYPE (GskPathPoint, gsk_path_point,
|
||||
gsk_path_point_ref,
|
||||
gsk_path_point_unref)
|
||||
|
||||
GskPathPoint *
|
||||
gsk_path_point_new (GskPathMeasure *measure,
|
||||
const GskContour *contour,
|
||||
gpointer measure_data,
|
||||
float contour_offset,
|
||||
float offset)
|
||||
{
|
||||
GskPathPoint *self;
|
||||
|
||||
self = g_new0 (GskPathPoint, 1);
|
||||
|
||||
self->ref_count = 1;
|
||||
|
||||
self->measure = gsk_path_measure_ref (measure);
|
||||
self->contour = contour;
|
||||
self->measure_data = measure_data;
|
||||
self->contour_offset = contour_offset;
|
||||
self->offset = offset;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_point_ref:
|
||||
* @self: a `GskPathPoint`
|
||||
*
|
||||
* Increases the reference count of a `GskPathPoint` by one.
|
||||
*
|
||||
* Returns: the passed in `GskPathPoint`
|
||||
*/
|
||||
GskPathPoint *
|
||||
gsk_path_point_ref (GskPathPoint *self)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, NULL);
|
||||
|
||||
self->ref_count++;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_point_unref:
|
||||
* @self: a `GskPathPoint`
|
||||
*
|
||||
* Decreases the reference count of a `GskPathPoint` by one.
|
||||
*
|
||||
* If the resulting reference count is zero, frees the path_measure.
|
||||
*/
|
||||
void
|
||||
gsk_path_point_unref (GskPathPoint *self)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (self->ref_count > 0);
|
||||
|
||||
self->ref_count--;
|
||||
if (self->ref_count > 0)
|
||||
return;
|
||||
|
||||
gsk_path_measure_unref (self->measure);
|
||||
|
||||
g_free (self);
|
||||
}
|
||||
|
||||
GskPathMeasure *
|
||||
gsk_path_point_get_measure (GskPathPoint *self)
|
||||
{
|
||||
return self->measure;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_point_get_distance:
|
||||
* @self: a `GskPathPoint`
|
||||
*
|
||||
* Returns the distance of the given point from the start of the path.
|
||||
*
|
||||
* This is the length of the contour from the beginning of the path
|
||||
* to the point.
|
||||
*
|
||||
* Returns: The offset of point in path
|
||||
*/
|
||||
float
|
||||
gsk_path_point_get_distance (GskPathPoint *self)
|
||||
{
|
||||
return self->contour_offset + self->offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_point_get_position:
|
||||
* @self: a `GskPathPoint`
|
||||
* @position: (out caller-allocates): Return location for
|
||||
* the coordinates of the point
|
||||
*
|
||||
* Gets the position of the point.
|
||||
*/
|
||||
void
|
||||
gsk_path_point_get_position (GskPathPoint *self,
|
||||
graphene_point_t *position)
|
||||
{
|
||||
gsk_contour_get_point (self->contour,
|
||||
self->measure_data,
|
||||
self->offset,
|
||||
GSK_PATH_END,
|
||||
position, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_point_get_tangent:
|
||||
* @self: a `GskPathPoint`
|
||||
* @direction: the direction for which to return the tangent
|
||||
* @tangent: (out caller-allocates): Return location for
|
||||
* the tangent at the point
|
||||
*
|
||||
* Gets the tangent of the path at the point.
|
||||
*
|
||||
* Note that certain points on a path may not have a single
|
||||
* tangent, such as sharp turns. At such points, there are
|
||||
* two tangents -- the direction of the path going into the
|
||||
* point, and the direction coming out of it.
|
||||
*
|
||||
* The @direction argument lets you choose which one to get.
|
||||
*/
|
||||
void
|
||||
gsk_path_point_get_tangent (GskPathPoint *self,
|
||||
GskPathDirection direction,
|
||||
graphene_vec2_t *tangent)
|
||||
{
|
||||
gsk_contour_get_point (self->contour,
|
||||
self->measure_data,
|
||||
self->offset,
|
||||
direction,
|
||||
NULL, tangent);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_point_get_curvature:
|
||||
* @self: a `GskPathPoint`
|
||||
* @center: (out caller-allocates): Return location for
|
||||
* the center of the osculating circle
|
||||
*
|
||||
* Calculates the curvature at the point @distance units into
|
||||
* the path.
|
||||
*
|
||||
* Optionally, returns the center of the osculating circle as well.
|
||||
*
|
||||
* If the curvature is infinite (at line segments), zero is returned,
|
||||
* and @center is not modified.
|
||||
*
|
||||
* Returns: The curvature of the path at the given point
|
||||
*/
|
||||
float
|
||||
gsk_path_point_get_curvature (GskPathPoint *self,
|
||||
graphene_point_t *center)
|
||||
{
|
||||
return gsk_contour_get_curvature (self->contour,
|
||||
self->measure_data,
|
||||
self->offset,
|
||||
center);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user