Compare commits

...

218 Commits

Author SHA1 Message Date
Matthias Clasen 8eded0ba62 text: Fix incomplete invalidation
When a style change affects the text, we need to
clear the cached content, in order to pick up the
new text style.
2019-07-22 20:20:07 -07:00
Matthias Clasen b25214aa26 text view: Fix incomplete invalidation
Update the cached text style when a css change affects
content or background. This fixes text views drawing
black-on-dark when switching to the dark theme.
2019-07-22 20:20:07 -07:00
Matthias Clasen 70013161b3 text: cache the content and cursor nodes
We don't want to redraw the unchanged text every frame
while we blink the cursor, so cache the pieces and just
combine them with the current opacity.
2019-07-22 20:20:07 -07:00
Jordi Mas 8999bb0b78 Update Catalan translation 2019-07-22 11:06:27 +02:00
Matthias Clasen 7a81b7c7be Merge branch 'wip/chergert/fix-textlayout-bounds' into 'master'
textlayout: fix bounds for clipping

See merge request GNOME/gtk!1006
2019-07-22 01:53:17 +00:00
Christian Hergert e475d4bdc5 textlayout: fix bounds for clipping
This should match gtk_snapshot_append_layout(), which means that we expect the
bounds to be rooted at 0, 0.
2019-07-21 18:21:04 -07:00
Matthias Clasen 980a6a20b1 Merge branch 'wip/textview' into 'master'
textview: port GtkTextView to GskPangoRenderer

See merge request GNOME/gtk!1005
2019-07-21 23:10:41 +00:00
Matthias Clasen 064ad42432 text view: Smooth cursor blinking
Fade the text cursor in and out, instead
of abruptly turning it on and off.
2019-07-21 16:03:49 -07:00
Christian Hergert 4ff9163c47 textview: port GtkTextView to GskPangoRenderer
This removes the use of GtkTextDisplay (a PangoRenderer) to use
the GskPangoRender which generates render nodes. Part of this means
improving the GskPangoRenderer to support the necessary features for
displaying a GtkTextView.

Primarily, this is a merging of GtkTextDisplay features into
GskPangoRender. Additionally, GtkTextDisplay was removed to allow for
gtk_text_layout_snapshot() to be implemented elsewhere.
2019-07-21 16:03:45 -07:00
Matthias Clasen 45ebe47d94 textview: Stop exporting private apis
These headers are no longer 'semi-public, but private
and uninstalled, so exporting these functions does
not do any good.
2019-07-21 13:26:40 -07:00
Matthias Clasen 2803bd93ce gsk: Fix a crash in gsk_render_node_diff
The only thing worse than freeing the same
cairo region twice is freeing it three times.
2019-07-21 13:18:58 -07:00
Matthias Clasen 51161fb0d6 text: Smooth cursor blinking
Fade the text cursor in and out, instead
of abruptly turning it on and off.
2019-07-21 11:35:13 -07:00
Matthias Clasen 63fd97749c Adwaita: Fix entry block cursors 2019-07-21 11:35:04 -07:00
Asier Sarasua Garmendia f2d736d2cc Update Basque translation 2019-07-21 18:02:07 +00:00
Serdar Sağlam 9b9a656e54 Update Turkish translation 2019-07-21 14:15:15 +00:00
Timm Bäder 8f734b01b2 window: Plug a GList leak
We need to free the GList manually when using g_list_remove_link().
2019-07-21 12:45:10 +02:00
Timm Bäder 69250371b0 gtk.supp: Add glXQueryServerString exceptions 2019-07-21 12:45:10 +02:00
Timm Bäder 731613d70b gl renderer: Remove leftover modelview matrix
We use a GskTransform there nowadays.
2019-07-21 12:45:10 +02:00
Timm Bäder 5f21c45f75 Revert "gl renderer: ops_set_modelview is (transfer full)"
This reverts commit e904c49e8a.

This breaks HiDPI setups, i.e. setups where the call to
ops_set_modelview does not end up with a NULL transform.
2019-07-21 12:45:10 +02:00
Timm Bäder 8beea4d958 window: Merge some functions into their only callers
So it's clear we only add or remove the pointerfocus-es in
_update_pointer_focus.
2019-07-21 11:06:24 +02:00
Timm Bäder 1583200e24 cellrenderertext: Remove some unnecessary NULL checks 2019-07-21 10:26:00 +02:00
Timm Bäder 03fa8ed259 cellrenderertext: Don't unnecessarily ref a layout
We never pass a NULL layout to get_size().
2019-07-21 10:22:05 +02:00
Timm Bäder 0bd939624e textlayout: Remove some outdated comments
These two members have been commented out for 19 years.
2019-07-21 10:02:54 +02:00
Timm Bäder b658a1a8e3 entry: Measure icons again
This was previously removed because it changes the minimum and natural
size of the entry when the icons are shown/hidden at runtime. Just not
measuring them does not work however, so reintroduce this.
2019-07-21 09:58:08 +02:00
Timm Bäder 7eae9d115c placesview: Make "Other Locations" search case-insensitive
It's just weird to search for "c" and not find the list item labelled
"Computer".
2019-07-21 09:51:54 +02:00
Timm Bäder 2ca56d4c4c linedisplay: Save paragraph bg color inline
No need to allocate this separately.
2019-07-21 09:47:09 +02:00
Timm Bäder f6d7967e96 gtk.supp: Add a pixman_image_composite32 exception 2019-07-21 09:13:24 +02:00
Timm Bäder 9bddc0ff85 gtk.supp: add a FcDefaultSubstitute exception 2019-07-21 09:07:27 +02:00
Timm Bäder 6e47ebe030 rendernodeparser: Fix a memory leak when parsing glyphs 2019-07-21 09:06:50 +02:00
Timm Bäder 9728dabf12 rendernodeparser: Fix a memory leak when parsing textures 2019-07-21 09:06:29 +02:00
Timm Bäder e904c49e8a gl renderer: ops_set_modelview is (transfer full)
regarding the passed modelview matrix
2019-07-21 09:06:10 +02:00
Timm Bäder 27ddd39d69 gl renderer: Pull out code from a loop
Does not not actually depend on anything done inside the loop.
2019-07-21 08:39:25 +02:00
Goran Vidović 86e907b088 Update Croatian translation 2019-07-19 21:29:56 +00:00
Goran Vidović 8b46538af9 Update Croatian translation 2019-07-19 21:20:13 +00:00
Timm Bäder 5910a28aa5 gl renderer: Replace a redundant function call
We're already getting the radius from the node above.
2019-07-19 18:14:50 +02:00
Timm Bäder 3935027880 filechooserwidget: Fold function into only caller 2019-07-19 18:14:50 +02:00
Timm Bäder 8665828d7f filechooserwidget: Don't emit default-size-changed() in unroot()
It doesn't make much sense to assume the default size has changed just
because the widget has been unrooted.
2019-07-19 18:14:50 +02:00
Timm Bäder a8b559e99f filechooser: Remove SETTINGS_KEY_WINDOW_POSITION
Now unused.
2019-07-19 18:14:50 +02:00
Timm Bäder 5674a3db46 filechooserwidget: Don't look at saved window position
We don't save it anymore so no need to look at it here.
2019-07-19 18:14:49 +02:00
Timm Bäder dd3acc9014 filechooserdialog: Stop using gtk_window_get_position() 2019-07-19 18:14:49 +02:00
Timm Bäder a9364bc053 Revert "file chooser: Stop using gtk_window_get_position"
This reverts commit 2ed533c3e1.

This also made the filechooser dialog not save the window size anymore,
which does not depend on the gtk_window_get_position() removal.
2019-07-19 18:14:49 +02:00
Timm Bäder 59313e1459 gtkfilechooserwidget: Temporarily disable revealer transitions...
... when going between recent and browse. It just looks weird to have
this transition while the treeview model is just cleared/repopulated
without any transition.
2019-07-19 18:14:49 +02:00
Timm Bäder 3e54d374de placessidebar: Remove sidebar border again 2019-07-19 18:14:49 +02:00
Christoph Reiter 9856218073 Merge branch 'tests-no-box-packing' into 'master'
testsuite: Remove dangling references to box-packing tests

See merge request GNOME/gtk!997
2019-07-18 19:32:19 +00:00
Emmanuele Bassi d8f91e7df9 Merge branch 'pc-libs-private' into 'master'
gtk4.pc: Move third-party libraries from Libs to Libs.private

See merge request GNOME/gtk!998
2019-07-18 10:31:19 +00:00
Emmanuele Bassi 91d4e2b3e3 Merge branch 'gtk-4-support-tcrypt-with-proxy-handler' into 'master'
gtkmountoperation: Support TCRYPT options when using proxy handler

See merge request GNOME/gtk!245
2019-07-18 10:11:12 +00:00
segfault e5cccbf5a0 gtkmountoperation: Support TCRYPT options when using proxy handler
GMountOperation now supports options to unlock TCRYPT volumes. This
patch sets these options if they are returned by AskPassword() of a
GtkMountOperationHandlerProxy.
2019-07-18 11:41:45 +02:00
Simon McVittie 5cfe9ab603 testsuite: Remove dangling references to box-packing tests
These were removed in commit c47abb5f, before 3.96.0.

Signed-off-by: Simon McVittie <smcv@debian.org>
2019-07-18 09:26:07 +01:00
Simon McVittie 01a6bbdc73 gtk4.pc: Move third-party libraries from Libs to Libs.private
This avoids "overlinking". These libraries are an implementation detail
of particular backends, so they only need to appear on library consumers'
linker command-lines if the dependency cannot be picked up from the
shared library automatically (when linking statically, or when building
on a deficient OS that doesn't support transitive dependencies between
shared libraries, in which case pkg-config should be built with
--enable-indirect-deps).

Signed-off-by: Simon McVittie <smcv@debian.org>
2019-07-18 09:24:41 +01:00
Timm Bäder 24a4063645 scrollbar: Use a box layout
Makes a lot more sense than the intermediate box just for its layout.
2019-07-15 07:52:42 +02:00
Timm Bäder 4f11bbc59b text: Don't leak emoji chooser 2019-07-15 06:56:19 +02:00
Timm Bäder 9ceb41f9a4 menu: Fix an uninitialized value
If the menu does not have any children, we'd otherwise end up calling
g_object_ref() on an uninitialized value.
2019-07-15 06:43:25 +02:00
Timm Bäder 831309eed2 progressbar: Use box layout
Instead of the custom layouting we did before.
2019-07-15 06:38:51 +02:00
Timm Bäder 4bb4a98493 text: Move some locals into the closest scope 2019-07-15 05:38:25 +02:00
Timm Bäder 70b0f712ad text: Remove some useless casts 2019-07-15 05:19:02 +02:00
Timm Bäder c6e9372ba3 text: Move some locals into the closest scope 2019-07-15 05:17:46 +02:00
Jordi Mas 13b055ab2d Update Catalan translation 2019-07-14 11:25:12 +02:00
Timm Bäder 38f4a7708e Remove some dead assignments 2019-07-14 10:08:04 +02:00
Timm Bäder 6abcd8d013 Adwaita: Add fontbutton spacing back 2019-07-14 10:08:04 +02:00
Timm Bäder 37906a2200 adwaita: Remove a dead rule
GtkFileChooserButtons are called "filechooserbutton" these days, not
button.file
2019-07-14 10:08:04 +02:00
Timm Bäder b9b5072668 gl renderer: Fix opacity nodes with overlapping child nodes 2019-07-14 10:08:04 +02:00
Aurimas Černius 459edfa77b Updated Lithuanian translation 2019-07-13 18:28:21 +03:00
Timm Bäder 92a79d3f96 popover: Fix a broken cast
The widget passed here is priv->relative_to, not the popover.
2019-07-13 17:06:22 +02:00
Timm Bäder 984dff54ab rendernodeparser: fix typo 2019-07-13 11:12:47 +02:00
Timm Bäder 1866aa93e3 fishbowl: Plug a small leak 2019-07-13 10:10:17 +02:00
Timm Bäder 2884691740 picture: Unref previous paintable
We were leaking all of them.
2019-07-13 09:38:28 +02:00
Timm Bäder b8549a142e suppression file: Add glReadPixels mesa exception 2019-07-13 09:38:14 +02:00
Timm Bäder 0f3ca349e7 node editor: Manually unrealize all created renderers
This has not been a problem before since we were leaking them.
2019-07-13 09:37:47 +02:00
Timm Bäder a13d6bbbdf Merge branch 'fix-issue-2014-gtk4' into 'master'
Fix a string leak in gtkemojicompletion.c [gtk4]

Closes #2014

See merge request GNOME/gtk!993
2019-07-12 09:59:38 +00:00
Luca Bacci d15dc6f90b Fix a string leak
Fixes #2014
2019-07-12 08:43:44 +00:00
Timm Bäder 58e6c277b0 fpsoverlay: Fix fps overlay position 2019-07-10 18:34:16 +02:00
Matthias Clasen 1d29d44ddb Merge branch 'wip/baedert/accelmap' into 'master'
AccelMap: Sort accels before iterating over them in foreach()

See merge request GNOME/gtk!980
2019-07-09 19:39:58 +00:00
Matthias Clasen bda3c6c084 Merge branch 'wip/baedert/for-master' into 'master'
Improve the valgrind experience

See merge request GNOME/gtk!984
2019-07-09 19:39:13 +00:00
Kukuh Syafaat 159913be2f Update Indonesian translation 2019-07-09 07:56:21 +00:00
Asier Sarasua Garmendia b05d1676d3 Update Basque translation 2019-07-08 20:19:10 +00:00
Asier Sarasua Garmendia 0b21ed0c7a Update Basque translation 2019-07-08 20:14:08 +00:00
Asier Sarasua Garmendia 564a92830b Update Basque translation 2019-07-08 19:18:08 +00:00
Chun-wei Fan a20fd5e14e demos/constraint-editor: Fix linking on MSVC builds
We must apply the /entry:mainCRTStartup linker flag in order to link GTK
apps in pure GUI form.  This follows what is done in demos/gtk-demo,
etc.
2019-07-08 18:37:27 +08:00
Timm Bäder 138986f064 Merge branch 'ui-enum-values' into 'master'
Change the few examples that use a full GTK_ enum value in .ui files.

See merge request GNOME/gtk!987
2019-07-08 07:14:48 +00:00
Timm Bäder f286c99338 Merge branch 'gltexsubimage2d' into 'master'
use glTexSubImage2D instead of glTextureSubImage2D

Closes #2005

See merge request GNOME/gtk!986
2019-07-08 07:14:13 +00:00
Timm Bäder ea48d1de5e Merge branch 'glsl-float-literals' into 'master'
glsl: use float literals

See merge request GNOME/gtk!985
2019-07-08 07:10:41 +00:00
Robert Ancell dbd2a81501 Change the few examples that use a full GTK_ enum value in .ui files.
Lowercase versions work just as well and are much more readable.
2019-07-08 15:52:28 +12:00
Piotr Drąg be6ec8f50b Update Polish translation 2019-07-07 13:22:10 +02:00
Timm Bäder 264d4bada6 widget: Remove queue_resize_no_redraw
We always invalidate the widget in size_allocate() anyway.
2019-07-07 07:43:08 +02:00
Timm Bäder 633172fd66 widget: Make queue_compute_expand() private
Nobody needs to call this anymore.
2019-07-07 07:36:29 +02:00
Timm Bäder 042f7d117f compare-render: Don't unref an invalid GFile
We already unref it when the g_file_make_directory_with_parents fails.
2019-07-07 07:24:00 +02:00
Timm Bäder b062594ae6 gl renderer: Properly clean up program state transforms 2019-07-07 07:24:00 +02:00
Timm Bäder 95f30fee87 iconhelper: Try to avoid some save/restore calls
GtkImage already does something similar so we often end up with 0/0
here. Avoid the save()/restore() calls in GtkSnapshot in that case.
2019-07-07 07:24:00 +02:00
Timm Bäder dbc49e7742 transform: Fix identity transform fast paths
Returning an extra ref will cause leaks later.
2019-07-07 07:24:00 +02:00
Timm Bäder 449c96ffb3 widget: Unref previous transform 2019-07-07 07:24:00 +02:00
Timm Bäder 1459ca2c26 widget factory: Plug a memory leak 2019-07-07 07:24:00 +02:00
Timm Bäder 4123c85021 actionmuxer: Plug a memory leak 2019-07-07 07:24:00 +02:00
Timm Bäder d1c37c41d9 Add a gtk valgrind suppression file
Not ideal but otherwise I get 30k line output from valgrind when just
running the widget factory. It's mostly mesa but still.
2019-07-07 07:23:57 +02:00
Elias Aebi ea6d3f589f use glTexSubImage2D instead of glTextureSubImage2D 2019-07-06 16:23:21 +02:00
Elias Aebi 1e6120e776 glsl: use float literals 2019-07-06 14:42:08 +02:00
Timm Bäder a77f8e886b cssprovider: Fix a memory leak in load_internal
We create a new GBytes but never unref it.
2019-07-06 09:50:07 +02:00
Benjamin Otte 96b782c026 x11: Make sure stream stays alive long enough
When unreffing the stream from a different thread, the close function
will schedule its cleanup asynchornously in the main thread.
We need to make sure the stream object stays alive for as long as
that hasn't happened, so ref() it.

Fixes #2003
2019-07-05 21:17:00 +02:00
Timm Bäder 6455a54f6c Merge branch 'header-custom-title-valign' into 'master'
headerbar: Don't change the custom title's valign

See merge request GNOME/gtk!981
2019-07-04 12:45:13 +00:00
Adrien Plazas 3bae6fa1c7 headerbar: Don't change the custom title's valign
This allows custom titles to use the vertical alignment of their choice
without having to set it manually after it has been added to the header
bar, hence allowing them to define their preferred alignment from a UI
template.

This is useful for widgets like the view switcher which requires filling
the header bar's whole height.
2019-07-04 13:03:37 +02:00
Timm Bäder 68f19a8e6a accelmap: Sort accels before interating over them in foreach() 2019-07-04 08:35:42 +02:00
Timm Bäder 12ebbd1b24 accelmap: Avoid a confusing goto 2019-07-04 08:35:34 +02:00
Emmanuele Bassi 9b7bda6137 ci: Comment job, not just the stage
GitLab doesn't like it when we keep a job but disable the stage.
2019-07-03 17:57:27 +01:00
Emmanuele Bassi 1b4ed58331 ci: Disable deploy jobs
The version of gtk-doc in our CI image is not new enough to cope with
the fact that GTK lost container properties.
2019-07-03 17:54:32 +01:00
Benjamin Otte b2868d7218 Merge branch 'wip/frame-clock-consumers' into 'master'
Frame clock consumers

See merge request GNOME/gtk!971
2019-07-03 16:21:32 +00:00
Emmanuele Bassi bdc8f9dccf Merge branch 'layout-manager-ref' into 'master'
widget: Don't lose a layout manager ref

See merge request GNOME/gtk!977
2019-07-03 13:25:44 +00:00
Matthias Clasen 9768f35931 widget: Don't lose a layout manager ref
gtk_widget_set_layout_manager is transfer-full,
so we must give it a new reference from set_property
to implement object property semantics properly.
2019-07-03 09:18:41 -04:00
Daniel Mustieles 19a4ee031d Updated Spanish translation 2019-07-03 11:45:12 +02:00
Jonas Ådahl a7ee1b4e85 gdksurface: Make all surfaces listen to the frame clock signals
Instead of the toplevel driving popups, have the popups listen to the
frame clock themselves. Otherwise, if the toplevel for some reason isn't
drawn by the compositor and stops drawing new frames, popups wouldn't
get painted either.
2019-07-03 11:42:28 +02:00
Jonas Ådahl 5db079b052 gdk/frameclock: Make surfaces inhibit freeze
To make a frame clock tick as long as any of the associated surfaces
expect to receive ticks, make the surfaces inhibit freezing the clock,
instead of directly tell the frame clock to freeze itself.

This makes it so that as long as any surface using a certain frame clock
is not frozen (e.g. just received a frame event from the display
server), the frame clock will not be frozen.

With this, the frame clock is initiated as frozen, and won't be thawed
until any surface inhibits freeze. It will be frozen again, when every
surface has that previously inhibited freeze uninhibited freeze.
2019-07-03 11:42:28 +02:00
Jonas Ådahl a2ff6af4b3 tests: Add back testpopupat
It's still useful for testing menus. Fixed the .ui file by removing a
property that no longer exists.

This effectively reverts commit
84d2150077.
2019-07-03 11:42:28 +02:00
Jonas Ådahl f66e764855 menu: Remove unused variable 2019-07-03 11:42:28 +02:00
Mohammed Sadiq a8c23d06ac constraint: Fix property name typo in doc 2019-07-03 09:31:39 +05:30
Piotr Drąg 36b4cd4bfc Update POTFILES.in and POTFILES.skip 2019-07-02 19:02:36 +02:00
Matej Urbančič 46c59e3c3d Updated Slovenian translation 2019-07-02 18:51:55 +02:00
Matthias Clasen b5aee936a9 Merge branch 'constraint-list-model' into 'master'
Constraint list models

See merge request GNOME/gtk!975
2019-07-02 14:18:42 +00:00
Matthias Clasen aa8687316f constraint editor: Implement loading
Allow to reread the ui builder files we write out.
Just barely.
2019-07-02 10:03:48 -04:00
Matthias Clasen 5a3cf5a194 constraints editor: Stop naming constraints
We don't have a field for the name in ui files,
so stop naming constraints.
2019-07-02 10:03:48 -04:00
Matthias Clasen c5e1b00994 constraint editor: Implement saving
Save to a ui file.
2019-07-02 10:03:48 -04:00
Matthias Clasen 377f0c1a0a constraint editor: Use name properties 2019-07-02 10:03:48 -04:00
Matthias Clasen a442e6e8de constraint editor: Use the list models
Instead of handrolling our own list models,
use the ones provided by GtkConstraintLayout.
2019-07-02 10:03:48 -04:00
Matthias Clasen 274c47e5ba constraint layout: Provide list models
Provide list models for the constraints and guides,
so we can show them in the inspector, and use them
in e.g. the constraints editor.
2019-07-02 10:03:48 -04:00
Matthias Clasen b2f15a622d Merge branch 'wip/ebassi/constraint-layout' into 'master'
Add constraint-based layout manager

Closes #1090

See merge request GNOME/gtk!973
2019-07-02 14:01:01 +00:00
Emmanuele Bassi 04aaf02881 docs: Add more private headers to the list
The various GtkConstraint private API should not be scanned for
documentation.
2019-07-02 09:48:17 +01:00
Emmanuele Bassi d5f8e1bf29 docs: Fix typo in function name 2019-07-02 09:44:48 +01:00
Daniel Boles 33bd7051f2 widget-factory: Use correct StyleProvider priority
We are an application, not a user.

cherry-pick of !974
2019-07-02 09:09:47 +01:00
Matthias Clasen 61345b3216 Merge branch 'option-names' into 'master'
meson: Rename documentation option to gtk_doc

See merge request GNOME/gtk!972
2019-07-02 01:28:43 +00:00
Benjamin Otte 129691f3a6 flattenlistmodeL: Compute items-changed position properly
The code previously forgot to include the left child of the model's
node. Which of course only happened if that child wasn't NULL, which is
a common case.

Found and test provided by Matthias Clasen.
2019-07-02 02:53:00 +02:00
Matthias Clasen 4eaf860e86 meson: Rename documentation option to gtk_doc
This name is what most of the stack is using.
Lets follow along, even though it is (imo)
uglier.
2019-07-01 20:16:37 -04:00
Christoph Reiter 72814c54a8 meson: cups: use cups-config for looking up cups
We were looking for the cups headers and the cups lib in the default locations
which for example breaks with OpenBSD where the cups headers are under /usr/local/include/

Instead just use the "cups" dependency type from meson which internally uses cups-config.

See #1967

Ported to master from !963
2019-07-01 21:52:06 +02:00
Christoph Reiter 4d4e02c9d0 build/cups: remove checks for httpGetAuthString and http_t.authstring
httpGetAuthString() was added with cups 1.3 and we depend on a newer version
now. The direct field access was a fallback in case httpGetAuthString()
was missing, so this can also be dropped.

Ported to master from !938
2019-07-01 21:34:44 +02:00
Emmanuele Bassi 8ab609e4e7 Add custom parser for guides defined in GtkBuilder UI files
Like we describe constraints, we can also define guides.
2019-07-01 19:22:48 +01:00
Emmanuele Bassi 6bc156c237 Implement GtkBuildable for GtkConstraintLayout
Using GtkBuildable we can provide a custom parser for reading
constraints defined in a GtkBuilder UI file.
2019-07-01 18:03:20 +01:00
Emmanuele Bassi b435dc4366 Use the right GValue getter for GtkConstraintGuide:strength
The property is defined as an enum.

This fixes the defaultvalue and notify tests.
2019-07-01 18:02:19 +01:00
Emmanuele Bassi 4dd1de4129 Use explicit values for constraint strength
Instead of playing games with mapping negative symbolic values to
positive ones, let's use the appropriate constants everywhere. This
allows us to use:

        GTK_CONSTRAINT_STRENGTH_WEAK * 2

Or

        GTK_CONSTRAINT_STRENGTH_STRONG + 1

In code using the public API.

We also store the strength values as integers, so we can compare them
properly, and only turn them into doubles when they are inserted into
the solver, just like every other variable.
2019-07-01 12:39:24 +01:00
Matthias Clasen 48e6cd4255 constraint editor: Allow dragging children
We add a weak constraint for the position
and update it as the widget is dragged.
2019-07-01 04:24:26 +00:00
Matthias Clasen 658397fad0 Documentation fixes
Make sure all types show up in the docs,
and misc other improvements.
2019-07-01 03:17:58 +00:00
Matthias Clasen 670fc5bb94 constraint editor: Enable max size for guide
Also, use the apis we have now, and make the
spin buttons display 'unset' values as such.
2019-07-01 02:23:39 +00:00
Matthias Clasen b224df8109 constraint layout: go back to keeping constraints
We want to minimize changes to the solver, so
keep the size constraints around and only update
them when the size changes.
2019-07-01 01:54:57 +00:00
Matthias Clasen c88e7c180d constraint layout: Use stronger force for min size
We want our edit constraint to be strong enough to
overpower nat. size constraint, therefore use STRONG * 2.
2019-07-01 01:49:20 +00:00
Emmanuele Bassi 2aabd64f1a Fix warnings from the introspection scanner
The name of the arguments of the functions must match the name of the
arguments in the documentation stanza.
2019-07-01 01:13:00 +01:00
Emmanuele Bassi 7990b24287 Add gtkconstraintguide.h to the public headers
It needs to be introspected and installed.
2019-07-01 01:12:25 +01:00
Emmanuele Bassi c76c1a46e4 Remove specialised API from GtkConstraint
Thet widget-based API for constraint target and source properties is
unused, and not really necessary.
2019-07-01 01:05:04 +01:00
Emmanuele Bassi 68fed63eac Add missing documentation for GtkConstraint 2019-07-01 01:02:56 +01:00
Emmanuele Bassi 46403bac12 docs: Add GtkConstraint and friends to the API reference 2019-07-01 00:49:20 +01:00
Emmanuele Bassi 74c626f835 Document GtkConstraintGuide 2019-07-01 00:48:59 +01:00
Emmanuele Bassi d45a662679 Move the VFL error domain to a public header
Since the public API will use it to fill out GErrors, it needs to be
publicly available.
2019-07-01 00:48:48 +01:00
Matthias Clasen f6019f1a16 Merge branch 'gbsneto/fix-popover-dark-theme' into 'master'
Fix GtkPopoverMenu in dark theme

See merge request GNOME/gtk!970
2019-06-30 23:17:40 +00:00
Matthias Clasen 514de0b91a Add a constraint editor demo
This is an initial cut at providing a tool
for interactive exploration of constraints.
2019-07-01 00:10:11 +01:00
Emmanuele Bassi 9a463056d0 constraint layout: Notice when guides change
We need to queue a resize here.
2019-07-01 00:10:11 +01:00
Matthias Clasen 035baa092c Mark the layout as changed
We should mark the layout as changed when
constraints are added or removed.
2019-07-01 00:10:11 +01:00
Matthias Clasen 499738c903 constraint guide: Avoid redundant constraints
There is no point in creating a stay for nat
size when min == max. And no point in a constraint
for <= G_MAXINT either.
2019-07-01 00:10:11 +01:00
Matthias Clasen f2d7433bf6 constraint guide: Fix initial property values
This was overlooked when the max-width/max-height/
strength properties were added.
2019-07-01 00:10:11 +01:00
Matthias Clasen 405121bccc constraint solver: Use GTK_NOTE
Allow using GTK_DEBUG=constraints to get debug
output from the constraints solver.
2019-07-01 00:10:11 +01:00
Matthias Clasen cb96b34315 solver: Add private statistics api
No point in keeping these counters without
a way to show them.
2019-07-01 00:10:11 +01:00
Matthias Clasen 9edf6fb6cb constraint layout: Dont reset constraints in allocate
If trust our allocation algorithm, this can never
trigger (and in fact, it never does).
2019-07-01 00:10:11 +01:00
Matthias Clasen e3c4fb67ca constraints: Add some internal apis
Checking if a set is empty or a singleton can
be done more efficiently than determining its size.
2019-07-01 00:10:11 +01:00
Matthias Clasen a9dfca04e4 constraint guide: Make strength tweakable
The strength for the natural width can be used
as a tie-breaker to make instable systems behave
in a more predictable way. This can be seen
in the simple constraints demo in gtk-demo.
2019-07-01 00:10:11 +01:00
Matthias Clasen 71b52f485e constraints demo: Update comments 2019-07-01 00:10:11 +01:00
Matthias Clasen f62fc4e2f2 constraint layout: freeze/thaw on mass ops
In measure and allocate we are potentially
changing quite a few constraints. Don't
optimize at every step.
2019-07-01 00:10:11 +01:00
Matthias Clasen 511e2b435e constraints: Use better data structures
Use a GSequence for GtkVariableSet, to avoid
quadratic behavior.
2019-07-01 00:10:11 +01:00
Matthias Clasen 3f36340921 constraint layout: Measure min/nat size separately
Only constraint the opposite direction if we
actually have a for_size, and measure natural
size after removing the edit constraints. With
these changes, the test that compares constraint
layout to grid layout passes.
2019-07-01 00:10:11 +01:00
Matthias Clasen b1f0f4478e constraint layout: Use stays for natural size
It makes more sense to treat the natural size
of both children and guides as stays, since
we want to meet these values as closely as we
can, under the circumstances.
2019-07-01 00:10:11 +01:00
Matthias Clasen 90f8dcc5e1 constraint layout: Add debug output for guides
Print out the allocation we end up giving to
guides. This helps in making sense of the
allocations of the child widgets that these
guides relate to.
2019-07-01 00:10:11 +01:00
Matthias Clasen 5a019bfccd constraints demo: Give space a name
Lets call it 'space'.
2019-07-01 00:10:11 +01:00
Matthias Clasen b39a5fe5dc constraint guide: Add a name property
We need to be able to print meaningful debug messages
regarding these objects, and eventually present them
in the inspector too.
2019-07-01 00:10:11 +01:00
Matthias Clasen c7ef8411bd constraint guide: Shorten names
Now that this is its own source file,
no need for these prefixes anymore.
2019-07-01 00:10:11 +01:00
Matthias Clasen dab8a8b5c5 constraint layout: Measure more correctly
Set up all constraints for minimum + natural
width + height when measuring, regardless
of the orientation we're measuring. Anything
else will lead to incorrect answers when
there are constraints that cut across
dimensions.
2019-07-01 00:10:11 +01:00
Matthias Clasen 8b9c5e3a04 solver: Fix a copy/paste error 2019-07-01 00:10:11 +01:00
Matthias Clasen 3d3a672deb constraint solver: Fix repeat suggestions
We were not storing the previous value, causing
the first two suggestions to work, but not later
ones.

Fixes the test added in the previous commit.
2019-07-01 00:10:11 +01:00
Matthias Clasen 2f97134a08 Amend a constraint solver test
Make the 'repeat edit' test make more than to
suggestions in a single edit phase. It turns out
that this does not work, whereas just doing
two in a row does.
2019-07-01 00:10:11 +01:00
Matthias Clasen 47237d32eb demo: Use constraint guide api
Use proper api to create and set up
the guide, and also try max-width.
2019-07-01 00:10:11 +01:00
Matthias Clasen 139a59cae3 Flesh out GtkConstraintGuide
This commit moves GtkConstraintGuide into its own
source files to avoid gtkconstraintlayout.c turning
too messy, adds max size properties and implements
getters and setters.
2019-07-01 00:10:11 +01:00
Matthias Clasen 60fb9092fe Drop an indirection
This struct is not really useful for just
a single hash table, and it gets in the way
of moving the guide code to its own file.
2019-07-01 00:10:11 +01:00
Matthias Clasen 61b4febbaf Detach guides on unroot
We don't want to leave constraints behind.
2019-07-01 00:10:11 +01:00
Matthias Clasen 4f4ba8c4f6 Simplify the guide implementation
Store the values and constraints in
arrays, to facilitate treating them
uniformly.
2019-07-01 00:10:11 +01:00
Emmanuele Bassi 651adbfb39 Return the list of constraints added via VFL description
Otherwise it's impossible to remove them.
2019-07-01 00:10:11 +01:00
Emmanuele Bassi 3204347bb0 Add method to remove all constraints from a layout 2019-07-01 00:10:11 +01:00
Georges Basile Stavracas Neto b929846cc1 Adwaita: Also apply $color_menu to popover arrows
So that popovers and arrows are always in agreement of
the background color.
2019-06-30 19:51:51 -03:00
Georges Basile Stavracas Neto fe65da05be Adwaita: Use $menu_color background in popover.menu
GtkPopoverMenus should mimic menus. Commit d936967b7a introduced
some CSS related to menu popovers, however, it hardcodes 'white'
as the background color. That is problematic for the dark theme.

