Compare commits

..

448 Commits

Author SHA1 Message Date
Matthias Clasen
d080a2c482 gtk-demo: Plug memory leaks in the settings demo 2019-12-25 01:10:48 -05:00
Matthias Clasen
682dbe1c9c inspector: Use search instead of filtering for properties
This is mainly to test the search support.
2019-12-24 20:09:48 -05:00
Matthias Clasen
3f5d6bd8b5 listbase: search support
Add a filter to GtkListBase, and move the selection
to the first matching item whenever the filter changes.
This is meant to be used with single selection and
a string filter that is hooked up to a search entry.
2019-12-24 20:09:01 -05:00
Matthias Clasen
98aedb7592 inspector: Add columns to the object tree
Add columnview columns in the object tree.
We do the same for treeview columns.
2019-12-24 15:36:08 -05:00
Matthias Clasen
b1fdd77ede builderlistitemfactory: Precompile the xml
This is the one place where we can really take advantage
of precompiling, since we instantiate this template
over and over.
2019-12-24 15:36:08 -05:00
Matthias Clasen
ed7f507206 builder: Avoid a crash in error cases
Don't leave a dangling pointer behind. I've hit
cases where we crash trying to free it again.
2019-12-24 15:36:08 -05:00
Matthias Clasen
a101e8079f builder: Avoid another critical
Only free an expression if we managed
to create one.
2019-12-24 15:36:08 -05:00
Matthias Clasen
b8faadec64 builder: Avoid a critical
Check that the property exists before trying
to create a property expression, and report
an error if it doesn't.
2019-12-24 15:36:08 -05:00
Matthias Clasen
51b4768fd7 expression: Add a new property expression constructor
Allow creating property expresions from a GParamSpec.
This lets us avoid a critical, and instead report an
error in GtkBuilder if the property does not exist.
2019-12-24 15:36:08 -05:00
Matthias Clasen
8febf5e98a Spread single-click-activate api
This makes sense to have in all the views,
not just GtkListView.
2019-12-24 15:36:08 -05:00
Matthias Clasen
1d9e09aaca printdialog: Port to column view
This is not 100% complete. The search is not there yet.
2019-12-24 15:36:08 -05:00
Matthias Clasen
eecb8092dc printer: Fix the default value of icon-name
Just set this to "printer", so we don't have
to fix it up in the print dialog.
2019-12-24 15:36:08 -05:00
Matthias Clasen
ddd504ddfe printbackend: Add a list model getter
Now that we have a list model for printers,
we can start using it.
2019-12-24 15:36:08 -05:00
Matthias Clasen
4044a8cc6c printbackend: Use a list store 2019-12-24 15:36:08 -05:00
Matthias Clasen
05c869d19b inspector: Expand the actions list 2019-12-24 15:36:08 -05:00
Matthias Clasen
57d635e1a1 inspector: Expand the resource list
This is an experiment with adding a filler column.
2019-12-24 15:36:08 -05:00
Matthias Clasen
2c1a0d3d2e inspector: Expand the property list
It looks better this way.
2019-12-24 15:36:08 -05:00
Matthias Clasen
d5d3b4b991 inspector: Expand the object tree
This is how it used to look, and it looks better that way.
2019-12-24 15:36:08 -05:00
Matthias Clasen
19166f15e3 columnview: Take expand into account
When allocating columns, distribute extra space
to columns that have expand set to TRUE.
2019-12-24 15:36:08 -05:00
Matthias Clasen
fe31c2221c columnviewcolumn: Add an expand property
This will be used to determine how to distribute
available extra space in a column view.
2019-12-24 15:36:08 -05:00
Matthias Clasen
50e8ccf030 gtk-demo: Add more scrolling benchmarks
Add a listview and gridview to the scrolling
benchmarks.
2019-12-24 15:36:08 -05:00
Matthias Clasen
7539fe1acc gtk-demo: Make gridview demo use rubberbanding 2019-12-24 15:36:08 -05:00
Matthias Clasen
ee03ae8b9b Add rubberband api
Add an enable-rubberband property to GtkListView,
GtkGridView and GtkColumnView.
2019-12-24 15:36:08 -05:00
Matthias Clasen
7bf21cf9d2 listbase: Add rubberband selection
Implement the typical rubberband selection, including
autoscroll. This is only useful with multiselection,
and not very compatible with single-click-activate.
Therefore, it is not enabled by default, and needs
to be turned on with the enable-rubber-band property.
2019-12-24 15:36:08 -05:00
Matthias Clasen
466aec41f5 multiselection: Add a copy constructor
Add a function to create a multiselection that
is a copy of an existing selection model. We
can do this efficiently if the original is a
multiselection as well, by just copying the
entire set in on go.
2019-12-24 15:36:08 -05:00
Matthias Clasen
5e9adeb9bf Add GtkMultiSelection
This is implemented using a private GtkSet helper.
2019-12-24 15:36:08 -05:00
Matthias Clasen
c7b2307a0b columnviewtitle: Display a context menu
When the ::header-menu property is set on the
column, use the menu model to create and show
a context menu.
2019-12-24 15:36:08 -05:00
Matthias Clasen
6e838098cb columnviewcolumn: Add a menu property
Add a ::header-menu property that will be used
to create a context menu for the header of the
column.
2019-12-24 15:36:08 -05:00
Matthias Clasen
ee76623e54 Add a selection model test
The test shows that we are failing to emit
::selection-changed in some circumstances.
2019-12-24 15:36:08 -05:00
Matthias Clasen
36aaece297 testcolumnview: Reordering in the column editor
Use Ctrl-Up/Down to move the column around.
2019-12-24 15:36:08 -05:00
Matthias Clasen
4c8de636ce testcolumnview: Flesh out column editor
Turn the column list into an editor with
controls for visibility, resizability, reorderability
and width.
2019-12-24 15:36:08 -05:00
Matthias Clasen
8c086dbdc7 columview: Add autoscroll
Autoscroll when the pointer gets close to the
edge during column resizing or reordering. This
is similar to what the treeview does, but it is
implemented using a tick callback, and has
variable speed.
2019-12-24 15:36:08 -05:00
Matthias Clasen
f86aeaf8cd columnview: Allow to cancel reorder with Escape
The treeview does this too.
2019-12-24 15:36:08 -05:00
Matthias Clasen
c814864a3f columnview: Interactive column reordering
Allow rearranging columns by dragging, in the same
way the treeview does.

We add the "dnd" style class to the header while
it is dragged, and we move the header of the dragged
column to the end of its parents children, so that
it gets drawn on top.
2019-12-24 15:36:08 -05:00
Matthias Clasen
9e9d4d914e columnviewcolumn: Add a reorderable property
This will be used for interactive column reordering
in the future.
2019-12-24 15:36:08 -05:00
Matthias Clasen
8f2351d5d3 columnviewlayout: Use header allocation for titles
Normally, this will be identical to the column
allocation, but we will temporarily change it
during column reordering.
2019-12-24 15:36:08 -05:00
Matthias Clasen
4817c7757b columnviewcolumn: Add reordering helpers
Add helper functions that let us temporarily give
a different allocation to headers. These will be
used to implement interactive column reordering
in GtkColumnView.
2019-12-24 15:36:08 -05:00
Matthias Clasen
a44c4b4877 columnviewtitle: Invert on release
This is necessary to make drag-to-reorder work
without triggering inversion.
2019-12-24 15:36:08 -05:00
Matthias Clasen
f8a14427ea columnview: Interactive column resizing
This copies just enough of the treeview code to
get columns moving.
2019-12-24 15:36:08 -05:00
Matthias Clasen
9d0904a445 columnviewcolumn: Add a helper
We need to check whether clicks are in the headers
of columns, so let the column view get at the the
header widget.
2019-12-24 15:36:08 -05:00
Matthias Clasen
4a659c169d columnviewcolumn: Add a resizable property
This will be used for interactive column resizing
in the future.
2019-12-24 15:36:08 -05:00
Matthias Clasen
5ca53555c7 Turn GtkRecentInfo into an object
This is in preparation to eventually using
a list model of recent infos.
2019-12-24 15:36:08 -05:00
Matthias Clasen
0bbc074e08 gtk-demo: Add row reordering to the settings demo 2019-12-24 15:36:08 -05:00
Matthias Clasen
7af244944a gtk-demo: Add filtering to the settings demo
A demo of filtering with lists was missing so far.
2019-12-24 15:36:08 -05:00
Matthias Clasen
ae084d2929 gtk-demo: Crank up max columns of gridview
This lets us fit more cells on screen.
2019-12-24 15:36:08 -05:00
Matthias Clasen
fe3dd5cd8b gtk-demo: Make gridview content switchable
Add a dropdown to switch out the item factory.
2019-12-24 15:36:08 -05:00
Matthias Clasen
3dbac6b133 gtk-demo: Add sorting to the gridview demo 2019-12-24 15:36:08 -05:00
Matthias Clasen
2cb5ce8c72 gtk-demo: Cosmetic changes for the flowbox demo
Mention the size of the dataset.
2019-12-24 15:36:08 -05:00
Matthias Clasen
8ae6e58e0c gtk-demo: Cosmetic changes to the file browser demo
Mention that it involves switching between
different views.
2019-12-24 15:36:08 -05:00
Matthias Clasen
6eebc9183a gtk-demo: Cosmetic changes for the weather demo
Give the weather demo a size and a title, and mention
the size of the dataset in the description.
2019-12-24 15:36:08 -05:00
Matthias Clasen
b84780cc98 gtk-demo: Cosmetic changes to the clocks demo
Give the clocks demo a title and size,
and tweak the description.
2019-12-24 15:36:08 -05:00
Matthias Clasen
46a6ab68f2 gtk-demo: Demo columnview sorting
Enhance the settings demo to have a sortable column.
2019-12-24 15:36:08 -05:00
Matthias Clasen
e5c57d10d7 filechooser: Use a dropdown for choices 2019-12-24 15:36:08 -05:00
Matthias Clasen
9aed6a2b56 filechooser: Use a dropdown for the filter combo 2019-12-24 15:36:08 -05:00
Matthias Clasen
843fa70bef inspector: Use dropdowns in the visual page
Convert everything in the visual page to dropdowns.
2019-12-24 15:36:08 -05:00
Matthias Clasen
2ea918a5e7 inspector: Use a dropdown for size groups
Use a GtkDropDown for the modes of size groups.
2019-12-24 15:36:08 -05:00
Matthias Clasen
f7608a2119 inspector: Use a dropdown for controllers
Use a GtkDropDown for the phases of event controllers.
2019-12-24 15:36:07 -05:00
Matthias Clasen
f55528fd10 inspector: Use a dropdown for attribute mapping
Use a GtkDropDown for the attribute mapping editor.
2019-12-24 15:36:07 -05:00
Matthias Clasen
1d7322ed63 inspector: Use dropdowns in property editor
Replace combo boxes by dropdowns in the property editor.
2019-12-24 15:36:07 -05:00
Matthias Clasen
f3dc528e7d Add GtkDropDown
This is a simple drop down control using list models.
2019-12-24 15:36:07 -05:00
Matthias Clasen
6265a60663 columnview: Add a helper
The column code needs to get access to the
listitem widgets that are children of the listview,
so add a getter.
2019-12-24 15:36:07 -05:00
Matthias Clasen
08bbf44602 columnview: Add column reordering
Add an API to allow reordering columns.
2019-12-24 15:36:07 -05:00
Matthias Clasen
640f165a81 columnviewcolumn: Add a fixed-width property
When fixed-width is set to a value > -1, we make the
measure function of cell and title widgets return this
width, and we set overflow to hidden.
2019-12-24 15:36:07 -05:00
Matthias Clasen
34cbaa9057 columnview: Implement horizontal scrolling
The listview inside always thinks it gets its full size,
and updates its horizontal adjustment accordingly.

So keep our own adjustment, and update it in size_allocate.
2019-12-24 15:36:07 -05:00
Matthias Clasen
2f666332ea columnview: Revise scroll-minimum handling
Tweak the behavior slightly. We don't show
a scrollbar as long as we have at least
min-size available, but we still give the
entire size to the child, up to nat-size.

This matches how viewports handle scroll-minimum.
2019-12-24 15:36:07 -05:00
Matthias Clasen
972090f34d column: Add a visible property
This lets us hide columns, which is useful.
2019-12-24 15:36:07 -05:00
Matthias Clasen
6ab8b1cfe5 inspector: Touch up list styling
This is just the minimal amount of work to make
headers recognizable.
2019-12-24 15:36:07 -05:00
Matthias Clasen
84fd2290a6 inspector: Use a column view for actions
A straight conversion from list box to column view.
2019-12-24 15:36:07 -05:00
Matthias Clasen
55f9e86d67 inspector: Make the resource list sortable
This is using a GtkTreeListRowSorter to keep expanded
state of the tree while changing the sorting.
2019-12-24 15:36:07 -05:00
Matthias Clasen
9892831d52 inspector: Use a column view for the resource list
A conversion from tree view to column view.
2019-12-24 15:36:07 -05:00
Matthias Clasen
baff649ca6 inspector: Use a column view for properties
Just a straight conversion from list box to column view.
2019-12-24 15:36:07 -05:00
Matthias Clasen
921ff0460b columnview: Add a sort-by api 2019-12-24 15:36:07 -05:00
Matthias Clasen
cab09d27db columnview: Document sorting
Add a paragraph outlining how sorting is set up
for GtkColumnView.
2019-12-24 15:36:07 -05:00
Matthias Clasen
65b3a9358a docs: Fix misc typos and omissions 2019-12-24 15:36:07 -05:00
Matthias Clasen
649bcc69e3 docs: Add more private headers to ignore 2019-12-24 15:36:07 -05:00
Matthias Clasen
2357771bd9 treelistmodel: Small documentation tweaks 2019-12-24 15:36:07 -05:00
Matthias Clasen
d53a0ba584 sorter: Small documentation fixes 2019-12-24 15:36:07 -05:00
Matthias Clasen
e2f78e95b2 numericsorter: Small documentation improvements 2019-12-24 15:36:07 -05:00
Matthias Clasen
dea3c8aed0 multisorter: Small documntation improvements 2019-12-24 15:36:07 -05:00
Matthias Clasen
f2a82e7d35 multifilter: Small documentation improvements 2019-12-24 15:36:07 -05:00
Matthias Clasen
9ff85899d0 builderlistitemfactory: Add an example to the docs 2019-12-24 15:36:07 -05:00
Matthias Clasen
602d141a7b maplistmodel: Add an example to the docs 2019-12-24 15:36:07 -05:00
Matthias Clasen
0bed5a8b9d stringfilter: Documnentation additions 2019-12-24 15:36:07 -05:00
Matthias Clasen
f2a50fa590 filter: Documentation fixes 2019-12-24 15:36:07 -05:00
Matthias Clasen
f833959acd filterlistmodel: Documentation fixes 2019-12-24 15:36:07 -05:00
Matthias Clasen
02168260e0 expression: Small documentation fixes 2019-12-24 15:36:07 -05:00
Matthias Clasen
68fbb59f82 docs: Add gtk_expression_watch_unwatch 2019-12-24 15:36:07 -05:00
Matthias Clasen
e7f3a4f61a expression: Correct an example in the docs 2019-12-24 15:36:07 -05:00
Matthias Clasen
e32ae895e3 Add some tests for new GtkBuilder syntax
Some valid and invalid examples for <closure>,
<lookup> and <constant>.
2019-12-24 15:36:07 -05:00
Matthias Clasen
44c5d47ed8 gtk-builder-tool: Minimally validate <binding>
Check that the toplevel property name is legit.
2019-12-24 15:36:07 -05:00
Matthias Clasen
a9f963b5d9 multifilter: Fix a few annotations 2019-12-24 15:36:07 -05:00
Matthias Clasen
0a711ec0b2 builderlistitemfactory: Fix a few annotations 2019-12-24 15:36:07 -05:00
Matthias Clasen
1630482d13 treelistrowsorter: Fix a doc typo 2019-12-24 15:36:07 -05:00
Matthias Clasen
bdaa41184f columnviewcolumn: Fix a type mismatch
The column-view property was declared with the wrong
type. This was causing criticals in the inspector.
2019-12-24 15:36:07 -05:00
Matthias Clasen
0a36ba0611 listitemwidget: Fix single-click-activate
This was broken by the renaming of ::contains-pointer-focus
to ::contains-pointer. Fix it up.
2019-12-24 15:36:07 -05:00
Matthias Clasen
cc39cc2e8d Fix gtk_column_view_create_cells
This code was assuming that the listitem widgets
are children of the column view, which they aren't.
2019-12-24 15:36:07 -05:00
Matthias Clasen
51e2a51dfd filterlistmodel: Remove pre-filter remnants
We are not using the filter func typdef anymore.
2019-12-24 15:36:07 -05:00
Matthias Clasen
90b32cac0b Add filter test to testsuite 2019-12-22 23:12:21 -05:00
Matthias Clasen
b56cfc5293 Add a test for multi filter unreffing
This tests the fix in the previous commit.
2019-12-22 23:12:21 -05:00
Matthias Clasen
7bb1f036d6 multifilter: Remove an extraneous unref
The sequence is using unref as free func,
no need to ido it ourselves.
2019-12-22 23:12:21 -05:00
Benjamin Otte
0cd203b07d testsuite: Add tests for GtkTreeListSorter 2019-12-18 05:48:03 +01:00
Matthias Clasen
86b29d4d7a Add GtkTreeListRowSorter
This is a special-purpose sorter that can
apply the sorting of another sorter to the
levels of a GtkTreeListModel.
2019-12-18 05:48:02 +01:00
Benjamin Otte
3ffb005135 testcolumnview: Add sorters 2019-12-18 05:48:02 +01:00
Matthias Clasen
a4b15d205e column view title: Show sort indicators 2019-12-18 05:48:02 +01:00
Matthias Clasen
0b4f75cf25 columnview: Add sorting
This is a somewhat large commit that:

- Adds GtkColumnViewSorter
This is a special-purpose, private sorter implementation which sorts
according to multiple sorters, allowing each individual sorter to be
inverted. This will be used with clickable column view headers.

- Adds a read-only GtkColumnView::sorter property
The GtkColumnView creates a GtkColumnViewSorter at startup that it uses
for this property.

- Adds a writable GtkColumnViewColumn::sorter property
This allows defining per-column sorters. Whenever an application sets a
sorter for a column, the header becomes clickable and whenever
a header is clicked, that column's sorter is prepended to the list of
sorters, unless it is already the first sorter, in which case we invert
its order. No column can be in the list more than once.
2019-12-18 05:48:02 +01:00
Matthias Clasen
163477acfb gtk-demo: Add a large grid demo
This is similar to the flowbox demo, but much bigger.
2019-12-18 05:45:39 +01:00
Matthias Clasen
f80335505e listview: Add single-click-activate
Add a single-click-activate property to GtkListView.
2019-12-18 05:45:39 +01:00
Matthias Clasen
ffdcde53f5 listitemwidget: Add single-click-activate
Add a mode to GtkListItemWidget that activates on
single click and selects on hover. Make
GtkListItemManager set this on its items
when its own 'property' of the same name is set.
2019-12-18 05:45:39 +01:00
Matthias Clasen
5d836b5e15 builder-tool: Pass through CDATA where it makes sense
This avoids a ton of escaping for
GtkBuilderListItemFactory::bytes.
2019-12-18 05:45:39 +01:00
Matthias Clasen
539213133f docs: Reorganize list widgets in their own chapter 2019-12-18 05:45:39 +01:00
Benjamin Otte
6977a03f65 fontchooserwidget: Port to listmodels
The port is kind of evil, in that it stores either a PangoFontFamily or a
PangoFontFace in the list, depending on if the fontchooser is configured
to select fonts or faces.
It also does not cache the font description anymore, so more calls to
pango_font_describe() may happen.

If both of these issues turn out problematic, the fontchooser would need
to resurrect GtkDelayedFontDescription again and put objects of that
type through the model.

These changes depend on Pango 1.46's introduction of listmodels and
various new getters, so the dependency has been upgraded.
2019-12-18 05:45:39 +01:00
Matthias Clasen
0875374b1d Add some tests for expression binding
In particular, test that expressios can deal with object == this.
2019-12-18 05:45:39 +01:00
Benjamin Otte
fe1ce2aaf8 expression: Allow passing a this object to bind()
This gives a bit more control over the arguments passed to expressions.
2019-12-18 05:45:39 +01:00
Benjamin Otte
a81429c10f widget: Do parent_class handling properly
The previous cosde did not actually query the parent class, it just did
a very complicated C cast.
2019-12-18 05:45:39 +01:00
Benjamin Otte
2f52d98ef4 gtk-demo: Add a Clocks demo
This demo is meant to showcase expressions.

It also needs the fixes in glib 2.64 to work properly.
2019-12-18 05:45:39 +01:00
Benjamin Otte
5a076b0c2f xxx: Add a hack to make paintables transform to/from objects
See also: https://gitlab.gnome.org/GNOME/glib/merge_requests/1251
2019-12-18 05:45:39 +01:00
Benjamin Otte
69f59109ee inspector: Remove private struct for prop editor 2019-12-18 05:45:39 +01:00
Benjamin Otte
6bf508ce73 inspector: Make Controller page a GtkWidget 2019-12-18 05:45:39 +01:00
Benjamin Otte
ae26ce017b inspector: Remove private struct from controllers 2019-12-18 05:45:39 +01:00
Benjamin Otte
0a126f65fb columnview: Add header
This uses a custom GtkColumnViewTitle widget. So far that widget is
pretty boring, but that will change once we added
resizing, reordering, dnd, sorting, hiding/showing of columns or
whatever UIs we want.
2019-12-18 05:45:39 +01:00
Benjamin Otte
6d0695260d tests: Add testcolumnview 2019-12-18 05:45:37 +01:00
Benjamin Otte
a43e0b1e62 columnview: Add a custom LayoutManager
The ColumnView now allocates column widths first and then the individual
rows use the new layout manager which looks at the column allocations to
allocate their children.
2019-12-15 23:33:04 +01:00
Benjamin Otte
01d4a28c9f constraint-editor: Don't poke around in widget internals 2019-12-15 23:33:04 +01:00
Benjamin Otte
052343ca7d columnview: Fix styling with Adwaita
- Use "treeview" as the node name
- Add .view style class
2019-12-15 23:33:04 +01:00
Benjamin Otte
7f4260f97e inspector: Port object tree to GtkColumnView 2019-12-15 23:33:04 +01:00
Benjamin Otte
2b42f0fcb3 columnview: Add GtkColumnViewCell
It's a GtkListItemWidget subclass that tracks the column it belongs to
and allows the column to track it.

We also use this subclass to implement sizing support so columns share
the same size and get resized in sync.
2019-12-15 23:33:04 +01:00
Benjamin Otte
f46c405351 widget: Add a hook for resizes
It's private, no APIs, we don't talk about it. But we will start using
it very soon, so we can do size request caching in columns and avoid
sizegroups...
2019-12-15 23:33:04 +01:00
Benjamin Otte
8f4a0391b3 columnview: Implement GtkScrollable
Just forward it to the listview for now.
2019-12-15 23:33:04 +01:00
Benjamin Otte
5b282411c4 columnview: Add listitems for the columns
They are not aligned in columns yet, but they do exist.
2019-12-15 23:33:04 +01:00
Benjamin Otte
e4392bdf5a listitemwidget: Lazily create listitems
We only create them in root/unroot (they should be created in
appear/disappear, but that vfunc doesn't exist yet), that way we can
avoid expensive work while the widget isn't used for anything.
2019-12-15 23:33:04 +01:00
Benjamin Otte
e845e93f58 listitem: Move position/item/selected tracking to widget
This way, we can ensure it's always there when we need it (before the
item gets created) and gone when we don't (if some GC language holds on
to the item after we've destroyed the widget).
2019-12-15 23:33:04 +01:00
Benjamin Otte
98b4269abd listitemwidget: Add a private struct
I had to rename the item property to list_item anyway, so I could just
do the next step with it.
2019-12-15 23:33:04 +01:00
Benjamin Otte
9b132b80ae listitemfactory: Simplify
Instead of 6 vfuncs, we now have 3 and rely on the factory keeping track
of what it needs to do.

We're doing lots of dancing from one object to another here, but this
will hopefully get simpler with further commits.
2019-12-15 23:33:04 +01:00
Benjamin Otte
7c402bcf2c listitemfactory: Reorganize vfuncs
Instead of bind/rebind/update/unbind, we now just have update, and the
factories get to interpret that in the way they want.
2019-12-15 23:33:04 +01:00
Benjamin Otte
6d73e3a6fa listitem: Make this a GObject
This splits GtkListItem into 2 parts:

1. GtkListItem
   This is purely a GObject with public API for developers who want to
   populate lists. There is no chance to cause conflict with GtkWidget
   properties that the list implementation assumed control over and
   defines a clear boundary.
2. GtkListItemWidget
   The widget part of the listitem. This is not only fully in control of
   the list machinery, the machinery can also use different widget
   implementations for different list widgets like I inted to for
   GtkColumnView.
2019-12-15 23:33:04 +01:00
Benjamin Otte
730575677f builder: Make gtk_builder_extend_with_template() work with objects
This will be relevant later when we introduce GtkListItem which is not a
GtkWidget.
2019-12-15 23:33:04 +01:00
Benjamin Otte
d4d07bcb2a gtk-demo: Add a Coverflow application launcher
This is roughly the simplest demo I could come up with.

But I documented it, so there's your tutorial.

Related: #2214
2019-12-15 23:33:04 +01:00
Benjamin Otte
01cdc67db0 Add GtkSignalListItemFactory
So the poor Rust users can actually use this.

I would totally not use this ever!
2019-12-15 23:33:04 +01:00
Benjamin Otte
77c9d0d0fb columnview: Allow adding/removing columns
... and make that work in UI files via <child>, too.
2019-12-15 23:33:04 +01:00
Benjamin Otte
3cc9fa9f67 gtk-demo: Add a minesweeper demo
The demo shows creating ones own listmodel and using it to fill a grid.

I am totally getting the hang of React btw:
500 lines of logic with no UI code and 100 lines of GtkBuilder XML and
I get a sweet UI.
2019-12-15 23:33:04 +01:00
Benjamin Otte
181b9655ef Add GtkColumnView skeleton
It's just a copy/paste of the listview code with all the internals
gutted. The code doesn't do anything.
2019-12-15 23:33:04 +01:00
Benjamin Otte
1eab9ba350 wip: Add GtkCoverFlow
The widget mostly works out of the box, but some tweaking may be
necessary (in particular in the theme) and the gtk-demo changes might
require removing before this is production-ready.
2019-12-15 23:33:04 +01:00
Benjamin Otte
d1d0adeae9 listbase: Take over anchor handling
With that, pretty much all code but allocating the widgets is gone from
the gridview and listview.
2019-12-15 23:33:04 +01:00
Benjamin Otte
64a2f04006 listbase: Add vfuncs to convert positions to/from coordinates
... and use that to implement PageUp/PageDown.

With that, all keyboard handling has been moved to GtkListBase.
2019-12-15 23:33:04 +01:00
Benjamin Otte
c835bb30d1 listbase: Move focus moving keybindings here
The focus tracker is not yet moved because that depends on scroll_to()
support and we don't have that yet.
Whoops.
So we use a hack.
2019-12-15 23:33:04 +01:00
Benjamin Otte
96d333f649 Remove gtk_selection_model_user_select_item() again
This reverts commit 6a164ab306dad9096bde736c907494c71086d3c4.

The function was awkward and we now have only one caller again, so we
can fold it back into it.
2019-12-15 23:33:04 +01:00
Benjamin Otte
66142ae74f listbase: Move orientable implementation here 2019-12-15 23:33:04 +01:00
Benjamin Otte
75f539b3a4 listbase: Move selection handling here 2019-12-15 23:33:04 +01:00
Benjamin Otte
ad12914c55 listbase: Move item manager here
Nothing really changes, because both ListView and GridView still keep
self->item_manager around, but it's set up to point at the base's item
manager.

This way we can slowly move things to GtkListBase that need the item
manager (like trackers).
2019-12-15 23:33:04 +01:00
Benjamin Otte
f614011569 listbase: Move GtkScrollable implementation
Shared code between GtkGridView and GtkListView.
2019-12-15 23:33:04 +01:00
Benjamin Otte
013db26d22 Add GtkListBase
This is a base item for GTK's list widgets so they can share some (read:
hopefully a lot of) code.
2019-12-15 23:33:04 +01:00
Benjamin Otte
9fab1b3d25 gridview: Simplify allocation code
It doesn't fix the bug I'm after, but it looks a lot better.
2019-12-15 23:33:04 +01:00
Benjamin Otte
c3bb95d7d9 listview: Port various gridview improvements
- Handle anchor as align + top/bottom
  This fixes behavior for cells that are higher than the view
- Add gtk_list_view_adjustment_is_flipped()
  This should fix RTL handling of horizontal lists
- Fix scrolling
  This should make scrolling more reliable, particularly on short lists
  that are only a few pages long.
2019-12-15 23:33:04 +01:00
Benjamin Otte
27a891adb8 demo: Add a file browser demo 2019-12-15 23:33:04 +01:00
Benjamin Otte
94b162829c gridview: Add move keybindings 2019-12-15 23:33:04 +01:00
Benjamin Otte
e54f3f68a0 gridview: Implement (un)select all
Adds listitem.select-all and listitem.unselect-all actions and installs
the same keybindings as the treeview for those actions.
2019-12-15 23:33:04 +01:00
Benjamin Otte
ddc665bb01 gridview: Add a focus tracker
... and use that to properly update selections when moving around with
the arrow keys.
2019-12-15 23:33:04 +01:00
Benjamin Otte
d0495e36e6 gridview: Implement list.scroll-to action 2019-12-15 23:33:04 +01:00
Benjamin Otte
4444bb3d98 gridview: Add activation 2019-12-15 23:33:04 +01:00
Benjamin Otte
b9616124cb gridview: Implement minimum row height
We only allocate a certain amount of widgets - and we don't want to run
out of them. So we make all widgets high enough for this to never
happen.
2019-12-15 23:33:04 +01:00
Benjamin Otte
6218a27daf gridview: Implement the list.select-item action 2019-12-15 23:33:04 +01:00
Benjamin Otte
51ecc2d566 selectionmodel: Add gtk_selection_model_user_select_item()
I'm not sure this should be public API because it's incredibly awkward.
But it should definitely be shared between list widget implementations.
2019-12-15 23:33:04 +01:00
Benjamin Otte
050bd6d5e3 gridview: Implement anchors and scrolling 2019-12-15 23:33:04 +01:00
Benjamin Otte
0229f11784 widget: Add gtk_widget_get_size()
A little bit of convenience.
2019-12-15 23:33:04 +01:00
Benjamin Otte
cee950b455 listitemmanager: Handle NULL factory
Just don't call it and create empty listitems.
2019-12-15 23:33:04 +01:00
Timm Bäder
3a5f47c3b8 demo: Use a listview as sidebar 2019-12-15 23:33:04 +01:00
Benjamin Otte
484f804ba6 gtk-demo: Introduce awards
We need a way to get a useful listbox, so here we go!
2019-12-15 23:33:04 +01:00
Benjamin Otte
5b96335956 builder: Autofill scope property of listitemfactory
I couldn't come up with a better way to automatically inherit the scope
in the builder list item factory that didn't involve a magic
incantation in the XML file. And I do not want developers to know magic
incantations to do a thing that should pretty much always be done.
2019-12-15 23:33:04 +01:00
Benjamin Otte
61362af27b builderlistitemfactory: Add scope argument
This way, the scope used when creating builder instances can be
influenced. This way, callbacks can be passed into the factory.
2019-12-15 23:33:04 +01:00
Benjamin Otte
fc82f5fe29 listitemfactory: Make the builder factory properly buildable
Turn the construct arguments into construct properties so that they can
be set from ui files.
2019-12-15 23:33:04 +01:00
Benjamin Otte
5ae2c1fdca listview: Add move keybindings
My god, these are a lot.

And my god, these are complicated to get right.
2019-12-15 23:33:04 +01:00
Benjamin Otte
eba9ec613d listview: Add gtk_list_view_get_position_at_y() 2019-12-15 23:33:04 +01:00
Benjamin Otte
61fc0a6a59 listitem: Add "listitem.select" action and keybindings for it
In fact, grab space with all modifiers to toggle selection of the
current item.
2019-12-15 23:33:03 +01:00
Benjamin Otte
250760468b listview: Add a focus tracker
This ensures that the row with the input focus always stays available,
even when scrolled out of view.
2019-12-15 23:33:03 +01:00
Benjamin Otte
9d5063cf68 listview: Implement (un)select all
Adds listitem.select-all and listitem.unselect-all actions and installs
the same keybindings as the treeview for those actions.
2019-12-15 23:33:03 +01:00
Benjamin Otte
c4af364bfb listview: Track focus movements and update selection
When focus moves via tab/arrow, we need to select the new item.
2019-12-15 23:33:03 +01:00
Benjamin Otte
3e1cad5755 listview: Implement activation
- a GtkListview::activate signal
- a GtkListItem::activatable property
- activate list items on double clicks and <Enter> presses
2019-12-15 23:33:03 +01:00
Benjamin Otte
42c077443e treeexpander: Implement input support
This implements all the keybindings from GtkTreeView that can be
supported.

It does not implement expand-all, because supporting that means
causing the TreeListModel to emit lots of create_model vfuncs which in
turn would cause many items-changed signal which in turn would cause
many signal handlers to run which in turn would make "expand-all" very
reentrant, and I'm uneasy about supporting that.

For the mouse, just add a click gesture to the expander icon that toggles
expanded state.
2019-12-15 23:33:03 +01:00
Benjamin Otte
7a49d2e848 listitem: Change focus handling
Focus in the listitem now works like this:
1. If any child can take focus, do not ever attempt
   to take focus.
2. Otherwise, if this item is selectable or activatable,
   allow focusing this widget.

This makes sure every item in a list is focusable for
activation and selection handling, but no useless widgets
get focused and moving focus is as fast as possible.
2019-12-15 23:33:03 +01:00
Benjamin Otte
462953cac0 inspector: Make the recorder node list use a ListView
It's quite a bit faster now, but the code is also a bit more awkward.

Pain points:

- GtkTreeListModel cannot be created in UI files because it needs
  a CreateModelFunc.
  Using a signal for this doesn't work because autoexpand wants to
  expand the model before the signal handler is connected.

- The list item factory usage is still awkward. It's bearable here
  because the list items are very simple, but still.
2019-12-15 23:33:03 +01:00
Benjamin Otte
5b5ab5c592 inspector: Use a GtkTreeExpander in the object tree 2019-12-15 23:33:03 +01:00
Benjamin Otte
d89f9b6684 inspector: Use a treeexpander in the recorder 2019-12-15 23:33:03 +01:00
Benjamin Otte
71f104782a demo: Add a GSettings tree demo
It is meant to look somewhat like dconf-editor when it is done.

So far, it's just a list.
2019-12-15 23:33:03 +01:00
Benjamin Otte
297a2795c3 Add GtkTreeExpander
This is a container widget that takes over all the duties of tree
expanding and collapsing.
It has to be a container so it can capture keybindings while focus is
inside the listitem.

So far, this widget does not allow interacting with it, but it shows the
expander arrow in its correct state.

Also, testlistview uses this widget now instead of implementing
expanding itself.
2019-12-15 23:33:03 +01:00
Benjamin Otte
081645186d gridview: Actually do something
Implement measuring and allocating items - which makes the items appear
when drawing and allows interacting with the items.

However, the gridview still does not allow any user interaction
(including scrolling).
2019-12-15 23:33:03 +01:00
Benjamin Otte
20201662f1 listview: Pass the CSS name of listitems to the manager
... instead of hardcoding "row".
2019-12-15 21:11:03 +01:00
Benjamin Otte
3c97226e66 gridview: Implement GtkOrientable
Again, this is just the skeleton, because the Gridview does nothing yet.
2019-12-15 21:11:03 +01:00
Benjamin Otte
6b4b1e1921 gridview: Add factory handling
Just copy the listview APIs.

Code still doesn't do anything with it.
2019-12-15 21:11:03 +01:00
Benjamin Otte
246421f92c listview: Expose GtkListItemFactory APIs
Due to the many different ways to set factories, it makes sense to
expose them as custom objects.

This makes the actual APIs for the list widgets simpler, because they
can just have a regular "factory" property.

