Compare commits

..

176 Commits

Author SHA1 Message Date
Matthias Clasen
c1995384f2 wip: Add GtkMultiSelection
This is implemented using a private GtkSet helper.
2019-12-09 12:10:05 -05:00
Matthias Clasen
9b3f42c695 wip: Add GtkSelectionMonitor
This is a list model that turns a GtkSelectionModel
into a model containing just the selected items.
This is currently only implemented for GtkSingleSelection.
2019-12-09 12:09:19 -05:00
Matthias Clasen
2cee1686a0 wip: Add GtkDropDown
This is a simple drop down control using list models.
2019-12-09 12:02:41 -05:00
Matthias Clasen
3e95a7a09a inspector: Touch up list styling
This is just the minimal amount of work to make
headers recognizable.
2019-12-09 00:03:48 -05:00
Matthias Clasen
e14c079b69 inspector: Use a column view for actions
A straight conversion from list box to column view.
2019-12-09 00:03:48 -05:00
Matthias Clasen
9645142e8c inspector: Make the resource list sortable
This is using a GtkTreeListRowSorter to keep expanded
state of the tree while changing the sorting.
2019-12-09 00:03:48 -05:00
Matthias Clasen
917b1e2d6e Add GtkTreeListRowSorter
This is a special-purpose sorter that can
apply the sorting of another sorter to the
levels of a GtkTreeListModel.
2019-12-09 00:03:48 -05:00
Matthias Clasen
dee6f30fab inspector: Use a column view for the resource list
A conversion from tree view to column view.
2019-12-09 00:03:48 -05:00
Matthias Clasen
152c2b9d22 inspector: Use a column view for properties
Just a straight conversion from list box to column view.
2019-12-09 00:03:48 -05:00
Matthias Clasen
4bfc653311 column view: Add a sort-by api 2019-12-09 00:03:48 -05:00
Matthias Clasen
27f19ca2a7 column view title: Show sort indicators 2019-12-09 00:03:48 -05:00
Matthias Clasen
54ded2a284 column view column: Add a sorter property
This will be used to implement sort by header click.
2019-12-09 00:03:48 -05:00
Matthias Clasen
fdcc452fd6 column view: Add a sorter property
The sorter is where the column view combines the sorters of
individual columns, as the user clicks on headers. To make
sorting take effect, the sorter needs to be associated with
a sort model underneath the model thats shown in the view.
2019-12-09 00:03:48 -05:00
Matthias Clasen
376bf3789b Add 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 - whenever
a header is clicked, that columns 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-09 00:03:48 -05:00
Matthias Clasen
0e59cc5e22 column view: Add some helpers
These functions will be used in updating sort indicators
in column headers.
2019-12-09 00:03:48 -05:00
Matthias Clasen
3f4b8d269e Redo sort list model with GtkSorter
Reshuffle the api to take full advantage
of GtkSorter. Update all callers.
2019-12-09 00:03:48 -05:00
Matthias Clasen
4471171a6a sorter: Add tests
Some basic tests for GtkSorter.
2019-12-09 00:03:48 -05:00
Matthias Clasen
93e2e5e171 Add GtkNumericSorter
This sorter compares numbers obtained from items
by evaluating an expression.
2019-12-09 00:03:48 -05:00
Matthias Clasen
a55d300357 Add GtkMultiSorter
This is a sorter that tries multiple sorters in turn.
2019-12-09 00:03:48 -05:00
Matthias Clasen
3c409a61fd Add GtkSorter, GtkStringSorter, GtkCustomSorter
This is a helper object for sorting. Also add
two implementations, GtkStringSorter for collating
strings, and GtkCustomSorter, which uses a GCompareDataFunc.
2019-12-09 00:03:48 -05:00
Matthias Clasen
59a6a3e056 list item factory: Small correction
The vfuncs for signals in GtkSignalListItemFactory
had the wrong 'this' type.
2019-12-09 00:03:44 -05:00
Matthias Clasen
e1ab8db88d filter: Add a missing precondition 2019-12-08 14:00:11 -05:00
Matthias Clasen
08beaa6448 filter: Small doc tweaks 2019-12-08 13:56:15 -05:00
Matthias Clasen
65ef4b6bc8 filter: Update tests 2019-12-08 13:56:15 -05:00
Matthias Clasen
dea0397e63 Add missing listmodel and selection types to the docs 2019-12-08 13:56:15 -05:00
Benjamin Otte
c246671634 xxx: WIP fontchooser conversion
It compiles, and no longer crashes insantly. But more work needed.

These changes depend on Pango 1.46's introduction of listmodels, so we
depend on that now.
2019-12-08 06:27:40 +01:00
Benjamin Otte
98c25a449d expression: Allow passing a this object to bind()
This gives a bit more control over the arguments passed to expressions.
2019-12-08 06:27:40 +01:00
Benjamin Otte
71fd74c88f 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-08 06:27:40 +01:00
Benjamin Otte
8efe92ec69 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-08 06:27:40 +01:00
Benjamin Otte
2f10212e7d xxx: Add a hack to make paintables transform to/from objects
See also: https://gitlab.gnome.org/GNOME/glib/merge_requests/1251
2019-12-08 06:27:40 +01:00
Benjamin Otte
13eb49c525 inspector: Remove private struct for prop editor 2019-12-08 06:27:39 +01:00
Benjamin Otte
531dc407e3 inspector: Make Controller page a GtkWidget 2019-12-08 06:27:39 +01:00
Benjamin Otte
fddd7c9fad inspector: Remove private struct from controllers 2019-12-08 06:27:39 +01:00
Benjamin Otte
1cbfdddb76 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-08 06:27:39 +01:00
Benjamin Otte
24df6869a3 tests: Add testcolumnview 2019-12-08 06:27:39 +01:00
Benjamin Otte
ffbc361c30 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-08 06:27:39 +01:00
Benjamin Otte
48f44e87ab constraint-editor: Don't poke around in widget internals 2019-12-08 06:27:39 +01:00
Benjamin Otte
6ed9df3058 columnview: Fix styling with Adwaita
- Use "treeview" as the node name
- Add .view style class
2019-12-08 06:27:39 +01:00
Benjamin Otte
47ee4bc223 inspector: Port object tree to GtkColumnView 2019-12-08 06:27:39 +01:00
Benjamin Otte
02096df981 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-08 06:27:39 +01:00
Benjamin Otte
63afc41eb8 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-08 06:27:39 +01:00
Benjamin Otte
5822d13763 columnview: Implement GtkScrollable
Just forward it to the listview for now.
2019-12-08 06:27:39 +01:00
Benjamin Otte
55018bc21a columnview: Add listitems for the columns
They are not aligned in columns yet, but they do exist.
2019-12-08 06:27:39 +01:00
Benjamin Otte
78e055c080 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-08 06:27:39 +01:00
Benjamin Otte
77b7c56de2 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-08 06:27:39 +01:00
Benjamin Otte
804e253f80 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-08 06:27:39 +01:00
Benjamin Otte
534fda92fa 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-08 06:27:39 +01:00
Benjamin Otte
0c1336f959 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-08 06:27:39 +01:00
Benjamin Otte
093c37a046 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-08 06:27:39 +01:00
Benjamin Otte
567548c11d 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-08 06:27:39 +01:00
Benjamin Otte
b4a6262b70 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-08 06:27:39 +01:00
Benjamin Otte
81264fa7ad Add GtkSignalListItemFactory
So the poor Rust users can actually use this.

I would totally not use this ever!
2019-12-08 06:27:39 +01:00
Benjamin Otte
002fafc160 columnview: Allow adding/removing columns
... and make that work in UI files via <child>, too.
2019-12-08 06:27:39 +01:00
Benjamin Otte
4c7d053db9 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-08 06:27:39 +01:00
Benjamin Otte
2b3f716ec3 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-08 06:27:39 +01:00
Benjamin Otte
a11c5e7741 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-08 06:27:39 +01:00
Benjamin Otte
35c177bae9 listbase: Take over anchor handling
With that, pretty much all code but allocating the widgets is gone from
the gridview and listview.
2019-12-08 06:27:39 +01:00
Benjamin Otte
c25dc91fab 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-08 06:27:39 +01:00
Benjamin Otte
52194f94dd 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-08 06:27:39 +01:00
Benjamin Otte
87ae1d94df 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-08 06:27:39 +01:00
Benjamin Otte
1717d30416 listbase: Move orientable implementation here 2019-12-08 06:27:39 +01:00
Benjamin Otte
0852f011de listbase: Move selection handling here 2019-12-08 06:27:39 +01:00
Benjamin Otte
da5f3a2ca3 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-08 06:27:39 +01:00
Benjamin Otte
b6d965af21 listbase: Move GtkScrollable implementation
Shared code between GtkGridView and GtkListView.
2019-12-08 06:27:39 +01:00
Benjamin Otte
ec2600c0f0 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-08 06:27:39 +01:00
Benjamin Otte
f7f3a9bd61 gridview: Simplify allocation code
It doesn't fix the bug I'm after, but it looks a lot better.
2019-12-08 06:27:39 +01:00
Benjamin Otte
c2102e5a1c 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-08 06:27:39 +01:00
Benjamin Otte
ab470f0c25 demo: Add a file browser demo 2019-12-08 06:27:39 +01:00
Benjamin Otte
89d48be883 gridview: Add move keybindings 2019-12-08 06:27:39 +01:00
Benjamin Otte
30ee9b0ab9 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-08 06:27:39 +01:00
Benjamin Otte
5954d8f52b gridview: Add a focus tracker
... and use that to properly update selections when moving around with
the arrow keys.
2019-12-08 06:27:39 +01:00
Benjamin Otte
dfbc73e41a gridview: Implement list.scroll-to action 2019-12-08 06:27:39 +01:00
Benjamin Otte
38dac9e7e1 gridview: Add activation 2019-12-08 06:27:39 +01:00
Benjamin Otte
a7947a3e6e 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-08 06:27:39 +01:00
Benjamin Otte
9f258e9544 gridview: Implement the list.select-item action 2019-12-08 06:27:39 +01:00
Benjamin Otte
272078be16 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-08 06:27:39 +01:00
Benjamin Otte
493cb48b5f gridview: Implement anchors and scrolling 2019-12-08 06:27:39 +01:00
Benjamin Otte
3cdb350769 widget: Add gtk_widget_get_size()
A little bit of convenience.
2019-12-08 06:27:39 +01:00
Benjamin Otte
2d380ca4d3 listitemmanager: Handle NULL factory
Just don't call it and create empty listitems.
2019-12-08 06:27:39 +01:00
Timm Bäder
ec50a66897 demo: Use a listview as sidebar 2019-12-08 06:27:39 +01:00
Benjamin Otte
d2efd6bb99 gtk-demo: Introduce awards
We need a way to get a useful listbox, so here we go!
2019-12-08 06:27:39 +01:00
Benjamin Otte
6bf147c651 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-08 06:27:39 +01:00
Benjamin Otte
6daa313718 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-08 06:27:39 +01:00
Benjamin Otte
dcab637dc1 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-08 06:27:39 +01:00
Benjamin Otte
4404f91685 listview: Add move keybindings
My god, these are a lot.

And my god, these are complicated to get right.
2019-12-08 06:27:39 +01:00
Benjamin Otte
8f1c09b963 listview: Add gtk_list_view_get_position_at_y() 2019-12-08 06:27:39 +01:00
Benjamin Otte
10296ccefe 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-08 06:27:39 +01:00
Benjamin Otte
2d3bcf5b33 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-08 06:27:39 +01:00
Benjamin Otte
9c089ec7d1 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-08 06:27:39 +01:00
Benjamin Otte
227d6977dd listview: Track focus movements and update selection
When focus moves via tab/arrow, we need to select the new item.
2019-12-08 06:27:39 +01:00
Benjamin Otte
ac55bfb999 listview: Implement activation
- a GtkListview::activate signal
- a GtkListItem::activatable property
- activate list items on double clicks and <Enter> presses
2019-12-08 06:27:38 +01:00
Benjamin Otte
be87b6b62d 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-08 06:27:38 +01:00
Benjamin Otte
a28cec61b0 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-08 06:27:38 +01:00
Benjamin Otte
31c5a46537 popover: Remove unneeded vfunc
The vfunc is identical to the GtkWidget implementation it replaces. So
just keep using that one.
2019-12-08 06:27:38 +01:00
Benjamin Otte
95b68384be 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-08 06:27:38 +01:00
Benjamin Otte
8d8152279e inspector: Use a GtkTreeExpander in the object tree 2019-12-08 06:27:38 +01:00
Benjamin Otte
0e84a9d47f inspector: Use a treeexpander in the recorder 2019-12-08 06:27:38 +01:00
Benjamin Otte
6fa7319498 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-08 06:27:38 +01:00
Benjamin Otte
7acfb4d918 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-08 06:27:38 +01:00
Benjamin Otte
90aaab5db9 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-08 06:27:38 +01:00
Benjamin Otte
b9d08d8b23 listview: Pass the CSS name of listitems to the manager
... instead of hardcoding "row".
2019-12-08 06:27:38 +01:00
Benjamin Otte
33ff020d13 gridview: Implement GtkOrientable
Again, this is just the skeleton, because the Gridview does nothing yet.
2019-12-08 06:27:38 +01:00
Benjamin Otte
30f61d38d3 gridview: Add factory handling
Just copy the listview APIs.

Code still doesn't do anything with it.
2019-12-08 06:27:38 +01:00
Benjamin Otte
4ec6d15013 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-08 06:27:38 +01:00
Benjamin Otte
fcb4c8d19b textview: Make cursor work when blinking is disabled 2019-12-08 06:27:38 +01:00
Benjamin Otte
e99b195c18 gtk-demo: Add a rough start at a Weather demo
This demos a horizontal listview.
2019-12-08 06:27:38 +01:00
Benjamin Otte
978119f268 listview: Implement GtkOrientable 2019-12-08 06:27:38 +01:00
Benjamin Otte
b3d16b28fd 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-08 06:27:38 +01:00
Benjamin Otte
136457f60c 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-08 06:27:38 +01:00
Benjamin Otte
29d10ac5ea 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-08 06:27:38 +01:00
Benjamin Otte
b668ad09d9 testlistview: Load icons async
Speeds up loading by 4x, because out of view icons aren't loaded
anymore.
2019-12-08 06:27:38 +01:00
Benjamin Otte
f4d0564074 testlistview: Port to directory list 2019-12-08 06:27:38 +01:00
Benjamin Otte
1b0d8b68d9 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-08 06:27:38 +01:00
Benjamin Otte
734456d6e3 listitemfactory: Split implementation out
.. into gtkfunctionslistitemfactory.c

Now we can add a different implmenetation.
2019-12-08 06:27:38 +01:00
Benjamin Otte
d2f4de1107 listitemfactory: vfuncify
No functional changes other than a new indirection.
2019-12-08 06:27:38 +01:00
Benjamin Otte
e72c56d2e8 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-08 06:27:38 +01:00
Benjamin Otte
73712a9dca listview: Add gtk_list_view_set_show_separators()
Do the same thing that GtkListBox does in commit
0249bd4f8a
2019-12-08 06:27:38 +01:00
Benjamin Otte
2dbc847bab 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-08 06:27:38 +01:00
Benjamin Otte
08f6e3d4e1 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-08 06:27:38 +01:00
Benjamin Otte
be1ffea531 gridview: Implement GtkScrollable
We can now scroll all the nothing we display.

We also clip it properly.
2019-12-08 06:27:38 +01:00
Benjamin Otte
97fbc3b13d listitemmanager: Move list of listitems here
All the listview infrastructure moved with it, so the next step is
moving that back...
2019-12-08 06:27:38 +01:00
Benjamin Otte
5351a95900 wayland: Remove function declaration for nonexisting function 2019-12-08 06:27:38 +01:00
Benjamin Otte
b5d937a497 gridview: Add API for setting number of columns
The API isn't used yet.
2019-12-08 06:27:38 +01:00
Benjamin Otte
7c1da37676 gtk: Add a GtkGridView skeleton 2019-12-08 06:27:38 +01:00
Benjamin Otte
25e896ec40 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-08 06:27:38 +01:00
Benjamin Otte
21f240e99a listview: Add initial support for displaying selections 2019-12-08 06:27:38 +01:00
Benjamin Otte
7b6a2f7b4d 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-08 06:27:38 +01:00
Benjamin Otte
5b12a0fe1b listview: Add selection properties to ListItem
This just brings the infrastructure into place, we're not using the
properties yet.
2019-12-08 06:27:38 +01:00
Benjamin Otte
eaefce91b2 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-08 06:27:38 +01:00
Benjamin Otte
382f543539 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-08 06:27:38 +01:00
Benjamin Otte
3c5f040e06 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-08 06:27:38 +01:00
Benjamin Otte
d58ba49d28 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-08 06:27:38 +01:00
Benjamin Otte
9435b7135d testlistview: Show the row number
Always show the current row. This is mostly useful for debugging, not
for beauty.
2019-12-08 06:27:38 +01:00
Benjamin Otte
e802551369 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-08 06:27:38 +01:00
Benjamin Otte
522c1f2883 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-08 06:27:38 +01:00
Benjamin Otte
11de7bf1a0 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-08 06:27:38 +01:00
Benjamin Otte
d01138c4d5 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-08 06:27:38 +01:00
Benjamin Otte
637ba7afd2 tests: Make animating listview do random resorts 2019-12-08 06:27:38 +01:00
Benjamin Otte
715e597107 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-08 06:27:38 +01:00
Benjamin Otte
9dc9092bac 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-08 06:27:38 +01:00
Benjamin Otte
9ee0283ffa listview: Add GtkListItem
GtkListItem is a generic row widget that is supposed to replace
GtkListBoxRow and GtkFlowBoxChild.
2019-12-08 06:27:38 +01:00
Benjamin Otte
9672aa089a 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-08 06:27:38 +01:00
Benjamin Otte
a6dcfe7b58 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-08 06:27:38 +01:00
Benjamin Otte
545398e819 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-08 06:27:38 +01:00
Benjamin Otte
ccb13a4c92 listview: Implement GtkScrollable
Scrolling in a very basic form is also supported
2019-12-08 06:27:37 +01:00
Benjamin Otte
6e756d9ad0 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-08 06:27:37 +01:00
Benjamin Otte
34709bc815 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-08 06:27:37 +01:00
Benjamin Otte
054299d45b gtk: Add a GtkListView skeleton 2019-12-08 06:27:37 +01:00
Benjamin Otte
f4ad74de9d 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-08 06:27:37 +01:00
Benjamin Otte
b20105b7bc 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-08 06:27:37 +01:00
Benjamin Otte
6600776865 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-08 06:27:37 +01:00
Benjamin Otte
3f23255e0f builder: Make <lookup> type optional
If no type is set, use the type of the expression.
2019-12-08 06:27:37 +01:00
Benjamin Otte
615a0ccae1 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-08 06:27:37 +01:00
Matthias Clasen
6a098e451e More expression tests
Test type mismatches, and the this pointer
during evaluation.
2019-12-08 06:27:37 +01:00
Benjamin Otte
a94d4648c8 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-08 06:27:37 +01:00
Benjamin Otte
c3d67d3271 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-08 06:27:37 +01:00
Benjamin Otte
b9b4e3ebe4 testsuite: Add expression tests 2019-12-08 06:27:37 +01:00
Benjamin Otte
adab2ba0de expression: Add the ability to watch an expression 2019-12-08 06:27:37 +01:00
Benjamin Otte
e6b82215d2 builder: Add support for parsing expressions 2019-12-08 06:27:37 +01:00
Benjamin Otte
02619e8a47 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-08 06:27:37 +01:00
Benjamin Otte
0956255b50 expression: Make property expression allow subexpressions 2019-12-08 06:27:37 +01:00
Benjamin Otte
4567c425ae expression: Add GtkObjectExpression
Weak refs break cycles...
2019-12-08 06:27:37 +01:00
Benjamin Otte
9371102bf9 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-08 06:27:37 +01:00
Benjamin Otte
dbaec8756d filter: Add GtkAnyFilter 2019-12-08 06:27:37 +01:00
Benjamin Otte
d3e75bcb3b filterlistmodel: Rewrite to use GtkFilter 2019-12-08 06:27:37 +01:00
Benjamin Otte
614a748d65 tests: Remove testtreemodel test
testlistview does everything this test does.
2019-12-08 06:27:37 +01:00
Benjamin Otte
1fd1f71abf filter: Add a custom filter 2019-12-08 06:27:37 +01:00
Benjamin Otte
8bf8bdb8ef Add GtkFilter 2019-12-08 06:27:37 +01:00
Benjamin Otte
94cb76788d 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-08 06:27:37 +01:00
Benjamin Otte
f16a9a5f5c 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-08 06:27:37 +01:00
Benjamin Otte
dccef45600 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-08 06:27:37 +01:00
Benjamin Otte
2baa8b750c 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-08 06:27:37 +01:00
Benjamin Otte
1420deb167 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-08 06:27:37 +01:00
Benjamin Otte
e3e8d72e72 a11y: We can peek here
Avoids instantiating a11y objects when we don't need to.
2019-12-08 06:27:37 +01:00
Benjamin Otte
2c48c1c9d9 treeview: Don't create a cyclic reference
TreeRowReference refs the proxy object, so don't use proxies.
2019-12-08 06:27:37 +01:00
Benjamin Otte
92a1683675 label: Compute label baselines correctly
When we were switching smallest and widest, we were not switching the
baselines.
2019-12-08 05:33:42 +01:00
2571 changed files with 280185 additions and 303230 deletions

View File

@@ -1,11 +0,0 @@
# See https://wiki.apertis.org/Guidelines/Coding_conventions#Code_formatting
BasedOnStyle: GNU
AlwaysBreakAfterDefinitionReturnType: All
BreakBeforeBinaryOperators: None
BinPackParameters: false
SpaceAfterCStyleCast: true
# Our column limit is actually 80, but setting that results in clang-format
# making a lot of dubious hanging-indent choices; disable it and assume the
# developer will line wrap appropriately. clang-format will still check
# existing hanging indents.
ColumnLimit: 0

View File

@@ -1,9 +1,7 @@
stages:
- build
- analysis
- docs
- flatpak
- deploy
# - deploy
.cache-paths: &cache-paths
paths:
@@ -14,111 +12,53 @@ stages:
- subprojects/libepoxy/
- subprojects/pango/
# Common variables
variables:
COMMON_MESON_FLAGS: "--fatal-meson-warnings --werror"
BACKEND_FLAGS: "-Dx11-backend=true -Dwayland-backend=true -Dbroadway-backend=true -Dvulkan=yes"
FEATURE_FLAGS: "-Dcloudproviders=true"
MESON_TEST_TIMEOUT_MULTIPLIER: 3
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v20"
FLATPAK_IMAGE: "registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master"
DOCS_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora-docs:v19"
.only-default:
only:
- branches
except:
- tags
style-check-diff:
extends: .only-default
image: $FEDORA_IMAGE
stage: .pre
allow_failure: true
fedora-x86_64: &fedora-x86_64-defaults
image: registry.gitlab.gnome.org/gnome/gtk/master:v7
stage: build
script:
- .gitlab-ci/run-style-check-diff.sh
.build-fedora-default:
image: $FEDORA_IMAGE
- bash -x ./.gitlab-ci/test-docker.sh
artifacts:
when: always
reports:
junit:
- "${CI_PROJECT_DIR}/_build/report-x11.xml"
- "${CI_PROJECT_DIR}/_build/report-wayland.xml"
- "${CI_PROJECT_DIR}/_build/report-broadway.xml"
- "${CI_PROJECT_DIR}/_build/report.xml"
name: "gtk-${CI_COMMIT_REF_NAME}"
paths:
- "${CI_PROJECT_DIR}/_build/meson-logs"
- "${CI_PROJECT_DIR}/_build/report*.xml"
- "${CI_PROJECT_DIR}/_build/report*.html"
- "${CI_PROJECT_DIR}/_build/testsuite/reftests/output/*/*.png"
- "${CI_PROJECT_DIR}/_build/testsuite/gsk/compare/*/*/*.png"
- "${CI_PROJECT_DIR}/_build/testsuite/css/output/*/*.syscap"
- "${CI_PROJECT_DIR}/_build/report.xml"
- "${CI_PROJECT_DIR}/_build/report.html"
- "${CI_PROJECT_DIR}/_build/testsuite/reftests/output/*.png"
- "${CI_PROJECT_DIR}/_build/testsuite/gsk/compare/*/*.png"
cache:
key: "$CI_JOB_NAME"
paths:
- _ccache/
- subprojects/gdk-pixbuf/
- subprojects/glib/
- subprojects/graphene/
- subprojects/libepoxy/
- subprojects/pango/
<<: *cache-paths
fedora-x86_64:
extends: .build-fedora-default
stage: build
fedora-x86_64-staticlibs:
variables:
EXTRA_MESON_FLAGS: "--buildtype=debug --default-library=both"
script:
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} ${BACKEND_FLAGS} ${FEATURE_FLAGS}
-Dprofiler=true
_build
- ninja -C _build
- .gitlab-ci/run-tests.sh _build x11
- .gitlab-ci/run-tests.sh _build wayland
- .gitlab-ci/run-tests.sh _build broadway
EXTRA_MESON_FLAGS: "-Ddefault_library=both"
<<: *fedora-x86_64-defaults
release-build:
extends: .build-fedora-default
stage: build
variables:
EXTRA_MESON_FLAGS: "--buildtype=release"
script:
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} ${BACKEND_FLAGS} ${FEATURE_FLAGS}
_build
- ninja -C _build
- .gitlab-ci/run-tests.sh _build x11
.mingw-defaults:
.mingw-defaults: &mingw-defaults
stage: build
tags:
- win32-ps
- win32
script:
- C:\msys64\usr\bin\pacman --noconfirm -Syyuu
- C:\msys64\usr\bin\bash -lc "bash -x ./.gitlab-ci/test-msys2.sh"
cache:
key: "$CI_JOB_NAME"
paths:
- _ccache/
- subprojects/gdk-pixbuf/
- subprojects/glib/
- subprojects/graphene/
- subprojects/libepoxy/
- subprojects/pango/
msys2-mingw64:
extends: .mingw-defaults
variables:
MSYSTEM: "MINGW64"
CHERE_INVOKING: "yes"
.flatpak-defaults:
image: $FLATPAK_IMAGE
stage: flatpak
allow_failure: true
tags:
- flatpak
cache:
key: "%CI_JOB_NAME%"
<<: *cache-paths
msys2-mingw32:
variables:
MSYSTEM: "MINGW32"
CHERE_INVOKING: "yes"
<<: *mingw-defaults
.flatpak-defaults: &flatpak-defaults
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master
stage: flatpak
artifacts:
paths:
- "${APPID}-dev.flatpak"
@@ -127,97 +67,59 @@ msys2-mingw64:
- bash -x ./.gitlab-ci/flatpak-build.sh "${APPID}"
# Manual jobs, for branches and MRs
.flatpak-manual:
extends: .flatpak-defaults
.flatpak-manual: &flatpak-manual
<<: *flatpak-defaults
when: manual
# Only build Flatpak bundles automatically on master
.flatpak-master:
extends: .flatpak-defaults
.flatpak-master: &flatpak-master
<<: *flatpak-defaults
only:
- master
flatpak-manual:demo:
extends: .flatpak-manual
variables:
APPID: org.gtk.Demo4
<<: *flatpak-manual
flatpak-master:demo:
extends: .flatpak-master
variables:
APPID: org.gtk.Demo4
<<: *flatpak-master
flatpak-manual:widget-factory:
extends: .flatpak-manual
variables:
APPID: org.gtk.WidgetFactory4
<<: *flatpak-manual
flatpak-master:widget-factory:
extends: .flatpak-master
variables:
APPID: org.gtk.WidgetFactory4
<<: *flatpak-master
flatpak-manual:icon-browser:
extends: .flatpak-manual
variables:
APPID: org.gtk.IconBrowser4
<<: *flatpak-manual
flatpak-master:icon-browser:
extends: .flatpak-master
variables:
APPID: org.gtk.IconBrowser4
<<: *flatpak-master
static-scan:
image: $FEDORA_IMAGE
stage: analysis
variables:
EXTRA_MESON_FLAGS: "--buildtype=debug"
script:
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} _scan_build
- ninja -C _scan_build scan-build
artifacts:
paths:
- _scan_build/meson-logs
allow_failure: true
# Run tests with the address sanitizer. We need to turn off introspection,
# since it is incompatible with asan
asan-build:
image: $FEDORA_IMAGE
tags: [ privileged ]
stage: analysis
variables:
script:
- CC=clang meson --buildtype=debugoptimized -Db_sanitize=address -Db_lundef=false -Dintrospection=false _build
- ninja -C _build
- .gitlab-ci/run-tests.sh _build wayland
artifacts:
paths:
- _build/meson-logs
allow_failure: true
reference:
image: $DOCS_IMAGE
stage: docs
variables:
EXTRA_MESON_FLAGS: "--buildtype=release"
script:
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} -Dgtk_doc=true _build
- ninja -C _build gdk4-doc gsk4-doc gtk4-doc
- mkdir -p _reference/
- mv _build/docs/reference/gdk/html/ _reference/gdk/
- mv _build/docs/reference/gsk/html/ _reference/gsk/
- mv _build/docs/reference/gtk/html/ _reference/gtk/
artifacts:
paths:
- _reference
pages:
stage: deploy
script:
- mv _reference/ public/
artifacts:
paths:
- public
only:
- master
#pages:
# image: registry.gitlab.gnome.org/gnome/gtk/master:v6
# stage: deploy
# script:
# - meson -Dgtk_doc=true _build .
# - ninja -C _build
# - ninja -C _build gdk4-doc gsk4-doc gtk4-doc
# - mkdir -p public/
# - mv _build/docs/reference/gtk/html/ public/gtk/
# - mv _build/docs/reference/gdk/html/ public/gdk/
# - mv _build/docs/reference/gsk/html/ public/gsk/
# artifacts:
# paths:
# - public
# only:
# - master

View File

@@ -8,12 +8,9 @@ RUN dnf -y install \
cairo-devel \
cairo-gobject-devel \
ccache \
clang \
clang-analyzer \
colord-devel \
cups-devel \
dbus-daemon \
dbus-x11 \
dejavu-sans-mono-fonts \
desktop-file-utils \
diffutils \
@@ -26,7 +23,6 @@ RUN dnf -y install \
gettext \
git \
glib2-devel \
glib2-static \
glibc-devel \
glibc-headers \
gobject-introspection-devel \
@@ -41,14 +37,12 @@ RUN dnf -y install \
itstool \
json-glib-devel \
lcov \
libasan \
libattr-devel \
libepoxy-devel \
libffi-devel \
libmount-devel \
librsvg2 \
libselinux-devel \
libubsan \
libXcomposite-devel \
libXcursor-devel \
libXcursor-devel \
@@ -59,7 +53,6 @@ RUN dnf -y install \
libxkbcommon-devel \
libXrandr-devel \
libXrender-devel \
libXtst-devel \
libxslt \
mesa-dri-drivers \
mesa-libEGL-devel \
@@ -67,24 +60,27 @@ RUN dnf -y install \
ninja-build \
pango-devel \
pcre-devel \
pcre-static \
python3 \
python3-jinja2 \
python3-pip \
python3-pygments \
python3-wheel \
redhat-rpm-config \
sassc \
sysprof-devel \
systemtap-sdt-devel \
vulkan-devel \
wayland-devel \
wayland-protocols-devel \
weston \
weston-libs \
which \
xorg-x11-server-Xvfb \
&& dnf clean all
RUN pip3 install meson==0.53.1
RUN pip3 install meson==0.50.1
ARG HOST_USER_ID=5555
ENV HOST_USER_ID ${HOST_USER_ID}
RUN useradd -u $HOST_USER_ID -ms /bin/bash user
USER user
WORKDIR /home/user
ENV LANG C.UTF-8

View File

@@ -1,47 +0,0 @@
## GTK CI infrastructure
GTK uses different CI images depending on platform and jobs.
The CI images are Docker containers, generated either using `docker` or
`podman`, and pushed to the GitLab [container registry][registry].
Each Docker image has a tag composed of two parts:
- `${image}`: the base image for a given platform, like "fedora" or
"debian-stable"
- `${number}`: an incremental version number, or `latest`
See the [container registry][registry] for the available images for each
branch, as well as their available versions.
### Checklist for Updating a CI image
- [ ] Update the `${image}.Dockerfile` file with the dependencies
- [ ] Run `./run-docker.sh build --base ${image} --base-version ${number}`
- [ ] Run `./run-docker.sh push --base ${image} --base-version ${number}`
once the Docker image is built; you may need to log in by using
`docker login` or `podman login`
- [ ] Update the `image` keys in the `.gitlab-ci.yml` file with the new
image tag
- [ ] Open a merge request with your changes and let it run
### Checklist for Adding a new CI image
- [ ] Write a new `${image}.Dockerfile` with the instructions to set up
a build environment
- [ ] Add the `pip3 install meson` incantation
- [ ] Run `./run-docker.sh build --base ${image} --base-version ${number}`
- [ ] Run `./run-docker.sh push --base ${image} --base-version ${number}`
- [ ] Add the new job to `.gitlab-ci.yml` referencing the image
- [ ] Open a merge request with your changes and let it run
### Checklist for Adding a new dependency to a CI image
Our images are layered, and the base (called fedora-base) contains
all the rpm payload. Therefore, adding a new dependency is a 2-step
process:
1. [ ] Build and upload fedora-base:$version+1
1. [ ] Build and upload fedora:$version+1 based on fedora-base:version+1
[registry]: https://gitlab.gnome.org/GNOME/gtk/container_registry

View File

@@ -1,133 +0,0 @@
#!/usr/bin/env python3
#
# === clang-format-diff.py - ClangFormat Diff Reformatter ---*- python -*-=== #
#
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
# ===---------------------------------------------------------------------=== #
"""
This script reads input from a unified diff and reformats all the changed
lines. This is useful to reformat all the lines touched by a specific patch.
Example usage for git/svn users:
git diff -U0 --no-color HEAD^ | clang-format-diff.py -p1 -i
svn diff --diff-cmd=diff -x-U0 | clang-format-diff.py -i
"""
from __future__ import absolute_import, division, print_function
import argparse
import difflib
import re
import subprocess
import sys
if sys.version_info.major >= 3:
from io import StringIO
else:
from io import BytesIO as StringIO
def main():
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('-i', action='store_true', default=False,
help='apply edits to files instead of displaying a '
'diff')
parser.add_argument('-p', metavar='NUM', default=0,
help='strip the smallest prefix containing P slashes')
parser.add_argument('-regex', metavar='PATTERN', default=None,
help='custom pattern selecting file paths to reformat '
'(case sensitive, overrides -iregex)')
parser.add_argument('-iregex', metavar='PATTERN',
default=r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hh|hpp|m|mm|inc'
r'|js|ts|proto|protodevel|java|cs)',
help='custom pattern selecting file paths to reformat '
'(case insensitive, overridden by -regex)')
parser.add_argument('-sort-includes', action='store_true', default=False,
help='let clang-format sort include blocks')
parser.add_argument('-v', '--verbose', action='store_true',
help='be more verbose, ineffective without -i')
parser.add_argument('-style',
help='formatting style to apply (LLVM, Google, '
'Chromium, Mozilla, WebKit)')
parser.add_argument('-binary', default='clang-format',
help='location of binary to use for clang-format')
args = parser.parse_args()
# Extract changed lines for each file.
filename = None
lines_by_file = {}
for line in sys.stdin:
match = re.search(r'^\+\+\+\ (.*?/){%s}(\S*)' % args.p, line)
if match:
filename = match.group(2)
if filename is None:
continue
if args.regex is not None:
if not re.match('^%s$' % args.regex, filename):
continue
else:
if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE):
continue
match = re.search(r'^@@.*\+(\d+)(,(\d+))?', line)
if match:
start_line = int(match.group(1))
line_count = 1
if match.group(3):
line_count = int(match.group(3))
if line_count == 0:
continue
end_line = start_line + line_count - 1
lines_by_file.setdefault(filename, []).extend(
['-lines', str(start_line) + ':' + str(end_line)])
# Reformat files containing changes in place.
# We need to count amount of bytes generated in the output of
# clang-format-diff. If clang-format-diff doesn't generate any bytes it
# means there is nothing to format.
format_line_counter = 0
for filename, lines in lines_by_file.items():
if args.i and args.verbose:
print('Formatting {}'.format(filename))
command = [args.binary, filename]
if args.i:
command.append('-i')
if args.sort_includes:
command.append('-sort-includes')
command.extend(lines)
if args.style:
command.extend(['-style', args.style])
p = subprocess.Popen(command,
stdout=subprocess.PIPE,
stderr=None,
stdin=subprocess.PIPE,
universal_newlines=True)
stdout, _ = p.communicate()
if p.returncode != 0:
sys.exit(p.returncode)
if not args.i:
with open(filename) as f:
code = f.readlines()
formatted_code = StringIO(stdout).readlines()
diff = difflib.unified_diff(code, formatted_code,
filename, filename,
'(before formatting)',
'(after formatting)')
diff_string = ''.join(diff)
if diff_string:
format_line_counter += sys.stdout.write(diff_string)
if format_line_counter > 0:
sys.exit(1)
if __name__ == '__main__':
main()

View File

@@ -1,12 +0,0 @@
FROM registry.gitlab.gnome.org/gnome/gtk/fedora-base:v19
RUN dnf -y install pandoc
ARG HOST_USER_ID=5555
ENV HOST_USER_ID ${HOST_USER_ID}
RUN useradd -u $HOST_USER_ID -ms /bin/bash user
USER user
WORKDIR /home/user
ENV LANG C.UTF-8

View File

@@ -1,10 +0,0 @@
FROM registry.gitlab.gnome.org/gnome/gtk/fedora-base:v20
ARG HOST_USER_ID=5555
ENV HOST_USER_ID ${HOST_USER_ID}
RUN useradd -u $HOST_USER_ID -ms /bin/bash user
USER user
WORKDIR /home/user
ENV LANG C.UTF-8

View File

@@ -4,19 +4,20 @@ set -e
appid=$1
builddir=flatpak_app
builddir=app
repodir=repo
flatpak-builder \
--user --disable-rofiles-fuse \
--stop-at=gtk \
${builddir} \
build-aux/flatpak/${appid}.json
flatpak build ${builddir} meson \
--prefix=/app \
--libdir=/app/lib \
--buildtype=release \
flatpak-builder \
--run ${builddir} build-aux/flatpak/${appid}.json \
meson \
--prefix /app \
--libdir /app/lib \
--buildtype debug \
-Dx11-backend=true \
-Dwayland-backend=true \
-Dprint-backends=file \
@@ -24,12 +25,13 @@ flatpak build ${builddir} meson \
-Dbuild-examples=false \
-Dintrospection=false \
-Ddemos=true \
_flatpak_build
flatpak build ${builddir} ninja -C _flatpak_build install
_build .
flatpak-builder \
--run ${builddir} build-aux/flatpak/${appid}.json \
ninja -C _build install
flatpak-builder \
--user --disable-rofiles-fuse \
--finish-only \
--repo=${repodir} \
${builddir} \
@@ -38,5 +40,5 @@ flatpak-builder \
flatpak build-bundle \
${repodir} \
${appid}-dev.flatpak \
--runtime-repo=https://nightly.gnome.org/gnome-nightly.flatpakrepo \
--runtime-repo=https://flathub.org/repo/flathub.flatpakrepo \
${appid}

View File

@@ -138,26 +138,22 @@ ul.images li {
</head>
<body>
<header>
<h1>{{ report.project_name }}/{{ report.backend }}/{{ report.branch_name }} :: Test Reports</h1>
<h1>{{ report.project_name }} :: Test Reports</h1>
<div class="report-meta">
<p><strong>Branch:</strong> {{ report.branch_name }}</p>
<p><strong>Date:</strong> <time datetime="{{ report.date.isoformat() }}">{{ report.locale_date }}</time></p>
{% if report.job_id %}<p><strong>Job ID:</strong> {{ report.job_id }}</p>{% endif %}
</div>
</header>
<article>
<section>
<div class="report-meta">
<p><strong>Backend:</strong> {{ report.backend }}</p>
<p><strong>Branch:</strong> {{ report.branch_name }}</p>
<p><strong>Date:</strong> <time datetime="{{ report.date.isoformat() }}">{{ report.locale_date }}</time></p>
{% if report.job_id %}<p><strong>Job ID:</strong> {{ report.job_id }}</p>{% endif %}
</div>
</section>
<section>
<div class="summary">
<h3><a name="summary">Summary</a></h3>
<ul>
<li><strong>Total units:</strong> {{ report.total_units }}</li>
<li><strong>Failed:</strong> {{ report.total_failures }}</li>
<li><strong>Passed:</strong> {{ report.total_successes }}</li>
<li><strong>Passed:</strong> <a href="#passed">{{ report.total_successes }}</a></li>
<li><strong>Failed:</strong> <a href="#failures">{{ report.total_failures }}</a></li>
</ul>
</div>
</section>
@@ -168,47 +164,30 @@ ul.images li {
<h3><a name="results">Suite: {{ suite_result.suite_name }}</a></h3>
<ul>
<li><strong>Units:</strong> {{ suite_result.n_units }}</li>
<li><strong>Failed:</strong> <a href="#{{ suite_result.suite_name }}-failed">{{ suite_result.n_failures }}</a></li>
<li><strong>Passed:</strong> <a href="#{{ suite_result.suite_name }}-passed">{{ suite_result.n_successes }}</a></li>
<li><strong>Passed:</strong> {{ suite_result.n_successes }}</li>
<li><strong>Failed:</strong> {{ suite_result.n_failures }}</li>
</ul>
<div class="failures">
<h4><a name="{{ suite_result.suite_name }}-failed">Failures</a></h4>
<ul class="failed">
{% for failure in suite_result.failures if failure.result in [ 'ERROR', 'FAIL', 'UNEXPECTEDPASS' ] %}
<li><a name="{{ failure.name }}">{{ failure.name }}</a> - result: <span class="result fail">{{ failure.result }}</span><br/>
{% if failure.stdout %}
Output: <pre>{{ failure.stdout }}</pre>
{% endif %}
{% if failure.image_data is defined %}
<ul class="images">
<li><img alt="ref" src="{{ failure.image_data.ref }}" /></li>
<li><img alt="out" src="{{ failure.image_data.out }}" /></li>
<li><img alt="diff" src="{{ failure.image_data.diff }}" /></li>
</ul>
{% endif %}
</li>
{% else %}
<li>None</li>
{% endfor %}
</ul>
<h4><a name="{{ suite_result.suite_name }}-timed-out">Timed out</a></h4>
<ul class="failed">
{% for failure in suite_result.failures if failure.result == 'TIMEOUT' %}
<li><a name="{{ failure.name }}">{{ failure.name }}</a> - result: <span class="result fail">{{ failure.result }}</span><br/>
{% if failure.stdout %}
Output: <pre>{{ failure.stdout }}</pre>
{% endif %}
</li>
{% else %}
<li>None</li>
{% endfor %}
</ul>
</div>
<div class="successes">
<h4><a name="{{ suite_result.suite_name }}-expected-fail">Expected failures</a></h4>
<h4><a name="passed">Passed</a></h4>
<ul class="passed">
{% for success in suite_result.successes if success.result == 'OK' %}
<li>{{ success.name }} - result: <span class="result pass">{{ success.result }}</li>
{% else %}
<li>None</li>
{% endfor %}
</ul>
<h4><a name="skipped">Skipped</a></h4>
<ul>
{% for success in suite_result.successes if success.result == 'SKIP' %}
<li>{{ success.name }} - result: <span class="result skip">{{ success.result }}</li>
{% else %}
<li>None</li>
{% endfor %}
</ul>
<h4><a name="expected-fail">Expected failures</a></h4>
<ul>
{% for success in suite_result.successes if success.result == 'EXPECTEDFAIL' %}
<li><a name="{{ success.name }}">{{ success.name }}</a> - result: <span class="result xfail">{{ success.result }}</span><br/>
@@ -227,20 +206,37 @@ ul.images li {
<li>None</li>
{% endfor %}
</ul>
</div>
<h4><a name="{{ suite_result.suite_name }}-skipped">Skipped</a></h4>
<ul>
{% for success in suite_result.successes if success.result == 'SKIP' %}
<li>{{ success.name }} - result: <span class="result skip">{{ success.result }}</li>
<div class="failures">
<h4><a name="failed">Failed</a></h4>
<ul class="failed">
{% for failure in suite_result.failures if failure.result == 'FAIL' %}
<li><a name="{{ failure.name }}">{{ failure.name }}</a> - result: <span class="result fail">{{ failure.result }}</span><br/>
{% if failure.stdout %}
Output: <pre>{{ failure.stdout }}</pre>
{% endif %}
{% if failure.image_data is defined %}
<ul class="images">
<li><img alt="ref" src="{{ failure.image_data.ref }}" /></li>
<li><img alt="out" src="{{ failure.image_data.out }}" /></li>
<li><img alt="diff" src="{{ failure.image_data.diff }}" /></li>
</ul>
{% endif %}
</li>
{% else %}
<li>None</li>
{% endfor %}
</ul>
<h4><a name="{{ suite_result.suite_name }}-passed">Passed</a></h4>
<ul class="passed">
{% for success in suite_result.successes if success.result == 'OK' %}
<li>{{ success.name }} - result: <span class="result pass">{{ success.result }}</li>
<h4><a name="timed-out">Timed out</a></h4>
<ul class="failed">
{% for failure in suite_result.failures if failure.result == 'TIMEOUT' %}
<li><a name="{{ failure.name }}">{{ failure.name }}</a> - result: <span class="result fail">{{ failure.result }}</span><br/>
{% if failure.stdout %}
Output: <pre>{{ failure.stdout }}</pre>
{% endif %}
</li>
{% else %}
<li>None</li>
{% endfor %}
@@ -260,9 +256,6 @@ aparser = argparse.ArgumentParser(description='Turns a Meson test log into an HT
aparser.add_argument('--project-name', metavar='NAME',
help='The project name',
default='Unknown')
aparser.add_argument('--backend', metavar='NAME',
help='The used backend',
default='unknown')
aparser.add_argument('--job-id', metavar='ID',
help='The job ID for the report',
default=None)
@@ -323,7 +316,6 @@ report = {}
report['date'] = datetime.datetime.utcnow()
report['locale_date'] = report['date'].strftime("%c")
report['project_name'] = args.project_name
report['backend'] = args.backend
report['job_id'] = args.job_id
report['branch_name'] = args.branch
report['total_successes'] = 0
@@ -336,7 +328,7 @@ for name, units in suites.items():
print('Processing {} suite {}:'.format(project_name, suite_name))
def if_failed(unit):
if unit['result'] in ['FAIL', 'UNEXPECTEDPASS', 'TIMEOUT', 'ERROR',]:
if unit['result'] in ['FAIL', 'TIMEOUT']:
return True
return False

View File

@@ -19,9 +19,6 @@ aparser = argparse.ArgumentParser(description='Turns a Meson test log into a JUn
aparser.add_argument('--project-name', metavar='NAME',
help='The project name',
default='unknown')
aparser.add_argument('--backend', metavar='NAME',
help='The used backend',
default='unknown')
aparser.add_argument('--job-id', metavar='ID',
help='The job ID for the report',
default='Unknown')
@@ -54,7 +51,6 @@ for line in args.infile:
duration = data['duration']
return_code = data['returncode']
result = data['result']
log = data['stdout']
unit = {
@@ -62,7 +58,6 @@ for line in args.infile:
'name': unit_name,
'duration': duration,
'returncode': return_code,
'result': result,
'stdout': log,
}
@@ -73,12 +68,12 @@ for name, units in suites.items():
print('Processing suite {} (units: {})'.format(name, len(units)))
def if_failed(unit):
if unit['result'] in ['ERROR', 'FAIL', 'UNEXPECTEDPASS', 'TIMEOUT']:
if unit['returncode'] != 0:
return True
return False
def if_succeded(unit):
if unit['result'] in ['OK', 'EXPECTEDFAIL', 'SKIP']:
if unit['returncode'] == 0:
return True
return False
@@ -95,18 +90,18 @@ for name, units in suites.items():
for unit in successes:
testcase = ET.SubElement(testsuite, 'testcase')
testcase.set('classname', '{}/{}'.format(args.project_name, unit['suite']))
testcase.set('name', '{}/{}'.format(args.backend, unit['name']))
testcase.set('name', unit['name'])
testcase.set('time', str(unit['duration']))
for unit in failures:
testcase = ET.SubElement(testsuite, 'testcase')
testcase.set('classname', '{}/{}'.format(args.project_name, unit['suite']))
testcase.set('name', '{}/{}'.format(args.backend, unit['name']))
testcase.set('name', unit['name'])
testcase.set('time', str(unit['duration']))
failure = ET.SubElement(testcase, 'failure')
failure.set('classname', '{}/{}'.format(args.project_name, unit['suite']))
testcase.set('name', '{}/{}'.format(args.backend, unit['name']))
failure.set('name', unit['name'])
failure.set('type', 'error')
failure.text = unit['stdout']

View File

@@ -1,135 +1,11 @@
#!/bin/bash
read_arg() {
# $1 = arg name
# $2 = arg value
# $3 = arg parameter
local rematch='^[^=]*=(.*)$'
if [[ $2 =~ $rematch ]]; then
read "$1" <<< "${BASH_REMATCH[1]}"
else
read "$1" <<< "$3"
# There is no way to shift our callers args, so
# return 1 to indicate they should do it instead.
return 1
fi
}
set -e
build=0
run=0
push=0
list=0
print_help=0
no_login=0
TAG="registry.gitlab.gnome.org/gnome/gtk/master:v7"
while (($# > 0)); do
case "${1%%=*}" in
build) build=1;;
run) run=1;;
push) push=1;;
list) list=1;;
help) print_help=1;;
--base|-b) read_arg base "$@" || shift;;
--base-version) read_arg base_version "$@" || shift;;
--no-login) no_login=1;;
*) echo -e "\e[1;31mERROR\e[0m: Unknown option '$1'"; exit 1;;
esac
shift
done
if [ $print_help == 1 ]; then
echo "$0 - Build and run Docker images"
echo ""
echo "Usage: $0 <command> [options] [basename]"
echo ""
echo "Available commands"
echo ""
echo " build --base=<BASENAME> - Build Docker image <BASENAME>.Dockerfile"
echo " run --base=<BASENAME> - Run Docker image <BASENAME>"
echo " push --base=<BASENAME> - Push Docker image <BASENAME> to the registry"
echo " list - List available images"
echo " help - This help message"
echo ""
exit 0
fi
cd "$(dirname "$0")"
if [ $list == 1 ]; then
echo "Available Docker images:"
for f in *.Dockerfile; do
filename=$( basename -- "$f" )
basename="${filename%.*}"
echo -e " \e[1;39m$basename\e[0m"
done
exit 0
fi
# All commands after this require --base to be set
if [ -z $base ]; then
echo "Usage: $0 <command>"
exit 1
fi
if [ ! -f "$base.Dockerfile" ]; then
echo -e "\e[1;31mERROR\e[0m: Dockerfile for '$base' not found"
exit 1
fi
if [ -z $base_version ]; then
base_version="latest"
elif [ $base_version != "latest" ]; then
base_version="v$base_version"
fi
if [ ! -x "$(command -v docker)" ] || [ docker --help |& grep -q podman ]; then
# Docker is actually implemented by podman, and its OCI output
# is incompatible with some of the dockerd instances on GitLab
# CI runners.
echo "Using: Podman"
format="--format docker"
CMD="podman"
else
echo "Using: Docker"
format=""
CMD="sudo docker"
fi
REGISTRY="registry.gitlab.gnome.org"
TAG="${REGISTRY}/gnome/gtk/${base}:${base_version}"
if [ $build == 1 ]; then
echo -e "\e[1;32mBUILDING\e[0m: ${base} as ${TAG}"
${CMD} build \
${format} \
--build-arg HOST_USER_ID="$UID" \
--tag "${TAG}" \
--file "${base}.Dockerfile" .
exit $?
fi
if [ $push == 1 ]; then
echo -e "\e[1;32mPUSHING\e[0m: ${base} as ${TAG}"
if [ $no_login == 0 ]; then
${CMD} login ${REGISTRY}
fi
${CMD} push ${TAG}
exit $?
fi
if [ $run == 1 ]; then
echo -e "\e[1;32mRUNNING\e[0m: ${base} as ${TAG}"
${CMD} run \
--rm \
--volume "$(pwd)/..:/home/user/app" \
--workdir "/home/user/app" \
--tty \
--interactive "${TAG}" \
bash
exit $?
fi
sudo docker build --build-arg HOST_USER_ID="$UID" --tag "${TAG}" \
--file "Dockerfile" .
sudo docker run --rm --security-opt label=disable \
--volume "$(pwd)/..:/home/user/app" --workdir "/home/user/app" \
--tty --interactive "${TAG}" bash

View File

@@ -1,44 +0,0 @@
#!/bin/bash
set -e
# We need to add a new remote for the upstream master, since this script could
# be running in a personal fork of the repository which has out of date branches.
if [ "${CI_PROJECT_NAMESPACE}" != "GNOME" ]; then
echo "Retrieving the current upstream repository from ${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}..."
git remote add upstream https://gitlab.gnome.org/GNOME/gtk.git
git fetch upstream
ORIGIN="upstream"
else
echo "Reusing the existing repository on ${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}"
ORIGIN="origin"
fi
# Work out the newest common ancestor between the detached HEAD that this CI job
# has checked out, and the upstream target branch (which will typically be
# `upstream/master` or `upstream/gtk-3-24`).
#
# `${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}` is only defined if were running in
# a merge request pipeline; fall back to `${CI_DEFAULT_BRANCH}` otherwise.
newest_common_ancestor_sha=$(diff --old-line-format='' --new-line-format='' <(git rev-list --first-parent "${ORIGIN}/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME:-${CI_DEFAULT_BRANCH}}") <(git rev-list --first-parent HEAD) | head -1)
git diff -U0 --no-color "${newest_common_ancestor_sha}" | .gitlab-ci/clang-format-diff.py -binary "clang-format" -p1
exit_status=$?
# The style check is not infallible. The clang-format configuration cannot
# perfectly describe GTKs coding style: in particular, it cannot align
# function arguments. The documented coding style for GTK takes priority over
# clang-format suggestions. Hopefully we can eventually improve clang-format to
# be configurable enough for our coding style. Thats why this CI check is OK
# to fail: the idea is that people can look through the output and ignore it if
# its wrong. (That situation can also happen if someone touches pre-existing
# badly formatted code and it doesnt make sense to tidy up the wider coding
# style with the changes theyre making.)
echo ""
echo "Note that clang-format output is advisory and cannot always match the"
echo "GTK coding style, documented at:"
echo " https://gitlab.gnome.org/GNOME/gtk/blob/master/docs/CODING-STYLE"
echo "Warnings from this tool can be ignored in favour of the documented "
echo "coding style, or in favour of matching the style of existing"
echo "surrounding code."
exit ${exit_status}

View File

@@ -1,85 +0,0 @@
#!/bin/bash
set +x
set +e
srcdir=$( pwd )
builddir=$1
backend=$2
# Ignore memory leaks lower in dependencies
export LSAN_OPTIONS=suppressions=$srcdir/lsan.supp
case "${backend}" in
x11)
xvfb-run -a -s "-screen 0 1024x768x24" \
meson test -C ${builddir} \
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
--print-errorlogs \
--setup=${backend} \
--suite=gtk \
--no-suite=gtk:a11y \
--no-suite=gsk-compare-broadway
# Store the exit code for the CI run, but always
# generate the reports
exit_code=$?
;;
wayland)
export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
weston --backend=headless-backend.so --socket=wayland-5 --idle-time=0 &
compositor=$!
export WAYLAND_DISPLAY=wayland-5
meson test -C ${builddir} \
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
--print-errorlogs \
--setup=${backend} \
--suite=gtk \
--no-suite=gtk:a11y \
--no-suite=gsk-compare-broadway
exit_code=$?
kill ${compositor}
;;
broadway)
export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
${builddir}/gdk/broadway/gtk4-broadwayd :5 &
server=$!
export BROADWAY_DISPLAY=:5
meson test -C ${builddir} \
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
--print-errorlogs \
--setup=${backend} \
--suite=gtk \
--no-suite=gtk:a11y \
--no-suite=gsk-compare-opengl
# don't let Broadway failures fail the run, for now
exit_code=0
kill ${server}
;;
esac
cd ${builddir}
$srcdir/.gitlab-ci/meson-junit-report.py \
--project-name=gtk \
--backend=${backend} \
--job-id="${CI_JOB_NAME}" \
--output=report-${backend}.xml \
meson-logs/testlog-${backend}.json
$srcdir/.gitlab-ci/meson-html-report.py \
--project-name=gtk \
--backend=${backend} \
--job-id="${CI_JOB_NAME}" \
--reftest-output-dir="testsuite/reftests/output/${backend}" \
--output=report-${backend}.html \
meson-logs/testlog-${backend}.json
exit $exit_code

View File

@@ -16,7 +16,6 @@ meson \
-Dwayland-backend=true \
-Dbroadway-backend=true \
-Dvulkan=yes \
-Dprofiler=true \
--werror \
${EXTRA_MESON_FLAGS:-} \
_build $srcdir

View File

@@ -33,13 +33,6 @@ pacman --noconfirm -S --needed \
mingw-w64-$MSYS2_ARCH-gst-plugins-bad \
mingw-w64-$MSYS2_ARCH-shared-mime-info
# https://gitlab.gnome.org/GNOME/gtk/issues/2243
wget "https://gitlab.gnome.org/creiter/gitlab-ci-win32-runner-v2/raw/master/pango/mingw-w64-$MSYS2_ARCH-pango-git-1.44.7.90.ge48ae523-1-any.pkg.tar.zst"
pacman --noconfirm -U "mingw-w64-$MSYS2_ARCH-pango-git-1.44.7.90.ge48ae523-1-any.pkg.tar.zst"
# https://github.com/msys2/MINGW-packages/pull/6465
pacman --noconfirm -S --needed mingw-w64-$MSYS2_ARCH-brotli
mkdir -p _ccache
export CCACHE_BASEDIR="$(pwd)"
export CCACHE_DIR="${CCACHE_BASEDIR}/_ccache"
@@ -48,14 +41,11 @@ export CCACHE_DIR="${CCACHE_BASEDIR}/_ccache"
ccache --zero-stats
ccache --show-stats
export CCACHE_DISABLE=true
# FIXME: introspection disabled for now because of
# https://gitlab.gnome.org/GNOME/gobject-introspection/-/issues/340
meson \
-Dx11-backend=false \
-Dwayland-backend=false \
-Dwin32-backend=true \
-Dvulkan=no \
-Dintrospection=false \
--werror \
_build
unset CCACHE_DISABLE

View File

@@ -22,7 +22,12 @@ Please, do not use the issue tracker for support questions. If you have
questions on how to use GTK effectively, you can use:
- the `#gtk` IRC channel on irc.gnome.org
- the [gtk tag on the GNOME Discourse instance](https://discourse.gnome.org/tag/gtk)
- the [gtk](https://mail.gnome.org/mailman/listinfo/gtk-list) mailing list,
for general questions on GTK
- the [gtk-app-devel](https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list)
mailing list, for questions on application development with GTK
- the [gtk-devel](https://mail.gnome.org/mailman/listinfo/gtk-devel-list)
mailing list, for questions on developing GTK itself
You can also look at the GTK tag on [Stack
Overflow](https://stackoverflow.com/questions/tagged/gtk).
@@ -169,7 +174,7 @@ maintainers review your contribution.
Each contribution is reviewed by the core developers of the GTK project.
The [CODEOWNERS](./docs/CODEOWNERS) document contains the list of core
The [CODE-OWNERS](./docs/CODE-OWNERS) document contains the list of core
contributors to GTK and the areas for which they are responsible; you
should ensure to receive their review and signoff on your changes.

500
NEWS
View File

@@ -1,501 +1,3 @@
Overview of Changes in GTK 3.99.0
=================================
* Add GtkEditableLabel
* Add GtkBookmarkList, a list model for bookmarks
* Add GtkStringList, a list model for strings
* Add GtkBitset, and use it for representing selections
* GtkTreeView:
- Make cell editing work again
* GtkSpinButton:
- Make autosizing work again
* Printing:
- Use GtkDropDown in the print dialog
* GtkApplication
- Support opening files on OS X
* GtkFileChooser:
- Fix libcloudproviders support
- Turn GtkFileFilter into a GtkFilter
- Simplify the api
* GtkGridView, GtkListView:
- Improve scrolling behavior
- Autoscroll and autoexpand during DND
* GtkScrolledWindow:
- Make autoscrolling work again
* GtkFilterListModel:
- Add incremental filtering
* GtkEntry:
- Make entry completion work again
- Drop action support from GtkEntryCompletion
* Inspector:
- Improve list model support
- Add direct navigation between objects
* GDK:
- Compress scroll events
- Keep a scroll history
- Clean up GdkDevice api
- Improve frame clock accuracy
* GSK:
- Use GL_ARB_framebuffer_object
* gtk-demo:
- Add incremental refill to the color grid
- Improve performance of the color grid
- Add an incrementally filtering word list
- Improve the sidebar
* Install print-editor as another demo
* Translation updates
Basque
Catalan
Chinese
Japanese
Kazakh
Lithuanian
Polish
Romanian
Spanish
Turkish
Ukrainian
Overview of Changes in GTK 3.98.5
=================================
* Introduce new list widgets and supporting infrastructure.
The main APIs are:
- GtkListView
- GtkGridView
- GtkColumnView and GtkColumnViewColumn
- GtkDropDown
- GtkListItemFactory and implementations
- GtkExpression
- GtkFilter and subclasses, and GtkFilterListModel
- GtkSorter and subclasses, and GtkSortListModel
- GtkSelectionModel and subclasses
- GtkTreeListModel, GtkTreeExpander and GtkTreeListRowSorter
* GtkFileChooser:
- Add a tracker3-based search engine implementation
- Rate-limit updates from the trash monitor
* GtkWindow:
- Redo the css node setup. There is now a single 'window' node
- Fix rounded corners on tiled windows
* GtkApplication:
- Drop app menu support. Menubar support is still there
* GtkFixed:
- Change coordinate APIs to take doubles
* GtkOverlay:
- Make GtkOverlayLayout public
* GtkTooltips:
- Fix line wrapping of tooltips
* Shortcuts:
- Fix mnemonic cycling
- Fix using '0' as a mnemonic
* Menus:
- Differentiate keypad keys in accelerators
* GtkIMContext:
- Add gtk_im_context_filter_key to allow event reinjection
* Themes:
- Adwaita: Limit the scope of backdrop
* Accessibility:
- Clean up and reorganize the code to prepare for the
dropping of ATK
* GDK:
- Drop unused enum and struct definitions from headers
- Make keymap translation API public again. Still needed
- Frameclock: Always use compositor refresh rate info
- Frameclock: Use quadratic correction for frame time jitter
- Frameclock: Ensure monotonicity
- Frameclock: Track resason for paint
- X11: Improve sync when the Nvidia driver is used
* GSK:
- GL renderer: Fix blurred outset shadows
- GL renderer: handle nested transform nodes properly
- GL renderer: Optimize clip handling
* gtk-demo:
- Improve the Drag-and-Drop demo with proper drag icons
- Don't show the main window if --run is given
- Add demos for list widgets and GtkDropDrown
* Documentation:
- Convert freestanding sections to markdown
- Drop the glossary
- Expand and improve the migration guide
* Build:
- We require pandoc now, for building the documentation
- Require Pango 1.45
* Translation updates:
Polish
Romanian
Slovenian
Turkish
Ukrainian
Overview of Changes in GTK 3.98.4
=================================
* Themes
- Refine menu styling
- Tweak visible focus behavior
- HighConstrast: Add public colors
- HighContrast: Fix scale borders
* CSS:
- Drop the nonstandard -gtk-icon-theme property
- Add a system_setting_changed vfunc to propagate global changes
* Untangle titlebars from windows:
- Add a GtkWindowControls widget
- Add a GtkWindowHandle widget
- Add actions for window menu items
- Remove app menu fallback from GtkHeaderBar
- Remove title and subtitle properties from GtkHeaderBar,
rename custom-title to title-widget
* GtkWidget
- Add a focusable property
* GtkPopover:
- Fix (re-)positioning issues
* GtkStack:
- Drop the homogeneous property
- Add a use-underline property to stack pages
* GtkScale:
- Make area around the trough clickable
* GtkScrolledWindow:
- Fix kinetic scrolling
* GtkTreeView:
- Break reference cycles in unroot
* Drop GtkBin and GtkContainer. All existing GtkBin subclasses
have grown a child property with setter and getter. All
existing GtkContainer subclasses have grown widget-specific
remove (and in some cases, add) functions. <child> in ui
files continues to work as before
* Replace gtk_widget_destroy by gtk_window_destroy
* Drop the ::size-allocate signal. Use a GtkWidgetPaintable
if you need to be informed about changes to a widgets
content or size
* Remove gtk_dialog_run
* GDK:
- Wayland: Provide a builtin cursor of last resort
- Change the monitor api to use a GListModel
* GSK:
- Don't include renderer-specific headers automatically
- GL: Fix nested rounded clips
* Introspection:
- Assorted annotation fixes
* Inspector:
- Preview media resources
- Show media backend information
* gtk4-widget-factory:
- Add GtkVideo
- Add text styles
- Add a print dialog
- Add a password entry
- Improve toolbar styling
- Revamp transition effects
* gtk4-demo:
- Replace some demos
* Translation updates:
Chinese (Taiwan)
Esperanto
Japanese
Romanian
Spanish
Ukrainian
Overview of Changes in GTK 3.98.3
=================================
* GtkEntry:
- Support setting attributes in ui files
* GtkScaleButton:
- Don't derive from GtkButton
* GtkAboutDialog:
- Support more common licenses
* GtkEmojiChooser:
- Improve keyboard navigation
* GtkLabel:
- Remove pattern API
* GtkAspectFrame:
- Modernize and simplify
* Chooser buttons:
- Make dialogs modal by default
* Various widgets:
- Replace shadow-type and relief properties by
a simpler has-frame
* CSS:
- Use :focus-visible instead of :focus(visible)
- Add support for :focus-within
* Focus handling
- Fix crossing event generation
- Fix focus handling in various widgets
- Change :can-focus to be recursive
- Fix GtkWindow:is-active setting
* Scrolling
- gtk_container_set_focus_[hv]adjustment has been removed
- gtk_viewport_set_scroll_to_focus has been added
* Accessibility:
- Add a cursor-aspect-ratio setting
- Set focus-related states properly
* Themes:
- Use blue focus outlines more
- Numerous minor improvements
* Wayland:
- Fix .Compose file loading
- Support popup repositioning
- Fix problems with autohide popovers
* GDK:
- Remove GdkKeymap from public API, replaced by
GdkDevice properties
- Add full keyboard translation state to key events
- Simplify modifier support, drop GdkModifierIntent
- Move key event matching to GDK
- Add GdkSurface::enter/leave-monitor signals
- Turn GskEvent into a derivable type, and make
it introspectable
* GSK:
- Turn GskRenderNode into a derivable type, and make
it introspectable
- Fall back to cairo if compiling shaders fails
* Translation updates:
- Japanese
- Lithuanian
- Turkish
Overview of Changes in GTK 3.98.2
=================================
* Introduce GtkShortcutController, and replace key bindings,
mnemonics and accelerators by GtkShortcut
* Derive the HighContrast theme from Adwaita
* GtkMenuButton: Add a use-underline property
* GtkTreeView: Fix cell editing
* Add gdk_toplevel_inhibit_system_shortcuts
* gtk-demo: Fix issues in multiple demos
* Translation updates:
Polish
Overview of Changes in GTK 3.98.1
=================================
* GtkFileChooser:
- Remove filename/uri api
- Drop extra-widget
- Remove overwrite confirmation
- Remove show-hidden property
- Remove local-only property
- Remove GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
- The portal file chooser supports selecting folders
* GtkSpinner:
- Rename active property to spinning
* GtkRevealer:
- Fix size allocation at small scales
* GtkPopover:
- Drop :relative-to, it is always the :parent now
* GtkWindow:
- Drop window-type, it is always a regular toplevel
* GtkWidget:
- Drop expand property
- Drop margin property
- Drop gtk_grab_add, gtk_device_grab_add
* GtkTextView:
- Support overlines in GtkTextTag
- Support visible spaces in GtkTextTag
- Support hyphenation control in GtkTextTag
* Split GtkEventControllerFocus from GtkEventControllerKey
* DND:
- Fix local DND to avoid serialization
- Add new content provider constructors
- Split GtkDropTargetAsync and GtkDropTarget
- Group DND events into event sequences
- Propagate DND events like motion events
- Introduce GtkDropControllerMotion
- Remove GtkSelectionData
* Performance:
- Clean up profiler marks
- Share GL programs between renderers
* GDK:
- Drop gdk_surface_new_temp
- Make GdkEvent an immutable boxed type, not an object
- Remove GdkAtom and property- and selection-related apis
- Introduce GdkPopup and GdkToplevel interfaces
- Implement them in backend-specific surface subtypes
- Rename gdk_surface_input_shape_combine_region to
gdk_surface_set_input_region
- Drop X11-only concepts such as sticky or keep-below
* OS X: Fix OpenGL extension detection
* Broadway: implement scaling
* Translation updates:
Dutch
Japanese
Persian
Overview of Changes in GTK 3.98.0
=================================
While this release gets significantly closer to what we aim for in GTK 4,
there are still a few big items outstanding that we are currently working
on:
- Event controllers for keyboard shortcuts
- Movable popovers
- Row-recycling list and grid views
- Revamped accessibility infrastructure
- Animation API
We will do further 3.98.x snapshots as these land.
*****************
* The DND refactoring has been completed. The GTK API for DND has been turned
into event controllers: GtkDragSource and GtkDropTarget. Support for file
transfers via file transfer portal has been added for both DND and the clipboard.
* Child surfaces have been removed. GDK only supports toplevel and popup surfaces
now. The client-side window implementation has been removed too. On the GTK side,
the GtkNative interface has been introduced for widgets that have their own
surface. This cleanup is not 100% complete yet.
* Global positions and related apis such as gdk_surface_move are no longer available.
* A constraint-based layout manager has been added.
* Many classes have been made explicitly non-subclassable, and the widget hierarchy
has been simplified, by making widgets derive directly from GtkWidget instead of
a container.
* Menu-related changes:
- GtkMenu, GtkMenuBar and related classes have been removed. They are being replaced
by GMenu and popover-based variants. Popover menus can now do traditional, nested
menus, and model buttons show accelerators.
- Context menus are no longer created with ::populate-popup signals, but use menu
models and actions.
- Widget actions can be created in class_init, with gtk_widget_class_install_action.
- GtkToolbar has been removed as well.
* Text-related changed:
- Text cursor blinking has been made smooth.
- GtkTextView is caching rendernodes for the visible text range now, improving the
scrolling performance of text.
- Add a simple undo stack for text edits has been added.
* The native Win32 filechooser backend supports choices.
* GtkTreeView renders tree and grid lines with textures.
* GtkEmojiChooser has been made public.
* GtkGestureMultiPress has been renamed to GtkGestureClick.
* GtkWidget has api to handle style classes: gtk_widget_add_style_class.
This is the first step towards moving away from GtkStyleContext.
* X11-specific changes:
- XI2 is now mandatory
- The xim input method has been removed
* Wayland-specific changes:
- The loading of cursor themes has been improved to load cursors on demand,
and no longer relies on libwayland-cursor.
* The GL renderer is now sharing icon and glyph caches for all surfaces,
and has better support for blurring and shadow rendering.
* Performance-related changes:
- GTK provides profiling information for Sysprof when launched with GTK_TRACE=1.
- Css computation has been optimized
- Css lookups are using a Bloom filter
- Icon loading IO has been moved to a thread
Overview of Changes in GTK+ 3.96.0
==================================
@@ -858,7 +360,7 @@ Overview of Changes in GTK+ 3.92.1, 重庆市
The bulk of the preparation for this release was done during
and after the fantastic GNOME.Asia Summit 2017 in Chongqing, China.
* Drop autotools support. Meson 0.42.1 is now required
* Drop autotools support. Meson 0.42.1 is now required
* Implement most of CSS3 font-variant

View File

@@ -27,9 +27,9 @@ The official developers blog
- https://blog.gtk.org
Discussion forum
Information about mailing lists can be found at
- https://discourse.gnome.org/c/platform/core/
- http://www.gtk.org/mailing-lists.php
Nightly documentation can be found at
- Gtk: https://gnome.pages.gitlab.gnome.org/gtk/gtk/
@@ -140,12 +140,6 @@ In the bug report please include:
* Further information such as stack traces may be useful, but
is not necessary.
Contributing to GTK
-------------------
Please, follow the [contribution guide](./CONTRIBUTING.md) to know how to
start contributing to GTK.
Release notes
-------------
@@ -162,4 +156,4 @@ GTK is released under the terms of the GNU Lesser General Public License,
version 2.1 or, at your option, any later version, as published by the Free
Software Foundation.
Please, see the [`COPYING`](./COPYING) file for further information.
Please, see the `COPYING` file for further information.

View File

@@ -54,36 +54,6 @@
}
]
},
{
"name" : "libsass",
"buildsystem" : "meson",
"builddir" : true,
"config-opts": [
"--libdir=/app/lib"
],
"sources" : [
{
"type" : "git",
"url" : "https://github.com/lazka/libsass.git",
"branch" : "meson"
}
]
},
{
"name" : "sassc",
"buildsystem" : "meson",
"builddir" : true,
"config-opts": [
"--libdir=/app/lib"
],
"sources" : [
{
"type" : "git",
"url" : "https://github.com/lazka/sassc.git",
"branch" : "meson"
}
]
},
{
"name": "gtk",
"buildsystem": "meson",

View File

@@ -54,36 +54,6 @@
}
]
},
{
"name" : "libsass",
"buildsystem" : "meson",
"builddir" : true,
"config-opts": [
"--libdir=/app/lib"
],
"sources" : [
{
"type" : "git",
"url" : "https://github.com/lazka/libsass.git",
"branch" : "meson"
}
]
},
{
"name" : "sassc",
"buildsystem" : "meson",
"builddir" : true,
"config-opts": [
"--libdir=/app/lib"
],
"sources" : [
{
"type" : "git",
"url" : "https://github.com/lazka/sassc.git",
"branch" : "meson"
}
]
},
{
"name": "gtk",
"buildsystem": "meson",

View File

@@ -1,38 +1,29 @@
{
"app-id" : "org.gtk.WidgetFactory4",
"runtime" : "org.gnome.Platform",
"runtime-version" : "master",
"sdk" : "org.gnome.Sdk",
"command" : "gtk4-widget-factory",
"tags" : [
"devel",
"development",
"nightly"
],
"desktop-file-name-prefix" : "(Development) ",
"finish-args" : [
"app-id": "org.gtk.WidgetFactory4",
"runtime": "org.gnome.Platform",
"runtime-version": "master",
"sdk": "org.gnome.Sdk",
"command": "gtk4-widget-factory",
"tags": ["devel", "development", "nightly"],
"desktop-file-name-prefix": "(Development) ",
"finish-args": [
"--device=dri",
"--share=ipc",
"--socket=fallback-x11",
"--socket=wayland",
"--talk-name=org.gtk.vfs",
"--talk-name=org.gtk.vfs.*"
"--talk-name=org.gtk.vfs", "--talk-name=org.gtk.vfs.*"
],
"cleanup" : [
"cleanup": [
"/include",
"/lib/pkgconfig",
"/share/pkgconfig",
"/lib/pkgconfig", "/share/pkgconfig",
"/share/aclocal",
"/man",
"/share/man",
"/share/gtk-doc",
"*.la",
".a",
"/man", "/share/man", "/share/gtk-doc",
"*.la", ".a",
"/lib/girepository-1.0",
"/share/gir-1.0",
"/share/doc"
],
"modules" : [
"modules": [
{
"name" : "wayland",
"buildsystem" : "autotools",
@@ -48,69 +39,34 @@
]
},
{
"name" : "graphene",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"name": "graphene",
"buildsystem": "meson",
"builddir": true,
"config-opts": [
"--libdir=/app/lib",
"-Dtests=false",
"-Dbenchmarks=false"
],
"sources" : [
"sources": [
{
"type" : "git",
"url" : "https://github.com/ebassi/graphene.git"
"type": "git",
"url": "https://github.com/ebassi/graphene.git"
}
]
},
{
"name" : "libsass",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"name": "gtk",
"buildsystem": "meson",
"builddir": true,
"config-opts": [
"--libdir=/app/lib"
],
"sources" : [
"sources": [
{
"type" : "git",
"url" : "https://github.com/lazka/libsass.git",
"branch" : "meson"
}
]
},
{
"name" : "sassc",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib"
],
"sources" : [
{
"type" : "git",
"url" : "https://github.com/lazka/sassc.git",
"branch" : "meson"
}
]
},
{
"name" : "gtk",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/GNOME/gtk.git"
"type": "git",
"url": "https://gitlab.gnome.org/GNOME/gtk.git"
}
]
}
],
"build-options" : {
"env" : {
"DBUS_SESSION_BUS_ADDRESS" : "''"
}
}
]
}

View File

@@ -15,13 +15,7 @@ if 'DESTDIR' not in os.environ:
gtk_immodule_dir = os.path.join(gtk_moduledir, 'immodules')
print('Compiling GSettings schemas...')
glib_compile_schemas = subprocess.check_output(['pkg-config',
'--variable=glib_compile_schemas',
'gio-2.0']).strip()
if not os.path.exists(glib_compile_schemas):
# pkg-config variables only available since GLib 2.62.0.
glib_compile_schemas = 'glib-compile-schemas'
subprocess.call([glib_compile_schemas,
subprocess.call(['glib-compile-schemas',
os.path.join(gtk_datadir, 'glib-2.0', 'schemas')])
print('Updating icon cache...')
@@ -30,14 +24,8 @@ if 'DESTDIR' not in os.environ:
print('Updating module cache for print backends...')
os.makedirs(gtk_printmodule_dir, exist_ok=True)
gio_querymodules = subprocess.check_output(['pkg-config',
'--variable=gio_querymodules',
'gio-2.0']).strip()
if not os.path.exists(gio_querymodules):
# pkg-config variables only available since GLib 2.62.0.
gio_querymodules = 'gio-querymodules'
subprocess.call([gio_querymodules, gtk_printmodule_dir])
subprocess.call(['gio-querymodules', gtk_printmodule_dir])
print('Updating module cache for input methods...')
os.makedirs(gtk_immodule_dir, exist_ok=True)
subprocess.call([gio_querymodules, gtk_immodule_dir])
subprocess.call(['gio-querymodules', gtk_immodule_dir])

View File

@@ -27,6 +27,14 @@
/* Define to 1 if you have the `dcgettext' function. */
#mesondefine HAVE_DCGETTEXT
/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't.
*/
#mesondefine HAVE_DECL_ISINF
/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't.
*/
#mesondefine HAVE_DECL_ISNAN
/* Define to 1 if you have the <dlfcn.h> header file. */
#mesondefine HAVE_DLFCN_H
@@ -72,6 +80,9 @@
/* Define to 1 if you have a working `mmap' system call. */
#mesondefine HAVE_MMAP
/* Define to 1 if you have the `nearbyint' function. */
#mesondefine HAVE_NEARBYINT
/* Define to 1 if you have the `posix_fallocate' function. */
#mesondefine HAVE_POSIX_FALLOCATE
@@ -81,9 +92,21 @@
/* Have the Xrandr 1.5 extension library */
#mesondefine HAVE_RANDR15
/* Define to 1 if you have the `rint' function. */
#mesondefine HAVE_RINT
/* Define to 1 if you have the `round' function. */
#mesondefine HAVE_ROUND
/* Define to 1 if you have the `sincos' function. */
#mesondefine HAVE_SINCOS
/* Define to 1 if you have the `log2` function */
#mesondefine HAVE_LOG2
/* Define to 1 if you ahve the `exp2` function */
#mesondefine HAVE_EXP2
/* Define to 1 if you have the <stdint.h> header file. */
#mesondefine HAVE_STDINT_H
@@ -272,6 +295,3 @@
#mesondefine HAVE_PANGOFT
#mesondefine ISO_CODES_PREFIX
/* Define if tracker3 is available */
#mesondefine HAVE_TRACKER3

View File

@@ -221,12 +221,9 @@ open_cb (GtkWidget *button,
GTK_FILE_CHOOSER_ACTION_OPEN,
"_Load",
"_Cancel");
gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (dialog), TRUE);
GFile *cwd = g_file_new_for_path (".");
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), cwd, NULL);
g_object_unref (cwd);
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), ".");
g_signal_connect (dialog, "response", G_CALLBACK (open_response_cb), self);
gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog));
}
@@ -293,37 +290,29 @@ save_response_cb (GtkNativeDialog *dialog,
if (response == GTK_RESPONSE_ACCEPT)
{
GListModel *model;
GFile *file;
char *text;
char *text, *filename;
GError *error = NULL;
model = constraint_view_get_model (CONSTRAINT_VIEW (self->view));
text = serialize_model (model);
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
g_file_replace_contents (file, text, -1,
NULL, FALSE,
G_FILE_CREATE_NONE,
NULL,
NULL,
&error);
if (error != NULL)
{
GtkWidget *message_dialog;
message_dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self))),
GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"Saving failed");
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (message_dialog),
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
if (!g_file_set_contents (filename, text, -1, &error))
{
GtkWidget *dialog;
dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self))),
GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"Saving failed");
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
"%s", error->message);
g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
gtk_widget_show (message_dialog);
g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
gtk_widget_show (dialog);
g_error_free (error);
}
g_free (text);
g_object_unref (file);
g_free (filename);
}
gtk_native_dialog_destroy (dialog);
@@ -340,12 +329,9 @@ save_cb (GtkWidget *button,
GTK_FILE_CHOOSER_ACTION_SAVE,
"_Save",
"_Cancel");
gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (dialog), TRUE);
GFile *cwd = g_file_new_for_path (".");
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), cwd, NULL);
g_object_unref (cwd);
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), ".");
g_signal_connect (dialog, "response", G_CALLBACK (save_response_cb), self);
gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog));
}
@@ -403,7 +389,7 @@ constraint_editor_done (ConstraintEditor *editor,
g_clear_object (&old_constraint);
gtk_window_destroy (GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW)));
gtk_widget_destroy (gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW));
}
static void
@@ -414,7 +400,7 @@ edit_constraint (ConstraintEditorWindow *win,
ConstraintEditor *editor;
GListModel *model;
window = gtk_window_new ();
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (win));
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
if (constraint)
@@ -426,7 +412,7 @@ edit_constraint (ConstraintEditorWindow *win,
editor = constraint_editor_new (model, constraint);
gtk_window_set_child (GTK_WINDOW (window), GTK_WIDGET (editor));
gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (editor));
g_signal_connect (editor, "done", G_CALLBACK (constraint_editor_done), win);
@@ -444,7 +430,7 @@ guide_editor_done (GuideEditor *editor,
GtkConstraintGuide *guide,
ConstraintEditorWindow *win)
{
gtk_window_destroy (GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW)));
gtk_widget_destroy (gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW));
}
static void
@@ -454,13 +440,13 @@ edit_guide (ConstraintEditorWindow *win,
GtkWidget *window;
GuideEditor *editor;
window = gtk_window_new ();
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (win));
gtk_window_set_title (GTK_WINDOW (window), "Edit Guide");
editor = guide_editor_new (guide);
gtk_window_set_child (GTK_WINDOW (window), GTK_WIDGET (editor));
gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (editor));
g_signal_connect (editor, "done", G_CALLBACK (guide_editor_done), win);
gtk_widget_show (window);
@@ -487,6 +473,8 @@ constraint_editor_window_class_init (ConstraintEditorWindowClass *class)
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
g_type_ensure (CONSTRAINT_VIEW_TYPE);
object_class->finalize = constraint_editor_window_finalize;
gtk_widget_class_set_template_from_resource (widget_class,
@@ -599,33 +587,30 @@ create_widget_func (gpointer item,
g_object_bind_property (item, "name",
label, "label",
G_BINDING_DEFAULT);
gtk_widget_set_margin_start (label, 10);
gtk_widget_set_margin_end (label, 10);
gtk_widget_set_margin_top (label, 10);
gtk_widget_set_margin_bottom (label, 10);
g_object_set (label, "margin", 10, NULL);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_widget_set_hexpand (label, TRUE);
gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), box);
gtk_box_append (GTK_BOX (box), label);
gtk_container_add (GTK_CONTAINER (row), box);
gtk_container_add (GTK_CONTAINER (box), label);
if (GTK_IS_CONSTRAINT (item) || GTK_IS_CONSTRAINT_GUIDE (item))
{
button = gtk_button_new_from_icon_name ("document-edit-symbolic");
gtk_button_set_has_frame (GTK_BUTTON (button), FALSE);
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
g_signal_connect (button, "clicked", G_CALLBACK (row_edit), win);
g_object_set_data (G_OBJECT (row), "edit", button);
gtk_box_append (GTK_BOX (box), button);
gtk_container_add (GTK_CONTAINER (box), button);
button = gtk_button_new_from_icon_name ("edit-delete-symbolic");
gtk_button_set_has_frame (GTK_BUTTON (button), FALSE);
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
g_signal_connect (button, "clicked", G_CALLBACK (row_delete), win);
gtk_box_append (GTK_BOX (box), button);
gtk_container_add (GTK_CONTAINER (box), button);
}
else if (GTK_IS_WIDGET (item))
{
button = gtk_button_new_from_icon_name ("edit-delete-symbolic");
gtk_button_set_has_frame (GTK_BUTTON (button), FALSE);
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
g_signal_connect (button, "clicked", G_CALLBACK (row_delete), win);
gtk_box_append (GTK_BOX (box), button);
gtk_container_add (GTK_CONTAINER (box), button);
}
g_free (freeme);

View File

@@ -9,6 +9,8 @@
<property name="default-height">768</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="title" translatable="yes">GTK Constraint Editor</property>
<property name="show-title-buttons">1</property>
<child type="start">
<object class="GtkButton">
<property name="icon-name">document-open-symbolic</property>

View File

@@ -3,10 +3,7 @@
<template class="ConstraintEditor" parent="GtkWidget">
<child>
<object class="GtkGrid" id="grid">
<property name="margin-start">20</property>
<property name="margin-end">20</property>
<property name="margin-top">20</property>
<property name="margin-bottom">20</property>
<property name="margin">20</property>
<property name="row-spacing">10</property>
<property name="column-spacing">10</property>
<child>

View File

@@ -77,7 +77,7 @@ update_weak_position (ConstraintView *self,
GTK_CONSTRAINT_RELATION_EQ,
x,
GTK_CONSTRAINT_STRENGTH_WEAK);
g_object_set_data (G_OBJECT (constraint), "internal", (char *)"yes");
g_object_set_data (G_OBJECT (constraint), "internal", "yes");
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (child), "x-constraint", constraint);
@@ -97,7 +97,7 @@ update_weak_position (ConstraintView *self,
GTK_CONSTRAINT_RELATION_EQ,
y,
GTK_CONSTRAINT_STRENGTH_WEAK);
g_object_set_data (G_OBJECT (constraint), "internal", (char *)"yes");
g_object_set_data (G_OBJECT (constraint), "internal", "yes");
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (child), "y-constraint", constraint);
@@ -188,7 +188,7 @@ constraint_view_init (ConstraintView *self)
g_list_store_append (list, children);
g_list_store_append (list, guides);
g_list_store_append (list, constraints);
self->model = G_LIST_MODEL (gtk_flatten_list_model_new (G_LIST_MODEL (list)));
self->model = G_LIST_MODEL (gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (list)));
g_object_unref (children);
g_object_unref (guides);
g_object_unref (constraints);
@@ -219,9 +219,9 @@ constraint_view_add_child (ConstraintView *view,
label = gtk_label_new (name);
frame = gtk_frame_new (NULL);
gtk_widget_add_css_class (frame, "child");
gtk_style_context_add_class (gtk_widget_get_style_context (frame), "child");
gtk_widget_set_name (frame, name);
gtk_frame_set_child (GTK_FRAME (frame), label);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_widget_set_parent (frame, GTK_WIDGET (view));
update_weak_position (view, frame, 100, 100);
@@ -262,9 +262,9 @@ constraint_view_add_guide (ConstraintView *view,
G_BINDING_DEFAULT);
frame = gtk_frame_new (NULL);
gtk_widget_add_css_class (frame, "guide");
g_object_set_data (G_OBJECT (frame), "internal", (char *)"yes");
gtk_frame_set_child (GTK_FRAME (frame), label);
gtk_style_context_add_class (gtk_widget_get_style_context (frame), "guide");
g_object_set_data (G_OBJECT (frame), "internal", "yes");
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_widget_insert_after (frame, GTK_WIDGET (view), NULL);
g_object_set_data (G_OBJECT (guide), "frame", frame);
@@ -281,7 +281,7 @@ constraint_view_add_guide (ConstraintView *view,
names[i].attr,
1.0, 0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED);
g_object_set_data (G_OBJECT (constraint), "internal", (char *)"yes");
g_object_set_data (G_OBJECT (constraint), "internal", "yes");
gtk_constraint_layout_add_constraint (layout, constraint);
g_object_set_data (G_OBJECT (guide), names[i].name, constraint);
}

View File

@@ -23,7 +23,6 @@
#define CONSTRAINT_VIEW_TYPE (constraint_view_get_type ())
G_MODULE_EXPORT
G_DECLARE_FINAL_TYPE (ConstraintView, constraint_view, CONSTRAINT, VIEW, GtkWidget)
ConstraintView * constraint_view_new (void);

View File

@@ -78,7 +78,7 @@ get_strength (const char *id)
return strength;
}
static const char *
const char *
get_strength_nick (GtkConstraintStrength strength)
{
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH);

View File

@@ -45,10 +45,7 @@
<template class="GuideEditor" parent="GtkWidget">
<child>
<object class="GtkGrid" id="grid">
<property name="margin-start">20</property>
<property name="margin-end">20</property>
<property name="margin-top">20</property>
<property name="margin-bottom">20</property>
<property name="margin">20</property>
<property name="row-spacing">10</property>
<property name="column-spacing">10</property>
<child>

View File

@@ -13,7 +13,6 @@ constraint_editor_resources = gnome.compile_resources('constraint_editor_resourc
executable('gtk4-constraint-editor',
constraint_editor_sources, constraint_editor_resources,
c_args: common_cflags,
dependencies: libgtk_dep,
include_directories: confinc,
gui_app: true,

View File

@@ -6,7 +6,6 @@
typedef GtkApplication DemoApplication;
typedef GtkApplicationClass DemoApplicationClass;
static GType demo_application_get_type (void);
G_DEFINE_TYPE (DemoApplication, demo_application, GTK_TYPE_APPLICATION)
typedef struct {
@@ -15,7 +14,7 @@ typedef struct {
GtkWidget *message;
GtkWidget *infobar;
GtkWidget *status;
GtkWidget *menubutton;
GtkWidget *menutool;
GMenuModel *toolmenu;
GtkTextBuffer *buffer;
@@ -26,7 +25,6 @@ typedef struct {
} DemoApplicationWindow;
typedef GtkApplicationWindowClass DemoApplicationWindowClass;
static GType demo_application_window_get_type (void);
G_DEFINE_TYPE (DemoApplicationWindow, demo_application_window, GTK_TYPE_APPLICATION_WINDOW)
static void create_window (GApplication *app, const char *contents);
@@ -47,7 +45,7 @@ show_action_dialog (GSimpleAction *action)
name);
g_signal_connect (dialog, "response",
G_CALLBACK (gtk_window_destroy), NULL);
G_CALLBACK (gtk_widget_destroy), NULL);
gtk_widget_show (dialog);
}
@@ -120,7 +118,7 @@ open_response_cb (GtkNativeDialog *dialog,
"Error loading file: \"%s\"",
error->message);
g_signal_connect (message_dialog, "response",
G_CALLBACK (gtk_window_destroy), NULL);
G_CALLBACK (gtk_widget_destroy), NULL);
gtk_widget_show (message_dialog);
g_error_free (error);
}
@@ -234,7 +232,7 @@ activate_quit (GSimpleAction *action,
win = list->data;
next = list->next;
gtk_window_destroy (GTK_WINDOW (win));
gtk_widget_destroy (GTK_WIDGET (win));
list = next;
}
@@ -328,14 +326,19 @@ static void
startup (GApplication *app)
{
GtkBuilder *builder;
GMenuModel *appmenu;
GMenuModel *menubar;
G_APPLICATION_CLASS (demo_application_parent_class)->startup (app);
builder = gtk_builder_new ();
gtk_builder_add_from_resource (builder, "/application_demo/menus.ui", NULL);
gtk_application_set_menubar (GTK_APPLICATION (app),
G_MENU_MODEL (gtk_builder_get_object (builder, "menubar")));
appmenu = (GMenuModel *)gtk_builder_get_object (builder, "appmenu");
menubar = (GMenuModel *)gtk_builder_get_object (builder, "menubar");
gtk_application_set_app_menu (GTK_APPLICATION (app), appmenu);
gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
g_object_unref (builder);
}
@@ -348,7 +351,6 @@ create_window (GApplication *app,
window = (DemoApplicationWindow *)g_object_new (demo_application_window_get_type (),
"application", app,
"show-menubar", TRUE,
NULL);
if (content)
gtk_text_buffer_set_text (window->buffer, content, -1);
@@ -417,7 +419,7 @@ demo_application_window_load_state (DemoApplicationWindow *win)
static void
demo_application_window_init (DemoApplicationWindow *window)
{
GtkWidget *popover;
GtkWidget *menu;
window->width = -1;
window->height = -1;
@@ -426,8 +428,8 @@ demo_application_window_init (DemoApplicationWindow *window)
gtk_widget_init_template (GTK_WIDGET (window));
popover = gtk_popover_menu_new_from_model (window->toolmenu);
gtk_menu_button_set_popover (GTK_MENU_BUTTON (window->menubutton), popover);
menu = gtk_menu_new_from_model (window->toolmenu);
gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (window->menutool), menu);
g_action_map_add_action_entries (G_ACTION_MAP (window),
win_entries, G_N_ELEMENTS (win_entries),
@@ -475,7 +477,7 @@ surface_state_changed (GtkWidget *widget)
DemoApplicationWindow *window = (DemoApplicationWindow *)widget;
GdkSurfaceState new_state;
new_state = gdk_toplevel_get_state (GDK_TOPLEVEL (gtk_native_get_surface (GTK_NATIVE (widget))));
new_state = gdk_surface_get_state (gtk_native_get_surface (GTK_NATIVE (widget)));
window->maximized = (new_state & GDK_SURFACE_STATE_MAXIMIZED) != 0;
window->fullscreen = (new_state & GDK_SURFACE_STATE_FULLSCREEN) != 0;
}
@@ -499,13 +501,13 @@ demo_application_window_unrealize (GtkWidget *widget)
}
static void
demo_application_window_dispose (GObject *object)
demo_application_window_destroy (GtkWidget *widget)
{
DemoApplicationWindow *window = (DemoApplicationWindow *)object;
DemoApplicationWindow *window = (DemoApplicationWindow *)widget;
demo_application_window_store_state (window);
G_OBJECT_CLASS (demo_application_window_parent_class)->dispose (object);
GTK_WIDGET_CLASS (demo_application_window_parent_class)->destroy (widget);
}
static void
@@ -515,18 +517,18 @@ demo_application_window_class_init (DemoApplicationWindowClass *class)
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->constructed = demo_application_window_constructed;
object_class->dispose = demo_application_window_dispose;
widget_class->size_allocate = demo_application_window_size_allocate;
widget_class->realize = demo_application_window_realize;
widget_class->unrealize = demo_application_window_unrealize;
widget_class->destroy = demo_application_window_destroy;
gtk_widget_class_set_template_from_resource (widget_class, "/application_demo/application.ui");
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, message);
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, infobar);
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, status);
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, buffer);
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, menubutton);
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, menutool);
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, toolmenu);
gtk_widget_class_bind_template_callback (widget_class, clicked_cb);
gtk_widget_class_bind_template_callback (widget_class, update_statusbar);

View File

@@ -8,24 +8,27 @@
<child>
<object class="GtkGrid">
<child>
<object class="GtkBox">
<object class="GtkToolbar">
<property name="hexpand">1</property>
<style>
<class name="primary-toolbar"/>
</style>
<child>
<object class="GtkMenuButton" id="menubutton">
<object class="GtkMenuToolButton" id="menutool">
<property name="icon-name">document-open</property>
</object>
</child>
<child>
<object class="GtkButton">
<object class="GtkToolButton">
<property name="icon-name">application-exit</property>
<property name="action-name">app.quit</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
<object class="GtkSeparatorToolItem"/>
</child>
<child>
<object class="GtkButton">
<object class="GtkToolButton">
<property name="icon-name">applications-other</property>
<property name="action-name">win.logo</property>
</object>
@@ -40,17 +43,25 @@
<object class="GtkInfoBar" id="infobar">
<property name="visible">0</property>
<property name="hexpand">1</property>
<child>
<object class="GtkLabel" id="message">
<property name="hexpand">1</property>
<child internal-child="content_area">
<object class="GtkBox" id="content_area">
<child>
<object class="GtkLabel" id="message">
<property name="hexpand">1</property>
</object>
</child>
</object>
</child>
<child type="action">
<object class="GtkButton">
<property name="valign">center</property>
<property name="label" translatable="yes">_OK</property>
<property name="use-underline">1</property>
<signal name="clicked" handler="clicked_cb"/>
<child internal-child="action_area">
<object class="GtkBox">
<child>
<object class="GtkButton">
<property name="valign">center</property>
<property name="label" translatable="yes">_OK</property>
<property name="use-underline">1</property>
<signal name="clicked" handler="clicked_cb"/>
</object>
</child>
</object>
</child>
<layout>
@@ -61,7 +72,7 @@
</child>
<child>
<object class="GtkScrolledWindow">
<property name="has-frame">1</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkTextView">
<property name="hexpand">1</property>

View File

@@ -31,7 +31,12 @@ on_name_vanished (GDBusConnection *connection,
if (!name_seen)
return;
g_clear_object (&placeholder);
if (placeholder)
{
gtk_widget_destroy (placeholder);
g_object_unref (placeholder);
placeholder = NULL;
}
}
#ifdef G_OS_WIN32

18
demos/gtk-demo/appmenu.ui Normal file
View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id="appmenu">
<section>
<item>
<attribute name="label" translatable="yes">About</attribute>
<attribute name="action">app.about</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">_Quit</attribute>
<attribute name="action">app.quit</attribute>
<attribute name="accel">&lt;Primary&gt;q</attribute>
</item>
</section>
</menu>
</interface>

View File

@@ -7,6 +7,7 @@
#include <gtk/gtk.h>
static GtkWidget *assistant = NULL;
static GtkWidget *progress_bar = NULL;
static gboolean
@@ -26,7 +27,8 @@ apply_changes_gradually (gpointer data)
else
{
/* Close automatically once changes are fully applied. */
gtk_window_destroy (GTK_WINDOW (data));
gtk_widget_destroy (assistant);
assistant = NULL;
return G_SOURCE_REMOVE;
}
}
@@ -35,13 +37,16 @@ static void
on_assistant_apply (GtkWidget *widget, gpointer data)
{
/* Start a timer to simulate changes taking a few seconds to apply. */
g_timeout_add (100, apply_changes_gradually, widget);
g_timeout_add (100, apply_changes_gradually, NULL);
}
static void
on_assistant_close_cancel (GtkWidget *widget, gpointer data)
{
gtk_window_destroy (GTK_WINDOW (widget));
GtkWidget **assistant = (GtkWidget **) data;
gtk_widget_destroy (*assistant);
*assistant = NULL;
}
static void
@@ -89,18 +94,14 @@ create_page1 (GtkWidget *assistant)
GtkWidget *box, *label, *entry;
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
gtk_widget_set_margin_start (box, 12);
gtk_widget_set_margin_end (box, 12);
gtk_widget_set_margin_top (box, 12);
gtk_widget_set_margin_bottom (box, 12);
label = gtk_label_new ("You must fill out this entry to continue:");
gtk_box_append (GTK_BOX (box), label);
gtk_container_add (GTK_CONTAINER (box), label);
entry = gtk_entry_new ();
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
gtk_widget_set_valign (entry, GTK_ALIGN_CENTER);
gtk_box_append (GTK_BOX (box), entry);
gtk_container_add (GTK_CONTAINER (box), entry);
g_signal_connect (G_OBJECT (entry), "changed",
G_CALLBACK (on_entry_changed), assistant);
@@ -114,16 +115,11 @@ create_page2 (GtkWidget *assistant)
{
GtkWidget *box, *checkbutton;
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
gtk_widget_set_margin_start (box, 12);
gtk_widget_set_margin_end (box, 12);
gtk_widget_set_margin_top (box, 12);
gtk_widget_set_margin_bottom (box, 12);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
checkbutton = gtk_check_button_new_with_label ("This is optional data, you may continue "
"even if you do not check this");
gtk_widget_set_valign (checkbutton, GTK_ALIGN_CENTER);
gtk_box_append (GTK_BOX (box), checkbutton);
gtk_container_add (GTK_CONTAINER (box), checkbutton);
gtk_assistant_append_page (GTK_ASSISTANT (assistant), box);
gtk_assistant_set_page_complete (GTK_ASSISTANT (assistant), box, TRUE);
@@ -168,8 +164,6 @@ create_page4 (GtkWidget *assistant)
GtkWidget*
do_assistant (GtkWidget *do_widget)
{
static GtkWidget *assistant;
if (!assistant)
{
assistant = gtk_assistant_new ();
@@ -178,7 +172,6 @@ do_assistant (GtkWidget *do_widget)
gtk_window_set_display (GTK_WINDOW (assistant),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (assistant), (gpointer *)&assistant);
create_page1 (assistant);
create_page2 (assistant);
@@ -186,9 +179,9 @@ do_assistant (GtkWidget *do_widget)
create_page4 (assistant);
g_signal_connect (G_OBJECT (assistant), "cancel",
G_CALLBACK (on_assistant_close_cancel), NULL);
G_CALLBACK (on_assistant_close_cancel), &assistant);
g_signal_connect (G_OBJECT (assistant), "close",
G_CALLBACK (on_assistant_close_cancel), NULL);
G_CALLBACK (on_assistant_close_cancel), &assistant);
g_signal_connect (G_OBJECT (assistant), "apply",
G_CALLBACK (on_assistant_apply), NULL);
g_signal_connect (G_OBJECT (assistant), "prepare",
@@ -198,7 +191,10 @@ do_assistant (GtkWidget *do_widget)
if (!gtk_widget_get_visible (assistant))
gtk_widget_show (assistant);
else
gtk_window_destroy (GTK_WINDOW (assistant));
{
gtk_widget_destroy (assistant);
assistant = NULL;
}
return assistant;
}

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

@@ -25,8 +25,9 @@
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow">
<property name="can-focus">1</property>
<property name="vexpand">1</property>
<property name="has-frame">1</property>
<property name="shadow-type">in</property>
<property name="min-content-width">150</property>
<layout>
<property name="left-attach">0</property>

View File

@@ -39,7 +39,7 @@ enum {
static guint signals[LAST_SIGNAL] = { 0 };
static GQuark child_data_quark = 0;
G_DEFINE_TYPE (BlurOverlay, blur_overlay, GTK_TYPE_WIDGET)
G_DEFINE_TYPE (BlurOverlay, blur_overlay, GTK_TYPE_BIN)
static void
blur_overlay_set_overlay_child (GtkWidget *widget,
@@ -131,11 +131,13 @@ blur_overlay_child_update_style_classes (BlurOverlay *overlay,
GtkAlign valign, halign;
gboolean is_left, is_right, is_top, is_bottom;
gboolean has_left, has_right, has_top, has_bottom;
GtkStyleContext *context;
has_left = gtk_widget_has_css_class (child, GTK_STYLE_CLASS_LEFT);
has_right = gtk_widget_has_css_class (child, GTK_STYLE_CLASS_RIGHT);
has_top = gtk_widget_has_css_class (child, GTK_STYLE_CLASS_TOP);
has_bottom = gtk_widget_has_css_class (child, GTK_STYLE_CLASS_BOTTOM);
context = gtk_widget_get_style_context (child);
has_left = gtk_style_context_has_class (context, GTK_STYLE_CLASS_LEFT);
has_right = gtk_style_context_has_class (context, GTK_STYLE_CLASS_RIGHT);
has_top = gtk_style_context_has_class (context, GTK_STYLE_CLASS_TOP);
has_bottom = gtk_style_context_has_class (context, GTK_STYLE_CLASS_BOTTOM);
is_left = is_right = is_top = is_bottom = FALSE;
@@ -158,24 +160,24 @@ blur_overlay_child_update_style_classes (BlurOverlay *overlay,
is_bottom = (child_allocation->y + child_allocation->height == height);
if (has_left && !is_left)
gtk_widget_remove_css_class (child, GTK_STYLE_CLASS_LEFT);
gtk_style_context_remove_class (context, GTK_STYLE_CLASS_LEFT);
else if (!has_left && is_left)
gtk_widget_add_css_class (child, GTK_STYLE_CLASS_LEFT);
gtk_style_context_add_class (context, GTK_STYLE_CLASS_LEFT);
if (has_right && !is_right)
gtk_widget_remove_css_class (child, GTK_STYLE_CLASS_RIGHT);
gtk_style_context_remove_class (context, GTK_STYLE_CLASS_RIGHT);
else if (!has_right && is_right)
gtk_widget_add_css_class (child, GTK_STYLE_CLASS_RIGHT);
gtk_style_context_add_class (context, GTK_STYLE_CLASS_RIGHT);
if (has_top && !is_top)
gtk_widget_remove_css_class (child, GTK_STYLE_CLASS_TOP);
gtk_style_context_remove_class (context, GTK_STYLE_CLASS_TOP);
else if (!has_top && is_top)
gtk_widget_add_css_class (child, GTK_STYLE_CLASS_TOP);
gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOP);
if (has_bottom && !is_bottom)
gtk_widget_remove_css_class (child, GTK_STYLE_CLASS_BOTTOM);
gtk_style_context_remove_class (context, GTK_STYLE_CLASS_BOTTOM);
else if (!has_bottom && is_bottom)
gtk_widget_add_css_class (child, GTK_STYLE_CLASS_BOTTOM);
gtk_style_context_add_class (context, GTK_STYLE_CLASS_BOTTOM);
}
static void
@@ -204,7 +206,7 @@ blur_overlay_size_allocate (GtkWidget *widget,
GtkWidget *child;
GtkWidget *main_widget;
main_widget = overlay->main_widget;
main_widget = gtk_bin_get_child (GTK_BIN (overlay));
if (main_widget && gtk_widget_get_visible (main_widget))
gtk_widget_size_allocate (main_widget,
&(GtkAllocation) {
@@ -290,6 +292,43 @@ blur_overlay_get_child_position (BlurOverlay *overlay,
return TRUE;
}
static void
blur_overlay_add (GtkContainer *container,
GtkWidget *widget)
{
BlurOverlay *overlay = BLUR_OVERLAY (container);
gtk_widget_insert_after (widget, GTK_WIDGET (container), NULL);
overlay->main_widget = widget;
}
static void
blur_overlay_remove (GtkContainer *container,
GtkWidget *widget)
{
BlurOverlay *overlay = BLUR_OVERLAY (container);
gtk_widget_unparent (widget);
if (overlay->main_widget == widget)
overlay->main_widget = NULL;
}
static void
blur_overlay_forall (GtkContainer *overlay,
GtkCallback callback,
gpointer callback_data)
{
GtkWidget *child;
child = gtk_widget_get_first_child (GTK_WIDGET (overlay));
while (child != NULL)
{
GtkWidget *next = gtk_widget_get_next_sibling (child);
(* callback) (child, callback_data);
child = next;
}
}
static void
blur_overlay_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
@@ -383,32 +422,21 @@ blur_overlay_snapshot (GtkWidget *widget,
gsk_render_node_unref (main_widget_node);
}
static void
blur_overlay_dispose (GObject *object)
{
BlurOverlay *overlay = BLUR_OVERLAY (object);
GtkWidget *child;
g_clear_pointer (&overlay->main_widget, gtk_widget_unparent);
while ((child = gtk_widget_get_first_child (GTK_WIDGET (overlay))))
gtk_widget_unparent (child);
G_OBJECT_CLASS (blur_overlay_parent_class)->dispose (object);
}
static void
blur_overlay_class_init (BlurOverlayClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = blur_overlay_dispose;
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
widget_class->measure = blur_overlay_measure;
widget_class->size_allocate = blur_overlay_size_allocate;
widget_class->snapshot = blur_overlay_snapshot;
container_class->add = blur_overlay_add;
container_class->remove = blur_overlay_remove;
container_class->forall = blur_overlay_forall;
klass->get_child_position = blur_overlay_get_child_position;
signals[GET_CHILD_POSITION] =
@@ -451,11 +479,3 @@ blur_overlay_add_overlay (BlurOverlay *overlay,
blur_overlay_set_overlay_child (widget, child);
}
void
blur_overlay_set_child (BlurOverlay *overlay,
GtkWidget *widget)
{
gtk_widget_insert_after (widget, GTK_WIDGET (overlay), NULL);
overlay->main_widget = widget;
}

View File

@@ -37,14 +37,14 @@ typedef struct _BlurOverlayClass BlurOverlayClass;
struct _BlurOverlay
{
GtkWidget parent_instance;
GtkBin parent_instance;
GtkWidget *main_widget;
};
struct _BlurOverlayClass
{
GtkWidgetClass parent_class;
GtkBinClass parent_class;
gboolean (*get_child_position) (BlurOverlay *overlay,
GtkWidget *widget,
@@ -59,9 +59,6 @@ GDK_AVAILABLE_IN_ALL
void blur_overlay_add_overlay (BlurOverlay *overlay,
GtkWidget *widget,
double blur);
GDK_AVAILABLE_IN_ALL
void blur_overlay_set_child (BlurOverlay *overlay,
GtkWidget *widget);
G_END_DECLS

View File

@@ -12,7 +12,7 @@ quit_activate (GSimpleAction *action,
{
GtkWidget *window = user_data;
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
}
static void
@@ -26,10 +26,8 @@ about_activate (GSimpleAction *action,
builder = g_object_get_data (G_OBJECT (window), "builder");
about_dlg = GTK_WIDGET (gtk_builder_get_object (builder, "aboutdialog1"));
gtk_window_set_transient_for (GTK_WINDOW (about_dlg), GTK_WINDOW (window));
gtk_window_set_hide_on_close (GTK_WINDOW (about_dlg), TRUE);
g_signal_connect (about_dlg, "response", G_CALLBACK (gtk_widget_hide), NULL);
gtk_widget_show (about_dlg);
gtk_dialog_run (GTK_DIALOG (about_dlg));
gtk_widget_hide (about_dlg);
}
static void
@@ -40,22 +38,7 @@ help_activate (GSimpleAction *action,
g_print ("Help not available\n");
}
static void
not_implemented (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
g_print ("Action “%s” not implemented\n", g_action_get_name (G_ACTION (action)));
}
static GActionEntry win_entries[] = {
{ "new", not_implemented, NULL, NULL, NULL },
{ "open", not_implemented, NULL, NULL, NULL },
{ "save", not_implemented, NULL, NULL, NULL },
{ "save-as", not_implemented, NULL, NULL, NULL },
{ "copy", not_implemented, NULL, NULL, NULL },
{ "cut", not_implemented, NULL, NULL, NULL },
{ "paste", not_implemented, NULL, NULL, NULL },
{ "quit", quit_activate, NULL, NULL, NULL },
{ "about", about_activate, NULL, NULL, NULL },
{ "help", help_activate, NULL, NULL, NULL }
@@ -65,7 +48,10 @@ GtkWidget *
do_builder (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
GtkWidget *toolbar;
GActionGroup *actions;
GtkAccelGroup *accel_group;
GtkWidget *item;
if (!window)
{
@@ -76,20 +62,62 @@ do_builder (GtkWidget *do_widget)
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
toolbar = GTK_WIDGET (gtk_builder_get_object (builder, "toolbar1"));
gtk_style_context_add_class (gtk_widget_get_style_context (toolbar),
"primary-toolbar");
actions = (GActionGroup*)g_simple_action_group_new ();
g_action_map_add_action_entries (G_ACTION_MAP (actions),
win_entries, G_N_ELEMENTS (win_entries),
window);
gtk_widget_insert_action_group (window, "win", actions);
accel_group = gtk_accel_group_new ();
gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
g_object_unref (builder);
item = (GtkWidget*)gtk_builder_get_object (builder, "new_item");
gtk_widget_add_accelerator (item, "activate", accel_group,
GDK_KEY_n, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
item = (GtkWidget*)gtk_builder_get_object (builder, "open_item");
gtk_widget_add_accelerator (item, "activate", accel_group,
GDK_KEY_o, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
item = (GtkWidget*)gtk_builder_get_object (builder, "save_item");
gtk_widget_add_accelerator (item, "activate", accel_group,
GDK_KEY_s, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
item = (GtkWidget*)gtk_builder_get_object (builder, "quit_item");
gtk_widget_add_accelerator (item, "activate", accel_group,
GDK_KEY_q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
item = (GtkWidget*)gtk_builder_get_object (builder, "copy_item");
gtk_widget_add_accelerator (item, "activate", accel_group,
GDK_KEY_c, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
item = (GtkWidget*)gtk_builder_get_object (builder, "cut_item");
gtk_widget_add_accelerator (item, "activate", accel_group,
GDK_KEY_x, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
item = (GtkWidget*)gtk_builder_get_object (builder, "paste_item");
gtk_widget_add_accelerator (item, "activate", accel_group,
GDK_KEY_v, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
item = (GtkWidget*)gtk_builder_get_object (builder, "help_item");
gtk_widget_add_accelerator (item, "activate", accel_group,
GDK_KEY_F1, 0, GTK_ACCEL_VISIBLE);
item = (GtkWidget*)gtk_builder_get_object (builder, "about_item");
gtk_widget_add_accelerator (item, "activate", accel_group,
GDK_KEY_F7, 0, GTK_ACCEL_VISIBLE);
g_object_set_data_full (G_OBJECT(window), "builder", builder, g_object_unref);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -0,0 +1,551 @@
/* Change Display
*
* Demonstrates migrating a window between different displays.
* A display is a mouse and keyboard with some number of
* associated monitors. The neat thing about having multiple
* displays is that they can be on a completely separate
* computers, as long as there is a network connection to the
* computer where the application is running.
*
* Only some of the windowing systems where GTK runs have the
* concept of multiple displays. (The X Window System is the
* main example.) Other windowing systems can only handle one
* keyboard and mouse, and combine all monitors into
* a single display.
*
* This is a moderately complex example, and demonstrates:
*
* - Tracking the currently open displays
*
* - Changing the display for a window
*
* - Letting the user choose a window by clicking on it
*
* - Using GtkListStore and GtkTreeView
*
* - Using GtkDialog
*/
#include <string.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
/* The ChangeDisplayInfo structure corresponds to a toplevel window and
* holds pointers to widgets inside the toplevel window along with other
* information about the contents of the window.
* This is a common organizational structure in real applications.
*/
typedef struct _ChangeDisplayInfo ChangeDisplayInfo;
struct _ChangeDisplayInfo
{
GtkWidget *window;
GtkSizeGroup *size_group;
GtkTreeModel *display_model;
GdkDisplay *current_display;
};
/* These enumerations provide symbolic names for the columns
* in the two GtkListStore models.
*/
enum
{
DISPLAY_COLUMN_NAME,
DISPLAY_COLUMN_DISPLAY,
DISPLAY_NUM_COLUMNS
};
enum
{
SCREEN_COLUMN_NUMBER,
SCREEN_COLUMN_SCREEN,
SCREEN_NUM_COLUMNS
};
/* Finds the toplevel window under the mouse pointer, if any.
*/
static GtkWidget *
find_toplevel_at_pointer (GdkDisplay *display)
{
GdkSurface *pointer_window;
GtkWidget *widget = NULL;
pointer_window = gdk_device_get_surface_at_position (gtk_get_current_event_device (), NULL, NULL);
if (pointer_window)
widget = GTK_WIDGET (gtk_native_get_for_surface (pointer_window));
return widget;
}
static void
released_cb (GtkGestureClick *gesture,
guint n_press,
gdouble x,
gdouble y,
gboolean *clicked)
{
*clicked = TRUE;
}
/* Asks the user to click on a window, then waits for them click
* the mouse. When the mouse is released, returns the toplevel
* window under the pointer, or NULL, if there is none.
*/
static GtkWidget *
query_for_toplevel (GdkDisplay *display,
const char *prompt)
{
GtkWidget *popup, *label, *frame;
GdkCursor *cursor;
GtkWidget *toplevel = NULL;
GdkDevice *device;
popup = gtk_window_new (GTK_WINDOW_POPUP);
gtk_window_set_display (GTK_WINDOW (popup), display);
gtk_window_set_modal (GTK_WINDOW (popup), TRUE);
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
gtk_container_add (GTK_CONTAINER (popup), frame);
label = gtk_label_new (prompt);
g_object_set (label, "margin", 10, NULL);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_widget_show (popup);
cursor = gdk_cursor_new_from_name ("crosshair", NULL);
device = gtk_get_current_event_device ();
if (gdk_seat_grab (gdk_device_get_seat (device),
gtk_native_get_surface (GTK_NATIVE (popup)),
GDK_SEAT_CAPABILITY_ALL_POINTING,
FALSE, cursor, NULL, NULL, NULL) == GDK_GRAB_SUCCESS)
{
GtkGesture *gesture = gtk_gesture_click_new ();
gboolean clicked = FALSE;
g_signal_connect (gesture, "released",
G_CALLBACK (released_cb), &clicked);
gtk_widget_add_controller (popup, GTK_EVENT_CONTROLLER (gesture));
/* Process events until clicked is set by our button release event handler.
* We pass in may_block=TRUE since we want to wait if there
* are no events currently.
*/
while (!clicked)
g_main_context_iteration (NULL, TRUE);
gdk_seat_ungrab (gdk_device_get_seat (device));
toplevel = find_toplevel_at_pointer (display);
if (toplevel == popup)
toplevel = NULL;
}
g_object_unref (cursor);
gtk_widget_destroy (popup);
return toplevel;
}
/* Prompts the user for a toplevel window to move, and then moves
* that window to the currently selected display
*/
static void
query_change_display (ChangeDisplayInfo *info)
{
GdkDisplay *display = gtk_widget_get_display (info->window);
GtkWidget *toplevel;
toplevel = query_for_toplevel (display,
"Please select the toplevel\n"
"to move to the new display");
if (toplevel)
gtk_window_set_display (GTK_WINDOW (toplevel), info->current_display);
else
gdk_display_beep (display);
}
/* Called when the user clicks on a button in our dialog or
* closes the dialog through the window manager. Unless the
* "Change" button was clicked, we destroy the dialog.
*/
static void
response_cb (GtkDialog *dialog,
gint response_id,
ChangeDisplayInfo *info)
{
if (response_id == GTK_RESPONSE_OK)
query_change_display (info);
else
gtk_widget_destroy (GTK_WIDGET (dialog));
}
/* Called when the user clicks on "Open..." in the display
* frame. Prompts for a new display, and then opens a connection
* to that display.
*/
static void
open_display_cb (GtkWidget *button,
ChangeDisplayInfo *info)
{
GtkWidget *content_area;
GtkWidget *dialog;
GtkWidget *display_entry;
GtkWidget *dialog_label;
gchar *new_screen_name = NULL;
GdkDisplay *result = NULL;
dialog = gtk_dialog_new_with_buttons ("Open Display",
GTK_WINDOW (info->window),
GTK_DIALOG_MODAL,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_OK"), GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
display_entry = gtk_entry_new ();
gtk_entry_set_activates_default (GTK_ENTRY (display_entry), TRUE);
dialog_label =
gtk_label_new ("Please enter the name of\nthe new display\n");
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
gtk_container_add (GTK_CONTAINER (content_area), dialog_label);
gtk_container_add (GTK_CONTAINER (content_area), display_entry);
gtk_widget_grab_focus (display_entry);
while (!result)
{
gint response_id = gtk_dialog_run (GTK_DIALOG (dialog));
if (response_id != GTK_RESPONSE_OK)
break;
new_screen_name = gtk_editable_get_chars (GTK_EDITABLE (display_entry),
0, -1);
if (strcmp (new_screen_name, "") != 0)
{
result = gdk_display_open (new_screen_name);
if (!result)
{
gchar *error_msg =
g_strdup_printf ("Can't open display:\n\t%s\nplease try another one\n",
new_screen_name);
gtk_label_set_text (GTK_LABEL (dialog_label), error_msg);
g_free (error_msg);
}
g_free (new_screen_name);
}
}
gtk_widget_destroy (dialog);
}
/* Called when the user clicks on the "Close" button in the
* "Display" frame. Closes the selected display.
*/
static void
close_display_cb (GtkWidget *button,
ChangeDisplayInfo *info)
{
if (info->current_display)
gdk_display_close (info->current_display);
}
/* Called when the selected row in the display list changes.
* Updates info->current_display, then refills the list of
* screens.
*/
static void
display_changed_cb (GtkTreeSelection *selection,
ChangeDisplayInfo *info)
{
GtkTreeModel *model;
GtkTreeIter iter;
if (info->current_display)
g_object_unref (info->current_display);
if (gtk_tree_selection_get_selected (selection, &model, &iter))
gtk_tree_model_get (model, &iter,
DISPLAY_COLUMN_DISPLAY, &info->current_display,
-1);
else
info->current_display = NULL;
}
/* This function is used both for creating the "Display" and
* "Screen" frames, since they have a similar structure. The
* caller hooks up the right context for the value returned
* in tree_view, and packs any relevant buttons into button_vbox.
*/
static void
create_frame (ChangeDisplayInfo *info,
const char *title,
GtkWidget **frame,
GtkWidget **tree_view,
GtkWidget **button_vbox)
{
GtkTreeSelection *selection;
GtkWidget *scrollwin;
GtkWidget *hbox;
*frame = gtk_frame_new (title);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
g_object_set (hbox, "margin", 8, NULL);
gtk_container_add (GTK_CONTAINER (*frame), hbox);
scrollwin = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollwin),
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollwin),
GTK_SHADOW_IN);
gtk_container_add (GTK_CONTAINER (hbox), scrollwin);
*tree_view = gtk_tree_view_new ();
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (*tree_view), FALSE);
gtk_container_add (GTK_CONTAINER (scrollwin), *tree_view);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*tree_view));
gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
*button_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
gtk_container_add (GTK_CONTAINER (hbox), *button_vbox);
if (!info->size_group)
info->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
gtk_size_group_add_widget (GTK_SIZE_GROUP (info->size_group), *button_vbox);
}
/* If we have a stack of buttons, it often looks better if their contents
* are left-aligned, rather than centered. This function creates a button
* and left-aligns it contents.
*/
GtkWidget *
left_align_button_new (const char *label)
{
GtkWidget *button = gtk_button_new_with_mnemonic (label);
GtkWidget *child = gtk_bin_get_child (GTK_BIN (button));
gtk_widget_set_halign (child, GTK_ALIGN_START);
gtk_widget_set_valign (child, GTK_ALIGN_CENTER);
return button;
}
/* Creates the "Display" frame in the main window.
*/
GtkWidget *
create_display_frame (ChangeDisplayInfo *info)
{
GtkWidget *frame;
GtkWidget *tree_view;
GtkWidget *button_vbox;
GtkTreeViewColumn *column;
GtkTreeSelection *selection;
GtkWidget *button;
create_frame (info, "Display", &frame, &tree_view, &button_vbox);
button = left_align_button_new ("_Open...");
g_signal_connect (button, "clicked", G_CALLBACK (open_display_cb), info);
gtk_container_add (GTK_CONTAINER (button_vbox), button);
button = left_align_button_new ("_Close");
g_signal_connect (button, "clicked", G_CALLBACK (close_display_cb), info);
gtk_container_add (GTK_CONTAINER (button_vbox), button);
info->display_model = (GtkTreeModel *)gtk_list_store_new (DISPLAY_NUM_COLUMNS,
G_TYPE_STRING,
GDK_TYPE_DISPLAY);
gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), info->display_model);
column = gtk_tree_view_column_new_with_attributes ("Name",
gtk_cell_renderer_text_new (),
"text", DISPLAY_COLUMN_NAME,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
g_signal_connect (selection, "changed",
G_CALLBACK (display_changed_cb), info);
return frame;
}
/* Called when one of the currently open displays is closed.
* Remove it from our list of displays.
*/
static void
display_closed_cb (GdkDisplay *display,
gboolean is_error,
ChangeDisplayInfo *info)
{
GtkTreeIter iter;
gboolean valid;
for (valid = gtk_tree_model_get_iter_first (info->display_model, &iter);
valid;
valid = gtk_tree_model_iter_next (info->display_model, &iter))
{
GdkDisplay *tmp_display;
gtk_tree_model_get (info->display_model, &iter,
DISPLAY_COLUMN_DISPLAY, &tmp_display,
-1);
if (tmp_display == display)
{
gtk_list_store_remove (GTK_LIST_STORE (info->display_model), &iter);
break;
}
}
}
/* Adds a new display to our list of displays, and connects
* to the "closed" signal so that we can remove it from the
* list of displays again.
*/
static void
add_display (ChangeDisplayInfo *info,
GdkDisplay *display)
{
const gchar *name = gdk_display_get_name (display);
GtkTreeIter iter;
gtk_list_store_append (GTK_LIST_STORE (info->display_model), &iter);
gtk_list_store_set (GTK_LIST_STORE (info->display_model), &iter,
DISPLAY_COLUMN_NAME, name,
DISPLAY_COLUMN_DISPLAY, display,
-1);
g_signal_connect (display, "closed",
G_CALLBACK (display_closed_cb), info);
}
/* Called when a new display is opened
*/
static void
display_opened_cb (GdkDisplayManager *manager,
GdkDisplay *display,
ChangeDisplayInfo *info)
{
add_display (info, display);
}
/* Adds all currently open displays to our list of displays,
* and set up a signal connection so that we'll be notified
* when displays are opened in the future as well.
*/
static void
initialize_displays (ChangeDisplayInfo *info)
{
GdkDisplayManager *manager = gdk_display_manager_get ();
GSList *displays = gdk_display_manager_list_displays (manager);
GSList *tmp_list;
for (tmp_list = displays; tmp_list; tmp_list = tmp_list->next)
add_display (info, tmp_list->data);
g_slist_free (tmp_list);
g_signal_connect (manager, "display-opened",
G_CALLBACK (display_opened_cb), info);
}
/* Cleans up when the toplevel is destroyed; we remove the
* connections we use to track currently open displays, then
* free the ChangeDisplayInfo structure.
*/
static void
destroy_info (ChangeDisplayInfo *info)
{
GdkDisplayManager *manager = gdk_display_manager_get ();
GSList *displays = gdk_display_manager_list_displays (manager);
GSList *tmp_list;
g_signal_handlers_disconnect_by_func (manager,
display_opened_cb,
info);
for (tmp_list = displays; tmp_list; tmp_list = tmp_list->next)
g_signal_handlers_disconnect_by_func (tmp_list->data,
display_closed_cb,
info);
g_slist_free (tmp_list);
g_object_unref (info->size_group);
g_object_unref (info->display_model);
if (info->current_display)
g_object_unref (info->current_display);
g_free (info);
}
static void
destroy_cb (GObject *object,
ChangeDisplayInfo **info)
{
destroy_info (*info);
*info = NULL;
}
/* Main entry point. If the dialog for this demo doesn't yet exist, creates
* it. Otherwise, destroys it.
*/
GtkWidget *
do_changedisplay (GtkWidget *do_widget)
{
static ChangeDisplayInfo *info = NULL;
if (!info)
{
GtkWidget *content_area;
GtkWidget *vbox;
GtkWidget *frame;
info = g_new0 (ChangeDisplayInfo, 1);
info->window = gtk_dialog_new_with_buttons ("Change Display",
GTK_WINDOW (do_widget),
0,
"Close", GTK_RESPONSE_CLOSE,
"Change", GTK_RESPONSE_OK,
NULL);
gtk_window_set_default_size (GTK_WINDOW (info->window), 300, 400);
g_signal_connect (info->window, "response",
G_CALLBACK (response_cb), info);
g_signal_connect (info->window, "destroy",
G_CALLBACK (destroy_cb), &info);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (info->window));
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
g_object_set (vbox, "margin", 8, NULL);
gtk_container_add (GTK_CONTAINER (content_area), vbox);
frame = create_display_frame (info);
gtk_container_add (GTK_CONTAINER (vbox), frame);
initialize_displays (info);
gtk_widget_show (info->window);
return info->window;
}
else
{
gtk_widget_destroy (info->window);
return NULL;
}
}

View File

@@ -12,11 +12,10 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <string.h>
#include "demoimage.h"
static GtkWidget *window = NULL;
static void
void
copy_button_clicked (GtkWidget *button,
gpointer user_data)
{
@@ -32,7 +31,7 @@ copy_button_clicked (GtkWidget *button,
gdk_clipboard_set_text (clipboard, gtk_editable_get_text (GTK_EDITABLE (entry)));
}
static void
void
paste_received (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
@@ -69,14 +68,14 @@ paste_received (GObject *source_object,
"Could not paste text: %s",
error->message);
g_signal_connect (dialog, "response",
G_CALLBACK (gtk_window_destroy), NULL);
G_CALLBACK (gtk_widget_destroy), NULL);
gtk_widget_show (dialog);
g_error_free (error);
}
}
static void
void
paste_button_clicked (GtkWidget *button,
gpointer user_data)
{
@@ -94,6 +93,146 @@ paste_button_clicked (GtkWidget *button,
gdk_clipboard_read_text_async (clipboard, NULL, paste_received, entry);
}
static GdkPaintable *
get_image_paintable (GtkImage *image)
{
const gchar *icon_name;
GtkIconTheme *icon_theme;
GtkIconInfo *icon_info;
switch (gtk_image_get_storage_type (image))
{
case GTK_IMAGE_PAINTABLE:
return g_object_ref (gtk_image_get_paintable (image));
case GTK_IMAGE_ICON_NAME:
icon_name = gtk_image_get_icon_name (image);
icon_theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (GTK_WIDGET (image)));
icon_info = gtk_icon_theme_lookup_icon (icon_theme, icon_name, 48, GTK_ICON_LOOKUP_GENERIC_FALLBACK);
if (icon_info == NULL)
return NULL;
return gtk_icon_info_load_icon (icon_info, NULL);
default:
g_warning ("Image storage type %d not handled",
gtk_image_get_storage_type (image));
return NULL;
}
}
static void
drag_begin (GtkWidget *widget,
GdkDrag *drag,
gpointer data)
{
GdkPaintable *paintable;
paintable = get_image_paintable (GTK_IMAGE (widget));
if (paintable)
{
gtk_drag_set_icon_paintable (drag, paintable, -2, -2);
g_object_unref (paintable);
}
}
void
drag_data_get (GtkWidget *widget,
GdkDrag *drag,
GtkSelectionData *selection_data,
guint info,
gpointer data)
{
GdkPaintable *paintable;
paintable = get_image_paintable (GTK_IMAGE (widget));
if (GDK_IS_TEXTURE (paintable))
gtk_selection_data_set_texture (selection_data, GDK_TEXTURE (paintable));
}
static void
drag_data_received (GtkWidget *widget,
GdkDrop *drop,
GtkSelectionData *selection_data,
gpointer data)
{
if (gtk_selection_data_get_length (selection_data) > 0)
{
GdkTexture *texture;
texture = gtk_selection_data_get_texture (selection_data);
gtk_image_set_from_paintable (GTK_IMAGE (data), GDK_PAINTABLE (texture));
g_object_unref (texture);
}
}
static void
copy_image (GtkMenuItem *item,
gpointer data)
{
GdkClipboard *clipboard;
GdkPaintable *paintable;
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (data));
paintable = get_image_paintable (GTK_IMAGE (data));
if (GDK_IS_TEXTURE (paintable))
gdk_clipboard_set_texture (clipboard, GDK_TEXTURE (paintable));
if (paintable)
g_object_unref (paintable);
}
static void
paste_image_received (GObject *source,
GAsyncResult *result,
gpointer data)
{
GdkTexture *texture;
texture = gdk_clipboard_read_texture_finish (GDK_CLIPBOARD (source), result, NULL);
if (texture == NULL)
return;
gtk_image_set_from_paintable (GTK_IMAGE (data), GDK_PAINTABLE (texture));
g_object_unref (texture);
}
static void
paste_image (GtkMenuItem *item,
gpointer data)
{
GdkClipboard *clipboard;
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (data));
gdk_clipboard_read_texture_async (clipboard,
NULL,
paste_image_received,
data);
}
static void
pressed_cb (GtkGesture *gesture,
int n_press,
double x,
double y,
GtkWidget *image)
{
GtkWidget *menu;
GtkWidget *item;
menu = gtk_menu_new ();
item = gtk_menu_item_new_with_mnemonic (_("_Copy"));
g_signal_connect (item, "activate", G_CALLBACK (copy_image), image);
gtk_widget_show (item);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
item = gtk_menu_item_new_with_mnemonic (_("_Paste"));
g_signal_connect (item, "activate", G_CALLBACK (paste_image), image);
gtk_widget_show (item);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
gtk_menu_popup_at_pointer (GTK_MENU (menu), NULL);
}
GtkWidget *
do_clipboard (GtkWidget *do_widget)
{
@@ -103,89 +242,118 @@ do_clipboard (GtkWidget *do_widget)
GtkWidget *label;
GtkWidget *entry, *button;
GtkWidget *image;
GtkGesture *gesture;
window = gtk_window_new ();
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), "Clipboard");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_margin_start (vbox, 8);
gtk_widget_set_margin_end (vbox, 8);
gtk_widget_set_margin_top (vbox, 8);
gtk_widget_set_margin_bottom (vbox, 8);
g_object_set (vbox, "margin", 8, NULL);
gtk_window_set_child (GTK_WINDOW (window), vbox);
gtk_container_add (GTK_CONTAINER (window), vbox);
label = gtk_label_new ("\"Copy\" will copy the text\nin the entry to the clipboard");
gtk_box_append (GTK_BOX (vbox), label);
gtk_container_add (GTK_CONTAINER (vbox), label);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
gtk_widget_set_margin_start (hbox, 8);
gtk_widget_set_margin_end (hbox, 8);
gtk_widget_set_margin_top (hbox, 8);
gtk_widget_set_margin_bottom (hbox, 8);
gtk_box_append (GTK_BOX (vbox), hbox);
g_object_set (hbox, "margin", 8, NULL);
gtk_container_add (GTK_CONTAINER (vbox), hbox);
/* Create the first entry */
entry = gtk_entry_new ();
gtk_box_append (GTK_BOX (hbox), entry);
gtk_container_add (GTK_CONTAINER (hbox), entry);
/* Create the button */
button = gtk_button_new_with_mnemonic (_("_Copy"));
gtk_box_append (GTK_BOX (hbox), button);
gtk_container_add (GTK_CONTAINER (hbox), button);
g_signal_connect (button, "clicked",
G_CALLBACK (copy_button_clicked), entry);
label = gtk_label_new ("\"Paste\" will paste the text from the clipboard to the entry");
gtk_box_append (GTK_BOX (vbox), label);
gtk_container_add (GTK_CONTAINER (vbox), label);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
gtk_widget_set_margin_start (hbox, 8);
gtk_widget_set_margin_end (hbox, 8);
gtk_widget_set_margin_top (hbox, 8);
gtk_widget_set_margin_bottom (hbox, 8);
gtk_box_append (GTK_BOX (vbox), hbox);
g_object_set (hbox, "margin", 8, NULL);
gtk_container_add (GTK_CONTAINER (vbox), hbox);
/* Create the second entry */
entry = gtk_entry_new ();
gtk_box_append (GTK_BOX (hbox), entry);
gtk_container_add (GTK_CONTAINER (hbox), entry);
/* Create the button */
button = gtk_button_new_with_mnemonic (_("_Paste"));
gtk_box_append (GTK_BOX (hbox), button);
gtk_container_add (GTK_CONTAINER (hbox), button);
g_signal_connect (button, "clicked",
G_CALLBACK (paste_button_clicked), entry);
label = gtk_label_new ("Images can be transferred via the clipboard, too");
gtk_box_append (GTK_BOX (vbox), label);
gtk_container_add (GTK_CONTAINER (vbox), label);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
gtk_widget_set_margin_start (hbox, 8);
gtk_widget_set_margin_end (hbox, 8);
gtk_widget_set_margin_top (hbox, 8);
gtk_widget_set_margin_bottom (hbox, 8);
gtk_box_append (GTK_BOX (vbox), hbox);
g_object_set (hbox, "margin", 8, NULL);
gtk_container_add (GTK_CONTAINER (vbox), hbox);
/* Create the first image */
image = demo_image_new ("dialog-warning");
gtk_box_append (GTK_BOX (hbox), image);
image = gtk_image_new_from_icon_name ("dialog-warning");
gtk_container_add (GTK_CONTAINER (hbox), image);
/* make image a drag source */
gtk_drag_source_set (image, GDK_BUTTON1_MASK, NULL, GDK_ACTION_COPY);
gtk_drag_source_add_image_targets (image);
g_signal_connect (image, "drag-begin",
G_CALLBACK (drag_begin), image);
g_signal_connect (image, "drag-data-get",
G_CALLBACK (drag_data_get), image);
/* accept drops on image */
gtk_drag_dest_set (image, GTK_DEST_DEFAULT_ALL,
NULL, GDK_ACTION_COPY);
gtk_drag_dest_add_image_targets (image);
g_signal_connect (image, "drag-data-received",
G_CALLBACK (drag_data_received), image);
/* context menu on image */
gesture = gtk_gesture_click_new ();
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY);
g_signal_connect (gesture, "pressed", G_CALLBACK (pressed_cb), image);
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (gesture));
/* Create the second image */
image = demo_image_new ("process-stop");
gtk_box_append (GTK_BOX (hbox), image);
image = gtk_image_new_from_icon_name ("process-stop");
gtk_container_add (GTK_CONTAINER (hbox), image);
/* Create the third image */
image = demo_image_new ("weather-clear");
gtk_box_append (GTK_BOX (hbox), image);
/* make image a drag source */
gtk_drag_source_set (image, GDK_BUTTON1_MASK, NULL, GDK_ACTION_COPY);
gtk_drag_source_add_image_targets (image);
g_signal_connect (image, "drag-begin",
G_CALLBACK (drag_begin), image);
g_signal_connect (image, "drag-data-get",
G_CALLBACK (drag_data_get), image);
/* accept drops on image */
gtk_drag_dest_set (image, GTK_DEST_DEFAULT_ALL,
NULL, GDK_ACTION_COPY);
gtk_drag_dest_add_image_targets (image);
g_signal_connect (image, "drag-data-received",
G_CALLBACK (drag_data_received), image);
/* context menu on image */
gesture = gtk_gesture_click_new ();
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY);
g_signal_connect (gesture, "pressed", G_CALLBACK (pressed_cb), image);
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (gesture));
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

File diff suppressed because it is too large Load Diff

116
demos/gtk-demo/colorsel.c Normal file
View File

@@ -0,0 +1,116 @@
/* Color Chooser
*
* A GtkColorChooser lets the user choose a color. There are several
* implementations of the GtkColorChooser interface in GTK. The
* GtkColorChooserDialog is a prebuilt dialog containing a
* GtkColorChooserWidget.
*/
#include <gtk/gtk.h>
static GtkWidget *window = NULL;
static GtkWidget *da;
static GdkRGBA color;
static GtkWidget *frame;
/* draw callback for the drawing area
*/
static void
draw_function (GtkDrawingArea *da,
cairo_t *cr,
int width,
int height,
gpointer data)
{
gdk_cairo_set_source_rgba (cr, &color);
cairo_paint (cr);
}
static void
response_cb (GtkDialog *dialog,
gint response_id,
gpointer user_data)
{
if (response_id == GTK_RESPONSE_OK)
{
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (dialog), &color);
gtk_widget_queue_draw (da);
}
gtk_widget_destroy (GTK_WIDGET (dialog));
}
static void
change_color_callback (GtkWidget *button,
gpointer data)
{
GtkWidget *dialog;
dialog = gtk_color_chooser_dialog_new ("Changing color", GTK_WINDOW (window));
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (dialog), &color);
g_signal_connect (dialog, "response",
G_CALLBACK (response_cb), NULL);
gtk_widget_show (dialog);
}
GtkWidget *
do_colorsel (GtkWidget *do_widget)
{
GtkWidget *vbox;
GtkWidget *button;
if (!window)
{
color.red = 0;
color.blue = 1;
color.green = 0;
color.alpha = 1;
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), "Color Chooser");
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
g_object_set (vbox, "margin", 12, NULL);
gtk_container_add (GTK_CONTAINER (window), vbox);
/*
* Create the color swatch area
*/
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
gtk_container_add (GTK_CONTAINER (vbox), frame);
da = gtk_drawing_area_new ();
gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (da), 200);
gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (da), 200);
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_function, NULL, NULL);
gtk_container_add (GTK_CONTAINER (frame), da);
button = gtk_button_new_with_mnemonic ("_Change the above color");
gtk_widget_set_halign (button, GTK_ALIGN_END);
gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
gtk_container_add (GTK_CONTAINER (vbox), button);
g_signal_connect (button, "clicked",
G_CALLBACK (change_color_callback), NULL);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -19,7 +19,7 @@ enum
static GtkTreeModel *
create_icon_store (void)
{
const char *icon_names[6] = {
const gchar *icon_names[6] = {
"dialog-warning",
"process-stop",
"document-new",
@@ -27,7 +27,7 @@ create_icon_store (void)
NULL,
"document-open"
};
const char *labels[6] = {
const gchar *labels[6] = {
N_("Warning"),
N_("Stop"),
N_("New"),
@@ -111,8 +111,8 @@ static GtkTreeModel *
create_capital_store (void)
{
struct {
const char *group;
const char *capital;
gchar *group;
gchar *capital;
} capitals[] = {
{ "A - B", NULL },
{ NULL, "Albany" },
@@ -234,7 +234,7 @@ typedef struct _MaskEntry MaskEntry;
struct _MaskEntry
{
GtkEntry entry;
const char *mask;
gchar *mask;
};
typedef struct _MaskEntryClass MaskEntryClass;
@@ -246,7 +246,6 @@ struct _MaskEntryClass
static void mask_entry_editable_init (GtkEditableInterface *iface);
static GType mask_entry_get_type (void);
G_DEFINE_TYPE_WITH_CODE (MaskEntry, mask_entry, GTK_TYPE_ENTRY,
G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE,
mask_entry_editable_init));
@@ -311,36 +310,32 @@ do_combobox (GtkWidget *do_widget)
if (!window)
{
window = gtk_window_new ();
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), "Combo Boxes");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
gtk_widget_set_margin_start (vbox, 10);
gtk_widget_set_margin_end (vbox, 10);
gtk_widget_set_margin_top (vbox, 10);
gtk_widget_set_margin_bottom (vbox, 10);
gtk_window_set_child (GTK_WINDOW (window), vbox);
g_object_set (vbox, "margin", 10, NULL);
gtk_container_add (GTK_CONTAINER (window), vbox);
/* A combobox demonstrating cell renderers, separators and
* insensitive rows
*/
frame = gtk_frame_new ("Items with icons");
gtk_box_append (GTK_BOX (vbox), frame);
gtk_container_add (GTK_CONTAINER (vbox), frame);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_margin_start (box, 5);
gtk_widget_set_margin_end (box, 5);
gtk_widget_set_margin_top (box, 5);
gtk_widget_set_margin_bottom (box, 5);
gtk_frame_set_child (GTK_FRAME (frame), box);
g_object_set (box, "margin", 5, NULL);
gtk_container_add (GTK_CONTAINER (frame), box);
model = create_icon_store ();
combo = gtk_combo_box_new_with_model (model);
g_object_unref (model);
gtk_box_append (GTK_BOX (box), combo);
gtk_container_add (GTK_CONTAINER (box), combo);
renderer = gtk_cell_renderer_pixbuf_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, FALSE);
@@ -372,19 +367,16 @@ do_combobox (GtkWidget *do_widget)
/* A combobox demonstrating trees.
*/
frame = gtk_frame_new ("Where are we ?");
gtk_box_append (GTK_BOX (vbox), frame);
gtk_container_add (GTK_CONTAINER (vbox), frame);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_margin_start (box, 5);
gtk_widget_set_margin_end (box, 5);
gtk_widget_set_margin_top (box, 5);
gtk_widget_set_margin_bottom (box, 5);
gtk_frame_set_child (GTK_FRAME (frame), box);
g_object_set (box, "margin", 5, NULL);
gtk_container_add (GTK_CONTAINER (frame), box);
model = create_capital_store ();
combo = gtk_combo_box_new_with_model (model);
g_object_unref (model);
gtk_box_append (GTK_BOX (box), combo);
gtk_container_add (GTK_CONTAINER (box), combo);
renderer = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
@@ -403,52 +395,47 @@ do_combobox (GtkWidget *do_widget)
/* A GtkComboBoxEntry with validation */
frame = gtk_frame_new ("Editable");
gtk_box_append (GTK_BOX (vbox), frame);
gtk_container_add (GTK_CONTAINER (vbox), frame);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_margin_start (box, 5);
gtk_widget_set_margin_end (box, 5);
gtk_widget_set_margin_top (box, 5);
gtk_widget_set_margin_bottom (box, 5);
gtk_frame_set_child (GTK_FRAME (frame), box);
g_object_set (box, "margin", 5, NULL);
gtk_container_add (GTK_CONTAINER (frame), box);
combo = gtk_combo_box_text_new_with_entry ();
fill_combo_entry (combo);
gtk_box_append (GTK_BOX (box), combo);
gtk_container_add (GTK_CONTAINER (box), combo);
entry = g_object_new (TYPE_MASK_ENTRY, NULL);
MASK_ENTRY (entry)->mask = "^([0-9]*|One|Two|2\302\275|Three)$";
gtk_combo_box_set_child (GTK_COMBO_BOX (combo), entry);
gtk_container_remove (GTK_CONTAINER (combo), gtk_bin_get_child (GTK_BIN (combo)));
gtk_container_add (GTK_CONTAINER (combo), entry);
/* A combobox with string IDs */
frame = gtk_frame_new ("String IDs");
gtk_box_append (GTK_BOX (vbox), frame);
gtk_container_add (GTK_CONTAINER (vbox), frame);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_margin_start (box, 5);
gtk_widget_set_margin_end (box, 5);
gtk_widget_set_margin_top (box, 5);
gtk_widget_set_margin_bottom (box, 5);
gtk_frame_set_child (GTK_FRAME (frame), box);
g_object_set (box, "margin", 5, NULL);
gtk_container_add (GTK_CONTAINER (frame), box);
combo = gtk_combo_box_text_new ();
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "never", "Not visible");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "when-active", "Visible when active");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "always", "Always visible");
gtk_box_append (GTK_BOX (box), combo);
gtk_container_add (GTK_CONTAINER (box), combo);
entry = gtk_entry_new ();
g_object_bind_property (combo, "active-id",
entry, "text",
G_BINDING_BIDIRECTIONAL);
gtk_box_append (GTK_BOX (box), entry);
gtk_container_add (GTK_CONTAINER (box), entry);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -21,24 +21,23 @@ struct _SimpleGrid
G_DEFINE_TYPE (SimpleGrid, simple_grid, GTK_TYPE_WIDGET)
static void
simple_grid_dispose (GObject *object)
simple_grid_destroy (GtkWidget *widget)
{
SimpleGrid *self = SIMPLE_GRID (object);
SimpleGrid *self = SIMPLE_GRID (widget);
g_clear_pointer (&self->button1, gtk_widget_unparent);
g_clear_pointer (&self->button2, gtk_widget_unparent);
g_clear_pointer (&self->button3, gtk_widget_unparent);
g_clear_pointer (&self->button1, gtk_widget_destroy);
g_clear_pointer (&self->button2, gtk_widget_destroy);
g_clear_pointer (&self->button3, gtk_widget_destroy);
G_OBJECT_CLASS (simple_grid_parent_class)->dispose (object);
GTK_WIDGET_CLASS (simple_grid_parent_class)->destroy (widget);
}
static void
simple_grid_class_init (SimpleGridClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = simple_grid_dispose;
widget_class->destroy = simple_grid_destroy;
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_CONSTRAINT_LAYOUT);
}
@@ -256,34 +255,35 @@ do_constraints (GtkWidget *do_widget)
{
GtkWidget *header, *box, *grid, *button;
window = gtk_window_new ();
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), "Constraints");
header = gtk_header_bar_new ();
gtk_header_bar_set_title (GTK_HEADER_BAR (header), "Constraints");
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), FALSE);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_window_set_child (GTK_WINDOW (window), box);
gtk_container_add (GTK_CONTAINER (window), box);
grid = g_object_new (simple_grid_get_type (), NULL);
gtk_widget_set_hexpand (grid, TRUE);
gtk_widget_set_vexpand (grid, TRUE);
gtk_box_append (GTK_BOX (box), grid);
gtk_container_add (GTK_CONTAINER (box), grid);
button = gtk_button_new_with_label ("Close");
gtk_box_append (GTK_BOX (box), button);
gtk_container_add (GTK_CONTAINER (box), button);
gtk_widget_set_hexpand (grid, TRUE);
g_signal_connect_swapped (button, "clicked",
G_CALLBACK (gtk_window_destroy), window);
G_CALLBACK (gtk_widget_destroy), window);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,7 +1,7 @@
/* Constraints/Interactive
*
* Demonstrate how constraints can be updates during user interaction.
* The vertical edge between the buttons can be dragged with the mouse.
* Demonstrate how constraints can be updates during
* user interaction.
*/
#include <glib/gi18n.h>
@@ -22,24 +22,23 @@ struct _InteractiveGrid
G_DEFINE_TYPE (InteractiveGrid, interactive_grid, GTK_TYPE_WIDGET)
static void
interactive_grid_dispose (GObject *object)
interactive_grid_destroy (GtkWidget *widget)
{
InteractiveGrid *self = INTERACTIVE_GRID (object);
InteractiveGrid *self = INTERACTIVE_GRID (widget);
g_clear_pointer (&self->button1, gtk_widget_unparent);
g_clear_pointer (&self->button2, gtk_widget_unparent);
g_clear_pointer (&self->button3, gtk_widget_unparent);
g_clear_pointer (&self->button1, gtk_widget_destroy);
g_clear_pointer (&self->button2, gtk_widget_destroy);
g_clear_pointer (&self->button3, gtk_widget_destroy);
G_OBJECT_CLASS (interactive_grid_parent_class)->dispose (object);
GTK_WIDGET_CLASS (interactive_grid_parent_class)->destroy (widget);
}
static void
interactive_grid_class_init (InteractiveGridClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = interactive_grid_dispose;
widget_class->destroy = interactive_grid_destroy;
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_CONSTRAINT_LAYOUT);
}
@@ -212,34 +211,35 @@ do_constraints2 (GtkWidget *do_widget)
{
GtkWidget *header, *box, *grid, *button;
window = gtk_window_new ();
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), "Constraints");
header = gtk_header_bar_new ();
gtk_header_bar_set_title (GTK_HEADER_BAR (header), "Constraints");
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), FALSE);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_window_set_child (GTK_WINDOW (window), box);
gtk_container_add (GTK_CONTAINER (window), box);
grid = g_object_new (interactive_grid_get_type (), NULL);
gtk_widget_set_hexpand (grid, TRUE);
gtk_widget_set_vexpand (grid, TRUE);
gtk_box_append (GTK_BOX (box), grid);
gtk_container_add (GTK_CONTAINER (box), grid);
button = gtk_button_new_with_label ("Close");
gtk_box_append (GTK_BOX (box), button);
gtk_container_add (GTK_CONTAINER (box), button);
gtk_widget_set_hexpand (grid, TRUE);
g_signal_connect_swapped (button, "clicked",
G_CALLBACK (gtk_window_destroy), window);
G_CALLBACK (gtk_widget_destroy), window);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -20,24 +20,23 @@ struct _VflGrid
G_DEFINE_TYPE (VflGrid, vfl_grid, GTK_TYPE_WIDGET)
static void
vfl_grid_dispose (GObject *object)
vfl_grid_destroy (GtkWidget *widget)
{
VflGrid *self = VFL_GRID (object);
VflGrid *self = VFL_GRID (widget);
g_clear_pointer (&self->button1, gtk_widget_unparent);
g_clear_pointer (&self->button2, gtk_widget_unparent);
g_clear_pointer (&self->button3, gtk_widget_unparent);
g_clear_pointer (&self->button1, gtk_widget_destroy);
g_clear_pointer (&self->button2, gtk_widget_destroy);
g_clear_pointer (&self->button3, gtk_widget_destroy);
G_OBJECT_CLASS (vfl_grid_parent_class)->dispose (object);
GTK_WIDGET_CLASS (vfl_grid_parent_class)->destroy (widget);
}
static void
vfl_grid_class_init (VflGridClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = vfl_grid_dispose;
widget_class->destroy = vfl_grid_destroy;
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_CONSTRAINT_LAYOUT);
}
@@ -132,34 +131,35 @@ do_constraints3 (GtkWidget *do_widget)
{
GtkWidget *header, *box, *grid, *button;
window = gtk_window_new ();
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), "Constraints");
header = gtk_header_bar_new ();
gtk_header_bar_set_title (GTK_HEADER_BAR (header), "Constraints");
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), FALSE);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_window_set_child (GTK_WINDOW (window), box);
gtk_container_add (GTK_CONTAINER (window), box);
grid = g_object_new (vfl_grid_get_type (), NULL);
gtk_widget_set_hexpand (grid, TRUE);
gtk_widget_set_vexpand (grid, TRUE);
gtk_box_append (GTK_BOX (box), grid);
gtk_container_add (GTK_CONTAINER (box), grid);
button = gtk_button_new_with_label ("Close");
gtk_box_append (GTK_BOX (box), button);
gtk_container_add (GTK_CONTAINER (box), button);
gtk_widget_set_hexpand (grid, TRUE);
g_signal_connect_swapped (button, "clicked",
G_CALLBACK (gtk_window_destroy), window);
G_CALLBACK (gtk_widget_destroy), window);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -9,13 +9,9 @@
static void
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
{
GtkWidget *child;
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
apply_css (child, provider);
if (GTK_IS_CONTAINER (widget))
gtk_container_forall (GTK_CONTAINER (widget), (GtkCallback) apply_css, provider);
}
GtkWidget *
@@ -28,34 +24,35 @@ do_css_accordion (GtkWidget *do_widget)
GtkWidget *container, *child;
GtkStyleProvider *provider;
window = gtk_window_new ();
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "CSS Accordion");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 600, 300);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
container = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_halign (container, GTK_ALIGN_CENTER);
gtk_widget_set_valign (container, GTK_ALIGN_CENTER);
gtk_window_set_child (GTK_WINDOW (window), container);
gtk_container_add (GTK_CONTAINER (window), container);
child = gtk_button_new_with_label ("This");
gtk_box_append (GTK_BOX (container), child);
gtk_container_add (GTK_CONTAINER (container), child);
child = gtk_button_new_with_label ("Is");
gtk_box_append (GTK_BOX (container), child);
gtk_container_add (GTK_CONTAINER (container), child);
child = gtk_button_new_with_label ("A");
gtk_box_append (GTK_BOX (container), child);
gtk_container_add (GTK_CONTAINER (container), child);
child = gtk_button_new_with_label ("CSS");
gtk_box_append (GTK_BOX (container), child);
gtk_container_add (GTK_CONTAINER (container), child);
child = gtk_button_new_with_label ("Accordion");
gtk_box_append (GTK_BOX (container), child);
gtk_container_add (GTK_CONTAINER (container), child);
child = gtk_button_new_with_label (":-)");
gtk_box_append (GTK_BOX (container), child);
gtk_container_add (GTK_CONTAINER (container), child);
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
gtk_css_provider_load_from_resource (GTK_CSS_PROVIDER (provider), "/css_accordion/css_accordion.css");
@@ -66,7 +63,7 @@ do_css_accordion (GtkWidget *do_widget)
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -55,13 +55,9 @@ css_text_changed (GtkTextBuffer *buffer,
static void
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
{
GtkWidget *child;
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
apply_css (child, provider);
if (GTK_IS_CONTAINER (widget))
gtk_container_forall (GTK_CONTAINER (widget), (GtkCallback) apply_css, provider);
}
GtkWidget *
@@ -76,11 +72,12 @@ do_css_basics (GtkWidget *do_widget)
GtkTextBuffer *text;
GBytes *bytes;
window = gtk_window_new ();
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "CSS Basics");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
text = gtk_text_buffer_new (NULL);
gtk_text_buffer_create_tag (text,
@@ -94,10 +91,10 @@ do_css_basics (GtkWidget *do_widget)
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
container = gtk_scrolled_window_new ();
gtk_window_set_child (GTK_WINDOW (window), container);
container = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (window), container);
child = gtk_text_view_new_with_buffer (text);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (container), child);
gtk_container_add (GTK_CONTAINER (container), child);
g_signal_connect (text, "changed",
G_CALLBACK (css_text_changed), provider);
@@ -116,7 +113,7 @@ do_css_basics (GtkWidget *do_widget)
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -11,8 +11,8 @@
* These are the available blend modes.
*/
struct {
const char *name;
const char *id;
gchar *name;
gchar *id;
} blend_modes[] =
{
{ "Color", "color" },
@@ -79,7 +79,7 @@ setup_listbox (GtkBuilder *builder,
normal_row = NULL;
listbox = gtk_list_box_new ();
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (WID ("scrolledwindow")), listbox);
gtk_container_add (GTK_CONTAINER (WID ("scrolledwindow")), listbox);
g_signal_connect (listbox, "row-activated", G_CALLBACK (row_activated), provider);
@@ -95,8 +95,9 @@ setup_listbox (GtkBuilder *builder,
"xalign", 0.0,
NULL);
gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), label);
gtk_list_box_insert (GTK_LIST_BOX (listbox), row, -1);
gtk_container_add (GTK_CONTAINER (row), label);
gtk_container_add (GTK_CONTAINER (listbox), row);
/* The first selected row is "normal" */
if (g_strcmp0 (blend_modes[i].id, "normal") == 0)
@@ -124,7 +125,7 @@ do_css_blendmodes (GtkWidget *do_widget)
window = WID ("window");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window);
/* Setup the CSS provider for window */
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
@@ -134,14 +135,12 @@ do_css_blendmodes (GtkWidget *do_widget)
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
setup_listbox (builder, provider);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -69,13 +69,9 @@ drawing_area_draw (GtkDrawingArea *da,
static void
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
{
GtkWidget *child;
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
apply_css (child, provider);
if (GTK_IS_CONTAINER (widget))
gtk_container_forall (GTK_CONTAINER (widget), (GtkCallback) apply_css, provider);
}
GtkWidget *
@@ -85,40 +81,41 @@ do_css_multiplebgs (GtkWidget *do_widget)
if (!window)
{
GtkWidget *paned, *overlay, *child, *sw;
GtkWidget *paned, *container, *child;
GtkStyleProvider *provider;
GtkTextBuffer *text;
GBytes *bytes;
window = gtk_window_new ();
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Multiple Backgrounds");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
overlay = gtk_overlay_new ();
gtk_window_set_child (GTK_WINDOW (window), overlay);
container = gtk_overlay_new ();
gtk_container_add (GTK_CONTAINER (window), container);
child = gtk_drawing_area_new ();
gtk_widget_set_name (child, "canvas");
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (child),
drawing_area_draw,
NULL, NULL);
gtk_overlay_set_child (GTK_OVERLAY (overlay), child);
gtk_container_add (GTK_CONTAINER (container), child);
child = gtk_button_new ();
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), child);
gtk_overlay_add_overlay (GTK_OVERLAY (container), child);
gtk_widget_set_name (child, "bricks-button");
gtk_widget_set_halign (child, GTK_ALIGN_CENTER);
gtk_widget_set_valign (child, GTK_ALIGN_CENTER);
gtk_widget_set_size_request (child, 250, 84);
paned = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), paned);
gtk_overlay_add_overlay (GTK_OVERLAY (container), paned);
/* Need a filler so we get a handle */
child = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_paned_set_start_child (GTK_PANED (paned), child);
gtk_container_add (GTK_CONTAINER (paned), child);
text = gtk_text_buffer_new (NULL);
gtk_text_buffer_create_tag (text,
@@ -132,10 +129,10 @@ do_css_multiplebgs (GtkWidget *do_widget)
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
sw = gtk_scrolled_window_new ();
gtk_paned_set_end_child (GTK_PANED (paned), sw);
container = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (paned), container);
child = gtk_text_view_new_with_buffer (text);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child);
gtk_container_add (GTK_CONTAINER (container), child);
g_signal_connect (text,
"changed",
G_CALLBACK (css_text_changed),
@@ -156,7 +153,7 @@ do_css_multiplebgs (GtkWidget *do_widget)
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -55,13 +55,9 @@ css_text_changed (GtkTextBuffer *buffer,
static void
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
{
GtkWidget *child;
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
apply_css (child, provider);
if (GTK_IS_CONTAINER (widget))
gtk_container_forall (GTK_CONTAINER (widget), (GtkCallback) apply_css, provider);
}
GtkWidget *
@@ -76,18 +72,19 @@ do_css_pixbufs (GtkWidget *do_widget)
GtkTextBuffer *text;
GBytes *bytes;
window = gtk_window_new ();
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Animated Backgrounds");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
paned = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
gtk_window_set_child (GTK_WINDOW (window), paned);
gtk_container_add (GTK_CONTAINER (window), paned);
/* Need a filler so we get a handle */
child = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_paned_set_start_child (GTK_PANED (paned), child);
gtk_container_add (GTK_CONTAINER (paned), child);
text = gtk_text_buffer_new (NULL);
gtk_text_buffer_create_tag (text,
@@ -101,10 +98,10 @@ do_css_pixbufs (GtkWidget *do_widget)
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
container = gtk_scrolled_window_new ();
gtk_paned_set_end_child (GTK_PANED (paned), container);
container = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (paned), container);
child = gtk_text_view_new_with_buffer (text);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (container), child);
gtk_container_add (GTK_CONTAINER (container), child);
g_signal_connect (text, "changed",
G_CALLBACK (css_text_changed), provider);
@@ -123,7 +120,7 @@ do_css_pixbufs (GtkWidget *do_widget)
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -53,32 +53,31 @@ css_text_changed (GtkTextBuffer *buffer,
static void
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
{
GtkWidget *child;
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
apply_css (child, provider);
if (GTK_IS_CONTAINER (widget))
gtk_container_forall (GTK_CONTAINER (widget), (GtkCallback) apply_css, provider);
}
static GtkWidget *
GtkWidget *
create_toolbar (void)
{
GtkWidget *toolbar;
GtkWidget *item;
GtkToolItem *item;
toolbar = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
toolbar = gtk_toolbar_new ();
gtk_widget_set_valign (toolbar, GTK_ALIGN_CENTER);
item = gtk_button_new_from_icon_name ("go-next");
gtk_box_append (GTK_BOX (toolbar), item);
item = gtk_tool_button_new (NULL, NULL);
gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item), "go-next");
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
item = gtk_button_new_from_icon_name ("go-previous");
gtk_box_append (GTK_BOX (toolbar), item);
item = gtk_tool_button_new (NULL, NULL);
gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item), "go-previous");
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
item = gtk_button_new_with_label ("Hello World");
gtk_box_append (GTK_BOX (toolbar), item);
item = gtk_tool_button_new (NULL, "Hello World");
gtk_tool_item_set_is_important (item, TRUE);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
return toolbar;
}
@@ -95,17 +94,18 @@ do_css_shadows (GtkWidget *do_widget)
GtkTextBuffer *text;
GBytes *bytes;
window = gtk_window_new ();
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Shadows");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
paned = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
gtk_window_set_child (GTK_WINDOW (window), paned);
gtk_container_add (GTK_CONTAINER (window), paned);
child = create_toolbar ();
gtk_paned_set_start_child (GTK_PANED (paned), child);
gtk_container_add (GTK_CONTAINER (paned), child);
text = gtk_text_buffer_new (NULL);
gtk_text_buffer_create_tag (text,
@@ -119,10 +119,10 @@ do_css_shadows (GtkWidget *do_widget)
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
container = gtk_scrolled_window_new ();
gtk_paned_set_end_child (GTK_PANED (paned), container);
container = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (paned), container);
child = gtk_text_view_new_with_buffer (text);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (container), child);
gtk_container_add (GTK_CONTAINER (container), child);
g_signal_connect (text, "changed",
G_CALLBACK (css_text_changed), provider);
@@ -141,7 +141,7 @@ do_css_shadows (GtkWidget *do_widget)
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,8 +1,9 @@
/* Cursors
*
* Demonstrates a useful set of available cursors. The cursors shown here are the
* ones defined by CSS, which we assume to be available. The example shows creating
* cursors by name or from an image, with or without a fallback.
* Demonstrates a useful set of available cursors. The cursors shown here are the ones
* defined by CSS, which we assume to be available.
*
* The example shows creating cursors by name or from an image, with or without a fallback.
*/
#include <gtk/gtk.h>
@@ -28,14 +29,14 @@ do_cursors (GtkWidget *do_widget)
gtk_widget_get_display (do_widget));
g_signal_connect (window, "destroy",
G_CALLBACK (on_destroy), NULL);
g_object_unref (builder);
g_object_set_data_full (G_OBJECT (window), "builder", builder, g_object_unref);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
{
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
}
return window;

View File

@@ -656,10 +656,7 @@
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="margin-start">60</property>
<property name="margin-end">60</property>
<property name="margin-top">60</property>
<property name="margin-bottom">60</property>
<property name="margin">60</property>
<property name="spacing">10</property>
<property name="halign">center</property>
<child>
@@ -675,10 +672,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -735,10 +729,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -795,10 +786,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -868,10 +856,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -928,10 +913,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -988,10 +970,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -1048,10 +1027,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -1108,10 +1084,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -1181,10 +1154,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -1241,10 +1211,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -1301,10 +1268,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -1361,10 +1325,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -1434,10 +1395,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -1494,10 +1452,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -1554,10 +1509,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -1614,10 +1566,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -1674,10 +1623,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -1734,10 +1680,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -1794,10 +1737,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -1867,10 +1807,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -1927,10 +1864,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -1987,10 +1921,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -2047,10 +1978,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -2107,10 +2035,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -2167,10 +2092,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -2227,10 +2149,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -2287,10 +2206,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -2347,10 +2263,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -2407,10 +2320,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -2467,10 +2377,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -2527,10 +2434,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -2587,10 +2491,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -2647,10 +2548,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -2707,10 +2605,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -2780,10 +2675,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
@@ -2840,10 +2732,7 @@
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">

View File

@@ -1,23 +1,24 @@
<?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">
<file>application.c</file>
<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>
<gresource prefix="/clipboard">
<file>demoimage.c</file>
<file>demoimage.h</file>
</gresource>
<gresource prefix="/css_accordion">
<file>css_accordion.css</file>
<file>reset.css</file>
@@ -105,18 +106,11 @@
<file>zoom_in_cursor.png</file>
<file>zoom_out_cursor.png</file>
</gresource>
<gresource prefix="/dnd">
<file>dnd.css</file>
</gresource>
<gresource prefix="/fishbowl">
<file>fishbowl.ui</file>
<file>gtkfishbowl.c</file>
<file>gtkfishbowl.h</file>
</gresource>
<gresource prefix="/gears">
<file>gtkgears.c</file>
<file>gtkgears.h</file>
</gresource>
<gresource prefix="/iconscroll">
<file>iconscroll.ui</file>
</gresource>
@@ -126,7 +120,6 @@
</gresource>
<gresource prefix="/listview_filebrowser">
<file>listview_filebrowser.ui</file>
<file>listview_filebrowser.css</file>
</gresource>
<gresource prefix="/listview_minesweeper">
<file>listview_minesweeper.ui</file>
@@ -138,10 +131,6 @@
<gresource prefix="/listview_weather">
<file compressed="true">listview_weather.txt</file>
</gresource>
<gresource prefix="/listview_colors">
<file compressed="true">color.names.txt</file>
<file>listview_colors.css</file>
</gresource>
<gresource prefix="/shortcuts">
<file>shortcuts.ui</file>
<file>shortcuts-builder.ui</file>
@@ -178,9 +167,12 @@
</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>
<file>clipboard.c</file>
<file>colorsel.c</file>
<file>combobox.c</file>
<file>constraints.c</file>
<file>constraints2.c</file>
@@ -194,7 +186,6 @@
<file>cursors.c</file>
<file>dialog.c</file>
<file>drawingarea.c</file>
<file>dropdown.c</file>
<file>dnd.c</file>
<file>editable_cells.c</file>
<file>entry_completion.c</file>
@@ -204,10 +195,10 @@
<file>fishbowl.c</file>
<file>fixed.c</file>
<file>flowbox.c</file>
<file>foreigndrawing.c</file>
<file>font_features.c</file>
<file>fontplane.c</file>
<file>fontrendering.c</file>
<file>gears.c</file>
<file>gestures.c</file>
<file>glarea.c</file>
<file>headerbar.c</file>
@@ -220,15 +211,14 @@
<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>listview_words.c</file>
<file>list_store.c</file>
<file>markup.c</file>
<file>menus.c</file>
<file>modelbutton.c</file>
<file>overlay.c</file>
<file>overlay2.c</file>
@@ -239,9 +229,9 @@
<file>paintable_mediastream.c</file>
<file>panes.c</file>
<file>password_entry.c</file>
<file>peg_solitaire.c</file>
<file>pickers.c</file>
<file>pixbufs.c</file>
<file>popover.c</file>
<file>printing.c</file>
<file>revealer.c</file>
<file>rotated_text.c</file>
@@ -249,7 +239,6 @@
<file>search_entry.c</file>
<file>search_entry2.c</file>
<file>shortcuts.c</file>
<file>shortcut_triggers.c</file>
<file>sizegroup.c</file>
<file>sidebar.c</file>
<file>sliding_puzzle.c</file>
@@ -279,6 +268,9 @@
<file>messages.txt</file>
<file>apple-red.png</file>
</gresource>
<gresource prefix="/popover">
<file>popover.ui</file>
</gresource>
<gresource prefix="/glarea">
<file>glarea-gl.fs.glsl</file>
<file>glarea-gl.vs.glsl</file>
@@ -301,7 +293,6 @@
</gresource>
<gresource prefix="/transparent">
<file>portland-rose.jpg</file>
<file>bluroverlay.h</file>
<file>bluroverlay.c</file>
</gresource>
<gresource prefix="/markup">
@@ -313,6 +304,9 @@
<gresource prefix="/modelbutton">
<file>modelbutton.ui</file>
</gresource>
<gresource prefix="/dnd">
<file>dnd.css</file>
</gresource>
<gresource prefix="/tagged_entry">
<file>demotaggedentry.c</file>
<file>demotaggedentry.h</file>
@@ -342,7 +336,4 @@
<file>icons/16x16/status/battery-caution-charging-symbolic.symbolic.png</file>
<file>icons/16x16/categories/applications-other.png</file>
</gresource>
<gresource prefix="/org/gtk/Demo4/gtk">
<file preprocess="xml-stripblanks">help-overlay.ui</file>
</gresource>
</gresources>

View File

@@ -22,79 +22,9 @@
</row>
</data>
</object>
<menu id="menubar">
<submenu>
<attribute name="label" translatable="yes">_File</attribute>
<section>
<item>
<attribute name="label" translatable="yes">_New</attribute>
<attribute name="action">win.new</attribute>
<attribute name="accel">&lt;Control&gt;n</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Open</attribute>
<attribute name="action">win.open</attribute>
<attribute name="accel">&lt;Control&gt;o</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Save</attribute>
<attribute name="action">win.save</attribute>
<attribute name="accel">&lt;Control&gt;s</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Save _As</attribute>
<attribute name="action">win.save-as</attribute>
<attribute name="accel">&lt;Control&gt;q</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">_Quit</attribute>
<attribute name="action">win.quit</attribute>
<attribute name="accel">&lt;Control&gt;&lt;Shift&gt;s</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">_Edit</attribute>
<section>
<item>
<attribute name="label" translatable="yes">_Copy</attribute>
<attribute name="action">win.copy</attribute>
<attribute name="accel">&lt;Control&gt;c</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Cut</attribute>
<attribute name="action">win.cut</attribute>
<attribute name="accel">&lt;Control&gt;x</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Paste</attribute>
<attribute name="action">win.paste</attribute>
<attribute name="accel">&lt;Control&gt;v</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">_Help</attribute>
<section>
<item>
<attribute name="label" translatable="yes">_Help</attribute>
<attribute name="action">win.help</attribute>
<attribute name="accel">F1</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_About</attribute>
<attribute name="action">win.about</attribute>
<attribute name="accel">F7</attribute>
</item>
</section>
</submenu>
</menu>
<object class="GtkAboutDialog" id="aboutdialog1">
<property name="program-name" translatable="yes">Builder demo</property>
<property name="logo-icon-name" translatable="yes">gtk3-demo</property>
<property name="modal">True</property>
<accessibility>
<relation target="window1" type="subwindow-of"/>
</accessibility>
@@ -107,57 +37,159 @@
<object class="GtkBox" id="vbox1">
<property name="orientation">vertical</property>
<child>
<object class="GtkPopoverMenuBar" id="menubar1">
<property name="menu-model">menubar</property>
<object class="GtkMenuBar" id="menubar1">
<child internal-child="accessible">
<object class="AtkObject" id="a11y-menubar">
<property name="AtkObject::accessible-name">The menubar</property>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="label" translatable="yes">_File</property>
<property name="use-underline">1</property>
<child type="submenu">
<object class="GtkMenu">
<child>
<object class="GtkMenuItem" id="new_item">
<property name="label" translatable="yes">_New</property>
<property name="use-underline">1</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="open_item">
<property name="label" translatable="yes">_Open</property>
<property name="use-underline">1</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="save_item">
<property name="label" translatable="yes">_Save</property>
<property name="use-underline">1</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="save_as_item">
<property name="label" translatable="yes">Save _As</property>
<property name="use-underline">1</property>
<accelerator key="s" modifiers="primary | shift-mask" signal="activate"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem"/>
</child>
<child>
<object class="GtkMenuItem" id="quit_item">
<property name="label" translatable="yes">_Quit</property>
<property name="use-underline">1</property>
<property name="action-name">win.quit</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="label" translatable="yes">_Edit</property>
<property name="use-underline">1</property>
<child type="submenu">
<object class="GtkMenu">
<child>
<object class="GtkMenuItem" id="copy_item">
<property name="label" translatable="yes">_Copy</property>
<property name="use-underline">1</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="cut_item">
<property name="label" translatable="yes">_Cut</property>
<property name="use-underline">1</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="paste_item">
<property name="label" translatable="yes">_Paste</property>
<property name="use-underline">1</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="label" translatable="yes">_Help</property>
<property name="use-underline">1</property>
<child type="submenu">
<object class="GtkMenu">
<child>
<object class="GtkMenuItem" id="help_item">
<property name="label" translatable="yes">_Help</property>
<property name="use-underline">1</property>
<property name="action-name">win.help</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="about_item">
<property name="label" translatable="yes">_About</property>
<property name="use-underline">1</property>
<property name="action-name">win.about</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="toolbar1">
<object class="GtkToolbar" id="toolbar1">
<child internal-child="accessible">
<object class="AtkObject" id="a11y-toolbar">
<property name="AtkObject::accessible-name">The toolbar</property>
</object>
</child>
<child>
<object class="GtkButton">
<object class="GtkToolButton">
<property name="label" translatable="yes">New</property>
<property name="tooltip-text" translatable="yes">Create a new file</property>
<property name="icon-name">document-new</property>
</object>
</child>
<child>
<object class="GtkButton">
<object class="GtkToolButton">
<property name="label" translatable="yes">Open</property>
<property name="tooltip-text" translatable="yes">Open a file</property>
<property name="icon-name">document-open</property>
</object>
</child>
<child>
<object class="GtkButton">
<object class="GtkToolButton">
<property name="label" translatable="yes">Save</property>
<property name="tooltip-text" translatable="yes">Save a file</property>
<property name="icon-name">document-save</property>
<property name="is-important">1</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
<object class="GtkSeparatorToolItem"/>
</child>
<child>
<object class="GtkButton">
<object class="GtkToolButton">
<property name="label" translatable="yes">Copy</property>
<property name="tooltip-text" translatable="yes">Copy selected object into the clipboard</property>
<property name="icon-name">edit-copy</property>
</object>
</child>
<child>
<object class="GtkButton">
<object class="GtkToolButton">
<property name="label" translatable="yes">Cut</property>
<property name="tooltip-text" translatable="yes">Cut selected object into the clipboard</property>
<property name="icon-name">edit-cut</property>
</object>
</child>
<child>
<object class="GtkButton">
<object class="GtkToolButton">
<property name="label" translatable="yes">Paste</property>
<property name="tooltip-text" translatable="yes">Paste object from the clipboard</property>
<property name="icon-name">edit-paste</property>
@@ -167,9 +199,8 @@
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="has-frame">1</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<property name="shadow-type">in</property>
<property name="expand">1</property>
<child>
<object class="GtkTreeView" id="treeview1">
<property name="model">liststore1</property>

View File

@@ -1,259 +0,0 @@
#include "demoimage.h"
#include <glib/gi18n.h>
struct _DemoImage {
GtkWidget parent_instance;
GtkWidget *image;
GtkWidget *popover;
};
enum {
PROP_ICON_NAME = 1
};
G_DEFINE_TYPE(DemoImage, demo_image, GTK_TYPE_WIDGET)
static GdkPaintable *
get_image_paintable (GtkImage *image)
{
const gchar *icon_name;
GtkIconTheme *icon_theme;
GtkIconPaintable *icon;
switch (gtk_image_get_storage_type (image))
{
case GTK_IMAGE_PAINTABLE:
return g_object_ref (gtk_image_get_paintable (image));
case GTK_IMAGE_ICON_NAME:
icon_name = gtk_image_get_icon_name (image);
icon_theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (GTK_WIDGET (image)));
icon = gtk_icon_theme_lookup_icon (icon_theme,
icon_name,
NULL,
48, 1,
gtk_widget_get_direction (GTK_WIDGET (image)),
0);
if (icon == NULL)
return NULL;
return GDK_PAINTABLE (icon);
case GTK_IMAGE_EMPTY:
case GTK_IMAGE_GICON:
default:
g_warning ("Image storage type %d not handled",
gtk_image_get_storage_type (image));
return NULL;
}
}
static void
drag_begin (GtkDragSource *source,
GdkDrag *drag,
gpointer data)
{
GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
DemoImage *demo = DEMO_IMAGE (widget);
GdkPaintable *paintable;
paintable = get_image_paintable (GTK_IMAGE (demo->image));
if (paintable)
{
gtk_drag_icon_set_from_paintable (drag, paintable, -2, -2);
g_object_unref (paintable);
}
}
static GdkContentProvider *
prepare_drag (GtkDragSource *source,
double x,
double y,
gpointer data)
{
GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
DemoImage *demo = DEMO_IMAGE (widget);
GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (demo->image));
return gdk_content_provider_new_typed (GDK_TYPE_PAINTABLE, paintable);
}
static gboolean
drag_drop (GtkDropTarget *dest,
const GValue *value,
double x,
double y,
gpointer data)
{
GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
DemoImage *demo = DEMO_IMAGE (widget);
GdkPaintable *paintable = g_value_get_object (value);
gtk_image_set_from_paintable (GTK_IMAGE (demo->image), paintable);
return TRUE;
}
static void
copy_image (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
GdkClipboard *clipboard = gtk_widget_get_clipboard (widget);
DemoImage *demo = DEMO_IMAGE (widget);
GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (demo->image));
GValue value = G_VALUE_INIT;
g_value_init (&value, GDK_TYPE_PAINTABLE);
g_value_set_object (&value, paintable);
gdk_clipboard_set_value (clipboard, &value);
g_value_unset (&value);
if (paintable)
g_object_unref (paintable);
}
static void
paste_image (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
GdkClipboard *clipboard = gtk_widget_get_clipboard (widget);
DemoImage *demo = DEMO_IMAGE (widget);
GdkContentProvider *content = gdk_clipboard_get_content (clipboard);
GValue value = G_VALUE_INIT;
GdkPaintable *paintable;
g_value_init (&value, GDK_TYPE_PAINTABLE);
if (!gdk_content_provider_get_value (content, &value, NULL))
return;
paintable = GDK_PAINTABLE (g_value_get_object (&value));
gtk_image_set_from_paintable (GTK_IMAGE (demo->image), paintable);
g_value_unset (&value);
}
static void
pressed_cb (GtkGesture *gesture,
int n_press,
double x,
double y,
gpointer data)
{
DemoImage *demo = DEMO_IMAGE (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)));
gtk_popover_popup (GTK_POPOVER (demo->popover));
}
static void
demo_image_init (DemoImage *demo)
{
GMenu *menu;
GMenuItem *item;
GtkDragSource *source;
GtkDropTarget *dest;
GtkGesture *gesture;
demo->image = gtk_image_new ();
gtk_image_set_pixel_size (GTK_IMAGE (demo->image), 48);
gtk_widget_set_parent (demo->image, GTK_WIDGET (demo));
menu = g_menu_new ();
item = g_menu_item_new (_("_Copy"), "clipboard.copy");
g_menu_append_item (menu, item);
item = g_menu_item_new (_("_Paste"), "clipboard.paste");
g_menu_append_item (menu, item);
demo->popover = gtk_popover_menu_new_from_model (G_MENU_MODEL (menu));
gtk_widget_set_parent (demo->popover, GTK_WIDGET (demo));
source = gtk_drag_source_new ();
g_signal_connect (source, "prepare", G_CALLBACK (prepare_drag), NULL);
g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), NULL);
gtk_widget_add_controller (GTK_WIDGET (demo), GTK_EVENT_CONTROLLER (source));
dest = gtk_drop_target_new (GDK_TYPE_PAINTABLE, GDK_ACTION_COPY);
g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), NULL);
gtk_widget_add_controller (GTK_WIDGET (demo), GTK_EVENT_CONTROLLER (dest));
gesture = gtk_gesture_click_new ();
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY);
g_signal_connect (gesture, "pressed", G_CALLBACK (pressed_cb), NULL);
gtk_widget_add_controller (GTK_WIDGET (demo), GTK_EVENT_CONTROLLER (gesture));
}
static void
demo_image_dispose (GObject *object)
{
DemoImage *demo = DEMO_IMAGE (object);
g_clear_pointer (&demo->image, gtk_widget_unparent);
g_clear_pointer (&demo->popover, gtk_widget_unparent);
G_OBJECT_CLASS (demo_image_parent_class)->dispose (object);
}
static void
demo_image_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
DemoImage *demo = DEMO_IMAGE (object);
switch (prop_id)
{
case PROP_ICON_NAME:
g_value_set_string (value, gtk_image_get_icon_name (GTK_IMAGE (demo->image)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
demo_image_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
DemoImage *demo = DEMO_IMAGE (object);
switch (prop_id)
{
case PROP_ICON_NAME:
gtk_image_set_from_icon_name (GTK_IMAGE (demo->image),
g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
demo_image_class_init (DemoImageClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->dispose = demo_image_dispose;
object_class->get_property = demo_image_get_property;
object_class->set_property = demo_image_set_property;
g_object_class_install_property (object_class, PROP_ICON_NAME,
g_param_spec_string ("icon-name", "Icon name", "Icon name",
NULL, G_PARAM_READWRITE));
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
gtk_widget_class_install_action (widget_class, "clipboard.copy", NULL, copy_image);
gtk_widget_class_install_action (widget_class, "clipboard.paste", NULL, paste_image);
}
GtkWidget *
demo_image_new (const char *icon_name)
{
return g_object_new (DEMO_TYPE_IMAGE, "icon-name", icon_name, NULL);
}

View File

@@ -1,13 +0,0 @@
#pragma once
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define DEMO_TYPE_IMAGE (demo_image_get_type ())
G_DECLARE_FINAL_TYPE(DemoImage, demo_image, DEMO, IMAGE, GtkWidget)
GtkWidget * demo_image_new (const char *icon_name);
G_END_DECLS

View File

@@ -25,36 +25,31 @@
#include <gtk/gtk.h>
#include <gtk/gtk-a11y.h>
struct _DemoTaggedEntry
{
GtkWidget parent_instance;
typedef struct {
GtkWidget *box;
GtkWidget *entry;
};
struct _DemoTaggedEntryClass
{
GtkWidgetClass parent_class;
};
} DemoTaggedEntryPrivate;
static void demo_tagged_entry_editable_init (GtkEditableInterface *iface);
G_DEFINE_TYPE_WITH_CODE (DemoTaggedEntry, demo_tagged_entry, GTK_TYPE_WIDGET,
G_ADD_PRIVATE (DemoTaggedEntry)
G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE, demo_tagged_entry_editable_init))
static void
demo_tagged_entry_init (DemoTaggedEntry *entry)
{
entry->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_parent (entry->box, GTK_WIDGET (entry));
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
entry->entry = gtk_text_new ();
gtk_widget_set_hexpand (entry->entry, TRUE);
gtk_widget_set_vexpand (entry->entry, TRUE);
gtk_widget_set_hexpand (entry->box, FALSE);
gtk_widget_set_vexpand (entry->box, FALSE);
gtk_box_append (GTK_BOX (entry->box), entry->entry);
priv->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_parent (priv->box, GTK_WIDGET (entry));
priv->entry = gtk_text_new ();
gtk_widget_set_hexpand (priv->entry, TRUE);
gtk_widget_set_vexpand (priv->entry, TRUE);
gtk_widget_set_hexpand (priv->box, FALSE);
gtk_widget_set_vexpand (priv->box, FALSE);
gtk_container_add (GTK_CONTAINER (priv->box), priv->entry);
gtk_editable_init_delegate (GTK_EDITABLE (entry));
}
@@ -62,16 +57,23 @@ static void
demo_tagged_entry_dispose (GObject *object)
{
DemoTaggedEntry *entry = DEMO_TAGGED_ENTRY (object);
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
if (entry->entry)
if (priv->entry)
gtk_editable_finish_delegate (GTK_EDITABLE (entry));
g_clear_pointer (&entry->entry, gtk_widget_unparent);
g_clear_pointer (&entry->box, gtk_widget_unparent);
g_clear_pointer (&priv->entry, gtk_widget_unparent);
g_clear_pointer (&priv->box, gtk_widget_unparent);
G_OBJECT_CLASS (demo_tagged_entry_parent_class)->dispose (object);
}
static void
demo_tagged_entry_finalize (GObject *object)
{
G_OBJECT_CLASS (demo_tagged_entry_parent_class)->finalize (object);
}
static void
demo_tagged_entry_set_property (GObject *object,
guint prop_id,
@@ -96,12 +98,44 @@ demo_tagged_entry_get_property (GObject *object,
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
static void
demo_tagged_entry_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
DemoTaggedEntry *entry = DEMO_TAGGED_ENTRY (widget);
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
gtk_widget_measure (priv->box, orientation, for_size,
minimum, natural,
minimum_baseline, natural_baseline);
}
static void
demo_tagged_entry_size_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
{
DemoTaggedEntry *entry = DEMO_TAGGED_ENTRY (widget);
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
gtk_widget_size_allocate (priv->box,
&(GtkAllocation) { 0, 0, width, height },
baseline);
}
static gboolean
demo_tagged_entry_grab_focus (GtkWidget *widget)
{
DemoTaggedEntry *entry = DEMO_TAGGED_ENTRY (widget);
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
return gtk_widget_grab_focus (entry->entry);
return gtk_widget_grab_focus (priv->entry);
}
static void
@@ -111,14 +145,16 @@ demo_tagged_entry_class_init (DemoTaggedEntryClass *klass)
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = demo_tagged_entry_dispose;
object_class->finalize = demo_tagged_entry_finalize;
object_class->get_property = demo_tagged_entry_get_property;
object_class->set_property = demo_tagged_entry_set_property;
widget_class->measure = demo_tagged_entry_measure;
widget_class->size_allocate = demo_tagged_entry_size_allocate;
widget_class->grab_focus = demo_tagged_entry_grab_focus;
gtk_editable_install_properties (object_class, 1);
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_ENTRY_ACCESSIBLE);
gtk_widget_class_set_css_name (widget_class, "entry");
}
@@ -126,7 +162,10 @@ demo_tagged_entry_class_init (DemoTaggedEntryClass *klass)
static GtkEditable *
demo_tagged_entry_get_delegate (GtkEditable *editable)
{
return GTK_EDITABLE (DEMO_TAGGED_ENTRY (editable)->entry);
DemoTaggedEntry *entry = DEMO_TAGGED_ENTRY (editable);
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
return GTK_EDITABLE (priv->entry);
}
static void
@@ -145,9 +184,11 @@ void
demo_tagged_entry_add_tag (DemoTaggedEntry *entry,
GtkWidget *tag)
{
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
g_return_if_fail (DEMO_IS_TAGGED_ENTRY (entry));
gtk_box_append (GTK_BOX (entry->box), tag);
gtk_container_add (GTK_CONTAINER (priv->box), tag);
}
void
@@ -155,27 +196,30 @@ demo_tagged_entry_insert_tag_after (DemoTaggedEntry *entry,
GtkWidget *tag,
GtkWidget *sibling)
{
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
g_return_if_fail (DEMO_IS_TAGGED_ENTRY (entry));
if (sibling == NULL)
gtk_box_append (GTK_BOX (entry->box), tag);
gtk_container_add (GTK_CONTAINER (priv->box), tag);
else
gtk_box_insert_child_after (GTK_BOX (entry->box), tag, sibling);
gtk_box_insert_child_after (GTK_BOX (priv->box), tag, sibling);
}
void
demo_tagged_entry_remove_tag (DemoTaggedEntry *entry,
GtkWidget *tag)
{
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
g_return_if_fail (DEMO_IS_TAGGED_ENTRY (entry));
gtk_box_remove (GTK_BOX (entry->box), tag);
gtk_container_remove (GTK_CONTAINER (priv->box), tag);
}
struct _DemoTaggedEntryTag
{
GtkWidget parent;
GtkWidget *box;
GtkWidget *label;
GtkWidget *button;
@@ -206,11 +250,11 @@ static guint signals[LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE (DemoTaggedEntryTag, demo_tagged_entry_tag, GTK_TYPE_WIDGET)
static void
on_released (GtkGestureClick *gesture,
int n_press,
double x,
double y,
DemoTaggedEntryTag *tag)
on_released (GtkGestureClick *gesture,
int n_press,
double x,
double y,
DemoTaggedEntryTag *tag)
{
g_signal_emit (tag, signals[SIGNAL_CLICKED], 0);
}
@@ -224,7 +268,7 @@ demo_tagged_entry_tag_init (DemoTaggedEntryTag *tag)
tag->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_parent (tag->box, GTK_WIDGET (tag));
tag->label = gtk_label_new ("");
gtk_box_append (GTK_BOX (tag->box), tag->label);
gtk_container_add (GTK_CONTAINER (tag->box), tag->label);
gesture = gtk_gesture_click_new ();
g_signal_connect (gesture, "released", G_CALLBACK (on_released), tag);
@@ -416,7 +460,7 @@ demo_tagged_entry_tag_set_has_close_button (DemoTaggedEntryTag *tag,
if (!has_close_button && tag->button)
{
gtk_box_remove (GTK_BOX (tag->box), tag->button);
gtk_container_remove (GTK_CONTAINER (tag->box), tag->button);
tag->button = NULL;
}
else if (has_close_button && tag->button == NULL)
@@ -425,11 +469,11 @@ demo_tagged_entry_tag_set_has_close_button (DemoTaggedEntryTag *tag,
image = gtk_image_new_from_icon_name ("window-close-symbolic");
tag->button = gtk_button_new ();
gtk_button_set_child (GTK_BUTTON (tag->button), image);
gtk_container_add (GTK_CONTAINER (tag->button), image);
gtk_widget_set_halign (tag->button, GTK_ALIGN_CENTER);
gtk_widget_set_valign (tag->button, GTK_ALIGN_CENTER);
gtk_button_set_has_frame (GTK_BUTTON (tag->button), FALSE);
gtk_box_append (GTK_BOX (tag->box), tag->button);
gtk_button_set_relief (GTK_BUTTON (tag->button), GTK_RELIEF_NONE);
gtk_container_add (GTK_CONTAINER (tag->box), tag->button);
g_signal_connect (tag->button, "clicked", G_CALLBACK (on_button_clicked), tag);
}

View File

@@ -25,11 +25,39 @@
G_BEGIN_DECLS
#define DEMO_TYPE_TAGGED_ENTRY (demo_tagged_entry_get_type ())
G_DECLARE_FINAL_TYPE (DemoTaggedEntry, demo_tagged_entry, DEMO, TAGGED_ENTRY, GtkWidget)
#define DEMO_TYPE_TAGGED_ENTRY (demo_tagged_entry_get_type ())
#define DEMO_TAGGED_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DEMO_TYPE_TAGGED_ENTRY, DemoTaggedEntry))
#define DEMO_TAGGED_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DEMO_TYPE_TAGGED_ENTRY, DemoTaggedEntryClass))
#define DEMO_IS_TAGGED_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DEMO_TYPE_TAGGED_ENTRY))
#define DEMO_IS_TAGGED_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DEMO_TYPE_TAGGED_ENTRY))
#define DEMO_TAGGED_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DEMO_TYPE_TAGGED_ENTRY, DemoTaggedEntryClass))
#define DEMO_TYPE_TAGGED_ENTRY_TAG (demo_tagged_entry_tag_get_type ())
G_DECLARE_FINAL_TYPE (DemoTaggedEntryTag, demo_tagged_entry_tag, DEMO, TAGGED_ENTRY_TAG, GtkWidget)
typedef struct _DemoTaggedEntry DemoTaggedEntry;
typedef struct _DemoTaggedEntryClass DemoTaggedEntryClass;
struct _DemoTaggedEntry
{
GtkWidget parent;
};
struct _DemoTaggedEntryClass
{
GtkWidgetClass parent_class;
};
#define DEMO_TYPE_TAGGED_ENTRY_TAG (demo_tagged_entry_tag_get_type ())
#define DEMO_TAGGED_ENTRY_TAG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DEMO_TYPE_TAGGED_ENTRY_TAG, DemoTaggedEntryTag))
#define DEMO_TAGGED_ENTRY_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DEMO_TYPE_TAGGED_ENTRY_TAG, DemoTaggedEntryTag))
#define DEMO_IS_TAGGED_ENTRY_TAG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DEMO_TYPE_TAGGED_ENTRY_TAG))
#define DEMO_IS_TAGGED_ENTRY_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DEMO_TYPE_TAGGED_ENTRY_TAG))
#define DEMO_TAGGED_ENTRY_TAG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DEMO_TYPE_TAGGED_ENTRY_TAG, DemoTaggedEntryTagClass))
typedef struct _DemoTaggedEntryTag DemoTaggedEntryTag;
typedef struct _DemoTaggedEntryTagClass DemoTaggedEntryTagClass;
GType demo_tagged_entry_get_type (void) G_GNUC_CONST;
GType demo_tagged_entry_tag_get_type (void) G_GNUC_CONST;
GtkWidget * demo_tagged_entry_new (void);

View File

@@ -1,7 +1,6 @@
/* Dialogs
/* Dialogs and Message Boxes
*
* Dialogs are used to pop up transient windows for information
* and user feedback.
* Dialog widgets are used to pop up a transient window for user feedback.
*/
#include <glib/gi18n.h>
@@ -22,71 +21,51 @@ message_dialog_clicked (GtkButton *button,
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK_CANCEL,
"Test message");
"This message box has been popped up the following\n"
"number of times:");
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
ngettext ("Has been shown once", "Has been shown %d times", i), i);
g_signal_connect (dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
gtk_widget_show (dialog);
"%d", i);
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
i++;
}
typedef struct {
GtkWidget *local_entry1;
GtkWidget *local_entry2;
GtkWidget *global_entry1;
GtkWidget *global_entry2;
} ResponseData;
static void
on_dialog_response (GtkDialog *dialog,
int response,
gpointer user_data)
{
ResponseData *data = user_data;
if (response == GTK_RESPONSE_OK)
{
gtk_editable_set_text (GTK_EDITABLE (data->global_entry1),
gtk_editable_get_text (GTK_EDITABLE (data->local_entry1)));
gtk_editable_set_text (GTK_EDITABLE (data->global_entry2),
gtk_editable_get_text (GTK_EDITABLE (data->local_entry2)));
}
gtk_window_destroy (GTK_WINDOW (dialog));
}
static void
interactive_dialog_clicked (GtkButton *button,
gpointer user_data)
{
GtkWidget *content_area;
GtkWidget *dialog;
GtkWidget *hbox;
GtkWidget *image;
GtkWidget *table;
GtkWidget *local_entry1;
GtkWidget *local_entry2;
GtkWidget *label;
ResponseData *data;
gint response;
dialog = gtk_dialog_new_with_buttons ("Interactive Dialog",
GTK_WINDOW (window),
GTK_DIALOG_MODAL| GTK_DIALOG_DESTROY_WITH_PARENT|GTK_DIALOG_USE_HEADER_BAR,
_("_OK"), GTK_RESPONSE_OK,
_("_Cancel"), GTK_RESPONSE_CANCEL,
GTK_DIALOG_MODAL| GTK_DIALOG_DESTROY_WITH_PARENT,
_("_OK"),
GTK_RESPONSE_OK,
"_Cancel",
GTK_RESPONSE_CANCEL,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
table = gtk_grid_new ();
gtk_widget_set_hexpand (table, TRUE);
gtk_widget_set_vexpand (table, TRUE);
gtk_widget_set_halign (table, GTK_ALIGN_CENTER);
gtk_widget_set_valign (table, GTK_ALIGN_CENTER);
gtk_box_append (GTK_BOX (content_area), table);
gtk_grid_set_row_spacing (GTK_GRID (table), 6);
gtk_grid_set_column_spacing (GTK_GRID (table), 6);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
gtk_container_add (GTK_CONTAINER (content_area), hbox);
image = gtk_image_new_from_icon_name ("dialog-question");
gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
gtk_container_add (GTK_CONTAINER (hbox), image);
table = gtk_grid_new ();
gtk_grid_set_row_spacing (GTK_GRID (table), 4);
gtk_grid_set_column_spacing (GTK_GRID (table), 4);
gtk_container_add (GTK_CONTAINER (hbox), table);
label = gtk_label_new_with_mnemonic ("_Entry 1");
gtk_grid_attach (GTK_GRID (table), label, 0, 0, 1, 1);
local_entry1 = gtk_entry_new ();
@@ -102,23 +81,21 @@ interactive_dialog_clicked (GtkButton *button,
gtk_grid_attach (GTK_GRID (table), local_entry2, 1, 1, 1, 1);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), local_entry2);
data = g_new (ResponseData, 1);
data->local_entry1 = local_entry1;
data->local_entry2 = local_entry2;
data->global_entry1 = entry1;
data->global_entry2 = entry2;
response = gtk_dialog_run (GTK_DIALOG (dialog));
g_signal_connect_data (dialog, "response",
G_CALLBACK (on_dialog_response),
data, (GClosureNotify) g_free,
0);
if (response == GTK_RESPONSE_OK)
{
gtk_editable_set_text (GTK_EDITABLE (entry1), gtk_editable_get_text (GTK_EDITABLE (local_entry1)));
gtk_editable_set_text (GTK_EDITABLE (entry2), gtk_editable_get_text (GTK_EDITABLE (local_entry2)));
}
gtk_widget_show (dialog);
gtk_widget_destroy (dialog);
}
GtkWidget *
do_dialog (GtkWidget *do_widget)
{
GtkWidget *frame;
GtkWidget *vbox;
GtkWidget *vbox2;
GtkWidget *hbox;
@@ -128,45 +105,47 @@ do_dialog (GtkWidget *do_widget)
if (!window)
{
window = gtk_window_new ();
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), "Dialogs");
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
gtk_window_set_title (GTK_WINDOW (window), "Dialogs and Message Boxes");
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
frame = gtk_frame_new ("Dialogs");
g_object_set (frame, "margin", 8, NULL);
gtk_container_add (GTK_CONTAINER (window), frame);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
gtk_widget_set_margin_start (vbox, 8);
gtk_widget_set_margin_end (vbox, 8);
gtk_widget_set_margin_top (vbox, 8);
gtk_widget_set_margin_bottom (vbox, 8);
gtk_window_set_child (GTK_WINDOW (window), vbox);
g_object_set (vbox, "margin", 8, NULL);
gtk_container_add (GTK_CONTAINER (frame), vbox);
/* Standard message dialog */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
gtk_box_append (GTK_BOX (vbox), hbox);
gtk_container_add (GTK_CONTAINER (vbox), hbox);
button = gtk_button_new_with_mnemonic ("_Message Dialog");
g_signal_connect (button, "clicked",
G_CALLBACK (message_dialog_clicked), NULL);
gtk_box_append (GTK_BOX (hbox), button);
gtk_container_add (GTK_CONTAINER (hbox), button);
gtk_box_append (GTK_BOX (vbox), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
gtk_container_add (GTK_CONTAINER (vbox), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
/* Interactive dialog*/
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
gtk_box_append (GTK_BOX (vbox), hbox);
gtk_container_add (GTK_CONTAINER (vbox), hbox);
vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
button = gtk_button_new_with_mnemonic ("_Interactive Dialog");
g_signal_connect (button, "clicked",
G_CALLBACK (interactive_dialog_clicked), NULL);
gtk_box_append (GTK_BOX (hbox), vbox2);
gtk_box_append (GTK_BOX (vbox2), button);
gtk_container_add (GTK_CONTAINER (hbox), vbox2);
gtk_container_add (GTK_CONTAINER (vbox2), button);
table = gtk_grid_new ();
gtk_grid_set_row_spacing (GTK_GRID (table), 4);
gtk_grid_set_column_spacing (GTK_GRID (table), 4);
gtk_box_append (GTK_BOX (hbox), table);
gtk_container_add (GTK_CONTAINER (hbox), table);
label = gtk_label_new_with_mnemonic ("_Entry 1");
gtk_grid_attach (GTK_GRID (table), label, 0, 0, 1, 1);
@@ -185,7 +164,7 @@ do_dialog (GtkWidget *do_widget)
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,450 +1,235 @@
/* Drag-and-Drop
*
* This demo shows dragging colors and widgets.
* The items in this demo can be moved, recolored
* and rotated.
* I can't believe its not glade!
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <string.h>
G_DECLARE_FINAL_TYPE (CanvasItem, canvas_item, CANVAS, ITEM, GtkWidget)
struct _CanvasItem {
GtkWidget parent;
GtkWidget *fixed;
GtkWidget *label;
double r;
double angle;
double delta;
GtkWidget *editor;
typedef struct _GtkDemoWidget GtkDemoWidget;
struct _GtkDemoWidget
{
GType type;
union {
char *text;
gboolean active;
};
};
struct _CanvasItemClass {
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE (CanvasItem, canvas_item, GTK_TYPE_WIDGET)
static int n_items = 0;
static void
set_color (CanvasItem *item,
GdkRGBA *color)
static gpointer
copy_demo_widget (gpointer data)
{
char *css;
char *str;
GtkStyleContext *context;
GtkCssProvider *provider;
const char *old_class;
GtkDemoWidget *demo = g_memdup (data, sizeof (GtkDemoWidget));
str = gdk_rgba_to_string (color);
css = g_strdup_printf ("* { background: %s; }", str);
if (demo->type == GTK_TYPE_LABEL)
demo->text = g_strdup (demo->text);
context = gtk_widget_get_style_context (item->label);
provider = g_object_get_data (G_OBJECT (context), "style-provider");
if (provider)
gtk_style_context_remove_provider (context, GTK_STYLE_PROVIDER (provider));
old_class = (const char *)g_object_get_data (G_OBJECT (item->label), "css-class");
if (old_class)
gtk_widget_remove_css_class (item->label, old_class);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_data (provider, css, -1);
gtk_style_context_add_provider (gtk_widget_get_style_context (item->label), GTK_STYLE_PROVIDER (provider), 800);
g_object_set_data_full (G_OBJECT (context), "style-provider", provider, g_object_unref);
g_free (str);
g_free (css);
return demo;
}
static void
set_css (CanvasItem *item,
const char *class)
free_demo_widget (gpointer data)
{
GtkStyleContext *context;
GtkCssProvider *provider;
const char *old_class;
GtkDemoWidget *demo = data;
context = gtk_widget_get_style_context (item->label);
provider = g_object_get_data (G_OBJECT (context), "style-provider");
if (provider)
gtk_style_context_remove_provider (context, GTK_STYLE_PROVIDER (provider));
if (demo->type == GTK_TYPE_LABEL)
g_free (demo->text);
old_class = (const char *)g_object_get_data (G_OBJECT (item->label), "css-class");
if (old_class)
gtk_widget_remove_css_class (item->label, old_class);
g_object_set_data_full (G_OBJECT (item->label), "css-class", g_strdup (class), g_free);
gtk_widget_add_css_class (item->label, class);
g_free (demo);
}
static gboolean
item_drag_drop (GtkDropTarget *dest,
const GValue *value,
double x,
double y)
#define GTK_TYPE_DEMO_WIDGET (gtk_demo_widget_get_type ())
G_DEFINE_BOXED_TYPE (GtkDemoWidget, gtk_demo_widget, copy_demo_widget, free_demo_widget)
static GtkDemoWidget *
serialize_widget (GtkWidget *widget)
{
GtkWidget *label = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
CanvasItem *item = CANVAS_ITEM (gtk_widget_get_parent (gtk_widget_get_parent (label)));
GtkDemoWidget *demo;
if (G_VALUE_TYPE (value) == GDK_TYPE_RGBA)
set_color (item, g_value_get_boxed (value));
else if (G_VALUE_TYPE (value) == G_TYPE_STRING)
set_css (item, g_value_get_string (value));
demo = g_new0 (GtkDemoWidget, 1);
demo->type = G_OBJECT_TYPE (widget);
return TRUE;
}
if (GTK_IS_LABEL (widget))
{
demo->text = g_strdup (gtk_label_get_text (GTK_LABEL (widget)));
}
else if (GTK_IS_SPINNER (widget))
{
g_object_get (widget, "active", &demo->active, NULL);
}
else
{
g_print ("Type %s not supported\n", g_type_name (demo->type));
}
static void
apply_transform (CanvasItem *item)
{
GskTransform *transform;
double x, y;
x = gtk_widget_get_allocated_width (item->label) / 2.0;
y = gtk_widget_get_allocated_height (item->label) / 2.0;
item->r = sqrt (x*x + y*y);
transform = gsk_transform_translate (
gsk_transform_rotate (
gsk_transform_translate (NULL,
&(graphene_point_t) { item->r, item->r }),
item->angle + item->delta),
&(graphene_point_t) { - x, - y });
gtk_fixed_set_child_transform (GTK_FIXED (item->fixed), item->label, transform);
gsk_transform_unref (transform);
}
static void
angle_changed (GtkGestureRotate *gesture,
double angle,
double delta)
{
CanvasItem *item = CANVAS_ITEM (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)));
item->delta = angle / M_PI * 180.0;
apply_transform (item);
}
static void
rotate_done (GtkGesture *gesture)
{
CanvasItem *item = CANVAS_ITEM (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)));
item->angle = item->angle + item->delta;
item->delta = 0;
}
static void
click_done (GtkGesture *gesture)
{
GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
GtkWidget *canvas = gtk_widget_get_parent (item);
GtkWidget *last_child;
last_child = gtk_widget_get_last_child (canvas);
if (item != last_child)
gtk_widget_insert_after (item, canvas, last_child);
}
static void
canvas_item_init (CanvasItem *item)
{
char *text;
char *id;
GdkRGBA rgba;
GtkDropTarget *dest;
GtkGesture *gesture;
GType types[2] = { GDK_TYPE_RGBA, G_TYPE_STRING };
n_items++;
text = g_strdup_printf ("Item %d", n_items);
item->label = gtk_label_new (text);
gtk_widget_add_css_class (item->label, "canvasitem");
g_free (text);
item->fixed = gtk_fixed_new ();
gtk_widget_set_parent (item->fixed, GTK_WIDGET (item));
gtk_fixed_put (GTK_FIXED (item->fixed), item->label, 0, 0);
gtk_widget_add_css_class (item->label, "frame");
id = g_strdup_printf ("item%d", n_items);
gtk_widget_set_name (item->label, id);
g_free (id);
gdk_rgba_parse (&rgba, "yellow");
set_color (item, &rgba);
item->angle = 0;
dest = gtk_drop_target_new (G_TYPE_INVALID, GDK_ACTION_COPY);
gtk_drop_target_set_gtypes (dest, types, G_N_ELEMENTS (types));
g_signal_connect (dest, "drop", G_CALLBACK (item_drag_drop), NULL);
gtk_widget_add_controller (GTK_WIDGET (item->label), GTK_EVENT_CONTROLLER (dest));
gesture = gtk_gesture_rotate_new ();
g_signal_connect (gesture, "angle-changed", G_CALLBACK (angle_changed), NULL);
g_signal_connect (gesture, "end", G_CALLBACK (rotate_done), NULL);
gtk_widget_add_controller (GTK_WIDGET (item), GTK_EVENT_CONTROLLER (gesture));
gesture = gtk_gesture_click_new ();
g_signal_connect (gesture, "released", G_CALLBACK (click_done), NULL);
gtk_widget_add_controller (GTK_WIDGET (item), GTK_EVENT_CONTROLLER (gesture));
}
static void
canvas_item_dispose (GObject *object)
{
CanvasItem *item = CANVAS_ITEM (object);
g_clear_pointer (&item->fixed, gtk_widget_unparent);
g_clear_pointer (&item->editor, gtk_widget_unparent);
G_OBJECT_CLASS (canvas_item_parent_class)->dispose (object);
}
static void
canvas_item_map (GtkWidget *widget)
{
CanvasItem *item = CANVAS_ITEM (widget);
GTK_WIDGET_CLASS (canvas_item_parent_class)->map (widget);
apply_transform (item);
}
static void
canvas_item_class_init (CanvasItemClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->dispose = canvas_item_dispose;
widget_class->map = canvas_item_map;
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
gtk_widget_class_set_css_name (widget_class, "item");
return demo;
}
static GtkWidget *
canvas_item_new (void)
deserialize_widget (GtkDemoWidget *demo)
{
CanvasItem *item = g_object_new (canvas_item_get_type (), NULL);
GtkWidget *widget = NULL;
return GTK_WIDGET (item);
if (demo->type == GTK_TYPE_LABEL)
{
widget = gtk_label_new (demo->text);
}
else if (demo->type == GTK_TYPE_SPINNER)
{
widget = g_object_new (demo->type, "active", demo->active, NULL);
gtk_style_context_add_class (gtk_widget_get_style_context (widget), "demo");
}
else
{
g_print ("Type %s not supported\n", g_type_name (demo->type));
}
return widget;
}
static GdkPaintable *
canvas_item_get_drag_icon (CanvasItem *item)
{
return gtk_widget_paintable_new (item->fixed);
}
static double pos_x, pos_y;
static gboolean
canvas_item_is_editing (CanvasItem *item)
static void
new_label_cb (GtkMenuItem *item,
gpointer data)
{
return item->editor != NULL;
GtkFixed *fixed = data;
GtkWidget *widget;
widget = gtk_label_new ("Label");
gtk_fixed_put (fixed, widget, pos_x, pos_y);
}
static void
scale_changed (GtkRange *range,
CanvasItem *item)
new_spinner_cb (GtkMenuItem *item,
gpointer data)
{
item->angle = gtk_range_get_value (range);
apply_transform (item);
GtkFixed *fixed = data;
GtkWidget *widget;
widget = gtk_spinner_new ();
gtk_style_context_add_class (gtk_widget_get_style_context (widget), "demo");
gtk_spinner_start (GTK_SPINNER (widget));
gtk_fixed_put (fixed, widget, pos_x, pos_y);
}
static void
text_changed (GtkEditable *editable,
GParamSpec *pspec,
CanvasItem *item)
copy_cb (GtkWidget *child)
{
gtk_label_set_text (GTK_LABEL (item->label), gtk_editable_get_text (editable));
apply_transform (item);
GdkClipboard *clipboard;
GtkDemoWidget *demo;
g_print ("Copy %s\n", G_OBJECT_TYPE_NAME (child));
demo = serialize_widget (child);
clipboard = gdk_display_get_clipboard (gdk_display_get_default ());
gdk_clipboard_set (clipboard, GTK_TYPE_DEMO_WIDGET, demo);
}
static void
canvas_item_stop_editing (CanvasItem *item)
delete_cb (GtkWidget *child)
{
GtkWidget *scale;
if (!item->editor)
return;
scale = gtk_widget_get_last_child (item->editor);
g_signal_handlers_disconnect_by_func (scale, scale_changed, item);
gtk_fixed_remove (GTK_FIXED (gtk_widget_get_parent (item->editor)), item->editor);
item->editor = NULL;
gtk_widget_destroy (child);
}
static void
canvas_item_start_editing (CanvasItem *item)
cut_cb (GtkWidget *child)
{
GtkWidget *canvas = gtk_widget_get_parent (GTK_WIDGET (item));
GtkWidget *entry;
GtkWidget *scale;
double x, y;
if (item->editor)
return;
item->editor = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
entry = gtk_entry_new ();
gtk_editable_set_text (GTK_EDITABLE (entry),
gtk_label_get_text (GTK_LABEL (item->label)));
gtk_editable_set_width_chars (GTK_EDITABLE (entry), 12);
g_signal_connect (entry, "notify::text", G_CALLBACK (text_changed), item);
g_signal_connect_swapped (entry, "activate", G_CALLBACK (canvas_item_stop_editing), item);
gtk_box_append (GTK_BOX (item->editor), entry);
scale = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0, 360, 1);
gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
gtk_range_set_value (GTK_RANGE (scale), fmod (item->angle, 360));
g_signal_connect (scale, "value-changed", G_CALLBACK (scale_changed), item);
gtk_box_append (GTK_BOX (item->editor), scale);
gtk_widget_translate_coordinates (GTK_WIDGET (item), canvas, 0, 0, &x, &y);
gtk_fixed_put (GTK_FIXED (canvas), item->editor, x, y + 2 * item->r);
gtk_widget_grab_focus (entry);
}
static GdkContentProvider *
prepare (GtkDragSource *source,
double x,
double y)
{
GtkWidget *canvas;
GtkWidget *item;
canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
item = gtk_widget_pick (canvas, x, y, GTK_PICK_DEFAULT);
item = gtk_widget_get_ancestor (item, canvas_item_get_type ());
if (!item)
return NULL;
g_object_set_data (G_OBJECT (canvas), "dragged-item", item);
return gdk_content_provider_new_typed (GTK_TYPE_WIDGET, item);
copy_cb (child);
delete_cb (child);
}
static void
drag_begin (GtkDragSource *source,
GdkDrag *drag)
value_read (GObject *source,
GAsyncResult *res,
gpointer data)
{
GtkWidget *canvas;
CanvasItem *item;
GdkPaintable *paintable;
GdkClipboard *clipboard = GDK_CLIPBOARD (source);
GError *error = NULL;
const GValue *value;
GtkDemoWidget *demo;
GtkWidget *widget = NULL;
canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
item = CANVAS_ITEM (g_object_get_data (G_OBJECT (canvas), "dragged-item"));
value = gdk_clipboard_read_value_finish (clipboard, res, &error);
paintable = canvas_item_get_drag_icon (item);
gtk_drag_source_set_icon (source, paintable, item->r, item->r);
g_object_unref (paintable);
if (value == NULL)
{
g_print ("error: %s\n", error->message);
g_error_free (error);
return;
}
gtk_widget_set_opacity (GTK_WIDGET (item), 0.3);
if (!G_VALUE_HOLDS (value, GTK_TYPE_DEMO_WIDGET))
{
g_print ("can't handle clipboard contents\n");
return;
}
demo = g_value_get_boxed (value);
widget = deserialize_widget (demo);
gtk_fixed_put (GTK_FIXED (data), widget, pos_x, pos_y);
}
static void
drag_end (GtkDragSource *source,
GdkDrag *drag)
paste_cb (GtkWidget *fixed)
{
GtkWidget *canvas;
GtkWidget *item;
GdkClipboard *clipboard;
canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
item = g_object_get_data (G_OBJECT (canvas), "dragged-item");
g_object_set_data (G_OBJECT (canvas), "dragged-item", NULL);
gtk_widget_set_opacity (item, 1.0);
}
static gboolean
drag_cancel (GtkDragSource *source,
GdkDrag *drag,
GdkDragCancelReason reason)
{
return FALSE;
}
static gboolean
drag_drop (GtkDropTarget *target,
const GValue *value,
double x,
double y)
{
CanvasItem *item;
GtkWidget *canvas;
GtkWidget *last_child;
item = g_value_get_object (value);
canvas = gtk_widget_get_parent (GTK_WIDGET (item));
last_child = gtk_widget_get_last_child (canvas);
if (GTK_WIDGET (item) != last_child)
gtk_widget_insert_after (GTK_WIDGET (item), canvas, last_child);
gtk_fixed_move (GTK_FIXED (canvas), GTK_WIDGET (item), x - item->r, y - item->r);
return TRUE;
clipboard = gdk_display_get_clipboard (gdk_display_get_default ());
if (gdk_content_formats_contain_gtype (gdk_clipboard_get_formats (clipboard), GTK_TYPE_DEMO_WIDGET))
{
g_print ("Paste %s\n", g_type_name (GTK_TYPE_DEMO_WIDGET));
gdk_clipboard_read_value_async (clipboard, GTK_TYPE_DEMO_WIDGET, 0, NULL, value_read, fixed);
}
else
g_print ("Don't know how to handle clipboard contents\n");
}
static void
new_item_cb (GtkWidget *button, gpointer data)
edit_label_done (GtkWidget *entry, gpointer data)
{
GtkWidget *canvas = data;
GtkWidget *popover;
GtkWidget *item;
GdkRectangle rect;
GtkWidget *fixed = gtk_widget_get_parent (entry);
GtkWidget *label;
int x, y;
popover = gtk_widget_get_ancestor (button, GTK_TYPE_POPOVER);
gtk_popover_get_pointing_to (GTK_POPOVER (popover), &rect);
gtk_fixed_get_child_position (GTK_FIXED (fixed), entry, &x, &y);
item = canvas_item_new ();
gtk_fixed_put (GTK_FIXED (canvas), item, rect.x, rect.y);
apply_transform (CANVAS_ITEM (item));
label = GTK_WIDGET (g_object_get_data (G_OBJECT (entry), "label"));
gtk_label_set_text (GTK_LABEL (label), gtk_editable_get_text (GTK_EDITABLE (entry)));
gtk_popover_popdown (GTK_POPOVER (gtk_widget_get_ancestor (button, GTK_TYPE_POPOVER)));
gtk_widget_destroy (entry);
}
static void
edit_cb (GtkWidget *button, GtkWidget *child)
edit_cb (GtkWidget *child)
{
CanvasItem *item = CANVAS_ITEM (child);
GtkWidget *fixed = gtk_widget_get_parent (child);
int x, y;
if (button)
gtk_popover_popdown (GTK_POPOVER (gtk_widget_get_ancestor (button, GTK_TYPE_POPOVER)));
gtk_fixed_get_child_position (GTK_FIXED (fixed), child, &x, &y);
if (!canvas_item_is_editing (item))
canvas_item_start_editing (item);
}
if (GTK_IS_LABEL (child))
{
GtkWidget *entry = gtk_entry_new ();
static void
delete_cb (GtkWidget *button, GtkWidget *child)
{
GtkWidget *canvas = gtk_widget_get_parent (child);
g_object_set_data (G_OBJECT (entry), "label", child);
gtk_fixed_remove (GTK_FIXED (canvas), child);
gtk_editable_set_text (GTK_EDITABLE (entry), gtk_label_get_text (GTK_LABEL (child)));
g_signal_connect (entry, "activate", G_CALLBACK (edit_label_done), NULL);
gtk_fixed_put (GTK_FIXED (fixed), entry, x, y);
gtk_widget_grab_focus (entry);
}
else if (GTK_IS_SPINNER (child))
{
gboolean active;
gtk_popover_popdown (GTK_POPOVER (gtk_widget_get_ancestor (button, GTK_TYPE_POPOVER)));
g_object_get (child, "active", &active, NULL);
g_object_set (child, "active", !active, NULL);
}
}
static void
@@ -459,45 +244,68 @@ pressed_cb (GtkGesture *gesture,
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
child = gtk_widget_pick (widget, x, y, GTK_PICK_DEFAULT);
child = gtk_widget_get_ancestor (child, canvas_item_get_type ());
if (gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture)) == GDK_BUTTON_SECONDARY)
{
GdkRectangle rect;
GtkWidget *menu;
GtkWidget *box;
GtkWidget *item;
GdkClipboard *clipboard;
menu = gtk_popover_new ();
gtk_widget_set_parent (menu, widget);
gtk_popover_set_has_arrow (GTK_POPOVER (menu), FALSE);
gtk_popover_set_pointing_to (GTK_POPOVER (menu), &(GdkRectangle){ x, y, 1, 1});
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_popover_set_child (GTK_POPOVER (menu), box);
pos_x = x;
pos_y = y;
item = gtk_button_new_with_label ("New");
gtk_button_set_has_frame (GTK_BUTTON (item), FALSE);
g_signal_connect (item, "clicked", G_CALLBACK (new_item_cb), widget);
gtk_box_append (GTK_BOX (box), item);
menu = gtk_menu_new ();
item = gtk_menu_item_new_with_label ("New Label");
g_signal_connect (item, "activate", G_CALLBACK (new_label_cb), widget);
gtk_container_add (GTK_CONTAINER (menu), item);
item = gtk_menu_item_new_with_label ("New Spinner");
g_signal_connect (item, "activate", G_CALLBACK (new_spinner_cb), widget);
gtk_container_add (GTK_CONTAINER (menu), item);
item = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
gtk_box_append (GTK_BOX (box), item);
item = gtk_separator_menu_item_new ();
gtk_container_add (GTK_CONTAINER (menu), item);
item = gtk_button_new_with_label ("Edit");
gtk_button_set_has_frame (GTK_BUTTON (item), FALSE);
item = gtk_menu_item_new_with_label ("Edit");
gtk_widget_set_sensitive (item, child != NULL && child != widget);
g_signal_connect (item, "clicked", G_CALLBACK (edit_cb), child);
gtk_box_append (GTK_BOX (box), item);
g_signal_connect_swapped (item, "activate", G_CALLBACK (edit_cb), child);
gtk_container_add (GTK_CONTAINER (menu), item);
item = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
gtk_box_append (GTK_BOX (box), item);
item = gtk_separator_menu_item_new ();
gtk_container_add (GTK_CONTAINER (menu), item);
item = gtk_button_new_with_label ("Delete");
gtk_button_set_has_frame (GTK_BUTTON (item), FALSE);
item = gtk_menu_item_new_with_label ("Cut");
gtk_widget_set_sensitive (item, child != NULL && child != widget);
g_signal_connect (item, "clicked", G_CALLBACK (delete_cb), child);
gtk_box_append (GTK_BOX (box), item);
g_signal_connect_swapped (item, "activate", G_CALLBACK (cut_cb), child);
gtk_container_add (GTK_CONTAINER (menu), item);
item = gtk_menu_item_new_with_label ("Copy");
gtk_widget_set_sensitive (item, child != NULL && child != widget);
g_signal_connect_swapped (item, "activate", G_CALLBACK (copy_cb), child);
gtk_container_add (GTK_CONTAINER (menu), item);
item = gtk_menu_item_new_with_label ("Paste");
clipboard = gdk_display_get_clipboard (gdk_display_get_default ());
gtk_widget_set_sensitive (item,
gdk_content_formats_contain_gtype (gdk_clipboard_get_formats (clipboard), GTK_TYPE_DEMO_WIDGET));
g_signal_connect_swapped (item, "activate", G_CALLBACK (paste_cb), widget);
gtk_container_add (GTK_CONTAINER (menu), item);
item = gtk_menu_item_new_with_label ("Delete");
gtk_widget_set_sensitive (item, child != NULL && child != widget);
g_signal_connect_swapped (item, "activate", G_CALLBACK (delete_cb), child);
gtk_container_add (GTK_CONTAINER (menu), item);
gtk_popover_popup (GTK_POPOVER (menu));
rect.x = x;
rect.y = y;
rect.width = 0;
rect.height = 0;
gtk_menu_popup_at_rect (GTK_MENU (menu),
gtk_native_get_surface (gtk_widget_get_native (widget)),
&rect,
GDK_GRAVITY_NORTH_WEST,
GDK_GRAVITY_NORTH_WEST,
NULL);
return;
}
}
@@ -510,170 +318,17 @@ released_cb (GtkGesture *gesture,
{
GtkWidget *widget;
GtkWidget *child;
CanvasItem *item;
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
child = gtk_widget_pick (widget, x, y, 0);
item = (CanvasItem *)gtk_widget_get_ancestor (child, canvas_item_get_type ());
if (!item)
return;
if (gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture)) == GDK_BUTTON_PRIMARY)
{
if (canvas_item_is_editing (item))
canvas_item_stop_editing (item);
else
canvas_item_start_editing (item);
if (child != NULL && child != widget)
edit_cb (child);
}
}
static GtkWidget *
canvas_new (void)
{
GtkWidget *canvas;
GtkDragSource *source;
GtkDropTarget *dest;
GtkGesture *gesture;
canvas = gtk_fixed_new ();
gtk_widget_set_hexpand (canvas, TRUE);
gtk_widget_set_vexpand (canvas, TRUE);
gtk_widget_add_css_class (canvas, "frame");
source = gtk_drag_source_new ();
gtk_drag_source_set_actions (source, GDK_ACTION_MOVE);
g_signal_connect (source, "prepare", G_CALLBACK (prepare), NULL);
g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), NULL);
g_signal_connect (source, "drag-end", G_CALLBACK (drag_end), NULL);
g_signal_connect (source, "drag-cancel", G_CALLBACK (drag_cancel), NULL);
gtk_widget_add_controller (canvas, GTK_EVENT_CONTROLLER (source));
dest = gtk_drop_target_new (GTK_TYPE_WIDGET, GDK_ACTION_MOVE);
g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), NULL);
gtk_widget_add_controller (canvas, GTK_EVENT_CONTROLLER (dest));
gesture = gtk_gesture_click_new ();
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), 0);
g_signal_connect (gesture, "pressed", G_CALLBACK (pressed_cb), NULL);
g_signal_connect (gesture, "released", G_CALLBACK (released_cb), NULL);
gtk_widget_add_controller (canvas, GTK_EVENT_CONTROLLER (gesture));
return canvas;
}
static GdkContentProvider *
css_drag_prepare (GtkDragSource *source,
double x,
double y,
GtkWidget *button)
{
const char *class;
GdkPaintable *paintable;
class = (const char *)g_object_get_data (G_OBJECT (button), "css-class");
paintable = gtk_widget_paintable_new (button);
gtk_drag_source_set_icon (source, paintable, 0, 0);
g_object_unref (paintable);
return gdk_content_provider_new_typed (G_TYPE_STRING, class);
}
static GtkWidget *
css_button_new (const char *class)
{
GtkWidget *button;
GtkDragSource *source;
button = gtk_image_new ();
gtk_widget_set_size_request (button, 48, 32);
gtk_widget_add_css_class (button, class);
g_object_set_data (G_OBJECT (button), "css-class", (gpointer)class);
source = gtk_drag_source_new ();
g_signal_connect (source, "prepare", G_CALLBACK (css_drag_prepare), button);
gtk_widget_add_controller (button, GTK_EVENT_CONTROLLER (source));
return button;
}
typedef struct
{
GtkWidget parent_instance;
GdkRGBA color;
} ColorSwatch;
typedef struct
{
GtkWidgetClass parent_class;
} ColorSwatchClass;
G_DEFINE_TYPE (ColorSwatch, color_swatch, GTK_TYPE_WIDGET)
static GdkContentProvider *
color_swatch_drag_prepare (GtkDragSource *source,
double x,
double y,
ColorSwatch *swatch)
{
return gdk_content_provider_new_typed (GDK_TYPE_RGBA, &swatch->color);
}
static void
color_swatch_init (ColorSwatch *swatch)
{
GtkDragSource *source = gtk_drag_source_new ();
g_signal_connect (source, "prepare", G_CALLBACK (color_swatch_drag_prepare), swatch);
gtk_widget_add_controller (GTK_WIDGET (swatch), GTK_EVENT_CONTROLLER (source));
}
static void
color_swatch_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
ColorSwatch *swatch = (ColorSwatch *)widget;
float w = gtk_widget_get_width (widget);
float h = gtk_widget_get_height (widget);
gtk_snapshot_append_color (snapshot, &swatch->color,
&GRAPHENE_RECT_INIT(0, 0, w, h));
}
void
color_swatch_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum_size,
int *natural_size,
int *minimum_baseline,
int *natural_baseline)
{
if (orientation == GTK_ORIENTATION_HORIZONTAL)
*minimum_size = *natural_size = 48;
else
*minimum_size = *natural_size = 32;
}
static void
color_swatch_class_init (ColorSwatchClass *class)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
widget_class->snapshot = color_swatch_snapshot;
widget_class->measure = color_swatch_measure;
gtk_widget_class_set_css_name (widget_class, "colorswatch");
}
static GtkWidget *
color_swatch_new (const char *color)
{
ColorSwatch *swatch = g_object_new (color_swatch_get_type (), NULL);
gdk_rgba_parse (&swatch->color, color);
return GTK_WIDGET (swatch);
}
static GtkWidget *window = NULL;
GtkWidget *
@@ -681,83 +336,43 @@ do_dnd (GtkWidget *do_widget)
{
if (!window)
{
GtkWidget *button;
GtkWidget *sw;
GtkWidget *canvas;
GtkWidget *box, *box2, *box3;
const char *colors[] = {
"red", "green", "blue", "magenta", "orange", "gray", "black", "yellow",
"white", "gray", "brown", "pink", "cyan", "bisque", "gold", "maroon",
"navy", "orchid", "olive", "peru", "salmon", "silver", "wheat",
NULL
};
int i;
int x, y;
GtkWidget *vbox, *fixed;
GtkGesture *multipress;
GtkCssProvider *provider;
button = gtk_color_button_new ();
g_object_unref (g_object_ref_sink (button));
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), "Drag-and-drop");
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (window), vbox);
fixed = gtk_fixed_new ();
gtk_container_add (GTK_CONTAINER (vbox), fixed);
gtk_widget_set_hexpand (fixed, TRUE);
gtk_widget_set_vexpand (fixed, TRUE);
multipress = gtk_gesture_click_new ();
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (multipress), 0);
g_signal_connect (multipress, "pressed", G_CALLBACK (pressed_cb), NULL);
g_signal_connect (multipress, "released", G_CALLBACK (released_cb), NULL);
gtk_widget_add_controller (fixed, GTK_EVENT_CONTROLLER (multipress));
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider, "/dnd/dnd.css");
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (provider),
800);
g_object_unref (provider);
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Drag-and-Drop");
gtk_window_set_default_size (GTK_WINDOW (window), 640, 480);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_window_set_child (GTK_WINDOW (window), box);
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_append (GTK_BOX (box), box2);
canvas = canvas_new ();
gtk_box_append (GTK_BOX (box2), canvas);
n_items = 0;
x = y = 40;
for (i = 0; i < 4; i++)
{
GtkWidget *item;
item = canvas_item_new ();
gtk_fixed_put (GTK_FIXED (canvas), item, x, y);
apply_transform (CANVAS_ITEM (item));
x += 150;
y += 100;
}
sw = gtk_scrolled_window_new ();
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_NEVER);
gtk_box_append (GTK_BOX (box), sw);
box3 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_add_css_class (box3, "linked");
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), box3);
for (i = 0; colors[i]; i++)
gtk_box_append (GTK_BOX (box3), color_swatch_new (colors[i]));
gtk_box_append (GTK_BOX (box3), css_button_new ("rainbow1"));
gtk_box_append (GTK_BOX (box3), css_button_new ("rainbow2"));
gtk_box_append (GTK_BOX (box3), css_button_new ("rainbow3"));
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,37 +1,3 @@
label.canvasitem {
padding: 10px;
margin: 1px;
}
.canvasitem.rainbow1,
image.rainbow1 {
background: linear-gradient(140deg,red,orange,yellow,green,blue,purple);
}
.canvasitem.rainbow2,
image.rainbow2 {
animation: rainbow2 1s infinite linear;
}
@keyframes rainbow2 {
0% { background: linear-gradient(0deg,red,orange,yellow,green,blue,purple); }
25% { background: linear-gradient(90deg,red,orange,yellow,green,blue,purple); }
50% { background: linear-gradient(180deg,red,orange,yellow,green,blue,purple); }
75% { background: linear-gradient(270deg,red,orange,yellow,green,blue,purple); }
100% { background: linear-gradient(360deg,red,orange,yellow,green,blue,purple); }
}
.canvasitem.rainbow3,
image.rainbow3 {
animation: rainbow3 1s infinite linear;
}
@keyframes rainbow3 {
0% { background: linear-gradient(140deg,red,orange,yellow,green,blue,purple); }
16.6% { background: linear-gradient(140deg,purple,red,orange,yellow,green,blue); }
33.2% { background: linear-gradient(140deg,blue,purple,red,orange,yellow,green); }
50% { background: linear-gradient(140deg,green,blue,purple,red,orange,yellow); }
66.6% { background: linear-gradient(140deg,yellow,green,blue,purple,red,orange); }
83.2% { background: linear-gradient(140deg,orange,yellow,green,blue,purple,red); }
100% { background: linear-gradient(140deg,red,orange,yellow,green,blue,purple); }
spinner.demo {
opacity: 1;
}

View File

@@ -42,9 +42,7 @@ create_surface (GtkWidget *widget)
}
static void
scribble_resize (GtkWidget *widget,
int width,
int height)
scribble_size_allocate (GtkWidget *widget)
{
create_surface (widget);
}
@@ -125,164 +123,49 @@ drag_end (GtkGestureDrag *gesture,
}
static void
oval_path (cairo_t *cr,
double xc, double yc,
double xr, double yr)
checkerboard_draw (GtkDrawingArea *da,
cairo_t *cr,
int width,
int height,
gpointer data)
{
cairo_save (cr);
gint i, j, xcount, ycount;
cairo_translate (cr, xc, yc);
cairo_scale (cr, 1.0, yr / xr);
cairo_move_to (cr, xr, 0.0);
cairo_arc (cr,
0, 0,
xr,
0, 2 * G_PI);
cairo_close_path (cr);
#define CHECK_SIZE 10
#define SPACING 2
cairo_restore (cr);
}
/* At the start of a draw handler, a clip region has been set on
* the Cairo context, and the contents have been cleared to the
* widget's background color. The docs for
* gdk_surface_begin_paint_region() give more details on how this
* works.
*/
/* Fill the given area with checks in the standard style
* for showing compositing effects.
*
* It would make sense to do this as a repeating surface,
* but most implementations of RENDER currently have broken
* implementations of repeat + transform, even when the
* transform is a translation.
*/
static void
fill_checks (cairo_t *cr,
int x, int y,
int width, int height)
{
int i, j;
#define CHECK_SIZE 16
cairo_rectangle (cr, x, y, width, height);
cairo_set_source_rgb (cr, 0.4, 0.4, 0.4);
cairo_fill (cr);
/* Only works for CHECK_SIZE a power of 2 */
j = x & (-CHECK_SIZE);
for (; j < height; j += CHECK_SIZE)
xcount = 0;
i = SPACING;
while (i < width)
{
i = y & (-CHECK_SIZE);
for (; i < width; i += CHECK_SIZE)
if ((i / CHECK_SIZE + j / CHECK_SIZE) % 2 == 0)
j = SPACING;
ycount = xcount % 2; /* start with even/odd depending on row */
while (j < height)
{
if (ycount % 2)
cairo_set_source_rgb (cr, 0.45777, 0, 0.45777);
else
cairo_set_source_rgb (cr, 1, 1, 1);
/* If we're outside the clip, this will do nothing.
*/
cairo_rectangle (cr, i, j, CHECK_SIZE, CHECK_SIZE);
cairo_fill (cr);
j += CHECK_SIZE + SPACING;
++ycount;
}
i += CHECK_SIZE + SPACING;
++xcount;
}
cairo_set_source_rgb (cr, 0.7, 0.7, 0.7);
cairo_fill (cr);
#undef CHECK_SIZE
}
/* Draw a red, green, and blue circle equally spaced inside
* the larger circle of radius r at (xc, yc)
*/
static void
draw_3circles (cairo_t *cr,
double xc, double yc,
double radius,
double alpha)
{
double subradius = radius * (2 / 3. - 0.1);
cairo_set_source_rgba (cr, 1., 0., 0., alpha);
oval_path (cr,
xc + radius / 3. * cos (G_PI * (0.5)),
yc - radius / 3. * sin (G_PI * (0.5)),
subradius, subradius);
cairo_fill (cr);
cairo_set_source_rgba (cr, 0., 1., 0., alpha);
oval_path (cr,
xc + radius / 3. * cos (G_PI * (0.5 + 2/.3)),
yc - radius / 3. * sin (G_PI * (0.5 + 2/.3)),
subradius, subradius);
cairo_fill (cr);
cairo_set_source_rgba (cr, 0., 0., 1., alpha);
oval_path (cr,
xc + radius / 3. * cos (G_PI * (0.5 + 4/.3)),
yc - radius / 3. * sin (G_PI * (0.5 + 4/.3)),
subradius, subradius);
cairo_fill (cr);
}
static void
groups_draw (GtkDrawingArea *darea,
cairo_t *cr,
int width,
int height,
gpointer data)
{
cairo_surface_t *overlay, *punch, *circles;
cairo_t *overlay_cr, *punch_cr, *circles_cr;
/* Fill the background */
double radius = 0.5 * (width < height ? width : height) - 10;
double xc = width / 2.;
double yc = height / 2.;
overlay = cairo_surface_create_similar (cairo_get_target (cr),
CAIRO_CONTENT_COLOR_ALPHA,
width, height);
punch = cairo_surface_create_similar (cairo_get_target (cr),
CAIRO_CONTENT_ALPHA,
width, height);
circles = cairo_surface_create_similar (cairo_get_target (cr),
CAIRO_CONTENT_COLOR_ALPHA,
width, height);
fill_checks (cr, 0, 0, width, height);
/* Draw a black circle on the overlay
*/
overlay_cr = cairo_create (overlay);
cairo_set_source_rgb (overlay_cr, 0., 0., 0.);
oval_path (overlay_cr, xc, yc, radius, radius);
cairo_fill (overlay_cr);
/* Draw 3 circles to the punch surface, then cut
* that out of the main circle in the overlay
*/
punch_cr = cairo_create (punch);
draw_3circles (punch_cr, xc, yc, radius, 1.0);
cairo_destroy (punch_cr);
cairo_set_operator (overlay_cr, CAIRO_OPERATOR_DEST_OUT);
cairo_set_source_surface (overlay_cr, punch, 0, 0);
cairo_paint (overlay_cr);
/* Now draw the 3 circles in a subgroup again
* at half intensity, and use OperatorAdd to join up
* without seams.
*/
circles_cr = cairo_create (circles);
cairo_set_operator (circles_cr, CAIRO_OPERATOR_OVER);
draw_3circles (circles_cr, xc, yc, radius, 0.5);
cairo_destroy (circles_cr);
cairo_set_operator (overlay_cr, CAIRO_OPERATOR_ADD);
cairo_set_source_surface (overlay_cr, circles, 0, 0);
cairo_paint (overlay_cr);
cairo_destroy (overlay_cr);
cairo_set_source_surface (cr, overlay, 0, 0);
cairo_paint (cr);
cairo_surface_destroy (overlay);
cairo_surface_destroy (punch);
cairo_surface_destroy (circles);
}
static void
@@ -306,7 +189,7 @@ do_drawingarea (GtkWidget *do_widget)
if (!window)
{
window = gtk_window_new ();
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), "Drawing Area");
@@ -315,29 +198,28 @@ do_drawingarea (GtkWidget *do_widget)
G_CALLBACK (close_window), NULL);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
gtk_widget_set_margin_start (vbox, 16);
gtk_widget_set_margin_end (vbox, 16);
gtk_widget_set_margin_top (vbox, 16);
gtk_widget_set_margin_bottom (vbox, 16);
gtk_window_set_child (GTK_WINDOW (window), vbox);
g_object_set (vbox, "margin", 16, NULL);
gtk_container_add (GTK_CONTAINER (window), vbox);
/*
* Create the groups area
* Create the checkerboard area
*/
label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (label),
"<u>Knockout groups</u>");
gtk_box_append (GTK_BOX (vbox), label);
"<u>Checkerboard pattern</u>");
gtk_container_add (GTK_CONTAINER (vbox), label);
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
gtk_widget_set_vexpand (frame, TRUE);
gtk_box_append (GTK_BOX (vbox), frame);
gtk_container_add (GTK_CONTAINER (vbox), frame);
da = gtk_drawing_area_new ();
gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (da), 100);
gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (da), 100);
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), groups_draw, NULL, NULL);
gtk_frame_set_child (GTK_FRAME (frame), da);
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), checkerboard_draw, NULL, NULL);
gtk_container_add (GTK_CONTAINER (frame), da);
/*
* Create the scribble area
@@ -346,20 +228,21 @@ do_drawingarea (GtkWidget *do_widget)
label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (label),
"<u>Scribble area</u>");
gtk_box_append (GTK_BOX (vbox), label);
gtk_container_add (GTK_CONTAINER (vbox), label);
frame = gtk_frame_new (NULL);
gtk_widget_set_vexpand (frame, TRUE);
gtk_box_append (GTK_BOX (vbox), frame);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
gtk_container_add (GTK_CONTAINER (vbox), frame);
da = gtk_drawing_area_new ();
gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (da), 100);
gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (da), 100);
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), scribble_draw, NULL, NULL);
gtk_frame_set_child (GTK_FRAME (frame), da);
gtk_container_add (GTK_CONTAINER (frame), da);
g_signal_connect (da, "resize",
G_CALLBACK (scribble_resize), NULL);
g_signal_connect (da, "size-allocate",
G_CALLBACK (scribble_size_allocate), NULL);
drag = gtk_gesture_drag_new ();
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (drag), GDK_BUTTON_PRIMARY);
@@ -374,7 +257,7 @@ do_drawingarea (GtkWidget *do_widget)
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,305 +0,0 @@
/* Drop Downs
*
* The GtkDropDown widget is a modern alternative to GtkComboBox.
* It uses list models instead of tree models, and the content is
* displayed using widgets instead of cell renderers.
*
* The examples here demonstrate how to use different kinds of
* list models with GtkDropDown, how to use search and how to
* display the selected item differently from the presentation
* in the popup.
*/
#include <gtk/gtk.h>
#define STRING_TYPE_HOLDER (string_holder_get_type ())
G_DECLARE_FINAL_TYPE (StringHolder, string_holder, STRING, HOLDER, GObject)
struct _StringHolder {
GObject parent_instance;
char *title;
char *icon;
char *description;
};
G_DEFINE_TYPE (StringHolder, string_holder, G_TYPE_OBJECT);
static void
string_holder_init (StringHolder *holder)
{
}
static void
string_holder_finalize (GObject *object)
{
StringHolder *holder = STRING_HOLDER (object);
g_free (holder->title);
g_free (holder->icon);
g_free (holder->description);
G_OBJECT_CLASS (string_holder_parent_class)->finalize (object);
}
static void
string_holder_class_init (StringHolderClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = string_holder_finalize;
}
static StringHolder *
string_holder_new (const char *title, const char *icon, const char *description)
{
StringHolder *holder = g_object_new (STRING_TYPE_HOLDER, NULL);
holder->title = g_strdup (title);
holder->icon = g_strdup (icon);
holder->description = g_strdup (description);
return holder;
}
static void
strings_setup_item_single_line (GtkSignalListItemFactory *factory,
GtkListItem *item)
{
GtkWidget *box, *image, *title;
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
image = gtk_image_new ();
title = gtk_label_new ("");
gtk_label_set_xalign (GTK_LABEL (title), 0.0);
gtk_box_append (GTK_BOX (box), image);
gtk_box_append (GTK_BOX (box), title);
g_object_set_data (G_OBJECT (item), "title", title);
g_object_set_data (G_OBJECT (item), "image", image);
gtk_list_item_set_child (item, box);
}
static void
strings_setup_item_full (GtkSignalListItemFactory *factory,
GtkListItem *item)
{
GtkWidget *box, *box2, *image, *title, *description;
image = gtk_image_new ();
title = gtk_label_new ("");
gtk_label_set_xalign (GTK_LABEL (title), 0.0);
description = gtk_label_new ("");
gtk_label_set_xalign (GTK_LABEL (description), 0.0);
gtk_widget_add_css_class (description, "dim-label");
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
box2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
gtk_box_append (GTK_BOX (box), image);
gtk_box_append (GTK_BOX (box), box2);
gtk_box_append (GTK_BOX (box2), title);
gtk_box_append (GTK_BOX (box2), description);
g_object_set_data (G_OBJECT (item), "title", title);
g_object_set_data (G_OBJECT (item), "image", image);
g_object_set_data (G_OBJECT (item), "description", description);
gtk_list_item_set_child (item, box);
}
static void
strings_bind_item (GtkSignalListItemFactory *factory,
GtkListItem *item)
{
GtkWidget *image, *title, *description;
StringHolder *holder;
holder = gtk_list_item_get_item (item);
title = g_object_get_data (G_OBJECT (item), "title");
image = g_object_get_data (G_OBJECT (item), "image");
description = g_object_get_data (G_OBJECT (item), "description");
gtk_label_set_label (GTK_LABEL (title), holder->title);
if (image)
{
gtk_image_set_from_icon_name (GTK_IMAGE (image), holder->icon);
gtk_widget_set_visible (image, holder->icon != NULL);
}
if (description)
{
gtk_label_set_label (GTK_LABEL (description), holder->description);
gtk_widget_set_visible (description , holder->description != NULL);
}
}
static GtkListItemFactory *
strings_factory_new (gboolean full)
{
GtkListItemFactory *factory;
factory = gtk_signal_list_item_factory_new ();
if (full)
g_signal_connect (factory, "setup", G_CALLBACK (strings_setup_item_full), NULL);
else
g_signal_connect (factory, "setup", G_CALLBACK (strings_setup_item_single_line), NULL);
g_signal_connect (factory, "bind", G_CALLBACK (strings_bind_item), NULL);
return factory;
}
static GListModel *
strings_model_new (const char *const *titles,
const char *const *icons,
const char *const *descriptions)
{
GListStore *store;
int i;
store = g_list_store_new (STRING_TYPE_HOLDER);
for (i = 0; titles[i]; i++)
{
StringHolder *holder = string_holder_new (titles[i],
icons ? icons[i] : NULL,
descriptions ? descriptions[i] : NULL);
g_list_store_append (store, holder);
g_object_unref (holder);
}
return G_LIST_MODEL (store);
}
static GtkWidget *
drop_down_new_from_strings (const char *const *titles,
const char *const *icons,
const char *const *descriptions)
{
GtkWidget *widget;
GListModel *model;
GtkListItemFactory *factory;
GtkListItemFactory *list_factory;
g_return_val_if_fail (titles != NULL, NULL);
g_return_val_if_fail (icons == NULL || g_strv_length ((char **)icons) == g_strv_length ((char **)titles), NULL);
g_return_val_if_fail (descriptions == NULL || g_strv_length ((char **)icons) == g_strv_length ((char **)descriptions), NULL);
model = strings_model_new (titles, icons, descriptions);
factory = strings_factory_new (FALSE);
if (icons != NULL || descriptions != NULL)
list_factory = strings_factory_new (TRUE);
else
list_factory = NULL;
widget = g_object_new (GTK_TYPE_DROP_DOWN,
"model", model,
"factory", factory,
"list-factory", list_factory,
NULL);
g_object_unref (model);
g_object_unref (factory);
if (list_factory)
g_object_unref (list_factory);
return widget;
}
static char *
get_family_name (gpointer item)
{
return g_strdup (pango_font_family_get_name (PANGO_FONT_FAMILY (item)));
}
static char *
get_title (gpointer item)
{
return g_strdup (STRING_HOLDER (item)->title);
}
GtkWidget *
do_dropdown (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
GtkWidget *button, *box, *spin, *check;
GListModel *model;
GtkExpression *expression;
const char * const times[] = { "1 minute", "2 minutes", "5 minutes", "20 minutes", NULL };
const char * const many_times[] = {
"1 minute", "2 minutes", "5 minutes", "10 minutes", "15 minutes", "20 minutes",
"25 minutes", "30 minutes", "35 minutes", "40 minutes", "45 minutes", "50 minutes",
"55 minutes", "1 hour", "2 hours", "3 hours", "5 hours", "6 hours", "7 hours",
"8 hours", "9 hours", "10 hours", "11 hours", "12 hours", NULL
};
const char * const device_titles[] = { "Digital Output", "Headphones", "Digital Output", "Analog Output", NULL };
const char * const device_icons[] = { "audio-card-symbolic", "audio-headphones-symbolic", "audio-card-symbolic", "audio-card-symbolic", NULL };
const char * const device_descriptions[] = {
"Built-in Audio", "Built-in audio", "Thinkpad Tunderbolt 3 Dock USB Audio", "Thinkpad Tunderbolt 3 Dock USB Audio", NULL
};
if (!window)
{
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Drop Downs");
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
gtk_widget_set_margin_start (box, 10);
gtk_widget_set_margin_end (box, 10);
gtk_widget_set_margin_top (box, 10);
gtk_widget_set_margin_bottom (box, 10);
gtk_window_set_child (GTK_WINDOW (window), box);
button = gtk_drop_down_new ();
model = G_LIST_MODEL (pango_cairo_font_map_get_default ());
gtk_drop_down_set_model (GTK_DROP_DOWN (button), model);
gtk_drop_down_set_selected (GTK_DROP_DOWN (button), 0);
expression = gtk_cclosure_expression_new (G_TYPE_STRING, NULL,
0, NULL,
(GCallback)get_family_name,
NULL, NULL);
gtk_drop_down_set_expression (GTK_DROP_DOWN (button), expression);
gtk_expression_unref (expression);
gtk_box_append (GTK_BOX (box), button);
spin = gtk_spin_button_new_with_range (-1, g_list_model_get_n_items (G_LIST_MODEL (model)), 1);
gtk_widget_set_halign (spin, GTK_ALIGN_START);
g_object_bind_property (button, "selected", spin, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
gtk_box_append (GTK_BOX (box), spin);
check = gtk_check_button_new_with_label ("Enable search");
g_object_bind_property (button, "enable-search", check, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
gtk_box_append (GTK_BOX (box), check);
g_object_unref (model);
button = drop_down_new_from_strings (times, NULL, NULL);
gtk_box_append (GTK_BOX (box), button);
button = drop_down_new_from_strings (many_times, NULL, NULL);
gtk_drop_down_set_enable_search (GTK_DROP_DOWN (button), TRUE);
expression = gtk_cclosure_expression_new (G_TYPE_STRING, NULL,
0, NULL,
(GCallback)get_title,
NULL, NULL);
gtk_drop_down_set_expression (GTK_DROP_DOWN (button), expression);
gtk_expression_unref (expression);
gtk_box_append (GTK_BOX (box), button);
button = drop_down_new_from_strings (device_titles, device_icons, device_descriptions);
gtk_box_append (GTK_BOX (box), button);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -275,9 +275,6 @@ cell_edited (GtkCellRendererText *cell,
g_array_index (articles, Item, i).product, -1);
}
break;
default:
g_assert_not_reached ();
}
gtk_tree_path_free (path);
@@ -348,28 +345,27 @@ do_editable_cells (GtkWidget *do_widget)
GtkTreeModel *items_model;
GtkTreeModel *numbers_model;
window = gtk_window_new ();
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), "Editable Cells");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
gtk_widget_set_margin_start (vbox, 5);
gtk_widget_set_margin_end (vbox, 5);
gtk_widget_set_margin_top (vbox, 5);
gtk_widget_set_margin_bottom (vbox, 5);
gtk_window_set_child (GTK_WINDOW (window), vbox);
g_object_set (vbox, "margin", 5, NULL);
gtk_container_add (GTK_CONTAINER (window), vbox);
gtk_box_append (GTK_BOX (vbox),
gtk_container_add (GTK_CONTAINER (vbox),
gtk_label_new ("Shopping list (you can edit the cells!)"));
sw = gtk_scrolled_window_new ();
gtk_scrolled_window_set_has_frame (GTK_SCROLLED_WINDOW (sw), TRUE);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
GTK_SHADOW_ETCHED_IN);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_box_append (GTK_BOX (vbox), sw);
gtk_container_add (GTK_CONTAINER (vbox), sw);
/* create models */
items_model = create_items_model ();
@@ -386,22 +382,22 @@ do_editable_cells (GtkWidget *do_widget)
g_object_unref (numbers_model);
g_object_unref (items_model);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), treeview);
gtk_container_add (GTK_CONTAINER (sw), treeview);
/* some buttons */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
gtk_box_append (GTK_BOX (vbox), hbox);
gtk_container_add (GTK_CONTAINER (vbox), hbox);
button = gtk_button_new_with_label ("Add item");
g_signal_connect (button, "clicked",
G_CALLBACK (add_item), treeview);
gtk_box_append (GTK_BOX (hbox), button);
gtk_container_add (GTK_CONTAINER (hbox), button);
button = gtk_button_new_with_label ("Remove item");
g_signal_connect (button, "clicked",
G_CALLBACK (remove_item), treeview);
gtk_box_append (GTK_BOX (hbox), button);
gtk_container_add (GTK_CONTAINER (hbox), button);
gtk_window_set_default_size (GTK_WINDOW (window), 320, 200);
}
@@ -409,7 +405,7 @@ do_editable_cells (GtkWidget *do_widget)
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,4 +1,4 @@
/* Entry/Completion
/* Entry/Entry Completion
*
* GtkEntryCompletion provides a mechanism for adding support for
* completion in GtkEntry.
@@ -9,51 +9,25 @@
#include <gtk/gtk.h>
/* Creates a tree model containing the completions */
static GtkTreeModel *
GtkTreeModel *
create_completion_model (void)
{
const char *strings[] = {
"GNOME",
"gnominious",
"Gnomonic projection",
"Gnosophy",
"total",
"totally",
"toto",
"tottery",
"totterer",
"Totten trust",
"Tottenham hotspurs",
"totipotent",
"totipotency",
"totemism",
"totem pole",
"Totara",
"totalizer",
"totalizator",
"totalitarianism",
"total parenteral nutrition",
"total eclipse",
"Totipresence",
"Totipalmi",
"zombie",
"aæx",
"aæy",
"aæz",
NULL
};
int i;
GtkListStore *store;
GtkTreeIter iter;
store = gtk_list_store_new (1, G_TYPE_STRING);
for (i = 0; strings[i]; i++)
{
/* Append one word */
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0, strings[i], -1);
}
/* Append one word */
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0, "GNOME", -1);
/* Append another word */
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0, "total", -1);
/* And another word */
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0, "totally", -1);
return GTK_TREE_MODEL (store);
}
@@ -71,27 +45,26 @@ do_entry_completion (GtkWidget *do_widget)
if (!window)
{
window = gtk_window_new ();
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), "Completion");
gtk_window_set_title (GTK_WINDOW (window), "Entry Completion");
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
gtk_widget_set_margin_start (vbox, 5);
gtk_widget_set_margin_end (vbox, 5);
gtk_widget_set_margin_top (vbox, 5);
gtk_widget_set_margin_bottom (vbox, 5);
gtk_window_set_child (GTK_WINDOW (window), vbox);
g_object_set (vbox, "margin", 5, NULL);
gtk_container_add (GTK_CONTAINER (window), vbox);
label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (label), "Try writing <b>total</b> or <b>gnome</b> for example.");
gtk_box_append (GTK_BOX (vbox), label);
gtk_label_set_markup (GTK_LABEL (label), "Completion demo, try writing <b>total</b> or <b>gnome</b> for example.");
gtk_container_add (GTK_CONTAINER (vbox), label);
/* Create our entry */
entry = gtk_entry_new ();
gtk_box_append (GTK_BOX (vbox), entry);
gtk_container_add (GTK_CONTAINER (vbox), entry);
/* Create the completion object */
completion = gtk_entry_completion_new ();
@@ -107,15 +80,12 @@ do_entry_completion (GtkWidget *do_widget)
/* Use model column 0 as the text column */
gtk_entry_completion_set_text_column (completion, 0);
gtk_entry_completion_set_inline_completion (completion, TRUE);
gtk_entry_completion_set_inline_selection (completion, TRUE);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,8 +1,8 @@
/* Entry/Undo and Redo
/* Entry/Entry Undo
*
* GtkEntry can provide basic Undo/Redo support using standard keyboard
* accelerators such as Control+z to undo and Control+Shift+z to redo.
* Additionally, Control+y can be used to redo.
* accelerators such as Primary+z to undo and Primary+Shift+z to redo.
* Additionally, Primary+y can be used to redo.
*
* Use gtk_entry_set_enable_undo() to enable undo/redo support.
*/
@@ -20,35 +20,33 @@ do_entry_undo (GtkWidget *do_widget)
if (!window)
{
window = gtk_window_new ();
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), "Undo and Redo");
gtk_window_set_title (GTK_WINDOW (window), "Entry Undo");
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
gtk_widget_set_margin_start (vbox, 5);
gtk_widget_set_margin_end (vbox, 5);
gtk_widget_set_margin_top (vbox, 5);
gtk_widget_set_margin_bottom (vbox, 5);
gtk_window_set_child (GTK_WINDOW (window), vbox);
g_object_set (vbox, "margin", 5, NULL);
gtk_container_add (GTK_CONTAINER (window), vbox);
label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (label),
"Use Primary+z or Primary+Shift+z to undo or redo changes");
gtk_box_append (GTK_BOX (vbox), label);
gtk_container_add (GTK_CONTAINER (vbox), label);
/* Create our entry */
entry = gtk_entry_new ();
gtk_editable_set_enable_undo (GTK_EDITABLE (entry), TRUE);
gtk_box_append (GTK_BOX (vbox), entry);
gtk_container_add (GTK_CONTAINER (vbox), entry);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -15,7 +15,7 @@ static GtkWidget *window = NULL;
static void
response_cb (GtkDialog *dialog, gint response_id)
{
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
window = NULL;
}
@@ -57,9 +57,9 @@ do_expander (GtkWidget *do_widget)
expander = gtk_expander_new ("Details:");
gtk_widget_set_vexpand (expander, TRUE);
sw = gtk_scrolled_window_new ();
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (sw), 100);
gtk_scrolled_window_set_has_frame (GTK_SCROLLED_WINDOW (sw), TRUE);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC);
@@ -78,9 +78,9 @@ do_expander (GtkWidget *do_widget)
"A second paragraph will contain even more "
"innuendo, just to make you scroll down or "
"resize the window. Do it already !", -1);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), tv);
gtk_expander_set_child (GTK_EXPANDER (expander), sw);
gtk_box_append (GTK_BOX (area), expander);
gtk_container_add (GTK_CONTAINER (sw), tv);
gtk_container_add (GTK_CONTAINER (expander), sw);
gtk_container_add (GTK_CONTAINER (area), expander);
g_signal_connect (expander, "notify::expanded",
G_CALLBACK (expander_cb), window);
@@ -90,7 +90,7 @@ do_expander (GtkWidget *do_widget)
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -125,7 +125,8 @@ do_filtermodel (GtkWidget *do_widget)
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
store = (GtkListStore*)gtk_builder_get_object (builder, "liststore1");
@@ -198,7 +199,7 @@ do_filtermodel (GtkWidget *do_widget)
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -31,10 +31,7 @@
<property name="title" translatable="yes">Filter Model</property>
<child>
<object class="GtkGrid" id="grid1">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="row-spacing">10</property>
<property name="column-spacing">10</property>
<property name="column-homogeneous">1</property>
@@ -56,6 +53,7 @@
</child>
<child>
<object class="GtkTreeView" id="treeview1">
<property name="can-focus">1</property>
<property name="model">liststore1</property>
<property name="headers-clickable">0</property>
<child internal-child="selection">
@@ -94,6 +92,7 @@
</child>
<child>
<object class="GtkTreeView" id="treeview2">
<property name="can-focus">1</property>
<property name="headers-clickable">0</property>
<property name="search-column">0</property>
<child internal-child="selection">
@@ -176,6 +175,7 @@
</child>
<child>
<object class="GtkTreeView" id="treeview3">
<property name="can-focus">1</property>
<property name="headers-clickable">0</property>
<property name="search-column">0</property>
<child internal-child="selection">

View File

@@ -22,11 +22,29 @@ gsize n_icon_names = 0;
static void
init_icon_names (GtkIconTheme *theme)
{
GPtrArray *icons;
GList *l, *icon_list;
if (icon_names)
return;
icon_names = gtk_icon_theme_get_icon_names (theme);
n_icon_names = g_strv_length (icon_names);
icon_list = gtk_icon_theme_list_icons (theme, NULL);
icons = g_ptr_array_new ();
for (l = icon_list; l; l = l->next)
{
if (g_str_has_suffix (l->data, "symbolic"))
continue;
g_ptr_array_add (icons, g_strdup (l->data));
}
n_icon_names = icons->len;
g_ptr_array_add (icons, NULL); /* NULL-terminate the array */
icon_names = (char **) g_ptr_array_free (icons, FALSE);
/* don't free strings, we assigned them to the array */
g_list_free_full (icon_list, g_free);
}
static const char *
@@ -37,16 +55,13 @@ get_random_icon_name (GtkIconTheme *theme)
return icon_names[g_random_int_range(0, n_icon_names)];
}
/* Can't be static because it's also used in iconscroll.c */
GtkWidget *
create_icon (void)
{
GtkWidget *image;
image = gtk_image_new ();
image = gtk_image_new_from_icon_name (get_random_icon_name (gtk_icon_theme_get_default ()));
gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
gtk_image_set_from_icon_name (GTK_IMAGE (image),
get_random_icon_name (gtk_icon_theme_get_for_display (gtk_widget_get_display (image))));
return image;
}
@@ -62,7 +77,7 @@ create_blurred_button (void)
{
GtkWidget *w = gtk_button_new ();
gtk_widget_add_css_class (w, "blurred-button");
gtk_style_context_add_class (gtk_widget_get_style_context (w), "blurred-button");
return w;
}
@@ -159,9 +174,9 @@ static GtkWidget *
create_menu_button (void)
{
GtkWidget *w = gtk_menu_button_new ();
GtkWidget *popover = gtk_popover_new ();
GtkWidget *popover = gtk_popover_new (NULL);
gtk_popover_set_child (GTK_POPOVER (popover), gtk_button_new_with_label ("Hey!"));
gtk_container_add (GTK_CONTAINER (popover), gtk_button_new_with_label ("Hey!"));
gtk_popover_set_autohide (GTK_POPOVER (popover), FALSE);
gtk_menu_button_set_popover (GTK_MENU_BUTTON (w), popover);
g_signal_connect (w, "map", G_CALLBACK (mapped), NULL);
@@ -194,7 +209,7 @@ static void
set_widget_type (GtkFishbowl *fishbowl,
int widget_type_index)
{
GtkWidget *window;
GtkWidget *window, *headerbar;
if (widget_type_index == selected_widget_type)
return;
@@ -205,8 +220,9 @@ set_widget_type (GtkFishbowl *fishbowl,
widget_types[selected_widget_type].create_func);
window = GTK_WIDGET (gtk_widget_get_root (GTK_WIDGET (fishbowl)));
gtk_window_set_title (GTK_WINDOW (window),
widget_types[selected_widget_type].name);
headerbar = gtk_window_get_titlebar (GTK_WINDOW (window));
gtk_header_bar_set_title (GTK_HEADER_BAR (headerbar),
widget_types[selected_widget_type].name);
}
void
@@ -281,13 +297,15 @@ do_fishbowl (GtkWidget *do_widget)
builder = gtk_builder_new_from_resource ("/fishbowl/fishbowl.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
bowl = GTK_WIDGET (gtk_builder_get_object (builder, "bowl"));
selected_widget_type = -1;
set_widget_type (GTK_FISHBOWL (bowl), 0);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
gtk_widget_realize (window);
g_object_unref (builder);
@@ -296,7 +314,7 @@ do_fishbowl (GtkWidget *do_widget)
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -6,6 +6,7 @@
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkBox">
<style>
@@ -38,7 +39,7 @@
<child type="end">
<object class="GtkToggleButton" id="changes_allow">
<property name="icon-name">changes-allow</property>
<property name="has-frame">0</property>
<property name="relief">none</property>
<signal name="notify::active" handler="fishbowl_changes_toggled_cb"/>
</object>
</child>
@@ -47,7 +48,6 @@
<child>
<object class="GtkFishbowl" id="bowl">
<property name="visible">True</property>
<property name="overflow">hidden</property>
<property name="animating">True</property>
<property name="benchmark" bind-source="changes_allow" bind-property="active" bind-flags="invert-boolean | sync-create"/>
</object>

View File

@@ -1,4 +1,4 @@
/* Fixed Layout
/* Fixed layout
*
* GtkFixed is a container that allows placing and transforming
* widgets manually.
@@ -52,8 +52,8 @@ create_faces (void)
/* Add a face */
faces[i].face = gtk_frame_new (NULL);
gtk_widget_set_size_request (faces[i].face, face_size, face_size);
gtk_widget_add_css_class (faces[i].face, faces[i].css_class);
gtk_fixed_put (GTK_FIXED (fixed), faces[i].face, 0, 0);
gtk_style_context_add_class (gtk_widget_get_style_context (faces[i].face), faces[i].css_class);
gtk_container_add (GTK_CONTAINER (fixed), faces[i].face);
/* Set up the transformation for each face */
transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (w, h));
@@ -124,22 +124,22 @@ create_demo_window (GtkWidget *do_widget)
{
GtkWidget *window, *sw, *fixed, *cube;
window = gtk_window_new ();
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), "Fixed Layout");
gtk_window_set_title (GTK_WINDOW (window), "Fixed layout");
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL);
sw = gtk_scrolled_window_new ();
gtk_window_set_child (GTK_WINDOW (window), sw);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (window), sw);
fixed = gtk_fixed_new ();
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), fixed);
gtk_container_add (GTK_CONTAINER (sw), fixed);
gtk_widget_set_halign (GTK_WIDGET (fixed), GTK_ALIGN_CENTER);
gtk_widget_set_valign (GTK_WIDGET (fixed), GTK_ALIGN_CENTER);
cube = create_faces ();
gtk_fixed_put (GTK_FIXED (fixed), cube, 0, 0);
gtk_container_add (GTK_CONTAINER (fixed), cube);
gtk_widget_set_overflow (fixed, GTK_OVERFLOW_VISIBLE);
provider = gtk_css_provider_new ();
@@ -161,7 +161,7 @@ do_fixed (GtkWidget *do_widget)
if (!gtk_widget_get_visible (demo_window))
gtk_widget_show (demo_window);
else
gtk_window_destroy (GTK_WINDOW (demo_window));
gtk_widget_destroy (demo_window);
return demo_window;
}

View File

@@ -1,10 +1,9 @@
/* Flow Box
*
* GtkFlowBox allows flexible and responsive grids which reflow
* as needed and support sorting and filtering. The children of
* a GtkFlowBox are regular widgets
* as needed and support sorting and filtering.
*
* The dataset used here has 665 colors.
* The children of a GtkFlowBox are regular widgets
*/
#include <gtk/gtk.h>
@@ -38,7 +37,7 @@ color_swatch_new (const gchar *color)
gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (area), 24);
gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (area), 24);
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (area), draw_color, (gpointer) color, NULL);
gtk_button_set_child (GTK_BUTTON (button), area);
gtk_container_add (GTK_CONTAINER (button), area);
return button;
}
@@ -720,31 +719,33 @@ do_flowbox (GtkWidget *do_widget)
if (!window)
{
window = gtk_window_new ();
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), "Flow Box");
gtk_window_set_default_size (GTK_WINDOW (window), 400, 600);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
scrolled = gtk_scrolled_window_new ();
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
scrolled = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
flowbox = gtk_flow_box_new ();
gtk_widget_set_valign (flowbox, GTK_ALIGN_START);
gtk_flow_box_set_max_children_per_line (GTK_FLOW_BOX (flowbox), 30);
gtk_flow_box_set_selection_mode (GTK_FLOW_BOX (flowbox), GTK_SELECTION_NONE);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled), flowbox);
gtk_window_set_child (GTK_WINDOW (window), scrolled);
gtk_container_add (GTK_CONTAINER (scrolled), flowbox);
gtk_container_add (GTK_CONTAINER (window), scrolled);
for (i = 0; colors[i]; i++)
gtk_flow_box_insert (GTK_FLOW_BOX (flowbox), color_swatch_new (colors[i]), -1);
gtk_container_add (GTK_CONTAINER (flowbox), color_swatch_new (colors[i]));
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -4,11 +4,13 @@
<object class="GtkWindow" id="window">
<property name="default-width">600</property>
<property name="default-height">500</property>
<property name="title">Font Explorer</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="show-title-buttons">1</property>
<property name="title">Font Explorer</property>
<child>
<object class="GtkButton" id="reset">
<property name="can-focus">1</property>
<property name="receives-default">1</property>
<property name="tooltip-text">Reset</property>
<signal name="clicked" handler="font_features_reset_features" swapped="no"/>
@@ -25,19 +27,18 @@
<object class="GtkBox">
<child>
<object class="GtkScrolledWindow">
<property name="can-focus">1</property>
<property name="hscrollbar-policy">never</property>
<child>
<object class="GtkViewport">
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin">10</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkFontButton" id="font">
<property name="can-focus">1</property>
<property name="receives-default">1</property>
<property name="font">Sans 12</property>
<property name="level">family|style|size|variations|features</property>
@@ -60,6 +61,7 @@
<property name="orientation">vertical</property>
<child>
<object class="GtkComboBox" id="script_lang">
<property name="can-focus">1</property>
<property name="margin-top">10</property>
<signal name="changed" handler="font_features_script_changed" swapped="no"/>
<child>
@@ -107,10 +109,7 @@
<property name="orientation">vertical</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<property name="margin-start">20</property>
<property name="margin-end">20</property>
<property name="margin-top">20</property>
<property name="margin-bottom">20</property>
<property name="margin">20</property>
<property name="spacing">20</property>
<child>
<object class="GtkStack" id="stack">

View File

@@ -25,14 +25,14 @@
#define MAKE_TAG(a,b,c,d) (unsigned int)(((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
static GtkWidget *the_label;
static GtkWidget *label;
static GtkWidget *settings;
static GtkWidget *description;
static GtkWidget *font;
static GtkWidget *script_lang;
static GtkWidget *resetbutton;
static GtkWidget *stack;
static GtkWidget *the_entry;
static GtkWidget *entry;
static GtkWidget *variations_heading;
static GtkWidget *variations_grid;
static GtkWidget *instance_combo;
@@ -194,7 +194,7 @@ add_check_group (GtkWidget *box,
pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
gtk_label_set_attributes (GTK_LABEL (label), attrs);
pango_attr_list_unref (attrs);
gtk_box_append (GTK_BOX (group), label);
gtk_container_add (GTK_CONTAINER (group), label);
for (i = 0; tags[i]; i++)
{
@@ -211,7 +211,7 @@ add_check_group (GtkWidget *box,
g_signal_connect (feat, "notify::inconsistent", G_CALLBACK (update_display), NULL);
g_signal_connect (feat, "clicked", G_CALLBACK (feat_clicked), NULL);
gtk_box_append (GTK_BOX (group), feat);
gtk_container_add (GTK_CONTAINER (group), feat);
item = g_new (FeatureItem, 1);
item->name = tags[i];
@@ -223,7 +223,7 @@ add_check_group (GtkWidget *box,
feature_items = g_list_prepend (feature_items, item);
}
gtk_box_append (GTK_BOX (box), group);
gtk_container_add (GTK_CONTAINER (box), group);
}
static void
@@ -248,7 +248,7 @@ add_radio_group (GtkWidget *box,
pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
gtk_label_set_attributes (GTK_LABEL (label), attrs);
pango_attr_list_unref (attrs);
gtk_box_append (GTK_BOX (group), label);
gtk_container_add (GTK_CONTAINER (group), label);
for (i = 0; tags[i]; i++)
{
@@ -268,7 +268,7 @@ add_radio_group (GtkWidget *box,
g_signal_connect (feat, "notify::active", G_CALLBACK (update_display), NULL);
g_object_set_data (G_OBJECT (feat), "default", group_button);
gtk_box_append (GTK_BOX (group), feat);
gtk_container_add (GTK_CONTAINER (group), feat);
item = g_new (FeatureItem, 1);
item->name = tags[i];
@@ -280,7 +280,7 @@ add_radio_group (GtkWidget *box,
feature_items = g_list_prepend (feature_items, item);
}
gtk_box_append (GTK_BOX (box), group);
gtk_container_add (GTK_CONTAINER (box), group);
}
static void
@@ -301,9 +301,9 @@ update_display (void)
char *font_desc;
char *features;
text = gtk_editable_get_text (GTK_EDITABLE (the_entry));
text = gtk_editable_get_text (GTK_EDITABLE (entry));
if (gtk_label_get_selection_bounds (GTK_LABEL (the_label), &ins, &bound))
if (gtk_label_get_selection_bounds (GTK_LABEL (label), &ins, &bound))
{
start = g_utf8_offset_to_pointer (text, ins) - text;
end = g_utf8_offset_to_pointer (text, bound) - text;
@@ -409,8 +409,8 @@ update_display (void)
gtk_label_set_text (GTK_LABEL (description), font_desc);
gtk_label_set_text (GTK_LABEL (settings), features);
gtk_label_set_text (GTK_LABEL (the_label), text);
gtk_label_set_attributes (GTK_LABEL (the_label), attrs);
gtk_label_set_text (GTK_LABEL (label), text);
gtk_label_set_attributes (GTK_LABEL (label), attrs);
g_free (font_desc);
pango_font_description_free (desc);
@@ -548,7 +548,7 @@ update_script_combo (void)
{
const char *langname;
char langbuf[5];
GtkTreeIter tree_iter;
GtkTreeIter iter;
if (pair->lang_tag == HB_OT_TAG_DEFAULT_LANGUAGE)
langname = NC_("Language", "Default");
@@ -563,7 +563,7 @@ update_script_combo (void)
}
}
gtk_list_store_insert_with_values (store, &tree_iter, -1,
gtk_list_store_insert_with_values (store, &iter, -1,
0, langname,
1, pair->script_index,
2, pair->lang_index,
@@ -572,7 +572,7 @@ update_script_combo (void)
if (pair->lang_tag == active)
{
have_active = TRUE;
active_iter = tree_iter;
active_iter = iter;
}
}
@@ -751,7 +751,7 @@ add_font_variations (GString *s)
GHashTableIter iter;
Axis *axis;
char buf[G_ASCII_DTOSTR_BUF_SIZE];
const char *sep = "";
char *sep = "";
g_hash_table_iter_init (&iter, axes);
while (g_hash_table_iter_next (&iter, (gpointer *)NULL, (gpointer *)&axis))
@@ -1025,7 +1025,7 @@ denorm_coord (hb_ot_var_axis_info_t *axis, int coord)
static void
update_font_variations (void)
{
GtkWidget *child;
GtkWidget *child, *next;
PangoFont *pango_font = NULL;
hb_font_t *hb_font;
hb_face_t *hb_face;
@@ -1037,8 +1037,12 @@ update_font_variations (void)
int i;
child = gtk_widget_get_first_child (variations_grid);
while ((child = gtk_widget_get_first_child (variations_grid)))
gtk_grid_remove (GTK_GRID (variations_grid), child);
while (child != NULL)
{
next = gtk_widget_get_next_sibling (child);
gtk_widget_destroy (child);
child = next;
}
instance_combo = NULL;
@@ -1125,7 +1129,7 @@ font_features_reset_features (void)
{
GList *l;
gtk_label_select_region (GTK_LABEL (the_label), 0, 0);
gtk_label_select_region (GTK_LABEL (label), 0, 0);
g_list_free_full (ranges, free_range);
ranges = NULL;
@@ -1152,9 +1156,9 @@ static char *text;
static void
switch_to_entry (void)
{
text = g_strdup (gtk_editable_get_text (GTK_EDITABLE (the_entry)));
text = g_strdup (gtk_editable_get_text (GTK_EDITABLE (entry)));
gtk_stack_set_visible_child_name (GTK_STACK (stack), "entry");
gtk_widget_grab_focus (the_entry);
gtk_widget_grab_focus (entry);
}
static void
@@ -1213,20 +1217,20 @@ do_font_features (GtkWidget *do_widget)
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
feature_list = GTK_WIDGET (gtk_builder_get_object (builder, "feature_list"));
the_label = GTK_WIDGET (gtk_builder_get_object (builder, "label"));
label = GTK_WIDGET (gtk_builder_get_object (builder, "label"));
settings = GTK_WIDGET (gtk_builder_get_object (builder, "settings"));
description = GTK_WIDGET (gtk_builder_get_object (builder, "description"));
resetbutton = GTK_WIDGET (gtk_builder_get_object (builder, "reset"));
font = GTK_WIDGET (gtk_builder_get_object (builder, "font"));
script_lang = GTK_WIDGET (gtk_builder_get_object (builder, "script_lang"));
stack = GTK_WIDGET (gtk_builder_get_object (builder, "stack"));
the_entry = GTK_WIDGET (gtk_builder_get_object (builder, "entry"));
entry = GTK_WIDGET (gtk_builder_get_object (builder, "entry"));
edit_toggle = GTK_WIDGET (gtk_builder_get_object (builder, "edit_toggle"));
controller = gtk_event_controller_key_new ();
g_object_set_data_full (G_OBJECT (the_entry), "controller", g_object_ref (controller), g_object_unref);
g_signal_connect (controller, "key-pressed", G_CALLBACK (entry_key_press), the_entry);
gtk_widget_add_controller (the_entry, controller);
g_object_set_data_full (G_OBJECT (entry), "controller", controller, g_object_unref);
g_signal_connect (controller, "key-pressed", G_CALLBACK (entry_key_press), entry);
gtk_widget_add_controller (entry, controller);
add_check_group (feature_list, _("Kerning"), (const char *[]){ "kern", NULL });
add_check_group (feature_list, _("Ligatures"), (const char *[]){ "liga",
@@ -1329,17 +1333,16 @@ do_font_features (GtkWidget *do_widget)
font_features_font_changed ();
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
g_object_unref (builder);
update_display ();
}
if (!gtk_widget_get_visible (window))
gtk_window_present (GTK_WINDOW (window));
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -19,6 +19,8 @@
#include "fontplane.h"
#include "gtk.h"
enum {
PROP_0,
PROP_WEIGHT_ADJUSTMENT,
@@ -140,6 +142,17 @@ update_value (GtkFontPlane *plane,
gtk_widget_queue_draw (widget);
}
static void
hold_action (GtkGestureLongPress *gesture,
gdouble x,
gdouble y,
GtkFontPlane *plane)
{
gboolean handled;
g_signal_emit_by_name (plane, "popup-menu", &handled);
}
static void
plane_drag_gesture_begin (GtkGestureDrag *gesture,
gdouble start_x,
@@ -150,6 +163,13 @@ plane_drag_gesture_begin (GtkGestureDrag *gesture,
button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
if (button == GDK_BUTTON_SECONDARY)
{
gboolean handled;
g_signal_emit_by_name (plane, "popup-menu", &handled);
}
if (button != GDK_BUTTON_PRIMARY)
{
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
@@ -189,6 +209,8 @@ gtk_font_plane_init (GtkFontPlane *plane)
{
GtkGesture *gesture;
gtk_widget_set_can_focus (GTK_WIDGET (plane), TRUE);
gesture = gtk_gesture_drag_new ();
g_signal_connect (gesture, "drag-begin",
G_CALLBACK (plane_drag_gesture_begin), plane);
@@ -198,6 +220,13 @@ gtk_font_plane_init (GtkFontPlane *plane)
G_CALLBACK (plane_drag_gesture_end), plane);
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), 0);
gtk_widget_add_controller (GTK_WIDGET (plane), GTK_EVENT_CONTROLLER (gesture));
gesture = gtk_gesture_long_press_new ();
g_signal_connect (gesture, "pressed",
G_CALLBACK (hold_action), plane);
gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (gesture),
TRUE);
gtk_widget_add_controller (GTK_WIDGET (plane), GTK_EVENT_CONTROLLER (gesture));
}
static void

View File

@@ -43,6 +43,7 @@ update_image (void)
cairo_font_options_t *fopt;
cairo_hint_style_t hintstyle;
cairo_hint_metrics_t hintmetrics;
int i;
if (!context)
context = gtk_widget_create_pango_context (image);
@@ -115,7 +116,6 @@ update_image (void)
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (show_grid)))
{
int i;
cairo_set_source_rgba (cr, 0.2, 0, 0, 0.2);
for (i = 1; i < ink.height + 20; i++)
{
@@ -281,7 +281,7 @@ do_fontrendering (GtkWidget *do_widget)
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -165,11 +165,10 @@
</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>
@@ -184,7 +183,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>
@@ -193,7 +192,7 @@
<child>
<object class="GtkScrolledWindow">
<property name="propagate-natural-height">1</property>
<property name="has-frame">1</property>
<property name="shadow-type">in</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<child>

View File

@@ -0,0 +1,984 @@
/* Foreign drawing
*
* Many applications can't use GTK widgets, for a variety of reasons,
* but still want their user interface to appear integrated with the
* rest of the desktop, and follow GTK themes. This demo shows how to
* use GtkStyleContext and the gtk_render_ APIs to achieve this.
*
* Note that this is a very simple, non-interactive example.
*/
#include <gtk/gtk.h>
#include <string.h>
static void
append_element (GtkWidgetPath *path,
const char *selector)
{
static const struct {
const char *name;
GtkStateFlags state_flag;
} pseudo_classes[] = {
{ "active", GTK_STATE_FLAG_ACTIVE },
{ "hover", GTK_STATE_FLAG_PRELIGHT },
{ "selected", GTK_STATE_FLAG_SELECTED },
{ "disabled", GTK_STATE_FLAG_INSENSITIVE },
{ "indeterminate", GTK_STATE_FLAG_INCONSISTENT },
{ "focus", GTK_STATE_FLAG_FOCUSED },
{ "backdrop", GTK_STATE_FLAG_BACKDROP },
{ "dir(ltr)", GTK_STATE_FLAG_DIR_LTR },
{ "dir(rtl)", GTK_STATE_FLAG_DIR_RTL },
{ "link", GTK_STATE_FLAG_LINK },
{ "visited", GTK_STATE_FLAG_VISITED },
{ "checked", GTK_STATE_FLAG_CHECKED },
{ "drop(active)", GTK_STATE_FLAG_DROP_ACTIVE }
};
const char *next;
char *name;
char type;
guint i;
next = strpbrk (selector, "#.:");
if (next == NULL)
next = selector + strlen (selector);
name = g_strndup (selector, next - selector);
if (g_ascii_isupper (selector[0]))
{
GType gtype;
gtype = g_type_from_name (name);
if (gtype == G_TYPE_INVALID)
{
g_critical ("Unknown type name `%s'", name);
g_free (name);
return;
}
gtk_widget_path_append_type (path, gtype);
}
else
{
/* Omit type, we're using name */
gtk_widget_path_append_type (path, G_TYPE_NONE);
gtk_widget_path_iter_set_object_name (path, -1, name);
}
g_free (name);
while (*next != '\0')
{
type = *next;
selector = next + 1;
next = strpbrk (selector, "#.:");
if (next == NULL)
next = selector + strlen (selector);
name = g_strndup (selector, next - selector);
switch (type)
{
case '#':
gtk_widget_path_iter_set_name (path, -1, name);
break;
case '.':
gtk_widget_path_iter_add_class (path, -1, name);
break;
case ':':
for (i = 0; i < G_N_ELEMENTS (pseudo_classes); i++)
{
if (g_str_equal (pseudo_classes[i].name, name))
{
gtk_widget_path_iter_set_state (path,
-1,
gtk_widget_path_iter_get_state (path, -1)
| pseudo_classes[i].state_flag);
break;
}
}
if (i == G_N_ELEMENTS (pseudo_classes))
g_critical ("Unknown pseudo-class :%s", name);
break;
default:
g_assert_not_reached ();
break;
}
g_free (name);
}
}
static GtkStyleContext *
create_context_for_path (GtkWidgetPath *path,
GtkStyleContext *parent)
{
GtkStyleContext *context;
context = gtk_style_context_new ();
gtk_style_context_set_path (context, path);
gtk_style_context_set_parent (context, parent);
/* Unfortunately, we have to explicitly set the state again here
* for it to take effect
*/
gtk_style_context_set_state (context, gtk_widget_path_iter_get_state (path, -1));
gtk_widget_path_unref (path);
return context;
}
static GtkStyleContext *
get_style (GtkStyleContext *parent,
const char *selector)
{
GtkWidgetPath *path;
if (parent)
path = gtk_widget_path_copy (gtk_style_context_get_path (parent));
else
path = gtk_widget_path_new ();
append_element (path, selector);
return create_context_for_path (path, parent);
}
static GtkStyleContext *
get_style_with_siblings (GtkStyleContext *parent,
const char *selector,
const char **siblings,
gint position)
{
GtkWidgetPath *path, *siblings_path;
guint i;
if (parent)
path = gtk_widget_path_copy (gtk_style_context_get_path (parent));
else
path = gtk_widget_path_new ();
siblings_path = gtk_widget_path_new ();
for (i = 0; siblings[i]; i++)
append_element (siblings_path, siblings[i]);
gtk_widget_path_append_with_siblings (path, siblings_path, position);
gtk_widget_path_unref (siblings_path);
return create_context_for_path (path, parent);
}
static void
draw_style_common (GtkStyleContext *context,
cairo_t *cr,
gint x,
gint y,
gint width,
gint height,
gint *contents_x,
gint *contents_y,
gint *contents_width,
gint *contents_height)
{
GtkBorder margin, border, padding;
int min_width, min_height;
gtk_style_context_get_margin (context, &margin);
gtk_style_context_get_border (context, &border);
gtk_style_context_get_padding (context, &padding);
gtk_style_context_get (context,
"min-width", &min_width,
"min-height", &min_height,
NULL);
x += margin.left;
y += margin.top;
width -= margin.left + margin.right;
height -= margin.top + margin.bottom;
width = MAX (width, min_width);
height = MAX (height, min_height);
gtk_render_background (context, cr, x, y, width, height);
gtk_render_frame (context, cr, x, y, width, height);
if (contents_x)
*contents_x = x + border.left + padding.left;
if (contents_y)
*contents_y = y + border.top + padding.top;
if (contents_width)
*contents_width = width - border.left - border.right - padding.left - padding.right;
if (contents_height)
*contents_height = height - border.top - border.bottom - padding.top - padding.bottom;
}
static void
query_size (GtkStyleContext *context,
gint *width,
gint *height)
{
GtkBorder margin, border, padding;
int min_width, min_height;
gtk_style_context_get_margin (context, &margin);
gtk_style_context_get_border (context, &border);
gtk_style_context_get_padding (context, &padding);
gtk_style_context_get (context,
"min-width", &min_width,
"min-height", &min_height,
NULL);
min_width += margin.left + margin.right + border.left + border.right + padding.left + padding.right;
min_height += margin.top + margin.bottom + border.top + border.bottom + padding.top + padding.bottom;
if (width)
*width = MAX (*width, min_width);
if (height)
*height = MAX (*height, min_height);
}
static void
draw_menu (GtkWidget *widget,
cairo_t *cr,
gint x,
gint y,
gint width,
gint *height)
{
GtkStyleContext *menu_context;
GtkStyleContext *menuitem_context;
GtkStyleContext *hovermenuitem_context;
GtkStyleContext *hoveredarrowmenuitem_context;
GtkStyleContext *arrowmenuitem_context;
GtkStyleContext *checkmenuitem_context;
GtkStyleContext *disabledarrowmenuitem_context;
GtkStyleContext *disabledcheckmenuitem_context;
GtkStyleContext *radiomenuitem_context;
GtkStyleContext *disablemenuitem_context;
GtkStyleContext *disabledradiomenuitem_context;
GtkStyleContext *separatormenuitem_context;
gint menuitem1_height, menuitem2_height, menuitem3_height, menuitem4_height, menuitem5_height;
gint contents_x, contents_y, contents_width, contents_height;
gint menu_x, menu_y, menu_width, menu_height;
gint arrow_width, arrow_height, arrow_size;
gint toggle_x, toggle_y, toggle_width, toggle_height;
/* This information is taken from the GtkMenu docs, see "CSS nodes" */
menu_context = get_style (gtk_widget_get_style_context(widget), "menu");
hovermenuitem_context = get_style (menu_context, "menuitem:hover");
hoveredarrowmenuitem_context = get_style (hovermenuitem_context, "arrow.right:dir(ltr)");
menuitem_context = get_style (menu_context, "menuitem");
arrowmenuitem_context = get_style (menuitem_context, "arrow:dir(rtl)");
disablemenuitem_context = get_style (menu_context, "menuitem:disabled");
disabledarrowmenuitem_context = get_style (disablemenuitem_context, "arrow:dir(rtl)");
checkmenuitem_context = get_style (menuitem_context, "check:checked");
disabledcheckmenuitem_context = get_style (disablemenuitem_context, "check");
separatormenuitem_context = get_style (menu_context, "separator:disabled");
radiomenuitem_context = get_style (menuitem_context, "radio:checked");
disabledradiomenuitem_context = get_style (disablemenuitem_context, "radio");
*height = 0;
query_size (menu_context, NULL, height);
menuitem1_height = 0;
query_size (hovermenuitem_context, NULL, &menuitem1_height);
query_size (hoveredarrowmenuitem_context, NULL, &menuitem1_height);
*height += menuitem1_height;
menuitem2_height = 0;
query_size (menu_context, NULL, &menuitem5_height);
query_size (menuitem_context, NULL, &menuitem2_height);
query_size (arrowmenuitem_context, NULL, &menuitem2_height);
query_size (disabledarrowmenuitem_context, NULL, &menuitem2_height);
*height += menuitem2_height;
menuitem3_height = 0;
query_size (menu_context, NULL, &menuitem5_height);
query_size (menuitem_context, NULL, &menuitem3_height);
query_size (checkmenuitem_context, NULL, &menuitem3_height);
query_size (disabledcheckmenuitem_context, NULL, &menuitem3_height);
*height += menuitem3_height;
menuitem4_height = 0;
query_size (menu_context, NULL, &menuitem5_height);
query_size (separatormenuitem_context, NULL, &menuitem4_height);
*height += menuitem4_height;
menuitem5_height = 0;
query_size (menu_context, NULL, &menuitem5_height);
query_size (menuitem_context, NULL, &menuitem5_height);
query_size (radiomenuitem_context, NULL, &menuitem5_height);
query_size (disabledradiomenuitem_context, NULL, &menuitem5_height);
*height += menuitem5_height;
draw_style_common (menu_context, cr, x, y, width, *height,
&menu_x, &menu_y, &menu_width, &menu_height);
/* Hovered with right arrow */
gtk_style_context_get (hoveredarrowmenuitem_context,
"min-width", &arrow_width, "min-height", &arrow_height, NULL);
arrow_size = MIN (arrow_width, arrow_height);
draw_style_common (hovermenuitem_context, cr, menu_x, menu_y, menu_width, menuitem1_height,
&contents_x, &contents_y, &contents_width, &contents_height);
gtk_render_arrow (hoveredarrowmenuitem_context, cr, G_PI / 2,
contents_x + contents_width - arrow_size,
contents_y + (contents_height - arrow_size) / 2, arrow_size);
/* Left arrow sensitive, and right arrow insensitive */
draw_style_common (menuitem_context, cr, menu_x, menu_y + menuitem1_height, menu_width, menuitem2_height,
&contents_x, &contents_y, &contents_width, &contents_height);
gtk_style_context_get (arrowmenuitem_context,
"min-width", &arrow_width, "min-height", &arrow_height, NULL);
arrow_size = MIN (arrow_width, arrow_height);
gtk_render_arrow (arrowmenuitem_context, cr, G_PI / 2,
contents_x,
contents_y + (contents_height - arrow_size) / 2, arrow_size);
gtk_style_context_get (disabledarrowmenuitem_context,
"min-width", &arrow_width, "min-height", &arrow_height, NULL);
arrow_size = MIN (arrow_width, arrow_height);
gtk_render_arrow (disabledarrowmenuitem_context, cr, G_PI / 2,
contents_x + contents_width - arrow_size,
contents_y + (contents_height - arrow_size) / 2, arrow_size);
/* Left check enabled, sensitive, and right check unchecked, insensitive */
draw_style_common (menuitem_context, cr, menu_x, menu_y + menuitem1_height + menuitem2_height, menu_width, menuitem3_height,
&contents_x, &contents_y, &contents_width, &contents_height);
gtk_style_context_get (checkmenuitem_context,
"min-width", &toggle_width, "min-height", &toggle_height, NULL);
draw_style_common (checkmenuitem_context, cr,
contents_x,
contents_y,
toggle_width, toggle_height,
&toggle_x, &toggle_y, &toggle_width, &toggle_height);
gtk_render_check (checkmenuitem_context, cr, toggle_x, toggle_y, toggle_width, toggle_height);
gtk_style_context_get (disabledcheckmenuitem_context,
"min-width", &toggle_width, "min-height", &toggle_height, NULL);
draw_style_common (disabledcheckmenuitem_context, cr,
contents_x + contents_width - toggle_width,
contents_y,
toggle_width, toggle_height,
&toggle_x, &toggle_y, &toggle_width, &toggle_height);
gtk_render_check (disabledcheckmenuitem_context, cr, toggle_x, toggle_y, toggle_width, toggle_height);
/* Separator */
draw_style_common (separatormenuitem_context, cr, menu_x, menu_y + menuitem1_height + menuitem2_height + menuitem3_height,
menu_width, menuitem4_height,
NULL, NULL, NULL, NULL);
/* Left check enabled, sensitive, and right check unchecked, insensitive */
draw_style_common (menuitem_context, cr, menu_x, menu_y + menuitem1_height + menuitem2_height + menuitem3_height + menuitem4_height,
menu_width, menuitem5_height,
&contents_x, &contents_y, &contents_width, &contents_height);
gtk_style_context_get (radiomenuitem_context,
"min-width", &toggle_width, "min-height", &toggle_height, NULL);
draw_style_common (radiomenuitem_context, cr,
contents_x,
contents_y,
toggle_width, toggle_height,
&toggle_x, &toggle_y, &toggle_width, &toggle_height);
gtk_render_check (radiomenuitem_context, cr, toggle_x, toggle_y, toggle_width, toggle_height);
gtk_style_context_get (disabledradiomenuitem_context,
"min-width", &toggle_width, "min-height", &toggle_height, NULL);
draw_style_common (disabledradiomenuitem_context, cr,
contents_x + contents_width - toggle_width,
contents_y,
toggle_width, toggle_height,
&toggle_x, &toggle_y, &toggle_width, &toggle_height);
gtk_render_check (disabledradiomenuitem_context, cr, toggle_x, toggle_y, toggle_width, toggle_height);
g_object_unref (menu_context);
g_object_unref (menuitem_context);
g_object_unref (hovermenuitem_context);
g_object_unref (hoveredarrowmenuitem_context);
g_object_unref (arrowmenuitem_context);
g_object_unref (checkmenuitem_context);
g_object_unref (disabledarrowmenuitem_context);
g_object_unref (disabledcheckmenuitem_context);
g_object_unref (radiomenuitem_context);
g_object_unref (disablemenuitem_context);
g_object_unref (disabledradiomenuitem_context);
g_object_unref (separatormenuitem_context);
}
static void
draw_menubar (GtkWidget *widget,
cairo_t *cr,
gint x,
gint y,
gint width,
gint *height)
{
GtkStyleContext *frame_context;
GtkStyleContext *border_context;
GtkStyleContext *menubar_context;
GtkStyleContext *hovered_menuitem_context;
GtkStyleContext *menuitem_context;
gint contents_x, contents_y, contents_width, contents_height;
gint item_width;
/* Menubar background is the same color as our base background, so use a frame */
frame_context = get_style (NULL, "frame");
border_context = get_style (frame_context, "border");
/* This information is taken from the GtkMenuBar docs, see "CSS nodes" */
menubar_context = get_style (NULL, "menubar");
hovered_menuitem_context = get_style (menubar_context, "menuitem:hover");
menuitem_context = get_style (menubar_context, "menuitem");
*height = 0;
query_size (frame_context, NULL, height);
query_size (border_context, NULL, height);
query_size (menubar_context, NULL, height);
query_size (hovered_menuitem_context, NULL, height);
query_size (menuitem_context, NULL, height);
draw_style_common (frame_context, cr, x, y, width, *height,
NULL, NULL, NULL, NULL);
draw_style_common (border_context, cr, x, y, width, *height,
&contents_x, &contents_y, &contents_width, &contents_height);
draw_style_common (menubar_context, cr, contents_x, contents_y, contents_width, contents_height,
NULL, NULL, NULL, NULL);
item_width = contents_width / 3;
draw_style_common (hovered_menuitem_context, cr, contents_x, contents_y, item_width, contents_height,
NULL, NULL, NULL, NULL);
draw_style_common (menuitem_context, cr, contents_x + item_width * 2, contents_y, item_width, contents_height,
NULL, NULL, NULL, NULL);
g_object_unref (menuitem_context);
g_object_unref (hovered_menuitem_context);
g_object_unref (menubar_context);
g_object_unref (border_context);
g_object_unref (frame_context);
}
static void
draw_notebook (GtkWidget *widget,
cairo_t *cr,
gint x,
gint y,
gint width,
gint height)
{
GtkStyleContext *notebook_context;
GtkStyleContext *header_context;
GtkStyleContext *tabs_context;
GtkStyleContext *tab1_context, *tab2_context;
GtkStyleContext *stack_context;
gint header_height;
gint contents_x, contents_y, contents_width, contents_height;
/* This information is taken from the GtkNotebook docs, see "CSS nodes" */
notebook_context = get_style (NULL, "notebook.frame");
header_context = get_style (notebook_context, "header.top");
tabs_context = get_style (header_context, "tabs");
tab1_context = get_style (tabs_context, "tab:checked");
tab2_context = get_style (tabs_context, "tab:hover");
stack_context = get_style (notebook_context, "stack");
header_height = 0;
query_size (notebook_context, NULL, &header_height);
query_size (header_context, NULL, &header_height);
query_size (tabs_context, NULL, &header_height);
query_size (tab1_context, NULL, &header_height);
query_size (tab2_context, NULL, &header_height);
draw_style_common (notebook_context, cr, x, y, width, height, NULL, NULL, NULL, NULL);
draw_style_common (header_context, cr, x, y, width, header_height, NULL, NULL, NULL, NULL);
draw_style_common (tabs_context, cr, x, y, width, header_height, NULL, NULL, NULL, NULL);
draw_style_common (tab1_context, cr, x, y, width / 2, header_height,
&contents_x, &contents_y, &contents_width, &contents_height);
draw_style_common (tab2_context, cr, x + width / 2, y, width / 2, header_height,
NULL, NULL, NULL, NULL);
draw_style_common (stack_context, cr, x, y + header_height, width,height - header_height,
NULL, NULL, NULL, NULL);
g_object_unref (stack_context);
g_object_unref (tabs_context);
g_object_unref (tab1_context);
g_object_unref (tab2_context);
g_object_unref (header_context);
g_object_unref (notebook_context);
}
static void
draw_horizontal_scrollbar (GtkWidget *widget,
cairo_t *cr,
gint x,
gint y,
gint width,
gint position,
GtkStateFlags state,
gint *height)
{
GtkStyleContext *scrollbar_context;
GtkStyleContext *contents_context;
GtkStyleContext *trough_context;
GtkStyleContext *slider_context;
gint slider_width;
/* This information is taken from the GtkScrollbar docs, see "CSS nodes" */
scrollbar_context = get_style (NULL, "scrollbar.horizontal.bottom");
contents_context = get_style (scrollbar_context, "contents");
trough_context = get_style (contents_context, "trough");
slider_context = get_style (trough_context, "slider");
gtk_style_context_set_state (scrollbar_context, state);
gtk_style_context_set_state (contents_context, state);
gtk_style_context_set_state (trough_context, state);
gtk_style_context_set_state (slider_context, state);
*height = 0;
query_size (scrollbar_context, NULL, height);
query_size (contents_context, NULL, height);
query_size (trough_context, NULL, height);
query_size (slider_context, NULL, height);
gtk_style_context_get (slider_context,
"min-width", &slider_width, NULL);
draw_style_common (scrollbar_context, cr, x, y, width, *height, NULL, NULL, NULL, NULL);
draw_style_common (contents_context, cr, x, y, width, *height, NULL, NULL, NULL, NULL);
draw_style_common (trough_context, cr, x, y, width, *height, NULL, NULL, NULL, NULL);
draw_style_common (slider_context, cr, x + position, y, slider_width, *height, NULL, NULL, NULL, NULL);
g_object_unref (slider_context);
g_object_unref (trough_context);
g_object_unref (contents_context);
g_object_unref (scrollbar_context);
}
static void
draw_text (GtkWidget *widget,
cairo_t *cr,
gint x,
gint y,
gint width,
gint height,
const gchar *text,
GtkStateFlags state)
{
GtkStyleContext *label_context;
GtkStyleContext *selection_context;
GtkStyleContext *context;
PangoLayout *layout;
/* This information is taken from the GtkLabel docs, see "CSS nodes" */
label_context = get_style (NULL, "label.view");
selection_context = get_style (label_context, "selection");
gtk_style_context_set_state (label_context, state);
if (state & GTK_STATE_FLAG_SELECTED)
context = selection_context;
else
context = label_context;
layout = gtk_widget_create_pango_layout (widget, text);
gtk_render_background (context, cr, x, y, width, height);
gtk_render_frame (context, cr, x, y, width, height);
gtk_render_layout (context, cr, x, y, layout);
g_object_unref (layout);
g_object_unref (selection_context);
g_object_unref (label_context);
}
static void
draw_check (GtkWidget *widget,
cairo_t *cr,
gint x,
gint y,
GtkStateFlags state,
gint *width,
gint *height)
{
GtkStyleContext *button_context;
GtkStyleContext *check_context;
gint contents_x, contents_y, contents_width, contents_height;
/* This information is taken from the GtkCheckButton docs, see "CSS nodes" */
button_context = get_style (NULL, "checkbutton");
check_context = get_style (button_context, "check");
gtk_style_context_set_state (check_context, state);
*width = *height = 0;
query_size (button_context, width, height);
query_size (check_context, width, height);
draw_style_common (button_context, cr, x, y, *width, *height, NULL, NULL, NULL, NULL);
draw_style_common (check_context, cr, x, y, *width, *height,
&contents_x, &contents_y, &contents_width, &contents_height);
gtk_render_check (check_context, cr, contents_x, contents_y, contents_width, contents_height);
g_object_unref (check_context);
g_object_unref (button_context);
}
static void
draw_radio (GtkWidget *widget,
cairo_t *cr,
gint x,
gint y,
GtkStateFlags state,
gint *width,
gint *height)
{
GtkStyleContext *button_context;
GtkStyleContext *check_context;
gint contents_x, contents_y, contents_width, contents_height;
/* This information is taken from the GtkRadioButton docs, see "CSS nodes" */
button_context = get_style (NULL, "radiobutton");
check_context = get_style (button_context, "radio");
gtk_style_context_set_state (check_context, state);
*width = *height = 0;
query_size (button_context, width, height);
query_size (check_context, width, height);
draw_style_common (button_context, cr, x, y, *width, *height, NULL, NULL, NULL, NULL);
draw_style_common (check_context, cr, x, y, *width, *height,
&contents_x, &contents_y, &contents_width, &contents_height);
gtk_render_check (check_context, cr, contents_x, contents_y, contents_width, contents_height);
g_object_unref (check_context);
g_object_unref (button_context);
}
static void
draw_progress (GtkWidget *widget,
cairo_t *cr,
gint x,
gint y,
gint width,
gint position,
gint *height)
{
GtkStyleContext *bar_context;
GtkStyleContext *trough_context;
GtkStyleContext *progress_context;
/* This information is taken from the GtkProgressBar docs, see "CSS nodes" */
bar_context = get_style (NULL, "progressbar.horizontal");
trough_context = get_style (bar_context, "trough");
progress_context = get_style (trough_context, "progress.left");
*height = 0;
query_size (bar_context, NULL, height);
query_size (trough_context, NULL, height);
query_size (progress_context, NULL, height);
draw_style_common (bar_context, cr, x, y, width, *height, NULL, NULL, NULL, NULL);
draw_style_common (trough_context, cr, x, y, width, *height, NULL, NULL, NULL, NULL);
draw_style_common (progress_context, cr, x, y, position, *height, NULL, NULL, NULL, NULL);
g_object_unref (progress_context);
g_object_unref (trough_context);
g_object_unref (bar_context);
}
static void
draw_scale (GtkWidget *widget,
cairo_t *cr,
gint x,
gint y,
gint width,
gint position,
gint *height)
{
GtkStyleContext *scale_context;
GtkStyleContext *contents_context;
GtkStyleContext *trough_context;
GtkStyleContext *slider_context;
GtkStyleContext *highlight_context;
gint contents_x, contents_y, contents_width, contents_height;
gint trough_height, slider_height;
scale_context = get_style (NULL, "scale.horizontal");
contents_context = get_style (scale_context, "contents");
trough_context = get_style (contents_context, "trough");
slider_context = get_style (trough_context, "slider");
highlight_context = get_style (trough_context, "highlight.top");
*height = 0;
query_size (scale_context, NULL, height);
query_size (contents_context, NULL, height);
query_size (trough_context, NULL, height);
query_size (slider_context, NULL, height);
query_size (highlight_context, NULL, height);
draw_style_common (scale_context, cr, x, y, width, *height,
&contents_x, &contents_y, &contents_width, &contents_height);
draw_style_common (contents_context, cr, contents_x, contents_y, contents_width, contents_height,
&contents_x, &contents_y, &contents_width, &contents_height);
/* Scale trough defines its size querying slider and highlight */
trough_height = 0;
query_size (trough_context, NULL, &trough_height);
slider_height = 0;
query_size (slider_context, NULL, &slider_height);
query_size (highlight_context, NULL, &slider_height);
trough_height += slider_height;
draw_style_common (trough_context, cr, contents_x, contents_y, contents_width, trough_height,
&contents_x, &contents_y, &contents_width, &contents_height);
draw_style_common (highlight_context, cr, contents_x, contents_y,
contents_width / 2, contents_height,
NULL, NULL, NULL, NULL);
draw_style_common (slider_context, cr, contents_x + position, contents_y, contents_height, contents_height,
NULL, NULL, NULL, NULL);
g_object_unref (scale_context);
g_object_unref (contents_context);
g_object_unref (trough_context);
g_object_unref (slider_context);
g_object_unref (highlight_context);
}
static void
draw_combobox (GtkWidget *widget,
cairo_t *cr,
gint x,
gint y,
gint width,
gboolean has_entry,
gint *height)
{
GtkStyleContext *combo_context;
GtkStyleContext *box_context;
GtkStyleContext *button_context;
GtkStyleContext *button_box_context;
GtkStyleContext *entry_context;
GtkStyleContext *arrow_context;
gint contents_x, contents_y, contents_width, contents_height;
gint button_width;
gint arrow_width, arrow_height, arrow_size;
/* This information is taken from the GtkComboBox docs, see "CSS nodes" */
combo_context = get_style (NULL, "combobox:focus");
box_context = get_style (combo_context, "box.horizontal.linked");
if (has_entry)
{
const char *siblings[3] = { "entry.combo:focus", "button.combo" , NULL };
entry_context = get_style_with_siblings (box_context, "entry.combo:focus", siblings, 0);
button_context = get_style_with_siblings (box_context, "button.combo", siblings, 1);
}
else
{
const char *siblings[2] = { "button.combo" , NULL };
button_context = get_style_with_siblings (box_context, "button.combo", siblings, 0);
}
button_box_context = get_style (button_context, "box.horizontal");
arrow_context = get_style (button_box_context, "arrow");
*height = 0;
query_size (combo_context, NULL, height);
query_size (box_context, NULL, height);
if (has_entry)
query_size (entry_context, NULL, height);
query_size (button_context, NULL, height);
query_size (button_box_context, NULL, height);
query_size (arrow_context, NULL, height);
gtk_style_context_get (arrow_context,
"min-width", &arrow_width, "min-height", &arrow_height, NULL);
arrow_size = MIN (arrow_width, arrow_height);
draw_style_common (combo_context, cr, x, y, width, *height, NULL, NULL, NULL, NULL);
draw_style_common (box_context, cr, x, y, width, *height, NULL, NULL, NULL, NULL);
if (has_entry)
{
button_width = *height;
draw_style_common (entry_context, cr, x, y, width - button_width, *height, NULL, NULL, NULL, NULL);
draw_style_common (button_context, cr, x + width - button_width, y, button_width, *height,
&contents_x, &contents_y, &contents_width, &contents_height);
}
else
{
button_width = width;
draw_style_common (button_context, cr, x, y, width, *height,
&contents_x, &contents_y, &contents_width, &contents_height);
}
draw_style_common (button_box_context, cr, contents_x, contents_y, contents_width, contents_height,
NULL, NULL, NULL, NULL);
draw_style_common (arrow_context, cr, contents_x, contents_y, contents_width, contents_height,
NULL, NULL, NULL, NULL);
gtk_render_arrow (arrow_context, cr, G_PI / 2,
contents_x + contents_width - arrow_size,
contents_y + (contents_height - arrow_size) / 2, arrow_size);
g_object_unref (arrow_context);
if (has_entry)
g_object_unref (entry_context);
g_object_unref (button_context);
g_object_unref (combo_context);
}
static void
draw_spinbutton (GtkWidget *widget,
cairo_t *cr,
gint x,
gint y,
gint width,
gint *height)
{
GtkStyleContext *spin_context;
GtkStyleContext *entry_context;
GtkStyleContext *up_context;
GtkStyleContext *down_context;
GtkIconTheme *icon_theme;
GtkIconInfo *icon_info;
GdkTexture *texture;
gint icon_width, icon_height, icon_size;
gint button_width;
gint contents_x, contents_y, contents_width, contents_height;
/* This information is taken from the GtkSpinButton docs, see "CSS nodes" */
spin_context = get_style (NULL, "spinbutton.horizontal:focus");
entry_context = get_style (spin_context, "entry:focus");
up_context = get_style (spin_context, "button.up:focus:active");
down_context = get_style (spin_context, "button.down:focus");
*height = 0;
query_size (spin_context, NULL, height);
query_size (entry_context, NULL, height);
query_size (up_context, NULL, height);
query_size (down_context, NULL, height);
button_width = *height;
draw_style_common (spin_context, cr, x, y, width, *height, NULL, NULL, NULL, NULL);
draw_style_common (entry_context, cr, x, y, width, *height, NULL, NULL, NULL, NULL);
icon_theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (widget));
gtk_style_context_get (up_context,
"min-width", &icon_width, "min-height", &icon_height, NULL);
icon_size = MIN (icon_width, icon_height);
icon_info = gtk_icon_theme_lookup_icon (icon_theme, "list-add-symbolic", icon_size, 0);
texture = GDK_TEXTURE (gtk_icon_info_load_symbolic_for_context (icon_info, up_context, NULL, NULL));
g_object_unref (icon_info);
draw_style_common (up_context, cr, x + width - button_width, y, button_width, *height,
&contents_x, &contents_y, &contents_width, &contents_height);
gtk_render_icon (up_context, cr, texture, contents_x, contents_y + (contents_height - icon_size) / 2);
g_object_unref (texture);
gtk_style_context_get (down_context,
"min-width", &icon_width, "min-height", &icon_height, NULL);
icon_size = MIN (icon_width, icon_height);
icon_info = gtk_icon_theme_lookup_icon (icon_theme, "list-remove-symbolic", icon_size, 0);
texture = GDK_TEXTURE (gtk_icon_info_load_symbolic_for_context (icon_info, down_context, NULL, NULL));
g_object_unref (icon_info);
draw_style_common (down_context, cr, x + width - 2 * button_width, y, button_width, *height,
&contents_x, &contents_y, &contents_width, &contents_height);
gtk_render_icon (down_context, cr, texture, contents_x, contents_y + (contents_height - icon_size) / 2);
g_object_unref (texture);
g_object_unref (down_context);
g_object_unref (up_context);
g_object_unref (entry_context);
g_object_unref (spin_context);
}
static void
draw_func (GtkDrawingArea *da,
cairo_t *cr,
int width,
int height,
gpointer data)
{
GtkWidget *widget = GTK_WIDGET (da);
gint panewidth;
gint x, y;
panewidth = width / 2;
cairo_rectangle (cr, 0, 0, width, height);
cairo_set_source_rgb (cr, 0.9, 0.9, 0.9);
cairo_fill (cr);
x = y = 10;
draw_horizontal_scrollbar (widget, cr, x, y, panewidth - 20, 30, GTK_STATE_FLAG_NORMAL, &height);
y += height + 8;
draw_horizontal_scrollbar (widget, cr, x, y, panewidth - 20, 40, GTK_STATE_FLAG_PRELIGHT, &height);
y += height + 8;
draw_horizontal_scrollbar (widget, cr, x, y, panewidth - 20, 50, GTK_STATE_FLAG_ACTIVE|GTK_STATE_FLAG_PRELIGHT, &height);
y += height + 8;
draw_text (widget, cr, x, y, panewidth - 20, 20, "Not selected", GTK_STATE_FLAG_NORMAL);
y += 20 + 10;
draw_text (widget, cr, x, y, panewidth - 20, 20, "Selected", GTK_STATE_FLAG_SELECTED);
x = 10;
y += 20 + 10;
draw_check (widget, cr, x, y, GTK_STATE_FLAG_NORMAL, &width, &height);
x += width + 10;
draw_check (widget, cr, x, y, GTK_STATE_FLAG_CHECKED, &width, &height);
x += width + 10;
draw_radio (widget, cr, x, y, GTK_STATE_FLAG_NORMAL, &width, &height);
x += width + 10;
draw_radio (widget, cr, x, y, GTK_STATE_FLAG_CHECKED, &width, &height);
x = 10;
y += height + 10;
draw_progress (widget, cr, x, y, panewidth - 20, 50, &height);
y += height + 10;
draw_scale (widget, cr, x, y, panewidth - 20, 75, &height);
y += height + 20;
draw_notebook (widget, cr, x, y, panewidth - 20, 160);
/* Second column */
x += panewidth;
y = 10;
draw_menu (widget, cr, x, y, panewidth - 20, &height);
y += height + 10;
draw_menubar (widget, cr, x, y, panewidth - 20, &height);
y += height + 20;
draw_spinbutton (widget, cr, x, y, panewidth - 20, &height);
y += height + 30;
draw_combobox (widget, cr, x, y, panewidth - 20, FALSE, &height);
y += height + 10;
draw_combobox (widget, cr, 10 + panewidth, y, panewidth - 20, TRUE, &height);
}
GtkWidget *
do_foreigndrawing (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
if (!window)
{
GtkWidget *box;
GtkWidget *da;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Foreign drawing");
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
gtk_container_add (GTK_CONTAINER (window), box);
da = gtk_drawing_area_new ();
gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (da), 400);
gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (da), 400);
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_func, NULL, NULL);
gtk_widget_set_hexpand (da, TRUE);
gtk_widget_set_vexpand (da, TRUE);
gtk_container_add (GTK_CONTAINER (box), da);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,137 +0,0 @@
/* OpenGL/Gears
*
* This is a classic OpenGL demo, running in a GtkGLArea.
*/
#include <stdlib.h>
#include <gtk/gtk.h>
#include "gtkgears.h"
/************************************************************************
* DEMO CODE *
************************************************************************/
static void
on_axis_value_change (GtkAdjustment *adjustment,
gpointer data)
{
GtkGears *gears = GTK_GEARS (data);
int axis = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (adjustment), "axis"));
gtk_gears_set_axis (gears, axis, gtk_adjustment_get_value (adjustment));
}
static GtkWidget *
create_axis_slider (GtkGears *gears,
int axis)
{
GtkWidget *box, *label, *slider;
GtkAdjustment *adj;
const char *text;
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE);
switch (axis)
{
case GTK_GEARS_X_AXIS:
text = "X";
break;
case GTK_GEARS_Y_AXIS:
text = "Y";
break;
case GTK_GEARS_Z_AXIS:
text = "Z";
break;
default:
g_assert_not_reached ();
}
label = gtk_label_new (text);
gtk_box_append (GTK_BOX (box), label);
gtk_widget_show (label);
adj = gtk_adjustment_new (gtk_gears_get_axis (gears, axis), 0.0, 360.0, 1.0, 12.0, 0.0);
g_object_set_data (G_OBJECT (adj), "axis", GINT_TO_POINTER (axis));
g_signal_connect (adj, "value-changed",
G_CALLBACK (on_axis_value_change),
gears);
slider = gtk_scale_new (GTK_ORIENTATION_VERTICAL, adj);
gtk_scale_set_draw_value (GTK_SCALE (slider), FALSE);
gtk_box_append (GTK_BOX (box), slider);
gtk_widget_set_vexpand (slider, TRUE);
gtk_widget_show (slider);
gtk_widget_show (box);
return box;
}
GtkWidget *
do_gears (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
GtkWidget *box, *hbox, *fps_label, *gears, *overlay, *frame;
int i;
if (!window)
{
window = gtk_window_new ();
gtk_window_set_title (GTK_WINDOW (window), "Gears");
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
gtk_window_set_default_size (GTK_WINDOW (window), 640, 640);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
overlay = gtk_overlay_new ();
gtk_widget_set_margin_start (overlay, 12);
gtk_widget_set_margin_end (overlay, 12);
gtk_widget_set_margin_top (overlay, 12);
gtk_widget_set_margin_bottom (overlay, 12);
gtk_window_set_child (GTK_WINDOW (window), overlay);
frame = gtk_frame_new (NULL);
gtk_widget_set_halign (frame, GTK_ALIGN_START);
gtk_widget_set_valign (frame, GTK_ALIGN_START);
gtk_widget_add_css_class (frame, "app-notification");
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), frame);
fps_label = gtk_label_new ("");
gtk_widget_set_halign (fps_label, GTK_ALIGN_START);
gtk_frame_set_child (GTK_FRAME (frame), fps_label);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE);
gtk_box_set_spacing (GTK_BOX (box), 6);
gtk_overlay_set_child (GTK_OVERLAY (overlay), box);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE);
gtk_box_set_spacing (GTK_BOX (box), 6);
gtk_box_append (GTK_BOX (box), hbox);
gears = gtk_gears_new ();
gtk_widget_set_hexpand (gears, TRUE);
gtk_widget_set_vexpand (gears, TRUE);
gtk_box_append (GTK_BOX (hbox), gears);
for (i = 0; i < GTK_GEARS_N_AXIS; i++)
gtk_box_append (GTK_BOX (hbox), create_axis_slider (GTK_GEARS (gears), i));
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE);
gtk_box_set_spacing (GTK_BOX (hbox), 6);
gtk_box_append (GTK_BOX (box), hbox);
gtk_gears_set_fps_label (GTK_GEARS (gears), GTK_LABEL (fps_label));
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -17,9 +17,9 @@ typedef struct _DemoData DemoData;
struct _DemoData
{
const char *name;
const char *title;
const char *filename;
char *name;
char *title;
char *filename;
GDoDemoFunc func;
DemoData *children;
};

View File

@@ -94,12 +94,9 @@ drawing_area_draw (GtkDrawingArea *area,
cairo_pattern_t *pat;
cairo_matrix_t matrix;
gdouble angle, scale;
gdouble x_center, y_center;
gtk_gesture_get_bounding_box_center (GTK_GESTURE (zoom), &x_center, &y_center);
cairo_get_matrix (cr, &matrix);
cairo_matrix_translate (&matrix, x_center, y_center);
cairo_matrix_translate (&matrix, width / 2, height / 2);
cairo_save (cr);
@@ -146,13 +143,14 @@ do_gestures (GtkWidget *do_widget)
if (!window)
{
window = gtk_window_new ();
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
gtk_window_set_title (GTK_WINDOW (window), "Gestures");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
drawing_area = gtk_drawing_area_new ();
gtk_window_set_child (GTK_WINDOW (window), drawing_area);
gtk_container_add (GTK_CONTAINER (window), drawing_area);
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (drawing_area),
drawing_area_draw,
@@ -209,7 +207,7 @@ do_gestures (GtkWidget *do_widget)
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,4 +1,4 @@
/* OpenGL/OpenGL Area
/* OpenGL Area
*
* GtkGLArea is a widget that allows custom drawing using OpenGL calls.
*/
@@ -354,7 +354,7 @@ create_axis_slider (int axis)
}
label = gtk_label_new (text);
gtk_box_append (GTK_BOX (box), label);
gtk_container_add (GTK_CONTAINER (box), label);
gtk_widget_show (label);
adj = gtk_adjustment_new (0.0, 0.0, 360.0, 1.0, 12.0, 0.0);
@@ -362,7 +362,7 @@ create_axis_slider (int axis)
G_CALLBACK (on_axis_value_change),
GINT_TO_POINTER (axis));
slider = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, adj);
gtk_box_append (GTK_BOX (box), slider);
gtk_container_add (GTK_CONTAINER (box), slider);
gtk_widget_set_hexpand (slider, TRUE);
gtk_widget_show (slider);
@@ -383,30 +383,27 @@ close_window (GtkWidget *widget)
rotation_angles[Z_AXIS] = 0.0;
}
static GtkWidget *
GtkWidget *
create_glarea_window (GtkWidget *do_widget)
{
GtkWidget *window, *box, *button, *controls;
int i;
window = gtk_window_new ();
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), "OpenGL Area");
gtk_window_set_default_size (GTK_WINDOW (window), 400, 600);
g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE);
gtk_widget_set_margin_start (box, 12);
gtk_widget_set_margin_end (box, 12);
gtk_widget_set_margin_top (box, 12);
gtk_widget_set_margin_bottom (box, 12);
g_object_set (box, "margin", 12, NULL);
gtk_box_set_spacing (GTK_BOX (box), 6);
gtk_window_set_child (GTK_WINDOW (window), box);
gtk_container_add (GTK_CONTAINER (window), box);
gl_area = gtk_gl_area_new ();
gtk_widget_set_hexpand (gl_area, TRUE);
gtk_widget_set_vexpand (gl_area, TRUE);
gtk_box_append (GTK_BOX (box), gl_area);
gtk_container_add (GTK_CONTAINER (box), gl_area);
/* We need to initialize and free GL resources, so we use
* the realize and unrealize signals on the widget
@@ -418,16 +415,16 @@ create_glarea_window (GtkWidget *do_widget)
g_signal_connect (gl_area, "render", G_CALLBACK (render), NULL);
controls = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE);
gtk_box_append (GTK_BOX (box), controls);
gtk_container_add (GTK_CONTAINER (box), controls);
gtk_widget_set_hexpand (controls, TRUE);
for (i = 0; i < N_AXIS; i++)
gtk_box_append (GTK_BOX (controls), create_axis_slider (i));
gtk_container_add (GTK_CONTAINER (controls), create_axis_slider (i));
button = gtk_button_new_with_label ("Quit");
gtk_widget_set_hexpand (button, TRUE);
gtk_box_append (GTK_BOX (box), button);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_window_destroy), window);
gtk_container_add (GTK_CONTAINER (box), button);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
return window;
}
@@ -441,7 +438,7 @@ do_glarea (GtkWidget *do_widget)
if (!gtk_widget_get_visible (demo_window))
gtk_widget_show (demo_window);
else
gtk_window_destroy (GTK_WINDOW (demo_window));
gtk_widget_destroy (demo_window);
return demo_window;
}

View File

@@ -25,7 +25,7 @@ typedef struct _GtkFishbowlChild GtkFishbowlChild;
struct _GtkFishbowlPrivate
{
GtkFishCreationFunc creation_func;
GHashTable *children;
GList *children;
guint count;
gint64 last_frame_time;
@@ -67,8 +67,6 @@ gtk_fishbowl_init (GtkFishbowl *fishbowl)
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
priv->update_delay = G_USEC_PER_SEC;
priv->children = g_hash_table_new_full (NULL, NULL,
NULL, (GDestroyNotify) g_free);
}
/**
@@ -95,18 +93,20 @@ gtk_fishbowl_measure (GtkWidget *widget,
{
GtkFishbowl *fishbowl = GTK_FISHBOWL (widget);
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
GHashTableIter iter;
gpointer key, value;
GtkFishbowlChild *child;
GList *children;
gint child_min, child_nat;
*minimum = 0;
*natural = 0;
g_hash_table_iter_init (&iter, priv->children);
while (g_hash_table_iter_next (&iter, &key, &value))
for (children = priv->children; children; children = children->next)
{
child = value;
child = children->data;
if (!gtk_widget_get_visible (child->widget))
continue;
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
@@ -136,13 +136,14 @@ gtk_fishbowl_size_allocate (GtkWidget *widget,
GtkFishbowlChild *child;
GtkAllocation child_allocation;
GtkRequisition child_requisition;
GHashTableIter iter;
gpointer key, value;
GList *children;
g_hash_table_iter_init (&iter, priv->children);
while (g_hash_table_iter_next (&iter, &key, &value))
for (children = priv->children; children; children = children->next)
{
child = value;
child = children->data;
if (!gtk_widget_get_visible (child->widget))
continue;
gtk_widget_get_preferred_size (child->widget, &child_requisition, NULL);
child_allocation.x = round (child->x * (width - child_requisition.width));
@@ -180,7 +181,7 @@ gtk_fishbowl_add (GtkFishbowl *fishbowl,
gtk_widget_set_parent (widget, GTK_WIDGET (fishbowl));
g_hash_table_insert (priv->children, widget, child_info);
priv->children = g_list_prepend (priv->children, child_info);
priv->count++;
g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_COUNT]);
}
@@ -190,26 +191,34 @@ gtk_fishbowl_remove (GtkFishbowl *fishbowl,
GtkWidget *widget)
{
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
GtkFishbowlChild *child;
GtkWidget *widget_bowl = GTK_WIDGET (fishbowl);
GList *children;
if (g_hash_table_remove (priv->children, widget))
for (children = priv->children; children; children = children->next)
{
gtk_widget_unparent (widget);
child = children->data;
priv->count--;
g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_COUNT]);
if (child->widget == widget)
{
gboolean was_visible = gtk_widget_get_visible (widget);
gtk_widget_unparent (widget);
priv->children = g_list_remove_link (priv->children, children);
g_list_free (children);
g_free (child);
if (was_visible && gtk_widget_get_visible (widget_bowl))
gtk_widget_queue_resize (widget_bowl);
priv->count--;
g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_COUNT]);
break;
}
}
}
static void
gtk_fishbowl_finalize (GObject *object)
{
GtkFishbowl *fishbowl = GTK_FISHBOWL (object);
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
g_hash_table_destroy (priv->children);
priv->children = NULL;
}
static void
gtk_fishbowl_dispose (GObject *object)
{
@@ -295,7 +304,6 @@ gtk_fishbowl_class_init (GtkFishbowlClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = gtk_fishbowl_finalize;
object_class->dispose = gtk_fishbowl_dispose;
object_class->set_property = gtk_fishbowl_set_property;
object_class->get_property = gtk_fishbowl_get_property;
@@ -527,9 +535,8 @@ gtk_fishbowl_tick (GtkWidget *widget,
GtkFishbowl *fishbowl = GTK_FISHBOWL (widget);
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
GtkFishbowlChild *child;
GList *l;
gint64 frame_time, elapsed;
GHashTableIter iter;
gpointer key, value;
gboolean do_update;
frame_time = gdk_frame_clock_get_frame_time (gtk_widget_get_frame_clock (widget));
@@ -541,10 +548,9 @@ gtk_fishbowl_tick (GtkWidget *widget,
if (elapsed == frame_time)
return G_SOURCE_CONTINUE;
g_hash_table_iter_init (&iter, priv->children);
while (g_hash_table_iter_next (&iter, &key, &value))
for (l = priv->children; l; l = l->next)
{
child = value;
child = l->data;
child->x += child->dx * ((double) elapsed / G_USEC_PER_SEC);
child->y += child->dy * ((double) elapsed / G_USEC_PER_SEC);

View File

@@ -197,7 +197,7 @@ gtk_gears_class_init (GtkGearsClass *klass)
* @param v the vertex to fill
* @param x the x coordinate
* @param y the y coordinate
* @param z the z coordinate
* @param z the z coortinate
* @param n pointer to the normal table
*
* @return the operation error code

View File

@@ -2,8 +2,9 @@
*
* GtkHeaderBar is a container that is suitable for implementing
* window titlebars. One of its features is that it can position
* a title centered with regard to the full width, regardless of
* variable-width content at the left or right.
* a title (and optional subtitle) centered with regard to the
* full width, regardless of variable-width content at the left
* or right.
*
* It is commonly used with gtk_window_set_titlebar()
*/
@@ -22,42 +23,44 @@ do_headerbar (GtkWidget *do_widget)
if (!window)
{
window = gtk_window_new ();
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), "Welcome to Facebook - Log in, sign up or learn more");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
header = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
gtk_header_bar_set_title (GTK_HEADER_BAR (header), "Welcome to Facebook - Log in, sign up or learn more");
gtk_header_bar_set_has_subtitle (GTK_HEADER_BAR (header), FALSE);
button = gtk_button_new ();
icon = g_themed_icon_new ("mail-send-receive-symbolic");
image = gtk_image_new_from_gicon (icon);
g_object_unref (icon);
gtk_button_set_child (GTK_BUTTON (button), image);
gtk_container_add (GTK_CONTAINER (button), image);
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), button);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_add_css_class (box, "linked");
gtk_style_context_add_class (gtk_widget_get_style_context (box), "linked");
button = gtk_button_new ();
gtk_button_set_child (GTK_BUTTON (button), gtk_image_new_from_icon_name ("pan-start-symbolic"));
gtk_box_append (GTK_BOX (box), button);
gtk_container_add (GTK_CONTAINER (button), gtk_image_new_from_icon_name ("pan-start-symbolic"));
gtk_container_add (GTK_CONTAINER (box), button);
button = gtk_button_new ();
gtk_button_set_child (GTK_BUTTON (button), gtk_image_new_from_icon_name ("pan-end-symbolic"));
gtk_box_append (GTK_BOX (box), button);
gtk_container_add (GTK_CONTAINER (button), gtk_image_new_from_icon_name ("pan-end-symbolic"));
gtk_container_add (GTK_CONTAINER (box), button);
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), box);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
gtk_window_set_child (GTK_WINDOW (window), gtk_text_view_new ());
gtk_container_add (GTK_CONTAINER (window), gtk_text_view_new ());
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,25 +0,0 @@
<interface>
<object class="GtkShortcutsWindow" id="help_overlay">
<child>
<object class="GtkShortcutsSection">
<child>
<object class="GtkShortcutsGroup">
<property name="title">General</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="accelerator">F1</property>
<property name="title">Show About Dialog</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="accelerator">&lt;Control&gt;q</property>
<property name="title">Quit</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -17,7 +17,7 @@
static void
insert_link (GtkTextBuffer *buffer,
GtkTextIter *iter,
const char *text,
gchar *text,
gint page)
{
GtkTextTag *tag;
@@ -232,12 +232,14 @@ do_hypertext (GtkWidget *do_widget)
GtkTextBuffer *buffer;
GtkEventController *controller;
window = gtk_window_new ();
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Hypertext");
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 450, 450);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
view = gtk_text_view_new ();
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view), GTK_WRAP_WORD);
@@ -260,12 +262,12 @@ do_hypertext (GtkWidget *do_widget)
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
gtk_text_buffer_set_enable_undo (buffer, TRUE);
sw = gtk_scrolled_window_new ();
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_window_set_child (GTK_WINDOW (window), sw);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), view);
gtk_container_add (GTK_CONTAINER (window), sw);
gtk_container_add (GTK_CONTAINER (sw), view);
show_page (buffer, 1);
}
@@ -273,7 +275,7 @@ do_hypertext (GtkWidget *do_widget)
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -12,7 +12,7 @@ static GtkWidget *window = NULL;
static GtkWidget *scrolledwindow;
static int selected;
#define N_WIDGET_TYPES 6
#define N_WIDGET_TYPES 4
static int hincrement = 5;
@@ -52,10 +52,7 @@ populate_icons (void)
grid = gtk_grid_new ();
gtk_widget_set_halign (grid, GTK_ALIGN_CENTER);
gtk_widget_set_margin_start (grid, 10);
gtk_widget_set_margin_end (grid, 10);
gtk_widget_set_margin_top (grid, 10);
gtk_widget_set_margin_bottom (grid, 10);
g_object_set (grid, "margin", 10, NULL);
gtk_grid_set_row_spacing (GTK_GRID (grid), 10);
gtk_grid_set_column_spacing (GTK_GRID (grid), 10);
@@ -64,12 +61,11 @@ 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,
GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), grid);
GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC);
gtk_container_add (GTK_CONTAINER (scrolledwindow), grid);
}
static char *content;
@@ -101,12 +97,11 @@ 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,
GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), textview);
GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC);
gtk_container_add (GTK_CONTAINER (scrolledwindow), textview);
}
static void
@@ -126,48 +121,11 @@ 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,
GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (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_scrolled_window_set_child (GTK_SCROLLED_WINDOW (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_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), list);
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_add (GTK_CONTAINER (scrolledwindow), image);
}
static void
@@ -176,8 +134,9 @@ set_widget_type (int type)
if (tick_cb)
gtk_widget_remove_tick_callback (window, tick_cb);
if (gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scrolledwindow)))
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), NULL);
if (gtk_bin_get_child (GTK_BIN (scrolledwindow)))
gtk_container_remove (GTK_CONTAINER (scrolledwindow),
gtk_bin_get_child (GTK_BIN (scrolledwindow)));
selected = type;
@@ -203,16 +162,6 @@ 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 ();
}
@@ -258,23 +207,23 @@ do_iconscroll (GtkWidget *do_widget)
builder = gtk_builder_new_from_resource ("/iconscroll/iconscroll.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &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);
scrolledwindow = GTK_WIDGET (gtk_builder_get_object (builder, "scrolledwindow"));
gtk_widget_realize (window);
hadjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "hadjustment"));
vadjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "vadjustment"));
set_widget_type (0);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -6,6 +6,7 @@
<property name="default-height">500</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkBox">
<style>
@@ -30,12 +31,9 @@
<child>
<object class="GtkScrolledWindow" id="scrolledwindow">
<property name="hscrollbar-policy">never</property>
<property name="hadjustment">
<object class="GtkAdjustment" id="hadjustment"/>
</property>
<property name="vadjustment">
<object class="GtkAdjustment" id="vadjustment"/>
</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>
</object>
</child>
</object>

View File

@@ -26,7 +26,7 @@ enum
static GdkPixbuf *file_pixbuf, *folder_pixbuf;
gchar *parent;
GtkWidget *up_button;
GtkToolItem *up_button;
/* Loads the images for the demo and returns whether the operation succeeded */
static void
@@ -188,8 +188,8 @@ item_activated (GtkIconView *icon_view,
}
static void
up_clicked (GtkButton *item,
gpointer user_data)
up_clicked (GtkToolItem *item,
gpointer user_data)
{
GtkListStore *store;
gchar *dir_name;
@@ -209,8 +209,8 @@ up_clicked (GtkButton *item,
}
static void
home_clicked (GtkButton *item,
gpointer user_data)
home_clicked (GtkToolItem *item,
gpointer user_data)
{
GtkListStore *store;
@@ -228,7 +228,7 @@ home_clicked (GtkButton *item,
static void close_window(void)
{
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
window = NULL;
g_object_unref (file_pixbuf);
@@ -248,9 +248,9 @@ do_iconview (GtkWidget *do_widget)
GtkListStore *store;
GtkWidget *vbox;
GtkWidget *tool_bar;
GtkWidget *home_button;
GtkToolItem *home_button;
window = gtk_window_new ();
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (window), 650, 400);
gtk_window_set_display (GTK_WINDOW (window),
@@ -263,27 +263,36 @@ do_iconview (GtkWidget *do_widget)
load_pixbufs ();
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_window_set_child (GTK_WINDOW (window), vbox);
gtk_container_add (GTK_CONTAINER (window), vbox);
tool_bar = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_append (GTK_BOX (vbox), tool_bar);
tool_bar = gtk_toolbar_new ();
gtk_container_add (GTK_CONTAINER (vbox), tool_bar);
up_button = gtk_button_new_with_mnemonic ("_Up");
up_button = gtk_tool_button_new (NULL, NULL);
gtk_tool_button_set_label (GTK_TOOL_BUTTON (up_button), _("_Up"));
gtk_tool_button_set_use_underline (GTK_TOOL_BUTTON (up_button), TRUE);
gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (up_button), "go-up");
gtk_tool_item_set_is_important (up_button, TRUE);
gtk_widget_set_sensitive (GTK_WIDGET (up_button), FALSE);
gtk_box_append (GTK_BOX (tool_bar), up_button);
gtk_toolbar_insert (GTK_TOOLBAR (tool_bar), up_button, -1);
home_button = gtk_button_new_with_mnemonic ("_Home");
gtk_box_append (GTK_BOX (tool_bar), home_button);
home_button = gtk_tool_button_new (NULL, NULL);
gtk_tool_button_set_label (GTK_TOOL_BUTTON (home_button), _("_Home"));
gtk_tool_button_set_use_underline (GTK_TOOL_BUTTON (home_button), TRUE);
gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (home_button), "go-home");
gtk_tool_item_set_is_important (home_button, TRUE);
gtk_toolbar_insert (GTK_TOOLBAR (tool_bar), home_button, -1);
sw = gtk_scrolled_window_new ();
gtk_scrolled_window_set_has_frame (GTK_SCROLLED_WINDOW (sw), TRUE);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
GTK_SHADOW_ETCHED_IN);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_widget_set_vexpand (sw, TRUE);
gtk_box_append (GTK_BOX (vbox), sw);
gtk_container_add (GTK_CONTAINER (vbox), sw);
/* Create the store and fill it with the contents of '/' */
parent = g_strdup ("/");
@@ -312,7 +321,7 @@ do_iconview (GtkWidget *do_widget)
/* Connect to the "item-activated" signal */
g_signal_connect (icon_view, "item-activated",
G_CALLBACK (item_activated), store);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), icon_view);
gtk_container_add (GTK_CONTAINER (sw), icon_view);
gtk_widget_grab_focus (icon_view);
}
@@ -320,7 +329,7 @@ do_iconview (GtkWidget *do_widget)
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

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