Use '$menu_color' instead of 'white', since $menu_color both
guarantees menu popovers and menus match, and already handles
different colors for dark and light theme variants.
2019-06-30 19:47:32 -03:00
Emmanuele Bassi 06c825df90 Add a C convenience function for VFL constraints
The dictionary-based function is convenient for language bindings, but C
developers will feel more at home with a variadic arguments list.
2019-06-30 23:42:45 +01:00
Emmanuele Bassi 46430ea85b Add Constraints/VFL demo
Shows how to describe constraints using VFL instead of constructing
objects manually.
2019-06-30 23:42:45 +01:00
Emmanuele Bassi 859c95b435 Allow adding constraints described through VFL 2019-06-30 23:42:45 +01:00
Emmanuele Bassi 5ea8167802 Add VFL parser for constraints
Constraints can be expressed with a compact syntax, called VFL (visual
format language).
2019-06-30 23:42:45 +01:00
Emmanuele Bassi 92d3d55164 Remove GtkConstraintVariable.set_prefix()
The prefix and name are set at construction time.
2019-06-30 23:42:45 +01:00
Matthias Clasen ba2125d8e1 Add an interactive constraints demo 2019-06-30 23:42:44 +01:00
Matthias Clasen 7c96326c18 Make the constraints demo more interesting
Add a max size to the buttons, to force the
space to open up.
2019-06-30 23:42:44 +01:00
Matthias Clasen 38d353dc1a Add GtkConstraintGuide
This is meant to be a flexible space.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi 7ae04ba36b Use generic pointers for constraint targets
Since GtkWidget implements GtkConstraintTarget, we can omit the explicit
cast, and validate the type at run time.
2019-06-30 23:42:44 +01:00
Matthias Clasen 39c284c490 Redefine constraints with GtkConstraintTarget
This is in preparation for allowing non-widgets
to act as constraint targets.
2019-06-30 23:42:44 +01:00
Matthias Clasen 895e8e25a8 widget: Implement GtkConstraintTarget 2019-06-30 23:42:44 +01:00
Matthias Clasen 04562a76e3 Add GtkConstraintTarget
This is an marker interface that we will
use to accept other things that widgets
in constraints.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi b6781e06c1 Notify a layout change when adding and removing constraints
Changing the set of constraints should cause a relayout.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi 54104b6676 Fix the opposite size measurement in GtkConstraintLayout
We cannot use the given "for size" when querying our children, because
the constraint layout has no idea about the opposite size of its
children until the layout is complete.

Additionally, we should only suggest an opposite size for the layout if
we have one, instead of suggesting a weak zero size.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi 21450d5f23 Remove size constraints from ConstraintLayoutChild
The size constraints are transient to measurement and allocation, so
they don't really need to be stored inside the GtkLayoutChild subclass
created by a GtkConstraintLayout.
2019-06-30 23:42:44 +01:00
Matthias Clasen a39bbb2041 constraints: Make internal consistency required
The relations between left, right, width
and top, bottom, height are required for
internal consistency. It doesn't make sense
to ever drop these.

Changing the strength of these relations makes
my systems behave much more stable.
2019-06-30 23:42:44 +01:00
Matthias Clasen 176d9c6baf Add gtk_constraint_layout_remove_constraint
Otherwise, you can't do many interesting things.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi 64afa765c8 Do not release reference on the subject of an expression
We don't own the reference in the first place.
2019-06-30 23:42:44 +01:00
Matthias Clasen a246d8c926 constraints solver: Avoid critials
When the solver is finalized with existing
constraints, we end up with criticals when
the constraints ref finalize code calls
back into the hash table. Avoid that by
emptying the hash table beforehand.
2019-06-30 23:42:44 +01:00
Matthias Clasen 0531e663ee constraint solver: Fix thawing
There was an obviously wrong precondition here.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi bd2349c0a0 Do not leak LayoutChild instances
Since the LayoutManager owns the LayoutChild it creates, it's also
responsible for mopping them up.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi 636fbc0f1a Add GtkConstraintLayout demo 2019-06-30 23:42:44 +01:00
Emmanuele Bassi cdf80f1d65 Add GtkConstraintLayout
A layout manager using GtkConstraintSolver to measure and allocate
children.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi e7b2c530c5 Propagate rooting and unrooting widgets to layout managers
Layout managers may need to get access to data attached to the root of a
scene graph.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi e07098da03 window: Create a GtkConstraintSolver
Implement the GtkRoot getter for GtkConstraintSolver.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi 98a21bf498 Assign a GtkConstraintSolver to each GtkRoot
Constraints need to work across different parents, so it's better to
have a single constraint solver per top level.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi c694dd6049 Move the Root interface to a private header
We don't expect out of tree implementations of GtkRoot, and having the
interface structure private to the GTK code allows us to add virtual
functions involving private types.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi 6b308cd71e Add constraint solver
GtkConstraintSolver is an implementation of the Cassowary constraint
solving algorithm:

  http://constraints.cs.washington.edu/cassowary/

The Cassowary method allows to incrementally solve a tableau of linear
equations, in the form of:

  x = y × coefficient + constant

with different weights, or strengths, applied to each one.

These equations can be used to describe constraints applied to a layout
of UI elements, which allows layout managers using the Cassowary method
to quickly, and efficiently, lay out widgets in complex relations
between themselves and their parent container.
2019-06-30 23:42:44 +01:00
Matthias Clasen 3b6ee32f83 Fix a crash in action muxer destruction
I've seen a crash when the action muxer gets
disposed during widget destroy, and tries to
disconnect from widget signals too late.