As a convenience function, gtk_list_view_new_with_factory() was added
to make this whole approach easy to use from C.
2019-12-15 21:11:03 +01:00
Benjamin Otte
603055b70d textview: Make cursor work when blinking is disabled 2019-12-15 21:10:29 +01:00
Benjamin Otte
6a26bb0e2f gtk-demo: Add a rough start at a Weather demo
This demos a horizontal listview.
2019-12-15 21:10:29 +01:00
Benjamin Otte
81bc2117b2 listview: Implement GtkOrientable 2019-12-15 21:10:28 +01:00
Benjamin Otte
f307f99275 tests: Add a rough form of multiselection
Just store a "filechooser::selected" attribute in the GFileInfo if
the file is meant to be selected.
2019-12-15 21:10:28 +01:00
Benjamin Otte
8157408df8 listview: Implement extending selections
Shift-clicking to extend selections now also works, imitating the
behavior of normal clicking and Windows Explorer (but not treeview):

1. We track the last selected item (normally, not via extend-clicking).

2. When shift-selecting, we modify the range from the last selected item
   to this item the same way we modify the regular item when not using
   shift:

2a. If Ctrl is not pressed, we select the range and unselect everything
    else.

2b. If Ctrl is pressed, we make the range have the same selection state
    as the last selected item:
    - If the last selected item is selected, select the range.
    - If the last selected item is not selected, unselect the range.
2019-12-15 21:10:28 +01:00
Benjamin Otte
9630b9f244 listview: Add list.scroll_to_item action
The action scrolls the given item into view.

Listitems activate this action when they gain focus.
2019-12-15 21:10:28 +01:00
Benjamin Otte
4b277dd47a testlistview: Load icons async
Speeds up loading by 4x, because out of view icons aren't loaded
anymore.
2019-12-15 21:10:28 +01:00
Benjamin Otte
5fcdf00a1a testlistview: Port to directory list 2019-12-15 21:10:28 +01:00
Benjamin Otte
48e1a3cc06 listitemfactory: Add a factory for ui files
Reuse <template> magic to initialize GtkListItems. This feels
amazingly hacky, but it also amazingly worked on the first try.
2019-12-15 21:10:28 +01:00
Benjamin Otte
8c5b077555 listitemfactory: Split implementation out
.. into gtkfunctionslistitemfactory.c

Now we can add a different implmenetation.
2019-12-15 21:10:28 +01:00
Benjamin Otte
023ff509b2 listitemfactory: vfuncify
No functional changes other than a new indirection.
2019-12-15 21:10:28 +01:00
Benjamin Otte
a0a7da2e3b listitemfactory: Sanitize APIs
Make sure the APIs follow a predictable path:

setup
  bind
    rebind/update (0-N times)
  unbind
teardown

This is the first step towards providing multiple different factories.
2019-12-15 21:10:28 +01:00
Benjamin Otte
b7ae37ab3d listview: Add gtk_list_view_set_show_separators()
Do the same thing that GtkListBox does in commit
0249bd4f8a
2019-12-15 21:10:28 +01:00
Benjamin Otte
6d8c6bb2f7 listitemmanager: Add trackers
... and replace the anchor tracking with a tracker.

Trackers track an item through the list across changes and ensure that
this item (and potentially siblings before/after it) are always backed
by a GtkListItem and that if the item gets removed a replacement gets
chosen.

This is now used for tracking the anchor but can also be used to add
trackers for the cursor later.
2019-12-15 21:10:28 +01:00
Benjamin Otte
b00c04a986 listitemmanager: Simplify
Remove a bunch of API from the headers that isn't used anymore and then
refactor code to not call it anymore.

In particular, get rid of GtkListItemManagerChange and replace it with a
GHashTable.
2019-12-15 21:10:28 +01:00
Benjamin Otte
62da088018 gridview: Implement GtkScrollable
We can now scroll all the nothing we display.

We also clip it properly.
2019-12-15 21:10:28 +01:00
Benjamin Otte
6d93197f08 listitemmanager: Move list of listitems here
All the listview infrastructure moved with it, so the next step is
moving that back...
2019-12-15 21:10:28 +01:00
Benjamin Otte
72ce2ff512 wayland: Remove function declaration for nonexisting function 2019-12-15 21:10:28 +01:00
Benjamin Otte
cfd503893c gridview: Add API for setting number of columns
The API isn't used yet.
2019-12-15 21:10:28 +01:00
Benjamin Otte
a2ec02875a gtk: Add a GtkGridView skeleton 2019-12-15 21:10:28 +01:00
Benjamin Otte
07036e28c0 listitem: Add a press gesture to select the item
This is implemented by using actions, which are a neat trick to get to
allow the ListItem to call functions on the ListView without actually
needing to be aware of it.
2019-12-15 21:10:28 +01:00
Benjamin Otte
0b3135bf14 listview: Add initial support for displaying selections 2019-12-15 21:10:28 +01:00
Benjamin Otte
2ea5607f79 listview: Reset listitems' CSS animations when rebinding
This way, newly displayed rows don't play an unselect animation (text
fading in) when they are unselected, but the row was previously used for
a selected item.
2019-12-15 21:10:28 +01:00
Benjamin Otte
35e516f996 listview: Add selection properties to ListItem
This just brings the infrastructure into place, we're not using the
properties yet.
2019-12-15 21:10:28 +01:00
Benjamin Otte
b856fe66b9 listview: Try to keep the list items in order when scrolling
Instead of just destroying all items and then recreating them (or even
hide()ing and then show()ing them again (or even even repositioning
them in the widget tree)), just try to reust them in the order they are.

This works surprisingly well when scrolling and most/all widgets
just moved.
2019-12-15 21:10:28 +01:00
Benjamin Otte
7d01e25558 listlistmodel: Add gtk_list_list_model_item_moved()
Use it to fix a case that just said g_warning ("oops").

Apparently I had forgotten the case where a container moved a child
in the widget tree.
2019-12-15 21:10:28 +01:00
Benjamin Otte
b99db2a60b listitemmanager: Switch from "insert_before" to "insert_after" argumnet
We reorder widgets start to end, so when reusing a list item, we
correctly know the previous sibling for that list item, but not the
next sibling yet. We just know the widget it should ultimately be in
front of.
So we can do a more correct guess of the list item's place in the widget
tree if we think about where to place an item like this.

Actually using this change will come in the next commit.
2019-12-15 21:10:28 +01:00
Benjamin Otte
085e4ad273 testlistview: Create widgets only once
Previously, we were recreating all widgets every time the list item was
rebound, which caused a lot of extra work every time we scrolled.

Now we keep the widgets around and only set their properties again when
the item changes.
2019-12-15 21:10:28 +01:00
Benjamin Otte
72dea0d5e9 testlistview: Show the row number
Always show the current row. This is mostly useful for debugging, not
for beauty.
2019-12-15 21:10:28 +01:00
Benjamin Otte
6dd18fafaa listview: Only allocate necesary rows
This is the big one.

The listview only allocates 200 rows around the visible row now.
Everything else is kept in ListRow instances with row->widget == NULL.

For rows without a widget, we assign the median height of the child
widgets as the row's height and then do all calculations as if there
were widgets that had requested that height (like setting adjustment
values or reacting to adjustment value changes).

When the view is scrolled, we bind the 200 rows to the new visible area,
so that the part of the listview that can be seen is always allocated.
2019-12-15 21:10:28 +01:00
Benjamin Otte
9b9aec360e listview: Change anchor handling again
The anchor is now a tuple of { listitem, align }.

Using the actual list item allows keeping the anchor across changes
in position (ie when lists get resorted) while still being able to fall
back to positions (list items store their position) when an item gets
removed.

The align value is in the range [0..1] and defines where in the visible
area to do the alignment.
0.0 means to align the top of the row with the top of the visible area,
1.0 aligns the bottom of the widget with the visible area and 0.5 keeps
the center of the widget at the center of the visible area.
It works conceptually the same as percentages in CSS background-position
(where the background area and the background image's size are matched
the same way) or CSS transform-origin.
2019-12-15 21:10:28 +01:00
Benjamin Otte
0db67c9709 listview: Change how binding is done
We now don't let the functions create widgets for the item from the
listmodel, instead we hand out a GtkListItem for them to add a widget
to.

GtkListItems are created in advance and can only be filled in by the
binding code by gtk_container_add()ing a widget.
However, they are GObjects, so they can provide properties that the
binding code can make use of - either via notify signals or GBinding.
2019-12-15 21:10:28 +01:00
Benjamin Otte
c935bf5648 listitem: Add gtk_list_item_get_position()
Also refactor the whole list item management yet again.

Now, list item APIs doesn't have bind/unbind functions anymore, but only
property setters.

The item factory is the only one doing the binding.
As before, the item manager manages when items need to be bound.
2019-12-15 21:10:28 +01:00
Benjamin Otte
94a9752c43 tests: Make animating listview do random resorts 2019-12-15 21:10:28 +01:00
Benjamin Otte
de005bd1d6 listview: Change change management
Add a GtkListItemManagerChange object that tracks all removed list
rows during an item-changed signal so they can be added back later.
2019-12-15 21:10:28 +01:00
Benjamin Otte
134db60479 listview: Make the listitemmanager stricter
Require that items created with the manager get destroyed via the
manager.

To that purpose, renamed create_list_item() to acquire_list_item() and
add a matching release_list_item() function.

This way, the manager can in the future keep track of all items and
cache information about them.
2019-12-15 21:10:28 +01:00
Benjamin Otte
662b142c86 listview: Add GtkListItem
GtkListItem is a generic row widget that is supposed to replace
GtkListBoxRow and GtkFlowBoxChild.
2019-12-15 21:10:28 +01:00
Benjamin Otte
22a9001103 listview: Add GtkListItemManager
It's all stubs for now, but here's the basic ideas about what
this object is supposed to do:

(1) It's supposed to be handling all the child GtkWidgets that are
    used by the listview, so that the listview can concern
    itself with how many items it needs and where to put them.
(2) It's meant to do the caching of widgets that are not (currently)
    used.
(3) It's meant to track items that remain in the model across
    items-changed emissions and just change position.
(2) It's code that can be shared between listview and potential
    other widgets like a GridView.

It's also free to assume that the number of items it's supposed to
manage doesn't grow too much, so it's free to use O(N) algorithms.
2019-12-15 21:10:28 +01:00
Benjamin Otte
42b62c7ba2 listview: Implement an anchor
The anchor selection is very basic: just anchor the top row.

That's vastly better than any other widget already though.
2019-12-15 21:10:28 +01:00
Benjamin Otte
8bf19f7cbf tests: Add a test for a permanently changing listview
This is mostly for dealing with proper anchoring and can be used to
check that things don't scroll or that selection and focus handling
properly works.

For comparison purposes, a ListBox is provided next to it.
2019-12-15 21:10:28 +01:00
Benjamin Otte
15dce5c26c listview: Implement GtkScrollable
Scrolling in a very basic form is also supported
2019-12-15 21:10:28 +01:00
Benjamin Otte
742dfd919d listview: Make widget actually do something
The thing we're actually doing is create and maintain a widget for every
row. That's it.

Also add a testcase using this. The testcase quickly allocates too many
rows though and then becomes unresponsive though. You have been warned.
2019-12-15 21:10:28 +01:00
Benjamin Otte
b5e54c1e7d listview: Introduce GtkListItemFactory
Thisis the abstraction I intend to use for creating widgets and binding
them to the item out of the listview.

For now this is a very dumb wrapper around the functions that exist in
the API.

But it leaves the freedom to turn this into public API, make an
interface out of it and most of all write different implementations, in
particular one that uses GtkBuilder.
2019-12-15 21:10:28 +01:00
Benjamin Otte
9756330b75 gtk: Add a GtkListView skeleton 2019-12-15 21:10:28 +01:00
Benjamin Otte
8126b24a78 builder: Add <binding> tag
The tag contains an expression that it then gtk_expression_bind()s to
the object it is contained in.
2019-12-15 21:10:28 +01:00
Benjamin Otte
9520a04d26 builder: Allow text content in <lookup>
<lookup>foo</lookup>
is now short for
  <lookup>
    <constant>foo</constant>
  </lookup>
ie it looks up the object with the given name so it can then do a
property lookup with it.

This is the most common operation, so it's a nice shortcut.
2019-12-15 21:10:28 +01:00
Benjamin Otte
aa1d21a7ae builder: Allow <constant> without a type
A constant without a type is assumed to be an object. This is the most
common case and allows
  <constant>foo</constant>
without requiring updates to the type whenever the foo object changes.
2019-12-15 21:10:28 +01:00
Benjamin Otte
1c354586d0 builder: Make <lookup> type optional
If no type is set, use the type of the expression.
2019-12-15 21:10:28 +01:00
Benjamin Otte
90277fba71 gtk-demo: Make fishbowl info text use bindings
It's a good demo for how bindings can format multiple properties into an
informative string with 1 line of code (and 5 lines of XML).
2019-12-15 21:10:28 +01:00
Matthias Clasen
830939d8c7 sorter: Add tests
Some basic tests for GtkSorter.
2019-12-15 21:10:28 +01:00
Benjamin Otte
900616ec7a sortlistmodel: Make sort stable
The sort of the sortlistmodel is now stable with respect to the original
list model.

That means that if the sorter compares items as equal, the model
will make sure those items keep the order they were in in the original
model.

Or in other words: The model guarantees a total order based on the
item's position in the original model.
2019-12-15 21:10:28 +01:00
Benjamin Otte
2c047aa76f sortlistmodel: Redo the way we store the items
We need to keep this data around for changes in future commits where we
make the sorting stable.

An important part of the new data handling is that the unsorted list
needs to always be dealt with before the sorted list - upon creation we
rely on the unsorted iter and upon destruction, the sorted sequence
frees the entry leaving the unsorted sequence pointer invalid.

This change does not do any behavioral changes.
2019-12-15 21:10:28 +01:00
Matthias Clasen
c1071d8c5d Redo sort list model with GtkSorter
Reshuffle the api to take full advantage
of GtkSorter. Update all callers.
2019-12-15 21:10:28 +01:00
Matthias Clasen
7c9ebaef3d Add GtkNumericSorter
This sorter compares numbers obtained from items
by evaluating an expression.
2019-12-15 21:10:28 +01:00
Matthias Clasen
90c75c8b9a Add GtkMultiSorter
This is a sorter that tries multiple sorters in turn.
2019-12-15 21:10:28 +01:00
Matthias Clasen
3c96f65094 Add GtkStringSorter
This is a GtkSorter implementation collating strings
2019-12-15 21:10:28 +01:00
Matthias Clasen
06fbc82ddf Add GtkCustomSorter
This is a GtkSorter implementation which uses a GCompareDataFunc.
2019-12-15 21:10:28 +01:00
Matthias Clasen
575b42c481 Add GtkSorter
This is a helper object for sorting, similar to GtkFilter.
2019-12-15 21:10:28 +01:00
Benjamin Otte
10631c979d Add GtkOrdering
This is an enum that we're gonna use soon and it's worth introducing as a
separate commit.

The intention is to have meaningful names for return values in
comparison functions.
2019-12-15 21:10:28 +01:00
Matthias Clasen
c4ce8ef60f More expression tests
Test type mismatches, and the this pointer
during evaluation.
2019-12-15 21:10:28 +01:00
Benjamin Otte
04df027567 expression: Invalidate bindings before destroying them
Use a weak ref to invalidate bindings. Make sure that this happens
before creating any watches, so that notifies from the
watched expression about changes will not trigger set_property() calls
during dispose()/finalize().

Invalidating also ensures that the watches aren't removed, which can
trigger warnings if the watches are watching the object itself, and the
weak refs cannot be removed anymore.
2019-12-15 21:10:28 +01:00
Benjamin Otte
fc0751a909 expression: Add gtk_expression_bind()
Add a simple way to bind expressions to object properties. This is
essentially the thing to replace g_object_bind_property().
2019-12-15 21:10:28 +01:00
Benjamin Otte
03815102d5 testsuite: Add expression tests 2019-12-15 21:10:28 +01:00
Benjamin Otte
e8613aab9c expression: Add the ability to watch an expression 2019-12-15 21:10:28 +01:00
Benjamin Otte
b603f472ab builder: Add support for parsing expressions 2019-12-15 21:10:28 +01:00
Benjamin Otte
b4b6be9f6e filter: Add tests
Some basic tests for GtkFilter
2019-12-15 21:10:28 +01:00
Benjamin Otte
bb12d3d8ca Add GtkMultiFilter, GtkAnyFilter, GtkEveryFilter
GtkMultiFilter is the abstract base class for managing multiple child
filter.
GtkAnyFilter and GtkEveryFilter are the actual implementations.
2019-12-15 21:10:28 +01:00
Benjamin Otte
52e385672a filter: Add GtkStringFilter
Users provide a search filter and an expression that evaluates the items
to a string and then the filter goes and matches those strings to the
search term.
2019-12-15 21:10:28 +01:00
Benjamin Otte
ca2ebaf90f expression: Make property expression allow subexpressions 2019-12-15 21:10:28 +01:00
Benjamin Otte
46c042ed06 expression: Add GtkObjectExpression
Weak refs break cycles...
2019-12-15 21:10:27 +01:00
Benjamin Otte
e462a2bdcc Add GtkExpression
GtkExpressions allow looking up values from objects.

There are a few simple expressions, but the main one is the closure
expression that just calls a user-provided closure.
2019-12-15 21:10:27 +01:00
Benjamin Otte
bb59b48871 filterlistmodel: Rewrite to use GtkFilter 2019-12-15 21:10:27 +01:00
Benjamin Otte
da413fa72d tests: Remove testtreemodel test
testlistview does everything this test does.
2019-12-15 21:10:27 +01:00
Benjamin Otte
75556a3485 Add GtkCustomFilter 2019-12-15 21:10:27 +01:00
Benjamin Otte
53401e5d89 Add GtkFilter 2019-12-15 21:10:27 +01:00
Benjamin Otte
56838cab86 Add GtkDirectoryList
Adds a new listmodel called GtkDirectoryList that lists the children of
a GFile as GFileInfos.

This is supposed to be used by the filechooser.
2019-12-15 21:10:27 +01:00
Benjamin Otte
0a551b9b2a gdk: Add GDK_DECLARE_EXPORTED_TYPE()
This is like G_DECLARE_FINAL_TYPE(), except it doesn't make the class
struct public, so internally all the subclassing in the world can
happen.

Some subtle differences:
- It marks the get_type() function as G_GNUC_CONST
- It doesn't require the parent type
- It uses G_DEFINE_AUTOPTR_CLEANUP_FUNC() instead of the private glib
  chainup method.

Port a bunch of GDK and the whole event controller + gesture machinery
to provew that it works.

As a side effect, we gained a bunch of missing autocleanups.
2019-12-15 21:10:27 +01:00
Benjamin Otte
ed24f93fb9 popover: Remove unneeded vfunc
The vfunc is identical to the GtkWidget implementation it replaces. So
just keep using that one.
2019-12-15 21:07:54 +01:00
Benjamin Otte
c4043a8eef treelistmodel: Improve docs
- Move into its own section
- Split GtkTreeListRow into its own document

Trees are weird with listmodels and they deserve their own treatment,
they shouldn't be mushed up with the rest of the list machinery.
2019-12-15 21:07:54 +01:00
Benjamin Otte
dff86c0e12 eventcontrollermotion: Add getters for the properties
... and use them.

Also, rename them from is/contains-pointer-focus to is/contains-pointer,
that's clear enough and not too long.

Finally, adapt the semantics of contains-pointer to mirror
GtkEventControllerKey::contains-focus. If is-pointer is set, so is
contains-pointer, they are not exclusive.
Which is what all users of this property wanted, too.
2019-12-15 21:07:54 +01:00
Matthias Clasen
9a5ec33d61 Merge branch 'fix-x11-cursor-crash' into 'master'
x11: Only update cursors if we have any

Closes #2308

See merge request GNOME/gtk!1249
2019-12-13 20:02:43 +00:00
Matthias Clasen
78227bf5b0 Merge branch 'matthiasc/for-master' into 'master'
some builder-tool improvements

See merge request GNOME/gtk!1248
2019-12-13 19:58:53 +00:00
Matthias Clasen
bf2c29a36a x11: Only update cursors if we have any
We were accessing an on-demand created hash table
without checking if it had been created first.

Fixes: https://gitlab.gnome.org/GNOME/gtk/issues/2308
2019-12-13 14:46:00 -05:00
Matthias Clasen
47285c6642 builder: Improve type name mangling
When looking for the get_type function for GThemedIcon,
try both g_themed_icon_get_type and gthemed_icon_get_type
The former is what gio has, the latter is still supported
to avoid breaking gweather_location_get_type.

Update tests to cover this new case.
2019-12-13 14:21:44 -05:00
Matthias Clasen
e4fb4116fd builder-tool: Don't try to find default boxed values
This doesn't work and yields an ugly, unnecessary
error message.
2019-12-13 14:21:44 -05:00
Matthias Clasen
6d3373cb2c gtk-builder-tool: More helpful error messages
Include line numbers in the error messages we
report, so it is possible to find the error.
2019-12-13 14:21:44 -05:00
Marek Kasik
6ddc214e68 printing: Fill device URI for non-Avahi printers
Device URI was not filled for non-Avahi printers by my previous commit.
I've added it back. It was a mistake during rebasing of the patch
to current master.
2019-12-13 17:53:14 +01:00
Matthias Clasen
91a802a1e5 Merge branch '1509-don-t-show-Rejecting-Jobs-when-we-don-t-know' into 'master'
Fix getting info for standalone IPP printers

Closes #1509

See merge request GNOME/gtk!1247
2019-12-13 16:13:17 +00:00
Daniel Mustieles
886ab54eda Updated Spanish translation 2019-12-13 12:24:36 +01:00
Matthias Clasen
4470e5bc93 gtk-demo: Some touchups
Make the theming style classes demo look a bit less odd.
2019-12-12 18:46:53 -05:00
Matthias Clasen
9bbacd3e4c Run gtk-builder-tool simplify over our ui files
This was done mainly to verify that the tool does not
make any unwarranted changes. The changes included here
are all cosmetic.
2019-12-12 18:37:39 -05:00
Matthias Clasen
353df67c0b Add GtkNative to the docs
It was not included in the generated docs.
2019-12-12 18:21:16 -05:00
Matthias Clasen
050eb9ba73 Fix up GtkBuilderScope docs
They were not hooked into the document generation.
2019-12-12 18:18:49 -05:00
Matthias Clasen
4fa5f5497a builder: Another small docs fix 2019-12-12 17:59:24 -05:00
Matthias Clasen
21a032b783 docs: Ignore more private headers 2019-12-12 17:59:24 -05:00
Matthias Clasen
207efd8932 docs: Remove symbols that no longer exist 2019-12-12 17:59:24 -05:00
Matthias Clasen
43c943e48a Merge branch 'issue-179' into 'master'
Use a separate gesture for middle clicks on PlaceView rows

Closes #179

See merge request GNOME/gtk!1199
2019-12-12 22:53:36 +00:00
Matthias Clasen
d6dc5da6db textbuffer: Minor doc fixes
Fix parameter name mismatches.
2019-12-12 17:31:13 -05:00
Matthias Clasen
12d787286e builder: Minor doc fixes
Fix parameter name mismatches.
2019-12-12 17:30:36 -05:00
Matthias Clasen
c33a7670d0 Merge branch 'wip/otte/builder' into 'master'
More builder work

Closes #2267

See merge request GNOME/gtk!1230
2019-12-12 20:36:08 +00:00
Matthias Clasen
bbb56d8216 Merge branch 'file-transfer' into 'master'
clipboard: file transfer portal support

See merge request GNOME/gtk!1244
2019-12-12 19:33:02 +00:00
Matthias Clasen
a20c8af678 clipboard: file transfer portal support
Implement file-list <-> application/vnd.flatpak.file-list
serialization by talking to the file transfer portal.

See https://github.com/flatpak/xdg-desktop-portal/pull/222
2019-12-12 14:25:33 -05:00
Matthias Clasen
0eb2b382a2 Merge branch 'master-gitlab-HC-tooltip' into 'master'
Set HighContrast tooltip back to black text over white background

See merge request GNOME/gtk!1242
2019-12-12 19:18:06 +00:00
Benjamin Otte
101298c54d gtk-demo: Don't include "gtk.h" 2019-12-12 19:50:55 +01:00
Benjamin Otte
f6bdfc32d3 tests: Set an existing font in testfontchooser 2019-12-12 19:50:55 +01:00
Benjamin Otte
5015730212 builder: Turn last dlsym() function into a scope API
Looking up a get_type function by its name is now also part of
GtkBuilderScope.
2019-12-12 19:39:36 +01:00
Benjamin Otte
f8a7f30a0d builder: Add GtkBuilderScope
GtkBuilderScope is an interface that provides the scope that a builder
instance operates in.
It creates closures and resolves types. Language bindings are meant to
use this interface to customize the behavior of builder files, in
particular when instantiating templates.

A default implementation for C is provided via GtkBuilderCScope (to keep
with the awkward naming that glib uses for closures). It is derivable on
purpose so that languages or extensions that extend C can use it.

The reftest code in fact does derive GtkBuilderCScope for its own scope
implementation that implements looking up symbols in modules.

gtk-widget-factory was updated to use the new GtkBuilderCScope to add
its custom callback symbols.
So it does it different from gtk-demo, which uses the normal way of
exporting symbols for dlsym() and thereby makes the 2 demos test the 2
ways GtkBuilder uses for looking up symbols.
2019-12-12 19:39:23 +01:00
Benjamin Otte
1f94028ff7 builder: Add gtk_builder_set_current_object()
Use it as the default object for expression binds and when connecting
signals. It is intended to work kind of as the "this" object while
parsing. In fact, the term "current object" was stolen from the Java
docs and various C++ tutorials for the this pointer.

Set the current object in gtk_widget_init_template() and
GtkListItemBuilder.

This more-or-less replaces the object passed to
gtk_builder_connect_signals() in GTK3.
2019-12-12 19:12:11 +01:00
Benjamin Otte
512c4c13a6 builder: Add gtk_builder_lookup_object()
... and use it. This function looks up an object like
gtk_builder_get_object() but generates an error on failure.

Unlike the evil function _gtk_builder_lookup_object() which also
generates an error but hides it for later lookup.

Use this to avoid continuing applying properties when an error was
encountered.
2019-12-12 19:12:11 +01:00
Benjamin Otte
552db7cb08 types: Move GTK_INVALID_LIST_POSITION here
I have no idea where it should go really - maybe glib?

It certainly shouldn't require everybody including selectionmodel code
just to get at this value.
2019-12-12 19:10:45 +01:00
Matthias Clasen
d564cb2a7e Merge branch 'terminal' into 'master'
imwayland: Suppport terminal purpose

See merge request GNOME/gtk!1243
2019-12-12 17:57:05 +00:00
Marek Kasik
a6e3fc2d2f printing: Fix getting info for standalone IPP printers
Create printer name from name of the advertised service
for standalone IPP printers as opposed to CUPS printers
advertised via Avahi which get name from their
resource path.
This is similar to what cups-filters does.

Pass GtkPrinter class to request for printer info
so that it does not need to be searched for
(such search could fail for standalone IPP printers).

https://gitlab.gnome.org/GNOME/gtk/issues/1509
2019-12-12 17:08:30 +01:00
Marek Kasik
e54049bc26 printing: Don't show Rejecting Jobs when we don't know
Set reasonable default values for printers discovered
by Avahi which do not have 'printer-type' attribute.
This is the case for network printers which were not
published by CUPS.

Related to the issue #1509.
2019-12-12 17:08:30 +01:00
Dorota Czaplejewicz
e331b39ca5 imwayland: Suppport terminal purpose 2019-12-12 14:37:51 +00:00
Jonathan Michalon
e6270ca43f Set HighContrast tooltip back to black text over white background
8abdbfee16 pulled Adwaita tooltip selectors,
but in the meantime the colors were also set to Adwaita's. Push back the same
behaviour as before because it's better for visually-impaired users.
2019-12-12 09:51:40 +01:00
Christoph Reiter
88da95d921 Merge branch 'honor-hotspot-gtk4' into 'master'
gdk/x11: Honor hotspot during drag cancel animation

See merge request GNOME/gtk!1236
2019-12-11 12:59:23 +00:00
Chun-wei Fan
44f9c67466 Merge branch 'vulkan-no-layered-windows' into 'master'
Win32: Do not enable layered windows when using Vulkan

See merge request GNOME/gtk!1217
2019-12-11 06:24:49 +00:00
Matthias Clasen
02bbe399df Merge branch 'matthiasc/for-master' into 'master'
widget factory: Fix more grid layout fallout

See merge request GNOME/gtk!1237
2019-12-10 03:05:09 +00:00
Matthias Clasen
41bb40feee widget factory: Fix more grid layout fallout 2019-12-09 21:29:03 -05:00
Benjamin Otte
336d652be5 a11y: We can peek here
Avoids instantiating a11y objects when we don't need to.
2019-12-09 16:35:41 +01:00
Benjamin Otte
d3e8678955 treeview: Don't create a cyclic reference
TreeRowReference refs the proxy object, so don't use proxies.
2019-12-09 16:35:41 +01:00
Benjamin Otte
503d988c1b label: Compute label baselines correctly
When we were switching smallest and widest, we were not switching the
baselines.
2019-12-09 16:35:41 +01:00
Robert Mader
7a46378e71 gdk/x11: Honor hotspot during drag cancel animation
Otherwise the icon "jumps" to the cursor position with its top left when
the animation starts.
This is especially visible if the dragged item is big, like when dragging
mails in Thunderbird.
2019-12-09 01:45:30 +01:00
Matthias Clasen
9f6d12551f Add GtkTreeListRow type to the docs 2019-12-08 17:58:09 -05:00
Matthias Clasen
43c93d6f85 Add missing listmodel and selection types to the docs 2019-12-08 13:56:47 -05:00
Matthias Clasen
d683d085c0 tree list model: Add a missing annotation
The GtkTreeListModelCreateModelFunc returns
a new reference.
2019-12-08 00:30:32 -05:00
Matthias Clasen
92ab450983 inspector: Avoid critical warnings
We were still using this but it's not defined in the UI xml.

Fixes: https://gitlab.gnome.org/GNOME/gtk/issues/2295
2019-12-07 19:39:02 -05:00
Matthias Clasen
7b14c65b41 Merge branch 'inspector-display' into 'master'
Inspector display

See merge request GNOME/gtk!1234
2019-12-07 23:20:51 +00:00
Matthias Clasen
c89c652401 inspector: Make the css tree respect inspected display
The display is used here to force reparsing the theme
on the right settings object.
2019-12-07 18:07:44 -05:00
Matthias Clasen
f0f57d156b inspector: Make logs respect inspected display 2019-12-07 18:07:05 -05:00
Matthias Clasen
cecf4f2763 inspector: Make inspect button use inspected display
This may not matter, but just for cleanliness.
2019-12-07 18:07:05 -05:00
Matthias Clasen
4eeed47c7b inspector: Make general respect inspected display 2019-12-07 18:07:05 -05:00
Matthias Clasen
bd1f7e057a inspector: Make visual settings respect the inspected display
This is not quite complete, GTK and GSK debug flags
are not per display, and slowdown and text direction
are not either.
2019-12-07 18:07:05 -05:00
Matthias Clasen
174d8b72a5 inspector: Make css editor respect inspected display
Stop using gdk_display_get_default and use the
inspected display instead.
2019-12-07 18:07:05 -05:00
Matthias Clasen
1437b0856c inspector: Make object tree respect inspected display
Stop using gdk_display_get_dfault and use the
inspected display instead.
2019-12-07 14:59:49 -05:00
Matthias Clasen
917181cb67 window: Get rid of the inspector_window static
Use the new per-display inspector plumbing and
stop relying on a static variable.
2019-12-07 14:59:49 -05:00
Matthias Clasen
a207a4b3cd inspector: Attach inspector window to display
Give the inspector window a ::inspected-display
property, and pass a display when obtaining an
inspector window. Update the caller.
2019-12-07 14:59:49 -05:00
Matthias Clasen
39a1d27960 window: Inspector cleanups
Reduce the use of the inspector_window static.
The goal is to have one inspector window per
display, so we need to get rid of the static.
2019-12-07 14:59:49 -05:00
Matthias Clasen
5ef4a64084 window: Remove inspector updating fully
Commit 05e752e096 left some ruins behind.
Clean that up.
2019-12-07 14:59:49 -05:00
Matthias Clasen
baacd9efbf inspector: Init yourself
No need to have GTK call this from the outside.
2019-12-07 14:59:49 -05:00
Matthias Clasen
abde37a4d7 inspector: Cleanup
Remove an unused enum.
2019-12-07 14:59:49 -05:00
Matthias Clasen
3ee9b0cf4b Make a test with a custom display
This completely breaks the inspector.
2019-12-07 10:03:42 -05:00
Matthias Clasen
88049915a2 Merge branch 'doc-update' into 'master'
doc: Cleanup doc removing mentions of gdk_surface_shape_combine_region()

See merge request GNOME/gtk!1232
2019-12-05 22:11:31 +00:00
Hubert Figuière
585397937d doc: Cleanup doc removing mentions of gdk_surface_shape_combine_region() 2019-12-05 11:33:09 -05:00
Matthias Clasen
256b6f1aff Merge branch 'matthiasc/for-master' into 'master'
fix leaks in the testsuite

See merge request GNOME/gtk!1231
2019-12-05 00:01:23 +00:00
Matthias Clasen
acabdafb35 Fix treelistmodel tests
They were failing to return a reference where they
need to. This was uncovered by fixing an unrelated
ref leak.
2019-12-04 18:30:37 -05:00
Matthias Clasen
168c1f440d Fix leaks in tests
All the list model tests were leaking items,
because g_list_model_get_item is transfer full.

Fixing these unveils a crash in the treelistmodel
and maplistmodel tests.
2019-12-04 18:24:56 -05:00
Tim Sabsch
33a8ef4bce Update German translation 2019-12-04 19:37:01 +00:00
Benjamin Otte
33bd8f322c builder: Improve error message 2019-12-03 18:12:25 +01:00
Benjamin Otte
bfe4255807 builder: Allow objects in gtk_builder_value_from_string_type()
Instead of throwing an error, lookup objects with
gtk_builder_get_object().
2019-12-03 18:12:25 +01:00
Benjamin Otte
a15fb95c46 gtk-demo: Use normal way to lookup up symbols
We're a normal application, so we can use the normal way to hook up code
into builder files, which is using dlsym() for the function pointers.

There's no need to to extra work exporting static symbols.
2019-12-03 18:12:25 +01:00
Benjamin Otte
292371932b css: Handle invalid :not() selectors
We weren't correctly ending the ( ) block when encountering an error.

Testcases added.

Fixes #2281
2019-12-03 18:12:25 +01:00
Timm Bäder
564e8f483c Merge branch 'wip/wayland-hidpi-swap-region' into 'master'
Fix HiDPI swap regions on Wayland

See merge request GNOME/gtk!1228
2019-12-03 16:05:08 +00:00
Jonas Ådahl
ba74f41a70 wayland/vulkancontext: Fix present region on HiDPI
VkPresentRegionsKHR is expected to operate in buffer coordinates, but
the region we get passed is in surface coordinates, so it must be scaled.
2019-12-03 16:45:37 +01:00
Jonas Ådahl
d6a6313493 wayland/glcontext: Fix damage region on HiDPI
The passed regions are in surface coordinates, but
eglSwapBuffersWithDamage() is in buffer coordinates.
2019-12-03 16:45:37 +01:00
Emmanuele Bassi
9b5a7ae802 Merge branch 'fix-treemodelsort_processed_as_treemodel' into 'master'
Annotate GtkTreeModelSort.new_with_model() appropriately

See merge request GNOME/gtk!1134
2019-12-03 15:36:43 +00:00
LutzLue
e4b8481dd0 Annotate GtkTreeModelSort.new_with_model() appropriately
The new_with_model() method is a constructor, and it returns a GtkTreeModelSort
instance, even if the C API returns a GtkTreeModel for the convenience of C
developers.

Fixes: #1077
2019-12-03 15:36:42 +00:00
Timm Bäder
d868b23c76 gl renderer: Implement blurred inset shadow nodes
And with this...

