Compare commits

...

469 Commits

Author SHA1 Message Date
Matthias Clasen 20422f98ab Fix up the warning
It is misleading to complain about the factory here.
2020-08-25 13:54:32 -04:00
Matthias Clasen ebfdd71a3e gtk-demo: Add suggestion entry demos
Move the Dropdowns demo to Lists/Selections,
and make it show both GtkDropDown and
GtkSuggestionEntry, with some variations.
2020-07-24 10:41:35 -04:00
Matthias Clasen 56069698b1 docs: Mention GtkSuggestionEntry in list widget overview 2020-07-24 10:41:35 -04:00
Matthias Clasen c86a4222a9 Add GtkSuggestionEntry
GtkSuggestionEntry is a replacement for GtkComboBoxText
and GtkEntryCompletion, very similar to GtkDropDown, but
using an entry as widget.
2020-07-24 10:41:35 -04:00
Matthias Clasen 16d09f154e sortlistmodel: Fix a crash 2020-07-24 10:41:35 -04:00
Matthias Clasen 67fdc4f533 dropdown: Fix popup sizing
Setting a width request is not quite enough, since
gtk_widget_set_size_request() only queues a resize
when the widget is visible. Explicitly force one
here. Without this, the popup sometimes shows up
too small.
2020-07-24 10:41:35 -04:00
Matthias Clasen 7e2fceebca Merge branch 'matthiasc/for-master' into 'master'
filechooser: Remove a leftover signal emission

Closes #2942

See merge request GNOME/gtk!2276
2020-07-24 02:58:51 +00:00
Matthias Clasen 1e00c887ec docs: Work around escaping bugs
This is truly a russian doll of documentation formats:
a string containing <> inside an xml fragment in an |[ ]|
gtk-doc example in markdown in a doc comment.

Sadly, something gets escaping wrong, so the <> end up
literally in the docbook and mess up the last step of
our document formatting, even after turning them into
entities.

Work around this with an extra level of entities that
really shouldn't be necessary.
2020-07-23 18:24:18 -04:00
Matthias Clasen 561d3c68a0 docs: Pass --standalone to pandoc
This flag causes pandoc to emit a proper doctype
declaration and, crucially, namespace declarations
for the xlink namespace that it insists on using
for href attributes. Without this, putting external
links in md documents doesn't survive the journey
through xml.
2020-07-23 18:24:18 -04:00
Matthias Clasen 03601cb794 docs: Improve shortcut trigger docs
Point out the need to escape <> in xml.
2020-07-23 18:24:18 -04:00
Matthias Clasen 3108b8b4d3 docs: Explain the shortcutcontroller example a bit
Add a reference to the the syntax for shortcut actions
in builder files.
2020-07-23 18:24:18 -04:00
Matthias Clasen d1afe32762 filechooser: Remove a leftover signal emission
Commit 0145809a94 replace the response-requested
signal with an action, but didn't actually remove the emission
of that no-longer-existing signal.

Fixes: #2942
2020-07-23 12:54:07 -04:00
Benjamin Otte 603dd72b09 Merge branch 'wip/otte/for-master' into 'master'
Wip/otte/for master

See merge request GNOME/gtk!2277
2020-07-23 14:34:33 +00:00
Benjamin Otte e81ba8924a searchenginemodel: Remove unused code 2020-07-23 15:31:08 +02:00
Benjamin Otte 8832ab45d9 searchengine: Remove unused set_recursive() call 2020-07-23 15:31:08 +02:00
Florentina Mușat 87d6e17bc7 Update Romanian translation 2020-07-23 10:33:16 +00:00
Florentina Mușat a5033cd79b Update Romanian translation 2020-07-23 10:32:08 +00:00
Matthias Clasen 44cbf3d605 Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2275
2020-07-23 00:19:15 +00:00
Matthias Clasen fb6288791e NEWS: Updates 2020-07-22 19:51:27 -04:00
Matthias Clasen 2160f52cbf migration guide: Add some tables
Add a table mapping event signals to their event controller
replacements, and a table mapping former GtkContainer
subclasses to their gtk_container_add replacement.
2020-07-22 19:38:58 -04:00
Benjamin Otte 8825e621c9 Merge branch 'wip/otte/for-master' into 'master'
timsort: Actually 0-terminate the array in get_runs()

See merge request GNOME/gtk!2274
2020-07-22 18:08:24 +00:00
Benjamin Otte e22abd73f2 timsort: Actually 0-terminate the array in get_runs()
This could cause SEGVs when changing the sort during an ongoing sort
operation.
2020-07-22 18:59:22 +02:00
Yuri Chornoivan f77d4d7fc0 Update Ukrainian translation 2020-07-22 13:27:26 +00:00
Yuri Chornoivan 8243133ca7 Update Ukrainian translation 2020-07-22 13:22:09 +00:00
Matthias Clasen 63a4345d2c Merge branch 'wip/otte/sortlistmodel2' into 'master'
Massively refactor and improve sortlistmodel

See merge request GNOME/gtk!2273
2020-07-22 13:15:45 +00:00
Piotr Drąg 56685a483d Update POTFILES.in 2020-07-22 15:01:05 +02:00
Benjamin Otte b23f793753 gtk-demo: Add a progress bar when the colors demo resorts 2020-07-22 14:30:49 +02:00
Benjamin Otte 2b19e2fc1f sortlistmodel: Add progress estimation 2020-07-22 14:30:49 +02:00
Benjamin Otte 703f8b8136 timsort: Add progress estimation 2020-07-22 14:30:49 +02:00
Benjamin Otte 5b18968867 sortlistmodel: Make key generation part of the step function
SSave the missing keys as a bitset and iterate over that bitset in the
step function.

Solves the problem with a large UI block at the beginning of a sort
operation when all the keys were generated, in particular when key
generation was slow.

Benchmarks for maximum time taken by a single main loop callback:

     initial sort with complex GFileInfo keys
                       old      new
      32,000 items   137ms      3ms
     128,000 items   520ms     31ms

     initial sort with string keys
                       old      new
      32,000 items   187ms      1ms
     128,000 items   804ms      3ms
2020-07-22 14:30:49 +02:00
Benjamin Otte e8c4e1205a gtk-demo: Make colors demo do incremental sorting 2020-07-22 14:30:49 +02:00
Benjamin Otte bf5c540357 sortlistmodel: Properly compute runs
When updating a (partially) sorted model, take the known runs for the
existing sort and apply them to the new sort. That way, we don't have to
check the whole model again.

Benchmarks:

      appending half the items to a model of strings
                        old      new
      512,000 items   437ms    389ms
    1,024,000 items  1006ms    914ms

      appending 10% of the items to a model of strings
                        old      new
      512,000 items   206ms    132ms
    1,024,000 items   438ms    301ms

      appending 1 item to a model of strings
                        old      new
       64,000 items   1.8ms   0.00ms
      512,000 items     ---   0.01ms
2020-07-22 14:30:49 +02:00
Benjamin Otte c03383d3e5 sortlistmodel: Make sort stable again
Previously, the sort was not stable when items were added/removed while
sorting or the sort algorithm was changed.

Now the sort looks at the item position (via the key's location in the
keys array) to make sure each comparison stays stable with respect to
this position.
2020-07-22 14:30:49 +02:00
Benjamin Otte eaaa287078 multisorter: Implement GtkSortKeys 2020-07-22 14:30:49 +02:00
Benjamin Otte 554defaf1a treelistrowsorter: Implement GtkSortKeys 2020-07-22 14:30:49 +02:00
Benjamin Otte 659fe52b7b numericsorter: Implement GtkSortKeys 2020-07-22 14:30:49 +02:00
Benjamin Otte 0970077af9 stringsorter: Implement GtkSortKeys 2020-07-22 14:30:49 +02:00
Benjamin Otte 814c88fbc1 sortkeys: Add an equal sort keys
Compares every element as equal.
This is useful when sorters are in an invalid configuration.
2020-07-22 14:30:49 +02:00
Benjamin Otte 3b24c8a0a4 sortlistmodel: Use GtkSortKeys
This massively speeds up sorting with expensive sort functions that it's
the most worthwhile optimization of this whole branch.
It's slower for simple sort functions though.

It's also quite a lot slower when the model doesn't support sort keys
(like GtkCustomSorter), but all the other sorters do support keys.

Of course, this depends on the number of items in the model - the number
of comparisons scales O(N * log N) while the overhead for key handling
scales O(N).
So as the log N part grows, generating keys gets more and more
beneficial.

Benchmarks:

       initial sort of a GFileInfo model with display-name keys
                       items     keys
         8,000 items   715ms     50ms
        64,000 items     ---    554ms

       initial sort of a GFileInfo model with complex keys
                       items     keys
        64,000 items   340ms    295ms
       128,000 items   641ms    605ms

       removing half a GFileInfo model with display-name keys
       (no comparisons, just key freeing overhead of a complex sorter)
                       items     keys
       512,000 items    14ms     21ms
     2,048,000 items    40ms     62ms

       removing half a GFileInfo model with complex keys
       (no comparisons, just key freeing overhead of a complex sorter)
                       items     keys
       512,000 items    90ms    237ms
     2,048,000 items   247ms    601ms
2020-07-22 14:30:49 +02:00
Benjamin Otte e34c7e6796 sorter: Introduce GtkSortKeys
GtkSortKeys is an immutable struct that can be used to manage "sort
keys" for items.

Sort keys are memory that is created specifically for sorting. Because
sorting involves lots of comparisons, it's a good idea to prepare the
data relevant for sorting in advance and sort on that data.

In measurements with a PropertyExpression on a string sorter, it's about
??? faster
2020-07-22 14:30:49 +02:00
Benjamin Otte 8c608e9c1c sortlistmodel: Split the SortItem into 2 arrays
Instead of one item keeping the item + its position and sorting that
list, keep the items in 1 array and put the positions into a 2nd array.

This is generally slower while sorting, but allows multiple improvements:

1. We can replace items with keys
   This allows avoiding multiple slow lookups when using complex
   comparisons

2. We can keep multiple position arrays
   This allows doing a sorting in the background without actually
   emitting items-changed() until the array is completely sorted.

3. The main list tracks the items in the original model
   So only a single memmove() is necessary there, while the old version
   had to upgrade the position in every item.
Benchmarks:

        sorting a model of simple strings
                          old      new
        256,000 items   256ms    268ms
        512,000 items   569ms    638ms

        sorting a model of file trees, directories first, by size
                          old      new
         64,000 items   350ms    364ms
        128,000 items   667ms    691ms

        removing half the model
                          old      new
        512,000 items    24ms     15ms
      1,024,000 items    49ms     25ms
2020-07-22 14:30:49 +02:00
Benjamin Otte 283c3b70dd sortlistmodel: Add an incremental property
Also refactor a large part of the sortmodel to make this convenient.

A large amount of time has been spent on getting items-changed regions
minimized.
2020-07-22 14:30:49 +02:00
Benjamin Otte 93599c2c48 testsuite: Add exhaustive sortlistmodel test
This is basically a copy/paste from the filterlistmodel test, but
adapted for sorting.
2020-07-22 14:04:40 +02:00
Benjamin Otte 080e625090 sortlistmodel: Make the sort callback useful
1. Run step() for a while to avoid very short steps
   This way, we batch items-changed() emissions.

2. Track the change region accurately
   This way, we can avoid invalidating the whole list if our step just
   touched a small part of a huge list.
   As this is a merge sort, this is a common occurence when we're buys
   merging chunks: The rest of the model outside those chunks isn't
   changed.

Note that the tracking is accurate: It determines the minimum change
region in the model.

This will be important, because the testsuite is going to test this.
2020-07-22 14:04:40 +02:00
Benjamin Otte 26696a741e timsort: Add change tracking to gtk_tim_sort_step() 2020-07-22 14:04:40 +02:00
Benjamin Otte a209e54b8f timsort: Add gtk_tim_sort_set_max_merge_size()
Makes the SOrtListModel responsive when incrementally sorting.

By making it configurable we can avoid losting performance in the
non-incremental case.
2020-07-22 14:04:40 +02:00
Benjamin Otte 8921dadaa1 timsort: Make sure merges don't take too long
Limit the size of the merged areas and thereby chunk larger merges into
smaller ones.
2020-07-22 14:04:40 +02:00
Benjamin Otte 47232acbd8 sortlistmodel: Make sorting incremental
This is just an experiment so far to see how long it takes to sort.
2020-07-22 14:04:40 +02:00
Benjamin Otte cbad8ec2e4 timsort: Add gtk_tim_sort_set_runs()
... and use it in the SortListModel

Setting runs allows declaring already sorted regions so the sort does
not attempt to sort them again.

This massively speeds up partial inserts where we can reuse the sorted
model as a run and only resort the newly inserted parts.

Benchmarks:

    appending half the model
                    qsort  timsort
    128,000 items    94ms     69ms
    256,000 items   202ms    143ms
    512,000 items   488ms    328ms

    appending 1 item
                    qsort  timsort
      8,000 items   1.5ms    0.0ms
     16,000 items   3.1ms    0.0ms
              ...
    512,000 items     ---    1.8ms
2020-07-22 14:04:40 +02:00
Benjamin Otte 800170b47d sortlistmodel: Use timsort
Simply replace the old qsort() call with a timsort() call.

This is ultimately relevant because timsort is a LOT faster in merging
to already sorted lists (think items-chaged adding some items) or
reversing an existing list (think columnview sort order changes).

Benchmarks:

    initially sorting the model
                    qsort  timsort
    128,000 items   124ms    111ms
    256,000 items   264ms    250ms
2020-07-22 14:04:40 +02:00
Benjamin Otte 97c5cb3514 Add a timsort() implementation 2020-07-22 14:04:40 +02:00
Benjamin Otte 081afc0477 sortlistmodel: Track item positions
The model now tracks the original positions on top of just the items so that
it can remove items in an items-changed emission.

It now takes twice as much memory but removes items much faster.

Benchmarks:

Removing 50% of a model:
                   before    after
   250,000 items    135ms     10ms
   500,000 items    300ms     25ms

Removing 1 item:
     4,000 items    2.2ms      0ms
     8,000 items    4.6ms      0ms
   500,000 items      ---   0.01ms
2020-07-22 14:04:40 +02:00
Benjamin Otte e807fc3be0 sortlistmodel: Replace with an array-based model
This is the dumbest possible sortmodel using an array:
Just grab all the items, put them in the array, qsort() the array.

Some benchmarks (setting a new model):

  125,000 items - old: 549ms
                  new: 115ms
  250,000 items - new: 250ms

This performance can not be kept for simple additions and removals
though.
2020-07-22 14:04:40 +02:00
Boyuan Yang a1bd3389ed Update Chinese (China) translation 2020-07-22 02:58:46 +00:00
Boyuan Yang 03a3b5a0b1 Update Chinese (China) translation 2020-07-22 02:39:21 +00:00
Boyuan Yang 1ee2d9a5fa Update Chinese (China) translation 2020-07-22 02:20:08 +00:00
Matthias Clasen 2e07fcd680 Merge branch 'wip/chergert/quartz4u' into 'master'
Merge GDK macOS branch

See merge request GNOME/gtk!2272
2020-07-21 22:22:41 +00:00
Matthias Clasen d3365d5a60 Merge branch 'matthiasc/for-master' into 'master'
gdk: Update gdkkeysyms.h

See merge request GNOME/gtk!2271
2020-07-21 21:53:16 +00:00
Christian Hergert 9dbf99d91a macos: prototype new GDK backend for macOS
This is fairly substantial rewrite of the GDK backend for quartz and
renamed to macOS to allow for a greenfield implementation.

Many things have come across from the quartz implementation fairly
intact such as the eventloop integration design and discovery of
event windows from the NSEvent.

However much has been changed to fit in with the new GDK design and
how removal of child GdkWindow have been completely eliminated.
Furthermore, the new GdkPopup allows for regular NSWindow to be used
to provide popovers unlike the previous implementation.

The object design more closely follows the ideal for a GDK backend.

Views have been broken out into subclasses so that we can support
multiple GSK renderer paths such as GL and Cairo (and Metal in the
future). However mixed mode GL and Cairo will not be supported. Currently
only the Cairo renderer has been implemented.

A new frame clock implementation using CVDisplayLink provides more
accurate information about when to draw drawing the next frame. Some
testing will need to be done here to understand the power implications
of this.

This implementation has also gained edge snapping for CSD windows. Some
work was also done to ensure that CSD windows have opaque regions
registered with the display server.

     ** This is still very much a work-in-progress **

Some outstanding work that needs to be done:

 - Finish a GL context for macOS and alternate NSView for GL rendering
   (possibly using speciailized CALayer for OpenGL).
 - Input rework to ensure that we don't loose remapping of keys that was
   dropped from GDK during GTK 4 development.
 - Make sure input methods continue to work.
 - Drag-n-Drop is still very much a work in progress
 - High resolution input scrolling needs various work in GDK to land
   first before we can plumb that to NSEvent.
 - gtk/ has a number of things based on GDK_WINDOWING_QUARTZ that need
   to be updated to use the macOS backend.

But this is good enough to start playing with and breaking things which
is what I'd like to see.
2020-07-21 14:45:12 -07:00
Christian Hergert 0154a7f528 gdk: disable file transfer portal on macOS 2020-07-21 14:45:12 -07:00
Christian Hergert add47bebc6 build: add ATK fallback subproject wrapper
Very similar to the other fallbacks we use.
2020-07-21 14:45:12 -07:00
Christian Hergert 514b62223d build: squash various warnings with Clang
Otherwise we have really chatty builds that make it difficult to catch
new issues when compiling.
2020-07-21 14:45:12 -07:00
Christian Hergert 7884ab6161 build: fix linking support on macOS with Clang
This was preventing any sort of building on macOS, even though the quartz
backend is currently non-functional. Fixing this is a pre-requisite to
getting a new macOS backend compiling.
2020-07-21 14:45:12 -07:00
Matthias Clasen bc542c5304 gdk: Update gdkkeysyms.h
Run the gdkkeysyms-update.pl script to pick up several
new keysyms:
GDK_dead_lowline
GDK_dead_aboveverticalline
GDK_dead_belowverticalline
GDK_dead_longsolidusoverlay
GDK_Keyboard
GDK_WWAN
GDK_RFKill
GDK_AudioPreset
2020-07-21 16:55:28 -04:00
Matthias Clasen d66ac4981e Merge branch 'matthiasc/for-master' into 'master'
inspector: Make picking objects show them

Closes #1876

See merge request GNOME/gtk!2269
2020-07-20 22:06:42 +00:00
Matthias Clasen 9b647a47d1 inspector: Make picking objects show them
Changing the selection in the object tree is
not a useful action if we are already in the
object details. Most likely, a user who picks
an object wants to inspect its details, so
just always show them.

Fixes: #1876
2020-07-20 17:30:16 -04:00
Benjamin Otte b67ffe9650 sortlistmodel: Test that the model is stable
Stability is measured relative to the child model, not relative to the
previous sorter.
2020-07-20 22:28:01 +02:00
Benjamin Otte 2c519b006d testsuite: Fix a leak 2020-07-20 22:28:01 +02:00
Matthias Clasen 852429d163 Merge branch 'barthalion/asan-runner' into 'master'
ci: Switch ASAN tests to runners tagged so

See merge request GNOME/gtk!2267
2020-07-20 16:17:49 +00:00
Matthias Clasen ee9c6bbf75 Merge branch 'action-muxer-speedup' into 'master'
Action muxer speedup

See merge request GNOME/gtk!1754
2020-07-20 16:17:17 +00:00
Bartłomiej Piotrowski d9ece94377 ci: Switch ASAN tests to runners tagged so 2020-07-20 16:41:46 +02:00
Matthias Clasen 486fbce42b actionmuxer: Update docs and clean up headers
Update the doc comment at the top to describe the
current  functionality of GtkActionMuxer.
2020-07-20 08:24:54 -04:00
Matthias Clasen ed92026632 actionmuxer: Use an array for accels
We have a lot of accels across all the muxers, but the vast
majority has just one or two, so an array is going to be
smaller and faster for this.
2020-07-20 08:24:54 -04:00
Matthias Clasen 05e614feb7 actionmuxer: Create observed_actions and groups on demand
The vast majority of action muxers don't have observers or
groups, so we can avoid the overhead of carrying all these
empty hash tables.
2020-07-20 08:24:54 -04:00
Matthias Clasen 14059afdf1 inspector: Make the actions tab work again
Bring back the actions tab; we don't receive
changes anymore, since GtkActionMuxer lost
the GActionGroup signals for this, and the
action observer machinery has no way to listen
for all changes.
2020-07-20 08:24:54 -04:00
Matthias Clasen 9b294eb94e Add gtk_action_muxer_list_actions
This is needed to reinstate the actions support
in the inspector.
2020-07-20 08:24:53 -04:00
Matthias Clasen 96d42cf1cc actionmuxer: Stop implementing GActionGroup
Instead of implementing the GActionGroup interface
and using its signals for propagating changes up
and down the muxer hierarchy, use the GtkActionObserver
mechanism. This cuts down on the signal emission
overhead.
2020-07-20 08:24:53 -04:00
Matthias Clasen 4786a16696 actionmuxer: Port internal users
Port all internal users of the action muxer
from the GActionGroup interface to the new
action muxer apis.
2020-07-20 08:24:52 -04:00
Matthias Clasen 14bb12125f actionmuxer: Add some more api
We want to drop the GActionGroup interface from
GtkActionMuxer, so add the necessary api directly
to GtkActionMuxer itself.
2020-07-20 08:24:14 -04:00
Matthias Clasen 07e8dafcea inspector: Remove action support temporarily
This is using the action muxer as a GActionGroup,
and we want to remove that interface from GtkActionMuxer.

The support will come back later.
2020-07-20 08:24:14 -04:00
Matthias Clasen ab67a81f11 Speed up action muxer setup more
Don't emit signals for group insertion/removal
if nobody is listening.
2020-07-20 08:24:14 -04:00
Matthias Clasen aa76f7e210 Speed up action muxer setup
We don't need to duplicate all these action names and
emit all these signals if nobody is listening.
2020-07-20 08:24:14 -04:00
Matthias Clasen 0c15463e41 Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2266
2020-07-20 12:23:12 +00:00
Matthias Clasen 5df1356295 gsk: Remove an unused debug flag
GSK_DEBUG_DIFF was not used anywhere, so remove it.
2020-07-20 07:03:08 -04:00
Matthias Clasen 95fc81c565 inspector: Add a few more debug flags
Add check buttons for GTK_DEBUG=constraints and
GTK_DEBUG=layout in the logs page.
2020-07-20 07:03:08 -04:00
Matthias Clasen 378e594f75 Tweak the GTK_DEBUG=help output
I got the layout flag wrong when I added the
improved help output. It is about layout managers,
not about showing layout borders.
2020-07-20 07:03:08 -04:00
Matthias Clasen 86c7fceb09 Merge branch 'list-model-docs' into 'master'
List model docs

See merge request GNOME/gtk!2182
2020-07-19 23:50:09 +00:00
Matthias Clasen b5e20a3e37 Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2265
2020-07-19 19:14:04 +00:00
Matthias Clasen 75a30b1f98 windowhandle: Don't use an action muxer needlessly
The api that is meant to be used here is
gtk_widget_activate_action.
2020-07-19 13:50:23 -04:00
Matthias Clasen c64a021af4 NEWS: Updates 2020-07-18 18:28:51 -04:00
Matthias Clasen 9b64635925 Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2264
2020-07-18 17:31:31 +00:00
Matthias Clasen 7b76be5360 button: Add explicit key bindings for activation
We should not rely on GtkWindow to have global
"activate-default" key bindings that happen to
fall back to activating the focus widget. This is
unreliable, since the bubbling up from the button
to the toplevel may run across other widgets that
may want to use Enter for their own purpose, and
then the button loses out. By adding our own
key bindings, the button gets to handle it before
its ancestors.

This fixes check buttons in the inspector property
list not reacting to Enter despite having focus.
2020-07-18 12:53:10 -04:00
Matthias Clasen 2e2336ffce text: Claim clicks when grabbing focus
If we don't, an ancestor (such a GtkListItemWidget)
may interpret the click as "I should grab focus!",
and still our focus away. This was causing hard-to-focus
entries in the property list in the inspector.
2020-07-18 12:47:47 -04:00
Matthias Clasen 76d80ef516 inspector: Add focus handling to the property editor
We want to focus the actual control here.
2020-07-18 11:55:19 -04:00
Matthias Clasen 287d80bd36 editablelabel: Stop editing on focus-out
This is the expected behavior for the main use case,
treeview-like 'edit one cell at a time'.
2020-07-18 10:45:27 -04:00
Matthias Clasen 77072b3eaa fixup editing style class 2020-07-18 10:10:28 -04:00
Matthias Clasen c7833bb090 editablelabel: Document css nodes
Just the usual.
2020-07-18 09:55:46 -04:00
Matthias Clasen 899024cef7 editablelabel: Add a style class while editing
Add the .editing style class to the editable label
while it is editing. The idea is that themes can
show a frame around the entry.
2020-07-18 09:54:55 -04:00
Rico Tzschichholz 4da3edd42e Merge branch 'wip/ricotz/annotations' into 'master'
gtk: Improve g-i annotations for methods of GtkExpression subclasses

See merge request GNOME/gtk!2263
2020-07-18 11:06:47 +00:00
Rico Tzschichholz 6b59626817 gtk: Improve g-i annotations for methods of GtkExpression subclasses 2020-07-18 12:30:05 +02:00
Matthias Clasen 7c02ae00c2 inspector: Clean up GtkInspectorGeneral
Drop the Private struct.
2020-07-18 00:31:04 -04:00
Matthias Clasen 80e29a3627 inspector: Clean up GtkInspectorMiscInfo
Drop the Private struct.
2020-07-18 00:25:46 -04:00
Matthias Clasen 26163a4f30 inspector: Clean up GtkInspectorVisual
Drop the Private struct, and do all cleanup in dispose.
2020-07-18 00:17:42 -04:00
Matthias Clasen dbd88fc210 inspector: Clean up GtkInspectorActions
Drop the Private struct, dispose properly,
and don't derive from GtkBox.
2020-07-17 23:59:49 -04:00
Matthias Clasen 2de31e4cac inspector: Clean up GtkInspectorActionEditor
Drop the Private struct, dispose properly,
and don't derive from GtkBox.
2020-07-17 23:36:05 -04:00
Matthias Clasen 1bff328895 inspector: Clean up GtkInspectorLogs
Drop the Private struct, dispose properly,
and don't derive from GtkBox.
2020-07-17 23:24:14 -04:00
Matthias Clasen facf78a5b6 inspector: Allow disposing the inspector
We were hiding the inspector when the window
is closed, but that has the side-effect of
keeping references to application windows,
so we would keep them artificially alive,
which can have side-effects.

So, make the inspector go away when closed.
2020-07-17 23:15:42 -04:00
Matthias Clasen 6b19fcd859 inspector: Properly dispose GtkInspectorWindow 2020-07-17 23:15:25 -04:00
Matthias Clasen ca784e3e1a inspector: Properly dispose GtkInspectorShortcuts 2020-07-17 23:13:29 -04:00
Matthias Clasen 314c8558d7 inspector: Properly dispose GtkInspectorListData 2020-07-17 23:13:07 -04:00
Matthias Clasen af30a7fe06 inspector: Dispose tree data properly
Another place where we were leaking children.
2020-07-17 22:54:19 -04:00
Matthias Clasen 9ffd7d1970 inspector: Dispose the recorder properly
We were leaking children here.
2020-07-17 22:54:10 -04:00
Matthias Clasen cb906c80eb inspector: Drop the recorder Private struct 2020-07-17 22:37:24 -04:00
Matthias Clasen 96ce0eb600 Merge branch 'matthiasc/for-master' into 'master'
gtk-demo: Don't use GtkColorSwatch

See merge request GNOME/gtk!2262
2020-07-18 01:17:43 +00:00
Matthias Clasen 0e476c1f28 gtk-demo: Don't use GtkColorSwatch
Making our own is 80 lines of code, so just do it.
2020-07-17 20:44:06 -04:00
Matthias Clasen f2924988db Merge branch 'ebassi/for-master' into 'master'
Fix typo in the GtkStrinFilter constructor declaration

See merge request GNOME/gtk!2261
2020-07-17 13:18:59 +00:00
Emmanuele Bassi 671435e07f Fix typo in the GtkStrinFilter constructor declaration 2020-07-17 14:16:46 +01:00
Emmanuele Bassi b17cfb9b65 Merge branch 'ebassi/for-master' into 'master'
Fix typo in the gtk-doc stanza for gtk_string_filter_new()

See merge request GNOME/gtk!2259
2020-07-17 13:09:55 +00:00
Emmanuele Bassi 0385f1aaf4 Fix typo in the gtk-doc stanza for gtk_string_filter_new() 2020-07-17 12:03:17 +01:00
Matthias Clasen 8611faf338 Merge branch 'wip/baedert/for-master' into 'master'
Wip/baedert/for master

Closes #2776

See merge request GNOME/gtk!2258
2020-07-17 10:56:16 +00:00
Timm Bäder 7e19911d3f testwidgettransforms: Fix GtkBox casts 2020-07-17 07:14:50 +02:00
Timm Bäder c1f5153f6d boxlayout: Remove unnecessary checks
The pointers passed to GtkLayoutManager::measure() are never NULL. The
ones passed to gtk_layout_manager_measure() can be, however.
2020-07-17 06:31:57 +02:00
Timm Bäder 2bd87ce771 boxlayout: Remove unused include 2020-07-17 06:27:50 +02:00
Timm Bäder de0547ede7 migration guide: Remove a stray html tag 2020-07-17 06:27:23 +02:00
Timm Bäder 14589c2a59 widget: Save a gtk_css_node_get_style call 2020-07-17 05:49:12 +02:00
Timm Bäder f678b3804d widget: Remove useless if statement
filter_value is never NULL anyway.
2020-07-17 05:49:12 +02:00
Timm Bäder 720c298786 snapshot: Use collect_default directoy in push_debug()
Instead of going through collect_debug and then doing a collect_default
anyway if the message is NULL.
2020-07-17 05:49:12 +02:00
Timm Bäder f721d2de15 debug: Remove resize highlighting
This has been broken ever since the debug highlighting moved to
inspector overlays.
2020-07-17 05:49:12 +02:00
Timm Bäder 11f07cb5ad GdkRGBA: Fix typo in documentation 2020-07-17 05:49:11 +02:00
Timm Bäder 37d7ab88dc gl renderer: Avoid 9-slicing things that can't be
The outline needs to be large enough so changing the size of the outline
does not affect the resulting blurred texture.

Fixes #2776
2020-07-17 05:49:11 +02:00
Timm Bäder 6cde64072d gl renderer: Remove outdated comment 2020-07-17 05:49:11 +02:00
Timm Bäder 6a60b0f591 gl renderer: Try to intersect rounded clips more often 2020-07-17 05:49:11 +02:00
Timm Bäder 339d9f05e4 gl renderer: Remove unused flag 2020-07-17 05:49:11 +02:00
Timm Bäder 4e4207457f adwaita: Remove header bar border radius
We get this from the window node these days.
2020-07-17 05:49:11 +02:00
Timm Bäder 46bb3e3046 icontheme: Indentation 2020-07-17 05:49:11 +02:00
Timm Bäder 34008e6aab gl renderer: Ignore rounded clip that only increase the clip
This fixes the widget factory rendering too much.

In the widget-factory, we generally have a pretty small update area (two
spinners and a progressbar). We take the extents of that as a update
area and inital clip.

However, the first clip node we see is from the toplevel window, which
essentially increases the clip again to almost the entire window.

Fix that by ignoring such cases.
2020-07-17 05:49:11 +02:00
Timm Bäder d6b3ac850d testsuite: Fix test case indentation 2020-07-17 05:49:11 +02:00
Matthias Clasen 9742200ff6 Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2257
2020-07-17 03:20:20 +00:00
Matthias Clasen ec10857b84 docs: Move columns below columnview 2020-07-16 22:14:39 -04:00
Matthias Clasen 353d4d161c Cosmetic docs change 2020-07-16 22:08:15 -04:00
Matthias Clasen bcd650f169 docs: Revise the filter docs a bit 2020-07-16 21:48:08 -04:00
Matthias Clasen 72d66dfcdd docs: Revise sorter docs a bit 2020-07-16 21:45:11 -04:00
Matthias Clasen 5e97df5058 bitset: try again 2020-07-16 21:44:31 -04:00
Matthias Clasen 059d131e2b Merge branch 'wip/chergert/subclass-treeview' into 'master'
treeview: allow subclassing GtkTreeView

Closes #2936

See merge request GNOME/gtk!2256
2020-07-17 01:05:07 +00:00
Matthias Clasen 8f7c207c7c docs: Add more GtkExpression
Make GtkExpression show up in the object
hierarchy, and add the param spec and GValue
support to the docs.
2020-07-16 21:02:33 -04:00
Matthias Clasen b9e8935037 docs: Document GtkBitsetIter 2020-07-16 20:28:21 -04:00
Matthias Clasen 5f33f4ae8e docs: Add an example
Add a small example for setting up columnview sorting.
2020-07-16 20:21:21 -04:00
Matthias Clasen adf0e8b1e6 docs: Fix examples
The formatting for examples in the GtkExpression
long description was messed up.
2020-07-16 20:21:21 -04:00
Christian Hergert 7500f9b255 treeview: allow subclassing GtkTreeView
Porting code from GTK 3 without the ability to subclass GtkTreeView
directly can cause an extreme amount of pain on application developers.
It can also complicate performance when it comes to dealing with
encapsulation as the outer widget would also encapsulate the GtkScrollable
implementation from GtkTreeView, typically through GtkViewport.

Fixes #2936
2020-07-16 17:06:15 -07:00
Matthias Clasen a8d433dd26 docs: Link to GtkTreeRowReference
The list overview cross-reference table links
to all objects, except for this one.
2020-07-16 19:53:47 -04:00
Matthias Clasen ecaf6fced0 docs: Add GtkTreeExpander
We want to link to it from various places, so it needs
to be present in the docs.
2020-07-16 19:53:47 -04:00
Matthias Clasen 31a7cac4a6 Merge branch 'matthiasc/arrays' into 'master'
Matthiasc/arrays

See merge request GNOME/gtk!2253
2020-07-16 23:31:31 +00:00
Matthias Clasen 5eec736b07 multifilter: Use GdkArray for the filters 2020-07-16 18:44:25 -04:00
Matthias Clasen cf4a8e2152 multisorter: Use GdkArray for the sorters 2020-07-16 18:44:25 -04:00
Matthias Clasen 31bb969cce Merge branch 'matthiasc/for-master' into 'master'
gtk-demo: Use better api

See merge request GNOME/gtk!2254
2020-07-16 21:03:21 +00:00
Matthias Clasen f4a7c7f6bf gtk-demo: Use better api
We have a getter for the model, lets use it.
2020-07-16 16:26:41 -04:00
Benjamin Otte 495069c868 Merge branch 'wip/otte/for-master' into 'master'
Wip/otte/for master

See merge request GNOME/gtk!2251
2020-07-16 19:43:45 +00:00
Matthias Clasen dfe470475b Merge branch 'missing-exports' into 'master'
Add missing exports for GtkColumnView methods.

See merge request GNOME/gtk!2252
2020-07-16 18:52:22 +00:00
Benjamin Otte de56e892aa listitemmanager: Do a better job on double items
Previously, we would unparent the existing item that we were about
to reuse, and not the duplicate one.

Change that.
2020-07-16 20:43:16 +02:00
Benjamin Otte e518c1f2f3 stringfilter: Make the constructor take an expression
An expression is critically important for a string filter and people
should be made aware of it when constructing the filter.
2020-07-16 20:43:16 +02:00
Benjamin Otte c5ea59d7d1 gtk-demo: Don't make demos modal
That way, demo windows can be maximized and multiple demos can run at
once.

It's especially useful when using --run because the main window is
invisible then.
2020-07-16 20:43:16 +02:00
Benjamin Otte 22eccbdbb6 testsuite: Don't be too exhaustive
The test was taking over 60s on CI, that's a but much.
2020-07-16 20:43:16 +02:00
Benjamin Otte 58e85c85e4 testsuite: Add a case with escaped Latin-1 code
This came up in recent g_uri_escape() discussions.
2020-07-16 20:43:11 +02:00
Matthias Clasen 6b89148487 Merge branch 'wip/otte/vector' into 'master'
Arrays

See merge request GNOME/gtk!2197
2020-07-16 18:05:43 +00:00
Matthias Clasen ddb9e428ec Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2250
2020-07-16 17:39:16 +00:00
Andreas Persson b7fa353db2 Add missing exports for GtkColumnView methods.
GDK_AVAILABLE_IN_ALL was missing for one method in GtkColumnView and one
in GtkColumnViewColumn.
2020-07-16 18:58:41 +02:00
Matthias Clasen 87b5eadb7c treesorter tests: Add a comment
This looks like a leak, but isn't one.
Add a comment to that effect.
2020-07-16 12:14:28 -04:00
Benjamin Otte 60a09e59e8 stringlist: Convert to array
Stringlists are usually built and then never modified, and accessing
items through an array is faster.
2020-07-16 18:09:58 +02:00
Benjamin Otte 6f8e9bf3a9 snapshot: Use GdkArray for the state stack 2020-07-16 18:09:58 +02:00
Benjamin Otte 90b7b84337 array: Add a bunch of new features
* GDK_ARRAY_BY_VALUE
  #define this to get GArray-like behavior
* gdk_array_splice (v, 0, 0, NULL, 25)
  Adding items but passing NULL as the items will zero() them.
* gdk_array_set_size()
  A nicer way to call gdk_array_splice()
* constify getters
2020-07-16 18:09:58 +02:00
Benjamin Otte 088b5fc57f icontheme: Use GdkArray 2020-07-16 18:09:58 +02:00
Benjamin Otte a4cd974912 array: Add null-termination 2020-07-16 18:09:57 +02:00
Benjamin Otte 65359dcc59 snapshot: Port node list to GdkArray 2020-07-16 18:09:57 +02:00
Benjamin Otte ac8b398c50 snapshot: Move structs into .c file
They aren't used anywhere else.
2020-07-16 18:09:57 +02:00
Benjamin Otte aac2417893 Remove preallocated array code
Now with GdkArray, we can use that one instead.
2020-07-16 18:09:57 +02:00
Benjamin Otte ad8892df10 main: Use a GdkArray 2020-07-16 18:09:57 +02:00
Benjamin Otte edc7977c4e cssselector: Use GdkArray 2020-07-16 18:09:57 +02:00
Benjamin Otte 8bf8ac5076 Add GdkArray
This is a scary idea where you #define a bunch of preprocessor values
and then #include "gdkarrayimpl.c" and end up with a dynamic array for
that data type.

See https://en.wikipedia.org/wiki/X_Macro for what's going on.

What are the advantages over using GArray or GPtrArray?

 * It's typesafe
   Because it works like C++ templates, we can use the actual type of
   the object instead of having to use gpointer.

 * It's one less indirection
   instead of 2 indirections via self->array->data, this array is
   embedded, so self->array is the actual data, and just one indirection
   away. This is pretty irrelevant in general, but can be very noticable
   in tight loops.

 * It's all inline
   Because the whole API is defined as static inline functions, the
   compiler has full access to everything and can (and does) optimize
   out unnecessary calls, thereby speeding up some operations quite
   significantly, when full optimizations are enabled.

 * It has more features
   In particular preallocation allows for avoiding malloc() calls, which
   can again speed up tight loops a lot.
   But there's also splice(), which is very useful when used with
   listmodels.
2020-07-16 18:09:57 +02:00
Benjamin Otte c36cbd5140 sortlistmodel: Remove forgotten G_PARAM_CONSTRUCT_ONLY 2020-07-16 17:33:29 +02:00
Matthias Clasen ee96bc7185 multiselection tests: Plug a leak
g_list_model_get_item is transfer full.
2020-07-16 08:54:36 -04:00
Matthias Clasen f94f325636 filterlistmodel tests: Plug a leak
g_list_model_get_item is transfer full.
2020-07-16 08:54:36 -04:00
Matthias Clasen 6c1217dd93 filter tests: Plug a leak
g_list_model_get_item is transfer full.
2020-07-16 08:54:36 -04:00
Matthias Clasen edb792503b printunixdialog: Plug a leak
g_list_model_get_item is transfer full.
2020-07-16 08:54:36 -04:00
Matthias Clasen 3a43859286 Cosmetics 2020-07-16 08:54:36 -04:00
Matthias Clasen c55dd104d4 placessidebar: Plug a leak
g_list_model_get_item is transfer full.
2020-07-16 08:54:36 -04:00
Matthias Clasen 497d137fb8 filechoosernativewin32: Plug a leak
g_list_model_get_item is transfer full.
2020-07-16 08:54:36 -04:00
Matthias Clasen df01c5c7a4 columnlistitemfactory: Plug a leak
g_list_model_get_item is transfer full.
2020-07-16 08:54:36 -04:00
Matthias Clasen 2d1135fba6 applicationaccels: Plug a leak
g_list_model_get_item is transfer full.
2020-07-16 08:54:36 -04:00
Matthias Clasen f54ed6f7dc columviewsorter: Add an assertion 2020-07-16 08:54:36 -04:00
Matthias Clasen b7efd896b6 Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2249
2020-07-16 12:52:46 +00:00
Matthias Clasen 46eb51bc30 inspector: Avoid losing a reference
This was copying the example in the treelistrowsorter
docs that the previous commit fixed, so we apply
the same fix here.
2020-07-16 07:14:01 -04:00
Matthias Clasen 500dbaabc3 treelistrowsorter: Fix a faulty example
gtk_tree_list_row_sorter_new() consumes the
sorter, so we can't pass gtk_column_view_get_sorter(),
since that is transfer none.
2020-07-16 07:14:01 -04:00
Matthias Clasen 594ec3d822 inspector: Don't derive from GtkBox
We don't do that anymore. A bin layout
is sufficient here.
2020-07-16 07:14:01 -04:00
Matthias Clasen f280508209 inspector: Drop a Private struct
These are really not needed in the inspector.
2020-07-16 07:14:01 -04:00
Matthias Clasen 480b88c776 inspector: Drop an unused field 2020-07-16 07:14:01 -04:00
Efstathios Iosifidis a4e63905b1 Update Greek translation 2020-07-15 18:12:26 +00:00
Matthias Clasen 5666127dbc Merge branch 'matthiasc/for-master' into 'master'
inspector: Use substring matching in the property list

See merge request GNOME/gtk!2247
2020-07-15 16:52:05 +00:00
Matthias Clasen c1c110ba65 inspector: Use substring matching in the property list
This is convenient for things like "set both hexpand and
vexpand", since you can then search for "expand"
2020-07-15 11:29:06 -04:00
Florentina Mușat eb2a839892 Update Romanian translation 2020-07-15 08:58:58 +00:00
Matthias Clasen 1c537a6d2e Merge branch 'wip/jimmac/file-dialog-sidebar-color' into 'master'
Adwaita: sidebar color for file picker

See merge request GNOME/gtk!2242
2020-07-15 01:41:35 +00:00
Matthias Clasen c12261a6ec Merge branch 'wip/fix-picom-crasher' into 'master'
x11: Don't set up frame sync fence on unsupported compositors

Closes #2927

See merge request GNOME/gtk!2245
2020-07-15 01:40:49 +00:00
Matthias Clasen 5af7d6bff3 Merge branch 'idle-inhibit' into 'master'
Add support for idle inhibition on Wayland

Closes #2202

See merge request GNOME/gtk!2226
2020-07-15 01:38:55 +00:00
Matthias Clasen de0f4b0f5b Merge branch 'shortcuts-section-reflow-fix' into 'master'
Fix shortcuts section reflow

Closes #2928

See merge request GNOME/gtk!2246
2020-07-15 01:38:38 +00:00
Emmanuel Gil Peyrot 966ab1152d gtk/wayland: Add support for idle inhibition in GtkApplication
This feature was previously only supported on DBus compositors, such as
Mutter, this adds support for other compositors such as all of those
based on wlroots.

This implementation prefers the idle-inhibit Wayland protocol to the
DBus version if it is available, since the inhibitor is per-surface
instead of global it allows a finer control over which displays get
dimmed for instance.  For every case not supported by this protocol, a
fallback to the DBus version is used.

It can’t do anything if the GtkWindow isn’t passed, which might warrant
some documentation change to encourage users to not use NULL for this
argument.

This has been tested on Sway.

Fixes #2202.
2020-07-14 21:47:22 +02:00
Emmanuel Gil Peyrot 74a4432688 gdk/wayland: Add an API to inhibit and uninhibit idle
This uses the idle-inhibit protocol from wayland-protocols, to attach an
inhibitor to the GdkSurface.  The inhibit function can be called as many
times as the user wants, but the uninhibit function MUST be called as
many times to unset the idle inhibition.

This has been tested on Sway.
2020-07-14 21:47:22 +02:00
Matthias Clasen 115d0cdc07 Fix shortcuts section reflow
When this code was ported from gtk_container_get_children
to the dom api, we inadvertendly inverted the order of the
list in one place. With the dom api, we can just avoid
reversing lists altogether, so do that.

Fixes: #2928
2020-07-14 14:48:32 -04:00
Ray Strode d0ec616fba x11: Don't set up frame sync fence on unsupported compositors
Not all compositors support _NET_WM_FRAME_DRAWN.  In cases
where the compositor doesn't support _NET_WM_FRAME_DRAWN we don't
need to do all the fancy damage tracking and fence watching.

Furthermore, if the compositor doesn't support _NET_WM_FRAME_DRAWN,
it's possible that one frame will start before the previous frame has
made it through the pipeline, leading to a blown assertion.

This commit side-steps the unnecessary code and associated assertion
when _NET_WM_FRAME_DRAWN isn't supported.

Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/2927
2020-07-14 14:33:12 -04:00
Florentina Mușat 38cce2bb18 Update Romanian translation 2020-07-14 14:52:19 +00:00
Matthias Clasen 9cb7002b98 Merge branch 'wip/jimmac/large-title-letterspacing' into 'master'
Adwaita: revert letter-spacing for large-title

Closes #2932

See merge request GNOME/gtk!2243
2020-07-14 11:47:36 +00:00
Yuri Chornoivan eb9c91c0a9 Update Ukrainian translation 2020-07-14 10:33:34 +00:00
Jakub Steiner be07153efa Adwaita: revert letter-spacing for large-title
Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/2932
2020-07-14 12:24:25 +02:00
Jakub Steiner 627ec82e60 Adwaita: sidebar color for file picker
- use menu like hovers and desaturated selected_bg_color

Partially addresses https://gitlab.gnome.org/GNOME/gtk/-/issues/1586
2020-07-14 11:37:29 +02:00
Matthias Clasen ccc34ca06c Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2241
2020-07-14 02:43:25 +00:00
Matthias Clasen 2b5dd0082d inspector: Show some information about expressions
This is not too useful, but better than nothing.
2020-07-13 20:49:56 -04:00
Matthias Clasen 7b36b339aa expression: Add some introspection
Add a few apis to peek inside expressions, mainly
for the benefit of GtkInspector and similar uses.
2020-07-13 20:19:07 -04:00
Matthias Clasen b7eb663b82 gtk-demo: Make the words demo expand
We want to fill the window here.
2020-07-13 17:54:27 -04:00
Matthias Clasen 1b28353be5 inspector: Ellipsize in the object tree
We don't want a long label to blow up the width
of the inspector window.
2020-07-13 17:32:52 -04:00
Matthias Clasen a07c030d02 inspector: Fix up input enum names
We've recently added and removed a few values in these
enumerations. Keep the names in sync, so we don't show
nonsense.
2020-07-13 17:13:43 -04:00
Matthias Clasen 339cccdf53 NEWS: Updates and fixes 2020-07-13 17:10:22 -04:00
Matthias Clasen 577126e99c Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2240
2020-07-13 20:48:08 +00:00
Matthias Clasen 125ea5ee4a treeexpander: Be focusable
We need to be focusable so that we can take focus
if the child doesn't.
2020-07-13 15:06:35 -04:00
Matthias Clasen 3c5afc06d1 searchbar: Set a focus vfunc
We don't want to take focus ourselves here.
2020-07-13 15:06:08 -04:00
Matthias Clasen f87c15f4f9 Merge branch 'wip/jimmac/file-dialog-sidebar-color' into 'master'
Adwaita: sidebar color for file picker

Closes #1586

See merge request GNOME/gtk!2238
2020-07-13 16:31:07 +00:00
Jakub Steiner fe5c0e2fe3 Adwaita: sidebar color for file picker
- avoid using the selected blue for the sidebar

Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/1586
2020-07-13 17:03:55 +02:00
Matthias Clasen c8421cfd82 Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2236
2020-07-13 14:38:03 +00:00
Matthias Clasen fbf99b8d65 Merge branch 'wip/carlosg/windowhandle-gesture-state' into 'master'
gtkwindowhandle: Only claim gesture on action

See merge request GNOME/gtk!2237
2020-07-13 14:32:06 +00:00
Yuri Chornoivan 57312c9b79 Update Ukrainian translation 2020-07-13 14:18:40 +00:00
Carlos Garnacho 35d2539ef8 gtkwindowhandle: Only claim gesture on action
The press gesture does not need to set claimed state just for n-press
tracking, it will however reset all other click gestures on each press
if the event gets propagated all the way up.

Fixes tracking of multi-press in gestures in widgets that are children
of the window handle. E.g. the headerbar listview in the "File browser"
gtk4-demo demo.
2020-07-13 15:48:12 +02:00
Matthias Clasen 08a4f4552c Give the inspector a devel header too
Lets clearly communicate that we're unstable.
2020-07-13 08:28:02 -04:00
Matthias Clasen 6502d3669f print-editor: Set the devel style class
Lets clearly communicate that we're unstable.
2020-07-13 08:27:51 -04:00
Matthias Clasen 53831e67a7 Integrate the new icons
Install and use the node-editor and print-editor icons.
2020-07-13 07:30:46 -04:00
Jakub Steiner e742fc1206 demos: icons for Print and Node Editors
- probably needs meson build hooks
2020-07-13 07:30:46 -04:00
Piotr Drąg 4ef5ee23e6 Update POTFILES.in 2020-07-13 13:17:37 +02:00
Matthias Clasen 4a8330fda0 Merge branch 'matthiasc/for-master' into 'master'
gtk-demo: Work harder to filter the tree

See merge request GNOME/gtk!2234
2020-07-12 23:16:35 +00:00
Matthias Clasen b4096cee64 gtk-demo: Work harder to filter the tree
Arrange for an item to be visible if it either
matches the filter or has children that do.
2020-07-12 18:26:56 -04:00
Matthias Clasen 032302c358 Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2233
2020-07-12 21:23:07 +00:00
Matthias Clasen a888e1cb65 demo: Clear filter when search is stopped
When the search entry disappears on Escape,
reset the search string to "", so we don't
end up with a filtered list and no obvious
way to remove the filtering.
2020-07-12 16:47:51 -04:00
Matthias Clasen c80b33b2ad gtk-demo: Make the search bar appear for typing
Having the search bar present from the start is
a bit jarring. Make it appear when called for.
2020-07-12 16:26:17 -04:00
Matthias Clasen f32239df1f searchbar: Add a key-capture-widget property
This is handy to set up this relationship in ui files,
and also makes it accessible in the inspector.
2020-07-12 16:25:48 -04:00
Matthias Clasen 22c1b541df Merge branch 'wip/sadiq/demo-filter' into 'master'
demo: Add a search filter

See merge request GNOME/gtk!2232
2020-07-12 19:04:00 +00:00
Matthias Clasen 78a59c95fe Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2231
2020-07-12 16:59:10 +00:00
Mohammed Sadiq 7583d48266 demo: Add a search filter 2020-07-12 22:19:40 +05:30
Matthias Clasen f1188aaeac Fix gtk_file_chooser_error_stack_set_custom_error
This never worked, due to a typo.
2020-07-12 12:15:08 -04:00
Matthias Clasen 4dac5c222f Drop GtkFileChooserEmbed
This private interface is no longer used.
2020-07-12 12:15:08 -04:00
Matthias Clasen 0145809a94 filechooserdialog: Stop using ::response-requested
Replace the ::response-requested signal by an action.
2020-07-12 12:15:08 -04:00
Matthias Clasen 2e6b8810c0 filechooserdialog: Stop using the embed interface
Just call private GtkFileChooserWidget api. There
is no real justification for diverting this through
an extra interface.
2020-07-12 10:59:49 -04:00
Matthias Clasen d8abcdb5a1 Remove unused includes
Only GtkFileChooserWidget and GtkFileChooserDialog
use the GtkFileChooserEmbed interface.
2020-07-12 10:59:31 -04:00
Matthias Clasen 65ecfa20dd filechooserwidget: Use dropdown api better
We now have GtkStringList, so we can implement
the choice api a little cleaner with it.
2020-07-12 10:58:33 -04:00
Matthias Clasen aa5ab02166 filechooserwidget: Remove homegrown profiling
We have sysprof support now, so we no longer have
to use this homegrown profiler.
2020-07-12 10:58:33 -04:00
Matthias Clasen 7ddbbb50ff Merge branch 'drop-file-system' into 'master'
Drop file system

See merge request GNOME/gtk!2229
2020-07-12 14:41:01 +00:00
Matthias Clasen f2eb036119 Merge branch 'matthiasc/for-master' into 'master'
gtk-demo: Make style apply in the file browser

See merge request GNOME/gtk!2230
2020-07-12 13:58:30 +00:00
Matthias Clasen 8a8b96bf4b Drop GtkFileSystem
It is no longer used.
2020-07-12 09:49:31 -04:00
Matthias Clasen bdcda2d8f0 filechooserwidget: Stop using GtkFileSystem
Just use gio directly.
2020-07-12 09:49:31 -04:00
Matthias Clasen ef3f997d55 filechooser: Drop get_file_system from the interface
This is no longer used.
2020-07-12 09:49:31 -04:00
Matthias Clasen b41d380230 filechooserbutton: Stop using GtkFileSystem
Just use gio directly.
2020-07-12 09:49:31 -04:00
Matthias Clasen 0210850e86 Reduce includes of gtkfilesystem.h
Move a few non-filesystem helpers to gtkfileutils.h,
and drop the include in all the places where it isn't needed.
2020-07-12 09:12:43 -04:00
Matthias Clasen 053223bf65 pathbar: Stop using GtkFileSystem
This is just a thin wrapper around some gio functionality
these days, and we want to get rid of it.
2020-07-12 09:12:43 -04:00
Matthias Clasen 746b84cc0f gtk-demo: Make style apply in the file browser
Commit 5afe6f7825 claims to make this demo
'look good', but it failed to actually make its
css apply. Now it really looks good.
2020-07-12 08:11:42 -04:00
Matthias Clasen f1ad883e00 pathbar: Drop the Private struct 2020-07-11 17:23:55 -04:00
Matthias Clasen 191e0e8d5e Merge branch 'matthiasc/for-master' into 'master'
Fix the build with clang

See merge request GNOME/gtk!2225
2020-07-10 19:29:18 +00:00
Matthias Clasen 55217e2181 Fix the build with clang
clang doesn't allow G_GNUC_FALLBACK in dead code.
Seems silly, but what can we do.
2020-07-10 13:21:23 -04:00
Emmanuele Bassi 7c8cd23c5f Merge branch 'ebassi/ci-timeout' into 'master'
Ebassi/ci timeout

See merge request GNOME/gtk!2223
2020-07-10 17:01:56 +00:00
Matthias Clasen 6aafb81702 Merge branch 'ci-tweaks' into 'master'
ci: Use lsan again

See merge request GNOME/gtk!2224
2020-07-10 16:13:48 +00:00
Emmanuele Bassi 0578422612 build: Restructure the tests to use dictionaries
Instead of an array of arrays, let's use an array of dictionaries; it's
easier to add optional keys without requiring to remember where to put
empty arrays.
2020-07-10 16:32:15 +01:00
Emmanuele Bassi ad04da84c9 Add the filtermodel-exhaustive test to the slow suite
This increases the default timeout.
2020-07-10 16:16:15 +01:00
Emmanuele Bassi 333b013f7f Increase the default timeout for slow tests
If a test is part of the 'slow' test suite, we should increment the
default timeout to compensate.
2020-07-10 16:13:37 +01:00
Matthias Clasen b3dc517565 ci: Use lsan again
Turning it off didn't fix the crashes; and we allow
the asan build to fail anyway now. And the leak reports
are useful whenever it doesn't crash.
2020-07-10 11:11:42 -04:00
Emmanuele Bassi 70e4dabe89 ci: Increase the timeout multiplier
We do have some slow tests.
2020-07-10 16:08:59 +01:00
Emmanuele Bassi d3443d6f2a ci: Use the timeout multiplier from the environment
When running our test suite on our CI infrastructure.
2020-07-10 16:08:14 +01:00
Matthias Clasen a508f68044 Merge branch 'asan-ci' into 'master'
Asan ci

See merge request GNOME/gtk!2214
2020-07-10 13:04:34 +00:00
Matthias Clasen f191b64bbc Disable lsan for now
The leak sanitizer causes on average 3-4 tests
to segfault during a testsuite run. Disable it
for now to see if we can get a successful
testsuite run with asan alone.
2020-07-10 07:32:48 -04:00
Matthias Clasen e9efe77839 Merge branch 'wip/Jehan/gio-querymodules-pkg-config-master' into 'master'
build-aux: search various Glib/GIO utilities in .pc file.

See merge request GNOME/gtk!2129
2020-07-09 23:53:25 +00:00
Matthias Clasen d98c0d32f2 ci: Add a build with asan
Run our testsuite under asan. We do this in a
separate build, since we need to turn off
introspection to make the build succeed.

As Michael Catanzaro pointed out, this requires a
privileged runner in order to use kernel apis.
2020-07-09 19:43:06 -04:00
Matthias Clasen dfa2dcceb8 Merge branch 'matthiasc/for-master' into 'master'
x11: Plug a memory leak

See merge request GNOME/gtk!2222
2020-07-09 23:06:37 +00:00
Matthias Clasen d441e7106b x11: Plug a memory leak
Don't leak atoms when we're storing the clipboard.
2020-07-09 18:19:32 -04:00
Benjamin Otte 4cd92f979c Merge branch 'wip/otte/for-master' into 'master'
Wip/otte/for master

See merge request GNOME/gtk!2221
2020-07-09 21:34:02 +00:00
Benjamin Otte d1a068e5b1 sorter: Remove a return_if_fail()
It's too expsensive.
2020-07-09 22:29:36 +02:00
Benjamin Otte 4d90846182 testsuite: Be more exhaustive
Create larger source models in tests, so that we hit the incremental
batch size more often and have a higher chance to expose bugs there.
2020-07-09 22:29:36 +02:00
Benjamin Otte 986f721938 filterlistmodel: Don't filter out every 513th element
Incremental filtering would skip every 513th element due to an
off-by-one error.

Test included
2020-07-09 22:29:36 +02:00
Matthias Clasen 7903246355 Ignore more leaks in asan
These showed up in ci. The atk-bridge will
be gone before too long anyway. Since we
may not have debug symbols in ci, just at
the so's.
2020-07-09 16:18:07 -04:00
Matthias Clasen 0252ae2be3 Merge branch 'wip/carlosg/range-autoscroll' into 'master'
gtkrange: group gestures the right way around

See merge request GNOME/gtk!2220
2020-07-09 20:05:07 +00:00
Matthias Clasen fa90e42a38 ci: Set LSAN_OPTIONS for tests
When running the testsuite with the address sanitizer,
many of our dependencies cause it to report cause it
to report memory leaks, causing tests to fail.
Therefore, point the leak sanitizer at a list of
suppressions. The list is kept in the lsan.supp
file in git.
2020-07-09 15:07:50 -04:00
Matthias Clasen 2d36109565 ci: Use the fedora:v20 image
This image includes libasan and libubsan.
2020-07-09 15:07:50 -04:00
Matthias Clasen de8258171a ci: Mention image layering in the README 2020-07-09 15:07:50 -04:00
Matthias Clasen 2ed6224778 ci: Add libasan and libubsan to the image
Add libasan and libubsan to fedora-base:v20,
and build fedora:20 on top of it.

This is so we can build and run the tests with
the address and undefined behavior sanitizers.
2020-07-09 15:07:50 -04:00
Carlos Garnacho e1a0171094 gtkrange: group gestures the right way around
The gtk_gesture_group() call is not a commutative operation, it
takes two gestures, maybe detaches the first one from its current
group, and adds it to the same group than the second gesture.

With the flipped argument order here, GtkRange was actually detaching
the same gesture in order to group it with a second one two times, so
the desired effect to group all 3 gestures was not achieved.

Fixes autoscroll as the drag gesture is now actually grouped with the
click one, so drag offsets can be accessed from the autoscroll
timeout.
2020-07-09 20:49:25 +02:00
Matthias Clasen 395521f3d3 x11: Plug a memory leak
Don't leak atoms when we're storing the clipboard.
2020-07-09 13:52:53 -04:00
Matthias Clasen 8c95a84ea4 Merge branch 'matthiasc/for-master' into 'master'
css: Plug a memory leak

Closes #2921

See merge request GNOME/gtk!2219
2020-07-09 17:19:57 +00:00
Matthias Clasen 75db19c789 css: Plug a memory leak
When a rule has no styles, we don't add it
to our ruleset. Since we are not adopting
the selectors in this case, we must free them.

Fixes: #2921
2020-07-09 12:14:18 -04:00
Matthias Clasen f00d2b30bb Merge branch 'wip/carlosg/scrollbar-fixes' into 'master'
Scrollbar fixes

Closes #2879

See merge request GNOME/gtk!2216
2020-07-09 15:56:13 +00:00
Carlos Garnacho c0c5ce2f9b gdk/x11: Ignore regular crossing events while in implicit grabs
If we create an implicit grab on a surface, leave the surface, and
release the button, we would get 2 XI_Leave events, one with mode
XINotifyNormal when the pointer leaves the surface, and another with
mode XINotifyUngrab when the button is released.

Meanwhile, the upper layers rely on crossing events being paired,
and particularly in no crossing event being sent until the implicit
grab is dismissed (either by releasing it, or via more pervasive
grabs).

Ignoring the set of XINotifyNormal events while an implicit grab
is active adapts the X11 backend to this behavior. If the grab were
released or taken away by another grab, a crossing event with one
of the other XINotify*Grab/XINotify*Ungrab will be generated.

Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/2879
2020-07-09 17:02:07 +02:00
Matthias Clasen ee9f9ae05e Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2212
2020-07-09 14:49:42 +00:00
Matthias Clasen 387649ded4 Merge branch 'ebassi/subprojects-depth' into 'master'
Use depth=1 for cloning sub-projects

See merge request GNOME/gtk!2215
2020-07-09 14:39:01 +00:00
Matthias Clasen be12131d74 Merge branch 'file-chooser-api-cleanup-2' into 'master'
File chooser api cleanup 2

See merge request GNOME/gtk!2213
2020-07-09 14:31:14 +00:00
Carlos Garnacho 896ebdc9d7 gtkscrolledwindow: Look up correctly target in captured motion events
Check correctly that the captured motion events are emitted towards the
content or one of the scrollbars, in order to have it set the expected
"over" state depending on whether the drag begins from the scrolledwindow
content or one of the scrollbars.

Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/2879
2020-07-09 16:10:55 +02:00
Matthias Clasen bc58bd0b83 NEWS: Updates 2020-07-09 09:29:09 -04:00
Matthias Clasen 8d4c87876b Add a suppression file for asan
This can be used similar to valgrind suppressions:

LSAN_OPTIONS=suppressions=`pwd`/lsan.supp meson  tests -Cbuild
2020-07-09 09:29:09 -04:00
Matthias Clasen cebc99ddc7 tests: Plug some more memory leaks
These showed up under asan.
2020-07-09 09:29:09 -04:00
Matthias Clasen 1b62203f18 cups: Plug a memory leak
This showed up under asan.
2020-07-09 09:29:09 -04:00
Matthias Clasen 06dd8c2cfd Merge branch 'wayland_surface_app_id_changing' into 'master'
add a way to change the application_id of a toplevel wayland GdkSurface

See merge request GNOME/gtk!2205
2020-07-09 13:28:07 +00:00
Emmanuele Bassi 5da21ca4dc Use depth=1 for cloning sub-projects
We don't really need the full history and branches when building
sub-projects.

This should shave some bandwidth and time in our CI pipeline as well.
2020-07-09 14:07:14 +01:00
Matthias Clasen 3e16ef33b0 Merge branch 'fix-levelbar-layout' into 'master'
levelbar: Chainup to parent buildable when handling custom tags

See merge request GNOME/gtk!2200
2020-07-09 11:42:33 +00:00
Matthias Clasen 2746a2d929 filechooser: Drop the ::selection-changed signal
This signal does not work on native file choosers,
and it exposes internals of the widget that should
not be public. And it is just not very interesting.
2020-07-09 02:06:31 -04:00
Matthias Clasen e31bacf7be filechooser: Drop the ::current-folder-changed signal
This signal does not work on native file choosers,
and it exposes internals of the widget that should
not be public. And it is just not very interesting.
2020-07-09 01:48:33 -04:00
Matthias Clasen 911ae64931 filechoosernative: Update docs
Remove mention of things that are no longer
in the filechooser api.
2020-07-09 01:44:09 -04:00
Matthias Clasen 99a0b35705 filechooser: Drop the ::file-activated signal
This signal does not work on native file choosers,
and it exposes internals of the widget that should
not be public. And it is just not very interesting.
2020-07-09 01:40:08 -04:00
Matthias Clasen 89bf8af878 filechooser: Make get_files return a list model
Like the other list getters in this interface,
make gtk_file_chooser_get_files() return a
list model.
2020-07-09 01:29:20 -04:00
Matthias Clasen f3744c991a Cosmetics 2020-07-09 01:02:21 -04:00
Matthias Clasen dcee15c0f1 filechooser: Drop gtk_file_chooser_[un]select_file
Most use cases for these apis can be handled with
gtk_file_chooser_set_file and/or
gtk_file_chooser_set_current_folder.
2020-07-09 00:50:03 -04:00
Matthias Clasen 2321e9de05 filechooser: Drop gtk_file_chooser_[un]_select_all
For now, we just remove them as public api, they are
still used internally.
2020-07-09 00:50:03 -04:00
Matthias Clasen 73dcda460f tests: Stop using file chooser apis that are going away
gtk_file_chooser_[un]select_all are going away, stop
using them.
2020-07-09 00:50:03 -04:00
Matthias Clasen 0f8bc67a98 docs: Add gtk_file_chooser_get_shortcut_folders 2020-07-09 00:50:03 -04:00
Matthias Clasen 379d830123 Merge branch 'printing-portal-fix-master' into 'master'
Remember to call print_cb even if print operation is cancelled.

Closes #2917

See merge request GNOME/gtk!2211
2020-07-09 04:40:34 +00:00
Matthias Clasen bc8bc68b80 Add a suppression file for asan
This can be used similar to valgrind suppressions:

LSAN_OPTIONS=suppressions=`pwd`/lsan.supp meson  tests -Cbuild
2020-07-09 00:33:35 -04:00
Matthias Clasen 8c4df51a14 tests: Plug some more memory leaks
These showed up under asan.
2020-07-09 00:33:14 -04:00
Matthias Clasen 06d67d2384 cups: Plug a memory leak
This showed up under asan.
2020-07-09 00:32:17 -04:00
Casey Jao cc8bb5fc54 Remember to call print_cb even if print operation is cancelled.
Closes #2917.
2020-07-08 23:32:43 -04:00
Matthias Clasen 8fb1e33d0f Merge branch 'matthiasc/for-master' into 'master'
directorylist: Fix file monitoring implementation

See merge request GNOME/gtk!2209
2020-07-09 02:08:53 +00:00
Matthias Clasen 0dc946da63 testsuite: Assorted leak fixes
All found by asan.
2020-07-08 17:44:49 -04:00
Matthias Clasen 26a23d3e56 shortcuttrigger: Fix some leaks in error paths
Found while running the testsuite under asan.
2020-07-08 17:44:42 -04:00
Matthias Clasen 766f4bc8fe css: Fix some memory leaks in error paths
Found while running the testsuite under asan.
2020-07-08 17:44:36 -04:00
Matthias Clasen 3d008d5929 picture: Don't leak alternative-test
This leak showed up while running the testsuite
under asan.
2020-07-08 17:44:29 -04:00
Matthias Clasen 0546e26434 bookmarklist: Don't leak uris
This leak showed up in multiple places while
running the testsuite under asan.
2020-07-08 17:44:23 -04:00
Matthias Clasen e6d8eedc00 testsuite: Fix a memory leak in the bitmask tests
This was showing up when running under asan.
2020-07-08 17:44:16 -04:00
Matthias Clasen 13b37b0ba4 gsk: Fix a transform leak
This was found by running our testsuite under asan.
2020-07-08 17:44:08 -04:00
Matthias Clasen 779c71b66d testsuite: Fix some memory leaks reported by asan 2020-07-08 15:09:13 -04:00
Matthias Clasen 8e73d007f5 testsuite: Fix an asan error
asan complains that some of the memorytexture tests
read past limits. Avoid that.
2020-07-08 15:09:08 -04:00
Matthias Clasen e376d638fb directorylist: Fix file monitoring implementation
The while loops were never advancing the iterator.
Oops.
2020-07-08 15:08:53 -04:00
Yuri Chornoivan 52982a88aa Update Ukrainian translation 2020-07-08 18:28:01 +00:00
Baurzhan Muftakhidinov 422c1d9c0d Update Kazakh translation 2020-07-08 17:44:28 +00:00
Daniel Șerbănescu ccc8ad8700 Update Romanian translation 2020-07-08 16:22:30 +00:00
Florentina Mușat 6b0eb970d8 Update Romanian translation 2020-07-08 16:17:12 +00:00
Florentina Mușat 775e35865c Update Romanian translation 2020-07-08 08:33:20 +00:00
Matthias Clasen 49ce680d53 Merge branch 'directorylist-monitor' into 'master'
directorylist: Add monitoring

See merge request GNOME/gtk!2207
2020-07-08 02:25:46 +00:00
Matthias Clasen 463f3d3a52 directorylist: Add monitoring
Add a GtkDirectoryList:monitored property, and
keep a file monitor if it is set to TRUE. To ensure
that the list reflects reality, we reload the directory
when monitoring is turned on after the fact. This means
that turning monitoring is expensive, while turning it
off is cheap, so we default to monitoring being on.
2020-07-07 21:21:41 -04:00
Jordi Mas f6347f18b0 Fixes to Catalan translations 2020-07-07 20:24:24 +02:00
Yuri Chornoivan 2e959fe300 Update Ukrainian translation 2020-07-07 18:03:32 +00:00
Yuri Chornoivan 56f771ba29 Update Ukrainian translation 2020-07-07 17:55:52 +00:00
Baurzhan Muftakhidinov 32e96215b4 Update Kazakh translation 2020-07-07 17:21:22 +00:00
Matthias Clasen 86f800e11d Merge branch 'inspector-navigation' into 'master'
Inspector navigation

See merge request GNOME/gtk!2201
2020-07-07 17:04:51 +00:00
Matthias Clasen 4d371b2b16 inspector: Fix property list styling
We use dropdowns here now, so style them.

Also, avoid the swoosh when switching to the
property list, when everything shrinks.
2020-07-07 11:21:42 -04:00
Caolán McNamara 7e97c2513f gtk#767 add a way to change the application_id of a toplevel wayland GdkSurface
so LibreOffice can reuse toplevels and get the right task icons

references;
 https://gitlab.gnome.org/GNOME/gtk/-/issues/767
 https://lists.freedesktop.org/archives/wayland-devel/2019-July/040704.html
 https://gitlab.freedesktop.org/wayland/wayland-protocols/commit/e0d6ad1d5e7e80321285a9b14ca3329289eb02e6
 https://bugs.documentfoundation.org/show_bug.cgi?id=125934
 https://bugzilla.redhat.com/show_bug.cgi?id=1334915
 https://bugreports.qt.io/browse/QTBUG-77182
2020-07-07 15:56:12 +01:00
Emmanuele Bassi 2bf5a150e6 Merge branch 'issue-2915' into 'master'
Issue 2915

Closes #2915

See merge request GNOME/gtk!2204
2020-07-07 11:48:07 +00:00
Emmanuele Bassi 18c87faaa5 Annotate string array
Fixes: #2915
2020-07-07 12:06:28 +01:00
Emmanuele Bassi fdeda388bf Fix "not nullable" annotation 2020-07-07 12:03:44 +01:00
Stefano Facchini ea2c27c640 levelbar: Chainup to parent buildable when handling custom tags
This is necessary to handle <layout> tags.
2020-07-07 09:34:00 +02:00
Matthias Clasen dfc04a590d inspector: Reshuffle the sidebar
Move the sidebar in the object page below the
object header, for a more logical hierarchy.
2020-07-07 02:05:18 -04:00
Matthias Clasen fe5b364675 inspector: Drop unused properties
The individual pages no longer need the object tree
to show object details, this works with the window
now.
2020-07-07 01:25:21 -04:00
Matthias Clasen 9b73c55559 Merge branch 'patch-1' into 'master'
Fix typo: Filer -> Filter

See merge request GNOME/gtk!2203
2020-07-07 05:08:19 +00:00
Matthias Clasen 0b38a0663d inspector: Add dom-like navigation controls
Maintain a stack of objects, and add ˂˅˄˃ buttons
that navigate this stack, as well as the widget
tree and list models.
2020-07-07 00:51:18 -04:00
Matthias Clasen e5c0716293 inspector: Remove an unused field 2020-07-07 00:48:43 -04:00
Matthias Clasen 54a3293cad stack: Fix handling of GtkStackPage:visible
The stack wasn't updating its visible-child when
the stack pages visible property changes. This
showed up in the inspector, when showing the details
for a list model item.
2020-07-07 00:48:43 -04:00
Yuri Chornoivan 818287a7ce Update Ukrainian translation 2020-07-07 04:45:03 +00:00
Yuri Chornoivan 59119cd898 Fix typo: Filer -> Filter 2020-07-07 04:41:44 +00:00
Daniel Șerbănescu 817da34f7e Update Romanian translation 2020-07-06 20:41:16 +00:00
Daniel Șerbănescu 8fa44fc3e6 Update Romanian translation 2020-07-06 20:38:44 +00:00
Jordi Mas c7e94151b2 Update Catalan translation 2020-07-06 22:35:10 +02:00
Matthias Clasen 729ba44297 Merge branch 'wip/otte/filterlistmodel' into 'master'
Improve GtkFilterListModel

See merge request GNOME/gtk!2199
2020-07-06 15:42:44 +00:00
Matthias Clasen 2a2a6879c5 Merge branch 'file-chooser-api-cleanups' into 'master'
File chooser api cleanups

See merge request GNOME/gtk!2195
2020-07-06 15:41:56 +00:00
Matthias Clasen e7b773b031 filechooser: Add a readonly :shortcut-folders property
This makes the shortcut folders list accessible in the
the inspector.
2020-07-06 11:03:48 -04:00
Matthias Clasen 57a225681c filechooser: Add gtk_file_chooser_get_shortcuts
Replace gtk_file_chooser_list_shortcuts with a new
api that returns a list model.

Update all callers.
2020-07-06 11:03:48 -04:00
Matthias Clasen ea07a92366 filechooser: Add a readonly :filters property
This makes the filters list accessible in the
the inspector.
2020-07-06 11:03:48 -04:00
Matthias Clasen 76290e8ddb filechooser: Add gtk_file_chooser_get_filters
Replace gtk_file_chooser_list_filters with a new
api that returns a list model.

Update all callers.
2020-07-06 10:36:35 -04:00
Jordi Mas 26d83b1ab7 Update Catalan translation 2020-07-06 09:41:45 +02:00
Jordi Mas 2bba856206 Update Catalan translation 2020-07-06 08:54:41 +02:00
Benjamin Otte bf3382a89e testsuite: Add more filterlistmodel tests
These ones try to be exhaustive and randomly catch weird cases.

As such, the tests are more complicated and harder to grasp.
Sorry.
2020-07-06 03:42:43 +02:00
Benjamin Otte 3162e25671 bitset: Fix typo: gtk_bitset_slice() => gtk_bitset_splice() 2020-07-06 03:42:43 +02:00
Benjamin Otte 3d931b4fe2 bitset: Don't overflow when splicing
Testcase added.
2020-07-06 03:42:43 +02:00
Matthias Clasen fc770a383a gtk-demo: Use a progressbar in the words demo
This looks better and a bit more polished.
2020-07-06 03:42:43 +02:00
Matthias Clasen 62c385a9dd gtk-demo: No selection in the words demo
This demo is about filtering, not about selection,
so use a GtkNoSelection.
2020-07-06 03:42:43 +02:00
Matthias Clasen 7c4ad1a5c4 gtk-demo: Cosmetic fixes for the words demo
Set a window size, and don't put newlines in titles, left align and
ellipsize the label.
2020-07-06 03:42:43 +02:00
Benjamin Otte ac524bb13a demo: Make words listview load async
And add an "Open" button (why are filechooser buttons such a catastrophe
that I can't make them smaller?).
2020-07-06 03:42:43 +02:00
Benjamin Otte 66fa9380b5 filterlistmodel: Look at type of change
This way we can avoid refiltering most of an already filtered list when
the change becomes more strict.
2020-07-06 03:42:43 +02:00
Benjamin Otte b64eb6ca13 gtk-demo: Add incremental filtering to words demo 2020-07-06 03:42:43 +02:00
Benjamin Otte 9b2d8ac362 filterlistmodel: Add gtk_filter_list_model_get_pending()
This allows tracking if the model is busy filtering.
2020-07-06 03:42:43 +02:00
Benjamin Otte 2a90bc1a9b filterlistmodel: Add incremental filtering 2020-07-06 03:42:43 +02:00
Benjamin Otte d4b868d9bc filterlistmodel: Rewrite with bitset data structure
Bitsets are more powerful, less memory intensive and faster than the old
GtkRbTree version.
2020-07-06 03:42:43 +02:00
Benjamin Otte b54f6710a7 gtk-demo: Add a listview demo for filtering strings 2020-07-06 03:42:42 +02:00
Matthias Clasen 6bb7caf155 Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2198
2020-07-06 00:42:14 +00:00
Matthias Clasen 202348f9d0 filefilter: Cosmetics
Various cleanups to make this code look less ancient.
2020-07-05 19:54:57 -04:00
Matthias Clasen 1a613de2f6 filefilter: Cosmetics 2020-07-05 19:54:20 -04:00
Matthias Clasen 665df37703 filefilter: Header file cosmetics 2020-07-05 19:36:45 -04:00
Matthias Clasen acad5e4e3d filefilter: Fix an embarrassing oversight
I forgot to remove some dead code, and left the
pixbuf_formats list in the rule union. Oops.
2020-07-05 19:32:36 -04:00
Matthias Clasen 6267c8469b Merge branch 'file-filter2' into 'master'
Make GtkFileFilter a GtkFilter

See merge request GNOME/gtk!2190
2020-07-05 20:32:05 +00:00
Matthias Clasen 5a2f791bdd filefilter: Cleanups and optimizations
Make mime-type rules hold multiple types. Store the
content types, so we don't have to do mime-type -> content-type
conversion in the match function. Store content types for the
pixbuf-formats rule as well, so we can avoid memory allocation
in the match function altogether.
2020-07-05 15:12:07 -04:00
Matthias Clasen 286a00a1db docs: Cleanups for the file filter docs
Now that GtkFileFilter is a GtkFilter, move it to the
filter section of the docs. While we are at it, touch
up the docs in some places.
2020-07-05 15:10:18 -04:00
Matthias Clasen 11dd602b28 Drop gtk_file_filter_filter
It has been superseded by gtk_filter_match.
2020-07-05 15:10:18 -04:00
Matthias Clasen 35988d659d Stop using gtk_file_filter_filter
Make all users of GtkFileFilter use it via the
GtkFilter api. This is in preparation for dropping
gtk_filter_filter_filter.
2020-07-05 15:10:18 -04:00
Matthias Clasen be3449b3ce filefilter: Convert to a GtkFilter
Make GtkFileFilter implement GtkFilter.
2020-07-05 15:10:18 -04:00
Matthias Clasen 2d8fddc1e9 filefilter: Drop GtkFileFilterFlags
Replace gtk_file_filter_get_needed by gtk_file_filter_get_attributes,
which directly returns the attributes that are needed.

Update all callers.
2020-07-05 15:10:13 -04:00
Matthias Clasen 644d522d19 filefilter: Drop custom filters
These don't work with native file choosers.
2020-07-05 14:34:33 -04:00
Matthias Clasen a8b0125da1 filefilter: Drop GtkFileFilterInfo
We can just make the filter operate on GFileInfo.
This is in preparation for making GtkFileFilter a
GtkFilter.

Update all users.
2020-07-05 13:55:42 -04:00
Matthias Clasen acccac516e filefiler: No more floating
Make GtkFileFilter not be initially unowned anymore.
This is in preparation for deriving GtkFileFilter
from GtkFilter. Update all callers.
2020-07-05 12:36:47 -04:00
Matthias Clasen d65214fa4e Merge branch 'wip/otte/for-master' into 'master'
Wip/otte/for master

See merge request GNOME/gtk!2193
2020-07-05 16:06:16 +00:00
Baurzhan Muftakhidinov 1d96fc8237 Update Kazakh translation 2020-07-05 12:51:00 +00:00
Florentina Mușat 882a87ca19 Update Romanian translation 2020-07-05 10:42:46 +00:00
Benjamin Otte 1dbb8df95f stringlist: Export gtk_string_object_new()
There are various use cases where it makes sense to construct these -
from our internal testing to using them in flatten- or mapmodels.
2020-07-05 02:59:21 +02:00
Benjamin Otte f6c2c2edbd stringlist: Call splice() for adding items after construction
This has the benefit of actually allowing NULL to be passed.
2020-07-05 02:59:21 +02:00
Benjamin Otte c4e4de36f6 stringlist: Remove n_additions argument from gtk_string_list_splice()
char ** arrays are null-terminated everywhere, so make sure they are in
splice(), too.

Also fix the argument to be a const char * const * like in the
constructor.
2020-07-05 02:59:21 +02:00
Benjamin Otte 67cbb2a7d3 stringlist: Clarify docs for gtk_string_list_get_string()
Make sure it's obvious that it behaves like g_list_model_get_item() and
returns NULL for pos >= n_items.
2020-07-05 02:59:21 +02:00
Benjamin Otte a979daa8ea stringlist: Make one constructor call the other
Simplifies code.
2020-07-05 02:59:21 +02:00
Benjamin Otte fb14f50ec1 stringlist: Make property not construct-only
Massively speeds up creation of long stringlists.
2020-07-05 02:59:21 +02:00
Benjamin Otte 6099fbafc1 bitset: Add gtk_bitset_new_range()
It's a common use.
2020-07-05 02:59:21 +02:00
Benjamin Otte 6f2f828bce tests: Make testlistview be a list again
The grid conversion was for testing and should never have been
committed.
2020-07-05 02:59:21 +02:00
Benjamin Otte 795d3122cc selectionmodels: Add set_model() support
Now that we don't care about item types anymore, we can make the child
models settable.

We try to retain the selection, even when the model changes.
2020-07-05 02:59:21 +02:00
Benjamin Otte 5080730728 listmodels: Stop respecting item-type
Simplify all view model APIs and always return G_TYPE_OBJECT as the
item-type for every model.

It turns out nobody uses item-type anyway.

So instead of adding lots of APIs, forcing people to think about it and
trying to figure out how to handle filter or map models that modify item
types, just having an easy life is a better approach.

All the models need to be able to deal with any type of object going
through anyway.
2020-07-05 02:59:21 +02:00
Benjamin Otte f75a3a0e95 stringlist: Take a const char const * argument
Sucks that we need to cast a char**, but otherwise we need to cast
{"foo", "bar", "baz" } arrays.
2020-07-05 02:34:42 +02:00
Benjamin Otte b75db7d1c6 stringfilter: Don't crash if the expression returns "" 2020-07-05 00:34:21 +02:00
Benjamin Otte b03069bdf6 a11y: Remove double initialization of variables 2020-07-05 00:34:21 +02:00
Yuri Chornoivan 1c71e56e75 Update Ukrainian translation 2020-07-04 17:02:55 +00:00
Matthias Clasen 9332d0dcc8 Merge branch 'typo' into 'master'
Fixes typos

See merge request GNOME/gtk!2188
2020-07-04 15:48:29 +00:00
Matthias Clasen 9ad37583e6 Merge branch 'matthiasc/for-master' into 'master'
filechooser: Make filtering work again

See merge request GNOME/gtk!2189
2020-07-04 15:46:19 +00:00
Matthias Clasen 69975627e9 filechooser: Make filtering work again
One too many lines were dropped when this filter combo
was converted to a dropdown. Bring it back, to make
filtering work again.
2020-07-04 10:28:10 -04:00
Piotr Drąg b74a489aba Update POTFILES.in and POTFILES.skip 2020-07-04 13:37:03 +02:00
Jordi Mas 599b807726 Fixes typos 2020-07-04 10:00:25 +02:00
Jordi Mas 6510ca8bdd Update Catalan translation 2020-07-04 09:58:03 +02:00
Matthias Clasen be20a04e04 Merge branch 'selection-filter-fixes' into 'master'
Selection filter fixes

See merge request GNOME/gtk!2186
2020-07-03 16:10:03 +00:00
Matthias Clasen 92e5536335 testsuite: Add selection filter model tests
Verify that the selection filter changes mirror
the selection changes of the underlying model,
as expected. These tests verify the fixes in
the previous commit.
2020-07-03 11:12:55 -04:00
Matthias Clasen c2da2f7ecd selectionfilter: Fix bugs in signal translation
When the position is 0, we can't check for unchanged
elements below with gtk_bitset_size_in_range. And
we don't need to, either.

And be careful when translating [start,length]
intervals to [first,last] ones. Off-by-one errors
lurk everywhere.
2020-07-03 11:12:55 -04:00
Matthias Clasen 130bd5937c docs: Add guidance about list model performance
Add a section about the performance tradeoffs between
different list model implementations.
2020-07-03 09:29:19 -04:00
Boyuan Yang 54bfd380a8 Update Chinese (China) translation 2020-07-03 12:49:24 +00:00
Matthias Clasen f01d695e6c Merge branch 'matthiasc/for-master' into 'master'
inspector: Fix the monitor list width

Closes #2909

See merge request GNOME/gtk!2185
2020-07-03 05:51:29 +00:00
Matthias Clasen 619b2465c1 inspector: Fix the monitor list width
Fixes #2909
2020-07-03 01:07:13 -04:00
Matthias Clasen cc18191a8e Merge branch 'wip/exalm/show-title-buttons' into 'master'
headerbar: Show title buttons by default

See merge request GNOME/gtk!2175
2020-07-03 05:05:24 +00:00
Matthias Clasen 1f8e7c8aab Merge branch 'selection-filter' into 'master'
Selection filter

See merge request GNOME/gtk!2184
2020-07-03 04:15:12 +00:00
Matthias Clasen 671daea262 gtk-demo: Track the selection
Use GtkSelectionFilterModel to track and display the
selection. Add some other selection information for
good measure.
2020-07-02 22:59:03 -04:00
Matthias Clasen 76533513c2 Add a selection filter model
This model presents the selection of a GtkSelectionModel
as its own list model.
2020-07-02 22:59:03 -04:00
Matthias Clasen 0d3988365b filterlistmodel: Make model not construct-only
This property wasn't meant to be construct-only.
2020-07-02 22:59:03 -04:00
Benjamin Otte 0966636803 bitset: Add APIs needed for a filterlistmodel 2020-07-02 17:19:16 -04:00
Alexander Mikhaylenko 7c3b30036e headerbar: Show title buttons by default
Most of the time show-title-buttons is set to TRUE. Go ahead and make that
the default.
2020-07-02 23:51:16 +05:00
Matthias Clasen 988901294d Merge branch 'matthiasc/for-master' into 'master'
Add gtk_multi_selection_get_model

See merge request GNOME/gtk!2179
2020-07-01 01:36:47 +00:00
Matthias Clasen 43b9fc6981 Merge branch 'wip/baedert/for-master' into 'master'
Wip/baedert/for master

See merge request GNOME/gtk!2162
2020-07-01 01:35:56 +00:00
Benjamin Otte 25f670faae Merge branch 'wip/chergert/gtk4-remove-textlayout-vtable' into 'master'
textlayout: remove virtual table indirection

See merge request GNOME/gtk!2178
2020-07-01 01:19:12 +00:00
Matthias Clasen d0068a036f Add gtk_multi_selection_get_model
This getter was missing.
2020-06-30 20:47:03 -04:00
Christian Hergert fae014eb45 textlayout: remove virtual table indirection
GtkTextLayout is private now and therefore we can drop all of
the indirection through the class vtable. Instead, just call the
implementations directly and remove the unused vtable entries
for default signal handlers.
2020-06-30 17:38:31 -07:00
Matthias Clasen f0ea0be15d Merge branch 'matthiasc/for-master' into 'master'
Drop unnecessary uses of gtk_style_context_add_class

See merge request GNOME/gtk!2177
2020-06-30 22:52:18 +00:00
Matthias Clasen 9650236b23 Merge branch 'inspector-list-model' into 'master'
Inspector list model support

See merge request GNOME/gtk!2176
2020-06-30 22:17:29 +00:00
Matthias Clasen c0e2d7c62f Drop unnecessary uses of gtk_style_context_add_class
We can use gtk_widget_add_css_class instead, most places.
2020-06-30 17:42:30 -04:00
Matthias Clasen cc072eb7cd inspector: Avoid a use of gtk_style_context_add_class
We have gtk_widget_add_css_class for this now.
2020-06-30 17:10:05 -04:00
Matthias Clasen 613213f597 inspector: proper list model support
Add a data tab for list models that allows exploring
the objects in the model.
2020-06-30 17:09:55 -04:00
Matthias Clasen e25c25fcb5 Merge branch 'wip/on-the-surface-good-fences-can-make-bad-neighbors' into 'master'
x11: Handle window getting unmap while frame still pending

Closes #2902

See merge request GNOME/gtk!2168
2020-06-30 19:21:45 +00:00
Matthias Clasen 52666d6fe5 inspector: Rename DataList -> TreeData
Rename the DataList object to TreeData, in preparation
for adding a ListData object for list models. While
we are touching it, modernize it a bit (drop the Private
struct, use a layout manager, etc).
2020-06-30 15:18:37 -04:00
Ray Strode 56b3669411 x11: Avoid thawing surface until frame is drawn
Since commit 972134abe4 a frame getting
drawn has three states (with the vendor nvidia driver at least):

1. drawn by gtk waiting on the GPU
2. drawn by GPU waiting on the compositor
3. drawn by compositor

Those three states are encoded in two flags: frame_pending and
frame_still_painting.

frame_pending means step 1 is done, but step 2 and 3 are still
in progress.  frame_still_painting means step 2 is still in progress.

After step 1 is finished the surface is frozen until step 3 is finished.

When the compositor notifies gtk it's done with step 3, with a
_NET_WM_FRAME_DRAWN client message, the toolkit thaws the surface to
allow the next frame to proceed.

The compositor sometimes sends gtk a _NET_WM_FRAME_DRAWN client message
between steps 1 and 2.  This message should be ignored because it's not
a reply to the current frame.

Unfortunately, gtk currently assumes if it gets a _NET_WM_FRAME_DRAWN
client message while waiting for step 2 that it's actually at step 3,
and proceeds to draw a new frame while the existing frame is still
pending, leading to a blown assertion.

This commit addresses the problem by ignoring _NET_WM_FRAME_DRAWN
client messages from the compositor unless actually expecting one.

Fixes: #2902
2020-06-30 14:36:15 -04:00
Ray Strode e3b5b76cdd x11: Handle window getting unmapped while frame still pending
Since commit 972134abe4 we now call
glClientWaitSync for the vendor nvidia driver, to know when a frame
is ready for the compositor to process.

If a surface is hidden while a frame is still being rendered by the GPU,
the surface will never produce the damage event the code relies on to
trigger the call to glClientWaitSync. This leaves the fence dangling,
and the next time the surface is shown, it will start a fresh frame
and blow an assertion since the fence from the last frame is still
hanging around.

This commit ensures a frame gets fully wrapped up before hiding a
surface.
2020-06-30 14:36:07 -04:00
Matthias Clasen bbb28196e5 inspector: Remove list model support from the property editor
This makes the inspector lock up when used with any production
size list model, and blocks access to properties of the model
itself. Instead, we'll make the model available as an object
and add a data tab for list model contents, like we already
do for tree models.
2020-06-30 14:22:01 -04:00
Matthias Clasen 72d3a9042c Merge branch 'issue-2904' into 'master'
Add nullable annotations for gtk_cclosure_expression_new()

Closes #2904

See merge request GNOME/gtk!2172
2020-06-30 12:03:06 +00:00
Emmanuele Bassi f2853ffa8e Add nullable annotations for gtk_cclosure_expression_new()
Fixes: #2904
2020-06-30 12:11:21 +01:00
Matthias Clasen fca2ba963d gtklistitemfactory: Cosmetic documentation fixes 2020-06-29 22:11:44 -04:00
Matthias Clasen 806779769e builderlistitemfactory: Documentation fixes 2020-06-29 22:11:36 -04:00
Matthias Clasen 82aa0d1f7c expression: Add to the docs
Add some more long-form explanation of what expressions
are about and where they are used.
2020-06-29 22:10:34 -04:00
Matthias Clasen 72f1d34eca Drop GtkFunctionsListItemFactory
It has been superseded by GtkSignalsListItemFactory.
2020-06-29 22:10:34 -04:00
Matthias Clasen c267a75eef Stop using GtkFunctionsListItemFactory
This was an early attempt at a factory, and has been
superseded by GtkSignalsListItemFactory. Port all users
the the newer one.
2020-06-29 22:10:34 -04:00
Jehan 2fb755e0c9 build-aux: fallback to default glib-compile-schemas & gio-querymodules.
The pkg-config variables have been added in GLib 2.62.0. Let's fallback
to default names for these tools in such case (`pkg-config` still
returns a 0 return value, but with empty output for absent variables).
2020-06-28 12:48:27 +02:00
Jehan cd096819d8 build-aux: search various Glib/GIO utilities in .pc file.
Some distributions are renaming Glib/GIO utilities for multi-arch
reasons so pkg-config variables have been added to find the correct name
of a tool. GTK+ should use these variables instead of searching in PATH.
See glib#1796.
2020-06-28 12:46:32 +02:00
Timm Bäder 83543423e2 widget: Don't get the frame clock if we don't use it 2020-06-27 11:47:42 +02:00
Timm Bäder d0bb72a2aa label: Only care about clipboard in unrealize of we need to 2020-06-27 11:47:39 +02:00
Timm Bäder 8cc2a44268 recorder: Don't select new row when adding recording
This is what makes the recorder slow. We might want to scroll down in
the list though.
2020-06-27 11:30:02 +02:00
Timm Bäder 4800dd3f95 rendernode: Trivial whitespace change 2020-06-27 11:22:54 +02:00
Timm Bäder 2534310ce9 recorder: Remove frame time from recording rows
We should bring this back in a different way, e.g. in a way that doesn't
just use the time of the previous recording.
2020-06-27 11:15:51 +02:00
Timm Bäder 3a4fbc5e50 recorder: Remove Full/Partial render distinction
It doesn't exist anymore these days
2020-06-27 11:08:09 +02:00
Timm Bäder 89a67ac719 recorder: s/gint/int/g 2020-06-27 11:04:03 +02:00
Timm Bäder 21b84b1890 recorder: Remove some debug spew
Stop printing the number of nodes we have
2020-06-27 11:01:28 +02:00
Timm Bäder 20935f678b scale: Rearrange child widgets
Always keep the order:

 - [value]
 - [marks.top]
 - [marks.bottom]
 - trough

Which makes sense given the rendering order. Slider should be drawn
after the marks.

Makes it possible to simply remove the custom snapshot implementations
in scale and range. And Adwaita does not depend on the node order
anyway.
2020-06-27 10:51:06 +02:00
Timm Bäder c41b4130c6 textview: Remove unused define 2020-06-27 10:51:06 +02:00
Timm Bäder f1b010af66 Add .view to view widgets 2020-06-27 10:51:06 +02:00
Timm Bäder ec1133d6e1 renderbackground: Only query number of layers once
We did it once in snapshot_background and then again in snapshot_color.
2020-06-27 10:51:06 +02:00
Timm Bäder 8fcf1b78a4 renderbackground: Only query h/vrepeat if we need to 2020-06-27 10:51:06 +02:00
Timm Bäder 21f9148155 gl renderer: Fix cross-fade nodes with invisible end child
Only loading the vertex data doesn't draw anything.
2020-06-27 10:51:06 +02:00
Timm Bäder d4f0593b37 gl renderer: Handle 0/1 progress in crossfade nodes 2020-06-27 10:51:06 +02:00
463 changed files with 41596 additions and 32235 deletions
+18 -2
View File
@@ -19,8 +19,8 @@ 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: 2
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v17"
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"
@@ -180,6 +180,22 @@ static-scan:
- _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: [ asan ]
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
View File
+9
View File
@@ -35,4 +35,13 @@ branch, as well as their available versions.
- [ ] 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
+2
View File
@@ -41,12 +41,14 @@ 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 \
+1 -1
View File
@@ -1,4 +1,4 @@
FROM registry.gitlab.gnome.org/gnome/gtk/fedora-base:v19
FROM registry.gitlab.gnome.org/gnome/gtk/fedora-base:v20
ARG HOST_USER_ID=5555
ENV HOST_USER_ID ${HOST_USER_ID}
+6
View File
@@ -7,10 +7,14 @@ 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 \
@@ -30,6 +34,7 @@ case "${backend}" in
export WAYLAND_DISPLAY=wayland-5
meson test -C ${builddir} \
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
--print-errorlogs \
--setup=${backend} \
--suite=gtk \
@@ -48,6 +53,7 @@ case "${backend}" in
export BROADWAY_DISPLAY=:5
meson test -C ${builddir} \
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
--print-errorlogs \
--setup=${backend} \
--suite=gtk \
+86
View File
@@ -1,3 +1,89 @@
Overview of Changes in GTK 3.99.0
=================================
* Add GtkEditableLabel, a label that can be edited
* 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
* GtkSortListModel:
- Use timsort
- Add various tweaks that massively speed up sorting
- Add incremental sorting
* GtkWidget:
- Massively speed up action handling
* 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
- Add a new macOS backend
* 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
=================================
+45 -31
View File
@@ -1,29 +1,38 @@
{
"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",
@@ -39,18 +48,18 @@
]
},
{
"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"
}
]
},
@@ -58,7 +67,7 @@
"name" : "libsass",
"buildsystem" : "meson",
"builddir" : true,
"config-opts": [
"config-opts" : [
"--libdir=/app/lib"
],
"sources" : [
@@ -73,7 +82,7 @@
"name" : "sassc",
"buildsystem" : "meson",
"builddir" : true,
"config-opts": [
"config-opts" : [
"--libdir=/app/lib"
],
"sources" : [
@@ -85,18 +94,23 @@
]
},
{
"name": "gtk",
"buildsystem": "meson",
"builddir": true,
"config-opts": [
"name" : "gtk",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib"
],
"sources": [
"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" : "''"
}
}
}
+15 -3
View File
@@ -15,7 +15,13 @@ if 'DESTDIR' not in os.environ:
gtk_immodule_dir = os.path.join(gtk_moduledir, 'immodules')
print('Compiling GSettings schemas...')
subprocess.call(['glib-compile-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,
os.path.join(gtk_datadir, 'glib-2.0', 'schemas')])
print('Updating icon cache...')
@@ -24,8 +30,14 @@ if 'DESTDIR' not in os.environ:
print('Updating module cache for print backends...')
os.makedirs(gtk_printmodule_dir, exist_ok=True)
subprocess.call(['gio-querymodules', gtk_printmodule_dir])
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])
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])
@@ -9,7 +9,6 @@
<property name="default-height">768</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="start">
<object class="GtkButton">
<property name="icon-name">document-open-symbolic</property>
+1 -1
View File
@@ -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_TYPE_OBJECT, G_LIST_MODEL (list)));
self->model = G_LIST_MODEL (gtk_flatten_list_model_new (G_LIST_MODEL (list)));
g_object_unref (children);
g_object_unref (guides);
g_object_unref (constraints);
+2
View File
@@ -140,6 +140,7 @@
</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>
@@ -225,6 +226,7 @@
<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>modelbutton.c</file>
+78 -12
View File
@@ -597,6 +597,83 @@ css_button_new (const char *class)
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 *
@@ -670,18 +747,7 @@ do_dnd (GtkWidget *do_widget)
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), box3);
for (i = 0; colors[i]; i++)
{
GdkRGBA rgba;
GtkWidget *swatch;
gdk_rgba_parse (&rgba, colors[i]);
swatch = g_object_new (g_type_from_name ("GtkColorSwatch"),
"rgba", &rgba,
"selectable", FALSE,
NULL);
gtk_box_append (GTK_BOX (box3), swatch);
}
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"));
+244 -29
View File
@@ -1,13 +1,15 @@
/* Drop Downs
/* Lists/Selections
*
* 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 GtkDropDown and GtkSuggestionEntry widgets are modern
* alternatives to GtkComboBox and GtkEntryCompletion.
*
* They use 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.
* list models with GtkDropDown and GtkSuggestionEntry, how to
* use search and how to display the selected item differently
* from the presentation in the popup.
*/
#include <gtk/gtk.h>
@@ -92,7 +94,7 @@ strings_setup_item_full (GtkSignalListItemFactory *factory,
gtk_label_set_xalign (GTK_LABEL (title), 0.0);
description = gtk_label_new ("");
gtk_label_set_xalign (GTK_LABEL (description), 0.0);
gtk_style_context_add_class (gtk_widget_get_style_context (description), "dim-label");
gtk_widget_add_css_class (description, "dim-label");
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
box2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
@@ -218,13 +220,110 @@ get_title (gpointer item)
return g_strdup (STRING_HOLDER (item)->title);
}
static char *
get_file_name (gpointer item)
{
return g_strdup (g_file_info_get_display_name (G_FILE_INFO (item)));
}
static void
setup_item (GtkSignalListItemFactory *factory,
GtkListItem *item)
{
GtkWidget *box;
GtkWidget *icon;
GtkWidget *label;
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
icon = gtk_image_new ();
label = gtk_label_new ("");
gtk_label_set_xalign (GTK_LABEL (label), 0);
gtk_box_append (GTK_BOX (box), icon);
gtk_box_append (GTK_BOX (box), label);
gtk_list_item_set_child (item, box);
}
static void
bind_item (GtkSignalListItemFactory *factory,
GtkListItem *item)
{
GtkMatchObject *match = GTK_MATCH_OBJECT (gtk_list_item_get_item (item));
GFileInfo *info = G_FILE_INFO (gtk_match_object_get_item (match));
GtkWidget *box = gtk_list_item_get_child (item);
GtkWidget *icon = gtk_widget_get_first_child (box);
GtkWidget *label = gtk_widget_get_last_child (box);
gtk_image_set_from_gicon (GTK_IMAGE (icon), g_file_info_get_icon (info));
gtk_label_set_label (GTK_LABEL (label), g_file_info_get_display_name (info));
}
static void
setup_highlight_item (GtkSignalListItemFactory *factory,
GtkListItem *item)
{
GtkWidget *label;
label = gtk_label_new ("");
gtk_label_set_xalign (GTK_LABEL (label), 0);
gtk_list_item_set_child (item, label);
}
static void
bind_highlight_item (GtkSignalListItemFactory *factory,
GtkListItem *item)
{
GtkMatchObject *obj;
GtkWidget *label;
PangoAttrList *attrs;
PangoAttribute *attr;
const char *str;
obj = GTK_MATCH_OBJECT (gtk_list_item_get_item (item));
label = gtk_list_item_get_child (item);
str = gtk_match_object_get_string (obj);
gtk_label_set_label (GTK_LABEL (label), str);
attrs = pango_attr_list_new ();
attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
attr->start_index = gtk_match_object_get_match_start (obj);
attr->end_index = gtk_match_object_get_match_end (obj);
pango_attr_list_insert (attrs, attr);
gtk_label_set_attributes (GTK_LABEL (label), attrs);
pango_attr_list_unref (attrs);
}
static void
match_func (GtkMatchObject *obj,
const char *search,
gpointer user_data)
{
char *tmp1, *tmp2;
char *p;
tmp1 = g_utf8_normalize (gtk_match_object_get_string (obj), -1, G_NORMALIZE_ALL);
tmp2 = g_utf8_normalize (search, -1, G_NORMALIZE_ALL);
if ((p = strstr (tmp1, tmp2)) != NULL)
gtk_match_object_set_match (obj,
p - tmp1,
(p - tmp1) + g_utf8_strlen (search, -1),
1);
else
gtk_match_object_set_match (obj, 0, 0, 0);
g_free (tmp1);
g_free (tmp2);
}
GtkWidget *
do_dropdown (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
GtkWidget *button, *box, *spin, *check;
GtkWidget *button, *box, *spin, *check, *hbox, *label, *entry;
GListModel *model;
GtkExpression *expression;
GtkListItemFactory *factory;
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",
@@ -237,23 +336,51 @@ do_dropdown (GtkWidget *do_widget)
const char * const device_descriptions[] = {
"Built-in Audio", "Built-in audio", "Thinkpad Tunderbolt 3 Dock USB Audio", "Thinkpad Tunderbolt 3 Dock USB Audio", NULL
};
char *cwd;
GFile *file;
GListModel *dir;
GtkStringList *strings;
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_title (GTK_WINDOW (window), "Selections");
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);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 20);
gtk_widget_set_margin_start (hbox, 20);
gtk_widget_set_margin_end (hbox, 20);
gtk_widget_set_margin_top (hbox, 20);
gtk_widget_set_margin_bottom (hbox, 20);
gtk_window_set_child (GTK_WINDOW (window), hbox);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
gtk_box_append (GTK_BOX (hbox), box);
label = gtk_label_new ("Dropdowns");
gtk_widget_add_css_class (label, "title-4");
gtk_box_append (GTK_BOX (box), label);
/* A basic dropdown */
button = drop_down_new_from_strings (times, NULL, NULL);
gtk_box_append (GTK_BOX (box), button);
/* A dropdown using an expression to obtain strings */
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);
/* A dropdown using a non-trivial model, and search */
button = gtk_drop_down_new ();
model = G_LIST_MODEL (pango_cairo_font_map_get_default ());
@@ -270,30 +397,118 @@ do_dropdown (GtkWidget *do_widget)
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);
gtk_widget_set_margin_start (spin, 20);
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");
gtk_widget_set_margin_start (check, 20);
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);
/* A dropdown with a separate list factory */
button = drop_down_new_from_strings (device_titles, device_icons, device_descriptions);
gtk_box_append (GTK_BOX (box), button);
gtk_box_append (GTK_BOX (hbox), gtk_separator_new (GTK_ORIENTATION_VERTICAL));
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
gtk_box_append (GTK_BOX (hbox), box);
label = gtk_label_new ("Suggestions");
gtk_widget_add_css_class (label, "title-4");
gtk_box_append (GTK_BOX (box), label);
/* A basic suggestion entry */
entry = gtk_suggestion_entry_new ();
g_object_set (entry, "placeholder-text", "Words with T or G…", NULL);
strings = gtk_string_list_new ((const char *[]){
"GNOME",
"gnominious",
"Gnomonic projection",
"total",
"totally",
"toto",
"tottery",
"totterer",
"Totten trust",
"totipotent",
"totipotency",
"totemism",
"totem pole",
"Totara",
"totalizer",
"totalizator",
"totalitarianism",
"total parenteral nutrition",
"total hysterectomy",
"total eclipse",
"Totipresence",
"Totipalmi",
"Tomboy",
"zombie",
NULL});
gtk_suggestion_entry_set_model (GTK_SUGGESTION_ENTRY (entry), G_LIST_MODEL (strings));
g_object_unref (strings);
gtk_box_append (GTK_BOX (box), entry);
/* A suggestion entry using a custom model, and no filtering */
entry = gtk_suggestion_entry_new ();
cwd = g_get_current_dir ();
file = g_file_new_for_path (cwd);
dir = G_LIST_MODEL (gtk_directory_list_new ("standard::display-name,standard::content-type,standard::icon,standard::size", file));
gtk_suggestion_entry_set_model (GTK_SUGGESTION_ENTRY (entry), dir);
g_object_unref (dir);
g_object_unref (file);
g_free (cwd);
expression = gtk_cclosure_expression_new (G_TYPE_STRING, NULL,
0, NULL,
(GCallback)get_file_name,
NULL, NULL);
gtk_suggestion_entry_set_expression (GTK_SUGGESTION_ENTRY (entry), expression);
gtk_expression_unref (expression);
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_item), NULL);
g_signal_connect (factory, "bind", G_CALLBACK (bind_item), NULL);
gtk_suggestion_entry_set_factory (GTK_SUGGESTION_ENTRY (entry), factory);
g_object_unref (factory);
gtk_suggestion_entry_set_use_filter (GTK_SUGGESTION_ENTRY (entry), FALSE);
gtk_suggestion_entry_set_show_arrow (GTK_SUGGESTION_ENTRY (entry), TRUE);
gtk_box_append (GTK_BOX (box), entry);
/* A suggestion entry with match highlighting */
entry = gtk_suggestion_entry_new ();
g_object_set (entry, "placeholder-text", "Destination", NULL);
strings = gtk_string_list_new ((const char *[]){
"app-mockups",
"settings-mockups",
"os-mockups",
"software-mockups",
"mocktails",
NULL});
gtk_suggestion_entry_set_model (GTK_SUGGESTION_ENTRY (entry), G_LIST_MODEL (strings));
g_object_unref (strings);
gtk_box_append (GTK_BOX (box), entry);
gtk_suggestion_entry_set_match_func (GTK_SUGGESTION_ENTRY (entry), match_func, NULL, NULL);
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_highlight_item), NULL);
g_signal_connect (factory, "bind", G_CALLBACK (bind_highlight_item), NULL);
gtk_suggestion_entry_set_factory (GTK_SUGGESTION_ENTRY (entry), factory);
g_object_unref (factory);
}
if (!gtk_widget_get_visible (window))
-1
View File
@@ -6,7 +6,6 @@
<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>
-1
View File
@@ -7,7 +7,6 @@
<property name="title">Font Explorer</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkButton" id="reset">
<property name="receives-default">1</property>
-1
View File
@@ -30,7 +30,6 @@ do_headerbar (GtkWidget *do_widget)
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);
button = gtk_button_new ();
icon = g_themed_icon_new ("mail-send-receive-symbolic");
-1
View File
@@ -6,7 +6,6 @@
<property name="default-height">500</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkBox">
<style>
+183 -20
View File
@@ -627,6 +627,23 @@ setup_listitem_cb (GtkListItemFactory *factory,
gtk_expression_unref (color_expression);
}
static void
setup_selection_listitem_cb (GtkListItemFactory *factory,
GtkListItem *list_item)
{
GtkWidget *picture;
GtkExpression *color_expression, *expression;
expression = gtk_constant_expression_new (GTK_TYPE_LIST_ITEM, list_item);
color_expression = gtk_property_expression_new (GTK_TYPE_LIST_ITEM, expression, "item");
picture = gtk_picture_new ();
gtk_widget_set_size_request (picture, 8, 8);
gtk_expression_bind (color_expression, picture, "paintable", NULL);
gtk_list_item_set_child (list_item, picture);
}
static void
set_title (gpointer item,
const char *title)
@@ -645,7 +662,6 @@ create_color_grid (void)
{
GtkWidget *gridview;
GtkListItemFactory *factory;
GListModel *model, *selection;
gridview = gtk_grid_view_new ();
gtk_scrollable_set_hscroll_policy (GTK_SCROLLABLE (gridview), GTK_SCROLL_NATURAL);
@@ -659,13 +675,6 @@ create_color_grid (void)
gtk_grid_view_set_max_columns (GTK_GRID_VIEW (gridview), 24);
gtk_grid_view_set_enable_rubberband (GTK_GRID_VIEW (gridview), TRUE);
model = G_LIST_MODEL (gtk_sort_list_model_new (gtk_color_list_new (0), NULL));
selection = G_LIST_MODEL (gtk_multi_selection_new (model));
gtk_grid_view_set_model (GTK_GRID_VIEW (gridview), selection);
g_object_unref (selection);
g_object_unref (model);
return gridview;
}
@@ -777,6 +786,63 @@ bind_number_item (GtkSignalListItemFactory *factory,
g_free (string);
}
static void
update_selection_count (GListModel *model,
guint position,
guint removed,
guint added,
gpointer data)
{
char *text;
text = g_strdup_printf ("%u", g_list_model_get_n_items (model));
gtk_label_set_label (GTK_LABEL (data), text);
g_free (text);
}
static void
update_selection_average (GListModel *model,
guint position,
guint removed,
guint added,
gpointer data)
{
guint n = g_list_model_get_n_items (model);
GdkRGBA c = { 0, 0, 0, 1 };
guint i;
GtkColor *color;
for (i = 0; i < n; i++)
{
color = g_list_model_get_item (model, i);
c.red += color->color.red;
c.green += color->color.green;
c.blue += color->color.blue;
g_object_unref (color);
}
color = gtk_color_new ("", c.red / n, c.green / n, c.blue / n);
gtk_picture_set_paintable (GTK_PICTURE (data), GDK_PAINTABLE (color));
g_object_unref (color);
}
static void
update_progress_cb (GtkSortListModel *model,
GParamSpec *pspec,
GtkProgressBar *progress)
{
guint total;
guint pending;
total = g_list_model_get_n_items (G_LIST_MODEL (model));
total = MAX (total, 1); /* avoid div by 0 below */
pending = gtk_sort_list_model_get_pending (model);
gtk_widget_set_visible (GTK_WIDGET (progress), pending != 0);
gtk_progress_bar_set_fraction (progress, (total - pending) / (double) total);
}
static GtkWidget *window = NULL;
GtkWidget *
@@ -784,10 +850,11 @@ do_listview_colors (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkWidget *header, *gridview, *sw, *box, *dropdown;
GtkMultiSelection *selection;
GtkSortListModel *sort_model;
GtkWidget *header, *overlay, *gridview, *sw, *box, *dropdown;
GtkListItemFactory *factory;
GListStore *factories;
GListModel *model;
GtkSorter *sorter;
GtkSorter *multi_sorter;
GListStore *sorters;
@@ -797,11 +864,31 @@ do_listview_colors (GtkWidget *do_widget)
PangoAttrList *attrs;
char *string;
guint len;
GtkWidget *selection_view;
GListModel *selection_filter;
GListModel *no_selection;
GtkWidget *grid;
GtkWidget *selection_size_label;
GtkWidget *selection_average_picture;
GtkWidget *selection_info_toggle;
GtkWidget *selection_info_revealer;
GtkWidget *progress;
GtkCssProvider *provider;
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider, "/listview_colors/listview_colors.css");
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (provider),
800);
g_object_unref (provider);
sort_model = gtk_sort_list_model_new (gtk_color_list_new (0), NULL);
gtk_sort_list_model_set_incremental (sort_model, TRUE);
selection = GTK_MULTI_SELECTION (gtk_multi_selection_new (G_LIST_MODEL (sort_model)));
window = gtk_window_new ();
gtk_window_set_title (GTK_WINDOW (window), "Colors");
header = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
@@ -809,18 +896,96 @@ do_listview_colors (GtkWidget *do_widget)
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer*)&window);
overlay = gtk_overlay_new ();
gtk_window_set_child (GTK_WINDOW (window), overlay);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_overlay_set_child (GTK_OVERLAY (overlay), box);
progress = gtk_progress_bar_new ();
gtk_widget_set_hexpand (progress, TRUE);
gtk_widget_set_valign (progress, GTK_ALIGN_START);
g_signal_connect (sort_model, "notify::pending", G_CALLBACK (update_progress_cb), progress);
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), progress);
selection_info_revealer = gtk_revealer_new ();
gtk_box_append (GTK_BOX (box), selection_info_revealer);
grid = gtk_grid_new ();
gtk_revealer_set_child (GTK_REVEALER (selection_info_revealer), grid);
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);
gtk_grid_set_row_spacing (GTK_GRID (grid), 10);
gtk_grid_set_column_spacing (GTK_GRID (grid), 10);
label = gtk_label_new ("Selection");
gtk_widget_set_hexpand (label, TRUE);
gtk_widget_add_css_class (label, "title-3");
gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 5, 1);
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Size:"), 0, 2, 1, 1);
selection_size_label = gtk_label_new ("0");
gtk_grid_attach (GTK_GRID (grid), selection_size_label, 1, 2, 1, 1);
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Average:"), 2, 2, 1, 1);
selection_average_picture = gtk_picture_new ();
gtk_widget_set_size_request (selection_average_picture, 32, 32);
gtk_grid_attach (GTK_GRID (grid), selection_average_picture, 3, 2, 1, 1);
label = gtk_label_new ("");
gtk_widget_set_hexpand (label, TRUE);
gtk_grid_attach (GTK_GRID (grid), label, 4, 2, 1, 1);
sw = gtk_scrolled_window_new ();
gtk_window_set_child (GTK_WINDOW (window), sw);
gtk_widget_set_hexpand (sw, TRUE);
gtk_grid_attach (GTK_GRID (grid), sw, 0, 1, 5, 1);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC);
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_selection_listitem_cb), NULL);
selection_view = gtk_grid_view_new_with_factory (factory);
gtk_widget_add_css_class (selection_view, "compact");
gtk_grid_view_set_max_columns (GTK_GRID_VIEW (selection_view), 200);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), selection_view);
sw = gtk_scrolled_window_new ();
gtk_box_append (GTK_BOX (box), sw);
gridview = create_color_grid ();
gtk_grid_view_set_model (GTK_GRID_VIEW (gridview), G_LIST_MODEL (selection));
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), gridview);
model = gtk_grid_view_get_model (GTK_GRID_VIEW (gridview));
g_object_get (model, "model", &model, NULL);
gtk_widget_set_hexpand (sw, TRUE);
gtk_widget_set_vexpand (sw, TRUE);
selection_filter = G_LIST_MODEL (gtk_selection_filter_model_new (GTK_SELECTION_MODEL (selection)));
g_signal_connect (selection_filter, "items-changed", G_CALLBACK (update_selection_count), selection_size_label);
g_signal_connect (selection_filter, "items-changed", G_CALLBACK (update_selection_average), selection_average_picture);
no_selection = G_LIST_MODEL (gtk_no_selection_new (selection_filter));
gtk_grid_view_set_model (GTK_GRID_VIEW (selection_view), no_selection);
g_object_unref (selection_filter);
g_object_unref (no_selection);
selection_info_toggle = gtk_toggle_button_new ();
gtk_button_set_icon_name (GTK_BUTTON (selection_info_toggle), "emblem-important-symbolic");
gtk_widget_set_tooltip_text (selection_info_toggle, "Show selection info");
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), selection_info_toggle);
g_object_bind_property (selection_info_toggle, "active",
selection_info_revealer, "reveal-child",
G_BINDING_DEFAULT);
button = gtk_button_new_with_mnemonic ("_Refill");
g_signal_connect (button, "clicked",
G_CALLBACK (refill),
gtk_sort_list_model_get_model (GTK_SORT_LIST_MODEL (model)));
gtk_sort_list_model_get_model (sort_model));
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), button);
@@ -835,15 +1000,14 @@ do_listview_colors (GtkWidget *do_widget)
gtk_label_set_width_chars (GTK_LABEL (label), len + 2);
gtk_label_set_xalign (GTK_LABEL (label), 1);
g_signal_connect (gtk_grid_view_get_model (GTK_GRID_VIEW (gridview)),
"items-changed", G_CALLBACK (items_changed_cb), label);
g_signal_connect (selection, "items-changed", G_CALLBACK (items_changed_cb), label);
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), label);
dropdown = gtk_drop_down_new ();
gtk_drop_down_set_from_strings (GTK_DROP_DOWN (dropdown), (const char *[]) { "8", "64", "512", "4096", "32768", "262144", "2097152", "16777216", NULL });
g_signal_connect (dropdown, "notify::selected",
G_CALLBACK (limit_changed_cb),
gtk_sort_list_model_get_model (GTK_SORT_LIST_MODEL (model)));
gtk_sort_list_model_get_model (sort_model));
g_signal_connect (dropdown, "notify::selected",
G_CALLBACK (limit_changed_cb2),
label);
@@ -935,7 +1099,7 @@ do_listview_colors (GtkWidget *do_widget)
gtk_drop_down_set_model (GTK_DROP_DOWN (dropdown), G_LIST_MODEL (sorters));
g_object_unref (sorters);
g_object_bind_property (dropdown, "selected-item", model, "sorter", G_BINDING_SYNC_CREATE);
g_object_bind_property (dropdown, "selected-item", sort_model, "sorter", G_BINDING_SYNC_CREATE);
factories = g_list_store_new (GTK_TYPE_LIST_ITEM_FACTORY);
@@ -967,7 +1131,6 @@ do_listview_colors (GtkWidget *do_widget)
g_object_unref (factories);
g_object_bind_property (dropdown, "selected-item", gridview, "factory", G_BINDING_SYNC_CREATE);
g_object_unref (model);
}
if (!gtk_widget_get_visible (window))
+3
View File
@@ -0,0 +1,3 @@
.view.compact > child {
padding: 1px;
}
+3 -3
View File
@@ -1,11 +1,11 @@
list.viewswitcher {
listview.viewswitcher {
border: 1px solid gray;
}
list.viewswitcher > row {
listview.viewswitcher > row {
padding: 5px;
}
list.viewswitcher row:selected {
listview.viewswitcher row:selected {
background: gray;
}
-1
View File
@@ -174,7 +174,6 @@
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkButton">
<property name="icon-name">go-up-symbolic</property>
-1
View File
@@ -6,7 +6,6 @@
<property name="title" translatable="yes">Minesweeper</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkButton">
<property name="label">New Game</property>
+1 -5
View File
@@ -215,7 +215,6 @@ transform_settings_to_keys (GBinding *binding,
GtkFilterListModel *filter_model;
GtkFilter *filter;
GtkNoSelection *selection_model;
GtkExpression *expression;
char **keys;
guint i;
@@ -246,11 +245,8 @@ transform_settings_to_keys (GBinding *binding,
gtk_column_view_get_sorter (GTK_COLUMN_VIEW (data)));
g_object_unref (store);
expression = gtk_property_expression_new (SETTINGS_TYPE_KEY, NULL, "name");
filter = gtk_string_filter_new ();
gtk_string_filter_set_expression (GTK_STRING_FILTER (filter), expression);
filter = gtk_string_filter_new (gtk_property_expression_new (SETTINGS_TYPE_KEY, NULL, "name"));
filter_model = gtk_filter_list_model_new (G_LIST_MODEL (sort_model), filter);
gtk_expression_unref (expression);
g_object_unref (sort_model);
g_set_object (&current_filter, filter);
-1
View File
@@ -6,7 +6,6 @@
<property name="default-height">480</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="show-title-buttons">1</property>
<child type="end">
<object class="GtkToggleButton" id="search_button">
<property name="icon-name">system-search-symbolic</property>
+9 -8
View File
@@ -194,8 +194,8 @@ create_weather_model (void)
}
static void
setup_widget (GtkListItem *list_item,
gpointer unused)
setup_widget (GtkSignalListItemFactory *factory,
GtkListItem *list_item)
{
GtkWidget *box, *child;
@@ -218,8 +218,8 @@ setup_widget (GtkListItem *list_item,
}
static void
bind_widget (GtkListItem *list_item,
gpointer unused)
bind_widget (GtkSignalListItemFactory *factory,
GtkListItem *list_item)
{
GtkWidget *box, *child;
GtkWeatherInfo *info;
@@ -282,11 +282,12 @@ create_weather_view (void)
{
GtkWidget *listview;
GListModel *model, *selection;
GtkListItemFactory *factory;
listview = gtk_list_view_new_with_factory (
gtk_functions_list_item_factory_new (setup_widget,
bind_widget,
NULL, NULL));
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_widget), NULL);
g_signal_connect (factory, "bind", G_CALLBACK (bind_widget), NULL);
listview = gtk_list_view_new_with_factory (factory);
gtk_orientable_set_orientation (GTK_ORIENTABLE (listview), GTK_ORIENTATION_HORIZONTAL);
gtk_list_view_set_show_separators (GTK_LIST_VIEW (listview), TRUE);
model = create_weather_model ();
+238
View File
@@ -0,0 +1,238 @@
/* Lists/Words
*
* This demo shows filtering a long list - of words.
*
* You should have the file `/usr/share/dict/words` installed for
* this demo to work.
*/
#include <gtk/gtk.h>
static GtkWidget *window = NULL;
static GtkWidget *progress;
const char *factory_text =
"<?xml version='1.0' encoding='UTF-8'?>\n"
"<interface>\n"
" <template class='GtkListItem'>\n"
" <property name='child'>\n"
" <object class='GtkLabel'>\n"
" <property name='ellipsize'>end</property>\n"
" <property name='xalign'>0</property>\n"
" <binding name='label'>\n"
" <lookup name='string' type='GtkStringObject'>\n"
" <lookup name='item'>GtkListItem</lookup>\n"
" </lookup>\n"
" </binding>\n"
" </object>\n"
" </property>\n"
" </template>\n"
"</interface>\n";
static void
update_title_cb (GtkFilterListModel *model)
{
guint total;
char *title;
guint pending;
total = g_list_model_get_n_items (gtk_filter_list_model_get_model (model));
pending = gtk_filter_list_model_get_pending (model);
title = g_strdup_printf ("%u lines", g_list_model_get_n_items (G_LIST_MODEL (model)));
gtk_widget_set_visible (progress, pending != 0);
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progress), (total - pending) / (double) total);
gtk_window_set_title (GTK_WINDOW (window), title);
g_free (title);
}
static void
read_lines_cb (GObject *object,
GAsyncResult *result,
gpointer data)
{
GBufferedInputStream *stream = G_BUFFERED_INPUT_STREAM (object);
GtkStringList *stringlist = data;
GError *error = NULL;
gsize size;
GPtrArray *lines;
gssize n_filled;
const char *buffer, *newline;
n_filled = g_buffered_input_stream_fill_finish (stream, result, &error);
if (n_filled < 0)
{
g_print ("Could not read data: %s\n", error->message);
g_clear_error (&error);
return;
}
buffer = g_buffered_input_stream_peek_buffer (stream, &size);
if (n_filled == 0)
{
if (size)
gtk_string_list_take (stringlist, g_utf8_make_valid (buffer, size));
return;
}
lines = NULL;
while ((newline = memchr (buffer, '\n', size)))
{
if (newline > buffer)
{
if (lines == NULL)
lines = g_ptr_array_new_with_free_func (g_free);
g_ptr_array_add (lines, g_utf8_make_valid (buffer, newline - buffer));
}
if (g_input_stream_skip (G_INPUT_STREAM (stream), newline - buffer + 1, NULL, &error) < 0)
{
g_clear_error (&error);
break;
}
buffer = g_buffered_input_stream_peek_buffer (stream, &size);
}
if (lines == NULL)
{
g_buffered_input_stream_set_buffer_size (stream, g_buffered_input_stream_get_buffer_size (stream) + 4096);
}
else
{
g_ptr_array_add (lines, NULL);
gtk_string_list_splice (stringlist, g_list_model_get_n_items (G_LIST_MODEL (stringlist)), 0, (const char **) lines->pdata);
g_ptr_array_free (lines, TRUE);
}
g_buffered_input_stream_fill_async (stream, -1, G_PRIORITY_HIGH_IDLE, NULL, read_lines_cb, data);
}
static void
file_is_open_cb (GObject *file,
GAsyncResult *result,
gpointer data)
{
GError *error = NULL;
GFileInputStream *file_stream;
GBufferedInputStream *stream;
file_stream = g_file_read_finish (G_FILE (file), result, &error);
if (file_stream == NULL)
{
g_print ("Could not open file: %s\n", error->message);
g_error_free (error);
return;
}
stream = G_BUFFERED_INPUT_STREAM (g_buffered_input_stream_new (G_INPUT_STREAM (file_stream)));
g_buffered_input_stream_fill_async (stream, -1, G_PRIORITY_HIGH_IDLE, NULL, read_lines_cb, data);
g_object_unref (stream);
}
static void
load_file (GtkStringList *list,
GFile *file)
{
gtk_string_list_splice (list, 0, g_list_model_get_n_items (G_LIST_MODEL (list)), NULL);
g_file_read_async (file, G_PRIORITY_HIGH_IDLE, NULL, file_is_open_cb, list);
}
static void
file_selected_cb (GtkWidget *button,
GtkStringList *stringlist)
{
GFile *file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (button));
if (file)
{
load_file (stringlist, file);
g_object_unref (file);
}
}
GtkWidget *
do_listview_words (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkWidget *header, *listview, *sw, *vbox, *search_entry, *open_button, *overlay;
GtkFilterListModel *filter_model;
GtkNoSelection *selection;
GtkStringList *stringlist;
GtkFilter *filter;
GFile *file;
file = g_file_new_for_path ("/usr/share/dict/words");
if (g_file_query_exists (file, NULL))
{
stringlist = gtk_string_list_new (NULL);
load_file (stringlist, file);
}
else
{
char **words;
words = g_strsplit ("lorem ipsum dolor sit amet consectetur adipisci elit sed eiusmod tempor incidunt labore et dolore magna aliqua ut enim ad minim veniam quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat", " ", -1);
stringlist = gtk_string_list_new ((const char **) words);
g_strfreev (words);
}
filter = gtk_string_filter_new (gtk_property_expression_new (GTK_TYPE_STRING_OBJECT, NULL, "string"));
filter_model = gtk_filter_list_model_new (G_LIST_MODEL (stringlist), filter);
gtk_filter_list_model_set_incremental (filter_model, TRUE);
window = gtk_window_new ();
gtk_window_set_default_size (GTK_WINDOW (window), 400, 600);
header = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
open_button = gtk_file_chooser_button_new ("_Open", GTK_FILE_CHOOSER_ACTION_OPEN);
g_signal_connect (open_button, "file-set", G_CALLBACK (file_selected_cb), stringlist);
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), open_button);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer*)&window);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_window_set_child (GTK_WINDOW (window), vbox);
search_entry = gtk_search_entry_new ();
g_object_bind_property (search_entry, "text", filter, "search", 0);
gtk_box_append (GTK_BOX (vbox), search_entry);
overlay = gtk_overlay_new ();
gtk_box_append (GTK_BOX (vbox), overlay);
progress = gtk_progress_bar_new ();
gtk_widget_set_halign (progress, GTK_ALIGN_FILL);
gtk_widget_set_valign (progress, GTK_ALIGN_START);
gtk_widget_set_hexpand (progress, TRUE);
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), progress);
sw = gtk_scrolled_window_new ();
gtk_widget_set_vexpand (sw, TRUE);
gtk_overlay_set_child (GTK_OVERLAY (overlay), sw);
listview = gtk_list_view_new_with_factory (
gtk_builder_list_item_factory_new_from_bytes (NULL,
g_bytes_new_static (factory_text, strlen (factory_text))));
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), listview);
selection = gtk_no_selection_new (G_LIST_MODEL (filter_model));
gtk_list_view_set_model (GTK_LIST_VIEW (listview), G_LIST_MODEL (selection));
g_object_unref (selection);
g_signal_connect (filter_model, "items-changed", G_CALLBACK (update_title_cb), progress);
g_signal_connect (filter_model, "notify::pending", G_CALLBACK (update_title_cb), progress);
update_title_cb (filter_model);
g_object_unref (filter_model);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}
+113 -4
View File
@@ -18,6 +18,7 @@ static gchar *current_file = NULL;
static GtkWidget *notebook;
static GtkSingleSelection *selection;
static GtkWidget *toplevel;
static char **search_needle;
typedef struct _GtkDemo GtkDemo;
struct _GtkDemo
@@ -945,7 +946,18 @@ selection_cb (GtkSingleSelection *sel,
gpointer user_data)
{
GtkTreeListRow *row = gtk_single_selection_get_selected_item (sel);
GtkDemo *demo = gtk_tree_list_row_get_item (row);
GtkDemo *demo;
gtk_widget_set_sensitive (GTK_WIDGET (notebook), !!row);
if (!row)
{
gtk_window_set_title (GTK_WINDOW (toplevel), "No match");
return;
}
demo = gtk_tree_list_row_get_item (row);
if (demo->filename)
load_file (demo->name, demo->filename);
@@ -953,6 +965,84 @@ selection_cb (GtkSingleSelection *sel,
gtk_window_set_title (GTK_WINDOW (toplevel), demo->title);
}
static gboolean
filter_demo (GtkDemo *demo)
{
int i;
/* Show only if the name maches every needle */
for (i = 0; search_needle[i]; i++)
{
if (!demo->title)
return FALSE;
if (g_str_match_string (search_needle[i], demo->title, TRUE))
continue;
return FALSE;
}
return TRUE;
}
static gboolean
demo_filter_by_name (GtkTreeListRow *row,
GtkFilterListModel *model)
{
GListModel *children;
GtkDemo *demo;
guint i, n;
/* Show all items if search is empty */
if (!search_needle || !search_needle[0] || !*search_needle[0])
return TRUE;
g_assert (GTK_IS_TREE_LIST_ROW (row));
g_assert (GTK_IS_FILTER_LIST_MODEL (model));
children = gtk_tree_list_row_get_children (row);
if (children)
{
n = g_list_model_get_n_items (children);
for (i = 0; i < n; i++)
{
demo = g_list_model_get_item (children, i);
g_assert (GTK_IS_DEMO (demo));
if (filter_demo (demo))
{
g_object_unref (demo);
return TRUE;
}
g_object_unref (demo);
}
}
demo = gtk_tree_list_row_get_item (row);
g_assert (GTK_IS_DEMO (demo));
return filter_demo (demo);
}
static void
demo_search_changed_cb (GtkSearchEntry *entry,
GtkFilter *filter)
{
const char *text;
g_assert (GTK_IS_SEARCH_ENTRY (entry));
g_assert (GTK_IS_FILTER (filter));
text = gtk_editable_get_text (GTK_EDITABLE (entry));
g_clear_pointer (&search_needle, g_strfreev);
if (text && *text)
search_needle = g_strsplit (text, " ", 0);
gtk_filter_changed (filter, GTK_FILTER_CHANGE_DIFFERENT);
}
static GListModel *
create_demo_model (void)
{
@@ -1007,13 +1097,25 @@ get_child_model (gpointer item,
return NULL;
}
static void
clear_search (GtkSearchBar *bar)
{
if (!gtk_search_bar_get_search_mode (bar))
{
GtkWidget *entry = gtk_search_bar_get_child (GTK_SEARCH_BAR (bar));
gtk_editable_set_text (GTK_EDITABLE (entry), "");
}
}
static void
activate (GApplication *app)
{
GtkBuilder *builder;
GListModel *listmodel;
GtkTreeListModel *treemodel;
GtkWidget *window, *listview;
GtkWidget *window, *listview, *search_entry, *search_bar;
GtkFilterListModel *filter_model;
GtkFilter *filter;
static GActionEntry win_entries[] = {
{ "run", activate_run, NULL, NULL, NULL }
@@ -1034,6 +1136,8 @@ activate (GApplication *app)
toplevel = GTK_WIDGET (window);
listview = GTK_WIDGET (gtk_builder_get_object (builder, "listview"));
g_signal_connect (listview, "activate", G_CALLBACK (activate_cb), window);
search_bar = GTK_WIDGET (gtk_builder_get_object (builder, "searchbar"));
g_signal_connect (search_bar, "notify::search-mode-enabled", G_CALLBACK (clear_search), NULL);
listmodel = create_demo_model ();
treemodel = gtk_tree_list_model_new (FALSE,
@@ -1042,7 +1146,13 @@ activate (GApplication *app)
get_child_model,
NULL,
NULL);
selection = gtk_single_selection_new (G_LIST_MODEL (treemodel));
filter_model = gtk_filter_list_model_new (G_LIST_MODEL (treemodel), NULL);
filter = gtk_custom_filter_new ((GtkCustomFilterFunc)demo_filter_by_name, filter_model, NULL);
gtk_filter_list_model_set_filter (filter_model, filter);
search_entry = GTK_WIDGET (gtk_builder_get_object (builder, "search-entry"));
g_signal_connect (search_entry, "search-changed", G_CALLBACK (demo_search_changed_cb), filter);
selection = gtk_single_selection_new (G_LIST_MODEL (filter_model));
g_signal_connect (selection, "notify::selected-item", G_CALLBACK (selection_cb), NULL);
gtk_list_view_set_model (GTK_LIST_VIEW (listview), G_LIST_MODEL (selection));
@@ -1139,7 +1249,6 @@ out:
demo = (func) (window);
gtk_window_set_transient_for (GTK_WINDOW (demo), GTK_WINDOW (window));
gtk_window_set_modal (GTK_WINDOW (demo), TRUE);
g_signal_connect_swapped (G_OBJECT (demo), "destroy", G_CALLBACK (g_application_quit), app);
}
+22 -6
View File
@@ -24,7 +24,6 @@
<property name="default-height">600</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="headerbar">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkButton">
<property name="valign">center</property>
@@ -56,12 +55,29 @@
<property name="hscrollbar-policy">never</property>
<property name="min-content-width">150</property>
<child>
<object class="GtkListView" id="listview">
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="resource">/ui/main-listitem.ui</property>
<object class="GtkBox">
<property name="width-request">220</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkSearchBar" id="searchbar">
<property name="key-capture-widget">window</property>
<child>
<object class="GtkSearchEntry" id="search-entry"/>
</child>
</object>
</property>
</child>
<child>
<object class="GtkListView" id="listview">
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="resource">/ui/main-listitem.ui</property>
</object>
</property>
</object>
</child>
</object>
</child>
</object>
-1
View File
@@ -69,7 +69,6 @@ do_markup (GtkWidget *do_widget)
g_signal_connect (show_source, "toggled", G_CALLBACK (source_toggled), stack);
header = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), show_source);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
+2 -1
View File
@@ -18,7 +18,6 @@ demos = files([
'cursors.c',
'dialog.c',
'drawingarea.c',
'dropdown.c',
'dnd.c',
'editable_cells.c',
'entry_completion.c',
@@ -47,8 +46,10 @@ demos = files([
'listview_colors.c',
'listview_filebrowser.c',
'listview_minesweeper.c',
'dropdown.c',
'listview_settings.c',
'listview_weather.c',
'listview_words.c',
'markup.c',
'modelbutton.c',
'overlay.c',
+1 -3
View File
@@ -4,9 +4,7 @@
<property name="title" translatable="yes">Model Button</property>
<property name="resizable">0</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="show-title-buttons">1</property>
</object>
<object class="GtkHeaderBar"/>
</child>
<child>
<object class="GtkBox">
-1
View File
@@ -392,7 +392,6 @@ do_paint (GtkWidget *toplevel)
gtk_window_set_child (GTK_WINDOW (window), draw_area);
headerbar = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (headerbar), TRUE);
colorbutton = gtk_color_button_new ();
g_signal_connect (colorbutton, "color-set",
-1
View File
@@ -276,7 +276,6 @@ do_peg_solitaire (GtkWidget *do_widget)
g_signal_connect (restart, "clicked", G_CALLBACK (restart), NULL);
header = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), restart);
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window),
-1
View File
@@ -40,7 +40,6 @@ do_sidebar (GtkWidget *do_widget)
gtk_widget_set_size_request (window, 500, 350);
header = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR(header), TRUE);
gtk_window_set_titlebar (GTK_WINDOW(window), header);
gtk_window_set_title (GTK_WINDOW(window), "Stack Sidebar");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
-1
View File
@@ -470,7 +470,6 @@ do_sliding_puzzle (GtkWidget *do_widget)
g_signal_connect (restart, "clicked", G_CALLBACK (reshuffle), NULL);
header = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), restart);
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), tweak);
window = gtk_window_new ();
-1
View File
@@ -4,7 +4,6 @@
<property name="resizable">0</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="start">
<object class="GtkToggleButton" id="toggle">
<property name="label">Cycle</property>
-1
View File
@@ -73,7 +73,6 @@ do_video_player (GtkWidget *do_widget)
gtk_window_set_child (GTK_WINDOW (window), video);
title = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (title), TRUE);
gtk_window_set_titlebar (GTK_WINDOW (window), title);
open_button = gtk_button_new_with_mnemonic ("_Open");
-1
View File
@@ -21,7 +21,6 @@
<property name="default-height">768</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkBox">
<style>
@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="128px" viewBox="0 0 128 128" width="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<linearGradient id="a" gradientUnits="userSpaceOnUse" x1="43.000351" x2="85.000351" y1="39.000164" y2="39.000164">
<stop offset="0" stop-color="#26a269"/>
<stop offset="0.0934161" stop-color="#84e3b7"/>
<stop offset="0.330831" stop-color="#26a269"/>
<stop offset="0.686952" stop-color="#26a269"/>
<stop offset="0.89736" stop-color="#175e3c"/>
<stop offset="1" stop-color="#26a269"/>
</linearGradient>
<linearGradient id="b" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#c0bfbc"/>
<stop offset="0.154754" stop-color="#ffffff"/>
<stop offset="0.433722" stop-color="#bdbbb5"/>
<stop offset="0.650505" stop-color="#c1c0ba"/>
<stop offset="0.825253" stop-color="#ffffff"/>
<stop offset="1" stop-color="#c0bfbc"/>
</linearGradient>
<linearGradient id="c" gradientTransform="matrix(0.0811899 -0.046875 0.069079 0.119648 307.03142 127.069456)" x1="-1710.210571" x2="-1774.45166" xlink:href="#b" y1="-1202.376709" y2="-1202.376709"/>
<linearGradient id="d" gradientTransform="matrix(-0.0811899 -0.046875 -0.069079 0.119648 -177.242852 127.069447)" x1="-1710.210571" x2="-1774.45166" xlink:href="#b" y1="-1202.376709" y2="-1202.376709"/>
<linearGradient id="e" gradientUnits="userSpaceOnUse" x1="14" x2="56" y1="94.999964" y2="94.999964">
<stop offset="0" stop-color="#813d9c"/>
<stop offset="0.109119" stop-color="#b378ca"/>
<stop offset="0.241583" stop-color="#813d9c"/>
<stop offset="0.731841" stop-color="#813d9c"/>
<stop offset="0.872163" stop-color="#4d255d"/>
<stop offset="1" stop-color="#813d9c"/>
</linearGradient>
<linearGradient id="f" gradientUnits="userSpaceOnUse" x1="72" x2="114" y1="94.999964" y2="94.999964">
<stop offset="0" stop-color="#e66100"/>
<stop offset="0.0678478" stop-color="#ff903e"/>
<stop offset="0.168852" stop-color="#e66100"/>
<stop offset="0.886626" stop-color="#e66100"/>
<stop offset="1" stop-color="#9d4200"/>
</linearGradient>
<clipPath id="g">
<rect height="128" width="128"/>
</clipPath>
<clipPath id="h">
<rect height="128" width="128"/>
</clipPath>
<filter id="i" height="100%" width="100%" x="0%" y="0%">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
<mask id="j">
<g clip-path="url(#h)" filter="url(#i)">
<g clip-path="url(#g)">
<path d="m 51 18 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="url(#a)"/>
<path d="m 51 12 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="#57e389"/>
<path d="m 76.976562 55.453125 c 1.480469 -0.855469 3.371094 -0.347656 4.226563 1.132813 l 6.742187 11.679687 c 0.855469 1.480469 0.347657 3.371094 -1.132812 4.226563 c -1.480469 0.851562 -3.371094 0.347656 -4.226562 -1.132813 l -6.742188 -11.679687 c -0.855469 -1.480469 -0.347656 -3.371094 1.132812 -4.226563 z m 0 0" fill="url(#c)"/>
<path d="m 52.8125 55.453125 c -1.480469 -0.855469 -3.371094 -0.347656 -4.226562 1.132813 l -6.742188 11.679687 c -0.855469 1.480469 -0.347656 3.371094 1.132812 4.226563 c 1.480469 0.851562 3.371094 0.347656 4.226563 -1.132813 l 6.742187 -11.679687 c 0.855469 -1.480469 0.347657 -3.371094 -1.132812 -4.226563 z m 0 0" fill="url(#d)"/>
<path d="m 22 74 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="url(#e)"/>
<path d="m 22 68 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="#dc8add"/>
<path d="m 80 74 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="url(#f)"/>
<path d="m 80 68 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="#ffa348"/>
</g>
</g>
</mask>
<mask id="k">
<g filter="url(#i)">
<rect fill-opacity="0.8" height="128" width="128"/>
</g>
</mask>
<linearGradient id="l" gradientTransform="matrix(0 0.37 -0.98462 0 295.38501 -30.360001)" gradientUnits="userSpaceOnUse" x1="300" x2="428" y1="235" y2="235">
<stop offset="0" stop-color="#f9f06b"/>
<stop offset="1" stop-color="#f5c211"/>
</linearGradient>
<clipPath id="m">
<rect height="128" width="128"/>
</clipPath>
<clipPath id="n">
<rect height="128" width="128"/>
</clipPath>
<path d="m 51 18 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="url(#a)"/>
<path d="m 51 12 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="#57e389"/>
<path d="m 76.976562 55.453125 c 1.480469 -0.855469 3.371094 -0.347656 4.226563 1.132813 l 6.742187 11.679687 c 0.855469 1.480469 0.347657 3.371094 -1.132812 4.226563 c -1.480469 0.851562 -3.371094 0.347656 -4.226562 -1.132813 l -6.742188 -11.679687 c -0.855469 -1.480469 -0.347656 -3.371094 1.132812 -4.226563 z m 0 0" fill="url(#c)"/>
<path d="m 52.8125 55.453125 c -1.480469 -0.855469 -3.371094 -0.347656 -4.226562 1.132813 l -6.742188 11.679687 c -0.855469 1.480469 -0.347656 3.371094 1.132812 4.226563 c 1.480469 0.851562 3.371094 0.347656 4.226563 -1.132813 l 6.742187 -11.679687 c 0.855469 -1.480469 0.347657 -3.371094 -1.132812 -4.226563 z m 0 0" fill="url(#d)"/>
<path d="m 22 74 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="url(#e)"/>
<path d="m 22 68 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="#dc8add"/>
<path d="m 80 74 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="url(#f)"/>
<path d="m 80 68 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="#ffa348"/>
<g clip-path="url(#n)" mask="url(#j)">
<g clip-path="url(#m)" mask="url(#k)">
<path d="m 128 80.640625 v 47.359375 h -128 v -47.359375 z m 0 0" fill="url(#l)"/>
<path d="m 13.308594 80.640625 l 47.355468 47.359375 h 21.214844 l -47.359375 -47.359375 z m 42.421875 0 l 47.363281 47.359375 h 21.214844 l -47.363282 -47.359375 z m 42.429687 0 l 29.839844 29.839844 v -21.210938 l -8.628906 -8.628906 z m -98.160156 7.90625 v 21.214844 l 18.238281 18.238281 h 21.214844 z m 0 0"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.4 KiB

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="128px" viewBox="0 0 128 128" width="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<linearGradient id="a" gradientUnits="userSpaceOnUse" x1="43.000351" x2="85.000351" y1="39.000164" y2="39.000164">
<stop offset="0" stop-color="#26a269"/>
<stop offset="0.0934161" stop-color="#84e3b7"/>
<stop offset="0.330831" stop-color="#26a269"/>
<stop offset="0.686952" stop-color="#26a269"/>
<stop offset="0.89736" stop-color="#175e3c"/>
<stop offset="1" stop-color="#26a269"/>
</linearGradient>
<linearGradient id="b" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#c0bfbc"/>
<stop offset="0.154754" stop-color="#ffffff"/>
<stop offset="0.433722" stop-color="#bdbbb5"/>
<stop offset="0.650505" stop-color="#c1c0ba"/>
<stop offset="0.825253" stop-color="#ffffff"/>
<stop offset="1" stop-color="#c0bfbc"/>
</linearGradient>
<linearGradient id="c" gradientTransform="matrix(0.0811899 -0.046875 0.069079 0.119648 307.03142 127.069456)" x1="-1710.210571" x2="-1774.45166" xlink:href="#b" y1="-1202.376709" y2="-1202.376709"/>
<linearGradient id="d" gradientTransform="matrix(-0.0811899 -0.046875 -0.069079 0.119648 -177.242852 127.069447)" x1="-1710.210571" x2="-1774.45166" xlink:href="#b" y1="-1202.376709" y2="-1202.376709"/>
<linearGradient id="e" gradientUnits="userSpaceOnUse" x1="14" x2="56" y1="94.999964" y2="94.999964">
<stop offset="0" stop-color="#813d9c"/>
<stop offset="0.109119" stop-color="#b378ca"/>
<stop offset="0.241583" stop-color="#813d9c"/>
<stop offset="0.731841" stop-color="#813d9c"/>
<stop offset="0.872163" stop-color="#4d255d"/>
<stop offset="1" stop-color="#813d9c"/>
</linearGradient>
<linearGradient id="f" gradientUnits="userSpaceOnUse" x1="72" x2="114" y1="94.999964" y2="94.999964">
<stop offset="0" stop-color="#e66100"/>
<stop offset="0.0678478" stop-color="#ff903e"/>
<stop offset="0.168852" stop-color="#e66100"/>
<stop offset="0.886626" stop-color="#e66100"/>
<stop offset="1" stop-color="#9d4200"/>
</linearGradient>
<path d="m 51 18 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="url(#a)"/>
<path d="m 51 12 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="#57e389"/>
<path d="m 76.976562 55.453125 c 1.480469 -0.855469 3.371094 -0.347656 4.226563 1.132813 l 6.742187 11.679687 c 0.855469 1.480469 0.347657 3.371094 -1.132812 4.226563 c -1.480469 0.851562 -3.371094 0.347656 -4.226562 -1.132813 l -6.742188 -11.679687 c -0.855469 -1.480469 -0.347656 -3.371094 1.132812 -4.226563 z m 0 0" fill="url(#c)"/>
<path d="m 52.8125 55.453125 c -1.480469 -0.855469 -3.371094 -0.347656 -4.226562 1.132813 l -6.742188 11.679687 c -0.855469 1.480469 -0.347656 3.371094 1.132812 4.226563 c 1.480469 0.851562 3.371094 0.347656 4.226563 -1.132813 l 6.742187 -11.679687 c 0.855469 -1.480469 0.347657 -3.371094 -1.132812 -4.226563 z m 0 0" fill="url(#d)"/>
<path d="m 22 74 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="url(#e)"/>
<path d="m 22 68 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="#dc8add"/>
<path d="m 80 74 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="url(#f)"/>
<path d="m 80 68 h 26 c 4.417969 0 8 3.582031 8 8 v 26 c 0 4.417969 -3.582031 8 -8 8 h -26 c -4.417969 0 -8 -3.582031 -8 -8 v -26 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="#ffa348"/>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 5.75 1 c -0.414062 0 -0.75 0.335938 -0.75 0.75 v 4.5 c 0 0.414062 0.335938 0.75 0.75 0.75 h 0.191406 l -1 2 h -3.191406 c -0.414062 0 -0.75 0.335938 -0.75 0.75 v 4.5 c 0 0.414062 0.335938 0.75 0.75 0.75 h 4.5 c 0.414062 0 0.75 -0.335938 0.75 -0.75 v -4.5 c 0 -0.414062 -0.335938 -0.75 -0.75 -0.75 h -0.191406 l 1 -2 h 1.882812 l 1 2 h -0.191406 c -0.414062 0 -0.75 0.335938 -0.75 0.75 v 4.5 c 0 0.414062 0.335938 0.75 0.75 0.75 h 4.5 c 0.414062 0 0.75 -0.335938 0.75 -0.75 v -4.5 c 0 -0.414062 -0.335938 -0.75 -0.75 -0.75 h -3.191406 l -1 -2 h 0.191406 c 0.414062 0 0.75 -0.335938 0.75 -0.75 v -4.5 c 0 -0.414062 -0.335938 -0.75 -0.75 -0.75 z m 0 0"/>
</svg>

After

Width:  |  Height:  |  Size: 801 B

+9
View File
@@ -19,3 +19,12 @@ executable('gtk4-node-editor',
gui_app: true,
link_args: extra_demo_ldflags,
install: false)
# icons
icontheme_dir = join_paths(gtk_datadir, 'icons/hicolor')
foreach size: ['scalable', 'symbolic']
install_subdir('data/' + size,
install_dir: icontheme_dir
)
endforeach
+1 -1
View File
@@ -101,7 +101,7 @@ activate_about (GSimpleAction *action,
"website", "http://www.gtk.org",
"comments", "Program to test GTK rendering",
"authors", (const char *[]){ "Benjamin Otte", "Timm Bäder", NULL},
"logo-icon-name", "text-editor-symbolic",
"logo-icon-name", "org.gtk.gtk4.NodeEditor.Devel",
"title", "About GTK Node Editor",
"system-information", s->str,
NULL);
-1
View File
@@ -103,7 +103,6 @@
<property name="focus-widget">text_view</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="start">
<object class="GtkButton">
<property name="icon-name">document-open-symbolic</property>
@@ -0,0 +1,179 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="128px" viewBox="0 0 128 128" width="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="a" gradientTransform="matrix(0.232143 0 0 0.328947 -7.567033 263.82666)" gradientUnits="userSpaceOnUse" x1="88.595886" x2="536.595886" y1="-449.394012" y2="-449.394012">
<stop offset="0" stop-color="#acabae"/>
<stop offset="0.0384615" stop-color="#deddda"/>
<stop offset="0.0768555" stop-color="#c0bfbc"/>
<stop offset="0.923077" stop-color="#c0bfbc"/>
<stop offset="0.961538" stop-color="#deddda"/>
<stop offset="1" stop-color="#9a9996"/>
</linearGradient>
<linearGradient id="b" gradientUnits="userSpaceOnUse" x1="26.999876" x2="100.999876" y1="32.999688" y2="32.999688">
<stop offset="0" stop-color="#7e7c77"/>
<stop offset="0.3" stop-color="#9a9996"/>
<stop offset="1" stop-color="#9a9996"/>
</linearGradient>
<linearGradient id="c" gradientUnits="userSpaceOnUse" x1="67.467916" x2="67.467916" y1="83.999688" y2="36.782906">
<stop offset="0" stop-color="#deddda"/>
<stop offset="1" stop-color="#c0bfbc"/>
</linearGradient>
<clipPath id="d">
<path d="m 79 72 h 15 v 16 h -15 z m 0 0"/>
</clipPath>
<clipPath id="e">
<path d="m 93.21875 72.921875 l -14.21875 14.21875 h -4.0625 v -18.28125 h 18.28125 z m 0 0"/>
</clipPath>
<linearGradient id="f" gradientTransform="matrix(0 0.126951 0.126951 0 76.460862 36.359884)" gradientUnits="userSpaceOnUse" x1="344" x2="340" y1="76" y2="72">
<stop offset="0" stop-color="#d5d3cf"/>
<stop offset="1" stop-color="#ffffff"/>
</linearGradient>
<filter id="g" height="100%" width="100%" x="0%" y="0%">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
<mask id="h">
<g filter="url(#g)">
<rect fill-opacity="0.396" height="128" width="128"/>
</g>
</mask>
<linearGradient id="i" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#1c71d8"/>
<stop offset="0.323117" stop-color="#62a0ea"/>
<stop offset="0.59387" stop-color="#1b5aa6"/>
<stop offset="1" stop-color="#1c71d8"/>
</linearGradient>
<linearGradient id="j" gradientTransform="matrix(1.597748 1.597748 -1.06066 1.06066 -56.853041 -543.720139)" x1="224.504562" x2="231.453873" xlink:href="#i" y1="282.5" y2="282.5"/>
<radialGradient id="k" cx="227.599915" cy="201.029724" gradientTransform="matrix(4.072817 4.073078 -5.940048 5.939073 373.883117 -2098.049112)" gradientUnits="userSpaceOnUse" r="2.5">
<stop offset="0" stop-color="#93bdf1"/>
<stop offset="1" stop-color="#1a5fb4"/>
</radialGradient>
<linearGradient id="l" gradientTransform="matrix(2.121328 2.121328 -2.174353 2.174353 181.766074 -1021.145947)" gradientUnits="userSpaceOnUse" x1="226.90625" x2="228.86203" y1="288.75" y2="288.767151">
<stop offset="0" stop-color="#77767b"/>
<stop offset="0.443872" stop-color="#f6f5f4"/>
<stop offset="1" stop-color="#5e5c64"/>
</linearGradient>
<linearGradient id="m" gradientTransform="matrix(1.258421 1.258421 -1.06066 1.06066 57.381892 -503.024312)" gradientUnits="userSpaceOnUse" x1="223.1875" x2="233.0625" y1="278" y2="278">
<stop offset="0" stop-color="#ffa348"/>
<stop offset="0.265823" stop-color="#ffd7af"/>
<stop offset="0.734177" stop-color="#ff8d1c"/>
<stop offset="1" stop-color="#ffa348"/>
</linearGradient>
<linearGradient id="n" gradientTransform="matrix(1.573027 1.573027 -1.06066 1.06066 -14.348129 -574.754333)" x1="224.504562" x2="231.453873" xlink:href="#i" y1="282.5" y2="282.5"/>
<clipPath id="o">
<path d="m 79 72 h 15 v 16 h -15 z m 0 0"/>
</clipPath>
<clipPath id="p">
<path d="m 93.21875 72.921875 l -14.21875 14.21875 h -4.0625 v -18.28125 h 18.28125 z m 0 0"/>
</clipPath>
<mask id="q">
<g filter="url(#g)">
<rect fill-opacity="0.396" height="128" width="128"/>
</g>
</mask>
<clipPath id="r">
<rect height="152" width="192"/>
</clipPath>
<g id="s" clip-path="url(#r)">
<path d="m 29 112 c -4.433594 0 -8 -3.566406 -8 -8 v -2 c 0 4.433594 3.566406 8 8 8 h 88 c 4.433594 0 8 -3.566406 8 -8 v 2 c 0 4.433594 -3.566406 8 -8 8 z m 0 0" fill="#f6f5f4"/>
</g>
<clipPath id="t">
<rect height="128" width="128"/>
</clipPath>
<clipPath id="u">
<rect height="128" width="128"/>
</clipPath>
<mask id="v">
<g clip-path="url(#u)" filter="url(#g)">
<g clip-path="url(#t)">
<path d="m 21 16 c -4.433594 0 -8 3.566406 -8 8 v 84 c 0 4.433594 3.566406 8 8 8 h 4 v -4 h 80 v 4 h 4 c 4.433594 0 8 -3.566406 8 -8 v -84 c 0 -4.433594 -3.566406 -8 -8 -8 z m 0 0" fill="url(#a)"/>
<path d="m 21 12 h 88 c 4.417969 0 8 3.582031 8 8 v 68 c 0 4.417969 -3.582031 8 -8 8 h -88 c -4.417969 0 -8 -3.582031 -8 -8 v -68 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="#deddda"/>
<path d="m 27 28 h 74 v 10 h -74 z m 0 0" fill="url(#b)"/>
<path d="m 27 38 h 74 v 46 h -74 z m 0 0" fill="url(#c)"/>
<path d="m 24 33 c 0 1.65625 -1.34375 3 -3 3 s -3 -1.34375 -3 -3 s 1.34375 -3 3 -3 s 3 1.34375 3 3 z m 0 0" fill="#bf5f00" fill-opacity="0.964567"/>
<path d="m 18 40 h 6 v 12 h -6 z m 0 0" fill="#acacac" fill-opacity="0.984252"/>
<path d="m 18 40 h 6 v 10 h -6 z m 0 0" fill="#d1d1d1" fill-opacity="0.984252"/>
<path d="m 37 36 h 56 v 44 h -56 z m 0 0" fill="#deddda" fill-opacity="0.984252"/>
<path d="m 37 34 h 56 c 1.105469 0 2 0.894531 2 2 s -0.894531 2 -2 2 h -56 c -1.105469 0 -2 -0.894531 -2 -2 s 0.894531 -2 2 -2 z m 0 0" fill-opacity="0.940945"/>
<path d="m 37 36.859375 h 56 v 36.925781 l -14.125 14.214844 h -41.875 z m 0 0" fill="#9a9996" fill-opacity="0.984252"/>
<path d="m 37 36 h 56 v 36.925781 l -14.125 14.214844 h -41.875 z m 0 0" fill="#f6f5f4" fill-opacity="0.984252"/>
<g clip-path="url(#o)">
<g clip-path="url(#p)">
<path d="m 79 77.386719 v 9.351562 c 0 2.464844 2 4.464844 4.464844 4.464844 h 9.351562 c 2.464844 0 4.464844 -2 4.464844 -4.464844 v -9.351562 c 0 -2.464844 -2 -4.464844 -4.464844 -4.464844 h -9.351562 c -2.464844 0 -4.464844 2 -4.464844 4.464844 z m 0 0" fill="url(#f)"/>
</g>
</g>
<path d="m 27 100 h 76 c 1.109375 0 2 0.890625 2 2 v 10 h -80 v -10 c 0 -1.109375 0.890625 -2 2 -2 z m 0 0" fill="#5e5c64" fill-opacity="0.940945"/>
<path d="m 27 102 h 76 c 1.109375 0 2 0.890625 2 2 v 10 h -80 v -10 c 0 -1.109375 0.890625 -2 2 -2 z m 0 0" fill="#9a9996"/>
<path d="m 13 106 v 2 c 0 4.433594 3.566406 8 8 8 h 4 v -2 h -4 c -4.433594 0 -8 -3.566406 -8 -8 z m 104 0 c 0 4.433594 -3.566406 8 -8 8 h -4 v 2 h 4 c 4.433594 0 8 -3.566406 8 -8 z m -92 6 v 2 h 80 v -2 z m 0 0" fill="#9e9c99" fill-opacity="0.366142"/>
<path d="m 27 38 v 46 l 6 -46 z m 0 0" fill="#7e7c77" fill-opacity="0.11811"/>
<path d="m 24 32 c 0 1.65625 -1.34375 3 -3 3 s -3 -1.34375 -3 -3 s 1.34375 -3 3 -3 s 3 1.34375 3 3 z m 0 0" fill="#ffa348" fill-opacity="0.964567"/>
<use mask="url(#q)" transform="matrix(1 0 0 1 -8 -16)" xlink:href="#s"/>
<path d="m 89.503906 31.144531 l 10.066406 10.066407 l -41.71875 41.71875 l -10.066406 -10.066407 z m 0 0" fill="#ffa348"/>
<path d="m 88.246094 29.886719 l 7.550781 7.550781 l -41.71875 41.71875 l -7.550781 -7.550781 z m 0 0" fill="#ff7800"/>
<path d="m 86.789062 28.429688 l 2.515626 2.515624 l -41.71875 41.71875 l -2.515626 -2.515624 z m 0 0" fill="#ffbe6f"/>
<path d="m 121.898438 -0.101562 c -4.855469 0.921874 -11.730469 5.152343 -18.140626 11.558593 l -16.96875 16.972657 l 12.78125 12.78125 l 16.972657 -16.972657 c 6.40625 -6.40625 10.636719 -13.28125 11.558593 -18.136719 z m 0 0" fill="url(#j)"/>
<path d="m 110.011719 13.882812 c -2.1875 -0.398437 -5.421875 0.988282 -8.167969 3.730469 l -11.871094 11.875 l -6.6875 6.6875 c -4.800781 4.800781 -9.234375 12.007813 -9.648437 13.042969 c -0.484375 1.207031 -0.449219 2.730469 0.953125 4.136719 c 1.40625 1.40625 2.917968 1.441406 4.136718 0.953125 c 1.035157 -0.414063 8.292969 -4.984375 13.042969 -9.648438 l 2.402344 -2.398437 l 16.160156 -16.160157 c 2.742188 -2.746093 4.128907 -5.976562 3.730469 -8.167968 c -0.742188 1.390625 -1.859375 2.902344 -3.308594 4.347656 l -13.996094 13.996094 l -5.089843 -5.089844 l 13.996093 -13.996094 c 1.445313 -1.445312 2.960938 -2.566406 4.347657 -3.308594 z m 0 0" fill="url(#k)"/>
<path d="m 95.273438 36.914062 l -2.960938 2.960938 l -2.398438 2.402344 c -4.90625 5.101562 -11.855468 10.828125 -11.855468 10.828125 c 1.011718 -0.433594 8.167968 -5.101563 12.914062 -9.769531 l 2.402344 -2.402344 l 2.960938 -2.957032 z m 0 0" fill="#62a0ea"/>
<path d="m 87.320312 26.835938 l 13.789063 13.789062 c 0.292969 0.292969 0.292969 0.769531 0 1.0625 s -0.769531 0.292969 -1.0625 0 l -13.789063 -13.789062 c -0.292968 -0.292969 -0.292968 -0.769532 0 -1.0625 c 0.292969 -0.289063 0.769532 -0.289063 1.0625 0 z m 0 0" fill="#3584e4"/>
<path d="m 42.421875 89.765625 c -3 3 -6.382813 4.484375 -7.554687 3.3125 c -1.171876 -1.171875 0.3125 -4.554687 3.3125 -7.554687 c 3.003906 -3.003907 6.386718 -4.488282 7.558593 -3.316407 s -0.3125 4.554688 -3.316406 7.558594 z m 0 0" fill="url(#l)"/>
<path d="m 45.269531 70.347656 l -7.851562 12.511719 l 7.835937 7.925781 l 12.597656 -7.855468 z m -6.039062 13.171875 l 5.449219 5.449219 c 0.347656 0.347656 0.449218 0.933594 0.097656 1.160156 c -0.886719 0.570313 -2.9375 1.539063 -2.9375 1.539063 c -0.25 0.128906 -0.539063 0.164062 -0.773438 -0.066407 l -4.546875 -4.550781 c -0.234375 -0.230469 -0.207031 -0.527343 -0.066406 -0.773437 l 1.617187 -2.859375 c 0.207032 -0.363281 0.8125 -0.25 1.160157 0.101562 z m 0 0" fill="url(#m)"/>
<path d="m 43.332031 74.777344 l 9.867188 9.867187 c 0.394531 0.390625 0.476562 0.871094 0.128906 1.066407 l -7.710937 5.253906 c -0.308594 0.210937 -0.785157 0.160156 -1.171876 -0.226563 l -6.984374 -6.988281 c -0.386719 -0.386719 -0.4375 -0.859375 -0.230469 -1.167969 l 5.234375 -7.8125 c 0.125 -0.285156 0.558594 -0.304687 0.867187 0.007813 z m 0 0" fill="url(#n)"/>
</g>
</g>
</mask>
<mask id="w">
<g filter="url(#g)">
<rect fill-opacity="0.8" height="128" width="128"/>
</g>
</mask>
<linearGradient id="x" gradientTransform="matrix(0 0.37 -0.98462 0 295.38501 -30.360001)" gradientUnits="userSpaceOnUse" x1="300" x2="428" y1="235" y2="235">
<stop offset="0" stop-color="#f9f06b"/>
<stop offset="1" stop-color="#f5c211"/>
</linearGradient>
<clipPath id="y">
<rect height="128" width="128"/>
</clipPath>
<clipPath id="z">
<rect height="128" width="128"/>
</clipPath>
</defs>
<path d="m 21 16 c -4.433594 0 -8 3.566406 -8 8 v 84 c 0 4.433594 3.566406 8 8 8 h 4 v -4 h 80 v 4 h 4 c 4.433594 0 8 -3.566406 8 -8 v -84 c 0 -4.433594 -3.566406 -8 -8 -8 z m 0 0" fill="url(#a)"/>
<path d="m 21 12 h 88 c 4.417969 0 8 3.582031 8 8 v 68 c 0 4.417969 -3.582031 8 -8 8 h -88 c -4.417969 0 -8 -3.582031 -8 -8 v -68 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="#deddda"/>
<path d="m 27 28 h 74 v 10 h -74 z m 0 0" fill="url(#b)"/>
<path d="m 27 38 h 74 v 46 h -74 z m 0 0" fill="url(#c)"/>
<path d="m 24 33 c 0 1.65625 -1.34375 3 -3 3 s -3 -1.34375 -3 -3 s 1.34375 -3 3 -3 s 3 1.34375 3 3 z m 0 0" fill="#bf5f00" fill-opacity="0.964567"/>
<g fill-opacity="0.984252">
<path d="m 18 40 h 6 v 12 h -6 z m 0 0" fill="#acacac"/>
<path d="m 18 40 h 6 v 10 h -6 z m 0 0" fill="#d1d1d1"/>
<path d="m 37 36 h 56 v 44 h -56 z m 0 0" fill="#deddda"/>
</g>
<path d="m 37 34 h 56 c 1.105469 0 2 0.894531 2 2 s -0.894531 2 -2 2 h -56 c -1.105469 0 -2 -0.894531 -2 -2 s 0.894531 -2 2 -2 z m 0 0" fill-opacity="0.940945"/>
<path d="m 37 36.859375 h 56 v 36.925781 l -14.125 14.214844 h -41.875 z m 0 0" fill="#9a9996" fill-opacity="0.984252"/>
<path d="m 37 36 h 56 v 36.925781 l -14.125 14.214844 h -41.875 z m 0 0" fill="#f6f5f4" fill-opacity="0.984252"/>
<g clip-path="url(#d)">
<g clip-path="url(#e)">
<path d="m 79 77.386719 v 9.351562 c 0 2.464844 2 4.464844 4.464844 4.464844 h 9.351562 c 2.464844 0 4.464844 -2 4.464844 -4.464844 v -9.351562 c 0 -2.464844 -2 -4.464844 -4.464844 -4.464844 h -9.351562 c -2.464844 0 -4.464844 2 -4.464844 4.464844 z m 0 0" fill="url(#f)"/>
</g>
</g>
<path d="m 27 100 h 76 c 1.109375 0 2 0.890625 2 2 v 10 h -80 v -10 c 0 -1.109375 0.890625 -2 2 -2 z m 0 0" fill="#5e5c64" fill-opacity="0.940945"/>
<path d="m 27 102 h 76 c 1.109375 0 2 0.890625 2 2 v 10 h -80 v -10 c 0 -1.109375 0.890625 -2 2 -2 z m 0 0" fill="#9a9996"/>
<path d="m 13 106 v 2 c 0 4.433594 3.566406 8 8 8 h 4 v -2 h -4 c -4.433594 0 -8 -3.566406 -8 -8 z m 104 0 c 0 4.433594 -3.566406 8 -8 8 h -4 v 2 h 4 c 4.433594 0 8 -3.566406 8 -8 z m -92 6 v 2 h 80 v -2 z m 0 0" fill="#9e9c99" fill-opacity="0.366142"/>
<path d="m 27 38 v 46 l 6 -46 z m 0 0" fill="#7e7c77" fill-opacity="0.11811"/>
<path d="m 24 32 c 0 1.65625 -1.34375 3 -3 3 s -3 -1.34375 -3 -3 s 1.34375 -3 3 -3 s 3 1.34375 3 3 z m 0 0" fill="#ffa348" fill-opacity="0.964567"/>
<use mask="url(#h)" transform="matrix(1 0 0 1 -8 -16)" xlink:href="#s"/>
<path d="m 89.503906 31.144531 l 10.066406 10.066407 l -41.71875 41.71875 l -10.066406 -10.066407 z m 0 0" fill="#ffa348"/>
<path d="m 88.246094 29.886719 l 7.550781 7.550781 l -41.71875 41.71875 l -7.550781 -7.550781 z m 0 0" fill="#ff7800"/>
<path d="m 86.789062 28.429688 l 2.515626 2.515624 l -41.71875 41.71875 l -2.515626 -2.515624 z m 0 0" fill="#ffbe6f"/>
<path d="m 121.898438 -0.101562 c -4.855469 0.921874 -11.730469 5.152343 -18.140626 11.558593 l -16.96875 16.972657 l 12.78125 12.78125 l 16.972657 -16.972657 c 6.40625 -6.40625 10.636719 -13.28125 11.558593 -18.136719 z m 0 0" fill="url(#j)"/>
<path d="m 110.011719 13.882812 c -2.1875 -0.398437 -5.421875 0.988282 -8.167969 3.730469 l -11.871094 11.875 l -6.6875 6.6875 c -4.800781 4.800781 -9.234375 12.007813 -9.648437 13.042969 c -0.484375 1.207031 -0.449219 2.730469 0.953125 4.136719 c 1.40625 1.40625 2.917968 1.441406 4.136718 0.953125 c 1.035157 -0.414063 8.292969 -4.984375 13.042969 -9.648438 l 2.402344 -2.398437 l 16.160156 -16.160157 c 2.742188 -2.746093 4.128907 -5.976562 3.730469 -8.167968 c -0.742188 1.390625 -1.859375 2.902344 -3.308594 4.347656 l -13.996094 13.996094 l -5.089843 -5.089844 l 13.996093 -13.996094 c 1.445313 -1.445312 2.960938 -2.566406 4.347657 -3.308594 z m 0 0" fill="url(#k)"/>
<path d="m 95.273438 36.914062 l -2.960938 2.960938 l -2.398438 2.402344 c -4.90625 5.101562 -11.855468 10.828125 -11.855468 10.828125 c 1.011718 -0.433594 8.167968 -5.101563 12.914062 -9.769531 l 2.402344 -2.402344 l 2.960938 -2.957032 z m 0 0" fill="#62a0ea"/>
<path d="m 87.320312 26.835938 l 13.789063 13.789062 c 0.292969 0.292969 0.292969 0.769531 0 1.0625 s -0.769531 0.292969 -1.0625 0 l -13.789063 -13.789062 c -0.292968 -0.292969 -0.292968 -0.769532 0 -1.0625 c 0.292969 -0.289063 0.769532 -0.289063 1.0625 0 z m 0 0" fill="#3584e4"/>
<path d="m 42.421875 89.765625 c -3 3 -6.382813 4.484375 -7.554687 3.3125 c -1.171876 -1.171875 0.3125 -4.554687 3.3125 -7.554687 c 3.003906 -3.003907 6.386718 -4.488282 7.558593 -3.316407 s -0.3125 4.554688 -3.316406 7.558594 z m 0 0" fill="url(#l)"/>
<path d="m 45.269531 70.347656 l -7.851562 12.511719 l 7.835937 7.925781 l 12.597656 -7.855468 z m -6.039062 13.171875 l 5.449219 5.449219 c 0.347656 0.347656 0.449218 0.933594 0.097656 1.160156 c -0.886719 0.570313 -2.9375 1.539063 -2.9375 1.539063 c -0.25 0.128906 -0.539063 0.164062 -0.773438 -0.066407 l -4.546875 -4.550781 c -0.234375 -0.230469 -0.207031 -0.527343 -0.066406 -0.773437 l 1.617187 -2.859375 c 0.207032 -0.363281 0.8125 -0.25 1.160157 0.101562 z m 0 0" fill="url(#m)"/>
<path d="m 43.332031 74.777344 l 9.867188 9.867187 c 0.394531 0.390625 0.476562 0.871094 0.128906 1.066407 l -7.710937 5.253906 c -0.308594 0.210937 -0.785157 0.160156 -1.171876 -0.226563 l -6.984374 -6.988281 c -0.386719 -0.386719 -0.4375 -0.859375 -0.230469 -1.167969 l 5.234375 -7.8125 c 0.125 -0.285156 0.558594 -0.304687 0.867187 0.007813 z m 0 0" fill="url(#n)"/>
<g clip-path="url(#z)" mask="url(#v)">
<g clip-path="url(#y)" mask="url(#w)">
<path d="m 128 80.640625 v 47.359375 h -128 v -47.359375 z m 0 0" fill="url(#x)"/>
<path d="m 13.308594 80.640625 l 47.355468 47.359375 h 21.214844 l -47.359375 -47.359375 z m 42.421875 0 l 47.363281 47.359375 h 21.214844 l -47.363282 -47.359375 z m 42.429687 0 l 29.839844 29.839844 v -21.210938 l -8.628906 -8.628906 z m -98.160156 7.90625 v 21.214844 l 18.238281 18.238281 h 21.214844 z m 0 0"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 18 KiB

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="128px" viewBox="0 0 128 128" width="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<linearGradient id="a" gradientTransform="matrix(0.232143 0 0 0.328947 -7.567033 263.82666)" gradientUnits="userSpaceOnUse" x1="88.595886" x2="536.595886" y1="-449.394012" y2="-449.394012">
<stop offset="0" stop-color="#acabae"/>
<stop offset="0.0384615" stop-color="#deddda"/>
<stop offset="0.0768555" stop-color="#c0bfbc"/>
<stop offset="0.923077" stop-color="#c0bfbc"/>
<stop offset="0.961538" stop-color="#deddda"/>
<stop offset="1" stop-color="#9a9996"/>
</linearGradient>
<linearGradient id="b" gradientUnits="userSpaceOnUse" x1="26.999876" x2="100.999876" y1="32.999688" y2="32.999688">
<stop offset="0" stop-color="#7e7c77"/>
<stop offset="0.3" stop-color="#9a9996"/>
<stop offset="1" stop-color="#9a9996"/>
</linearGradient>
<linearGradient id="c" gradientUnits="userSpaceOnUse" x1="67.467916" x2="67.467916" y1="83.999688" y2="36.782906">
<stop offset="0" stop-color="#deddda"/>
<stop offset="1" stop-color="#c0bfbc"/>
</linearGradient>
<clipPath id="d">
<path d="m 79 72 h 15 v 16 h -15 z m 0 0"/>
</clipPath>
<clipPath id="e">
<path d="m 93.21875 72.921875 l -14.21875 14.21875 h -4.0625 v -18.28125 h 18.28125 z m 0 0"/>
</clipPath>
<linearGradient id="f" gradientTransform="matrix(0 0.126951 0.126951 0 76.460862 36.359884)" gradientUnits="userSpaceOnUse" x1="344" x2="340" y1="76" y2="72">
<stop offset="0" stop-color="#d5d3cf"/>
<stop offset="1" stop-color="#ffffff"/>
</linearGradient>
<filter id="g" height="100%" width="100%" x="0%" y="0%">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
<mask id="h">
<g filter="url(#g)">
<rect fill-opacity="0.396" height="128" width="128"/>
</g>
</mask>
<clipPath id="i">
<rect height="152" width="192"/>
</clipPath>
<linearGradient id="j" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#1c71d8"/>
<stop offset="0.323117" stop-color="#62a0ea"/>
<stop offset="0.59387" stop-color="#1b5aa6"/>
<stop offset="1" stop-color="#1c71d8"/>
</linearGradient>
<linearGradient id="k" gradientTransform="matrix(1.597748 1.597748 -1.06066 1.06066 -56.853041 -543.720139)" x1="224.504562" x2="231.453873" xlink:href="#j" y1="282.5" y2="282.5"/>
<radialGradient id="l" cx="227.599915" cy="201.029724" gradientTransform="matrix(4.072817 4.073078 -5.940048 5.939073 373.883117 -2098.049112)" gradientUnits="userSpaceOnUse" r="2.5">
<stop offset="0" stop-color="#93bdf1"/>
<stop offset="1" stop-color="#1a5fb4"/>
</radialGradient>
<linearGradient id="m" gradientTransform="matrix(2.121328 2.121328 -2.174353 2.174353 181.766074 -1021.145947)" gradientUnits="userSpaceOnUse" x1="226.90625" x2="228.86203" y1="288.75" y2="288.767151">
<stop offset="0" stop-color="#77767b"/>
<stop offset="0.443872" stop-color="#f6f5f4"/>
<stop offset="1" stop-color="#5e5c64"/>
</linearGradient>
<linearGradient id="n" gradientTransform="matrix(1.258421 1.258421 -1.06066 1.06066 57.381892 -503.024312)" gradientUnits="userSpaceOnUse" x1="223.1875" x2="233.0625" y1="278" y2="278">
<stop offset="0" stop-color="#ffa348"/>
<stop offset="0.265823" stop-color="#ffd7af"/>
<stop offset="0.734177" stop-color="#ff8d1c"/>
<stop offset="1" stop-color="#ffa348"/>
</linearGradient>
<linearGradient id="o" gradientTransform="matrix(1.573027 1.573027 -1.06066 1.06066 -14.348129 -574.754333)" x1="224.504562" x2="231.453873" xlink:href="#j" y1="282.5" y2="282.5"/>
<path d="m 21 16 c -4.433594 0 -8 3.566406 -8 8 v 84 c 0 4.433594 3.566406 8 8 8 h 4 v -4 h 80 v 4 h 4 c 4.433594 0 8 -3.566406 8 -8 v -84 c 0 -4.433594 -3.566406 -8 -8 -8 z m 0 0" fill="url(#a)"/>
<path d="m 21 12 h 88 c 4.417969 0 8 3.582031 8 8 v 68 c 0 4.417969 -3.582031 8 -8 8 h -88 c -4.417969 0 -8 -3.582031 -8 -8 v -68 c 0 -4.417969 3.582031 -8 8 -8 z m 0 0" fill="#deddda"/>
<path d="m 27 28 h 74 v 10 h -74 z m 0 0" fill="url(#b)"/>
<path d="m 27 38 h 74 v 46 h -74 z m 0 0" fill="url(#c)"/>
<path d="m 24 33 c 0 1.65625 -1.34375 3 -3 3 s -3 -1.34375 -3 -3 s 1.34375 -3 3 -3 s 3 1.34375 3 3 z m 0 0" fill="#bf5f00" fill-opacity="0.964567"/>
<g fill-opacity="0.984252">
<path d="m 18 40 h 6 v 12 h -6 z m 0 0" fill="#acacac"/>
<path d="m 18 40 h 6 v 10 h -6 z m 0 0" fill="#d1d1d1"/>
<path d="m 37 36 h 56 v 44 h -56 z m 0 0" fill="#deddda"/>
</g>
<path d="m 37 34 h 56 c 1.105469 0 2 0.894531 2 2 s -0.894531 2 -2 2 h -56 c -1.105469 0 -2 -0.894531 -2 -2 s 0.894531 -2 2 -2 z m 0 0" fill-opacity="0.940945"/>
<path d="m 37 36.859375 h 56 v 36.925781 l -14.125 14.214844 h -41.875 z m 0 0" fill="#9a9996" fill-opacity="0.984252"/>
<path d="m 37 36 h 56 v 36.925781 l -14.125 14.214844 h -41.875 z m 0 0" fill="#f6f5f4" fill-opacity="0.984252"/>
<g clip-path="url(#d)">
<g clip-path="url(#e)">
<path d="m 79 77.386719 v 9.351562 c 0 2.464844 2 4.464844 4.464844 4.464844 h 9.351562 c 2.464844 0 4.464844 -2 4.464844 -4.464844 v -9.351562 c 0 -2.464844 -2 -4.464844 -4.464844 -4.464844 h -9.351562 c -2.464844 0 -4.464844 2 -4.464844 4.464844 z m 0 0" fill="url(#f)"/>
</g>
</g>
<path d="m 27 100 h 76 c 1.109375 0 2 0.890625 2 2 v 10 h -80 v -10 c 0 -1.109375 0.890625 -2 2 -2 z m 0 0" fill="#5e5c64" fill-opacity="0.940945"/>
<path d="m 27 102 h 76 c 1.109375 0 2 0.890625 2 2 v 10 h -80 v -10 c 0 -1.109375 0.890625 -2 2 -2 z m 0 0" fill="#9a9996"/>
<path d="m 13 106 v 2 c 0 4.433594 3.566406 8 8 8 h 4 v -2 h -4 c -4.433594 0 -8 -3.566406 -8 -8 z m 104 0 c 0 4.433594 -3.566406 8 -8 8 h -4 v 2 h 4 c 4.433594 0 8 -3.566406 8 -8 z m -92 6 v 2 h 80 v -2 z m 0 0" fill="#9e9c99" fill-opacity="0.366142"/>
<path d="m 27 38 v 46 l 6 -46 z m 0 0" fill="#7e7c77" fill-opacity="0.11811"/>
<path d="m 24 32 c 0 1.65625 -1.34375 3 -3 3 s -3 -1.34375 -3 -3 s 1.34375 -3 3 -3 s 3 1.34375 3 3 z m 0 0" fill="#ffa348" fill-opacity="0.964567"/>
<g clip-path="url(#i)" mask="url(#h)" transform="matrix(1 0 0 1 -8 -16)">
<path d="m 29 112 c -4.433594 0 -8 -3.566406 -8 -8 v -2 c 0 4.433594 3.566406 8 8 8 h 88 c 4.433594 0 8 -3.566406 8 -8 v 2 c 0 4.433594 -3.566406 8 -8 8 z m 0 0" fill="#f6f5f4"/>
</g>
<path d="m 89.503906 31.144531 l 10.066406 10.066407 l -41.71875 41.71875 l -10.066406 -10.066407 z m 0 0" fill="#ffa348"/>
<path d="m 88.246094 29.886719 l 7.550781 7.550781 l -41.71875 41.71875 l -7.550781 -7.550781 z m 0 0" fill="#ff7800"/>
<path d="m 86.789062 28.429688 l 2.515626 2.515624 l -41.71875 41.71875 l -2.515626 -2.515624 z m 0 0" fill="#ffbe6f"/>
<path d="m 121.898438 -0.101562 c -4.855469 0.921874 -11.730469 5.152343 -18.140626 11.558593 l -16.96875 16.972657 l 12.78125 12.78125 l 16.972657 -16.972657 c 6.40625 -6.40625 10.636719 -13.28125 11.558593 -18.136719 z m 0 0" fill="url(#k)"/>
<path d="m 110.011719 13.882812 c -2.1875 -0.398437 -5.421875 0.988282 -8.167969 3.730469 l -11.871094 11.875 l -6.6875 6.6875 c -4.800781 4.800781 -9.234375 12.007813 -9.648437 13.042969 c -0.484375 1.207031 -0.449219 2.730469 0.953125 4.136719 c 1.40625 1.40625 2.917968 1.441406 4.136718 0.953125 c 1.035157 -0.414063 8.292969 -4.984375 13.042969 -9.648438 l 2.402344 -2.398437 l 16.160156 -16.160157 c 2.742188 -2.746093 4.128907 -5.976562 3.730469 -8.167968 c -0.742188 1.390625 -1.859375 2.902344 -3.308594 4.347656 l -13.996094 13.996094 l -5.089843 -5.089844 l 13.996093 -13.996094 c 1.445313 -1.445312 2.960938 -2.566406 4.347657 -3.308594 z m 0 0" fill="url(#l)"/>
<path d="m 95.273438 36.914062 l -2.960938 2.960938 l -2.398438 2.402344 c -4.90625 5.101562 -11.855468 10.828125 -11.855468 10.828125 c 1.011718 -0.433594 8.167968 -5.101563 12.914062 -9.769531 l 2.402344 -2.402344 l 2.960938 -2.957032 z m 0 0" fill="#62a0ea"/>
<path d="m 87.320312 26.835938 l 13.789063 13.789062 c 0.292969 0.292969 0.292969 0.769531 0 1.0625 s -0.769531 0.292969 -1.0625 0 l -13.789063 -13.789062 c -0.292968 -0.292969 -0.292968 -0.769532 0 -1.0625 c 0.292969 -0.289063 0.769532 -0.289063 1.0625 0 z m 0 0" fill="#3584e4"/>
<path d="m 42.421875 89.765625 c -3 3 -6.382813 4.484375 -7.554687 3.3125 c -1.171876 -1.171875 0.3125 -4.554687 3.3125 -7.554687 c 3.003906 -3.003907 6.386718 -4.488282 7.558593 -3.316407 s -0.3125 4.554688 -3.316406 7.558594 z m 0 0" fill="url(#m)"/>
<path d="m 45.269531 70.347656 l -7.851562 12.511719 l 7.835937 7.925781 l 12.597656 -7.855468 z m -6.039062 13.171875 l 5.449219 5.449219 c 0.347656 0.347656 0.449218 0.933594 0.097656 1.160156 c -0.886719 0.570313 -2.9375 1.539063 -2.9375 1.539063 c -0.25 0.128906 -0.539063 0.164062 -0.773438 -0.066407 l -4.546875 -4.550781 c -0.234375 -0.230469 -0.207031 -0.527343 -0.066406 -0.773437 l 1.617187 -2.859375 c 0.207032 -0.363281 0.8125 -0.25 1.160157 0.101562 z m 0 0" fill="url(#n)"/>
<path d="m 43.332031 74.777344 l 9.867188 9.867187 c 0.394531 0.390625 0.476562 0.871094 0.128906 1.066407 l -7.710937 5.253906 c -0.308594 0.210937 -0.785157 0.160156 -1.171876 -0.226563 l -6.984374 -6.988281 c -0.386719 -0.386719 -0.4375 -0.859375 -0.230469 -1.167969 l 5.234375 -7.8125 c 0.125 -0.285156 0.558594 -0.304687 0.867187 0.007813 z m 0 0" fill="url(#o)"/>
</svg>

After

Width:  |  Height:  |  Size: 9.4 KiB

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<filter id="a" height="100%" width="100%" x="0%" y="0%">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
<mask id="b">
<g filter="url(#a)">
<rect fill-opacity="0.396" height="16" width="16"/>
</g>
</mask>
<clipPath id="c">
<rect height="152" width="192"/>
</clipPath>
<g clip-path="url(#c)" mask="url(#b)" transform="matrix(1 0 0 1 -168 -16)">
<path d="m 29 112 c -4.433594 0 -8 -3.566406 -8 -8 v -2 c 0 4.433594 3.566406 8 8 8 h 88 c 4.433594 0 8 -3.566406 8 -8 v 2 c 0 4.433594 -3.566406 8 -8 8 z m 0 0" fill="#f6f5f4"/>
</g>
<g fill="#2e3436">
<path d="m 4 2 v 2 h 5.585938 l 2 -2 z m -2 3 c -0.5 0 -1 0.5 -1 1 v 4 c 0 0.5 0.5 1 1 1 h 1 v -2 h 2 c 0 -0.265625 0.105469 -0.519531 0.292969 -0.707031 l 3.292969 -3.292969 z m 11.414062 0 l -4 4 h 3.585938 v 2 h 1 c 0.5 0 1 -0.5 1 -1 v -4 c 0 -0.5 -0.5 -1 -1 -1 z m -9.414062 5 v 5 h 8 v -5 h -3.585938 l -0.707031 0.707031 c -0.1875 0.1875 -0.441406 0.292969 -0.707031 0.292969 h -1 c -0.550781 0 -1 -0.449219 -1 -1 z m 0 0"/>
<path d="m 6 10 h 1 l 9 -9 l -1 -1 l -9 9 z m 0 0"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+9
View File
@@ -12,3 +12,12 @@ install_data('org.gtk.PrintEditor4.desktop', install_dir: gtk_applicationsdir)
# appdata
install_data('org.gtk.PrintEditor4.appdata.xml', install_dir: gtk_appdatadir)
# icons
icontheme_dir = join_paths(gtk_datadir, 'icons/hicolor')
foreach size: ['scalable', 'symbolic']
install_subdir('data/' + size,
install_dir: icontheme_dir
)
endforeach
@@ -2,7 +2,7 @@
Name=Print Editor
Comment=A simple editor demonstrating GTK printing
Exec=gtk4-print-editor %f
Icon=text-editor-symbolic
Icon=org.gtk.PrintEditor4.Devel
Terminal=false
Type=Application
StartupNotify=true
+3 -1
View File
@@ -633,7 +633,7 @@ activate_about (GSimpleAction *action,
"website", "http://www.gtk.org",
"comments", "Program to demonstrate GTK printing",
"authors", (const char *[]){ "Alexander Larsson", NULL },
"logo-icon-name", "text-editor-symbolic",
"logo-icon-name", "org.gtk.PrintEditor4.Devel",
"title", "About GTK Print Editor",
"system-information", sysinfo->str,
NULL);
@@ -781,6 +781,8 @@ activate (GApplication *app)
gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (main_window), TRUE);
update_title (GTK_WINDOW (main_window));
gtk_widget_add_css_class (main_window, "devel");
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_window_set_child (GTK_WINDOW (main_window), box);
-1
View File
@@ -436,7 +436,6 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<property name="title">GTK Widget Factory</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="headerbar1">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkStackSwitcher" id="stack_switcher">
<property name="stack">toplevel_stack</property>
-2
View File
@@ -1423,7 +1423,6 @@ the search bar below the header bar.
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkStackSwitcher" id="tabs">
<property name="stack">stack</property>
@@ -1537,7 +1536,6 @@ GtkMenuButton, GtkRevealer and GtkListBox.
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkStackSwitcher" id="tabs">
<property name="stack">stack</property>
@@ -177,6 +177,7 @@ def ConvertToDocbook(infile, outfile):
subprocess.check_call(["pandoc", infile, "-o", outfile,
"--from=" + input_format,
"--to=" + output_format,
"--standalone",
"--top-level-division=" + division])
def ExpandGtkDocAbbreviations(infile, outfile):
+8 -4
View File
@@ -54,8 +54,9 @@
<section>
<xi:include href="xml/gtkfilter.xml" />
<xi:include href="xml/gtkcustomfilter.xml" />
<xi:include href="xml/gtkstringfilter.xml" />
<xi:include href="xml/gtkmultifilter.xml" />
<xi:include href="xml/gtkstringfilter.xml" />
<xi:include href="xml/gtkfilefilter.xml" />
</section>
<xi:include href="xml/gtkflattenlistmodel.xml" />
<xi:include href="xml/gtkmaplistmodel.xml" />
@@ -64,9 +65,9 @@
<section>
<xi:include href="xml/gtksorter.xml" />
<xi:include href="xml/gtkcustomsorter.xml" />
<xi:include href="xml/gtkmultisorter.xml" />
<xi:include href="xml/gtkstringsorter.xml" />
<xi:include href="xml/gtknumericsorter.xml" />
<xi:include href="xml/gtkmultisorter.xml" />
</section>
<xi:include href="xml/gtkselectionmodel.xml" />
<section>
@@ -74,6 +75,7 @@
<xi:include href="xml/gtksingleselection.xml" />
<xi:include href="xml/gtkmultiselection.xml" />
</section>
<xi:include href="xml/gtkselectionfiltermodel.xml" />
<xi:include href="xml/gtkbookmarklist.xml" />
<xi:include href="xml/gtkdirectorylist.xml" />
<xi:include href="xml/gtkstringlist.xml" />
@@ -91,7 +93,9 @@
<xi:include href="xml/gtklistview.xml" />
<xi:include href="xml/gtkgridview.xml" />
<xi:include href="xml/gtkcolumnview.xml" />
<xi:include href="xml/gtkcolumnviewcolumn.xml" />
<section>
<xi:include href="xml/gtkcolumnviewcolumn.xml" />
</section>
<xi:include href="xml/gtkdropdown.xml" />
</chapter>
@@ -219,6 +223,7 @@
<xi:include href="xml/gtksearchentry.xml" />
<xi:include href="xml/gtksearchbar.xml" />
<xi:include href="xml/gtkeditablelabel.xml" />
<xi:include href="xml/gtksuggestionentry.xml" />
</chapter>
<chapter id="TextWidgetObjects">
@@ -284,7 +289,6 @@
<xi:include href="xml/gtkfilechoosernative.xml" />
<xi:include href="xml/gtkfilechooserdialog.xml" />
<xi:include href="xml/gtkfilechooserwidget.xml" />
<xi:include href="xml/gtkfilefilter.xml" />
<xi:include href="xml/gtkfontchooser.xml" />
<xi:include href="xml/gtkfontbutton.xml" />
<xi:include href="xml/gtkfontchooserwidget.xml" />
+72 -16
View File
@@ -348,6 +348,7 @@ GtkBitset
gtk_bitset_ref
gtk_bitset_unref
gtk_bitset_new_empty
gtk_bitset_new_range
gtk_bitset_copy
<SUBSECTION>
gtk_bitset_contains
@@ -355,6 +356,9 @@ gtk_bitset_is_empty
gtk_bitset_equals
gtk_bitset_get_minimum
gtk_bitset_get_maximum
gtk_bitset_get_size
gtk_bitset_get_size_in_range
gtk_bitset_get_nth
<SUBSECTION>
gtk_bitset_remove_all
gtk_bitset_add
@@ -371,7 +375,7 @@ gtk_bitset_subtract
gtk_bitset_difference
gtk_bitset_shift_left
gtk_bitset_shift_right
gtk_bitset_slice
gtk_bitset_splice
<SUBSECTION>
GtkBitsetIter
gtk_bitset_iter_init_first
@@ -419,6 +423,7 @@ gtk_selection_model_get_type
GtkNoSelection
gtk_no_selection_new
gtk_no_selection_get_model
gtk_no_selection_set_model
<SUBSECTION Private>
gtk_no_selection_get_type
</SECTION>
@@ -430,6 +435,7 @@ GtkSingleSelection
GTK_INVALID_LIST_POSITION
gtk_single_selection_new
gtk_single_selection_get_model
gtk_single_selection_set_model
gtk_single_selection_get_selected
gtk_single_selection_set_selected
gtk_single_selection_get_selected_item
@@ -446,6 +452,8 @@ gtk_single_selection_get_type
<TITLE>GtkMultiSeledction</TITLE>
GtkMultiSelection
gtk_multi_selection_new
gtk_multi_selection_get_model
gtk_multi_selection_set_model
<SUBSECTION Private>
gtk_multi_selection_get_type
</SECTION>
@@ -1292,23 +1300,19 @@ gtk_file_chooser_get_current_name
<SUBSECTION>
gtk_file_chooser_get_file
gtk_file_chooser_set_file
gtk_file_chooser_select_file
gtk_file_chooser_unselect_file
gtk_file_chooser_select_all
gtk_file_chooser_unselect_all
gtk_file_chooser_get_files
gtk_file_chooser_set_current_folder
gtk_file_chooser_get_current_folder
<SUBSECTION>
gtk_file_chooser_add_filter
gtk_file_chooser_remove_filter
gtk_file_chooser_list_filters
gtk_file_chooser_get_filters
gtk_file_chooser_set_filter
gtk_file_chooser_get_filter
<SUBSECTION>
gtk_file_chooser_add_shortcut_folder
gtk_file_chooser_remove_shortcut_folder
gtk_file_chooser_list_shortcut_folders
gtk_file_chooser_get_shortcut_folders
<SUBSECTION>
gtk_file_chooser_add_choice
gtk_file_chooser_remove_choice
@@ -1405,18 +1409,13 @@ GtkFileChooserButtonPrivate
<SECTION>
<FILE>gtkfilefilter</FILE>
GtkFileFilter
GtkFileFilterInfo
GtkFileFilterFlags
GtkFileFilterFunc
gtk_file_filter_new
gtk_file_filter_set_name
gtk_file_filter_get_name
gtk_file_filter_add_mime_type
gtk_file_filter_add_pattern
gtk_file_filter_add_pixbuf_formats
gtk_file_filter_add_custom
gtk_file_filter_get_needed
gtk_file_filter_filter
gtk_file_filter_get_attributes
<SUBSECTION Serialization>
gtk_file_filter_new_from_gvariant
@@ -1441,6 +1440,8 @@ gtk_directory_list_get_file
gtk_directory_list_set_file
gtk_directory_list_get_io_priority
gtk_directory_list_set_io_priority
gtk_directory_list_get_monitored
gtk_directory_list_set_monitored
gtk_directory_list_is_loading
gtk_directory_list_get_error
<SUBSECTION Standard>
@@ -1535,11 +1536,13 @@ gtk_custom_filter_get_type
<TITLE>GtkFilterListModel</TITLE>
GtkFilterListModel
gtk_filter_list_model_new
gtk_filter_list_model_new_for_type
gtk_filter_list_model_set_model
gtk_filter_list_model_get_model
gtk_filter_list_model_set_filter
gtk_filter_list_model_get_filter
gtk_filter_list_model_set_incremental
gtk_filter_list_model_get_incremental
gtk_filter_list_model_get_pending
<SUBSECTION Standard>
GTK_FILTER_LIST_MODEL
GTK_IS_FILTER_LIST_MODEL
@@ -2694,7 +2697,6 @@ gtk_size_group_get_type
<TITLE>GtkSliceListModel</TITLE>
GtkSliceListModel
gtk_slice_list_model_new
gtk_slice_list_model_new_for_type
gtk_slice_list_model_set_model
gtk_slice_list_model_get_model
gtk_slice_list_model_set_offset
@@ -2826,11 +2828,13 @@ gtk_tree_list_row_sorter_get_type
<TITLE>GtkSortListModel</TITLE>
GtkSortListModel
gtk_sort_list_model_new
gtk_sort_list_model_new_for_type
gtk_sort_list_model_set_sorter
gtk_sort_list_model_get_sorter
gtk_sort_list_model_set_model
gtk_sort_list_model_get_model
gtk_sort_list_model_set_incremental
gtk_sort_list_model_get_incremental
gtk_sort_list_model_get_peanding
<SUBSECTION Standard>
GTK_SORT_LIST_MODEL
GTK_IS_SORT_LIST_MODEL
@@ -3419,6 +3423,7 @@ gtk_tree_list_row_get_type
<SECTION>
<FILE>gtktreeexpander</FILE>
<TITLE>GtkTreeExpander</TITLE>
GtkTreeExpander
gtk_tree_expander_new
gtk_tree_expander_get_child
gtk_tree_expander_set_child
@@ -7540,12 +7545,27 @@ gtk_expression_watch_unwatch
<SUBSECTION>
gtk_property_expression_new
gtk_property_expression_new_for_pspec
gtk_property_expression_get_expression
gtk_property_expression_get_pspec
gtk_constant_expression_new
gtk_constant_expression_new_for_value
gtk_constant_expression_get_value
gtk_object_expression_new
gtk_object_expression_get_object
gtk_closure_expression_new
gtk_cclosure_expression_new
<SUBSECTION>
GTK_VALUE_HOLDS_EXPRESSION
gtk_value_set_expression
gtk_value_take_expression
gtk_value_get_expression
gtk_value_dup_expression
<SUBSECTION>
GtkParamSpecExpression
gtk_param_spec_expression
<SUBSECTION Standard>
GTK_IS_EXPRESSION
GTK_TYPE_EXPRESSION
@@ -7606,6 +7626,42 @@ gtk_string_list_take
gtk_string_list_remove
gtk_string_list_splice
gtk_string_list_get_string
<SUBSECTION>
GtkStringObject
gtk_string_object_new
gtk_string_object_get_string
</SECTION>
<SECTION>
<FILE>gtkselectionfiltermodel</FILE>
<TITLE>GtkSelectionFilterModel</TITLE>
GtkSelectionFilterModel
gtk_selection_filter_model_new
gtk_selection_filter_model_new_for_type
gtk_selection_filter_model_set_model
gtk_selection_filter_model_get_model
</SECTION>
<SECTION>
<FILE>gtksuggestionentry</FILE>
<TITLE>GtkSuggestionEntry</TITLE>
GtkSuggestionEntry
gtk_suggestion_entry_new
gtk_suggestion_entry_set_model
gtk_suggestion_entry_get_model
gtk_suggestion_entry_set_from_strings
gtk_suggestion_entry_set_factory
gtk_suggestion_entry_get_factory
gtk_suggestion_entry_set_expression
gtk_suggestion_entry_get_expression
gtk_suggestion_entry_set_use_filter
gtk_suggestion_entry_get_use_filter
gtk_suggestion_entry_set_insert_selection
gtk_suggestion_entry_get_insert_selection
gtk_suggestion_entry_set_insert_prefix
gtk_suggestion_entry_get_insert_prefix
gtk_suggestion_entry_set_show_button
gtk_suggestion_entry_get_show_button
gtk_suggestion_entry_set_minimum_length
gtk_suggestion_entry_get_minimum_length
</SECTION>
+9
View File
@@ -19,6 +19,7 @@ gtk_assistant_get_type
gtk_assistant_page_get_type
gtk_bin_layout_get_type
gtk_bitset_get_type
gtk_expression_get_type
gtk_bookmark_list_get_type
gtk_box_get_type
gtk_box_layout_get_type
@@ -29,6 +30,7 @@ gtk_builder_list_item_factory_get_type
gtk_builder_scope_get_type
gtk_button_get_type
gtk_calendar_get_type
gtk_cclosure_expression_get_type
gtk_cell_area_get_type
gtk_cell_area_box_get_type
gtk_cell_area_context_get_type
@@ -46,6 +48,7 @@ gtk_cell_renderer_toggle_get_type
gtk_cell_view_get_type
gtk_center_layout_get_type
gtk_check_button_get_type
gtk_closure_expression_get_type
gtk_color_button_get_type
gtk_color_chooser_get_type
gtk_color_chooser_dialog_get_type
@@ -54,6 +57,7 @@ gtk_column_view_get_type
gtk_column_view_column_get_type
gtk_combo_box_get_type
gtk_combo_box_text_get_type
gtk_constant_expression_get_type
gtk_constraint_get_type
gtk_constraint_guide_get_type
gtk_constraint_layout_get_type
@@ -150,6 +154,7 @@ gtk_no_selection_get_type
gtk_notebook_get_type
gtk_notebook_page_get_type
gtk_numeric_sorter_get_type
gtk_object_expression_get_type
gtk_orientable_get_type
gtk_overlay_get_type
gtk_overlay_layout_get_type
@@ -172,6 +177,7 @@ gtk_print_operation_preview_get_type
gtk_print_settings_get_type
@DISABLE_ON_W32@gtk_print_unix_dialog_get_type
gtk_progress_bar_get_type
gtk_property_expression_get_type
gtk_radio_button_get_type
gtk_range_get_type
gtk_recent_manager_get_type
@@ -184,6 +190,7 @@ gtk_scrollbar_get_type
gtk_scrolled_window_get_type
gtk_search_bar_get_type
gtk_search_entry_get_type
gtk_selection_filter_model_get_type
gtk_selection_model_get_type
gtk_separator_get_type
gtk_settings_get_type
@@ -213,6 +220,7 @@ gtk_string_filter_get_type
gtk_string_list_get_type
gtk_string_object_get_type
gtk_string_sorter_get_type
gtk_suggestion_entry_get_type
gtk_switch_get_type
gtk_level_bar_get_type
gtk_style_context_get_type
@@ -228,6 +236,7 @@ gtk_text_view_get_type
gtk_toggle_button_get_type
gtk_tree_drag_dest_get_type
gtk_tree_drag_source_get_type
gtk_tree_expander_get_type
gtk_tree_list_model_get_type
gtk_tree_list_row_get_type
gtk_tree_list_row_sorter_get_type
+57 -3
View File
@@ -137,8 +137,41 @@ use gtk_button_new_from_icon_name().
### Stop using GtkWidget event signals
Event controllers and #GtkGestures replace event signals in GTK 4.
They have been backported to GTK 3.x so you can prepare for this change.
Event controllers and gestures replace event signals in GTK 4.
Most of them have been backported to GTK 3.x so you can prepare
for this change.
| Signal | Event controller |
| --- | --- |
| ::event | #GtkEventControllerLegacy |
| ::event-after | #GtkEventControllerLegacy |
| ::button-press-event | #GtkGestureClick |
| ::button-release-event | #GtkGestureClick |
| ::touch-event | various touch gestures |
| ::scroll-event | #GtkEventControllerScroll |
| ::motion-notify-event | #GtkEventControllerMotion |
| ::delete-event | - |
| ::key-press-event | #GtkEventControllerKey |
| ::key-release-event | #GtkEventControllerKey |
| ::enter-notify-event | #GtkEventControllerMotion |
| ::leave-notify-event | #GtkEventControllerMotion |
| ::configure-event | replaced by #GdkSurface::size-changed |
| ::focus-in-event | #GtkEventControllerFocus |
| ::focus-out-event | #GtkEventControllerFocus |
| ::map-event | replaced by #GdkSurface:mapped |
| ::unmap-event | replaced by #GdkSurface:mapped |
| ::property-notify-event | replaced by #GdkClipboard |
| ::selection-clear-event | replaced by #GdkClipboard |
| ::selection-request-event | replaced by #GdkClipboard |
| ::selection-notify-event | replaced by #GdkClipboard |
| Drag-and-Drop signals | #GtkDragSource, #GtkDropTarget |
| ::proximity-in-event | #GtkGestureStylus |
| ::proximity-out-event | #GtkGestureStylus |
| ::visibility-notify-event | - |
| ::window-state-event | replaced by #GdkToplevel:state |
| ::damage-event | - |
| ::grab-broken-event | - |
### Set a proper application ID
@@ -170,7 +203,7 @@ in GTK 3, you can prepare for the switch by using gtk_widget_destroy()
only on toplevel windows, and replace all other uses with
gtk_container_remove() or g_object_unref().
### Reduce the use of generic container APIs</title>
### Reduce the use of generic container APIs
GTK 4 removes gtk_container_add() and gtk_container_remove(). While there
is not always a replacement for gtk_container_remove() in GTK 3, you can
@@ -411,6 +444,7 @@ and gtk_box_append(). You can also reorder box children as necessary.
The gtk_header_bar_set_show_close_button() function has been renamed to
the more accurate name gtk_header_bar_set_show_title_buttons(). The
corresponding getter and the property itself have also been renamed.
The default value of the property is now %TRUE instead of %FALSE.
The gtk_header_bar_set_custom_title() function has been renamed to
the more accurate name gtk_header_bar_set_title_widget(). The
@@ -530,6 +564,26 @@ by a layout manager (if they are layout-related), or handled in some
other way. One possibility is to use child meta objects, as seen with
GtkAssistantPage, GtkStackPage and the like.
The replacements for gtk_container_add() are:
| Widget | Replacement |
| ------ | ----------- |
| GtkActionBar | gtk_action_bar_pack_start(), gtk_action_bar_pack_end() |
| GtkBox | gtk_box_append() |
| GtkExpander | gtk_expander_set_child() |
| GtkFixed | gtk_fixed_put() |
| GtkFlowBox | gtk_flow_box_insert() |
| GtkGrid | gtk_grid_attach() |
| GtkHeaderBar | gtk_header_bar_pack_start(), gtk_header_bar_pack_end() |
| GtkIconView | - |
| GtkInfoBar | gtk_info_bar_add_child() |
| GtkListBox | gtk_list_box_insert() |
| GtkNotebook | gtk_notebook_append_page() |
| GtkPaned | gtk_paned_set_start_child(), gtk_paned_set_end_child() |
| GtkStack | gtk_stack_add_named() |
| GtkTextView | gtk_text_view_add_child_at_anchor(), gtk_text_view_add_overlay() |
| GtkTreeView | - |
### Stop using GtkContainer::border-width
GTK 4 has removed the #GtkContainer::border-width property (together
+29 -1
View File
@@ -123,6 +123,32 @@ the number of listitems they create such as with gtk_grid_view_set_max_columns()
and developers running into performance problems should definitely study the
tradeoffs of those and experiment with them.
## Choosing the right model {#model-choosing}
GTK offers a wide variety of wrapping models which change or supplement an
existing model (or models) in some way. But when it comes to storing your
actual data, there are only a few ready-made choices available: #GListStore
and #GtkStringList.
GListStore is backed by a balanced tree and has performance characteristics
that are expected for that data structure. It works reasonably well for dataset
sizes in the 1,000,000 range, and can handle insertions and deletions. It uses
a cached iter to make linear access to the items fast.
GtkStringList is not a general store - it can only handle strings. It is
backed by an dynamically allocated array and has performance characteristics
that are expected for that data structure. GtkStringList is a good fit for any
place where you would otherwise use `char*[]` and works best if the dataset
is not very dynamic.
If these models don't fit your use case or scalability requirements, you
should make a custom #GListModel. It is a small interface and not very hard
to implement.
For asymptotic performance comparisons between tree- and array-based
implementations, see this
[article](https://en.wikipedia.org/wiki/Dynamic_array#Performance).
## Displaying trees {#displaying-trees}
While #GtkTreeView provided built-in support for trees, the list widgets, and
@@ -183,7 +209,7 @@ transitioning code for easy lookup:
| #GtkTreeModel | #GListModel |
| #GtkTreePath | #guint position, #GtkTreeListRow |
| #GtkTreeIter | #guint position |
| GtkTreeRowReference | #GObject item |
| #GtkTreeRowReference | #GObject item |
| #GtkListStore | #GListStore |
| #GtkTreeStore | #GtkTreeListModel, #GtkTreeExpander |
| #GtkTreeSelection | #GtkSelectionModel |
@@ -198,4 +224,6 @@ transitioning code for easy lookup:
| #GtkCellLayout | #GtkListItemFactory |
| #GtkCellArea | #GtkWidget |
| #GtkCellRenderer | #GtkWidget |
| #GtkComboBoxText | #GtkSuggestionEntry |
| #GtkEntryCompletion | #GtkSuggestionEntry |
-1
View File
@@ -6,7 +6,6 @@
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkStackSwitcher" id="tabs">
<property name="stack">stack</property>
-1
View File
@@ -6,7 +6,6 @@
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkStackSwitcher" id="tabs">
<property name="stack">stack</property>
-1
View File
@@ -6,7 +6,6 @@
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkStackSwitcher" id="tabs">
<property name="stack">stack</property>
-1
View File
@@ -6,7 +6,6 @@
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkStackSwitcher" id="tabs">
<property name="stack">stack</property>
-1
View File
@@ -6,7 +6,6 @@
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkStackSwitcher" id="tabs">
<property name="stack">stack</property>
-1
View File
@@ -6,7 +6,6 @@
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkStackSwitcher" id="tabs">
<property name="stack">stack</property>
-1
View File
@@ -6,7 +6,6 @@
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkLabel" id="lines_label">
<property name="visible">0</property>
-1
View File
@@ -15,7 +15,6 @@ new_window (GApplication *app,
gtk_window_set_icon_name (GTK_WINDOW (window), "sunny");
header = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
overlay = gtk_overlay_new ();
+283
View File
@@ -0,0 +1,283 @@
/*
* Copyright © 2020 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include <glib.h>
G_BEGIN_DECLS
#ifndef GDK_ARRAY_TYPE_NAME
#define GDK_ARRAY_TYPE_NAME GdkArray
#endif
#ifndef GDK_ARRAY_NAME
#define GDK_ARRAY_NAME gdk_array
#endif
#ifndef GDK_ARRAY_ELEMENT_TYPE
#define GDK_ARRAY_ELEMENT_TYPE gpointer
#endif
#ifdef GDK_ARRAY_PREALLOC
#if GDK_ARRAY_PREALLOC == 0
#undef GDK_ARRAY_PREALLOC
#endif
#endif
#ifdef GDK_ARRAY_NULL_TERMINATED
#define GDK_ARRAY_REAL_SIZE(_size) ((_size) + 1)
#else
#define GDK_ARRAY_REAL_SIZE(_size) (_size)
#endif
/* make this readable */
#define _T_ GDK_ARRAY_ELEMENT_TYPE
#define GdkArray GDK_ARRAY_TYPE_NAME
#define gdk_array_paste_more(GDK_ARRAY_NAME, func_name) GDK_ARRAY_NAME ## _ ## func_name
#define gdk_array_paste(GDK_ARRAY_NAME, func_name) gdk_array_paste_more (GDK_ARRAY_NAME, func_name)
#define gdk_array(func_name) gdk_array_paste (GDK_ARRAY_NAME, func_name)
typedef struct GdkArray GdkArray;
struct GdkArray
{
_T_ *start;
_T_ *end;
_T_ *end_allocation;
#ifdef GDK_ARRAY_PREALLOC
_T_ preallocated[GDK_ARRAY_REAL_SIZE(GDK_ARRAY_PREALLOC)];
#endif
};
/* no G_GNUC_UNUSED here, if you don't use an array type, remove it. */
static inline void
gdk_array(init) (GdkArray *self)
{
#ifdef GDK_ARRAY_PREALLOC
self->start = self->preallocated;
self->end = self->start;
self->end_allocation = self->start + GDK_ARRAY_PREALLOC;
#ifdef GDK_ARRAY_NULL_TERMINATED
*self->start = *(_T_[1]) {};
#endif
#else
self->start = NULL;
self->end = NULL;
self->end_allocation = NULL;
#endif
}
static inline void
gdk_array(free_elements) (_T_ *start,
_T_ *end)
{
#ifdef GDK_ARRAY_FREE_FUNC
_T_ *e;
for (e = start; e < end; e++)
#ifdef GDK_ARRAY_BY_VALUE
GDK_ARRAY_FREE_FUNC (e);
#else
GDK_ARRAY_FREE_FUNC (*e);
#endif
#endif
}
/* no G_GNUC_UNUSED here */
static inline void
gdk_array(clear) (GdkArray *self)
{
gdk_array(free_elements) (self->start, self->end);
#ifdef GDK_ARRAY_PREALLOC
if (self->start != self->preallocated)
#endif
g_free (self->start);
gdk_array(init) (self);
}
G_GNUC_UNUSED static inline _T_ *
gdk_array(get_data) (const GdkArray *self)
{
return self->start;
}
G_GNUC_UNUSED static inline _T_ *
gdk_array(index) (const GdkArray *self,
gsize pos)
{
return self->start + pos;
}
G_GNUC_UNUSED static inline gsize
gdk_array(get_capacity) (const GdkArray *self)
{
return self->end_allocation - self->start;
}
G_GNUC_UNUSED static inline gsize
gdk_array(get_size) (const GdkArray *self)
{
return self->end - self->start;
}
G_GNUC_UNUSED static inline gboolean
gdk_array(is_empty) (const GdkArray *self)
{
return self->end == self->start;
}
G_GNUC_UNUSED static void
gdk_array(reserve) (GdkArray *self,
gsize n)
{
gsize new_size, size;
if (n <= gdk_array(get_capacity) (self))
return;
size = gdk_array(get_size) (self);
new_size = 1 << g_bit_storage (MAX (GDK_ARRAY_REAL_SIZE (n), 16) - 1);
#ifdef GDK_ARRAY_PREALLOC
if (self->start == self->preallocated)
{
self->start = g_new (_T_, new_size);
memcpy (self->start, self->preallocated, sizeof (_T_) * GDK_ARRAY_REAL_SIZE (size));
}
else
#endif
#ifdef GDK_ARRAY_NULL_TERMINATED
if (self->start == NULL)
{
self->start = g_new (_T_, new_size);
*self->start = *(_T_[1]) {};
}
else
#endif
self->start = g_renew (_T_, self->start, new_size);
self->end = self->start + size;
self->end_allocation = self->start + new_size;
#ifdef GDK_ARRAY_NULL_TERMINATED
self->end_allocation--;
#endif
}
G_GNUC_UNUSED static void
gdk_array(splice) (GdkArray *self,
gsize pos,
gsize removed,
_T_ *additions,
gsize added)
{
gsize size;
gsize remaining;
size = gdk_array(get_size) (self);
g_assert (pos + removed <= size);
remaining = size - pos - removed;
gdk_array(free_elements) (gdk_array(index) (self, pos),
gdk_array(index) (self, pos + removed));
gdk_array(reserve) (self, size - removed + added);
if (GDK_ARRAY_REAL_SIZE (remaining) && removed != added)
memmove (gdk_array(index) (self, pos + added),
gdk_array(index) (self, pos + removed),
GDK_ARRAY_REAL_SIZE (remaining) * sizeof (_T_));
if (added)
{
if (additions)
memcpy (gdk_array(index) (self, pos),
additions,
added * sizeof (_T_));
else
memset (gdk_array(index) (self, pos), 0, added * sizeof (_T_));
}
/* might overflow, but does the right thing */
self->end += added - removed;
}
G_GNUC_UNUSED static void
gdk_array(set_size) (GdkArray *self,
gsize new_size)
{
gsize old_size = gdk_array(get_size) (self);
if (new_size > old_size)
gdk_array(splice) (self, old_size, 0, NULL, new_size - old_size);
else
gdk_array(splice) (self, new_size, old_size - new_size, NULL, 0);
}
G_GNUC_UNUSED static void
gdk_array(append) (GdkArray *self,
#ifdef GDK_ARRAY_BY_VALUE
_T_ *value)
#else
_T_ value)
#endif
{
gdk_array(splice) (self,
gdk_array(get_size) (self),
0,
#ifdef GDK_ARRAY_BY_VALUE
value,
#else
&value,
#endif
1);
}
#ifdef GDK_ARRAY_BY_VALUE
G_GNUC_UNUSED static _T_ *
gdk_array(get) (const GdkArray *self,
gsize pos)
{
return gdk_array(index) (self, pos);
}
#else
G_GNUC_UNUSED static _T_
gdk_array(get) (const GdkArray *self,
gsize pos)
{
return *gdk_array(index) (self, pos);
}
#endif
#ifndef GDK_ARRAY_NO_UNDEF
#undef _T_
#undef GdkArray
#undef gdk_array_paste_more
#undef gdk_array_paste
#undef gdk_array
#undef GDK_ARRAY_REAL_SIZE
#undef GDK_ARRAY_BY_VALUE
#undef GDK_ARRAY_ELEMENT_TYPE
#undef GDK_ARRAY_FREE_FUNC
#undef GDK_ARRAY_NAME
#undef GDK_ARRAY_NULL_TERMINATED
#undef GDK_ARRAY_PREALLOC
#undef GDK_ARRAY_TYPE_NAME
#endif
+1
View File
@@ -12,6 +12,7 @@ G_BEGIN_DECLS
#mesondefine GDK_WINDOWING_X11
#mesondefine GDK_WINDOWING_BROADWAY
#mesondefine GDK_WINDOWING_MACOS
#mesondefine GDK_WINDOWING_WAYLAND
#mesondefine GDK_WINDOWING_WIN32
+1 -1
View File
@@ -875,7 +875,7 @@ init (void)
g_slist_free (formats);
#ifdef G_OS_UNIX
#if defined(G_OS_UNIX) && !defined(__APPLE__)
file_transfer_portal_register ();
#endif
+1 -1
View File
@@ -907,7 +907,7 @@ init (void)
g_slist_free (formats);
#ifdef G_OS_UNIX
#if defined(G_OS_UNIX) && !defined(__APPLE__)
file_transfer_portal_register ();
#endif
+7
View File
@@ -50,6 +50,10 @@
#include "broadway/gdkprivate-broadway.h"
#endif
#ifdef GDK_WINDOWING_MACOS
#include "macos/gdkmacosdisplay-private.h"
#endif
#ifdef GDK_WINDOWING_WIN32
#include "win32/gdkwin32.h"
#include "win32/gdkprivate-win32.h"
@@ -262,6 +266,9 @@ static GdkBackend gdk_backends[] = {
#ifdef GDK_WINDOWING_QUARTZ
{ "quartz", _gdk_quartz_display_open },
#endif
#ifdef GDK_WINDOWING_MACOS
{ "macos", _gdk_macos_display_open },
#endif
#ifdef GDK_WINDOWING_WIN32
{ "win32", _gdk_win32_display_open },
#endif
+8
View File
@@ -283,6 +283,10 @@
#define GDK_KEY_dead_invertedbreve 0xfe6d
#define GDK_KEY_dead_belowcomma 0xfe6e
#define GDK_KEY_dead_currency 0xfe6f
#define GDK_KEY_dead_lowline 0xfe90
#define GDK_KEY_dead_aboveverticalline 0xfe91
#define GDK_KEY_dead_belowverticalline 0xfe92
#define GDK_KEY_dead_longsolidusoverlay 0xfe93
#define GDK_KEY_dead_a 0xfe80
#define GDK_KEY_dead_A 0xfe81
#define GDK_KEY_dead_e 0xfe82
@@ -2288,6 +2292,10 @@
#define GDK_KEY_TouchpadOn 0x1008ffb0
#define GDK_KEY_TouchpadOff 0x1008ffb1
#define GDK_KEY_AudioMicMute 0x1008ffb2
#define GDK_KEY_Keyboard 0x1008ffb3
#define GDK_KEY_WWAN 0x1008ffb4
#define GDK_KEY_RFKill 0x1008ffb5
#define GDK_KEY_AudioPreset 0x1008ffb6
#define GDK_KEY_Switch_VT_1 0x1008fe01
#define GDK_KEY_Switch_VT_2 0x1008fe02
#define GDK_KEY_Switch_VT_3 0x1008fe03
+1 -1
View File
@@ -354,7 +354,7 @@ gdk_rgba_equal (gconstpointer p1,
*
* Returns a textual specification of @rgba in the form
* `rgb(r,g,b)` or
* `rgba(r g,b,a)`,
* `rgba(r,g,b,a)`,
* where r, g, b and a represent the red, green,
* blue and alpha values respectively. r, g, and b are
* represented as integers in the range 0 to 255, and a
+718
View File
@@ -0,0 +1,718 @@
/* GdkMacosBaseView.c
*
* Copyright 2005-2007 Imendio AB
* Copyright 2011 Hiroyuki Yamamoto
* Copyright 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 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/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "config.h"
#import "GdkMacosBaseView.h"
#import "GdkMacosWindow.h"
#include "gdkinternals.h"
#include "gdkmacosdisplay-private.h"
#include "gdkmacossurface-private.h"
/* Text Input Client */
#define TIC_MARKED_TEXT "tic-marked-text"
#define TIC_SELECTED_POS "tic-selected-pos"
#define TIC_SELECTED_LEN "tic-selected-len"
#define TIC_INSERT_TEXT "tic-insert-text"
#define TIC_IN_KEY_DOWN "tic-in-key-down"
/* GtkIMContext */
#define GIC_CURSOR_RECT "gic-cursor-rect"
#define GIC_FILTER_KEY "gic-filter-key"
#define GIC_FILTER_PASSTHRU 0
#define GIC_FILTER_FILTERED 1
@implementation GdkMacosBaseView
-(id)initWithFrame:(NSRect)frameRect
{
if ((self = [super initWithFrame: frameRect]))
{
NSRect rect = NSMakeRect (0, 0, 0, 0);
NSTrackingAreaOptions options;
markedRange = NSMakeRange (NSNotFound, 0);
selectedRange = NSMakeRange (0, 0);
[self setValue: @(YES) forKey: @"postsFrameChangedNotifications"];
options = (NSTrackingMouseEnteredAndExited |
NSTrackingMouseMoved |
NSTrackingInVisibleRect |
NSTrackingActiveAlways);
trackingArea = [[NSTrackingArea alloc] initWithRect:rect
options:options
owner:(id)self
userInfo:nil];
[self addTrackingArea:trackingArea];
}
return self;
}
-(void)setNeedsDisplay:(BOOL)needsDisplay
{
for (id child in [self subviews])
[child setNeedsDisplay:needsDisplay];
}
-(void)setOpaqueRegion:(cairo_region_t *)region
{
/* Do nothing */
}
-(BOOL)acceptsFirstMouse
{
return YES;
}
-(BOOL)mouseDownCanMoveWindow
{
return NO;
}
-(BOOL)acceptsFirstResponder
{
GDK_NOTE (EVENTS, g_message ("acceptsFirstResponder"));
return YES;
}
-(BOOL)becomeFirstResponder
{
GDK_NOTE (EVENTS, g_message ("becomeFirstResponder"));
return YES;
}
-(BOOL)resignFirstResponder
{
GDK_NOTE (EVENTS, g_message ("resignFirstResponder"));
return YES;
}
-(void)setNeedsInvalidateShadow: (BOOL)invalidate
{
needsInvalidateShadow = invalidate;
}
-(NSTrackingArea *)trackingArea
{
return trackingArea;
}
-(GdkMacosSurface *)gdkSurface
{
return [(GdkMacosWindow *)[self window] gdkSurface];
}
-(GdkMacosDisplay *)gdkDisplay
{
GdkMacosSurface *surface = [self gdkSurface];
GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (surface));
return GDK_MACOS_DISPLAY (display);
}
-(void)keyDown:(NSEvent *)theEvent
{
/* NOTE: When user press Cmd+A, interpretKeyEvents: will call noop:
* method. When user press and hold A to show the accented char window,
* it consumed repeating key down events for key 'A' do NOT call
* any other method. We use this behavior to determine if this key
* down event is filtered by interpretKeyEvents.
*/
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_FILTERED));
GDK_NOTE (EVENTS, g_message ("keyDown"));
[self interpretKeyEvents: [NSArray arrayWithObject: theEvent]];
}
-(void)flagsChanged: (NSEvent *)theEvent
{
}
-(NSUInteger)characterIndexForPoint:(NSPoint)aPoint
{
GDK_NOTE (EVENTS, g_message ("characterIndexForPoint"));
return 0;
}
-(NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange: (NSRangePointer)actualRange
{
GdkRectangle *rect;
GDK_NOTE (EVENTS, g_message ("firstRectForCharacterRange"));
if ((rect = g_object_get_data (G_OBJECT ([self gdkSurface]), GIC_CURSOR_RECT)))
{
GdkMacosDisplay *display = [self gdkDisplay];
int ns_x, ns_y;
_gdk_macos_display_to_display_coords (display,
rect->x, rect->y + rect->height,
&ns_x, &ns_y);
return NSMakeRect (ns_x, ns_y, rect->width, rect->height);
}
return NSMakeRect (0, 0, 0, 0);
}
-(NSArray *)validAttributesForMarkedText
{
GDK_NOTE (EVENTS, g_message ("validAttributesForMarkedText"));
return [NSArray arrayWithObjects: NSUnderlineStyleAttributeName, nil];
}
-(NSAttributedString *)attributedSubstringForProposedRange: (NSRange)aRange actualRange: (NSRangePointer)actualRange
{
GDK_NOTE (EVENTS, g_message ("attributedSubstringForProposedRange"));
return nil;
}
-(BOOL)hasMarkedText
{
GDK_NOTE (EVENTS, g_message ("hasMarkedText"));
return markedRange.location != NSNotFound && markedRange.length != 0;
}
-(NSRange)markedRange
{
GDK_NOTE (EVENTS, g_message ("markedRange"));
return markedRange;
}
-(NSRange)selectedRange
{
GDK_NOTE (EVENTS, g_message ("selectedRange"));
return selectedRange;
}
-(void)unmarkText
{
GDK_NOTE (EVENTS, g_message ("unmarkText"));
selectedRange = NSMakeRange (0, 0);
markedRange = NSMakeRange (NSNotFound, 0);
g_object_set_data_full (G_OBJECT ([self gdkSurface]), TIC_MARKED_TEXT, NULL, g_free);
}
-(void)setMarkedText:(id)aString selectedRange: (NSRange)newSelection replacementRange: (NSRange)replacementRange
{
const char *str;
GDK_NOTE (EVENTS, g_message ("setMarkedText"));
if (replacementRange.location == NSNotFound)
{
markedRange = NSMakeRange (newSelection.location, [aString length]);
selectedRange = NSMakeRange (newSelection.location, newSelection.length);
}
else
{
markedRange = NSMakeRange (replacementRange.location, [aString length]);
selectedRange = NSMakeRange (replacementRange.location + newSelection.location, newSelection.length);
}
if ([aString isKindOfClass: [NSAttributedString class]])
str = [[aString string] UTF8String];
else
str = [aString UTF8String];
g_object_set_data_full (G_OBJECT ([self gdkSurface]), TIC_MARKED_TEXT, g_strdup (str), g_free);
g_object_set_data (G_OBJECT ([self gdkSurface]),
TIC_SELECTED_POS,
GUINT_TO_POINTER (selectedRange.location));
g_object_set_data (G_OBJECT ([self gdkSurface]),
TIC_SELECTED_LEN,
GUINT_TO_POINTER (selectedRange.length));
GDK_NOTE (EVENTS, g_message ("setMarkedText: set %s (%p, nsview %p): %s",
TIC_MARKED_TEXT, [self gdkSurface], self,
str ? str : "(empty)"));
/* handle text input changes by mouse events */
if (!GPOINTER_TO_UINT (g_object_get_data (G_OBJECT ([self gdkSurface]), TIC_IN_KEY_DOWN)))
_gdk_macos_surface_synthesize_null_key ([self gdkSurface]);
}
-(void)doCommandBySelector:(SEL)aSelector
{
GDK_NOTE (EVENTS, g_message ("doCommandBySelector"));
if ([self respondsToSelector: aSelector])
[self performSelector: aSelector];
}
-(void)insertText:(id)aString replacementRange: (NSRange)replacementRange
{
const char *str;
NSString *string;
GDK_NOTE (EVENTS, g_message ("insertText"));
if ([self hasMarkedText])
[self unmarkText];
if ([aString isKindOfClass: [NSAttributedString class]])
string = [aString string];
else
string = aString;
NSCharacterSet *ctrlChars = [NSCharacterSet controlCharacterSet];
NSCharacterSet *wsnlChars = [NSCharacterSet whitespaceAndNewlineCharacterSet];
if ([string rangeOfCharacterFromSet:ctrlChars].length &&
[string rangeOfCharacterFromSet:wsnlChars].length == 0)
{
/* discard invalid text input with Chinese input methods */
str = "";
[self unmarkText];
[[NSTextInputContext currentInputContext] discardMarkedText];
}
else
{
str = [string UTF8String];
}
g_object_set_data_full (G_OBJECT ([self gdkSurface]), TIC_INSERT_TEXT, g_strdup (str), g_free);
GDK_NOTE (EVENTS, g_message ("insertText: set %s (%p, nsview %p): %s",
TIC_INSERT_TEXT, [self gdkSurface], self,
str ? str : "(empty)"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_FILTERED));
/* handle text input changes by mouse events */
if (!GPOINTER_TO_UINT (g_object_get_data (G_OBJECT ([self gdkSurface]), TIC_IN_KEY_DOWN)))
_gdk_macos_surface_synthesize_null_key ([self gdkSurface]);
}
-(void)deleteBackward:(id)sender
{
GDK_NOTE (EVENTS, g_message ("deleteBackward"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)deleteForward:(id)sender
{
GDK_NOTE (EVENTS, g_message ("deleteForward"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)deleteToBeginningOfLine:(id)sender
{
GDK_NOTE (EVENTS, g_message ("deleteToBeginningOfLine"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)deleteToEndOfLine:(id)sender
{
GDK_NOTE (EVENTS, g_message ("deleteToEndOfLine"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)deleteWordBackward:(id)sender
{
GDK_NOTE (EVENTS, g_message ("deleteWordBackward"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)deleteWordForward:(id)sender
{
GDK_NOTE (EVENTS, g_message ("deleteWordForward"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)insertBacktab:(id)sender
{
GDK_NOTE (EVENTS, g_message ("insertBacktab"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)insertNewline:(id)sender
{
GDK_NOTE (EVENTS, g_message ("insertNewline"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)insertTab:(id)sender
{
GDK_NOTE (EVENTS, g_message ("insertTab"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveBackward:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveBackward"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveBackwardAndModifySelection:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveBackwardAndModifySelection"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveDown:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveDown"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveDownAndModifySelection:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveDownAndModifySelection"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveForward:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveForward"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveForwardAndModifySelection:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveForwardAndModifySelection"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveLeft:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveLeft"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveLeftAndModifySelection:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveLeftAndModifySelection"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveRight:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveRight"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveRightAndModifySelection:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveRightAndModifySelection"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveToBeginningOfDocument:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveToBeginningOfDocument"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveToBeginningOfDocumentAndModifySelection:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveToBeginningOfDocumentAndModifySelection"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveToBeginningOfLine:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveToBeginningOfLine"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveToBeginningOfLineAndModifySelection:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveToBeginningOfLineAndModifySelection"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveToEndOfDocument:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveToEndOfDocument"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveToEndOfDocumentAndModifySelection:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveToEndOfDocumentAndModifySelection"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveToEndOfLine:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveToEndOfLine"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveToEndOfLineAndModifySelection:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveToEndOfLineAndModifySelection"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveUp:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveUp"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveUpAndModifySelection:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveUpAndModifySelection"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveWordBackward:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveWordBackward"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveWordBackwardAndModifySelection:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveWordBackwardAndModifySelection"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveWordForward:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveWordForward"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveWordForwardAndModifySelection:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveWordForwardAndModifySelection"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveWordLeft:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveWordLeft"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveWordLeftAndModifySelection:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveWordLeftAndModifySelection"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveWordRight:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveWordRight"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)moveWordRightAndModifySelection:(id)sender
{
GDK_NOTE (EVENTS, g_message ("moveWordRightAndModifySelection"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)pageDown:(id)sender
{
GDK_NOTE (EVENTS, g_message ("pageDown"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)pageDownAndModifySelection:(id)sender
{
GDK_NOTE (EVENTS, g_message ("pageDownAndModifySelection"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)pageUp:(id)sender
{
GDK_NOTE (EVENTS, g_message ("pageUp"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)pageUpAndModifySelection:(id)sender
{
GDK_NOTE (EVENTS, g_message ("pageUpAndModifySelection"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)selectAll:(id)sender
{
GDK_NOTE (EVENTS, g_message ("selectAll"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)selectLine:(id)sender
{
GDK_NOTE (EVENTS, g_message ("selectLine"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)selectWord:(id)sender
{
GDK_NOTE (EVENTS, g_message ("selectWord"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)noop: (id)sender
{
GDK_NOTE (EVENTS, g_message ("noop"));
g_object_set_data (G_OBJECT ([self gdkSurface]),
GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
@end
@@ -1,6 +1,7 @@
/* GdkQuartzView.h
/* GdkMacosBaseView.h
*
* Copyright (C) 2005 Imendio AB
* Copyright © 2020 Red Hat, Inc.
* Copyright © 2005-2007 Imendio AB
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -14,36 +15,32 @@
*
* 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/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#import <AppKit/AppKit.h>
#include "gdk/gdk.h"
#import <Foundation/Foundation.h>
/* Text Input Client */
#define TIC_MARKED_TEXT "tic-marked-text"
#define TIC_SELECTED_POS "tic-selected-pos"
#define TIC_SELECTED_LEN "tic-selected-len"
#define TIC_INSERT_TEXT "tic-insert-text"
#define TIC_IN_KEY_DOWN "tic-in-key-down"
#include <gdk/gdk.h>
/* GtkIMContext */
#define GIC_CURSOR_RECT "gic-cursor-rect"
#define GIC_FILTER_KEY "gic-filter-key"
#define GIC_FILTER_PASSTHRU 0
#define GIC_FILTER_FILTERED 1
#include "gdkmacosdisplay.h"
#include "gdkmacossurface.h"
@interface GdkQuartzView : NSView <NSTextInputClient>
#define GDK_IS_MACOS_BASE_VIEW(obj) ((obj) && [obj isKindOfClass:[GdkMacosBaseView class]])
@interface GdkMacosBaseView : NSView <NSTextInputClient>
{
GdkSurface *gdk_surface;
NSTrackingRectTag trackingRect;
NSTrackingArea *trackingArea;
BOOL needsInvalidateShadow;
NSRange markedRange;
NSRange selectedRange;
}
- (void)setGdkSurface: (GdkSurface *)window;
- (GdkSurface *)gdkSurface;
- (NSTrackingRectTag)trackingRect;
- (void)setNeedsInvalidateShadow: (BOOL)invalidate;
-(GdkMacosSurface *)gdkSurface;
-(GdkMacosDisplay *)gdkDisplay;
-(void)setNeedsInvalidateShadow: (BOOL)invalidate;
-(NSTrackingArea *)trackingArea;
-(void)setOpaqueRegion:(cairo_region_t *)region;
@end
+171
View File
@@ -0,0 +1,171 @@
/* GdkMacosCairoSubview.c
*
* Copyright © 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 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/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "config.h"
#include <CoreGraphics/CoreGraphics.h>
#include <cairo-quartz.h>
#include "gdkinternals.h"
#import "GdkMacosCairoSubview.h"
#import "GdkMacosCairoView.h"
#include "gdkmacossurface-private.h"
@implementation GdkMacosCairoSubview
-(BOOL)isOpaque
{
return _isOpaque;
}
-(BOOL)isFlipped
{
return YES;
}
-(GdkSurface *)gdkSurface
{
return GDK_SURFACE ([(GdkMacosBaseView *)[self superview] gdkSurface]);
}
-(void)drawRect:(NSRect)rect
{
CGContextRef cgContext;
GdkSurface *gdk_surface;
cairo_surface_t *dest;
const NSRect *rects = NULL;
NSView *root_view;
NSInteger n_rects = 0;
NSRect abs_bounds;
cairo_t *cr;
CGSize scale;
int scale_factor;
if (self->cairoSurface == NULL)
return;
/* Acquire everything we need to do translations, drawing, etc */
gdk_surface = [self gdkSurface];
scale_factor = gdk_surface_get_scale_factor (gdk_surface);
root_view = [[self window] contentView];
cgContext = [[NSGraphicsContext currentContext] CGContext];
abs_bounds = [self convertRect:[self bounds] toView:root_view];
CGContextSaveGState (cgContext);
/* Translate scaling to remove HiDPI scaling from CGContext as
* cairo will be doing that for us already.
*/
scale = CGSizeMake (1.0, 1.0);
scale = CGContextConvertSizeToDeviceSpace (cgContext, scale);
CGContextScaleCTM (cgContext, 1.0 / scale.width, 1.0 / scale.height);
/* Create the cairo surface to draw to the CGContext and translate
* coordinates so we can pretend we are in the same coordinate system
* as the GDK surface.
*/
dest = cairo_quartz_surface_create_for_cg_context (cgContext,
gdk_surface->width * scale_factor,
gdk_surface->height * scale_factor);
cairo_surface_set_device_scale (dest, scale_factor, scale_factor);
/* Create cairo context and translate things into the origin of
* the topmost contentView so that we just draw at 0,0 with a
* clip region to paint the surface.
*/
cr = cairo_create (dest);
cairo_translate (cr, -abs_bounds.origin.x, -abs_bounds.origin.y);
/* Clip the cairo context based on the rectangles to be drawn
* within the bounding box :rect.
*/
[self getRectsBeingDrawn:&rects count:&n_rects];
for (NSInteger i = 0; i < n_rects; i++)
{
NSRect area = [self convertRect:rects[i] toView:root_view];
cairo_rectangle (cr,
area.origin.x, area.origin.y,
area.size.width, area.size.height);
}
cairo_clip (cr);
/* Now paint the surface (without blending) as we do not need
* any compositing here. The transparent regions (like shadows)
* are already on non-opaque layers.
*/
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_surface (cr, self->cairoSurface, 0, 0);
cairo_paint (cr);
/* Cleanup state, flush the surface to the backing layer, and
* restore GState for future use.
*/
cairo_destroy (cr);
cairo_surface_flush (dest);
cairo_surface_destroy (dest);
CGContextRestoreGState (cgContext);
}
-(void)setCairoSurface:(cairo_surface_t *)surface
withDamage:(cairo_region_t *)region
{
if (surface != self->cairoSurface)
{
g_clear_pointer (&self->cairoSurface, cairo_surface_destroy);
if (surface != NULL)
self->cairoSurface = cairo_surface_reference (surface);
}
if (region != NULL)
{
NSView *root_view = [[self window] contentView];
NSRect abs_bounds = [self convertRect:[self bounds] toView:root_view];
guint n_rects = cairo_region_num_rectangles (region);
for (guint i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
NSRect nsrect;
cairo_region_get_rectangle (region, i, &rect);
nsrect = NSMakeRect (rect.x, rect.y, rect.width, rect.height);
if (NSIntersectsRect (abs_bounds, nsrect))
{
nsrect.origin.x -= abs_bounds.origin.x;
nsrect.origin.y -= abs_bounds.origin.y;
[self setNeedsDisplayInRect:nsrect];
}
}
}
for (id view in [self subviews])
[(GdkMacosCairoSubview *)view setCairoSurface:surface
withDamage:region];
}
-(void)setOpaque:(BOOL)opaque
{
self->_isOpaque = opaque;
}
@end
+35
View File
@@ -0,0 +1,35 @@
/* GdkMacosCairoSubview.h
*
* Copyright © 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 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/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include <AppKit/AppKit.h>
#define GDK_IS_MACOS_CAIRO_SUBVIEW(obj) ((obj) && [obj isKindOfClass:[GdkMacosCairoSubview class]])
@interface GdkMacosCairoSubview : NSView
{
BOOL _isOpaque;
cairo_surface_t *cairoSurface;
}
-(void)setOpaque:(BOOL)opaque;
-(void)setCairoSurface:(cairo_surface_t *)cairoSurface
withDamage:(cairo_region_t *)region;
@end
+170
View File
@@ -0,0 +1,170 @@
/* GdkMacosCairoView.c
*
* Copyright © 2020 Red Hat, Inc.
* Copyright © 2005-2007 Imendio AB
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "config.h"
#include <CoreGraphics/CoreGraphics.h>
#include <cairo-quartz.h>
#include "gdkinternals.h"
#import "GdkMacosCairoView.h"
#import "GdkMacosCairoSubview.h"
#include "gdkmacossurface-private.h"
@implementation GdkMacosCairoView
-(void)dealloc
{
g_clear_pointer (&self->opaque, g_ptr_array_unref);
self->transparent = NULL;
[super dealloc];
}
-(BOOL)isOpaque
{
if ([self window])
return [[self window] isOpaque];
return YES;
}
-(BOOL)isFlipped
{
return YES;
}
-(void)setCairoSurface:(cairo_surface_t *)cairoSurface
withDamage:(cairo_region_t *)cairoRegion
{
for (id view in [self subviews])
[(GdkMacosCairoSubview *)view setCairoSurface:cairoSurface
withDamage:cairoRegion];
}
-(void)removeOpaqueChildren
{
[[self->transparent subviews]
makeObjectsPerformSelector:@selector(removeFromSuperview)];
if (self->opaque->len)
g_ptr_array_remove_range (self->opaque, 0, self->opaque->len);
}
-(void)setOpaqueRegion:(cairo_region_t *)region
{
NSRect abs_bounds;
guint n_rects;
if (region == NULL)
return;
abs_bounds = [self convertRect:[self bounds] toView:nil];
n_rects = cairo_region_num_rectangles (region);
/* The common case (at least for opaque windows and CSD) is that we will
* have either one or two opaque rectangles. If we detect that the same
* number of them are available as the previous, we can just resize the
* previous ones to avoid adding/removing views at a fast rate while
* resizing.
*/
if (n_rects == self->opaque->len)
{
for (guint i = 0; i < n_rects; i++)
{
GdkMacosCairoSubview *child;
cairo_rectangle_int_t rect;
child = g_ptr_array_index (self->opaque, i);
cairo_region_get_rectangle (region, i, &rect);
[child setFrame:NSMakeRect (rect.x - abs_bounds.origin.x,
rect.y - abs_bounds.origin.y,
rect.width,
rect.height)];
}
return;
}
[self removeOpaqueChildren];
for (guint i = 0; i < n_rects; i++)
{
GdkMacosCairoSubview *child;
cairo_rectangle_int_t rect;
NSRect nsrect;
cairo_region_get_rectangle (region, i, &rect);
nsrect = NSMakeRect (rect.x - abs_bounds.origin.x,
rect.y - abs_bounds.origin.y,
rect.width,
rect.height);
child = [[GdkMacosCairoSubview alloc] initWithFrame:nsrect];
[child setOpaque:YES];
[child setWantsLayer:YES];
[self->transparent addSubview:child];
g_ptr_array_add (self->opaque, child);
}
}
-(NSView *)initWithFrame:(NSRect)frame
{
if ((self = [super initWithFrame:frame]))
{
/* An array to track all the opaque children placed into
* the child self->transparent. This allows us to reuse them
* when we receive a new opaque area instead of discarding
* them on each draw.
*/
self->opaque = g_ptr_array_new ();
/* Setup our primary subview which will render all content that is not
* within an opaque region (such as shadows for CSD windows). For opaque
* windows, this will all be obscurred by other views, so it doesn't
* matter much to have it here.
*/
self->transparent = [[GdkMacosCairoSubview alloc] initWithFrame:frame];
[self addSubview:self->transparent];
}
return self;
}
-(void)setFrame:(NSRect)rect
{
[super setFrame:rect];
[self->transparent setFrame:NSMakeRect (0, 0, rect.size.width, rect.size.height)];
}
-(BOOL)acceptsFirstMouse
{
return YES;
}
-(BOOL)mouseDownCanMoveWindow
{
return NO;
}
@end
@@ -1,7 +1,7 @@
/* gdkdevicemanager-quartz.h
/* GdkMacosCairoView.h
*
* Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
* Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
* Copyright © 2020 Red Hat, Inc.
* Copyright © 2005-2007 Imendio AB
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -15,28 +15,23 @@
*
* 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/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef __GDK_QUARTZ_DEVICE_MANAGER_CORE__
#define __GDK_QUARTZ_DEVICE_MANAGER_CORE__
#include <cairo.h>
#include <gdkdevicemanagerprivate.h>
#include "gdkquartzdevicemanager-core.h"
#import "GdkMacosBaseView.h"
G_BEGIN_DECLS
#define GDK_IS_MACOS_CAIRO_VIEW(obj) ((obj) && [obj isKindOfClass:[GdkMacosCairoView class]])
struct _GdkQuartzDeviceManagerCore
@interface GdkMacosCairoView : GdkMacosBaseView
{
GObject parent_object;
GdkDevice *core_pointer;
GdkDevice *core_keyboard;
};
NSView *transparent;
GPtrArray *opaque;
}
struct _GdkQuartzDeviceManagerCoreClass
{
GObjectClass parent_class;
};
-(void)setCairoSurface:(cairo_surface_t *)cairoSurface
withDamage:(cairo_region_t *)region;
G_END_DECLS
#endif /* __GDK_QUARTZ_DEVICE_MANAGER__ */
@end
+157
View File
@@ -0,0 +1,157 @@
/* GdkMacosGLLayer.c
*
* Copyright © 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 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/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/* Based on Chromium image_transport_surface_calayer_mac.mm
* See the BSD-style license above.
*/
#include "config.h"
#include <OpenGL/gl.h>
#import "GdkMacosGLLayer.h"
@implementation GdkMacosGLLayer
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-(id)initWithContext:(NSOpenGLContext *)shared
{
[super init];
_shared = [shared retain];
return self;
}
-(void)dealloc
{
[_shared release];
_shared = nil;
[super dealloc];
}
-(void)setContentsRect:(NSRect)bounds
{
_pixelSize = bounds.size;
[super setContentsRect:bounds];
}
-(CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask
{
return CGLRetainPixelFormat ([[_shared pixelFormat] CGLPixelFormatObj]);
}
-(CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat
{
CGLContextObj context = NULL;
CGLCreateContext (pixelFormat, [_shared CGLContextObj], &context);
return context;
}
-(BOOL)canDrawInCGLContext:(CGLContextObj)glContext
pixelFormat:(CGLPixelFormatObj)pixelFormat
forLayerTime:(CFTimeInterval)timeInterval
displayTime:(const CVTimeStamp*)timeStamp
{
return YES;
}
-(void)drawInCGLContext:(CGLContextObj)glContext
pixelFormat:(CGLPixelFormatObj)pixelFormat
forLayerTime:(CFTimeInterval)timeInterval
displayTime:(const CVTimeStamp*)timeStamp
{
if (_texture == 0)
return;
glClearColor (1, 0, 1, 1);
glClear (GL_COLOR_BUFFER_BIT);
GLint viewport[4] = {0, 0, 0, 0};
glGetIntegerv (GL_VIEWPORT, viewport);
NSSize viewportSize = NSMakeSize (viewport[2], viewport[3]);
/* Set the coordinate system to be one-to-one with pixels. */
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0, viewportSize.width, 0, viewportSize.height, -1, 1);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
/* Draw a fullscreen quad. */
glColor4f (1, 1, 1, 1);
glEnable (GL_TEXTURE_RECTANGLE_ARB);
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, _texture);
glBegin (GL_QUADS);
{
glTexCoord2f (0, 0);
glVertex2f (0, 0);
glTexCoord2f (0, _pixelSize.height);
glVertex2f (0, _pixelSize.height);
glTexCoord2f (_pixelSize.width, _pixelSize.height);
glVertex2f (_pixelSize.width, _pixelSize.height);
glTexCoord2f (_pixelSize.width, 0);
glVertex2f (_pixelSize.width, 0);
}
glEnd ();
glBindTexture (0, _texture);
glDisable (GL_TEXTURE_RECTANGLE_ARB);
[super drawInCGLContext:glContext
pixelFormat:pixelFormat
forLayerTime:timeInterval
displayTime:timeStamp];
}
-(void)setTexture:(GLuint)texture
{
_texture = texture;
[self setNeedsDisplay];
}
G_GNUC_END_IGNORE_DEPRECATIONS
@end
@@ -1,6 +1,6 @@
/* gdkscreen-quartz.h
/* GdkMacosGLLayer.h
*
* Copyright (C) 2009,2010 Kristian Rietveld <kris@gtk.org>
* Copyright © 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -14,36 +14,27 @@
*
* 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/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef __GDK_QUARTZ_SCREEN__
#define __GDK_QUARTZ_SCREEN__
#include <AppKit/AppKit.h>
#include <glib.h>
G_BEGIN_DECLS
#define GDK_IS_MACOS_GL_LAYER(obj) ((obj) && [obj isKindOfClass:[GdkMacosGLLayer class]])
struct _GdkQuartzScreen
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
@interface GdkMacosGLLayer : CAOpenGLLayer
{
GObject parent_instance;
NSOpenGLContext *_shared;
GLuint _texture;
NSSize _pixelSize;
}
GdkDisplay *display;
-(id)initWithContext:(NSOpenGLContext *)shared;
-(void)setTexture:(GLuint)texture;
/* Origin of "root window" in Cocoa coordinates */
gint min_x;
gint min_y;
@end
gint width;
gint height;
guint screen_changed_id;
guint emit_monitors_changed : 1;
};
struct _GdkQuartzScreenClass
{
GObjectClass parent_class;
};
G_END_DECLS
#endif /* __GDK_QUARTZ_SCREEN__ */
G_GNUC_END_IGNORE_DEPRECATIONS
+732
View File
@@ -0,0 +1,732 @@
/* GdkMacosWindow.m
*
* Copyright © 2020 Red Hat, Inc.
* Copyright © 2005-2007 Imendio AB
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "config.h"
#include <gdk/gdk.h>
#import "GdkMacosBaseView.h"
#import "GdkMacosCairoView.h"
#import "GdkMacosWindow.h"
#include "gdkmacosdisplay-private.h"
#include "gdkmacossurface-private.h"
#include "gdkmacospopupsurface-private.h"
#include "gdkmacostoplevelsurface-private.h"
#include "gdkmonitorprivate.h"
#include "gdksurfaceprivate.h"
@implementation GdkMacosWindow
-(BOOL)windowShouldClose:(id)sender
{
GdkDisplay *display;
GdkEvent *event;
GList *node;
display = gdk_surface_get_display (GDK_SURFACE (gdk_surface));
event = gdk_delete_event_new (GDK_SURFACE (gdk_surface));
node = _gdk_event_queue_append (display, event);
_gdk_windowing_got_event (display, node, event,
_gdk_display_get_next_serial (display));
return NO;
}
-(void)windowWillMiniaturize:(NSNotification *)aNotification
{
if (GDK_IS_MACOS_TOPLEVEL_SURFACE (gdk_surface))
_gdk_macos_toplevel_surface_detach_from_parent (GDK_MACOS_TOPLEVEL_SURFACE (gdk_surface));
else if (GDK_IS_MACOS_POPUP_SURFACE (gdk_surface))
_gdk_macos_popup_surface_detach_from_parent (GDK_MACOS_POPUP_SURFACE (gdk_surface));
}
-(void)windowDidMiniaturize:(NSNotification *)aNotification
{
gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface), 0, GDK_SURFACE_STATE_MINIMIZED);
}
-(void)windowDidDeminiaturize:(NSNotification *)aNotification
{
if (GDK_IS_MACOS_TOPLEVEL_SURFACE (gdk_surface))
_gdk_macos_toplevel_surface_attach_to_parent (GDK_MACOS_TOPLEVEL_SURFACE (gdk_surface));
else if (GDK_IS_MACOS_POPUP_SURFACE (gdk_surface))
_gdk_macos_popup_surface_attach_to_parent (GDK_MACOS_POPUP_SURFACE (gdk_surface));
gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface), GDK_SURFACE_STATE_MINIMIZED, 0);
}
-(void)windowDidBecomeKey:(NSNotification *)aNotification
{
gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface), 0, GDK_SURFACE_STATE_FOCUSED);
_gdk_macos_display_surface_became_key ([self gdkDisplay], gdk_surface);
}
-(void)windowDidResignKey:(NSNotification *)aNotification
{
gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface), GDK_SURFACE_STATE_FOCUSED, 0);
_gdk_macos_display_surface_resigned_key ([self gdkDisplay], gdk_surface);
}
-(void)windowDidBecomeMain:(NSNotification *)aNotification
{
if (![self isVisible])
{
/* Note: This is a hack needed because for unknown reasons, hidden
* windows get shown when clicking the dock icon when the application
* is not already active.
*/
[self orderOut:nil];
return;
}
_gdk_macos_display_surface_became_main ([self gdkDisplay], gdk_surface);
}
-(void)windowDidResignMain:(NSNotification *)aNotification
{
_gdk_macos_display_surface_resigned_main ([self gdkDisplay], gdk_surface);
}
/* Used in combination with NSLeftMouseUp in sendEvent to keep track
* of when the window is being moved with the mouse.
*/
-(void)windowWillMove:(NSNotification *)aNotification
{
inMove = YES;
}
-(void)sendEvent:(NSEvent *)event
{
NSEventType event_type = [event type];
switch ((int)event_type)
{
case NSEventTypeLeftMouseUp: {
GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (gdk_surface));
double time = ((double)[event timestamp]) * 1000.0;
_gdk_macos_display_break_all_grabs (GDK_MACOS_DISPLAY (display), time);
inManualMove = NO;
inManualResize = NO;
inMove = NO;
/* We need to deliver the event to the proper drag gestures or we
* will leave the window in inconsistent state that requires clicking
* in the window to cancel the gesture.
*
* TODO: Can we improve grab breaking to fix this?
*/
_gdk_macos_display_send_button_event ([self gdkDisplay], event);
break;
}
case NSEventTypeLeftMouseDragged:
if ([self trackManualMove] || [self trackManualResize])
return;
break;
default:
break;
}
[super sendEvent:event];
}
-(BOOL)isInMove
{
return inMove;
}
-(void)checkSendEnterNotify
{
/* When a new window has been created, and the mouse is in the window
* area, we will not receive an NSEventTypeMouseEntered event.
* Therefore, we synthesize an enter notify event manually.
*/
if (!initialPositionKnown)
{
initialPositionKnown = YES;
if (NSPointInRect ([NSEvent mouseLocation], [self frame]))
{
GdkMacosBaseView *view = (GdkMacosBaseView *)[self contentView];
NSEvent *event;
event = [NSEvent enterExitEventWithType: NSEventTypeMouseEntered
location: [self mouseLocationOutsideOfEventStream]
modifierFlags: 0
timestamp: [[NSApp currentEvent] timestamp]
windowNumber: [self windowNumber]
context: NULL
eventNumber: 0
trackingNumber: (NSInteger)[view trackingArea]
userData: nil];
[NSApp postEvent:event atStart:NO];
}
}
}
-(void)windowDidUnmaximize
{
NSWindowStyleMask style_mask = [self styleMask];
gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface), GDK_SURFACE_STATE_MAXIMIZED, 0);
/* If we are using CSD, then we transitioned to an opaque
* window while we were maximized. Now we need to drop that
* as we are leaving maximized state.
*/
if ((style_mask & NSWindowStyleMaskTitled) == 0 && [self isOpaque])
[self setOpaque:NO];
}
-(void)windowDidMove:(NSNotification *)aNotification
{
GdkSurface *surface = GDK_SURFACE (gdk_surface);
gboolean maximized = (surface->state & GDK_SURFACE_STATE_MAXIMIZED) != 0;
/* In case the window is changed when maximized remove the maximized state */
if (maximized && !inMaximizeTransition && !NSEqualRects (lastMaximizedFrame, [self frame]))
[self windowDidUnmaximize];
_gdk_macos_surface_update_position (gdk_surface);
_gdk_macos_surface_reposition_children (gdk_surface);
[self checkSendEnterNotify];
}
-(void)windowDidResize:(NSNotification *)aNotification
{
NSRect content_rect;
GdkSurface *surface;
GdkDisplay *display;
GdkEvent *event;
gboolean maximized;
GList *node;
surface = GDK_SURFACE (gdk_surface);
display = gdk_surface_get_display (surface);
content_rect = [self contentRectForFrameRect:[self frame]];
maximized = (surface->state & GDK_SURFACE_STATE_MAXIMIZED) != 0;
/* see same in windowDidMove */
if (maximized && !inMaximizeTransition && !NSEqualRects (lastMaximizedFrame, [self frame]))
[self windowDidUnmaximize];
surface->width = content_rect.size.width;
surface->height = content_rect.size.height;
/* Certain resize operations (e.g. going fullscreen), also move the
* origin of the window.
*/
_gdk_macos_surface_update_position (GDK_MACOS_SURFACE (surface));
[[self contentView] setFrame:NSMakeRect (0, 0, surface->width, surface->height)];
_gdk_surface_update_size (surface);
/* Synthesize a configure event */
event = gdk_configure_event_new (surface,
content_rect.size.width,
content_rect.size.height);
node = _gdk_event_queue_append (display, event);
_gdk_windowing_got_event (display, node, event,
_gdk_display_get_next_serial (display));
_gdk_macos_surface_reposition_children (gdk_surface);
[self checkSendEnterNotify];
}
-(id)initWithContentRect:(NSRect)contentRect
styleMask:(NSWindowStyleMask)styleMask
backing:(NSBackingStoreType)backingType
defer:(BOOL)flag
screen:(NSScreen *)screen
{
GdkMacosCairoView *view;
self = [super initWithContentRect:contentRect
styleMask:styleMask
backing:backingType
defer:flag
screen:screen];
[self setAcceptsMouseMovedEvents:YES];
[self setDelegate:(id<NSWindowDelegate>)self];
[self setReleasedWhenClosed:YES];
view = [[GdkMacosCairoView alloc] initWithFrame:contentRect];
[self setContentView:view];
[view release];
return self;
}
-(BOOL)canBecomeMainWindow
{
return GDK_IS_TOPLEVEL (gdk_surface);
}
-(BOOL)canBecomeKeyWindow
{
return GDK_IS_TOPLEVEL (gdk_surface);
}
-(void)showAndMakeKey:(BOOL)makeKey
{
inShowOrHide = YES;
if (makeKey && [self canBecomeKeyWindow])
[self makeKeyAndOrderFront:nil];
else
[self orderFront:nil];
inShowOrHide = NO;
[self checkSendEnterNotify];
}
-(void)hide
{
inShowOrHide = YES;
[self orderOut:nil];
inShowOrHide = NO;
initialPositionKnown = NO;
}
-(BOOL)trackManualMove
{
NSRect windowFrame;
NSPoint currentLocation;
GdkMonitor *monitor;
GdkRectangle geometry;
GdkRectangle workarea;
int shadow_top = 0;
int shadow_left = 0;
int shadow_right = 0;
int shadow_bottom = 0;
GdkRectangle window_gdk;
GdkPoint pointer_position;
GdkPoint new_origin;
if (!inManualMove)
return NO;
/* Get our shadow so we can adjust the window position sans-shadow */
_gdk_macos_surface_get_shadow (gdk_surface,
&shadow_top,
&shadow_right,
&shadow_bottom,
&shadow_left);
windowFrame = [self frame];
currentLocation = [NSEvent mouseLocation];
/* Update the snapping geometry to match the current monitor */
monitor = _gdk_macos_display_get_monitor_at_display_coords ([self gdkDisplay],
currentLocation.x,
currentLocation.y);
gdk_monitor_get_geometry (monitor, &geometry);
gdk_monitor_get_workarea (monitor, &workarea);
_edge_snapping_set_monitor (&self->snapping, &geometry, &workarea);
/* Convert origins to GDK coordinates */
_gdk_macos_display_from_display_coords ([self gdkDisplay],
currentLocation.x,
currentLocation.y,
&pointer_position.x,
&pointer_position.y);
_gdk_macos_display_from_display_coords ([self gdkDisplay],
windowFrame.origin.x,
windowFrame.origin.y + windowFrame.size.height,
&window_gdk.x,
&window_gdk.y);
window_gdk.width = windowFrame.size.width;
window_gdk.height = windowFrame.size.height;
/* Subtract our shadowin from the window */
window_gdk.x += shadow_left;
window_gdk.y += shadow_top;
window_gdk.width = window_gdk.width - shadow_left - shadow_right;
window_gdk.height = window_gdk.height - shadow_top - shadow_bottom;
/* Now place things on the monitor */
_edge_snapping_motion (&self->snapping, &pointer_position, &window_gdk);
/* And add our shadow back to the frame */
window_gdk.x -= shadow_left;
window_gdk.y -= shadow_top;
window_gdk.width += shadow_left + shadow_right;
window_gdk.height += shadow_top + shadow_bottom;
/* Convert to quartz coordiantes */
_gdk_macos_display_to_display_coords ([self gdkDisplay],
window_gdk.x,
window_gdk.y + window_gdk.height,
&new_origin.x, &new_origin.y);
windowFrame.origin.x = new_origin.x;
windowFrame.origin.y = new_origin.y;
/* And now apply the frame to the window */
[self setFrameOrigin:NSMakePoint(new_origin.x, new_origin.y)];
return YES;
}
/* Used by gdkmacosdisplay-translate.c to decide if our sendEvent() handler
* above will see the event or if it will be subjected to standard processing
* by GDK.
*/
-(BOOL)isInManualResizeOrMove
{
return inManualResize || inManualMove;
}
-(void)beginManualMove
{
NSPoint initialMoveLocation;
GdkPoint point;
GdkMonitor *monitor;
GdkRectangle geometry;
GdkRectangle area;
GdkRectangle workarea;
if (inMove || inManualMove || inManualResize)
return;
inManualMove = YES;
monitor = _gdk_macos_surface_get_best_monitor ([self gdkSurface]);
gdk_monitor_get_geometry (monitor, &geometry);
gdk_monitor_get_workarea (monitor, &workarea);
initialMoveLocation = [NSEvent mouseLocation];
_gdk_macos_display_from_display_coords ([self gdkDisplay],
initialMoveLocation.x,
initialMoveLocation.y,
&point.x,
&point.y);
area.x = gdk_surface->root_x;
area.y = gdk_surface->root_y;
area.width = GDK_SURFACE (gdk_surface)->width;
area.height = GDK_SURFACE (gdk_surface)->height;
_edge_snapping_init (&self->snapping,
&geometry,
&workarea,
&point,
&area);
}
-(BOOL)trackManualResize
{
NSPoint mouse_location;
NSRect new_frame;
float mdx, mdy, dw, dh, dx, dy;
NSSize min_size;
if (!inManualResize || inTrackManualResize)
return NO;
inTrackManualResize = YES;
mouse_location = [self convertPointToScreen:[self mouseLocationOutsideOfEventStream]];
mdx = initialResizeLocation.x - mouse_location.x;
mdy = initialResizeLocation.y - mouse_location.y;
/* Set how a mouse location delta translates to changes in width,
* height and position.
*/
dw = dh = dx = dy = 0.0;
if (resizeEdge == GDK_SURFACE_EDGE_EAST ||
resizeEdge == GDK_SURFACE_EDGE_NORTH_EAST ||
resizeEdge == GDK_SURFACE_EDGE_SOUTH_EAST)
{
dw = -1.0;
}
if (resizeEdge == GDK_SURFACE_EDGE_NORTH ||
resizeEdge == GDK_SURFACE_EDGE_NORTH_WEST ||
resizeEdge == GDK_SURFACE_EDGE_NORTH_EAST)
{
dh = -1.0;
}
if (resizeEdge == GDK_SURFACE_EDGE_SOUTH ||
resizeEdge == GDK_SURFACE_EDGE_SOUTH_WEST ||
resizeEdge == GDK_SURFACE_EDGE_SOUTH_EAST)
{
dh = 1.0;
dy = -1.0;
}
if (resizeEdge == GDK_SURFACE_EDGE_WEST ||
resizeEdge == GDK_SURFACE_EDGE_NORTH_WEST ||
resizeEdge == GDK_SURFACE_EDGE_SOUTH_WEST)
{
dw = 1.0;
dx = -1.0;
}
/* Apply changes to the frame captured when we started resizing */
new_frame = initialResizeFrame;
new_frame.origin.x += mdx * dx;
new_frame.origin.y += mdy * dy;
new_frame.size.width += mdx * dw;
new_frame.size.height += mdy * dh;
/* In case the resulting window would be too small reduce the
* change to both size and position.
*/
min_size = [self contentMinSize];
if (new_frame.size.width < min_size.width)
{
if (dx)
new_frame.origin.x -= min_size.width - new_frame.size.width;
new_frame.size.width = min_size.width;
}
if (new_frame.size.height < min_size.height)
{
if (dy)
new_frame.origin.y -= min_size.height - new_frame.size.height;
new_frame.size.height = min_size.height;
}
/* We could also apply aspect ratio:
new_frame.size.height = new_frame.size.width / [self aspectRatio].width * [self aspectRatio].height;
*/
[self setFrame:new_frame display:YES];
/* Let the resizing be handled by GTK+. */
if (g_main_context_pending (NULL))
g_main_context_iteration (NULL, FALSE);
inTrackManualResize = NO;
return YES;
}
-(void)beginManualResize:(GdkSurfaceEdge)edge
{
if (inMove || inManualMove || inManualResize)
return;
inManualResize = YES;
resizeEdge = edge;
initialResizeFrame = [self frame];
initialResizeLocation = [self convertPointToScreen:[self mouseLocationOutsideOfEventStream]];
}
-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
{
return NSDragOperationNone;
}
-(void)draggingEnded:(id <NSDraggingInfo>)sender
{
}
-(void)draggingExited:(id <NSDraggingInfo>)sender
{
}
-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
{
return NSDragOperationNone;
}
-(BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
return YES;
}
-(BOOL)wantsPeriodicDraggingUpdates
{
return NO;
}
-(void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
{
}
-(void)setStyleMask:(NSWindowStyleMask)styleMask
{
gboolean was_fullscreen;
gboolean is_fullscreen;
gboolean was_opaque;
gboolean is_opaque;
was_fullscreen = (([self styleMask] & NSWindowStyleMaskFullScreen) != 0);
was_opaque = (([self styleMask] & NSWindowStyleMaskTitled) != 0);
[super setStyleMask:styleMask];
is_fullscreen = (([self styleMask] & NSWindowStyleMaskFullScreen) != 0);
is_opaque = (([self styleMask] & NSWindowStyleMaskTitled) != 0);
if (was_fullscreen != is_fullscreen)
_gdk_macos_surface_update_fullscreen_state (gdk_surface);
if (was_opaque != is_opaque)
{
[self setOpaque:is_opaque];
if (!is_opaque)
[self setBackgroundColor:[NSColor clearColor]];
}
}
-(NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
{
GdkMacosSurface *surface = gdk_surface;
NSRect rect;
gint shadow_top;
/* Allow the window to move up "shadow_top" more than normally allowed
* by the default impl. This makes it possible to move windows with
* client side shadow right up to the screen's menu bar. */
_gdk_macos_surface_get_shadow (surface, &shadow_top, NULL, NULL, NULL);
rect = [super constrainFrameRect:frameRect toScreen:screen];
if (frameRect.origin.y > rect.origin.y)
rect.origin.y = MIN (frameRect.origin.y, rect.origin.y + shadow_top);
return rect;
}
-(NSRect)windowWillUseStandardFrame:(NSWindow *)nsWindow
defaultFrame:(NSRect)newFrame
{
NSRect screenFrame = [[self screen] visibleFrame];
GdkMacosSurface *surface = gdk_surface;
gboolean maximized = GDK_SURFACE (surface)->state & GDK_SURFACE_STATE_MAXIMIZED;
if (!maximized)
return screenFrame;
else
return lastUnmaximizedFrame;
}
-(BOOL)windowShouldZoom:(NSWindow *)nsWindow
toFrame:(NSRect)newFrame
{
GdkMacosSurface *surface = gdk_surface;
GdkSurfaceState state = GDK_SURFACE (surface)->state;
if (state & GDK_SURFACE_STATE_MAXIMIZED)
{
lastMaximizedFrame = newFrame;
[self windowDidUnmaximize];
}
else
{
lastUnmaximizedFrame = [nsWindow frame];
gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface), 0, GDK_SURFACE_STATE_MAXIMIZED);
}
inMaximizeTransition = YES;
return YES;
}
-(void)windowDidEndLiveResize:(NSNotification *)aNotification
{
gboolean maximized = GDK_SURFACE (gdk_surface)->state & GDK_SURFACE_STATE_MAXIMIZED;
inMaximizeTransition = NO;
/* Even if this is CSD, we want to be opaque while maximized
* to speed up compositing by allowing the display server to
* avoid costly blends.
*/
if (maximized)
[self setOpaque:YES];
}
-(NSSize)window:(NSWindow *)window willUseFullScreenContentSize:(NSSize)proposedSize
{
return [[window screen] frame].size;
}
-(void)windowWillEnterFullScreen:(NSNotification *)aNotification
{
lastUnfullscreenFrame = [self frame];
}
-(void)windowWillExitFullScreen:(NSNotification *)aNotification
{
[self setFrame:lastUnfullscreenFrame display:YES];
}
-(void)windowDidExitFullScreen:(NSNotification *)aNotification
{
}
-(void)windowDidChangeScreen:(NSNotification *)aNotification
{
_gdk_macos_surface_monitor_changed (gdk_surface);
}
-(void)setGdkSurface:(GdkMacosSurface *)surface
{
self->gdk_surface = surface;
}
-(void)setDecorated:(BOOL)decorated
{
NSWindowStyleMask style_mask = [self styleMask];
[self setHasShadow:decorated];
if (decorated)
style_mask |= NSWindowStyleMaskTitled;
else
style_mask &= ~NSWindowStyleMaskTitled;
[self setStyleMask:style_mask];
}
-(GdkMacosSurface *)gdkSurface
{
return self->gdk_surface;
}
-(GdkMacosDisplay *)gdkDisplay
{
return GDK_MACOS_DISPLAY (GDK_SURFACE (self->gdk_surface)->display);
}
-(BOOL)movableByWindowBackground
{
return NO;
}
@end
+70
View File
@@ -0,0 +1,70 @@
/* GdkMacosWindow.h
*
* Copyright © 2020 Red Hat, Inc.
* Copyright © 2005-2007 Imendio AB
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
#include <gdk/gdk.h>
#include "gdkmacosdisplay.h"
#include "gdkmacossurface.h"
#include "edgesnapping.h"
#define GDK_IS_MACOS_WINDOW(obj) ([obj isKindOfClass:[GdkMacosWindow class]])
@interface GdkMacosWindow : NSWindow {
GdkMacosSurface *gdk_surface;
BOOL inMove;
BOOL inShowOrHide;
BOOL initialPositionKnown;
/* Manually triggered move/resize (not by the window manager) */
BOOL inManualMove;
BOOL inManualResize;
BOOL inTrackManualResize;
NSPoint initialResizeLocation;
NSRect initialResizeFrame;
GdkSurfaceEdge resizeEdge;
EdgeSnapping snapping;
NSRect lastUnmaximizedFrame;
NSRect lastMaximizedFrame;
NSRect lastUnfullscreenFrame;
BOOL inMaximizeTransition;
}
-(void)beginManualMove;
-(void)beginManualResize:(GdkSurfaceEdge)edge;
-(void)hide;
-(BOOL)isInManualResizeOrMove;
-(BOOL)isInMove;
-(GdkMacosDisplay *)gdkDisplay;
-(GdkMacosSurface *)gdkSurface;
-(void)setGdkSurface:(GdkMacosSurface *)surface;
-(void)setStyleMask:(NSWindowStyleMask)styleMask;
-(void)showAndMakeKey:(BOOL)makeKey;
-(BOOL)trackManualMove;
-(BOOL)trackManualResize;
-(void)setDecorated:(BOOL)decorated;
@end
+229
View File
@@ -0,0 +1,229 @@
/* edgesnapping.c
*
* Copyright © 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 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/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "config.h"
#include "gdkrectangle.h"
#include "edgesnapping.h"
#define LEAVE_THRESHOLD 3.0
#define ENTER_THRESHOLD 2.0
#define X1(r) ((r)->x)
#define X2(r) ((r)->x + (r)->width)
#define Y1(r) ((r)->y)
#define Y2(r) ((r)->y + (r)->height)
void
_edge_snapping_init (EdgeSnapping *self,
const GdkRectangle *geometry,
const GdkRectangle *workarea,
const GdkPoint *pointer_position,
const GdkRectangle *window)
{
g_assert (self != NULL);
g_assert (geometry != NULL);
g_assert (workarea != NULL);
g_assert (pointer_position != NULL);
self->geometry = *geometry;
self->workarea = *workarea;
self->last_pointer_position = *pointer_position;
self->pointer_offset_in_window.x = pointer_position->x - window->x;
self->pointer_offset_in_window.y = pointer_position->y - window->y;
}
static void
edge_snapping_constrain_left (EdgeSnapping *self,
int change,
const GdkRectangle *geometry,
GdkRectangle *window)
{
if (change < 0)
{
if (X1 (window) < X1 (geometry) &&
X1 (window) > X1 (geometry) - LEAVE_THRESHOLD &&
ABS (change) < LEAVE_THRESHOLD)
window->x = geometry->x;
}
/* We don't constrain when returning from left edge */
}
static void
edge_snapping_constrain_right (EdgeSnapping *self,
int change,
const GdkRectangle *geometry,
GdkRectangle *window)
{
if (change > 0)
{
if (X2 (window) > X2 (geometry) &&
X2 (window) < X2 (geometry) + LEAVE_THRESHOLD &&
ABS (change) < LEAVE_THRESHOLD)
window->x = X2 (geometry) - window->width;
}
/* We don't constrain when returning from right edge */
}
static void
edge_snapping_constrain_top (EdgeSnapping *self,
int change,
const GdkRectangle *geometry,
GdkRectangle *window)
{
if (change < 0)
{
if (Y1 (window) < Y1 (geometry))
window->y = geometry->y;
}
/* We don't constrain when returning from top edge */
}
static void
edge_snapping_constrain_bottom (EdgeSnapping *self,
int change,
const GdkRectangle *geometry,
GdkRectangle *window)
{
if (change > 0)
{
if (Y2 (window) > Y2 (geometry) &&
Y2 (window) < Y2 (geometry) + LEAVE_THRESHOLD &&
ABS (change) < LEAVE_THRESHOLD)
window->y = Y2 (geometry) - window->height;
}
else if (change < 0)
{
if (Y2 (window) < Y2 (geometry) &&
Y2 (window) > Y2 (geometry) - ENTER_THRESHOLD &&
ABS (change) < ENTER_THRESHOLD)
window->y = Y2 (geometry) - window->height;
}
}
static void
edge_snapping_constrain_horizontal (EdgeSnapping *self,
int change,
const GdkRectangle *geometry,
GdkRectangle *window)
{
g_assert (self != NULL);
g_assert (geometry != NULL);
g_assert (window != NULL);
g_assert (change != 0);
if (ABS (X1 (geometry) - X1 (window)) < ABS (X2 (geometry)) - ABS (X2 (window)))
edge_snapping_constrain_left (self, change, geometry, window);
else
edge_snapping_constrain_right (self, change, geometry, window);
}
static void
edge_snapping_constrain_vertical (EdgeSnapping *self,
int change,
const GdkRectangle *geometry,
GdkRectangle *window,
gboolean bottom_only)
{
g_assert (self != NULL);
g_assert (geometry != NULL);
g_assert (window != NULL);
g_assert (change != 0);
if (!bottom_only &&
ABS (Y1 (geometry) - Y1 (window)) < ABS (Y2 (geometry)) - ABS (Y2 (window)))
edge_snapping_constrain_top (self, change, geometry, window);
else
edge_snapping_constrain_bottom (self, change, geometry, window);
}
void
_edge_snapping_motion (EdgeSnapping *self,
const GdkPoint *pointer_position,
GdkRectangle *window)
{
GdkRectangle new_window;
GdkRectangle overlap;
GdkPoint change;
g_assert (self != NULL);
g_assert (pointer_position != NULL);
change.x = pointer_position->x - self->last_pointer_position.x;
change.y = pointer_position->y - self->last_pointer_position.y;
self->last_pointer_position = *pointer_position;
window->x += change.x;
window->y += change.y;
new_window = *window;
/* First constrain horizontal */
if (change.x)
{
edge_snapping_constrain_horizontal (self, change.x, &self->workarea, &new_window);
if (gdk_rectangle_equal (&new_window, window))
edge_snapping_constrain_horizontal (self, change.x, &self->geometry, &new_window);
}
/* Now constrain veritcally */
if (change.y)
{
edge_snapping_constrain_vertical (self, change.y, &self->workarea, &new_window, FALSE);
if (new_window.y == window->y)
edge_snapping_constrain_vertical (self, change.y, &self->geometry, &new_window, TRUE);
}
/* If the window is not placed in the monitor at all, then we need to
* just move the window onto the new screen using the original offset
* of the pointer within the window.
*/
if (!gdk_rectangle_intersect (&self->geometry, &new_window, &overlap))
{
new_window.x = pointer_position->x - self->pointer_offset_in_window.x;
new_window.y = pointer_position->y - self->pointer_offset_in_window.y;
}
/* And finally make sure we aren't underneath the top bar of the
* particular monitor.
*/
if (Y1 (&new_window) < Y1 (&self->workarea))
new_window.y = self->workarea.y;
*window = new_window;
}
void
_edge_snapping_set_monitor (EdgeSnapping *self,
const GdkRectangle *geometry,
const GdkRectangle *workarea)
{
g_assert (self != NULL);
g_assert (geometry != NULL);
g_assert (workarea != NULL);
self->geometry = *geometry;
self->workarea = *workarea;
}
+50
View File
@@ -0,0 +1,50 @@
/* edgesnapping.h
*
* Copyright © 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 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/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef __EDGE_SNAPPING_H__
#define __EDGE_SNAPPING_H__
#include "gdktypes.h"
G_BEGIN_DECLS
typedef struct
{
GdkRectangle geometry;
GdkRectangle workarea;
GdkPoint last_pointer_position;
GdkPoint pointer_offset_in_window;
} EdgeSnapping;
void _edge_snapping_init (EdgeSnapping *self,
const GdkRectangle *geometry,
const GdkRectangle *workarea,
const GdkPoint *pointer_position,
const GdkRectangle *window);
void _edge_snapping_motion (EdgeSnapping *self,
const GdkPoint *pointer_position,
GdkRectangle *window);
void _edge_snapping_set_monitor (EdgeSnapping *self,
const GdkRectangle *geometry,
const GdkRectangle *workarea);
G_END_DECLS
#endif /* __EDGE_SNAPPING_H__ */
+254
View File
@@ -0,0 +1,254 @@
/* gdkdisplaylinksource.c
*
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Christian Hergert <christian@hergert.me>
*/
#include "config.h"
#include <AppKit/AppKit.h>
#include <mach/mach_time.h>
#include "gdkdisplaylinksource.h"
#include "gdkmacoseventsource-private.h"
static gint64 host_to_frame_clock_time (gint64 host_time);
static gboolean
gdk_display_link_source_prepare (GSource *source,
gint *timeout_)
{
GdkDisplayLinkSource *impl = (GdkDisplayLinkSource *)source;
gint64 now;
now = g_source_get_time (source);
if (now < impl->presentation_time)
*timeout_ = (impl->presentation_time - now) / 1000L;
else
*timeout_ = -1;
return impl->needs_dispatch;
}
static gboolean
gdk_display_link_source_check (GSource *source)
{
GdkDisplayLinkSource *impl = (GdkDisplayLinkSource *)source;
return impl->needs_dispatch;
}
static gboolean
gdk_display_link_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
GdkDisplayLinkSource *impl = (GdkDisplayLinkSource *)source;
gboolean ret = G_SOURCE_CONTINUE;
impl->needs_dispatch = FALSE;
if (callback != NULL)
ret = callback (user_data);
return ret;
}
static void
gdk_display_link_source_finalize (GSource *source)
{
GdkDisplayLinkSource *impl = (GdkDisplayLinkSource *)source;
CVDisplayLinkStop (impl->display_link);
CVDisplayLinkRelease (impl->display_link);
}
static GSourceFuncs gdk_display_link_source_funcs = {
gdk_display_link_source_prepare,
gdk_display_link_source_check,
gdk_display_link_source_dispatch,
gdk_display_link_source_finalize
};
void
gdk_display_link_source_pause (GdkDisplayLinkSource *source)
{
CVDisplayLinkStop (source->display_link);
}
void
gdk_display_link_source_unpause (GdkDisplayLinkSource *source)
{
CVDisplayLinkStart (source->display_link);
}
static CVReturn
gdk_display_link_source_frame_cb (CVDisplayLinkRef display_link,
const CVTimeStamp *inNow,
const CVTimeStamp *inOutputTime,
CVOptionFlags flagsIn,
CVOptionFlags *flagsOut,
void *user_data)
{
GdkDisplayLinkSource *impl = user_data;
gint64 presentation_time;
gboolean needs_wakeup;
needs_wakeup = !g_atomic_int_get (&impl->needs_dispatch);
presentation_time = host_to_frame_clock_time (inOutputTime->hostTime);
impl->presentation_time = presentation_time;
impl->needs_dispatch = TRUE;
if (needs_wakeup)
{
NSEvent *event;
/* Post a message so we'll break out of the message loop.
*
* We don't use g_main_context_wakeup() here because that
* would result in sending a message to the pipe(2) fd in
* the select thread which would then send this message as
* well. Lots of extra work.
*/
event = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
location: NSZeroPoint
modifierFlags: 0
timestamp: 0
windowNumber: 0
context: nil
subtype: GDK_MACOS_EVENT_SUBTYPE_EVENTLOOP
data1: 0
data2: 0];
[NSApp postEvent:event atStart:YES];
}
return kCVReturnSuccess;
}
/**
* gdk_display_link_source_new:
*
* Creates a new #GSource that will activate the dispatch function upon
* notification from a CVDisplayLink that a new frame should be drawn.
*
* Effort is made to keep the transition from the high-priority
* CVDisplayLink thread into this GSource lightweight. However, this is
* somewhat non-ideal since the best case would be to do the drawing
* from the high-priority thread.
*
* Returns: (transfer full): A newly created #GSource.
*/
GSource *
gdk_display_link_source_new (void)
{
GdkDisplayLinkSource *impl;
GSource *source;
CVReturn ret;
double period;
source = g_source_new (&gdk_display_link_source_funcs, sizeof *impl);
impl = (GdkDisplayLinkSource *)source;
/*
* Create our link based on currently connected displays.
* If there are multiple displays, this will be something that tries
* to work for all of them. In the future, we may want to explore multiple
* links based on the connected displays.
*/
ret = CVDisplayLinkCreateWithActiveCGDisplays (&impl->display_link);
if (ret != kCVReturnSuccess)
{
g_warning ("Failed to initialize CVDisplayLink!");
return source;
}
/*
* Determine our nominal period between frames.
*/
period = CVDisplayLinkGetActualOutputVideoRefreshPeriod (impl->display_link);
if (period == 0.0)
period = 1.0 / 60.0;
impl->refresh_interval = period * 1000000L;
impl->refresh_rate = 1.0 / period * 1000L;
/*
* Wire up our callback to be executed within the high-priority thread.
*/
CVDisplayLinkSetOutputCallback (impl->display_link,
gdk_display_link_source_frame_cb,
source);
g_source_set_name (source, "[gdk] quartz frame clock");
return source;
}
static gint64
host_to_frame_clock_time (gint64 host_time)
{
static mach_timebase_info_data_t timebase_info;
/*
* NOTE:
*
* This code is taken from GLib to match g_get_monotonic_time().
*/
if (G_UNLIKELY (timebase_info.denom == 0))
{
/* This is a fraction that we must use to scale
* mach_absolute_time() by in order to reach nanoseconds.
*
* We've only ever observed this to be 1/1, but maybe it could be
* 1000/1 if mach time is microseconds already, or 1/1000 if
* picoseconds. Try to deal nicely with that.
*/
mach_timebase_info (&timebase_info);
/* We actually want microseconds... */
if (timebase_info.numer % 1000 == 0)
timebase_info.numer /= 1000;
else
timebase_info.denom *= 1000;
/* We want to make the numer 1 to avoid having to multiply... */
if (timebase_info.denom % timebase_info.numer == 0)
{
timebase_info.denom /= timebase_info.numer;
timebase_info.numer = 1;
}
else
{
/* We could just multiply by timebase_info.numer below, but why
* bother for a case that may never actually exist...
*
* Plus -- performing the multiplication would risk integer
* overflow. If we ever actually end up in this situation, we
* should more carefully evaluate the correct course of action.
*/
mach_timebase_info (&timebase_info); /* Get a fresh copy for a better message */
g_error ("Got weird mach timebase info of %d/%d. Please file a bug against GLib.",
timebase_info.numer, timebase_info.denom);
}
}
return host_time / timebase_info.denom;
}
+49
View File
@@ -0,0 +1,49 @@
/* gdkdisplaylinksource.h
*
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Christian Hergert <christian@hergert.me>
*/
#ifndef GDK_DISPLAY_LINK_SOURCE_H
#define GDK_DISPLAY_LINK_SOURCE_H
#include <glib.h>
#include <QuartzCore/QuartzCore.h>
G_BEGIN_DECLS
typedef struct
{
GSource source;
CVDisplayLinkRef display_link;
gint64 refresh_interval;
guint refresh_rate;
volatile gint64 presentation_time;
volatile guint needs_dispatch;
} GdkDisplayLinkSource;
GSource *gdk_display_link_source_new (void);
void gdk_display_link_source_pause (GdkDisplayLinkSource *source);
void gdk_display_link_source_unpause (GdkDisplayLinkSource *source);
G_END_DECLS
#endif /* GDK_DISPLAY_LINK_SOURCE_H */
+32
View File
@@ -0,0 +1,32 @@
/*
* Copyright © 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef __GDK_MACOS_H__
#define __GDK_MACOS_H__
#include <gdk/gdk.h>
#include "gdkmacosdevice.h"
#include "gdkmacosdisplay.h"
#include "gdkmacosglcontext.h"
#include "gdkmacoskeymap.h"
#include "gdkmacosmonitor.h"
#include "gdkmacossurface.h"
#endif /* __GDK_MACOS_H__ */
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright © 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef __GDK_MACOS_CAIRO_CONTEXT_PRIVATE_H__
#define __GDK_MACOS_CAIRO_CONTEXT_PRIVATE_H__
#include "gdkcairocontextprivate.h"
G_BEGIN_DECLS
typedef struct _GdkMacosCairoContext GdkMacosCairoContext;
typedef struct _GdkMacosCairoContextClass GdkMacosCairoContextClass;
#define GDK_TYPE_MACOS_CAIRO_CONTEXT (_gdk_macos_cairo_context_get_type())
#define GDK_MACOS_CAIRO_CONTEXT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_CAIRO_CONTEXT, GdkMacosCairoContext))
#define GDK_IS_MACOS_CAIRO_CONTEXT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_CAIRO_CONTEXT))
GType _gdk_macos_cairo_context_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __GDK_MACOS_CAIRO_CONTEXT_PRIVATE_H__ */
+155
View File
@@ -0,0 +1,155 @@
/*
* Copyright © 2016 Benjamin Otte
* Copyright © 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "config.h"
#include "gdkconfig.h"
#include <CoreGraphics/CoreGraphics.h>
#include <cairo-quartz.h>
#import "GdkMacosCairoView.h"
#include "gdkmacoscairocontext-private.h"
#include "gdkmacossurface-private.h"
struct _GdkMacosCairoContext
{
GdkCairoContext parent_instance;
cairo_surface_t *window_surface;
};
struct _GdkMacosCairoContextClass
{
GdkCairoContextClass parent_class;
};
G_DEFINE_TYPE (GdkMacosCairoContext, _gdk_macos_cairo_context, GDK_TYPE_CAIRO_CONTEXT)
static cairo_surface_t *
create_cairo_surface_for_surface (GdkSurface *surface)
{
cairo_surface_t *cairo_surface;
int scale;
int width;
int height;
g_assert (GDK_IS_MACOS_SURFACE (surface));
scale = gdk_surface_get_scale_factor (surface);
width = scale * gdk_surface_get_width (surface);
height = scale * gdk_surface_get_height (surface);
cairo_surface = cairo_quartz_surface_create (CAIRO_FORMAT_ARGB32, width, height);
if (cairo_surface != NULL)
cairo_surface_set_device_scale (cairo_surface, scale, scale);
return cairo_surface;
}
static cairo_t *
_gdk_macos_cairo_context_cairo_create (GdkCairoContext *cairo_context)
{
GdkMacosCairoContext *self = (GdkMacosCairoContext *)cairo_context;
g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (self));
return cairo_create (self->window_surface);
}
static void
_gdk_macos_cairo_context_begin_frame (GdkDrawContext *draw_context,
cairo_region_t *region)
{
GdkMacosCairoContext *self = (GdkMacosCairoContext *)draw_context;
GdkSurface *surface;
NSWindow *nswindow;
g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (self));
surface = gdk_draw_context_get_surface (draw_context);
nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface));
if (self->window_surface == NULL)
{
self->window_surface = create_cairo_surface_for_surface (surface);
}
else
{
if (![nswindow isOpaque])
{
cairo_t *cr = cairo_create (self->window_surface);
gdk_cairo_region (cr, region);
cairo_set_source_rgba (cr, 0, 0, 0, 0);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_fill (cr);
cairo_destroy (cr);
}
}
}
static void
_gdk_macos_cairo_context_end_frame (GdkDrawContext *draw_context,
cairo_region_t *painted)
{
GdkMacosCairoContext *self = (GdkMacosCairoContext *)draw_context;
GdkSurface *surface;
NSView *nsview;
g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (self));
g_assert (self->window_surface != NULL);
surface = gdk_draw_context_get_surface (draw_context);
nsview = _gdk_macos_surface_get_view (GDK_MACOS_SURFACE (surface));
if (GDK_IS_MACOS_CAIRO_VIEW (nsview))
[(GdkMacosCairoView *)nsview setCairoSurface:self->window_surface
withDamage:painted];
}
static void
_gdk_macos_cairo_context_surface_resized (GdkDrawContext *draw_context)
{
GdkMacosCairoContext *self = (GdkMacosCairoContext *)draw_context;
g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (self));
g_clear_pointer (&self->window_surface, cairo_surface_destroy);
}
static void
_gdk_macos_cairo_context_class_init (GdkMacosCairoContextClass *klass)
{
GdkCairoContextClass *cairo_context_class = GDK_CAIRO_CONTEXT_CLASS (klass);
GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
draw_context_class->begin_frame = _gdk_macos_cairo_context_begin_frame;
draw_context_class->end_frame = _gdk_macos_cairo_context_end_frame;
draw_context_class->surface_resized = _gdk_macos_cairo_context_surface_resized;
cairo_context_class->cairo_create = _gdk_macos_cairo_context_cairo_create;
}
static void
_gdk_macos_cairo_context_init (GdkMacosCairoContext *self)
{
}
+54
View File
@@ -0,0 +1,54 @@
/*
* Copyright © 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef __GDK_MACOS_CLIPBOARD_PRIVATE_H__
#define __GDK_MACOS_CLIPBOARD_PRIVATE_H__
#include <AppKit/AppKit.h>
#include "gdkclipboardprivate.h"
#include "gdkmacosdisplay-private.h"
G_BEGIN_DECLS
#define GDK_TYPE_MACOS_CLIPBOARD (_gdk_macos_clipboard_get_type())
G_DECLARE_FINAL_TYPE (GdkMacosClipboard, _gdk_macos_clipboard, GDK, MACOS_CLIPBOARD, GdkClipboard)
GdkClipboard *_gdk_macos_clipboard_new (GdkMacosDisplay *display);
void _gdk_macos_clipboard_check_externally_modified (GdkMacosClipboard *self);
NSPasteboardType _gdk_macos_clipboard_to_ns_type (const char *mime_type,
NSPasteboardType *alternate);
const char *_gdk_macos_clipboard_from_ns_type (NSPasteboardType ns_type);
@interface GdkMacosClipboardDataProvider : NSObject <NSPasteboardItemDataProvider>
{
GCancellable *cancellable;
GdkClipboard *clipboard;
char **mimeTypes;
}
-(id)initClipboard:(GdkClipboard *)gdkClipboard mimetypes:(const char * const *)mime_types;
-(NSArray<NSPasteboardType> *)types;
@end
G_END_DECLS
#endif /* __GDK_MACOS_CLIPBOARD_PRIVATE_H__ */
+576
View File
@@ -0,0 +1,576 @@
/*
* Copyright © 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "config.h"
#include <glib/gi18n.h>
#include "gdkmacosclipboard-private.h"
#include "gdkmacosutils-private.h"
struct _GdkMacosClipboard
{
GdkClipboard parent_instance;
NSPasteboard *pasteboard;
NSInteger last_change_count;
};
typedef struct
{
GMemoryOutputStream *stream;
NSPasteboardItem *item;
NSPasteboardType type;
GMainContext *main_context;
guint done : 1;
} WriteRequest;
G_DEFINE_TYPE (GdkMacosClipboard, _gdk_macos_clipboard, GDK_TYPE_CLIPBOARD)
static void
write_request_free (WriteRequest *wr)
{
g_clear_pointer (&wr->main_context, g_main_context_unref);
g_clear_object (&wr->stream);
[wr->item release];
g_slice_free (WriteRequest, wr);
}
const char *
_gdk_macos_clipboard_from_ns_type (NSPasteboardType type)
{
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
if ([type isEqualToString:NSPasteboardTypeString] ||
[type isEqualToString:NSStringPboardType])
return g_intern_string ("text/plain;charset=utf-8");
else if ([type isEqualToString:NSPasteboardTypeURL] ||
[type isEqualToString:NSPasteboardTypeFileURL])
return g_intern_string ("text/uri-list");
else if ([type isEqualToString:NSPasteboardTypeColor])
return g_intern_string ("application/x-color");
else if ([type isEqualToString:NSPasteboardTypeTIFF])
return g_intern_string ("image/tiff");
else if ([type isEqualToString:NSPasteboardTypePNG])
return g_intern_string ("image/png");
G_GNUC_END_IGNORE_DEPRECATIONS;
return NULL;
}
NSPasteboardType
_gdk_macos_clipboard_to_ns_type (const char *mime_type,
NSPasteboardType *alternate)
{
if (alternate)
*alternate = NULL;
if (g_strcmp0 (mime_type, "text/plain;charset=utf-8") == 0)
{
return NSPasteboardTypeString;
}
else if (g_strcmp0 (mime_type, "text/uri-list") == 0)
{
if (alternate)
*alternate = NSPasteboardTypeURL;
return NSPasteboardTypeFileURL;
}
else if (g_strcmp0 (mime_type, "application/x-color") == 0)
{
return NSPasteboardTypeColor;
}
else if (g_strcmp0 (mime_type, "image/tiff") == 0)
{
return NSPasteboardTypeTIFF;
}
else if (g_strcmp0 (mime_type, "image/png") == 0)
{
return NSPasteboardTypePNG;
}
return nil;
}
static void
populate_content_formats (GdkContentFormatsBuilder *builder,
NSPasteboardType type)
{
const char *mime_type;
g_return_if_fail (builder != NULL);
g_return_if_fail (type != NULL);
mime_type = _gdk_macos_clipboard_from_ns_type (type);
if (mime_type != NULL)
gdk_content_formats_builder_add_mime_type (builder, mime_type);
}
static GdkContentFormats *
load_offer_formats (GdkMacosClipboard *self)
{
GDK_BEGIN_MACOS_ALLOC_POOL;
GdkContentFormatsBuilder *builder;
GdkContentFormats *formats;
g_assert (GDK_IS_MACOS_CLIPBOARD (self));
builder = gdk_content_formats_builder_new ();
for (NSPasteboardType type in [self->pasteboard types])
populate_content_formats (builder, type);
formats = gdk_content_formats_builder_free_to_formats (builder);
GDK_END_MACOS_ALLOC_POOL;
return g_steal_pointer (&formats);
}
static void
_gdk_macos_clipboard_load_contents (GdkMacosClipboard *self)
{
GdkContentFormats *formats;
NSInteger change_count;
g_assert (GDK_IS_MACOS_CLIPBOARD (self));
change_count = [self->pasteboard changeCount];
formats = load_offer_formats (self);
gdk_clipboard_claim_remote (GDK_CLIPBOARD (self), formats);
gdk_content_formats_unref (formats);
self->last_change_count = change_count;
}
static GInputStream *
create_stream_from_nsdata (NSData *data)
{
const guint8 *bytes = [data bytes];
gsize len = [data length];
return g_memory_input_stream_new_from_data (g_memdup (bytes, len), len, g_free);
}
static void
_gdk_macos_clipboard_read_async (GdkClipboard *clipboard,
GdkContentFormats *formats,
int io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GDK_BEGIN_MACOS_ALLOC_POOL;
GdkMacosClipboard *self = (GdkMacosClipboard *)clipboard;
GdkContentFormats *offer_formats = NULL;
const char *mime_type;
GInputStream *stream = NULL;
GTask *task = NULL;
g_assert (GDK_IS_MACOS_CLIPBOARD (self));
g_assert (formats != NULL);
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, _gdk_macos_clipboard_read_async);
g_task_set_priority (task, io_priority);
offer_formats = load_offer_formats (GDK_MACOS_CLIPBOARD (clipboard));
mime_type = gdk_content_formats_match_mime_type (formats, offer_formats);
if (mime_type == NULL)
{
g_task_return_new_error (task,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"%s",
_("No compatible transfer format found"));
goto cleanup;
}
if (strcmp (mime_type, "text/plain;charset=utf-8") == 0)
{
NSString *nsstr = [self->pasteboard stringForType:NSPasteboardTypeString];
if (nsstr != NULL)
{
const char *str = [nsstr UTF8String];
stream = g_memory_input_stream_new_from_data (g_strdup (str),
strlen (str) + 1,
g_free);
}
}
else if (strcmp (mime_type, "text/uri-list") == 0)
{
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
if ([[self->pasteboard types] containsObject:NSPasteboardTypeFileURL])
{
GString *str = g_string_new (NULL);
NSArray *files = [self->pasteboard propertyListForType:NSFilenamesPboardType];
gsize n_files = [files count];
char *data;
guint len;
for (gsize i = 0; i < n_files; ++i)
{
NSString* uriString = [files objectAtIndex:i];
uriString = [@"file://" stringByAppendingString:uriString];
uriString = [uriString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
g_string_append_printf (str,
"%s\r\n",
[uriString cStringUsingEncoding:NSUTF8StringEncoding]);
}
len = str->len;
data = g_string_free (str, FALSE);
stream = g_memory_input_stream_new_from_data (data, len, g_free);
}
G_GNUC_END_IGNORE_DEPRECATIONS;
}
else if (strcmp (mime_type, "application/x-color") == 0)
{
NSColorSpace *colorspace;
NSColor *nscolor;
guint16 color[4];
colorspace = [NSColorSpace genericRGBColorSpace];
nscolor = [[NSColor colorFromPasteboard:self->pasteboard]
colorUsingColorSpace:colorspace];
color[0] = 0xffff * [nscolor redComponent];
color[1] = 0xffff * [nscolor greenComponent];
color[2] = 0xffff * [nscolor blueComponent];
color[3] = 0xffff * [nscolor alphaComponent];
stream = g_memory_input_stream_new_from_data (g_memdup (&color, sizeof color),
sizeof color,
g_free);
}
else if (strcmp (mime_type, "image/tiff") == 0)
{
NSData *data = [self->pasteboard dataForType:NSPasteboardTypeTIFF];
stream = create_stream_from_nsdata (data);
}
else if (strcmp (mime_type, "image/png") == 0)
{
NSData *data = [self->pasteboard dataForType:NSPasteboardTypePNG];
stream = create_stream_from_nsdata (data);
}
if (stream != NULL)
{
g_task_set_task_data (task, g_strdup (mime_type), g_free);
g_task_return_pointer (task, g_steal_pointer (&stream), g_object_unref);
}
else
{
g_task_return_new_error (task,
G_IO_ERROR,
G_IO_ERROR_FAILED,
_("Failed to decode contents with mime-type of '%s'"),
mime_type);
}
cleanup:
g_clear_object (&task);
g_clear_pointer (&offer_formats, gdk_content_formats_unref);
GDK_END_MACOS_ALLOC_POOL;
}
static GInputStream *
_gdk_macos_clipboard_read_finish (GdkClipboard *clipboard,
GAsyncResult *result,
const char **out_mime_type,
GError **error)
{
GTask *task = (GTask *)result;
g_assert (GDK_IS_MACOS_CLIPBOARD (clipboard));
g_assert (G_IS_TASK (task));
if (out_mime_type != NULL)
*out_mime_type = g_strdup (g_task_get_task_data (task));
return g_task_propagate_pointer (task, error);
}
static void
_gdk_macos_clipboard_send_to_pasteboard (GdkMacosClipboard *self,
GdkContentProvider *content)
{
GDK_BEGIN_MACOS_ALLOC_POOL;
GdkMacosClipboardDataProvider *dataProvider;
GdkContentFormats *serializable;
NSPasteboardItem *item;
const char * const *mime_types;
gsize n_mime_types;
g_return_if_fail (GDK_IS_MACOS_CLIPBOARD (self));
g_return_if_fail (GDK_IS_CONTENT_PROVIDER (content));
serializable = gdk_content_provider_ref_storable_formats (content);
serializable = gdk_content_formats_union_serialize_mime_types (serializable);
mime_types = gdk_content_formats_get_mime_types (serializable, &n_mime_types);
dataProvider = [[GdkMacosClipboardDataProvider alloc] initClipboard:GDK_CLIPBOARD (self)
mimetypes:mime_types];
item = [[NSPasteboardItem alloc] init];
[item setDataProvider:dataProvider forTypes:[dataProvider types]];
[self->pasteboard clearContents];
if ([self->pasteboard writeObjects:[NSArray arrayWithObject:item]] == NO)
g_warning ("Failed to write object to pasteboard");
self->last_change_count = [self->pasteboard changeCount];
g_clear_pointer (&serializable, gdk_content_formats_unref);
GDK_END_MACOS_ALLOC_POOL;
}
static gboolean
_gdk_macos_clipboard_claim (GdkClipboard *clipboard,
GdkContentFormats *formats,
gboolean local,
GdkContentProvider *provider)
{
GdkMacosClipboard *self = (GdkMacosClipboard *)clipboard;
gboolean ret;
g_assert (GDK_IS_CLIPBOARD (clipboard));
g_assert (formats != NULL);
g_assert (!provider || GDK_IS_CONTENT_PROVIDER (provider));
ret = GDK_CLIPBOARD_CLASS (_gdk_macos_clipboard_parent_class)->claim (clipboard, formats, local, provider);
if (local)
_gdk_macos_clipboard_send_to_pasteboard (self, provider);
return ret;
}
static void
_gdk_macos_clipboard_constructed (GObject *object)
{
GdkMacosClipboard *self = (GdkMacosClipboard *)object;
if (self->pasteboard == nil)
self->pasteboard = [[NSPasteboard generalPasteboard] retain];
G_OBJECT_CLASS (_gdk_macos_clipboard_parent_class)->constructed (object);
}
static void
_gdk_macos_clipboard_finalize (GObject *object)
{
GdkMacosClipboard *self = (GdkMacosClipboard *)object;
if (self->pasteboard != nil)
{
[self->pasteboard release];
self->pasteboard = nil;
}
G_OBJECT_CLASS (_gdk_macos_clipboard_parent_class)->finalize (object);
}
static void
_gdk_macos_clipboard_class_init (GdkMacosClipboardClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdkClipboardClass *clipboard_class = GDK_CLIPBOARD_CLASS (klass);
object_class->constructed = _gdk_macos_clipboard_constructed;
object_class->finalize = _gdk_macos_clipboard_finalize;
clipboard_class->claim = _gdk_macos_clipboard_claim;
clipboard_class->read_async = _gdk_macos_clipboard_read_async;
clipboard_class->read_finish = _gdk_macos_clipboard_read_finish;
}
static void
_gdk_macos_clipboard_init (GdkMacosClipboard *self)
{
}
GdkClipboard *
_gdk_macos_clipboard_new (GdkMacosDisplay *display)
{
GdkMacosClipboard *self;
g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
self = g_object_new (GDK_TYPE_MACOS_CLIPBOARD,
"display", display,
NULL);
_gdk_macos_clipboard_load_contents (self);
return GDK_CLIPBOARD (self);
}
void
_gdk_macos_clipboard_check_externally_modified (GdkMacosClipboard *self)
{
g_return_if_fail (GDK_IS_MACOS_CLIPBOARD (self));
if ([self->pasteboard changeCount] != self->last_change_count)
_gdk_macos_clipboard_load_contents (self);
}
@implementation GdkMacosClipboardDataProvider
-(id)initClipboard:(GdkClipboard *)gdkClipboard mimetypes:(const char * const *)mime_types;
{
[super init];
self->mimeTypes = g_strdupv ((char **)mime_types);
self->clipboard = g_object_ref (gdkClipboard);
return self;
}
-(void)dealloc
{
g_cancellable_cancel (self->cancellable);
g_clear_pointer (&self->mimeTypes, g_strfreev);
g_clear_object (&self->clipboard);
g_clear_object (&self->cancellable);
[super dealloc];
}
-(void)pasteboardFinishedWithDataProvider:(NSPasteboard *)pasteboard
{
g_clear_object (&self->clipboard);
}
-(NSArray<NSPasteboardType> *)types
{
NSMutableArray *ret = [[NSMutableArray alloc] init];
for (guint i = 0; self->mimeTypes[i]; i++)
{
const char *mime_type = self->mimeTypes[i];
NSPasteboardType type;
NSPasteboardType alternate = nil;
if ((type = _gdk_macos_clipboard_to_ns_type (mime_type, &alternate)))
{
[ret addObject:type];
if (alternate)
[ret addObject:alternate];
}
}
return g_steal_pointer (&ret);
}
static void
on_data_ready_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GDK_BEGIN_MACOS_ALLOC_POOL;
GdkClipboard *clipboard = (GdkClipboard *)object;
WriteRequest *wr = user_data;
GError *error = NULL;
NSData *data = nil;
g_assert (GDK_IS_CLIPBOARD (clipboard));
g_assert (G_IS_ASYNC_RESULT (result));
g_assert (wr != NULL);
g_assert (G_IS_MEMORY_OUTPUT_STREAM (wr->stream));
g_assert ([wr->item isKindOfClass:[NSPasteboardItem class]]);
if (gdk_clipboard_write_finish (clipboard, result, &error))
{
gsize size;
gpointer bytes;
g_output_stream_close (G_OUTPUT_STREAM (wr->stream), NULL, NULL);
size = g_memory_output_stream_get_size (wr->stream);
bytes = g_memory_output_stream_steal_data (wr->stream);
data = [[NSData alloc] initWithBytesNoCopy:bytes
length:size
deallocator:^(void *alloc, NSUInteger length) { g_free (alloc); }];
}
else
{
g_warning ("Failed to serialize clipboard contents: %s",
error->message);
g_clear_error (&error);
}
[wr->item setData:data forType:wr->type];
wr->done = TRUE;
GDK_END_MACOS_ALLOC_POOL;
}
-(void) pasteboard:(NSPasteboard *)pasteboard
item:(NSPasteboardItem *)item
provideDataForType:(NSPasteboardType)type
{
const char *mime_type = _gdk_macos_clipboard_from_ns_type (type);
GMainContext *main_context = g_main_context_default ();
WriteRequest *wr;
if (self->clipboard == NULL || mime_type == NULL)
{
[item setData:[NSData data] forType:type];
return;
}
wr = g_slice_new0 (WriteRequest);
wr->item = [item retain];
wr->stream = G_MEMORY_OUTPUT_STREAM (g_memory_output_stream_new_resizable ());
wr->type = type;
wr->main_context = g_main_context_ref (main_context);
wr->done = FALSE;
gdk_clipboard_write_async (self->clipboard,
mime_type,
G_OUTPUT_STREAM (wr->stream),
G_PRIORITY_DEFAULT,
self->cancellable,
on_data_ready_cb,
wr);
/* We're forced to provide data synchronously via this API
* so we must block on the main loop. Using another main loop
* than the default tends to get us locked up here, so that is
* what we'll do for now.
*/
while (!wr->done)
g_main_context_iteration (wr->main_context, TRUE);
write_request_free (wr);
}
@end
@@ -1,7 +1,7 @@
/* gdkdnd-quartz.h
/* gdkmacoscursor-private.h
*
* Copyright (C) 2005 Imendio AB
* Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
* Copyright (C) 2005-2007 Imendio AB
* Copyright (C) 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -17,29 +17,16 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_QUARTZ_DND__
#define __GDK_QUARTZ_DND__
#include <gdkdndprivate.h>
#include "gdkquartzdnd.h"
#ifndef __GDK_MACOS_CURSOR_PRIVATE_H__
#define __GDK_MACOS_CURSOR_PRIVATE_H__
#include <AppKit/AppKit.h>
#include <gdk/gdk.h>
G_BEGIN_DECLS
struct _GdkQuartzDragContext
{
GdkDragContext context;
id <NSDraggingInfo> dragging_info;
GdkDevice *device;
};
struct _GdkQuartzDragContextClass
{
GdkDragContextClass context_class;
};
NSCursor *_gdk_macos_cursor_get_ns_cursor (GdkCursor *cursor);
G_END_DECLS
#endif /* __GDK_QUARTZ_DND__ */
#endif /* __GDK_MACOS_CURSOR_PRIVATE_H__ */
+181
View File
@@ -0,0 +1,181 @@
/* gdkcursor-macos.c
*
* Copyright (C) 2005-2007 Imendio AB
* Copyright (C) 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include "gdkmacoscursor-private.h"
/* OS X only exports a number of cursor types in its public NSCursor interface.
* By overriding the private _coreCursorType method, we can tell OS X to load
* one of its internal cursors instead (since cursor images are loaded on demand
* instead of in advance). WebKit does this too.
*/
@interface gdkCoreCursor : NSCursor {
@private
int type;
BOOL override;
}
@end
@implementation gdkCoreCursor
- (long long)_coreCursorType
{
if (self->override)
return self->type;
return [super _coreCursorType];
}
#define CUSTOM_CURSOR_CTOR(name, id) \
+ (gdkCoreCursor *)name \
{ \
gdkCoreCursor *obj; \
obj = [self new]; \
if (obj) { \
obj->override = YES; \
obj->type = id; \
} \
return obj; \
}
CUSTOM_CURSOR_CTOR(gdkHelpCursor, 40)
CUSTOM_CURSOR_CTOR(gdkProgressCursor, 4)
/* TODO OS X doesn't seem to have a way to get this. There is an undocumented
* method +[NSCursor _waitCursor], but it doesn't actually return this cursor,
* but rather some odd low-quality non-animating version of this cursor. Use
* the progress cursor instead for now.
*/
CUSTOM_CURSOR_CTOR(gdkWaitCursor, 4)
CUSTOM_CURSOR_CTOR(gdkAliasCursor, 2)
CUSTOM_CURSOR_CTOR(gdkMoveCursor, 39)
/* TODO OS X doesn't seem to provide one; copy the move cursor for now
* since it looks similar to what we want. */
CUSTOM_CURSOR_CTOR(gdkAllScrollCursor, 39)
CUSTOM_CURSOR_CTOR(gdkNEResizeCursor, 29)
CUSTOM_CURSOR_CTOR(gdkNWResizeCursor, 33)
CUSTOM_CURSOR_CTOR(gdkSEResizeCursor, 35)
CUSTOM_CURSOR_CTOR(gdkSWResizeCursor, 37)
CUSTOM_CURSOR_CTOR(gdkEWResizeCursor, 28)
CUSTOM_CURSOR_CTOR(gdkNSResizeCursor, 32)
CUSTOM_CURSOR_CTOR(gdkNESWResizeCursor, 30)
CUSTOM_CURSOR_CTOR(gdkNWSEResizeCursor, 34)
CUSTOM_CURSOR_CTOR(gdkZoomInCursor, 42)
CUSTOM_CURSOR_CTOR(gdkZoomOutCursor, 43)
#undef CUSTOM_CURSOR_CTOR
@end
struct CursorsByName {
const gchar *name;
NSString *selector;
};
static const struct CursorsByName cursors_by_name[] = {
/* Link & Status */
{ "context-menu", @"contextualMenuCursor" },
{ "help", @"gdkHelpCursor" },
{ "pointer", @"pointingHandCursor" },
{ "progress", @"gdkProgressCursor" },
{ "wait", @"gdkWaitCursor" },
/* Selection */
{ "cell", @"crosshairCursor" },
{ "crosshair", @"crosshairCursor" },
{ "text", @"IBeamCursor" },
{ "vertical-text", @"IBeamCursorForVerticalLayout" },
/* Drag & Drop */
{ "alias", @"gdkAliasCursor" },
{ "copy", @"dragCopyCursor" },
{ "move", @"gdkMoveCursor" },
{ "no-drop", @"operationNotAllowedCursor" },
{ "not-allowed", @"operationNotAllowedCursor" },
{ "grab", @"openHandCursor" },
{ "grabbing", @"closedHandCursor" },
/* Resize & Scrolling */
{ "all-scroll", @"gdkAllScrollCursor" },
{ "col-resize", @"resizeLeftRightCursor" },
{ "row-resize", @"resizeUpDownCursor" },
/* Undocumented cursors to match native resizing */
{ "e-resize", @"_windowResizeEastWestCursor" },
{ "w-resize", @"_windowResizeEastWestCursor" },
{ "n-resize", @"_windowResizeNorthSouthCursor" },
{ "s-resize", @"_windowResizeNorthSouthCursor" },
{ "ne-resize", @"gdkNEResizeCursor" },
{ "nw-resize", @"gdkNWResizeCursor" },
{ "se-resize", @"gdkSEResizeCursor" },
{ "sw-resize", @"gdkSWResizeCursor" },
{ "ew-resize", @"gdkEWResizeCursor" },
{ "ns-resize", @"gdkNSResizeCursor" },
{ "nesw-resize", @"gdkNESWResizeCursor" },
{ "nwse-resize", @"gdkNWSEResizeCursor" },
/* Zoom */
{ "zoom-in", @"gdkZoomInCursor" },
{ "zoom-out", @"gdkZoomOutCursor" },
};
static NSCursor *
create_blank_cursor (void)
{
NSCursor *nscursor;
NSImage *nsimage;
NSSize size = { 1.0, 1.0 };
nsimage = [[NSImage alloc] initWithSize:size];
nscursor = [[NSCursor alloc] initWithImage:nsimage
hotSpot:NSMakePoint(0.0, 0.0)];
[nsimage release];
return nscursor;
}
NSCursor *
_gdk_macos_cursor_get_ns_cursor (GdkCursor *cursor)
{
const char *name = NULL;
NSCursor *nscursor;
SEL selector = @selector(arrowCursor);
g_return_val_if_fail (!cursor || GDK_IS_CURSOR (cursor), NULL);
if (cursor != NULL)
name = gdk_cursor_get_name (cursor);
if (name == NULL)
goto load_cursor;
if (strcmp (name, "none") == 0)
return create_blank_cursor ();
for (guint i = 0; i < G_N_ELEMENTS (cursors_by_name); i++)
{
if (strcmp (cursors_by_name[i].name, name) == 0)
{
selector = NSSelectorFromString (cursors_by_name[i].selector);
break;
}
}
load_cursor:
nscursor = [[gdkCoreCursor class] performSelector:selector];
[nscursor retain];
return nscursor;
}
+208
View File
@@ -0,0 +1,208 @@
/*
* Copyright 2009 Carlos Garnacho <carlosg@gnome.org>
* Copyright 2010 Kristian Rietveld <kris@gtk.org>
* Copyright 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "config.h"
#include <gdk/gdk.h>
#include "gdkdeviceprivate.h"
#include "gdkdisplayprivate.h"
#include "gdkmacoscursor-private.h"
#include "gdkmacosdevice.h"
#include "gdkmacosdisplay-private.h"
#include "gdkmacossurface-private.h"
struct _GdkMacosDevice
{
GdkDevice parent_instance;
};
struct _GdkMacosDeviceClass
{
GdkDeviceClass parent_class;
};
G_DEFINE_TYPE (GdkMacosDevice, gdk_macos_device, GDK_TYPE_DEVICE)
static void
gdk_macos_device_set_surface_cursor (GdkDevice *device,
GdkSurface *surface,
GdkCursor *cursor)
{
NSCursor *nscursor;
g_assert (GDK_IS_MACOS_DEVICE (device));
g_assert (GDK_IS_MACOS_SURFACE (surface));
g_assert (!cursor || GDK_IS_CURSOR (cursor));
nscursor = _gdk_macos_cursor_get_ns_cursor (cursor);
if (nscursor != NULL)
{
[nscursor set];
[nscursor release];
}
}
static GdkSurface *
gdk_macos_device_surface_at_position (GdkDevice *device,
gdouble *win_x,
gdouble *win_y,
GdkModifierType *state)
{
GdkMacosDisplay *display;
GdkMacosSurface *surface;
NSPoint point;
gint x;
gint y;
g_assert (GDK_IS_MACOS_DEVICE (device));
g_assert (win_x != NULL);
g_assert (win_y != NULL);
point = [NSEvent mouseLocation];
display = GDK_MACOS_DISPLAY (gdk_device_get_display (device));
if (state != NULL)
*state = (_gdk_macos_display_get_current_keyboard_modifiers (display) |
_gdk_macos_display_get_current_mouse_modifiers (display));
surface = _gdk_macos_display_get_surface_at_display_coords (display, point.x, point.y, &x, &y);
*win_x = x;
*win_y = y;
return GDK_SURFACE (surface);
}
static GdkGrabStatus
gdk_macos_device_grab (GdkDevice *device,
GdkSurface *window,
gboolean owner_events,
GdkEventMask event_mask,
GdkSurface *confine_to,
GdkCursor *cursor,
guint32 time_)
{
/* Should remain empty */
return GDK_GRAB_SUCCESS;
}
static void
gdk_macos_device_ungrab (GdkDevice *device,
guint32 time_)
{
GdkMacosDevice *self = (GdkMacosDevice *)device;
GdkDeviceGrabInfo *grab;
GdkDisplay *display;
g_assert (GDK_IS_MACOS_DEVICE (self));
display = gdk_device_get_display (device);
grab = _gdk_display_get_last_device_grab (display, device);
if (grab != NULL)
grab->serial_end = 0;
_gdk_display_device_grab_update (display, device, device, 0);
}
static void
gdk_macos_device_get_state (GdkDevice *device,
GdkSurface *surface,
gdouble *axes,
GdkModifierType *mask)
{
gdouble x_pos, y_pos;
g_assert (GDK_IS_MACOS_DEVICE (device));
g_assert (GDK_IS_MACOS_SURFACE (surface));
gdk_surface_get_device_position (surface, device, &x_pos, &y_pos, mask);
if (axes != NULL)
{
axes[0] = x_pos;
axes[1] = y_pos;
}
}
static void
gdk_macos_device_query_state (GdkDevice *device,
GdkSurface *surface,
GdkSurface **child_surface,
gdouble *win_x,
gdouble *win_y,
GdkModifierType *mask)
{
GdkDisplay *display;
NSPoint point;
int sx = 0;
int sy = 0;
int x_tmp;
int y_tmp;
g_assert (GDK_IS_MACOS_DEVICE (device));
g_assert (!surface || GDK_IS_MACOS_SURFACE (surface));
if (child_surface)
*child_surface = surface;
display = gdk_device_get_display (device);
point = [NSEvent mouseLocation];
_gdk_macos_display_from_display_coords (GDK_MACOS_DISPLAY (display),
point.x, point.y,
&x_tmp, &y_tmp);
if (surface)
_gdk_macos_surface_get_root_coords (GDK_MACOS_SURFACE (surface), &sx, &sy);
if (win_x)
*win_x = x_tmp - sx;
if (win_y)
*win_y = y_tmp - sy;
if (mask)
*mask = _gdk_macos_display_get_current_keyboard_modifiers (GDK_MACOS_DISPLAY (display)) |
_gdk_macos_display_get_current_mouse_modifiers (GDK_MACOS_DISPLAY (display));
}
static void
gdk_macos_device_class_init (GdkMacosDeviceClass *klass)
{
GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
device_class->get_state = gdk_macos_device_get_state;
device_class->grab = gdk_macos_device_grab;
device_class->query_state = gdk_macos_device_query_state;
device_class->set_surface_cursor = gdk_macos_device_set_surface_cursor;
device_class->surface_at_position = gdk_macos_device_surface_at_position;
device_class->ungrab = gdk_macos_device_ungrab;
}
static void
gdk_macos_device_init (GdkMacosDevice *self)
{
_gdk_device_add_axis (GDK_DEVICE (self), GDK_AXIS_X, 0, 0, 1);
_gdk_device_add_axis (GDK_DEVICE (self), GDK_AXIS_Y, 0, 0, 1);
}
+43
View File
@@ -0,0 +1,43 @@
/*
* Copyright © 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef __GDK_MACOS_DEVICE_H__
#define __GDK_MACOS_DEVICE_H__
#if !defined (__GDKMACOS_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/macos/gdkmacos.h> can be included directly."
#endif
#include <gdk/gdk.h>
G_BEGIN_DECLS
typedef struct _GdkMacosDevice GdkMacosDevice;
typedef struct _GdkMacosDeviceClass GdkMacosDeviceClass;
#define GDK_TYPE_MACOS_DEVICE (gdk_macos_device_get_type())
#define GDK_MACOS_DEVICE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_DEVICE, GdkMacosDevice))
#define GDK_IS_MACOS_DEVICE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_DEVICE))
GDK_AVAILABLE_IN_ALL
GType gdk_macos_device_get_type (void);
G_END_DECLS
#endif /* __GDK_MACOS_DEVICE_H__ */
+154
View File
@@ -0,0 +1,154 @@
/*
* Copyright © 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef __GDK_MACOS_DISPLAY_PRIVATE_H__
#define __GDK_MACOS_DISPLAY_PRIVATE_H__
#include <AppKit/AppKit.h>
#include "gdkdisplayprivate.h"
#include "gdkmacosdisplay.h"
#include "gdkmacoskeymap.h"
#include "gdkmacossurface.h"
G_BEGIN_DECLS
struct _GdkMacosDisplay
{
GdkDisplay parent_instance;
char *name;
GdkMacosKeymap *keymap;
/* An list of GdkMacosMonitor. The first instance is always the primary
* monitor. This contains the 0,0 coordinate in quartz coordinates, but may
* not be 0,0 in GDK coordinates.
*/
GListStore *monitors;
/* A queue of surfaces that have been made "main" so that we can update the
* main status to the next surface when a window has lost main status (such
* as when destroyed). This uses the GdkMacosSurface main link.
*/
GQueue main_surfaces;
/* A queue of surfaces sorted by their front-to-back ordering on the screen.
* This is updated occasionally when we know that the data we have cached
* has been invalidated. This uses the GdkMacosSurface.sorted link.
*/
GQueue sorted_surfaces;
/* Our CVDisplayLink based GSource which we use to freeze/thaw the
* GdkFrameClock for the surface.
*/
GSource *frame_source;
/* A queue of surfaces which we know are awaiting frames to be drawn. This
* uses the GdkMacosSurface.frame link.
*/
GQueue awaiting_frames;
/* The surface that is receiving keyboard events */
GdkMacosSurface *keyboard_surface;
/* Used to translate from quartz coordinate space to GDK */
int width;
int height;
int min_x;
int min_y;
int max_x;
int max_y;
};
struct _GdkMacosDisplayClass
{
GdkDisplayClass parent_class;
};
GdkDisplay *_gdk_macos_display_open (const gchar *display_name);
int _gdk_macos_display_get_fd (GdkMacosDisplay *self);
void _gdk_macos_display_queue_events (GdkMacosDisplay *self);
void _gdk_macos_display_to_display_coords (GdkMacosDisplay *self,
int x,
int y,
int *out_x,
int *out_y);
void _gdk_macos_display_from_display_coords (GdkMacosDisplay *self,
int x,
int y,
int *out_x,
int *out_y);
NSScreen *_gdk_macos_display_get_screen_at_display_coords (GdkMacosDisplay *self,
int x,
int y);
GdkMonitor *_gdk_macos_display_get_monitor_at_coords (GdkMacosDisplay *self,
int x,
int y);
GdkMonitor *_gdk_macos_display_get_monitor_at_display_coords (GdkMacosDisplay *self,
int x,
int y);
GdkEvent *_gdk_macos_display_translate (GdkMacosDisplay *self,
NSEvent *event);
void _gdk_macos_display_break_all_grabs (GdkMacosDisplay *self,
guint32 time);
GdkModifierType _gdk_macos_display_get_current_keyboard_modifiers (GdkMacosDisplay *self);
GdkModifierType _gdk_macos_display_get_current_mouse_modifiers (GdkMacosDisplay *self);
GdkMacosSurface *_gdk_macos_display_get_surface_at_display_coords (GdkMacosDisplay *self,
double x,
double y,
int *surface_x,
int *surface_y);
void _gdk_macos_display_reload_monitors (GdkMacosDisplay *self);
void _gdk_macos_display_surface_removed (GdkMacosDisplay *self,
GdkMacosSurface *surface);
void _gdk_macos_display_add_frame_callback (GdkMacosDisplay *self,
GdkMacosSurface *surface);
void _gdk_macos_display_remove_frame_callback (GdkMacosDisplay *self,
GdkMacosSurface *surface);
void _gdk_macos_display_synthesize_motion (GdkMacosDisplay *self,
GdkMacosSurface *surface);
NSWindow *_gdk_macos_display_find_native_under_pointer (GdkMacosDisplay *self,
int *x,
int *y);
gboolean _gdk_macos_display_get_setting (GdkMacosDisplay *self,
const gchar *setting,
GValue *value);
void _gdk_macos_display_reload_settings (GdkMacosDisplay *self);
void _gdk_macos_display_surface_resigned_main (GdkMacosDisplay *self,
GdkMacosSurface *surface);
void _gdk_macos_display_surface_became_main (GdkMacosDisplay *self,
GdkMacosSurface *surface);
void _gdk_macos_display_surface_resigned_key (GdkMacosDisplay *self,
GdkMacosSurface *surface);
void _gdk_macos_display_surface_became_key (GdkMacosDisplay *self,
GdkMacosSurface *surface);
int _gdk_macos_display_get_nominal_refresh_rate (GdkMacosDisplay *self);
void _gdk_macos_display_clear_sorting (GdkMacosDisplay *self);
const GList *_gdk_macos_display_get_surfaces (GdkMacosDisplay *self);
void _gdk_macos_display_send_button_event (GdkMacosDisplay *self,
NSEvent *nsevent);
void _gdk_macos_display_warp_pointer (GdkMacosDisplay *self,
int x,
int y);
G_END_DECLS
#endif /* __GDK_MACOS_DISPLAY_PRIVATE_H__ */
+194
View File
@@ -0,0 +1,194 @@
/*
* Copyright © 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
* Copyright © 1998-2002 Tor Lillqvist
* Copyright © 2005-2008 Imendio AB
* Copyright © 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "config.h"
#include <AppKit/AppKit.h>
#include "gdkdisplayprivate.h"
#include "gdkmacosdisplay-private.h"
#include "gdkmacosutils-private.h"
typedef struct
{
const char *font_name;
int xft_dpi;
int double_click_time;
int cursor_blink_timeout;
guint enable_animations : 1;
guint shell_shows_desktop : 1;
guint shell_shows_menubar : 1;
guint primary_button_warps_slider : 1;
} GdkMacosSettings;
static GdkMacosSettings current_settings;
static gboolean current_settings_initialized;
static void
_gdk_macos_settings_load (GdkMacosSettings *settings)
{
GDK_BEGIN_MACOS_ALLOC_POOL;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *name;
NSInteger ival;
float fval;
char *str;
int pt_size;
g_assert (settings != NULL);
settings->shell_shows_desktop = TRUE;
settings->shell_shows_menubar = TRUE;
settings->enable_animations = TRUE;
settings->xft_dpi = 72 * 1024;
ival = [defaults integerForKey:@"NSTextInsertionPointBlinkPeriod"];
if (ival > 0)
settings->cursor_blink_timeout = ival;
else
settings->cursor_blink_timeout = 1000;
settings->primary_button_warps_slider =
[[NSUserDefaults standardUserDefaults] boolForKey:@"AppleScrollerPagingBehavior"] == YES;
fval = [defaults floatForKey:@"com.apple.mouse.doubleClickThreshold"];
if (fval == 0.0)
fval = 0.5;
settings->double_click_time = fval * 1000;
name = [[NSFont systemFontOfSize:0] familyName];
pt_size = (gint)[[NSFont userFontOfSize:0] pointSize];
/* Let's try to use the "views" font size (12pt) by default. This is
* used for lists/text/other "content" which is the largest parts of
* apps, using the "regular control" size (13pt) looks a bit out of
* place. We might have to tweak this.
*
* The size has to be hardcoded as there doesn't seem to be a way to
* get the views font size programmatically.
*/
str = g_strdup_printf ("%s %d", [name UTF8String], pt_size);
settings->font_name = g_intern_string (str);
g_free (str);
GDK_END_MACOS_ALLOC_POOL;
}
gboolean
_gdk_macos_display_get_setting (GdkMacosDisplay *self,
const gchar *setting,
GValue *value)
{
GDK_BEGIN_MACOS_ALLOC_POOL;
gboolean ret = FALSE;
g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (self), FALSE);
g_return_val_if_fail (setting != NULL, FALSE);
g_return_val_if_fail (value != NULL, FALSE);
if (!current_settings_initialized)
{
_gdk_macos_settings_load (&current_settings);
current_settings_initialized = TRUE;
}
if (FALSE) {}
else if (strcmp (setting, "gtk-enable-animations") == 0)
{
g_value_set_boolean (value, current_settings.enable_animations);
ret = TRUE;
}
else if (strcmp (setting, "gtk-xft-dpi") == 0)
{
g_value_set_int (value, current_settings.xft_dpi);
ret = TRUE;
}
else if (strcmp (setting, "gtk-cursor-blink-timeout") == 0)
{
g_value_set_int (value, current_settings.cursor_blink_timeout);
ret = TRUE;
}
else if (strcmp (setting, "gtk-double-click-time") == 0)
{
g_value_set_int (value, current_settings.double_click_time);
ret = TRUE;
}
else if (strcmp (setting, "gtk-font-name") == 0)
{
g_value_set_static_string (value, current_settings.font_name);
ret = TRUE;
}
else if (strcmp (setting, "gtk-primary-button-warps-slider") == 0)
{
g_value_set_boolean (value, current_settings.primary_button_warps_slider);
ret = TRUE;
}
else if (strcmp (setting, "gtk-shell-shows-desktop") == 0)
{
g_value_set_boolean (value, current_settings.shell_shows_desktop);
ret = TRUE;
}
else if (strcmp (setting, "gtk-shell-shows-menubar") == 0)
{
g_value_set_boolean (value, current_settings.shell_shows_menubar);
ret = TRUE;
}
GDK_END_MACOS_ALLOC_POOL;
return ret;
}
void
_gdk_macos_display_reload_settings (GdkMacosDisplay *self)
{
GdkMacosSettings old_settings;
g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
old_settings = current_settings;
_gdk_macos_settings_load (&current_settings);
current_settings_initialized = TRUE;
if (old_settings.xft_dpi != current_settings.xft_dpi)
gdk_display_setting_changed (GDK_DISPLAY (self), "gtk-xft-dpi");
if (old_settings.double_click_time != current_settings.double_click_time)
gdk_display_setting_changed (GDK_DISPLAY (self), "gtk-double-click-time");
if (old_settings.enable_animations != current_settings.enable_animations)
gdk_display_setting_changed (GDK_DISPLAY (self), "gtk-enable-animations");
if (old_settings.font_name != current_settings.font_name)
gdk_display_setting_changed (GDK_DISPLAY (self), "gtk-font-name");
if (old_settings.primary_button_warps_slider != current_settings.primary_button_warps_slider)
gdk_display_setting_changed (GDK_DISPLAY (self), "gtk-primary-button-warps-slider");
if (old_settings.shell_shows_menubar != current_settings.shell_shows_menubar)
gdk_display_setting_changed (GDK_DISPLAY (self), "gtk-shell-shows-menubar");
if (old_settings.shell_shows_desktop != current_settings.shell_shows_desktop)
gdk_display_setting_changed (GDK_DISPLAY (self), "gtk-shell-shows-desktop");
}
File diff suppressed because it is too large Load Diff

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