Compare commits

...

167 Commits

Author SHA1 Message Date
Emmanuele Bassi 109593ab18 WIP: Implement Scrollable in GtkFixed 2019-04-01 18:02:48 +01:00
Emmanuele Bassi 7b17f6fede WIP: Additional API for GtkLayout 2019-04-01 18:02:22 +01:00
Emmanuele Bassi 060e30de3f Turn GtkFixedLayoutChild:position into a transformation
This way we can transform children instead of just allocating them at an
offset.
2019-03-26 19:17:26 +00:00
Emmanuele Bassi fc33bf2d1f Skip all LayoutChild when testing
GtkLayoutChild instances are created on demand once we have a widget, a
GtkLayoutManager, and a child widget. This makes testing their creation
fairly tricky.

Let's skip them, for the time being.
2019-03-26 18:46:55 +00:00
Emmanuele Bassi dd5c981b63 Use GtkFixedLayout in GtkFixed
Drop the child properties and the sizing code.
2019-03-26 18:15:13 +00:00
Emmanuele Bassi 9a4c19349e Add GtkFixedLayout
A layout manager for fixed positioning.
2019-03-26 17:43:53 +00:00
Emmanuele Bassi 3389ddf6fc Do not connect to a non-existing signal
The GtkWidget::parent-set signal was removed in ff6cd8f7.

Instead of removing GtkLayoutChild instances associated to a widget
using notifications when the widget's parent changes, we can have
gtk_widget_unparent() call a method on GtkLayoutManager to remove any
eventual GtkLayoutChild instances associated to the widget.
2019-03-26 17:37:49 +00:00
Emmanuele Bassi 341660e056 Drop warning from GtkLayoutManager::get_request_mode()
We can return a sensible default value, so we don't really need to warn
about a missing implementation.
2019-03-26 17:37:49 +00:00
Piotr Drąg b42bf99b13 Update POTFILES.in 2019-03-26 18:36:51 +01:00
Alexander Larsson 18d814d2ce Merge branch 'wip/alexl/broadway5' into 'master'
Update broadway for gtk4

See merge request GNOME/gtk!667
2019-03-26 16:25:10 +00:00
Alexander Larsson 6fce18e1a1 broadway: Remove some spew 2019-03-26 17:09:41 +01:00
Alexander Larsson cf4226586a broadway: Load all textures before applying display ops, fixing flickers 2019-03-26 17:07:47 +01:00
Alexander Larsson 0481aa10e7 broadway: Use const use for constants in the js code 2019-03-26 17:07:47 +01:00
Alexander Larsson edbaa0964f broadway: Clean up stuff using const defines 2019-03-26 17:07:47 +01:00
Alexander Larsson fbefec52a5 Broadway: Add id for nodes and reuse old ones
When sending render nodes from the client to the daemon we add an id,
and whenever we're about to re-send the entire tree node we instead
send the old id. We track all the nodes for the previous frame
of the surface this way.

Having the id on the daemon side will allow us do to much better deltas.
2019-03-26 17:07:47 +01:00
Alexander Larsson d59d8b5dd4 Disable accidental debug spew 2019-03-26 17:07:47 +01:00
Alexander Larsson 87a13fe3d2 broadway: Prepare for splitting display ops out of command handling 2019-03-26 17:07:47 +01:00
Alexander Larsson 2f85443e37 broadway: Refcount textures
We want to delay some rendering, and to make that safe we need to correctly
refcount the use of blob uris for the textures so that we don't unref
it while something is scheduled to use it.
2019-03-26 17:07:47 +01:00
Alexander Larsson 311aa01e01 broadway: Simplify fallback node cache
Since nodes are now cached we just store the fallback as a
texture in a hashtable indexed by the node. If its unused for
5 frames we drop it.
2019-03-26 17:07:47 +01:00
Alexander Larsson 3bbbe9f71b broadway: Don't crash of drag-resizing when already active
This is what the X11 code does.
2019-03-26 17:07:47 +01:00
Alexander Larsson 890b759091 broadway: Send actual float32, not some hack 2019-03-26 17:07:47 +01:00
Alexander Larsson d997903d29 broadway: Use DataView instead of hand-rolled int parsers
This is nicer in general, but also will let us do floats more sanely.
2019-03-26 17:07:47 +01:00
Alexander Larsson b097f0a7d8 Broadway: Add node for debug nodes
This can be helpful when debugging broadway.
2019-03-26 17:07:47 +01:00
Alexander Larsson 1b5b1bfd0e broadway: Don't fall back for translation transform nodes
These are trivial anyway
2019-03-26 17:07:47 +01:00
Christoph Reiter c94867f8a1 CI: set a timeout multiplier for the tests
CI can be slower than your normal dev machine so give it a bit more time
2019-03-26 16:37:22 +01:00
Matthias Clasen dbac377ad2 Merge branch 'wip/layout-manager' into 'master'
Add Layout Managers

See merge request GNOME/gtk!534
2019-03-26 12:38:18 +00:00
Christoph Reiter 0638dca29a win32: remove another call to gdk_device_warp()
Inline the implementation (untested). To fix the build.
2019-03-26 08:20:07 +01:00
Christoph Reiter ae68dc7a7d win32: remove unused gdk_display_warp_device
to fix the build
2019-03-26 07:59:01 +01:00
Matthias Clasen 20b4a8b38c Yet another win32 build fix
So much empty warping.
2019-03-25 23:29:34 -04:00
Emmanuele Bassi 65965bed16 Changes after review
- Rename GtkLegacyLayout to GtkCustomLayout
 - Use for() to iterate over children in GtkBinLayout
 - Whitespace fixes for code imported from GtkBox
 - Store the GtkLayoutChild instances inside LayoutManager
 - Simplify the GtkLayoutManager API by dropping unnecessary arguments
 - Fix the ownership model of GtkLayoutManager
2019-03-26 00:11:27 +00:00
Emmanuele Bassi 630442f31c Parse layout properties
If a widget has a LayoutManager instance, then we want to parse layout
properties in UI description files; the grammar is similar to packing
properties in GtkContainer:

    <child>
      <object ...>
        <property name="...">...</property>
        <layout>
          <property name="pname">value</property>
        </layout>
      </object>
    </child>

The properties are applied after a child has been added to its parent,
to the parent's layout manager property should be set.
2019-03-26 00:11:27 +00:00
Emmanuele Bassi d6dfa41f10 Add GtkBinLayout
Like GtkBin, but lets you lay out multiple children instead of just one.
2019-03-26 00:11:27 +00:00
Emmanuele Bassi 8cf06befc0 Port GtkSwitch to GtkLegacyLayout 2019-03-26 00:11:27 +00:00
Emmanuele Bassi 128a34fe37 Add GtkLegacyLayout
GtkLegacyLayout is a layout manager for the transitional period between
the introduction of layout managers and the removal of GtkWidget virtual
functions for the size negotiation.
2019-03-26 00:11:27 +00:00
Emmanuele Bassi 0285919f4a docs: Add chapter on layout managers 2019-03-26 00:11:27 +00:00
Emmanuele Bassi 1fed357752 Port GtkBox to GtkBoxLayout
We can delegate all the layout management to a GtkBoxLayout, now that we
have one.
2019-03-26 00:11:27 +00:00
Emmanuele Bassi ef9863ab63 Add GtkBoxLayout
The same layout policy of GtkBox, without all the GtkContainer calories.
2019-03-26 00:11:27 +00:00
Emmanuele Bassi 5cbf6f5fbd Add GtkLayoutChild
Layout managers needs a way to store properties that control the layout
policy of a widget; typically, we used to store these in GtkContainer's
child properties, but since GtkLayoutManager is decoupled from the
actual container widget, we need a separate storage. Additionally, child
properties have their own downsides, like requiring a separate, global
GParamSpecPool storage, and additional lookup API.

GtkLayoutChild is a simple GObject class, which means you can introspect
and document it as you would any other type.
2019-03-26 00:11:27 +00:00
Emmanuele Bassi 15fda18791 Rename the internal GtkLayoutChild type
The type is completely private to GtkLayout, so there's really no need
to namespace it.
2019-03-26 00:11:27 +00:00
Emmanuele Bassi f7856e887e Add GtkWidget:layout-manager
We can use a constructor property for existing container widgets with
a layout policy, and move the layout policy implementation out of the
widget itself and into a LayoutManager subclass.
2019-03-26 00:11:27 +00:00
Emmanuele Bassi 1b8595b5f2 Hook GtkLayoutManager into GtkWidget
We delegate the size request mode, the measuring, and the allocation of
a widget through a GtkLayoutManager instance, if one has been attached
to the widget; otherwise, we fall back to the widget's own implementation.
2019-03-26 00:11:27 +00:00
Emmanuele Bassi 24754c3259 Add GtkLayoutManager
A base abstract class for layout manager delegate objects.

Layout managers are associated to a single widget, like event
controllers, and are responsible for measuring and allocating the
children of the widget they are bound to.
2019-03-26 00:11:27 +00:00
Matthias Clasen 4dfe2a8aa8 Fix the windows build
There was another warp implementation that needed to be removed.
This commit also addresses a number of compiler warnings
in passing.
2019-03-25 20:06:08 -04:00
Timm Bäder ab7507150b Doc comment fixup 2019-03-25 15:57:31 +01:00
Timm Bäder e657d9d553 popover: Always measure contents gizmo
Otherwise we're getting warnings about allocating a widget we haven't
measured first, which is fair. The contents gizmo itself will later take
care about whether or not the real popover child is NULL.
2019-03-25 15:57:31 +01:00
Timm Bäder 36e00ae95e popover: Don't try to compute_bounds of a NULL child 2019-03-25 15:57:30 +01:00
Matthias Clasen f2dff5115f win32: Drop the warp implementation
We no longer support pointer warping.
2019-03-25 10:16:14 -04:00
Piotr Drąg a246f8c22a Update Polish translation 2019-03-25 14:37:44 +01:00
Piotr Drąg 6efa1fc006 Update POTFILES.in 2019-03-25 14:19:54 +01:00
Matthias Clasen 3d37f08f38 Remove gdk_device_warp
This was only ever implemented on X11, and is
not something we want to encourage apps to do, ever.
2019-03-24 20:49:08 -04:00
Matthias Clasen 160f1e581a Remove a dead file
We are not using this anymore.
2019-03-24 20:48:35 -04:00
Matthias Clasen 661e195ffc color editor: Don't warn if editing is cancelled
Thats a valid way to end color picking.
2019-03-24 20:47:26 -04:00
Benjamin Otte 551ced9ae4 Fix compile warning 2019-03-23 03:08:20 +01:00
Benjamin Otte 799cb39e08 Remove win32 themeing support
It was unused through all of GTK 3, so it is not worth supporting.

The best Windows themes do not make use of it at all.
2019-03-22 22:30:01 +01:00
LRN 0615668dd9 Merge branch 'ime-load-fix' into 'master'
Ime load fix (GTK4)

See merge request GNOME/gtk!662
2019-03-22 21:10:35 +00:00
Matthias Clasen 1ada7bbc02 Fix hover state handling
We were not paying enough attention to detail when updating
hover and focus state while generating crossing events. The
invariant that we need to preserve here is that when a widget
has focus or hover, its parent does too.
2019-03-22 16:35:20 -04:00
Matthias Clasen 81658105f7 Stop walking parent surfaces for crossing event generation
We basically don't have child surfaces anymore (the last
use in popovers is on the way out). This really needs
to be done in terms of widgets, not surfaces. For now,
just stop walking parent surfaces.
2019-03-22 16:35:20 -04:00
Benjamin Otte d9ef734458 cssparser: Simplify
Remove the uint parser (and use the int parser in the one user of it).

And avoid unnecessarily going through a macro.
2019-03-22 19:55:34 +01:00
Benjamin Otte 73760e5835 cssparser: Remove unused functions 2019-03-22 19:55:34 +01:00
Matthias Clasen 5638882dca Remove debug spew 2019-03-22 14:44:51 -04:00
Руслан Ижбулатов 8da56cef79 GDK W32: Fix property setting to correctly use static strings
The strings that are set are static, so g_value_set_static_string() should
be used to set them instead of g_value_set_string().
2019-03-22 16:59:03 +00:00
Руслан Ижбулатов 64ab82c403 GDK W32: Test for IME correctly
ImmIsIME() doesn't work (always returns TRUE) since Vista.
Use ITfActiveLanguageProfileNotifySink to detect TSF changes,
which are equal to IME changes for us.

Also make sure that IMMultiContext re-loads the IM when keyboard layout
changes, otherwise there's a subtle bug that could happen:
* Run GTK application with non-IME layout (US, for example)
* Focus on an editable widget (GtkEntry, for example)
* IM Context is initialized to use the simple IM
* Switch to an IME layout (such as Korean)
* Start typing
* Since IME module is not loaded yet, keypresses are handled
  by a default MS IME handler
* Once IME commits a character, GDK will get a WM_KEYDOWN,
  which will trigger a GdkKeyEvent, which will be handled by
  an event filter in IM Context, which will finally re-evaluate
  its status and load IME, and only after that GTK will get
  to handle IME by itself - but by that point input would
  already be broken.
To avoid this we can emit a dummy event (with Void keyval),
which will cause IM Context to load the appropriate module
immediately.
2019-03-22 16:58:59 +00:00
Matthias Clasen 56df49971a entry: Disconnect text signals in dispose
This was showing up as crashes when closing
the file chooser.
2019-03-21 19:15:55 -04:00
Matthias Clasen 0bf136a902 Merge branch 'adwaita-remove-selectionmode-assets-master' into 'master'
Adwaita: Drop checkbox-selectionmode assets

See merge request GNOME/gtk!634
2019-03-20 14:10:18 +00:00
Matthias Clasen 2479d60012 Merge branch 'adwaita-selectionmode-checkboxes-master' into 'master'
Adwaita: Fix selection-mode checkboxes

Closes #28

See merge request GNOME/gtk!629
2019-03-20 14:10:05 +00:00
Matthias Clasen 6990f73940 Merge branch 'adwaita-headerbar-switch-margins-master' into 'master'
Adwaita: Adjust switch margins on headerbars

Closes #1759

See merge request GNOME/gtk!651
2019-03-20 14:06:19 +00:00
Matthias Clasen 254c27acbe Merge branch 'wip/jimmac/focus-ring-radii' into 'master'
Adwaita: draw bigger radius for focus rings

Closes #1756

See merge request GNOME/gtk!649
2019-03-20 12:32:15 +00:00
Matthias Clasen 558405e1bc window: Update state flags
When the window gets active / inactive, we
don't propagate events, but just send focus-in / -out
to the current focus_widget. Improve this by updating
its state flags as well.
2019-03-19 21:33:38 -04:00
Matthias Clasen f47c376fb1 main: Fix crossing event generation for parented roots
We were walking the parent chain here, which now
always needs to consider whether it should stop
at roots. Like this one should.

The symptom was that a label with a popup attached to
it would end up with an unintentional focus ring that
would not go away.
2019-03-19 21:33:38 -04:00
Alex Monday 5679b9a687 Adwaita: Adjust switch margins on headerbars
Closes https://gitlab.gnome.org/GNOME/gtk/issues/1759
2019-03-19 19:59:05 +05:00
Jakub Steiner 24235f61ab Adwaita: draw bigger radius for focus rings
Fixes https://gitlab.gnome.org/GNOME/gtk/issues/1756
2019-03-19 14:07:10 +01:00
Benjamin Otte a44ac75e65 gtk: Don't include gtkstylecontext.h from gtkcsstypesprivate.h
And make sure it's included everywhere it's needed.
2019-03-19 08:53:25 +01:00
Benjamin Otte 85c8e29d78 stylecontext: Move atk.h include where it belongs 2019-03-19 08:49:15 +01:00
Benjamin Otte 8fb797866d paned: hide the handle widget when <2 children are visible 2019-03-19 08:48:50 +01:00
Benjamin Otte 96a677e5ca paned: Refactor
Don't call a useless function, call gtk_widget_set_child_visible()
directly.
2019-03-19 08:48:41 +01:00
Benjamin Otte 07054ca20d singleselection: Add forgotten notify emission
Also, add docs for the model property while I'm looking at the file.
2019-03-19 08:48:22 +01:00
Benjamin Otte 8f6a48832d revealer: Always use identity transform for revealed child
Refactor the child allocation machinery, so that the complex allocation
paths are only run when the animation is running.

And in particular, ensure that when no animation is running, the
identity transform is allocated.
2019-03-19 08:48:06 +01:00
Benjamin Otte 658588dfe7 renderer: Make gsk_renderer_is_realized() public
... and add a property for it.
2019-03-19 08:47:54 +01:00
Benjamin Otte 480d8aec06 renderer: Remove display property
Renderers don't need a display until they get realized. And once they
get realized, they can look up the display from the surface.
2019-03-19 08:47:54 +01:00
Matthias Clasen 0d91481587 One forgotten leave signal handler 2019-03-18 15:35:07 -04:00
Matthias Clasen 8650980797 Adapt to motion controller api change
The signature of the enter/leave signals changed.
Adapt all users.
2019-03-18 09:24:42 -04:00
Matthias Clasen 2b0d1bca43 motion controller: Install the properties
Oops
2019-03-18 08:44:35 -04:00
Matthias Clasen f7e328e5f7 Merge branch 'paned-no-grab' into 'master'
paned: Don't use a grab

See merge request GNOME/gtk!644
2019-03-18 11:50:42 +00:00
Matthias Clasen b40743121b Merge branch 'crossing-details' into 'master'
motion controller: add details to signals

See merge request GNOME/gtk!621
2019-03-18 01:49:45 +00:00
Matthias Clasen 93c1353c69 Merge branch 'wip/carlosg/include-constructors-header' into 'master'
gdk: Include copy of glib/gconstructor.h

See merge request GNOME/gtk!642
2019-03-18 01:10:06 +00:00
Matthias Clasen 1196380f28 paned: Don't use a grab
It does not seem necessary for proper functioning
of the drag handle.
2019-03-17 18:55:00 -04:00
Matthias Clasen 26f99bf20c editable: Fix a thinko
When dealing with subclasses of GtkEntry, we were not
getting the property offset that is stored on the GtkEntry
type.

This was showing up as criticals when trying to set
::width-chars on a GtkFileChooserEntry.
2019-03-17 18:46:18 -04:00
Carlos Garnacho 65d9b7ee86 gdk: Include copy of glib/gconstructor.h
This is named gdkconstructor.h to avoid any possible conflicts. This fixes
the current usages of G_HAS_CONSTRUCTORS, as that header is not installed
by glib.
2019-03-17 21:29:59 +01:00
Piotr Drąg 688f0997f4 Update POTFILES.in 2019-03-17 17:17:02 +01:00
Matthias Clasen 430ea05aea widget: Fix a mission annotation 2019-03-17 01:11:22 -04:00
Matthias Clasen 17f4211e4f motion controller: Add getters for crossing event targets
This information can be needed in signal handlers,
so make it available.
2019-03-16 23:52:58 -04:00
Matthias Clasen ecd6446d08 motion controller: Add focus properties
Add boolean properties, is-pointer-focus and
contains-pointer-focus, that track whether the pointer
is in the widget itself or in one of its descendants.
2019-03-16 23:32:31 -04:00
Matthias Clasen 1540797237 motion controller: add details to signals
The ::enter and ::leave signals get emitted up and down the
connecting path between the old an the new pointer location.

The signals are less useful if you can't find out where along
the path you are. That is what crossing mode and detail are
about, so add those to the signals.
2019-03-16 23:03:41 -04:00
Matthias Clasen 898728fb2d a11y tests: Clean up the placeholder-text test
This was relying on setting has-focus for initial focus.
2019-03-16 22:46:34 -04:00
Matthias Clasen fc2b412c0c Merge branch 'wip/matthiasc/focus3' into 'master'
Move focus to GtkRoot

See merge request GNOME/gtk!640
2019-03-17 02:42:46 +00:00
Matthias Clasen 1ce5327058 xim: Stop using GtkWidget::event
It does not exist anymore. I'm removing this code now
because our CI tests are using xim and fail due to this.

Eventually, this code should be ported to use a popover.
2019-03-16 22:16:10 -04:00
Matthias Clasen ad3773b2e1 a11y tests: Update expected results
The changes here are all related to initial focus.
2019-03-16 21:49:24 -04:00
Matthias Clasen 8619b109cc Update the focus test
Check that we get the expected sequences of focus
change events for the nonlinear, inferior and ancestor
cases.

It would be nice to do the same checks for crossing
events, but we have no gtk_window_set_hover().
2019-03-16 21:31:56 -04:00
Matthias Clasen 6ddb61119a Use root in gdk_synthesize_crossing_events 2019-03-16 21:30:48 -04:00
Matthias Clasen 492a38c229 Make gtk_widget_get_focus_child public
It doesn't really make sense to have only
the setter, but not the getter public.
2019-03-16 21:24:45 -04:00
Matthias Clasen 181a4bce25 Add key controller API to the docs
A bunch of API was missing here.
2019-03-16 21:24:45 -04:00
Matthias Clasen 93905a8513 key controller: Enforce limitations of key forwarding
We now set current_event for focus-change as well,
so make sure to check the event type.
2019-03-16 21:24:45 -04:00
Matthias Clasen 4f06b669c5 key controller: Improve the docs
Mention the limitations of the key forwarding api.
2019-03-16 21:24:45 -04:00
Matthias Clasen f3ed3e99c3 key controller: Add getters for focus event targets
This information can be needed in signal handlers,
so make it available.
2019-03-16 21:24:45 -04:00
Matthias Clasen 4f5a8207bc key controller: Add focus properties
Add boolean properties, is-focus and contains-focus, that
track whether the focus is in the widget itself or in
one of its descendants.
2019-03-16 21:24:45 -04:00
Matthias Clasen 2f1194c0c1 key controller: Fix a copy/paste error
Prefix the finalize function properly.
2019-03-16 21:24:45 -04:00
Matthias Clasen 921eccb459 Pass mode and detail to focus-in/out signals
This information is useful when maintaining a
'last focus' field.

Update all users.
2019-03-16 21:24:45 -04:00
Matthias Clasen 888b92674f Move maintaining the focus chain
Put this code in the same place where we generate
the crossing events.
2019-03-16 21:24:45 -04:00
Matthias Clasen 7d354b5084 Some fixes to crossing event generation
In the inferior and ancestor cases, we were missing
the initial/final event.
2019-03-16 21:24:45 -04:00
Matthias Clasen 4238a04c7b window: Use gtk_synthesize_crossing_events
Emit focus change events in the same way as crossing events.
Also change the code to only emit focus change events for
the master keyboard - we only maintain a single focus location,
so sending multiple focus change events for different devices
seems confusing.
2019-03-16 21:24:45 -04:00
Matthias Clasen adb547a147 Export gtk_synthesize_crossing_events internally
We want to use this for focus changes, now that
it can emit focus change events.
2019-03-16 21:24:45 -04:00
Matthias Clasen cdcd2bb073 Share crossing and focus change event code
Make a single function that can emit both
enter/leave and focus change events.
2019-03-16 21:24:45 -04:00
Matthias Clasen 06f790d663 gdk: Add a related_target field to some events
Crossing and focus change events are emitted between
two widgets, and want to associate both with the
events.
2019-03-16 21:24:45 -04:00
Matthias Clasen c73972f7df gdk: Rename gdk_event_set_user_data
Lets call it what it is, the target.
All of this is private api anyway.

Update all callers.
2019-03-16 21:24:45 -04:00
Matthias Clasen 8d5f1ae662 gdk: Add crossing mode and detail to focus events
We want focus events more similar to crossing events.
2019-03-16 21:24:45 -04:00
Matthias Clasen a3abf0693d Clarify grab_focus docs 2019-03-16 21:24:45 -04:00
Matthias Clasen 7ca24f12d7 window: Remove initial-focus builder support
With focus-widget now a property, this is no longer needed.
2019-03-16 21:24:45 -04:00
Matthias Clasen f68855341e window: Remove ::set-focus
The focus-widget is now a property, so we don't need
this signal anymore.
2019-03-16 21:24:45 -04:00
Matthias Clasen 31d9ecb5c3 popover: Stop using ::set-focus
This will change completely when GtkPopover becomes a
root. For now, stop using ::set-focus and just use the
focus-widget property.
2019-03-16 21:24:44 -04:00
Matthias Clasen f13e6179e8 filechooser: Stop using ::set-focus
We can achieve the same with the focus-widget property.
2019-03-16 21:24:44 -04:00
Matthias Clasen d279c666a9 inspector: Stop using ::set-focus
The focus-widget is just a regular property now that shows
up on the property page. No need to special-case it on
the misc page anymore.
2019-03-16 21:24:44 -04:00
Matthias Clasen 7819a5aab9 Drop gtk_widget_send_focus_change
Replace this with gtk_widget_set_has_focus + gtk_widget_event.
2019-03-16 21:24:44 -04:00
Matthias Clasen 15300f839e widget: Add a private setter for has-focus 2019-03-16 21:24:44 -04:00
Matthias Clasen 94b0e99be5 Exclude non-drawable widgets from focus
This was showing up as confusion between palette
and editor in the color chooser.
2019-03-16 21:24:44 -04:00
Matthias Clasen 8c1d852a84 widget: Drop the ::focus signal
The focus vfunc is an implementation detail
of GTK focus handling, and having external
signal handlers interfere with it is not
a good idea.
2019-03-16 21:24:44 -04:00
Matthias Clasen 2738926dcb Simplify the move_focus api
No need to pass the array in from the outside.
2019-03-16 21:24:44 -04:00
Matthias Clasen 029ec38e63 Move a check to gtk_window_set_focus
gtk_widget_grab_focus is just a wrapper for
gtk_window_set_focus. We should do all the enforcement
there.
2019-03-16 21:24:44 -04:00
Matthias Clasen 2bf1561b48 Port widgets to the root focus API 2019-03-16 21:24:44 -04:00
Matthias Clasen bd44831987 window: Implement the root focus api
This just uses the existing get/set_focus functions.
We keep them public for now.
2019-03-16 21:24:44 -04:00
Matthias Clasen ab5d3e756b root: Add focus
Add a getter and a setter for the focus widget.
The default implementations do nothing.
2019-03-16 21:24:44 -04:00
Matthias Clasen 92f1bdcf45 Redo focus handling
GtkWindow has a focus_widget that points to the current input focus.
GtkWidget has a focus_child that points to the child that contains
the input focus. Following the focus_child chain from the toplevel
always leads to the focus_widget. We never unset focus_child, we only
set it. We bubble focus change events.
2019-03-16 21:24:44 -04:00
Matthias Clasen 64b9114d98 password entry: Fix property notification
Both placeholder-text and activates-default were not
up to our usual standards for property notification,
and the tests complained.
2019-03-16 21:23:28 -04:00
Matthias Clasen a1cc809c60 search entry: Fix property notification
Both placeholder-text and activates-default were not
up to our usual standards for property notification,
and the tests complained.
2019-03-16 21:23:28 -04:00
Matthias Clasen 7c19ab66ee single selection: Skip tests properly
Do runtime checks for the GLib version,
instead of compiling out tests.
This avoids compiler warnings.
2019-03-16 21:23:28 -04:00
Matthias Clasen 7ca528b896 widget: Check rootness for invisibility
Make the function that determines initial visibility
look at whether the class implements GtkRoot. That is
the eventual goal for this check. For now, allow
popovers in here as well.
2019-03-16 21:23:28 -04:00
Jordi Mas 2870f4dbfe Update Catalan translation 2019-03-16 22:06:43 +01:00
Matthias Clasen f14d998c95 password entry: Don't show both icons
It can be a bit confusing to have an indicator
and an action next to each other, and with the
peek icon, the need for the Caps Lock warning is
reduced, since you can just reveal the text to
see that it is capitalized.

Therefore, only show the Caps Lock warning if
the peek icon is disabled.
2019-03-15 14:35:25 -04:00
Matthias Clasen 34e859a5bc Add a tagged entry demo
This can serve as an example for how composite entries
can now be done outside of GTK, easily.
2019-03-15 13:21:26 -04:00
Matthias Clasen 5822a35087 gtk-demo: Show password peek icon 2019-03-14 20:43:15 -04:00
Matthias Clasen a3b73a416e password entry: Add a way to see the content
Add a ::show-peek-icon property and show a clickable
icon when it is set. Clicking it toggles the visibility
of the content. The same functionality is also accessible
via a context menu item.

This is a common feature of password entries.
2019-03-14 20:31:45 -04:00
Matthias Clasen d3cecd65a5 password entry: Make the Caps Lock icon less prominent
Set a style class, and theme the Caps Lock icon to
be  less promient, so it does not appear clickable.
2019-03-14 20:03:34 -04:00
Matthias Clasen 470720e11a password entry: Use text cursor for Caps Lock indicator
We don't want it to appear clickable, but we still
need to keep it pickable for the tooltip to work,
so explicitly give it the same cursor that we use
for the text.
2019-03-14 19:17:39 -04:00
Matthias Clasen c3f43cf1f2 entry: Make progress bar not pickable
There is no need for that, we don't want to
handle input here at all.
2019-03-14 19:15:31 -04:00
Matthias Clasen 5251253fc0 password entry: a better Caps Lock icon
This is more in line with how Caps Lock
is typically indicated.
2019-03-14 19:00:37 -04:00
Matthias Clasen f5e112fd2d gtk-demo: Add a password entry demo 2019-03-14 18:55:51 -04:00
Matthias Clasen 56ee1f3566 password entry: Add placeholder-text and activates-default
Add ::placeholder-text and ::activates-default properties.
Password entries are going to be used in dialogs, where
these two properties are useful.
2019-03-14 18:42:07 -04:00
Matthias Clasen 4afad781fe password entry: Initialize capslock state
The icon was erroneously showing up before the first
focus-in event.
2019-03-14 17:58:10 -04:00
Matthias Clasen 8e4c441f78 a11y: More entry fixes
Remove the GtkEntry assumption from more places.
2019-03-14 17:58:02 -04:00
Alex Monday d07cd892e7 Adwaita: Drop checkbox-selectionmode assets 2019-03-13 14:12:45 +05:00
Matej Urbančič 44198cc779 Updated Slovenian translation 2019-03-12 20:25:31 +01:00
Alex Monday 4bba279085 Adwaita: Fix selection-mode checkboxes
Use object-select-symbolic as a check icon, adjust styles.

Closes https://gitlab.gnome.org/GNOME/gtk/issues/28
2019-03-12 22:05:08 +05:00
Nathan Follens f454a31caa Update Dutch translation 2019-03-10 13:02:39 +00:00
Benjamin Otte 3863e44360 text: Simplify
The previous arguments were equivalent to using NULL.
2019-03-08 14:12:17 +01:00
Benjamin Otte 8566218485 text: Remove two unused member variables 2019-03-08 14:12:04 +01:00
Benjamin Otte 1475575799 text: Use gtk_widget_set_overflow() 2019-03-08 13:39:52 +01:00
Benjamin Otte bc901ffa5a text: Remove 2 unused variables
One is always 0, the other is always equal to gtk_widget_get_width()
2019-03-08 13:33:54 +01:00
Benjamin Otte b114d45c5f colorswatch: Use gtk_widget_set_overflow() 2019-03-08 13:20:17 +01:00
Benjamin Otte 9a1c698070 widget: Make overflow respect rounded corners
Fixes !574
2019-03-08 13:20:17 +01:00
Bastien Nocera 884088f649 gsk: API docs fixes
gsk/gskenums.h:181: Error: Gsk: multiple "@GSK_TRANSFORM_CATEGORY_2D" parameters for identifier "GskTransformCategory":
 * @GSK_TRANSFORM_CATEGORY_2D: The matrix is a 2D matrix. This is equivalent
    ^