Fixes #1101
2019-12-03 08:40:35 +01:00
Timm Bäder
56b456ff21 gl renderer: Remove unused uniform from inset shadow shader 2019-12-03 08:40:35 +01:00
Timm Bäder
b91913d10d opbuffer: Remove unused op member 2019-12-03 08:40:35 +01:00
Timm Bäder
ac1497eb2d testsuite: Add an inset shadow rendering test case 2019-12-03 08:40:35 +01:00
Timm Bäder
1854f3f49c gl renderer: Cache current scale in RenderOpBuilder
We call ops_get_scale a lot, so this should be better. It will also make
a later x/y split for the scaling easier.
2019-12-03 08:40:34 +01:00
Timm Bäder
a75523da68 cssshadowvalue: Simplify inset shadow nodes to color nodes if possible
inset shadows like this are frequently used to implement highlights in
CSS without crowing them min size of the element.
2019-12-03 08:40:34 +01:00
Timm Bäder
ca66e9788c gl renderer: Save one level of indentation 2019-12-03 08:40:34 +01:00
Timm Bäder
83ec7d562a window: Don't set invalid csd input shape
This might happen if the CSS values of the decoration node are broken,
e.g. if people *accidentally* type large negative values for the
margins.

Fixes #2268
2019-12-03 08:40:34 +01:00
Timm Bäder
05e9a9b572 snapshot: Reorder color matrix nodes containing a transform node
A color matrix node that contains a transform node can also be expressed
the other way around, as a transform node containing a color matrix
node.

In the general case, the color matrix node will have to draw its
child to a texture so it can color every pixel of that texture, but the
renderers can short-cut this if the child of the color matrix node is
already a texture node. So if we have a node tree like

Color Matrix
    - Transform
        - Texture

The renderer would have to either check the grandchild of the color
matrix or simply fall back to rendering the transform node to a texture.

In the new configuration:

Transform
    - Color Matrix
        - Texture

The renderer can easily see that the child node of the color matrix node
is a texture, and skip rendering it to a texture.

This is for example happening in current Adwaita for spinners, which are
rotated symbolics.
2019-12-03 08:40:34 +01:00
Timm Bäder
bc7b37d307 snapshot: Factor out color matrix merging
We will use that elsewhere in the next commit.
2019-12-03 08:40:34 +01:00
Timm Bäder
fb5dc73841 gl renderer: Implement blurred shadow nodes 2019-12-03 08:40:34 +01:00
Timm Bäder
8d61d9f627 gl renderer: Take a TextureRegion in blur_texture
So we can refer to textures on a texture atlas.
2019-12-03 08:40:34 +01:00
Timm Bäder
22b6085c32 gl renderer: Scale blur radius
We scale the texture size, so as a consequence we have to scale the blur
radius.
2019-12-03 08:40:34 +01:00
Timm Bäder
2deb1a05a0 gl renderer: Add some often needed debug code 2019-12-03 08:40:34 +01:00
Timm Bäder
8ca46169b1 gl renderer: Blur shader improvements
Use a two-pass blur shader, fix a few other things and unify the
blurring of blur nodes and blurred outset shadow nodes.

Related to #1283
2019-12-03 08:40:34 +01:00
Timm Bäder
642ced0cfc testblur: Fix default blur radius
sync it up with the adjustment value. also just add the destroyed
handler.
2019-12-03 08:40:34 +01:00
Matthias Clasen
a635076106 Merge branch 'improve-popover-menu-style' into 'master'
Adwaita: Improve popover.menu styling

See merge request GNOME/gtk!1083
2019-12-02 13:19:50 +00:00
nana-4
23d8aa40fe Adwaita: Remove unused popover check/radio styling 2019-12-02 20:48:10 +09:00
nana-4
0933630ee5 Adwaita: Flatten circular buttons in popover.menu
Just reuse the list button style.

https://gitlab.gnome.org/GNOME/gtk/issues/1824
2019-12-02 20:48:09 +09:00
nana-4
797cecd9ae Adwaita: Make check & radio symbolic icon style in popover.menu
The disabled modelbutton color needs to be specified explicitly
in order for check & radio to properly read the color with
currentColor.

https://gitlab.gnome.org/GNOME/gtk/issues/1824
2019-12-02 20:48:09 +09:00
nana-4
4c2707916c Adwaita: Improve popover.menu styling
Based on the mockup:
https://gitlab.gnome.org/Teams/Design/os-mockups/blob/master/menus/menu-design-patterns.png

- Remove horizontal padding from popover.menu contents
- Remove roundness from modelbutton
- Adjust sizing to match the mockup
- Fix visual glitches on button.image-button.model
- Add missing mergin to arrow icons
- Fix accelerator position in rtl direction
- Fix accelerator color

https://gitlab.gnome.org/GNOME/gtk/issues/1824
2019-12-02 20:48:09 +09:00
Matthias Clasen
ab32b1bba2 Merge branch 'wip/muktupavels/opaque-region-master' into 'master'
window: fix opaque region

See merge request GNOME/gtk!1222
2019-12-01 15:11:00 +00:00
Matthias Clasen
619c892032 Merge branch 'sass-no-extend-compound-master' into 'master'
themes: remove various @extend with compound selectors

See merge request GNOME/gtk!1223
2019-12-01 15:09:39 +00:00
nana-4
87ea0253aa themes: remove various @extend with compound selectors
They are no longer supported by sass and broken with libsass 3.6.3
(https://github.com/sass/libsass/issues/3033)

This removes them by replacing them with a placeholder selector. This at
least brings the resulting CSS size down a bit so gtk can be build
again.

`%button.flat.suggested-action` has been replaced by
`%selection_mode_button_flat`, which is a more appropriate selector for
`.selection-mode button.titlebutton`.

The CSS was generated with libsass 3.5.5.

Co-authored-by: Christoph Reiter <reiter.christoph@gmail.com>

See https://gitlab.gnome.org/GNOME/gtk/issues/2237
2019-12-01 10:43:16 +09:00
Alberts Muktupāvels
e81a90c432 window: fix opaque region
Decoration node for drawing is used only for client side decorated
windows, but corners from opaque region is subtracted also for
normal windows.

Rename function to better reflect what it does and do not subtract
corners if decoration node was not used for drawing.
2019-11-30 20:19:26 +02:00
Timm Bäder
fe385c28f6 Merge branch 'gtk-link-color' into 'master'
Adwaita: always use link specific colors for link selector

See merge request GNOME/gtk!1201
2019-11-30 07:40:48 +00:00
Matthias Clasen
6c4ab7d208 Merge branch 'matthiasc/for-master' into 'master'
some builder-tool tests

See merge request GNOME/gtk!1220
2019-11-29 15:21:40 +00:00
Matthias Clasen
dd52dd8bb0 Update the test scripts
All tools got renamed to have a gtk4 prefix.
2019-11-29 10:06:39 -05:00
Matthias Clasen
174cdb09a7 Add a test for the previous fix 2019-11-29 10:04:59 -05:00
Matthias Clasen
c3ca34cf51 Merge branch 'matthiasc/for-master' into 'master'
builder-tool: Fix handling of layout properties

See merge request GNOME/gtk!1219
2019-11-29 14:00:05 +00:00
Matthias Clasen
85950afbbd builder-tool: Fix handling of layout properties
We were not properly identifying layout properties
that need to be kept, causing GtkGrid left-attachment
to go missing in widget-factory.ui.
2019-11-29 08:47:35 -05:00
Matthias Clasen
da063a8aa5 Fix up widget-factory ui 2019-11-29 08:34:09 -05:00
Timm Bäder
9d94627f75 Merge branch 'dont-color-labels-directly-gtk4' into 'master'
Adwaita: Avoid directly coloring labels wherever possible (GTK4)

Closes #1643

See merge request GNOME/gtk!1209
2019-11-29 11:53:07 +00:00
Timm Bäder
5bdd25627f reftests: Fix css-multi-state test
Properly unset theme CSS and use the right selector for the toggle
buttons.
2019-11-29 20:26:45 +09:00
Carlo Lobrano
7bb8a480f1 Adwaita: always use link specific colors for link selector
link target uses `$selected_bg_color` and `$selected_fg_color` for the
definition of some selectors (e.g. selected).

While `$link_color` and `$link_visited_color` are based on
`$selected_bg_color`, this does not seem coherent.

Replacing `$selected_*g_color` in link target style with link colors
defined in `_colors.scss file`.
2019-11-29 07:32:16 +01:00
Matthias Clasen
be74be0e3b widget-factory: Fix a popover menu
This one is manually constructed, and things have
changed enough for that to break. Fix it up.
2019-11-27 17:41:44 -05:00
Timm Bäder
982890515d gl renderer: Don't use g_assert() for code that should always run
g_assert can be compiled out.
2019-11-27 16:56:47 +01:00
Timm Bäder
1817025f46 gl renderer: Don't save repeat nodes to disk
This is just debuggin code someone forgot.
2019-11-27 16:47:14 +01:00
Matthias Clasen
c5d24fc5cd Merge branch 'single-compilation-symbol' into 'master'
Use a single compilation symbol

See merge request GNOME/gtk!1216
2019-11-27 15:14:54 +00:00
Timm Bäder
965e37bee9 Merge branch 'fix-issue-1646-master' into 'master'
HighContrast: Add missing color to entry

Closes #1646

See merge request GNOME/gtk!1215
2019-11-27 13:52:08 +00:00
Emmanuele Bassi
def700739d Use a single compilation symbol
We use a compilation symbol in our build to allow the inclusion of
specific headers while building GTK, to avoid the need to include only
the global header.

Each namespace has its own compilation symbol because we used to have
different libraries, and strict symbol visibility between libraries;
now that we have a single library, and we can use private symbols across
namespaces while building GTK, we should have a single compilation
symbol, and simplify the build rules.
2019-11-27 13:33:43 +00:00
nana-4
5590bcb9cc HighContrast: Add missing color to entry
So entries don't inherit color from the parent element anymore.

Fixes https://gitlab.gnome.org/GNOME/gtk/issues/1646
2019-11-27 22:22:11 +09:00
Timm Bäder
9f69c7f3e8 Merge branch 'broken-annotation' into 'master'
builder: Fix broken annotation

See merge request GNOME/gtk!1213
2019-11-27 06:46:15 +00:00
Robert Ancell
0df45f0de0 builder: Fix broken annotation
Missing a ':', was introduced in 0627bba5a0.
2019-11-27 16:06:36 +13:00
Chun-wei Fan
9c5ea8eba4 gdkvulkancontext-win32.c: Suppress layered Windows on Vulkan
The Vulkan renderer does not work well with layered windows enabled, so
turn it off when we successfully created the Vulkan context on Windows.
2019-11-26 17:00:11 +08:00
Timm Bäder
8f6de1f955 gl renderer: Load flipped-y offscreen vertex data directly
Instead of loading the unflipped version first and then flipping it.
Don't do it in add_render_ops either but only in the function actually
adding the render ops for the nodes, since those frequently have
early-out conditions that don't need the vertex data at all.
2019-11-26 09:09:25 +01:00
Timm Bäder
4f532224e0 testsuite: Add another repeat node test case 2019-11-26 09:09:25 +01:00
Timm Bäder
1c2661ed12 gl renderer: Fix repeat node shader once again 2019-11-26 09:09:25 +01:00
Timm Bäder
91f7ac2d58 gl renderer: Care more about 0×0 offscreen nodes
These never result in a rendering of course, but we must make sure not
to create a 0×0 texture for them, since that will cause problems later
on.
2019-11-26 09:09:25 +01:00
Timm Bäder
3d1a9c7484 Merge branch 'unsafe-strdup-printf' into 'master'
gtk-demo: Fix incorrect use of g_strdup_printf

See merge request GNOME/gtk!1211
2019-11-26 07:11:19 +00:00
Robert Ancell
25e4174a38 gtk-demo: Fix incorrect use of g_strdup_printf
Was broken in a refactoring in 4a2f313
2019-11-26 10:11:28 +13:00
Emmanuele Bassi
04bb5aad36 Use a separate gesture for middle clicks on PlaceView rows
The click gesture in GtkListBox is exclusively for primary button
clicks; this means we're never going to get a click from the middle
button. We need to use a separate GtkGestureClick controller for middle
clicks, in order to activate rows with the 'open-in-tab' flag.

Fixes: #179
2019-11-25 16:02:40 +00:00
nana-4
4f82a0de89 Adwaita: Avoid directly coloring labels wherever possible
Directly coloring labels can create a lot of unintended behaviors.
Unfortunately we can't avoid directly coloring `label:disabled` because
it can be used individually. This, however, tries to inherit color from
the parent element of labels wherever possible.

Fixes https://gitlab.gnome.org/GNOME/gtk/issues/1643
2019-11-26 00:39:33 +09:00
Benjamin Otte
9e4901e8ce testsuite: Fix expected test output
This reverts part of 91497348bf
2019-11-23 19:33:36 +01:00
Benjamin Otte
7523a3f2f2 cssprovider: Don't add empty rulesets
This change was lost during the parser changes, but the newly added test
exposes it.

And fix the expected error, the syntax has changed.
2019-11-23 19:02:36 +01:00
Alexandr Miloslavskiy
fd1630e049 Fix crash in parse_border()
The bug was introduced in commit:
	9b7640b8 by Benjamin Otte, 2012-03-26 17:24:02
	styleproperty: Make _gtk_style_property_parse_value() return a CssValue

In that commit, `values` changed from `GValue*` to `GtkCssValue**`,
but one `!G_IS_VALUE (&values[8])` was left untouched. As a result,
if `border` shorthand contains anything after color, it might crash,
depending on memory layout.

New test included.

Fixes: #751
2019-11-23 18:15:19 +01:00
Benjamin Otte
e3c3cbbbcb Merge branch 'wip/otte/builder' into 'master'
Reorganize various GtkBuilder things

See merge request GNOME/gtk!1204
2019-11-23 17:09:15 +00:00
Benjamin Otte
4fbb0d7ce4 builder: Make the struct private
We don't want anyone to subclass it - if we want to allow bindings to
extend GtkBuilder, we will be using delegate objects/functions for it.
2019-11-22 17:42:32 +01:00
Benjamin Otte
245fdc8b38 builder: Remove get_type_from_name() vfunc 2019-11-22 17:42:32 +01:00
Benjamin Otte
420169d5cd builder: Improve signal connecting
- Propagate the error back to the parser, so we get a proper GError
  instead of a g_warning().
- Connect closures by id, don't construct a name from the ids so that
  glib can take it apart again.
2019-11-22 17:42:31 +01:00
Benjamin Otte
b025ee428c builder: Connect signals automatically
gtk_builder_connect_signals() is no longer necessary, because all the
setup that made it necessary to have this extra step is now done
automatically via the closure functions.
2019-11-22 17:42:31 +01:00
Benjamin Otte
82395a93b0 reftests: Switch to gtk_builder_set_closure_func() 2019-11-22 17:42:31 +01:00
Benjamin Otte
b7ff017f8d widget: Change templates to use closure functions
... instead of connect functions.
2019-11-22 17:42:31 +01:00
Benjamin Otte
0627bba5a0 builder: Add gtk_builder_set_closure_func()
This allows bindings and templates to setup a way to create closures.
2019-11-22 08:13:16 +01:00
Benjamin Otte
ab53731f4a widget: Reinstate custom closure func
It turns out it ws used in various places.
2019-11-22 07:46:18 +01:00
Benjamin Otte
094c537001 builder: Add gtk_builder_create_closure()
This will be the future way to connect signals automatically (and be
used for other things, too).

For now, gtk_builder_connect_signals_default() is ported to use it.
2019-11-22 07:46:18 +01:00
Benjamin Otte
27d05102ab builder: Remove user_data argument from gtk_builder_connect_signals()
This is pretty unused and gets in the way of the next steps.

A potential side effect is that for templates the widget was passed as
the user data argument. If that turns out to be important, we have to
special case that situation.
2019-11-22 07:46:18 +01:00
Benjamin Otte
f5e4dc824c builder: Remove application setter/getter
It's unused and doesn't belong to GtkBuilder.
2019-11-22 07:46:18 +01:00
Benjamin Otte
80acc8f296 builder: Carry the module as part of the GtkBuilder object
This way, we don't open the module in every place we want to look up
functions.
2019-11-22 07:46:18 +01:00
Benjamin Otte
e3860d25e9 builder: Fix typo in docs 2019-11-22 07:35:03 +01:00
Benjamin Otte
a2634077e7 testsuite: Print useful statement on notify test error
... and don't instantly abort, test the rest of the properties, too.
2019-11-22 07:35:03 +01:00
Benjamin Otte
c72c0f4d43 types: Remove and unused typedef
GtkRcPropertyParser is gone.
2019-11-22 07:35:03 +01:00
Benjamin Otte
d92cfa2179 settings: Remove RC property parsers
They've not been used for a long time and the APIs where they could
reasonably be used have been gone for as long.
2019-11-22 07:35:03 +01:00
Benjamin Otte
bbdaa4a0ff settings: Remove code dealing with property parsers
They only remained in private code where they were always set to NULL.
2019-11-22 07:35:03 +01:00
Sam Hewitt
5e11a2ae6a adwaita: level bar refinements
- shave a few pixels off large level bar
 - thinner discrete level bar
2019-11-19 11:46:18 -05:00
Timm Bäder
053360df85 gl renderer: Remove unused function 2019-11-19 11:06:08 +01:00
Timm Bäder
39a48de025 testsuite: Add a testcase for repeat nodes that don't repeat 2019-11-19 10:45:35 +01:00
Timm Bäder
600ce68210 gl renderer: Add a short cut for repeat nodes that don't repeat
These happen and we don't even need to draw the child to a texture.
2019-11-19 10:45:02 +01:00
Timm Bäder
604f44da11 gl renderer: Fix repeat nodes that don't repeat
Fixes #2234
2019-11-19 10:31:21 +01:00
Timm Bäder
581f5bd749 csstokenizer: Plug a leak 2019-11-19 09:37:45 +01:00
Timm Bäder
ecc40cf115 rendernodeparser: Only report a GError* if we have one 2019-11-19 09:37:26 +01:00
Timm Bäder
3d7817154c rendernodeparser: Handle resolving NULL urls 2019-11-19 09:37:03 +01:00
Emmanuele Bassi
232e313823 docs: Add migration note for iconify → minimize
See commit b70e4f6de9.
2019-11-18 14:12:41 +00:00
Daniel Mustieles
914e2a6656 Updated Spanish translation 2019-11-18 15:08:59 +01:00
Emmanuele Bassi
9a88d17ef2 Merge branch 'gdk-backend-imports' into 'master'
Correct Gdk backend import paths and related gtk-doc

See merge request GNOME/gtk!1197
2019-11-18 10:27:32 +00:00
Andy Holmes
907a86fd93 Correct Gdk backend import paths and related gtk-doc
Correct the paths in the include guard warnings and use the `@Include`
directive for the Gdk backends.
2019-11-18 00:31:38 -08:00
Matthias Clasen
d4180931f8 Merge branch 'seal-popover-menu' into 'master'
Privatize popover menu pieces

See merge request GNOME/gtk!925
2019-11-18 01:57:55 +00:00
Matthias Clasen
dd913423d3 Merge branch 'signal-naming' into 'master'
gtkstyleprovider: Rename -gtk-style-changed signal to have a valid name

See merge request GNOME/gtk!1176
2019-11-18 01:55:34 +00:00
Matthias Clasen
c296101a2f Merge branch 'issue-67' into 'master'
Rename "iconify" to "minimize"

Closes #67

See merge request GNOME/gtk!1190
2019-11-18 00:52:53 +00:00
Emmanuele Bassi
1ba2923616 Merge branch 'meson-bump' into 'master'
Bump up the required version of Meson

See merge request GNOME/gtk!1191
2019-11-16 20:26:31 +00:00
Emmanuele Bassi
1ec4cb7f17 Disable GdkSurface.minimize on Wayland
The existing xdg-shell protocols do not support minimization in a way
that allows us to implement the GdkSurface API; the only minimization
operation does not come with a state notification, nor it comes with
a way to undo itself.

Closes: #67
2019-11-16 20:25:01 +00:00
Emmanuele Bassi
b70e4f6de9 Rename "iconify" to "minimize"
The "iconified" state is mostly an X11-ism; every other platform calls
this state "minimized" because it may not involve turning a window into
an icon at all.
2019-11-16 20:07:37 +00:00
Emmanuele Bassi
3c11c57755 Bump up the required version of Meson
Match the one we're testing on our CI infrastructure.
2019-11-16 18:40:23 +00:00
Emmanuele Bassi
1b7c6e5687 Merge branch 'gdkx-import-doc' into 'master'
Correct GdkX11 import path in docs and include guards

Closes #2254

See merge request GNOME/gtk!1188
2019-11-16 18:19:26 +00:00
Andy Holmes
d32cd210bb Correct GdkX11 import path in docs and include guards
Update the include directives in the documentation, as well as the
include guards in headers, to point to gdk/x11/gdkx.h.

closes #2254
2019-11-16 01:35:09 -08:00
Emmanuele Bassi
e056e4ff58 Merge branch 'fix-menu-check-radio-styling-gtk4' into 'master'
Adwaita: Fix check/radio styling in menu (GTK4)

See merge request GNOME/gtk!1187
2019-11-15 23:26:17 +00:00
Emmanuele Bassi
ae66c07a70 Merge branch 'dont-hardcode-shared-library' into 'master'
build: Don't hardcode shared_library() in meson

See merge request GNOME/gtk!1172
2019-11-15 23:24:42 +00:00
Niklas Hambüchen
3936412332 Try building static libs on CI 2019-11-15 18:42:36 +01:00
nana-4
ea5eeb7c7a Adwaita: Fix check/radio styling in menu
The new check/radio style increased their specificity, but it was not
synchronized in the menu styling.

This commit increases the specificity to match the updated check/radio
styling.

https://gitlab.gnome.org/GNOME/gtk/issues/2096
2019-11-16 01:08:44 +09:00
Philip Withnall
13f4d639fd gtkstyleprovider: Rename -gtk-style-changed signal to have a valid name
Signal names must start with a letter. They can’t start with a hyphen.

It was originally added in commit 74f4c6f6bd with no given reason
for why the signal name was chosen as it was.

Signed-off-by: Philip Withnall <withnall@endlessm.com>
2019-11-12 19:51:33 +00:00
Niklas Hambüchen
bb9c07d8fe build: Don't hardcode shared_library() in meson.
Instead, use the standard library().
This is a meson best practice.

Fixes -Ddefault_library=static not having any effect.
2019-11-11 16:37:46 +01:00
Matthias Clasen
bfa0509f08 Privatize popover menu pieces
Don't allow manual creation of popover menus
anymore. This lets us also make GtkModelButton
private
2019-11-11 12:42:06 +01:00
540 changed files with 124873 additions and 10845 deletions

View File

@@ -12,7 +12,7 @@ stages:
- subprojects/libepoxy/
- subprojects/pango/
fedora-x86_64:
fedora-x86_64: &fedora-x86_64-defaults
image: registry.gitlab.gnome.org/gnome/gtk/master:v7
stage: build
script:
@@ -33,6 +33,11 @@ fedora-x86_64:
key: "$CI_JOB_NAME"
<<: *cache-paths
fedora-x86_64-staticlibs:
variables:
EXTRA_MESON_FLAGS: "-Ddefault_library=both"
<<: *fedora-x86_64-defaults
.mingw-defaults: &mingw-defaults
stage: build
tags:

View File

@@ -17,6 +17,7 @@ meson \
-Dbroadway-backend=true \
-Dvulkan=yes \
--werror \
${EXTRA_MESON_FLAGS:-} \
_build $srcdir
unset CCACHE_DISABLE

View File

@@ -169,6 +169,7 @@ constraint_view_init (ConstraintView *self)
GListModel *guides;
GListModel *children;
GListModel *constraints;
GtkFilter *filter;
manager = gtk_constraint_layout_new ();
gtk_widget_set_layout_manager (GTK_WIDGET (self), manager);
@@ -176,8 +177,12 @@ constraint_view_init (ConstraintView *self)
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);
filter = gtk_custom_filter_new (omit_internal, NULL, NULL);
constraints = (GListModel *)gtk_filter_list_model_new (all_constraints, filter);
g_object_unref (filter);
filter = gtk_custom_filter_new (omit_internal, NULL, NULL);
children = (GListModel *)gtk_filter_list_model_new (all_children, filter);
g_object_unref (filter);
list = g_list_store_new (G_TYPE_LIST_MODEL);
g_list_store_append (list, children);

View File

