Compare commits

..

94 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
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 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
179 changed files with 21746 additions and 17791 deletions
+1 -1
View File
@@ -184,7 +184,7 @@ static-scan:
# since it is incompatible with asan
asan-build:
image: $FEDORA_IMAGE
tags: [ privileged ]
tags: [ asan ]
stage: analysis
variables:
script:
+10 -1
View File
@@ -1,7 +1,7 @@
Overview of Changes in GTK 3.99.0
=================================
* Add GtkEditableLabel
* Add GtkEditableLabel, a label that can be edited
* Add GtkBookmarkList, a list model for bookmarks
@@ -36,6 +36,14 @@ Overview of Changes in GTK 3.99.0
* 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
@@ -49,6 +57,7 @@ Overview of Changes in GTK 3.99.0
- Keep a scroll history
- Clean up GdkDevice api
- Improve frame clock accuracy
- Add a new macOS backend
* GSK:
- Use GL_ARB_framebuffer_object
+243 -28
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>
@@ -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))
+40 -22
View File
@@ -662,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);
@@ -676,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;
}
@@ -835,6 +827,22 @@ update_selection_average (GListModel *model,
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 *
@@ -842,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;
@@ -863,6 +872,7 @@ do_listview_colors (GtkWidget *do_widget)
GtkWidget *selection_average_picture;
GtkWidget *selection_info_toggle;
GtkWidget *selection_info_revealer;
GtkWidget *progress;
GtkCssProvider *provider;
provider = gtk_css_provider_new ();
@@ -872,6 +882,10 @@ do_listview_colors (GtkWidget *do_widget)
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 ();
@@ -882,8 +896,17 @@ 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_window_set_child (GTK_WINDOW (window), box);
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);
@@ -936,12 +959,12 @@ do_listview_colors (GtkWidget *do_widget)
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);
gtk_widget_set_hexpand (sw, TRUE);
gtk_widget_set_vexpand (sw, TRUE);
model = gtk_grid_view_get_model (GTK_GRID_VIEW (gridview));
selection_filter = G_LIST_MODEL (gtk_selection_filter_model_new (GTK_SELECTION_MODEL (model)));
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);
@@ -950,9 +973,6 @@ do_listview_colors (GtkWidget *do_widget)
g_object_unref (selection_filter);
g_object_unref (no_selection);
model = gtk_multi_selection_get_model (GTK_MULTI_SELECTION (model));
g_object_ref (model);
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");
@@ -965,7 +985,7 @@ do_listview_colors (GtkWidget *do_widget)
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);
@@ -980,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);
@@ -1080,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);
@@ -1112,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))
+1 -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,6 +46,7 @@ demos = files([
'listview_colors.c',
'listview_filebrowser.c',
'listview_minesweeper.c',
'dropdown.c',
'listview_settings.c',
'listview_weather.c',
'listview_words.c',
@@ -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):
+1
View File
@@ -223,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">
+27
View File
@@ -2832,6 +2832,9 @@ 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
@@ -7638,3 +7641,27 @@ 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>
+1
View File
@@ -220,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
+55 -2
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
@@ -531,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
+28
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
@@ -198,4 +224,6 @@ transitioning code for easy lookup:
| #GtkCellLayout | #GtkListItemFactory |
| #GtkCellArea | #GtkWidget |
| #GtkCellRenderer | #GtkWidget |
| #GtkComboBoxText | #GtkSuggestionEntry |
| #GtkEntryCompletion | #GtkSuggestionEntry |
+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
+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
File diff suppressed because it is too large Load Diff
+47
View File
@@ -0,0 +1,47 @@
/*
* 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_H__
#define __GDK_MACOS_DISPLAY_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
#ifdef GTK_COMPILATION
typedef struct _GdkMacosDisplay GdkMacosDisplay;
#else
typedef GdkDisplay GdkMacosDisplay;
#endif
typedef struct _GdkMacosDisplayClass GdkMacosDisplayClass;
#define GDK_TYPE_MACOS_DISPLAY (gdk_macos_display_get_type())
#define GDK_MACOS_DISPLAY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_DISPLAY, GdkMacosDisplay))
#define GDK_IS_MACOS_DISPLAY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_DISPLAY))
GDK_AVAILABLE_IN_ALL
GType gdk_macos_display_get_type (void);
G_END_DECLS
#endif /* __GDK_MACOS_DISPLAY_H__ */
+70
View File
@@ -0,0 +1,70 @@
/*
* 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_DRAG_PRIVATE_H__
#define __GDK_MACOS_DRAG_PRIVATE_H__
#include "gdkdragprivate.h"
#include "gdkmacosdragsurface-private.h"
G_BEGIN_DECLS
#define GDK_TYPE_MACOS_DRAG (gdk_macos_drag_get_type ())
#define GDK_MACOS_DRAG(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_DRAG, GdkMacosDrag))
#define GDK_MACOS_DRAG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_MACOS_DRAG, GdkMacosDragClass))
#define GDK_IS_MACOS_DRAG(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_DRAG))
#define GDK_IS_MACOS_DRAG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_MACOS_DRAG))
#define GDK_MACOS_DRAG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_MACOS_DRAG, GdkMacosDragClass))
typedef struct _GdkMacosDrag GdkMacosDrag;
typedef struct _GdkMacosDragClass GdkMacosDragClass;
struct _GdkMacosDrag
{
GdkDrag parent_instance;
GdkMacosDragSurface *drag_surface;
GdkSeat *drag_seat;
GdkCursor *cursor;
int hot_x;
int hot_y;
int last_x;
int last_y;
int start_x;
int start_y;
guint did_update : 1;
guint cancelled : 1;
};
struct _GdkMacosDragClass
{
GdkDragClass parent_class;
};
GType gdk_macos_drag_get_type (void) G_GNUC_CONST;
gboolean _gdk_macos_drag_begin (GdkMacosDrag *self);
G_END_DECLS
#endif /* __GDK_MACOS_DRAG_PRIVATE_H__ */
+617
View File
@@ -0,0 +1,617 @@
/*
* 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 "gdkdeviceprivate.h"
#include "gdkintl.h"
#include "gdkmacoscursor-private.h"
#include "gdkmacosdisplay-private.h"
#include "gdkmacosdrag-private.h"
#include "gdkmacosdragsurface-private.h"
#define BIG_STEP 20
#define SMALL_STEP 1
#define ANIM_TIME 500000 /* .5 seconds */
typedef struct
{
GdkMacosDrag *drag;
GdkFrameClock *frame_clock;
gint64 start_time;
} GdkMacosZoomback;
G_DEFINE_TYPE (GdkMacosDrag, gdk_macos_drag, GDK_TYPE_DRAG)
enum {
PROP_0,
PROP_DRAG_SURFACE,
N_PROPS
};
static GParamSpec *properties [N_PROPS];
static double
ease_out_cubic (double t)
{
double p = t - 1;
return p * p * p + 1;
}
static void
gdk_macos_zoomback_destroy (GdkMacosZoomback *zb)
{
gdk_surface_hide (GDK_SURFACE (zb->drag->drag_surface));
g_clear_object (&zb->drag);
g_slice_free (GdkMacosZoomback, zb);
}
static gboolean
gdk_macos_zoomback_timeout (gpointer data)
{
GdkMacosZoomback *zb = data;
GdkFrameClock *frame_clock;
GdkMacosDrag *drag;
gint64 current_time;
double f;
double t;
g_assert (zb != NULL);
g_assert (GDK_IS_MACOS_DRAG (zb->drag));
drag = zb->drag;
frame_clock = zb->frame_clock;
if (!frame_clock)
return G_SOURCE_REMOVE;
current_time = gdk_frame_clock_get_frame_time (frame_clock);
f = (current_time - zb->start_time) / (double) ANIM_TIME;
if (f >= 1.0)
return G_SOURCE_REMOVE;
t = ease_out_cubic (f);
_gdk_macos_surface_move (GDK_MACOS_SURFACE (drag->drag_surface),
(drag->last_x - drag->hot_x) +
(drag->start_x - drag->last_x) * t,
(drag->last_y - drag->hot_y) +
(drag->start_y - drag->last_y) * t);
_gdk_macos_surface_set_opacity (GDK_MACOS_SURFACE (drag->drag_surface), 1.0 - f);
/* Make sure we're topmost */
_gdk_macos_surface_show (GDK_MACOS_SURFACE (drag->drag_surface));
return G_SOURCE_CONTINUE;
}
static GdkSurface *
gdk_macos_drag_get_drag_surface (GdkDrag *drag)
{
return GDK_SURFACE (GDK_MACOS_DRAG (drag)->drag_surface);
}
static void
gdk_macos_drag_set_hotspot (GdkDrag *drag,
int hot_x,
int hot_y)
{
GdkMacosDrag *self = (GdkMacosDrag *)drag;
int change_x;
int change_y;
g_assert (GDK_IS_MACOS_DRAG (self));
change_x = hot_x - self->hot_x;
change_y = hot_y - self->hot_y;
self->hot_x = hot_x;
self->hot_y = hot_y;
if (change_x || change_y)
_gdk_macos_surface_move (GDK_MACOS_SURFACE (self->drag_surface),
GDK_SURFACE (self->drag_surface)->x + change_x,
GDK_SURFACE (self->drag_surface)->y + change_y);
}
static void
gdk_macos_drag_drop_done (GdkDrag *drag,
gboolean success)
{
GdkMacosDrag *self = (GdkMacosDrag *)drag;
GdkMacosZoomback *zb;
guint id;
g_assert (GDK_IS_MACOS_DRAG (self));
if (success)
{
gdk_surface_hide (GDK_SURFACE (self->drag_surface));
g_object_unref (drag);
return;
}
/* Apple HIG suggests doing a "zoomback" animation of the surface back
* towards the original position.
*/
zb = g_slice_new0 (GdkMacosZoomback);
zb->drag = g_object_ref (self);
zb->frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self->drag_surface));
zb->start_time = gdk_frame_clock_get_frame_time (zb->frame_clock);
id = g_timeout_add_full (G_PRIORITY_DEFAULT, 17,
gdk_macos_zoomback_timeout,
zb,
(GDestroyNotify) gdk_macos_zoomback_destroy);
g_source_set_name_by_id (id, "[gtk] gdk_macos_zoomback_timeout");
g_object_unref (drag);
}
static void
gdk_macos_drag_set_cursor (GdkDrag *drag,
GdkCursor *cursor)
{
GdkMacosDrag *self = (GdkMacosDrag *)drag;
NSCursor *nscursor;
g_assert (GDK_IS_MACOS_DRAG (self));
g_assert (!cursor || GDK_IS_CURSOR (cursor));
g_set_object (&self->cursor, cursor);
nscursor = _gdk_macos_cursor_get_ns_cursor (cursor);
if (nscursor != NULL)
[nscursor set];
}
static gboolean
drag_grab (GdkMacosDrag *self)
{
GdkSeat *seat;
g_assert (GDK_IS_MACOS_DRAG (self));
seat = gdk_device_get_seat (gdk_drag_get_device (GDK_DRAG (self)));
if (gdk_seat_grab (seat,
GDK_SURFACE (self->drag_surface),
GDK_SEAT_CAPABILITY_ALL_POINTING,
FALSE,
self->cursor,
NULL,
NULL,
NULL) != GDK_GRAB_SUCCESS)
return FALSE;
g_set_object (&self->drag_seat, seat);
return TRUE;
}
static void
drag_ungrab (GdkMacosDrag *self)
{
GdkDisplay *display;
g_assert (GDK_IS_MACOS_DRAG (self));
display = gdk_drag_get_display (GDK_DRAG (self));
_gdk_macos_display_break_all_grabs (GDK_MACOS_DISPLAY (display), GDK_CURRENT_TIME);
}
static void
gdk_macos_drag_cancel (GdkDrag *drag,
GdkDragCancelReason reason)
{
GdkMacosDrag *self = (GdkMacosDrag *)drag;
g_assert (GDK_IS_MACOS_DRAG (self));
if (self->cancelled)
return;
self->cancelled = TRUE;
drag_ungrab (self);
gdk_drag_drop_done (drag, FALSE);
}
static void
gdk_macos_drag_drop_performed (GdkDrag *drag,
guint32 time)
{
GdkMacosDrag *self = (GdkMacosDrag *)drag;
g_assert (GDK_IS_MACOS_DRAG (self));
drag_ungrab (self);
g_signal_emit_by_name (drag, "dnd-finished");
gdk_drag_drop_done (drag, TRUE);
}
static void
gdk_drag_get_current_actions (GdkModifierType state,
gint button,
GdkDragAction actions,
GdkDragAction *suggested_action,
GdkDragAction *possible_actions)
{
*suggested_action = 0;
*possible_actions = 0;
if ((button == GDK_BUTTON_MIDDLE || button == GDK_BUTTON_SECONDARY) && (actions & GDK_ACTION_ASK))
{
*suggested_action = GDK_ACTION_ASK;
*possible_actions = actions;
}
else if (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))
{
if ((state & GDK_SHIFT_MASK) && (state & GDK_CONTROL_MASK))
{
if (actions & GDK_ACTION_LINK)
{
*suggested_action = GDK_ACTION_LINK;
*possible_actions = GDK_ACTION_LINK;
}
}
else if (state & GDK_CONTROL_MASK)
{
if (actions & GDK_ACTION_COPY)
{
*suggested_action = GDK_ACTION_COPY;
*possible_actions = GDK_ACTION_COPY;
}
}
else
{
if (actions & GDK_ACTION_MOVE)
{
*suggested_action = GDK_ACTION_MOVE;
*possible_actions = GDK_ACTION_MOVE;
}
}
}
else
{
*possible_actions = actions;
if ((state & (GDK_ALT_MASK)) && (actions & GDK_ACTION_ASK))
*suggested_action = GDK_ACTION_ASK;
else if (actions & GDK_ACTION_COPY)
*suggested_action = GDK_ACTION_COPY;
else if (actions & GDK_ACTION_MOVE)
*suggested_action = GDK_ACTION_MOVE;
else if (actions & GDK_ACTION_LINK)
*suggested_action = GDK_ACTION_LINK;
}
}
static void
gdk_drag_update (GdkDrag *drag,
gdouble x_root,
gdouble y_root,
GdkModifierType mods,
guint32 evtime)
{
GdkMacosDrag *self = (GdkMacosDrag *)drag;
GdkDragAction suggested_action;
GdkDragAction possible_actions;
g_assert (GDK_IS_MACOS_DRAG (self));
self->last_x = x_root;
self->last_y = y_root;
gdk_drag_get_current_actions (mods,
GDK_BUTTON_PRIMARY,
gdk_drag_get_actions (drag),
&suggested_action,
&possible_actions);
_gdk_macos_drag_surface_drag_motion (self->drag_surface,
x_root - self->hot_x,
y_root - self->hot_y,
suggested_action,
possible_actions,
evtime);
if (!self->did_update)
{
self->start_x = self->last_x;
self->start_y = self->last_y;
self->did_update = TRUE;
}
}
static gboolean
gdk_dnd_handle_motion_event (GdkDrag *drag,
GdkEvent *event)
{
double x, y;
int x_root, y_root;
g_assert (GDK_IS_MACOS_DRAG (drag));
g_assert (event != NULL);
/* Ignore motion while doing zoomback */
if (GDK_MACOS_DRAG (drag)->cancelled)
return FALSE;
gdk_event_get_position (event, &x, &y);
x_root = event->surface->x + x;
y_root = event->surface->y + y;
gdk_drag_update (drag, x_root, y_root,
gdk_event_get_modifier_state (event),
gdk_event_get_time (event));
return TRUE;
}
static gboolean
gdk_dnd_handle_grab_broken_event (GdkDrag *drag,
GdkEvent *event)
{
GdkMacosDrag *self = GDK_MACOS_DRAG (drag);
gboolean is_implicit = gdk_grab_broken_event_get_implicit (event);
GdkSurface *grab_surface = gdk_grab_broken_event_get_grab_surface (event);
/* Don't cancel if we break the implicit grab from the initial button_press. */
if (is_implicit || grab_surface == (GdkSurface *)self->drag_surface)
return FALSE;
if (gdk_event_get_device (event) != gdk_drag_get_device (drag))
return FALSE;
gdk_drag_cancel (drag, GDK_DRAG_CANCEL_ERROR);
return TRUE;
}
static gboolean
gdk_dnd_handle_button_event (GdkDrag *drag,
GdkEvent *event)
{
GdkMacosDrag *self = GDK_MACOS_DRAG (drag);
g_assert (GDK_IS_MACOS_DRAG (self));
g_assert (event != NULL);
#if 0
/* FIXME: Check the button matches */
if (event->button != self->button)
return FALSE;
#endif
if (gdk_drag_get_selected_action (drag) != 0)
g_signal_emit_by_name (drag, "drop-performed");
else
gdk_drag_cancel (drag, GDK_DRAG_CANCEL_NO_TARGET);
return TRUE;
}
static gboolean
gdk_dnd_handle_key_event (GdkDrag *drag,
GdkEvent *event)
{
GdkMacosDrag *self = GDK_MACOS_DRAG (drag);
GdkModifierType state;
GdkDevice *pointer;
gint dx, dy;
dx = dy = 0;
state = gdk_event_get_modifier_state (event);
pointer = gdk_device_get_associated_device (gdk_event_get_device (event));
if (event->event_type == GDK_KEY_PRESS)
{
guint keyval = gdk_key_event_get_keyval (event);
switch (keyval)
{
case GDK_KEY_Escape:
gdk_drag_cancel (drag, GDK_DRAG_CANCEL_USER_CANCELLED);
return TRUE;
case GDK_KEY_space:
case GDK_KEY_Return:
case GDK_KEY_ISO_Enter:
case GDK_KEY_KP_Enter:
case GDK_KEY_KP_Space:
if (gdk_drag_get_selected_action (drag) != 0)
g_signal_emit_by_name (drag, "drop-performed");
else
gdk_drag_cancel (drag, GDK_DRAG_CANCEL_NO_TARGET);
return TRUE;
case GDK_KEY_Up:
case GDK_KEY_KP_Up:
dy = (state & GDK_ALT_MASK) ? -BIG_STEP : -SMALL_STEP;
break;
case GDK_KEY_Down:
case GDK_KEY_KP_Down:
dy = (state & GDK_ALT_MASK) ? BIG_STEP : SMALL_STEP;
break;
case GDK_KEY_Left:
case GDK_KEY_KP_Left:
dx = (state & GDK_ALT_MASK) ? -BIG_STEP : -SMALL_STEP;
break;
case GDK_KEY_Right:
case GDK_KEY_KP_Right:
dx = (state & GDK_ALT_MASK) ? BIG_STEP : SMALL_STEP;
break;
default:
break;
}
}
/* The state is not yet updated in the event, so we need
* to query it here. We could use XGetModifierMapping, but
* that would be overkill.
*/
_gdk_device_query_state (pointer, NULL, NULL, NULL, NULL, &state);
if (dx != 0 || dy != 0)
{
GdkDisplay *display = gdk_event_get_display ((GdkEvent *)event);
self->last_x += dx;
self->last_y += dy;
_gdk_macos_display_warp_pointer (GDK_MACOS_DISPLAY (display),
self->last_x,
self->last_y);
}
gdk_drag_update (drag,
self->last_x, self->last_y,
state,
gdk_event_get_time (event));
return TRUE;
}
static gboolean
gdk_macos_drag_handle_event (GdkDrag *drag,
GdkEvent *event)
{
g_assert (GDK_IS_MACOS_DRAG (drag));
g_assert (event != NULL);
switch ((guint) event->event_type)
{
case GDK_MOTION_NOTIFY:
return gdk_dnd_handle_motion_event (drag, event);
case GDK_BUTTON_RELEASE:
return gdk_dnd_handle_button_event (drag, event);
case GDK_KEY_PRESS:
case GDK_KEY_RELEASE:
return gdk_dnd_handle_key_event (drag, event);
case GDK_GRAB_BROKEN:
return gdk_dnd_handle_grab_broken_event (drag, event);
default:
return FALSE;
}
}
static void
gdk_macos_drag_finalize (GObject *object)
{
GdkMacosDrag *self = (GdkMacosDrag *)object;
GdkMacosDragSurface *drag_surface = g_steal_pointer (&self->drag_surface);
g_clear_object (&self->cursor);
g_clear_object (&self->drag_seat);
G_OBJECT_CLASS (gdk_macos_drag_parent_class)->finalize (object);
if (drag_surface)
gdk_surface_destroy (GDK_SURFACE (drag_surface));
}
static void
gdk_macos_drag_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdkMacosDrag *self = GDK_MACOS_DRAG (object);
switch (prop_id)
{
case PROP_DRAG_SURFACE:
g_value_set_object (value, self->drag_surface);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gdk_macos_drag_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GdkMacosDrag *self = GDK_MACOS_DRAG (object);
switch (prop_id)
{
case PROP_DRAG_SURFACE:
self->drag_surface = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gdk_macos_drag_class_init (GdkMacosDragClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdkDragClass *drag_class = GDK_DRAG_CLASS (klass);
object_class->finalize = gdk_macos_drag_finalize;
object_class->get_property = gdk_macos_drag_get_property;
object_class->set_property = gdk_macos_drag_set_property;
drag_class->get_drag_surface = gdk_macos_drag_get_drag_surface;
drag_class->set_hotspot = gdk_macos_drag_set_hotspot;
drag_class->drop_done = gdk_macos_drag_drop_done;
drag_class->set_cursor = gdk_macos_drag_set_cursor;
drag_class->cancel = gdk_macos_drag_cancel;
drag_class->drop_performed = gdk_macos_drag_drop_performed;
drag_class->handle_event = gdk_macos_drag_handle_event;
properties [PROP_DRAG_SURFACE] =
g_param_spec_object ("drag-surface",
P_("Drag Surface"),
P_("Drag Surface"),
GDK_TYPE_MACOS_DRAG_SURFACE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
gdk_macos_drag_init (GdkMacosDrag *self)
{
}
gboolean
_gdk_macos_drag_begin (GdkMacosDrag *self)
{
g_return_val_if_fail (GDK_IS_MACOS_DRAG (self), FALSE);
_gdk_macos_surface_show (GDK_MACOS_SURFACE (self->drag_surface));
return drag_grab (self);
}
+50
View File
@@ -0,0 +1,50 @@
/*
* 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_DRAG_SURFACE_PRIVATE_H__
#define __GDK_MACOS_DRAG_SURFACE_PRIVATE_H__
#include "gdkmacossurface-private.h"
G_BEGIN_DECLS
typedef struct _GdkMacosDragSurface GdkMacosDragSurface;
typedef struct _GdkMacosDragSurfaceClass GdkMacosDragSurfaceClass;
#define GDK_TYPE_MACOS_DRAG_SURFACE (_gdk_macos_drag_surface_get_type())
#define GDK_MACOS_DRAG_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_DRAG_SURFACE, GdkMacosDragSurface))
#define GDK_IS_MACOS_DRAG_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_DRAG_SURFACE))
GType _gdk_macos_drag_surface_get_type (void);
GdkMacosSurface *_gdk_macos_drag_surface_new (GdkMacosDisplay *display,
GdkFrameClock *frame_clock,
int x,
int y,
int width,
int height);
void _gdk_macos_drag_surface_drag_motion (GdkMacosDragSurface *self,
int x_root,
int y_root,
GdkDragAction suggested_action,
GdkDragAction possible_actions,
guint32 evtime);
G_END_DECLS
#endif /* __GDK_MACOS_DRAG_SURFACE_PRIVATE_H__ */
+138
View File
@@ -0,0 +1,138 @@
/*
* 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 "gdkdragsurfaceprivate.h"
#include "gdkmacosdragsurface-private.h"
#include "gdkmacosdisplay-private.h"
#include "gdkmacosutils-private.h"
struct _GdkMacosDragSurface
{
GdkMacosSurface parent_instance;
};
struct _GdkMacosDragSurfaceClass
{
GdkMacosSurfaceClass parent_instance;
};
static gboolean
_gdk_macos_drag_surface_present (GdkDragSurface *surface,
int width,
int height)
{
g_assert (GDK_IS_MACOS_SURFACE (surface));
_gdk_macos_surface_move_resize (GDK_MACOS_SURFACE (surface),
-1, -1,
width, height);
if (!GDK_SURFACE_IS_MAPPED (GDK_SURFACE (surface)))
_gdk_macos_surface_show (GDK_MACOS_SURFACE (surface));
return GDK_SURFACE_IS_MAPPED (GDK_SURFACE (surface));
}
static void
drag_surface_iface_init (GdkDragSurfaceInterface *iface)
{
iface->present = _gdk_macos_drag_surface_present;
}
G_DEFINE_TYPE_WITH_CODE (GdkMacosDragSurface, _gdk_macos_drag_surface, GDK_TYPE_MACOS_SURFACE,
G_IMPLEMENT_INTERFACE (GDK_TYPE_DRAG_SURFACE, drag_surface_iface_init))
static void
_gdk_macos_drag_surface_class_init (GdkMacosDragSurfaceClass *klass)
{
}
static void
_gdk_macos_drag_surface_init (GdkMacosDragSurface *self)
{
}
GdkMacosSurface *
_gdk_macos_drag_surface_new (GdkMacosDisplay *display,
GdkFrameClock *frame_clock,
int x,
int y,
int width,
int height)
{
GDK_BEGIN_MACOS_ALLOC_POOL;
GdkMacosWindow *window;
GdkMacosSurface *self;
NSScreen *screen;
NSUInteger style_mask;
NSRect content_rect;
NSRect screen_rect;
int nx;
int ny;
g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
g_return_val_if_fail (!frame_clock || GDK_IS_FRAME_CLOCK (frame_clock), NULL);
style_mask = NSWindowStyleMaskBorderless;
_gdk_macos_display_to_display_coords (display, x, y, &nx, &ny);
screen = _gdk_macos_display_get_screen_at_display_coords (display, nx, ny);
screen_rect = [screen frame];
nx -= screen_rect.origin.x;
ny -= screen_rect.origin.y;
content_rect = NSMakeRect (nx, ny - height, width, height);
window = [[GdkMacosWindow alloc] initWithContentRect:content_rect
styleMask:style_mask
backing:NSBackingStoreBuffered
defer:NO
screen:screen];
[window setOpaque:NO];
[window setBackgroundColor:[NSColor clearColor]];
[window setDecorated:NO];
self = g_object_new (GDK_TYPE_MACOS_DRAG_SURFACE,
"display", display,
"frame-clock", frame_clock,
"native", window,
NULL);
GDK_END_MACOS_ALLOC_POOL;
return g_steal_pointer (&self);
}
void
_gdk_macos_drag_surface_drag_motion (GdkMacosDragSurface *self,
int x_root,
int y_root,
GdkDragAction suggested_action,
GdkDragAction possible_actions,
guint32 evtime)
{
g_return_if_fail (GDK_IS_MACOS_DRAG_SURFACE (self));
_gdk_macos_surface_move (GDK_MACOS_SURFACE (self), x_root, y_root);
}
+40
View File
@@ -0,0 +1,40 @@
/*
* 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_EVENT_SOURCE_PRIVATE_H__
#define __GDK_MACOS_EVENT_SOURCE_PRIVATE_H__
#include <AppKit/AppKit.h>
#include "gdkmacosdisplay.h"
G_BEGIN_DECLS
typedef enum
{
GDK_MACOS_EVENT_SUBTYPE_EVENTLOOP,
} GdkMacosEventSubType;
GSource *_gdk_macos_event_source_new (GdkMacosDisplay *display);
NSEvent *_gdk_macos_event_source_get_pending (void);
gboolean _gdk_macos_event_source_check_pending (void);
G_END_DECLS
#endif /* __GDK_MACOS_EVENT_SOURCE_PRIVATE_H__ */
@@ -1,3 +1,23 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
* Copyright (C) 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 <glib.h>
@@ -6,10 +26,13 @@
#include <sys/uio.h>
#include <unistd.h>
#include "gdkprivate-quartz.h"
#include <gdk/gdkdisplayprivate.h>
#include "gdkdisplayprivate.h"
#include "gdkinternals.h"
/*
#include "gdkmacoseventsource-private.h"
#include "gdkmacosdisplay-private.h"
/*
* This file implementations integration between the GLib main loop and
* the native system of the Core Foundation run loop and Cocoa event
* handling. There are basically two different cases that we need to
@@ -55,16 +78,16 @@ static int current_loop_level = 0;
/* Run loop level at which we acquired ownership of the GLib main
* loop. See note in run_loop_entry(). -1 means that we dont have
* ownership
*/
*/
static int acquired_loop_level = -1;
/* Between run_loop_before_waiting() and run_loop_after_waiting();
* whether we need to call select_thread_collect_poll()
* whether we we need to call select_thread_collect_poll()
*/
static gboolean run_loop_polling_async = FALSE;
/* Between run_loop_before_waiting() and run_loop_after_waiting();
* max_priority to pass to g_main_loop_check()
* max_prioritiy to pass to g_main_loop_check()
*/
static gint run_loop_max_priority;
@@ -95,7 +118,7 @@ static GPollFD event_poll_fd;
/* Current NSEvents that we've gotten from Cocoa but haven't yet converted
* to GdkEvents. We wait until our dispatch() function to do the conversion
* since the conversion can conceivably cause signals to be emitted
* since the conversion can conceivably cause signals to be emmitted
* or other things that shouldnt happen inside a poll function.
*/
static GQueue *current_events;
@@ -132,7 +155,7 @@ static gint getting_events = 0;
************************************************************/
/* The states in our state machine, see comments in select_thread_func()
* for descriptions of each state
* for descriptiions of each state
*/
typedef enum {
BEFORE_START,
@@ -220,93 +243,93 @@ static void *
select_thread_func (void *arg)
{
char c;
SELECT_THREAD_LOCK ();
while (TRUE)
{
switch (select_thread_state)
{
case BEFORE_START:
/* The select thread has not been started yet
*/
g_assert_not_reached ();
case WAITING:
/* Waiting for a set of file descriptors to be submitted by the main thread
*
* => POLLING_QUEUED: main thread submits a set of file descriptors
*/
SELECT_THREAD_WAIT ();
break;
case POLLING_QUEUED:
/* Waiting for a set of file descriptors to be submitted by the main thread
*
* => POLLING_DESCRIPTORS: select thread picks up the file descriptors to begin polling
*/
g_free (current_pollfds);
current_pollfds = next_pollfds;
current_n_pollfds = next_n_pollfds;
{
case BEFORE_START:
/* The select thread has not been started yet
*/
g_assert_not_reached ();
next_pollfds = NULL;
next_n_pollfds = 0;
case WAITING:
/* Waiting for a set of file descriptors to be submitted by the main thread
*
* => POLLING_QUEUED: main thread thread submits a set of file descriptors
*/
SELECT_THREAD_WAIT ();
break;
select_thread_set_state (POLLING_DESCRIPTORS);
break;
case POLLING_RESTART:
/* Select thread is currently polling a set of file descriptors, main thread has
* began a new iteration with the same set of file descriptors. We don't want to
* wake the select thread up and wait for it to restart immediately, but to avoid
* a race (described below in select_thread_start_polling()) we need to recheck after
* polling completes.
*
* => POLLING_DESCRIPTORS: select completes, main thread rechecks by polling again
* => POLLING_QUEUED: main thread submits a new set of file descriptors to be polled
*/
select_thread_set_state (POLLING_DESCRIPTORS);
break;
case POLLING_QUEUED:
/* Waiting for a set of file descriptors to be submitted by the main thread
*
* => POLLING_DESCRIPTORS: select thread picks up the file descriptors to begin polling
*/
g_free (current_pollfds);
case POLLING_DESCRIPTORS:
/* In the process of polling the file descriptors
*
* => WAITING: polling completes when a file descriptor becomes active
* => POLLING_QUEUED: main thread submits a new set of file descriptors to be polled
* => POLLING_RESTART: main thread begins a new iteration with the same set file descriptors
*/
SELECT_THREAD_UNLOCK ();
old_poll_func (current_pollfds, current_n_pollfds, -1);
SELECT_THREAD_LOCK ();
current_pollfds = next_pollfds;
current_n_pollfds = next_n_pollfds;
read (select_thread_wakeup_pipe[0], &c, 1);
next_pollfds = NULL;
next_n_pollfds = 0;
if (select_thread_state == POLLING_DESCRIPTORS)
{
signal_main_thread ();
select_thread_set_state (WAITING);
}
break;
}
select_thread_set_state (POLLING_DESCRIPTORS);
break;
case POLLING_RESTART:
/* Select thread is currently polling a set of file descriptors, main thread has
* began a new iteration with the same set of file descriptors. We don't want to
* wake the select thread up and wait for it to restart immediately, but to avoid
* a race (described below in select_thread_start_polling()) we need to recheck after
* polling completes.
*
* => POLLING_DESCRIPTORS: select completes, main thread rechecks by polling again
* => POLLING_QUEUED: main thread submits a new set of file descriptors to be polled
*/
select_thread_set_state (POLLING_DESCRIPTORS);
break;
case POLLING_DESCRIPTORS:
/* In the process of polling the file descriptors
*
* => WAITING: polling completes when a file descriptor becomes active
* => POLLING_QUEUED: main thread submits a new set of file descriptors to be polled
* => POLLING_RESTART: main thread begins a new iteration with the same set file descriptors
*/
SELECT_THREAD_UNLOCK ();
old_poll_func (current_pollfds, current_n_pollfds, -1);
SELECT_THREAD_LOCK ();
read (select_thread_wakeup_pipe[0], &c, 1);
if (select_thread_state == POLLING_DESCRIPTORS)
{
signal_main_thread ();
select_thread_set_state (WAITING);
}
break;
}
}
}
static void
static void
got_fd_activity (void *info)
{
NSEvent *event;
/* Post a message so we'll break out of the message loop */
event = [NSEvent otherEventWithType: NSApplicationDefined
location: NSZeroPoint
modifierFlags: 0
timestamp: 0
windowNumber: 0
context: nil
subtype: GDK_QUARTZ_EVENT_SUBTYPE_EVENTLOOP
data1: 0
data2: 0];
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];
}
@@ -315,21 +338,21 @@ static void
select_thread_start (void)
{
g_return_if_fail (select_thread_state == BEFORE_START);
pipe (select_thread_wakeup_pipe);
fcntl (select_thread_wakeup_pipe[0], F_SETFL, O_NONBLOCK);
CFRunLoopSourceContext source_context = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, got_fd_activity };
select_main_thread_source = CFRunLoopSourceCreate (NULL, 0, &source_context);
CFRunLoopAddSource (main_thread_run_loop, select_main_thread_source, kCFRunLoopCommonModes);
select_thread_state = WAITING;
while (TRUE)
{
if (pthread_create (&select_thread, NULL, select_thread_func, NULL) == 0)
break;
break;
g_warning ("Failed to create select thread, sleeping and trying again");
sleep (1);
@@ -339,7 +362,7 @@ select_thread_start (void)
#ifdef G_ENABLE_DEBUG
static void
dump_poll_result (GPollFD *ufds,
guint nfds)
guint nfds)
{
GString *s;
gint i;
@@ -348,44 +371,44 @@ dump_poll_result (GPollFD *ufds,
for (i = 0; i < nfds; i++)
{
if (ufds[i].fd >= 0 && ufds[i].revents)
{
{
g_string_append_printf (s, " %d:", ufds[i].fd);
if (ufds[i].revents & G_IO_IN)
if (ufds[i].revents & G_IO_IN)
g_string_append (s, " in");
if (ufds[i].revents & G_IO_OUT)
g_string_append (s, " out");
if (ufds[i].revents & G_IO_PRI)
g_string_append (s, " pri");
g_string_append (s, "\n");
}
if (ufds[i].revents & G_IO_OUT)
g_string_append (s, " out");
if (ufds[i].revents & G_IO_PRI)
g_string_append (s, " pri");
g_string_append (s, "\n");
}
}
g_message ("%s", s->str);
g_string_free (s, TRUE);
}
#endif
gboolean
static gboolean
pollfds_equal (GPollFD *old_pollfds,
guint old_n_pollfds,
GPollFD *new_pollfds,
guint new_n_pollfds)
guint old_n_pollfds,
GPollFD *new_pollfds,
guint new_n_pollfds)
{
gint i;
if (old_n_pollfds != new_n_pollfds)
return FALSE;
for (i = 0; i < old_n_pollfds; i++)
{
if (old_pollfds[i].fd != new_pollfds[i].fd ||
old_pollfds[i].events != new_pollfds[i].events)
return FALSE;
old_pollfds[i].events != new_pollfds[i].events)
return FALSE;
}
return TRUE;
}
/* Begins a polling operation with the specified GPollFD array; the
/* Begins a polling operation with the specified GPollFD array; the
* timeout is used only to tell if the polling operation is blocking
* or non-blocking.
*
@@ -396,7 +419,8 @@ pollfds_equal (GPollFD *old_pollfds,
*/
static gint
select_thread_start_poll (GPollFD *ufds,
guint nfds, gint timeout)
guint nfds,
gint timeout)
{
gint n_ready;
gboolean have_new_pollfds = FALSE;
@@ -406,10 +430,10 @@ select_thread_start_poll (GPollFD *ufds,
for (i = 0; i < nfds; i++)
if (ufds[i].fd == -1)
{
poll_fd_index = i;
break;
poll_fd_index = i;
break;
}
if (nfds == 0 ||
(nfds == 1 && poll_fd_index >= 0))
{
@@ -431,35 +455,35 @@ select_thread_start_poll (GPollFD *ufds,
{
#ifdef G_ENABLE_DEBUG
if ((_gdk_debug_flags & GDK_DEBUG_EVENTLOOP) && n_ready > 0)
{
g_message ("EventLoop: Found ready file descriptors before waiting");
dump_poll_result (ufds, nfds);
}
{
g_message ("EventLoop: Found ready file descriptors before waiting");
dump_poll_result (ufds, nfds);
}
#endif
return n_ready;
}
SELECT_THREAD_LOCK ();
if (select_thread_state == BEFORE_START)
{
select_thread_start ();
}
if (select_thread_state == POLLING_QUEUED)
{
/* If the select thread hasn't picked up the set of file descriptors yet
* then we can simply replace an old stale set with a new set.
*/
if (!pollfds_equal (ufds, nfds, next_pollfds, next_n_pollfds - 1))
{
g_free (next_pollfds);
next_pollfds = NULL;
next_n_pollfds = 0;
have_new_pollfds = TRUE;
}
{
g_free (next_pollfds);
next_pollfds = NULL;
next_n_pollfds = 0;
have_new_pollfds = TRUE;
}
}
else if (select_thread_state == POLLING_RESTART || select_thread_state == POLLING_DESCRIPTORS)
{
@@ -481,7 +505,7 @@ select_thread_start_poll (GPollFD *ufds,
* Marks polling as complete
* Wakes main thread
* Receives old stale file descriptor state
*
*
* To avoid this, when the new set of poll descriptors is the same as the current
* one, we transition to the POLLING_RESTART stage at the point marked (*). When
* the select thread wakes up from the poll because a file descriptor is active, if
@@ -498,13 +522,13 @@ select_thread_start_poll (GPollFD *ufds,
* from a file descriptor that hangs.
*/
if (!pollfds_equal (ufds, nfds, current_pollfds, current_n_pollfds - 1))
have_new_pollfds = TRUE;
have_new_pollfds = TRUE;
else
{
if (!((nfds == 1 && poll_fd_index < 0 && g_thread_supported ()) ||
(nfds == 2 && poll_fd_index >= 0 && g_thread_supported ())))
select_thread_set_state (POLLING_RESTART);
}
{
if (!((nfds == 1 && poll_fd_index < 0 && g_thread_supported ()) ||
(nfds == 2 && poll_fd_index >= 0 && g_thread_supported ())))
select_thread_set_state (POLLING_RESTART);
}
}
else
have_new_pollfds = TRUE;
@@ -512,28 +536,28 @@ select_thread_start_poll (GPollFD *ufds,
if (have_new_pollfds)
{
GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Submitting a new set of file descriptor to the select thread"));
g_assert (next_pollfds == NULL);
next_n_pollfds = nfds + 1;
next_pollfds = g_new (GPollFD, nfds + 1);
memcpy (next_pollfds, ufds, nfds * sizeof (GPollFD));
next_pollfds[nfds].fd = select_thread_wakeup_pipe[0];
next_pollfds[nfds].events = G_IO_IN;
if (select_thread_state != POLLING_QUEUED && select_thread_state != WAITING)
{
if (select_thread_wakeup_pipe[1])
{
char c = 'A';
write (select_thread_wakeup_pipe[1], &c, 1);
}
}
{
if (select_thread_wakeup_pipe[1])
{
char c = 'A';
write (select_thread_wakeup_pipe[1], &c, 1);
}
}
select_thread_set_state (POLLING_QUEUED);
}
SELECT_THREAD_UNLOCK ();
return -1;
@@ -553,32 +577,32 @@ select_thread_collect_poll (GPollFD *ufds, guint nfds)
{
gint i;
gint n_ready = 0;
SELECT_THREAD_LOCK ();
if (select_thread_state == WAITING) /* The poll completed */
{
for (i = 0; i < nfds; i++)
{
if (ufds[i].fd == -1)
continue;
g_assert (ufds[i].fd == current_pollfds[i].fd);
g_assert (ufds[i].events == current_pollfds[i].events);
{
if (ufds[i].fd == -1)
continue;
g_assert (ufds[i].fd == current_pollfds[i].fd);
g_assert (ufds[i].events == current_pollfds[i].events);
if (current_pollfds[i].revents)
{
ufds[i].revents = current_pollfds[i].revents;
n_ready++;
}
}
if (current_pollfds[i].revents)
{
ufds[i].revents = current_pollfds[i].revents;
n_ready++;
}
}
#ifdef G_ENABLE_DEBUG
if (_gdk_debug_flags & GDK_DEBUG_EVENTLOOP)
{
g_message ("EventLoop: Found ready file descriptors after waiting");
dump_poll_result (ufds, nfds);
}
{
g_message ("EventLoop: Found ready file descriptors after waiting");
dump_poll_result (ufds, nfds);
}
#endif
}
@@ -591,14 +615,20 @@ select_thread_collect_poll (GPollFD *ufds, guint nfds)
********* Main Loop Source *********
************************************************************/
typedef struct _GdkMacosEventSource
{
GSource source;
GdkDisplay *display;
} GdkMacosEventSource;
gboolean
_gdk_quartz_event_loop_check_pending (void)
_gdk_macos_event_source_check_pending (void)
{
return current_events && current_events->head;
}
NSEvent*
_gdk_quartz_event_loop_get_pending (void)
NSEvent *
_gdk_macos_event_source_get_pending (void)
{
NSEvent *event = NULL;
@@ -608,16 +638,11 @@ _gdk_quartz_event_loop_get_pending (void)
return event;
}
void
_gdk_quartz_event_loop_release_event (NSEvent *event)
{
[event release];
}
static gboolean
gdk_event_prepare (GSource *source,
gint *timeout)
gdk_macos_event_source_prepare (GSource *source,
gint *timeout)
{
GdkMacosEventSource *event_source = (GdkMacosEventSource *)source;
gboolean retval;
/* The prepare stage is the stage before the main loop starts polling
@@ -647,55 +672,65 @@ gdk_event_prepare (GSource *source,
*timeout = -1;
if (_gdk_display->event_pause_count > 0)
retval = _gdk_event_queue_find_first (_gdk_display) != NULL;
if (event_source->display->event_pause_count > 0)
retval = _gdk_event_queue_find_first (event_source->display) != NULL;
else
retval = (_gdk_event_queue_find_first (_gdk_display) != NULL ||
_gdk_quartz_event_loop_check_pending ());
retval = (_gdk_event_queue_find_first (event_source->display) != NULL ||
_gdk_macos_event_source_check_pending ());
return retval;
}
static gboolean
gdk_event_check (GSource *source)
gdk_macos_event_source_check (GSource *source)
{
GdkMacosEventSource *event_source = (GdkMacosEventSource *)source;
gboolean retval;
if (_gdk_display->event_pause_count > 0)
retval = _gdk_event_queue_find_first (_gdk_display) != NULL;
if (event_source->display->event_pause_count > 0)
retval = _gdk_event_queue_find_first (event_source->display) != NULL;
else
retval = (_gdk_event_queue_find_first (_gdk_display) != NULL ||
_gdk_quartz_event_loop_check_pending ());
retval = (_gdk_event_queue_find_first (event_source->display) != NULL ||
_gdk_macos_event_source_check_pending ());
return retval;
}
static gboolean
gdk_event_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
gdk_macos_event_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
GdkMacosEventSource *event_source = (GdkMacosEventSource *)source;
GdkEvent *event;
_gdk_quartz_display_queue_events (_gdk_display);
_gdk_macos_display_queue_events (GDK_MACOS_DISPLAY (event_source->display));
event = _gdk_event_unqueue (_gdk_display);
event = _gdk_event_unqueue (event_source->display);
if (event)
{
_gdk_event_emit (event);
g_object_unref (event);
gdk_event_unref (event);
}
return TRUE;
}
static void
gdk_macos_event_source_finalize (GSource *source)
{
GdkMacosEventSource *event_source = (GdkMacosEventSource *)source;
g_clear_object (&event_source->display);
}
static GSourceFuncs event_funcs = {
gdk_event_prepare,
gdk_event_check,
gdk_event_dispatch,
NULL
gdk_macos_event_source_prepare,
gdk_macos_event_source_check,
gdk_macos_event_source_dispatch,
gdk_macos_event_source_finalize,
};
/************************************************************
@@ -704,8 +739,8 @@ static GSourceFuncs event_funcs = {
static gint
poll_func (GPollFD *ufds,
guint nfds,
gint timeout_)
guint nfds,
gint timeout_)
{
NSEvent *event;
NSDate *limit_date;
@@ -727,9 +762,9 @@ poll_func (GPollFD *ufds,
limit_date = [NSDate dateWithTimeIntervalSinceNow:timeout_/1000.0];
getting_events++;
event = [NSApp nextEventMatchingMask: NSAnyEventMask
untilDate: limit_date
inMode: NSDefaultRunLoopMode
event = [NSApp nextEventMatchingMask: NSEventMaskAny
untilDate: limit_date
inMode: NSDefaultRunLoopMode
dequeue: YES];
getting_events--;
@@ -744,10 +779,10 @@ poll_func (GPollFD *ufds,
*/
if (last_ufds == ufds && n_ready < 0)
n_ready = select_thread_collect_poll (ufds, nfds);
if (event &&
[event type] == NSApplicationDefined &&
[event subtype] == GDK_QUARTZ_EVENT_SUBTYPE_EVENTLOOP)
[event type] == NSEventTypeApplicationDefined &&
[event subtype] == GDK_MACOS_EVENT_SUBTYPE_EVENTLOOP)
{
/* Just used to wake us up; if an event and a FD arrived at the same
* time; could have come from a previous iteration in some cases,
@@ -756,7 +791,7 @@ poll_func (GPollFD *ufds,
event = NULL;
}
if (event)
if (event)
{
if (!current_events)
current_events = g_queue_new ();
@@ -775,11 +810,11 @@ poll_func (GPollFD *ufds,
*/
static gint
query_main_context (GMainContext *context,
int max_priority,
int *timeout)
int max_priority,
int *timeout)
{
gint nfds;
if (!run_loop_pollfds)
{
run_loop_pollfds_size = RUN_LOOP_POLLFDS_INITIAL_SIZE;
@@ -787,8 +822,8 @@ query_main_context (GMainContext *context,
}
while ((nfds = g_main_context_query (context, max_priority, timeout,
run_loop_pollfds,
run_loop_pollfds_size)) > run_loop_pollfds_size)
run_loop_pollfds,
run_loop_pollfds_size)) > run_loop_pollfds_size)
{
g_free (run_loop_pollfds);
run_loop_pollfds_size = nfds;
@@ -804,24 +839,24 @@ run_loop_entry (void)
if (acquired_loop_level == -1)
{
if (g_main_context_acquire (NULL))
{
GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Beginning tracking run loop activity"));
acquired_loop_level = current_loop_level;
}
{
GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Beginning tracking run loop activity"));
acquired_loop_level = current_loop_level;
}
else
{
/* If we fail to acquire the main context, that means someone is iterating
* the main context in a different thread; we simply wait until this loop
* exits and then try again at next entry. In general, iterating the loop
* from a different thread is rare: it is only possible when GDK threading
* is initialized and is not frequently used even then. So, we hope that
* having GLib main loop iteration blocked in the combination of that and
* a native modal operation is a minimal problem. We could imagine using a
* thread that does g_main_context_wait() and then wakes us back up, but
* the gain doesn't seem worth the complexity.
*/
GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Can't acquire main loop; skipping tracking run loop activity"));
}
{
/* If we fail to acquire the main context, that means someone is iterating
* the main context in a different thread; we simply wait until this loop
* exits and then try again at next entry. In general, iterating the loop
* from a different thread is rare: it is only possible when GDK threading
* is initialized and is not frequently used even then. So, we hope that
* having GLib main loop iteration blocked in the combination of that and
* a native modal operation is a minimal problem. We could imagine using a
* thread that does g_main_context_wait() and then wakes us back up, but
* the gain doesn't seem worth the complexity.
*/
GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Can't acquire main loop; skipping tracking run loop activity"));
}
}
}
@@ -844,8 +879,8 @@ run_loop_before_sources (void)
* sources are processed by the CFRunLoop, then processing will continue
* on to the BeforeWaiting stage where we check for lower priority sources.
*/
g_main_context_prepare (context, &max_priority);
g_main_context_prepare (context, &max_priority);
max_priority = MIN (max_priority, G_PRIORITY_DEFAULT);
/* We ignore the timeout that query_main_context () returns since we'll
@@ -855,7 +890,7 @@ run_loop_before_sources (void)
if (nfds)
old_poll_func (run_loop_pollfds, nfds, 0);
if (g_main_context_check (context, max_priority, run_loop_pollfds, nfds))
{
GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Dispatching high priority sources"));
@@ -865,7 +900,7 @@ run_loop_before_sources (void)
static void
dummy_timer_callback (CFRunLoopTimerRef timer,
void *info)
void *info)
{
/* Nothing; won't normally even be called */
}
@@ -883,9 +918,9 @@ run_loop_before_waiting (void)
* go ahead and sleep. Before doing that, if there was a timeout from
* GLib, we set up a CFRunLoopTimer to wake us up.
*/
g_main_context_prepare (context, &run_loop_max_priority);
g_main_context_prepare (context, &run_loop_max_priority);
run_loop_n_pollfds = query_main_context (context, run_loop_max_priority, &timeout);
n_ready = select_thread_start_poll (run_loop_pollfds, run_loop_n_pollfds, timeout);
@@ -902,18 +937,18 @@ run_loop_before_waiting (void)
* after the wait wakes up.
*/
GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Adding timer to wake us up in %d milliseconds", timeout));
run_loop_timer = CFRunLoopTimerCreate (NULL, /* allocator */
CFAbsoluteTimeGetCurrent () + timeout / 1000.,
0, /* interval (0=does not repeat) */
0, /* flags */
0, /* order (priority) */
dummy_timer_callback,
NULL);
CFAbsoluteTimeGetCurrent () + timeout / 1000.,
0, /* interval (0=does not repeat) */
0, /* flags */
0, /* order (priority) */
dummy_timer_callback,
NULL);
CFRunLoopAddTimer (main_thread_run_loop, run_loop_timer, kCFRunLoopCommonModes);
}
run_loop_polling_async = n_ready < 0;
}
@@ -932,13 +967,13 @@ run_loop_after_waiting (void)
CFRelease (run_loop_timer);
run_loop_timer = NULL;
}
if (run_loop_polling_async)
{
select_thread_collect_poll (run_loop_pollfds, run_loop_n_pollfds);
run_loop_polling_async = FALSE;
}
if (g_main_context_check (context, run_loop_max_priority, run_loop_pollfds, run_loop_n_pollfds))
{
GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Dispatching after waiting"));
@@ -960,8 +995,8 @@ run_loop_exit (void)
static void
run_loop_observer_callback (CFRunLoopObserverRef observer,
CFRunLoopActivity activity,
void *info)
CFRunLoopActivity activity,
void *info)
{
switch (activity)
{
@@ -972,6 +1007,11 @@ run_loop_observer_callback (CFRunLoopObserverRef observer,
g_return_if_fail (current_loop_level > 0);
current_loop_level--;
break;
case kCFRunLoopBeforeTimers:
case kCFRunLoopBeforeSources:
case kCFRunLoopBeforeWaiting:
case kCFRunLoopAfterWaiting:
case kCFRunLoopAllActivities:
default:
break;
}
@@ -999,6 +1039,8 @@ run_loop_observer_callback (CFRunLoopObserverRef observer,
case kCFRunLoopExit:
run_loop_exit ();
break;
case kCFRunLoopAllActivities:
/* TODO: Do most of the above? */
default:
break;
}
@@ -1006,41 +1048,47 @@ run_loop_observer_callback (CFRunLoopObserverRef observer,
/************************************************************/
void
_gdk_quartz_event_loop_init (void)
GSource *
_gdk_macos_event_source_new (GdkMacosDisplay *display)
{
GSource *source;
CFRunLoopObserverRef observer;
GdkMacosEventSource *event_source;
GSource *source;
g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
/* Hook into the GLib main loop */
event_poll_fd.events = G_IO_IN;
event_poll_fd.fd = -1;
source = g_source_new (&event_funcs, sizeof (GSource));
g_source_set_name (source, "GDK Quartz event source");
source = g_source_new (&event_funcs, sizeof (GdkMacosEventSource));
g_source_set_name (source, "GDK Quartz event source");
g_source_add_poll (source, &event_poll_fd);
g_source_set_priority (source, GDK_PRIORITY_EVENTS);
g_source_set_can_recurse (source, TRUE);
g_source_attach (source, NULL);
old_poll_func = g_main_context_get_poll_func (NULL);
g_main_context_set_poll_func (NULL, poll_func);
event_source = (GdkMacosEventSource *)source;
event_source->display = g_object_ref (GDK_DISPLAY (display));
/* Hook into the the CFRunLoop for the main thread */
main_thread_run_loop = CFRunLoopGetCurrent ();
observer = CFRunLoopObserverCreate (NULL, /* default allocator */
kCFRunLoopAllActivities,
true, /* repeats: not one-shot */
0, /* order (priority) */
run_loop_observer_callback,
NULL);
CFRunLoopAddObserver (main_thread_run_loop, observer, kCFRunLoopCommonModes);
/* Initialize our autorelease pool */
kCFRunLoopAllActivities,
true, /* repeats: not one-shot */
0, /* order (priority) */
run_loop_observer_callback,
NULL);
CFRunLoopAddObserver (main_thread_run_loop, observer, kCFRunLoopCommonModes);
/* Initialize our autorelease pool */
autorelease_pool = [[NSAutoreleasePool alloc] init];
return source;
}
+60
View File
@@ -0,0 +1,60 @@
/* gdkmacosglcontext-private.h
*
* 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/>.
*/
#ifndef __GDK_MACOS_GL_CONTEXT_PRIVATE_H__
#define __GDK_MACOS_GL_CONTEXT_PRIVATE_H__
#include "gdkglcontextprivate.h"
#include "gdkdisplayprivate.h"
#include "gdksurface.h"
#include "gdkinternals.h"
#include "gdkmacosglcontext.h"
#include "gdkmacossurface.h"
#import <OpenGL/OpenGL.h>
#import <OpenGL/gl.h>
#import <AppKit/AppKit.h>
G_BEGIN_DECLS
struct _GdkMacosGLContext
{
GdkGLContext parent_instance;
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
NSOpenGLContext *gl_context;
G_GNUC_END_IGNORE_DEPRECATIONS
gboolean is_attached;
};
struct _GdkMacosGLContextClass
{
GdkGLContextClass parent_class;
};
GdkGLContext *_gdk_macos_gl_context_new (GdkMacosSurface *surface,
gboolean attached,
GdkGLContext *share,
GError **error);
gboolean _gdk_macos_gl_context_make_current (GdkMacosGLContext *self);
G_END_DECLS
#endif /* __GDK_MACOS_GL_CONTEXT_PRIVATE_H__ */
+153
View File
@@ -0,0 +1,153 @@
/*
* 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 "gdkmacosglcontext-private.h"
#include "gdkmacossurface-private.h"
#include "gdkinternals.h"
#include "gdkintl.h"
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
G_DEFINE_TYPE (GdkMacosGLContext, gdk_macos_gl_context, GDK_TYPE_GL_CONTEXT)
static void
gdk_macos_gl_context_end_frame (GdkDrawContext *context,
cairo_region_t *painted)
{
GdkMacosGLContext *self = GDK_MACOS_GL_CONTEXT (context);
g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
[self->gl_context flushBuffer];
}
static void
gdk_macos_gl_context_dispose (GObject *gobject)
{
GdkMacosGLContext *context_macos = GDK_MACOS_GL_CONTEXT (gobject);
if (context_macos->gl_context != NULL)
{
[context_macos->gl_context clearDrawable];
[context_macos->gl_context release];
context_macos->gl_context = NULL;
}
G_OBJECT_CLASS (gdk_macos_gl_context_parent_class)->dispose (gobject);
}
static void
gdk_macos_gl_context_class_init (GdkMacosGLContextClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
object_class->dispose = gdk_macos_gl_context_dispose;
draw_context_class->end_frame = gdk_macos_gl_context_end_frame;
}
static void
gdk_macos_gl_context_init (GdkMacosGLContext *self)
{
}
GdkGLContext *
_gdk_macos_gl_context_new (GdkMacosSurface *surface,
gboolean attached,
GdkGLContext *share,
GError **error)
{
static const NSOpenGLPixelFormatAttribute attrs[] = {
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAColorSize, 24,
NSOpenGLPFAAlphaSize, 8,
0
};
NSOpenGLPixelFormat *format;
GdkMacosGLContext *context = NULL;
NSOpenGLContext *ctx;
GdkDisplay *display;
NSView *nsview;
GLint sync_to_framerate = 1;
g_return_val_if_fail (GDK_IS_MACOS_SURFACE (surface), NULL);
g_return_val_if_fail (!share || GDK_IS_MACOS_GL_CONTEXT (share), NULL);
display = gdk_surface_get_display (GDK_SURFACE (surface));
if (!(format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]))
{
g_set_error_literal (error,
GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
_("Unable to create a GL pixel format"));
goto failure;
}
ctx = [[NSOpenGLContext alloc] initWithFormat:format
shareContext:share ? GDK_MACOS_GL_CONTEXT (share)->gl_context : nil];
if (ctx == NULL)
{
g_set_error_literal (error,
GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
_("Unable to create a GL context"));
goto failure;
}
nsview = _gdk_macos_surface_get_view (surface);
[nsview setWantsBestResolutionOpenGLSurface:YES];
[ctx setValues:&sync_to_framerate forParameter:NSOpenGLCPSwapInterval];
[ctx setView:nsview];
GDK_NOTE (OPENGL,
g_print ("Created NSOpenGLContext[%p]\n", ctx));
context = g_object_new (GDK_TYPE_MACOS_GL_CONTEXT,
"surface", surface,
"shared-context", share,
NULL);
context->gl_context = ctx;
context->is_attached = attached;
failure:
if (format != NULL)
[format release];
return GDK_GL_CONTEXT (context);
}
gboolean
_gdk_macos_gl_context_make_current (GdkMacosGLContext *self)
{
g_return_val_if_fail (GDK_IS_MACOS_GL_CONTEXT (self), FALSE);
[self->gl_context makeCurrentContext];
return TRUE;
}
G_GNUC_END_IGNORE_DEPRECATIONS
+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_GL_CONTEXT_H__
#define __GDK_MACOS_GL_CONTEXT_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
#define GDK_TYPE_MACOS_GL_CONTEXT (gdk_macos_gl_context_get_type ())
#define GDK_MACOS_GL_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_MACOS_GL_CONTEXT, GdkMacosGLContext))
#define GDK_IS_MACOS_GL_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_MACOS_GL_CONTEXT))
typedef struct _GdkMacosGLContext GdkMacosGLContext;
typedef struct _GdkMacosGLContextClass GdkMacosGLContextClass;
GDK_AVAILABLE_IN_ALL
GType gdk_macos_gl_context_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __GDK_MACOS_GL_CONTEXT_H__ */
+36
View File
@@ -0,0 +1,36 @@
/*
* 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_KEYMAP_PRIVATE_H__
#define __GDK_MACOS_KEYMAP_PRIVATE_H__
#include <AppKit/AppKit.h>
#include "gdkmacosdisplay.h"
#include "gdkmacoskeymap.h"
G_BEGIN_DECLS
GdkMacosKeymap *_gdk_macos_keymap_new (GdkMacosDisplay *display);
GdkEventType _gdk_macos_keymap_get_event_type (NSEvent *event);
gboolean _gdk_macos_keymap_is_modifier (guint keycode);
G_END_DECLS
#endif /* __GDK_MACOS_KEYMAP_PRIVATE_H__ */
+698
View File
@@ -0,0 +1,698 @@
/*
* Copyright © 2000-2020 Red Hat, Inc.
* Copyright © 2005 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.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
*/
/* Some parts of this code come from quartzKeyboard.c,
* from the Apple X11 Server.
*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
* HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name(s) of the above
* copyright holders shall not be used in advertising or otherwise to
* promote the sale, use or other dealings in this Software without
* prior written authorization.
*/
#include "config.h"
#include <AppKit/AppKit.h>
#include <Carbon/Carbon.h>
#include <gdk/gdk.h>
#include "gdkkeysprivate.h"
#include "gdkkeysyms.h"
#include "gdkmacoskeymap-private.h"
struct _GdkMacosKeymap
{
GdkKeymap parent_instance;
};
struct _GdkMacosKeymapClass
{
GdkKeymapClass parent_instance;
};
G_DEFINE_TYPE (GdkMacosKeymap, gdk_macos_keymap, GDK_TYPE_KEYMAP)
/* This is a table of all keyvals. Each keycode gets KEYVALS_PER_KEYCODE entries.
* TThere is 1 keyval per modifier (Nothing, Shift, Alt, Shift+Alt);
*/
static guint *keyval_array = NULL;
#define NUM_KEYCODES 128
#define KEYVALS_PER_KEYCODE 4
#define GET_KEYVAL(keycode, group, level) \
(keyval_array[(keycode * KEYVALS_PER_KEYCODE + group * 2 + level)])
const static struct {
guint keycode;
guint keyval;
unsigned int modmask; /* So we can tell when a mod key is pressed/released */
} modifier_keys[] = {
{ 54, GDK_KEY_Meta_R, NSEventModifierFlagCommand },
{ 55, GDK_KEY_Meta_L, NSEventModifierFlagCommand },
{ 56, GDK_KEY_Shift_L, NSEventModifierFlagShift },
{ 57, GDK_KEY_Caps_Lock, NSEventModifierFlagCapsLock },
{ 58, GDK_KEY_Alt_L, NSEventModifierFlagOption },
{ 59, GDK_KEY_Control_L, NSEventModifierFlagControl },
{ 60, GDK_KEY_Shift_R, NSEventModifierFlagShift },
{ 61, GDK_KEY_Alt_R, NSEventModifierFlagOption },
{ 62, GDK_KEY_Control_R, NSEventModifierFlagControl }
};
const static struct {
guint keycode;
guint keyval;
} function_keys[] = {
{ 122, GDK_KEY_F1 },
{ 120, GDK_KEY_F2 },
{ 99, GDK_KEY_F3 },
{ 118, GDK_KEY_F4 },
{ 96, GDK_KEY_F5 },
{ 97, GDK_KEY_F6 },
{ 98, GDK_KEY_F7 },
{ 100, GDK_KEY_F8 },
{ 101, GDK_KEY_F9 },
{ 109, GDK_KEY_F10 },
{ 103, GDK_KEY_F11 },
{ 111, GDK_KEY_F12 },
{ 105, GDK_KEY_F13 },
{ 107, GDK_KEY_F14 },
{ 113, GDK_KEY_F15 },
{ 106, GDK_KEY_F16 }
};
const static struct {
guint keycode;
guint normal_keyval, keypad_keyval;
} known_numeric_keys[] = {
{ 65, GDK_KEY_period, GDK_KEY_KP_Decimal },
{ 67, GDK_KEY_asterisk, GDK_KEY_KP_Multiply },
{ 69, GDK_KEY_plus, GDK_KEY_KP_Add },
{ 75, GDK_KEY_slash, GDK_KEY_KP_Divide },
{ 76, GDK_KEY_Return, GDK_KEY_KP_Enter },
{ 78, GDK_KEY_minus, GDK_KEY_KP_Subtract },
{ 81, GDK_KEY_equal, GDK_KEY_KP_Equal },
{ 82, GDK_KEY_0, GDK_KEY_KP_0 },
{ 83, GDK_KEY_1, GDK_KEY_KP_1 },
{ 84, GDK_KEY_2, GDK_KEY_KP_2 },
{ 85, GDK_KEY_3, GDK_KEY_KP_3 },
{ 86, GDK_KEY_4, GDK_KEY_KP_4 },
{ 87, GDK_KEY_5, GDK_KEY_KP_5 },
{ 88, GDK_KEY_6, GDK_KEY_KP_6 },
{ 89, GDK_KEY_7, GDK_KEY_KP_7 },
{ 91, GDK_KEY_8, GDK_KEY_KP_8 },
{ 92, GDK_KEY_9, GDK_KEY_KP_9 }
};
/* These values aren't covered by gdk_unicode_to_keyval */
const static struct {
gunichar ucs_value;
guint keyval;
} special_ucs_table [] = {
{ 0x0001, GDK_KEY_Home },
{ 0x0003, GDK_KEY_Return },
{ 0x0004, GDK_KEY_End },
{ 0x0008, GDK_KEY_BackSpace },
{ 0x0009, GDK_KEY_Tab },
{ 0x000b, GDK_KEY_Page_Up },
{ 0x000c, GDK_KEY_Page_Down },
{ 0x000d, GDK_KEY_Return },
{ 0x001b, GDK_KEY_Escape },
{ 0x001c, GDK_KEY_Left },
{ 0x001d, GDK_KEY_Right },
{ 0x001e, GDK_KEY_Up },
{ 0x001f, GDK_KEY_Down },
{ 0x007f, GDK_KEY_Delete },
{ 0xf027, GDK_KEY_dead_acute },
{ 0xf060, GDK_KEY_dead_grave },
{ 0xf300, GDK_KEY_dead_grave },
{ 0xf0b4, GDK_KEY_dead_acute },
{ 0xf301, GDK_KEY_dead_acute },
{ 0xf385, GDK_KEY_dead_acute },
{ 0xf05e, GDK_KEY_dead_circumflex },
{ 0xf2c6, GDK_KEY_dead_circumflex },
{ 0xf302, GDK_KEY_dead_circumflex },
{ 0xf07e, GDK_KEY_dead_tilde },
{ 0xf2dc, GDK_KEY_dead_tilde },
{ 0xf303, GDK_KEY_dead_tilde },
{ 0xf342, GDK_KEY_dead_perispomeni },
{ 0xf0af, GDK_KEY_dead_macron },
{ 0xf304, GDK_KEY_dead_macron },
{ 0xf2d8, GDK_KEY_dead_breve },
{ 0xf306, GDK_KEY_dead_breve },
{ 0xf2d9, GDK_KEY_dead_abovedot },
{ 0xf307, GDK_KEY_dead_abovedot },
{ 0xf0a8, GDK_KEY_dead_diaeresis },
{ 0xf308, GDK_KEY_dead_diaeresis },
{ 0xf2da, GDK_KEY_dead_abovering },
{ 0xf30A, GDK_KEY_dead_abovering },
{ 0xf022, GDK_KEY_dead_doubleacute },
{ 0xf2dd, GDK_KEY_dead_doubleacute },
{ 0xf30B, GDK_KEY_dead_doubleacute },
{ 0xf2c7, GDK_KEY_dead_caron },
{ 0xf30C, GDK_KEY_dead_caron },
{ 0xf0be, GDK_KEY_dead_cedilla },
{ 0xf327, GDK_KEY_dead_cedilla },
{ 0xf2db, GDK_KEY_dead_ogonek },
{ 0xf328, GDK_KEY_dead_ogonek },
{ 0xfe5d, GDK_KEY_dead_iota },
{ 0xf323, GDK_KEY_dead_belowdot },
{ 0xf309, GDK_KEY_dead_hook },
{ 0xf31B, GDK_KEY_dead_horn },
{ 0xf02d, GDK_KEY_dead_stroke },
{ 0xf335, GDK_KEY_dead_stroke },
{ 0xf336, GDK_KEY_dead_stroke },
{ 0xf313, GDK_KEY_dead_abovecomma },
/* { 0xf313, GDK_KEY_dead_psili }, */
{ 0xf314, GDK_KEY_dead_abovereversedcomma },
/* { 0xf314, GDK_KEY_dead_dasia }, */
{ 0xf30F, GDK_KEY_dead_doublegrave },
{ 0xf325, GDK_KEY_dead_belowring },
{ 0xf2cd, GDK_KEY_dead_belowmacron },
{ 0xf331, GDK_KEY_dead_belowmacron },
{ 0xf32D, GDK_KEY_dead_belowcircumflex },
{ 0xf330, GDK_KEY_dead_belowtilde },
{ 0xf32E, GDK_KEY_dead_belowbreve },
{ 0xf324, GDK_KEY_dead_belowdiaeresis },
{ 0xf311, GDK_KEY_dead_invertedbreve },
{ 0xf02c, GDK_KEY_dead_belowcomma },
{ 0xf326, GDK_KEY_dead_belowcomma }
};
static void
gdk_macos_keymap_update (GdkMacosKeymap *self)
{
const void *chr_data = NULL;
guint *p;
int i;
TISInputSourceRef new_layout = TISCopyCurrentKeyboardLayoutInputSource ();
CFDataRef layout_data_ref;
g_free (keyval_array);
keyval_array = g_new0 (guint, NUM_KEYCODES * KEYVALS_PER_KEYCODE);
layout_data_ref = (CFDataRef)TISGetInputSourceProperty (new_layout, kTISPropertyUnicodeKeyLayoutData);
if (layout_data_ref)
chr_data = CFDataGetBytePtr (layout_data_ref);
if (chr_data == NULL)
{
g_error ("cannot get keyboard layout data");
return;
}
for (i = 0; i < NUM_KEYCODES; i++)
{
int j;
UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
UniChar chars[4];
UniCharCount nChars;
p = keyval_array + i * KEYVALS_PER_KEYCODE;
for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
{
UInt32 state = 0;
OSStatus err;
UInt16 key_code;
UniChar uc;
key_code = modifiers[j] | i;
err = UCKeyTranslate (chr_data, i, kUCKeyActionDisplay,
(modifiers[j] >> 8) & 0xFF,
LMGetKbdType(),
0,
&state, 4, &nChars, chars);
/* FIXME: Theoretically, we can get multiple UTF-16
* values; we should convert them to proper unicode and
* figure out whether there are really keyboard layouts
* that give us more than one character for one
* keypress.
*/
if (err == noErr && nChars == 1)
{
int k;
gboolean found = FALSE;
/* A few <Shift><Option>keys return two characters,
* the first of which is U+00a0, which isn't
* interesting; so we return the second. More
* sophisticated handling is the job of a
* GtkIMContext.
*
* If state isn't zero, it means that it's a dead
* key of some sort. Some of those are enumerated in
* the special_ucs_table with the high nibble set to
* f to push it into the private use range. Here we
* do the same.
*/
if (state != 0)
chars[nChars - 1] |= 0xf000;
uc = chars[nChars - 1];
for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++)
{
if (special_ucs_table[k].ucs_value == uc)
{
p[j] = special_ucs_table[k].keyval;
found = TRUE;
break;
}
}
/* Special-case shift-tab since GTK+ expects
* GDK_KEY_ISO_Left_Tab for that.
*/
if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
p[j] = GDK_KEY_ISO_Left_Tab;
if (!found)
p[j] = gdk_unicode_to_keyval (uc);
}
}
if (p[3] == p[2])
p[3] = 0;
if (p[2] == p[1])
p[2] = 0;
if (p[1] == p[0])
p[1] = 0;
if (p[0] == p[2] &&
p[1] == p[3])
p[2] = p[3] = 0;
}
for (i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
{
p = keyval_array + modifier_keys[i].keycode * KEYVALS_PER_KEYCODE;
if (p[0] == 0 && p[1] == 0 &&
p[2] == 0 && p[3] == 0)
p[0] = modifier_keys[i].keyval;
}
for (i = 0; i < G_N_ELEMENTS (function_keys); i++)
{
p = keyval_array + function_keys[i].keycode * KEYVALS_PER_KEYCODE;
p[0] = function_keys[i].keyval;
p[1] = p[2] = p[3] = 0;
}
for (i = 0; i < G_N_ELEMENTS (known_numeric_keys); i++)
{
p = keyval_array + known_numeric_keys[i].keycode * KEYVALS_PER_KEYCODE;
if (p[0] == known_numeric_keys[i].normal_keyval)
p[0] = known_numeric_keys[i].keypad_keyval;
}
g_signal_emit_by_name (self, "keys-changed");
}
static PangoDirection
gdk_macos_keymap_get_direction (GdkKeymap *keymap)
{
return PANGO_DIRECTION_NEUTRAL;
}
static gboolean
gdk_macos_keymap_have_bidi_layouts (GdkKeymap *keymap)
{
return FALSE;
}
static gboolean
gdk_macos_keymap_get_caps_lock_state (GdkKeymap *keymap)
{
return FALSE;
}
static gboolean
gdk_macos_keymap_get_num_lock_state (GdkKeymap *keymap)
{
return FALSE;
}
static gboolean
gdk_macos_keymap_get_scroll_lock_state (GdkKeymap *keymap)
{
return FALSE;
}
static guint
gdk_macos_keymap_lookup_key (GdkKeymap *keymap,
const GdkKeymapKey *key)
{
GdkMacosKeymap *self = (GdkMacosKeymap *)keymap;
g_assert (GDK_IS_MACOS_KEYMAP (self));
g_assert (key != NULL);
return GET_KEYVAL (key->keycode, key->group, key->level);
}
static guint
translate_keysym (guint hardware_keycode,
gint group,
GdkModifierType state,
gint *effective_group,
gint *effective_level)
{
gint level;
guint tmp_keyval;
level = (state & GDK_SHIFT_MASK) ? 1 : 0;
if (!(GET_KEYVAL (hardware_keycode, group, 0) || GET_KEYVAL (hardware_keycode, group, 1)) &&
(GET_KEYVAL (hardware_keycode, 0, 0) || GET_KEYVAL (hardware_keycode, 0, 1)))
group = 0;
if (!GET_KEYVAL (hardware_keycode, group, level) &&
GET_KEYVAL (hardware_keycode, group, 0))
level = 0;
tmp_keyval = GET_KEYVAL (hardware_keycode, group, level);
if (state & GDK_LOCK_MASK)
{
guint upper = gdk_keyval_to_upper (tmp_keyval);
if (upper != tmp_keyval)
tmp_keyval = upper;
}
if (effective_group)
*effective_group = group;
if (effective_level)
*effective_level = level;
return tmp_keyval;
}
static gboolean
gdk_macos_keymap_get_entries_for_keyval (GdkKeymap *keymap,
guint keyval,
GArray *keys)
{
gboolean ret = FALSE;
g_assert (GDK_IS_MACOS_KEYMAP (keymap));
g_assert (keys != NULL);
for (guint i = 0; i < NUM_KEYCODES * KEYVALS_PER_KEYCODE; i++)
{
GdkKeymapKey key;
if (keyval_array[i] != keyval)
continue;
key.keycode = i / KEYVALS_PER_KEYCODE;
key.group = (i % KEYVALS_PER_KEYCODE) >= 2;
key.level = i % 2;
g_array_append_val (keys, key);
ret = TRUE;
}
return ret;
}
static gboolean
gdk_macos_keymap_get_entries_for_keycode (GdkKeymap *keymap,
guint hardware_keycode,
GdkKeymapKey **keys,
guint **keyvals,
gint *n_entries)
{
GArray *keys_array;
GArray *keyvals_array;
guint *p;
guint i;
g_assert (GDK_IS_MACOS_KEYMAP (keymap));
g_assert (keyvals != NULL);
g_assert (n_entries != NULL);
*keyvals = NULL;
*n_entries = 0;
if (hardware_keycode > NUM_KEYCODES)
return FALSE;
if (keys)
keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
else
keys_array = NULL;
if (keyvals)
keyvals_array = g_array_new (FALSE, FALSE, sizeof (guint));
else
keyvals_array = NULL;
p = keyval_array + hardware_keycode * KEYVALS_PER_KEYCODE;
for (i = 0; i < KEYVALS_PER_KEYCODE; i++)
{
if (!p[i])
continue;
(*n_entries)++;
if (keyvals_array)
g_array_append_val (keyvals_array, p[i]);
if (keys_array)
{
GdkKeymapKey key;
key.keycode = hardware_keycode;
key.group = i >= 2;
key.level = i % 2;
g_array_append_val (keys_array, key);
}
}
if (keys)
*keys = (GdkKeymapKey *)(gpointer)g_array_free (keys_array, FALSE);
if (keyvals)
*keyvals = (guint *)(gpointer)g_array_free (keyvals_array, FALSE);
return *n_entries > 0;
}
static gboolean
gdk_macos_keymap_translate_keyboard_state (GdkKeymap *keymap,
guint hardware_keycode,
GdkModifierType state,
gint group,
guint *keyval,
gint *effective_group,
gint *level,
GdkModifierType *consumed_modifiers)
{
guint tmp_keyval;
GdkModifierType bit;
g_assert (GDK_IS_MACOS_KEYMAP (keymap));
if (keyval)
*keyval = 0;
if (effective_group)
*effective_group = 0;
if (level)
*level = 0;
if (consumed_modifiers)
*consumed_modifiers = 0;
if (hardware_keycode < 0 || hardware_keycode >= NUM_KEYCODES)
return FALSE;
tmp_keyval = translate_keysym (hardware_keycode, group, state, level, effective_group);
/* Check if modifiers modify the keyval */
if (consumed_modifiers)
{
guint tmp_modifiers = (state & GDK_MODIFIER_MASK);
for (bit = 1; bit <= tmp_modifiers; bit <<= 1)
{
if ((bit & tmp_modifiers) &&
translate_keysym (hardware_keycode, group, state & ~bit,
NULL, NULL) == tmp_keyval)
tmp_modifiers &= ~bit;
}
*consumed_modifiers = tmp_modifiers;
}
if (keyval)
*keyval = tmp_keyval;
return TRUE;
}
static void
input_sources_changed_notification (CFNotificationCenterRef center,
void *observer,
CFStringRef name,
const void *object,
CFDictionaryRef userInfo)
{
GdkMacosKeymap *self = observer;
g_assert (GDK_IS_MACOS_KEYMAP (self));
gdk_macos_keymap_update (self);
}
static void
gdk_macos_keymap_finalize (GObject *object)
{
CFNotificationCenterRemoveObserver (CFNotificationCenterGetDistributedCenter (),
object,
CFSTR ("AppleSelectedInputSourcesChangedNotification"),
NULL);
G_OBJECT_CLASS (gdk_macos_keymap_parent_class)->finalize (object);
}
static void
gdk_macos_keymap_class_init (GdkMacosKeymapClass *klass)
{
GdkKeymapClass *keymap_class = GDK_KEYMAP_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gdk_macos_keymap_finalize;
keymap_class->get_caps_lock_state = gdk_macos_keymap_get_caps_lock_state;
keymap_class->get_direction = gdk_macos_keymap_get_direction;
keymap_class->get_entries_for_keycode = gdk_macos_keymap_get_entries_for_keycode;
keymap_class->get_entries_for_keyval = gdk_macos_keymap_get_entries_for_keyval;
keymap_class->get_num_lock_state = gdk_macos_keymap_get_num_lock_state;
keymap_class->get_scroll_lock_state = gdk_macos_keymap_get_scroll_lock_state;
keymap_class->have_bidi_layouts = gdk_macos_keymap_have_bidi_layouts;
keymap_class->lookup_key = gdk_macos_keymap_lookup_key;
keymap_class->translate_keyboard_state = gdk_macos_keymap_translate_keyboard_state;
}
static void
gdk_macos_keymap_init (GdkMacosKeymap *self)
{
CFNotificationCenterAddObserver (CFNotificationCenterGetDistributedCenter (),
self,
input_sources_changed_notification,
CFSTR ("AppleSelectedInputSourcesChangedNotification"),
NULL,
CFNotificationSuspensionBehaviorDeliverImmediately);
gdk_macos_keymap_update (self);
}
GdkMacosKeymap *
_gdk_macos_keymap_new (GdkMacosDisplay *display)
{
g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
return g_object_new (GDK_TYPE_MACOS_KEYMAP,
"display", display,
NULL);
}
/* What sort of key event is this? Returns one of
* GDK_KEY_PRESS, GDK_KEY_RELEASE, GDK_NOTHING (should be ignored)
*/
GdkEventType
_gdk_macos_keymap_get_event_type (NSEvent *event)
{
unsigned short keycode;
unsigned int flags;
switch ((int)[event type])
{
case NSEventTypeKeyDown:
return GDK_KEY_PRESS;
case NSEventTypeKeyUp:
return GDK_KEY_RELEASE;
case NSEventTypeFlagsChanged:
break;
default:
g_assert_not_reached ();
}
/* For flags-changed events, we have to find the special key that caused the
* event, and see if it's in the modifier mask. */
keycode = [event keyCode];
flags = [event modifierFlags];
for (guint i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
{
if (modifier_keys[i].keycode == keycode)
{
if (flags & modifier_keys[i].modmask)
return GDK_KEY_PRESS;
else
return GDK_KEY_RELEASE;
}
}
/* Some keypresses (eg: Expose' activations) seem to trigger flags-changed
* events for no good reason. Ignore them! */
return 0;
}
gboolean
_gdk_macos_keymap_is_modifier (guint keycode)
{
for (guint i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
{
if (modifier_keys[i].modmask == 0)
break;
if (modifier_keys[i].keycode == keycode)
return TRUE;
}
return FALSE;
}
+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_KEYMAP_H__
#define __GDK_MACOS_KEYMAP_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 _GdkMacosKeymap GdkMacosKeymap;
typedef struct _GdkMacosKeymapClass GdkMacosKeymapClass;
#define GDK_TYPE_MACOS_KEYMAP (gdk_macos_keymap_get_type())
#define GDK_MACOS_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_KEYMAP, GdkMacosKeymap))
#define GDK_IS_MACOS_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_KEYMAP))
GDK_AVAILABLE_IN_ALL
GType gdk_macos_keymap_get_type (void);
G_END_DECLS
#endif /* __GDK_MACOS_KEYMAP_H__ */
+39
View File
@@ -0,0 +1,39 @@
/*
* 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_MONITOR_PRIVATE_H__
#define __GDK_MACOS_MONITOR_PRIVATE_H__
#include <AppKit/AppKit.h>
#include "gdkmacosdisplay.h"
#include "gdkmacosmonitor.h"
#include "gdkmonitorprivate.h"
G_BEGIN_DECLS
GdkMacosMonitor *_gdk_macos_monitor_new (GdkMacosDisplay *display,
CGDirectDisplayID screen_id);
CGDirectDisplayID _gdk_macos_monitor_get_screen_id (GdkMacosMonitor *self);
gboolean _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self);
G_END_DECLS
#endif /* __GDK_MACOS_MONITOR_PRIVATE_H__ */
+288
View File
@@ -0,0 +1,288 @@
/*
* 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 <math.h>
#include "gdkmacosdisplay-private.h"
#include "gdkmacosmonitor-private.h"
#include "gdkmacosutils-private.h"
struct _GdkMacosMonitor
{
GdkMonitor parent_instance;
CGDirectDisplayID screen_id;
NSRect workarea;
guint has_opengl : 1;
};
struct _GdkMacosMonitorClass
{
GdkMonitorClass parent_class;
};
G_DEFINE_TYPE (GdkMacosMonitor, gdk_macos_monitor, GDK_TYPE_MONITOR)
static void
gdk_macos_monitor_get_workarea (GdkMonitor *monitor,
GdkRectangle *geometry)
{
GDK_BEGIN_MACOS_ALLOC_POOL;
GdkMacosMonitor *self = (GdkMacosMonitor *)monitor;
int x, y;
g_assert (GDK_IS_MACOS_MONITOR (self));
g_assert (geometry != NULL);
x = self->workarea.origin.x;
y = self->workarea.origin.y + self->workarea.size.height;
_gdk_macos_display_from_display_coords (GDK_MACOS_DISPLAY (monitor->display),
x, y,
&x, &y);
geometry->x = x;
geometry->y = y;
geometry->width = self->workarea.size.width;
geometry->height = self->workarea.size.height;
GDK_END_MACOS_ALLOC_POOL;
}
static void
gdk_macos_monitor_class_init (GdkMacosMonitorClass *klass)
{
GdkMonitorClass *monitor_class = GDK_MONITOR_CLASS (klass);
monitor_class->get_workarea = gdk_macos_monitor_get_workarea;
}
static void
gdk_macos_monitor_init (GdkMacosMonitor *self)
{
}
static GdkSubpixelLayout
GetSubpixelLayout (CGDirectDisplayID screen_id)
{
#if 0
GDK_BEGIN_MACOS_ALLOC_POOL;
GdkSubpixelLayout subpixel_layout = GDK_SUBPIXEL_LAYOUT_UNKNOWN;
io_service_t iosvc;
NSDictionary *dict;
guint layout;
gboolean rotation;
rotation = CGDisplayRotation (screen_id);
iosvc = CGDisplayIOServicePort (screen_id);
dict = (NSDictionary *)IODisplayCreateInfoDictionary (iosvc, kIODisplayOnlyPreferredName);
layout = [[dict objectForKey:@kDisplaySubPixelLayout] unsignedIntValue];
switch (layout)
{
case kDisplaySubPixelLayoutRGB:
if (rotation == 0.0)
subpixel_layout = GDK_SUBPIXEL_LAYOUT_HORIZONTAL_RGB;
else if (rotation == 90.0)
subpixel_layout = GDK_SUBPIXEL_LAYOUT_VERTICAL_RGB;
else if (rotation == 180.0 || rotation == -180.0)
subpixel_layout = GDK_SUBPIXEL_LAYOUT_HORIZONTAL_BGR;
else if (rotation == -90.0)
subpixel_layout = GDK_SUBPIXEL_LAYOUT_VERTICAL_BGR;
break;
case kDisplaySubPixelLayoutBGR:
if (rotation == 0.0)
subpixel_layout = GDK_SUBPIXEL_LAYOUT_HORIZONTAL_BGR;
else if (rotation == 90.0)
subpixel_layout = GDK_SUBPIXEL_LAYOUT_VERTICAL_BGR;
else if (rotation == 180.0 || rotation == -180.0)
subpixel_layout = GDK_SUBPIXEL_LAYOUT_HORIZONTAL_RGB;
else if (rotation == -90.0 || rotation == 270.0)
subpixel_layout = GDK_SUBPIXEL_LAYOUT_VERTICAL_RGB;
break;
default:
break;
}
GDK_END_MACOS_ALLOC_POOL;
return subpixel_layout;
#endif
return GDK_SUBPIXEL_LAYOUT_UNKNOWN;
}
static char *
GetLocalizedName (NSScreen *screen)
{
GDK_BEGIN_MACOS_ALLOC_POOL;
NSString *str;
char *name;
g_assert (screen);
str = [screen localizedName];
name = g_strdup ([str UTF8String]);
GDK_END_MACOS_ALLOC_POOL;
return g_steal_pointer (&name);
}
static gchar *
GetConnectorName (CGDirectDisplayID screen_id)
{
guint unit = CGDisplayUnitNumber (screen_id);
return g_strdup_printf ("unit-%u", unit);
}
static NSScreen *
find_screen (CGDirectDisplayID screen_id)
{
GDK_BEGIN_MACOS_ALLOC_POOL;
NSScreen *screen = NULL;
for (id obj in [NSScreen screens])
{
if (screen_id == [[[obj deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue])
{
screen = (NSScreen *)obj;
break;
}
}
GDK_END_MACOS_ALLOC_POOL;
return screen;
}
gboolean
_gdk_macos_monitor_reconfigure (GdkMacosMonitor *self)
{
GdkSubpixelLayout subpixel_layout;
CGDisplayModeRef mode;
GdkMacosDisplay *display;
NSScreen *screen;
GdkRectangle geom;
gboolean has_opengl;
CGSize size;
CGRect bounds;
size_t width;
size_t pixel_width;
gchar *connector;
gchar *name;
int refresh_rate;
int scale_factor = 1;
int width_mm;
int height_mm;
g_return_val_if_fail (GDK_IS_MACOS_MONITOR (self), FALSE);
display = GDK_MACOS_DISPLAY (GDK_MONITOR (self)->display);
if (!(screen = find_screen (self->screen_id)) ||
!(mode = CGDisplayCopyDisplayMode (self->screen_id)))
return FALSE;
size = CGDisplayScreenSize (self->screen_id);
bounds = [screen frame];
width = CGDisplayModeGetWidth (mode);
pixel_width = CGDisplayModeGetPixelWidth (mode);
has_opengl = CGDisplayUsesOpenGLAcceleration (self->screen_id);
subpixel_layout = GetSubpixelLayout (self->screen_id);
name = GetLocalizedName (screen);
connector = GetConnectorName (self->screen_id);
if (width != 0 && pixel_width != 0)
scale_factor = MAX (1, pixel_width / width);
width_mm = size.width;
height_mm = size.height;
geom.x = bounds.origin.x - display->min_x;
geom.y = display->height - bounds.origin.y - bounds.size.height + display->min_y;
geom.width = bounds.size.width;
geom.height = bounds.size.height;
/* We will often get 0 back from CGDisplayModeGetRefreshRate(). We
* can fallback by getting it from CoreVideo based on a CVDisplayLink
* setting (which is also used by the frame clock).
*/
if (!(refresh_rate = CGDisplayModeGetRefreshRate (mode)))
refresh_rate = _gdk_macos_display_get_nominal_refresh_rate (display);
gdk_monitor_set_connector (GDK_MONITOR (self), connector);
gdk_monitor_set_model (GDK_MONITOR (self), name);
gdk_monitor_set_geometry (GDK_MONITOR (self), &geom);
gdk_monitor_set_physical_size (GDK_MONITOR (self), width_mm, height_mm);
gdk_monitor_set_scale_factor (GDK_MONITOR (self), scale_factor);
gdk_monitor_set_refresh_rate (GDK_MONITOR (self), refresh_rate);
gdk_monitor_set_subpixel_layout (GDK_MONITOR (self), GDK_SUBPIXEL_LAYOUT_UNKNOWN);
self->workarea = [screen visibleFrame];
/* We might be able to use this at some point to change which GSK renderer
* we use for surfaces on this monitor. For example, it might be better
* to use cairo if we cannot use OpenGL (or it would be software) anyway.
* Presumably that is more common in cases where macOS is running under
* an emulator such as QEMU.
*/
self->has_opengl = !!has_opengl;
CGDisplayModeRelease (mode);
g_free (name);
g_free (connector);
return TRUE;
}
GdkMacosMonitor *
_gdk_macos_monitor_new (GdkMacosDisplay *display,
CGDirectDisplayID screen_id)
{
GdkMacosMonitor *self;
g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
self = g_object_new (GDK_TYPE_MACOS_MONITOR,
"display", display,
NULL);
self->screen_id = screen_id;
_gdk_macos_monitor_reconfigure (self);
return g_steal_pointer (&self);
}
CGDirectDisplayID
_gdk_macos_monitor_get_screen_id (GdkMacosMonitor *self)
{
g_return_val_if_fail (GDK_IS_MACOS_MONITOR (self), 0);
return self->screen_id;
}
+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_MONITOR_H__
#define __GDK_MACOS_MONITOR_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 _GdkMacosMonitor GdkMacosMonitor;
typedef struct _GdkMacosMonitorClass GdkMacosMonitorClass;
#define GDK_TYPE_MACOS_MONITOR (gdk_macos_monitor_get_type())
#define GDK_MACOS_MONITOR(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_MONITOR, GdkMacosMonitor))
#define GDK_IS_MACOS_MONITOR(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_MONITOR))
GDK_AVAILABLE_IN_ALL
GType gdk_macos_monitor_get_type (void);
G_END_DECLS
#endif /* __GDK_MACOS_MONITOR_H__ */
+48
View File
@@ -0,0 +1,48 @@
/*
* 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_POPUP_SURFACE_PRIVATE_H__
#define __GDK_MACOS_POPUP_SURFACE_PRIVATE_H__
#include "gdkmacossurface-private.h"
G_BEGIN_DECLS
typedef struct _GdkMacosPopupSurface GdkMacosPopupSurface;
typedef struct _GdkMacosPopupSurfaceClass GdkMacosPopupSurfaceClass;
#define GDK_TYPE_MACOS_POPUP_SURFACE (_gdk_macos_popup_surface_get_type())
#define GDK_MACOS_POPUP_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_POPUP_SURFACE, GdkMacosPopupSurface))
#define GDK_IS_MACOS_POPUP_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_POPUP_SURFACE))
GType _gdk_macos_popup_surface_get_type (void);
GdkMacosSurface *_gdk_macos_popup_surface_new (GdkMacosDisplay *display,
GdkSurface *parent,
GdkFrameClock *frame_clock,
int x,
int y,
int width,
int height);
void _gdk_macos_popup_surface_attach_to_parent (GdkMacosPopupSurface *self);
void _gdk_macos_popup_surface_detach_from_parent (GdkMacosPopupSurface *self);
void _gdk_macos_popup_surface_reposition (GdkMacosPopupSurface *self);
G_END_DECLS
#endif /* __GDK_MACOS_POPUP_SURFACE_PRIVATE_H__ */
+378
View File
@@ -0,0 +1,378 @@
/*
* 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"
#import "GdkMacosWindow.h"
#include "gdkinternals.h"
#include "gdkpopupprivate.h"
#include "gdkmacosdisplay-private.h"
#include "gdkmacospopupsurface-private.h"
#include "gdkmacosutils-private.h"
struct _GdkMacosPopupSurface
{
GdkMacosSurface parent_instance;
GdkPopupLayout *layout;
};
struct _GdkMacosPopupSurfaceClass
{
GdkMacosSurfaceClass parent_class;
};
static void
gdk_macos_popup_surface_layout (GdkMacosPopupSurface *self,
int width,
int height,
GdkPopupLayout *layout)
{
GdkRectangle final_rect;
int x, y;
g_assert (GDK_IS_MACOS_POPUP_SURFACE (self));
g_assert (layout != NULL);
g_assert (GDK_SURFACE (self)->parent);
if (layout != self->layout)
{
g_clear_pointer (&self->layout, gdk_popup_layout_unref);
self->layout = gdk_popup_layout_ref (layout);
}
gdk_surface_layout_popup_helper (GDK_SURFACE (self),
width,
height,
layout,
&final_rect);
gdk_surface_get_origin (GDK_SURFACE (self)->parent, &x, &y);
x += final_rect.x;
y += final_rect.y;
if (final_rect.width != GDK_SURFACE (self)->width ||
final_rect.height != GDK_SURFACE (self)->height)
_gdk_macos_surface_move_resize (GDK_MACOS_SURFACE (self),
x,
y,
final_rect.width,
final_rect.height);
else if (x != GDK_MACOS_SURFACE (self)->root_x ||
y != GDK_MACOS_SURFACE (self)->root_y)
_gdk_macos_surface_move (GDK_MACOS_SURFACE (self), x, y);
else
return;
gdk_surface_invalidate_rect (GDK_SURFACE (self), NULL);
}
static void
show_popup (GdkMacosPopupSurface *self)
{
_gdk_macos_surface_show (GDK_MACOS_SURFACE (self));
}
static void
show_grabbing_popup (GdkSeat *seat,
GdkSurface *surface,
gpointer user_data)
{
show_popup (GDK_MACOS_POPUP_SURFACE (surface));
}
static gboolean
gdk_macos_popup_surface_present (GdkPopup *popup,
int width,
int height,
GdkPopupLayout *layout)
{
GdkMacosPopupSurface *self = (GdkMacosPopupSurface *)popup;
g_assert (GDK_IS_MACOS_POPUP_SURFACE (self));
gdk_macos_popup_surface_layout (self, width, height, layout);
GDK_MACOS_SURFACE (self)->did_initial_present = TRUE;
if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self)))
return TRUE;
if (GDK_SURFACE (self)->autohide)
{
GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (popup));
GdkSeat *seat = gdk_display_get_default_seat (display);
gdk_seat_grab (seat,
GDK_SURFACE (self),
GDK_SEAT_CAPABILITY_ALL,
TRUE,
NULL, NULL,
show_grabbing_popup,
NULL);
}
else
{
show_popup (GDK_MACOS_POPUP_SURFACE (self));
}
return GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self));
}
static GdkGravity
gdk_macos_popup_surface_get_surface_anchor (GdkPopup *popup)
{
return GDK_SURFACE (popup)->popup.surface_anchor;
}
static GdkGravity
gdk_macos_popup_surface_get_rect_anchor (GdkPopup *popup)
{
return GDK_SURFACE (popup)->popup.rect_anchor;
}
static int
gdk_macos_popup_surface_get_position_x (GdkPopup *popup)
{
return GDK_SURFACE (popup)->x;
}
static int
gdk_macos_popup_surface_get_position_y (GdkPopup *popup)
{
return GDK_SURFACE (popup)->y;
}
static void
popup_interface_init (GdkPopupInterface *iface)
{
iface->present = gdk_macos_popup_surface_present;
iface->get_surface_anchor = gdk_macos_popup_surface_get_surface_anchor;
iface->get_rect_anchor = gdk_macos_popup_surface_get_rect_anchor;
iface->get_position_x = gdk_macos_popup_surface_get_position_x;
iface->get_position_y = gdk_macos_popup_surface_get_position_y;
}
G_DEFINE_TYPE_WITH_CODE (GdkMacosPopupSurface, _gdk_macos_popup_surface, GDK_TYPE_MACOS_SURFACE,
G_IMPLEMENT_INTERFACE (GDK_TYPE_POPUP, popup_interface_init))
enum {
PROP_0,
LAST_PROP,
};
static void
_gdk_macos_popup_surface_finalize (GObject *object)
{
GdkMacosPopupSurface *self = (GdkMacosPopupSurface *)object;
g_clear_object (&GDK_SURFACE (self)->parent);
g_clear_pointer (&self->layout, gdk_popup_layout_unref);
G_OBJECT_CLASS (_gdk_macos_popup_surface_parent_class)->finalize (object);
}
static void
_gdk_macos_popup_surface_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdkSurface *surface = GDK_SURFACE (object);
switch (prop_id)
{
case LAST_PROP + GDK_POPUP_PROP_PARENT:
g_value_set_object (value, surface->parent);
break;
case LAST_PROP + GDK_POPUP_PROP_AUTOHIDE:
g_value_set_boolean (value, surface->autohide);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
_gdk_macos_popup_surface_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GdkSurface *surface = GDK_SURFACE (object);
switch (prop_id)
{
case LAST_PROP + GDK_POPUP_PROP_PARENT:
surface->parent = g_value_dup_object (value);
if (surface->parent)
surface->parent->children = g_list_prepend (surface->parent->children, surface);
break;
case LAST_PROP + GDK_POPUP_PROP_AUTOHIDE:
surface->autohide = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
_gdk_macos_popup_surface_class_init (GdkMacosPopupSurfaceClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = _gdk_macos_popup_surface_finalize;
object_class->get_property = _gdk_macos_popup_surface_get_property;
object_class->set_property = _gdk_macos_popup_surface_set_property;
gdk_popup_install_properties (object_class, 1);
}
static void
_gdk_macos_popup_surface_init (GdkMacosPopupSurface *self)
{
}
GdkMacosSurface *
_gdk_macos_popup_surface_new (GdkMacosDisplay *display,
GdkSurface *parent,
GdkFrameClock *frame_clock,
int x,
int y,
int width,
int height)
{
GDK_BEGIN_MACOS_ALLOC_POOL;
GdkMacosWindow *window;
GdkMacosSurface *self;
NSScreen *screen;
NSUInteger style_mask;
NSRect content_rect;
NSRect screen_rect;
int nx;
int ny;
g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
g_return_val_if_fail (!frame_clock || GDK_IS_FRAME_CLOCK (frame_clock), NULL);
g_return_val_if_fail (!parent || GDK_IS_MACOS_SURFACE (parent), NULL);
style_mask = NSWindowStyleMaskBorderless;
_gdk_macos_display_to_display_coords (display, x, y, &nx, &ny);
screen = _gdk_macos_display_get_screen_at_display_coords (display, nx, ny);
screen_rect = [screen frame];
nx -= screen_rect.origin.x;
ny -= screen_rect.origin.y;
content_rect = NSMakeRect (nx, ny - height, width, height);
window = [[GdkMacosWindow alloc] initWithContentRect:content_rect
styleMask:style_mask
backing:NSBackingStoreBuffered
defer:NO
screen:screen];
[window setOpaque:NO];
[window setBackgroundColor:[NSColor clearColor]];
[window setDecorated:NO];
#if 0
/* NOTE: We could set these to be popup level, but then
* [NSApp orderedWindows] would not give us the windows
* back with the stacking order applied.
*/
[window setLevel:NSPopUpMenuWindowLevel];
#endif
self = g_object_new (GDK_TYPE_MACOS_POPUP_SURFACE,
"display", display,
"frame-clock", frame_clock,
"native", window,
"parent", parent,
NULL);
GDK_END_MACOS_ALLOC_POOL;
return g_steal_pointer (&self);
}
void
_gdk_macos_popup_surface_attach_to_parent (GdkMacosPopupSurface *self)
{
GdkSurface *surface = (GdkSurface *)self;
g_return_if_fail (GDK_IS_MACOS_POPUP_SURFACE (self));
if (GDK_SURFACE_DESTROYED (surface))
return;
if (surface->parent != NULL && !GDK_SURFACE_DESTROYED (surface->parent))
{
NSWindow *parent = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface->parent));
NSWindow *window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
[parent addChildWindow:window ordered:NSWindowAbove];
_gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (surface->display));
}
}
void
_gdk_macos_popup_surface_detach_from_parent (GdkMacosPopupSurface *self)
{
GdkSurface *surface = (GdkSurface *)self;
g_return_if_fail (GDK_IS_MACOS_POPUP_SURFACE (self));
if (GDK_SURFACE_DESTROYED (surface))
return;
if (surface->parent != NULL && !GDK_SURFACE_DESTROYED (surface->parent))
{
NSWindow *parent = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface->parent));
NSWindow *window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
[parent removeChildWindow:window];
_gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (surface->display));
}
}
void
_gdk_macos_popup_surface_reposition (GdkMacosPopupSurface *self)
{
g_return_if_fail (GDK_IS_MACOS_POPUP_SURFACE (self));
if (self->layout == NULL ||
!gdk_surface_get_mapped (GDK_SURFACE (self)) ||
GDK_SURFACE (self)->parent == NULL)
return;
gdk_macos_popup_surface_layout (self,
GDK_SURFACE (self)->width,
GDK_SURFACE (self)->height,
self->layout);
}
+35
View File
@@ -0,0 +1,35 @@
/*
* 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_SEAT_PRIVATE_H__
#define __GDK_MACOS_SEAT_PRIVATE_H__
#include <AppKit/AppKit.h>
#include "gdkmacosdisplay.h"
#include "gdkseatprivate.h"
G_BEGIN_DECLS
GdkSeat *_gdk_macos_seat_new (GdkMacosDisplay *display);
G_END_DECLS
#endif /* __GDK_MACOS_SEAT_PRIVATE_H__ */
+65
View File
@@ -0,0 +1,65 @@
/*
* 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 "gdkseatdefaultprivate.h"
#include "gdkmacosdevice.h"
#include "gdkmacosseat-private.h"
GdkSeat *
_gdk_macos_seat_new (GdkMacosDisplay *display)
{
GdkDevice *core_keyboard;
GdkDevice *core_pointer;
GdkSeat *seat;
g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
core_pointer = g_object_new (GDK_TYPE_MACOS_DEVICE,
"name", "Core Pointer",
"type", GDK_DEVICE_TYPE_LOGICAL,
"source", GDK_SOURCE_MOUSE,
"has-cursor", TRUE,
"display", display,
NULL);
core_keyboard = g_object_new (GDK_TYPE_MACOS_DEVICE,
"name", "Core Keyboard",
"type", GDK_DEVICE_TYPE_LOGICAL,
"source", GDK_SOURCE_KEYBOARD,
"has-cursor", FALSE,
"display", display,
NULL);
_gdk_device_set_associated_device (GDK_DEVICE (core_pointer),
GDK_DEVICE (core_keyboard));
_gdk_device_set_associated_device (GDK_DEVICE (core_keyboard),
GDK_DEVICE (core_pointer));
seat = gdk_seat_default_new_for_logical_pair (core_pointer, core_keyboard);
g_object_unref (core_pointer);
g_object_unref (core_keyboard);
return g_steal_pointer (&seat);
}
+131
View File
@@ -0,0 +1,131 @@
/*
* 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_SURFACE_PRIVATE_H__
#define __GDK_MACOS_SURFACE_PRIVATE_H__
#include <AppKit/AppKit.h>
#include <cairo.h>
#include "gdkinternals.h"
#include "gdksurfaceprivate.h"
#include "gdkmacosdisplay.h"
#include "gdkmacossurface.h"
#import "GdkMacosWindow.h"
G_BEGIN_DECLS
#define GDK_MACOS_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_MACOS_SURFACE, GdkMacosSurfaceClass))
#define GDK_IS_MACOS_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_MACOS_SURFACE))
#define GDK_MACOS_SURFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_MACOS_SURFACE, GdkMacosSurfaceClass))
struct _GdkMacosSurface
{
GdkSurface parent_instance;
GList main;
GList sorted;
GList frame;
GdkMacosWindow *window;
GPtrArray *monitors;
cairo_region_t *input_region;
char *title;
int root_x;
int root_y;
int shadow_top;
int shadow_right;
int shadow_bottom;
int shadow_left;
gint64 pending_frame_counter;
guint did_initial_present : 1;
};
struct _GdkMacosSurfaceClass
{
GdkSurfaceClass parent_class;
};
GdkMacosSurface *_gdk_macos_surface_new (GdkMacosDisplay *display,
GdkSurfaceType surface_type,
GdkSurface *parent,
int x,
int y,
int width,
int height);
NSWindow *_gdk_macos_surface_get_native (GdkMacosSurface *self);
CGDirectDisplayID _gdk_macos_surface_get_screen_id (GdkMacosSurface *self);
const char *_gdk_macos_surface_get_title (GdkMacosSurface *self);
void _gdk_macos_surface_set_title (GdkMacosSurface *self,
const gchar *title);
void _gdk_macos_surface_get_shadow (GdkMacosSurface *self,
gint *top,
gint *right,
gint *bottom,
gint *left);
NSView *_gdk_macos_surface_get_view (GdkMacosSurface *self);
gboolean _gdk_macos_surface_get_modal_hint (GdkMacosSurface *self);
void _gdk_macos_surface_set_modal_hint (GdkMacosSurface *self,
gboolean modal_hint);
void _gdk_macos_surface_set_geometry_hints (GdkMacosSurface *self,
const GdkGeometry *geometry,
GdkSurfaceHints geom_mask);
void _gdk_macos_surface_resize (GdkMacosSurface *self,
int width,
int height);
void _gdk_macos_surface_update_fullscreen_state (GdkMacosSurface *self);
void _gdk_macos_surface_update_position (GdkMacosSurface *self);
void _gdk_macos_surface_show (GdkMacosSurface *self);
void _gdk_macos_surface_thaw (GdkMacosSurface *self,
gint64 predicted_presentation_time,
gint64 refresh_interval);
CGContextRef _gdk_macos_surface_acquire_context (GdkMacosSurface *self,
gboolean clear_scale,
gboolean antialias);
void _gdk_macos_surface_release_context (GdkMacosSurface *self,
CGContextRef cg_context);
void _gdk_macos_surface_synthesize_null_key (GdkMacosSurface *self);
void _gdk_macos_surface_move (GdkMacosSurface *self,
int x,
int y);
void _gdk_macos_surface_move_resize (GdkMacosSurface *self,
int x,
int y,
int width,
int height);
gboolean _gdk_macos_surface_is_tracking (GdkMacosSurface *self,
NSTrackingArea *area);
void _gdk_macos_surface_monitor_changed (GdkMacosSurface *self);
GdkMonitor *_gdk_macos_surface_get_best_monitor (GdkMacosSurface *self);
void _gdk_macos_surface_reposition_children (GdkMacosSurface *self);
void _gdk_macos_surface_set_opacity (GdkMacosSurface *self,
double opacity);
void _gdk_macos_surface_get_root_coords (GdkMacosSurface *self,
int *x,
int *y);
G_END_DECLS
#endif /* __GDK_MACOS_SURFACE_PRIVATE_H__ */
File diff suppressed because it is too large Load Diff
+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_SURFACE_H__
#define __GDK_MACOS_SURFACE_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 _GdkMacosSurface GdkMacosSurface;
typedef struct _GdkMacosSurfaceClass GdkMacosSurfaceClass;
#define GDK_TYPE_MACOS_SURFACE (gdk_macos_surface_get_type())
#define GDK_MACOS_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_SURFACE, GdkMacosSurface))
#define GDK_IS_MACOS_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_SURFACE))
GDK_AVAILABLE_IN_ALL
GType gdk_macos_surface_get_type (void);
G_END_DECLS
#endif /* __GDK_MACOS_SURFACE_H__ */
@@ -0,0 +1,47 @@
/*
* 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_TOPLEVEL_SURFACE_PRIVATE_H__
#define __GDK_MACOS_TOPLEVEL_SURFACE_PRIVATE_H__
#include "gdkmacossurface-private.h"
G_BEGIN_DECLS
typedef struct _GdkMacosToplevelSurface GdkMacosToplevelSurface;
typedef struct _GdkMacosToplevelSurfaceClass GdkMacosToplevelSurfaceClass;
#define GDK_TYPE_MACOS_TOPLEVEL_SURFACE (_gdk_macos_toplevel_surface_get_type())
#define GDK_MACOS_TOPLEVEL_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_TOPLEVEL_SURFACE, GdkMacosToplevelSurface))
#define GDK_IS_MACOS_TOPLEVEL_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_TOPLEVEL_SURFACE))
GType _gdk_macos_toplevel_surface_get_type (void);
GdkMacosSurface *_gdk_macos_toplevel_surface_new (GdkMacosDisplay *display,
GdkSurface *parent,
GdkFrameClock *frame_clock,
int x,
int y,
int width,
int height);
void _gdk_macos_toplevel_surface_attach_to_parent (GdkMacosToplevelSurface *self);
void _gdk_macos_toplevel_surface_detach_from_parent (GdkMacosToplevelSurface *self);
G_END_DECLS
#endif /* __GDK_MACOS_TOPLEVEL_SURFACE_PRIVATE_H__ */
+581
View File
@@ -0,0 +1,581 @@
/*
* 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"
#import "GdkMacosWindow.h"
#include "gdkinternals.h"
#include "gdktoplevelprivate.h"
#include "gdkmacosdisplay-private.h"
#include "gdkmacostoplevelsurface-private.h"
#include "gdkmacosutils-private.h"
struct _GdkMacosToplevelSurface
{
GdkMacosSurface parent_instance;
guint decorated : 1;
};
struct _GdkMacosToplevelSurfaceClass
{
GdkMacosSurfaceClass parent_instance;
};
static void
_gdk_macos_toplevel_surface_fullscreen (GdkMacosToplevelSurface *self)
{
NSWindow *window;
g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
if (([window styleMask] & NSWindowStyleMaskFullScreen) == 0)
[window toggleFullScreen:window];
}
static void
_gdk_macos_toplevel_surface_unfullscreen (GdkMacosToplevelSurface *self)
{
NSWindow *window;
g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
if (([window styleMask] & NSWindowStyleMaskFullScreen) != 0)
[window toggleFullScreen:window];
}
static void
_gdk_macos_toplevel_surface_maximize (GdkMacosToplevelSurface *self)
{
NSWindow *window;
g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
if (![window isZoomed])
[window zoom:window];
}
static void
_gdk_macos_toplevel_surface_unmaximize (GdkMacosToplevelSurface *self)
{
NSWindow *window;
g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
if ([window isZoomed])
[window zoom:window];
}
static gboolean
_gdk_macos_toplevel_surface_present (GdkToplevel *toplevel,
int width,
int height,
GdkToplevelLayout *layout)
{
GdkMacosToplevelSurface *self = (GdkMacosToplevelSurface *)toplevel;
NSWindow *nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
GdkGeometry geometry;
GdkSurfaceHints mask;
NSWindowStyleMask style_mask;
g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
g_assert (GDK_IS_MACOS_WINDOW (nswindow));
style_mask = [nswindow styleMask];
if (gdk_toplevel_layout_get_resizable (layout))
{
geometry.min_width = gdk_toplevel_layout_get_min_width (layout);
geometry.min_height = gdk_toplevel_layout_get_min_height (layout);
mask = GDK_HINT_MIN_SIZE;
/* Only set 'Resizable' mask to get native resize zones if the window is
* titled, otherwise we do this internally for CSD and do not need
* NSWindow to do it for us. Additionally, it can mess things up when
* doing a window resize since it can cause mouseDown to get passed
* through to the next window.
*/
if ((style_mask & NSWindowStyleMaskTitled) != 0)
style_mask |= NSWindowStyleMaskResizable;
else
style_mask &= ~NSWindowStyleMaskResizable;
}
else
{
geometry.max_width = geometry.min_width = width;
geometry.max_height = geometry.min_height = height;
mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
style_mask &= ~NSWindowStyleMaskResizable;
}
if (style_mask != [nswindow styleMask])
[nswindow setStyleMask:style_mask];
_gdk_macos_surface_set_geometry_hints (GDK_MACOS_SURFACE (self), &geometry, mask);
gdk_surface_constrain_size (&geometry, mask, width, height, &width, &height);
_gdk_macos_surface_resize (GDK_MACOS_SURFACE (self), width, height);
/* Maximized state */
if (gdk_toplevel_layout_get_maximized (layout))
_gdk_macos_toplevel_surface_maximize (self);
else
_gdk_macos_toplevel_surface_unmaximize (self);
/* Fullscreen state */
if (gdk_toplevel_layout_get_fullscreen (layout))
_gdk_macos_toplevel_surface_fullscreen (self);
else
_gdk_macos_toplevel_surface_unfullscreen (self);
if (GDK_SURFACE (self)->transient_for != NULL)
{
}
else
{
if (!self->decorated &&
!GDK_MACOS_SURFACE (self)->did_initial_present &&
GDK_SURFACE (self)->x == 0 &&
GDK_SURFACE (self)->y == 0 &&
(GDK_MACOS_SURFACE (self)->shadow_left ||
GDK_MACOS_SURFACE (self)->shadow_top))
{
GdkMonitor *monitor = _gdk_macos_surface_get_best_monitor (GDK_MACOS_SURFACE (self));
int x = GDK_SURFACE (self)->x;
int y = GDK_SURFACE (self)->y;
if (monitor != NULL)
{
GdkRectangle visible;
gdk_monitor_get_workarea (monitor, &visible);
if (x < visible.x)
x = visible.x;
if (y < visible.y)
y = visible.y;
}
x -= GDK_MACOS_SURFACE (self)->shadow_left;
y -= GDK_MACOS_SURFACE (self)->shadow_top;
_gdk_macos_surface_move (GDK_MACOS_SURFACE (self), x, y);
}
}
_gdk_macos_surface_show (GDK_MACOS_SURFACE (self));
GDK_MACOS_SURFACE (self)->did_initial_present = TRUE;
return TRUE;
}
static gboolean
_gdk_macos_toplevel_surface_minimize (GdkToplevel *toplevel)
{
GdkMacosToplevelSurface *self = (GdkMacosToplevelSurface *)toplevel;
NSWindow *window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
[window miniaturize:window];
return TRUE;
}
static gboolean
_gdk_macos_toplevel_surface_lower (GdkToplevel *toplevel)
{
GdkMacosToplevelSurface *self = (GdkMacosToplevelSurface *)toplevel;
NSWindow *window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
[window orderBack:window];
return TRUE;
}
static void
_gdk_macos_toplevel_surface_focus (GdkToplevel *toplevel,
guint32 timestamp)
{
GdkMacosToplevelSurface *self = (GdkMacosToplevelSurface *)toplevel;
NSWindow *nswindow;
if (GDK_SURFACE_DESTROYED (self))
return;
nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
[nswindow makeKeyAndOrderFront:nswindow];
}
static void
_gdk_macos_toplevel_surface_begin_resize (GdkToplevel *toplevel,
GdkSurfaceEdge edge,
GdkDevice *device,
int button,
double root_x,
double root_y,
guint32 timestamp)
{
NSWindow *nswindow;
g_assert (GDK_IS_MACOS_SURFACE (toplevel));
if (GDK_SURFACE_DESTROYED (toplevel))
return;
/* Release passive grab */
if (button != 0)
gdk_seat_ungrab (gdk_device_get_seat (device));
if ((nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (toplevel))))
[(GdkMacosWindow *)nswindow beginManualResize:edge];
}
static void
_gdk_macos_toplevel_surface_begin_move (GdkToplevel *toplevel,
GdkDevice *device,
int button,
double root_x,
double root_y,
guint32 timestamp)
{
NSWindow *nswindow;
g_assert (GDK_IS_MACOS_SURFACE (toplevel));
if (GDK_SURFACE_DESTROYED (toplevel))
return;
/* Release passive grab */
if (button != 0)
gdk_seat_ungrab (gdk_device_get_seat (device));
if ((nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (toplevel))))
[(GdkMacosWindow *)nswindow beginManualMove];
}
static void
toplevel_iface_init (GdkToplevelInterface *iface)
{
iface->present = _gdk_macos_toplevel_surface_present;
iface->minimize = _gdk_macos_toplevel_surface_minimize;
iface->lower = _gdk_macos_toplevel_surface_lower;
iface->focus = _gdk_macos_toplevel_surface_focus;
iface->begin_resize = _gdk_macos_toplevel_surface_begin_resize;
iface->begin_move = _gdk_macos_toplevel_surface_begin_move;
}
G_DEFINE_TYPE_WITH_CODE (GdkMacosToplevelSurface, _gdk_macos_toplevel_surface, GDK_TYPE_MACOS_SURFACE,
G_IMPLEMENT_INTERFACE (GDK_TYPE_TOPLEVEL, toplevel_iface_init))
enum {
PROP_0,
LAST_PROP
};
static void
_gdk_macos_toplevel_surface_set_transient_for (GdkMacosToplevelSurface *self,
GdkMacosSurface *parent)
{
g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
g_assert (!parent || GDK_IS_MACOS_SURFACE (parent));
_gdk_macos_toplevel_surface_detach_from_parent (self);
g_clear_object (&GDK_SURFACE (self)->transient_for);
if (g_set_object (&GDK_SURFACE (self)->transient_for, GDK_SURFACE (parent)))
_gdk_macos_toplevel_surface_attach_to_parent (self);
}
static void
_gdk_macos_toplevel_surface_set_decorated (GdkMacosToplevelSurface *self,
gboolean decorated)
{
g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
decorated = !!decorated;
if (decorated != self->decorated)
{
NSWindow *window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
self->decorated = decorated;
[(GdkMacosWindow *)window setDecorated:(BOOL)decorated];
}
}
static void
_gdk_macos_toplevel_surface_hide (GdkSurface *surface)
{
GdkMacosToplevelSurface *self = (GdkMacosToplevelSurface *)surface;
_gdk_macos_toplevel_surface_detach_from_parent (self);
GDK_SURFACE_CLASS (_gdk_macos_toplevel_surface_parent_class)->hide (surface);
}
static void
_gdk_macos_toplevel_surface_destroy (GdkSurface *surface,
gboolean foreign_destroy)
{
GdkMacosToplevelSurface *self = (GdkMacosToplevelSurface *)surface;
g_clear_object (&GDK_SURFACE (self)->transient_for);
GDK_SURFACE_CLASS (_gdk_macos_toplevel_surface_parent_class)->destroy (surface, foreign_destroy);
}
static void
_gdk_macos_toplevel_surface_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdkSurface *surface = GDK_SURFACE (object);
GdkMacosSurface *base = GDK_MACOS_SURFACE (surface);
GdkMacosToplevelSurface *toplevel = GDK_MACOS_TOPLEVEL_SURFACE (base);
switch (prop_id)
{
case LAST_PROP + GDK_TOPLEVEL_PROP_STATE:
g_value_set_flags (value, surface->state);
break;
case LAST_PROP + GDK_TOPLEVEL_PROP_TITLE:
g_value_set_string (value, _gdk_macos_surface_get_title (base));
break;
case LAST_PROP + GDK_TOPLEVEL_PROP_STARTUP_ID:
g_value_set_string (value, "");
break;
case LAST_PROP + GDK_TOPLEVEL_PROP_TRANSIENT_FOR:
g_value_set_object (value, GDK_SURFACE (toplevel)->transient_for);
break;
case LAST_PROP + GDK_TOPLEVEL_PROP_MODAL:
g_value_set_boolean (value, GDK_SURFACE (toplevel)->modal_hint);
break;
case LAST_PROP + GDK_TOPLEVEL_PROP_ICON_LIST:
g_value_set_pointer (value, NULL);
break;
case LAST_PROP + GDK_TOPLEVEL_PROP_DECORATED:
g_value_set_boolean (value, toplevel->decorated);
break;
case LAST_PROP + GDK_TOPLEVEL_PROP_DELETABLE:
break;
case LAST_PROP + GDK_TOPLEVEL_PROP_FULLSCREEN_MODE:
g_value_set_enum (value, surface->fullscreen_mode);
break;
case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED:
g_value_set_boolean (value, surface->shortcuts_inhibited);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
_gdk_macos_toplevel_surface_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GdkSurface *surface = GDK_SURFACE (object);
GdkMacosSurface *base = GDK_MACOS_SURFACE (surface);
GdkMacosToplevelSurface *toplevel = GDK_MACOS_TOPLEVEL_SURFACE (base);
switch (prop_id)
{
case LAST_PROP + GDK_TOPLEVEL_PROP_TITLE:
_gdk_macos_surface_set_title (base, g_value_get_string (value));
g_object_notify_by_pspec (G_OBJECT (surface), pspec);
break;
case LAST_PROP + GDK_TOPLEVEL_PROP_STARTUP_ID:
break;
case LAST_PROP + GDK_TOPLEVEL_PROP_TRANSIENT_FOR:
_gdk_macos_toplevel_surface_set_transient_for (toplevel, g_value_get_object (value));
g_object_notify_by_pspec (G_OBJECT (surface), pspec);
break;
case LAST_PROP + GDK_TOPLEVEL_PROP_MODAL:
GDK_SURFACE (surface)->modal_hint = g_value_get_boolean (value);
g_object_notify_by_pspec (G_OBJECT (surface), pspec);
break;
case LAST_PROP + GDK_TOPLEVEL_PROP_ICON_LIST:
break;
case LAST_PROP + GDK_TOPLEVEL_PROP_DECORATED:
_gdk_macos_toplevel_surface_set_decorated (toplevel, g_value_get_boolean (value));
break;
case LAST_PROP + GDK_TOPLEVEL_PROP_DELETABLE:
break;
case LAST_PROP + GDK_TOPLEVEL_PROP_FULLSCREEN_MODE:
surface->fullscreen_mode = g_value_get_enum (value);
g_object_notify_by_pspec (G_OBJECT (surface), pspec);
break;
case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED:
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
_gdk_macos_toplevel_surface_class_init (GdkMacosToplevelSurfaceClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdkSurfaceClass *surface_class = GDK_SURFACE_CLASS (klass);
object_class->get_property = _gdk_macos_toplevel_surface_get_property;
object_class->set_property = _gdk_macos_toplevel_surface_set_property;
surface_class->destroy = _gdk_macos_toplevel_surface_destroy;
surface_class->hide = _gdk_macos_toplevel_surface_hide;
gdk_toplevel_install_properties (object_class, LAST_PROP);
}
static void
_gdk_macos_toplevel_surface_init (GdkMacosToplevelSurface *self)
{
self->decorated = TRUE;
}
GdkMacosSurface *
_gdk_macos_toplevel_surface_new (GdkMacosDisplay *display,
GdkSurface *parent,
GdkFrameClock *frame_clock,
int x,
int y,
int width,
int height)
{
GDK_BEGIN_MACOS_ALLOC_POOL;
GdkMacosWindow *window;
GdkMacosSurface *self;
NSScreen *screen;
NSUInteger style_mask;
NSRect content_rect;
NSRect screen_rect;
int nx;
int ny;
g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
g_return_val_if_fail (!frame_clock || GDK_IS_FRAME_CLOCK (frame_clock), NULL);
g_return_val_if_fail (!parent || GDK_IS_MACOS_SURFACE (parent), NULL);
style_mask = (NSWindowStyleMaskTitled |
NSWindowStyleMaskClosable |
NSWindowStyleMaskMiniaturizable |
NSWindowStyleMaskResizable);
_gdk_macos_display_to_display_coords (display, x, y, &nx, &ny);
screen = _gdk_macos_display_get_screen_at_display_coords (display, nx, ny);
screen_rect = [screen visibleFrame];
nx -= screen_rect.origin.x;
ny -= screen_rect.origin.y;
content_rect = NSMakeRect (nx, ny - height, width, height);
window = [[GdkMacosWindow alloc] initWithContentRect:content_rect
styleMask:style_mask
backing:NSBackingStoreBuffered
defer:NO
screen:screen];
self = g_object_new (GDK_TYPE_MACOS_TOPLEVEL_SURFACE,
"display", display,
"frame-clock", frame_clock,
"native", window,
NULL);
GDK_END_MACOS_ALLOC_POOL;
return g_steal_pointer (&self);
}
void
_gdk_macos_toplevel_surface_attach_to_parent (GdkMacosToplevelSurface *self)
{
GdkSurface *surface = (GdkSurface *)self;
g_return_if_fail (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
if (GDK_SURFACE_DESTROYED (surface))
return;
if (surface->transient_for != NULL &&
!GDK_SURFACE_DESTROYED (surface->transient_for))
{
NSWindow *parent = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface->transient_for));
NSWindow *window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
[parent addChildWindow:window ordered:NSWindowAbove];
if (GDK_SURFACE (self)->modal_hint)
[window setLevel:NSModalPanelWindowLevel];
_gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (surface->display));
}
}
void
_gdk_macos_toplevel_surface_detach_from_parent (GdkMacosToplevelSurface *self)
{
GdkSurface *surface = (GdkSurface *)self;
g_return_if_fail (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
if (GDK_SURFACE_DESTROYED (surface))
return;
if (surface->transient_for != NULL &&
!GDK_SURFACE_DESTROYED (surface->transient_for))
{
NSWindow *parent = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface->transient_for));
NSWindow *window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
[parent removeChildWindow:window];
[window setLevel:NSNormalWindowLevel];
_gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (surface->display));
}
}
+36
View File
@@ -0,0 +1,36 @@
/*
* 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_UTILS_PRIVATE_H__
#define __GDK_MACOS_UTILS_PRIVATE_H__
#include <AppKit/AppKit.h>
#include <gdk/gdk.h>
#define GDK_BEGIN_MACOS_ALLOC_POOL NSAutoreleasePool *_pool = [[NSAutoreleasePool alloc] init]
#define GDK_END_MACOS_ALLOC_POOL [_pool release]
static inline gboolean
queue_contains (GQueue *queue,
GList *link_)
{
return queue->head == link_ || link_->prev || link_->next;
}
#endif /* __GDK_MACOS_UTILS_PRIVATE_H__ */
+62
View File
@@ -0,0 +1,62 @@
gdk_macos_sources = files([
'edgesnapping.c',
'gdkdisplaylinksource.c',
'gdkmacoscairocontext.c',
'gdkmacosclipboard.c',
'gdkmacoscursor.c',
'gdkmacosdevice.c',
'gdkmacosdisplay.c',
'gdkmacosdisplay-settings.c',
'gdkmacosdisplay-translate.c',
'gdkmacosdrag.c',
'gdkmacosdragsurface.c',
'gdkmacosglcontext.c',
'gdkmacoseventsource.c',
'gdkmacoskeymap.c',
'gdkmacosmonitor.c',
'gdkmacospopupsurface.c',
'gdkmacosseat.c',
'gdkmacossurface.c',
'gdkmacostoplevelsurface.c',
'GdkMacosBaseView.c',
'GdkMacosCairoView.c',
'GdkMacosCairoSubview.c',
'GdkMacosGLLayer.c',
'GdkMacosWindow.c',
])
gdk_macos_public_headers = files([
'gdkmacosdevice.h',
'gdkmacosdisplay.h',
'gdkmacosglcontext.h',
'gdkmacoskeymap.h',
'gdkmacosmonitor.h',
'gdkmacossurface.h',
])
install_headers(gdk_macos_public_headers, 'gdkmacos.h', subdir: 'gtk-4.0/gdk/macos/')
gdk_macos_frameworks = [
'AppKit',
'Carbon',
'CoreVideo',
'CoreServices',
'OpenGL',
'QuartzCore',
]
gdk_macos_deps = [
dependency('appleframeworks', modules: gdk_macos_frameworks)
]
libgdk_c_args += ['-xobjective-c']
libgdk_macos = static_library('gdk-macos',
gdk_macos_sources, gdkconfig, gdkenum_h,
include_directories: [ confinc, gdkinc, ],
c_args: libgdk_c_args + common_cflags,
link_args: common_ldflags,
link_with: [],
dependencies: gdk_deps + gdk_macos_deps)
+8 -6
View File
@@ -143,6 +143,7 @@ gdkconfig_cdata.set('GDK_WINDOWING_X11', x11_enabled)
gdkconfig_cdata.set('GDK_WINDOWING_WAYLAND', wayland_enabled)
gdkconfig_cdata.set('GDK_WINDOWING_WIN32', win32_enabled)
gdkconfig_cdata.set('GDK_WINDOWING_BROADWAY', broadway_enabled)
gdkconfig_cdata.set('GDK_WINDOWING_MACOS', macos_enabled)
gdkconfig_cdata.set('GDK_RENDERING_VULKAN', have_vulkan)
gdkconfig = configure_file(
@@ -216,9 +217,14 @@ if wayland_enabled or broadway_enabled
endif
endif
libgdk_c_args = [
'-DGTK_COMPILATION',
'-DG_LOG_DOMAIN="Gdk"',
]
gdk_backends = []
gdk_backends_gen_headers = [] # non-public generated headers
foreach backend : ['broadway', 'quartz', 'wayland', 'win32', 'x11']
foreach backend : ['broadway', 'quartz', 'wayland', 'win32', 'x11', 'macos']
if get_variable('@0@_enabled'.format(backend))
subdir(backend)
gdk_deps += get_variable('gdk_@0@_deps'.format(backend))
@@ -235,16 +241,12 @@ if gdk_backends.length() == 0
error('No backends enabled')
endif
# FIXME: might have to add '-xobjective-c' to c_args for quartz backend?
libgdk = static_library('gdk',
sources: [gdk_sources, gdk_backends_gen_headers, gdkconfig],
dependencies: gdk_deps + [libgtk_css_dep],
link_with: [libgtk_css, ],
include_directories: [confinc, gdkx11_inc, wlinc],
c_args: [
'-DGTK_COMPILATION',
'-DG_LOG_DOMAIN="Gdk"',
] + common_cflags,
c_args: libgdk_c_args + common_cflags,
link_whole: gdk_backends,
link_args: common_ldflags)
-845
View File
@@ -1,845 +0,0 @@
/* GdkQuartzSurface.m
*
* Copyright (C) 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/>.
*/
#include "config.h"
#import "GdkQuartzNSWindow.h"
#include "gdkquartzsurface.h"
#include "gdkdnd-quartz.h"
#include "gdkprivate-quartz.h"
@implementation GdkQuartzNSWindow
- (void)windowWillClose:(NSNotification*)notification
{
// Clears the delegate when window is going to be closed; since EL
// Capitan it is possible that the methods of delegate would get
// called after the window has been closed.
[self setDelegate:nil];
}
-(BOOL)windowShouldClose:(id)sender
{
GdkSurface *window = [[self contentView] gdkSurface];
GdkEvent *event;
event = gdk_event_new (GDK_DELETE);
event->any.surface = g_object_ref (window);
event->any.send_event = FALSE;
_gdk_event_queue_append (gdk_display_get_default (), event);
return NO;
}
-(void)windowWillMiniaturize:(NSNotification *)aNotification
{
GdkSurface *window = [[self contentView] gdkSurface];
_gdk_quartz_surface_detach_from_parent (window);
}
-(void)windowDidMiniaturize:(NSNotification *)aNotification
{
GdkSurface *window = [[self contentView] gdkSurface];
gdk_synthesize_surface_state (window, 0, GDK_SURFACE_STATE_MINIMIZED);
}
-(void)windowDidDeminiaturize:(NSNotification *)aNotification
{
GdkSurface *window = [[self contentView] gdkSurface];
_gdk_quartz_surface_attach_to_parent (window);
gdk_synthesize_surface_state (window, GDK_SURFACE_STATE_MINIMIZED, 0);
}
-(void)windowDidBecomeKey:(NSNotification *)aNotification
{
GdkSurface *window = [[self contentView] gdkSurface];
gdk_synthesize_surface_state (window, 0, GDK_SURFACE_STATE_FOCUSED);
_gdk_quartz_events_update_focus_window (window, TRUE);
}
-(void)windowDidResignKey:(NSNotification *)aNotification
{
GdkSurface *window = [[self contentView] gdkSurface];
_gdk_quartz_events_update_focus_window (window, FALSE);
gdk_synthesize_surface_state (window, GDK_SURFACE_STATE_FOCUSED, 0);
}
-(void)windowDidBecomeMain:(NSNotification *)aNotification
{
GdkSurface *window = [[self contentView] gdkSurface];
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_quartz_surface_did_become_main (window);
}
-(void)windowDidResignMain:(NSNotification *)aNotification
{
GdkSurface *window;
window = [[self contentView] gdkSurface];
_gdk_quartz_surface_did_resign_main (window);
}
/* 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
{
switch ([event type])
{
case NSLeftMouseUp:
{
double time = ((double)[event timestamp]) * 1000.0;
_gdk_quartz_events_break_all_grabs (time);
inManualMove = NO;
inManualResize = NO;
inMove = NO;
break;
}
case NSLeftMouseDragged:
if ([self trackManualMove] || [self trackManualResize])
return;
break;
default:
break;
}
[super sendEvent:event];
}
-(BOOL)isInMove
{
return inMove;
}
-(void)checkSendEnterNotify
{
GdkSurface *window = [[self contentView] gdkSurface];
GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
/* When a new window has been created, and the mouse
* is in the window area, we will not receive an NSMouseEntered
* event. Therefore, we synthesize an enter notify event manually.
*/
if (!initialPositionKnown)
{
initialPositionKnown = YES;
if (NSPointInRect ([NSEvent mouseLocation], [self frame]))
{
NSEvent *event;
event = [NSEvent enterExitEventWithType: NSMouseEntered
location: [self mouseLocationOutsideOfEventStream]
modifierFlags: 0
timestamp: [[NSApp currentEvent] timestamp]
windowNumber: [impl->toplevel windowNumber]
context: NULL
eventNumber: 0
trackingNumber: [impl->view trackingRect]
userData: nil];
[NSApp postEvent:event atStart:NO];
}
}
}
-(void)windowDidMove:(NSNotification *)aNotification
{
GdkSurface *window = [[self contentView] gdkSurface];
GdkEvent *event;
GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
gboolean maximized = gdk_surface_get_state (window) & GDK_SURFACE_STATE_MAXIMIZED;
/* In case the window is changed when maximized remove the maximized state */
if (maximized && !inMaximizeTransition && !NSEqualRects (lastMaximizedFrame, [self frame]))
{
gdk_synthesize_surface_state (window,
GDK_SURFACE_STATE_MAXIMIZED,
0);
}
_gdk_quartz_surface_update_position (window);
/* Synthesize a configure event */
event = gdk_event_new (GDK_CONFIGURE);
event->configure.window = g_object_ref (window);
event->configure.x = window->x;
event->configure.y = window->y;
event->configure.width = window->width;
event->configure.height = window->height;
_gdk_event_queue_append (gdk_display_get_default (), event);
[self checkSendEnterNotify];
}
-(void)windowDidResize:(NSNotification *)aNotification
{
NSRect content_rect = [self contentRectForFrameRect:[self frame]];
GdkSurface *window = [[self contentView] gdkSurface];
GdkEvent *event;
GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
gboolean maximized = gdk_surface_get_state (window) & GDK_SURFACE_STATE_MAXIMIZED;
/* see same in windowDidMove */
if (maximized && !inMaximizeTransition && !NSEqualRects (lastMaximizedFrame, [self frame]))
{
gdk_synthesize_surface_state (window,
GDK_SURFACE_STATE_MAXIMIZED,
0);
}
window->width = content_rect.size.width;
window->height = content_rect.size.height;
/* Certain resize operations (e.g. going fullscreen), also move the
* origin of the window.
*/
_gdk_quartz_surface_update_position (window);
[[self contentView] setFrame:NSMakeRect (0, 0, window->width, window->height)];
_gdk_surface_update_size (window);
/* Synthesize a configure event */
event = gdk_event_new (GDK_CONFIGURE);
event->configure.window = g_object_ref (window);
event->configure.x = window->x;
event->configure.y = window->y;
event->configure.width = window->width;
event->configure.height = window->height;
_gdk_event_queue_append (gdk_display_get_default (), event);
[self checkSendEnterNotify];
}
-(id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag screen:(NSScreen *)screen
{
self = [super initWithContentRect:contentRect
styleMask:styleMask
backing:backingType
defer:flag
screen:screen];
[self setAcceptsMouseMovedEvents:YES];
[self setDelegate:self];
[self setReleasedWhenClosed:YES];
return self;
}
-(BOOL)canBecomeMainWindow
{
GdkSurface *window = [[self contentView] gdkSurface];
GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
switch (impl->type_hint)
{
case GDK_SURFACE_TYPE_HINT_NORMAL:
case GDK_SURFACE_TYPE_HINT_DIALOG:
return YES;
case GDK_SURFACE_TYPE_HINT_MENU:
case GDK_SURFACE_TYPE_HINT_TOOLBAR:
case GDK_SURFACE_TYPE_HINT_SPLASHSCREEN:
case GDK_SURFACE_TYPE_HINT_UTILITY:
case GDK_SURFACE_TYPE_HINT_DOCK:
case GDK_SURFACE_TYPE_HINT_DESKTOP:
case GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU:
case GDK_SURFACE_TYPE_HINT_POPUP_MENU:
case GDK_SURFACE_TYPE_HINT_TOOLTIP:
case GDK_SURFACE_TYPE_HINT_NOTIFICATION:
case GDK_SURFACE_TYPE_HINT_COMBO:
case GDK_SURFACE_TYPE_HINT_DND:
return NO;
}
return YES;
}
-(BOOL)canBecomeKeyWindow
{
GdkSurface *window = [[self contentView] gdkSurface];
GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
if (!window->accept_focus)
return NO;
/* Popup windows should not be able to get focused in the window
* manager sense, it's only handled through grabs.
*/
if (window->surface_type == GDK_SURFACE_TEMP)
return NO;
switch (impl->type_hint)
{
case GDK_SURFACE_TYPE_HINT_NORMAL:
case GDK_SURFACE_TYPE_HINT_DIALOG:
case GDK_SURFACE_TYPE_HINT_MENU:
case GDK_SURFACE_TYPE_HINT_TOOLBAR:
case GDK_SURFACE_TYPE_HINT_UTILITY:
case GDK_SURFACE_TYPE_HINT_DOCK:
case GDK_SURFACE_TYPE_HINT_DESKTOP:
case GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU:
case GDK_SURFACE_TYPE_HINT_POPUP_MENU:
case GDK_SURFACE_TYPE_HINT_COMBO:
return YES;
case GDK_SURFACE_TYPE_HINT_SPLASHSCREEN:
case GDK_SURFACE_TYPE_HINT_TOOLTIP:
case GDK_SURFACE_TYPE_HINT_NOTIFICATION:
case GDK_SURFACE_TYPE_HINT_DND:
return NO;
}
return YES;
}
- (void)showAndMakeKey:(BOOL)makeKey
{
GdkSurface *window = [[self contentView] gdkSurface];
GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
inShowOrHide = YES;
if (makeKey)
[impl->toplevel makeKeyAndOrderFront:impl->toplevel];
else
[impl->toplevel orderFront:nil];
inShowOrHide = NO;
[self checkSendEnterNotify];
}
- (void)hide
{
GdkSurface *window = [[self contentView] gdkSurface];
GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
inShowOrHide = YES;
[impl->toplevel orderOut:nil];
inShowOrHide = NO;
initialPositionKnown = NO;
}
- (BOOL)trackManualMove
{
GdkSurface *window = [[self contentView] gdkSurface];
GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
NSPoint currentLocation;
NSPoint newOrigin;
NSRect screenFrame = [[NSScreen mainScreen] visibleFrame];
NSRect windowFrame = [self frame];
if (!inManualMove)
return NO;
currentLocation = [self convertBaseToScreen:[self mouseLocationOutsideOfEventStream]];
newOrigin.x = currentLocation.x - initialMoveLocation.x;
newOrigin.y = currentLocation.y - initialMoveLocation.y;
/* Clamp vertical position to below the menu bar. */
if (newOrigin.y + windowFrame.size.height - impl->shadow_top > screenFrame.origin.y + screenFrame.size.height)
newOrigin.y = screenFrame.origin.y + screenFrame.size.height - windowFrame.size.height + impl->shadow_top;
[self setFrameOrigin:newOrigin];
return YES;
}
/* Used by gdkevents-quartz.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
{
NSRect frame = [self frame];
if (inMove || inManualMove || inManualResize)
return;
inManualMove = YES;
initialMoveLocation = [self convertBaseToScreen:[self mouseLocationOutsideOfEventStream]];
initialMoveLocation.x -= frame.origin.x;
initialMoveLocation.y -= frame.origin.y;
}
- (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 convertBaseToScreen:[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 convertBaseToScreen:[self mouseLocationOutsideOfEventStream]];
}
static GdkDragContext *current_context = NULL;
static GdkDragAction
drag_operation_to_drag_action (NSDragOperation operation)
{
GdkDragAction result = 0;
/* GDK and Quartz drag operations do not map 1:1.
* This mapping represents about the best that we
* can come up.
*/
if (operation & NSDragOperationGeneric)
result |= GDK_ACTION_MOVE;
if (operation & NSDragOperationCopy)
result |= GDK_ACTION_COPY;
if (operation & NSDragOperationMove)
result |= GDK_ACTION_MOVE;
if (operation & NSDragOperationLink)
result |= GDK_ACTION_LINK;
return result;
}
static NSDragOperation
drag_action_to_drag_operation (GdkDragAction action)
{
NSDragOperation result = 0;
if (action & GDK_ACTION_COPY)
result |= NSDragOperationCopy;
if (action & GDK_ACTION_LINK)
result |= NSDragOperationLink;
if (action & GDK_ACTION_MOVE)
result |= NSDragOperationMove;
return result;
}
static void
update_context_from_dragging_info (id <NSDraggingInfo> sender)
{
GdkDragAction action;
g_assert (current_context != NULL);
GDK_QUARTZ_DRAG_CONTEXT (current_context)->dragging_info = sender;
action = drag_operation_to_drag_action ([sender draggingSourceOperationMask]);
gdk_drag_context_set_actions (current_context, action, action);
}
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
{
GdkEvent *event;
GdkSurface *window;
if (current_context)
g_object_unref (current_context);
current_context = g_object_new (GDK_TYPE_QUARTZ_DRAG_CONTEXT,
"device", gdk_seat_get_pointer (gdk_display_get_default_seat (current_context->display)),
NULL);
update_context_from_dragging_info (sender);
window = [[self contentView] gdkSurface];
event = gdk_event_new (GDK_DRAG_ENTER);
event->dnd.window = g_object_ref (window);
event->dnd.send_event = FALSE;
event->dnd.context = g_object_ref (current_context);
event->dnd.time = GDK_CURRENT_TIME;
gdk_event_set_device (event, gdk_drag_context_get_device (current_context));
gdk_event_set_seat (event, gdk_device_get_seat (gdk_drag_context_get_device (current_context)));
_gdk_event_emit (event);
g_object_unref (event);
return NSDragOperationNone;
}
- (void)draggingEnded:(id <NSDraggingInfo>)sender
{
/* leave a note for the source about what action was taken */
if (_gdk_quartz_drag_source_context && current_context)
_gdk_quartz_drag_source_context->action = current_context->action;
if (current_context)
g_object_unref (current_context);
current_context = NULL;
}
- (void)draggingExited:(id <NSDraggingInfo>)sender
{
GdkEvent *event;
event = gdk_event_new (GDK_DRAG_LEAVE);
event->dnd.window = g_object_ref ([[self contentView] gdkSurface]);
event->dnd.send_event = FALSE;
event->dnd.context = g_object_ref (current_context);
event->dnd.time = GDK_CURRENT_TIME;
gdk_event_set_device (event, gdk_drag_context_get_device (current_context));
gdk_event_set_seat (event, gdk_device_get_seat (gdk_drag_context_get_device (current_context)));
_gdk_event_emit (event);
g_object_unref (event);
g_object_unref (current_context);
current_context = NULL;
}
- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
{
NSPoint point = [sender draggingLocation];
NSPoint screen_point = [self convertBaseToScreen:point];
GdkEvent *event;
int gx, gy;
update_context_from_dragging_info (sender);
_gdk_quartz_surface_nspoint_to_gdk_xy (screen_point, &gx, &gy);
event = gdk_event_new (GDK_DRAG_MOTION);
event->dnd.window = g_object_ref ([[self contentView] gdkSurface]);
event->dnd.send_event = FALSE;
event->dnd.context = g_object_ref (current_context);
event->dnd.time = GDK_CURRENT_TIME;
event->dnd.x_root = gx;
event->dnd.y_root = gy;
gdk_event_set_device (event, gdk_drag_context_get_device (current_context));
gdk_event_set_seat (event, gdk_device_get_seat (gdk_drag_context_get_device (current_context)));
_gdk_event_emit (event);
g_object_unref (event);
return drag_action_to_drag_operation (current_context->action);
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
NSPoint point = [sender draggingLocation];
NSPoint screen_point = [self convertBaseToScreen:point];
GdkEvent *event;
int gy, gx;
update_context_from_dragging_info (sender);
_gdk_quartz_surface_nspoint_to_gdk_xy (screen_point, &gx, &gy);
event = gdk_event_new (GDK_DROP_START);
event->dnd.window = g_object_ref ([[self contentView] gdkSurface]);
event->dnd.send_event = FALSE;
event->dnd.context = g_object_ref (current_context);
event->dnd.time = GDK_CURRENT_TIME;
event->dnd.x_root = gx;
event->dnd.y_root = gy;
gdk_event_set_device (event, gdk_drag_context_get_device (current_context));
gdk_event_set_seat (event, gdk_device_get_seat (gdk_drag_context_get_device (current_context)));
_gdk_event_emit (event);
g_object_unref (event);
g_object_unref (current_context);
current_context = NULL;
return YES;
}
- (BOOL)wantsPeriodicDraggingUpdates
{
return NO;
}
- (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
{
GdkEvent *event;
GdkDisplay *display;
GdkDevice *device;
g_assert (_gdk_quartz_drag_source_context != NULL);
event = gdk_event_new (GDK_DROP_FINISHED);
event->dnd.window = g_object_ref ([[self contentView] gdkSurface]);
event->dnd.send_event = FALSE;
event->dnd.context = g_object_ref (_gdk_quartz_drag_source_context);
display = gdk_surface_get_display (event->dnd.window);
if (display)
{
GList* windows, *list;
gint gx, gy;
event->dnd.context->dest_surface = NULL;
windows = get_toplevels ();
_gdk_quartz_surface_nspoint_to_gdk_xy (aPoint, &gx, &gy);
for (list = windows; list; list = list->next)
{
GdkSurface* win = (GdkSurface*) list->data;
gint wx, wy;
gint ww, wh;
gdk_surface_get_root_origin (win, &wx, &wy);
ww = gdk_surface_get_width (win);
wh = gdk_surface_get_height (win);
if (gx > wx && gy > wy && gx <= wx + ww && gy <= wy + wh)
event->dnd.context->dest_surface = win;
}
}
device = gdk_drag_context_get_device (_gdk_quartz_drag_source_context);
gdk_event_set_device (event, device);
gdk_event_set_seat (event, gdk_device_get_seat (device));
_gdk_event_emit (event);
g_object_unref (event);
g_object_unref (_gdk_quartz_drag_source_context);
_gdk_quartz_drag_source_context = NULL;
}
#ifdef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
- (void)setStyleMask:(NSUInteger)styleMask
{
gboolean was_fullscreen;
gboolean is_fullscreen;
was_fullscreen = (([self styleMask] & NSFullScreenWindowMask) != 0);
[super setStyleMask:styleMask];
is_fullscreen = (([self styleMask] & NSFullScreenWindowMask) != 0);
if (was_fullscreen != is_fullscreen)
_gdk_quartz_surface_update_fullscreen_state ([[self contentView] gdkSurface]);
}
#endif
- (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
{
NSRect rect;
GdkSurface *window = [[self contentView] gdkSurface];
GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
/* 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. */
rect = [super constrainFrameRect:frameRect toScreen:screen];
if (frameRect.origin.y > rect.origin.y)
rect.origin.y = MIN (frameRect.origin.y, rect.origin.y + impl->shadow_top);
return rect;
}
- (NSRect)windowWillUseStandardFrame:(NSWindow *)nsWindow
defaultFrame:(NSRect)newFrame
{
NSRect screenFrame = [[self screen] visibleFrame];
GdkSurface *window = [[self contentView] gdkSurface];
GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
gboolean maximized = gdk_surface_get_state (window) & GDK_SURFACE_STATE_MAXIMIZED;
if (!maximized)
return screenFrame;
else
return lastUnmaximizedFrame;
}
- (BOOL)windowShouldZoom:(NSWindow *)nsWindow
toFrame:(NSRect)newFrame
{
GdkSurface *window = [[self contentView] gdkSurface];
GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
gboolean maximized = gdk_surface_get_state (window) & GDK_SURFACE_STATE_MAXIMIZED;
if (maximized)
{
lastMaximizedFrame = newFrame;
gdk_synthesize_surface_state (window,
GDK_SURFACE_STATE_MAXIMIZED,
0);
}
else
{
lastUnmaximizedFrame = [nsWindow frame];
gdk_synthesize_surface_state (window,
0,
GDK_SURFACE_STATE_MAXIMIZED);
}
inMaximizeTransition = YES;
return YES;
}
-(void)windowDidEndLiveResize:(NSNotification *)aNotification
{
inMaximizeTransition = NO;
}
-(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];
}
@end
-61
View File
@@ -1,61 +0,0 @@
/* GdkQuartzNSWindow.h
*
* Copyright (C) 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/>.
*/
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
#include <glib.h>
#include <gdk.h>
@interface GdkQuartzNSWindow : NSWindow {
BOOL inMove;
BOOL inShowOrHide;
BOOL initialPositionKnown;
/* Manually triggered move/resize (not by the window manager) */
BOOL inManualMove;
BOOL inManualResize;
BOOL inTrackManualResize;
NSPoint initialMoveLocation;
NSPoint initialResizeLocation;
NSRect initialResizeFrame;
GdkSurfaceEdge resizeEdge;
NSRect lastUnmaximizedFrame;
NSRect lastMaximizedFrame;
NSRect lastUnfullscreenFrame;
BOOL inMaximizeTransition;
}
-(BOOL)isInMove;
-(void)beginManualMove;
-(BOOL)trackManualMove;
-(BOOL)isInManualResizeOrMove;
-(void)beginManualResize:(GdkSurfaceEdge)edge;
-(BOOL)trackManualResize;
-(void)showAndMakeKey:(BOOL)makeKey;
-(void)hide;
#ifdef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
-(void)setStyleMask:(NSUInteger)styleMask;
#endif
@end
-712
View File
@@ -1,712 +0,0 @@
/* GdkQuartzView.m
*
* Copyright (C) 2005-2007 Imendio AB
* Copyright (C) 2011 Hiroyuki Yamamoto
*
* 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"
#import "GdkQuartzView.h"
#include "gdkquartzsurface.h"
#include "gdkprivate-quartz.h"
#include "gdkquartz.h"
@implementation GdkQuartzView
-(id)initWithFrame: (NSRect)frameRect
{
if ((self = [super initWithFrame: frameRect]))
{
markedRange = NSMakeRange (NSNotFound, 0);
selectedRange = NSMakeRange (NSNotFound, 0);
}
return self;
}
-(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) keyDown: (NSEvent *) theEvent
{
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
{
GDK_NOTE (EVENTS, g_message ("firstRectForCharacterRange"));
gint ns_x, ns_y;
GdkRectangle *rect;
rect = g_object_get_data (G_OBJECT (gdk_surface), GIC_CURSOR_RECT);
if (rect)
{
_gdk_quartz_surface_gdk_xy_to_xy (rect->x, rect->y + rect->height,
&ns_x, &ns_y);
return NSMakeRect (ns_x, ns_y, rect->width, rect->height);
}
else
{
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"));
gchar *prev_str;
markedRange = selectedRange = NSMakeRange (NSNotFound, 0);
g_object_set_data_full (G_OBJECT (gdk_surface), TIC_MARKED_TEXT, NULL, g_free);
}
-(void)setMarkedText: (id)aString selectedRange: (NSRange)newSelection replacementRange: (NSRange)replacementRange
{
GDK_NOTE (EVENTS, g_message ("setMarkedText"));
const char *str;
gchar *prev_str;
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 (gdk_surface), TIC_MARKED_TEXT, g_strdup (str), g_free);
g_object_set_data (G_OBJECT (gdk_surface), TIC_SELECTED_POS,
GUINT_TO_POINTER (selectedRange.location));
g_object_set_data (G_OBJECT (gdk_surface), TIC_SELECTED_LEN,
GUINT_TO_POINTER (selectedRange.length));
GDK_NOTE (EVENTS, g_message ("setMarkedText: set %s (%p, nsview %p): %s",
TIC_MARKED_TEXT, gdk_surface, self,
str ? str : "(empty)"));
/* handle text input changes by mouse events */
if (!GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (gdk_surface),
TIC_IN_KEY_DOWN)))
{
_gdk_quartz_synthesize_null_key_event(gdk_surface);
}
}
-(void)doCommandBySelector: (SEL)aSelector
{
GDK_NOTE (EVENTS, g_message ("doCommandBySelector"));
if ([self respondsToSelector: aSelector])
[self performSelector: aSelector];
}
-(void)insertText: (id)aString replacementRange: (NSRange)replacementRange
{
GDK_NOTE (EVENTS, g_message ("insertText"));
const char *str;
NSString *string;
gchar *prev_str;
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];
NSInputManager *currentInputManager = [NSInputManager currentInputManager];
[currentInputManager markedTextAbandoned:self];
}
else
{
str = [string UTF8String];
}
g_object_set_data_full (G_OBJECT (gdk_surface), TIC_INSERT_TEXT, g_strdup (str), g_free);
GDK_NOTE (EVENTS, g_message ("insertText: set %s (%p, nsview %p): %s",
TIC_INSERT_TEXT, gdk_surface, self,
str ? str : "(empty)"));
g_object_set_data (G_OBJECT (gdk_surface), 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 (gdk_surface),
TIC_IN_KEY_DOWN)))
{
_gdk_quartz_synthesize_null_key_event(gdk_surface);
}
}
-(void)deleteBackward: (id)sender
{
GDK_NOTE (EVENTS, g_message ("deleteBackward"));
g_object_set_data (G_OBJECT (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), 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 (gdk_surface), GIC_FILTER_KEY,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
-(void)noop: (id)sender
{
GDK_NOTE (EVENTS, g_message ("noop"));
}
/* --------------------------------------------------------------- */
-(void)dealloc
{
if (trackingRect)
{
[self removeTrackingRect: trackingRect];
trackingRect = 0;
}
[super dealloc];
}
-(void)setGdkSurface: (GdkSurface *)window
{
gdk_surface = window;
}
-(GdkSurface *)gdkSurface
{
return gdk_surface;
}
-(NSTrackingRectTag)trackingRect
{
return trackingRect;
}
-(BOOL)isFlipped
{
return YES;
}
-(BOOL)isOpaque
{
if (GDK_SURFACE_DESTROYED (gdk_surface))
return YES;
return NO;
}
-(void)drawRect: (NSRect)rect
{
GdkRectangle gdk_rect;
GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (gdk_window->impl);
const NSRect *drawn_rects;
NSInteger count;
int i;
cairo_region_t *region;
if (GDK_SURFACE_DESTROYED (gdk_surface))
return;
if (! (gdk_window->event_mask & GDK_EXPOSURE_MASK))
return;
if (NSEqualRects (rect, NSZeroRect))
return;
if (!GDK_SURFACE_IS_MAPPED (gdk_surface))
{
/* If the window is not yet mapped, clip_region_with_children
* will be empty causing the usual code below to draw nothing.
* To not see garbage on the screen, we draw an aesthetic color
* here. The garbage would be visible if any widget enabled
* the NSView's CALayer in order to add sublayers for custom
* native rendering.
*/
[NSGraphicsContext saveGraphicsState];
[[NSColor windowBackgroundColor] setFill];
[NSBezierPath fillRect: rect];
[NSGraphicsContext restoreGraphicsState];
return;
}
/* Clear our own bookkeeping of regions that need display */
if (impl->needs_display_region)
{
cairo_region_destroy (impl->needs_display_region);
impl->needs_display_region = NULL;
}
[self getRectsBeingDrawn: &drawn_rects count: &count];
region = cairo_region_create ();
for (i = 0; i < count; i++)
{
gdk_rect.x = drawn_rects[i].origin.x;
gdk_rect.y = drawn_rects[i].origin.y;
gdk_rect.width = drawn_rects[i].size.width;
gdk_rect.height = drawn_rects[i].size.height;
cairo_region_union_rectangle (region, &gdk_rect);
}
impl->in_paint_rect_count++;
_gdk_surface_process_updates_recurse (gdk_surface, region);
impl->in_paint_rect_count--;
cairo_region_destroy (region);
if (needsInvalidateShadow)
{
[[self window] invalidateShadow];
needsInvalidateShadow = NO;
}
}
-(void)setNeedsInvalidateShadow: (BOOL)invalidate
{
needsInvalidateShadow = invalidate;
}
/* For information on setting up tracking rects properly, see here:
* http://developer.apple.com/documentation/Cocoa/Conceptual/EventOverview/EventOverview.pdf
*/
-(void)updateTrackingRect
{
GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (gdk_window->impl);
NSRect rect;
if (!impl || !impl->toplevel)
return;
if (trackingRect)
{
[self removeTrackingRect: trackingRect];
trackingRect = 0;
}
if (!impl->toplevel)
return;
/* Note, if we want to set assumeInside we can use:
* NSPointInRect ([[self window] convertScreenToBase:[NSEvent mouseLocation]], rect)
*/
rect = [self bounds];
trackingRect = [self addTrackingRect: rect
owner: self
userData: nil
assumeInside: NO];
}
-(void)viewDidMoveToWindow
{
if (![self window]) /* We are destroyed already */
return;
[self updateTrackingRect];
}
-(void)viewWillMoveToWindow: (NSWindow *)newWindow
{
if (newWindow == nil && trackingRect)
{
[self removeTrackingRect: trackingRect];
trackingRect = 0;
}
}
-(void)setFrame: (NSRect)frame
{
[super setFrame: frame];
if ([self window])
[self updateTrackingRect];
}
@end
-36
View File
@@ -1,36 +0,0 @@
/* GDK - The GIMP Drawing Kit
*
* Copyright © 2018 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gdkconfig.h"
#include "gdkcairocontext-quartz.h"
G_DEFINE_TYPE (GdkQuartzCairoContext, gdk_quartz_cairo_context, GDK_TYPE_CAIRO_CONTEXT)
static void
gdk_quartz_cairo_context_class_init (GdkQuartzCairoContextClass *klass)
{
}
static void
gdk_quartz_cairo_context_init (GdkQuartzCairoContext *self)
{
}
-53
View File
@@ -1,53 +0,0 @@
/* GDK - The GIMP Drawing Kit
*
* Copyright © 2018 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_QUARTZ_CAIRO_CONTEXT__
#define __GDK_QUARTZ_CAIRO_CONTEXT__
#include "gdkconfig.h"
#include "gdkcairocontextprivate.h"
G_BEGIN_DECLS
#define GDK_TYPE_QUARTZ_CAIRO_CONTEXT (gdk_quartz_cairo_context_get_type ())
#define GDK_QUARTZ_CAIRO_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_QUARTZ_CAIRO_CONTEXT, GdkQuartzCairoContext))
#define GDK_IS_QUARTZ_CAIRO_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_QUARTZ_CAIRO_CONTEXT))
#define GDK_QUARTZ_CAIRO_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_QUARTZ_CAIRO_CONTEXT, GdkQuartzCairoContextClass))
#define GDK_IS_QUARTZ_CAIRO_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_QUARTZ_CAIRO_CONTEXT))
#define GDK_QUARTZ_CAIRO_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_QUARTZ_CAIRO_CONTEXT, GdkQuartzCairoContextClass))
typedef struct _GdkQuartzCairoContext GdkQuartzCairoContext;
typedef struct _GdkQuartzCairoContextClass GdkQuartzCairoContextClass;
struct _GdkQuartzCairoContext
{
GdkCairoContext parent_instance;
};
struct _GdkQuartzCairoContextClass
{
GdkCairoContextClass parent_class;
};
GDK_AVAILABLE_IN_ALL
GType gdk_quartz_cairo_context_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __GDK_QUARTZ_CAIRO_CONTEXT__ */
-482
View File
@@ -1,482 +0,0 @@
/* gdkcursor-quartz.c
*
* Copyright (C) 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/>.
*/
#include "config.h"
#include "gdkdisplay.h"
#include "gdkcursor.h"
#include "gdkcursorprivate.h"
#include "gdkquartzcursor.h"
#include "gdkprivate-quartz.h"
#include "xcursors.h"
struct _GdkQuartzCursor
{
GdkCursor cursor;
NSCursor *nscursor;
};
struct _GdkQuartzCursorClass
{
GdkCursorClass cursor_class;
};
static GdkCursor *cached_xcursors[G_N_ELEMENTS (xcursors)];
static GdkCursor *
gdk_quartz_cursor_new_from_nscursor (NSCursor *nscursor,
GdkCursorType cursor_type)
{
GdkQuartzCursor *private;
private = g_object_new (GDK_TYPE_QUARTZ_CURSOR,
"cursor-type", cursor_type,
"display", _gdk_display,
NULL);
private->nscursor = nscursor;
return GDK_CURSOR (private);
}
static GdkCursor *
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 gdk_quartz_cursor_new_from_nscursor (nscursor, GDK_BLANK_CURSOR);
}
static gboolean
get_bit (const guchar *data,
gint width,
gint height,
gint x,
gint y)
{
gint bytes_per_line;
const guchar *src;
if (x < 0 || y < 0 || x >= width || y >= height)
return FALSE;
bytes_per_line = (width + 7) / 8;
src = &data[y * bytes_per_line];
return ((src[x / 8] >> x % 8) & 1);
}
static GdkCursor *
create_builtin_cursor (GdkCursorType cursor_type)
{
GdkCursor *cursor;
NSBitmapImageRep *bitmap_rep;
NSInteger mask_width, mask_height;
gint src_width, src_height;
gint dst_stride;
const guchar *mask_start, *src_start;
gint dx, dy;
gint x, y;
NSPoint hotspot;
NSImage *image;
NSCursor *nscursor;
if (cursor_type >= G_N_ELEMENTS (xcursors) || cursor_type < 0)
return NULL;
cursor = cached_xcursors[cursor_type];
if (cursor)
return cursor;
GDK_QUARTZ_ALLOC_POOL;
src_width = xcursors[cursor_type].width;
src_height = xcursors[cursor_type].height;
mask_width = xcursors[cursor_type+1].width;
mask_height = xcursors[cursor_type+1].height;
bitmap_rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
pixelsWide:mask_width pixelsHigh:mask_height
bitsPerSample:8 samplesPerPixel:4
hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace
bytesPerRow:0 bitsPerPixel:0];
dst_stride = [bitmap_rep bytesPerRow];
src_start = xcursors[cursor_type].bits;
mask_start = xcursors[cursor_type+1].bits;
dx = xcursors[cursor_type+1].hotx - xcursors[cursor_type].hotx;
dy = xcursors[cursor_type+1].hoty - xcursors[cursor_type].hoty;
for (y = 0; y < mask_height; y++)
{
guchar *dst = [bitmap_rep bitmapData] + y * dst_stride;
for (x = 0; x < mask_width; x++)
{
if (get_bit (mask_start, mask_width, mask_height, x, y))
{
if (get_bit (src_start, src_width, src_height, x - dx, y - dy))
{
*dst++ = 0;
*dst++ = 0;
*dst++ = 0;
}
else
{
*dst++ = 0xff;
*dst++ = 0xff;
*dst++ = 0xff;
}
*dst++ = 0xff;
}
else
{
*dst++ = 0;
*dst++ = 0;
*dst++ = 0;
*dst++ = 0;
}
}
}
image = [[NSImage alloc] init];
[image addRepresentation:bitmap_rep];
[bitmap_rep release];
hotspot = NSMakePoint (xcursors[cursor_type+1].hotx,
xcursors[cursor_type+1].hoty);
nscursor = [[NSCursor alloc] initWithImage:image hotSpot:hotspot];
[image release];
cursor = gdk_quartz_cursor_new_from_nscursor (nscursor, GDK_CURSOR_IS_PIXMAP);
cached_xcursors[cursor_type] = g_object_ref (cursor);
GDK_QUARTZ_RELEASE_POOL;
return cursor;
}
GdkCursor*
_gdk_quartz_display_get_cursor_for_type (GdkDisplay *display,
GdkCursorType cursor_type)
{
NSCursor *nscursor;
g_return_val_if_fail (display == gdk_display_get_default (), NULL);
switch (cursor_type)
{
case GDK_XTERM:
nscursor = [NSCursor IBeamCursor];
break;
case GDK_SB_H_DOUBLE_ARROW:
nscursor = [NSCursor resizeLeftRightCursor];
break;
case GDK_SB_V_DOUBLE_ARROW:
nscursor = [NSCursor resizeUpDownCursor];
break;
case GDK_SB_UP_ARROW:
case GDK_BASED_ARROW_UP:
case GDK_BOTTOM_TEE:
case GDK_TOP_SIDE:
nscursor = [NSCursor resizeUpCursor];
break;
case GDK_SB_DOWN_ARROW:
case GDK_BASED_ARROW_DOWN:
case GDK_TOP_TEE:
case GDK_BOTTOM_SIDE:
nscursor = [NSCursor resizeDownCursor];
break;
case GDK_SB_LEFT_ARROW:
case GDK_RIGHT_TEE:
case GDK_LEFT_SIDE:
nscursor = [NSCursor resizeLeftCursor];
break;
case GDK_SB_RIGHT_ARROW:
case GDK_LEFT_TEE:
case GDK_RIGHT_SIDE:
nscursor = [NSCursor resizeRightCursor];
break;
case GDK_TCROSS:
case GDK_CROSS:
case GDK_CROSSHAIR:
case GDK_DIAMOND_CROSS:
nscursor = [NSCursor crosshairCursor];
break;
case GDK_HAND1:
case GDK_HAND2:
nscursor = [NSCursor pointingHandCursor];
break;
case GDK_CURSOR_IS_PIXMAP:
return NULL;
case GDK_BLANK_CURSOR:
return create_blank_cursor ();
default:
return g_object_ref (create_builtin_cursor (cursor_type));
}
[nscursor retain];
return gdk_quartz_cursor_new_from_nscursor (nscursor, cursor_type);
}
GdkCursor *
_gdk_quartz_display_get_cursor_for_surface (GdkDisplay *display,
cairo_surface_t *surface,
gdouble x,
gdouble y)
{
NSImage *image;
NSCursor *nscursor;
GdkCursor *cursor;
GdkPixbuf *pixbuf;
GDK_QUARTZ_ALLOC_POOL;
pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0,
cairo_image_surface_get_width (surface),
cairo_image_surface_get_height (surface));
image = gdk_quartz_pixbuf_to_ns_image_libgtk_only (pixbuf);
nscursor = [[NSCursor alloc] initWithImage:image hotSpot:NSMakePoint(x, y)];
cursor = gdk_quartz_cursor_new_from_nscursor (nscursor, GDK_CURSOR_IS_PIXMAP);
g_object_unref (pixbuf);
GDK_QUARTZ_RELEASE_POOL;
return cursor;
}
/* 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
- (int)_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)
@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" },
{ "n-resize", @"resizeUpCursor" },
{ "e-resize", @"resizeRightCursor" },
{ "s-resize", @"resizeDownCursor" },
{ "w-resize", @"resizeLeftCursor" },
{ "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" },
{ NULL, NULL },
};
GdkCursor*
_gdk_quartz_display_get_cursor_for_name (GdkDisplay *display,
const gchar *name)
{
NSCursor *nscursor;
const struct CursorsByName *test;
SEL selector;
if (name == NULL || g_str_equal (name, "none"))
return create_blank_cursor ();
// use this selector if nothing found
selector = @selector(arrowCursor);
for (test = cursors_by_name; test->name != NULL; test++)
if (g_str_equal (name, test->name))
{
selector = NSSelectorFromString(test->selector);
break;
}
nscursor = [[gdkCoreCursor class] performSelector:selector];
[nscursor retain];
return gdk_quartz_cursor_new_from_nscursor (nscursor, GDK_CURSOR_IS_PIXMAP);
}
G_DEFINE_TYPE (GdkQuartzCursor, gdk_quartz_cursor, GDK_TYPE_CURSOR)
static void
gdk_quartz_cursor_finalize (GObject *object)
{
GdkQuartzCursor *private = GDK_QUARTZ_CURSOR (object);
if (private->nscursor)
[private->nscursor release];
private->nscursor = NULL;
}
static void
gdk_quartz_cursor_class_init (GdkQuartzCursorClass *quartz_cursor_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (quartz_cursor_class);
object_class->finalize = gdk_quartz_cursor_finalize;
}
static void
gdk_quartz_cursor_init (GdkQuartzCursor *cursor)
{
}
gboolean
_gdk_quartz_display_supports_cursor_alpha (GdkDisplay *display)
{
return TRUE;
}
gboolean
_gdk_quartz_display_supports_cursor_color (GdkDisplay *display)
{
return TRUE;
}
void
_gdk_quartz_display_get_default_cursor_size (GdkDisplay *display,
guint *width,
guint *height)
{
/* Mac OS X doesn't have the notion of a default size */
*width = 32;
*height = 32;
}
void
_gdk_quartz_display_get_maximal_cursor_size (GdkDisplay *display,
guint *width,
guint *height)
{
/* Cursor sizes in Mac OS X can be arbitrarily large */
*width = 65536;
*height = 65536;
}
NSCursor *
_gdk_quartz_cursor_get_ns_cursor (GdkCursor *cursor)
{
GdkQuartzCursor *cursor_private;
if (!cursor)
return [NSCursor arrowCursor];
g_return_val_if_fail (GDK_IS_QUARTZ_CURSOR (cursor), NULL);
cursor_private = GDK_QUARTZ_CURSOR (cursor);
return cursor_private->nscursor;
}
-347
View File
@@ -1,347 +0,0 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
* Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
*
* 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 <gdk/gdkdeviceprivate.h>
#include <gdk/gdkdisplayprivate.h>
#import "GdkQuartzView.h"
#include "gdkquartzsurface.h"
#include "gdkquartzcursor.h"
#include "gdkprivate-quartz.h"
#include "gdkquartzdevice-core.h"
struct _GdkQuartzDeviceCore
{
GdkDevice parent_instance;
};
struct _GdkQuartzDeviceCoreClass
{
GdkDeviceClass parent_class;
};
static gboolean gdk_quartz_device_core_get_history (GdkDevice *device,
GdkSurface *window,
guint32 start,
guint32 stop,
GdkTimeCoord ***events,
gint *n_events);
static void gdk_quartz_device_core_get_state (GdkDevice *device,
GdkSurface *window,
gdouble *axes,
GdkModifierType *mask);
static void gdk_quartz_device_core_set_surface_cursor (GdkDevice *device,
GdkSurface *window,
GdkCursor *cursor);
static void gdk_quartz_device_core_warp (GdkDevice *device,
gdouble x,
gdouble y);
static void gdk_quartz_device_core_query_state (GdkDevice *device,
GdkSurface *window,
GdkSurface **root_window,
GdkSurface **child_window,
gdouble *root_x,
gdouble *root_y,
gdouble *win_x,
gdouble *win_y,
GdkModifierType *mask);
static GdkGrabStatus gdk_quartz_device_core_grab (GdkDevice *device,
GdkSurface *window,
gboolean owner_events,
GdkEventMask event_mask,
GdkSurface *confine_to,
GdkCursor *cursor,
guint32 time_);
static void gdk_quartz_device_core_ungrab (GdkDevice *device,
guint32 time_);
static GdkSurface * gdk_quartz_device_core_surface_at_position (GdkDevice *device,
gdouble *win_x,
gdouble *win_y,
GdkModifierType *mask,
gboolean get_toplevel);
G_DEFINE_TYPE (GdkQuartzDeviceCore, gdk_quartz_device_core, GDK_TYPE_DEVICE)
static void
gdk_quartz_device_core_class_init (GdkQuartzDeviceCoreClass *klass)
{
GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
device_class->get_history = gdk_quartz_device_core_get_history;
device_class->get_state = gdk_quartz_device_core_get_state;
device_class->set_surface_cursor = gdk_quartz_device_core_set_surface_cursor;
device_class->warp = gdk_quartz_device_core_warp;
device_class->query_state = gdk_quartz_device_core_query_state;
device_class->grab = gdk_quartz_device_core_grab;
device_class->ungrab = gdk_quartz_device_core_ungrab;
device_class->surface_at_position = gdk_quartz_device_core_surface_at_position;
}
static void
gdk_quartz_device_core_init (GdkQuartzDeviceCore *quartz_device_core)
{
GdkDevice *device;
device = GDK_DEVICE (quartz_device_core);
_gdk_device_add_axis (device, NULL, GDK_AXIS_X, 0, 0, 1);
_gdk_device_add_axis (device, NULL, GDK_AXIS_Y, 0, 0, 1);
}
static gboolean
gdk_quartz_device_core_get_history (GdkDevice *device,
GdkSurface *window,
guint32 start,
guint32 stop,
GdkTimeCoord ***events,
gint *n_events)
{
return FALSE;
}
static void
gdk_quartz_device_core_get_state (GdkDevice *device,
GdkSurface *window,
gdouble *axes,
GdkModifierType *mask)
{
gdouble x_pos, y_pos;
gdk_surface_get_device_position (window, device, &x_pos, &y_pos, mask);
if (axes)
{
axes[0] = x_pos;
axes[1] = y_pos;
}
}
static void
translate_coords_to_child_coords (GdkSurface *parent,
GdkSurface *child,
gint *x,
gint *y)
{
GdkSurface *current = child;
if (child == parent)
return;
while (current != parent)
{
gint tmp_x, tmp_y;
gdk_surface_get_origin (current, &tmp_x, &tmp_y);
*x -= tmp_x;
*y -= tmp_y;
current = gdk_surface_get_parent (current);
}
}
static void
gdk_quartz_device_core_set_surface_cursor (GdkDevice *device,
GdkSurface *window,
GdkCursor *cursor)
{
NSCursor *nscursor;
if (GDK_SURFACE_DESTROYED (window))
return;
nscursor = _gdk_quartz_cursor_get_ns_cursor (cursor);
[nscursor set];
}
static void
gdk_quartz_device_core_warp (GdkDevice *device,
gdouble x,
gdouble y)
{
CGDisplayMoveCursorToPoint (CGMainDisplayID (), CGPointMake (x, y));
}
static GdkSurface *
gdk_quartz_device_core_query_state_helper (GdkSurface *window,
GdkDevice *device,
gdouble *x,
gdouble *y,
GdkModifierType *mask)
{
GdkSurface *toplevel;
NSPoint point;
gint x_tmp, y_tmp;
GdkSurface *found_window;
g_return_val_if_fail (window == NULL || GDK_IS_SURFACE (window), NULL);
if (GDK_SURFACE_DESTROYED (window))
{
*x = 0;
*y = 0;
*mask = 0;
return NULL;
}
toplevel = gdk_surface_get_toplevel (window);
if (mask)
*mask = _gdk_quartz_events_get_current_keyboard_modifiers () |
_gdk_quartz_events_get_current_mouse_modifiers ();
/* Get the y coordinate, needs to be flipped. */
if (window == _gdk_root)
{
point = [NSEvent mouseLocation];
_gdk_quartz_surface_nspoint_to_gdk_xy (point, &x_tmp, &y_tmp);
}
else
{
GdkSurfaceImplQuartz *impl;
NSWindow *nswindow;
impl = GDK_SURFACE_IMPL_QUARTZ (toplevel->impl);
nswindow = impl->toplevel;
point = [nswindow mouseLocationOutsideOfEventStream];
x_tmp = point.x;
y_tmp = toplevel->height - point.y;
window = toplevel;
}
found_window = _gdk_quartz_surface_find_child (window, x_tmp, y_tmp,
FALSE);
if (found_window == _gdk_root)
found_window = NULL;
else if (found_window)
translate_coords_to_child_coords (window, found_window,
&x_tmp, &y_tmp);
if (x)
*x = x_tmp;
if (y)
*y = y_tmp;
return found_window;
}
static void
gdk_quartz_device_core_query_state (GdkDevice *device,
GdkSurface *window,
GdkSurface **child_window,
gdouble *root_x,
gdouble *root_y,
gdouble *win_x,
gdouble *win_y,
GdkModifierType *mask)
{
GdkSurface *found_window;
NSPoint point;
gint x_tmp, y_tmp;
if (window == NULL)
window = _gdk_root;
found_window = gdk_quartz_device_core_query_state_helper (window, device,
win_x, win_y,
mask);
if (root_window)
*root_window = _gdk_root;
if (child_window)
*child_window = found_window;
point = [NSEvent mouseLocation];
_gdk_quartz_surface_nspoint_to_gdk_xy (point, &x_tmp, &y_tmp);
if (root_x)
*root_x = x_tmp;
if (root_y)
*root_y = y_tmp;
}
static GdkGrabStatus
gdk_quartz_device_core_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_quartz_device_core_ungrab (GdkDevice *device,
guint32 time_)
{
GdkDeviceGrabInfo *grab;
grab = _gdk_display_get_last_device_grab (_gdk_display, device);
if (grab)
grab->serial_end = 0;
_gdk_display_device_grab_update (_gdk_display, device, NULL, 0);
}
static GdkSurface *
gdk_quartz_device_core_surface_at_position (GdkDevice *device,
gdouble *win_x,
gdouble *win_y,
GdkModifierType *mask,
gboolean get_toplevel)
{
GdkSurface *found_window;
NSPoint point;
gint x_tmp, y_tmp;
/* Get mouse coordinates, find window under the mouse pointer */
point = [NSEvent mouseLocation];
_gdk_quartz_surface_nspoint_to_gdk_xy (point, &x_tmp, &y_tmp);
found_window = _gdk_quartz_surface_find_child (_gdk_root, x_tmp, y_tmp, get_toplevel);
if (found_window)
translate_coords_to_child_coords (_gdk_root, found_window, &x_tmp, &y_tmp);
if (win_x)
*win_x = found_window ? x_tmp : -1;
if (win_y)
*win_y = found_window ? y_tmp : -1;
if (mask)
*mask = _gdk_quartz_events_get_current_keyboard_modifiers () |
_gdk_quartz_events_get_current_mouse_modifiers ();
return found_window;
}
-119
View File
@@ -1,119 +0,0 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
*
* 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 <gdk/gdktypes.h>
#include <gdk/gdkdevicemanager.h>
#include <gdk/gdkdeviceprivate.h>
#include <gdk/gdkseatdefaultprivate.h>
#include <gdk/gdkdevicemanagerprivate.h>
#include "gdkdevicemanager-core-quartz.h"
#include "gdkquartzdevice-core.h"
#include "gdkkeysyms.h"
#include "gdkprivate-quartz.h"
#define HAS_FOCUS(toplevel) \
((toplevel)->has_focus || (toplevel)->has_pointer_focus)
static void gdk_quartz_device_manager_core_finalize (GObject *object);
static void gdk_quartz_device_manager_core_constructed (GObject *object);
static GdkDevice * gdk_quartz_device_manager_core_get_client_pointer (GdkDeviceManager *device_manager);
G_DEFINE_TYPE (GdkQuartzDeviceManagerCore, gdk_quartz_device_manager_core, G_TYPE_OBJECT)
static void
gdk_quartz_device_manager_core_class_init (GdkQuartzDeviceManagerCoreClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gdk_quartz_device_manager_core_finalize;
object_class->constructed = gdk_quartz_device_manager_core_constructed;
}
static GdkDevice *
create_core_pointer (GdkQuartzDeviceManagerCore *device_manager,
GdkDisplay *display)
{
return g_object_new (GDK_TYPE_QUARTZ_DEVICE_CORE,
"name", "Core Pointer",
"type", GDK_DEVICE_TYPE_LOGICAL,
"input-source", GDK_SOURCE_MOUSE,
"input-mode", GDK_MODE_SCREEN,
"has-cursor", TRUE,
"display", display,
"device-manager", device_manager,
NULL);
}
static GdkDevice *
create_core_keyboard (GdkQuartzDeviceManagerCore *device_manager,
GdkDisplay *display)
{
return g_object_new (GDK_TYPE_QUARTZ_DEVICE_CORE,
"name", "Core Keyboard",
"type", GDK_DEVICE_TYPE_LOGICAL,
"input-source", GDK_SOURCE_KEYBOARD,
"input-mode", GDK_MODE_SCREEN,
"has-cursor", FALSE,
"display", display,
"device-manager", device_manager,
NULL);
}
static void
gdk_quartz_device_manager_core_init (GdkQuartzDeviceManagerCore *device_manager)
{
}
static void
gdk_quartz_device_manager_core_finalize (GObject *object)
{
GdkQuartzDeviceManagerCore *quartz_device_manager_core;
quartz_device_manager_core = GDK_QUARTZ_DEVICE_MANAGER_CORE (object);
g_object_unref (quartz_device_manager_core->core_pointer);
g_object_unref (quartz_device_manager_core->core_keyboard);
G_OBJECT_CLASS (gdk_quartz_device_manager_core_parent_class)->finalize (object);
}
static void
gdk_quartz_device_manager_core_constructed (GObject *object)
{
GdkQuartzDeviceManagerCore *device_manager;
GdkDisplay *display;
GdkSeat *seat;
display = _gdk_display;
device_manager = GDK_QUARTZ_DEVICE_MANAGER_CORE (object);
device_manager->core_pointer = create_core_pointer (GDK_DEVICE_MANAGER (device_manager), display);
device_manager->core_keyboard = create_core_keyboard (GDK_DEVICE_MANAGER (device_manager), display);
_gdk_device_set_associated_device (device_manager->core_pointer, device_manager->core_keyboard);
_gdk_device_set_associated_device (device_manager->core_keyboard, device_manager->core_pointer);
seat = gdk_seat_default_new_for_logical_pair (device_manager->core_pointer,
device_manager->core_keyboard);
gdk_display_add_seat (display, seat);
g_object_unref (seat);
}
-243
View File
@@ -1,243 +0,0 @@
/* gdkdisplay-quartz.c
*
* Copyright (C) 2005 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/>.
*/
#include "config.h"
#include <gdk/gdk.h>
#include <gdk/gdkdisplayprivate.h>
#include "gdkprivate-quartz.h"
#include "gdkquartzscreen.h"
#include "gdkquartzsurface.h"
#include "gdkquartzdisplay.h"
#include "gdkquartzdevicemanager-core.h"
#include "gdkmonitorprivate.h"
#include "gdkdisplay-quartz.h"
#include "gdkcairocontext-quartz.h"
static GdkSurface *
gdk_quartz_display_get_default_group (GdkDisplay *display)
{
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
/* FIXME: Implement */
return NULL;
}
GdkDeviceManager *
_gdk_device_manager_new (GdkDisplay *display)
{
return g_object_new (GDK_TYPE_QUARTZ_DEVICE_MANAGER_CORE,
"display", display,
NULL);
}
GdkDisplay *
_gdk_quartz_display_open (const gchar *display_name)
{
if (_gdk_display != NULL)
return NULL;
_gdk_display = g_object_new (gdk_quartz_display_get_type (), NULL);
_gdk_device_manager = _gdk_device_manager_new (_gdk_display);
_gdk_screen = g_object_new (gdk_quartz_screen_get_type (), NULL);
_gdk_quartz_surface_init_windowing (_gdk_display);
_gdk_quartz_events_init ();
/* Initialize application */
[NSApplication sharedApplication];
#if 0
/* FIXME: Remove the #if 0 when we have these functions */
_gdk_quartz_dnd_init ();
#endif
g_signal_emit_by_name (_gdk_display, "opened");
return _gdk_display;
}
static const gchar *
gdk_quartz_display_get_name (GdkDisplay *display)
{
static gchar *display_name = NULL;
if (!display_name)
{
GDK_QUARTZ_ALLOC_POOL;
display_name = g_strdup ([[[NSHost currentHost] name] UTF8String]);
GDK_QUARTZ_RELEASE_POOL;
}
return display_name;
}
static void
gdk_quartz_display_beep (GdkDisplay *display)
{
g_return_if_fail (GDK_IS_DISPLAY (display));
NSBeep();
}
static void
gdk_quartz_display_sync (GdkDisplay *display)
{
/* Not supported. */
}
static void
gdk_quartz_display_flush (GdkDisplay *display)
{
/* Not supported. */
}
static gboolean
gdk_quartz_display_supports_shapes (GdkDisplay *display)
{
/* FIXME: Implement */
return FALSE;
}
static gboolean
gdk_quartz_display_supports_input_shapes (GdkDisplay *display)
{
/* FIXME: Implement */
return FALSE;
}
static gulong
gdk_quartz_display_get_next_serial (GdkDisplay *display)
{
return 0;
}
static void
gdk_quartz_display_notify_startup_complete (GdkDisplay *display,
const gchar *startup_id)
{
/* FIXME: Implement? */
}
static int
gdk_quartz_display_get_n_monitors (GdkDisplay *display)
{
GdkQuartzDisplay *quartz_display = GDK_QUARTZ_DISPLAY (display);
return quartz_display->monitors->len;
}
static GdkMonitor *
gdk_quartz_display_get_monitor (GdkDisplay *display,
int monitor_num)
{
GdkQuartzDisplay *quartz_display = GDK_QUARTZ_DISPLAY (display);
if (0 <= monitor_num || monitor_num < quartz_display->monitors->len)
return (GdkMonitor *)quartz_display->monitors->pdata[monitor_num];
return NULL;
}
static gboolean
gdk_quartz_display_get_setting (GdkDisplay *display,
const gchar *name,
GValue *value)
{
return _gdk_quartz_get_setting (name, value);
}
G_DEFINE_TYPE (GdkQuartzDisplay, gdk_quartz_display, GDK_TYPE_DISPLAY)
static void
gdk_quartz_display_init (GdkQuartzDisplay *display)
{
GDK_QUARTZ_ALLOC_POOL;
display->monitors = g_ptr_array_new_with_free_func (g_object_unref);
GDK_QUARTZ_RELEASE_POOL;
}
static void
gdk_quartz_display_dispose (GObject *object)
{
GdkQuartzDisplay *display_quartz = GDK_QUARTZ_DISPLAY (object);
g_ptr_array_free (display_quartz->monitors, TRUE);
G_OBJECT_CLASS (gdk_quartz_display_parent_class)->dispose (object);
}
static void
gdk_quartz_display_finalize (GObject *object)
{
GdkQuartzDisplay *display_quartz = GDK_QUARTZ_DISPLAY (object);
G_OBJECT_CLASS (gdk_quartz_display_parent_class)->finalize (object);
}
static void
gdk_quartz_display_class_init (GdkQuartzDisplayClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GdkDisplayClass *display_class = GDK_DISPLAY_CLASS (class);
object_class->finalize = gdk_quartz_display_finalize;
object_class->dispose = gdk_quartz_display_dispose;
display_class->surface_type = GDK_TYPE_QUARTZ_SURFACE;
display_class->cairo_context_type = GDK_TYPE_QUARTZ_CAIRO_CONTEXT;
display_class->get_name = gdk_quartz_display_get_name;
display_class->beep = gdk_quartz_display_beep;
display_class->sync = gdk_quartz_display_sync;
display_class->flush = gdk_quartz_display_flush;
display_class->queue_events = _gdk_quartz_display_queue_events;
display_class->has_pending = _gdk_quartz_display_has_pending;
display_class->get_default_group = gdk_quartz_display_get_default_group;
display_class->supports_shapes = gdk_quartz_display_supports_shapes;
display_class->supports_input_shapes = gdk_quartz_display_supports_input_shapes;
display_class->get_default_cursor_size = _gdk_quartz_display_get_default_cursor_size;
display_class->get_maximal_cursor_size = _gdk_quartz_display_get_maximal_cursor_size;
display_class->supports_cursor_alpha = _gdk_quartz_display_supports_cursor_alpha;
display_class->supports_cursor_color = _gdk_quartz_display_supports_cursor_color;
display_class->get_next_serial = gdk_quartz_display_get_next_serial;
display_class->notify_startup_complete = gdk_quartz_display_notify_startup_complete;
display_class->event_data_copy = _gdk_quartz_display_event_data_copy;
display_class->event_data_free = _gdk_quartz_display_event_data_free;
display_class->create_surface_impl = _gdk_quartz_display_create_surface_impl;
display_class->get_keymap = _gdk_quartz_display_get_keymap;
display_class->get_n_monitors = gdk_quartz_display_get_n_monitors;
display_class->get_monitor = gdk_quartz_display_get_monitor;
display_class->get_setting = gdk_quartz_display_get_setting;
ProcessSerialNumber psn = { 0, kCurrentProcess };
/* Make the current process a foreground application, i.e. an app
* with a user interface, in case we're not running from a .app bundle
*/
TransformProcessType (&psn, kProcessTransformToForegroundApplication);
}
-77
View File
@@ -1,77 +0,0 @@
/*
* gdkdisplay-quartz.h
*
* Copyright 2017 Tom Schoonjans
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_QUARTZ_DISPLAY__
#define __GDK_QUARTZ_DISPLAY__
#include "gdkdisplayprivate.h"
#include "gdkkeys.h"
#include "gdksurface.h"
#include "gdkinternals.h"
G_BEGIN_DECLS
struct _GdkQuartzDisplay
{
GdkDisplay parent_instance;
GPtrArray *monitors;
};
struct _GdkQuartzDisplayClass
{
GdkDisplayClass parent_class;
};
/* Display methods - events */
void _gdk_quartz_display_queue_events (GdkDisplay *display);
gboolean _gdk_quartz_display_has_pending (GdkDisplay *display);
void _gdk_quartz_display_event_data_copy (GdkDisplay *display,
const GdkEvent *src,
GdkEvent *dst);
void _gdk_quartz_display_event_data_free (GdkDisplay *display,
GdkEvent *event);
/* Display methods - cursor */
gboolean _gdk_quartz_display_supports_cursor_alpha (GdkDisplay *display);
gboolean _gdk_quartz_display_supports_cursor_color (GdkDisplay *display);
void _gdk_quartz_display_get_default_cursor_size (GdkDisplay *display,
guint *width,
guint *height);
void _gdk_quartz_display_get_maximal_cursor_size (GdkDisplay *display,
guint *width,
guint *height);
/* Display methods - window */
void _gdk_quartz_display_before_process_all_updates (GdkDisplay *display);
void _gdk_quartz_display_after_process_all_updates (GdkDisplay *display);
void _gdk_quartz_display_create_surface_impl (GdkDisplay *display,
GdkSurface *window,
GdkSurface *real_parent,
GdkSurfaceAttr *attributes);
/* Display methods - keymap */
GdkKeymap * _gdk_quartz_display_get_keymap (GdkDisplay *display);
G_END_DECLS
#endif /* __GDK_QUARTZ_DISPLAY__ */
-61
View File
@@ -1,61 +0,0 @@
/* GDK - The GIMP Drawing Kit
* gdkdisplaymanager-quartz.c
*
* Copyright (C) 2005 Imendio AB
* Copyright 2010 Red Hat, Inc.
*
* Author: Matthias clasen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <ApplicationServices/ApplicationServices.h>
#include "gdkquartzdisplay.h"
#include "gdkquartzdisplaymanager.h"
#include "gdkprivate-quartz.h"
#include "gdkdisplaymanagerprivate.h"
#include "gdkinternals.h"
struct _GdkQuartzDisplayManager
{
GdkDisplayManager parent;
};
G_DEFINE_TYPE (GdkQuartzDisplayManager, gdk_quartz_display_manager, GDK_TYPE_DISPLAY_MANAGER)
static void
gdk_quartz_display_manager_init (GdkQuartzDisplayManager *manager)
{
}
static void
gdk_quartz_display_manager_finalize (GObject *object)
{
g_error ("A GdkQuartzDisplayManager object was finalized. This should not happen");
G_OBJECT_CLASS (gdk_quartz_display_manager_parent_class)->finalize (object);
}
static void
gdk_quartz_display_manager_class_init (GdkQuartzDisplayManagerClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GdkDisplayManagerClass *manager_class = GDK_DISPLAY_MANAGER_CLASS (class);
object_class->finalize = gdk_quartz_display_manager_finalize;
}
-99
View File
@@ -1,99 +0,0 @@
/* gdkdnd-quartz.c
*
* Copyright (C) 2005 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/>.
*/
#include "config.h"
#include "gdkdnd.h"
#include "gdkquartzdnd.h"
#include "gdkprivate-quartz.h"
G_DEFINE_TYPE (GdkQuartzDragContext, gdk_quartz_drag_context, GDK_TYPE_DRAG_CONTEXT)
GdkDragContext *_gdk_quartz_drag_source_context = NULL;
GdkDragContext *
gdk_quartz_drag_source_context_libgtk_only ()
{
return _gdk_quartz_drag_source_context;
}
GdkDragContext *
_gdk_quartz_surface_drag_begin (GdkSurface *window,
GdkDevice *device,
GList *targets,
gint dx,
gint dy)
{
g_assert (_gdk_quartz_drag_source_context == NULL);
/* Create fake context */
_gdk_quartz_drag_source_context = g_object_new (GDK_TYPE_QUARTZ_DRAG_CONTEXT,
"device", device,
NULL);
_gdk_quartz_drag_source_context->source_surface = window;
g_object_ref (window);
_gdk_quartz_drag_source_context->targets = targets;
return _gdk_quartz_drag_source_context;
}
static void
gdk_quartz_drag_context_drag_drop (GdkDragContext *context,
guint32 time)
{
/* FIXME: Implement */
}
static void
gdk_quartz_drag_context_drag_abort (GdkDragContext *context,
guint32 time)
{
/* FIXME: Implement */
}
id
gdk_quartz_drag_context_get_dragging_info_libgtk_only (GdkDragContext *context)
{
return GDK_QUARTZ_DRAG_CONTEXT (context)->dragging_info;
}
static void
gdk_quartz_drag_context_init (GdkQuartzDragContext *context)
{
}
static void
gdk_quartz_drag_context_finalize (GObject *object)
{
G_OBJECT_CLASS (gdk_quartz_drag_context_parent_class)->finalize (object);
}
static void
gdk_quartz_drag_context_class_init (GdkQuartzDragContextClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdkDragContextClass *context_class = GDK_DRAG_CONTEXT_CLASS (klass);
object_class->finalize = gdk_quartz_drag_context_finalize;
context_class->drag_abort = gdk_quartz_drag_context_drag_abort;
context_class->drag_drop = gdk_quartz_drag_context_drag_drop;
}
File diff suppressed because it is too large Load Diff
-39
View File
@@ -1,39 +0,0 @@
/* GDK - The GIMP Drawing Kit
*
* gdkglcontext-quartz.c: Quartz specific OpenGL wrappers
*
* Copyright © 2014 Emmanuele Bassi
* Copyright © 2014 Alexander Larsson
* Copyright © 2014 Brion Vibber
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gdkglcontext-quartz.h"
#include "gdkintl.h"
GdkGLContext *
gdk_quartz_surface_create_gl_context (GdkSurface *window,
gboolean attached,
GdkGLContext *share,
GError **error)
{
/* FIXME: implement */
g_set_error_literal (error, GDK_GL_ERROR, GDK_GL_ERROR_NOT_AVAILABLE,
_("Not implemented on OS X"));
return NULL;
}
-39
View File
@@ -1,39 +0,0 @@
/* GDK - The GIMP Drawing Kit
*
* gdkglcontext-quartz.h: Private Quartz specific OpenGL wrappers
*
* Copyright © 2014 Emmanuele Bassi
* Copyright © 2014 Red Hat, Int
* Copyright © 2014 Brion Vibber
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_QUARTZ_GL_CONTEXT__
#define __GDK_QUARTZ_GL_CONTEXT__
#include "gdkglcontextprivate.h"
#include "gdksurface.h"
#include "gdkinternals.h"
G_BEGIN_DECLS
GdkGLContext * gdk_quartz_surface_create_gl_context (GdkSurface *window,
gboolean attach,
GdkGLContext *share,
GError **error);
G_END_DECLS
#endif /* __GDK_QUARTZ_GL_CONTEXT__ */
-47
View File
@@ -1,47 +0,0 @@
/* gdkglobals-quartz.c
*
* Copyright (C) 2005 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/>.
*/
#include "config.h"
#include "gdktypes.h"
#include "gdkquartz.h"
#include "gdkscreen-quartz.h"
GdkDisplay *_gdk_display = NULL;
GdkQuartzScreen *_gdk_screen = NULL;
GdkSurface *_gdk_root = NULL;
GdkDeviceManager *_gdk_device_manager = NULL;
GdkOSXVersion
gdk_quartz_osx_version (void)
{
static gint32 minor = GDK_OSX_UNSUPPORTED;
if (minor == GDK_OSX_UNSUPPORTED)
{
OSErr err = Gestalt (gestaltSystemVersionMinor, (SInt32*)&minor);
g_return_val_if_fail (err == noErr, GDK_OSX_UNSUPPORTED);
}
if (minor < GDK_OSX_MIN)
return GDK_OSX_UNSUPPORTED;
else if (minor > GDK_OSX_CURRENT)
return GDK_OSX_NEW;
else
return minor;
}
-850
View File
@@ -1,850 +0,0 @@
/* gdkkeys-quartz.c
*
* Copyright (C) 2000 Red Hat, Inc.
* Copyright (C) 2005 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/>.
*/
/* Some parts of this code come from quartzKeyboard.c,
* from the Apple X11 Server.
*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
* HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name(s) of the above
* copyright holders shall not be used in advertising or otherwise to
* promote the sale, use or other dealings in this Software without
* prior written authorization.
*/
#include "config.h"
#include <Carbon/Carbon.h>
#include <AppKit/NSEvent.h>
#include "gdk.h"
#include "gdkquartzkeys.h"
#include "gdkkeysprivate.h"
#include "gdkkeysyms.h"
#define NUM_KEYCODES 128
#define KEYVALS_PER_KEYCODE 4
static GdkKeymap *default_keymap = NULL;
struct _GdkQuartzKeymap
{
GdkKeymap keymap;
};
struct _GdkQuartzKeymapClass
{
GdkKeymapClass keymap_class;
};
G_DEFINE_TYPE (GdkQuartzKeymap, gdk_quartz_keymap, GDK_TYPE_KEYMAP)
GdkKeymap *
_gdk_quartz_display_get_keymap (GdkDisplay *display)
{
if (default_keymap == NULL)
default_keymap = g_object_new (gdk_quartz_keymap_get_type (), NULL);
return default_keymap;
}
/* This is a table of all keyvals. Each keycode gets KEYVALS_PER_KEYCODE entries.
* TThere is 1 keyval per modifier (Nothing, Shift, Alt, Shift+Alt);
*/
static guint *keyval_array = NULL;
static inline UniChar
macroman2ucs (unsigned char c)
{
/* Precalculated table mapping MacRoman-128 to Unicode. Generated
by creating single element CFStringRefs then extracting the
first character. */
static const unsigned short table[128] = {
0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1,
0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8,
0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3,
0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc,
0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 0xdf,
0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 0xd8,
0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 0x2211,
0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 0xf8,
0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 0xab,
0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 0x153,
0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 0x25ca,
0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02,
0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 0xc1,
0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4,
0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 0x2dc,
0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 0x2c7
};
if (c < 128)
return c;
else
return table[c - 128];
}
const static struct {
guint keycode;
guint keyval;
unsigned int modmask; /* So we can tell when a mod key is pressed/released */
} modifier_keys[] = {
{ 54, GDK_KEY_Meta_R, NSCommandKeyMask },
{ 55, GDK_KEY_Meta_L, NSCommandKeyMask },
{ 56, GDK_KEY_Shift_L, NSShiftKeyMask },
{ 57, GDK_KEY_Caps_Lock, NSAlphaShiftKeyMask },
{ 58, GDK_KEY_Alt_L, NSAlternateKeyMask },
{ 59, GDK_KEY_Control_L, NSControlKeyMask },
{ 60, GDK_KEY_Shift_R, NSShiftKeyMask },
{ 61, GDK_KEY_Alt_R, NSAlternateKeyMask },
{ 62, GDK_KEY_Control_R, NSControlKeyMask }
};
const static struct {
guint keycode;
guint keyval;
} function_keys[] = {
{ 122, GDK_KEY_F1 },
{ 120, GDK_KEY_F2 },
{ 99, GDK_KEY_F3 },
{ 118, GDK_KEY_F4 },
{ 96, GDK_KEY_F5 },
{ 97, GDK_KEY_F6 },
{ 98, GDK_KEY_F7 },
{ 100, GDK_KEY_F8 },
{ 101, GDK_KEY_F9 },
{ 109, GDK_KEY_F10 },
{ 103, GDK_KEY_F11 },
{ 111, GDK_KEY_F12 },
{ 105, GDK_KEY_F13 },
{ 107, GDK_KEY_F14 },
{ 113, GDK_KEY_F15 },
{ 106, GDK_KEY_F16 }
};
const static struct {
guint keycode;
guint normal_keyval, keypad_keyval;
} known_numeric_keys[] = {
{ 65, GDK_KEY_period, GDK_KEY_KP_Decimal },
{ 67, GDK_KEY_asterisk, GDK_KEY_KP_Multiply },
{ 69, GDK_KEY_plus, GDK_KEY_KP_Add },
{ 75, GDK_KEY_slash, GDK_KEY_KP_Divide },
{ 76, GDK_KEY_Return, GDK_KEY_KP_Enter },
{ 78, GDK_KEY_minus, GDK_KEY_KP_Subtract },
{ 81, GDK_KEY_equal, GDK_KEY_KP_Equal },
{ 82, GDK_KEY_0, GDK_KEY_KP_0 },
{ 83, GDK_KEY_1, GDK_KEY_KP_1 },
{ 84, GDK_KEY_2, GDK_KEY_KP_2 },
{ 85, GDK_KEY_3, GDK_KEY_KP_3 },
{ 86, GDK_KEY_4, GDK_KEY_KP_4 },
{ 87, GDK_KEY_5, GDK_KEY_KP_5 },
{ 88, GDK_KEY_6, GDK_KEY_KP_6 },
{ 89, GDK_KEY_7, GDK_KEY_KP_7 },
{ 91, GDK_KEY_8, GDK_KEY_KP_8 },
{ 92, GDK_KEY_9, GDK_KEY_KP_9 }
};
/* These values aren't covered by gdk_unicode_to_keyval */
const static struct {
gunichar ucs_value;
guint keyval;
} special_ucs_table [] = {
{ 0x0001, GDK_KEY_Home },
{ 0x0003, GDK_KEY_Return },
{ 0x0004, GDK_KEY_End },
{ 0x0008, GDK_KEY_BackSpace },
{ 0x0009, GDK_KEY_Tab },
{ 0x000b, GDK_KEY_Page_Up },
{ 0x000c, GDK_KEY_Page_Down },
{ 0x000d, GDK_KEY_Return },
{ 0x001b, GDK_KEY_Escape },
{ 0x001c, GDK_KEY_Left },
{ 0x001d, GDK_KEY_Right },
{ 0x001e, GDK_KEY_Up },
{ 0x001f, GDK_KEY_Down },
{ 0x007f, GDK_KEY_Delete },
{ 0xf027, GDK_KEY_dead_acute },
{ 0xf060, GDK_KEY_dead_grave },
{ 0xf300, GDK_KEY_dead_grave },
{ 0xf0b4, GDK_KEY_dead_acute },
{ 0xf301, GDK_KEY_dead_acute },
{ 0xf385, GDK_KEY_dead_acute },
{ 0xf05e, GDK_KEY_dead_circumflex },
{ 0xf2c6, GDK_KEY_dead_circumflex },
{ 0xf302, GDK_KEY_dead_circumflex },
{ 0xf07e, GDK_KEY_dead_tilde },
{ 0xf2dc, GDK_KEY_dead_tilde },
{ 0xf303, GDK_KEY_dead_tilde },
{ 0xf342, GDK_KEY_dead_perispomeni },
{ 0xf0af, GDK_KEY_dead_macron },
{ 0xf304, GDK_KEY_dead_macron },
{ 0xf2d8, GDK_KEY_dead_breve },
{ 0xf306, GDK_KEY_dead_breve },
{ 0xf2d9, GDK_KEY_dead_abovedot },
{ 0xf307, GDK_KEY_dead_abovedot },
{ 0xf0a8, GDK_KEY_dead_diaeresis },
{ 0xf308, GDK_KEY_dead_diaeresis },
{ 0xf2da, GDK_KEY_dead_abovering },
{ 0xf30A, GDK_KEY_dead_abovering },
{ 0xf022, GDK_KEY_dead_doubleacute },
{ 0xf2dd, GDK_KEY_dead_doubleacute },
{ 0xf30B, GDK_KEY_dead_doubleacute },
{ 0xf2c7, GDK_KEY_dead_caron },
{ 0xf30C, GDK_KEY_dead_caron },
{ 0xf0be, GDK_KEY_dead_cedilla },
{ 0xf327, GDK_KEY_dead_cedilla },
{ 0xf2db, GDK_KEY_dead_ogonek },
{ 0xf328, GDK_KEY_dead_ogonek },
{ 0xfe5d, GDK_KEY_dead_iota },
{ 0xf323, GDK_KEY_dead_belowdot },
{ 0xf309, GDK_KEY_dead_hook },
{ 0xf31B, GDK_KEY_dead_horn },
{ 0xf02d, GDK_KEY_dead_stroke },
{ 0xf335, GDK_KEY_dead_stroke },
{ 0xf336, GDK_KEY_dead_stroke },
{ 0xf313, GDK_KEY_dead_abovecomma },
/* { 0xf313, GDK_KEY_dead_psili }, */
{ 0xf314, GDK_KEY_dead_abovereversedcomma },
/* { 0xf314, GDK_KEY_dead_dasia }, */
{ 0xf30F, GDK_KEY_dead_doublegrave },
{ 0xf325, GDK_KEY_dead_belowring },
{ 0xf2cd, GDK_KEY_dead_belowmacron },
{ 0xf331, GDK_KEY_dead_belowmacron },
{ 0xf32D, GDK_KEY_dead_belowcircumflex },
{ 0xf330, GDK_KEY_dead_belowtilde },
{ 0xf32E, GDK_KEY_dead_belowbreve },
{ 0xf324, GDK_KEY_dead_belowdiaeresis },
{ 0xf311, GDK_KEY_dead_invertedbreve },
{ 0xf02c, GDK_KEY_dead_belowcomma },
{ 0xf326, GDK_KEY_dead_belowcomma }
};
static void
update_keymap (void)
{
const void *chr_data = NULL;
guint *p;
int i;
/* Note: we could check only if building against the 10.5 SDK instead, but
* that would make non-xml layouts not work in 32-bit which would be a quite
* bad regression. This way, old unsupported layouts will just not work in
* 64-bit.
*/
#ifdef __LP64__
TISInputSourceRef new_layout = TISCopyCurrentKeyboardLayoutInputSource ();
CFDataRef layout_data_ref;
#else
KeyboardLayoutRef new_layout;
KeyboardLayoutKind layout_kind;
KLGetCurrentKeyboardLayout (&new_layout);
#endif
g_free (keyval_array);
keyval_array = g_new0 (guint, NUM_KEYCODES * KEYVALS_PER_KEYCODE);
#ifdef __LP64__
layout_data_ref = (CFDataRef) TISGetInputSourceProperty
(new_layout, kTISPropertyUnicodeKeyLayoutData);
if (layout_data_ref)
chr_data = CFDataGetBytePtr (layout_data_ref);
if (chr_data == NULL)
{
g_error ("cannot get keyboard layout data");
return;
}
#else
/* Get the layout kind */
KLGetKeyboardLayoutProperty (new_layout, kKLKind, (const void **)&layout_kind);
/* 8-bit-only keyabord layout */
if (layout_kind == kKLKCHRKind)
{
/* Get chr data */
KLGetKeyboardLayoutProperty (new_layout, kKLKCHRData, (const void **)&chr_data);
for (i = 0; i < NUM_KEYCODES; i++)
{
int j;
UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
p = keyval_array + i * KEYVALS_PER_KEYCODE;
for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
{
UInt32 c, state = 0;
UInt16 key_code;
UniChar uc;
key_code = modifiers[j] | i;
c = KeyTranslate (chr_data, key_code, &state);
if (state != 0)
{
UInt32 state2 = 0;
c = KeyTranslate (chr_data, key_code | 128, &state2);
}
if (c != 0 && c != 0x10)
{
int k;
gboolean found = FALSE;
/* FIXME: some keyboard layouts (e.g. Russian) use a
* different 8-bit character set. We should check
* for this. Not a serious problem, because most
* (all?) of these layouts also have a uchr version.
*/
uc = macroman2ucs (c);
for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++)
{
if (special_ucs_table[k].ucs_value == uc)
{
p[j] = special_ucs_table[k].keyval;
found = TRUE;
break;
}
}
/* Special-case shift-tab since GTK+ expects
* GDK_KEY_ISO_Left_Tab for that.
*/
if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
p[j] = GDK_KEY_ISO_Left_Tab;
if (!found)
p[j] = gdk_unicode_to_keyval (uc);
}
}
if (p[3] == p[2])
p[3] = 0;
if (p[2] == p[1])
p[2] = 0;
if (p[1] == p[0])
p[1] = 0;
if (p[0] == p[2] &&
p[1] == p[3])
p[2] = p[3] = 0;
}
}
/* unicode keyboard layout */
else if (layout_kind == kKLKCHRuchrKind || layout_kind == kKLuchrKind)
{
/* Get chr data */
KLGetKeyboardLayoutProperty (new_layout, kKLuchrData, (const void **)&chr_data);
#endif
for (i = 0; i < NUM_KEYCODES; i++)
{
int j;
UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
UniChar chars[4];
UniCharCount nChars;
p = keyval_array + i * KEYVALS_PER_KEYCODE;
for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
{
UInt32 state = 0;
OSStatus err;
UInt16 key_code;
UniChar uc;
key_code = modifiers[j] | i;
err = UCKeyTranslate (chr_data, i, kUCKeyActionDisplay,
(modifiers[j] >> 8) & 0xFF,
LMGetKbdType(),
0,
&state, 4, &nChars, chars);
/* FIXME: Theoretically, we can get multiple UTF-16
* values; we should convert them to proper unicode and
* figure out whether there are really keyboard layouts
* that give us more than one character for one
* keypress.
*/
if (err == noErr && nChars == 1)
{
int k;
gboolean found = FALSE;
/* A few <Shift><Option>keys return two characters,
* the first of which is U+00a0, which isn't
* interesting; so we return the second. More
* sophisticated handling is the job of a
* GtkIMContext.
*
* If state isn't zero, it means that it's a dead
* key of some sort. Some of those are enumerated in
* the special_ucs_table with the high nibble set to
* f to push it into the private use range. Here we
* do the same.
*/
if (state != 0)
chars[nChars - 1] |= 0xf000;
uc = chars[nChars - 1];
for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++)
{
if (special_ucs_table[k].ucs_value == uc)
{
p[j] = special_ucs_table[k].keyval;
found = TRUE;
break;
}
}
/* Special-case shift-tab since GTK+ expects
* GDK_KEY_ISO_Left_Tab for that.
*/
if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
p[j] = GDK_KEY_ISO_Left_Tab;
if (!found)
p[j] = gdk_unicode_to_keyval (uc);
}
}
if (p[3] == p[2])
p[3] = 0;
if (p[2] == p[1])
p[2] = 0;
if (p[1] == p[0])
p[1] = 0;
if (p[0] == p[2] &&
p[1] == p[3])
p[2] = p[3] = 0;
}
#ifndef __LP64__
}
else
{
g_error ("unknown type of keyboard layout (neither KCHR nor uchr)"
" - not supported right now");
}
#endif
for (i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
{
p = keyval_array + modifier_keys[i].keycode * KEYVALS_PER_KEYCODE;
if (p[0] == 0 && p[1] == 0 &&
p[2] == 0 && p[3] == 0)
p[0] = modifier_keys[i].keyval;
}
for (i = 0; i < G_N_ELEMENTS (function_keys); i++)
{
p = keyval_array + function_keys[i].keycode * KEYVALS_PER_KEYCODE;
p[0] = function_keys[i].keyval;
p[1] = p[2] = p[3] = 0;
}
for (i = 0; i < G_N_ELEMENTS (known_numeric_keys); i++)
{
p = keyval_array + known_numeric_keys[i].keycode * KEYVALS_PER_KEYCODE;
if (p[0] == known_numeric_keys[i].normal_keyval)
p[0] = known_numeric_keys[i].keypad_keyval;
}
if (default_keymap != NULL)
g_signal_emit_by_name (default_keymap, "keys-changed");
}
static PangoDirection
gdk_quartz_keymap_get_direction (GdkKeymap *keymap)
{
return PANGO_DIRECTION_NEUTRAL;
}
static gboolean
gdk_quartz_keymap_have_bidi_layouts (GdkKeymap *keymap)
{
/* FIXME: Can we implement this? */
return FALSE;
}
static gboolean
gdk_quartz_keymap_get_caps_lock_state (GdkKeymap *keymap)
{
/* FIXME: Implement this. */
return FALSE;
}
static gboolean
gdk_quartz_keymap_get_num_lock_state (GdkKeymap *keymap)
{
/* FIXME: Implement this. */
return FALSE;
}
static gboolean
gdk_quartz_keymap_get_scroll_lock_state (GdkKeymap *keymap)
{
/* FIXME: Implement this. */
return FALSE;
}
static gboolean
gdk_quartz_keymap_get_entries_for_keyval (GdkKeymap *keymap,
guint keyval,
GdkKeymapKey **keys,
gint *n_keys)
{
GArray *keys_array;
int i;
*n_keys = 0;
keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
for (i = 0; i < NUM_KEYCODES * KEYVALS_PER_KEYCODE; i++)
{
GdkKeymapKey key;
if (keyval_array[i] != keyval)
continue;
(*n_keys)++;
key.keycode = i / KEYVALS_PER_KEYCODE;
key.group = (i % KEYVALS_PER_KEYCODE) >= 2;
key.level = i % 2;
g_array_append_val (keys_array, key);
}
*keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
return *n_keys > 0;;
}
static gboolean
gdk_quartz_keymap_get_entries_for_keycode (GdkKeymap *keymap,
guint hardware_keycode,
GdkKeymapKey **keys,
guint **keyvals,
gint *n_entries)
{
GArray *keys_array, *keyvals_array;
int i;
guint *p;
*n_entries = 0;
if (hardware_keycode > NUM_KEYCODES)
return FALSE;
if (keys)
keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
else
keys_array = NULL;
if (keyvals)
keyvals_array = g_array_new (FALSE, FALSE, sizeof (guint));
else
keyvals_array = NULL;
p = keyval_array + hardware_keycode * KEYVALS_PER_KEYCODE;
for (i = 0; i < KEYVALS_PER_KEYCODE; i++)
{
if (!p[i])
continue;
(*n_entries)++;
if (keyvals_array)
g_array_append_val (keyvals_array, p[i]);
if (keys_array)
{
GdkKeymapKey key;
key.keycode = hardware_keycode;
key.group = i >= 2;
key.level = i % 2;
g_array_append_val (keys_array, key);
}
}
if (keys)
*keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
if (keyvals)
*keyvals = (guint *)g_array_free (keyvals_array, FALSE);
return *n_entries > 0;
}
#define GET_KEYVAL(keycode, group, level) (keyval_array[(keycode * KEYVALS_PER_KEYCODE + group * 2 + level)])
static guint
gdk_quartz_keymap_lookup_key (GdkKeymap *keymap,
const GdkKeymapKey *key)
{
return GET_KEYVAL (key->keycode, key->group, key->level);
}
static guint
translate_keysym (guint hardware_keycode,
gint group,
GdkModifierType state,
gint *effective_group,
gint *effective_level)
{
gint level;
guint tmp_keyval;
level = (state & GDK_SHIFT_MASK) ? 1 : 0;
if (!(GET_KEYVAL (hardware_keycode, group, 0) || GET_KEYVAL (hardware_keycode, group, 1)) &&
(GET_KEYVAL (hardware_keycode, 0, 0) || GET_KEYVAL (hardware_keycode, 0, 1)))
group = 0;
if (!GET_KEYVAL (hardware_keycode, group, level) &&
GET_KEYVAL (hardware_keycode, group, 0))
level = 0;
tmp_keyval = GET_KEYVAL (hardware_keycode, group, level);
if (state & GDK_LOCK_MASK)
{
guint upper = gdk_keyval_to_upper (tmp_keyval);
if (upper != tmp_keyval)
tmp_keyval = upper;
}
if (effective_group)
*effective_group = group;
if (effective_level)
*effective_level = level;
return tmp_keyval;
}
static gboolean
gdk_quartz_keymap_translate_keyboard_state (GdkKeymap *keymap,
guint hardware_keycode,
GdkModifierType state,
gint group,
guint *keyval,
gint *effective_group,
gint *level,
GdkModifierType *consumed_modifiers)
{
guint tmp_keyval;
GdkModifierType bit;
if (keyval)
*keyval = 0;
if (effective_group)
*effective_group = 0;
if (level)
*level = 0;
if (consumed_modifiers)
*consumed_modifiers = 0;
if (hardware_keycode < 0 || hardware_keycode >= NUM_KEYCODES)
return FALSE;
tmp_keyval = translate_keysym (hardware_keycode, group, state, level, effective_group);
/* Check if modifiers modify the keyval */
if (consumed_modifiers)
{
guint tmp_modifiers = (state & GDK_MODIFIER_MASK);
for (bit = 1; bit <= tmp_modifiers; bit <<= 1)
{
if ((bit & tmp_modifiers) &&
translate_keysym (hardware_keycode, group, state & ~bit,
NULL, NULL) == tmp_keyval)
tmp_modifiers &= ~bit;
}
*consumed_modifiers = tmp_modifiers;
}
if (keyval)
*keyval = tmp_keyval;
return TRUE;
}
static void
gdk_quartz_keymap_add_virtual_modifiers (GdkKeymap *keymap,
GdkModifierType *state)
{
if (*state & GDK_MOD2_MASK)
*state |= GDK_META_MASK;
}
static gboolean
gdk_quartz_keymap_map_virtual_modifiers (GdkKeymap *keymap,
GdkModifierType *state)
{
if (*state & GDK_META_MASK)
*state |= GDK_MOD2_MASK;
return TRUE;
}
/* What sort of key event is this? Returns one of
* GDK_KEY_PRESS, GDK_KEY_RELEASE, GDK_NOTHING (should be ignored)
*/
GdkEventType
_gdk_quartz_keys_event_type (NSEvent *event)
{
unsigned short keycode;
unsigned int flags;
int i;
switch ([event type])
{
case NSKeyDown:
return GDK_KEY_PRESS;
case NSKeyUp:
return GDK_KEY_RELEASE;
case NSFlagsChanged:
break;
default:
g_assert_not_reached ();
}
/* For flags-changed events, we have to find the special key that caused the
* event, and see if it's in the modifier mask. */
keycode = [event keyCode];
flags = [event modifierFlags];
for (i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
{
if (modifier_keys[i].keycode == keycode)
{
if (flags & modifier_keys[i].modmask)
return GDK_KEY_PRESS;
else
return GDK_KEY_RELEASE;
}
}
/* Some keypresses (eg: Expose' activations) seem to trigger flags-changed
* events for no good reason. Ignore them! */
return GDK_NOTHING;
}
gboolean
_gdk_quartz_keys_is_modifier (guint keycode)
{
gint i;
for (i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
{
if (modifier_keys[i].modmask == 0)
break;
if (modifier_keys[i].keycode == keycode)
return TRUE;
}
return FALSE;
}
static void
input_sources_changed_notification (CFNotificationCenterRef center,
void *observer,
CFStringRef name,
const void *object,
CFDictionaryRef userInfo)
{
update_keymap ();
}
static void
gdk_quartz_keymap_init (GdkQuartzKeymap *keymap)
{
update_keymap ();
CFNotificationCenterAddObserver (CFNotificationCenterGetDistributedCenter (),
keymap,
input_sources_changed_notification,
CFSTR ("AppleSelectedInputSourcesChangedNotification"),
NULL,
CFNotificationSuspensionBehaviorDeliverImmediately);
}
static void
gdk_quartz_keymap_finalize (GObject *object)
{
CFNotificationCenterRemoveObserver (CFNotificationCenterGetDistributedCenter (),
object,
CFSTR ("AppleSelectedInputSourcesChangedNotification"),
NULL);
G_OBJECT_CLASS (gdk_quartz_keymap_parent_class)->finalize (object);
}
static void
gdk_quartz_keymap_class_init (GdkQuartzKeymapClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdkKeymapClass *keymap_class = GDK_KEYMAP_CLASS (klass);
object_class->finalize = gdk_quartz_keymap_finalize;
keymap_class->get_direction = gdk_quartz_keymap_get_direction;
keymap_class->have_bidi_layouts = gdk_quartz_keymap_have_bidi_layouts;
keymap_class->get_caps_lock_state = gdk_quartz_keymap_get_caps_lock_state;
keymap_class->get_num_lock_state = gdk_quartz_keymap_get_num_lock_state;
keymap_class->get_scroll_lock_state = gdk_quartz_keymap_get_scroll_lock_state;
keymap_class->get_entries_for_keyval = gdk_quartz_keymap_get_entries_for_keyval;
keymap_class->get_entries_for_keycode = gdk_quartz_keymap_get_entries_for_keycode;
keymap_class->lookup_key = gdk_quartz_keymap_lookup_key;
keymap_class->translate_keyboard_state = gdk_quartz_keymap_translate_keyboard_state;
keymap_class->add_virtual_modifiers = gdk_quartz_keymap_add_virtual_modifiers;
keymap_class->map_virtual_modifiers = gdk_quartz_keymap_map_virtual_modifiers;
}
-65
View File
@@ -1,65 +0,0 @@
/*
* Copyright © 2017 Tom Schoonjans
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <glib.h>
#include <gio/gio.h>
#include "gdkmonitor-quartz.h"
#include "gdkscreen-quartz.h"
G_DEFINE_TYPE (GdkQuartzMonitor, gdk_quartz_monitor, GDK_TYPE_MONITOR)
static void
gdk_quartz_monitor_get_workarea (GdkMonitor *monitor,
GdkRectangle *dest)
{
GdkQuartzScreen *quartz_screen = GDK_QUARTZ_SCREEN(_gdk_screen);
GdkQuartzMonitor *quartz_monitor = GDK_QUARTZ_MONITOR(monitor);
GDK_QUARTZ_ALLOC_POOL;
NSArray *array = [NSScreen screens];
if (quartz_monitor->monitor_num < [array count])
{
NSScreen *screen = [array objectAtIndex:quartz_monitor->monitor_num];
NSRect rect = [screen visibleFrame];
dest->x = rect.origin.x - quartz_screen->min_x;
dest->y = quartz_screen->height - (rect.origin.y + rect.size.height) + quartz_screen->min_y;
dest->width = rect.size.width;
dest->height = rect.size.height;
}
else
*dest = monitor->geometry;
GDK_QUARTZ_RELEASE_POOL;
}
static void
gdk_quartz_monitor_init (GdkQuartzMonitor *monitor)
{
}
static void
gdk_quartz_monitor_class_init (GdkQuartzMonitorClass *class)
{
GDK_MONITOR_CLASS (class)->get_workarea = gdk_quartz_monitor_get_workarea;
}
-41
View File
@@ -1,41 +0,0 @@
/*
* Copyright © 2017 Tom Schoonjans
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_QUARTZ_MONITOR_PRIVATE_H__
#define __GDK_QUARTZ_MONITOR_PRIVATE_H__
#include <glib.h>
#include <gio/gio.h>
#include "gdkmonitorprivate.h"
#include "gdkquartzmonitor.h"
#include "gdkprivate-quartz.h"
struct _GdkQuartzMonitor
{
GdkMonitor parent;
gint monitor_num;
};
struct _GdkQuartzMonitorClass {
GdkMonitorClass parent_class;
};
#endif
-149
View File
@@ -1,149 +0,0 @@
/* gdksurface-quartz.c
*
* Copyright (C) 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/>.
*/
#ifndef __GDK_PRIVATE_QUARTZ_H__
#define __GDK_PRIVATE_QUARTZ_H__
#define GDK_QUARTZ_ALLOC_POOL NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]
#define GDK_QUARTZ_RELEASE_POOL [pool release]
#include <gdk/quartz/gdkquartz.h>
#include <gdk/quartz/gdkdevicemanager-core-quartz.h>
#include <gdk/quartz/gdkdnd-quartz.h>
#include <gdk/quartz/gdkscreen-quartz.h>
#include <gdk/quartz/gdksurface-quartz.h>
#include <gdk/gdk.h>
#include "gdkinternals.h"
#include "config.h"
extern GdkDisplay *_gdk_display;
extern GdkQuartzScreen *_gdk_screen;
extern GdkSurface *_gdk_root;
extern GdkDeviceManager *_gdk_device_manager;
extern GdkDragContext *_gdk_quartz_drag_source_context;
#define GDK_SURFACE_IS_QUARTZ(win) (GDK_IS_SURFACE_IMPL_QUARTZ (((GdkSurface *)win)->impl))
/* Initialization */
void _gdk_quartz_surface_init_windowing (GdkDisplay *display);
void _gdk_quartz_events_init (void);
void _gdk_quartz_event_loop_init (void);
/* Cursor */
NSCursor *_gdk_quartz_cursor_get_ns_cursor (GdkCursor *cursor);
/* Events */
typedef enum {
GDK_QUARTZ_EVENT_SUBTYPE_EVENTLOOP
} GdkQuartzEventSubType;
void _gdk_quartz_events_update_focus_window (GdkSurface *new_window,
gboolean got_focus);
void _gdk_quartz_events_send_map_event (GdkSurface *window);
GdkModifierType _gdk_quartz_events_get_current_keyboard_modifiers (void);
GdkModifierType _gdk_quartz_events_get_current_mouse_modifiers (void);
void _gdk_quartz_events_break_all_grabs (guint32 time);
/* Event loop */
gboolean _gdk_quartz_event_loop_check_pending (void);
NSEvent * _gdk_quartz_event_loop_get_pending (void);
void _gdk_quartz_event_loop_release_event (NSEvent *event);
/* Keys */
GdkEventType _gdk_quartz_keys_event_type (NSEvent *event);
gboolean _gdk_quartz_keys_is_modifier (guint keycode);
void _gdk_quartz_synthesize_null_key_event (GdkSurface *window);
/* Drag and Drop */
GdkDragContext * _gdk_quartz_surface_drag_begin (GdkSurface *window,
GdkDevice *device,
GList *targets,
gint x_root,
gint y_root);
/* Display */
GdkDisplay * _gdk_quartz_display_open (const gchar *name);
/* Screen */
GdkQuartzScreen *_gdk_quartz_screen_new (void);
void _gdk_quartz_screen_update_window_sizes (GdkQuartzScreen *screen);
/* Screen methods - events */
gboolean _gdk_quartz_get_setting (const gchar *name,
GValue *value);
/* Window */
gboolean _gdk_quartz_surface_is_ancestor (GdkSurface *ancestor,
GdkSurface *window);
void _gdk_quartz_surface_gdk_xy_to_xy (gint gdk_x,
gint gdk_y,
gint *ns_x,
gint *ns_y);
void _gdk_quartz_surface_xy_to_gdk_xy (gint ns_x,
gint ns_y,
gint *gdk_x,
gint *gdk_y);
void _gdk_quartz_surface_nspoint_to_gdk_xy (NSPoint point,
gint *x,
gint *y);
GdkSurface *_gdk_quartz_surface_find_child (GdkSurface *window,
gint x,
gint y,
gboolean get_toplevel);
void _gdk_quartz_surface_attach_to_parent (GdkSurface *window);
void _gdk_quartz_surface_detach_from_parent (GdkSurface *window);
void _gdk_quartz_surface_did_become_main (GdkSurface *window);
void _gdk_quartz_surface_did_resign_main (GdkSurface *window);
void _gdk_quartz_surface_debug_highlight (GdkSurface *window,
gint number);
void _gdk_quartz_surface_update_position (GdkSurface *window);
void _gdk_quartz_surface_update_fullscreen_state (GdkSurface *window);
/* Window methods - property */
gboolean _gdk_quartz_surface_get_property (GdkSurface *window,
GdkAtom property,
GdkAtom type,
gulong offset,
gulong length,
gint pdelete,
GdkAtom *actual_property_type,
gint *actual_format_type,
gint *actual_length,
guchar **data);
void _gdk_quartz_surface_change_property (GdkSurface *window,
GdkAtom property,
GdkAtom type,
gint format,
GdkPropMode mode,
const guchar *data,
gint nelements);
void _gdk_quartz_surface_delete_property (GdkSurface *window,
GdkAtom property);
#endif /* __GDK_PRIVATE_QUARTZ_H__ */
-89
View File
@@ -1,89 +0,0 @@
/* gdkquartz.h
*
* Copyright (C) 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/>.
*/
#ifndef __GDK_QUARTZ_H__
#define __GDK_QUARTZ_H__
#include <AppKit/AppKit.h>
#include <gdk/gdk.h>
G_BEGIN_DECLS
/* NSInteger only exists in Leopard and newer. This check has to be
* done after inclusion of the system headers. If NSInteger has not
* been defined, we know for sure that we are on 32-bit.
*/
#ifndef NSINTEGER_DEFINED
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif
#ifndef CGFLOAT_DEFINED
typedef float CGFloat;
#endif
typedef enum
{
GDK_OSX_UNSUPPORTED = 0,
GDK_OSX_MIN = 4,
GDK_OSX_TIGER = 4,
GDK_OSX_LEOPARD = 5,
GDK_OSX_SNOW_LEOPARD = 6,
GDK_OSX_LION = 7,
GDK_OSX_MOUNTAIN_LION = 8,
GDK_OSX_MAVERICKS = 9,
GDK_OSX_YOSEMITE = 10,
GDK_OSX_EL_CAPITAN = 11,
GDK_OSX_SIERRA = 12,
GDK_OSX_HIGH_SIERRA = 13,
GDK_OSX_MOJAVE = 14,
GDK_OSX_CURRENT = 14,
GDK_OSX_NEW = 99
} GdkOSXVersion;
GDK_AVAILABLE_IN_ALL
GdkOSXVersion gdk_quartz_osx_version (void);
GDK_AVAILABLE_IN_ALL
GdkAtom gdk_quartz_pasteboard_type_to_atom_libgtk_only (NSString *type);
GDK_AVAILABLE_IN_ALL
NSString *gdk_quartz_target_to_pasteboard_type_libgtk_only (const gchar *target);
GDK_AVAILABLE_IN_ALL
NSString *gdk_quartz_atom_to_pasteboard_type_libgtk_only (GdkAtom atom);
G_END_DECLS
#define __GDKQUARTZ_H_INSIDE__
#include <gdk/quartz/gdkquartzcursor.h>
#include <gdk/quartz/gdkquartzdevice-core.h>
#include <gdk/quartz/gdkquartzdevicemanager-core.h>
#include <gdk/quartz/gdkquartzdisplay.h>
#include <gdk/quartz/gdkquartzdisplaymanager.h>
#include <gdk/quartz/gdkquartzdnd.h>
#include <gdk/quartz/gdkquartzkeys.h>
#include <gdk/quartz/gdkquartzmonitor.h>
#include <gdk/quartz/gdkquartzscreen.h>
#include <gdk/quartz/gdkquartzutils.h>
#include <gdk/quartz/gdkquartzsurface.h>
#undef __GDKQUARTZ_H_INSIDE__
#endif /* __GDK_QUARTZ_H__ */
-50
View File
@@ -1,50 +0,0 @@
/* gdkquartzcursor.h
*
* Copyright (C) 2005-2007 Imendio AB
* Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_QUARTZ_CURSOR_H__
#define __GDK_QUARTZ_CURSOR_H__
#if !defined(__GDKQUARTZ_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/quartz/gdkquartz.h> can be included directly."
#endif
#include <gdk/gdk.h>
G_BEGIN_DECLS
#define GDK_TYPE_QUARTZ_CURSOR (gdk_quartz_cursor_get_type ())
#define GDK_QUARTZ_CURSOR(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_QUARTZ_CURSOR, GdkQuartzCursor))
#define GDK_QUARTZ_CURSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_QUARTZ_CURSOR, GdkQuartzCursorClass))
#define GDK_IS_QUARTZ_CURSOR(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_QUARTZ_CURSOR))
#define GDK_IS_QUARTZ_CURSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_QUARTZ_CURSOR))
#define GDK_QUARTZ_CURSOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_QUARTZ_CURSOR, GdkQuartzCursorClass))
#ifdef GTK_COMPILATION
typedef struct _GdkQuartzCursor GdkQuartzCursor;
#else
typedef GdkCursor GdkQuartzCursor;
#endif
typedef struct _GdkQuartzCursorClass GdkQuartzCursorClass;
GDK_AVAILABLE_IN_ALL
GType gdk_quartz_cursor_get_type (void);
G_END_DECLS
#endif /* __GDK_QUARTZ_CURSOR_H__ */
-44
View File
@@ -1,44 +0,0 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_QUARTZ_DEVICE_CORE_H__
#define __GDK_QUARTZ_DEVICE_CORE_H__
#if !defined(__GDKQUARTZ_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/quartz/gdkquartz.h> can be included directly."
#endif
#include <gdk/gdk.h>
G_BEGIN_DECLS
#define GDK_TYPE_QUARTZ_DEVICE_CORE (gdk_quartz_device_core_get_type ())
#define GDK_QUARTZ_DEVICE_CORE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_QUARTZ_DEVICE_CORE, GdkQuartzDeviceCore))
#define GDK_QUARTZ_DEVICE_CORE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_QUARTZ_DEVICE_CORE, GdkQuartzDeviceCoreClass))
#define GDK_IS_QUARTZ_DEVICE_CORE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_QUARTZ_DEVICE_CORE))
#define GDK_IS_QUARTZ_DEVICE_CORE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_QUARTZ_DEVICE_CORE))
#define GDK_QUARTZ_DEVICE_CORE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_QUARTZ_DEVICE_CORE, GdkQuartzDeviceCoreClass))
typedef struct _GdkQuartzDeviceCore GdkQuartzDeviceCore;
typedef struct _GdkQuartzDeviceCoreClass GdkQuartzDeviceCoreClass;
GDK_AVAILABLE_IN_ALL
GType gdk_quartz_device_core_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __GDK_QUARTZ_DEVICE_CORE_H__ */
-46
View File
@@ -1,46 +0,0 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_QUARTZ_DEVICE_MANAGER_CORE_H__
#define __GDK_QUARTZ_DEVICE_MANAGER_CORE_H__
#if !defined(__GDKQUARTZ_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/quartz/gdkquartz.h> can be included directly."
#endif
#include <gdk/gdk.h>
G_BEGIN_DECLS
#define GDK_TYPE_QUARTZ_DEVICE_MANAGER_CORE (gdk_quartz_device_manager_core_get_type ())
#define GDK_QUARTZ_DEVICE_MANAGER_CORE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_QUARTZ_DEVICE_MANAGER_CORE, GdkQuartzDeviceManagerCore))
#define GDK_QUARTZ_DEVICE_MANAGER_CORE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_QUARTZ_DEVICE_MANAGER_CORE, GdkQuartzDeviceManagerCoreClass))
#define GDK_IS_QUARTZ_DEVICE_MANAGER_CORE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_QUARTZ_DEVICE_MANAGER_CORE))
#define GDK_IS_QUARTZ_DEVICE_MANAGER_CORE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_QUARTZ_DEVICE_MANAGER_CORE))
#define GDK_QUARTZ_DEVICE_MANAGER_CORE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_QUARTZ_DEVICE_MANAGER_CORE, GdkQuartzDeviceManagerCoreClass))
typedef struct _GdkQuartzDeviceManagerCore GdkQuartzDeviceManagerCore;
typedef struct _GdkQuartzDeviceManagerCoreClass GdkQuartzDeviceManagerCoreClass;
GDK_AVAILABLE_IN_ALL
GType gdk_quartz_device_manager_core_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __GDK_QUARTZ_DEVICE_MANAGER_CORE_H__ */
-51
View File
@@ -1,51 +0,0 @@
/* gdkquartzdisplay.h
*
* Copyright (C) 2005-2007 Imendio AB
* Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_QUARTZ_DISPLAY_H__
#define __GDK_QUARTZ_DISPLAY_H__
#if !defined(__GDKQUARTZ_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/quartz/gdkquartz.h> can be included directly."
#endif
#include <gdk/gdk.h>
G_BEGIN_DECLS
#define GDK_TYPE_QUARTZ_DISPLAY (gdk_quartz_display_get_type ())
#define GDK_QUARTZ_DISPLAY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_QUARTZ_DISPLAY, GdkQuartzDisplay))
#define GDK_QUARTZ_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_QUARTZ_DISPLAY, GdkQuartzDisplayClass))
#define GDK_IS_QUARTZ_DISPLAY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_QUARTZ_DISPLAY))
#define GDK_IS_QUARTZ_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_QUARTZ_DISPLAY))
#define GDK_QUARTZ_DISPLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_QUARTZ_DISPLAY, GdkQuartzDisplayClass))
#ifdef GTK_COMPILATION
typedef struct _GdkQuartzDisplay GdkQuartzDisplay;
#else
typedef GdkDisplay GdkQuartzDisplay;
#endif
typedef struct _GdkQuartzDisplayClass GdkQuartzDisplayClass;
GDK_AVAILABLE_IN_ALL
GType gdk_quartz_display_get_type (void);
G_END_DECLS
#endif /* __GDK_QUARTZ_DISPLAY_H__ */
-47
View File
@@ -1,47 +0,0 @@
/* gdkquartzdisplaymanager.h
*
* Copyright (C) 2005-2007 Imendio AB
* Copyright 2010 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/>.
*/
#ifndef __GDK_QUARTZ_DISPLAY_MANAGER_H__
#define __GDK_QUARTZ_DISPLAY_MANAGER_H__
#if !defined(__GDKQUARTZ_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/quartz/gdkquartz.h> can be included directly."
#endif
#include <gdk/gdk.h>
G_BEGIN_DECLS
#define GDK_TYPE_QUARTZ_DISPLAY_MANAGER (gdk_quartz_display_manager_get_type ())
#define GDK_QUARTZ_DISPLAY_MANAGER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_QUARTZ_DISPLAY_MANAGER, GdkQuartzDisplayManager))
#ifdef GTK_COMPILATION
typedef struct _GdkQuartzDisplayManager GdkQuartzDisplayManager;
#else
typedef GdkDisplayManager _GdkQuartzDisplayManager;
#endif
typedef struct _GdkDisplayManagerClass GdkQuartzDisplayManagerClass;
GDK_AVAILABLE_IN_ALL
GType gdk_quartz_display_manager_get_type (void);
G_END_DECLS
#endif /* __GDK_QUARTZ_DISPLAY_MANAGER_H__ */
-56
View File
@@ -1,56 +0,0 @@
/* gdkquartzdnd.h
*
* Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_QUARTZ_DND_H__
#define __GDK_QUARTZ_DND_H__
#if !defined(__GDKQUARTZ_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/quartz/gdkquartz.h> can be included directly."
#endif
#include <gdk/gdk.h>
G_BEGIN_DECLS
#define GDK_TYPE_QUARTZ_DRAG_CONTEXT (gdk_quartz_drag_context_get_type ())
#define GDK_QUARTZ_DRAG_CONTEXT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_QUARTZ_DRAG_CONTEXT, GdkQuartzDragContext))
#define GDK_QUARTZ_DRAG_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_QUARTZ_DRAG_CONTEXT, GdkQuartzDragContextClass))
#define GDK_IS_QUARTZ_DRAG_CONTEXT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_QUARTZ_DRAG_CONTEXT))
#define GDK_IS_QUARTZ_DRAG_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_QUARTZ_DRAG_CONTEXT))
#define GDK_QUARTZ_DRAG_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_QUARTZ_DRAG_CONTEXT, GdkQuartzDragContextClass))
#ifdef GTK_COMPILATION
typedef struct _GdkQuartzDragContext GdkQuartzDragContext;
#else
typedef GdkDragContext GdkQuartzDragContext;
#endif
typedef struct _GdkQuartzDragContextClass GdkQuartzDragContextClass;
GDK_AVAILABLE_IN_ALL
GType gdk_quartz_drag_context_get_type (void);
GDK_AVAILABLE_IN_ALL
id gdk_quartz_drag_context_get_dragging_info_libgtk_only (GdkDragContext *context);
GDK_AVAILABLE_IN_ALL
GdkDragContext *gdk_quartz_drag_source_context_libgtk_only (void);
G_END_DECLS
#endif /* __GDK_QUARTZ_DRAG_CONTEXT_H__ */
-50
View File
@@ -1,50 +0,0 @@
/* gdkquartzkeyd.h
*
* Copyright (C) 2005 Imendio AB
* Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_QUARTZ_KEYS_H__
#define __GDK_QUARTZ_KEYS_H__
#if !defined (__GDKQUARTZ_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/quartz/gdkquartz.h> can be included directly."
#endif
#include <gdk/gdk.h>
G_BEGIN_DECLS
#define GDK_TYPE_QUARTZ_KEYMAP (gdk_quartz_keymap_get_type ())
#define GDK_QUARTZ_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_QUARTZ_KEYMAP, GdkQuartzKeymap))
#define GDK_QUARTZ_KEYMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_QUARTZ_KEYMAP, GdkQuartzKeymapClass))
#define GDK_IS_QUARTZ_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_QUARTZ_KEYMAP))
#define GDK_IS_QUARTZ_KEYMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_QUARTZ_KEYMAP))
#define GDK_QUARTZ_KEYMAP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_QUARTZ_KEYMAP, GdkQuartzKeymapClass))
#ifdef GTK_COMPILATION
typedef struct _GdkQuartzKeymap GdkQuartzKeymap;
#else
typedef GdkKeymap GdkQuartzKeymap;
#endif
typedef struct _GdkQuartzKeymapClass GdkQuartzKeymapClass;
GDK_AVAILABLE_IN_ALL
GType gdk_quartz_keymap_get_type (void);
G_END_DECLS
#endif /* __GDK_QUARTZ_KEYS_H__ */
-45
View File
@@ -1,45 +0,0 @@
/*
* gdkquartzmonitor.h
*
* Copyright 2017 Tom Schoonjans
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_QUARTZ_MONITOR_H__
#define __GDK_QUARTZ_MONITOR_H__
#if !defined (__GDKQUARTZ_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/quartz/gdkquartz.h> can be included directly."
#endif
#include <gdk/gdkmonitor.h>
G_BEGIN_DECLS
#define GDK_TYPE_QUARTZ_MONITOR (gdk_quartz_monitor_get_type ())
#define GDK_QUARTZ_MONITOR(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_QUARTZ_MONITOR, GdkQuartzMonitor))
#define GDK_IS_QUARTZ_MONITOR(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_QUARTZ_MONITOR))
typedef struct _GdkQuartzMonitor GdkQuartzMonitor;
typedef struct _GdkQuartzMonitorClass GdkQuartzMonitorClass;
GDK_AVAILABLE_IN_ALL
GType gdk_quartz_monitor_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __GDK_QUARTZ_MONITOR_H__ */

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