gsk/gsktransform.c:1342: Warning: Gsk: gsk_transform_to_2d: unknown parameter 'm' in documentation comment, should be 'self'
gsk/gsktransform.c:1368: Warning: Gsk: gsk_transform_to_2d: invalid return annotation
gsk/gsktransform.c:1461: Warning: Gsk: gsk_transform_to_translate: unknown parameter 'm' in documentation comment, should be 'self'
2019-03-07 16:29:28 +01:00
Benjamin Otte ad5c5d477e revealer: Add swing transitions
And make the revealer on page 2 of the widget-factory use one.
2019-03-07 15:06:12 +01:00
Piotr Drąg 1513bf4174 Update Polish translation 2019-03-07 11:56:27 +01:00
Matthias Clasen eacbeb9efd x11: Don't emit GDK_NOTHING events
They are good for nothing.
2019-03-06 23:42:36 -05:00
Benjamin Otte 18da852e15 rendernode: Add can_diff implementation for transform nodes
That one was missing and killing performance in the fishbowl.
2019-03-06 12:40:58 +01:00
Timm Bäder 39fbf13fcb entry: Update CSS node docs
Remove all the nodes that are subnodes of GtkText nowadays and refer to
the GtkText docs instead.
2019-03-06 09:03:17 +01:00
Timm Bäder 9105de9170 gl renderer: Cache rendered fallback nodes 2019-03-06 06:31:25 +01:00
Timm Bäder eeed55d45c gl renderer: Mark pointer textures as used
Otherwise we remove them, causing additional texture uploads.
2019-03-06 06:31:25 +01:00
Benjamin Otte 3a3b325f8e transform: Add perspective()
This commit adds gsk_transform_perspective(), gtk_snapshot_perspective()
and support for perspective() in the CSS syntax.
2019-03-05 20:46:00 +01:00
266 changed files with 14059 additions and 12430 deletions
+1
View File
@@ -26,6 +26,7 @@ ccache --show-stats
xvfb-run -a -s "-screen 0 1024x768x24" \
meson test \
--timeout-multiplier 2 \
--print-errorlogs \
--suite=gtk \
--no-suite=gtk:gsk \
+9
View File
@@ -189,6 +189,7 @@
<file>paintable_animated.c</file>
<file>paintable_mediastream.c</file>
<file>panes.c</file>
<file>password_entry.c</file>
<file>pickers.c</file>
<file>pixbufs.c</file>
<file>popover.c</file>
@@ -206,6 +207,7 @@
<file>spinbutton.c</file>
<file>spinner.c</file>
<file>tabs.c</file>
<file>tagged_entry.c</file>
<file>textview.c</file>
<file>textscroll.c</file>
<file>theming_style_classes.c</file>
@@ -217,6 +219,9 @@
<gresource prefix="/textview">
<file>floppybuddy.gif</file>
</gresource>
<gresource prefix="/tagged_entry">
<file>tagstyle.css</file>
</gresource>
<gresource prefix="/listbox">
<file>listbox.ui</file>
<file>messages.txt</file>
@@ -261,6 +266,10 @@
<gresource prefix="/dnd">
<file>dnd.css</file>
</gresource>
<gresource prefix="/tagged_entry">
<file>demotaggedentry.c</file>
<file>demotaggedentry.h</file>
</gresource>
<gresource prefix="/org/gtk/Demo">
<file>icons/16x16/actions/application-exit.png</file>
<file>icons/16x16/actions/document-new.png</file>
+493
View File
@@ -0,0 +1,493 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2019 Red Hat, Inc.
*
* Authors:
* - Matthias Clasen <mclasen@redhat.com>
*
* 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 "demotaggedentry.h"
#include <gtk/gtk.h>
#include <gtk/gtk-a11y.h>
typedef struct {
GtkWidget *box;
GtkWidget *entry;
} DemoTaggedEntryPrivate;
static void demo_tagged_entry_editable_init (GtkEditableInterface *iface);
G_DEFINE_TYPE_WITH_CODE (DemoTaggedEntry, demo_tagged_entry, GTK_TYPE_WIDGET,
G_ADD_PRIVATE (DemoTaggedEntry)
G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE, demo_tagged_entry_editable_init))
static void
demo_tagged_entry_init (DemoTaggedEntry *entry)
{
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
gtk_widget_set_has_surface (GTK_WIDGET (entry), FALSE);
priv->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_parent (priv->box, GTK_WIDGET (entry));
priv->entry = gtk_text_new ();
gtk_widget_set_hexpand (priv->entry, TRUE);
gtk_widget_set_vexpand (priv->entry, TRUE);
gtk_widget_set_hexpand (priv->box, FALSE);
gtk_widget_set_vexpand (priv->box, FALSE);
gtk_container_add (GTK_CONTAINER (priv->box), priv->entry);
gtk_editable_init_delegate (GTK_EDITABLE (entry));
}
static void
demo_tagged_entry_dispose (GObject *object)
{
DemoTaggedEntry *entry = DEMO_TAGGED_ENTRY (object);
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
if (priv->entry)
gtk_editable_finish_delegate (GTK_EDITABLE (entry));
g_clear_pointer (&priv->entry, gtk_widget_unparent);
g_clear_pointer (&priv->box, gtk_widget_unparent);
G_OBJECT_CLASS (demo_tagged_entry_parent_class)->dispose (object);
}
static void
demo_tagged_entry_finalize (GObject *object)
{
G_OBJECT_CLASS (demo_tagged_entry_parent_class)->finalize (object);
}
static void
demo_tagged_entry_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
if (gtk_editable_delegate_set_property (object, prop_id, value, pspec))
return;
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
static void
demo_tagged_entry_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
if (gtk_editable_delegate_get_property (object, prop_id, value, pspec))
return;
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
static void
demo_tagged_entry_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
DemoTaggedEntry *entry = DEMO_TAGGED_ENTRY (widget);
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
gtk_widget_measure (priv->box, orientation, for_size,
minimum, natural,
minimum_baseline, natural_baseline);
}
static void
demo_tagged_entry_size_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
{
DemoTaggedEntry *entry = DEMO_TAGGED_ENTRY (widget);
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
gtk_widget_size_allocate (priv->box,
&(GtkAllocation) { 0, 0, width, height },
baseline);
}
static void
demo_tagged_entry_grab_focus (GtkWidget *widget)
{
DemoTaggedEntry *entry = DEMO_TAGGED_ENTRY (widget);
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
gtk_widget_grab_focus (priv->entry);
}
static void
demo_tagged_entry_class_init (DemoTaggedEntryClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = demo_tagged_entry_dispose;
object_class->finalize = demo_tagged_entry_finalize;
object_class->get_property = demo_tagged_entry_get_property;
object_class->set_property = demo_tagged_entry_set_property;
widget_class->measure = demo_tagged_entry_measure;
widget_class->size_allocate = demo_tagged_entry_size_allocate;
widget_class->grab_focus = demo_tagged_entry_grab_focus;
gtk_editable_install_properties (object_class, 1);
gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_ENTRY_ACCESSIBLE);
gtk_widget_class_set_css_name (widget_class, "entry");
}
static GtkEditable *
demo_tagged_entry_get_delegate (GtkEditable *editable)
{
DemoTaggedEntry *entry = DEMO_TAGGED_ENTRY (editable);
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
return GTK_EDITABLE (priv->entry);
}
static void
demo_tagged_entry_editable_init (GtkEditableInterface *iface)
{
iface->get_delegate = demo_tagged_entry_get_delegate;
}
GtkWidget *
demo_tagged_entry_new (void)
{
return GTK_WIDGET (g_object_new (DEMO_TYPE_TAGGED_ENTRY, NULL));
}
void
demo_tagged_entry_add_tag (DemoTaggedEntry *entry,
GtkWidget *tag)
{
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
g_return_if_fail (DEMO_IS_TAGGED_ENTRY (entry));
gtk_container_add (GTK_CONTAINER (priv->box), tag);
}
void
demo_tagged_entry_insert_tag_after (DemoTaggedEntry *entry,
GtkWidget *tag,
GtkWidget *sibling)
{
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
g_return_if_fail (DEMO_IS_TAGGED_ENTRY (entry));
if (sibling == NULL)
gtk_container_add (GTK_CONTAINER (priv->box), tag);
else
gtk_box_insert_child_after (GTK_BOX (priv->box), tag, sibling);
}
void
demo_tagged_entry_remove_tag (DemoTaggedEntry *entry,
GtkWidget *tag)
{
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
g_return_if_fail (DEMO_IS_TAGGED_ENTRY (entry));
gtk_container_remove (GTK_CONTAINER (priv->box), tag);
}
struct _DemoTaggedEntryTag
{
GtkWidget parent;
GtkWidget *box;
GtkWidget *label;
GtkWidget *button;
gboolean has_close_button;
char *style;
};
struct _DemoTaggedEntryTagClass
{
GtkWidgetClass parent_class;
};
enum {
PROP_0,
PROP_LABEL,
PROP_HAS_CLOSE_BUTTON,
};
enum {
SIGNAL_CLICKED,
SIGNAL_BUTTON_CLICKED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE (DemoTaggedEntryTag, demo_tagged_entry_tag, GTK_TYPE_WIDGET)
static void
on_released (GtkGestureMultiPress *gesture,
int n_press,
double x,
double y,
DemoTaggedEntryTag *tag)
{
g_signal_emit (tag, signals[SIGNAL_CLICKED], 0);
}
static void
demo_tagged_entry_tag_init (DemoTaggedEntryTag *tag)
{
GtkGesture *gesture;
GtkCssProvider *provider;
gtk_widget_set_has_surface (GTK_WIDGET (tag), FALSE);
tag->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_parent (tag->box, GTK_WIDGET (tag));
tag->label = gtk_label_new ("");
gtk_container_add (GTK_CONTAINER (tag->box), tag->label);
gesture = gtk_gesture_multi_press_new ();
g_signal_connect (gesture, "released", G_CALLBACK (on_released), tag);
gtk_widget_add_controller (GTK_WIDGET (tag), GTK_EVENT_CONTROLLER (gesture));
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider, "/tagged_entry/tagstyle.css");
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (provider),
800);
g_object_unref (provider);
}
static void
demo_tagged_entry_tag_dispose (GObject *object)
{
DemoTaggedEntryTag *tag = DEMO_TAGGED_ENTRY_TAG (object);
g_clear_pointer (&tag->box, gtk_widget_unparent);
G_OBJECT_CLASS (demo_tagged_entry_tag_parent_class)->dispose (object);
}
static void
demo_tagged_entry_tag_finalize (GObject *object)
{
DemoTaggedEntryTag *tag = DEMO_TAGGED_ENTRY_TAG (object);
g_clear_pointer (&tag->box, gtk_widget_unparent);
g_clear_pointer (&tag->style, g_free);
G_OBJECT_CLASS (demo_tagged_entry_tag_parent_class)->finalize (object);
}
static void
demo_tagged_entry_tag_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
DemoTaggedEntryTag *tag = DEMO_TAGGED_ENTRY_TAG (object);
switch (prop_id)
{
case PROP_LABEL:
demo_tagged_entry_tag_set_label (tag, g_value_get_string (value));
break;
case PROP_HAS_CLOSE_BUTTON:
demo_tagged_entry_tag_set_has_close_button (tag, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
demo_tagged_entry_tag_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
DemoTaggedEntryTag *tag = DEMO_TAGGED_ENTRY_TAG (object);
switch (prop_id)
{
case PROP_LABEL:
g_value_set_string (value, demo_tagged_entry_tag_get_label (tag));
break;
case PROP_HAS_CLOSE_BUTTON:
g_value_set_boolean (value, demo_tagged_entry_tag_get_has_close_button (tag));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
demo_tagged_entry_tag_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
DemoTaggedEntryTag *tag = DEMO_TAGGED_ENTRY_TAG (widget);
gtk_widget_measure (tag->box, orientation, for_size,
minimum, natural,
minimum_baseline, natural_baseline);
}
static void
demo_tagged_entry_tag_size_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
{
DemoTaggedEntryTag *tag = DEMO_TAGGED_ENTRY_TAG (widget);
gtk_widget_size_allocate (tag->box,
&(GtkAllocation) { 0, 0, width, height },
baseline);
}
static void
demo_tagged_entry_tag_class_init (DemoTaggedEntryTagClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->dispose = demo_tagged_entry_tag_dispose;
object_class->finalize = demo_tagged_entry_tag_finalize;
object_class->set_property = demo_tagged_entry_tag_set_property;
object_class->get_property = demo_tagged_entry_tag_get_property;
widget_class->measure = demo_tagged_entry_tag_measure;
widget_class->size_allocate = demo_tagged_entry_tag_size_allocate;
signals[SIGNAL_CLICKED] =
g_signal_new ("clicked",
DEMO_TYPE_TAGGED_ENTRY_TAG,
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
signals[SIGNAL_BUTTON_CLICKED] =
g_signal_new ("button-clicked",
DEMO_TYPE_TAGGED_ENTRY_TAG,
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
g_object_class_install_property (object_class, PROP_LABEL,
g_param_spec_string ("label", "Label", "Label",
NULL, G_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_HAS_CLOSE_BUTTON,
g_param_spec_boolean ("has-close-button", "Has close button", "Whether this tag has a close button",
FALSE, G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
gtk_widget_class_set_css_name (widget_class, "tag");
}
DemoTaggedEntryTag *
demo_tagged_entry_tag_new (const char *label)
{
return DEMO_TAGGED_ENTRY_TAG (g_object_new (DEMO_TYPE_TAGGED_ENTRY_TAG,
"label", label,
NULL));
}
const char *
demo_tagged_entry_tag_get_label (DemoTaggedEntryTag *tag)
{
g_return_val_if_fail (DEMO_IS_TAGGED_ENTRY_TAG (tag), NULL);
return gtk_label_get_label (GTK_LABEL (tag->label));
}
void
demo_tagged_entry_tag_set_label (DemoTaggedEntryTag *tag,
const char *label)
{
g_return_if_fail (DEMO_IS_TAGGED_ENTRY_TAG (tag));
gtk_label_set_label (GTK_LABEL (tag->label), label);
}
static void
on_button_clicked (GtkButton *button,
DemoTaggedEntryTag *tag)
{
g_signal_emit (tag, signals[SIGNAL_BUTTON_CLICKED], 0);
}
void
demo_tagged_entry_tag_set_has_close_button (DemoTaggedEntryTag *tag,
gboolean has_close_button)
{
g_return_if_fail (DEMO_IS_TAGGED_ENTRY_TAG (tag));
if ((tag->button != NULL) == has_close_button)
return;
if (!has_close_button && tag->button)
{
gtk_container_remove (GTK_CONTAINER (tag->box), tag->button);
tag->button = NULL;
}
else if (has_close_button && tag->button == NULL)
{
GtkWidget *image;
image = gtk_image_new_from_icon_name ("window-close-symbolic");
tag->button = gtk_button_new ();
gtk_container_add (GTK_CONTAINER (tag->button), image);
gtk_widget_set_halign (tag->button, GTK_ALIGN_CENTER);
gtk_widget_set_valign (tag->button, GTK_ALIGN_CENTER);
gtk_button_set_relief (GTK_BUTTON (tag->button), GTK_RELIEF_NONE);
gtk_container_add (GTK_CONTAINER (tag->box), tag->button);
g_signal_connect (tag->button, "clicked", G_CALLBACK (on_button_clicked), tag);
}
g_object_notify (G_OBJECT (tag), "has-close-button");
}
gboolean
demo_tagged_entry_tag_get_has_close_button (DemoTaggedEntryTag *tag)
{
g_return_val_if_fail (DEMO_IS_TAGGED_ENTRY_TAG (tag), FALSE);
return tag->button != NULL;
}
+89
View File
@@ -0,0 +1,89 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2019 Red Hat, Inc.
*
* Authors:
* - Matthias Clasen <mclasen@redhat.com>
*
* 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 __DEMO_TAGGED_ENTRY_H__
#define __DEMO_TAGGED_ENTRY_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define DEMO_TYPE_TAGGED_ENTRY (demo_tagged_entry_get_type ())
#define DEMO_TAGGED_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DEMO_TYPE_TAGGED_ENTRY, DemoTaggedEntry))
#define DEMO_TAGGED_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DEMO_TYPE_TAGGED_ENTRY, DemoTaggedEntryClass))
#define DEMO_IS_TAGGED_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DEMO_TYPE_TAGGED_ENTRY))
#define DEMO_IS_TAGGED_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DEMO_TYPE_TAGGED_ENTRY))
#define DEMO_TAGGED_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DEMO_TYPE_TAGGED_ENTRY, DemoTaggedEntryClass))
typedef struct _DemoTaggedEntry DemoTaggedEntry;
typedef struct _DemoTaggedEntryClass DemoTaggedEntryClass;
struct _DemoTaggedEntry
{
GtkWidget parent;
};
struct _DemoTaggedEntryClass
{
GtkWidgetClass parent_class;
};
#define DEMO_TYPE_TAGGED_ENTRY_TAG (demo_tagged_entry_tag_get_type ())
#define DEMO_TAGGED_ENTRY_TAG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DEMO_TYPE_TAGGED_ENTRY_TAG, DemoTaggedEntryTag))
#define DEMO_TAGGED_ENTRY_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DEMO_TYPE_TAGGED_ENTRY_TAG, DemoTaggedEntryTag))
#define DEMO_IS_TAGGED_ENTRY_TAG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DEMO_TYPE_TAGGED_ENTRY_TAG))
#define DEMO_IS_TAGGED_ENTRY_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DEMO_TYPE_TAGGED_ENTRY_TAG))
#define DEMO_TAGGED_ENTRY_TAG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DEMO_TYPE_TAGGED_ENTRY_TAG, DemoTaggedEntryTagClass))
typedef struct _DemoTaggedEntryTag DemoTaggedEntryTag;
typedef struct _DemoTaggedEntryTagClass DemoTaggedEntryTagClass;
GType demo_tagged_entry_get_type (void) G_GNUC_CONST;
GType demo_tagged_entry_tag_get_type (void) G_GNUC_CONST;
GtkWidget * demo_tagged_entry_new (void);
void demo_tagged_entry_add_tag (DemoTaggedEntry *entry,
GtkWidget *tag);
void demo_tagged_entry_insert_tag_after (DemoTaggedEntry *entry,
GtkWidget *tag,
GtkWidget *sibling);
void demo_tagged_entry_remove_tag (DemoTaggedEntry *entry,
GtkWidget *tag);
DemoTaggedEntryTag *
demo_tagged_entry_tag_new (const char *label);
const char * demo_tagged_entry_tag_get_label (DemoTaggedEntryTag *tag);
void demo_tagged_entry_tag_set_label (DemoTaggedEntryTag *tag,
const char *label);
gboolean demo_tagged_entry_tag_get_has_close_button (DemoTaggedEntryTag *tag);
void demo_tagged_entry_tag_set_has_close_button (DemoTaggedEntryTag *tag,
gboolean has_close_button);
G_END_DECLS
#endif /* __DEMO_TAGGED_ENTRY_H__ */
+2 -2
View File
@@ -196,7 +196,7 @@ edit_label_done (GtkWidget *entry, gpointer data)
GtkWidget *label;
int x, y;
gtk_container_child_get (GTK_CONTAINER (fixed), entry, "x", &x, "y", &y, NULL);
gtk_fixed_get_child_position (GTK_FIXED (fixed), entry, &x, &y);
label = GTK_WIDGET (g_object_get_data (G_OBJECT (entry), "label"));
gtk_label_set_text (GTK_LABEL (label), gtk_editable_get_text (GTK_EDITABLE (entry)));
@@ -210,7 +210,7 @@ edit_cb (GtkWidget *child)
GtkWidget *fixed = gtk_widget_get_parent (child);
int x, y;
gtk_container_child_get (GTK_CONTAINER (fixed), child, "x", &x, "y", &y, NULL);
gtk_fixed_get_child_position (GTK_FIXED (fixed), child, &x, &y);
if (GTK_IS_LABEL (child))
{
+9 -1
View File
@@ -47,6 +47,7 @@ demos = files([
'paintable_animated.c',
'paintable_mediastream.c',
'panes.c',
'password_entry.c',
'pickers.c',
'pixbufs.c',
'popover.c',
@@ -64,6 +65,7 @@ demos = files([
'spinner.c',
'stack.c',
'tabs.c',
'tagged_entry.c',
'textmask.c',
'textview.c',
'textscroll.c',
@@ -75,7 +77,13 @@ demos = files([
gtkdemo_deps = [ libgtk_dep, ]
extra_demo_sources = files(['main.c', 'gtkfishbowl.c', 'fontplane.c', 'gtkgears.c', 'puzzlepiece.c', 'bluroverlay.c'])
extra_demo_sources = files(['main.c',
'gtkfishbowl.c',
'fontplane.c',
'gtkgears.c',
'puzzlepiece.c',
'bluroverlay.c',
'demotaggedentry.c'])
if harfbuzz_dep.found() and pangoft_dep.found()
demos += files('font_features.c')
+89
View File
@@ -0,0 +1,89 @@
/* Entry/Password Entry
*
* GtkPasswordEntry provides common functionality of
* entries that are used to enter passwords and other
* secrets.
*
* It will display a warning if CapsLock is on, and it
* can optionally provide a way to see the text.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
static GtkWidget *entry;
static GtkWidget *entry2;
static GtkWidget *button;
static void
update_button (GObject *object,
GParamSpec *pspec,
gpointer data)
{
const char *text = gtk_editable_get_text (GTK_EDITABLE (entry));
const char *text2 = gtk_editable_get_text (GTK_EDITABLE (entry2));
gtk_widget_set_sensitive (button,
text[0] != '\0' && g_str_equal (text, text2));
}
GtkWidget *
do_password_entry (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
GtkWidget *box;
GtkWidget *header;
if (!window)
{
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
header = gtk_header_bar_new ();
gtk_header_bar_set_title (GTK_HEADER_BAR (header), "Choose a Password");
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), FALSE);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
gtk_window_set_deletable (GTK_WINDOW (window), FALSE);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
g_object_set (box, "margin", 18, NULL);
gtk_container_add (GTK_CONTAINER (window), box);
entry = gtk_password_entry_new ();
gtk_password_entry_set_show_peek_icon (GTK_PASSWORD_ENTRY (entry), TRUE);
g_object_set (entry,
"placeholder-text", "Password",
"activates-default", TRUE,
NULL);
g_signal_connect (entry, "notify::text", G_CALLBACK (update_button), NULL);
gtk_container_add (GTK_CONTAINER (box), entry);
entry2 = gtk_password_entry_new ();
gtk_password_entry_set_show_peek_icon (GTK_PASSWORD_ENTRY (entry2), TRUE);
g_object_set (entry2,
"placeholder-text", "Confirm",
"activates-default", TRUE,
NULL);
g_signal_connect (entry2, "notify::text", G_CALLBACK (update_button), NULL);
gtk_container_add (GTK_CONTAINER (box), entry2);
button = gtk_button_new_with_mnemonic ("_Done");
gtk_style_context_add_class (gtk_widget_get_style_context (button), "suggested-action");
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
gtk_widget_set_sensitive (button, FALSE);
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), button);
gtk_widget_set_can_default (button, TRUE);
gtk_window_set_default (GTK_WINDOW (window), button);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}
+112
View File
@@ -0,0 +1,112 @@
/* Entry/Tagged Entry
*
* This example shows how to build a complex composite
* entry using GtkText, outside of GTK.
*
* This tagged entry can display tags and other widgets
* inside the entry area.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "demotaggedentry.h"
static GtkWidget *spinner = NULL;
static void
closed_cb (DemoTaggedEntryTag *tag, DemoTaggedEntry *entry)
{
demo_tagged_entry_remove_tag (entry, GTK_WIDGET (tag));
}
static void
add_tag (GtkButton *button, DemoTaggedEntry *entry)
{
DemoTaggedEntryTag *tag;
tag = demo_tagged_entry_tag_new ("Blue");
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (tag)), "blue");
demo_tagged_entry_tag_set_has_close_button (tag, TRUE);
g_signal_connect (tag, "button-clicked", G_CALLBACK (closed_cb), entry);
if (spinner == NULL)
demo_tagged_entry_add_tag (entry, GTK_WIDGET (tag));
else
demo_tagged_entry_insert_tag_after (entry, GTK_WIDGET (tag), gtk_widget_get_prev_sibling (spinner));
}
static void
toggle_spinner (GtkCheckButton *button, DemoTaggedEntry *entry)
{
if (spinner)
{
demo_tagged_entry_remove_tag (entry, spinner);
spinner = NULL;
}
else
{
spinner = gtk_spinner_new ();
gtk_spinner_start (GTK_SPINNER (spinner));
demo_tagged_entry_add_tag (entry, spinner);
}
}
GtkWidget *
do_tagged_entry (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
GtkWidget *box;
GtkWidget *box2;
GtkWidget *header;
GtkWidget *entry;
GtkWidget *button;
if (!window)
{
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
header = gtk_header_bar_new ();
gtk_header_bar_set_title (GTK_HEADER_BAR (header), "A tagged entry");
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), FALSE);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
gtk_window_set_deletable (GTK_WINDOW (window), FALSE);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
g_object_set (box, "margin", 18, NULL);
gtk_container_add (GTK_CONTAINER (window), box);
entry = demo_tagged_entry_new ();
gtk_container_add (GTK_CONTAINER (box), entry);
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_widget_set_halign (box2, GTK_ALIGN_END);
gtk_container_add (GTK_CONTAINER (box), box2);
button = gtk_button_new_with_mnemonic ("Add _Tag");
g_signal_connect (button, "clicked", G_CALLBACK (add_tag), entry);
gtk_container_add (GTK_CONTAINER (box2), button);
button = gtk_check_button_new_with_mnemonic ("_Spinner");
g_signal_connect (button, "toggled", G_CALLBACK (toggle_spinner), entry);
gtk_container_add (GTK_CONTAINER (box2), button);
button = gtk_button_new_with_mnemonic ("_Done");
gtk_style_context_add_class (gtk_widget_get_style_context (button), "suggested-action");
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), button);
gtk_widget_set_can_default (button, TRUE);
gtk_window_set_default (GTK_WINDOW (window), button);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}
+19
View File
@@ -0,0 +1,19 @@
tag {
margin: 4px;
padding: 4px;
border-radius: 4px;
background: lightskyblue;
}
tag box {
border-spacing: 4px;
}
tag label,
tag image {
color: white;
}
tag button {
min-height: 0;
min-width: 0;
padding: 0;
border: 1px solid white;
}
+1
View File
@@ -1432,6 +1432,7 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<object class="GtkOverlay" id="page2">
<child type="overlay">
<object class="GtkRevealer" id="page2revealer">
<property name="transition-type">swing-down</property>
<property name="halign">center</property>
<property name="valign">start</property>
<child>
-1
View File
@@ -502,7 +502,6 @@ gdk_device_get_has_cursor
gdk_device_get_n_axes
gdk_device_get_n_keys
gdk_device_get_axes
gdk_device_warp
gdk_device_get_seat
<SUBSECTION>
+2 -1
View File
@@ -2,9 +2,9 @@
<FILE>GskRenderer</FILE>
gsk_renderer_new_for_surface
gsk_renderer_get_surface
gsk_renderer_get_display
gsk_renderer_realize
gsk_renderer_unrealize
gsk_renderer_is_realized
gsk_renderer_render
gsk_renderer_render_texture
<SUBSECTION Standard>
@@ -171,6 +171,7 @@ gsk_transform_rotate
gsk_transform_rotate_3d
gsk_transform_scale
gsk_transform_scale_3d
gsk_transform_perspective
<SUBSECTION>
gsk_transform_equal
<SUBSECTION>
+2 -16
View File
@@ -546,7 +546,7 @@ checkbutton:indeterminate {
GTK adds several additional ways to specify colors.
</para>
<literallayout><code>〈gtk color〉 = 〈symbolic color〉 | 〈color expression〉 | 〈win32 color〉</code>
<literallayout><code>〈gtk color〉 = 〈symbolic color〉 | 〈color expression〉</code>
</literallayout>
<para>
@@ -592,13 +592,6 @@ checkbutton:indeterminate {
<literallayout><code>〈color expression〉 = lighter( 〈color〉 ) | darker( 〈color〉 ) | shade( 〈color〉, 〈number〉 ) |</code>
<code> alpha( 〈color〉, 〈number〉 ) | mix( 〈color〉, 〈color〉, 〈number〉 )</code>
</literallayout>
<para>
On Windows, GTK allows to refer to system colors, as follows:
</para>
<literallayout><code>〈win32 color〉 = -gtk-win32-color( 〈name〉, 〈integer〉 )</code>
</literallayout>
</refsect2>
@@ -737,7 +730,7 @@ label {
GTK extends the CSS syntax for images and also uses it for specifying icons.
</para>
<literallayout><code>〈gtk image〉 = 〈themed icon〉 | 〈scaled image〉 | 〈recolored image〉 | 〈win32 theme part〉</code>
<literallayout><code>〈gtk image〉 = 〈themed icon〉 | 〈scaled image〉 | 〈recolored image〉</code>
</literallayout>
<para>
@@ -815,13 +808,6 @@ arrow {
}
]]></programlisting>
</example>
<para>
On Windows, GTK allows to refer to system theme parts as images, as follows:
</para>
<literallayout><code>〈win32 theme part〉 = -gtk-win32-theme-part( 〈name〉, 〈integer〉 〈integer〉</code>
<code> [ , [ over( 〈integer〉 〈integer〉 [ , 〈alpha value〉 ]? ) | margins( 〈integer〉{1,4} ) ] ]* )</code>
</literallayout>
</refsect2>
-14
View File
@@ -65,20 +65,6 @@ We use <literallayout> for syntax productions, and each line is put in a <code>
not quite the same as the CSS definition of rem.
</para>
<para>
Whereever a number is allowed, GTK also accepts a Windows-specific
theme size:
</para>
<literallayout>
<code>〈win32 theme size〉 = 〈win32 size〉 | 〈win32 part size〉</code>
<code>〈win32 size〉 = -gtk-win32-size ( 〈theme name〉, 〈metric id〉 )</code>
<code>〈win32 part size〉 = [ -gtk-win32-part-width | -gtk-win32-part-height |</code>
<code> -gtk-win32-part-border-top | -gtk-win32-part-border-right |</code>
<code> -gtk-win32-part-border-bottom | -gtk-win32-part-border-left ]</code>
<code> ( 〈theme name〉 , 〈integer〉 , 〈integer〉 )</code>
</literallayout>
<literallayout><code>〈calc expression〉 = calc( 〈calc sum〉 )</code>
<code>〈calc sum〉 = 〈calc product〉 [ [ + | - ] 〈calc product〉 ]*</code>
<code>〈calc product〉 = 〈calc value〉 [ * 〈calc value〉 | / 〈number〉 ]*</code>
+7
View File
@@ -100,6 +100,13 @@
<xi:include href="xml/gtkfixed.xml" />
</chapter>
<chapter id="LayoutManagers">
<title>Layout Managers</title>
<xi:include href="xml/gtklayoutmanager.xml" />
<xi:include href="xml/gtklayoutchild.xml" />
<xi:include href="xml/gtkboxlayout.xml" />
</chapter>
<chapter id="DisplayWidgets">
<title>Display Widgets</title>
<xi:include href="xml/gtklabel.xml" />
+61
View File
@@ -995,6 +995,8 @@ gtk_entry_get_type
<TITLE>GtkPasswordEntry</TITLE>
GtkPasswordEntry
gtk_password_entry_new
gtk_password_entry_set_show_peek_icon
gtk_password_entry_get_show_peek_icon
<SUBSECTION Private>
gtk_password_entry_get_type
</SECTION>
@@ -4388,6 +4390,7 @@ gtk_snapshot_rotate
gtk_snapshot_rotate_3d
gtk_snapshot_scale
gtk_snapshot_scale_3d
gtk_snapshot_perspective
gtk_snapshot_append_node
gtk_snapshot_append_cairo
gtk_snapshot_append_texture
@@ -4587,6 +4590,8 @@ gtk_widget_get_first_child
gtk_widget_get_last_child
gtk_widget_insert_before
gtk_widget_insert_after
gtk_widget_set_layout_manager
gtk_widget_get_layout_manager
<SUBSECTION>
gtk_widget_get_path
@@ -6681,6 +6686,8 @@ gtk_event_controller_scroll_get_type
<TITLE>GtkEventControllerMotion</TITLE>
GtkEventControllerMotion
gtk_event_controller_motion_new
gtk_event_controller_motion_get_pointer_origin
gtk_event_controller_motion_get_pointer_target
<SUBSECTION Standard>
GTK_TYPE_EVENT_CONTROLLER_MOTION
@@ -6699,6 +6706,12 @@ gtk_event_controller_motion_get_type
<TITLE>GtkEventControllerKey</TITLE>
GtkEventControllerKey
gtk_event_controller_key_new
gtk_event_controller_key_set_im_context
gtk_event_controller_key_get_im_context
gtk_event_controller_key_forward
gtk_event_controller_key_get_group
gtk_event_controller_key_get_focus_origin
gtk_event_controller_key_get_focus_target
<SUBSECTION Standard>
GTK_TYPE_EVENT_CONTROLLER_KEY
@@ -7141,3 +7154,51 @@ gtk_root_get_for_surface
<SUBSECTION Private>
gtk_root_get_type
</SECTION>
<SECTION>
<FILE>gtklayoutmanager</FILE>
GtkLayoutManager
GtkLayoutManagerClass
gtk_layout_manager_measure
gtk_layout_manager_allocate
gtk_layout_manager_get_request_mode
gtk_layout_manager_get_widget
gtk_layout_manager_get_layout_child
gtk_layout_manager_layout_changed
<SUBSECTION Standard>
GTK_TYPE_LAYOUT_MANAGER
gtk_layout_manager_get_type
</SECTION>
<SECTION>
<FILE>gtklayoutchild</FILE>
GtkLayoutChild
GtkLayoutChildClass
gtk_layout_child_get_layout_manager
gtk_layout_child_get_child_widget
<SUBSECTION Standard>
GTK_TYPE_LAYOUT_CHILD
gtk_layout_child_get_type
</SECTION>
<SECTION>
<FILE>gtkboxlayout</FILE>
GtkBoxLayout
GtkBoxLayoutClass
gtk_box_layout_new
gtk_box_layout_set_homogeneous
gtk_box_layout_get_homogeneous
gtk_box_layout_set_spacing
gtk_box_layout_get_spacing
gtk_box_layout_set_baseline_position
gtk_box_layout_get_baseline_position
<SUBSECTION Standard>
GTK_TYPE_BOX_LAYOUT
gtk_box_layout_get_type
</SECTION>
+5
View File
@@ -22,6 +22,9 @@ typedef enum { /* Sync changes with broadway.js */
BROADWAY_NODE_CLIP = 10,
BROADWAY_NODE_KEEP_ALL = 11,
BROADWAY_NODE_KEEP_THIS = 12,
BROADWAY_NODE_TRANSLATE = 13,
BROADWAY_NODE_DEBUG = 14,
BROADWAY_NODE_REUSE = 15,
} BroadwayNodeType;
static const char *broadway_node_type_names[] G_GNUC_UNUSED = {
@@ -38,6 +41,8 @@ static const char *broadway_node_type_names[] G_GNUC_UNUSED = {
"CLIP",
"KEEP_ALL",
"KEEP_THIS",
"TRANSLATE",
"DEBUG",
};
typedef enum {
+243 -26
View File
@@ -35,7 +35,6 @@
#include <string.h>
#endif
typedef struct {
int id;
guint32 tag;
@@ -126,23 +125,56 @@ struct BroadwaySurface {
gint32 transient_for;
guint32 texture;
BroadwayNode *nodes;
GHashTable *node_lookup;
};
struct _BroadwayTexture {
grefcount refcount;
guint32 id;
GBytes *bytes;
};
static void broadway_server_resync_surfaces (BroadwayServer *server);
static void send_outstanding_roundtrips (BroadwayServer *server);
static void broadway_server_ref_texture (BroadwayServer *server,
guint32 id);
static GType broadway_server_get_type (void);
G_DEFINE_TYPE (BroadwayServer, broadway_server, G_TYPE_OBJECT)
static void
broadway_node_free (BroadwayNode *node)
broadway_texture_free (BroadwayTexture *texture)
{
g_bytes_unref (texture->bytes);
g_free (texture);
}
static void
broadway_node_unref (BroadwayServer *server,
BroadwayNode *node)
{
int i;
for (i = 0; i < node->n_children; i++)
broadway_node_free (node->children[i]);
g_free (node);
if (g_ref_count_dec (&node->refcount))
{
for (i = 0; i < node->n_children; i++)
broadway_node_unref (server, node->children[i]);
if (node->texture_id)
broadway_server_release_texture (server, node->texture_id);
g_free (node);
}
}
static BroadwayNode *
broadway_node_ref (BroadwayNode *node)
{
g_ref_count_inc (&node->refcount);
return node;
}
gboolean
@@ -204,7 +236,7 @@ broadway_server_init (BroadwayServer *server)
server->surface_id_hash = g_hash_table_new (NULL, NULL);
server->id_counter = 0;
server->textures = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
(GDestroyNotify)g_bytes_unref);
(GDestroyNotify)broadway_texture_free);
root = g_new0 (BroadwaySurface, 1);
root->id = server->id_counter++;
@@ -241,10 +273,12 @@ broadway_server_class_init (BroadwayServerClass * class)
}
static void
broadway_surface_free (BroadwaySurface *surface)
broadway_surface_free (BroadwayServer *server,
BroadwaySurface *surface)
{
if (surface->nodes)
broadway_node_free (surface->nodes);
broadway_node_unref (server, surface->nodes);
g_hash_table_unref (surface->node_lookup);
g_free (surface);
}
@@ -1477,7 +1511,7 @@ broadway_server_destroy_surface (BroadwayServer *server,
server->surfaces = g_list_remove (server->surfaces, surface);
g_hash_table_remove (server->surface_id_hash,
GINT_TO_POINTER (id));
broadway_surface_free (surface);
broadway_surface_free (server, surface);
}
}
@@ -1605,53 +1639,232 @@ broadway_server_has_client (BroadwayServer *server)
return server->output != NULL;
}
#define NODE_SIZE_COLOR 1
#define NODE_SIZE_FLOAT 1
#define NODE_SIZE_POINT 2
#define NODE_SIZE_SIZE 2
#define NODE_SIZE_RECT (NODE_SIZE_POINT + NODE_SIZE_SIZE)
#define NODE_SIZE_RRECT (NODE_SIZE_RECT + 4 * NODE_SIZE_SIZE)
#define NODE_SIZE_COLOR_STOP (NODE_SIZE_FLOAT + NODE_SIZE_COLOR)
#define NODE_SIZE_SHADOW (NODE_SIZE_COLOR + 3 * NODE_SIZE_FLOAT)
static guint32
rotl (guint32 value, int shift)
{
if ((shift &= 32 - 1) == 0)
return value;
return (value << shift) | (value >> (32 - shift));
}
static BroadwayNode *
decode_nodes (BroadwayServer *server,
BroadwaySurface *surface,
int len,
guint32 data[],
GHashTable *client_texture_map,
int *pos)
{
BroadwayNode *node;
guint32 type, id;
guint32 i, n_stops, n_shadows, n_chars;
guint32 size, n_children;
gint32 texture_offset;
guint32 hash;
g_assert (*pos < len);
size = 0;
n_children = 0;
texture_offset = -1;
type = data[(*pos)++];
id = data[(*pos)++];
switch (type) {
case BROADWAY_NODE_REUSE:
node = g_hash_table_lookup (surface->node_lookup, GINT_TO_POINTER(id));
g_assert (node != NULL);
return broadway_node_ref (node);
break;
case BROADWAY_NODE_COLOR:
size = NODE_SIZE_RECT + NODE_SIZE_COLOR;
break;
case BROADWAY_NODE_BORDER:
size = NODE_SIZE_RRECT + 4 * NODE_SIZE_FLOAT + 4 * NODE_SIZE_COLOR;
break;
case BROADWAY_NODE_INSET_SHADOW:
case BROADWAY_NODE_OUTSET_SHADOW:
size = NODE_SIZE_RRECT + NODE_SIZE_COLOR + 4 * NODE_SIZE_FLOAT;
break;
case BROADWAY_NODE_TEXTURE:
texture_offset = 4;
size = 5;
break;
case BROADWAY_NODE_CONTAINER:
size = 1;
n_children = data[*pos];
break;
case BROADWAY_NODE_ROUNDED_CLIP:
size = NODE_SIZE_RRECT;
n_children = 1;
break;
case BROADWAY_NODE_CLIP:
size = NODE_SIZE_RECT;
n_children = 1;
break;
case BROADWAY_NODE_TRANSLATE:
size = NODE_SIZE_POINT;
n_children = 1;
break;
case BROADWAY_NODE_LINEAR_GRADIENT:
size = NODE_SIZE_RECT + 2 * NODE_SIZE_POINT;
n_stops = data[*pos + size++];
size += n_stops * NODE_SIZE_COLOR_STOP;
break;
case BROADWAY_NODE_SHADOW:
size = 1;
n_shadows = data[*pos];
size += n_shadows * NODE_SIZE_SHADOW;
n_children = 1;
break;
case BROADWAY_NODE_OPACITY:
size = NODE_SIZE_FLOAT;
n_children = 1;
break;
case BROADWAY_NODE_DEBUG:
n_chars = data[*pos];
size = 1 + (n_chars + 3) / 4;
n_children = 1;
break;
default:
g_assert_not_reached ();
}
node = g_malloc (sizeof(BroadwayNode) + (size - 1) * sizeof(guint32) + n_children * sizeof (BroadwayNode *));
g_ref_count_init (&node->refcount);
node->type = type;
node->id = id;
node->texture_id = 0;
node->n_children = n_children;
node->children = (BroadwayNode **)((char *)node + sizeof(BroadwayNode) + (size - 1) * sizeof(guint32));
node->n_data = size;
for (i = 0; i < size; i++)
{
node->data[i] = data[(*pos)++];
if (i == texture_offset)
{
node->texture_id = GPOINTER_TO_INT (g_hash_table_lookup (client_texture_map, GINT_TO_POINTER (node->data[i])));
broadway_server_ref_texture (server, node->texture_id);
node->data[i] = node->texture_id;
}
}
for (i = 0; i < n_children; i++)
node->children[i] = decode_nodes (server, surface, len, data, client_texture_map, pos);
hash = node->type << 16;
for (i = 0; i < size; i++)
hash ^= rotl (node->data[i], i);
for (i = 0; i < n_children; i++)
hash ^= rotl (node->children[i]->hash, i);
node->hash = hash;
return node;
}
static void
init_node_lookup (BroadwaySurface *surface,
BroadwayNode *node)
{
int i;
g_hash_table_insert (surface->node_lookup, GINT_TO_POINTER(node->id), node);
for (i = 0; i < node->n_children; i++)
init_node_lookup (surface, node->children[i]);
}
/* passes ownership of nodes */
void
broadway_server_surface_set_nodes (BroadwayServer *server,
gint id,
BroadwayNode *root)
broadway_server_surface_update_nodes (BroadwayServer *server,
gint id,
guint32 data[],
int len,
GHashTable *client_texture_map)
{
BroadwaySurface *surface;
int pos = 0;
BroadwayNode *root;
surface = broadway_server_lookup_surface (server, id);
if (surface == NULL)
return;
root = decode_nodes (server, surface, len, data, client_texture_map, &pos);
if (server->output != NULL)
broadway_output_surface_set_nodes (server->output, surface->id,
root,
surface->nodes);
if (surface->nodes)
broadway_node_free (surface->nodes);
broadway_node_unref (server, surface->nodes);
surface->nodes = root;
g_hash_table_remove_all (surface->node_lookup);
init_node_lookup (surface, surface->nodes);
}
guint32
broadway_server_upload_texture (BroadwayServer *server,
GBytes *texture)
GBytes *bytes)
{
guint32 id;
BroadwayTexture *texture;
texture = g_new0 (BroadwayTexture, 1);
g_ref_count_init (&texture->refcount);
texture->id = ++server->next_texture_id;
texture->bytes = g_bytes_ref (bytes);
id = ++server->next_texture_id;
g_hash_table_replace (server->textures,
GINT_TO_POINTER (id),
g_bytes_ref (texture));
GINT_TO_POINTER (texture->id),
texture);
if (server->output)
broadway_output_upload_texture (server->output, id, texture);
broadway_output_upload_texture (server->output, texture->id, texture->bytes);
return id;
return texture->id;
}
static void
broadway_server_ref_texture (BroadwayServer *server,
guint32 id)
{
BroadwayTexture *texture;
texture = g_hash_table_lookup (server->textures, GINT_TO_POINTER (id));
if (texture)
g_ref_count_inc (&texture->refcount);
}
void
broadway_server_release_texture (BroadwayServer *server,
guint32 id)
{
g_hash_table_remove (server->textures, GINT_TO_POINTER (id));
BroadwayTexture *texture;
if (server->output)
broadway_output_release_texture (server->output, id);
texture = g_hash_table_lookup (server->textures, GINT_TO_POINTER (id));
if (texture && g_ref_count_dec (&texture->refcount))
{
g_hash_table_remove (server->textures, GINT_TO_POINTER (id));
if (server->output)
broadway_output_release_texture (server->output, id);
}
}
gboolean
@@ -1801,6 +2014,7 @@ broadway_server_new_surface (BroadwayServer *server,
surface->width = width;
surface->height = height;
surface->is_temp = is_temp;
surface->node_lookup = g_hash_table_new (g_direct_hash, g_direct_equal);
g_hash_table_insert (server->surface_id_hash,
GINT_TO_POINTER (surface->id),
@@ -1835,9 +2049,12 @@ broadway_server_resync_surfaces (BroadwayServer *server)
/* First upload all textures */
g_hash_table_iter_init (&iter, server->textures);
while (g_hash_table_iter_next (&iter, &key, &value))
broadway_output_upload_texture (server->output,
GPOINTER_TO_INT (key),
(GBytes *)value);
{
BroadwayTexture *texture = value;
broadway_output_upload_texture (server->output,
GPOINTER_TO_INT (key),
texture->bytes);
}
/* Then create all surfaces */
for (l = server->surfaces; l != NULL; l = l->next)
+8 -2
View File
@@ -19,12 +19,16 @@ typedef struct _BroadwayServerClass BroadwayServerClass;
#define BROADWAY_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), BROADWAY_TYPE_SERVER, BroadwayServerClass))
typedef struct _BroadwayNode BroadwayNode;
typedef struct _BroadwayTexture BroadwayTexture;
struct _BroadwayNode {
grefcount refcount;
guint32 type;
guint32 id;
guint32 hash; /* deep hash */
guint32 n_children;
BroadwayNode **children;
guint32 texture_id;
guint32 n_data;
guint32 data[1];
};
@@ -99,9 +103,11 @@ void broadway_server_release_texture (BroadwayServer *
guint32 id);
cairo_surface_t * broadway_server_create_surface (int width,
int height);
void broadway_server_surface_set_nodes (BroadwayServer *server,
void broadway_server_surface_update_nodes (BroadwayServer *server,
gint id,
BroadwayNode *root);
guint32 data[],
int len,
GHashTable *client_texture_map);
gboolean broadway_server_surface_move_resize (BroadwayServer *server,
gint id,
gboolean with_move,
+500 -276
View File
File diff suppressed because it is too large Load Diff
+3 -116
View File
@@ -215,116 +215,6 @@ get_client_serial (BroadwayClient *client, guint32 daemon_serial)
return client_serial;
}
#define NODE_SIZE_COLOR 1
#define NODE_SIZE_FLOAT 1
#define NODE_SIZE_POINT 2
#define NODE_SIZE_SIZE 2
#define NODE_SIZE_RECT (NODE_SIZE_POINT + NODE_SIZE_SIZE)
#define NODE_SIZE_RRECT (NODE_SIZE_RECT + 4 * NODE_SIZE_SIZE)
#define NODE_SIZE_COLOR_STOP (NODE_SIZE_FLOAT + NODE_SIZE_COLOR)
#define NODE_SIZE_SHADOW (NODE_SIZE_COLOR + 3 * NODE_SIZE_FLOAT)
static guint32
rotl (guint32 value, int shift)
{
if ((shift &= 32 - 1) == 0)
return value;
return (value << shift) | (value >> (32 - shift));
}
static BroadwayNode *
decode_nodes (BroadwayClient *client,
int len, guint32 data[], int *pos)
{
BroadwayNode *node;
guint32 type;
guint32 i, n_stops, n_shadows;
guint32 size, n_children;
gint32 texture_offset;
guint32 hash;
g_assert (*pos < len);
size = 0;
n_children = 0;
texture_offset = -1;
type = data[(*pos)++];
switch (type) {
case BROADWAY_NODE_COLOR:
size = NODE_SIZE_RECT + NODE_SIZE_COLOR;
break;
case BROADWAY_NODE_BORDER:
size = NODE_SIZE_RRECT + 4 * NODE_SIZE_FLOAT + 4 * NODE_SIZE_COLOR;
break;
case BROADWAY_NODE_INSET_SHADOW:
case BROADWAY_NODE_OUTSET_SHADOW:
size = NODE_SIZE_RRECT + NODE_SIZE_COLOR + 4 * NODE_SIZE_FLOAT;
break;
case BROADWAY_NODE_TEXTURE:
texture_offset = 4;
size = 5;
break;
case BROADWAY_NODE_CONTAINER:
size = 1;
n_children = data[*pos];
break;
case BROADWAY_NODE_ROUNDED_CLIP:
size = NODE_SIZE_RRECT;
n_children = 1;
break;
case BROADWAY_NODE_CLIP:
size = NODE_SIZE_RECT;
n_children = 1;
break;
case BROADWAY_NODE_LINEAR_GRADIENT:
size = NODE_SIZE_RECT + 2 * NODE_SIZE_POINT;
n_stops = data[*pos + size++];
size += n_stops * NODE_SIZE_COLOR_STOP;
break;
case BROADWAY_NODE_SHADOW:
size = 1;
n_shadows = data[*pos];
size += n_shadows * NODE_SIZE_SHADOW;
n_children = 1;
break;
case BROADWAY_NODE_OPACITY:
size = NODE_SIZE_FLOAT;
n_children = 1;
break;
default:
g_assert_not_reached ();
}
node = g_malloc (sizeof(BroadwayNode) + (size - 1) * sizeof(guint32) + n_children * sizeof (BroadwayNode *));
node->type = type;
node->n_children = n_children;
node->children = (BroadwayNode **)((char *)node + sizeof(BroadwayNode) + (size - 1) * sizeof(guint32));
node->n_data = size;
for (i = 0; i < size; i++)
{
node->data[i] = data[(*pos)++];
if (i == texture_offset)
node->data[i] = GPOINTER_TO_INT (g_hash_table_lookup (client->textures,
GINT_TO_POINTER (node->data[i])));
}
for (i = 0; i < n_children; i++)
node->children[i] = decode_nodes (client, len, data, pos);
hash = node->type << 16;
for (i = 0; i < size; i++)
hash ^= rotl (node->data[i], i);
for (i = 0; i < n_children; i++)
hash ^= rotl (node->children[i]->hash, i);
node->hash = hash;
return node;
}
static void
client_handle_request (BroadwayClient *client,
BroadwayRequest *request)
@@ -400,13 +290,10 @@ client_handle_request (BroadwayClient *client,
{
gsize array_size = request->base.size - sizeof (BroadwayRequestSetNodes) + sizeof(guint32);
int n_data = array_size / sizeof(guint32);
int pos = 0;
BroadwayNode *node;
node = decode_nodes (client, n_data, request->set_nodes.data, &pos);
broadway_server_surface_set_nodes (server, request->set_nodes.id,
node);
broadway_server_surface_update_nodes (server, request->set_nodes.id,
request->set_nodes.data, n_data,
client->textures);
}
break;
case BROADWAY_REQUEST_UPLOAD_TEXTURE:
-11
View File
@@ -36,9 +36,6 @@ static void gdk_broadway_device_get_state (GdkDevice *device,
static void gdk_broadway_device_set_surface_cursor (GdkDevice *device,
GdkSurface *surface,
GdkCursor *cursor);
static void gdk_broadway_device_warp (GdkDevice *device,
gdouble x,
gdouble y);
static void gdk_broadway_device_query_state (GdkDevice *device,
GdkSurface *surface,
GdkSurface **child_surface,
@@ -73,7 +70,6 @@ gdk_broadway_device_class_init (GdkBroadwayDeviceClass *klass)
device_class->get_history = gdk_broadway_device_get_history;
device_class->get_state = gdk_broadway_device_get_state;
device_class->set_surface_cursor = gdk_broadway_device_set_surface_cursor;
device_class->warp = gdk_broadway_device_warp;
device_class->query_state = gdk_broadway_device_query_state;
device_class->grab = gdk_broadway_device_grab;
device_class->ungrab = gdk_broadway_device_ungrab;
@@ -126,13 +122,6 @@ gdk_broadway_device_set_surface_cursor (GdkDevice *device,
{
}
static void
gdk_broadway_device_warp (GdkDevice *device,
gdouble x,
gdouble y)
{
}
static void
gdk_broadway_device_query_state (GdkDevice *device,
GdkSurface *surface,
+1 -1
View File
@@ -380,7 +380,7 @@ gdk_broadway_display_ensure_texture (GdkDisplay *display,
data = g_new0 (BroadwayTextureData, 1);
data->id = id;
data->display = g_object_ref (display);
g_object_set_data_full (G_OBJECT (texture), "broadway-data", data, (GDestroyNotify)broadway_texture_data_free);
g_object_set_data_full (G_OBJECT (texture), "broadway-data", data, (GDestroyNotify)broadway_texture_data_free);
}
return data->id;
+2
View File
@@ -64,6 +64,8 @@ gdk_broadway_draw_context_end_frame (GdkDrawContext *draw_context,
g_array_unref (self->nodes);
self->nodes = NULL;
/* We now sent all new texture refs to the daemon via the nodes, so we can drop them here */
g_ptr_array_unref (self->node_textures);
self->node_textures = NULL;
}
+6
View File
@@ -1232,6 +1232,9 @@ gdk_broadway_surface_begin_resize_drag (GdkSurface *surface,
mv_resize = get_move_resize_data (gdk_surface_get_display (surface), TRUE);
if (mv_resize->moveresize_surface != NULL)
return; /* already a drag operation in progress */
mv_resize->is_resize = TRUE;
mv_resize->moveresize_button = button;
mv_resize->resize_edge = edge;
@@ -1272,6 +1275,9 @@ gdk_broadway_surface_begin_move_drag (GdkSurface *surface,
mv_resize = get_move_resize_data (gdk_surface_get_display (surface), TRUE);
if (mv_resize->moveresize_surface != NULL)
return; /* already a drag operation in progress */
mv_resize->is_resize = FALSE;
mv_resize->moveresize_button = button;
mv_resize->moveresize_x = root_x;
-2
View File
@@ -20,8 +20,6 @@ void gdk_surface_thaw_toplevel_updates (GdkSurface *surface);
gboolean gdk_surface_supports_edge_constraints (GdkSurface *surface);
GObject * gdk_event_get_user_data (const GdkEvent *event);
guint32 gdk_display_get_last_seen_time (GdkDisplay *display);
void gdk_display_set_double_click_time (GdkDisplay *display,
+2
View File
@@ -33,6 +33,8 @@
#include "gdk-private.h"
#include "gdkconstructor.h"
#ifndef HAVE_XCONVERTCASE
#include "gdkkeysyms.h"
#endif
+120
View File
@@ -0,0 +1,120 @@
/*
If G_HAS_CONSTRUCTORS is true then the compiler support *both* constructors and
destructors, in a sane way, including e.g. on library unload. If not you're on
your own.
Some compilers need #pragma to handle this, which does not work with macros,
so the way you need to use this is (for constructors):
#ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA
#pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(my_constructor)
#endif
G_DEFINE_CONSTRUCTOR(my_constructor)
static void my_constructor(void) {
...
}
*/
#ifndef __GTK_DOC_IGNORE__
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
#define G_HAS_CONSTRUCTORS 1
#define G_DEFINE_CONSTRUCTOR(_func) static void __attribute__((constructor)) _func (void);
#define G_DEFINE_DESTRUCTOR(_func) static void __attribute__((destructor)) _func (void);
#elif defined (_MSC_VER) && (_MSC_VER >= 1500)
/* Visual studio 2008 and later has _Pragma */
#define G_HAS_CONSTRUCTORS 1
/* We do some weird things to avoid the constructors being optimized
* away on VS2015 if WholeProgramOptimization is enabled. First we
* make a reference to the array from the wrapper to make sure its
* references. Then we use a pragma to make sure the wrapper function
* symbol is always included at the link stage. Also, the symbols
* need to be extern (but not dllexport), even though they are not
* really used from another object file.
*/
/* We need to account for differences between the mangling of symbols
* for Win32 (x86) and x64 programs, as symbols on Win32 are prefixed
* with an underscore but symbols on x64 are not.
*/
#ifdef _WIN64
#define G_MSVC_SYMBOL_PREFIX ""
#else
#define G_MSVC_SYMBOL_PREFIX "_"
#endif
#define G_DEFINE_CONSTRUCTOR(_func) G_MSVC_CTOR (_func, G_MSVC_SYMBOL_PREFIX)
#define G_DEFINE_DESTRUCTOR(_func) G_MSVC_DTOR (_func, G_MSVC_SYMBOL_PREFIX)
#define G_MSVC_CTOR(_func,_sym_prefix) \
static void _func(void); \
extern int (* _array ## _func)(void); \
int _func ## _wrapper(void) { _func(); g_slist_find (NULL, _array ## _func); return 0; } \
__pragma(comment(linker,"/include:" _sym_prefix # _func "_wrapper")) \
__pragma(section(".CRT$XCU",read)) \
__declspec(allocate(".CRT$XCU")) int (* _array ## _func)(void) = _func ## _wrapper;
#define G_MSVC_DTOR(_func,_sym_prefix) \
static void _func(void); \
extern int (* _array ## _func)(void); \
int _func ## _constructor(void) { atexit (_func); g_slist_find (NULL, _array ## _func); return 0; } \
__pragma(comment(linker,"/include:" _sym_prefix # _func "_constructor")) \
__pragma(section(".CRT$XCU",read)) \
__declspec(allocate(".CRT$XCU")) int (* _array ## _func)(void) = _func ## _constructor;
#elif defined (_MSC_VER)
#define G_HAS_CONSTRUCTORS 1
/* Pre Visual studio 2008 must use #pragma section */
#define G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA 1
#define G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA 1
#define G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(_func) \
section(".CRT$XCU",read)
#define G_DEFINE_CONSTRUCTOR(_func) \
static void _func(void); \
static int _func ## _wrapper(void) { _func(); return 0; } \
__declspec(allocate(".CRT$XCU")) static int (*p)(void) = _func ## _wrapper;
#define G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(_func) \
section(".CRT$XCU",read)
#define G_DEFINE_DESTRUCTOR(_func) \
static void _func(void); \
static int _func ## _constructor(void) { atexit (_func); return 0; } \
__declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor;
#elif defined(__SUNPRO_C)
/* This is not tested, but i believe it should work, based on:
* http://opensource.apple.com/source/OpenSSL098/OpenSSL098-35/src/fips/fips_premain.c
*/
#define G_HAS_CONSTRUCTORS 1
#define G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA 1
#define G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA 1
#define G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(_func) \
init(_func)
#define G_DEFINE_CONSTRUCTOR(_func) \
static void _func(void);
#define G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(_func) \
fini(_func)
#define G_DEFINE_DESTRUCTOR(_func) \
static void _func(void);
#else
/* constructors not supported for this compiler */
#endif
#endif /* __GTK_DOC_IGNORE__ */
-28
View File
@@ -1425,34 +1425,6 @@ gdk_device_ungrab (GdkDevice *device,
GDK_DEVICE_GET_CLASS (device)->ungrab (device, time_);
}
/**
* gdk_device_warp:
* @device: the device to warp.
* @x: the X coordinate of the destination.
* @y: the Y coordinate of the destination.
*
* Warps @device in @display to the point @x,@y,
* unless the device is confined to a surface by a grab,
* in which case it will be moved
* as far as allowed by the grab. Warping the pointer
* creates events as if the user had moved the mouse
* instantaneously to the destination.
*
* Note that the pointer should normally be under the
* control of the user. This function was added to cover
* some rare use cases like keyboard navigation support
* for the color picker in the #GtkColorSelectionDialog.
**/
void
gdk_device_warp (GdkDevice *device,
gint x,
gint y)
{
g_return_if_fail (GDK_IS_DEVICE (device));
GDK_DEVICE_GET_CLASS (device)->warp (device, x, y);
}
/* Private API */
void
_gdk_device_reset_axes (GdkDevice *device)
-5
View File
@@ -236,11 +236,6 @@ GDK_DEPRECATED_FOR(gdk_seat_ungrab)
void gdk_device_ungrab (GdkDevice *device,
guint32 time_);
GDK_AVAILABLE_IN_ALL
void gdk_device_warp (GdkDevice *device,
gint x,
gint y);
GDK_AVAILABLE_IN_ALL
GdkSurface *gdk_device_get_last_event_surface (GdkDevice *device);
-3
View File
@@ -86,9 +86,6 @@ struct _GdkDeviceClass
GdkSurface *surface,
GdkCursor *cursor);
void (* warp) (GdkDevice *device,
gdouble x,
gdouble y);
void (* query_state) (GdkDevice *device,
GdkSurface *surface,
GdkSurface **child_surface,
+53 -8
View File
@@ -564,8 +564,8 @@ gdk_event_copy (const GdkEvent *event)
g_object_ref (new_event->any.device);
if (new_event->any.source_device)
g_object_ref (new_event->any.source_device);
if (new_event->any.user_data)
g_object_ref (new_event->any.user_data);
if (new_event->any.target)
g_object_ref (new_event->any.target);
switch ((guint) event->any.type)
{
@@ -573,6 +573,13 @@ gdk_event_copy (const GdkEvent *event)
case GDK_LEAVE_NOTIFY:
if (event->crossing.child_surface != NULL)
g_object_ref (event->crossing.child_surface);
if (event->crossing.related_target)
g_object_ref (event->crossing.related_target);
break;
case GDK_FOCUS_CHANGE:
if (event->focus_change.related_target)
g_object_ref (event->focus_change.related_target);
break;
case GDK_DRAG_ENTER:
@@ -634,6 +641,11 @@ gdk_event_finalize (GObject *object)
case GDK_ENTER_NOTIFY:
case GDK_LEAVE_NOTIFY:
g_clear_object (&event->crossing.child_surface);
g_clear_object (&event->crossing.related_target);
break;
case GDK_FOCUS_CHANGE:
g_clear_object (&event->focus_change.related_target);
break;
case GDK_DRAG_ENTER:
@@ -675,7 +687,7 @@ gdk_event_finalize (GObject *object)
g_clear_object (&event->any.device);
g_clear_object (&event->any.source_device);
g_clear_object (&event->any.user_data);
g_clear_object (&event->any.target);
G_OBJECT_CLASS (gdk_event_parent_class)->finalize (object);
}
@@ -1904,16 +1916,39 @@ gdk_event_get_scancode (GdkEvent *event)
}
void
gdk_event_set_user_data (GdkEvent *event,
GObject *user_data)
gdk_event_set_target (GdkEvent *event,
GObject *target)
{
g_set_object (&event->any.user_data, user_data);
g_set_object (&event->any.target, target);
}
GObject *
gdk_event_get_user_data (const GdkEvent *event)
gdk_event_get_target (const GdkEvent *event)
{
return event->any.user_data;
return event->any.target;
}
void
gdk_event_set_related_target (GdkEvent *event,
GObject *target)
{
if (event->any.type == GDK_ENTER_NOTIFY ||
event->any.type == GDK_LEAVE_NOTIFY)
g_set_object (&event->crossing.related_target, target);
else if (event->any.type == GDK_FOCUS_CHANGE)
g_set_object (&event->focus_change.related_target, target);
}
GObject *
gdk_event_get_related_target (const GdkEvent *event)
{
if (event->any.type == GDK_ENTER_NOTIFY ||
event->any.type == GDK_LEAVE_NOTIFY)
return event->crossing.related_target;
else if (event->any.type == GDK_FOCUS_CHANGE)
return event->focus_change.related_target;
return NULL;
}
/**
@@ -1980,6 +2015,11 @@ gdk_event_get_crossing_mode (const GdkEvent *event,
*mode = event->crossing.mode;
return TRUE;
}
else if (event->any.type == GDK_FOCUS_CHANGE)
{
*mode = event->focus_change.mode;
return TRUE;
}
return FALSE;
}
@@ -2006,6 +2046,11 @@ gdk_event_get_crossing_detail (const GdkEvent *event,
*detail = event->crossing.detail;
return TRUE;
}
else if (event->any.type == GDK_FOCUS_CHANGE)
{
*detail = event->focus_change.detail;
return TRUE;
}
return FALSE;
}
+13 -3
View File
@@ -61,7 +61,7 @@ struct _GdkEventAny
GdkDevice *device;
GdkDevice *source_device;
GdkDisplay *display;
GObject *user_data;
GObject *target;
};
/*
@@ -303,6 +303,7 @@ struct _GdkEventCrossing
GdkNotifyType detail;
gboolean focus;
guint state;
GObject *related_target;
};
/*
@@ -312,6 +313,8 @@ struct _GdkEventCrossing
* @send_event: %TRUE if the event was sent explicitly.
* @in: %TRUE if the surface has gained the keyboard focus, %FALSE if
* it has lost the focus.
* @mode: the crossing mode
* @detail: the kind of crossing that happened
*
* Describes a change of keyboard focus.
*/
@@ -319,6 +322,9 @@ struct _GdkEventFocus
{
GdkEventAny any;
gint16 in;
GdkCrossingMode mode;
GdkNotifyType detail;
GObject *related_target;
};
/*
@@ -632,8 +638,12 @@ union _GdkEvent
GdkEventPadGroupMode pad_group_mode;
};
void gdk_event_set_user_data (GdkEvent *event,
GObject *user_data);
void gdk_event_set_target (GdkEvent *event,
GObject *user_data);
GObject * gdk_event_get_target (const GdkEvent *event);
void gdk_event_set_related_target (GdkEvent *event,
GObject *user_data);
GObject * gdk_event_get_related_target (const GdkEvent *event);
#endif /* __GDK_EVENTS_PRIVATE_H__ */
-8
View File
@@ -517,13 +517,6 @@ gdk_wayland_device_set_surface_cursor (GdkDevice *device,
gdk_wayland_device_update_surface_cursor (device);
}
static void
gdk_wayland_device_warp (GdkDevice *device,
gdouble x,
gdouble y)
{
}
static void
get_coordinates (GdkDevice *device,
double *x,
@@ -871,7 +864,6 @@ gdk_wayland_device_class_init (GdkWaylandDeviceClass *klass)
device_class->get_history = gdk_wayland_device_get_history;
device_class->get_state = gdk_wayland_device_get_state;
device_class->set_surface_cursor = gdk_wayland_device_set_surface_cursor;
device_class->warp = gdk_wayland_device_warp;
device_class->query_state = gdk_wayland_device_query_state;
device_class->grab = gdk_wayland_device_grab;
device_class->ungrab = gdk_wayland_device_ungrab;
-9
View File
@@ -112,14 +112,6 @@ gdk_device_virtual_set_surface_cursor (GdkDevice *device,
g_set_object (&GDK_SURFACE_IMPL_WIN32 (window->impl)->cursor, win32_hcursor);
}
static void
gdk_device_virtual_warp (GdkDevice *device,
gdouble x,
gdouble y)
{
SetCursorPos (x - _gdk_offset_x, y - _gdk_offset_y);
}
static void
gdk_device_virtual_query_state (GdkDevice *device,
GdkSurface *window,
@@ -198,7 +190,6 @@ gdk_device_virtual_class_init (GdkDeviceVirtualClass *klass)
device_class->get_history = gdk_device_virtual_get_history;
device_class->get_state = gdk_device_virtual_get_state;
device_class->set_surface_cursor = gdk_device_virtual_set_surface_cursor;
device_class->warp = gdk_device_virtual_warp;
device_class->query_state = gdk_device_virtual_query_state;
device_class->grab = gdk_device_virtual_grab;
device_class->ungrab = gdk_device_virtual_ungrab;
-8
View File
@@ -63,13 +63,6 @@ gdk_device_win32_set_surface_cursor (GdkDevice *device,
{
}
static void
gdk_device_win32_warp (GdkDevice *device,
gdouble x,
gdouble y)
{
}
static GdkModifierType
get_current_mask (void)
{
@@ -286,7 +279,6 @@ gdk_device_win32_class_init (GdkDeviceWin32Class *klass)
device_class->get_history = gdk_device_win32_get_history;
device_class->get_state = gdk_device_win32_get_state;
device_class->set_surface_cursor = gdk_device_win32_set_surface_cursor;
device_class->warp = gdk_device_win32_warp;
device_class->query_state = gdk_device_win32_query_state;
device_class->grab = gdk_device_win32_grab;
device_class->ungrab = gdk_device_win32_ungrab;
-8
View File
@@ -99,13 +99,6 @@ gdk_device_wintab_set_surface_cursor (GdkDevice *device,
{
}
static void
gdk_device_wintab_warp (GdkDevice *device,
gdouble x,
gdouble y)
{
}
static void
gdk_device_wintab_query_state (GdkDevice *device,
GdkSurface *window,
@@ -291,7 +284,6 @@ gdk_device_wintab_class_init (GdkDeviceWintabClass *klass)
device_class->get_history = gdk_device_wintab_get_history;
device_class->get_state = gdk_device_wintab_get_state;
device_class->set_surface_cursor = gdk_device_wintab_set_surface_cursor;
device_class->warp = gdk_device_wintab_warp;
device_class->query_state = gdk_device_wintab_query_state;
device_class->grab = gdk_device_wintab_grab;
device_class->ungrab = gdk_device_wintab_ungrab;
-3
View File
@@ -883,10 +883,7 @@ gdk_input_other_event (GdkDisplay *display,
GdkDeviceManagerWin32 *device_manager;
GdkDeviceWintab *source_device = NULL;
GdkDeviceGrabInfo *last_grab;
GdkEventMask masktest;
guint key_state;
POINT pt;
GdkSurfaceImplWin32 *impl;
PACKET packet;
gint root_x, root_y;
+4
View File
@@ -38,6 +38,8 @@
#include <dwmapi.h>
#include "gdkwin32langnotification.h"
static int debug_indent = 0;
/**
@@ -536,6 +538,7 @@ _gdk_win32_display_open (const gchar *display_name)
NULL);
_gdk_device_manager->display = _gdk_display;
_gdk_win32_lang_notification_init ();
_gdk_drag_init ();
_gdk_drop_init ();
@@ -701,6 +704,7 @@ gdk_win32_display_finalize (GObject *object)
_gdk_win32_display_finalize_cursors (display_win32);
_gdk_win32_dnd_exit ();
_gdk_win32_lang_notification_exit ();
g_ptr_array_free (display_win32->monitors, TRUE);
-2
View File
@@ -1840,7 +1840,6 @@ gdk_win32_drag_find_window (GdkDrag *drag,
{
GdkWin32Drag *drag_win32 = GDK_WIN32_DRAG (drag);
find_window_enum_arg a;
HWND result;
g_assert (_win32_main_thread == NULL ||
_win32_main_thread == g_thread_self ());
@@ -2439,7 +2438,6 @@ gdk_dnd_handle_key_event (GdkDrag *drag,
{
drag_win32->util_data.last_x += dx;
drag_win32->util_data.last_y += dy;
gdk_device_warp (pointer, drag_win32->util_data.last_x, drag_win32->util_data.last_y);
}
if (drag_win32->drag_surface)
-7
View File
@@ -1090,7 +1090,6 @@ static void
gdk_win32_drop_finish (GdkDrop *drop,
GdkDragAction action)
{
GdkDrag *drag;
GdkWin32Drop *drop_win32 = GDK_WIN32_DROP (drop);
g_return_if_fail (drop != NULL);
@@ -1103,12 +1102,6 @@ gdk_win32_drop_finish (GdkDrop *drop,
if (drop_win32->protocol == GDK_DRAG_PROTO_OLE2)
return;
/* FIXME: remove?
drag = gdk_drop_get_drag (drop);
if (drag != NULL)
_gdk_win32_local_drag_drop_response (drag, action);
*/
}
#if 0
+14 -2
View File
@@ -1331,7 +1331,6 @@ _gdk_win32_do_emit_configure_event (GdkSurface *window,
RECT rect)
{
GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
GdkEvent *event;
impl->unscaled_width = rect.right - rect.left;
impl->unscaled_height = rect.bottom - rect.top;
@@ -2113,7 +2112,6 @@ gdk_event_translate (MSG *msg,
case WM_INPUTLANGCHANGE:
_gdk_input_locale = (HKL) msg->lParam;
_gdk_win32_keymap_set_active_layout (GDK_WIN32_KEYMAP (_gdk_win32_display_get_keymap (_gdk_display)), _gdk_input_locale);
_gdk_input_locale_is_ime = ImmIsIME (_gdk_input_locale);
GetLocaleInfo (MAKELCID (LOWORD (_gdk_input_locale), SORT_DEFAULT),
LOCALE_IDEFAULTANSICODEPAGE,
buf, sizeof (buf));
@@ -2125,6 +2123,20 @@ gdk_event_translate (MSG *msg,
(gpointer) msg->lParam, _gdk_input_locale_is_ime ? " (IME)" : "",
_gdk_input_codepage));
gdk_display_setting_changed (display, "gtk-im-module");
/* Generate a dummy key event to "nudge" IMContext */
event = gdk_event_new (GDK_KEY_PRESS);
event->any.surface = window;
event->key.time = _gdk_win32_get_next_tick (msg->time);
event->key.keyval = GDK_KEY_VoidSymbol;
event->key.hardware_keycode = 0;
event->key.group = 0;
gdk_event_set_scancode (event, 0);
gdk_event_set_device (event, device_manager_win32->core_keyboard);
gdk_event_set_source_device (event, device_manager_win32->system_keyboard);
event->key.is_modifier = FALSE;
event->key.state = 0;
_gdk_win32_append_event (event);
break;
case WM_SYSKEYUP:
+1 -1
View File
@@ -39,7 +39,7 @@ HINSTANCE _gdk_app_hmodule;
gint _gdk_input_ignore_core;
HKL _gdk_input_locale;
gboolean _gdk_input_locale_is_ime;
gboolean _gdk_input_locale_is_ime = FALSE;
UINT _gdk_input_codepage;
gint _gdk_input_ignore_wintab = FALSE;
-1
View File
@@ -83,7 +83,6 @@ _gdk_win32_surfaceing_init (void)
_gdk_display_hdc = CreateDC ("DISPLAY", NULL, NULL, NULL);
_gdk_input_locale = GetKeyboardLayout (0);
_gdk_win32_keymap_set_active_layout (GDK_WIN32_KEYMAP (_gdk_win32_display_get_keymap (_gdk_display)), _gdk_input_locale);
_gdk_input_locale_is_ime = ImmIsIME (_gdk_input_locale);
GetLocaleInfo (MAKELCID (LOWORD (_gdk_input_locale), SORT_DEFAULT),
LOCALE_IDEFAULTANSICODEPAGE,
buf, sizeof (buf));
+2 -2
View File
@@ -215,9 +215,9 @@ _gdk_win32_get_setting (const gchar *name,
else if (strcmp ("gtk-im-module", name) == 0)
{
if (_gdk_input_locale_is_ime)
g_value_set_string (value, "ime");
g_value_set_static_string (value, "ime");
else
g_value_set_string (value, "");
g_value_set_static_string (value, "");
return TRUE;
}
+1 -14
View File
@@ -1953,19 +1953,6 @@ gdk_surface_win32_get_device_state (GdkSurface *window,
return (child != NULL);
}
void
gdk_display_warp_device (GdkDisplay *display,
GdkDevice *device,
gint x,
gint y)
{
g_return_if_fail (display == gdk_display_get_default ());
g_return_if_fail (GDK_IS_DEVICE (device));
g_return_if_fail (display == gdk_device_get_display (device));
GDK_DEVICE_GET_CLASS (device)->warp (device, x, y);
}
static void
gdk_win32_surface_set_accept_focus (GdkSurface *window,
gboolean accept_focus)
@@ -4125,7 +4112,7 @@ setup_drag_move_resize_context (GdkSurface *window,
* the titlebar is, if any.
*/
root_y = wy + wheight / 2;
gdk_device_warp (device, root_x, root_y);
SetCursorPos (root_x - _gdk_offset_x, root_y - _gdk_offset_y);
}
}
+172
View File
@@ -0,0 +1,172 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2019 Руслан Ижбулатов <lrn1986@gmail.com>
*
* 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"
#define COBJMACROS
#include <msctf.h>
#include <gdk/gdk.h>
#include "gdkprivate-win32.h"
struct _GdkWin32ALPNSink
{
ITfActiveLanguageProfileNotifySink itf_alpn_sink;
gint ref_count;
};
typedef struct _GdkWin32ALPNSink GdkWin32ALPNSink;
static GdkWin32ALPNSink *actlangchangenotify = NULL;
static ITfSource *itf_source = NULL;
static DWORD actlangchangenotify_id = 0;
static ULONG STDMETHODCALLTYPE
alpn_sink_addref (ITfActiveLanguageProfileNotifySink *This)
{
GdkWin32ALPNSink *alpn_sink = (GdkWin32ALPNSink *) This;
int ref_count = ++alpn_sink->ref_count;
return ref_count;
}
static HRESULT STDMETHODCALLTYPE
alpn_sink_queryinterface (ITfActiveLanguageProfileNotifySink *This,
REFIID riid,
LPVOID *ppvObject)
{
*ppvObject = NULL;
if (IsEqualGUID (riid, &IID_IUnknown))
{
ITfActiveLanguageProfileNotifySink_AddRef (This);
*ppvObject = This;
return S_OK;
}
if (IsEqualGUID (riid, &IID_ITfActiveLanguageProfileNotifySink))
{
ITfActiveLanguageProfileNotifySink_AddRef (This);
*ppvObject = This;
return S_OK;
}
return E_NOINTERFACE;
}
static ULONG STDMETHODCALLTYPE
alpn_sink_release (ITfActiveLanguageProfileNotifySink *This)
{
GdkWin32ALPNSink *alpn_sink = (GdkWin32ALPNSink *) This;
int ref_count = --alpn_sink->ref_count;
if (ref_count == 0)
{
g_free (This);
}
return ref_count;
}
static HRESULT STDMETHODCALLTYPE
alpn_sink_on_activated (ITfActiveLanguageProfileNotifySink *This,
REFCLSID clsid,
REFGUID guidProfile,
BOOL fActivated)
{
_gdk_input_locale_is_ime = fActivated;
return S_OK;
}
static ITfActiveLanguageProfileNotifySinkVtbl alpn_sink_vtbl = {
alpn_sink_queryinterface,
alpn_sink_addref,
alpn_sink_release,
alpn_sink_on_activated,
};
static GdkWin32ALPNSink *
alpn_sink_new ()
{
GdkWin32ALPNSink *result;
result = g_new0 (GdkWin32ALPNSink, 1);
result->itf_alpn_sink.lpVtbl = &alpn_sink_vtbl;
result->ref_count = 0;
ITfActiveLanguageProfileNotifySink_AddRef (&result->itf_alpn_sink);
return result;
}
void
_gdk_win32_lang_notification_init ()
{
HRESULT hr;
ITfThreadMgr *itf_threadmgr;
CoInitializeEx (NULL, COINIT_APARTMENTTHREADED);
if (actlangchangenotify != NULL)
return;
hr = CoCreateInstance (&CLSID_TF_ThreadMgr,
NULL,
CLSCTX_INPROC_SERVER,
&IID_ITfThreadMgr,
(LPVOID *) &itf_threadmgr);
if (!SUCCEEDED (hr))
return;
hr = ITfThreadMgr_QueryInterface (itf_threadmgr, &IID_ITfSource, (VOID **) &itf_source);
ITfThreadMgr_Release (itf_threadmgr);
if (!SUCCEEDED (hr))
return;
actlangchangenotify = alpn_sink_new ();
hr = ITfSource_AdviseSink (itf_source,
&IID_ITfActiveLanguageProfileNotifySink,
(IUnknown *) actlangchangenotify,
&actlangchangenotify_id);
if (!SUCCEEDED (hr))
{
ITfActiveLanguageProfileNotifySink_Release (&actlangchangenotify->itf_alpn_sink);
actlangchangenotify = NULL;
ITfSource_Release (itf_source);
itf_source = NULL;
}
}
void
_gdk_win32_lang_notification_exit ()
{
if (actlangchangenotify != NULL && itf_source != NULL)
{
ITfSource_UnadviseSink (itf_source, actlangchangenotify_id);
ITfSource_Release (itf_source);
ITfActiveLanguageProfileNotifySink_Release (&actlangchangenotify->itf_alpn_sink);
}
CoUninitialize ();
}
+26
View File
@@ -0,0 +1,26 @@
/*
* gdkwin32langnotification.h
*
* Copyright 2019 Руслан Ижбулатов <lrn1986@gmail.com>
*
* 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_WIN32_LANGNOTIFICATION_H__
#define __GDK_WIN32_LANGNOTIFICATION_H__
void _gdk_win32_lang_notification_init (void);
void _gdk_win32_lang_notification_exit (void);
#endif
+1
View File
@@ -17,6 +17,7 @@ gdk_win32_sources = files([
'gdkglobals-win32.c',
'gdkhdataoutputstream-win32.c',
'gdkkeys-win32.c',
'gdkwin32langnotification.c',
'gdkmain-win32.c',
'gdkmonitor-win32.c',
'gdkproperty-win32.c',
-24
View File
@@ -52,9 +52,6 @@ static void gdk_x11_device_core_get_state (GdkDevice *device,
static void gdk_x11_device_core_set_surface_cursor (GdkDevice *device,
GdkSurface *surface,
GdkCursor *cursor);
static void gdk_x11_device_core_warp (GdkDevice *device,
gdouble x,
gdouble y);
static void gdk_x11_device_core_query_state (GdkDevice *device,
GdkSurface *surface,
GdkSurface **child_surface,
@@ -88,7 +85,6 @@ gdk_x11_device_core_class_init (GdkX11DeviceCoreClass *klass)
device_class->get_history = gdk_x11_device_core_get_history;
device_class->get_state = gdk_x11_device_core_get_state;
device_class->set_surface_cursor = gdk_x11_device_core_set_surface_cursor;
device_class->warp = gdk_x11_device_core_warp;
device_class->query_state = gdk_x11_device_core_query_state;
device_class->grab = gdk_x11_device_core_grab;
device_class->ungrab = gdk_x11_device_core_ungrab;
@@ -223,26 +219,6 @@ gdk_x11_device_core_set_surface_cursor (GdkDevice *device,
xcursor);
}
static void
gdk_x11_device_core_warp (GdkDevice *device,
gdouble x,
gdouble y)
{
GdkDisplay *display;
Display *xdisplay;
Window dest;
GdkX11Screen *screen;
display = gdk_device_get_display (device);
xdisplay = GDK_DISPLAY_XDISPLAY (display);
screen = GDK_X11_DISPLAY (display)->screen;
dest = GDK_SCREEN_XROOTWIN (screen);
XWarpPointer (xdisplay, None, dest, 0, 0, 0, 0,
round (x * screen->surface_scale),
round (y * screen->surface_scale));
}
static void
gdk_x11_device_core_query_state (GdkDevice *device,
GdkSurface *surface,
-22
View File
@@ -77,9 +77,6 @@ static void gdk_x11_device_xi2_get_state (GdkDevice *device,
static void gdk_x11_device_xi2_set_surface_cursor (GdkDevice *device,
GdkSurface *surface,
GdkCursor *cursor);
static void gdk_x11_device_xi2_warp (GdkDevice *device,
gdouble x,
gdouble y);
static void gdk_x11_device_xi2_query_state (GdkDevice *device,
GdkSurface *surface,
GdkSurface **child_surface,
@@ -123,7 +120,6 @@ gdk_x11_device_xi2_class_init (GdkX11DeviceXI2Class *klass)
device_class->get_state = gdk_x11_device_xi2_get_state;
device_class->set_surface_cursor = gdk_x11_device_xi2_set_surface_cursor;
device_class->warp = gdk_x11_device_xi2_warp;
device_class->query_state = gdk_x11_device_xi2_query_state;
device_class->grab = gdk_x11_device_xi2_grab;
device_class->ungrab = gdk_x11_device_xi2_ungrab;
@@ -292,24 +288,6 @@ gdk_x11_device_xi2_set_surface_cursor (GdkDevice *device,
GDK_SURFACE_XID (surface));
}
static void
gdk_x11_device_xi2_warp (GdkDevice *device,
gdouble x,
gdouble y)
{
GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
GdkDisplay *display = gdk_device_get_display (device);
GdkX11Screen *screen = GDK_X11_DISPLAY (display)->screen;
Window dest = GDK_DISPLAY_XROOTWIN (display);
XIWarpPointer (GDK_SCREEN_XDISPLAY (screen),
device_xi2->device_id,
None, dest,
0, 0, 0, 0,
round (x * screen->surface_scale),
round (y * screen->surface_scale));
}
static void
gdk_x11_device_xi2_query_state (GdkDevice *device,
GdkSurface *surface,
+15 -1
View File
@@ -41,6 +41,7 @@
#include "gdkselectioninputstream-x11.h"
#include "gdkselectionoutputstream-x11.h"
#include <math.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
@@ -2342,9 +2343,22 @@ gdk_dnd_handle_key_event (GdkDrag *drag,
if (dx != 0 || dy != 0)
{
GdkDisplay *display;
Display *xdisplay;
GdkX11Screen *screen;
Window dest;
x11_drag->last_x += dx;
x11_drag->last_y += dy;
gdk_device_warp (pointer, x11_drag->last_x, x11_drag->last_y);
display = gdk_event_get_display ((GdkEvent *)event);
xdisplay = GDK_DISPLAY_XDISPLAY (display);
screen = GDK_X11_DISPLAY (display)->screen;
dest = GDK_SCREEN_XROOTWIN (screen);
XWarpPointer (xdisplay, None, dest, 0, 0, 0, 0,
round (x11_drag->last_x * screen->surface_scale),
round (x11_drag->last_y * screen->surface_scale));
}
gdk_drag_update (drag, x11_drag->last_x, x11_drag->last_y, state,
+6
View File
@@ -305,6 +305,12 @@ gdk_event_source_translate_event (GdkX11Display *x11_display,
}
}
if (event &&
event->any.type == GDK_NOTHING)
{
g_clear_object (&event);
}
if (event &&
(event->any.type == GDK_ENTER_NOTIFY ||
event->any.type == GDK_LEAVE_NOTIFY) &&
+19
View File
@@ -547,6 +547,25 @@ gsk_gl_driver_get_texture_for_pointer (GskGLDriver *self,
id = GPOINTER_TO_INT (g_hash_table_lookup (self->pointer_textures, pointer));
if (id != 0)
{
GHashTableIter iter;
gpointer value_p;
/* Find the texture in self->textures and mark it used */
g_hash_table_iter_init (&iter, self->textures);
while (g_hash_table_iter_next (&iter, NULL, &value_p))
{
Texture *t = value_p;
if (t->texture_id == id)
{
t->in_use = TRUE;
break;
}
}
}
return id;
}
+13
View File
@@ -433,12 +433,23 @@ render_fallback_node (GskGLRenderer *self,
const int surface_height = ceilf (node->bounds.size.height) * scale;
cairo_surface_t *surface;
cairo_t *cr;
int cached_id;
int texture_id;
if (surface_width <= 0 ||
surface_height <= 0)
return;
cached_id = gsk_gl_driver_get_texture_for_pointer (self->gl_driver, node);
if (cached_id != 0)
{
ops_set_program (builder, &self->blit_program);
ops_set_texture (builder, cached_id);
ops_draw (builder, vertex_data);
return;
}
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
surface_width,
surface_height);
@@ -474,6 +485,8 @@ render_fallback_node (GskGLRenderer *self,
cairo_surface_destroy (surface);
gsk_gl_driver_set_texture_for_pointer (self->gl_driver, node, texture_id);
ops_set_program (builder, &self->blit_program);
ops_set_texture (builder, texture_id);
ops_draw (builder, vertex_data);
+377 -447
View File
@@ -4,6 +4,7 @@
#include "broadway/gdkprivate-broadway.h"
#include "gskdebugprivate.h"
#include "gsktransformprivate.h"
#include "gskrendererprivate.h"
#include "gskrendernodeprivate.h"
#include "gdk/gdktextureprivate.h"
@@ -12,6 +13,16 @@ struct _GskBroadwayRenderer
{
GskRenderer parent_instance;
GdkBroadwayDrawContext *draw_context;
guint32 next_node_id;
/* Set during rendering */
GArray *nodes; /* Owned by draw_contex */
GPtrArray *node_textures; /* Owned by draw_contex */
GHashTable *node_lookup;
/* Kept from last frame */
GHashTable *last_node_lookup;
GskRenderNode *last_root; /* Owning refs to the things in last_node_lookup */
};
struct _GskBroadwayRendererClass
@@ -71,12 +82,25 @@ gsk_broadway_renderer_render_texture (GskRenderer *renderer,
return texture;
}
/* uint32 is sent in native endianness, and then converted to little endian in broadwayd when sending to browser */
static void
add_uint32 (GArray *nodes, guint32 v)
{
g_array_append_val (nodes, v);
}
static void
add_float (GArray *nodes, float f)
{
union {
float f;
guint32 i;
} u;
u.f = f;
g_array_append_val (nodes, u.i);
}
static guint32
rgba_to_uint32 (const GdkRGBA *rgba)
{
@@ -96,18 +120,16 @@ add_rgba (GArray *nodes, const GdkRGBA *rgba)
}
static void
add_float (GArray *nodes, float f)
add_xy (GArray *nodes, float x, float y, float offset_x, float offset_y)
{
gint32 i = (gint32) (f * 256.0f);
guint u = (guint32) i;
g_array_append_val (nodes, u);
add_float (nodes, x - offset_x);
add_float (nodes, y - offset_y);
}
static void
add_point (GArray *nodes, const graphene_point_t *point, float offset_x, float offset_y)
{
add_float (nodes, point->x - offset_x);
add_float (nodes, point->y - offset_y);
add_xy (nodes, point->x, point->y, offset_x, offset_y);
}
static void
@@ -140,313 +162,157 @@ add_color_stop (GArray *nodes, const GskColorStop *stop)
add_rgba (nodes, &stop->color);
}
static gboolean
float_is_int32 (float f)
{
gint32 i = (gint32)f;
float f2 = (float)i;
return f2 == f;
}
static GHashTable *gsk_broadway_node_cache;
typedef struct {
GdkTexture *texture;
GskRenderNode *node;
float off_x;
float off_y;
} NodeCacheElement;
static void
node_cache_element_free (NodeCacheElement *element)
add_string (GArray *nodes, const char *str)
{
gsk_render_node_unref (element->node);
g_free (element);
}
guint32 len = strlen(str);
guint32 v, c;
static guint
glyph_info_hash (const PangoGlyphInfo *info)
{
return info->glyph ^
info->geometry.width << 6 ^
info->geometry.x_offset << 12 ^
info->geometry.y_offset << 18 ^
info->attr.is_cluster_start << 30;
}
add_uint32 (nodes, len);
static gboolean
glyph_info_equal (const PangoGlyphInfo *a,
const PangoGlyphInfo *b)
{
return
a->glyph == b->glyph &&
a->geometry.width == b->geometry.width &&
a->geometry.x_offset == b->geometry.x_offset &&
a->geometry.y_offset == b->geometry.y_offset &&
a->attr.is_cluster_start == b->attr.is_cluster_start;
}
static guint
hash_matrix (const graphene_matrix_t *matrix)
{
float m[16];
guint h = 0;
int i;
graphene_matrix_to_float (matrix, m);
for (i = 0; i < 16; i++)
h ^= (guint) m[i];
return h;
}
static gboolean
matrix_equal (const graphene_matrix_t *a,
const graphene_matrix_t *b)
{
float ma[16];
float mb[16];
int i;
graphene_matrix_to_float (a, ma);
graphene_matrix_to_float (b, mb);
for (i = 0; i < 16; i++)
v = 0;
c = 0;
while (*str != 0)
{
if (ma[i] != mb[i])
return FALSE;
}
return TRUE;
}
static guint
hash_vec4 (const graphene_vec4_t *vec4)
{
float v[4];
guint h = 0;
int i;
graphene_vec4_to_float (vec4, v);
for (i = 0; i < 4; i++)
h ^= (guint) v[i];
return h;
}
static gboolean
vec4_equal (const graphene_vec4_t *a,
const graphene_vec4_t *b)
{
float va[4];
float vb[4];
int i;
graphene_vec4_to_float (a, va);
graphene_vec4_to_float (b, vb);
for (i = 0; i < 4; i++)
{
if (va[i] != vb[i])
return FALSE;
}
return TRUE;
}
static guint
node_cache_hash (GskRenderNode *node)
{
GskRenderNodeType type;
guint h;
type = gsk_render_node_get_node_type (node);
h = type << 28;
if (type == GSK_TEXT_NODE &&
float_is_int32 (gsk_text_node_get_x (node)) &&
float_is_int32 (gsk_text_node_get_y (node)))
{
guint i;
const PangoFont *font = gsk_text_node_peek_font (node);
guint n_glyphs = gsk_text_node_get_num_glyphs (node);
const PangoGlyphInfo *infos = gsk_text_node_peek_glyphs (node);
const GdkRGBA *color = gsk_text_node_peek_color (node);
h ^= g_direct_hash (font) ^ n_glyphs << 16 ^ gdk_rgba_hash (color);
for (i = 0; i < n_glyphs; i++)
h ^= glyph_info_hash (&infos[i]);
return h;
}
if (type == GSK_COLOR_MATRIX_NODE &&
gsk_render_node_get_node_type (gsk_color_matrix_node_get_child (node)) == GSK_TEXTURE_NODE)
{
const graphene_matrix_t *matrix = gsk_color_matrix_node_peek_color_matrix (node);
const graphene_vec4_t *offset = gsk_color_matrix_node_peek_color_offset (node);
GskRenderNode *child = gsk_color_matrix_node_get_child (node);
GdkTexture *texture = gsk_texture_node_get_texture (child);
h ^= g_direct_hash (texture) ^ hash_matrix (matrix) ^ hash_vec4 (offset);
return h;
}
return 0;
}
static gboolean
node_cache_equal (GskRenderNode *a,
GskRenderNode *b)
{
GskRenderNodeType type;
type = gsk_render_node_get_node_type (a);
if (type != gsk_render_node_get_node_type (b))
return FALSE;
if (type == GSK_TEXT_NODE &&
float_is_int32 (gsk_text_node_get_x (a)) &&
float_is_int32 (gsk_text_node_get_y (a)) &&
float_is_int32 (gsk_text_node_get_x (b)) &&
float_is_int32 (gsk_text_node_get_y (b)))
{
const PangoFont *a_font = gsk_text_node_peek_font (a);
guint a_n_glyphs = gsk_text_node_get_num_glyphs (a);
const PangoGlyphInfo *a_infos = gsk_text_node_peek_glyphs (a);
const GdkRGBA *a_color = gsk_text_node_peek_color (a);
const PangoFont *b_font = gsk_text_node_peek_font (b);
guint b_n_glyphs = gsk_text_node_get_num_glyphs (b);
const PangoGlyphInfo *b_infos = gsk_text_node_peek_glyphs (b);
const GdkRGBA *b_color = gsk_text_node_peek_color (a);
guint i;
if (a_font != b_font)
return FALSE;
if (a_n_glyphs != b_n_glyphs)
return FALSE;
for (i = 0; i < a_n_glyphs; i++)
v |= (*str++) << 8*c++;
if (c == 4)
{
if (!glyph_info_equal (&a_infos[i], &b_infos[i]))
return FALSE;
add_uint32 (nodes, v);
v = 0;
c = 0;
}
if (!gdk_rgba_equal (a_color, b_color))
return FALSE;
return TRUE;
}
if (type == GSK_COLOR_MATRIX_NODE &&
gsk_render_node_get_node_type (gsk_color_matrix_node_get_child (a)) == GSK_TEXTURE_NODE &&
gsk_render_node_get_node_type (gsk_color_matrix_node_get_child (b)) == GSK_TEXTURE_NODE)
{
const graphene_matrix_t *a_matrix = gsk_color_matrix_node_peek_color_matrix (a);
const graphene_vec4_t *a_offset = gsk_color_matrix_node_peek_color_offset (a);
GskRenderNode *a_child = gsk_color_matrix_node_get_child (a);
GdkTexture *a_texture = gsk_texture_node_get_texture (a_child);
const graphene_matrix_t *b_matrix = gsk_color_matrix_node_peek_color_matrix (b);
const graphene_vec4_t *b_offset = gsk_color_matrix_node_peek_color_offset (b);
GskRenderNode *b_child = gsk_color_matrix_node_get_child (b);
GdkTexture *b_texture = gsk_texture_node_get_texture (b_child);
if (a_texture != b_texture)
return FALSE;
if (!matrix_equal (a_matrix, b_matrix))
return FALSE;
if (!vec4_equal (a_offset, b_offset))
return FALSE;
return TRUE;
}
return FALSE;
}
static GdkTexture *
node_cache_lookup (GskRenderNode *node,
float *off_x, float *off_y)
{
NodeCacheElement *hit;
if (gsk_broadway_node_cache == NULL)
gsk_broadway_node_cache = g_hash_table_new_full ((GHashFunc)node_cache_hash,
(GEqualFunc)node_cache_equal,
NULL,
(GDestroyNotify)node_cache_element_free);
hit = g_hash_table_lookup (gsk_broadway_node_cache, node);
if (hit)
{
*off_x = hit->off_x;
*off_y = hit->off_y;
return g_object_ref (hit->texture);
}
return NULL;
if (c != 0)
add_uint32 (nodes, v);
}
static void
cached_texture_gone (gpointer data,
GObject *where_the_object_was)
{
NodeCacheElement *element = data;
g_hash_table_remove (gsk_broadway_node_cache, element->node);
}
collect_reused_child_nodes (GskRenderer *renderer,
GskRenderNode *node);
static void
node_cache_store (GskRenderNode *node,
GdkTexture *texture,
float off_x,
float off_y)
collect_reused_node (GskRenderer *renderer,
GskRenderNode *node)
{
GskRenderNodeType type;
GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer);
guint32 old_id;
type = gsk_render_node_get_node_type (node);
if ((type == GSK_TEXT_NODE &&
float_is_int32 (gsk_text_node_get_x (node)) &&
float_is_int32 (gsk_text_node_get_y (node))) ||
(type == GSK_COLOR_MATRIX_NODE &&
gsk_render_node_get_node_type (gsk_color_matrix_node_get_child (node)) == GSK_TEXTURE_NODE))
if (self->last_node_lookup &&
(old_id = GPOINTER_TO_INT(g_hash_table_lookup (self->last_node_lookup, node))) != 0)
{
NodeCacheElement *element = g_new0 (NodeCacheElement, 1);
element->texture = texture;
element->node = gsk_render_node_ref (node);
element->off_x = off_x;
element->off_y = off_y;
g_object_weak_ref (G_OBJECT (texture), cached_texture_gone, element);
g_hash_table_insert (gsk_broadway_node_cache, element->node, element);
g_hash_table_insert (self->node_lookup, node, GINT_TO_POINTER (old_id));
collect_reused_child_nodes (renderer, node);
}
}
static void
collect_reused_child_nodes (GskRenderer *renderer,
GskRenderNode *node)
{
guint i;
switch (gsk_render_node_get_node_type (node))
{
case GSK_NOT_A_RENDER_NODE:
g_assert_not_reached ();
return;
/* Leaf nodes */
case GSK_TEXTURE_NODE:
case GSK_CAIRO_NODE:
case GSK_COLOR_NODE:
case GSK_BORDER_NODE:
case GSK_OUTSET_SHADOW_NODE:
case GSK_INSET_SHADOW_NODE:
case GSK_LINEAR_GRADIENT_NODE:
/* Fallbacks (=> leaf for now */
case GSK_COLOR_MATRIX_NODE:
case GSK_TEXT_NODE:
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_REPEAT_NODE:
case GSK_BLEND_NODE:
case GSK_CROSS_FADE_NODE:
case GSK_BLUR_NODE:
default:
break;
/* Bin nodes */
case GSK_SHADOW_NODE:
collect_reused_node (renderer,
gsk_shadow_node_get_child (node));
break;
case GSK_OPACITY_NODE:
collect_reused_node (renderer,
gsk_opacity_node_get_child (node));
break;
case GSK_ROUNDED_CLIP_NODE:
collect_reused_node (renderer,
gsk_rounded_clip_node_get_child (node));
break;
case GSK_CLIP_NODE:
collect_reused_node (renderer,
gsk_clip_node_get_child (node));
break;
case GSK_TRANSFORM_NODE:
collect_reused_node (renderer,
gsk_transform_node_get_child (node));
break;
case GSK_DEBUG_NODE:
collect_reused_node (renderer,
gsk_debug_node_get_child (node));
break;
/* Generic nodes */
case GSK_CONTAINER_NODE:
for (i = 0; i < gsk_container_node_get_n_children (node); i++)
collect_reused_node (renderer,
gsk_container_node_get_child (node, i));
break;
break; /* Fallback */
}
}
static GdkTexture *
node_texture_fallback (GskRenderNode *node,
float *off_x,
float *off_y)
static gboolean
add_new_node (GskRenderer *renderer,
GskRenderNode *node,
BroadwayNodeType type)
{
cairo_surface_t *surface;
cairo_t *cr;
int x = floorf (node->bounds.origin.x);
int y = floorf (node->bounds.origin.y);
int width = ceil (node->bounds.origin.x + node->bounds.size.width) - x;
int height = ceil (node->bounds.origin.y + node->bounds.size.height) - y;
GdkTexture *texture;
GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer);
guint32 id, old_id;
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
cr = cairo_create (surface);
cairo_translate (cr, -x, -y);
gsk_render_node_draw (node, cr);
cairo_destroy (cr);
if (self->last_node_lookup &&
(old_id = GPOINTER_TO_INT (g_hash_table_lookup (self->last_node_lookup, node))) != 0)
{
add_uint32 (self->nodes, BROADWAY_NODE_REUSE);
add_uint32 (self->nodes, old_id);
texture = gdk_texture_new_for_surface (surface);
*off_x = x - node->bounds.origin.x;
*off_y = y - node->bounds.origin.y;
g_hash_table_insert (self->node_lookup, node, GINT_TO_POINTER(old_id));
collect_reused_child_nodes (renderer, node);
return texture;
return FALSE;
}
id = ++self->next_node_id;
g_hash_table_insert (self->node_lookup, node, GINT_TO_POINTER(id));
add_uint32 (self->nodes, type);
add_uint32 (self->nodes, id);
return TRUE;
}
/* Note: This tracks the offset so that we can convert
@@ -455,13 +321,13 @@ node_texture_fallback (GskRenderNode *node,
which is good for re-using subtrees. */
static void
gsk_broadway_renderer_add_node (GskRenderer *renderer,
GArray *nodes,
GPtrArray *node_textures,
GskRenderNode *node,
float offset_x,
float offset_y)
{
GdkDisplay *display = gsk_renderer_get_display (renderer);
GdkDisplay *display = gdk_surface_get_display (gsk_renderer_get_surface (renderer));
GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer);
GArray *nodes = self->nodes;
switch (gsk_render_node_get_node_type (node))
{
@@ -472,191 +338,223 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
/* Leaf nodes */
case GSK_TEXTURE_NODE:
{
GdkTexture *texture = gsk_texture_node_get_texture (node);
guint32 texture_id;
if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE))
{
GdkTexture *texture = gsk_texture_node_get_texture (node);
guint32 texture_id;
g_ptr_array_add (node_textures, g_object_ref (texture)); /* Transfers ownership to node_textures */
texture_id = gdk_broadway_display_ensure_texture (display, texture);
/* No need to add to self->node_textures here, the node will keep it alive until end of frame. */
add_uint32 (nodes, BROADWAY_NODE_TEXTURE);
add_rect (nodes, &node->bounds, offset_x, offset_y);
add_uint32 (nodes, texture_id);
}
texture_id = gdk_broadway_display_ensure_texture (display, texture);
add_rect (nodes, &node->bounds, offset_x, offset_y);
add_uint32 (nodes, texture_id);
}
return;
case GSK_CAIRO_NODE:
{
cairo_surface_t *surface = (cairo_surface_t *)gsk_cairo_node_peek_surface (node);
cairo_surface_t *image_surface = NULL;
GdkTexture *texture;
guint32 texture_id;
if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE))
{
cairo_surface_t *surface = (cairo_surface_t *)gsk_cairo_node_peek_surface (node);
cairo_surface_t *image_surface = NULL;
GdkTexture *texture;
guint32 texture_id;
if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE)
image_surface = cairo_surface_reference (surface);
else
{
cairo_t *cr;
image_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
ceilf (node->bounds.size.width),
ceilf (node->bounds.size.height));
cr = cairo_create (image_surface);
cairo_set_source_surface (cr, surface, 0, 0);
cairo_rectangle (cr, 0, 0, node->bounds.size.width, node->bounds.size.height);
cairo_fill (cr);
cairo_destroy (cr);
}
if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE)
image_surface = cairo_surface_reference (surface);
else
{
cairo_t *cr;
image_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
ceilf (node->bounds.size.width),
ceilf (node->bounds.size.height));
cr = cairo_create (image_surface);
cairo_set_source_surface (cr, surface, 0, 0);
cairo_rectangle (cr, 0, 0, node->bounds.size.width, node->bounds.size.height);
cairo_fill (cr);
cairo_destroy (cr);
}
texture = gdk_texture_new_for_surface (image_surface);
g_ptr_array_add (node_textures, g_object_ref (texture)); /* Transfers ownership to node_textures */
texture_id = gdk_broadway_display_ensure_texture (display, texture);
texture = gdk_texture_new_for_surface (image_surface);
g_ptr_array_add (self->node_textures, g_object_ref (texture)); /* Transfers ownership to node_textures */
texture_id = gdk_broadway_display_ensure_texture (display, texture);
add_uint32 (nodes, BROADWAY_NODE_TEXTURE);
add_rect (nodes, &node->bounds, offset_x, offset_y);
add_uint32 (nodes, texture_id);
add_rect (nodes, &node->bounds, offset_x, offset_y);
add_uint32 (nodes, texture_id);
cairo_surface_destroy (image_surface);
}
cairo_surface_destroy (image_surface);
}
return;
case GSK_COLOR_NODE:
{
add_uint32 (nodes, BROADWAY_NODE_COLOR);
add_rect (nodes, &node->bounds, offset_x, offset_y);
add_rgba (nodes, gsk_color_node_peek_color (node));
}
if (add_new_node (renderer, node, BROADWAY_NODE_COLOR))
{
add_rect (nodes, &node->bounds, offset_x, offset_y);
add_rgba (nodes, gsk_color_node_peek_color (node));
}
return;
case GSK_BORDER_NODE:
{
int i;
add_uint32 (nodes, BROADWAY_NODE_BORDER);
add_rounded_rect (nodes, gsk_border_node_peek_outline (node), offset_x, offset_y);
for (i = 0; i < 4; i++)
add_float (nodes, gsk_border_node_peek_widths (node)[i]);
for (i = 0; i < 4; i++)
add_rgba (nodes, &gsk_border_node_peek_colors (node)[i]);
}
if (add_new_node (renderer, node, BROADWAY_NODE_BORDER))
{
int i;
add_rounded_rect (nodes, gsk_border_node_peek_outline (node), offset_x, offset_y);
for (i = 0; i < 4; i++)
add_float (nodes, gsk_border_node_peek_widths (node)[i]);
for (i = 0; i < 4; i++)
add_rgba (nodes, &gsk_border_node_peek_colors (node)[i]);
}
return;
case GSK_OUTSET_SHADOW_NODE:
{
add_uint32 (nodes, BROADWAY_NODE_OUTSET_SHADOW);
add_rounded_rect (nodes, gsk_outset_shadow_node_peek_outline (node), offset_x, offset_y);
add_rgba (nodes, gsk_outset_shadow_node_peek_color (node));
add_float (nodes, gsk_outset_shadow_node_get_dx (node));
add_float (nodes, gsk_outset_shadow_node_get_dy (node));
add_float (nodes, gsk_outset_shadow_node_get_spread (node));
add_float (nodes, gsk_outset_shadow_node_get_blur_radius (node));
}
if (add_new_node (renderer, node, BROADWAY_NODE_OUTSET_SHADOW))
{
add_rounded_rect (nodes, gsk_outset_shadow_node_peek_outline (node), offset_x, offset_y);
add_rgba (nodes, gsk_outset_shadow_node_peek_color (node));
add_float (nodes, gsk_outset_shadow_node_get_dx (node));
add_float (nodes, gsk_outset_shadow_node_get_dy (node));
add_float (nodes, gsk_outset_shadow_node_get_spread (node));
add_float (nodes, gsk_outset_shadow_node_get_blur_radius (node));
}
return;
case GSK_INSET_SHADOW_NODE:
{
add_uint32 (nodes, BROADWAY_NODE_INSET_SHADOW);
add_rounded_rect (nodes, gsk_inset_shadow_node_peek_outline (node), offset_x, offset_y);
add_rgba (nodes, gsk_inset_shadow_node_peek_color (node));
add_float (nodes, gsk_inset_shadow_node_get_dx (node));
add_float (nodes, gsk_inset_shadow_node_get_dy (node));
add_float (nodes, gsk_inset_shadow_node_get_spread (node));
add_float (nodes, gsk_inset_shadow_node_get_blur_radius (node));
}
if (add_new_node (renderer, node, BROADWAY_NODE_INSET_SHADOW))
{
add_rounded_rect (nodes, gsk_inset_shadow_node_peek_outline (node), offset_x, offset_y);
add_rgba (nodes, gsk_inset_shadow_node_peek_color (node));
add_float (nodes, gsk_inset_shadow_node_get_dx (node));
add_float (nodes, gsk_inset_shadow_node_get_dy (node));
add_float (nodes, gsk_inset_shadow_node_get_spread (node));
add_float (nodes, gsk_inset_shadow_node_get_blur_radius (node));
}
return;
case GSK_LINEAR_GRADIENT_NODE:
{
guint i, n;
if (add_new_node (renderer, node, BROADWAY_NODE_LINEAR_GRADIENT))
{
guint i, n;
add_uint32 (nodes, BROADWAY_NODE_LINEAR_GRADIENT);
add_rect (nodes, &node->bounds, offset_x, offset_y);
add_point (nodes, gsk_linear_gradient_node_peek_start (node), offset_x, offset_y);
add_point (nodes, gsk_linear_gradient_node_peek_end (node), offset_x, offset_y);
n = gsk_linear_gradient_node_get_n_color_stops (node);
add_uint32 (nodes, n);
for (i = 0; i < n; i++)
add_color_stop (nodes, &gsk_linear_gradient_node_peek_color_stops (node)[i]);
}
add_rect (nodes, &node->bounds, offset_x, offset_y);
add_point (nodes, gsk_linear_gradient_node_peek_start (node), offset_x, offset_y);
add_point (nodes, gsk_linear_gradient_node_peek_end (node), offset_x, offset_y);
n = gsk_linear_gradient_node_get_n_color_stops (node);
add_uint32 (nodes, n);
for (i = 0; i < n; i++)
add_color_stop (nodes, &gsk_linear_gradient_node_peek_color_stops (node)[i]);
}
return;
/* Bin nodes */
case GSK_SHADOW_NODE:
{
gsize i, n_shadows = gsk_shadow_node_get_n_shadows (node);
add_uint32 (nodes, BROADWAY_NODE_SHADOW);
add_uint32 (nodes, n_shadows);
for (i = 0; i < n_shadows; i++)
{
const GskShadow *shadow = gsk_shadow_node_peek_shadow (node, i);
add_rgba (nodes, &shadow->color);
add_float (nodes, shadow->dx);
add_float (nodes, shadow->dy);
add_float (nodes, shadow->radius);
}
gsk_broadway_renderer_add_node (renderer, nodes, node_textures,
gsk_shadow_node_get_child (node),
offset_x, offset_y);
}
if (add_new_node (renderer, node, BROADWAY_NODE_SHADOW))
{
gsize i, n_shadows = gsk_shadow_node_get_n_shadows (node);
add_uint32 (nodes, n_shadows);
for (i = 0; i < n_shadows; i++)
{
const GskShadow *shadow = gsk_shadow_node_peek_shadow (node, i);
add_rgba (nodes, &shadow->color);
add_float (nodes, shadow->dx);
add_float (nodes, shadow->dy);
add_float (nodes, shadow->radius);
}
gsk_broadway_renderer_add_node (renderer,
gsk_shadow_node_get_child (node),
offset_x, offset_y);
}
return;
case GSK_OPACITY_NODE:
{
add_uint32 (nodes, BROADWAY_NODE_OPACITY);
add_float (nodes, gsk_opacity_node_get_opacity (node));
gsk_broadway_renderer_add_node (renderer, nodes, node_textures,
gsk_opacity_node_get_child (node),
offset_x, offset_y);
}
if (add_new_node (renderer, node, BROADWAY_NODE_OPACITY))
{
add_float (nodes, gsk_opacity_node_get_opacity (node));
gsk_broadway_renderer_add_node (renderer,
gsk_opacity_node_get_child (node),
offset_x, offset_y);
}
return;
case GSK_ROUNDED_CLIP_NODE:
{
const GskRoundedRect *rclip = gsk_rounded_clip_node_peek_clip (node);
add_uint32 (nodes, BROADWAY_NODE_ROUNDED_CLIP);
add_rounded_rect (nodes, rclip, offset_x, offset_y);
gsk_broadway_renderer_add_node (renderer, nodes, node_textures,
gsk_rounded_clip_node_get_child (node),
rclip->bounds.origin.x,
rclip->bounds.origin.y);
}
if (add_new_node (renderer, node, BROADWAY_NODE_ROUNDED_CLIP))
{
const GskRoundedRect *rclip = gsk_rounded_clip_node_peek_clip (node);
add_rounded_rect (nodes, rclip, offset_x, offset_y);
gsk_broadway_renderer_add_node (renderer,
gsk_rounded_clip_node_get_child (node),
rclip->bounds.origin.x,
rclip->bounds.origin.y);
}
return;
case GSK_CLIP_NODE:
if (add_new_node (renderer, node, BROADWAY_NODE_CLIP))
{
const graphene_rect_t *clip = gsk_clip_node_peek_clip (node);
add_rect (nodes, clip, offset_x, offset_y);
gsk_broadway_renderer_add_node (renderer,
gsk_clip_node_get_child (node),
clip->origin.x,
clip->origin.y);
}
return;
case GSK_TRANSFORM_NODE:
{
const graphene_rect_t *clip = gsk_clip_node_peek_clip (node);
add_uint32 (nodes, BROADWAY_NODE_CLIP);
add_rect (nodes, clip, offset_x, offset_y);
gsk_broadway_renderer_add_node (renderer, nodes, node_textures,
gsk_clip_node_get_child (node),
clip->origin.x,
clip->origin.y);
GskTransform *transform = gsk_transform_node_get_transform (node);
GskTransformCategory category = gsk_transform_get_category (transform);
if (category >= GSK_TRANSFORM_CATEGORY_2D_TRANSLATE)
{
if (add_new_node (renderer, node, BROADWAY_NODE_TRANSLATE)) {
float dx, dy;
gsk_transform_to_translate (transform, &dx, &dy);
add_xy (nodes, dx, dy, offset_x, offset_y);
gsk_broadway_renderer_add_node (renderer,
gsk_transform_node_get_child (node),
0, 0);
}
}
else
{
/* Fallback to texture for now */
break;
}
}
return;
case GSK_DEBUG_NODE:
if (add_new_node (renderer, node, BROADWAY_NODE_DEBUG))
{
const char *message = gsk_debug_node_get_message (node);
add_string (nodes, message);
gsk_broadway_renderer_add_node (renderer,
gsk_debug_node_get_child (node), offset_x, offset_y);
}
return;
/* Generic nodes */
case GSK_CONTAINER_NODE:
{
guint i;
if (add_new_node (renderer, node, BROADWAY_NODE_CONTAINER))
{
guint i;
add_uint32 (nodes, BROADWAY_NODE_CONTAINER);
add_uint32 (nodes, gsk_container_node_get_n_children (node));
for (i = 0; i < gsk_container_node_get_n_children (node); i++)
gsk_broadway_renderer_add_node (renderer, nodes, node_textures,
gsk_container_node_get_child (node, i), offset_x, offset_y);
}
return;
case GSK_DEBUG_NODE:
gsk_broadway_renderer_add_node (renderer, nodes, node_textures,
gsk_debug_node_get_child (node), offset_x, offset_y);
add_uint32 (nodes, gsk_container_node_get_n_children (node));
for (i = 0; i < gsk_container_node_get_n_children (node); i++)
gsk_broadway_renderer_add_node (renderer,
gsk_container_node_get_child (node, i), offset_x, offset_y);
}
return;
case GSK_COLOR_MATRIX_NODE:
case GSK_TEXT_NODE:
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_TRANSFORM_NODE:
case GSK_REPEAT_NODE:
case GSK_BLEND_NODE:
case GSK_CROSS_FADE_NODE:
@@ -665,32 +563,33 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
break; /* Fallback */
}
{
GdkTexture *texture;
guint32 texture_id;
float t_off_x = 0, t_off_y = 0;
if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE))
{
GdkTexture *texture;
cairo_surface_t *surface;
cairo_t *cr;
guint32 texture_id;
int x = floorf (node->bounds.origin.x);
int y = floorf (node->bounds.origin.y);
int width = ceil (node->bounds.origin.x + node->bounds.size.width) - x;
int height = ceil (node->bounds.origin.y + node->bounds.size.height) - y;
texture = node_cache_lookup (node, &t_off_x, &t_off_y);
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
cr = cairo_create (surface);
cairo_translate (cr, -x, -y);
gsk_render_node_draw (node, cr);
cairo_destroy (cr);
if (!texture)
{
texture = node_texture_fallback (node, &t_off_x, &t_off_y);
#if 0
g_print ("Fallback %p for %s\n", texture, node->node_class->type_name);
#endif
texture = gdk_texture_new_for_surface (surface);
g_ptr_array_add (self->node_textures, texture); /* Transfers ownership to node_textures */
node_cache_store (node, texture, t_off_x, t_off_y);
}
g_ptr_array_add (node_textures, texture); /* Transfers ownership to node_textures */
texture_id = gdk_broadway_display_ensure_texture (display, texture);
add_uint32 (nodes, BROADWAY_NODE_TEXTURE);
add_float (nodes, node->bounds.origin.x + t_off_x - offset_x);
add_float (nodes, node->bounds.origin.y + t_off_y - offset_y);
add_float (nodes, gdk_texture_get_width (texture));
add_float (nodes, gdk_texture_get_height (texture));
add_uint32 (nodes, texture_id);
}
texture_id = gdk_broadway_display_ensure_texture (display, texture);
add_float (nodes, x - offset_x);
add_float (nodes, y - offset_y);
add_float (nodes, gdk_texture_get_width (texture));
add_float (nodes, gdk_texture_get_height (texture));
add_uint32 (nodes, texture_id);
}
}
static void
@@ -700,9 +599,40 @@ gsk_broadway_renderer_render (GskRenderer *renderer,
{
GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer);
self->node_lookup = g_hash_table_new (g_direct_hash, g_direct_equal);
gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->draw_context), update_area);
gsk_broadway_renderer_add_node (renderer, self->draw_context->nodes, self->draw_context->node_textures, root, 0, 0);
/* These are owned by the draw context between begin and end, but
cache them here for easier access during the render */
self->nodes = self->draw_context->nodes;
self->node_textures = self->draw_context->node_textures;
gsk_broadway_renderer_add_node (renderer, root, 0, 0);
self->nodes = NULL;
self->node_textures = NULL;
gdk_draw_context_end_frame (GDK_DRAW_CONTEXT (self->draw_context));
if (self->last_node_lookup)
g_hash_table_unref (self->last_node_lookup);
self->last_node_lookup = self->node_lookup;
self->node_lookup = NULL;
if (self->last_root)
gsk_render_node_unref (self->last_root);
self->last_root = gsk_render_node_ref (root);
if (self->next_node_id > G_MAXUINT32 / 2)
{
/* We're "near" a wrap of the ids, lets avoid reusing any of
* these nodes next frame, then we can reset the id counter
* without risk of any old nodes sticking around and conflicting. */
g_hash_table_remove_all (self->last_node_lookup);
self->next_node_id = 0;
}
}
static void
+1 -1
View File
@@ -176,7 +176,7 @@ typedef enum {
* determined.
* @GSK_TRANSFORM_CATEGORY_ANY: Analyzing the matrix concluded that it does
* not fit in any other category.
* @GSK_TRANSFORM_CATEGORY_2D: The matrix is a 3D matrix. This means that
* @GSK_TRANSFORM_CATEGORY_3D: The matrix is a 3D matrix. This means that
* the w column (the last column) has the values (0, 0, 0, 1).
* @GSK_TRANSFORM_CATEGORY_2D: The matrix is a 2D matrix. This is equivalent
* to graphene_matrix_is_2d() returning %TRUE. In particular, this
+15 -85
View File
@@ -68,7 +68,6 @@ typedef struct
GdkSurface *surface;
GskRenderNode *prev_node;
GskRenderNode *root_node;
GdkDisplay *display;
GskProfiler *profiler;
@@ -80,8 +79,9 @@ typedef struct
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GskRenderer, gsk_renderer, G_TYPE_OBJECT)
enum {
PROP_SURFACE = 1,
PROP_DISPLAY,
PROP_0,
PROP_REALIZED,
PROP_SURFACE,
N_PROPS
};
@@ -134,33 +134,10 @@ gsk_renderer_dispose (GObject *gobject)
g_assert (!priv->is_realized);
g_clear_object (&priv->profiler);
g_clear_object (&priv->display);
G_OBJECT_CLASS (gsk_renderer_parent_class)->dispose (gobject);
}
static void
gsk_renderer_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GskRenderer *self = GSK_RENDERER (gobject);
GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);
switch (prop_id)
{
case PROP_DISPLAY:
/* Construct-only */
priv->display = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
gsk_renderer_get_property (GObject *gobject,
guint prop_id,
@@ -172,12 +149,12 @@ gsk_renderer_get_property (GObject *gobject,
switch (prop_id)
{
case PROP_SURFACE:
g_value_set_object (value, priv->surface);
case PROP_REALIZED:
g_value_set_boolean (value, priv->is_realized);
break;
case PROP_DISPLAY:
g_value_set_object (value, priv->display);
case PROP_SURFACE:
g_value_set_object (value, priv->surface);
break;
default:
@@ -186,23 +163,6 @@ gsk_renderer_get_property (GObject *gobject,
}
}
static void
gsk_renderer_constructed (GObject *gobject)
{
GskRenderer *self = GSK_RENDERER (gobject);
GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);
if (priv->display == NULL)
{
GdkDisplayManager *manager = gdk_display_manager_get ();
priv->display = gdk_display_manager_get_default_display (manager);
g_assert (priv->display != NULL);
}
G_OBJECT_CLASS (gsk_renderer_parent_class)->constructed (gobject);
}
static void
gsk_renderer_class_init (GskRendererClass *klass)
{
@@ -213,32 +173,22 @@ gsk_renderer_class_init (GskRendererClass *klass)
klass->render = gsk_renderer_real_render;
klass->render_texture = gsk_renderer_real_render_texture;
gobject_class->constructed = gsk_renderer_constructed;
gobject_class->set_property = gsk_renderer_set_property;
gobject_class->get_property = gsk_renderer_get_property;
gobject_class->dispose = gsk_renderer_dispose;
/**
* GskRenderer:display:
*
* The #GdkDisplay used by the #GskRenderer.
*/
gsk_renderer_properties[PROP_DISPLAY] =
g_param_spec_object ("display",
"Display",
"The GdkDisplay object used by the renderer",
GDK_TYPE_DISPLAY,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
gsk_renderer_properties[PROP_REALIZED] =
g_param_spec_boolean ("realized",
"Realized",
"The renderer has been associated with a surface",
FALSE,
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
gsk_renderer_properties[PROP_SURFACE] =
g_param_spec_object ("surface",
"Surface",
"The surface associated to the renderer",
GDK_TYPE_SURFACE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPS, gsk_renderer_properties);
}
@@ -290,24 +240,6 @@ gsk_renderer_get_root_node (GskRenderer *renderer)
}
/**
* gsk_renderer_get_display:
* @renderer: a #GskRenderer
*
* Retrieves the #GdkDisplay used when creating the #GskRenderer.
*
* Returns: (transfer none): a #GdkDisplay
*/
GdkDisplay *
gsk_renderer_get_display (GskRenderer *renderer)
{
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
return priv->display;
}
/*< private >
* gsk_renderer_is_realized:
* @renderer: a #GskRenderer
*
@@ -674,9 +606,7 @@ gsk_renderer_new_for_surface (GdkSurface *surface)
* information to stdout.
*/
verbose |= renderer_possibilities[i].verbose;
renderer = g_object_new (renderer_type,
"display", gdk_surface_get_display (surface),
NULL);
renderer = g_object_new (renderer_type, NULL);
if (gsk_renderer_realize (renderer, surface, &error))
{
+4 -5
View File
@@ -39,13 +39,10 @@ GDK_AVAILABLE_IN_ALL
GType gsk_renderer_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GskRenderer * gsk_renderer_new_for_surface (GdkSurface *surface);
GskRenderer * gsk_renderer_new_for_surface (GdkSurface *surface);
GDK_AVAILABLE_IN_ALL
GdkSurface * gsk_renderer_get_surface (GskRenderer *renderer);
GDK_AVAILABLE_IN_ALL
GdkDisplay * gsk_renderer_get_display (GskRenderer *renderer);
GdkSurface * gsk_renderer_get_surface (GskRenderer *renderer);
GDK_AVAILABLE_IN_ALL
gboolean gsk_renderer_realize (GskRenderer *renderer,
@@ -53,6 +50,8 @@ gboolean gsk_renderer_realize (GskRenderer
GError **error);
GDK_AVAILABLE_IN_ALL
void gsk_renderer_unrealize (GskRenderer *renderer);
GDK_AVAILABLE_IN_ALL
gboolean gsk_renderer_is_realized (GskRenderer *renderer);
GDK_AVAILABLE_IN_ALL
GdkTexture * gsk_renderer_render_texture (GskRenderer *renderer,
-2
View File
@@ -51,8 +51,6 @@ struct _GskRendererClass
const cairo_region_t *invalid);
};
gboolean gsk_renderer_is_realized (GskRenderer *renderer);
GskRenderNode * gsk_renderer_get_root_node (GskRenderer *renderer);
GskProfiler * gsk_renderer_get_profiler (GskRenderer *renderer);
+14 -1
View File
@@ -2427,6 +2427,19 @@ gsk_transform_node_draw (GskRenderNode *node,
gsk_render_node_draw (self->child, cr);
}
static gboolean
gsk_transform_node_can_diff (GskRenderNode *node1,
GskRenderNode *node2)
{
GskTransformNode *self1 = (GskTransformNode *) node1;
GskTransformNode *self2 = (GskTransformNode *) node2;
if (!gsk_transform_equal (self1->transform, self2->transform))
return FALSE;
return gsk_render_node_can_diff (self1->child, self2->child);
}
static void
gsk_transform_node_diff (GskRenderNode *node1,
GskRenderNode *node2,
@@ -2563,7 +2576,7 @@ static const GskRenderNodeClass GSK_TRANSFORM_NODE_CLASS = {
"GskTransformNode",
gsk_transform_node_finalize,
gsk_transform_node_draw,
gsk_render_node_can_diff_true,
gsk_transform_node_can_diff,
gsk_transform_node_diff,
gsk_transform_node_serialize,
gsk_transform_node_deserialize
+116 -5
View File
@@ -1095,6 +1095,120 @@ gsk_transform_scale_3d (GskTransform *next,
return &result->parent;
}
/*** PERSPECTIVE ***/
typedef struct _GskPerspectiveTransform GskPerspectiveTransform;
struct _GskPerspectiveTransform
{
GskTransform parent;
float depth;
};
static void
gsk_perspective_transform_finalize (GskTransform *self)
{
}
static void
gsk_perspective_transform_to_matrix (GskTransform *transform,
graphene_matrix_t *out_matrix)
{
GskPerspectiveTransform *self = (GskPerspectiveTransform *) transform;
float f[16] = { 1.f, 0.f, 0.f, 0.f,
0.f, 1.f, 0.f, 0.f,
0.f, 0.f, 1.f, -1.f / self->depth,
0.f, 0.f, 0.f, 1.f };
graphene_matrix_init_from_float (out_matrix, f);
}
static GskTransform *
gsk_perspective_transform_apply (GskTransform *transform,
GskTransform *apply_to)
{
GskPerspectiveTransform *self = (GskPerspectiveTransform *) transform;
return gsk_transform_perspective (apply_to, self->depth);
}
static GskTransform *
gsk_perspective_transform_invert (GskTransform *transform,
GskTransform *next)
{
GskPerspectiveTransform *self = (GskPerspectiveTransform *) transform;
return gsk_transform_perspective (next, - self->depth);
}
static gboolean
gsk_perspective_transform_equal (GskTransform *first_transform,
GskTransform *second_transform)
{
GskPerspectiveTransform *first = (GskPerspectiveTransform *) first_transform;
GskPerspectiveTransform *second = (GskPerspectiveTransform *) second_transform;
return first->depth == second->depth;
}
static void
gsk_perspective_transform_print (GskTransform *transform,
GString *string)
{
GskPerspectiveTransform *self = (GskPerspectiveTransform *) transform;
g_string_append (string, "perspective(");
string_append_double (string, self->depth);
g_string_append (string, ")");
}
static const GskTransformClass GSK_PERSPECTIVE_TRANSFORM_CLASS =
{
sizeof (GskPerspectiveTransform),
"GskPerspectiveTransform",
gsk_perspective_transform_finalize,
gsk_perspective_transform_to_matrix,
NULL,
NULL,
NULL,
gsk_perspective_transform_print,
gsk_perspective_transform_apply,
gsk_perspective_transform_invert,
gsk_perspective_transform_equal,
};
/**
* gsk_transform_perspective:
* @next: (allow-none): the next transform
* @depth: distance of the z=0 plane. Lower values give a more
* flattened pyramid and therefore a more pronounced
* perspective effect.
*
* Applies a perspective projection transform. This transform
* scales points in X and Y based on their Z value, scaling
* points with positive Z values away from the origin, and
* those with negative Z values towards the origin. Points
* on the z=0 plane are unchanged.
*
* Returns: The new matrix
**/
GskTransform *
gsk_transform_perspective (GskTransform *next,
float depth)
{
GskPerspectiveTransform *result;
result = gsk_transform_alloc (&GSK_PERSPECTIVE_TRANSFORM_CLASS,
GSK_TRANSFORM_CATEGORY_ANY,
next);
result->depth = depth;
return &result->parent;
}
/*** PUBLIC API ***/
static void
@@ -1225,7 +1339,7 @@ gsk_transform_to_matrix (GskTransform *self,
/**
* gsk_transform_to_2d:
* @m: a 2D #GskTransform
* @self: a 2D #GskTransform
* @out_xx: (out): return location for the xx member
* @out_yx: (out): return location for the yx member
* @out_xy: (out): return location for the xy member
@@ -1250,9 +1364,6 @@ gsk_transform_to_matrix (GskTransform *self,
* This function can be used to convert between a #GskTransform
* and a matrix type from other 2D drawing libraries, in particular
* Cairo.
*
* Returns: %TRUE if the matrix is compatible with an 2D
* transformation matrix.
*/
void
gsk_transform_to_2d (GskTransform *self,
@@ -1344,7 +1455,7 @@ gsk_transform_to_affine (GskTransform *self,
/**
* gsk_transform_to_translate:
* @m: a #GskTransform
* @self: a #GskTransform
* @out_dx: (out): return location for the translation
* in the x direction
* @out_dy: (out): return location for the translation
+3
View File
@@ -105,6 +105,9 @@ GskTransform * gsk_transform_scale_3d (GskTransform
float factor_x,
float factor_y,
float factor_z);
GDK_AVAILABLE_IN_ALL
GskTransform * gsk_transform_perspective (GskTransform *next,
float depth);
GDK_AVAILABLE_IN_ALL
void gsk_transform_transform_bounds (GskTransform *self,
+47 -45
View File
@@ -367,7 +367,7 @@ static void delete_text_cb (GtkEditable *editable,
gint end);
static gboolean check_for_selection_change (GtkEntryAccessible *entry,
GtkEntry *gtk_entry);
GtkEditable *editable);
static void atk_editable_text_interface_init (AtkEditableTextIface *iface);
@@ -465,56 +465,57 @@ gtk_entry_accessible_notify_gtk (GObject *obj,
{
GtkWidget *widget;
AtkObject* atk_obj;
GtkEntry* gtk_entry;
GtkEntryAccessible* entry;
GtkEntryAccessiblePrivate *priv;
widget = GTK_WIDGET (obj);
atk_obj = gtk_widget_get_accessible (widget);
gtk_entry = GTK_ENTRY (widget);
entry = GTK_ENTRY_ACCESSIBLE (atk_obj);
priv = entry->priv;
if (g_strcmp0 (pspec->name, "cursor-position") == 0)
{
if (check_for_selection_change (entry, gtk_entry))
if (check_for_selection_change (entry, GTK_EDITABLE (widget)))
g_signal_emit_by_name (atk_obj, "text-selection-changed");
/*
* The entry cursor position has moved so generate the signal.
*/
g_signal_emit_by_name (atk_obj, "text-caret-moved",
entry->priv->cursor_position);
gtk_editable_get_position (GTK_EDITABLE (widget)));
}
else if (g_strcmp0 (pspec->name, "selection-bound") == 0)
{
if (check_for_selection_change (entry, gtk_entry))
if (check_for_selection_change (entry, GTK_EDITABLE (widget)))
g_signal_emit_by_name (atk_obj, "text-selection-changed");
}
else if (g_strcmp0 (pspec->name, "editable") == 0)
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "editable") == 0)
{
gboolean value;
g_object_get (obj, "editable", &value, NULL);
atk_object_notify_state_change (atk_obj, ATK_STATE_EDITABLE, value);
}
else if (g_strcmp0 (pspec->name, "visibility") == 0)
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "visibility") == 0)
{
gboolean visibility;
AtkRole new_role;
visibility = gtk_entry_get_visibility (gtk_entry);
visibility = gtk_entry_get_visibility (GTK_ENTRY (widget));
new_role = visibility ? ATK_ROLE_TEXT : ATK_ROLE_PASSWORD_TEXT;
atk_object_set_role (atk_obj, new_role);
}
else if (g_strcmp0 (pspec->name, "primary-icon-storage-type") == 0)
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "primary-icon-storage-type") == 0)
{
if (gtk_entry_get_icon_storage_type (gtk_entry, GTK_ENTRY_ICON_PRIMARY) != GTK_IMAGE_EMPTY && !priv->icons[GTK_ENTRY_ICON_PRIMARY])
if (gtk_entry_get_icon_storage_type (GTK_ENTRY (widget), GTK_ENTRY_ICON_PRIMARY) != GTK_IMAGE_EMPTY && !priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
priv->icons[GTK_ENTRY_ICON_PRIMARY] = gtk_entry_icon_accessible_new (entry, GTK_ENTRY_ICON_PRIMARY);
g_signal_emit_by_name (entry, "children-changed::add", 0,
priv->icons[GTK_ENTRY_ICON_PRIMARY], NULL);
}
else if (gtk_entry_get_icon_storage_type (gtk_entry, GTK_ENTRY_ICON_PRIMARY) == GTK_IMAGE_EMPTY && priv->icons[GTK_ENTRY_ICON_PRIMARY])
else if (gtk_entry_get_icon_storage_type (GTK_ENTRY (widget), GTK_ENTRY_ICON_PRIMARY) == GTK_IMAGE_EMPTY && priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
gtk_entry_icon_accessible_invalidate (GTK_ENTRY_ICON_ACCESSIBLE (priv->icons[GTK_ENTRY_ICON_PRIMARY]));
g_signal_emit_by_name (entry, "children-changed::remove", 0,
@@ -522,16 +523,17 @@ gtk_entry_accessible_notify_gtk (GObject *obj,
g_clear_object (&priv->icons[GTK_ENTRY_ICON_PRIMARY]);
}
}
else if (g_strcmp0 (pspec->name, "secondary-icon-storage-type") == 0)
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "secondary-icon-storage-type") == 0)
{
gint index = (priv->icons[GTK_ENTRY_ICON_PRIMARY] ? 1 : 0);
if (gtk_entry_get_icon_storage_type (gtk_entry, GTK_ENTRY_ICON_SECONDARY) != GTK_IMAGE_EMPTY && !priv->icons[GTK_ENTRY_ICON_SECONDARY])
if (gtk_entry_get_icon_storage_type (GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY) != GTK_IMAGE_EMPTY && !priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
priv->icons[GTK_ENTRY_ICON_SECONDARY] = gtk_entry_icon_accessible_new (entry, GTK_ENTRY_ICON_SECONDARY);
g_signal_emit_by_name (entry, "children-changed::add", index,
priv->icons[GTK_ENTRY_ICON_SECONDARY], NULL);
}
else if (gtk_entry_get_icon_storage_type (gtk_entry, GTK_ENTRY_ICON_SECONDARY) == GTK_IMAGE_EMPTY && priv->icons[GTK_ENTRY_ICON_SECONDARY])
else if (gtk_entry_get_icon_storage_type (GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY) == GTK_IMAGE_EMPTY && priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
gtk_entry_icon_accessible_invalidate (GTK_ENTRY_ICON_ACCESSIBLE (priv->icons[GTK_ENTRY_ICON_SECONDARY]));
g_signal_emit_by_name (entry, "children-changed::remove", index,
@@ -539,100 +541,100 @@ gtk_entry_accessible_notify_gtk (GObject *obj,
g_clear_object (&priv->icons[GTK_ENTRY_ICON_SECONDARY]);
}
}
else if (g_strcmp0 (pspec->name, "primary-icon-name") == 0)
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "primary-icon-name") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
const gchar *name;
name = gtk_entry_get_icon_name (gtk_entry,
GTK_ENTRY_ICON_PRIMARY);
name = gtk_entry_get_icon_name (GTK_ENTRY (widget), GTK_ENTRY_ICON_PRIMARY);
if (name)
atk_object_set_name (priv->icons[GTK_ENTRY_ICON_PRIMARY], name);
}
}
else if (g_strcmp0 (pspec->name, "secondary-icon-name") == 0)
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "secondary-icon-name") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
const gchar *name;
name = gtk_entry_get_icon_name (gtk_entry,
GTK_ENTRY_ICON_SECONDARY);
name = gtk_entry_get_icon_name (GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY);
if (name)
atk_object_set_name (priv->icons[GTK_ENTRY_ICON_SECONDARY], name);
}
}
else if (g_strcmp0 (pspec->name, "primary-icon-tooltip-text") == 0)
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "primary-icon-tooltip-text") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
gchar *text;
text = gtk_entry_get_icon_tooltip_text (gtk_entry,
GTK_ENTRY_ICON_PRIMARY);
text = gtk_entry_get_icon_tooltip_text (GTK_ENTRY (widget), GTK_ENTRY_ICON_PRIMARY);
if (text)
{
atk_object_set_description (priv->icons[GTK_ENTRY_ICON_PRIMARY],
text);
atk_object_set_description (priv->icons[GTK_ENTRY_ICON_PRIMARY], text);
g_free (text);
}
else
{
atk_object_set_description (priv->icons[GTK_ENTRY_ICON_PRIMARY],
"");
atk_object_set_description (priv->icons[GTK_ENTRY_ICON_PRIMARY], "");
}
}
}
else if (g_strcmp0 (pspec->name, "secondary-icon-tooltip-text") == 0)
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "secondary-icon-tooltip-text") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
gchar *text;
text = gtk_entry_get_icon_tooltip_text (gtk_entry,
GTK_ENTRY_ICON_SECONDARY);
text = gtk_entry_get_icon_tooltip_text (GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY);
if (text)
{
atk_object_set_description (priv->icons[GTK_ENTRY_ICON_SECONDARY],
text);
atk_object_set_description (priv->icons[GTK_ENTRY_ICON_SECONDARY], text);
g_free (text);
}
else
{
atk_object_set_description (priv->icons[GTK_ENTRY_ICON_SECONDARY],
"");
atk_object_set_description (priv->icons[GTK_ENTRY_ICON_SECONDARY], "");
}
}
}
else if (g_strcmp0 (pspec->name, "primary-icon-activatable") == 0)
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "primary-icon-activatable") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
gboolean on = gtk_entry_get_icon_activatable (gtk_entry, GTK_ENTRY_ICON_PRIMARY);
gboolean on = gtk_entry_get_icon_activatable (GTK_ENTRY (widget), GTK_ENTRY_ICON_PRIMARY);
atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_PRIMARY],
ATK_STATE_ENABLED, on);
}
}
else if (g_strcmp0 (pspec->name, "secondary-icon-activatable") == 0)
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "secondary-icon-activatable") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
gboolean on = gtk_entry_get_icon_activatable (gtk_entry, GTK_ENTRY_ICON_SECONDARY);
gboolean on = gtk_entry_get_icon_activatable (GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY);
atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_SECONDARY],
ATK_STATE_ENABLED, on);
}
}
else if (g_strcmp0 (pspec->name, "primary-icon-sensitive") == 0)
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "primary-icon-sensitive") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
gboolean on = gtk_entry_get_icon_sensitive (gtk_entry, GTK_ENTRY_ICON_PRIMARY);
gboolean on = gtk_entry_get_icon_sensitive (GTK_ENTRY (widget), GTK_ENTRY_ICON_PRIMARY);
atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_PRIMARY],
ATK_STATE_SENSITIVE, on);
}
}
else if (g_strcmp0 (pspec->name, "secondary-icon-sensitive") == 0)
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "secondary-icon-sensitive") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
gboolean on = gtk_entry_get_icon_sensitive (gtk_entry, GTK_ENTRY_ICON_SECONDARY);
gboolean on = gtk_entry_get_icon_sensitive (GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY);
atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_SECONDARY],
ATK_STATE_SENSITIVE, on);
}
@@ -1450,12 +1452,12 @@ delete_text_cb (GtkEditable *editable,
static gboolean
check_for_selection_change (GtkEntryAccessible *accessible,
GtkEntry *entry)
GtkEditable *editable)
{
gboolean ret_val = FALSE;
gint start, end;
if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start, &end))
if (gtk_editable_get_selection_bounds (editable, &start, &end))
{
if (end != accessible->priv->cursor_position ||
start != accessible->priv->selection_bound)
-5
View File
@@ -46,11 +46,6 @@ xml += '\n'
for f in get_files('theme/HighContrast/assets', '.svg'):
xml += ' <file>theme/HighContrast/assets/{0}</file>\n'.format(f)
xml += '''
<file>theme/win32/gtk-win32-base.css</file>
<file>theme/win32/gtk.css</file>
'''
for f in get_files('gesture', '.symbolic.png'):
xml += ' <file alias=\'icons/64x64/actions/{0}\'>gesture/{0}</file>\n'.format(f)
+6
View File
@@ -45,8 +45,10 @@
#include <gtk/gtkaspectframe.h>
#include <gtk/gtkassistant.h>
#include <gtk/gtkbin.h>
#include <gtk/gtkbinlayout.h>
#include <gtk/gtkbindings.h>
#include <gtk/gtkborder.h>
#include <gtk/gtkboxlayout.h>
#include <gtk/gtkbox.h>
#include <gtk/gtkbuildable.h>
#include <gtk/gtkbuilder.h>
@@ -80,6 +82,7 @@
#include <gtk/gtkcontainer.h>
#include <gtk/gtkcssprovider.h>
#include <gtk/gtkcsssection.h>
#include <gtk/gtkcustomlayout.h>
#include <gtk/gtkdebug.h>
#include <gtk/gtkdialog.h>
#include <gtk/gtkdnd.h>
@@ -98,6 +101,7 @@
#include <gtk/gtkeventcontrollerscroll.h>
#include <gtk/gtkexpander.h>
#include <gtk/gtkfixed.h>
#include <gtk/gtkfixedlayout.h>
#include <gtk/gtkfilechooser.h>
#include <gtk/gtkfilechooserbutton.h>
#include <gtk/gtkfilechooserdialog.h>
@@ -134,6 +138,8 @@
#include <gtk/gtkinfobar.h>
#include <gtk/gtklabel.h>
#include <gtk/gtklayout.h>
#include <gtk/gtklayoutmanager.h>
#include <gtk/gtklayoutchild.h>
#include <gtk/gtklevelbar.h>
#include <gtk/gtklinkbutton.h>
#include <gtk/gtklistbox.h>
+2
View File
@@ -26,6 +26,8 @@
#include "gtksettings.h"
#include "gtkprivate.h"
#include "gdk/gdkconstructor.h"
G_DEFINE_TYPE (GtkApplicationImplDBus, gtk_application_impl_dbus, GTK_TYPE_APPLICATION_IMPL)
#define DBUS_BUS_NAME "org.freedesktop.DBus"
+4 -3
View File
@@ -74,14 +74,15 @@
#include "gtkintl.h"
#include "gtkimage.h"
#include "gtklabel.h"
#include "gtkstack.h"
#include "gtklistlistmodelprivate.h"
#include "gtkmaplistmodel.h"
#include "gtkprivate.h"
#include "gtksettings.h"
#include "gtksizegroup.h"
#include "gtksizerequest.h"
#include "gtkstack.h"
#include "gtkstylecontext.h"
#include "gtktypebuiltins.h"
#include "gtklistlistmodelprivate.h"
#include "gtkmaplistmodel.h"
#include "a11y/gtkwindowaccessible.h"
+124
View File
@@ -0,0 +1,124 @@
/* gtkbinlayout.c: Layout manager for bin-like widgets
* Copyright 2019 GNOME Foundation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* SECTION:gtkbinlayout
* @Title: GtkBinLayout
* @Short_description: A layout manager for bin-like widgets
* @Include: gtk/gtk.h
*
* GtkBinLayout is a #GtkLayoutManager subclass useful for create "bins" of
* widgets. GtkBinLayout will stack each child of a widget on top of each
* other, using the #GtkWidget:hexpand, #GtkWidget:vexpand, #GtkWidget:halign,
* and #GtkWidget:valign properties of each child to determine where they
* should be positioned.
*/
#include "config.h"
#include "gtkbinlayout.h"
#include "gtkwidgetprivate.h"
struct _GtkBinLayout
{
GtkLayoutManager parent_instance;
};
G_DEFINE_TYPE (GtkBinLayout, gtk_bin_layout, GTK_TYPE_LAYOUT_MANAGER)
static void
gtk_bin_layout_measure (GtkLayoutManager *layout_manager,
GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
GtkWidget *child;
for (child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
if (gtk_widget_get_visible (child))
{
int child_min = 0;
int child_nat = 0;
int child_min_baseline = -1;
int child_nat_baseline = -1;
gtk_widget_measure (child, orientation, for_size,
&child_min, &child_nat,
&child_min_baseline, &child_nat_baseline);
*minimum = MAX (*minimum, child_min);
*natural = MAX (*natural, child_nat);
if (child_min_baseline > -1)
*minimum_baseline = MAX (*minimum_baseline, child_min_baseline);
if (child_nat_baseline > -1)
*natural_baseline = MAX (*natural_baseline, child_nat_baseline);
}
}
}
static void
gtk_bin_layout_allocate (GtkLayoutManager *layout_manager,
GtkWidget *widget,
int width,
int height,
int baseline)
{
GtkWidget *child;
for (child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
if (child && gtk_widget_get_visible (child))
gtk_widget_allocate (child, width, height, baseline, NULL);
}
}
static void
gtk_bin_layout_class_init (GtkBinLayoutClass *klass)
{
GtkLayoutManagerClass *layout_manager_class = GTK_LAYOUT_MANAGER_CLASS (klass);
layout_manager_class->measure = gtk_bin_layout_measure;
layout_manager_class->allocate = gtk_bin_layout_allocate;
}
static void
gtk_bin_layout_init (GtkBinLayout *self)
{
}
/**
* gtk_bin_layout_new:
*
* Creates a new #GtkBinLayout instance.
*
* Returns: the newly created #GtkBinLayout
*/
GtkLayoutManager *
gtk_bin_layout_new (void)
{
return g_object_new (GTK_TYPE_BIN_LAYOUT, NULL);
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2012 Red Hat Inc.
/* gtkbinlayout.h: Layout manager for bin-like widgets
* Copyright 2019 GNOME Foundation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -13,20 +13,19 @@
*
* 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: Alexander Larsson <alexl@gnome.org>
*/
#pragma once
#ifndef __GTK_CSS_WIN32_SIZE_VALUE_PRIVATE_H__
#define __GTK_CSS_WIN32_SIZE_VALUE_PRIVATE_H__
#include "gtkcssnumbervalueprivate.h"
#include <gtk/gtklayoutmanager.h>
G_BEGIN_DECLS
GtkCssValue * gtk_css_win32_size_value_parse (GtkCssParser *parser,
GtkCssNumberParseFlags flags);
#define GTK_TYPE_BIN_LAYOUT (gtk_bin_layout_get_type ())
GDK_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (GtkBinLayout, gtk_bin_layout, GTK, BIN_LAYOUT, GtkLayoutManager)
GDK_AVAILABLE_IN_ALL
GtkLayoutManager * gtk_bin_layout_new (void);
G_END_DECLS
#endif /* __GTK_CSS_WIN32_SIZE_VALUE_PRIVATE_H__ */
+45 -578
View File
@@ -57,6 +57,7 @@
#include "config.h"
#include "gtkbox.h"
#include "gtkboxlayout.h"
#include "gtkcsspositionvalueprivate.h"
#include "gtkintl.h"
#include "gtkorientable.h"
@@ -92,11 +93,6 @@ typedef struct
static GParamSpec *props[LAST_PROP] = { NULL, };
static void gtk_box_size_allocate (GtkWidget *widget,
int width,
int height,
int baseline);
static void gtk_box_set_property (GObject *object,
guint prop_id,
const GValue *value,
@@ -116,13 +112,6 @@ static GType gtk_box_child_type (GtkContainer *container);
static GtkWidgetPath * gtk_box_get_path_for_child
(GtkContainer *container,
GtkWidget *child);
static void gtk_box_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline);
G_DEFINE_TYPE_WITH_CODE (GtkBox, gtk_box, GTK_TYPE_CONTAINER,
G_ADD_PRIVATE (GtkBox)
@@ -138,9 +127,6 @@ gtk_box_class_init (GtkBoxClass *class)
object_class->set_property = gtk_box_set_property;
object_class->get_property = gtk_box_get_property;
widget_class->size_allocate = gtk_box_size_allocate;
widget_class->measure = gtk_box_measure;
container_class->add = gtk_box_add;
container_class->remove = gtk_box_remove;
container_class->forall = gtk_box_forall;
@@ -187,6 +173,7 @@ gtk_box_set_property (GObject *object,
{
GtkBox *box = GTK_BOX (object);
GtkBoxPrivate *priv = gtk_box_get_instance_private (box);
GtkLayoutManager *box_layout = gtk_widget_get_layout_manager (GTK_WIDGET (box));
switch (prop_id)
{
@@ -196,8 +183,9 @@ gtk_box_set_property (GObject *object,
if (priv->orientation != orientation)
{
priv->orientation = orientation;
gtk_orientable_set_orientation (GTK_ORIENTABLE (box_layout),
priv->orientation);
_gtk_orientable_set_style_classes (GTK_ORIENTABLE (box));
gtk_widget_queue_resize (GTK_WIDGET (box));
g_object_notify (object, "orientation");
}
}
@@ -225,6 +213,7 @@ gtk_box_get_property (GObject *object,
{
GtkBox *box = GTK_BOX (object);
GtkBoxPrivate *priv = gtk_box_get_instance_private (box);
GtkBoxLayout *box_layout = GTK_BOX_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (box)));
switch (prop_id)
{
@@ -232,13 +221,13 @@ gtk_box_get_property (GObject *object,
g_value_set_enum (value, priv->orientation);
break;
case PROP_SPACING:
g_value_set_int (value, priv->spacing);
g_value_set_int (value, gtk_box_layout_get_spacing (box_layout));
break;
case PROP_BASELINE_POSITION:
g_value_set_enum (value, priv->baseline_pos);
g_value_set_enum (value, gtk_box_layout_get_baseline_position (box_layout));
break;
case PROP_HOMOGENEOUS:
g_value_set_boolean (value, priv->homogeneous);
g_value_set_boolean (value, gtk_box_layout_get_homogeneous (box_layout));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -246,285 +235,6 @@ gtk_box_get_property (GObject *object,
}
}
static void
count_expand_children (GtkBox *box,
gint *visible_children,
gint *expand_children)
{
GtkBoxPrivate *priv = gtk_box_get_instance_private (box);
GtkWidget *child;
*visible_children = *expand_children = 0;
for (child = _gtk_widget_get_first_child (GTK_WIDGET (box));
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
if (_gtk_widget_get_visible (child))
{
*visible_children += 1;
if (gtk_widget_compute_expand (child, priv->orientation))
*expand_children += 1;
}
}
}
static gint
get_spacing (GtkBox *box)
{
GtkBoxPrivate *priv = gtk_box_get_instance_private (box);
GtkCssValue *border_spacing;
gint css_spacing;
border_spacing = _gtk_style_context_peek_property (gtk_widget_get_style_context (GTK_WIDGET (box)), GTK_CSS_PROPERTY_BORDER_SPACING);
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
css_spacing = _gtk_css_position_value_get_x (border_spacing, 100);
else
css_spacing = _gtk_css_position_value_get_y (border_spacing, 100);
return css_spacing + priv->spacing;
}
static void
gtk_box_size_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
{
GtkBox *box = GTK_BOX (widget);
GtkBoxPrivate *priv = gtk_box_get_instance_private (box);
GtkWidget *child;
gint nvis_children;
gint nexpand_children;
GtkTextDirection direction;
GtkAllocation child_allocation;
GtkRequestedSize *sizes;
gint child_minimum_baseline, child_natural_baseline;
gint minimum_above, natural_above;
gint minimum_below, natural_below;
gboolean have_baseline;
gint extra_space;
gint children_minimum_size = 0;
gint size_given_to_child;
gint n_extra_widgets = 0; /* Number of widgets that receive 1 extra px */
gint x = 0, y = 0, i;
gint child_size;
gint spacing;
count_expand_children (box, &nvis_children, &nexpand_children);
/* If there is no visible child, simply return. */
if (nvis_children <= 0)
return;
direction = _gtk_widget_get_direction (widget);
sizes = g_newa (GtkRequestedSize, nvis_children);
spacing = get_spacing (box);
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
extra_space = width - (nvis_children - 1) * spacing;
else
extra_space = height - (nvis_children - 1) * spacing;
have_baseline = FALSE;
minimum_above = natural_above = 0;
minimum_below = natural_below = 0;
/* Retrieve desired size for visible children. */
for (i = 0, child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
if (!_gtk_widget_get_visible (child))
continue;
gtk_widget_measure (child,
priv->orientation,
priv->orientation == GTK_ORIENTATION_HORIZONTAL ? height : width,
&sizes[i].minimum_size, &sizes[i].natural_size,
NULL, NULL);
children_minimum_size += sizes[i].minimum_size;
sizes[i].data = child;
i++;
}
if (priv->homogeneous)
{
/* We still need to run the above loop to populate the minimum sizes for
* children that aren't going to fill.
*/
size_given_to_child = extra_space / nvis_children;
n_extra_widgets = extra_space % nvis_children;
}
else
{
/* Bring children up to size first */
extra_space -= children_minimum_size;
extra_space = MAX (0, extra_space);
extra_space = gtk_distribute_natural_allocation (extra_space, nvis_children, sizes);
/* Calculate space which hasn't distributed yet,
* and is available for expanding children.
*/
if (nexpand_children > 0)
{
size_given_to_child = extra_space / nexpand_children;
n_extra_widgets = extra_space % nexpand_children;
}
else
{
size_given_to_child = 0;
}
}
/* Allocate child sizes. */
for (i = 0, child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
/* If widget is not visible, skip it. */
if (!_gtk_widget_get_visible (child))
continue;
/* Assign the child's size. */
if (priv->homogeneous)
{
child_size = size_given_to_child;
if (n_extra_widgets > 0)
{
child_size++;
n_extra_widgets--;
}
}
else
{
child_size = sizes[i].minimum_size;
if (gtk_widget_compute_expand (child, priv->orientation))
{
child_size += size_given_to_child;
if (n_extra_widgets > 0)
{
child_size++;
n_extra_widgets--;
}
}
}
sizes[i].natural_size = child_size;
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL &&
gtk_widget_get_valign (child) == GTK_ALIGN_BASELINE)
{
int child_allocation_width;
int child_minimum_height, child_natural_height;
child_allocation_width = child_size;
child_minimum_baseline = -1;
child_natural_baseline = -1;
gtk_widget_measure (child, GTK_ORIENTATION_VERTICAL,
child_allocation_width,
&child_minimum_height, &child_natural_height,
&child_minimum_baseline, &child_natural_baseline);
if (child_minimum_baseline >= 0)
{
have_baseline = TRUE;
minimum_below = MAX (minimum_below, child_minimum_height - child_minimum_baseline);
natural_below = MAX (natural_below, child_natural_height - child_natural_baseline);
minimum_above = MAX (minimum_above, child_minimum_baseline);
natural_above = MAX (natural_above, child_natural_baseline);
}
}
i++;
}
if (priv->orientation == GTK_ORIENTATION_VERTICAL)
baseline = -1;
/* we only calculate our own baseline if we don't get one passed from the parent
* and any of the child widgets explicitly request one */
if (baseline == -1 && have_baseline)
{
/* TODO: This is purely based on the minimum baseline, when things fit we should
use the natural one? */
switch (priv->baseline_pos)
{
case GTK_BASELINE_POSITION_TOP:
baseline = minimum_above;
break;
case GTK_BASELINE_POSITION_CENTER:
baseline = minimum_above + (height - (minimum_above + minimum_below)) / 2;
break;
case GTK_BASELINE_POSITION_BOTTOM:
baseline = height - minimum_below;
break;
default:
break;
}
}
/* Allocate child positions. */
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
{
child_allocation.y = 0;
child_allocation.height = height;
x = 0;
}
else
{
child_allocation.x = 0;
child_allocation.width = width;
y = 0;
}
for (i = 0, child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
/* If widget is not visible, skip it. */
if (!_gtk_widget_get_visible (child))
continue;
child_size = sizes[i].natural_size;
/* Assign the child's position. */
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
{
child_allocation.width = child_size;
child_allocation.x = x;
x += child_size + spacing;
if (direction == GTK_TEXT_DIR_RTL)
child_allocation.x = width - child_allocation.x - child_allocation.width;
}
else /* (priv->orientation == GTK_ORIENTATION_VERTICAL) */
{
child_allocation.height = child_size;
child_allocation.y = y;
y += child_size + spacing;
}
gtk_widget_size_allocate (child, &child_allocation, baseline);
i++;
}
}
static GType
gtk_box_child_type (GtkContainer *container)
{
@@ -630,263 +340,17 @@ gtk_box_get_path_for_child (GtkContainer *container,
return path;
}
static void
gtk_box_compute_size_for_opposing_orientation (GtkBox *box,
int for_size,
gint *minimum_size,
gint *natural_size,
gint *minimum_baseline,
gint *natural_baseline)
{
GtkBoxPrivate *priv = gtk_box_get_instance_private (box);
GtkWidget *widget = GTK_WIDGET (box);
GtkWidget *child;
gint nvis_children;
gint nexpand_children;
gint computed_minimum = 0, computed_natural = 0;
gint computed_minimum_above = 0, computed_natural_above = 0;
gint computed_minimum_below = 0, computed_natural_below = 0;
gint computed_minimum_baseline = -1, computed_natural_baseline = -1;
GtkRequestedSize *sizes;
gint extra_space, size_given_to_child, i;
gint children_minimum_size = 0;
gint child_size, child_minimum, child_natural;
gint child_minimum_baseline, child_natural_baseline;
gint n_extra_widgets = 0;
gint spacing;
gboolean have_baseline;
count_expand_children (box, &nvis_children, &nexpand_children);
if (nvis_children <= 0)
return;
spacing = get_spacing (box);
sizes = g_newa (GtkRequestedSize, nvis_children);
extra_space = MAX (0, for_size - (nvis_children - 1) * spacing);
/* Retrieve desired size for visible children */
for (i = 0, child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
if (_gtk_widget_get_visible (child))
{
gtk_widget_measure (child,
priv->orientation,
-1,
&sizes[i].minimum_size, &sizes[i].natural_size,
NULL, NULL);
children_minimum_size += sizes[i].minimum_size;
i += 1;
}
}
if (priv->homogeneous)
{
/* We still need to run the above loop to populate the minimum sizes for
* children that aren't going to fill.
*/
size_given_to_child = extra_space / nvis_children;
n_extra_widgets = extra_space % nvis_children;
}
else
{
/* Bring children up to size first */
extra_space -= children_minimum_size;
extra_space = MAX (0, extra_space);
extra_space = gtk_distribute_natural_allocation (extra_space, nvis_children, sizes);
/* Calculate space which hasn't distributed yet,
* and is available for expanding children.
*/
if (nexpand_children > 0)
{
size_given_to_child = extra_space / nexpand_children;
n_extra_widgets = extra_space % nexpand_children;
}
else
{
size_given_to_child = 0;
}
}
have_baseline = FALSE;
for (i = 0, child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
/* If widget is not visible, skip it. */
if (!_gtk_widget_get_visible (child))
continue;
/* Assign the child's size. */
if (priv->homogeneous)
{
child_size = size_given_to_child;
if (n_extra_widgets > 0)
{
child_size++;
n_extra_widgets--;
}
}
else
{
child_size = sizes[i].minimum_size;
if (gtk_widget_compute_expand (child, priv->orientation))
{
child_size += size_given_to_child;
if (n_extra_widgets > 0)
{
child_size++;
n_extra_widgets--;
}
}
}
child_minimum_baseline = child_natural_baseline = -1;
/* Assign the child's position. */
gtk_widget_measure (child,
OPPOSITE_ORIENTATION (priv->orientation),
child_size,
&child_minimum, &child_natural,
&child_minimum_baseline, &child_natural_baseline);
if (child_minimum_baseline >= 0)
{
have_baseline = TRUE;
computed_minimum_below = MAX (computed_minimum_below, child_minimum - child_minimum_baseline);
computed_natural_below = MAX (computed_natural_below, child_natural - child_natural_baseline);
computed_minimum_above = MAX (computed_minimum_above, child_minimum_baseline);
computed_natural_above = MAX (computed_natural_above, child_natural_baseline);
}
else
{
computed_minimum = MAX (computed_minimum, child_minimum);
computed_natural = MAX (computed_natural, child_natural);
}
i += 1;
}
if (have_baseline)
{
computed_minimum = MAX (computed_minimum, computed_minimum_below + computed_minimum_above);
computed_natural = MAX (computed_natural, computed_natural_below + computed_natural_above);
switch (priv->baseline_pos)
{
case GTK_BASELINE_POSITION_TOP:
computed_minimum_baseline = computed_minimum_above;
computed_natural_baseline = computed_natural_above;
break;
case GTK_BASELINE_POSITION_CENTER:
computed_minimum_baseline = computed_minimum_above + MAX((computed_minimum - (computed_minimum_above + computed_minimum_below)) / 2, 0);
computed_natural_baseline = computed_natural_above + MAX((computed_natural - (computed_natural_above + computed_natural_below)) / 2, 0);
break;
case GTK_BASELINE_POSITION_BOTTOM:
computed_minimum_baseline = computed_minimum - computed_minimum_below;
computed_natural_baseline = computed_natural - computed_natural_below;
break;
default:
break;
}
}
*minimum_size = computed_minimum;
*natural_size = MAX (computed_natural, computed_natural_below + computed_natural_above);
*minimum_baseline = computed_minimum_baseline;
*natural_baseline = computed_natural_baseline;
}
static void
gtk_box_compute_size_for_orientation (GtkBox *box,
int for_size,
int *minimum_size,
int *natural_size)
{
GtkBoxPrivate *priv = gtk_box_get_instance_private (box);
GtkWidget *child;
const int spacing = get_spacing (box);
int nvis_children = 0;
int required_size = 0, required_natural = 0;
int largest_child = 0, largest_natural = 0;
for (child = _gtk_widget_get_first_child (GTK_WIDGET (box));
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
if (_gtk_widget_get_visible (child))
{
int child_size, child_natural;
gtk_widget_measure (child,
priv->orientation,
for_size,
&child_size, &child_natural,
NULL, NULL);
largest_child = MAX (largest_child, child_size);
largest_natural = MAX (largest_natural, child_natural);
required_size += child_size;
required_natural += child_natural;
nvis_children += 1;
}
}
if (nvis_children > 0)
{
if (priv->homogeneous)
{
required_size = largest_child * nvis_children;
required_natural = largest_natural * nvis_children;
}
required_size += (nvis_children - 1) * spacing;
required_natural += (nvis_children - 1) * spacing;
}
*minimum_size = required_size;
*natural_size = required_natural;
}
static void
gtk_box_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
GtkBox *box = GTK_BOX (widget);
GtkBoxPrivate *priv = gtk_box_get_instance_private (box);
if (priv->orientation != orientation)
gtk_box_compute_size_for_opposing_orientation (box, for_size, minimum, natural, minimum_baseline, natural_baseline);
else
gtk_box_compute_size_for_orientation (box, for_size, minimum, natural);
}
static void
gtk_box_init (GtkBox *box)
{
GtkBoxPrivate *priv = gtk_box_get_instance_private (box);
GtkLayoutManager *box_layout = gtk_box_layout_new (GTK_ORIENTATION_HORIZONTAL);
gtk_widget_set_has_surface (GTK_WIDGET (box), FALSE);
priv->orientation = GTK_ORIENTATION_HORIZONTAL;
priv->homogeneous = FALSE;
priv->spacing = 0;
priv->baseline_pos = GTK_BASELINE_POSITION_CENTER;
gtk_widget_set_layout_manager (GTK_WIDGET (box), box_layout);
priv->orientation = GTK_ORIENTATION_HORIZONTAL;
_gtk_orientable_set_style_classes (GTK_ORIENTABLE (box));
}
@@ -905,7 +369,7 @@ gtk_box_new (GtkOrientation orientation,
{
return g_object_new (GTK_TYPE_BOX,
"orientation", orientation,
"spacing", spacing,
"spacing", spacing,
NULL);
}
@@ -923,18 +387,18 @@ void
gtk_box_set_homogeneous (GtkBox *box,
gboolean homogeneous)
{
GtkBoxPrivate *priv = gtk_box_get_instance_private (box);
GtkBoxLayout *box_layout;
g_return_if_fail (GTK_IS_BOX (box));
homogeneous = homogeneous != FALSE;
homogeneous = !!homogeneous;
if (priv->homogeneous != homogeneous)
{
priv->homogeneous = homogeneous;
g_object_notify_by_pspec (G_OBJECT (box), props[PROP_HOMOGENEOUS]);
gtk_widget_queue_resize (GTK_WIDGET (box));
}
box_layout = GTK_BOX_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (box)));
if (homogeneous == gtk_box_layout_get_homogeneous (box_layout))
return;
gtk_box_layout_set_homogeneous (box_layout, homogeneous);
g_object_notify_by_pspec (G_OBJECT (box), props[PROP_HOMOGENEOUS]);
}
/**
@@ -949,11 +413,13 @@ gtk_box_set_homogeneous (GtkBox *box,
gboolean
gtk_box_get_homogeneous (GtkBox *box)
{
GtkBoxPrivate *priv = gtk_box_get_instance_private (box);
GtkLayoutManager *box_layout;
g_return_val_if_fail (GTK_IS_BOX (box), FALSE);
return priv->homogeneous;
box_layout = gtk_widget_get_layout_manager (GTK_WIDGET (box));
return gtk_box_layout_get_homogeneous (GTK_BOX_LAYOUT (box_layout));
}
/**
@@ -968,18 +434,16 @@ void
gtk_box_set_spacing (GtkBox *box,
gint spacing)
{
GtkBoxPrivate *priv = gtk_box_get_instance_private (box);
GtkBoxLayout *box_layout;
g_return_if_fail (GTK_IS_BOX (box));
if (priv->spacing != spacing)
{
priv->spacing = spacing;
box_layout = GTK_BOX_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (box)));
if (spacing == gtk_box_layout_get_spacing (box_layout))
return;
g_object_notify_by_pspec (G_OBJECT (box), props[PROP_SPACING]);
gtk_widget_queue_resize (GTK_WIDGET (box));
}
gtk_box_layout_set_spacing (box_layout, spacing);
g_object_notify_by_pspec (G_OBJECT (box), props[PROP_SPACING]);
}
/**
@@ -993,10 +457,13 @@ gtk_box_set_spacing (GtkBox *box,
gint
gtk_box_get_spacing (GtkBox *box)
{
GtkBoxPrivate *priv = gtk_box_get_instance_private (box);
GtkLayoutManager *box_layout;
g_return_val_if_fail (GTK_IS_BOX (box), 0);
return priv->spacing;
box_layout = gtk_widget_get_layout_manager (GTK_WIDGET (box));
return gtk_box_layout_get_spacing (GTK_BOX_LAYOUT (box_layout));
}
/**
@@ -1015,18 +482,16 @@ void
gtk_box_set_baseline_position (GtkBox *box,
GtkBaselinePosition position)
{
GtkBoxPrivate *priv = gtk_box_get_instance_private (box);
GtkBoxLayout *box_layout;
g_return_if_fail (GTK_IS_BOX (box));
if (priv->baseline_pos != position)
{
priv->baseline_pos = position;
box_layout = GTK_BOX_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (box)));
if (position == gtk_box_layout_get_baseline_position (box_layout))
return;
g_object_notify_by_pspec (G_OBJECT (box), props[PROP_BASELINE_POSITION]);
gtk_widget_queue_resize (GTK_WIDGET (box));
}
gtk_box_layout_set_baseline_position (box_layout, position);
g_object_notify_by_pspec (G_OBJECT (box), props[PROP_BASELINE_POSITION]);
}
/**
@@ -1040,11 +505,13 @@ gtk_box_set_baseline_position (GtkBox *box,
GtkBaselinePosition
gtk_box_get_baseline_position (GtkBox *box)
{
GtkBoxPrivate *priv = gtk_box_get_instance_private (box);
GtkLayoutManager *box_layout;
g_return_val_if_fail (GTK_IS_BOX (box), GTK_BASELINE_POSITION_CENTER);
return priv->baseline_pos;
box_layout = gtk_widget_get_layout_manager (GTK_WIDGET (box));
return gtk_box_layout_get_baseline_position (GTK_BOX_LAYOUT (box_layout));
}
static void
+877
View File
@@ -0,0 +1,877 @@
/* gtkboxlayout.c: Box layout manager
*
* Copyright 2019 GNOME Foundation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 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 "gtkboxlayout.h"
#include "gtkcsspositionvalueprivate.h"
#include "gtkintl.h"
#include "gtkorientableprivate.h"
#include "gtkprivate.h"
#include "gtksizerequest.h"
#include "gtkstylecontextprivate.h"
#include "gtktypebuiltins.h"
#include "gtkwidgetprivate.h"
/**
* SECTION:gtkboxlayout
* @Title: GtkBoxLayout
* @Short_description: Layout manager for placing all children in a single row or column
*
* A GtkBoxLayout is a layout manager that arranges the children of any
* widget using it into a single row or column, depending on the value
* of its #GtkOrientable:orientation property. Within the other dimension
* all children all allocated the same size. The GtkBoxLayout will respect
* the #GtkWidget:halign and #GtkWidget:valign properties of each child
* widget.
*
* If you want all children to be assigned the same size, you can use
* the #GtkBoxLayout:homogeneous property.
*
* If you want to specify the amount of space placed between each child,
* you can use the #GtkBoxLayout:spacing property.
*/
struct _GtkBoxLayout
{
GtkLayoutManager parent_instance;
gboolean homogeneous;
guint spacing;
GtkOrientation orientation;
GtkBaselinePosition baseline_position;
};
G_DEFINE_TYPE_WITH_CODE (GtkBoxLayout, gtk_box_layout, GTK_TYPE_LAYOUT_MANAGER,
G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))
enum {
PROP_HOMOGENEOUS = 1,
PROP_SPACING,
PROP_BASELINE_POSITION,
/* From GtkOrientable */
PROP_ORIENTATION,
N_PROPS = PROP_ORIENTATION
};
static GParamSpec *box_layout_props[N_PROPS];
static void
gtk_box_layout_set_orientation (GtkBoxLayout *self,
GtkOrientation orientation)
{
GtkLayoutManager *layout_manager = GTK_LAYOUT_MANAGER (self);
GtkWidget *widget;
if (self->orientation == orientation)
return;
self->orientation = orientation;
widget = gtk_layout_manager_get_widget (layout_manager);
if (widget != NULL && GTK_IS_ORIENTABLE (widget))
_gtk_orientable_set_style_classes (GTK_ORIENTABLE (widget));
gtk_layout_manager_layout_changed (layout_manager);
}
static void
gtk_box_layout_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkBoxLayout *self = GTK_BOX_LAYOUT (gobject);
switch (prop_id)
{
case PROP_HOMOGENEOUS:
gtk_box_layout_set_homogeneous (self, g_value_get_boolean (value));
break;
case PROP_SPACING:
gtk_box_layout_set_spacing (self, g_value_get_int (value));
break;
case PROP_BASELINE_POSITION:
gtk_box_layout_set_baseline_position (self, g_value_get_enum (value));
break;
case PROP_ORIENTATION:
gtk_box_layout_set_orientation (self, g_value_get_enum (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
gtk_box_layout_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkBoxLayout *box_layout = GTK_BOX_LAYOUT (gobject);
switch (prop_id)
{
case PROP_HOMOGENEOUS:
g_value_set_boolean (value, box_layout->homogeneous);
break;
case PROP_SPACING:
g_value_set_int (value, box_layout->spacing);
break;
case PROP_BASELINE_POSITION:
g_value_set_enum (value, box_layout->baseline_position);
break;
case PROP_ORIENTATION:
g_value_set_enum (value, box_layout->orientation);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
count_expand_children (GtkWidget *widget,
GtkOrientation orientation,
gint *visible_children,
gint *expand_children)
{
GtkWidget *child;
*visible_children = *expand_children = 0;
for (child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
if (_gtk_widget_get_visible (child))
{
*visible_children += 1;
if (gtk_widget_compute_expand (child, orientation))
*expand_children += 1;
}
}
}
static gint
get_spacing (GtkBoxLayout *self,
GtkStyleContext *style_context)
{
GtkCssValue *border_spacing;
gint css_spacing;
border_spacing = _gtk_style_context_peek_property (style_context, GTK_CSS_PROPERTY_BORDER_SPACING);
if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
css_spacing = _gtk_css_position_value_get_x (border_spacing, 100);
else
css_spacing = _gtk_css_position_value_get_y (border_spacing, 100);
return css_spacing + self->spacing;
}
static GtkSizeRequestMode
gtk_box_layout_get_request_mode (GtkLayoutManager *layout_manager,
GtkWidget *widget)
{
GtkBoxLayout *self = GTK_BOX_LAYOUT (layout_manager);
return self->orientation == GTK_ORIENTATION_HORIZONTAL
? GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT
: GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
}
static void
gtk_box_layout_compute_size (GtkBoxLayout *self,
GtkWidget *widget,
int for_size,
int *minimum,
int *natural)
{
GtkWidget *child;
int n_visible_children = 0;
int required_min = 0, required_nat = 0;
int largest_min = 0, largest_nat = 0;
int spacing = get_spacing (self, _gtk_widget_get_style_context (widget));
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
{
int child_min = 0;
int child_nat = 0;
if (!_gtk_widget_get_visible (child))
continue;
gtk_widget_measure (child, self->orientation,
for_size,
&child_min, &child_nat,
NULL, NULL);
largest_min = MAX (largest_min, child_min);
largest_nat = MAX (largest_nat, child_nat);
required_min += child_min;
required_nat += child_nat;
n_visible_children += 1;
}
if (n_visible_children > 0)
{
if (self->homogeneous)
{
required_min = largest_min * n_visible_children;
required_nat = largest_nat * n_visible_children;
}
required_min += (n_visible_children - 1) * spacing;
required_nat += (n_visible_children - 1) * spacing;
}
if (minimum != NULL)
*minimum = required_min;
if (natural != NULL)
*natural = required_nat;
}
static void
gtk_box_layout_compute_opposite_size (GtkBoxLayout *self,
GtkWidget *widget,
int for_size,
int *minimum,
int *natural,
int *min_baseline,
int *nat_baseline)
{
GtkWidget *child;
int nvis_children;
int nexpand_children;
int computed_minimum = 0, computed_natural = 0;
int computed_minimum_above = 0, computed_natural_above = 0;
int computed_minimum_below = 0, computed_natural_below = 0;
int computed_minimum_baseline = -1, computed_natural_baseline = -1;
GtkRequestedSize *sizes;
int extra_space, size_given_to_child, i;
int children_minimum_size = 0;
int child_size, child_minimum, child_natural;
int child_minimum_baseline, child_natural_baseline;
int n_extra_widgets = 0;
int spacing;
gboolean have_baseline;
count_expand_children (widget, self->orientation, &nvis_children, &nexpand_children);
if (nvis_children <= 0)
return;
spacing = get_spacing (self, _gtk_widget_get_style_context (widget));
sizes = g_newa (GtkRequestedSize, nvis_children);
extra_space = MAX (0, for_size - (nvis_children - 1) * spacing);
/* Retrieve desired size for visible children */
for (i = 0, child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
if (_gtk_widget_get_visible (child))
{
gtk_widget_measure (child,
self->orientation,
-1,
&sizes[i].minimum_size, &sizes[i].natural_size,
NULL, NULL);
children_minimum_size += sizes[i].minimum_size;
i += 1;
}
}
if (self->homogeneous)
{
/* We still need to run the above loop to populate the minimum sizes for
* children that aren't going to fill.
*/
size_given_to_child = extra_space / nvis_children;
n_extra_widgets = extra_space % nvis_children;
}
else
{
/* Bring children up to size first */
extra_space -= children_minimum_size;
extra_space = MAX (0, extra_space);
extra_space = gtk_distribute_natural_allocation (extra_space, nvis_children, sizes);
/* Calculate space which hasn't distributed yet,
* and is available for expanding children.
*/
if (nexpand_children > 0)
{
size_given_to_child = extra_space / nexpand_children;
n_extra_widgets = extra_space % nexpand_children;
}
else
{
size_given_to_child = 0;
}
}
have_baseline = FALSE;
for (i = 0, child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
/* If widget is not visible, skip it. */
if (!_gtk_widget_get_visible (child))
continue;
/* Assign the child's size. */
if (self->homogeneous)
{
child_size = size_given_to_child;
if (n_extra_widgets > 0)
{
child_size++;
n_extra_widgets--;
}
}
else
{
child_size = sizes[i].minimum_size;
if (gtk_widget_compute_expand (child, self->orientation))
{
child_size += size_given_to_child;
if (n_extra_widgets > 0)
{
child_size++;
n_extra_widgets--;
}
}
}
child_minimum_baseline = child_natural_baseline = -1;
/* Assign the child's position. */
gtk_widget_measure (child,
OPPOSITE_ORIENTATION (self->orientation),
child_size,
&child_minimum, &child_natural,
&child_minimum_baseline, &child_natural_baseline);
if (child_minimum_baseline >= 0)
{
have_baseline = TRUE;
computed_minimum_below = MAX (computed_minimum_below, child_minimum - child_minimum_baseline);
computed_natural_below = MAX (computed_natural_below, child_natural - child_natural_baseline);
computed_minimum_above = MAX (computed_minimum_above, child_minimum_baseline);
computed_natural_above = MAX (computed_natural_above, child_natural_baseline);
}
else
{
computed_minimum = MAX (computed_minimum, child_minimum);
computed_natural = MAX (computed_natural, child_natural);
}
i += 1;
}
if (have_baseline)
{
computed_minimum = MAX (computed_minimum, computed_minimum_below + computed_minimum_above);
computed_natural = MAX (computed_natural, computed_natural_below + computed_natural_above);
switch (self->baseline_position)
{
case GTK_BASELINE_POSITION_TOP:
computed_minimum_baseline = computed_minimum_above;
computed_natural_baseline = computed_natural_above;
break;
case GTK_BASELINE_POSITION_CENTER:
computed_minimum_baseline = computed_minimum_above + MAX((computed_minimum - (computed_minimum_above + computed_minimum_below)) / 2, 0);
computed_natural_baseline = computed_natural_above + MAX((computed_natural - (computed_natural_above + computed_natural_below)) / 2, 0);
break;
case GTK_BASELINE_POSITION_BOTTOM:
computed_minimum_baseline = computed_minimum - computed_minimum_below;
computed_natural_baseline = computed_natural - computed_natural_below;
break;
default:
break;
}
}
if (minimum != NULL)
*minimum = computed_minimum;
if (natural != NULL)
*natural = MAX (computed_natural, computed_natural_below + computed_natural_above);
if (min_baseline != NULL)
*min_baseline = computed_minimum_baseline;
if (nat_baseline != NULL)
*nat_baseline = computed_natural_baseline;
}
static void
gtk_box_layout_measure (GtkLayoutManager *layout_manager,
GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *min_baseline,
int *nat_baseline)
{
GtkBoxLayout *self = GTK_BOX_LAYOUT (layout_manager);
if (self->orientation != orientation)
{
gtk_box_layout_compute_opposite_size (self, widget, for_size,
minimum, natural,
min_baseline, nat_baseline);
}
else
{
gtk_box_layout_compute_size (self, widget, for_size,
minimum, natural);
}
}
static void
gtk_box_layout_allocate (GtkLayoutManager *layout_manager,
GtkWidget *widget,
int width,
int height,
int baseline)
{
GtkBoxLayout *self = GTK_BOX_LAYOUT (layout_manager);
GtkWidget *child;
gint nvis_children;
gint nexpand_children;
GtkTextDirection direction;
GtkAllocation child_allocation;
GtkRequestedSize *sizes;
gint child_minimum_baseline, child_natural_baseline;
gint minimum_above, natural_above;
gint minimum_below, natural_below;
gboolean have_baseline;
gint extra_space;
gint children_minimum_size = 0;
gint size_given_to_child;
gint n_extra_widgets = 0; /* Number of widgets that receive 1 extra px */
gint x = 0, y = 0, i;
gint child_size;
gint spacing;
count_expand_children (widget, self->orientation, &nvis_children, &nexpand_children);
/* If there is no visible child, simply return. */
if (nvis_children <= 0)
return;
direction = _gtk_widget_get_direction (widget);
sizes = g_newa (GtkRequestedSize, nvis_children);
spacing = get_spacing (self, _gtk_widget_get_style_context (widget));
if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
extra_space = width - (nvis_children - 1) * spacing;
else
extra_space = height - (nvis_children - 1) * spacing;
have_baseline = FALSE;
minimum_above = natural_above = 0;
minimum_below = natural_below = 0;
/* Retrieve desired size for visible children. */
for (i = 0, child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
if (!_gtk_widget_get_visible (child))
continue;
gtk_widget_measure (child,
self->orientation,
self->orientation == GTK_ORIENTATION_HORIZONTAL ? height : width,
&sizes[i].minimum_size, &sizes[i].natural_size,
NULL, NULL);
children_minimum_size += sizes[i].minimum_size;
sizes[i].data = child;
i++;
}
if (self->homogeneous)
{
/* We still need to run the above loop to populate the minimum sizes for
* children that aren't going to fill.
*/
size_given_to_child = extra_space / nvis_children;
n_extra_widgets = extra_space % nvis_children;
}
else
{
/* Bring children up to size first */
extra_space -= children_minimum_size;
extra_space = MAX (0, extra_space);
extra_space = gtk_distribute_natural_allocation (extra_space, nvis_children, sizes);
/* Calculate space which hasn't distributed yet,
* and is available for expanding children.
*/
if (nexpand_children > 0)
{
size_given_to_child = extra_space / nexpand_children;
n_extra_widgets = extra_space % nexpand_children;
}
else
{
size_given_to_child = 0;
}
}
/* Allocate child sizes. */
for (i = 0, child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
/* If widget is not visible, skip it. */
if (!_gtk_widget_get_visible (child))
continue;
/* Assign the child's size. */
if (self->homogeneous)
{
child_size = size_given_to_child;
if (n_extra_widgets > 0)
{
child_size++;
n_extra_widgets--;
}
}
else
{
child_size = sizes[i].minimum_size;
if (gtk_widget_compute_expand (child, self->orientation))
{
child_size += size_given_to_child;
if (n_extra_widgets > 0)
{
child_size++;
n_extra_widgets--;
}
}
}
sizes[i].natural_size = child_size;
if (self->orientation == GTK_ORIENTATION_HORIZONTAL &&
gtk_widget_get_valign (child) == GTK_ALIGN_BASELINE)
{
int child_allocation_width;
int child_minimum_height, child_natural_height;
child_allocation_width = child_size;
child_minimum_baseline = -1;
child_natural_baseline = -1;
gtk_widget_measure (child, GTK_ORIENTATION_VERTICAL,
child_allocation_width,
&child_minimum_height, &child_natural_height,
&child_minimum_baseline, &child_natural_baseline);
if (child_minimum_baseline >= 0)
{
have_baseline = TRUE;
minimum_below = MAX (minimum_below, child_minimum_height - child_minimum_baseline);
natural_below = MAX (natural_below, child_natural_height - child_natural_baseline);
minimum_above = MAX (minimum_above, child_minimum_baseline);
natural_above = MAX (natural_above, child_natural_baseline);
}
}
i++;
}
if (self->orientation == GTK_ORIENTATION_VERTICAL)
baseline = -1;
/* we only calculate our own baseline if we don't get one passed from the parent
* and any of the child widgets explicitly request one */
if (baseline == -1 && have_baseline)
{
/* TODO: This is purely based on the minimum baseline, when things fit we should
use the natural one? */
switch (self->baseline_position)
{
case GTK_BASELINE_POSITION_TOP:
baseline = minimum_above;
break;
case GTK_BASELINE_POSITION_CENTER:
baseline = minimum_above + (height - (minimum_above + minimum_below)) / 2;
break;
case GTK_BASELINE_POSITION_BOTTOM:
baseline = height - minimum_below;
break;
default:
break;
}
}
/* Allocate child positions. */
if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
{
child_allocation.y = 0;
child_allocation.height = height;
x = 0;
}
else
{
child_allocation.x = 0;
child_allocation.width = width;
y = 0;
}
for (i = 0, child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
/* If widget is not visible, skip it. */
if (!_gtk_widget_get_visible (child))
continue;
child_size = sizes[i].natural_size;
/* Assign the child's position. */
if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
{
child_allocation.width = child_size;
child_allocation.x = x;
x += child_size + spacing;
if (direction == GTK_TEXT_DIR_RTL)
child_allocation.x = width - child_allocation.x - child_allocation.width;
}
else /* (self->orientation == GTK_ORIENTATION_VERTICAL) */
{
child_allocation.height = child_size;
child_allocation.y = y;
y += child_size + spacing;
}
gtk_widget_size_allocate (child, &child_allocation, baseline);
i++;
}
}
static void
gtk_box_layout_class_init (GtkBoxLayoutClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GtkLayoutManagerClass *layout_manager_class = GTK_LAYOUT_MANAGER_CLASS (klass);
gobject_class->set_property = gtk_box_layout_set_property;
gobject_class->get_property = gtk_box_layout_get_property;
layout_manager_class->get_request_mode = gtk_box_layout_get_request_mode;
layout_manager_class->measure = gtk_box_layout_measure;
layout_manager_class->allocate = gtk_box_layout_allocate;
/**
* GtkBoxLayout:homogeneous:
*
* Whether the box layout should distribute the available space
* homogeneously among the children of the widget using it as a
* layout manager.
*/
box_layout_props[PROP_HOMOGENEOUS] =
g_param_spec_boolean ("homogeneous",
P_("Homogeneous"),
P_("Distribute space homogeneously"),
FALSE,
GTK_PARAM_READWRITE |
G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkBoxLayout:spacing:
*
* The space between each child of the widget using the box
* layout as its layout manager.
*/
box_layout_props[PROP_SPACING] =
g_param_spec_int ("spacing",
P_("Spacing"),
P_("Spacing between widgets"),
0, G_MAXINT, 0,
GTK_PARAM_READWRITE |
G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkBoxLayout:baseline-position:
*
* The position of the allocated baseline within the extra space
* allocated to each child of the widget using a box layout
* manager.
*
* This property is only relevant for horizontal layouts containing
* at least one child with a baseline alignment.
*/
box_layout_props[PROP_BASELINE_POSITION] =
g_param_spec_enum ("baseline-position",
P_("Baseline position"),
P_("The position of the baseline aligned widgets if extra space is available"),
GTK_TYPE_BASELINE_POSITION,
GTK_BASELINE_POSITION_CENTER,
GTK_PARAM_READWRITE |
G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (gobject_class, N_PROPS, box_layout_props);
g_object_class_override_property (gobject_class, PROP_ORIENTATION, "orientation");
}
static void
gtk_box_layout_init (GtkBoxLayout *self)
{
self->homogeneous = FALSE;
self->spacing = 0;
self->orientation = GTK_ORIENTATION_HORIZONTAL;
self->baseline_position = GTK_BASELINE_POSITION_CENTER;
}
GtkLayoutManager *
gtk_box_layout_new (GtkOrientation orientation)
{
return g_object_new (GTK_TYPE_BOX_LAYOUT,
"orientation", orientation,
NULL);
}
void
gtk_box_layout_set_homogeneous (GtkBoxLayout *box_layout,
gboolean homogeneous)
{
g_return_if_fail (GTK_IS_BOX_LAYOUT (box_layout));
homogeneous = !!homogeneous;
if (box_layout->homogeneous == homogeneous)
return;
box_layout->homogeneous = homogeneous;
gtk_layout_manager_layout_changed (GTK_LAYOUT_MANAGER (box_layout));
g_object_notify_by_pspec (G_OBJECT (box_layout), box_layout_props[PROP_HOMOGENEOUS]);
}
gboolean
gtk_box_layout_get_homogeneous (GtkBoxLayout *box_layout)
{
g_return_val_if_fail (GTK_IS_BOX_LAYOUT (box_layout), FALSE);
return box_layout->homogeneous;
}
void
gtk_box_layout_set_spacing (GtkBoxLayout *box_layout,
guint spacing)
{
g_return_if_fail (GTK_IS_BOX_LAYOUT (box_layout));
if (box_layout->spacing == spacing)
return;
box_layout->spacing = spacing;
gtk_layout_manager_layout_changed (GTK_LAYOUT_MANAGER (box_layout));
g_object_notify_by_pspec (G_OBJECT (box_layout), box_layout_props[PROP_SPACING]);
}
guint
gtk_box_layout_get_spacing (GtkBoxLayout *box_layout)
{
g_return_val_if_fail (GTK_IS_BOX_LAYOUT (box_layout), 0);
return box_layout->spacing;
}
/**
* gtk_box_layout_set_baseline_position:
* @box_layout: a #GtkBoxLayout
* @position: a #GtkBaselinePosition
*
* Sets the baseline position of a box layout.
*
* The baseline position affects only horizontal boxes with at least one
* baseline aligned child. If there is more vertical space available than
* requested, and the baseline is not allocated by the parent then the
* given @position is used to allocate the baseline within the extra
* space available.
*/
void
gtk_box_layout_set_baseline_position (GtkBoxLayout *box_layout,
GtkBaselinePosition position)
{
g_return_if_fail (GTK_IS_BOX_LAYOUT (box_layout));
if (box_layout->baseline_position != position)
{
box_layout->baseline_position = position;
g_object_notify_by_pspec (G_OBJECT (box_layout), box_layout_props[PROP_BASELINE_POSITION]);
gtk_layout_manager_layout_changed (GTK_LAYOUT_MANAGER (box_layout));
}
}
/**
* gtk_box_layout_get_baseline_position:
* @box_layout: a #GtkBoxLayout
*
* Gets the value set by gtk_box_layout_set_baseline_position().
*
* Returns: the baseline position
*/
GtkBaselinePosition
gtk_box_layout_get_baseline_position (GtkBoxLayout *box_layout)
{
g_return_val_if_fail (GTK_IS_BOX_LAYOUT (box_layout), GTK_BASELINE_POSITION_CENTER);
return box_layout->baseline_position;
}
+54
View File
@@ -0,0 +1,54 @@
/* gtkboxlayout.h: Box layout manager
*
* Copyright 2019 GNOME Foundation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkenums.h>
#include <gtk/gtklayoutmanager.h>
G_BEGIN_DECLS
#define GTK_TYPE_BOX_LAYOUT (gtk_box_layout_get_type())
GDK_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (GtkBoxLayout, gtk_box_layout, GTK, BOX_LAYOUT, GtkLayoutManager)
GDK_AVAILABLE_IN_ALL
GtkLayoutManager * gtk_box_layout_new (GtkOrientation orientation);
GDK_AVAILABLE_IN_ALL
void gtk_box_layout_set_homogeneous (GtkBoxLayout *box_layout,
gboolean homogeneous);
GDK_AVAILABLE_IN_ALL
gboolean gtk_box_layout_get_homogeneous (GtkBoxLayout *box_layout);
GDK_AVAILABLE_IN_ALL
void gtk_box_layout_set_spacing (GtkBoxLayout *box_layout,
guint spacing);
GDK_AVAILABLE_IN_ALL
guint gtk_box_layout_get_spacing (GtkBoxLayout *box_layout);
GDK_AVAILABLE_IN_ALL
void gtk_box_layout_set_baseline_position (GtkBoxLayout *box_layout,
GtkBaselinePosition position);
GDK_AVAILABLE_IN_ALL
GtkBaselinePosition gtk_box_layout_get_baseline_position (GtkBoxLayout *box_layout);
G_END_DECLS
+1
View File
@@ -66,6 +66,7 @@
#include "gtkmain.h"
#include "gtkmarshalers.h"
#include "gtkprivate.h"
#include "gtkstylecontext.h"
#include "gtktypebuiltins.h"
#include "a11y/gtkbuttonaccessible.h"
+4
View File
@@ -295,6 +295,8 @@ static gboolean gtk_calendar_key_controller_key_pressed (GtkEventControllerKey *
GdkModifierType state,
GtkWidget *widget);
static void gtk_calendar_key_controller_focus (GtkEventControllerKey *controller,
GdkCrossingMode mode,
GdkNotifyType detail,
GtkWidget *widget);
static void gtk_calendar_grab_notify (GtkWidget *widget,
gboolean was_grabbed);
@@ -2854,6 +2856,8 @@ gtk_calendar_key_controller_key_pressed (GtkEventControllerKey *controller,
static void
gtk_calendar_key_controller_focus (GtkEventControllerKey *key,
GdkCrossingMode mode,
GdkNotifyType detail,
GtkWidget *widget)
{
GtkCalendar *calendar = GTK_CALENDAR (widget);
+1
View File
@@ -352,6 +352,7 @@
#include "gtkmarshalers.h"
#include "gtkprivate.h"
#include "gtksnapshot.h"
#include "gtkstylecontext.h"
#include <gobject/gvaluecollector.h>
+1
View File
@@ -23,6 +23,7 @@
#include "gtkmarshalers.h"
#include "gtkprivate.h"
#include "gtksnapshot.h"
#include "gtkstylecontext.h"
#include "gtktreeprivate.h"
#include "gtktypebuiltins.h"
+1
View File
@@ -31,6 +31,7 @@
#include "gtkorientable.h"
#include "gtkprivate.h"
#include "gtksnapshot.h"
#include "gtkstylecontext.h"
/**
+1
View File
@@ -26,6 +26,7 @@
#include "gtkprivate.h"
#include "gtksizerequest.h"
#include "gtksnapshot.h"
#include "gtkstylecontext.h"
#include "gtktreeprivate.h"
#include "a11y/gtktextcellaccessible.h"
+1
View File
@@ -43,6 +43,7 @@
#include "gtkmarshalers.h"
#include "gtkprivate.h"
#include "gtksnapshot.h"
#include "gtkstylecontext.h"
/**
+1
View File
@@ -29,6 +29,7 @@
#include "gtkprivate.h"
#include "gtkintl.h"
#include "gtksizegroup.h"
#include "gtkstylecontext.h"
#include <math.h>
+2 -2
View File
@@ -36,6 +36,7 @@
#include "gtkspinbutton.h"
#include "gtkstylecontext.h"
#include "gtkeventcontrollerkey.h"
#include "gtkroot.h"
#include <math.h>
@@ -224,7 +225,7 @@ popup_edit (GtkWidget *widget,
{
dismiss_current_popup (editor);
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (editor));
g_set_object (&editor->priv->popdown_focus, gtk_window_get_focus (GTK_WINDOW (toplevel)));
g_set_object (&editor->priv->popdown_focus, gtk_root_get_focus (GTK_ROOT (toplevel)));
editor->priv->current_popup = popup;
editor->priv->popup_position = position;
gtk_widget_show (popup);
@@ -355,7 +356,6 @@ color_picked (GObject *source,
color = gtk_color_picker_pick_finish (picker, res, &error);
if (color == NULL)
{
g_warning ("Picking color failed: %s", error->message);
g_error_free (error);
}
else
+14 -21
View File
@@ -35,7 +35,6 @@
#include "gtkmodelbutton.h"
#include "gtkpopover.h"
#include "gtkprivate.h"
#include "gtkroundedboxprivate.h"
#include "gtksnapshot.h"
#include "gtkstylecontextprivate.h"
#include "gtkwidgetprivate.h"
@@ -43,8 +42,6 @@
#include "a11y/gtkcolorswatchaccessibleprivate.h"
#include "gsk/gskroundedrectprivate.h"
/*
* GtkColorSwatch has two CSS nodes, the main one named colorswatch
* and a subnode named overlay. The main node gets the .light or .dark
@@ -97,30 +94,21 @@ swatch_snapshot (GtkWidget *widget,
{
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
GtkColorSwatchPrivate *priv = gtk_color_swatch_get_instance_private (swatch);
GtkStyleContext *context;
context = gtk_widget_get_style_context (widget);
if (priv->has_color)
{
cairo_pattern_t *pattern;
cairo_matrix_t matrix;
GskRoundedRect content_box;
gtk_rounded_boxes_init_for_style (NULL,
NULL,
&content_box,
gtk_style_context_lookup_style (context),
0, 0,
gtk_widget_get_width (widget),
gtk_widget_get_height (widget));
gtk_snapshot_push_rounded_clip (snapshot, &content_box);
if (priv->use_alpha && !gdk_rgba_is_opaque (&priv->color))
{
cairo_t *cr;
cr = gtk_snapshot_append_cairo (snapshot, &content_box.bounds);
cr = gtk_snapshot_append_cairo (snapshot,
&GRAPHENE_RECT_INIT (
0, 0,
gtk_widget_get_width (widget),
gtk_widget_get_height (widget)));
cairo_set_source_rgb (cr, 0.33, 0.33, 0.33);
cairo_paint (cr);
@@ -136,7 +124,10 @@ swatch_snapshot (GtkWidget *widget,
gtk_snapshot_append_color (snapshot,
&priv->color,
&content_box.bounds);
&GRAPHENE_RECT_INIT (
0, 0,
gtk_widget_get_width (widget),
gtk_widget_get_height (widget)));
}
else
{
@@ -146,10 +137,11 @@ swatch_snapshot (GtkWidget *widget,
gtk_snapshot_append_color (snapshot,
&color,
&content_box.bounds);
&GRAPHENE_RECT_INIT (
0, 0,
gtk_widget_get_width (widget),
gtk_widget_get_height (widget)));
}
gtk_snapshot_pop (snapshot);
}
gtk_widget_snapshot_child (widget, priv->overlay_widget, snapshot);
@@ -576,6 +568,7 @@ gtk_color_swatch_init (GtkColorSwatch *swatch)
gtk_widget_set_can_focus (GTK_WIDGET (swatch), TRUE);
gtk_widget_set_has_surface (GTK_WIDGET (swatch), FALSE);
gtk_widget_set_overflow (GTK_WIDGET (swatch), GTK_OVERFLOW_HIDDEN);
gesture = gtk_gesture_long_press_new ();
gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (gesture),
+1
View File
@@ -19,6 +19,7 @@
#define __GTK_CSS_BOXES_PRIVATE_H__
#include "gtkcsstypesprivate.h"
#include "gtktypes.h"
G_BEGIN_DECLS
+2 -128
View File
@@ -23,8 +23,6 @@
#include "gtkcssstylepropertyprivate.h"
#include "gtkhslaprivate.h"
#include "gtkstylepropertyprivate.h"
#include "gtkwin32drawprivate.h"
#include "gtkwin32themeprivate.h"
#include "gtkprivate.h"
@@ -34,7 +32,6 @@ typedef enum {
COLOR_TYPE_SHADE,
COLOR_TYPE_ALPHA,
COLOR_TYPE_MIX,
COLOR_TYPE_WIN32,
COLOR_TYPE_CURRENT_COLOR
} ColorType;
@@ -60,12 +57,6 @@ struct _GtkCssValue
GtkCssValue *color2;
gdouble factor;
} mix;
struct
{
GtkWin32Theme *theme;
gint id;
} win32;
} sym_col;
};
@@ -90,9 +81,6 @@ gtk_css_value_color_free (GtkCssValue *color)
_gtk_css_value_unref (color->sym_col.mix.color1);
_gtk_css_value_unref (color->sym_col.mix.color2);
break;
case COLOR_TYPE_WIN32:
gtk_win32_theme_unref (color->sym_col.win32.theme);
break;
case COLOR_TYPE_LITERAL:
case COLOR_TYPE_CURRENT_COLOR:
default:
@@ -240,18 +228,6 @@ _gtk_css_color_value_resolve (GtkCssValue *color,
value =_gtk_css_rgba_value_new_from_rgba (&res);
}
break;
case COLOR_TYPE_WIN32:
{
GdkRGBA res;
gtk_win32_theme_get_color (color->sym_col.win32.theme,
color->sym_col.win32.id,
&res);
value = _gtk_css_rgba_value_new_from_rgba (&res);
}
break;
case COLOR_TYPE_CURRENT_COLOR:
if (current)
@@ -350,9 +326,6 @@ gtk_css_value_color_equal (const GtkCssValue *value1,
value2->sym_col.mix.color1) &&
_gtk_css_value_equal (value1->sym_col.mix.color2,
value2->sym_col.mix.color2);
case COLOR_TYPE_WIN32:
return gtk_win32_theme_equal (value1->sym_col.win32.theme, value2->sym_col.win32.theme) &&
value1->sym_col.win32.id == value2->sym_col.win32.id;
case COLOR_TYPE_CURRENT_COLOR:
return TRUE;
default:
@@ -421,20 +394,6 @@ gtk_css_value_color_print (const GtkCssValue *value,
g_string_append (string, ")");
}
break;
case COLOR_TYPE_WIN32:
{
const char *name;
g_string_append (string, GTK_WIN32_THEME_SYMBOLIC_COLOR_NAME"(");
gtk_win32_theme_print (value->sym_col.win32.theme, string);
g_string_append (string, ", ");
name = gtk_win32_get_sys_color_name_for_id (value->sym_col.win32.id);
if (name)
g_string_append (string, name);
else
g_string_append_printf (string, "%d", value->sym_col.win32.id);
g_string_append (string, ")");
}
break;
case COLOR_TYPE_CURRENT_COLOR:
g_string_append (string, "currentColor");
break;
@@ -543,38 +502,6 @@ _gtk_css_color_value_new_mix (GtkCssValue *color1,
return value;
}
static GtkCssValue *
gtk_css_color_value_new_win32_for_theme (GtkWin32Theme *theme,
gint id)
{
GtkCssValue *value;
gtk_internal_return_val_if_fail (theme != NULL, NULL);
value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_COLOR);
value->type = COLOR_TYPE_WIN32;
value->sym_col.win32.theme = gtk_win32_theme_ref (theme);
value->sym_col.win32.id = id;
return value;
}
GtkCssValue *
_gtk_css_color_value_new_win32 (const gchar *theme_class,
gint id)
{
GtkWin32Theme *theme;
GtkCssValue *value;
gtk_internal_return_val_if_fail (theme_class != NULL, NULL);
theme = gtk_win32_theme_lookup (theme_class);
value = gtk_css_color_value_new_win32_for_theme (theme, id);
gtk_win32_theme_unref (theme);
return value;
}
GtkCssValue *
_gtk_css_color_value_new_current_color (void)
{
@@ -590,54 +517,9 @@ typedef enum {
COLOR_DARKER,
COLOR_SHADE,
COLOR_ALPHA,
COLOR_MIX,
COLOR_WIN32
COLOR_MIX
} ColorParseType;
static GtkCssValue *
gtk_css_color_parse_win32 (GtkCssParser *parser)
{
GtkCssValue *color;
GtkWin32Theme *theme;
char *name;
int id;
theme = gtk_win32_theme_parse (parser);
if (theme == NULL)
return NULL;
if (! _gtk_css_parser_try (parser, ",", TRUE))
{
gtk_win32_theme_unref (theme);
_gtk_css_parser_error (parser,
"Expected ','");
return NULL;
}
name = _gtk_css_parser_try_ident (parser, TRUE);
if (name)
{
id = gtk_win32_get_sys_color_id_for_name (name);
if (id == -1)
{
_gtk_css_parser_error (parser, "'%s' is not a win32 color name.", name);
g_free (name);
return NULL;
}
g_free (name);
}
else if (!_gtk_css_parser_try_int (parser, &id))
{
gtk_win32_theme_unref (theme);
_gtk_css_parser_error (parser, "Expected a valid integer value");
return NULL;
}
color = gtk_css_color_value_new_win32_for_theme (theme, id);
gtk_win32_theme_unref (theme);
return color;
}
static GtkCssValue *
_gtk_css_color_value_parse_function (GtkCssParser *parser,
ColorParseType color)
@@ -704,12 +586,6 @@ _gtk_css_color_value_parse_function (GtkCssParser *parser,
value = _gtk_css_color_value_new_literal (&rgba);
}
else if (color == COLOR_WIN32)
{
value = gtk_css_color_parse_win32 (parser);
if (value == NULL)
return NULL;
}
else
{
child1 = _gtk_css_color_value_parse (parser);
@@ -775,7 +651,6 @@ _gtk_css_color_value_parse_function (GtkCssParser *parser,
break;
case COLOR_RGB:
case COLOR_RGBA:
case COLOR_WIN32:
default:
g_assert_not_reached ();
value = NULL;
@@ -802,8 +677,7 @@ _gtk_css_color_value_parse (GtkCssParser *parser)
GtkCssValue *value;
GdkRGBA rgba;
guint color;
const char *names[] = {"rgba", "rgb", "lighter", "darker", "shade", "alpha", "mix",
GTK_WIN32_THEME_SYMBOLIC_COLOR_NAME};
const char *names[] = {"rgba", "rgb", "lighter", "darker", "shade", "alpha", "mix"};
char *name;
if (_gtk_css_parser_try (parser, "currentColor", TRUE))
-2
View File
@@ -37,8 +37,6 @@ GtkCssValue * _gtk_css_color_value_new_alpha (GtkCssValue *color,
GtkCssValue * _gtk_css_color_value_new_mix (GtkCssValue *color1,
GtkCssValue *color2,
gdouble factor);
GtkCssValue * _gtk_css_color_value_new_win32 (const gchar *theme_class,
gint id);
GtkCssValue * _gtk_css_color_value_new_current_color (void);
GtkCssValue * _gtk_css_color_value_parse (GtkCssParser *parser);
+7 -2
View File
@@ -254,7 +254,7 @@ gtk_css_ease_value_parse_cubic_bezier (GtkCssParser *parser)
static GtkCssValue *
gtk_css_ease_value_parse_steps (GtkCssParser *parser)
{
guint n_steps;
int n_steps;
gboolean start;
if (!_gtk_css_parser_try (parser, "(", TRUE))
@@ -263,11 +263,16 @@ gtk_css_ease_value_parse_steps (GtkCssParser *parser)
return NULL;
}
if (!_gtk_css_parser_try_uint (parser, &n_steps))
if (!_gtk_css_parser_try_int (parser, &n_steps))
{
_gtk_css_parser_error (parser, "Expected number of steps");
return NULL;
}
else if (n_steps < 1)
{
_gtk_css_parser_error (parser, "Number of steps must be > 0");
return NULL;
}
if (_gtk_css_parser_try (parser, ",", TRUE))
{
-2
View File
@@ -33,7 +33,6 @@
#include "gtk/gtkcssimagescaledprivate.h"
#include "gtk/gtkcssimagerecolorprivate.h"
#include "gtk/gtkcssimagefallbackprivate.h"
#include "gtk/gtkcssimagewin32private.h"
G_DEFINE_ABSTRACT_TYPE (GtkCssImage, _gtk_css_image, G_TYPE_OBJECT)
@@ -499,7 +498,6 @@ gtk_css_image_get_parser_type (GtkCssParser *parser)
{ "-gtk-icontheme", _gtk_css_image_icon_theme_get_type },
{ "-gtk-scaled", _gtk_css_image_scaled_get_type },
{ "-gtk-recolor", _gtk_css_image_recolor_get_type },
{ "-gtk-win32-theme-part", _gtk_css_image_win32_get_type },
{ "linear-gradient", _gtk_css_image_linear_get_type },
{ "repeating-linear-gradient", _gtk_css_image_linear_get_type },
{ "radial-gradient", _gtk_css_image_radial_get_type },
+1
View File
@@ -26,6 +26,7 @@
#include "gtk/gtkcssparserprivate.h"
#include "gtk/gtkcsstypesprivate.h"
#include "gtk/gtksnapshot.h"
#include "gtk/gtkstyleprovider.h"
G_BEGIN_DECLS
-263
View File
@@ -1,263 +0,0 @@
/*
* Copyright © 2011 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkcssimagewin32private.h"
#include "gtkcssprovider.h"
G_DEFINE_TYPE (GtkCssImageWin32, _gtk_css_image_win32, GTK_TYPE_CSS_IMAGE)
static void
gtk_css_image_win32_snapshot (GtkCssImage *image,
GtkSnapshot *snapshot,
double width,
double height)
{
GtkCssImageWin32 *wimage = GTK_CSS_IMAGE_WIN32 (image);
cairo_surface_t *surface;
int dx, dy;
cairo_t *cr;
cr = gtk_snapshot_append_cairo (snapshot,
&GRAPHENE_RECT_INIT (0, 0, width, height));
surface = gtk_win32_theme_create_surface (wimage->theme, wimage->part, wimage->state, wimage->margins,
width, height, &dx, &dy);
if (wimage->state2 >= 0)
{
cairo_surface_t *surface2;
cairo_t *cr2;
int dx2, dy2;
surface2 = gtk_win32_theme_create_surface (wimage->theme, wimage->part2, wimage->state2, wimage->margins,
width, height, &dx2, &dy2);
cr2 = cairo_create (surface);
cairo_set_source_surface (cr2, surface2, dx2 - dx, dy2-dy);
cairo_paint_with_alpha (cr2, wimage->over_alpha);
cairo_destroy (cr2);
cairo_surface_destroy (surface2);
}
cairo_set_source_surface (cr, surface, dx, dy);
cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_NONE);
cairo_rectangle (cr, 0, 0, width, height);
cairo_fill (cr);
cairo_surface_destroy (surface);
cairo_destroy (cr);
}
static gboolean
gtk_css_image_win32_parse (GtkCssImage *image,
GtkCssParser *parser)
{
GtkCssImageWin32 *wimage = GTK_CSS_IMAGE_WIN32 (image);
if (!_gtk_css_parser_try (parser, "-gtk-win32-theme-part", TRUE))
{
_gtk_css_parser_error (parser, "'-gtk-win32-theme-part'");
return FALSE;
}
if (!_gtk_css_parser_try (parser, "(", TRUE))
{
_gtk_css_parser_error (parser,
"Expected '(' after '-gtk-win32-theme-part'");
return FALSE;
}
wimage->theme = gtk_win32_theme_parse (parser);
if (wimage->theme == NULL)
return FALSE;
if (! _gtk_css_parser_try (parser, ",", TRUE))
{
_gtk_css_parser_error (parser, "Expected ','");
return FALSE;
}
if (!_gtk_css_parser_try_int (parser, &wimage->part))
{
_gtk_css_parser_error (parser, "Expected a valid integer value");
return FALSE;
}
if (! _gtk_css_parser_try (parser, ",", TRUE))
{
_gtk_css_parser_error (parser, "Expected ','");
return FALSE;
}
if (!_gtk_css_parser_try_int (parser, &wimage->state))
{
_gtk_css_parser_error (parser, "Expected a valid integer value");
return FALSE;
}
while ( _gtk_css_parser_try (parser, ",", TRUE))
{
if ( _gtk_css_parser_try (parser, "over", TRUE))
{
if (!_gtk_css_parser_try (parser, "(", TRUE))
{
_gtk_css_parser_error (parser,
"Expected '(' after 'over'");
return FALSE;
}
if (!_gtk_css_parser_try_int (parser, &wimage->part2))
{
_gtk_css_parser_error (parser, "Expected a valid integer value");
return FALSE;
}
if (! _gtk_css_parser_try (parser, ",", TRUE))
{
_gtk_css_parser_error (parser, "Expected ','");
return FALSE;
}
if (!_gtk_css_parser_try_int (parser, &wimage->state2))
{
_gtk_css_parser_error (parser, "Expected a valid integer value");
return FALSE;
}
if ( _gtk_css_parser_try (parser, ",", TRUE))
{
if (!_gtk_css_parser_try_double (parser, &wimage->over_alpha))
{
_gtk_css_parser_error (parser, "Expected a valid double value");
return FALSE;
}
}
if (!_gtk_css_parser_try (parser, ")", TRUE))
{
_gtk_css_parser_error (parser,
"Expected ')' at end of 'over'");
return FALSE;
}
}
else if ( _gtk_css_parser_try (parser, "margins", TRUE))
{
guint i;
if (!_gtk_css_parser_try (parser, "(", TRUE))
{
_gtk_css_parser_error (parser,
"Expected '(' after 'margins'");
return FALSE;
}
for (i = 0; i < 4; i++)
{
if (!_gtk_css_parser_try_int (parser, &wimage->margins[i]))
break;
}
if (i == 0)
{
_gtk_css_parser_error (parser, "Expected valid margins");
return FALSE;
}
if (i == 1)
wimage->margins[1] = wimage->margins[0];
if (i <= 2)
wimage->margins[2] = wimage->margins[1];
if (i <= 3)
wimage->margins[3] = wimage->margins[2];
if (!_gtk_css_parser_try (parser, ")", TRUE))
{
_gtk_css_parser_error (parser,
"Expected ')' at end of 'margins'");
return FALSE;
}
}
else
{
_gtk_css_parser_error (parser,
"Expected identifier");
return FALSE;
}
}
if (!_gtk_css_parser_try (parser, ")", TRUE))
{
_gtk_css_parser_error (parser,
"Expected ')'");
return FALSE;
}
return TRUE;
}
static void
gtk_css_image_win32_print (GtkCssImage *image,
GString *string)
{
GtkCssImageWin32 *wimage = GTK_CSS_IMAGE_WIN32 (image);
g_string_append (string, "-gtk-win32-theme-part(");
gtk_win32_theme_print (wimage->theme, string);
g_string_append_printf (string, ", %d, %d)", wimage->part, wimage->state);
}
static void
gtk_css_image_win32_finalize (GObject *object)
{
GtkCssImageWin32 *wimage = GTK_CSS_IMAGE_WIN32 (object);
if (wimage->theme)
gtk_win32_theme_unref (wimage->theme);
G_OBJECT_CLASS (_gtk_css_image_win32_parent_class)->finalize (object);
}
static void
_gtk_css_image_win32_class_init (GtkCssImageWin32Class *klass)
{
GtkCssImageClass *image_class = GTK_CSS_IMAGE_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_css_image_win32_finalize;
image_class->snapshot = gtk_css_image_win32_snapshot;
image_class->parse = gtk_css_image_win32_parse;
image_class->print = gtk_css_image_win32_print;
}
static void
_gtk_css_image_win32_init (GtkCssImageWin32 *wimage)
{
wimage->over_alpha = 1.0;
wimage->part2 = -1;
wimage->state2 = -1;
}
-64
View File
@@ -1,64 +0,0 @@
/*
* Copyright © 2011 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GTK_CSS_IMAGE_WIN32_PRIVATE_H__
#define __GTK_CSS_IMAGE_WIN32_PRIVATE_H__
#include "gtk/gtkcssimageprivate.h"
#include "gtk/gtkwin32themeprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_CSS_IMAGE_WIN32 (_gtk_css_image_win32_get_type ())
#define GTK_CSS_IMAGE_WIN32(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_IMAGE_WIN32, GtkCssImageWin32))
#define GTK_CSS_IMAGE_WIN32_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_IMAGE_WIN32, GtkCssImageWin32Class))
#define GTK_IS_CSS_IMAGE_WIN32(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_IMAGE_WIN32))
#define GTK_IS_CSS_IMAGE_WIN32_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_IMAGE_WIN32))
#define GTK_CSS_IMAGE_WIN32_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_IMAGE_WIN32, GtkCssImageWin32Class))
typedef struct _GtkCssImageWin32 GtkCssImageWin32;
typedef struct _GtkCssImageWin32Class GtkCssImageWin32Class;
struct _GtkCssImageWin32
{
GtkCssImage parent;
int part;
int state;
double over_alpha;
int part2;
int state2;
gint margins[4];
GtkWin32Theme *theme;
};
struct _GtkCssImageWin32Class
{
GtkCssImageClass parent_class;
};
GType _gtk_css_image_win32_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __GTK_CSS_IMAGE_WIN32_PRIVATE_H__ */
+1
View File
@@ -23,6 +23,7 @@
#include "gtkcssstylechangeprivate.h"
#include "gtkbitmaskprivate.h"
#include "gtkcsstypesprivate.h"
#include "gtkstylecontext.h"
G_BEGIN_DECLS
+1 -17
View File
@@ -21,7 +21,6 @@
#include "gtkcsscalcvalueprivate.h"
#include "gtkcssdimensionvalueprivate.h"
#include "gtkcsswin32sizevalueprivate.h"
#include "gtkprivate.h"
struct _GtkCssValue {
@@ -131,14 +130,7 @@ gboolean
gtk_css_number_value_can_parse (GtkCssParser *parser)
{
return _gtk_css_parser_has_number (parser)
|| _gtk_css_parser_has_prefix (parser, "calc")
|| _gtk_css_parser_has_prefix (parser, "-gtk-win32-size")
|| _gtk_css_parser_has_prefix (parser, "-gtk-win32-part-width")
|| _gtk_css_parser_has_prefix (parser, "-gtk-win32-part-height")
|| _gtk_css_parser_has_prefix (parser, "-gtk-win32-part-border-top")
|| _gtk_css_parser_has_prefix (parser, "-gtk-win32-part-border-left")
|| _gtk_css_parser_has_prefix (parser, "-gtk-win32-part-border-bottom")
|| _gtk_css_parser_has_prefix (parser, "-gtk-win32-part-border-right");
|| _gtk_css_parser_has_prefix (parser, "calc");
}
GtkCssValue *
@@ -147,14 +139,6 @@ _gtk_css_number_value_parse (GtkCssParser *parser,
{
if (_gtk_css_parser_has_prefix (parser, "calc"))
return gtk_css_calc_value_parse (parser, flags);
if (_gtk_css_parser_has_prefix (parser, "-gtk-win32-size") ||
_gtk_css_parser_has_prefix (parser, "-gtk-win32-part-width") ||
_gtk_css_parser_has_prefix (parser, "-gtk-win32-part-height") ||
_gtk_css_parser_has_prefix (parser, "-gtk-win32-part-border-top") ||
_gtk_css_parser_has_prefix (parser, "-gtk-win32-part-border-left") ||
_gtk_css_parser_has_prefix (parser, "-gtk-win32-part-border-bottom") ||
_gtk_css_parser_has_prefix (parser, "-gtk-win32-part-border-right"))
return gtk_css_win32_size_value_parse (parser, flags);
return gtk_css_dimension_value_parse (parser, flags);
}
+7 -143
View File
@@ -202,23 +202,6 @@ _gtk_css_parser_error (GtkCssParser *parser,
_gtk_css_parser_take_error (parser, error);
}
void
_gtk_css_parser_error_full (GtkCssParser *parser,
GtkCssProviderError code,
const char *format,
...)
{
GError *error;
va_list args;
va_start (args, format);
error = g_error_new_valist (GTK_CSS_PROVIDER_ERROR,
code, format, args);
va_end (args);
_gtk_css_parser_take_error (parser, error);
}
static gboolean
gtk_css_parser_new_line (GtkCssParser *parser)
{
@@ -298,14 +281,17 @@ _gtk_css_parser_skip_whitespace (GtkCssParser *parser)
}
gboolean
gtk_css_parser_try_len (GtkCssParser *parser,
const char *string,
gsize string_len,
gboolean skip_whitespace)
_gtk_css_parser_try (GtkCssParser *parser,
const char *string,
gboolean skip_whitespace)
{
gsize string_len;
g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
g_return_val_if_fail (string != NULL, FALSE);
string_len = strlen (string);
if (g_ascii_strncasecmp (parser->data, string, string_len) != 0)
return FALSE;
@@ -579,33 +565,6 @@ _gtk_css_parser_try_int (GtkCssParser *parser,
return TRUE;
}
gboolean
_gtk_css_parser_try_uint (GtkCssParser *parser,
guint *value)
{
guint64 result;
char *end;
g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
g_return_val_if_fail (value != NULL, FALSE);
errno = 0;
result = g_ascii_strtoull (parser->data, &end, 10);
if (errno)
return FALSE;
if (result > G_MAXUINT)
return FALSE;
if (parser->data == end)
return FALSE;
parser->data = end;
*value = result;
_gtk_css_parser_skip_whitespace (parser);
return TRUE;
}
gboolean
_gtk_css_parser_try_double (GtkCssParser *parser,
gdouble *value)
@@ -758,71 +717,6 @@ gtk_css_dimension_value_parse (GtkCssParser *parser,
return gtk_css_dimension_value_new (value, unit);
}
/* XXX: we should introduce GtkCssLenght that deals with
* different kind of units */
gboolean
_gtk_css_parser_try_length (GtkCssParser *parser,
int *value)
{
if (!_gtk_css_parser_try_int (parser, value))
return FALSE;
/* FIXME: _try_uint skips spaces while the
* spec forbids them
*/
_gtk_css_parser_try (parser, "px", TRUE);
return TRUE;
}
gboolean
_gtk_css_parser_try_enum (GtkCssParser *parser,
GType enum_type,
int *value)
{
GEnumClass *enum_class;
gboolean result;
const char *start;
char *str;
g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
g_return_val_if_fail (value != NULL, FALSE);
result = FALSE;
enum_class = g_type_class_ref (enum_type);
start = parser->data;
str = _gtk_css_parser_try_ident (parser, TRUE);
if (str == NULL)
return FALSE;
if (enum_class->n_values)
{
GEnumValue *enum_value;
for (enum_value = enum_class->values; enum_value->value_name; enum_value++)
{
if (enum_value->value_nick &&
g_ascii_strcasecmp (str, enum_value->value_nick) == 0)
{
*value = enum_value->value;
result = TRUE;
break;
}
}
}
g_free (str);
g_type_class_unref (enum_class);
if (!result)
parser->data = start;
return result;
}
gboolean
_gtk_css_parser_try_hash_color (GtkCssParser *parser,
GdkRGBA *rgba)
@@ -1017,36 +911,6 @@ gtk_css_parser_resync_internal (GtkCssParser *parser,
} while (*parser->data);
}
char *
_gtk_css_parser_read_value (GtkCssParser *parser)
{
const char *start;
char *result;
g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL);
start = parser->data;
/* This needs to be done better */
gtk_css_parser_resync_internal (parser, TRUE, FALSE, '}');
result = g_strndup (start, parser->data - start);
if (result)
{
g_strchomp (result);
if (result[0] == 0)
{
g_free (result);
result = NULL;
}
}
if (result == NULL)
_gtk_css_parser_error (parser, "Expected a property value");
return result;
}
void
_gtk_css_parser_resync (GtkCssParser *parser,
gboolean sync_at_semicolon,
+1 -16
View File
@@ -18,7 +18,6 @@
#ifndef __GTK_CSS_PARSER_PRIVATE_H__
#define __GTK_CSS_PARSER_PRIVATE_H__
#include "gtk/gtkcsstypesprivate.h"
#include <gtk/gtkcssprovider.h>
G_BEGIN_DECLS
@@ -40,10 +39,6 @@ void _gtk_css_parser_take_error (GtkCssParser *parser
void _gtk_css_parser_error (GtkCssParser *parser,
const char *format,
...) G_GNUC_PRINTF (2, 3);
void _gtk_css_parser_error_full (GtkCssParser *parser,
GtkCssProviderError code,
const char *format,
...) G_GNUC_PRINTF (3, 4);
guint _gtk_css_parser_get_line (GtkCssParser *parser);
guint _gtk_css_parser_get_position (GtkCssParser *parser);
@@ -66,10 +61,8 @@ gboolean _gtk_css_parser_is_string (GtkCssParser *parser
* however is fine to call if you dont know yet if the token is a foo or a bar,
* you can _try_bar() if try_foo() failed.
*/
#define _gtk_css_parser_try(p, s, skip) (gtk_css_parser_try_len (p, s, strlen(s), skip))
gboolean gtk_css_parser_try_len (GtkCssParser *parser,
gboolean _gtk_css_parser_try (GtkCssParser *parser,
const char *string,
gsize string_len,
gboolean skip_whitespace);
char * _gtk_css_parser_try_ident (GtkCssParser *parser,
gboolean skip_whitespace);
@@ -77,21 +70,13 @@ char * _gtk_css_parser_try_name (GtkCssParser *parser
gboolean skip_whitespace);
gboolean _gtk_css_parser_try_int (GtkCssParser *parser,
int *value);
gboolean _gtk_css_parser_try_uint (GtkCssParser *parser,
guint *value);
gboolean _gtk_css_parser_try_double (GtkCssParser *parser,
gdouble *value);
gboolean _gtk_css_parser_try_length (GtkCssParser *parser,
int *value);
gboolean _gtk_css_parser_try_enum (GtkCssParser *parser,
GType enum_type,
int *value);
gboolean _gtk_css_parser_try_hash_color (GtkCssParser *parser,
GdkRGBA *rgba);
gboolean _gtk_css_parser_has_number (GtkCssParser *parser);
char * _gtk_css_parser_read_string (GtkCssParser *parser);
char * _gtk_css_parser_read_value (GtkCssParser *parser);
GFile * _gtk_css_parser_read_url (GtkCssParser *parser);
void _gtk_css_parser_skip_whitespace (GtkCssParser *parser);
+1
View File
@@ -23,6 +23,7 @@
#include <cairo.h>
#include <pango/pango.h>
#include "gtkborder.h"
#include "gtktypes.h"
#include "gtkcssparserprivate.h"
#include "gtkcssvalueprivate.h"
+1
View File
@@ -23,6 +23,7 @@
#include <cairo.h>
#include <pango/pango.h>
#include "gtkborder.h"
#include "gtktypes.h"
#include "gtkcssparserprivate.h"
#include "gtkcssvalueprivate.h"
+110 -19
View File
@@ -35,7 +35,8 @@ typedef enum {
GTK_CSS_TRANSFORM_SCALE,
GTK_CSS_TRANSFORM_SKEW,
GTK_CSS_TRANSFORM_SKEW_X,
GTK_CSS_TRANSFORM_SKEW_Y
GTK_CSS_TRANSFORM_SKEW_Y,
GTK_CSS_TRANSFORM_PERSPECTIVE
} GtkCssTransformType;
union _GtkCssTransform {
@@ -66,6 +67,10 @@ union _GtkCssTransform {
GtkCssTransformType type;
GtkCssValue *skew;
} skew_x, skew_y;
struct {
GtkCssTransformType type;
GtkCssValue *depth;
} perspective;
};
struct _GtkCssValue {
@@ -110,6 +115,9 @@ gtk_css_transform_clear (GtkCssTransform *transform)
case GTK_CSS_TRANSFORM_SKEW_Y:
_gtk_css_value_unref (transform->skew_y.skew);
break;
case GTK_CSS_TRANSFORM_PERSPECTIVE:
_gtk_css_value_unref (transform->perspective.depth);
break;
case GTK_CSS_TRANSFORM_NONE:
default:
g_assert_not_reached ();
@@ -117,7 +125,7 @@ gtk_css_transform_clear (GtkCssTransform *transform)
}
}
static void
static gboolean
gtk_css_transform_init_identity (GtkCssTransform *transform,
GtkCssTransformType type)
{
@@ -152,13 +160,18 @@ gtk_css_transform_init_identity (GtkCssTransform *transform,
case GTK_CSS_TRANSFORM_SKEW_Y:
transform->skew_y.skew = _gtk_css_number_value_new (0, GTK_CSS_DEG);
break;
case GTK_CSS_TRANSFORM_PERSPECTIVE:
return FALSE;
case GTK_CSS_TRANSFORM_NONE:
default:
g_assert_not_reached ();
break;
return FALSE;
}
transform->type = type;
return TRUE;
}
static GskTransform *
@@ -198,7 +211,7 @@ gtk_css_transform_apply (const GtkCssTransform *transform,
_gtk_css_number_value_get (transform->scale.x, 1),
_gtk_css_number_value_get (transform->scale.y, 1),
_gtk_css_number_value_get (transform->scale.z, 1));
break;
case GTK_CSS_TRANSFORM_SKEW:
graphene_matrix_init_skew (&skew,
_gtk_css_number_value_get (transform->skew.x, 100) / 180.0f * G_PI,
@@ -217,6 +230,10 @@ gtk_css_transform_apply (const GtkCssTransform *transform,
_gtk_css_number_value_get (transform->skew_y.skew, 100) / 180.0f * G_PI);
return gsk_transform_matrix (next, &skew);
case GTK_CSS_TRANSFORM_PERSPECTIVE:
return gsk_transform_perspective (next,
_gtk_css_number_value_get (transform->perspective.depth, 100));
case GTK_CSS_TRANSFORM_NONE:
default:
g_assert_not_reached ();
@@ -303,6 +320,9 @@ gtk_css_transform_compute (GtkCssTransform *dest,
case GTK_CSS_TRANSFORM_SKEW_Y:
dest->skew_y.skew = _gtk_css_value_compute (src->skew_y.skew, property_id, provider, style, parent_style);
return dest->skew_y.skew == src->skew_y.skew;
case GTK_CSS_TRANSFORM_PERSPECTIVE:
dest->perspective.depth = _gtk_css_value_compute (src->perspective.depth, property_id, provider, style, parent_style);
return dest->perspective.depth == src->perspective.depth;
case GTK_CSS_TRANSFORM_NONE:
default:
g_assert_not_reached ();
@@ -389,6 +409,8 @@ gtk_css_transform_equal (const GtkCssTransform *transform1,
return _gtk_css_value_equal (transform1->skew_x.skew, transform2->skew_x.skew);
case GTK_CSS_TRANSFORM_SKEW_Y:
return _gtk_css_value_equal (transform1->skew_y.skew, transform2->skew_y.skew);
case GTK_CSS_TRANSFORM_PERSPECTIVE:
return _gtk_css_value_equal (transform1->perspective.depth, transform2->perspective.depth);
case GTK_CSS_TRANSFORM_NONE:
default:
g_assert_not_reached ();
@@ -416,7 +438,8 @@ gtk_css_value_transform_equal (const GtkCssValue *value1,
{
GtkCssTransform transform;
gtk_css_transform_init_identity (&transform, larger->transforms[i].type);
if (!gtk_css_transform_init_identity (&transform, larger->transforms[i].type))
return FALSE;
if (!gtk_css_transform_equal (&larger->transforms[i], &transform))
{
@@ -430,6 +453,38 @@ gtk_css_value_transform_equal (const GtkCssValue *value1,
return TRUE;
}
static void
gtk_css_transform_transition_default (GtkCssTransform *result,
const GtkCssTransform *start,
const GtkCssTransform *end,
guint property_id,
double progress)
{
graphene_matrix_t start_mat, end_mat;
GskTransform *trans;
result->type = GTK_CSS_TRANSFORM_MATRIX;
if (start)
trans = gtk_css_transform_apply (start, NULL);
else
trans = NULL;
gsk_transform_to_matrix (trans, &start_mat);
gsk_transform_unref (trans);
if (end)
trans = gtk_css_transform_apply (end, NULL);
else
trans = NULL;
gsk_transform_to_matrix (trans, &end_mat);
gsk_transform_unref (trans);
graphene_matrix_interpolate (&start_mat,
&end_mat,
progress,
&result->matrix.matrix);
}
static void
gtk_css_transform_transition (GtkCssTransform *result,
const GtkCssTransform *start,
@@ -473,6 +528,9 @@ gtk_css_transform_transition (GtkCssTransform *result,
case GTK_CSS_TRANSFORM_SKEW_Y:
result->skew_y.skew = _gtk_css_value_transition (start->skew_y.skew, end->skew_y.skew, property_id, progress);
break;
case GTK_CSS_TRANSFORM_PERSPECTIVE:
gtk_css_transform_transition_default (result, start, end, property_id, progress);
break;
case GTK_CSS_TRANSFORM_NONE:
default:
g_assert_not_reached ();
@@ -546,25 +604,45 @@ gtk_css_value_transform_transition (GtkCssValue *start,
{
GtkCssTransform transform;
gtk_css_transform_init_identity (&transform, start->transforms[i].type);
gtk_css_transform_transition (&result->transforms[i],
&start->transforms[i],
&transform,
property_id,
progress);
gtk_css_transform_clear (&transform);
if (gtk_css_transform_init_identity (&transform, start->transforms[i].type))
{
gtk_css_transform_transition (&result->transforms[i],
&start->transforms[i],
&transform,
property_id,
progress);
gtk_css_transform_clear (&transform);
}
else
{
gtk_css_transform_transition_default (&result->transforms[i],
&start->transforms[i],
NULL,
property_id,
progress);
}
}
for (; i < end->n_transforms; i++)
{
GtkCssTransform transform;
gtk_css_transform_init_identity (&transform, end->transforms[i].type);
gtk_css_transform_transition (&result->transforms[i],
&transform,
&end->transforms[i],
property_id,
progress);
gtk_css_transform_clear (&transform);
if (gtk_css_transform_init_identity (&transform, end->transforms[i].type))
{
gtk_css_transform_transition (&result->transforms[i],
&transform,
&end->transforms[i],
property_id,
progress);
gtk_css_transform_clear (&transform);
}
else
{
gtk_css_transform_transition_default (&result->transforms[i],
NULL,
&end->transforms[i],
property_id,
progress);
}
}
g_assert (i == MAX (start->n_transforms, end->n_transforms));
@@ -678,6 +756,11 @@ gtk_css_transform_print (const GtkCssTransform *transform,
_gtk_css_value_print (transform->skew_y.skew, string);
g_string_append (string, ")");
break;
case GTK_CSS_TRANSFORM_PERSPECTIVE:
g_string_append (string, "perspective(");
_gtk_css_value_print (transform->perspective.depth, string);
g_string_append (string, ")");
break;
case GTK_CSS_TRANSFORM_NONE:
default:
g_assert_not_reached ();
@@ -1046,6 +1129,14 @@ gtk_css_transform_parse (GtkCssTransform *transform,
if (transform->skew_y.skew == NULL)
return FALSE;
}
else if (_gtk_css_parser_try (parser, "perspective(", TRUE))
{
transform->type = GTK_CSS_TRANSFORM_PERSPECTIVE;
transform->perspective.depth = _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_LENGTH);
if (transform->perspective.depth == NULL)
return FALSE;
}
else
{
_gtk_css_parser_error (parser, "unknown syntax for transform");
-1
View File
@@ -20,7 +20,6 @@
#include <glib-object.h>
#include <gsk/gsk.h>
#include <gtk/gtkstylecontext.h>
G_BEGIN_DECLS
+2
View File
@@ -21,7 +21,9 @@
#define __GTK_CSS_VALUE_PRIVATE_H__
#include <glib-object.h>
#include "gtkcsstypesprivate.h"
#include "gtkstyleprovider.h"
G_BEGIN_DECLS

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