@@ -184,58 +184,6 @@ max_input (GtkSpinButton *spin_button,
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)
{
@@ -244,16 +192,12 @@ guide_editor_constructed (GObject *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)
{

247
demos/gtk-demo/award.c Normal file
View File

@@ -0,0 +1,247 @@
/*
* Copyright © 2018 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "award.h"
struct _GtkAward
{
GObject parent;
char *explanation;
char *name;
char *title;
GDateTime *granted; /* or NULL if not granted */
};
enum {
PROP_0,
PROP_EXPLANATION,
PROP_NAME,
PROP_TITLE,
PROP_GRANTED,
N_PROPS,
};
static GParamSpec *properties[N_PROPS] = { NULL, };
G_DEFINE_TYPE (GtkAward, gtk_award, G_TYPE_OBJECT)
static void
gtk_award_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkAward *self = GTK_AWARD (object);
switch (prop_id)
{
case PROP_EXPLANATION:
self->explanation = g_value_dup_string (value);
break;
case PROP_NAME:
self->name = g_value_dup_string (value);
break;
case PROP_TITLE:
self->title = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_award_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkAward *self = GTK_AWARD (object);
switch (prop_id)
{
case PROP_EXPLANATION:
g_value_set_string (value, self->explanation);
break;
case PROP_NAME:
g_value_set_string (value, self->name);
break;
case PROP_TITLE:
g_value_set_string (value, self->title);
break;
case PROP_GRANTED:
g_value_set_boxed (value, self->granted);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_award_dispose (GObject *object)
{
GtkAward *self = GTK_AWARD (object);
g_clear_pointer (&self->name, g_free);
g_clear_pointer (&self->title, g_free);
g_clear_pointer (&self->granted, g_date_time_unref);
G_OBJECT_CLASS (gtk_award_parent_class)->dispose (object);
}
static void
gtk_award_class_init (GtkAwardClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
gobject_class->set_property = gtk_award_set_property;
gobject_class->get_property = gtk_award_get_property;
gobject_class->dispose = gtk_award_dispose;
properties[PROP_EXPLANATION] =
g_param_spec_string ("explanation",
"Explanation",
"How to get the title",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
properties[PROP_NAME] =
g_param_spec_string ("name",
"Name",
"internal name of the award",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
properties[PROP_TITLE] =
g_param_spec_string ("title",
"Title",
"user-visible title",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
properties[PROP_GRANTED] =
g_param_spec_boxed ("granted",
"Granted",
"Timestamp the award was granted or NULL if not granted yet",
G_TYPE_DATE_TIME,
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void
gtk_award_init (GtkAward *self)
{
}
GListModel *
gtk_award_get_list (void)
{
static GListModel *list = NULL;
if (list == NULL)
{
GtkBuilder *builder;
g_type_ensure (GTK_TYPE_AWARD);
builder = gtk_builder_new_from_resource ("/awards.ui");
list = G_LIST_MODEL (gtk_builder_get_object (builder, "list"));
g_object_ref (list);
g_object_unref (builder);
}
return g_object_ref (list);
}
const char *
gtk_award_get_name (GtkAward *award)
{
return award->name;
}
const char *
gtk_award_get_title (GtkAward *award)
{
return award->title;
}
GDateTime *
gtk_award_get_granted (GtkAward *award)
{
return award->granted;
}
GtkAward *
award_find (const char *name)
{
GListModel *list;
GtkAward *self;
guint i;
list = gtk_award_get_list ();
g_object_unref (list);
for (i = 0; i < g_list_model_get_n_items (list); i++)
{
self = g_list_model_get_item (list, i);
g_object_unref (self);
if (g_ascii_strcasecmp (name, self->name) == 0)
return self;
}
return NULL;
}
void
award (const char *name)
{
GtkAward *self;
GNotification *notification;
self = award_find (name);
if (self == NULL)
{
g_warning ("Did not find award \"%s\"", name);
return;
}
if (self->granted)
return;
self->granted = g_date_time_new_now_utc ();
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_GRANTED]);
notification = g_notification_new ("You won an award!");
g_notification_set_body (notification, self->title);
g_application_send_notification (g_application_get_default (), NULL, notification);
g_object_unref (notification);
}

18
demos/gtk-demo/award.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef __AWARD_H__
#define __AWARD_H__
#include <gtk/gtk.h>
#define GTK_TYPE_AWARD (gtk_award_get_type ())
G_DECLARE_FINAL_TYPE (GtkAward, gtk_award, GTK, AWARD, GObject)
GListModel * gtk_award_get_list (void);
const char * gtk_award_get_name (GtkAward *award);
const char * gtk_award_get_title (GtkAward *award);
GDateTime * gtk_award_get_granted (GtkAward *award);
void award (const char *name);
#endif /* __AWARD_H__ */

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="gtk40">
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<property name="label" bind-source="GtkListItem" bind-property="position"></property>
<property name="margin">6</property>
</object>
</property>
</template>
</interface>

89
demos/gtk-demo/awards.ui Normal file
View File

@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GListStore" id="list">
<property name="item-type">GtkAward</property>
<child>
<object class="GtkAward">
<property name="name">demo-inspector</property>
<!-- Transformers -->
<property name="title" translatable="yes">You got a high-rise double-pump carburetor.</property>
<property name="explanation" translatable="yes">Launch the inspector</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">demo-start</property>
<!-- The Matrix -->
<property name="title" translatable="yes">After this, there is no turning back.</property>
<property name="explanation" translatable="yes">Start gtk-demo</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">listbox-reshare</property>
<!-- Mean Girls -->
<property name="title" translatable="yes">Trying to make fetch happen</property>
<property name="explanation" translatable="yes">Reshare a tweet</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">listbox-100th-row</property>
<!-- Aladdin -->
<property name="title" translatable="yes">The ever impressive, long contained, often imitated, but never duplicated Genie of the lamp.</property>
<property name="explanation" translatable="yes">Select a 100th row in a list</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">password-best</property>
<!-- Spaceballs -->
<property name="title" translatable="yes">I've got the same combination on my luggage!</property>
<property name="explanation" translatable="yes">Use "12345" as the password</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">password-correct</property>
<!-- Stanley Parable -->
<property name="title" translatable="yes">Night Shark 1-1-5</property>
<property name="explanation" translatable="yes">Correctly enter a password</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">puzzle-give-up</property>
<!-- Pretty Woman -->
<property name="title" translatable="yes">Big Mistake. Big. Huge!</property>
<property name="explanation" translatable="yes">Close the puzzle without finishing it</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">puzzle-solve</property>
<!-- The Incredibles -->
<property name="title" translatable="yes">That was totally wicked!</property>
<property name="explanation" translatable="yes">Solve a puzzle</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">puzzle-solve-animated</property>
<!-- The Phantom Menace -->
<property name="title" translatable="yes">A surprise to be sure but a welcome one.</property>
<property name="explanation" translatable="yes">Solve an animated puzzle</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">puzzle-solve-large</property>
<!-- Portal -->
<property name="title" translatable="yes">Science isn't about WHY. It's about WHY NOT?!</property>
<property name="explanation" translatable="yes">Solve a puzzle with at least 20 pieces</property>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,49 @@
/* Awards
*
* This demo demonstrates how to use lists to show the awards you have collected
* while exploring this demo.
*
*/
#include <gtk/gtk.h>
/* Include the header for accessing the awards */
#include "award.h"
static GtkWidget *window = NULL;
GtkWidget *
do_awardview (GtkWidget *do_widget)
{
if (!window)
{
GtkWidget *sw, *listview;
GListModel *list;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Awards");
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (window), sw);
listview = gtk_list_view_new_with_factory (
gtk_builder_list_item_factory_new_from_resource (NULL, "/awardview/awardlistitem.ui"));
list = gtk_award_get_list ();
gtk_list_view_set_model (GTK_LIST_VIEW (listview), list);
g_object_unref (list);
gtk_list_view_set_show_separators (GTK_LIST_VIEW (listview), TRUE);
gtk_container_add (GTK_CONTAINER (sw), listview);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -59,7 +59,6 @@ do_builder (GtkWidget *do_widget)
builder = gtk_builder_new_from_resource ("/builder/demo.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));

File diff suppressed because it is too large Load Diff

View File

@@ -24,7 +24,6 @@ do_cursors (GtkWidget *do_widget)
GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/cursors/cursors.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));

View File

@@ -1,7 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/">
<file>awards.ui</file>
</gresource>
<gresource prefix="/ui">
<file preprocess="xml-stripblanks">main.ui</file>
<file preprocess="xml-stripblanks">main-listitem.ui</file>
<file preprocess="xml-stripblanks">appmenu.ui</file>
</gresource>
<gresource prefix="/application_demo">
@@ -9,6 +13,9 @@
<file>application.ui</file>
<file>menus.ui</file>
</gresource>
<gresource prefix="/awardview">
<file>awardlistitem.ui</file>
</gresource>
<gresource prefix="/builder">
<file>demo.ui</file>
</gresource>
@@ -111,6 +118,22 @@
<file>gnome-fs-directory.png</file>
<file>gnome-fs-regular.png</file>
</gresource>
<gresource prefix="/listview_filebrowser">
<file>listview_filebrowser.ui</file>
</gresource>
<gresource prefix="/listview_minesweeper">
<file>listview_minesweeper.ui</file>
<file>listview_minesweeper_cell.ui</file>
</gresource>
<gresource prefix="/listview_settings">
<file>listview_settings.ui</file>
</gresource>
<gresource prefix="/listview_weather">
<file compressed="true">listview_weather.txt</file>
</gresource>
<gresource prefix="/listview_colors">
<file compressed="true">color.names.txt</file>
</gresource>
<gresource prefix="/shortcuts">
<file>shortcuts.ui</file>
<file>shortcuts-builder.ui</file>
@@ -147,6 +170,7 @@
</gresource>
<gresource prefix="/sources">
<file>application_demo.c</file>
<file>awardview.c</file>
<file>assistant.c</file>
<file>builder.c</file>
<file>changedisplay.c</file>
@@ -189,6 +213,13 @@
<file>infobar.c</file>
<file>links.c</file>
<file>listbox.c</file>
<file>listview_applauncher.c</file>
<file>listview_colors.c</file>
<file>listview_clocks.c</file>
<file>listview_filebrowser.c</file>
<file>listview_minesweeper.c</file>
<file>listview_settings.c</file>
<file>listview_weather.c</file>
<file>list_store.c</file>
<file>markup.c</file>
<file>menus.c</file>

View File

@@ -122,7 +122,6 @@ do_filtermodel (GtkWidget *do_widget)
GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/filtermodel/filtermodel.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));

View File

@@ -226,8 +226,8 @@ set_widget_type (GtkFishbowl *fishbowl,
}
void
next_button_clicked_cb (GtkButton *source,
gpointer user_data)
fishbowl_next_button_clicked_cb (GtkButton *source,
gpointer user_data)
{
GtkFishbowl *fishbowl = user_data;
int new_index;
@@ -241,8 +241,8 @@ next_button_clicked_cb (GtkButton *source,
}
void
prev_button_clicked_cb (GtkButton *source,
gpointer user_data)
fishbowl_prev_button_clicked_cb (GtkButton *source,
gpointer user_data)
{
GtkFishbowl *fishbowl = user_data;
int new_index;
@@ -256,8 +256,8 @@ prev_button_clicked_cb (GtkButton *source,
}
void
changes_toggled_cb (GtkToggleButton *button,
gpointer user_data)
fishbowl_changes_toggled_cb (GtkToggleButton *button,
gpointer user_data)
{
if (gtk_toggle_button_get_active (button))
gtk_button_set_icon_name (GTK_BUTTON (button), "changes-prevent");
@@ -265,6 +265,14 @@ changes_toggled_cb (GtkToggleButton *button,
gtk_button_set_icon_name (GTK_BUTTON (button), "changes-allow");
}
char *
format_header_cb (GObject *object,
guint count,
double fps)
{
return g_strdup_printf ("%u Icons, %.2f fps", count, fps);
}
GtkWidget *
do_fishbowl (GtkWidget *do_widget)
{
@@ -288,12 +296,6 @@ do_fishbowl (GtkWidget *do_widget)
g_type_ensure (GTK_TYPE_FISHBOWL);
builder = gtk_builder_new_from_resource ("/fishbowl/fishbowl.ui");
gtk_builder_add_callback_symbols (builder,
"next_button_clicked_cb", G_CALLBACK (next_button_clicked_cb),
"prev_button_clicked_cb", G_CALLBACK (prev_button_clicked_cb),
"changes_toggled_cb", G_CALLBACK (changes_toggled_cb),
NULL);
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);

View File

@@ -15,42 +15,32 @@
<child>
<object class="GtkButton">
<property name="icon-name">pan-start-symbolic</property>
<signal name="clicked" handler="prev_button_clicked_cb" object="bowl" swapped="no"/>
<signal name="clicked" handler="fishbowl_prev_button_clicked_cb" object="bowl" swapped="no"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="icon-name">pan-end-symbolic</property>
<signal name="clicked" handler="next_button_clicked_cb" object="bowl" swapped="no"/>
<signal name="clicked" handler="fishbowl_next_button_clicked_cb" object="bowl" swapped="no"/>
</object>
</child>
</object>
</child>
<child type="end">
<object class="GtkLabel">
<property name="label">fps</property>
</object>
</child>
<child type="end">
<object class="GtkLabel">
<property name="label" bind-source="bowl" bind-property="framerate-string"/>
</object>
</child>
<child type="end">
<object class="GtkLabel">
<property name="label">Icons, </property>
</object>
</child>
<child type="end">
<object class="GtkLabel">
<property name="label" bind-source="bowl" bind-property="count"/>
<binding name="label">
<closure type="gchararray" function="format_header_cb">
<lookup name="count">bowl</lookup>
<lookup name="framerate">bowl</lookup>
</closure>
</binding>
</object>
</child>
<child type="end">
<object class="GtkToggleButton" id="changes_allow">
<property name="icon-name">changes-allow</property>
<property name="relief">none</property>
<signal name="notify::active" handler="changes_toggled_cb"/>
<signal name="notify::active" handler="fishbowl_changes_toggled_cb"/>
</object>
</child>
</object>

View File

@@ -4,6 +4,8 @@
* as needed and support sorting and filtering.
*
* The children of a GtkFlowBox are regular widgets
*
* The dataset used here has 665 colors.
*/
#include <gtk/gtk.h>

View File

@@ -13,7 +13,7 @@
<property name="can-focus">1</property>
<property name="receives-default">1</property>
<property name="tooltip-text">Reset</property>
<signal name="clicked" handler="reset" swapped="no"/>
<signal name="clicked" handler="font_features_reset_features" swapped="no"/>
<child>
<object class="GtkImage">
<property name="icon-name">view-refresh-symbolic</property>
@@ -42,7 +42,7 @@
<property name="receives-default">1</property>
<property name="font">Sans 12</property>
<property name="level">family|style|size|variations|features</property>
<signal name="font-set" handler="font_changed" swapped="no"/>
<signal name="font-set" handler="font_features_font_changed" swapped="no"/>
</object>
</child>
<child>
@@ -63,7 +63,7 @@
<object class="GtkComboBox" id="script_lang">
<property name="can-focus">1</property>
<property name="margin-top">10</property>
<signal name="changed" handler="script_changed" swapped="no"/>
<signal name="changed" handler="font_features_script_changed" swapped="no"/>
<child>
<object class="GtkCellRendererText"/>
<attributes>
@@ -137,7 +137,7 @@
Разъяренный чтец эгоистично бьёт пятью жердями шустрого фехтовальщика. Наш банк вчера же выплатил Ф.Я. Эйхгольду комиссию за ценные вещи. Эх, чужак, общий съём цен шляп (юфть) вдрызг! В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!
Τάχιστη αλώπηξ βαφής ψημένη γη, δρασκελίζει υπέρ νωθρού κυνός</property>
<signal name="activate" handler="stop_edit"/>
<signal name="activate" handler="font_features_stop_edit"/>
<property name="valign">start</property>
<property name="width-chars">50</property>
</object>
@@ -181,7 +181,7 @@
<property name="icon-name">document-edit-symbolic</property>
<property name="halign">end</property>
<property name="valign">end</property>
<signal name="toggled" handler="toggle_edit"/>
<signal name="toggled" handler="font_features_toggle_edit"/>
</object>
</child>
</object>

View File

@@ -880,7 +880,7 @@ add_instance (hb_face_t *face,
name_id = hb_ot_var_named_instance_get_subfamily_name_id (face, index);
hb_ot_name_get_utf8 (face, name_id, HB_LANGUAGE_INVALID, &name_len, name);
instance->name = g_strdup_printf (name);
instance->name = g_strdup (name);
instance->index = index;
g_hash_table_add (instances, instance);
@@ -1109,23 +1109,23 @@ done:
g_free (design_coords);
}
static void
font_changed (void)
void
font_features_font_changed (void)
{
update_script_combo ();
update_features ();
update_font_variations ();
}
static void
script_changed (void)
void
font_features_script_changed (void)
{
update_features ();
update_display ();
}
static void
reset_features (void)
void
font_features_reset_features (void)
{
GList *l;
@@ -1170,8 +1170,8 @@ switch_to_label (void)
update_display ();
}
static void
toggle_edit (void)
void
font_features_toggle_edit (void)
{
if (strcmp (gtk_stack_get_visible_child_name (GTK_STACK (stack)), "label") == 0)
switch_to_entry ();
@@ -1179,8 +1179,8 @@ toggle_edit (void)
switch_to_label ();
}
static void
stop_edit (void)
void
font_features_stop_edit (void)
{
g_signal_emit_by_name (edit_toggle, "clicked");
}
@@ -1195,7 +1195,7 @@ entry_key_press (GtkEventController *controller,
if (keyval == GDK_KEY_Escape)
{
gtk_editable_set_text (GTK_EDITABLE (entry), text);
stop_edit ();
font_features_stop_edit ();
return GDK_EVENT_STOP;
}
@@ -1215,14 +1215,6 @@ do_font_features (GtkWidget *do_widget)
builder = gtk_builder_new_from_resource ("/font_features/font-features.ui");
gtk_builder_add_callback_symbol (builder, "update_display", update_display);
gtk_builder_add_callback_symbol (builder, "font_changed", font_changed);
gtk_builder_add_callback_symbol (builder, "script_changed", script_changed);
gtk_builder_add_callback_symbol (builder, "reset", reset_features);
gtk_builder_add_callback_symbol (builder, "stop_edit", G_CALLBACK (stop_edit));
gtk_builder_add_callback_symbol (builder, "toggle_edit", G_CALLBACK (toggle_edit));
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
feature_list = GTK_WIDGET (gtk_builder_get_object (builder, "feature_list"));
label = GTK_WIDGET (gtk_builder_get_object (builder, "label"));
@@ -1339,7 +1331,7 @@ do_font_features (GtkWidget *do_widget)
else
g_hash_table_remove_all (axes);
font_changed ();
font_features_font_changed ();
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);

View File

@@ -19,8 +19,6 @@
#include "fontplane.h"
#include "gtk.h"
enum {
PROP_0,
PROP_WEIGHT_ADJUSTMENT,

View File

@@ -248,7 +248,6 @@ do_fontrendering (GtkWidget *do_widget)
GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/fontrendering/fontrendering.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));

View File

@@ -165,10 +165,11 @@
</child>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="halign">center</property>
<property name="valign">center</property>
<style><class name="linked"/></style>
<style>
<class name="linked"/>
</style>
<child>
<object class="GtkRadioButton" id="text_radio">
<property name="draw-indicator">0</property>
@@ -183,7 +184,7 @@
</object>
</child>
<layout>
<property name="left-attach">0</property>
<property name="left-attach">0</property>
<property name="top-attach">3</property>
<property name="column-span">7</property>
</layout>

View File

@@ -13,17 +13,16 @@ in_files = sys.argv[2:]
file_output = """
typedef GtkWidget *(*GDoDemoFunc) (GtkWidget *do_widget);
typedef struct _Demo Demo;
typedef struct _DemoData DemoData;
struct _Demo
struct _DemoData
{
gchar *name;
gchar *title;
gchar *filename;
char *name;
char *title;
char *filename;
GDoDemoFunc func;
Demo *children;
DemoData *children;
};
"""
# Demo = namedtuple('Demo', ['name', 'title', 'file', 'func'])
@@ -67,7 +66,7 @@ for demo in demos:
i = 0
for parent in parents:
id = parent_ids[i]
file_output += "\nDemo child" + str(id) + "[] = {\n"
file_output += "\nDemoData child" + str(id) + "[] = {\n"
# iterate over all demos and check if the name starts with the given parent name
for child in demos:
if child[1].startswith(parent + "/"):
@@ -82,7 +81,7 @@ for parent in parents:
# Sort demos by title
demos = sorted(demos, key=lambda x: x[1])
file_output += "\nDemo gtk_demos[] = {\n"
file_output += "\nDemoData gtk_demos[] = {\n"
for demo in demos:
# Do not generate one of these for demos with a parent demo
if "/" not in demo[1]:

View File

@@ -53,7 +53,6 @@ enum {
PROP_BENCHMARK,
PROP_COUNT,
PROP_FRAMERATE,
PROP_FRAMERATE_STRING,
PROP_UPDATE_DELAY,
NUM_PROPERTIES
};
@@ -289,14 +288,6 @@ gtk_fishbowl_get_property (GObject *object,
g_value_set_double (value, gtk_fishbowl_get_framerate (fishbowl));
break;
case PROP_FRAMERATE_STRING:
{
char *s = g_strdup_printf ("%.2f", gtk_fishbowl_get_framerate (fishbowl));
g_value_set_string (value, s);
g_free (s);
}
break;
case PROP_UPDATE_DELAY:
g_value_set_int64 (value, gtk_fishbowl_get_update_delay (fishbowl));
break;
@@ -350,13 +341,6 @@ gtk_fishbowl_class_init (GtkFishbowlClass *klass)
0,
G_PARAM_READABLE);
props[PROP_FRAMERATE_STRING] =
g_param_spec_string ("framerate-string",
"Framerate as string",
"Framerate as string, with 2 decimals",
NULL,
G_PARAM_READABLE);
props[PROP_UPDATE_DELAY] =
g_param_spec_int64 ("update-delay",
"Update delay",
@@ -508,7 +492,6 @@ gtk_fishbowl_do_update (GtkFishbowl *fishbowl)
priv->framerate = ((int)(priv->framerate * 100))/100.0;
g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_FRAMERATE]);
g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_FRAMERATE_STRING]);
if (!priv->benchmark)
return;

View File

@@ -12,7 +12,7 @@ static GtkWidget *window = NULL;
static GtkWidget *scrolledwindow;
static int selected;
#define N_WIDGET_TYPES 4
#define N_WIDGET_TYPES 6
static int hincrement = 5;
@@ -61,6 +61,7 @@ populate_icons (void)
gtk_grid_attach (GTK_GRID (grid), create_icon (), left, top, 1, 1);
hincrement = 0;
vincrement = 5;
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
GTK_POLICY_NEVER,
@@ -97,6 +98,7 @@ populate_text (gboolean hilight)
gtk_text_view_set_buffer (GTK_TEXT_VIEW (textview), buffer);
hincrement = 0;
vincrement = 5;
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
GTK_POLICY_NEVER,
@@ -121,6 +123,7 @@ populate_image (void)
gtk_picture_set_can_shrink (GTK_PICTURE (image), FALSE);
hincrement = 5;
vincrement = 5;
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
GTK_POLICY_AUTOMATIC,
@@ -128,6 +131,42 @@ populate_image (void)
gtk_container_add (GTK_CONTAINER (scrolledwindow), image);
}
extern GtkWidget *create_weather_view (void);
static void
populate_list (void)
{
GtkWidget *list;
list = create_weather_view ();
hincrement = 5;
vincrement = 0;
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_add (GTK_CONTAINER (scrolledwindow), list);
}
extern GtkWidget *create_color_grid (void);
static void
populate_grid (void)
{
GtkWidget *list;
list = create_color_grid ();
hincrement = 0;
vincrement = 5;
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_add (GTK_CONTAINER (scrolledwindow), list);
}
static void
set_widget_type (int type)
{
@@ -162,6 +201,16 @@ set_widget_type (int type)
populate_image ();
break;
case 4:
gtk_window_set_title (GTK_WINDOW (window), "Scrolling a list");
populate_list ();
break;
case 5:
gtk_window_set_title (GTK_WINDOW (window), "Scrolling a grid");
populate_grid ();
break;
default:
g_assert_not_reached ();
}
@@ -169,9 +218,9 @@ set_widget_type (int type)
tick_cb = gtk_widget_add_tick_callback (window, scroll_cb, NULL, NULL);
}
static void
next_clicked_cb (GtkButton *source,
gpointer user_data)
void
iconscroll_next_clicked_cb (GtkButton *source,
gpointer user_data)
{
int new_index;
@@ -184,9 +233,9 @@ next_clicked_cb (GtkButton *source,
set_widget_type (new_index);
}
static void
prev_clicked_cb (GtkButton *source,
gpointer user_data)
void
iconscroll_prev_clicked_cb (GtkButton *source,
gpointer user_data)
{
int new_index;
@@ -206,11 +255,6 @@ do_iconscroll (GtkWidget *do_widget)
GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/iconscroll/iconscroll.ui");
gtk_builder_add_callback_symbols (builder,
"next_clicked_cb", G_CALLBACK (next_clicked_cb),
"prev_clicked_cb", G_CALLBACK (prev_clicked_cb),
NULL);
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);

View File

@@ -15,13 +15,13 @@
<child>
<object class="GtkButton">
<property name="icon-name">pan-start-symbolic</property>
<signal name="clicked" handler="prev_clicked_cb"/>
<signal name="clicked" handler="iconscroll_prev_clicked_cb"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="icon-name">pan-end-symbolic</property>
<signal name="clicked" handler="next_clicked_cb"/>
<signal name="clicked" handler="iconscroll_next_clicked_cb"/>
</object>
</child>
</object>
@@ -31,9 +31,12 @@
<child>
<object class="GtkScrolledWindow" id="scrolledwindow">
<property name="hscrollbar-policy">never</property>
<property name="vscrollbar-policy">automatic</property>
<property name="hadjustment"><object class="GtkAdjustment" id="hadjustment"/></property>
<property name="vadjustment"><object class="GtkAdjustment" id="vadjustment"/></property>
<property name="hadjustment">
<object class="GtkAdjustment" id="hadjustment"/>
</property>
<property name="vadjustment">
<object class="GtkAdjustment" id="vadjustment"/>
</property>
</object>
</child>
</object>

View File

@@ -8,6 +8,7 @@
#include <gtk/gtk.h>
#include <stdlib.h>
#include <string.h>
#include "award.h"
static GdkPixbuf *avatar_pixbuf_other;
static GtkWidget *window = NULL;
@@ -234,9 +235,9 @@ reshare_clicked (GtkMessageRow *row,
{
GtkMessageRowPrivate *priv = row->priv;
award ("listbox-reshare");
priv->message->n_reshares++;
gtk_message_row_update (row);
}
static void
@@ -255,11 +256,14 @@ gtk_message_row_state_flags_changed (GtkWidget *widget,
{
GtkMessageRowPrivate *priv = GTK_MESSAGE_ROW (widget)->priv;
GtkStateFlags flags;
gboolean visible;
flags = gtk_widget_get_state_flags (widget);
gtk_widget_set_visible (priv->extra_buttons_box,
flags & (GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_SELECTED));
visible = flags & (GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_SELECTED) ? TRUE : FALSE;
gtk_widget_set_visible (priv->extra_buttons_box, visible);
if (visible && gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (widget)) % 100 == 99)
award ("listbox-100th-row");
GTK_WIDGET_CLASS (gtk_message_row_parent_class)->state_flags_changed (widget, previous_state_flags);
}

View File

@@ -0,0 +1,200 @@
/* Lists/Application launcher
*
* This demo uses the GtkCoverFlow widget as a fancy application launcher.
*
* It is also a very small introduction to listviews.
*/
#include <gtk/gtk.h>
/* This is the function that creates the #GListModel that we need.
* GTK list widgets need a #GListModel to display, as models support change
* notifications.
* Unfortunately various older APIs do not provide list models, so we create
* our own.
*/
static GListModel *
create_application_list (void)
{
GListStore *store;
GList *apps, *l;
/* We use a #GListStore here, which is a simple array-like list implementation
* for manual management.
* List models need to know what type of data they provide, so we need to
* provide the type here. As we want to do a list of applications, #GAppInfo
* is the object we provide.
*/
store = g_list_store_new (G_TYPE_APP_INFO);
apps = g_app_info_get_all ();
for (l = apps; l; l = l->next)
{
g_list_store_append (store, l->data);
}
g_list_free_full (apps, g_object_unref);
return G_LIST_MODEL (store);
}
/* This is the function we use for setting up new listitems to display.
* We add just a #GtkImage here to display the application's icon as this is just
* a simple demo.
*/
static void
setup_listitem_cb (GtkListItemFactory *factory,
GtkListItem *list_item)
{
GtkWidget *image;
image = gtk_image_new ();
gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
gtk_list_item_set_child (list_item, image);
}
/* Here we need to prepare the listitem for displaying its item. We get the
* listitem already set up from the previous function, so we can reuse the
* #GtkImage widget we set up above.
* We get the item - which we know is a #GAppInfo because it comes out of
* the model we set up above, grab its icon and display it.
*/
static void
bind_listitem_cb (GtkListItemFactory *factory,
GtkListItem *list_item)
{
GtkWidget *image;
GAppInfo *app_info;
image = gtk_list_item_get_child (list_item);
app_info = gtk_list_item_get_item (list_item);
gtk_image_set_from_gicon (GTK_IMAGE (image), g_app_info_get_icon (app_info));
}
/* In more complex code, we would also need functions to unbind and teardown
* the listitem, but this is simple code, so the default implementations are
* enough. If we had connected signals, this step would have been necessary.
*
* The #GtkSignalListItemFactory documentation contains more information about
* this step.
*/
/* This function is called whenever an item in the list is activated. This is
* the simple way to allow reacting to the Enter key or double-clicking on a
* listitem.
* Of course, it is possible to use far more complex interactions by turning
* off activation and adding buttons or other widgets in the setup function
* above, but this is a simple demo, so we'll use the simple way.
*/
static void
activate_cb (GtkCoverFlow *coverflow,
guint position,
gpointer unused)
{
GAppInfo *app_info;
GdkAppLaunchContext *context;
GError *error = NULL;
app_info = g_list_model_get_item (gtk_cover_flow_get_model (coverflow), position);
/* Prepare the context for launching the application and launch it. This
* code is explained in detail in the documentation for #GdkAppLaunchContext
* and #GAppInfo.
*/
context = gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (coverflow)));
if (!g_app_info_launch (app_info,
NULL,
G_APP_LAUNCH_CONTEXT (context),
&error))
{
GtkWidget *dialog;
/* And because error handling is important, even a simple demo has it:
* We display an error dialog that something went wrong.
*/
dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (coverflow))),
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"Could not launch %s", g_app_info_get_display_name (app_info));
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error->message);
g_clear_error (&error);
gtk_widget_show (dialog);
}
g_object_unref (context);
g_object_unref (app_info);
}
static GtkWidget *window = NULL;
GtkWidget *
do_listview_applauncher (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkWidget *coverflow, *sw;;
GListModel *model;
GtkListItemFactory *factory;
/* Create a window and set a few defaults */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (window), 640, 320);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Application Launcher");
g_signal_connect (window, "destroy",
G_CALLBACK(gtk_widget_destroyed), &window);
/* The #GtkListitemFactory is what is used to create #GtkListItems
* to display the data from the model. So it is absolutely necessary
* to create one.
* We will use a #GtkSignalListItemFactory because it is the simplest
* one to use. Different ones are available for different use cases.
* The most powerful one is #GtkBuilderListItemFactory which uses
* #GtkBuilder .ui files, so it requires little code.
*/
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_listitem_cb), NULL);
g_signal_connect (factory, "bind", G_CALLBACK (bind_listitem_cb), NULL);
/* Create the list widget here: We use a coverflow widget because it's
* the coolest one. We could just as well use other list widgets such
* as a #GtkListView or a #GtkGridView and the code would look very
* similar.
*/
coverflow = gtk_cover_flow_new_with_factory (factory);
/* We connect the activate signal here. It's the function we defined
* above for launching the selected application.
*/
g_signal_connect (coverflow, "activate", G_CALLBACK (activate_cb), NULL);
/* And of course we need to set the data model. Here we call the function
* we wrote above that gives us the list of applications. Then we set
* it on the coverflow list widget.
* The coverflow will now take items from the model and use the factory
* to create as many listitems as it needs to show itself to the user.
*/
model = create_application_list ();
gtk_cover_flow_set_model (GTK_COVER_FLOW (coverflow), model);
g_object_unref (model);
/* List widgets should always be contained in a #GtkScrolledWindow,
* because otherwise they might get too large or they might not
* be scrollable.
*/
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (window), sw);
gtk_container_add (GTK_CONTAINER (sw), coverflow);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -0,0 +1,491 @@
/* Lists/Clocks
*
* This demo displays the time in different timezones.
*
* It is using a GtkGridView.
*
* The goal is to show how to set up expressions that track changes
* in objects and make them update widgets. For that, we create a
* GtkClock object that updates its time every second and then use
* various ways to display that time.
*
* Typically, this will be done using GtkBuilder .ui files with the
* help of the <binding> tag, but this demo shows the code that runs
* behind that.
*/
#include <gtk/gtk.h>
#define GTK_TYPE_CLOCK (gtk_clock_get_type ())
G_DECLARE_FINAL_TYPE (GtkClock, gtk_clock, GTK, CLOCK, GObject)
/* This is our object. It's just a timezone */
typedef struct _GtkClock GtkClock;
struct _GtkClock
{
GObject parent_instance;
/* We allow this to be NULL for the local timezone */
GTimeZone *timezone;
/* Name of the location we're displaying time for */
char *location;
};
enum {
PROP_0,
PROP_LOCATION,
PROP_TIME,
PROP_TIMEZONE,
N_PROPS
};
/* This function returns the current time in the clock's timezone.
* Note that this returns a new object every time, so we need to
* remember to unref it after use. */
static GDateTime *
gtk_clock_get_time (GtkClock *clock)
{
if (clock->timezone)
return g_date_time_new_now (clock->timezone);
else
return g_date_time_new_now_local ();
}
/* Here, we implement the functionality required by the GdkPaintable interface.
* This way we have a trivial way to display an analog clock.
* It also allows demonstrating how to directly use objects in the listview
* later by making this object do something interesting. */
static void
gtk_clock_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
double width,
double height)
{
GtkClock *self = GTK_CLOCK (paintable);
GDateTime *time;
GskRoundedRect outline;
#define BLACK ((GdkRGBA) { 0, 0, 0, 1 })
/* save/restore() is necessary so we can undo the transforms we start
* out with. */
gtk_snapshot_save (snapshot);
/* First, we move the (0, 0) point to the center of the area so
* we can draw everything relative to it. */
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (width / 2, height / 2));
/* Next we scale it, so that we can pretend that the clock is
* 100px in size. That way, we don't need to do any complicated
* math later.
* We use MIN() here so that we use the smaller dimension for sizing.
* That way we don't overdraw but keep the aspect ratio. */
gtk_snapshot_scale (snapshot, MIN (width, height) / 100.0, MIN (width, height) / 100.0);
/* Now we have a circle with diameter 100px (and radius 50px) that
* has its (0, 0) point at the center.
* Let's draw a simple clock into it. */
time = gtk_clock_get_time (self);
/* First, draw a circle. This is a neat little trick to draw a circle
* without requiring Cairo. */
gsk_rounded_rect_init_from_rect (&outline, &GRAPHENE_RECT_INIT(-50, -50, 100, 100), 50);
gtk_snapshot_append_border (snapshot,
&outline,
(float[4]) { 4, 4, 4, 4 },
(GdkRGBA [4]) { BLACK, BLACK, BLACK, BLACK });
/* Next, draw the hour hand.
* We do this using tranforms again: Instead of computing where the angle points
* to, we just rotate everything and then draw the hand as if if was :00.
* We don't even need to care about am/pm here because rotations just work. */
gtk_snapshot_save (snapshot);
gtk_snapshot_rotate (snapshot, 30 * g_date_time_get_hour (time) + 0.5 * g_date_time_get_minute (time));
gsk_rounded_rect_init_from_rect (&outline, &GRAPHENE_RECT_INIT(-2, -23, 4, 25), 2);
gtk_snapshot_push_rounded_clip (snapshot, &outline);
gtk_snapshot_append_color (snapshot, &BLACK, &outline.bounds);
gtk_snapshot_pop (snapshot);
gtk_snapshot_restore (snapshot);
/* And the same as above for the minute hand. Just make this one longer
* so people can tell the hands apart. */
gtk_snapshot_save (snapshot);
gtk_snapshot_rotate (snapshot, 6 * g_date_time_get_minute (time));
gsk_rounded_rect_init_from_rect (&outline, &GRAPHENE_RECT_INIT(-2, -43, 4, 45), 2);
gtk_snapshot_push_rounded_clip (snapshot, &outline);
gtk_snapshot_append_color (snapshot, &BLACK, &outline.bounds);
gtk_snapshot_pop (snapshot);
gtk_snapshot_restore (snapshot);
/* and finally, the second indicator. */
gtk_snapshot_save (snapshot);
gtk_snapshot_rotate (snapshot, 6 * g_date_time_get_second (time));
gsk_rounded_rect_init_from_rect (&outline, &GRAPHENE_RECT_INIT(-2, -43, 4, 10), 2);
gtk_snapshot_push_rounded_clip (snapshot, &outline);
gtk_snapshot_append_color (snapshot, &BLACK, &outline.bounds);
gtk_snapshot_pop (snapshot);
gtk_snapshot_restore (snapshot);
/* And finally, don't forget to restore the initial save() that we did for
* the initial transformations. */
gtk_snapshot_restore (snapshot);
g_date_time_unref (time);
}
/* Our desired size is 100px. That sounds okay for an analog clock */
static int
gtk_clock_get_intrinsic_width (GdkPaintable *paintable)
{
return 100;
}
static int
gtk_clock_get_intrinsic_height (GdkPaintable *paintable)
{
return 100;
}
/* Initialize the paintable interface. This way we turn our clock objects
* into objects that can be drawn.
* There are more functions to this interface to define desired size,
* but this is enough.
*/
static void
gtk_clock_paintable_init (GdkPaintableInterface *iface)
{
iface->snapshot = gtk_clock_snapshot;
iface->get_intrinsic_width = gtk_clock_get_intrinsic_width;
iface->get_intrinsic_height = gtk_clock_get_intrinsic_height;
}
/* Finally, we define the type. The important part is adding the paintable
* interface, so GTK knows that this object can indeed be drawm.
*/
G_DEFINE_TYPE_WITH_CODE (GtkClock, gtk_clock, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
gtk_clock_paintable_init))
static GParamSpec *properties[N_PROPS] = { NULL, };
static void
gtk_clock_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GtkClock *self = GTK_CLOCK (object);
switch (property_id)
{
case PROP_LOCATION:
g_value_set_string (value, self->location);
break;
case PROP_TIME:
g_value_take_boxed (value, gtk_clock_get_time (self));
break;
case PROP_TIMEZONE:
g_value_set_boxed (value, self->timezone);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gtk_clock_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GtkClock *self = GTK_CLOCK (object);
switch (property_id)
{
case PROP_LOCATION:
self->location = g_value_dup_string (value);
break;
case PROP_TIMEZONE:
self->timezone = g_value_dup_boxed (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
/* This is the list of all the ticking clocks */
static GSList *ticking_clocks = NULL;
/* This is the id of the timeout source that is updating all ticking clocks */
static guint ticking_clock_id = 0;
/* Every second, this function is called to tell everybody that the
* clocks are ticking.
*/
static gboolean
gtk_clock_tick (gpointer unused)
{
GSList *l;
for (l = ticking_clocks; l; l = l->next)
{
GtkClock *clock = l->data;
/* We will now return a different value for the time porperty,
* so notify about that.
*/
g_object_notify_by_pspec (G_OBJECT (clock), properties[PROP_TIME]);
/* We will also draw the hands of the clock differently.
* So notify about that, too.
*/
gdk_paintable_invalidate_contents (GDK_PAINTABLE (clock));
}
return G_SOURCE_CONTINUE;
}
static void
gtk_clock_stop_ticking (GtkClock *self)
{
ticking_clocks = g_slist_remove (ticking_clocks, self);
/* If no clock is remaining, stop running the tick updates */
if (ticking_clocks == NULL && ticking_clock_id != 0)
g_clear_handle_id (&ticking_clock_id, g_source_remove);
}
static void
gtk_clock_start_ticking (GtkClock *self)
{
/* if no clock is ticking yet, start */
if (ticking_clock_id == 0)
ticking_clock_id = g_timeout_add_seconds (1, gtk_clock_tick, NULL);
ticking_clocks = g_slist_prepend (ticking_clocks, self);
}
static void
gtk_clock_finalize (GObject *object)
{
GtkClock *self = GTK_CLOCK (object);
gtk_clock_stop_ticking (self);
g_free (self->location);
g_clear_pointer (&self->timezone, g_time_zone_unref);
G_OBJECT_CLASS (gtk_clock_parent_class)->finalize (object);
}
static void
gtk_clock_class_init (GtkClockClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gtk_clock_get_property;
gobject_class->set_property = gtk_clock_set_property;
gobject_class->finalize = gtk_clock_finalize;
properties[PROP_LOCATION] =
g_param_spec_string ("location", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_TIME] =
g_param_spec_boxed ("time", NULL, NULL, G_TYPE_DATE_TIME, G_PARAM_READABLE);
properties[PROP_TIMEZONE] =
g_param_spec_boxed ("timezone", NULL, NULL, G_TYPE_TIME_ZONE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void
gtk_clock_init (GtkClock *self)
{
gtk_clock_start_ticking (self);
}
static GtkClock *
gtk_clock_new (const char *location,
GTimeZone *timezone)
{
GtkClock *result;
result = g_object_new (GTK_TYPE_CLOCK,
"location", location,
"timezone", timezone,
NULL);
g_clear_pointer (&timezone, g_time_zone_unref);
return result;
}
static GListModel *
create_clocks_model (void)
{
GListStore *result;
GtkClock *clock;
result = g_list_store_new (GTK_TYPE_CLOCK);
/* local time */
clock = gtk_clock_new ("local", NULL);
g_list_store_append (result, clock);
g_object_unref (clock);
/* UTC time */
clock = gtk_clock_new ("UTC", g_time_zone_new_utc ());
g_list_store_append (result, clock);
g_object_unref (clock);
/* A bunch of timezones with GTK hackers */
clock = gtk_clock_new ("San Francisco", g_time_zone_new ("America/Los_Angeles"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("Boston", g_time_zone_new ("America/New_York"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("London", g_time_zone_new ("Europe/London"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("Berlin", g_time_zone_new ("Europe/Berlin"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("Moscow", g_time_zone_new ("Europe/Moscow"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("New Delhi", g_time_zone_new ("Asia/Kolkata"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("Shanghai", g_time_zone_new ("Asia/Shanghai"));
g_list_store_append (result, clock);
g_object_unref (clock);
return G_LIST_MODEL (result);
}
static char *
convert_time_to_string (GObject *image,
GDateTime *time,
gpointer unused)
{
return g_date_time_format (time, "%x\n%X");
}
/* And this function is the crux for this whole demo.
* It shows how to use expressions to set up bindings.
*/
static void
setup_listitem_cb (GtkListItemFactory *factory,
GtkListItem *list_item)
{
GtkWidget *box, *picture, *location_label, *time_label;
GtkExpression *clock_expression, *expression;
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_list_item_set_child (list_item, box);
/* First, we create an expression that gets us the clock from the listitem:
* 1. Create an expression that gets the list item.
* 2. Use that expression's "item" property to get the clock
*/
expression = gtk_constant_expression_new (GTK_TYPE_LIST_ITEM, list_item);
clock_expression = gtk_property_expression_new (GTK_TYPE_LIST_ITEM, expression, "item");
/* Bind the clock's location to a label.
* This is easy: We just get the "location" property of the clock.
*/
expression = gtk_property_expression_new (GTK_TYPE_CLOCK,
gtk_expression_ref (clock_expression),
"location");
/* Now create the label and bind the expression to it. */
location_label = gtk_label_new (NULL);
gtk_expression_bind (expression, location_label, "label", location_label);
gtk_container_add (GTK_CONTAINER (box), location_label);
/* Here we bind the item itself to a GdkPicture.
* This is simply done by using the clock expression itself.
*/
expression = gtk_expression_ref (clock_expression);
/* Now create the widget and bind the expression to it. */
picture = gtk_picture_new ();
gtk_expression_bind (expression, picture, "paintable", picture);
gtk_container_add (GTK_CONTAINER (box), picture);
/* And finally, everything comes together.
* We create a label for displaying the time as text.
* For that, we need to transform the "GDateTime" of the
* time property into a string so that the label can display it.
*/
expression = gtk_property_expression_new (GTK_TYPE_CLOCK,
gtk_expression_ref (clock_expression),
"time");
expression = gtk_cclosure_expression_new (G_TYPE_STRING,
NULL,
1, (GtkExpression *[1]) { expression },
G_CALLBACK (convert_time_to_string),
NULL, NULL);
/* Now create the label and bind the expression to it. */
time_label = gtk_label_new (NULL);
gtk_expression_bind (expression, time_label, "label", time_label);
gtk_container_add (GTK_CONTAINER (box), time_label);
gtk_expression_unref (clock_expression);
}
static GtkWidget *window = NULL;
GtkWidget *
do_listview_clocks (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkWidget *gridview, *sw;
GtkListItemFactory *factory;
GListModel *model;
GtkNoSelection *selection;
/* This is the normal window setup code every demo does */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Clocks");
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
/* List widgets go into a scrolled window. Always. */
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (window), sw);
/* Create the factory that creates the listitems. Because we
* used bindings above during setup, we only need to connect
* to the setup signal.
* The bindings take care of the bind step.
*/
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_listitem_cb), NULL);
gridview = gtk_grid_view_new_with_factory (factory);
gtk_scrollable_set_hscroll_policy (GTK_SCROLLABLE (gridview), GTK_SCROLL_NATURAL);
gtk_scrollable_set_vscroll_policy (GTK_SCROLLABLE (gridview), GTK_SCROLL_NATURAL);
model = create_clocks_model ();
selection = gtk_no_selection_new (model);
gtk_grid_view_set_model (GTK_GRID_VIEW (gridview), G_LIST_MODEL (selection));
gtk_container_add (GTK_CONTAINER (sw), gridview);
g_object_unref (selection);
g_object_unref (model);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -0,0 +1,593 @@
/* Lists/Colors
*
* This demo displays a named colors.
*
* It is using a GtkGridView, and shows
* how to sort the data in various ways.
*
* The dataset used here has 9283 items.
*/
#include <gtk/gtk.h>
#define GTK_TYPE_COLOR (gtk_color_get_type ())
G_DECLARE_FINAL_TYPE (GtkColor, gtk_color, GTK, COLOR, GObject)
/* This is our object. It's just a color */
typedef struct _GtkColor GtkColor;
struct _GtkColor
{
GObject parent_instance;
char *name;
GdkRGBA *color;
int h, s, v;
};
enum {
PROP_0,
PROP_NAME,
PROP_COLOR,
PROP_RED,
PROP_GREEN,
PROP_BLUE,
PROP_HUE,
PROP_SATURATION,
PROP_VALUE,
N_PROPS
};
static void
gtk_color_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
double width,
double height)
{
GtkColor *self = GTK_COLOR (paintable);
gtk_snapshot_append_color (snapshot, self->color, &GRAPHENE_RECT_INIT (0, 0, width, height));
}
static int
gtk_color_get_intrinsic_width (GdkPaintable *paintable)
{
return 32;
}
static int
gtk_color_get_intrinsic_height (GdkPaintable *paintable)
{
return 32;
}
static void
gtk_color_paintable_init (GdkPaintableInterface *iface)
{
iface->snapshot = gtk_color_snapshot;
iface->get_intrinsic_width = gtk_color_get_intrinsic_width;
iface->get_intrinsic_height = gtk_color_get_intrinsic_height;
}
/*
* Finally, we define the type. The important part is adding the paintable
* interface, so GTK knows that this object can indeed be drawm.
*/
G_DEFINE_TYPE_WITH_CODE (GtkColor, gtk_color, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
gtk_color_paintable_init))
static GParamSpec *properties[N_PROPS] = { NULL, };
static void
gtk_color_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GtkColor *self = GTK_COLOR (object);
switch (property_id)
{
case PROP_NAME:
g_value_set_string (value, self->name);
break;
case PROP_COLOR:
g_value_set_boxed (value, self->color);
break;
case PROP_RED:
g_value_set_float (value, self->color->red);
break;
case PROP_GREEN:
g_value_set_float (value, self->color->green);
break;
case PROP_BLUE:
g_value_set_float (value, self->color->blue);
break;
case PROP_HUE:
g_value_set_int (value, self->h);
break;
case PROP_SATURATION:
g_value_set_int (value, self->s);
break;
case PROP_VALUE:
g_value_set_int (value, self->v);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gtk_color_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GtkColor *self = GTK_COLOR (object);
switch (property_id)
{
case PROP_NAME:
self->name = g_value_dup_string (value);
break;
case PROP_COLOR:
self->color = g_value_dup_boxed (value);
break;
case PROP_HUE:
self->h = g_value_get_int (value);
break;
case PROP_SATURATION:
self->s = g_value_get_int (value);
break;
case PROP_VALUE:
self->v = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gtk_color_finalize (GObject *object)
{
GtkColor *self = GTK_COLOR (object);
g_free (self->name);
g_clear_pointer (&self->color, gdk_rgba_free);
G_OBJECT_CLASS (gtk_color_parent_class)->finalize (object);
}
static void
gtk_color_class_init (GtkColorClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gtk_color_get_property;
gobject_class->set_property = gtk_color_set_property;
gobject_class->finalize = gtk_color_finalize;
properties[PROP_NAME] =
g_param_spec_string ("name", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_COLOR] =
g_param_spec_boxed ("color", NULL, NULL, GDK_TYPE_RGBA, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_RED] =
g_param_spec_float ("red", NULL, NULL, 0, 1, 0, G_PARAM_READABLE);
properties[PROP_GREEN] =
g_param_spec_float ("green", NULL, NULL, 0, 1, 0, G_PARAM_READABLE);
properties[PROP_BLUE] =
g_param_spec_float ("blue", NULL, NULL, 0, 1, 0, G_PARAM_READABLE);
properties[PROP_HUE] =
g_param_spec_int ("hue", NULL, NULL, 0, 360, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_SATURATION] =
g_param_spec_int ("saturation", NULL, NULL, 0, 100, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_VALUE] =
g_param_spec_int ("value", NULL, NULL, 0, 100, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void
gtk_color_init (GtkColor *self)
{
}
static GtkColor *
gtk_color_new (const char *name,
float r, float g, float b,
int h, int s, int v)
{
GtkColor *result;
GdkRGBA color = { r, g, b, 1.0 };
result = g_object_new (GTK_TYPE_COLOR,
"name", name,
"color", &color,
"hue", h,
"saturation", s,
"value", v,
NULL);
return result;
}
static GListModel *
create_colors_model (void)
{
GListStore *result;
GtkColor *color;
GBytes *data;
char **lines;
guint i;
result = g_list_store_new (GTK_TYPE_COLOR);
data = g_resources_lookup_data ("/listview_colors/color.names.txt", 0, NULL);
lines = g_strsplit (g_bytes_get_data (data, NULL), "\n", 0);
for (i = 0; lines[i]; i++)
{
const char *name;
char **fields;
int red, green, blue;
int h, s, v;
if (lines[i][0] == '#' || lines[i][0] == '\0')
continue;
fields = g_strsplit (lines[i], " ", 0);
name = fields[1];
red = atoi (fields[3]);
green = atoi (fields[4]);
blue = atoi (fields[5]);
h = atoi (fields[9]);
s = atoi (fields[10]);
v = atoi (fields[11]);
color = gtk_color_new (name, red / 255., green / 255., blue / 255., h, s, v);
g_list_store_append (result, color);
g_object_unref (color);
g_strfreev (fields);
}
g_strfreev (lines);
g_bytes_unref (data);
return G_LIST_MODEL (result);
}
static char *
get_rgb_markup (gpointer this,
GtkColor *color)
{
if (!color)
return NULL;
return g_strdup_printf ("<b>R:</b> %d <b>G:</b> %d <b>B:</b> %d",
(int)(color->color->red * 255),
(int)(color->color->green * 255),
(int)(color->color->blue * 255));
}
static char *
get_hsv_markup (gpointer this,
GtkColor *color)
{
if (!color)
return NULL;
return g_strdup_printf ("<b>H:</b> %d <b>S:</b> %d <b>V:</b> %d",
color->h,
color->s,
color->v);
}
static void
setup_simple_listitem_cb (GtkListItemFactory *factory,
GtkListItem *list_item)
{
GtkWidget *picture;
GtkExpression *color_expression, *expression;
expression = gtk_constant_expression_new (GTK_TYPE_LIST_ITEM, list_item);
color_expression = gtk_property_expression_new (GTK_TYPE_LIST_ITEM, expression, "item");
picture = gtk_picture_new ();
gtk_widget_set_size_request (picture, 32, 32);
gtk_expression_bind (color_expression, picture, "paintable", NULL);
gtk_list_item_set_child (list_item, picture);
}
static void
setup_listitem_cb (GtkListItemFactory *factory,
GtkListItem *list_item)
{
GtkWidget *box, *picture, *name_label, *rgb_label, *hsv_label;;
GtkExpression *color_expression, *expression;
GtkExpression *params[1];
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_list_item_set_child (list_item, box);
expression = gtk_constant_expression_new (GTK_TYPE_LIST_ITEM, list_item);
color_expression = gtk_property_expression_new (GTK_TYPE_LIST_ITEM, expression, "item");
expression = gtk_property_expression_new (GTK_TYPE_COLOR,
gtk_expression_ref (color_expression),
"name");
name_label = gtk_label_new (NULL);
gtk_expression_bind (expression, name_label, "label", NULL);
gtk_container_add (GTK_CONTAINER (box), name_label);
expression = gtk_expression_ref (color_expression);
picture = gtk_picture_new ();
gtk_expression_bind (expression, picture, "paintable", NULL);
gtk_container_add (GTK_CONTAINER (box), picture);
params[0] = gtk_expression_ref (color_expression);
expression = gtk_cclosure_expression_new (G_TYPE_STRING,
NULL,
1, params,
(GCallback)get_rgb_markup,
NULL, NULL);
rgb_label = gtk_label_new (NULL);
gtk_label_set_use_markup (GTK_LABEL (rgb_label), TRUE);
gtk_expression_bind (expression, rgb_label, "label", NULL);
gtk_container_add (GTK_CONTAINER (box), rgb_label);
params[0] = gtk_expression_ref (color_expression);
expression = gtk_cclosure_expression_new (G_TYPE_STRING,
NULL,
1, params,
(GCallback)get_hsv_markup,
NULL, NULL);
hsv_label = gtk_label_new (NULL);
gtk_label_set_use_markup (GTK_LABEL (hsv_label), TRUE);
gtk_expression_bind (expression, hsv_label, "label", NULL);
gtk_container_add (GTK_CONTAINER (box), hsv_label);
gtk_expression_unref (color_expression);
}
static void
set_title (gpointer item,
const char *title)
{
g_object_set_data (G_OBJECT (item), "title", (gpointer)title);
}
static char *
get_title (gpointer item)
{
return g_strdup ((char *)g_object_get_data (G_OBJECT (item), "title"));
}
static gboolean
set_item (GBinding *binding,
const GValue *from,
GValue *to,
gpointer data)
{
GObject *source = g_binding_get_source (binding);
GListModel *model;
guint selected;
gpointer item;
selected = g_value_get_uint (from);
model = gtk_drop_down_get_model (GTK_DROP_DOWN (source));
item = g_list_model_get_item (model, selected);
g_value_set_object (to, item);
g_clear_object (&item);
return TRUE;
}
GtkWidget *
create_color_grid (void)
{
GtkWidget *gridview;
GtkListItemFactory *factory;
GListModel *model, *selection;
gridview = gtk_grid_view_new ();
gtk_scrollable_set_hscroll_policy (GTK_SCROLLABLE (gridview), GTK_SCROLL_NATURAL);
gtk_scrollable_set_vscroll_policy (GTK_SCROLLABLE (gridview), GTK_SCROLL_NATURAL);
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_simple_listitem_cb), NULL);
gtk_grid_view_set_factory (GTK_GRID_VIEW (gridview), factory);
g_object_unref (factory);
gtk_grid_view_set_max_columns (GTK_GRID_VIEW (gridview), 24);
gtk_grid_view_set_enable_rubberband (GTK_GRID_VIEW (gridview), TRUE);
model = G_LIST_MODEL (gtk_sort_list_model_new (create_colors_model (), NULL));
selection = G_LIST_MODEL (gtk_multi_selection_new (model));
gtk_grid_view_set_model (GTK_GRID_VIEW (gridview), selection);
g_object_unref (selection);
g_object_unref (model);
return gridview;
}
static GtkWidget *window = NULL;
GtkWidget *
do_listview_colors (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkWidget *header, *gridview, *sw, *box, *dropdown;
GtkListItemFactory *factory;
GListStore *factories;
GListModel *model;
GtkSorter *sorter;
GtkSorter *multi_sorter;
GListStore *sorters;
GtkExpression *expression;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Colors");
header = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (window), sw);
gridview = create_color_grid ();
gtk_container_add (GTK_CONTAINER (sw), gridview);
model = gtk_grid_view_get_model (GTK_GRID_VIEW (gridview));
g_object_get (model, "model", &model, NULL);
sorters = g_list_store_new (GTK_TYPE_SORTER);
sorter = gtk_string_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "name"));
set_title (sorter, "Name");
g_list_store_append (sorters, sorter);
g_object_unref (sorter);
multi_sorter = gtk_multi_sorter_new ();
sorter = gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "red"));
gtk_numeric_sorter_set_sort_order (GTK_NUMERIC_SORTER (sorter), GTK_SORT_DESCENDING);
set_title (sorter, "Red");
g_list_store_append (sorters, sorter);
gtk_multi_sorter_append (GTK_MULTI_SORTER (multi_sorter), sorter);
sorter = gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "green"));
gtk_numeric_sorter_set_sort_order (GTK_NUMERIC_SORTER (sorter), GTK_SORT_DESCENDING);
set_title (sorter, "Green");
g_list_store_append (sorters, sorter);
gtk_multi_sorter_append (GTK_MULTI_SORTER (multi_sorter), sorter);
sorter = gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "blue"));
gtk_numeric_sorter_set_sort_order (GTK_NUMERIC_SORTER (sorter), GTK_SORT_DESCENDING);
set_title (sorter, "Blue");
g_list_store_append (sorters, sorter);
gtk_multi_sorter_append (GTK_MULTI_SORTER (multi_sorter), sorter);
set_title (multi_sorter, "RGB");
g_list_store_append (sorters, multi_sorter);
g_object_unref (multi_sorter);
multi_sorter = gtk_multi_sorter_new ();
sorter = gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "hue"));
gtk_numeric_sorter_set_sort_order (GTK_NUMERIC_SORTER (sorter), GTK_SORT_DESCENDING);
set_title (sorter, "Hue");
g_list_store_append (sorters, sorter);
gtk_multi_sorter_append (GTK_MULTI_SORTER (multi_sorter), sorter);
sorter = gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "saturation"));
gtk_numeric_sorter_set_sort_order (GTK_NUMERIC_SORTER (sorter), GTK_SORT_DESCENDING);
set_title (sorter, "Saturation");
g_list_store_append (sorters, sorter);
gtk_multi_sorter_append (GTK_MULTI_SORTER (multi_sorter), sorter);
sorter = gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "value"));
gtk_numeric_sorter_set_sort_order (GTK_NUMERIC_SORTER (sorter), GTK_SORT_DESCENDING);
set_title (sorter, "Value");
g_list_store_append (sorters, sorter);
gtk_multi_sorter_append (GTK_MULTI_SORTER (multi_sorter), sorter);
set_title (multi_sorter, "HSV");
g_list_store_append (sorters, multi_sorter);
g_object_unref (multi_sorter);
dropdown = gtk_drop_down_new ();
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
gtk_container_add (GTK_CONTAINER (box), gtk_label_new ("Sort by:"));
gtk_container_add (GTK_CONTAINER (box), dropdown);
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), box);
expression = gtk_cclosure_expression_new (G_TYPE_STRING,
NULL,
0, NULL,
(GCallback)get_title,
NULL, NULL);
gtk_drop_down_set_expression (GTK_DROP_DOWN (dropdown), expression);
gtk_expression_unref (expression);
gtk_drop_down_set_model (GTK_DROP_DOWN (dropdown), G_LIST_MODEL (sorters));
g_object_unref (sorters);
g_object_bind_property_full (dropdown, "selected",
model, "sorter",
G_BINDING_SYNC_CREATE,
set_item, NULL,
NULL, NULL);
factories = g_list_store_new (GTK_TYPE_LIST_ITEM_FACTORY);
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_simple_listitem_cb), NULL);
set_title (factory, "Colors");
g_list_store_append (factories, factory);
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_listitem_cb), NULL);
set_title (factory, "Everything");
g_list_store_append (factories, factory);
dropdown = gtk_drop_down_new ();
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
gtk_container_add (GTK_CONTAINER (box), gtk_label_new ("Show:"));
gtk_container_add (GTK_CONTAINER (box), dropdown);
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), box);
expression = gtk_cclosure_expression_new (G_TYPE_STRING,
NULL,
0, NULL,
(GCallback)get_title,
NULL, NULL);
gtk_drop_down_set_expression (GTK_DROP_DOWN (dropdown), expression);
gtk_expression_unref (expression);
gtk_drop_down_set_model (GTK_DROP_DOWN (dropdown), G_LIST_MODEL (factories));
g_object_unref (factories);
g_object_bind_property_full (dropdown, "selected",
gridview, "factory",
G_BINDING_SYNC_CREATE,
set_item, NULL,
NULL, NULL);
g_object_unref (model);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -0,0 +1,256 @@
/* Lists/File browser
*
* This demo shows off the different layouts that are quickly achievable
* with GtkListview and GtkGridView by implementing a file browser with
* different views.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
static GtkWidget *window = NULL;
/* Create a simple object that holds the data for the different views */
typedef struct _FileBrowserView FileBrowserView;
struct _FileBrowserView
{
GObject parent_instance;
GtkListItemFactory *factory;
char *icon_name;
GtkOrientation orientation;
};
enum {
PROP_0,
PROP_FACTORY,
PROP_ICON_NAME,
PROP_ORIENTATION,
N_PROPS
};
#define FILE_BROWSER_TYPE_VIEW (file_browser_view_get_type ())
G_DECLARE_FINAL_TYPE (FileBrowserView, file_browser_view, FILE_BROWSER, VIEW, GObject);
G_DEFINE_TYPE (FileBrowserView, file_browser_view, G_TYPE_OBJECT);
static GParamSpec *properties[N_PROPS] = { NULL, };
static void
file_browser_view_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
FileBrowserView *self = FILE_BROWSER_VIEW (object);
switch (property_id)
{
case PROP_FACTORY:
g_value_set_object (value, self->factory);
break;
case PROP_ICON_NAME:
g_value_set_string (value, self->icon_name);
break;
case PROP_ORIENTATION:
g_value_set_enum (value, self->orientation);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
file_browser_view_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
FileBrowserView *self = FILE_BROWSER_VIEW (object);
switch (prop_id)
{
case PROP_FACTORY:
g_set_object (&self->factory, g_value_get_object (value));
break;
case PROP_ICON_NAME:
g_free (self->icon_name);
self->icon_name = g_value_dup_string (value);
break;
case PROP_ORIENTATION:
self->orientation = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
file_browser_view_finalize (GObject *object)
{
FileBrowserView *self = FILE_BROWSER_VIEW (object);
g_object_unref (self->factory);
g_free (self->icon_name);
G_OBJECT_CLASS (file_browser_view_parent_class)->dispose (object);
}
static void
file_browser_view_class_init (FileBrowserViewClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = file_browser_view_get_property;
gobject_class->set_property = file_browser_view_set_property;
gobject_class->finalize = file_browser_view_finalize;
properties[PROP_FACTORY] =
g_param_spec_object ("factory",
"factory",
"factory to use in the main view",
GTK_TYPE_LIST_ITEM_FACTORY,
G_PARAM_READWRITE);
properties[PROP_ICON_NAME] =
g_param_spec_string ("icon-name",
"icon name",
"icon to display for selecting this view",
NULL,
G_PARAM_READWRITE);
properties[PROP_ORIENTATION] =
g_param_spec_enum ("orientation",
"orientation",
"orientation of the view",
GTK_TYPE_ORIENTATION,
GTK_ORIENTATION_VERTICAL,
G_PARAM_READWRITE);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void file_browser_view_init (FileBrowserView *self)
{
}
char *
filebrowser_get_display_name (GObject *object,
GFileInfo *info)
{
if (!info)
return NULL;
return g_strdup (g_file_info_get_attribute_string (info, "standard::display-name"));
}
char *
filebrowser_get_content_type (GObject *object,
GFileInfo *info)
{
if (!info)
return NULL;
return g_strdup (g_file_info_get_attribute_string (info, "standard::content-type"));
}
char *
filebrowser_get_size (GObject *object,
GFileInfo *info)
{
if (!info)
return NULL;
return g_format_size (g_file_info_get_attribute_uint64 (info, "standard::size"));
}
GIcon *
filebrowser_get_icon (GObject *object,
GFileInfo *info)
{
GIcon *icon;
if (info)
icon = G_ICON (g_file_info_get_attribute_object (info, "standard::icon"));
else
icon = NULL;
if (icon)
g_object_ref (icon);
return icon;
}
void
filebrowser_up_clicked_cb (GtkButton *button,
GtkDirectoryList *list)
{
GFile *file;
file = g_file_get_parent (gtk_directory_list_get_file (list));
if (file == NULL)
return;
gtk_directory_list_set_file (list, file);
}
void
filebrowser_view_activated_cb (GtkGridView *view,
guint pos,
GtkDirectoryList *list)
{
GFileInfo *info;
info = g_list_model_get_item (gtk_grid_view_get_model (view), pos);
if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
gtk_directory_list_set_file (list, G_FILE (g_file_info_get_attribute_object (info, "standard::file")));
g_object_unref (info);
}
GtkWidget *
do_listview_filebrowser (GtkWidget *do_widget)
{
if (!window)
{
GtkWidget *view;
GtkBuilder *builder;
GtkDirectoryList *dirlist;
GFile *file;
char *cwd;
builder = gtk_builder_new_from_resource ("/listview_filebrowser/listview_filebrowser.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
/* Create the model and fill it with the contents of the current directory */
cwd = g_get_current_dir ();
file = g_file_new_for_path (cwd);
g_free (cwd);
dirlist = GTK_DIRECTORY_LIST (gtk_builder_get_object (builder, "dirlist"));
gtk_directory_list_set_file (dirlist, file);
g_object_unref (file);
/* grab focus in the view */
view = GTK_WIDGET (gtk_builder_get_object (builder, "view"));
gtk_widget_grab_focus (view);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -0,0 +1,240 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GListStore" id="viewlist">
<property name="item-type">FileBrowserView</property>
<child>
<object class="FileBrowserView">
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkBox">
<child>
<object class="GtkImage">
<binding name="gicon">
<closure type="GIcon" function="filebrowser_get_icon">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<binding name="label">
<closure type="gchararray" function="filebrowser_get_display_name">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
</object>
</child>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
<property name="icon-name">view-list-symbolic</property>
<property name="orientation">horizontal</property>
</object>
</child>
<child>
<object class="FileBrowserView">
<property name="icon-name">view-grid-symbolic</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkImage">
<property name="icon-size">large</property>
<binding name="gicon">
<closure type="GIcon" function="filebrowser_get_icon">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="wrap">1</property>
<property name="wrap-mode">word-char</property>
<property name="lines">2</property>
<property name="ellipsize">end</property>
<property name="width-chars">10</property>
<property name="max-width-chars">30</property>
<binding name="label">
<closure type="gchararray" function="filebrowser_get_display_name">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
</object>
</child>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
<property name="orientation">vertical</property>
</object>
</child>
<child>
<object class="FileBrowserView">
<property name="icon-name">view-paged-symbolic</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkBox">
<child>
<object class="GtkImage">
<property name="icon-size">large</property>
<binding name="gicon">
<closure type="GIcon" function="filebrowser_get_icon">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
</object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<binding name="label">
<closure type="gchararray" function="filebrowser_get_display_name">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<binding name="label">
<closure type="gchararray" function="filebrowser_get_size">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<binding name="label">
<closure type="gchararray" function="filebrowser_get_content_type">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
</object>
</child>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
<property name="orientation">horizontal</property>
</object>
</child>
</object>
<object class="GtkDirectoryList" id="dirlist">
<property name="attributes">standard::name,standard::display-name,standard::icon,standard::size,standard::content-type</property>
</object>
<object class="GtkWindow" id="window">
<property name="title" translatable="yes">File browser</property>
<property name="default-width">600</property>
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkButton">
<property name="icon-name">go-up</property>
<signal name="clicked" handler="filebrowser_up_clicked_cb" object="dirlist" swapped="no"/>
</object>
</child>
<child type="end">
<object class="GtkListView">
<property name="valign">center</property>
<property name="orientation">horizontal</property>
<style>
<class name="linked"/>
</style>
<property name="model">
<object class="GtkSingleSelection" id="selected-view">
<property name="model">viewlist</property>
</object>
</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkImage">
<binding name="icon-name">
<lookup type="FileBrowserView" name="icon-name">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="can-focus">1</property>
<child>
<object class="GtkGridView" id="view">
<property name="model">dirlist</property>
<property name="max-columns">15</property>
<binding name="factory">
<lookup name="factory" type="FileBrowserView">
<lookup name="selected-item">selected-view</lookup>
</lookup>
</binding>
<binding name="orientation">
<lookup name="orientation" type="FileBrowserView">
<lookup name="selected-item">selected-view</lookup>
</lookup>
</binding>
<signal name="activate" handler="filebrowser_view_activated_cb" object="dirlist" swapped="no"/>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,473 @@
/* Lists/Minesweeper
*
* This demo shows how to develop a user interface for small game using a
* gridview.
*
* It demonstrates how to use the activate signal and single-press behavior
* to implement rather different interaction behavior to a typical list.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
/*** The cell object ***/
/* Create an object that holds the data for a cell in the game */
typedef struct _SweeperCell SweeperCell;
struct _SweeperCell
{
GObject parent_instance;
gboolean is_mine;
gboolean is_visible;
guint neighbor_mines;
};
enum {
CELL_PROP_0,
CELL_PROP_LABEL,
N_CELL_PROPS
};
#define SWEEPER_TYPE_CELL (sweeper_cell_get_type ())
G_DECLARE_FINAL_TYPE (SweeperCell, sweeper_cell, SWEEPER, CELL, GObject);
G_DEFINE_TYPE (SweeperCell, sweeper_cell, G_TYPE_OBJECT);
static GParamSpec *cell_properties[N_CELL_PROPS] = { NULL, };
static const char *
sweeper_cell_get_label (SweeperCell *self)
{
static const char *minecount_labels[10] = { "", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
if (!self->is_visible)
return "?";
if (self->is_mine)
return "💣";
return minecount_labels[self->neighbor_mines];
}
static void
sweeper_cell_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
SweeperCell *self = SWEEPER_CELL (object);
switch (property_id)
{
case CELL_PROP_LABEL:
g_value_set_string (value, sweeper_cell_get_label (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
sweeper_cell_class_init (SweeperCellClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = sweeper_cell_get_property;
cell_properties[CELL_PROP_LABEL] =
g_param_spec_string ("label",
"label",
"label to display for this row",
NULL,
G_PARAM_READABLE);
g_object_class_install_properties (gobject_class, N_CELL_PROPS, cell_properties);
}
static void
sweeper_cell_init (SweeperCell *self)
{
}
static void
sweeper_cell_reveal (SweeperCell *self)
{
if (self->is_visible)
return;
self->is_visible = TRUE;
g_object_notify_by_pspec (G_OBJECT (self), cell_properties[CELL_PROP_LABEL]);
}
static SweeperCell *
sweeper_cell_new ()
{
return g_object_new (SWEEPER_TYPE_CELL, NULL);
}
/*** The board object ***/
/* Create an object that holds the data for the game */
typedef struct _SweeperGame SweeperGame;
struct _SweeperGame
{
GObject parent_instance;
GPtrArray *cells;
guint width;
guint height;
gboolean playing;
gboolean win;
};
enum {
GAME_PROP_0,
GAME_PROP_HEIGHT,
GAME_PROP_PLAYING,
GAME_PROP_WIDTH,
GAME_PROP_WIN,
N_GAME_PROPS
};
#define SWEEPER_TYPE_GAME (sweeper_game_get_type ())
G_DECLARE_FINAL_TYPE (SweeperGame, sweeper_game, SWEEPER, GAME, GObject);
static GType
sweeper_game_list_model_get_item_type (GListModel *model)
{
return SWEEPER_TYPE_GAME;
}
static guint
sweeper_game_list_model_get_n_items (GListModel *model)
{
SweeperGame *self = SWEEPER_GAME (model);
return self->width * self->height;
}
static gpointer
sweeper_game_list_model_get_item (GListModel *model,
guint position)
{
SweeperGame *self = SWEEPER_GAME (model);
return g_object_ref (g_ptr_array_index (self->cells, position));
}
static void
sweeper_game_list_model_init (GListModelInterface *iface)
{
iface->get_item_type = sweeper_game_list_model_get_item_type;
iface->get_n_items = sweeper_game_list_model_get_n_items;
iface->get_item = sweeper_game_list_model_get_item;
}
G_DEFINE_TYPE_WITH_CODE (SweeperGame, sweeper_game, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, sweeper_game_list_model_init))
static GParamSpec *game_properties[N_GAME_PROPS] = { NULL, };
static void
sweeper_game_dispose (GObject *object)
{
SweeperGame *self = SWEEPER_GAME (object);
g_clear_pointer (&self->cells, g_ptr_array_unref);
G_OBJECT_CLASS (sweeper_game_parent_class)->dispose (object);
}
static void
sweeper_game_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
SweeperGame *self = SWEEPER_GAME (object);
switch (property_id)
{
case GAME_PROP_HEIGHT:
g_value_set_uint (value, self->height);
break;
case GAME_PROP_PLAYING:
g_value_set_boolean (value, self->playing);
break;
case GAME_PROP_WIDTH:
g_value_set_uint (value, self->width);
break;
case GAME_PROP_WIN:
g_value_set_boolean (value, self->win);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
sweeper_game_class_init (SweeperGameClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = sweeper_game_dispose;
gobject_class->get_property = sweeper_game_get_property;
game_properties[GAME_PROP_HEIGHT] =
g_param_spec_uint ("height",
"height",
"height of the game grid",
1, G_MAXUINT, 8,
G_PARAM_READABLE);
game_properties[GAME_PROP_PLAYING] =
g_param_spec_boolean ("playing",
"playing",
"if the game is still going on",
FALSE,
G_PARAM_READABLE);
game_properties[GAME_PROP_WIDTH] =
g_param_spec_uint ("width",
"width",
"width of the game grid",
1, G_MAXUINT, 8,
G_PARAM_READABLE);
game_properties[GAME_PROP_WIN] =
g_param_spec_boolean ("win",
"win",
"if the game was won",
FALSE,
G_PARAM_READABLE);
g_object_class_install_properties (gobject_class, N_GAME_PROPS, game_properties);
}
static void
sweeper_game_reset_board (SweeperGame *self,
guint width,
guint height)
{
guint i;
g_ptr_array_set_size (self->cells, 0);
for (i = 0; i < width * height; i++)
{
g_ptr_array_add (self->cells, sweeper_cell_new ());
}
if (self->width != width)
{
self->width = width;
g_object_notify_by_pspec (G_OBJECT (self), game_properties[GAME_PROP_WIDTH]);
}
if (self->height != height)
{
self->height = height;
g_object_notify_by_pspec (G_OBJECT (self), game_properties[GAME_PROP_HEIGHT]);
}
if (!self->playing)
{
self->playing = TRUE;
g_object_notify_by_pspec (G_OBJECT (self), game_properties[GAME_PROP_PLAYING]);
}
if (self->win)
{
self->win = FALSE;
g_object_notify_by_pspec (G_OBJECT (self), game_properties[GAME_PROP_WIN]);
}
}
static void
sweeper_game_place_mines (SweeperGame *self,
guint n_mines)
{
guint i;
for (i = 0; i < n_mines; i++)
{
SweeperCell *cell;
do {
cell = g_ptr_array_index (self->cells, g_random_int_range (0, self->cells->len));
} while (cell->is_mine);
cell->is_mine = TRUE;
}
}
static SweeperCell *
get_cell (SweeperGame *self,
guint x,
guint y)
{
return g_ptr_array_index (self->cells, y * self->width + x);
}
static void
sweeper_game_count_neighbor_mines (SweeperGame *self,
guint width,
guint height)
{
guint x, y, x2, y2;
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
SweeperCell *cell = get_cell (self, x, y);
for (y2 = MAX (1, y) - 1; y2 < MIN (height, y + 2); y2++)
{
for (x2 = MAX (1, x) - 1; x2 < MIN (width, x + 2); x2++)
{
SweeperCell *other = get_cell (self, x2, y2);
if (other->is_mine)
cell->neighbor_mines++;
}
}
}
}
}
static void
sweeper_game_new_game (SweeperGame *self,
guint width,
guint height,
guint n_mines)
{
guint n_items_before;
g_return_if_fail (n_mines <= width * height);
n_items_before = self->width * self->height;
g_object_freeze_notify (G_OBJECT (self));
sweeper_game_reset_board (self, width, height);
sweeper_game_place_mines (self, n_mines);
sweeper_game_count_neighbor_mines (self, width, height);
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items_before, width * height);
g_object_thaw_notify (G_OBJECT (self));
}
static void
sweeper_game_init (SweeperGame *self)
{
self->cells = g_ptr_array_new_with_free_func (g_object_unref);
sweeper_game_new_game (self, 8, 8, 10);
}
static void
sweeper_game_end (SweeperGame *self,
gboolean win)
{
if (self->playing)
{
self->playing = FALSE;
g_object_notify_by_pspec (G_OBJECT (self), game_properties[GAME_PROP_PLAYING]);
}
if (self->win != win)
{
self->win = win;
g_object_notify_by_pspec (G_OBJECT (self), game_properties[GAME_PROP_WIN]);
}
}
static void
sweeper_game_check_finished (SweeperGame *self)
{
guint i;
if (!self->playing)
return;
for (i = 0; i < self->cells->len; i++)
{
SweeperCell *cell = g_ptr_array_index (self->cells, i);
/* There's still a non-revealed cell that isn't a mine */
if (!cell->is_visible && !cell->is_mine)
return;
}
sweeper_game_end (self, TRUE);
}
static void
sweeper_game_reveal_cell (SweeperGame *self,
guint position)
{
SweeperCell *cell;
if (!self->playing)
return;
cell = g_ptr_array_index (self->cells, position);
sweeper_cell_reveal (cell);
if (cell->is_mine)
sweeper_game_end (self, FALSE);
sweeper_game_check_finished (self);
}
void
minesweeper_cell_clicked_cb (GtkGridView *gridview,
guint pos,
SweeperGame *game)
{
sweeper_game_reveal_cell (game, pos);
}
void
minesweeper_new_game_cb (GtkButton *button,
SweeperGame *game)
{
sweeper_game_new_game (game, 8, 8, 10);
}
static GtkWidget *window = NULL;
GtkWidget *
do_listview_minesweeper (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkBuilder *builder;
g_type_ensure (SWEEPER_TYPE_GAME);
builder = gtk_builder_new_from_resource ("/listview_minesweeper/listview_minesweeper.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="SweeperGame" id="game">
</object>
<object class="GtkWindow" id="window">
<property name="title" translatable="yes">Minesweeper</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkButton">
<property name="label">New Game</property>
<signal name="clicked" handler="minesweeper_new_game_cb" object="game" swapped="no"/>
</object>
</child>
<child type="title">
<object class="GtkImage">
<property name="icon-name">trophy-gold</property>
<binding name="visible">
<lookup name="win">game</lookup>
</binding>
</object>
</child>
</object>
</child>
<child>
<object class="GtkGridView" id="view">
<property name="model">
<object class="GtkNoSelection">
<property name="model">game</property>
</object>
</property>
<binding name="max-columns">
<lookup name="width">game</lookup>
</binding>
<binding name="min-columns">
<lookup name="width">game</lookup>
</binding>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="resource">/listview_minesweeper/listview_minesweeper_cell.ui</property>
</object>
</property>
<signal name="activate" handler="minesweeper_cell_clicked_cb" object="game" swapped="no"/>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<property name="halign">center</property>
<property name="valign">center</property>
<binding name="label">
<lookup name="label" type="SweeperCell">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>

View File

@@ -0,0 +1,398 @@
/* Lists/Settings
*
* This demo shows a settings viewer for GSettings.
*
* It demonstrates how to implement support for trees with GtkListView.
*
* It also shows how to set up sorting for columns in a GtkColumnView.
*/
#include <gtk/gtk.h>
/* Create an object that wraps GSettingsSchemaKey because that's a boxed type */
typedef struct _SettingsKey SettingsKey;
struct _SettingsKey
{
GObject parent_instance;
GSettings *settings;
GSettingsSchemaKey *key;
};
enum {
PROP_0,
PROP_NAME,
PROP_SUMMARY,
PROP_DESCRIPTION,
PROP_VALUE,
N_PROPS
};
#define SETTINGS_TYPE_KEY (settings_key_get_type ())
G_DECLARE_FINAL_TYPE (SettingsKey, settings_key, SETTINGS, KEY, GObject);
G_DEFINE_TYPE (SettingsKey, settings_key, G_TYPE_OBJECT);
static GParamSpec *properties[N_PROPS] = { NULL, };
static void
settings_key_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
SettingsKey *self = SETTINGS_KEY (object);
switch (property_id)
{
case PROP_DESCRIPTION:
g_value_set_string (value, g_settings_schema_key_get_description (self->key));
break;
case PROP_NAME:
g_value_set_string (value, g_settings_schema_key_get_name (self->key));
break;
case PROP_SUMMARY:
g_value_set_string (value, g_settings_schema_key_get_summary (self->key));
break;
case PROP_VALUE:
{
GVariant *variant = g_settings_get_value (self->settings, g_settings_schema_key_get_name (self->key));
g_value_take_string (value, g_variant_print (variant, FALSE));
g_variant_unref (variant);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
settings_key_finalize (GObject *object)
{
SettingsKey *self = SETTINGS_KEY (object);
g_object_unref (self->settings);
g_settings_schema_key_unref (self->key);
G_OBJECT_CLASS (settings_key_parent_class)->finalize (object);
}
static void
settings_key_class_init (SettingsKeyClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = settings_key_finalize;
gobject_class->get_property = settings_key_get_property;
properties[PROP_DESCRIPTION] =
g_param_spec_string ("description", NULL, NULL, NULL, G_PARAM_READABLE);
properties[PROP_NAME] =
g_param_spec_string ("name", NULL, NULL, NULL, G_PARAM_READABLE);
properties[PROP_SUMMARY] =
g_param_spec_string ("summary", NULL, NULL, NULL, G_PARAM_READABLE);
properties[PROP_VALUE] =
g_param_spec_string ("value", NULL, NULL, NULL, G_PARAM_READABLE);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void
settings_key_init (SettingsKey *self)
{
}
static SettingsKey *
settings_key_new (GSettings *settings,
GSettingsSchemaKey *key)
{
SettingsKey *result = g_object_new (SETTINGS_TYPE_KEY, NULL);
result->settings = g_object_ref (settings);
result->key = g_settings_schema_key_ref (key);
return result;
}
static int
strvcmp (gconstpointer p1,
gconstpointer p2)
{
const char * const *s1 = p1;
const char * const *s2 = p2;
return strcmp (*s1, *s2);
}
static GtkFilter *current_filter;
static gboolean
transform_settings_to_keys (GBinding *binding,
const GValue *from_value,
GValue *to_value,
gpointer data)
{
GtkTreeListRow *treelistrow;
GSettings *settings;
GSettingsSchema *schema;
GListStore *store;
GtkSortListModel *sort_model;
GtkFilterListModel *filter_model;
GtkFilter *filter;
GtkExpression *expression;
char **keys;
guint i;
treelistrow = g_value_get_object (from_value);
if (treelistrow == NULL)
return TRUE;
settings = gtk_tree_list_row_get_item (treelistrow);
g_object_get (settings, "settings-schema", &schema, NULL);
store = g_list_store_new (SETTINGS_TYPE_KEY);
keys = g_settings_schema_list_keys (schema);
for (i = 0; keys[i] != NULL; i++)
{
GSettingsSchemaKey *almost_there = g_settings_schema_get_key (schema, keys[i]);
SettingsKey *finally = settings_key_new (settings, almost_there);
g_list_store_append (store, finally);
g_object_unref (finally);
g_settings_schema_key_unref (almost_there);
}
g_strfreev (keys);
g_settings_schema_unref (schema);
g_object_unref (settings);
sort_model = gtk_sort_list_model_new (G_LIST_MODEL (store),
gtk_column_view_get_sorter (GTK_COLUMN_VIEW (data)));
g_object_unref (store);
expression = gtk_property_expression_new (SETTINGS_TYPE_KEY, NULL, "name");
filter = gtk_string_filter_new ();
gtk_string_filter_set_expression (GTK_STRING_FILTER (filter), expression);
filter_model = gtk_filter_list_model_new (G_LIST_MODEL (sort_model), filter);
gtk_expression_unref (expression);
g_object_unref (sort_model);
g_set_object (&current_filter, filter);
g_object_unref (filter);
g_value_take_object (to_value, filter_model);
return TRUE;
}
static GListModel *
create_settings_model (gpointer item,
gpointer unused)
{
GSettings *settings = item;
char **schemas;
GListStore *result;
guint i;
if (settings == NULL)
{
g_settings_schema_source_list_schemas (g_settings_schema_source_get_default (),
TRUE,
&schemas,
NULL);
}
else
{
schemas = g_settings_list_children (settings);
}
if (schemas == NULL || schemas[0] == NULL)
{
g_free (schemas);
return NULL;
}
qsort (schemas, g_strv_length (schemas), sizeof (char *), strvcmp);
result = g_list_store_new (G_TYPE_SETTINGS);
for (i = 0; schemas[i] != NULL; i++)
{
GSettings *child;
if (settings == NULL)
child = g_settings_new (schemas[i]);
else
child = g_settings_get_child (settings, schemas[i]);
g_list_store_append (result, child);
g_object_unref (child);
}
g_strfreev (schemas);
return G_LIST_MODEL (result);
}
static void
search_enabled (GtkSearchEntry *entry)
{
gtk_editable_set_text (GTK_EDITABLE (entry), "");
}
static void
search_changed (GtkSearchEntry *entry,
gpointer data)
{
const char *text = gtk_editable_get_text (GTK_EDITABLE (entry));
if (current_filter)
gtk_string_filter_set_search (GTK_STRING_FILTER (current_filter), text);
}
static void
stop_search (GtkSearchEntry *entry,
gpointer data)
{
gtk_editable_set_text (GTK_EDITABLE (entry), "");
if (current_filter)
gtk_string_filter_set_search (GTK_STRING_FILTER (current_filter), "");
}
static void
move_column (GtkListView *columns_list, gboolean down)
{
GListModel *columns;
guint position;
GtkColumnViewColumn *selected;
GtkColumnView *view;
columns = gtk_list_view_get_model (columns_list);
position = gtk_single_selection_get_selected (GTK_SINGLE_SELECTION (columns));
selected = gtk_single_selection_get_selected_item (GTK_SINGLE_SELECTION (columns));
view = gtk_column_view_column_get_column_view (selected);
if (down && position + 1 < g_list_model_get_n_items (columns))
position++;
else if (!down && position > 0)
position--;
else
return;
gtk_column_view_insert_column (view, position, selected);
gtk_single_selection_set_selected (GTK_SINGLE_SELECTION (columns), position);
}
static void
move_column_down (GtkListView *columns_list)
{
move_column (columns_list, TRUE);
}
static void
move_column_up (GtkListView *columns_list)
{
move_column (columns_list, FALSE);
}
static void
column_visible_toggled (GtkListItem *item, GtkToggleButton *button)
{
GtkColumnViewColumn *column = gtk_list_item_get_item (item);
gtk_column_view_column_set_visible (column, gtk_toggle_button_get_active (button));
}
static GtkWidget *window = NULL;
GtkWidget *
do_listview_settings (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkWidget *listview, *columnview;
GListModel *model;
GtkTreeListModel *treemodel;
GtkSingleSelection *selection;
GtkBuilderScope *scope;
GtkBuilder *builder;
GtkColumnViewColumn *name_column;
GtkSorter *sorter;
GtkWidget *menubutton, *popover;
GtkWidget *columns_list;
g_type_ensure (SETTINGS_TYPE_KEY);
scope = gtk_builder_cscope_new ();
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope), "search_enabled", (GCallback)search_enabled);
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope), "search_changed", (GCallback)search_changed);
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope), "stop_search", (GCallback)stop_search);
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope), "move_column_down", (GCallback)move_column_down);
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope), "move_column_up", (GCallback)move_column_up);
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope), "column_visible_toggled", (GCallback)column_visible_toggled);
builder = gtk_builder_new ();
gtk_builder_set_scope (builder, scope);
{
g_autoptr(GError) error = NULL;
gtk_builder_add_from_resource (builder, "/listview_settings/listview_settings.ui", &error);
if (error)
g_warning ("%s", error->message);
}
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
listview = GTK_WIDGET (gtk_builder_get_object (builder, "listview"));
columnview = GTK_WIDGET (gtk_builder_get_object (builder, "columnview"));
model = create_settings_model (NULL, NULL);
treemodel = gtk_tree_list_model_new (FALSE,
model,
TRUE,
create_settings_model,
NULL,
NULL);
selection = gtk_single_selection_new (G_LIST_MODEL (treemodel));
g_object_bind_property_full (selection, "selected-item",
columnview, "model",
G_BINDING_SYNC_CREATE,
transform_settings_to_keys,
NULL,
columnview, NULL);
gtk_list_view_set_model (GTK_LIST_VIEW (listview), G_LIST_MODEL (selection));
g_object_unref (selection);
g_object_unref (treemodel);
g_object_unref (model);
name_column = GTK_COLUMN_VIEW_COLUMN (gtk_builder_get_object (builder, "name_column"));
sorter = gtk_string_sorter_new (gtk_property_expression_new (SETTINGS_TYPE_KEY, NULL, "name"));
gtk_column_view_column_set_sorter (name_column, sorter);
g_object_unref (sorter);
menubutton = GTK_WIDGET (gtk_builder_get_object (builder, "menubutton"));
popover = GTK_WIDGET (gtk_builder_get_object (builder, "column_popover"));
gtk_menu_button_set_popover (GTK_MENU_BUTTON (menubutton), popover);
columns_list = GTK_WIDGET (gtk_builder_get_object (builder, "columns_list"));
model = G_LIST_MODEL (gtk_single_selection_new (gtk_column_view_get_columns (GTK_COLUMN_VIEW (columnview))));
gtk_list_view_set_model (GTK_LIST_VIEW (columns_list), model);
g_object_unref (model);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -0,0 +1,262 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow" id="window">
<property name="title" translatable="yes">Settings</property>
<property name="default-width">640</property>
<property name="default-height">480</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="show-title-buttons">1</property>
<child type="end">
<object class="GtkMenuButton" id="menubutton">
<property name="icon-name">open-menu-symbolic</property>
</object>
</child>
<child type="end">
<object class="GtkToggleButton" id="search_button">
<property name="icon-name">system-search-symbolic</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkPaned">
<property name="position">300</property>
<child>
<object class="GtkScrolledWindow">
<child>
<object class="GtkListView" id="listview">
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkTreeExpander" id="expander">
<binding name="list-row">
<lookup name="item">GtkListItem</lookup>
</binding>
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<binding name="label">
<lookup name="schema" type="GSettings">
<lookup name="item">expander</lookup>
</lookup>
</binding>
</object>
</property>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkSearchBar">
<property name="search-mode-enabled" bind-source="search_button" bind-property="active" bind-flags="bidirectional"/>
<signal name="notify::search-mode-enabled" handler="search_enabled" object="entry"/>
<child>
<object class="GtkSearchEntry" id="entry">
<signal name="search-changed" handler="search_changed"/>
<signal name="stop-search" handler="stop_search"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="expand">1</property>
<child>
<object class="GtkColumnView" id="columnview">
<child>
<object class="GtkColumnViewColumn" id="name_column">
<property name="title">Name</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<binding name="label">
<lookup name="name" type="SettingsKey">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkColumnViewColumn" id="value_column">
<property name="title">Value</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<binding name="label">
<lookup name="value" type="SettingsKey">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkColumnViewColumn" id="summary_column">
<property name="title">Summary</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<binding name="label">
<lookup name="summary" type="SettingsKey">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkColumnViewColumn" id="description_column">
<property name="title">Description</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<binding name="label">
<lookup name="description" type="SettingsKey">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<object class="GtkPopover" id="column_popover">
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkListView" id="columns_list">
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkBox">
<property name="spacing">10</property>
<child>
<object class="GtkCheckButton">
<signal name="toggled" handler="column_visible_toggled" object="GtkListItem"/>
<binding name="active">
<lookup name="visible" type="GtkColumnViewColumn">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="xalign">0</property>
<property name="label">label</property>
<binding name="label">
<lookup name="title" type="GtkColumnViewColumn">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</child>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkBox">
<property name="halign">center</property>
<style>
<class name="linked"/>
</style>
<child>
<object class="GtkButton">
<property name="icon-name">go-down-symbolic</property>
<signal name="clicked" handler="move_column_down" object="columns_list"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="icon-name">go-up-symbolic</property>
<signal name="clicked" handler="move_column_up" object="columns_list"/>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,329 @@
/* Lists/Weather
*
* This demo shows a few of the rarer features of GtkListView and
* how they can be used to display weather information.
*
* The hourly weather info uses a horizontal listview. This is easy
* to achieve because GtkListView implements the GtkOrientable interface.
* To make the items in the list stand out more, the listview uses
* separators.
*
* A GtkNoSelectionModel is used to make sure no item in the list can be
* selected. All other interactions with the items is still possible.
*
* The dataset used here has 70000 items.
*/
#include <gtk/gtk.h>
#define GTK_TYPE_WEATHER_INFO (gtk_weather_info_get_type ())
G_DECLARE_FINAL_TYPE (GtkWeatherInfo, gtk_weather_info, GTK, WEATHER_INFO, GObject)
typedef enum {
GTK_WEATHER_CLEAR,
GTK_WEATHER_FEW_CLOUDS,
GTK_WEATHER_FOG,
GTK_WEATHER_OVERCAST,
GTK_WEATHER_SCATTERED_SHOWERS,
GTK_WEATHER_SHOWERS,
GTK_WEATHER_SNOW,
GTK_WEATHER_STORM
} GtkWeatherType;
struct _GtkWeatherInfo
{
GObject parent_instance;
gint64 timestamp;
int temperature;
GtkWeatherType weather_type;
};
struct _GtkWeatherInfoClass
{
GObjectClass parent_class;
};
static void
gtk_weather_info_class_init (GtkWeatherInfoClass *klass)
{
}
static void
gtk_weather_info_init (GtkWeatherInfo *self)
{
}
G_DEFINE_TYPE (GtkWeatherInfo, gtk_weather_info, G_TYPE_OBJECT);
static GtkWeatherInfo *
gtk_weather_info_new (GDateTime *timestamp,
GtkWeatherInfo *copy_from)
{
GtkWeatherInfo *result;
result = g_object_new (GTK_TYPE_WEATHER_INFO, NULL);
result->timestamp = g_date_time_to_unix (timestamp);
if (copy_from)
{
result->temperature = copy_from->temperature;
result->weather_type = copy_from->weather_type;
g_object_unref (copy_from);
}
return result;
}
static GDateTime *
parse_timestamp (const char *string,
GTimeZone *timezone)
{
char *with_seconds;
GDateTime *result;
with_seconds = g_strconcat (string, ":00", NULL);
result = g_date_time_new_from_iso8601 (with_seconds, timezone);
g_free (with_seconds);
return result;
}
static GtkWeatherType
parse_weather_type (const char *clouds,
const char *precip,
GtkWeatherType fallback)
{
if (strstr (precip, "SN"))
return GTK_WEATHER_SNOW;
if (strstr (precip, "TS"))
return GTK_WEATHER_STORM;
if (strstr (precip, "DZ"))
return GTK_WEATHER_SCATTERED_SHOWERS;
if (strstr (precip, "SH") || strstr (precip, "RA"))
return GTK_WEATHER_SHOWERS;
if (strstr (precip, "FG"))
return GTK_WEATHER_FOG;
if (g_str_equal (clouds, "M") ||
g_str_equal (clouds, ""))
return fallback;
if (strstr (clouds, "OVC") ||
strstr (clouds, "BKN"))
return GTK_WEATHER_OVERCAST;
if (strstr (clouds, "BKN") ||
strstr (clouds, "SCT"))
return GTK_WEATHER_FEW_CLOUDS;
if (strstr (clouds, "VV"))
return GTK_WEATHER_FOG;
return GTK_WEATHER_CLEAR;
}
static double
parse_temperature (const char *s,
double fallback)
{
char *endptr;
double d;
d = g_ascii_strtod (s, &endptr);
if (*endptr != '\0')
return fallback;
return d;
}
static GListModel *
create_weather_model (void)
{
GListStore *store;
GTimeZone *utc;
GDateTime *timestamp;
GtkWeatherInfo *info;
GBytes *data;
char **lines;
guint i;
store = g_list_store_new (GTK_TYPE_WEATHER_INFO);
data = g_resources_lookup_data ("/listview_weather/listview_weather.txt", 0, NULL);
lines = g_strsplit (g_bytes_get_data (data, NULL), "\n", 0);
utc = g_time_zone_new_utc ();
timestamp = g_date_time_new (utc, 2011, 1, 1, 0, 0, 0);
info = gtk_weather_info_new (timestamp, NULL);
g_list_store_append (store, info);
for (i = 0; lines[i] != NULL && *lines[i]; i++)
{
char **fields;
GDateTime *date;
fields = g_strsplit (lines[i], ",", 0);
date = parse_timestamp (fields[0], utc);
while (g_date_time_difference (date, timestamp) > 30 * G_TIME_SPAN_MINUTE)
{
GDateTime *new_timestamp = g_date_time_add_hours (timestamp, 1);
g_date_time_unref (timestamp);
timestamp = new_timestamp;
info = gtk_weather_info_new (timestamp, info);
g_list_store_append (store, info);
}
info->temperature = parse_temperature (fields[1], info->temperature);
info->weather_type = parse_weather_type (fields[2], fields[3], info->weather_type);
g_date_time_unref (date);
g_strfreev (fields);
}
g_strfreev (lines);
g_bytes_unref (data);
g_time_zone_unref (utc);
return G_LIST_MODEL (store);
}
static void
setup_widget (GtkListItem *list_item,
gpointer unused)
{
GtkWidget *box, *child;
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_list_item_set_child (list_item, box);
child = gtk_label_new (NULL);
gtk_label_set_width_chars (GTK_LABEL (child), 5);
gtk_container_add (GTK_CONTAINER (box), child);
child = gtk_image_new ();
gtk_image_set_icon_size (GTK_IMAGE (child), GTK_ICON_SIZE_LARGE);
gtk_container_add (GTK_CONTAINER (box), child);
child = gtk_label_new (NULL);
gtk_widget_set_vexpand (child, TRUE);
gtk_widget_set_valign (child, GTK_ALIGN_END);
gtk_label_set_width_chars (GTK_LABEL (child), 4);
gtk_container_add (GTK_CONTAINER (box), child);
}
static void
bind_widget (GtkListItem *list_item,
gpointer unused)
{
GtkWidget *box, *child;
GtkWeatherInfo *info;
GDateTime *timestamp;
char *s;
box = gtk_list_item_get_child (list_item);
info = gtk_list_item_get_item (list_item);
child = gtk_widget_get_first_child (box);
timestamp = g_date_time_new_from_unix_utc (info->timestamp);
s = g_date_time_format (timestamp, "%R");
gtk_label_set_text (GTK_LABEL (child), s);
g_free (s);
g_date_time_unref (timestamp);
child = gtk_widget_get_next_sibling (child);
switch (info->weather_type)
{
case GTK_WEATHER_CLEAR:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-clear-symbolic");
break;
case GTK_WEATHER_FEW_CLOUDS:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-few-clouds-symbolic");
break;
case GTK_WEATHER_FOG:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-fog-symbolic");
break;
case GTK_WEATHER_OVERCAST:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-overcast-symbolic");
break;
case GTK_WEATHER_SCATTERED_SHOWERS:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-showers-scattered-symbolic");
break;
case GTK_WEATHER_SHOWERS:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-showers-symbolic");
break;
case GTK_WEATHER_SNOW:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-snow-symbolic");
break;
case GTK_WEATHER_STORM:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-storm-symbolic");
break;
default:
gtk_image_clear (GTK_IMAGE (child));
break;
}
child = gtk_widget_get_next_sibling (child);
s = g_strdup_printf ("%d°", info->temperature);
gtk_label_set_text (GTK_LABEL (child), s);
g_free (s);
}
static GtkWidget *window = NULL;
GtkWidget *
create_weather_view (void)
{
GtkWidget *listview;
GListModel *model, *selection;
listview = gtk_list_view_new_with_factory (
gtk_functions_list_item_factory_new (setup_widget,
bind_widget,
NULL, NULL));
gtk_orientable_set_orientation (GTK_ORIENTABLE (listview), GTK_ORIENTATION_HORIZONTAL);
gtk_list_view_set_show_separators (GTK_LIST_VIEW (listview), TRUE);
model = create_weather_model ();
selection = G_LIST_MODEL (gtk_no_selection_new (model));
gtk_list_view_set_model (GTK_LIST_VIEW (listview), selection);
g_object_unref (selection);
g_object_unref (model);
return listview;
}
GtkWidget *
do_listview_weather (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkWidget *listview, *sw;;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
gtk_window_set_title (GTK_WINDOW (window), "Weather");
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Weather");
g_signal_connect (window, "destroy",
G_CALLBACK(gtk_widget_destroyed), &window);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (window), sw);
listview = create_weather_view ();
gtk_container_add (GTK_CONTAINER (sw), listview);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkTreeExpander" id="expander">
<binding name="list-row">
<lookup name="item">GtkListItem</lookup>
</binding>
<property name="child">
<object class="GtkLabel">
<property name="halign">start</property>
<binding name="label">
<lookup name="title" type="GtkDemo">
<lookup name="item">expander</lookup>
</lookup>
</binding>
</object>
</property>
</object>
</property>
</template>
</interface>

View File

@@ -8,6 +8,7 @@
#include <gtk/gtk.h>
#include <glib/gstdio.h>
#include "award.h"
#include "demos.h"
static GtkWidget *info_view;
@@ -15,19 +16,99 @@ static GtkWidget *source_view;
static gchar *current_file = NULL;
static GtkWidget *window;
static GtkWidget *notebook;
static GtkWidget *treeview;
static GtkWidget *listview;
static GtkSingleSelection *selection;
static GtkWidget *headerbar;
enum {
NAME_COLUMN,
TITLE_COLUMN,
FILENAME_COLUMN,
FUNC_COLUMN,
STYLE_COLUMN,
NUM_COLUMNS
typedef struct _GtkDemo GtkDemo;
struct _GtkDemo
{
GObject parent_instance;
const char *name;
const char *title;
const char *filename;
GDoDemoFunc func;
GListModel *children_model;
};
enum {
PROP_0,
PROP_FILENAME,
PROP_NAME,
PROP_TITLE,
N_PROPS
};
# define GTK_TYPE_DEMO (gtk_demo_get_type ())
G_DECLARE_FINAL_TYPE (GtkDemo, gtk_demo, GTK, DEMO, GObject);
G_DEFINE_TYPE (GtkDemo, gtk_demo, G_TYPE_OBJECT);
static GParamSpec *properties[N_PROPS] = { NULL, };
static void
gtk_demo_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GtkDemo *self = GTK_DEMO (object);
switch (property_id)
{
case PROP_FILENAME:
g_value_set_string (value, self->filename);
break;
case PROP_NAME:
g_value_set_string (value, self->name);
break;
case PROP_TITLE:
g_value_set_string (value, self->title);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void gtk_demo_class_init (GtkDemoClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gtk_demo_get_property;
properties[PROP_FILENAME] =
g_param_spec_string ("filename",
"filename",
"filename",
NULL,
G_PARAM_READABLE);
properties[PROP_NAME] =
g_param_spec_string ("name",
"name",
"name",
NULL,
G_PARAM_READABLE);
properties[PROP_TITLE] =
g_param_spec_string ("title",
"title",
"title",
NULL,
G_PARAM_READABLE);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void gtk_demo_init (GtkDemo *self)
{
}
typedef struct _CallbackData CallbackData;
struct _CallbackData
{
@@ -35,6 +116,27 @@ struct _CallbackData
GtkTreePath *path;
};
static gboolean
gtk_demo_run (GtkDemo *self,
GtkWidget *window)
{
GtkWidget *result;
if (!self->func)
return FALSE;
result = self->func (window);
if (result == NULL)
return FALSE;
if (GTK_IS_WINDOW (result))
{
gtk_window_set_transient_for (GTK_WINDOW (result), GTK_WINDOW (window));
gtk_window_set_modal (GTK_WINDOW (result), TRUE);
}
return TRUE;
}
static void
activate_about (GSimpleAction *action,
GVariant *parameter,
@@ -111,69 +213,7 @@ activate_inspector (GSimpleAction *action,
gpointer user_data)
{
gtk_window_set_interactive_debugging (TRUE);
}
static void
window_closed_cb (GtkWidget *window, gpointer data)
{
CallbackData *cbdata = data;
GtkTreeIter iter;
PangoStyle style;
gtk_tree_model_get_iter (cbdata->model, &iter, cbdata->path);
gtk_tree_model_get (GTK_TREE_MODEL (cbdata->model), &iter,
STYLE_COLUMN, &style,
-1);
if (style == PANGO_STYLE_ITALIC)
gtk_tree_store_set (GTK_TREE_STORE (cbdata->model), &iter,
STYLE_COLUMN, PANGO_STYLE_NORMAL,
-1);
gtk_tree_path_free (cbdata->path);
g_free (cbdata);
}
static void
run_example_for_row (GtkWidget *window,
GtkTreeModel *model,
GtkTreeIter *iter)
{
PangoStyle style;
GDoDemoFunc func;
GtkWidget *demo;
gtk_tree_model_get (GTK_TREE_MODEL (model),
iter,
FUNC_COLUMN, &func,
STYLE_COLUMN, &style,
-1);
if (func)
{
gtk_tree_store_set (GTK_TREE_STORE (model),
iter,
STYLE_COLUMN, (style == PANGO_STYLE_ITALIC ? PANGO_STYLE_NORMAL : PANGO_STYLE_ITALIC),
-1);
demo = (func) (window);
if (demo != NULL)
{
CallbackData *cbdata;
cbdata = g_new (CallbackData, 1);
cbdata->model = model;
cbdata->path = gtk_tree_model_get_path (model, iter);
if (GTK_IS_WINDOW (demo))
{
gtk_window_set_transient_for (GTK_WINDOW (demo), GTK_WINDOW (window));
gtk_window_set_modal (GTK_WINDOW (demo), TRUE);
}
g_signal_connect (demo, "destroy",
G_CALLBACK (window_closed_cb), cbdata);
}
}
award ("demo-inspector");
}
static void
@@ -181,14 +221,10 @@ activate_run (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GtkWidget *window = user_data;
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeIter iter;
GtkTreeListRow *row = gtk_single_selection_get_selected_item (selection);
GtkDemo *demo = gtk_tree_list_row_get_item (row);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
if (gtk_tree_selection_get_selected (selection, &model, &iter))
run_example_for_row (window, model, &iter);
gtk_demo_run (demo, window);
}
/* Stupid syntax highlighting.
@@ -893,81 +929,72 @@ load_file (const gchar *demoname,
}
static void
selection_cb (GtkTreeSelection *selection,
GtkTreeModel *model)
selection_cb (GtkSingleSelection *selection,
GParamSpec *pspec,
gpointer user_data)
{
GtkTreeIter iter;
char *name;
char *filename;
char *title;
GtkTreeListRow *row = gtk_single_selection_get_selected_item (selection);
GtkDemo *demo = gtk_tree_list_row_get_item (row);
if (! gtk_tree_selection_get_selected (selection, NULL, &iter))
return;
if (demo->filename)
load_file (demo->name, demo->filename);
gtk_tree_model_get (model, &iter,
NAME_COLUMN, &name,
TITLE_COLUMN, &title,
FILENAME_COLUMN, &filename,
-1);
if (filename)
load_file (name, filename);
gtk_header_bar_set_title (GTK_HEADER_BAR (headerbar), title);
g_free (name);
g_free (title);
g_free (filename);
gtk_header_bar_set_title (GTK_HEADER_BAR (headerbar), demo->title);
}
static void
populate_model (GtkTreeModel *model)
static GListModel *
create_demo_model (void)
{
Demo *d = gtk_demos;
GListStore *store = g_list_store_new (GTK_TYPE_DEMO);
DemoData *demo = gtk_demos;
/* this code only supports 1 level of children. If we
* want more we probably have to use a recursing function.
*/
while (d->title)
while (demo->title)
{
Demo *children = d->children;
GtkTreeIter iter;
GtkDemo *d = GTK_DEMO (g_object_new (GTK_TYPE_DEMO, NULL));
DemoData *children = demo->children;
gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
d->name = demo->name;
d->title = demo->title;
d->filename = demo->filename;
d->func = demo->func;
gtk_tree_store_set (GTK_TREE_STORE (model),
&iter,
NAME_COLUMN, d->name,
TITLE_COLUMN, d->title,
FILENAME_COLUMN, d->filename,
FUNC_COLUMN, d->func,
STYLE_COLUMN, PANGO_STYLE_NORMAL,
-1);
g_list_store_append (store, d);
d++;
if (!children)
continue;
while (children->title)
if (children)
{
GtkTreeIter child_iter;
d->children_model = G_LIST_MODEL (g_list_store_new (GTK_TYPE_DEMO));
gtk_tree_store_append (GTK_TREE_STORE (model), &child_iter, &iter);
while (children->title)
{
GtkDemo *child = GTK_DEMO (g_object_new (GTK_TYPE_DEMO, NULL));
gtk_tree_store_set (GTK_TREE_STORE (model),
&child_iter,
NAME_COLUMN, children->name,
TITLE_COLUMN, children->title,
FILENAME_COLUMN, children->filename,
FUNC_COLUMN, children->func,
STYLE_COLUMN, PANGO_STYLE_NORMAL,
-1);
child->name = children->name;
child->title = children->title;
child->filename = children->filename;
child->func = children->func;
children++;
g_list_store_append (G_LIST_STORE (d->children_model), child);
children++;
}
}
demo++;
}
return G_LIST_MODEL (store);
}
static GListModel *
get_child_model (gpointer item,
gpointer user_data)
{
GtkDemo *demo = item;
if (demo->children_model)
return g_object_ref (G_LIST_MODEL (demo->children_model));
return NULL;
}
static void
@@ -987,22 +1014,6 @@ startup (GApplication *app)
g_object_unref (builder);
}
static void
row_activated_cb (GtkWidget *tree_view,
GtkTreePath *path,
GtkTreeViewColumn *column)
{
GtkTreeIter iter;
GtkWidget *window;
GtkTreeModel *model;
window = GTK_WIDGET (gtk_widget_get_root (tree_view));
model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
gtk_tree_model_get_iter (model, &iter, path);
run_example_for_row (window, model, &iter);
}
static void
start_cb (GtkMenuItem *item, GtkWidget *scrollbar)
{
@@ -1029,34 +1040,36 @@ scrollbar_popup (GtkWidget *scrollbar, GtkWidget *menu)
return TRUE;
}
void
main_activate_cb (GtkListView *listview,
guint position,
gpointer user_data)
{
GtkTreeListRow *row = g_list_model_get_item (gtk_list_view_get_model (listview), position);
GtkDemo *demo = gtk_tree_list_row_get_item (row);
gtk_demo_run (demo, window);
}
static void
activate (GApplication *app)
{
GtkBuilder *builder;
GtkWindow *window;
GtkWidget *widget;
GtkTreeModel *model;
GtkTreeIter iter;
GError *error = NULL;
GtkWidget *sw;
GtkWidget *scrollbar;
GtkWidget *menu;
GtkWidget *item;
GListModel *listmodel;
GtkTreeListModel *treemodel;
static GActionEntry win_entries[] = {
{ "run", activate_run, NULL, NULL, NULL }
};
builder = gtk_builder_new ();
gtk_builder_add_from_resource (builder, "/ui/main.ui", &error);
if (error != NULL)
{
g_critical ("%s", error->message);
exit (1);
}
builder = gtk_builder_new_from_resource ("/ui/main.ui");
window = (GtkWindow *)gtk_builder_get_object (builder, "window");
gtk_application_add_window (GTK_APPLICATION (app), window);
window = (GtkWidget *)gtk_builder_get_object (builder, "window");
gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (window));
g_action_map_add_action_entries (G_ACTION_MAP (window),
win_entries, G_N_ELEMENTS (win_entries),
window);
@@ -1066,8 +1079,7 @@ activate (GApplication *app)
info_view = (GtkWidget *)gtk_builder_get_object (builder, "info-textview");
source_view = (GtkWidget *)gtk_builder_get_object (builder, "source-textview");
headerbar = (GtkWidget *)gtk_builder_get_object (builder, "headerbar");
treeview = (GtkWidget *)gtk_builder_get_object (builder, "treeview");
model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
listview = (GtkWidget *)gtk_builder_get_object (builder, "listview");
sw = (GtkWidget *)gtk_builder_get_object (builder, "source-scrolledwindow");
scrollbar = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (sw));
@@ -1086,17 +1098,19 @@ activate (GApplication *app)
load_file (gtk_demos[0].name, gtk_demos[0].filename);
populate_model (model);
listmodel = create_demo_model ();
treemodel = gtk_tree_list_model_new (FALSE,
G_LIST_MODEL (listmodel),
FALSE,
get_child_model,
NULL,
NULL);
selection = gtk_single_selection_new (G_LIST_MODEL (treemodel));
g_signal_connect (selection, "notify::selected-item", G_CALLBACK (selection_cb), NULL);
gtk_list_view_set_model (GTK_LIST_VIEW (listview),
G_LIST_MODEL (selection));
g_signal_connect (treeview, "row-activated", G_CALLBACK (row_activated_cb), model);
widget = (GtkWidget *)gtk_builder_get_object (builder, "treeview-selection");
g_signal_connect (widget, "changed", G_CALLBACK (selection_cb), model);
gtk_tree_model_get_iter_first (gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)), &iter);
gtk_tree_selection_select_iter (GTK_TREE_SELECTION (widget), &iter);
gtk_tree_view_collapse_all (GTK_TREE_VIEW (treeview));
award ("demo-start");
gtk_widget_show (GTK_WIDGET (window));
@@ -1113,7 +1127,7 @@ auto_quit (gpointer data)
static void
list_demos (void)
{
Demo *d, *c;
DemoData *d, *c;
d = gtk_demos;
@@ -1140,7 +1154,7 @@ command_line (GApplication *app,
const gchar *name = NULL;
gboolean autoquit = FALSE;
gboolean list = FALSE;
Demo *d, *c;
DemoData *d, *c;
GDoDemoFunc func = 0;
GtkWidget *window, *demo;

View File

@@ -28,7 +28,6 @@
<property name="default-width">800</property>
<property name="default-height">600</property>
<property name="title">GTK Demo</property>
<signal name="destroy" handler="gtk_main_quit" swapped="no"/>
<child type="titlebar">
<object class="GtkHeaderBar" id="headerbar">
<property name="show-title-buttons">1</property>
@@ -66,32 +65,15 @@
<property name="can-focus">1</property>
<property name="hscrollbar-policy">never</property>
<property name="min-content-width">150</property>
<child>
<object class="GtkTreeView" id="treeview">
<property name="can-focus">1</property>
<property name="model">treestore</property>
<property name="headers-visible">0</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection">
<property name="mode">browse</property>
<object class="GtkListView" id="listview">
<signal name="activate" handler="main_activate_cb" swapped="no" />
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="resource">/ui/main-listitem.ui</property>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="style">4</attribute>
<attribute name="text">1</attribute>
</attributes>
</child>
<child>
<object class="GtkCellRendererText">
<property name="text"> </property>
</object>
</child>
</object>
</child>
</property>
</object>
</child>
</object>

View File

@@ -3,6 +3,7 @@
demos = files([
'application_demo.c',
'assistant.c',
'awardview.c',
'builder.c',
'changedisplay.c',
'clipboard.c',
@@ -43,6 +44,13 @@ demos = files([
'listbox.c',
'flowbox.c',
'list_store.c',
'listview_applauncher.c',
'listview_clocks.c',
'listview_colors.c',
'listview_filebrowser.c',
'listview_minesweeper.c',
'listview_settings.c',
'listview_weather.c',
'markup.c',
'menus.c',
'modelbutton.c',
@@ -86,6 +94,7 @@ demos = files([
gtkdemo_deps = [ libgtk_dep, ]
extra_demo_sources = files(['main.c',
'award.c',
'gtkfishbowl.c',
'fontplane.c',
'gtkgears.c',
@@ -96,7 +105,7 @@ extra_demo_sources = files(['main.c',
if harfbuzz_dep.found() and pangoft_dep.found()
demos += files('font_features.c')
extra_demo_sources += files(['script-names.c', 'language-names.c'])
gtkdemo_deps += [ harfbuzz_dep, ]
gtkdemo_deps += [ harfbuzz_dep, epoxy_dep ]
endif
if os_unix

View File

@@ -14,8 +14,8 @@
#include <gtk/gtk.h>
static void
tool_clicked (GtkButton *button)
void
modelbutton_tool_clicked (GtkButton *button)
{
gboolean active;
@@ -40,8 +40,6 @@ do_modelbutton (GtkWidget *do_widget)
GActionGroup *actions;
builder = gtk_builder_new_from_resource ("/modelbutton/modelbutton.ui");
gtk_builder_add_callback_symbol (builder, "tool_clicked", G_CALLBACK (tool_clicked));
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));

View File

@@ -101,21 +101,21 @@
<object class="GtkModelButton">
<property name="text">Hammer</property>
<property name="role">check</property>
<signal name="clicked" handler="tool_clicked"/>
<signal name="clicked" handler="modelbutton_tool_clicked"/>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Screwdriver</property>
<property name="role">check</property>
<signal name="clicked" handler="tool_clicked"/>
<signal name="clicked" handler="modelbutton_tool_clicked"/>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Drill</property>
<property name="role">check</property>
<signal name="clicked" handler="tool_clicked"/>
<signal name="clicked" handler="modelbutton_tool_clicked"/>
</object>
</child>
</object>

View File

@@ -11,6 +11,8 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "award.h"
static GtkWidget *entry;
static GtkWidget *entry2;
static GtkWidget *button;
@@ -25,6 +27,18 @@ update_button (GObject *object,
gtk_widget_set_sensitive (button,
text[0] != '\0' && g_str_equal (text, text2));
if (g_str_equal (text, text2) &&
g_ascii_strcasecmp (text, "12345") == 0)
award ("password-best");
}
static void
button_pressed (GtkButton *button,
GtkWidget *window)
{
award ("password-correct");
gtk_widget_destroy (window);
}
GtkWidget *
@@ -72,7 +86,7 @@ do_password_entry (GtkWidget *do_widget)
button = gtk_button_new_with_mnemonic ("_Done");
gtk_style_context_add_class (gtk_widget_get_style_context (button), "suggested-action");
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
g_signal_connect (button, "clicked", G_CALLBACK (button_pressed), window);
gtk_widget_set_sensitive (button, FALSE);
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), button);

View File

@@ -69,7 +69,6 @@ do_revealer (GtkWidget *do_widget)
GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/revealer/revealer.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));

View File

@@ -18,7 +18,6 @@ do_scale (GtkWidget *do_widget)
GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/scale/scale.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));

View File

@@ -75,11 +75,11 @@
<property name="adjustment">adjustment2</property>
<property name="hexpand">1</property>
<marks>
<mark value="0" position="bottom"/>
<mark value="1" position="bottom"/>
<mark value="2" position="bottom"/>
<mark value="3" position="bottom"/>
<mark value="4" position="bottom"/>
<mark value="0" position="bottom"></mark>
<mark value="1" position="bottom"></mark>
<mark value="2" position="bottom"></mark>
<mark value="3" position="bottom"></mark>
<mark value="4" position="bottom"></mark>
</marks>
<accessibility>
<relation type="labelled-by" target="label_marks"/>
@@ -115,11 +115,11 @@
<relation type="labelled-by" target="label_discrete"/>
</accessibility>
<marks>
<mark value="0" position="bottom"/>
<mark value="1" position="bottom"/>
<mark value="2" position="bottom"/>
<mark value="3" position="bottom"/>
<mark value="4" position="bottom"/>
<mark value="0" position="bottom"></mark>
<mark value="1" position="bottom"></mark>
<mark value="2" position="bottom"></mark>
<mark value="3" position="bottom"></mark>
<mark value="4" position="bottom"></mark>
</marks>
<layout>
<property name="left-attach">1</property>

View File

@@ -25,44 +25,44 @@ show_shortcuts (GtkWidget *window,
g_object_unref (builder);
}
static void
builder_shortcuts (GtkWidget *window)
void
shortcuts_builder_shortcuts (GtkWidget *window)
{
show_shortcuts (window, "shortcuts-builder", NULL);
}
static void
gedit_shortcuts (GtkWidget *window)
void
shortcuts_gedit_shortcuts (GtkWidget *window)
{
show_shortcuts (window, "shortcuts-gedit", NULL);
}
static void
clocks_shortcuts (GtkWidget *window)
void
shortcuts_clocks_shortcuts (GtkWidget *window)
{
show_shortcuts (window, "shortcuts-clocks", NULL);
}
static void
clocks_shortcuts_stopwatch (GtkWidget *window)
void
shortcuts_clocks_shortcuts_stopwatch (GtkWidget *window)
{
show_shortcuts (window, "shortcuts-clocks", "stopwatch");
}
static void
boxes_shortcuts (GtkWidget *window)
void
shortcuts_boxes_shortcuts (GtkWidget *window)
{
show_shortcuts (window, "shortcuts-boxes", NULL);
}
static void
boxes_shortcuts_wizard (GtkWidget *window)
void
shortcuts_boxes_shortcuts_wizard (GtkWidget *window)
{
show_shortcuts (window, "shortcuts-boxes", "wizard");
}
static void
boxes_shortcuts_display (GtkWidget *window)
void
shortcuts_boxes_shortcuts_display (GtkWidget *window)
{
show_shortcuts (window, "shortcuts-boxes", "display");
}
@@ -86,16 +86,6 @@ do_shortcuts (GtkWidget *do_widget)
GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/shortcuts/shortcuts.ui");
gtk_builder_add_callback_symbols (builder,
"builder_shortcuts", G_CALLBACK (builder_shortcuts),
"gedit_shortcuts", G_CALLBACK (gedit_shortcuts),
"clocks_shortcuts", G_CALLBACK (clocks_shortcuts),
"clocks_shortcuts_stopwatch", G_CALLBACK (clocks_shortcuts_stopwatch),
"boxes_shortcuts", G_CALLBACK (boxes_shortcuts),
"boxes_shortcuts_wizard", G_CALLBACK (boxes_shortcuts_wizard),
"boxes_shortcuts_display", G_CALLBACK (boxes_shortcuts_display),
NULL);
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));

View File

@@ -10,43 +10,43 @@
<child>
<object class="GtkButton">
<property name="label">Builder</property>
<signal name="clicked" handler="builder_shortcuts" swapped="1" object="window1"/>
<signal name="clicked" handler="shortcuts_builder_shortcuts" swapped="1" object="window1"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">GEdit</property>
<signal name="clicked" handler="gedit_shortcuts" swapped="1" object="window1"/>
<signal name="clicked" handler="shortcuts_gedit_shortcuts" swapped="1" object="window1"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Clocks - All</property>
<signal name="clicked" handler="clocks_shortcuts" swapped="1" object="window1"/>
<signal name="clicked" handler="shortcuts_clocks_shortcuts" swapped="1" object="window1"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Clocks - Stopwatch</property>
<signal name="clicked" handler="clocks_shortcuts_stopwatch" swapped="1" object="window1"/>
<signal name="clicked" handler="shortcuts_clocks_shortcuts_stopwatch" swapped="1" object="window1"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Boxes</property>
<signal name="clicked" handler="boxes_shortcuts" swapped="1" object="window1"/>
<signal name="clicked" handler="shortcuts_boxes_shortcuts" swapped="1" object="window1"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Boxes - Wizard</property>
<signal name="clicked" handler="boxes_shortcuts_wizard" swapped="1" object="window1"/>
<signal name="clicked" handler="shortcuts_boxes_shortcuts_wizard" swapped="1" object="window1"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Boxes - Display</property>
<signal name="clicked" handler="boxes_shortcuts_display" swapped="1" object="window1"/>
<signal name="clicked" handler="shortcuts_boxes_shortcuts_display" swapped="1" object="window1"/>
</object>
</child>
</object>

View File

@@ -11,6 +11,9 @@
#include "puzzlepiece.h"
#include "paintable.h"
/* Give out awards */
#include "award.h"
static GtkWidget *window = NULL;
static GtkWidget *frame = NULL;
static GtkWidget *choices = NULL;
@@ -156,6 +159,14 @@ check_solved (GtkWidget *grid)
picture = gtk_grid_get_child_at (GTK_GRID (grid), pos_x, pos_y);
gtk_picture_set_paintable (GTK_PICTURE (picture), piece);
/* Hand out a bunch of awards
*/
award ("puzzle-solve");
if ((gdk_paintable_get_flags (piece) & GDK_PAINTABLE_STATIC_CONTENTS) == 0)
award ("puzzle-solve-animated");
if (height * width > 20)
award ("puzzle-solve-large");
return TRUE;
}
@@ -401,6 +412,18 @@ add_choice (GtkWidget *choices,
gtk_container_add (GTK_CONTAINER (choices), icon);
}
static void
widget_destroyed (GtkWidget *widget,
GtkWidget **widget_pointer)
{
if (widget_pointer)
*widget_pointer = NULL;
if (!solved)
award ("puzzle-give-up");
}
GtkWidget *
do_sliding_puzzle (GtkWidget *do_widget)
{
@@ -469,7 +492,7 @@ do_sliding_puzzle (GtkWidget *do_widget)
gtk_window_set_titlebar (GTK_WINDOW (window), header);
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
G_CALLBACK (widget_destroyed), &window);
frame = gtk_aspect_frame_new (NULL, 0.5, 0.5, (float) gdk_paintable_get_intrinsic_aspect_ratio (puzzle), FALSE);
gtk_container_add (GTK_CONTAINER (window), frame);

View File

@@ -11,9 +11,9 @@
#include <math.h>
#include <stdlib.h>
static gint
hex_spin_input (GtkSpinButton *spin_button,
gdouble *new_val)
gint
spinbutton_hex_spin_input (GtkSpinButton *spin_button,
gdouble *new_val)
{
const gchar *buf;
gchar *err;
@@ -28,8 +28,8 @@ hex_spin_input (GtkSpinButton *spin_button,
return TRUE;
}
static gint
hex_spin_output (GtkSpinButton *spin_button)
gint
spinbutton_hex_spin_output (GtkSpinButton *spin_button)
{
GtkAdjustment *adjustment;
gchar *buf;
@@ -48,9 +48,9 @@ hex_spin_output (GtkSpinButton *spin_button)
return TRUE;
}
static gint
time_spin_input (GtkSpinButton *spin_button,
gdouble *new_val)
gint
spinbutton_time_spin_input (GtkSpinButton *spin_button,
gdouble *new_val)
{
const gchar *text;
gchar **str;
@@ -87,8 +87,8 @@ time_spin_input (GtkSpinButton *spin_button,
return TRUE;
}
static gint
time_spin_output (GtkSpinButton *spin_button)
gint
spinbutton_time_spin_output (GtkSpinButton *spin_button)
{
GtkAdjustment *adjustment;
gchar *buf;
@@ -121,9 +121,9 @@ static gchar *month[12] = {
"December"
};
static gint
month_spin_input (GtkSpinButton *spin_button,
gdouble *new_val)
gint
spinbutton_month_spin_input (GtkSpinButton *spin_button,
gdouble *new_val)
{
gint i;
gchar *tmp1, *tmp2;
@@ -150,8 +150,8 @@ month_spin_input (GtkSpinButton *spin_button,
return TRUE;
}
static gint
month_spin_output (GtkSpinButton *spin_button)
gint
spinbutton_month_spin_output (GtkSpinButton *spin_button)
{
GtkAdjustment *adjustment;
gdouble value;
@@ -191,15 +191,6 @@ do_spinbutton (GtkWidget *do_widget)
GtkWidget *label;
builder = gtk_builder_new_from_resource ("/spinbutton/spinbutton.ui");
gtk_builder_add_callback_symbols (builder,
"hex_spin_input", G_CALLBACK (hex_spin_input),
"hex_spin_output", G_CALLBACK (hex_spin_output),
"time_spin_input", G_CALLBACK (time_spin_input),
"time_spin_output", G_CALLBACK (time_spin_output),
"month_spin_input", G_CALLBACK (month_spin_input),
"month_spin_output", G_CALLBACK (month_spin_output),
NULL);
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));

View File

@@ -83,8 +83,8 @@
<property name="halign">start</property>
<property name="width-chars">4</property>
<property name="adjustment">hex_adjustment</property>
<signal name="input" handler="hex_spin_input"/>
<signal name="output" handler="hex_spin_output"/>
<signal name="input" handler="spinbutton_hex_spin_input"/>
<signal name="output" handler="spinbutton_hex_spin_output"/>
<property name="wrap">1</property>
<layout>
<property name="left-attach">1</property>
@@ -119,8 +119,8 @@
<property name="halign">start</property>
<property name="width-chars">5</property>
<property name="adjustment">time_adjustment</property>
<signal name="input" handler="time_spin_input"/>
<signal name="output" handler="time_spin_output"/>
<signal name="input" handler="spinbutton_time_spin_input"/>
<signal name="output" handler="spinbutton_time_spin_output"/>
<property name="wrap">1</property>
<layout>
<property name="left-attach">1</property>
@@ -154,8 +154,8 @@
<object class="GtkSpinButton" id="month_spin">
<property name="halign">start</property>
<property name="width-chars">9</property>
<signal name="input" handler="month_spin_input"/>
<signal name="output" handler="month_spin_output"/>
<signal name="input" handler="spinbutton_month_spin_input"/>
<signal name="output" handler="spinbutton_month_spin_output"/>
<property name="adjustment">month_adjustment</property>
<property name="wrap">1</property>
<property name="update-policy">if-valid</property>

View File

@@ -18,7 +18,6 @@ do_stack (GtkWidget *do_widget)
GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/stack/stack.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));

View File

@@ -6,236 +6,235 @@
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="end">
<object class="GtkLabel" id="fps">
</object>
<object class="GtkLabel" id="fps"/>
</child>
</object>
</child>
<child>
<object class="GtkGrid" id="grid">
<property name="margin">10</property>
<property name="row-spacing">10</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkToolbar">
<property name="hexpand">1</property>
<property name="show-arrow">0</property>
<style>
<class name="primary-toolbar"/>
</style>
<object class="GtkGrid" id="grid">
<property name="margin">10</property>
<property name="row-spacing">10</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="label" translatable="yes">Normal</property>
<property name="use-underline">1</property>
<property name="is-important">1</property>
<property name="icon-name">edit-find</property>
</object>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="label" translatable="yes">Active</property>
<property name="use-underline">1</property>
<property name="is-important">1</property>
<property name="icon-name">edit-find</property>
<property name="active">1</property>
</object>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="sensitive">0</property>
<property name="label" translatable="yes">Insensitive</property>
<property name="use-underline">1</property>
<property name="is-important">1</property>
<property name="icon-name">edit-find</property>
</object>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="label" translatable="yes">Raised</property>
<property name="use-underline">1</property>
<property name="is-important">1</property>
<property name="icon-name">edit-find</property>
<style>
<class name="raised"/>
</style>
</object>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="label" translatable="yes">Raised Active</property>
<property name="use-underline">1</property>
<property name="is-important">1</property>
<property name="icon-name">edit-find</property>
<property name="active">1</property>
<style>
<class name="raised"/>
</style>
</object>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="sensitive">0</property>
<property name="label" translatable="yes">Insensitive Active</property>
<property name="use-underline">1</property>
<property name="icon-name">edit-find</property>
<property name="is-important">1</property>
<property name="active">1</property>
</object>
</child>
<child>
<object class="GtkToolItem">
<child>
<object class="GtkEntry" id="entry1">
<property name="can-focus">1</property>
<property name="width-chars">10</property>
<property name="invisible-char">•</property>
<property name="placeholder-text" translatable="yes">Search...</property>
<property name="secondary-icon-name">edit-find-symbolic</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkToolItem">
<child>
<object class="GtkSwitch" id="switch1">
<property name="can-focus">1</property>
<property name="valign">center</property>
<property name="tooltip_text">Switch it</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="valign">center</property>
<property name="halign">center</property>
<style>
<class name="linked"/>
</style>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Hi, I am a button</property>
<property name="can-focus">1</property>
<property name="receives-default">1</property>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">And I&apos;m another button</property>
<property name="can-focus">1</property>
<property name="receives-default">1</property>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">This is a button party!</property>
<property name="can-focus">1</property>
<property name="receives-default">1</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkToolbar">
<property name="hexpand">1</property>
<property name="toolbar-style">icons</property>
<style>
<class name="inline-toolbar"/>
</style>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="label" translatable="yes">Normal</property>
<property name="use-underline">1</property>
<property name="icon-name">list-add-symbolic</property>
</object>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="label" translatable="yes">Normal</property>
<property name="use-underline">1</property>
<property name="icon-name">list-add-symbolic</property>
</object>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="label" translatable="yes">Active</property>
<property name="use-underline">1</property>
<property name="icon-name">list-remove-symbolic</property>
<property name="active">1</property>
</object>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="label" translatable="yes">Active</property>
<property name="use-underline">1</property>
<property name="icon-name">list-remove-symbolic</property>
<property name="active">1</property>
</object>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="sensitive">0</property>
<property name="label" translatable="yes">Insensitive</property>
<property name="use-underline">1</property>
<property name="icon-name">edit-find-symbolic</property>
</object>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="sensitive">0</property>
<property name="label" translatable="yes">Insensitive Active</property>
<property name="use-underline">1</property>
<property name="icon-name">go-up-symbolic</property>
<property name="active">1</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="spacing">10</property>
<child>
<object class="GtkButton">
<property name="label">Plain</property>
<property name="halign">end</property>
<object class="GtkToolbar">
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<property name="show-arrow">0</property>
<style>
<class name="primary-toolbar"/>
</style>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="label" translatable="yes">Normal</property>
<property name="use-underline">1</property>
<property name="is-important">1</property>
<property name="icon-name">edit-find</property>
</object>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="label" translatable="yes">Active</property>
<property name="use-underline">1</property>
<property name="is-important">1</property>
<property name="icon-name">edit-find</property>
<property name="active">1</property>
</object>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="sensitive">0</property>
<property name="label" translatable="yes">Insensitive</property>
<property name="use-underline">1</property>
<property name="is-important">1</property>
<property name="icon-name">edit-find</property>
</object>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="label" translatable="yes">Raised</property>
<property name="use-underline">1</property>
<property name="is-important">1</property>
<property name="icon-name">edit-find</property>
<style>
<class name="raised"/>
</style>
</object>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="label" translatable="yes">Raised Active</property>
<property name="use-underline">1</property>
<property name="is-important">1</property>
<property name="icon-name">edit-find</property>
<property name="active">1</property>
<style>
<class name="raised"/>
</style>
</object>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="sensitive">0</property>
<property name="label" translatable="yes">Insensitive Active</property>
<property name="use-underline">1</property>
<property name="icon-name">edit-find</property>
<property name="is-important">1</property>
<property name="active">1</property>
</object>
</child>
<child>
<object class="GtkToolItem">
<child>
<object class="GtkEntry" id="entry1">
<property name="can-focus">1</property>
<property name="width-chars">10</property>
<property name="invisible-char">•</property>
<property name="placeholder-text" translatable="yes">Search...</property>
<property name="secondary-icon-name">edit-find-symbolic</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkToolItem">
<child>
<object class="GtkSwitch" id="switch1">
<property name="can-focus">1</property>
<property name="valign">center</property>
<property name="tooltip_text">Switch it</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Destructive</property>
<object class="GtkBox">
<property name="valign">center</property>
<property name="halign">center</property>
<style>
<class name="destructive-action"/>
<class name="linked"/>
</style>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Hi, I am a button</property>
<property name="can-focus">1</property>
<property name="receives-default">1</property>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">And I&apos;m another button</property>
<property name="can-focus">1</property>
<property name="receives-default">1</property>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">This is a button party!</property>
<property name="can-focus">1</property>
<property name="receives-default">1</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Suggested</property>
<object class="GtkToolbar">
<property name="hexpand">1</property>
<property name="toolbar-style">icons</property>
<style>
<class name="suggested-action"/>
<class name="inline-toolbar"/>
</style>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="label" translatable="yes">Normal</property>
<property name="use-underline">1</property>
<property name="icon-name">list-add-symbolic</property>
</object>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="label" translatable="yes">Normal</property>
<property name="use-underline">1</property>
<property name="icon-name">list-add-symbolic</property>
</object>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="label" translatable="yes">Active</property>
<property name="use-underline">1</property>
<property name="icon-name">list-remove-symbolic</property>
<property name="active">1</property>
</object>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="label" translatable="yes">Active</property>
<property name="use-underline">1</property>
<property name="icon-name">list-remove-symbolic</property>
<property name="active">1</property>
</object>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="sensitive">0</property>
<property name="label" translatable="yes">Insensitive</property>
<property name="use-underline">1</property>
<property name="icon-name">edit-find-symbolic</property>
</object>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="homogeneous">1</property>
<property name="sensitive">0</property>
<property name="label" translatable="yes">Insensitive Active</property>
<property name="use-underline">1</property>
<property name="icon-name">go-up-symbolic</property>
<property name="active">1</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="spacing">10</property>
<child>
<object class="GtkButton">
<property name="label">Plain</property>
<property name="halign">end</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Destructive</property>
<style>
<class name="destructive-action"/>
</style>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Suggested</property>
<style>
<class name="suggested-action"/>
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -2,6 +2,7 @@
<interface>
<object class="GtkGrid" id="grid">
<property name="row-spacing">10</property>
<property name="margin">10</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkToolbar">
@@ -92,6 +93,7 @@
<child>
<object class="GtkSwitch" id="switch1">
<property name="can-focus">1</property>
<property name="valign">center</property>
<property name="tooltip_text">Switch it</property>
</object>
</child>

View File

@@ -1663,6 +1663,7 @@ static void
activate (GApplication *app)
{
GtkBuilder *builder;
GtkBuilderScope *scope;
GtkWindow *window;
GtkWidget *widget;
GtkWidget *widget2;
@@ -1715,21 +1716,25 @@ activate (GApplication *app)
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
g_object_unref (provider);
builder = gtk_builder_new_from_resource ("/org/gtk/WidgetFactory4/widget-factory.ui");
gtk_builder_add_callback_symbol (builder, "on_entry_icon_release", (GCallback)on_entry_icon_release);
gtk_builder_add_callback_symbol (builder, "on_scale_button_value_changed", (GCallback)on_scale_button_value_changed);
gtk_builder_add_callback_symbol (builder, "on_scale_button_query_tooltip", (GCallback)on_scale_button_query_tooltip);
gtk_builder_add_callback_symbol (builder, "on_record_button_toggled", (GCallback)on_record_button_toggled);
gtk_builder_add_callback_symbol (builder, "on_page_combo_changed", (GCallback)on_page_combo_changed);
gtk_builder_add_callback_symbol (builder, "on_range_from_changed", (GCallback)on_range_from_changed);
gtk_builder_add_callback_symbol (builder, "on_range_to_changed", (GCallback)on_range_to_changed);
gtk_builder_add_callback_symbol (builder, "tab_close_cb", (GCallback)tab_close_cb);
gtk_builder_add_callback_symbol (builder, "increase_icon_size", (GCallback)increase_icon_size);
gtk_builder_add_callback_symbol (builder, "decrease_icon_size", (GCallback)decrease_icon_size);
gtk_builder_add_callback_symbol (builder, "reset_icon_size", (GCallback)reset_icon_size);
gtk_builder_add_callback_symbol (builder, "osd_frame_pressed", (GCallback)osd_frame_pressed);
gtk_builder_connect_signals (builder, NULL);
builder = gtk_builder_new ();
scope = gtk_builder_cscope_new ();
gtk_builder_cscope_add_callback_symbols (GTK_BUILDER_CSCOPE (scope),
"on_entry_icon_release", (GCallback)on_entry_icon_release,
"on_scale_button_value_changed", (GCallback)on_scale_button_value_changed,
"on_scale_button_query_tooltip", (GCallback)on_scale_button_query_tooltip,
"on_record_button_toggled", (GCallback)on_record_button_toggled,
"on_page_combo_changed", (GCallback)on_page_combo_changed,
"on_range_from_changed", (GCallback)on_range_from_changed,
"on_range_to_changed", (GCallback)on_range_to_changed,
"tab_close_cb", (GCallback)tab_close_cb,
"increase_icon_size", (GCallback)increase_icon_size,
"decrease_icon_size", (GCallback)decrease_icon_size,
"reset_icon_size", (GCallback)reset_icon_size,
"osd_frame_pressed", (GCallback)osd_frame_pressed,
NULL);
gtk_builder_set_scope (builder, scope);
g_object_unref (scope);
gtk_builder_add_from_resource (builder, "/org/gtk/WidgetFactory4/widget-factory.ui", NULL);
window = (GtkWindow *)gtk_builder_get_object (builder, "window");
gtk_application_add_window (GTK_APPLICATION (app), window);

View File

@@ -598,10 +598,6 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<property name="label" translatable="yes">checkbutton</property>
<property name="can-focus">1</property>
<property name="active">1</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
<child>
@@ -666,8 +662,8 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<property name="can-focus">1</property>
<property name="active">1</property>
<layout>
<property name="left-attach">0</property>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
@@ -740,7 +736,6 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<property name="active">1</property>
<layout>
<property name="left-attach">2</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
@@ -971,11 +966,11 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<property name="adjustment">adjustment3</property>
<property name="restrict-to-fill-level">0</property>
<marks>
<mark value="0" position="bottom"/>
<mark value="1" position="bottom"/>
<mark value="2" position="bottom"/>
<mark value="3" position="bottom"/>
<mark value="4" position="bottom"/>
<mark value="0" position="bottom"></mark>
<mark value="1" position="bottom"></mark>
<mark value="2" position="bottom"></mark>
<mark value="3" position="bottom"></mark>
<mark value="4" position="bottom"></mark>
</marks>
</object>
</child>
@@ -1505,10 +1500,6 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<property name="valign">center</property>
<property name="value">.5</property>
<property name="halign">center</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
<child>
@@ -1524,7 +1515,6 @@ microphone-sensitivity-medium-symbolic</property>
<signal name="query-tooltip" handler="on_scale_button_query_tooltip" swapped="no"/>
<signal name="value-changed" handler="on_scale_button_value_changed" swapped="no"/>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</layout>
</object>
@@ -1575,7 +1565,7 @@ microphone-sensitivity-medium-symbolic</property>
<property name="icon-name">org.gtk.WidgetFactory4</property>
<property name="pixel-size">256</property>
<style>
<class name="icon-dropshadow" />
<class name="icon-dropshadow"/>
</style>
</object>
</property>
@@ -2014,7 +2004,6 @@ microphone-sensitivity-medium-symbolic</property>
</child>
</object>
</child>
FOO
<child>
<object class="GtkMenuItem" id="menuitem3">
<property name="label" translatable="yes">View</property>
@@ -2134,13 +2123,10 @@ FOO
</object>
</child>
<child>
<object class="GtkSeparator">
<property name="orientation">horizontal</property>
</object>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="shadow-type">none</property>
<property name="vexpand">1</property>
<child>
<object class="MyTextView" id="text3">
@@ -2155,9 +2141,7 @@ FOO
</object>
</child>
<child>
<object class="GtkSeparator">
<property name="orientation">horizontal</property>
</object>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkStatusbar" id="statusbar"/>
@@ -2449,11 +2433,9 @@ FOO
<property name="spacing">10</property>
<child>
<object class="GtkBox">
<property name="halign">fill</property>
<property name="spacing">6</property>
<child>
<object class="GtkBox" id="lockbox">
<property name="halign">fill</property>
<property name="hexpand">1</property>
<property name="spacing">6</property>
<child>
@@ -2530,9 +2512,6 @@ FOO
<object class="GtkMenuButton">
<property name="icon-name">view-more-symbolic</property>
<property name="popover">new_style_menu</property>
<!--
<property name="menu-model">new_style_menu_model</property>
-->
</object>
</child>
</object>
@@ -3367,10 +3346,6 @@ bad things might happen.</property>
<accessibility>
<relation type="label-for" target="open_popover_entry"/>
</accessibility>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
<child>
@@ -3382,7 +3357,6 @@ bad things might happen.</property>
<relation type="label-for" target="open_popover_textview"/>
</accessibility>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</layout>
</object>
@@ -3417,7 +3391,6 @@ bad things might happen.</property>
</accessibility>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
<property name="column-span">2</property>
</layout>
</object>
@@ -3456,7 +3429,6 @@ bad things might happen.</property>
</child>
<child>
<object class="GtkButton" id="open_popover_button">
<property name="halign">fill</property>
<property name="label">_Open</property>
<property name="use-underline">1</property>
<property name="sensitive">0</property>
@@ -3505,7 +3477,7 @@ bad things might happen.</property>
<property name="autohide">0</property>
<child>
<object class="GtkLabel">
<property name="label">You're in too deep!</property>
<property name="label">You&apos;re in too deep!</property>
<accessibility>
<role type="static"/>
</accessibility>
@@ -3516,7 +3488,6 @@ bad things might happen.</property>
<property name="autohide">0</property>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<child>
<object class="GtkLabel">
<property name="label">Hidden gems:</property>
@@ -3536,219 +3507,246 @@ bad things might happen.</property>
</object>
</child>
</object>
<object class="GtkPopoverMenu" id="new_style_menu">
<object class="GtkPopover" id="new_style_menu">
<child>
<object class="GtkBox">
<property name="name">main</property>
<property name="orientation">vertical</property>
<object class="GtkStack">
<child>
<object class="GtkBox">
<property name="halign">fill</property>
<style>
<class name="circular-buttons"/>
</style>
<child>
<object class="GtkModelButton">
<property name="icon"><object class="GThemedIcon"><property name="name">printer-symbolic</property></object></property>
<property name="iconic">1</property>
<property name="action-name">app.print</property>
<property name="hexpand">1</property>
<property name="halign">center</property>
<style>
<class name="circular"/>
</style>
<object class="GtkStackPage">
<property name="name">main</property>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<style>
<class name="circular-buttons"/>
</style>
<child>
<object class="GtkModelButton">
<property name="icon">
<object class="GThemedIcon">
<property name="name">printer-symbolic</property>
</object>
</property>
<property name="iconic">1</property>
<property name="action-name">app.print</property>
<property name="hexpand">1</property>
<property name="halign">center</property>
<style>
<class name="circular"/>
</style>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="icon">
<object class="GThemedIcon">
<property name="name">emblem-shared-symbolic</property>
</object>
</property>
<property name="iconic">1</property>
<property name="action-name">app.share</property>
<property name="hexpand">1</property>
<property name="halign">center</property>
<style>
<class name="circular"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Open in New Window</property>
<property name="action-name">app.open-in</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkBox">
<style>
<class name="inline-buttons"/>
</style>
<child>
<object class="GtkLabel" id="cut_copy_paste_filler"/>
</child>
<child>
<object class="GtkLabel">
<property name="label">Edit</property>
<property name="xalign">0</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="icon">
<object class="GThemedIcon">
<property name="name">edit-cut-symbolic</property>
</object>
</property>
<property name="iconic">1</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="icon">
<object class="GThemedIcon">
<property name="name">edit-copy-symbolic</property>
</object>
</property>
<property name="iconic">1</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="icon">
<object class="GThemedIcon">
<property name="name">edit-paste-symbolic</property>
</object>
</property>
<property name="iconic">1</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Pin</property>
<property name="action-name">app.pin</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Select Labels…</property>
<property name="action-name">app.labels</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Share…</property>
<property name="action-name">app.share</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Basement</property>
<property name="menu-name">basement</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Large</property>
<property name="action-name">app.size</property>
<property name="action-target">&apos;large&apos;</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Medium</property>
<property name="action-name">app.size</property>
<property name="action-target">&apos;medium&apos;</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Small</property>
<property name="action-name">app.size</property>
<property name="action-target">&apos;small&apos;</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Move to Trash</property>
<property name="action-name">win.delete</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="icon"><object class="GThemedIcon"><property name="name">emblem-shared-symbolic</property></object></property>
<property name="iconic">1</property>
<property name="action-name">app.share</property>
<property name="hexpand">1</property>
<property name="halign">center</property>
<style>
<class name="circular"/>
</style>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">basement</property>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkModelButton">
<property name="text">Basement</property>
<property name="role">title</property>
<property name="menu-name">main</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Berk</property>
<property name="action-name">app.berk</property>
<property name="indicator-size-group">basement-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Broni</property>
<property name="action-name">app.broni</property>
<property name="indicator-size-group">basement-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Drutt</property>
<property name="action-name">app.drutt</property>
<property name="indicator-size-group">basement-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">The Thing Upstairs</property>
<property name="action-name">app.upstairs</property>
<property name="indicator-size-group">basement-indicators</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Open in New Window</property>
<property name="action-name">app.open-in</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkBox">
<style>
<class name="inline-buttons"/>
</style>
<child>
<object class="GtkLabel" id="cut_copy_paste_filler">
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Edit</property>
<property name="xalign">0</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="icon"><object class="GThemedIcon"><property name="name">edit-cut-symbolic</property></object></property>
<property name="iconic">1</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="icon"><object class="GThemedIcon"><property name="name">edit-copy-symbolic</property></object></property>
<property name="iconic">1</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="icon"><object class="GThemedIcon"><property name="name">edit-paste-symbolic</property></object></property>
<property name="iconic">1</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Pin</property>
<property name="action-name">app.pin</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Select Labels…</property>
<property name="action-name">app.labels</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Share…</property>
<property name="action-name">app.share</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Basement</property>
<property name="menu-name">basement</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Large</property>
<property name="action-name">app.size</property>
<property name="action-target">'large'</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Medium</property>
<property name="action-name">app.size</property>
<property name="action-target">'medium'</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Small</property>
<property name="action-name">app.size</property>
<property name="action-target">'small'</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Move to Trash</property>
<property name="action-name">win.delete</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="name">basement</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkModelButton">
<property name="text">Basement</property>
<property name="role">title</property>
<property name="menu-name">main</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Berk</property>
<property name="action-name">app.berk</property>
<property name="indicator-size-group">basement-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Broni</property>
<property name="action-name">app.broni</property>
<property name="indicator-size-group">basement-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Drutt</property>
<property name="action-name">app.drutt</property>
<property name="indicator-size-group">basement-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">The Thing Upstairs</property>
<property name="action-name">app.upstairs</property>
<property name="indicator-size-group">basement-indicators</property>
</property>
</object>
</child>
</object>
</child>
</object>
<object class="GtkSizeGroup" id="main-indicators">
<property name="mode">horizontal</property>
<widgets>
<widget name="cut_copy_paste_filler"/>
</widgets>
</object>
<object class="GtkSizeGroup" id="basement-indicators">
<property name="mode">horizontal</property>
</object>
<object class="GtkSizeGroup" id="basement-indicators"/>
<menu id="new_style_menu_model">
<section>
<attribute name="display-hint">circular-buttons</attribute>
@@ -3838,10 +3836,10 @@ bad things might happen.</property>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">Move to Trash</attribute>
<attribute name="action">win.delete</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Move to Trash</attribute>
<attribute name="action">win.delete</attribute>
</item>
</section>
</menu>
<menu id="new_style_context_menu_model">
@@ -4032,14 +4030,13 @@ bad things might happen.</property>
<attribute name="action">win.background</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">_Help</attribute>
<item>
<attribute name="label" translatable="yes">About</attribute>
<attribute name="action">app.about</attribute>
</item>
<item>
<attribute name="label" translatable="yes">About</attribute>
<attribute name="action">app.about</attribute>
</item>
</submenu>
</menu>
</interface>

View File

@@ -192,8 +192,8 @@ gdk_surface_is_destroyed
gdk_surface_is_visible
gdk_surface_is_viewable
gdk_surface_get_state
gdk_surface_iconify
gdk_surface_deiconify
gdk_surface_minimize
gdk_surface_unminimize
gdk_surface_stick
gdk_surface_unstick
gdk_surface_maximize
@@ -789,8 +789,6 @@ gdk_drop_get_type
</SECTION>
<SECTION>
<INCLUDE>gdk/gdkx.h</INCLUDE>
<TITLE>X Window System Interaction</TITLE>
<FILE>x_interaction</FILE>
GDK_SURFACE_XID
GDK_DISPLAY_XDISPLAY
@@ -941,8 +939,6 @@ gdk_surface_impl_x11_get_type
</SECTION>
<SECTION>
<INCLUDE>gdk/gdkwayland.h</INCLUDE>
<TITLE>Wayland Interaction</TITLE>
<FILE>wayland_interaction</FILE>
gdk_wayland_seat_get_wl_seat
gdk_wayland_device_get_wl_keyboard

View File

@@ -44,15 +44,51 @@
<chapter id="Lists">
<title>GListModel support</title>
<xi:include href="xml/gtkexpression.xml" />
<xi:include href="xml/gtkfilterlistmodel.xml" />
<section>
<xi:include href="xml/gtkfilter.xml" />
<xi:include href="xml/gtkcustomfilter.xml" />
<xi:include href="xml/gtkstringfilter.xml" />
<xi:include href="xml/gtkmultifilter.xml" />
</section>
<xi:include href="xml/gtkflattenlistmodel.xml" />
<xi:include href="xml/gtkmaplistmodel.xml" />
<xi:include href="xml/gtkslicelistmodel.xml" />
<xi:include href="xml/gtksortlistmodel.xml" />
<xi:include href="xml/gtktreelistmodel.xml" />
<section>
<xi:include href="xml/gtksorter.xml" />
<xi:include href="xml/gtkcustomsorter.xml" />
<xi:include href="xml/gtkstringsorter.xml" />
<xi:include href="xml/gtknumericsorter.xml" />
<xi:include href="xml/gtkmultisorter.xml" />
</section>
<xi:include href="xml/gtkselectionmodel.xml" />
<xi:include href="xml/gtknoselection.xml" />
<xi:include href="xml/gtksingleselection.xml" />
<xi:include href="xml/gtkdirectorylist.xml" />
</chapter>
<chapter id="ListContainers">
<title>List-based Widgets</title>
<xi:include href="xml/gtklistitem.xml" />
<xi:include href="xml/gtklistitemfactory.xml" />
<section>
<xi:include href="xml/gtksignallistitemfactory.xml" />
<xi:include href="xml/gtkbuilderlistitemfactory.xml" />
</section>
<xi:include href="xml/gtklistview.xml" />
<xi:include href="xml/gtkgridview.xml" />
<xi:include href="xml/gtkcolumnview.xml" />
<xi:include href="xml/gtkcolumnviewcolumn.xml" />
<xi:include href="xml/gtkdropdown.xml" />
</chapter>
<chapter id="Trees">
<xi:include href="xml/gtktreelistrow.xml" />
<xi:include href="xml/gtktreelistmodel.xml" />
<xi:include href="xml/gtktreelistrowsorter.xml" />
<xi:include href="xml/gtktreeexpander.xml" />
</chapter>
<chapter id="Application">
@@ -66,11 +102,13 @@
<title>Interface builder</title>
<xi:include href="xml/gtkbuilder.xml" />
<xi:include href="xml/gtkbuildable.xml" />
<xi:include href="xml/gtkbuilderscope.xml" />
</chapter>
<chapter id="WindowWidgets">
<title>Windows</title>
<xi:include href="xml/gtkroot.xml" />
<xi:include href="xml/gtknative.xml" />
<xi:include href="xml/gtkwindow.xml" />
<xi:include href="xml/gtkdialog.xml" />
<xi:include href="xml/gtkmessagedialog.xml" />
@@ -149,7 +187,6 @@
<xi:include href="xml/gtkscalebutton.xml" />
<xi:include href="xml/gtkvolumebutton.xml" />
<xi:include href="xml/gtklockbutton.xml" />
<xi:include href="xml/gtkmodelbutton.xml" />
</chapter>
<chapter id="NumericEntry">
@@ -229,6 +266,7 @@
<xi:include href="xml/gtkpopover.xml" />
<xi:include href="xml/gtkpopovermenu.xml" />
<xi:include href="xml/gtkpopovermenubar.xml" />
<xi:include href="xml/gtkdropdown.xml" />
</chapter>
<chapter id="SelectorWidgets">

File diff suppressed because it is too large Load Diff

View File

@@ -9,6 +9,7 @@ gtk_accessible_get_type
gtk_actionable_get_type
gtk_action_bar_get_type
gtk_adjustment_get_type
gtk_any_filter_get_type
gtk_app_chooser_get_type
gtk_app_chooser_button_get_type
gtk_app_chooser_dialog_get_type
@@ -22,8 +23,11 @@ gtk_bin_get_type
gtk_bin_layout_get_type
gtk_box_get_type
gtk_box_layout_get_type
gtk_builder_get_type
gtk_buildable_get_type
gtk_builder_cscope_get_type
gtk_builder_get_type
gtk_builder_list_item_factory_get_type
gtk_builder_scope_get_type
gtk_button_get_type
gtk_calendar_get_type
gtk_cell_area_get_type
@@ -47,6 +51,8 @@ gtk_color_button_get_type
gtk_color_chooser_get_type
gtk_color_chooser_dialog_get_type
gtk_color_chooser_widget_get_type
gtk_column_view_get_type
gtk_column_view_column_get_type
gtk_combo_box_get_type
gtk_combo_box_text_get_type
gtk_constraint_get_type
@@ -54,9 +60,13 @@ gtk_constraint_guide_get_type
gtk_constraint_layout_get_type
gtk_constraint_target_get_type
gtk_container_get_type
gtk_custom_sorter_get_type
gtk_css_provider_get_type
gtk_custom_filter_get_type
gtk_dialog_get_type
gtk_directory_list_get_type
gtk_drawing_area_get_type
gtk_drop_down_get_type
gtk_editable_get_type
gtk_entry_buffer_get_type
gtk_entry_completion_get_type
@@ -66,14 +76,18 @@ gtk_event_controller_key_get_type
gtk_event_controller_legacy_get_type
gtk_event_controller_motion_get_type
gtk_event_controller_scroll_get_type
gtk_every_filter_get_type
gtk_expander_get_type
gtk_file_chooser_button_get_type
gtk_file_chooser_dialog_get_type
gtk_file_chooser_get_type
gtk_file_chooser_widget_get_type
gtk_file_filter_get_type
gtk_filter_get_type
gtk_filter_list_model_get_type
gtk_fixed_get_type
gtk_fixed_layout_get_type
gtk_flatten_list_model_get_type
gtk_flow_box_get_type
gtk_flow_box_child_get_type
gtk_font_button_get_type
@@ -95,6 +109,7 @@ gtk_gl_area_get_type
gtk_grid_get_type
gtk_grid_layout_child_get_type
gtk_grid_layout_get_type
gtk_grid_view_get_type
gtk_header_bar_get_type
gtk_icon_theme_get_type
gtk_icon_view_get_type
@@ -107,10 +122,14 @@ gtk_label_get_type
gtk_layout_child_get_type
gtk_layout_manager_get_type
gtk_link_button_get_type
gtk_list_item_get_type
gtk_list_item_factory_get_type
gtk_list_store_get_type
gtk_list_box_get_type
gtk_list_box_row_get_type
gtk_list_view_get_type
gtk_lock_button_get_type
gtk_map_list_model_get_type
gtk_media_controls_get_type
gtk_media_file_get_type
gtk_media_stream_get_type
@@ -121,11 +140,14 @@ gtk_menu_item_get_type
gtk_menu_shell_get_type
gtk_menu_tool_button_get_type
gtk_message_dialog_get_type
gtk_model_button_get_type
gtk_mount_operation_get_type
gtk_multi_filter_get_type
gtk_multi_sorter_get_type
gtk_native_get_type
gtk_no_selection_get_type
gtk_notebook_get_type
gtk_notebook_page_get_type
gtk_numeric_sorter_get_type
gtk_orientable_get_type
gtk_overlay_get_type
gtk_pad_controller_get_type
@@ -170,9 +192,13 @@ gtk_shortcuts_window_get_type
gtk_shortcuts_section_get_type
gtk_shortcuts_group_get_type
gtk_shortcuts_shortcut_get_type
gtk_signal_list_item_factory_get_type
gtk_single_selection_get_type
gtk_size_group_get_type
gtk_slice_list_model_get_type
gtk_snapshot_get_type
gtk_sort_list_model_get_type
gtk_sorter_get_type
gtk_spin_button_get_type
gtk_spinner_get_type
gtk_stack_get_type
@@ -180,6 +206,8 @@ gtk_stack_page_get_type
gtk_stack_sidebar_get_type
gtk_stack_switcher_get_type
gtk_statusbar_get_type
gtk_string_filter_get_type
gtk_string_sorter_get_type
gtk_switch_get_type
gtk_level_bar_get_type
gtk_style_context_get_type
@@ -199,6 +227,10 @@ gtk_tool_button_get_type
gtk_tool_item_get_type
gtk_tree_drag_dest_get_type
gtk_tree_drag_source_get_type
gtk_tree_expander_get_type
gtk_tree_list_model_get_type
gtk_tree_list_row_get_type
gtk_tree_list_row_sorter_get_type
gtk_tree_model_filter_get_type
gtk_tree_model_get_type
gtk_tree_model_sort_get_type

View File

@@ -21,6 +21,13 @@ private_headers = [
'gtkcolorplaneprivate.h',
'gtkcolorscaleprivate.h',
'gtkcolorswatchprivate.h',
'gtkcolumnviewcellprivate.h',
'gtkcolumnviewcolumnprivate.h',
'gtkcolumnviewlayoutprivate.h',
'gtkcolumnlistitemfactoryprivate.h',
'gtkcolumviewprivate.h',
'gtkcolumnviewsorterprivate.h',
'gtkcolumnviewtitleprivate.h',
'gtkcomboboxprivate.h',
'gtkcontainerprivate.h',
'gtkconstraintexpressionprivate.h',
@@ -131,6 +138,11 @@ private_headers = [
'gtkimmoduleprivate.h',
'gtkkineticscrollingprivate.h',
'gtklabelprivate.h',
'gtklistbaseprivate.h',
'gtklistitemprivate.h',
'gtklistitemfactoryprivate.h',
'gtklistitemmanagerprivate.h',
'gtklistitemwidgetprivate.h',
'gtklockbuttonprivate.h',
'gtkmagnifierprivate.h',
'gtkmediafileprivate.h',
@@ -178,8 +190,10 @@ private_headers = [
'gtktextchildprivate.h',
'gtktextdisplayprivate.h',
'gtktexthandleprivate.h',
'gtktexthistoryprivate.h',
'gtktextiterprivate.h',
'gtktextlayoutprivate.h',
'gtktextlinedisplaycacheprivate.h',
'gtktextmarkprivate.h',
'gtktexttagprivate.h',
'gtktextviewprivate.h',

View File

@@ -828,6 +828,29 @@
</para>
</section>
<section>
<title>The "iconified" window state has been renamed to "minimized"</title>
<para>
The <literal>GDK_SURFACE_STATE_ICONIFIED</literal> value of the
#GdkSurfaceState enumeration is now %GDK_SURFACE_STATE_MINIMIZED.
</para>
<para>
The #GdkSurface functions <function>gdk_surface_iconify()</function>
and <function>gdk_surface_deiconify()</function> have been renamed to
gdk_surface_minimize() and gdk_surface_unminimize(), respectively.
</para>
<para>
The corresponding #GtkWindow functions <function>gtk_window_iconify()</function>
and <function>gtk_window_deiconify()</function> have been renamed
to gtk_window_minimize() and gtk_window_unminimize(), respectively.
</para>
<para>
The behavior of the minimization and unminimization operations have
not been changed, and they still require support from the underlying
windowing system.
</para>
</section>
</section>
</chapter>

View File

@@ -138,7 +138,7 @@ url="http://www.freedesktop.org/standards/">convention</ulink>.
<para>
GTK has functions for asking the window manager to do various things;
see for example <link
linkend="gtk-window-iconify">gtk_window_iconify()</link> or <link
linkend="gtk-window-minimize">gtk_window_minimize()</link> or <link
linkend="gtk-window-maximize">gtk_window_maximize()</link> or <link
linkend="gtk-window-set-decorated">gtk_window_set_decorated()</link>.
Keep in mind that most window managers <emphasis>will</emphasis> ignore

View File

@@ -25,8 +25,8 @@
#ifndef __GDK_BROADWAY_CURSOR_H__
#define __GDK_BROADWAY_CURSOR_H__
#if !defined (__GDKBROADWAY_H_INSIDE__) && !defined (GDK_COMPILATION)
#error "Only <gdk/gdkbroadway.h> can be included directly."
#if !defined (__GDKBROADWAY_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/broadway/gdkbroadway.h> can be included directly."
#endif
#include <gdk/gdk.h>
@@ -40,7 +40,7 @@ G_BEGIN_DECLS
#define GDK_IS_BROADWAY_CURSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_BROADWAY_CURSOR))
#define GDK_BROADWAY_CURSOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_BROADWAY_CURSOR, GdkBroadwayCursorClass))
#ifdef GDK_COMPILATION
#ifdef GTK_COMPILATION
typedef struct _GdkBroadwayCursor GdkBroadwayCursor;
#else
typedef GdkCursor GdkBroadwayCursor;

View File

@@ -18,15 +18,15 @@
#ifndef __GDK_BROADWAY_DISPLAY_H__
#define __GDK_BROADWAY_DISPLAY_H__
#if !defined (__GDKBROADWAY_H_INSIDE__) && !defined (GDK_COMPILATION)
#error "Only <gdk/gdkbroadway.h> can be included directly."
#if !defined (__GDKBROADWAY_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/broadway/gdkbroadway.h> can be included directly."
#endif
#include <gdk/gdk.h>
G_BEGIN_DECLS
#ifdef GDK_COMPILATION
#ifdef GTK_COMPILATION
typedef struct _GdkBroadwayDisplay GdkBroadwayDisplay;
#else
typedef GdkDisplay GdkBroadwayDisplay;

View File

@@ -20,8 +20,8 @@
#ifndef __GDK_BROADWAY_DISPLAY_MANAGER_H__
#define __GDK_BROADWAY_DISPLAY_MANAGER_H__
#if !defined(__GDKBROADWAY_H_INSIDE__) && !defined (GDK_COMPILATION)
#error "Only <gdk/gdkbroadway.h> can be included directly."
#if !defined(__GDKBROADWAY_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/broadway/gdkbroadway.h> can be included directly."
#endif
#include <gdk/gdk.h>
@@ -31,7 +31,7 @@ G_BEGIN_DECLS
#define GDK_TYPE_BROADWAY_DISPLAY_MANAGER (gdk_broadway_display_manager_get_type ())
#define GDK_BROADWAY_DISPLAY_MANAGER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_BROADWAY_DISPLAY_MANAGER, GdkBroadwayDisplayManager))
#ifdef GDK_COMPILATION
#ifdef GTK_COMPILATION
typedef struct _GdkBroadwayDisplayManager GdkBroadwayDisplayManager;
#else
typedef GdkDisplayManager _GdkBroadwayDisplayManager;

View File

@@ -22,8 +22,8 @@
#ifndef __GDK_BROADWAY_MONITOR_H__
#define __GDK_BROADWAY_MONITOR_H__
#if !defined (__GDKBROADWAY_H_INSIDE__) && !defined (GDK_COMPILATION)
#error "Only <gdk/gdkbroadway.h> can be included directly."
#if !defined (__GDKBROADWAY_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/broadway/gdkbroadway.h> can be included directly."
#endif
#include <gdk/gdkmonitor.h>

View File

@@ -36,7 +36,7 @@ G_BEGIN_DECLS
#define GDK_IS_BROADWAY_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_BROADWAY_SURFACE))
#define GDK_BROADWAY_SURFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_BROADWAY_SURFACE, GdkBroadwaySurfaceClass))
#ifdef GDK_COMPILATION
#ifdef GTK_COMPILATION
typedef struct _GdkBroadwaySurface GdkBroadwaySurface;
#else
typedef GdkSurface GdkBroadwaySurface;

View File

@@ -41,7 +41,7 @@
#define GDK_IS_BROADWAY_DRAG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_BROADWAY_DRAG))
#define GDK_BROADWAY_DRAG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_BROADWAY_DRAG, GdkBroadwayDragClass))
#ifdef GDK_COMPILATION
#ifdef GTK_COMPILATION
typedef struct _GdkBroadwayDrag GdkBroadwayDrag;
#else
typedef GdkDrag GdkBroadwayDrag;

View File

@@ -710,7 +710,7 @@ gdk_broadway_surface_set_icon_name (GdkSurface *surface,
}
static void
gdk_broadway_surface_iconify (GdkSurface *surface)
gdk_broadway_surface_minimize (GdkSurface *surface)
{
if (GDK_SURFACE_DESTROYED (surface) ||
!SURFACE_IS_TOPLEVEL (surface))
@@ -718,7 +718,7 @@ gdk_broadway_surface_iconify (GdkSurface *surface)
}
static void
gdk_broadway_surface_deiconify (GdkSurface *surface)
gdk_broadway_surface_unminimize (GdkSurface *surface)
{
if (GDK_SURFACE_DESTROYED (surface) ||
!SURFACE_IS_TOPLEVEL (surface))
@@ -1413,8 +1413,8 @@ gdk_broadway_surface_class_init (GdkBroadwaySurfaceClass *klass)
impl_class->set_focus_on_map = gdk_broadway_surface_set_focus_on_map;
impl_class->set_icon_list = gdk_broadway_surface_set_icon_list;
impl_class->set_icon_name = gdk_broadway_surface_set_icon_name;
impl_class->iconify = gdk_broadway_surface_iconify;
impl_class->deiconify = gdk_broadway_surface_deiconify;
impl_class->minimize = gdk_broadway_surface_minimize;
impl_class->unminimize = gdk_broadway_surface_unminimize;
impl_class->stick = gdk_broadway_surface_stick;
impl_class->unstick = gdk_broadway_surface_unstick;
impl_class->maximize = gdk_broadway_surface_maximize;

View File

@@ -57,7 +57,7 @@ libgdk_broadway = static_library('gdk-broadway',
gdk_broadway_sources, gdkconfig, gdkenum_h,
include_directories: [confinc, gdkinc],
c_args: [
'-DGDK_COMPILATION',
'-DGTK_COMPILATION',
'-DG_LOG_DOMAIN="Gdk"',
] + common_cflags,
link_args: common_ldflags,
@@ -71,6 +71,6 @@ executable('gtk4-broadwayd',
clienthtml_h, broadwayjs_h,
'broadwayd.c', 'broadway-server.c', 'broadway-output.c',
include_directories: [confinc, gdkinc, include_directories('.')],
c_args: ['-DGDK_COMPILATION', '-DG_LOG_DOMAIN="Gdk"', ],
c_args: ['-DGTK_COMPILATION', '-DG_LOG_DOMAIN="Gdk"', ],
dependencies : [broadwayd_syslib, gdk_deps],
install : true)

341
gdk/filetransferportal.c Normal file
View File

@@ -0,0 +1,341 @@
/*
* Copyright (C) 2018 Matthias Clasen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <gio/gio.h>
#include <gio/gunixfdlist.h>
#include "filetransferportalprivate.h"
static GDBusProxy *file_transfer_proxy = NULL;
static GDBusProxy *
ensure_file_transfer_portal (void)
{
if (file_transfer_proxy == NULL)
{
GError *error = NULL;
file_transfer_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
| G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS
| G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
NULL,
"org.freedesktop.portal.Documents",
"/org/freedesktop/portal/documents",
"org.freedesktop.portal.FileTransfer",
NULL, &error);
if (error)
{
g_debug ("Failed to get proxy: %s", error->message);
g_error_free (error);
}
}
if (file_transfer_proxy)
{
char *owner = g_dbus_proxy_get_name_owner (file_transfer_proxy);
if (owner)
{
g_free (owner);
return file_transfer_proxy;
}
}
return NULL;
}
gboolean
file_transfer_portal_available (void)
{
gboolean available;
ensure_file_transfer_portal ();
available = file_transfer_proxy != NULL;
g_clear_object (&file_transfer_proxy);
return available;
}
typedef struct {
GTask *task;
const char **files;
int len;
int start;
} AddFileData;
static void add_files (GDBusProxy *proxy,
AddFileData *afd);
static void
add_files_done (GObject *object,
GAsyncResult *result,
gpointer data)
{
GDBusProxy *proxy = G_DBUS_PROXY (object);
AddFileData *afd = data;
GError *error = NULL;
GVariant *ret;
ret = g_dbus_proxy_call_with_unix_fd_list_finish (proxy, NULL, result, &error);
if (ret == NULL)
{
g_task_return_error (afd->task, error);
g_object_unref (afd->task);
g_free (afd);
return;
}
g_variant_unref (ret);
if (afd->start >= afd->len)
{
g_task_return_boolean (afd->task, TRUE);
g_object_unref (afd->task);
g_free (afd);
return;
}
add_files (proxy, afd);
}
/* We call AddFiles in chunks of 16 to avoid running into
* the per-message fd limit of the bus.
*/
static void
add_files (GDBusProxy *proxy,
AddFileData *afd)
{
GUnixFDList *fd_list;
GVariantBuilder fds;
int i;
char *key;
g_variant_builder_init (&fds, G_VARIANT_TYPE ("ah"));
fd_list = g_unix_fd_list_new ();
for (i = 0; afd->files[afd->start + i]; i++)
{
int fd;
int fd_in;
GError *error = NULL;
if (i == 16)
break;
fd = open (afd->files[afd->start + i], O_PATH | O_CLOEXEC);
if (fd == -1)
{
g_task_return_new_error (afd->task, G_IO_ERROR, g_io_error_from_errno (errno),
"Failed to open %s", afd->files[afd->start + i]);
g_object_unref (afd->task);
g_free (afd);
g_object_unref (fd_list);
return;
}
fd_in = g_unix_fd_list_append (fd_list, fd, &error);
close (fd);
if (fd_in == -1)
{
g_task_return_error (afd->task, error);
g_object_unref (afd->task);
g_free (afd);
g_object_unref (fd_list);
return;
}
g_variant_builder_add (&fds, "h", fd_in);
}
afd->start += 16;
key = (char *)g_object_get_data (G_OBJECT (afd->task), "key");
g_dbus_proxy_call_with_unix_fd_list (proxy,
"AddFiles",
g_variant_new ("(sah)", key, &fds),
0, -1,
fd_list,
NULL,
add_files_done, afd);
g_object_unref (fd_list);
}
static void
start_session_done (GObject *object,
GAsyncResult *result,
gpointer data)
{
GDBusProxy *proxy = G_DBUS_PROXY (object);
AddFileData *afd = data;
GError *error = NULL;
GVariant *ret;
const char *key;
ret = g_dbus_proxy_call_finish (proxy, result, &error);
if (ret == NULL)
{
g_task_return_error (afd->task, error);
g_object_unref (afd->task);
g_free (afd);
return;
}
g_variant_get (ret, "(&s)", &key);
g_object_set_data_full (G_OBJECT (afd->task), "key", g_strdup (key), g_free);
g_variant_unref (ret);
add_files (proxy, afd);
}
void
file_transfer_portal_register_files (const char **files,
gboolean writable,
GAsyncReadyCallback callback,
gpointer data)
{
GTask *task;
GDBusProxy *proxy;
AddFileData *afd;
GVariantBuilder options;
task = g_task_new (NULL, NULL, callback, data);
proxy = ensure_file_transfer_portal ();
if (proxy == NULL)
{
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
"No portal found");
g_object_unref (task);
return;
}
afd = g_new (AddFileData, 1);
afd->task = task;
afd->files = files;
afd->len = g_strv_length ((char **)files);
afd->start = 0;
g_variant_builder_init (&options, G_VARIANT_TYPE_VARDICT);
g_variant_builder_add (&options, "{sv}", "writable", g_variant_new_boolean (writable));
g_variant_builder_add (&options, "{sv}", "autostop", g_variant_new_boolean (TRUE));
g_dbus_proxy_call (proxy, "StartTransfer",
g_variant_new ("(a{sv})", &options),
0, -1, NULL, start_session_done, afd);
}
gboolean
file_transfer_portal_register_files_finish (GAsyncResult *result,
char **key,
GError **error)
{
if (g_task_propagate_boolean (G_TASK (result), error))
{
*key = g_strdup (g_object_get_data (G_OBJECT (result), "key"));
return TRUE;
}
return FALSE;
}
static void
retrieve_files_done (GObject *object,
GAsyncResult *result,
gpointer data)
{
GDBusProxy *proxy = G_DBUS_PROXY (object);
GTask *task = data;
GError *error = NULL;
GVariant *ret;
char **files;
ret = g_dbus_proxy_call_finish (proxy, result, &error);
if (ret == NULL)
{
g_task_return_error (task, error);
g_object_unref (task);
return;
}
g_variant_get (ret, "(^a&s)", &files);
g_object_set_data_full (G_OBJECT (task), "files", g_strdupv (files), (GDestroyNotify)g_strfreev);
g_variant_unref (ret);
g_task_return_boolean (task, TRUE);
}
void
file_transfer_portal_retrieve_files (const char *key,
GAsyncReadyCallback callback,
gpointer data)
{
GDBusProxy *proxy;
GTask *task;
GVariantBuilder options;
task = g_task_new (NULL, NULL, callback, data);
proxy = ensure_file_transfer_portal ();
if (proxy == NULL)
{
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
"No portal found");
g_object_unref (task);
return;
}
g_variant_builder_init (&options, G_VARIANT_TYPE_VARDICT);
g_dbus_proxy_call (proxy,
"RetrieveFiles",
g_variant_new ("(sa{sv})", key, &options),
0, -1, NULL,
retrieve_files_done, task);
}
gboolean
file_transfer_portal_retrieve_files_finish (GAsyncResult *result,
char ***files,
GError **error)
{
if (g_task_propagate_boolean (G_TASK (result), error))
{
*files = g_strdupv (g_object_get_data (G_OBJECT (result), "files"));
return TRUE;
}
return FALSE;
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2018 Matthias Clasen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FILE_TRANSFER_PROTOCOL_H__
#define __FILE_TRANSFER_PROTOCOL_H__
gboolean file_transfer_portal_available (void);
void file_transfer_portal_register_files (const char **files,
gboolean writable,
GAsyncReadyCallback callback,
gpointer data);
gboolean file_transfer_portal_register_files_finish (GAsyncResult *result,
char **key,
GError **error);
void file_transfer_portal_retrieve_files (const char *key,
GAsyncReadyCallback callback,
gpointer data);
gboolean file_transfer_portal_retrieve_files_finish (GAsyncResult *result,
char ***files,
GError **error);
#endif

View File

@@ -15,27 +15,19 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
#ifndef __GI_SCANNER__
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkAppLaunchContext, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkClipboard, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkContentProvider, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkCursor, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkDevice, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkDisplay, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkDisplayManager, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkDrag, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkDrawContext, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkFrameClock, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkGLContext, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkKeymap, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkMonitor, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkSeat, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkVulkanContext, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkSurface, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkContentFormats, gdk_content_formats_unref)

View File

@@ -21,7 +21,7 @@
#ifndef __GDK_APP_LAUNCH_CONTEXT_H__
#define __GDK_APP_LAUNCH_CONTEXT_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif

View File

@@ -18,7 +18,7 @@
#ifndef __GDK_CAIRO_H__
#define __GDK_CAIRO_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif

View File

@@ -21,7 +21,7 @@
#ifndef __GDK_CAIRO_CONTEXT__
#define __GDK_CAIRO_CONTEXT__
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
@@ -32,14 +32,11 @@
G_BEGIN_DECLS
#define GDK_TYPE_CAIRO_CONTEXT (gdk_cairo_context_get_type ())
#define GDK_CAIRO_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_CAIRO_CONTEXT, GdkCairoContext))
#define GDK_IS_CAIRO_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_CAIRO_CONTEXT))
#define GDK_CAIRO_ERROR (gdk_cairo_error_quark ())
#define GDK_TYPE_CAIRO_CONTEXT (gdk_cairo_context_get_type ())
GDK_AVAILABLE_IN_ALL
GType gdk_cairo_context_get_type (void) G_GNUC_CONST;
GDK_DECLARE_EXPORTED_TYPE (GdkCairoContext, gdk_cairo_context, GDK, CAIRO_CONTEXT)
GDK_AVAILABLE_IN_ALL
cairo_t * gdk_cairo_context_cairo_create (GdkCairoContext *self);

View File

@@ -29,12 +29,6 @@
G_BEGIN_DECLS
#define GDK_CAIRO_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_CAIRO_CONTEXT, GdkCairoContextClass))
#define GDK_IS_CAIRO_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_CAIRO_CONTEXT))
#define GDK_CAIRO_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_CAIRO_CONTEXT, GdkCairoContextClass))
typedef struct _GdkCairoContextClass GdkCairoContextClass;
struct _GdkCairoContext
{
GdkDrawContext parent_instance;

View File

@@ -1054,6 +1054,7 @@ gdk_clipboard_write_serialize_done (GObject *content,
g_object_unref (task);
}
void
gdk_clipboard_write_async (GdkClipboard *clipboard,
const char *mime_type,

View File

@@ -19,7 +19,7 @@
#ifndef __GDK_CLIPBOARD_H__
#define __GDK_CLIPBOARD_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
@@ -31,11 +31,8 @@
G_BEGIN_DECLS
#define GDK_TYPE_CLIPBOARD (gdk_clipboard_get_type ())
#define GDK_CLIPBOARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_CLIPBOARD, GdkClipboard))
#define GDK_IS_CLIPBOARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_CLIPBOARD))
GDK_AVAILABLE_IN_ALL
GType gdk_clipboard_get_type (void) G_GNUC_CONST;
GDK_DECLARE_EXPORTED_TYPE (GdkClipboard, gdk_clipboard, GDK, CLIPBOARD)
GDK_AVAILABLE_IN_ALL
GdkDisplay * gdk_clipboard_get_display (GdkClipboard *clipboard);

View File

@@ -22,12 +22,6 @@
G_BEGIN_DECLS
#define GDK_CLIPBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_CLIPBOARD, GdkClipboardClass))
#define GDK_IS_CLIPBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_CLIPBOARD))
#define GDK_CLIPBOARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_CLIPBOARD, GdkClipboardClass))
typedef struct _GdkClipboardClass GdkClipboardClass;
struct _GdkClipboard
{
GObject parent;

View File

@@ -1,7 +1,7 @@
#ifndef __GDKCONFIG_H__
#define __GDKCONFIG_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif

View File

@@ -6,7 +6,7 @@
#ifndef __GDKCONFIG_H__
#define __GDKCONFIG_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif

View File

@@ -6,7 +6,7 @@
#ifndef __GDKCONFIG_H__
#define __GDKCONFIG_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif

View File

@@ -22,6 +22,7 @@
#include "gdkcontentdeserializer.h"
#include "gdkcontentformats.h"
#include "filetransferportalprivate.h"
#include "gdktexture.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
@@ -690,6 +691,93 @@ string_deserializer (GdkContentDeserializer *deserializer)
g_object_unref (filter);
}
static void
portal_finish (GObject *object,
GAsyncResult *result,
gpointer deserializer)
{
char **files = NULL;
GError *error = NULL;
GValue *value;
if (!file_transfer_portal_retrieve_files_finish (result, &files, &error))
{
gdk_content_deserializer_return_error (deserializer, error);
return;
}
value = gdk_content_deserializer_get_value (deserializer);
if (G_VALUE_HOLDS (value, G_TYPE_FILE))
{
if (files[0] != NULL)
g_value_take_object (value, g_file_new_for_path (files[0]));
}
else
{
GSList *l = NULL;
gsize i;
for (i = 0; files[i] != NULL; i++)
l = g_slist_prepend (l, g_file_new_for_path (files[i]));
g_value_take_boxed (value, g_slist_reverse (l));
}
g_strfreev (files);
gdk_content_deserializer_return_success (deserializer);
}
static void
portal_file_deserializer_finish (GObject *source,
GAsyncResult *result,
gpointer deserializer)
{
GOutputStream *stream = G_OUTPUT_STREAM (source);
GError *error = NULL;
gssize written;
char *key;
written = g_output_stream_splice_finish (stream, result, &error);
if (written < 0)
{
gdk_content_deserializer_return_error (deserializer, error);
return;
}
/* write terminating NULL */
if (!g_output_stream_write (stream, "", 1, NULL, &error))
{
gdk_content_deserializer_return_error (deserializer, error);
return;
}
key = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (stream));
if (key == NULL)
{
deserialize_not_found (deserializer);
return;
}
file_transfer_portal_retrieve_files (key, portal_finish, deserializer);
gdk_content_deserializer_set_task_data (deserializer, key, g_free);
}
static void
portal_file_deserializer (GdkContentDeserializer *deserializer)
{
GOutputStream *output;
output = g_memory_output_stream_new_resizable ();
g_output_stream_splice_async (output,
gdk_content_deserializer_get_input_stream (deserializer),
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
gdk_content_deserializer_get_priority (deserializer),
gdk_content_deserializer_get_cancellable (deserializer),
portal_file_deserializer_finish,
deserializer);
g_object_unref (output);
}
static void
file_uri_deserializer_finish (GObject *source,
GAsyncResult *result,
@@ -764,6 +852,7 @@ init (void)
static gboolean initialized = FALSE;
GSList *formats, *f;
const char *charset;
gboolean has_portal;
if (initialized)
return;
@@ -816,11 +905,24 @@ init (void)
g_slist_free (formats);
has_portal = file_transfer_portal_available ();
if (has_portal)
gdk_content_register_deserializer ("application/vnd.portal.files",
GDK_TYPE_FILE_LIST,
portal_file_deserializer,
NULL,
NULL);
gdk_content_register_deserializer ("text/uri-list",
GDK_TYPE_FILE_LIST,
file_uri_deserializer,
NULL,
NULL);
if (has_portal)
gdk_content_register_deserializer ("application/vnd.portal.files",
G_TYPE_FILE,
portal_file_deserializer,
NULL,
NULL);
gdk_content_register_deserializer ("text/uri-list",
G_TYPE_FILE,
file_uri_deserializer,

View File

@@ -18,7 +18,7 @@
#ifndef __GTK_CONTENT_DESERIALIZER_H__
#define __GTK_CONTENT_DESERIALIZER_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif

View File

@@ -18,7 +18,7 @@
#ifndef __GTK_CONTENT_FORMATS_H__
#define __GTK_CONTENT_FORMATS_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif

View File

@@ -19,7 +19,7 @@
#ifndef __GDK_CONTENT_PROVIDER_H__
#define __GDK_CONTENT_PROVIDER_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif

View File

@@ -19,7 +19,7 @@
#ifndef __GDK_CONTENT_PROVIDER_IMPL_H__
#define __GDK_CONTENT_PROVIDER_IMPL_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif

View File

@@ -23,6 +23,7 @@
#include "gdkcontentformats.h"
#include "gdkpixbuf.h"
#include "filetransferportalprivate.h"
#include "gdktextureprivate.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
@@ -701,6 +702,63 @@ file_serializer_finish (GObject *source,
gdk_content_serializer_return_success (serializer);
}
static void
portal_ready (GObject *object,
GAsyncResult *result,
gpointer serializer)
{
GError *error = NULL;
char *key;
if (!file_transfer_portal_register_files_finish (result, &key, &error))
{
gdk_content_serializer_return_error (serializer, error);
return;
}
g_output_stream_write_all_async (gdk_content_serializer_get_output_stream (serializer),
key,
strlen (key) + 1,
gdk_content_serializer_get_priority (serializer),
gdk_content_serializer_get_cancellable (serializer),
file_serializer_finish,
serializer);
gdk_content_serializer_set_task_data (serializer, key, g_free);
}
static void
portal_file_serializer (GdkContentSerializer *serializer)
{
GFile *file;
const GValue *value;
GPtrArray *files;
files = g_ptr_array_new_with_free_func (g_free);
value = gdk_content_serializer_get_value (serializer);
if (G_VALUE_HOLDS (value, G_TYPE_FILE))
{
file = g_value_get_object (gdk_content_serializer_get_value (serializer));
if (file)
g_ptr_array_add (files, g_file_get_path (file));
g_ptr_array_add (files, NULL);
}
else if (G_VALUE_HOLDS (value, GDK_TYPE_FILE_LIST))
{
GSList *l;
for (l = g_value_get_boxed (value); l; l = l->next)
g_ptr_array_add (files, g_file_get_path (l->data));
g_ptr_array_add (files, NULL);
}
/* this call doesn't copy the strings, so keep the array around until the registration is done */
file_transfer_portal_register_files ((const char **)files->pdata, TRUE, portal_ready, serializer);
gdk_content_serializer_set_task_data (serializer, files, (GDestroyNotify)g_ptr_array_unref);
}
static void
file_uri_serializer (GdkContentSerializer *serializer)
{
@@ -808,6 +866,7 @@ init (void)
static gboolean initialized = FALSE;
GSList *formats, *f;
const char *charset;
gboolean has_portal;
if (initialized)
return;
@@ -863,6 +922,14 @@ init (void)
g_slist_free (formats);
has_portal = file_transfer_portal_available ();
if (has_portal)
gdk_content_register_serializer (G_TYPE_FILE,
"application/vnd.portal.files",
portal_file_serializer,
NULL,
NULL);
gdk_content_register_serializer (G_TYPE_FILE,
"text/uri-list",
file_uri_serializer,
@@ -873,6 +940,12 @@ init (void)
file_text_serializer,
NULL,
NULL);
if (has_portal)
gdk_content_register_serializer (GDK_TYPE_FILE_LIST,
"application/vnd.portal.files",
portal_file_serializer,
NULL,
NULL);
gdk_content_register_serializer (GDK_TYPE_FILE_LIST,
"text/uri-list",
file_uri_serializer,

View File

@@ -18,7 +18,7 @@
#ifndef __GTK_CONTENT_SERIALIZER_H__
#define __GTK_CONTENT_SERIALIZER_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif

View File

@@ -25,7 +25,7 @@
#ifndef __GDK_CURSOR_H__
#define __GDK_CURSOR_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
@@ -35,14 +35,8 @@
G_BEGIN_DECLS
#define GDK_TYPE_CURSOR (gdk_cursor_get_type ())
#define GDK_CURSOR(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_CURSOR, GdkCursor))
#define GDK_IS_CURSOR(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_CURSOR))
/* Cursors
*/
GDK_AVAILABLE_IN_ALL
GType gdk_cursor_get_type (void) G_GNUC_CONST;
GDK_DECLARE_EXPORTED_TYPE (GdkCursor, gdk_cursor, GDK, CURSOR)
GDK_AVAILABLE_IN_ALL
GdkCursor* gdk_cursor_new_from_texture (GdkTexture *texture,

View File

@@ -29,12 +29,6 @@
G_BEGIN_DECLS
#define GDK_CURSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_CURSOR, GdkCursorClass))
#define GDK_IS_CURSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_CURSOR))
#define GDK_CURSOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_CURSOR, GdkCursorClass))
typedef struct _GdkCursorClass GdkCursorClass;
struct _GdkCursor
{
GObject parent_instance;

View File

@@ -18,7 +18,7 @@
#ifndef __GDK_DEVICE_H__
#define __GDK_DEVICE_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
@@ -29,8 +29,8 @@
G_BEGIN_DECLS
#define GDK_TYPE_DEVICE (gdk_device_get_type ())
#define GDK_DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE, GdkDevice))
#define GDK_IS_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE))
GDK_AVAILABLE_IN_ALL
GDK_DECLARE_EXPORTED_TYPE (GdkDevice, gdk_device, GDK, DEVICE)
typedef struct _GdkTimeCoord GdkTimeCoord;
@@ -121,9 +121,6 @@ struct _GdkTimeCoord
gdouble axes[GDK_MAX_TIMECOORD_AXES];
};
GDK_AVAILABLE_IN_ALL
GType gdk_device_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
const gchar * gdk_device_get_name (GdkDevice *device);
GDK_AVAILABLE_IN_ALL

View File

@@ -20,7 +20,7 @@
#ifndef __GDK_DEVICE_PAD_H__
#define __GDK_DEVICE_PAD_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif

View File

@@ -25,11 +25,6 @@
G_BEGIN_DECLS
#define GDK_DEVICE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE, GdkDeviceClass))
#define GDK_IS_DEVICE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE))
#define GDK_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE, GdkDeviceClass))
typedef struct _GdkDeviceClass GdkDeviceClass;
typedef struct _GdkDeviceKey GdkDeviceKey;
struct _GdkDeviceKey

View File

@@ -18,7 +18,7 @@
#ifndef __GDK_DEVICE_TOOL_H__
#define __GDK_DEVICE_TOOL_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif

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