There is no real need to disconnect, since the
only time an action muxer is going away is when
its widget is destroyed, so just don't do it.
2019-06-30 18:37:32 +00:00
Timm Bäder 3bc3e140dd transform: Add transform_bounds fast path for 2D_AFFINE transforms
E.g. anything involving a scale. This is important when e.g. scrolling
in the node list in the recorder, which scales every recorded node down
to fit in the list.
2019-06-29 09:49:38 +02:00
Timm Bäder a6a9853676 Adwaita: Fix popover style
We add the .background class to the popover node now.
2019-06-29 09:06:32 +02:00
Timm Bäder 6b42e5b433 gl renderer: Fix push/pop modelview behavior 2019-06-29 08:57:27 +02:00
Timm Bäder 99c01607f1 gl renderer: Remove some dead code 2019-06-29 08:53:36 +02:00
Timm Bäder 071748592d gl renderer: Don't upload GL textures into the icon cache 2019-06-29 07:15:43 +02:00
Timm Bäder 8dd74eac2e transform: Add skew parsing 2019-06-29 07:15:43 +02:00
Matthias Clasen f6a2678486 Add another grid layout test
This one will be used for comparison
with constraint layouts.
2019-06-28 19:21:21 +00:00
Matthias Clasen e28ec2a3eb Some more grid layout tests
Add testcases for spanning children and homogeneity.
2019-06-28 18:07:23 +00:00
Matthias Clasen c4fd786866 Add a test for the grid layout manager
Test some obvious conditions. This is mainly
to test the waters for more intesting tests
with other layout managers later.
2019-06-28 13:30:16 +00:00
Matthias Clasen 8fa7de5563 grid layout: Fix initial property values
Too bad that we don't cover layout children
in the default value test - it would have
caught this.
2019-06-28 12:42:06 +00:00
166 changed files with 33719 additions and 13760 deletions
+17 -18
View File
@@ -1,7 +1,7 @@
stages:
- build
- flatpak
- deploy
# - deploy
.cache-paths: &cache-paths
paths:
@@ -101,20 +101,19 @@ flatpak-master:icon-browser:
APPID: org.gtk.IconBrowser4
<<: *flatpak-master
pages:
image: registry.gitlab.gnome.org/gnome/gtk/master:v6
stage: deploy
script:
- meson -Ddocumentation=true _build .
- ninja -C _build
- ninja -C _build gdk4-doc gsk4-doc gtk4-doc
- mkdir -p public/
- mv _build/docs/reference/gtk/html/ public/gtk/
- mv _build/docs/reference/gdk/html/ public/gdk/
- mv _build/docs/reference/gsk/html/ public/gsk/
artifacts:
paths:
- public
only:
- master
#pages:
# image: registry.gitlab.gnome.org/gnome/gtk/master:v6
# stage: deploy
# script:
# - meson -Dgtk_doc=true _build .
# - ninja -C _build
# - ninja -C _build gdk4-doc gsk4-doc gtk4-doc
# - mkdir -p public/
# - mv _build/docs/reference/gtk/html/ public/gtk/
# - mv _build/docs/reference/gdk/html/ public/gdk/
# - mv _build/docs/reference/gsk/html/ public/gsk/
# artifacts:
# paths:
# - public
# only:
# - master
-6
View File
@@ -56,12 +56,6 @@
/* Define if GStreamer support is available */
#mesondefine HAVE_GSTREAMER
/* Define to 1 if you have the `httpGetAuthString' function. */
#mesondefine HAVE_HTTPGETAUTHSTRING
/* Define if cups http_t authstring field is accessible */
#mesondefine HAVE_HTTP_AUTHSTRING
/* Define to 1 if you have the <inttypes.h> header file. */
#mesondefine HAVE_INTTYPES_H
@@ -0,0 +1,115 @@
/*
* Copyright © 2019 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
*/
#include "config.h"
#include "constraint-editor-application.h"
#include "constraint-editor-window.h"
struct _ConstraintEditorApplication
{
GtkApplication parent_instance;
};
G_DEFINE_TYPE(ConstraintEditorApplication, constraint_editor_application, GTK_TYPE_APPLICATION);
static void
constraint_editor_application_init (ConstraintEditorApplication *app)
{
}
static void
quit_activated (GSimpleAction *action,
GVariant *parameter,
gpointer data)
{
g_application_quit (G_APPLICATION (data));
}
static GActionEntry app_entries[] =
{
{ "quit", quit_activated, NULL, NULL, NULL }
};
static void
constraint_editor_application_startup (GApplication *app)
{
const char *quit_accels[2] = { "<Ctrl>Q", NULL };
const char *open_accels[2] = { "<Ctrl>O", NULL };
GtkCssProvider *provider;
G_APPLICATION_CLASS (constraint_editor_application_parent_class)->startup (app);
g_action_map_add_action_entries (G_ACTION_MAP (app),
app_entries, G_N_ELEMENTS (app_entries),
app);
gtk_application_set_accels_for_action (GTK_APPLICATION (app), "app.quit", quit_accels);
gtk_application_set_accels_for_action (GTK_APPLICATION (app), "win.open", open_accels);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider, "/org/gtk/gtk4/constraint-editor/constraint-editor.css");
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
}
static void
constraint_editor_application_activate (GApplication *app)
{
ConstraintEditorWindow *win;
win = constraint_editor_window_new (CONSTRAINT_EDITOR_APPLICATION (app));
gtk_window_present (GTK_WINDOW (win));
}
static void
constraint_editor_application_open (GApplication *app,
GFile **files,
gint n_files,
const gchar *hint)
{
ConstraintEditorWindow *win;
gint i;
for (i = 0; i < n_files; i++)
{
win = constraint_editor_window_new (CONSTRAINT_EDITOR_APPLICATION (app));
constraint_editor_window_load (win, files[i]);
gtk_window_present (GTK_WINDOW (win));
}
}
static void
constraint_editor_application_class_init (ConstraintEditorApplicationClass *class)
{
GApplicationClass *application_class = G_APPLICATION_CLASS (class);
application_class->startup = constraint_editor_application_startup;
application_class->activate = constraint_editor_application_activate;
application_class->open = constraint_editor_application_open;
}
ConstraintEditorApplication *
constraint_editor_application_new (void)
{
return g_object_new (CONSTRAINT_EDITOR_APPLICATION_TYPE,
"application-id", "org.gtk.gtk4.ConstraintEditor",
"flags", G_APPLICATION_HANDLES_OPEN,
NULL);
}
@@ -0,0 +1,28 @@
/*
* Copyright © 2019 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
*/
#pragma once
#include <gtk/gtk.h>
#define CONSTRAINT_EDITOR_APPLICATION_TYPE (constraint_editor_application_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintEditorApplication, constraint_editor_application, CONSTRAINT, EDITOR_APPLICATION, GtkApplication)
ConstraintEditorApplication *constraint_editor_application_new (void);
@@ -0,0 +1,639 @@
/*
* Copyright © 2019 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
*/
#include "config.h"
#include "constraint-editor-window.h"
#include "constraint-view.h"
#include "constraint-editor.h"
#include "guide-editor.h"
struct _ConstraintEditorWindow
{
GtkApplicationWindow parent_instance;
GtkWidget *paned;
GtkWidget *view;
GtkWidget *list;
};
G_DEFINE_TYPE(ConstraintEditorWindow, constraint_editor_window, GTK_TYPE_APPLICATION_WINDOW);
static GtkConstraintTarget *
find_target (GListModel *model,
GtkConstraintTarget *orig)
{
const char *name;
const char *model_name;
gpointer item;
int i;
if (orig == NULL)
return NULL;
if (GTK_IS_LABEL (orig))
name = gtk_label_get_label (GTK_LABEL (orig));
else if (GTK_IS_CONSTRAINT_GUIDE (orig))
name = gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (orig));
else
{
g_warning ("Don't know how to handle %s targets", G_OBJECT_TYPE_NAME (orig));
return NULL;
}
for (i = 0; i < g_list_model_get_n_items (model); i++)
{
item = g_list_model_get_item (model, i);
g_object_unref (item);
if (GTK_IS_WIDGET (item))
model_name = gtk_widget_get_name (GTK_WIDGET (item));
else
model_name = gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (item));
if (strcmp (name, model_name) == 0)
return GTK_CONSTRAINT_TARGET (item);
}
g_warning ("Failed to find target '%s'", name);
return NULL;
}
gboolean
constraint_editor_window_load (ConstraintEditorWindow *self,
GFile *file)
{
char *path;
GtkBuilder *builder;
GError *error = NULL;
GtkWidget *view;
GtkLayoutManager *layout;
GtkWidget *child;
const char *name;
gpointer item;
int i;
GListModel *list;
path = g_file_get_path (file);
builder = gtk_builder_new ();
if (!gtk_builder_add_from_file (builder, path, &error))
{
g_print ("Could not load %s: %s", path, error->message);
g_error_free (error);
g_free (path);
g_object_unref (builder);
return FALSE;
}
view = GTK_WIDGET (gtk_builder_get_object (builder, "view"));
if (!GTK_IS_BOX (view))
{
g_print ("Could not load %s: No GtkBox named 'view'", path);
g_free (path);
g_object_unref (builder);
return FALSE;
}
layout = gtk_widget_get_layout_manager (view);
if (!GTK_IS_CONSTRAINT_LAYOUT (layout))
{
g_print ("Could not load %s: Widget 'view' does not use GtkConstraintLayout", path);
g_free (path);
g_object_unref (builder);
return FALSE;
}
for (child = gtk_widget_get_first_child (view);
child;
child = gtk_widget_get_next_sibling (child))
{
if (!GTK_IS_LABEL (child))
{
g_print ("Skipping non-GtkLabel child\n");
continue;
}
name = gtk_label_get_label (GTK_LABEL (child));
constraint_view_add_child (CONSTRAINT_VIEW (self->view), name);
}
list = gtk_constraint_layout_observe_guides (GTK_CONSTRAINT_LAYOUT (layout));
for (i = 0; i < g_list_model_get_n_items (list); i++)
{
GtkConstraintGuide *guide, *clone;
int w, h;
item = g_list_model_get_item (list, i);
guide = GTK_CONSTRAINT_GUIDE (item);
/* need to clone here, to attach to the right targets */
clone = gtk_constraint_guide_new ();
gtk_constraint_guide_set_name (clone, gtk_constraint_guide_get_name (guide));
gtk_constraint_guide_set_strength (clone, gtk_constraint_guide_get_strength (guide));
gtk_constraint_guide_get_min_size (guide, &w, &h);
gtk_constraint_guide_set_min_size (clone, w, h);
gtk_constraint_guide_get_nat_size (guide, &w, &h);
gtk_constraint_guide_set_nat_size (clone, w, h);
gtk_constraint_guide_get_max_size (guide, &w, &h);
gtk_constraint_guide_set_max_size (clone, w, h);
constraint_view_add_guide (CONSTRAINT_VIEW (self->view), clone);
g_object_unref (guide);
g_object_unref (clone);
}
g_object_unref (list);
list = gtk_constraint_layout_observe_constraints (GTK_CONSTRAINT_LAYOUT (layout));
for (i = 0; i < g_list_model_get_n_items (list); i++)
{
GtkConstraint *constraint;
GtkConstraint *clone;
GtkConstraintTarget *target;
GtkConstraintTarget *source;
item = g_list_model_get_item (list, i);
constraint = GTK_CONSTRAINT (item);
target = gtk_constraint_get_target (constraint);
source = gtk_constraint_get_source (constraint);
clone = gtk_constraint_new (find_target (constraint_view_get_model (CONSTRAINT_VIEW (self->view)), target),
gtk_constraint_get_target_attribute (constraint),
gtk_constraint_get_relation (constraint),
find_target (constraint_view_get_model (CONSTRAINT_VIEW (self->view)), source),
gtk_constraint_get_target_attribute (constraint),
gtk_constraint_get_multiplier (constraint),
gtk_constraint_get_constant (constraint),
gtk_constraint_get_strength (constraint));
constraint_view_add_constraint (CONSTRAINT_VIEW (self->view), clone);
g_object_unref (constraint);
g_object_unref (clone);
}
g_object_unref (list);
g_free (path);
g_object_unref (builder);
return TRUE;
}
static void
open_response_cb (GtkNativeDialog *dialog,
gint response,
ConstraintEditorWindow *self)
{
gtk_native_dialog_hide (dialog);
if (response == GTK_RESPONSE_ACCEPT)
{
GFile *file;
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
constraint_editor_window_load (self, file);
g_object_unref (file);
}
gtk_native_dialog_destroy (dialog);
}
static void
open_cb (GtkWidget *button,
ConstraintEditorWindow *self)
{
GtkFileChooserNative *dialog;
dialog = gtk_file_chooser_native_new ("Open file",
GTK_WINDOW (self),
GTK_FILE_CHOOSER_ACTION_OPEN,
"_Load",
"_Cancel");
gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (dialog), TRUE);
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), ".");
g_signal_connect (dialog, "response", G_CALLBACK (open_response_cb), self);
gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog));
}
static void
serialize_child (GString *str,
int indent,
GtkWidget *child)
{
const char *name;
name = gtk_widget_get_name (child);
g_string_append_printf (str, "%*s<child>\n", indent, "");
g_string_append_printf (str, "%*s <object class=\"GtkLabel\" id=\"%s\">\n", indent, "", name);
g_string_append_printf (str, "%*s <property name=\"label\">%s</property>\n", indent, "", name);
g_string_append_printf (str, "%*s </object>\n", indent, "");
g_string_append_printf (str, "%*s</child>\n", indent, "");
}
static char *
serialize_model (GListModel *list)
{
GString *str = g_string_new ("");
int i;
g_string_append (str, "<interface>\n");
g_string_append (str, " <object class=\"GtkBox\" id=\"view\">\n");
g_string_append (str, " <property name=\"layout-manager\">\n");
g_string_append (str, " <object class=\"GtkConstraintLayout\">\n");
g_string_append (str, " <constraints>\n");
for (i = 0; i < g_list_model_get_n_items (list); i++)
{
gpointer item = g_list_model_get_item (list, i);
g_object_unref (item);
if (GTK_IS_CONSTRAINT (item))
constraint_editor_serialize_constraint (str, 10, GTK_CONSTRAINT (item));
else if (GTK_IS_CONSTRAINT_GUIDE (item))
guide_editor_serialize_guide (str, 10, GTK_CONSTRAINT_GUIDE (item));
}
g_string_append (str, " </constraints>\n");
g_string_append (str, " </object>\n");
g_string_append (str, " </property>\n");
for (i = 0; i < g_list_model_get_n_items (list); i++)
{
gpointer item = g_list_model_get_item (list, i);
g_object_unref (item);
if (GTK_IS_WIDGET (item))
serialize_child (str, 4, GTK_WIDGET (item));
}
g_string_append (str, " </object>\n");
g_string_append (str, "</interface>\n");
return g_string_free (str, FALSE);
}
static void
save_response_cb (GtkNativeDialog *dialog,
gint response,
ConstraintEditorWindow *self)
{
gtk_native_dialog_hide (dialog);
if (response == GTK_RESPONSE_ACCEPT)
{
GListModel *model;
char *text, *filename;
GError *error = NULL;
model = constraint_view_get_model (CONSTRAINT_VIEW (self->view));
text = serialize_model (model);
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
if (!g_file_set_contents (filename, text, -1, &error))
{
GtkWidget *dialog;
dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self))),
GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"Saving failed");
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
"%s", error->message);
g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
gtk_widget_show (dialog);
g_error_free (error);
}
g_free (filename);
}
gtk_native_dialog_destroy (dialog);
}
static void
save_cb (GtkWidget *button,
ConstraintEditorWindow *self)
{
GtkFileChooserNative *dialog;
dialog = gtk_file_chooser_native_new ("Save constraints",
GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (button))),
GTK_FILE_CHOOSER_ACTION_SAVE,
"_Save",
"_Cancel");
gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (dialog), TRUE);
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), ".");
g_signal_connect (dialog, "response", G_CALLBACK (save_response_cb), self);
gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog));
}
static void
constraint_editor_window_finalize (GObject *object)
{
//ConstraintEditorWindow *self = (ConstraintEditorWindow *)object;
G_OBJECT_CLASS (constraint_editor_window_parent_class)->finalize (object);
}
static int child_counter;
static int guide_counter;
static void
add_child (ConstraintEditorWindow *win)
{
char *name;
child_counter++;
name = g_strdup_printf ("Child %d", child_counter);
constraint_view_add_child (CONSTRAINT_VIEW (win->view), name);
g_free (name);
}
static void
add_guide (ConstraintEditorWindow *win)
{
char *name;
GtkConstraintGuide *guide;
guide_counter++;
name = g_strdup_printf ("Guide %d", guide_counter);
guide = gtk_constraint_guide_new ();
gtk_constraint_guide_set_name (guide, name);
g_free (name);
constraint_view_add_guide (CONSTRAINT_VIEW (win->view), guide);
}
static void
constraint_editor_done (ConstraintEditor *editor,
GtkConstraint *constraint,
ConstraintEditorWindow *win)
{
GtkConstraint *old_constraint;
g_object_get (editor, "constraint", &old_constraint, NULL);
if (old_constraint)
constraint_view_remove_constraint (CONSTRAINT_VIEW (win->view), old_constraint);
constraint_view_add_constraint (CONSTRAINT_VIEW (win->view), constraint);
g_clear_object (&old_constraint);
gtk_widget_destroy (gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW));
}
static void
edit_constraint (ConstraintEditorWindow *win,
GtkConstraint *constraint)
{
GtkWidget *window;
ConstraintEditor *editor;
GListModel *model;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (win));
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
if (constraint)
gtk_window_set_title (GTK_WINDOW (window), "Edit Constraint");
else
gtk_window_set_title (GTK_WINDOW (window), "Create Constraint");
model = constraint_view_get_model (CONSTRAINT_VIEW (win->view));
editor = constraint_editor_new (model, constraint);
gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (editor));
g_signal_connect (editor, "done", G_CALLBACK (constraint_editor_done), win);
gtk_widget_show (window);
}
static void
add_constraint (ConstraintEditorWindow *win)
{
edit_constraint (win, NULL);
}
static void
guide_editor_done (GuideEditor *editor,
GtkConstraintGuide *guide,
ConstraintEditorWindow *win)
{
gtk_widget_destroy (gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW));
}
static void
edit_guide (ConstraintEditorWindow *win,
GtkConstraintGuide *guide)
{
GtkWidget *window;
GuideEditor *editor;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (win));
gtk_window_set_title (GTK_WINDOW (window), "Edit Guide");
editor = guide_editor_new (guide);
gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (editor));
g_signal_connect (editor, "done", G_CALLBACK (guide_editor_done), win);
gtk_widget_show (window);
}
static void
row_activated (GtkListBox *list,
GtkListBoxRow *row,
ConstraintEditorWindow *win)
{
GObject *item;
item = G_OBJECT (g_object_get_data (G_OBJECT (row), "item"));
if (GTK_IS_CONSTRAINT (item))
edit_constraint (win, GTK_CONSTRAINT (item));
else if (GTK_IS_CONSTRAINT_GUIDE (item))
edit_guide (win, GTK_CONSTRAINT_GUIDE (item));
}
static void
constraint_editor_window_class_init (ConstraintEditorWindowClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
g_type_ensure (CONSTRAINT_VIEW_TYPE);
object_class->finalize = constraint_editor_window_finalize;
gtk_widget_class_set_template_from_resource (widget_class,
"/org/gtk/gtk4/constraint-editor/constraint-editor-window.ui");
gtk_widget_class_bind_template_child (widget_class, ConstraintEditorWindow, paned);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditorWindow, view);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditorWindow, list);
gtk_widget_class_bind_template_callback (widget_class, open_cb);
gtk_widget_class_bind_template_callback (widget_class, save_cb);
gtk_widget_class_bind_template_callback (widget_class, add_child);
gtk_widget_class_bind_template_callback (widget_class, add_guide);
gtk_widget_class_bind_template_callback (widget_class, add_constraint);
gtk_widget_class_bind_template_callback (widget_class, row_activated);
}
static void
row_edit (GtkButton *button,
ConstraintEditorWindow *win)
{
GtkWidget *row;
GObject *item;
row = gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_LIST_BOX_ROW);
item = (GObject *)g_object_get_data (G_OBJECT (row), "item");
if (GTK_IS_CONSTRAINT (item))
edit_constraint (win, GTK_CONSTRAINT (item));
else if (GTK_IS_CONSTRAINT_GUIDE (item))
edit_guide (win, GTK_CONSTRAINT_GUIDE (item));
}
static void
mark_constraints_invalid (ConstraintEditorWindow *win,
gpointer removed)
{
GtkWidget *child;
GObject *item;
for (child = gtk_widget_get_first_child (win->list);
child;
child = gtk_widget_get_next_sibling (child))
{
item = (GObject *)g_object_get_data (G_OBJECT (child), "item");
if (GTK_IS_CONSTRAINT (item))
{
GtkConstraint *constraint = GTK_CONSTRAINT (item);
if (gtk_constraint_get_target (constraint) == (GtkConstraintTarget *)removed ||
gtk_constraint_get_source (constraint) == (GtkConstraintTarget *)removed)
{
GtkWidget *button;
button = (GtkWidget *)g_object_get_data (G_OBJECT (child), "edit");
gtk_button_set_icon_name (GTK_BUTTON (button), "dialog-warning-symbolic");
gtk_widget_set_tooltip_text (button, "Constraint is invalid");
}
}
}
}
static void
row_delete (GtkButton *button,
ConstraintEditorWindow *win)
{
GtkWidget *row;
GObject *item;
row = gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_LIST_BOX_ROW);
item = (GObject *)g_object_get_data (G_OBJECT (row), "item");
if (GTK_IS_CONSTRAINT (item))
constraint_view_remove_constraint (CONSTRAINT_VIEW (win->view),
GTK_CONSTRAINT (item));
else if (GTK_IS_CONSTRAINT_GUIDE (item))
{
mark_constraints_invalid (win, item);
constraint_view_remove_guide (CONSTRAINT_VIEW (win->view),
GTK_CONSTRAINT_GUIDE (item));
}
else if (GTK_IS_WIDGET (item))
{
mark_constraints_invalid (win, item);
constraint_view_remove_child (CONSTRAINT_VIEW (win->view),
GTK_WIDGET (item));
}
}
static GtkWidget *
create_widget_func (gpointer item,
gpointer user_data)
{
ConstraintEditorWindow *win = user_data;
const char *name;
char *freeme = NULL;
GtkWidget *row, *box, *label, *button;
if (GTK_IS_WIDGET (item))
name = gtk_widget_get_name (GTK_WIDGET (item));
else if (GTK_IS_CONSTRAINT_GUIDE (item))
name = gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (item));
else if (GTK_IS_CONSTRAINT (item))
name = freeme = constraint_editor_constraint_to_string (GTK_CONSTRAINT (item));
else
name = "";
row = gtk_list_box_row_new ();
g_object_set_data_full (G_OBJECT (row), "item", g_object_ref (item), g_object_unref);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
label = gtk_label_new (name);
if (GTK_IS_WIDGET (item) || GTK_IS_CONSTRAINT_GUIDE (item))
g_object_bind_property (item, "name",
label, "label",
G_BINDING_DEFAULT);
g_object_set (label, "margin", 10, NULL);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_widget_set_hexpand (label, TRUE);
gtk_container_add (GTK_CONTAINER (row), box);
gtk_container_add (GTK_CONTAINER (box), label);
if (GTK_IS_CONSTRAINT (item) || GTK_IS_CONSTRAINT_GUIDE (item))
{
button = gtk_button_new_from_icon_name ("document-edit-symbolic");
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
g_signal_connect (button, "clicked", G_CALLBACK (row_edit), win);
g_object_set_data (G_OBJECT (row), "edit", button);
gtk_container_add (GTK_CONTAINER (box), button);
button = gtk_button_new_from_icon_name ("edit-delete-symbolic");
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
g_signal_connect (button, "clicked", G_CALLBACK (row_delete), win);
gtk_container_add (GTK_CONTAINER (box), button);
}
else if (GTK_IS_WIDGET (item))
{
button = gtk_button_new_from_icon_name ("edit-delete-symbolic");
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
g_signal_connect (button, "clicked", G_CALLBACK (row_delete), win);
gtk_container_add (GTK_CONTAINER (box), button);
}
g_free (freeme);
return row;
}
static void
constraint_editor_window_init (ConstraintEditorWindow *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
gtk_list_box_bind_model (GTK_LIST_BOX (self->list),
constraint_view_get_model (CONSTRAINT_VIEW (self->view)),
create_widget_func,
self,
NULL);
}
ConstraintEditorWindow *
constraint_editor_window_new (ConstraintEditorApplication *application)
{
return g_object_new (CONSTRAINT_EDITOR_WINDOW_TYPE,
"application", application,
NULL);
}
@@ -0,0 +1,34 @@
/*
* Copyright © 2019 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
*/
#pragma once
#include <gtk/gtk.h>
#include "constraint-editor-application.h"
#define CONSTRAINT_EDITOR_WINDOW_TYPE (constraint_editor_window_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintEditorWindow, constraint_editor_window, CONSTRAINT, EDITOR_WINDOW, GtkApplicationWindow)
ConstraintEditorWindow * constraint_editor_window_new (ConstraintEditorApplication *application);
gboolean constraint_editor_window_load (ConstraintEditorWindow *self,
GFile *file);
@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="ConstraintEditorWindow" parent="GtkApplicationWindow">
<style>
<class name="devel"/>
</style>
<property name="title" translatable="yes">GTK Constraint Editor</property>
<property name="default-width">1024</property>
<property name="default-height">768</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="title" translatable="yes">GTK Constraint Editor</property>
<property name="show-title-buttons">1</property>
<child type="start">
<object class="GtkButton">
<property name="icon-name">document-open-symbolic</property>
<property name="tooltip-text">Open ui file</property>
<signal name="clicked" handler="open_cb"/>
</object>
</child>
<child type="start">
<object class="GtkButton">
<property name="icon-name">document-save-symbolic</property>
<property name="tooltip-text">Save to ui file</property>
<signal name="clicked" handler="save_cb"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkPaned" id="paned">
<property name="orientation">horizontal</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<child>
<object class="GtkButton">
<property name="label">Add Child</property>
<signal name="clicked" handler="add_child" swapped="yes"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Add Guide</property>
<signal name="clicked" handler="add_guide" swapped="yes"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Add Constraint</property>
<signal name="clicked" handler="add_constraint" swapped="yes"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<property name="vscrollbar-policy">automatic</property>
<property name="vexpand">1</property>
<child>
<object class="GtkListBox" id="list">
<property name="show-separators">1</property>
<property name="selection-mode">none</property>
<signal name="row-activated" handler="row_activated"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="ConstraintView" id="view">
</object>
</child>
</object>
</child>
</template>
</interface>
+656
View File
@@ -0,0 +1,656 @@
/*
* Copyright © 2019 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
*/
#include "config.h"
#include "constraint-editor.h"
struct _ConstraintEditor
{
GtkWidget parent_instance;
GtkWidget *grid;
GtkWidget *target;
GtkWidget *target_attr;
GtkWidget *relation;
GtkWidget *source;
GtkWidget *source_attr;
GtkWidget *multiplier;
GtkWidget *constant;
GtkWidget *strength;
GtkWidget *preview;
GtkWidget *button;
GtkConstraint *constraint;
GListModel *model;
gboolean constructed;
};
enum {
PROP_MODEL = 1,
PROP_CONSTRAINT,
LAST_PROP
};
static GParamSpec *pspecs[LAST_PROP];
enum {
DONE,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
G_DEFINE_TYPE(ConstraintEditor, constraint_editor, GTK_TYPE_WIDGET);
static const char *
get_target_name (GtkConstraintTarget *target)
{
if (target == NULL)
return "super";
else if (GTK_IS_WIDGET (target))
return gtk_widget_get_name (GTK_WIDGET (target));
else if (GTK_IS_CONSTRAINT_GUIDE (target))
return gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (target));
else
return "";
}
static void
constraint_target_combo (GListModel *model,
GtkWidget *combo,
gboolean is_source)
{
int i;
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "super", "Super");
if (model)
{
for (i = 0; i < g_list_model_get_n_items (model); i++)
{
GObject *item = g_list_model_get_object (model, i);
const char *name;
if (GTK_IS_CONSTRAINT (item))
continue;
name = get_target_name (GTK_CONSTRAINT_TARGET (item));
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), name, name);
g_object_unref (item);
}
}
}
static void
constraint_attribute_combo (GtkWidget *combo,
gboolean is_source)
{
if (is_source)
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "none", "None");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "left", "Left");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "right", "Right");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "top", "Top");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "bottom", "Bottom");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "start", "Start");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "end", "End");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "width", "Width");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "height", "Height");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "center-x", "Center X");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "center-y", "Center Y");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "baseline", "Baseline");
}
static void
constraint_relation_combo (GtkWidget *combo)
{
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "le", "");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "eq", "=");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "ge", "");
}
static void
constraint_strength_combo (GtkWidget *combo)
{
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "weak", "Weak");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "medium", "Medium");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "strong", "Strong");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "required", "Required");
}
static gpointer
get_target (GListModel *model,
const char *id)
{
int i;
if (strcmp ("super", id) == 0)
return NULL;
for (i = 0; i < g_list_model_get_n_items (model); i++)
{
GObject *item = g_list_model_get_object (model, i);
g_object_unref (item);
if (GTK_IS_CONSTRAINT (item))
continue;
else if (GTK_IS_WIDGET (item))
{
if (strcmp (id, gtk_widget_get_name (GTK_WIDGET (item))) == 0)
return item;
}
else if (GTK_IS_CONSTRAINT_GUIDE (item))
{
if (strcmp (id, gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (item))) == 0)
return item;
}
}
return NULL;
}
static GtkConstraintAttribute
get_target_attr (const char *id)
{
GtkConstraintAttribute attr;
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_ATTRIBUTE);
GEnumValue *value = g_enum_get_value_by_nick (class, id);
attr = value->value;
g_type_class_unref (class);
return attr;
}
static const char *
get_attr_nick (GtkConstraintAttribute attr)
{
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_ATTRIBUTE);
GEnumValue *value = g_enum_get_value (class, attr);
const char *nick = value->value_nick;
g_type_class_unref (class);
return nick;
}
static GtkConstraintRelation
get_relation (const char *id)
{
GtkConstraintRelation relation;
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_RELATION);
GEnumValue *value = g_enum_get_value_by_nick (class, id);
relation = value->value;
g_type_class_unref (class);
return relation;
}
static const char *
get_relation_nick (GtkConstraintRelation relation)
{
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_RELATION);
GEnumValue *value = g_enum_get_value (class, relation);
const char *nick = value->value_nick;
g_type_class_unref (class);
return nick;
}
static GtkConstraintStrength
get_strength (const char *id)
{
GtkConstraintStrength strength;
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH);
GEnumValue *value = g_enum_get_value_by_nick (class, id);
strength = value->value;
g_type_class_unref (class);
return strength;
}
static const char *
get_strength_nick (GtkConstraintStrength strength)
{
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH);
GEnumValue *value = g_enum_get_value (class, strength);
const char *nick = value->value_nick;
g_type_class_unref (class);
return nick;
}
void
constraint_editor_serialize_constraint (GString *str,
int indent,
GtkConstraint *constraint)
{
const char *target;
const char *target_attr;
const char *relation;
const char *source;
const char *source_attr;
double multiplier;
double constant;
const char *strength;
target = get_target_name (gtk_constraint_get_target (constraint));
target_attr = get_attr_nick (gtk_constraint_get_target_attribute (constraint));
relation = get_relation_nick (gtk_constraint_get_relation (constraint));
source = get_target_name (gtk_constraint_get_source (constraint));
source_attr = get_attr_nick (gtk_constraint_get_source_attribute (constraint));
multiplier = gtk_constraint_get_multiplier (constraint);
constant = gtk_constraint_get_constant (constraint);
strength = get_strength_nick (gtk_constraint_get_strength (constraint));
g_string_append_printf (str, "%*s<constraint target=\"%s\" target-attribute=\"%s\"\n", indent, "", target, target_attr);
g_string_append_printf (str, "%*s relation=\"%s\"\n", indent, "", relation);
if (strcmp (source_attr, "none") != 0)
{
g_string_append_printf (str, "%*s source=\"%s\" source-attribute=\"%s\"\n", indent, "", source, source_attr);
g_string_append_printf (str, "%*s multiplier=\"%g\"\n", indent, "", multiplier);
}
g_string_append_printf (str, "%*s constant=\"%g\"\n", indent, "", constant);
g_string_append_printf (str, "%*s strength=\"%s\" />\n", indent, "", strength);
}
static void
create_constraint (GtkButton *button,
ConstraintEditor *editor)
{
const char *id;
gpointer target;
GtkConstraintAttribute target_attr;
gpointer source;
GtkConstraintAttribute source_attr;
GtkConstraintRelation relation;
double multiplier;
double constant;
int strength;
GtkConstraint *constraint;
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target));
target = get_target (editor->model, id);
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target_attr));
target_attr = get_target_attr (id);
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source));
source = get_target (editor->model, id);
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
source_attr = get_target_attr (id);
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->relation));
relation = get_relation (id);
multiplier = g_ascii_strtod (gtk_editable_get_text (GTK_EDITABLE (editor->multiplier)), NULL);
constant = g_ascii_strtod (gtk_editable_get_text (GTK_EDITABLE (editor->constant)), NULL);
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->strength));
strength = get_strength (id);
constraint = gtk_constraint_new (target, target_attr,
relation,
source, source_attr,
multiplier,
constant,
strength);
g_signal_emit (editor, signals[DONE], 0, constraint);
g_object_unref (constraint);
}
static void
source_attr_changed (ConstraintEditor *editor)
{
const char *id;
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
if (strcmp (id, "none") == 0)
{
gtk_combo_box_set_active (GTK_COMBO_BOX (editor->source), -1);
gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), "");
gtk_widget_set_sensitive (editor->source, FALSE);
gtk_widget_set_sensitive (editor->multiplier, FALSE);
}
else
{
gtk_widget_set_sensitive (editor->source, TRUE);
gtk_widget_set_sensitive (editor->multiplier, TRUE);
}
}
char *
constraint_editor_constraint_to_string (GtkConstraint *constraint)
{
GString *str;
const char *name;
const char *attr;
const char *relation;
double c, m;
str = g_string_new ("");
name = get_target_name (gtk_constraint_get_target (constraint));
attr = get_attr_nick (gtk_constraint_get_target_attribute (constraint));
relation = get_relation_nick (gtk_constraint_get_relation (constraint));
if (name == NULL)
name = "[ ]";
g_string_append_printf (str, "%s.%s %s ", name, attr, relation);
c = gtk_constraint_get_constant (constraint);
attr = get_attr_nick (gtk_constraint_get_source_attribute (constraint));
if (strcmp (attr, "none") != 0)
{
name = get_target_name (gtk_constraint_get_source (constraint));
m = gtk_constraint_get_multiplier (constraint);
if (name == NULL)
name = "[ ]";
g_string_append_printf (str, "%s.%s", name, attr);
if (m != 1.0)
g_string_append_printf (str, " × %g", m);
if (c > 0.0)
g_string_append_printf (str, " + %g", c);
else if (c < 0.0)
g_string_append_printf (str, " - %g", -c);
}
else
g_string_append_printf (str, "%g", c);
return g_string_free (str, FALSE);
}
static void
update_preview (ConstraintEditor *editor)
{
GString *str;
const char *name;
const char *attr;
char *relation;
const char *multiplier;
const char *constant;
double c, m;
if (!editor->constructed)
return;
str = g_string_new ("");
name = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target));
attr = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target_attr));
relation = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (editor->relation));
if (name == NULL)
name = "[ ]";
g_string_append_printf (str, "%s.%s %s ", name, attr, relation);
g_free (relation);
constant = gtk_editable_get_text (GTK_EDITABLE (editor->constant));
c = g_ascii_strtod (constant, NULL);
attr = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
if (strcmp (attr, "none") != 0)
{
name = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source));
multiplier = gtk_editable_get_text (GTK_EDITABLE (editor->multiplier));
m = g_ascii_strtod (multiplier, NULL);
if (name == NULL)
name = "[ ]";
g_string_append_printf (str, "%s.%s", name, attr);
if (m != 1.0)
g_string_append_printf (str, " × %g", m);
if (c > 0.0)
g_string_append_printf (str, " + %g", c);
else if (c < 0.0)
g_string_append_printf (str, " - %g", -c);
}
else
g_string_append_printf (str, "%g", c);
gtk_label_set_label (GTK_LABEL (editor->preview), str->str);
g_string_free (str, TRUE);
}
static void
update_button (ConstraintEditor *editor)
{
if (gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target)) != NULL &&
gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source)) != NULL)
gtk_widget_set_sensitive (editor->button, TRUE);
else
gtk_widget_set_sensitive (editor->button, FALSE);
}
static void
constraint_editor_init (ConstraintEditor *editor)
{
gtk_widget_init_template (GTK_WIDGET (editor));
}
static void
constraint_editor_constructed (GObject *object)
{
ConstraintEditor *editor = CONSTRAINT_EDITOR (object);
constraint_target_combo (editor->model, editor->target, FALSE);
constraint_attribute_combo (editor->target_attr, FALSE);
constraint_relation_combo (editor->relation);
constraint_target_combo (editor->model, editor->source, TRUE);
constraint_attribute_combo (editor->source_attr, TRUE);
constraint_strength_combo (editor->strength);
if (editor->constraint)
{
GtkConstraintTarget *target;
GtkConstraintAttribute attr;
GtkConstraintRelation relation;
GtkConstraintStrength strength;
const char *nick;
char *val;
double multiplier;
double constant;
target = gtk_constraint_get_target (editor->constraint);
nick = get_target_name (target);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->target), nick);
attr = gtk_constraint_get_target_attribute (editor->constraint);
nick = get_attr_nick (attr);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->target_attr), nick);
target = gtk_constraint_get_source (editor->constraint);
nick = get_target_name (target);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->source), nick);
attr = gtk_constraint_get_source_attribute (editor->constraint);
nick = get_attr_nick (attr);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->source_attr), nick);
relation = gtk_constraint_get_relation (editor->constraint);
nick = get_relation_nick (relation);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->relation), nick);
multiplier = gtk_constraint_get_multiplier (editor->constraint);
val = g_strdup_printf ("%g", multiplier);
gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), val);
g_free (val);
constant = gtk_constraint_get_constant (editor->constraint);
val = g_strdup_printf ("%g", constant);
gtk_editable_set_text (GTK_EDITABLE (editor->constant), val);
g_free (val);
strength = gtk_constraint_get_strength (editor->constraint);
nick = get_strength_nick (strength);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), nick);
gtk_button_set_label (GTK_BUTTON (editor->button), "Apply");
}
else
{
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->target_attr), "left");
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->source_attr), "left");
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->relation), "eq");
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), "required");
gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), "1.0");
gtk_editable_set_text (GTK_EDITABLE (editor->constant), "0.0");
gtk_button_set_label (GTK_BUTTON (editor->button), "Create");
}
editor->constructed = TRUE;
update_preview (editor);
update_button (editor);
}
static void
constraint_editor_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
ConstraintEditor *self = CONSTRAINT_EDITOR (object);
switch (property_id)
{
case PROP_MODEL:
self->model = g_value_dup_object (value);
break;
case PROP_CONSTRAINT:
self->constraint = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
constraint_editor_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
ConstraintEditor *self = CONSTRAINT_EDITOR (object);
switch (property_id)
{
case PROP_MODEL:
g_value_set_object (value, self->model);
break;
case PROP_CONSTRAINT:
g_value_set_object (value, self->constraint);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
constraint_editor_dispose (GObject *object)
{
ConstraintEditor *self = (ConstraintEditor *)object;
g_clear_pointer (&self->grid, gtk_widget_unparent);
g_clear_object (&self->model);
g_clear_object (&self->constraint);
G_OBJECT_CLASS (constraint_editor_parent_class)->dispose (object);
}
static void
constraint_editor_class_init (ConstraintEditorClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->constructed = constraint_editor_constructed;
object_class->dispose = constraint_editor_dispose;
object_class->set_property = constraint_editor_set_property;
object_class->get_property = constraint_editor_get_property;
pspecs[PROP_CONSTRAINT] =
g_param_spec_object ("constraint", "constraint", "constraint",
GTK_TYPE_CONSTRAINT,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
pspecs[PROP_MODEL] =
g_param_spec_object ("model", "model", "model",
G_TYPE_LIST_MODEL,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, LAST_PROP, pspecs);
signals[DONE] =
g_signal_new ("done",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
NULL,
G_TYPE_NONE, 1, GTK_TYPE_CONSTRAINT);
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
gtk_widget_class_set_template_from_resource (widget_class,
"/org/gtk/gtk4/constraint-editor/constraint-editor.ui");
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, grid);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, target);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, target_attr);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, relation);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, source);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, source_attr);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, multiplier);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, constant);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, strength);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, preview);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, button);
gtk_widget_class_bind_template_callback (widget_class, update_preview);
gtk_widget_class_bind_template_callback (widget_class, update_button);
gtk_widget_class_bind_template_callback (widget_class, create_constraint);
gtk_widget_class_bind_template_callback (widget_class, source_attr_changed);
}
ConstraintEditor *
constraint_editor_new (GListModel *model,
GtkConstraint *constraint)
{
return g_object_new (CONSTRAINT_EDITOR_TYPE,
"model", model,
"constraint", constraint,
NULL);
}
@@ -0,0 +1,12 @@
constraintview {
background: black;
color: white;
}
constraintview .child {
background: red;
}
constraintview .guide {
background: blue;
}
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gtk/gtk4/constraint-editor">
<file preprocess="xml-stripblanks">constraint-editor-window.ui</file>
<file preprocess="xml-stripblanks">constraint-editor.ui</file>
<file preprocess="xml-stripblanks">guide-editor.ui</file>
<file>constraint-editor.css</file>
</gresource>
</gresources>
@@ -0,0 +1,34 @@
/*
* Copyright © 2019 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
*/
#pragma once
#include <gtk/gtk.h>
#define CONSTRAINT_EDITOR_TYPE (constraint_editor_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintEditor, constraint_editor, CONSTRAINT, EDITOR, GtkWidget)
ConstraintEditor * constraint_editor_new (GListModel *model,
GtkConstraint *constraint);
void constraint_editor_serialize_constraint (GString *str,
int indent,
GtkConstraint *constraint);
char *constraint_editor_constraint_to_string (GtkConstraint *constraint);
@@ -0,0 +1,163 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="ConstraintEditor" parent="GtkWidget">
<child>
<object class="GtkGrid" id="grid">
<property name="margin">20</property>
<property name="row-spacing">10</property>
<property name="column-spacing">10</property>
<child>
<object class="GtkLabel">
<property name="label">Target</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="target">
<signal name="changed" handler="update_preview" swapped="yes"/>
<signal name="changed" handler="update_button" swapped="yes"/>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="target_attr">
<signal name="changed" handler="update_preview" swapped="yes"/>
<layout>
<property name="left-attach">2</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Relation</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="relation">
<signal name="changed" handler="update_preview" swapped="yes"/>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Source</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="source">
<signal name="changed" handler="update_preview" swapped="yes"/>
<signal name="changed" handler="update_button" swapped="yes"/>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="source_attr">
<signal name="changed" handler="update_preview" swapped="yes"/>
<signal name="changed" handler="source_attr_changed" swapped="yes"/>
<layout>
<property name="left-attach">2</property>
<property name="top-attach">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Multiplier</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">4</property>
</layout>
</object>
</child>
<child>
<object class="GtkEntry" id="multiplier">
<signal name="changed" handler="update_preview" swapped="yes"/>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">4</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Constant</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">5</property>
</layout>
</object>
</child>
<child>
<object class="GtkEntry" id="constant">
<signal name="changed" handler="update_preview" swapped="yes"/>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">5</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Strength</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">6</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="strength">
<layout>
<property name="left-attach">1</property>
<property name="top-attach">6</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="preview">
<property name="xalign">0</property>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">7</property>
<property name="column-span">2</property>
</layout>
<attributes>
<attribute name="scale" value="1.44"/>
</attributes>
</object>
</child>
<child>
<object class="GtkButton" id="button">
<property name="label">Create</property>
<signal name="clicked" handler="create_constraint"/>
<layout>
<property name="left-attach">2</property>
<property name="top-attach">8</property>
</layout>
</object>
</child>
</object>
</child>
</template>
</interface>
@@ -0,0 +1,93 @@
/*
* Copyright © 2019 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
*/
#include "constraint-view-child.h"
struct _ConstraintViewChild
{
GObject parent_instance;
char *name;
};
enum {
PROP_NAME = 1,
LAST_PROP
};
static GParamSpec props[LAST_PROP];
G_DEFINE_TYPE (ConstraintViewChild, constraint_view_child, G_TYPE_OBJECT)
static void
constraint_view_child_init (ConstraintViewChild *child)
{
}
static void
constraint_view_child_finalize (GObject *object)
{
ConstraintViewChild *child = CONSTRAINT_VIEW_CHILD (object);
g_free (child->name);
G_OBJECT_CLASS (constraint_view_child_parent_class)->finalize (object);
}
static void
constraint_view_child_set_property (GObject *object,
static void
constraint_view_child_class_init (ConstraintViewChildClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = constraint_view_child_finalize;
object_class->get_property = constraint_view_child_get_property;
object_class->set_property = constraint_view_child_set_property;
props[PROP_NAME] =
g_param_spec_string ("name", "name", "name",
NULL,
G_PARAM_READWRITE);
g_object_class_install_properties (object_class, LAST_PROP, props);
}
#define CONSTRAINT_VIEW_CHILD_TYPE (constraint_view_get_type ())
G_DECLARE_TYPE (ConstraintViewChild, constraint_view_child, CONSTRAINT, VIEW_CHILD, GObject)
#define CONSTRAINT_VIEW_WIDGET_TYPE (constraint_view_widget_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintViewWidget, constraint_view_widget, CONSTRAINT, VIEW_WIDGET, ConstraintViewChild)
ConstraintViewWidget * constraint_view_widget_new (void);
#define CONSTRAINT_VIEW_GUIDE_TYPE (constraint_view_guide_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintViewGuide, constraint_view_guide, CONSTRAINT, VIEW_GUIDE, ConstraintViewChild)
ConstraintViewGuide * constraint_view_guide_new (void);
#define CONSTRAINT_VIEW_CONSTRAINT_TYPE (constraint_view_constraint_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintViewConstraint, constraint_view_constraint, CONSTRAINT, VIEW_CONSTRAINT, ConstraintViewChild)
ConstraintViewGuide * constraint_view_constraint_new (void);
@@ -0,0 +1,44 @@
/*
* Copyright © 2019 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
*/
#pragma once
#include <gtk/gtk.h>
#define CONSTRAINT_VIEW_CHILD_TYPE (constraint_view_get_type ())
G_DECLARE_TYPE (ConstraintViewChild, constraint_view_child, CONSTRAINT, VIEW_CHILD, GObject)
#define CONSTRAINT_VIEW_WIDGET_TYPE (constraint_view_widget_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintViewWidget, constraint_view_widget, CONSTRAINT, VIEW_WIDGET, ConstraintViewChild)
ConstraintViewWidget * constraint_view_widget_new (void);
#define CONSTRAINT_VIEW_GUIDE_TYPE (constraint_view_guide_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintViewGuide, constraint_view_guide, CONSTRAINT, VIEW_GUIDE, ConstraintViewChild)
ConstraintViewGuide * constraint_view_guide_new (void);
#define CONSTRAINT_VIEW_CONSTRAINT_TYPE (constraint_view_constraint_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintViewConstraint, constraint_view_constraint, CONSTRAINT, VIEW_CONSTRAINT, ConstraintViewChild)
ConstraintViewGuide * constraint_view_constraint_new (void);
+343
View File
@@ -0,0 +1,343 @@
/* Copyright (C) 2019 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gtk/gtk.h>
#include "constraint-view.h"
struct _ConstraintView
{
GtkWidget parent;
GListModel *model;
GtkWidget *drag_widget;
};
G_DEFINE_TYPE (ConstraintView, constraint_view, GTK_TYPE_WIDGET);
static void
constraint_view_dispose (GObject *object)
{
ConstraintView *view = CONSTRAINT_VIEW (object);
GtkWidget *child;
while ((child = gtk_widget_get_first_child (GTK_WIDGET (view))) != NULL)
gtk_widget_unparent (child);
g_clear_object (&view->model);
G_OBJECT_CLASS (constraint_view_parent_class)->dispose (object);
}
static void
constraint_view_class_init (ConstraintViewClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = constraint_view_dispose;
gtk_widget_class_set_css_name (widget_class, "constraintview");
}
static void
update_weak_position (ConstraintView *self,
GtkWidget *child,
double x,
double y)
{
GtkLayoutManager *manager;
GtkConstraint *constraint;
manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
constraint = (GtkConstraint *)g_object_get_data (G_OBJECT (child), "x-constraint");
if (constraint)
{
gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (child), "x-constraint", NULL);
}
if (x != -100)
{
constraint = gtk_constraint_new_constant (child,
GTK_CONSTRAINT_ATTRIBUTE_CENTER_X,
GTK_CONSTRAINT_RELATION_EQ,
x,
GTK_CONSTRAINT_STRENGTH_WEAK);
g_object_set_data (G_OBJECT (constraint), "internal", "yes");
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (child), "x-constraint", constraint);
}
constraint = (GtkConstraint *)g_object_get_data (G_OBJECT (child), "y-constraint");
if (constraint)
{
gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (child), "y-constraint", NULL);
}
if (y != -100)
{
constraint = gtk_constraint_new_constant (child,
GTK_CONSTRAINT_ATTRIBUTE_CENTER_Y,
GTK_CONSTRAINT_RELATION_EQ,
y,
GTK_CONSTRAINT_STRENGTH_WEAK);
g_object_set_data (G_OBJECT (constraint), "internal", "yes");
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (child), "y-constraint", constraint);
}
}
static void
drag_begin (GtkGestureDrag *drag,
double start_x,
double start_y,
ConstraintView *self)
{
GtkWidget *widget;
widget = gtk_widget_pick (GTK_WIDGET (self), start_x, start_y, GTK_PICK_DEFAULT);
if (GTK_IS_LABEL (widget))
{
widget = gtk_widget_get_ancestor (widget, GTK_TYPE_FRAME);
if (widget &&
gtk_widget_get_parent (widget) == (GtkWidget *)self)
{
self->drag_widget = widget;
}
}
}
static void
drag_update (GtkGestureDrag *drag,
double offset_x,
double offset_y,
ConstraintView *self)
{
double x, y;
if (!self->drag_widget)
return;
gtk_gesture_drag_get_start_point (drag, &x, &y);
update_weak_position (self, self->drag_widget, x + offset_x, y + offset_y);
}
static void
drag_end (GtkGestureDrag *drag,
double offset_x,
double offset_y,
ConstraintView *self)
{
self->drag_widget = NULL;
}
static gboolean
omit_internal (gpointer item, gpointer user_data)
{
if (g_object_get_data (G_OBJECT (item), "internal"))
return FALSE;
return TRUE;
}
static void
constraint_view_init (ConstraintView *self)
{
GtkLayoutManager *manager;
GtkEventController *controller;
GListStore *list;
GListModel *all_children;
GListModel *all_constraints;
GListModel *guides;
GListModel *children;
GListModel *constraints;
manager = gtk_constraint_layout_new ();
gtk_widget_set_layout_manager (GTK_WIDGET (self), manager);
all_children = gtk_widget_observe_children (GTK_WIDGET (self));
all_constraints = gtk_constraint_layout_observe_constraints (GTK_CONSTRAINT_LAYOUT (manager));
guides = gtk_constraint_layout_observe_guides (GTK_CONSTRAINT_LAYOUT (manager));
constraints = (GListModel *)gtk_filter_list_model_new (all_constraints, omit_internal, NULL, NULL);
children = (GListModel *)gtk_filter_list_model_new (all_children, omit_internal, NULL, NULL);
list = g_list_store_new (G_TYPE_LIST_MODEL);
g_list_store_append (list, children);
g_list_store_append (list, guides);
g_list_store_append (list, constraints);
self->model = G_LIST_MODEL (gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (list)));
g_object_unref (children);
g_object_unref (guides);
g_object_unref (constraints);
g_object_unref (all_children);
g_object_unref (all_constraints);
g_object_unref (list);
controller = (GtkEventController *)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_end), self);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
}
ConstraintView *
constraint_view_new (void)
{
return g_object_new (CONSTRAINT_VIEW_TYPE, NULL);
}
void
constraint_view_add_child (ConstraintView *view,
const char *name)
{
GtkWidget *frame;
GtkWidget *label;
label = gtk_label_new (name);
frame = gtk_frame_new (NULL);
gtk_style_context_add_class (gtk_widget_get_style_context (frame), "child");
gtk_widget_set_name (frame, name);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_widget_set_parent (frame, GTK_WIDGET (view));
update_weak_position (view, frame, 100, 100);
}
void
constraint_view_remove_child (ConstraintView *view,
GtkWidget *child)
{
update_weak_position (view, child, -100, -100);
gtk_widget_unparent (child);
}
void
constraint_view_add_guide (ConstraintView *view,
GtkConstraintGuide *guide)
{
GtkConstraintLayout *layout;
GtkWidget *frame;
GtkWidget *label;
const char *name;
GtkConstraint *constraint;
struct {
const char *name;
GtkConstraintAttribute attr;
} names[] = {
{ "left-constraint", GTK_CONSTRAINT_ATTRIBUTE_LEFT },
{ "top-constraint", GTK_CONSTRAINT_ATTRIBUTE_TOP },
{ "width-constraint", GTK_CONSTRAINT_ATTRIBUTE_WIDTH },
{ "height-constraint", GTK_CONSTRAINT_ATTRIBUTE_HEIGHT },
};
int i;
name = gtk_constraint_guide_get_name (guide);
label = gtk_label_new (name);
g_object_bind_property (guide, "name",
label, "label",
G_BINDING_DEFAULT);
frame = gtk_frame_new (NULL);
gtk_style_context_add_class (gtk_widget_get_style_context (frame), "guide");
g_object_set_data (G_OBJECT (frame), "internal", "yes");
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_widget_insert_after (frame, GTK_WIDGET (view), NULL);
g_object_set_data (G_OBJECT (guide), "frame", frame);
layout = GTK_CONSTRAINT_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (view)));
gtk_constraint_layout_add_guide (layout, g_object_ref (guide));
for (i = 0; i < G_N_ELEMENTS (names); i++)
{
constraint = gtk_constraint_new (frame,
names[i].attr,
GTK_CONSTRAINT_RELATION_EQ,
guide,
names[i].attr,
1.0, 0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED);
g_object_set_data (G_OBJECT (constraint), "internal", "yes");
gtk_constraint_layout_add_constraint (layout, constraint);
g_object_set_data (G_OBJECT (guide), names[i].name, constraint);
}
update_weak_position (view, frame, 150, 150);
}
void
constraint_view_remove_guide (ConstraintView *view,
GtkConstraintGuide *guide)
{
GtkConstraintLayout *layout;
GtkWidget *frame;
GtkConstraint *constraint;
const char *names[] = {
"left-constraint",
"top-constraint",
"width-constraint",
"height-constraint"
};
int i;
layout = GTK_CONSTRAINT_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (view)));
for (i = 0; i < G_N_ELEMENTS (names); i++)
{
constraint = (GtkConstraint*)g_object_get_data (G_OBJECT (guide), names[i]);
gtk_constraint_layout_remove_constraint (layout, constraint);
}
frame = (GtkWidget *)g_object_get_data (G_OBJECT (guide), "frame");
update_weak_position (view, frame, -100, -100);
gtk_widget_unparent (frame);
gtk_constraint_layout_remove_guide (layout, guide);
}
void
constraint_view_add_constraint (ConstraintView *view,
GtkConstraint *constraint)
{
GtkLayoutManager *manager;
manager = gtk_widget_get_layout_manager (GTK_WIDGET (view));
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
g_object_ref (constraint));
}
void
constraint_view_remove_constraint (ConstraintView *view,
GtkConstraint *constraint)
{
GtkLayoutManager *manager;
manager = gtk_widget_get_layout_manager (GTK_WIDGET (view));
gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
}
GListModel *
constraint_view_get_model (ConstraintView *view)
{
return view->model;
}
+44
View File
@@ -0,0 +1,44 @@
/*
* Copyright © 2019 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
*/
#pragma once
#include <gtk/gtk.h>
#define CONSTRAINT_VIEW_TYPE (constraint_view_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintView, constraint_view, CONSTRAINT, VIEW, GtkWidget)
ConstraintView * constraint_view_new (void);
void constraint_view_add_child (ConstraintView *view,
const char *name);
void constraint_view_remove_child (ConstraintView *view,
GtkWidget *child);
void constraint_view_add_guide (ConstraintView *view,
GtkConstraintGuide *guide);
void constraint_view_remove_guide (ConstraintView *view,
GtkConstraintGuide *guide);
void constraint_view_guide_changed (ConstraintView *view,
GtkConstraintGuide *guide);
void constraint_view_add_constraint (ConstraintView *view,
GtkConstraint *constraint);
void constraint_view_remove_constraint (ConstraintView *view,
GtkConstraint *constraint);
GListModel * constraint_view_get_model (ConstraintView *view);
+411
View File
@@ -0,0 +1,411 @@
/*
* Copyright © 2019 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
*/
#include "config.h"
#include "guide-editor.h"
struct _GuideEditor
{
GtkWidget parent_instance;
GtkWidget *grid;
GtkWidget *name;
GtkWidget *min_width;
GtkWidget *min_height;
GtkWidget *nat_width;
GtkWidget *nat_height;
GtkWidget *max_width;
GtkWidget *max_height;
GtkWidget *strength;
GtkWidget *button;
GtkConstraintGuide *guide;
gboolean constructed;
};
enum {
PROP_GUIDE = 1,
LAST_PROP
};
static GParamSpec *pspecs[LAST_PROP];
enum {
DONE,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
G_DEFINE_TYPE(GuideEditor, guide_editor, GTK_TYPE_WIDGET);
static void
guide_strength_combo (GtkWidget *combo)
{
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "weak", "Weak");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "medium", "Medium");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "strong", "Strong");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "required", "Required");
}
static GtkConstraintStrength
get_strength (const char *id)
{
GtkConstraintStrength strength;
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH);
GEnumValue *value = g_enum_get_value_by_nick (class, id);
strength = value->value;
g_type_class_unref (class);
return strength;
}
const char *
get_strength_nick (GtkConstraintStrength strength)
{
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH);
GEnumValue *value = g_enum_get_value (class, strength);
const char *nick = value->value_nick;
g_type_class_unref (class);
return nick;
}
void
guide_editor_serialize_guide (GString *str,
int indent,
GtkConstraintGuide *guide)
{
int min_width, min_height;
int nat_width, nat_height;
int max_width, max_height;
const char *name;
const char *strength;
gtk_constraint_guide_get_min_size (guide, &min_width, &min_height);
gtk_constraint_guide_get_nat_size (guide, &nat_width, &nat_height);
gtk_constraint_guide_get_max_size (guide, &max_width, &max_height);
name = gtk_constraint_guide_get_name (guide);
strength = get_strength_nick (gtk_constraint_guide_get_strength (guide));
g_string_append_printf (str, "%*s<guide min-width=\"%d\" min-height=\"%d\"\n", indent, "", min_width, min_height);
g_string_append_printf (str, "%*s nat-width=\"%d\" nat-height=\"%d\"\n", indent, "", nat_width, nat_height);
g_string_append_printf (str, "%*s max-width=\"%d\" max-height=\"%d\"\n", indent, "", max_width, max_height);
g_string_append_printf (str, "%*s name=\"%s\" strength=\"%s\" />\n", indent, "", name, strength);
}
static void
create_guide (GtkButton *button,
GuideEditor *editor)
{
const char *id;
int strength;
const char *name;
int w, h;
GtkConstraintGuide *guide;
if (editor->guide)
guide = g_object_ref (editor->guide);
else
guide = gtk_constraint_guide_new ();
name = gtk_editable_get_text (GTK_EDITABLE (editor->name));
gtk_constraint_guide_set_name (guide, name);
w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->min_width));
h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->min_height));
gtk_constraint_guide_set_min_size (guide, w, h);
w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->nat_width));
h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->nat_height));
gtk_constraint_guide_set_nat_size (guide, w, h);
w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->max_width));
h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->max_height));
gtk_constraint_guide_set_max_size (guide, w, h);
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->strength));
strength = get_strength (id);
gtk_constraint_guide_set_strength (guide, strength);
g_signal_emit (editor, signals[DONE], 0, guide);
g_object_unref (guide);
}
static void
guide_editor_init (GuideEditor *editor)
{
gtk_widget_init_template (GTK_WIDGET (editor));
}
static int guide_counter;
static int
min_input (GtkSpinButton *spin_button,
double *new_val)
{
if (strcmp (gtk_editable_get_text (GTK_EDITABLE (spin_button)), "") == 0)
{
*new_val = 0.0;
return TRUE;
}
return FALSE;
}
static int
max_input (GtkSpinButton *spin_button,
double *new_val)
{
if (strcmp (gtk_editable_get_text (GTK_EDITABLE (spin_button)), "") == 0)
{
*new_val = G_MAXINT;
return TRUE;
}
return FALSE;
}
static gboolean
min_output (GtkSpinButton *spin_button)
{
GtkAdjustment *adjustment;
double value;
GtkWidget *box, *text;
adjustment = gtk_spin_button_get_adjustment (spin_button);
value = gtk_adjustment_get_value (adjustment);
box = gtk_widget_get_first_child (GTK_WIDGET (spin_button));
text = gtk_widget_get_first_child (box);
if (value == 0.0)
{
gtk_editable_set_text (GTK_EDITABLE (spin_button), "");
gtk_text_set_placeholder_text (GTK_TEXT (text), "unset");
return TRUE;
}
else
{
gtk_text_set_placeholder_text (GTK_TEXT (text), "");
return FALSE;
}
}
static gboolean
max_output (GtkSpinButton *spin_button)
{
GtkAdjustment *adjustment;
double value;
GtkWidget *box, *text;
adjustment = gtk_spin_button_get_adjustment (spin_button);
value = gtk_adjustment_get_value (adjustment);
box = gtk_widget_get_first_child (GTK_WIDGET (spin_button));
text = gtk_widget_get_first_child (box);
if (value == (double)G_MAXINT)
{
gtk_editable_set_text (GTK_EDITABLE (spin_button), "");
gtk_text_set_placeholder_text (GTK_TEXT (text), "unset");
return TRUE;
}
else
{
gtk_text_set_placeholder_text (GTK_TEXT (text), "");
return FALSE;
}
}
static void
guide_editor_constructed (GObject *object)
{
GuideEditor *editor = GUIDE_EDITOR (object);
guide_strength_combo (editor->strength);
g_signal_connect (editor->min_width, "input", G_CALLBACK (min_input), NULL);
g_signal_connect (editor->min_width, "output", G_CALLBACK (min_output), NULL);
g_signal_connect (editor->min_height, "input", G_CALLBACK (min_input), NULL);
g_signal_connect (editor->min_height, "output", G_CALLBACK (min_output), NULL);
g_signal_connect (editor->max_width, "input", G_CALLBACK (max_input), NULL);
g_signal_connect (editor->max_width, "output", G_CALLBACK (max_output), NULL);
g_signal_connect (editor->max_height, "input", G_CALLBACK (max_input), NULL);
g_signal_connect (editor->max_height, "output", G_CALLBACK (max_output), NULL);
if (editor->guide)
{
GtkConstraintStrength strength;
const char *nick;
int w, h;
nick = gtk_constraint_guide_get_name (editor->guide);
if (nick)
gtk_editable_set_text (GTK_EDITABLE (editor->name), nick);
gtk_constraint_guide_get_min_size (editor->guide, &w, &h);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_width), w);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_height), h);
gtk_constraint_guide_get_nat_size (editor->guide, &w, &h);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_width), w);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_height), h);
gtk_constraint_guide_get_max_size (editor->guide, &w, &h);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_width), w);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_height), h);
strength = gtk_constraint_guide_get_strength (editor->guide);
nick = get_strength_nick (strength);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), nick);
gtk_button_set_label (GTK_BUTTON (editor->button), "Apply");
}
else
{
char *name;
guide_counter++;
name = g_strdup_printf ("Guide %d", guide_counter);
gtk_editable_set_text (GTK_EDITABLE (editor->name), name);
g_free (name);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_width), 0.0);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_height), 0.0);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_width), 0.0);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_height), 0.0);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_width), G_MAXINT);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_height), G_MAXINT);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), "medium");
gtk_button_set_label (GTK_BUTTON (editor->button), "Create");
}
editor->constructed = TRUE;
}
static void
guide_editor_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GuideEditor *self = GUIDE_EDITOR (object);
switch (property_id)
{
case PROP_GUIDE:
self->guide = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
guide_editor_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GuideEditor *self = GUIDE_EDITOR (object);
switch (property_id)
{
case PROP_GUIDE:
g_value_set_object (value, self->guide);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
guide_editor_dispose (GObject *object)
{
GuideEditor *self = (GuideEditor *)object;
g_clear_pointer (&self->grid, gtk_widget_unparent);
g_clear_object (&self->guide);
G_OBJECT_CLASS (guide_editor_parent_class)->dispose (object);
}
static void
guide_editor_class_init (GuideEditorClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->constructed = guide_editor_constructed;
object_class->dispose = guide_editor_dispose;
object_class->set_property = guide_editor_set_property;
object_class->get_property = guide_editor_get_property;
pspecs[PROP_GUIDE] =
g_param_spec_object ("guide", "guide", "guide",
GTK_TYPE_CONSTRAINT_GUIDE,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, LAST_PROP, pspecs);
signals[DONE] =
g_signal_new ("done",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
NULL,
G_TYPE_NONE, 1, GTK_TYPE_CONSTRAINT_GUIDE);
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
gtk_widget_class_set_template_from_resource (widget_class,
"/org/gtk/gtk4/constraint-editor/guide-editor.ui");
gtk_widget_class_bind_template_child (widget_class, GuideEditor, grid);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, name);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, min_width);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, min_height);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, nat_width);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, nat_height);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, max_width);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, max_height);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, strength);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, button);
gtk_widget_class_bind_template_callback (widget_class, create_guide);
}
GuideEditor *
guide_editor_new (GtkConstraintGuide *guide)
{
return g_object_new (GUIDE_EDITOR_TYPE,
"guide", guide,
NULL);
}
+32
View File
@@ -0,0 +1,32 @@
/*
* Copyright © 2019 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
*/
#pragma once
#include <gtk/gtk.h>
#define GUIDE_EDITOR_TYPE (guide_editor_get_type ())
G_DECLARE_FINAL_TYPE (GuideEditor, guide_editor, GUIDE, EDITOR, GtkWidget)
GuideEditor * guide_editor_new (GtkConstraintGuide *guide);
void guide_editor_serialize_guide (GString *str,
int indent,
GtkConstraintGuide *guide);
+188
View File
@@ -0,0 +1,188 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkAdjustment" id="min_width_adj">
<property name="lower">0</property>
<property name="upper">2147483647</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<object class="GtkAdjustment" id="min_height_adj">
<property name="lower">0</property>
<property name="upper">2147483647</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<object class="GtkAdjustment" id="nat_width_adj">
<property name="lower">0</property>
<property name="upper">2147483647</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<object class="GtkAdjustment" id="nat_height_adj">
<property name="lower">0</property>
<property name="upper">2147483647</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<object class="GtkAdjustment" id="max_width_adj">
<property name="lower">0</property>
<property name="upper">2147483647</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<object class="GtkAdjustment" id="max_height_adj">
<property name="lower">0</property>
<property name="upper">2147483647</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<template class="GuideEditor" parent="GtkWidget">
<child>
<object class="GtkGrid" id="grid">
<property name="margin">20</property>
<property name="row-spacing">10</property>
<property name="column-spacing">10</property>
<child>
<object class="GtkLabel">
<property name="label">Name</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkEntry" id="name">
<property name="max-width-chars">20</property>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Min Size</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkSpinButton" id="min_width">
<property name="adjustment">min_width_adj</property>
<property name="max-width-chars">5</property>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkSpinButton" id="min_height">
<property name="adjustment">min_height_adj</property>
<property name="max-width-chars">5</property>
<layout>
<property name="left-attach">2</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Nat Size</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkSpinButton" id="nat_width">
<property name="adjustment">nat_width_adj</property>
<property name="max-width-chars">5</property>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkSpinButton" id="nat_height">
<property name="adjustment">nat_height_adj</property>
<property name="max-width-chars">5</property>
<layout>
<property name="left-attach">2</property>
<property name="top-attach">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Max Size</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkSpinButton" id="max_width">
<property name="adjustment">max_width_adj</property>
<property name="max-width-chars">5</property>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkSpinButton" id="max_height">
<property name="adjustment">max_height_adj</property>
<property name="max-width-chars">5</property>
<layout>
<property name="left-attach">2</property>
<property name="top-attach">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Strength</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">4</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="strength">
<layout>
<property name="left-attach">1</property>
<property name="top-attach">4</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkButton" id="button">
<property name="label">Create</property>
<signal name="clicked" handler="create_guide"/>
<layout>
<property name="left-attach">2</property>
<property name="top-attach">5</property>
</layout>
</object>
</child>
</object>
</child>
</template>
</interface>
+28
View File
@@ -0,0 +1,28 @@
/*
* Copyright © 2019 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 <constraint-editor-application.h>
int
main (int argc, char *argv[])
{
return g_application_run (G_APPLICATION (constraint_editor_application_new ()), argc, argv);
}
+20
View File
@@ -0,0 +1,20 @@
constraint_editor_sources = [
'main.c',
'constraint-editor-application.c',
'constraint-editor-window.c',
'constraint-view.c',
'constraint-editor.c',
'guide-editor.c',
]
constraint_editor_resources = gnome.compile_resources('constraint_editor_resources',
'constraint-editor.gresource.xml',
source_dir: '.')
executable('gtk4-constraint-editor',
constraint_editor_sources, constraint_editor_resources,
dependencies: libgtk_dep,
include_directories: confinc,
gui_app: true,
link_args: extra_demo_ldflags,
install: false)
+289
View File
@@ -0,0 +1,289 @@
/* Constraints/Simple
*
* GtkConstraintLayout provides a layout manager that uses relations
* between widgets (also known as "constraints") to compute the position
* and size of each child.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE (SimpleGrid, simple_grid, SIMPLE, GRID, GtkWidget)
struct _SimpleGrid
{
GtkWidget parent_instance;
GtkWidget *button1, *button2;
GtkWidget *button3;
};
G_DEFINE_TYPE (SimpleGrid, simple_grid, GTK_TYPE_WIDGET)
static void
simple_grid_destroy (GtkWidget *widget)
{
SimpleGrid *self = SIMPLE_GRID (widget);
g_clear_pointer (&self->button1, gtk_widget_destroy);
g_clear_pointer (&self->button2, gtk_widget_destroy);
g_clear_pointer (&self->button3, gtk_widget_destroy);
GTK_WIDGET_CLASS (simple_grid_parent_class)->destroy (widget);
}
static void
simple_grid_class_init (SimpleGridClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
widget_class->destroy = simple_grid_destroy;
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_CONSTRAINT_LAYOUT);
}
/* Layout:
*
* +-------------------------------------+
* | +-----------++-------++-----------+ |
* | | Child 1 || Space || Child 2 | |
* | +-----------++-------++-----------+ |
* | +---------------------------------+ |
* | | Child 3 | |
* | +---------------------------------+ |
* +-------------------------------------+
*
* Constraints:
*
* super.start = child1.start - 8
* child1.width = child2.width
* child1.end = space.start
* space.end = child2.start
* child2.end = super.end - 8
* super.start = child3.start - 8
* child3.end = super.end - 8
* super.top = child1.top - 8
* super.top = child2.top - 8
* child1.bottom = child3.top - 12
* child2.bottom = child3.top - 12
* child3.height = child1.height
* child3.height = child2.height
* child3.bottom = super.bottom - 8
*
* To add some flexibility, we make the space
* stretchable:
*
* space.width >= 10
* space.width = 100
* space.width <= 200
*/
static void
build_constraints (SimpleGrid *self,
GtkConstraintLayout *manager)
{
GtkConstraintGuide *guide;
guide = gtk_constraint_guide_new ();
gtk_constraint_guide_set_name (guide, "space");
gtk_constraint_guide_set_min_size (guide, 10, 10);
gtk_constraint_guide_set_nat_size (guide, 100, 10);
gtk_constraint_guide_set_max_size (guide, 200, 20);
gtk_constraint_guide_set_strength (guide, GTK_CONSTRAINT_STRENGTH_STRONG);
gtk_constraint_layout_add_guide (manager, guide);
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new_constant (GTK_CONSTRAINT_TARGET (self->button1),
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
GTK_CONSTRAINT_RELATION_LE,
200.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (NULL,
GTK_CONSTRAINT_ATTRIBUTE_START,
GTK_CONSTRAINT_RELATION_EQ,
self->button1,
GTK_CONSTRAINT_ATTRIBUTE_START,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (self->button1,
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
GTK_CONSTRAINT_RELATION_EQ,
self->button2,
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (self->button1,
GTK_CONSTRAINT_ATTRIBUTE_END,
GTK_CONSTRAINT_RELATION_EQ,
guide,
GTK_CONSTRAINT_ATTRIBUTE_START,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (guide,
GTK_CONSTRAINT_ATTRIBUTE_END,
GTK_CONSTRAINT_RELATION_EQ,
self->button2,
GTK_CONSTRAINT_ATTRIBUTE_START,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (self->button2,
GTK_CONSTRAINT_ATTRIBUTE_END,
GTK_CONSTRAINT_RELATION_EQ,
NULL,
GTK_CONSTRAINT_ATTRIBUTE_END,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (NULL,
GTK_CONSTRAINT_ATTRIBUTE_START,
GTK_CONSTRAINT_RELATION_EQ,
self->button3,
GTK_CONSTRAINT_ATTRIBUTE_START,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (self->button3,
GTK_CONSTRAINT_ATTRIBUTE_END,
GTK_CONSTRAINT_RELATION_EQ,
NULL,
GTK_CONSTRAINT_ATTRIBUTE_END,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (NULL,
GTK_CONSTRAINT_ATTRIBUTE_TOP,
GTK_CONSTRAINT_RELATION_EQ,
self->button1,
GTK_CONSTRAINT_ATTRIBUTE_TOP,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (NULL,
GTK_CONSTRAINT_ATTRIBUTE_TOP,
GTK_CONSTRAINT_RELATION_EQ,
self->button2,
GTK_CONSTRAINT_ATTRIBUTE_TOP,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (self->button1,
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
GTK_CONSTRAINT_RELATION_EQ,
self->button3,
GTK_CONSTRAINT_ATTRIBUTE_TOP,
1.0,
-12.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (self->button2,
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
GTK_CONSTRAINT_RELATION_EQ,
self->button3,
GTK_CONSTRAINT_ATTRIBUTE_TOP,
1.0,
-12.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (self->button3,
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT,
GTK_CONSTRAINT_RELATION_EQ,
self->button1,
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (self->button3,
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT,
GTK_CONSTRAINT_RELATION_EQ,
self->button2,
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (self->button3,
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
GTK_CONSTRAINT_RELATION_EQ,
NULL,
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
}
static void
simple_grid_init (SimpleGrid *self)
{
GtkWidget *widget = GTK_WIDGET (self);
self->button1 = gtk_button_new_with_label ("Child 1");
gtk_widget_set_parent (self->button1, widget);
gtk_widget_set_name (self->button1, "button1");
self->button2 = gtk_button_new_with_label ("Child 2");
gtk_widget_set_parent (self->button2, widget);
gtk_widget_set_name (self->button2, "button2");
self->button3 = gtk_button_new_with_label ("Child 3");
gtk_widget_set_parent (self->button3, widget);
gtk_widget_set_name (self->button3, "button3");
GtkLayoutManager *manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
build_constraints (self, GTK_CONSTRAINT_LAYOUT (manager));
}
GtkWidget *
do_constraints (GtkWidget *do_widget)
{
static GtkWidget *window;
if (!window)
{
GtkWidget *header, *box, *grid, *button;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
header = gtk_header_bar_new ();
gtk_header_bar_set_title (GTK_HEADER_BAR (header), "Constraints");
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), FALSE);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_add (GTK_CONTAINER (window), box);
grid = g_object_new (simple_grid_get_type (), NULL);
gtk_widget_set_hexpand (grid, TRUE);
gtk_widget_set_vexpand (grid, TRUE);
gtk_container_add (GTK_CONTAINER (box), grid);
button = gtk_button_new_with_label ("Close");
gtk_container_add (GTK_CONTAINER (box), button);
gtk_widget_set_hexpand (grid, TRUE);
g_signal_connect_swapped (button, "clicked",
G_CALLBACK (gtk_widget_destroy), window);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}
+245
View File
@@ -0,0 +1,245 @@
/* Constraints/Interactive
*
* Demonstrate how constraints can be updates during
* user interaction.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE (InteractiveGrid, interactive_grid, INTERACTIVE, GRID, GtkWidget)
struct _InteractiveGrid
{
GtkWidget parent_instance;
GtkWidget *button1, *button2;
GtkWidget *button3;
GtkConstraintGuide *guide;
GtkConstraint *constraint;
};
G_DEFINE_TYPE (InteractiveGrid, interactive_grid, GTK_TYPE_WIDGET)
static void
interactive_grid_destroy (GtkWidget *widget)
{
InteractiveGrid *self = INTERACTIVE_GRID (widget);
g_clear_pointer (&self->button1, gtk_widget_destroy);
g_clear_pointer (&self->button2, gtk_widget_destroy);
g_clear_pointer (&self->button3, gtk_widget_destroy);
GTK_WIDGET_CLASS (interactive_grid_parent_class)->destroy (widget);
}
static void
interactive_grid_class_init (InteractiveGridClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
widget_class->destroy = interactive_grid_destroy;
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_CONSTRAINT_LAYOUT);
}
static void
build_constraints (InteractiveGrid *self,
GtkConstraintLayout *manager)
{
self->guide = g_object_new (GTK_TYPE_CONSTRAINT_GUIDE, NULL);
gtk_constraint_layout_add_guide (manager, self->guide);
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new_constant (GTK_CONSTRAINT_TARGET (self->guide),
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
GTK_CONSTRAINT_RELATION_EQ,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (NULL,
GTK_CONSTRAINT_ATTRIBUTE_START,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->button1),
GTK_CONSTRAINT_ATTRIBUTE_START,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button1),
GTK_CONSTRAINT_ATTRIBUTE_END,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->guide),
GTK_CONSTRAINT_ATTRIBUTE_START,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button2),
GTK_CONSTRAINT_ATTRIBUTE_START,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->guide),
GTK_CONSTRAINT_ATTRIBUTE_END,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button2),
GTK_CONSTRAINT_ATTRIBUTE_END,
GTK_CONSTRAINT_RELATION_EQ,
NULL,
GTK_CONSTRAINT_ATTRIBUTE_END,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (NULL,
GTK_CONSTRAINT_ATTRIBUTE_START,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->button3),
GTK_CONSTRAINT_ATTRIBUTE_START,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button3),
GTK_CONSTRAINT_ATTRIBUTE_END,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->guide),
GTK_CONSTRAINT_ATTRIBUTE_START,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (NULL,
GTK_CONSTRAINT_ATTRIBUTE_TOP,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->button1),
GTK_CONSTRAINT_ATTRIBUTE_TOP,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button2),
GTK_CONSTRAINT_ATTRIBUTE_TOP,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->button1),
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button3),
GTK_CONSTRAINT_ATTRIBUTE_TOP,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->button2),
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button3),
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
GTK_CONSTRAINT_RELATION_EQ,
NULL,
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
}
static void
drag_cb (GtkGestureDrag *drag,
double offset_x,
double offset_y,
InteractiveGrid *self)
{
GtkConstraintLayout *layout = GTK_CONSTRAINT_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (self)));
double x, y;
if (self->constraint)
{
gtk_constraint_layout_remove_constraint (layout, self->constraint);
g_clear_object (&self->constraint);
}
gtk_gesture_drag_get_start_point (drag, &x, &y);
self->constraint = gtk_constraint_new_constant (GTK_CONSTRAINT_TARGET (self->guide),
GTK_CONSTRAINT_ATTRIBUTE_LEFT,
GTK_CONSTRAINT_RELATION_EQ,
x + offset_x,
GTK_CONSTRAINT_STRENGTH_REQUIRED);
gtk_constraint_layout_add_constraint (layout, g_object_ref (self->constraint));
gtk_widget_queue_allocate (GTK_WIDGET (self));
}
static void
interactive_grid_init (InteractiveGrid *self)
{
GtkWidget *widget = GTK_WIDGET (self);
GtkGesture *drag;
self->button1 = gtk_button_new_with_label ("Child 1");
gtk_widget_set_parent (self->button1, widget);
gtk_widget_set_name (self->button1, "button1");
self->button2 = gtk_button_new_with_label ("Child 2");
gtk_widget_set_parent (self->button2, widget);
gtk_widget_set_name (self->button2, "button2");
self->button3 = gtk_button_new_with_label ("Child 3");
gtk_widget_set_parent (self->button3, widget);
gtk_widget_set_name (self->button3, "button3");
GtkLayoutManager *manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
build_constraints (self, GTK_CONSTRAINT_LAYOUT (manager));
drag = gtk_gesture_drag_new ();
g_signal_connect (drag, "drag-update", G_CALLBACK (drag_cb), self);
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (drag));
}
GtkWidget *
do_constraints2 (GtkWidget *do_widget)
{
static GtkWidget *window;
if (!window)
{
GtkWidget *header, *box, *grid, *button;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
header = gtk_header_bar_new ();
gtk_header_bar_set_title (GTK_HEADER_BAR (header), "Constraints");
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), FALSE);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_add (GTK_CONTAINER (window), box);
grid = g_object_new (interactive_grid_get_type (), NULL);
gtk_widget_set_hexpand (grid, TRUE);
gtk_widget_set_vexpand (grid, TRUE);
gtk_container_add (GTK_CONTAINER (box), grid);
button = gtk_button_new_with_label ("Close");
gtk_container_add (GTK_CONTAINER (box), button);
gtk_widget_set_hexpand (grid, TRUE);
g_signal_connect_swapped (button, "clicked",
G_CALLBACK (gtk_widget_destroy), window);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}
+165
View File
@@ -0,0 +1,165 @@
/* Constraints/VFL
*
* GtkConstraintLayout allows defining constraints using a
* compact syntax called Visual Format Language, or VFL.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE (VflGrid, vfl_grid, VFL, GRID, GtkWidget)
struct _VflGrid
{
GtkWidget parent_instance;
GtkWidget *button1, *button2;
GtkWidget *button3;
};
G_DEFINE_TYPE (VflGrid, vfl_grid, GTK_TYPE_WIDGET)
static void
vfl_grid_destroy (GtkWidget *widget)
{
VflGrid *self = VFL_GRID (widget);
g_clear_pointer (&self->button1, gtk_widget_destroy);
g_clear_pointer (&self->button2, gtk_widget_destroy);
g_clear_pointer (&self->button3, gtk_widget_destroy);
GTK_WIDGET_CLASS (vfl_grid_parent_class)->destroy (widget);
}
static void
vfl_grid_class_init (VflGridClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
widget_class->destroy = vfl_grid_destroy;
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_CONSTRAINT_LAYOUT);
}
/* Layout:
*
* +-----------------------------+
* | +-----------+ +-----------+ |
* | | Child 1 | | Child 2 | |
* | +-----------+ +-----------+ |
* | +-------------------------+ |
* | | Child 3 | |
* | +-------------------------+ |
* +-----------------------------+
*
* Constraints:
*
* super.start = child1.start - 8
* child1.width = child2.width
* child1.end = child2.start - 12
* child2.end = super.end - 8
* super.start = child3.start - 8
* child3.end = super.end - 8
* super.top = child1.top - 8
* super.top = child2.top - 8
* child1.bottom = child3.top - 12
* child2.bottom = child3.top - 12
* child3.height = child1.height
* child3.height = child2.height
* child3.bottom = super.bottom - 8
*
* Visual format:
*
* H:|-8-[view1(==view2)-12-[view2]-8-|
* H:|-8-[view3]-8-|
* V:|-8-[view1]-12-[view3(==view1)]-8-|
* V:|-8-[view2]-12-[view3(==view2)]-8-|
*/
static void
build_constraints (VflGrid *self,
GtkConstraintLayout *manager)
{
const char * const vfl[] = {
"H:|-[button1(==button2)]-12-[button2]-|",
"H:|-[button3]-|",
"V:|-[button1]-12-[button3(==button1)]-|",
"V:|-[button2]-12-[button3(==button2)]-|",
};
GError *error = NULL;
gtk_constraint_layout_add_constraints_from_description (manager, vfl, G_N_ELEMENTS (vfl),
8, 8,
&error,
"button1", self->button1,
"button2", self->button2,
"button3", self->button3,
NULL);
if (error != NULL)
{
g_printerr ("VFL parsing error:\n%s", error->message);
g_error_free (error);
}
}
static void
vfl_grid_init (VflGrid *self)
{
GtkWidget *widget = GTK_WIDGET (self);
self->button1 = gtk_button_new_with_label ("Child 1");
gtk_widget_set_parent (self->button1, widget);
gtk_widget_set_name (self->button1, "button1");
self->button2 = gtk_button_new_with_label ("Child 2");
gtk_widget_set_parent (self->button2, widget);
gtk_widget_set_name (self->button2, "button2");
self->button3 = gtk_button_new_with_label ("Child 3");
gtk_widget_set_parent (self->button3, widget);
gtk_widget_set_name (self->button3, "button3");
GtkLayoutManager *manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
build_constraints (self, GTK_CONSTRAINT_LAYOUT (manager));
}
GtkWidget *
do_constraints3 (GtkWidget *do_widget)
{
static GtkWidget *window;
if (!window)
{
GtkWidget *header, *box, *grid, *button;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
header = gtk_header_bar_new ();
gtk_header_bar_set_title (GTK_HEADER_BAR (header), "Constraints");
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), FALSE);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_add (GTK_CONTAINER (window), box);
grid = g_object_new (vfl_grid_get_type (), NULL);
gtk_widget_set_hexpand (grid, TRUE);
gtk_widget_set_vexpand (grid, TRUE);
gtk_container_add (GTK_CONTAINER (box), grid);
button = gtk_button_new_with_label ("Close");
gtk_container_add (GTK_CONTAINER (box), button);
gtk_widget_set_hexpand (grid, TRUE);
g_signal_connect_swapped (button, "clicked",
G_CALLBACK (gtk_widget_destroy), window);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}
+3
View File
@@ -150,6 +150,9 @@
<file>clipboard.c</file>
<file>colorsel.c</file>
<file>combobox.c</file>
<file>constraints.c</file>
<file>constraints2.c</file>
<file>constraints3.c</file>
<file>css_accordion.c</file>
<file>css_basics.c</file>
<file>css_blendmodes.c</file>
+1
View File
@@ -306,6 +306,7 @@ do_fishbowl (GtkWidget *do_widget)
G_CALLBACK (gtk_widget_destroyed), &window);
gtk_widget_realize (window);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))
+3
View File
@@ -8,6 +8,9 @@ demos = files([
'clipboard.c',
'colorsel.c',
'combobox.c',
'constraints.c',
'constraints2.c',
'constraints3.c',
'css_accordion.c',
'css_basics.c',
'css_blendmodes.c',
+1
View File
@@ -1,3 +1,4 @@
subdir('constraint-editor')
subdir('gtk-demo')
subdir('icon-browser')
subdir('node-editor')
+8
View File
@@ -707,6 +707,14 @@ static void
node_editor_window_unrealize (GtkWidget *widget)
{
NodeEditorWindow *self = NODE_EDITOR_WINDOW (widget);
guint i;
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (self->renderers)); i ++)
{
gpointer item = g_list_model_get_item (G_LIST_MODEL (self->renderers), i);
gsk_renderer_unrealize (gtk_renderer_paintable_get_renderer (item));
g_object_unref (item);
}
g_list_store_remove_all (self->renderers);
+3 -1
View File
@@ -1405,8 +1405,10 @@ text_view_add_to_context_menu (GtkTextView *text_view)
item = g_menu_item_new (_("Underline"), "format.underline");
g_menu_item_set_attribute (item, "touch-icon", "s", "format-text-underline-symbolic");
g_menu_append_item (G_MENU (menu), item);
g_object_unref (item);
gtk_text_view_set_extra_menu (text_view, G_MENU_MODEL (menu));
g_object_unref (menu);
g_signal_connect (gtk_text_view_get_buffer (text_view), "changed", G_CALLBACK (text_changed), NULL);
g_signal_connect (gtk_text_view_get_buffer (text_view), "mark-set", G_CALLBACK (text_changed), NULL);
@@ -1707,7 +1709,7 @@ activate (GApplication *app)
gtk_css_provider_load_from_resource (provider, "/org/gtk/WidgetFactory4/widget-factory.css");
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_USER);
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
g_object_unref (provider);
builder = gtk_builder_new_from_resource ("/org/gtk/WidgetFactory4/widget-factory.ui");
+1 -1
View File
@@ -99,7 +99,7 @@ if wayland_enabled
src_dir += [ gdkwayland_inc ]
endif
if get_option('documentation')
if get_option('gtk_doc')
configure_file(input: 'version.xml.in', output: 'version.xml', configuration: version_conf)
gnome.gtkdoc('gdk4',
+1 -1
View File
@@ -34,7 +34,7 @@ private_headers = [
images = [
]
if get_option('documentation')
if get_option('gtk_doc')
configure_file(input: 'version.xml.in', output: 'version.xml', configuration: version_conf)
gnome.gtkdoc('gsk4',
+4 -4
View File
@@ -355,8 +355,8 @@ How to compile GTK itself
</group>
<sbr/>
<group>
<arg choice="plain">-Ddocumentation=true</arg>
<arg choice="plain">-Ddocumentation=false</arg>
<arg choice="plain">-Dgtk_doc=true</arg>
<arg choice="plain">-Dgtk_doc=false</arg>
</group>
<sbr/>
<group>
@@ -382,7 +382,7 @@ How to compile GTK itself
</formalpara>
<formalpara>
<title><systemitem>documentation</systemitem> and
<title><systemitem>gtk_doc</systemitem> and
<systemitem>man-pages</systemitem></title>
<para>
@@ -394,7 +394,7 @@ How to compile GTK itself
<application>gtk-doc</application> installed and
are modifying GTK, you may want to enable
<application>gtk-doc</application> support by passing
in <systemitem>documentation</systemitem>.
in <systemitem>gtk_doc</systemitem>.
</para>
<para>
Additionally, some tools provided by GTK have their own
+3
View File
@@ -109,6 +109,9 @@
<xi:include href="xml/gtkcustomlayout.xml" />
<xi:include href="xml/gtkfixedlayout.xml" />
<xi:include href="xml/gtkgridlayout.xml" />
<xi:include href="xml/gtkconstraintlayout.xml" />
<xi:include href="xml/gtkconstraint.xml" />
<xi:include href="xml/gtkconstraintguide.xml" />
</chapter>
<chapter id="DisplayWidgets">
+84 -2
View File
@@ -4432,7 +4432,6 @@ gtk_widget_realize
gtk_widget_unrealize
gtk_widget_queue_draw
gtk_widget_queue_resize
gtk_widget_queue_resize_no_redraw
gtk_widget_queue_allocate
gtk_widget_get_frame_clock
gtk_widget_get_scale_factor
@@ -4604,7 +4603,6 @@ gtk_widget_get_vexpand
gtk_widget_set_vexpand
gtk_widget_get_vexpand_set
gtk_widget_set_vexpand_set
gtk_widget_queue_compute_expand
gtk_widget_compute_expand
<SUBSECTION Templates>
@@ -7287,3 +7285,87 @@ gtk_grid_layout_get_type
GTK_TYPE_GRID_LAYOUT_CHILD
gtk_grid_layout_child_get_type
</SECTION>
<SECTION>
<FILE>gtkconstraint</FILE>
GtkConstraint
GtkConstraintTarget
gtk_constraint_new
gtk_constraint_new_constant
gtk_constraint_get_target
GtkConstraintAttribute
gtk_constraint_get_target_attribute
GtkConstraintRelation
gtk_constraint_get_relation
gtk_constraint_get_source
gtk_constraint_get_source_attribute
gtk_constraint_get_multiplier
gtk_constraint_get_constant
GtkConstraintStrength
gtk_constraint_get_strength
gtk_constraint_is_required
gtk_constraint_is_attached
gtk_constraint_is_constant
<SUBSECTION Standard>
GTK_TYPE_CONSTRAINT
gtk_constraint_get_type
GTK_TYPE_CONSTRAINT_TARGET
gtk_constraint_target_get_type
</SECTION>
<SECTION>
<FILE>gtkconstraintlayout</FILE>
GtkConstraintLayout
GtkConstraintLayoutChild
GtkConstraintVflParserError
gtk_constraint_layout_new
<SUBSECTION Constraints>
gtk_constraint_layout_add_constraint
gtk_constraint_layout_remove_constraint
gtk_constraint_layout_remove_all_constraints
<SUBSECTION Guides>
gtk_constraint_layout_add_guide
gtk_constraint_layout_remove_guide
<SUBSECTION VFL>
gtk_constraint_layout_add_constraints_from_description
gtk_constraint_layout_add_constraints_from_descriptionv
<SUBSECTION>
gtk_constraint_layout_observe_constraints
gtk_constraint_layout_observe_guides
<SUBSECTION Standard>
GTK_TYPE_CONSTRAINT_LAYOUT
gtk_constraint_layout_get_type
GTK_TYPE_CONSTRAINT_LAYOUT_CHILD
gtk_constraint_layout_child_get_type
GTK_CONSTRAINT_VFL_PARSER_ERROR
gtk_constraint_vfl_parser_error_quark
</SECTION>
<SECTION>
<FILE>gtkconstraintguide</FILE>
GtkConstraintGuide
gtk_constraint_guide_new
gtk_constraint_guide_set_name
gtk_constraint_guide_get_name
gtk_constraint_guide_set_strength
gtk_constraint_guide_get_strength
gtk_constraint_guide_set_min_size
gtk_constraint_guide_get_min_size
gtk_constraint_guide_set_nat_size
gtk_constraint_guide_get_nat_size
gtk_constraint_guide_set_max_size
gtk_constraint_guide_get_max_size
<SUBSECTION Standard>
GTK_TYPE_CONSTRAINT_GUIDE
gtk_constraint_guide_get_tyoe
</SECTION>
+4
View File
@@ -49,6 +49,10 @@ gtk_color_chooser_dialog_get_type
gtk_color_chooser_widget_get_type
gtk_combo_box_get_type
gtk_combo_box_text_get_type
gtk_constraint_get_type
gtk_constraint_guide_get_type
gtk_constraint_layout_get_type
gtk_constraint_target_get_type
gtk_container_get_type
gtk_css_provider_get_type
gtk_dialog_get_type
+8 -1
View File
@@ -23,6 +23,13 @@ private_headers = [
'gtkcolorswatchprivate.h',
'gtkcomboboxprivate.h',
'gtkcontainerprivate.h',
'gtkconstraintexpressionprivate.h',
'gtkconstraintguideprivate.h',
'gtkconstraintlayoutprivate.h',
'gtkconstraintprivate.h',
'gtkconstraintsolverprivate.h',
'gtkconstrainttypesprivate.h',
'gtkconstraintvflparserprivate.h',
'gtkcssanimatedstyleprivate.h',
'gtkcssanimationprivate.h',
'gtkcssarrayvalueprivate.h',
@@ -394,7 +401,7 @@ else
types_conf.set('DISABLE_ON_QUARTZ', '')
endif
if get_option('documentation')
if get_option('gtk_doc')
configure_file(input: 'version.xml.in', output: 'version.xml', configuration: version_conf)
configure_file(input: 'getting_started.xml.in', output: 'getting_started.xml', configuration: src_dir_conf)
+1 -1
View File
@@ -1,4 +1,4 @@
if get_option('documentation')
if get_option('gtk_doc')
glib_prefix = dependency('glib-2.0').get_pkgconfig_variable('prefix')
glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html')
+1 -1
View File
@@ -1,4 +1,4 @@
if x11_enabled and get_option('documentation')
if x11_enabled and get_option('gtk_doc')
doc_shooter_sources = [
'shadow.c',
'shooter.c',
+6 -6
View File
@@ -88,10 +88,10 @@ gdk_broadway_surface_finalize (GObject *object)
}
static gboolean
thaw_clock_cb (GdkFrameClock *clock)
thaw_updates_cb (GdkSurface *surface)
{
_gdk_frame_clock_thaw (clock);
g_object_unref (clock);
gdk_surface_thaw_updates (surface);
g_object_unref (surface);
return G_SOURCE_REMOVE;
}
@@ -109,9 +109,9 @@ _gdk_broadway_roundtrip_notify (GdkSurface *surface,
/* If there is no remote web client, rate limit update to once a second */
if (local_reply)
g_timeout_add_seconds (1, (GSourceFunc)thaw_clock_cb, g_object_ref (clock));
g_timeout_add_seconds (1, (GSourceFunc)thaw_updates_cb, g_object_ref (surface));
else
_gdk_frame_clock_thaw (clock);
gdk_surface_thaw_updates (surface);
if (timings)
{
@@ -140,7 +140,7 @@ on_frame_clock_after_paint (GdkFrameClock *clock,
GdkBroadwayDisplay *broadway_display;
impl->pending_frame_counter = gdk_frame_clock_get_frame_counter (clock);
_gdk_frame_clock_freeze (gdk_surface_get_frame_clock (surface));
gdk_surface_freeze_updates (surface);
broadway_display = GDK_BROADWAY_DISPLAY (display);
+44 -2
View File
@@ -97,10 +97,14 @@ struct _GdkFrameClockPrivate
gint n_timings;
gint current;
GdkFrameTimings *timings[FRAME_HISTORY_MAX_LENGTH];
gint n_freeze_inhibitors;
};
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GdkFrameClock, gdk_frame_clock, G_TYPE_OBJECT)
static void
_gdk_frame_clock_freeze (GdkFrameClock *clock);
static void
gdk_frame_clock_finalize (GObject *object)
{
@@ -114,12 +118,21 @@ gdk_frame_clock_finalize (GObject *object)
G_OBJECT_CLASS (gdk_frame_clock_parent_class)->finalize (object);
}
static void
gdk_frame_clock_constructed (GObject *object)
{
G_OBJECT_CLASS (gdk_frame_clock_parent_class)->constructed (object);
_gdk_frame_clock_freeze (GDK_FRAME_CLOCK (object));
}
static void
gdk_frame_clock_class_init (GdkFrameClockClass *klass)
{
GObjectClass *gobject_class = (GObjectClass*) klass;
gobject_class->finalize = gdk_frame_clock_finalize;
gobject_class->constructed = gdk_frame_clock_constructed;
/**
* GdkFrameClock::flush-events:
@@ -335,7 +348,7 @@ gdk_frame_clock_end_updating (GdkFrameClock *frame_clock)
GDK_FRAME_CLOCK_GET_CLASS (frame_clock)->end_updating (frame_clock);
}
void
static void
_gdk_frame_clock_freeze (GdkFrameClock *clock)
{
g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
@@ -344,7 +357,7 @@ _gdk_frame_clock_freeze (GdkFrameClock *clock)
}
void
static void
_gdk_frame_clock_thaw (GdkFrameClock *clock)
{
g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
@@ -352,6 +365,35 @@ _gdk_frame_clock_thaw (GdkFrameClock *clock)
GDK_FRAME_CLOCK_GET_CLASS (clock)->thaw (clock);
}
void
_gdk_frame_clock_inhibit_freeze (GdkFrameClock *clock)
{
GdkFrameClockPrivate *priv;
g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
priv = clock->priv;
priv->n_freeze_inhibitors++;
if (priv->n_freeze_inhibitors == 1)
_gdk_frame_clock_thaw (clock);
}
void
_gdk_frame_clock_uninhibit_freeze (GdkFrameClock *clock)
{
GdkFrameClockPrivate *priv;
g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
priv = clock->priv;
priv->n_freeze_inhibitors--;
if (priv->n_freeze_inhibitors == 0)
_gdk_frame_clock_freeze (clock);
}
/**
* gdk_frame_clock_get_frame_counter:
* @frame_clock: a #GdkFrameClock
+2 -2
View File
@@ -105,8 +105,8 @@ struct _GdkFrameTimings
guint slept_before : 1;
};
void _gdk_frame_clock_freeze (GdkFrameClock *clock);
void _gdk_frame_clock_thaw (GdkFrameClock *clock);
void _gdk_frame_clock_inhibit_freeze (GdkFrameClock *clock);
void _gdk_frame_clock_uninhibit_freeze (GdkFrameClock *clock);
void _gdk_frame_clock_begin_frame (GdkFrameClock *clock);
void _gdk_frame_clock_debug_print_timings (GdkFrameClock *clock,
+56 -42
View File
@@ -1341,10 +1341,14 @@ gdk_surface_schedule_update (GdkSurface *surface)
{
GdkFrameClock *frame_clock;
if (surface &&
(surface->update_freeze_count ||
gdk_surface_is_toplevel_frozen (surface)))
return;
g_return_if_fail (surface);
if (surface->update_freeze_count ||
gdk_surface_is_toplevel_frozen (surface))
{
surface->pending_schedule_update = TRUE;
return;
}
/* If there's no frame clock (a foreign surface), then the invalid
* region will just stick around unless gdk_surface_process_updates()
@@ -1400,7 +1404,6 @@ gdk_surface_paint_on_clock (GdkFrameClock *clock,
void *data)
{
GdkSurface *surface = GDK_SURFACE (data);
GList *l;
g_return_if_fail (GDK_IS_SURFACE (surface));
@@ -1421,9 +1424,6 @@ gdk_surface_paint_on_clock (GdkFrameClock *clock,
gdk_surface_remove_update_surface (surface);
}
for (l = surface->children; l; l = l->next)
gdk_surface_paint_on_clock (clock, l->data);
g_object_unref (surface);
}
@@ -1581,13 +1581,17 @@ gdk_surface_freeze_updates (GdkSurface *surface)
g_return_if_fail (GDK_IS_SURFACE (surface));
surface->update_freeze_count++;
if (surface->update_freeze_count == 1)
_gdk_frame_clock_uninhibit_freeze (surface->frame_clock);
}
/**
* gdk_surface_thaw_updates:
* @surface: a #GdkSurface
*
* Thaws a surface frozen with gdk_surface_freeze_updates().
* Thaws a surface frozen with gdk_surface_freeze_updates(). Note that this
* will not necessarily schedule updates if the surface freeze count reaches
* zero.
**/
void
gdk_surface_thaw_updates (GdkSurface *surface)
@@ -1597,7 +1601,15 @@ gdk_surface_thaw_updates (GdkSurface *surface)
g_return_if_fail (surface->update_freeze_count > 0);
if (--surface->update_freeze_count == 0)
gdk_surface_schedule_update (surface);
{
_gdk_frame_clock_inhibit_freeze (surface->frame_clock);
if (surface->pending_schedule_update)
{
surface->pending_schedule_update = FALSE;
gdk_surface_schedule_update (surface);
}
}
}
void
@@ -1606,7 +1618,7 @@ gdk_surface_freeze_toplevel_updates (GdkSurface *surface)
g_return_if_fail (GDK_IS_SURFACE (surface));
surface->update_and_descendants_freeze_count++;
_gdk_frame_clock_freeze (gdk_surface_get_frame_clock (surface));
gdk_surface_freeze_updates (surface);
}
void
@@ -1616,9 +1628,9 @@ gdk_surface_thaw_toplevel_updates (GdkSurface *surface)
g_return_if_fail (surface->update_and_descendants_freeze_count > 0);
surface->update_and_descendants_freeze_count--;
_gdk_frame_clock_thaw (gdk_surface_get_frame_clock (surface));
gdk_surface_schedule_update (surface);
gdk_surface_thaw_updates (surface);
}
/**
@@ -3703,40 +3715,42 @@ gdk_surface_set_frame_clock (GdkSurface *surface,
if (clock)
{
g_object_ref (clock);
if (surface->parent == NULL)
{
g_signal_connect (G_OBJECT (clock),
"flush-events",
G_CALLBACK (gdk_surface_flush_events),
surface);
g_signal_connect (G_OBJECT (clock),
"resume-events",
G_CALLBACK (gdk_surface_resume_events),
surface);
g_signal_connect (G_OBJECT (clock),
"paint",
G_CALLBACK (gdk_surface_paint_on_clock),
surface);
}
g_signal_connect (G_OBJECT (clock),
"flush-events",
G_CALLBACK (gdk_surface_flush_events),
surface);
g_signal_connect (G_OBJECT (clock),
"resume-events",
G_CALLBACK (gdk_surface_resume_events),
surface);
g_signal_connect (G_OBJECT (clock),
"paint",
G_CALLBACK (gdk_surface_paint_on_clock),
surface);
if (surface->update_freeze_count == 0)
_gdk_frame_clock_inhibit_freeze (clock);
}
if (surface->frame_clock)
{
if (surface->parent == NULL)
{
if (surface->frame_clock_events_paused)
gdk_surface_resume_events (surface->frame_clock, G_OBJECT (surface));
if (surface->frame_clock_events_paused)
gdk_surface_resume_events (surface->frame_clock, G_OBJECT (surface));
g_signal_handlers_disconnect_by_func (G_OBJECT (surface->frame_clock),
G_CALLBACK (gdk_surface_flush_events),
surface);
g_signal_handlers_disconnect_by_func (G_OBJECT (surface->frame_clock),
G_CALLBACK (gdk_surface_resume_events),
surface);
g_signal_handlers_disconnect_by_func (G_OBJECT (surface->frame_clock),
G_CALLBACK (gdk_surface_paint_on_clock),
surface);
if (surface->update_freeze_count == 0)
_gdk_frame_clock_uninhibit_freeze (surface->frame_clock);
g_signal_handlers_disconnect_by_func (G_OBJECT (surface->frame_clock),
G_CALLBACK (gdk_surface_flush_events),
surface);
g_signal_handlers_disconnect_by_func (G_OBJECT (surface->frame_clock),
G_CALLBACK (gdk_surface_resume_events),
surface);
g_signal_handlers_disconnect_by_func (G_OBJECT (surface->frame_clock),
G_CALLBACK (gdk_surface_paint_on_clock),
surface);
}
g_object_unref (surface->frame_clock);
}
+1
View File
@@ -49,6 +49,7 @@ struct _GdkSurface
cairo_region_t *update_area;
guint update_freeze_count;
gboolean pending_schedule_update;
/* This is the update_area that was in effect when the current expose
started. It may be smaller than the expose area if we'e painting
more than we have to, but it represents the "true" damage. */
+5 -8
View File
@@ -349,7 +349,7 @@ frame_callback (void *data,
return;
impl->awaiting_frame = FALSE;
_gdk_frame_clock_thaw (clock);
gdk_surface_thaw_updates (surface);
timings = gdk_frame_clock_get_timings (clock, impl->pending_frame_counter);
impl->pending_frame_counter = 0;
@@ -465,8 +465,9 @@ on_frame_clock_after_paint (GdkFrameClock *clock,
g_signal_emit (impl, signals[COMMITTED], 0);
}
if (impl->awaiting_frame)
_gdk_frame_clock_freeze (clock);
if (impl->awaiting_frame &&
impl->pending_frame_counter == gdk_frame_clock_get_frame_counter (clock))
gdk_surface_freeze_updates (surface);
}
void
@@ -2577,12 +2578,8 @@ gdk_wayland_surface_hide_surface (GdkSurface *surface)
if (impl->awaiting_frame)
{
GdkFrameClock *frame_clock;
impl->awaiting_frame = FALSE;
frame_clock = gdk_surface_get_frame_clock (surface);
if (frame_clock)
_gdk_frame_clock_thaw (frame_clock);
gdk_surface_thaw_updates (surface);
}
if (impl->display_server.gtk_surface)
+2 -2
View File
@@ -874,7 +874,7 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
surface_impl->toplevel->frame_pending)
{
surface_impl->toplevel->frame_pending = FALSE;
_gdk_frame_clock_thaw (gdk_surface_get_frame_clock (event->any.surface));
gdk_surface_thaw_updates (event->any.surface);
}
if (toplevel)
@@ -1238,7 +1238,7 @@ _gdk_wm_protocols_filter (const XEvent *xevent,
if (surface_impl->toplevel->frame_pending)
{
surface_impl->toplevel->frame_pending = FALSE;
_gdk_frame_clock_thaw (clock);
gdk_surface_thaw_updates (event->any.surface);
}
gdk_frame_clock_get_refresh_info (clock,
+2 -1
View File
@@ -503,6 +503,7 @@ gdk_x11_selection_output_stream_invoke_close (gpointer stream)
g_signal_handlers_disconnect_by_func (priv->display,
gdk_x11_selection_output_stream_xevent,
stream);
g_object_unref (stream);
return G_SOURCE_REMOVE;
}
@@ -512,7 +513,7 @@ gdk_x11_selection_output_stream_close (GOutputStream *stream,
GCancellable *cancellable,
GError **error)
{
g_main_context_invoke (NULL, gdk_x11_selection_output_stream_invoke_close, stream);
g_main_context_invoke (NULL, gdk_x11_selection_output_stream_invoke_close, g_object_ref (stream));
return TRUE;
}
+1 -1
View File
@@ -397,7 +397,7 @@ gdk_x11_surface_end_frame (GdkSurface *surface)
g_intern_static_string ("_NET_WM_FRAME_DRAWN")))
{
impl->toplevel->frame_pending = TRUE;
_gdk_frame_clock_freeze (gdk_surface_get_frame_clock (surface));
gdk_surface_freeze_updates (surface);
timings->cookie = impl->toplevel->current_counter_value;
}
}
+4 -4
View File
@@ -193,10 +193,10 @@ upload_glyph (GlyphCacheKey *key,
if (render_glyph (key, value, &r))
{
glBindTexture (GL_TEXTURE_2D, value->texture_id);
glTextureSubImage2D (value->texture_id, 0,
r.x, r.y, r.width, r.height,
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
r.data);
glTexSubImage2D (GL_TEXTURE_2D, 0,
r.x, r.y, r.width, r.height,
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
r.data);
g_free (r.data);
}
+1 -1
View File
@@ -136,7 +136,7 @@ upload_region_or_else (GskGLIconCache *self,
GskImageRegion *region)
{
glBindTexture (GL_TEXTURE_2D, texture_id);
glTextureSubImage2D (texture_id, 0, region->x, region->y, region->width, region->height,
glTexSubImage2D (GL_TEXTURE_2D, 0, region->x, region->y, region->width, region->height,
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, region->data);
}
+56 -21
View File
@@ -808,7 +808,8 @@ upload_texture (GskGLRenderer *self,
int texture_id;
if (texture->width <= 128 &&
texture->height <= 128)
texture->height <= 128 &&
!GDK_IS_GL_TEXTURE (texture))
{
graphene_rect_t trect;
@@ -943,11 +944,9 @@ render_transform_node (GskGLRenderer *self,
case GSK_TRANSFORM_CATEGORY_2D:
default:
{
graphene_matrix_t mat;
if (node_supports_transform (child))
{
gsk_transform_to_matrix (node_transform, &mat);
ops_push_modelview (builder, node_transform);
gsk_gl_renderer_add_render_ops (self, child, builder);
ops_pop_modelview (builder);
@@ -972,7 +971,6 @@ render_transform_node (GskGLRenderer *self,
&region, &is_offscreen,
RESET_CLIP | RESET_OPACITY);
gsk_transform_to_matrix (node_transform, &mat);
ops_push_modelview (builder, node_transform);
ops_set_texture (builder, region.texture_id);
ops_set_program (builder, &self->blit_program);
@@ -1017,12 +1015,49 @@ render_opacity_node (GskGLRenderer *self,
GskRenderNode *node,
RenderOpBuilder *builder)
{
GskRenderNode *child = gsk_opacity_node_get_child (node);
const float opacity = gsk_opacity_node_get_opacity (node);
float prev_opacity;
prev_opacity = ops_set_opacity (builder,
builder->current_opacity * gsk_opacity_node_get_opacity (node));
if (gsk_render_node_get_node_type (child) == GSK_CONTAINER_NODE)
{
const float min_x = builder->dx + node->bounds.origin.x;
const float min_y = builder->dy + node->bounds.origin.y;
const float max_x = min_x + node->bounds.size.width;
const float max_y = min_y + node->bounds.size.height;
gboolean is_offscreen;
TextureRegion region;
gsk_gl_renderer_add_render_ops (self, gsk_opacity_node_get_child (node), builder);
/* The semantics of an opacity node mandate that when, e.g., two color nodes overlap,
* there may not be any blending between them */
add_offscreen_ops (self, builder, &child->bounds,
child,
&region, &is_offscreen,
FORCE_OFFSCREEN | RESET_OPACITY | RESET_CLIP);
prev_opacity = ops_set_opacity (builder,
builder->current_opacity * opacity);
ops_set_program (builder, &self->blit_program);
ops_set_texture (builder, region.texture_id);
ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
{ { min_x, min_y }, { region.x, region.y2 }, },
{ { min_x, max_y }, { region.x, region.y }, },
{ { max_x, min_y }, { region.x2, region.y2 }, },
{ { max_x, max_y }, { region.x2, region.y }, },
{ { min_x, max_y }, { region.x, region.y }, },
{ { max_x, min_y }, { region.x2, region.y2 }, },
});
}
else
{
prev_opacity = ops_set_opacity (builder,
builder->current_opacity * opacity);
gsk_gl_renderer_add_render_ops (self, child, builder);
}
ops_set_opacity (builder, prev_opacity);
}
@@ -1292,7 +1327,7 @@ render_rounded_clip_node (GskGLRenderer *self,
{ { min_x, min_y }, { 0, 1 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
{ { max_x, max_y }, { 1, 0 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
@@ -1393,7 +1428,7 @@ render_blur_node (GskGLRenderer *self,
ops_set_program (builder, &self->blur_program);
op.op = OP_CHANGE_BLUR;
graphene_size_init_from_size (&op.blur.size, &node->bounds.size);
op.blur.radius = gsk_blur_node_get_radius (node);
op.blur.radius = blur_radius;
ops_add (builder, &op);
ops_set_texture (builder, region.texture_id);
@@ -1404,7 +1439,7 @@ render_blur_node (GskGLRenderer *self,
{ { min_x, min_y }, { 0, 1 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
{ { max_x, max_y }, { 1, 0 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
@@ -1855,10 +1890,10 @@ render_shadow_node (GskGLRenderer *self,
RenderOpBuilder *builder,
const GskQuadVertex *vertex_data)
{
float min_x = node->bounds.origin.x;
float min_y = node->bounds.origin.y;
float max_x = min_x + node->bounds.size.width;
float max_y = min_y + node->bounds.size.height;
float min_x;
float min_y;
float max_x;
float max_y;
GskRenderNode *original_child = gsk_shadow_node_get_child (node);
GskRenderNode *shadow_child = original_child;
gsize n_shadows = gsk_shadow_node_get_n_shadows (node);
@@ -1884,6 +1919,11 @@ render_shadow_node (GskGLRenderer *self,
shadow_child = gsk_color_matrix_node_get_child (shadow_child);
}
min_x = builder->dx + shadow_child->bounds.origin.x;
min_y = builder->dy + shadow_child->bounds.origin.y;
max_x = min_x + shadow_child->bounds.size.width;
max_y = min_y + shadow_child->bounds.size.height;
for (i = 0; i < n_shadows; i ++)
{
const GskShadow *shadow = gsk_shadow_node_peek_shadow (node, i);
@@ -1905,11 +1945,6 @@ render_shadow_node (GskGLRenderer *self,
if (gdk_rgba_is_clear (&shadow->color))
continue;
min_x = builder->dx + shadow_child->bounds.origin.x;
min_y = builder->dy + shadow_child->bounds.origin.y;
max_x = min_x + shadow_child->bounds.size.width;
max_y = min_y + shadow_child->bounds.size.height;
/* Draw the child offscreen, without the offset. */
add_offscreen_ops (self, builder,
&shadow_child->bounds,
@@ -2344,6 +2379,7 @@ gsk_gl_renderer_dispose (GObject *gobject)
GskGLRenderer *self = GSK_GL_RENDERER (gobject);
g_clear_pointer (&self->render_ops, g_array_unref);
ops_free (&self->op_builder);
G_OBJECT_CLASS (gsk_gl_renderer_parent_class)->dispose (gobject);
}
@@ -3160,7 +3196,7 @@ gsk_gl_renderer_do_render (GskRenderer *renderer,
int scale_factor)
{
GskGLRenderer *self = GSK_GL_RENDERER (renderer);
graphene_matrix_t modelview, projection;
graphene_matrix_t projection;
gsize buffer_size;
#ifdef G_ENABLE_DEBUG
GskProfiler *profiler;
@@ -3180,7 +3216,6 @@ gsk_gl_renderer_do_render (GskRenderer *renderer,
g_assert (gsk_gl_driver_in_frame (self->gl_driver));
/* Set up the modelview and projection matrices to fit our viewport */
graphene_matrix_init_scale (&modelview, scale_factor, scale_factor, 1.0);
graphene_matrix_init_ortho (&projection,
viewport->origin.x,
viewport->origin.x + viewport->size.width,
+15
View File
@@ -187,6 +187,17 @@ ops_init (RenderOpBuilder *builder)
}
}
void
ops_free (RenderOpBuilder *builder)
{
int i;
for (i = 0; i < GL_N_PROGRAMS; i ++)
{
gsk_transform_unref (builder->program_state[i].modelview);
}
}
void
ops_set_program (RenderOpBuilder *builder,
const Program *program)
@@ -225,6 +236,7 @@ ops_set_program (RenderOpBuilder *builder,
op.op = OP_CHANGE_MODELVIEW;
gsk_transform_to_matrix (builder->current_modelview, &op.modelview);
g_array_append_val (builder->render_ops, op);
gsk_transform_unref (program_state->modelview);
program_state->modelview = gsk_transform_ref (builder->current_modelview);
}
@@ -339,9 +351,12 @@ ops_set_modelview_internal (RenderOpBuilder *builder,
RenderOp op;
graphene_matrix_t matrix;
#if 0
XXX This is not possible if we want pop() to work.
if (builder->current_program &&
gsk_transform_equal (builder->current_program_state->modelview, transform))
return;
#endif
gsk_transform_to_matrix (transform, &matrix);
+1
View File
@@ -290,6 +290,7 @@ void ops_dump_framebuffer (RenderOpBuilder *builder,
int width,
int height);
void ops_init (RenderOpBuilder *builder);
void ops_free (RenderOpBuilder *builder);
void ops_push_debug_group (RenderOpBuilder *builder,
const char *text);
void ops_pop_debug_group (RenderOpBuilder *builder);
+2 -2
View File
@@ -1966,14 +1966,14 @@ gsk_transform_node_diff (GskRenderNode *node1,
cairo_region_t *tmp = cairo_region_copy (sub);
cairo_region_translate (tmp, 1, 0);
cairo_region_union (sub, tmp);
cairo_region_destroy (sub);
cairo_region_destroy (tmp);
}
if (floor (dy) != dy)
{
cairo_region_t *tmp = cairo_region_copy (sub);
cairo_region_translate (tmp, 0, 1);
cairo_region_union (sub, tmp);
cairo_region_destroy (sub);
cairo_region_destroy (tmp);
}
cairo_region_union (region, sub);
cairo_region_destroy (sub);
+4 -1
View File
@@ -94,6 +94,7 @@ parse_texture (GtkCssParser *parser,
if (bytes)
{
stream = g_memory_input_stream_new_from_bytes (bytes);
g_bytes_unref (bytes);
pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, &error);
g_object_unref (stream);
if (pixbuf != NULL)
@@ -748,6 +749,8 @@ parse_glyphs (GtkCssParser *parser,
pango_glyph_string_set_size (glyph_string, glyph_string->num_glyphs + 1);
glyph_string->glyphs[glyph_string->num_glyphs - 1] = gi;
}
g_free (s);
}
else
{
@@ -817,7 +820,7 @@ parse_container_node (GtkCssParser *parser)
token = gtk_css_parser_get_token (parser))
{
node = NULL;
/* We don't wand a semicolon here, but the parse_node function will figure
/* We don't want a semicolon here, but the parse_node function will figure
* that out itself and return an error if we encounter one.
*/
gtk_css_parser_start_semicolon_block (parser, GTK_CSS_TOKEN_OPEN_CURLY);
+49 -9
View File
@@ -646,7 +646,7 @@ gsk_transform_translate_3d (GskTransform *next,
GskTranslateTransform *result;
if (graphene_point3d_equal (point, graphene_point3d_zero ()))
return gsk_transform_ref (next);
return next;
if (gsk_transform_has_class (next, &GSK_TRANSLATE_TRANSFORM_CLASS))
{
@@ -801,7 +801,7 @@ gsk_transform_rotate (GskTransform *next,
GskRotateTransform *result;
if (angle == 0.0f)
return gsk_transform_ref (next);
return next;
if (gsk_transform_has_class (next, &GSK_ROTATE_TRANSFORM_CLASS))
{
@@ -932,7 +932,7 @@ gsk_transform_rotate_3d (GskTransform *next,
return gsk_transform_rotate (next, angle);
if (angle == 0.0f)
return gsk_transform_ref (next);
return next;
result = gsk_transform_alloc (&GSK_ROTATE3D_TRANSFORM_CLASS,
GSK_TRANSFORM_CATEGORY_3D,
@@ -1121,7 +1121,7 @@ gsk_transform_scale_3d (GskTransform *next,
GskScaleTransform *result;
if (factor_x == 1 && factor_y == 1 && factor_z == 1)
return gsk_transform_ref (next);
return next;
if (gsk_transform_has_class (next, &GSK_SCALE_TRANSFORM_CLASS))
{
@@ -1250,7 +1250,7 @@ gsk_transform_perspective (GskTransform *next,
float depth)
{
GskPerspectiveTransform *result;
if (gsk_transform_has_class (next, &GSK_PERSPECTIVE_TRANSFORM_CLASS))
{
GskTransform *r = gsk_transform_perspective (gsk_transform_ref (next->next),
@@ -1690,11 +1690,26 @@ gsk_transform_transform_bounds (GskTransform *self,
}
break;
case GSK_TRANSFORM_CATEGORY_2D_AFFINE:
{
float dx, dy, scale_x, scale_y;
gsk_transform_to_affine (self, &scale_x, &scale_y, &dx, &dy);
*out_rect = *rect;
out_rect->origin.x *= scale_x;
out_rect->origin.y *= scale_y;
out_rect->size.width *= scale_x;
out_rect->size.height *= scale_y;
out_rect->origin.x += dx;
out_rect->origin.y += dy;
}
break;
case GSK_TRANSFORM_CATEGORY_UNKNOWN:
case GSK_TRANSFORM_CATEGORY_ANY:
case GSK_TRANSFORM_CATEGORY_3D:
case GSK_TRANSFORM_CATEGORY_2D:
case GSK_TRANSFORM_CATEGORY_2D_AFFINE:
default:
{
graphene_matrix_t mat;
@@ -1886,18 +1901,43 @@ gsk_transform_parser_parse (GtkCssParser *parser,
transform = gsk_transform_translate_3d (transform, &GRAPHENE_POINT3D_INIT (0.f, 0.f, f[0]));
}
#if 0
/* FIXME: add these */
else if (gtk_css_token_is_function (token, "skew"))
{
graphene_matrix_t matrix;
if (!gtk_css_parser_consume_function (parser, 2, 2, gsk_transform_parse_float, f))
goto fail;
f[0] = f[0] / 180.0 * G_PI;
f[1] = f[1] / 180.0 * G_PI;
graphene_matrix_init_skew (&matrix, f[0], f[1]);
transform = gsk_transform_matrix (transform, &matrix);
}
else if (gtk_css_token_is_function (token, "skewX"))
{
graphene_matrix_t matrix;
if (!gtk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
goto fail;
f[0] = f[0] / 180.0 * G_PI;
graphene_matrix_init_skew (&matrix, f[0], 0);
transform = gsk_transform_matrix (transform, &matrix);
}
else if (gtk_css_token_is_function (token, "skewY"))
{
graphene_matrix_t matrix;
if (!gtk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
goto fail;
f[0] = f[0] / 180.0 * G_PI;
graphene_matrix_init_skew (&matrix, 0, f[0]);
transform = gsk_transform_matrix (transform, &matrix);
}
#endif
else
{
break;
+16 -16
View File
@@ -4,14 +4,14 @@ uniform sampler2D u_source2;
float
combine (float source, float backdrop)
{
return source + backdrop * (1 - source);
return source + backdrop * (1.0 - source);
}
vec4
composite (vec4 Cs, vec4 Cb, vec3 B)
{
float ao = Cs.a + Cb.a * (1 - Cs.a);
vec3 Co = (Cs.a*(1 - Cb.a)*Cs.rgb + Cs.a*Cb.a*B + (1 - Cs.a)*Cb.a*Cb.rgb) / ao;
float ao = Cs.a + Cb.a * (1.0 - Cs.a);
vec3 Co = (Cs.a*(1.0 - Cb.a)*Cs.rgb + Cs.a*Cb.a*B + (1.0 - Cs.a)*Cb.a*Cb.rgb) / ao;
return vec4(Co, ao);
}
@@ -43,9 +43,9 @@ float
hard_light (float source, float backdrop)
{
if (source <= 0.5)
return 2 * backdrop * source;
return 2.0 * backdrop * source;
else
return 2 * (backdrop + source - backdrop * source) - 1;
return 2.0 * (backdrop + source - backdrop * source) - 1.0;
}
vec4
@@ -63,14 +63,14 @@ soft_light (float source, float backdrop)
float db;
if (backdrop <= 0.25)
db = ((16 * backdrop - 12) * backdrop + 4) * backdrop;
db = ((16.0 * backdrop - 12.0) * backdrop + 4.0) * backdrop;
else
db = sqrt (backdrop);
if (source <= 0.5)
return backdrop - (1 - 2 * source) * backdrop * (1 - backdrop);
return backdrop - (1.0 - 2.0 * source) * backdrop * (1.0 - backdrop);
else
return backdrop + (2 * source - 1) * (db - backdrop);
return backdrop + (2.0 * source - 1.0) * (db - backdrop);
}
vec4
@@ -155,8 +155,8 @@ clip_color (vec3 c)
float l = lum (c);
float n = min (c.r, min (c.g, c.b));
float x = max (c.r, max (c.g, c.b));
if (n < 0) c = l + (((c - l) * l) / (l - n));
if (x > 1) c = l + (((c - l) * (1 - l)) / (x - l));
if (n < 0.0) c = l + (((c - l) * l) / (l - n));
if (x > 1.0) c = l + (((c - l) * (1.0 - l)) / (x - l));
return c;
}
@@ -189,12 +189,12 @@ set_sat (vec3 c, float s)
if (c.g == cmin)
{
res.b = ((c.b - cmin) * s) / (cmax - cmin);
res.g = 0;
res.g = 0.0;
}
else
{
res.g = ((c.g - cmin) * s) / (cmax - cmin);
res.b = 0;
res.b = 0.0;
}
res.r = s;
}
@@ -203,12 +203,12 @@ set_sat (vec3 c, float s)
if (c.r == cmin)
{
res.b = ((c.b - cmin) * s) / (cmax - cmin);
res.r = 0;
res.r = 0.0;
}
else
{
res.r = ((c.r - cmin) * s) / (cmax - cmin);
res.b = 0;
res.b = 0.0;
}
res.g = s;
}
@@ -217,12 +217,12 @@ set_sat (vec3 c, float s)
if (c.r == cmin)
{
res.g = ((c.g - cmin) * s) / (cmax - cmin);
res.r = 0;
res.r = 0.0;
}
else
{
res.r = ((c.r - cmin) * s) / (cmax - cmin);
res.g = 0;
res.g = 0.0;
}
res.b = s;
}
+213
View File
@@ -0,0 +1,213 @@
# Actual GTK things
{
GtkWidgetClass action GPtrArray
Memcheck:Leak
fun:malloc
fun:g_malloc
fun:g_slice_alloc
fun:g_ptr_array_sized_new
fun:g_ptr_array_new
fun:gtk_widget_class_add_action
}
{
GTK media extension gio modules
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
fun:g_malloc
fun:g_slice_alloc
fun:g_slice_alloc0
fun:g_type_create_instance
fun:g_object_new_internal
fun:g_object_new_with_properties
fun:g_object_new
fun:g_io_module_new
fun:g_io_modules_scan_all_in_directory_with_scope
fun:gtk_media_file_extension_init
}
# mesa driver stuff
{
i965 addr4
Memcheck:Addr4
obj:/usr/lib/dri/i965_dri.so*
}
{
i965 addr8
Memcheck:Addr8
obj:/usr/lib/dri/i965_dri.so*
}
{
i965 memcpy
Memcheck:Addr8
fun:memcpy*
obj:/usr/lib/dri/i965_dri.so*
}
{
i965 memcpy
Memcheck:Addr2
fun:memcpy*
obj:/usr/lib/dri/i965_dri.so*
}
{
mesa memcmp 8
Memcheck:Addr8
fun:*memcmp*
obj:/usr/lib/dri/i965_dri.so*
}
{
mesa memcmp 1
Memcheck:Addr1
fun:*memcmp*
obj:/usr/lib/dri/i965_dri.so*
}
{
mesa memset 8
Memcheck:Addr8
fun:*memset*
obj:/usr/lib/dri/i965_dri.so
}
{
mesa realpath
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
fun:realpath@@GLIBC_2.3
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
fun:epoxy_eglInitialize_global_rewrite_ptr
}
{
mesa calloc
Memcheck:Leak
match-leak-kinds: definite
fun:calloc
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
fun:epoxy_eglInitialize_global_rewrite_ptr
}
{
mesa malloc
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
obj:/usr/lib/dri/i965_dri.so*
}
{
mesa glReadPixels
Memcheck:Addr16
obj:*
obj:*
obj:*
obj:*
obj:*
fun:epoxy_glReadPixels_global_rewrite_ptr
}
{
epoxy glxQueryServerString 1
Memcheck:Leak
fun:malloc
fun:XextAddDisplay
obj:*
obj:*
obj:*
obj:*
obj:*
fun:epoxy_glXQueryServerString_global_rewrite_ptr
}
{
epoxy glxQueryServerString 2
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
fun:realpath*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
fun:epoxy_glXQueryServerString_global_rewrite_ptr
}
# Fontconfig
{
FcFontSetList
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
obj:/usr/lib/libfontconfig.so*
obj:/usr/lib/libfontconfig.so*
fun:FcFontSetList
}
{
FcFontRenderPrepare
Memcheck:Leak
match-leak-kinds: definite
fun:realloc
obj:/usr/lib/libfontconfig.so*
obj:/usr/lib/libfontconfig.so*
fun:FcFontRenderPrepare
}
{
FcDefaultSubstitute
Memcheck:Leak
match-leak-kinds: definite
fun:realloc
obj:/usr/lib/libfontconfig.so*
obj:/usr/lib/libfontconfig.so*
fun:FcDefaultSubstitute
}
# Pixman
{
pixman_image_composite32
Memcheck:Cond
obj:/usr/lib/libpixman-1.so*
obj:/usr/lib/libpixman-1.so*
fun:pixman_image_composite32
}
# Pango
{
pango 1
Memcheck:Leak
match-leak-kinds: definite
fun:realloc
obj:/usr/lib/libfontconfig.so*
obj:/usr/lib/libfontconfig.so*
obj:/usr/lib/libcairo.so*
fun:pango_cairo_fc_font_map_fontset_key_substitute
}
+150 -40
View File
@@ -23,41 +23,26 @@
#include "gsk/gskrendernodeprivate.h"
#include "gskpango.h"
#include "gtksnapshotprivate.h"
#include "gtkstylecontextprivate.h"
#include "gtktextlayoutprivate.h"
#include "gtktextviewprivate.h"
#include <math.h>
#include <pango/pango.h>
#include <cairo.h>
#define GSK_PANGO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_PANGO_RENDERER, GskPangoRendererClass))
#define GSK_IS_PANGO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_PANGO_RENDERER))
#define GSK_PANGO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_PANGO_RENDERER, GskPangoRendererClass))
/*
* This is a PangoRenderer implementation that translates all the draw calls to
* gsk render nodes, using the GtkSnapshot helper class. Glyphs are translated
* to text nodes, all other draw calls fall back to cairo nodes.
*/
struct _GskPangoRenderer
{
PangoRenderer parent_instance;
GtkSnapshot *snapshot;
GdkRGBA fg_color;
graphene_rect_t bounds;
/* house-keeping options */
gboolean is_cached_renderer;
};
struct _GskPangoRendererClass
{
PangoRendererClass parent_class;
};
G_DEFINE_TYPE (GskPangoRenderer, gsk_pango_renderer, PANGO_TYPE_RENDERER)
void
gsk_pango_renderer_set_state (GskPangoRenderer *crenderer,
GskPangoRendererState state)
{
g_return_if_fail (GSK_IS_PANGO_RENDERER (crenderer));
crenderer->state = state;
}
static void
get_color (GskPangoRenderer *crenderer,
PangoRenderPart part,
@@ -158,15 +143,14 @@ gsk_pango_renderer_draw_rectangle (PangoRenderer *renderer,
{
GskPangoRenderer *crenderer = (GskPangoRenderer *) (renderer);
GdkRGBA rgba;
graphene_rect_t bounds;
get_color (crenderer, part, &rgba);
graphene_rect_init (&bounds,
(double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
(double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
gtk_snapshot_append_color (crenderer->snapshot, &rgba, &bounds);
gtk_snapshot_append_color (crenderer->snapshot,
&rgba,
&GRAPHENE_RECT_INIT ((double)x / PANGO_SCALE,
(double)y / PANGO_SCALE,
(double)width / PANGO_SCALE,
(double)height / PANGO_SCALE));
}
static void
@@ -336,6 +320,124 @@ gsk_pango_renderer_draw_shape (PangoRenderer *renderer,
cairo_destroy (cr);
}
static void
text_renderer_set_rgba (GskPangoRenderer *crenderer,
PangoRenderPart part,
const GdkRGBA *rgba)
{
PangoRenderer *renderer = PANGO_RENDERER (crenderer);
PangoColor color = { 0, };
guint16 alpha;
if (rgba)
{
color.red = (guint16)(rgba->red * 65535);
color.green = (guint16)(rgba->green * 65535);
color.blue = (guint16)(rgba->blue * 65535);
alpha = (guint16)(rgba->alpha * 65535);
pango_renderer_set_color (renderer, part, &color);
pango_renderer_set_alpha (renderer, part, alpha);
}
else
{
pango_renderer_set_color (renderer, part, NULL);
pango_renderer_set_alpha (renderer, part, 0);
}
}
static GtkTextAppearance *
get_item_appearance (PangoItem *item)
{
GSList *tmp_list = item->analysis.extra_attrs;
while (tmp_list)
{
PangoAttribute *attr = tmp_list->data;
if (attr->klass->type == gtk_text_attr_appearance_type)
return &((GtkTextAttrAppearance *)attr)->appearance;
tmp_list = tmp_list->next;
}
return NULL;
}
static void
gsk_pango_renderer_prepare_run (PangoRenderer *renderer,
PangoLayoutRun *run)
{
GtkStyleContext *context;
GskPangoRenderer *crenderer = GSK_PANGO_RENDERER (renderer);
GdkRGBA *bg_rgba = NULL;
GdkRGBA *fg_rgba = NULL;
GtkTextAppearance *appearance;
PANGO_RENDERER_CLASS (gsk_pango_renderer_parent_class)->prepare_run (renderer, run);
appearance = get_item_appearance (run->item);
if (appearance == NULL)
return;
context = gtk_widget_get_style_context (crenderer->widget);
if (appearance->draw_bg && crenderer->state == GSK_PANGO_RENDERER_NORMAL)
bg_rgba = appearance->bg_rgba;
else
bg_rgba = NULL;
text_renderer_set_rgba (crenderer, PANGO_RENDER_PART_BACKGROUND, bg_rgba);
if (crenderer->state == GSK_PANGO_RENDERER_SELECTED &&
GTK_IS_TEXT_VIEW (crenderer->widget))
{
GtkCssNode *selection_node;
selection_node = gtk_text_view_get_selection_node ((GtkTextView *)crenderer->widget);
gtk_style_context_save_to_node (context, selection_node);
gtk_style_context_get (context,
"color", &fg_rgba,
NULL);
gtk_style_context_restore (context);
}
else if (crenderer->state == GSK_PANGO_RENDERER_CURSOR && gtk_widget_has_focus (crenderer->widget))
{
gtk_style_context_get (context,
"background-color", &fg_rgba,
NULL);
}
else
fg_rgba = appearance->fg_rgba;
text_renderer_set_rgba (crenderer, PANGO_RENDER_PART_FOREGROUND, fg_rgba);
if (appearance->strikethrough_rgba)
text_renderer_set_rgba (crenderer, PANGO_RENDER_PART_STRIKETHROUGH, appearance->strikethrough_rgba);
else
text_renderer_set_rgba (crenderer, PANGO_RENDER_PART_STRIKETHROUGH, fg_rgba);
if (appearance->underline_rgba)
text_renderer_set_rgba (crenderer, PANGO_RENDER_PART_UNDERLINE, appearance->underline_rgba);
else if (appearance->underline == PANGO_UNDERLINE_ERROR)
{
if (!crenderer->error_color)
{
static const GdkRGBA red = { 1, 0, 0, 1 };
crenderer->error_color = gdk_rgba_copy (&red);
}
text_renderer_set_rgba (crenderer, PANGO_RENDER_PART_UNDERLINE, crenderer->error_color);
}
else
text_renderer_set_rgba (crenderer, PANGO_RENDER_PART_UNDERLINE, fg_rgba);
if (fg_rgba != appearance->fg_rgba)
gdk_rgba_free (fg_rgba);
}
static void
gsk_pango_renderer_init (GskPangoRenderer *renderer G_GNUC_UNUSED)
{
@@ -352,13 +454,14 @@ gsk_pango_renderer_class_init (GskPangoRendererClass *klass)
renderer_class->draw_trapezoid = gsk_pango_renderer_draw_trapezoid;
renderer_class->draw_error_underline = gsk_pango_renderer_draw_error_underline;
renderer_class->draw_shape = gsk_pango_renderer_draw_shape;
renderer_class->prepare_run = gsk_pango_renderer_prepare_run;
}
static GskPangoRenderer *cached_renderer = NULL; /* MT-safe */
G_LOCK_DEFINE_STATIC (cached_renderer);
static GskPangoRenderer *
acquire_renderer (void)
GskPangoRenderer *
gsk_pango_renderer_acquire (void)
{
GskPangoRenderer *renderer;
@@ -380,13 +483,20 @@ acquire_renderer (void)
return renderer;
}
static void
release_renderer (GskPangoRenderer *renderer)
void
gsk_pango_renderer_release (GskPangoRenderer *renderer)
{
if (G_LIKELY (renderer->is_cached_renderer))
{
renderer->widget = NULL;
renderer->snapshot = NULL;
if (renderer->error_color)
{
gdk_rgba_free (renderer->error_color);
renderer->error_color = NULL;
}
G_UNLOCK (cached_renderer);
}
else
@@ -414,7 +524,7 @@ gtk_snapshot_append_layout (GtkSnapshot *snapshot,
g_return_if_fail (snapshot != NULL);
g_return_if_fail (PANGO_IS_LAYOUT (layout));
crenderer = acquire_renderer ();
crenderer = gsk_pango_renderer_acquire ();
crenderer->snapshot = snapshot;
crenderer->fg_color = *color;
@@ -424,5 +534,5 @@ gtk_snapshot_append_layout (GtkSnapshot *snapshot,
pango_renderer_draw_layout (PANGO_RENDERER (crenderer), layout, 0, 0);
release_renderer (crenderer);
gsk_pango_renderer_release (crenderer);
}
+48 -6
View File
@@ -24,15 +24,57 @@
G_BEGIN_DECLS
#define GSK_TYPE_PANGO_RENDERER (gsk_pango_renderer_get_type ())
#define GSK_TYPE_PANGO_RENDERER (gsk_pango_renderer_get_type ())
#define GSK_PANGO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_PANGO_RENDERER, GskPangoRenderer))
#define GSK_IS_PANGO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_PANGO_RENDERER))
#define GSK_PANGO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_PANGO_RENDERER, GskPangoRendererClass))
#define GSK_IS_PANGO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_PANGO_RENDERER))
#define GSK_PANGO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_PANGO_RENDERER, GskPangoRendererClass))
#define GSK_PANGO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_PANGO_RENDERER, GskPangoRenderer))
#define GSK_IS_PANGO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_PANGO_RENDERER))
typedef struct _GskPangoRenderer GskPangoRenderer;
typedef struct _GskPangoRendererClass GskPangoRendererClass;
typedef struct _GskPangoRenderer GskPangoRenderer;
typedef struct _GskPangoRendererClass GskPangoRendererClass;
typedef enum
{
GSK_PANGO_RENDERER_NORMAL,
GSK_PANGO_RENDERER_SELECTED,
GSK_PANGO_RENDERER_CURSOR
} GskPangoRendererState;
GType gsk_pango_renderer_get_type (void) G_GNUC_CONST;
/*
* This is a PangoRenderer implementation that translates all the draw calls to
* gsk render nodes, using the GtkSnapshot helper class. Glyphs are translated
* to text nodes, all other draw calls fall back to cairo nodes.
*/
struct _GskPangoRenderer
{
PangoRenderer parent_instance;
GtkWidget *widget;
GtkSnapshot *snapshot;
GdkRGBA fg_color;
graphene_rect_t bounds;
/* Error underline color for this widget */
GdkRGBA *error_color;
GskPangoRendererState state;
/* house-keeping options */
guint is_cached_renderer : 1;
};
struct _GskPangoRendererClass
{
PangoRendererClass parent_class;
};
GType gsk_pango_renderer_get_type (void) G_GNUC_CONST;
void gsk_pango_renderer_set_state (GskPangoRenderer *crenderer,
GskPangoRendererState state);
GskPangoRenderer *gsk_pango_renderer_acquire (void);
void gsk_pango_renderer_release (GskPangoRenderer *crenderer);
G_END_DECLS
+2
View File
@@ -82,6 +82,8 @@
#include <gtk/gtkcolorutils.h>
#include <gtk/gtkcombobox.h>
#include <gtk/gtkcomboboxtext.h>
#include <gtk/gtkconstraintlayout.h>
#include <gtk/gtkconstraint.h>
#include <gtk/gtkcontainer.h>
#include <gtk/gtkcssprovider.h>
#include <gtk/gtkcustomlayout.h>
+21 -5
View File
@@ -155,6 +155,16 @@ accel_entry_equal (gconstpointer key1,
return g_str_equal (entry1->accel_path, entry2->accel_path);
}
static int
accel_entry_compare (gconstpointer a,
gconstpointer b)
{
const AccelEntry *entry1 = a;
const AccelEntry *entry2 = b;
return strcmp (entry1->accel_path, entry2->accel_path);
}
static inline AccelEntry*
accel_path_lookup (const gchar *accel_path)
{
@@ -817,17 +827,23 @@ gtk_accel_map_foreach (gpointer data,
g_return_if_fail (foreach_func != NULL);
entries = g_hash_table_slist_values (accel_entry_ht);
entries = g_slist_sort (entries, accel_entry_compare);
for (slist = entries; slist; slist = slist->next)
{
AccelEntry *entry = slist->data;
gboolean changed = entry->accel_key != entry->std_accel_key || entry->accel_mods != entry->std_accel_mods;
gboolean skip = FALSE;
for (node = accel_filters; node; node = node->next)
if (g_pattern_match_string (node->data, entry->accel_path))
goto skip_accel;
foreach_func (data, entry->accel_path, entry->accel_key, entry->accel_mods, changed);
skip_accel:
/* noop */;
if (g_pattern_match_string (node->data, entry->accel_path))
{
skip = TRUE;
break;
}
if (!skip)
foreach_func (data, entry->accel_path, entry->accel_key, entry->accel_mods, changed);
}
g_slist_free (entries);
}
+2 -9
View File
@@ -561,13 +561,6 @@ prop_actions_connect (GtkActionMuxer *muxer)
}
}
static void
prop_actions_disconnect (GtkActionMuxer *muxer)
{
if (muxer->widget)
g_signal_handlers_disconnect_by_func (muxer->widget,
prop_action_notify, muxer);
}
static gboolean
gtk_action_muxer_query_action (GActionGroup *action_group,
@@ -810,6 +803,8 @@ gtk_action_muxer_finalize (GObject *object)
if (muxer->primary_accels)
g_hash_table_unref (muxer->primary_accels);
g_free (muxer->widget_actions_enabled);
G_OBJECT_CLASS (gtk_action_muxer_parent_class)
->finalize (object);
}
@@ -819,8 +814,6 @@ gtk_action_muxer_dispose (GObject *object)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (object);
prop_actions_disconnect (muxer);
if (muxer->parent)
{
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_added_to_parent, muxer);
-1
View File
@@ -289,7 +289,6 @@ gtk_builder_init (GtkBuilder *builder)
{
GtkBuilderPrivate *priv = gtk_builder_get_instance_private (builder);
priv = gtk_builder_get_instance_private (builder);
priv->domain = NULL;
priv->objects = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
+2 -2
View File
@@ -3474,7 +3474,7 @@ gtk_calendar_set_detail_width_chars (GtkCalendar *calendar,
{
priv->detail_width_chars = chars;
g_object_notify (G_OBJECT (calendar), "detail-width-chars");
gtk_widget_queue_resize_no_redraw (GTK_WIDGET (calendar));
gtk_widget_queue_resize (GTK_WIDGET (calendar));
}
}
@@ -3498,7 +3498,7 @@ gtk_calendar_set_detail_height_rows (GtkCalendar *calendar,
{
priv->detail_height_rows = rows;
g_object_notify (G_OBJECT (calendar), "detail-height-rows");
gtk_widget_queue_resize_no_redraw (GTK_WIDGET (calendar));
gtk_widget_queue_resize (GTK_WIDGET (calendar));
}
}
+15 -36
View File
@@ -1604,8 +1604,9 @@ get_size (GtkCellRenderer *cell,
GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (cell);
GtkCellRendererTextPrivate *priv = gtk_cell_renderer_text_get_instance_private (celltext);
PangoRectangle rect;
gint xpad, ypad;
gint cell_width, cell_height;
int xpad, ypad;
int cell_width, cell_height;
float xalign, yalign;
gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
@@ -1652,52 +1653,30 @@ get_size (GtkCellRenderer *cell,
if (width == NULL)
return;
}
if (layout)
g_object_ref (layout);
else
layout = get_layout (celltext, widget, NULL, 0);
pango_layout_get_pixel_extents (layout, NULL, &rect);
if (cell_area)
{
gfloat xalign, yalign;
gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
rect.height = MIN (rect.height, cell_area->height - 2 * ypad);
rect.width = MIN (rect.width, cell_area->width - 2 * xpad);
rect.height = MIN (rect.height, cell_area->height - 2 * ypad);
rect.width = MIN (rect.width, cell_area->width - 2 * xpad);
if (x_offset)
{
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
*x_offset = (1.0 - xalign) * (cell_area->width - (rect.width + (2 * xpad)));
else
*x_offset = xalign * (cell_area->width - (rect.width + (2 * xpad)));
if ((priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE) || priv->wrap_width != -1)
*x_offset = MAX(*x_offset, 0);
}
if (y_offset)
{
*y_offset = yalign * (cell_area->height - (rect.height + (2 * ypad)));
*y_offset = MAX (*y_offset, 0);
}
}
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
*x_offset = (1.0 - xalign) * (cell_area->width - (rect.width + (2 * xpad)));
else
{
if (x_offset) *x_offset = 0;
if (y_offset) *y_offset = 0;
}
*x_offset = xalign * (cell_area->width - (rect.width + (2 * xpad)));
if ((priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE) || priv->wrap_width != -1)
*x_offset = MAX(*x_offset, 0);
*y_offset = yalign * (cell_area->height - (rect.height + (2 * ypad)));
*y_offset = MAX (*y_offset, 0);
if (height)
*height = ypad * 2 + rect.height;
if (width)
*width = xpad * 2 + rect.width;
g_object_unref (layout);
}
static void
-1
View File
@@ -408,7 +408,6 @@ gtk_cell_renderer_toggle_snapshot (GtkCellRenderer *cell,
GtkBorder padding, border;
GtkCssImageBuiltinType image_type;
context = gtk_widget_get_style_context (widget);
gtk_cell_renderer_toggle_get_size (cell, widget, cell_area,
&x_offset, &y_offset,
&width, &height);
-2
View File
@@ -537,8 +537,6 @@ gtk_color_chooser_widget_init (GtkColorChooserWidget *cc)
AtkObject *atk_obj;
gchar *text, *name;
priv = gtk_color_chooser_widget_get_instance_private (cc);
priv->use_alpha = TRUE;
gtk_orientable_set_orientation (GTK_ORIENTABLE (cc), GTK_ORIENTATION_VERTICAL);
+614
View File
@@ -0,0 +1,614 @@
/* gtkconstraint.c: Constraint between two widgets
* Copyright 2019 GNOME Foundation
*
* 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/>.
*
* Author: Emmanuele Bassi
*/
/**
* SECTION:gtkconstraint
* @Title: GtkConstraint
* @Short_description: The description of a constraint
*
* #GtkConstraint describes a constraint between an attribute on a widget
* and another attribute on another widget, expressed as a linear equation
* like:
*
* |[
* target.attr1 = source.attr2 × multiplier + constant
* ]|
*
* Each #GtkConstraint is part of a system that will be solved by a
* #GtkConstraintLayout in order to allocate and position each child widget.
*
* The source and target widgets, as well as their attributes, of a
* #GtkConstraint instance are immutable after creation.
*/
#include "config.h"
#include "gtkconstraintprivate.h"
#include "gtkconstraintsolverprivate.h"
#include "gtkintl.h"
#include "gtktypebuiltins.h"
#include "gtkwidget.h"
enum {
PROP_TARGET = 1,
PROP_TARGET_ATTRIBUTE,
PROP_RELATION,
PROP_SOURCE,
PROP_SOURCE_ATTRIBUTE,
PROP_MULTIPLIER,
PROP_CONSTANT,
PROP_STRENGTH,
N_PROPERTIES
};
static GParamSpec *obj_props[N_PROPERTIES];
G_DEFINE_TYPE (GtkConstraint, gtk_constraint, G_TYPE_OBJECT)
static void
gtk_constraint_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkConstraint *self = GTK_CONSTRAINT (gobject);
switch (prop_id)
{
case PROP_TARGET:
self->target = g_value_get_object (value);
break;
case PROP_TARGET_ATTRIBUTE:
self->target_attribute = g_value_get_enum (value);
break;
case PROP_RELATION:
self->relation = g_value_get_enum (value);
break;
case PROP_SOURCE:
self->source = g_value_get_object (value);
break;
case PROP_SOURCE_ATTRIBUTE:
self->source_attribute = g_value_get_enum (value);
break;
case PROP_MULTIPLIER:
self->multiplier = g_value_get_double (value);
break;
case PROP_CONSTANT:
self->constant = g_value_get_double (value);
break;
case PROP_STRENGTH:
self->strength = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
gtk_constraint_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkConstraint *self = GTK_CONSTRAINT (gobject);
switch (prop_id)
{
case PROP_TARGET:
g_value_set_object (value, self->target);
break;
case PROP_TARGET_ATTRIBUTE:
g_value_set_enum (value, self->target_attribute);
break;
case PROP_RELATION:
g_value_set_enum (value, self->relation);
break;
case PROP_SOURCE:
g_value_set_object (value, self->source);
break;
case PROP_SOURCE_ATTRIBUTE:
g_value_set_enum (value, self->source_attribute);
break;
case PROP_MULTIPLIER:
g_value_set_double (value, self->multiplier);
break;
case PROP_CONSTANT:
g_value_set_double (value, self->constant);
break;
case PROP_STRENGTH:
g_value_set_int (value, self->strength);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
gtk_constraint_finalize (GObject *gobject)
{
GtkConstraint *self = GTK_CONSTRAINT (gobject);
gtk_constraint_detach (self);
G_OBJECT_CLASS (gtk_constraint_parent_class)->finalize (gobject);
}
static void
gtk_constraint_class_init (GtkConstraintClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->set_property = gtk_constraint_set_property;
gobject_class->get_property = gtk_constraint_get_property;
gobject_class->finalize = gtk_constraint_finalize;
/**
* GtkConstraint:target:
*
* The target of the constraint.
*
* The constraint will set the #GtkConstraint:target-attribute of the
* target using the #GtkConstraint:source-attribute of the source
* widget.
*/
obj_props[PROP_TARGET] =
g_param_spec_object ("target",
P_("Target"),
P_("The target of the constraint"),
GTK_TYPE_CONSTRAINT_TARGET,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS |
G_PARAM_CONSTRUCT_ONLY);
/**
* GtkConstraint:target-attribute:
*
* The attribute of the #GtkConstraint:target set by the constraint.
*/
obj_props[PROP_TARGET_ATTRIBUTE] =
g_param_spec_enum ("target-attribute",
P_("Target Attribute"),
P_("The attribute of the target set by the constraint"),
GTK_TYPE_CONSTRAINT_ATTRIBUTE,
GTK_CONSTRAINT_ATTRIBUTE_NONE,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS |
G_PARAM_CONSTRUCT_ONLY);
/**
* GtkConstraint:relation:
*
* The order relation between the terms of the constraint.
*/
obj_props[PROP_RELATION] =
g_param_spec_enum ("relation",
P_("Relation"),
P_("The relation between the source and target attributes"),
GTK_TYPE_CONSTRAINT_RELATION,
GTK_CONSTRAINT_RELATION_EQ,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS |
G_PARAM_CONSTRUCT_ONLY);
/**
* GtkConstraint:source:
*
* The source of the constraint.
*
* The constraint will set the #GtkConstraint:target-attribute of the
* target using the #GtkConstraint:source-attribute of the source.
*/
obj_props[PROP_SOURCE] =
g_param_spec_object ("source",
P_("Source"),
P_("The source of the constraint"),
GTK_TYPE_CONSTRAINT_TARGET,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS |
G_PARAM_CONSTRUCT_ONLY);
/**
* GtkConstraint:source-attribute:
*
* The attribute of the #GtkConstraint:source read by the constraint.
*/
obj_props[PROP_SOURCE_ATTRIBUTE] =
g_param_spec_enum ("source-attribute",
P_("Source Attribute"),
P_("The attribute of the source widget set by the constraint"),
GTK_TYPE_CONSTRAINT_ATTRIBUTE,
GTK_CONSTRAINT_ATTRIBUTE_NONE,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS |
G_PARAM_CONSTRUCT_ONLY);
/**
* GtkConstraint:multiplier:
*
* The multiplication factor to be applied to the
* #GtkConstraint:source-attribute.
*/
obj_props[PROP_MULTIPLIER] =
g_param_spec_double ("multiplier",
P_("Multiplier"),
P_("The multiplication factor to be applied to the source attribute"),
-G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS |
G_PARAM_CONSTRUCT_ONLY);
/**
* GtkConstraint:constant:
*
* The constant value to be added to the #GtkConstraint:source-attribute.
*/
obj_props[PROP_CONSTANT] =
g_param_spec_double ("constant",
P_("Constant"),
P_("The constant to be added to the source attribute"),
-G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS |
G_PARAM_CONSTRUCT_ONLY);
/**
* GtkConstraint:strength:
*
* The strength of the constraint.
*
* The strength can be expressed either using one of the symbolic values
* of the #GtkConstraintStrength enumeration, or any positive integer
* value.
*/
obj_props[PROP_STRENGTH] =
g_param_spec_int ("strength",
P_("Strength"),
P_("The strength of the constraint"),
0, GTK_CONSTRAINT_STRENGTH_REQUIRED,
GTK_CONSTRAINT_STRENGTH_REQUIRED,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS |
G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (gobject_class, N_PROPERTIES, obj_props);
}
static void
gtk_constraint_init (GtkConstraint *self)
{
self->multiplier = 1.0;
self->constant = 0.0;
self->target_attribute = GTK_CONSTRAINT_ATTRIBUTE_NONE;
self->source_attribute = GTK_CONSTRAINT_ATTRIBUTE_NONE;
self->relation = GTK_CONSTRAINT_RELATION_EQ;
self->strength = GTK_CONSTRAINT_STRENGTH_REQUIRED;
}
/**
* gtk_constraint_new:
* @target: (nullable) (type GtkConstraintTarget): a #GtkConstraintTarget
* @target_attribute: the attribute of @target to be set
* @relation: the relation equivalence between @target_attribute and @source_attribute
* @source: (nullable) (type GtkConstraintTarget): a #GtkConstraintTarget
* @source_attribute: the attribute of @source to be read
* @multiplier: a multiplication factor to be applied to @source_attribute
* @constant: a constant factor to be added to @source_attribute
* @strength: the strength of the constraint
*
* Creates a new #GtkConstraint representing a relation between a layout
* attribute on a source and a layout attribute on a target.
*
* Returns: the newly created #GtkConstraint
*/
GtkConstraint *
gtk_constraint_new (gpointer target,
GtkConstraintAttribute target_attribute,
GtkConstraintRelation relation,
gpointer source,
GtkConstraintAttribute source_attribute,
double multiplier,
double constant,
int strength)
{
g_return_val_if_fail (target == NULL || GTK_IS_CONSTRAINT_TARGET (target), NULL);
g_return_val_if_fail (source == NULL || GTK_IS_CONSTRAINT_TARGET (source), NULL);
return g_object_new (GTK_TYPE_CONSTRAINT,
"target", target,
"target-attribute", target_attribute,
"relation", relation,
"source", source,
"source-attribute", source_attribute,
"multiplier", multiplier,
"constant", constant,
"strength", strength,
NULL);
}
/**
* gtk_constraint_new_constant:
* @target: (nullable) (type GtkConstraintTarget): a #GtkConstraintTarget
* @target_attribute: the attribute of @target to be set
* @relation: the relation equivalence between @target_attribute and @constant
* @constant: a constant factor to be set on @target_attribute
* @strength: the strength of the constraint
*
* Creates a new #GtkConstraint representing a relation between a layout
* attribute on a target and a constant value.
*
* Returns: the newly created #GtkConstraint
*/
GtkConstraint *
gtk_constraint_new_constant (gpointer target,
GtkConstraintAttribute target_attribute,
GtkConstraintRelation relation,
double constant,
int strength)
{
g_return_val_if_fail (target == NULL || GTK_IS_CONSTRAINT_TARGET (target), NULL);
return g_object_new (GTK_TYPE_CONSTRAINT,
"target", target,
"target-attribute", target_attribute,
"relation", relation,
"source-attribute", GTK_CONSTRAINT_ATTRIBUTE_NONE,
"constant", constant,
"strength", strength,
NULL);
}
/**
* gtk_constraint_get_target:
* @constraint: a #GtkConstraint
*
* Retrieves the #GtkConstraintTarget used as the target for @constraint.
*
* If the #GtkConstraint:target property is set to %NULL, the @constraint
* will use the #GtkConstraintLayout's widget.
*
* Returns: (transfer none) (nullable): a #GtkConstraintTarget
*/
GtkConstraintTarget *
gtk_constraint_get_target (GtkConstraint *constraint)
{
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), NULL);
return constraint->target;
}
/**
* gtk_constraint_get_target_attribute:
* @constraint: a #GtkConstraint
*
* Retrieves the attribute of the target to be set by the @constraint.
*
* Returns: the target's attribute
*/
GtkConstraintAttribute
gtk_constraint_get_target_attribute (GtkConstraint *constraint)
{
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), GTK_CONSTRAINT_ATTRIBUTE_NONE);
return constraint->target_attribute;
}
/**
* gtk_constraint_get_source:
* @constraint: a #GtkConstraint
*
* Retrieves the #GtkConstraintTarget used as the source for @constraint.
*
* If the #GtkConstraint:source property is set to %NULL, the @constraint
* will use the #GtkConstraintLayout's widget.
*
* Returns: (transfer none) (nullable): a #GtkConstraintTarget
*/
GtkConstraintTarget *
gtk_constraint_get_source (GtkConstraint *constraint)
{
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), NULL);
return constraint->source;
}
/**
* gtk_constraint_get_source_attribute:
* @constraint: a #GtkConstraint
*
* Retrieves the attribute of the source to be read by the @constraint.
*
* Returns: the target's attribute
*/
GtkConstraintAttribute
gtk_constraint_get_source_attribute (GtkConstraint *constraint)
{
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), GTK_CONSTRAINT_ATTRIBUTE_NONE);
return constraint->source_attribute;
}
/**
* gtk_constraint_get_relation:
* @constraint: a #GtkConstraint
*
* The order relation between the terms of the @constraint.
*
* Returns: a #GtkConstraintRelation value
*/
GtkConstraintRelation
gtk_constraint_get_relation (GtkConstraint *constraint)
{
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), GTK_CONSTRAINT_RELATION_EQ);
return constraint->relation;
}
/**
* gtk_constraint_get_multiplier:
* @constraint: a #GtkConstraint
*
* Retrieves the multiplication factor applied to the source
* attribute's value.
*
* Returns: a multiplication factor
*/
double
gtk_constraint_get_multiplier (GtkConstraint *constraint)
{
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), 1.0);
return constraint->multiplier;
}
/**
* gtk_constraint_get_constant:
* @constraint: a #GtkConstraint
*
* Retrieves the constant factor added to the source attributes' value.
*
* Returns: a constant factor
*/
double
gtk_constraint_get_constant (GtkConstraint *constraint)
{
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), 0.0);
return constraint->constant;
}
/**
* gtk_constraint_get_strength:
* @constraint: a #GtkConstraint
*
* Retrieves the strength of the constraint.
*
* Returns: the strength of the constraint
*/
int
gtk_constraint_get_strength (GtkConstraint *constraint)
{
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), GTK_CONSTRAINT_STRENGTH_REQUIRED);
return constraint->strength;
}
/**
* gtk_constraint_is_required:
* @constraint: a #GtkConstraint
*
* Checks whether the @constraint is a required relation for solving the
* constraint layout.
*
* Returns: %TRUE if the constraint is required
*/
gboolean
gtk_constraint_is_required (GtkConstraint *constraint)
{
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), FALSE);
return constraint->strength == GTK_CONSTRAINT_STRENGTH_REQUIRED;
}
/**
* gtk_constraint_is_attached:
* @constraint: a #GtkConstraint
*
* Checks whether the @constraint is attached to a #GtkConstraintLayout,
* and it is contributing to the layout.
*
* Returns: %TRUE if the constraint is attached
*/
gboolean
gtk_constraint_is_attached (GtkConstraint *constraint)
{
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), FALSE);
return constraint->constraint_ref != NULL;
}
/**
* gtk_constraint_is_constant:
* @constraint: a #GtkConstraint
*
* Checks whether the @constraint describes a relation between an attribute
* on the #GtkConstraint:target-widget and a constant value.
*
* Returns: %TRUE if the constraint is a constant relation
*/
gboolean
gtk_constraint_is_constant (GtkConstraint *constraint)
{
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), FALSE);
return constraint->source == NULL &&
constraint->source_attribute == GTK_CONSTRAINT_ATTRIBUTE_NONE;
}
void
gtk_constraint_attach (GtkConstraint *constraint,
GtkConstraintSolver *solver,
GtkConstraintRef *ref)
{
g_return_if_fail (GTK_IS_CONSTRAINT (constraint));
g_return_if_fail (GTK_IS_CONSTRAINT_SOLVER (solver));
g_return_if_fail (ref != NULL);
constraint->constraint_ref = ref;
constraint->solver = solver;
}
void
gtk_constraint_detach (GtkConstraint *constraint)
{
g_return_if_fail (GTK_IS_CONSTRAINT (constraint));
if (constraint->constraint_ref == NULL)
return;
gtk_constraint_solver_remove_constraint (constraint->solver, constraint->constraint_ref);
constraint->constraint_ref = NULL;
constraint->solver = NULL;
}
typedef struct _GtkConstraintTargetInterface GtkConstraintTargetInterface;
struct _GtkConstraintTargetInterface
{
GTypeInterface g_iface;
};
G_DEFINE_INTERFACE (GtkConstraintTarget, gtk_constraint_target, G_TYPE_OBJECT)
static void
gtk_constraint_target_default_init (GtkConstraintTargetInterface *iface)
{
}
+100
View File
@@ -0,0 +1,100 @@
/* gtkconstraint.h: Constraint between two widgets
* Copyright 2019 GNOME Foundation
*
* 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/>.
*
* Author: Emmanuele Bassi
*/
#pragma once
#include <gtk/gtktypes.h>
#include <gtk/gtkenums.h>
G_BEGIN_DECLS
typedef struct _GtkConstraintTarget GtkConstraintTarget;
#define GTK_TYPE_CONSTRAINT_TARGET (gtk_constraint_target_get_type ())
/**
* GtkConstraintTarget:
*
* The GtkConstraintTarget interface is implemented by objects that
* can be used as source or target in #GtkConstraints. Besides
* #GtkWidget, it is also implemented by #GtkConstraintGuide.
*/
GDK_AVAILABLE_IN_ALL
G_DECLARE_INTERFACE (GtkConstraintTarget, gtk_constraint_target, GTK, CONSTRAINT_TARGET, GObject)
#define GTK_TYPE_CONSTRAINT (gtk_constraint_get_type ())
/**
* GtkConstraint:
*
* An object describing the relation between two widget attributes.
*
* All relations are in the form:
*
* |[<!-- language=plain -->
* target.attr_name = source.attr_name × multiplier + constant
* ]|
*
* A #GtkConstraint is immutable once it's created.
*/
GDK_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (GtkConstraint, gtk_constraint, GTK, CONSTRAINT, GObject)
GDK_AVAILABLE_IN_ALL
GtkConstraint * gtk_constraint_new (gpointer target,
GtkConstraintAttribute target_attribute,
GtkConstraintRelation relation,
gpointer source,
GtkConstraintAttribute source_attribute,
double multiplier,
double constant,
int strength);
GDK_AVAILABLE_IN_ALL
GtkConstraint * gtk_constraint_new_constant (gpointer target,
GtkConstraintAttribute target_attribute,
GtkConstraintRelation relation,
double constant,
int strength);
GDK_AVAILABLE_IN_ALL
GtkConstraintTarget * gtk_constraint_get_target (GtkConstraint *constraint);
GDK_AVAILABLE_IN_ALL
GtkConstraintAttribute gtk_constraint_get_target_attribute (GtkConstraint *constraint);
GDK_AVAILABLE_IN_ALL
GtkConstraintTarget * gtk_constraint_get_source (GtkConstraint *constraint);
GDK_AVAILABLE_IN_ALL
GtkConstraintAttribute gtk_constraint_get_source_attribute (GtkConstraint *constraint);
GDK_AVAILABLE_IN_ALL
GtkConstraintRelation gtk_constraint_get_relation (GtkConstraint *constraint);
GDK_AVAILABLE_IN_ALL
double gtk_constraint_get_multiplier (GtkConstraint *constraint);
GDK_AVAILABLE_IN_ALL
double gtk_constraint_get_constant (GtkConstraint *constraint);
GDK_AVAILABLE_IN_ALL
int gtk_constraint_get_strength (GtkConstraint *constraint);
GDK_AVAILABLE_IN_ALL
gboolean gtk_constraint_is_required (GtkConstraint *constraint);
GDK_AVAILABLE_IN_ALL
gboolean gtk_constraint_is_attached (GtkConstraint *constraint);
GDK_AVAILABLE_IN_ALL
gboolean gtk_constraint_is_constant (GtkConstraint *constraint);
G_END_DECLS
File diff suppressed because it is too large Load Diff
+279
View File
@@ -0,0 +1,279 @@
/* gtkconstraintequationprivate.h: Constraint expressions and variables
* Copyright 2019 GNOME Foundation
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* 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/>.
*
* Author: Emmanuele Bassi
*/
#pragma once
#include "gtkconstrainttypesprivate.h"
G_BEGIN_DECLS
GtkConstraintVariable *
gtk_constraint_variable_new (const char *prefix,
const char *name);
GtkConstraintVariable *
gtk_constraint_variable_new_dummy (const char *name);
GtkConstraintVariable *
gtk_constraint_variable_new_objective (const char *name);
GtkConstraintVariable *
gtk_constraint_variable_new_slack (const char *name);
GtkConstraintVariable *
gtk_constraint_variable_ref (GtkConstraintVariable *variable);
void
gtk_constraint_variable_unref (GtkConstraintVariable *variable);
void
gtk_constraint_variable_set_value (GtkConstraintVariable *variable,
double value);
double
gtk_constraint_variable_get_value (const GtkConstraintVariable *variable);
char *
gtk_constraint_variable_to_string (const GtkConstraintVariable *variable);
gboolean
gtk_constraint_variable_is_external (const GtkConstraintVariable *variable);
gboolean
gtk_constraint_variable_is_pivotable (const GtkConstraintVariable *variable);
gboolean
gtk_constraint_variable_is_restricted (const GtkConstraintVariable *variable);
gboolean
gtk_constraint_variable_is_dummy (const GtkConstraintVariable *variable);
typedef struct {
GtkConstraintVariable *first;
GtkConstraintVariable *second;
} GtkConstraintVariablePair;
GtkConstraintVariablePair *
gtk_constraint_variable_pair_new (GtkConstraintVariable *first,
GtkConstraintVariable *second);
void
gtk_constraint_variable_pair_free (GtkConstraintVariablePair *pair);
typedef struct _GtkConstraintVariableSet GtkConstraintVariableSet;
GtkConstraintVariableSet *
gtk_constraint_variable_set_new (void);
void
gtk_constraint_variable_set_free (GtkConstraintVariableSet *set);
gboolean
gtk_constraint_variable_set_add (GtkConstraintVariableSet *set,
GtkConstraintVariable *variable);
gboolean
gtk_constraint_variable_set_remove (GtkConstraintVariableSet *set,
GtkConstraintVariable *variable);
gboolean
gtk_constraint_variable_set_is_empty (GtkConstraintVariableSet *set);
gboolean
gtk_constraint_variable_set_is_singleton (GtkConstraintVariableSet *set);
int
gtk_constraint_variable_set_size (GtkConstraintVariableSet *set);
typedef struct {
/*< private >*/
gpointer dummy1;
gpointer dummy2;
gint64 dummy3;
} GtkConstraintVariableSetIter;
void
gtk_constraint_variable_set_iter_init (GtkConstraintVariableSetIter *iter,
GtkConstraintVariableSet *set);
gboolean
gtk_constraint_variable_set_iter_next (GtkConstraintVariableSetIter *iter,
GtkConstraintVariable **variable_p);
GtkConstraintExpression *
gtk_constraint_expression_new (double constant);
GtkConstraintExpression *
gtk_constraint_expression_new_from_variable (GtkConstraintVariable *variable);
GtkConstraintExpression *
gtk_constraint_expression_ref (GtkConstraintExpression *expression);
void
gtk_constraint_expression_unref (GtkConstraintExpression *expression);
GtkConstraintExpression *
gtk_constraint_expression_clone (GtkConstraintExpression *expression);
void
gtk_constraint_expression_set_constant (GtkConstraintExpression *expression,
double constant);
double
gtk_constraint_expression_get_constant (const GtkConstraintExpression *expression);
gboolean
gtk_constraint_expression_is_constant (const GtkConstraintExpression *expression);
void
gtk_constraint_expression_add_expression (GtkConstraintExpression *a_expr,
GtkConstraintExpression *b_expr,
double n,
GtkConstraintVariable *subject,
GtkConstraintSolver *solver);
void
gtk_constraint_expression_add_variable (GtkConstraintExpression *expression,
GtkConstraintVariable *variable,
double coefficient,
GtkConstraintVariable *subject,
GtkConstraintSolver *solver);
void
gtk_constraint_expression_remove_variable (GtkConstraintExpression *expression,
GtkConstraintVariable *variable);
void
gtk_constraint_expression_set_variable (GtkConstraintExpression *expression,
GtkConstraintVariable *variable,
double coefficient);
double
gtk_constraint_expression_get_coefficient (GtkConstraintExpression *expression,
GtkConstraintVariable *variable);
char *
gtk_constraint_expression_to_string (const GtkConstraintExpression *expression);
double
gtk_constraint_expression_new_subject (GtkConstraintExpression *expression,
GtkConstraintVariable *subject);
void
gtk_constraint_expression_change_subject (GtkConstraintExpression *expression,
GtkConstraintVariable *old_subject,
GtkConstraintVariable *new_subject);
void
gtk_constraint_expression_substitute_out (GtkConstraintExpression *expression,
GtkConstraintVariable *out_var,
GtkConstraintExpression *expr,
GtkConstraintVariable *subject,
GtkConstraintSolver *solver);
GtkConstraintVariable *
gtk_constraint_expression_get_pivotable_variable (GtkConstraintExpression *expression);
GtkConstraintExpression *
gtk_constraint_expression_plus_constant (GtkConstraintExpression *expression,
double constant);
GtkConstraintExpression *
gtk_constraint_expression_minus_constant (GtkConstraintExpression *expression,
double constant);
GtkConstraintExpression *
gtk_constraint_expression_plus_variable (GtkConstraintExpression *expression,
GtkConstraintVariable *variable);
GtkConstraintExpression *
gtk_constraint_expression_minus_variable (GtkConstraintExpression *expression,
GtkConstraintVariable *variable);
GtkConstraintExpression *
gtk_constraint_expression_multiply_by (GtkConstraintExpression *expression,
double factor);
GtkConstraintExpression *
gtk_constraint_expression_divide_by (GtkConstraintExpression *expression,
double factor);
struct _GtkConstraintExpressionBuilder
{
/*< private >*/
gpointer dummy1;
gpointer dummy2;
int dummy3;
};
void
gtk_constraint_expression_builder_init (GtkConstraintExpressionBuilder *builder,
GtkConstraintSolver *solver);
void
gtk_constraint_expression_builder_term (GtkConstraintExpressionBuilder *builder,
GtkConstraintVariable *term);
void
gtk_constraint_expression_builder_plus (GtkConstraintExpressionBuilder *builder);
void
gtk_constraint_expression_builder_minus (GtkConstraintExpressionBuilder *builder);
void
gtk_constraint_expression_builder_divide_by (GtkConstraintExpressionBuilder *builder);
void
gtk_constraint_expression_builder_multiply_by (GtkConstraintExpressionBuilder *builder);
void
gtk_constraint_expression_builder_constant (GtkConstraintExpressionBuilder *builder,
double value);
GtkConstraintExpression *
gtk_constraint_expression_builder_finish (GtkConstraintExpressionBuilder *builder) G_GNUC_WARN_UNUSED_RESULT;
/*< private >
* GtkConstraintExpressionIter:
*
* An iterator object for terms inside a #GtkConstraintExpression.
*/
typedef struct {
/*< private >*/
gpointer dummy1;
gpointer dummy2;
gint64 dummy3;
} GtkConstraintExpressionIter;
void
gtk_constraint_expression_iter_init (GtkConstraintExpressionIter *iter,
GtkConstraintExpression *equation);
gboolean
gtk_constraint_expression_iter_next (GtkConstraintExpressionIter *iter,
GtkConstraintVariable **variable,
double *coefficient);
gboolean
gtk_constraint_expression_iter_prev (GtkConstraintExpressionIter *iter,
GtkConstraintVariable **variable,
double *coefficient);
G_END_DECLS
+694
View File
@@ -0,0 +1,694 @@
/* gtkconstraintguide.c: Flexible space for constraints
* Copyright 2019 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/>.
*
* Author: Matthias Clasen
*/
/**
* SECTION:gtkconstraintguide
* @Title: GtkConstraintGuide
* @Short_description: An invisible constraint target
*
* A #GtkConstraintGuide is an invisible layout element that can be
* used by widgets inside a #GtkConstraintLayout as a source or a target
* of a #GtkConstraint. Guides can be used like guidelines or as
* flexible space.
*
* Unlike a #GtkWidget, a #GtkConstraintGuide will not be drawn.
*/
#include "config.h"
#include "gtkconstraintguide.h"
#include "gtkconstraintguideprivate.h"
#include "gtkconstraintlayoutprivate.h"
#include "gtkconstraintexpressionprivate.h"
#include "gtkconstraintsolverprivate.h"
#include "gtkdebug.h"
#include "gtkintl.h"
#include "gtkprivate.h"
typedef enum {
MIN_WIDTH,
MIN_HEIGHT,
NAT_WIDTH,
NAT_HEIGHT,
MAX_WIDTH,
MAX_HEIGHT,
LAST_VALUE
} GuideValue;
struct _GtkConstraintGuide
{
GObject parent_instance;
char *name;
int strength;
int values[LAST_VALUE];
GtkConstraintLayout *layout;
/* HashTable<static string, Variable>; a hash table of variables,
* one for each attribute; we use these to query and suggest the
* values for the solver. The string is static and does not need
* to be freed.
*/
GHashTable *bound_attributes;
GtkConstraintRef *constraints[LAST_VALUE];
};
struct _GtkConstraintGuideClass {
GObjectClass parent_class;
};
enum {
PROP_MIN_WIDTH = 1,
PROP_MIN_HEIGHT,
PROP_NAT_WIDTH,
PROP_NAT_HEIGHT,
PROP_MAX_WIDTH,
PROP_MAX_HEIGHT,
PROP_STRENGTH,
PROP_NAME,
LAST_PROP
};
static GParamSpec *guide_props[LAST_PROP];
static void
gtk_constraint_guide_constraint_target_iface_init (GtkConstraintTargetInterface *iface)
{
}
G_DEFINE_TYPE_WITH_CODE (GtkConstraintGuide, gtk_constraint_guide, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GTK_TYPE_CONSTRAINT_TARGET,
gtk_constraint_guide_constraint_target_iface_init))
static void
gtk_constraint_guide_init (GtkConstraintGuide *guide)
{
guide->strength = GTK_CONSTRAINT_STRENGTH_MEDIUM;
guide->values[MIN_WIDTH] = 0;
guide->values[MIN_HEIGHT] = 0;
guide->values[NAT_WIDTH] = 0;
guide->values[NAT_HEIGHT] = 0;
guide->values[MAX_WIDTH] = G_MAXINT;
guide->values[MAX_HEIGHT] = G_MAXINT;
guide->bound_attributes =
g_hash_table_new_full (g_str_hash, g_str_equal,
NULL,
(GDestroyNotify) gtk_constraint_variable_unref);
}
static void
gtk_constraint_guide_update_constraint (GtkConstraintGuide *guide,
GuideValue index)
{
GtkConstraintSolver *solver;
GtkConstraintVariable *var;
if (!guide->layout)
return;
solver = gtk_constraint_layout_get_solver (guide->layout);
if (!solver)
return;
if (guide->constraints[index] != NULL)
{
gtk_constraint_solver_remove_constraint (solver, guide->constraints[index]);
guide->constraints[index] = NULL;
}
if (index == MIN_WIDTH || index == NAT_WIDTH || index == MAX_WIDTH)
var = gtk_constraint_layout_get_attribute (guide->layout, GTK_CONSTRAINT_ATTRIBUTE_WIDTH, "guide", NULL, guide->bound_attributes);
else
var = gtk_constraint_layout_get_attribute (guide->layout, GTK_CONSTRAINT_ATTRIBUTE_HEIGHT, "guide", NULL, guide->bound_attributes);
/* We always install min-size constraints,
* but we avoid nat-size constraints if min == max
* and we avoid max-size constraints if max == G_MAXINT
*/
if (index == MIN_WIDTH || index == MIN_HEIGHT)
{
guide->constraints[index] =
gtk_constraint_solver_add_constraint (solver,
var,
GTK_CONSTRAINT_RELATION_GE,
gtk_constraint_expression_new (guide->values[index]),
GTK_CONSTRAINT_STRENGTH_REQUIRED);
}
else if ((index == NAT_WIDTH && guide->values[MIN_WIDTH] != guide->values[MAX_WIDTH]) ||
(index == NAT_HEIGHT && guide->values[MIN_HEIGHT] != guide->values[MAX_HEIGHT]))
{
gtk_constraint_variable_set_value (var, guide->values[index]);
guide->constraints[index] =
gtk_constraint_solver_add_stay_variable (solver,
var,
guide->strength);
}
else if ((index == MAX_WIDTH || index == MAX_HEIGHT) &&
guide->values[index] < G_MAXINT)
{
guide->constraints[index] =
gtk_constraint_solver_add_constraint (solver,
var,
GTK_CONSTRAINT_RELATION_LE,
gtk_constraint_expression_new (guide->values[index]),
GTK_CONSTRAINT_STRENGTH_REQUIRED);
}
gtk_layout_manager_layout_changed (GTK_LAYOUT_MANAGER (guide->layout));
}
void
gtk_constraint_guide_update (GtkConstraintGuide *guide)
{
int i;
for (i = 0; i < LAST_VALUE; i++)
gtk_constraint_guide_update_constraint (guide, i);
}
void
gtk_constraint_guide_detach (GtkConstraintGuide *guide)
{
GtkConstraintSolver *solver;
int i;
if (!guide->layout)
return;
solver = gtk_constraint_layout_get_solver (guide->layout);
if (!solver)
return;
for (i = 0; i < LAST_VALUE; i++)
{
if (guide->constraints[i])
{
gtk_constraint_solver_remove_constraint (solver, guide->constraints[i]);
guide->constraints[i] = NULL;
}
}
g_hash_table_remove_all (guide->bound_attributes);
}
GtkConstraintVariable *
gtk_constraint_guide_get_attribute (GtkConstraintGuide *guide,
GtkConstraintAttribute attr)
{
GtkLayoutManager *manager = GTK_LAYOUT_MANAGER (guide->layout);
GtkWidget *widget = gtk_layout_manager_get_widget (manager);
return gtk_constraint_layout_get_attribute (guide->layout, attr, "guide", widget, guide->bound_attributes);
}
GtkConstraintLayout *
gtk_constraint_guide_get_layout (GtkConstraintGuide *guide)
{
return guide->layout;
}
void
gtk_constraint_guide_set_layout (GtkConstraintGuide *guide,
GtkConstraintLayout *layout)
{
guide->layout = layout;
}
static void
gtk_constraint_guide_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkConstraintGuide *self = GTK_CONSTRAINT_GUIDE (gobject);
int val;
GuideValue index;
switch (prop_id)
{
case PROP_MIN_WIDTH:
case PROP_MIN_HEIGHT:
case PROP_NAT_WIDTH:
case PROP_NAT_HEIGHT:
case PROP_MAX_WIDTH:
case PROP_MAX_HEIGHT:
val = g_value_get_int (value);
index = prop_id - 1;
if (self->values[index] != val)
{
self->values[index] = val;
g_object_notify_by_pspec (gobject, pspec);
gtk_constraint_guide_update_constraint (self, index);
if (index == MIN_WIDTH || index == MAX_WIDTH)
gtk_constraint_guide_update_constraint (self, NAT_WIDTH);
if (index == MIN_HEIGHT || index == MAX_HEIGHT)
gtk_constraint_guide_update_constraint (self, NAT_HEIGHT);
}
break;
case PROP_STRENGTH:
gtk_constraint_guide_set_strength (self, g_value_get_enum (value));
break;
case PROP_NAME:
gtk_constraint_guide_set_name (self, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
gtk_constraint_guide_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkConstraintGuide *self = GTK_CONSTRAINT_GUIDE (gobject);
switch (prop_id)
{
case PROP_MIN_WIDTH:
case PROP_MIN_HEIGHT:
case PROP_NAT_WIDTH:
case PROP_NAT_HEIGHT:
case PROP_MAX_WIDTH:
case PROP_MAX_HEIGHT:
g_value_set_int (value, self->values[prop_id - 1]);
break;
case PROP_STRENGTH:
g_value_set_enum (value, self->strength);
break;
case PROP_NAME:
g_value_set_string (value, self->name);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
gtk_constraint_guide_finalize (GObject *object)
{
GtkConstraintGuide *self = GTK_CONSTRAINT_GUIDE (object);
g_free (self->name);
g_clear_pointer (&self->bound_attributes, g_hash_table_unref);
G_OBJECT_CLASS (gtk_constraint_guide_parent_class)->finalize (object);
}
static void
gtk_constraint_guide_class_init (GtkConstraintGuideClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = gtk_constraint_guide_finalize;
object_class->set_property = gtk_constraint_guide_set_property;
object_class->get_property = gtk_constraint_guide_get_property;
/**
* GtkConstraintGuide:min-width:
*
* The minimum width of the guide.
*/
guide_props[PROP_MIN_WIDTH] =
g_param_spec_int ("min-width",
"Minimum width",
"Minimum width",
0, G_MAXINT, 0,
G_PARAM_READWRITE|
G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkConstraintGuide:min-height:
*
* The minimum height of the guide.
*/
guide_props[PROP_MIN_HEIGHT] =
g_param_spec_int ("min-height",
"Minimum height",
"Minimum height",
0, G_MAXINT, 0,
G_PARAM_READWRITE|
G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkConstraintGuide:nat-width:
*
* The preferred, or natural, width of the guide.
*/
guide_props[PROP_NAT_WIDTH] =
g_param_spec_int ("nat-width",
"Natural width",
"Natural width",
0, G_MAXINT, 0,
G_PARAM_READWRITE|
G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkConstraintGuide:nat-height:
*
* The preferred, or natural, height of the guide.
*/
guide_props[PROP_NAT_HEIGHT] =
g_param_spec_int ("nat-height",
"Natural height",
"Natural height",
0, G_MAXINT, 0,
G_PARAM_READWRITE|
G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkConstraintGuide:max-width:
*
* The maximum width of the guide.
*/
guide_props[PROP_MAX_WIDTH] =
g_param_spec_int ("max-width",
"Maximum width",
"Maximum width",
0, G_MAXINT, G_MAXINT,
G_PARAM_READWRITE|
G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkConstraintGuide:max-height:
*
* The maximum height of the guide.
*/
guide_props[PROP_MAX_HEIGHT] =
g_param_spec_int ("max-height",
"Maximum height",
"Maximum height",
0, G_MAXINT, G_MAXINT,
G_PARAM_READWRITE|
G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkConstraintGuide:strength:
*
* The #GtkConstraintStrength to be used for the constraint on
* the natural size of the guide.
*/
guide_props[PROP_STRENGTH] =
g_param_spec_enum ("strength",
"Strength",
"The strength to use for natural size",
GTK_TYPE_CONSTRAINT_STRENGTH,
GTK_CONSTRAINT_STRENGTH_MEDIUM,
G_PARAM_READWRITE|
G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkConstraintGuide:name:
*
* A name that identifies the #GtkConstraintGuide, for debugging.
*/
guide_props[PROP_NAME] =
g_param_spec_string ("name",
"Name",
"A name to use in debug message",
NULL,
G_PARAM_READWRITE);
g_object_class_install_properties (object_class, LAST_PROP, guide_props);
}
/**
* gtk_constraint_guide_new:
*
* Creates a new #GtkConstraintGuide object.
*
* Return: a new #GtkConstraintGuide object.
*/
GtkConstraintGuide *
gtk_constraint_guide_new (void)
{
return g_object_new (GTK_TYPE_CONSTRAINT_GUIDE, NULL);
}
/**
* gtk_constraint_guide_set_min_size:
* @guide: a #GtkConstraintGuide object
* @width: the new minimum width, or -1 to not change it
* @height: the new minimum height, or -1 to not change it
*
* Sets the minimum size of @guide.
*
* If @guide is attached to a #GtkConstraintLayout,
* the constraints will be updated to reflect the new size.
*/
void
gtk_constraint_guide_set_min_size (GtkConstraintGuide *guide,
int width,
int height)
{
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
g_return_if_fail (width >= -1);
g_return_if_fail (height >= -1);
g_object_freeze_notify (G_OBJECT (guide));
if (width != -1)
g_object_set (guide, "min-width", width, NULL);
if (height != -1)
g_object_set (guide, "min-height", height, NULL);
g_object_thaw_notify (G_OBJECT (guide));
}
/**
* gtk_constraint_guide_get_min_size:
* @guide: a #GtkContraintGuide object
* @width: (allow-none): return location for the minimum width,
* or %NULL
* @height: (allow-none): return location for the minimum height,
* or %NULL
*
* Gets the minimum size of @guide.
*/
void
gtk_constraint_guide_get_min_size (GtkConstraintGuide *guide,
int *width,
int *height)
{
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
if (width)
*width = guide->values[MIN_WIDTH];
if (height)
*height = guide->values[MIN_HEIGHT];
}
/**
* gtk_constraint_guide_set_nat_size:
* @guide: a #GtkConstraintGuide object
* @width: the new natural width, or -1 to not change it
* @height: the new natural height, or -1 to not change it
*
* Sets the natural size of @guide.
*
* If @guide is attached to a #GtkConstraintLayout,
* the constraints will be updated to reflect the new size.
*/
void
gtk_constraint_guide_set_nat_size (GtkConstraintGuide *guide,
int width,
int height)
{
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
g_return_if_fail (width >= -1);
g_return_if_fail (height >= -1);
g_object_freeze_notify (G_OBJECT (guide));
if (width != -1)
g_object_set (guide, "nat-width", width, NULL);
if (height != -1)
g_object_set (guide, "nat-height", height, NULL);
g_object_thaw_notify (G_OBJECT (guide));
}
/**
* gtk_constraint_guide_get_nat_size:
* @guide: a #GtkContraintGuide object
* @width: (allow-none): return location for the natural width,
* or %NULL
* @height: (allow-none): return location for the natural height,
* or %NULL
*
* Gets the natural size of @guide.
*/
void
gtk_constraint_guide_get_nat_size (GtkConstraintGuide *guide,
int *width,
int *height)
{
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
if (width)
*width = guide->values[NAT_WIDTH];
if (height)
*height = guide->values[NAT_HEIGHT];
}
/**
* gtk_constraint_guide_set_max_size:
* @guide: a #GtkConstraintGuide object
* @width: the new maximum width, or -1 to not change it
* @height: the new maximum height, or -1 to not change it
*
* Sets the maximum size of @guide.
*
* If @guide is attached to a #GtkConstraintLayout,
* the constraints will be updated to reflect the new size.
*/
void
gtk_constraint_guide_set_max_size (GtkConstraintGuide *guide,
int width,
int height)
{
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
g_return_if_fail (width >= -1);
g_return_if_fail (height >= -1);
g_object_freeze_notify (G_OBJECT (guide));
if (width != -1)
g_object_set (guide, "max-width", width, NULL);
if (height != -1)
g_object_set (guide, "max-height", height, NULL);
g_object_thaw_notify (G_OBJECT (guide));
}
/**
* gtk_constraint_guide_get_max_size:
* @guide: a #GtkContraintGuide object
* @width: (allow-none): return location for the maximum width,
* or %NULL
* @height: (allow-none): return location for the maximum height,
* or %NULL
*
* Gets the maximum size of @guide.
*/
void
gtk_constraint_guide_get_max_size (GtkConstraintGuide *guide,
int *width,
int *height)
{
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
if (width)
*width = guide->values[MAX_WIDTH];
if (height)
*height = guide->values[MAX_HEIGHT];
}
/**
* gtk_constraint_guide_get_name:
* @guide: a #GtkConstraintGuide
*
* Retrieves the name set using gtk_constraint_guide_set_name().
*
* Returns: (transfer none) (nullable): the name of the guide
*/
const char *
gtk_constraint_guide_get_name (GtkConstraintGuide *guide)
{
g_return_val_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide), NULL);
return guide->name;
}
/**
* gtk_constraint_guide_set_name:
* @guide: a #GtkConstraintGuide
* @name: (nullable): a name for the @guide
*
* Sets a name for the given #GtkConstraintGuide.
*
* The name is useful for debugging purposes.
*/
void
gtk_constraint_guide_set_name (GtkConstraintGuide *guide,
const char *name)
{
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
g_free (guide->name);
guide->name = g_strdup (name);
g_object_notify_by_pspec (G_OBJECT (guide), guide_props[PROP_NAME]);
}
/**
* gtk_constraint_guide_get_strength:
* @guide: a #GtkConstraintGuide
*
* Retrieves the strength set using gtk_constraint_guide_set_strength().
*
* Returns: the strength of the constraint on the natural size
*/
GtkConstraintStrength
gtk_constraint_guide_get_strength (GtkConstraintGuide *guide)
{
g_return_val_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide),
GTK_CONSTRAINT_STRENGTH_MEDIUM);
return guide->strength;
}
/**
* gtk_constraint_guide_set_strength:
* @guide: a #GtkConstraintGuide
* @strength: the strength of the constraint
*
* Sets the strength of the constraint on the natural size of the
* given #GtkConstraintGuide.
*/
void
gtk_constraint_guide_set_strength (GtkConstraintGuide *guide,
GtkConstraintStrength strength)
{
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
if (guide->strength == strength)
return;
guide->strength = strength;
g_object_notify_by_pspec (G_OBJECT (guide), guide_props[PROP_STRENGTH]);
gtk_constraint_guide_update_constraint (guide, NAT_WIDTH);
gtk_constraint_guide_update_constraint (guide, NAT_HEIGHT);
}
+83
View File
@@ -0,0 +1,83 @@
/* gtkconstraintguide.h: Flexible space for constraints
* Copyright 2019 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/>.
*
* Author: Matthias Clasen
*/
#pragma once
#include <gtk/gtktypes.h>
#include <gtk/gtkenums.h>
#include <gtk/gtktypebuiltins.h>
G_BEGIN_DECLS
#define GTK_TYPE_CONSTRAINT_GUIDE (gtk_constraint_guide_get_type ())
/**
* GtkConstraintGuide:
*
* An object that can be added to a #GtkConstraintLayout and be
* used in constraints like a widget, without being drawn.
*
* Guides have a minimum, maximum and natural size. Depending
* on the constraints that are applied, they can act like a
* guideline that widgets can be aligned to, or like 'flexible space'.
*/
GDK_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (GtkConstraintGuide, gtk_constraint_guide, GTK, CONSTRAINT_GUIDE, GObject)
GDK_AVAILABLE_IN_ALL
GtkConstraintGuide * gtk_constraint_guide_new (void);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_guide_set_min_size (GtkConstraintGuide *guide,
int width,
int height);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_guide_get_min_size (GtkConstraintGuide *guide,
int *width,
int *height);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_guide_set_nat_size (GtkConstraintGuide *guide,
int width,
int height);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_guide_get_nat_size (GtkConstraintGuide *guide,
int *width,
int *height);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_guide_set_max_size (GtkConstraintGuide *guide,
int width,
int height);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_guide_get_max_size (GtkConstraintGuide *guide,
int *width,
int *height);
GDK_AVAILABLE_IN_ALL
GtkConstraintStrength gtk_constraint_guide_get_strength (GtkConstraintGuide *guide);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_guide_set_strength (GtkConstraintGuide *guide,
GtkConstraintStrength strength);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_guide_set_name (GtkConstraintGuide *guide,
const char *name);
GDK_AVAILABLE_IN_ALL
const char * gtk_constraint_guide_get_name (GtkConstraintGuide *guide);
G_END_DECLS
+38
View File
@@ -0,0 +1,38 @@
/* gtkconstraintguideprivate.h: Constraint between two widgets
* Copyright 2019 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/>.
*
* Author: Matthias Clasen
*/
#pragma once
#include "gtkconstraintguide.h"
#include "gtkconstraintlayout.h"
#include "gtkconstrainttypesprivate.h"
G_BEGIN_DECLS
void gtk_constraint_guide_update (GtkConstraintGuide *guide);
void gtk_constraint_guide_detach (GtkConstraintGuide *guide);
GtkConstraintVariable *gtk_constraint_guide_get_attribute (GtkConstraintGuide *guide,
GtkConstraintAttribute attr);
GtkConstraintLayout *gtk_constraint_guide_get_layout (GtkConstraintGuide *guide);
void gtk_constraint_guide_set_layout (GtkConstraintGuide *guide,
GtkConstraintLayout *layout);
G_END_DECLS
File diff suppressed because it is too large Load Diff
+93
View File
@@ -0,0 +1,93 @@
/* gtkconstraintlayout.h: Layout manager using constraints
* Copyright 2019 GNOME Foundation
*
* 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/>.
*
* Author: Emmanuele Bassi
*/
#pragma once
#include <gtk/gtklayoutmanager.h>
#include <gtk/gtkconstraint.h>
#include <gtk/gtkconstraintguide.h>
G_BEGIN_DECLS
#define GTK_TYPE_CONSTRAINT_LAYOUT (gtk_constraint_layout_get_type ())
#define GTK_TYPE_CONSTRAINT_LAYOUT_CHILD (gtk_constraint_layout_child_get_type ())
#define GTK_CONSTRAINT_VFL_PARSER_ERROR (gtk_constraint_vfl_parser_error_quark ())
/**
* GtkConstraintLayoutChild:
*
* A #GtkLayoutChild in a #GtkConstraintLayout.
*/
GDK_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (GtkConstraintLayoutChild, gtk_constraint_layout_child, GTK, CONSTRAINT_LAYOUT_CHILD, GtkLayoutChild)
/**
* GtkConstraintLayout:
*
* A layout manager using #GtkConstraint to describe
* relations between widgets.
*/
GDK_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (GtkConstraintLayout, gtk_constraint_layout, GTK, CONSTRAINT_LAYOUT, GtkLayoutManager)
GDK_AVAILABLE_IN_ALL
GQuark gtk_constraint_vfl_parser_error_quark (void);
GDK_AVAILABLE_IN_ALL
GtkLayoutManager * gtk_constraint_layout_new (void);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_layout_add_constraint (GtkConstraintLayout *layout,
GtkConstraint *constraint);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_layout_remove_constraint (GtkConstraintLayout *layout,
GtkConstraint *constraint);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_layout_add_guide (GtkConstraintLayout *layout,
GtkConstraintGuide *guide);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_layout_remove_guide (GtkConstraintLayout *layout,
GtkConstraintGuide *guide);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_layout_remove_all_constraints (GtkConstraintLayout *layout);
GDK_AVAILABLE_IN_ALL
GList * gtk_constraint_layout_add_constraints_from_description (GtkConstraintLayout *layout,
const char * const lines[],
gsize n_lines,
int hspacing,
int vspacing,
GError **error,
const char *first_view,
...) G_GNUC_NULL_TERMINATED;
GDK_AVAILABLE_IN_ALL
GList * gtk_constraint_layout_add_constraints_from_descriptionv (GtkConstraintLayout *layout,
const char * const lines[],
gsize n_lines,
int hspacing,
int vspacing,
GHashTable *views,
GError **error);
GDK_AVAILABLE_IN_ALL
GListModel * gtk_constraint_layout_observe_constraints (GtkConstraintLayout *layout);
GDK_AVAILABLE_IN_ALL
GListModel * gtk_constraint_layout_observe_guides (GtkConstraintLayout *layout);
G_END_DECLS
+37
View File
@@ -0,0 +1,37 @@
/*
* Copyright 2019 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/>.
*
* Author: Matthias Clasen
*/
#pragma once
#include "gtkconstraintlayout.h"
#include "gtkconstraintsolverprivate.h"
G_BEGIN_DECLS
GtkConstraintSolver *
gtk_constraint_layout_get_solver (GtkConstraintLayout *layout);
GtkConstraintVariable *
gtk_constraint_layout_get_attribute (GtkConstraintLayout *layout,
GtkConstraintAttribute attr,
const char *prefix,
GtkWidget *widget,
GHashTable *bound_attributes);
G_END_DECLS
+60
View File
@@ -0,0 +1,60 @@
/* gtkconstraintprivate.h: Constraint between two widgets
* Copyright 2019 GNOME Foundation
*
* 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/>.
*
* Author: Emmanuele Bassi
*/
#pragma once
#include "gtkconstraint.h"
#include "gtkconstrainttypesprivate.h"
G_BEGIN_DECLS
struct _GtkConstraint
{
GObject parent_instance;
GtkConstraintAttribute target_attribute;
GtkConstraintAttribute source_attribute;
GtkConstraintTarget *target;
GtkConstraintTarget *source;
GtkConstraintRelation relation;
double multiplier;
double constant;
int strength;
/* A reference to the real constraint inside the
* GtkConstraintSolver, so we can remove it when
* finalizing the GtkConstraint instance
*/
GtkConstraintRef *constraint_ref;
GtkConstraintSolver *solver;
guint active : 1;
};
void gtk_constraint_attach (GtkConstraint *constraint,
GtkConstraintSolver *solver,
GtkConstraintRef *ref);
void gtk_constraint_detach (GtkConstraint *constraint);
G_END_DECLS
File diff suppressed because it is too large Load Diff
+117
View File
@@ -0,0 +1,117 @@
/* gtkconstraintsolverprivate.h: Constraint solver based on the Cassowary method
* Copyright 2019 GNOME Foundation
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* 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/>.
*
* Author: Emmanuele Bassi
*/
#pragma once
#include "gtkconstrainttypesprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_CONSTRAINT_SOLVER (gtk_constraint_solver_get_type())
G_DECLARE_FINAL_TYPE (GtkConstraintSolver, gtk_constraint_solver, GTK, CONSTRAINT_SOLVER, GObject)
GtkConstraintSolver *
gtk_constraint_solver_new (void);
void
gtk_constraint_solver_freeze (GtkConstraintSolver *solver);
void
gtk_constraint_solver_thaw (GtkConstraintSolver *solver);
void
gtk_constraint_solver_resolve (GtkConstraintSolver *solver);
GtkConstraintVariable *
gtk_constraint_solver_create_variable (GtkConstraintSolver *solver,
const char *prefix,
const char *name,
double value);
GtkConstraintRef *
gtk_constraint_solver_add_constraint (GtkConstraintSolver *solver,
GtkConstraintVariable *variable,
GtkConstraintRelation relation,
GtkConstraintExpression *expression,
int strength);
void
gtk_constraint_solver_remove_constraint (GtkConstraintSolver *solver,
GtkConstraintRef *reference);
GtkConstraintRef *
gtk_constraint_solver_add_stay_variable (GtkConstraintSolver *solver,
GtkConstraintVariable *variable,
int strength);
void
gtk_constraint_solver_remove_stay_variable (GtkConstraintSolver *solver,
GtkConstraintVariable *variable);
gboolean
gtk_constraint_solver_has_stay_variable (GtkConstraintSolver *solver,
GtkConstraintVariable *variable);
GtkConstraintRef *
gtk_constraint_solver_add_edit_variable (GtkConstraintSolver *solver,
GtkConstraintVariable *variable,
int strength);
void
gtk_constraint_solver_remove_edit_variable (GtkConstraintSolver *solver,
GtkConstraintVariable *variable);
gboolean
gtk_constraint_solver_has_edit_variable (GtkConstraintSolver *solver,
GtkConstraintVariable *variable);
void
gtk_constraint_solver_suggest_value (GtkConstraintSolver *solver,
GtkConstraintVariable *variable,
double value);
void
gtk_constraint_solver_begin_edit (GtkConstraintSolver *solver);
void
gtk_constraint_solver_end_edit (GtkConstraintSolver *solver);
void
gtk_constraint_solver_note_added_variable (GtkConstraintSolver *self,
GtkConstraintVariable *variable,
GtkConstraintVariable *subject);
void
gtk_constraint_solver_note_removed_variable (GtkConstraintSolver *self,
GtkConstraintVariable *variable,
GtkConstraintVariable *subject);
void
gtk_constraint_solver_clear (GtkConstraintSolver *solver);
char *
gtk_constraint_solver_to_string (GtkConstraintSolver *solver);
char *
gtk_constraint_solver_statistics (GtkConstraintSolver *solver);
G_END_DECLS
+50
View File
@@ -0,0 +1,50 @@
/* gtkconstrainttypesprivate.h: Private types for the constraint solver
* Copyright 2019 GNOME Foundation
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* 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/>.
*
* Author: Emmanuele Bassi
*/
#pragma once
#include <gtk/gtktypes.h>
#include <gtk/gtkenums.h>
G_BEGIN_DECLS
typedef struct _GtkConstraintVariable GtkConstraintVariable;
typedef struct _GtkConstraintExpression GtkConstraintExpression;
typedef struct _GtkConstraintExpressionBuilder GtkConstraintExpressionBuilder;
/*< private >
* GtkConstraintRef:
*
* A reference to a constraint stored inside the solver; while #GtkConstraint
* represent the public API, a #GtkConstraintRef represents data stored inside
* the solver. A #GtkConstraintRef is completely opaque, and should only be
* used to remove a constraint from the solver.
*/
typedef struct _GtkConstraintRef GtkConstraintRef;
/*< private >
* GtkConstraintSolver:
*
* A simplex solver using the Cassowary constraint solving algorithm.
*/
typedef struct _GtkConstraintSolver GtkConstraintSolver;
G_END_DECLS
File diff suppressed because it is too large Load Diff
+76
View File
@@ -0,0 +1,76 @@
/* gtkconstraintvflparserprivate.h: VFL constraint definition parser
*
* Copyright 2017 Endless
* Copyright 2019 GNOME Foundation
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* 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/>.
*/
#pragma once
#include "gtkconstrainttypesprivate.h"
G_BEGIN_DECLS
typedef struct _GtkConstraintVflParser GtkConstraintVflParser;
typedef struct {
const char *view1;
const char *attr1;
GtkConstraintRelation relation;
const char *view2;
const char *attr2;
double constant;
double multiplier;
double strength;
} GtkConstraintVfl;
GtkConstraintVflParser *
gtk_constraint_vfl_parser_new (void);
void
gtk_constraint_vfl_parser_free (GtkConstraintVflParser *parser);
void
gtk_constraint_vfl_parser_set_default_spacing (GtkConstraintVflParser *parser,
int hspacing,
int vspacing);
void
gtk_constraint_vfl_parser_set_metrics (GtkConstraintVflParser *parser,
GHashTable *metrics);
void
gtk_constraint_vfl_parser_set_views (GtkConstraintVflParser *parser,
GHashTable *views);
gboolean
gtk_constraint_vfl_parser_parse_line (GtkConstraintVflParser *parser,
const char *line,
gssize len,
GError **error);
int
gtk_constraint_vfl_parser_get_error_offset (GtkConstraintVflParser *parser);
int
gtk_constraint_vfl_parser_get_error_range (GtkConstraintVflParser *parser);
GtkConstraintVfl *
gtk_constraint_vfl_parser_get_constraints (GtkConstraintVflParser *parser,
int *n_constraints);
G_END_DECLS
+3 -1
View File
@@ -1118,6 +1118,8 @@ gtk_css_provider_load_internal (GtkCssProvider *self,
if (parent == NULL)
gtk_css_provider_postprocess (self);
g_bytes_unref (bytes);
}
}
@@ -1149,8 +1151,8 @@ gtk_css_provider_load_from_data (GtkCssProvider *css_provider,
gtk_css_provider_reset (css_provider);
g_bytes_ref (bytes);
gtk_css_provider_load_internal (css_provider, NULL, NULL, bytes);
g_bytes_unref (bytes);
gtk_style_provider_changed (GTK_STYLE_PROVIDER (css_provider));
+2 -1
View File
@@ -51,7 +51,8 @@ typedef enum {
GTK_DEBUG_ACTIONS = 1 << 13,
GTK_DEBUG_RESIZE = 1 << 14,
GTK_DEBUG_LAYOUT = 1 << 15,
GTK_DEBUG_SNAPSHOT = 1 << 16
GTK_DEBUG_SNAPSHOT = 1 << 16,
GTK_DEBUG_CONSTRAINTS = 1 << 17,
} GtkDebugFlag;
#ifdef G_ENABLE_DEBUG
-1
View File
@@ -566,7 +566,6 @@ populate_completion (GtkEmojiCompletion *completion,
GVariantIter iter;
GVariant *item;
text = g_strdup (text);
g_free (completion->text);
completion->text = g_strdup (text);
completion->length = g_utf8_strlen (text, -1);
+25
View File
@@ -1529,6 +1529,7 @@ gtk_entry_measure (GtkWidget *widget,
{
GtkEntry *entry = GTK_ENTRY (widget);
GtkEntryPrivate *priv = gtk_entry_get_instance_private (entry);
int i;
gtk_widget_measure (priv->text,
orientation,
@@ -1536,6 +1537,30 @@ gtk_entry_measure (GtkWidget *widget,
minimum, natural,
minimum_baseline, natural_baseline);
for (i = 0; i < MAX_ICONS; i++)
{
EntryIconInfo *icon_info = priv->icons[i];
int icon_min, icon_nat;
if (!icon_info)
continue;
gtk_widget_measure (icon_info->widget,
GTK_ORIENTATION_HORIZONTAL,
-1, &icon_min, &icon_nat, NULL, NULL);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
*minimum += icon_min;
*natural += icon_nat;
}
else
{
*minimum = MAX (*minimum, icon_min);
*natural = MAX (*natural, icon_nat);
}
}
if (priv->progress_widget && gtk_widget_get_visible (priv->progress_widget))
{
int prog_min, prog_nat;
+94
View File
@@ -1053,4 +1053,98 @@ typedef enum {
GTK_PICK_NON_TARGETABLE = 1 << 1
} GtkPickFlags;
/**
* GtkConstraintRelation:
* @GTK_CONSTRAINT_RELATION_EQ: Equal
* @GTK_CONSTRAINT_RELATION_LE: Less than, or equal
* @GTK_CONSTRAINT_RELATION_GE: Greater than, or equal
*
* The relation between two terms of a constraint.
*/
typedef enum {
GTK_CONSTRAINT_RELATION_LE = -1,
GTK_CONSTRAINT_RELATION_EQ = 0,
GTK_CONSTRAINT_RELATION_GE = 1
} GtkConstraintRelation;
/**
* GtkConstraintStrength:
* @GTK_CONSTRAINT_STRENGTH_REQUIRED: The constraint is required towards solving the layout
* @GTK_CONSTRAINT_STRENGTH_STRONG: A strong constraint
* @GTK_CONSTRAINT_STRENGTH_MEDIUM: A medium constraint
* @GTK_CONSTRAINT_STRENGTH_WEAK: A weak constraint
*
* The strength of a constraint, expressed as a symbolic constant.
*
* The strength of a #GtkConstraint can be expressed with any positive
* integer; the values of this enumeration can be used for readability.
*/
typedef enum {
GTK_CONSTRAINT_STRENGTH_REQUIRED = 1001001000,
GTK_CONSTRAINT_STRENGTH_STRONG = 1000000000,
GTK_CONSTRAINT_STRENGTH_MEDIUM = 1000,
GTK_CONSTRAINT_STRENGTH_WEAK = 1
} GtkConstraintStrength;
/**
* GtkConstraintAttribute:
* @GTK_CONSTRAINT_ATTRIBUTE_NONE: No attribute, used for constant
* relations
* @GTK_CONSTRAINT_ATTRIBUTE_LEFT: The left edge of a widget, regardless of
* text direction
* @GTK_CONSTRAINT_ATTRIBUTE_RIGHT: The right edge of a widget, regardless
* of text direction
* @GTK_CONSTRAINT_ATTRIBUTE_TOP: The top edge of a widget
* @GTK_CONSTRAINT_ATTRIBUTE_BOTTOM: The bottom edge of a widget
* @GTK_CONSTRAINT_ATTRIBUTE_START: The leading edge of a widget, depending
* on text direction; equivalent to %GTK_CONSTRAINT_ATTRIBUTE_LEFT for LTR
* languages, and %GTK_CONSTRAINT_ATTRIBUTE_RIGHT for RTL ones
* @GTK_CONSTRAINT_ATTRIBUTE_END: The trailing edge of a widget, depending
* on text direction; equivalent to %GTK_CONSTRAINT_ATTRIBUTE_RIGHT for LTR
* languages, and %GTK_CONSTRAINT_ATTRIBUTE_LEFT for RTL ones
* @GTK_CONSTRAINT_ATTRIBUTE_WIDTH: The width of a widget
* @GTK_CONSTRAINT_ATTRIBUTE_HEIGHT: The height of a widget
* @GTK_CONSTRAINT_ATTRIBUTE_CENTER_X: The center of a widget, on the
* horizontal axis
* @GTK_CONSTRAINT_ATTRIBUTE_CENTER_Y: The center of a widget, on the
* vertical axis
* @GTK_CONSTRAINT_ATTRIBUTE_BASELINE: The baseline of a widget
*
* The widget attributes that can be used when creating a #GtkConstraint.
*/
typedef enum {
GTK_CONSTRAINT_ATTRIBUTE_NONE,
GTK_CONSTRAINT_ATTRIBUTE_LEFT,
GTK_CONSTRAINT_ATTRIBUTE_RIGHT,
GTK_CONSTRAINT_ATTRIBUTE_TOP,
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
GTK_CONSTRAINT_ATTRIBUTE_START,
GTK_CONSTRAINT_ATTRIBUTE_END,
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT,
GTK_CONSTRAINT_ATTRIBUTE_CENTER_X,
GTK_CONSTRAINT_ATTRIBUTE_CENTER_Y,
GTK_CONSTRAINT_ATTRIBUTE_BASELINE
} GtkConstraintAttribute;
/**
* GtkConstraintVflParserError:
* @GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_SYMBOL: Invalid or unknown symbol
* @GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_ATTRIBUTE: Invalid or unknown attribute
* @GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_VIEW: Invalid or unknown view
* @GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_METRIC: Invalid or unknown metric
* @GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_PRIORITY: Invalid or unknown priority
* @GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_RELATION: Invalid or unknown relation
*
* Domain for VFL parsing errors.
*/
typedef enum {
GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_SYMBOL,
GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_ATTRIBUTE,
GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_VIEW,
GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_METRIC,
GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_PRIORITY,
GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_RELATION
} GtkConstraintVflParserError;
#endif /* __GTK_ENUMS_H__ */
+27
View File
@@ -577,9 +577,34 @@ gtk_file_chooser_dialog_map (GtkWidget *widget)
GTK_WIDGET_CLASS (gtk_file_chooser_dialog_parent_class)->map (widget);
}
static void
save_dialog_geometry (GtkFileChooserDialog *dialog)
{
GtkWindow *window;
GSettings *settings;
int old_width, old_height;
int width, height;
settings = _gtk_file_chooser_get_settings_for_widget (GTK_WIDGET (dialog));
window = GTK_WINDOW (dialog);
gtk_window_get_size (window, &width, &height);
g_settings_get (settings, SETTINGS_KEY_WINDOW_SIZE, "(ii)", &old_width, &old_height);
if (old_width != width || old_height != height)
g_settings_set (settings, SETTINGS_KEY_WINDOW_SIZE, "(ii)", width, height);
g_settings_apply (settings);
}
static void
gtk_file_chooser_dialog_unmap (GtkWidget *widget)
{
GtkFileChooserDialog *dialog = GTK_FILE_CHOOSER_DIALOG (widget);
save_dialog_geometry (dialog);
GTK_WIDGET_CLASS (gtk_file_chooser_dialog_parent_class)->unmap (widget);
}
@@ -593,6 +618,8 @@ gtk_file_chooser_dialog_size_allocate (GtkWidget *widget,
width,
height,
baseline);
if (gtk_widget_is_drawable (widget))
save_dialog_geometry (GTK_FILE_CHOOSER_DIALOG (widget));
}
/* We do a signal connection here rather than overriding the method in
+27 -15
View File
@@ -2460,19 +2460,6 @@ location_changed_timeout_cb (gpointer user_data)
return G_SOURCE_REMOVE;
}
static void
reset_location_timeout (GtkFileChooserWidget *impl)
{
GtkFileChooserWidgetPrivate *priv = gtk_file_chooser_widget_get_instance_private (impl);
if (priv->location_changed_id > 0)
g_source_remove (priv->location_changed_id);
priv->location_changed_id = g_timeout_add (LOCATION_CHANGED_TIMEOUT,
location_changed_timeout_cb,
impl);
g_source_set_name_by_id (priv->location_changed_id, "[gtk] location_changed_timeout_cb");
}
static void
location_entry_changed_cb (GtkEditable *editable,
GtkFileChooserWidget *impl)
@@ -2489,7 +2476,16 @@ location_entry_changed_cb (GtkEditable *editable,
}
if (priv->action != GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
reset_location_timeout (impl);
{
/* Reset location timeout */
if (priv->location_changed_id > 0)
g_source_remove (priv->location_changed_id);
priv->location_changed_id = g_timeout_add (LOCATION_CHANGED_TIMEOUT,
location_changed_timeout_cb,
impl);
g_source_set_name_by_id (priv->location_changed_id, "[gtk] location_changed_timeout_cb");
}
}
static void
@@ -3051,12 +3047,20 @@ static void
operation_mode_set_browse (GtkFileChooserWidget *impl)
{
GtkFileChooserWidgetPrivate *priv = gtk_file_chooser_widget_get_instance_private (impl);
GtkRevealerTransitionType old_revealer_transition_type;
gtk_places_sidebar_set_location (GTK_PLACES_SIDEBAR (priv->places_sidebar), priv->current_folder);
gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_files_stack), "list");
location_mode_set (impl, LOCATION_MODE_PATH_BAR);
gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_header_stack), "pathbar");
old_revealer_transition_type = gtk_revealer_get_transition_type (GTK_REVEALER (priv->browse_header_revealer));
gtk_revealer_set_transition_type (GTK_REVEALER (priv->browse_header_revealer),
GTK_REVEALER_TRANSITION_TYPE_NONE);
gtk_revealer_set_reveal_child (GTK_REVEALER (priv->browse_header_revealer), TRUE);
gtk_revealer_set_transition_type (GTK_REVEALER (priv->browse_header_revealer),
old_revealer_transition_type);
gtk_widget_set_sensitive (priv->filter_combo, TRUE);
g_object_notify (G_OBJECT (impl), "subtitle");
}
@@ -3090,10 +3094,19 @@ operation_mode_set_recent (GtkFileChooserWidget *impl)
{
GtkFileChooserWidgetPrivate *priv = gtk_file_chooser_widget_get_instance_private (impl);
GFile *file;
GtkRevealerTransitionType old_revealer_transition_type;
gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_files_stack), "list");
gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_header_stack), "pathbar");
/* Hide browse_header without a transition */
old_revealer_transition_type = gtk_revealer_get_transition_type (GTK_REVEALER (priv->browse_header_revealer));
gtk_revealer_set_transition_type (GTK_REVEALER (priv->browse_header_revealer),
GTK_REVEALER_TRANSITION_TYPE_NONE);
gtk_revealer_set_reveal_child (GTK_REVEALER (priv->browse_header_revealer), FALSE);
gtk_revealer_set_transition_type (GTK_REVEALER (priv->browse_header_revealer),
old_revealer_transition_type);
location_bar_update (impl);
recent_start_loading (impl);
file = g_file_new_for_uri ("recent:///");
@@ -3584,7 +3597,6 @@ gtk_file_chooser_widget_unroot (GtkWidget *widget)
remove_settings_signal (impl, gtk_widget_get_display (widget));
check_icon_theme (impl);
emit_default_size_changed (impl);
GTK_WIDGET_CLASS (gtk_file_chooser_widget_parent_class)->unroot (widget);
}
+11 -3
View File
@@ -216,17 +216,25 @@ gtk_flatten_list_model_items_changed_cb (GListModel *model,
guint added,
gpointer _node)
{
FlattenNode *node = _node, *parent;
FlattenNode *node = _node, *parent, *left;
GtkFlattenListModel *self = node->list;
guint real_position;
gtk_rb_tree_node_mark_dirty (node);
real_position = position;
for (real_position = position;
left = gtk_rb_tree_node_get_left (node);
if (left)
{
FlattenAugment *aug = gtk_rb_tree_get_augment (self->items, left);
real_position += aug->n_items;
}
for (;
(parent = gtk_rb_tree_node_get_parent (node)) != NULL;
node = parent)
{
FlattenNode *left = gtk_rb_tree_node_get_left (parent);
left = gtk_rb_tree_node_get_left (parent);
if (left != node)
{
if (left)
+2
View File
@@ -212,6 +212,8 @@ gtk_grid_layout_child_class_init (GtkGridLayoutChildClass *klass)
static void
gtk_grid_layout_child_init (GtkGridLayoutChild *self)
{
CHILD_ROW_SPAN (self) = 1;
CHILD_COL_SPAN (self) = 1;
}
/**
-1
View File
@@ -1356,7 +1356,6 @@ gtk_header_bar_set_custom_title (GtkHeaderBar *bar,
gtk_header_bar_reorder_css_node (bar, GTK_PACK_START, priv->custom_title);
gtk_widget_set_parent (priv->custom_title, GTK_WIDGET (bar));
gtk_widget_set_valign (priv->custom_title, GTK_ALIGN_CENTER);
if (priv->label_box != NULL)
{
+44 -17
View File
@@ -227,19 +227,35 @@ gtk_icon_helper_paintable_snapshot (GdkPaintable *paintable,
h = MIN (h, height);
x = (width - w) / 2;
y = (height - h) / 2;
gtk_snapshot_save (snapshot);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x, y));
gtk_css_style_snapshot_icon_paintable (style,
snapshot,
self->paintable,
w, h,
self->texture_is_symbolic);
gtk_snapshot_restore (snapshot);
if (x != 0 || y != 0)
{
gtk_snapshot_save (snapshot);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x, y));
gtk_css_style_snapshot_icon_paintable (style,
snapshot,
self->paintable,
w, h,
self->texture_is_symbolic);
gtk_snapshot_restore (snapshot);
}
else
{
gtk_css_style_snapshot_icon_paintable (style,
snapshot,
self->paintable,
w, h,
self->texture_is_symbolic);
}
}
break;
case GTK_IMAGE_PAINTABLE:
case GTK_IMAGE_EMPTY:
break;
case GTK_IMAGE_PAINTABLE:
default:
{
double image_ratio = (double) width / height;
@@ -269,14 +285,25 @@ gtk_icon_helper_paintable_snapshot (GdkPaintable *paintable,
x = floor (width - ceil (w)) / 2;
y = floor (height - ceil (h)) / 2;
gtk_snapshot_save (snapshot);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x, y));
gtk_css_style_snapshot_icon_paintable (style,
snapshot,
self->paintable,
w, h,
self->texture_is_symbolic);
gtk_snapshot_restore (snapshot);
if (x != 0 || y != 0)
{
gtk_snapshot_save (snapshot);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x, y));
gtk_css_style_snapshot_icon_paintable (style,
snapshot,
self->paintable,
w, h,
self->texture_is_symbolic);
gtk_snapshot_restore (snapshot);
}
else
{
gtk_css_style_snapshot_icon_paintable (style,
snapshot,
self->paintable,
w, h,
self->texture_is_symbolic);
}
}
break;
}
+60
View File
@@ -91,6 +91,7 @@
typedef struct {
GtkWidget *widget;
GtkRoot *root;
/* HashTable<Widget, LayoutChild> */
GHashTable *layout_children;
@@ -98,6 +99,16 @@ typedef struct {
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GtkLayoutManager, gtk_layout_manager, G_TYPE_OBJECT)
static void
gtk_layout_manager_real_root (GtkLayoutManager *manager)
{
}
static void
gtk_layout_manager_real_unroot (GtkLayoutManager *manager)
{
}
static GtkSizeRequestMode
gtk_layout_manager_real_get_request_mode (GtkLayoutManager *manager,
GtkWidget *widget)
@@ -188,13 +199,30 @@ gtk_layout_manager_real_create_layout_child (GtkLayoutManager *manager,
NULL);
}
static void
gtk_layout_manager_finalize (GObject *gobject)
{
GtkLayoutManager *self = GTK_LAYOUT_MANAGER (gobject);
GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (self);
g_clear_pointer (&priv->layout_children, g_hash_table_unref);
G_OBJECT_CLASS (gtk_layout_manager_parent_class)->finalize (gobject);
}
static void
gtk_layout_manager_class_init (GtkLayoutManagerClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = gtk_layout_manager_finalize;
klass->get_request_mode = gtk_layout_manager_real_get_request_mode;
klass->measure = gtk_layout_manager_real_measure;
klass->allocate = gtk_layout_manager_real_allocate;
klass->create_layout_child = gtk_layout_manager_real_create_layout_child;
klass->root = gtk_layout_manager_real_root;
klass->unroot = gtk_layout_manager_real_unroot;
}
static void
@@ -226,6 +254,38 @@ gtk_layout_manager_set_widget (GtkLayoutManager *layout_manager,
}
priv->widget = widget;
if (widget != NULL)
gtk_layout_manager_set_root (layout_manager, gtk_widget_get_root (widget));
}
/*< private >
* gtk_layout_manager_set_root:
* @layout_manager: a #GtkLayoutManager
* @root: (nullable): a #GtkWidget implementing #GtkRoot
*
* Sets a back pointer from @root to @layout_manager.
*
* This function is called by #GtkWidget when getting rooted and unrooted,
* and will call #GtkLayoutManagerClass.root() or #GtkLayoutManagerClass.unroot()
* depending on whether @root is a #GtkWidget or %NULL.
*/
void
gtk_layout_manager_set_root (GtkLayoutManager *layout_manager,
GtkRoot *root)
{
GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (layout_manager);
GtkRoot *old_root = priv->root;
priv->root = root;
if (old_root != root)
{
if (priv->root != NULL)
GTK_LAYOUT_MANAGER_GET_CLASS (layout_manager)->root (layout_manager);
else
GTK_LAYOUT_MANAGER_GET_CLASS (layout_manager)->unroot (layout_manager);
}
}
/**
+7
View File
@@ -42,6 +42,10 @@ G_DECLARE_DERIVABLE_TYPE (GtkLayoutManager, gtk_layout_manager, GTK, LAYOUT_MANA
* @layout_child_type: the type of #GtkLayoutChild used by this layout manager
* @create_layout_child: a virtual function, used to create a #GtkLayoutChild
* meta object for the layout properties
* @root: a virtual function, called when the widget using the layout
* manager is attached to a #GtkRoot
* @unroot: a virtual function, called when the widget using the layout
* manager is detached from a #GtkRoot
*
* The `GtkLayoutManagerClass` structure contains only private data, and
* should only be accessed through the provided API, or when subclassing
@@ -77,6 +81,9 @@ struct _GtkLayoutManagerClass
GtkWidget *widget,
GtkWidget *for_child);
void (* root) (GtkLayoutManager *manager);
void (* unroot) (GtkLayoutManager *manager);
/*< private >*/
gpointer _padding[16];
};
+3
View File
@@ -10,4 +10,7 @@ void gtk_layout_manager_set_widget (GtkLayoutManager *manager,
void gtk_layout_manager_remove_layout_child (GtkLayoutManager *manager,
GtkWidget *widget);
void gtk_layout_manager_set_root (GtkLayoutManager *manager,
GtkRoot *root);
G_END_DECLS
+2 -1
View File
@@ -179,7 +179,8 @@ static const GDebugKey gtk_debug_keys[] = {
{ "actions", GTK_DEBUG_ACTIONS },
{ "resize", GTK_DEBUG_RESIZE },
{ "layout", GTK_DEBUG_LAYOUT },
{ "snapshot", GTK_DEBUG_SNAPSHOT }
{ "snapshot", GTK_DEBUG_SNAPSHOT },
{ "constraints", GTK_DEBUG_CONSTRAINTS },
};
#endif /* G_ENABLE_DEBUG */
+3 -6
View File
@@ -1757,7 +1757,7 @@ GtkWidget*
gtk_menu_get_active (GtkMenu *menu)
{
GtkMenuPrivate *priv;
GtkWidget *child;
GtkWidget *child = NULL;
GList *children, *l;
g_return_val_if_fail (GTK_IS_MENU (menu), NULL);
@@ -2414,7 +2414,6 @@ gtk_menu_position (GtkMenu *menu)
GdkAnchorHints anchor_hints;
gint rect_anchor_dx, rect_anchor_dy;
GdkSurface *toplevel;
gboolean emulated_move_to_rect = FALSE;
rect_anchor = priv->rect_anchor;
menu_anchor = priv->menu_anchor;
@@ -2461,10 +2460,8 @@ gtk_menu_position (GtkMenu *menu)
g_signal_handlers_disconnect_by_func (toplevel, moved_to_rect_cb, menu);
if (!emulated_move_to_rect)
g_signal_connect (toplevel, "moved-to-rect", G_CALLBACK (moved_to_rect_cb),
menu);
g_signal_connect (toplevel, "moved-to-rect", G_CALLBACK (moved_to_rect_cb),
menu);
gdk_surface_move_to_rect (toplevel,
&rect,

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